""" Thousands of games rise from the dead, shrouded in crypt dust and pixels! Retromancer is an application for launching quests, showing quest results, and navigating through a map full of games. NecroApp is the application class, NecroFrame is the top-level window widget. """ import sys import string TempLogFile = open("BootstrapLog.txt", "wb") #sys.path = [".","library.zip"] # release hack sys.stdout = TempLogFile sys.stderr = TempLogFile import wx import os import types import time import thread import Global import traceback import NecroQuest import GameInfo import UIProgress import UIImages import KeyConfigDialog import DirConfigDialog import Config import Keystroke import UIQuest import UIMessage import getopt import GamePlayer import GameMap import NecroUIFrame import UIQuestReward from Global import Log, LogException from wx.lib.wordwrap import wordwrap import UIConversation class MenuID: """ ID numbers for various menu entries, huzzah. """ LoadQuests = 100 ReloadQuests = 101 OpenNES = 102 Exit = 103 LoadPlayer = 104 NewPlayer = 105 OpenMAME = 108 OpenGBA = 107 TestOptionA = 106 TestOptionB = 109 ConfigKeys = 200 ConfigDirectories = 201 Help = 300 About = 301 AboutBoxText = """ Retromancer is a mutli-emulator frontend that plays arcade and console \ games. Retromancer supports meta-games built from bits and pieces of \ other games. """ class NecroMode: QuestGroup = 0 FrontEnd = 1 AdventureMap = 2 class VBARunnerThread: def __init__(self, ROMPath, SavePath = None, Quest = None, PatchFilePath = None): self.ROMPath = ROMPath self.SavePath = SavePath self.Quest = Quest self.PatchFilePath = PatchFilePath self.IsRunningFlag = 0 self.KeepRunningFlag = 0 def Start(self): self.KeepRunningFlag = 1 self.IsRunningFlag = 1 thread.start_new_thread(self.Run, ()) def IsRunning(self): return self.IsRunningFlag def Run(self): try: import PyVBA self.ResultsList = PyVBA.PlayGame(self.ROMPath, self.SavePath, self.Quest, self.PatchFilePath) except: LogException() self.IsRunningFlag = 0 self.KeepRunningFlag = 0 class IDGenerator: "Generates widget IDs." def __init__(self): self.NextID = 0 def GetID(self): ID = self.NextID self.NextID += 1 return ID class NecroToolbook(wx.Toolbook): """ A 'notebook-ish' widget, with buttons along the top that you can click to switch between pages. First page is the adventure map, second page is the quest list, and other pages are front-end pages for individual emulators. """ def __init__(self, Parent, App): self.App = App wx.Toolbook.__init__(self, Parent, -1, style = wx.BK_DEFAULT) self.PageIndexMap = 0 self.PageIndexOverall = 1 self.PageIndexQuests = 2 self.LoadImages() self.BuildPanels() def BuildPanels(self): "Build our panels. The main one is the NecroUIFrame." ImageIDGenerator = IDGenerator() # Build the NecroUIFrame, containing the world map: self.UIPanel = NecroUIFrame.NecroUIFrame(self, self.App, -1) self.UIPanel.App = self.App self.UIPanel.BuildWidgets() self.Parent.UIFrame = self.UIPanel self.AddPage(self.UIPanel, "World Map", imageId = ImageIDGenerator.GetID()) # Build the OverallPanel, giving progress: Panel = UIProgress.OverallStausPanel(self, -1) self.Parent.ProgressPanel = Panel self.AddPage(Panel, "Status", imageId = ImageIDGenerator.GetID()) # Build the QuestPanel, containing a listbox of quests: Panel = UIQuest.QuestPanel(self, -1) Panel.App = self.App Panel.BuildWidgets() self.Parent.QuestPanel = Panel self.AddPage(Panel, "Quests", imageId = ImageIDGenerator.GetID()) # Bind events: self.Bind(wx.EVT_TOOLBOOK_PAGE_CHANGED, self.OnPageChanged) #self.Bind(wx.EVT_TOOLBOOK_PAGE_CHANGING, self.OnPageChanging) def LoadImages(self): ImageList = wx.ImageList(32, 32) ImageFileNames = ["Insectoid.png", "PacGhost.png", "RType.png", "Marble.png", "Shuriken.png"] for FileName in ImageFileNames: Image = wx.Bitmap(os.path.join("Images", FileName), wx.BITMAP_TYPE_ANY) ImageList.Add(Image) self.AssignImageList(ImageList) def OnPageChanged(self, event): try: old = event.GetOldSelection() new = event.GetSelection() sel = self.GetSelection() if (new == self.PageIndexMap): Log(">>>Set map focus!") Global.UIMap.SetManualFocus() elif new == self.PageIndexOverall: Log(">>>Set overall stats!") self.Parent.ProgressPanel.UpdateStatus() else: Global.UIMap.KillManualFocus() event.Skip() except: LogException() class NecroFrame(wx.Frame): """ NecroFrame is the main window. It implements menu commands and a few other things. It delegates most of the real work to the NecroUIFrame. """ def __init__(self, App, Parent, Title): self.App = App self.Mode = NecroMode.QuestGroup wx.Frame.__init__(self, Parent, -1, Title, size = (900,700)) self.BuildWidgets() def BuildWidgets(self): self.BuildMenuWidgets() self.StatusBar = wx.StatusBar(self) # Add a Toolbook, for selecting map/quest/freeplay: self.MainBook = NecroToolbook(self, self.App) # LAYOUT: ...is simple! Box = wx.BoxSizer(wx.VERTICAL) Box.Add(self.MainBook, 10, wx.EXPAND) #Box.Add(self.StatusBar, 1) self.SetStatusBar(self.StatusBar) self.SetAutoLayout(True) self.SetSizer(Box) self.Layout() def BuildMenuWidgets(self): MenuBar = wx.MenuBar() ############# Menu = wx.Menu() Menu.Append(MenuID.LoadPlayer, "&Load Player...", "") Menu.Append(MenuID.NewPlayer, "&New Player...", "") #Menu.Append(MenuID.LoadQuests, "&Open quests...", "") #Menu.Append(MenuID.ReloadQuests, "&Reload quests...", "") Menu.AppendSeparator() Menu.Append(MenuID.OpenNES, "Open &NES...", "") Menu.Append(MenuID.OpenMAME, "Open &MAME...", "") Menu.Append(MenuID.OpenGBA, "Open &GBA...", "") Menu.AppendSeparator() Menu.Append(MenuID.TestOptionA, "Test/Debug A", "") Menu.Append(MenuID.TestOptionB, "Test/Debug B", "") Menu.Append(MenuID.Exit, "E&xit", "") MenuBar.Append(Menu, "&File") ############# Menu = wx.Menu() Menu.Append(MenuID.ConfigKeys, "Config &keys...", "") Menu.Append(MenuID.ConfigDirectories, "Config &directories...", "") MenuBar.Append(Menu, "&Config") ############# Menu = wx.Menu() Menu.Append(MenuID.Help, "&Help", "") Menu.AppendSeparator() Menu.Append(MenuID.About, "&About Retromancer", "") MenuBar.Append(Menu, "Help") ############# # bind menu events: self.Bind(wx.EVT_MENU, self.MenuLoadQuests, id = MenuID.LoadQuests) self.Bind(wx.EVT_MENU, self.MenuLoadPlayer, id = MenuID.LoadPlayer) self.Bind(wx.EVT_MENU, self.MenuNewPlayer, id = MenuID.NewPlayer) #self.Bind(wx.EVT_MENU, self.MenuReloadQuests, id = MenuID.ReloadQuests) self.Bind(wx.EVT_MENU, self.MenuOpenNES, id = MenuID.OpenNES) self.Bind(wx.EVT_MENU, self.MenuTestOptionA, id = MenuID.TestOptionA) self.Bind(wx.EVT_MENU, self.MenuTestOptionB, id = MenuID.TestOptionB) self.Bind(wx.EVT_MENU, self.MenuOpenMAME, id = MenuID.OpenMAME) self.Bind(wx.EVT_MENU, self.MenuOpenGBA, id = MenuID.OpenGBA) self.Bind(wx.EVT_MENU, self.MenuExit, id = MenuID.Exit) # self.Bind(wx.EVT_MENU, self.MenuConfigKeys, id = MenuID.ConfigKeys) self.Bind(wx.EVT_MENU, self.MenuConfigDirs, id = MenuID.ConfigDirectories) # self.Bind(wx.EVT_MENU, self.MenuHelp, id = MenuID.Help) self.Bind(wx.EVT_MENU, self.MenuAbout, id = MenuID.About) self.SetMenuBar(MenuBar) def DebugPrintQuestResult(self, Result): Log(">>> Log quest result:") Log(sys.getrefcount(Result)) for (Key, Value) in Result.items(): Log("Key '%s' (%s), value '%s' (%s)"%(Key, sys.getrefcount(Key), Value, sys.getrefcount(Value))) if type(Value) == types.ListType: for Entry in Value: Log(" List entry '%s' (%s)"%(Entry, sys.getrefcount(Entry))) def RequestQuestGroupPath(self): # windows specific: Dir = os.getcwd() import win32ui Dialog = win32ui.CreateFileDialog(1, ".qst", "", 0, "Quest files (*.qst)|*.qst|All Files (*.*)|*.*|") Dialog.DoModal() os.chdir(Dir) return Dialog.GetPathName() def RequestGBAROMPath(self): WildCard = "GBA game (*.gba)|*.gba|Compressed GBA game (*.zip)|*.zip|All Files (*.*)|*.*" GBADir = Global.Config.Directories[Config.DirectoryConfig.GBA] if not GBADir: GBADir = os.getcwd() Dialog = wx.FileDialog(self, message = "Choose a game to play", defaultDir = GBADir, defaultFile="", wildcard = WildCard, style = wx.OPEN) Result = Dialog.ShowModal() if Result == wx.ID_OK: Paths = Dialog.GetPaths() else: Paths = [] Dialog.Destroy() if len(Paths) > 0: return Paths[0] def RequestMAMEROMPath(self): WildCard = "MAME rom file (*.zip)|*.zip|All Files (*.*)|*.*" MAMEDir = Global.Config.Directories[Config.DirectoryConfig.Arcade] if not MAMEDir: MAMEDir = os.getcwd() Dialog = wx.FileDialog(self, message = "Choose a game to play", defaultDir = MAMEDir, defaultFile="", wildcard = WildCard, style = wx.OPEN) Result = Dialog.ShowModal() if Result == wx.ID_OK: Paths = Dialog.GetPaths() else: Paths = [] Dialog.Destroy() if len(Paths) > 0: return Paths[0] def RequestNESROMPath(self): WildCard = "NES game (*.nes)|*.nes|Compressed NES game (*.zip)|*.zip|All Files (*.*)|*.*" NESDir = Global.Config.Directories[Config.DirectoryConfig.NES] if not NESDir: NESDir = os.getcwd() Dialog = wx.FileDialog(self, message = "Choose a game to play", defaultDir = NESDir, defaultFile="", wildcard = WildCard, style=wx.OPEN) Result = Dialog.ShowModal() if Result == wx.ID_OK: Paths = Dialog.GetPaths() else: Paths = [] Dialog.Destroy() if len(Paths) > 0: return Paths[0] def ComplainNotImplemented(self, *args, **kw): self.App.ShowMessage("You can't do that...yet.", "Not implemented") def MenuAbout(self, Event): Log(">>> ABOUT nekofami...") Info = wx.AboutDialogInfo() Info.Name = "Retromancer" Info.Version = Global.RetromancerVersion Info.Copyright = "All games and emulators (C) their respective creators" Info.Description = wordwrap(AboutBoxText, 350, wx.ClientDC(self)) Info.WebSite = ("http://necrofamicon.com", "Retromancer homepage") # Then we call wx.AboutBox giving it that info object wx.AboutBox(Info) def MenuHelp(self, Event): DocsPath = os.path.join("docs", "index.html") os.startfile(DocsPath) def MenuExit(self, Event): self.Close() def MenuLoadPlayer(self, Event): try: WildCard = "Retromancer SaveGame (*.sav)|*.sav|All Files (*.*)|*.*" Dialog = wx.FileDialog(self, message = "Choose a saved game to load", defaultDir = os.getcwd(), defaultFile="", wildcard = WildCard, style=wx.OPEN | wx.CHANGE_DIR) Result = Dialog.ShowModal() if Result == wx.ID_OK: Paths = Dialog.GetPaths() else: Paths = [] Dialog.Destroy() if len(Paths) > 0: FilePath = Paths[0] try: Player = GamePlayer.Player() Player.Load(FilePath) except: LogException() self.App.ShowMessage("Error loading save-file!") return self.App.SetPlayer(Player) except: LogException() def MenuNewPlayer(self, Event): try: Dialog = wx.TextEntryDialog(self, "A new player is ready to begin the adventure...\nPlease enter your name:", "Here comes a new challenger!", "", wx.OK) Result = Dialog.ShowModal() if Result != wx.ID_OK: return PlayerName = Dialog.GetValue() DummyTable = string.maketrans("", "") PlayerName = string.translate(PlayerName, DummyTable, "/\\:*?\"><|") if not PlayerName: return Player = GamePlayer.Player() Player.Name = PlayerName SaveFilePath = Player.GetFilePath() if os.path.exists(SaveFilePath): # Prompt to over-write: Dialog = wx.MessageDialog(self, "Savefile for '%s' exists already. Overwrite the old save?"%PlayerName, 'Overwrite?', style = wx.OK | wx.CANCEL) Result = Dialog.ShowModal() Log("Result: %s vs %s"%(Result, wx.ID_OK)) Dialog.Destroy() if Result != wx.ID_OK: Log("NOT creating the new player.") return #Global.Config.CurrentPlayer = Player.Name Log(">>>Init player info...") Player.InitQuestMapInfo() Player.Save() self.App.SetPlayer(Player) except: LogException() def MenuLoadQuests(self, Event): QuestPath = self.RequestQuestGroupPath() if not QuestPath: return self.App.LoadQuestGroup(QuestPath) def MenuOpenMAME(self, Event): ROMPath = self.RequestMAMEROMPath() if not ROMPath: return Stub = os.path.splitext(os.path.split(ROMPath)[1])[0] self.App.LaunchMAME(Stub) def MenuOpenGBA(self, Event): ROMPath = self.RequestGBAROMPath() if not ROMPath: return self.App.LaunchGBA(ROMPath) def MenuOpenNES(self, Event): try: ROMPath = self.RequestNESROMPath() if not ROMPath: return self.App.LaunchNES(ROMPath) except: LogException() def MenuConfigDirs(self, Event): Dialog = DirConfigDialog.DirConfigDialog(self.App.Config, self, -1, "Directory config", size = (300, 500), style = wx.DEFAULT_DIALOG_STYLE) Dialog.CenterOnScreen() # this does not return until the dialog is closed. ReturnValue = Dialog.ShowModal() if ReturnValue == wx.ID_OK: Log("OK! - time to set directories...") for Key in range(Config.DirectoryConfig.DirCount): #for Key in self.App.Config.Directories.keys(): Control = Dialog.DirectoryTextControls[Key] Value = Control.GetValue() Log("CONFIG: %s, %s"%(Key, Value)) self.App.Config.Directories[Key] = Value self.App.Config.Save() self.App.PyMAME.SetOption("rompath", self.App.Config.Directories[Config.DirectoryConfig.Arcade]) else: Log("Canceled - directory config unchanged") Dialog.Destroy() def MenuConfigKeys(self, Event): Dialog = KeyConfigDialog.KeyConfigDialog(self.App.Config.KeyConfig, self, -1, "Key config", size = (300, 500), style = wx.DEFAULT_DIALOG_STYLE) Dialog.CenterOnScreen() # this does not return until the dialog is closed. ReturnValue = Dialog.ShowModal() if ReturnValue == wx.ID_OK: Log("OK! - time to set key-config...") self.App.Config.KeyConfig = Dialog.KeyConfig self.App.Config.Save() else: Log("Canceled - key config unchanged") Dialog.Destroy() def PopulateQuestList(self, QuestGroup): self.QuestPanel.PopulateQuestList(QuestGroup) pass def MenuTestOptionB(self, Event): Sound = wx.Sound(r"c:\swt\foo.wav") Sound.Play(wx.SOUND_ASYNC) def MenuTestOptionA(self, Event): try: Log("Test...") Map = Global.Metagame.Maps[Global.Player.CurrentMap] CurrentRoom = Map.Rooms[Global.Player.CurrentRoom] Log("Current room %s"%CurrentRoom) if CurrentRoom.QuestID != None: Quest = Global.Metagame.Quests[CurrentRoom.QuestID] ResultsList = Global.Player.DebugClearQuest(Quest.ID) Reward = Global.Player.GetQuestReward(Quest, ResultsList) Global.Player.Money += Reward.Money Global.Player.NoteQuestRecords(Quest, ResultsList) if Reward.Money > 0: Dialog = UIQuestReward.QuestRewardDialog(self, Reward) Dialog.ShowModal() Dialog.Destroy() except: LogException() class NecroApp(wx.App): def __init__(self, *args, **kw): wx.App.__init__(self, 0, *args, **kw) #self.KeyConfig = [56, 29, 15, 28, 200, 208, 203, 205, 0, 0, 0, 0, 114, 13] self.CurrentQuestGroupPath = None self.PyMAME = None self.PyNES = None self.PyVBA = None self.QuestRunningFlag = 0 def ShowMessage(self, Message): Dialog = wx.MessageDialog(self, Message, "Retromancer") Dialog.ShowModal() Dialog.Destroy() def LoadConfiguration(self): Global.Config = Config.NecroConfig() self.Config = Global.Config self.Config.Load() self.PyMAME.SetOption("rompath", self.Config.Directories[Config.DirectoryConfig.Arcade]) def OnInit(self): Log(">>>>>>OnInit() called!") self.BuildWidgets() self.keepGoing = True Log(">>>Widgets built.") return True def BuildWidgets(self): self.Frame = NecroFrame(self, None, "Retromancer") self.Frame.Show(True) self.SetTopWindow(self.Frame) self.BuildIcon() def BuildIcon(self): import win32api exeName = win32api.GetModuleFileName(win32api.GetModuleHandle(None)) Icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO) self.Frame.SetIcon(Icon) def ShowMessage(self, MessageText, Title = "Retromancer alert"): Dialog = wx.MessageDialog(self.Frame, MessageText, Title, wx.OK | wx.ICON_INFORMATION) Dialog.ShowModal() Dialog.Destroy() def LoadMetagame(self, QuestFilePath): Metagame = GameMap.MetagameClass() try: Metagame.Load(QuestFilePath) except: LogException() self.ShowMessage("Error parsing quest - see logfile for errors.") return 0 self.CurrentQuestGroupPath = QuestFilePath Global.Metagame = Metagame self.Frame.PopulateQuestList(Metagame) def SetPlayer(self, Player): Global.Player = Player Log("Player location: (%s, %s)"%(Player.CurrentMap, Player.CurrentRoom)) Log("Prepping player file...") Player.InitQuestMapInfo() Player.Save() Global.Config.CurrentPlayer = Player.Name Global.Config.Save() Log("Player and config has been saved.") # Propagate info to windows: Log("Enter map %s, room %s"%(Player.CurrentMap, Player.CurrentRoom)) try: Global.UIMap.SetFocus() Global.UIMap.EnterMap(Player.CurrentMap, Player.CurrentRoom) Global.UIInfo.BuildPlayerWidgets() except: LogException() def LoadPlayer(self): """ Global.Player should be set. If our configuration specifies a player and there's a savefile for the player, then use that player. If not, ask the player for their name. """ PlayerName = Global.Config.CurrentPlayer SaveFilePath = "%s.sav"%PlayerName GreetFlag = 0 if os.path.exists(SaveFilePath): Player = GamePlayer.Player() try: Player.Load(SaveFilePath) GreetFlag = 1 except: LogException() Player = GamePlayer.Player() else: Dialog = wx.TextEntryDialog(self.Frame, "Welcome to Retromancer. Please enter your name:", "Who are you?", "", wx.OK) Result = Dialog.ShowModal() PlayerName = Dialog.GetValue() DummyTable = string.maketrans("", "") PlayerName = string.translate(PlayerName, DummyTable, "/\\:*?\"><|") if not PlayerName: PlayerName = "AAA" Player = GamePlayer.Player() Player.Name = PlayerName SaveFilePath = Player.GetFilePath() if os.path.exists(SaveFilePath): Player.Load() GreetFlag = 1 Global.Config.CurrentPlayer = PlayerName self.SetPlayer(Player) if GreetFlag: self.GreetPlayer() else: UIConversation.ShowConversation(self.Frame, "intro") def GreetPlayer(self): # Show a dialog box: Map = Global.Metagame.Maps[Global.Player.CurrentMap] DialogText = """Welcome back, %s!\n\nYour adventures have brought you to the %s.\n\n"""%(Global.Player.Name, Map.Name) if (Map.Type == GameMap.MapType.LifeDungeon): DialogText += "In this dungeon, you have limited lives." elif (Map.Type == GameMap.MapType.TimeDungeon): DialogText += "In this dungeon, you have limited in-game time." else: DialogText += "Enjoy your stay." Dialog = UIMessage.MessageDialog(self.Frame, DialogText, "Welcome again to the stage of history") Dialog.ShowModal() def SetPyMAMEKeyConfig(self): TranslatedKeys = [] # Translate WX keystrokes into MAME key codes: for Key in self.Config.KeyConfig: FixedKey = Keystroke.MAMEKeyMapping.get(Key, Key) TranslatedKeys.append(FixedKey) #Log("PyMAME: %s -> %s"%(Key, FixedKey)) PyMAME.SetKeyConfig(TranslatedKeys) def SetPyNESKeyConfig(self): Keystroke.SetPyNESKeyConfig(self.Config.KeyConfig) def ParseCommandLine(self): # Default: self.QuestPath = os.path.join("Quests", "Dot", "Dot.qst") (Options, Args) = getopt.getopt(sys.argv[1:], "q:") for (Option, Value) in Options: if Option == "-q": self.QuestPath = Value if not os.path.exists(self.QuestPath): Log("** Warning: Quest file '%s' doesn't seem to exist!"%self.QuestPath) def RedirectStdout(self): # Redirect LOGGING pass def LaunchGBA(self, ROMPath): self.QuestRunningFlag = 1 try: TranslatedConfig = [] for Key in Global.Config.KeyConfig: MappedKey = Keystroke.VBAKeyMapping.get(Key, Key) Log("%s maps to %s"%(Key, MappedKey)) TranslatedConfig.append(MappedKey) Log("Config: %s"%TranslatedConfig) PyVBA.SetKeyConfig(TranslatedConfig) #%%% Thread = VBARunnerThread(ROMPath) Thread.Start() Log(">>>Launched VBARunner...") while Thread.IsRunning(): Log(">>>Waiting for VBARunner...") time.sleep(0.1) except: LogException() self.QuestRunningFlag = 0 def LaunchNES(self, ROMPath): self.QuestRunningFlag = 1 try: self.SetPyNESKeyConfig() self.PyNES.PlayGame(ROMPath) except: LogException() self.QuestRunningFlag = 0 def LaunchMAME(self, DriverName): self.QuestRunningFlag = 1 try: self.SetPyMAMEKeyConfig() self.PyMAME.PlayGame(DriverName) except: LogException() self.QuestRunningFlag = 0 def LaunchQuest(self, Quest, Map): if self.QuestRunningFlag: return Log("LAUNCH QUEST: %s, %s"%(Quest, Quest.ID)) self.QuestRunningFlag = 1 RawResultsList = [] Quest.MasterTicksLeft = Global.Player.CurrentTime Quest.MasterLivesLeft = Global.Player.CurrentLives Game = Global.GetGame(Quest.GameType, Quest.DriverName) Memloc = Game.GetMemloc("Lives") if Memloc != None: Quest.MasterLivesLoc = Memloc.Location Quest.MasterLivesOffset = Memloc.Offset Log("Quest.MasterLivesLoc = %s"%Quest.MasterLivesLoc) Quest.DungeonFlag = -1 if Map: if Map.Type == GameMap.MapType.TimeDungeon: Quest.DungeonFlag = 2 elif Map.Type == GameMap.MapType.LifeDungeon: if Quest.LifekeepFlag == 1: Quest.DungeonFlag = 1 else: Quest.DungeonFlag = 0 try: if Quest.GameType == GameInfo.GameType.MAME: RawResultsList = self.LaunchQuestArcade(Quest) elif Quest.GameType == GameInfo.GameType.NES: RawResultsList = self.LaunchQuestNES(Quest) elif Quest.GameType == GameInfo.GameType.GBA: RawResultsList = self.LaunchQuestGBA(Quest) else: self.ShowMessage("Error: quest has weird game type '%s'"%Quest.GameType, "A Dream Deferred") return None except: LogException() self.QuestRunningFlag = 0 if RawResultsList == None: RawResultsList = [] ResultsList = [] for RawResult in RawResultsList: Result = Quest.GetResultsFromDict(RawResult) if Result: ResultsList.append(Result) if not ResultsList: Log(">>> WARNING: Emulator returned no results. It should at least have returned an ABORT result.") Record = NecroQuest.QuestRecordClass() Record.Result = NecroQuest.QuestState.Abort Record.MasterLivesLeft = Global.Player.CurrentLives - 1 ResultsList.append(Record) Map = Global.Metagame.Maps[Global.Player.CurrentMap] # Figure out the quest rewards: try: Reward = Global.Player.GetQuestReward(Quest, ResultsList) Global.Player.Money += Reward.Money except: LogException() DungeonFailFlag = 0 try: # Quest completion should be SAVED by the player: DungeonFailFlag = Global.Player.NoteQuestRecords(Quest, ResultsList) except: LogException() if DungeonFailFlag: Stuff = "lives" if Map.Type == GameMap.MapType.TimeDungeon: Stuff = "time" DungeonFailMessage = "You have perished in the dungeon %s, having run out of %s."%(Map.Name, Stuff) DungeonFailMessage += "\n\nYou slip into the void..." DungeonFailMessage += "\n\nSome time later, you awaken at the dungeon entrance. You resolve to try again, with your new knowledge and skills..." Dialog = UIMessage.MessageDialog(self.Frame, DungeonFailMessage, "Mission Failed") Dialog.ShowModal() Dialog.Destroy() elif Reward.Money > 0: Dialog = UIQuestReward.QuestRewardDialog(self.Frame, Reward) Dialog.ShowModal() Dialog.Destroy() return ResultsList def LaunchQuestArcade(self, Quest): import PyMAME Log("SetPyMAMEKeyConfig()") self.SetPyMAMEKeyConfig() try: ResultList = PyMAME.PlayGame(Quest.DriverName, Quest.GetSaveFilePath(), Quest) except: LogException() self.ShowMessage("Error - unable to launch the quest. See logfile for details.", "A Dream Deferred") return return ResultList def LaunchQuestNES(self, Quest): import PyNES ROMPath = Quest.Game.GetNESPath() if not ROMPath: self.ShowMessage("Unable to find NES ROM '%s'"%Quest.DriverName) return SavePath = Quest.GetSaveFilePath() if not os.path.exists(SavePath): self.ShowMessage("Unable to find quest savestate '%s'"%SavePath) return PatchFilePath = Quest.GetPatchFilePath() try: self.SetPyNESKeyConfig() except: LogException() self.ShowMessage("Error - unable to set KeyConfig. See logfile for details.", "A Dream Deferred") return try: ResultsList = PyNES.PlayGame(ROMPath, SavePath, Quest, PatchFilePath) except: LogException() self.ShowMessage("Error - unable to launch the quest. See logfile for details.", "A Dream Deferred") return return ResultsList def LaunchQuestGBA(self, Quest): import PyVBA ROMPath = Quest.Game.GetGBAPath() if not ROMPath: self.ShowMessage("Unable to find GBA ROM '%s'"%Quest.DriverName) return SavePath = Quest.GetSaveFilePath() if not os.path.exists(SavePath): self.ShowMessage("Unable to find quest savestate '%s'"%SavePath) return PatchFilePath = Quest.GetPatchFilePath() TranslatedConfig = [] for Key in Global.Config.KeyConfig: MappedKey = Keystroke.VBAKeyMapping.get(Key, Key) Log("%s maps to %s"%(Key, MappedKey)) TranslatedConfig.append(MappedKey) Log("Config: %s"%TranslatedConfig) PyVBA.SetKeyConfig(TranslatedConfig) Thread = VBARunnerThread(ROMPath, SavePath, Quest, PatchFilePath) Thread.Start() while Thread.IsRunning(): Log("GBA running...") time.sleep(0.5) ResultList = Thread.ResultsList return ResultList def ShowQuestStatsScreen(self, Quest): import UIQuestStats Dialog = UIQuestStats.QuestStatsScreen(self.Frame, Quest) Result = Dialog.ShowModal() Dialog.Destroy() def InitGameInfo(): FileName = os.path.join("Quests", "Games.xml") GameInfo.ParseGameInfoFromFile(FileName) def UpdateLibrary(PathHere, PathThere): NeedUpdate = 0 try: StatHere = os.stat(PathHere) except: StatHere = None NeedUpdate = 1 if StatHere: try: StatThere = os.stat(PathThere) except: NeedUpdate = 0 StatThere = None if StatHere and StatThere: if StatHere.st_mtime < StatThere.st_mtime: NeedUpdate = 1 if NeedUpdate: Command = "copy \"%s\" \"%s\""%(PathThere, PathHere) os.system(Command) def UpdatePyMAMEBuild(): # Update build: PathHere = "PyMAME.pyd" PathThere = r"build\lib.win32-2.5\PyMAME.pyd" UpdateLibrary(PathHere, PathThere) def UpdatePyNESBuild(): # Update build: PathHere = "PyNES.pyd" PathThere = r"build\lib.win32-2.5\PyNES.pyd" UpdateLibrary(PathHere, PathThere) def UpdatePyVBABuild(): # Update build: PathHere = "PyVBA.pyd" PathThere = r"build\lib.win32-2.5\PyVBA.pyd" UpdateLibrary(PathHere, PathThere) if __name__ == "__main__": # Update and import emulators: UpdatePyMAMEBuild() Log(">>>PyMAME import:") import PyMAME UpdatePyNESBuild() Log(">>>NES import:") try: import PyNES except: LogException() UpdatePyVBABuild() Log(">>>PyVBA import:") import PyVBA Global.ImageHandler = Global.ImageHandlerClass() InitGameInfo() Log("Instantiate app:") App = NecroApp() Log(">>>App instantiated!") Global.App = App App.PyMAME = PyMAME App.PyNES = PyNES Log(">>>Load config:") App.LoadConfiguration() Log("App instantiated!") App.ParseCommandLine() App.LoadMetagame(App.QuestPath) try: App.LoadPlayer() except: LogException() App.RedirectStdout() TempLogFile.close() App.MainLoop()