From 34541f64a8b2ed44d18309f64f0772d824425072 Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Wed, 28 Oct 2026 21:11:05 +0000 Subject: [PATCH] Decompile 6 functions in Source/Contents/HeadResources.cpp, Source/Client/Session.h, ... Batch #1721 by ragnarok-clanker: 0 byte-identical, 6 confirmed by peer review. - fn_19751 EquipmentResourceMgr::GetHeadName: logic confirmed by peer review - fn_23373 CSession::GetHeadActName: logic confirmed by peer review - fn_23374 CSession::GetPlayerHeadActName: logic confirmed by peer review - fn_23375 CSession::GetHeadPalName: logic confirmed by peer review - fn_23376 CSession::GetPlayerHeadPalName: logic confirmed by peer review - fn_23377 CSession::GetHeadSprName: logic confirmed by peer review Accepted without human review: peers confirmed the logic ("same" ahead by at least 3, with 70% of the votes). Adds to the build: Source/Contents/HeadResources.cpp --- Source/Client/Session.h | 43 +++- Source/Contents/EquipmentResourceMgr.h | 5 + Source/Contents/HeadResources.cpp | 300 +++++++++++++++++++++++++ data/compile.json | 1 + 4 files changed, 343 insertions(+), 6 deletions(-) create mode 100644 Source/Contents/HeadResources.cpp diff --git a/Source/Client/Session.h b/Source/Client/Session.h index 73e315e..6f2e668 100644 --- a/Source/Client/Session.h +++ b/Source/Client/Session.h @@ -71,15 +71,24 @@ public: /* 07B4 */ unsigned char m_playerNameKey[0x40]; /* 07F4 */ unsigned char unknown_07F4[0x6A4]; /* 0E98 */ int unknown_0E98; - /* 0E9C */ unsigned char unknown_0E9C[0x64]; + /* 0E9C */ unsigned char unknown_0E9C[0x3C]; + /* 0ED8 */ int m_head; + /* 0EDC */ unsigned char unknown_0EDC[0x14]; + /* 0EF0 */ int m_headPalette; + /* 0EF4 */ unsigned char unknown_0EF4[0x0C]; /* 0F00 */ int m_robe; - /* 0F04 */ unsigned char unknown_0F04[0x14]; + /* 0F04 */ unsigned char unknown_0F04[0x10]; + /* 0F14 */ std::uint32_t m_jobFlags; /* 0F18 */ int m_playerX; /* 0F1C */ int m_playerY; /* 0F20 */ unsigned char unknown_0F20[0x08]; /* 0F28 */ int m_score1; /* 0F2C */ int m_score2; - /* 0F30 */ unsigned char unknown_0F30[0x78]; + /* 0F30 */ unsigned char unknown_0F30[0x3C]; + /* 0F6C */ const char* const* m_humanMaleHeadNames; + /* 0F70 */ unsigned char unknown_0F70[0x08]; + /* 0F78 */ const char* const* m_humanFemaleHeadNames; + /* 0F7C */ unsigned char unknown_0F7C[0x2C]; /* 0FA8 */ const char* const* m_jobNamesBegin; /* 0FAC */ const char* const* m_jobNamesEnd; /* 0FB0 */ unsigned char unknown_0FB0[0x34]; @@ -115,7 +124,9 @@ public: /* 4860 */ ItemInfo m_itemSlots[10]; /* 5210 */ unsigned char unknown_5210[0x44]; /* 5254 */ std::map m_npcLocationRadius; - /* 525C */ unsigned char unknown_525C[0x5C]; + /* 525C */ unsigned char unknown_525C[0x44]; + /* 52A0 */ const char* const* m_sexNames; + /* 52A4 */ unsigned char unknown_52A4[0x14]; /* 52B8 */ std::vector m_accessoryNames; /* 52C4 */ unsigned char unknown_52C4[0x294]; /* 5558 */ int unknown_5558; @@ -148,11 +159,17 @@ public: /* 6144 */ std::map unknown_6144; /* 614C */ unsigned char unknown_614C[0x20]; /* 616C */ std::vector unknown_616C; - /* 6178 */ unsigned char unknown_6178[0x1D68]; + /* 6178 */ unsigned char unknown_6178[0x14]; + /* 618C */ const char* const* m_doramMaleHeadNames; + /* 6190 */ unsigned char unknown_6190[0x08]; + /* 6198 */ const char* const* m_doramFemaleHeadNames; + /* 619C */ unsigned char unknown_619C[0x1D44]; /* 7EE0 */ std::map m_robeAlpha; /* 7EE8 */ unsigned char unknown_7EE8[0xC0]; /* 7FA8 */ CInstantVar m_options; - /* 7FB4 */ unsigned char unknown_7FB4[0x100]; + /* 7FB4 */ unsigned char unknown_7FB4[0xC0]; + /* 8074 */ int unknown_8074; + /* 8078 */ unsigned char unknown_8078[0x3C]; /* 80B4 */ std::map m_nameToId; /* 80BC */ std::map m_shops; /* 80C4 */ unsigned char unknown_80C4[0x58]; @@ -252,6 +269,14 @@ public: bool HasInventoryItem(std::uint32_t id) const; bool HasItemId(int itemId) const; bool HasItemCount(int itemId, int count) const; + void NormalizeHead(int* head, int job); + int GetDisplayJob(); + std::string GetSexName(int sex); + std::string GetHeadActName(int job, int sex, int* head); + std::string GetPlayerHeadActName(); + std::string GetHeadPalName(int head, int job, int sex, int palette); + std::string GetPlayerHeadPalName(); + std::string GetHeadSprName(int job, int sex, int* head); }; extern CSession g_session; @@ -303,6 +328,12 @@ static_assert(offsetof(CSession, m_score1) == 0xF28); static_assert(offsetof(CSession, m_score2) == 0xF2C); static_assert(offsetof(CSession, m_jobNamesBegin) == 0xFA8); static_assert(offsetof(CSession, m_jobNamesEnd) == 0xFAC); +static_assert(offsetof(CSession, m_head) == 0xED8); +static_assert(offsetof(CSession, m_headPalette) == 0xEF0); +static_assert(offsetof(CSession, m_humanMaleHeadNames) == 0xF6C); +static_assert(offsetof(CSession, m_humanFemaleHeadNames) == 0xF78); +static_assert(offsetof(CSession, m_doramMaleHeadNames) == 0x618C); +static_assert(offsetof(CSession, m_doramFemaleHeadNames) == 0x6198); static_assert(offsetof(CSession, unknown_0E98) == 0xE98); static_assert(offsetof(CSession, m_petActionTable) == 0x1058); static_assert(offsetof(CSession, m_job) == 0x1628); diff --git a/Source/Contents/EquipmentResourceMgr.h b/Source/Contents/EquipmentResourceMgr.h index 1e5e8e1..75dec90 100644 --- a/Source/Contents/EquipmentResourceMgr.h +++ b/Source/Contents/EquipmentResourceMgr.h @@ -7,6 +7,11 @@ class EquipmentResourceMgr { public: std::string GetBodyRacePrefix(int job); std::string GetRobeSprName(int robe, int); + std::string GetHeadName(int type, int job, int sex, int* head); + std::string GetHeadPalName(int head, int job, int sex, int palette); }; +extern EquipmentResourceMgr* g_equipmentResourceMgr; +extern const char* g_equipmentResourceExtensions[2]; + #endif diff --git a/Source/Contents/HeadResources.cpp b/Source/Contents/HeadResources.cpp new file mode 100644 index 0000000..905f9b6 --- /dev/null +++ b/Source/Contents/HeadResources.cpp @@ -0,0 +1,300 @@ +#include "Client/Session.h" +#include "Contents/EquipmentResourceMgr.h" +#include "Resource/ResourceMgr.h" +#include "Utility/Text/FormatString.h" + +#include + +// GLOBAL: gl_24703 +EquipmentResourceMgr* g_equipmentResourceMgr; +// GLOBAL: gl_24539 +const char* g_equipmentResourceExtensions[2] = {"act", "spr"}; + +// OFFSET: 0x00DDDFE0 +// FUNCTION: fn_23393 +int CSession::GetDisplayJob() { + const int job = this->m_job; + const std::uint32_t flags = this->m_jobFlags; + + if (job == 7) { + if (flags >> 5 & 1) { + return 13; + } + } else if (job == 14) { + if (flags >> 5 & 1) { + return 21; + } + } else if (job == 4008) { + if (flags >> 5 & 1) { + return 4014; + } + } else if (job == 4030) { + if (flags >> 5 & 1) { + return 4036; + } + } else if (job == 4015) { + if (flags >> 5 & 1) { + return 4022; + } + } else if (job == 4037) { + if (flags >> 5 & 1) { + return 4044; + } + } else if (job == 4066) { + if (flags >> 5 & 1) { + return 4082; + } + } else if (job == 4073) { + if (flags >> 5 & 1) { + return 4083; + } + } else if (job == 4102) { + if (flags >> 5 & 1) { + return 4110; + } + } else if (job == 4054) { + if (flags >> 19 & 1) { + return 4080; + } + if (flags >> 23 & 1) { + return 4088; + } + if (flags & 0x1000000) { + return 4090; + } + if (flags >> 25 & 1) { + return 4092; + } + if (flags >> 26 & 1) { + return 4094; + } + } else if (job == 4060) { + if (flags >> 19 & 1) { + return 4081; + } + if (flags >> 23 & 1) { + return 4089; + } + if (flags & 0x1000000) { + return 4091; + } + if (flags >> 25 & 1) { + return 4093; + } + if (flags >> 26 & 1) { + return 4095; + } + } else if (job == 4096) { + if (flags >> 19 & 1) { + return 4109; + } + } else if (job == 4047) { + if (flags >> 15 & 1) { + return 4048; + } + } else if (job == 4056) { + if (flags >> 21 & 1) { + return 4084; + } + } else if (job == 4062) { + if (flags >> 21 & 1) { + return 4085; + } + } else if (job == 4098) { + if (flags >> 21 & 1) { + return 4111; + } + } else if (job == 4058) { + if (this->unknown_8074 != 0) { + return 4086; + } + } else if (job == 4064) { + if (this->unknown_8074 != 0) { + return 4087; + } + } else if (job == 4100) { + if (this->unknown_8074 != 0) { + return 4112; + } + } else if (job == 4253) { + if (this->unknown_8074 != 0) { + return 4279; + } + } else if (job == 4226) { + if (flags >> 15 & 1) { + return 4238; + } + } else if (job == 4239) { + if (flags >> 15 & 1) { + return 4243; + } + } else if (job == 4241) { + if (flags >> 15 & 1) { + return 4244; + } + } else if (job == 4257) { + if (flags >> 21 & 1) { + return 4278; + } + } else if (job == 4252) { + if (flags >> 19 & 1) { + return 4280; + } + } else if (job == 4258) { + if (flags >> 5 & 1) { + return 4281; + } + } else if (job == 4302) { + if (flags >> 15 & 1) { + return 4316; + } + } + + return job; +} + +// OFFSET: 0x00E0A430 +// FUNCTION: fn_23796 +std::string CSession::GetSexName(int sex) { + return this->m_sexNames[sex]; +} + +// OFFSET: 0x00BAB110 +// FUNCTION: fn_19751 +std::string EquipmentResourceMgr::GetHeadName(int type, int job, int sex, int* head) { + if (job < 0 || (job > 30 && job < 1000) || (job > 1000 && job < 3999) || (job >= 20021 && job < 32000)) { + job = 0; + } + + std::string result; + const int male = sex != 0 ? 1 : 0; + std::string sexName; + std::string headName; + + if (g_session.IsDoramJob(job) == true) { + if (*head < 1 || *head > 10) { + *head = 10; + } + + if (male == 1) { + headName = g_session.m_doramMaleHeadNames[*head]; + } else if (male == 0) { + headName = g_session.m_doramFemaleHeadNames[*head]; + } + } else { + if (*head < 0 || *head > 45) { + *head = 13; + } + + if (male == 1) { + headName = g_session.m_humanMaleHeadNames[*head]; + } else if (male == 0) { + headName = g_session.m_humanFemaleHeadNames[*head]; + } + } + + sexName = g_session.GetSexName(male); + result = this->GetBodyRacePrefix(job) + + FormatOwnedString("\\머리통\\%s\\%s_%s.%s", sexName.c_str(), headName.c_str(), sexName.c_str(), g_equipmentResourceExtensions[type]); + return result; +} + +// OFFSET: 0x00DD9CC0 +// FUNCTION: fn_23336 +void CSession::NormalizeHead(int* head, int job) { + if (*head != 0) { + return; + } + + switch (job) { + case 1: + *head = 2; + break; + case 2: + *head = 3; + break; + case 3: + *head = 4; + break; + case 4: + *head = 5; + break; + case 5: + *head = 6; + break; + case 6: + *head = 7; + break; + default: + *head = 1; + break; + } +} + +// OFFSET: 0x00BAAB10 +// FUNCTION: fn_19750 +std::string EquipmentResourceMgr::GetHeadPalName(int head, int job, int sex, int palette) { + std::string result; + std::string sexName; + std::string headName; + + if (g_session.IsDoramJob(job) == true) { + if (head < 1 || head > 10) { + head = 10; + } + + if (sex == 1) { + headName = g_session.m_doramMaleHeadNames[head]; + } else if (sex == 0) { + headName = g_session.m_doramFemaleHeadNames[head]; + } + + if (!ResourceMgr::Instance().Exists(result.c_str())) { + sexName = g_session.GetSexName(sex); + result = FormatOwnedString("%s\\머리\\머리%s_%s_%d.pal", this->GetBodyRacePrefix(job).c_str(), headName.c_str(), sexName.c_str(), palette); + } + } else { + g_session.NormalizeHead(&head, job); + + if (sex == 1) { + headName = g_session.m_humanMaleHeadNames[head]; + } else if (sex == 0) { + headName = g_session.m_humanFemaleHeadNames[head]; + } + + sexName = g_session.GetSexName(sex); + result = FormatOwnedString("머리\\머리%s_%s_%d.pal", headName.c_str(), sexName.c_str(), palette); + } + + return result; +} + +// OFFSET: 0x00DDCD50 +// FUNCTION: fn_23373 +std::string CSession::GetHeadActName(int job, int sex, int* head) { + return g_equipmentResourceMgr->GetHeadName(0, job, sex, head); +} + +// OFFSET: 0x00DDCDC0 +// FUNCTION: fn_23374 +std::string CSession::GetPlayerHeadActName() { + return g_equipmentResourceMgr->GetHeadName(0, this->GetDisplayJob(), this->SyncUnknown0E98(), &this->m_head); +} + +// OFFSET: 0x00DDCEF0 +// FUNCTION: fn_23375 +std::string CSession::GetHeadPalName(int head, int job, int sex, int palette) { + return g_equipmentResourceMgr->GetHeadPalName(head, job, sex, palette); +} + +// OFFSET: 0x00DDCF60 +// FUNCTION: fn_23376 +std::string CSession::GetPlayerHeadPalName() { + return g_equipmentResourceMgr->GetHeadPalName(this->m_head, this->m_job, this->unknown_0E98, this->m_headPalette); +} + +// OFFSET: 0x00DDCFE0 +// FUNCTION: fn_23377 +std::string CSession::GetHeadSprName(int job, int sex, int* head) { + return g_equipmentResourceMgr->GetHeadName(1, job, sex, head); +} diff --git a/data/compile.json b/data/compile.json index 526f03a..f7d3870 100644 --- a/data/compile.json +++ b/data/compile.json @@ -341,6 +341,7 @@ "Source/Contents/Ground/TerrainPlane.cpp": 4, "Source/Contents/GuildEmblemState.cpp": 4, "Source/Contents/GuildMgr.cpp": 4, + "Source/Contents/HeadResources.cpp": 4, "Source/Contents/Hotkeys/EmotionHotkeys.cpp": 4, "Source/Contents/Hotkeys/HotkeyInfo.cpp": 4, "Source/Contents/Hotkeys/UserHotkeyMgr.cpp": 4,