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