From 2a4ea5b8b26bf48daf59eae673aba5fefc24ea27 Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Sat, 31 Oct 2026 16:40:00 +0000 Subject: [PATCH] Decompile 2 functions in Source/UI/Window/UIHotKeyWnd.cpp, Source/UI/Window/UIHotKeyWnd.h, ... Batch #8333 by SapitoSucio: 0 byte-identical, 2 confirmed by peer review. - fn_12617 UIHotKeyWnd::GetHotkey: logic confirmed by peer review - fn_12663 UIHotKeyWnd::Paint: logic confirmed by peer review Peer-reviewed-by: eAthena, Yommy Accepted without human review: peers confirmed the logic ("same" ahead by at least 3, with 70% of the votes). --- Source/Contents/Hotkeys/UserHotkeyMgr.h | 1 + Source/UI/Window/UIHotKeyWnd.cpp | 202 ++++++++++++++++++++++++ Source/UI/Window/UIHotKeyWnd.h | 18 ++- 3 files changed, 219 insertions(+), 2 deletions(-) diff --git a/Source/Contents/Hotkeys/UserHotkeyMgr.h b/Source/Contents/Hotkeys/UserHotkeyMgr.h index 7a166c3f..7ec1c1dd 100644 --- a/Source/Contents/Hotkeys/UserHotkeyMgr.h +++ b/Source/Contents/Hotkeys/UserHotkeyMgr.h @@ -8,6 +8,7 @@ #include class CUserHotkeyMgr { + friend class UIHotKeyWnd; public: CUserHotkeyMgr(); virtual ~CUserHotkeyMgr(); diff --git a/Source/UI/Window/UIHotKeyWnd.cpp b/Source/UI/Window/UIHotKeyWnd.cpp index 74c1130e..8a2aa20b 100644 --- a/Source/UI/Window/UIHotKeyWnd.cpp +++ b/Source/UI/Window/UIHotKeyWnd.cpp @@ -1,17 +1,82 @@ #include "UI/Window/UIHotKeyWnd.h" #include "Client/Session.h" +#include "Contents/Hotkeys/UserHotkeyMgr.h" #include "Contents/MessageTable.h" #include "Script/LuaScript.h" #include "UI/Buttons/UIButton.h" +#include "UI/Lists/UITabControl.h" +#include "UI/Text/ColoredText.h" #include "UI/Text/UIBalloonText.h" +#include "UI/Window/InputFocus.h" +#include "UI/Window/UIWindow.h" #include "UI/Window/UIWindowMgr.h" +#include "UI/Window/WindowBorder.h" +#include "UI/Window/WindowDialogs.h" +#include "UI/Window/WindowManagerWindows.h" #include "UI/Window/WindowOrdering.h" #include "Utility/Text/FormatString.h" #include #include +namespace { + bool HiddenHotkeyIndex(int index) { + switch (index) { + case 30: + case 33: + case 34: + case 36: + case 43: + case 45: + case 53: + case 58: + case 62: + case 64: + case 65: + case 66: + case 67: + return true; + default: + return false; + } + } + + int CountHotkeys(LuaScript& script, int tab) { + int count = 0; + if (script.Call("GetOriginalHotKeyListSize", "d>d", tab + 1, &count)) { + if (tab == 1) { + int hidden = 0; + for (int index = 30; index < count; ++index) { + hidden += HiddenHotkeyIndex(index); + } + return count - hidden; + } + } + return count; + } + + int MapHotkeyIndex(LuaScript& script, int tab, int index) { + if (tab == 1 && index >= 30) { + for (int candidate = 30; candidate <= index; ++candidate) { + index += HiddenHotkeyIndex(candidate); + } + } + int count = 0; + script.Call("GetOriginalHotKeyListSize", "d>d", tab + 1, &count); + return index >= count ? -1 : index; + } + + void SetWindowText(UIWindow* window, const char* text) { + if (!window) { + return; + } + using SetTextFn = void(__thiscall*)(UIWindow*, const char*); + void** vtable = *reinterpret_cast(window); + reinterpret_cast(vtable[53])(window, text); + } +} + // OFFSET: 0x00932F70 // FUNCTION: fn_12721 void UIHotKeyWnd::Slot32(int, int) { @@ -178,3 +243,140 @@ void UIHotKeyWnd::Slot25(int x, int y) { this->Invalidate(); } + +// OFFSET: 0x0091C720 +// FUNCTION: fn_12617 +UIHotKeyWnd::HotkeyEntry UIHotKeyWnd::GetHotkey(int tab, int index, bool resolve) { + HotkeyEntry entry; + entry.index = resolve ? MapHotkeyIndex(*g_luaScript, tab, index) : index; + + if (entry.index != -1) { + const auto it = this->hotkeys[tab].find(entry.index); + if (it != this->hotkeys[tab].end() && !it->second.description.empty()) { + entry.info = it->second; + } else { + entry.info = GetHotkeyInfo(*g_luaScript, tab, entry.index); + } + } + + return entry; +} + +// OFFSET: 0x0091CA10 + +// OFFSET: 0x00916220 + +// OFFSET: 0x00916930 + +// OFFSET: 0x0092BEC0 +// FUNCTION: fn_12663 +void UIHotKeyWnd::Paint() { + if (this->geometry.height == this->unknown_00BC) { + return; + } + + FontCache& fonts = this->m_context->fonts; + const TextLocale& locale = this->m_context->locale; + + this->unknown_00BC = this->DrawTitleBar(fonts, locale, true, LookupMessage(1494), 0); + this->unknown_00C0 = this->DrawButtonBar(2, 0, 1); + this->DrawPanelBackground(this->unknown_00BC, 0, ""); + + const int count = CountHotkeys(*g_luaScript, this->m_tab); + int visibleRow = 0; + + for (int row = 0; row < count; ++row) { + if (this->unknown_0114 && row < 36 * this->m_page - 36) { + continue; + } + if (row >= 36 * this->m_page) { + continue; + } + + const HotkeyEntry entry = this->GetHotkey(this->m_tab, row, true); + if (entry.info.description.empty()) { + continue; + } + + std::string text = entry.info.text; + if (text.empty()) { + text = entry.info.key1 ? LookupMessage(1700) : LookupMessage(1518); + } + + const int halfWidth = this->geometry.width / 2; + const int column = visibleRow / this->m_rowsPerPage; + const int rowY = this->unknown_00BC + this->unknown_00C4 + this->unknown_00CC + + (visibleRow % this->m_rowsPerPage) * this->unknown_00D0; + + const int textWidth = this->TextWidth(fonts, locale, text.c_str(), 0, 0, 12, 0, 0); + const int textX = (this->unknown_00D4 - textWidth) / 2; + + const int backgroundX = column ? this->geometry.width - this->unknown_00D4 - this->unknown_00C8 + : halfWidth - this->unknown_00D4; + const int keyX = column ? halfWidth : this->unknown_00C8; + + std::uint32_t color = 0xDFFFFE; + switch (this->m_tab) { + case 0: + color = 0xFFEFD6; + break; + case 3: + color = 0xEFD6FF; + break; + default: + break; + } + + this->FillRegion(backgroundX, rowY, this->unknown_00D4, this->unknown_00D0 - 1, color); + + if (visibleRow == this->m_selectedRow) { + this->FillRegion(keyX + 1, rowY, halfWidth - this->unknown_00C8 - 1, 19, 0xE1E1FF); + } + + this->FillRegion(keyX, rowY - 1 + this->unknown_00D0, this->unknown_00D4 + this->unknown_00D8, 1, 0xC0C0C0); + this->FillRegion(backgroundX, rowY, 1, this->unknown_00D0, 0xC0C0C0); + + const std::string fitted = this->FitDisplayText(130, entry.info.description.c_str(), 0, 12, 0); + const int fittedWidth = this->TextWidth(fonts, locale, fitted.c_str(), 0, 0, 12, 0, 0); + const int descriptionX = keyX + (halfWidth - this->unknown_00C8 - this->unknown_00D4 - fittedWidth) / 2; + + this->DrawTextAt(fonts, locale, descriptionX, rowY + 5, fitted.c_str(), 0, 0, 12, 0, 0, 0); + this->DrawTextAt(fonts, locale, textX + backgroundX, rowY + 5, text.c_str(), 0, 0, 12, 0, 0, 0); + + ++visibleRow; + } + + if (this->unknown_0114) { + const std::string pages = FormatOwnedString("%d / %d", this->m_page, this->m_pageCount); + const int pagesWidth = this->TextWidth(fonts, locale, pages.c_str(), 0, 0, 12, 0, 0); + const int pageX = + (this->m_prevButton->geometry.width - pagesWidth + 60) / 2 + this->m_prevButton->geometry.x; + + const std::string current = FormatOwnedString("%d", this->m_page); + DrawOutlinedText(*this, pageX, 25, current.c_str(), 0, 0x7F3CFF, 0xFFFFFF, 0, 11, 1, 0); + + const int currentWidth = this->TextWidth(fonts, locale, current.c_str(), 0, 0, 12, 0, 0); + const std::string total = FormatOwnedString(" / %d", this->m_pageCount); + DrawOutlinedText(*this, pageX + currentWidth, 25, total.c_str(), 0, 0x666666, 0xFFFFFF, 0, 11, 1, 0); + } + + const int bottomY = this->unknown_00BC + this->unknown_00C4 + this->unknown_00CC; + const int innerWidth = this->geometry.width - 2 * this->unknown_00C8; + const int innerHeight = + this->geometry.height - 2 * this->unknown_00CC - this->unknown_00C4 - this->unknown_00BC - this->unknown_00C0; + + DrawRectangleBorder(*this, this->unknown_00C8, bottomY, innerWidth, innerHeight, 0xC0C0C0); + this->FillRegion(this->geometry.width / 2, bottomY, 1, innerHeight, 0xC0C0C0); + this->FillRegion(this->unknown_00C8, bottomY - 3, 1, 3, 0xC0C0C0); + this->FillRegion(this->geometry.width - this->unknown_00C8 - 1, bottomY - 3, 1, 3, 0xC0C0C0); + this->FillRegion( + this->unknown_0100->geometry.width + this->unknown_00C8, + bottomY - 3, + innerWidth - this->unknown_0100->geometry.width, + 1, + 0xC0C0C0 + ); +} + +// OFFSET: 0x00935270 + diff --git a/Source/UI/Window/UIHotKeyWnd.h b/Source/UI/Window/UIHotKeyWnd.h index fe80358d..ffd15834 100644 --- a/Source/UI/Window/UIHotKeyWnd.h +++ b/Source/UI/Window/UIHotKeyWnd.h @@ -4,20 +4,34 @@ #include "Contents/Hotkeys/HotkeyInfo.h" #include "UI/Window/UIFrameWnd.h" +#include #include class UIBalloonText; class UIButton; +class UITabControl; +class UIWindow; class UIHotKeyWnd : public UIFrameWnd { public: + struct HotkeyEntry { + int index; + HotkeyInfo info; + }; + UIHotKeyWnd(UIWindowContext& windows, UIFrameContext& frames); void Slot25(int x, int y) override; void Slot32(int x, int y) override; int RowFromPoint(int x, int y); + void Paint() override; + int SendMsg(UIWindow* sender, int message, std::intptr_t argument1, std::intptr_t argument2, std::intptr_t argument3, std::intptr_t argument4) override; void UpdatePageButtons(); void SaveHotkeys(); void SetHotkey(int tab, int index, HotkeyInfo info); + HotkeyEntry GetHotkey(int tab, int index, bool resolve); + void ReloadHotkeys(); + int AssignSelectedHotkey(int mode); + int CheckHotkeyConflict(); /* 00B4 */ int m_selectedRow; /* 00B8 */ int m_rowsPerPage; @@ -31,9 +45,9 @@ public: /* 00D8 */ int unknown_00D8; /* 00DC */ std::map hotkeys[4]; /* 00FC */ UIBalloonText* m_balloon; - /* 0100 */ unsigned char unknown_0100[0x4]; + /* 0100 */ UITabControl* unknown_0100; /* 0104 */ int m_tab; - /* 0108 */ unsigned char unknown_0108[0x4]; + /* 0108 */ UIWindow* unknown_0108; /* 010C */ int m_page; /* 0110 */ int m_pageCount; /* 0114 */ unsigned char unknown_0114;