rodecomp/Source/UI/Text/NavigationLink.cpp
ragnarok-clanker cddce682ef Decompile 8 functions in Source/UI/Text/NavigationLink.cpp
Batch #3069 by eAthena: 0 byte-identical, 8 confirmed by peer review.

- fn_10472 LineCutter::UIText::Slot26: logic confirmed by peer review
- fn_10473 LineCutter::UIText::Slot25: logic confirmed by peer review
- fn_10474 LineCutter::UIText::Slot31: logic confirmed by peer review
- fn_10476 LineCutter::UIText::Slot27: logic confirmed by peer review
- fn_10477 LineCutter::UIText::ResetCursor: logic confirmed by peer review
- fn_10480 LineCutter::UIText::Slot32: logic confirmed by peer review
- fn_10481 LineCutter::UIText::Slot33: logic confirmed by peer review
- fn_10482 LineCutter::UIText::Slot35: logic confirmed by peer review

Peer-reviewed-by: superintelligence
Reviewed-by: ragnarok-clanker
2026-10-29 21:49:52 +00:00

296 lines
8.2 KiB
C++

#include "UI/Text/NavigationLink.h"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <mbstring.h>
#include <vector>
#include "Contents/MessageTable.h"
#include "UI/Window/UIWindow.h"
namespace LineCutter {
class UIText : public UIWindow {
public:
void Slot25(int x, int y) override;
void Slot26(int x, int y) override;
void Slot27(int x, int y) override;
void ResetCursor(int x, int y) override;
void Slot31(int x, int y) override;
void Slot32(int x, int y) override;
void Slot33(int x, int y) override;
void Slot35(int value) override;
/* 0080 */ unsigned char unknown_0080[0x18];
/* 0098 */ std::string m_text;
};
}
#if defined(_WIN32) && !defined(_WIN64)
static_assert(sizeof(LineCutter::UIText) == 0xB0);
#endif
// OFFSET: 0x00833160
// FUNCTION: fn_10409
int DecodeNavigationNumber(std::string value) {
constexpr char digits[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
const std::size_t length = value.size();
std::uint32_t result = 0;
for (std::size_t index = 0; index < length; ++index) {
const char* digit = std::strchr(digits, value[index]);
if (!digit || *digit == '\0') {
continue;
}
std::uint32_t place = 1;
for (std::size_t exponent = index + 1; exponent < length; ++exponent) {
place *= 62;
}
result += static_cast<std::uint32_t>(digit - digits) * place;
}
return static_cast<int>(result);
}
// OFFSET: 0x00833270
// FUNCTION: fn_10410
std::string EncodeNavigationNumber(int value) {
const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::vector<char> characters;
do {
characters.push_back(digits[value % 62]);
value /= 62;
} while (value >= 62);
characters.push_back(digits[value]);
std::string result;
const std::size_t count = characters.size();
for (std::size_t index = 0; index < count; ++index) {
result += characters[count - 1 - index];
}
return result;
}
// OFFSET: 0x00835890
// FUNCTION: fn_10420
bool ParseNavigationLink(std::string value, std::string& name, int& x, int& y) {
const auto end = value.find("</NAVIL>");
if (end == std::string::npos) {
return true;
}
const auto coordinates = end - 4;
const std::string tail = value.substr(coordinates);
x = DecodeNavigationNumber(tail.substr(0, 2));
y = DecodeNavigationNumber(tail.substr(2, 2));
const std::string head = value.substr(0, coordinates);
const auto begin = head.find("<NAVIL>");
if (begin != std::string::npos) {
name = head.substr(begin + 7);
}
return !name.empty();
}
// OFFSET: 0x00835600
// FUNCTION: fn_10419
std::string FormatNavigationLink(std::string value, bool brackets) {
std::string name;
int x = 0, y = 0;
ParseNavigationLink(value, name, x, y);
char text[128] = {};
if (x > 999 && y > 999) {
std::sprintf(text, brackets ? "<%s>" : "%s", name.c_str());
} else {
std::sprintf(text, brackets ? "<%s %d,%d>" : "%s %d,%d", name.c_str(), x, y);
}
return text;
}
// OFFSET: 0x00833550
// FUNCTION: fn_10411
void DisplayNavigationLink(std::string& output, std::string value) {
output = value;
const auto begin = value.find("<NAVIL>");
if (begin != std::string::npos) {
output.clear();
const std::string head = value.substr(0, begin);
const std::string tail = value.substr(begin);
const auto end = tail.find("</NAVIL>");
if (end != std::string::npos) {
const auto extent = end + 8;
const std::string rest = tail.substr(extent);
output = head;
output += FormatNavigationLink(tail.substr(0, extent), true);
output += rest;
}
}
}
// OFFSET: 0x00834980
// FUNCTION: fn_10417
void ExtractNavigationLink(std::string& output, std::string value) {
output = value;
const auto begin = value.find("<NAVIL>");
if (begin != std::string::npos) {
output = value.substr(begin);
const auto end = output.find("</NAVIL>");
if (end != std::string::npos) {
output.resize(end + 8);
}
}
}
// OFFSET: 0x00834160
// FUNCTION: fn_10415
static void SplitMessageArguments(const char* text, std::vector<std::string>& arguments) {
std::string remaining = text;
std::size_t separator = remaining.find(',');
while (separator != std::string::npos) {
std::string argument = remaining.substr(0, separator);
arguments.emplace_back(argument.data(), argument.size());
remaining = remaining.substr(separator + 1);
separator = remaining.find(',');
}
if (!remaining.empty()) {
arguments.emplace_back(remaining.data(), remaining.size());
}
}
// OFFSET: 0x00834C30
// FUNCTION: fn_10418
std::string FormatMessageArguments(std::string value, int messageId) {
const std::string text(value.data(), value.size());
std::string result = LookupMessage(messageId);
const std::size_t separator = text.find(',');
if (separator != std::string::npos) {
const std::string tail = text.substr(separator + 1);
std::vector<std::string> arguments;
arguments.reserve(8);
SplitMessageArguments(tail.c_str(), arguments);
for (std::size_t index = 0; index < arguments.size(); ++index) {
const std::size_t percent = result.find('%');
if (percent != std::string::npos) {
unsigned length = 1;
char conversion[8] = {};
std::size_t position = percent + 1;
for (;;) {
strcpy_s(conversion, sizeof(conversion), result.substr(position, 1).c_str());
if (conversion[0] >= 'A') {
break;
}
++length;
++position;
}
const std::size_t end = percent + length + 1;
const std::string format = result.substr(0, end);
const std::string remainder = result.substr(end);
char buffer[164] = {};
std::string& argument = arguments[index];
if (_mbsstr(reinterpret_cast<const unsigned char*>(conversion), reinterpret_cast<const unsigned char*>("s"))) {
if (argument.find("MsgStr(") != std::string::npos) {
argument = argument.substr(7);
argument = argument.substr(0, argument.size() - 1);
const std::string nested = LookupMessage(std::atoi(argument.c_str()));
std::sprintf(buffer, format.c_str(), nested.c_str());
} else {
std::sprintf(buffer, format.c_str(), argument.c_str());
}
} else if (_mbsstr(reinterpret_cast<const unsigned char*>(conversion), reinterpret_cast<const unsigned char*>("d"))) {
std::sprintf(buffer, format.c_str(), std::atoi(argument.c_str()));
} else if (_mbsstr(reinterpret_cast<const unsigned char*>(conversion), reinterpret_cast<const unsigned char*>("f"))) {
std::sprintf(buffer, format.c_str(), std::atof(argument.c_str()));
}
result = buffer + remainder;
}
}
}
return result;
}
// OFFSET: 0x0083B250
// FUNCTION: fn_10473
void LineCutter::UIText::Slot25(int x, int y) {
if (this->parent) {
this->parent->Slot25(x + this->geometry.x, y + this->geometry.y);
}
}
// OFFSET: 0x0083B220
// FUNCTION: fn_10472
void LineCutter::UIText::Slot26(int x, int y) {
if (this->parent) {
this->parent->Slot26(x + this->geometry.x, y + this->geometry.y);
}
}
// OFFSET: 0x0083B400
// FUNCTION: fn_10476
void LineCutter::UIText::Slot27(int x, int y) {
if (this->parent) {
this->parent->Slot27(x + this->geometry.x, y + this->geometry.y);
}
}
// OFFSET: 0x0083B430
// FUNCTION: fn_10477
void LineCutter::UIText::ResetCursor(int x, int y) {
if (this->parent) {
this->parent->ResetCursor(x + this->geometry.x, y + this->geometry.y);
}
}
// OFFSET: 0x0083B280
// FUNCTION: fn_10474
void LineCutter::UIText::Slot31(int x, int y) {
if (this->parent) {
this->parent->Slot31(x + this->geometry.x, y + this->geometry.y);
}
}
// OFFSET: 0x0083B630
// FUNCTION: fn_10480
void LineCutter::UIText::Slot32(int x, int y) {
if (this->parent) {
this->parent->Slot32(x + this->geometry.x, y + this->geometry.y);
}
}
// OFFSET: 0x0083B660
// FUNCTION: fn_10481
void LineCutter::UIText::Slot33(int x, int y) {
if (this->parent) {
this->parent->Slot33(x + this->geometry.x, y + this->geometry.y);
}
}
// OFFSET: 0x0083B690
// FUNCTION: fn_10482
void LineCutter::UIText::Slot35(int value) {
if (this->parent) {
this->parent->Slot35(value);
}
}