From a52debbb2a12b2b7701cc0d2b7cd3f595ed6e60c Mon Sep 17 00:00:00 2001 From: server Date: Thu, 16 Apr 2026 17:27:05 +0200 Subject: [PATCH] issue-4: add biolog hud --- assets/root/interfacemodule.py | 21 +++++ assets/root/uiBiolog.py | 142 +++++++++++++++++++++++++++++++++ assets/root/uiminimap.py | 30 +++++++ 3 files changed, 193 insertions(+) create mode 100644 assets/root/uiBiolog.py diff --git a/assets/root/interfacemodule.py b/assets/root/interfacemodule.py index 45f8d7cb..a2752c77 100644 --- a/assets/root/interfacemodule.py +++ b/assets/root/interfacemodule.py @@ -25,6 +25,7 @@ import uiSystem import uiRestart import uiToolTip import uiMiniMap +import uiBiolog import uiParty import uiSafebox import uiGuild @@ -75,6 +76,7 @@ class Interface(object): self.wndChat = None self.wndMessenger = None self.wndMiniMap = None + self.wndBiolog = None self.wndGuild = None self.wndGuildBuilding = None @@ -180,6 +182,7 @@ class Interface(object): wndDragonSoulRefine = None wndMiniMap = uiMiniMap.MiniMap() + wndBiolog = uiBiolog.BiologWindow() wndSafebox = uiSafebox.SafeboxWindow() # ITEM_MALL @@ -195,8 +198,10 @@ class Interface(object): self.wndDragonSoul = wndDragonSoul self.wndDragonSoulRefine = wndDragonSoulRefine self.wndMiniMap = wndMiniMap + self.wndBiolog = wndBiolog self.wndSafebox = wndSafebox self.wndChatLog = wndChatLog + self.wndMiniMap.SetBiologButtonEvent(ui.__mem_func__(self.ToggleBiologWindow)) if app.ENABLE_DRAGON_SOUL_SYSTEM: self.wndDragonSoul.SetDragonSoulRefineWindow(self.wndDragonSoulRefine) @@ -409,6 +414,9 @@ class Interface(object): if self.wndMiniMap: self.wndMiniMap.Destroy() + if self.wndBiolog: + self.wndBiolog.Hide() + if self.wndSafebox: self.wndSafebox.Destroy() @@ -499,6 +507,7 @@ class Interface(object): del self.tooltipItem del self.tooltipSkill del self.wndMiniMap + del self.wndBiolog del self.wndSafebox del self.wndMall del self.wndParty @@ -858,6 +867,9 @@ class Interface(object): if self.wndMiniMap: self.wndMiniMap.Hide() + if self.wndBiolog: + self.wndBiolog.Hide() + if self.wndMessenger: self.wndMessenger.Hide() @@ -942,6 +954,15 @@ class Interface(object): def MiniMapScaleDown(self): self.wndMiniMap.ScaleDown() + def ToggleBiologWindow(self): + if False == self.wndBiolog.IsShow(): + (miniMapX, miniMapY) = self.wndMiniMap.GetGlobalPosition() + self.wndBiolog.SetPosition(max(10, miniMapX - self.wndBiolog.GetWidth() - 10), miniMapY + 8) + self.wndBiolog.Show() + self.wndBiolog.SetTop() + else: + self.wndBiolog.Hide() + def ToggleCharacterWindow(self, state): if False == player.IsObserverMode(): if False == self.wndCharacter.IsShow(): diff --git a/assets/root/uiBiolog.py b/assets/root/uiBiolog.py new file mode 100644 index 00000000..c0a0b6ff --- /dev/null +++ b/assets/root/uiBiolog.py @@ -0,0 +1,142 @@ +import time + +import net +import player +import quest +import ui + + +class BiologWindow(ui.BoardWithTitleBar): + TITLE_PREFIX = "Biolog Stage " + STAGE_TARGETS = { + 1 : 10, + 2 : 15, + 3 : 20, + 4 : 20, + 5 : 25, + 6 : 30, + 7 : 30, + 8 : 40, + 9 : 40, + } + + def __init__(self): + ui.BoardWithTitleBar.__init__(self) + + self.lastRefreshTime = 0.0 + + self.AddFlag("float") + self.AddFlag("movable") + self.SetSize(230, 165) + self.SetTitleName("Biolog") + self.SetCloseEvent(self.Hide) + + self.__CreateChildren() + self.Hide() + + def __del__(self): + ui.BoardWithTitleBar.__del__(self) + + def __CreateChildren(self): + self.statusLine = self.__CreateValueLine(15, 36) + self.stageLine = self.__CreateValueLine(15, 58) + self.itemLine = self.__CreateValueLine(15, 80) + self.progressLine = self.__CreateValueLine(15, 102) + self.cooldownLine = self.__CreateValueLine(15, 124) + + submitButton = ui.Button() + submitButton.SetParent(self) + submitButton.SetPosition(134, 132) + submitButton.SetUpVisual("d:/ymir work/ui/public/small_thin_button_01.sub") + submitButton.SetOverVisual("d:/ymir work/ui/public/small_thin_button_02.sub") + submitButton.SetDownVisual("d:/ymir work/ui/public/small_thin_button_03.sub") + submitButton.SetText("Submit") + submitButton.SetEvent(self.__OnSubmit) + submitButton.Show() + self.submitButton = submitButton + + def __CreateValueLine(self, x, y): + textLine = ui.TextLine() + textLine.SetParent(self) + textLine.SetPosition(x, y) + textLine.SetOutline() + textLine.Show() + return textLine + + def __GetBiologData(self): + questCount = min(quest.GetQuestCount(), quest.QUEST_MAX_NUM) + for questIndex in range(questCount): + (questName, questIcon, questCounterName, questCounterValue) = quest.GetQuestData(questIndex) + if not questName.startswith(self.TITLE_PREFIX): + continue + + try: + stageIndex = int(questName[len(self.TITLE_PREFIX):]) + except: + continue + + totalRequired = self.STAGE_TARGETS.get(stageIndex, questCounterValue) + (clockName, clockValue) = quest.GetQuestLastTime(questIndex) + return { + "stage" : stageIndex, + "itemName" : questCounterName, + "remaining" : max(questCounterValue, 0), + "required" : max(totalRequired, 0), + "clockName" : clockName, + "clockValue" : max(clockValue, 0), + } + + return None + + def __FormatCooldown(self, seconds): + hours = seconds // 3600 + minutes = (seconds // 60) % 60 + return "%02d:%02d:%02d" % (hours, minutes, seconds % 60) + + def __RefreshLockedState(self): + if player.GetStatus(player.LEVEL) < 30: + self.statusLine.SetText("Status: Unlocks at level 30") + else: + self.statusLine.SetText("Status: No active biolog stage") + + self.stageLine.SetText("Stage: -") + self.itemLine.SetText("Item: -") + self.progressLine.SetText("Progress: -") + self.cooldownLine.SetText("Cooldown: -") + self.submitButton.Hide() + + def Refresh(self): + biologData = self.__GetBiologData() + if not biologData: + self.__RefreshLockedState() + return + + submitted = max(biologData["required"] - biologData["remaining"], 0) + self.statusLine.SetText("Status: %s" % ("Ready" if biologData["clockValue"] <= 0 else "Cooldown")) + self.stageLine.SetText("Stage: %d / 9" % biologData["stage"]) + self.itemLine.SetText("Item: %s" % biologData["itemName"]) + self.progressLine.SetText("Progress: %d / %d" % (submitted, biologData["required"])) + + if biologData["clockValue"] > 0 and len(biologData["clockName"]) > 0: + self.cooldownLine.SetText("Cooldown: %s" % self.__FormatCooldown(biologData["clockValue"])) + else: + self.cooldownLine.SetText("Cooldown: Ready") + + self.submitButton.Show() + + def Show(self): + self.Refresh() + ui.BoardWithTitleBar.Show(self) + + def OnUpdate(self): + currentTime = time.time() + if currentTime - self.lastRefreshTime < 0.2: + return + + self.lastRefreshTime = currentTime + self.Refresh() + + def __OnSubmit(self): + net.SendBiologSubmit() + self.lastRefreshTime = 0.0 + self.Refresh() diff --git a/assets/root/uiminimap.py b/assets/root/uiminimap.py index b6c5a2c9..ae0143a8 100644 --- a/assets/root/uiminimap.py +++ b/assets/root/uiminimap.py @@ -222,6 +222,9 @@ class MiniMap(ui.ScriptWindow): self.tooltipAtlasOpen = MapTextToolTip() self.tooltipAtlasOpen.SetText(localeInfo.MINIMAP_SHOW_AREAMAP) self.tooltipAtlasOpen.Show() + self.tooltipBiolog = MapTextToolTip() + self.tooltipBiolog.SetText("Biolog") + self.tooltipBiolog.Show() self.tooltipInfo = MapTextToolTip() self.tooltipInfo.Show() @@ -259,12 +262,15 @@ class MiniMap(ui.ScriptWindow): self.MiniMapHideButton = 0 self.MiniMapShowButton = 0 self.AtlasShowButton = 0 + self.BiologButton = 0 + self.biologButtonEvent = None self.tooltipMiniMapOpen = 0 self.tooltipMiniMapClose = 0 self.tooltipScaleUp = 0 self.tooltipScaleDown = 0 self.tooltipAtlasOpen = 0 + self.tooltipBiolog = 0 self.tooltipInfo = None self.serverInfo = None @@ -346,6 +352,17 @@ class MiniMap(ui.ScriptWindow): if miniMap.IsAtlas(): self.AtlasShowButton.SetEvent(ui.__mem_func__(self.ShowAtlas)) + self.BiologButton = ui.Button() + self.BiologButton.SetParent(self.OpenWindow) + self.BiologButton.SetPosition(9, 111) + self.BiologButton.SetUpVisual("d:/ymir work/ui/public/small_thin_button_01.sub") + self.BiologButton.SetOverVisual("d:/ymir work/ui/public/small_thin_button_02.sub") + self.BiologButton.SetDownVisual("d:/ymir work/ui/public/small_thin_button_03.sub") + self.BiologButton.SetText("Bio") + if self.biologButtonEvent: + self.BiologButton.SetEvent(self.biologButtonEvent) + self.BiologButton.Show() + (ButtonPosX, ButtonPosY) = self.MiniMapShowButton.GetGlobalPosition() self.tooltipMiniMapOpen.SetTooltipPosition(ButtonPosX, ButtonPosY) @@ -361,6 +378,9 @@ class MiniMap(ui.ScriptWindow): (ButtonPosX, ButtonPosY) = self.AtlasShowButton.GetGlobalPosition() self.tooltipAtlasOpen.SetTooltipPosition(ButtonPosX, ButtonPosY) + (ButtonPosX, ButtonPosY) = self.BiologButton.GetGlobalPosition() + self.tooltipBiolog.SetTooltipPosition(ButtonPosX, ButtonPosY) + self.ShowMiniMap() def Destroy(self): @@ -441,6 +461,11 @@ class MiniMap(ui.ScriptWindow): else: self.tooltipAtlasOpen.Hide() + if True == self.BiologButton.IsIn(): + self.tooltipBiolog.Show() + else: + self.tooltipBiolog.Hide() + def OnRender(self): (x, y) = self.GetGlobalPosition() fx = float(x) @@ -485,3 +510,8 @@ class MiniMap(ui.ScriptWindow): self.AtlasWindow.Hide() else: self.AtlasWindow.Show() + + def SetBiologButtonEvent(self, event): + self.biologButtonEvent = event + if self.BiologButton: + self.BiologButton.SetEvent(event)