From 3863fe6f3c14ce332db2b50ac63151b596f906b9 Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Wed, 28 Oct 2026 15:38:29 +0000 Subject: [PATCH] Decompile 6 functions in Source/Contents/Jobs/JobInheritance.cpp, Source/Contents/Jobs/JobInheritance.h, ... Batch #1478 by ragnarok-clanker: 0 byte-identical, 6 confirmed by peer review. - fn_23898 GetDualWieldWeaponType: logic confirmed by peer review - fn_23583 IsJobWeaponAllowed: logic confirmed by peer review - fn_23836 GetJobTitleString: logic confirmed by peer review - fn_23909 CSession::InsertPair: logic confirmed by peer review - fn_23911 CSession::SetHotkeyEntry: logic confirmed by peer review - fn_23912 CSession::SetFlag: logic confirmed by peer review Reviewed-by: ragnarok-clanker --- Source/Contents/Jobs/JobInheritance.cpp | 392 ++++++++++++++++++++++++ 1 file changed, 392 insertions(+) diff --git a/Source/Contents/Jobs/JobInheritance.cpp b/Source/Contents/Jobs/JobInheritance.cpp index 0baa420..6dfd18c 100644 --- a/Source/Contents/Jobs/JobInheritance.cpp +++ b/Source/Contents/Jobs/JobInheritance.cpp @@ -133,6 +133,272 @@ int __stdcall GetRealWeaponId(int weapon) { } // OFFSET: 0x00DFB4B0 +// FUNCTION: fn_23583 +bool __stdcall IsJobWeaponAllowed(int job, int slot, std::int64_t weapon) { + if (weapon >= 105) { + if (job == JT_ASSASSIN || job == JT_ASSASSIN_H || job == JT_ASSASSIN_B || job == JT_GUILLOTINE_CROSS || job == JT_GUILLOTINE_CROSS_H || + job == JT_GUILLOTINE_CROSS_B || job == JT_SHADOW_CROSS) { + if (GetWeaponViewValue(static_cast(weapon >> 32)) > 0) { + weapon = GetDualWieldWeaponType(static_cast(weapon), static_cast(weapon >> 32)); + } else { + weapon = GetWeaponViewValue(static_cast(weapon)); + } + } else { + weapon = GetWeaponViewValue(static_cast(weapon)); + } + } + + const std::int64_t view = GetRealWeaponId(static_cast(weapon)); + + switch (job) { + case JT_SWORDMAN: + case JT_KNIGHT: + case JT_CHICKEN: + case JT_CRUSADER: + case JT_CHICKEN2: + case JT_SWORDMAN_H: + case JT_KNIGHT_H: + case JT_CHICKEN_H: + case JT_CRUSADER_H: + case JT_CHICKEN2_H: + case JT_SWORDMAN_B: + case JT_KNIGHT_B: + case JT_CHICKEN_B: + case JT_CRUSADER_B: + case JT_CHICKEN2_B: + case JT_RUNE_KNIGHT: + case JT_RUNE_KNIGHT_H: + case JT_ROYAL_GUARD: + case JT_ROYAL_GUARD_H: + case JT_RUNE_CHICKEN: + case JT_RUNE_CHICKEN_H: + case JT_ROYAL_CHICKEN: + case JT_ROYAL_CHICKEN_H: + case JT_RUNE_CHICKEN2: + case JT_RUNE_CHICKEN2_H: + case JT_RUNE_CHICKEN3: + case JT_RUNE_CHICKEN3_H: + case JT_RUNE_CHICKEN4: + case JT_RUNE_CHICKEN4_H: + case JT_RUNE_CHICKEN5: + case JT_RUNE_CHICKEN5_H: + case JT_RUNE_KNIGHT_B: + case JT_ROYAL_GUARD_B: + case JT_RUNE_CHICKEN_B: + case JT_ROYAL_CHICKEN_B: + case JT_DRAGON_KNIGHT: + case JT_IMPERIAL_GUARD: + case JT_DRAGON_KNIGHT_CHICKEN: + case JT_IMPERIAL_GUARD_CHICKEN: + return view == 4 || view == 5; + case JT_MAGICIAN: + case JT_MERCHANT: + case JT_MAGICIAN_H: + case JT_MERCHANT_H: + case JT_MAGICIAN_B: + case JT_MERCHANT_B: + return view == 1; + case JT_ARCHER: + case JT_ARCHER_H: + case JT_ARCHER_B: + return view != 11; + case JT_THIEF: + case JT_HUNTER: + case JT_ROGUE: + case JT_BARD: + case JT_DANCER: + case JT_THIEF_H: + case JT_HUNTER_H: + case JT_ROGUE_H: + case JT_BARD_H: + case JT_DANCER_H: + case JT_THIEF_B: + case JT_HUNTER_B: + case JT_ROGUE_B: + case JT_BARD_B: + case JT_DANCER_B: + case JT_RANGER: + case JT_RANGER_H: + case JT_MINSTREL: + case JT_WANDERER: + case JT_SHADOW_CHASER: + case JT_MINSTREL_H: + case JT_WANDERER_H: + case JT_SHADOW_CHASER_H: + case JT_WOLF_RANGER: + case JT_WOLF_RANGER_H: + case JT_RANGER_B: + case JT_MINSTREL_B: + case JT_WANDERER_B: + case JT_SHADOW_CHASER_B: + case JT_WOLF_RANGER_B: + case JT_WINDHAWK: + case JT_ABYSS_CHASER: + case JT_TROUBADOUR: + case JT_TROUVERE: + case JT_WOLF_WINDHAWK: + return view == 11; + case JT_PRIEST: + case JT_PRIEST_H: + case JT_PRIEST_B: + case JT_ARCHBISHOP: + case JT_ARCHBISHOP_H: + case JT_ARCHBISHOP_B: + case JT_CARDINAL: + return view == 15; + case JT_WIZARD: + case JT_WIZARD_H: + case JT_WIZARD_B: + case JT_LINKER: + case JT_WARLOCK: + case JT_WARLOCK_H: + case JT_WARLOCK_B: + case JT_LINKER_B: + case JT_SOUL_REAPER: + case JT_SOUL_REAPER_B: + case JT_ARCH_MAGE: + case JT_SOUL_ASCETIC: + if (view == 1) { + return slot == 1; + } + + if (view == 10 || view == 23) { + return slot == 0; + } + + return false; + case JT_BLACKSMITH: + case JT_BLACKSMITH_H: + case JT_BLACKSMITH_B: + case JT_MECHANIC: + case JT_MECHANIC_H: + case JT_MADOGEAR: + case JT_MADOGEAR_H: + case JT_MECHANIC_B: + case JT_MADOGEAR_B: + case JT_MEISTER: + case JT_MEISTER_MADOGEAR: + case JT_DRUID: + case JT_DRUID_B: + case JT_KARNOS: + case JT_KARNOS_B: + case JT_ALITEA: + switch (view) { + case 2: + case 6: + case 7: + case 8: + return true; + default: + return false; + } + case JT_ASSASSIN: + case JT_ASSASSIN_H: + case JT_ASSASSIN_B: + case JT_GUILLOTINE_CROSS: + case JT_GUILLOTINE_CROSS_H: + case JT_GUILLOTINE_CROSS_B: + case JT_SHADOW_CROSS: + switch (view) { + case 16: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + return true; + default: + return false; + } + case JT_MONK: + case JT_MONK_H: + case JT_MONK_B: + case JT_SURA: + case JT_SURA_H: + case JT_SURA_B: + case JT_INQUISITOR: + return view == 0 || view == 12; + case JT_SAGE: + case JT_SAGE_H: + case JT_SAGE_B: + case JT_SORCERER: + case JT_SORCERER_H: + case JT_SORCERER_B: + case JT_ELEMENTAL_MASTER: + switch (view) { + case 5: + case 10: + case 15: + case 23: + return true; + default: + return false; + } + case JT_ALCHEMIST: + case JT_ALCHEMIST_H: + case JT_ALCHEMIST_B: + case JT_GENETIC: + case JT_GENETIC_H: + case JT_GENETIC_B: + case JT_BIOLO: + switch (view) { + case 2: + case 6: + case 7: + case 8: + return true; + default: + return false; + } + case JT_NOVICE: + case JT_SUPERNOVICE: + case JT_NOVICE_H: + case JT_NOVICE_B: + case JT_SUPERNOVICE_B: + case JT_SUPERNOVICE2: + case JT_SUPERNOVICE2_B: + case JT_HYPER_NOVICE: + if (slot == 0) { + return view == 1; + } + + if (slot != 1) { + return false; + } + + switch (view) { + case 2: + case 3: + case 6: + case 7: + case 8: + case 9: + case 10: + case 23: + return true; + default: + return false; + } + case JT_GUNSLINGER: + case JT_REBELLION: + case JT_GUNSLINGER_B: + case JT_REBELLION_B: + case JT_NIGHT_WATCH: + return view >= 18 && view <= 21; + case JT_NINJA: + case JT_KAGEROU: + case JT_OBORO: + case JT_NINJA_B: + case JT_KAGEROU_B: + case JT_OBORO_B: + case JT_SHINKIRO: + case JT_SHIRANUI: + return view == 22; + default: + return false; + } +} // OFFSET: 0x00DFBE10 // FUNCTION: fn_23590 @@ -141,6 +407,16 @@ bool __stdcall IsVisibleJob(int job) { } // OFFSET: 0x00E19230 +// FUNCTION: fn_23836 +std::string GetJobTitleString(int job) { + const char* title = nullptr; + + if (!g_session.m_hotkeyScript->Call("GetTitleString", "d>s", job, &title)) { + return ""; + } + + return title ? title : ""; +} // OFFSET: 0x00E19530 // FUNCTION: fn_23841 @@ -155,6 +431,77 @@ int __stdcall GetWeaponViewValue(int weapon) { } // OFFSET: 0x00E248F0 +// FUNCTION: fn_23898 +int __stdcall GetDualWieldWeaponType(int first, int second) { + int main = first; + int result = 0; + int sub; + + if (first != 0) { + sub = second; + } else { + main = second; + + if (second == 0) { + return result; + } + + sub = 0; + } + + if (main >= 1100 && main < 1150 || main >= 13400 && main < 13500 || static_cast(main - 500000) <= 0x270F) { + result = 2; + + if (sub >= 1100 && sub < 1150 || sub >= 13400 && sub < 13500 || static_cast(sub - 500000) <= 0x270F) { + return 26; + } + + if ((sub < 1200 || sub >= 1250) && (sub < 13000 || sub >= 13100) && (sub < 28700 || sub >= 28900) && + static_cast(sub - 510000) > 0x270F) { + if (sub >= 1300 && sub < 1350 || static_cast(sub - 520000) <= 0x270F) { + return 30; + } + + return result; + } + + return 28; + } + + if (main >= 1200 && main < 1250 || main >= 13000 && main < 13100 || main >= 28700 && main < 28900 || + static_cast(main - 510000) <= 0x270F) { + result = 1; + + if ((sub < 1100 || sub >= 1150) && (sub < 13400 || sub >= 13500) && static_cast(sub - 500000) > 0x270F) { + if (sub >= 1200 && sub < 1250 || sub >= 13000 && sub < 13100 || sub >= 28700 && sub < 28900 || + static_cast(sub - 510000) <= 0x270F) { + return 25; + } + + if (sub >= 1300 && sub < 1350 || static_cast(sub - 520000) <= 0x270F) { + return 29; + } + + return result; + } + + return 28; + } + + if (main >= 1300 && main < 1350 || static_cast(main - 520000) <= 0x270F) { + result = 6; + + if (sub >= 1300 && sub < 1350) { + return 27; + } + + if (static_cast(sub - 520000) <= 0x270F) { + return 27; + } + } + + return result; +} // OFFSET: 0x00E25970 // FUNCTION: fn_23906 @@ -164,6 +511,18 @@ bool ResetHotkeySlots() { } // OFFSET: 0x00E25E60 +// FUNCTION: fn_23909 +std::pair* CSession::InsertPair(int key, int value) { + for (auto& entry : this->unknown_0778) { + if (entry.first == key) { + entry.second = value; + return &entry; + } + } + + this->unknown_0778.push_back(std::make_pair(key, value)); + return &this->unknown_0778.back(); +} // OFFSET: 0x00E25EE0 // FUNCTION: fn_23910 @@ -187,5 +546,38 @@ int CSession::SetPairValue(int value, int slot) { } // OFFSET: 0x00E25F20 +// FUNCTION: fn_23911 +int CSession::SetHotkeyEntry(char enabled, int id, int value, int slot) { + for (int index = 0; index < 2; ++index) { + NormalItemSlot& entry = this->SkillHotkey(index); + + if (id == static_cast(entry.itemId) && value == entry.unknown_0005 && enabled == static_cast(entry.unknown_0000) || + !CSkillInfo::UsesLevel(*g_session.m_hotkeyScript, static_cast(entry.itemId)) && id == static_cast(entry.itemId)) { + entry.unknown_0000 = 0; + entry.itemId = 0; + entry.unknown_0005 = 0; + g_world.ActiveGameMode()->SendMsg(313, index + 36, 0, 0, 0); + } + } + + if (id == 0) { + enabled = 0; + value = 0; + } + + NormalItemSlot& target = this->SkillHotkey(slot); + target.unknown_0000 = static_cast(enabled); + target.itemId = static_cast(id); + target.unknown_0005 = static_cast(value); + + return g_world.ActiveGameMode()->SendMsg(313, slot + 36, 0, 0, 0); +} // OFFSET: 0x00E26030 +// FUNCTION: fn_23912 +int CSession::SetFlag(char value) { + const int result = value & 1; + this->unknown_0E98 = result; + this->unknown_5558 = result; + return result; +}