Batch #10785 by kyoshi: 1 byte-identical, 0 confirmed by peer review. - fn_21247 CGameMode::CompleteUnknown0194: byte-identical Merged automatically: every function is byte-identical to the original.
11139 lines
389 KiB
C++
11139 lines
389 KiB
C++
#include "Client/Mode/CGameMode.h"
|
|
#include "Client/Mode/CLoginMode.h"
|
|
#include "Client/Mode/ModeMgr.h"
|
|
#include "Client/Replay.h"
|
|
#include "Client/Input/InputCharset.h"
|
|
#include "Client/Session.h"
|
|
#include "Contents/Actors/Npc.h"
|
|
#include "Contents/Actors/Pc.h"
|
|
#include "Contents/Camera/Camera.h"
|
|
#include "Contents/Configuration/ServiceConfiguration.h"
|
|
#include "Contents/Configuration/ServiceOptions.h"
|
|
#include "Contents/Effects/DummyEffectLauncher.h"
|
|
#include "Contents/Effects/EffectLists.h"
|
|
#include "Contents/Effects/SkillEffects.h"
|
|
#include "Contents/Effects/RagEffect.h"
|
|
#include "Contents/Jobs/JobInheritance.h"
|
|
#include "Contents/GuildInfo.h"
|
|
#include "Contents/GuildMgr.h"
|
|
#include "Contents/MessageTable.h"
|
|
#include "Contents/Actors/MousePointer.h"
|
|
#include "Contents/Actors/RenderObject.h"
|
|
#include "Contents/Items/ItemInfo.h"
|
|
#include "Contents/PlayerNameDictionary.h"
|
|
#include "Contents/Skills/ClientSkills.h"
|
|
#include "Contents/Skills/SkillInfo.h"
|
|
#include "Contents/Sound/SoundMgr.h"
|
|
#include "Contents/World/World.h"
|
|
#include "Network/Connection/Connection.h"
|
|
#include "Network/Packets/PacketLengths.h"
|
|
#include "Network/Packets/PacketId.h"
|
|
#include "Render/Renderer.h"
|
|
#include "Resource/World/TerrainResource.h"
|
|
#include "Script/LuaScript.h"
|
|
#include "UI/UIBroadcastBalloon.h"
|
|
#include "UI/Chat/UINewChatWnd.h"
|
|
#include "UI/Window/UIWindow.h"
|
|
#include "UI/Window/UIWindowMgr.h"
|
|
#include "UI/Edit/UIEditCtrl.h"
|
|
#include "Contents/Actors/GrannyGameActor.h"
|
|
#include "Utility/Text/FormatString.h"
|
|
#include "Utility/Text/TextTokens.h"
|
|
#include "Client/Application/Launcher.h"
|
|
#include "UI/Text/NavigationLink.h"
|
|
#include "Contents/RenewQuestMgr.h"
|
|
#include "Contents/Party/AdventurerAgencyMgr.h"
|
|
#include "Contents/Skills/AutomaticSkills.h"
|
|
#include "UI/Shortcuts/UIShortCutWnd.h"
|
|
#include "Contents/MapInfoMgr.h"
|
|
#include <timeapi.h>
|
|
#include "File/File.h"
|
|
#include "Client/Stove/StoveMgr.h"
|
|
#include "Contents/ShowRankingScheduler.h"
|
|
#include "Render/TextureQuad.h"
|
|
#include "UI/Cooldowns/CooldownOwner.h"
|
|
#include "Utility/Text/HexString.h"
|
|
#include "Client/Timer.h"
|
|
#include "Contents/MapSkyMgr.h"
|
|
#include "Contents/Messenger/WhisperBlockMgr.h"
|
|
#include "Contents/ForbiddenWords.h"
|
|
#include "Contents/Items/BarterMarketItemMgr.h"
|
|
#include "Client/Input/Language.h"
|
|
#include "UI/Chat/UIChatRoomMakeWnd.h"
|
|
#include "UI/Gauges/UIPcGage.h"
|
|
#include "Render/ScreenGeometry.h"
|
|
#include "UI/Shop/UIMerchantShopMakeWnd.h"
|
|
#include "UI/UIRefiningWnd.h"
|
|
#include "UI/UIGradeEnchantWnd.h"
|
|
#include "UI/Items/UISwapEquipmentWnd.h"
|
|
#include "UI/Window/UIMonsterInfoWnd.h"
|
|
#include "Contents/ClanInfo.h"
|
|
#include "Contents/Actors/ActorStateFlags.h"
|
|
#include "Contents/Items/SelectPackageItemMgr.h"
|
|
#include "Contents/Jobs/JobNames.h"
|
|
#include "Contents/NavigationManager.h"
|
|
#include "UI/Guild/UIGuildWnd.h"
|
|
#include "Contents/CashEmotionMgr.h"
|
|
#include "Contents/SimpleStringMgr.h"
|
|
#include "File/ShortcutFilename.h"
|
|
#include "UI/Window/UICntWnd.h"
|
|
#include "UI/Window/UINormalMB.h"
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <mbstring.h>
|
|
#include <new>
|
|
#include "Client/Application/ApplicationWindow.h"
|
|
#include "UI/Window/UINewSelectCharWnd.h"
|
|
#include "Network/TextEncoding.h"
|
|
|
|
extern "C" long long _Xtime_get_ticks();
|
|
|
|
#pragma pack(push, 1)
|
|
struct GameModeTextRecord {
|
|
/* 0000 */ std::uint32_t header;
|
|
/* 0004 */ std::int16_t length;
|
|
/* 0006 */ int firstLength;
|
|
/* 000A */ int secondLength;
|
|
/* 000E */ int unknown_000E;
|
|
/* 0012 */ int unknown_0012;
|
|
/* 0016 */ int unknown_0016;
|
|
/* 001A */ int unknown_001A;
|
|
/* 001E */ char buffer[0x172];
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
#pragma pack(push, 1)
|
|
struct GameModeReplayPacket {
|
|
/* 0000 */ std::uint32_t header;
|
|
/* 0004 */ std::uint16_t length;
|
|
/* 0006 */ unsigned char info[0x19];
|
|
/* 001F */ unsigned char data[0xDF];
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
#pragma pack(push, 1)
|
|
struct GameModePacketText40 {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ char text[40];
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
namespace {
|
|
struct RodexSendMailRequest {
|
|
/* 0000 */ int recipientId;
|
|
/* 0004 */ std::string recipient;
|
|
/* 001C */ std::string title;
|
|
/* 0034 */ std::string body;
|
|
/* 004C */ int zeny;
|
|
};
|
|
}
|
|
|
|
class ICashEmotionAction {
|
|
public:
|
|
virtual ~ICashEmotionAction();
|
|
virtual bool Execute(int packId, int argument) = 0;
|
|
|
|
bool ExecuteNamed(const char* name);
|
|
};
|
|
|
|
class CCashEmotionAction_Play : public ICashEmotionAction {
|
|
public:
|
|
CCashEmotionAction_Play();
|
|
~CCashEmotionAction_Play() override;
|
|
bool Execute(int packId, int emotionId) override;
|
|
|
|
protected:
|
|
/* 0004 */ int m_diceEmotion;
|
|
/* 0008 */ int m_yutEmotion;
|
|
};
|
|
|
|
#pragma pack(push, 1)
|
|
struct GameModePacketByte {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint8_t argument;
|
|
};
|
|
|
|
struct GameModePacketWord {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint16_t argument;
|
|
};
|
|
|
|
struct GameModePacketDword {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint32_t argument;
|
|
};
|
|
|
|
struct GameModePacketDwordByte {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint32_t argument;
|
|
/* 0006 */ std::uint8_t flag;
|
|
};
|
|
|
|
struct GameModePacketDwordByteByte {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint32_t argument;
|
|
/* 0006 */ std::uint8_t firstFlag;
|
|
/* 0007 */ std::uint8_t secondFlag;
|
|
};
|
|
|
|
struct GameModePacketDwordByteWord {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint32_t dwordArgument;
|
|
/* 0006 */ std::uint8_t byteArgument;
|
|
/* 0007 */ std::uint16_t wordArgument;
|
|
};
|
|
|
|
struct GameModePacketByteInt64 {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint8_t argument;
|
|
/* 0003 */ std::int64_t value;
|
|
};
|
|
|
|
struct GameModePacketDwordDwordByte {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint32_t firstArgument;
|
|
/* 0006 */ std::uint32_t secondArgument;
|
|
/* 000A */ std::uint8_t flag;
|
|
};
|
|
|
|
struct GameModePacketDwordDwordDword {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint32_t firstArgument;
|
|
/* 0006 */ std::uint32_t secondArgument;
|
|
/* 000A */ std::uint32_t thirdArgument;
|
|
};
|
|
|
|
struct GameModePacketPayload24 {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint8_t payload[24];
|
|
};
|
|
|
|
struct GameModePacketText100 {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ char text[100];
|
|
};
|
|
|
|
struct GameModePacketDwordPayload24 {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint32_t argument;
|
|
/* 0006 */ std::uint8_t payload[24];
|
|
};
|
|
|
|
struct GameModePacketDwordText60Text120 {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint32_t argument;
|
|
/* 0006 */ char firstText[60];
|
|
/* 0042 */ char secondText[120];
|
|
};
|
|
|
|
struct GameModePacketWordWord {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint16_t firstArgument;
|
|
/* 0004 */ std::uint16_t secondArgument;
|
|
};
|
|
|
|
struct GameModePacketWordDword {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint16_t wordArgument;
|
|
/* 0004 */ std::uint32_t dwordArgument;
|
|
};
|
|
|
|
struct GameModePacketWordWordWord {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint16_t firstArgument;
|
|
/* 0004 */ std::uint16_t secondArgument;
|
|
/* 0006 */ std::uint16_t trailingValue;
|
|
};
|
|
|
|
struct GameModePacketByteWord {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint16_t wordArgument;
|
|
/* 0004 */ std::uint8_t byteArgument;
|
|
};
|
|
|
|
struct GameModePacketByte3 {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint8_t firstByte;
|
|
/* 0003 */ std::uint8_t secondByte;
|
|
/* 0004 */ std::uint8_t thirdByte;
|
|
};
|
|
|
|
struct GameModePacketDwordWord {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint32_t dwordArgument;
|
|
/* 0006 */ std::uint16_t wordArgument;
|
|
};
|
|
|
|
struct GameModePacketDwordDword {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint32_t firstArgument;
|
|
/* 0006 */ std::uint32_t secondArgument;
|
|
};
|
|
|
|
struct GameModePacketDwordWordDword {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint32_t value;
|
|
/* 0006 */ std::uint16_t firstArgument;
|
|
/* 0008 */ std::uint32_t secondArgument;
|
|
};
|
|
|
|
struct GameModePacketWordText16 {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint16_t argument;
|
|
/* 0004 */ char text[16];
|
|
};
|
|
|
|
struct GameModePacketText16Words {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ char text[16];
|
|
/* 0012 */ std::uint16_t firstArgument;
|
|
/* 0014 */ std::uint16_t secondArgument;
|
|
};
|
|
|
|
struct GameModePacketC5 {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint32_t argument;
|
|
/* 0006 */ std::uint8_t flag;
|
|
};
|
|
|
|
struct GameModePacketBB {
|
|
/* 0000 */ std::uint16_t packetId;
|
|
/* 0002 */ std::uint16_t argument1;
|
|
/* 0004 */ std::uint8_t argument2;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(sizeof(GameModeReplayPacket) == 0xFE);
|
|
|
|
static_assert(sizeof(GameModeTextRecord) == 0x190);
|
|
static_assert(offsetof(GameModeTextRecord, buffer) == 0x1E);
|
|
static_assert(sizeof(GameModePacketByte) == 3);
|
|
static_assert(sizeof(GameModePacketWord) == 4);
|
|
static_assert(sizeof(GameModePacketDword) == 6);
|
|
static_assert(sizeof(GameModePacketDwordByte) == 7);
|
|
static_assert(sizeof(GameModePacketDwordByteByte) == 8);
|
|
static_assert(sizeof(GameModePacketDwordByteWord) == 9);
|
|
static_assert(sizeof(GameModePacketByteInt64) == 11);
|
|
static_assert(sizeof(GameModePacketDwordDwordByte) == 11);
|
|
static_assert(sizeof(GameModePacketDwordDwordDword) == 14);
|
|
static_assert(sizeof(GameModePacketPayload24) == 26);
|
|
static_assert(sizeof(GameModePacketText100) == 102);
|
|
static_assert(sizeof(GameModePacketDwordPayload24) == 30);
|
|
static_assert(sizeof(GameModePacketDwordText60Text120) == 186);
|
|
static_assert(sizeof(GameModePacketWordWord) == 6);
|
|
static_assert(sizeof(GameModePacketWordDword) == 8);
|
|
static_assert(sizeof(GameModePacketWordWordWord) == 8);
|
|
static_assert(sizeof(GameModePacketByteWord) == 5);
|
|
static_assert(sizeof(GameModePacketByte3) == 5);
|
|
static_assert(sizeof(GameModePacketDwordWord) == 8);
|
|
static_assert(sizeof(GameModePacketDwordDword) == 10);
|
|
static_assert(sizeof(GameModePacketDwordWordDword) == 12);
|
|
static_assert(sizeof(GameModePacketWordText16) == 20);
|
|
static_assert(sizeof(GameModePacketText16Words) == 22);
|
|
static_assert(sizeof(GameModePacketC5) == 7);
|
|
static_assert(sizeof(GameModePacketBB) == 5);
|
|
|
|
// GLOBAL: gl_24661
|
|
std::vector<ActiveSkillEffect> g_activeSkillEffects;
|
|
|
|
// OFFSET: 0x00CCF480
|
|
// FUNCTION: fn_21242
|
|
void CGameMode::PushUnknown01A4(int value) {
|
|
this->unknown_01A4.push_back(value);
|
|
}
|
|
|
|
// OFFSET: 0x00CCF530
|
|
// FUNCTION: fn_21243
|
|
bool CGameMode::IsOverWeight(bool notify) {
|
|
int maxWeight = g_session.m_maxWeight;
|
|
if (maxWeight < 1) {
|
|
maxWeight = 1;
|
|
}
|
|
|
|
if (g_session.m_weight * 100 / maxWeight >= 90) {
|
|
if (notify) {
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(307)), 255, 0, 0, 0);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// OFFSET: 0x00CCFCF0
|
|
// FUNCTION: fn_21247
|
|
__declspec(noinline) void CGameMode::CompleteUnknown0194(std::uint32_t id, const std::string& text) {
|
|
auto it = this->unknown_0194.find(id);
|
|
if (it != this->unknown_0194.end()) {
|
|
this->SendMsg(140, reinterpret_cast<int>(text.c_str()), it->second, 0, 0);
|
|
this->unknown_0194.erase(it);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CD52F0
|
|
// FUNCTION: fn_21279
|
|
int CGameMode::GetSkillAttackRange(int id, int level) {
|
|
if (id == 10000) {
|
|
return 5;
|
|
}
|
|
|
|
int range = 1;
|
|
CSkillInfo skill = g_session.LookupSkill(id);
|
|
if (!skill.available) {
|
|
skill = g_session.m_skillBundle.Pending(id);
|
|
if (!skill.available) {
|
|
return range;
|
|
}
|
|
|
|
level = skill.level;
|
|
}
|
|
|
|
int reduction = 0;
|
|
g_session.m_hotkeyScript->Call("GetSkillAttackRange", "ddd>dd", id, level, skill.level, &range, &reduction);
|
|
range += skill.unknown_001C - reduction;
|
|
return range;
|
|
}
|
|
|
|
// OFFSET: 0x00CD54D0
|
|
// FUNCTION: fn_21280
|
|
int CGameMode::TerrainHeight() const {
|
|
if (!this->scene || !this->scene->terrain) {
|
|
return 0;
|
|
}
|
|
|
|
return this->scene->terrain->height;
|
|
}
|
|
|
|
// OFFSET: 0x00CD54F0
|
|
// FUNCTION: fn_21281
|
|
int CGameMode::TerrainWidth() const {
|
|
if (!this->scene || !this->scene->terrain) {
|
|
return 0;
|
|
}
|
|
|
|
return this->scene->terrain->width;
|
|
}
|
|
|
|
// OFFSET: 0x00CD5550
|
|
// FUNCTION: fn_21283
|
|
std::string CGameMode::LocationText() {
|
|
char text[120];
|
|
std::memset(text, 0, sizeof(text));
|
|
|
|
int column;
|
|
int row;
|
|
const auto* player = reinterpret_cast<const CRenderObject*>(this->scene->player);
|
|
this->WorldCell(player->render.position.x, player->render.position.z, column, row);
|
|
|
|
std::string name = this->mapName;
|
|
if (name.size() > 4) {
|
|
name.resize(name.size() - 4);
|
|
}
|
|
|
|
std::sprintf(text, "Location: %s ( %d , %d )", name.c_str(), column, row);
|
|
return text;
|
|
}
|
|
|
|
// OFFSET: 0x00CD5800
|
|
// FUNCTION: fn_21284
|
|
bool CGameMode::HasInventoryItem(int id) {
|
|
const ITEM_INFO item = LookupClientItem(g_session.m_inventoryItems, id, 0);
|
|
return item.unknown_0000[1] != 0 && item.quantity > 0;
|
|
}
|
|
|
|
// OFFSET: 0x00CD58B0
|
|
// FUNCTION: fn_21285
|
|
bool CGameMode::HasResurrectionItem() {
|
|
ITEM_INFO item = LookupClientItem(g_session.m_inventoryItems, 7621, 0);
|
|
const CWorld* world = this->scene;
|
|
if (world->unknown_0048 || world->unknown_004C || world->unknown_0054) {
|
|
return false;
|
|
}
|
|
|
|
if (item.unknown_0000[1] != 0 && item.quantity > 0) {
|
|
return true;
|
|
}
|
|
|
|
item = LookupClientItem(g_session.m_inventoryItems, 6833, 0);
|
|
if (item.unknown_0000[1] != 0 && item.quantity > 0) {
|
|
return true;
|
|
}
|
|
|
|
item = LookupClientItem(g_session.m_inventoryItems, 6316, 0);
|
|
if (item.unknown_0000[1] != 0 && item.quantity > 0) {
|
|
return true;
|
|
}
|
|
|
|
item = LookupClientItem(g_session.m_inventoryItems, 6293, 0);
|
|
if (item.unknown_0000[1] != 0 && item.quantity > 0) {
|
|
return true;
|
|
}
|
|
|
|
item = LookupClientItem(g_session.m_inventoryItems, 25310, 0);
|
|
if (item.unknown_0000[1] != 0 && item.quantity > 0) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// OFFSET: 0x00CD5CD0
|
|
// FUNCTION: fn_21287
|
|
void CGameMode::SendMousePointerState(int value) {
|
|
if (this->mousePointer) {
|
|
this->mousePointer->SendMsg(nullptr, 2, 0, value, value >> 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CECE00
|
|
// FUNCTION: fn_21360
|
|
void CGameMode::ClearUnknown0458() {
|
|
*reinterpret_cast<int*>(reinterpret_cast<char*>(this) + 0x458) = 0;
|
|
}
|
|
|
|
// OFFSET: 0x00CECE10
|
|
// FUNCTION: fn_21361
|
|
void CGameMode::SetDragIds(int source, int id) {
|
|
if (id != -1) {
|
|
this->drag.source = source;
|
|
this->drag.id = static_cast<std::uint32_t>(id);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CED190
|
|
// FUNCTION: fn_21363
|
|
void CGameMode::UpdateUnknown0628(int id, bool add) {
|
|
if (add == true) {
|
|
this->unknown_0628.insert(id);
|
|
} else {
|
|
this->unknown_0628.erase(id);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CEFFC0
|
|
|
|
// OFFSET: 0x00CF0070
|
|
// FUNCTION: fn_21410
|
|
const char* CGameMode::Unknown04DCText() {
|
|
return reinterpret_cast<std::string*>(reinterpret_cast<char*>(this) + 0x4DC)->c_str();
|
|
}
|
|
|
|
// OFFSET: 0x00CF0320
|
|
// FUNCTION: fn_21412
|
|
CPlayer* CGameMode::Player() {
|
|
if (!this->scene) {
|
|
return nullptr;
|
|
}
|
|
return this->scene->player;
|
|
}
|
|
|
|
// OFFSET: 0x00CF0330
|
|
// FUNCTION: fn_21413
|
|
MinimapMarker* CGameMode::FindMinimapMarker(std::uint32_t key) {
|
|
const auto it = this->minimapMarkers.find(key);
|
|
if (it == this->minimapMarkers.end()) {
|
|
return nullptr;
|
|
}
|
|
return &it->second;
|
|
}
|
|
|
|
// OFFSET: 0x00CF05E0
|
|
// FUNCTION: fn_21415
|
|
std::string CGameMode::GetUnknown0084(unsigned int index) {
|
|
if (!this->unknown_0084.empty() && index <= this->unknown_0084.size()) {
|
|
return this->unknown_0084[index];
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
// OFFSET: 0x00CF06B0
|
|
// FUNCTION: fn_21416
|
|
float CGameMode::CameraDesiredYaw() {
|
|
if (!this->camera) {
|
|
return 0.0f;
|
|
}
|
|
return this->camera->camera.desiredYaw;
|
|
}
|
|
|
|
// OFFSET: 0x00CF06D0
|
|
// FUNCTION: fn_45499
|
|
int ConfirmGameModeActionB8() {
|
|
if (g_windowMgr.LookupWindow(0x271B)) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xDDF)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
g_modeMgr.gameMode->SendMsg(0xB8, 1, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
|
|
// OFFSET: 0x00CF0380
|
|
// FUNCTION: fn_21414
|
|
std::string CGameMode::GetActiveSkillEffectTimeText(int skillId, int* activeSkillId) {
|
|
std::string output;
|
|
*activeSkillId = skillId;
|
|
|
|
for (const ActiveSkillEffect& effect : g_activeSkillEffects) {
|
|
const int effectId = static_cast<int>(effect.id);
|
|
if (skillId != (effectId == 0x2A ? 0x0C : effectId)) {
|
|
continue;
|
|
}
|
|
|
|
*activeSkillId = effectId;
|
|
const std::uint32_t expiration = effect.unknown_0004;
|
|
if (expiration == 999999 || expiration == 0) {
|
|
return output;
|
|
}
|
|
|
|
std::uint32_t remainingSeconds = 0;
|
|
if (g_replayAnimationScaling == 0) {
|
|
remainingSeconds = (expiration - timeGetTime()) / 1000;
|
|
} else {
|
|
const int remainingMilliseconds = static_cast<int>(expiration) - static_cast<int>(Replay::Instance().elapsed);
|
|
if (remainingMilliseconds >= 1000) {
|
|
remainingSeconds = static_cast<std::uint32_t>(remainingMilliseconds) / 1000;
|
|
}
|
|
}
|
|
|
|
const int signedSeconds = static_cast<int>(remainingSeconds);
|
|
const int hours = signedSeconds / 3600;
|
|
if (hours != 0) {
|
|
output.append(FormatOwnedString("%d %s", hours, LookupMessage(0x6A1)));
|
|
}
|
|
|
|
const int remainder = signedSeconds - hours * 3600;
|
|
const int minutes = remainder / 60;
|
|
const int seconds = remainder % 60;
|
|
if (minutes != 0) {
|
|
output.append(FormatOwnedString(" %d %s", minutes, LookupMessage(0x70F)));
|
|
}
|
|
if (seconds != 0) {
|
|
output.append(FormatOwnedString(" %d %s", seconds, LookupMessage(0x710)));
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
// OFFSET: 0x00CF0A80
|
|
// FUNCTION: fn_21420
|
|
bool CGameMode::IsActiveSkillEffectId(std::uint32_t id) {
|
|
if (this->IsExcludedSkillEffectId(id)) {
|
|
return false;
|
|
}
|
|
|
|
for (const ActiveSkillEffect& effect : g_activeSkillEffects) {
|
|
if (effect.id == id) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// OFFSET: 0x00D07720
|
|
// FUNCTION: fn_21582
|
|
bool CGameMode::IsExcludedSkillEffectId(std::uint32_t id) {
|
|
return id == 0x28 || id == 0x2A;
|
|
}
|
|
|
|
// OFFSET: 0x00D07740
|
|
// FUNCTION: fn_21583
|
|
int CGameMode::SubD07740(int id, int defaultResult) {
|
|
switch (id) {
|
|
case 0x13:
|
|
case 0xFB4:
|
|
case 0xFCA:
|
|
case 0xFE4:
|
|
case 0xFEB:
|
|
case 0x1008:
|
|
case 0x10A7:
|
|
return 1;
|
|
case 0x14:
|
|
case 0xFB5:
|
|
case 0xFCB:
|
|
case 0xFE5:
|
|
case 0xFEC:
|
|
case 0x1009:
|
|
case 0x10A8:
|
|
return 0;
|
|
}
|
|
|
|
return defaultResult;
|
|
}
|
|
|
|
// OFFSET: 0x00CEB8E0
|
|
// FUNCTION: fn_21352
|
|
void CGameMode::sub_CEB8E0() {
|
|
if (Replay::Instance().state != 2) {
|
|
return;
|
|
}
|
|
|
|
GameModeTextRecord record = {};
|
|
record.header = 0x038808AE;
|
|
record.firstLength = static_cast<int>(this->unknown_03C8.size());
|
|
record.secondLength = static_cast<int>(this->unknown_03E0.size());
|
|
record.unknown_000E = this->unknown_03F8;
|
|
record.unknown_0012 = this->unknown_03FC;
|
|
record.unknown_0016 = this->unknown_0400;
|
|
record.unknown_001A = this->unknown_0404;
|
|
|
|
std::memcpy(record.buffer, this->unknown_03C8.data(), record.firstLength);
|
|
std::memcpy(record.buffer + record.firstLength, this->unknown_03E0.data(), record.secondLength);
|
|
record.length = static_cast<std::int16_t>(offsetof(GameModeTextRecord, buffer) + record.firstLength + record.secondLength);
|
|
|
|
Replay::Instance().Record(static_cast<std::uint16_t>(record.length), &record, 0x2A, 0);
|
|
}
|
|
|
|
// OFFSET: 0x00CEBF30
|
|
|
|
// OFFSET: 0x00CEC100
|
|
|
|
// OFFSET: 0x00CEC6A0
|
|
// FUNCTION: fn_21356
|
|
unsigned CGameMode::sub_CEC6A0(const std::vector<unsigned char>& data) {
|
|
if (data.empty()) {
|
|
return 0xFFFFFFFFu;
|
|
}
|
|
|
|
unsigned offset = 6;
|
|
if (*reinterpret_cast<const std::int16_t*>(data.data()) == 17000) {
|
|
while (offset < data.size()) {
|
|
const short type = *reinterpret_cast<const short*>(data.data() + offset);
|
|
const std::uint32_t size = *reinterpret_cast<const std::uint32_t*>(data.data() + offset + 2);
|
|
offset += 6;
|
|
|
|
if (type == 0xCD) {
|
|
std::vector<unsigned char> record(0x10);
|
|
std::memcpy(record.data(), data.data() + offset, size);
|
|
offset += size;
|
|
this->sub_D41250(record.data());
|
|
} else if (type == 0xCE) {
|
|
std::vector<unsigned char> record(0x61);
|
|
std::memcpy(record.data(), data.data() + offset, size);
|
|
offset += size;
|
|
this->sub_D40730(record.data());
|
|
} else if (type == 0x4269) {
|
|
break;
|
|
} else {
|
|
offset += size;
|
|
}
|
|
}
|
|
} else {
|
|
offset = 0xFFFFFFFFu;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
// OFFSET: 0x00CEFE50
|
|
// FUNCTION: fn_21407
|
|
void UIWindowMgr::ClearUnknown04DC() {
|
|
this->unknown_04DC.assign("", 0);
|
|
}
|
|
|
|
// GLOBAL: gl_24846
|
|
int g_followUpdateTick;
|
|
|
|
// GLOBAL: gl_24847
|
|
int g_followLostTick;
|
|
|
|
// OFFSET: 0x00CECB60
|
|
// FUNCTION: fn_21358
|
|
void CGameMode::SetFollowTicks(int updateTick, int lostTick) {
|
|
g_followUpdateTick = updateTick != -1 ? updateTick : g_followUpdateTick;
|
|
g_followLostTick = lostTick != -1 ? lostTick : g_followLostTick;
|
|
}
|
|
|
|
// OFFSET: 0x00CF0AC0
|
|
// FUNCTION: fn_21421
|
|
bool CGameMode::IsMenuWindowOpen() const {
|
|
return g_windowMgr.LookupWindow(0x122) != nullptr || g_windowMgr.LookupWindow(0x12E) != nullptr
|
|
|| g_windowMgr.LookupWindow(0x15C) != nullptr || g_windowMgr.LookupWindow(0x2716) != nullptr
|
|
|| g_windowMgr.LookupWindow(0x169) != nullptr;
|
|
}
|
|
|
|
// OFFSET: 0x00CF0B30
|
|
// FUNCTION: fn_21422
|
|
bool CGameMode::ShowRestrictedNotice(int grade) {
|
|
if (g_serviceMode == 3 || g_serviceType == 10 || grade < 2) {
|
|
return false;
|
|
}
|
|
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x31)), 255, 0, 0, 0);
|
|
g_windowMgr.unknown_04DC.assign("", 0);
|
|
return true;
|
|
}
|
|
|
|
void __stdcall sub_CE8F10(const void* info, const unsigned char* data);
|
|
int ConfirmGameModeAction96();
|
|
|
|
// OFFSET: 0x00CF10B0
|
|
// FUNCTION: fn_45487
|
|
int CGameMode::SendMsg(int event, int argument1, int argument2, int argument3, int argument4) {
|
|
switch (event) {
|
|
case 4:
|
|
this->SendMousePointerPosition(static_cast<float>(argument1), static_cast<float>(argument2), argument3);
|
|
return 0;
|
|
case 5:
|
|
this->SendMousePointerState(argument1);
|
|
return 0;
|
|
case 0x10:
|
|
if (!this->IsMenuWindowOpen() &&
|
|
*reinterpret_cast<const std::uint32_t*>(&this->unknown_0100[4]) + 2000U <= timeGetTime() &&
|
|
this->unknown_02CC == 0 && *reinterpret_cast<int*>(this->unknown_02D0) == 0 && argument1 != 0 &&
|
|
this->unknown_0250 == 0) {
|
|
*reinterpret_cast<int*>(this->unknown_02D0) = 1;
|
|
const std::uint16_t packet[3] = {
|
|
0x363, static_cast<std::uint16_t>(argument1), static_cast<std::uint16_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet[0]), packet);
|
|
}
|
|
this->SendMsg(0x12, 0, 0, 0, 0);
|
|
return 0;
|
|
case 0xE: {
|
|
const GameModePacketDword packet{0xCC, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xF: {
|
|
const std::uint16_t packet = 0xCE;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x16: {
|
|
const GameModePacketDword packet{0xB9, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x17: {
|
|
const GameModePacketDwordByte packet{
|
|
0xB8, static_cast<std::uint32_t>(argument2), static_cast<std::uint8_t>(argument1)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x19: {
|
|
const GameModePacketByte packet{0xB2, static_cast<std::uint8_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x20: {
|
|
const std::uint16_t packet = 0xC1;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x30:
|
|
if (g_windowMgr.window_027C != nullptr) {
|
|
const std::uint16_t packet = 0xE3;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
}
|
|
return 0;
|
|
case 0x2A:
|
|
this->ExecuteTalkType(argument1, reinterpret_cast<std::string*>(argument2));
|
|
return 0;
|
|
case 0x2E: {
|
|
char text[24];
|
|
std::strcpy(text, reinterpret_cast<const char*>(argument1));
|
|
GameModePacketDwordPayload24 packet;
|
|
packet.packetId = 0xE0;
|
|
packet.argument = static_cast<std::uint32_t>(argument2);
|
|
std::memcpy(packet.payload, text, sizeof(text));
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x2F: {
|
|
char text[24];
|
|
std::strcpy(text, reinterpret_cast<const char*>(argument1));
|
|
GameModePacketPayload24 packet;
|
|
packet.packetId = 0xE2;
|
|
std::memcpy(packet.payload, text, sizeof(text));
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x34: {
|
|
const std::uint16_t packet = 0xEB;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x35: {
|
|
const std::uint16_t packet = 0xED;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x36: {
|
|
const std::uint16_t packet = 0xEF;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x37: {
|
|
g_session.FlagInventoryItem(static_cast<std::uint32_t>(argument1));
|
|
const GameModePacketWordDword packet{
|
|
g_unknown_01738268 != 0 ? 0x9E1 : 0x364,
|
|
static_cast<std::uint16_t>(argument1), static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x38: {
|
|
g_session.FlagItem1738(static_cast<std::uint32_t>(argument1));
|
|
const GameModePacketWordDword packet{
|
|
g_unknown_01738268 != 0 ? 0x9E2 : 0x365,
|
|
static_cast<std::uint16_t>(argument1), static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x39: {
|
|
const std::uint16_t packet = g_unknown_01738268 != 0 ? 0x9BE : 0x193;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x49: {
|
|
const std::uint16_t packet = 0x118;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x4A: {
|
|
GameModePacketWordText16 packet{0x11B, static_cast<std::uint16_t>(argument2), {}};
|
|
std::strncpy(packet.text, reinterpret_cast<const char*>(argument1), sizeof(packet.text));
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x4B: {
|
|
const std::uint16_t packet = 0x11D;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x4C:
|
|
if (!this->IsMenuWindowOpen()) {
|
|
g_session.FlagInventoryItem(static_cast<std::uint32_t>(argument1));
|
|
const GameModePacketWordDword packet{
|
|
0x126, static_cast<std::uint16_t>(argument1), static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x4D:
|
|
if (!this->IsMenuWindowOpen()) {
|
|
g_session.FlagItem1740(static_cast<std::uint32_t>(argument1));
|
|
const GameModePacketWordDword packet{
|
|
0x127, static_cast<std::uint16_t>(argument1), static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x4E:
|
|
if (!this->IsMenuWindowOpen()) {
|
|
g_session.FlagItem1738(static_cast<std::uint32_t>(argument1));
|
|
const GameModePacketWordDword packet{
|
|
g_unknown_01738268 != 0 ? 0x9E4 : 0x128,
|
|
static_cast<std::uint16_t>(argument1), static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x4F:
|
|
if (!this->IsMenuWindowOpen()) {
|
|
g_session.FlagItem1740(static_cast<std::uint32_t>(argument1));
|
|
const GameModePacketWordDword packet{
|
|
g_unknown_01738268 != 0 ? 0x9E3 : 0x129,
|
|
static_cast<std::uint16_t>(argument1), static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x50: {
|
|
const GameModePacketByte packet{0xB35, static_cast<std::uint8_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x51: {
|
|
const std::uint16_t packet = 0x12E;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x43: {
|
|
*reinterpret_cast<int*>(&this->unknown_0100[0x0C]) = 1;
|
|
const GameModePacketWord packet{0x112, static_cast<std::uint16_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x5C: {
|
|
GameModePacketText16Words packet{
|
|
0x140, {}, static_cast<std::uint16_t>(argument2), static_cast<std::uint16_t>(argument3)
|
|
};
|
|
std::strncpy(packet.text, reinterpret_cast<const char*>(argument1), sizeof(packet.text));
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x57:
|
|
if (!this->IsMenuWindowOpen() &&
|
|
*reinterpret_cast<const std::uint32_t*>(&this->unknown_0100[4]) + 2000U <= timeGetTime() &&
|
|
this->unknown_0250 == 0) {
|
|
*reinterpret_cast<std::uint32_t*>(&this->unknown_0100[4]) = timeGetTime();
|
|
const GameModePacketWordDword packet{
|
|
static_cast<std::uint16_t>(ID_CZ_REQ_WEAR_EQUIP_V5), static_cast<std::uint16_t>(argument1),
|
|
static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x59: {
|
|
this->unknown_024C = 0;
|
|
g_windowMgr.CloseWindow(0x10);
|
|
g_windowMgr.CloseWindow(0x11);
|
|
const GameModePacketDword packet{0x146, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x5A:
|
|
if (g_serviceOptions.Get(7) != 0) {
|
|
if (g_soundMgr->secondaryEnabled == 0) {
|
|
g_soundMgr->PlayStream(nullptr, 0, false);
|
|
}
|
|
} else {
|
|
g_soundMgr->secondaryEnabled = 0;
|
|
g_soundMgr->StopStreams();
|
|
}
|
|
return 0;
|
|
case 0x5B:
|
|
if (argument1 != 0) {
|
|
GameModePacketText100 packet;
|
|
packet.packetId = 0x9CE;
|
|
std::memset(packet.text, 0, sizeof(packet.text));
|
|
StringFormat(packet.text, sizeof(packet.text), static_cast<std::size_t>(-1), "%s",
|
|
reinterpret_cast<const char*>(argument1));
|
|
GetRagConnection().Send(0x66, &packet);
|
|
}
|
|
return 0;
|
|
case 0x60: {
|
|
const GameModePacketDword packet{0x102, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x6B: {
|
|
const GameModePacketDword packet{0x14F, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x6D: {
|
|
const GameModePacketDword packet{0x157, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x72: {
|
|
const GameModePacketDwordDword packet{
|
|
0x16B, static_cast<std::uint32_t>(argument1), static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x69: {
|
|
const std::uint16_t packet = 0x14D;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x74: {
|
|
const GameModePacketWord packet{0xF3, 2};
|
|
GetRagConnection().Send(4, &packet);
|
|
return 0;
|
|
}
|
|
case 0x75:
|
|
if (g_serviceMode != 3) {
|
|
int duration = argument3;
|
|
if (duration < 0) {
|
|
duration = 0;
|
|
} else if (duration > 30000) {
|
|
duration = 30000;
|
|
}
|
|
const GameModePacketDwordByteWord packet{
|
|
0x149, static_cast<std::uint32_t>(argument1), static_cast<std::uint8_t>(argument2),
|
|
static_cast<std::uint16_t>(duration)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x76: {
|
|
GameModePacketDwordText60Text120 packet;
|
|
packet.packetId = 0x16E;
|
|
packet.argument = static_cast<std::uint32_t>(argument1);
|
|
if (g_inlineCharset == 0) {
|
|
std::strncpy(packet.firstText, reinterpret_cast<const char*>(argument2), 0x3B);
|
|
std::strncpy(packet.secondText, reinterpret_cast<const char*>(argument3), 0x77);
|
|
} else {
|
|
std::strcpy(packet.firstText, g_serverLanguage->Prefix(false));
|
|
std::strncpy(packet.firstText + 3, reinterpret_cast<const char*>(argument2), 0x38);
|
|
std::strcpy(packet.secondText, g_serverLanguage->Prefix(false));
|
|
std::strncpy(packet.secondText + 3, reinterpret_cast<const char*>(argument3), 0x74);
|
|
}
|
|
packet.firstText[0x3B] = 0;
|
|
packet.secondText[0x77] = 0;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x79: {
|
|
const GameModePacketWord packet{0x178, static_cast<std::uint16_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x80: {
|
|
const std::uint16_t packet[2] = {0x18A, 0};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet[0]), packet);
|
|
return 0;
|
|
}
|
|
case 0x7C: {
|
|
const GameModePacketWordWord packet{
|
|
0x17C, static_cast<std::uint16_t>(argument1), static_cast<std::uint16_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x7D: {
|
|
const GameModePacketDword packet{0x180, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x7B: {
|
|
*reinterpret_cast<int*>(this->unknown_045C) = argument1;
|
|
const GameModePacketWord packet{0x17A, static_cast<std::uint16_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x78: {
|
|
const GameModePacketDwordDword packet{
|
|
0x172, static_cast<std::uint32_t>(argument1), static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x7F: {
|
|
const GameModePacketDwordDword packet{
|
|
0x183, static_cast<std::uint32_t>(argument1), static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x82: {
|
|
GameModePacketDwordDwordDword packet{0x18E, 0, 0, 0};
|
|
if (argument1 != 0) {
|
|
const ITEM_INFO* materials = reinterpret_cast<const ITEM_INFO*>(argument2);
|
|
packet.firstArgument = static_cast<std::uint32_t>(std::atoi(materials[0].itemId.c_str()));
|
|
packet.secondArgument = static_cast<std::uint32_t>(std::atoi(materials[1].itemId.c_str()));
|
|
packet.thirdArgument = static_cast<std::uint32_t>(std::atoi(materials[2].itemId.c_str()));
|
|
}
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x86: {
|
|
const char* itemId = reinterpret_cast<const char*>(argument1);
|
|
this->drag.Clear();
|
|
this->drag.source = 0xE;
|
|
this->drag.name = itemId;
|
|
this->drag.resource = g_session.ItemDragResource(itemId, 1);
|
|
return 0;
|
|
}
|
|
case 0x88: {
|
|
const GameModePacketDword packet{0x362, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x89:
|
|
if (this->scene->player->unknown_02CC != 0 && (argument1 == 0 || argument1 == 7)) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x75D)), 0xFF, 0, 0, 0);
|
|
} else {
|
|
const GameModePacketDwordByte packet{
|
|
0x437, static_cast<std::uint32_t>(argument2), static_cast<std::uint8_t>(argument1)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x8A:
|
|
if (!this->IsMenuWindowOpen()) {
|
|
const GameModePacketByte3 packet{
|
|
0x35F,
|
|
static_cast<std::uint8_t>(argument1 >> 2),
|
|
static_cast<std::uint8_t>(((static_cast<std::uint32_t>(argument2) >> 4) & 0x3F) |
|
|
(static_cast<std::uint32_t>(argument1) << 6)),
|
|
static_cast<std::uint8_t>(static_cast<std::uint32_t>(argument2) << 4)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x8B: {
|
|
const GameModePacketByteWord packet{
|
|
0x361, static_cast<std::uint16_t>(argument2), static_cast<std::uint8_t>(argument1)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x8E: {
|
|
if (argument1 == 1) {
|
|
g_session.m_skillBundle.ResetFirstLevelChange();
|
|
}
|
|
const std::uint16_t packet = 0x197;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x8F: {
|
|
const GameModePacketWordWordWord packet{
|
|
0x198, static_cast<std::uint16_t>(argument1), static_cast<std::uint16_t>(argument2),
|
|
static_cast<std::uint16_t>(argument3 != 0)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x90: {
|
|
const GameModePacketDword packet{0x19D, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x91: {
|
|
GameModePacketPayload24 packet;
|
|
packet.packetId = 0x1A5;
|
|
const char* text = reinterpret_cast<const char*>(argument1);
|
|
const std::size_t length = std::strlen(text);
|
|
if (length < sizeof(packet.payload)) {
|
|
std::memcpy(packet.payload, text, length + 1);
|
|
} else {
|
|
std::memcpy(packet.payload, text, sizeof(packet.payload) - 1);
|
|
packet.payload[sizeof(packet.payload) - 1] = 0;
|
|
}
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x92: {
|
|
const GameModePacketWord packet{0x1A7, static_cast<std::uint16_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x93: {
|
|
const GameModePacketWord packet{0x1A8, static_cast<std::uint16_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x95: {
|
|
const GameModePacketDword packet{0x19F, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x97:
|
|
this->SendMsg(0x75, this->unknown_02E0, 0, argument1, 0);
|
|
g_session.DeleteProhibitionLog(this->unknown_02E0, argument1);
|
|
return 0;
|
|
case 0x98:
|
|
this->SendMsg(0x75, this->unknown_02E0, 1, argument1, 0);
|
|
g_session.AddProhibitionLog(this->unknown_02E0, argument1);
|
|
return 0;
|
|
case 0x99: {
|
|
const GameModePacketDword packet{0x1AE, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x9A:
|
|
if (argument2 != 0) {
|
|
const GameModePacketDwordByte packet{
|
|
0x980, static_cast<std::uint32_t>(argument2), static_cast<std::uint8_t>(argument1)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
} else {
|
|
const GameModePacketWord packet{0x1AF, static_cast<std::uint16_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x9B: {
|
|
const GameModePacketDword packet{
|
|
0x843, static_cast<std::uint32_t>(std::atoi(reinterpret_cast<const char*>(argument1)))
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x9C: {
|
|
GameModePacketPayload24 packet{0x1BB, {}};
|
|
std::strcpy(reinterpret_cast<char*>(packet.payload), reinterpret_cast<const char*>(argument1));
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x9D: {
|
|
const GameModePacketDword packet{
|
|
0x842, static_cast<std::uint32_t>(std::atoi(reinterpret_cast<const char*>(argument1)))
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x9E: {
|
|
GameModePacketPayload24 packet{0x1BD, {}};
|
|
std::strcpy(reinterpret_cast<char*>(packet.payload), reinterpret_cast<const char*>(argument1));
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x100: {
|
|
const GameModePacketDwordWord packet{
|
|
0x443, static_cast<std::uint32_t>(argument2), static_cast<std::uint16_t>(argument1)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xFD: {
|
|
const GameModePacketDwordDword packet{0x2D8, 0, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xA1: {
|
|
const std::uint16_t packet = 0x1C0;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0xA3: {
|
|
const GameModePacketDword packet{0x1CE, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xA7: {
|
|
const GameModePacketDwordDwordDword packet{
|
|
0x1E3,
|
|
*reinterpret_cast<const std::uint32_t*>(&this->unknown_028C[0]),
|
|
*reinterpret_cast<const std::uint32_t*>(&this->unknown_028C[4]),
|
|
static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xAD: {
|
|
const GameModePacketDwordDwordDword packet{
|
|
0x1F7,
|
|
*reinterpret_cast<const std::uint32_t*>(&this->unknown_028C[0]),
|
|
*reinterpret_cast<const std::uint32_t*>(&this->unknown_028C[4]),
|
|
static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xAE: {
|
|
GameModePacketPayload24 packet;
|
|
packet.packetId = 0xB66;
|
|
if (argument1 == -1) {
|
|
packet.payload[0] = 0xFF;
|
|
packet.payload[1] = 0xFF;
|
|
} else {
|
|
std::memcpy(packet.payload, reinterpret_cast<const void*>(argument1), sizeof(packet.payload));
|
|
}
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xA9: {
|
|
const std::uint16_t packet = 0x1E7;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0xA4:
|
|
this->SendNpcInputText(
|
|
argument1, reinterpret_cast<const char*>(argument2), reinterpret_cast<const char*>(argument3), argument4
|
|
);
|
|
return 0;
|
|
case 0x108: {
|
|
const GameModePacketDwordDwordByte packet{
|
|
0xAF8, static_cast<std::uint32_t>(argument1),
|
|
static_cast<std::uint32_t>(*reinterpret_cast<const int*>(argument3)),
|
|
static_cast<std::uint8_t>(argument2 != 0)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x109: {
|
|
const GameModePacketDwordDword packet{
|
|
0xAE6, static_cast<std::uint32_t>(*reinterpret_cast<const int*>(argument2)),
|
|
static_cast<std::uint32_t>(*reinterpret_cast<const int*>(argument1))
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x105:
|
|
g_windowMgr.sub_A978D0(0xA8);
|
|
return 0;
|
|
case 0x10D:
|
|
g_windowMgr.sub_A978D0(0xA9);
|
|
return 0;
|
|
case 0x103: {
|
|
const GameModePacketDwordByteByte packet{
|
|
0x7D7, static_cast<std::uint32_t>(argument1), static_cast<std::uint8_t>(argument2),
|
|
static_cast<std::uint8_t>(argument3)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x104: {
|
|
g_adventurerAgencyMgr->RequestStop();
|
|
const GameModePacketDword packet{0x7DA, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x114:
|
|
this->UpdateReplayPause(true);
|
|
Replay::Instance().SetState(7);
|
|
return 0;
|
|
case 0x115:
|
|
this->UpdateReplayPause(false);
|
|
Replay::Instance().SetState(6);
|
|
return 0;
|
|
case 0x117:
|
|
Replay::Instance().IncreaseSpeed();
|
|
static_cast<CGameMode*>(g_modeMgr.GetGameMode())->UpdateReplayActionSpeeds();
|
|
return 0;
|
|
case 0x118:
|
|
Replay::Instance().DecreaseSpeed();
|
|
static_cast<CGameMode*>(g_modeMgr.GetGameMode())->UpdateReplayActionSpeeds();
|
|
return 0;
|
|
case 0x116:
|
|
g_loginStartMode = 0x19;
|
|
Replay::Instance().SetState(6);
|
|
g_modeMgr.Switch(0, "login.rsw");
|
|
return 0;
|
|
case 0x119:
|
|
g_loginStartMode = 0x1A;
|
|
Replay::Instance().SetState(6);
|
|
g_modeMgr.Switch(0, "login.rsw");
|
|
return 0;
|
|
case 0x10E: {
|
|
const std::uint16_t packet = 0x815;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x11A: {
|
|
const GameModePacketDword packet{0x8B5, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x11F: {
|
|
const GameModePacketWord packet{0x97C, static_cast<std::uint16_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x129: {
|
|
const std::uint16_t packet = 0xA8C;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x12D: {
|
|
const GameModePacketDword packet{0xA80, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x132: {
|
|
const GameModePacketDword packet{0x2CF, 3};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x146: {
|
|
g_session.m_skillBundle.ResetFirstLevelChange();
|
|
const GameModePacketByte packet{0xBB1, static_cast<std::uint8_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xC2: {
|
|
const GameModePacketByteInt64 packet{
|
|
0x9EA, static_cast<std::uint8_t>(argument2), static_cast<std::int64_t>(argument1)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xC4: {
|
|
const GameModePacketByteInt64 packet{
|
|
0x9F5, static_cast<std::uint8_t>(argument2), static_cast<std::int64_t>(argument1)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x148: {
|
|
const GameModePacketDwordDword packet{
|
|
0x2D8, 5, argument1 == 0 ? 0x3C00u : 0u
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xB3: {
|
|
const GameModePacketDword packet{0x1F9, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xB0: {
|
|
const GameModePacketDwordDword packet{
|
|
0x203, static_cast<std::uint32_t>(argument1), static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xB1: {
|
|
GameModePacketPayload24 packet{0x213, {}};
|
|
std::memcpy(packet.payload, reinterpret_cast<const void*>(argument1), sizeof(packet.payload));
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xB2: {
|
|
GameModePacketPayload24 packet{0x212, {}};
|
|
std::memcpy(packet.payload, reinterpret_cast<const void*>(argument1), sizeof(packet.payload));
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xB6: {
|
|
const GameModePacketDword packet{0x222, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xB8: {
|
|
const GameModePacketByte packet{0x22D, static_cast<std::uint8_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xB9: {
|
|
GameModePacketPayload24 packet;
|
|
packet.packetId = 0x231;
|
|
const char* text = reinterpret_cast<const char*>(argument1);
|
|
const std::size_t length = std::strlen(text);
|
|
if (length < sizeof(packet.payload)) {
|
|
std::memcpy(packet.payload, text, length + 1);
|
|
} else {
|
|
std::memcpy(packet.payload, text, sizeof(packet.payload) - 1);
|
|
packet.payload[sizeof(packet.payload) - 1] = 0;
|
|
}
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xBA: {
|
|
const GameModePacketByte packet{0x29F, static_cast<std::uint8_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xBE: {
|
|
const GameModePacketByte packet{0x254, static_cast<std::uint8_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xBF: {
|
|
const std::uint16_t packet = 0x23F;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0xC1: {
|
|
const GameModePacketWord packet{0x246, static_cast<std::uint16_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xC5: {
|
|
GameModePacketDwordPayload24 packet{0x273, static_cast<std::uint32_t>(argument1), {}};
|
|
std::memcpy(packet.payload, reinterpret_cast<const void*>(argument2), sizeof(packet.payload));
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xC6: {
|
|
const GameModePacketDword packet{0x244, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xCF: {
|
|
const GameModePacketDwordWord packet{
|
|
0x25B, static_cast<std::uint32_t>(argument1), static_cast<std::uint16_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x12B: {
|
|
const std::uint16_t packet = 0xA94;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x136: {
|
|
const std::uint16_t packet = 0xB14;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x137: {
|
|
const std::uint16_t packet = 0xB16;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x138: {
|
|
const std::uint16_t packet = 0xB19;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x13E: {
|
|
const std::uint16_t packet = 0xB4F;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x13F: {
|
|
const std::uint16_t packet = 0xB51;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x13A:
|
|
if (this->unknown_02D4 == 0 && this->unknown_0250 == 0) {
|
|
this->unknown_02D4 = 1;
|
|
const GameModePacketWordWord packet{
|
|
0xB24, static_cast<std::uint16_t>(argument1), static_cast<std::uint16_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x13B:
|
|
if (argument1 != 0) {
|
|
const GameModePacketByte packet{0xB28, static_cast<std::uint8_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x13C:
|
|
if (argument1 != 0) {
|
|
const GameModePacketByte packet{0xB2C, static_cast<std::uint8_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0xFA: {
|
|
const std::uint16_t packet = 0x292;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0xF5:
|
|
this->unknown_024C = 0;
|
|
g_windowMgr.CloseWindow(0x2B);
|
|
g_windowMgr.CloseWindow(0x2C);
|
|
g_windowMgr.CloseWindow(0x0C);
|
|
g_windowMgr.CloseWindow(0xB1);
|
|
g_windowMgr.CloseWindow(0xB2);
|
|
g_windowMgr.CloseWindow(0xB3);
|
|
return 0;
|
|
case 0xF6: {
|
|
const std::uint16_t packet = 0x279;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x1A:
|
|
this->unknown_0028 = argument1;
|
|
if (argument1 == 0) {
|
|
*reinterpret_cast<int*>(this->unknown_00EC) = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[4]) = 0;
|
|
}
|
|
return 0;
|
|
case 0x1D:
|
|
if (this->unknown_02D4 == 0) {
|
|
this->unknown_02D4 = 1;
|
|
if (this->unknown_0250 == 0) {
|
|
const std::uint16_t packet = 0xBA;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
}
|
|
}
|
|
return 0;
|
|
case 0x1E:
|
|
if (this->unknown_02D4 == 0) {
|
|
this->unknown_02D4 = 1;
|
|
if (this->unknown_0250 == 0) {
|
|
const GameModePacketBB packet{
|
|
0xBB, static_cast<std::uint16_t>(argument1), static_cast<std::uint8_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
}
|
|
return 0;
|
|
case 0x12:
|
|
if (g_replayAnimationScaling == 0 || this->unknown_05EC[0] == 0) {
|
|
this->drag.source = 0;
|
|
this->drag.id = 0;
|
|
this->drag.quantity = 0;
|
|
g_windowMgr.ShowWindowById(15, 0);
|
|
}
|
|
return 0;
|
|
case 9:
|
|
return reinterpret_cast<int>(this->mapName);
|
|
case 0x21:
|
|
this->unknown_026E[0x16] = 0;
|
|
return 0;
|
|
case 0x25:
|
|
if (this->unknown_0250 == 0) {
|
|
const GameModePacketC5 packet{0xC5, static_cast<std::uint32_t>(argument1), 1};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x26:
|
|
if (this->unknown_0250 == 0) {
|
|
const GameModePacketC5 packet{0xC5, static_cast<std::uint32_t>(argument1), 0};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x41:
|
|
this->unknown_01B4.clear();
|
|
return 0;
|
|
case 0x47:
|
|
this->unknown_0408 = nullptr;
|
|
this->unknown_040C = 0;
|
|
this->unknown_0414 = 0;
|
|
g_pickInvert = 0;
|
|
return 0;
|
|
case 0xAC:
|
|
this->unknown_01BC.clear();
|
|
return 0;
|
|
case 0x5F:
|
|
return reinterpret_cast<int>(this->unknown_0408);
|
|
case 0x61:
|
|
return this->unknown_0414;
|
|
case 0x63:
|
|
if (this->scene->GetGameActorByAID(argument1) != nullptr) {
|
|
const GameModePacketDwordDword packet{
|
|
0x143, static_cast<std::uint32_t>(argument1), static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x65:
|
|
this->unknown_01FC = reinterpret_cast<const char*>(argument1);
|
|
this->actorMenuIds.clear();
|
|
this->actorMenuIds.push_back(0xB);
|
|
this->actorMenuIds.push_back(0x15);
|
|
return 0;
|
|
case 0x8D:
|
|
g_charServerAccountIdPending = 0;
|
|
g_loginStartMode = 3;
|
|
g_modeMgr.Switch(0, "login.rsw");
|
|
return 0;
|
|
case 0x123: {
|
|
const std::uint16_t packet = 0x9D4;
|
|
GetRagConnection().Send(2, &packet);
|
|
return 0;
|
|
}
|
|
case 0x124: {
|
|
const std::uint16_t packet = 0x9D8;
|
|
GetRagConnection().Send(2, &packet);
|
|
return 0;
|
|
}
|
|
case 0x125: {
|
|
const std::uint16_t packet = 0xA03;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
g_session.RestoreItems5C68();
|
|
g_session.ClearItemQuantities();
|
|
return 0;
|
|
}
|
|
case 0x135: {
|
|
const std::uint16_t packet = 0xB12;
|
|
GetRagConnection().Send(2, &packet);
|
|
return 0;
|
|
}
|
|
case 0x142: {
|
|
const std::uint16_t packet = 0xB58;
|
|
GetRagConnection().Send(2, &packet);
|
|
return 0;
|
|
}
|
|
case 0x143:
|
|
if (IsNavigationActive()) {
|
|
int value = argument1;
|
|
if (value < 0 || value >= 0xB) {
|
|
value = 0;
|
|
}
|
|
const GameModePacketDword packet{
|
|
static_cast<std::uint16_t>(ID_CZ_SE_CASHSHOP_OPEN2), static_cast<std::uint32_t>(value)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x14E: {
|
|
const GameModePacketBB packet{
|
|
0x907, static_cast<std::uint16_t>(argument1), static_cast<std::uint8_t>(argument2 == 1)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x14F:
|
|
if (!this->IsMenuWindowOpen()) {
|
|
g_session.FlagItem1740(static_cast<std::uint32_t>(argument1));
|
|
const GameModePacketDwordWordDword packet{
|
|
static_cast<std::uint16_t>(ID_CZ_MOVE_ITEM_TO_PERSONAL), 2, static_cast<std::uint16_t>(argument1),
|
|
static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
case 0x15:
|
|
this->SendMsg(0x10, static_cast<int>(this->drag.id), argument1, 0, 0);
|
|
return 0;
|
|
case 0x58:
|
|
this->SendMsg(0x80, 0, 0, 0, 0);
|
|
return 0;
|
|
case 0x24:
|
|
case 0x55:
|
|
case 0x62:
|
|
case 0x9F:
|
|
case 0xA0:
|
|
case 0xA6:
|
|
case 0x127:
|
|
return 0;
|
|
case 0x6: {
|
|
if (g_windowMgr.unknown_04DC.empty() || g_session.IsBerserkActive() == 1) {
|
|
return 0;
|
|
}
|
|
char text[0x16A];
|
|
std::strcpy(text, g_windowMgr.unknown_04DC.c_str());
|
|
if (g_forbiddenWords.Contains(text)) {
|
|
std::string replacement;
|
|
g_forbiddenWords.Mask(text, &replacement);
|
|
g_windowMgr.unknown_04DC.assign(text);
|
|
}
|
|
if (this->unknown_0438 == text) {
|
|
++this->unknown_0450;
|
|
} else {
|
|
this->unknown_0450 = 0;
|
|
}
|
|
if (this->ShowRestrictedNotice(this->unknown_0450)) {
|
|
return 0;
|
|
}
|
|
this->unknown_0438.assign(text);
|
|
char extendedPair[0x16A];
|
|
char extendedByte[0x16A];
|
|
char shortenedByte[0x16A];
|
|
char shortenedPair[0x16A];
|
|
std::memcpy(extendedPair, text, sizeof(text));
|
|
const int length = static_cast<int>(std::strlen(text));
|
|
if (length > 6) {
|
|
if (length + 3 < 0x16A) {
|
|
extendedPair[length + 2] = extendedPair[length];
|
|
extendedPair[length + 3] = extendedPair[length + 1];
|
|
extendedPair[length] = extendedPair[length - 2];
|
|
extendedPair[length + 1] = extendedPair[length - 1];
|
|
}
|
|
std::memcpy(extendedByte, text, sizeof(text));
|
|
if (length + 1 < 0x16A) {
|
|
extendedByte[length + 1] = extendedByte[length];
|
|
extendedByte[length] = extendedByte[length - 1];
|
|
}
|
|
std::memcpy(shortenedByte, text, sizeof(text));
|
|
if (length + 1 < 0x16A) {
|
|
shortenedByte[length - 1] = shortenedByte[length];
|
|
shortenedByte[length] = shortenedByte[length + 1];
|
|
}
|
|
std::memcpy(shortenedPair, text, sizeof(text));
|
|
if (length + 1 < 0x16A) {
|
|
shortenedPair[length - 2] = shortenedPair[length];
|
|
shortenedPair[length - 1] = shortenedPair[length + 1];
|
|
}
|
|
}
|
|
auto* chatTicks = reinterpret_cast<std::uint32_t*>(this->unknown_0574);
|
|
if (this->unknown_0468 == 10) {
|
|
for (int i = 0; i < 10; ++i) {
|
|
this->unknown_046C[i] = this->unknown_046C[i + 1];
|
|
chatTicks[i] = chatTicks[i + 1];
|
|
}
|
|
}
|
|
this->unknown_046C[this->unknown_0468].assign(text);
|
|
chatTicks[this->unknown_0468] = timeGetTime();
|
|
++this->unknown_0468;
|
|
if (this->unknown_0468 > 10) {
|
|
this->unknown_0468 = 10;
|
|
}
|
|
int matches = 0;
|
|
for (int i = 0; i <= this->unknown_0468; ++i) {
|
|
if (i == 10) {
|
|
const std::uint32_t elapsed = timeGetTime() - chatTicks[0];
|
|
if (elapsed != 0 && elapsed < 10000) {
|
|
this->RequestAdminStatus();
|
|
this->unknown_05A0 = 0;
|
|
break;
|
|
}
|
|
if (elapsed != 0 && elapsed < 30000) {
|
|
for (int j = 0; j < this->unknown_0468; ++j) {
|
|
if (this->unknown_046C[j].size() < 20) {
|
|
break;
|
|
}
|
|
if (j == this->unknown_0468 - 1) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>("TOO FAST CHATTING!"), 0x6E96FF, 0, 0, 0);
|
|
this->RequestAdminStatus();
|
|
this->unknown_05A0 = 0;
|
|
}
|
|
}
|
|
}
|
|
if (g_session.IsSuperNoviceClass(g_session.GetDisplayJob())) {
|
|
char first[0x16A];
|
|
char middle[0x400];
|
|
char last[0x16A];
|
|
if (g_serviceType == 0) {
|
|
std::sprintf(first, LookupMessage(0x316));
|
|
const char* suffix = LookupMessage(0x318);
|
|
const char* name = g_session.DecodePlayerName();
|
|
const char* prefix = LookupMessage(0x317);
|
|
std::sprintf(middle, "%s %s%s", prefix, name, suffix);
|
|
std::sprintf(last, LookupMessage(0x319));
|
|
} else {
|
|
std::sprintf(first, GetMessageString(0x316));
|
|
const char* suffix = GetMessageString(0x318);
|
|
const char* name = g_session.DecodePlayerName();
|
|
const char* prefix = GetMessageString(0x317);
|
|
std::sprintf(middle, "%s %s%s", prefix, name, suffix);
|
|
std::sprintf(last, GetMessageString(0x319));
|
|
}
|
|
if (this->unknown_046C[9] == last && this->unknown_046C[7] == first &&
|
|
this->scene->player->render.unknown_0070 != 3) {
|
|
if ((g_session.IsSuperNoviceJob(g_session.GetDisplayJob()) &&
|
|
g_session.m_level >= *reinterpret_cast<const int*>(g_session.unknown_7EE8)) ||
|
|
(g_session.IsSuperNovice2Job(g_session.GetDisplayJob()) &&
|
|
g_session.m_level >= *reinterpret_cast<const int*>(g_session.unknown_7EF0))) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x7DF)), 0xFF, 0, 0, 0);
|
|
break;
|
|
}
|
|
const std::uint16_t packet = 0x1ED;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
}
|
|
}
|
|
}
|
|
if (length > 6 &&
|
|
(this->unknown_046C[i] == text || this->unknown_046C[i] == extendedPair ||
|
|
this->unknown_046C[i] == extendedByte || this->unknown_046C[i] == shortenedByte ||
|
|
this->unknown_046C[i] == shortenedPair) &&
|
|
chatTicks[0] < timeGetTime() && timeGetTime() - chatTicks[i] < 30000 && ++matches >= 3) {
|
|
auto* repeatTicks = reinterpret_cast<std::uint32_t*>(this->unknown_05A4);
|
|
if (this->unknown_05A0 == 3) {
|
|
repeatTicks[0] = repeatTicks[1];
|
|
repeatTicks[1] = repeatTicks[2];
|
|
this->unknown_05A0 = 2;
|
|
}
|
|
repeatTicks[this->unknown_05A0] = timeGetTime();
|
|
if (this->unknown_05A0 >= 2 && repeatTicks[2] - repeatTicks[0] < 90000) {
|
|
this->RequestAdminStatus();
|
|
this->unknown_05A0 = 0;
|
|
} else if (this->unknown_05A0 < 3) {
|
|
++this->unknown_05A0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (g_navigationLinkParser->HasUnownedItemLink(g_windowMgr.unknown_04DC) == true) {
|
|
return 0;
|
|
}
|
|
char message[0x169]{};
|
|
const char* input = g_windowMgr.unknown_04DC.c_str();
|
|
const char* prefix = g_serverLanguage->Prefix(false);
|
|
const char* name = g_session.DecodePlayerName();
|
|
StringFormat(message, sizeof(message), static_cast<std::size_t>(-1), "%s : %s%s", name, prefix, input);
|
|
g_windowMgr.ClearUnknown04DC();
|
|
const std::size_t size = std::strlen(message);
|
|
unsigned char packet[0x16D];
|
|
const std::uint16_t header[2] = {0xF3, static_cast<std::uint16_t>(size + 4)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
std::memcpy(packet + 4, message, size);
|
|
GetRagConnection().Send(static_cast<int>(size + 4), packet);
|
|
return 0;
|
|
}
|
|
case 0x23: {
|
|
const int count = g_session.GetList4Size();
|
|
const std::uint32_t size = 4U + static_cast<std::uint32_t>(count) * 4U;
|
|
if (size > 0x800) {
|
|
return 0;
|
|
}
|
|
unsigned char packet[0x800];
|
|
const std::uint16_t header[2] = {0xC9, static_cast<std::uint16_t>(size)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
for (int i = 0; i < count; ++i) {
|
|
const ITEM_INFO item = g_session.GetItem1730At(i);
|
|
const std::uint16_t entry[2] = {
|
|
static_cast<std::uint16_t>(item.unknown_0000[1]), static_cast<std::uint16_t>(item.quantity)
|
|
};
|
|
std::memcpy(packet + 4 + i * 4, entry, sizeof(entry));
|
|
}
|
|
if (count != 0 && this->unknown_0250 == 0) {
|
|
GetRagConnection().Send(static_cast<std::int16_t>(size), packet);
|
|
}
|
|
g_session.ClearTradeItems();
|
|
g_windowMgr.CloseWindow(0x19);
|
|
g_windowMgr.CloseWindow(0x16);
|
|
g_windowMgr.CloseWindow(0x18);
|
|
return 0;
|
|
}
|
|
case 0x3F: {
|
|
const std::uint32_t accountId = static_cast<std::uint32_t>(argument1);
|
|
this->unknown_01B4[accountId].x = argument2;
|
|
this->unknown_01B4[accountId].y = argument3;
|
|
const MessengerMember member = g_session.PartyByAccount(accountId);
|
|
this->unknown_01B4[accountId].color = member.color;
|
|
return 0;
|
|
}
|
|
case 0x71: {
|
|
if (g_replayAnimationScaling != 0) {
|
|
return 0;
|
|
}
|
|
const auto* skill = reinterpret_cast<const CSkillInfo*>(argument1);
|
|
if (argument3 == 0 && this->scene->player->unknown_02CC != 0 &&
|
|
!g_session.IsHomunculusSkill(skill->id) && !g_session.IsMercenarySkill(skill->id)) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x75E)), 0xFF, 0, 0, 0);
|
|
g_session.m_automaticSkills.Complete(skill->id);
|
|
return 0;
|
|
}
|
|
this->SendMsg(0x47, 0, 0, 0, 0);
|
|
this->unknown_0418 = argument4 == -1;
|
|
switch (skill->unknown_000C) {
|
|
case 1:
|
|
this->SendMsg(0x48, 2, argument1, argument2, 0);
|
|
return 0;
|
|
case 2:
|
|
this->SendMsg(0x48, 1, argument1, argument2, 0);
|
|
return 0;
|
|
case 4: {
|
|
std::uint32_t target;
|
|
if (g_session.IsHomunculusSkill(skill->id)) {
|
|
target = *reinterpret_cast<const std::uint32_t*>(&g_session.unknown_5570[8]);
|
|
} else {
|
|
const bool mercenary = g_session.IsMercenarySkill(skill->id) != 0;
|
|
target = mercenary ? *reinterpret_cast<const std::uint32_t*>(&g_session.unknown_5620[8]) : g_session.m_aid;
|
|
}
|
|
this->SendMsg(0x45, skill->id, target, argument2, argument3);
|
|
this->SendMsg(0x48, 0, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
case 8:
|
|
this->SendMsg(0x48, 3, argument1, argument2, 0);
|
|
return 0;
|
|
case 16:
|
|
this->SendMsg(0x48, 4, argument1, argument2, 0);
|
|
return 0;
|
|
case 32:
|
|
this->SendMsg(0x48, 5, argument1, argument2, 0);
|
|
return 0;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
case 0x73: {
|
|
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(argument1));
|
|
if (actor == nullptr || actor->unknown_0305 != 0) {
|
|
return 0;
|
|
}
|
|
const GameModePacketDwordDwordDword packet{
|
|
0x168, static_cast<std::uint32_t>(argument1), g_session.m_aid, g_session.m_gid
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x11E: {
|
|
if (g_guildInfo.m_guildId == 0 || g_guildInfo.unknown_00AC == 0) {
|
|
return 0;
|
|
}
|
|
const char* name = reinterpret_cast<const char*>(argument1);
|
|
if (std::strlen(name) >= 24) {
|
|
g_windowMgr.Confirm(LookupMessage(0x213), 0, true, false, 0, "Message", 280, 120, 0);
|
|
return 0;
|
|
}
|
|
GameModePacketPayload24 packet;
|
|
packet.packetId = 0x916;
|
|
std::strncpy(reinterpret_cast<char*>(packet.payload), name, sizeof(packet.payload));
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
const std::string notice = FormatOwnedString(LookupMessage(0x17E), name);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(notice.c_str()), 0xFFFF00, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
case 0x134: {
|
|
unsigned char packet[0x800]{};
|
|
const int count = g_barterMarketItemMgr->GetAllItemCount();
|
|
const std::uint32_t size = 4U + static_cast<std::uint32_t>(count) * 14U;
|
|
if (size > sizeof(packet)) {
|
|
return 0;
|
|
}
|
|
const std::uint16_t header[2] = {0xB0F, static_cast<std::uint16_t>(size)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
unsigned char* output = packet + sizeof(header);
|
|
for (const BarterMarketItem& item : *g_barterMarketItemMgr->GetAllItems()) {
|
|
const int id = std::atoi(item.name.c_str());
|
|
const std::uint16_t index = static_cast<std::uint16_t>(g_session.FindInventoryIndexByItemId(item.field_2c));
|
|
std::memcpy(output, &id, 4);
|
|
std::memcpy(output + 4, &item.value, 4);
|
|
std::memcpy(output + 8, &index, 2);
|
|
std::memcpy(output + 10, &item.id, 4);
|
|
output += 14;
|
|
}
|
|
if (count > 0 && this->unknown_0250 == 0) {
|
|
GetRagConnection().Send(static_cast<std::int16_t>(size), packet);
|
|
}
|
|
return 0;
|
|
}
|
|
case 0xC:
|
|
this->unknown_019C[static_cast<std::uint32_t>(argument1)].first = argument2;
|
|
this->unknown_019C[static_cast<std::uint32_t>(argument1)].second = argument3;
|
|
return 0;
|
|
case 0x32: {
|
|
this->SendMsg(0x28, 0, 0, 0, 0);
|
|
g_session.ClearTradeItems();
|
|
const GameModePacketByte packet{0xE6, static_cast<std::uint8_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x3B: {
|
|
const char* name = reinterpret_cast<const char*>(argument1);
|
|
if (std::strlen(name) >= 24) {
|
|
g_windowMgr.Confirm(LookupMessage(0x213), 0, true, false, 0, "Message", 280, 120, 0);
|
|
return 0;
|
|
}
|
|
GameModePacketPayload24 packet;
|
|
packet.packetId = 0x2C4;
|
|
std::strncpy(reinterpret_cast<char*>(packet.payload), name, sizeof(packet.payload));
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
if (g_session.unknown_5464 != 0) {
|
|
const std::string message = std::string(name) + LookupMessage(0x80B);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message.c_str()), 0xFFFF00, 0, 0, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
case 0x68: {
|
|
if (g_guildInfo.unknown_00B4 == 0) {
|
|
return 0;
|
|
}
|
|
auto& positions = reinterpret_cast<std::map<int, GuildPositionEntry>&>(g_guildInfo.unknown_010C);
|
|
const std::int16_t length = static_cast<std::int16_t>(4U + 40U * positions.size());
|
|
if (length > 0x800) {
|
|
return 0;
|
|
}
|
|
unsigned char packet[0x800];
|
|
const std::uint16_t packetId = 0x161;
|
|
std::memcpy(packet, &packetId, sizeof(packetId));
|
|
std::memcpy(packet + 2, &length, sizeof(length));
|
|
unsigned char* output = packet + 4;
|
|
for (const auto& entry : positions) {
|
|
const auto& position = entry.second;
|
|
const int flags = (position.canInvite != 0 ? 1 : 0) | (position.canExpel != 0 ? 0x10 : 0) |
|
|
(position.canStorage != 0 ? 0x100 : 0);
|
|
std::memcpy(output, &position.unknown_0004, 4);
|
|
std::memcpy(output + 4, &flags, 4);
|
|
std::memcpy(output + 8, &position.id, 4);
|
|
std::memcpy(output + 12, &position.tax, 4);
|
|
std::strncpy(reinterpret_cast<char*>(output + 16), position.name.c_str(), 23);
|
|
output[39] = 0;
|
|
output += 40;
|
|
}
|
|
positions.clear();
|
|
GetRagConnection().Send(length, packet);
|
|
return 0;
|
|
}
|
|
case 0x8C: {
|
|
if (!g_serviceOptions.Get(0xA5) || (argument2 != 0 && argument2 != 1)) {
|
|
return 0;
|
|
}
|
|
char message[1024];
|
|
std::sprintf(message, LookupMessage(argument2 == 0 ? 0x1E6 : 0x1E5), argument1);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0xFFFF00, 4, 0, 0);
|
|
return 0;
|
|
}
|
|
case 0xA8: {
|
|
if (g_forbiddenWords.Contains(g_session.unknown_54AC.c_str())) {
|
|
g_windowMgr.Confirm(LookupMessage(14), 0, true, false, 0, "Message", 280, 120, 0);
|
|
return 0;
|
|
}
|
|
unsigned char packet[28];
|
|
const std::uint16_t packetId = 0x1E8;
|
|
std::memcpy(packet, &packetId, sizeof(packetId));
|
|
std::strncpy(reinterpret_cast<char*>(packet + 2), g_session.unknown_54AC.c_str(), 24);
|
|
packet[26] = static_cast<std::uint8_t>(argument2);
|
|
packet[27] = static_cast<std::uint8_t>(argument3);
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packetId), packet);
|
|
return 0;
|
|
}
|
|
case 0x111: {
|
|
g_session.CopyItems1760To1770();
|
|
const int count = g_session.GetList10Size();
|
|
const std::uint32_t size = 12U + static_cast<std::uint32_t>(count) * 8U;
|
|
if (size > 0x800) {
|
|
return 0;
|
|
}
|
|
unsigned char packet[0x800];
|
|
const std::uint16_t packetId = 0x819;
|
|
const std::uint16_t length = static_cast<std::uint16_t>(size);
|
|
std::memcpy(packet, &packetId, 2);
|
|
std::memcpy(packet + 2, &length, 2);
|
|
std::memcpy(packet + 4, &argument1, 4);
|
|
std::memcpy(packet + 8, &argument2, 4);
|
|
for (int index = 0; index < count; ++index) {
|
|
const ITEM_INFO item = g_session.GetItem1760At(index);
|
|
if (item.unknown_0000[1] != 0) {
|
|
const std::uint16_t itemIndex = static_cast<std::uint16_t>(item.unknown_0000[1]);
|
|
const int itemId = std::atoi(item.itemId.c_str());
|
|
const std::uint16_t quantity = static_cast<std::uint16_t>(item.quantity);
|
|
std::memcpy(packet + 12 + index * 8, &itemIndex, 2);
|
|
std::memcpy(packet + 14 + index * 8, &itemId, 4);
|
|
std::memcpy(packet + 18 + index * 8, &quantity, 2);
|
|
}
|
|
}
|
|
if (count == 0) {
|
|
return 0;
|
|
}
|
|
GetRagConnection().Send(static_cast<std::int16_t>(length), packet);
|
|
return 0;
|
|
}
|
|
case 0x112: {
|
|
Replay::Instance().ResetFile();
|
|
SYSTEMTIME time;
|
|
GetLocalTime(&time);
|
|
const std::uint32_t key0 = time.wYear | (static_cast<std::uint32_t>(static_cast<std::uint8_t>(time.wMonth)) << 16) |
|
|
(static_cast<std::uint32_t>(static_cast<std::uint8_t>(time.wDay)) << 24);
|
|
const std::uint32_t key1 = (static_cast<std::uint32_t>(static_cast<std::uint8_t>(time.wHour)) << 8) |
|
|
(static_cast<std::uint32_t>(static_cast<std::uint8_t>(time.wMinute)) << 16) |
|
|
(static_cast<std::uint32_t>(static_cast<std::uint8_t>(time.wSecond)) << 24);
|
|
int column;
|
|
int row;
|
|
this->WorldCell(this->scene->player->render.position.x, this->scene->player->render.position.z, column, row);
|
|
g_windowMgr.InitializeWindowPolicy();
|
|
char characterName[64]{};
|
|
std::sprintf(characterName, "%s", g_session.DecodePlayerName());
|
|
Replay::Instance().SetHeaderInfo(key0, key1, characterName, g_session.m_navigationPlayerMap, g_session.m_aid,
|
|
column, row, g_session.m_playerDir, g_serviceType, g_serviceMode, g_session.SyncUnknown0E98());
|
|
reinterpret_cast<Replay&>(ReplayFileList::Instance()).SetBaseFrame(reinterpret_cast<std::uint32_t>(&Replay::Instance()));
|
|
int windowIds[0x100];
|
|
const int windowCount = g_windowMgr.GetRenderedWindowIds(windowIds);
|
|
const int result = ReplayFileList::Instance().Open(0x1F, windowCount, reinterpret_cast<int>(windowIds));
|
|
if (result == 0) {
|
|
Replay::Instance().SetState(1);
|
|
return 0;
|
|
}
|
|
if (result == -2) {
|
|
Replay::Instance().SetState(1);
|
|
g_windowMgr.Confirm(LookupMessage(0x7C5), 0, true, false, 0, "Message", 280, 120, 0);
|
|
return 0;
|
|
}
|
|
char message[50]{};
|
|
std::sprintf(message, LookupMessage(0x7C6));
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0x62B0FF, 0, 0, 0);
|
|
Replay::Instance().SetState(2);
|
|
{
|
|
auto records = g_navigationManager.WriteReplayState();
|
|
Replay::Instance().WriteSection(0x18, records, 0xE);
|
|
}
|
|
{
|
|
auto records = g_session.BuildCharacterReplayRecords();
|
|
Replay::Instance().WriteSection(3, records, 0xE);
|
|
}
|
|
{
|
|
auto records = g_session.BuildStatsReplayRecords();
|
|
Replay::Instance().WriteSection(4, records, 0xE);
|
|
}
|
|
{
|
|
auto records = BuildRenewQuestReplayRecords();
|
|
Replay::Instance().WriteSection(6, records, 0xE);
|
|
}
|
|
{
|
|
auto records = g_session.BuildMessengerReplayRecords();
|
|
Replay::Instance().WriteSection(7, records, 0xE);
|
|
}
|
|
{
|
|
auto records = g_session.BuildItemReplayRecords();
|
|
Replay::Instance().WriteSection(8, records, 0xE);
|
|
}
|
|
{
|
|
auto records = g_session.BuildCompanionReplayRecords();
|
|
Replay::Instance().WriteSection(9, records, 0xE);
|
|
}
|
|
{
|
|
auto records = g_session.BuildExtraReplayRecords();
|
|
Replay::Instance().WriteSection(0xA, records, 0xE);
|
|
}
|
|
{
|
|
auto records = g_session.BuildReservedReplayRecords();
|
|
Replay::Instance().WriteSection(0xB, records, 0xE);
|
|
}
|
|
{
|
|
auto records = BuildEntryQueueReplayRecords();
|
|
Replay::Instance().WriteSection(0xC, records, 0xE);
|
|
}
|
|
{
|
|
auto records = g_session.BuildShortcutReplayRecords();
|
|
Replay::Instance().WriteSection(0xD, records, 0xE);
|
|
}
|
|
{
|
|
auto records = g_session.BuildShopReplayRecords();
|
|
Replay::Instance().WriteSection(0xE, records, 0xE);
|
|
}
|
|
{
|
|
auto records = this->SaveNameCardState();
|
|
Replay::Instance().WriteSection(0x16, records, 0xE);
|
|
}
|
|
{
|
|
auto records = this->SaveActiveSkillEffects();
|
|
Replay::Instance().WriteSection(0x12, records, 0xE);
|
|
}
|
|
{
|
|
auto records = this->SaveActorStates();
|
|
Replay::Instance().WriteSection(0xF, records, 0xE);
|
|
}
|
|
{
|
|
auto records = this->SaveGroundItems();
|
|
Replay::Instance().WriteSection(0x10, records, 0xE);
|
|
}
|
|
{
|
|
auto records = this->WriteReplaySkillState();
|
|
Replay::Instance().WriteSection(0x11, records, 0xE);
|
|
}
|
|
{
|
|
auto records = this->SaveUnknown024C();
|
|
Replay::Instance().WriteSection(0x17, records, 0xE);
|
|
}
|
|
{
|
|
auto records = g_windowMgr.SaveReplaySettings();
|
|
Replay::Instance().WriteSection(0x14, records, 0xE);
|
|
}
|
|
{
|
|
auto records = g_windowMgr.SaveReplayWindows();
|
|
Replay::Instance().WriteSection(0x13, records, 0xE);
|
|
}
|
|
{
|
|
auto records = g_windowMgr.SaveReplayReserved();
|
|
Replay::Instance().WriteSection(0x15, records, 0xE);
|
|
}
|
|
Replay::Instance().WriteHeader(0xB);
|
|
Replay::Instance().WriteFinalSection();
|
|
Replay::Instance().RecordCachedPackets();
|
|
Replay::Instance().RestartClock();
|
|
return 0;
|
|
}
|
|
case 0x11: {
|
|
if (this->drag.source == 0) {
|
|
return 0;
|
|
}
|
|
if (this->drag.source == 1) {
|
|
if (!g_session.HasInventoryItem(this->drag.id) ||
|
|
*reinterpret_cast<const std::uint32_t*>(&this->unknown_0100[4]) + 2000U > timeGetTime()) {
|
|
this->drag.source = 0;
|
|
return 0;
|
|
}
|
|
} else if (this->drag.source == 2 && !g_session.IsSlotItemIdentity(this->drag.id)) {
|
|
this->drag.source = 0;
|
|
return 0;
|
|
}
|
|
if (g_windowMgr.DropAt(argument1, argument2, &this->drag)) {
|
|
return 0;
|
|
}
|
|
if (this->drag.source == 0x10 || this->drag.source == 7) {
|
|
if (this->drag.skill) {
|
|
UIWindow* window = g_windowMgr.LookupWindow(this->drag.source == 0x10 ? 0x9F : 0x24);
|
|
if (window) {
|
|
window->RecordDrop(argument1, argument2, this->drag, -1);
|
|
window->Slot10(argument1, argument2, reinterpret_cast<std::intptr_t>(&this->drag));
|
|
}
|
|
} else {
|
|
ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, this->drag.id);
|
|
if (item.unknown_0000[1] > 0) {
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x6A0)), 0xFF, 0, 0, 0);
|
|
}
|
|
}
|
|
this->SendMsg(0x12, 0, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (this->drag.source == 1) {
|
|
if (g_windowMgr.unknown_01D4 == nullptr) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x2B2)), 0xFF, 0, 0, 0);
|
|
this->SendMsg(0x12, 0, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (g_session.m_lockItemDrop) {
|
|
this->drag.source = 0;
|
|
return 0;
|
|
}
|
|
}
|
|
if (this->drag.source == 0x1C) {
|
|
UIWindow* window = g_windowMgr.LookupWindow(0x127);
|
|
if (window) {
|
|
static_cast<UIRefiningWnd*>(window)->Reset();
|
|
}
|
|
this->SendMsg(0x12, 0, 0, 0, 0);
|
|
}
|
|
if (this->drag.source == 0x21) {
|
|
UIWindow* window = g_windowMgr.LookupWindow(0x157);
|
|
if (window) {
|
|
static_cast<UIGradeEnchantWnd*>(window)->ResetItem();
|
|
}
|
|
this->SendMsg(0x12, 0, 0, 0, 0);
|
|
}
|
|
if (this->unknown_024C == 0 && !g_windowMgr.LookupWindow(0x271B) &&
|
|
!g_windowMgr.unknown_01E0 && !g_windowMgr.window_0288 && !g_windowMgr.unknown_0458 &&
|
|
!g_windowMgr.LookupWindow(0x122) && !g_windowMgr.LookupWindow(0x12E) &&
|
|
!g_windowMgr.LookupWindow(0x127) && !g_windowMgr.LookupWindow(0x128) &&
|
|
!g_windowMgr.LookupWindow(0x14E) && !g_windowMgr.LookupWindow(0x157)) {
|
|
if (this->drag.source != 1) {
|
|
this->SendMsg(0x12, 0, 0, 0, 0);
|
|
g_windowMgr.RetireTransientWindow();
|
|
return 0;
|
|
}
|
|
if (this->ConfirmDraggedItemUse()) {
|
|
return 0;
|
|
}
|
|
if (this->drag.quantity == 1) {
|
|
this->SendMsg(0x10, this->drag.id, 1, 0, 0);
|
|
} else {
|
|
g_windowMgr.ShowWindowById(0xF, 1);
|
|
g_windowMgr.window_01EC->SendMsg(nullptr, 0xD, 0, 0, 0, 0);
|
|
}
|
|
g_windowMgr.RetireTransientWindow();
|
|
return 0;
|
|
}
|
|
this->SendMsg(0x12, 0, 0, 0, 0);
|
|
if (g_windowMgr.LookupWindow(0x128)) {
|
|
return 0;
|
|
}
|
|
if (g_windowMgr.unknown_01E0) {
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xBD)), 0xFF, 0, 0, 0);
|
|
}
|
|
if (g_windowMgr.unknown_0458) {
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xAB0)), 0xFF, 0, 0, 0);
|
|
}
|
|
g_windowMgr.RetireTransientWindow();
|
|
return 0;
|
|
}
|
|
case 0x2D: {
|
|
UIWindow* window = g_windowMgr.window_027C;
|
|
std::uint32_t& lastTick = *reinterpret_cast<std::uint32_t*>(&this->unknown_026E[0xE]);
|
|
if (timeGetTime() > lastTick + 1000U) {
|
|
this->unknown_00FC = 0;
|
|
}
|
|
if (window || this->unknown_00FC) {
|
|
return 0;
|
|
}
|
|
this->unknown_00FC = 1;
|
|
lastTick = timeGetTime();
|
|
GameModePacketDwordDwordDword packet;
|
|
packet.packetId = 0xD9;
|
|
packet.firstArgument = static_cast<std::uint32_t>(argument1);
|
|
if (argument2) {
|
|
char text[8];
|
|
std::strcpy(text, reinterpret_cast<const char*>(argument2));
|
|
std::memcpy(&packet.secondArgument, text, sizeof(text));
|
|
} else {
|
|
packet.secondArgument = 0;
|
|
packet.thirdArgument = 0;
|
|
}
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x3C: {
|
|
if (argument2 == 0) {
|
|
g_session.unknown_54C4.clear();
|
|
} else {
|
|
g_windowMgr.sub_A978D0(0x22);
|
|
}
|
|
const GameModePacketDwordByte packet{0x2C7, static_cast<std::uint32_t>(argument1), static_cast<std::uint8_t>(argument2 != 0)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x5D: {
|
|
if (CSkillInfo::UsesLevel(*g_session.m_hotkeyScript, this->unknown_040C)) {
|
|
CSkillInfo skill = g_session.m_skillBundle.Lookup(this->unknown_040C);
|
|
if (skill.available) {
|
|
this->unknown_0414 += argument1;
|
|
if (this->unknown_0414 > skill.level) {
|
|
this->unknown_0414 = skill.level;
|
|
}
|
|
if (this->unknown_0414 <= 0) {
|
|
this->unknown_0414 = 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
case 0x6A: {
|
|
if (g_guildInfo.unknown_00B4 == 0) {
|
|
return 0;
|
|
}
|
|
GameModePacketText40 packet;
|
|
packet.packetId = 0x15D;
|
|
const char* name = reinterpret_cast<const char*>(argument1);
|
|
std::strncpy(packet.text, name, 39);
|
|
packet.text[39] = 0;
|
|
if (std::strcmp(name, g_guildInfo.unknown_0000.c_str()) != 0) {
|
|
g_windowMgr.Confirm(LookupMessage(0x16E), 0, true, false, 0, "Message", 280, 120, 0);
|
|
return 0;
|
|
}
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x96: {
|
|
if (argument3 == 1) {
|
|
const int foodId = g_session.GetPetFood(g_session.unknown_103C);
|
|
int quantity;
|
|
{
|
|
ITEM_INFO item = LookupClientItem(g_session.m_inventoryItems, foodId, 0);
|
|
quantity = item.quantity;
|
|
}
|
|
if (quantity <= 0) {
|
|
ITEM_INFO item;
|
|
item.SetItemId(foodId);
|
|
char name[260]{};
|
|
int capacity = sizeof(name);
|
|
item.sub_6D5810(name, capacity, 0);
|
|
std::string text = FormatOwnedString(LookupMessage(0x24F), name);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.c_str()), 0x1E1EF5, 0, 0, 0);
|
|
g_windowMgr.SendNotice(0x13, reinterpret_cast<std::intptr_t>(text.c_str()), 0x1E1EF5, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
}
|
|
const GameModePacketByte packet{0x1A1, static_cast<std::uint8_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x10B: {
|
|
const std::uint32_t packet[3] = {0x000C07E4, static_cast<std::uint32_t>(argument1), 0};
|
|
GetRagConnection().Send(12, packet);
|
|
g_session.ClearTradeItems();
|
|
return 0;
|
|
}
|
|
case 0x12A: {
|
|
unsigned char packet[0x800]{};
|
|
const int count = g_session.GetList11Size();
|
|
const std::uint16_t packetId = 0xA92;
|
|
const std::uint16_t length = static_cast<std::uint16_t>(96 + count * 10);
|
|
std::memcpy(packet, &packetId, sizeof(packetId));
|
|
std::memcpy(packet + 2, &length, sizeof(length));
|
|
std::memcpy(packet + 4, &argument2, sizeof(argument2));
|
|
std::strncpy(reinterpret_cast<char*>(packet + 12), reinterpret_cast<const char*>(argument1), 79);
|
|
packet[91] = 0;
|
|
if (g_windowMgr.unknown_040C) {
|
|
const auto* window = static_cast<const UIMerchantShopMakeWnd*>(g_windowMgr.unknown_040C);
|
|
std::memcpy(packet + 92, &window->unknown_018A, sizeof(window->unknown_018A));
|
|
std::memcpy(packet + 94, &window->unknown_018C, sizeof(window->unknown_018C));
|
|
}
|
|
if (!g_replayAnimationScaling) {
|
|
g_session.unknown_550C = reinterpret_cast<const char*>(packet + 12);
|
|
}
|
|
unsigned char* output = packet + 96;
|
|
for (int index = 0; index < count; ++index) {
|
|
ITEM_INFO item = g_session.GetItem1768At(index);
|
|
if (item.unknown_0000[1] > 0) {
|
|
const int itemId = std::atoi(item.itemId.c_str());
|
|
const std::uint16_t quantity = static_cast<std::uint16_t>(item.quantity);
|
|
std::memcpy(output, &itemId, sizeof(itemId));
|
|
std::memcpy(output + 4, &quantity, sizeof(quantity));
|
|
std::memcpy(output + 6, &item.unknown_0014[1], sizeof(item.unknown_0014[1]));
|
|
output += 10;
|
|
}
|
|
}
|
|
GetRagConnection().Send(static_cast<std::int16_t>(length), packet);
|
|
return 0;
|
|
}
|
|
case 0xD:
|
|
this->unknown_019C.erase(static_cast<std::uint32_t>(argument1));
|
|
return 0;
|
|
case 0x3D: {
|
|
if (g_session.unknown_5948 == 1 || g_session.unknown_5948 == 2) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xBD3)), 0xFF, 0, 0, 0);
|
|
}
|
|
const int count = g_session.PartyCount();
|
|
if (g_session.unknown_5464 != 0) {
|
|
if (count > 1) {
|
|
bool online = false;
|
|
bool transferred = false;
|
|
for (int index = 0; index < count; ++index) {
|
|
const MessengerMember member = g_session.PartyAt(index);
|
|
if (member.accountId != g_session.m_aid && member.offline == 0) {
|
|
online = true;
|
|
if (member.map == this->mapName) {
|
|
g_modeMgr.gameMode->SendMsg(0x104, member.accountId, 0, 0, 0);
|
|
transferred = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!transferred) {
|
|
if (online) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xCC9)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (g_windowMgr.Confirm(LookupMessage(0xCB9), 2, false, false, 0, "Message", 280, 120, 0) != 0xBB) {
|
|
return 0;
|
|
}
|
|
}
|
|
} else if (count == 1) {
|
|
g_adventurerAgencyMgr->RequestStop();
|
|
}
|
|
}
|
|
if (g_windowMgr.unknown_042C != nullptr) {
|
|
g_windowMgr.CloseWindow(0xD0);
|
|
}
|
|
const std::uint16_t packet = 0x100;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x45: {
|
|
if (g_windowMgr.LookupWindow(0xC4) != nullptr) {
|
|
g_session.m_automaticSkills.Complete(argument1);
|
|
return 0;
|
|
}
|
|
if (argument4 == 0 && this->scene->player->unknown_02CC != 0 &&
|
|
!g_session.IsHomunculusSkill(argument1) && !g_session.IsMercenarySkill(argument1)) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x75E)), 0xFF, 11, 0, 0);
|
|
g_session.m_automaticSkills.Complete(argument1);
|
|
return 0;
|
|
}
|
|
if (this->IsMenuWindowOpen()) {
|
|
return 0;
|
|
}
|
|
this->RecordReplayMessage(event, argument1, argument2, argument3);
|
|
if (argument1 == 10000) {
|
|
if (static_cast<std::uint32_t>(argument2) == g_session.unknown_1010) {
|
|
return 0;
|
|
}
|
|
const CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(argument2));
|
|
if (actor != nullptr && actor->unknown_0314 == 0) {
|
|
return 0;
|
|
}
|
|
g_windowMgr.sub_A978D0(0x5B)->SendMsg(nullptr, 0x50, 0, argument2, 0, 0);
|
|
return 0;
|
|
}
|
|
if (argument1 == 20000) {
|
|
const GameModePacketDword packet{0x1E5, static_cast<std::uint32_t>(argument2)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
if (argument1 == 20001) {
|
|
char message[260];
|
|
std::sprintf(message, "[ (val1 == 20001) ]");
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0x6E96FF, 0, 0, 0);
|
|
const GameModePacketDword packet{0x1F9, static_cast<std::uint32_t>(argument2)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
if (argument1 == 40000) {
|
|
if (static_cast<std::uint32_t>(argument2) != g_session.unknown_1010) {
|
|
g_windowMgr.sub_A978D0(0xC4)->SendMsg(nullptr, 0x50, 0, argument2, 0, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
if (g_windowMgr.unknown_0304 != nullptr) {
|
|
return 0;
|
|
}
|
|
if (this->unknown_0418 == 0 && !g_session.IsRequestReady(argument1)) {
|
|
char message[260];
|
|
const char* name = CSkillInfo::DisplayName(*g_session.m_hotkeyScript, argument1);
|
|
std::sprintf(message, LookupMessage(0x5B4), name);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0xFF, 11, 0, 0);
|
|
g_session.m_automaticSkills.Complete(argument1);
|
|
return 0;
|
|
}
|
|
if (argument3 == 0) {
|
|
const CSkillInfo skill = g_session.LookupSkill(argument1);
|
|
if (skill.available != 0) {
|
|
argument3 = skill.level;
|
|
} else {
|
|
const CSkillInfo pending = g_session.m_skillBundle.Pending(argument1);
|
|
argument3 = pending.available != 0 ? pending.level : 0;
|
|
}
|
|
}
|
|
if ((!g_session.IsHomunculusSkill(argument1) && !g_session.IsMercenarySkill(argument1) &&
|
|
this->scene->player->render.unknown_0070 == 6) || g_windowMgr.window_027C != nullptr) {
|
|
g_session.m_automaticSkills.Complete(argument1);
|
|
return 0;
|
|
}
|
|
if (argument1 == 154 || argument1 == 41) {
|
|
if (*reinterpret_cast<const int*>(g_session.unknown_5570) < (argument1 == 154 ? 40 : 30)) {
|
|
char message[256];
|
|
std::sprintf(message, LookupMessage(0xCA));
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0xFF, 11, 0, 0);
|
|
return 0;
|
|
}
|
|
if (g_session.unknown_5C1C <= 0) {
|
|
char message[256];
|
|
std::sprintf(message, LookupMessage(0x294));
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0xFF, 11, 0, 0);
|
|
return 0;
|
|
}
|
|
if (argument1 == 154) {
|
|
g_windowMgr.sub_A978D0(0x5F);
|
|
}
|
|
}
|
|
const std::uint16_t id = static_cast<std::uint16_t>(argument1);
|
|
const std::uint16_t level = static_cast<std::uint16_t>(argument3);
|
|
if (g_session.m_automaticSkills.Contains(id)) {
|
|
g_session.m_automaticSkills.Use(static_cast<std::int16_t>(id), static_cast<std::int16_t>(level), argument2);
|
|
return 0;
|
|
}
|
|
unsigned char packet[10];
|
|
const std::uint16_t packetId = 0x438;
|
|
std::memcpy(packet, &packetId, sizeof(packetId));
|
|
std::memcpy(packet + 2, &level, sizeof(level));
|
|
std::memcpy(packet + 4, &id, sizeof(id));
|
|
std::memcpy(packet + 6, &argument2, sizeof(argument2));
|
|
if (id == 0x5D) {
|
|
g_monsterInfoActorId = argument2;
|
|
}
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packetId), packet);
|
|
return 0;
|
|
}
|
|
case 0x64: {
|
|
const std::string text(reinterpret_cast<const char*>(argument1));
|
|
this->miniMapTooltipId = argument2;
|
|
this->miniMapTooltipText = text;
|
|
if (text.empty() && argument2 == -1 && argument3 == 0) {
|
|
this->miniMapTooltipId = 11;
|
|
}
|
|
LowercaseText(this->miniMapTooltipText);
|
|
if (this->miniMapTooltipText.find(".bmp") == std::string::npos &&
|
|
this->miniMapTooltipText.find(".png") == std::string::npos) {
|
|
this->miniMapTooltipText.append(".bmp", 4);
|
|
}
|
|
this->UpdateMiniMapTooltip();
|
|
return 0;
|
|
}
|
|
case 0xAA:
|
|
this->unknown_01BC[static_cast<std::uint32_t>(argument1)].x = argument2;
|
|
this->unknown_01BC[static_cast<std::uint32_t>(argument1)].y = argument3;
|
|
this->unknown_01BC[static_cast<std::uint32_t>(argument1)].color = 0xFFFFA6D2;
|
|
return 0;
|
|
case 0x106: {
|
|
unsigned char packet[2048]{};
|
|
const int count = g_session.GetList2Size();
|
|
const std::uint32_t length = 4U + static_cast<std::uint32_t>(count) * 8U;
|
|
if (length > sizeof(packet)) {
|
|
return 0;
|
|
}
|
|
const std::uint16_t packetId = 0x9D6;
|
|
const std::uint16_t packetLength = static_cast<std::uint16_t>(length);
|
|
std::memcpy(packet, &packetId, sizeof(packetId));
|
|
std::memcpy(packet + 2, &packetLength, sizeof(packetLength));
|
|
if (count > 0) {
|
|
for (int index = 0; index < count; ++index) {
|
|
const ITEM_INFO item = g_session.GetItem1720At(index);
|
|
const int id = std::atoi(item.itemId.c_str());
|
|
std::memcpy(packet + 4 + index * 8, &id, sizeof(id));
|
|
std::memcpy(packet + 8 + index * 8, &item.quantity, sizeof(item.quantity));
|
|
}
|
|
if (this->unknown_0250 == 0) {
|
|
GetRagConnection().Send(static_cast<std::int16_t>(packetLength), packet);
|
|
}
|
|
g_windowMgr.LookupWindow(0xFF)->Show(0);
|
|
g_windowMgr.CloseWindow(0xC);
|
|
} else {
|
|
g_windowMgr.CloseWindow(0xFF);
|
|
g_modeMgr.gameMode->SendMsg(0x28, 0, 0, 0, 0);
|
|
}
|
|
g_session.ClearTradeItems();
|
|
g_windowMgr.CloseWindow(0xFE);
|
|
return 0;
|
|
}
|
|
case 0x130: {
|
|
if (timeGetTime() - g_swapEquipmentTick < 10000U) {
|
|
const char* suffix = LookupMessage(0xC9E);
|
|
const std::string message = FormatOwnedString("%d%s", 10U - (timeGetTime() - g_swapEquipmentTick) / 1000U, suffix);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message.c_str()), 0xC8FF00, 7, 0, 0);
|
|
return 0;
|
|
}
|
|
g_swapEquipmentTick = timeGetTime();
|
|
const std::uint16_t packet = 0xA9C;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x14B: {
|
|
if (g_stoveMgr->unknown_0008 != 0) {
|
|
return 0;
|
|
}
|
|
g_stoveMgr->unknown_0008 = argument1;
|
|
unsigned char packet[610]{};
|
|
const std::uint16_t packetId = 0xC0F;
|
|
std::memcpy(packet, &packetId, sizeof(packetId));
|
|
const std::string memberNumber(g_stoveMgr->m_memberNumber);
|
|
const unsigned long long member = std::stoull(memberNumber, nullptr, 10);
|
|
std::memcpy(packet + 2, &member, sizeof(member));
|
|
StringFormat(reinterpret_cast<char*>(packet + 10), 600, static_cast<std::size_t>(-1), g_stoveMgr->GetAccessToken());
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packetId), packet);
|
|
return 0;
|
|
}
|
|
case 0x14: {
|
|
if (g_windowMgr.LookupWindow(0x271B) != nullptr) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x6A3)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (this->IsMenuWindowOpen() ||
|
|
*reinterpret_cast<const std::uint32_t*>(&this->unknown_0100[8]) + 2000U > timeGetTime() ||
|
|
this->unknown_0250 != 0) {
|
|
return 0;
|
|
}
|
|
ITEM_INFO item(0);
|
|
item = argument2 != 0 ? g_session.GetItem2B50(argument1) : g_session.GetItem17F0(argument1);
|
|
if (item.unknown_0000[1] == 0 || item.quantity <= 0) {
|
|
return 0;
|
|
}
|
|
*reinterpret_cast<std::uint32_t*>(&this->unknown_0100[8]) = timeGetTime();
|
|
const GameModePacketWord packet{0xAB, static_cast<std::uint16_t>(item.unknown_0000[1])};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 1;
|
|
}
|
|
case 0x29: {
|
|
if (this->itemWindow != nullptr) {
|
|
g_windowMgr.Schedule(this->itemWindow);
|
|
this->itemWindow = nullptr;
|
|
return 0;
|
|
}
|
|
UIPlayerGage* gauge = new UIPlayerGage;
|
|
this->itemWindow = gauge;
|
|
gauge->SetFirstValues(
|
|
[] { return static_cast<std::int64_t>(g_session.unknown_5568); },
|
|
[] { return static_cast<std::int64_t>(g_session.unknown_556C); }
|
|
);
|
|
gauge->SetSecondValues(
|
|
[] { return static_cast<std::int64_t>(*reinterpret_cast<const int*>(&g_session.unknown_5570[0])); },
|
|
[] { return static_cast<std::int64_t>(*reinterpret_cast<const int*>(&g_session.unknown_5570[4])); }
|
|
);
|
|
if (g_session.IsTreeGroupThree(g_session.GetDisplayJob()) == true) {
|
|
gauge->SetFourthValues(
|
|
[] { return static_cast<std::int64_t>(g_session.GetTraitStat(0xE8)); },
|
|
[] { return static_cast<std::int64_t>(g_session.GetTraitStat(0xE9)); }
|
|
);
|
|
gauge->SetSize(60, 13);
|
|
} else {
|
|
gauge->SetFourthValues({}, {});
|
|
gauge->SetSize(60, 9);
|
|
}
|
|
CGameActor* player = this->scene->player;
|
|
gauge->Move(player->render.screenX - 30,
|
|
static_cast<int>(static_cast<float>(ScaleByScreenHeight(12)) * player->render.unknown_005C +
|
|
static_cast<float>(player->render.screenY)));
|
|
g_windowMgr.AddRenderedFront(gauge);
|
|
return 0;
|
|
}
|
|
case 0x48: {
|
|
if (g_windowMgr.LookupWindow(0xC4) != nullptr || g_windowMgr.unknown_0304 != nullptr) {
|
|
return 0;
|
|
}
|
|
this->unknown_0408 = reinterpret_cast<void*>(argument1);
|
|
if (argument2 == 0) {
|
|
return 0;
|
|
}
|
|
const CSkillInfo* skill = reinterpret_cast<const CSkillInfo*>(argument2);
|
|
this->unknown_040C = skill->id;
|
|
this->unknown_0410 = skill->unknown_001C;
|
|
if (CSkillInfo::UsesLevel(*g_session.m_hotkeyScript, skill->id)) {
|
|
this->unknown_0414 = argument3;
|
|
} else {
|
|
const CSkillInfo learned = g_session.LookupSkill(this->unknown_040C);
|
|
this->unknown_0414 = learned.available != 0 ? learned.level : 0;
|
|
}
|
|
g_pickInvert = IsSupportSkill(this->unknown_040C);
|
|
return 0;
|
|
}
|
|
case 0x56: {
|
|
bool allowed = argument3 >= 0 && argument1 >= 0;
|
|
switch (argument1) {
|
|
case 0x28:
|
|
case 0x29:
|
|
case 0x33:
|
|
case 0x87:
|
|
case 0x185:
|
|
case 0x7F1:
|
|
case 0x8C7:
|
|
case 0x8F2:
|
|
case 0x926:
|
|
case 0x9E7:
|
|
case 0xBB9:
|
|
case 0x1506:
|
|
case 0x1507:
|
|
allowed = false;
|
|
break;
|
|
}
|
|
CGameActor* actor = reinterpret_cast<CGameActor*>(argument2);
|
|
if (g_session.IsMonsterActor(actor) == 1) {
|
|
allowed = true;
|
|
}
|
|
if (actor == nullptr || !allowed) {
|
|
return 0;
|
|
}
|
|
char text[64];
|
|
char skillName[64];
|
|
if (argument1 == 0x14E || argument1 == 0x14F) {
|
|
const std::string actorName = static_cast<CGameMode*>(g_modeMgr.GetGameMode())->ActorName(argument3);
|
|
std::strcpy(text, actorName.c_str());
|
|
std::strcpy(skillName, CSkillInfo::DisplayName(*g_session.m_hotkeyScript, argument1));
|
|
if (g_serviceType == 0) {
|
|
std::strcat(skillName, " \xA2\xBD");
|
|
}
|
|
std::strcat(text, " !! ");
|
|
std::strcat(text, LookupMessage(0x2F7));
|
|
const int address = reinterpret_cast<int>(text);
|
|
actor->SendMsg(nullptr, 7, 0, address, address >> 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (argument1 == 0x150) {
|
|
std::sprintf(text, "%s", this->unknown_0294);
|
|
std::strcpy(skillName, CSkillInfo::DisplayName(*g_session.m_hotkeyScript, argument1));
|
|
if (g_serviceType == 0) {
|
|
std::strcat(skillName, " \xA2\xBD");
|
|
}
|
|
std::strcat(text, " !! ");
|
|
std::strcat(text, skillName);
|
|
const int address = reinterpret_cast<int>(text);
|
|
actor->SendMsg(nullptr, 7, 0, address, address >> 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (argument1 == 0x146 || argument1 == 0x13E || argument1 == 0x1EC ||
|
|
(g_session.IsMonsterActor(actor) == 1 && actor->render.visible == 0)) {
|
|
return 0;
|
|
}
|
|
std::strcpy(skillName, CSkillInfo::DisplayName(*g_session.m_hotkeyScript, argument1));
|
|
std::strcat(skillName, " !!");
|
|
const int address = reinterpret_cast<int>(skillName);
|
|
actor->SendMsg(nullptr, 7, 0, address, address >> 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
case 0x67: {
|
|
if (g_guildInfo.unknown_00B4 == 0) {
|
|
return 0;
|
|
}
|
|
const std::int16_t length = static_cast<std::int16_t>(4U + 12U * g_guildInfo.unknown_0104.size());
|
|
if (length > 2048) {
|
|
return 0;
|
|
}
|
|
unsigned char packet[2048];
|
|
const std::uint16_t header[2] = {0x155, static_cast<std::uint16_t>(length)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
unsigned char* output = packet + sizeof(header);
|
|
for (const auto& entry : g_guildInfo.unknown_0104) {
|
|
std::memcpy(output, &entry.second, sizeof(entry.second));
|
|
output += sizeof(entry.second);
|
|
}
|
|
g_guildInfo.unknown_0104.clear();
|
|
GetRagConnection().Send(length, packet);
|
|
return 0;
|
|
}
|
|
case 0x77: {
|
|
const GameModePacketDwordDwordDword packet{
|
|
0x170, static_cast<std::uint32_t>(argument1), g_session.m_aid, g_session.m_gid
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xC3: {
|
|
if (static_cast<CGameMode*>(g_modeMgr.GetGameMode())->IsMenuWindowOpen()) {
|
|
return 0;
|
|
}
|
|
const GameModePacketWordWord packet{
|
|
0xA04, static_cast<std::uint16_t>(argument1), static_cast<std::uint16_t>(argument2)
|
|
};
|
|
*reinterpret_cast<int*>(&g_session.unknown_52E8[0x24]) = static_cast<std::int16_t>(argument2);
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x10C: {
|
|
GameModePacketPayload24 packet{0xA08, {}};
|
|
if (argument1 != 0) {
|
|
const std::string text(reinterpret_cast<const char*>(argument1));
|
|
if (text.size() >= 24) {
|
|
g_windowMgr.Confirm(LookupMessage(0x213), 0, true, false, 0, "Message", 280, 120, 0);
|
|
return 0;
|
|
}
|
|
std::memcpy(packet.payload, text.c_str(), 24);
|
|
}
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x13: {
|
|
if (g_windowMgr.LookupWindow(0x271B) != nullptr) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x6A3)), 255, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (this->IsMenuWindowOpen()) {
|
|
return 0;
|
|
}
|
|
if (g_windowMgr.window_4F260 != nullptr || g_windowMgr.window_4F268 != nullptr) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xE68)), 255, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (*reinterpret_cast<const std::uint32_t*>(&this->unknown_0100[4]) + 2000U > timeGetTime() || this->unknown_0250 != 0) {
|
|
return 0;
|
|
}
|
|
const EquipSlots slots = g_session.GetEquipSlots(argument2);
|
|
const ITEM_INFO equipped = g_session.GetItem17F0(slots.values[2]);
|
|
if (equipped.unknown_005D != 0) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x2BB)), 255, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (equipped.unknown_0000[1] > 0 && equipped.quantity == 1) {
|
|
g_session.GetEquipSlots(equipped.unknown_0000[3]);
|
|
}
|
|
const ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, static_cast<std::uint32_t>(argument1));
|
|
if (item.unknown_0064 == 1) {
|
|
UIWindow* window = g_windowMgr.sub_A978D0(0x8A);
|
|
*reinterpret_cast<std::uint32_t*>(&this->unknown_0100[4]) = timeGetTime();
|
|
window->SendMsg(nullptr, 0x5B, argument1, argument2, 0, 0);
|
|
} else {
|
|
*reinterpret_cast<std::uint32_t*>(&this->unknown_0100[4]) = timeGetTime();
|
|
const GameModePacketWordDword packet{0x998, static_cast<std::uint16_t>(argument1), static_cast<std::uint32_t>(argument2)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
}
|
|
case 0x31: {
|
|
if (this->IsMenuWindowOpen()) {
|
|
return 0;
|
|
}
|
|
if (g_serviceType == 6 && g_windowMgr.unknown_0284 != nullptr) {
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x48)), 255, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
this->SendMsg(0x28, 0, 0, 0, 0);
|
|
g_session.ClearTradeItems();
|
|
const std::string name = this->ActorName(argument1);
|
|
if (!name.empty()) {
|
|
this->exchangeName = name;
|
|
const GameModePacketDword packet{0xE4, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
}
|
|
case 0x7A:
|
|
if (g_serviceOptions.Get(0xDD)) {
|
|
this->camera->shake.Start(1, argument1 == 1 || argument1 >= 650 ? argument1 : 0, 1.0f, 0.24f, 0.2f);
|
|
}
|
|
return 0;
|
|
case 0x87:
|
|
this->camera->shake.SetAmplitudes(*reinterpret_cast<const float*>(argument1), *reinterpret_cast<const float*>(argument2), *reinterpret_cast<const float*>(argument3));
|
|
return 0;
|
|
case 0x94: {
|
|
if (argument1 == -1 || (argument1 % 10 < 2 && g_session.m_petFriendly / 10 < 90 && !g_session.IsAdminSubMode(3))) {
|
|
return 0;
|
|
}
|
|
const GameModePacketDword packet{0x1A9, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x107: {
|
|
unsigned char packet[0x800]{};
|
|
const int count = g_session.GetList2Size();
|
|
const std::uint32_t length = static_cast<std::uint32_t>(count) * 10U + 4U;
|
|
if (length > sizeof(packet)) {
|
|
return 0;
|
|
}
|
|
const std::uint16_t header[2]{0xAAA, static_cast<std::uint16_t>(length)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
if (count > 0) {
|
|
for (int index = 0; index < count; ++index) {
|
|
const ITEM_INFO item = g_session.GetItem1720At(index);
|
|
const std::int32_t itemId = std::atoi(item.itemId.c_str());
|
|
const std::uint16_t identity = static_cast<std::uint16_t>(item.unknown_0000[1]);
|
|
unsigned char* entry = packet + 4 + index * 10;
|
|
std::memcpy(entry, &itemId, sizeof(itemId));
|
|
std::memcpy(entry + 4, &item.quantity, sizeof(item.quantity));
|
|
std::memcpy(entry + 8, &identity, sizeof(identity));
|
|
}
|
|
if (this->unknown_0250 == 0) {
|
|
GetRagConnection().Send(static_cast<std::int16_t>(length), packet);
|
|
}
|
|
if (UIWindow* window = g_windowMgr.LookupWindow(0xFF)) {
|
|
window->Show(0);
|
|
}
|
|
g_windowMgr.CloseWindow(0xC);
|
|
} else {
|
|
g_windowMgr.CloseWindow(0xFF);
|
|
if (g_charViewMode != nullptr) {
|
|
static_cast<CMode*>(g_charViewMode)->SendMsg(0x28, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
g_session.ClearTradeItems();
|
|
g_windowMgr.CloseWindow(0xFE);
|
|
return 0;
|
|
}
|
|
case 0x110: {
|
|
if ((this->scene != nullptr && this->scene->player != nullptr && this->scene->player->render.unknown_0070 == 3) ||
|
|
static_cast<std::uint32_t>(argument1) == g_session.m_aid || g_windowMgr.unknown_0418 != nullptr) {
|
|
return 0;
|
|
}
|
|
std::uint32_t& lastRequest = *reinterpret_cast<std::uint32_t*>(&this->unknown_026E[0x12]);
|
|
if (timeGetTime() <= lastRequest + 1000U) {
|
|
return 0;
|
|
}
|
|
lastRequest = timeGetTime();
|
|
const GameModePacketDword packet{0x817, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x13D: {
|
|
if (!IsAdminAccount(g_session.m_aid) && !IsMonsterJob(g_session.m_aid)) {
|
|
return 0;
|
|
}
|
|
const char* name = reinterpret_cast<const char*>(argument1);
|
|
const std::size_t length = strnlen(name, 24);
|
|
if (length - 1 > 22) {
|
|
return 0;
|
|
}
|
|
std::uint16_t packet[25]{};
|
|
packet[0] = 0xB34;
|
|
std::strncpy(reinterpret_cast<char*>(packet + 1), g_session.DecodePlayerName(), 24);
|
|
std::strncpy(reinterpret_cast<char*>(packet + 13), name, 24);
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet[0]), packet);
|
|
return 0;
|
|
}
|
|
case 0x14A: {
|
|
if (std::strlen(g_windowMgr.unknown_04DC.c_str()) == 0 || g_guildInfo.m_guildId == 0 || g_session.IsBerserkActive() == 1) {
|
|
return 0;
|
|
}
|
|
char filtered[0x16A];
|
|
strncpy_s(filtered, sizeof(filtered), g_windowMgr.unknown_04DC.c_str(), static_cast<std::size_t>(-1));
|
|
if (g_forbiddenWords.Contains(filtered)) {
|
|
std::string masked;
|
|
g_forbiddenWords.Mask(filtered, &masked);
|
|
g_windowMgr.unknown_04DC.assign(filtered, std::strlen(filtered));
|
|
return 0;
|
|
}
|
|
if (this->unknown_0438 == filtered) {
|
|
++this->unknown_0450;
|
|
} else {
|
|
this->unknown_0450 = 0;
|
|
}
|
|
if (this->ShowRestrictedNotice(this->unknown_0450)) {
|
|
return 0;
|
|
}
|
|
this->unknown_0438.assign(filtered, std::strlen(filtered));
|
|
if (g_navigationLinkParser->HasUnownedItemLink(std::string(g_windowMgr.unknown_04DC.c_str()))) {
|
|
return 0;
|
|
}
|
|
char text[0x169]{};
|
|
const char* message = g_windowMgr.unknown_04DC.c_str();
|
|
const char* prefix = g_serverLanguage->Prefix(false);
|
|
const char* name = g_session.DecodePlayerName();
|
|
const char separator[4]{' ', ':', ' ', 0};
|
|
const char* parts[4]{name, separator, prefix, message};
|
|
std::size_t length = 0;
|
|
for (const char* part : parts) {
|
|
const std::size_t available = 0x168 - length;
|
|
const std::size_t partLength = std::strlen(part);
|
|
const std::size_t copied = partLength < available ? partLength : available;
|
|
std::memcpy(text + length, part, copied);
|
|
length += copied;
|
|
}
|
|
text[length] = 0;
|
|
g_windowMgr.ClearUnknown04DC();
|
|
length = std::strlen(text);
|
|
unsigned char packet[0x16C];
|
|
const std::uint16_t header[2]{0xBDD, static_cast<std::uint16_t>(length + 4)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
std::memcpy(packet + 4, text, length);
|
|
GetRagConnection().Send(header[1], packet);
|
|
return 0;
|
|
}
|
|
case 0xB: {
|
|
if (std::strlen(g_windowMgr.unknown_04DC.c_str()) == 0 || g_session.IsBerserkActive() == 1) {
|
|
return 0;
|
|
}
|
|
char text[0x152];
|
|
std::strncpy(text, g_windowMgr.unknown_04DC.c_str(), 0x151);
|
|
text[0x151] = 0;
|
|
if (g_forbiddenWords.Contains(text)) {
|
|
std::string replacement("");
|
|
g_forbiddenWords.Mask(text, &replacement);
|
|
g_windowMgr.unknown_04DC.assign(text, std::strlen(text));
|
|
}
|
|
if (g_pendingWhisperCount == 0) {
|
|
if (this->unknown_0438 == text) {
|
|
++this->unknown_0450;
|
|
} else {
|
|
this->unknown_0450 = 0;
|
|
}
|
|
}
|
|
if (g_windowToggleFlag == 0 && this->ShowRestrictedNotice(this->unknown_0450)) {
|
|
return 0;
|
|
}
|
|
this->unknown_0438.assign(text, std::strlen(text));
|
|
char target[25] = {};
|
|
std::strcpy(target, reinterpret_cast<const char*>(argument1));
|
|
this->unknown_022C.assign(target, std::strlen(target));
|
|
if (std::strcmp(this->unknown_022C.c_str(), g_session.DecodePlayerName()) != 0) {
|
|
char message[0x152];
|
|
if (g_inlineCharset != 0) {
|
|
std::strcpy(message, g_serverLanguage->Prefix(false));
|
|
std::strncpy(message + 3, g_windowMgr.unknown_04DC.c_str(), 0x14E);
|
|
} else {
|
|
std::strncpy(message, g_windowMgr.unknown_04DC.c_str(), 0x151);
|
|
}
|
|
message[0x151] = 0;
|
|
this->unknown_0214.assign(message, std::strlen(message));
|
|
const std::size_t length = std::strlen(message);
|
|
if (length - 1 <= 0x14F) {
|
|
g_windowMgr.ClearUnknown04DC();
|
|
sub_CE8F10(target, reinterpret_cast<const unsigned char*>(message));
|
|
unsigned char packet[0x16D];
|
|
const std::uint16_t packetId = 0x96;
|
|
const std::uint16_t packetLength = static_cast<std::uint16_t>(length + 0x1C);
|
|
std::memcpy(packet, &packetId, sizeof(packetId));
|
|
std::memcpy(packet + 2, &packetLength, sizeof(packetLength));
|
|
std::memcpy(packet + 4, target, 24);
|
|
std::memcpy(packet + 0x1C, message, length);
|
|
GetRagConnection().Send(packetLength, packet);
|
|
return 0;
|
|
}
|
|
}
|
|
g_windowMgr.ClearUnknown04DC();
|
|
return 0;
|
|
}
|
|
case 0x28:
|
|
this->unknown_024C = 0;
|
|
if (argument1 == 0 && g_windowMgr.unknown_01F8 != nullptr) {
|
|
g_windowMgr.unknown_01F8->SendMsg(nullptr, 0xA6, 0, 0, 0, 0);
|
|
g_windowMgr.CloseWindow(0x11);
|
|
}
|
|
if (g_windowMgr.unknown_01F0 != nullptr) {
|
|
if (CMode* mode = g_modeMgr.GetGameMode()) {
|
|
mode->SendMsg(0x59, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
g_windowMgr.CloseWindow(0x19);
|
|
g_windowMgr.CloseWindow(0x16);
|
|
g_windowMgr.CloseWindow(0x17);
|
|
g_windowMgr.CloseWindow(0x18);
|
|
g_windowMgr.CloseWindow(0x2B);
|
|
g_windowMgr.CloseWindow(0x2C);
|
|
g_windowMgr.CloseWindow(0xC);
|
|
g_windowMgr.CloseWindow(0x32);
|
|
g_windowMgr.CloseWindow(0xB1);
|
|
g_windowMgr.CloseWindow(0xB2);
|
|
g_windowMgr.CloseWindow(0xB3);
|
|
g_windowMgr.CloseWindow(0xFE);
|
|
g_windowMgr.CloseWindow(0x100);
|
|
g_windowMgr.CloseWindow(0xFF);
|
|
g_windowMgr.CloseWindow(0x14E);
|
|
g_windowMgr.CloseWindow(0x14F);
|
|
g_windowMgr.CloseWindow(0x155);
|
|
g_windowMgr.CloseWindow(0x156);
|
|
this->SendMsg(0x64, reinterpret_cast<int>(""), -1, 0, 0);
|
|
return 0;
|
|
case 0x2B: {
|
|
const ChatRoomSetting& setting = *reinterpret_cast<const ChatRoomSetting*>(argument1);
|
|
this->unknown_03C8 = setting.title;
|
|
this->unknown_03F8 = setting.isPublic;
|
|
this->unknown_03FC = setting.unknown_0034;
|
|
this->unknown_0400 = setting.limit;
|
|
this->unknown_0404 = setting.roomId;
|
|
this->unknown_03E0 = setting.password;
|
|
unsigned char packet[0x800];
|
|
const std::uint16_t packetId = 0xD5;
|
|
const std::uint16_t packetLength = static_cast<std::uint16_t>(setting.title.size() + 15);
|
|
const std::uint16_t limit = static_cast<std::uint16_t>(setting.limit);
|
|
std::memcpy(packet, &packetId, sizeof(packetId));
|
|
std::memcpy(packet + 2, &packetLength, sizeof(packetLength));
|
|
std::memcpy(packet + 4, &limit, sizeof(limit));
|
|
packet[6] = static_cast<unsigned char>(setting.isPublic);
|
|
std::memset(packet + 7, 0, 8);
|
|
std::memcpy(packet + 7, setting.password.c_str(), setting.password.size());
|
|
std::memcpy(packet + 15, setting.title.c_str(), setting.title.size());
|
|
this->sub_CEB8E0();
|
|
GetRagConnection().Send(static_cast<std::int16_t>(packetLength), packet);
|
|
return 0;
|
|
}
|
|
case 0x40: {
|
|
const auto found = this->unknown_01B4.find(static_cast<std::uint32_t>(argument1));
|
|
if (found != this->unknown_01B4.end()) {
|
|
this->unknown_01B4.erase(found);
|
|
}
|
|
return 0;
|
|
}
|
|
case 0x6F: {
|
|
if (g_guildInfo.unknown_00B4 == 0 && g_guildInfo.unknown_00B0 == 0) {
|
|
return 0;
|
|
}
|
|
unsigned char packet[54];
|
|
const std::uint16_t packetId = 0x15B;
|
|
std::memcpy(packet, &packetId, sizeof(packetId));
|
|
std::memcpy(packet + 2, reinterpret_cast<const void*>(argument1), 12);
|
|
char* text = reinterpret_cast<char*>(packet + 14);
|
|
if (g_inlineCharset != 0) {
|
|
std::strcpy(text, g_serverLanguage->Prefix(false));
|
|
std::strncpy(text + 3, reinterpret_cast<const char*>(argument2), 0x24);
|
|
} else {
|
|
std::strncpy(text, reinterpret_cast<const char*>(argument2), 0x27);
|
|
}
|
|
text[0x27] = 0;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packetId), packet);
|
|
return 0;
|
|
}
|
|
case 0xAF: {
|
|
if (argument3 != 0) {
|
|
g_windowMgr.sub_A978D0(0x22)->SendMsg(nullptr, 6, 0xD7, 1, 0, 0);
|
|
}
|
|
const GameModePacketDwordDwordDword packet{
|
|
0x208, static_cast<std::uint32_t>(argument1), static_cast<std::uint32_t>(argument2),
|
|
static_cast<std::uint32_t>(argument3)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xBD: {
|
|
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(
|
|
*reinterpret_cast<const std::uint32_t*>(&g_session.unknown_5570[8])));
|
|
if (actor != nullptr && actor->HasUnknown030CEntry()) {
|
|
const int message[6] = {9, 0, 0, 0, 0, 0};
|
|
actor->SetUnknown0318(reinterpret_cast<const float*>(message), 0);
|
|
}
|
|
return 0;
|
|
}
|
|
case 0xF9: {
|
|
if (g_session.GetList2Size() == 0 || this->unknown_0250 != 0) {
|
|
g_session.ClearTradeItems();
|
|
return 0;
|
|
}
|
|
const int count = g_session.GetList2Size();
|
|
const std::uint32_t length = static_cast<std::uint32_t>(count) * 6U + 10U;
|
|
if (length > 0x800) {
|
|
return 0;
|
|
}
|
|
unsigned char packet[0x800];
|
|
const std::uint16_t packetId = 0x288;
|
|
const std::uint16_t packetLength = static_cast<std::uint16_t>(length);
|
|
const std::uint16_t itemCount = static_cast<std::uint16_t>(count);
|
|
std::memcpy(packet, &packetId, sizeof(packetId));
|
|
std::memcpy(packet + 2, &packetLength, sizeof(packetLength));
|
|
std::memcpy(packet + 4, &argument1, sizeof(argument1));
|
|
std::memcpy(packet + 8, &itemCount, sizeof(itemCount));
|
|
for (int index = 0; index < count; ++index) {
|
|
const ITEM_INFO item = g_session.GetItem1720At(index);
|
|
const std::uint16_t quantity = static_cast<std::uint16_t>(item.quantity);
|
|
const int itemId = std::atoi(item.itemId.c_str());
|
|
std::memcpy(packet + 10 + index * 6, &quantity, sizeof(quantity));
|
|
std::memcpy(packet + 12 + index * 6, &itemId, sizeof(itemId));
|
|
}
|
|
if (count != 0 && this->unknown_0250 == 0) {
|
|
GetRagConnection().Send(static_cast<std::int16_t>(packetLength), packet);
|
|
}
|
|
g_session.ClearTradeItems();
|
|
return 0;
|
|
}
|
|
case 0x141: {
|
|
unsigned char packet[0x800] = {};
|
|
const int count = g_expandedBarterMarketItemMgr->GetEntryCount();
|
|
const std::uint32_t length = static_cast<std::uint32_t>(count) * 12U + 4U;
|
|
if (length > sizeof(packet)) {
|
|
return 0;
|
|
}
|
|
const std::uint16_t packetId = 0xB57;
|
|
const std::uint16_t packetLength = static_cast<std::uint16_t>(length);
|
|
std::memcpy(packet, &packetId, sizeof(packetId));
|
|
std::memcpy(packet + 2, &packetLength, sizeof(packetLength));
|
|
unsigned char* output = packet + 4;
|
|
for (const BarterMarketEntry& entry : *g_expandedBarterMarketItemMgr->GetEntries()) {
|
|
const int name = std::atoi(entry.name.c_str());
|
|
std::memcpy(output, &name, sizeof(name));
|
|
std::memcpy(output + 4, &entry.id, sizeof(entry.id));
|
|
std::memcpy(output + 8, &entry.value, sizeof(entry.value));
|
|
output += 12;
|
|
}
|
|
if (count > 0 && this->unknown_0250 == 0) {
|
|
GetRagConnection().Send(static_cast<std::int16_t>(packetLength), packet);
|
|
}
|
|
return 0;
|
|
}
|
|
case 0x1B: {
|
|
if (g_windowMgr.LookupWindow(0x271B)) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x6A3)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (this->IsMenuWindowOpen() || this->unknown_02CC != 0 || *reinterpret_cast<int*>(this->unknown_02D0) != 0 || argument1 == 0 || this->unknown_0250 != 0) {
|
|
return 0;
|
|
}
|
|
ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, argument1);
|
|
const std::uint32_t state = this->scene->player->Slot13();
|
|
const int bodyState = this->scene->player->bodyState;
|
|
if (StateFlag01(state) || ((bodyState == 4 || bodyState == 1) && item.GetItemId() != 0x31B5)) {
|
|
return 0;
|
|
}
|
|
if (this->scene->player->render.unknown_0070 == 6 &&
|
|
(item.GetItemId() == 0x259 || item.GetItemId() == 0x25A || item.GetItemId() == 0x263 ||
|
|
item.GetItemId() == 0x25D || item.GetItemId() == 0x25E || item.GetItemId() == 0x5813)) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x297)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (Singleton<CSelectPackageItemMgr>::GetInstance()->OpenItem(argument1)) {
|
|
return 0;
|
|
}
|
|
if (item.GetItemId() == 0x19295) {
|
|
if (g_session.IsPlayerPerformerJob(g_session.m_job)) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x1022)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (this->scene->player->unknown_02CC != 0) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x1070)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
const unsigned baseJob = JobNames::BaseJob(g_session.GetDisplayJob());
|
|
if (g_session.GetDisplayJob() != baseJob) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x1070)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (this->scene->player->Slot50() > 0 || g_session.PartyCount() > 0) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x1023)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (g_session.unknown_8128[4] != 0) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x1024)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
for (const ActiveSkillEffect& effect : g_activeSkillEffects) {
|
|
if (effect.id == 0x26D) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x1025)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
}
|
|
if (g_windowMgr.Confirm(LookupMessage(0x1026), 2, false, false, 0, "Message", 280, 120, 0) != 0xBB) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x1028)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x1027)), 0, 0, 0, 0);
|
|
}
|
|
this->unknown_02CC = 1;
|
|
const GameModePacketWordDword packet{0x439, static_cast<std::uint16_t>(argument1), g_session.m_aid};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x3A: {
|
|
if (g_session.unknown_5460 != 0) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x56B)), 0x6E96FF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (g_session.PartyCount() != 0) {
|
|
return 0;
|
|
}
|
|
const char* name = reinterpret_cast<const char*>(argument1);
|
|
if (_mbsstr(reinterpret_cast<const unsigned char*>(name), reinterpret_cast<const unsigned char*>("#"))) {
|
|
g_windowMgr.Confirm(LookupMessage(0xB17), 0, true, false, 0, "Message", 280, 120, 0);
|
|
return 0;
|
|
}
|
|
if (std::strlen(name) >= 24) {
|
|
g_windowMgr.Confirm(LookupMessage(0x213), 0, true, false, 0, "Message", 280, 120, 0);
|
|
return 0;
|
|
}
|
|
g_windowMgr.CloseWindow(0x35);
|
|
g_windowMgr.sub_A978D0(0x35);
|
|
g_session.unknown_54AC = name;
|
|
return 0;
|
|
}
|
|
case 0x3E: {
|
|
if (g_session.unknown_5464 == 0) {
|
|
return 0;
|
|
}
|
|
GameModePacketDwordPayload24 packet;
|
|
packet.packetId = 0x103;
|
|
std::strncpy(reinterpret_cast<char*>(packet.payload), reinterpret_cast<const char*>(argument1), 24);
|
|
const MessengerMember member = g_session.PartyByName(reinterpret_cast<const char*>(argument1));
|
|
packet.argument = member.accountId;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x83: {
|
|
const int* request = reinterpret_cast<const int*>(argument1);
|
|
std::uint16_t packet[16];
|
|
packet[0] = 0x367;
|
|
packet[1] = static_cast<std::uint16_t>(request[3]);
|
|
packet[2] = static_cast<std::uint16_t>(request[0]);
|
|
packet[3] = static_cast<std::uint16_t>(request[1]);
|
|
packet[4] = static_cast<std::uint16_t>(request[2]);
|
|
if (this->unknown_0418 == 0 && !g_session.IsRequestReady(packet[2])) {
|
|
char text[1024];
|
|
const char* skillName = CSkillInfo::DisplayName(*g_session.m_hotkeyScript, packet[2]);
|
|
std::sprintf(text, LookupMessage(0x5B4), skillName);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFF, 11, 0, 0);
|
|
return 0;
|
|
}
|
|
char* text = reinterpret_cast<char*>(packet + 5);
|
|
_snprintf_s(text, 21, _TRUNCATE, "%s", reinterpret_cast<const char*>(request[4]));
|
|
if (g_forbiddenWords.Contains(text)) {
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x32)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (packet[1] == 0) {
|
|
packet[1] = static_cast<std::uint16_t>(g_session.m_skillBundle.Lookup(packet[2]).level);
|
|
}
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet[0]), packet);
|
|
return 0;
|
|
}
|
|
case 0xFE: {
|
|
if (std::strlen(g_windowMgr.unknown_04DC.c_str()) == 0 || g_session.IsBerserkActive() == 1) {
|
|
return 0;
|
|
}
|
|
char text[4096];
|
|
std::strcpy(text, g_windowMgr.unknown_04DC.c_str());
|
|
if (g_forbiddenWords.Contains(text)) {
|
|
std::string masked;
|
|
g_forbiddenWords.Mask(text, &masked);
|
|
g_windowMgr.unknown_04DC.assign(text, std::strlen(text));
|
|
}
|
|
if (this->unknown_0438 == text) {
|
|
++this->unknown_0450;
|
|
} else {
|
|
this->unknown_0450 = 0;
|
|
}
|
|
if (this->ShowRestrictedNotice(this->unknown_0450)) {
|
|
return 0;
|
|
}
|
|
this->unknown_0438.assign(text, std::strlen(text));
|
|
const char* message = g_windowMgr.unknown_04DC.c_str();
|
|
const char* prefix = g_serverLanguage->Prefix(false);
|
|
const char* name = g_session.DecodePlayerName();
|
|
char formatted[16384];
|
|
std::sprintf(formatted, "%s : %s%s", name, prefix, message);
|
|
const std::size_t length = std::strlen(formatted);
|
|
g_windowMgr.ClearUnknown04DC();
|
|
std::uint16_t packet[16384];
|
|
packet[0] = 0x2DB;
|
|
packet[1] = static_cast<std::uint16_t>(length + 5);
|
|
std::memcpy(packet + 2, formatted, length + 1);
|
|
GetRagConnection().Send(packet[1], packet);
|
|
return 0;
|
|
}
|
|
case 0x126: {
|
|
if (static_cast<CGameMode*>(g_modeMgr.GetGameMode())->IsMenuWindowOpen()) {
|
|
return 0;
|
|
}
|
|
const GameModePacketWordWord packet{0xA06, static_cast<std::uint16_t>(argument1), static_cast<std::uint16_t>(argument2)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x131: {
|
|
if (timeGetTime() - g_swapEquipmentTick < 10000U) {
|
|
const char* suffix = LookupMessage(0xC9E);
|
|
const unsigned remaining = 10U - (timeGetTime() - g_swapEquipmentTick) / 1000U;
|
|
const std::string text = FormatOwnedString("%d%s", remaining, suffix);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.c_str()), 0xC8FF00, 7, 0, 0);
|
|
return 0;
|
|
}
|
|
const auto* request = reinterpret_cast<const std::uint16_t*>(argument1);
|
|
const GameModePacketWord packet{0xACE, request[2]};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x139: {
|
|
std::uint16_t packet[7];
|
|
packet[0] = 0xB21;
|
|
packet[1] = 0;
|
|
const NormalItemSlot* slot = nullptr;
|
|
if (argument1 >= 36) {
|
|
if (static_cast<unsigned>(argument1 - 36) <= 1) {
|
|
slot = &g_session.SkillHotkey(argument1 - 36);
|
|
}
|
|
} else if (argument2 == 0) {
|
|
slot = &g_session.m_shortcutSlots[argument1];
|
|
} else if (argument2 == 1) {
|
|
slot = &g_session.m_secondaryShortcutSlots[argument1];
|
|
packet[1] = 1;
|
|
}
|
|
if (slot) {
|
|
std::memcpy(packet + 3, slot, 7);
|
|
}
|
|
packet[2] = static_cast<std::uint16_t>(argument1);
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet[0]), packet);
|
|
return 0;
|
|
}
|
|
case 0x149: {
|
|
CCashEmotionAction_Play action;
|
|
action.ExecuteNamed(reinterpret_cast<const char*>(argument1));
|
|
return 0;
|
|
}
|
|
case 0x18: {
|
|
if (g_windowMgr.unknown_0210) {
|
|
g_windowMgr.CloseWindow(0x12);
|
|
}
|
|
if (g_windowMgr.window_0288 || static_cast<std::uint32_t>(argument1) >= this->actorMenuIds.size()) {
|
|
return 0;
|
|
}
|
|
const int action = this->actorMenuIds[argument1];
|
|
switch (action) {
|
|
case 4:
|
|
if (this->unknown_024C == 1 || g_windowMgr.unknown_01F0 || g_windowMgr.unknown_01F8 || g_windowMgr.unknown_01F4) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x783)), 0xFFFFFF, 0, 0, 0);
|
|
} else if (static_cast<CGameMode*>(g_modeMgr.GetGameMode())->scene->player->Slot13() != 2) {
|
|
this->SendMsg(0x31, this->unknown_02E0, 0, 0, 0);
|
|
}
|
|
return 0;
|
|
case 5:
|
|
case 58: {
|
|
const std::string name = this->ActorName(this->unknown_02E0);
|
|
this->SendMsg(action == 5 ? 0x3B : 0x10C, reinterpret_cast<int>(name.c_str()), 0, 0, 0);
|
|
return 0;
|
|
}
|
|
case 10:
|
|
g_windowMgr.RequestAddFriend(this->ActorName(this->unknown_02E0).c_str());
|
|
return 0;
|
|
case 11:
|
|
g_windowMgr.SendMsgToNamedWindow(this->unknown_01FC.c_str());
|
|
return 0;
|
|
case 12:
|
|
case 13: {
|
|
std::string name = this->ActorName(this->unknown_02E0);
|
|
this->ExecuteTalkType(action == 12 ? 0x12 : 0x13, &name);
|
|
return 0;
|
|
}
|
|
case 20: {
|
|
const std::string name = this->ActorName(this->unknown_02E0);
|
|
const char* category = g_windowMgr.IsFriend(name.c_str()) ? LookupMessage(0x66) :
|
|
(g_session.IsGuildMemberAccount(this->unknown_02E0) ? "GuildMember" : nullptr);
|
|
std::string code;
|
|
if (auto* actor = dynamic_cast<CPc*>(this->scene->GetGameActorByAID(this->unknown_02E0))) {
|
|
code = ShortcutFilename(actor->Slot42());
|
|
}
|
|
g_windowMgr.SendNotice(0xE, reinterpret_cast<std::intptr_t>(name.c_str()), reinterpret_cast<std::intptr_t>(category),
|
|
reinterpret_cast<std::intptr_t>(code.c_str()), 0, 0);
|
|
return 0;
|
|
}
|
|
case 21:
|
|
g_windowMgr.RequestAddFriend(this->unknown_01FC.c_str());
|
|
return 0;
|
|
case 22:
|
|
this->SendMsg(0x73, this->unknown_02E0, 0, 0, 0);
|
|
return 0;
|
|
case 23:
|
|
case 24: {
|
|
if (!(action == 23 ? IsMonsterJob(g_session.m_aid) : IsAdminAccount(g_session.m_aid))) {
|
|
return 0;
|
|
}
|
|
auto* window = new UICntWnd;
|
|
window->SetSize(0xB6, 0x2E);
|
|
const int y = ScaleByScreenHeight(200);
|
|
window->Move(UIWindowMgr::CenterOnViewportX(200), y);
|
|
g_windowMgr.AddRendered(window);
|
|
window->SendMsg(nullptr, 0x50, action == 23 ? 0x97 : 0x98, 0, 0, 0);
|
|
window->SendMsg(nullptr, 0x1D, reinterpret_cast<std::intptr_t>(LookupMessage(action == 23 ? 0x185 : 0x186)), 0, 0, 0);
|
|
window->SendMsg(nullptr, 0x51, 1, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
case 25:
|
|
this->SendMsg(0x77, this->unknown_02E0, 0, 0, 0);
|
|
return 0;
|
|
case 26:
|
|
this->SendMsg(0x7D, this->unknown_02E0, 0, 0, 0);
|
|
return 0;
|
|
case 28:
|
|
this->SendMsg(0xE, this->unknown_02E0, 0, 0, 0);
|
|
return 0;
|
|
case 29:
|
|
case 38: {
|
|
if (action == 29 && g_windowMgr.unknown_0458) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xBA9)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
auto* window = new UINormalMB;
|
|
window->Create(nullptr, LookupMessage(0x259), 2, true, nullptr, 280, 120, nullptr);
|
|
g_windowMgr.AddRendered(window);
|
|
window->SetAction(0xBB, reinterpret_cast<void (*)()>(action == 29 ? ConfirmGameModeAction96 : ConfirmGameModeActionB8));
|
|
return 0;
|
|
}
|
|
case 30:
|
|
case 31:
|
|
case 32:
|
|
this->SendMsg(0x96, action - 28, 0, 0, 0);
|
|
return 0;
|
|
case 33:
|
|
this->SendMsg(0x96, 0, 0, 0, 0);
|
|
if (!g_windowMgr.CloseWindow(0x58)) {
|
|
g_windowMgr.EnsureWindow(0x58);
|
|
}
|
|
return 0;
|
|
case 34: {
|
|
char text[512];
|
|
std::sprintf(text, "%s : %d (GID)", g_session.m_serverName.c_str(), this->unknown_02E0);
|
|
CLanguageBase* language = g_serverLanguage;
|
|
language->ResetInput();
|
|
language->Insert(text);
|
|
return 0;
|
|
}
|
|
case 35:
|
|
g_windowMgr.EnsureWindow(0x67)->SendMsg(nullptr, 0x22, this->unknown_02E0, 0, 0, 0);
|
|
return 0;
|
|
case 36:
|
|
this->SendMsg(0xB3, this->unknown_02E0, 0, 0, 0);
|
|
return 0;
|
|
case 37:
|
|
this->SendMsg(0xB8, 0, 0, 0, 0);
|
|
if (!g_windowMgr.CloseWindow(0x71)) {
|
|
g_windowMgr.EnsureWindow(0x71);
|
|
}
|
|
return 0;
|
|
case 39: {
|
|
auto* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(*reinterpret_cast<std::uint32_t*>(&g_session.unknown_5570[8])));
|
|
if (actor && actor->HasUnknown030CEntry()) {
|
|
float value[6] = {};
|
|
const int type = 9;
|
|
std::memcpy(value, &type, sizeof(type));
|
|
actor->SetUnknown0318(value, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
case 40:
|
|
this->SendMsg(0xBA, 1, 0, 0, 0);
|
|
if (!g_windowMgr.CloseWindow(0x7D)) {
|
|
g_windowMgr.EnsureWindow(0x7D);
|
|
}
|
|
return 0;
|
|
case 41: {
|
|
auto* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(*reinterpret_cast<std::uint32_t*>(&g_session.unknown_5620[8])));
|
|
if (actor && actor->unknown_0310 && *reinterpret_cast<int*>(actor->unknown_0310 + 4)) {
|
|
float value[6] = {};
|
|
const int type = 9;
|
|
std::memcpy(value, &type, sizeof(type));
|
|
actor->SetUnknown0318(value, 1);
|
|
}
|
|
return 0;
|
|
}
|
|
case 42:
|
|
case 44:
|
|
case 65: {
|
|
if (action == 44 && !IsAdminAccount(g_session.m_aid)) {
|
|
return 0;
|
|
}
|
|
const GameModePacketDword packet{static_cast<std::uint16_t>(action == 42 ? 0x2D6 : action == 44 ? 0x7F5 : 0xAF9),
|
|
static_cast<std::uint32_t>(this->unknown_02E0)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 57: {
|
|
auto* actor = dynamic_cast<CPc*>(this->scene->GetGameActorByAID(this->unknown_02E0));
|
|
if (!actor) {
|
|
return 0;
|
|
}
|
|
const std::string code = ShortcutFilename(actor->Slot42());
|
|
HGLOBAL memory = GlobalAlloc(0x42, code.size() + 1);
|
|
void* destination = GlobalLock(memory);
|
|
std::memcpy(destination, code.data(), code.size());
|
|
GlobalUnWire(memory);
|
|
if (OpenClipboard(hWnd)) {
|
|
EmptyClipboard();
|
|
SetClipboardData(1, memory);
|
|
CloseClipboard();
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>("C-Code copied to clipboard"), 0x64FFFF, 0, 0, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
case 63:
|
|
g_windowMgr.EnsureWindow(0x2715);
|
|
return 0;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
case 0x1F: {
|
|
auto& tick = *reinterpret_cast<std::uint32_t*>(&this->unknown_026E[0xA]);
|
|
if (this->unknown_026E[0x16] || timeGetTime() <= tick + 2500U) {
|
|
return 0;
|
|
}
|
|
const bool doram = g_session.IsDoramJob(g_session.GetDisplayJob());
|
|
const CSkillInfo* skill = g_session.m_skillBundle.Find(doram ? 0x139A : 1);
|
|
if (!skill || skill->level <= (doram ? 0 : 1)) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(g_simpleStringMgr->GetString("EMSG_EMOTION_USE_FAIL_SKILL_LEVEL")), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (g_cashEmotionMgr->BasePackId() != argument2 && !g_cashEmotionMgr->IsOwnedPack(argument2)) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(g_simpleStringMgr->GetString("EMSG_EMOTION_EXPANTION_USE_FAIL_UNPURCHASED")), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (!g_cashEmotionMgr->GetEmotionData(argument2, argument1)) {
|
|
return 0;
|
|
}
|
|
const GameModePacketWordWord packet{0xBE9, static_cast<std::uint16_t>(argument2), static_cast<std::uint16_t>(argument1)};
|
|
tick = timeGetTime();
|
|
this->unknown_026E[0x16] = 1;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x52: {
|
|
const int count = g_session.GetList11Size();
|
|
unsigned char packet[0x47BC];
|
|
*reinterpret_cast<std::uint16_t*>(packet) = 0x1B2;
|
|
*reinterpret_cast<std::uint16_t*>(packet + 2) = static_cast<std::uint16_t>(85 + count * 8);
|
|
char* title = reinterpret_cast<char*>(packet + 4);
|
|
if (argument2 == 1) {
|
|
std::strncpy(title, reinterpret_cast<const char*>(argument1), 79);
|
|
title[79] = 0;
|
|
packet[84] = 1;
|
|
} else {
|
|
title[0] = 0;
|
|
packet[84] = 0;
|
|
}
|
|
if (!g_replayAnimationScaling) {
|
|
g_session.unknown_550C = title;
|
|
}
|
|
unsigned char* entry = packet + 85;
|
|
for (int index = 0; index < count; ++index) {
|
|
const ITEM_INFO item = g_session.GetItem1768At(index);
|
|
if (item.unknown_0000[1]) {
|
|
*reinterpret_cast<std::uint16_t*>(entry) = static_cast<std::uint16_t>(item.unknown_0000[1]);
|
|
*reinterpret_cast<std::uint16_t*>(entry + 2) = static_cast<std::uint16_t>(item.quantity);
|
|
*reinterpret_cast<std::uint32_t*>(entry + 4) = item.unknown_0014[1];
|
|
entry += 8;
|
|
}
|
|
}
|
|
if (count == 0) {
|
|
packet[84] = 0;
|
|
}
|
|
GetRagConnection().Send(*reinterpret_cast<std::int16_t*>(packet + 2), packet);
|
|
g_session.ClearItems1768();
|
|
return 0;
|
|
}
|
|
case 0x6E: {
|
|
unsigned char packet[54];
|
|
*reinterpret_cast<std::uint16_t*>(packet) = 0x159;
|
|
*reinterpret_cast<std::uint32_t*>(packet + 2) = g_guildInfo.m_guildId;
|
|
*reinterpret_cast<std::uint32_t*>(packet + 6) = g_session.m_aid;
|
|
*reinterpret_cast<std::uint32_t*>(packet + 10) = g_session.m_gid;
|
|
char* text = reinterpret_cast<char*>(packet + 14);
|
|
if (g_inlineCharset) {
|
|
std::strcpy(text, g_serverLanguage->Prefix(false));
|
|
std::strncpy(text + 3, reinterpret_cast<const char*>(argument1), 36);
|
|
} else {
|
|
std::strncpy(text, reinterpret_cast<const char*>(argument1), 39);
|
|
}
|
|
text[39] = 0;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(0x159), packet);
|
|
return 0;
|
|
}
|
|
case 0x70: {
|
|
const char* name = reinterpret_cast<const char*>(argument1);
|
|
const std::size_t length = std::strlen(name);
|
|
char text[256];
|
|
if ((static_cast<unsigned char>(name[0]) == 0xA1 && static_cast<unsigned char>(name[1]) == 0xA1) ||
|
|
(static_cast<unsigned char>(name[length - 2]) == 0xA1 && static_cast<unsigned char>(name[length - 1]) == 0xA1) ||
|
|
std::strchr(name, ' ')) {
|
|
std::sprintf(text, LookupMessage(0x97B));
|
|
if (std::strstr(text, "NO MSG")) {
|
|
std::sprintf(text, "Can NOT use space in Guild Name !!");
|
|
}
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0x6E96FF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (g_forbiddenWords.Contains(name)) {
|
|
StringFormat(text, sizeof(text), static_cast<std::size_t>(-1), LookupMessage(0xD07));
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0x6E96FF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (g_serviceType == 12 && std::strchr(name, 0x2323)) {
|
|
g_windowMgr.Confirm(LookupMessage(0x464), 0, true, false, 0, "Message", 280, 120, 0);
|
|
return 0;
|
|
}
|
|
if (length >= 24) {
|
|
g_windowMgr.Confirm(LookupMessage(0x213), 0, true, false, 0, "Message", 280, 120, 0);
|
|
return 0;
|
|
}
|
|
if (static_cast<CGameMode*>(g_modeMgr.GetGameMode())->scene->player->unknown_0305 == 1) {
|
|
std::sprintf(text, LookupMessage(0xA2D));
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0x6E96FF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
GameModePacketDwordPayload24 packet;
|
|
packet.packetId = 0x165;
|
|
packet.argument = g_session.m_gid;
|
|
std::strncpy(reinterpret_cast<char*>(packet.payload), name, 23);
|
|
packet.payload[23] = 0;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xAB: {
|
|
const auto entry = this->unknown_01BC.find(static_cast<std::uint32_t>(argument1));
|
|
if (entry != this->unknown_01BC.end()) {
|
|
this->unknown_01BC.erase(entry);
|
|
}
|
|
return 0;
|
|
}
|
|
case 0x12F: {
|
|
int message = 0;
|
|
if (g_windowMgr.LookupWindow(0x271B)) {
|
|
message = 0xBB9;
|
|
} else if (this->unknown_0250) {
|
|
message = 0xBB7;
|
|
} else if (g_windowMgr.unknown_0304 || g_windowMgr.unknown_0308 || g_windowMgr.unknown_02FC) {
|
|
message = 0xBBA;
|
|
} else if (static_cast<CGameMode*>(g_modeMgr.GetGameMode())->scene->player->unknown_0264[3]) {
|
|
message = 0xBB8;
|
|
} else if (g_windowMgr.unknown_01F0 || g_windowMgr.unknown_01F8) {
|
|
message = 0xBBB;
|
|
}
|
|
if (message) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(message)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
ITEM_INFO item(0);
|
|
item = argument2 ? g_session.GetItem6B68(argument1) : g_session.GetItem61B8(argument1);
|
|
if (item.unknown_0000[1] && item.quantity > 0) {
|
|
const GameModePacketWord packet{0xA99, static_cast<std::uint16_t>(item.unknown_0000[1])};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
}
|
|
return 0;
|
|
}
|
|
case 0x140: {
|
|
auto& tick = *reinterpret_cast<std::uint32_t*>(&g_session.unknown_807C[0x18]);
|
|
if (timeGetTime() - tick < 5000U) {
|
|
const char* message = LookupMessage(0xC9E);
|
|
const std::string text = FormatOwnedString("%d%s", 5U - (timeGetTime() - tick) / 1000U, message);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text.c_str()), 0xC8FF00, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
tick = timeGetTime();
|
|
const std::uint16_t packet = 0xB4C;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
return 0;
|
|
}
|
|
case 0x145: {
|
|
int message = 0;
|
|
if (g_windowMgr.LookupWindow(0x271B)) {
|
|
message = 0x6A3;
|
|
} else if (this->IsMenuWindowOpen() || this->unknown_02CC || *reinterpret_cast<int*>(this->unknown_02D0)) {
|
|
message = 0xF84;
|
|
} else if (this->unknown_0250) {
|
|
message = 0xBB7;
|
|
} else if (StateFlag01(this->scene->player->Slot13())) {
|
|
message = 0xF83;
|
|
}
|
|
if (message) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(message)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
const ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, argument1);
|
|
if (this->scene->player->bodyState == 4 || this->scene->player->bodyState == 1) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xF82)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (this->scene->player->render.unknown_0070 == 6) {
|
|
const int itemId = item.GetItemId();
|
|
if (itemId == 0x259 || itemId == 0x25A || itemId == 0x263 || itemId == 0x25D || itemId == 0x25E || itemId == 0x5813) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x297)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
}
|
|
this->unknown_02CC = 1;
|
|
unsigned char packet[16];
|
|
*reinterpret_cast<std::uint16_t*>(packet) = 0xBAF;
|
|
*reinterpret_cast<std::uint16_t*>(packet + 2) = static_cast<std::uint16_t>(argument1);
|
|
*reinterpret_cast<std::uint32_t*>(packet + 4) = g_session.m_aid;
|
|
*reinterpret_cast<std::uint32_t*>(packet + 8) = static_cast<std::uint32_t>(argument2);
|
|
*reinterpret_cast<std::uint32_t*>(packet + 12) = static_cast<std::uint32_t>(argument3);
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(0xBAF), packet);
|
|
g_windowMgr.CloseWindow(0x2731);
|
|
return 0;
|
|
}
|
|
case 0x33: {
|
|
if (g_session.HasExchangeItem(static_cast<std::uint32_t>(argument1))) {
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x33)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (g_session.IsExchangeItemListFull() && argument1 != 0) {
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x129)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (*reinterpret_cast<int*>(this->unknown_0100) != 0) {
|
|
return 0;
|
|
}
|
|
*reinterpret_cast<int*>(this->unknown_0100) = 1;
|
|
const GameModePacketWordDword packet{0xE8, static_cast<std::uint16_t>(argument1), static_cast<std::uint32_t>(argument2)};
|
|
*reinterpret_cast<int*>(&this->unknown_0100[0x10]) = argument2;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
if (Replay::Instance().state == 2) {
|
|
std::uint16_t record[5] = {0x08AE, 0x0387, 10};
|
|
std::memcpy(record + 3, &this->unknown_0100[0x10], sizeof(int));
|
|
Replay::Instance().Record(10, record, 0x2A, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
case 0x53: {
|
|
g_session.CopyItems1760To1770();
|
|
const int count = g_session.GetList10Size();
|
|
const std::uint32_t length = 12U + static_cast<std::uint32_t>(count) * 4U;
|
|
if (length > 0x800U) {
|
|
return 0;
|
|
}
|
|
unsigned char packet[0x800];
|
|
*reinterpret_cast<std::uint16_t*>(packet) = 0x801;
|
|
*reinterpret_cast<std::uint16_t*>(packet + 2) = static_cast<std::uint16_t>(length);
|
|
std::memcpy(packet + 4, &argument1, sizeof(argument1));
|
|
std::memcpy(packet + 8, &argument2, sizeof(argument2));
|
|
for (int index = 0; index < count; ++index) {
|
|
ITEM_INFO item = g_session.GetItem1760At(index);
|
|
if (item.unknown_0000[1] != 0) {
|
|
*reinterpret_cast<std::uint16_t*>(packet + 12 + index * 4) = static_cast<std::uint16_t>(item.quantity);
|
|
*reinterpret_cast<std::uint16_t*>(packet + 14 + index * 4) = static_cast<std::uint16_t>(item.unknown_0000[1]);
|
|
}
|
|
}
|
|
if (count != 0) {
|
|
GetRagConnection().Send(static_cast<std::int16_t>(length), packet);
|
|
}
|
|
return 0;
|
|
}
|
|
case 0x54: {
|
|
if (this->scene != nullptr && this->scene->player != nullptr && this->scene->player->render.unknown_0070 == 3) {
|
|
return 0;
|
|
}
|
|
if (static_cast<std::uint32_t>(argument1) == g_session.m_aid || g_windowMgr.unknown_0300 != nullptr) {
|
|
return 0;
|
|
}
|
|
auto& previousTick = *reinterpret_cast<std::uint32_t*>(&this->unknown_026E[0x12]);
|
|
if (timeGetTime() <= previousTick + 1000U) {
|
|
return 0;
|
|
}
|
|
previousTick = timeGetTime();
|
|
const GameModePacketDword packet{0x130, static_cast<std::uint32_t>(argument1)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0xC0: {
|
|
const auto& request = *reinterpret_cast<const RodexSendMailRequest*>(argument1);
|
|
if (g_forbiddenWords.Contains(request.title.c_str()) || g_forbiddenWords.Contains(request.body.c_str())) {
|
|
g_windowMgr.Confirm(LookupMessage(0xBD4), 0, true, false, 0, "Message", 0x118, 0x78, 0);
|
|
return 0;
|
|
}
|
|
g_session.RestoreItems5C68();
|
|
g_session.ClearItemQuantities();
|
|
unsigned char header[0x44];
|
|
*reinterpret_cast<std::uint16_t*>(header) = 0xA6E;
|
|
std::memcpy(header + 0x40, &request.recipientId, sizeof(request.recipientId));
|
|
const std::int64_t zeny = request.zeny;
|
|
std::memcpy(header + 0x34, &zeny, sizeof(zeny));
|
|
strcpy_s(reinterpret_cast<char*>(header + 4), 24, request.recipient.c_str());
|
|
strcpy_s(reinterpret_cast<char*>(header + 0x1C), 24, g_session.DecodePlayerName());
|
|
const std::int16_t titleLength = static_cast<std::int16_t>(request.title.size() + 1);
|
|
const std::int16_t bodyLength = static_cast<std::int16_t>(request.body.size() + 1);
|
|
std::memcpy(header + 0x3C, &titleLength, sizeof(titleLength));
|
|
std::memcpy(header + 0x3E, &bodyLength, sizeof(bodyLength));
|
|
std::vector<unsigned char> packet;
|
|
packet.insert(packet.end(), header, header + sizeof(header));
|
|
packet.insert(packet.end(), request.title.c_str(), request.title.c_str() + titleLength);
|
|
packet.insert(packet.end(), request.body.c_str(), request.body.c_str() + bodyLength);
|
|
const std::int16_t length = static_cast<std::int16_t>(packet.size());
|
|
std::memcpy(packet.data() + 2, &length, sizeof(length));
|
|
GetRagConnection().Send(length, packet.data());
|
|
g_windowMgr.CloseWindow(0x108);
|
|
return 0;
|
|
}
|
|
case 0x113: {
|
|
if (Replay::Instance().state == 2) {
|
|
Replay::Instance().SetState(1);
|
|
Replay::Instance().UpdateDuration();
|
|
Replay::Instance().Duration();
|
|
Replay::Instance().CloseFile();
|
|
}
|
|
char notice[0x104] = {};
|
|
char directory[0x104] = {};
|
|
GetCurrentDirectoryA(0x104, directory);
|
|
std::string text(directory);
|
|
text += ReplayFileList::Instance().path;
|
|
text += LookupMessage(0x7C7);
|
|
std::sprintf(notice, "%s", text.c_str());
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(notice), 0x62B0FF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
case 0x121: {
|
|
if (std::strlen(g_windowMgr.unknown_04DC.c_str()) == 0 || !g_clanInfo->m_hasClan || g_session.IsBerserkActive() == 1) {
|
|
return 0;
|
|
}
|
|
char text[0x16A];
|
|
strcpy_s(text, sizeof(text), g_windowMgr.unknown_04DC.c_str());
|
|
if (g_forbiddenWords.Contains(text)) {
|
|
std::string replacement("");
|
|
g_forbiddenWords.Mask(text, &replacement);
|
|
g_windowMgr.unknown_04DC.assign(text, std::strlen(text));
|
|
}
|
|
if (this->unknown_0438 == text) {
|
|
++this->unknown_0450;
|
|
if (this->ShowRestrictedNotice(this->unknown_0450)) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
this->unknown_0450 = 0;
|
|
}
|
|
this->unknown_0438.assign(text, std::strlen(text));
|
|
const char* message = g_windowMgr.unknown_04DC.c_str();
|
|
const char* prefix = g_serverLanguage->Prefix(false);
|
|
const char* playerName = g_session.DecodePlayerName();
|
|
char formatted[0x400];
|
|
std::sprintf(formatted, "%s : %s%s", playerName, prefix, message);
|
|
const std::size_t textLength = std::strlen(formatted);
|
|
g_windowMgr.ClearUnknown04DC();
|
|
if (textLength > 0xDC) {
|
|
return 0;
|
|
}
|
|
unsigned char packet[0x400];
|
|
std::memset(packet + 4, 0, 0x3FC);
|
|
const std::uint16_t length = static_cast<std::uint16_t>(textLength + 5);
|
|
*reinterpret_cast<std::uint16_t*>(packet) = 0x98D;
|
|
*reinterpret_cast<std::uint16_t*>(packet + 2) = length;
|
|
std::memcpy(packet + 4, formatted, textLength + 1);
|
|
GetRagConnection().Send(static_cast<std::int16_t>(length), packet);
|
|
return 0;
|
|
}
|
|
case 0x12E: {
|
|
if (this->IsMenuWindowOpen()) {
|
|
return 0;
|
|
}
|
|
if (g_windowMgr.LookupWindow(0x271B) != nullptr) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xBB9)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (this->unknown_0250 != 0) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xBB7)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (g_windowMgr.unknown_0304 != nullptr || g_windowMgr.unknown_0308 != nullptr || g_windowMgr.unknown_02FC != nullptr) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xBBA)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (static_cast<CGameMode*>(g_modeMgr.GetGameMode())->scene->player->unknown_0264[3] != 0) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xBB8)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (g_windowMgr.unknown_01F0 != nullptr || g_windowMgr.unknown_01F8 != nullptr) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xBBB)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
ITEM_INFO item = g_session.FindItemByIdentity(static_cast<std::uint32_t>(argument1), argument2);
|
|
if (!item.identified || item.unknown_005D != 0) {
|
|
return 0;
|
|
}
|
|
const bool special = item.unknown_0000[1] > 0 &&
|
|
(item.unknown_0000[0] == 10 || item.unknown_0000[0] == 16 || item.unknown_0000[0] == 17 || item.unknown_0000[0] == 19);
|
|
if (special) {
|
|
if (static_cast<std::uint32_t>(argument1) == g_session.unknown_7EC8) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
const EquipSlots slots = g_session.GetEquipSlots(argument2);
|
|
for (int index = 2; index >= 0; --index) {
|
|
ITEM_INFO equipped;
|
|
if (g_session.IsCostumeLocation(argument2)) {
|
|
equipped = g_session.GetItem6B68(slots.values[index]);
|
|
} else {
|
|
equipped = g_session.GetItem61B8(slots.values[index]);
|
|
}
|
|
if (static_cast<std::uint32_t>(argument1) == equipped.unknown_0000[1]) {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
*reinterpret_cast<std::uint32_t*>(&this->unknown_0100[4]) = timeGetTime();
|
|
const GameModePacketWordDword packet{0xA97, static_cast<std::uint16_t>(argument1), static_cast<std::uint32_t>(argument2)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x14D: {
|
|
g_session.FlagItem1738(static_cast<std::uint32_t>(argument1));
|
|
const GameModePacketDwordWordDword packet{
|
|
0xC22, g_unknown_01738268 != 0 ? 1U : 0U, static_cast<std::uint16_t>(argument1), static_cast<std::uint32_t>(argument2)
|
|
};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x22: {
|
|
const int count = g_session.GetList2Size();
|
|
const std::uint32_t length = 4U + static_cast<std::uint32_t>(count) * 6U;
|
|
if (length > 0x800) {
|
|
return 0;
|
|
}
|
|
unsigned char packet[0x800];
|
|
const std::uint16_t header[2] = {0xC8, static_cast<std::uint16_t>(length)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
for (int index = 0; index < count; ++index) {
|
|
const ITEM_INFO item = g_session.GetItem1720At(index);
|
|
const std::uint16_t quantity = static_cast<std::uint16_t>(item.quantity);
|
|
const int itemId = std::atoi(item.itemId.c_str());
|
|
std::memcpy(packet + 4 + index * 6, &quantity, sizeof(quantity));
|
|
std::memcpy(packet + 6 + index * 6, &itemId, sizeof(itemId));
|
|
}
|
|
if (count != 0 && this->unknown_0250 == 0) {
|
|
GetRagConnection().Send(static_cast<std::int16_t>(length), packet);
|
|
}
|
|
g_session.ClearTradeItems();
|
|
g_windowMgr.CloseWindow(0x19);
|
|
g_windowMgr.CloseWindow(0x16);
|
|
g_windowMgr.CloseWindow(0x17);
|
|
return 0;
|
|
}
|
|
case 0x2C: {
|
|
if (g_windowMgr.window_027C == nullptr) {
|
|
return 0;
|
|
}
|
|
const ChatRoomSetting& settings = *reinterpret_cast<const ChatRoomSetting*>(argument1);
|
|
this->unknown_03C8 = settings.title;
|
|
this->unknown_03F8 = settings.isPublic;
|
|
this->unknown_03FC = settings.unknown_0034;
|
|
this->unknown_0400 = settings.limit;
|
|
this->unknown_0404 = settings.roomId;
|
|
this->unknown_03E0 = settings.password;
|
|
unsigned char packet[0x800];
|
|
const std::uint16_t header[3] = {
|
|
0xDE, static_cast<std::uint16_t>(settings.title.size() + 15), static_cast<std::uint16_t>(settings.limit)
|
|
};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
packet[6] = static_cast<unsigned char>(settings.isPublic);
|
|
std::memset(packet + 7, 0, 8);
|
|
std::memcpy(packet + 7, settings.password.c_str(), settings.password.size());
|
|
std::memcpy(packet + 15, settings.title.c_str(), settings.title.size());
|
|
this->sub_CEB8E0();
|
|
GetRagConnection().Send(static_cast<std::int16_t>(header[1]), packet);
|
|
return 0;
|
|
}
|
|
case 0x42: {
|
|
if (g_windowMgr.unknown_04DC.empty() || g_session.IsBerserkActive() == 1) {
|
|
return 0;
|
|
}
|
|
char text[0x800];
|
|
std::strcpy(text, g_windowMgr.unknown_04DC.c_str());
|
|
if (g_forbiddenWords.Contains(text)) {
|
|
std::string masked;
|
|
g_forbiddenWords.Mask(text, &masked);
|
|
g_windowMgr.unknown_04DC.assign(text, std::strlen(text));
|
|
}
|
|
if (this->unknown_0438 == text) {
|
|
++this->unknown_0450;
|
|
} else {
|
|
this->unknown_0450 = 0;
|
|
}
|
|
if (this->ShowRestrictedNotice(this->unknown_0450)) {
|
|
return 0;
|
|
}
|
|
this->unknown_0438.assign(text, std::strlen(text));
|
|
if (g_navigationLinkParser->HasUnownedItemLink(g_windowMgr.unknown_04DC)) {
|
|
return 0;
|
|
}
|
|
char message[0x169] = {};
|
|
const char* input = g_windowMgr.unknown_04DC.c_str();
|
|
const char* prefix = g_serverLanguage->Prefix(false);
|
|
const char* name = g_session.DecodePlayerName();
|
|
StringFormat(message, sizeof(message), static_cast<std::size_t>(-1), "%s : %s%s", name, prefix, input);
|
|
g_windowMgr.ClearUnknown04DC();
|
|
const std::size_t size = std::strlen(message);
|
|
unsigned char packet[0x16D];
|
|
const std::uint16_t header[2] = {0x108, static_cast<std::uint16_t>(size + 4)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
std::memcpy(packet + 4, message, size);
|
|
GetRagConnection().Send(header[1], packet);
|
|
return 0;
|
|
}
|
|
case 0x5E: {
|
|
if (CSkillInfo::UsesLevel(*g_session.m_hotkeyScript, this->unknown_040C)) {
|
|
const CSkillInfo skill = g_session.m_skillBundle.Lookup(this->unknown_040C);
|
|
if (skill.available != 0) {
|
|
this->unknown_0414 -= argument1;
|
|
if (this->unknown_0414 > skill.level) {
|
|
this->unknown_0414 = skill.level;
|
|
}
|
|
if (this->unknown_0414 <= 0) {
|
|
this->unknown_0414 = 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
case 0xA5: {
|
|
CFile file;
|
|
const char* path = nullptr;
|
|
if (argument1 == 0) {
|
|
path = g_serviceType == 10 ? "english\\DC_scream.txt" : "DC_scream.txt";
|
|
} else if (argument1 == 1) {
|
|
path = g_serviceType == 10 ? "english\\BA_frostjoke.txt" : "BA_frostjoke.txt";
|
|
}
|
|
if (file.Open(path, 0, true, false)) {
|
|
const int size = static_cast<int>(file.GetSize());
|
|
char* data = static_cast<char*>(::operator new(static_cast<std::size_t>(size) + 1));
|
|
file.Read(data, size);
|
|
data[size] = 0;
|
|
file.Close();
|
|
int selected;
|
|
if (argument1 == 0) {
|
|
selected = std::rand() % 114 + 1;
|
|
} else if (argument1 == 1) {
|
|
selected = std::rand() % 117 + 1;
|
|
}
|
|
signed char line = 0;
|
|
unsigned int length = 0;
|
|
char text[0x100];
|
|
for (int index = 0; index < size; ++index) {
|
|
const char value = data[index];
|
|
if (value == '\r') {
|
|
line = static_cast<signed char>(static_cast<unsigned char>(line) + 1);
|
|
}
|
|
if (line == selected) {
|
|
if (value != '\r' && value != '\n' && value != '\t') {
|
|
text[length++] = value;
|
|
if (length >= sizeof(text)) {
|
|
__report_rangecheckfailure();
|
|
}
|
|
text[length] = 0;
|
|
}
|
|
} else if (line == selected + 1) {
|
|
break;
|
|
}
|
|
}
|
|
std::free(data);
|
|
char message[0x200];
|
|
const char* decoded = DecodeMessageRot(text);
|
|
std::sprintf(message, "%s : %s", g_session.DecodePlayerName(), decoded);
|
|
message[0x169] = 0;
|
|
const std::size_t messageLength = std::strlen(message);
|
|
g_windowMgr.ClearUnknown04DC();
|
|
unsigned char packet[0x800];
|
|
const std::uint16_t header[2] = {0xF3, static_cast<std::uint16_t>(messageLength + 5)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
std::memcpy(packet + 4, message, messageLength + 1);
|
|
GetRagConnection().Send(header[1], packet);
|
|
}
|
|
return 0;
|
|
}
|
|
case 0x10A: {
|
|
const int count = g_session.GetList4Size();
|
|
const std::uint32_t length = 12U + static_cast<std::uint32_t>(count) * 4U;
|
|
if (length > 0x800) {
|
|
return 0;
|
|
}
|
|
unsigned char packet[0x800];
|
|
const std::uint16_t header[2] = {0x7E4, static_cast<std::uint16_t>(length)};
|
|
const int flag = 1;
|
|
std::memcpy(packet, header, sizeof(header));
|
|
std::memcpy(packet + 4, &argument1, sizeof(argument1));
|
|
std::memcpy(packet + 8, &flag, sizeof(flag));
|
|
for (int index = 0; index < count; ++index) {
|
|
const ITEM_INFO item = g_session.GetItem1730At(index);
|
|
const std::uint16_t entry[2] = {
|
|
static_cast<std::uint16_t>(item.unknown_0000[1]), static_cast<std::uint16_t>(item.quantity)
|
|
};
|
|
std::memcpy(packet + 12 + index * 4, entry, sizeof(entry));
|
|
}
|
|
if (count != 0) {
|
|
GetRagConnection().Send(static_cast<std::int16_t>(length), packet);
|
|
}
|
|
g_session.ClearTradeItems();
|
|
return 0;
|
|
}
|
|
case 0x11D:
|
|
if (g_session.unknown_5460 != 0) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x56B)), 0x6E96FF, 0, 0, 0);
|
|
} else if (g_session.PartyCount() == 0) {
|
|
g_windowMgr.CloseWindow(0xCF);
|
|
g_session.unknown_54AC = reinterpret_cast<const char*>(argument1);
|
|
}
|
|
return 0;
|
|
case 0x144: {
|
|
if (this->itemWindow == nullptr) {
|
|
return 0;
|
|
}
|
|
UIPlayerGage* gauge = static_cast<UIPlayerGage*>(this->itemWindow);
|
|
gauge->SetFirstValues(
|
|
[] { return static_cast<std::int64_t>(g_session.unknown_5568); },
|
|
[] { return static_cast<std::int64_t>(g_session.unknown_556C); }
|
|
);
|
|
gauge->SetSecondValues(
|
|
[] { return static_cast<std::int64_t>(*reinterpret_cast<const int*>(&g_session.unknown_5570[0])); },
|
|
[] { return static_cast<std::int64_t>(*reinterpret_cast<const int*>(&g_session.unknown_5570[4])); }
|
|
);
|
|
if (g_session.IsTreeGroupThree(g_session.GetDisplayJob())) {
|
|
gauge->SetFourthValues(
|
|
[] { return static_cast<std::int64_t>(g_session.GetTraitStat(0xE8)); },
|
|
[] { return static_cast<std::int64_t>(g_session.GetTraitStat(0xE9)); }
|
|
);
|
|
gauge->SetSize(60, 13);
|
|
} else {
|
|
gauge->SetFourthValues({}, {});
|
|
gauge->SetSize(60, 9);
|
|
}
|
|
CPlayer* player = this->scene->player;
|
|
const int offset = ScaleByScreenHeight(12);
|
|
gauge->Move(player->render.screenX - 30,
|
|
static_cast<int>(static_cast<float>(player->render.screenY) + static_cast<float>(offset) * player->render.unknown_005C));
|
|
return 0;
|
|
}
|
|
case 0x1:
|
|
this->unknown_0244 = 1;
|
|
this->unknown_0248 = timeGetTime();
|
|
GetRagConnection().Close();
|
|
if (g_windowMgr.Confirm(LookupMessage(2), 0, true, true, 0, "Message", 280, 120, 0) != 0x10D) {
|
|
this->SendMsg(0x8D, 0, 0, 0, 0);
|
|
}
|
|
return 0;
|
|
case 0x7: {
|
|
std::string text;
|
|
if (argument1 == 0 || argument1 == 1) {
|
|
text = std::string(g_session.DecodePlayerName()) + ": " + g_windowMgr.unknown_04DC.c_str();
|
|
} else if (argument1 == 4 || argument1 == 5) {
|
|
text = std::string("blue") + g_windowMgr.unknown_04DC.c_str();
|
|
} else {
|
|
text = g_windowMgr.unknown_04DC.c_str();
|
|
}
|
|
char message[0x16A];
|
|
std::strcpy(message, text.c_str());
|
|
message[0x169] = 0;
|
|
const std::size_t length = std::strlen(message) + 1;
|
|
if (std::strlen(g_windowMgr.unknown_04DC.c_str()) != 0) {
|
|
std::uint16_t packetId;
|
|
if (argument1 == 0 || argument1 == 2 || argument1 == 4) {
|
|
packetId = 0x99;
|
|
} else if (argument1 == 1 || argument1 == 3 || argument1 == 5) {
|
|
packetId = 0x19C;
|
|
}
|
|
unsigned char packet[0x800];
|
|
const std::uint16_t packetLength = static_cast<std::uint16_t>(length + 4);
|
|
std::memcpy(packet, &packetId, 2);
|
|
std::memcpy(packet + 2, &packetLength, 2);
|
|
std::memcpy(packet + 4, message, length);
|
|
GetRagConnection().Send(packetLength, packet);
|
|
}
|
|
g_windowMgr.ClearUnknown04DC();
|
|
return 0;
|
|
}
|
|
case 0xA: {
|
|
if (this->scene->player != nullptr) {
|
|
this->scene->player->SendMsg(nullptr, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
const auto* request = reinterpret_cast<const std::uint32_t*>(argument1);
|
|
if (request[1] == 0x2D) {
|
|
if (this->unknown_0244 == 1) {
|
|
return 0;
|
|
}
|
|
this->unknown_0244 = 1;
|
|
this->unknown_0248 = timeGetTime();
|
|
}
|
|
const GameModePacketDwordByte packet{0x90, request[0], *reinterpret_cast<const std::uint8_t*>(request + 2)};
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetId), &packet);
|
|
return 0;
|
|
}
|
|
case 0x46: {
|
|
if (this->scene->player->unknown_02CC != 0 && !g_session.IsHomunculusSkill(argument1) && !g_session.IsMercenarySkill(argument1)) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x75E)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
if (this->IsMenuWindowOpen()) {
|
|
return 0;
|
|
}
|
|
const auto* request = reinterpret_cast<const int*>(argument1);
|
|
const int skill = request[0];
|
|
const int x = request[1];
|
|
const int y = request[2];
|
|
int level = request[3];
|
|
if (this->unknown_0418 == 0 && !g_session.IsRequestReady(skill)) {
|
|
char message[0x800];
|
|
const char* name = CSkillInfo::DisplayName(*g_session.m_hotkeyScript, skill);
|
|
std::sprintf(message, LookupMessage(0x5B4), name);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0xFF, 0xB, 0, 0);
|
|
return 0;
|
|
}
|
|
if (level == 0) {
|
|
level = g_session.m_skillBundle.Lookup(skill).level;
|
|
}
|
|
const std::uint16_t words[] = {0xAF4, static_cast<std::uint16_t>(level), static_cast<std::uint16_t>(skill), static_cast<std::uint16_t>(x), static_cast<std::uint16_t>(y)};
|
|
unsigned char packet[11];
|
|
std::memcpy(packet, words, sizeof(words));
|
|
packet[10] = static_cast<unsigned char>(argument2);
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(words[0]), packet);
|
|
return 0;
|
|
}
|
|
case 0x66: {
|
|
if (g_guildInfo.unknown_00B4 == 0 || static_cast<std::int32_t>(static_cast<std::uint32_t>(argument2) + 4) > 0x800) {
|
|
return 0;
|
|
}
|
|
unsigned char packet[0x800];
|
|
const std::uint16_t header[] = {0x153, static_cast<std::uint16_t>(argument2 + 4)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
std::memcpy(packet + 4, reinterpret_cast<const void*>(argument1), argument2);
|
|
GetRagConnection().Send(static_cast<std::int16_t>(header[1]), packet);
|
|
return 0;
|
|
}
|
|
case 0x81: {
|
|
if (std::strlen(g_windowMgr.unknown_04DC.c_str()) == 0 || g_guildInfo.m_guildId == 0 || g_session.IsBerserkActive() == 1) {
|
|
return 0;
|
|
}
|
|
char text[0x800];
|
|
std::strcpy(text, g_windowMgr.unknown_04DC.c_str());
|
|
if (g_forbiddenWords.Contains(text)) {
|
|
std::string masked;
|
|
g_forbiddenWords.Mask(text, &masked);
|
|
g_windowMgr.unknown_04DC.assign(text, std::strlen(text));
|
|
}
|
|
if (this->unknown_0438 == text) {
|
|
++this->unknown_0450;
|
|
} else {
|
|
this->unknown_0450 = 0;
|
|
}
|
|
if (this->ShowRestrictedNotice(this->unknown_0450)) {
|
|
return 0;
|
|
}
|
|
this->unknown_0438.assign(text, std::strlen(text));
|
|
if (g_navigationLinkParser->HasUnownedItemLink(g_windowMgr.unknown_04DC.c_str())) {
|
|
return 0;
|
|
}
|
|
char message[0x169] = {};
|
|
const char* body = g_windowMgr.unknown_04DC.c_str();
|
|
const char* prefix = g_serverLanguage->Prefix(false);
|
|
StringFormat(message, sizeof(message), static_cast<std::size_t>(-1), "%s : %s%s", g_session.DecodePlayerName(), prefix, body);
|
|
g_windowMgr.ClearUnknown04DC();
|
|
const std::size_t length = std::strlen(message);
|
|
unsigned char packet[0x16D];
|
|
const std::uint16_t header[] = {0x17E, static_cast<std::uint16_t>(length + 4)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
std::memcpy(packet + 4, message, length);
|
|
GetRagConnection().Send(header[1], packet);
|
|
return 0;
|
|
}
|
|
case 0x10F: {
|
|
const int count = g_session.GetList11Size();
|
|
unsigned char packet[0x800];
|
|
const std::uint16_t header[] = {0x811, static_cast<std::uint16_t>(0x59 + count * 10)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
if (argument2 == 1) {
|
|
std::strncpy(reinterpret_cast<char*>(packet + 9), reinterpret_cast<const char*>(argument1), 0x4F);
|
|
packet[0x58] = 0;
|
|
std::memcpy(packet + 4, &argument3, 4);
|
|
packet[8] = 1;
|
|
} else {
|
|
std::memset(packet + 4, 0, 6);
|
|
}
|
|
if (g_replayAnimationScaling == 0) {
|
|
g_session.unknown_550C = reinterpret_cast<const char*>(packet + 9);
|
|
}
|
|
unsigned char* output = packet + 0x59;
|
|
for (int index = 0; index < count; ++index) {
|
|
const ITEM_INFO item = g_session.GetItem1768At(index);
|
|
if (item.unknown_0000[1] > 0) {
|
|
const int id = std::atoi(item.itemId.c_str());
|
|
const std::uint16_t quantity = static_cast<std::uint16_t>(item.quantity);
|
|
std::memcpy(output, &id, 4);
|
|
std::memcpy(output + 4, &quantity, 2);
|
|
std::memcpy(output + 6, &item.unknown_0014[1], 4);
|
|
output += 10;
|
|
}
|
|
}
|
|
if (count == 0) {
|
|
packet[8] = 0;
|
|
}
|
|
GetRagConnection().Send(static_cast<std::int16_t>(header[1]), packet);
|
|
return 0;
|
|
}
|
|
case 0x128: {
|
|
unsigned char packet[0x800] = {};
|
|
const int count = g_session.GetList11Size();
|
|
const std::uint16_t header[] = {0xA7F, static_cast<std::uint16_t>(0x58 + count * 8)};
|
|
std::memcpy(packet, header, sizeof(header));
|
|
std::strncpy(reinterpret_cast<char*>(packet + 4), reinterpret_cast<const char*>(argument1), 0x4F);
|
|
packet[0x53] = 0;
|
|
if (g_windowMgr.unknown_02FC != nullptr) {
|
|
const auto* shop = reinterpret_cast<const UIMerchantShopMakeWnd*>(g_windowMgr.unknown_02FC);
|
|
std::memcpy(packet + 0x54, &shop->unknown_018A, 2);
|
|
std::memcpy(packet + 0x56, &shop->unknown_018C, 2);
|
|
}
|
|
unsigned char* output = packet + 0x58;
|
|
for (int index = 0; index < count; ++index) {
|
|
const ITEM_INFO item = g_session.GetItem1768At(index);
|
|
if (item.unknown_0000[1] != 0) {
|
|
const std::uint16_t id = static_cast<std::uint16_t>(item.unknown_0000[1]);
|
|
const std::uint16_t quantity = static_cast<std::uint16_t>(item.quantity);
|
|
std::memcpy(output, &id, 2);
|
|
std::memcpy(output + 2, &quantity, 2);
|
|
std::memcpy(output + 4, &item.unknown_0014[1], 4);
|
|
output += 8;
|
|
}
|
|
}
|
|
GetRagConnection().Send(static_cast<std::int16_t>(header[1]), packet);
|
|
return 0;
|
|
}
|
|
default:
|
|
return CMode::SendMsg(event, argument1, argument2, argument3, 0);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CCD880
|
|
// FUNCTION: fn_21217
|
|
CGameMode::CGameMode()
|
|
: scene(nullptr), unknown_0408(nullptr), unknown_040C(0), unknown_0410(0), unknown_0414(0), unknown_0418(0), unknown_05C4(0), unknown_05C8(0),
|
|
broadcastBalloon(nullptr), noticeBalloon(nullptr), unknown_0648(0) {
|
|
this->unknown_0624[0] = 0;
|
|
this->camera = nullptr;
|
|
this->mousePointer = nullptr;
|
|
this->replayPauseTick = 0;
|
|
this->unknown_05EC[0] = 0;
|
|
this->itemWindow = nullptr;
|
|
this->unknown_060C[0] = 0;
|
|
}
|
|
|
|
// OFFSET: 0x00CEFE70
|
|
// FUNCTION: fn_21408
|
|
void CGameMode::RemoveUnknown0604(int window) {
|
|
UIWindow* target = reinterpret_cast<UIWindow*>(window);
|
|
for (std::list<UIWindow*>::iterator it = this->unknown_0604.begin(); it != this->unknown_0604.end(); ++it) {
|
|
if (*it == target) {
|
|
this->unknown_0604.erase(it);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CEFB30
|
|
// FUNCTION: fn_21404
|
|
void CGameMode::AddUnknown0604(UIWindow* window) {
|
|
this->unknown_0604.push_back(window);
|
|
}
|
|
|
|
#pragma pack(push, 1)
|
|
struct AdminStatusRequestPacket {
|
|
/* 0000 */ std::uint16_t id;
|
|
/* 0002 */ std::uint32_t accountId;
|
|
/* 0006 */ unsigned char unknown_0006;
|
|
/* 0007 */ std::uint16_t unknown_0007;
|
|
};
|
|
#pragma pack(pop)
|
|
static_assert(sizeof(AdminStatusRequestPacket) == 9);
|
|
|
|
// OFFSET: 0x00CEFCA0
|
|
// FUNCTION: fn_21405
|
|
void CGameMode::RequestAdminStatus() {
|
|
if (IsAdminAccount(g_session.m_aid)) {
|
|
return;
|
|
}
|
|
|
|
if (g_serviceMode == 3) {
|
|
return;
|
|
}
|
|
|
|
AdminStatusRequestPacket packet = {};
|
|
packet.id = 0x149;
|
|
packet.accountId = static_cast<std::uint32_t>(g_session.m_aid);
|
|
packet.unknown_0006 = 2;
|
|
packet.unknown_0007 = 0xA;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.id), &packet);
|
|
}
|
|
|
|
// OFFSET: 0x00D06BD0
|
|
// FUNCTION: fn_21578
|
|
void SetPlayerName(std::uint32_t id, std::string name) {
|
|
g_playerNameDictionary->Set(id, name);
|
|
static_cast<CGameMode*>(g_modeMgr.GetGameMode())->CompleteUnknown0194(id, name);
|
|
GuildInfo* guildInfo = &g_guildInfo;
|
|
guildInfo->UpdateCharacterName(id, name.c_str());
|
|
g_session.NotifyUnknown7F94Name(id, name.c_str());
|
|
g_session.UpdateFriendName(id, name.c_str());
|
|
}
|
|
|
|
// OFFSET: 0x00CDD350
|
|
// FUNCTION: fn_21316
|
|
void CGameMode::PlaceWindowAtActor(UIWindow* window, CGameActor* actor) {
|
|
const int width = window->geometry.width;
|
|
const int height = window->geometry.height;
|
|
const bool raised = g_serviceOptions.Get(0x5C) != 0;
|
|
int offsetX = 0;
|
|
int offsetY = 0;
|
|
switch (actor->render.unknown_00A8 != 0 ? raised : 0) {
|
|
case 0:
|
|
offsetX = -(width / 2);
|
|
offsetY = static_cast<int>(static_cast<float>(g_renderer->viewport.height * 20 / 480) * actor->render.unknown_005C);
|
|
break;
|
|
case 1:
|
|
offsetX = -(width / 2);
|
|
offsetY = static_cast<int>(static_cast<float>(g_renderer->viewport.height * -100 / 480) * actor->render.unknown_005C);
|
|
break;
|
|
case 2:
|
|
offsetX = static_cast<int>(
|
|
static_cast<float>(g_renderer->viewport.width * -30 / 640) * actor->render.unknown_005C - static_cast<float>(width / 2)
|
|
);
|
|
offsetY = static_cast<int>(
|
|
static_cast<float>(g_renderer->viewport.height * -25 / 480) * actor->render.unknown_005C - static_cast<float>(height / 2)
|
|
);
|
|
break;
|
|
case 3:
|
|
offsetX = static_cast<int>(
|
|
static_cast<float>(g_renderer->viewport.width * 30 / 640) * actor->render.unknown_005C - static_cast<float>(width / 2)
|
|
);
|
|
offsetY = static_cast<int>(
|
|
static_cast<float>(g_renderer->viewport.height * -25 / 480) * actor->render.unknown_005C - static_cast<float>(height / 2)
|
|
);
|
|
break;
|
|
}
|
|
|
|
int x = actor->render.screenX + offsetX;
|
|
int y = actor->render.screenY + offsetY;
|
|
if (x < -3) {
|
|
x = -3;
|
|
}
|
|
const int maximumX = g_renderer->viewport.width - window->geometry.width + 3;
|
|
if (maximumX < x) {
|
|
x = maximumX;
|
|
}
|
|
if (y < -3) {
|
|
y = -3;
|
|
}
|
|
const int maximumY = g_renderer->viewport.height - window->geometry.height + 3;
|
|
if (maximumY < y) {
|
|
y = maximumY;
|
|
}
|
|
window->Move(x, y);
|
|
}
|
|
|
|
// OFFSET: 0x00CDD790
|
|
// FUNCTION: fn_21318
|
|
void CGameMode::Slot7(int value) {
|
|
}
|
|
|
|
// OFFSET: 0x00CDFA00
|
|
// FUNCTION: fn_21324
|
|
std::uint64_t CGameMode::LaunchDummyEffect(const vector3d* position, int effectId, int lifeFrames, int value) {
|
|
if (lifeFrames > 0) {
|
|
CDummyEffectLauncher* launcher = new CDummyEffectLauncher;
|
|
if (launcher != nullptr) {
|
|
const int address = reinterpret_cast<int>(position);
|
|
launcher->SendMsg(nullptr, 14, 0, address, address >> 31, effectId, effectId >> 31, lifeFrames, lifeFrames >> 31, value, value >> 31, 0, 0, 0, 0);
|
|
this->scene->objects.push_back(launcher);
|
|
return launcher->identity;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// OFFSET: 0x00CDFB00
|
|
// FUNCTION: fn_21326
|
|
void CGameMode::RequestPlayerAction(int target, int argument) {
|
|
int value = this->unknown_040C;
|
|
if (value != 10000) {
|
|
const int maxWeight = g_session.m_maxWeight < 1 ? 1 : g_session.m_maxWeight;
|
|
if (g_session.m_weight * 100 / maxWeight >= 90) {
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(307)), 0xFF, 0, 0, 0);
|
|
value = this->unknown_040C;
|
|
if (value != 40000) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (reinterpret_cast<std::intptr_t>(this->unknown_0408)) {
|
|
case 0:
|
|
this->scene->player->SendMsg(nullptr, 10, 0, target, 0, argument, argument >> 31, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
break;
|
|
case 2:
|
|
case 4:
|
|
this->scene->player->SendMsg(nullptr, 41, 0, target, 0, value, value >> 31, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
this->scene->player->SendMsg(nullptr, 90, 0, this->unknown_0414, this->unknown_0414 >> 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CE45B0
|
|
// FUNCTION: fn_21336
|
|
void CGameMode::UpdateLoopSounds() {
|
|
for (std::vector<GameModeLoopSound>::iterator it = this->loopSounds.begin(); it != this->loopSounds.end(); ++it) {
|
|
timeGetTime();
|
|
if (timeGetTime() < it->nextTick) {
|
|
continue;
|
|
}
|
|
|
|
if (it->npcId) {
|
|
CRenderObject* actor = this->scene->GetGameActorByAID(it->npcId);
|
|
if (actor) {
|
|
CPlayer* player = this->scene->player;
|
|
g_soundMgr->PlayWave(it->name.c_str(), player->render.position.x - actor->render.position.x, 0.0f,
|
|
player->render.position.z - actor->render.position.z, 250, 40, 1.0f, 0);
|
|
}
|
|
} else {
|
|
g_soundMgr->PlayWave(it->name.c_str(), 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
}
|
|
it->nextTick = timeGetTime() + it->term;
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CE81C0
|
|
// FUNCTION: fn_21340
|
|
void CGameMode::AddSceneObject(CRenderObject* object) {
|
|
if (this->scene && object) {
|
|
this->scene->objects.push_back(object);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CED2E0
|
|
// FUNCTION: fn_21365
|
|
void CGameMode::SendMousePointerPosition(float x, float y, int value) {
|
|
float position[2];
|
|
position[0] = x;
|
|
position[1] = y;
|
|
const std::intptr_t address = reinterpret_cast<std::intptr_t>(position);
|
|
this->mousePointer->SendMsg(nullptr, 1, 0, address, address >> 31, value, value >> 31, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
|
|
// OFFSET: 0x00CED330
|
|
// FUNCTION: fn_21366
|
|
void ShowCurrentMapName() {
|
|
if (g_serviceOptions.Get(0x10C)) {
|
|
const std::string mapName = g_session.m_navigationPlayerMap + std::string(".rsw");
|
|
g_mapInfoMgr->ShowMapName(mapName);
|
|
}
|
|
}
|
|
|
|
// GLOBAL: gl_25129
|
|
char g_chatLogPath[260];
|
|
|
|
// OFFSET: 0x00CED760
|
|
// FUNCTION: fn_21369
|
|
void CGameMode::WriteChatLog(const char* text) {
|
|
if (g_session.IsAdminSubMode(7) == 0) {
|
|
return;
|
|
}
|
|
|
|
++this->chatLogLines;
|
|
CFile previous;
|
|
previous.Open(g_chatLogPath, 0, true, false);
|
|
const std::uint32_t size = previous.GetSize();
|
|
char* contents = new char[size];
|
|
previous.Read(contents, size);
|
|
previous.Close();
|
|
g_whisperFile.Open(g_chatLogPath, 0x1001, true, false);
|
|
g_whisperFile.Write(contents, size);
|
|
g_whisperFile.Write(text, static_cast<std::uint32_t>(std::strlen(text) + 1));
|
|
g_whisperFile.Write("\r\n", 2);
|
|
g_whisperFile.Close();
|
|
delete[] contents;
|
|
}
|
|
|
|
// OFFSET: 0x00CF08D0
|
|
// FUNCTION: fn_21417
|
|
bool CGameMode::IsEffectId990Group(int id) {
|
|
bool result = false;
|
|
switch (id) {
|
|
case 990:
|
|
case 991:
|
|
case 992:
|
|
case 993:
|
|
result = true;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// OFFSET: 0x00CF0910
|
|
// FUNCTION: fn_21418
|
|
bool CGameMode::IsEffectId994Group(int id) {
|
|
bool result = false;
|
|
switch (id) {
|
|
case 994:
|
|
case 995:
|
|
case 996:
|
|
case 997:
|
|
result = true;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// OFFSET: 0x00CF0950
|
|
// FUNCTION: fn_21419
|
|
bool CGameMode::ConfirmDraggedItemUse() {
|
|
if (g_session.unknown_16EC != this->drag.id) {
|
|
return false;
|
|
}
|
|
|
|
ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, this->drag.id);
|
|
if (item.unknown_0000[1] > 0) {
|
|
if (g_replayAnimationScaling) {
|
|
this->unknown_05EC[0] = 0;
|
|
}
|
|
g_modeMgr.GetGameMode()->SendMsg(18, 0, 0, 0, 0);
|
|
g_windowMgr.Confirm(LookupMessage(657), 0, true, false, 0, "Message", 280, 120, 0);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// OFFSET: 0x00CFE480
|
|
// FUNCTION: fn_21432
|
|
void CGameMode::sub_CFE480(int actorId) {
|
|
if (g_windowMgr.unknown_0508 != 2 && actorId == static_cast<int>(g_session.m_aid)) {
|
|
this->scene->player->unknown_0544->SendMsg(nullptr, 44, 0, 1, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CDBC30
|
|
// FUNCTION: fn_21312
|
|
void __stdcall sub_CDBC30(const vector3d* position, int actorId, float scale, int job) {
|
|
if (actorId == 0) {
|
|
return;
|
|
}
|
|
|
|
CSprArrowEffect* effect = static_cast<CSprArrowEffect*>(
|
|
g_effectMgr->Spawn(0, 0x964, position->x, position->y, position->z, actorId, -1, 0, 0)
|
|
);
|
|
if (effect != nullptr) {
|
|
effect->unknown_00F4 = scale;
|
|
effect->SetBulletSprite(job);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CE8F10
|
|
// FUNCTION: fn_21344
|
|
void __stdcall sub_CE8F10(const void* info, const unsigned char* data) {
|
|
if (Replay::Instance().state != 2) {
|
|
return;
|
|
}
|
|
|
|
if (Replay::Instance().header.options.recordRestricted == 0) {
|
|
return;
|
|
}
|
|
|
|
GameModeReplayPacket packet;
|
|
packet.header = 0x038A08AE;
|
|
packet.length = 0xFE;
|
|
std::memcpy(&packet.info, info, sizeof(packet.info));
|
|
std::memcpy(packet.data, data, sizeof(packet.data));
|
|
|
|
Replay::Instance().Record(packet.length, &packet, 0x2A, 0);
|
|
}
|
|
|
|
// OFFSET: 0x00CDFAF0
|
|
// FUNCTION: fn_21325
|
|
void CGameMode::IgnorePacket() {
|
|
}
|
|
|
|
// OFFSET: 0x00CE8EC0
|
|
// FUNCTION: fn_21343
|
|
void CGameMode::RemoveUnknown01A4(int value) {
|
|
for (std::list<int>::iterator it = this->unknown_01A4.begin(); it != this->unknown_01A4.end(); ++it) {
|
|
if (*it == value) {
|
|
this->unknown_01A4.erase(it);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma pack(push, 1)
|
|
struct GameModeMessageRecord {
|
|
/* 0000 */ std::uint32_t header;
|
|
/* 0004 */ std::uint16_t length;
|
|
/* 0006 */ int message;
|
|
/* 000A */ int value;
|
|
/* 000E */ int first;
|
|
/* 0012 */ int second;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(sizeof(GameModeMessageRecord) == 0x16);
|
|
|
|
// OFFSET: 0x00CE8FC0
|
|
// FUNCTION: fn_21345
|
|
bool CGameMode::RecordReplayMessage(int message, int value, int first, int second) {
|
|
if (Replay::Instance().state != 2 || message != 0x45 || value != 10000) {
|
|
return false;
|
|
}
|
|
|
|
GameModeMessageRecord record;
|
|
record.header = 0x038908AE;
|
|
record.length = sizeof(GameModeMessageRecord);
|
|
record.message = 0x45;
|
|
record.value = 10000;
|
|
record.first = first;
|
|
record.second = second;
|
|
|
|
Replay::Instance().Record(record.length, &record, 0x2A, 0);
|
|
return true;
|
|
}
|
|
|
|
// OFFSET: 0x00CED260
|
|
// FUNCTION: fn_21364
|
|
void CGameMode::UpdateReplayActionSpeeds() {
|
|
CPlayer* player = this->scene->player;
|
|
player->SetActionSpeed(Replay::Instance().AnimationScale());
|
|
for (CRenderObject* actor : this->scene->actors) {
|
|
actor->SetActionSpeed(Replay::Instance().AnimationScale());
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CF1010
|
|
// FUNCTION: fn_45498
|
|
int ConfirmGameModeAction96() {
|
|
if (g_windowMgr.LookupWindow(0x271B)) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xDDE)), 0xFF, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
g_modeMgr.gameMode->SendMsg(0x96, 1, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
|
|
// OFFSET: 0x00CF1060
|
|
// FUNCTION: fn_21425
|
|
ReplayTime CGameMode::StopReplayRecording() {
|
|
if (Replay::Instance().state != 2) {
|
|
return ReplayTime();
|
|
}
|
|
|
|
Replay::Instance().SetState(1);
|
|
Replay::Instance().UpdateDuration();
|
|
const ReplayTime duration = Replay::Instance().Duration();
|
|
Replay::Instance().CloseFile();
|
|
return duration;
|
|
}
|
|
|
|
#pragma pack(push, 1)
|
|
struct GameModeChunkHeader {
|
|
/* 0000 */ std::int16_t type;
|
|
/* 0002 */ std::uint32_t size;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(sizeof(GameModeChunkHeader) == 6);
|
|
|
|
#pragma pack(push, 1)
|
|
struct GameModeStoredRecord00DA {
|
|
/* 0000 */ std::uint16_t type;
|
|
/* 0002 */ int value0002;
|
|
/* 0006 */ int value0006;
|
|
/* 000A */ std::uint16_t value000A;
|
|
/* 000C */ std::uint16_t value000C;
|
|
/* 000E */ unsigned char value000E;
|
|
/* 000F */ std::uint16_t value000F;
|
|
/* 0011 */ int value0011;
|
|
/* 0015 */ int value0015;
|
|
/* 0019 */ std::uint16_t value0019;
|
|
/* 001B */ std::uint16_t value001B;
|
|
/* 001D */ std::uint16_t value001D;
|
|
/* 001F */ std::uint16_t value001F;
|
|
/* 0021 */ std::uint16_t value0021;
|
|
/* 0023 */ std::uint16_t value0023;
|
|
/* 0025 */ char text[0x18];
|
|
/* 003D */ std::uint16_t value003D;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(offsetof(GameModeStoredRecord00DA, text) == 0x25);
|
|
static_assert(offsetof(GameModeStoredRecord00DA, value003D) == 0x3D);
|
|
|
|
static_assert(sizeof(GameModeTextRecord) == 0x190);
|
|
static_assert(offsetof(GameModeTextRecord, buffer) == 0x1E);
|
|
|
|
// OFFSET: 0x00CFE4D0
|
|
// FUNCTION: fn_21433
|
|
void CGameMode::NotifyUnknown0604(int value) {
|
|
for (std::list<UIWindow*>::iterator it = this->unknown_0604.begin(); it != this->unknown_0604.end(); ++it) {
|
|
(*it)->SendMsg(nullptr, 60, value, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CEBF30
|
|
// FUNCTION: fn_21354
|
|
unsigned CGameMode::sub_CEBF30(const std::vector<unsigned char>& data) {
|
|
if (data.empty()) {
|
|
return 0xFFFFFFFFu;
|
|
}
|
|
|
|
GameModeChunkHeader header = {};
|
|
unsigned offset = 6;
|
|
header = *reinterpret_cast<const GameModeChunkHeader*>(data.data());
|
|
if (header.type == 15000) {
|
|
while (offset < data.size()) {
|
|
header = {};
|
|
header = *reinterpret_cast<const GameModeChunkHeader*>(data.data() + offset);
|
|
offset += 6;
|
|
|
|
if (header.type == 0xCF) {
|
|
std::vector<unsigned char> record(0x13);
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D2DB80(record.data());
|
|
} else if (header.type == 15001) {
|
|
break;
|
|
} else {
|
|
offset += header.size;
|
|
}
|
|
}
|
|
} else {
|
|
offset = 0xFFFFFFFFu;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
// OFFSET: 0x00CEC100
|
|
// FUNCTION: fn_21355
|
|
unsigned CGameMode::sub_CEC100(const std::vector<unsigned char>& data) {
|
|
if (data.empty()) {
|
|
return 0xFFFFFFFFu;
|
|
}
|
|
|
|
GameModeChunkHeader header = {};
|
|
unsigned offset = 6;
|
|
header = *reinterpret_cast<const GameModeChunkHeader*>(data.data());
|
|
if (header.type == 10000) {
|
|
std::vector<unsigned char> record;
|
|
while (offset < data.size()) {
|
|
header = {};
|
|
header = *reinterpret_cast<const GameModeChunkHeader*>(data.data() + offset);
|
|
offset += 6;
|
|
|
|
if (static_cast<int>(header.size) > 0) {
|
|
record.resize(header.size);
|
|
}
|
|
|
|
if (header.type == 10001) {
|
|
break;
|
|
}
|
|
|
|
switch (header.type) {
|
|
case 0xC9:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D3F130(record.data());
|
|
break;
|
|
case 0xCA:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D51A90(record.data());
|
|
break;
|
|
case 0xCB:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D3D2F0(record.data());
|
|
break;
|
|
case 0xCC:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D24430(record.data());
|
|
break;
|
|
case 0xD0:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D350A0(record.data());
|
|
break;
|
|
case 0xD2:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D37A10(record.data());
|
|
break;
|
|
case 0xD4:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D619E0(record.data());
|
|
break;
|
|
case 0xD5:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D61390(record.data());
|
|
break;
|
|
case 0xD6:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D616B0(record.data());
|
|
break;
|
|
case 0xD7:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D63D70(record.data());
|
|
break;
|
|
case 0xD8:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D63720(record.data());
|
|
break;
|
|
case 0xD9:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D63A40(record.data());
|
|
break;
|
|
case 0xDA: {
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
const auto* stored = reinterpret_cast<const GameModeStoredRecord00DA*>(record.data());
|
|
this->sub_D7B170(
|
|
stored->value0002, stored->value0006, stored->value000A, stored->value000C, stored->value000E, stored->value000F,
|
|
stored->value0011, stored->value0015, stored->value0019, stored->value001B, stored->value001D, stored->value001F,
|
|
stored->value0021, stored->value0023, stored->text, stored->value003D
|
|
);
|
|
break;
|
|
}
|
|
case 0x191:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->sub_D65FC0(record.data());
|
|
break;
|
|
default:
|
|
offset += header.size;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
offset = 0xFFFFFFFFu;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
// OFFSET: 0x00CCFD70
|
|
// FUNCTION: fn_21248
|
|
void CGameMode::UpdatePetFriendlyWindow(int previousFriendly) {
|
|
if (!g_serviceOptions.Get(0x128)) {
|
|
return;
|
|
}
|
|
|
|
if (g_session.GetPetFriendlyState(g_session.m_petFriendly) == 0 && g_session.m_petFriendly <= 100) {
|
|
if (this->unknown_0628.find(g_session.unknown_1010) == this->unknown_0628.end()) {
|
|
if (g_windowMgr.window_038C == nullptr) {
|
|
g_windowMgr.EnsureWindow(0x58);
|
|
}
|
|
|
|
this->UpdateUnknown0628(g_session.unknown_1010, true);
|
|
}
|
|
}
|
|
|
|
if (previousFriendly < g_session.m_petFriendly && g_session.m_petFriendly > 99) {
|
|
auto it = this->unknown_0628.find(g_session.unknown_1010);
|
|
if (it != this->unknown_0628.end()) {
|
|
this->unknown_0628.erase(it);
|
|
}
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CECE30
|
|
// FUNCTION: fn_21362
|
|
bool CGameMode::SaveEmblemFile(const std::vector<unsigned char>& data) {
|
|
if (data.empty()) {
|
|
return false;
|
|
}
|
|
|
|
const int nameLength = *reinterpret_cast<const int*>(data.data());
|
|
std::string name;
|
|
name.assign(reinterpret_cast<const char*>(data.data() + 4), nameLength);
|
|
|
|
char path[260];
|
|
std::memset(path, 0, sizeof(path));
|
|
std::sprintf(path, "%s\\_tmpEmblem\\%s", g_applicationDirectory, name.c_str());
|
|
|
|
CFile file;
|
|
if (file.Open(path, 0, true, false)) {
|
|
file.Close();
|
|
} else {
|
|
file.Close();
|
|
std::FILE* output = std::fopen(path, "wb");
|
|
if (output != nullptr) {
|
|
std::fwrite(data.data() + 4 + nameLength, data.size() - nameLength - 4, 1, output);
|
|
std::fclose(output);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// OFFSET: 0x00CF0E30
|
|
|
|
// OFFSET: 0x00CF0BA0
|
|
// FUNCTION: fn_21423
|
|
void WriteMyLog(const char* file, int line, const char* format, ...) {
|
|
char message[0x801];
|
|
std::memset(message, 0, sizeof(message));
|
|
|
|
va_list arguments;
|
|
va_start(arguments, format);
|
|
_vsnprintf(message, 0x800, format, arguments);
|
|
va_end(arguments);
|
|
|
|
if (std::strrchr(file, '\\') != nullptr) {
|
|
file = std::strrchr(file, '\\');
|
|
}
|
|
|
|
std::string path = FormatString("mylog(%s).txt", "");
|
|
std::FILE* output = std::fopen(path.c_str(), "a");
|
|
if (output != nullptr) {
|
|
SYSTEMTIME time;
|
|
GetLocalTime(&time);
|
|
std::fprintf(
|
|
output, "%-30s(%04d) %02d-%02d-%02d %02d:%02d:%02d.%03d %s\n", file, line, time.wYear, time.wMonth, time.wDay, time.wHour,
|
|
time.wMinute, time.wSecond, time.wMilliseconds, message
|
|
);
|
|
std::fclose(output);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CF0090
|
|
// FUNCTION: fn_21411
|
|
std::string CGameMode::HuntTargetText(const RenewQuestOngoingInfo& quest, int index) {
|
|
std::string text;
|
|
if (std::strlen(quest.m_huntName[index]) == 0) {
|
|
text.assign(g_renewQuestMgr->GetMonsterConditionText(quest.m_huntUnknown01A0[index], quest.m_huntUnknown01AC[index], quest.m_huntUnknown01B2[index]));
|
|
} else {
|
|
text.assign(FormatOwnedString("%s", quest.m_huntName[index]));
|
|
}
|
|
|
|
if (quest.m_huntUnknown00E0[index] == quest.m_huntUnknown0180[index]) {
|
|
text.assign(FormatOwnedString("%s [ %s ]", text.c_str(), LookupMessage(0x7EE)));
|
|
} else {
|
|
text.assign(FormatOwnedString("%s [ %d / %d ]", text.c_str(), quest.m_huntUnknown00E0[index], quest.m_huntUnknown0180[index]));
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
#pragma pack(push, 1)
|
|
struct GameModeStoredSkillEffect {
|
|
/* 0000 */ GameModeChunkHeader header;
|
|
/* 0006 */ ActiveSkillEffect effect;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(sizeof(GameModeStoredSkillEffect) == 0x22);
|
|
|
|
#pragma pack(push, 1)
|
|
struct GameModeStoredValue {
|
|
/* 0000 */ GameModeChunkHeader header;
|
|
/* 0006 */ int value;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(sizeof(GameModeStoredValue) == 0xA);
|
|
|
|
// OFFSET: 0x00CE9050
|
|
// FUNCTION: fn_21346
|
|
std::vector<unsigned char> CGameMode::SaveActiveSkillEffects() {
|
|
std::vector<unsigned char> data;
|
|
|
|
{
|
|
std::vector<unsigned char> chunk(sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 19000;
|
|
header->size = 0;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
for (ActiveSkillEffect effect : g_activeSkillEffects) {
|
|
if (effect.unknown_0004 != 0 && effect.unknown_0004 != 999999) {
|
|
effect.unknown_0004 -= timeGetTime();
|
|
}
|
|
|
|
std::vector<unsigned char> chunk(sizeof(GameModeStoredSkillEffect));
|
|
auto* record = reinterpret_cast<GameModeStoredSkillEffect*>(chunk.data());
|
|
record->header.type = 0x4A43;
|
|
record->header.size = sizeof(ActiveSkillEffect);
|
|
record->effect = effect;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
{
|
|
std::vector<unsigned char> chunk(sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 19001;
|
|
header->size = 0;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
// OFFSET: 0x00CE9DB0
|
|
// FUNCTION: fn_21348
|
|
std::vector<unsigned char> CGameMode::SaveUnknown024C() {
|
|
std::vector<unsigned char> data;
|
|
|
|
{
|
|
std::vector<unsigned char> chunk(sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 14000;
|
|
header->size = 0;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
{
|
|
std::vector<unsigned char> chunk(sizeof(GameModeStoredValue));
|
|
auto* record = reinterpret_cast<GameModeStoredValue*>(chunk.data());
|
|
record->header.type = 14011;
|
|
record->header.size = sizeof(int);
|
|
record->value = this->unknown_024C;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
{
|
|
std::vector<unsigned char> chunk(sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 14001;
|
|
header->size = 0;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
// OFFSET: 0x00CF0E30
|
|
// FUNCTION: fn_21424
|
|
void CGameMode::SendNpcInputText(std::uint32_t npcId, const char* text, const char* replacement, int unused) {
|
|
if (npcId != 0 && this->scene->GetGameActorByAID(npcId) == nullptr) {
|
|
return;
|
|
}
|
|
|
|
char buffer[0x16A];
|
|
std::memset(buffer, 0, sizeof(buffer));
|
|
StringFormat(buffer, sizeof(buffer), static_cast<std::size_t>(-1), "%s", replacement != nullptr ? replacement : text);
|
|
if (g_navigationLinkParser->HasUnownedItemLink(buffer) == true) {
|
|
return;
|
|
}
|
|
|
|
const std::size_t length = std::strlen(buffer);
|
|
unsigned char* packet = static_cast<unsigned char*>(
|
|
_MallocaComputeSize(length + 8) != 0
|
|
? (_MallocaComputeSize(length + 8) <= _ALLOCA_S_THRESHOLD
|
|
? _MarkAllocaS(_alloca(_MallocaComputeSize(length + 8)), _ALLOCA_S_STACK_MARKER)
|
|
: _MarkAllocaS(std::malloc(_MallocaComputeSize(length + 8)), _ALLOCA_S_HEAP_MARKER))
|
|
: nullptr
|
|
);
|
|
if (packet == nullptr) {
|
|
return;
|
|
}
|
|
|
|
*reinterpret_cast<std::uint32_t*>(packet + 4) = npcId;
|
|
*reinterpret_cast<std::uint16_t*>(packet) = 0x1D5;
|
|
*reinterpret_cast<std::uint16_t*>(packet + 2) = static_cast<std::uint16_t>(length + 8);
|
|
memcpy_s(packet + 8, length, buffer, length);
|
|
GetRagConnection().Send(*reinterpret_cast<std::uint16_t*>(packet + 2), packet);
|
|
_freea(packet);
|
|
}
|
|
|
|
// GLOBAL: gl_25200
|
|
float g_cameraMinDistance = 230.0f;
|
|
|
|
// GLOBAL: gl_24576
|
|
float g_cameraBaseDistance = 300.0f;
|
|
|
|
// GLOBAL: gl_25201
|
|
float g_cameraPitch = -45.0f;
|
|
|
|
// GLOBAL: gl_25202
|
|
float g_indoorCameraPitch = -45.0f;
|
|
|
|
// GLOBAL: gl_25203
|
|
float g_indoorCameraDistance = 300.0f;
|
|
|
|
// GLOBAL: gl_25204
|
|
float g_outdoorCameraPitch = -45.0f;
|
|
|
|
// GLOBAL: gl_25205
|
|
float g_outdoorCameraDistance = 300.0f;
|
|
|
|
// OFFSET: 0x00CECB90
|
|
// FUNCTION: fn_21359
|
|
void CGameMode::InitializeCamera() {
|
|
this->camera->camera.target[0] = this->scene->player->render.position.x;
|
|
this->camera->camera.target[1] = this->scene->player->render.position.y;
|
|
this->camera->camera.target[2] = this->scene->player->render.position.z;
|
|
this->camera->camera.desiredTarget[0] = this->scene->player->render.position.x;
|
|
this->camera->camera.desiredTarget[1] = this->scene->player->render.position.y;
|
|
this->camera->camera.desiredTarget[2] = this->scene->player->render.position.z;
|
|
this->hasViewParameters = 0;
|
|
|
|
int found;
|
|
const std::vector<std::string>* parameters = g_session.GetMapViewParameters(this->mapName, &found);
|
|
if (found != 0) {
|
|
this->hasViewParameters = 1;
|
|
for (int index = 0; index < 9; ++index) {
|
|
this->viewParameters[index] = static_cast<std::int16_t>(std::atof((*parameters)[index].c_str()));
|
|
}
|
|
}
|
|
|
|
const bool indoor = g_session.IsUnknownName5248(this->mapName);
|
|
this->unknown_0254 = !indoor;
|
|
float pitchRange = 10.0f;
|
|
float maxDistance = g_cameraBaseDistance;
|
|
float pitch;
|
|
float distance;
|
|
if (!indoor) {
|
|
pitchRange = 20.0f;
|
|
maxDistance = g_serviceOptionJitterScale;
|
|
pitch = g_outdoorCameraPitch;
|
|
distance = g_outdoorCameraDistance;
|
|
} else {
|
|
this->unknown_0288 = 45.0f;
|
|
this->camera->camera.yaw = 45.0f;
|
|
this->camera->camera.desiredYaw = this->unknown_0288;
|
|
pitch = g_indoorCameraPitch;
|
|
distance = g_indoorCameraDistance;
|
|
}
|
|
|
|
g_cameraDistance = distance;
|
|
g_cameraPitch = pitch;
|
|
if (-45.0f - pitchRange > pitch) {
|
|
pitch = -45.0f - pitchRange;
|
|
g_cameraPitch = pitch;
|
|
}
|
|
if (pitch > pitchRange - 45.0f) {
|
|
pitch = pitchRange - 45.0f;
|
|
g_cameraPitch = pitch;
|
|
}
|
|
if (g_cameraMinDistance > distance) {
|
|
distance = g_cameraMinDistance;
|
|
g_cameraDistance = distance;
|
|
}
|
|
if (distance > maxDistance) {
|
|
g_cameraDistance = maxDistance;
|
|
}
|
|
|
|
if (this->hasViewParameters != 0) {
|
|
g_cameraDistance = static_cast<float>(this->viewParameters[2]);
|
|
this->camera->camera.yaw = static_cast<float>(this->viewParameters[5]);
|
|
this->camera->camera.desiredYaw = static_cast<float>(this->viewParameters[5]);
|
|
pitch = static_cast<float>(this->viewParameters[8]);
|
|
g_cameraPitch = pitch;
|
|
}
|
|
|
|
this->camera->camera.pitch = pitch;
|
|
this->camera->camera.desiredPitch = g_cameraPitch;
|
|
this->camera->camera.distance = g_cameraDistance;
|
|
this->camera->camera.desiredDistance = g_cameraDistance;
|
|
}
|
|
|
|
#include "Contents/Schedule/Schedule.h"
|
|
#include "UI/Text/UINameBalloonText.h"
|
|
#include "UI/Text/UITransBalloonText.h"
|
|
#include "Contents/Messenger/ClientMessenger.h"
|
|
#include "ActorPickNode.h"
|
|
#include "Client/Registry.h"
|
|
#include "Contents/Schedule/CheckGDISchedule.h"
|
|
#include "Contents/Schedule/TimeScheduler.h"
|
|
#include "Render/Textures/TextureCache.h"
|
|
#include "Security/ReassemblyPacketMgr.h"
|
|
#include "UI/Dialogs/UIWaitWnd.h"
|
|
#include <chrono>
|
|
#include <winsock2.h>
|
|
#include "UI/Window/UIWordDisplayWnd.h"
|
|
|
|
class CPingLiveSchedule : public CSchedule {
|
|
public:
|
|
// INLINED
|
|
CPingLiveSchedule(const std::uint64_t& timestamp, const std::int64_t& interval)
|
|
: CSchedule(timestamp, interval, 1, ++g_schedulerSerial, 0) {
|
|
}
|
|
|
|
void Process(const std::uint64_t& now) override;
|
|
};
|
|
|
|
// OFFSET: 0x00CDEDF0
|
|
// FUNCTION: fn_21321
|
|
void CPingLiveSchedule::Process(const std::uint64_t& now) {
|
|
this->timestamp = now;
|
|
if (GetRagConnection().NativeSocket() == INVALID_SOCKET) {
|
|
this->active = false;
|
|
return;
|
|
}
|
|
|
|
const DWORD tick = timeGetTime();
|
|
if (g_session.m_lastReceiveTick + 60000 < tick) {
|
|
this->active = false;
|
|
GetRagConnection().Close();
|
|
g_windowMgr.EnsureWindow(332);
|
|
return;
|
|
}
|
|
|
|
if (g_session.m_lastSendTick + 10000 < tick) {
|
|
std::uint16_t packet = 0xB1C;
|
|
GetRagConnection().Send(sizeof(packet), &packet);
|
|
}
|
|
}
|
|
|
|
#include "Client/ModeFadeOut.h"
|
|
#include "Render/DeviceContext/DCSurface.h"
|
|
#include "Render/RenderSystemBase.h"
|
|
#include "Resource/ResourceMgr.h"
|
|
#include "Security/NProtectGameGuardMgr.h"
|
|
#include "Utility/Cipher/XorBytes.h"
|
|
|
|
namespace {
|
|
|
|
template <std::size_t Length, std::uint64_t Key>
|
|
class GameModeEncryptedName {
|
|
public:
|
|
explicit GameModeEncryptedName(const std::uint8_t (&source)[Length]) : m_encrypted(true) {
|
|
for (std::uint64_t index = 0; index < Length; ++index) {
|
|
this->m_text[index] = source[index];
|
|
}
|
|
}
|
|
|
|
~GameModeEncryptedName() {
|
|
for (std::uint64_t index = 0; index < Length; ++index) {
|
|
this->m_text[index] = 0;
|
|
}
|
|
}
|
|
|
|
const char* Text() {
|
|
if (this->m_encrypted) {
|
|
utility::XorBytes(this->m_text, Length, Key);
|
|
this->m_encrypted = false;
|
|
}
|
|
|
|
return reinterpret_cast<const char*>(this->m_text);
|
|
}
|
|
|
|
private:
|
|
/* 0000 */ std::uint8_t m_text[Length];
|
|
bool m_encrypted;
|
|
};
|
|
|
|
}
|
|
|
|
// OFFSET: 0x00CDEF00
|
|
// FUNCTION: fn_21322
|
|
int CGameMode::Run() {
|
|
while (this->running) {
|
|
if (g_modalImmediate) {
|
|
break;
|
|
}
|
|
|
|
if (g_windowMgr.modalWindows.empty() || g_windowMgr.modalWindows.back() == nullptr) {
|
|
if (!g_windowMgr.persistentWindows.empty()) {
|
|
if (g_windowMgr.retainedPersistentWindow) {
|
|
for (UIWindow* window : g_windowMgr.persistentWindows) {
|
|
g_windowMgr.Schedule(window);
|
|
}
|
|
g_windowMgr.retainedPersistentWindow = false;
|
|
}
|
|
g_windowMgr.persistentWindows.clear();
|
|
}
|
|
|
|
if (this->pendingCursorType != -1) {
|
|
this->cursorType = this->pendingCursorType;
|
|
this->cursorFrame = 0;
|
|
this->pendingCursorType = -1;
|
|
this->Slot7(this->cursorType);
|
|
}
|
|
}
|
|
|
|
if (g_nProtectGameGuardMgr->HasError()) {
|
|
GetRagConnection().Close();
|
|
g_modeMgr.Quit();
|
|
std::string message = g_nProtectGameGuardMgr->ErrorMessage();
|
|
if (!message.empty()) {
|
|
const std::uint8_t source[] = {0x53, 0x11, 0xF9, 0xA6, 0x8D, 0x7E, 0xA6, 0xD9, 0x1D, 0x06,
|
|
0xEA, 0xA4, 0x9C, 0x5C, 0xB0, 0xCC, 0x4F, 0x25, 0x8B};
|
|
thread_local GameModeEncryptedName<sizeof(source), 0xADC51BF9C98B413DULL> name(source);
|
|
MessageBoxA(hWnd, message.c_str(), name.Text(), 0);
|
|
}
|
|
}
|
|
|
|
this->Update();
|
|
Sleep(1);
|
|
}
|
|
|
|
FadeOutMode(*g_renderer, *GetRenderSystemHolder()->system, ResourceMgr::Instance(), 0, false, 0.0f, 0.0f);
|
|
return 1;
|
|
}
|
|
|
|
#include "Client/Input/Mouse.h"
|
|
|
|
// OFFSET: 0x00CDFC40
|
|
// FUNCTION: fn_21327
|
|
void CGameMode::TargetActorByAid(int aid) {
|
|
if (this->unknown_0250 != 0) {
|
|
return;
|
|
}
|
|
|
|
const unsigned char selfTargetOption = g_serviceOptions.Get(0x69);
|
|
const unsigned char forceOption = g_serviceOptions.Get(0x6D);
|
|
const int shiftHeld = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
int force = shiftHeld;
|
|
const std::intptr_t mode = reinterpret_cast<std::intptr_t>(this->unknown_0408);
|
|
const bool skillMode = mode == 2 || mode == 4;
|
|
const bool allowed = aid != static_cast<int>(g_session.m_aid) || mode == 4;
|
|
|
|
if (skillMode == true) {
|
|
const bool support = IsSupportSkill(this->unknown_040C);
|
|
const bool optionalSelf = IsOptionalSelfTargetSkill(this->unknown_040C);
|
|
if (support == true) {
|
|
force = 1;
|
|
}
|
|
if ((selfTargetOption != 0 || shiftHeld != 0) && optionalSelf == true) {
|
|
force = 1;
|
|
}
|
|
|
|
CWorld* scene = this->scene;
|
|
if (scene->unknown_0048 == 0 && scene->unknown_0054 == 0) {
|
|
if (scene->unknown_004C != 0) {
|
|
CGameActor* actor = static_cast<CGameActor*>(scene->GetGameActorByAID(aid));
|
|
if (actor != nullptr && !g_session.IsLocalPlayerAid(actor->Slot50())) {
|
|
GuildInfo* guildInfo = &g_guildInfo;
|
|
if (!guildInfo->HasRelatedGuild(actor->Slot50())) {
|
|
force = 1;
|
|
}
|
|
}
|
|
}
|
|
} else if (!g_session.IsPartyMember(aid, true)) {
|
|
force = 1;
|
|
}
|
|
}
|
|
|
|
if (allowed && g_mouse.buttons[0] == 1 && force != 0 && !HIBYTE(GetAsyncKeyState(VK_MENU))) {
|
|
this->SendMsg(0x1A, 1, 0, 0, 0);
|
|
*reinterpret_cast<int*>(&this->unknown_00D8[0x20]) = 0;
|
|
if (g_session.GetSceneUnknown004C() == 0 && (HIBYTE(GetAsyncKeyState(VK_CONTROL)) || forceOption != 0)) {
|
|
this->RequestPlayerAction(aid, 0);
|
|
this->forcedAttack = 1;
|
|
return;
|
|
}
|
|
this->RequestPlayerAction(aid, 1);
|
|
this->forcedAttack = 0;
|
|
}
|
|
}
|
|
|
|
#include "Contents/Actors/Skill.h"
|
|
|
|
#pragma pack(push, 1)
|
|
struct SkillEntryPacket {
|
|
/* 0000 */ std::int16_t packetType;
|
|
/* 0002 */ std::uint32_t aid;
|
|
/* 0006 */ std::uint32_t creatorAid;
|
|
/* 000A */ std::int16_t x;
|
|
/* 000C */ std::int16_t y;
|
|
/* 000E */ unsigned char job;
|
|
/* 000F */ unsigned char isVisible;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(sizeof(SkillEntryPacket) == 16);
|
|
|
|
// OFFSET: 0x00CEB4C0
|
|
// FUNCTION: fn_21351
|
|
std::vector<unsigned char> CGameMode::WriteReplaySkillState() {
|
|
std::vector<unsigned char> output;
|
|
{
|
|
const auto record = BuildReplayTaggedRecord(17000, nullptr, 0);
|
|
output.insert(output.end(), record.begin(), record.end());
|
|
}
|
|
|
|
for (CRenderObject* object : this->scene->unknown_0020) {
|
|
CSkill* skill = static_cast<CSkill*>(object);
|
|
SkillEntryPacket packet;
|
|
packet.packetType = 0x11F;
|
|
packet.aid = skill->skillAid;
|
|
packet.creatorAid = static_cast<std::uint32_t>(skill->unknown_0410);
|
|
packet.job = static_cast<unsigned char>(skill->GetEffectiveJob(-1));
|
|
packet.isVisible = 1;
|
|
|
|
const C3dAttr* terrain = this->scene->terrain;
|
|
const float column = static_cast<float>(std::floor(static_cast<float>(terrain->width / 2) + skill->render.position.x / static_cast<float>(terrain->cellSize)));
|
|
const float row = static_cast<float>(std::floor(static_cast<float>(terrain->height / 2) + skill->render.position.z / static_cast<float>(terrain->cellSize)));
|
|
packet.x = static_cast<std::int16_t>(static_cast<int>(column));
|
|
packet.y = static_cast<std::int16_t>(static_cast<int>(row));
|
|
|
|
const auto record = BuildReplayTaggedRecord(0xCD, &packet, sizeof(packet));
|
|
output.insert(output.end(), record.begin(), record.end());
|
|
}
|
|
|
|
{
|
|
const auto record = BuildReplayTaggedRecord(17001, nullptr, 0);
|
|
output.insert(output.end(), record.begin(), record.end());
|
|
}
|
|
return output;
|
|
}
|
|
|
|
// OFFSET: 0x00CEBBB0
|
|
// FUNCTION: fn_21353
|
|
unsigned CGameMode::sub_CEBBB0(const std::vector<unsigned char>& data) {
|
|
if (data.empty()) {
|
|
return 0xFFFFFFFFu;
|
|
}
|
|
|
|
GameModeChunkHeader header = {};
|
|
std::vector<unsigned char> record;
|
|
unsigned offset = 6;
|
|
std::uint32_t guildId = 0;
|
|
header = *reinterpret_cast<const GameModeChunkHeader*>(data.data());
|
|
if (header.type == 13000) {
|
|
while (offset < data.size()) {
|
|
header = {};
|
|
header = *reinterpret_cast<const GameModeChunkHeader*>(data.data() + offset);
|
|
offset += 6;
|
|
|
|
if (static_cast<int>(header.size) > 0) {
|
|
record.resize(header.size);
|
|
}
|
|
|
|
switch (header.type) {
|
|
case 13001:
|
|
goto finished;
|
|
case 13002:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->SaveEmblemFile(record);
|
|
break;
|
|
case 13003:
|
|
std::memcpy(record.data(), data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->nameCard.Load(reinterpret_cast<const std::vector<char>&>(record));
|
|
break;
|
|
case 13004:
|
|
std::memcpy(&guildId, data.data() + offset, header.size);
|
|
offset += header.size;
|
|
break;
|
|
case 13005: {
|
|
int emblemVersion = 0;
|
|
std::memcpy(&emblemVersion, data.data() + offset, header.size);
|
|
offset += header.size;
|
|
this->scene->player->Slot49(guildId, emblemVersion);
|
|
g_guildInfo.m_guildId = guildId;
|
|
break;
|
|
}
|
|
default:
|
|
offset += header.size;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
offset = 0xFFFFFFFFu;
|
|
}
|
|
|
|
finished:
|
|
return offset;
|
|
}
|
|
|
|
#include "Contents/Actors/Item.h"
|
|
|
|
// OFFSET: 0x00CE93E0
|
|
// FUNCTION: fn_21347
|
|
std::vector<unsigned char> CGameMode::SaveNameCardState() {
|
|
std::vector<unsigned char> data;
|
|
|
|
{
|
|
std::vector<unsigned char> chunk(sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 13000;
|
|
header->size = 0;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
std::vector<char> buffer;
|
|
std::vector<std::string> names;
|
|
if (static_cast<int>(this->nameCard.Save(buffer)) > 0) {
|
|
std::vector<unsigned char> chunk(buffer.size() + sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 13003;
|
|
header->size = buffer.size();
|
|
if (buffer.size() != 0) {
|
|
std::memcpy(chunk.data() + sizeof(GameModeChunkHeader), buffer.data(), buffer.size());
|
|
}
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
{
|
|
const int emblemVersion = g_guildMgr->GetEmblemVersion(this->scene->player->Slot50());
|
|
if (this->AppendGuildEmblem(buffer, names, this->scene->player->Slot50(), emblemVersion)) {
|
|
std::vector<unsigned char> chunk(buffer.size() + sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 13002;
|
|
header->size = buffer.size();
|
|
if (buffer.size() != 0) {
|
|
std::memcpy(chunk.data() + sizeof(GameModeChunkHeader), buffer.data(), buffer.size());
|
|
}
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
}
|
|
|
|
{
|
|
const int guildId = this->scene->player->Slot50();
|
|
std::vector<unsigned char> chunk(sizeof(GameModeStoredValue));
|
|
auto* record = reinterpret_cast<GameModeStoredValue*>(chunk.data());
|
|
record->header.type = 13004;
|
|
record->header.size = sizeof(int);
|
|
record->value = guildId;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
{
|
|
const int emblemVersion = g_guildMgr->GetEmblemVersion(this->scene->player->Slot50());
|
|
std::vector<unsigned char> chunk(sizeof(GameModeStoredValue));
|
|
auto* record = reinterpret_cast<GameModeStoredValue*>(chunk.data());
|
|
record->header.type = 13005;
|
|
record->header.size = sizeof(int);
|
|
record->value = emblemVersion;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
for (CRenderObject* object : this->scene->actors) {
|
|
CGameActor* actor = static_cast<CGameActor*>(object);
|
|
const int emblemVersion = g_guildMgr->GetEmblemVersion(actor->Slot50());
|
|
if (this->AppendGuildEmblem(buffer, names, actor->Slot50(), emblemVersion)) {
|
|
std::vector<unsigned char> chunk(buffer.size() + sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 13002;
|
|
header->size = buffer.size();
|
|
if (buffer.size() != 0) {
|
|
std::memcpy(chunk.data() + sizeof(GameModeChunkHeader), buffer.data(), buffer.size());
|
|
}
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
}
|
|
|
|
{
|
|
std::vector<unsigned char> chunk(sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 13001;
|
|
header->size = 0;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
#include "UI/Chat/UIChatRoomTitle.h"
|
|
#include "UI/Shop/UIMerchantShopTitle.h"
|
|
#include "UI/Text/UIStaticText.h"
|
|
|
|
#pragma pack(push, 1)
|
|
struct ChatRoomEntryPacket {
|
|
/* 0000 */ std::uint16_t packetType;
|
|
/* 0002 */ std::uint16_t packetLength;
|
|
/* 0004 */ std::uint32_t aid;
|
|
/* 0008 */ std::uint32_t roomId;
|
|
/* 000C */ std::uint16_t maxCount;
|
|
/* 000E */ std::uint16_t curCount;
|
|
/* 0010 */ unsigned char type;
|
|
};
|
|
|
|
struct ShopEntryPacket {
|
|
/* 0000 */ std::uint16_t packetType;
|
|
/* 0002 */ std::uint32_t aid;
|
|
/* 0006 */ char name[0x50];
|
|
};
|
|
|
|
struct ProgressPacket {
|
|
/* 0000 */ std::uint16_t packetType;
|
|
/* 0002 */ std::uint32_t color;
|
|
/* 0006 */ std::uint32_t seconds;
|
|
};
|
|
|
|
struct GameModeStoredRecord0191 {
|
|
/* 0000 */ std::uint16_t value0000;
|
|
/* 0002 */ std::uint32_t aid;
|
|
/* 0006 */ std::uint16_t value0006;
|
|
/* 0008 */ int value0008;
|
|
/* 000C */ int value000C;
|
|
/* 0010 */ int count;
|
|
/* 0014 */ int value0014;
|
|
/* 0018 */ int value0018;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(sizeof(ChatRoomEntryPacket) == 0x11);
|
|
static_assert(sizeof(ShopEntryPacket) == 0x56);
|
|
static_assert(sizeof(ProgressPacket) == 0xA);
|
|
static_assert(sizeof(GameModeStoredRecord0191) == 0x1C);
|
|
static_assert(sizeof(GameModeStoredRecord00DA) == 0x3F);
|
|
|
|
// OFFSET: 0x00CEA510
|
|
// FUNCTION: fn_21350
|
|
std::vector<unsigned char> CGameMode::SaveActorStates() {
|
|
std::vector<unsigned char> data;
|
|
|
|
{
|
|
std::vector<unsigned char> chunk(sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 10000;
|
|
header->size = 0;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
std::vector<unsigned char> scratch;
|
|
for (std::list<CRenderObject*>::iterator it = this->scene->actors.begin(); it != this->scene->actors.end(); ++it) {
|
|
CGameActor* actor = static_cast<CGameActor*>(*it);
|
|
CPc* pc = static_cast<CPc*>(actor);
|
|
|
|
if (actor->unknown_03E0Low == 0) {
|
|
if (actor->render.unknown_0070 == 1) {
|
|
std::vector<char> entry = this->BuildActorEntryPacket(actor, 0x9FD);
|
|
std::vector<unsigned char> chunk(entry.size() + sizeof(GameModeChunkHeader), 0);
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 0xD6;
|
|
header->size = entry.size();
|
|
if (entry.size() != 0) {
|
|
std::memcpy(chunk.data() + sizeof(GameModeChunkHeader), entry.data(), entry.size());
|
|
}
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
} else {
|
|
std::vector<char> entry = this->BuildActorEntryPacket(actor, 0x9FF);
|
|
std::vector<unsigned char> chunk(entry.size() + sizeof(GameModeChunkHeader), 0);
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 0xD9;
|
|
header->size = entry.size();
|
|
if (entry.size() != 0) {
|
|
std::memcpy(chunk.data() + sizeof(GameModeChunkHeader), entry.data(), entry.size());
|
|
}
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
}
|
|
|
|
UIChatRoomTitle* room = reinterpret_cast<UIChatRoomTitle*>(actor->unknown_0264[1]);
|
|
if (room != nullptr) {
|
|
scratch.resize(sizeof(ChatRoomEntryPacket), 0);
|
|
auto* packet = reinterpret_cast<ChatRoomEntryPacket*>(scratch.data());
|
|
packet->type = 0xD7;
|
|
packet->packetLength = static_cast<std::uint16_t>(room->title.size() + sizeof(ChatRoomEntryPacket));
|
|
packet->aid = actor->render.accountId;
|
|
packet->roomId = room->roomId;
|
|
packet->maxCount = static_cast<std::uint16_t>(room->memberLimit);
|
|
packet->curCount = static_cast<std::uint16_t>(room->memberCount);
|
|
packet->type = static_cast<unsigned char>(room->roomType);
|
|
scratch.insert(scratch.end(), room->title.begin(), room->title.end());
|
|
|
|
std::vector<unsigned char> chunk(scratch.size() + sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 0xC9;
|
|
header->size = scratch.size();
|
|
if (scratch.size() != 0) {
|
|
std::memcpy(chunk.data() + sizeof(GameModeChunkHeader), scratch.data(), scratch.size());
|
|
}
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
if (actor->unknown_03E0Low == 1) {
|
|
std::vector<unsigned char> record;
|
|
record.resize(sizeof(GameModeStoredRecord00DA), 0);
|
|
auto* stored = reinterpret_cast<GameModeStoredRecord00DA*>(record.data());
|
|
stored->value0002 = actor->render.accountId;
|
|
stored->value0006 = actor->GetEffectiveJob(-1);
|
|
stored->value000E = static_cast<unsigned char>(actor->unknown_0260);
|
|
stored->value000A = static_cast<std::uint16_t>(actor->unknown_0158[5]);
|
|
stored->value000C = static_cast<std::uint16_t>(*reinterpret_cast<const int*>(actor->unknown_0170));
|
|
stored->value000F = static_cast<std::uint16_t>(pc->unknown_0440);
|
|
const std::int64_t value = actor->Slot35();
|
|
stored->value0011 = static_cast<int>(value);
|
|
stored->value0015 = static_cast<int>(value >> 32);
|
|
stored->value0019 = static_cast<std::uint16_t>(pc->unknown_0450);
|
|
stored->value001B = static_cast<std::uint16_t>(pc->unknown_0454);
|
|
stored->value001D = static_cast<std::uint16_t>(pc->unknown_0458);
|
|
stored->value001F = static_cast<std::uint16_t>(pc->unknown_0444);
|
|
stored->value0021 = static_cast<std::uint16_t>(actor->render.unknown_0048);
|
|
stored->value0023 = static_cast<std::uint16_t>(pc->unknown_049C);
|
|
stored->value003D = static_cast<std::uint16_t>(actor->Slot46());
|
|
{
|
|
std::string name = this->nameCard.Name(actor->render.accountId);
|
|
std::memcpy(stored->text, name.c_str(), sizeof(stored->text));
|
|
}
|
|
|
|
std::vector<unsigned char> chunk(record.size() + sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 0xDA;
|
|
header->size = record.size();
|
|
if (record.size() != 0) {
|
|
std::memcpy(chunk.data() + sizeof(GameModeChunkHeader), record.data(), record.size());
|
|
}
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
UIMerchantShopTitle* shop = reinterpret_cast<UIMerchantShopTitle*>(actor->unknown_0264[2]);
|
|
if (shop != nullptr) {
|
|
scratch.resize(sizeof(ShopEntryPacket), 0);
|
|
auto* packet = reinterpret_cast<ShopEntryPacket*>(scratch.data());
|
|
packet->packetType = 0x131;
|
|
packet->aid = actor->render.accountId;
|
|
std::memcpy(packet->name, shop->label->tooltip.c_str(), sizeof(packet->name));
|
|
|
|
std::vector<unsigned char> chunk(scratch.size() + sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 0xCA;
|
|
header->size = scratch.size();
|
|
if (scratch.size() != 0) {
|
|
std::memcpy(chunk.data() + sizeof(GameModeChunkHeader), scratch.data(), scratch.size());
|
|
}
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
if (actor->unknown_0264[3] != 0) {
|
|
scratch.resize(sizeof(ProgressPacket), 0);
|
|
auto* packet = reinterpret_cast<ProgressPacket*>(scratch.data());
|
|
packet->color = 0;
|
|
packet->packetType = 0x2F0;
|
|
packet->seconds = (actor->unknown_0280 - actor->unknown_0284) / 1000;
|
|
|
|
std::vector<unsigned char> chunk(scratch.size() + sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 0xCB;
|
|
header->size = scratch.size();
|
|
if (scratch.size() != 0) {
|
|
std::memcpy(chunk.data() + sizeof(GameModeChunkHeader), scratch.data(), scratch.size());
|
|
}
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
UIMerchantShopTitle* buyingShop = reinterpret_cast<UIMerchantShopTitle*>(actor->unknown_0264[4]);
|
|
if (buyingShop != nullptr) {
|
|
scratch.resize(sizeof(ShopEntryPacket), 0);
|
|
auto* packet = reinterpret_cast<ShopEntryPacket*>(scratch.data());
|
|
packet->packetType = 0x814;
|
|
packet->aid = actor->render.accountId;
|
|
std::memcpy(packet->name, buyingShop->label->tooltip.c_str(), sizeof(packet->name));
|
|
|
|
std::vector<unsigned char> chunk(scratch.size() + sizeof(GameModeChunkHeader), 0);
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 0xCC;
|
|
header->size = scratch.size();
|
|
if (scratch.size() != 0) {
|
|
std::memcpy(chunk.data() + sizeof(GameModeChunkHeader), scratch.data(), scratch.size());
|
|
}
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
const int count = actor->Slot56();
|
|
if (count > 0) {
|
|
GameModeStoredRecord0191 record;
|
|
record.value000C = 9999;
|
|
record.value0000 = 0;
|
|
record.count = count;
|
|
record.value0014 = 0;
|
|
record.value0008 = 9999;
|
|
record.aid = actor->render.accountId;
|
|
record.value0006 = 0x47D;
|
|
record.value0018 = 0;
|
|
|
|
std::vector<unsigned char> chunk(sizeof(GameModeChunkHeader) + sizeof(record), 0);
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 0x191;
|
|
header->size = sizeof(record);
|
|
*reinterpret_cast<GameModeStoredRecord0191*>(chunk.data() + sizeof(GameModeChunkHeader)) = record;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
}
|
|
|
|
{
|
|
std::vector<unsigned char> chunk(sizeof(GameModeChunkHeader), 0);
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 10001;
|
|
header->size = 0;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
#pragma pack(push, 1)
|
|
struct ItemEntryPacket {
|
|
/* 0000 */ std::int16_t packetType;
|
|
/* 0002 */ std::uint32_t aid;
|
|
/* 0006 */ std::uint32_t itemId;
|
|
/* 000A */ unsigned char identified;
|
|
/* 000B */ std::int16_t x;
|
|
/* 000D */ std::int16_t y;
|
|
/* 000F */ std::int16_t count;
|
|
/* 0011 */ unsigned char subX;
|
|
/* 0012 */ unsigned char subY;
|
|
};
|
|
|
|
struct GameModeStoredItemEntry {
|
|
/* 0000 */ GameModeChunkHeader header;
|
|
/* 0006 */ ItemEntryPacket packet;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(sizeof(ItemEntryPacket) == 0x13);
|
|
static_assert(sizeof(GameModeStoredItemEntry) == 0x19);
|
|
|
|
#include "Contents/Items/ItemNaming.h"
|
|
#include "UI/Navigation/UINavigationV4Wnd.h"
|
|
#include "UI/Window/UINavigationWnd.h"
|
|
#include "Contents/Effects/EffectActor.h"
|
|
|
|
#pragma pack(push, 1)
|
|
struct GameModeUiMessage {
|
|
/* 0000 */ std::uint16_t unknown_0000;
|
|
/* 0002 */ std::uint16_t type;
|
|
/* 0004 */ std::uint16_t length;
|
|
/* 0006 */ int values[6];
|
|
/* 001E */ char text[1];
|
|
};
|
|
|
|
struct GameModeUiWhisperMessage {
|
|
/* 0000 */ std::uint16_t unknown_0000;
|
|
/* 0002 */ std::uint16_t type;
|
|
/* 0004 */ std::uint16_t length;
|
|
/* 0006 */ char target[0x19];
|
|
/* 001F */ char text[1];
|
|
};
|
|
|
|
struct GameModeUiKindTextMessage {
|
|
/* 0000 */ std::uint16_t unknown_0000;
|
|
/* 0002 */ std::uint16_t type;
|
|
/* 0004 */ std::uint16_t length;
|
|
/* 0006 */ int kind;
|
|
/* 000A */ int unknown_000A;
|
|
/* 000E */ char text[1];
|
|
};
|
|
|
|
struct GameModeUiNavigationMessage {
|
|
/* 0000 */ std::uint16_t unknown_0000;
|
|
/* 0002 */ std::uint16_t type;
|
|
/* 0004 */ std::uint16_t length;
|
|
/* 0006 */ char name[0x1E];
|
|
/* 0024 */ int kind;
|
|
/* 0028 */ unsigned char mode;
|
|
/* 0029 */ unsigned char flag;
|
|
/* 002A */ int x;
|
|
/* 002E */ int y;
|
|
/* 0032 */ int id;
|
|
};
|
|
|
|
struct GameModeUiDestinationMessage {
|
|
/* 0000 */ std::uint16_t unknown_0000;
|
|
/* 0002 */ std::uint16_t type;
|
|
/* 0004 */ std::uint16_t length;
|
|
/* 0006 */ char mapName[0x1E];
|
|
/* 0024 */ int x;
|
|
/* 0028 */ int y;
|
|
};
|
|
|
|
struct GameModeUiDragMessage {
|
|
/* 0000 */ std::uint16_t unknown_0000;
|
|
/* 0002 */ std::uint16_t type;
|
|
/* 0004 */ std::uint16_t length;
|
|
/* 0006 */ int windowId;
|
|
/* 000A */ int x;
|
|
/* 000E */ int y;
|
|
/* 0012 */ int source;
|
|
/* 0016 */ std::uint32_t id;
|
|
/* 001A */ std::uint32_t unknown_001A;
|
|
/* 001E */ std::uint32_t unknown_001E;
|
|
/* 0022 */ int quantity;
|
|
/* 0026 */ int slot;
|
|
/* 002A */ std::uint32_t itemType;
|
|
/* 002E */ std::uint32_t refine;
|
|
/* 0032 */ unsigned char identified;
|
|
/* 0033 */ char resource[100];
|
|
/* 0097 */ char name[100];
|
|
/* 00FB */ char skillName[100];
|
|
/* 015F */ int skillLevel;
|
|
/* 0163 */ unsigned char cards[16];
|
|
/* 0173 */ unsigned char skill;
|
|
/* 0174 */ int optionCount;
|
|
/* 0178 */ unsigned char options[25];
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(offsetof(GameModeUiMessage, text) == 0x1E);
|
|
static_assert(offsetof(GameModeUiWhisperMessage, text) == 0x1F);
|
|
static_assert(offsetof(GameModeUiKindTextMessage, text) == 0x0E);
|
|
static_assert(offsetof(GameModeUiNavigationMessage, id) == 0x32);
|
|
static_assert(offsetof(GameModeUiDestinationMessage, y) == 0x28);
|
|
static_assert(offsetof(GameModeUiDragMessage, options) == 0x178);
|
|
|
|
// OFFSET: 0x00CCF680
|
|
// FUNCTION: fn_21244
|
|
void CGameMode::ProcessUiMessage(unsigned char* message) {
|
|
GameModeUiMessage* values = reinterpret_cast<GameModeUiMessage*>(message);
|
|
|
|
switch (values->type) {
|
|
case 900: {
|
|
if (values->values[1] == 0xB8) {
|
|
if (values->values[0] == 0x29) {
|
|
values->values[1] = 0xB9;
|
|
} else if (values->values[0] == 0xAE) {
|
|
break;
|
|
}
|
|
}
|
|
UIWindow* window = g_windowMgr.LookupWindow(values->values[0]);
|
|
if (window != nullptr) {
|
|
window->SendMsg(nullptr, 6, values->values[1], values->values[2], values->values[3], values->values[4]);
|
|
}
|
|
break;
|
|
}
|
|
case 901:
|
|
this->ReceiveUiDragMessage(message);
|
|
break;
|
|
case 902: {
|
|
UIWindow* window = g_windowMgr.LookupWindow(values->values[0]);
|
|
if (window != nullptr) {
|
|
window->RestoreEditTexts(reinterpret_cast<const unsigned char*>(&values->values[1]));
|
|
}
|
|
break;
|
|
}
|
|
case 903:
|
|
*reinterpret_cast<int*>(&this->unknown_0100[0x10]) = values->values[0];
|
|
break;
|
|
case 904: {
|
|
char buffer[200];
|
|
std::memset(buffer, 0, sizeof(buffer));
|
|
std::memcpy(buffer, values->text, values->values[0]);
|
|
this->unknown_03C8 = buffer;
|
|
std::memset(buffer, 0, sizeof(buffer));
|
|
std::memcpy(buffer, values->text + values->values[0], values->values[1]);
|
|
this->unknown_03E0 = buffer;
|
|
this->unknown_03F8 = values->values[2];
|
|
this->unknown_03FC = values->values[3];
|
|
this->unknown_0400 = values->values[4];
|
|
this->unknown_0404 = values->values[5];
|
|
break;
|
|
}
|
|
case 905:
|
|
this->SendMsg(values->values[0], values->values[1], values->values[2], values->values[3], 0);
|
|
this->SendMsg(0x47, 0, 0, 0, 0);
|
|
break;
|
|
case 906: {
|
|
const GameModeUiWhisperMessage* whisper = reinterpret_cast<const GameModeUiWhisperMessage*>(message);
|
|
this->unknown_022C = whisper->target;
|
|
this->unknown_0214 = whisper->text;
|
|
break;
|
|
}
|
|
case 907: {
|
|
const GameModeUiKindTextMessage* text = reinterpret_cast<const GameModeUiKindTextMessage*>(message);
|
|
if (text->kind == 0x29) {
|
|
g_session.unknown_550C = text->text;
|
|
} else if (text->kind == 0xAE) {
|
|
g_session.unknown_550C = text->text;
|
|
}
|
|
break;
|
|
}
|
|
case 908:
|
|
if (values->values[0] == 0xCB && g_windowMgr.window_4F174 != nullptr) {
|
|
g_windowMgr.window_4F174->SendMsg(nullptr, values->values[1], values->values[2], reinterpret_cast<std::intptr_t>(&values->values[3]), 0, 0);
|
|
}
|
|
break;
|
|
case 909:
|
|
g_windowMgr.EnsureWindow(values->values[0]);
|
|
break;
|
|
case 910: {
|
|
const GameModeUiNavigationMessage* navigation = reinterpret_cast<const GameModeUiNavigationMessage*>(message);
|
|
g_navigationManager.sub_B99030(
|
|
std::string(navigation->name), navigation->kind, navigation->mode, navigation->flag != 0, navigation->x, navigation->y, navigation->id
|
|
);
|
|
break;
|
|
}
|
|
case 911: {
|
|
std::vector<char> states(values->length - 6, 0);
|
|
std::memcpy(&states[0], values->values, states.size());
|
|
g_windowMgr.CloseWindow(0x1A);
|
|
g_navigationManager.LoadStates(states);
|
|
if (g_windowMgr.window_4F174 != nullptr) {
|
|
static_cast<UINavigationV4Wnd*>(g_windowMgr.window_4F174)->FillRouteGroups();
|
|
}
|
|
break;
|
|
}
|
|
case 912: {
|
|
const GameModeUiDestinationMessage* destination = reinterpret_cast<const GameModeUiDestinationMessage*>(message);
|
|
g_navigationManager.SetDestinationMap(std::string(destination->mapName), destination->x, destination->y);
|
|
break;
|
|
}
|
|
case 913: {
|
|
if (values->values[1] == 0xB8) {
|
|
if (values->values[0] == 0x29) {
|
|
values->values[1] = 0xB9;
|
|
} else if (values->values[0] == 0xAE) {
|
|
break;
|
|
}
|
|
}
|
|
UIWindow* window = g_windowMgr.LookupWindow(values->values[0]);
|
|
if (window != nullptr) {
|
|
window->SendMsg(nullptr, values->values[5], values->values[1], values->values[2], values->values[3], values->values[4]);
|
|
}
|
|
break;
|
|
}
|
|
case 914:
|
|
g_windowMgr.CloseWindowExcept251(values->values[0]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CE8400
|
|
// FUNCTION: fn_21341
|
|
void CGameMode::ReceiveUiDragMessage(const unsigned char* message) {
|
|
const GameModeUiDragMessage* packet = reinterpret_cast<const GameModeUiDragMessage*>(message);
|
|
|
|
ModeDragState drag;
|
|
drag.source = packet->source;
|
|
drag.id = packet->id;
|
|
drag.unknown_0310 = packet->unknown_001A;
|
|
drag.unknown_0314 = packet->unknown_001E;
|
|
drag.quantity = packet->quantity;
|
|
drag.slot = packet->slot;
|
|
drag.type = packet->itemType;
|
|
drag.refine = packet->refine;
|
|
drag.identified = packet->identified;
|
|
drag.resource = packet->resource;
|
|
drag.name = packet->name;
|
|
drag.skillName = packet->skillName;
|
|
drag.skillLevel = packet->skillLevel;
|
|
std::memcpy(drag.cards, packet->cards, sizeof(drag.cards));
|
|
drag.skill = packet->skill;
|
|
drag.optionCount = packet->optionCount;
|
|
if (drag.optionCount > 5) {
|
|
drag.optionCount = 0;
|
|
}
|
|
for (int index = 0; index < drag.optionCount; ++index) {
|
|
std::memcpy(&drag.options[index * 5], &packet->options[index * 5], 5);
|
|
}
|
|
|
|
UIWindow* window = g_windowMgr.LookupWindow(packet->windowId);
|
|
this->drag = drag;
|
|
|
|
if (this->drag.quantity == 1) {
|
|
const int kind = packet->windowId;
|
|
if (kind == 0x17 || kind == 0x2C) {
|
|
if (packet->itemType <= 3 || packet->itemType == 7) {
|
|
this->unknown_05EC[0] = this->IsAllowedPair(kind, packet->source);
|
|
}
|
|
} else if (kind == 0x16) {
|
|
if (packet->itemType <= 3 || packet->itemType == 7) {
|
|
this->unknown_05EC[0] = this->IsAllowedPair(0x16, packet->source);
|
|
}
|
|
}
|
|
} else {
|
|
this->unknown_05EC[0] = this->IsAllowedPair(packet->windowId, packet->source);
|
|
}
|
|
|
|
if (window != nullptr) {
|
|
window->Slot10(packet->x, packet->y, reinterpret_cast<std::intptr_t>(&drag));
|
|
}
|
|
|
|
const int kind = packet->windowId;
|
|
if (kind == 0x24 || kind == 0x9F) {
|
|
this->unknown_05EC[0] = 0;
|
|
} else if (this->unknown_05EC[0] == 1 && g_windowMgr.window_01EC != nullptr) {
|
|
if (drag.type == 6) {
|
|
const ItemCardName card = FindItemCardName(std::atoi(drag.name.c_str()));
|
|
g_windowMgr.window_01EC->SendMsg(nullptr, 0x1D, 0, reinterpret_cast<std::intptr_t>(card.name), 0, 0);
|
|
} else {
|
|
const ITEM_DESC description = FindItemDescription(std::atoi(drag.name.c_str()));
|
|
g_windowMgr.window_01EC->SendMsg(nullptr, 0x1D, 0, reinterpret_cast<std::intptr_t>(description.identifiedName), 0, 0);
|
|
}
|
|
}
|
|
|
|
this->SendMsg(0x12, 0, 0, 0, 0);
|
|
}
|
|
|
|
// OFFSET: 0x00CDBEB0
|
|
|
|
// OFFSET: 0x00CEA0C0
|
|
// FUNCTION: fn_21349
|
|
std::vector<unsigned char> CGameMode::SaveGroundItems() {
|
|
std::vector<unsigned char> data;
|
|
|
|
{
|
|
std::vector<unsigned char> chunk(sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 15000;
|
|
header->size = 0;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
for (CRenderObject* object : this->scene->unknown_0018) {
|
|
CItem* item = static_cast<CItem*>(object);
|
|
ItemEntryPacket packet;
|
|
packet.packetType = 0x9D;
|
|
packet.aid = item->itemAid;
|
|
packet.itemId = item->itemId;
|
|
packet.identified = item->identified;
|
|
|
|
int column;
|
|
int row;
|
|
int subColumn;
|
|
int subRow;
|
|
this->WorldSubcell(item->render.position.x, item->render.position.z, column, row, subColumn, subRow);
|
|
packet.x = static_cast<std::int16_t>(column);
|
|
packet.y = static_cast<std::int16_t>(row);
|
|
packet.subX = static_cast<unsigned char>(subColumn);
|
|
|
|
const int length = static_cast<int>(item->name.size());
|
|
std::size_t digits = 0;
|
|
for (int index = length - 4; index >= 0; --index) {
|
|
if (item->name[index] == ' ') {
|
|
break;
|
|
}
|
|
++digits;
|
|
}
|
|
char text[6] = {};
|
|
std::memcpy(text, item->name.c_str() + (length - 3) - digits, digits);
|
|
packet.count = static_cast<std::int16_t>(std::atoi(text));
|
|
|
|
std::vector<unsigned char> chunk(sizeof(GameModeStoredItemEntry));
|
|
auto* record = reinterpret_cast<GameModeStoredItemEntry*>(chunk.data());
|
|
record->header.type = 0xCF;
|
|
record->header.size = sizeof(ItemEntryPacket);
|
|
packet.subY = static_cast<unsigned char>(subRow);
|
|
record->packet = packet;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
{
|
|
std::vector<unsigned char> chunk(sizeof(GameModeChunkHeader));
|
|
auto* header = reinterpret_cast<GameModeChunkHeader*>(chunk.data());
|
|
header->type = 15001;
|
|
header->size = 0;
|
|
data.insert(data.end(), chunk.begin(), chunk.end());
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
// OFFSET: 0x00CEFFC0
|
|
// FUNCTION: fn_21409
|
|
UIBroadcastBalloon* CGameMode::EnsureBroadcastBalloon() {
|
|
if (!this->broadcastBalloon) {
|
|
this->broadcastBalloon = new UIBroadcastBalloon();
|
|
this->broadcastBalloon->SetSize(g_renderer->viewport.width, 50);
|
|
this->broadcastBalloon->Move(0, 51);
|
|
g_windowMgr.AddRenderedFront(this->broadcastBalloon);
|
|
}
|
|
return this->broadcastBalloon;
|
|
}
|
|
|
|
// OFFSET: 0x00CDBB10
|
|
// FUNCTION: fn_21311
|
|
void CGameMode::EnsureNameBalloon(UINameBalloonText*& balloon) {
|
|
if (balloon) {
|
|
return;
|
|
}
|
|
|
|
g_serviceOptions.Get(0x5C);
|
|
balloon = new UINameBalloonText();
|
|
balloon->SetSize(8, 8);
|
|
g_windowMgr.AddRenderedFront(balloon);
|
|
}
|
|
|
|
// OFFSET: 0x00CDD240
|
|
// FUNCTION: fn_21315
|
|
void __stdcall OpenWordDisplay(CGameActor* actor) {
|
|
if (actor->unknown_018C || IsAdminAccount(actor->render.accountId)) {
|
|
return;
|
|
}
|
|
|
|
if (!IsAdminAccount(g_session.m_aid)) {
|
|
if (StateFlag02(actor->Slot13()) || StateFlag01(actor->Slot13()) || StateFlag06(actor->Slot13())) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
UIWordDisplayWnd* window = new UIWordDisplayWnd();
|
|
window->SendMsg(nullptr, 34, actor->render.accountId, 0, 0, 0);
|
|
g_windowMgr.AddRendered(window);
|
|
actor->unknown_018C = reinterpret_cast<int>(window);
|
|
}
|
|
|
|
// OFFSET: 0x00CFF070
|
|
// FUNCTION: fn_21435
|
|
void CGameMode::ShowNoticeBalloon(const std::vector<std::string>* lines) {
|
|
if (!lines || lines->empty()) {
|
|
return;
|
|
}
|
|
|
|
UIBroadcastBalloon* balloon = this->noticeBalloon;
|
|
if (!balloon) {
|
|
this->noticeBalloon = new UIBroadcastBalloon();
|
|
this->noticeBalloon->SetSize(g_renderer->viewport.width, 50);
|
|
this->noticeBalloon->Move(0, 130 * g_renderer->viewport.height / 480);
|
|
g_windowMgr.AddRenderedFront(this->noticeBalloon);
|
|
balloon = this->noticeBalloon;
|
|
if (!balloon) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
BroadcastBalloonMessage message{{}, {}, std::chrono::seconds(20), 12, 0x40000000, 0, 0};
|
|
message.start = std::chrono::system_clock::now();
|
|
for (std::vector<std::string>::const_iterator it = lines->begin(); it != lines->end(); ++it) {
|
|
message.lines.push_back(BroadcastBalloonLine{*it, 0xFFFF, 0});
|
|
}
|
|
balloon->AddMessage(2, message);
|
|
}
|
|
|
|
#pragma pack(push, 1)
|
|
struct ZoneEnterPacket {
|
|
/* 0000 */ std::uint16_t packetType;
|
|
/* 0002 */ std::uint32_t aid;
|
|
/* 0006 */ std::uint32_t gid;
|
|
/* 000A */ int authCode;
|
|
/* 000E */ unsigned char unknown_000E[4];
|
|
/* 0012 */ std::uint32_t clientTime;
|
|
/* 0016 */ unsigned char sex;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(sizeof(ZoneEnterPacket) == 0x17);
|
|
static_assert(offsetof(ZoneEnterPacket, clientTime) == 0x12);
|
|
static_assert(offsetof(ZoneEnterPacket, sex) == 0x16);
|
|
|
|
// OFFSET: 0x00D06CB0
|
|
// FUNCTION: fn_21579
|
|
void CGameMode::ChangeZoneServer(std::string mapName, int x, int y, int ip, int port, std::string host) {
|
|
g_session.m_startTimeTicks = std::chrono::system_clock::now().time_since_epoch().count();
|
|
g_session.m_loginTimeTicks = std::chrono::system_clock::now().time_since_epoch().count();
|
|
g_session.SetOption(20, 1, 0);
|
|
this->nameCard.Clear();
|
|
g_session.ClearEntryList5BD4();
|
|
g_session.ClearShortcutSlots();
|
|
g_session.ClearSecondaryShortcutSlots();
|
|
g_session.unknown_6184 = 0;
|
|
g_session.ResetInventoryItems();
|
|
g_session.ClearPartyMembers();
|
|
|
|
std::string name = mapName;
|
|
name.resize(name.size() - 4);
|
|
g_session.SetNavigationPlayerMap(name.c_str());
|
|
g_session.m_playerX = x;
|
|
g_session.m_playerY = y;
|
|
|
|
in_addr address;
|
|
address.s_addr = static_cast<ULONG>(ip);
|
|
StringFormat(g_zoneServerIp, sizeof(g_zoneServerIp), static_cast<std::size_t>(-1), inet_ntoa(address));
|
|
g_zoneServerPort = port;
|
|
StringFormat(g_zoneServerHost, sizeof(g_zoneServerHost), static_cast<std::size_t>(-1), "%s", host.c_str());
|
|
GetRagConnection().Close();
|
|
g_activeSkillEffects.clear();
|
|
|
|
this->unknown_0244 = 1;
|
|
this->unknown_0248 = timeGetTime();
|
|
this->scene->player->SendMsg(nullptr, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
if (g_screenShakeDuration > 0) {
|
|
g_screenShakeDuration = g_screenShakeMode == 2 ? 10001 : g_screenShakeDuration;
|
|
}
|
|
|
|
if (g_replayAnimationScaling == 0) {
|
|
this->unknown_0018 = GetRagConnection().Connect(*reinterpret_cast<const ConnectionEndpoint*>(g_zoneServerIp));
|
|
if (!this->unknown_0018) {
|
|
GetRagConnection().Close();
|
|
if (g_windowMgr.Confirm(LookupMessage(1), 1, true, true, 0, "Message", 280, 120, 0) != 269) {
|
|
this->SendMsg(141, 0, 0, 0, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
g_nProtectGameGuardMgr->IncrementCounter();
|
|
g_packetReassembler->Notify(1);
|
|
GetRagConnection().SendDeadline() = timeGetTime() + 1000;
|
|
|
|
ZoneEnterPacket packet;
|
|
packet.packetType = ID_CZ_ENTER2;
|
|
packet.clientTime = timeGetTime();
|
|
packet.aid = g_session.m_aid;
|
|
packet.gid = g_session.m_gid;
|
|
packet.authCode = reinterpret_cast<const int*>(g_session.unknown_0E9C)[2];
|
|
packet.sex = static_cast<unsigned char>(g_session.SyncUnknown0E98());
|
|
GetRagConnection().Send(reinterpret_cast<const PacketLengths&>(GetRagConnection()).FixedLength(packet.packetType), &packet);
|
|
g_session.SetOption(17, 1, 0);
|
|
GetRagConnection().SetBlock(1);
|
|
}
|
|
|
|
static_cast<UIWaitWnd*>(g_windowMgr.EnsureWindow(6))->SetMessage(LookupMessage(122), 16, 1);
|
|
g_windowMgr.unknown_0474 = 185;
|
|
}
|
|
|
|
// OFFSET: 0x00CE1FA0
|
|
// FUNCTION: fn_21333
|
|
void CGameMode::UpdateBalloons() {
|
|
if (this->nameBalloon) {
|
|
if (*reinterpret_cast<int*>(&this->unknown_02B8[0x0C])) {
|
|
g_windowMgr.Schedule(this->nameBalloon);
|
|
this->nameBalloon = nullptr;
|
|
} else {
|
|
*reinterpret_cast<int*>(&this->unknown_02B8[0x0C]) = 1;
|
|
if (this->balloonActorId == g_session.m_aid) {
|
|
this->PlaceWindowAtActor(this->nameBalloon, reinterpret_cast<CGameActor*>(this->scene->player));
|
|
} else if (CRenderObject* actor = this->scene->GetGameActorByAID(this->balloonActorId)) {
|
|
this->PlaceWindowAtActor(this->nameBalloon, reinterpret_cast<CGameActor*>(actor));
|
|
} else if (CItem* item = this->scene->GetItemByAID(this->balloonActorId)) {
|
|
this->PlaceWindowAtActor(this->nameBalloon, reinterpret_cast<CGameActor*>(item));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this->itemNameBalloon) {
|
|
if (*reinterpret_cast<int*>(&this->unknown_02B8[0x10])) {
|
|
g_windowMgr.Schedule(this->itemNameBalloon);
|
|
this->itemNameBalloon = nullptr;
|
|
} else {
|
|
*reinterpret_cast<int*>(&this->unknown_02B8[0x10]) = 1;
|
|
if (this->balloonActorId == g_session.m_aid) {
|
|
this->PlaceWindowAtActor(this->itemNameBalloon, reinterpret_cast<CGameActor*>(this->scene->player));
|
|
} else if (CRenderObject* actor = this->scene->GetGameActorByAID(this->balloonActorId)) {
|
|
this->PlaceWindowAtActor(this->itemNameBalloon, reinterpret_cast<CGameActor*>(actor));
|
|
} else if (CItem* item = this->scene->GetItemByAID(this->balloonActorId)) {
|
|
this->PlaceWindowAtActor(this->itemNameBalloon, reinterpret_cast<CGameActor*>(item));
|
|
}
|
|
}
|
|
}
|
|
|
|
UIWindow*& skillBalloon = *reinterpret_cast<UIWindow**>(&this->unknown_02B8[0x00]);
|
|
UIWindow*& hintBalloon = *reinterpret_cast<UIWindow**>(&this->unknown_02B8[0x04]);
|
|
int& shownSkill = *reinterpret_cast<int*>(&this->unknown_045C[0x04]);
|
|
if (this->unknown_0408 == nullptr) {
|
|
if (skillBalloon) {
|
|
g_windowMgr.Schedule(skillBalloon);
|
|
skillBalloon = nullptr;
|
|
}
|
|
if (hintBalloon) {
|
|
g_windowMgr.Schedule(hintBalloon);
|
|
hintBalloon = nullptr;
|
|
}
|
|
} else {
|
|
bool created = false;
|
|
if (!skillBalloon) {
|
|
skillBalloon = new UITransBalloonText();
|
|
skillBalloon->SetSize(8, 8);
|
|
g_windowMgr.AddRendered(skillBalloon);
|
|
created = true;
|
|
}
|
|
|
|
if (shownSkill != this->unknown_040C || created == true) {
|
|
std::string text;
|
|
shownSkill = this->unknown_040C;
|
|
switch (shownSkill) {
|
|
case 10000: {
|
|
const std::uint8_t source[] = {0xBC, 0x82, 0x2D, 0x77, 0xD2, 0xDD, 0xC6, 0x1F, 0xB2, 0x8C, 0x33, 0x70, 0xD3, 0xCA, 0xD1, 0x3F};
|
|
thread_local GameModeEncryptedName<sizeof(source), 0x3FA3AFA7035DE3FFULL> name(source);
|
|
text.assign(name.Text());
|
|
break;
|
|
}
|
|
case 20000: {
|
|
const std::uint8_t source[] = {0x09, 0xEB, 0x66, 0x1C, 0x26, 0xAE, 0x07, 0x96, 0x38, 0xF5, 0x71, 0x04, 0x75, 0x86, 0x42, 0xDB};
|
|
thread_local GameModeEncryptedName<sizeof(source), 0xDB27CB557D038759ULL> name(source);
|
|
text = name.Text();
|
|
break;
|
|
}
|
|
case 20001: {
|
|
const std::uint8_t source[] = {0xCF, 0xD8, 0x9B, 0x0E, 0xCE, 0x19, 0xF9, 0x30, 0xEF, 0xC4, 0xBB};
|
|
thread_local GameModeEncryptedName<sizeof(source), 0x51BB39B763BBBD8DULL> name(source);
|
|
text = name.Text();
|
|
break;
|
|
}
|
|
case 40000: {
|
|
const std::uint8_t source[] = {0xAC, 0x4C, 0x27, 0x79, 0xB0, 0xA3, 0x86, 0xA7, 0xA2, 0x42, 0x39, 0x7E, 0xB1, 0xB4, 0x91, 0x87};
|
|
thread_local GameModeEncryptedName<sizeof(source), 0x87E3D1C50D572DEFULL> name(source);
|
|
text = name.Text();
|
|
break;
|
|
}
|
|
default:
|
|
if (g_session.IsState291To303(shownSkill)) {
|
|
const std::uint8_t source[] = {0x3E, 0x4A, 0xC2, 0xE6, 0x2F};
|
|
thread_local GameModeEncryptedName<sizeof(source), 0xB7AFBD2FD9FD7501ULL> name(source);
|
|
text = name.Text();
|
|
} else {
|
|
text = CSkillInfo::DisplayName(*g_session.m_hotkeyScript, shownSkill);
|
|
}
|
|
break;
|
|
}
|
|
|
|
UITransBalloonText* balloon = static_cast<UITransBalloonText*>(skillBalloon);
|
|
balloon->SetText(text.c_str(), 35);
|
|
balloon->Move((g_renderer->viewport.width - 640) / 2 - balloon->geometry.width / 2 + 320, 46 * g_renderer->viewport.height / 480);
|
|
balloon->m_textColor = 0x32FF32;
|
|
balloon->m_outlineColor = 0;
|
|
}
|
|
|
|
if (!hintBalloon) {
|
|
UITransBalloonText* balloon = new UITransBalloonText();
|
|
hintBalloon = balloon;
|
|
balloon->SetSize(8, 8);
|
|
g_windowMgr.AddRendered(hintBalloon);
|
|
static_cast<UITransBalloonText*>(hintBalloon)->SetText(LookupMessage(234), 35);
|
|
hintBalloon->Move((g_renderer->viewport.width - 640) / 2 - hintBalloon->geometry.width / 2 + 320, 400 * g_renderer->viewport.height / 480);
|
|
static_cast<UITransBalloonText*>(hintBalloon)->m_textColor = 0x32FF32;
|
|
static_cast<UITransBalloonText*>(hintBalloon)->m_outlineColor = 0;
|
|
}
|
|
}
|
|
|
|
if (this->itemWindow) {
|
|
CPlayer* player = this->scene->player;
|
|
const int x = player->render.screenX - 30;
|
|
const int y = player->render.screenY;
|
|
const int offset = static_cast<int>(static_cast<float>(12 * g_renderer->viewport.height / 480) * player->render.unknown_005C);
|
|
if (IsScreenShakeActive()) {
|
|
this->itemWindow->Move(x, y - offset);
|
|
} else {
|
|
this->itemWindow->Move(x, offset + y);
|
|
}
|
|
}
|
|
|
|
if (this->unknown_05FC && timeGetTime() > this->unknown_0600 + 10000) {
|
|
g_windowMgr.Schedule(this->unknown_05FC);
|
|
this->unknown_05FC = nullptr;
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CDD7A0
|
|
// FUNCTION: fn_21319
|
|
void CGameMode::End() {
|
|
CSchedule* schedule = g_timeScheduler->FindSchedule(g_session.m_pingLiveSchedule);
|
|
if (schedule) {
|
|
schedule->active = false;
|
|
}
|
|
g_timeScheduler->sub_BA95F0(4);
|
|
this->StopReplayRecording();
|
|
g_soundMgr->EndSamples();
|
|
|
|
if (this->scene) {
|
|
this->scene->OnExitFrame();
|
|
delete this->scene;
|
|
}
|
|
|
|
if (this->camera) {
|
|
this->camera->Slot2();
|
|
delete this->camera;
|
|
}
|
|
|
|
g_actorPickNode.Clear();
|
|
ResourceMgr::Instance().ClearUnused("rsm");
|
|
ResourceMgr::Instance().ClearUnused("rsw");
|
|
ResourceMgr::Instance().ClearUnused("gat");
|
|
ResourceMgr::Instance().ClearExpired();
|
|
g_texMgr.ClearUnused();
|
|
g_renderer->ClearFrame();
|
|
g_renderer->atlas.Clear();
|
|
g_windowMgr.SaveShortcutItems();
|
|
|
|
char subKey[512];
|
|
std::strcpy(subKey, g_subKey);
|
|
std::strcat(subKey, "\\NameBaloon");
|
|
std::strcat(subKey, "\\");
|
|
std::strcat(subKey, g_session.m_serverName.c_str());
|
|
HKEY key;
|
|
DWORD disposition = 0;
|
|
if (RegCreateKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &key, &disposition) == ERROR_SUCCESS) {
|
|
DWORD value = g_serviceOptions.Get(92) != 0;
|
|
RegSetValueExA(key, "POS", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
|
RegCloseKey(key);
|
|
}
|
|
|
|
if (this->unknown_0254) {
|
|
g_outdoorCameraPitch = g_cameraPitch;
|
|
g_outdoorCameraDistance = g_cameraDistance;
|
|
} else {
|
|
g_indoorCameraPitch = g_cameraPitch;
|
|
g_indoorCameraDistance = g_cameraDistance;
|
|
}
|
|
|
|
if (g_session.m_whisperRecord != 0) {
|
|
sub_CCFF10();
|
|
}
|
|
g_effectMgr->Clear();
|
|
g_session.SaveMiniPartyInfo();
|
|
g_session.SetUnknown8134(0);
|
|
}
|
|
|
|
|
|
// OFFSET: 0x00CE8DE0
|
|
// FUNCTION: fn_21342
|
|
void CGameMode::ReloadScene() {
|
|
this->scene->Clear();
|
|
this->scene->CreatePlayer();
|
|
this->scene->LoadMapEffects();
|
|
g_weatherEffect.ResetEffect();
|
|
this->mousePointer = new CMousePointer();
|
|
this->scene->objects.push_back(this->mousePointer);
|
|
this->camera->camera.target[0] = this->scene->player->render.position.x;
|
|
this->camera->camera.target[1] = this->scene->player->render.position.y;
|
|
this->camera->camera.target[2] = this->scene->player->render.position.z;
|
|
}
|
|
|
|
// OFFSET: 0x00CDBEB0
|
|
// FUNCTION: fn_21314
|
|
void CGameMode::PlayItemUseEffect(int itemId, std::uint32_t aid) {
|
|
ITEM_INFO item = LookupClientItem(g_session.m_inventoryItems, itemId, 0);
|
|
|
|
CRenderObject* actor;
|
|
if (aid == g_session.m_aid) {
|
|
CPlayer* player = this->scene->player;
|
|
actor = player;
|
|
if (actor == nullptr) {
|
|
return;
|
|
}
|
|
|
|
if (itemId == 0x3113) {
|
|
const int job = player->GetEffectiveJob(-1);
|
|
char text[0x100];
|
|
strcpy_s(text, sizeof(text), LookupMessage(job >= 4054 && job <= 4112 ? 0x704 : 0x703));
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF00, 8, 0, 0);
|
|
}
|
|
} else {
|
|
actor = this->scene->GetGameActorByAID(aid);
|
|
if (actor == nullptr) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
int effectId = -1;
|
|
int secondEffectId = -1;
|
|
switch (itemId) {
|
|
case 0x1F5:
|
|
case 0x1FB:
|
|
case 0x221:
|
|
case 0x239:
|
|
case 0x242:
|
|
case 0x256:
|
|
case 0x2D2F:
|
|
case 0x2D30:
|
|
case 0x2D32:
|
|
case 0x3909:
|
|
effectId = 0xCC;
|
|
break;
|
|
case 0x1F6:
|
|
case 0x243:
|
|
case 0x257:
|
|
case 0x2D31:
|
|
case 0x311E:
|
|
effectId = 0xCD;
|
|
break;
|
|
case 0x1F7:
|
|
case 0x1FC:
|
|
case 0x222:
|
|
case 0x2CEC:
|
|
case 0x2D2E:
|
|
case 0x2D36:
|
|
effectId = 0xCE;
|
|
break;
|
|
case 0x1F8:
|
|
case 0x1FD:
|
|
case 0x223:
|
|
case 0x22B:
|
|
case 0x22C:
|
|
case 0x22D:
|
|
case 0x2CED:
|
|
case 0x2CEF:
|
|
case 0x2D1C:
|
|
case 0x2D25:
|
|
case 0x2D26:
|
|
case 0x2D2D:
|
|
case 0x2D35:
|
|
effectId = 0xCF;
|
|
break;
|
|
case 0x1F9:
|
|
case 0x1FE:
|
|
case 0x2CEE:
|
|
case 0x2CF0:
|
|
case 0x2D1D:
|
|
case 0x2D34:
|
|
effectId = 0xD0;
|
|
break;
|
|
case 0x1FA:
|
|
case 0x1FF:
|
|
case 0x2D33:
|
|
effectId = 0xD1;
|
|
break;
|
|
case 0x200:
|
|
case 0x201:
|
|
case 0x203:
|
|
case 0x204:
|
|
case 0x213:
|
|
case 0x214:
|
|
case 0x216:
|
|
case 0x217:
|
|
case 0x224:
|
|
case 0x225:
|
|
case 0x226:
|
|
case 0x246:
|
|
case 0x2AA:
|
|
effectId = 0xD2;
|
|
break;
|
|
case 0x202:
|
|
case 0x215:
|
|
case 0x238:
|
|
case 0x25F:
|
|
case 0x2A8:
|
|
case 0x2AB:
|
|
case 0x302D:
|
|
case 0x3037:
|
|
case 0x3039:
|
|
case 0x3041:
|
|
effectId = 0xD3;
|
|
break;
|
|
case 0x205:
|
|
case 0x206:
|
|
case 0x207:
|
|
case 0x208:
|
|
case 0x209:
|
|
case 0x20E:
|
|
case 0x210:
|
|
case 0x211:
|
|
case 0x212:
|
|
case 0x218:
|
|
case 0x219:
|
|
case 0x21A:
|
|
case 0x21B:
|
|
case 0x21C:
|
|
case 0x21D:
|
|
case 0x21E:
|
|
case 0x21F:
|
|
case 0x220:
|
|
case 0x227:
|
|
case 0x228:
|
|
case 0x229:
|
|
case 0x232:
|
|
case 0x233:
|
|
case 0x234:
|
|
case 0x235:
|
|
case 0x236:
|
|
case 0x237:
|
|
case 0x23A:
|
|
case 0x23B:
|
|
case 0x23C:
|
|
case 0x23F:
|
|
case 0x240:
|
|
case 0x241:
|
|
case 0x244:
|
|
case 0x245:
|
|
case 0x247:
|
|
case 0x248:
|
|
case 0x249:
|
|
case 0x24A:
|
|
case 0x297:
|
|
case 0x2D1B:
|
|
case 0x2D37:
|
|
case 0x2D38:
|
|
case 0x2D39:
|
|
case 0x2D3A:
|
|
case 0x2D3B:
|
|
case 0x2D3C:
|
|
case 0x2D3D:
|
|
case 0x2D3E:
|
|
effectId = 7;
|
|
break;
|
|
case 0x20A:
|
|
g_soundMgr->PlayWave("_heal_effect.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
break;
|
|
case 0x20B:
|
|
g_soundMgr->PlayWave("effect\\EF_Blessing.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
break;
|
|
case 0x22A:
|
|
case 0x2F5A:
|
|
case 0x2F5B:
|
|
case 0x2F5C:
|
|
case 0x2FA3:
|
|
case 0x2FA4:
|
|
case 0x2FA5:
|
|
case 0x2FA6:
|
|
case 0x2FCE:
|
|
case 0x2FCF:
|
|
case 0x5817:
|
|
case 0x5818:
|
|
case 0x5819:
|
|
g_soundMgr->PlayWave("_heal_effect.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x1EB;
|
|
break;
|
|
case 0x22E:
|
|
case 0x231:
|
|
case 0x2D40:
|
|
case 0x2D43:
|
|
case 0x2FCD:
|
|
effectId = 0x16C;
|
|
break;
|
|
case 0x22F:
|
|
case 0x230:
|
|
case 0x2D41:
|
|
case 0x2D42:
|
|
case 0x2DB5:
|
|
effectId = 0x16B;
|
|
break;
|
|
case 0x23D:
|
|
case 0x254:
|
|
case 0x255:
|
|
case 0x2D3F:
|
|
case 0x2FCA:
|
|
effectId = 0x1FD;
|
|
break;
|
|
case 0x23E:
|
|
case 0x3036:
|
|
case 0x3038:
|
|
effectId = 0xD2;
|
|
break;
|
|
case 0x285:
|
|
case 0x38AD:
|
|
case 0x580E:
|
|
effectId = 0xDA;
|
|
break;
|
|
case 0x290:
|
|
case 0x38AE:
|
|
case 0x5810:
|
|
effectId = 0xDB;
|
|
break;
|
|
case 0x291:
|
|
case 0x38AF:
|
|
case 0x580F:
|
|
effectId = 0xDC;
|
|
break;
|
|
case 0x296:
|
|
case 0x2FE6:
|
|
g_soundMgr->PlayWave("effect\\mapae.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x1FB;
|
|
break;
|
|
case 0x2AC:
|
|
static_cast<EffectActor*>(actor)->LaunchEffect(0x105, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
|
|
effectId = 0xDC;
|
|
break;
|
|
case 0x2AD:
|
|
effectId = 0x1EC;
|
|
break;
|
|
case 0x2EF0:
|
|
case 0x5811:
|
|
g_soundMgr->PlayWave("effect\\fast.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x207;
|
|
break;
|
|
case 0x2EF1:
|
|
case 0x5812:
|
|
effectId = 0x26;
|
|
break;
|
|
case 0x2EF2:
|
|
g_soundMgr->PlayWave("effect\\itempokjuk.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x1FC;
|
|
break;
|
|
case 0x2EF7:
|
|
g_soundMgr->PlayWave("effect\\ro2effect.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x221;
|
|
break;
|
|
case 0x2EFB:
|
|
case 0x588D:
|
|
g_soundMgr->PlayWave("wraith_die.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
break;
|
|
case 0x2EFC:
|
|
effectId = 0x240;
|
|
break;
|
|
case 0x2EFD:
|
|
effectId = 0x241;
|
|
break;
|
|
case 0x2EFE:
|
|
effectId = 0x242;
|
|
break;
|
|
case 0x2EFF:
|
|
effectId = 0x243;
|
|
break;
|
|
case 0x2F00:
|
|
effectId = 0x244;
|
|
break;
|
|
case 0x2F01:
|
|
effectId = 0x245;
|
|
break;
|
|
case 0x2F02:
|
|
g_soundMgr->PlayWave("ork_warrior_breath.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
break;
|
|
case 0x2F56:
|
|
g_soundMgr->PlayWave("evil_cloud_hermit_attack.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x25B;
|
|
break;
|
|
case 0x2F57:
|
|
g_soundMgr->PlayWave("evil_cloud_hermit_attack.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x33;
|
|
break;
|
|
case 0x2F58:
|
|
g_soundMgr->PlayWave("evil_cloud_hermit_attack.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x93;
|
|
break;
|
|
case 0x2F59:
|
|
g_soundMgr->PlayWave("evil_cloud_hermit_attack.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x34;
|
|
break;
|
|
case 0x2F63:
|
|
effectId = 0x264;
|
|
break;
|
|
case 0x2FBA:
|
|
static_cast<EffectActor*>(actor)->LaunchEffect(0x177, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
|
|
static_cast<EffectActor*>(actor)->LaunchEffect(0x1B8, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
|
|
break;
|
|
case 0x2FDA:
|
|
effectId = 0x251;
|
|
break;
|
|
case 0x2FDB:
|
|
effectId = 0x254;
|
|
break;
|
|
case 0x2FDC:
|
|
effectId = 0x252;
|
|
break;
|
|
case 0x2FDD:
|
|
effectId = 0x255;
|
|
break;
|
|
case 0x2FDE:
|
|
effectId = 0x256;
|
|
break;
|
|
case 0x2FDF:
|
|
effectId = 0x253;
|
|
break;
|
|
case 0x3016:
|
|
case 0x3017:
|
|
effectId = 0x2BB;
|
|
break;
|
|
case 0x301B:
|
|
effectId = 0x152;
|
|
break;
|
|
case 0x301C:
|
|
effectId = 0x2C1;
|
|
break;
|
|
case 0x301D:
|
|
g_soundMgr->PlayWave("effect\\storm.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x2C2;
|
|
break;
|
|
case 0x301E:
|
|
effectId = 0x2C3;
|
|
break;
|
|
case 0x3026:
|
|
g_soundMgr->PlayWave("effect\\pokjuk_jap.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x2C5;
|
|
break;
|
|
case 0x3198:
|
|
g_soundMgr->PlayWave("effect\\itempokjuk.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x3DB;
|
|
break;
|
|
case 0x3199:
|
|
g_soundMgr->PlayWave("effect\\itempokjuk.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x3DC;
|
|
break;
|
|
case 0x31F4:
|
|
g_soundMgr->PlayWave("effect\\itempokjuk.wav", 0.0f, 0.0f, 0.0f, 250, 40, 1.0f, 0);
|
|
effectId = 0x3EE;
|
|
break;
|
|
case 0x3280:
|
|
effectId = 0x56;
|
|
break;
|
|
case 0x38D2:
|
|
effectId = 0x2AA;
|
|
break;
|
|
case 0x38D3:
|
|
effectId = 0x2AB;
|
|
break;
|
|
case 0x38D4:
|
|
effectId = 0x2AC;
|
|
break;
|
|
case 0x38D5:
|
|
effectId = 0x2AD;
|
|
break;
|
|
case 0x38D6:
|
|
effectId = 0x2AE;
|
|
break;
|
|
case 0x18733:
|
|
case 0x18734:
|
|
case 0x18735:
|
|
effectId = 0x63D;
|
|
secondEffectId = 0x63E;
|
|
break;
|
|
case 0x18736:
|
|
effectId = 0x63B;
|
|
secondEffectId = 0x63C;
|
|
break;
|
|
case 0x19605:
|
|
effectId = 0x982;
|
|
break;
|
|
}
|
|
|
|
if ((itemId >= 0x2F09 && itemId <= 0x2F0D) || (itemId >= 0x2F27 && itemId <= 0x2F2B) || itemId == 0x2FAA) {
|
|
effectId = 0x251;
|
|
} else if ((itemId >= 0x2F0E && itemId <= 0x2F12) || (itemId >= 0x2F2C && itemId <= 0x2F30) || itemId == 0x2FAC) {
|
|
effectId = 0x252;
|
|
} else if ((itemId >= 0x2F13 && itemId <= 0x2F17) || (itemId >= 0x2F31 && itemId <= 0x2F35) || itemId == 0x2FAF) {
|
|
effectId = 0x253;
|
|
} else if ((itemId >= 0x2F18 && itemId <= 0x2F1C) || (itemId >= 0x2F36 && itemId <= 0x2F3A) || itemId == 0x2FAB) {
|
|
effectId = 0x254;
|
|
} else if ((itemId >= 0x2F1D && itemId <= 0x2F21) || (itemId >= 0x2F3B && itemId <= 0x2F3F) || itemId == 0x2FAD) {
|
|
effectId = 0x255;
|
|
} else if ((itemId >= 0x2F22 && itemId <= 0x2F26) || (itemId >= 0x2F40 && itemId <= 0x2F44) || itemId == 0x2FAE) {
|
|
effectId = 0x256;
|
|
}
|
|
|
|
if (effectId > 0) {
|
|
while (static_cast<EffectActor*>(actor)->HasId(effectId)) {
|
|
actor->SendMsg(nullptr, 109, 0, effectId, effectId >> 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
if (g_effectMgr->HasAllocator(effectId)) {
|
|
g_effectMgr->Spawn(actor->render.accountId, effectId, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
|
|
} else {
|
|
static_cast<EffectActor*>(actor)->LaunchEffect(effectId, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
|
|
}
|
|
}
|
|
|
|
if (secondEffectId > 0) {
|
|
while (static_cast<EffectActor*>(actor)->HasId(secondEffectId)) {
|
|
actor->SendMsg(nullptr, 109, 0, secondEffectId, secondEffectId >> 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
if (g_effectMgr->HasAllocator(secondEffectId)) {
|
|
g_effectMgr->Spawn(actor->render.accountId, secondEffectId, 0.0f, 0.0f, 0.0f, 0, -1, 0, 0);
|
|
} else {
|
|
static_cast<EffectActor*>(actor)->LaunchEffect(secondEffectId, vector3d{0.0f, 0.0f, 0.0f}, 0.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
#include "Contents/Effects/EffectPrim.h"
|
|
#include "Contents/SignBoard/SignBoard.h"
|
|
#include "Contents/Sound/SoundMaker.h"
|
|
#include "Contents/TerrainPathSearch.h"
|
|
#include "Contents/UserData/AccountLinkedUserDataMgr.h"
|
|
#include "Network/GameTickPacket.h"
|
|
#include "UI/Buttons/UITextButton.h"
|
|
#include "UI/UIMacroUserInfoWnd.h"
|
|
#include "UI/Layout/SnapMgr.h"
|
|
#include "UI/Window/UIMileageWnd.h"
|
|
#include "UI/Window/UIWindowFactory.h"
|
|
#include <list>
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
// GLOBAL: gl_24776
|
|
int g_visibleMinX;
|
|
|
|
// GLOBAL: gl_24777
|
|
int g_visibleMinY;
|
|
|
|
// GLOBAL: gl_24778
|
|
int g_visibleMaxX;
|
|
|
|
// GLOBAL: gl_24779
|
|
int g_visibleMaxY;
|
|
|
|
// GLOBAL: gl_25330
|
|
std::uint32_t g_gameTickInterval = 12000;
|
|
|
|
// GLOBAL: gl_25332
|
|
int g_window315Enabled = 1;
|
|
|
|
// OFFSET: 0x00CD5E90
|
|
// FUNCTION: fn_21288
|
|
void CGameMode::InitializeState() {
|
|
this->ClearTooltip();
|
|
this->nameCard.Clear();
|
|
this->unknown_019C.clear();
|
|
this->unknown_01A4.clear();
|
|
this->actorMenuIds.clear();
|
|
this->unknown_01B4.clear();
|
|
this->unknown_01C4.clear();
|
|
this->m_skillUnitIds.clear();
|
|
this->spriteMirrorActorIds.clear();
|
|
this->minimapMarkers.clear();
|
|
|
|
if (g_windowMgr.window_4F1CC) {
|
|
g_windowMgr.window_4F1CC->SendMsg(nullptr, 486, 0, 0, 0, 0);
|
|
}
|
|
|
|
g_snapMgr.Clear();
|
|
g_windowMgr.sub_AA6B80();
|
|
this->broadcastBalloon = nullptr;
|
|
this->noticeBalloon = nullptr;
|
|
g_windowMgr.SetSurface0478(nullptr);
|
|
g_windowMgr.EnsureWindow(0);
|
|
g_windowMgr.ShowWindowsWithId(67, 1);
|
|
g_windowMgr.EnsureWindow(204);
|
|
|
|
const char* worldName = reinterpret_cast<const char*>(g_modeMgr.GetGameMode()->SendMsg(9, 0, 0, 0, 0));
|
|
if (std::strcmp(worldName, "new_event.rsw") != 0) {
|
|
g_windowMgr.EnsureWindow(190);
|
|
}
|
|
|
|
if (g_session.unknown_593C) {
|
|
g_windowMgr.EnsureWindow(137);
|
|
}
|
|
|
|
if (!g_replayAnimationScaling && g_serviceOptions.Get(270)) {
|
|
g_windowMgr.EnsureWindow(159);
|
|
}
|
|
|
|
if (g_closeWindow164State) {
|
|
g_windowMgr.EnsureWindow(164);
|
|
}
|
|
|
|
if (g_searchStoreInfoCreated) {
|
|
g_windowMgr.EnsureWindow(181);
|
|
}
|
|
|
|
g_windowMgr.EnsureWindow(268);
|
|
if (g_refreshWindow289) {
|
|
g_windowMgr.EnsureWindow(289);
|
|
}
|
|
|
|
this->running = 1;
|
|
g_visibleMinX = 0;
|
|
g_visibleMaxX = 0;
|
|
g_visibleMinY = 0;
|
|
g_visibleMaxY = 0;
|
|
ActorPickBounds bounds;
|
|
bounds.left = 0;
|
|
bounds.top = 0;
|
|
bounds.right = g_renderer->viewport.width;
|
|
bounds.bottom = g_renderer->viewport.height;
|
|
g_actorPickNode.MakeQuardTree(1, bounds);
|
|
g_pathFinder.attr = this->scene->terrain;
|
|
g_navigationManager.UpdateGround();
|
|
g_overrideColor = 0;
|
|
|
|
this->fadeInRequested = 1;
|
|
this->cursorOffsetX = 0.0f;
|
|
this->cursorOffsetY = 0.0f;
|
|
*reinterpret_cast<int*>(this->unknown_00D8) = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_00D8[4]) = g_screenWidth;
|
|
*reinterpret_cast<int*>(&this->unknown_00D8[8]) = g_screenHeight;
|
|
this->unknown_00E4 = g_screenWidth;
|
|
this->unknown_00E8 = g_screenHeight;
|
|
this->unknown_0244 = 0;
|
|
this->unknown_024C = 0;
|
|
this->unknown_0250 = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_0294[0x18]) = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_0294[0x1C]) = 0;
|
|
*reinterpret_cast<int*>(this->unknown_02B8) = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_02B8[4]) = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_02B8[8]) = 0;
|
|
this->itemWindow = nullptr;
|
|
this->unknown_05D0 = nullptr;
|
|
this->unknown_01F8 = -1;
|
|
this->balloonActorId = 0;
|
|
*reinterpret_cast<int*>(this->unknown_02E4) = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_02E4[4]) = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_02B8[0x0C]) = 1;
|
|
*reinterpret_cast<int*>(&this->unknown_02B8[0x10]) = 1;
|
|
this->unknown_02CC = 0;
|
|
*reinterpret_cast<int*>(this->unknown_02D0) = 0;
|
|
this->unknown_02D4 = 0;
|
|
this->drag.Clear();
|
|
this->unknown_02DC = 0;
|
|
this->unknown_02E0 = 0;
|
|
*reinterpret_cast<int*>(this->unknown_00EC) = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[4]) = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[8]) = 0;
|
|
this->unknown_00F8 = 1;
|
|
this->unknown_00FC = 0;
|
|
*reinterpret_cast<int*>(this->unknown_0100) = 0;
|
|
*reinterpret_cast<std::uint32_t*>(&this->unknown_0100[0x04]) = timeGetTime() - 2000;
|
|
*reinterpret_cast<std::uint32_t*>(&this->unknown_0100[0x08]) = timeGetTime() - 2000;
|
|
*reinterpret_cast<int*>(&this->unknown_0100[0x0C]) = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_0100[0x10]) = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_0100[0x14]) = 0;
|
|
this->unknown_0450 = 0;
|
|
this->unknown_0454 = 0;
|
|
this->unknown_0438 = "";
|
|
this->unknown_0408 = nullptr;
|
|
this->unknown_040C = 0;
|
|
g_pickInvert = 0;
|
|
*reinterpret_cast<int*>(this->unknown_045C) = 0;
|
|
this->miniMapTooltipId = -1;
|
|
*reinterpret_cast<int*>(&this->unknown_045C[4]) = -1;
|
|
|
|
char subKey[512];
|
|
std::strcpy(subKey, g_subKey);
|
|
std::strcat(subKey, "\\NameBaloon");
|
|
std::strcat(subKey, "\\");
|
|
std::strcat(subKey, g_session.m_serverName.c_str());
|
|
HKEY key;
|
|
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
|
|
RegCloseKey(key);
|
|
HKEY valueKey;
|
|
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, KEY_ALL_ACCESS, &valueKey) == ERROR_SUCCESS) {
|
|
DWORD position = 0;
|
|
DWORD type = REG_DWORD;
|
|
DWORD size = sizeof(position);
|
|
RegQueryValueExA(valueKey, "POS", nullptr, &type, reinterpret_cast<BYTE*>(&position), &size);
|
|
g_serviceOptions.Set(92, position == 1);
|
|
RegCloseKey(valueKey);
|
|
}
|
|
}
|
|
|
|
g_mouse.Reset();
|
|
*reinterpret_cast<int*>(&this->unknown_026E[0x02]) = 1;
|
|
this->unknown_026E[0x16] = 0;
|
|
*reinterpret_cast<std::uint32_t*>(&this->unknown_026E[0x06]) = timeGetTime();
|
|
*reinterpret_cast<std::uint32_t*>(&this->unknown_026E[0x0A]) = timeGetTime();
|
|
this->unknown_0248 = timeGetTime();
|
|
*reinterpret_cast<std::uint32_t*>(this->unknown_01E0) = timeGetTime();
|
|
this->broadcastBalloon = nullptr;
|
|
*reinterpret_cast<std::uint32_t*>(&this->unknown_026E[0x0E]) = timeGetTime();
|
|
*reinterpret_cast<std::uint32_t*>(&this->unknown_026E[0x12]) = timeGetTime();
|
|
this->unknown_05CE = 1;
|
|
std::memset(&this->unknown_05EC[1], 0, 6);
|
|
*reinterpret_cast<int*>(&this->unknown_05EC[0x08]) = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_05EC[0x0C]) = 0;
|
|
g_soundMgr->SetListenerYaw(this->camera->camera.desiredYaw);
|
|
this->SendMsg(41, 0, 0, 0, 0);
|
|
|
|
if (g_isStopByLogin) {
|
|
g_isStopByLogin = 0;
|
|
g_guildInfo.Init();
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(22)), 0xFFE6E6, 0, 0, 0);
|
|
inet_ntoa(*reinterpret_cast<const in_addr*>(&g_session.unknown_0E9C[0x10]));
|
|
if (!g_accountLinkedUserDataMgr->m_loaded) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(3457)), 255, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
g_session.ResetUnknown166C();
|
|
g_session.UpdateRandomStats();
|
|
g_session.ClearItems1738();
|
|
g_session.ClearTradeItems();
|
|
g_session.ClearItems1768();
|
|
g_session.ClearItems1758();
|
|
g_session.ClearItems1750();
|
|
|
|
// GLOBAL: gl_25334
|
|
static int s_window315Checked;
|
|
if (!g_replayAnimationScaling && !s_window315Checked) {
|
|
s_window315Checked = 1;
|
|
if (g_window315Enabled) {
|
|
g_windowMgr.EnsureWindow(315);
|
|
}
|
|
}
|
|
|
|
if (g_replayAnimationScaling != 1) {
|
|
std::int16_t packet = 0x7D;
|
|
GetRagConnection().Send(2, &packet);
|
|
GetRagConnection().ResetDeferred();
|
|
g_session.SetOption(5, 1, 0);
|
|
}
|
|
|
|
SendGameTick(
|
|
true, *reinterpret_cast<std::uint32_t*>(&this->unknown_026E[0x02]), *reinterpret_cast<std::uint32_t*>(&this->unknown_026E[0x06]), g_gameTickInterval,
|
|
GetRagConnection(), g_packetLengths, g_pingLogEnabled, g_pingLogFirstTick, g_pingLogTicks
|
|
);
|
|
g_weatherEffect.ResetEffect();
|
|
g_weatherEffect.ApplyMapWeather(this->mapName);
|
|
if (std::strcmp(this->mapName, "xmas_fild01.rsw") == 0 || std::strcmp(this->mapName, "xmas.rsw") == 0) {
|
|
if (g_serviceOptions.Get(8)) {
|
|
g_weatherEffect.Snow();
|
|
} else {
|
|
g_weatherEffect.ExtendEffect();
|
|
}
|
|
}
|
|
|
|
if (!g_mapSkyMgr) {
|
|
g_mapSkyMgr = new (std::nothrow) CMapSkyMgr;
|
|
}
|
|
|
|
g_mapSkyMgr->Apply(this->mapName);
|
|
if ((g_serviceType == 8 || g_serviceType == 9) && std::strcmp(this->mapName, "comodo.rsw") == 0 && g_serviceOptions.Get(8)) {
|
|
g_weatherEffect.Fireworks();
|
|
}
|
|
|
|
*reinterpret_cast<int*>(&g_session.unknown_5570[0x08]) = -1;
|
|
g_session.unknown_5614 = 0;
|
|
g_session.ClearHomunStatus();
|
|
*reinterpret_cast<int*>(&g_session.unknown_5620[0x08]) = -1;
|
|
g_session.unknown_56B0 = 0;
|
|
g_session.ResetMercenaryStats();
|
|
g_windowMgr.FocusWindow01C8Edit();
|
|
|
|
g_windowMgr.window_4F168 = nullptr;
|
|
const int replayState = Replay::Instance().state;
|
|
if (g_replayAnimationScaling) {
|
|
g_windowMgr.EnsureWindow(187);
|
|
if (replayState == 8) {
|
|
g_windowMgr.window_4F168->SendMsg(nullptr, 35, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
if (replayState == 3) {
|
|
Replay::Instance().SetState(2);
|
|
g_windowMgr.EnsureWindow(198);
|
|
g_windowMgr.window_4F164->Move(Replay::Instance().unknown_01F4, Replay::Instance().unknown_01F8);
|
|
g_windowMgr.window_4F164->SendMsg(nullptr, 123, 0, 0, 0, 0);
|
|
} else if (replayState == 8) {
|
|
Replay::Instance().SetState(7);
|
|
}
|
|
|
|
g_navigationManager.ResumeRoute();
|
|
if (g_mileageWndActive) {
|
|
UIWindow* mileage = g_windowMgr.EnsureWindow(267);
|
|
if (mileage) {
|
|
mileage->SendMsg(nullptr, 34, g_mileageWndActive, g_mileageWndPoint, g_mileageWndElapsed, g_mileageWndBonus);
|
|
}
|
|
}
|
|
|
|
this->unknown_05FC = nullptr;
|
|
*reinterpret_cast<int*>(this->unknown_0600) = 0;
|
|
s_signBoardMgr->Initialize();
|
|
g_statusRefreshSuppressed = 0;
|
|
int& localMapMove = g_session.m_localMapMove;
|
|
if (localMapMove == 1) {
|
|
localMapMove = 0;
|
|
}
|
|
|
|
g_guildInfo.ClearUnknown0114();
|
|
this->unknown_02EC = "";
|
|
}
|
|
|
|
// OFFSET: 0x00CE46B0
|
|
// FUNCTION: fn_21337
|
|
void CGameMode::ProcessRightButtonDrag() {
|
|
switch (g_mouse.buttons[1]) {
|
|
case 1: {
|
|
if (g_windowMgr.unknown_0210) {
|
|
g_windowMgr.CloseWindow(0x12);
|
|
}
|
|
|
|
this->SendMsg(0x12, 0, 0, 0, 0);
|
|
this->SendMsg(0x47, 0, 0, 0, 0);
|
|
this->unknown_00E4 = g_screenWidth;
|
|
this->unknown_00E8 = g_screenHeight;
|
|
if (!g_serviceOptions.Get(0x78)) {
|
|
return;
|
|
}
|
|
|
|
UIShortCutWnd* shortcuts = static_cast<UIShortCutWnd*>(g_windowMgr.window_01E8);
|
|
if (!shortcuts) {
|
|
return;
|
|
}
|
|
|
|
AutomaticSkills* automatic = &g_session.m_automaticSkills;
|
|
if (shortcuts->m_slots[4]->unknown_0000 && automatic->Contains(static_cast<std::uint16_t>(shortcuts->m_slots[4]->itemId))) {
|
|
g_session.SetOption(AutomaticSkills::CancelOption(static_cast<std::int16_t>(shortcuts->m_slots[4]->itemId)), 1, 0);
|
|
} else {
|
|
automatic->DisableAll();
|
|
}
|
|
|
|
shortcuts->SendMsg(nullptr, 0x29, 8, 0, 0, 0);
|
|
return;
|
|
}
|
|
case 2:
|
|
if (!HIBYTE(GetAsyncKeyState(VK_MENU)) && !HIBYTE(GetAsyncKeyState(VK_SHIFT))) {
|
|
this->SetCursorAction(4);
|
|
if (this->hasViewParameters) {
|
|
float yaw = static_cast<float>(g_screenWidth) + this->camera->camera.desiredYaw - static_cast<float>(this->unknown_00DC);
|
|
const float low = static_cast<float>(this->viewParameters[3]);
|
|
const float high = static_cast<float>(this->viewParameters[4]);
|
|
if (yaw < low) {
|
|
yaw = low;
|
|
}
|
|
if (yaw > high) {
|
|
yaw = high;
|
|
}
|
|
this->camera->camera.desiredYaw = yaw;
|
|
} else if (this->unknown_0254 == 0 && g_session.IsAdminSubMode(6) == 0) {
|
|
float yaw = static_cast<float>(g_screenWidth) + this->camera->camera.desiredYaw - static_cast<float>(this->unknown_00DC);
|
|
const float low = this->unknown_0288 - 20.0f;
|
|
const float high = this->unknown_0288 + 20.0f;
|
|
if (yaw < low) {
|
|
yaw = low;
|
|
}
|
|
if (yaw > high) {
|
|
yaw = high;
|
|
}
|
|
this->camera->camera.desiredYaw = yaw;
|
|
} else {
|
|
this->camera->camera.AddYaw(static_cast<float>(g_screenWidth - this->unknown_00DC));
|
|
}
|
|
|
|
g_soundMgr->SetListenerYaw(this->camera->camera.desiredYaw);
|
|
}
|
|
|
|
if (!HIBYTE(GetAsyncKeyState(VK_MENU)) && HIBYTE(GetAsyncKeyState(VK_SHIFT))) {
|
|
const float range = this->unknown_0254 ? 42.0f : 10.0f;
|
|
g_cameraPitch = this->camera->camera.desiredPitch - static_cast<float>((g_screenHeight - this->unknown_00E0) / 2);
|
|
float limit;
|
|
if (this->hasViewParameters) {
|
|
if (g_cameraPitch < static_cast<float>(this->viewParameters[7])) {
|
|
g_cameraPitch = static_cast<float>(this->viewParameters[7]);
|
|
}
|
|
limit = static_cast<float>(this->viewParameters[6]);
|
|
} else {
|
|
if (g_cameraPitch < -45.0f - range) {
|
|
g_cameraPitch = -45.0f - range;
|
|
}
|
|
if (HIBYTE(GetAsyncKeyState(VK_CONTROL)) && this->camera->camera.desiredDistance <= g_serviceOptionJitterScale) {
|
|
limit = range - 45.0f;
|
|
} else {
|
|
limit = range - 70.0f;
|
|
}
|
|
}
|
|
|
|
if (g_cameraPitch > limit) {
|
|
g_cameraPitch = limit;
|
|
}
|
|
this->camera->camera.desiredPitch = g_cameraPitch;
|
|
}
|
|
|
|
if (HIBYTE(GetAsyncKeyState(VK_CONTROL))) {
|
|
g_cameraDistance = this->camera->camera.desiredDistance - static_cast<float>((g_screenHeight - this->unknown_00E0) / 2);
|
|
float maxDistance = this->unknown_0254 ? g_serviceOptionJitterScale : g_cameraBaseDistance;
|
|
if (this->hasViewParameters) {
|
|
if (g_cameraDistance < static_cast<float>(this->viewParameters[0])) {
|
|
g_cameraDistance = static_cast<float>(this->viewParameters[0]);
|
|
}
|
|
maxDistance = static_cast<float>(this->viewParameters[1] + this->viewParameters[0]);
|
|
if (g_cameraDistance > maxDistance) {
|
|
g_cameraDistance = maxDistance;
|
|
}
|
|
} else if (g_session.IsAdminSubMode(5) == 0) {
|
|
if (g_cameraDistance < g_cameraMinDistance) {
|
|
g_cameraDistance = g_cameraMinDistance;
|
|
}
|
|
if (g_cameraDistance > maxDistance) {
|
|
g_cameraDistance = maxDistance;
|
|
}
|
|
}
|
|
|
|
this->camera->camera.desiredDistance = g_cameraDistance;
|
|
}
|
|
return;
|
|
case 4:
|
|
if (this->hasViewParameters) {
|
|
return;
|
|
}
|
|
|
|
if (HIBYTE(GetAsyncKeyState(VK_CONTROL))) {
|
|
this->camera->camera.desiredDistance = g_cameraBaseDistance;
|
|
}
|
|
if (HIBYTE(GetAsyncKeyState(VK_SHIFT))) {
|
|
this->camera->camera.desiredPitch = -50.0f;
|
|
}
|
|
if (!g_serviceOptions.Get(0x78) && this->unknown_0254 && !HIBYTE(GetAsyncKeyState(VK_SHIFT)) && !HIBYTE(GetAsyncKeyState(VK_CONTROL))) {
|
|
this->camera->camera.desiredYaw = 0.0f;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CE7CE0
|
|
// FUNCTION: fn_21339
|
|
void CGameMode::ProcessMouseWheel(int requireControl) {
|
|
if (timeGetTime() - this->wheelTick < 16) {
|
|
return;
|
|
}
|
|
|
|
this->wheelTick = timeGetTime();
|
|
if (g_mouse.wheel == 0 || this->unknown_0408 != nullptr) {
|
|
return;
|
|
}
|
|
|
|
CSkillInfo wheelSkill = g_session.m_skillBundle.Lookup(0x27F);
|
|
if (wheelSkill.level > 0) {
|
|
const int count = this->unknown_05F4;
|
|
if (count > this->unknown_05F8) {
|
|
this->unknown_05F8 = count;
|
|
}
|
|
this->unknown_05F4 = count + 4;
|
|
}
|
|
|
|
if (HIBYTE(GetAsyncKeyState(VK_SHIFT))) {
|
|
const float step = g_mouse.wheel > 0 ? -5.0f : 5.0f;
|
|
const float range = this->unknown_0254 ? 20.0f : 10.0f;
|
|
g_cameraPitch = this->camera->camera.desiredPitch - step;
|
|
float limit;
|
|
if (this->hasViewParameters) {
|
|
if (g_cameraPitch < static_cast<float>(this->viewParameters[7])) {
|
|
g_cameraPitch = static_cast<float>(this->viewParameters[7]);
|
|
}
|
|
limit = static_cast<float>(this->viewParameters[6]);
|
|
} else {
|
|
if (g_cameraPitch < -45.0f - range) {
|
|
g_cameraPitch = -45.0f - range;
|
|
}
|
|
if (HIBYTE(GetAsyncKeyState(VK_CONTROL)) && this->camera->camera.desiredDistance <= g_serviceOptionJitterScale) {
|
|
limit = range - 45.0f;
|
|
} else {
|
|
limit = range - 70.0f;
|
|
}
|
|
}
|
|
|
|
if (g_cameraPitch > limit) {
|
|
g_cameraPitch = limit;
|
|
}
|
|
this->camera->camera.desiredPitch = g_cameraPitch;
|
|
return;
|
|
}
|
|
|
|
if (requireControl != 0 && !HIBYTE(GetAsyncKeyState(VK_CONTROL))) {
|
|
return;
|
|
}
|
|
|
|
if (g_serviceOptions.Get(0x79)) {
|
|
UIShortCutWnd* shortcuts = static_cast<UIShortCutWnd*>(g_windowMgr.window_01E8);
|
|
*reinterpret_cast<int*>(&g_session.unknown_544C[0x00]) = 1;
|
|
AutomaticSkills* automatic = &g_session.m_automaticSkills;
|
|
if (g_mouse.wheel > 0) {
|
|
if (!shortcuts) {
|
|
return;
|
|
}
|
|
|
|
if (shortcuts->m_slots[3]->unknown_0000 && automatic->Contains(shortcuts->m_slots[3]->itemId)) {
|
|
g_session.SetOption(AutomaticSkills::CancelOption(static_cast<std::int16_t>(shortcuts->m_slots[3]->itemId)), 1, 0);
|
|
} else {
|
|
automatic->DisableAll();
|
|
}
|
|
|
|
shortcuts->SendMsg(nullptr, 0x29, 7, 0, 0, 0);
|
|
} else {
|
|
if (!shortcuts) {
|
|
return;
|
|
}
|
|
|
|
if (shortcuts->m_slots[2]->unknown_0000 && automatic->Contains(shortcuts->m_slots[2]->itemId)) {
|
|
g_session.SetOption(AutomaticSkills::CancelOption(static_cast<std::int16_t>(shortcuts->m_slots[2]->itemId)), 1, 0);
|
|
} else {
|
|
automatic->DisableAll();
|
|
}
|
|
|
|
shortcuts->SendMsg(nullptr, 0x29, 6, 0, 0, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
const float step = g_mouse.wheel > 0 ? -24.3f : 24.3f;
|
|
g_cameraDistance = this->camera->camera.desiredDistance - step;
|
|
float maxDistance = this->unknown_0254 ? g_serviceOptionJitterScale : g_cameraBaseDistance;
|
|
CSkillInfo zoomSkill = g_session.m_skillBundle.Lookup(0x1B9);
|
|
bool extendedZoom = false;
|
|
if (this->hasViewParameters) {
|
|
if (g_cameraDistance < static_cast<float>(this->viewParameters[0])) {
|
|
g_cameraDistance = static_cast<float>(this->viewParameters[0]);
|
|
}
|
|
maxDistance = static_cast<float>(this->viewParameters[1] + this->viewParameters[0]);
|
|
} else if (zoomSkill.level <= 0 && this->scene->player->render.unknown_0070 == 6 && !this->scene->player->HasId(0x14E)) {
|
|
switch (g_session.m_job) {
|
|
case 0xFCF:
|
|
case 0x1082:
|
|
case 0x108F:
|
|
case 0x1091:
|
|
case 0x10CE:
|
|
extendedZoom = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (extendedZoom) {
|
|
if (g_cameraDistance < g_cameraMinDistance) {
|
|
g_cameraDistance = g_cameraMinDistance;
|
|
}
|
|
if (g_cameraDistance > maxDistance * 3.0f) {
|
|
g_cameraDistance = maxDistance * 3.0f;
|
|
}
|
|
if (g_cameraDistance > maxDistance && this->camera->camera.desiredPitch > -50.0f) {
|
|
this->camera->camera.desiredPitch = -50.0f;
|
|
}
|
|
} else {
|
|
if (!this->hasViewParameters && g_cameraDistance < g_cameraMinDistance) {
|
|
g_cameraDistance = g_cameraMinDistance;
|
|
}
|
|
if (g_cameraDistance > maxDistance) {
|
|
g_cameraDistance = maxDistance;
|
|
}
|
|
}
|
|
|
|
this->camera->camera.desiredDistance = g_cameraDistance;
|
|
}
|
|
|
|
struct AiMessage {
|
|
/* 0000 */ int type;
|
|
/* 0004 */ int x;
|
|
/* 0008 */ int y;
|
|
/* 000C */ int level;
|
|
/* 0010 */ int skill;
|
|
/* 0014 */ int target;
|
|
};
|
|
|
|
#pragma pack(push, 1)
|
|
struct ContactNpcPacket {
|
|
/* 0000 */ std::int16_t packetType;
|
|
/* 0002 */ std::uint32_t npcId;
|
|
/* 0006 */ unsigned char type;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
namespace EquipmentProperties {
|
|
class CEquipmentPropertiesMgr {
|
|
public:
|
|
virtual ~CEquipmentPropertiesMgr();
|
|
/* 0004 */ unsigned char unknown_0004[0x1F8];
|
|
|
|
CEquipmentPropertiesMgr();
|
|
void RefreshPretend();
|
|
void RefreshShop();
|
|
};
|
|
}
|
|
|
|
#if defined(_WIN32) && !defined(_WIN64)
|
|
static_assert(sizeof(EquipmentProperties::CEquipmentPropertiesMgr) == 0x1FC);
|
|
#endif
|
|
|
|
// OFFSET: 0x00CDDA50
|
|
// FUNCTION: fn_21320
|
|
void CGameMode::Initialize(const char* name) {
|
|
this->unknown_0624[0] = 1;
|
|
this->unknown_0468 = 0;
|
|
this->nameCard.SetName(g_session.m_aid, g_session.DecodePlayerName());
|
|
g_playerNameDictionary->Set(g_session.m_gid, g_session.DecodePlayerName());
|
|
this->unknown_05C4 = -1;
|
|
this->unknown_05C8 = -1;
|
|
*reinterpret_cast<std::uint16_t*>(this->unknown_05CC) = 0;
|
|
|
|
if (Replay::Instance().state == 6) {
|
|
const std::vector<unsigned char> data = Replay::Instance().ReadSection(0x12);
|
|
if (data.begin() != data.end()) {
|
|
GameModeChunkHeader header = {};
|
|
g_activeSkillEffects.clear();
|
|
unsigned offset = 6;
|
|
header = *reinterpret_cast<const GameModeChunkHeader*>(data.data());
|
|
if (header.type == 19000) {
|
|
while (offset < data.size()) {
|
|
header = {};
|
|
header = *reinterpret_cast<const GameModeChunkHeader*>(data.data() + offset);
|
|
offset += 6;
|
|
if (header.type == 19001) {
|
|
break;
|
|
}
|
|
|
|
if (header.type == 19011) {
|
|
ActiveSkillEffect effect;
|
|
std::memcpy(&effect, data.data() + offset, header.size);
|
|
offset += header.size;
|
|
if (effect.unknown_0004 != 999999) {
|
|
g_cooldownOwner->Register(effect.id, effect.unknown_0014, effect.unknown_0004 - effect.unknown_0018, effect.unknown_0014 - effect.unknown_0018);
|
|
}
|
|
g_activeSkillEffects.push_back(effect);
|
|
} else {
|
|
offset += header.size;
|
|
}
|
|
}
|
|
g_statusRefreshSuppressed = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
g_session.ClearPairValues(1, 0, 0);
|
|
this->scene = new CWorld();
|
|
this->scene->gameMode = this;
|
|
this->camera = new CView();
|
|
this->camera->scene = this->scene;
|
|
std::strcpy(this->mapName, name);
|
|
|
|
std::string miniMap = "유저인터페이스\\map\\";
|
|
miniMap.append(name, std::strlen(name));
|
|
miniMap.resize(miniMap.size() - 4);
|
|
miniMap.append(".bmp", 4);
|
|
std::strcpy(reinterpret_cast<char*>(this->unknown_0090), miniMap.c_str());
|
|
|
|
g_renderer->SetFog(1);
|
|
g_session.m_weight = 0;
|
|
g_session.RefreshHpSpWindows();
|
|
g_session.InvalidateWindowFrames();
|
|
g_session.m_maxWeight = 0;
|
|
g_session.RefreshHpSpWindows();
|
|
g_session.InvalidateWindowFrames();
|
|
g_windowMgr.SetSurface0478(nullptr);
|
|
g_windowMgr.sub_AA6B80();
|
|
this->broadcastBalloon = nullptr;
|
|
this->noticeBalloon = nullptr;
|
|
g_windowMgr.HideWindow01C8();
|
|
g_windowMgr.ShowWindowsWithId(0x43, 0);
|
|
g_windowMgr.sub_A978D0(7);
|
|
g_windowMgr.SendNotice(4, 0, 0, 0, 0, 0);
|
|
g_windowMgr.CenterSurface0478();
|
|
g_windowMgr.DrawWindows();
|
|
if (g_renderer->CaptureBackBuffer()) {
|
|
g_renderer->Present(1);
|
|
}
|
|
|
|
this->camera->Reset();
|
|
this->scene->InitWorld();
|
|
this->unknown_0458 = 0;
|
|
this->InitializeCamera();
|
|
this->mousePointer = new CMousePointer();
|
|
this->scene->objects.push_back(this->mousePointer);
|
|
g_soundMgr->SetDefaultName(g_session.GetBgmFileName(std::string(this->mapName).c_str()));
|
|
|
|
g_weatherEffect.unknown_0001 = g_serviceOptions.Get(0x77) == 0;
|
|
if (g_serviceOptions.Get(0x3C)) {
|
|
int found = 0;
|
|
const std::vector<std::string>* fog = g_session.GetFogParameters(this->mapName, &found);
|
|
if (found) {
|
|
g_depthStart = static_cast<float>(std::atof((*fog)[0].c_str()));
|
|
g_depthEnd = static_cast<float>(std::atof((*fog)[1].c_str()));
|
|
g_worldOverlayColor = ParseHexString((*fog)[2].c_str());
|
|
g_fogDensity = static_cast<float>(std::atof((*fog)[3].c_str()));
|
|
g_renderer->SetClearColor(1);
|
|
} else {
|
|
g_renderer->SetClearColor(0);
|
|
}
|
|
} else {
|
|
g_renderer->SetClearColor(0);
|
|
}
|
|
|
|
Replay::Instance().ResetPlayback();
|
|
g_session.RestoreItems5C68();
|
|
g_session.ClearItemQuantities();
|
|
this->InitializeState();
|
|
ShowCurrentMapName();
|
|
ResetTimer();
|
|
this->forcedAttack = 0;
|
|
this->unknown_0464 = 0;
|
|
this->chatLogLines = 0;
|
|
this->unknown_05A0 = 0;
|
|
this->unknown_05D4.resize(6);
|
|
|
|
if (*reinterpret_cast<const int*>(g_session.unknown_5554) && g_session.IsAdminSubMode(7)) {
|
|
char message[256];
|
|
std::sprintf(message, "Now Auto chat Save System is ENABLED.");
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0xFFFF, 0, 0, 0);
|
|
}
|
|
|
|
if (g_replayAnimationScaling == 0) {
|
|
std::uint64_t now = _Xtime_get_ticks();
|
|
std::int64_t interval = 60000;
|
|
g_timeScheduler->AddSchedule(new CCheckGDISchedule(now, interval, 2));
|
|
interval = 5000;
|
|
CPingLiveSchedule* ping = new CPingLiveSchedule(now, interval);
|
|
g_session.m_pingLiveSchedule = ping->serial;
|
|
g_timeScheduler->AddSchedule(ping);
|
|
}
|
|
|
|
if (g_session.HasNoUnknown1784Items()) {
|
|
if (g_launchPassCommandLine) {
|
|
this->SendMsg(0x14B, 1, 0, 0, 0);
|
|
g_stoveMgr->FetchAllProducts();
|
|
} else {
|
|
std::int16_t packet = 0x8C9;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet), &packet);
|
|
}
|
|
}
|
|
|
|
if (Replay::Instance().state == 6) {
|
|
Replay::Instance().speed = 1.0f;
|
|
g_session.ReadReplayQuests(Replay::Instance().ReadSection(6));
|
|
g_session.ReadReplayStats(Replay::Instance().ReadSection(4));
|
|
g_session.ReadReplayItems(Replay::Instance().ReadSection(8));
|
|
g_session.ReadReplayCompanions(Replay::Instance().ReadSection(9));
|
|
g_session.ReadReplayMessenger(Replay::Instance().ReadSection(7));
|
|
g_session.ReadReplayExtra(Replay::Instance().ReadSection(10));
|
|
g_session.ReadReplayReserved(Replay::Instance().ReadSection(11));
|
|
g_session.ReadReplayEntryQueue(Replay::Instance().ReadSection(12));
|
|
g_session.ReadReplayShortcuts(Replay::Instance().ReadSection(13));
|
|
g_session.ReadReplayShops(Replay::Instance().ReadSection(14));
|
|
this->sub_CEBBB0(Replay::Instance().ReadSection(0x16));
|
|
this->sub_CEC100(Replay::Instance().ReadSection(0xF));
|
|
this->sub_CEBF30(Replay::Instance().ReadSection(0x10));
|
|
this->sub_CEC6A0(Replay::Instance().ReadSection(0x11));
|
|
|
|
const std::vector<unsigned char> data = Replay::Instance().ReadSection(0x17);
|
|
if (data.begin() != data.end()) {
|
|
GameModeChunkHeader header = {};
|
|
unsigned offset = 6;
|
|
header = *reinterpret_cast<const GameModeChunkHeader*>(data.data());
|
|
if (header.type == 14000) {
|
|
while (offset < data.size()) {
|
|
header = {};
|
|
header = *reinterpret_cast<const GameModeChunkHeader*>(data.data() + offset);
|
|
offset += 6;
|
|
if (header.type == 14001) {
|
|
break;
|
|
}
|
|
|
|
if (header.type == 14011) {
|
|
std::memcpy(&this->unknown_024C, data.data() + offset, header.size);
|
|
}
|
|
offset += header.size;
|
|
}
|
|
}
|
|
}
|
|
|
|
g_navigationManager.LoadReplayState(Replay::Instance().ReadSection(0x18));
|
|
g_windowMgr.LoadReplaySettings(Replay::Instance().ReadSection(0x14));
|
|
g_windowMgr.LoadReplayWindows(Replay::Instance().ReadSection(0x13));
|
|
g_windowMgr.LoadReplayReserved(Replay::Instance().ReadSection(0x15));
|
|
Replay::Instance().Rewind();
|
|
this->replayPauseTick = 0;
|
|
g_windowMgr.ShowWindowById(1, Replay::Instance().header.options.recordRestricted);
|
|
}
|
|
|
|
if (g_screenShakeMode == 2) {
|
|
this->scene->player->SendMsg(nullptr, 0x6E, 0, 0x22, 0, g_screenShakeDuration <= 10000 && g_screenShakeDuration != 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
|
|
if (g_session.GetOption(6) > 0) {
|
|
g_session.SetOption(6, 0, 0);
|
|
char message[256];
|
|
std::memset(message, 0, sizeof(message));
|
|
StringFormat(message, sizeof(message), static_cast<std::size_t>(-1), LookupMessage(0xDFA), g_serviceOptions.Get(0xFA) ? "ON" : "OFF");
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(message), 0xFF, 0, 0, 0);
|
|
}
|
|
|
|
if (g_equipmentPropertiesMgr == nullptr) {
|
|
g_equipmentPropertiesMgr = new (std::nothrow) EquipmentProperties::CEquipmentPropertiesMgr;
|
|
}
|
|
g_equipmentPropertiesMgr->RefreshShop();
|
|
|
|
if (g_session.GetOption(0xB) == 1) {
|
|
for (const std::string& blocked : g_whisperBlockMgr->Names()) {
|
|
std::string arguments[1] = {blocked};
|
|
this->ExecuteTalkType(0x12, arguments);
|
|
}
|
|
g_session.SetOption(0xB, 0, 0);
|
|
}
|
|
|
|
g_session.SetOption(0x14, 0, 0);
|
|
this->unknown_0624[0] = 0;
|
|
}
|
|
|
|
|
|
// OFFSET: 0x00D07030
|
|
// FUNCTION: fn_21580
|
|
void CGameMode::ReceiveSkillList(int packetType, const std::vector<SkillListEntry>& skills) {
|
|
if (packetType == 0x10F || packetType == 0xB32) {
|
|
g_session.m_skillBundle.skills.clear();
|
|
} else if (packetType == 0x235) {
|
|
g_session.m_homunSkills.clear();
|
|
} else if (packetType == 0x29D) {
|
|
g_session.m_mercSkills.clear();
|
|
}
|
|
|
|
for (const SkillListEntry& entry : skills) {
|
|
CSkillInfo skill;
|
|
if ((entry.id != 0 && entry.id < 7999) || g_session.IsHomunculusSkill(entry.id) || g_session.IsMercenarySkill(entry.id)) {
|
|
skill.id = entry.id;
|
|
skill.unknown_000C = entry.type;
|
|
skill.level = entry.level;
|
|
skill.unknown_0014 = entry.spCost;
|
|
skill.unknown_0018 = entry.upgradable;
|
|
skill.unknown_001C = entry.range;
|
|
skill.name = skill.IdName(*g_session.m_hotkeyScript);
|
|
skill.unknown_0030 = entry.unknown_000D;
|
|
skill.unknown_0034 = skill.UseApAmount(*g_session.m_hotkeyScript, entry.level);
|
|
g_session.m_skillBundle.ApplyLevelChange(skill);
|
|
|
|
if (packetType == 0x10F || packetType == 0xB32) {
|
|
g_session.UpdateSkill(skill, 0, 0);
|
|
} else if (packetType == 0x235) {
|
|
g_session.UpdateHomunSkill(skill, 0);
|
|
} else if (packetType == 0x29D) {
|
|
g_session.UpdateMercSkill(skill, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (packetType == 0x10F || packetType == 0xB32) {
|
|
g_session.NotifySkillWindows();
|
|
} else if (packetType == 0x235) {
|
|
g_session.NotifyHomunSkillWindows();
|
|
} else if (packetType == 0x29D) {
|
|
g_session.NotifyMercSkillWindows();
|
|
}
|
|
|
|
if (g_equipmentPropertiesMgr == nullptr) {
|
|
g_equipmentPropertiesMgr = new (std::nothrow) EquipmentProperties::CEquipmentPropertiesMgr;
|
|
}
|
|
g_equipmentPropertiesMgr->RefreshPretend();
|
|
}
|
|
|
|
// OFFSET: 0x00D07250
|
|
// FUNCTION: fn_21581
|
|
void CGameMode::ReceiveSkillUpdate(
|
|
std::uint16_t id, std::int16_t level, std::int16_t spCost, unsigned char upgradable, std::int16_t range, int type, std::int16_t unknown
|
|
) {
|
|
*reinterpret_cast<int*>(&this->unknown_0100[0x0C]) = 0;
|
|
|
|
CSkillInfo skill = g_session.LookupSkill(id);
|
|
skill.level = level;
|
|
skill.unknown_0014 = spCost;
|
|
skill.unknown_0018 = upgradable;
|
|
skill.unknown_001C = range;
|
|
skill.unknown_000C = type;
|
|
skill.unknown_0030 = unknown;
|
|
skill.id = id;
|
|
|
|
if (g_session.IsHomunculusSkill(id)) {
|
|
g_session.UpdateHomunSkill(skill, 1);
|
|
} else if (g_session.IsMercenarySkill(id)) {
|
|
g_session.UpdateMercSkill(skill, 1);
|
|
} else {
|
|
g_session.UpdateSkill(skill, 1, 1);
|
|
}
|
|
|
|
if (g_equipmentPropertiesMgr == nullptr) {
|
|
g_equipmentPropertiesMgr = new (std::nothrow) EquipmentProperties::CEquipmentPropertiesMgr;
|
|
}
|
|
g_equipmentPropertiesMgr->RefreshPretend();
|
|
}
|
|
|
|
// OFFSET: 0x00CDB910
|
|
// FUNCTION: fn_21310
|
|
void CGameMode::ShowActorNameBalloon(std::uint32_t id) {
|
|
if (!id) {
|
|
return;
|
|
}
|
|
|
|
int& placed = *reinterpret_cast<int*>(&this->unknown_02B8[0x0C]);
|
|
if (this->balloonActorId != id && this->balloonActorId != 0) {
|
|
this->balloonActorId = id;
|
|
placed = 1;
|
|
return;
|
|
}
|
|
|
|
this->balloonActorId = id;
|
|
CRenderObject* actor = this->scene->GetGameActorByAID(id);
|
|
if (actor) {
|
|
CGameActor* gameActor = static_cast<CGameActor*>(actor);
|
|
if (gameActor->GetEffectiveJob(-1) == 45) {
|
|
return;
|
|
}
|
|
|
|
placed = 0;
|
|
this->UpdateNameBalloon(gameActor);
|
|
if (this->unknown_05CC[1] && g_session.IsPlayerJobId(gameActor->GetEffectiveJob(-1)) && IsAdminAccount(g_session.m_aid)) {
|
|
g_windowMgr.SelectWhisperName(this->ActorName(id).c_str());
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (id == g_session.m_aid) {
|
|
placed = 0;
|
|
this->UpdateNameBalloon(reinterpret_cast<CGameActor*>(this->scene->player));
|
|
return;
|
|
}
|
|
|
|
CItem* item = this->scene->GetItemByAID(id);
|
|
if (!item) {
|
|
return;
|
|
}
|
|
|
|
std::string name(item->name.c_str());
|
|
placed = 0;
|
|
this->EnsureNameBalloon(this->nameBalloon);
|
|
this->nameBalloon->AddNameLine(name.c_str());
|
|
this->nameBalloon->SetIcon("", 0);
|
|
this->nameBalloon->m_textColor = 0x95EFFF;
|
|
this->nameBalloon->m_outlineColor = 0;
|
|
*reinterpret_cast<int*>(&this->unknown_02E4[0]) = this->nameBalloon->geometry.width;
|
|
*reinterpret_cast<int*>(&this->unknown_02E4[4]) = this->nameBalloon->geometry.height;
|
|
this->PlaceWindowAtActor(this->nameBalloon, reinterpret_cast<CGameActor*>(item));
|
|
}
|
|
|
|
|
|
// OFFSET: 0x00CE18A0
|
|
// FUNCTION: fn_21332
|
|
void CGameMode::ProcessActorClick(int& handled, ActorPickInfo* pick, CGameActor* actor) {
|
|
const unsigned char selfTargetOption = g_serviceOptions.Get(0x69);
|
|
const unsigned char forceOption = g_serviceOptions.Get(0x6D);
|
|
const std::intptr_t mode = reinterpret_cast<std::intptr_t>(this->unknown_0408);
|
|
|
|
int attack;
|
|
if (mode == 2 || mode == 4) {
|
|
const int shiftHeld = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
attack = IsSupportSkill(this->unknown_040C) ? shiftHeld : shiftHeld == 0;
|
|
this->SetCursorAction(11);
|
|
} else {
|
|
attack = HIBYTE(GetAsyncKeyState(VK_SHIFT)) == 0;
|
|
if (actor->unknown_0314 == 7) {
|
|
this->SetCursorAction(0);
|
|
} else if (g_session.GetMapProperty08() == 0 && this->scene->unknown_004C == 0) {
|
|
this->SetCursorAction(5);
|
|
} else if (g_session.IsLocalPlayerAid(actor->Slot50())) {
|
|
attack = 0;
|
|
this->SetCursorAction(0);
|
|
}
|
|
}
|
|
|
|
handled = 1;
|
|
if (selfTargetOption) {
|
|
attack = 1;
|
|
}
|
|
|
|
const std::uint32_t homunAid = *reinterpret_cast<const std::uint32_t*>(&g_session.unknown_5570[8]);
|
|
const std::uint32_t mercenaryAid = *reinterpret_cast<const std::uint32_t*>(&g_session.unknown_5620[8]);
|
|
if (g_session.unknown_5614 != 0) {
|
|
if (g_mouse.buttons[1] == 1 && HIBYTE(GetAsyncKeyState(VK_MENU))) {
|
|
if (HIBYTE(GetAsyncKeyState(VK_SHIFT))) {
|
|
CGameActor* homun = static_cast<CGameActor*>(this->scene->GetGameActorByAID(homunAid));
|
|
if (homun && homun->HasUnknown030CEntry()) {
|
|
AiMessage message = {};
|
|
message.type = 3;
|
|
message.target = actor->render.accountId;
|
|
homun->SetUnknown0330(reinterpret_cast<const float*>(&message), 0);
|
|
}
|
|
} else if (g_session.unknown_5610 != 0 && g_groundMarkAid == actor->render.accountId) {
|
|
CGameActor* homun = static_cast<CGameActor*>(this->scene->GetGameActorByAID(homunAid));
|
|
if (homun && homun->HasUnknown030CEntry()) {
|
|
AiMessage message = {};
|
|
message.type = 3;
|
|
message.target = g_groundMarkAid;
|
|
homun->SetUnknown0318(reinterpret_cast<const float*>(&message), 0);
|
|
}
|
|
g_session.unknown_5610 = 0;
|
|
} else {
|
|
this->SetCursorAction(11);
|
|
g_groundMarkAid = actor->render.accountId;
|
|
g_session.unknown_5600 = 0;
|
|
g_session.unknown_5604 = 0;
|
|
g_session.unknown_5608 = 0;
|
|
g_session.unknown_5610 = 1;
|
|
}
|
|
g_session.unknown_560C = 1;
|
|
}
|
|
|
|
if (g_session.unknown_5614 != 0 && g_mouse.buttons[0] == 1 && g_session.IsHomunculusSkill(this->unknown_040C)) {
|
|
CGameActor* homun = static_cast<CGameActor*>(this->scene->GetGameActorByAID(homunAid));
|
|
if (homun && homun->HasUnknown030CEntry()) {
|
|
AiMessage message = {};
|
|
message.type = 7;
|
|
message.level = this->unknown_0414;
|
|
message.skill = this->unknown_040C;
|
|
message.target = actor->render.accountId;
|
|
homun->SetUnknown0318(reinterpret_cast<const float*>(&message), 0);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (g_session.unknown_56B0 != 0 && g_mouse.buttons[0] == 1 && HIBYTE(GetAsyncKeyState(VK_MENU))) {
|
|
if (HIBYTE(GetAsyncKeyState(VK_SHIFT))) {
|
|
CGameActor* mercenary = static_cast<CGameActor*>(this->scene->GetGameActorByAID(mercenaryAid));
|
|
if (mercenary && mercenary->HasUnknown0310Entry()) {
|
|
AiMessage message = {};
|
|
message.type = 3;
|
|
message.target = actor->render.accountId;
|
|
mercenary->SetUnknown0330(reinterpret_cast<const float*>(&message), 1);
|
|
}
|
|
} else if (g_session.unknown_56AC != 0 && g_groundMarkAltAid == actor->render.accountId) {
|
|
CGameActor* mercenary = static_cast<CGameActor*>(this->scene->GetGameActorByAID(mercenaryAid));
|
|
if (mercenary && mercenary->HasUnknown0310Entry()) {
|
|
AiMessage message = {};
|
|
message.type = 3;
|
|
message.target = g_groundMarkAltAid;
|
|
mercenary->SetUnknown0318(reinterpret_cast<const float*>(&message), 1);
|
|
}
|
|
g_session.unknown_56AC = 0;
|
|
} else {
|
|
this->SetCursorAction(11);
|
|
g_groundMarkAltAid = actor->render.accountId;
|
|
g_session.unknown_569C = 0;
|
|
g_session.unknown_56A0 = 0;
|
|
g_session.unknown_56A4 = 0;
|
|
g_session.unknown_56AC = 1;
|
|
}
|
|
g_session.unknown_56A8 = 1;
|
|
}
|
|
|
|
int& targetAid = *reinterpret_cast<int*>(&this->unknown_00EC[0x04]);
|
|
int& forced = this->forcedAttack;
|
|
if (attack != 0 && g_session.unknown_56B0 != 0 && g_mouse.buttons[0] == 1 && g_session.IsMercenarySkill(this->unknown_040C)) {
|
|
CGameActor* mercenary = static_cast<CGameActor*>(this->scene->GetGameActorByAID(mercenaryAid));
|
|
if (mercenary && mercenary->HasUnknown0310Entry()) {
|
|
AiMessage message = {};
|
|
message.type = 7;
|
|
message.level = this->unknown_0414;
|
|
message.skill = this->unknown_040C;
|
|
message.target = actor->render.accountId;
|
|
mercenary->SetUnknown0318(reinterpret_cast<const float*>(&message), 1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (g_mouse.buttons[0] == 1 && attack != 0 && !HIBYTE(GetAsyncKeyState(VK_MENU))) {
|
|
this->SendMsg(0x1A, 1, 0, 0, 0);
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[0x08]) = targetAid;
|
|
this->unknown_00F8 = 0;
|
|
if (g_session.GetSceneUnknown004C() == 0 && (HIBYTE(GetAsyncKeyState(VK_CONTROL)) || forceOption != 0)) {
|
|
this->RequestPlayerAction(targetAid, 0);
|
|
forced = 1;
|
|
} else {
|
|
this->RequestPlayerAction(targetAid, 1);
|
|
forced = 0;
|
|
}
|
|
} else if (forced == 0 && g_mouse.buttons[0] == 3) {
|
|
targetAid = 0;
|
|
}
|
|
|
|
if ((this->unknown_00DC != g_screenWidth || this->unknown_00E0 != g_screenHeight) && forced == 0 && g_mouse.buttons[0] == 0) {
|
|
targetAid = 0;
|
|
}
|
|
|
|
this->ShowActorNameBalloon(targetAid);
|
|
if (actor->render.unknown_0070 == 3) {
|
|
targetAid = 0;
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CDD6B0
|
|
// FUNCTION: fn_21317
|
|
CGameActor* CGameMode::NewActor(int job) {
|
|
CGameActor* actor;
|
|
if (IsPlayerJob(job)) {
|
|
actor = new CCharacterNpc;
|
|
} else {
|
|
const char* jobName = g_session.GetJobName(job, -1);
|
|
if (std::strstr(jobName, ".gr2") != nullptr) {
|
|
actor = new C3dGrannyGameActor(jobName);
|
|
} else {
|
|
actor = new CNpc;
|
|
}
|
|
}
|
|
return actor;
|
|
}
|
|
|
|
// GLOBAL: gl_25393
|
|
int g_hoverActorGid;
|
|
|
|
// INLINED
|
|
__forceinline void CGameMode::ShowHoverActorName(CGameActor* actor) {
|
|
this->EnsureNameBalloon(this->itemNameBalloon);
|
|
CActorNameCard card = this->nameCard.Lookup(actor->render.accountId);
|
|
if (!card.received) {
|
|
return;
|
|
}
|
|
|
|
if (actor->unknown_02F8 == 1 && (this->scene->unknown_0048 == 1 || this->scene->unknown_004C == 1)) {
|
|
card.name = "??????";
|
|
} else {
|
|
const std::string name = this->nameCard.Name(actor->render.accountId);
|
|
card.name = name;
|
|
}
|
|
|
|
if (g_session.IsMonsterActor(actor) == 1) {
|
|
UINameBalloonText* balloon = this->itemNameBalloon;
|
|
unsigned char monsterType;
|
|
if (actor->GetEffectiveJob(-1) == 20269) {
|
|
monsterType = 0;
|
|
} else {
|
|
monsterType = actor->unknown_0304;
|
|
}
|
|
balloon->SetName(card, actor->IsPlayerClass(actor->GetEffectiveJob(-1)) == 0, monsterType);
|
|
} else {
|
|
this->itemNameBalloon->SetName(card, actor->IsPlayerClass(actor->GetEffectiveJob(-1)) == 0, 0);
|
|
}
|
|
|
|
const unsigned char showEmblem = g_serviceOptions.Get(0x40);
|
|
if ((g_session.IsNpcJob(actor->GetEffectiveJob(-1)) || g_session.IsMonsterActor(actor)) && card.unknown_0094) {
|
|
this->itemNameBalloon->SetIcon(FormatOwnedString("유저인터페이스\\group\\group_%d.bmp", card.unknown_0094).c_str(), 0);
|
|
} else if (g_session.IsAllyActor(actor->render.accountId, actor->GetEffectiveJob(-1)) && card.unknown_0094) {
|
|
this->nameBalloon->SetIcon(FormatOwnedString("유저인터페이스\\group\\group_%d.bmp", card.unknown_0094).c_str(), 0);
|
|
} else if (actor->Slot50() && showEmblem) {
|
|
std::string emblem = g_guildMgr->GetEmblemFilename(actor->Slot50());
|
|
const unsigned char framedEmblem = g_serviceOptions.Get(0xF3);
|
|
this->itemNameBalloon->SetIcon(emblem.c_str(), static_cast<CGameMode*>(g_modeMgr.GetGameMode())->scene->unknown_004C == 1 && framedEmblem ? 1 : 0);
|
|
} else {
|
|
this->itemNameBalloon->SetIcon("", 0);
|
|
}
|
|
|
|
UINameBalloonText* balloon = this->itemNameBalloon;
|
|
if (balloon) {
|
|
balloon->m_textColor = this->ActorNameColor(actor->GetEffectiveJob(-1), actor->render.accountId);
|
|
balloon->m_outlineColor = 0;
|
|
}
|
|
this->PlaceWindowAtActor(this->itemNameBalloon, actor);
|
|
}
|
|
|
|
// OFFSET: 0x00CDFE10
|
|
// FUNCTION: fn_21328
|
|
int CGameMode::ProcessMousePick(int result, ActorPickInfo* pick) {
|
|
if (g_sub_1319eb4 == 1 && pick) {
|
|
UIMacroReporterWnd* reporter = static_cast<UIMacroReporterWnd*>(g_windowMgr.LookupWindow(286));
|
|
if (reporter && reporter->unknown_010C == true && reporter->m_mode == 0) {
|
|
reporter->sub_7EF2C0(reinterpret_cast<MacroReporterEntry*>(pick));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (g_windowMgr.LookupWindow(196) || reinterpret_cast<std::intptr_t>(this->unknown_0408) == 1) {
|
|
return result;
|
|
}
|
|
|
|
int& lockedPick = this->forcedAttack;
|
|
int& pickTarget = *reinterpret_cast<int*>(&this->unknown_00EC[0x00]);
|
|
int& clickTarget = *reinterpret_cast<int*>(&this->unknown_00EC[0x04]);
|
|
|
|
if (this->unknown_0028 == 0) {
|
|
if (!pick) {
|
|
if (lockedPick != 0 || g_sub_1319eb4 == 1) {
|
|
return result;
|
|
}
|
|
if (this->unknown_00DC == g_screenWidth && this->unknown_00E0 == g_screenHeight) {
|
|
return result;
|
|
}
|
|
pickTarget = 0;
|
|
clickTarget = 0;
|
|
return result;
|
|
}
|
|
} else {
|
|
this->SetCursorAction(5);
|
|
if (lockedPick != 0) {
|
|
if (g_sub_1319eb4 == 1) {
|
|
this->SendMsg(26, 0, 0, 0, 0);
|
|
} else {
|
|
this->SetCursorAction(0);
|
|
if (!pick) {
|
|
return result;
|
|
}
|
|
result = 0;
|
|
}
|
|
} else {
|
|
if (g_sub_1319eb4 == 2) {
|
|
return 1;
|
|
}
|
|
if (!pick && clickTarget == 0 && pickTarget == 0) {
|
|
this->unknown_0028 = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lockedPick == 0) {
|
|
if (clickTarget != 0) {
|
|
if (pick) {
|
|
if (pick->kind == 3) {
|
|
this->SetCursorAction(0);
|
|
return 0;
|
|
}
|
|
if (pick->kind == 4) {
|
|
this->SetCursorAction(0);
|
|
this->ShowActorNameBalloon(pick->accountId);
|
|
return this->HandleActorPick(pick, result);
|
|
}
|
|
}
|
|
|
|
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(clickTarget));
|
|
if (!actor) {
|
|
clickTarget = 0;
|
|
return result;
|
|
}
|
|
this->ProcessActorClick(result, pick, actor);
|
|
return result;
|
|
}
|
|
|
|
if (pickTarget != 0) {
|
|
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(pickTarget));
|
|
if (!actor) {
|
|
pickTarget = 0;
|
|
return result;
|
|
}
|
|
if (lockedPick != 0 && *reinterpret_cast<const int*>(&actor->render.unknown_0060) == 3) {
|
|
lockedPick = 0;
|
|
}
|
|
this->ProcessActorPick(result, pick, actor);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
if (pick && result == 0) {
|
|
this->ShowActorNameBalloon(pick->accountId);
|
|
result = this->HandleActorPick(pick, 0);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#include "Contents/World/WorldModelView.h"
|
|
#include "Contents/World/WorldTerrainPicking.h"
|
|
|
|
void __stdcall SendMacroUserInfoPacket(std::uint16_t first, std::uint16_t second, std::uint8_t third);
|
|
|
|
// OFFSET: 0x00CE0210
|
|
// FUNCTION: fn_21329
|
|
int CGameMode::ProcessGroundClick(int result) {
|
|
const auto drawCell = [](GroundGeometry* ground, const float* matrix, int column, int row, std::uint32_t color) {
|
|
void** groundVtable = *reinterpret_cast<void***>(ground);
|
|
reinterpret_cast<void(__thiscall*)(GroundGeometry*, const float*, int, int, std::uint32_t)>(groundVtable[14])(ground, matrix, column, row, color);
|
|
};
|
|
|
|
UIWindow* macroArea = g_windowMgr.LookupWindow(0x11E);
|
|
if (macroArea) {
|
|
const unsigned char* macroFields = reinterpret_cast<const unsigned char*>(macroArea);
|
|
if (macroFields[0x10C] == 1 && *reinterpret_cast<const int*>(macroFields + 0xEC) == 1) {
|
|
int column = -1;
|
|
int row = -1;
|
|
PickScreenTerrain(g_screenWidth, g_screenHeight, this->camera->frame.eye, this->camera->frame.inverse.values, this->scene->spatial, column, row);
|
|
const int radius = *reinterpret_cast<const int*>(macroFields + 0xF4);
|
|
for (int dx = -radius; dx <= radius; ++dx) {
|
|
for (int dy = -radius; dy <= radius; ++dy) {
|
|
drawCell(this->scene->ground, this->camera->frame.view.values, column + dx, row + dy, 0x660000FF);
|
|
}
|
|
}
|
|
|
|
if (g_mouse.buttons[1] == 1) {
|
|
SendMacroUserInfoPacket(static_cast<std::uint16_t>(column), static_cast<std::uint16_t>(row), static_cast<std::uint8_t>(radius));
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
UIMerchantShopMakeWnd* shop = reinterpret_cast<UIMerchantShopMakeWnd*>(g_windowMgr.unknown_02FC);
|
|
if (!shop && g_windowMgr.unknown_040C) {
|
|
shop = reinterpret_cast<UIMerchantShopMakeWnd*>(g_windowMgr.unknown_040C);
|
|
}
|
|
|
|
bool shopSuspended = false;
|
|
if (shop) {
|
|
if (shop->suspended == 1) {
|
|
shopSuspended = true;
|
|
int column = -1;
|
|
int row = -1;
|
|
PickScreenTerrain(g_screenWidth, g_screenHeight, this->camera->frame.eye, this->camera->frame.inverse.values, this->scene->spatial, column, row);
|
|
drawCell(this->scene->ground, this->camera->frame.view.values, column, row, 0x66FF0000);
|
|
if (g_mouse.buttons[0] == 1) {
|
|
shop->SetSuspended(0);
|
|
shop->SetSelection(static_cast<short>(column), static_cast<short>(row));
|
|
if (g_windowMgr.Confirm(LookupMessage(0xB63), 2, true, false, 0, "Message", 280, 120, 0) == 0xBB) {
|
|
shop->SendShopRequest();
|
|
return -1;
|
|
}
|
|
shop->SetSuspended(1);
|
|
}
|
|
} else if (shop->HasSelection() == true) {
|
|
drawCell(this->scene->ground, this->camera->frame.view.values, shop->unknown_018A, shop->unknown_018C, 0x66FF0000);
|
|
}
|
|
}
|
|
|
|
const std::intptr_t mode = reinterpret_cast<std::intptr_t>(this->unknown_0408);
|
|
if (mode == 2 || mode == 3 || mode == 4) {
|
|
return result;
|
|
}
|
|
|
|
int column = -1;
|
|
int row = -1;
|
|
if (!PickScreenTerrain(g_screenWidth, g_screenHeight, this->camera->frame.eye, this->camera->frame.inverse.values, this->scene->spatial, column, row)) {
|
|
return result;
|
|
}
|
|
|
|
const std::uint32_t homunAid = *reinterpret_cast<const std::uint32_t*>(&g_session.unknown_5570[8]);
|
|
const std::uint32_t mercenaryAid = *reinterpret_cast<const std::uint32_t*>(&g_session.unknown_5620[8]);
|
|
if (g_session.unknown_5614 != 0) {
|
|
if (HIBYTE(GetAsyncKeyState(VK_MENU)) && g_mouse.buttons[1] == 1) {
|
|
if (g_session.unknown_560C != 0) {
|
|
g_session.unknown_560C = 0;
|
|
return result;
|
|
}
|
|
|
|
CGameActor* homun = static_cast<CGameActor*>(this->scene->GetGameActorByAID(homunAid));
|
|
if (HIBYTE(GetAsyncKeyState(VK_SHIFT))) {
|
|
if (homun && homun->HasUnknown030CEntry()) {
|
|
AiMessage message = {};
|
|
message.type = 1;
|
|
message.x = column;
|
|
message.y = row;
|
|
homun->SetUnknown0330(reinterpret_cast<const float*>(&message), 0);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
g_session.unknown_5600 = column;
|
|
g_session.unknown_5604 = row;
|
|
g_groundMarkAid = 0;
|
|
g_session.unknown_5610 = 0;
|
|
if (homun && homun->HasUnknown030CEntry()) {
|
|
AiMessage message = {};
|
|
message.type = 1;
|
|
message.x = column;
|
|
message.y = row;
|
|
homun->SetUnknown0318(reinterpret_cast<const float*>(&message), 0);
|
|
}
|
|
g_session.unknown_5608 = 1;
|
|
return result;
|
|
}
|
|
|
|
if (g_session.unknown_5614 != 0 && g_mouse.buttons[1] == 1) {
|
|
g_session.ClearHomunStatus();
|
|
}
|
|
}
|
|
|
|
if (g_session.unknown_56B0 != 0) {
|
|
if (HIBYTE(GetAsyncKeyState(VK_MENU)) && g_mouse.buttons[0] == 1) {
|
|
if (g_session.unknown_56A8 != 0) {
|
|
g_session.unknown_56A8 = 0;
|
|
return result;
|
|
}
|
|
|
|
CGameActor* mercenary = static_cast<CGameActor*>(this->scene->GetGameActorByAID(mercenaryAid));
|
|
if (HIBYTE(GetAsyncKeyState(VK_SHIFT))) {
|
|
if (mercenary && mercenary->HasUnknown0310Entry()) {
|
|
AiMessage message = {};
|
|
message.type = 1;
|
|
message.x = column;
|
|
message.y = row;
|
|
mercenary->SetUnknown0330(reinterpret_cast<const float*>(&message), 1);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
g_session.unknown_569C = column;
|
|
g_session.unknown_56A0 = row;
|
|
g_groundMarkAltAid = 0;
|
|
g_session.unknown_56AC = 0;
|
|
if (mercenary && mercenary->HasUnknown0310Entry()) {
|
|
AiMessage message = {};
|
|
message.type = 1;
|
|
message.x = column;
|
|
message.y = row;
|
|
mercenary->SetUnknown0318(reinterpret_cast<const float*>(&message), 1);
|
|
}
|
|
g_session.unknown_56A4 = 1;
|
|
return result;
|
|
}
|
|
|
|
if (g_session.unknown_56B0 != 0 && g_mouse.buttons[0] == 1) {
|
|
g_session.ResetMercenaryStats();
|
|
if (reinterpret_cast<std::intptr_t>(this->unknown_0408) == 1 && g_session.IsMercenarySkill(this->unknown_040C)) {
|
|
CGameActor* mercenary = static_cast<CGameActor*>(this->scene->GetGameActorByAID(mercenaryAid));
|
|
if (mercenary && mercenary->HasUnknown0310Entry()) {
|
|
const std::uint32_t state = mercenary->render.unknown_0070;
|
|
if (state == 1 || state == 0 || state == 4) {
|
|
AiMessage message;
|
|
message.type = 8;
|
|
message.x = column;
|
|
message.y = row;
|
|
message.level = this->unknown_0414;
|
|
message.skill = this->unknown_040C;
|
|
message.target = 0;
|
|
mercenary->SetUnknown0318(reinterpret_cast<const float*>(&message), 1);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (reinterpret_cast<std::intptr_t>(this->unknown_0408) == 1 && g_mouse.buttons[0] == 1 && (result == 0 || result == 2)) {
|
|
result = 1;
|
|
if (g_session.IsHomunculusSkill(this->unknown_040C) == 1 && g_session.unknown_5614 == 1) {
|
|
CGameActor* homun = static_cast<CGameActor*>(this->scene->GetGameActorByAID(homunAid));
|
|
if (homun && homun->HasUnknown030CEntry() == true) {
|
|
const std::uint32_t state = homun->render.unknown_0070;
|
|
if (state == 0 || state == 1 || state == 4) {
|
|
AiMessage message;
|
|
message.type = 8;
|
|
message.x = column;
|
|
message.y = row;
|
|
message.level = this->unknown_0414;
|
|
message.skill = this->unknown_040C;
|
|
message.target = 0;
|
|
homun->SetUnknown0318(reinterpret_cast<const float*>(&message), 0);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this->scene->player) {
|
|
const int skill = this->unknown_040C;
|
|
this->scene->player->SendMsg(nullptr, 0x41, 0, skill, skill >> 31, column, column >> 31, row, row >> 31, 0, 0, 0, 0, 0, 0);
|
|
const int level = this->unknown_0414;
|
|
this->scene->player->SendMsg(nullptr, 0x5A, 0, level, level >> 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
if (HIBYTE(GetAsyncKeyState(VK_CONTROL))) {
|
|
return result;
|
|
}
|
|
if (this->unknown_0244 != 0) {
|
|
return result;
|
|
}
|
|
if (result != 0 && result != 2) {
|
|
return result;
|
|
}
|
|
if (this->drag.source != 0) {
|
|
return result;
|
|
}
|
|
|
|
if (*reinterpret_cast<const int*>(g_session.unknown_546C) != 0) {
|
|
g_groundOverlayA = column;
|
|
g_groundOverlayB = row;
|
|
g_groundOverlaySkip = 0;
|
|
int skip = 1;
|
|
const TerrainHeightCell* cell = this->scene->terrain->CellAt(column, row);
|
|
if (!cell || cell->type == 1) {
|
|
g_groundOverlayC = 0xFEFF0000;
|
|
} else if (cell->type == 5) {
|
|
g_groundOverlayC = 0xFEFFFF00;
|
|
} else {
|
|
g_groundOverlayC = 0x6600FFAA;
|
|
skip = 0;
|
|
}
|
|
g_groundOverlaySkip = shopSuspended == true ? 1 : skip;
|
|
}
|
|
|
|
std::uint32_t& clickTick = *reinterpret_cast<std::uint32_t*>(&this->unknown_00D8[0]);
|
|
const bool elapsed = timeGetTime() > clickTick + 600;
|
|
if (this->scene->player->unknown_0508 == 0 && g_mouse.buttons[0] == 2) {
|
|
if (!elapsed) {
|
|
return result;
|
|
}
|
|
if (this->unknown_00F8 == 0) {
|
|
return result;
|
|
}
|
|
} else {
|
|
if (g_mouse.buttons[0] != 1) {
|
|
return result;
|
|
}
|
|
if (g_mouse.buttons[1] == 2) {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
g_windowMgr.UpdateNavigationList();
|
|
clickTick = timeGetTime();
|
|
if (HIBYTE(GetAsyncKeyState(VK_SHIFT)) || g_windowMgr.window_027C || this->scene->player->render.unknown_0070 == 6) {
|
|
this->scene->player->SendMsg(nullptr, 0x10, 0, column, column >> 31, row, row >> 31, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
return result;
|
|
}
|
|
|
|
bool findClosest = true;
|
|
CPlayer* player = this->scene->player;
|
|
const TerrainHeightCell* cell = this->scene->terrain->CellAt(column, row);
|
|
if (cell && cell->type != 1 && cell->type != 5 &&
|
|
(column != *reinterpret_cast<const int*>(&player->unknown_04F8) || row != player->unknown_04FC)) {
|
|
int startColumn;
|
|
int startRow;
|
|
int startSubColumn;
|
|
int startSubRow;
|
|
this->WorldSubcell(player->render.position.x, player->render.position.z, startColumn, startRow, startSubColumn, startSubRow);
|
|
if (this->CanFindPath(startColumn, startRow, startSubColumn, startSubRow, column, row) && !this->IsRegisterCell(column, row)) {
|
|
findClosest = false;
|
|
}
|
|
}
|
|
|
|
if (findClosest && !this->GetClosestValidCell(&column, &row)) {
|
|
return result;
|
|
}
|
|
|
|
if (g_windowMgr.unknown_0210) {
|
|
g_windowMgr.CloseWindow(0x12);
|
|
}
|
|
if (this->scene->player) {
|
|
this->scene->player->SendMsg(nullptr, 0x11, 0, column, column >> 31, row, row >> 31, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#include "Contents/World/WorldOcclusion.h"
|
|
#include "UI/Dialogs/UIMenuWnd.h"
|
|
#include "UI/Window/InputFocus.h"
|
|
|
|
|
|
#include "Client/Application/ApplicationMessages.h"
|
|
#include "Client/ModeFade.h"
|
|
#include "Contents/ActorNameCard.h"
|
|
#include "Contents/Async/AsyncWorkMgr.h"
|
|
#include "Contents/Emblems/EmblemDataMgr.h"
|
|
#include "Client/Stove/StovePCSDK.h"
|
|
#include "Render/ActionSpriteDrawing.h"
|
|
#include "Utility/GGHashMgr.h"
|
|
#include "Contents/Actors/GroundScope.h"
|
|
#include "Contents/Ground/GroundGeometry.h"
|
|
#include "Resource/Sprites/ActionResource.h"
|
|
#include "Resource/Sprites/SpriteResource.h"
|
|
|
|
#pragma pack(push, 1)
|
|
struct StatusPointRequestPacket {
|
|
/* 0000 */ std::uint16_t packetType;
|
|
/* 0002 */ std::uint16_t statusId;
|
|
/* 0004 */ std::uint8_t amount;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(sizeof(StatusPointRequestPacket) == 5);
|
|
|
|
int sub_C7F5A0();
|
|
|
|
// GLOBAL: gl_25463
|
|
std::uint32_t g_spriteAtlasClearTick;
|
|
|
|
// OFFSET: 0x00CDF1E0
|
|
// FUNCTION: fn_21323
|
|
void CGameMode::Update() {
|
|
PumpApplicationMessages();
|
|
this->sub_D08910();
|
|
if (Replay::Instance().AdvanceFrame() == 0) {
|
|
g_windowMgr.window_4F168->SendMsg(nullptr, 35, 0, 0, 0, 0);
|
|
}
|
|
|
|
if (this->running != 0) {
|
|
g_timeScheduler->Process();
|
|
g_playerNameDictionary->Update();
|
|
this->nameCard.ProcessRequests();
|
|
g_guildMgr->UpdateEmblemRequests(
|
|
*g_emblemDataMgr, g_session.m_aid, g_session.m_accountName, reinterpret_cast<const char*>(&g_session.unknown_807C[0x08]), GetRagConnection(),
|
|
*g_asyncWorkMgr
|
|
);
|
|
g_asyncWorkMgr->Update(1000);
|
|
this->ProcessInput();
|
|
|
|
if (g_hoverActorGid != 0) {
|
|
if (g_mouse.buttons[0] != 0) {
|
|
g_hoverActorGid = 0;
|
|
g_followLostTick = 0;
|
|
g_followUpdateTick = 0;
|
|
} else {
|
|
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetActorByGID(g_hoverActorGid));
|
|
if (actor == nullptr) {
|
|
if (g_followLostTick == 0) {
|
|
g_followLostTick = timeGetTime();
|
|
}
|
|
if (timeGetTime() - g_followLostTick > 10000) {
|
|
g_hoverActorGid = 0;
|
|
g_followUpdateTick = 0;
|
|
g_followLostTick = 0;
|
|
}
|
|
} else {
|
|
g_followLostTick = 0;
|
|
if (timeGetTime() - g_followUpdateTick > 1000) {
|
|
g_followUpdateTick = timeGetTime();
|
|
int x = actor->unknown_0158[5];
|
|
int y = *reinterpret_cast<const int*>(actor->unknown_0170);
|
|
int cellX = x;
|
|
int cellY = y;
|
|
if (g_windowMgr.window_027C == nullptr && this->scene->player->render.unknown_0070 != 6) {
|
|
bool reachable = true;
|
|
if (!this->IsValidCell(x, y)) {
|
|
reachable = this->GetClosestValidCell(&cellX, &cellY);
|
|
x = cellX;
|
|
y = cellY;
|
|
}
|
|
if (reachable) {
|
|
if (g_windowMgr.unknown_0210 != nullptr) {
|
|
g_windowMgr.CloseWindow(0x12);
|
|
}
|
|
this->scene->player->SendMsg(nullptr, 0x11, 0, x, x >> 31, y, y >> 31, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
} else {
|
|
this->scene->player->SendMsg(nullptr, 0x10, 0, x, x >> 31, y, y >> 31, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this->UpdateLoopSounds();
|
|
|
|
g_soundMgr->Update();
|
|
if (g_soundMgr->IsComplete() && g_soundMgr->secondaryEnabled != 0) {
|
|
g_soundMgr->secondaryEnabled = 0;
|
|
if (g_soundMgr->IsStopped()) {
|
|
CSoundMgr::Pause(g_soundMgr, 0);
|
|
} else {
|
|
g_soundMgr->SetDefaultName(g_session.GetBgmFileName(this->MapName().c_str()));
|
|
}
|
|
}
|
|
|
|
g_nProtectGameGuardMgr->Stop();
|
|
g_ggHashMgr->VerifyPendingFiles();
|
|
if (g_session.unknown_5912) {
|
|
Base_RunCallback();
|
|
}
|
|
|
|
if (g_updateTick > 0) {
|
|
SendGameTick(
|
|
false, *reinterpret_cast<std::uint32_t*>(&this->unknown_026E[0x02]), *reinterpret_cast<std::uint32_t*>(&this->unknown_026E[0x06]), g_gameTickInterval,
|
|
GetRagConnection(), g_packetLengths, g_pingLogEnabled, g_pingLogFirstTick, g_pingLogTicks
|
|
);
|
|
if (timeGetTime() > g_spriteAtlasClearTick) {
|
|
g_spriteAtlasClearTick = timeGetTime() + 15000;
|
|
g_renderer->atlas.ClearExpired(g_resourceReuseDelay);
|
|
}
|
|
}
|
|
|
|
const int frames = GetSkipFrameCount();
|
|
g_updateTick = frames;
|
|
this->ProcessInput();
|
|
ResourceMgr::Instance().UpdateTransient();
|
|
if (frames > 0) {
|
|
for (int frame = frames; frame != 0; --frame) {
|
|
g_effectMgr->Update();
|
|
this->scene->OnProcess();
|
|
this->scene->ground->Slot19();
|
|
this->camera->Update();
|
|
}
|
|
} else if (frames == 0) {
|
|
this->scene->OnProcess();
|
|
this->camera->Update();
|
|
}
|
|
}
|
|
|
|
if (g_restoreSurfaces != 0) {
|
|
g_restoreSurfaces = 0;
|
|
GetRenderSystemHolder()->TestDevice();
|
|
g_windowMgr.InvalidateAll();
|
|
}
|
|
|
|
g_weatherEffect.Process();
|
|
if (g_isAppActive == 0 && GetRenderSystemHolder()->IsWindowed()) {
|
|
return;
|
|
}
|
|
|
|
if (sub_C7F5A0()) {
|
|
g_renderer->ClearWorld();
|
|
g_actorPickNode.Clear();
|
|
this->camera->Render();
|
|
this->DrawMiniMap();
|
|
g_windowMgr.CenterSurface0478();
|
|
g_windowMgr.DrawWindows();
|
|
g_mapInfoMgr->DrawMapName(*GetRenderSystemHolder()->system);
|
|
if (this->scene->unknown_0048 != 0 || *reinterpret_cast<const int*>(&g_session.unknown_5454[0x08]) != 0) {
|
|
this->DrawMiniMapCoordinates();
|
|
this->DrawTimeAttackTimer();
|
|
}
|
|
if (*reinterpret_cast<const int*>(&g_session.unknown_07A4[0x08]) != 0) {
|
|
this->DrawTimeAttackCountdown(*reinterpret_cast<const std::uint32_t*>(&g_session.unknown_07A4[0x00]), *reinterpret_cast<const int*>(g_session.unknown_079C));
|
|
}
|
|
|
|
if (this->drag.source != 0 && (g_windowMgr.window_01EC == nullptr || g_windowMgr.window_01EC->geometry.visible == 0)) {
|
|
if (this->drag.source == 0x1D) {
|
|
if (g_windowMgr.Window4F250Ready()) {
|
|
g_windowMgr.MoveTransient(g_mouse.x, g_mouse.y);
|
|
}
|
|
} else if (this->drag.resource.empty()) {
|
|
this->drag.Clear();
|
|
} else {
|
|
const std::string resource = this->drag.resource;
|
|
CSprRes* sprite = static_cast<CSprRes*>(ResourceMgr::Instance().Load((resource + ".spr").c_str()));
|
|
CActRes* action = static_cast<CActRes*>(ResourceMgr::Instance().Load((resource + ".act").c_str()));
|
|
DrawActionSprite(*GetRenderSystemHolder()->system, g_mouse.x, g_mouse.y, action, sprite, 0, 0, 1.0f, 0.0f, 0xFAFFFFFF, 0x201);
|
|
}
|
|
}
|
|
|
|
this->DrawCursor();
|
|
this->DrawMiniMapNumber();
|
|
this->DrawFadeIn();
|
|
if (g_renderer->Draw()) {
|
|
g_renderer->DrawOverlays(*GetRenderSystemHolder()->system);
|
|
}
|
|
g_renderer->Present(1);
|
|
}
|
|
|
|
this->TakeScreenshot();
|
|
|
|
for (int index = 0; index < 6; ++index) {
|
|
unsigned char& pending = this->unknown_05EC[1 + index];
|
|
if (pending == 0) {
|
|
continue;
|
|
}
|
|
|
|
StatusPointRequestPacket packet;
|
|
packet.packetType = 0xBB;
|
|
if (index == 0) {
|
|
packet.statusId = 13;
|
|
} else if (index == 1) {
|
|
packet.statusId = 14;
|
|
} else if (index == 2) {
|
|
packet.statusId = 18;
|
|
} else if (index == 3) {
|
|
packet.statusId = 16;
|
|
} else if (index == 4) {
|
|
packet.statusId = 15;
|
|
} else if (index == 5) {
|
|
packet.statusId = 17;
|
|
}
|
|
packet.amount = 1;
|
|
if (this->unknown_0250 == 0) {
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.packetType), &packet);
|
|
--pending;
|
|
}
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CE0B80
|
|
// FUNCTION: fn_21330
|
|
void CGameMode::ProcessInput() {
|
|
g_mouse.Update();
|
|
int handled = g_windowMgr.ProcessMouse();
|
|
g_windowMgr.UpdateFrameWindows();
|
|
this->UpdateBalloons();
|
|
this->ExpireTooltip();
|
|
this->ProcessRightButtonDrag();
|
|
this->ProcessMouseWheel(handled);
|
|
|
|
if (timeGetTime() > *reinterpret_cast<std::uint32_t*>(this->unknown_01E0) + 1000) {
|
|
g_windowMgr.InvalidateRegisteredWindows();
|
|
*reinterpret_cast<std::uint32_t*>(this->unknown_01E0) = timeGetTime();
|
|
}
|
|
|
|
if (handled == 2) {
|
|
handled = 0;
|
|
}
|
|
|
|
if (this->unknown_0408 != nullptr) {
|
|
if (*reinterpret_cast<int*>(&g_session.unknown_544C[0x00]) == 0) {
|
|
if (g_mouse.wheel > 0) {
|
|
this->SendMsg(0x5D, 1, 0, 0, 0);
|
|
} else if (g_mouse.wheel < 0) {
|
|
this->SendMsg(0x5E, 1, 0, 0, 0);
|
|
}
|
|
}
|
|
*reinterpret_cast<int*>(&g_session.unknown_544C[0x00]) = 0;
|
|
}
|
|
|
|
if (g_mouse.buttons[0] == 3) {
|
|
if (this->scene->player) {
|
|
this->scene->player->SendMsg(nullptr, 0xF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
this->SendMsg(0x11, g_mouse.x, g_mouse.y, 0, 0);
|
|
UIMenuWnd* menu = static_cast<UIMenuWnd*>(g_windowMgr.unknown_0210);
|
|
if (menu) {
|
|
if (menu->unknown_00DC) {
|
|
menu->unknown_00DC = 0;
|
|
} else {
|
|
g_windowMgr.CloseWindow(0x12);
|
|
}
|
|
}
|
|
this->unknown_00F8 = 1;
|
|
}
|
|
|
|
g_pickModifierKey = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
ActorPickInfo* pick = g_actorPickNode.Pick(static_cast<float>(g_mouse.x), static_cast<float>(g_mouse.y));
|
|
UIWindow* blocker = g_windowMgr.LookupWindow(0x271B);
|
|
if (!blocker) {
|
|
this->OpenActorMenu(pick, handled);
|
|
}
|
|
|
|
this->cursorOffsetX = 0.0f;
|
|
this->cursorOffsetY = 0.0f;
|
|
if (handled == 0) {
|
|
const std::intptr_t mode = reinterpret_cast<std::intptr_t>(this->unknown_0408);
|
|
g_session.UpdateUnknown1708(mode == 2 || mode == 4);
|
|
if (pick) {
|
|
bool offset;
|
|
if (this->unknown_040C == 0xE7) {
|
|
offset = g_session.IsSkillIdInRange6001(pick->job) && pick->kind == 4;
|
|
} else {
|
|
int eligible;
|
|
if (g_session.unknown_1708 && g_session.IsMonsterClass(pick->job)) {
|
|
eligible = 1;
|
|
} else if (g_serviceOptions.Get(0x2F)) {
|
|
eligible = pick->kind == 1;
|
|
} else {
|
|
eligible = 0;
|
|
}
|
|
offset = pick->kind != 3 && pick->kind != 4 && eligible;
|
|
}
|
|
if (offset) {
|
|
this->cursorOffsetX = (pick->left - pick->right) * g_depthAverageHalf + pick->right - static_cast<float>(g_mouse.x);
|
|
this->cursorOffsetY = (pick->top - pick->bottom) * g_depthAverageHalf + pick->bottom - static_cast<float>(g_mouse.y);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this->scene && this->scene->player && g_renderer) {
|
|
MarkScreenWorldOcclusion(
|
|
this->scene->player->render.screenX, this->scene->player->render.screenY, g_renderer->viewport.uiScaleY, this->camera->frame.eye,
|
|
this->camera->frame.inverse.values, this->scene->player->render.position.y, this->camera->camera.distance, this->scene->spatial, *this->scene->ground,
|
|
this->unknown_0458 != 0
|
|
);
|
|
}
|
|
|
|
if (this->unknown_0250 == 0 && (this->unknown_024C == 0 || this->scene->player->unknown_0264[3] != 0) && !blocker && g_windowMgr.window_0288 == nullptr &&
|
|
!g_windowMgr.LookupWindow(0x169)) {
|
|
handled = this->ProcessGroundClick(this->ProcessMousePick(handled, pick));
|
|
this->UpdateHoverNameBalloon();
|
|
if (handled != 1 && g_mouse.buttons[0] == 1) {
|
|
g_windowMgr.SetFocus(nullptr);
|
|
}
|
|
} else if (pick && handled == 0) {
|
|
this->ShowActorNameBalloon(pick->accountId);
|
|
}
|
|
|
|
if ((handled == 1 || g_mouse.buttons[0] == 1) && g_mouse.buttons[0] == 1) {
|
|
g_unknown173AD3F = false;
|
|
this->SendMsg(0x47, 0, 0, 0, 0);
|
|
if (timeGetTime() > this->unknown_0248 + 5000) {
|
|
this->unknown_0244 = 0;
|
|
}
|
|
*reinterpret_cast<std::uint32_t*>(this->unknown_00D8) = timeGetTime();
|
|
}
|
|
|
|
const bool statusIcons = g_serviceOptions.Get(0xC9) != 0;
|
|
if (Replay::Instance().state != 6 && statusIcons) {
|
|
this->ProcessStatusIconTooltip(g_mouse.x, g_mouse.y);
|
|
}
|
|
|
|
if (handled == 0) {
|
|
if (this->unknown_0408 != nullptr) {
|
|
this->SetCursorAction(10);
|
|
} else if (g_mouse.buttons[1] != 2) {
|
|
int column = -1;
|
|
int row = -1;
|
|
PickScreenTerrain(
|
|
g_mouse.x, g_mouse.y, this->camera->frame.eye, this->camera->frame.inverse.values, this->scene->spatial,
|
|
column, row
|
|
);
|
|
const TerrainHeightCell* cell = this->scene->terrain->CellAt(column, row);
|
|
if (cell && cell->type != 1 && cell->type != 5) {
|
|
this->SetCursorAction(0);
|
|
} else {
|
|
this->SetCursorAction(13);
|
|
}
|
|
}
|
|
}
|
|
|
|
this->unknown_00DC = g_mouse.x;
|
|
this->unknown_00E0 = g_mouse.y;
|
|
}
|
|
|
|
// OFFSET: 0x00CE1010
|
|
// FUNCTION: fn_21331
|
|
void CGameMode::UpdateHoverNameBalloon() {
|
|
CGameActor* actor;
|
|
if (g_hoverActorGid) {
|
|
actor = static_cast<CGameActor*>(this->scene->GetActorByGID(g_hoverActorGid));
|
|
if (!actor) {
|
|
return;
|
|
}
|
|
|
|
if (actor->render.visible == 1 && actor->render.enabled == 1 && !StateFlag02(actor->Slot13())) {
|
|
this->ShowHoverActorName(actor);
|
|
}
|
|
} else {
|
|
if (!this->unknown_0028) {
|
|
this->SendMsg(5, 0, 0, 0, 0);
|
|
return;
|
|
}
|
|
|
|
actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(*reinterpret_cast<std::uint32_t*>(&this->unknown_00EC[8])));
|
|
if (!actor) {
|
|
return;
|
|
}
|
|
|
|
if (!actor->unknown_0314 && actor->render.visible == 1 && actor->render.enabled == 1 && !StateFlag02(actor->Slot13())) {
|
|
*reinterpret_cast<int*>(&this->unknown_02B8[0x10]) = 0;
|
|
this->ShowHoverActorName(actor);
|
|
}
|
|
}
|
|
|
|
if (actor->GetEffectiveJob(-1) != 45 &&
|
|
(actor->unknown_0314 || (actor->render.visible == 1 && actor->render.enabled == 1 && !StateFlag02(actor->Slot13())))) {
|
|
this->SendMsg(4, static_cast<int>(actor->render.position.x), static_cast<int>(actor->render.position.z), 0, 0);
|
|
return;
|
|
}
|
|
|
|
this->SendMsg(5, 0, 0, 0, 0);
|
|
}
|
|
|
|
#include "Client/Browser/WebBrowser.h"
|
|
#include "Contents/Configuration/GameSettingsMgr.h"
|
|
#include <direct.h>
|
|
#include <format>
|
|
#include <io.h>
|
|
|
|
#pragma pack(push, 1)
|
|
struct TalkWhisperSettingPacket {
|
|
/* 0000 */ std::int16_t id;
|
|
/* 0002 */ char name[0x18];
|
|
/* 001A */ unsigned char type;
|
|
};
|
|
|
|
struct TalkConfigPacket {
|
|
/* 0000 */ std::int16_t id;
|
|
/* 0002 */ unsigned char value;
|
|
};
|
|
|
|
struct TalkIntPacket {
|
|
/* 0000 */ std::int16_t id;
|
|
/* 0002 */ int value;
|
|
};
|
|
|
|
struct TalkSelectPacket {
|
|
/* 0000 */ std::int16_t id;
|
|
/* 0002 */ unsigned char enabled;
|
|
/* 0003 */ int value;
|
|
/* 0007 */ unsigned char option;
|
|
};
|
|
|
|
struct TalkCameraPacket {
|
|
/* 0000 */ std::int16_t id;
|
|
/* 0002 */ unsigned char action;
|
|
/* 0003 */ float range;
|
|
/* 0007 */ float rotation;
|
|
/* 000B */ float latitude;
|
|
};
|
|
|
|
struct TalkNamePacket {
|
|
/* 0000 */ std::int16_t id;
|
|
/* 0002 */ char name[0x10];
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
static_assert(sizeof(TalkWhisperSettingPacket) == 0x1B);
|
|
static_assert(sizeof(TalkCameraPacket) == 0xF);
|
|
static_assert(sizeof(TalkSelectPacket) == 8);
|
|
|
|
// OFFSET: 0x00CE4B90
|
|
// FUNCTION: fn_21338
|
|
void CGameMode::ExecuteTalkType(int talkType, std::string* arguments) {
|
|
std::string defaults[3];
|
|
std::string* parts = arguments ? arguments : defaults;
|
|
if (g_serviceType == 4 && talkType == 6) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x5F)), 0xFFFF, 0, 0, 0);
|
|
return;
|
|
}
|
|
|
|
switch (talkType) {
|
|
case 57:
|
|
g_windowMgr.SetUnknown04DC(parts[0].c_str());
|
|
this->SendMsg(0x81, 0, 0, 0, 0);
|
|
break;
|
|
case 18:
|
|
case 19: {
|
|
this->unknown_0118 = parts[0];
|
|
if (this->unknown_0118.size() > 0x18) {
|
|
break;
|
|
}
|
|
TalkWhisperSettingPacket packet;
|
|
if (talkType == 18) {
|
|
g_whisperBlockMgr->Add(this->unknown_0118);
|
|
} else {
|
|
g_whisperBlockMgr->Remove(this->unknown_0118);
|
|
}
|
|
packet.id = ID_CZ_SETTING_WHISPER_PC;
|
|
StringFormat(packet.name, 0x18, static_cast<std::size_t>(-1), "%s", parts[0].c_str());
|
|
packet.type = talkType == 18 ? 0 : 1;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.id), &packet);
|
|
break;
|
|
}
|
|
case 52:
|
|
g_windowMgr.SendNotice(7, 0, 0, 0, 0, 0);
|
|
break;
|
|
case 104: {
|
|
if (g_session.IsAdminSubMode(7) == 0) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x5F)), 0xFFFF, 0, 0, 0);
|
|
break;
|
|
}
|
|
char text[128];
|
|
g_whisperRecord = 1 - g_whisperRecord;
|
|
if (g_whisperRecord != 0) {
|
|
CGameMode* mode = static_cast<CGameMode*>(g_modeMgr.GetGameMode());
|
|
if (g_session.IsAdminSubMode(7) != 0) {
|
|
char directory[3000];
|
|
mode->chatLogLines = 0;
|
|
std::sprintf(directory, "%s\\Chat", g_applicationDirectory);
|
|
int index = 0;
|
|
if (_access(directory, 0) == 0 || _mkdir(directory) == 0) {
|
|
std::sprintf(g_chatLogPath, "%s\\Chat\\Chat.txt", g_applicationDirectory);
|
|
if (_access(g_chatLogPath, 0) == 0) {
|
|
do {
|
|
++index;
|
|
std::sprintf(g_chatLogPath, "%s\\Chat\\Chat%03d.txt", g_applicationDirectory, index);
|
|
} while (_access(g_chatLogPath, 0) == 0);
|
|
}
|
|
}
|
|
}
|
|
std::sprintf(text, "Chatting Auto Save Start..");
|
|
} else {
|
|
std::sprintf(text, "Chatting Auto Save END");
|
|
g_modeMgr.GetGameMode();
|
|
sub_CCFF10();
|
|
}
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
|
|
break;
|
|
}
|
|
case 3:
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x5F)), 0xFFFF, 0, 0, 0);
|
|
break;
|
|
case 0:
|
|
case 50: {
|
|
char text[364];
|
|
int party = 0;
|
|
int alternate = 0;
|
|
std::strcpy(text, g_windowMgr.unknown_04DC.c_str());
|
|
if (text[0] == '%') {
|
|
if (std::strlen(text) <= 1) {
|
|
break;
|
|
}
|
|
g_windowMgr.SetUnknown04DC(text + 1);
|
|
party = 1;
|
|
} else if (text[0] == '$') {
|
|
if (std::strlen(text) <= 1) {
|
|
break;
|
|
}
|
|
g_windowMgr.SetUnknown04DC(text + 1);
|
|
alternate = 1;
|
|
}
|
|
if (HIBYTE(GetAsyncKeyState(VK_CONTROL))) {
|
|
party = 1;
|
|
}
|
|
if (HIBYTE(GetAsyncKeyState(VK_MENU))) {
|
|
alternate = 1;
|
|
}
|
|
bool clan = false;
|
|
if (text[0] == '#') {
|
|
if (std::strlen(text) <= 1) {
|
|
break;
|
|
}
|
|
g_windowMgr.SetUnknown04DC(text + 1);
|
|
clan = true;
|
|
}
|
|
int clanChat = clan;
|
|
if (HIBYTE(GetAsyncKeyState(VK_CAPITAL))) {
|
|
clanChat = 1;
|
|
}
|
|
if (talkType == 50) {
|
|
this->SendMsg(6, 0, 0, 0, 0);
|
|
break;
|
|
}
|
|
if (g_session.unknown_5484 != 0) {
|
|
this->SendMsg(0xFE, 0, 0, 0, 0);
|
|
break;
|
|
}
|
|
const int sendMode = *reinterpret_cast<const int*>(&g_session.unknown_5490[8]);
|
|
if (sendMode == 2 && g_guildInfo.m_guildId != 0) {
|
|
this->SendMsg(alternate ? 6 : 0x81, 0, 0, 0, 0);
|
|
break;
|
|
}
|
|
if (sendMode == 1) {
|
|
if (party == 0 && g_session.PartyCount() != 0) {
|
|
this->SendMsg(0x42, 0, 0, 0, 0);
|
|
} else {
|
|
this->SendMsg(6, 0, 0, 0, 0);
|
|
}
|
|
break;
|
|
}
|
|
if (sendMode == 3 && g_clanInfo->m_hasClan == 1) {
|
|
this->SendMsg(0x121, 0, 0, 0, 0);
|
|
break;
|
|
}
|
|
if (sendMode == 4 && g_guildInfo.m_guildId != 0) {
|
|
this->SendMsg(static_cast<char>(clanChat) ? 6 : 0x14A, 0, 0, 0, 0);
|
|
break;
|
|
}
|
|
if (party != 0 && g_session.PartyCount() != 0) {
|
|
this->SendMsg(0x42, 0, 0, 0, 0);
|
|
} else if (alternate != 0) {
|
|
this->SendMsg(0x81, 0, 0, 0, 0);
|
|
} else if (static_cast<char>(clanChat)) {
|
|
this->SendMsg(0x14A, 0, 0, 0, 0);
|
|
} else {
|
|
this->SendMsg(6, 0, 0, 0, 0);
|
|
}
|
|
break;
|
|
}
|
|
case 151: {
|
|
char text[256];
|
|
if (std::strcmp(parts[0].c_str(), "") == 0) {
|
|
g_session.sub_DE3D90(nullptr);
|
|
std::sprintf(text, "[ To Friends ] : (Hi) *^_^*");
|
|
} else {
|
|
char* message = const_cast<char*>(g_windowMgr.unknown_04DC.c_str());
|
|
std::string copy(message);
|
|
g_session.sub_DE3D90(message);
|
|
if (g_serviceType == 0) {
|
|
std::sprintf(text, "[ To Friends ] : (Hi) %s", copy.c_str());
|
|
} else {
|
|
std::sprintf(text, "[ To Friends ] : (Hi) %s%s", g_serverLanguage->Prefix(false), copy.c_str());
|
|
}
|
|
}
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0x1EFFFF, 0, 0, 0);
|
|
break;
|
|
}
|
|
case 149:
|
|
for (int count = 32; count != 0; --count) {
|
|
this->SendMsg(0x5B, reinterpret_cast<int>("LEVEL"), 0, 0, 0);
|
|
}
|
|
break;
|
|
case 150:
|
|
for (int count = 5; count != 0; --count) {
|
|
this->SendMsg(0x5B, reinterpret_cast<int>("SPPOINT"), 0, 0, 0);
|
|
this->SendMsg(0x5B, reinterpret_cast<int>("JOBLEVEL"), 0, 0, 0);
|
|
}
|
|
break;
|
|
case 145: {
|
|
const char* text;
|
|
if (g_randomLoadingScreen) {
|
|
g_randomLoadingScreen = false;
|
|
text = "RANDOM LOADING SCREEN ON";
|
|
} else {
|
|
g_randomLoadingScreen = true;
|
|
text = "RANDOM LOADING SCREEN OFF";
|
|
}
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0x6E96FF, 0, 0, 0);
|
|
break;
|
|
}
|
|
case 115:
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x71, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x6C, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x6D, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x8D, 0, 0, 0);
|
|
break;
|
|
case 138:
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x71, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x6C, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x6D, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x78, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x79, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x8D, 0, 0, 0);
|
|
break;
|
|
case 166:
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x71, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x6C, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x6D, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x8D, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0xA5, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x87, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0xA7, 0, 0, 0);
|
|
break;
|
|
case 122:
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x78, 0, 0, 0);
|
|
g_modeMgr.gameMode->SendMsg(0x2A, 0x79, 0, 0, 0);
|
|
break;
|
|
case 113:
|
|
g_serviceOptions.Set(0x71, !g_serviceOptions.Get(0x71));
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(g_serviceOptions.Get(0x71) ? 0x2DA : 0x2DB)), 0x64FFFF, 0, 0, 0);
|
|
break;
|
|
case 165:
|
|
g_serviceOptions.Set(0xA5, !g_serviceOptions.Get(0xA5));
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(g_serviceOptions.Get(0xA5) ? 0x414 : 0x415)), 0x64FFFF, 0, 0, 0);
|
|
g_windowMgr.sub_AAB090();
|
|
break;
|
|
case 243:
|
|
g_serviceOptions.Set(0xF3, !g_serviceOptions.Get(0xF3));
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(g_serviceOptions.Get(0xF3) ? 0xDC7 : 0xDC8)), 0x64FFFF, 0, 0, 0);
|
|
g_windowMgr.sub_AAB090();
|
|
break;
|
|
case 135:
|
|
g_windowMgr.chatModeChanged = g_windowMgr.chatModeChanged == 0;
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
if (g_windowMgr.chatModeChanged) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x311)), 0x64FFFF, 0, 0, 0);
|
|
} else {
|
|
if (!g_windowMgr.inputSuggestionsEnabled) {
|
|
ChatWindow()->ToggleInput();
|
|
}
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x312)), 0x64FFFF, 0, 0, 0);
|
|
}
|
|
break;
|
|
case 186:
|
|
g_session.unknown_5484 = 1 - g_session.unknown_5484;
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(g_session.unknown_5484 ? 0x555 : 0x556)), 0x64FFFF, 0, 0, 0);
|
|
break;
|
|
case 153:
|
|
g_windowToggleFlag = !g_windowToggleFlag;
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
if (g_windowToggleFlag) {
|
|
g_windowMgr.sub_A978D0(0x74);
|
|
} else {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x3AF)), 0x64FFFF, 0, 0, 0);
|
|
}
|
|
break;
|
|
case 162:
|
|
g_session.m_traceAi = g_session.m_traceAi == 0;
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
if (g_session.m_traceAi != 0) {
|
|
char path[256];
|
|
GetCurrentDirectoryA(sizeof(path), path);
|
|
char* data = std::strstr(path, "\\data");
|
|
if (data) {
|
|
std::memcpy(path, path, data - path);
|
|
}
|
|
std::strcat(path, "\\TraceAI.txt");
|
|
CFile file;
|
|
file.Open(path, 0x1001, true, false);
|
|
file.Write("", 0);
|
|
file.Close();
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x3BC)), 0x64FFFF, 0, 0, 0);
|
|
} else {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x3BD)), 0x64FFFF, 0, 0, 0);
|
|
}
|
|
break;
|
|
case 12: {
|
|
const int volume = std::atoi(parts[0].c_str());
|
|
g_soundMgr->SetSampleVolume(volume);
|
|
g_soundMgr->Set3DVolume(volume);
|
|
char text[120];
|
|
std::sprintf(text, "%s %d", LookupMessage(0x19), volume);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0x64FFFF, 0, 0, 0);
|
|
g_windowMgr.sub_AAB090();
|
|
break;
|
|
}
|
|
case 13: {
|
|
const int volume = std::atoi(parts[0].c_str());
|
|
CSoundMgr::SetVolume(g_soundMgr, volume);
|
|
g_soundMgr->SetTargetVolume(CSoundMgr::Volume(g_soundMgr));
|
|
char text[120];
|
|
std::sprintf(text, "%s %d", LookupMessage(0x1A), volume);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0x64FFFF, 0, 0, 0);
|
|
g_windowMgr.sub_AAB090();
|
|
break;
|
|
}
|
|
case 11:
|
|
g_serviceOptions.Set(0xB, !g_serviceOptions.Get(0xB));
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(g_serviceOptions.Get(0xB) ? 0x1B : 0x1C)), 0x64FFFF, 0, 0, 0);
|
|
if (g_serviceOptions.Get(0xB)) {
|
|
g_soundMgr->unknown = 0;
|
|
}
|
|
g_windowMgr.sub_AAB090();
|
|
break;
|
|
case 195:
|
|
g_soundMgr->unknown = g_soundMgr->unknown == 0;
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(g_soundMgr->unknown ? 0x5DA : 0x5DB)), 0x64FFFF, 0, 0, 0);
|
|
break;
|
|
case 10:
|
|
g_frameskip = 1 - g_frameskip;
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(g_frameskip ? 0x1D : 0x1E)), 0x64FFFF, 0, 0, 0);
|
|
break;
|
|
case 7:
|
|
g_serviceOptions.Set(7, !g_serviceOptions.Get(7));
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(g_serviceOptions.Get(7) ? 0x1F : 0x20)), 0x64FFFF, 0, 0, 0);
|
|
if (g_serviceOptions.Get(7)) {
|
|
g_soundMgr->PlayStream(nullptr, 0, false);
|
|
} else {
|
|
g_soundMgr->StopStreams();
|
|
}
|
|
g_windowMgr.sub_AAB090();
|
|
break;
|
|
case 49: {
|
|
const int third = std::atoi(parts[2].c_str());
|
|
const int second = std::atoi(parts[1].c_str());
|
|
this->SendMsg(0x5C, reinterpret_cast<int>(parts[0].c_str()), second, third, 0);
|
|
break;
|
|
}
|
|
case 44: {
|
|
std::string value(parts[0].c_str());
|
|
LowercaseText(value);
|
|
if (value == "off" || value == "on") {
|
|
this->SendMsg(0x55, value == "off" ? 0 : 1, 0, 0, 0);
|
|
}
|
|
break;
|
|
}
|
|
case 25: {
|
|
const std::uint32_t id = this->nameCard.FindId(parts[0].c_str());
|
|
if (id != 0) {
|
|
this->SendMsg(0x31, id, 0, 0, 0);
|
|
}
|
|
break;
|
|
}
|
|
case 42:
|
|
if (!g_windowMgr.CloseWindow(0x13B)) {
|
|
g_windowMgr.sub_A978D0(0x13B);
|
|
}
|
|
break;
|
|
case 29:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_SURPRISE"), 0, 0, 0);
|
|
break;
|
|
case 30:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_QUESTION"), 0, 0, 0);
|
|
break;
|
|
case 31:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_DELIGHT"), 0, 0, 0);
|
|
break;
|
|
case 32:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_THROB"), 0, 0, 0);
|
|
break;
|
|
case 33:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_SWEAT"), 0, 0, 0);
|
|
break;
|
|
case 34:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_AHA"), 0, 0, 0);
|
|
break;
|
|
case 35:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_FRET"), 0, 0, 0);
|
|
break;
|
|
case 36:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_ANGER"), 0, 0, 0);
|
|
break;
|
|
case 37:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_MONEY"), 0, 0, 0);
|
|
break;
|
|
case 38:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_THINK"), 0, 0, 0);
|
|
break;
|
|
case 39:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_SCISSOR"), 0, 0, 0);
|
|
break;
|
|
case 40:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_ROCK"), 0, 0, 0);
|
|
break;
|
|
case 41:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_WRAP"), 0, 0, 0);
|
|
break;
|
|
case 79:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_BIGTHROB"), 0, 0, 0);
|
|
break;
|
|
case 66:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_THANKS"), 0, 0, 0);
|
|
break;
|
|
case 67:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_KEK"), 0, 0, 0);
|
|
break;
|
|
case 68:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_SORRY"), 0, 0, 0);
|
|
break;
|
|
case 69:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_SMILE"), 0, 0, 0);
|
|
break;
|
|
case 70:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_PROFUSELY_SWEAT"), 0, 0, 0);
|
|
break;
|
|
case 71:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_SCRATCH"), 0, 0, 0);
|
|
break;
|
|
case 72:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_BEST"), 0, 0, 0);
|
|
break;
|
|
case 73:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_STARE_ABOUT"), 0, 0, 0);
|
|
break;
|
|
case 74:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_HUK"), 0, 0, 0);
|
|
break;
|
|
case 75:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_O"), 0, 0, 0);
|
|
break;
|
|
case 76:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_X"), 0, 0, 0);
|
|
break;
|
|
case 77:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_HELP"), 0, 0, 0);
|
|
break;
|
|
case 78:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_GO"), 0, 0, 0);
|
|
break;
|
|
case 80:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_CRY"), 0, 0, 0);
|
|
break;
|
|
case 81:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_KIK"), 0, 0, 0);
|
|
break;
|
|
case 82:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_CHUP"), 0, 0, 0);
|
|
break;
|
|
case 83:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_CHUPCHUP"), 0, 0, 0);
|
|
break;
|
|
case 84:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_HNG"), 0, 0, 0);
|
|
break;
|
|
case 85:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_OK"), 0, 0, 0);
|
|
break;
|
|
case 123:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_STARE"), 0, 0, 0);
|
|
break;
|
|
case 124:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_HUNGRY"), 0, 0, 0);
|
|
break;
|
|
case 125:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_COOL"), 0, 0, 0);
|
|
break;
|
|
case 126:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_MERONG"), 0, 0, 0);
|
|
break;
|
|
case 127:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_SHY"), 0, 0, 0);
|
|
break;
|
|
case 128:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_GOODBOY"), 0, 0, 0);
|
|
break;
|
|
case 129:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_SPTIME"), 0, 0, 0);
|
|
break;
|
|
case 130:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_SEXY"), 0, 0, 0);
|
|
break;
|
|
case 131:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_COMEON"), 0, 0, 0);
|
|
break;
|
|
case 132:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_SLEEPY"), 0, 0, 0);
|
|
break;
|
|
case 133:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_CONGRATULATION"), 0, 0, 0);
|
|
break;
|
|
case 134:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_HPTIME"), 0, 0, 0);
|
|
break;
|
|
case 154:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_SPARK"), 0, 0, 0);
|
|
break;
|
|
case 155:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_CONFUSE"), 0, 0, 0);
|
|
break;
|
|
case 156:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_OHNO"), 0, 0, 0);
|
|
break;
|
|
case 157:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_HUM"), 0, 0, 0);
|
|
break;
|
|
case 158:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_BLABLA"), 0, 0, 0);
|
|
break;
|
|
case 159:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_OTL"), 0, 0, 0);
|
|
break;
|
|
case 171:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_LUV"), 0, 0, 0);
|
|
break;
|
|
case 175:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_MOBILE"), 0, 0, 0);
|
|
break;
|
|
case 176:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_MAIL"), 0, 0, 0);
|
|
break;
|
|
case 177:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_ANTENNA0"), 0, 0, 0);
|
|
break;
|
|
case 178:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_ANTENNA1"), 0, 0, 0);
|
|
break;
|
|
case 179:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_ANTENNA2"), 0, 0, 0);
|
|
break;
|
|
case 180:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_ANTENNA3"), 0, 0, 0);
|
|
break;
|
|
case 187:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_HUM2"), 0, 0, 0);
|
|
break;
|
|
case 188:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_ABS"), 0, 0, 0);
|
|
break;
|
|
case 189:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_OOPS"), 0, 0, 0);
|
|
break;
|
|
case 190:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_SPIT"), 0, 0, 0);
|
|
break;
|
|
case 191:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_ENE"), 0, 0, 0);
|
|
break;
|
|
case 192:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_PANIC"), 0, 0, 0);
|
|
break;
|
|
case 193:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_WHISP"), 0, 0, 0);
|
|
break;
|
|
case 160:
|
|
this->SendMsg(0x149, reinterpret_cast<int>("ET_DICE1"), 0, 0, 0);
|
|
break;
|
|
case 1:
|
|
this->SendMsg(7, 0, 0, 0, 0);
|
|
break;
|
|
case 87:
|
|
this->SendMsg(7, 1, 0, 0, 0);
|
|
break;
|
|
case 90:
|
|
this->SendMsg(7, 2, 0, 0, 0);
|
|
break;
|
|
case 91:
|
|
this->SendMsg(7, 3, 0, 0, 0);
|
|
break;
|
|
case 102:
|
|
this->SendMsg(7, 4, 0, 0, 0);
|
|
break;
|
|
case 103:
|
|
this->SendMsg(7, 5, 0, 0, 0);
|
|
break;
|
|
case 6:
|
|
this->SendMsg(0x20, 0, 0, 0, 0);
|
|
break;
|
|
case 163:
|
|
this->SendMsg(0xbd, 0, 0, 0, 0);
|
|
break;
|
|
case 4:
|
|
this->SendMsg(0xe, 0, 0, 0, 0);
|
|
break;
|
|
case 5:
|
|
this->SendMsg(0xf, 0, 0, 0, 0);
|
|
break;
|
|
case 56:
|
|
this->SendMsg(0x6a, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 55:
|
|
this->SendMsg(0x70, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 26:
|
|
this->SendMsg(0x3a, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 196:
|
|
this->SendMsg(0x105, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 200:
|
|
this->SendMsg(0x10d, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 48:
|
|
this->SendMsg(0x5b, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 95:
|
|
this->SendMsg(0x9b, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 96:
|
|
this->SendMsg(0x9c, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 97:
|
|
this->SendMsg(0x9d, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 98:
|
|
this->SendMsg(0x9e, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 143:
|
|
this->SendMsg(0xb1, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 144:
|
|
this->SendMsg(0xb2, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 101:
|
|
this->SendMsg(0xa1, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 28:
|
|
this->SendMsg(0x3e, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 61:
|
|
this->SendMsg(0x8e, 0, 0, 0, 0);
|
|
break;
|
|
case 184:
|
|
this->SendMsg(0x3b, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 211:
|
|
this->SendMsg(0x11e, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 251:
|
|
this->SendMsg(0x13d, reinterpret_cast<int>(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 252:
|
|
this->SendMsg(0x13e, 0, 0, 0, 0);
|
|
break;
|
|
case 86: {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x25D)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x224)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x22b)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x22c)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x22d)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x22e)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x22f)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x230)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x231)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x232)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x233)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x234)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x235)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x236)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x237)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x238)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x239)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x23a)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x23b)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x23c)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x23d)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x304)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x305)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x306)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x307)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x308)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x309)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x30a)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x30b)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x30c)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x30d)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x30e)), 0xFFFF64, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0x30f)), 0xFFFF64, 0, 0, 0);
|
|
break;
|
|
}
|
|
case 62:
|
|
this->SendMsg(0x146, std::atoi(parts[0].c_str()), 0, 0, 0);
|
|
break;
|
|
case 63: {
|
|
const int third = std::atoi(parts[2].c_str());
|
|
const int second = std::atoi(parts[1].c_str());
|
|
this->SendMsg(0x8F, std::atoi(parts[0].c_str()), second, third, 0);
|
|
break;
|
|
}
|
|
case 88: {
|
|
std::uint32_t flags = g_session.m_jobFlags;
|
|
if (StateFlag02(flags)) {
|
|
ClearMemberFlags(&flags);
|
|
} else {
|
|
SetMemberFlags(&flags);
|
|
}
|
|
this->SendMsg(0x90, 0x40, 0, 0, 0);
|
|
break;
|
|
}
|
|
case 181:
|
|
if (IsAdminAccount(g_session.m_aid)) {
|
|
const unsigned char enabled = this->unknown_05CC[1];
|
|
this->unknown_05CC[1] = enabled == 0;
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(enabled == 0 ? "Copy_Name_On!!" : "Copy_Name_Off!!"), 0x64FFFF, 0, 0, 0);
|
|
}
|
|
break;
|
|
case 182:
|
|
case 183: {
|
|
TalkConfigPacket packet;
|
|
packet.value = talkType != 182;
|
|
packet.id = ID_CZ_PARTY_CONFIG;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.id), &packet);
|
|
break;
|
|
}
|
|
case 185:
|
|
this->SendMsg(0xFD, *reinterpret_cast<int*>(g_session.unknown_5974) == 0, 0, 0, 0);
|
|
break;
|
|
case 205: {
|
|
CWebBrowser* browser = g_windowMgr.activeBrowser;
|
|
if (browser) {
|
|
browser->ShowAuxiliary(browser->auxiliaryVisible == 0);
|
|
}
|
|
break;
|
|
}
|
|
case 208: {
|
|
CWebBrowser* browser = g_windowMgr.EnsureSpecialBrowser(g_renderer->viewport.width, g_renderer->viewport.height);
|
|
if (browser) {
|
|
browser->Navigate(parts[0].c_str());
|
|
}
|
|
break;
|
|
}
|
|
case 209: {
|
|
const NaviCell cell = g_navigationManager.ParseCell(parts[1].c_str());
|
|
if (cell.x == -1 || cell.y == -1) {
|
|
g_navigationManager.ShowRouteResult(-100, 1);
|
|
break;
|
|
}
|
|
g_navigationManager.sub_B99030(parts[0], 0, 5, true, cell.x, cell.y, 0x3EA);
|
|
break;
|
|
}
|
|
case 210: {
|
|
const NaviCell cell = g_navigationManager.ParseCell(parts[1].c_str());
|
|
bool first = false;
|
|
bool second = false;
|
|
bool third = false;
|
|
if (cell.x == -1 || cell.y == -1 || !g_navigationManager.ParseFlags(parts[2].c_str(), &first, &second, &third)) {
|
|
g_navigationManager.ShowRouteResult(-100, 1);
|
|
break;
|
|
}
|
|
unsigned char mode = second ? 1 : 0;
|
|
if (first) {
|
|
mode += 2;
|
|
}
|
|
if (third) {
|
|
mode += 4;
|
|
}
|
|
g_navigationManager.sub_B99030(parts[0], 0, mode, true, cell.x, cell.y, 0x3EA);
|
|
break;
|
|
}
|
|
case 217:
|
|
g_windowMgr.sub_A978D0(0xCB);
|
|
break;
|
|
case 207: {
|
|
char text[1024];
|
|
std::memset(text, 0, sizeof(text));
|
|
sprintf_s(text, sizeof(text), "", "", "");
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
|
|
sprintf_s(text, sizeof(text), "ver : %d.%d.%d", 14, 2, 3);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
|
|
sprintf_s(text, sizeof(text), "s/n : %s", "");
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
|
|
_snprintf_s(text, _TRUNCATE, "verification : %s", "XXXXXXX");
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(text), 0xFFFF, 0, 0, 0);
|
|
break;
|
|
}
|
|
case 214:
|
|
g_windowMgr.SetUnknown04DC(parts[0].c_str());
|
|
this->SendMsg(0x121, 0, 0, 0, 0);
|
|
break;
|
|
case 218: {
|
|
UIWindow* window = g_windowMgr.LookupWindow(0xBE);
|
|
if (window) {
|
|
g_serviceOptions.Set(0xDA, !g_serviceOptions.Get(0xDA));
|
|
window->Show(g_serviceOptions.Get(0xDA));
|
|
}
|
|
break;
|
|
}
|
|
case 219: {
|
|
UIWindow* window = g_windowMgr.LookupWindow(0x10B);
|
|
if (window) {
|
|
g_serviceOptions.Set(0xDB, !g_serviceOptions.Get(0xDB));
|
|
window->Show(g_serviceOptions.Get(0xDB));
|
|
}
|
|
break;
|
|
}
|
|
case 220: {
|
|
UIWindow* window = g_windowMgr.LookupWindow(0x10C);
|
|
if (window) {
|
|
g_serviceOptions.Set(0xDC, !g_serviceOptions.Get(0xDC));
|
|
window->Show(g_serviceOptions.Get(0xDC));
|
|
}
|
|
break;
|
|
}
|
|
case 224:
|
|
case 226: {
|
|
TalkConfigPacket packet;
|
|
packet.value = talkType == 224 ? 2 : 3;
|
|
packet.id = 0xA68;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.id), &packet);
|
|
break;
|
|
}
|
|
case 225: {
|
|
TalkIntPacket packet;
|
|
packet.id = ID_CZ_REQ_PREVIEW_MACRO_DETECTOR;
|
|
packet.value = std::atoi(parts[0].c_str());
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.id), &packet);
|
|
break;
|
|
}
|
|
case 227: {
|
|
TalkCameraPacket packet;
|
|
packet.range = 0.0f;
|
|
packet.rotation = 0.0f;
|
|
packet.latitude = 0.0f;
|
|
packet.id = ID_CZ_VIEW_CAMERAINFO;
|
|
packet.action = 1;
|
|
GetRagConnection().Send(sizeof(packet), &packet);
|
|
break;
|
|
}
|
|
case 228: {
|
|
CView* camera = this->camera;
|
|
if (camera == nullptr) {
|
|
break;
|
|
}
|
|
TalkCameraPacket packet;
|
|
packet.action = 0;
|
|
packet.id = ID_CZ_VIEW_CAMERAINFO;
|
|
packet.range = camera->camera.distance;
|
|
packet.rotation = camera->camera.yaw;
|
|
packet.latitude = camera->camera.pitch;
|
|
if (parts[0].find("range", 0) != std::string::npos) {
|
|
packet.range = static_cast<float>(std::atof(parts[1].c_str()));
|
|
} else if (parts[0].find("rotation", 0) != std::string::npos) {
|
|
packet.rotation = static_cast<float>(std::atof(parts[1].c_str()));
|
|
} else if (parts[0].find("latitude", 0) != std::string::npos) {
|
|
packet.latitude = static_cast<float>(std::atof(parts[1].c_str()));
|
|
} else {
|
|
packet.range = static_cast<float>(std::atof(parts[0].c_str()));
|
|
packet.rotation = static_cast<float>(std::atof(parts[1].c_str()));
|
|
packet.latitude = static_cast<float>(std::atof(parts[2].c_str()));
|
|
}
|
|
GetRagConnection().Send(sizeof(packet), &packet);
|
|
break;
|
|
}
|
|
case 230: {
|
|
TalkConfigPacket packet;
|
|
packet.id = ID_CZ_CMD_RESETCOOLTIME;
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.id), &packet);
|
|
break;
|
|
}
|
|
case 237:
|
|
if (!g_windowMgr.CloseWindow(0x144)) {
|
|
g_windowMgr.sub_A978D0(0x144);
|
|
}
|
|
break;
|
|
case 254:
|
|
case 255: {
|
|
TalkSelectPacket packet;
|
|
packet.id = 0xA5F;
|
|
if (talkType == 254) {
|
|
packet.enabled = 1;
|
|
packet.value = std::atoi(parts[0].c_str());
|
|
packet.option = static_cast<unsigned char>(std::atoi(parts[1].c_str()));
|
|
} else {
|
|
packet.enabled = 0;
|
|
packet.value = 0;
|
|
}
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.id), &packet);
|
|
break;
|
|
}
|
|
case 260: {
|
|
TalkNamePacket packet;
|
|
packet.id = ID_CZ_GM_CHECKER;
|
|
strncpy_s(packet.name, sizeof(packet.name), parts[0].c_str(), _TRUNCATE);
|
|
GetRagConnection().Send(g_packetLengths.FixedLength(packet.id), &packet);
|
|
break;
|
|
}
|
|
case 279: {
|
|
this->unknown_0648 = this->unknown_0648 == 0;
|
|
std::string server("Dev");
|
|
if (g_serviceMode == 0 && server.compare(0, 3, g_launchServerName, std::strlen(g_launchServerName)) != 0) {
|
|
break;
|
|
}
|
|
SYSTEMTIME time;
|
|
GetLocalTime(&time);
|
|
if (this->unknown_0648 == 1) {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>("확률 로그 시작"), 0x64FFFF, 0, 0, 0);
|
|
std::string name(FormatString("ProbabilityLog(%02d-%02d-%02d).txt", time.wYear, time.wMonth, time.wDay));
|
|
FILE* file = std::fopen(name.c_str(), "a");
|
|
if (file) {
|
|
std::fprintf(file, "시작 : %02d-%02d-%02d %02d:%02d:%02d \n", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute,
|
|
time.wSecond);
|
|
}
|
|
std::fclose(file);
|
|
} else {
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>("확률 로그 끝"), 0x64FFFF, 0, 0, 0);
|
|
std::string name(FormatString("ProbabilityLog(%02d-%02d-%02d).txt", time.wYear, time.wMonth, time.wDay));
|
|
FILE* file = std::fopen(name.c_str(), "a");
|
|
if (file) {
|
|
for (const auto& entry : this->unknown_064C) {
|
|
int itemId = entry.first;
|
|
int count = entry.second;
|
|
ITEM_INFO item;
|
|
item.SetItemId(itemId);
|
|
item.identified = 1;
|
|
const std::string itemName = item.DisplayName(0);
|
|
std::string line = std::format("ID : {}, {}, {}개 \n", itemId, itemName.c_str(), count);
|
|
std::fprintf(file, line.c_str());
|
|
}
|
|
std::fprintf(file, "끝 : %02d-%02d-%02d %02d:%02d:%02d \n\n", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute,
|
|
time.wSecond);
|
|
std::fclose(file);
|
|
}
|
|
this->unknown_064C.clear();
|
|
}
|
|
break;
|
|
}
|
|
case 2:
|
|
case 20:
|
|
case 137:
|
|
case 169:
|
|
case 173:
|
|
case 194:
|
|
case 203:
|
|
break;
|
|
default:
|
|
Singleton<CGameSettingsMgr>::GetInstance()->ToggleOption(talkType);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CE3D30
|
|
// FUNCTION: fn_21335
|
|
void CGameMode::ProcessActorPick(int& handled, ActorPickInfo* pick, CGameActor* actor) {
|
|
const unsigned char selfTargetOption = g_serviceOptions.Get(0x69);
|
|
const unsigned char forceOption = g_serviceOptions.Get(0x6D);
|
|
const std::intptr_t mode = reinterpret_cast<std::intptr_t>(this->unknown_0408);
|
|
|
|
int skillMode;
|
|
int shiftHeld;
|
|
bool optionalSelf;
|
|
int support;
|
|
int attack;
|
|
if (mode == 2 || mode == 4) {
|
|
skillMode = 1;
|
|
shiftHeld = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
optionalSelf = IsOptionalSelfTargetSkill(this->unknown_040C);
|
|
support = IsSupportSkill(this->unknown_040C);
|
|
attack = shiftHeld;
|
|
if (support) {
|
|
attack = shiftHeld == 0;
|
|
}
|
|
} else {
|
|
skillMode = 0;
|
|
shiftHeld = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
attack = shiftHeld;
|
|
support = 0;
|
|
optionalSelf = false;
|
|
}
|
|
|
|
bool resetCursor = false;
|
|
if (pick) {
|
|
if (this->scene->unknown_0050 != 0) {
|
|
if (actor && g_session.unknown_0F24[0] != actor->render.unknown_00FB) {
|
|
attack = 1;
|
|
}
|
|
} else {
|
|
if (g_session.GetMapProperty07()) {
|
|
if (!g_session.IsPartyMember(actor->render.accountId, true)) {
|
|
attack = 1;
|
|
}
|
|
} else if (g_session.GetMapProperty08()) {
|
|
if (!g_session.IsLocalPlayerAid(actor->Slot50())) {
|
|
attack = 1;
|
|
}
|
|
}
|
|
|
|
CWorld* scene = this->scene;
|
|
if (scene->unknown_004C == 0) {
|
|
if (pick->unknown_0024 != 0 || scene->unknown_0048 != 0 || scene->unknown_0054 != 0 ||
|
|
*reinterpret_cast<const int*>(&g_session.unknown_5454[4]) != 0) {
|
|
if (!g_session.IsPartyMember(actor->render.accountId, true)) {
|
|
attack = 1;
|
|
}
|
|
}
|
|
} else if (actor) {
|
|
GuildInfo* guildInfo = &g_guildInfo;
|
|
bool friendly = true;
|
|
bool known = true;
|
|
switch (actor->unknown_0314) {
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 13:
|
|
case 14: {
|
|
CGameActor* summoner = static_cast<CGameActor*>(scene->GetGameActorByAID(actor->unknown_02EC));
|
|
if (!summoner) {
|
|
known = this->scene->player->render.accountId == static_cast<std::uint32_t>(actor->unknown_02EC);
|
|
} else if (!g_session.IsLocalPlayerAid(summoner->Slot50())) {
|
|
friendly = guildInfo->HasRelatedGuild(summoner->Slot50());
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
if (!g_session.IsLocalPlayerAid(actor->Slot50())) {
|
|
friendly = guildInfo->HasRelatedGuild(actor->Slot50());
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!friendly) {
|
|
attack = 1;
|
|
} else if (known) {
|
|
attack = 0;
|
|
if (!skillMode) {
|
|
resetCursor = true;
|
|
} else {
|
|
attack = support;
|
|
if ((selfTargetOption || shiftHeld) && optionalSelf == true) {
|
|
attack = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (resetCursor) {
|
|
this->SetCursorAction(0);
|
|
} else if (attack && actor->render.unknown_0070 != 3) {
|
|
this->SetCursorAction(skillMode ? 11 : 5);
|
|
handled = 1;
|
|
} else if (skillMode && actor->render.unknown_0070 != 3) {
|
|
this->SetCursorAction(10);
|
|
} else {
|
|
this->SetCursorAction(0);
|
|
}
|
|
|
|
const std::uint32_t homunAid = *reinterpret_cast<const std::uint32_t*>(&g_session.unknown_5570[8]);
|
|
const std::uint32_t mercenaryAid = *reinterpret_cast<const std::uint32_t*>(&g_session.unknown_5620[8]);
|
|
const bool engaged = (attack || this->scene->unknown_004C != 0) && actor->render.unknown_0070 != 3 && !skillMode;
|
|
if (engaged && g_session.unknown_5614 != 0 && g_mouse.buttons[1] == 1 && HIBYTE(GetAsyncKeyState(VK_MENU))) {
|
|
if (HIBYTE(GetAsyncKeyState(VK_SHIFT))) {
|
|
CGameActor* homun = static_cast<CGameActor*>(this->scene->GetGameActorByAID(homunAid));
|
|
if (homun && homun->HasUnknown030CEntry()) {
|
|
AiMessage message = {};
|
|
message.type = 3;
|
|
message.target = actor->render.accountId;
|
|
homun->SetUnknown0330(reinterpret_cast<const float*>(&message), 0);
|
|
}
|
|
} else if (g_session.unknown_5610 != 0 && g_groundMarkAid == actor->render.accountId) {
|
|
CGameActor* homun = static_cast<CGameActor*>(this->scene->GetGameActorByAID(homunAid));
|
|
if (homun && homun->HasUnknown030CEntry()) {
|
|
AiMessage message = {};
|
|
message.type = 3;
|
|
message.target = g_groundMarkAid;
|
|
homun->SetUnknown0318(reinterpret_cast<const float*>(&message), 0);
|
|
}
|
|
g_session.unknown_5610 = 0;
|
|
} else {
|
|
this->SetCursorAction(11);
|
|
g_groundMarkAid = actor->render.accountId;
|
|
g_session.unknown_5600 = 0;
|
|
g_session.unknown_5604 = 0;
|
|
g_session.unknown_5608 = 0;
|
|
g_session.unknown_5610 = 1;
|
|
}
|
|
g_session.unknown_560C = 1;
|
|
}
|
|
|
|
if (g_session.unknown_5614 != 0 && g_mouse.buttons[0] == 1 && g_session.IsHomunculusSkill(this->unknown_040C)) {
|
|
CGameActor* homun = static_cast<CGameActor*>(this->scene->GetGameActorByAID(homunAid));
|
|
if (homun && homun->HasUnknown030CEntry()) {
|
|
AiMessage message = {};
|
|
message.type = 7;
|
|
message.level = this->unknown_0414;
|
|
message.skill = this->unknown_040C;
|
|
message.target = actor->render.accountId;
|
|
homun->SetUnknown0318(reinterpret_cast<const float*>(&message), 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (engaged && g_session.unknown_56B0 != 0 && g_mouse.buttons[0] == 1 && HIBYTE(GetAsyncKeyState(VK_MENU))) {
|
|
if (HIBYTE(GetAsyncKeyState(VK_SHIFT))) {
|
|
CGameActor* mercenary = static_cast<CGameActor*>(this->scene->GetGameActorByAID(mercenaryAid));
|
|
if (mercenary && mercenary->HasUnknown0310Entry()) {
|
|
AiMessage message = {};
|
|
message.type = 3;
|
|
message.target = actor->render.accountId;
|
|
mercenary->SetUnknown0330(reinterpret_cast<const float*>(&message), 1);
|
|
}
|
|
} else if (g_session.unknown_56AC != 0 && g_groundMarkAltAid == actor->render.accountId) {
|
|
CGameActor* mercenary = static_cast<CGameActor*>(this->scene->GetGameActorByAID(mercenaryAid));
|
|
if (mercenary && mercenary->HasUnknown0310Entry()) {
|
|
AiMessage message = {};
|
|
message.type = 3;
|
|
message.target = g_groundMarkAltAid;
|
|
mercenary->SetUnknown0318(reinterpret_cast<const float*>(&message), 1);
|
|
}
|
|
g_session.unknown_56AC = 0;
|
|
} else {
|
|
this->SetCursorAction(11);
|
|
g_groundMarkAltAid = actor->render.accountId;
|
|
g_session.unknown_569C = 0;
|
|
g_session.unknown_56A0 = 0;
|
|
g_session.unknown_56A4 = 0;
|
|
g_session.unknown_56AC = 1;
|
|
}
|
|
g_session.unknown_56A8 = 1;
|
|
}
|
|
|
|
if (attack != 0 && g_session.unknown_56B0 != 0 && g_mouse.buttons[0] == 1 && g_session.IsMercenarySkill(this->unknown_040C)) {
|
|
CGameActor* mercenary = static_cast<CGameActor*>(this->scene->GetGameActorByAID(mercenaryAid));
|
|
if (mercenary && mercenary->HasUnknown0310Entry()) {
|
|
AiMessage message = {};
|
|
message.type = 7;
|
|
message.level = this->unknown_0414;
|
|
message.skill = this->unknown_040C;
|
|
message.target = actor->render.accountId;
|
|
mercenary->SetUnknown0318(reinterpret_cast<const float*>(&message), 1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
int& forced = this->forcedAttack;
|
|
if (g_mouse.buttons[0] == 1 && attack != 0 && !HIBYTE(GetAsyncKeyState(VK_MENU))) {
|
|
this->SendMsg(0x1A, 1, 0, 0, 0);
|
|
*reinterpret_cast<std::uint32_t*>(&this->unknown_00EC[0x08]) = actor->render.accountId;
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[0x0C]) = 0;
|
|
if (g_session.GetSceneUnknown004C() == 0 && (HIBYTE(GetAsyncKeyState(VK_CONTROL)) || forceOption != 0)) {
|
|
this->RequestPlayerAction(actor->render.accountId, 0);
|
|
if (!skillMode) {
|
|
forced = 1;
|
|
}
|
|
} else {
|
|
this->RequestPlayerAction(actor->render.accountId, 1);
|
|
forced = 0;
|
|
}
|
|
}
|
|
|
|
if (g_mouse.buttons[1] == 1 && shiftHeld) {
|
|
if (this->IsOverWeight(true)) {
|
|
return;
|
|
}
|
|
this->SendMsg(0x1A, 1, 0, 0, 0);
|
|
g_hoverActorGid = actor->Slot42();
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[0x0C]) = 0;
|
|
}
|
|
|
|
int& balloonAid = *reinterpret_cast<int*>(&this->unknown_00EC[0x00]);
|
|
if (this->unknown_00DC == g_screenWidth && this->unknown_00E0 == g_screenHeight) {
|
|
this->ShowActorNameBalloon(balloonAid);
|
|
return;
|
|
}
|
|
balloonAid = 0;
|
|
this->ShowActorNameBalloon(0);
|
|
}
|
|
|
|
// OFFSET: 0x00CFE510
|
|
// FUNCTION: fn_21434
|
|
void CGameMode::ProcessStatusIconTooltip(int x, int y) {
|
|
auto firstLine = [](UIWindow* window) -> std::string {
|
|
const std::vector<std::string>& lines = static_cast<UIBalloonText*>(window)->m_lines;
|
|
if (!lines.empty()) {
|
|
return lines[0];
|
|
}
|
|
return std::string();
|
|
};
|
|
|
|
if (this->unknown_05D0) {
|
|
this->unknown_05D0->Show(0);
|
|
}
|
|
|
|
if (g_activeSkillEffects.begin() == g_activeSkillEffects.end()) {
|
|
return;
|
|
}
|
|
|
|
int& hoveredId = this->unknown_01F8;
|
|
const int count = static_cast<int>(g_activeSkillEffects.end() - g_activeSkillEffects.begin());
|
|
const int rows = (g_renderer->viewport.height - 169) / 35;
|
|
const int right = g_renderer->viewport.width - 18;
|
|
const int columns = count / rows + (count % rows != 0 ? 1 : 0);
|
|
if (right - columns * 45 + 15 > x || x > right || y < 168 || y > rows * 35 + 168) {
|
|
hoveredId = -1;
|
|
return;
|
|
}
|
|
|
|
const int dx = right - x;
|
|
const int column = dx / 45;
|
|
const int columnEdge = (column + (dx != column * 45 ? 1 : 0)) * 45;
|
|
if (columnEdge - 15 < dx && dx < columnEdge) {
|
|
return;
|
|
}
|
|
|
|
const int dy = y - 168;
|
|
const int row = dy / 35;
|
|
const int rowEdge = (row + (dy != row * 35 ? 1 : 0)) * 35;
|
|
if (rowEdge - 5 < dy && dy < rowEdge) {
|
|
return;
|
|
}
|
|
|
|
const int slot = column * rows + row;
|
|
if (slot >= count) {
|
|
return;
|
|
}
|
|
|
|
const int id = g_statusIconIds[slot];
|
|
if (id == -1) {
|
|
hoveredId = -1;
|
|
if (this->unknown_05D0) {
|
|
static_cast<UIBalloonText*>(this->unknown_05D0)->SetText(" ", 35);
|
|
}
|
|
return;
|
|
}
|
|
|
|
int hasLimit = 0;
|
|
int limitLine = -1;
|
|
g_session.m_hotkeyScript->Call("GetTimeLimitInfo", "d>dd", id, &hasLimit, &limitLine);
|
|
|
|
std::string timeText;
|
|
int activeId = id;
|
|
if (hasLimit != 0) {
|
|
timeText = this->GetActiveSkillEffectTimeText(id, &activeId);
|
|
}
|
|
|
|
if (hoveredId == id && this->unknown_05D0 && id != 0x175 && id != 0x2B7) {
|
|
if (firstLine(this->unknown_05D0).size() != 0) {
|
|
this->unknown_05D0->Show(1);
|
|
}
|
|
} else {
|
|
if (!this->unknown_05D0) {
|
|
this->unknown_05D0 = new UITransBalloonText();
|
|
this->unknown_05D0->SetSize(50, 50);
|
|
g_windowMgr.AddRendered(this->unknown_05D0);
|
|
static_cast<UITransBalloonText*>(this->unknown_05D0)->SetFontHeight(11);
|
|
static_cast<UITransBalloonText*>(this->unknown_05D0)->m_borderColor = 0xC0C0C0;
|
|
} else {
|
|
static_cast<UIBalloonText*>(this->unknown_05D0)->SetText(" ", 35);
|
|
}
|
|
|
|
UITransBalloonText* balloon = static_cast<UITransBalloonText*>(this->unknown_05D0);
|
|
std::string extra;
|
|
int line = 1;
|
|
std::uint32_t color = 0;
|
|
if (id != 0x2B7) {
|
|
for (;;) {
|
|
const char* text;
|
|
int red;
|
|
int green;
|
|
int blue;
|
|
do {
|
|
text = nullptr;
|
|
red = 0;
|
|
green = 0;
|
|
blue = 0;
|
|
} while (!g_session.m_hotkeyScript->Call("GetStateIconDescript", "dd>sddd", activeId, line, &text, &red, &green, &blue));
|
|
|
|
std::string description(text);
|
|
if (description.size() == 0) {
|
|
break;
|
|
}
|
|
|
|
if (line == limitLine) {
|
|
description = FormatOwnedString(description.c_str(), timeText.c_str());
|
|
}
|
|
|
|
const std::uint32_t lineColor = RGB(red, green, blue);
|
|
bool replace;
|
|
if (line == 1) {
|
|
replace = true;
|
|
} else {
|
|
const std::string first = firstLine(balloon);
|
|
replace = first.size() == 1 && first[0] == ' ';
|
|
}
|
|
|
|
if (replace) {
|
|
balloon->SetLine(description.c_str(), lineColor);
|
|
} else {
|
|
balloon->AddLine(description.c_str(), lineColor);
|
|
}
|
|
++line;
|
|
}
|
|
|
|
if (id == 0x175) {
|
|
if (timeGetTime() - g_session.unknown_7ED4 > 10000) {
|
|
g_session.unknown_7ED0 = 0;
|
|
} else if (g_session.unknown_7ED0 != 0) {
|
|
extra = FormatOwnedString(LookupMessage(0xBD2), g_session.unknown_7ED0);
|
|
}
|
|
|
|
if (extra.size() != 0) {
|
|
balloon->AddLine(extra.c_str(), 0);
|
|
}
|
|
}
|
|
} else {
|
|
{
|
|
ITEM_INFO item = LookupClientItemByIdentity(g_session.m_inventoryItems, g_session.unknown_16EC);
|
|
if (item.unknown_0000[1] != 0) {
|
|
extra = FormatOwnedString("%s : %d", item.DisplayName(0).c_str(), item.quantity);
|
|
color = 0xFABEBE;
|
|
}
|
|
}
|
|
|
|
if (extra.size() != 0) {
|
|
balloon->SetLine(extra.c_str(), color);
|
|
}
|
|
}
|
|
|
|
const std::string first = firstLine(this->unknown_05D0);
|
|
if (!(first.size() == 1 && first[0] == ' ')) {
|
|
this->unknown_05D0->Show(1);
|
|
const int windowHeight = this->unknown_05D0->geometry.height;
|
|
const int left = right - 30 + (slot / rows) * -45 - this->unknown_05D0->geometry.width;
|
|
const int top = (slot % rows) * 35;
|
|
int windowY = g_renderer->viewport.height - windowHeight;
|
|
if (windowHeight + 171 + top <= g_renderer->viewport.height) {
|
|
windowY = top + 171;
|
|
}
|
|
this->unknown_05D0->Move(left, windowY);
|
|
}
|
|
|
|
hoveredId = id;
|
|
}
|
|
|
|
if (hasLimit != 0 && timeText.size() != 0 && limitLine != -1 && this->unknown_05D0) {
|
|
const char* text = nullptr;
|
|
if (g_session.m_hotkeyScript->Call("GetStateIconDescript", "dd>s", activeId, limitLine, &text)) {
|
|
std::string description(text);
|
|
description = FormatOwnedString(description.c_str(), timeText.c_str());
|
|
static_cast<UITransBalloonText*>(this->unknown_05D0)->ChangeText(description.c_str(), limitLine - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00CE2880
|
|
// FUNCTION: fn_21334
|
|
int CGameMode::HandleActorPick(ActorPickInfo* pick, int result) {
|
|
const unsigned char selfTargetOption = g_serviceOptions.Get(0x69);
|
|
const unsigned char forceOption = g_serviceOptions.Get(0x6D);
|
|
const int& siegeMode = *reinterpret_cast<const int*>(&g_session.unknown_5454[4]);
|
|
const std::uint32_t& homunAid = *reinterpret_cast<const std::uint32_t*>(&g_session.unknown_5570[8]);
|
|
const std::uint32_t& mercenaryAid = *reinterpret_cast<const std::uint32_t*>(&g_session.unknown_5620[8]);
|
|
GuildInfo* guildInfo = &g_guildInfo;
|
|
|
|
if (pick->accountId != g_session.m_aid) {
|
|
switch (pick->kind) {
|
|
case 0:
|
|
if (pick->job != 45 && g_session.IsAllyActor(pick->accountId, pick->job) == 1) {
|
|
this->SetCursorAction(1);
|
|
if (g_mouse.buttons[0] == 2) {
|
|
result = 2;
|
|
} else {
|
|
result = 1;
|
|
}
|
|
} else if (pick->job == 45) {
|
|
this->SetCursorAction(7);
|
|
result = 2;
|
|
} else {
|
|
result = 1;
|
|
if (IsPlayerJob(pick->job)) {
|
|
const std::intptr_t mode = reinterpret_cast<std::intptr_t>(this->unknown_0408);
|
|
int skillMode;
|
|
int shift;
|
|
int support;
|
|
int attack;
|
|
if (mode == 2 || mode == 4) {
|
|
skillMode = 1;
|
|
shift = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
support = IsSupportSkill(this->unknown_040C);
|
|
attack = shift;
|
|
if (support) {
|
|
skillMode = 1;
|
|
attack = shift == 0;
|
|
}
|
|
} else {
|
|
skillMode = 0;
|
|
shift = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
attack = shift;
|
|
support = 0;
|
|
}
|
|
|
|
CWorld* scene = this->scene;
|
|
CGameActor* actor = static_cast<CGameActor*>(scene->GetGameActorByAID(pick->accountId));
|
|
if (scene->unknown_0050 == 0) {
|
|
if (g_session.GetMapProperty07()) {
|
|
if (!g_session.IsPartyMember(pick->accountId, true)) {
|
|
attack = 1;
|
|
}
|
|
} else if (g_session.GetMapProperty08() && actor != nullptr) {
|
|
if (!g_session.IsLocalPlayerAid(actor->Slot50())) {
|
|
attack = 1;
|
|
}
|
|
}
|
|
|
|
if (this->scene->unknown_004C != 0) {
|
|
if (actor != nullptr) {
|
|
if (!g_session.IsLocalPlayerAid(actor->Slot50()) && !guildInfo->HasRelatedGuild(actor->Slot50())) {
|
|
attack = 1;
|
|
} else {
|
|
attack = 0;
|
|
if (skillMode) {
|
|
const bool optionalSelf = IsOptionalSelfTargetSkill(this->unknown_040C);
|
|
attack = support;
|
|
if ((selfTargetOption != 0 || shift != 0) && optionalSelf == true) {
|
|
attack = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (pick->unknown_0024 != 0 || this->scene->unknown_0048 != 0 || this->scene->unknown_0054 != 0 || siegeMode != 0) {
|
|
if (!g_session.IsPartyMember(pick->accountId, true)) {
|
|
attack = 1;
|
|
}
|
|
}
|
|
} else if (actor != nullptr && g_session.unknown_0F24[0] != actor->render.unknown_00FB) {
|
|
attack = 1;
|
|
}
|
|
|
|
const int state = actor != nullptr ? actor->render.unknown_0070 : 3;
|
|
if (attack && state != 3) {
|
|
this->SetCursorAction(skillMode ? 11 : 5);
|
|
result = 1;
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[0]) = pick->accountId;
|
|
} else {
|
|
this->SetCursorAction(skillMode && state != 3 ? 10 : 0);
|
|
result = 0;
|
|
if (g_mouse.buttons[0] == 0 && this->unknown_0028 == 0 && *reinterpret_cast<int*>(&this->unknown_00EC[4]) == 0) {
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[0]) = pick->accountId;
|
|
}
|
|
}
|
|
} else if (g_session.IsNpcJob(pick->job) == true) {
|
|
this->SetCursorAction(1);
|
|
if (g_mouse.buttons[0] == 2) {
|
|
result = 2;
|
|
}
|
|
} else if (g_session.IsMonsterClass(pick->job)) {
|
|
const std::intptr_t mode = reinterpret_cast<std::intptr_t>(this->unknown_0408);
|
|
int skillMode;
|
|
int attack;
|
|
if (mode == 2 || mode == 4) {
|
|
skillMode = 1;
|
|
const int shift = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
attack = shift == 0;
|
|
if (IsSupportSkill(this->unknown_040C)) {
|
|
attack = shift;
|
|
skillMode = 1;
|
|
}
|
|
} else {
|
|
skillMode = 0;
|
|
attack = HIBYTE(GetAsyncKeyState(VK_SHIFT)) == 0;
|
|
}
|
|
if (selfTargetOption != 0) {
|
|
attack = 1;
|
|
}
|
|
|
|
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(pick->accountId));
|
|
if (g_session.GetMapProperty08() && actor != nullptr && g_session.IsLocalPlayerAid(actor->Slot50())) {
|
|
attack = 0;
|
|
}
|
|
if (this->scene->unknown_004C != 0 && actor != nullptr && g_session.IsLocalPlayerAid(actor->Slot50())) {
|
|
attack = 0;
|
|
}
|
|
|
|
if (this->unknown_00F8 != 0) {
|
|
if (attack) {
|
|
if (skillMode) {
|
|
this->SetCursorAction(11);
|
|
} else if (actor != nullptr && actor->unknown_0314 == 7) {
|
|
this->SetCursorAction(0);
|
|
} else {
|
|
this->SetCursorAction(5);
|
|
}
|
|
} else {
|
|
this->SetCursorAction(skillMode ? 10 : 0);
|
|
}
|
|
}
|
|
|
|
if (g_mouse.buttons[0] == 0 && this->unknown_0028 == 0) {
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[4]) = pick->accountId;
|
|
}
|
|
if (g_mouse.buttons[0] == 2 || g_mouse.buttons[1] == 2) {
|
|
result = 2;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 2: {
|
|
result = 1;
|
|
int action;
|
|
if (g_session.GetSceneUnknown004C()) {
|
|
switch (pick->job) {
|
|
case 0x8D:
|
|
case 0x8F:
|
|
case 0x90:
|
|
case 0x91:
|
|
case 0x93:
|
|
case 0x94:
|
|
case 0x95:
|
|
case 0x96:
|
|
case 0x97:
|
|
case 0x98:
|
|
case 0x99:
|
|
case 0xBE:
|
|
case 0xBF:
|
|
case 0xC0:
|
|
case 0xC1:
|
|
case 0xC2:
|
|
case 0xCB:
|
|
case 0xD2:
|
|
case 0xD3:
|
|
case 0xD4:
|
|
case 0xD5:
|
|
case 0xD6:
|
|
case 0xD7:
|
|
case 0xD8:
|
|
case 0xD9:
|
|
case 0xDA:
|
|
case 0xDE:
|
|
case 0xE5:
|
|
case 0xE6:
|
|
case 0xE7:
|
|
case 0xE8:
|
|
case 0xE9:
|
|
case 0xF0:
|
|
case 0x108:
|
|
case 0x5174:
|
|
case 0x5175:
|
|
case 0x5176:
|
|
case 0x5177:
|
|
action = reinterpret_cast<std::intptr_t>(this->unknown_0408) == 5 ? 10 : 5;
|
|
break;
|
|
default:
|
|
action = reinterpret_cast<std::intptr_t>(this->unknown_0408) == 5 ? 10 : 0;
|
|
break;
|
|
}
|
|
} else {
|
|
switch (pick->job) {
|
|
case 0x8D:
|
|
case 0x8F:
|
|
case 0x98:
|
|
case 0xDA:
|
|
case 0xDE:
|
|
case 0xE6:
|
|
case 0x5174:
|
|
case 0x5175:
|
|
case 0x5176:
|
|
case 0x5177:
|
|
action = reinterpret_cast<std::intptr_t>(this->unknown_0408) == 5 ? 10 : 5;
|
|
break;
|
|
default:
|
|
action = reinterpret_cast<std::intptr_t>(this->unknown_0408) == 5 ? 10 : 0;
|
|
break;
|
|
}
|
|
}
|
|
this->SetCursorAction(action);
|
|
if (g_mouse.buttons[0] == 2) {
|
|
result = 2;
|
|
}
|
|
break;
|
|
}
|
|
case 1:
|
|
result = 1;
|
|
this->SetCursorAction(9);
|
|
if (g_mouse.buttons[0] == 2) {
|
|
result = 2;
|
|
}
|
|
break;
|
|
case 3:
|
|
result = 0;
|
|
this->SetCursorAction(0);
|
|
break;
|
|
case 4: {
|
|
result = 0;
|
|
this->SetCursorAction(0);
|
|
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(pick->accountId));
|
|
if (actor != nullptr && actor->render.unknown_0070 != 3) {
|
|
if (g_session.m_aid == static_cast<std::uint32_t>(actor->unknown_02EC)) {
|
|
if (actor->unknown_0314 == 8 && this->unknown_040C == 0xE7) {
|
|
result = 1;
|
|
this->SetCursorAction(11);
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[4]) = pick->accountId;
|
|
}
|
|
} else {
|
|
CWorld* scene = this->scene;
|
|
if (scene->unknown_0048 == 1 || siegeMode == 1 || scene->unknown_004C == 1) {
|
|
if (scene->unknown_004C == 1) {
|
|
CGameActor* owner = static_cast<CGameActor*>(scene->GetGameActorByAID(actor->unknown_02EC));
|
|
if (owner == nullptr || g_session.IsLocalPlayerAid(owner->Slot50()) == 1 || guildInfo->HasRelatedGuild(owner->Slot50()) == true) {
|
|
break;
|
|
}
|
|
}
|
|
result = 1;
|
|
this->SetCursorAction(5);
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[4]) = pick->accountId;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_mouse.buttons[0] != 1 && g_mouse.buttons[1] != 1) {
|
|
return result;
|
|
}
|
|
|
|
switch (pick->kind) {
|
|
case 0: {
|
|
if (pick->job == 45) {
|
|
return result;
|
|
}
|
|
|
|
if (g_session.IsAllyActor(pick->accountId, pick->job) == 1) {
|
|
const int state = this->scene->player->render.unknown_0070;
|
|
if (state != 0 && state != 6) {
|
|
return result;
|
|
}
|
|
if (this->IsMenuWindowOpen() == true) {
|
|
return result;
|
|
}
|
|
|
|
CGameActor* actor = static_cast<CGameActor*>(this->scene->GetGameActorByAID(pick->accountId));
|
|
int column;
|
|
int row;
|
|
this->WorldCell(actor->render.position.x, actor->render.position.z, column, row);
|
|
this->scene->player->SendMsg(nullptr, 16, 0, column, column >> 31, row, row >> 31, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
if (g_windowMgr.HasPendingDialog() == true) {
|
|
g_windowMgr.SendNotice(3, 0, 0, 0, 0, 0);
|
|
g_windowMgr.SendNotice(1, reinterpret_cast<std::intptr_t>(LookupMessage(0xFBB)), 255, 25, 0, 0);
|
|
return result;
|
|
}
|
|
|
|
ContactNpcPacket packet;
|
|
packet.packetType = ID_CZ_CONTACTNPC;
|
|
packet.npcId = pick->accountId;
|
|
packet.type = 1;
|
|
GetRagConnection().Send(reinterpret_cast<const PacketLengths&>(GetRagConnection()).FixedLength(packet.packetType), &packet);
|
|
return result;
|
|
}
|
|
|
|
const int job = pick->job;
|
|
if (g_session.IsMonsterClass(job)) {
|
|
const std::intptr_t mode = reinterpret_cast<std::intptr_t>(this->unknown_0408);
|
|
int attack;
|
|
if (mode == 2 || mode == 4) {
|
|
const int shift = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
const bool support = IsSupportSkill(this->unknown_040C);
|
|
attack = shift == 0;
|
|
if (support) {
|
|
attack = shift;
|
|
}
|
|
} else {
|
|
attack = HIBYTE(GetAsyncKeyState(VK_SHIFT)) == 0;
|
|
}
|
|
if (selfTargetOption != 0) {
|
|
attack = 1;
|
|
}
|
|
|
|
if (g_session.unknown_5614 && g_mouse.buttons[1] == 1 && HIBYTE(GetAsyncKeyState(VK_MENU))) {
|
|
if (HIBYTE(GetAsyncKeyState(VK_SHIFT))) {
|
|
CGameActor* homun = static_cast<CGameActor*>(this->scene->GetGameActorByAID(homunAid));
|
|
if (homun != nullptr && homun->HasUnknown030CEntry()) {
|
|
AiMessage message = {};
|
|
message.type = 3;
|
|
message.target = pick->accountId;
|
|
homun->SetUnknown0330(reinterpret_cast<const float*>(&message), 0);
|
|
}
|
|
} else if (g_session.unknown_5610 != 0 && g_groundMarkAid == pick->accountId) {
|
|
CGameActor* homun = static_cast<CGameActor*>(this->scene->GetGameActorByAID(homunAid));
|
|
if (homun != nullptr && homun->HasUnknown030CEntry()) {
|
|
AiMessage message = {};
|
|
message.type = 3;
|
|
message.target = g_groundMarkAid;
|
|
homun->SetUnknown0318(reinterpret_cast<const float*>(&message), 0);
|
|
}
|
|
g_session.unknown_5610 = 0;
|
|
} else {
|
|
this->SetCursorAction(11);
|
|
g_groundMarkAid = pick->accountId;
|
|
g_session.unknown_5600 = 0;
|
|
g_session.unknown_5604 = 0;
|
|
g_session.unknown_5608 = 0;
|
|
g_session.unknown_5610 = 1;
|
|
}
|
|
g_session.unknown_560C = 1;
|
|
}
|
|
|
|
if (g_session.unknown_5614 && g_mouse.buttons[0] == 1 && g_session.IsHomunculusSkill(this->unknown_040C)) {
|
|
CGameActor* homun = static_cast<CGameActor*>(this->scene->GetGameActorByAID(homunAid));
|
|
if (homun != nullptr && homun->HasUnknown030CEntry()) {
|
|
AiMessage message;
|
|
message.type = 7;
|
|
message.x = 0;
|
|
message.y = 0;
|
|
message.level = this->unknown_0414;
|
|
message.skill = this->unknown_040C;
|
|
message.target = pick->accountId;
|
|
homun->SetUnknown0318(reinterpret_cast<const float*>(&message), 0);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
if (g_session.unknown_56B0 && g_mouse.buttons[0] == 1 && HIBYTE(GetAsyncKeyState(VK_MENU))) {
|
|
if (HIBYTE(GetAsyncKeyState(VK_SHIFT))) {
|
|
CGameActor* mercenary = static_cast<CGameActor*>(this->scene->GetGameActorByAID(mercenaryAid));
|
|
if (mercenary != nullptr && mercenary->HasUnknown0310Entry()) {
|
|
AiMessage message = {};
|
|
message.type = 3;
|
|
message.target = pick->accountId;
|
|
mercenary->SetUnknown0330(reinterpret_cast<const float*>(&message), 1);
|
|
}
|
|
} else if (g_session.unknown_56AC != 0 && g_groundMarkAltAid == pick->accountId) {
|
|
CGameActor* mercenary = static_cast<CGameActor*>(this->scene->GetGameActorByAID(mercenaryAid));
|
|
if (mercenary != nullptr && mercenary->HasUnknown0310Entry()) {
|
|
AiMessage message = {};
|
|
message.type = 3;
|
|
message.target = g_groundMarkAltAid;
|
|
mercenary->SetUnknown0318(reinterpret_cast<const float*>(&message), 1);
|
|
}
|
|
g_session.unknown_56AC = 0;
|
|
} else {
|
|
this->SetCursorAction(11);
|
|
g_groundMarkAltAid = pick->accountId;
|
|
g_session.unknown_569C = 0;
|
|
g_session.unknown_56A0 = 0;
|
|
g_session.unknown_56A4 = 0;
|
|
g_session.unknown_56AC = 1;
|
|
}
|
|
g_session.unknown_56A8 = 1;
|
|
}
|
|
|
|
if (attack && g_session.unknown_56B0 && g_mouse.buttons[0] == 1 && g_session.IsMercenarySkill(this->unknown_040C)) {
|
|
CGameActor* mercenary = static_cast<CGameActor*>(this->scene->GetGameActorByAID(mercenaryAid));
|
|
if (mercenary != nullptr && mercenary->HasUnknown0310Entry()) {
|
|
AiMessage message;
|
|
message.type = 7;
|
|
message.x = 0;
|
|
message.y = 0;
|
|
message.level = this->unknown_0414;
|
|
message.skill = this->unknown_040C;
|
|
message.target = pick->accountId;
|
|
mercenary->SetUnknown0318(reinterpret_cast<const float*>(&message), 1);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
if (g_mouse.buttons[0] == 1 && attack && !HIBYTE(GetAsyncKeyState(VK_MENU))) {
|
|
this->SendMsg(0x1A, 1, 0, 0, 0);
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[8]) = pick->accountId;
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[4]) = pick->accountId;
|
|
this->unknown_00F8 = 0;
|
|
if (g_session.GetSceneUnknown004C() == 0 && (HIBYTE(GetAsyncKeyState(VK_CONTROL)) || forceOption != 0)) {
|
|
this->RequestPlayerAction(pick->accountId, 0);
|
|
this->forcedAttack = 1;
|
|
} else {
|
|
this->RequestPlayerAction(pick->accountId, 1);
|
|
this->forcedAttack = 0;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
if (this->forcedAttack == 0 && g_mouse.buttons[0] == 3) {
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[4]) = 0;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
if (!IsPlayerJob(job)) {
|
|
break;
|
|
}
|
|
|
|
const std::intptr_t mode = reinterpret_cast<std::intptr_t>(this->unknown_0408);
|
|
int attack;
|
|
if (mode == 2 || mode == 4) {
|
|
const int shift = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
attack = shift;
|
|
if (IsSupportSkill(this->unknown_040C)) {
|
|
attack = shift == 0;
|
|
}
|
|
} else {
|
|
attack = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
}
|
|
if (pick->unknown_0024 != 0 || this->scene->unknown_0048 != 0 || siegeMode != 0) {
|
|
attack = 1;
|
|
}
|
|
if (selfTargetOption != 0) {
|
|
attack = 1;
|
|
}
|
|
|
|
if (attack && g_mouse.buttons[0] == 1) {
|
|
int index = 0;
|
|
CGameActor* companion;
|
|
if (g_session.IsHomunculusSkill(this->unknown_040C) && g_session.unknown_5614) {
|
|
companion = static_cast<CGameActor*>(this->scene->GetGameActorByAID(homunAid));
|
|
if (companion != nullptr && companion->HasUnknown030CEntry()) {
|
|
AiMessage message;
|
|
message.type = 7;
|
|
message.x = 0;
|
|
message.y = 0;
|
|
message.level = this->unknown_0414;
|
|
message.skill = this->unknown_040C;
|
|
message.target = pick->accountId;
|
|
companion->SetUnknown0318(reinterpret_cast<const float*>(&message), index);
|
|
return result;
|
|
}
|
|
} else if (g_session.IsMercenarySkill(this->unknown_040C) && g_session.unknown_56B0) {
|
|
companion = static_cast<CGameActor*>(this->scene->GetGameActorByAID(mercenaryAid));
|
|
if (companion != nullptr && companion->HasUnknown0310Entry()) {
|
|
index = 1;
|
|
AiMessage message;
|
|
message.type = 7;
|
|
message.x = 0;
|
|
message.y = 0;
|
|
message.level = this->unknown_0414;
|
|
message.skill = this->unknown_040C;
|
|
message.target = pick->accountId;
|
|
companion->SetUnknown0318(reinterpret_cast<const float*>(&message), index);
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
const bool allowed = pick->accountId != g_session.m_aid || mode == 4;
|
|
if (!allowed || !attack) {
|
|
return result;
|
|
}
|
|
|
|
this->SendMsg(0x1A, 1, 0, 0, 0);
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[8]) = pick->accountId;
|
|
*reinterpret_cast<int*>(&this->unknown_00EC[4]) = pick->accountId;
|
|
this->unknown_00F8 = 0;
|
|
if (g_session.GetSceneUnknown004C() == 0 && (HIBYTE(GetAsyncKeyState(VK_CONTROL)) || forceOption != 0)) {
|
|
this->RequestPlayerAction(pick->accountId, 0);
|
|
this->forcedAttack = 1;
|
|
return result;
|
|
}
|
|
this->RequestPlayerAction(pick->accountId, 1);
|
|
this->forcedAttack = 0;
|
|
return result;
|
|
}
|
|
case 2:
|
|
switch (pick->job) {
|
|
case 0x8D:
|
|
case 0x8F:
|
|
case 0x98:
|
|
case 0xDA:
|
|
case 0xDE:
|
|
case 0xE6:
|
|
case 0x5174:
|
|
case 0x5175:
|
|
case 0x5176:
|
|
case 0x5177: {
|
|
const int skill = this->unknown_040C;
|
|
if (skill == 0xD7 || skill == 0xD8 || skill == 0xD9 || skill == 0xDA) {
|
|
return result;
|
|
}
|
|
|
|
this->SendMsg(0x1A, 1, 0, 0, 0);
|
|
this->unknown_00F8 = 0;
|
|
const int skillUse = reinterpret_cast<int>(&this->unknown_0408);
|
|
if (!HIBYTE(GetAsyncKeyState(VK_CONTROL)) && forceOption == 0) {
|
|
this->scene->player->SendMsg(nullptr, 103, 0, pick->accountId, 0, skillUse, skillUse >> 31, 1, 0, 0, 0, 0, 0, 0, 0);
|
|
this->forcedAttack = 0;
|
|
} else {
|
|
this->scene->player->SendMsg(nullptr, 103, 0, pick->accountId, 0, skillUse, skillUse >> 31, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
this->forcedAttack = 1;
|
|
}
|
|
return result;
|
|
}
|
|
default:
|
|
if (reinterpret_cast<std::intptr_t>(this->unknown_0408) == 5) {
|
|
const long long skillUse = static_cast<long long>(reinterpret_cast<int>(this)) + offsetof(CGameMode, unknown_0408);
|
|
this->scene->player->SendMsg(nullptr, 103, 0, pick->accountId, 0, static_cast<int>(skillUse), static_cast<int>(skillUse >> 32), 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
return result;
|
|
}
|
|
case 3:
|
|
this->SetCursorAction(0);
|
|
return 0;
|
|
case 1:
|
|
if (g_mouse.buttons[0] == 1 && reinterpret_cast<std::intptr_t>(this->unknown_0408) == 0) {
|
|
this->scene->player->SendMsg(nullptr, 18, 0, pick->accountId, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
break;
|
|
case 4: {
|
|
this->SetCursorAction(0);
|
|
if (g_session.IsMercenaryJob(pick->job)) {
|
|
CWorld* scene = this->scene;
|
|
if (this->unknown_040C == 0xE7 || ((scene->unknown_0048 != 0 || scene->unknown_004C != 0 || siegeMode != 0) && !g_session.IsHomunAid(pick->accountId))) {
|
|
if ((this->scene->unknown_0048 != 0 || this->scene->unknown_004C != 0 || siegeMode != 0) && !g_session.IsHomunAid(pick->accountId)) {
|
|
this->SetCursorAction(5);
|
|
}
|
|
this->RequestPlayerAction(pick->accountId, 1);
|
|
this->forcedAttack = 0;
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
const std::intptr_t mode = reinterpret_cast<std::intptr_t>(this->unknown_0408);
|
|
int attack;
|
|
if (mode == 2 || mode == 4) {
|
|
const int shift = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
attack = shift;
|
|
if (IsSupportSkill(this->unknown_040C)) {
|
|
attack = shift == 0;
|
|
}
|
|
} else {
|
|
attack = HIBYTE(GetAsyncKeyState(VK_SHIFT));
|
|
}
|
|
if (pick->unknown_0024 != 0 || this->scene->unknown_0048 != 0 || this->scene->unknown_004C != 0 || siegeMode != 0) {
|
|
attack = 1;
|
|
}
|
|
|
|
const bool allowed = pick->accountId != mercenaryAid || mode == 4;
|
|
if (allowed && attack) {
|
|
this->RequestPlayerAction(pick->accountId, 1);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|