#include "Client/Application/Launcher.h" #include "Client/Input/InputCharset.h" #include "Client/Mode/CGameMode.h" #include "Client/Mode/CLoginMode.h" #include "Client/Mode/ModeMgr.h" #include "Client/Replay.h" #include "Client/Stove/StoveMgr.h" #include "Client/Session.h" #include "Contents/Actors/ActorStateFlags.h" #include "Contents/Actors/GameActor.h" #include "Contents/Actors/Item.h" #include "Contents/Actors/Pc.h" #include "Contents/Actors/RenderObject.h" #include "Contents/ClientState.h" #include "Contents/Configuration/ServiceConfiguration.h" #include "Contents/Configuration/ServiceOptions.h" #include "Contents/Effects/EffectActor.h" #include "Contents/Effects/Effect.h" #include "Contents/Effects/EffectLists.h" #include "Contents/Effects/RagEffect.h" #include "Contents/Effects/EffectTypes.h" #include "Contents/ForbiddenWords.h" #include "Contents/GuildInfo.h" #include "Contents/GuildMgr.h" #include "Contents/Items/ItemDescription.h" #include "Contents/Items/ItemInfo.h" #include "Contents/Items/ItemNaming.h" #include "Contents/Jobs/JobId.h" #include "Contents/Jobs/JobInheritance.h" #include "Contents/MapPropertyMgr.h" #include "Contents/MessageTable.h" #include "Contents/Messenger/ClientMessenger.h" #include "Contents/NavigationManager.h" #include "Contents/PlayerNameDictionary.h" #include "Contents/RenewQuestMgr.h" #include "Contents/RodexMailStore.h" #include "Contents/RouletteMgr.h" #include "Contents/Schedule/CaptchaUploadSchedule.h" #include "Contents/Schedule/CheckGDISchedule.h" #include "Contents/Schedule/TimeScheduler.h" #include "Contents/Skills/SkillInfo.h" #include "Contents/Sound/SoundMgr.h" #include "Contents/World/World.h" #include "File/ShortcutFilename.h" #include "Network/Connection/Connection.h" #include "Network/Packets/PacketLengths.h" #include "Render/Renderer.h" #include "Resource/World/TerrainResource.h" #include "UI/AdventureGuide/UIAdventureGuide.h" #include "UI/CashShop/UICashShopWnd.h" #include "UI/Dialogs/UISayDialogWnd.h" #include "UI/Guild/UIGuild_Storage_Log.h" #include "UI/Rodex/UIRodexComposeWnd.h" #include "UI/Text/UITagTextViewer.h" #include "UI/UICaptchaPreviewWnd.h" #include "UI/UICaptchaRegisterWnd.h" #include "UI/UIGradeEnchantWnd.h" #include "UI/UILapineScrollBar.h" #include "UI/UILapineUpgradeBoxWnd.h" #include "UI/UIMacroBlackListCheckWnd.h" #include "UI/UIMacroDetectorWnd.h" #include "UI/UIMacroUserInfoWnd.h" #include "UI/UIRefiningWnd.h" #include "UI/Status/UIStatusWnd.h" #include "UI/Window/UINewSelectCharWnd.h" #include "UI/Window/UIRodexContentsWnd.h" #include "UI/Window/UIWindow.h" #include "UI/Window/UIWindowMgr.h" #include "UI/Window/WindowDialogs.h" #include "Utility/Text/FormatString.h" #include "Utility/Math/AffineMatrix.h" #include "UI/UIBroadcastBalloon.h" #include #include #include #include #include #include #include #include #include // GLOBAL: gl_25253 int g_localMapMove; #include "UI/Rodex/UIRodexInboxWnd.h" #pragma pack(push, 1) struct ActorPairFreezePacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t firstAid; /* 0006 */ std::uint32_t secondAid; /* 000A */ int frozen; }; struct ActorEffectPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; /* 0006 */ int effectId; }; struct ActorPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; }; struct ShortValuePacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t value; }; struct ActorPointPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; /* 0006 */ std::int16_t x; /* 0008 */ std::int16_t y; }; struct VariablePacketHeader { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; }; struct RodexMailDeletedPacket { /* 0000 */ std::int16_t id; /* 0002 */ unsigned char type; /* 0003 */ std::int64_t mailId; }; struct RouletteResultPacket { /* 0000 */ std::int16_t id; /* 0002 */ unsigned char result; /* 0003 */ std::uint16_t stage; /* 0005 */ std::uint16_t index; /* 0007 */ int additionItemId; /* 000B */ int goldPoint; /* 000F */ int silverPoint; /* 0013 */ int bronzePoint; }; struct ByteValuePacket { /* 0000 */ std::int16_t id; /* 0002 */ unsigned char value; }; struct StatusPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t statusPoint; /* 0004 */ unsigned char stats[12]; /* 0010 */ std::int16_t values[14]; }; struct StatusChangePacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint16_t type; /* 0004 */ unsigned char value; }; struct StatusChangeAckPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint16_t type; /* 0004 */ unsigned char result; /* 0005 */ unsigned char value; }; struct StatusChangeEffectPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; /* 0006 */ std::int16_t type; /* 0008 */ std::uint32_t remaining; /* 000C */ int value1; /* 0010 */ int value2; /* 0014 */ int value3; }; struct ItemSlotOption { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t value; /* 0004 */ unsigned char parameter; }; struct ItemSlotAddOptionsPacket { /* 0000 */ std::int16_t id; /* 0002 */ int itemId; /* 0006 */ unsigned char type; /* 0007 */ int slot; /* 000B */ unsigned char identified; /* 000C */ unsigned char damaged; /* 000D */ unsigned char refine; /* 000E */ unsigned char cards[16]; /* 001E */ ItemSlotOption options[5]; /* 0037 */ std::uint32_t expireTime; /* 003B */ std::uint16_t bindType; }; struct ItemSlotAddGradePacket { /* 0000 */ std::int16_t id; /* 0002 */ int itemId; /* 0006 */ unsigned char type; /* 0007 */ int slot; /* 000B */ unsigned char identified; /* 000C */ unsigned char damaged; /* 000D */ unsigned char cards[16]; /* 001D */ ItemSlotOption options[5]; /* 0036 */ std::uint32_t expireTime; /* 003A */ std::uint16_t bindType; /* 003C */ unsigned char refine; /* 003D */ unsigned char grade; }; struct ItemOptionsRefreshPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint16_t index; /* 0004 */ std::uint16_t refine; /* 0006 */ ItemSlotOption options[5]; }; struct PacketIdOnly { /* 0000 */ std::int16_t id; }; struct AccountRequestPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; }; struct Window227ResultPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint16_t first; /* 0004 */ std::uint16_t second; /* 0006 */ unsigned char result; }; struct RouletteOpenPacket { /* 0000 */ std::int16_t id; /* 0002 */ unsigned char result; /* 0003 */ int serial; /* 0007 */ unsigned char stage; /* 0008 */ unsigned char index; /* 0009 */ int additionItemId; /* 000D */ int goldPoint; /* 0011 */ int silverPoint; /* 0015 */ int bronzePoint; }; struct RodexOpenPacket { /* 0000 */ std::int16_t id; /* 0002 */ char text[24]; /* 001A */ unsigned char result; }; struct StackedItemReturnPacket { /* 0000 */ std::int16_t id; /* 0002 */ unsigned char result; /* 0003 */ std::int16_t index; /* 0005 */ std::uint16_t count; /* 0007 */ std::uint16_t value; }; struct RouletteInfoSlot { /* 0000 */ std::int16_t row; /* 0002 */ std::int16_t column; /* 0004 */ int itemId; /* 0008 */ std::int16_t count; /* 000A */ std::int16_t unknown_000A; }; struct RouletteInfoPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; /* 0004 */ int unknown_0004; /* 0008 */ RouletteInfoSlot slots[42]; }; #pragma pack(pop) // INLINED static int CountItemSlotOptions(const ItemSlotOption* options) { int count = 0; for (int index = 0; index < 5; ++index) { if (options[index].id != 0) { ++count; } } return count; } // OFFSET: 0x00D45740 // FUNCTION: fn_21839 void CGameMode::ReceiveStatus(const unsigned char* data) { const auto* packet = reinterpret_cast(data); int* bonusStats = reinterpret_cast(g_session.unknown_169C); g_session.m_standardStats[0] = packet->stats[0]; g_session.InvalidateWindowFrames(); g_session.m_standardStats[1] = packet->stats[2]; g_session.InvalidateWindowFrames(); g_session.m_standardStats[2] = packet->stats[4]; g_session.InvalidateWindowFrames(); g_session.m_standardStats[3] = packet->stats[6]; g_session.InvalidateWindowFrames(); g_session.m_standardStats[4] = packet->stats[8]; g_session.InvalidateWindowFrames(); g_session.m_standardStats[5] = packet->stats[10]; g_session.InvalidateWindowFrames(); bonusStats[0] = packet->stats[1]; g_session.InvalidateWindowFrames(); bonusStats[1] = packet->stats[3]; g_session.InvalidateWindowFrames(); bonusStats[2] = packet->stats[5]; g_session.InvalidateWindowFrames(); bonusStats[3] = packet->stats[7]; g_session.InvalidateWindowFrames(); bonusStats[4] = packet->stats[9]; g_session.InvalidateWindowFrames(); bonusStats[5] = packet->stats[11]; g_session.InvalidateWindowFrames(); *reinterpret_cast(g_session.unknown_1654) = packet->statusPoint; g_session.InvalidateWindowFrames(); bonusStats[7] = packet->values[0]; g_session.InvalidateWindowFrames(); bonusStats[12] = packet->values[1]; g_session.InvalidateWindowFrames(); bonusStats[13] = packet->values[2]; g_session.InvalidateWindowFrames(); bonusStats[14] = packet->values[3]; g_session.InvalidateWindowFrames(); bonusStats[10] = packet->values[4]; g_session.InvalidateWindowFrames(); bonusStats[11] = packet->values[5]; g_session.InvalidateWindowFrames(); bonusStats[8] = packet->values[6]; g_session.InvalidateWindowFrames(); bonusStats[15] = packet->values[7]; g_session.InvalidateWindowFrames(); bonusStats[16] = packet->values[8]; g_session.InvalidateWindowFrames(); bonusStats[17] = packet->values[9]; g_session.InvalidateWindowFrames(); bonusStats[19] = packet->values[10]; g_session.InvalidateWindowFrames(); bonusStats[18] = packet->values[11]; g_session.InvalidateWindowFrames(); bonusStats[6] = packet->values[12]; g_session.InvalidateWindowFrames(); bonusStats[9] = packet->values[13]; g_session.InvalidateWindowFrames(); if (UIWindow* window = reinterpret_cast(g_windowMgr.unknown_01C4)) { window->SendMsg(nullptr, 35, 0, 0, 0, 0); } } // OFFSET: 0x00D45970 // FUNCTION: fn_21840 void CGameMode::ReceiveStatusChange(const unsigned char* data) { const auto* packet = reinterpret_cast(data); const unsigned int type = packet->type; if (type >= 32 && type <= 37) { reinterpret_cast(g_session.unknown_169C)[type - 32] = packet->value; g_session.InvalidateWindowFrames(); } else if (type >= 247 && type <= 252) { reinterpret_cast(&g_session.unknown_7FC0[0x20])[type - 247] = packet->value; g_session.InvalidateWindowFrames(); } if (UIWindow* window = reinterpret_cast(g_windowMgr.unknown_01C4)) { window->SendMsg(nullptr, 35, 0, 0, 0, 0); } } // OFFSET: 0x00D6EB40 // FUNCTION: fn_22115 void CGameMode::ReceiveStatusChangeEffect(const unsigned char* data) { const auto* packet = reinterpret_cast(data); this->ApplyStatusChange(packet->aid, 1, packet->type, packet->remaining, packet->value1, packet->value2, packet->value3, 1, 0); } // OFFSET: 0x00D45B90 // FUNCTION: fn_21841 void CGameMode::ReceiveStatusChangeAck(const unsigned char* data) { this->unknown_02D4 = 0; UIWindow* window = reinterpret_cast(g_windowMgr.unknown_01C4); const auto* packet = reinterpret_cast(data); if (!packet->result) { return; } int* bonusStats = reinterpret_cast(g_session.unknown_169C); switch (packet->type) { case 13: case 14: case 15: case 16: case 17: case 18: g_session.m_standardStats[packet->type - 13] = packet->value; g_session.InvalidateWindowFrames(); if (window) { window->SendMsg(nullptr, 35, 0, 0, 0, 0); } break; case 41: bonusStats[7] = packet->value; g_session.InvalidateWindowFrames(); break; case 42: bonusStats[12] = packet->value; g_session.InvalidateWindowFrames(); break; case 43: bonusStats[13] = packet->value; g_session.InvalidateWindowFrames(); break; case 44: bonusStats[14] = packet->value; g_session.InvalidateWindowFrames(); break; case 45: bonusStats[10] = packet->value; g_session.InvalidateWindowFrames(); break; case 46: bonusStats[11] = packet->value; g_session.InvalidateWindowFrames(); break; case 47: bonusStats[8] = packet->value; g_session.InvalidateWindowFrames(); break; case 48: bonusStats[15] = packet->value; g_session.InvalidateWindowFrames(); break; case 49: bonusStats[16] = packet->value; g_session.InvalidateWindowFrames(); break; case 50: bonusStats[17] = packet->value; g_session.InvalidateWindowFrames(); break; case 51: bonusStats[19] = packet->value; g_session.InvalidateWindowFrames(); break; case 52: bonusStats[18] = packet->value; g_session.InvalidateWindowFrames(); break; case 53: bonusStats[6] = packet->value; g_session.InvalidateWindowFrames(); break; case 54: bonusStats[9] = packet->value; g_session.InvalidateWindowFrames(); break; case 55: g_session.m_jobLevel = packet->value; g_session.InvalidateWindowFrames(); g_windowMgr.EnsureWindow(49); break; } } // OFFSET: 0x00D45E30 // FUNCTION: fn_21842 void CGameMode::StopActorMove(std::uint32_t aid, std::int16_t x, std::int16_t y, unsigned char flag) { CRenderObject* actor; if (aid == g_session.m_aid) { actor = this->scene->player; } else { actor = this->scene->GetGameActorByAID(aid); if (!actor) { return; } } const int posX = x; const int posY = y; const int value = flag; actor->SendMsg(nullptr, 19, 0, posX, posX >> 31, posY, posY >> 31, 0, 0, value, value >> 31, 0, 0, 0, 0); } // OFFSET: 0x00D69140 // FUNCTION: fn_22044 void CGameMode::NotifyResult2877(int result) { switch (result) { case 0: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2877)), 0xFF, 0, 0, 0); break; case 1: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2878)), 0xFF, 0, 0, 0); break; case 2: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2879)), 0xFF, 0, 0, 0); break; } } // OFFSET: 0x00D69700 // FUNCTION: fn_22051 void CGameMode::ReceiveRodexMailDeleted(const unsigned char* packet) { const auto* deleted = reinterpret_cast(packet); std::map::iterator mail; std::map::iterator end; switch (deleted->type) { case 0: mail = g_rodexMailStore->m_mails0.find(deleted->mailId); end = g_rodexMailStore->m_mails0.end(); break; case 1: mail = g_rodexMailStore->m_mails1.find(deleted->mailId); end = g_rodexMailStore->m_mails1.end(); break; case 2: mail = g_rodexMailStore->m_mails2.find(deleted->mailId); end = g_rodexMailStore->m_mails2.end(); break; default: goto refresh; } if (mail != end) { mail->second.unknown_0190 = 1; if (!mail->second.isRead) { --g_rodexMailStore->unknown_0018; if (g_rodexMailStore->unknown_0018 == 0) { UIWindow* window = g_windowMgr.LookupWindow(307); if (window) { window->SendMsg(nullptr, 6, 286, 476, 0, 0); } } } } refresh: if (g_windowMgr.unknown_0454) { reinterpret_cast(g_windowMgr.unknown_0454)->Invalidate(); } } // OFFSET: 0x00D69850 // FUNCTION: fn_22052 void CGameMode::NotifyResult3562(const unsigned char* packet) { switch (reinterpret_cast(packet)->value) { case 0: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3566)), 0xFFFF00, 0, 0, 0); break; case 1: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3562)), 0xFF, 0, 0, 0); break; case 2: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3563)), 0xFF, 0, 0, 0); break; case 3: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3564)), 0xFF, 0, 0, 0); break; case 4: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3565)), 0xFF, 0, 0, 0); break; } } // OFFSET: 0x00D698F0 // FUNCTION: fn_22053 void CGameMode::IgnoreRemovedPacket6() { } // OFFSET: 0x00D69900 // FUNCTION: fn_22054 void CGameMode::ReceiveRouletteResult(const unsigned char* packet) { const auto* result = reinterpret_cast(packet); unsigned char bonus; switch (result->result) { case 0: g_rouletteMgr->m_stage = result->stage; g_rouletteMgr->SetAdditionItem(result->additionItemId); bonus = 0; break; case 3: g_rouletteMgr->m_stage = result->stage; g_rouletteMgr->SetAdditionItem(result->additionItemId); bonus = 1; break; case 1: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2634)), 0x64FFFF, 0, 0, 0); if (g_windowMgr.unknown_0464) { g_windowMgr.EnableRouletteWnd(); } return; case 2: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2635)), 0x64FFFF, 0, 0, 0); if (g_windowMgr.unknown_0464) { g_windowMgr.EnableRouletteWnd(); } return; case 4: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2693)), 0x64FFFF, 0, 0, 0); if (g_windowMgr.unknown_0464) { g_windowMgr.EnableRouletteWnd(); } return; case 5: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2700)), 0x64FFFF, 0, 0, 0); if (g_windowMgr.unknown_0464) { g_windowMgr.EnableRouletteWnd(); } return; default: return; } g_rouletteMgr->m_goldPoint = result->goldPoint; g_rouletteMgr->m_silverPoint = result->silverPoint; g_rouletteMgr->m_bronzePoint = result->bronzePoint; g_rouletteMgr->SetResult(result->index, 0, bonus); g_rouletteMgr->StartSpin(461, 341 - result->stage * 40, static_cast(g_renderer->viewport.width * 0.5 - 320.0), static_cast(g_renderer->viewport.height * 0.5 - 240.0)); } // OFFSET: 0x00D69FC0 // FUNCTION: fn_22057 void CGameMode::NotifyResult4013(unsigned char result, unsigned short value) { char text[256]; switch (result) { case 0: std::memset(text, 0, sizeof(text)); StringFormat(text, sizeof(text), static_cast(-1), LookupMessage(4013), value); g_windowMgr.SendNotice(1, reinterpret_cast(text), 0xFFFF00, 0, 0, 0); break; case 1: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4014)), 0xFF, 0, 0, 0); break; case 2: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4015)), 0xFF, 0, 0, 0); break; case 3: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4016)), 0xFF, 0, 0, 0); break; case 4: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4017)), 0xFF, 0, 0, 0); break; case 5: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4018)), 0xFF, 0, 0, 0); break; } } // OFFSET: 0x00D6AE70 // FUNCTION: fn_22065 void CGameMode::NotifyWindow4F258(int result) { UIWindow* window = g_windowMgr.window_4F258; if (!window) { return; } switch (result) { case 0: if (!g_windowMgr.modalWindows.empty() && g_windowMgr.modalWindows.back()) { g_windowMgr.unknown_0474 = 188; } break; case 1: window->SendMsg(nullptr, 154, reinterpret_cast(LookupMessage(2825)), 0, 0, 0); break; case 2: window->SendMsg(nullptr, 154, reinterpret_cast(LookupMessage(3333)), 0, 0, 0); break; case 3: window->SendMsg(nullptr, 154, reinterpret_cast(LookupMessage(3332)), 0, 0, 0); break; case 4: window->SendMsg(nullptr, 154, reinterpret_cast(LookupMessage(3331)), 0, 0, 0); break; case 5: window->SendMsg(nullptr, 154, reinterpret_cast(LookupMessage(3352)), 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(1923)), 0xFF, 0, 0, 0); break; } } // OFFSET: 0x00D6B950 // FUNCTION: fn_22071 void CGameMode::ReceiveNamedResult(std::uint32_t, std::string name, int result) { switch (result) { case 0: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4068)), 0x64FFFF, 0, 0, 0); break; case 1: { g_windowMgr.SendNotice(1, reinterpret_cast(FormatOwnedString(LookupMessage(4069), name.c_str()).c_str()), 0x64FFFF, 0, 0, 0); CWorld* scene = static_cast(g_modeMgr.GetGameMode())->scene; if (scene) { scene->player->LaunchEffect(41, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); } break; } case 2: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4070)), 0x64FFFF, 0, 0, 0); break; case 3: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4071)), 0x64FFFF, 0, 0, 0); break; case 4: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4072)), 0x64FFFF, 0, 0, 0); break; case 5: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4073)), 0x64FFFF, 0, 0, 0); break; case 6: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4096)), 0x64FFFF, 0, 0, 0); break; case 7: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4000)), 0x64FFFF, 0, 0, 0); break; } } // OFFSET: 0x00D6BBC0 // FUNCTION: fn_22073 void CGameMode::ReceiveBasicInfoResult(unsigned char result) { switch (result) { case 1: case 2: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3956)), 0xFF, 0, 0, 0); if (g_windowMgr.unknown_01E0) { g_windowMgr.unknown_01E0->SendMsg(nullptr, 106, 575, 0, 0, 0); } break; } if (g_windowMgr.unknown_01E0) { g_windowMgr.unknown_01E0->SendMsg(nullptr, 106, 575, 0, 0, 0); } } // OFFSET: 0x00D6BD40 // FUNCTION: fn_22075 void CGameMode::ReceiveUnknown0454Result(const unsigned char* data) { const auto* packet = reinterpret_cast(data); switch (packet->value) { case 0: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2587)), 0x64FFFF, 0, 0, 0); break; case 1: g_modeMgr.GetGameMode()->SendMsg(293, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2597)), 0x64FFFF, 0, 0, 0); break; case 2: g_modeMgr.GetGameMode()->SendMsg(293, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2603)), 0x64FFFF, 0, 0, 0); break; case 3: g_modeMgr.GetGameMode()->SendMsg(293, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2598)), 0x64FFFF, 0, 0, 0); break; case 4: g_modeMgr.GetGameMode()->SendMsg(293, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2599)), 0x64FFFF, 0, 0, 0); break; } if (g_windowMgr.unknown_0454) { reinterpret_cast(g_windowMgr.unknown_0454)->SendMsg(nullptr, 60, 0, 0, 0, 0); } } // OFFSET: 0x00D6BFA0 // FUNCTION: fn_22077 void CGameMode::ReceiveWindow154Result(std::int16_t value) { switch (value) { case 0: { UIWindow* window = g_windowMgr.LookupWindow(340); if (window) { window->SendMsg(nullptr, 64, 1, 0, 0, 0); } break; } case 1: { UIWindow* window = g_windowMgr.LookupWindow(340); if (window) { window->SendMsg(nullptr, 64, 1, 1, 0, 0); } break; } case 3: { UIWindow* window = g_windowMgr.LookupWindow(340); if (window) { window->SendMsg(nullptr, 64, 1, 3, 0, 0); } break; } case 2: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2517)), 0xFF, 0, 0, 0); break; } } // OFFSET: 0x00D6D200 // FUNCTION: fn_22087 void CGameMode::ReceiveResultNotice(int result) { switch (result) { case 0: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4125)), 0xFF, 0, 0, 0); break; case 1: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4126)), 0xFF, 0, 0, 0); break; case 2: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4127)), 0xFF, 0, 0, 0); break; } } // OFFSET: 0x00D6D260 // FUNCTION: fn_22088 void CGameMode::ReceiveActorPairFreeze(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (packet->frozen) { CRenderObject* first = packet->firstAid == g_session.m_aid ? this->scene->player : this->scene->GetGameActorByAID(packet->firstAid); CRenderObject* second = packet->secondAid == g_session.m_aid ? this->scene->player : this->scene->GetGameActorByAID(packet->secondAid); if (first && second) { first->SetFrameSequence(96, 4, 4, 96, 4, 1, 99999999, 0); first->render.unknown_00A3 = 1; first->SetColor(-1, 64, 64, 64); first->render.instant.Set(3, 1); second->render.instant.Set(3, 1); second->render.isMotionFreezed = true; second->render.unknown_00A3 = 1; second->SetColor(-1, 64, 64, 64); } } else { CRenderObject* first = packet->firstAid == g_session.m_aid ? this->scene->player : this->scene->GetGameActorByAID(packet->firstAid); CRenderObject* second = packet->secondAid == g_session.m_aid ? this->scene->player : this->scene->GetGameActorByAID(packet->secondAid); if (first) { first->SetFrameSequence(96, 4, 4, 96, 4, 1, 1, 0); first->render.unknown_00A3 = 0; first->SetColor(-1, 255, 255, 255); first->render.instant.Set(3, 0); } if (second) { second->render.isMotionFreezed = false; second->render.unknown_00A3 = 0; second->SetColor(-1, 255, 255, 255); second->render.instant.Set(3, 0); } } } // OFFSET: 0x00D6E100 // FUNCTION: fn_22096 void CGameMode::RefreshWindow16(const unsigned char*) { UIWindow* window = g_windowMgr.LookupWindow(16); if (window) { window->SendMsg(nullptr, 75, 0, 0, 0, 0); } } // OFFSET: 0x00D6E130 // FUNCTION: fn_22097 void CGameMode::ReceiveEffectRemove(const unsigned char* data) { const auto* packet = reinterpret_cast(data); CRenderObject* actor = this->scene->GetGameActorByAidIncludeMe(packet->aid); if (actor) { while (static_cast(actor)->state.Attachments().HasId(packet->effectId)) { actor->SendMsg(nullptr, 109, 0, packet->effectId, packet->effectId >> 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } } while (g_effectMgr->Find(packet->aid, packet->effectId)) { g_effectMgr->Retire(packet->aid, packet->effectId); } } // OFFSET: 0x00D6E930 // FUNCTION: fn_22107 void CGameMode::ReceiveToggle128(int enabled) { sub_E489C0(enabled != 0); } // OFFSET: 0x00D6E950 // FUNCTION: fn_22108 void CGameMode::ReceiveActorEffect347(const unsigned char* data) { if (g_serviceOptions.Get(8)) { const auto* packet = reinterpret_cast(data); CRenderObject* actor = packet->aid == g_session.m_aid ? this->scene->player : this->scene->GetGameActorByAID(packet->aid); if (actor && packet->aid) { static_cast(actor)->LaunchEffect(347, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); } } } // OFFSET: 0x00D6E9D0 // FUNCTION: fn_22109 void CGameMode::ReceiveUnknown0294Text(const unsigned char* data) { std::sprintf(this->unknown_0294, reinterpret_cast(data + 2)); } // OFFSET: 0x00D6E9F0 // FUNCTION: fn_22110 void CGameMode::ReceiveWindow154Close(std::int16_t value) { if (value == 0) { UIWindow* window = g_windowMgr.LookupWindow(340); if (window) { window->SendMsg(nullptr, 64, 2, 0, 0, 0); } } } // OFFSET: 0x00D6EA30 // FUNCTION: fn_22111 void CGameMode::SetWindow16Align(unsigned char align) { UISayDialogWnd* window = static_cast(g_windowMgr.LookupWindow(16)); if (window) { static_cast(window->m_viewer)->SetAlign(align); } } // OFFSET: 0x00D6EA60 // FUNCTION: fn_22112 void CGameMode::PlaceWindow16(unsigned int xPercent, unsigned int yPercent) { UIWindow* window = g_windowMgr.LookupWindow(16); if (window) { window->Move(static_cast((g_renderer->viewport.width - window->geometry.width) * (xPercent * 0.01)), static_cast((g_renderer->viewport.height - window->geometry.height) * (yPercent * 0.01))); } } // OFFSET: 0x00D6EB00 // FUNCTION: fn_22113 void CGameMode::MoveWindow16(int x, int y) { UIWindow* window = g_windowMgr.LookupWindow(16); if (window) { window->Move(x, y); } } // OFFSET: 0x00D6EB20 // FUNCTION: fn_22114 void CGameMode::ResizeWindow16(int width, int height) { UIWindow* window = g_windowMgr.LookupWindow(16); if (window) { window->Resize(width, height); } } // OFFSET: 0x00D6EBD0 // FUNCTION: fn_22117 void CGameMode::ReceiveUnknown7FBC(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (packet->value <= 100) { g_session.unknown_7FBC = packet->value; if (g_windowMgr.unknown_01D4) { reinterpret_cast(g_windowMgr.unknown_01D4)->SendMsg(nullptr, 23, 0, 0, 0, 0); } } } // OFFSET: 0x00D6EC10 // FUNCTION: fn_22118 void CGameMode::ReceiveNotice1950(const unsigned char*) { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(1950)), 0xFF, 0, 0, 0); } // OFFSET: 0x00D6EC40 // FUNCTION: fn_22119 void CGameMode::ReceiveActorMessage144(const unsigned char* data) { const auto* packet = reinterpret_cast(data); CRenderObject* actor; if (packet->aid == g_session.m_aid) { actor = static_cast(g_modeMgr.GetGameMode())->scene->player; } else { actor = g_session.FindGameActor(packet->aid); } if (actor) { const int x = packet->x; const int y = packet->y; actor->SendMsg(nullptr, 144, 0, x, x >> 31, y, y >> 31, 0, 0, 0, 0, 0, 0, 0, 0); } } // OFFSET: 0x00D6EF60 // FUNCTION: fn_22121 void CGameMode::NotifyResult4138(int result) { int message; switch (result) { case 0: message = 4138; break; case 1: message = 4139; break; case 2: message = 4140; break; case 3: message = 4187; break; case 4: message = 4141; break; default: return; } g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(message)), 0xFF, 0, 0, 0); } #pragma pack(push, 1) struct GradeEnchantInfoPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; /* 0004 */ std::int16_t index; /* 0006 */ int value; /* 000A */ GradeEnchantInfo info; /* 001A */ int value1A; /* 001E */ int value1E; }; struct PartyItemPickupPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; /* 0006 */ int itemId; /* 000A */ unsigned char identified; /* 000B */ unsigned char damaged; /* 000C */ std::uint32_t cards[4]; /* 001C */ std::uint16_t location; /* 001E */ unsigned char type; /* 001F */ unsigned char refine; /* 0020 */ unsigned char grade; }; struct ActorEffect228Packet { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; /* 0006 */ std::int16_t value; /* 0008 */ std::uint16_t state; }; #pragma pack(pop) // OFFSET: 0x00D6F870 // FUNCTION: fn_22123 void CGameMode::ReceiveGradeEnchantInfo(const unsigned char* data) { const auto* packet = reinterpret_cast(data); const int count = static_cast(packet->length - sizeof(GradeEnchantInfoPacket)) / sizeof(GradeEnchantMaterial); if (packet->index == -1) { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3720)), 0x62B0FF, 0, 0, 0); return; } auto* window = static_cast(g_windowMgr.LookupWindow(343)); if (window) { window->SetEnchantInfo(packet->index, packet->value, count, packet->info, packet->value1A, packet->value1E, reinterpret_cast(data + sizeof(GradeEnchantInfoPacket))); } } // OFFSET: 0x00D6FCD0 // FUNCTION: fn_22127 void CGameMode::ReceivePartyItemPickup(const unsigned char* data) { const auto* packet = reinterpret_cast(data); MessengerMember member = ClientMessenger{g_session.m_partyMembers, g_session.m_friends}.PartyByAccount(packet->aid); if (packet->aid != g_session.m_aid && member.valid) { ITEM_INFO item; item.unknown_0000[0] = packet->type; item.unknown_0000[2] = packet->location; item.unknown_0000[1] = packet->itemId; item.unknown_0000[3] = 0; item.SetItemId(packet->itemId); std::memcpy(item.unknown_001C, packet->cards, sizeof(packet->cards)); item.identified = packet->identified; item.unknown_005D = packet->damaged; item.unknown_0060 = packet->refine; item.unknown_0088 = packet->grade; ItemDescriptions descriptions{g_itemDescriptions}; bool languagePrefix = false; WORD language = g_serverLanguage->language; ItemNaming naming{descriptions, g_itemCardNames, *g_playerNameDictionary, languagePrefix, g_serviceType, language}; std::string name = naming.DisplayName(item, 0); g_windowMgr.SendNotice(1, reinterpret_cast(FormatOwnedString(LookupMessage(1276), member.name.c_str(), name.c_str()).c_str()), 0xFFFF00, 9, 0, 0); } } // OFFSET: 0x00D71660 // FUNCTION: fn_22135 void CGameMode::NotifyResult3995(unsigned char result) { switch (result) { case 0: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3995)), 0xFFFF, 0, 0, 0); break; case 1: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3996)), 0xFFFF, 0, 0, 0); break; case 2: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3997)), 0xFFFF, 0, 0, 0); break; case 3: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3998)), 0xFFFF, 0, 0, 0); break; case 4: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3999)), 0xFFFF, 0, 0, 0); break; case 5: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4000)), 0xFFFF, 0, 0, 0); break; } } // OFFSET: 0x00D718D0 // FUNCTION: fn_22138 void CGameMode::ReceiveActorEffect228(const unsigned char* data) { if (!g_serviceOptions.Get(8)) { return; } const auto* packet = reinterpret_cast(data); CRenderObject* actor = this->scene->GetGameActorByAID(packet->aid); if (g_session.m_aid == packet->aid) { actor = this->scene->player; } if (!actor) { return; } auto* gameActor = static_cast(actor); if (StateFlag01(gameActor->Slot13()) == true || StateFlag02(gameActor->Slot13()) == true) { actor->SendMsg(nullptr, 109, 0, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } if (packet->state == 0) { actor->SendMsg(nullptr, 109, 0, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } else if (packet->state != 1 || static_cast(actor)->state.Attachments().HasId(228)) { return; } CRagEffect* effect = static_cast(actor)->LaunchEffect(228, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); if (effect) { vector3d position{static_cast(packet->value), 0.0f, 0.0f}; effect->SendMsg(nullptr, 14, 0, reinterpret_cast(&position), 0, 0, 0, 0); } } // OFFSET: 0x00D6FAC0 // FUNCTION: fn_22125 void CGameMode::ReceiveGuildUnknown0114List(const unsigned char* packet) { const auto* header = reinterpret_cast(packet); GuildInfo* guildInfo = reinterpret_cast(reinterpret_cast(&g_guildId) - offsetof(GuildInfo, m_guildId)); guildInfo->ClearUnknown0114(); const int count = header->length - 4; for (int i = 0; i < count; ++i) { unsigned char value; memcpy_s(&value, sizeof(value), packet + sizeof(VariablePacketHeader) + i, sizeof(value)); guildInfo->AddUnknown0114(value); } } #pragma pack(push, 1) struct ShortcutPagePayload { /* 0000 */ NormalItemSlot slots[36]; /* 00FC */ NormalItemSlot slot06EB; /* 0103 */ NormalItemSlot slot06F2; }; struct QuestStateEntry { /* 0000 */ unsigned int questId; /* 0004 */ unsigned char state; }; struct MessageBoxPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint16_t captionId; /* 0004 */ int captionArgument; /* 0008 */ std::uint16_t textId; /* 000A */ int textArgument; }; struct Item1784Entry { /* 0000 */ int itemId; /* 0004 */ int quantity; /* 0008 */ std::uint32_t unknown_0008; /* 000C */ std::uint32_t unknown_000C; /* 0010 */ std::uint32_t unknown_0010; /* 0014 */ std::uint32_t unknown_0014; }; struct Item1784ListPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; /* 0004 */ std::int16_t flag; /* 0006 */ Item1784Entry entries[1]; }; struct ShortcutPagePacket { /* 0000 */ std::int16_t id; /* 0002 */ char position; /* 0003 */ std::uint16_t bank; /* 0005 */ ShortcutPagePayload payload; }; struct CardCompositionPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t equipIndex; /* 0004 */ std::int16_t cardIndex; /* 0006 */ unsigned char result; }; struct RefineResultPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t result; /* 0004 */ std::int16_t index; /* 0006 */ std::int16_t refine; }; struct ItemEffectResultPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t type; /* 0004 */ int itemId; }; #pragma pack(pop) struct ClientItemLists { void ClearItems1738(); void ClearItems1784(int index); void RemoveItem1710(std::uint32_t id, int quantity); bool AddItem1738(const ITEM_INFO& item, unsigned char refresh); bool AddExchangeItem(ITEM_INFO item); void ClearItemSlotQuantities(); void ClearItems1768(); void ClearItems1758(); void ClearItems1748(); void ClearItems1760(); void AddItem1758(const ITEM_INFO& item); void AddItem1748(const ITEM_INFO& item); void AddItem1718(const RawItemBasic& item, int mode); }; struct AchievementStatePacket { /* 0000 */ std::int16_t unknown_0000; /* 0002 */ std::int16_t type; }; // OFFSET: 0x00D18BD0 // FUNCTION: fn_21601 __declspec(noinline) void ReceiveShortcutPage(int position, const ShortcutPagePayload* payload, std::int16_t bank) { int base = 0; if (bank == 0) { g_session.ClearShortcutSlots(); memcpy_s(g_session.m_shortcutSlots, sizeof(g_session.m_shortcutSlots), payload, sizeof(payload->slots)); g_session.ClearSlots06EB(); g_session.unknown_06EB = payload->slot06EB; g_session.unknown_06F2 = payload->slot06F2; base = g_session.unknown_06FC; } else if (bank == 1) { g_session.ClearSecondaryShortcutSlots(); memcpy_s(g_session.m_secondaryShortcutSlots, sizeof(g_session.m_secondaryShortcutSlots), payload, sizeof(payload->slots)); base = g_session.unknown_06A8; } if (g_windowMgr.window_01E8) { g_windowMgr.window_01E8->SendMsg(nullptr, 143, position - base + 4, bank, 0, 0); } } // OFFSET: 0x00D18F60 // FUNCTION: fn_21603 void CGameMode::ResendMinimapMarkers() { if (g_windowMgr.window_4F1CC) { for (auto it = this->minimapMarkers.begin(); it != this->minimapMarkers.end(); ++it) { if (it->second.unknown_0006 != 0) { g_windowMgr.window_4F1CC->SendMsg(nullptr, 485, it->second.unknown_0004, it->second.unknown_0006, it->second.unknown_0000, it->second.unknown_0002); } } } } // OFFSET: 0x00D69260 // FUNCTION: fn_22046 void CGameMode::ReceiveJobTitle(unsigned char result, int job) { if (result != 0) { return; } g_session.unknown_615C = job; std::string title = GetJobTitleString(job); CActorNameCard card = this->LookupNameCard(g_session.m_aid); this->nameCard.SetValue4(g_session.m_aid, title); UIWindow* window = g_windowMgr.LookupWindow(10); if (window) { window->SendMsg(nullptr, 60, 0, 0, 0, 0); } } // OFFSET: 0x00D694C0 // FUNCTION: fn_22049 void CGameMode::ReceiveQuestStates(int count, const unsigned char* data) { const auto* entry = reinterpret_cast(data); for (int i = 0; i < count; ++i, ++entry) { const unsigned int questId = entry->questId; if (entry->state == 1) { g_renewQuestMgr->AddNewQuest(questId); UIWindow* window = g_windowMgr.LookupWindow(10002); if (window) { static_cast(window)->MarkQuest(questId); } } else if (entry->state == 2) { g_renewQuestMgr->RemoveStatusRequest(questId); } } } // OFFSET: 0x00D6E1E0 // FUNCTION: fn_22098 void CGameMode::ReceiveMessageBox(const unsigned char* data) { const auto* packet = reinterpret_cast(data); std::string caption = LookupMessage(packet->captionId); if (packet->captionArgument) { const std::string formatted = FormatOwnedString(caption.c_str(), packet->captionArgument); caption = formatted; } std::string text = LookupMessage(packet->textId); if (packet->textArgument) { const std::string formatted = FormatOwnedString(text.c_str(), packet->textArgument); text = formatted; } reinterpret_cast(&g_windowMgr)->Confirm(text.c_str(), 0, true, false, 0, caption.c_str(), 280, 120, 0); } // OFFSET: 0x00D6E5F0 // FUNCTION: fn_22102 void CGameMode::NotifyCaptchaRegistered() { UIWindow* window = g_windowMgr.LookupWindow(284); if (window) { static_cast(window)->SetRegisterDisabled(0); reinterpret_cast(&g_windowMgr)->Confirm(LookupMessage(2880), 0, true, false, 0, "Message", 280, 120, 0); } } // OFFSET: 0x00D6ECB0 // FUNCTION: fn_22120 void CGameMode::ReceiveItem1784List(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (g_session.unknown_5912 || packet->flag != 0) { return; } const unsigned int count = (packet->length - 6) / sizeof(Item1784Entry); reinterpret_cast(&g_session)->ClearItems1784(9); char name[256]; std::memset(name, 0, sizeof(name)); int capacity = sizeof(name); for (unsigned int i = 0; i < count; ++i) { Item1784Entry entry; memcpy_s(&entry, sizeof(entry), &packet->entries[i], sizeof(entry)); ITEM_INFO item; item.unknown_0000[1] = -1; item.SetItemId(entry.itemId); item.unknown_0078[3] = entry.unknown_0008; item.quantity = entry.quantity; item.unknown_0014[0] = entry.unknown_000C; item.unknown_0078[1] = entry.unknown_0010; item.unknown_0078[2] = entry.unknown_0014; item.unknown_0064 = 8; item.identified = 1; ItemDescriptions descriptions{g_itemDescriptions}; descriptions.Name(item, name, capacity, 0); item.SetName(name); g_session.unknown_1784[9].push_back(item); } UIWindow* window = g_windowMgr.LookupWindow(318); if (window) { window->SendMsg(nullptr, 23, 1, 0, 0, 0); } } // OFFSET: 0x00D48800 // FUNCTION: fn_21854 void CGameMode::ReceiveShortcutPagePacket(const unsigned char* data) { const auto* packet = reinterpret_cast(data); ReceiveShortcutPage(packet->position, &packet->payload, packet->bank); } // OFFSET: 0x00D496D0 // FUNCTION: fn_21858 void CGameMode::ReceiveCardCompositionResult(const unsigned char* data) { const auto* packet = reinterpret_cast(data); switch (packet->result) { case 0: { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(493)), 0xFFFF00, 0, 0, 0); ITEM_INFO card = LookupClientItemByIdentity(g_session.m_inventoryItems, packet->cardIndex); ITEM_INFO equip = LookupClientItemByIdentity(g_session.m_inventoryItems, packet->equipIndex); if (equip.unknown_0000[1] != 0 && card.unknown_0000[1] != 0) { int* cards = reinterpret_cast(equip.unknown_001C); for (int i = 0; i < 4; ++i) { if (cards[i] == 0) { cards[i] = std::atoi(card.itemId.c_str()); break; } } reinterpret_cast(&g_session)->RemoveItem1710(packet->cardIndex, 1); g_session.UpdateInventoryItem(equip, 1); } break; } case 1: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(494)), 0xFF, 0, 0, 0); break; } } // OFFSET: 0x00D499B0 // FUNCTION: fn_21859 void CGameMode::ReceiveRefineResult(const unsigned char* data) { const auto* packet = reinterpret_cast(data); ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, packet->index); if (item.unknown_0000[1] != 0) { item.unknown_0060 = packet->refine; g_session.UpdateInventoryItem(item, 1); } UIRefiningWnd* window = static_cast(g_windowMgr.LookupWindow(295)); if (window) { switch (packet->result) { case 0: window->SetState(2, 3); break; case 1: window->SetState(2, 4); break; case 2: window->SetState(2, 5); break; case 3: window->SetState(2, 6); break; } return; } switch (packet->result) { case 0: static_cast(g_modeMgr.GetGameMode())->scene->player->LaunchEffect(154, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(498)), 0xFFFF00, 0, 0, 0); break; case 1: static_cast(g_modeMgr.GetGameMode())->scene->player->LaunchEffect(155, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(499)), 0xFFFF00, 0, 0, 0); break; case 2: static_cast(g_modeMgr.GetGameMode())->scene->player->LaunchEffect(155, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(1537)), 0xFFFF00, 0, 0, 0); break; } ITEM_INFO refined = LookupClientItemByIdentity(g_session.m_inventoryItems, packet->index); refined.unknown_0060 = packet->refine; g_session.UpdateInventoryItem(refined, 1); } // OFFSET: 0x00D4A650 // FUNCTION: fn_21862 void CGameMode::ReceiveItemEffectResult(const unsigned char* data) { const auto* packet = reinterpret_cast(data); ITEM_INFO item; item.SetItemId(packet->itemId); item.identified = 1; std::string text; ItemDescriptions descriptions{g_itemDescriptions}; bool languagePrefix = false; WORD language = g_serverLanguage->language; ItemNaming naming{descriptions, g_itemCardNames, *g_playerNameDictionary, languagePrefix, g_serviceType, language}; switch (packet->type) { case 0: static_cast(g_modeMgr.GetGameMode())->scene->player->LaunchEffect(154, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); text = static_cast(FormatOwnedString(LookupMessage(431), naming.DisplayName(item, 0).c_str())); break; case 1: static_cast(g_modeMgr.GetGameMode())->scene->player->LaunchEffect(155, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); text = static_cast(FormatOwnedString(LookupMessage(430), naming.DisplayName(item, 0).c_str())); break; case 2: if (static_cast(g_modeMgr.GetGameMode())->scene->player->state.Attachments().HasId(305)) { static_cast(g_modeMgr.GetGameMode())->scene->player->SendMsg(nullptr, 109, 0, 305, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } static_cast(g_modeMgr.GetGameMode())->scene->player->LaunchEffect(305, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); text = FormatOwnedString(LookupMessage(431), naming.DisplayName(item, 0).c_str()).c_str(); break; case 3: if (static_cast(g_modeMgr.GetGameMode())->scene->player->state.Attachments().HasId(306)) { static_cast(g_modeMgr.GetGameMode())->scene->player->SendMsg(nullptr, 109, 0, 306, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } static_cast(g_modeMgr.GetGameMode())->scene->player->LaunchEffect(306, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); text = FormatOwnedString(LookupMessage(430), naming.DisplayName(item, 0).c_str()).c_str(); break; case 4: if (static_cast(g_modeMgr.GetGameMode())->scene->player->state.Attachments().HasId(1015)) { static_cast(g_modeMgr.GetGameMode())->scene->player->SendMsg(nullptr, 109, 0, 1015, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } static_cast(g_modeMgr.GetGameMode())->scene->player->LaunchEffect(1015, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); text = FormatOwnedString(LookupMessage(431), naming.DisplayName(item, 0).c_str()).c_str(); break; case 5: if (static_cast(g_modeMgr.GetGameMode())->scene->player->state.Attachments().HasId(1016)) { static_cast(g_modeMgr.GetGameMode())->scene->player->SendMsg(nullptr, 109, 0, 1016, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } static_cast(g_modeMgr.GetGameMode())->scene->player->LaunchEffect(1016, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); text = FormatOwnedString(LookupMessage(430), naming.DisplayName(item, 0).c_str()).c_str(); break; case 6: { if (static_cast(g_modeMgr.GetGameMode())->scene->player->state.Attachments().HasId(1017)) { static_cast(g_modeMgr.GetGameMode())->scene->player->SendMsg(nullptr, 109, 0, 1017, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } static_cast(g_modeMgr.GetGameMode())->scene->player->LaunchEffect(1017, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); text = FormatOwnedString(LookupMessage(430), naming.DisplayName(item, 0).c_str()).c_str(); UIWindow* window = g_windowMgr.LookupWindow(344); if (window) { window->SendMsg(nullptr, 6, 415, 0, 0, 0); } break; } case 7: { if (static_cast(g_modeMgr.GetGameMode())->scene->player->state.Attachments().HasId(1018)) { static_cast(g_modeMgr.GetGameMode())->scene->player->SendMsg(nullptr, 109, 0, 1018, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } static_cast(g_modeMgr.GetGameMode())->scene->player->LaunchEffect(1018, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); text = FormatOwnedString(LookupMessage(430), naming.DisplayName(item, 0).c_str()).c_str(); UIWindow* window = g_windowMgr.LookupWindow(344); if (window) { window->SendMsg(nullptr, 6, 415, 0, 0, 0); } break; } } } // OFFSET: 0x00D691A0 // FUNCTION: fn_22045 void CGameMode::ReceiveCharacterRenameResult(const unsigned char* packet) { switch (reinterpret_cast(packet)->value) { case 0: { PacketIdOnly request; request.id = 0xA48; GetRagConnection().Send(g_packetLengths.FixedLength(request.id), &request); reinterpret_cast(&g_windowMgr)->Confirm(LookupMessage(2836), 0, true, false, 0, "Message", 280, 120, 0); g_windowMgr.CloseWindow(281); break; } case 1: case 2: reinterpret_cast(&g_windowMgr)->Confirm(LookupMessage(1575), 0, true, false, 0, "Message", 280, 120, 0); break; } } // OFFSET: 0x00D6B010 // FUNCTION: fn_22066 void CGameMode::ReceiveLapineUpgradeResult(std::int16_t result) { if (result != 0) { UIWindow* window = g_windowMgr.LookupWindow(290); if (window) { static_cast(window)->SetWaiting(0); } } else if (g_windowMgr.LookupWindow(302)) { g_windowMgr.CloseWindow(302); } } // OFFSET: 0x00D6B070 // FUNCTION: fn_22067 void CGameMode::ReceiveLapineBoxResult(std::uint16_t result) { if (result != 0) { UIWindow* window = g_windowMgr.LookupWindow(290); if (window) { static_cast(window)->SetWaiting(0); } } switch (result) { case 0: if (g_windowMgr.LookupWindow(290)) { g_windowMgr.CloseWindow(290); } break; case 5: case 7: { UIWindow* window = g_windowMgr.LookupWindow(290); if (window) { window->SendMsg(nullptr, 111, reinterpret_cast(LookupMessage(2897)), 0, 0, 0); } break; } } } // OFFSET: 0x00D6BB10 // FUNCTION: fn_22072 void CGameMode::ReceiveRouletteInfo(const unsigned char* packet) { const auto* info = reinterpret_cast(packet); for (int i = 0; i < 42; ++i) { RouletteSlot slot; slot.row = info->slots[i].row; slot.column = info->slots[i].column; slot.itemId = info->slots[i].itemId; slot.count = info->slots[i].count; g_rouletteMgr->AddItem(slot); } g_rouletteMgr->SetAdditionItem(g_rouletteMgr->m_additionItemId); if (g_rouletteMgr->m_resultShown == 1) { g_rouletteMgr->SetResult(static_cast(g_rouletteMgr->m_index), 1, 0); } if (!g_windowMgr.unknown_0464) { g_windowMgr.EnsureWindow(269); } } // OFFSET: 0x00D6D080 // FUNCTION: fn_22084 void CGameMode::BeginCaptchaImage(unsigned short size, const char* key) { if (g_windowMgr.LookupWindow(285)) { return; } UIMacroDetectorWnd* window = static_cast(g_windowMgr.EnsureWindow(285)); if (window) { if (std::strncmp(window->m_captchaKey, key, 4) != 0) { window->ClearImageData(); } window->Show(0); memcpy_s(window->m_captchaKey, 4, key, 4); window->InitImageData(size); } } // OFFSET: 0x00D6D130 // FUNCTION: fn_22085 void CGameMode::ReceiveCaptchaImageData(const char* key, const void* data, unsigned short size) { UIMacroDetectorWnd* window = static_cast(g_windowMgr.LookupWindow(285)); if (window && std::strncmp(window->m_captchaKey, key, 4) == 0) { window->AddImageData(data, size); } } // OFFSET: 0x00D6D180 // FUNCTION: fn_22086 void CGameMode::ReceiveWindow99Values(int count, const int* values) { if (count <= 0 || !values) { return; } char positive = 0; for (int i = 0; i < count; ++i) { if (values[i] > 0) { ++positive; } } if (positive > 0) { UIWindow* window = g_windowMgr.EnsureWindow(99); if (window) { for (int i = 0; i < count; ++i) { if (values[i] > 0) { window->SendMsg(nullptr, 31, values[i], 0, 0, 0); } } } } } // OFFSET: 0x00D6E440 // FUNCTION: fn_22099 void sub_D6E440() { g_windowMgr.CloseWindow(0x154); } // OFFSET: 0x00D6E450 // FUNCTION: fn_22100 void CGameMode::ReceiveMacroBlackListResult(int result) { switch (result) { case 0: reinterpret_cast(&g_windowMgr)->Confirm(LookupMessage(2869), 0, true, false, 0, "Message", 280, 120, 0); break; case 1: reinterpret_cast(&g_windowMgr)->Confirm(LookupMessage(2870), 0, true, false, 0, "Message", 280, 120, 0); break; case 2: g_windowMgr.CloseWindow(359); reinterpret_cast(&g_windowMgr)->Confirm(LookupMessage(2871), 0, true, false, 0, "Message", 280, 120, 0); return; default: return; } GetRagConnection().Close(); static_cast(g_charViewMode)->SendMsg(2, 0, 0, 0, 0); } // OFFSET: 0x00D6E520 // FUNCTION: fn_22101 void CGameMode::ReceiveMacroDetectorResult(int result) { switch (result) { case 0: reinterpret_cast(&g_windowMgr)->Confirm(LookupMessage(2869), 0, true, false, 0, "Message", 280, 120, 0); break; case 1: reinterpret_cast(&g_windowMgr)->Confirm(LookupMessage(2870), 0, true, false, 0, "Message", 280, 120, 0); break; case 2: g_windowMgr.CloseWindow(285); reinterpret_cast(&g_windowMgr)->Confirm(LookupMessage(2871), 0, true, false, 0, "Message", 280, 120, 0); return; default: return; } GetRagConnection().Close(); static_cast(g_charViewMode)->SendMsg(2, 0, 0, 0, 0); } // OFFSET: 0x00D71600 // FUNCTION: fn_22134 void CGameMode::ReceiveMacroBlackListCode(unsigned char state, const char* code) { UIMacroBlackListCheckWnd* window = static_cast(g_windowMgr.EnsureWindow(359)); if (window) { window->SetCode(state, code); PacketIdOnly request; request.id = 0xBC4; GetRagConnection().Send(g_packetLengths.FixedLength(request.id), &request); } } // OFFSET: 0x00D1BC20 // FUNCTION: fn_21621 void __stdcall nullsub_467(int) { } // OFFSET: 0x00D1BE00 // FUNCTION: fn_21622 void __stdcall nullsub_468(int) { } // OFFSET: 0x00D6AD60 // FUNCTION: fn_22063 void __stdcall sub_D6AD60(int count, const int* aids) { if (count <= 0) { return; } UIMacroReporterWnd* window = static_cast(g_windowMgr.LookupWindow(286)); if (!window) { return; } for (int i = 0; i < count; ++i) { window->sub_7EF2E0(aids[i]); } } // GLOBAL: gl_25111 int g_unknown_01738268; // GLOBAL: gl_25112 int g_unknown_0173826C; // GLOBAL: gl_25113 int g_unknown_01738270; // GLOBAL: gl_25114 int g_unknown_01738784; // GLOBAL: gl_25115 short g_unknown_01738788; // GLOBAL: gl_24957 int g_achievementCompleted; // GLOBAL: gl_24958 int g_achievementTotal; // OFFSET: 0x00D1C050 // FUNCTION: fn_21624 void __stdcall sub_D1C050(const AchievementStatePacket* packet) { UIWindow* window = nullptr; bool notify = true; if (packet->type == 2) { reinterpret_cast(&g_windowMgr)->Confirm(LookupMessage(0x9F5), 0, true, true, 0, "Message", 280, 120, 0); window = g_windowMgr.LookupWindow(0x21); } else { window = g_windowMgr.LookupWindow(0x21); notify = window != nullptr; } if (notify) { window->SendMsg(nullptr, 6, 0xC9, 0, 0, 0); g_windowMgr.CloseWindow(0x21); } reinterpret_cast(&g_session)->ClearItems1738(); g_unknown_01738268 = 0; g_unknown_0173826C = 0; g_unknown_01738270 = 0; } // OFFSET: 0x00D6C460 // FUNCTION: fn_22081 void __stdcall sub_D6C460(int count, int unknown01738784, short unknown01738788, int completed, int total, const AchievementRecordPacket* packets) { g_unknown_01738784 = unknown01738784; g_unknown_01738788 = unknown01738788; g_achievementCompleted = completed; g_achievementTotal = total; for (int i = 0; i < count; ++i) { g_session.UpdateRecord6144(packets[i]); if (packets[i].rewarded == 1) { g_session.AddUnknown6160(packets[i].id); } } UIWindow* window = g_windowMgr.LookupWindow(0x10E); if (window != nullptr) { window->SendMsg(nullptr, 60, 0, 0, 0, 0); } } // OFFSET: 0x00D1A0A0 // FUNCTION: fn_21615 void CGameMode::OpenServiceWindow(unsigned char type) { switch (type) { case 0: if (!g_windowMgr.LookupWindow(251)) { AccountRequestPacket request; request.id = 0x9AB; request.aid = g_session.m_aid; GetRagConnection().Send(6, &request); } break; case 1: if (g_windowMgr.LookupWindow(16)) { this->SendMsg(89, 0, 0, 0, 0); } if (!g_windowMgr.LookupWindow(281)) { g_windowMgr.EnsureWindow(281); } break; case 2: g_windowMgr.EnsureWindow(284); break; case 3: g_windowMgr.EnsureWindow(286); break; case 9: g_windowMgr.EnsureWindow(344); break; } } // OFFSET: 0x00D693E0 // FUNCTION: fn_22047 void CGameMode::ReceiveWindow328Result(int result, int value) { if (result == 0) { UIWindow* window = g_windowMgr.LookupWindow(328); if (window) { window->SendMsg(nullptr, 34, value * 10 + 1, 0, 0, 0); } } else if (result == 1) { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3472)), 0xFF, 0, 0, 0); g_windowMgr.CloseWindow(328); } } // OFFSET: 0x00D69460 // FUNCTION: fn_22048 void CGameMode::ReceiveRouletteClose(const unsigned char* packet) { switch (reinterpret_cast(packet)->value) { case 0: g_rouletteMgr->Reset(); if (g_windowMgr.unknown_0464) { g_windowMgr.CloseWindow(269); } break; case 1: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2633)), 0x6464FF, 0, 0, 0); break; } } // OFFSET: 0x00D6A920 // FUNCTION: fn_22059 void CGameMode::ReceiveWindow227Result(const unsigned char* packet) { const auto* result = reinterpret_cast(packet); const unsigned short first = result->first; const unsigned short second = result->second; switch (result->result) { case 0: { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2171)), 0x64FFFF, 0, 0, 0); UIWindow* window = g_windowMgr.LookupWindow(227); if (window) { window->SendMsg(nullptr, 60, first, second, 0, 0); } break; } case 1: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2172)), 0xFF, 0, 0, 0); break; case 2: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2173)), 0xFF, 0, 0, 0); break; } g_windowMgr.CloseWindow(227); } // OFFSET: 0x00D6AB60 // FUNCTION: fn_22061 void CGameMode::ReceiveRouletteOpen(const unsigned char* packet) { const auto* open = reinterpret_cast(packet); switch (open->result) { case 0: g_rouletteMgr->unknown_0004 = open->serial; g_rouletteMgr->m_stage = open->stage; g_rouletteMgr->SetAdditionItem(open->additionItemId); g_rouletteMgr->m_goldPoint = open->goldPoint; g_rouletteMgr->m_silverPoint = open->silverPoint; g_rouletteMgr->m_bronzePoint = open->bronzePoint; g_rouletteMgr->SetResult(open->index, open->index != 0xFF, 0); if (open->index != 0xFF) { g_rouletteMgr->SetQuad((open->index + open->stage) * 36 + 173, 341 - open->stage * 40, static_cast(g_renderer->viewport.width * 0.5 - 320.0), static_cast(g_renderer->viewport.height * 0.5 - 240.0)); } if (g_rouletteMgr->m_items.size() == 0) { PacketIdOnly request; request.id = 0xA1B; GetRagConnection().Send(g_packetLengths.FixedLength(request.id), &request); } else if (!g_windowMgr.unknown_0464) { g_windowMgr.EnsureWindow(269); } break; case 1: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2632)), 0x6464FF, 0, 0, 0); break; } } // OFFSET: 0x00D6ACE0 // FUNCTION: fn_22062 void CGameMode::ReceiveRodexOpen(const unsigned char* packet) { const auto* open = reinterpret_cast(packet); if (open->result != 1) { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2604)), 0x64FFFF, 0, 0, 0); return; } if (g_windowMgr.unknown_0458) { return; } g_session.RestoreItems5C68(); g_session.ClearItemQuantities(); g_windowMgr.EnsureWindow(264); const char* text = open->text; if (text) { reinterpret_cast(g_windowMgr.unknown_0458)->SetContentsText(text); } } // OFFSET: 0x00D6ADA0 // FUNCTION: fn_22064 void CGameMode::ReceiveCaptchaPreview(int result, unsigned short size, const char* key) { if (result == 0) { UICaptchaPreviewWnd* window = static_cast(g_windowMgr.LookupWindow(288)); if (!window) { window = static_cast(g_windowMgr.EnsureWindow(288)); if (!window) { return; } } if (std::strncmp(window->m_captchaKey, key, 4) != 0) { window->ClearImageData(); } window->Show(0); memcpy_s(window->m_captchaKey, 4, key, 4); window->InitImageData(size); } else if (result == 1) { g_windowMgr.SendNotice(1, reinterpret_cast("wrong captcha ID."), 0xFF, 0, 0, 0); } } // OFFSET: 0x00D6B8F0 // FUNCTION: fn_22070 void CGameMode::ReceiveStackedItemReturn(const unsigned char* packet) { const auto* result = reinterpret_cast(packet); if (result->result == 1) { g_session.ReturnStackedItem(result->index, result->count); g_session.unknown_6140 = result->value; } else { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2602)), 0x64FFFF, 0, 0, 0); } } // OFFSET: 0x00D6E0B0 // FUNCTION: fn_22095 void CGameMode::ReceiveRodexRecipient(int id, unsigned short job, unsigned short level, const char* name) { if (id == 0) { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2615)), 0x64FFFF, 0, 0, 0); } else if (g_windowMgr.unknown_0458) { reinterpret_cast(g_windowMgr.unknown_0458)->SetRecipient(id, job, level, name); } } struct BuyingStoreResultPacket { /* 0000 */ std::uint16_t id; /* 0002 */ std::int16_t result; /* 0004 */ std::int16_t value; }; // OFFSET: 0x00D1D460 // FUNCTION: fn_21629 void __stdcall ReceiveBuyingStoreResult(const BuyingStoreResultPacket* packet) { char text[256]; int message; const std::int16_t result = packet->result; if (result == 0) { std::memset(text, 0, 250); message = 0x9C0; } else if (result == 2) { std::memset(text, 0, 250); message = 0x9C1; } else if (result == 3) { g_unknown_01738270 = 1; std::memset(text, 0, 250); message = 0x9C2; } else if (result == 1) { g_unknown_01738268 = 1; g_unknown_0173826C = packet->value; if (packet->value != 0) { return; } std::memset(text, 0, 250); message = 0x9C5; } else { return; } std::sprintf(text, LookupMessage(message)); g_windowMgr.SendNotice(1, reinterpret_cast(text), 0xFF, 0, 0, 0); } // OFFSET: 0x00D18BA0 // FUNCTION: fn_21600 void CGameMode::SetActorUnknown02E4(std::uint32_t aid, int value) { CGameActor* actor = static_cast(this->scene->GetGameActorByAID(aid)); if (actor) { actor->SetUnknown02E4(value); } } // OFFSET: 0x00D197D0 // FUNCTION: fn_21608 void CGameMode::IgnoreRemovedPacket13(const unsigned char*) { } // OFFSET: 0x00D197E0 // FUNCTION: fn_21609 void CGameMode::IgnoreRemovedPacket14(const unsigned char*) { } // OFFSET: 0x00D198E0 // FUNCTION: fn_21611 void CGameMode::IgnoreRemovedPacket15(const unsigned char*) { } // OFFSET: 0x00D19EE0 // FUNCTION: fn_21614 void CGameMode::IgnoreRemovedPacket16(const unsigned char*) { } // OFFSET: 0x00D6C080 // FUNCTION: fn_22078 void CGameMode::ReceiveItemSlotAddOptions(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (packet->slot < 0) { g_modeMgr.gameMode->SendMsg(0x35, 0, 0, 0, 0); } if (packet->itemId == 0) { g_session.SetUnknown5214(packet->slot); return; } ITEM_INFO item; item.unknown_0000[0] = packet->type; item.SetItemId(packet->itemId); item.quantity = packet->slot; item.unknown_005D = packet->damaged; item.identified = packet->identified; item.unknown_0060 = packet->refine; std::memcpy(item.unknown_001C, packet->cards, sizeof(packet->cards)); item.unknown_0000[1] = 0xFFFFFFFF; item.unknown_0098 = CountItemSlotOptions(packet->options); for (int index = 0; index < item.unknown_0098; ++index) { reinterpret_cast(item.unknown_009C)[index] = packet->options[index]; } item.unknown_0000[2] = packet->expireTime; item.unknown_0070 = packet->bindType; g_session.AddItemSlot(item); } // OFFSET: 0x00D6C240 // FUNCTION: fn_22079 void CGameMode::ReceiveItemSlotAddGrade(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (packet->slot < 0) { g_modeMgr.gameMode->SendMsg(0x35, 0, 0, 0, 0); } if (packet->itemId == 0) { g_session.SetUnknown5214(packet->slot); return; } ITEM_INFO item; item.unknown_0000[0] = packet->type; item.SetItemId(packet->itemId); item.quantity = packet->slot; item.unknown_005D = packet->damaged; item.identified = packet->identified; item.unknown_0060 = packet->refine; std::memcpy(item.unknown_001C, packet->cards, sizeof(packet->cards)); item.unknown_0000[1] = 0xFFFFFFFF; item.unknown_0098 = CountItemSlotOptions(packet->options); for (int index = 0; index < item.unknown_0098; ++index) { reinterpret_cast(item.unknown_009C)[index] = packet->options[index]; } item.unknown_0000[2] = packet->expireTime; item.unknown_0070 = packet->bindType; item.unknown_0088 = packet->grade; g_session.AddItemSlot(item); } // OFFSET: 0x00D6D7E0 // FUNCTION: fn_22090 void CGameMode::ReceiveGuildUnknown0114Change(unsigned char value, std::uint32_t removeAid, std::uint32_t addAid) { GuildInfo* guildInfo = reinterpret_cast(reinterpret_cast(&g_guildId) - offsetof(GuildInfo, m_guildId)); if (g_session.IsLocalPlayerAid(removeAid) == 1) { guildInfo->RemoveUnknown0114(value); } else if (g_session.IsLocalPlayerAid(addAid) == 0) { guildInfo->AddUnknown0114(value); } if (g_windowMgr.window_0320) { g_windowMgr.window_0320->SendMsg(nullptr, 0x3C, 0, 0, 0, 0); } } // OFFSET: 0x00D6DDD0 // FUNCTION: fn_22093 void CGameMode::ReceiveItemOptionsRefresh(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (!packet) { return; } ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, packet->index); if (item.unknown_0000[1] != 0) { item.unknown_0060 = packet->refine; item.unknown_0098 = CountItemSlotOptions(packet->options); for (int index = 0; index < item.unknown_0098; ++index) { reinterpret_cast(item.unknown_009C)[index] = packet->options[index]; } g_session.UpdateInventoryItem(item, 1); } } // OFFSET: 0x00D06410 // FUNCTION: fn_21575 int GetBaseJob(int job) { switch (job) { case JT_NOVICE_H: case JT_NOVICE_B: return JT_NOVICE; case JT_SWORDMAN_H: case JT_SWORDMAN_B: return JT_SWORDMAN; case JT_MAGICIAN_H: case JT_MAGICIAN_B: return JT_MAGICIAN; case JT_ARCHER_H: case JT_ARCHER_B: return JT_ARCHER; case JT_ACOLYTE_H: case JT_ACOLYTE_B: return JT_ACOLYTE; case JT_MERCHANT_H: case JT_MERCHANT_B: return JT_MERCHANT; case JT_THIEF_H: case JT_THIEF_B: return JT_THIEF; case JT_KNIGHT_H: case JT_KNIGHT_B: case JT_RUNE_KNIGHT: case JT_RUNE_KNIGHT_H: case JT_RUNE_KNIGHT_B: case JT_DRAGON_KNIGHT: return JT_KNIGHT; case JT_PRIEST_H: case JT_PRIEST_B: case JT_ARCHBISHOP: case JT_ARCHBISHOP_H: case JT_ARCHBISHOP_B: case JT_CARDINAL: return JT_PRIEST; case JT_WIZARD_H: case JT_WIZARD_B: case JT_WARLOCK: case JT_WARLOCK_H: case JT_WARLOCK_B: case JT_ARCH_MAGE: return JT_WIZARD; case JT_BLACKSMITH_H: case JT_BLACKSMITH_B: case JT_MECHANIC: case JT_MECHANIC_H: case JT_MECHANIC_B: case JT_MEISTER: return JT_BLACKSMITH; case JT_HUNTER_H: case JT_HUNTER_B: case JT_RANGER: case JT_RANGER_H: case JT_RANGER_B: case JT_WINDHAWK: return JT_HUNTER; 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: return JT_ASSASSIN; case JT_CRUSADER_H: case JT_CRUSADER_B: case JT_ROYAL_GUARD: case JT_ROYAL_GUARD_H: case JT_ROYAL_GUARD_B: case JT_IMPERIAL_GUARD: return JT_CRUSADER; case JT_MONK_H: case JT_MONK_B: case JT_SURA: case JT_SURA_H: case JT_SURA_B: case JT_INQUISITOR: return JT_MONK; case JT_SAGE_H: case JT_SAGE_B: case JT_SORCERER: case JT_SORCERER_H: case JT_SORCERER_B: case JT_ELEMENTAL_MASTER: return JT_SAGE; case JT_ROGUE_H: case JT_ROGUE_B: case JT_SHADOW_CHASER: case JT_SHADOW_CHASER_H: case JT_SHADOW_CHASER_B: case JT_ABYSS_CHASER: return JT_ROGUE; case JT_ALCHEMIST_H: case JT_ALCHEMIST_B: case JT_GENETIC: case JT_GENETIC_H: case JT_GENETIC_B: case JT_BIOLO: return JT_ALCHEMIST; case JT_BARD_H: case JT_BARD_B: case JT_MINSTREL: case JT_MINSTREL_H: case JT_MINSTREL_B: case JT_TROUBADOUR: return JT_BARD; case JT_DANCER_H: case JT_DANCER_B: case JT_WANDERER: case JT_WANDERER_H: case JT_WANDERER_B: case JT_TROUVERE: return JT_DANCER; case JT_SUPERNOVICE_B: case JT_SUPERNOVICE2: case JT_SUPERNOVICE2_B: case JT_HYPER_NOVICE: return JT_SUPERNOVICE; case JT_REBELLION: case JT_GUNSLINGER_B: case JT_REBELLION_B: case JT_NIGHT_WATCH: return JT_GUNSLINGER; 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 JT_NINJA; case JT_TAEKWON_B: return JT_TAEKWON; case JT_STAR_B: case JT_STAR_EMPEROR: case JT_STAR_EMPEROR_B: case JT_SKY_EMPEROR: return JT_STAR; case JT_LINKER_B: case JT_SOUL_REAPER: case JT_SOUL_REAPER_B: case JT_SOUL_ASCETIC: return JT_LINKER; case JT_DO_SUMMONER_B: case JT_SPIRIT_HANDLER: return JT_DO_SUMMONER; case JT_DRUID_B: case JT_KARNOS: case JT_KARNOS_B: case JT_ALITEA: return JT_DRUID; } return job; } #pragma pack(push, 1) struct TypedNoticePacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t type; /* 0004 */ int first; /* 0008 */ int second; }; struct RodexMailReturnPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int64_t mailId; /* 000A */ unsigned char type; /* 000B */ unsigned char result; }; struct ActorStatusValuePacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; /* 0006 */ int status; /* 000A */ int value; }; struct PartyMemberEffectPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; /* 0006 */ int type; }; struct ExtraInventoryResultPacket { /* 0000 */ std::int16_t id; /* 0002 */ unsigned char result; /* 0003 */ int itemId; }; #pragma pack(pop) // GLOBAL: gl_25117 int g_partyEffectNoticePending; // OFFSET: 0x00D1A1C0 // FUNCTION: fn_21616 void CGameMode::ReceiveTypedNotice(const unsigned char* data) { const auto* packet = reinterpret_cast(data); switch (packet->type) { case 0: g_windowMgr.SendNotice(1, reinterpret_cast(FormatOwnedString(LookupMessage(901), packet->first, packet->second).c_str()), 0xCDCDCD, 0, 0, 0); break; case 1: g_windowMgr.SendNotice(1, reinterpret_cast(FormatOwnedString(LookupMessage(902), packet->first, packet->second).c_str()), 0xCDFFCD, 0, 0, 0); break; case 2: g_windowMgr.SendNotice(1, reinterpret_cast(FormatOwnedString(LookupMessage(926), packet->first, packet->second).c_str()), 0xFFCDCD, 0, 0, 0); break; case 3: g_windowMgr.SendNotice(1, reinterpret_cast(FormatOwnedString(LookupMessage(953), packet->first, packet->second).c_str()), 0xCDCDCD, 0, 0, 0); break; } } // OFFSET: 0x00D6BE80 // FUNCTION: fn_22076 void CGameMode::ReceiveRodexMailReturn(const unsigned char* data) { if (g_windowMgr.unknown_045C) { reinterpret_cast(g_windowMgr.unknown_045C)->SetZenyButtonDisabled(0); } const auto* packet = reinterpret_cast(data); switch (packet->result) { case 0: { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2591)), 0x64FFFF, 0, 0, 0); std::map::iterator mail; switch (packet->type) { case 0: mail = g_rodexMailStore->m_mails0.find(packet->mailId); if (mail != g_rodexMailStore->m_mails0.end()) { mail->second.unknown_0001 -= 2; } break; case 1: mail = g_rodexMailStore->m_mails1.find(packet->mailId); if (mail != g_rodexMailStore->m_mails1.end()) { mail->second.unknown_0001 -= 2; } break; case 2: mail = g_rodexMailStore->m_mails2.find(packet->mailId); if (mail != g_rodexMailStore->m_mails2.end()) { mail->second.unknown_0001 -= 2; } break; } if (g_windowMgr.unknown_045C) { reinterpret_cast(g_windowMgr.unknown_045C)->DisableZenyButton(); } break; } case 1: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2592)), 0x64FFFF, 0, 0, 0); break; case 2: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2593)), 0x64FFFF, 0, 0, 0); break; } } // OFFSET: 0x00D73E00 // FUNCTION: fn_22144 void CGameMode::ReceiveActorStatusValuePacket(const unsigned char* data) { const auto* packet = reinterpret_cast(data); this->ReceiveActorStatusValue(packet->aid, packet->status, packet->value, packet->value >> 31); } // OFFSET: 0x00D73E20 // FUNCTION: fn_22145 void CGameMode::ReceivePartyMemberEffect(const unsigned char* data) { const auto* packet = reinterpret_cast(data); auto* actor = static_cast(this->scene->GetGameActorByAID(packet->aid)); if (!actor) { return; } switch (packet->type) { case 0: actor->LaunchEffect(371, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; case 1: actor->LaunchEffect(158, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; case 2: actor->LaunchEffect(155, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; case 3: actor->LaunchEffect(154, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; case 4: g_partyEffectNoticePending = 1; break; case 5: actor->LaunchEffect(305, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; case 6: actor->LaunchEffect(306, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; case 7: actor->LaunchEffect(338, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; case 8: actor->LaunchEffect(337, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; case 9: actor->LaunchEffect(582, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; } } // OFFSET: 0x00D73960 // FUNCTION: fn_22141 void CGameMode::ShowFormattedNotice(unsigned short messageId, std::uint32_t color, int argument) { std::string text = FormatOwnedString(LookupMessage(messageId), argument); if (!text.empty()) { g_windowMgr.SendNotice(1, reinterpret_cast(text.c_str()), color, messageId == 2962 ? 22 : 0, 0, 0); } } // OFFSET: 0x00D6BC40 // FUNCTION: fn_22074 void CGameMode::ReceiveCaptchaUploadRequest(const std::uint32_t* sessionId, int result) { int message; switch (result) { case 0: { auto* window = static_cast(g_windowMgr.LookupWindow(284)); if (window) { std::uint64_t now = _Xtime_get_ticks(); CCaptchaUploadSchedule* schedule = new CCaptchaUploadSchedule(now, sessionId, window->m_decompressedSize, window->m_decompressedData); reinterpret_cast(g_timeScheduler)->AddSchedule(schedule); return; } message = 2881; break; } case 1: message = 2882; break; default: return; } g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(message)), 0xFF, 0, 0, 0); } // OFFSET: 0x00D6A9F0 // FUNCTION: fn_22060 void CGameMode::ReceiveExtraInventoryResult(const unsigned char* data) { const auto* packet = reinterpret_cast(data); int message; switch (packet->result) { case 0: { const int nextSlots = g_session.unknown_7FBC + 110; const int slots = g_session.unknown_7FBC + 100; const char* name = FindItemDescription(packet->itemId).identifiedName; const int answer = reinterpret_cast(&g_windowMgr)->Confirm( FormatOwnedString(LookupMessage(3561), name, slots, nextSlots).c_str(), 2, false, false, 0, "Message", 280, 120, 0); if (answer == 187) { this->SendMsg(311, 0, 0, 0, 0); } else { this->SendMsg(312, 0, 0, 0, 0); } return; } case 1: message = 3562; break; case 2: message = 3563; break; case 3: message = 3564; break; case 4: message = 3565; break; default: return; } g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(message)), 0xFF, 0, 0, 0); } // OFFSET: 0x00D6FEA0 // FUNCTION: fn_22128 void CGameMode::ReceiveWindow348Result(unsigned char result, std::int16_t index) { if (result == 0) { g_windowMgr.CloseWindow(348); g_effectMgr->Spawn(g_session.m_aid, 1608, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0); ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, index); if (item.unknown_0000[1] != 0) { UIWindow* window = g_windowMgr.EnsureWindow(12); if (window) { window->SendMsg(nullptr, 24, reinterpret_cast(&item), 1, 0, 0); } } } else if (result == 3) { UIWindow* window = g_windowMgr.LookupWindow(348); if (window) { window->SendMsg(nullptr, 29, reinterpret_cast(LookupMessage(3848)), 0, 0, 0); } } } // OFFSET: 0x00D69E60 // FUNCTION: fn_22056 void CGameMode::ReceiveRodexItemReturn(const unsigned char* data) { if (g_windowMgr.unknown_045C) { reinterpret_cast(g_windowMgr.unknown_045C)->SetItemButtonDisabled(0); } const auto* packet = reinterpret_cast(data); switch (packet->result) { case 0: { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2588)), 0x64FFFF, 0, 0, 0); g_session.ClearItemQuantities(); std::map::iterator mail; switch (packet->type) { case 0: mail = g_rodexMailStore->m_mails0.find(packet->mailId); if (mail != g_rodexMailStore->m_mails0.end()) { mail->second.unknown_0001 -= 4; } break; case 1: mail = g_rodexMailStore->m_mails1.find(packet->mailId); if (mail != g_rodexMailStore->m_mails1.end()) { mail->second.unknown_0001 -= 4; } break; case 2: mail = g_rodexMailStore->m_mails2.find(packet->mailId); if (mail != g_rodexMailStore->m_mails2.end()) { mail->second.unknown_0001 -= 4; } break; } if (g_windowMgr.unknown_045C) { auto* contents = reinterpret_cast(g_windowMgr.unknown_045C); contents->SendMsg(nullptr, 23, 0, 0, 0, 0); contents->DisableItemButton(); } if (g_windowMgr.unknown_0454) { reinterpret_cast(g_windowMgr.unknown_0454)->SendMsg(nullptr, 60, 0, 0, 0, 0); } break; } case 1: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2589)), 0x64FFFF, 0, 0, 0); break; case 2: g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2590)), 0x64FFFF, 0, 0, 0); break; } } #pragma pack(push, 1) struct ExpGainNoticePacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; /* 0006 */ std::int64_t amount; /* 000E */ std::int16_t type; /* 0010 */ std::int16_t quest; }; #pragma pack(pop) // OFFSET: 0x00D74080 // FUNCTION: fn_22146 void CGameMode::ReceiveExpGainNotice(const unsigned char* data) { const auto* packet = reinterpret_cast(data); std::string text; if (g_session.m_aid != packet->aid) { return; } const std::uint32_t color = packet->quest == 1 ? 0xBE58BE : 0xFFFF; if (packet->amount == 0) { return; } char buffer[256]; if (packet->type == 1) { std::sprintf(buffer, LookupMessage(3220), packet->amount); text += buffer; } else if (packet->type == 2) { std::sprintf(buffer, LookupMessage(3227), packet->amount); text += buffer; } if (packet->amount < 0) { text += LookupMessage(1616); } else { text += LookupMessage(1615); } g_windowMgr.SendNotice(1, reinterpret_cast(text.c_str()), color, 18, 0, 0); } #include "UI/Item/UIItemStoreWnd.h" #include "UI/Shop/UIMerchantShopMakeWnd.h" #include "UI/Text/UIStaticText.h" #include "UI/UIBarGraph.h" #include "UI/Window/UIBasicInfoWnd.h" #include "Contents/Effects/EmitterEffect.h" #pragma pack(push, 1) struct BankDepositAckPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t reason; /* 0004 */ std::int64_t money; /* 000C */ int zeny; }; struct BankCheckPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int64_t money; /* 000A */ std::int16_t reason; }; struct ExchangeItemAddAckPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t index; /* 0004 */ unsigned char result; }; struct ExchangeRequestAckPacket { /* 0000 */ std::int16_t id; /* 0002 */ unsigned char result; /* 0003 */ std::uint32_t charId; /* 0007 */ std::int16_t level; }; struct SearchStoreOpenPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t openType; /* 0004 */ unsigned char count; }; struct StorageListHeader { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; }; struct NamedStorageListHeader { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; /* 0004 */ char title[24]; }; struct StorageEquipRecord { /* 0000 */ std::int16_t index; /* 0002 */ int itemId; /* 0006 */ unsigned char type; /* 0007 */ unsigned char identified; /* 0008 */ std::uint16_t location; /* 000A */ std::uint16_t wearState; /* 000C */ unsigned char damaged; /* 000D */ unsigned char refine; /* 000E */ std::uint32_t cards[4]; /* 001E */ int expireTime; }; struct StorageEquipRecord2 { /* 0000 */ std::int16_t index; /* 0002 */ int itemId; /* 0006 */ unsigned char type; /* 0007 */ unsigned char identified; /* 0008 */ std::uint16_t location; /* 000A */ std::uint16_t wearState; /* 000C */ unsigned char damaged; /* 000D */ unsigned char refine; /* 000E */ std::uint32_t cards[4]; /* 001E */ int expireTime; /* 0022 */ std::uint16_t bindOnEquip; /* 0024 */ std::uint16_t sprite; }; struct StorageEquipRecord3 { /* 0000 */ std::int16_t index; /* 0002 */ int itemId; /* 0006 */ unsigned char type; /* 0007 */ std::uint16_t location; /* 0009 */ std::uint16_t wearState; /* 000B */ unsigned char refine; /* 000C */ std::uint32_t cards[4]; /* 001C */ int expireTime; /* 0020 */ std::uint16_t bindOnEquip; /* 0022 */ std::uint16_t sprite; /* 0024 */ unsigned char flags; }; struct StorageEquipRecord4 { /* 0000 */ std::int16_t index; /* 0002 */ int itemId; /* 0006 */ unsigned char type; /* 0007 */ int location; /* 000B */ int wearState; /* 000F */ unsigned char refine; /* 0010 */ std::uint32_t cards[4]; /* 0020 */ int expireTime; /* 0024 */ std::uint16_t bindOnEquip; /* 0026 */ std::uint16_t sprite; /* 0028 */ unsigned char flags; }; struct StorageEquipRecord5 { /* 0000 */ std::int16_t index; /* 0002 */ int itemId; /* 0006 */ unsigned char type; /* 0007 */ int location; /* 000B */ int wearState; /* 000F */ unsigned char refine; /* 0010 */ std::uint32_t cards[4]; /* 0020 */ int expireTime; /* 0024 */ std::uint16_t bindOnEquip; /* 0026 */ std::uint16_t sprite; /* 0028 */ unsigned char optionCount; /* 0029 */ ItemSlotOption options[5]; /* 0042 */ unsigned char flags; }; struct StorageNormalRecord { /* 0000 */ std::int16_t index; /* 0002 */ int itemId; /* 0006 */ unsigned char type; /* 0007 */ std::int16_t amount; /* 0009 */ std::uint16_t wearState; /* 000B */ std::uint32_t cards[4]; /* 001B */ int expireTime; /* 001F */ unsigned char flags; }; struct StorageNormalRecord2 { /* 0000 */ std::int16_t index; /* 0002 */ int itemId; /* 0006 */ unsigned char type; /* 0007 */ std::int16_t amount; /* 0009 */ int wearState; /* 000D */ std::uint32_t cards[4]; /* 001D */ int expireTime; /* 0021 */ unsigned char flags; }; struct ItemCardSlots { /* 0000 */ std::uint32_t cards[4]; }; struct ItemSlotOptions { /* 0000 */ ItemSlotOption options[5]; }; struct LongParChangePacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint16_t type; /* 0004 */ std::int64_t value; }; #pragma pack(pop) struct SessionMessengerContext { void ResetSlots(); int GetList0Size() const; }; // OFFSET: 0x00D195D0 // FUNCTION: fn_21606 void CGameMode::ReceiveBankDepositAck(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (packet->reason == 0) { g_session.m_bankBalance = packet->money; g_session.m_zeny = packet->zeny; g_session.RefreshHpSpWindows(); g_session.InvalidateWindowFrames(); return; } char text[256]; if (packet->reason == 2) { std::memset(text, 0, 250); std::sprintf(text, LookupMessage(2456)); } else if (packet->reason == 3) { std::memset(text, 0, 250); std::sprintf(text, LookupMessage(2465)); } else if (packet->reason == 4) { std::memset(text, 0, 250); std::sprintf(text, LookupMessage(2489)); } else { std::memset(text, 0, 250); std::sprintf(text, LookupMessage(2454)); } g_windowMgr.SendNotice(1, reinterpret_cast(text), 0xFF, 0, 0, 0); } // OFFSET: 0x00D196E0 // FUNCTION: fn_21607 void CGameMode::ReceiveBankWithdrawAck(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (packet->reason == 0) { g_session.m_bankBalance = packet->money; g_session.m_zeny = packet->zeny; g_session.RefreshHpSpWindows(); g_session.InvalidateWindowFrames(); return; } char text[256]; if (packet->reason == 1) { std::memset(text, 0, 250); std::sprintf(text, LookupMessage(2455)); } else if (packet->reason == 3) { std::memset(text, 0, 250); std::sprintf(text, LookupMessage(2489)); } else { std::memset(text, 0, 250); std::sprintf(text, LookupMessage(2454)); } g_windowMgr.SendNotice(1, reinterpret_cast(text), 0xFF, 0, 0, 0); } // OFFSET: 0x00D197F0 // FUNCTION: fn_21610 void CGameMode::ReceiveBankCheck(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (packet->reason == 0) { g_session.m_bankBalance = packet->money; if (!g_windowMgr.CloseWindow(275)) { g_windowMgr.EnsureWindow(275); } return; } if (packet->reason == 2) { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(3031)), 0xFF, 0, 0, 0); } else { char text[256]; std::memset(text, 0, 250); std::sprintf(text, LookupMessage(2454)); g_windowMgr.SendNotice(1, reinterpret_cast(text), 0xFF, 0, 0, 0); } } #pragma pack(push, 1) struct TradeItemFilterPacket { /* 0000 */ std::uint16_t opcode; /* 0002 */ int type; }; #pragma pack(pop) struct SessionItemLists { void ClearTradeItems(); }; // OFFSET: 0x00D198F0 // FUNCTION: fn_21612 void CGameMode::ReceiveTradeItemFilter(const unsigned char* data) { const auto* packet = reinterpret_cast(data); reinterpret_cast(&g_session)->ClearTradeItems(); const int count = reinterpret_cast(&g_session)->GetList0Size(); for (int i = 0; i < count; ++i) { ITEM_INFO item = g_session.GetInventoryItemAt(i); if (item.unknown_0000[1] == 0) { continue; } if (packet->type == 1 && !this->IsEffectId994Group(std::atoi(item.itemId.c_str()))) { continue; } if (packet->type == 2 && !this->IsEffectId990Group(std::atoi(item.itemId.c_str()))) { continue; } if (item.unknown_0000[1] == g_session.unknown_16EC) { continue; } RawItemBasic raw = {}; raw.id = item.unknown_0000[1]; strcpy_s(raw.itemId, sizeof(raw.itemId), item.itemId.c_str()); raw.unknown_000C = item.unknown_0000[0]; raw.identified = item.identified; raw.unknown_0004 = 1; raw.unknown_0008 = 2; reinterpret_cast(&g_session)->AddItem1718(raw, 1); } UIWindow* window = g_windowMgr.EnsureWindow(160); window->SendMsg(nullptr, 0x24, 1, 0, 0, 0); window->SendMsg(nullptr, 0x17, 0, 0, 0, 0); g_windowMgr.EnsureWindow(161)->SendMsg(nullptr, 0x17, packet->type, 0, 0, 0); } // OFFSET: 0x00D1BE10 // FUNCTION: fn_21623 void CGameMode::ReceiveExchangeItemAddAck(const unsigned char* data) { const auto* packet = reinterpret_cast(data); int& exchangeAmount = *reinterpret_cast(&this->unknown_0100[0x10]); *reinterpret_cast(&this->unknown_0100[0x00]) = 0; this->unknown_05CE = 1; switch (packet->result) { case 0: if (packet->index != 0) { ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, packet->index); item.quantity = exchangeAmount; reinterpret_cast(&g_session)->AddExchangeItem(item); } else { g_session.m_zeny -= exchangeAmount; g_session.RefreshHpSpWindows(); g_session.InvalidateWindowFrames(); g_session.SetUnknown5210(g_session.unknown_5210 + exchangeAmount); } break; case 1: g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(73)), 0xFF, 0, 0, 0); break; case 3: g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(1938)), 0xFF, 0, 0, 0); break; case 4: g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(1939)), 0xFF, 0, 0, 0); break; } } // OFFSET: 0x00D1C2B0 // FUNCTION: fn_21625 void CGameMode::ReceiveExchangeRequestAck2(const unsigned char* data) { const auto* packet = reinterpret_cast(data); const std::string& exchangeName = *reinterpret_cast(&this->unknown_0130[0x18]); switch (packet->result) { case 3: { this->SendMsg(40, 0, 0, 0, 0); *reinterpret_cast(&this->unknown_0100[0x14]) = 1; reinterpret_cast(&g_session)->ResetSlots(); reinterpret_cast(&g_session)->ClearItemSlotQuantities(); g_windowMgr.CloseWindow(10011); UIWindow* window = g_windowMgr.EnsureWindow(10011); if (window) { window->SendMsg(nullptr, 50, reinterpret_cast(exchangeName.c_str()), packet->charId, packet->level, 0); } break; } case 4: g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(69)), 0xFF, 0, 0, 0); break; case 0: g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(70)), 0xFF, 0, 0, 0); break; case 1: g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(71)), 0xFF, 0, 0, 0); break; case 2: g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(72)), 0xFF, 0, 0, 0); break; case 5: { std::string text = FormatOwnedString(LookupMessage(1708), exchangeName.c_str()); g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(text.c_str()), 0xFF, 0, 0, 0); break; } } } // OFFSET: 0x00D1C4E0 // FUNCTION: fn_21626 void CGameMode::ReceiveExchangeRequestAck(const unsigned char* data) { const auto* packet = reinterpret_cast(data); switch (packet->result) { case 3: { this->SendMsg(40, 0, 0, 0, 0); *reinterpret_cast(&this->unknown_0100[0x14]) = 1; reinterpret_cast(&g_session)->ResetSlots(); reinterpret_cast(&g_session)->ClearItemSlotQuantities(); g_windowMgr.CloseWindow(10011); UIWindow* window = g_windowMgr.EnsureWindow(10011); if (window) { const std::string& exchangeName = *reinterpret_cast(&this->unknown_0130[0x18]); window->SendMsg(nullptr, 50, reinterpret_cast(exchangeName.c_str()), 0, 0, 0); } break; } case 4: g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(69)), 0xFF, 0, 0, 0); break; case 0: g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(70)), 0xFF, 0, 0, 0); break; case 1: g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(71)), 0xFF, 0, 0, 0); break; case 2: g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(72)), 0xFF, 0, 0, 0); break; } } #pragma pack(push, 1) struct GuildStorageLogPacketEntry { /* 0000 */ int unknown_0000; /* 0004 */ int itemId; /* 0008 */ int unknown_0008; /* 000C */ unsigned char unknown_000C; /* 000D */ int refine; /* 0011 */ unsigned char unknown_0011[8]; /* 0019 */ unsigned char identified; /* 001A */ std::int16_t count; /* 001C */ unsigned char cards[16]; /* 002C */ char name[24]; /* 0044 */ char date[24]; /* 005C */ unsigned char unknown_005C; }; struct GuildStorageLogPacket { /* 0000 */ std::uint16_t opcode; /* 0002 */ std::uint16_t length; /* 0004 */ std::int16_t result; /* 0006 */ std::int16_t count; /* 0008 */ GuildStorageLogPacketEntry entries[1]; }; #pragma pack(pop) // OFFSET: 0x00D1C640 // FUNCTION: fn_21627 void CGameMode::ReceiveGuildStorageLog(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (packet->result == 0) { for (int i = 0; i < packet->count; ++i) { const GuildStorageLogPacketEntry& source = packet->entries[i]; ITEM_INFO item; item.unknown_00B8[0] = source.unknown_0000; item.unknown_00B8[1] = source.unknown_0008; item.unknown_00C0 = source.unknown_000C; std::strcpy(reinterpret_cast(item.unknown_00C1), source.name); std::strcpy(reinterpret_cast(item.unknown_00D9), source.date); char number[16] = {}; item.itemId = _itoa(source.itemId, number, 10); item.identified = source.identified; item.unknown_0000[0] = source.count; item.unknown_0060 = source.refine; std::memcpy(item.unknown_001C, source.cards, sizeof(source.cards)); GuildStorageLogEntry entry; entry.unknown_0000 = item.unknown_00B8[0]; entry.unknown_0004 = item.unknown_00B8[1]; entry.unknown_0008 = item.unknown_00C0; std::strcpy(entry.unknown_0009, reinterpret_cast(item.unknown_00C1)); std::strcpy(entry.unknown_0021, reinterpret_cast(item.unknown_00D9)); entry.unknown_003C = item.DisplayName(0); entry.unknown_0054 = item.identified; entry.unknown_0058 = item.unknown_0000[0]; entry.unknown_005C = item.unknown_0060; std::memcpy(entry.unknown_0060, item.unknown_001C, sizeof(entry.unknown_0060)); entry.unknown_0070 = source.unknown_005C; g_guildStorageLogs[0].push_back(entry); } } else if (packet->result == 1) { for (int i = 0; i < packet->count; ++i) { const GuildStorageLogPacketEntry& source = packet->entries[i]; ITEM_INFO item; item.unknown_00B8[0] = source.unknown_0000; item.unknown_00B8[1] = source.unknown_0008; item.unknown_00C0 = source.unknown_000C; std::strcpy(reinterpret_cast(item.unknown_00C1), source.name); std::strcpy(reinterpret_cast(item.unknown_00D9), source.date); char number[16] = {}; item.itemId = _itoa(source.itemId, number, 10); item.identified = source.identified; item.unknown_0000[0] = source.count; item.unknown_0060 = source.refine; std::memcpy(item.unknown_001C, source.cards, sizeof(source.cards)); GuildStorageLogEntry entry; entry.unknown_0000 = item.unknown_00B8[0]; entry.unknown_0004 = item.unknown_00B8[1]; entry.unknown_0008 = item.unknown_00C0; std::strcpy(entry.unknown_0009, reinterpret_cast(item.unknown_00C1)); std::strcpy(entry.unknown_0021, reinterpret_cast(item.unknown_00D9)); entry.unknown_003C = item.DisplayName(0); entry.unknown_0054 = item.identified; entry.unknown_0058 = item.unknown_0000[0]; entry.unknown_005C = item.unknown_0060; std::memcpy(entry.unknown_0060, item.unknown_001C, sizeof(entry.unknown_0060)); entry.unknown_0070 = source.unknown_005C; g_guildStorageLogs[0].push_back(entry); } GuildStorageLogEntry pivot; std::sort(g_guildStorageLogs[0].begin(), g_guildStorageLogs[0].end(), [&pivot](const GuildStorageLogEntry& left, const GuildStorageLogEntry& right) { return std::strcmp(left.unknown_0021, right.unknown_0021) > 0; }); for (auto it = g_guildStorageLogs[0].begin(); it != g_guildStorageLogs[0].end(); ++it) { if (it->unknown_0008 == 1) { g_guildStorageLogs[1].push_back(*it); } else { g_guildStorageLogs[2].push_back(*it); } } g_windowMgr.EnsureWindow(253); } else { char text[252]; if (packet->result == 2) { std::memset(text, 0, 250); std::sprintf(text, LookupMessage(2543)); } else { std::memset(text, 0, 250); std::sprintf(text, LookupMessage(1816)); } g_windowMgr.SendNotice(1, reinterpret_cast(text), 0xFF, 0, 0, 0); g_guildStorageLogs[0].clear(); g_guildStorageLogs[1].clear(); g_guildStorageLogs[2].clear(); } } // OFFSET: 0x00D45E90 // FUNCTION: fn_21843 void CGameMode::ReceiveStorageEquipList(const unsigned char* data) { const auto* header = reinterpret_cast(data); g_windowMgr.EnsureWindow(33); const int count = (header->length - sizeof(StorageListHeader)) / sizeof(StorageEquipRecord); const auto* record = reinterpret_cast(data + sizeof(StorageListHeader)); for (int i = 0; i < count; ++i, ++record) { ITEM_INFO item; item.unknown_0000[0] = record->type; item.unknown_0000[2] = record->location; item.unknown_0000[1] = record->index; item.unknown_0000[3] = record->wearState; std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards)); item.quantity = 1; item.SetItemId(record->itemId); item.identified = record->identified; item.unknown_005D = record->damaged; item.unknown_0060 = record->refine; item.unknown_0068 = record->expireTime; reinterpret_cast(&g_session)->AddItem1738(item, 0); } g_session.RefreshItem1738Window(); } // OFFSET: 0x00D46000 // FUNCTION: fn_21844 void CGameMode::ReceiveStorageEquipList2(const unsigned char* data) { const auto* header = reinterpret_cast(data); g_windowMgr.EnsureWindow(33); const int count = (header->length - sizeof(StorageListHeader)) / sizeof(StorageEquipRecord2); const auto* record = reinterpret_cast(data + sizeof(StorageListHeader)); for (int i = 0; i < count; ++i, ++record) { ITEM_INFO item; item.unknown_0000[0] = record->type; item.unknown_0000[2] = record->location; item.unknown_0000[1] = record->index; item.unknown_0000[3] = record->wearState; std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards)); item.quantity = 1; item.SetItemId(record->itemId); item.identified = record->identified; item.unknown_005D = record->damaged; item.unknown_0060 = record->refine; item.unknown_0068 = record->expireTime; item.unknown_0064 = record->bindOnEquip; item.unknown_0070 = record->sprite; reinterpret_cast(&g_session)->AddItem1738(item, 0); } g_session.RefreshItem1738Window(); } // OFFSET: 0x00D46460 // FUNCTION: fn_21845 void CGameMode::ReceiveStorageEquipList3(const unsigned char* data) { const auto* header = reinterpret_cast(data); UIItemStoreWnd* window = static_cast(g_windowMgr.EnsureWindow(33)); if (header->title[0] != '\0') { std::string title(header->title); window->title->SetTextFitted(title.c_str()); } const int count = (header->length - sizeof(NamedStorageListHeader)) / sizeof(StorageEquipRecord3); const auto* record = reinterpret_cast(data + sizeof(NamedStorageListHeader)); for (int i = 0; i < count; ++i, ++record) { ITEM_INFO item; item.unknown_0000[0] = record->type; std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards)); item.unknown_0000[2] = record->location; item.unknown_0000[1] = record->index; item.unknown_0000[3] = record->wearState; item.quantity = 1; item.SetItemId(record->itemId); item.identified = record->flags & 1; item.unknown_005D = (record->flags >> 1) & 1; item.unknown_0060 = record->refine; item.unknown_0068 = record->expireTime; item.unknown_0064 = record->bindOnEquip; item.unknown_0070 = record->sprite; item.unknown_0074[0] = (record->flags >> 2) & 1; reinterpret_cast(&g_session)->AddItem1738(item, 0); } g_session.RefreshItem1738Window(); } // OFFSET: 0x00D46680 // FUNCTION: fn_21846 void CGameMode::ReceiveStorageEquipList4(const unsigned char* data) { const auto* header = reinterpret_cast(data); UIItemStoreWnd* window = static_cast(g_windowMgr.EnsureWindow(33)); if (header->title[0] != '\0') { std::string title(header->title); window->title->SetTextFitted(title.c_str()); } const int count = (header->length - sizeof(NamedStorageListHeader)) / sizeof(StorageEquipRecord4); const auto* entry = reinterpret_cast(data + sizeof(NamedStorageListHeader)); for (int i = 0; i < count; ++i, ++entry) { ItemSlotOption options[5] = {}; const StorageEquipRecord4 record = *entry; if (record.location == 0x8000) { continue; } ITEM_INFO item; item.unknown_0000[0] = record.type; item.unknown_0000[2] = record.location; item.unknown_0000[1] = record.index; item.unknown_0000[3] = record.wearState; std::memcpy(item.unknown_001C, record.cards, sizeof(record.cards)); item.quantity = 1; item.SetItemId(record.itemId); item.identified = record.flags & 1; item.unknown_005D = (record.flags >> 1) & 1; item.unknown_0060 = record.refine; item.unknown_0068 = record.expireTime; item.unknown_0064 = record.bindOnEquip; item.unknown_0070 = record.sprite; item.unknown_0074[0] = (record.flags >> 2) & 1; item.unknown_0098 = CountItemSlotOptions(options); item.unknown_0088 = 0; for (int index = 0; index < item.unknown_0098; ++index) { reinterpret_cast(item.unknown_009C)[index] = options[index]; } reinterpret_cast(&g_session)->AddItem1738(item, 0); } g_session.RefreshItem1738Window(); } // OFFSET: 0x00D46A20 // FUNCTION: fn_21847 void CGameMode::ReceiveStorageEquipList5(const unsigned char* data) { const auto* header = reinterpret_cast(data); UIItemStoreWnd* window = static_cast(g_windowMgr.EnsureWindow(33)); if (header->title[0] != '\0') { std::string title(header->title); window->title->SetTextFitted(title.c_str()); } const int count = (static_cast(header->length) - sizeof(NamedStorageListHeader)) / sizeof(StorageEquipRecord5); const auto* record = reinterpret_cast(data + sizeof(NamedStorageListHeader)); for (int i = 0; i < count; ++i, ++record) { ItemSlotOption options[5]; std::memcpy(options, record->options, sizeof(options)); if (record->location == 0x8000) { continue; } ITEM_INFO item; item.unknown_0000[0] = record->type; item.unknown_0000[2] = record->location; item.unknown_0000[1] = record->index; item.unknown_0000[3] = record->wearState; std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards)); item.quantity = 1; item.SetItemId(record->itemId); item.identified = record->flags & 1; item.unknown_005D = (record->flags >> 1) & 1; item.unknown_0060 = record->refine; item.unknown_0068 = record->expireTime; item.unknown_0064 = record->bindOnEquip; item.unknown_0070 = record->sprite; item.unknown_0074[0] = (record->flags >> 2) & 1; item.unknown_0098 = CountItemSlotOptions(options); item.unknown_0088 = 0; for (int index = 0; index < item.unknown_0098; ++index) { reinterpret_cast(item.unknown_009C)[index] = options[index]; } reinterpret_cast(&g_session)->AddItem1738(item, 0); } g_session.RefreshItem1738Window(); } // OFFSET: 0x00D46EE0 // FUNCTION: fn_21848 void CGameMode::ReceiveStorageNormalList(const unsigned char* data) { const auto* header = reinterpret_cast(data); UIItemStoreWnd* window = static_cast(g_windowMgr.EnsureWindow(33)); if (header->title[0] != '\0') { std::string title(header->title); window->title->SetTextFitted(title.c_str()); } const unsigned int count = (header->length - sizeof(NamedStorageListHeader)) / sizeof(StorageNormalRecord); const auto* record = reinterpret_cast(data + sizeof(NamedStorageListHeader)); for (unsigned int i = 0; i < count; ++i, ++record) { ITEM_INFO item; item.unknown_0000[0] = record->type; std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards)); item.unknown_0000[1] = record->index; item.unknown_0000[3] = record->wearState; item.unknown_0000[2] = 0; item.quantity = record->amount; item.SetItemId(record->itemId); item.unknown_005D = 0; item.identified = record->flags & 1; item.unknown_0074[0] = (record->flags >> 1) & 1; item.unknown_0068 = record->expireTime; item.unknown_0060 = 0; reinterpret_cast(&g_session)->AddItem1738(item, 0); } g_session.RefreshItem1738Window(); } // OFFSET: 0x00D470E0 // FUNCTION: fn_21849 void CGameMode::ReceiveStorageNormalList2(const unsigned char* data) { const auto* header = reinterpret_cast(data); UIItemStoreWnd* window = static_cast(g_windowMgr.EnsureWindow(33)); if (header->title[0] != '\0') { std::string title(header->title); window->title->SetTextFitted(title.c_str()); } const int count = (header->length - sizeof(NamedStorageListHeader)) / sizeof(StorageNormalRecord2); const auto* record = reinterpret_cast(data + sizeof(NamedStorageListHeader)); for (int i = 0; i < count; ++i, ++record) { ITEM_INFO item; item.unknown_0000[0] = record->type; std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards)); item.unknown_0000[1] = record->index; item.unknown_0000[3] = record->wearState; item.unknown_0000[2] = 0; item.quantity = record->amount; item.SetItemId(record->itemId); item.unknown_005D = 0; item.identified = record->flags & 1; item.unknown_0074[0] = (record->flags >> 1) & 1; item.unknown_0068 = record->expireTime; item.unknown_0060 = 0; reinterpret_cast(&g_session)->AddItem1738(item, 0); } g_session.RefreshItem1738Window(); } // OFFSET: 0x00D6DEF0 // FUNCTION: fn_22094 void CGameMode::ReceiveItemUpgrade(std::uint16_t index, std::uint16_t refine, ItemCardSlots cards, ItemSlotOptions options) { ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, index); item.unknown_0060 = refine; std::memcpy(item.unknown_001C, cards.cards, sizeof(cards.cards)); item.unknown_0098 = CountItemSlotOptions(options.options); for (int i = 0; i < item.unknown_0098; ++i) { reinterpret_cast(item.unknown_009C)[i] = options.options[i]; } g_session.UpdateInventoryItem(item, 1); if (UIWindow* window = g_windowMgr.EnsureWindow(12)) { window->SendMsg(nullptr, 24, reinterpret_cast(&item), 1, 0, 0); } } // OFFSET: 0x00D6E640 // FUNCTION: fn_22103 void CGameMode::ReceiveFeedConfig(unsigned char state, unsigned char option) { *reinterpret_cast(g_session.unknown_5974) = state; g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(state + 0x54E)), 0x64FFFF, 0, 0, 0); if (g_windowMgr.unknown_01E0) { g_windowMgr.unknown_01E0->SendMsg(nullptr, 0x3C, 0, 0, 0, 0); } g_serviceOptions.Set(231, option); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(option + 0xBA2)), 0x64FFFF, 0, 0, 0); g_windowMgr.sub_AAB070(231); } // OFFSET: 0x00D6E6F0 // FUNCTION: fn_22104 void CGameMode::ReceiveFeedConfig2(unsigned char state, unsigned char option, bool petAutoFeed) { *reinterpret_cast(g_session.unknown_5974) = state; g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(state + 0x54E)), 0x64FFFF, 0, 0, 0); if (g_windowMgr.unknown_01E0) { g_windowMgr.unknown_01E0->SendMsg(nullptr, 0x3C, 0, 0, 0, 0); } g_serviceOptions.Set(231, option); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(option + 0xBA2)), 0x64FFFF, 0, 0, 0); g_windowMgr.sub_AAB070(231); g_session.SetPetAutoFeed(petAutoFeed); } // OFFSET: 0x00D6E7A0 // FUNCTION: fn_22105 void CGameMode::ReceiveFeedConfig3(unsigned char state, unsigned char option, bool petAutoFeed, bool homunculusAutoFeed) { *reinterpret_cast(g_session.unknown_5974) = state; g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(state + 0x54E)), 0x64FFFF, 0, 0, 0); if (g_windowMgr.unknown_01E0) { g_windowMgr.unknown_01E0->SendMsg(nullptr, 0x3C, 0, 0, 0, 0); } g_serviceOptions.Set(231, option); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(option + 0xBA2)), 0x64FFFF, 0, 0, 0); g_windowMgr.sub_AAB070(231); g_session.SetPetAutoFeed(petAutoFeed); g_session.SetHomunculusAutoFeed(homunculusAutoFeed); } // OFFSET: 0x00D6E860 // FUNCTION: fn_22106 void CGameMode::ReceiveFeedConfig4(unsigned char state, unsigned char option, bool petAutoFeed, bool homunculusAutoFeed, int value) { *reinterpret_cast(g_session.unknown_5974) = state; g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(state + 0x54E)), 0x64FFFF, 0, 0, 0); if (g_windowMgr.unknown_01E0) { g_windowMgr.unknown_01E0->SendMsg(nullptr, 0x3C, 0, 0, 0, 0); } g_serviceOptions.Set(231, option); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(option + 0xBA2)), 0x64FFFF, 0, 0, 0); g_windowMgr.sub_AAB070(231); g_session.SetPetAutoFeed(petAutoFeed); g_session.SetHomunculusAutoFeed(homunculusAutoFeed); *reinterpret_cast(g_session.unknown_8128) = value; } // OFFSET: 0x00D713E0 // FUNCTION: fn_22133 void CGameMode::ReceiveLongParChange(const unsigned char* data) { const auto* packet = reinterpret_cast(data); std::int64_t& exp = *reinterpret_cast(&g_session.unknown_162C[0x04]); std::int64_t& nextExp = *reinterpret_cast(&g_session.unknown_162C[0x0C]); std::int64_t& nextJobExp = *reinterpret_cast(&g_session.unknown_162C[0x14]); std::int64_t& jobExp = *reinterpret_cast(&g_session.unknown_162C[0x1C]); bool refresh = true; switch (packet->type) { case 1: if (g_session.IsAdminSubMode(2)) { const std::int64_t value = packet->value; const int gained = static_cast(value) - static_cast(exp); if (value != 0 && gained != 0) { char text[256]; StringFormat( text, sizeof(text), static_cast(-1), "%lld : %lld/%lld More : %d", value - exp, value, nextExp, static_cast((nextExp - exp) / gained) ); g_windowMgr.SendNotice(1, reinterpret_cast(text), 0xF51EF5, 0, 0, 0); } } exp = packet->value; break; case 2: jobExp = packet->value; break; case 20: if (*reinterpret_cast(&this->unknown_0100[0x14])) { *reinterpret_cast(&this->unknown_0100[0x14]) = 0; reinterpret_cast(&g_session)->ResetSlots(); } g_session.m_zeny = static_cast(packet->value); g_session.RefreshHpSpWindows(); break; case 22: nextExp = packet->value; break; case 23: nextJobExp = packet->value; break; default: refresh = false; break; } if (refresh) { g_session.InvalidateWindowFrames(); } static_cast(reinterpret_cast(g_windowMgr.unknown_01DC)->baseExpBar)->SetValues(exp, nextExp); static_cast(reinterpret_cast(g_windowMgr.unknown_01DC)->jobExpBar)->SetValues(jobExp, nextJobExp); } // OFFSET: 0x00D73A10 // FUNCTION: fn_22142 void sub_D73A10(const unsigned char* packet) { int group = packet[3] >= 100 ? 1 : 0; int code = packet[3] >= 100 ? packet[3] - 100 : packet[3]; if (code >= 10) { group += 2; code -= 10; } const unsigned char mode = static_cast(group + (code < 1 ? 0 : 4)); const int x = *reinterpret_cast(packet + 0x15); const int y = *reinterpret_cast(packet + 0x17); const int id = *reinterpret_cast(packet + 0x19); const std::string name(reinterpret_cast(packet + 5)); g_navigationManager.sub_B99030(name, packet[2], mode, packet[4] != 0, x, y, id); } // OFFSET: 0x00D73AF0 // FUNCTION: fn_22143 void CGameMode::ReceiveNotifyEffect(const unsigned char* packet) { CRenderObject* actor = this->scene->GetGameActorByAidIncludeMe(*reinterpret_cast(packet + 2)); if (!actor) { return; } int effectId = *reinterpret_cast(packet + 6); if (effectId == 0x3FD) { CEmitterEffect* emitter = static_cast(g_effectMgr->Spawn( 0, 0x3CE, actor->render.position.x, actor->render.position.y, actor->render.position.z, 0, -1, 0, 0 )); emitter->velocityMin.x = -2.0f; emitter->velocityMin.y = 2.0f; emitter->velocityMin.z = -2.0f; emitter->velocityMax.x = 0.0f; emitter->velocityMax.y = -1.0f; emitter->velocityMax.z = 0.0f; emitter->acceleration.x = 0.0f; emitter->acceleration.y = -7.5f; emitter->acceleration.z = 0.0f; emitter->spread.x = -1.0f; emitter->spread.y = 2.0f; emitter->spread.z = -1.0f; emitter->red = 255; emitter->green = 255; emitter->blue = 100; emitter->alpha = 100; emitter->rateMin = 20.0f; emitter->rateMax = 100.0f; emitter->scaleMin = 30.0f; emitter->scaleMax = 30.0f; emitter->lifeMin = 5.0f; emitter->lifeMax = 10.0f; emitter->sourceBlend = 5; emitter->destinationBlend = 2; emitter->SetParticleSpeed(3.0f); emitter->SetCount(30); emitter->SetTexture("smoke2.bmp"); emitter->duration = 1250; effectId = *reinterpret_cast(packet + 6); } if (g_serviceOptions.Get(0xE5)) { switch (*reinterpret_cast(packet + 6)) { case 0x5A: effectId = 0x48A; break; case 0x5C: effectId = 0x48B; break; case 0x5F: effectId = 0x489; break; } } CGameActor* gameActor = static_cast(actor); if (!g_effectMgr->Spawn( actor->render.accountId, effectId, actor->render.position.x, actor->render.position.y, actor->render.position.z, 0, -1, 0, 0 )) { gameActor->LaunchEffect(*reinterpret_cast(packet + 6), vector3d{0.0f, 0.0f, 0.0f}, 0.0f); } if (g_session.IsMercenaryJob(gameActor->GetEffectiveJob(-1)) && *reinterpret_cast(packet + 6) == 0x238) { ++gameActor->unknown_0210; gameActor->ResetJobEffects(); gameActor->sub_CAA4D0(); } } #include "Client/Application/Launcher.h" #pragma pack(push, 1) struct TypedItemEntry { /* 0000 */ int itemId; /* 0004 */ std::uint32_t unknown_0004; /* 0008 */ std::uint16_t unknown_0008; /* 000A */ std::uint32_t unknown_000A; }; struct TypedItemListPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; /* 0004 */ std::int16_t count; /* 0006 */ std::int16_t type; /* 0008 */ TypedItemEntry entries[1]; }; #pragma pack(pop) // OFFSET: 0x00D1B690 // FUNCTION: fn_21619 void CGameMode::ReceiveTypedItemList(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (g_launchPassCommandLine) { return; } for (int i = 0; i < packet->count; ++i) { const TypedItemEntry& entry = packet->entries[i]; const int itemId = entry.itemId; char name[256]; ITEM_INFO item; item.unknown_0000[1] = -1; item.unknown_0014[0] = entry.unknown_0004; item.unknown_0014[1] = entry.unknown_0004; item.unknown_0000[0] = 4; item.identified = 1; item.unknown_005D = 0; item.unknown_0060 = 0; std::uint16_t type = packet->type; if (type == 8) { type = 0xFFFF; } item.unknown_0070 = entry.unknown_0008; item.unknown_0000[2] = entry.unknown_000A; item.unknown_0064 = type; item.SetItemId(itemId); int capacity = sizeof(name); ItemDescriptions descriptions{g_itemDescriptions}; descriptions.Name(item, name, capacity, 0); item.SetName(name); if (static_cast(packet->type) <= 10) { g_session.unknown_1784[packet->type].push_back(item); } } } #include "UI/Shop/UIMerchantItemMyShopWnd.h" #include "UI/Shop/UIMerchantItemShopWnd.h" #pragma pack(push, 1) struct VendingItemRecord { /* 0000 */ int price; /* 0004 */ std::int16_t amount; /* 0006 */ unsigned char type; /* 0007 */ int itemId; }; #pragma pack(pop) // OFFSET: 0x00D70010 // FUNCTION: fn_22129 void CGameMode::ReceiveVendingItemList( int aid, int storeId, char own, int count, std::uint32_t duration, const unsigned char* data, int value, int ) { const auto* records = reinterpret_cast(data); if (own == 1) { reinterpret_cast(&g_session)->ClearItems1758(); for (int i = 0; i < count;) { const VendingItemRecord record = records[i]; ITEM_INFO item; ++i; item.unknown_0014[0] = record.price; item.unknown_0014[1] = record.price; item.quantity = record.amount; item.unknown_0000[0] = record.type; item.unknown_0000[1] = i; item.identified = 1; item.SetItemId(record.itemId); reinterpret_cast(&g_session)->AddItem1758(item); } UIMerchantItemMyShopWnd* window = dynamic_cast(static_cast(g_windowMgr.EnsureWindow(176))); if (window) { window->OpenShop(); window->SendMsg(nullptr, 23, 0, 0, 0, 0); window->SendMsg(nullptr, 119, value, 0, 0, 0); window->SendMsg(nullptr, 28, aid, 0, 0, 0); window->SetDuration(duration); } } else { reinterpret_cast(&g_session)->ClearItems1748(); reinterpret_cast(&g_session)->ClearItems1760(); for (int i = 0; i < count;) { const VendingItemRecord record = records[i]; ITEM_INFO item; ++i; item.unknown_0014[0] = record.price; item.unknown_0014[1] = record.price; item.quantity = record.amount; item.unknown_0000[0] = record.type; item.unknown_0000[1] = i; item.identified = 1; item.SetItemId(record.itemId); reinterpret_cast(&g_session)->AddItem1748(item); } UIMerchantItemShopWnd* shop = static_cast(g_windowMgr.EnsureWindow(177)); shop->SendMsg(nullptr, 23, 0, 0, 0, 0); shop->SendMsg(nullptr, 28, aid, 0, 0, 0); shop->SendMsg(nullptr, 119, value, 0, 0, 0); shop->StartTimer(duration); UIWindow* window = g_windowMgr.EnsureWindow(178); window->SendMsg(nullptr, 23, 0, 0, 0, 0); window->SendMsg(nullptr, 28, aid, storeId, 0, 0); UIWindow* list = reinterpret_cast(g_windowMgr.unknown_0420); if (list) { g_session.RefreshItems1750(); } else { list = g_windowMgr.EnsureWindow(179); } if (list) { list->SendMsg(nullptr, 23, 0, 0, 0, 0); } } this->unknown_024C = 1; } #pragma pack(push, 1) struct VendingItemRecord2 { /* 0000 */ int price; /* 0004 */ std::int16_t amount; /* 0006 */ std::int16_t index; /* 0008 */ unsigned char type; /* 0009 */ int itemId; /* 000D */ unsigned char identified; /* 000E */ unsigned char damaged; /* 000F */ unsigned char refine; /* 0010 */ std::uint32_t cards[4]; /* 0020 */ ItemSlotOption options[5]; /* 0039 */ int location; /* 003D */ std::uint16_t sprite; }; #pragma pack(pop) // INLINED static void FillVendingItem(ITEM_INFO& item, const VendingItemRecord2& record) { item.unknown_0000[1] = record.index; item.unknown_0014[0] = record.price; item.unknown_0014[1] = record.price; item.unknown_0000[0] = record.type; item.quantity = record.amount; item.identified = record.identified; item.unknown_005D = record.damaged; item.unknown_0060 = record.refine; item.SetItemId(record.itemId); std::memcpy(item.unknown_001C, record.cards, sizeof(record.cards)); item.unknown_0098 = CountItemSlotOptions(record.options); for (int index = 0; index < item.unknown_0098; ++index) { reinterpret_cast(item.unknown_009C)[index] = record.options[index]; } item.unknown_0000[2] = record.location; item.unknown_0070 = record.sprite; } // OFFSET: 0x00D47720 // FUNCTION: fn_21850 void CGameMode::ReceiveVendingItemSoldNow(const unsigned char* data) { const int itemId = *reinterpret_cast(data + 2); const short quantity = *reinterpret_cast(data + 6); const int field8 = *reinterpret_cast(data + 8); sub_D08670(static_cast(_time32(nullptr)), itemId, quantity, field8, 0, 0); } // OFFSET: 0x00D70790 // OFFSET: 0x00D6C410 // FUNCTION: fn_22080 void CGameMode::ReceiveTraitStatusChangeAck(unsigned char result, unsigned short statusId, unsigned char value) { this->unknown_02D4 = 0; if (result == 1) { std::map& traitStats = reinterpret_cast&>(g_session.unknown_7FC0); traitStats[statusId] = value; if (UIStatusWnd* window = reinterpret_cast(g_windowMgr.unknown_01C4)) { window->ValidatePlacement(); } } } // FUNCTION: fn_22131 void CGameMode::ReceiveVendingItemList2(int aid, int storeId, char own, int count, std::uint32_t duration, const unsigned char* data) { const auto* records = reinterpret_cast(data); if (own == 1) { reinterpret_cast(&g_session)->ClearItems1758(); for (int i = 0; i < count; ++i) { const VendingItemRecord2 record = records[i]; ITEM_INFO item; FillVendingItem(item, record); reinterpret_cast(&g_session)->AddItem1758(item); } UIMerchantItemMyShopWnd* window = dynamic_cast(static_cast(g_windowMgr.EnsureWindow(45))); if (window) { window->OpenShop(); window->SendMsg(nullptr, 23, 0, 0, 0, 0); window->SendMsg(nullptr, 28, aid, 0, 0, 0); window->SetDuration(duration); } this->unknown_024C = 1; } else { reinterpret_cast(&g_session)->ClearItems1748(); reinterpret_cast(&g_session)->ClearItems1760(); for (int i = 0; i < count; ++i) { const VendingItemRecord2 record = records[i]; ITEM_INFO item; FillVendingItem(item, record); reinterpret_cast(&g_session)->AddItem1748(item); } UIMerchantItemShopWnd* shop = static_cast(g_windowMgr.EnsureWindow(43)); shop->SendMsg(nullptr, 23, 0, 0, 0, 0); shop->SendMsg(nullptr, 28, aid, 0, 0, 0); shop->StartTimer(duration); UIWindow* window = g_windowMgr.EnsureWindow(44); window->SendMsg(nullptr, 23, 0, 0, 0, 0); window->SendMsg(nullptr, 28, aid, storeId, 0, 0); this->unknown_024C = 1; } } // OFFSET: 0x00D742B0 // FUNCTION: fn_22147 void CGameMode::ReceiveNotifyGroundSkill(const unsigned char* packet) { struct GroundSkillMessage { /* 0000 */ int skillId; /* 0004 */ int startTime; /* 0008 */ int x; /* 000C */ int y; /* 0010 */ int level; }; GroundSkillMessage message; message.skillId = *reinterpret_cast(packet + 2); message.startTime = *reinterpret_cast(packet + 0xE); message.x = *reinterpret_cast(packet + 0xA); message.y = *reinterpret_cast(packet + 0xC); message.level = *reinterpret_cast(packet + 8); CGameActor* actor = nullptr; int job = -1; if (*reinterpret_cast(packet + 4) == g_session.m_aid) { const std::int64_t value = reinterpret_cast(&message); this->scene->player->SendMsg(nullptr, 0x26, 0, static_cast(value), static_cast(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); actor = this->scene->player; if (actor != nullptr) { job = actor->GetEffectiveJob(-1); } } else { CGameActor* gameActor = static_cast(this->scene->GetGameActorByAID(*reinterpret_cast(packet + 4))); if (gameActor != nullptr) { const std::int64_t value = reinterpret_cast(&message); gameActor->SendMsg(nullptr, 0x26, 0, static_cast(value), static_cast(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); actor = gameActor; job = actor->GetEffectiveJob(-1); } } if (g_session.IsMonsterActor(actor) != 0) { int action; int loopType; g_session.GetMonsterSkillInfo(g_session.GetJobName(job, -1), *reinterpret_cast(packet + 2), &action, &loopType, *reinterpret_cast(&g_windowMgr)); if (*reinterpret_cast(packet + 2) == 0x2C8) { actor->LaunchEffect(0x199, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); } if (*reinterpret_cast(packet + 2) == 0x2E0) { CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); g_soundMgr->PlayWave("effect\\S사이킥웨이브.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); actor->LaunchEffect(0x376, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); float x; float z; reinterpret_cast(mode)->CellCenter(*reinterpret_cast(packet + 0xA), *reinterpret_cast(packet + 0xC), x, z); vector3d position; position.x = x; position.y = mode->scene->terrain->Grid().Height(x, z); position.z = z; int count = message.level + 2; if (count > 7) { count = 7; } else if (count <= 0) { return; } for (int delay = 0; count != 0; --count, delay += 500) { CEffect* effect; if (g_serviceOptions.Get(0xE5)) { effect = g_effectMgr->Spawn(0, 0x5AE, position.x, position.y, position.z, 0, -1, 0, 0); if (effect) { effect->Slot16(delay); } effect = g_effectMgr->Spawn(0, 0x5AF, position.x, position.y, position.z, 0, -1, 0, 0); } else { effect = g_effectMgr->Spawn(0, 0x508, position.x, position.y, position.z, 0, -1, 0, 0); if (effect) { effect->Slot16(delay); } effect = g_effectMgr->Spawn(0, 0x509, position.x, position.y, position.z, 0, -1, 0, 0); } if (effect) { effect->Slot16(delay); } } } return; } this->SendMsg(0x56, *reinterpret_cast(packet + 2), reinterpret_cast(actor), *reinterpret_cast(packet + 8), 0); switch (*reinterpret_cast(packet + 2)) { case 0x2F: { CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); if (actor == nullptr) { return; } vector3d* source = &actor->render.position; mode->SpawnArrowEffect64(source, source, 18.0f); const int offsets[8][2] = {{1, 0}, {1, 1}, {1, -1}, {-1, 0}, {-1, 1}, {-1, -1}, {0, 1}, {0, -1}}; const int cellX = *reinterpret_cast(packet + 0xA); const int cellY = *reinterpret_cast(packet + 0xC); for (int index = 0; index < 8; ++index) { float x; float z; reinterpret_cast(mode)->CellCenter(offsets[index][0] + cellX, offsets[index][1] + cellY, x, z); vector3d target; target.x = x; target.y = mode->scene->terrain->Grid().Height(x, z); target.z = z; mode->SpawnArrowEffect64(source, &target, 18.0f); } break; } case 0x16A: g_soundMgr->PlayWave("effect\\바실리카.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); break; case 0x171: g_soundMgr->PlayWave("effect\\가스펠.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); break; case 0x21D: { CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); float x; float z; reinterpret_cast(mode)->CellCenter(*reinterpret_cast(packet + 0xA), *reinterpret_cast(packet + 0xC), x, z); vector3d position; position.x = x; position.y = mode->scene->terrain->Grid().Height(x, z); position.z = z; this->LaunchDummyEffect(&position, 0x26E, 200, 0); break; } case 0x2E3: case 0x992: actor->LaunchEffect(0x376, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); g_soundMgr->PlayWave("effect\\S클라우드킬.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); break; case 0x89B: { CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); float x; float z; reinterpret_cast(mode)->CellCenter(*reinterpret_cast(packet + 0xA), *reinterpret_cast(packet + 0xC), x, z); vector3d position; position.x = x; position.y = mode->scene->terrain->Grid().Height(x, z); position.z = z; this->LaunchDummyEffect(&position, 0x2D6, EffectLifetime(0x2D6) + 10, 0); break; } case 0x2E0: case 0x991: { CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); g_soundMgr->PlayWave("effect\\S사이킥웨이브.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); actor->LaunchEffect(0x376, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); float x; float z; reinterpret_cast(mode)->CellCenter(*reinterpret_cast(packet + 0xA), *reinterpret_cast(packet + 0xC), x, z); vector3d position; position.x = x; position.y = mode->scene->terrain->Grid().Height(x, z); position.z = z; int count = message.level + 2; if (count > 7) { count = 7; } else if (count <= 0) { return; } for (int delay = 0; count != 0; --count, delay += 500) { CEffect* effect; if (g_serviceOptions.Get(0xE5)) { effect = g_effectMgr->Spawn(0, 0x5AE, position.x, position.y, position.z, 0, -1, 0, 0); if (effect) { effect->Slot16(delay); } effect = g_effectMgr->Spawn(0, 0x5AF, position.x, position.y, position.z, 0, -1, 0, 0); } else { effect = g_effectMgr->Spawn(0, 0x508, position.x, position.y, position.z, 0, -1, 0, 0); if (effect) { effect->Slot16(delay); } effect = g_effectMgr->Spawn(0, 0x509, position.x, position.y, position.z, 0, -1, 0, 0); } if (effect) { effect->Slot16(delay); } } break; } case 0x8FD: g_soundMgr->PlayWave("effect\\chaospanic.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); break; case 0x8FE: g_soundMgr->PlayWave("effect\\maelstrom.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); break; case 0x8FF: g_soundMgr->PlayWave("effect\\bloodylust.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); break; case 0x90D: { CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); if (actor == nullptr) { return; } float angle = mode->CameraDesiredYaw() + actor->render.angle; if (angle >= 360.0f) { angle -= 360.0f; } int effectId = 0; if (angle >= 0.0f && angle < 23.0f) { effectId = 0x692; } else if (angle >= 23.0f && angle < 67.0f) { effectId = 0x691; } else if (angle >= 67.0f && angle < 112.0f) { effectId = 0x690; } else if (angle >= 112.0f && angle < 157.0f) { effectId = 0x68F; } else if (angle >= 157.0f && angle < 202.0f) { effectId = 0x696; } else if (angle >= 202.0f && angle < 247.0f) { effectId = 0x695; } else if (angle >= 247.0f && angle < 292.0f) { effectId = 0x694; } else if (angle >= 292.0f && angle < 337.0f) { effectId = 0x693; } else if (angle >= 337.0f && angle <= 360.0f) { effectId = 0x692; } g_effectMgr->Spawn(actor->render.accountId, effectId, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0); g_soundMgr->PlayWave("effect\\LG_OVERBRAND.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); break; } case 0x971: { CRagEffect* effect = actor->LaunchEffect(0x35F, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); if (effect == nullptr) { return; } CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); float x; float z; reinterpret_cast(mode)->CellCenter(*reinterpret_cast(packet + 0xA), *reinterpret_cast(packet + 0xC), x, z); vector3d position; position.x = x; position.y = mode->scene->terrain->Grid().Height(x, z); position.z = z; effect->SendMsg(nullptr, 14, 0, reinterpret_cast(&position), 0, 0, 0, 0); g_modeMgr.GetGameMode()->SendMsg(0x7A, 0, 0, 0, 0); g_soundMgr->PlayWave("effect\\invisibility.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); break; } case 0x976: { g_soundMgr->PlayWave("effect\\안식의자장가.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); CRagEffect* effect = actor->LaunchEffect(0x35A, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); if (effect == nullptr) { return; } CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); float x; float z; reinterpret_cast(mode)->CellCenter(*reinterpret_cast(packet + 0xA), *reinterpret_cast(packet + 0xC), x, z); vector3d position; position.x = x; position.y = mode->scene->terrain->Grid().Height(x, z); position.z = z; effect->SendMsg(nullptr, 14, 0, reinterpret_cast(&position), 0, 0, 0, 0); break; } case 0x98E: { CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); g_soundMgr->PlayWave("effect\\G가시나무덫.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); actor->LaunchEffect(0x376, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); float x; float z; reinterpret_cast(mode)->CellCenter(*reinterpret_cast(packet + 0xA), *reinterpret_cast(packet + 0xC), x, z); const float y = mode->scene->terrain->Grid().Height(x, z); int delay = 0; for (int degrees = 0; degrees < 1080; degrees += 72) { const float radius = static_cast(std::max(std::rand() % 20, 0)) + 5.0f; matrix rotation; rotation.MakeYRotation(static_cast(degrees) / 180.0f * 3.141592f); vector3d position; position.x = rotation.values[0] * radius + rotation.values[3] * 0.0f + rotation.values[6] * 0.0f + rotation.values[9] + x; position.y = rotation.values[1] * radius + rotation.values[4] * 0.0f + rotation.values[7] * 0.0f + rotation.values[10] + y; position.z = rotation.values[2] * radius + rotation.values[5] * 0.0f + rotation.values[8] * 0.0f + rotation.values[11] + z; CEffect* effect = g_effectMgr->Spawn(0, 0x5B9, position.x, position.y, position.z, 0, -1, 0, 0); if (effect) { effect->Slot22(0.5f); effect->Slot16(delay); } effect = g_effectMgr->Spawn(0, 0x656, position.x, position.y, position.z, 0, -1, 0, 0); if (effect) { effect->Slot22(0.5f); effect->Slot16(delay); } delay += 70; } break; } case 0x9B3: { CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); g_soundMgr->PlayWave("effect\\G가시나무덫.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); float x; float z; reinterpret_cast(mode)->CellCenter(*reinterpret_cast(packet + 0xA), *reinterpret_cast(packet + 0xC), x, z); vector3d position; position.x = x; position.y = mode->scene->terrain->Grid().Height(x, z); position.z = z; this->LaunchDummyEffect(&position, 0x393, 150, 0); break; } case 0x9D6: { CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); actor->LaunchEffect(0x376, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); float x; float z; reinterpret_cast(mode)->CellCenter(*reinterpret_cast(packet + 0xA), *reinterpret_cast(packet + 0xC), x, z); vector3d position; position.x = x; position.y = mode->scene->terrain->Grid().Height(x, z); position.z = z; this->LaunchDummyEffect(&position, 0x376, 300, 0); this->LaunchDummyEffect(&position, 0x375, 200, 0); this->LaunchDummyEffect(&position, 0x383, 999, 0); g_soundMgr->PlayWave("effect\\SR_RIDEINLIGHTNING.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); break; } case 0xA1B: if (actor == nullptr) { return; } g_effectMgr->Spawn(actor->render.accountId, 0x4D0, actor->render.position.x, actor->render.position.y, actor->render.position.z, 0, -1, 0, 0); break; case 0x14F9: { vector3d position = {0.0f, 0.0f, 0.0f}; reinterpret_cast(this)->CellCenter(*reinterpret_cast(packet + 0xA), *reinterpret_cast(packet + 0xC), position.x, position.z); position.y = this->scene->terrain->Grid().Height(position.x, position.z); g_effectMgr->Spawn(0, 0x7EB, position.x, position.y, position.z, 0, -1, 0, 0); g_effectMgr->Spawn(0, 0x7EA, position.x, position.y, position.z, 0, -1, 0, 0); break; } case 0x14FD: { vector3d position = {0.0f, 0.0f, 0.0f}; reinterpret_cast(this)->CellCenter(*reinterpret_cast(packet + 0xA), *reinterpret_cast(packet + 0xC), position.x, position.z); position.y = this->scene->terrain->Grid().Height(position.x, position.z); g_effectMgr->Spawn(0, 0x856, position.x, position.y, position.z, 0, -1, 0, 0); g_effectMgr->Spawn(0, 0x855, position.x, position.y, position.z, 0, -1, 0, 0); break; } default: CSkillActionMgr::GetInstance()->ActionSlot12(*reinterpret_cast(packet + 2), *reinterpret_cast(packet + 0xA), *reinterpret_cast(packet + 0xC), *reinterpret_cast(packet + 8), reinterpret_cast(actor)); break; } } #pragma pack(push, 1) struct GameAcceptEnterPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t startTime; /* 0006 */ unsigned char posDir[3]; /* 0009 */ unsigned char xSize; /* 000A */ unsigned char ySize; /* 000B */ unsigned char font; }; #pragma pack(pop) // OFFSET: 0x00D1B890 // FUNCTION: fn_21620 void CGameMode::ReceiveAcceptEnter(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (Replay::Instance().state == 2) { Replay::Instance().SetState(3); g_windowMgr.window_4F164->SendMsg(nullptr, 0x57, 0, 0, 0, 0); g_windowMgr.CloseWindow(0xC6); } else if (Replay::Instance().state == 7) { Replay::Instance().SetState(8); } g_session.SetServerTime(packet->startTime); g_session.SetPlayerPosition((packet->posDir[0] << 2) | (packet->posDir[1] >> 6), ((packet->posDir[1] & 0x3F) << 4) | (packet->posDir[2] >> 4), packet->posDir[2] & 0xF); g_session.unknown_0F30[0] = packet->font; char mapName[36]; sprintf(mapName, "%s.rsw", g_session.m_navigationPlayerMap); g_modeMgr.Switch(1, mapName); g_session.SetOption(17, 0, 0); GetRagConnection().SetBlock(0); if (g_pingLogEnabled) { FILE* file = fopen("PingLog.txt", "at"); if (file) { __time32_t now; _time32(&now); fprintf(file, "\n"); fprintf(file, "server:%s\n", g_session.m_accountName.c_str()); fprintf(file, "ip:%s\n", g_zoneServerIp); fprintf(file, "map:%s.gat\n", g_session.m_navigationPlayerMap); fprintf(file, "time:%s\n\n", _ctime32(&now)); fclose(file); } g_pingLogTicks.clear(); g_pingLogFirstTick = 0; } } #pragma pack(push, 1) struct RodexMailListEntry { /* 0000 */ std::uint8_t openType; /* 0001 */ std::int64_t mailId; /* 0009 */ std::uint8_t isRead; /* 000A */ std::uint8_t type; /* 000B */ char sender[24]; /* 0023 */ int expireTime; /* 0027 */ std::int16_t titleLength; /* 0029 */ char title[1]; }; #pragma pack(pop) // OFFSET: 0x00D68730 // FUNCTION: fn_22043 void CGameMode::ReceiveRodexMailList(const unsigned char* packet) { for (int offset = 5; offset < *reinterpret_cast(packet + 2);) { const RodexMailListEntry* entry = reinterpret_cast(packet + offset); std::map* mails = nullptr; switch (entry->openType) { case 0: mails = &g_rodexMailStore->m_mails0; break; case 1: mails = &g_rodexMailStore->m_mails1; break; case 2: mails = &g_rodexMailStore->m_mails2; break; } if (mails) { RodexMail mail; mail.isRead = entry->isRead; mail.unknown_0001 = entry->type; mail.unknown_0024.assign(entry->title, entry->titleLength); mail.unknown_0004.assign(entry->sender, std::min(std::strlen(entry->sender), 24)); mail.unknown_0020 = _time32(nullptr) + entry->expireTime; if (entry->openType == 0 && !(mail.unknown_0001 & 8) && !g_session.HasUnknown809C(mail.unknown_0004)) { mail.unknown_0194 = g_session.IsKnownName(mail.unknown_0004); } else { mail.unknown_0194 = 1; } if (mails->find(entry->mailId) == mails->end() && !mail.isRead) { ++g_rodexMailStore->unknown_0018; } mails->insert(std::pair(entry->mailId, mail)); } offset += entry->titleLength + 0x29; } if (packet[4] == 1) { g_rodexMailStore->unknown_001C = true; UIWindow* window = g_windowMgr.LookupWindow(0x107); if (window) { window->SendMsg(nullptr, 0x17, 0, 0, 0, 0); } } } #pragma pack(push, 1) struct StatusChangeListPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; /* 0004 */ std::uint32_t aid; /* 0008 */ unsigned char on; /* 0009 */ std::uint16_t values[1]; }; struct StatusChangeExtendedPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t type; /* 0004 */ std::uint32_t aid; /* 0008 */ unsigned char on; /* 0009 */ std::uint32_t remaining; /* 000D */ int value1; /* 0011 */ int value2; /* 0015 */ int value3; }; struct Window227EntriesPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; /* 0004 */ std::uint16_t entries[1]; }; #pragma pack(pop) // OFFSET: 0x00D6EB70 // FUNCTION: fn_22116 void CGameMode::ReceiveStatusChangeList(const unsigned char* data) { const auto* packet = reinterpret_cast(data); const unsigned int count = (packet->length - 9u) >> 1; for (int index = 0; index < static_cast(count); ++index) { this->ApplyStatusChange(packet->aid, packet->on, 0x37F, 0, packet->values[index], 0, 0, 0, 0); } } // OFFSET: 0x00D71A30 // FUNCTION: fn_22139 void CGameMode::ReceiveStatusChangeExtended(const unsigned char* data) { const auto* packet = reinterpret_cast(data); switch (packet->type) { case 0x46: case 0x47: case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x1C6: case 0x4ED: case 0x4EE: case 0x4EF: return; } this->ApplyStatusChange(packet->aid, packet->on, packet->type, packet->remaining, packet->value1, packet->value2, packet->value3, 0, 0); } // OFFSET: 0x00D71790 // FUNCTION: fn_22137 void CGameMode::ReceiveWindow227Entries(const unsigned char* data) { const auto* packet = reinterpret_cast(data); const unsigned int count = (packet->length - 4u) >> 1; if (count == 0) { PacketIdOnly request; request.id = 0x974; GetRagConnection().Send(g_packetLengths.FixedLength(request.id), &request); return; } std::vector entries(packet->entries, packet->entries + count); UIWindow* window = g_windowMgr.EnsureWindow(227); if (window) { window->SendMsg(nullptr, 34, reinterpret_cast(entries.data()), count, 0, 0); } } #pragma pack(push, 1) struct ItemDropPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; /* 0006 */ int itemId; /* 000A */ std::uint16_t type; /* 000C */ unsigned char identified; /* 000D */ std::int16_t column; /* 000F */ std::int16_t row; /* 0011 */ unsigned char subColumn; /* 0012 */ unsigned char subRow; /* 0013 */ std::int16_t count; /* 0015 */ unsigned char showEffect; /* 0016 */ std::uint16_t grade; }; #pragma pack(pop) struct ItemFallEntry { /* 0000 */ char itemId[0x20]; /* 0020 */ std::uint32_t aid; /* 0024 */ int column; /* 0028 */ int row; /* 002C */ int subColumn; /* 0030 */ int subRow; /* 0034 */ int falling; /* 0038 */ int count; /* 003C */ unsigned char identified; /* 003E */ std::uint16_t unknown_003E; /* 0040 */ unsigned char showEffect; /* 0042 */ std::uint16_t grade; }; // OFFSET: 0x00D6FB20 // FUNCTION: fn_22126 void CGameMode::ReceiveItemDropEntry(const unsigned char* data) { const auto* packet = reinterpret_cast(data); ItemFallEntry entry = {}; _itoa(packet->itemId, entry.itemId, 10); entry.column = packet->column; entry.aid = packet->aid; entry.row = packet->row; entry.subColumn = packet->subColumn; entry.subRow = packet->subRow; entry.count = packet->count; entry.identified = packet->identified; entry.unknown_003E = packet->type; entry.showEffect = packet->showEffect; entry.grade = packet->grade; entry.falling = 1; CItem* item = this->scene->GetItemByAID(packet->aid); if (!item) { item = new CItem; this->scene->objects.push_back(item); this->scene->unknown_0018.push_back(item); } const int entryAddress = reinterpret_cast(&entry); item->SendMsg(nullptr, 4, 0, entryAddress, entryAddress >> 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } #pragma pack(push, 1) struct SpriteChangePacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; /* 0006 */ unsigned char type; /* 0007 */ unsigned char value; }; struct SpriteChange2Packet { /* 0000 */ std::int16_t id; /* 0002 */ std::uint32_t aid; /* 0006 */ unsigned char type; /* 0007 */ std::int64_t value; }; #pragma pack(pop) // OFFSET: 0x00D44C90 // FUNCTION: fn_21837 void CGameMode::ReceiveSpriteChange(const unsigned char* data) { const auto* packet = reinterpret_cast(data); const int bodyCostume = g_session.m_bodyCostume; const int bodyStyle = g_session.m_bodyStyle; CGameActor* actor; if (packet->aid == g_session.m_aid) { actor = this->scene->player; switch (packet->type) { case 0: g_session.UpdateBodyStyle(g_session.GetDisplayJob(), bodyStyle, bodyCostume); g_session.SetJob(packet->value); break; case 1: g_session.m_head = packet->value; break; case 2: *reinterpret_cast(&g_session.unknown_0EDC[0x4]) = packet->value; *reinterpret_cast(&g_session.unknown_0EDC[0x8]) = 0; break; case 3: *reinterpret_cast(&g_session.unknown_0EF4[0x0]) = packet->value; break; case 4: *reinterpret_cast(&g_session.unknown_0EF4[0x4]) = packet->value; break; case 5: *reinterpret_cast(&g_session.unknown_0EF4[0x8]) = packet->value; break; case 6: g_session.m_headPalette = packet->value; break; case 7: { const unsigned char style = packet->value; g_session.UpdateBodyStyle(g_session.GetDisplayJob(), style, bodyCostume); break; } case 8: *reinterpret_cast(&g_session.unknown_0EDC[0xC]) = packet->value; break; } if (!actor) { return; } } else { actor = static_cast(this->scene->GetGameActorByAID(packet->aid)); if (!actor) { CRenderObject* skill = this->scene->GetSkillByAID(packet->aid); if (!skill) { return; } if (packet->type == 0) { skill->SendMsg(nullptr, 47, 0, packet->value, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } return; } } switch (packet->type) { case 0: actor->SetActorJob(packet->value); actor->Slot30(); actor->Slot31(); actor->Slot32(); break; case 1: actor->Slot22(packet->value); actor->Slot30(); actor->Slot31(); actor->Slot60(); break; case 2: actor->Slot23(packet->value, 0); break; case 3: actor->Slot25(packet->value); break; case 4: actor->Slot26(packet->value); break; case 5: actor->Slot27(packet->value); break; case 6: actor->Slot34(packet->value); break; case 7: actor->Slot33(packet->value); break; case 8: actor->Slot28(packet->value); break; } } // OFFSET: 0x00D44760 // FUNCTION: fn_21836 void CGameMode::ReceiveSpriteChange2(const unsigned char* data) { const auto* packet = reinterpret_cast(data); const int bodyCostume = g_session.m_bodyCostume; const int bodyStyle = g_session.m_bodyStyle; const int value = static_cast(packet->value); CGameActor* actor; if (packet->aid == g_session.m_aid) { actor = this->scene->player; switch (packet->type) { case 0: g_session.UpdateBodyStyle(g_session.GetDisplayJob(), bodyStyle, bodyCostume); if (g_session.m_job != packet->value) { g_session.SetJob(value); } break; case 1: g_session.m_head = value; break; case 2: { *reinterpret_cast(&g_session.unknown_0EDC[0x4]) = value; const int shield = static_cast(packet->value >> 32); *reinterpret_cast(&g_session.unknown_0EDC[0x8]) = shield; if (value != 0 && GetWeaponViewValue(shield) == -1) { *reinterpret_cast(&g_session.unknown_0EDC[0xC]) = shield; } break; } case 3: *reinterpret_cast(&g_session.unknown_0EF4[0x0]) = value; break; case 4: *reinterpret_cast(&g_session.unknown_0EF4[0x4]) = value; break; case 5: *reinterpret_cast(&g_session.unknown_0EF4[0x8]) = value; break; case 6: g_session.m_headPalette = value; break; case 7: g_session.UpdateBodyStyle(g_session.GetDisplayJob(), value, bodyCostume); break; case 11: *reinterpret_cast(&g_session.unknown_0EF4[0x0]) = 0; *reinterpret_cast(&g_session.unknown_0EF4[0x4]) = 0; *reinterpret_cast(&g_session.unknown_0EF4[0x8]) = 0; g_session.m_robe = 0; break; case 12: g_session.m_robe = value; break; case 13: g_session.m_bodyCostume = value; break; case 14: g_session.SetFlag(static_cast(value)); actor->Slot62(value); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(4137)), 0, 0, 0, 0); break; } if (!actor) { return; } } else { actor = static_cast(this->scene->GetGameActorByAID(packet->aid)); if (!actor) { CRenderObject* skill = this->scene->GetSkillByAID(packet->aid); if (!skill) { return; } if (packet->type == 0) { skill->SendMsg(nullptr, 47, 0, value, static_cast(packet->value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } return; } } switch (packet->type) { case 0: actor->SetActorJob(value); if (packet->aid == g_session.m_aid) { actor->Slot33(g_session.m_bodyStyle); } actor->Slot30(); actor->Slot31(); actor->Slot32(); break; case 1: actor->Slot22(value); actor->Slot30(); actor->Slot31(); actor->Slot60(); break; case 2: { const int shield = static_cast(packet->value >> 32); const int weapon = value; const int view = GetWeaponViewValue(shield); switch (actor->GetEffectiveJob(-1)) { case 0xC: case 0xFAD: case 0xFC3: case 0xFDB: case 0xFE1: case 0x1005: case 0x109E: actor->Slot24(value, shield); break; default: actor->Slot24(weapon, weapon >> 31); break; } if (view == -1 || shield == 0) { actor->Slot28(shield); } break; } case 3: actor->Slot25(value); break; case 4: actor->Slot26(value); break; case 5: actor->Slot27(value); break; case 6: actor->Slot34(value); break; case 7: actor->Slot33(value); break; case 9: actor->Slot29(value); break; case 11: actor->Slot25(0); actor->Slot26(0); actor->Slot27(0); actor->Slot43(0, 0); break; case 12: actor->Slot43(value, 0); break; case 13: actor->Slot44(value, 1); if (StateFlag04(actor->Slot13())) { actor->SendMsg(nullptr, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); actor->SendMsg(nullptr, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } if (StateFlag20(actor->Slot13())) { actor->SendMsg(nullptr, 138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); actor->SendMsg(nullptr, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } break; case 14: actor->Slot62(value); break; } } #pragma pack(push, 1) struct MapPropertyPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t mapId; /* 0004 */ std::uint32_t flags; }; #pragma pack(pop) // OFFSET: 0x00D19B30 // FUNCTION: fn_21613 void CGameMode::ReceiveMapProperty(const unsigned char* data) { const auto* packet = reinterpret_cast(data); g_mapPropertyMgr->SetValue(packet->mapId, 7, packet->flags & 1); g_mapPropertyMgr->SetValue(packet->mapId, 8, (packet->flags >> 1) & 1); g_mapPropertyMgr->SetValue(packet->mapId, 9, (packet->flags >> 2) & 1); g_mapPropertyMgr->SetValue(packet->mapId, 15, (packet->flags >> 3) & 1); g_mapPropertyMgr->SetValue(packet->mapId, 16, (packet->flags >> 4) & 1); g_mapPropertyMgr->SetValue(packet->mapId, 17, (packet->flags >> 5) & 1); g_mapPropertyMgr->SetValue(packet->mapId, 18, (packet->flags >> 6) & 1); g_mapPropertyMgr->SetValue(packet->mapId, 19, (packet->flags >> 7) & 1); g_mapPropertyMgr->SetValue(packet->mapId, 20, (packet->flags >> 8) & 1); g_mapPropertyMgr->SetValue(packet->mapId, 40, (packet->flags >> 9) & 1); g_mapPropertyMgr->SetValue(packet->mapId, 41, (packet->flags >> 10) & 1); g_session.unknown_0000 = packet->mapId; g_serviceOptions.Set(229, *reinterpret_cast(&g_session.unknown_5454[0x0]) != 0); *reinterpret_cast(&g_session.unknown_5454[0x4]) = 0; *reinterpret_cast(&g_session.unknown_5454[0x8]) = 0; g_session.unknown_5460 = 0; if (g_session.GetMapProperty0F()) { g_serviceOptions.Set(229, 1); } if (g_session.GetMapProperty10()) { *reinterpret_cast(&g_session.unknown_5454[0x4]) = 1; } if (g_session.GetMapProperty11()) { *reinterpret_cast(&g_session.unknown_5454[0x8]) = 1; } if (g_session.GetMapProperty12()) { g_session.unknown_5460 = 1; } if (g_session.GetMapProperty09()) { this->scene->unknown_004C = 1; } if (g_session.GetMapProperty13()) { this->scene->unknown_0050 = 1; } if (GetBaseJob(g_session.GetDisplayJob()) == 0xFCF && !g_mapPropertyMgr->GetValue(g_session.unknown_0000, 41)) { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2381)), 0xFFFF64, 0, 0, 0); } if (GetBaseJob(g_session.GetDisplayJob()) == 0x1082 && !g_mapPropertyMgr->GetValue(g_session.unknown_0000, 41)) { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2381)), 0xFFFF64, 0, 0, 0); } if ((g_session.GetDisplayJob() == 0x108F || g_session.GetDisplayJob() == 0x1091 || g_session.GetDisplayJob() == 0x10CE) && !g_mapPropertyMgr->GetValue(g_session.unknown_0000, 41)) { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(2381)), 0xFFFF64, 0, 0, 0); } if (g_mapPropertyMgr->GetValue(packet->mapId, 20)) { g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(1772)), 0xFFFF64, 0, 0, 0); } PacketIdOnly request; request.id = 0x447; GetRagConnection().Send(g_packetLengths.FixedLength(request.id), &request); } #pragma pack(push, 1) struct StovePurchaseResultPacket { /* 0000 */ std::int16_t id; /* 0002 */ int result; /* 0006 */ int itemId; /* 000A */ int count; }; #pragma pack(pop) // OFFSET: 0x00D6B5C0 // FUNCTION: fn_22069 void CGameMode::ReceiveStovePurchaseResult(const unsigned char* data) { if (!g_launchPassCommandLine) { return; } const auto* packet = reinterpret_cast(data); std::string message; switch (packet->result) { case 0: { char name[256]; std::memset(name, 0, sizeof(name)); int capacity = sizeof(name); ITEM_INFO item; item.SetItemId(packet->itemId); ItemDescriptions{g_itemDescriptions}.Name(item, name, capacity, 0); message = FormatOwnedString("%s아이템 %d개 지급 완료", name, packet->count); } case 2: if (g_stoveMgr->unknown_0008 == 2) { FetchStoveTermsAgreement(); } else if (g_stoveMgr->unknown_0008 == 3) { g_stoveMgr->unknown_0008 = 0; UICashShopWnd* window = static_cast(g_windowMgr.LookupWindow(318)); g_stoveMgr->StartPurchase(window->m_cart->m_cartItems); } break; case 1: message = FormatOwnedString("Stove 유저가 아닙니다."); break; case 3: case 4: message = LookupMessage(3022); break; case 5: case 6: case 7: message = FormatOwnedString("아이템 수령 실패"); break; default: message = FormatOwnedString("Unknown Error (Stove:%d)", packet->result); break; } g_stoveMgr->unknown_0008 = 0; if (message.size() != 0) { reinterpret_cast(&g_windowMgr)->Confirm(message.c_str(), 0, true, false, 0, "Message", 280, 120, 0); } } #pragma pack(push, 1) struct OngoingQuestListPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; /* 0004 */ int count; }; struct OngoingQuestEntry { /* 0000 */ unsigned int questId; /* 0004 */ unsigned char state; /* 0005 */ int startTime; /* 0009 */ int endTime; /* 000D */ std::int16_t huntCount; }; struct OngoingQuestHunt { /* 0000 */ int huntId; /* 0004 */ int unknown_0004; /* 0008 */ int mobId; /* 000C */ std::int16_t unknown_000C; /* 000E */ std::int16_t unknown_000E; /* 0010 */ std::int16_t unknown_0010; /* 0012 */ std::int16_t unknown_0012; /* 0014 */ char name[24]; }; struct OngoingQuestHunt2 { /* 0000 */ std::int64_t huntId; /* 0008 */ int unknown_0008; /* 000C */ int mobId; /* 0010 */ std::int16_t unknown_0010; /* 0012 */ std::int16_t unknown_0012; /* 0014 */ std::int16_t unknown_0014; /* 0016 */ std::int16_t unknown_0016; /* 0018 */ char name[24]; }; #pragma pack(pop) // OFFSET: 0x00D6C510 // FUNCTION: fn_22082 void CGameMode::ReceiveOngoingQuestList(const unsigned char* data) { const auto* packet = reinterpret_cast(data); const unsigned char* cursor = data + sizeof(OngoingQuestListPacket); for (int index = 0; index < packet->count; ++index) { const auto* entry = reinterpret_cast(cursor); const auto* hunts = reinterpret_cast(cursor + sizeof(OngoingQuestEntry)); if (g_renewQuestMgr->SetOngoingQuestState(entry->questId, entry->state)) { cursor = reinterpret_cast(hunts + entry->huntCount); continue; } RenewQuestOngoingInfo info; info.m_state = entry->state; __time32_t endTime = 0; if (entry->endTime > 0) { endTime = entry->endTime; } const tm* time = _localtime32(&endTime); info.m_day = time->tm_mday; info.m_year = time->tm_year + 1900; info.m_month = time->tm_mon + 1; info.m_hour = entry->endTime != 0 ? time->tm_hour : 0; info.m_minute = entry->endTime != 0 ? time->tm_min : 0; info.m_huntCount = static_cast(entry->huntCount); const OngoingQuestHunt* hunt = hunts; for (int i = 0; i < entry->huntCount; ++i, ++hunt) { info.m_huntId[i] = hunt->huntId; info.m_huntUnknown01A0[i] = hunt->unknown_0004; info.m_huntUnknown00D4[i] = hunt->mobId; info.m_huntUnknown00E0[i] = hunt->unknown_0010; info.m_huntUnknown0180[i] = hunt->unknown_0012; info.m_huntUnknown01AC[i] = hunt->unknown_000C; info.m_huntUnknown01B2[i] = hunt->unknown_000E; const int mobId = hunt->mobId; if ((mobId < 1001 || mobId > 3998) && static_cast(mobId - 20021) > 11978) { if (mobId == 0x1099) { StringFormat(info.m_huntName[i], 0x33, static_cast(-1), "%s", LookupMessage(3558)); } else if (mobId == 0x109A) { StringFormat(info.m_huntName[i], 0x33, static_cast(-1), "%s", LookupMessage(3559)); } else if (mobId == 0x287B) { const std::string mapName = FormatOwnedString("%s.rsw", hunt->name); StringFormat(info.m_huntName[i], 0x33, static_cast(-1), "%s", g_session.GetMapDisplayName(mapName.c_str())); } else { StringFormat(info.m_huntName[i], 0x33, static_cast(-1), "%s", g_session.GetJobName(mobId, 99)); } } else { StringFormat(info.m_huntName[i], 0x33, static_cast(-1), "%s", hunt->name); } } cursor = reinterpret_cast(hunt); g_renewQuestMgr->AddOngoingQuest(entry->questId, info); } g_renewQuestMgr->sub_67B6B0(); } // OFFSET: 0x00D6CAD0 // FUNCTION: fn_22083 void CGameMode::ReceiveOngoingQuestList2(const unsigned char* data) { const auto* packet = reinterpret_cast(data); const unsigned char* cursor = data + sizeof(OngoingQuestListPacket); for (int index = 0; index < packet->count; ++index) { const auto* entry = reinterpret_cast(cursor); const auto* hunts = reinterpret_cast(cursor + sizeof(OngoingQuestEntry)); if (g_renewQuestMgr->SetOngoingQuestState(entry->questId, entry->state)) { cursor = reinterpret_cast(hunts + entry->huntCount); continue; } RenewQuestOngoingInfo info; info.m_state = entry->state; __time32_t endTime = 0; if (entry->endTime > 0) { endTime = entry->endTime; } const tm* time = _localtime32(&endTime); info.m_day = time->tm_mday; info.m_year = time->tm_year + 1900; info.m_month = time->tm_mon + 1; info.m_hour = entry->endTime != 0 ? time->tm_hour : 0; info.m_minute = entry->endTime != 0 ? time->tm_min : 0; info.m_huntCount = static_cast(entry->huntCount); const OngoingQuestHunt2* hunt = hunts; for (int i = 0; i < entry->huntCount; ++i, ++hunt) { info.m_huntId[i] = hunt->huntId; info.m_huntUnknown01A0[i] = hunt->unknown_0008; info.m_huntUnknown00D4[i] = hunt->mobId; info.m_huntUnknown00E0[i] = hunt->unknown_0014; info.m_huntUnknown0180[i] = hunt->unknown_0016; info.m_huntUnknown01AC[i] = hunt->unknown_0010; info.m_huntUnknown01B2[i] = hunt->unknown_0012; const int mobId = hunt->mobId; if ((mobId < 1001 || mobId > 3998) && static_cast(mobId - 20021) > 11978) { if (mobId == 0x1099) { StringFormat(info.m_huntName[i], 0x33, static_cast(-1), "%s", LookupMessage(3558)); } else if (mobId == 0x109A) { StringFormat(info.m_huntName[i], 0x33, static_cast(-1), "%s", LookupMessage(3559)); } else if (mobId == 0x287B) { const std::string mapName = FormatOwnedString("%s.rsw", hunt->name); StringFormat(info.m_huntName[i], 0x33, static_cast(-1), "%s", g_session.GetMapDisplayName(mapName.c_str())); } else { StringFormat(info.m_huntName[i], 0x33, static_cast(-1), "%s", g_session.GetJobName(mobId, 99)); } } else { StringFormat(info.m_huntName[i], 0x33, static_cast(-1), "%s", hunt->name); } } cursor = reinterpret_cast(hunt); g_renewQuestMgr->AddOngoingQuest(entry->questId, info); } g_renewQuestMgr->sub_67B6B0(); } #pragma pack(push, 1) struct ShopItemListEntry { /* 0000 */ int price; /* 0004 */ std::int16_t amount; /* 0006 */ std::int16_t index; /* 0008 */ unsigned char type; /* 0009 */ int itemId; /* 000D */ unsigned char identified; /* 000E */ unsigned char damaged; /* 000F */ std::uint32_t cards[4]; /* 001F */ ItemSlotOption options[5]; /* 0038 */ std::uint32_t location; /* 003C */ std::uint16_t sprite; /* 003E */ unsigned char refine; /* 003F */ unsigned char grade; }; struct ShopItemListHeader { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; /* 0004 */ int value; /* 0008 */ int argument; /* 000C */ unsigned char myShop; /* 000D */ std::uint32_t duration; }; #pragma pack(pop) // OFFSET: 0x00D703A0 // FUNCTION: fn_22130 void CGameMode::ReceiveShopItemListPacket(const unsigned char* data) { const auto* header = reinterpret_cast(data); const auto* entries = reinterpret_cast(data + sizeof(ShopItemListHeader)); const unsigned int count = (header->length - sizeof(ShopItemListHeader)) / sizeof(ShopItemListEntry); std::vector items; if (count != 0) { items.reserve(count); } for (long long i = 0; i < count; ++i) { const ShopItemListEntry& entry = entries[i]; ITEM_INFO item; item.unknown_0000[1] = entry.index; item.unknown_0014[0] = entry.price; item.unknown_0000[0] = entry.type; item.quantity = entry.amount; item.identified = entry.identified; item.unknown_005D = entry.damaged; item.unknown_0060 = entry.refine; item.unknown_0014[1] = entry.price; item.SetItemId(entry.itemId); std::memcpy(item.unknown_001C, entry.cards, sizeof(entry.cards)); item.unknown_0098 = CountItemSlotOptions(entry.options); for (long long option = 0; option < static_cast(item.unknown_0098); ++option) { reinterpret_cast(item.unknown_009C)[option] = entry.options[option]; } item.unknown_0000[2] = entry.location; item.unknown_0070 = entry.sprite; item.unknown_0088 = entry.grade; items.push_back(item); } this->ReceiveShopItemList(items, header->value, 0, header->argument, 0, header->duration, header->myShop); } // OFFSET: 0x00D71720 // FUNCTION: fn_22136 void CGameMode::RequestLocalMapMove(const char* mapName, std::uint16_t x, std::uint16_t y) { struct MapMovePacket { /* 0000 */ std::uint16_t id; /* 0002 */ char mapName[16]; /* 0012 */ std::uint16_t x; /* 0014 */ std::uint16_t y; } packet; g_localMapMove = 1; packet.id = 0x91; strcpy_s(packet.mapName, sizeof(packet.mapName), mapName); packet.x = x; packet.y = y; this->ReceiveNpcAckMapmove(reinterpret_cast(&packet)); } #pragma pack(push, 1) struct GradeEnchantBroadcastPacket { /* 0000 */ std::int16_t id; /* 0002 */ char name[24]; /* 001A */ int itemId; /* 001E */ std::int16_t grade; /* 0020 */ unsigned char success; }; #pragma pack(pop) // OFFSET: 0x00D6D400 // FUNCTION: fn_22089 void CGameMode::ReceiveRefineStatus(const char* playerName, int itemId, unsigned char refine, bool success) { std::string name(playerName, 24); std::string itemName; ITEM_INFO item; item.SetItemId(itemId); item.identified = 1; { ItemDescriptions descriptions{g_itemDescriptions}; bool languagePrefix = false; WORD language = g_serverLanguage->language; ItemNaming naming{descriptions, g_itemCardNames, *g_playerNameDictionary, languagePrefix, g_serviceType, language}; itemName = naming.DisplayName(item, 0); } std::string text = FormatOwnedString(LookupMessage(!success + 3271), name.c_str(), refine, itemName.c_str()); if (UIBroadcastBalloon* balloon = this->EnsureBroadcastBalloon()) { BroadcastBalloonMessage message{{}, {}, std::chrono::seconds(20), 12, 0x40000000, 0, 0}; message.start = std::chrono::system_clock::now(); message.lines.push_back(BroadcastBalloonLine{text, 0x62B0FF, 0}); balloon->AddMessage(0, message); } g_windowMgr.SendNotice(1, reinterpret_cast(text.c_str()), 0x62B0FF, 0, 0, 0); } // OFFSET: 0x00D6F000 #pragma pack(push, 1) struct RodexMailItem { /* 0000 */ std::uint16_t quantity; /* 0002 */ int itemId; /* 0006 */ unsigned char identified; /* 0007 */ unsigned char damaged; /* 0008 */ std::uint32_t cards[4]; /* 0018 */ std::uint32_t expireTime; /* 001C */ unsigned char type; /* 001D */ std::uint16_t bindType; /* 001F */ std::uint16_t unknown_001F; /* 0021 */ ItemSlotOption options[5]; /* 003A */ unsigned char refine; /* 003B */ unsigned char grade; }; struct RodexReadMailPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; /* 0004 */ unsigned char type; /* 0005 */ std::int64_t mailId; /* 000D */ std::int16_t textLength; /* 000F */ std::int64_t zeny; /* 0017 */ unsigned char itemCount; /* 0018 */ char text[1]; }; #pragma pack(pop) // OFFSET: 0x00D6B120 // FUNCTION: fn_22068 void CGameMode::ReceiveRodexReadMail(const unsigned char* data) { const auto* packet = reinterpret_cast(data); g_session.ClearItemQuantities(); g_rodexMailStore->currentMailId = packet->mailId; g_rodexMailStore->unknown_0010 = packet->type; std::map* mails; switch (packet->type) { case 0: mails = &g_rodexMailStore->m_mails0; break; case 1: mails = &g_rodexMailStore->m_mails1; break; case 2: mails = &g_rodexMailStore->m_mails2; break; default: return; } std::map::iterator found = mails->find(packet->mailId); if (found == mails->end()) { return; } RodexMail& mail = found->second; if (!mail.isRead && --g_rodexMailStore->unknown_0018 == 0) { if (UIWindow* window = g_windowMgr.LookupWindow(307)) { window->SendMsg(nullptr, 6, 286, 476, 0, 0); } } mail.unknown_003C.append(packet->text, packet->textLength); mail.hasItem = packet->itemCount; mail.zeny = packet->zeny; mail.isRead = 1; auto* mailItems = reinterpret_cast(mail.unknown_0055.data()); const auto* packetItems = reinterpret_cast(packet->text + packet->textLength); for (long long i = 0; i < packet->itemCount; ++i) { RodexMailItem& record = mailItems[i]; memcpy_s(&record, sizeof(RodexMailItem), &packetItems[i], sizeof(RodexMailItem)); ITEM_INFO item; item.unknown_0000[0] = record.type; item.unknown_0000[2] = record.expireTime; item.quantity = record.quantity; std::memcpy(item.unknown_001C, record.cards, sizeof(record.cards)); item.SetItemId(record.itemId); item.identified = record.identified; item.unknown_005D = record.damaged; item.unknown_0060 = record.refine; item.unknown_0064 = record.unknown_001F; item.unknown_0070 = record.bindType; item.unknown_0098 = CountItemSlotOptions(record.options); for (long long option = 0; option < item.unknown_0098; ++option) { reinterpret_cast(item.unknown_009C)[option] = record.options[option]; } item.unknown_0088 = record.grade; g_session.AddItemToFreeSlot(item); } if (!g_windowMgr.CloseWindow(265)) { g_windowMgr.EnsureWindow(265); g_windowMgr.unknown_045C->SendMsg(nullptr, 23, 0, 0, 0, 0); } } #pragma pack(push, 1) struct RodexMailPageEntry { /* 0000 */ std::int64_t mailId; /* 0008 */ unsigned char isRead; /* 0009 */ unsigned char type; /* 000A */ char sender[24]; /* 0022 */ int unknown_0022; /* 0026 */ int expireTime; /* 002A */ std::int16_t titleLength; /* 002C */ char title[1]; }; struct RodexMailPagePacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t length; /* 0004 */ unsigned char type; /* 0005 */ unsigned char count; /* 0006 */ unsigned char isEnd; /* 0007 */ RodexMailPageEntry entries[1]; }; #pragma pack(pop) // OFFSET: 0x00D70BF0 // FUNCTION: fn_22132 void CGameMode::ReceiveRodexMailListRefresh(const unsigned char* data) { const auto* packet = reinterpret_cast(data); const RodexMailPageEntry* entry = packet->entries; g_rodexMailStore->unknown_0010 = packet->type; g_rodexMailStore->unknown_001C = packet->isEnd; std::map* mails; if (g_rodexMailStore->unknown_0010 == 0) { mails = &g_rodexMailStore->m_mails0; } else if (g_rodexMailStore->unknown_0010 == 1) { mails = &g_rodexMailStore->m_mails1; } else if (g_rodexMailStore->unknown_0010 == 2) { mails = &g_rodexMailStore->m_mails2; } mails->clear(); for (int i = 0; i < packet->count; ++i) { RodexMail mail; mail.isRead = entry->isRead; mail.unknown_0001 = entry->type; mail.unknown_0020 = _time32(nullptr) + entry->expireTime; mail.unknown_0004.assign(entry->sender, (std::min)(std::strlen(entry->sender), static_cast(24))); mail.unknown_0024.assign(entry->title, entry->titleLength); if (mails->find(entry->mailId) == mails->end()) { mails->insert(std::make_pair(entry->mailId, mail)); } entry = reinterpret_cast(reinterpret_cast(entry) + 0x2C + entry->titleLength); } if (g_windowMgr.unknown_0454) { reinterpret_cast(g_windowMgr.unknown_0454)->InitializeMailActions(); reinterpret_cast(g_windowMgr.unknown_0454)->SetButtonsDisabled(0); } } // OFFSET: 0x00D6A0D0 // OFFSET: 0x00D19000 // FUNCTION: fn_21604 void CRenewQuestMgr::SetOngoingQuest(unsigned int id, const RenewQuestOngoingInfo& info) { this->m_ongoingQuests[id] = info; } #pragma pack(push, 1) struct SpecialBroadcastPacket { /* 0000 */ std::uint16_t packetType; /* 0002 */ char name[24]; /* 001A */ int value; /* 001E */ unsigned char index; /* 001F */ unsigned char type; }; #pragma pack(pop) // OFFSET: 0x00D44F50 // FUNCTION: fn_21838 void CGameMode::ReceiveSpecialBroadcast(const unsigned char* data) { const auto* packet = reinterpret_cast(data); CPlayer* player = this->scene->player; UIBroadcastBalloon* balloon = this->EnsureBroadcastBalloon(); if (!balloon) { return; } std::string text; switch (packet->type) { case 0: text.assign(FormatOwnedString(LookupMessage(packet->index + 837), g_session.DecodePlayerName(), packet->name)); break; case 1: text.assign(FormatOwnedString(LookupMessage(packet->index + 840), g_session.DecodePlayerName(), packet->name)); player->LaunchEffect(543, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); g_soundMgr->PlayWave("effect\\T_피링.wav", 0.0f, -250.0f, 0.0f, 250, 40, 1.0f, 0); break; case 10: text.assign(FormatOwnedString(LookupMessage(packet->index + 843), g_session.DecodePlayerName(), g_session.GetJobName(packet->value, -1))); break; case 11: text.assign(FormatOwnedString(LookupMessage(packet->index + 846), g_session.DecodePlayerName(), g_session.GetJobName(packet->value, -1))); player->LaunchEffect(543, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); g_soundMgr->PlayWave("effect\\T_피링.wav", 0.0f, -250.0f, 0.0f, 250, 40, 1.0f, 0); break; case 20: text.assign(FormatOwnedString(LookupMessage(927), packet->name, packet->index)); player->LaunchEffect(543, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; case 21: text.assign(FormatOwnedString(LookupMessage(1190), packet->name)); player->LaunchEffect(543, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; case 22: { ITEM_INFO item; item.SetItemId(packet->value); char itemName[256]; int capacity = sizeof(itemName); ItemDescriptions{g_itemDescriptions}.Name(item, itemName, capacity, 0); text.assign(FormatOwnedString(LookupMessage(1265), itemName)); player->LaunchEffect(543, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; } case 30: text = LookupMessage(1033); player->LaunchEffect(432, vector3d{0.0f, 0.0f, 0.0f}, 0.0f); break; case 40: text = std::format("Target HP : {}", packet->value); break; } BroadcastBalloonMessage message{{}, {}, std::chrono::seconds(20), 12, 0x40000000, 0, 0}; message.start = std::chrono::system_clock::now(); message.fontHeight = 14; std::uint32_t color = 0xFFC8C8; message.lines.emplace_back(text, color); balloon->AddMessage(0, message); } #pragma pack(push, 1) struct QuestHuntUpdateEntry { /* 0000 */ unsigned int questId; /* 0004 */ __int64 huntId; /* 000C */ short maxCount; /* 000E */ short count; }; struct QuestHuntUpdatePacket { /* 0000 */ std::uint16_t packetType; /* 0002 */ std::int16_t length; /* 0004 */ std::int16_t unknown_0004; /* 0006 */ QuestHuntUpdateEntry entries[1]; }; #pragma pack(pop) // OFFSET: 0x00D47760 #pragma pack(push, 1) struct QuestHuntUpdateEntry2 { /* 0000 */ unsigned int questId; /* 0004 */ unsigned int huntId; /* 0008 */ short maxCount; /* 000A */ short count; }; struct QuestHuntUpdatePacket2 { /* 0000 */ std::uint16_t packetType; /* 0002 */ std::int16_t length; /* 0004 */ std::int16_t unknown_0004; /* 0006 */ QuestHuntUpdateEntry2 entries[1]; }; #pragma pack(pop) // OFFSET: 0x00D47C20 // FUNCTION: fn_22058 void CGameMode::ReceiveRodexMailListAppend(const unsigned char* data) { const auto* packet = reinterpret_cast(data); const RodexMailPageEntry* entry = packet->entries; g_rodexMailStore->unknown_0010 = packet->type; g_rodexMailStore->unknown_001C = packet->isEnd; for (int i = 1; i < packet->count + 1; ++i) { RodexMail mail; mail.isRead = entry->isRead; mail.unknown_0001 = entry->type; mail.unknown_0020 = _time32(nullptr) + entry->expireTime; mail.unknown_0004.assign(entry->sender, (std::min)(std::strlen(entry->sender), static_cast(24))); if (packet->type == 0 && (mail.unknown_0001 & 8) == 0 && !g_session.HasUnknown809C(mail.unknown_0004)) { mail.unknown_0194 = g_session.IsKnownName(mail.unknown_0004); } else { mail.unknown_0194 = 1; } mail.unknown_0024.append(entry->title, entry->titleLength); switch (packet->type) { case 0: if (g_rodexMailStore->m_mails0.find(entry->mailId) == g_rodexMailStore->m_mails0.end()) { g_rodexMailStore->m_mails0.insert(std::make_pair(entry->mailId, mail)); } break; case 1: if (g_rodexMailStore->m_mails1.find(entry->mailId) == g_rodexMailStore->m_mails1.end()) { g_rodexMailStore->m_mails1.insert(std::make_pair(entry->mailId, mail)); } break; case 2: if (g_rodexMailStore->m_mails2.find(entry->mailId) == g_rodexMailStore->m_mails2.end()) { g_rodexMailStore->m_mails2.insert(std::make_pair(entry->mailId, mail)); } break; } entry = reinterpret_cast(reinterpret_cast(entry) + 0x2C + entry->titleLength); } if (g_windowMgr.unknown_0454) { static_cast(g_windowMgr.unknown_0454)->RefreshMailLists(); static_cast(g_windowMgr.unknown_0454)->SetButtonsDisabled(0); static_cast(g_windowMgr.unknown_0454)->ClearChecks(); } } #include "Contents/Skills/ClientSkills.h" #pragma pack(push, 1) struct StatusChangeNoticePacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t type; /* 0004 */ std::uint32_t aid; /* 0008 */ unsigned char state; }; #pragma pack(pop) // OFFSET: 0x00D71AB0 // FUNCTION: fn_22140 void CGameMode::ReceiveStatusChangeNotice(const unsigned char* data) { const auto* packet = reinterpret_cast(data); if (packet->aid != g_session.m_aid) { if (CRenderObject* actor = this->scene->GetGameActorByAID(packet->aid)) { actor->SendMsg(nullptr, 110, 0, packet->type, packet->type >> 31, packet->state, 0, 0, 0, 0, 0, 0, 0, 0, 0); } } MessengerMember member = ClientMessenger{g_session.m_partyMembers, g_session.m_friends}.PartyByAccount(packet->aid); if (packet->aid != g_session.m_aid && (!member.valid || member.offline)) { return; } char name[256]; std::sprintf(name, ""); if (packet->aid != g_session.m_aid) { std::sprintf(name, LookupMessage(1275), member.name.c_str()); } char message[256]; std::memset(message, 0, sizeof(message)); std::uint32_t color; if (packet->state) { if (packet->aid == g_session.m_aid) { ActiveSkillEffect effect; effect.id = packet->type; effect.unknown_0004 = 999999; if (!this->IsExcludedSkillEffectId(packet->type)) { for (std::vector::iterator it = g_activeSkillEffects.begin(); it != g_activeSkillEffects.end();) { if (it->id == packet->type) { g_activeSkillEffects.erase(it); it = g_activeSkillEffects.begin(); } else { ++it; } } } g_activeSkillEffects.push_back(effect); } color = 0xFFFF00; switch (packet->type) { case 2: case 37: case 38: case 39: case 40: case 68: case 161: std::sprintf(message, LookupMessage(463)); break; case 896: case 917: case 919: case 937: case 982: break; case 15: std::sprintf(message, LookupMessage(3463)); break; case 16: std::sprintf(message, LookupMessage(467)); break; case 6: std::sprintf(message, LookupMessage(469)); break; case 17: case 64: std::sprintf(message, LookupMessage(470)); break; case 18: std::sprintf(message, LookupMessage(472)); break; case 19: std::sprintf(message, LookupMessage(474)); break; case 24: std::sprintf(message, LookupMessage(476)); break; case 25: case 188: std::sprintf(message, LookupMessage(465)); break; case 26: std::sprintf(message, LookupMessage(480)); break; case 12: case 41: case 42: std::sprintf(message, LookupMessage(209)); break; case 13: std::sprintf(message, LookupMessage(210)); break; case 7: std::sprintf(message, LookupMessage(620)); break; case 8: std::sprintf(message, LookupMessage(622)); break; case 9: std::sprintf(message, LookupMessage(3435)); break; case 10: std::sprintf(message, LookupMessage(3434)); break; case 14: std::sprintf(message, LookupMessage(630)); break; case 20: std::sprintf(message, LookupMessage(632)); break; case 21: std::sprintf(message, LookupMessage(634)); break; case 22: std::sprintf(message, LookupMessage(636)); break; case 23: case 147: std::sprintf(message, LookupMessage(638)); break; case 29: std::sprintf(message, ""); if (packet->aid == g_session.m_aid) { this->scene->player->SetAction(64, 4, 1); this->scene->player->render.isMotionFreezed = true; } break; case 30: std::sprintf(message, LookupMessage(3433)); break; case 31: std::sprintf(message, LookupMessage(648)); break; case 32: std::sprintf(message, LookupMessage(650)); break; case 33: std::sprintf(message, LookupMessage(652)); break; case 182: if (packet->aid == g_session.m_aid) { g_soundMgr->PlayWave("lava_golem_move.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0); } std::sprintf(message, ""); break; case 0: case 1: case 3: case 4: case 5: case 11: case 27: case 28: case 34: case 54: case 55: case 56: case 57: case 61: case 86: case 87: case 95: case 97: case 98: case 103: case 104: case 105: case 107: case 110: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 120: case 121: case 122: case 123: case 124: case 125: case 130: case 132: case 133: case 134: case 135: case 137: case 139: case 141: case 143: case 145: case 149: case 152: case 153: case 156: case 157: case 158: case 159: case 160: case 165: case 166: case 167: case 169: case 170: case 171: case 181: case 184: case 186: case 191: case 197: case 198: case 199: case 200: case 201: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 238: case 239: case 240: case 250: case 254: case 255: case 256: case 257: case 258: case 259: case 261: case 262: case 263: case 264: case 265: case 266: case 267: case 268: case 269: case 270: case 282: case 286: case 289: case 290: case 291: case 292: case 293: case 294: case 295: case 296: case 298: case 300: case 301: case 302: case 313: case 314: case 316: case 318: case 319: case 320: case 321: case 322: case 323: case 328: case 330: case 333: case 334: case 336: case 337: case 339: case 341: case 342: case 343: case 344: case 345: case 346: case 347: case 348: case 349: case 350: case 351: case 352: case 353: case 354: case 355: case 357: case 360: case 361: case 362: case 363: case 364: case 365: case 366: case 367: case 373: case 374: case 375: case 377: case 379: case 381: case 382: case 383: case 384: case 385: case 386: case 387: case 388: case 389: case 390: case 393: case 394: case 396: case 397: case 398: case 399: case 401: case 402: case 403: case 404: case 405: case 407: case 408: case 409: case 410: case 411: case 412: case 413: case 414: case 415: case 416: case 417: case 418: case 419: case 421: case 422: case 423: case 425: case 426: case 427: case 429: case 430: case 433: case 434: case 435: case 436: case 437: case 438: case 439: case 440: case 441: case 442: case 443: case 444: case 445: case 446: case 447: case 448: case 450: case 451: case 452: case 453: case 454: case 461: case 463: case 464: case 472: case 473: case 476: case 491: case 492: case 493: case 494: case 495: case 496: case 571: case 577: case 580: case 581: case 584: case 605: case 606: case 607: case 608: case 611: case 648: case 649: case 670: case 869: case 1056: case 1057: case 1058: case 1059: case 1121: std::sprintf(message, ""); break; case 260: if (packet->aid == g_session.m_aid) { g_seasonalMonsterSprites = 1; } std::sprintf(message, ""); break; case 241: case 271: std::sprintf(message, LookupMessage(1231)); break; case 242: case 272: std::sprintf(message, LookupMessage(1233)); break; case 243: case 273: std::sprintf(message, LookupMessage(1235)); break; case 244: case 274: std::sprintf(message, LookupMessage(1239)); break; case 245: case 275: std::sprintf(message, LookupMessage(1237)); break; case 246: case 276: std::sprintf(message, LookupMessage(1241)); break; case 247: std::sprintf(message, LookupMessage(1243)); break; case 248: std::sprintf(message, LookupMessage(1245)); break; case 249: std::sprintf(message, LookupMessage(1247)); break; case 251: std::sprintf(message, LookupMessage(1250)); break; case 252: std::sprintf(message, LookupMessage(1251)); break; case 253: if (packet->aid == g_session.m_aid) { this->unknown_05CC[0] = 1; } std::sprintf(message, LookupMessage(1252)); break; case 312: std::sprintf(message, LookupMessage(1383)); break; case 933: if (packet->aid == g_session.m_aid) { this->scene->player->Slot15(48, 1); this->scene->player->render.isMotionFreezed = true; } break; case 893: if (packet->aid == g_session.m_aid) { this->scene->GetGameActorByAID(packet->aid); this->scene->player->Slot15(47, 1); } break; case 1013: color = 0xFF; std::sprintf(message, LookupMessage(3247)); break; default: this->sub_CFE480(packet->aid); return; } } else { if (packet->aid == g_session.m_aid) { for (std::vector::iterator it = g_activeSkillEffects.begin(); it != g_activeSkillEffects.end();) { if (it->id == packet->type) { g_activeSkillEffects.erase(it); it = g_activeSkillEffects.begin(); } else { ++it; } } } color = 0xFF; switch (packet->type) { case 2: case 37: case 38: case 39: case 68: case 161: std::sprintf(message, LookupMessage(464)); break; case 15: std::sprintf(message, LookupMessage(3464)); break; case 16: std::sprintf(message, LookupMessage(468)); break; case 64: if (packet->aid == g_session.m_aid) { for (std::vector::iterator it = g_activeSkillEffects.begin(); it != g_activeSkillEffects.end();) { if (it->id - 897U <= 9) { g_activeSkillEffects.erase(it); it = g_activeSkillEffects.begin(); } else { ++it; } } } std::sprintf(message, LookupMessage(471)); break; case 6: case 17: std::sprintf(message, LookupMessage(471)); break; case 18: std::sprintf(message, LookupMessage(473)); break; case 19: std::sprintf(message, LookupMessage(475)); break; case 24: std::sprintf(message, LookupMessage(477)); break; case 25: case 188: std::sprintf(message, LookupMessage(466)); break; case 26: std::sprintf(message, LookupMessage(481)); break; case 13: std::sprintf(message, LookupMessage(209)); break; case 7: std::sprintf(message, LookupMessage(621)); break; case 8: std::sprintf(message, LookupMessage(623)); break; case 9: std::sprintf(message, LookupMessage(625)); break; case 10: std::sprintf(message, LookupMessage(627)); break; case 14: std::sprintf(message, LookupMessage(631)); break; case 20: std::sprintf(message, LookupMessage(633)); break; case 21: std::sprintf(message, LookupMessage(635)); break; case 22: std::sprintf(message, LookupMessage(637)); break; case 23: case 147: std::sprintf(message, LookupMessage(639)); break; case 29: std::sprintf(message, ""); if (packet->aid == g_session.m_aid) { this->scene->player->Slot15(0, 1); this->scene->player->render.isMotionFreezed = false; } break; case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 621: case 645: case 646: case 651: case 655: case 656: case 657: case 659: case 660: case 665: case 674: case 716: case 717: case 718: case 719: case 720: case 721: case 728: case 734: case 735: case 736: case 737: case 760: case 779: case 822: case 823: case 825: case 826: case 849: case 856: case 857: case 859: case 863: case 864: case 872: case 895: case 896: case 917: case 919: case 937: case 982: case 1016: case 1017: case 1018: case 1019: case 1020: case 1021: case 1022: case 1023: case 1024: case 1025: case 1038: case 1039: case 1040: case 1041: case 1043: case 1050: case 1055: case 1139: case 1141: case 1142: case 1148: case 1150: case 1184: case 1190: case 1196: case 1197: case 1205: case 1206: case 1207: case 1208: case 1209: case 1210: case 1211: case 1212: case 1213: case 1214: case 1215: case 1216: case 1230: case 1231: case 1232: case 1233: case 1234: case 1250: case 1258: case 1318: case 1319: case 1337: case 1338: case 1339: case 1688: break; case 30: std::sprintf(message, LookupMessage(647)); break; case 31: std::sprintf(message, LookupMessage(649)); break; case 40: if (packet->aid == g_session.m_aid) { for (std::vector::iterator it = g_activeSkillEffects.begin(); it != g_activeSkillEffects.end();) { if (it->id == packet->type) { g_activeSkillEffects.erase(it); it = g_activeSkillEffects.begin(); } else { ++it; } } } std::sprintf(message, LookupMessage(210)); break; case 41: std::sprintf(message, LookupMessage(210)); break; case 12: case 42: if (packet->aid == g_session.m_aid) { for (std::vector::iterator it = g_activeSkillEffects.begin(); it != g_activeSkillEffects.end();) { if (it->id == packet->type) { g_activeSkillEffects.erase(it); it = g_activeSkillEffects.begin(); } else { ++it; } } } std::sprintf(message, LookupMessage(210)); break; case 339: if (packet->aid == g_session.m_aid) { CPlayer* player = this->scene->player; for (int i = 0; i < 10; ++i) { g_effectMgr->Retire(player->render.accountId, 1300 + i); g_effectMgr->Retire(player->render.accountId, 1467 + i); } } std::sprintf(message, ""); break; case 0: case 1: case 3: case 4: case 5: case 11: case 27: case 28: case 32: case 33: case 34: case 54: case 55: case 56: case 57: case 86: case 87: case 95: case 97: case 98: case 103: case 104: case 105: case 107: case 110: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 120: case 121: case 122: case 123: case 124: case 125: case 130: case 132: case 133: case 134: case 135: case 137: case 139: case 141: case 143: case 145: case 149: case 150: case 151: case 152: case 153: case 156: case 157: case 158: case 159: case 160: case 165: case 166: case 167: case 169: case 170: case 171: case 181: case 182: case 184: case 186: case 191: case 197: case 198: case 199: case 200: case 201: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 238: case 239: case 240: case 250: case 251: case 252: case 254: case 255: case 256: case 257: case 258: case 259: case 261: case 262: case 263: case 264: case 265: case 266: case 267: case 268: case 269: case 270: case 282: case 286: case 289: case 290: case 291: case 292: case 293: case 294: case 295: case 296: case 297: case 298: case 299: case 300: case 301: case 302: case 312: case 313: case 314: case 316: case 318: case 319: case 320: case 321: case 322: case 323: case 328: case 330: case 333: case 334: case 336: case 337: case 341: case 342: case 343: case 344: case 345: case 346: case 347: case 348: case 349: case 350: case 351: case 352: case 353: case 354: case 355: case 357: case 360: case 361: case 362: case 363: case 364: case 365: case 366: case 367: case 373: case 374: case 375: case 377: case 379: case 381: case 382: case 383: case 384: case 385: case 386: case 387: case 388: case 389: case 390: case 393: case 394: case 396: case 397: case 398: case 399: case 401: case 402: case 403: case 404: case 405: case 407: case 408: case 409: case 410: case 411: case 412: case 413: case 414: case 415: case 416: case 417: case 418: case 419: case 421: case 422: case 423: case 425: case 426: case 427: case 429: case 430: case 436: case 437: case 438: case 439: case 440: case 441: case 442: case 443: case 444: case 445: case 446: case 447: case 448: case 450: case 451: case 452: case 453: case 454: case 461: case 463: case 464: case 472: case 473: case 476: case 491: case 492: case 493: case 494: case 495: case 496: case 571: case 577: case 580: case 581: case 584: case 605: case 606: case 607: case 608: case 611: case 613: case 618: case 636: case 648: case 649: case 670: case 869: case 1056: case 1057: case 1058: case 1059: case 1121: std::sprintf(message, ""); break; case 434: if (packet->aid == g_session.m_aid) { this->scene->player->SendMsg(nullptr, 109, 0, 879, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } std::sprintf(message, ""); break; case 435: if (packet->aid == g_session.m_aid) { this->scene->player->SendMsg(nullptr, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } std::sprintf(message, ""); break; case 433: if (packet->aid == g_session.m_aid) { this->scene->player->SendMsg(nullptr, 109, 0, 453, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } std::sprintf(message, ""); break; case 358: if (packet->aid == g_session.m_aid) { CPlayer* player = this->scene->player; while (player->state.Attachments().HasId(752)) { player->SendMsg(nullptr, 109, 0, 752, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } } std::sprintf(message, ""); break; case 260: if (packet->aid == g_session.m_aid) { g_seasonalMonsterSprites = 0; } std::sprintf(message, ""); break; case 241: case 271: std::sprintf(message, LookupMessage(1232)); break; case 242: case 272: std::sprintf(message, LookupMessage(1234)); break; case 243: case 273: std::sprintf(message, LookupMessage(1236)); break; case 244: case 274: std::sprintf(message, LookupMessage(1240)); break; case 245: case 275: std::sprintf(message, LookupMessage(1238)); break; case 246: case 276: std::sprintf(message, LookupMessage(1242)); break; case 247: std::sprintf(message, LookupMessage(1244)); break; case 248: std::sprintf(message, LookupMessage(1246)); break; case 249: std::sprintf(message, LookupMessage(1248)); break; case 253: if (packet->aid == g_session.m_aid) { this->unknown_05CC[0] = 0; } break; case 673: if (packet->aid == g_session.m_aid) { g_session.SetUnknown5C1C(0); } break; case 710: if (packet->aid == g_session.m_aid && this->scene->player) { this->scene->player->SendMsg(nullptr, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } break; case 730: if (packet->aid == g_session.m_aid) { CPlayer* player = this->scene->player; while (player->state.Attachments().HasId(1040)) { player->SendMsg(nullptr, 109, 0, 1040, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } } break; case 755: if (packet->aid == g_session.m_aid) { CPlayer* player = this->scene->player; while (player->state.Attachments().HasId(1061)) { player->SendMsg(nullptr, 109, 0, 1061, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } } break; case 933: if (packet->aid == g_session.m_aid) { this->scene->player->Slot15(0, 1); this->scene->player->render.isMotionFreezed = false; } break; case 893: if (packet->aid == g_session.m_aid && !this->scene->player->render.unknown_0114) { this->scene->player->Slot15(0, 1); } break; case 1013: color = 0xFFFF00; std::sprintf(message, LookupMessage(3248)); break; case 1125: if (CEffect* effect = g_effectMgr->Find(packet->aid, 1362)) { g_effectMgr->Retire(effect, 1); } break; case 1149: { CGameActor* actor; if (packet->aid == g_session.m_aid) { actor = this->scene->player; } else { actor = static_cast(this->scene->GetGameActorByAID(packet->aid)); } if (!actor) { break; } actor->Slot57(0); if (packet->aid == g_session.m_aid) { g_session.unknown_8074 = 0; } actor->SendMsg(nullptr, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; } case 1166: if (CEffect* effect = g_effectMgr->Find(packet->aid, 1599)) { g_effectMgr->Retire(effect, 1); } break; case 1167: { CRenderObject* actor; if (packet->aid == g_session.m_aid) { actor = this->scene->player; } else { actor = this->scene->GetGameActorByAID(packet->aid); } if (actor) { actor->SendMsg(nullptr, 109, 0, 1601, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } break; } case 1165: { CRenderObject* actor; if (packet->aid == g_session.m_aid) { actor = this->scene->player; } else { actor = this->scene->GetGameActorByAID(packet->aid); } if (actor) { actor->SendMsg(nullptr, 109, 0, 1610, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } break; } case 1176: if (CEffect* effect = g_effectMgr->Find(packet->aid, 1726)) { g_effectMgr->Retire(effect, 1); } if (CEffect* effect = g_effectMgr->Find(packet->aid, 1727)) { g_effectMgr->Retire(effect, 1); } break; case 1245: StringFormat(message, 256, static_cast(-1), "%s", LookupMessage(3816)); break; case 1221: _snprintf_s(message, 256, LookupMessage(3759)); break; case 1160: _snprintf_s(message, 256, LookupMessage(3727)); break; case 1162: _snprintf_s(message, 256, LookupMessage(3729)); break; case 1161: _snprintf_s(message, 256, LookupMessage(3731)); break; case 1228: _snprintf_s(message, 256, LookupMessage(3733)); break; case 1227: _snprintf_s(message, 256, LookupMessage(3735)); break; case 1201: _snprintf_s(message, 256, LookupMessage(3737)); break; case 1200: _snprintf_s(message, 256, LookupMessage(3739)); break; case 1199: _snprintf_s(message, 256, LookupMessage(3741)); break; case 1198: _snprintf_s(message, 256, LookupMessage(3743)); break; case 1152: if (CEffect* effect = g_effectMgr->Find(packet->aid, 1800)) { g_effectMgr->Retire(effect, 1); } _snprintf_s(message, 256, LookupMessage(3761)); break; case 1194: _snprintf_s(message, 256, LookupMessage(3765)); break; case 1247: _snprintf_s(message, 256, LookupMessage(3783)); break; case 1248: _snprintf_s(message, 256, LookupMessage(3779)); break; case 1249: _snprintf_s(message, 256, LookupMessage(3785)); break; case 1237: if (CEffect* effect = g_effectMgr->Find(packet->aid, 1817)) { g_effectMgr->Retire(effect, 1); g_effectMgr->Spawn(packet->aid, 1821, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0); } StringFormat(message, 256, static_cast(-1), "%s", LookupMessage(3789)); break; case 1236: StringFormat(message, 256, static_cast(-1), "%s", LookupMessage(3787)); break; case 1261: StringFormat(message, 256, static_cast(-1), "%s", LookupMessage(3800)); break; case 1271: StringFormat(message, 256, static_cast(-1), "%s", LookupMessage(3813)); break; case 1244: StringFormat(message, 256, static_cast(-1), "%s", LookupMessage(3814)); break; default: if (CSkillActionMgr::GetInstance()->HasEfstAction(packet->type) != true) { this->sub_CFE480(packet->aid); return; } { const EfstActionMessage action = CSkillActionMgr::GetInstance()->EfstSlot04(packet->type); if (action.text) { color = action.color; StringFormat(message, 256, static_cast(-1), "%s", action.text); } } } } this->sub_CFE480(packet->aid); if (std::strlen(message) > 1) { char text[512]; std::sprintf(text, "%s%s", name, message); g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast(text), color, std::strlen(name) > 1 ? 10 : 8, 0, 0); } if (packet->aid == g_session.m_aid) { this->scene->player->SendMsg(nullptr, 110, 0, packet->type, packet->type >> 31, packet->state, 0, 0, 0, 0, 0, 0, 0, 0, 0); } } #pragma pack(push, 1) struct GuildMemberRemovedPacket { /* 0000 */ std::uint16_t packetType; /* 0002 */ char name[24]; /* 001A */ char reason[40]; }; #pragma pack(pop) // OFFSET: 0x00D48820 // FUNCTION: fn_21855 void CGameMode::ReceiveGuildMemberExpelled(const unsigned char* data) { const auto* packet = reinterpret_cast(data); GuildInfo* guildInfo = reinterpret_cast(reinterpret_cast(&g_guildId) - offsetof(GuildInfo, m_guildId)); char reason[41]; std::memcpy(reason, packet->reason, sizeof(packet->reason)); reason[40] = '\0'; char name[25]; std::memcpy(name, packet->name, sizeof(packet->name)); name[24] = '\0'; if (std::string(name) == g_session.DecodePlayerName()) { g_guildId = 0; g_windowMgr.CloseWindow(59); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(490)), 0xFF, 4, 0, 0); this->SendMsg(172, 0, 0, 0, 0); return; } if (guildInfo->unknown_00C0) { guildInfo->DeleteMember(name); } char message[1024]; std::memset(message, 0, sizeof(message)); std::sprintf(message, LookupMessage(370), name); g_windowMgr.SendNotice(1, reinterpret_cast(message), 0xFFFF, 4, 0, 0); std::memset(message, 0, sizeof(message)); sprintf_s(message, sizeof(message), LookupMessage(371), reason); if (g_forbiddenWords.Contains(message) == true) { std::string masked; g_forbiddenWords.Mask(message, &masked); } g_windowMgr.SendNotice(1, reinterpret_cast(message), 0xFFFF, 4, 0, 0); GuildInfo::Unknown00ECEntry entry; entry.name = name; entry.unknown_0034 = reason; guildInfo->AddUnknown00EC(entry); } #pragma pack(push, 1) struct GuildPositionUpdateEntry { /* 0000 */ int positionId; /* 0004 */ unsigned int mode; /* 0008 */ int ranking; /* 000C */ int payRate; /* 0010 */ char name[24]; }; struct GuildPositionUpdatePacket { /* 0000 */ std::uint16_t packetType; /* 0002 */ std::int16_t length; /* 0004 */ GuildPositionUpdateEntry entries[1]; }; #pragma pack(pop) // OFFSET: 0x00D49020 // FUNCTION: fn_21857 void CGameMode::ReceiveGuildPositionUpdate(const unsigned char* data) { const auto* packet = reinterpret_cast(data); GuildInfo* guildInfo = reinterpret_cast(reinterpret_cast(&g_guildId) - offsetof(GuildInfo, m_guildId)); if (!guildInfo->unknown_00C4) { return; } const int count = (packet->length - 4) / sizeof(GuildPositionUpdateEntry); for (int i = 0; i < count; ++i) { GuildPositionUpdateEntry position = packet->entries[i]; char name[25]; std::memcpy(name, position.name, sizeof(position.name)); name[24] = '\0'; if (g_forbiddenWords.Contains(name)) { std::string masked; g_forbiddenWords.Mask(name, &masked); } guildInfo->m_positions[position.positionId] = name; GuildInfo::Unknown00D4Entry entry; entry.unknown_0004 = position.positionId; entry.unknown_0008 = guildInfo->m_positions[position.positionId]; entry.unknown_0020 = position.mode & 1; entry.unknown_0024 = (position.mode >> 4) & 1; entry.unknown_0028 = position.payRate; entry.unknown_002C = (position.mode >> 8) & 1; entry.unknown_0000 = position.ranking; guildInfo->UpdateUnknown00D4(entry); } g_windowMgr.RefreshGuildWindows(); } // OFFSET: 0x00D49CC0 // FUNCTION: fn_21860 void CGameMode::ReceiveGuildMemberLeft(const unsigned char* data) { const auto* packet = reinterpret_cast(data); GuildInfo* guildInfo = reinterpret_cast(reinterpret_cast(&g_guildId) - offsetof(GuildInfo, m_guildId)); char reason[41]; std::memcpy(reason, packet->reason, sizeof(packet->reason)); reason[40] = '\0'; char name[25]; std::memcpy(name, packet->name, sizeof(packet->name)); name[24] = '\0'; if (std::string(name) == g_session.DecodePlayerName()) { guildInfo->Init(); g_windowMgr.CloseWindow(59); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(489)), 0xFF, 4, 0, 0); this->scene->player->Slot49(0, 0); this->SendMsg(172, 0, 0, 0, 0); return; } if (guildInfo->unknown_00C0) { guildInfo->DeleteMember(name); } char message[1024]; std::sprintf(message, LookupMessage(364), name); g_windowMgr.SendNotice(1, reinterpret_cast(message), 0xFFFF, 4, 0, 0); sprintf_s(message, sizeof(message), LookupMessage(365), reason); if (g_forbiddenWords.Contains(message) == true) { std::string masked; g_forbiddenWords.Mask(message, &masked); } g_windowMgr.SendNotice(1, reinterpret_cast(message), 0xFFFF, 4, 0, 0); } #pragma pack(push, 1) struct GuildPacketText { /* 0000 */ std::uint16_t packetType; /* 0002 */ std::uint16_t length; /* 0004 */ char text[1]; }; #pragma pack(push, 1) struct GuildMemberKickedPacket { /* 0000 */ std::uint16_t packetType; /* 0002 */ char text[40]; /* 002A */ std::uint32_t characterId; }; struct GuildMemberLeftPacket2 { /* 0000 */ std::uint16_t packetType; /* 0002 */ std::uint32_t characterId; /* 0006 */ char name[30]; }; #pragma pack(pop) // OFFSET: 0x00D48C60 // FUNCTION: fn_21856 void CGameMode::sub_D48C60(const unsigned char* data) { const auto* packet = reinterpret_cast(data); GuildInfo* guildInfo = reinterpret_cast(reinterpret_cast(&g_guildId) - offsetof(GuildInfo, m_guildId)); char reason[41]; std::memcpy(reason, packet->text, sizeof(packet->text)); reason[40] = '\0'; if (packet->characterId == g_session.m_gid) { g_session.ClearShortcutSlots(); g_session.ClearSecondaryShortcutSlots(); g_guildId = 0; g_windowMgr.CloseWindow(59); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(490)), 0xFF, 4, 0, 0); this->SendMsg(172, 0, 0, 0, 0); if (this->scene != nullptr && this->scene->player != nullptr) { this->scene->player->Slot48(0); } guildInfo->ClearUnknown0114(); return; } if (guildInfo->unknown_00C0) { guildInfo->DeleteMemberByCharacterId(static_cast(packet->characterId)); } std::string name = LookupPlayerName(packet->characterId); if (name.empty()) { name = LookupMessage(0x245); } char message[1024]; std::memset(message, 0, sizeof(message)); std::sprintf(message, LookupMessage(0x172), name.c_str()); g_windowMgr.SendNotice(1, reinterpret_cast(message), 0xFFFF, 4, 0, 0); std::memset(message, 0, sizeof(message)); sprintf_s(message, sizeof(message), LookupMessage(0x173), reason); if (g_forbiddenWords.Contains(message) == true) { std::string masked; g_forbiddenWords.Mask(message, &masked); } g_windowMgr.SendNotice(1, reinterpret_cast(message), 0xFFFF, 4, 0, 0); GuildInfo::Unknown00ECEntry entry; entry.name = name; entry.unknown_0034 = reason; guildInfo->AddUnknown00EC(entry); } // OFFSET: 0x00D4A060 // FUNCTION: fn_21861 void CGameMode::sub_D4A060(const unsigned char* data) { const auto* packet = reinterpret_cast(data); GuildInfo* guildInfo = reinterpret_cast(reinterpret_cast(&g_guildId) - offsetof(GuildInfo, m_guildId)); char reason[40]; strcpy_s(reason, sizeof(reason), packet->name); if (packet->characterId == g_session.m_gid) { g_session.ClearShortcutSlots(); g_session.ClearSecondaryShortcutSlots(); guildInfo->Init(); g_windowMgr.CloseWindow(59); g_windowMgr.SendNotice(1, reinterpret_cast(LookupMessage(489)), 0xFF, 4, 0, 0); if (this->scene != nullptr && this->scene->player != nullptr) { this->scene->player->Slot49(0, 0); } this->SendMsg(172, 0, 0, 0, 0); return; } if (guildInfo->unknown_00C0) { guildInfo->DeleteMemberByCharacterId(static_cast(packet->characterId)); } std::string name = packet->characterId == g_session.m_gid ? std::string(g_session.DecodePlayerName()) : LookupPlayerName(packet->characterId); if (name.empty()) { name = LookupMessage(0x245); } char message[1024]; std::sprintf(message, LookupMessage(0x16C), name.c_str()); g_windowMgr.SendNotice(1, reinterpret_cast(message), 0xFFFF, 4, 0, 0); sprintf_s(message, sizeof(message), LookupMessage(0x16D), reason); if (g_forbiddenWords.Contains(message) == true) { std::string masked; g_forbiddenWords.Mask(message, &masked); } g_windowMgr.SendNotice(1, reinterpret_cast(message), 0xFFFF, 4, 0, 0); if (CRenderObject* actor = this->scene->GetGameActorByAID(packet->characterId)) { static_cast(actor)->Slot49(0, 0); } } #pragma pack(push, 1) struct PartyRosterRecord50 { /* 0000 */ std::uint32_t accountId; /* 0004 */ char name[24]; /* 001C */ char mapName[16]; /* 002C */ unsigned char member; /* 002D */ unsigned char offline; /* 002E */ std::int16_t x; /* 0030 */ std::int16_t y; }; #pragma pack(pop) struct PartyRosterListPacket { /* 0000 */ std::uint16_t packetType; /* 0002 */ std::int16_t length; /* 0004 */ char partyName[24]; /* 001C */ PartyRosterRecord50 entries[1]; }; // OFFSET: 0x00D6F900 // FUNCTION: fn_22124 void CGameMode::sub_D6F900(const unsigned char* data) { const auto* packet = reinterpret_cast(data); std::vector members; const int count = (packet->length - 0x1C) / sizeof(PartyRosterRecord50); for (int index = 0; index < count; ++index) { const PartyRosterRecord50& record = packet->entries[index]; PartyRosterEntry entry = {}; entry.accountId = record.accountId; std::memcpy(entry.name, record.name, sizeof(entry.name)); std::memcpy(entry.mapName, record.mapName, sizeof(entry.mapName)); entry.member = record.member; entry.offline = record.offline; entry.x = record.x; entry.y = record.y; members.push_back(entry); } this->sub_D59FD0(reinterpret_cast(packet->partyName), &members); } #pragma pack(push, 1) struct EquipItemUpdatePacket { /* 0000 */ std::int16_t id; /* 0002 */ std::uint16_t itemId; /* 0004 */ unsigned char unknown_0004; /* 0005 */ std::uint32_t cards[4]; /* 0015 */ ItemSlotOption options[5]; /* 002E */ unsigned char refine; /* 002F */ unsigned char unknown_002F; }; #pragma pack(pop) // OFFSET: 0x00D6D850 // FUNCTION: fn_22091 void CGameMode::RefreshInventoryOrEquipItem(std::uint16_t itemId, unsigned char unknownValue, std::uint16_t refine, ItemCardSlots cards, ItemSlotOptions options) { ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, itemId); int lookup = 0; int slot = 0; if (item.unknown_0000[1] == 0) { item = g_session.FindItem17F0(itemId, &slot); lookup = 1; if (item.unknown_0000[1] == 0) { item = g_session.FindItem2B50(itemId, &slot); lookup = 2; } } item.unknown_005D = unknownValue; item.unknown_0060 = refine; std::memcpy(item.unknown_001C, cards.cards, sizeof(cards.cards)); item.unknown_0098 = CountItemSlotOptions(options.options); for (int index = 0; index < item.unknown_0098; ++index) { reinterpret_cast(item.unknown_009C)[index] = options.options[index]; } if (lookup == 0) { g_session.UpdateInventoryItem(item, 1); } else if (lookup == 1) { g_session.SetEquipItem17F0(slot, item); } else if (lookup == 2) { g_session.SetEquipItem2B50(slot, item); } if (UIWindow* window = g_windowMgr.LookupWindow(12)) { window->SendMsg(nullptr, 24, reinterpret_cast(&item), 1, 0, 0); } } // OFFSET: 0x00D6DAE0 // FUNCTION: fn_22092 void CGameMode::RefreshInventoryOrEquipItem2(const unsigned char* data) { const auto* packet = reinterpret_cast(data); ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, packet->itemId); long long lookup = 0; int slot = 0; if (item.unknown_0000[1] == 0) { item = g_session.FindItem17F0(packet->itemId, &slot); lookup = 1; if (item.unknown_0000[1] == 0) { item = g_session.FindItem2B50(packet->itemId, &slot); lookup = 2; } } item.unknown_005D = packet->unknown_0004; item.unknown_0060 = packet->refine; for (long long index = 0; index < 4; ++index) { reinterpret_cast(item.unknown_001C)[index] = packet->cards[index]; } item.unknown_0098 = CountItemSlotOptions(packet->options); for (long long index = 0; index < item.unknown_0098; ++index) { reinterpret_cast(item.unknown_009C)[index] = packet->options[index]; } item.unknown_0088 = packet->unknown_002F; if (lookup == 0) { g_session.UpdateInventoryItem(item, 1); } else if (lookup == 1) { g_session.SetEquipItem17F0(slot, item); } else if (lookup == 2) { g_session.SetEquipItem2B50(slot, item); } if (UIWindow* window = g_windowMgr.LookupWindow(12)) { window->SendMsg(nullptr, 24, reinterpret_cast(&item), 1, 0, 0); } } // OFFSET: 0x00D48530 // FUNCTION: fn_21853 void CGameMode::sub_D48530(const unsigned char* data) { const auto* packet = reinterpret_cast(data); char nameBuffer[24] = {}; StringFormat(nameBuffer, sizeof(nameBuffer), static_cast(-1), "%s", reinterpret_cast(data) + 4); std::string text(reinterpret_cast(data) + 0x20, reinterpret_cast(data) + packet->length); this->sub_D1A520(0, std::string(nameBuffer), text, *reinterpret_cast(data + 0x1C) != 0); } // OFFSET: 0x00D1A330 // FUNCTION: fn_21617 void CGameMode::sub_D1A330(const unsigned char* data) { char nameBuffer[24]; std::memset(nameBuffer, 0, sizeof(nameBuffer)); StringFormat(nameBuffer, sizeof(nameBuffer), static_cast(-1), "%s", reinterpret_cast(data) + 8); const int length = *reinterpret_cast(data + 2) - 0x21; std::string text(reinterpret_cast(data) + 0x21, length > 0 ? static_cast(length) : 0); this->sub_D1A520(static_cast(*reinterpret_cast(data + 4)), std::string(nameBuffer), text, data[0x20] != 0); } #include "Contents/ShowRankingScheduler.h" // OFFSET: 0x00D06760 // FUNCTION: fn_21576 static std::map RankNoticeStyles() { std::map styles; styles.insert({0, {"========== BLACKSMITH RANK ============", 0x9B9B9B, 0xCDCDCD}}); styles.insert({1, {"=========== ALCHEMIST RANK =============", 0x9BCD9B, 0xCDFFCD}}); styles.insert({2, {"============ TAEKWON RANK =============", 0xCD9B9B, 0xFFCDCD}}); styles.insert({3, {"=========== KILLER RANK ==============", 0x9B9B9B, 0xCDCDCD}}); return styles; } #pragma pack(push, 1) struct RankingListPacket { /* 0000 */ std::int16_t id; /* 0002 */ std::int16_t type; /* 0004 */ char names[10][24]; /* 00F4 */ int points[10]; /* 011C */ int myPoint; }; #pragma pack(pop) // OFFSET: 0x00D19390 // FUNCTION: fn_21605 void CGameMode::ReceiveRankingList(const unsigned char* data) { const auto* packet = reinterpret_cast(data); const int kind = packet->type; // GLOBAL: gl_25258 static const std::map styles = RankNoticeStyles(); const char* title; std::uint32_t color; std::uint32_t background; auto style = styles.find(kind); if (style != styles.end()) { background = style->second.background; title = style->second.title; color = style->second.color; } else { title = "==========================================="; background = 0; color = 0; } g_windowMgr.SendNotice(1, reinterpret_cast(title), color, 0, 0, 0); for (int index = 0; index < 10; ++index) { const std::string line = FormatOwnedString("[ %2d ] %-18s : %4d POINT", index + 1, packet->names[index], packet->points[index]); g_windowMgr.SendNotice(1, reinterpret_cast(line.c_str()), background, 0, 0, 0); } g_windowMgr.SendNotice(1, reinterpret_cast("==========================================="), color, 0, 0, 0); const std::string mine = FormatOwnedString("MY POINT : %4d POINT ", packet->myPoint); g_windowMgr.SendNotice(1, reinterpret_cast(mine.c_str()), background, 0, 0, 0); g_windowMgr.SendNotice(1, reinterpret_cast("==========================================="), color, 0, 0, 0); } // OFFSET: 0x00D1A520