""" Player: Represents a player's state within a metagame. Everything that CHANGES about a map during the course of the game is tracked in the player. """ import os import sys import time import types import struct import GameItem import GameMap import Global import Utils from Global import Log import NecroQuest # Cache some sizes, for reading/writing binary files. IntSize = struct.calcsize("i") FloatSize = struct.calcsize("f") IIFSize = struct.calcsize("iif") IISize = struct.calcsize("ii") QuestRecordSize = struct.calcsize(">>Current lives: %s"%LastRecord.MasterLivesLeft) if Map.Type == GameMap.MapType.LifeDungeon: self.CurrentLives = LastRecord.MasterLivesLeft if self.CurrentLives <= 0: DungeonFailFlag = 1 self.FailDungeon() elif Map.Type == GameMap.MapType.TimeDungeon: self.CurrentTime = LastRecord.MasterTicksLeft if self.CurrentTime <= 0: DungeonFailFlag = 1 self.FailDungeon() for Room in Map.Rooms: if not hasattr(Room, "QuestID") or Room.QuestID != Quest.ID: continue OldRoomClearFlag = MapInfo.RoomClearFlags.get(Room.ID, 0) Log(">>> Room %s quest %s clear flag: Old %s new %s"%(Room.ID, Quest.ID, OldRoomClearFlag, ClearFlag)) if ClearFlag and not OldRoomClearFlag: MapChangedFlag = 1 MapInfo.RoomClearFlags[Room.ID] = 1 self.UpdateSavefilePlayer() # Save the quest stuff: self.UpdateSavefileQuest(Quest.ID) # Save the map change: if MapChangedFlag: self.UpdateSavefileMap(self.CurrentMap) # Move to different map, if necessary: # Update images: Global.UIMap.UpdateRoomImages() # Update info panel: Global.UIInfo.BuildPlayerWidgets() for Record in RecordList: if Record.Result > NecroQuest.QuestState.Failure: # Add a visit, probably: if (self.LastVisits[-1] != Quest.ID or self.LastVisits[-2] != Quest.ID): self.LastVisits.append(Quest.ID) self.LastVisits = self.LastVisits[-self.RECENT_QUEST_COUNT:] return DungeonFailFlag def GetFilePath(self): return "%s.sav"%self.Name def Load(self, FilePath = None): """ Load a saved game! """ if FilePath == None: FilePath = self.GetFilePath() File = open(FilePath, "rb") # skip magic-number: File.read(8) Version = struct.unpack(" 0: Info.TicksToComplete[1] = Ticks Ticks = struct.unpack(" 0: Info.TicksToComplete[2] = Ticks Ticks = struct.unpack(" 0: Info.TicksToComplete[3] = Ticks # Tries to complete: Tries = struct.unpack(" 0: Info.TriesToComplete[1] = Tries Tries = struct.unpack(" 0: Info.TriesToComplete[2] = Tries Tries = struct.unpack(" 0: Info.TriesToComplete[3] = Tries EBA = struct.unpack("= 0): Info.EBA[1] = EBA EBA = struct.unpack("= 0): Info.EBA[2] = EBA EBA = struct.unpack("= 0): Info.EBA[3] = EBA # Recent records: for Index in range(self.MAX_RECENT_RECORDS): String = File.read(QuestRecordSize) Record = self.UnpackQuestRecord(String) if Record: Info.RecentRecords.append(Record) # Top records: for Index in range(self.MAX_TOP_RECORDS): String = File.read(QuestRecordSize) Record = self.UnpackQuestRecord(String) if Record: Info.TopRecords.append(Record) def LoadMapInfo(self, File): "Helper for Load: Load map info (clear-flags and open doors)" #Log("Maps start at %s"%File.tell()) MapCount = struct.unpack(" Key[1]): continue File.write(struct.pack("= 0: Item = GameItem.ItemClass(ItemType, Uses) self.Equipment.append(Item) for Index in range(self.MAX_INVENTORY_SIZE): (ItemType, Uses) = struct.unpack("= 0: Item = GameItem.ItemClass(ItemType, Uses) self.Inventory.append(Item) for Index in range(self.MAX_EQUIP_SIZE): (ItemType, Uses) = struct.unpack("= 0: Item = GameItem.ItemClass(ItemType, Uses) self.PreDungeonEquipment.append(Item) for Index in range(self.MAX_INVENTORY_SIZE): (ItemType, Uses) = struct.unpack("= 0: Item = GameItem.ItemClass(ItemType, Uses) self.PreDungeonInventory.append(Item) def SavePlayer(self, File): """ Helper for Save: Write the core player-character state. We call SavePlayer once, then we call SaveMap and SaveQuest. """ File.write(struct.pack("<255s", self.Name)) File.write(struct.pack("<3s", self.Initials)) Log("Save location: %s, %s, %s"%(self.CurrentMap, self.CurrentRoom, self.PreviousRoom)) File.write(struct.pack(" Key[1]): continue File.write(struct.pack(">>Update savefile for quest %s"%QuestID) # Save quest info for ONE quest to our savefile. File = open(self.GetFilePath(), "r+b") QuestDataSize = (IntSize * 13) + (FloatSize * 3) + (QuestRecordSize * (self.MAX_RECENT_RECORDS + self.MAX_TOP_RECORDS)) Log("QuestDataSize is %s"%QuestDataSize) File.seek(self.FilePosQuest + 4 + QuestID * QuestDataSize) Log("Seek: %s + 4 + %s * %s"%(self.FilePosQuest, QuestID, QuestDataSize)) QuestInfo = self.QuestInfoDict[QuestID] self.SaveOneQuestInfo(QuestInfo, File) File.close() def GetRoomClearFlag(self, RoomID, MapID = None): if MapID == None: MapID = self.CurrentMap return self.MapInfoDict[MapID].RoomClearFlags.get(RoomID, 0) def GetPathClearFlag(self, RoomIDA, RoomIDB, MapID = None): if MapID == None: MapID = self.CurrentMap return self.MapInfoDict[MapID].DoorOpenFlags.get((RoomIDA, RoomIDB), 0) def GetBestCompletionString(self, QuestID): """ Return our best completion as a string. """ QuestInfo = self.QuestInfoDict.get(QuestID, None) if not QuestInfo: return "" if QuestInfo.TotalPlays.get(NecroQuest.QuestState.Gold, 0): return "Gold" if QuestInfo.TotalPlays.get(NecroQuest.QuestState.Silver, 0): return "Silver" if QuestInfo.TotalPlays.get(NecroQuest.QuestState.Bronze, 0): return "Bronze" if QuestInfo.TotalPlays.get(NecroQuest.QuestState.Failure, 0): return "Failure" return "" def DebugPrint(self): print "Player: %s (%s)"%(self.Name, self.Initials) print "Location: Map %s room %s"%(self.CurrentMap, self.CurrentRoom) def GetMapInfo(self, MapID = None): if not MapID: MapID = self.CurrentMap return self.MapInfoDict[MapID] if __name__ == "__main__": import GameInfo import GameMap FileName = os.path.join("Quests", "Games.xml") GameInfo.ParseGameInfoFromFile(FileName) Metagame = GameMap.MetagameClass() Metagame.Load(r"Quests\Dot\Dot.qst") Global.Metagame = Metagame # Unit test: SaveFileName = sys.argv[1] TestPlayer = Player() TestPlayer.Load(SaveFileName) TestPlayer.Name = "swt" TestPlayer.DebugPrint() TestPlayer.CurrentRoom = 4 TestPlayer.Save(SaveFileName)