rodecomp/Source/Client/Mode/GameModePackets.cpp
ragnarok-clanker d1dbb94673 Decompile fn_21777 (CGameMode::ReceiveZoneServerChange)
Batch #9060 by doczeira: 0 byte-identical, 1 confirmed by peer review.

- fn_21777 CGameMode::ReceiveZoneServerChange: logic confirmed by peer review

Peer-reviewed-by: eAthena, Montyla, pedrao
Accepted without human review: peers confirmed the logic ("same" ahead by at least 3, with 70% of the votes).
2026-11-01 00:13:25 +00:00

7549 lines
241 KiB
C++

#include "Client/Application/Launcher.h"
#include "File/ShortcutFilename.h"
#include "Client/Input/InputCharset.h"
#include "Client/Mode/CGameMode.h"
#include "Client/Mode/EquipWindowLook.h"
#include "UI/UIMacroDetectorWnd.h"
#include "UI/UIMacroBlackListCheckWnd.h"
#include "UI/UILapineScrollBar.h"
#include "UI/UICaptchaPreviewWnd.h"
#include "Client/Mode/ModeMgr.h"
#include "Client/ModeFadeOut.h"
#include "Client/Replay.h"
#include "Client/Session.h"
#include "Contents/Actors/ActorStateFlags.h"
#include "Contents/Actors/GameActor.h"
#include "Contents/Actors/MousePointer.h"
#include "Contents/GuildInfo.h"
#include "Contents/Actors/Pc.h"
#include "Contents/Actors/RenderObject.h"
#include "Contents/CashEmotionMgr.h"
#include "Contents/Configuration/ServiceOptions.h"
#include "Contents/Effects/EffectActor.h"
#include "Contents/Effects/EffectLists.h"
#include "Contents/Effects/RagEffect.h"
#include "Contents/Effects/MonsterSkillEffects.h"
#include "Contents/Skills/ClientSkills.h"
#include "Contents/Configuration/ServiceConfiguration.h"
#include "Contents/Items/ItemDescription.h"
#include "Contents/Items/ItemInfo.h"
#include "Contents/Items/ItemNaming.h"
#include "Contents/MessageTable.h"
#include "Contents/MapSkyMgr.h"
#include "Contents/Messenger/ClientMessenger.h"
#include "Contents/PlayerNameDictionary.h"
#include "Contents/RodexMailStore.h"
#include "Contents/RouletteMgr.h"
#include "Contents/World/World.h"
#include "Contents/Camera/Camera.h"
#include "Network/Connection/Connection.h"
#include "Network/Packets/PacketLengths.h"
#include "Render/RenderSystemBase.h"
#include "Render/Renderer.h"
#include "Render/DeviceContext/DCSurface.h"
#include "Resource/ResourceMgr.h"
#include "Network/TextEncoding.h"
#include "UI/Item/UIItemStoreWnd.h"
#include "UI/Text/UIStaticText.h"
#include "UI/Cooldowns/CooldownOwner.h"
#include "UI/UIBarGraph.h"
#include "UI/Window/UIHomunInfoWnd.h"
#include "Contents/Sound/SoundMgr.h"
#include "UI/Status/UIStatusWnd.h"
#include "UI/Window/UIBasicInfoWnd.h"
#include "UI/Shop/UIMerchantItemMyShopWnd.h"
#include "UI/Shop/UIMerchantShopMakeWnd.h"
#include "UI/Shop/UIMerchantItemShopWnd.h"
#include "UI/Window/UIWindow.h"
#include "UI/Window/UIWindowMgr.h"
#include "UI/Dialogs/UIWaitWnd.h"
#include "UI/Window/WindowDialogs.h"
#include "Utility/Math/Vector3d.h"
#include "Utility/Text/FormatString.h"
#include "Utility/Text/StringUtil.h"
#include "Contents/GuildMgr.h"
#include "Contents/EnchantMgr.h"
#include "Contents/Items/ItemReformMgr.h"
#include "Contents/ReputeMgr.h"
#include "Contents/RenewQuestMgr.h"
#include "Contents/Items/BarterMarketItemMgr.h"
#include "Contents/Skills/SkillInfo.h"
#include "Contents/Schedule/CheckGDISchedule.h"
#include "Contents/Schedule/EmotionSchedule.h"
#include "Contents/Schedule/TimeScheduler.h"
#include <direct.h>
#include <io.h>
#include <timeapi.h>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <string>
#include <vector>
#include <xtimec.h>
// OFFSET: 0x00D7AF70
// FUNCTION: fn_22198
void CGameMode::ReceiveItemDisappear(std::uint32_t itemAid) {
if (this->scene->RemoveItem(itemAid)) {
this->SendMsg(13, static_cast<int>(itemAid), 0, 0, 0);
}
}
struct SessionMessengerContext {
void UpdateRandomStats();
int GetList9Size() const;
void KeepEquipment();
void ResetEquipment();
void ResetSlots();
};
struct SessionItemLists {
void ClearTradeItems();
void RemoveEquipment();
};
#pragma pack(push, 1)
struct TradeItemRecord {
/* 0000 */ int itemId;
/* 0004 */ unsigned char unknown_0004;
/* 0005 */ int unknown_0005;
/* 0009 */ int quantity;
/* 000D */ std::uint16_t unknown_000D;
/* 000F */ unsigned char unknown_000F;
/* 0010 */ std::uint32_t cards[4];
/* 0020 */ std::uint16_t unknown_0020;
};
#pragma pack(pop)
#if defined(_WIN32) && !defined(_WIN64)
static_assert(sizeof(TradeItemRecord) == 0x22);
#endif
struct ClientItemLists {
bool AddItem1738(const ITEM_INFO& item, unsigned char refresh);
bool AddItem1740(const ITEM_INFO& item);
void AddItem1758(const ITEM_INFO& item);
void AddItem1718(const RawItemBasic& item, int quantity, std::uint16_t unknown_006C);
void AppendItem1718(const ITEM_INFO& item);
void AddItem1748(const ITEM_INFO& item);
void RemoveItem1758(ITEM_INFO& item);
void RemoveItem1758ByItemId(ITEM_INFO& item);
void ClearItems1768();
void ClearItems1760And1748();
void ClearItems1758();
void ClearItems1760();
void ClearItems1748();
void ResetEquipped();
bool Equip(const ITEM_INFO& item);
void RemoveItem1710(std::uint32_t id, int quantity);
bool AddItem1710(const ITEM_INFO& item, unsigned char refresh);
bool EquipItem6B68(const ITEM_INFO& item);
};
void __fastcall sub_DFF150(CSession* session);
// GLOBAL: gl_24992
char g_pendingWhisperCount;
// GLOBAL: gl_25102
int g_whisperRecord;
// GLOBAL: gl_25097
UIWindow* g_saleOpenWindow;
// GLOBAL: gl_25098
UIWindow* g_saleResultWindow;
// GLOBAL: gl_25099
UIWindow* g_vendingOpenWindow;
// GLOBAL: gl_25100
UIWindow* g_vendingOpenResultWindow;
namespace {
#pragma pack(push, 1)
struct SimulationPacketHeader {
/* 0000 */ std::uint16_t packetType;
/* 0002 */ std::uint16_t length;
/* 0004 */ std::uint32_t unknown_0004;
/* 0008 */ int value;
/* 000C */ unsigned char unknown_000C[0x18];
};
struct EnchantSimulationRecord {
/* 0000 */ int itemId;
/* 0004 */ int resultItemId;
/* 0008 */ std::uint32_t unknown_0008[2];
/* 0010 */ int rate;
/* 0014 */ std::uint32_t unknown_0014;
/* 0018 */ int count;
};
struct PackageSimulationRecord {
/* 0000 */ int itemId;
/* 0004 */ unsigned char refine;
/* 0005 */ unsigned char packageType;
/* 0006 */ int unknown_0006;
/* 000A */ int unknown_000A;
/* 000E */ char text[24];
/* 0026 */ int unknown_0026;
/* 002A */ int unknown_002A;
/* 002E */ int count;
};
struct NamedProgressPacket {
/* 0000 */ std::uint16_t packetType;
/* 0002 */ unsigned char result;
/* 0003 */ int first;
/* 0007 */ int second;
/* 000B */ std::uint16_t current;
/* 000D */ std::uint16_t total;
/* 000F */ unsigned char unknown_000F[4];
/* 0013 */ char name[1];
};
struct PacketLengthHeader {
/* 0000 */ std::uint16_t packetType;
/* 0002 */ std::int16_t length;
};
struct Item1740Record {
/* 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 unknown_000C;
/* 000D */ unsigned char refine;
/* 000E */ std::uint32_t cards[4];
/* 001E */ std::uint32_t expireTime;
};
struct Item1740EquipRecord {
/* 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 unknown_000C;
/* 000D */ unsigned char refine;
/* 000E */ std::uint32_t cards[4];
/* 001E */ std::uint32_t expireTime;
/* 0022 */ std::uint16_t bindOnEquip;
/* 0024 */ std::uint16_t sprite;
};
struct ItemStoreListHeader {
/* 0000 */ std::uint16_t packetType;
/* 0002 */ std::uint16_t length;
/* 0004 */ char title[24];
};
struct StoreItemOption {
/* 0000 */ std::int16_t id;
/* 0002 */ std::int16_t value;
/* 0004 */ unsigned char param;
};
struct StoreEquipRecord {
/* 0000 */ std::int16_t index;
/* 0002 */ int itemId;
/* 0006 */ unsigned char type;
/* 0007 */ std::uint32_t location;
/* 000B */ std::uint32_t wearState;
/* 000F */ unsigned char refine;
/* 0010 */ std::uint32_t cards[4];
/* 0020 */ std::uint32_t expireTime;
/* 0024 */ std::uint16_t bindOnEquip;
/* 0026 */ std::uint16_t sprite;
/* 0028 */ unsigned char flags;
};
struct StoreEquipOptionRecord {
/* 0000 */ std::int16_t index;
/* 0002 */ int itemId;
/* 0006 */ unsigned char type;
/* 0007 */ std::uint32_t location;
/* 000B */ std::uint32_t wearState;
/* 000F */ unsigned char refine;
/* 0010 */ std::uint32_t cards[4];
/* 0020 */ std::uint32_t expireTime;
/* 0024 */ std::uint16_t bindOnEquip;
/* 0026 */ std::uint16_t sprite;
/* 0028 */ unsigned char optionCount;
/* 0029 */ StoreItemOption options[5];
/* 0042 */ unsigned char flags;
};
struct StoreNormalRecord {
/* 0000 */ std::int16_t index;
/* 0002 */ int itemId;
/* 0006 */ unsigned char type;
/* 0007 */ std::int16_t amount;
/* 0009 */ std::uint32_t location;
/* 000D */ std::uint32_t cards[4];
/* 001D */ std::uint32_t expireTime;
/* 0021 */ unsigned char flags;
};
struct HomunculusProperty64Packet {
/* 0000 */ std::uint16_t packetType;
/* 0002 */ std::uint16_t type;
/* 0004 */ std::int64_t value;
};
struct HomunculusPropertyPacket {
/* 0000 */ std::uint16_t packetType;
/* 0002 */ std::uint16_t type;
/* 0004 */ int value;
};
struct ValuePacket {
/* 0000 */ std::int16_t id;
/* 0002 */ int value;
};
struct ChatTextEntry {
/* 0000 */ char text[16];
};
struct ChatEntryListPacket {
/* 0000 */ std::uint16_t packetType;
/* 0002 */ std::int16_t length;
/* 0004 */ std::uint16_t unknown_0004;
/* 0006 */ ChatTextEntry entries[1];
};
struct ActorValuePacket {
/* 0000 */ std::uint16_t id;
/* 0002 */ std::uint32_t accountId;
/* 0006 */ short value;
};
struct ActorSkillMessage {
/* 0000 */ int unknown_0000;
/* 0004 */ int unknown_0004;
/* 0008 */ int unknown_0008;
/* 000C */ int unknown_000C;
/* 0010 */ int unknown_0010;
/* 0014 */ int unknown_0014;
/* 0018 */ int unknown_0018;
/* 001C */ int unknown_001C;
/* 0020 */ int unknown_0020;
/* 0024 */ int unknown_0024;
/* 0028 */ int unknown_0028;
};
struct DispelPacket {
/* 0000 */ std::int16_t id;
/* 0002 */ std::uint32_t aid;
};
struct DevotionListPacket {
/* 0000 */ std::int16_t id;
/* 0002 */ std::uint32_t aid;
/* 0006 */ std::uint32_t devotees[5];
/* 001A */ std::int16_t range;
};
struct FormatStringMessagePacket {
/* 0000 */ std::int16_t id;
/* 0002 */ std::int16_t length;
/* 0004 */ std::uint16_t messageId;
};
struct NotifyExpPacket {
/* 0000 */ std::int16_t packetType;
/* 0002 */ std::uint32_t accountId;
/* 0006 */ int amount;
/* 000A */ std::uint16_t varId;
/* 000C */ std::int16_t expType;
};
struct Item1758Record {
/* 0000 */ std::int32_t price;
/* 0004 */ std::int16_t quantity;
/* 0006 */ unsigned char type;
/* 0007 */ std::int32_t itemId;
};
struct Item1758StoreRecord {
/* 0000 */ std::uint32_t unknown_0000;
/* 0004 */ std::int16_t index;
/* 0006 */ std::int16_t amount;
/* 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 */ StoreItemOption options[5];
};
struct Item1718Record {
/* 0000 */ std::int32_t itemId;
/* 0004 */ unsigned char type;
/* 0005 */ std::uint32_t unknown_0005;
/* 0009 */ std::int32_t quantity;
/* 000D */ std::uint16_t unknown_000D;
/* 000F */ std::uint32_t unknown_000F;
};
struct Item1748Record {
/* 0000 */ std::uint32_t unknown_0000;
/* 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 */ StoreItemOption options[5];
/* 0039 */ std::int32_t unknown_0039;
/* 003D */ std::uint16_t sprite;
};
#pragma pack(pop)
static_assert(sizeof(ItemStoreListHeader) == 0x1C);
static_assert(sizeof(StoreEquipRecord) == 0x29);
static_assert(sizeof(StoreEquipOptionRecord) == 0x43);
static_assert(sizeof(StoreNormalRecord) == 0x22);
static_assert(sizeof(PacketLengthHeader) == 0x04);
static_assert(sizeof(Item1740Record) == 0x22);
static_assert(sizeof(Item1740EquipRecord) == 0x26);
static_assert(sizeof(ValuePacket) == 0x06);
static_assert(sizeof(ChatTextEntry) == 0x10);
static_assert(sizeof(ChatEntryListPacket) == 0x16);
static_assert(sizeof(ActorValuePacket) == 0x08);
// INLINED
int CountStoreItemOptions(const StoreItemOption* options) {
int count = 0;
for (int index = 0; index < 5; ++index) {
if (options[index].id != 0) {
++count;
}
}
return count;
}
static_assert(sizeof(DispelPacket) == 6);
static_assert(sizeof(DevotionListPacket) == 0x1C);
static_assert(sizeof(FormatStringMessagePacket) == 6);
static_assert(sizeof(NotifyExpPacket) == 0xE);
static_assert(sizeof(Item1758Record) == 0xB);
static_assert(sizeof(Item1758StoreRecord) == 0x39);
static_assert(sizeof(Item1718Record) == 0x13);
static_assert(sizeof(Item1748Record) == 0x3F);
static_assert(sizeof(SimulationPacketHeader) == 0x24);
static_assert(sizeof(EnchantSimulationRecord) == 0x1C);
static_assert(sizeof(PackageSimulationRecord) == 0x32);
}
// OFFSET: 0x00D1F540
// FUNCTION: fn_21638
void CGameMode::IgnoreRemovedPacket3(const unsigned char*) {
}
// OFFSET: 0x00D208F0
// FUNCTION: fn_21649
void CGameMode::IgnoreRemovedPacket4(const unsigned char*) {
}
// OFFSET: 0x00D21210
// FUNCTION: fn_21653
void CGameMode::IgnoreRemovedPacket5(const unsigned char*) {
}
// OFFSET: 0x00D21D00
// FUNCTION: fn_21657
void CGameMode::ReceiveUnknown05C4Result(const unsigned char* data) {
const auto* packet = reinterpret_cast<const NamedProgressPacket*>(data);
char message[256];
char name[51] = {};
std::sprintf(name, "%s", packet->name);
this->unknown_05C4 = -1;
this->unknown_05C8 = -1;
switch (packet->result) {
case 0:
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(1223)), 0xFFFFFF, 0, 0, 0);
g_windowMgr.SendNotice(19, reinterpret_cast<std::intptr_t>(LookupMessage(1223)), 0xFFFFFF, 0, 0, 0);
return;
case 1:
case 2:
this->unknown_05C4 = packet->first;
this->unknown_05C8 = packet->second;
if (packet->result != 2) {
return;
}
std::sprintf(message, LookupMessage(1225), name);
break;
case 3:
if (packet->current == 0 && packet->total == 1) {
std::sprintf(message, LookupMessage(1261), name);
} else {
std::sprintf(message, LookupMessage(1224), name, packet->current, packet->total);
}
break;
default:
return;
}
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0xFFFFFF, 0, 0, 0);
g_windowMgr.SendNotice(19, reinterpret_cast<std::intptr_t>(message), 0xFFFFFF, 0, 0, 0);
}
// OFFSET: 0x00D230E0
// FUNCTION: fn_21660
void CGameMode::ReceiveColoredNotice(const unsigned char* packet) {
std::string text;
text.assign(reinterpret_cast<const char*>(packet + 9), *reinterpret_cast<const short*>(packet + 2) - 9);
if (!text.empty()) {
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.c_str()), *reinterpret_cast<const std::uint32_t*>(packet + 5), packet[4], 0, 0);
}
}
// OFFSET: 0x00D1D690
// FUNCTION: fn_21630
void CGameMode::ReceiveNamedActionResult(const unsigned char* packet) {
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
const std::string name = reinterpret_cast<const char*>(packet + 2);
const int result = *reinterpret_cast<const int*>(packet + 0x1A);
switch (result) {
case 0:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x50)), 0xFF, 0, 0, 0);
break;
case 1: {
const std::string text = name + LookupMessage(0x80C);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.c_str()), 0xFF, 0, 0, 0);
break;
}
case 2: {
const std::string text = name + LookupMessage(0x80D);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.c_str()), 0xFFFF00, 0, 0, 0);
break;
}
case 3:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x53)), 0xFF, 0, 0, 0);
break;
case 4:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x260)), 0xFF, 0, 0, 0);
break;
}
switch (result) {
case 5:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x52C)), 0xFF, 0, 0, 0);
break;
case 7:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x47)), 0xFF, 0, 0, 0);
break;
case 8: {
char text[256];
std::sprintf(text, LookupMessage(0x56C), reinterpret_cast<const char*>(packet + 2));
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFF, 0, 0, 0);
break;
}
case 9:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x74F)), 0xFF, 0, 0, 0);
break;
case 10:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xBD3)), 0xFF, 0, 0, 0);
break;
case 11:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xC9A)), 0xFF, 0, 0, 0);
break;
case 18:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xE32)), 0xFF, 0, 0, 0);
break;
}
}
// OFFSET: 0x00D1E610
// FUNCTION: fn_21634
void CGameMode::ReceiveStatDump(const unsigned char* packet) {
char text[256];
const short* values = reinterpret_cast<const short*>(packet);
std::sprintf(
text, " STR=%3d AGI=%3d VIT=%3d INT=%3d DEX=%3d LUK=%d", packet[2], packet[4], packet[6], packet[8], packet[10], packet[12]
);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
std::sprintf(
text, "standard STR=%3d AGI=%3d VIT=%3d INT=%3d DEX=%3d LUK=%2d", packet[3], packet[5], packet[7], packet[9], packet[11], packet[13]
);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFF37, 0, 0, 0);
std::sprintf(
text, " attPower=%3d refiningPow=%3d MAXmatPow=%3d MINmatPower=%3d ASPD=%3d", values[7], values[8], values[9], values[10], values[19]
);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
std::sprintf(
text, "itemdefPow=%3d plusdefPow=%3d mdefPower=%3d plusmdefPow=%3d plusASPD=%3d", values[11], values[12], values[13], values[14], values[20]
);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFF37, 0, 0, 0);
std::sprintf(text, "hitSuccessVal=%3d avoidSuccessVal=%3d plusAvoidSuccessValue=%3d", values[15], values[16], values[17]);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
}
// OFFSET: 0x00D24430
// FUNCTION: fn_21666
void CGameMode::ReceiveActorText(const unsigned char* packet) {
char text[81];
std::strncpy(text, reinterpret_cast<const char*>(packet + 6), 80);
text[80] = '\0';
if (CRenderObject* actor = this->scene->GetGameActorByAID(*reinterpret_cast<const std::uint32_t*>(packet + 2))) {
const std::int64_t value = reinterpret_cast<std::intptr_t>(text);
actor->SendMsg(nullptr, 141, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
// OFFSET: 0x00D25920
// FUNCTION: fn_21674
void CGameMode::ReceiveRentalItemTime(const unsigned char* packet) {
char number[12];
char text[260];
_itoa(*reinterpret_cast<const int*>(packet + 2), number, 10);
const ITEM_DESC& description = FindItemDescription(std::atoi(number));
const std::uint32_t seconds = *reinterpret_cast<const std::uint32_t*>(packet + 6);
const char* name = description.identifiedName;
const int minutes = static_cast<int>(seconds / 60);
if (minutes > 0) {
std::sprintf(text, LookupMessage(1256), name, minutes);
} else {
std::sprintf(text, LookupMessage(1270), name, seconds);
}
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
g_windowMgr.SendNotice(19, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
if (minutes == 1) {
std::sprintf(text, LookupMessage(1257), name);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
g_windowMgr.SendNotice(19, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
}
}
// OFFSET: 0x00D264E0
// FUNCTION: fn_21679
void CGameMode::ReceiveUnknownD264E0(const unsigned char* packet) {
if (UIWindow* window = g_windowMgr.unknown_01F0) {
window->SendMsg(nullptr, 32, 0, 0, 0, 0);
window->SendMsg(nullptr, 63, 0, 0, 0, 0);
} else {
this->unknown_024C = 0;
this->unknown_02DC = *reinterpret_cast<const int*>(packet + 2);
g_windowMgr.CloseWindow(16);
g_windowMgr.CloseWindow(17);
g_windowMgr.CloseWindow(226);
}
if (UIWindow* window = g_windowMgr.unknown_01F4) {
window->SendMsg(nullptr, 32, 0, 0, 0, 0);
window->SendMsg(nullptr, 63, 0, 0, 0, 0);
} else {
this->unknown_024C = 0;
this->unknown_02DC = *reinterpret_cast<const int*>(packet + 2);
g_windowMgr.CloseWindow(226);
g_windowMgr.CloseWindow(17);
g_windowMgr.CloseWindow(226);
}
}
// OFFSET: 0x00D26600
// FUNCTION: fn_21680
void CGameMode::ReceiveActorSequenceDeadline(const unsigned char* packet) {
g_session.InsertPair(*reinterpret_cast<const int*>(packet + 2), *reinterpret_cast<const int*>(packet + 6));
const std::uint32_t aid = *reinterpret_cast<const std::uint32_t*>(packet + 2);
if (aid == g_session.m_aid) {
this->scene->player->SetSequenceDeadline(*reinterpret_cast<const std::uint32_t*>(packet + 6));
return;
}
if (CRenderObject* actor = this->scene->GetGameActorByAID(aid)) {
actor->SetSequenceDeadline(*reinterpret_cast<const std::uint32_t*>(packet + 6));
}
}
// OFFSET: 0x00D26E50
// FUNCTION: fn_21685
void CGameMode::ReceiveDevotionList(const unsigned char* packet) {
const auto* list = reinterpret_cast<const DevotionListPacket*>(packet);
if (!g_serviceOptions.Get(8)) {
return;
}
CGameActor* actor;
if (list->aid == g_session.m_aid) {
actor = this->scene->player;
} else {
actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(list->aid));
}
if (actor != nullptr) {
for (int index = 0; index < 5; ++index) {
actor->SendMsg(nullptr, 109, 0, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
for (int index = 0; index < 5; ++index) {
if (list->devotees[index] == 0) {
continue;
}
vector3d position{static_cast<float>(list->aid), static_cast<float>(list->devotees[index]), 0.0f};
if (position.y == position.y && position.x == position.x) {
if (actor != nullptr) {
CRagEffect* effect = actor->LaunchEffect(232, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
if (effect != nullptr) {
effect->SendMsg(nullptr, 14, 0, reinterpret_cast<int>(&position), 0, 0, 0, 0);
}
}
} else {
char message[256];
sprintf(message, "DEVOTION OVERFLOW : %d -- %d , %d , %d , %d , %d", list->aid, list->devotees[0], list->devotees[1], list->devotees[2],
list->devotees[3], list->devotees[4]);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0x3232FA, 0, 0, 0);
sprintf(message, "DEVOTION OVERFLOW : 그라비티에 메일로 문의해주십시요");
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0x3232FA, 0, 0, 0);
}
}
}
// OFFSET: 0x00D27060
// FUNCTION: fn_21686
void CGameMode::ReceiveActorSignal(const unsigned char* packet) {
if (CRenderObject* actor = this->scene->GetGameActorByAID(*reinterpret_cast<const std::uint32_t*>(packet + 2))) {
actor->SendMsg(nullptr, 142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
// OFFSET: 0x00D2A990
// FUNCTION: fn_21705
void CGameMode::ReceiveFormatStringMessage(const unsigned char* packet) {
const auto* message = reinterpret_cast<const FormatStringMessagePacket*>(packet);
const char* format = LookupMessage(message->messageId);
int count = 0;
const char* cursor = format;
while (*cursor != '\0') {
if (IsDBCSLeadByte(*cursor)) {
cursor += 2;
} else if (cursor[0] == '%' && cursor[1] == 's') {
++count;
cursor += 2;
} else {
++cursor;
}
}
char text[261];
std::memset(text, 0, sizeof(text));
const char* first = reinterpret_cast<const char*>(message + 1);
switch (count) {
case 0:
_snprintf(text, 260, format);
break;
case 1:
_snprintf(text, 260, format, first);
break;
case 2: {
const char* second = first + std::strlen(first) + 1;
_snprintf(text, 260, format, first, second);
break;
}
case 3: {
const char* second = first + std::strlen(first) + 1;
const char* third = second + std::strlen(second) + 1;
_snprintf(text, 260, format, first, second, third);
break;
}
default:
sprintf(text, "unknown argment list");
return;
}
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFFFF, 0, 0, 0);
}
// OFFSET: 0x00D2AF90
// FUNCTION: fn_21707
void CGameMode::IgnorePacket(const unsigned char*) {
}
// OFFSET: 0x00D2B710
// FUNCTION: fn_21710
void CGameMode::ReceiveItem1738EquipList(const unsigned char* data) {
const ItemStoreListHeader* packet = reinterpret_cast<const ItemStoreListHeader*>(data);
UIItemStoreWnd* window = static_cast<UIItemStoreWnd*>(g_windowMgr.EnsureWindow(33));
if (packet->title[0] != '\0') {
std::string title(packet->title);
window->title->SetTextFitted(title.c_str());
}
const int count = (packet->length - sizeof(ItemStoreListHeader)) / sizeof(StoreEquipRecord);
const StoreEquipRecord* record = reinterpret_cast<const StoreEquipRecord*>(data + sizeof(ItemStoreListHeader));
for (int i = 0; i < count; ++i, ++record) {
StoreItemOption options[5] = {};
ITEM_INFO item;
item.unknown_0000[0] = record->type;
item.unknown_0000[1] = record->index;
item.unknown_0000[2] = record->location;
item.unknown_0000[3] = record->wearState;
item.quantity = 1;
std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards));
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;
*reinterpret_cast<std::uint32_t*>(item.unknown_0074) = record->sprite;
*reinterpret_cast<unsigned char*>(item.unknown_0078) = (record->flags >> 2) & 1;
item.unknown_0098 = CountStoreItemOptions(options);
for (int index = 0; index < item.unknown_0098; ++index) {
reinterpret_cast<StoreItemOption*>(item.unknown_009C)[index] = options[index];
}
reinterpret_cast<ClientItemLists*>(&g_session)->AddItem1738(item, 1);
}
g_session.RefreshItem1738Window();
}
// OFFSET: 0x00D2BA50
// FUNCTION: fn_21711
void CGameMode::ReceiveItem1738EquipListOptions(const unsigned char* data) {
const ItemStoreListHeader* packet = reinterpret_cast<const ItemStoreListHeader*>(data);
UIItemStoreWnd* window = static_cast<UIItemStoreWnd*>(g_windowMgr.EnsureWindow(33));
if (packet->title[0] != '\0') {
std::string title(packet->title);
window->title->SetTextFitted(title.c_str());
}
const int count = (packet->length - sizeof(ItemStoreListHeader)) / sizeof(StoreEquipOptionRecord);
const StoreEquipOptionRecord* record = reinterpret_cast<const StoreEquipOptionRecord*>(data + sizeof(ItemStoreListHeader));
for (int i = 0; i < count; ++i, ++record) {
StoreItemOption options[5];
std::memcpy(options, record->options, sizeof(options));
ITEM_INFO item;
item.unknown_0000[0] = record->type;
item.unknown_0000[1] = record->index;
item.unknown_0000[2] = record->location;
item.unknown_0000[3] = record->wearState;
item.quantity = 1;
std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards));
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;
*reinterpret_cast<std::uint32_t*>(item.unknown_0074) = record->sprite;
*reinterpret_cast<unsigned char*>(item.unknown_0078) = (record->flags >> 2) & 1;
item.unknown_0098 = CountStoreItemOptions(options);
for (int index = 0; index < item.unknown_0098; ++index) {
reinterpret_cast<StoreItemOption*>(item.unknown_009C)[index] = options[index];
}
reinterpret_cast<ClientItemLists*>(&g_session)->AddItem1738(item, 1);
}
g_session.RefreshItem1738Window();
}
// OFFSET: 0x00D2BDF0
// FUNCTION: fn_21712
void CGameMode::ReceiveItem1738NormalList(const unsigned char* data) {
const ItemStoreListHeader* packet = reinterpret_cast<const ItemStoreListHeader*>(data);
UIItemStoreWnd* window = static_cast<UIItemStoreWnd*>(g_windowMgr.EnsureWindow(33));
if (packet->title[0] != '\0') {
std::string title(packet->title);
window->title->SetTextFitted(title.c_str());
}
const int count = (packet->length - sizeof(ItemStoreListHeader)) / sizeof(StoreNormalRecord);
const StoreNormalRecord* record = reinterpret_cast<const StoreNormalRecord*>(data + sizeof(ItemStoreListHeader));
for (int i = 0; i < count; ++i, ++record) {
ITEM_INFO item;
item.unknown_0000[0] = record->type;
item.unknown_0000[1] = record->index;
item.unknown_0000[3] = record->location;
item.unknown_0000[2] = 0;
item.quantity = record->amount;
std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards));
item.SetItemId(record->itemId);
item.identified = record->flags & 1;
item.unknown_005D = 0;
item.unknown_0060 = 0;
item.unknown_0068 = record->expireTime;
item.unknown_0074[0] = (record->flags >> 1) & 1;
reinterpret_cast<ClientItemLists*>(&g_session)->AddItem1738(item, 0);
}
g_session.RefreshItem1738Window();
}
// OFFSET: 0x00D2C190
// FUNCTION: fn_21713
void CGameMode::ReceiveHomunculusProperty64(const unsigned char* data) {
if (!data) {
return;
}
const HomunculusProperty64Packet* packet = reinterpret_cast<const HomunculusProperty64Packet*>(data);
switch (packet->type) {
case 1:
g_session.m_homunExp = packet->value;
g_session.RefreshHomunculusInfo();
if (UIHomunInfoWnd* window = static_cast<UIHomunInfoWnd*>(g_windowMgr.window_03C0)) {
window->expBar->SetValues(g_session.m_homunExp, g_session.m_homunMaxExp);
}
break;
case 5:
g_session.m_homunHp = static_cast<int>(packet->value);
g_session.RefreshHomunculusInfo();
break;
case 7:
g_session.m_homunSp = static_cast<int>(packet->value);
g_session.RefreshHomunculusInfo();
break;
}
g_session.RefreshHomunculusInfo();
}
// OFFSET: 0x00D2C250
// FUNCTION: fn_21714
void CGameMode::ReceiveHomunculusProperty(const unsigned char* data) {
const HomunculusPropertyPacket* packet = reinterpret_cast<const HomunculusPropertyPacket*>(data);
switch (packet->type) {
case 5:
g_session.m_homunHp = packet->value;
g_session.RefreshHomunculusInfo();
break;
case 7:
g_session.m_homunSp = packet->value;
g_session.RefreshHomunculusInfo();
break;
case 1:
g_session.m_homunExp = packet->value;
g_session.RefreshHomunculusInfo();
break;
}
g_session.RefreshHomunculusInfo();
}
// OFFSET: 0x00D2C2B0
// FUNCTION: fn_21715
void CGameMode::ReceiveHuntingList(const unsigned char* packet) {
char text[256];
int size = *reinterpret_cast<const short*>(packet + 2) - 4;
if (size > 5000) {
size = 5000;
}
char* list = new char[size + 1];
std::memcpy(list, packet + 4, size);
list[size] = '\0';
std::sprintf(text, "=========== HUNTING LIST =============");
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0x9BCD9B, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(list), 0xCDFFCD, 0, 0, 0);
std::sprintf(text, "========================================");
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0x9BCD9B, 0, 0, 0);
}
// OFFSET: 0x00D2F150
// FUNCTION: fn_21728
bool CGameMode::NotifyItemResult(int result) {
int message;
switch (result) {
case 1:
case 6:
message = 53;
break;
case 2:
message = 52;
break;
case 4:
message = 220;
break;
case 5:
message = 279;
break;
case 7:
message = 1418;
break;
case 9:
message = 3984;
break;
default:
return false;
}
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(message)), 0xFF, 0, 0, 0);
return true;
}
// OFFSET: 0x00D4B2C0
// FUNCTION: fn_21864
void CGameMode::ReceiveEquipAck(const unsigned char* packet) {
switch (*reinterpret_cast<const short*>(packet + 2)) {
case 0:
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(242)), 0xFF, 0, 0, 0);
break;
case 1:
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(243)), 0xFFFF64, 0, 0, 0);
break;
case 2:
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(244)), 0xFFFF64, 0, 0, 0);
break;
case 3:
switch (g_session.GetDisplayJob()) {
case 12:
case 4013:
case 4035:
case 4059:
case 4065:
case 4101:
case 4254:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(1040)), 0xFFFF64, 0, 0, 0);
break;
case 24:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(1175)), 0xFFFF64, 0, 0, 0);
break;
case 25:
case 4222:
break;
default:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(245)), 0xFFFF64, 0, 0, 0);
break;
}
break;
}
}
// OFFSET: 0x00D58970
// FUNCTION: fn_21955
std::string CGameMode::MakeSimulatorFolder(const std::string& folder) {
std::string path = g_applicationDirectory + folder;
if (_access(path.c_str(), 0) != 0 && _mkdir(path.c_str()) != 0) {
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(FormatOwnedString("Create Folder Fail!!! %s", path.c_str()).c_str()), 0xFF, 0, 0, 0);
return std::string();
}
return path;
}
// OFFSET: 0x00D58B20
// FUNCTION: fn_21956
std::FILE* CGameMode::OpenPackageSimulatorFile(const std::string& folder, int itemId, std::string& itemName) {
std::string directory = this->MakeSimulatorFolder(folder);
if (directory.size() == 0) {
return nullptr;
}
itemName = FindItemDescription(itemId).identifiedName;
SYSTEMTIME time;
GetLocalTime(&time);
std::string name = FormatOwnedString("%s_%d(%d_%d_%d)", itemName.c_str(), itemId, time.wYear, time.wMonth, time.wDay);
std::string path = FormatOwnedString("%s\\%s.txt", directory.c_str(), name.c_str());
int index = 0;
while (_access(path.c_str(), 0) == 0) {
++index;
path = FormatOwnedString("%s\\%s_%d.txt", directory.c_str(), name.c_str(), index);
}
std::FILE* file = _wfopen(DecodeText(g_textCodePage, path).c_str(), L"w");
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(FormatOwnedString("Simulator Result File Create %s %d!!!!!!!!!!!!", file ? "success" : "Fail", itemId).c_str()),
file ? 0xFFFF : 0xFF, 0, 0, 0);
return file;
}
// OFFSET: 0x00D58D80
// FUNCTION: fn_21957
std::FILE* CGameMode::OpenSimulatorFile(const std::string& folder, const std::string& name) {
std::string directory = this->MakeSimulatorFolder(folder);
if (directory.size() == 0) {
return nullptr;
}
std::string path = FormatOwnedString("%s\\%s.txt", directory.c_str(), name.c_str());
int index = 0;
while (_access(path.c_str(), 0) == 0) {
++index;
path = FormatOwnedString("%s\\%s_%d.txt", directory.c_str(), name.c_str(), index);
}
std::FILE* file = _wfopen(DecodeText(g_textCodePage, path).c_str(), L"w");
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(FormatOwnedString("%s Simulator File Create %s !!!!!!!!!!!!", name.c_str(), file ? "success" : "Fail").c_str()),
file ? 0xFFFF : 0xFF, 0, 0, 0);
return file;
}
// OFFSET: 0x00D5F830
// FUNCTION: fn_21971
void CGameMode::ReceiveRandomUpgradeSimulation(const unsigned char* packet) {
const SimulationPacketHeader* header = reinterpret_cast<const SimulationPacketHeader*>(packet);
std::string itemName;
SYSTEMTIME time;
GetLocalTime(&time);
std::string name = FormatOwnedString("%d_EnchantUpgradeTest_Slot_%d(%d_%d_%d)", header->value / 10, header->value % 10, time.wYear, time.wMonth, time.wDay);
std::FILE* file = this->OpenSimulatorFile("\\PackageItemTest", name);
if (!file) {
return;
}
const EnchantSimulationRecord* record = reinterpret_cast<const EnchantSimulationRecord*>(packet + sizeof(SimulationPacketHeader));
int total = 0;
const int count = static_cast<int>((header->length - sizeof(SimulationPacketHeader)) / sizeof(EnchantSimulationRecord));
std::fprintf(file, "\n- %s\n\n", ToUtf8(name, g_textCodePage).c_str());
std::fprintf(file, "============================\tSTART\t============================\n");
for (int i = 0; i < count; ++i) {
ITEM_INFO item;
item.SetItemId(record->itemId);
item.identified = 1;
item.unknown_0000[0] = 0x15;
ITEM_INFO result;
result.SetItemId(record->resultItemId);
result.identified = 1;
result.unknown_0000[0] = 0x15;
ItemDescriptions descriptions{g_itemDescriptions};
bool languagePrefix = false;
WORD language = g_serverLanguage->language;
ItemNaming naming{descriptions, g_itemCardNames, *g_playerNameDictionary, languagePrefix, g_serviceType, language};
std::fprintf(file, "\t\t%s\t%s\t%d\t\t%.5f%%\n", ToUtf8(naming.DisplayName(item, 0), g_textCodePage).c_str(),
ToUtf8(naming.DisplayName(result, 0), g_textCodePage).c_str(), record->count, static_cast<float>(record->rate) / 1000.0f);
total += record->count;
++record;
}
std::fprintf(file, "Try\t%d\tRandomUpgrade\n", total);
std::fprintf(file, "============================\tEND\t============================\n");
std::fclose(file);
}
// OFFSET: 0x00D5FC60
// FUNCTION: fn_21972
void CGameMode::ReceiveEnchantSimulation(const unsigned char* packet) {
const SimulationPacketHeader* header = reinterpret_cast<const SimulationPacketHeader*>(packet);
std::string itemName;
SYSTEMTIME time;
GetLocalTime(&time);
std::string name = FormatOwnedString("%d_EnchantTest_Slot_%d(%d_%d_%d)", header->value / 100, header->value / 10 % 10, time.wYear, time.wMonth, time.wDay);
std::FILE* file = this->OpenSimulatorFile("\\PackageItemTest", name);
if (!file) {
return;
}
const int grade = header->value % 10;
const EnchantSimulationRecord* record = reinterpret_cast<const EnchantSimulationRecord*>(packet + sizeof(SimulationPacketHeader));
int total = 0;
const int count = static_cast<int>((header->length - sizeof(SimulationPacketHeader)) / sizeof(EnchantSimulationRecord));
std::fprintf(file, "\n- %s\n\n", ToUtf8(name, g_textCodePage).c_str());
std::fprintf(file, "============================\tSTART\t============================\n");
std::fprintf(file, "\nGrade %d\n", grade);
for (int i = 0; i < count; ++i) {
ITEM_INFO item;
item.SetItemId(record->itemId);
item.identified = 1;
item.unknown_0000[0] = 6;
ItemDescriptions descriptions{g_itemDescriptions};
bool languagePrefix = false;
WORD language = g_serverLanguage->language;
ItemNaming naming{descriptions, g_itemCardNames, *g_playerNameDictionary, languagePrefix, g_serviceType, language};
std::fprintf(file, "\t\t%s\t%d\t%.5f%%\n", ToUtf8(naming.DisplayName(item, 0), g_textCodePage).c_str(), record->count,
static_cast<float>(record->rate) / 1000.0f);
total += record->count;
++record;
}
std::fprintf(file, "Try\t%d\tSetEnchant\n", total);
std::fprintf(file, "============================\tEND\t============================\n");
std::fclose(file);
}
// OFFSET: 0x00D60030
// FUNCTION: fn_21973
void CGameMode::ReceivePackageSimulation(const unsigned char* packet) {
const SimulationPacketHeader* header = reinterpret_cast<const SimulationPacketHeader*>(packet);
std::string itemName;
std::FILE* file = this->OpenPackageSimulatorFile("\\PackageItemTest", header->value, itemName);
if (!file) {
return;
}
const char* typeNames[22] = {
"PACKAGETYPE_NONE", "PACKAGETYPE_MUST", "PACKAGETYPE_RANDOM_0", "PACKAGETYPE_RANDOM_1", "PACKAGETYPE_RANDOM_2", "PACKAGETYPE_RANDOM_3",
"PACKAGETYPE_RANDOM_4", "PACKAGETYPE_RANDOM_5", "PACKAGETYPE_RANDOM_6", "PACKAGETYPE_RANDOM_7", "PACKAGETYPE_RANDOM_8", "PACKAGETYPE_RANDOM_9",
"PACKAGETYPE_NATURAL_0", "PACKAGETYPE_NATURAL_1", "PACKAGETYPE_NATURAL_2", "PACKAGETYPE_NATURAL_3", "PACKAGETYPE_NATURAL_4", "PACKAGETYPE_NATURAL_5",
"PACKAGETYPE_NATURAL_6", "PACKAGETYPE_NATURAL_7", "PACKAGETYPE_NATURAL_8", "PACKAGETYPE_NATURAL_9",
};
const PackageSimulationRecord* record = reinterpret_cast<const PackageSimulationRecord*>(packet + sizeof(SimulationPacketHeader));
const int count = static_cast<int>((header->length - sizeof(SimulationPacketHeader)) / sizeof(PackageSimulationRecord));
std::vector<const PackageSimulationRecord*> packages[22];
for (int i = 0; i < count; ++i) {
packages[record->packageType].push_back(record);
++record;
}
std::fprintf(file, "\n--Item Name : %s (%d)\n\n", ToUtf8(itemName, g_textCodePage).c_str(), header->value);
std::fprintf(file, "============================\tSTART\t============================\n");
for (int type = 0; type < 22; ++type) {
if (packages[type].empty()) {
continue;
}
std::fprintf(file, "\n--\t%s\n", typeNames[type]);
int unpacked = 0;
for (const PackageSimulationRecord* package : packages[type]) {
ITEM_INFO item;
item.SetItemId(package->itemId);
item.unknown_0088 = package->refine;
item.identified = 1;
item.unknown_0060 = package->unknown_0006;
if (package->refine != 0 || package->unknown_0006 != 0) {
item.unknown_0000[0] = 0x15;
}
ItemDescriptions descriptions{g_itemDescriptions};
bool languagePrefix = false;
WORD language = g_serverLanguage->language;
ItemNaming naming{descriptions, g_itemCardNames, *g_playerNameDictionary, languagePrefix, g_serviceType, language};
std::fprintf(file, "\t%-24s\t\t\t\t\t\t\t%d\t(%d)\t%d/%d\t%s\n", ToUtf8(naming.DisplayName(item, 0), g_textCodePage).c_str(), package->count,
package->unknown_000A, package->unknown_0026, package->unknown_002A, ToUtf8(std::string(package->text), g_textCodePage).c_str());
unpacked += package->count;
}
std::fprintf(file, "\n\t\t\t\t\tUnpacked\t%d\tPackages\n", unpacked);
}
std::fprintf(file, "============================\tEND\t============================\n");
std::fclose(file);
}
// OFFSET: 0x00D612A0
// FUNCTION: fn_21979
void CGameMode::ReceiveUnknownD612A0(const unsigned char* packet) {
UIWindow* window = g_windowMgr.EnsureWindow(267);
if (!window) {
return;
}
window->SendMsg(
nullptr, 34, packet[2] != 0, *reinterpret_cast<const int*>(packet + 4), *reinterpret_cast<const int*>(packet + 8), static_cast<signed char>(packet[3])
);
}
// OFFSET: 0x00D77BF0
// FUNCTION: fn_22152
void CGameMode::ReceiveUnknownD77BF0(const unsigned char* packet) {
if (packet[2] == 1) {
if (!g_windowMgr.unknown_0450) {
g_windowMgr.EnsureWindow(262);
}
if (UIWindow* window = g_windowMgr.LookupWindow(307)) {
window->SendMsg(nullptr, 6, 286, 476, 1, 0);
}
return;
}
g_windowMgr.CloseWindow(262);
}
// OFFSET: 0x00D8A300
// FUNCTION: fn_22218
void CGameMode::ReceiveHpSpRecovery(const unsigned char* packet, int variant) {
CPlayer* player = this->scene->player;
int amount;
std::int16_t type;
switch (variant) {
case 0:
amount = *reinterpret_cast<const std::int16_t*>(packet + 4);
type = *reinterpret_cast<const std::int16_t*>(packet + 2);
break;
case 1:
amount = *reinterpret_cast<const int*>(packet + 4);
type = *reinterpret_cast<const std::int16_t*>(packet + 2);
break;
}
switch (type) {
case 5: {
reinterpret_cast<SessionMessengerContext*>(&g_session)->UpdateRandomStats();
const int hp = g_session.unknown_5568 + amount;
if (g_session.unknown_5568 != hp) {
g_session.unknown_5568 = hp;
g_session.RefreshHpSpWindows();
}
player->SendMsg(nullptr, 88, 0, amount, amount >> 31, static_cast<int>(0xFF00FF00), 0, 114, 0, 0, 0, 0, 0, 0, 0);
player->LaunchEffect(331, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
break;
}
case 7: {
reinterpret_cast<SessionMessengerContext*>(&g_session)->UpdateRandomStats();
int& sp = *reinterpret_cast<int*>(&g_session.unknown_5570[0]);
const int value = sp + amount;
if (sp != value) {
sp = value;
g_session.RefreshHpSpWindows();
}
player->SendMsg(nullptr, 88, 0, amount, amount >> 31, static_cast<int>(0xFF0000FF), 0, 114, 0, 0, 0, 0, 0, 0, 0);
player->LaunchEffect(332, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
break;
}
}
}
// GLOBAL: gl_24965
int g_unknown173A5BC;
// OFFSET: 0x00D50580
// FUNCTION: fn_21884
void CGameMode::IgnoreRemovedPacket7(const unsigned char*) {
}
// OFFSET: 0x00D79420
// FUNCTION: fn_22167
void CGameMode::ReceiveUnknown173A5BC(const unsigned char* packet) {
const int value = *reinterpret_cast<const int*>(packet + 2);
if (value > 0) {
g_unknown173A5BC = value;
}
}
// GLOBAL: gl_24967
int g_unknown16FC588;
// OFFSET: 0x00D7A0B0
// FUNCTION: fn_22186
void CGameMode::ReceiveUnknown16FC588(const unsigned char* packet) {
const signed char value = *reinterpret_cast<const signed char*>(packet + 2);
if (value != 1 && value != 2) {
g_unknown16FC588 = 0;
}
}
// OFFSET: 0x00D08370
// FUNCTION: fn_21586
void CGameMode::IgnoreRemovedPacket8() {
}
// OFFSET: 0x00D08380
// FUNCTION: fn_21587
void CGameMode::IgnoreRemovedPacket9() {
}
// OFFSET: 0x00D088F0
// FUNCTION: fn_21593
void CGameMode::IgnoreRemovedPacket10(const unsigned char*) {
}
// OFFSET: 0x00D08900
// FUNCTION: fn_21594
void CGameMode::IgnoreRemovedPacket11(const unsigned char*) {
}
// OFFSET: 0x00D89BD0
// FUNCTION: fn_22211
void CGameMode::ReceiveCharViewResult(const unsigned char* packet) {
switch (*reinterpret_cast<const std::uint16_t*>(packet + 2)) {
case 0: {
CMode* mode = g_modeMgr.gameMode;
CPlayer* player = static_cast<CGameMode*>(g_modeMgr.GetGameMode())->scene->player;
if (player->render.unknown_0070 != 0 && mode != nullptr) {
mode->SendMsg(137, 3, player->unknown_051C, 0, 0);
}
return;
}
case 1:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(3009)), 0xFF, 0, 0, 0);
return;
default:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(3040)), 0xFF, 0, 0, 0);
return;
}
}
// OFFSET: 0x00D89CA0
// FUNCTION: fn_22213
void CGameMode::ResetItemLists(const unsigned char*) {
g_session.ResetItems61B8();
g_session.ResetItems6B68();
}
// OFFSET: 0x00D8A1F0
// FUNCTION: fn_22216
void CGameMode::ClearItemLists(const unsigned char* packet) {
const std::uint16_t slot = *reinterpret_cast<const std::uint16_t*>(packet + 2);
g_session.ClearUnknown1710(slot);
this->unknown_05CE = 1;
RefreshItemWindows(&g_windowMgr);
g_session.ClearUnknown1740(slot);
g_session.RefreshItem1740Window();
g_session.ClearUnknown1738(slot);
g_session.RefreshItem1738Window();
}
// OFFSET: 0x00D31E50
// FUNCTION: fn_21736
void CGameMode::ReceiveMemorialDungeonInfo(const unsigned char* packet) {
g_session.unknown_5950 = reinterpret_cast<const char*>(packet + 2);
g_session.unknown_596C = *reinterpret_cast<const int*>(packet + 63);
g_session.unknown_5970 = *reinterpret_cast<const int*>(packet + 67);
const int previous = g_session.unknown_5948;
const int state = *reinterpret_cast<const int*>(packet + 67) != 0 ? 1 : 2;
g_session.unknown_5948 = state;
if (previous != state || state != 2 || g_session.unknown_593C != 0) {
if (UIWindow* window = g_windowMgr.EnsureWindow(137)) {
window->SendMsg(nullptr, 60, 0, 0, 0, 0);
}
}
}
// OFFSET: 0x00D31EE0
// FUNCTION: fn_21737
void CGameMode::ReceiveMemorialDungeonNotify(const unsigned char* packet) {
const int previous = g_session.unknown_5948;
g_session.unknown_5970 = *reinterpret_cast<const int*>(packet + 6);
const int time = *reinterpret_cast<const int*>(packet + 6);
g_session.unknown_5948 = time != 0 ? 1 : 2;
if (*reinterpret_cast<const int*>(packet + 2) == 0) {
if (previous != (time != 0 ? 1 : 2) || time != 0 || g_session.unknown_593C != 0) {
if (UIWindow* window = g_windowMgr.EnsureWindow(137)) {
window->SendMsg(nullptr, 60, 0, 0, 0, 0);
}
}
return;
}
g_windowMgr.CloseWindow(137);
const int type = *reinterpret_cast<const int*>(packet + 2);
if (type == 1) {
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(1346)), 0x64FFFF, 0, 0, 0);
} else if (type == 2) {
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(1347)), 0x64FFFF, 0, 0, 0);
} else if (type == 3) {
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(1348)), 0x64FFFF, 0, 0, 0);
}
}
// OFFSET: 0x00D31FD0
// FUNCTION: fn_21738
void CGameMode::ReceiveMemorialDungeonSubscriptionInfo(const unsigned char* packet) {
g_session.unknown_5950 = reinterpret_cast<const char*>(packet + 2);
g_session.unknown_5968 = *reinterpret_cast<const short*>(packet + 63);
g_session.unknown_5948 = 0;
if (UIWindow* window = g_windowMgr.EnsureWindow(137)) {
window->SendMsg(nullptr, 60, 0, 0, 0, 0);
}
}
// OFFSET: 0x00D32040
// FUNCTION: fn_21739
void CGameMode::ReceiveMemorialDungeonSubscriptionNotify(const unsigned char* packet) {
g_session.unknown_5968 = *reinterpret_cast<const short*>(packet + 2);
UIWindow* window = g_windowMgr.EnsureWindow(137);
if (!window) {
return;
}
if (*reinterpret_cast<const short*>(packet + 2) >= 0) {
g_session.unknown_5948 = 0;
window->SendMsg(nullptr, 60, 0, 0, 0, 0);
return;
}
g_windowMgr.CloseWindow(137);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(1345)), 0x64FFFF, 0, 0, 0);
}
// OFFSET: 0x00D320D0
// FUNCTION: fn_21740
void CGameMode::ReceiveWindow17Entries(const unsigned char* packet) {
this->unknown_024C = 1;
g_windowMgr.CloseWindow(17);
if (UIWindow* window = g_windowMgr.EnsureWindow(17)) {
std::string text;
text.assign(reinterpret_cast<const char*>(packet + 8), *reinterpret_cast<const unsigned short*>(packet + 2) - 9);
const std::vector<std::string> entries = Split(text, ":");
for (const std::string& entry : entries) {
if (!entry.empty()) {
window->SendMsg(nullptr, 27, reinterpret_cast<std::intptr_t>(entry.c_str()), 0, 0, 0);
}
}
window->SendMsg(nullptr, 28, *reinterpret_cast<const int*>(packet + 4), 0, 0, 0);
}
if (g_windowMgr.unknown_01F0) {
g_windowMgr.unknown_01F0->SendMsg(nullptr, 32, 0, 0, 0, 0);
}
}
// OFFSET: 0x00D32820
// FUNCTION: fn_21744
void CGameMode::IgnorePacket473(const unsigned char*) {
}
// OFFSET: 0x00D33970
// FUNCTION: fn_21750
void CGameMode::IgnorePacket474(const unsigned char*) {
}
// OFFSET: 0x00D34040
// FUNCTION: fn_21753
void CGameMode::Zc_Notify_Exp(const unsigned char* packet) {
const NotifyExpPacket* data = reinterpret_cast<const NotifyExpPacket*>(packet);
std::string text;
if (g_session.m_aid != data->accountId) {
return;
}
const std::uint32_t color = data->expType != 1 ? 0xFFFF : 0xBE58BE;
const int amount = data->amount;
if (amount == 0) {
return;
}
char buffer[256];
if (data->varId == 1) {
std::sprintf(buffer, LookupMessage(1613), amount);
text += buffer;
} else if (data->varId == 2) {
std::sprintf(buffer, LookupMessage(1614), amount);
text += buffer;
}
if (data->amount >= 0) {
text += LookupMessage(1615);
} else {
text += LookupMessage(1616);
}
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.c_str()), color, 18, 0, 0);
}
// OFFSET: 0x00D61290
// FUNCTION: fn_21978
void CGameMode::IgnorePacket478(const unsigned char*) {
}
// OFFSET: 0x00D3A1D0
// FUNCTION: fn_21775
void CGameMode::ClearUnknown0244(const unsigned char*) {
*reinterpret_cast<int*>(this->unknown_01F8 + 0x4C) = 0;
}
#pragma pack(push, 1)
struct ZoneServerChangePacket {
/* 0000 */ std::uint16_t packetType;
/* 0002 */ char mapName[16];
/* 0012 */ std::int16_t x;
/* 0014 */ std::int16_t y;
/* 0016 */ std::uint32_t ip;
/* 001A */ std::int16_t port;
};
#pragma pack(pop)
// OFFSET: 0x00D3A4C0
// FUNCTION: fn_21777
void CGameMode::ReceiveZoneServerChange(const unsigned char* packet) {
const auto* change = reinterpret_cast<const ZoneServerChangePacket*>(packet);
const std::string mapName(change->mapName, change->mapName + sizeof(change->mapName));
this->ChangeZoneServer(mapName.c_str(), change->x, change->y, static_cast<int>(change->ip), change->port, std::string());
}
// OFFSET: 0x00D3A1E0
// OFFSET: 0x00D272A0
// FUNCTION: fn_21688
void CGameMode::ReceiveActorStatusBlock(const unsigned char* packet) {
g_session.SetUnknown5BC0(*reinterpret_cast<const int*>(packet + 2));
g_session.unknown_5BC4 = *reinterpret_cast<const int*>(packet + 6);
g_session.unknown_5BC8 = *reinterpret_cast<const int*>(packet + 0xE);
g_session.unknown_5BCC = *reinterpret_cast<const int*>(packet + 0xA);
g_session.unknown_5BD0 = *reinterpret_cast<const int*>(packet + 0x12);
if (CRenderObject* actor = this->scene->GetGameActorByAID(*reinterpret_cast<const std::uint32_t*>(packet + 2))) {
actor->SendMsg(nullptr, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
// OFFSET: 0x00D27320
// FUNCTION: fn_21689
void CGameMode::ReceiveActorStatusUpdate(const unsigned char* packet) {
if (g_session.unknown_5BC0 != -1) {
const unsigned int field = *reinterpret_cast<const std::uint16_t*>(packet + 2) - 5;
switch (field) {
case 0:
g_session.unknown_5BC4 = *reinterpret_cast<const int*>(packet + 4);
break;
case 1:
g_session.unknown_5BCC = *reinterpret_cast<const int*>(packet + 4);
break;
case 2:
g_session.unknown_5BC8 = *reinterpret_cast<const int*>(packet + 4);
break;
case 3:
g_session.unknown_5BD0 = *reinterpret_cast<const int*>(packet + 4);
break;
}
if (CRenderObject* actor = this->scene->GetGameActorByAID(g_session.unknown_5BC0)) {
actor->SendMsg(nullptr, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
}
// OFFSET: 0x00D51A90
// FUNCTION: fn_21890
void CGameMode::ReceiveActorTitle(const unsigned char* packet) {
char text[81];
std::strncpy(text, reinterpret_cast<const char*>(packet + 6), 80);
text[80] = '\0';
if (CRenderObject* actor = this->scene->GetGameActorByAID(*reinterpret_cast<const std::uint32_t*>(packet + 2))) {
const std::int64_t value = reinterpret_cast<std::intptr_t>(text);
actor->SendMsg(nullptr, 0x37, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
// OFFSET: 0x00D61340
// FUNCTION: fn_21981
void CGameMode::ReceiveActorInt8(const unsigned char* packet) {
if (CRenderObject* actor = this->scene->GetGameActorByAID(*reinterpret_cast<const std::uint32_t*>(packet + 2))) {
const std::int64_t value = *reinterpret_cast<const signed char*>(packet + 6);
actor->SendMsg(nullptr, 0x91, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
// OFFSET: 0x00D612F0
// FUNCTION: fn_21980
void CGameMode::ReceiveActorInt64Pair(const unsigned char* packet) {
if (CRenderObject* actor = this->scene->GetGameActorByAID(*reinterpret_cast<const std::uint32_t*>(packet + 2))) {
const std::int64_t first = *reinterpret_cast<const int*>(packet + 6);
const std::int64_t second = *reinterpret_cast<const int*>(packet + 0xA);
actor->SendMsg(
nullptr, 0x91, 0, static_cast<int>(first), static_cast<int>(first >> 32), static_cast<int>(second), static_cast<int>(second >> 32), 0, 0, 0, 0, 0, 0, 0, 0
);
}
}
// OFFSET: 0x00D24C40
// FUNCTION: fn_21670
void CGameMode::ReceiveItem1740EquipList(const unsigned char* packet) {
const int count = (*reinterpret_cast<const std::int16_t*>(packet + 2) - 4) / sizeof(StoreEquipRecord);
const StoreEquipRecord* record = reinterpret_cast<const StoreEquipRecord*>(packet + 4);
for (int i = 0; i < count; ++i, ++record) {
StoreItemOption options[5] = {};
ITEM_INFO item;
item.unknown_0000[0] = record->type;
item.unknown_0000[1] = record->index;
item.unknown_0000[2] = record->location;
item.unknown_0000[3] = record->wearState;
item.quantity = 1;
std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards));
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_0088 = 0;
item.unknown_0098 = CountStoreItemOptions(options);
for (int index = 0; index < item.unknown_0098; ++index) {
reinterpret_cast<StoreItemOption*>(item.unknown_009C)[index] = options[index];
}
reinterpret_cast<ClientItemLists*>(&g_session)->AddItem1740(item);
}
g_session.RefreshItem1740Window();
}
// OFFSET: 0x00D24EF0
// FUNCTION: fn_21671
void CGameMode::ReceiveItem1740EquipListOptions(const unsigned char* packet) {
const int count = (*reinterpret_cast<const std::int16_t*>(packet + 2) - 4) / sizeof(StoreEquipOptionRecord);
const StoreEquipOptionRecord* record = reinterpret_cast<const StoreEquipOptionRecord*>(packet + 4);
for (int i = 0; i < count; ++i, ++record) {
StoreItemOption options[5];
std::memcpy(options, record->options, sizeof(options));
ITEM_INFO item;
item.unknown_0000[0] = record->type;
item.unknown_0000[1] = record->index;
item.unknown_0000[2] = record->location;
item.unknown_0000[3] = record->wearState;
item.quantity = 1;
std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards));
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_0088 = 0;
item.unknown_0098 = CountStoreItemOptions(options);
for (int index = 0; index < item.unknown_0098; ++index) {
reinterpret_cast<StoreItemOption*>(item.unknown_009C)[index] = options[index];
}
reinterpret_cast<ClientItemLists*>(&g_session)->AddItem1740(item);
}
g_session.RefreshItem1740Window();
}
// OFFSET: 0x00D26800
// FUNCTION: fn_21682
void CGameMode::ReceiveUnknownD26800(const unsigned char* packet) {
const unsigned char value = packet[2];
*reinterpret_cast<int*>(g_session.unknown_5974) = value;
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(value != 0 ? 0x54F : 0x54E)), 0x64FFFF, 0, 0, 0);
if (g_windowMgr.unknown_01E0) {
g_windowMgr.unknown_01E0->SendMsg(nullptr, 0x3C, 0, 0, 0, 0);
}
}
// OFFSET: 0x00D79660
// FUNCTION: fn_22172
void CGameMode::ReceiveUnknownD79660(const unsigned char* packet) {
UIWindow* window = g_windowMgr.LookupWindow(10032);
if (!window) {
return;
}
switch (*reinterpret_cast<const std::int16_t*>(packet + 6) - 1) {
case 0:
window->Show(0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x10E8)), 0xFF, 0, 0, 0);
return;
case 1:
g_windowMgr.CloseWindow(10032);
return;
case 2:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x79B)), 0xFF, 0, 0, 0);
return;
case 3:
window->Show(1);
return;
}
}
// OFFSET: 0x00D79E90
// FUNCTION: fn_22183
void CGameMode::ReceiveUnknownD79E90(std::int16_t result, std::intptr_t value) {
switch (result) {
case 0:
if (UIWindow* window = g_windowMgr.LookupWindow(340)) {
window->SendMsg(nullptr, 0x40, 0, value, 0, 0);
}
break;
case 1:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x9D1)), 0xFF, 0, 0, 0);
break;
}
}
// OFFSET: 0x00D79440
// FUNCTION: fn_22168
void CGameMode::ReceiveRouletteSetResult(const unsigned char* packet) {
switch (packet[2]) {
case 0:
g_rouletteMgr->SetAdditionItem(*reinterpret_cast<const int*>(packet + 3));
g_rouletteMgr->SetResult(0, 0, 0);
g_rouletteMgr->Reset();
if (g_windowMgr.unknown_0464) {
g_windowMgr.RefreshRouletteWnd();
}
break;
case 1:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xA4C)), 0x6464FF, 0, 0, 0);
break;
case 2:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xA4D)), 0x6464FF, 0, 0, 0);
break;
case 3:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xA4E)), 0x6464FF, 0, 0, 0);
break;
}
}
// OFFSET: 0x00D611B0
// FUNCTION: fn_21977
void CGameMode::ReceiveDynamicNpcNotice(const unsigned char* packet) {
char text[0x400];
const char* message;
switch (*reinterpret_cast<const int*>(packet + 2)) {
case 1:
std::memset(text, 0, sizeof(text));
StringFormat(text, sizeof(text), static_cast<std::size_t>(-1), "dynamic npc create error found(unknown) ");
message = text;
break;
case 2:
std::memset(text, 0, sizeof(text));
StringFormat(text, sizeof(text), static_cast<std::size_t>(-1), "dynamic npc not found ");
message = text;
break;
case 3:
message = LookupMessage(0xA47);
break;
case 4:
message = LookupMessage(0xFA2);
break;
default:
return;
}
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0x64FFFF, 0, 0, 0);
}
// OFFSET: 0x00D079A0
// FUNCTION: fn_21584
void CGameMode::sub_D079A0(unsigned char kind, int argument) {
std::string& speaker = *reinterpret_cast<std::string*>(this->unknown_01F8 + 0x1C);
std::string& target = *reinterpret_cast<std::string*>(this->unknown_01F8 + 0x34);
switch (kind) {
case 0: {
std::string line(g_session.DecodePlayerName());
line.append(" : ", 3);
line.append(speaker.data(), speaker.size());
if (g_windowMgr.ShowWhisperFrom(target.c_str(), line.c_str(), 0x7800, static_cast<std::uint32_t>(argument)) != 0) {
return;
}
const std::string copied = target;
const std::string identity = ShortcutFilename(static_cast<std::uint32_t>(argument));
std::string message;
if (g_windowMgr.IsFriend(target.c_str()) || g_session.IsGuildMemberName(target.c_str())) {
message = std::string("[ To ") + copied + " (" + identity + ") ] : " + speaker;
} else {
message = std::string("( To ") + copied + " (" + identity + ") : " + speaker;
}
if (g_pendingWhisperCount <= 0) {
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message.c_str()), 0xFFFF, 2, reinterpret_cast<std::intptr_t>(copied.c_str()), 0);
} else {
--g_pendingWhisperCount;
}
if (g_whisperRecord != 0) {
this->WriteChatLog(message.c_str());
}
return;
}
case 1:
case 2:
case 3: {
const int messageId = kind == 1 ? 0x94 : kind == 2 ? 0x95 : 0x96;
const std::string text = std::string("(") + target + ")" + LookupMessage(messageId);
if (kind == 1 && g_pendingWhisperCount > 0) {
--g_pendingWhisperCount;
return;
}
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.c_str()), 0xFFFF, 2, 0, 0);
return;
}
default: {
const std::string text = std::string("(") + target + ")" + LookupMessage(0x94);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.c_str()), 0xFFFF, 2, 0, 0);
if (g_whisperRecord != 0) {
this->WriteChatLog(text.c_str());
}
return;
}
}
}
// OFFSET: 0x00D08390
// OFFSET: 0x00D08110
// FUNCTION: fn_21585
void __stdcall sub_D08110(int field8, int itemIdWord, int quantityWord, int field14, int field18) {
const int itemId = static_cast<short>(itemIdWord);
const int quantity = static_cast<short>(quantityWord);
ITEM_INFO item = g_session.FindItem1758(static_cast<unsigned int>(itemId));
item.unknown_0000[1] = static_cast<std::uint32_t>(itemId);
item.quantity = quantity;
item.unknown_0014[0] = static_cast<std::uint32_t>(field14);
UIWindow* window = g_windowMgr.EnsureWindow(0x101);
window->SendMsg(nullptr, 0x17, reinterpret_cast<std::intptr_t>(&item), field18, field8, 0);
reinterpret_cast<ClientItemLists*>(&g_session)->RemoveItem1758(item);
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
ItemDescriptions descriptions{g_itemDescriptions};
bool languagePrefix = false;
WORD language = g_serverLanguage->language;
ItemNaming naming{descriptions, g_itemCardNames, *g_playerNameDictionary, languagePrefix, g_serviceType, language};
g_windowMgr.SendNotice(
1, reinterpret_cast<std::intptr_t>(FormatOwnedString(LookupMessage(0xE7), naming.DisplayName(item, 0).c_str(), quantity).c_str()), 0xFFFF64, 0, 0, 0
);
if (g_vendingOpenWindow != nullptr) {
g_vendingOpenWindow->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
}
if (reinterpret_cast<const SessionMessengerContext*>(&g_session)->GetList9Size() == 0) {
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x137)), 0xFF00, 0, 0, 0);
if (g_vendingOpenResultWindow != nullptr) {
g_vendingOpenResultWindow->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
g_vendingOpenResultWindow->SendMsg(nullptr, 6, 0xC9, 0, 0, 0);
}
} else if (g_vendingOpenResultWindow != nullptr) {
g_vendingOpenResultWindow->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
}
if (g_vendingOpenResultWindow != nullptr && g_vendingSaleAlarm) {
g_soundMgr->PlayWave("effect\\ef_steal.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
}
}
// OFFSET: 0x00D08670
// FUNCTION: fn_21592
void __declspec(noinline) __stdcall sub_D08670(int field14, int itemId, int quantity, int field8, int fieldC, int field10) {
ITEM_INFO item = g_session.FindItem1758ByItemId(itemId);
item.SetItemId(itemId);
item.quantity = quantity;
item.unknown_0014[0] = static_cast<std::uint32_t>(field8);
UIWindow* window = g_windowMgr.EnsureWindow(0x102);
window->SendMsg(nullptr, 0x17, reinterpret_cast<std::intptr_t>(&item), field10, field14, 0);
reinterpret_cast<ClientItemLists*>(&g_session)->RemoveItem1758ByItemId(item);
if (g_saleOpenWindow != nullptr) {
g_saleOpenWindow->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
}
if (g_saleResultWindow != nullptr) {
g_saleResultWindow->SendMsg(nullptr, 0x77, fieldC, 0, 0, 0);
g_saleResultWindow->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
if (g_vendingSaleAlarm) {
g_soundMgr->PlayWave("effect\\ef_steal.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
}
if (reinterpret_cast<SessionMessengerContext*>(&g_session)->GetList9Size() == 0) {
g_saleResultWindow->SendMsg(nullptr, 6, 0xC9, 0, 0, 0);
}
}
}
// OFFSET: 0x00D08640
// FUNCTION: fn_21591
void __stdcall sub_D08640(const unsigned char* packet) {
sub_D08670(
*reinterpret_cast<const int*>(packet + 0x14),
*reinterpret_cast<const int*>(packet + 2),
*reinterpret_cast<const short*>(packet + 6),
*reinterpret_cast<const int*>(packet + 8),
*reinterpret_cast<const int*>(packet + 0xC),
*reinterpret_cast<const int*>(packet + 0x10));
}
// OFFSET: 0x00D246B0
// FUNCTION: fn_21668
void CGameMode::ReceiveItem1740BasicList(const unsigned char* data) {
const PacketLengthHeader* packet = reinterpret_cast<const PacketLengthHeader*>(data);
const int count = (packet->length - sizeof(PacketLengthHeader)) / sizeof(Item1740Record);
const Item1740Record* record = reinterpret_cast<const Item1740Record*>(data + sizeof(PacketLengthHeader));
for (int i = 0; i < count; ++i, ++record) {
ITEM_INFO item;
item.unknown_0000[0] = record->type;
item.unknown_0000[1] = record->index;
item.unknown_0000[2] = record->location;
item.unknown_0000[3] = record->wearState;
item.quantity = 1;
std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards));
item.SetItemId(record->itemId);
item.identified = record->identified;
item.unknown_005D = record->unknown_000C;
item.unknown_0060 = record->refine;
item.unknown_0068 = record->expireTime;
reinterpret_cast<ClientItemLists*>(&g_session)->AddItem1740(item);
}
g_session.RefreshItem1740Window();
}
// OFFSET: 0x00D24810
// FUNCTION: fn_21669
void CGameMode::ReceiveItem1740BasicListBind(const unsigned char* data) {
const PacketLengthHeader* packet = reinterpret_cast<const PacketLengthHeader*>(data);
const int count = (packet->length - sizeof(PacketLengthHeader)) / sizeof(Item1740EquipRecord);
const Item1740EquipRecord* record = reinterpret_cast<const Item1740EquipRecord*>(data + sizeof(PacketLengthHeader));
for (int i = 0; i < count; ++i, ++record) {
ITEM_INFO item;
item.unknown_0000[0] = record->type;
item.unknown_0000[1] = record->index;
item.unknown_0000[2] = record->location;
item.unknown_0000[3] = record->wearState;
item.quantity = 1;
std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards));
item.SetItemId(record->itemId);
item.identified = record->identified;
item.unknown_005D = record->unknown_000C;
item.unknown_0060 = record->refine;
item.unknown_0068 = record->expireTime;
item.unknown_0064 = record->bindOnEquip;
item.unknown_0070 = record->sprite;
reinterpret_cast<ClientItemLists*>(&g_session)->AddItem1740(item);
}
g_session.RefreshItem1740Window();
}
// OFFSET: 0x00D2D770
// FUNCTION: fn_21720
void CGameMode::ReceiveItemInventoryList(const unsigned char* data) {
reinterpret_cast<SessionMessengerContext*>(&g_session)->KeepEquipment();
const PacketLengthHeader* packet = reinterpret_cast<const PacketLengthHeader*>(data);
const int count = (packet->length - sizeof(PacketLengthHeader)) / sizeof(StoreNormalRecord);
const StoreNormalRecord* record = reinterpret_cast<const StoreNormalRecord*>(data + sizeof(PacketLengthHeader));
for (int i = 0; i < count; ++i, ++record) {
ITEM_INFO item;
item.unknown_0000[0] = record->type;
item.unknown_0000[1] = record->index;
item.unknown_0000[3] = record->location;
item.unknown_0000[2] = 0;
item.quantity = record->amount;
std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards));
item.SetItemId(record->itemId);
item.identified = record->flags & 1;
item.unknown_005D = 0;
item.unknown_0060 = 0;
item.unknown_0068 = record->expireTime;
item.unknown_0074[0] = (record->flags >> 1) & 1;
g_session.UpdateInventoryItem(item, 0);
}
RefreshItemWindows(&g_windowMgr);
}
// OFFSET: 0x00D64930
// FUNCTION: fn_21994
void __stdcall Nullsub479(int value) {
}
// OFFSET: 0x00D64A40
// FUNCTION: fn_21996
int sub_D64A40(const unsigned char* entries) {
int count = 0;
if (*reinterpret_cast<const std::uint16_t*>(entries) != 0) {
++count;
}
if (*reinterpret_cast<const std::uint16_t*>(entries + 5) != 0) {
++count;
}
if (*reinterpret_cast<const std::uint16_t*>(entries + 10) != 0) {
++count;
}
if (*reinterpret_cast<const std::uint16_t*>(entries + 15) != 0) {
++count;
}
if (*reinterpret_cast<const std::uint16_t*>(entries + 20) != 0) {
++count;
}
return count;
}
// OFFSET: 0x00D77C60
// FUNCTION: fn_22153
void CGameMode::ReceivePartyJobLevel(const unsigned char* packet) {
ClientMessenger{g_session.m_partyMembers, g_session.m_friends}.SetPartyJobLevel(
*reinterpret_cast<const std::uint32_t*>(packet + 2), *reinterpret_cast<const std::uint16_t*>(packet + 6),
*reinterpret_cast<const std::uint16_t*>(packet + 8)
);
sub_DFF150(&g_session);
}
// OFFSET: 0x00D8A260
// FUNCTION: fn_22217
void CGameMode::ReceivePartyDead(const unsigned char* packet) {
ClientMessenger messenger{g_session.m_partyMembers, g_session.m_friends};
MessengerMember member = messenger.PartyByAccount(*reinterpret_cast<const std::uint32_t*>(packet + 2));
if (member.valid != 0) {
messenger.SetPartyDead(*reinterpret_cast<const std::uint32_t*>(packet + 2), packet[6]);
sub_DFF150(&g_session);
}
}
// OFFSET: 0x00D5AB80
// FUNCTION: fn_21962
void CGameMode::ReceiveShopItemList(
const std::vector<ITEM_INFO>& items, int value, int unused1, int argument, int unused2, std::uint32_t duration, unsigned char myShop
) {
ClientItemLists* lists = reinterpret_cast<ClientItemLists*>(&g_session);
if (myShop == 1) {
lists->ClearItems1758();
for (ITEM_INFO item : items) {
lists->AddItem1758(item);
}
if (UIMerchantItemMyShopWnd* window = static_cast<UIMerchantItemMyShopWnd*>(g_windowMgr.EnsureWindow(45))) {
window->OpenShop();
window->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
window->SendMsg(nullptr, 0x1C, value, 0, 0, 0);
window->SetDuration(duration);
}
} else {
lists->ClearItems1748();
lists->ClearItems1760();
for (ITEM_INFO item : items) {
lists->AddItem1748(item);
}
if (UIMerchantItemShopWnd* window = static_cast<UIMerchantItemShopWnd*>(g_windowMgr.EnsureWindow(43))) {
window->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
window->SendMsg(nullptr, 0x1C, value, 0, 0, 0);
window->StartTimer(duration);
}
if (UIWindow* window = g_windowMgr.EnsureWindow(44)) {
window->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
window->SendMsg(nullptr, 0x1C, value, argument, 0, 0);
}
}
this->unknown_024C = 1;
}
// OFFSET: 0x00D79AF0
// FUNCTION: fn_22177
void CGameMode::ReceivePacket0B2E(short result) {
switch (result) {
case 1:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x442)), 0xff, 0, 0, 0);
break;
case 2:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xe31)), 0xff, 0, 0, 0);
break;
}
}
// OFFSET: 0x00D2A1F0
// FUNCTION: fn_21702
void CGameMode::ReceiveUnknownD2A1F0(const unsigned char* packet) {
switch (*reinterpret_cast<const std::int16_t*>(packet + 2)) {
case 3:
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x6CF)), 0xFF, 0, 0, 0);
break;
case 4:
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x6D0)), 0xFF, 0, 0, 0);
break;
}
this->SendMsg(0x28, 0, 0, 0, 0);
g_windowMgr.CloseWindow(0xB0);
}
// OFFSET: 0x00D7A0E0
// FUNCTION: fn_22187
void CGameMode::ReceiveActorMessage7(const unsigned char* packet) {
const std::int16_t length = *reinterpret_cast<const std::int16_t*>(packet + 2) - 8;
if (length == 0) {
return;
}
const std::uint32_t aid = *reinterpret_cast<const std::uint32_t*>(packet + 4);
CRenderObject* actor = aid == g_session.m_aid ? this->scene->player : this->scene->GetGameActorByAID(aid);
if (!actor) {
return;
}
char text[256];
std::memcpy(text, packet + 8, length);
const std::int64_t value = reinterpret_cast<std::intptr_t>(text);
actor->SendMsg(
nullptr, 7, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
);
}
// OFFSET: 0x00D7AEB0
// FUNCTION: fn_22194
void CGameMode::Zc_Start_Baby(const unsigned char*) {
this->unknown_040C = 20001;
*reinterpret_cast<int*>(this->unknown_0410) = 5;
this->unknown_0414 = 0;
this->unknown_0408 = reinterpret_cast<void*>(2);
}
// OFFSET: 0x00D7AEE0
// FUNCTION: fn_22195
void CGameMode::Zc_Start_Capture(const unsigned char*) {
this->unknown_040C = 10000;
*reinterpret_cast<int*>(this->unknown_0410) = 5;
this->unknown_0414 = 0;
this->unknown_0408 = reinterpret_cast<void*>(2);
}
// OFFSET: 0x00D7AF10
// FUNCTION: fn_22196
void CGameMode::Zc_Start_Collection(const unsigned char*) {
this->unknown_040C = 40000;
*reinterpret_cast<int*>(this->unknown_0410) = 1;
this->unknown_0414 = 0;
this->unknown_0408 = reinterpret_cast<void*>(2);
}
// OFFSET: 0x00D7AF40
// FUNCTION: fn_22197
void CGameMode::Zc_Start_Couple(const unsigned char*) {
this->unknown_040C = 20000;
*reinterpret_cast<int*>(this->unknown_0410) = 5;
this->unknown_0414 = 0;
this->unknown_0408 = reinterpret_cast<void*>(2);
}
// OFFSET: 0x00D591A0
// FUNCTION: fn_21959
void CGameMode::sub_D591A0(std::uint32_t aid, int state, int flag, int options) {
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(aid));
if (!actor) {
return;
}
actor->unknown_0210 = static_cast<std::uint16_t>(flag);
if (!StateFlag06(state)) {
actor->sub_CAA4D0();
}
if (actor->IsPlayerClass(actor->GetEffectiveJob(-1))) {
if (StateFlag01(actor->Slot13()) || StateFlag02(actor->Slot13())) {
actor->SendMsg(nullptr, 109, 0, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor->SendMsg(nullptr, 109, 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor->SendMsg(nullptr, 109, 0, 1132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor->SendMsg(nullptr, 109, 0, 418, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor->SendMsg(nullptr, 109, 0, 586, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
return;
}
if (options & 0x1) {
if (!actor->state.Attachments().HasId(166)) {
CRagEffect* effect = actor->LaunchEffect(166, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
if (effect) {
effect->SendMsg(nullptr, 44, 0, 0xFFFF, 130, 0, 0, 0);
}
}
} else if (options & 0x2) {
if (!actor->state.Attachments().HasId(166)) {
CRagEffect* effect = actor->LaunchEffect(166, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
if (effect) {
effect->SendMsg(nullptr, 44, 0, 0xFFFF, 128, 0, 0, 0);
}
}
} else if (options & 0x4) {
if (!actor->state.Attachments().HasId(166)) {
CRagEffect* effect = actor->LaunchEffect(166, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
if (effect) {
effect->SendMsg(nullptr, 44, 0, 0xFFFF, 169, 0, 0, 0);
}
}
} else if (options & 0x4000) {
if (!actor->state.Attachments().HasId(617)) {
actor->LaunchEffect(617, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
}
if ((options & 0x8) && !actor->state.Attachments().HasId(203)) {
actor->LaunchEffect(203, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if ((options & 0x10) && !actor->state.Attachments().HasId(254)) {
actor->LaunchEffect(254, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
actor->LaunchEffect(1132, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if ((options & 0x1000) && !actor->state.Attachments().HasId(418)) {
actor->LaunchEffect(418, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
actor->LaunchEffect(544, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if ((options & 0x2000) && !actor->state.Attachments().HasId(419)) {
actor->LaunchEffect(419, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if ((options & 0x8000) && !actor->state.Attachments().HasId(424)) {
actor->LaunchEffect(424, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if ((options & 0x20000) && !actor->state.Attachments().HasId(586)) {
actor->LaunchEffect(586, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if ((options & 0x10000) && !actor->state.Attachments().HasId(655)) {
actor->LaunchEffect(655, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if ((options & 0x40) && !actor->state.Attachments().HasId(474)) {
actor->LaunchEffect(474, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if ((options & 0x100) && !actor->state.Attachments().HasId(382)) {
actor->LaunchEffect(382, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if ((options & 0x80) && !actor->state.Attachments().HasId(368)) {
actor->LaunchEffect(368, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if ((options & 0x200) && !actor->state.Attachments().HasId(394)) {
actor->LaunchEffect(394, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if ((options & 0x400) && !actor->state.Attachments().HasId(396)) {
actor->LaunchEffect(396, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if (options & 0x20) {
switch (actor->GetEffectiveJob(-1)) {
case 15:
case 4016:
case 4038:
case 4070:
case 4077:
case 4106:
case 4262:
actor->SetFrameSequence(96, 4, 4, 96, 4, 1, 99999999, 0);
break;
default:
actor->render.isMotionFreezed = true;
break;
}
actor->render.unknown_00A3 = 1;
actor->SetColor(-1, 64, 64, 64);
}
if ((options & 0x800) && !actor->state.Attachments().HasId(375)) {
actor->LaunchEffect(375, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
if ((options & 0x40000) && !actor->state.Attachments().HasId(744)) {
actor->LaunchEffect(744, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
return;
}
if (StateFlag01(actor->Slot13()) || StateFlag02(actor->Slot13())) {
actor->SendMsg(nullptr, 109, 0, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor->SendMsg(nullptr, 109, 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor->SendMsg(nullptr, 109, 0, 1132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor->SendMsg(nullptr, 109, 0, 418, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
return;
}
if (options & 0x20) {
actor->render.isMotionFreezed = true;
actor->render.unknown_00A3 = 1;
actor->SetColor(-1, 64, 64, 64);
}
if (options & 0x2) {
if (!actor->state.Attachments().HasId(420)) {
actor->LaunchEffect(420, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
} else {
while (actor->state.Attachments().HasId(420)) {
actor->SendMsg(nullptr, 109, 0, 420, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor->LaunchEffect(540, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
}
if (options & 0x4) {
if (!actor->state.Attachments().HasId(427)) {
actor->LaunchEffect(427, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
} else {
while (actor->state.Attachments().HasId(427)) {
actor->SendMsg(nullptr, 109, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
if (options & 0x10) {
if (!actor->state.Attachments().HasId(254)) {
actor->LaunchEffect(254, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
actor->LaunchEffect(1132, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
} else {
while (actor->state.Attachments().HasId(254)) {
actor->SendMsg(nullptr, 109, 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor->SendMsg(nullptr, 109, 0, 1132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
if (options & 0x10000) {
if (!actor->state.Attachments().HasId(655)) {
actor->LaunchEffect(655, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
} else {
while (actor->state.Attachments().HasId(655)) {
actor->SendMsg(nullptr, 109, 0, 655, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor->LaunchEffect(656, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
}
if (options & 0x8000) {
if (!actor->state.Attachments().HasId(667)) {
actor->LaunchEffect(667, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
} else {
while (actor->state.Attachments().HasId(667)) {
actor->SendMsg(nullptr, 109, 0, 667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
if (options & 0x800) {
if (!actor->state.Attachments().HasId(375)) {
actor->LaunchEffect(375, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
} else {
while (actor->state.Attachments().HasId(375)) {
actor->SendMsg(nullptr, 109, 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
if (options & 0x40000) {
if (!actor->state.Attachments().HasId(744)) {
actor->LaunchEffect(744, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
} else {
while (actor->state.Attachments().HasId(744)) {
actor->SendMsg(nullptr, 109, 0, 744, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
}
// OFFSET: 0x00D7B350
// FUNCTION: fn_22201
void CGameMode::ReceivePacket0AB8(const unsigned char*) {
this->scene->player->SendMsg(nullptr, 149, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
// OFFSET: 0x00D78010
// FUNCTION: fn_22156
void CGameMode::ReceiveUnknownD78010(const unsigned char* packet) {
this->sub_D591A0(
*reinterpret_cast<const std::uint32_t*>(packet + 2),
*reinterpret_cast<const int*>(packet + 6),
*reinterpret_cast<const int*>(packet + 0xA),
*reinterpret_cast<const int*>(packet + 0xE)
);
}
// OFFSET: 0x00D89C60
// FUNCTION: fn_22212
void CGameMode::ReceiveUnknownD89C60(const unsigned char* packet) {
this->sub_D5EEF0(
reinterpret_cast<const char*>(packet + 0x2B),
*reinterpret_cast<const int*>(packet + 2),
reinterpret_cast<const char*>(packet + 0x43),
*reinterpret_cast<const int*>(packet + 6),
packet[0x12],
*reinterpret_cast<const std::uint16_t*>(packet + 0xA),
*reinterpret_cast<const std::uint16_t*>(packet + 0xC),
reinterpret_cast<const char*>(packet + 0x13),
packet[0x53],
packet[0x54],
0
);
}
// OFFSET: 0x00D79390
// FUNCTION: fn_22165
void CGameMode::ReceiveLapineBoxIngredient(const unsigned char* packet) {
if (g_windowMgr.LookupWindow(0x122) != nullptr) {
return;
}
if (UIWindow* window = g_windowMgr.EnsureWindow(0x122)) {
static_cast<UILapineBoxWnd*>(window)->SetIngredient(static_cast<int>(reinterpret_cast<std::intptr_t>(packet)));
}
}
// OFFSET: 0x00D79B40
// FUNCTION: fn_22178
void CGameMode::ActivateMacroBlackListCheck(unsigned char state, int duration) {
if (UIWindow* window = g_windowMgr.LookupWindow(0x167)) {
static_cast<UIMacroBlackListCheckWnd*>(window)->Activate(state, duration);
}
}
// OFFSET: 0x00D79B70
// FUNCTION: fn_22179
void CGameMode::SetMacroDetectorCountdown(unsigned char count, std::uint32_t duration) {
if (UIWindow* window = g_windowMgr.LookupWindow(0x11D)) {
window->Show(1);
static_cast<UIMacroDetectorWnd*>(window)->SetCountdown(count, duration);
}
}
// OFFSET: 0x00D79340
// FUNCTION: fn_22164
void CGameMode::ReceiveCaptchaPreviewImage(const char* key, const void* data, unsigned short size) {
UICaptchaPreviewWnd* window = static_cast<UICaptchaPreviewWnd*>(g_windowMgr.LookupWindow(0x120));
if (window != nullptr && std::strncmp(window->m_captchaKey, key, 4) == 0) {
window->AddImageData(data, size);
}
}
// OFFSET: 0x00D793D0
// FUNCTION: fn_22166
void CGameMode::ReceiveLapineUpgradeBoxValue(int value) {
if (g_windowMgr.LookupWindow(0x12E) != nullptr) {
return;
}
UIWindow* window = g_windowMgr.EnsureWindow(0x12E);
if (window == nullptr) {
return;
}
window->SendMsg(nullptr, 0x17, value, 0, 0, 0);
}
// OFFSET: 0x00D7B420
// FUNCTION: fn_22203
void CGameMode::Zc_Trycapture_Monster(const unsigned char* packet) {
UIWindow* window = reinterpret_cast<UIWindow*>(g_windowMgr.unknown_0394);
if (packet[2] != 0) {
if (window) {
window->SendMsg(nullptr, 0x50, 1, 7, 0, 0);
}
} else {
if (window) {
window->SendMsg(nullptr, 0x50, 1, 3, 0, 0);
}
}
}
// OFFSET: 0x00D7B470
// FUNCTION: fn_22204
void CGameMode::Zc_Trycollection(const unsigned char* packet) {
if (UIWindow* window = g_windowMgr.LookupWindow(0xC4)) {
if (packet[2] != 0) {
window->SendMsg(nullptr, 0x50, 1, 7, 0, 0);
} else {
window->SendMsg(nullptr, 0x50, 1, 3, 0, 0);
}
}
}
// OFFSET: 0x00D32830
// FUNCTION: fn_21745
void CGameMode::Zc_Msg(const unsigned char* packet) {
const std::uint16_t message = *reinterpret_cast<const std::uint16_t*>(packet + 2);
std::uint32_t color = 0xFFFFFF;
switch (message) {
case 0x4C5:
case 0x4C6:
case 0x757:
case 0x758:
case 0x886:
color = 0xFF;
break;
}
int type = 0;
switch (message) {
case 0xD93:
case 0xD94:
type = 0x17;
break;
}
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(message)), color, type, 0, 0);
g_windowMgr.SendNotice(19, reinterpret_cast<std::intptr_t>(LookupMessage(message)), color, type, 0, 0);
}
// OFFSET: 0x00D328E0
// FUNCTION: fn_21746
void CGameMode::Zc_Msg_Color(const unsigned char* packet) {
const std::uint16_t message = *reinterpret_cast<const std::uint16_t*>(packet + 2);
std::uint32_t color = *reinterpret_cast<const std::uint32_t*>(packet + 4);
switch (message) {
case 0x4C5:
case 0x4C6:
case 0x757:
case 0x758:
case 0x886:
color = 0xFF;
break;
}
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(message)), color, 0, 0, 0);
g_windowMgr.SendNotice(19, reinterpret_cast<std::intptr_t>(LookupMessage(message)), color, 0, 0, 0);
}
// OFFSET: 0x00D7B5E0
// FUNCTION: fn_22207
void CGameMode::ReceiveRouletteBonusPoints(const unsigned char* packet) {
switch (packet[2]) {
case 0:
g_rouletteMgr->m_goldPoint = *reinterpret_cast<const int*>(packet + 3);
break;
case 1:
g_rouletteMgr->m_silverPoint = *reinterpret_cast<const int*>(packet + 3);
break;
case 2:
g_rouletteMgr->m_bronzePoint = *reinterpret_cast<const int*>(packet + 3);
break;
}
if (g_windowMgr.unknown_0464 != nullptr) {
g_windowMgr.RefreshRouletteWnd();
}
}
// OFFSET: 0x00D7AE60
// FUNCTION: fn_22193
void CGameMode::ReceiveActorCharm(const unsigned char* packet) {
const std::uint32_t aid = *reinterpret_cast<const std::uint32_t*>(packet + 2);
CRenderObject* actor;
if (aid == *reinterpret_cast<const std::uint32_t*>(reinterpret_cast<const void*>(&g_session.m_aid))) {
actor = static_cast<CGameMode*>(g_modeMgr.GetGameMode())->scene->player;
} else {
actor = g_session.FindGameActor(aid);
}
if (actor) {
static_cast<CGameActor*>(actor)->SetCharm(
*reinterpret_cast<const std::int16_t*>(packet + 6), *reinterpret_cast<const std::int16_t*>(packet + 8)
);
}
}
// OFFSET: 0x00D79970
// FUNCTION: fn_22175
void CGameMode::ReceivePacket0A29(int value) {
ValuePacket packet;
packet.id = 0x0A2A;
packet.value = value;
GetRagConnection().Send(g_packetLengths.FixedLength(packet.id), &packet);
}
// OFFSET: 0x00D79E10
// FUNCTION: fn_22182
void CGameMode::ReceiveCashShopBanner(int value1, int value2, int value3) {
if (!g_windowMgr.CloseWindow(0x13e)) {
if (UIWindow* window = g_windowMgr.EnsureWindow(0x13e)) {
window->SendMsg(nullptr, 0xa4, value3, 0, 0, 0);
window->SendMsg(nullptr, 0x78, value1, value2, 0, 0);
} else {
g_modeMgr.gameMode->SendMsg(0x143, value3, 0, 0, 0);
}
}
}
// OFFSET: 0x00D7A180
// FUNCTION: fn_22188
void CGameMode::ReceiveWindow308TextEntries(unsigned char* packet) {
g_windowMgr.CloseWindow(0x134);
UIWindow* window = g_windowMgr.EnsureWindow(0x134);
const int count = (*reinterpret_cast<const std::int16_t*>(packet + 2) - 4) / 16;
char* text = reinterpret_cast<char*>(packet + 4);
for (int i = 0; i < count; ++i, text += 16) {
text[15] = '\0';
if (std::strlen(text) != 0) {
window->SendMsg(nullptr, 0x22, reinterpret_cast<std::intptr_t>(text), 0, 0, 0);
}
}
}
// OFFSET: 0x00D7B390
// FUNCTION: fn_22202
void CGameMode::ReceiveActorStateValue(std::uint32_t aid, int unused, std::int16_t value) {
if (aid == 0 || !g_serviceOptions.Get(8)) {
return;
}
CGameActor* actor;
if (aid == g_session.m_aid) {
actor = this->scene->player;
} else {
actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(aid));
}
if (actor == nullptr) {
return;
}
if (actor->UpdateUnknown03E8(value)) {
actor->LaunchEffect(0x2a5, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
}
// OFFSET: 0x00D898B0
// FUNCTION: fn_22209
void CGameMode::ReceiveChatEntries(unsigned char* data) {
ChatEntryListPacket* packet = reinterpret_cast<ChatEntryListPacket*>(data);
const int count = (packet->length - 6) / static_cast<int>(sizeof(ChatTextEntry));
g_windowMgr.CloseWindow(39);
UIWindow* window = g_windowMgr.EnsureWindow(39);
window->SendMsg(nullptr, 0x3B, packet->unknown_0004, 0, 0, 0);
for (int i = 0; i < count; ++i) {
ChatTextEntry* entry = &packet->entries[i];
entry->text[15] = '\0';
if (std::strlen(entry->text) != 0) {
window->SendMsg(nullptr, 0x1B, reinterpret_cast<std::intptr_t>(entry->text), 0, 0, 0);
}
}
window->SendMsg(nullptr, 0x1B, reinterpret_cast<std::intptr_t>("cancel"), 0, 0, 0);
}
// OFFSET: 0x00D795B0
// OFFSET: 0x00D7A200
// FUNCTION: fn_22189
void CGameMode::ReceivePacket0B73(const unsigned char* data) {
const auto* packet = reinterpret_cast<const ActorValuePacket*>(data);
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAidIncludeMe(packet->accountId));
if (!actor) {
return;
}
const int job = actor->GetEffectiveJob(-1);
if (job != 4240 && job != 4242 && job != 4303) {
return;
}
if (StateFlag01(actor->Slot13()) || StateFlag02(actor->Slot13())) {
g_effectMgr->Retire(actor->render.accountId, 1225);
}
CEffect* effect = g_effectMgr->Find(actor->render.accountId, 1225);
if (!effect) {
effect = g_effectMgr->Spawn(actor->render.accountId, 1225, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
if (!effect) {
return;
}
}
effect->unknown_00B0 = packet->value;
effect->Slot01();
}
// OFFSET: 0x00D25850
// FUNCTION: fn_21673
void CGameMode::ReceiveUnknownD25850(const unsigned char* packet) {
reinterpret_cast<ClientItemLists*>(&g_session)->RemoveItem1710(*reinterpret_cast<const std::int16_t*>(packet + 2), 1);
char number[12];
char text[260];
_itoa(*reinterpret_cast<const int*>(packet + 4), number, 10);
const ITEM_DESC& description = FindItemDescription(std::atoi(number));
std::sprintf(text, LookupMessage(1258), description.identifiedName);
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
g_windowMgr.SendNotice(19, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
}
// OFFSET: 0x00D31A40
// FUNCTION: fn_21735
void CGameMode::ReceiveUnknownD31A40(const unsigned char* packet) {
char text[512];
const unsigned int count = static_cast<unsigned int>(*reinterpret_cast<const std::int16_t*>(packet + 2) - 4) >> 2;
const int* ids = reinterpret_cast<const int*>(packet + 4);
std::strcpy(text, FindItemDescription(*ids).identifiedName);
++ids;
for (unsigned int index = 1; index < count; ++index, ++ids) {
std::sprintf(text, "%s %s", text, FindItemDescription(*ids).identifiedName);
}
std::sprintf(text, LookupMessage(2087), text);
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFF, 0, 0, 0);
}
// OFFSET: 0x00D61100
// FUNCTION: fn_21976
void LaunchRollingCutterEffect(CGameActor* actor) {
if (!actor || !actor->LaunchEffect(837, vector3d{0.0f, 0.0f, 0.0f}, 0.0f)) {
return;
}
if (static_cast<int>(actor->GetInstant(1)) <= 0) {
actor->render.instant.Set(1, 0);
actor->render.instant.Set(0, static_cast<std::int64_t>(actor->render.angle * 1000.0f));
}
actor->render.instant.Set(1, static_cast<int>(actor->GetInstant(1)) + 1);
}
// OFFSET: 0x00D2D8D0
// FUNCTION: fn_21721
void CGameMode::ReceiveInventoryItemUpdate(const unsigned char* packet) {
ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, *reinterpret_cast<const std::uint16_t*>(packet + 2));
if (item.unknown_0000[1] != 0) {
item.unknown_0074[0] = *reinterpret_cast<const unsigned char*>(packet + 4) == 0;
g_session.UpdateInventoryItem(item, 1);
}
}
// OFFSET: 0x00D78030
// FUNCTION: fn_22157
void CGameMode::OpenWindow154() {
if (g_windowMgr.LookupWindow(0x154) == nullptr) {
g_windowMgr.EnsureWindow(0x154);
}
}
// OFFSET: 0x00D2D990
// FUNCTION: fn_21722
void CGameMode::ReceiveUnknownD2D990(const unsigned char*) {
if (g_windowMgr.unknown_03F8) {
g_windowMgr.CloseWindow(137);
GetRagConnection().Close();
if (reinterpret_cast<WindowDialogs*>(&g_windowMgr)->Confirm(LookupMessage(1349), 0, true, true, 0, "Message", 280, 120, 0) != 269) {
this->SendMsg(141, 0, 0, 0, 0);
}
}
}
// OFFSET: 0x00D4E3F0
// FUNCTION: fn_21876
void CGameMode::ReceiveUnknownD4E3F0(const unsigned char* packet) {
unsigned int count = *reinterpret_cast<const std::uint16_t*>(packet + 2) - 4;
UIWindow* window = g_windowMgr.EnsureWindow(0x49);
window->SendMsg(nullptr, 0x4B, 0, 0, 0, 0);
count >>= 1;
const std::int16_t* ids = reinterpret_cast<const std::int16_t*>(packet + 4);
for (unsigned int index = count; index != 0; --index, ++ids) {
ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, *ids);
if (item.unknown_0000[1] != 0) {
window->SendMsg(nullptr, 0x1F, reinterpret_cast<std::intptr_t>(item.itemId.c_str()), item.unknown_0000[1], 0, 0);
}
}
window->SendMsg(nullptr, 0x3C, 0, 0, 0, 0);
}
// OFFSET: 0x00D4E2A0
// FUNCTION: fn_21875
void CGameMode::ReceiveUnknownD4E2A0(const unsigned char* packet) {
unsigned int count = *reinterpret_cast<const std::uint16_t*>(packet + 2) - 4;
UIWindow* window = g_windowMgr.EnsureWindow(0x4A);
window->SendMsg(nullptr, 0x4B, 0, 0, 0, 0);
window->SendMsg(nullptr, 0x4D, *reinterpret_cast<const int*>(this->unknown_045C), 0, 0, 0);
count >>= 1;
const std::int16_t* ids = reinterpret_cast<const std::int16_t*>(packet + 4);
for (unsigned int index = count; index != 0; --index, ++ids) {
ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, *ids);
if (item.unknown_0000[1] != 0) {
window->SendMsg(nullptr, 0x1F, reinterpret_cast<std::intptr_t>(item.itemId.c_str()), item.unknown_0000[1], 0, 0);
}
}
window->SendMsg(nullptr, 0x3C, 0, 0, 0, 0);
}
// OFFSET: 0x00D75960
// FUNCTION: fn_22149
void CGameMode::ReceiveNotifySkill(const unsigned char* packet) {
ActorSkillMessage message;
message.unknown_0000 = *reinterpret_cast<const std::uint16_t*>(packet + 2);
message.unknown_0004 = *reinterpret_cast<const std::int32_t*>(packet + 0x18);
message.unknown_0008 = packet[0x20];
message.unknown_000C = *reinterpret_cast<const std::uint32_t*>(packet + 8);
message.unknown_0010 = *reinterpret_cast<const std::uint32_t*>(packet + 0xC);
message.unknown_0014 = *reinterpret_cast<const std::int16_t*>(packet + 0x1C);
message.unknown_0018 = *reinterpret_cast<const std::int16_t*>(packet + 0x1E);
message.unknown_001C = -1;
message.unknown_0020 = -1;
message.unknown_0024 = *reinterpret_cast<const std::uint32_t*>(packet + 0x10);
message.unknown_0028 = *reinterpret_cast<const std::uint32_t*>(packet + 0x14);
const std::uint16_t skillId = *reinterpret_cast<const std::uint16_t*>(packet + 2);
const std::uint32_t sourceAid = *reinterpret_cast<const std::uint32_t*>(packet + 4);
const std::uint32_t targetAid = *reinterpret_cast<const std::uint32_t*>(packet + 8);
CGameActor* gameActor = nullptr;
CGameActor* source = nullptr;
int job = -1;
if (skillId == 0x8C2 && targetAid == g_session.m_aid) {
return;
}
CGameActor* target;
if (targetAid == g_session.m_aid) {
target = this->scene->player;
} else {
target = static_cast<CGameActor*>(this->scene->GetGameActorByAID(targetAid));
}
if (sourceAid == g_session.m_aid) {
const std::int64_t value = reinterpret_cast<std::intptr_t>(&message);
this->scene->player->SendMsg(nullptr, 0x25, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
source = this->scene->player;
job = source->GetEffectiveJob(-1);
} else {
gameActor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(sourceAid));
if (gameActor != nullptr) {
const std::int64_t value = reinterpret_cast<std::intptr_t>(&message);
gameActor->SendMsg(nullptr, 0x25, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
source = gameActor;
job = source->GetEffectiveJob(-1);
} else if (CRenderObject* skill = this->scene->GetSkillByAID(sourceAid)) {
const std::int64_t value = reinterpret_cast<std::intptr_t>(&message);
skill->SendMsg(nullptr, 0x25, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
CRenderObject* targetSkill;
if (target == nullptr) {
targetSkill = this->scene->GetSkillByAID(targetAid);
} else {
targetSkill = nullptr;
}
CSkillActionMgr::GetInstance()->ActionSlot15(
skillId, reinterpret_cast<int>(source), target, static_cast<CGameActor*>(targetSkill)
);
const vector3d origin{0.0f, 0.0f, 0.0f};
int effectId;
if (target != nullptr && source != nullptr) {
switch (skillId) {
case 0x2E1:
case 0x911:
case 0x96D: {
effectId = skillId == 0x96D ? 0x62F : 0x593;
const int duration = static_cast<int>(source->render.speed * 100.0f + 100.0f);
CEffect* effect = g_effectMgr->Spawn(target->render.accountId, effectId, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(duration);
}
break;
}
case 0x2C4:
target->LaunchEffect(0x5C, origin, 0.0f);
source->Slot15(7, 1);
break;
case 0x2ED:
if (source == this->scene->player) {
source->LaunchEffect(0x461, origin, 0.0f);
}
if (target == this->scene->player) {
target->LaunchEffect(0x461, origin, 0.0f);
}
break;
case 0x296:
case 0x300:
if (source != target) {
target->LaunchEffect(0x174, origin, 0.0f);
}
break;
case 0x7D3:
source->Slot15(2, 1);
target->LaunchEffect(0xB7, origin, 0.0f);
break;
case 0x8A5:
if (g_serviceOptions.Get(0xE5)) {
g_effectMgr->Spawn(target->render.accountId, 0x5FE, origin.x, origin.y, origin.z, 0, -1, 0, 0);
effectId = 0x5FF;
} else {
g_effectMgr->Spawn(target->render.accountId, 0x585, origin.x, origin.y, origin.z, 0, -1, 0, 0);
effectId = 0x586;
}
g_effectMgr->Spawn(target->render.accountId, effectId, origin.x, origin.y, origin.z, 0, -1, 0, 0);
source->Slot15(7, 1);
break;
case 0x996:
g_effectMgr->Spawn(target->render.accountId, 0x619, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_effectMgr->Spawn(target->render.accountId, 0x61A, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x9AD: {
CEffect* effect;
if (g_serviceOptions.Get(0xE5)) {
effect = g_effectMgr->Spawn(source->render.accountId, 0x5DA, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(200);
}
effect = g_effectMgr->Spawn(target->render.accountId, 0x5D8, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(400);
}
effectId = 0x5D9;
} else {
effect = g_effectMgr->Spawn(source->render.accountId, 0x550, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(200);
}
effect = g_effectMgr->Spawn(source->render.accountId, 0x551, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(200);
}
effect = g_effectMgr->Spawn(target->render.accountId, 0x54E, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(400);
}
effectId = 0x54F;
}
effect = g_effectMgr->Spawn(target->render.accountId, effectId, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(400);
}
break;
}
case 0x14C3:
g_effectMgr->Spawn(
source->render.accountId, 0x86A, source->render.position.x, source->render.position.y, source->render.position.z,
target->render.accountId, -1, 0, 0
);
break;
case 0x1F78: {
CGameMode* mode = static_cast<CGameMode*>(g_modeMgr.GetGameMode());
const vector3d from = source->render.position;
const vector3d to = target->render.position;
const float yaw = mode->CameraDesiredYaw();
const float heading = static_cast<float>(std::atan2(static_cast<double>(to.z - from.z), static_cast<double>(to.x - from.x)));
const float angle = 360.0f - (heading / 3.141592f * 180.0f + yaw);
CEffect* effect = g_effectMgr->Spawn(source->render.accountId, 0x91F, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot17(angle);
}
break;
}
}
}
if (source != nullptr && skillId == 0x89B) {
source->Slot15(7, 1);
}
if (target != nullptr) {
switch (skillId) {
case 0x8D:
if (*reinterpret_cast<const std::int16_t*>(packet + 0x1C) == -1) {
target->LaunchEffect(0x81, origin, 0.0f);
}
break;
case 0x2DB:
case 0x7D8: {
CGameMode* mode = static_cast<CGameMode*>(g_modeMgr.GetGameMode());
if (mode == nullptr || source == nullptr) {
break;
}
float angle = mode->CameraDesiredYaw() + source->render.angle;
if (angle >= 360.0f) {
angle -= 360.0f;
}
int directionId;
if (angle > 0.0f && angle < 90.0f) {
directionId = 0x565;
} else if (angle >= 90.0f && angle < 180.0f) {
directionId = 0x564;
} else if (angle >= 180.0f && angle < 270.0f) {
directionId = 0x567;
} else {
directionId = 0x566;
}
CEffect* effect;
if (g_serviceOptions.Get(0xE5)) {
directionId += 0x8D;
if (g_effectMgr->Find(source->render.accountId, directionId) == nullptr) {
effect = g_effectMgr->Spawn(source->render.accountId, directionId, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(200);
}
}
effectId = 0x5F0;
} else {
if (g_effectMgr->Find(source->render.accountId, directionId) == nullptr) {
effect = g_effectMgr->Spawn(source->render.accountId, directionId, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(200);
}
}
effect = g_effectMgr->Spawn(target->render.accountId, 0x562, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(350);
}
effectId = 0x563;
}
effect = g_effectMgr->Spawn(target->render.accountId, effectId, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(350);
}
g_soundMgr->PlayWave("effect\\폭염룡.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
break;
}
case 0x138C: {
CGameMode* mode = static_cast<CGameMode*>(g_modeMgr.GetGameMode());
if (mode == nullptr || source == nullptr) {
break;
}
float angle = mode->CameraDesiredYaw() + source->render.angle;
if (angle >= 360.0f) {
angle -= 360.0f;
}
int directionId;
if (angle > 0.0f && angle < 90.0f) {
directionId = 0x56D;
} else if (angle >= 90.0f && angle < 180.0f) {
directionId = 0x56C;
} else if (angle >= 180.0f && angle < 270.0f) {
directionId = 0x56F;
} else {
directionId = 0x56E;
}
CEffect* effect;
if (g_serviceOptions.Get(0xE5)) {
directionId += 0x8B;
if (g_effectMgr->Find(source->render.accountId, directionId) == nullptr) {
effect = g_effectMgr->Spawn(source->render.accountId, directionId, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(200);
}
}
effectId = 0x5F6;
} else {
if (g_effectMgr->Find(source->render.accountId, directionId) == nullptr) {
effect = g_effectMgr->Spawn(source->render.accountId, directionId, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(200);
}
}
effect = g_effectMgr->Spawn(target->render.accountId, 0x56A, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(350);
}
effectId = 0x56B;
}
effect = g_effectMgr->Spawn(target->render.accountId, effectId, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(350);
}
g_soundMgr->PlayWave("effect\\폭염룡.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
break;
}
case 0x7D5:
if (target != source) {
g_effectMgr->Spawn(target->render.accountId, 0x69D, origin.x, origin.y, origin.z, 0, -1, 0, 0);
}
break;
case 0x89C: {
const float step = static_cast<float>(std::max(std::rand() % 5, 0) + 8) * 10.0f;
for (int index = 0; index < 3; ++index) {
const float radius = static_cast<float>(std::max(std::rand() % 10, 0)) + 5.0f;
matrix rotation;
rotation.MakeYRotation(static_cast<float>(index) * step / 180.0f * 3.141592f);
vector3d position;
position.x = radius * rotation.values[0] + rotation.values[3] * origin.x + rotation.values[6] * origin.x
+ rotation.values[9] + target->render.position.x;
position.y = radius * rotation.values[1] + rotation.values[4] * origin.x + rotation.values[7] * origin.x
+ rotation.values[10] + target->render.position.y;
position.z = radius * rotation.values[2] + rotation.values[5] * origin.x + rotation.values[8] * origin.x
+ rotation.values[11] + target->render.position.z;
const int kind = std::max(std::rand() % 3, 0);
int id;
if (kind == 0) {
id = 0x5A3;
} else {
id = (kind != 1) + 0x5A4;
}
if (g_serviceOptions.Get(0xE5)) {
id += 0x61;
}
g_effectMgr->Spawn(0, id, position.x, position.y, position.z, 0, -1, 0, 0);
}
break;
}
case 0x8BE:
g_soundMgr->PlayWave("effect\\hunter_shockwavetrap.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
target->LaunchEffect(0x92, origin, 0.0f);
break;
case 0x8BF:
target->LaunchEffect(0x249, origin, 0.0f);
g_soundMgr->PlayWave("effect\\hunter_landmine.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
break;
case 0x8CD:
target->LaunchEffect(0x247, origin, 0.0f);
g_soundMgr->PlayWave("effect\\폭염룡.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
break;
case 0x8CE:
target->LaunchEffect(0x87, origin, 0.0f);
g_soundMgr->PlayWave("effect\\ef_frostdiver.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
break;
case 0x8D3:
target->LaunchEffect(0x247, origin, 0.0f);
target->LaunchEffect(0x31, origin, 0.0f);
g_soundMgr->PlayWave("effect\\폭염룡.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
break;
case 0x8D5: {
for (int duration = 90; duration < 450; duration += 90) {
const float x = target->render.position.x;
const float y = target->render.position.y;
const float z = target->render.position.z;
int dx = std::max(std::rand() % 3, 0) * 5;
int dz = std::max(std::rand() % 3, 0) * 5;
const int direction = std::max(std::rand() % 4, 0);
if (dx == 10 && dz == 10) {
if (std::max(std::rand() % 2, 0) == 0) {
dx = 5;
} else {
dz = 5;
}
}
if (direction == 0) {
dx = -dx;
} else if (direction == 1) {
dz = -dz;
} else if (direction == 2) {
dx = -dx;
dz = -dz;
}
const vector3d position{static_cast<float>(dx) + x, y, static_cast<float>(dz) + z};
CEffect* effect;
if (g_serviceOptions.Get(0xE5)) {
effect = g_effectMgr->Spawn(0, 0x5D2, position.x, position.y, position.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(duration);
}
effectId = 0x5D3;
} else {
effect = g_effectMgr->Spawn(0, 0x54B, position.x, position.y, position.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(duration);
}
effectId = 0x54C;
}
effect = g_effectMgr->Spawn(0, effectId, position.x, position.y, position.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(duration);
}
}
if (g_serviceOptions.Get(0xE5)) {
g_effectMgr->Spawn(target->render.accountId, 0x5D2, origin.x, origin.y, origin.z, 0, -1, 0, 0);
effectId = 0x5D3;
} else {
g_effectMgr->Spawn(target->render.accountId, 0x54B, origin.x, origin.y, origin.z, 0, -1, 0, 0);
effectId = 0x54C;
}
g_effectMgr->Spawn(target->render.accountId, effectId, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_soundMgr->PlayWave("effect\\폭염룡.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
break;
}
case 0x900:
if (g_serviceOptions.Get(0xE5)) {
g_effectMgr->Spawn(target->render.accountId, 0x5B7, origin.x, origin.y, origin.z, 0, -1, 0, 0);
effectId = 0x5B8;
} else {
g_effectMgr->Spawn(target->render.accountId, 0x520, origin.x, origin.y, origin.z, 0, -1, 0, 0);
effectId = 0x521;
}
g_effectMgr->Spawn(target->render.accountId, effectId, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x919: {
CEffect* effect = g_effectMgr->Spawn(target->render.accountId, 0x624, origin.x, origin.y, origin.z, 0, -1, 0, 0);
if (effect) {
effect->Slot16(100);
}
break;
}
case 0x9B1:
g_soundMgr->PlayWave("effect\\폭염룡.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
target->LaunchEffect(0x385, origin, 0.0f);
break;
case 0x9BA:
g_effectMgr->Spawn(target->render.accountId, 0x551, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_soundMgr->PlayWave("spore_attack.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
break;
case 0x9D5:
g_effectMgr->Spawn(target->render.accountId, 0x62C, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x1499:
g_effectMgr->Spawn(target->render.accountId, 0x720, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_effectMgr->Spawn(target->render.accountId, 0x721, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x14AE:
g_effectMgr->Spawn(target->render.accountId, 0x748, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_effectMgr->Spawn(target->render.accountId, 0x749, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x1F6F:
g_effectMgr->Spawn(target->render.accountId, 0x919, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x1F70:
g_effectMgr->Spawn(target->render.accountId, 0x916, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_effectMgr->Spawn(target->render.accountId, 0x917, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x1F72:
g_effectMgr->Spawn(target->render.accountId, 0x921, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x1F75:
g_effectMgr->Spawn(target->render.accountId, 0x912, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x1F76:
g_effectMgr->Spawn(target->render.accountId, 0x913, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_effectMgr->Spawn(target->render.accountId, 0x914, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x20FD:
g_effectMgr->Spawn(target->render.accountId, 0x7F3, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_effectMgr->Spawn(target->render.accountId, 0x7F4, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x2100:
g_effectMgr->Spawn(target->render.accountId, 0x7E3, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_effectMgr->Spawn(target->render.accountId, 0x7E4, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x2103:
g_effectMgr->Spawn(target->render.accountId, 0x832, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_effectMgr->Spawn(target->render.accountId, 0x833, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x2106:
g_effectMgr->Spawn(target->render.accountId, 0x838, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x2109:
g_effectMgr->Spawn(target->render.accountId, 0x7D9, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x2199:
g_effectMgr->Spawn(target->render.accountId, 0x78E, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_effectMgr->Spawn(target->render.accountId, 0x791, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x219A:
g_effectMgr->Spawn(target->render.accountId, 0x77B, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_effectMgr->Spawn(target->render.accountId, 0x77D, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
case 0x219D:
g_effectMgr->Spawn(target->render.accountId, 0x772, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_effectMgr->Spawn(target->render.accountId, 0x773, origin.x, origin.y, origin.z, 0, -1, 0, 0);
g_effectMgr->Spawn(target->render.accountId, 0x775, origin.x, origin.y, origin.z, 0, -1, 0, 0);
break;
}
}
if (source != nullptr) {
if (g_session.IsMonsterActor(source) == 0) {
this->SendMsg(0x56, skillId, reinterpret_cast<std::intptr_t>(source), *reinterpret_cast<const std::int16_t*>(packet + 0x1C), 0);
return;
}
const unsigned char kind = source->unknown_0314;
if (kind == 10 || kind == 13 || kind == 14) {
this->SendMsg(0x56, skillId, reinterpret_cast<std::intptr_t>(source), *reinterpret_cast<const std::int16_t*>(packet + 0x1C), 0);
}
}
int action;
int loopType;
g_session.GetMonsterSkillInfo(g_session.GetJobName(job, -1), message.unknown_0000, &action, &loopType, *reinterpret_cast<WindowDialogs*>(&g_windowMgr));
if (action != -1 && gameActor != nullptr) {
gameActor->SetAction(action * 8 - 8, 1, loopType == 0);
}
}
// OFFSET: 0x00D77850
// FUNCTION: fn_22150
void CGameMode::ReceiveActorSkillAction(const unsigned char* packet) {
ActorSkillMessage message;
message.unknown_0000 = *reinterpret_cast<const std::uint16_t*>(packet + 2);
message.unknown_0004 = *reinterpret_cast<const std::int16_t*>(packet + 0x18);
message.unknown_0008 = packet[0x1E];
message.unknown_000C = *reinterpret_cast<const std::uint32_t*>(packet + 8);
message.unknown_0010 = *reinterpret_cast<const std::uint32_t*>(packet + 0xC);
message.unknown_0014 = *reinterpret_cast<const std::int16_t*>(packet + 0x1A);
message.unknown_0018 = *reinterpret_cast<const std::int16_t*>(packet + 0x1C);
message.unknown_001C = -1;
message.unknown_0020 = -1;
message.unknown_0024 = *reinterpret_cast<const std::uint32_t*>(packet + 0x10);
message.unknown_0028 = *reinterpret_cast<const std::uint32_t*>(packet + 0x14);
CGameActor* actor = nullptr;
CGameActor* gameActor = nullptr;
int job = -1;
if (*reinterpret_cast<const std::uint32_t*>(packet + 4) == g_session.m_aid) {
actor = this->scene->player;
const std::int64_t value = reinterpret_cast<std::intptr_t>(&message);
actor->SendMsg(nullptr, 0x25, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
job = actor->GetEffectiveJob(-1);
} else {
gameActor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(*reinterpret_cast<const std::uint32_t*>(packet + 4)));
if (gameActor != nullptr) {
actor = gameActor;
const std::int64_t value = reinterpret_cast<std::intptr_t>(&message);
actor->SendMsg(nullptr, 0x25, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
job = actor->GetEffectiveJob(-1);
} else if (CRenderObject* skill = this->scene->GetSkillByAID(*reinterpret_cast<const std::uint32_t*>(packet + 4))) {
const std::int64_t value = reinterpret_cast<std::intptr_t>(&message);
skill->SendMsg(nullptr, 0x25, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
if (g_session.IsMonsterActor(actor) == 0) {
this->SendMsg(0x56, *reinterpret_cast<const std::uint16_t*>(packet + 2), reinterpret_cast<std::intptr_t>(actor), *reinterpret_cast<const std::int16_t*>(packet + 0x1A), 0);
return;
}
int action;
int loopType;
g_session.GetMonsterSkillInfo(g_session.GetJobName(job, -1), message.unknown_0000, &action, &loopType, *reinterpret_cast<WindowDialogs*>(&g_windowMgr));
if (action != -1 && gameActor != nullptr) {
gameActor->SetAction(action * 8 - 8, 1, loopType == 0);
}
}
// OFFSET: 0x00D77A30
// FUNCTION: fn_22151
void CGameMode::ReceiveActorSkillMessage(const unsigned char* packet) {
ActorSkillMessage message;
message.unknown_0000 = *reinterpret_cast<const std::uint16_t*>(packet + 2);
message.unknown_0004 = *reinterpret_cast<const std::int16_t*>(packet + 0x1C);
message.unknown_0008 = packet[0x22];
message.unknown_000C = *reinterpret_cast<const std::uint32_t*>(packet + 8);
message.unknown_0010 = *reinterpret_cast<const std::uint32_t*>(packet + 0xC);
message.unknown_0014 = *reinterpret_cast<const std::int16_t*>(packet + 0x1E);
message.unknown_0018 = *reinterpret_cast<const std::int16_t*>(packet + 0x20);
message.unknown_001C = *reinterpret_cast<const std::int16_t*>(packet + 0x18);
message.unknown_0020 = *reinterpret_cast<const std::int16_t*>(packet + 0x1A);
message.unknown_0024 = *reinterpret_cast<const std::uint32_t*>(packet + 0x10);
message.unknown_0028 = *reinterpret_cast<const std::uint32_t*>(packet + 0x14);
CGameActor* actor = nullptr;
int job = -1;
if (*reinterpret_cast<const std::uint32_t*>(packet + 4) == g_session.m_aid) {
actor = this->scene->player;
const std::int64_t value = reinterpret_cast<std::intptr_t>(&message);
actor->SendMsg(nullptr, 0x25, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
job = actor->GetEffectiveJob(-1);
} else {
actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(*reinterpret_cast<const std::uint32_t*>(packet + 4)));
if (actor != nullptr) {
const std::int64_t value = reinterpret_cast<std::intptr_t>(&message);
actor->SendMsg(nullptr, 0x25, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
job = actor->GetEffectiveJob(-1);
} else if (CRenderObject* skill = this->scene->GetSkillByAID(*reinterpret_cast<const std::uint32_t*>(packet + 4))) {
const std::int64_t value = reinterpret_cast<std::intptr_t>(&message);
skill->SendMsg(nullptr, 0x25, 0, static_cast<int>(value), static_cast<int>(value >> 32), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor = nullptr;
}
}
if (g_session.IsMonsterActor(actor) == 0) {
this->SendMsg(0x56, *reinterpret_cast<const std::uint16_t*>(packet + 2), reinterpret_cast<std::intptr_t>(actor), *reinterpret_cast<const std::int16_t*>(packet + 0x1E), 0);
return;
}
int action;
int loopType;
g_session.GetMonsterSkillInfo(g_session.GetJobName(job, -1), message.unknown_0000, &action, &loopType, *reinterpret_cast<WindowDialogs*>(&g_windowMgr));
}
// OFFSET: 0x00D25310
// FUNCTION: fn_21672
void CGameMode::ReceiveItem1740List(const unsigned char* packet) {
const int length = *reinterpret_cast<const std::int16_t*>(packet + 2);
const int count = static_cast<int>(static_cast<unsigned int>(length - 4) / sizeof(StoreNormalRecord));
const auto* record = reinterpret_cast<const StoreNormalRecord*>(packet + 4);
for (int index = count; index > 0; --index, ++record) {
ITEM_INFO item;
item.unknown_0000[0] = record->type;
item.unknown_0000[1] = record->index;
item.unknown_0000[2] = 0;
item.unknown_0000[3] = record->location;
item.quantity = record->amount;
std::memcpy(item.unknown_001C, record->cards, sizeof(record->cards));
item.SetItemId(record->itemId);
item.unknown_005D = 0;
item.identified = record->flags & 1;
item.unknown_0060 = 0;
item.unknown_0068 = record->expireTime;
item.unknown_0074[0] = (record->flags >> 1) & 1;
reinterpret_cast<ClientItemLists*>(&g_session)->AddItem1740(item);
}
g_session.RefreshItem1740Window();
}
// OFFSET: 0x00D270B0
// FUNCTION: fn_21687
void CGameMode::ReceiveDispel(const unsigned char* packet) {
const auto* dispel = reinterpret_cast<const DispelPacket*>(packet);
if (dispel->aid == g_session.m_aid) {
this->scene->player->SendMsg(nullptr, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
this->scene->player->SendMsg(nullptr, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
this->scene->player->SendMsg(nullptr, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
CPlayer* player = this->scene->player;
if (player->render.unknown_0070 == 8) {
player->Slot15(0, 1);
}
return;
}
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(dispel->aid));
if (actor == nullptr) {
return;
}
actor->SendMsg(nullptr, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor->SendMsg(nullptr, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
actor->SendMsg(nullptr, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
g_effectMgr->Retire(dispel->aid, 1114);
if (actor->render.unknown_0070 == 8) {
actor->Slot15(0, 1);
}
}
// OFFSET: 0x00D32E10
// FUNCTION: fn_21748
void CGameMode::ReceiveItem1758List(const unsigned char* packet) {
if (g_replayAnimationScaling == 0) {
reinterpret_cast<UIMerchantShopMakeWnd*>(g_windowMgr.unknown_040C)->PrintBuyList();
}
reinterpret_cast<ClientItemLists*>(&g_session)->ClearItems1768();
g_windowMgr.CloseWindow(0xAE);
g_windowMgr.CloseWindow(0xAF);
reinterpret_cast<ClientItemLists*>(&g_session)->ClearItems1758();
const int count = static_cast<unsigned int>(static_cast<int>(*reinterpret_cast<const std::int16_t*>(packet + 2)) - 12) / 11u;
const Item1758Record* record = reinterpret_cast<const Item1758Record*>(packet + 12);
for (int index = 0; index < count; ++index, ++record) {
const Item1758Record entry = *record;
ITEM_INFO item;
item.unknown_0014[0] = entry.price;
item.unknown_0014[1] = entry.price;
item.quantity = entry.quantity;
item.unknown_0000[0] = entry.type;
item.unknown_0000[1] = index + 1;
item.identified = 1;
item.SetItemId(entry.itemId);
reinterpret_cast<ClientItemLists*>(&g_session)->AddItem1758(item);
}
UIWindow* window = g_windowMgr.EnsureWindow(0xB0);
window->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
window->SendMsg(nullptr, 0x77, *reinterpret_cast<const int*>(packet + 8), 0, 0, 0);
this->unknown_024C = 1;
}
// OFFSET: 0x00D50810
// FUNCTION: fn_21886
void CGameMode::ReceiveUnknownD50810(const unsigned char* packet) {
if (g_replayAnimationScaling != 0) {
g_modeMgr.GetGameMode()->SendMsg(82, 0, 0, 0, 0);
}
reinterpret_cast<ClientItemLists*>(&g_session)->ClearItems1758();
const int count = (*reinterpret_cast<const std::int16_t*>(packet + 2) - 8) / sizeof(Item1758StoreRecord);
if (count == 0) {
this->SendMsg(40, 0, 0, 0, 0);
g_windowMgr.CloseWindow(43);
g_windowMgr.CloseWindow(44);
reinterpret_cast<ClientItemLists*>(&g_session)->ClearItems1760And1748();
return;
}
const Item1758StoreRecord* record = reinterpret_cast<const Item1758StoreRecord*>(packet + 8);
for (int i = 0; i < count; ++i, ++record) {
ITEM_INFO item;
item.unknown_0000[0] = record->type;
item.unknown_0000[1] = record->index;
item.unknown_0014[0] = record->unknown_0000;
item.unknown_0014[1] = record->unknown_0000;
item.quantity = record->amount;
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_0098 = CountStoreItemOptions(record->options);
for (int index = 0; index < item.unknown_0098; ++index) {
reinterpret_cast<StoreItemOption*>(item.unknown_009C)[index] = record->options[index];
}
reinterpret_cast<ClientItemLists*>(&g_session)->AddItem1758(item);
}
}
// OFFSET: 0x00D50590
// FUNCTION: fn_21885
void CGameMode::ReceiveItem1748List(const unsigned char* packet) {
reinterpret_cast<ClientItemLists*>(&g_session)->ClearItems1748();
reinterpret_cast<ClientItemLists*>(&g_session)->ClearItems1760();
const int count = (*reinterpret_cast<const std::int16_t*>(packet + 2) - 0x0C) / sizeof(Item1748Record);
for (int i = 0; i < count; ++i) {
const Item1748Record record = *reinterpret_cast<const Item1748Record*>(packet + 0x0C + i * sizeof(Item1748Record));
ITEM_INFO item;
item.unknown_0000[0] = record.type;
item.unknown_0000[1] = record.index;
item.unknown_0000[2] = record.unknown_0039;
item.unknown_0014[0] = record.unknown_0000;
item.unknown_0014[1] = record.unknown_0000;
item.quantity = record.amount;
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_0070 = record.sprite;
item.unknown_0098 = CountStoreItemOptions(record.options);
for (int index = 0; index < item.unknown_0098; ++index) {
reinterpret_cast<StoreItemOption*>(item.unknown_009C)[index] = record.options[index];
}
reinterpret_cast<ClientItemLists*>(&g_session)->AddItem1748(item);
}
UIWindow* window = g_windowMgr.EnsureWindow(43);
window->SendMsg(nullptr, 23, 0, 0, 0, 0);
window->SendMsg(nullptr, 28, *reinterpret_cast<const std::int32_t*>(packet + 4), 0, 0, 0);
UIWindow* optionsWindow = g_windowMgr.EnsureWindow(44);
optionsWindow->SendMsg(nullptr, 23, 0, 0, 0, 0);
optionsWindow->SendMsg(nullptr, 28, *reinterpret_cast<const std::int32_t*>(packet + 4), *reinterpret_cast<const std::int32_t*>(packet + 8), 0, 0);
this->unknown_024C = 1;
}
// OFFSET: 0x00D5F5C0
// FUNCTION: fn_21970
void CGameMode::ReceiveActorStatusValue(std::uint32_t aid, int status, int amount, int option) {
CGameActor* actor;
if (aid == g_session.m_aid) {
actor = this->scene->player;
} else {
actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(aid));
}
if (actor == nullptr) {
return;
}
switch (status) {
case 0x14b:
if (aid == g_session.m_aid) {
reinterpret_cast<SessionMessengerContext*>(&g_session)->UpdateRandomStats();
const int hp = g_session.unknown_5568 + amount;
if (g_session.unknown_5568 != hp) {
g_session.unknown_5568 = hp;
g_session.RefreshHpSpWindows();
}
}
actor->SendMsg(nullptr, 0x58, 0, amount, option, 0xFF00FF00, 0, 0x72, 0, 0, 0, 0, 0, 0, 0);
break;
case 0x14c:
if (aid == g_session.m_aid) {
reinterpret_cast<SessionMessengerContext*>(&g_session)->UpdateRandomStats();
int& sp = *reinterpret_cast<int*>(&g_session.unknown_5570[0]);
const int value = sp + amount;
if (sp != value) {
sp = value;
g_session.RefreshHpSpWindows();
}
}
actor->SendMsg(nullptr, 0x58, 0, amount, option, 0xFF0000FF, 0, 0x72, 0, 0, 0, 0, 0, 0, 0);
break;
case 0x291:
actor->SendMsg(nullptr, 0x58, 0, amount, option, 0xFF00FF00, 0, 0x72, 0, 0, 0, 0, 0, 0, 0);
break;
case 0x292:
actor->SendMsg(nullptr, 0x58, 0, amount, option, 0xFF0000FF, 0, 0x72, 0, 0, 0, 0, 0, 0, 0);
break;
case 0x293:
actor->SendMsg(nullptr, 0x58, 0, amount, option, 0xFFFF0000, 0, 0x72, 0, 0, 0, 0, 0, 0, 0);
break;
case 0x294:
actor->SendMsg(nullptr, 0x58, 0, amount, option, 0xFFFF00FF, 0, 0x72, 0, 0, 0, 0, 0, 0, 0);
break;
case 0x295:
actor->SendMsg(nullptr, 0x58, 0, amount, option, 0xFF000000, 0, 0x72, 0, 0, 0, 0, 0, 0, 0);
break;
case 0x296:
actor->SendMsg(nullptr, 0x58, 0, amount, option, 0xFFFFFFFF, 0, 0x72, 0, 0, 0, 0, 0, 0, 0);
break;
case 0x297:
actor->SendMsg(nullptr, 0x58, 0, amount, option, 0xFFFFFF00, 0, 0x72, 0, 0, 0, 0, 0, 0, 0);
break;
case 0x298:
actor->SendMsg(nullptr, 0x58, 0, amount, option, 0xFFFF55B1, 0, 0x72, 0, 0, 0, 0, 0, 0, 0);
break;
default:
break;
}
CEffect* effect = g_effectMgr->Spawn(actor->render.accountId, status, actor->render.position.x, actor->render.position.y,
actor->render.position.z, 0, 0xFFFFFFFF, 0, 0);
if (effect == nullptr) {
actor->LaunchEffect(status, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
}
// OFFSET: 0x00D39BB0
// FUNCTION: fn_21773
void CGameMode::ReceiveItem1718List(const unsigned char* packet) {
reinterpret_cast<SessionItemLists*>(&g_session)->ClearTradeItems();
const std::int64_t count = (static_cast<std::int64_t>(*reinterpret_cast<const std::int16_t*>(packet + 2)) - 4) / 19;
const Item1718Record* record = reinterpret_cast<const Item1718Record*>(packet + 4);
for (std::int64_t index = 0; index < count; ++index) {
Item1718Record entry;
memcpy_s(&entry, sizeof(entry), &record[index], sizeof(entry));
RawItemBasic item = {};
_itoa(entry.itemId, item.itemId, 10);
item.unknown_0004 = entry.unknown_0005;
item.unknown_0008 = entry.unknown_0005;
item.unknown_000C = entry.type;
item.unknown_0034 = entry.unknown_000F;
item.id = -1;
item.identified = 1;
item.unknown_0038 = FindItemDescription(std::atoi(item.itemId)).unknown_0040;
reinterpret_cast<ClientItemLists*>(&g_session)->AddItem1718(item, entry.quantity, static_cast<std::uint16_t>(entry.unknown_000D / 10));
}
if (UIWindow* window = g_windowMgr.EnsureWindow(0xFE)) {
window->SendMsg(nullptr, 0x24, 0, 0, 0, 0);
window->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
}
if (UIWindow* window = g_windowMgr.EnsureWindow(0xFF)) {
window->SendMsg(nullptr, 0x24, 0, 0, 0, 0);
window->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
}
}
// OFFSET: 0x00D77C90
// FUNCTION: fn_22154
void ReceiveTradeItems(int count, const TradeItemRecord* records) {
reinterpret_cast<SessionItemLists*>(&g_session)->ClearTradeItems();
for (int i = 0; i < count; ++i) {
const TradeItemRecord& record = records[i];
ITEM_INFO item;
item.SetItemId(record.itemId);
item.unknown_0000[0] = record.unknown_0004;
item.unknown_006C = record.unknown_000D / 10;
item.quantity = record.quantity;
item.unknown_0014[0] = record.unknown_0005;
item.unknown_0014[1] = record.unknown_0005;
item.unknown_0060 = record.unknown_000F;
std::memcpy(item.unknown_001C, record.cards, sizeof(record.cards));
item.unknown_0000[1] = record.unknown_0020;
item.identified = 1;
item.unknown_0074[3] = 1;
if (item.quantity > 0) {
reinterpret_cast<ClientItemLists*>(&g_session)->AppendItem1718(item);
}
}
if (UIWindow* window = g_windowMgr.EnsureWindow(0xfe)) {
window->SendMsg(nullptr, 0x24, 0, 0, 0, 0);
window->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
}
if (UIWindow* window = g_windowMgr.EnsureWindow(0xff)) {
window->SendMsg(nullptr, 0x24, 0, 0, 0, 0);
window->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
}
}
// OFFSET: 0x00D7A690
// FUNCTION: fn_22191
void CGameMode::Zc_Spirits2(const unsigned char* data) {
if (!g_serviceOptions.Get(8)) {
return;
}
const auto* packet = reinterpret_cast<const ActorValuePacket*>(data);
CGameActor* actor;
if (packet->accountId == g_session.m_aid) {
actor = this->scene->player;
} else {
actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(packet->accountId));
}
if (!actor) {
return;
}
if (StateFlag01(actor->Slot13()) || StateFlag02(actor->Slot13())) {
int effectId;
switch (actor->GetEffectiveJob(-1)) {
case 24:
case 4215:
case 4228:
case 4229:
case 4306:
effectId = 629;
break;
case 4038:
effectId = 504;
break;
default:
effectId = 228;
break;
}
actor->SendMsg(nullptr, 109, 0, effectId, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
return;
}
CRagEffect* effect;
if (actor->GetEffectiveJob(-1) == 4038) {
if (actor->state.Attachments().HasId(504) || packet->accountId == 0) {
return;
}
effect = actor->LaunchEffect(504, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
} else if (actor->GetEffectiveJob(-1) == 24 || actor->GetEffectiveJob(-1) == 4215 || actor->GetEffectiveJob(-1) == 4228 ||
actor->GetEffectiveJob(-1) == 4229 || actor->GetEffectiveJob(-1) == 4306) {
if (actor->state.Attachments().HasId(629) || packet->accountId == 0) {
return;
}
effect = actor->LaunchEffect(629, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
} else {
if (actor->state.Attachments().HasId(228) || packet->accountId == 0) {
return;
}
effect = actor->LaunchEffect(228, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
vector3d count{static_cast<float>(packet->value), 0.0f, 0.0f};
if (effect) {
effect->SendMsg(nullptr, 14, 0, reinterpret_cast<int>(&count), 0, 0, 0, 0);
}
}
// OFFSET: 0x00D7A920
// FUNCTION: fn_22192
void CGameMode::UpdateActorSpiritCount(std::uint32_t aid, std::int16_t count) {
if (!aid) {
return;
}
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAidIncludeMe(aid));
if (!actor) {
return;
}
const int job = actor->GetEffectiveJob(-1);
switch (job) {
case 4252:
case 4265:
case 4280:
break;
case 4260:
if (count == 0) {
g_effectMgr->Retire(actor->render.accountId, 2109);
return;
}
break;
case 24:
case 4228:
actor->SendMsg(nullptr, 109, 0, 629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (count == 0) {
return;
}
break;
case 4038:
actor->SendMsg(nullptr, 109, 0, 504, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (count == 0) {
return;
}
break;
case 4215:
case 4229:
case 4306:
g_effectMgr->Retire(actor->render.accountId, 1135);
if (count == 0) {
return;
}
break;
default:
actor->SendMsg(nullptr, 109, 0, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (count == 0) {
return;
}
break;
}
if (StateFlag01(actor->Slot13()) || StateFlag02(actor->Slot13())) {
switch (job) {
case 4252:
case 4265:
case 4280:
g_effectMgr->Retire(g_effectMgr->Find(actor->render.accountId, 2460), 1);
return;
case 4260:
g_effectMgr->Retire(actor->render.accountId, 2109);
break;
}
}
CRagEffect* effect;
switch (job) {
case 24:
case 4228:
effect = actor->LaunchEffect(629, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
break;
case 4038:
effect = actor->LaunchEffect(504, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
break;
case 4215:
case 4229:
case 4306: {
CEffect* coins = g_effectMgr->Spawn(actor->render.accountId, 1135, actor->render.position.x, actor->render.position.y,
actor->render.position.z, 0, -1, 0, 0);
if (!coins) {
return;
}
static_cast<CRichsCoinEffect*>(coins)->unknown_00E4 = count;
coins->Slot01();
return;
}
case 4252:
case 4265:
case 4280: {
CServantWeaponNewEffect* weapons =
static_cast<CServantWeaponNewEffect*>(g_effectMgr->Spawn(actor->render.accountId, 2460, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0));
if (!weapons) {
return;
}
const int current = static_cast<int>(weapons->emitters.size());
if (current < count) {
for (int remaining = count - current; remaining != 0; --remaining) {
weapons->AddWeapon();
}
} else if (current > count) {
for (int remaining = current - count; remaining != 0; --remaining) {
weapons->Shoot(5202);
}
}
return;
}
case 4260: {
CEffect* abyss = g_effectMgr->Find(actor->render.accountId, 2109);
if (!abyss) {
abyss = g_effectMgr->Spawn(actor->render.accountId, 2109, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
}
if (abyss) {
static_cast<CFromTheAbyssEffect*>(abyss)->SetLevel(count);
}
for (auto it = g_activeSkillEffects.begin(); it != g_activeSkillEffects.end(); ++it) {
if (it->id == 1244) {
it->unknown_0008 = count;
break;
}
}
return;
}
default:
effect = actor->LaunchEffect(228, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
break;
}
if (effect && (effect->state.type == 228 || effect->state.type == 504 || effect->state.type == 629)) {
vector3d value{static_cast<float>(count), 0.0f, 0.0f};
effect->SendMsg(nullptr, 14, 0, reinterpret_cast<int>(&value), 0, 0, 0, 0);
}
}
#pragma pack(push, 1)
struct BuyingStoreItemRecord {
/* 0000 */ std::uint32_t price;
/* 0004 */ std::int16_t count;
/* 0006 */ unsigned char type;
/* 0007 */ std::int32_t itemId;
};
#pragma pack(pop)
// OFFSET: 0x00D1CFF0
// FUNCTION: fn_21628
void CGameMode::ReceiveBuyingStoreItemList(const unsigned char* packet) {
ClientItemLists* lists = reinterpret_cast<ClientItemLists*>(&g_session);
lists->ClearItems1748();
lists->ClearItems1760();
const BuyingStoreItemRecord* record = reinterpret_cast<const BuyingStoreItemRecord*>(packet + 16);
const unsigned count = (static_cast<int>(*reinterpret_cast<const std::int16_t*>(packet + 2)) - 16u) / 11;
for (int index = 0; index < static_cast<int>(count);) {
const BuyingStoreItemRecord entry = *record;
ITEM_INFO item;
++index;
item.unknown_0014[0] = entry.price;
item.unknown_0014[1] = entry.price;
item.unknown_0000[0] = entry.type;
item.quantity = entry.count;
item.identified = 1;
item.unknown_0000[1] = index;
item.SetItemId(entry.itemId);
lists->AddItem1748(item);
++record;
}
UIWindow* window = g_windowMgr.EnsureWindow(0xB1);
window->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
window->SendMsg(nullptr, 0x1C, *reinterpret_cast<const std::int32_t*>(packet + 4), 0, 0, 0);
window->SendMsg(nullptr, 0x77, *reinterpret_cast<const std::int32_t*>(packet + 12), 0, 0, 0);
window = g_windowMgr.EnsureWindow(0xB2);
window->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
window->SendMsg(nullptr, 0x1C, *reinterpret_cast<const std::int32_t*>(packet + 4), *reinterpret_cast<const std::int32_t*>(packet + 8), 0, 0);
window = reinterpret_cast<UIWindow*>(g_windowMgr.unknown_0420);
if (window) {
g_session.RefreshItems1750();
window->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
} else if ((window = g_windowMgr.EnsureWindow(0xB3)) != nullptr) {
window->SendMsg(nullptr, 0x17, 0, 0, 0, 0);
}
this->unknown_024C = 1;
}
#include "Contents/Jobs/JobInheritance.h"
// OFFSET: 0x00D5F3E0
// FUNCTION: fn_21969
void CGameMode::SetActorNameCard(std::uint32_t id, const char* name, const char* value1, const char* value2, const char* value3, int job) {
if (id == g_session.m_aid) {
g_session.unknown_615C = job;
}
std::string jobTitle = GetJobTitleString(job);
this->nameCard.Set(id, name, value1, value2, value3, jobTitle, std::string(), 0);
}
// OFFSET: 0x00D79BB0
// FUNCTION: fn_22180
void CGameMode::ReceiveShopName(const char* text, int shopId) {
std::string name = text;
name.resize(name.size() - 4);
if (!g_session.AddShopName(name, shopId)) {
ValuePacket packet;
packet.id = 0x0BBD;
packet.value = shopId;
GetRagConnection().Send(g_packetLengths.FixedLength(packet.id), &packet);
}
}
void SetPlayerName(std::uint32_t id, std::string name);
namespace {
struct FriendRecord {
/* 0000 */ std::uint32_t accountId;
/* 0004 */ std::uint32_t characterId;
/* 0008 */ char name[24];
};
static_assert(sizeof(FriendRecord) == 0x20);
}
// OFFSET: 0x00D2AB70
// FUNCTION: fn_21706
void CGameMode::ReceiveFriendList(const unsigned char* packet) {
ClientMessenger messenger{g_session.m_partyMembers, g_session.m_friends};
messenger.ClearFriends();
const std::int64_t length = *reinterpret_cast<const std::uint16_t*>(packet + 2);
if (length == 4) {
return;
}
const std::int64_t count = (length - 4) / static_cast<std::int64_t>(sizeof(FriendRecord));
const FriendRecord* records = reinterpret_cast<const FriendRecord*>(packet + 4);
for (std::int64_t index = 0; index < count; ++index) {
FriendRecord record;
memcpy_s(&record, sizeof(record), &records[index], sizeof(record));
char name[25] = {};
StringFormat(name, sizeof(name), static_cast<std::size_t>(-1), "%s", record.name);
if (!g_playerNameDictionary->Contains(record.characterId)) {
std::string text(name, sizeof(name));
SetPlayerName(record.characterId, text.c_str());
}
MessengerMember member;
member.name = name;
member.accountId = record.accountId;
member.characterId = record.characterId;
member.offline = 1;
messenger.AddFriend(member);
}
g_session.RefreshWindow02C8();
}
namespace {
#pragma pack(push, 1)
struct SwapEquipmentRecord {
/* 0000 */ std::uint16_t index;
/* 0002 */ int location;
};
#pragma pack(pop)
static_assert(sizeof(SwapEquipmentRecord) == 6);
#pragma pack(push, 1)
struct StatusBonusPacket {
/* 0000 */ std::uint16_t packetType;
/* 0002 */ int type;
/* 0006 */ int value;
/* 000A */ int bonus;
};
#pragma pack(pop)
static_assert(sizeof(StatusBonusPacket) == 0xE);
}
namespace EquipmentProperties {
class CEquipmentPropertiesMgr {
public:
CEquipmentPropertiesMgr();
virtual ~CEquipmentPropertiesMgr();
static CEquipmentPropertiesMgr* GetInstance();
void RefreshPretend();
void RemoveExpansion(const int& kind, const int& itemId);
unsigned char unknown_0004[0x1F8];
};
}
// OFFSET: 0x00D4CAD0
// FUNCTION: fn_21869
void CGameMode::ReceiveStatusBonus(const unsigned char* data) {
const StatusBonusPacket* packet = reinterpret_cast<const StatusBonusPacket*>(data);
int* traitBonus = reinterpret_cast<int*>(g_session.unknown_7FC0 + 8);
switch (packet->type) {
case 13:
g_session.m_standardStats[0] = packet->value;
g_session.InvalidateWindowFrames();
g_session.unknown_166C = packet->bonus;
g_session.InvalidateWindowFrames();
break;
case 14:
g_session.m_standardStats[1] = packet->value;
g_session.InvalidateWindowFrames();
g_session.unknown_1670 = packet->bonus;
g_session.InvalidateWindowFrames();
break;
case 15:
g_session.m_standardStats[2] = packet->value;
g_session.InvalidateWindowFrames();
g_session.unknown_1674 = packet->bonus;
g_session.InvalidateWindowFrames();
break;
case 16:
g_session.m_standardStats[3] = packet->value;
g_session.InvalidateWindowFrames();
g_session.unknown_1678 = packet->bonus;
g_session.InvalidateWindowFrames();
break;
case 17:
g_session.m_standardStats[4] = packet->value;
g_session.InvalidateWindowFrames();
g_session.unknown_167C = packet->bonus;
g_session.InvalidateWindowFrames();
break;
case 18:
g_session.m_standardStats[5] = packet->value;
g_session.InvalidateWindowFrames();
g_session.unknown_1680 = packet->bonus;
g_session.InvalidateWindowFrames();
break;
case 219:
g_session.SetTraitStat(219, packet->value);
traitBonus[0] = packet->bonus;
g_session.InvalidateWindowFrames();
break;
case 220:
g_session.SetTraitStat(220, packet->value);
traitBonus[1] = packet->bonus;
g_session.InvalidateWindowFrames();
break;
case 221:
g_session.SetTraitStat(221, packet->value);
traitBonus[2] = packet->bonus;
g_session.InvalidateWindowFrames();
break;
case 222:
g_session.SetTraitStat(222, packet->value);
traitBonus[3] = packet->bonus;
g_session.InvalidateWindowFrames();
break;
case 223:
g_session.SetTraitStat(223, packet->value);
traitBonus[4] = packet->bonus;
g_session.InvalidateWindowFrames();
break;
case 224:
g_session.SetTraitStat(224, packet->value);
traitBonus[5] = packet->bonus;
g_session.InvalidateWindowFrames();
break;
}
switch (packet->type) {
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 219:
case 220:
case 221:
case 222:
case 223:
case 224:
if (g_equipmentPropertiesMgr == nullptr) {
g_equipmentPropertiesMgr = new (std::nothrow) EquipmentProperties::CEquipmentPropertiesMgr;
}
g_equipmentPropertiesMgr->RefreshPretend();
break;
}
}
// OFFSET: 0x00D27EC0
// OFFSET: 0x00D8A600
// FUNCTION: fn_22220
void CGameMode::ReceiveSwapEquipmentList(const unsigned char* data) {
g_session.ResetItems61B8();
g_session.ResetItems6B68();
const PacketLengthHeader* packet = reinterpret_cast<const PacketLengthHeader*>(data);
const int count = (packet->length - sizeof(PacketLengthHeader)) / sizeof(SwapEquipmentRecord);
const SwapEquipmentRecord* record = reinterpret_cast<const SwapEquipmentRecord*>(data + sizeof(PacketLengthHeader));
for (int i = 0; i < count; ++i, ++record) {
ITEM_INFO item = g_session.FindItemByIdentity(record->index, record->location);
item.unknown_0000[3] = record->location;
if (item.unknown_0000[1] == 0) {
break;
}
if (g_session.IsCostumeLocation(record->location)) {
reinterpret_cast<ClientItemLists*>(&g_session)->EquipItem6B68(item);
} else {
g_session.EquipItem61B8(item);
}
}
}
namespace {
#pragma pack(push, 1)
struct GuildMemberRecord {
/* 0000 */ int accountId;
/* 0004 */ int characterId;
/* 0008 */ std::int16_t unknown_0008;
/* 000A */ std::int16_t unknown_000A;
/* 000C */ std::int16_t unknown_000C;
/* 000E */ std::int16_t job;
/* 0010 */ std::int16_t level;
/* 0012 */ int exp;
/* 0016 */ int online;
/* 001A */ int positionId;
/* 001E */ int unknown_001E;
};
#pragma pack(pop)
static_assert(sizeof(GuildMemberRecord) == 0x22);
}
// OFFSET: 0x00D89F20
// FUNCTION: fn_22215
void CGameMode::ReceiveGuildMemberList(const unsigned char* data) {
GuildInfo* guildInfo = reinterpret_cast<GuildInfo*>(reinterpret_cast<char*>(&g_guildId) - offsetof(GuildInfo, m_guildId));
const PacketLengthHeader* packet = reinterpret_cast<const PacketLengthHeader*>(data);
const int count = (packet->length - sizeof(PacketLengthHeader)) / sizeof(GuildMemberRecord);
guildInfo->unknown_0064 = count;
guildInfo->ClearMembers();
const GuildMemberRecord* record = reinterpret_cast<const GuildMemberRecord*>(data + sizeof(PacketLengthHeader));
for (int i = 0; i < count; ++i, ++record) {
GuildInfo::Member member;
member.accountId = record->accountId;
member.characterId = record->characterId;
member.unknown_0020 = record->unknown_0008;
member.unknown_0024 = record->unknown_000A;
member.job = record->job;
member.unknown_002C = record->unknown_000C;
member.positionId = record->positionId;
member.level = record->level;
member.exp = record->exp;
member.online = record->online;
member.expRatio = 0.0f;
*reinterpret_cast<int*>(member.unknown_0074) = record->unknown_001E;
if (member.characterId == g_session.m_gid) {
member.name = g_session.DecodePlayerName();
}
member.positionName.clear();
guildInfo->AddMember(member);
}
guildInfo->UpdateMemberExpRatios();
g_windowMgr.RefreshGuildWindows();
}
namespace {
#pragma pack(push, 1)
struct GuildMemberMemoRecord {
/* 0000 */ int accountId;
/* 0004 */ int characterId;
/* 0008 */ std::int16_t unknown_0008;
/* 000A */ std::int16_t unknown_000A;
/* 000C */ std::int16_t unknown_000C;
/* 000E */ std::int16_t job;
/* 0010 */ std::int16_t level;
/* 0012 */ int exp;
/* 0016 */ int online;
/* 001A */ int positionId;
/* 001E */ char memo[50];
/* 0050 */ char name[24];
};
#pragma pack(pop)
static_assert(sizeof(GuildMemberMemoRecord) == 0x68);
}
// OFFSET: 0x00D4EE00
// FUNCTION: fn_21880
void CGameMode::ReceiveGuildMemberMemoList(const unsigned char* data) {
GuildInfo* guildInfo = reinterpret_cast<GuildInfo*>(reinterpret_cast<char*>(&g_guildId) - offsetof(GuildInfo, m_guildId));
const PacketLengthHeader* packet = reinterpret_cast<const PacketLengthHeader*>(data);
const int count = (packet->length - sizeof(PacketLengthHeader)) / sizeof(GuildMemberMemoRecord);
guildInfo->unknown_0064 = count;
guildInfo->ClearMembers();
const GuildMemberMemoRecord* record = reinterpret_cast<const GuildMemberMemoRecord*>(data + sizeof(PacketLengthHeader));
for (int i = 0; i < count; ++i, ++record) {
GuildInfo::Member member;
member.accountId = record->accountId;
member.characterId = record->characterId;
member.unknown_0020 = record->unknown_0008;
member.unknown_0024 = record->unknown_000A;
member.job = record->job;
member.unknown_002C = record->unknown_000C;
member.positionId = record->positionId;
member.level = record->level;
member.exp = record->exp;
member.online = record->online;
member.expRatio = 0.0f;
char memo[51];
std::memcpy(memo, record->memo, sizeof(record->memo));
memo[50] = '\0';
char name[25];
std::memcpy(name, record->name, sizeof(record->name));
name[24] = '\0';
member.name = name;
member.unknown_0050 = memo;
member.positionName.clear();
guildInfo->AddMember(member);
}
guildInfo->UpdateMemberExpRatios();
g_windowMgr.RefreshGuildWindows();
}
// OFFSET: 0x00D3A630
// FUNCTION: fn_21778
void CGameMode::ReceiveOpenStore(const unsigned char* packet) {
CGameMode* mode = static_cast<CGameMode*>(g_modeMgr.GetGameMode());
if (mode) {
const ModeDragState* drag = &mode->drag;
if (drag && drag->source) {
this->SendMsg(81, 0, 0, 0, 0);
return;
}
}
const unsigned int count = packet[2];
int& storeCount = *reinterpret_cast<int*>(&g_session.unknown_0F44[4]);
if (count < 2) {
storeCount = 2;
} else {
storeCount = count > 5 ? 5 : count;
}
reinterpret_cast<ClientItemLists*>(&g_session)->ClearItems1768();
if (!g_windowMgr.window_027C && !g_windowMgr.window_0274 && !g_windowMgr.unknown_02FC) {
if (UIWindow* window = g_windowMgr.EnsureWindow(174)) {
static_cast<UIMerchantShopMakeWnd*>(window)->AddActionButton();
}
return;
}
reinterpret_cast<WindowDialogs*>(&g_windowMgr)->Confirm(LookupMessage(587), 0, true, false, 0, "Message", 280, 120, 0);
this->SendMsg(270, 0, 0, 0, 0);
}
// OFFSET: 0x00D3A770
struct ACTSTRUCT {
virtual ~ACTSTRUCT();
};
// OFFSET: 0x00D051F0
// FUNCTION: fn_21563
ACTSTRUCT::~ACTSTRUCT() = default;
// FUNCTION: fn_21779
void CGameMode::ReceiveSearchStoreOpen(const unsigned char* packet) {
g_session.unknown_5BE0 = packet[4];
reinterpret_cast<std::int16_t*>(&g_session.unknown_5BE4)[1] = *reinterpret_cast<const std::int16_t*>(packet + 2);
g_windowMgr.EnsureWindow(181);
}
#pragma pack(push, 1)
struct ParChangePacket {
/* 0000 */ std::uint16_t header;
/* 0002 */ std::uint16_t type;
/* 0004 */ std::int32_t value;
};
#pragma pack(pop)
static_assert(sizeof(ParChangePacket) == 8);
// OFFSET: 0x00D3A7A0
// FUNCTION: fn_21780
void CGameMode::ReceiveParChange(unsigned char* data) {
auto* packet = reinterpret_cast<ParChangePacket*>(data);
int* derivedStats = reinterpret_cast<int*>(g_session.unknown_169C);
std::string text;
g_modeMgr.GetGameMode();
switch (packet->type) {
case 0:
if (*reinterpret_cast<int*>(&g_session.unknown_16F4[0]) != packet->value) {
*reinterpret_cast<int*>(&g_session.unknown_16F4[0]) = packet->value;
g_session.InvalidateWindowFrames();
}
break;
case 3:
*reinterpret_cast<int*>(&g_session.unknown_1704[0]) = packet->value;
g_session.InvalidateWindowFrames();
break;
case 4:
if (packet->value < 0) {
text = FormatOwnedString(LookupMessage(664), -packet->value);
const int emotion = g_cashEmotionMgr->GetSpecialEmotion(CashEmotionSpecial::ChatProhibit);
this->scene->player->SendMsg(nullptr, 160, 0, 0, 0, emotion, emotion >> 31, 0, 0, 0, 0, 0, 0, 0, 0);
} else {
text = LookupMessage(665);
this->scene->player->SendMsg(nullptr, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.c_str()), 0xFFFF, 0, 0, 0);
*reinterpret_cast<int*>(&g_session.unknown_16F4[4]) = packet->value;
g_session.InvalidateWindowFrames();
break;
case 5:
if (g_session.unknown_556C > 0 && (packet->value * 100) / g_session.unknown_556C < 25 &&
this->scene->GetGameActorByAID(g_session.unknown_1010) && rand() % 100 < 50 &&
g_session.CheckInterval(5000)) {
const int hungerLevel = g_session.GetPetHungryState(g_session.unknown_1044);
const int friendlyLevel = g_session.GetPetFriendlyState(g_session.m_petFriendly);
this->SendMsg(148, g_session.GetPetEmotionNumber(g_session.unknown_103C, 2, hungerLevel), 0, 0, 0);
this->SendMsg(148, g_session.GetPetActionNumber(hungerLevel, friendlyLevel, 2), 0, 0, 0);
}
if (g_session.unknown_5568 != packet->value) {
g_session.unknown_5568 = packet->value;
g_session.RefreshHpSpWindows();
}
break;
case 6:
if (g_session.unknown_556C != packet->value) {
g_session.unknown_556C = packet->value;
g_session.RefreshHpSpWindows();
}
if (g_windowMgr.window_02C8) {
g_windowMgr.window_02C8->SendMsg(nullptr, 6, 34, g_session.m_aid, 0, 0);
}
break;
case 7:
if (*reinterpret_cast<int*>(&g_session.unknown_5570[0]) != packet->value) {
*reinterpret_cast<int*>(&g_session.unknown_5570[0]) = packet->value;
g_session.RefreshHpSpWindows();
}
break;
case 8:
if (*reinterpret_cast<int*>(&g_session.unknown_5570[4]) != packet->value) {
*reinterpret_cast<int*>(&g_session.unknown_5570[4]) = packet->value;
g_session.RefreshHpSpWindows();
}
break;
case 9:
*reinterpret_cast<int*>(&g_session.unknown_1654[0]) = packet->value;
g_session.InvalidateWindowFrames();
if (g_windowMgr.unknown_01C4) {
g_windowMgr.unknown_01C4->SendMsg(nullptr, 35, 0, 0, 0, 0);
}
break;
case 11: {
g_session.m_level = packet->value;
g_session.InvalidateWindowFrames();
this->scene->player->unknown_0210 = static_cast<std::uint16_t>(g_session.m_level);
g_soundMgr->PlayWave("levelup.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
const int job = g_session.GetDisplayJob();
int effectId;
if (g_session.IsSuperNoviceClass(job)) {
effectId = 338;
} else if (job < 4303) {
if (job == 4302) {
effectId = 582;
} else {
switch (job) {
case 4046:
case 4047:
case 4048:
case 4049:
case 4225:
case 4226:
case 4227:
case 4238:
case 4239:
case 4240:
case 4241:
case 4242:
case 4243:
case 4244:
effectId = 582;
break;
case 4050:
case 4051:
case 4052:
effectId = 338;
break;
default:
effectId = 371;
break;
}
}
} else if (job == 4303 || job == 4316) {
effectId = 582;
} else {
effectId = 371;
}
this->scene->player->LaunchEffect(effectId, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
if (g_replayAnimationScaling == 0) {
g_windowMgr.EnsureWindow(21);
}
if (this->scene->GetGameActorByAID(g_session.unknown_1010)) {
const int hungerLevel = g_session.GetPetHungryState(g_session.unknown_1044);
const int friendlyLevel = g_session.GetPetFriendlyState(g_session.m_petFriendly);
this->SendMsg(148, g_session.GetPetEmotionNumber(g_session.unknown_103C, 6, hungerLevel), 0, 0, 0);
this->SendMsg(148, g_session.GetPetActionNumber(hungerLevel, friendlyLevel, 6), 0, 0, 0);
}
if (g_replayAnimationScaling == 0) {
if (g_windowMgr.unknown_01DC) {
reinterpret_cast<UIBasicInfoWnd*>(g_windowMgr.unknown_01DC)->SetHeight(g_windowMgr.unknown_01DC->geometry.height);
}
}
this->RefreshActorJobEffects(true);
if (UIWindow* window = g_windowMgr.LookupWindow(307)) {
window->SendMsg(nullptr, 6, 286, 192, 1, 0);
}
break;
}
case 12:
*reinterpret_cast<int*>(&g_session.unknown_165C[0]) = packet->value;
g_session.InvalidateWindowFrames();
reinterpret_cast<SkillWindows*>(&g_session)->Notify();
break;
case 13:
g_session.m_standardStats[0] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 14:
g_session.m_standardStats[1] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 15:
g_session.m_standardStats[2] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 16:
g_session.m_standardStats[3] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 17:
g_session.m_standardStats[4] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 18:
g_session.m_standardStats[5] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 24: {
packet->value = packet->value / 10;
const int oldPercent = (g_session.m_weight * 100) / (g_session.m_maxWeight < 1 ? 1 : g_session.m_maxWeight);
g_session.m_weight = packet->value;
g_session.RefreshHpSpWindows();
g_session.InvalidateWindowFrames();
if (g_session.m_maxWeight == 0) {
break;
}
const int percent = (g_session.m_weight * 100) / (g_session.m_maxWeight < 1 ? 1 : g_session.m_maxWeight);
if (oldPercent < percent) {
if (percent >= g_unknown173A5BC && oldPercent < g_unknown173A5BC) {
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
text = FormatOwnedString(LookupMessage(3311), g_unknown173A5BC);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.c_str()), 0xFF, 8, 0, 0);
}
if (percent > 89 && oldPercent < 90) {
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(307)), 0xFF, 8, 0, 0);
}
break;
}
if (oldPercent <= percent) {
break;
}
if (percent < g_unknown173A5BC && g_unknown173A5BC <= oldPercent) {
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(308)), 0xFFFF00, 8, 0, 0);
}
if (percent > 89) {
break;
}
if (oldPercent >= 90) {
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(309)), 0xFFFF00, 8, 0, 0);
}
break;
}
case 25: {
packet->value = packet->value / 10;
const int oldMaxWeight = g_session.m_maxWeight;
if (g_session.m_maxWeight < 1) {
g_session.m_maxWeight = 1;
}
const int oldPercent = (g_session.m_weight * 100) / g_session.m_maxWeight;
g_session.m_maxWeight = packet->value;
g_session.RefreshHpSpWindows();
g_session.InvalidateWindowFrames();
if (oldMaxWeight == 0 || g_session.m_maxWeight <= oldMaxWeight) {
break;
}
const int percent = (g_session.m_weight * 100) / (g_session.m_maxWeight < 1 ? 1 : g_session.m_maxWeight);
if (percent < 50) {
if (oldPercent > 49) {
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(308)), 0xFFFF00, 8, 0, 0);
}
} else if (percent > 89) {
break;
}
if (oldPercent >= 90) {
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(309)), 0xFFFF00, 8, 0, 0);
}
break;
}
case 41:
derivedStats[7] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 42:
derivedStats[12] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 43:
derivedStats[13] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 44:
derivedStats[14] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 45:
derivedStats[10] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 46:
derivedStats[11] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 47:
derivedStats[8] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 48:
derivedStats[15] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 49:
derivedStats[16] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 50:
derivedStats[17] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 51:
derivedStats[19] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 52:
derivedStats[18] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 53:
derivedStats[6] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 54:
derivedStats[9] = packet->value;
g_session.InvalidateWindowFrames();
break;
case 55:
g_session.m_jobLevel = packet->value;
g_session.InvalidateWindowFrames();
this->scene->player->LaunchEffect(packet->value < 51 ? 158 : 337, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
if (g_replayAnimationScaling == 0) {
g_windowMgr.EnsureWindow(49);
if (g_windowMgr.unknown_01DC) {
reinterpret_cast<UIBasicInfoWnd*>(g_windowMgr.unknown_01DC)->SetHeight(g_windowMgr.unknown_01DC->geometry.height);
}
}
if (UIWindow* window = g_windowMgr.LookupWindow(307)) {
window->SendMsg(nullptr, 6, 286, 196, 1, 0);
}
break;
case 60:
if (packet->value < -60) {
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(858)), 0xFFFF, 0, 0, 0);
}
break;
case 169:
reinterpret_cast<bool&>(g_session.unknown_8128[4]) = packet->value != 0;
break;
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:
g_session.SetTraitStat(packet->type, packet->value);
if (g_windowMgr.unknown_01C4) {
static_cast<UIStatusWnd*>(g_windowMgr.unknown_01C4)->ValidatePlacement();
}
g_session.InvalidateWindowFrames();
break;
}
if (packet->type == 11 || packet->type == 55) {
if (g_equipmentPropertiesMgr == nullptr) {
g_equipmentPropertiesMgr = new (std::nothrow) EquipmentProperties::CEquipmentPropertiesMgr;
}
g_equipmentPropertiesMgr->RefreshPretend();
}
}
// OFFSET: 0x00D55AB0
// FUNCTION: fn_21953
void CGameMode::ApplyStatusChange(
std::uint32_t aid, unsigned char on, int type, std::uint32_t remaining, int value1, int value2, int value3, unsigned char flag, std::uint32_t total
) {
std::uint32_t now;
if (g_replayAnimationScaling != 0) {
now = Replay::Instance().elapsed;
} else {
now = timeGetTime();
}
if (type == 64) {
type = value1 + 897;
}
if (aid != g_session.m_aid) {
CRenderObject* actor = this->scene->GetGameActorByAID(aid);
if (actor) {
actor->SendMsg(
nullptr, 110, 0, type, type >> 31, on, 0, value1, value1 >> 31, value2, value2 >> 31, flag, 0, value3, value3 >> 31
);
}
if (type == 432 && actor) {
const unsigned char element = static_cast<unsigned char>(value3);
if (element == 19) {
g_effectMgr->Spawn(actor->render.accountId, 1665, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
g_effectMgr->Spawn(actor->render.accountId, 1666, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
} else if (element == 20) {
g_effectMgr->Spawn(actor->render.accountId, 1669, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
} else if (element == 14) {
g_effectMgr->Spawn(actor->render.accountId, 1667, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
g_effectMgr->Spawn(actor->render.accountId, 1668, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
}
}
}
MessengerMember member = ClientMessenger{g_session.m_partyMembers, g_session.m_friends}.PartyByAccount(aid);
if (aid != g_session.m_aid && (!member.valid || member.offline)) {
return;
}
char name[256];
std::sprintf(name, "");
if (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 (on) {
if (aid == g_session.m_aid) {
if (type == 696) {
if (this->scene->player) {
this->scene->player->SetUnknown0305(1, value2);
}
} else if (type == 46) {
SessionRequestTimer timer;
timer.requestId = 577;
timer.readyTime = now + remaining;
timer.duration = total;
g_session.m_requestTimers.push_back(timer);
} else if (type == 684) {
SessionRequestTimer timer;
timer.requestId = 9999;
timer.readyTime = now + remaining;
timer.duration = total;
g_session.m_requestTimers.push_back(timer);
} else if (type == 175) {
SessionRequestTimer timer;
for (int requestId = 10000; requestId < 10020; ++requestId) {
std::list<SessionRequestTimer>::iterator it = g_session.m_requestTimers.begin();
for (; it != g_session.m_requestTimers.end(); ++it) {
if (it->requestId == requestId) {
break;
}
}
timer.requestId = requestId;
timer.readyTime = now + remaining;
timer.duration = total;
if (it == g_session.m_requestTimers.end()) {
g_session.m_requestTimers.push_back(timer);
} else {
it->readyTime = timer.readyTime;
}
}
} else if (type == 824) {
g_rodexMailStore->unknown_0014 = value2;
}
if (type != 824) {
ActiveSkillEffect effect;
effect.id = type;
effect.unknown_0004 = remaining == 9999 ? 999999 : now + remaining;
if (type >= 363 && type <= 367) {
effect.unknown_0008 = value1 & 3;
} else if (type == 339 || type == 895 || type == 1149) {
effect.unknown_0008 = value1;
}
if (type == 1152 || type == 1196) {
effect.unknown_0008 = value1;
} else if (type == 1244) {
effect.unknown_0008 = value2;
} else if (CSkillActionMgr::GetInstance()->HasEfstAction(type) == true) {
effect.unknown_000C = value2;
effect.unknown_0008 = value1;
effect.unknown_0010 = value3;
}
for (std::vector<ActiveSkillEffect>::iterator it = g_activeSkillEffects.begin(); it != g_activeSkillEffects.end();) {
if (it->id == type && (it->id != 895 || it->unknown_0008 == effect.unknown_0008)) {
g_cooldownOwner->Remove(it->id);
g_activeSkillEffects.erase(it);
it = g_activeSkillEffects.begin();
} else {
++it;
}
}
effect.unknown_0014 = total;
effect.unknown_0018 = remaining;
if (effect.unknown_0004 != 999999) {
g_cooldownOwner->Register(effect.id, total, now, total - remaining);
}
g_activeSkillEffects.push_back(effect);
}
}
color = 0xFFFF00;
switch (type) {
case 2:
case 37:
case 38:
case 39:
case 40:
case 68:
case 161:
std::sprintf(message, LookupMessage(463));
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 363:
case 364:
case 365:
case 366:
case 367:
case 448:
case 452:
case 453:
case 454:
case 645:
case 646:
case 655:
case 656:
case 657:
case 659:
case 660:
case 674:
case 716:
case 717:
case 718:
case 719:
case 720:
case 721:
case 728:
case 730:
case 734:
case 735:
case 736:
case 737:
case 755:
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 1126:
case 1139:
case 1141:
case 1142:
case 1148:
case 1150:
case 1165:
case 1166:
case 1167:
case 1176:
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 1258:
case 1318:
case 1319:
case 1337:
case 1338:
case 1339:
case 1688:
break;
case 339:
if (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);
}
g_effectMgr->Spawn(
player->render.accountId, g_serviceOptions.Get(229) ? value1 + 1466 : value1 + 1299, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0
);
std::sprintf(message, "");
}
break;
case 434:
if (aid == g_session.m_aid) {
CPlayer* player = this->scene->player;
player->SendMsg(nullptr, 109, 0, 879, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
player->LaunchEffect(879, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
std::sprintf(message, "");
}
break;
case 439:
if (aid == g_session.m_aid) {
CPlayer* player = this->scene->player;
player->SendMsg(nullptr, 109, 0, 865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
player->LaunchEffect(865, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
std::sprintf(message, "");
}
break;
case 441:
if (aid == g_session.m_aid) {
CPlayer* player = this->scene->player;
player->SendMsg(nullptr, 109, 0, 867, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
player->LaunchEffect(867, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
std::sprintf(message, "");
}
break;
case 451:
if (aid == g_session.m_aid) {
CPlayer* player = this->scene->player;
player->SendMsg(nullptr, 109, 0, 871, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
player->LaunchEffect(871, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
std::sprintf(message, "");
}
break;
case 435:
if (aid == g_session.m_aid) {
this->scene->player->SendMsg(nullptr, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
std::sprintf(message, "");
}
break;
case 433:
if (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 (aid == g_session.m_aid) {
this->scene->player->LaunchEffect(752, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
std::sprintf(message, "");
}
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 (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 (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 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 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 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 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 355:
case 357:
case 360:
case 361:
case 362:
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 440:
case 442:
case 443:
case 444:
case 445:
case 446:
case 447:
case 450:
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 648:
case 649:
case 670:
case 869:
case 1056:
case 1057:
case 1058:
case 1059:
case 1121:
std::sprintf(message, "");
break;
case 354:
if (aid == g_session.m_aid) {
this->scene->player->LaunchEffect(729, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
}
std::printf(message, "");
break;
case 260:
if (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 250:
{
const int minutes = remaining / 60000;
if (minutes > 0) {
const std::string text = FormatOwnedString(LookupMessage(2031), minutes, value1);
std::strcpy(message, text.c_str());
} else {
message[0] = '\0';
}
break;
}
case 251:
std::sprintf(message, LookupMessage(1250));
break;
case 252:
{
const int minutes = remaining / 60000;
if (minutes > 0) {
const int hours = minutes / 60;
if (hours > 0) {
const std::string text = FormatOwnedString(LookupMessage(2472), hours, minutes % 60, value1);
std::strcpy(message, text.c_str());
} else {
const std::string text = FormatOwnedString(LookupMessage(2471), minutes, value1);
std::strcpy(message, text.c_str());
}
} else {
message[0] = '\0';
}
break;
}
case 253:
if (aid == g_session.m_aid) {
this->unknown_05CC[0] = 1;
}
std::sprintf(message, LookupMessage(1252));
break;
case 312:
{
const int minutes = remaining / 60000;
if (minutes > 0) {
const std::string text = FormatOwnedString(LookupMessage(2462), minutes, value1);
std::strcpy(message, text.c_str());
} else {
message[0] = '\0';
}
break;
}
case 636:
{
const std::string text = FormatOwnedString(LookupMessage(1924), value2, value1 / 100.0 + 1.0);
std::sprintf(message, text.c_str());
break;
}
case 621:
case 651:
case 665:
if (aid == g_session.m_aid) {
this->scene->player->SendMsg(nullptr, 110, 0, type, type >> 31, on, 0, value1, value1 >> 31, 0, 0, 0, 0, 0, 0);
this->sub_CFE480(aid);
}
return;
case 673:
if (aid == g_session.m_aid) {
g_session.SetUnknown5C1C(value1);
}
break;
case 675:
if (aid == g_session.m_aid) {
this->scene->player->SendMsg(nullptr, 110, 0, 675, 0, on, 0, value1, value1 >> 31, 0, 0, 0, 0, 0, 0);
this->sub_CFE480(aid);
}
return;
case 676:
if (aid == g_session.m_aid) {
this->scene->player->SendMsg(nullptr, 110, 0, 676, 0, on, 0, value1, value1 >> 31, 0, 0, 0, 0, 0, 0);
this->sub_CFE480(aid);
}
break;
case 710:
if (aid == g_session.m_aid) {
this->scene->player->SendMsg(nullptr, 110, 0, 710, 0, on, 0, value1, value1 >> 31, 0, 0, 0, 0, 0, 0);
this->sub_CFE480(aid);
}
break;
case 933:
if (aid == g_session.m_aid) {
this->scene->player->Slot15(48, 1);
this->scene->player->render.isMotionFreezed = true;
}
break;
case 893:
if (aid == g_session.m_aid) {
this->scene->GetGameActorByAID(aid);
this->scene->player->Slot15(47, 1);
}
break;
case 373:
g_session.unknown_7ED4 = timeGetTime();
g_session.unknown_7ED0 = value2 == 0 ? value1 : 0;
if (value1 == 0) {
for (std::vector<ActiveSkillEffect>::iterator it = g_activeSkillEffects.begin(); it != g_activeSkillEffects.end();) {
if (it->id == 373) {
g_activeSkillEffects.erase(it);
it = g_activeSkillEffects.begin();
} else {
++it;
}
}
}
break;
case 1013:
color = 0xFF;
std::sprintf(message, LookupMessage(3247));
break;
case 1125:
g_effectMgr->Spawn(aid, 1362, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
g_soundMgr->PlayWave("effect\\s포이즌버스터.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
break;
case 1149:
{
CGameActor* actor;
if (aid == g_session.m_aid) {
actor = this->scene->player;
} else {
actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(aid));
}
if (!actor) {
break;
}
if (value1 == 2) {
actor->Slot57(2);
if (aid == g_session.m_aid) {
g_session.unknown_8074 = 2;
}
} else {
actor->Slot57(1);
if (aid == g_session.m_aid) {
g_session.unknown_8074 = 1;
}
}
actor->SendMsg(nullptr, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
break;
}
case 432:
{
CRenderObject* actor = this->scene->GetGameActorByAidIncludeMe(aid);
if (!actor) {
break;
}
const unsigned char element = static_cast<unsigned char>(value3);
if (element == 19) {
g_effectMgr->Spawn(actor->render.accountId, 1665, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
g_effectMgr->Spawn(actor->render.accountId, 1666, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
} else if (element == 20) {
g_effectMgr->Spawn(actor->render.accountId, 1669, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
} else if (element == 14) {
g_effectMgr->Spawn(actor->render.accountId, 1667, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
g_effectMgr->Spawn(actor->render.accountId, 1668, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
}
break;
}
case 1160:
_snprintf_s(message, 256, LookupMessage(3726));
break;
case 1162:
_snprintf_s(message, 256, LookupMessage(3728));
break;
case 1161:
_snprintf_s(message, 256, LookupMessage(3730));
break;
case 1228:
_snprintf_s(message, 256, LookupMessage(3732));
break;
case 1227:
_snprintf_s(message, 256, LookupMessage(3734));
break;
case 1201:
_snprintf_s(message, 256, LookupMessage(3736));
break;
case 1200:
_snprintf_s(message, 256, LookupMessage(3738));
break;
case 1199:
_snprintf_s(message, 256, LookupMessage(3740));
break;
case 1198:
_snprintf_s(message, 256, LookupMessage(3742));
break;
case 1221:
_snprintf_s(message, 256, LookupMessage(3758));
break;
case 1152:
_snprintf_s(message, 256, LookupMessage(3760));
break;
case 1194:
_snprintf_s(message, 256, LookupMessage(3764));
break;
case 1247:
_snprintf_s(message, 256, LookupMessage(3782));
break;
case 1248:
_snprintf_s(message, 256, LookupMessage(3778));
break;
case 1249:
_snprintf_s(message, 256, LookupMessage(3784));
break;
case 1237:
StringFormat(message, 256, static_cast<std::size_t>(-1), "%s", LookupMessage(3788));
break;
case 1236:
StringFormat(message, 256, static_cast<std::size_t>(-1), "%s", LookupMessage(3786));
break;
case 1261:
StringFormat(message, 256, static_cast<std::size_t>(-1), "%s", LookupMessage(3799));
break;
case 1250:
color = 0xFF;
StringFormat(message, 256, static_cast<std::size_t>(-1), "%s", LookupMessage(3807));
break;
case 1245:
StringFormat(message, 256, static_cast<std::size_t>(-1), "%s", LookupMessage(3815));
break;
case 1271:
StringFormat(message, 256, static_cast<std::size_t>(-1), "%s", LookupMessage(3812));
break;
default:
if (CSkillActionMgr::GetInstance()->HasEfstAction(type) != true) {
this->sub_CFE480(aid);
return;
}
{
const EfstActionMessage action = CSkillActionMgr::GetInstance()->EfstSlot03(type);
if (action.text) {
color = action.color;
StringFormat(message, 256, static_cast<std::size_t>(-1), "%s", action.text);
}
}
break;
}
} else {
if (aid == g_session.m_aid) {
for (std::vector<ActiveSkillEffect>::iterator it = g_activeSkillEffects.begin(); it != g_activeSkillEffects.end();) {
if (it->id == type && (it->id != 895 || it->unknown_0008 == value1)) {
g_activeSkillEffects.erase(it);
it = g_activeSkillEffects.begin();
} else {
++it;
}
}
}
color = 0xFF;
switch (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 6:
case 17:
case 64:
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 (aid == g_session.m_aid) {
this->scene->player->Slot15(0, 1);
this->scene->player->render.isMotionFreezed = false;
}
break;
case 30:
std::sprintf(message, LookupMessage(647));
break;
case 31:
std::sprintf(message, LookupMessage(649));
break;
case 40:
case 12:
case 42:
if (aid == g_session.m_aid) {
for (std::vector<ActiveSkillEffect>::iterator it = g_activeSkillEffects.begin(); it != g_activeSkillEffects.end();) {
if (it->id == 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 363:
case 364:
case 365:
case 366:
case 367:
if (aid != g_session.m_aid) {
break;
}
{
CPlayer* player = this->scene->player;
const int stage = value1 & 3;
if (stage == 0) {
player->SendMsg(nullptr, 109, 0, 735, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
} else if (stage == 1) {
player->SendMsg(nullptr, 109, 0, 736, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
} else if (stage == 2) {
player->SendMsg(nullptr, 109, 0, 737, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
} else if (stage == 3) {
player->SendMsg(nullptr, 109, 0, 738, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
}
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 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 450:
case 451:
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 339:
if (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 434:
if (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 (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 (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 (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 (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 (aid == g_session.m_aid) {
this->unknown_05CC[0] = 0;
}
break;
case 933:
if (aid == g_session.m_aid) {
this->scene->player->Slot15(0, 1);
this->scene->player->render.isMotionFreezed = false;
}
break;
case 893:
if (aid == g_session.m_aid) {
this->scene->player->Slot15(0, 1);
}
break;
case 1013:
color = 0xFFFF00;
std::sprintf(message, LookupMessage(3247));
break;
case 1125:
{
CEffect* effect = g_effectMgr->Find(aid, 1362);
if (effect) {
g_effectMgr->Retire(effect, 1);
}
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 448:
case 452:
case 453:
case 454:
case 673:
case 674:
case 716:
case 717:
case 718:
case 719:
case 720:
case 721:
case 728:
case 730:
case 734:
case 735:
case 736:
case 737:
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 1126:
case 1139:
case 1141:
case 1142:
case 1149:
case 1165:
case 1166:
case 1167:
case 1176:
case 1184:
case 1197:
case 1227:
case 1688:
break;
default:
this->sub_CFE480(aid);
return;
}
}
this->sub_CFE480(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<std::intptr_t>(text), color, std::strlen(name) > 1 ? 10 : 8, 0, 0);
}
if (aid == g_session.m_aid) {
this->scene->player->SendMsg(
nullptr, 110, 0, type, type >> 31, on, 0, value1, value1 >> 31, value2, value2 >> 31, flag, 0, value3, value3 >> 31
);
}
}
#pragma pack(push, 1)
struct Window107Entry {
/* 0000 */ unsigned char unknown_0000[0x18];
};
#pragma pack(pop)
// OFFSET: 0x00D79540
// FUNCTION: fn_22170
void CGameMode::ReceiveObjectsDisappear(int count, const std::uint32_t* aids) {
for (int i = 0; i < count; ++i) {
const std::uint32_t aid = aids[i];
if (this->scene->RemoveItem(aid) == true) {
this->SendMsg(13, aid, 0, 0, 0);
} else if (this->scene->RemoveGroundItem(aid) == true) {
this->RemoveUnknown01A4(aid);
} else {
this->scene->RemoveSkill(aid);
}
}
}
// OFFSET: 0x00D795B0
// FUNCTION: fn_22171
void CGameMode::ReceiveWindow107List(const unsigned char* packet) {
const std::int64_t count = (*reinterpret_cast<const std::int16_t*>(packet + 2) - 4) / sizeof(Window107Entry);
if (count == 0) {
reinterpret_cast<WindowDialogs*>(&g_windowMgr)->Confirm(LookupMessage(424), 0, true, false, 0, "Message", 280, 120, 0);
return;
}
g_windowMgr.CloseWindow(107);
UIWindow* window = g_windowMgr.EnsureWindow(107);
const Window107Entry* entry = reinterpret_cast<const Window107Entry*>(packet + 4);
if (count != 0 && window != nullptr) {
for (int i = 0; i < count; ++i) {
window->SendMsg(nullptr, 31, reinterpret_cast<std::intptr_t>(entry), 0, 0, 0);
++entry;
}
}
}
// OFFSET: 0x00D39AE0
// FUNCTION: fn_21772
void CGameMode::ReceiveActorColorChat(const unsigned char* packet) {
char text[256];
std::memset(text, 0, sizeof(text));
std::memcpy(text, packet + 12, *reinterpret_cast<const std::uint16_t*>(packet + 2) - 12);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), *reinterpret_cast<const int*>(packet + 8), 0, 0, 0);
CRenderObject* actor = this->scene->GetGameActorByAID(*reinterpret_cast<const std::uint32_t*>(packet + 4));
if (actor != nullptr) {
const int color = *reinterpret_cast<const int*>(packet + 8);
actor->SendMsg(nullptr, 7, 0, reinterpret_cast<int>(text), reinterpret_cast<int>(text) >> 31, color, color >> 31, 0, 0, 0, 0, 0, 0, 0, 0);
}
if (g_whisperRecord != 0) {
this->WriteChatLog(text);
}
}
// OFFSET: 0x00D1F400
// FUNCTION: fn_21637
void CGameMode::ReceiveWearEquipAck(unsigned char result, std::uint16_t index, std::uint16_t look, int location) {
*reinterpret_cast<std::uint32_t*>(&this->unknown_0100[0x04]) = timeGetTime() - 2000;
switch (result) {
case 0: {
ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, index);
if (item.unknown_0000[1]) {
item.unknown_0070 = look;
item.unknown_0000[3] = location;
g_session.OnItemEquipped(item);
}
break;
}
case 1:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(1953)), 0xFF, 7, 0, 0);
break;
case 2:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(372)), 0xFF, 7, 0, 0);
break;
}
}
// OFFSET: 0x00D32A10
// FUNCTION: fn_21747
void CGameMode::ReceiveFormattedMessage(const unsigned char* packet) {
char text[500];
std::memset(text, 0, sizeof(text));
const std::uint16_t messageId = *reinterpret_cast<const std::uint16_t*>(packet + 2);
if (messageId == 3278) {
char name[260];
std::memset(name, 0, sizeof(name));
ITEM_INFO item;
item.SetItemId(*reinterpret_cast<const int*>(packet + 4));
int capacity = sizeof(name);
ItemDescriptions{g_itemDescriptions}.Name(item, name, capacity, 0);
StringFormat(text, sizeof(text), static_cast<std::size_t>(-1), LookupMessage(3278), name);
} else {
std::sprintf(text, LookupMessage(messageId), *reinterpret_cast<const int*>(packet + 4));
}
if (std::strlen(text) != 0) {
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
}
}
#include "UI/Item/UIParaItemShopWnd.h"
#pragma pack(push, 1)
struct ParaResultEntry {
/* 0000 */ int itemId;
/* 0004 */ std::int16_t quantity;
/* 0006 */ int location;
/* 000A */ unsigned char refine;
/* 000B */ int cards[4];
/* 001B */ std::uint16_t index;
};
#pragma pack(pop)
// OFFSET: 0x00D77E70
// FUNCTION: fn_22155
void CGameMode::ReceiveParaItemResult(unsigned char success, int count, const unsigned char* data) {
UIParaResultWnd* window = static_cast<UIParaResultWnd*>(g_windowMgr.EnsureWindow(256));
if (window == nullptr) {
return;
}
const ParaResultEntry* entry = reinterpret_cast<const ParaResultEntry*>(data);
for (int i = 0; i < count; ++i, ++entry) {
ITEM_INFO item;
item.SetItemId(entry->itemId);
item.quantity = entry->quantity;
item.unknown_0014[0] = entry->location;
item.unknown_0014[1] = entry->location;
item.unknown_0060 = entry->refine;
std::memcpy(item.unknown_001C, entry->cards, sizeof(entry->cards));
item.unknown_0000[1] = entry->index;
item.identified = 1;
window->AddItem(item);
}
window->SendMsg(nullptr, 36, (count - 2 > 0 ? count : 0) * 32 + 120, 0, 0, 0);
window->SendMsg(nullptr, 23, 0, 0, 0, 0);
if (!success) {
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(3043)), 0xFF, 0, 0, 0);
}
}
// OFFSET: 0x00D79700
// FUNCTION: fn_22173
void CGameMode::ReceiveResultNotice4327(const unsigned char* packet) {
std::string text;
switch (*reinterpret_cast<const std::int16_t*>(packet + 2)) {
case 0:
text = static_cast<const std::string&>(FormatOwnedString(LookupMessage(4327)));
break;
case 1:
text = static_cast<const std::string&>(FormatOwnedString(LookupMessage(4327)));
break;
case 2:
text = static_cast<const std::string&>(FormatOwnedString(LookupMessage(4327)));
break;
}
if (!text.empty()) {
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.c_str()), 0xFF, 0, 0, 0);
}
}
// OFFSET: 0x00D78130
// FUNCTION: fn_22159
void CGameMode::OpenBuyingStoreMake(unsigned char slotCount) {
CGameMode* mode = static_cast<CGameMode*>(g_modeMgr.GetGameMode());
if (mode) {
const ModeDragState* drag = &mode->drag;
if (drag && drag->source) {
this->SendMsg(299, 0, 0, 0, 0);
return;
}
}
const unsigned int count = slotCount;
if (count < 2) {
g_session.m_buyingStoreSlotCount = 2;
} else {
g_session.m_buyingStoreSlotCount = count > 5 ? 5 : count;
}
reinterpret_cast<ClientItemLists*>(&g_session)->ClearItems1768();
if (!g_windowMgr.window_027C && !g_windowMgr.window_0274 && !g_windowMgr.unknown_02FC) {
g_windowMgr.EnsureWindow(174);
if (g_windowMgr.unknown_040C) {
static_cast<UIMerchantShopMakeWnd*>(g_windowMgr.unknown_040C)->SetItems(0, nullptr);
}
return;
}
reinterpret_cast<WindowDialogs*>(&g_windowMgr)->Confirm(LookupMessage(587), 0, true, false, 0, "Message", 280, 120, 0);
this->SendMsg(299, 0, 0, 0, 0);
}
// OFFSET: 0x00D78210
// FUNCTION: fn_22160
void CGameMode::OpenVendingMake(unsigned char slotCount, int itemCount, const short* items) {
CGameMode* mode = static_cast<CGameMode*>(g_modeMgr.GetGameMode());
if (mode) {
const ModeDragState* drag = &mode->drag;
if (drag && drag->source) {
this->SendMsg(297, 0, 0, 0, 0);
return;
}
}
const unsigned int count = slotCount;
if (count < 3) {
g_session.m_vendingSlotCount = 3;
} else {
g_session.m_vendingSlotCount = count > 13 ? 13 : count;
}
reinterpret_cast<ClientItemLists*>(&g_session)->ClearItems1768();
if (!g_windowMgr.window_027C && !g_windowMgr.window_0274) {
g_windowMgr.EnsureWindow(41);
if (g_windowMgr.unknown_02FC) {
static_cast<UIMerchantShopMakeWnd*>(g_windowMgr.unknown_02FC)->SetItems(itemCount, items);
}
return;
}
reinterpret_cast<WindowDialogs*>(&g_windowMgr)->Confirm(LookupMessage(587), 0, true, false, 0, "Message", 280, 120, 0);
this->SendMsg(297, 0, 0, 0, 0);
}
#include "Script/LuaScript.h"
// OFFSET: 0x00D799C0
// FUNCTION: fn_22176
void CGameMode::ReceiveAgitNotice(unsigned char agitId, int first, int second) {
if (!g_windowMgr.window_0320) {
return;
}
char text[256] = {};
const char* agitName = nullptr;
g_luaScript->Call("get_agit_name", "d>s", agitId, &agitName);
sprintf_s(text, LookupMessage(3632), agitName, second, 100, first, 100);
reinterpret_cast<WindowDialogs*>(&g_windowMgr)->Confirm(text, 0, true, false, 0, "Message", 250, 130, 0);
}
#include "Contents/Actors/Item.h"
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: 0x00D2DB80
// FUNCTION: fn_21724
void CGameMode::ReceiveItemFallEntry(const unsigned char* packet) {
ItemFallEntry entry = {};
entry.count = *reinterpret_cast<const std::int16_t*>(packet + 0x0F);
entry.aid = *reinterpret_cast<const std::uint32_t*>(packet + 2);
entry.column = *reinterpret_cast<const std::int16_t*>(packet + 0x0B);
entry.row = *reinterpret_cast<const std::int16_t*>(packet + 0x0D);
entry.subColumn = packet[0x11];
entry.subRow = packet[0x12];
entry.falling = 0;
_itoa(*reinterpret_cast<const int*>(packet + 6), entry.itemId, 10);
entry.falling = 0;
entry.identified = packet[0x0A];
CItem* item = this->scene->GetItemByAID(*reinterpret_cast<const std::uint32_t*>(packet + 2));
if (!item) {
item = new CItem;
this->scene->objects.push_back(item);
this->scene->unknown_0018.push_back(item);
}
const int entryAddress = reinterpret_cast<int>(&entry);
item->SendMsg(nullptr, 4, 0, entryAddress, entryAddress >> 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
#include "Contents/ClientState.h"
// OFFSET: 0x00D266C0
// FUNCTION: fn_21681
void CGameMode::ReceiveFeedOption(const unsigned char* packet) {
switch (*reinterpret_cast<const int*>(packet + 2)) {
case 0:
*reinterpret_cast<int*>(g_session.unknown_5974) = *reinterpret_cast<const int*>(packet + 6);
g_windowMgr.SendNotice(
1, reinterpret_cast<std::intptr_t>(LookupMessage((*reinterpret_cast<int*>(g_session.unknown_5974) != 0) + 0x54E)), 0x64FFFF, 0, 0, 0
);
if (g_windowMgr.unknown_01E0) {
g_windowMgr.unknown_01E0->SendMsg(nullptr, 0x3C, 0, 0, 0, 0);
}
break;
case 1:
g_serviceOptions.Set(231, *reinterpret_cast<const int*>(packet + 6) != 0);
g_windowMgr.SendNotice(
1, reinterpret_cast<std::intptr_t>(LookupMessage((*reinterpret_cast<const int*>(packet + 6) != 0) + 0xBA2)), 0x64FFFF, 0, 0, 0
);
g_windowMgr.sub_AAB070(231);
break;
case 2:
g_session.SetPetAutoFeed(*reinterpret_cast<const int*>(packet + 6) > 0);
break;
case 3:
g_session.SetHomunculusAutoFeed(*reinterpret_cast<const int*>(packet + 6) > 0);
break;
case 5:
*reinterpret_cast<int*>(g_session.unknown_8128) = *reinterpret_cast<const int*>(packet + 6);
break;
case 6:
sub_E489C0(*reinterpret_cast<const int*>(packet + 6) != 0);
break;
}
}
// OFFSET: 0x00D1E7B0
// FUNCTION: fn_21635
void CGameMode::ReceiveTakeOffEquipResult(unsigned char result, int location, std::uint16_t identity) {
*reinterpret_cast<std::uint32_t*>(&this->unknown_0100[0x08]) = timeGetTime() - 2000;
switch (result) {
case 0:
if (location) {
if (g_session.IsCostumeLocation(location)) {
g_session.UnequipItem2B50(location);
return;
}
g_session.UnequipItem(location, identity);
}
break;
case 1:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(1953)), 0xFF, 7, 0, 0);
break;
}
}
#include "Contents/Sound/SoundMaker.h"
// OFFSET: 0x00D25E90
// FUNCTION: fn_21677
void CGameMode::ReceiveHomunculusChange(const unsigned char* packet) {
char text[256];
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(*reinterpret_cast<const std::uint32_t*>(packet + 4)));
switch (static_cast<char>(packet[3])) {
case 0:
*reinterpret_cast<std::uint32_t*>(&g_session.unknown_5570[0x08]) = *reinterpret_cast<const std::uint32_t*>(packet + 4);
if (actor) {
g_groundMarkEnabled = 1;
g_session.m_homunJob = actor->GetEffectiveJob(-1);
}
break;
case 1:
g_session.unknown_55D4 = *reinterpret_cast<const int*>(packet + 8);
if (actor) {
g_session.m_homunJob = actor->GetEffectiveJob(-1);
}
if (g_windowMgr.window_03C0) {
g_windowMgr.window_03C0->Invalidate();
}
if (g_session.IsAdminSubMode(3)) {
std::sprintf(text, "%d", *reinterpret_cast<const int*>(packet + 8));
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xF5F5F5, 0, 0, 0);
}
break;
case 2:
g_session.unknown_55F0 = *reinterpret_cast<const int*>(packet + 8);
g_session.RefreshHomunculusInfo();
if (actor) {
g_session.m_homunJob = actor->GetEffectiveJob(-1);
}
if (g_windowMgr.window_03C0) {
g_windowMgr.window_03C0->Invalidate();
}
if (g_session.IsAdminSubMode(3)) {
std::sprintf(text, "Full : %d", *reinterpret_cast<const int*>(packet + 8));
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0x1EF5F5, 0, 0, 0);
}
break;
case 3:
if (actor) {
if (*reinterpret_cast<const int*>(packet + 8)) {
g_session.unknown_55D8 = *reinterpret_cast<const int*>(packet + 8);
} else {
g_session.unknown_55D8 = 0;
actor->Slot21(actor->GetEffectiveJob(-1));
}
if (g_session.IsHomunAid(*reinterpret_cast<const std::uint32_t*>(packet + 4)) && g_windowMgr.window_03C0) {
g_windowMgr.window_03C0->Invalidate();
}
}
break;
}
}
// OFFSET: 0x00D26950
// FUNCTION: fn_21683
void CGameMode::ReceiveItemConsumed(const unsigned char* packet) {
if (g_windowMgr.unknown_0458) {
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(2734)), 0x64FFFF, 0, 0, 0);
g_modeMgr.GetGameMode()->SendMsg(293, 0, 0, 0, 0);
g_windowMgr.CloseWindow(264);
}
if (*reinterpret_cast<int*>(&this->unknown_0100[0x14])) {
*reinterpret_cast<int*>(&this->unknown_0100[0x14]) = 0;
reinterpret_cast<SessionMessengerContext*>(&g_session)->ResetSlots();
}
reinterpret_cast<ClientItemLists*>(&g_session)->RemoveItem1710(
*reinterpret_cast<const std::uint16_t*>(packet + 4), *reinterpret_cast<const std::int16_t*>(packet + 6)
);
*reinterpret_cast<int*>(&this->unknown_02B8[0x18]) = 0;
this->unknown_05CE = 1;
if (g_session.unknown_103C != -1 && g_session.unknown_1050 == *reinterpret_cast<const std::uint16_t*>(packet + 4)) {
g_session.ResetUnknown1050();
EquipmentProperties::CEquipmentPropertiesMgr* properties = EquipmentProperties::CEquipmentPropertiesMgr::GetInstance();
int itemId = -1;
int kind = 0;
properties->RemoveExpansion(kind, itemId);
}
}
// OFFSET: 0x00D25D50
// FUNCTION: fn_21676
void CGameMode::ReceivePartyLeaderChange(const unsigned char* packet) {
char text[500];
ClientMessenger messenger{g_session.m_partyMembers, g_session.m_friends};
MessengerMember member = messenger.PartyByAccount(*reinterpret_cast<const std::uint32_t*>(packet + 6));
if (member.valid != 0) {
messenger.SetPartyLeader(*reinterpret_cast<const std::uint32_t*>(packet + 2), 1);
messenger.SetPartyLeader(*reinterpret_cast<const std::uint32_t*>(packet + 6), 0);
g_session.unknown_5464 = *reinterpret_cast<const std::uint32_t*>(packet + 6) == g_session.m_aid;
std::sprintf(text, LookupMessage(1552), member.name.c_str());
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 12, 0, 0);
sub_DFF150(&g_session);
if (g_windowMgr.unknown_03F8) {
g_windowMgr.unknown_03F8->SendMsg(nullptr, 0x3C, 0, 0, 0, 0);
}
}
}
// OFFSET: 0x00D2DA10
// FUNCTION: fn_21723
void CGameMode::ReceiveItemSellResult(const unsigned char* packet) {
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
const int count = *reinterpret_cast<const std::int16_t*>(packet + 4);
const int price = *reinterpret_cast<const int*>(packet + 6);
ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, *reinterpret_cast<const std::int16_t*>(packet + 2));
ItemDescriptions descriptions{g_itemDescriptions};
bool languagePrefix = false;
WORD language = g_serverLanguage->language;
ItemNaming naming{descriptions, g_itemCardNames, *g_playerNameDictionary, languagePrefix, g_serviceType, language};
g_windowMgr.SendNotice(
1,
reinterpret_cast<std::intptr_t>(FormatOwnedString(LookupMessage(1746), naming.DisplayName(item, 0).c_str(), count, price * count).c_str()),
0xFFFF64, 0, 0, 0
);
reinterpret_cast<ClientItemLists*>(&g_session)->RemoveItem1710(
*reinterpret_cast<const std::int16_t*>(packet + 2), *reinterpret_cast<const std::int16_t*>(packet + 4)
);
}
// OFFSET: 0x00D58F60
// FUNCTION: fn_21958
std::FILE* CGameMode::OpenRandomOptionSimulatorFile(const std::string& folder, const std::string& itemName) {
std::string directory = this->MakeSimulatorFolder(folder);
if (directory.size() == 0) {
return nullptr;
}
SYSTEMTIME time;
GetLocalTime(&time);
std::string name = FormatOwnedString("%s_RandomOption(%d_%d_%d)", itemName.c_str(), time.wYear, time.wMonth, time.wDay);
std::string path = FormatOwnedString("%s\\%s.txt", directory.c_str(), name.c_str());
int index = 0;
while (_access(path.c_str(), 0) == 0) {
++index;
path = FormatOwnedString("%s\\%s_%d.txt", directory.c_str(), name.c_str(), index);
}
std::FILE* file = _wfopen(DecodeText(g_textCodePage, path).c_str(), L"w");
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(FormatOwnedString("Simulator Result File Create %s %s!!!!!!!!!!!!", file ? "success" : "Fail", itemName.c_str()).c_str()),
file ? 0xFFFF : 0xFF, 0, 0, 0);
return file;
}
#pragma pack(push, 1)
struct RandomOptionSimulationRecord {
/* 0000 */ int optionId;
/* 0004 */ int unknown_0004;
/* 0008 */ int unknown_0008;
/* 000C */ unsigned char optionType;
/* 000D */ int rate;
/* 0011 */ int unknown_0011;
/* 0015 */ int unknown_0015;
/* 0019 */ int unknown_0019;
/* 001D */ int unknown_001D;
/* 0021 */ int unknown_0021;
};
#pragma pack(pop)
static_assert(sizeof(RandomOptionSimulationRecord) == 0x25);
// OFFSET: 0x00D606B0
// FUNCTION: fn_21974
void CGameMode::ReceiveRandomOptionSimulation(const unsigned char* packet) {
const SimulationPacketHeader* header = reinterpret_cast<const SimulationPacketHeader*>(packet);
std::string itemName;
const char* name = reinterpret_cast<const char*>(header->unknown_000C);
std::FILE* file = this->OpenRandomOptionSimulatorFile("\\PackageItemTest", std::string(name));
if (!file) {
return;
}
const char* typeNames[6] = {
"RANDOM_OPT_TYPE_MUST_1", "RANDOM_OPT_TYPE_MUST_2", "RANDOM_OPT_TYPE_MUST_3",
"RANDOM_OPT_TYPE_MUST_4", "RANDOM_OPT_TYPE_MUST_5", "RANDOM_OPT_TYPE_RANDOM",
};
const RandomOptionSimulationRecord* record = reinterpret_cast<const RandomOptionSimulationRecord*>(packet + sizeof(SimulationPacketHeader));
const int count = static_cast<int>((header->length - sizeof(SimulationPacketHeader)) / sizeof(RandomOptionSimulationRecord));
std::vector<const RandomOptionSimulationRecord*> options[6];
for (int i = 0; i < count; ++i) {
options[record->optionType].push_back(record);
++record;
}
std::fprintf(file, "\t%s", ToUtf8(std::string(name), g_textCodePage).c_str());
std::fprintf(file, "============================\tSTART\t============================\n");
int total = 0;
for (int type = 0; type < 6; ++type) {
if (options[type].empty()) {
continue;
}
std::fprintf(file, "\n%s\n", typeNames[type]);
for (const RandomOptionSimulationRecord* option : options[type]) {
const char* optionName = nullptr;
if (g_luaScript->Call("GetVarOptionName", "d>s", option->optionId, &optionName)) {
std::fprintf(file, "\t%s", ToUtf8(std::string(optionName), g_textCodePage).c_str());
if (type == 5) {
std::fprintf(
file, "\t\t%d\t%d\t(%d/%d)\t%d\t(%d/%d)\t%.2f%%\n", option->unknown_0019, option->unknown_001D, option->unknown_0004,
option->unknown_0008, option->unknown_0021, option->unknown_0011, option->unknown_0015,
static_cast<float>(option->rate / 100.0)
);
} else {
std::fprintf(
file, "\t\t%d\t%d\t(%d/%d)\t%d\t(%d/%d)\n", option->unknown_0019, option->unknown_001D, option->unknown_0004,
option->unknown_0008, option->unknown_0021, option->unknown_0011, option->unknown_0015
);
}
}
++total;
}
}
std::fprintf(file, "Try %d RandomOption\n", total);
std::fprintf(file, "============================\tEND\t============================\n");
std::fclose(file);
}
// OFFSET: 0x00D2A020
// FUNCTION: fn_21701
void CGameMode::ReceiveBuyingStoreOpenResult(const unsigned char* packet) {
char text[128];
switch (*reinterpret_cast<const std::int16_t*>(packet + 2)) {
case 1:
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(1741)), 0xFF, 0, 0, 0);
reinterpret_cast<ClientItemLists*>(&g_session)->ClearItems1768();
g_windowMgr.CloseWindow(174);
g_windowMgr.CloseWindow(175);
break;
case 2:
std::sprintf(
text, LookupMessage(1742),
static_cast<int>(
static_cast<float>(*reinterpret_cast<const int*>(packet + 4) / 10 + g_session.m_weight) - static_cast<float>(g_session.m_maxWeight) * 0.9f
)
);
reinterpret_cast<WindowDialogs*>(&g_windowMgr)->Confirm(text, 0, true, false, 0, "Message", 280, 120, 0);
break;
case 9:
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(1797)), 0xFF, 0, 0, 0);
break;
case 10:
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(3229)), 0xFF, 0, 0, 0);
reinterpret_cast<ClientItemLists*>(&g_session)->ClearItems1768();
g_windowMgr.CloseWindow(174);
g_windowMgr.CloseWindow(175);
break;
}
}
// OFFSET: 0x00D316D0
// OFFSET: 0x00D4B050
// FUNCTION: fn_21863
void CGameMode::ReceiveItemObtainNotice(const unsigned char* packet) {
ITEM_INFO item;
item.SetItemId(*reinterpret_cast<const int*>(packet + 6));
item.unknown_0060 = 0;
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};
switch (*reinterpret_cast<const int*>(packet + 2)) {
case 0:
g_windowMgr.SendNotice(
1, reinterpret_cast<std::intptr_t>(FormatOwnedString(LookupMessage(911), naming.DisplayName(item, 0).c_str()).c_str()), 0xFFFF00, 0, 0, 0
);
break;
case 1:
g_windowMgr.SendNotice(
1, reinterpret_cast<std::intptr_t>(FormatOwnedString(LookupMessage(912), naming.DisplayName(item, 0).c_str()).c_str()), 0xCDCD00, 0, 0, 0
);
break;
case 2:
g_windowMgr.SendNotice(
1, reinterpret_cast<std::intptr_t>(FormatOwnedString(LookupMessage(913), naming.DisplayName(item, 0).c_str()).c_str()), 0xC8C8FF, 0, 0, 0
);
break;
case 3:
g_windowMgr.SendNotice(
1, reinterpret_cast<std::intptr_t>(FormatOwnedString(LookupMessage(914), naming.DisplayName(item, 0).c_str()).c_str()), 0xC8C8FF, 0, 0, 0
);
break;
}
}
// OFFSET: 0x00D8A460
// FUNCTION: fn_22219
void CGameMode::ReceiveTakeOffEquipItemResult(const unsigned char* packet) {
ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, *reinterpret_cast<const std::uint16_t*>(packet + 2));
item.unknown_0000[3] = *reinterpret_cast<const std::uint32_t*>(packet + 4);
switch (*reinterpret_cast<const std::uint16_t*>(packet + 8)) {
case 0: {
if (g_session.IsCostumeLocation(*reinterpret_cast<const int*>(packet + 4))) {
g_session.UnequipItem6B68(item);
} else {
g_session.UnequipItem61B8(item);
}
ItemDescriptions descriptions{g_itemDescriptions};
bool languagePrefix = false;
WORD language = g_serverLanguage->language;
ItemNaming naming{descriptions, g_itemCardNames, *g_playerNameDictionary, languagePrefix, g_serviceType, language};
const char* suffix = LookupMessage(3144);
g_windowMgr.SendNotice(
1, reinterpret_cast<std::intptr_t>(FormatOwnedString("%s%s", naming.DisplayName(item, 0).c_str(), suffix).c_str()), 0xC8FF00, 7, 0, 0
);
break;
}
case 1:
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(3009)), 0xFF, 0, 0, 0);
if (g_session.IsCostumeLocation(*reinterpret_cast<const int*>(packet + 4))) {
g_session.UnequipItem6B68(item);
} else {
g_session.UnequipItem61B8(item);
}
break;
}
}
// OFFSET: 0x00D2A290
// FUNCTION: fn_21703
void CGameMode::ReceiveBuyingStoreSellResult(const unsigned char* packet) {
switch (*reinterpret_cast<const std::int16_t*>(packet + 2)) {
case 5:
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(57)), 0xFF, 0, 0, 0);
break;
case 6: {
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
ITEM_INFO item = LookupClientItem(g_session.m_inventoryItems, *reinterpret_cast<const int*>(packet + 4), 0);
ItemDescriptions descriptions{g_itemDescriptions};
bool languagePrefix = false;
WORD language = g_serverLanguage->language;
ItemNaming naming{descriptions, g_itemCardNames, *g_playerNameDictionary, languagePrefix, g_serviceType, language};
g_windowMgr.SendNotice(
1, reinterpret_cast<std::intptr_t>(FormatOwnedString(LookupMessage(1747), naming.DisplayName(item, 0).c_str()).c_str()), 0xFF, 0, 0, 0
);
break;
}
case 7:
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(1745)), 0xFF, 0, 0, 0);
break;
}
g_windowMgr.CloseWindow(177);
g_windowMgr.CloseWindow(178);
g_windowMgr.CloseWindow(179);
}
// OFFSET: 0x00D31390
struct ReputePointEntry {
/* 0000 */ std::uint64_t id;
/* 0008 */ std::int64_t point;
};
// OFFSET: 0x00D78060
// FUNCTION: fn_22158
void CGameMode::ReceiveItemReformOpen(int itemId) {
UIWindow* window = g_windowMgr.EnsureWindow(0x15C);
if (!g_itemReformMgr) {
g_itemReformMgr = new (std::nothrow) CItemReformMgr;
}
if (g_itemReformMgr->HasItem(itemId) == true) {
if (window) {
window->SendMsg(nullptr, 0x17, itemId, 0, 0, 0);
}
} else {
g_windowMgr.CloseWindow(0x15C);
}
}
// OFFSET: 0x00D79880
// FUNCTION: fn_22174
void CGameMode::ReceiveReputeInfo(bool received, unsigned int count, const ReputePointEntry* entries) {
for (unsigned int index = 0; index < count; ++index) {
if (!CReputeMgr::s_instance) {
CReputeMgr::s_instance = new (std::nothrow) CReputeMgr;
}
CReputeMgr::s_instance->SetPoint(entries[index].id, entries[index].point);
}
if (!CReputeMgr::s_instance) {
CReputeMgr::s_instance = new (std::nothrow) CReputeMgr;
}
CReputeMgr::s_instance->SetPointsReceived(received);
}
// OFFSET: 0x00D79D90
// FUNCTION: fn_22181
void CGameMode::ReceiveEnchantResult(int messageId, int itemId) {
if (!CEnchantMgr::s_instance) {
CEnchantMgr::s_instance = new (std::nothrow) CEnchantMgr;
}
CEnchantMgr::s_instance->HandleEnchantResult(messageId, itemId);
}
// OFFSET: 0x00D7B4C0
// FUNCTION: fn_22205
void CGameMode::ReceiveReputeOpen(std::uint64_t groupId, std::uint64_t reputeId) {
if (!CReputeMgr::s_instance) {
CReputeMgr::s_instance = new (std::nothrow) CReputeMgr;
}
CReputeMgr::s_instance->OpenRepute(groupId, reputeId);
}
// OFFSET: 0x00D7B550
// FUNCTION: fn_22206
void CGameMode::ReceiveUiOpen(unsigned char type, std::uint64_t data) {
if (type == 10) {
if (!CEnchantMgr::s_instance) {
CEnchantMgr::s_instance = new (std::nothrow) CEnchantMgr;
}
CEnchantMgr::s_instance->OpenEnchant(data);
}
}
// OFFSET: 0x00D17AD0
// FUNCTION: fn_21596
void CGameMode::RefreshEmotionPurchaseSchedule() {
reinterpret_cast<CTimeScheduler*>(g_timeScheduler)->sub_BA95F0(5);
CCashEmotionMgr* manager = g_cashEmotionMgr;
if (!manager) {
return;
}
manager->sub_59C5A0();
const int expiry = manager->GetEarliestExpiry();
if (expiry < 0x7FFFFFFF) {
const std::uint64_t now = static_cast<std::int64_t>(manager->sub_59FC50()) * 10000000;
const std::int64_t interval = (static_cast<std::int64_t>(expiry) * 10000000 - static_cast<std::int64_t>(now)) / 10000;
if (interval != 0 && interval >= 0) {
reinterpret_cast<CTimeScheduler*>(g_timeScheduler)->AddSchedule(new CEmotionPurchaseExpireSchedule(now, interval, 1));
}
}
manager->RefreshCommands();
}
// OFFSET: 0x00D17BF0
// FUNCTION: fn_21733
void CGameMode::ReceivePartyItemPickupNotice(const unsigned char* packet) {
const std::uint32_t aid = *reinterpret_cast<const std::uint32_t*>(packet + 2);
MessengerMember member = ClientMessenger{g_session.m_partyMembers, g_session.m_friends}.PartyByAccount(aid);
if (aid != g_session.m_aid && member.valid) {
ITEM_INFO item;
item.unknown_0000[0] = packet[0x1F];
item.unknown_0000[2] = *reinterpret_cast<const std::uint16_t*>(packet + 0x1D);
item.unknown_0000[1] = *reinterpret_cast<const std::uint32_t*>(packet + 6);
item.unknown_0000[3] = 0;
item.SetItemId(*reinterpret_cast<const int*>(packet + 6));
std::memcpy(item.unknown_001C, packet + 0x0D, sizeof(item.unknown_001C));
item.identified = packet[0x0A];
item.unknown_005D = packet[0x0B];
item.unknown_0060 = packet[0x0C];
ItemDescriptions descriptions{g_itemDescriptions};
bool languagePrefix = false;
WORD language = g_serverLanguage->language;
ItemNaming naming{descriptions, g_itemCardNames, *g_playerNameDictionary, languagePrefix, g_serviceType, language};
g_windowMgr.SendNotice(
1, reinterpret_cast<std::intptr_t>(FormatOwnedString(LookupMessage(1276), member.name.c_str(), naming.DisplayName(item, 0).c_str()).c_str()),
0xFFFF00, 9, 0, 0
);
}
}
// OFFSET: 0x00D64940
// FUNCTION: fn_21995
void CGameMode::ReceiveEquipCardChange(const unsigned char* packet) {
const EquipSlots slots = g_session.GetEquipSlots(*reinterpret_cast<const std::int16_t*>(packet + 2));
ITEM_INFO item = g_session.GetItem17F0(slots.values[2]);
if (item.unknown_0000[1] != 0) {
int* cards = reinterpret_cast<int*>(item.unknown_001C);
switch (packet[0xA]) {
case 1:
cards[*reinterpret_cast<const std::int16_t*>(packet + 4)] = *reinterpret_cast<const int*>(packet + 6);
break;
case 2:
case 3:
cards[*reinterpret_cast<const std::int16_t*>(packet + 4)] = 0;
break;
}
g_session.SetEquipItem17F0(slots.values[2], item);
}
}
// OFFSET: 0x00D284D0
// FUNCTION: fn_21694
void CGameMode::ReceiveEquipWindowMicroscope2(const unsigned char* packet) {
reinterpret_cast<ClientItemLists*>(&g_session)->ResetEquipped();
g_session.ResetItems3500();
const int length = *reinterpret_cast<const std::int16_t*>(packet + 2);
const int count = static_cast<unsigned>(length - 45) / 38u;
const unsigned char* entry = packet + 45;
for (int index = 0; index < count; ++index, entry += 38) {
ITEM_INFO item;
item.unknown_0000[0] = entry[6];
item.unknown_0000[2] = *reinterpret_cast<const std::uint16_t*>(entry + 8);
item.unknown_0000[1] = *reinterpret_cast<const std::int16_t*>(entry);
item.unknown_0000[3] = *reinterpret_cast<const std::uint16_t*>(entry + 10);
item.quantity = 1;
std::memcpy(item.unknown_001C, entry + 14, sizeof(item.unknown_001C));
item.SetItemId(*reinterpret_cast<const int*>(entry + 2));
item.identified = entry[7];
item.unknown_005D = entry[12];
item.unknown_0060 = entry[13];
item.unknown_0068 = *reinterpret_cast<const std::uint32_t*>(entry + 30);
item.unknown_0064 = *reinterpret_cast<const std::uint16_t*>(entry + 34);
item.unknown_0070 = *reinterpret_cast<const std::uint16_t*>(entry + 36);
if (item.unknown_0000[3] != 0) {
if (g_session.IsCostumeLocation(item.unknown_0000[3])) {
g_session.EquipItem3500(item);
} else {
reinterpret_cast<ClientItemLists*>(&g_session)->Equip(item);
}
}
}
g_equipWindowLook.job = *reinterpret_cast<const std::int16_t*>(packet + 0x1C);
g_equipWindowLook.sex = packet[0x2C];
g_equipWindowLook.head = *reinterpret_cast<const std::int16_t*>(packet + 0x1E);
g_equipWindowLook.accessory = *reinterpret_cast<const std::int16_t*>(packet + 0x20);
g_equipWindowLook.accessory2 = *reinterpret_cast<const std::int16_t*>(packet + 0x22);
g_equipWindowLook.accessory3 = *reinterpret_cast<const std::int16_t*>(packet + 0x24);
g_equipWindowLook.bodyPalette = *reinterpret_cast<const std::int16_t*>(packet + 0x2A);
g_equipWindowLook.headPalette = *reinterpret_cast<const std::int16_t*>(packet + 0x28);
std::memcpy(g_equipWindowLook.name, packet + 4, sizeof(g_equipWindowLook.name));
g_equipWindowLook.robe = *reinterpret_cast<const std::int16_t*>(packet + 0x26);
if (!g_windowMgr.CloseWindow(0x8B)) {
g_windowMgr.EnsureWindow(0x8B);
}
}
// OFFSET: 0x00D28700
// FUNCTION: fn_21695
void CGameMode::ReceiveEquipWindowMicroscope3(const unsigned char* packet) {
reinterpret_cast<ClientItemLists*>(&g_session)->ResetEquipped();
g_session.ResetItems3500();
const int length = *reinterpret_cast<const std::int16_t*>(packet + 2);
const int count = static_cast<unsigned>(length - 45) / 41u;
const unsigned char* entry = packet + 45;
for (int index = 0; index < count; ++index, entry += 41) {
ITEM_INFO item;
item.unknown_0000[0] = entry[6];
item.unknown_0000[2] = *reinterpret_cast<const std::uint32_t*>(entry + 7);
item.unknown_0000[1] = *reinterpret_cast<const std::int16_t*>(entry);
item.unknown_0000[3] = *reinterpret_cast<const std::uint32_t*>(entry + 11);
item.quantity = 1;
std::memcpy(item.unknown_001C, entry + 16, sizeof(item.unknown_001C));
item.SetItemId(*reinterpret_cast<const int*>(entry + 2));
const unsigned char flags = entry[40];
item.identified = flags & 1;
item.unknown_005D = (flags >> 1) & 1;
item.unknown_0060 = entry[15];
item.unknown_0068 = *reinterpret_cast<const std::uint32_t*>(entry + 32);
item.unknown_0064 = *reinterpret_cast<const std::uint16_t*>(entry + 36);
item.unknown_0070 = *reinterpret_cast<const std::uint16_t*>(entry + 38);
if (item.unknown_0000[3] != 0) {
if (g_session.IsCostumeLocation(item.unknown_0000[3])) {
g_session.EquipItem3500(item);
} else {
reinterpret_cast<ClientItemLists*>(&g_session)->Equip(item);
}
}
}
g_equipWindowLook.job = *reinterpret_cast<const std::int16_t*>(packet + 0x1C);
g_equipWindowLook.sex = packet[0x2C];
g_equipWindowLook.head = *reinterpret_cast<const std::int16_t*>(packet + 0x1E);
g_equipWindowLook.accessory = *reinterpret_cast<const std::int16_t*>(packet + 0x20);
g_equipWindowLook.accessory2 = *reinterpret_cast<const std::int16_t*>(packet + 0x22);
g_equipWindowLook.accessory3 = *reinterpret_cast<const std::int16_t*>(packet + 0x24);
g_equipWindowLook.bodyPalette = *reinterpret_cast<const std::int16_t*>(packet + 0x2A);
g_equipWindowLook.headPalette = *reinterpret_cast<const std::int16_t*>(packet + 0x28);
memcpy_s(g_equipWindowLook.name, sizeof(g_equipWindowLook.name), packet + 4, sizeof(g_equipWindowLook.name));
g_equipWindowLook.robe = *reinterpret_cast<const std::int16_t*>(packet + 0x26);
if (!g_windowMgr.CloseWindow(0x8B)) {
g_windowMgr.EnsureWindow(0x8B);
}
}
// OFFSET: 0x00D4E5A0
// FUNCTION: fn_21877
void CGameMode::ReceiveGuildMemberAdd(const unsigned char* packet) {
GuildInfo* guildInfo = reinterpret_cast<GuildInfo*>(reinterpret_cast<char*>(&g_guildId) - offsetof(GuildInfo, m_guildId));
if (guildInfo->unknown_00C0 == 0) {
return;
}
char memo[51];
std::memcpy(memo, packet + 0x20, 50);
memo[50] = '\0';
char name[25];
std::memcpy(name, packet + 0x52, 24);
name[24] = '\0';
GuildInfo::Member member;
member.accountId = *reinterpret_cast<const int*>(packet + 2);
member.characterId = *reinterpret_cast<const int*>(packet + 6);
member.name = name;
member.unknown_0020 = *reinterpret_cast<const std::int16_t*>(packet + 0xA);
member.unknown_0024 = *reinterpret_cast<const std::int16_t*>(packet + 0xC);
member.job = *reinterpret_cast<const std::int16_t*>(packet + 0x10);
member.unknown_002C = *reinterpret_cast<const std::int16_t*>(packet + 0xE);
member.positionId = *reinterpret_cast<const int*>(packet + 0x1C);
member.level = *reinterpret_cast<const std::int16_t*>(packet + 0x12);
member.unknown_0050 = memo;
member.exp = *reinterpret_cast<const int*>(packet + 0x14);
member.online = *reinterpret_cast<const int*>(packet + 0x18);
guildInfo->AddMember(member);
const std::string playerName(name, 25);
g_playerNameDictionary->Set(*reinterpret_cast<const std::uint32_t*>(packet + 6), playerName.c_str());
guildInfo->UpdateMemberExpRatios();
g_windowMgr.RefreshGuildWindows();
}
// OFFSET: 0x00D510C0
// FUNCTION: fn_21889
void CGameMode::ReceiveGuildPositionInfo(const unsigned char* packet) {
GuildInfo* guildInfo = reinterpret_cast<GuildInfo*>(reinterpret_cast<char*>(&g_guildId) - offsetof(GuildInfo, m_guildId));
const int count = static_cast<unsigned>(*reinterpret_cast<const std::int16_t*>(packet + 2) - 4) >> 4;
guildInfo->unknown_00D4.clear();
const unsigned char* entry = packet + 4;
for (int index = 0; index < count; ++index, entry += 16) {
const int positionId = *reinterpret_cast<const int*>(entry);
std::string name;
name = guildInfo->m_positions[positionId];
const unsigned int mode = *reinterpret_cast<const unsigned int*>(entry + 4);
GuildInfo::Unknown00D4Entry position;
position.unknown_0000 = *reinterpret_cast<const int*>(entry + 8);
position.unknown_0004 = positionId;
position.unknown_0008 = name;
position.unknown_0020 = mode & 1;
position.unknown_0024 = (mode >> 4) & 1;
position.unknown_0028 = *reinterpret_cast<const int*>(entry + 12);
position.unknown_002C = (mode >> 8) & 1;
guildInfo->unknown_00D4.push_back(position);
}
guildInfo->unknown_00D4.sort([](const GuildInfo::Unknown00D4Entry& left, const GuildInfo::Unknown00D4Entry& right) {
return left.unknown_0004 < right.unknown_0004;
});
g_windowMgr.RefreshGuildWindows();
}
// FUNCTION: fn_21597
void CGameMode::RefreshEmotionSaleSchedule() {
reinterpret_cast<CTimeScheduler*>(g_timeScheduler)->sub_BA95F0(6);
CCashEmotionMgr* manager = g_cashEmotionMgr;
if (!manager) {
return;
}
const int expiry = manager->RefreshUnownedPacks().nextTime;
if (expiry < 0x7FFFFFFF) {
const std::uint64_t now = static_cast<std::int64_t>(manager->sub_59FC50()) * 10000000;
const std::int64_t interval = (static_cast<std::int64_t>(expiry) * 10000000 - static_cast<std::int64_t>(now)) / 10000;
if (interval != 0 && interval >= 0) {
reinterpret_cast<CTimeScheduler*>(g_timeScheduler)->AddSchedule(new CEmotionSaleExpireSchedule(now, interval, 1));
}
}
manager->RefreshCommands();
}
#pragma pack(push, 1)
struct MiniMapEffectMarkerPacket {
/* 0000 */ std::int16_t id;
/* 0002 */ int key;
/* 0006 */ std::int16_t x;
/* 0008 */ std::int16_t y;
};
#pragma pack(pop)
struct MiniMapEffectMarker {
/* 0000 */ int unknown_0000;
/* 0004 */ int x;
/* 0008 */ int y;
};
// GLOBAL: gl_25132
std::map<int, MiniMapEffectMarker> g_miniMapEffectMarkers;
// OFFSET: 0x00D244B0
// FUNCTION: fn_21667
void CGameMode::AddMiniMapEffectMarker(const unsigned char* packet) {
const MiniMapEffectMarkerPacket* marker = reinterpret_cast<const MiniMapEffectMarkerPacket*>(packet);
auto found = g_miniMapEffectMarkers.find(marker->key);
if (found != g_miniMapEffectMarkers.end()) {
found->second.x = marker->x;
found->second.y = marker->y;
found->second.unknown_0000 = 0x78;
return;
}
g_miniMapEffectMarkers.emplace(marker->key, MiniMapEffectMarker{0x78, marker->x, marker->y});
}
struct ActorMessage32 {
/* 0000 */ std::string text;
/* 0018 */ std::string extra;
/* 0030 */ int unknown_0030;
/* 0034 */ int unknown_0034;
/* 0038 */ int unknown_0038;
/* 003C */ int unknown_003C;
};
// OFFSET: 0x00D25AC0
// FUNCTION: fn_21675
void CGameMode::ReceiveActorMessage34(const unsigned char* packet) {
this->unknown_01AC[*reinterpret_cast<const std::uint32_t*>(packet + 8)] = *reinterpret_cast<const std::uint32_t*>(packet + 4);
ActorMessage32 message;
message.text.assign(reinterpret_cast<const char*>(packet + 17), *reinterpret_cast<const std::int16_t*>(packet + 2) - 17);
message.unknown_0030 = packet[16];
message.unknown_0034 = *reinterpret_cast<const std::int16_t*>(packet + 14);
message.unknown_0038 = *reinterpret_cast<const std::int16_t*>(packet + 12);
message.unknown_003C = *reinterpret_cast<const int*>(packet + 8);
if (message.text.size() > 60) {
message.text.resize(60);
}
UIWindow* window = g_windowMgr.EnsureWindow(0x1C);
window->SendMsg(nullptr, 0x22, reinterpret_cast<std::intptr_t>(&message), 0, 0, 0);
}
#pragma pack(push, 1)
struct AddQuestPacket {
/* 0000 */ std::int16_t packetType;
/* 0002 */ unsigned int questId;
/* 0006 */ unsigned char state;
/* 0007 */ __time32_t startTime;
/* 000B */ __time32_t endTime;
/* 000F */ std::int16_t huntCount;
};
struct AddQuestHunt64 {
/* 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 */ char name[24];
};
struct AddQuestHunt {
/* 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 */ char name[24];
};
#pragma pack(pop)
static_assert(sizeof(AddQuestPacket) == 0x11);
static_assert(sizeof(AddQuestHunt64) == 0x2E);
static_assert(sizeof(AddQuestHunt) == 0x2A);
// OFFSET: 0x00D20C00
// OFFSET: 0x00D20EF0
#pragma pack(push, 1)
struct BarterMarketItemListPacket {
/* 0000 */ std::int16_t packetType;
/* 0002 */ std::int16_t length;
};
struct BarterMarketItemRecord {
/* 0000 */ int itemId;
/* 0004 */ unsigned char type;
/* 0005 */ int amount;
/* 0009 */ int currencyItemId;
/* 000D */ int currencyAmount;
/* 0011 */ int weight;
/* 0015 */ int index;
/* 0019 */ std::uint16_t viewSprite;
/* 001B */ int location;
};
#pragma pack(pop)
static_assert(sizeof(BarterMarketItemRecord) == 0x1F);
// OFFSET: 0x00D215B0
// OFFSET: 0x00D17D30
// FUNCTION: fn_21598
void CGameMode::ReceiveNotifyBan(const unsigned char* packet) {
const int code = packet[2];
GetRagConnection().Close();
std::string text;
switch (code) {
case 0:
text = text + LookupMessage(3) + "(" + IntToString(0, 0) + ")";
break;
case 1:
text = text + LookupMessage(4) + "(" + IntToString(1, 0) + ")";
break;
case 2:
text = text + LookupMessage(5) + "(" + IntToString(2, 0) + ")";
break;
case 3:
text = text + LookupMessage(241) + "(" + IntToString(3, 0) + ")";
break;
case 4:
text = text + LookupMessage(264) + "(" + IntToString(4, 0) + ")";
break;
case 5:
text = text + LookupMessage(305) + "(" + IntToString(5, 0) + ")";
break;
case 9:
text = text + LookupMessage(529) + "(" + IntToString(9, 0) + ")";
break;
case 10:
text = text + LookupMessage(530) + "(" + IntToString(10, 0) + ")";
break;
case 15:
if (g_serviceType == 4) {
text = text + LookupMessage(579) + "(" + IntToString(15, 0) + ")";
}
break;
case 110:
text = text + LookupMessage(1589) + "(" + IntToString(110, 0) + ")";
break;
case 113:
text = text + LookupMessage(2021) + "(" + IntToString(113, 0) + ")";
break;
case 115:
text = text + LookupMessage(2347) + "(" + IntToString(115, 0) + ")";
break;
default:
text = text + LookupMessage(3) + "(" + IntToString(code, 0) + ")";
break;
}
if (text.size() == 0) {
text = LookupMessage(0x718);
}
reinterpret_cast<WindowDialogs*>(&g_windowMgr)->Confirm(text.c_str(), 0, true, true, 0, "Message", 280, 120, 0);
this->SendMsg(2, 0, 0, 0, 0);
}
#pragma pack(push, 1)
struct SkillFailurePacket {
/* 0000 */ std::int16_t packetType;
/* 0002 */ std::uint16_t skillId;
/* 0004 */ int value;
/* 0008 */ int itemId;
/* 000C */ unsigned char result;
/* 000D */ unsigned char cause;
};
#pragma pack(pop)
static_assert(sizeof(SkillFailurePacket) == 0xE);
// OFFSET: 0x00D1E840