# HG changeset patch # User M. George Hansen # Date 1307411774 36000 # Node ID 06145a6ee38738a31efc959942c6522d546b3cef # Parent 4912a6f97c52efcbba8a9615067f6500c81efba0 Fixed resource path dependencies issue that caused PARPG to crash on start. * PARPG should now run without issue (system installation not tested). * Utilized FIFE's VFS module to remove path dependencies from most PARPG modules. * The new parpg.vfs module is a singleton with a single global variable, VFS, which is a reference to the global VFS instance. Although a singleton is not ideal it should be replaced once PARPG's core code is refactored. * The parpg.vfs singleton is initialized in the parpg.applicaiton.PARPGApplication class with the absolute path to the data directory via the parpg.settings module and corresponding configuration file. * A new DataPath entry was added to the default system configuration file template under the [parpg] section to support the new parpg.vfs module. * Updated the parpg-assets subrepo to revision 3 to fix some dialog file format issues (for details see commit message for parpg-assets). * Fixed a few bugs in the parpg.dialogueparsers.YAMLDialogueParser class related to exception handling. diff -r 4912a6f97c52 -r 06145a6ee387 application.py --- a/application.py Tue May 31 02:46:20 2011 -0700 +++ b/application.py Mon Jun 06 15:56:14 2011 -1000 @@ -21,7 +21,7 @@ from fife.extensions.serializers.xmlanimation import XMLAnimationLoader from fife.extensions.basicapplication import ApplicationBase -from parpg import console +from parpg import console, vfs from parpg.font import PARPGFont from parpg.gamemodel import GameModel from parpg.mainmenuview import MainMenuView @@ -116,6 +116,9 @@ self.engine = fife.Engine() self.loadSettings() self.engine.init() + # KLUDGE M. George Hansen 2011-06-04: See parpg/vfs.py. + vfs.VFS = self.engine.getVFS() + vfs.VFS.addNewSource(setting.parpg.DataPath) self._animationloader = XMLAnimationLoader(self.engine.getImagePool(), self.engine.getVFS()) self.engine.getAnimationPool().addResourceLoader(self._animationloader) @@ -133,6 +136,9 @@ self.model.getAgentImportFiles() self.model.readAllAgents() self.model.getDialogues() + # KLUDGE M. George Hansen 2011-06-04: Hack to allow loaded PyChan XML + # scripts to locate their resources. + os.chdir(setting.parpg.DataPath) self.view = MainMenuView(self.engine, self.model) self.loadFonts() self.event_listener = EventListener(self.engine) @@ -150,8 +156,7 @@ def loadFonts(self): # add the fonts path to the system path to import font definitons - sys.path.insert(0, os.path.join(self._setting.system_path, - self._setting.fife.FontsPath)) + sys.path.insert(0, os.path.join(self._setting.parpg.DataPath, 'fonts')) from oldtypewriter import fontdefs for fontdef in fontdefs: @@ -167,9 +172,10 @@ engineSetting = self.engine.getSettings() engineSetting.setDefaultFontGlyphs(self._setting.fife.FontGlyphs) - engineSetting.setDefaultFontPath(os.path.join(self._setting.system_path, - self._setting.fife.FontsPath, - self._setting.fife.Font)) + engineSetting.setDefaultFontPath( + '{0}/fonts/{1}'.format(self._setting.parpg.DataPath, + self._setting.fife.Font) + ) engineSetting.setDefaultFontSize(self._setting.fife.DefaultFontSize) engineSetting.setBitsPerPixel(self._setting.fife.BitsPerPixel) engineSetting.setInitialVolume(self._setting.fife.InitialVolume) @@ -186,9 +192,9 @@ for digit in self._setting.fife.ColorKey]) engineSetting.setWindowTitle(self._setting.fife.WindowTitle) - engineSetting.setWindowIcon(os.path.join(self._setting.system_path, - self._setting.fife.IconsPath, - self._setting.fife.WindowIcon)) + engineSetting.setWindowIcon( + '/'.join(['gui/icons', self._setting.fife.WindowIcon]) + ) def createListener(self): """ __init__ takes care of creating an event listener, so diff -r 4912a6f97c52 -r 06145a6ee387 charactercreationcontroller.py --- a/charactercreationcontroller.py Tue May 31 02:46:20 2011 -0700 +++ b/charactercreationcontroller.py Mon Jun 06 15:56:14 2011 -1000 @@ -15,6 +15,7 @@ """Provides the controller that defines the behaviour of the character creation screen.""" +from parpg import vfs import characterstatistics as char_stats from serializers import XmlSerializer from controllerbase import ControllerBase @@ -27,8 +28,10 @@ def getStatCost(offset): """Gets and returns the cost to increase stat based on the offset""" + if offset < 0: offset *= -1 + if offset < 22: return 1 elif offset < 29: @@ -106,23 +109,31 @@ @type application: L{fife.extensions.basicapplication.ApplicationBase}""" ControllerBase.__init__(self, engine, view, model, application) + self.settings = self.model.settings self.view.start_new_game_callback = self.startNewGame self.view.cancel_new_game_callback = self.cancelNewGame self.view.show() - #TODO: Maybe this should not be hardcoded - stream = file("character_scripts/primary_stats.xml") - prim_stats = XmlSerializer.deserialize(stream) - stream = file("character_scripts/secondary_stats.xml") - sec_stats = XmlSerializer.deserialize(stream) - self.char_data = SimpleCharacter("", - self.GENDERS[0], - self.ORIGINS.keys()[0], - 20, - self.PICTURES[self.GENDERS[0]][0], - [], - prim_stats, - sec_stats, - Inventory()) + # FIXME M. George Hansen 2011-06-06: character stats scripts aren't + # finished, unfortunately. +# primary_stats_file = \ +# vfs.VFS.open('character_scripts/primary_stats.xml') +# primary_stats = XmlSerializer.deserialize(primary_stats_file) +# secondary_stats_file = \ +# vfs.VFS.open('character_scripts/secondary_stats.xml') +# secondary_stats = XmlSerializer.deserialize(secondary_stats_file) + primary_stats = [] + secondary_stats = [] + self.char_data = SimpleCharacter( + "", + self.GENDERS[0], + self.ORIGINS.keys()[0], + 20, + self.PICTURES[self.GENDERS[0]][0], + [], + primary_stats, + secondary_stats, + Inventory() + ) self._stat_points = 200 @@ -134,7 +145,7 @@ self.application) self.application.view = view self.application.switchController(controller) - start_map = self.model.settings.parpg.Map + start_map = self.settings.parpg.Map self.model.changeMap(start_map) def cancelNewGame(self): diff -r 4912a6f97c52 -r 06145a6ee387 charactercreationview.py --- a/charactercreationview.py Tue May 31 02:46:20 2011 -0700 +++ b/charactercreationview.py Mon Jun 06 15:56:14 2011 -1000 @@ -14,10 +14,9 @@ # along with PARPG. If not, see . """Provides the view for displaying the character creation screen.""" -import os - from fife.extensions import pychan +from parpg import vfs from viewbase import ViewBase class CharacterCreationView(ViewBase): @@ -40,17 +39,17 @@ @type model: L{GameState}""" ViewBase.__init__(self, engine, model) self.settings = settings - gui_path = os.path.join(self.settings.system_path, - self.settings.parpg.GuiPath) - self.background = pychan.loadXML(os.path.join(gui_path, - 'main_menu_background.xml')) + xml_file = vfs.VFS.open('gui/main_menu_background.xml') + self.background = pychan.loadXML(xml_file) screen_mode = self.engine.getRenderBackend().getCurrentScreenMode() self.background.width = screen_mode.getWidth() self.background.height = screen_mode.getHeight() self.start_new_game_callback = None self.cancel_new_game_callback = None - self.character_screen = pychan.loadXML(os.path.join(gui_path, - 'character_screen.xml')) + + xml_file = vfs.VFS.open('gui/character_screen.xml') + self.character_screen = pychan.loadXML(xml_file) + self.character_screen.adaptLayout() character_screen_events = {} character_screen_events['startButton'] = self.startNewGame diff -r 4912a6f97c52 -r 06145a6ee387 common/utils.py --- a/common/utils.py Tue May 31 02:46:20 2011 -0700 +++ b/common/utils.py Mon Jun 06 15:56:14 2011 -1000 @@ -13,8 +13,13 @@ # Miscellaneous game functions -import os, sys, fnmatch +import sys +import os +import fnmatch + from textwrap import dedent +from contextlib import contextmanager +from parpg import vfs def addPaths (*paths): """Adds a list of paths to sys.path. Paths are expected to use forward @@ -38,9 +43,16 @@ def locateFiles(pattern, root=os.curdir): """Locate all files matching supplied filename pattern in and below supplied root directory.""" - for path, _, files in os.walk(os.path.abspath(root)): - for filename in fnmatch.filter(files, pattern): - yield os.path.join(path, filename) + filepaths = [] + filenames = vfs.VFS.listFiles(root) + for filename in fnmatch.filter(filenames, pattern): + vfs_file_path = '/'.join([root, filename]) + filepaths.append(vfs_file_path) + dirnames = vfs.VFS.listDirectories(root) + for dirname in dirnames: + subdir_filepaths = locateFiles(pattern, '/'.join([root, dirname])) + filepaths.extend(subdir_filepaths) + return filepaths def dedent_chomp(string): """Remove common leading whitespace and chomp each non-blank line.""" @@ -59,3 +71,13 @@ formatted_lines.append(line) result = ''.join(formatted_lines) return result + +@contextmanager +def cwd(dirname): + cwd = os.getcwd() + + try: + os.chdir(dirname) + yield + finally: + os.chdir(cwd) diff -r 4912a6f97c52 -r 06145a6ee387 controllerbase.py --- a/controllerbase.py Tue May 31 02:46:20 2011 -0700 +++ b/controllerbase.py Mon Jun 06 15:56:14 2011 -1000 @@ -12,7 +12,6 @@ # You should have received a copy of the GNU General Public License # along with PARPG. If not, see . -import os from fife import fife from parpg.common.listeners.key_listener import KeyListener @@ -83,10 +82,8 @@ def resetMouseCursor(self): """Reset cursor to default image. @return: None""" - image = os.path.join(self.model.settings.system_path, - self.model.settings.parpg.GuiPath, - self.model.settings.parpg.CursorPath, - self.model.settings.parpg.CursorDefault) + image = '/'.join(['gui/cursors/', + self.model.settings.parpg.CursorDefault]) self.setMouseCursor(image, image) def onStop(self): diff -r 4912a6f97c52 -r 06145a6ee387 dialogueparsers.py --- a/dialogueparsers.py Tue May 31 02:46:20 2011 -0700 +++ b/dialogueparsers.py Mon Jun 06 15:56:14 2011 -1000 @@ -114,11 +114,7 @@ @type loader_class: yaml.BaseLoader subclass """ loader = loader_class(stream) - try: - dialogue = \ - self._constructDialogue(loader, loader.get_single_node()) - except (AssertionError,) as error: - raise DialogueFormatError(str(error)) + dialogue = self._constructDialogue(loader, loader.get_single_node()) return dialogue def dump(self, dialogue, output_stream, dumper_class=yaml.Dumper): @@ -368,8 +364,9 @@ section_node ) sections.append(dialogue_section) - except (AttributeError, TypeError, ValueError) as e: - raise DialogueFormatError(e) + except (AttributeError, TypeError, ValueError, + yaml.scanner.ScannerError) as error: + raise DialogueFormatError(error) dialogue = Dialogue(npc_name=npc_name, avatar_path=avatar_path, default_greeting=default_greeting, diff -r 4912a6f97c52 -r 06145a6ee387 font.py --- a/font.py Tue May 31 02:46:20 2011 -0700 +++ b/font.py Mon Jun 06 15:56:14 2011 -1000 @@ -27,9 +27,7 @@ if self.typename == 'truetype': self.filename = '{0}.ttf'.format(self.name.lower().split('_')[0]) - self.source = os.path.join(settings.system_path, - settings.fife.FontsPath, - self.filename) + self.source = '/'.join(['fonts', self.filename]) self.row_spacing = fontdef.get('row_spacing', 0) self.glyph_spacing = fontdef.get('glyph_spacing', 0) diff -r 4912a6f97c52 -r 06145a6ee387 gamemap.py --- a/gamemap.py Tue May 31 02:46:20 2011 -0700 +++ b/gamemap.py Mon Jun 06 15:56:14 2011 -1000 @@ -14,7 +14,6 @@ # along with PARPG. If not, see . from fife import fife - from fife.extensions.loaders import loadMapFile class GameMap(fife.MapChangeListener): @@ -25,6 +24,7 @@ self.map = None self.engine = engine self.model = model + self.settings = self.model.settings # init map attributes self.my_cam_id = None @@ -46,6 +46,7 @@ if self.map: self.model.deleteObjects() self.model.deleteMap(self.map) + self.transitions = [] self.map = None self.agent_layer = None @@ -71,7 +72,9 @@ @param filename: Name of map to load @return: None""" self.reset() + self.map = loadMapFile(filename, self.engine) + self.agent_layer = self.map.getLayer('ObjectLayer') self.top_layer = self.map.getLayer('TopLayer') @@ -88,8 +91,8 @@ the proper camera is set as the 'main' camera. At this point we also set the viewport to the current resolution.""" for cam in self.map.getCameras(): - width = self.model.settings.fife.ScreenWidth - height = self.model.settings.fife.ScreenHeight + width = self.settings.fife.ScreenWidth + height = self.settings.fife.ScreenHeight viewport = fife.Rect(0, 0, width, height) cam.setViewPort(viewport) self.my_cam_id = cam.getId() @@ -108,9 +111,10 @@ rend = fife.FloatingTextRenderer.getInstance(self.cameras[ self.my_cam_id ]) - text = self.engine.getGuiManager().\ - createFont('fonts/rpgfont.png', 0, \ - self.model.settings.fife.FontGlyphs) + text = self.engine.getGuiManager().createFont('fonts/rpgfont.png', + 0, + self.settings.fife.FontGlyphs) + rend.changeDefaultFont(text) rend.activateAllLayers(self.map) rend.setEnabled(True) diff -r 4912a6f97c52 -r 06145a6ee387 gamemodel.py --- a/gamemodel.py Tue May 31 02:46:20 2011 -0700 +++ b/gamemodel.py Mon Jun 06 15:56:14 2011 -1000 @@ -22,6 +22,7 @@ from fife import fife from fife.extensions.serializers.xmlobject import XMLObjectLoader +from parpg import vfs from gamestate import GameState from objects import createObject from objects.composed import CarryableItem, CarryableContainer @@ -61,8 +62,7 @@ self.map_change = False self.load_saver = False self.savegame = None - quests_directory = os.path.join(self.settings.system_path, - self.settings.parpg.QuestsPath) + quests_directory = settings.parpg.QuestsPath self.game_state = GameState(quests_dir=quests_directory) #self.game_state.quest_engine = #self.game_state.quest_engine.readQuests() @@ -78,23 +78,16 @@ self.fife_model = engine.getModel() # set values from settings - maps_file = os.path.join(self.settings.system_path, - self.settings.parpg.MapsPath, - self.settings.parpg.MapsFile) - self.game_state.maps_file = maps_file - all_agents_file = os.path.join(self.settings.system_path, - self.settings.parpg.MapsPath, - self.settings.parpg.AllAgentsFile) - self.all_agents_file = all_agents_file - objects_dir = os.path.join(self.settings.system_path, - self.settings.parpg.ObjectsPath) - self.objects_directory = objects_dir - object_db_file = os.path.join(self.objects_directory, - self.settings.parpg.ObjectDatabaseFile) - self.object_db_file = object_db_file - dialogues_dir = os.path.join(self.settings.system_path, - self.settings.parpg.DialoguesPath) - self.dialogues_directory = dialogues_dir + maps_directory = settings.parpg.MapsPath + self.game_state.maps_file = '/'.join([maps_directory, + settings.parpg.MapsFile]) + self.all_agents_file = '/'.join([maps_directory, + settings.parpg.AllAgentsFile]) + objects_directory = self.settings.parpg.ObjectsPath + self.objects_directory = objects_directory + self.object_db_file = '/'.join([objects_directory, + settings.parpg.ObjectDatabaseFile]) + self.dialogue_directory = settings.parpg.DialoguesPath self.dialogues = {} self.agent_import_files = {} self.obj_loader = XMLObjectLoader( @@ -373,8 +366,8 @@ def readMapFiles(self): """Read all a available map-files and store them""" - maps_data = file(self.game_state.maps_file) - self.map_files = yaml.load(maps_data)["Maps"] + maps_file = vfs.VFS.open(self.game_state.maps_file) + self.map_files = yaml.load(maps_file)["Maps"] def addAgent(self, namespace, agent): """Adds an agent to the agents dictionary @@ -410,7 +403,7 @@ #Get the agents of the map map_agents_file = self.map_files[map_name].\ replace(".xml", "_agents.yaml") - agents_data = file(map_agents_file) + agents_data = vfs.VFS.open(map_agents_file) agents = yaml.load_all(agents_data) for agent in agents: if not agent == None: @@ -418,10 +411,10 @@ def readAllAgents(self): """Read the agents of the all_agents_file and store them""" - agents_data = file(self.all_agents_file) - agents = yaml.load_all(agents_data) + agents_file = vfs.VFS.open(self.all_agents_file) + agents = yaml.load_all(agents_file) for agent in agents: - if not agent == None: + if agent is not None: self.addAgent(self.ALL_AGENTS_KEY, agent) def getAgentsOfMap(self, map_name): @@ -730,44 +723,40 @@ def readObjectDB(self): """Reads the Object Information Database from a file. """ - database_file = file(self.object_db_file, "r") + database_file = vfs.VFS.open(self.object_db_file) database = yaml.load_all(database_file) for object_info in database: self.object_db.update(object_info) def getAgentImportFiles(self): """Searches the agents directory for import files """ - files = locateFiles("*.xml", self.objects_directory) - for xml_file in files: - xml_file = os.path.relpath(xml_file).replace("\\", "/") + filepaths = locateFiles("*.xml", self.objects_directory) + for filepath in filepaths: try: + xml_file = vfs.VFS.open(filepath) root = ElementTree.parse(xml_file).getroot() if root.tag == "object": - self.agent_import_files[root.attrib["id"]] = xml_file + self.agent_import_files[root.attrib["id"]] = filepath except SyntaxError as error: - assert(isinstance(error, SyntaxError)) - logging.critical("Error parsing file {0}: " - "{1}".format(xml_file, error.msg)) - sys.exit(1) + logging.error("Error parsing file {0}: {1}".format(filepath, + error)) def getDialogues(self): """Searches the dialogue directory for dialogues """ - files = locateFiles("*.yaml", self.dialogues_directory) + files = locateFiles("*.yaml", self.dialogue_directory) dialogue_parser = YamlDialogueParser() for dialogue_filepath in files: - dialogue_filepath = os.path.relpath(dialogue_filepath) \ - .replace("\\", "/") # Note Technomage 2010-11-13: the new DialogueEngine uses its own # parser now, YamlDialogueParser. # dialogues = yaml.load_all(file(dialogue_file, "r")) - with file(dialogue_filepath, 'r') as dialogue_file: - try: - dialogue = dialogue_parser.load(dialogue_file) - except (DialogueFormatError,) as error: - logging.error('unable to load dialogue file {0}: {1}' - .format(dialogue_filepath, error)) - else: - self.dialogues[dialogue.npc_name] = dialogue + dialogue_file = vfs.VFS.open(dialogue_filepath) + try: + dialogue = dialogue_parser.load(dialogue_file) + except DialogueFormatError as error: + logging.error('unable to load dialogue file {0}: {1}' + .format(dialogue_filepath, error)) + else: + self.dialogues[dialogue.npc_name] = dialogue # Note Technomage 2010-11-13: the below code is used to load # multiple dialogues from a single file. Is this functionality # used/necessary? diff -r 4912a6f97c52 -r 06145a6ee387 gamescenecontroller.py --- a/gamescenecontroller.py Tue May 31 02:46:20 2011 -0700 +++ b/gamescenecontroller.py Mon Jun 06 15:56:14 2011 -1000 @@ -94,9 +94,10 @@ if model.settings.fife.EnableSound: if not self.view.sounds.music_init: - music_file = random.choice(glob.glob(os.path.join( - "music", - "*.ogg"))) + music_path = 'music' + music_file = random.choice( + glob.glob('/'.join([music_path, '*.ogg'])) + ) self.view.sounds.playMusic(music_file) self.initHud() @@ -135,8 +136,10 @@ # F7 saves a screenshot to screenshots directory settings = self.model.settings + # FIXME M. George Hansen 2011-06-06: Not sure that user_path is set + # correctly atm. screenshot_directory = os.path.join(settings.user_path, - settings.parpg.ScreenshotsPath) + 'screenshots') # try to create the screenshots directory try: os.mkdir(screenshot_directory) @@ -256,37 +259,25 @@ if mouse_y <= pixle_edge: direction[0] += 1 direction[1] -= 1 - image = os.path.join(settings.system_path, - settings.parpg.GuiPath, - settings.parpg.CursorPath, - settings.parpg.CursorUp) + image = '/'.join(['gui/cursors', settings.parpg.CursorUp]) #right if mouse_x >= screen_width - pixle_edge: direction[0] += 1 direction[1] += 1 - image = os.path.join(settings.system_path, - settings.parpg.GuiPath, - settings.parpg.CursorPath, - settings.parpg.CursorRight) + image = '/'.join(['gui/cursors', settings.parpg.CursorRight]) #down if mouse_y >= screen_height - pixle_edge: direction[0] -= 1 direction[1] += 1 - image = os.path.join(settings.system_path, - settings.parpg.GuiPath, - settings.parpg.CursorPath, - settings.parpg.CursorDown) + image = '/'.join(['gui/cursors', settings.parpg.CursorDown]) #left if mouse_x <= pixle_edge: direction[0] -= 1 direction[1] -= 1 - image = os.path.join(settings.system_path, - settings.parpg.GuiPath, - settings.parpg.CursorPath, - settings.parpg.CursorLeft) + image = '/'.join(['gui/cursors', settings.parpg.CursorLeft]) if image is not None and not data_drag.dragging: self.setMouseCursor(image, image) @@ -310,9 +301,12 @@ player_agent = self.model.active_map.\ agent_layer.getInstance("PlayerCharacter") self.model.active_map.agent_layer.deleteInstance(player_agent) + self.model.loadMap(self.model.target_map_name) + self.model.setActiveMap(self.model.target_map_name) self.model.readAgentsOfMap(self.model.target_map_name) + self.model.placeAgents() self.model.placePC() self.model.map_change = False diff -r 4912a6f97c52 -r 06145a6ee387 gui/__init__.py --- a/gui/__init__.py Tue May 31 02:46:20 2011 -0700 +++ b/gui/__init__.py Mon Jun 06 15:56:14 2011 -1000 @@ -1,4 +1,5 @@ from fife.extensions import pychan + from .inventorygui import EquipmentSlot, InventoryGrid from .spinners import Spinner, IntSpinner from .tabwidget import TabWidget diff -r 4912a6f97c52 -r 06145a6ee387 gui/charactercreationview.py --- a/gui/charactercreationview.py Tue May 31 02:46:20 2011 -0700 +++ b/gui/charactercreationview.py Mon Jun 06 15:56:14 2011 -1000 @@ -1,11 +1,13 @@ from fife.extensions import pychan from fife.extensions.pychan.widgets import Label, HBox +from parpg import vfs from parpg.gui.spinner import IntSpinner class CharacterCreationView(object): def __init__(self, xml_script_path='gui/character_creation.xml'): - self.gui = pychan.loadXML(xml_script_path) + xml_file = vfs.VFS.open(xml_script_path) + self.gui = pychan.loadXML(xml_file) def createStatisticList(self, statistics): statistics_list = self.gui.findChild(name='statisticsList') diff -r 4912a6f97c52 -r 06145a6ee387 gui/containergui_base.py --- a/gui/containergui_base.py Tue May 31 02:46:20 2011 -0700 +++ b/gui/containergui_base.py Mon Jun 06 15:56:14 2011 -1000 @@ -10,13 +10,15 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from copy import deepcopy +from types import StringTypes from fife import fife from fife.extensions import pychan +from parpg import vfs from parpg.gui import drag_drop_data as data_drag from parpg.objects.action import ACTIONS -from copy import deepcopy class ContainerGUIBase(object): """ @@ -26,7 +28,11 @@ def __init__(self, controller, gui_file): self.controller = controller - self.gui = pychan.loadXML(gui_file) + if isinstance(gui_file, StringTypes): + xml_file = vfs.VFS.open(gui_file) + self.gui = pychan.loadXML(xml_file) + else: + self.gui = pychan.loadXML(gui_file) def dragDrop(self, obj): """Decide whether to drag or drop the image. diff -r 4912a6f97c52 -r 06145a6ee387 gui/dialogs.py --- a/gui/dialogs.py Tue May 31 02:46:20 2011 -0700 +++ b/gui/dialogs.py Mon Jun 06 15:56:14 2011 -1000 @@ -12,17 +12,15 @@ # You should have received a copy of the GNU General Public License # along with PARPG. If not, see . +from fife.extensions import pychan -import os - -from fife.extensions import pychan +from parpg import vfs class RestartDialog(object): def __init__(self, settings): self.settings = settings - self.window = pychan.loadXML(os.path.join(self.settings.system_path, - self.settings.parpg.GuiPath, - 'restart_dialog.xml')) + xml_file = vfs.VFS.open('gui/restart_dialog.xml') + self.window = pychan.loadXML(xml_file) self.window.mapEvents({'closeButton': self.hide}) def hide(self): diff -r 4912a6f97c52 -r 06145a6ee387 gui/dialoguegui.py --- a/gui/dialoguegui.py Tue May 31 02:46:20 2011 -0700 +++ b/gui/dialoguegui.py Mon Jun 06 15:56:14 2011 -1000 @@ -18,6 +18,7 @@ from fife.extensions import pychan from fife.extensions.pychan import widgets +from parpg import vfs from parpg.dialogueprocessor import DialogueProcessor logger = logging.getLogger('dialoguegui') @@ -29,7 +30,8 @@ def __init__(self, controller, npc, quest_engine, player_character): self.active = False self.controller = controller - self.dialogue_gui = pychan.loadXML("gui/dialogue.xml") + xml_file = vfs.VFS.open('gui/dialogue.xml') + self.dialogue_gui = pychan.loadXML(xml_file) self.npc = npc # TODO Technomage 2010-11-10: the QuestEngine should probably be # a singleton-like object, which would avoid all of this instance diff -r 4912a6f97c52 -r 06145a6ee387 gui/filebrowser.py --- a/gui/filebrowser.py Tue May 31 02:46:20 2011 -0700 +++ b/gui/filebrowser.py Mon Jun 06 15:56:14 2011 -1000 @@ -10,13 +10,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import sys +import os +import logging from fife.extensions import pychan from fife.extensions.pychan import widgets -import sys -import os -import logging +from parpg import vfs logger = logging.getLogger('filebrowser') @@ -37,7 +38,6 @@ extensions=('.dat',)): self.engine = engine self.settings = settings - print self.settings.parpg.SavesPath self.file_selected = file_selected self._widget = None @@ -47,8 +47,10 @@ self.gui_xml_path = gui_xml_path self.extensions = extensions - self.path = os.path.join(self.settings.user_path, - self.settings.parpg.SavesPath) + # FIXME M. George Hansen 2011-06-06: Not sure that user_path is set + # correctly atm. Plus, I don't think that this should be + # hard-coded. + self.path = os.path.join(self.settings.user_path, 'saves') self.dir_list = [] self.file_list = [] @@ -63,7 +65,8 @@ if self._widget: self._widget.show() return - self._widget = pychan.loadXML(self.gui_xml_path) + xml_file = vfs.VFS.open(self.gui_xml_path) + self._widget = pychan.loadXML(xml_file) self._widget.mapEvents({ 'dirList' : self._setPath, 'selectButton' : self._selectFile, diff -r 4912a6f97c52 -r 06145a6ee387 gui/hud.py --- a/gui/hud.py Tue May 31 02:46:20 2011 -0700 +++ b/gui/hud.py Mon Jun 06 15:56:14 2011 -1000 @@ -19,13 +19,14 @@ from fife.extensions import pychan from fife.extensions.pychan.tools import callbackWithArguments as cbwa +from parpg import vfs from parpg.gui.filebrowser import FileBrowser from parpg.gui.menus import ContextMenu, SettingsMenu -from parpg.gui import inventorygui from parpg.gui.popups import ExaminePopup from parpg.gui.containergui import ContainerGUI from parpg.gui.dialoguegui import DialogueGUI from parpg.gui import drag_drop_data as data_drag +from parpg.gui.inventorygui import InventoryGUI from actionsbox import ActionsBox logger = logging.getLogger('hud') @@ -46,12 +47,15 @@ @return: None""" # TODO: perhaps this should not be hard-coded here + self.settings = settings pychan.registerWidget(ActionsBox) - self.hud = pychan.loadXML("gui/hud.xml") + + xml_file = vfs.VFS.open('gui/hud.xml') + self.hud = pychan.loadXML(xml_file) + self.controller = controller self.engine = controller.engine self.model = controller.model - self.settings = settings self.inventory = None self.character_screen = None @@ -152,9 +156,8 @@ def initializeInventory(self): """Initialize the inventory""" if not self.inventory: - self.inventory = inventorygui.InventoryGUI(self.controller, - None, - None) + xml_file = vfs.VFS.open('gui/inventory.xml') + self.inventory = InventoryGUI(self.controller, xml_file, None) # inv_callbacks = { # 'refreshReadyImages': self.refreshReadyImages, # 'toggleInventoryButton': self.toggleInventoryButton, @@ -173,13 +176,13 @@ """Initialize the character screen.""" # TODO Technomage 2010-12-24: if not self.character_screen: - self.character_screen = pychan.loadXML('gui/character_screen.xml') - + xml_file = vfs.VFS.open('gui/character_screen.xml') + self.character_screen = pychan.loadXML(xml_file) def initializeContextMenu(self): """Initialize the Context Menu @return: None""" - self.context_menu = ContextMenu (self.engine, [], (0, 0)) + self.context_menu = ContextMenu(self.engine, [], (0, 0)) def showContextMenu(self, data, pos): """Display the Context Menu with model at pos @@ -199,7 +202,10 @@ def initializeMainMenu(self): """Initalize the main menu. @return: None""" - self.main_menu = pychan.loadXML("gui/hud_pause_menu.xml") + + xml_file = vfs.VFS.open('gui/hud_pause_menu.xml') + self.main_menu = pychan.loadXML(xml_file) + #TODO: find more suitalbe place for onOptilonsPress implementation self.menu_events = {"resumeButton": self.hideMenu, "settingsButton": self.displaySettings, @@ -237,7 +243,10 @@ def initializeHelpMenu(self): """Initialize the help menu @return: None""" - self.help_dialog = pychan.loadXML("gui/help.xml") + + xml_file = vfs.VFS.open('gui/help.xml') + self.help_dialog = pychan.loadXML(xml_file) + help_events = {"closeButton":self.help_dialog.hide} self.help_dialog.mapEvents(help_events) main_help_text = u"Welcome to Post-Apocalyptic RPG or PARPG![br][br]"\ @@ -273,9 +282,7 @@ """ Called when the user wants to save the game. @return: None""" self.stopActions() - xml_path = os.path.join(self.settings.system_path, - self.settings.parpg.GuiPath, - 'savebrowser.xml') + xml_path = 'gui/savebrowser.xml' save_browser = FileBrowser(self.engine, self.settings, self.save_game_callback, @@ -318,9 +325,7 @@ """ Called when the user wants to load a game. @return: None""" self.stopActions() - xml_path = os.path.join(self.settings.system_path, - self.settings.parpg.GuiPath, - 'loadbrowser.xml') + xml_path = 'gui/loadbrowser.xml' load_browser = FileBrowser(self.engine, self.settings, self.load_game_callback, @@ -380,13 +385,15 @@ def toggleInventory(self, toggle_image=True): """Displays the inventory screen @return: None""" - if self.inventory == None: + if self.inventory is None: self.initializeInventory() + self.inventory.toggleInventory(toggle_image) def toggleCharacterScreen(self): - if not self.character_screen: + if self.characcter_screen is None: self.initializeCharacterScreen() + if not self.character_screen.isVisible(): self.character_screen.show() else: diff -r 4912a6f97c52 -r 06145a6ee387 gui/inventorygui.py --- a/gui/inventorygui.py Tue May 31 02:46:20 2011 -0700 +++ b/gui/inventorygui.py Mon Jun 06 15:56:14 2011 -1000 @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # This file is part of PARPG. # PARPG is free software: you can redistribute it and/or modify @@ -48,11 +46,10 @@ def __init__(self, label_text=u'equipment', min_size=(50, 50), max_size=(50, 50), margins=None, - background_image="gui/inv_images/inv_background.png", **kwargs): pychan.VBox.__init__(self, min_size=min_size, max_size=max_size, **kwargs) - self.background_image = background_image + self.background_image = 'gui/inv_images/inv_background.png' label = pychan.Label(text=unicode(label_text)) self.addChild(label) self.label_text = label_text @@ -114,7 +111,7 @@ class InventoryGUI(ContainerGUIBase): def __init__(self, controller, inventory, callbacks): - super(InventoryGUI, self).__init__(controller, "gui/inventory.xml") + super(InventoryGUI, self).__init__(controller, inventory) self.engine = controller.engine self.inventory_shown = False render_backend = self.engine.getRenderBackend() diff -r 4912a6f97c52 -r 06145a6ee387 gui/menus.py --- a/gui/menus.py Tue May 31 02:46:20 2011 -0700 +++ b/gui/menus.py Mon Jun 06 15:56:14 2011 -1000 @@ -13,10 +13,11 @@ # You should have received a copy of the GNU General Public License # along with PARPG. If not, see . -import os import logging from fife.extensions import pychan + +from parpg import vfs from dialogs import RestartDialog logger = logging.getLogger('menus') @@ -88,17 +89,16 @@ self.render_backends = ['OpenGL', 'SDL'] self.lighting_models = range(3) - + # selected options self.resolution = "{0}x{1}".format(width, height) self.render_backend = self.settings.fife.RenderBackend self.lighting_model = self.settings.fife.Lighting self.fullscreen = self.settings.fife.FullScreen self.sound = self.settings.fife.EnableSound - - self.window = pychan.loadXML(os.path.join(self.settings.system_path, - self.settings.parpg.GuiPath, - 'settings_menu.xml')) + + xml_file = vfs.VFS.open('gui/settings_menu.xml') + self.window = pychan.loadXML(xml_file) self.restart_dialog = RestartDialog(self.settings) self.window.mapEvents({'okButton': self.save, 'cancelButton': self.hide, diff -r 4912a6f97c52 -r 06145a6ee387 main.py --- a/main.py Tue May 31 02:46:20 2011 -0700 +++ b/main.py Mon Jun 06 15:56:14 2011 -1000 @@ -18,6 +18,8 @@ from optparse import OptionParser +from parpg.settings import Settings + usage = ('usage: %prog [options] settings_path [system_path user_path]\n\n' 'The settings_path argument is mandatory and is the directory in \n' 'which your system.cfg file is located. Optionally, you may \n' @@ -30,8 +32,6 @@ help='Name of log file to save to') parser.add_option('-l', '--loglevel', default='critical', help='desired output level for log file') -parser.add_option('-m', '--module', - help='location of the parpg module') opts, args = parser.parse_args() if not args: @@ -39,12 +39,6 @@ sys.exit(1) -# initialize settings -if opts.module: - print('added ' + opts.module) - sys.path.insert(0, opts.module) - -from parpg.settings import Settings settings = Settings(*args) diff -r 4912a6f97c52 -r 06145a6ee387 mainmenuview.py --- a/mainmenuview.py Tue May 31 02:46:20 2011 -0700 +++ b/mainmenuview.py Mon Jun 06 15:56:14 2011 -1000 @@ -13,10 +13,9 @@ # You should have received a copy of the GNU General Public License # along with PARPG. If not, see . import yaml + from parpg.common.utils import locateFiles -import os.path +from parpg import vfs class Quest(object): """Class that holds the information for a quest""" @@ -142,14 +143,14 @@ def readQuests(self): """Reads in the quests in the quest directory""" - files = locateFiles("*.yaml", self.quest_dir) + filepaths = locateFiles("*.yaml", self.quest_dir) self.quests = {} self.active_quests = [] self.finished_quests = [] self.failed_quests = [] - for quest_file in files: - quest_file = os.path.relpath(quest_file).replace("\\", "/") - tree = yaml.load(open(quest_file)) + for filepath in filepaths: + quest_file = vfs.VFS.open(filepath) + tree = yaml.load(quest_file) quest_properties = tree["QUEST_PROPERTIES"] variable_defines = tree["DEFINES"] diff -r 4912a6f97c52 -r 06145a6ee387 vfs.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vfs.py Mon Jun 06 15:56:14 2011 -1000 @@ -0,0 +1,17 @@ +# This file is part of PARPG. + +# PARPG is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# PARPG is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with PARPG. If not, see . + +# KLUDGE M. George Hansen 2011-06-04: Die, global variable, die! +VFS = None \ No newline at end of file