From 489efa8614a5fd105a097a486eaac63d2d4faf36 Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Fri, 30 Oct 2026 02:18:23 +0000 Subject: [PATCH] Decompile fn_10419 (FormatNavigationLink) Batch #4375 by youko: 0 byte-identical, 1 confirmed by peer review. - fn_10419 FormatNavigationLink: logic confirmed by peer review Peer-reviewed-by: ragnarok-clanker, ntrl, bigodeira Accepted without human review: peers confirmed the logic ("same" ahead by at least 3, with 70% of the votes). --- Source/UI/Text/CreateLineInfo.h | 121 +++++++++++++++++++++++ Source/UI/Text/NavigationLink.cpp | 155 +++++++++++++++++++++++++++++- 2 files changed, 271 insertions(+), 5 deletions(-) create mode 100644 Source/UI/Text/CreateLineInfo.h diff --git a/Source/UI/Text/CreateLineInfo.h b/Source/UI/Text/CreateLineInfo.h new file mode 100644 index 00000000..f72a3874 --- /dev/null +++ b/Source/UI/Text/CreateLineInfo.h @@ -0,0 +1,121 @@ +#ifndef RAGNAROK_SOURCE_UI_TEXT_CREATELINEINFO_H +#define RAGNAROK_SOURCE_UI_TEXT_CREATELINEINFO_H + +#include +#include +#include +#include +#include +#include + +class UIWindow; + +enum LineSegmentType { + LINE_SEGMENT_URL = 0x1B5, + LINE_SEGMENT_NAVI = 0x1B6, + LINE_SEGMENT_ITEM = 0x1D0, + LINE_SEGMENT_ITEM_LINK = 0x1F5, + LINE_SEGMENT_TIPBOX = 0x205, + LINE_SEGMENT_QUEST = 0x21B, + LINE_SEGMENT_NAVI_LINK = 0x232, + LINE_SEGMENT_MESSAGE = 0x233, + LINE_SEGMENT_EMOTION = 0x236, + LINE_SEGMENT_ITEM_IMAGE = 0x241, + LINE_SEGMENT_TEXT = 0x258, +}; + +struct LineTextStyle { + /* 0000 */ std::uint32_t color; + /* 0004 */ int fontHeight; + /* 0008 */ bool bold; + /* 0009 */ bool italic; +}; + +struct LineTextSegment { + // INLINED + LineTextSegment(const std::string& text, const LineTextStyle& style) + : text(text), style(style), type(LINE_SEGMENT_TEXT), unknown_0028(0), unknown_002C(0) { + } + + /* 0000 */ std::string text; + /* 0018 */ LineTextStyle style; + /* 0024 */ int type; + /* 0028 */ int unknown_0028; + /* 002C */ int unknown_002C; +}; + +struct LineFontState { + /* 0000 */ int fontHeight; + /* 0004 */ std::uint32_t color; +}; + +// VTABLE: vt_00879 +class CCreateLineInfo { +public: + static std::vector s_fontStackCache; + + static bool CompareTag(std::string text, std::string keyword, bool exactMatch, bool caseSensitive); + static std::size_t FindTag(std::string text, std::string keyword, bool caseSensitive); + static std::pair GetLinkTags(int type); + static std::string NextCharacter(std::string text); + static std::tuple SplitLinkInfo(std::string text, int type); + static std::vector SplitString(std::string text, const std::string& delimiter); + + /* 0004 */ UIWindow* m_parent; + /* 0008 */ int m_width; + /* 000C */ int m_lineSpacing; + /* 0010 */ int m_bold; + /* 0014 */ int m_italic; + /* 0018 */ int m_defaultFontHeight; + /* 001C */ int m_fontHeight; + /* 0020 */ std::uint32_t m_defaultColor; + /* 0024 */ std::uint32_t m_color; + /* 0028 */ bool unknown_0028; + /* 002C */ int unknown_002C; + /* 0030 */ bool unknown_0030; + /* 0034 */ int unknown_0034; + /* 0038 */ unsigned char m_align; + /* 003C */ std::vector m_fontStack; + /* 0048 */ bool m_newSegment; + /* 004C */ std::string m_text; + /* 0064 */ std::vector m_segments; + /* 0070 */ std::vector> m_lines; + /* 007C */ int m_height; + + virtual ~CCreateLineInfo(); + + void AppendText(const std::string& text); + void AddWindow(UIWindow* window); + void ApplyFont(std::string tag); + int AddLink(int index, int type); + void NewLine(); + void AddSegment(int type); + void ParseText(); + int ParseEmotion(int index); + int ParseMarkup(int index); + int ParseLink(int index); + int ParseItemImage(int index); + int ParseItemName(int index); + int ParseChar(int index); + int ParseTag(int index); + void ArrangeLines(); + +private: + void CloseFont(std::string tag); + void OpenBold(std::string tag); + void CloseBold(std::string tag); + void OpenItalic(std::string tag); + void CloseItalic(std::string tag); +}; + +#if defined(_WIN32) && !defined(_WIN64) +static_assert(sizeof(LineTextStyle) == 0xC); +static_assert(sizeof(LineTextSegment) == 0x30); +static_assert(sizeof(LineFontState) == 0x8); +static_assert(sizeof(CCreateLineInfo) == 0x80); +static_assert(offsetof(CCreateLineInfo, m_fontStack) == 0x3C); +static_assert(offsetof(CCreateLineInfo, m_text) == 0x4C); +static_assert(offsetof(CCreateLineInfo, m_height) == 0x7C); +#endif + +#endif diff --git a/Source/UI/Text/NavigationLink.cpp b/Source/UI/Text/NavigationLink.cpp index dec8c9ac..a438761a 100644 --- a/Source/UI/Text/NavigationLink.cpp +++ b/Source/UI/Text/NavigationLink.cpp @@ -1,24 +1,31 @@ #include "UI/Text/NavigationLink.h" +#include +#include #include #include #include #include #include #include +#include #include #include #include #include "Contents/Items/ItemDescription.h" +#include "Contents/Items/ItemInfo.h" #include "Contents/MessageTable.h" +#include "Network/TextEncoding.h" #include "Resource/Bitmap/BitmapResource.h" #include "Resource/ResourceMgr.h" #include "Resource/Sprites/ActionResource.h" #include "Resource/TextureNames.h" #include "UI/Buttons/UIButton.h" #include "UI/Text/ColoredText.h" +#include "UI/Text/CreateLineInfo.h" #include "UI/Window/UIWindow.h" +#include "Utility/Text/TextTokens.h" namespace LineCutter { class UIText : public UIWindow { @@ -117,6 +124,46 @@ void DestroyNavigationLinkParser() { } } +// GLOBAL: gl_24818 +static const std::string g_urlTag = ""; +// GLOBAL: gl_24819 +static const std::string g_urlCloseTag = ""; +// GLOBAL: gl_24820 +static const std::string g_naviTag = ""; +// GLOBAL: gl_24821 +static const std::string g_naviCloseTag = ""; +// GLOBAL: gl_24822 +static const std::string g_infoTag = ""; +// GLOBAL: gl_24823 +static const std::string g_infoCloseTag = ""; +// GLOBAL: gl_24824 +static const std::string g_itemTag = ""; +// GLOBAL: gl_24825 +static const std::string g_itemCloseTag = ""; +// GLOBAL: gl_24826 +static const std::string g_itemLinkTag = ""; +// GLOBAL: gl_24827 +static const std::string g_itemLinkCloseTag = ""; +// GLOBAL: gl_24828 +static const std::string g_messageTag = ""; +// GLOBAL: gl_24829 +static const std::string g_messageCloseTag = ""; +// GLOBAL: gl_24830 +static const std::string g_naviLinkTag = ""; +// GLOBAL: gl_24831 +static const std::string g_naviLinkCloseTag = ""; +// GLOBAL: gl_24832 +static const std::string g_tipBoxTag = ""; +// GLOBAL: gl_24833 +static const std::string g_tipBoxCloseTag = ""; +// GLOBAL: gl_24834 +static const std::string g_questTag = ""; +// GLOBAL: gl_24835 +static const std::string g_questCloseTag = ""; + +// GLOBAL: gl_24836 +std::vector CCreateLineInfo::s_fontStackCache; + // OFFSET: 0x00833160 // FUNCTION: fn_10409 int DecodeNavigationNumber(std::string value) { @@ -190,14 +237,23 @@ bool ParseNavigationLink(std::string value, std::string& name, int& x, int& y) { // FUNCTION: fn_10419 std::string FormatNavigationLink(std::string value, bool brackets) { std::string name; - int x = 0, y = 0; - ParseNavigationLink(value, name, x, y); + int x = 0; + int y = 0; + ParseNavigationLink(std::move(value), name, x, y); char text[128] = {}; - if (x > 999 && y > 999) { - std::sprintf(text, brackets ? "<%s>" : "%s", name.c_str()); + if (brackets) { + if (x > 999 && y > 999) { + std::sprintf(text, "<%s>", name.c_str()); + } else { + std::sprintf(text, "<%s %d,%d>", name.c_str(), x, y); + } } else { - std::sprintf(text, brackets ? "<%s %d,%d>" : "%s %d,%d", name.c_str(), x, y); + if (x > 999 && y > 999) { + std::sprintf(text, "%s", name.c_str()); + } else { + std::sprintf(text, "%s %d,%d", name.c_str(), x, y); + } } return text; @@ -408,3 +464,92 @@ void UIEmotion::Slot19() { } // OFFSET: 0x0083B0A0 + +// OFFSET: 0x00837390 + +// OFFSET: 0x008379D0 + +// OFFSET: 0x00837B40 + +// OFFSET: 0x00837B80 + +// OFFSET: 0x00839310 + +// OFFSET: 0x00839D60 + +// OFFSET: 0x0083A180 + +// OFFSET: 0x0083A820 + +// OFFSET: 0x0083AA40 + +// OFFSET: 0x0083AB90 + +// OFFSET: 0x0083AF20 + +// OFFSET: 0x0083BD80 + +// INLINED +inline void CCreateLineInfo::CloseFont(std::string tag) { + if (!this->m_fontStack.empty()) { + this->m_fontStack.pop_back(); + if (this->m_fontStack.empty()) { + this->m_fontHeight = this->m_defaultFontHeight; + this->m_color = this->m_defaultColor; + } else { + this->m_fontHeight = this->m_fontStack.back().fontHeight; + this->m_color = this->m_fontStack.back().color; + } + this->m_newSegment = true; + } +} + +// INLINED +inline void CCreateLineInfo::OpenBold(std::string tag) { + if (this->m_bold == 0) { + this->m_newSegment = true; + } + ++this->m_bold; +} + +// INLINED +inline void CCreateLineInfo::CloseBold(std::string tag) { + if (--this->m_bold == 0) { + this->m_newSegment = true; + } +} + +// INLINED +inline void CCreateLineInfo::OpenItalic(std::string tag) { + if (this->m_italic == 0) { + this->m_newSegment = true; + } + ++this->m_italic; +} + +// INLINED +inline void CCreateLineInfo::CloseItalic(std::string tag) { + if (--this->m_italic == 0) { + this->m_newSegment = true; + } +} + +// OFFSET: 0x0083BFF0 + +// OFFSET: 0x0083C3D0 + +// OFFSET: 0x0083C6A0 + +// OFFSET: 0x0083C890 + +// OFFSET: 0x0083CDA0 + +// OFFSET: 0x0083CFE0 + +// OFFSET: 0x0083D090 + +// OFFSET: 0x0083D1F0 + +// OFFSET: 0x0083D360 + +// OFFSET: 0x0083D660