Batch #7278 by superintelligence: 0 byte-identical, 5 confirmed by peer review. - fn_21886 CGameMode::ReceiveUnknownD50810: logic confirmed by peer review - fn_21885 CGameMode::ReceiveItem1748List: logic confirmed by peer review - fn_21970 CGameMode::ReceiveActorStatusValue: logic confirmed by peer review - fn_21773 CGameMode::ReceiveItem1718List: logic confirmed by peer review - fn_22191 CGameMode::Zc_Spirits2: logic confirmed by peer review Peer-reviewed-by: eAthena, Lumen, willerthal, ragnarok-clanker, gordaoprogramas, kyoshi, alisonrag, superintelligence Accepted without human review: peers confirmed the logic ("same" ahead by at least 3, with 70% of the votes).
2850 lines
100 KiB
C++
2850 lines
100 KiB
C++
#include "Client/Application/Launcher.h"
|
|
#include "File/ShortcutFilename.h"
|
|
#include "Client/Input/InputCharset.h"
|
|
#include "Client/Mode/CGameMode.h"
|
|
#include "UI/UIMacroDetectorWnd.h"
|
|
#include "UI/UIMacroBlackListCheckWnd.h"
|
|
#include "UI/UILapineScrollBar.h"
|
|
#include "UI/UICaptchaPreviewWnd.h"
|
|
#include "Client/Mode/ModeMgr.h"
|
|
#include "Client/Replay.h"
|
|
#include "Client/Session.h"
|
|
#include "Contents/Actors/ActorStateFlags.h"
|
|
#include "Contents/Actors/GameActor.h"
|
|
#include "Client/Mode/ModeMgr.h"
|
|
#include "Contents/Actors/Pc.h"
|
|
#include "Contents/Actors/RenderObject.h"
|
|
#include "Contents/Configuration/ServiceOptions.h"
|
|
#include "Contents/Effects/EffectActor.h"
|
|
#include "Contents/Effects/EffectLists.h"
|
|
#include "Contents/Effects/RagEffect.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/Messenger/ClientMessenger.h"
|
|
#include "Contents/PlayerNameDictionary.h"
|
|
#include "Contents/RouletteMgr.h"
|
|
#include "Contents/World/World.h"
|
|
#include "Network/Connection/Connection.h"
|
|
#include "Network/Packets/PacketLengths.h"
|
|
#include "Network/TextEncoding.h"
|
|
#include "UI/Item/UIItemStoreWnd.h"
|
|
#include "UI/Text/UIStaticText.h"
|
|
#include "UI/UIBarGraph.h"
|
|
#include "UI/Window/UIHomunInfoWnd.h"
|
|
#include "Contents/Sound/SoundMgr.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/Window/WindowDialogs.h"
|
|
#include "Utility/Math/Vector3d.h"
|
|
#include "Utility/Text/FormatString.h"
|
|
#include "Utility/Text/StringUtil.h"
|
|
|
|
#include <direct.h>
|
|
#include <io.h>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
struct SessionMessengerContext {
|
|
void UpdateRandomStats();
|
|
int GetList9Size() const;
|
|
void KeepEquipment();
|
|
};
|
|
|
|
struct SessionItemLists {
|
|
void ClearTradeItems();
|
|
};
|
|
|
|
#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);
|
|
};
|
|
|
|
void __fastcall sub_DFF150(CSession* session);
|
|
|
|
// GLOBAL: gl_24992
|
|
char g_pendingWhisperCount;
|
|
|
|
// GLOBAL: gl_25102
|
|
int g_whisperRecord;
|
|
|
|
// GLOBAL: gl_25097
|
|
UIWindow* g_saleOpenWindow = reinterpret_cast<UIWindow*>(0x039E23A6);
|
|
|
|
// GLOBAL: gl_25098
|
|
UIWindow* g_saleResultWindow = reinterpret_cast<UIWindow*>(0x039E3603);
|
|
|
|
// GLOBAL: gl_25099
|
|
UIWindow* g_vendingOpenWindow = reinterpret_cast<UIWindow*>(0x039E2CDC);
|
|
|
|
// GLOBAL: gl_25100
|
|
UIWindow* g_vendingOpenResultWindow = reinterpret_cast<UIWindow*>(0x039E2DC6);
|
|
|
|
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 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(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));
|
|
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: 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: 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: 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;
|
|
}
|
|
|
|
// 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
|
|
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 (reinterpret_cast<int(__thiscall*)(UIWindowMgr*, const char*, const char*, int, int)>(0x00A8B3D0)(
|
|
&g_windowMgr, target.c_str(), line.c_str(), 0x7800, 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) {
|
|
reinterpret_cast<void(__thiscall*)(CGameMode*, const char*)>(0x00CED760)(this, 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) {
|
|
reinterpret_cast<void(__thiscall*)(CGameMode*, const char*)>(0x00CED760)(this, text.c_str());
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00D08390
|
|
void CGameMode::sub_D08390(const unsigned char* packet) {
|
|
std::string title;
|
|
title.assign(reinterpret_cast<const char*>(packet + 0x1C), 0x80);
|
|
std::string name;
|
|
name.assign(reinterpret_cast<const char*>(packet + 2), 0x10);
|
|
const int first = *reinterpret_cast<const short*>(packet + 0x12);
|
|
const int second = *reinterpret_cast<const short*>(packet + 0x14);
|
|
const int third = *reinterpret_cast<const int*>(packet + 0x16);
|
|
const int fourth = *reinterpret_cast<const short*>(packet + 0x1A);
|
|
reinterpret_cast<void(__thiscall*)(CGameMode*, std::string, int, int, int, int, std::string)>(0x00D06CB0)(
|
|
this, std::string(name.c_str()), first, second, third, fourth, std::string(title.c_str()));
|
|
}
|
|
|
|
// OFFSET: 0x00D08110
|
|
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 = reinterpret_cast<UIWindow*(__thiscall*)(UIWindowMgr*, int)>(0x00A978D0)(&g_windowMgr, 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);
|
|
std::string name;
|
|
reinterpret_cast<void(__thiscall*)(ITEM_INFO*, std::string*)>(0x006D59A0)(&item, &name);
|
|
const std::string text = FormatOwnedString(LookupMessage(0xE7), name.c_str(), item.quantity);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.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
|
|
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 = reinterpret_cast<UIWindow*(__thiscall*)(UIWindowMgr*, int)>(0x00A978D0)(&g_windowMgr, 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: 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: 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
|
|
|
|
// 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);
|
|
}
|
|
}
|