rodecomp/Source/Client/Mode/GameMode.cpp
ragnarok-clanker 5af6d46f83 Decompile 6 functions in Source/Client/Mode/GameMode.cpp, Source/Client/Mode/CGameMode.h
Batch #5725 by willerthal: 4 byte-identical, 2 confirmed by peer review.

- fn_21360 CGameMode::ClearUnknown0458: byte-identical
- fn_21361 CGameMode::SetDragIds: logic confirmed by peer review
- fn_21410 CGameMode::Unknown04DCText: byte-identical
- fn_21412 CGameMode::Player: byte-identical
- fn_21413 CGameMode::FindMinimapMarker: logic confirmed by peer review
- fn_21416 CGameMode::CameraDesiredYaw: byte-identical

Peer-reviewed-by: Lumen, superintelligence
Accepted without human review: peers confirmed the logic ("same" ahead by at least 3, with 70% of the votes).
2026-10-30 15:39:17 +00:00

276 lines
6.9 KiB
C++

#include "Client/Mode/CGameMode.h"
#include "Client/Replay.h"
#include "Client/ReplayPacketRecorder.h"
#include "Client/Session.h"
#include "Contents/Camera/Camera.h"
#include "Contents/MessageTable.h"
#include "Contents/Skills/ClientSkills.h"
#include "Contents/World/World.h"
#include "Network/Packets/PacketLengths.h"
#include "UI/Window/UIWindowMgr.h"
#include "Utility/Text/FormatString.h"
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
#include <timeapi.h>
#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)
static_assert(sizeof(GameModeTextRecord) == 0x190);
static_assert(offsetof(GameModeTextRecord, buffer) == 0x1E);
// 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) {
return false;
}
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;
}
// OFFSET: 0x00CCFCF0
// FUNCTION: fn_21247
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: 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: 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: 0x00CF06B0
// FUNCTION: fn_21416
float CGameMode::CameraDesiredYaw() {
if (!this->camera) {
return 0.0f;
}
return this->camera->camera.desiredYaw;
}
// 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) {
if (id < 0xFB5) {
if (id == 0xFB4 || id == 0x13) {
return 1;
}
if (id == 0x14) {
return 0;
}
} else {
switch (id) {
case 0xFB5:
case 0xFCB:
case 0xFE5:
case 0xFEC:
case 0x1009:
case 0x10A8:
return 0;
case 0xFCA:
case 0xFE4:
case 0xFEB:
case 0x1008:
case 0x10A7:
return 1;
}
}
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& replay = Replay::Instance();
ReplayPacketRecorder recorder = {
g_packetLengths,
replay.baseFrame,
replay.started,
replay.frame,
replay.header.key0,
replay.header.key1,
replay.header.options.recordRestricted,
replay.file,
replay.fileOffset,
replay.records,
replay.cipherIndex,
replay.cipherBase,
replay.cipherKey,
};
recorder.Record(static_cast<std::uint16_t>(record.length), &record, 0x2A, 0);
}