import sys import time import wx import Utils import Global import Config import GameInfo import UIImages import UIUtils import GameMap import NecroQuest import JoyTracker from Global import Log, LogException class NoFocusButton(wx.Button): def __init__(self, *args, **kw): wx.Button.__init__(*args, **kw) def AcceptsFocusFromKeyboard(self): return 0 class SimpleListControl(wx.ListCtrl, wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin): def __init__(self, parent, ID, pos = wx.DefaultPosition, size = wx.DefaultSize, style=0): wx.ListCtrl.__init__(self, parent, ID, pos, size, style) wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin.__init__(self) class QuestStatsScreen(wx.Dialog, JoyTracker.JoyTracker): def __init__(self, Parent, Quest, *args, **kw): self.NavPauseType = None self.CompletionThrobber = None try: wx.Dialog.__init__(self, Parent, title = "Quest stats", style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, *args, **kw) # style = wx.OK, except: LogException() JoyTracker.JoyTracker.__init__(self) self.BackgroundColor = "black" self.ForegroundColor = "white" self.SetBackgroundColour(self.BackgroundColor) self.Quest = Quest self.QuestInfo = Global.Player.GetQuestInfo(Quest) self.BigFont = wx.Font(16, wx.SWISS, wx.NORMAL, wx.NORMAL) try: self.BuildWidgets() except: LogException() self.PopulateWidgets() self.FocusGamepadState = self.GetRawGamepad() self.Timer = wx.CallLater(100, self.OnTimer) self.NavigatePause = 0 self.StartQuestID = Quest.ID def GetQuestMapName(self): """ There's no link back from a quest to its map, so let's just brute-force it. """ for Map in Global.Metagame.Maps: for Room in Map.Rooms: if Room.QuestID == self.Quest.ID and Room.Type == GameMap.RoomTypes.Quest: return Map.Name def PopulateWidgets(self): "Called after creating widgets or after shifting to another quest. Fills in the values!" self.SetStarImages() self.PopulateRecordsBox(self.TopRecordBox, self.QuestInfo.TopRecords) self.PopulateRecordsBox(self.LatestRecordBox, self.QuestInfo.RecentRecords) self.QuestNameText.SetLabel(self.Quest.Name) self.QuestMapText.SetLabel("Map: %s"%self.GetQuestMapName()) Width = self.InstructionsText.GetSize().GetWidth() self.QuestNameText.Wrap(Width) Game = self.Quest.Game SystemName = GameInfo.GameType.PrettyNames[Game.GameType] Label = "From: %s [%s]"%(Game.GameName, SystemName) self.GameNameText.SetLabel(Label) FixedInstructions = Config.GetFixedInstructions(self.Quest.Instructions, Global.Config) Label = "Gold clear count: %s"%self.QuestInfo.TotalPlays.get(NecroQuest.QuestState.Gold, 0) self.GoldClearCountText.SetLabel(Label) Label = "Silver clear count: %s"%self.QuestInfo.TotalPlays.get(NecroQuest.QuestState.Silver, 0) self.SilverClearCountText.SetLabel(Label) Label = "Bronze clear count: %s"%self.QuestInfo.TotalPlays.get(NecroQuest.QuestState.Bronze, 0) self.BronzeClearCountText.SetLabel(Label) Label = "Misses: %s"%self.QuestInfo.TotalPlays.get(NecroQuest.QuestState.Failure, 0) self.FailureCountText.SetLabel(Label) Label = "Gold EBA: %.3f"%self.QuestInfo.EBA.get(NecroQuest.QuestState.Gold, 0) self.GoldEBAText.SetLabel(Label) Label = "Silver EBA: %.3f"%self.QuestInfo.EBA.get(NecroQuest.QuestState.Silver, 0) self.SilverEBAText.SetLabel(Label) Label = "Bronze EBA: %.3f"%self.QuestInfo.EBA.get(NecroQuest.QuestState.Bronze, 0) self.BronzeEBAText.SetLabel(Label) self.InstructionsText.SetLabel(FixedInstructions) self.InstructionsText.Wrap(Width) if self.CompletionThrobber: self.CompletionThrobber.Destroy() self.CompletionThrobber = None BestResult = Global.Player.GetBestCompletionString(self.Quest.ID) ThrobberName = Utils.GetCompletionThrobberName(BestResult) self.CompletionThrobber = UIImages.Throbber(self, ThrobberName) self.NameAndMedalSizer.Add(self.CompletionThrobber) self.Layout() def CycleQuests(self, CycleDirection, Flag): QuestID = self.Quest.ID QuestCount = len(Global.Metagame.Quests) while 1: QuestID += CycleDirection if (QuestID < 0): QuestID = QuestCount -1 elif QuestID >= QuestCount: QuestID = 0 if QuestID == self.Quest.ID: # We cycled all the way around. There are no more # quests of the type requested! if Flag == None: Message = "You don't know of any other quests." else: Message = "There are no more %s quests."%Flag Dialog = wx.MessageDialog(self, Message, "Nothing found.", wx.OK | wx.ICON_INFORMATION) Dialog.ShowModal() Dialog.Destroy() return Quest = Global.Metagame.Quests[QuestID] QuestInfo = Global.Player.GetQuestInfo(Quest) # Skip over any quests which have never been visited yet: if QuestInfo.VisitFlag == 0: continue Medal = QuestInfo.HasMedal() if Flag == "unfinished" and Medal not in (0, None): continue if Flag == "non-perfect" and Medal == 1: continue break self.Quest = Quest self.QuestInfo = QuestInfo self.PopulateWidgets() def OnTimer(self, *args, **kw): NavPauseTime = 15 if (self.NavigatePause > 0): self.NavigatePause -= 1 if self.NavigatePause == 0: self.NavPauseType = None try: self.SetGamepad() if self.ButtonState[Config.KeyConfig.ButtonB] or self.ButtonState[Config.KeyConfig.ButtonA]: self.Destroy() elif self.KeyState.get(wx.WXK_RETURN, 0) or self.KeyState.get(wx.WXK_NUMPAD_ENTER, 0): self.Destroy() if self.ButtonState[Config.KeyConfig.Left] and self.NavPauseType != Config.KeyConfig.Left: self.OnClickPrev(None) self.NavigatePause = NavPauseTime self.NavPauseType = Config.KeyConfig.Left elif self.ButtonState[Config.KeyConfig.Right] and self.NavPauseType != Config.KeyConfig.Right: self.OnClickNext(None) self.NavigatePause = NavPauseTime self.NavPauseType = Config.KeyConfig.Right elif self.ButtonState[Config.KeyConfig.RightTrigger] and self.NavPauseType != Config.KeyConfig.RightTrigger: self.OnClickNextOpen(None) self.NavigatePause = NavPauseTime self.NavPauseType = Config.KeyConfig.RightTrigger elif self.ButtonState[Config.KeyConfig.ButtonY] and self.NavPauseType != Config.KeyConfig.ButtonY: self.OnClickNextGold(None) self.NavigatePause = NavPauseTime self.NavPauseType = Config.KeyConfig.ButtonY if self.NavPauseType != None and not self.ButtonState[self.NavPauseType]: self.NavPauseType = None self.Timer.Restart(25) except: LogException() def BuildWidgets(self): self.MasterVerticalSizer = wx.BoxSizer(wx.VERTICAL) self.HorizontalSizer = wx.BoxSizer(wx.HORIZONTAL) self.Eater = UIUtils.KeyEater(self) self.HorizontalSizer.Add(self.Eater) LeftHalfSizer = wx.BoxSizer(wx.VERTICAL) RightHalfSizer = wx.BoxSizer(wx.VERTICAL) self.BuildInstructionsSide(LeftHalfSizer) self.BuildRecordsSide(RightHalfSizer) self.HorizontalSizer.Add(LeftHalfSizer, 3, wx.EXPAND | wx.LEFT, 5) self.HorizontalSizer.Add(RightHalfSizer, 3, wx.EXPAND | wx.RIGHT, 5) self.MasterVerticalSizer.Add(self.HorizontalSizer, 1, wx.EXPAND) self.BuildButtons() self.SetSizer(self.MasterVerticalSizer) self.MasterVerticalSizer.Fit(self) self.SetClientSizeWH(700, 550) self.SetAutoLayout(True) self.Layout() def PopulateRecordsBox(self, ListControl, Records): ListControl.ClearAll() ListControl.InsertColumn(0, "Date") ListControl.InsertColumn(1, "Result") ListControl.SetColumnWidth(0, 100) ListControl.SetColumnWidth(1, 50) ColumnIndex = 2 for Stat in self.Quest.Stats: ListControl.InsertColumn(ColumnIndex, str(Stat.GetNiceName())) ListControl.SetColumnWidth(ColumnIndex, 50) ColumnIndex += 1 ########################## for RecordIndex in range(len(Records)): QuestRecord = Records[RecordIndex] TimeTuple = time.localtime(QuestRecord.Timestamp) TimeStamp = "%s/%s/%s %s:%02d"%(TimeTuple[1], TimeTuple[2], TimeTuple[0], TimeTuple[3], TimeTuple[4]) #ItemText = self.GetQRecordListBoxString(QuestRecord) ListBoxIndex = ListControl.InsertStringItem(sys.maxint, TimeStamp) ListControl.SetStringItem(ListBoxIndex, 0, TimeStamp) ListControl.SetStringItem(ListBoxIndex, 1, NecroQuest.QuestState.Names.get(QuestRecord.Result, "???")) for StatIndex in range(len(QuestRecord.StatValues)): ListControl.SetStringItem(ListBoxIndex, StatIndex + 2, str(QuestRecord.StatValues[StatIndex])) ListControl.SetItemData(ListBoxIndex, RecordIndex) ListControl.currentItem = 0 def BuildButtons(self): "Along the bottom of the dialog we add 'ok' and other buttons" ButtonSizer = wx.BoxSizer(wx.HORIZONTAL) #ButtonSizer.SetBackgroundColour(wx.RED) PrevButton = wx.Button(self, -1, "Prev") self.Bind(wx.EVT_BUTTON, self.OnClickPrev, PrevButton) ButtonSizer.Add(PrevButton, 0, wx.LEFT, 5) NextButton = wx.Button(self, -1, "Next") self.Bind(wx.EVT_BUTTON, self.OnClickNext, NextButton) ButtonSizer.Add(NextButton, 0, wx.LEFT, 5) NextOpenButton = wx.Button(self, -1, "Next unfinished") self.Bind(wx.EVT_BUTTON, self.OnClickNextOpen, NextOpenButton) ButtonSizer.Add(NextOpenButton, 0, wx.LEFT, 5) NextGoldButton = wx.Button(self, -1, "Next non-perfect") self.Bind(wx.EVT_BUTTON, self.OnClickNextGold, NextGoldButton) ButtonSizer.Add(NextGoldButton, 0, wx.LEFT, 5) ButtonSizer.Add((5, 5), 1, wx.EXPAND) self.OKButton = wx.Button(self, wx.ID_OK) self.OKButton.SetDefault() ButtonSizer.Add(self.OKButton, 0, wx.ALIGN_RIGHT | wx.RIGHT, 5) self.MasterVerticalSizer.Add(ButtonSizer, 0, wx.EXPAND | wx.TOP, 3) def OnClickPrev(self, Event): self.CycleQuests(-1, None) self.Eater.SetFocus() def OnClickNext(self, Event): self.CycleQuests(1, None) self.Eater.SetFocus() def OnClickNextOpen(self, Event): self.CycleQuests(1, "unfinished") self.Eater.SetFocus() def OnClickNextGold(self, Event): self.CycleQuests(1, "non-perfect") self.Eater.SetFocus() def OnClickStar(self, Event): try: Info = Global.Player.GetQuestInfo(self.Quest) NewStars = Event.GetId() - 1000 + 1 if NewStars != Info.Stars: Info.Stars = NewStars Log("Set stars: %s"%Info.Stars) self.SetStarImages() Global.Player.UpdateSavefileQuest(self.Quest.ID) except: LogException() self.Eater.SetFocus() def SetStarImages(self): Info = Global.Player.GetQuestInfo(self.Quest) GrayBitmap = Global.ImageHandler.GetImage("StarGray.png") GoldBitmap = Global.ImageHandler.GetImage("StarGold.png") for StarIndex in range(len(self.StarWidgets)): Widget = self.StarWidgets[StarIndex] if (StarIndex < Info.Stars): if not Widget.GoldFlag: self.StarWidgets[StarIndex].SetBitmapLabel(GoldBitmap) Widget.GoldFlag = 1 else: if Widget.GoldFlag: self.StarWidgets[StarIndex].SetBitmapLabel(GrayBitmap) Widget.GoldFlag = 0 def BuildRecordsSide(self, Sizer): "Build the right-hand side of the quest stats screen." # Add the stars-display: StarSizer = wx.BoxSizer(wx.HORIZONTAL) Text = wx.StaticText(self, -1, "My rating:") Text.SetForegroundColour(self.ForegroundColor) StarSizer.Add(Text, 0, wx.TOP, 6) self.StarWidgets = [] Bitmap = Global.ImageHandler.GetImage("StarGray.png") for Index in range(5): StarWidget = wx.BitmapButton(self, 1000 + Index, bitmap = Bitmap, style = wx.NO_BORDER) StarWidget.GoldFlag = 0 self.Bind(wx.EVT_BUTTON, self.OnClickStar, StarWidget) self.StarWidgets.append(StarWidget) StarSizer.Add(StarWidget, 0, wx.LEFT, 4) Sizer.Add(StarSizer) # Add two listboxes - one for top records, one for latest records. TextTop = wx.StaticText(self, -1, "Top plays:") TextTop.SetForegroundColour(self.ForegroundColor) TextLatest = wx.StaticText(self, -1, "Latest plays:") TextLatest.SetForegroundColour(self.ForegroundColor) self.TopRecordBox = SimpleListControl(self, -1, style = wx.LC_REPORT | wx.BORDER_NONE) self.LatestRecordBox = SimpleListControl(self, -1, style = wx.LC_REPORT | wx.BORDER_NONE) Sizer.Add(TextTop, 0, wx.ALIGN_CENTER | wx.ALL, 2) Sizer.Add(self.TopRecordBox, 2, wx.EXPAND) Sizer.Add(TextLatest, 0, wx.ALIGN_CENTER | wx.TOP, 5) Sizer.Add(self.LatestRecordBox, 2, wx.EXPAND | wx.TOP, 2) def BuildInstructionsSide(self, Sizer): # First row: Quest name and medal icon self.NameAndMedalSizer = wx.BoxSizer(wx.HORIZONTAL) self.QuestNameText = wx.StaticText(self, -1, "") self.QuestNameText.SetFont(self.BigFont) self.QuestNameText.SetForegroundColour(self.ForegroundColor) self.NameAndMedalSizer.Add(self.QuestNameText, 1, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5) Sizer.Add(self.NameAndMedalSizer) # Second row: Game map self.QuestMapText = wx.StaticText(self, -1, "") self.QuestMapText.SetForegroundColour(self.ForegroundColor) Sizer.Add(self.QuestMapText) # Third row: Game, platform, year, publisher self.GameNameText = wx.StaticText(self, -1, "") self.GameNameText.SetForegroundColour(self.ForegroundColor) Sizer.Add(self.GameNameText) # Padding: Sizer.Add(wx.Size(5, 5)) # Table of completions, playtime, EBA Info = Global.Player.QuestInfoDict[self.Quest.ID] TotalPlays = 0 TotalPlays += Info.TotalPlays.get(NecroQuest.QuestState.Gold, 0) TotalPlays += Info.TotalPlays.get(NecroQuest.QuestState.Silver, 0) TotalPlays += Info.TotalPlays.get(NecroQuest.QuestState.Bronze, 0) TotalPlays += Info.TotalPlays.get(NecroQuest.QuestState.Failure, 0) TotalPlays += Info.TotalPlays.get(NecroQuest.QuestState.Abort, 0) # Clear counts: self.GoldClearCountText = wx.StaticText(self, -1, "") self.GoldClearCountText.SetForegroundColour(self.ForegroundColor) Sizer.Add(self.GoldClearCountText) self.SilverClearCountText = wx.StaticText(self, -1, "") self.SilverClearCountText.SetForegroundColour(self.ForegroundColor) Sizer.Add(self.SilverClearCountText) self.BronzeClearCountText = wx.StaticText(self, -1, "") self.BronzeClearCountText.SetForegroundColour(self.ForegroundColor) Sizer.Add(self.BronzeClearCountText) self.FailureCountText = wx.StaticText(self, -1, "") self.FailureCountText.SetForegroundColour(self.ForegroundColor) Sizer.Add(self.FailureCountText) self.GoldEBAText = wx.StaticText(self, -1, "") self.GoldEBAText.SetForegroundColour(self.ForegroundColor) Sizer.Add(self.GoldEBAText) self.SilverEBAText = wx.StaticText(self, -1, "") self.SilverEBAText.SetForegroundColour(self.ForegroundColor) Sizer.Add(self.SilverEBAText) self.BronzeEBAText = wx.StaticText(self, -1, "") self.BronzeEBAText.SetForegroundColour(self.ForegroundColor) Sizer.Add(self.BronzeEBAText) # Instructions StaticBox = wx.StaticBox(self, -1, "Instructions") StaticBox.SetForegroundColour(self.ForegroundColor) StaticBoxSizer = wx.StaticBoxSizer(StaticBox, wx.VERTICAL) Sizer.Add(StaticBoxSizer, 1, wx.EXPAND | wx.ALL, 5) self.InstructionsText = wx.StaticText(self, -1, "") self.InstructionsText.SetForegroundColour(self.ForegroundColor) StaticBoxSizer.Add(self.InstructionsText, 1, wx.EXPAND) # Widgets for data-miner data (seeeeecrets), if available