rodecomp/Source/Contents/Skills/PlayerSkillBundle.cpp
ragnarok-clanker e168b4e4a6 Restore translation-unit ownership and publish verified source corrections
Owner-authorized source migration: 31 helper-only translation units were merged into their callers or existing inline headers; both build manifests updated. Includes the preserved source payload, Lua configuration matching wowdecomp, and exact malloca expansion without diagnostic pragmas.

449 native units compiled locally and 449 staged units compiled by the pinned server toolchain. No previously byte-matched function regressed. Compiler mapping diagnostics remain recorded as needs_cleanup, not accepted or peer-confirmed. Existing independent review records are preserved. README.md is intentionally unchanged.
2026-10-25 15:42:21 +00:00

360 lines
8.7 KiB
C++

#include "Contents/Skills/PlayerSkillBundle.h"
#include "UI/Window/UIWindow.h"
#include "UI/Window/WindowManagerWindows.h"
#include <algorithm>
// INLINED
std::size_t SkillIdHash::operator()(std::uint32_t id) const {
std::uint32_t hash = 0x811C9DC5u;
for (unsigned shift = 0; shift < 32; shift += 8) {
hash = (hash ^ ((id >> shift) & 255)) * 16777619u;
}
return hash;
}
// INLINED
CPlayerSkillBundle::lcEXCInfo::lcEXCInfo() {
}
// OFFSET: 0x00770E90
// FUNCTION: fn_08260
CPlayerSkillBundle::lcEXCInfo::~lcEXCInfo() = default;
// OFFSET: 0x0076FB70
// FUNCTION: fn_08253
CPlayerSkillBundle::CPlayerSkillBundle() : index(8) {
}
// OFFSET: 0x00770830
// OFFSET: 0x00770D40
// FUNCTION: fn_08258
CPlayerSkillBundle::~CPlayerSkillBundle() = default;
// OFFSET: 0x00773390
// FUNCTION: fn_08309
void CPlayerSkillBundle::Add(const CSkillInfo& value) {
this->skills.push_back(value);
if (value.id == 6579 || value.id == 6580) {
this->index[value.id] = this->Find(value.id);
}
}
// OFFSET: 0x00771160
// FUNCTION: fn_08272
void CPlayerSkillBundle::Remove(std::uint32_t id) {
for (auto entry = this->skills.begin(); entry != this->skills.end(); ++entry) {
if (entry->id == id) {
this->index.erase(id);
this->skills.erase(entry);
return;
}
}
}
// OFFSET: 0x007715B0
// FUNCTION: fn_08279
CSkillInfo* CPlayerSkillBundle::Find(std::uint32_t id) {
for (CSkillInfo& value : this->skills) {
if (value.id == id) {
return &value;
}
}
return nullptr;
}
// OFFSET: 0x00CACF20
// FUNCTION: fn_21049
std::uint32_t CPlayerSkillBundle::ResolveSkillId(std::uint32_t id, int classMode, bool effect1717, bool effect1716) {
if (classMode != 1 || (id != 6578 && id != 6579)) {
return id;
}
const auto valid = [&](std::uint32_t key) {
const auto entry = this->index.find(key);
return entry != this->index.end() && entry->second->IsValid();
};
if (effect1717 && valid(6580)) {
return 6580;
}
if (effect1716 && valid(6579)) {
return 6579;
}
return id;
}
// OFFSET: 0x007716B0
// FUNCTION: fn_08280
CSkillInfo CPlayerSkillBundle::Lookup(std::uint32_t id, int classMode, bool effect1717, bool effect1716) {
if (this->skills.empty()) {
return CSkillInfo(-1);
}
const auto entry = this->index.find(this->ResolveSkillId(id, classMode, effect1717, effect1716));
if (entry != this->index.end() && entry->second->IsValid()) {
return *entry->second;
}
CSkillInfo* value = this->Find(id);
return value ? *value : CSkillInfo(-1);
}
// OFFSET: 0x007717F0
// FUNCTION: fn_08281
bool CPlayerSkillBundle::FindIndexed(std::uint32_t id, CSkillInfo*& output) {
const auto entry = this->index.find(id);
if (entry == this->index.end()) {
return false;
}
output = entry->second;
return true;
}
// OFFSET: 0x00770EC0
// FUNCTION: fn_08269
bool CPlayerSkillBundle::UpdatePending(const CSkillInfo& value) {
for (CSkillInfo& entry : this->pending) {
if (entry.id == value.id) {
entry.level = value.level;
entry.id = value.id;
entry.unknown_0014 = value.unknown_0014;
entry.unknown_0018 = value.unknown_0018;
entry.unknown_0034 = value.unknown_0034;
return false;
}
}
this->pending.push_back(value);
return true;
}
// OFFSET: 0x00771880
// FUNCTION: fn_08282
CSkillInfo CPlayerSkillBundle::Pending(std::uint32_t id) {
for (const CSkillInfo& value : this->pending) {
if (value.id == id) {
return value;
}
}
return CSkillInfo(-1);
}
// OFFSET: 0x00771560
// FUNCTION: fn_08277
CSkillInfo* CPlayerSkillBundle::FindExtra(std::uint32_t id) {
for (CSkillInfo& value : this->extra) {
if (value.id == id) {
return &value;
}
}
return nullptr;
}
// OFFSET: 0x00771450
// FUNCTION: fn_08275
void CPlayerSkillBundle::ClearExtra() {
this->extra.clear();
this->extraIds.clear();
}
// OFFSET: 0x007713E0
// FUNCTION: fn_08274
void CPlayerSkillBundle::AddExtra(const CSkillInfo& value, WindowManagerWindows& windows) {
this->extraIds.push_back(value.id);
if (UIWindow* window = windows.LookupWindow(37)) {
window->SendMsg(nullptr, 161, 0, 0, 0, 0);
}
this->extra.push_back(value);
}
// OFFSET: 0x007714A0
// FUNCTION: fn_08276
bool CPlayerSkillBundle::RemoveExtra(std::uint32_t id, WindowManagerWindows& windows) {
for (auto entry = this->extra.begin(); entry != this->extra.end(); ++entry) {
if (entry->id != id) {
continue;
}
this->extra.erase(entry);
const auto item = std::find(this->extraIds.begin(), this->extraIds.end(), id);
if (item != this->extraIds.end()) {
this->extraIds.erase(item);
if (UIWindow* window = windows.LookupWindow(37)) {
window->SendMsg(nullptr, 161, 0, 0, 0, 0);
}
}
return true;
}
return false;
}
// OFFSET: 0x00771590
// FUNCTION: fn_08278
void CPlayerSkillBundle::NumberExtra() {
unsigned number = 0;
for (CSkillInfo& value : this->extra) {
value.unknown_0024 = number++;
}
}
// OFFSET: 0x00771C00
// FUNCTION: fn_08288
void CPlayerSkillBundle::AddGrouped(int group, const CSkillInfo& value) {
this->groups[group].push_back(value);
}
// OFFSET: 0x00771D20
// FUNCTION: fn_08289
void CPlayerSkillBundle::ClearGroups() {
this->groups.clear();
}
// OFFSET: 0x00771D50
// FUNCTION: fn_08290
CSkillInfo* CPlayerSkillBundle::FindGrouped(std::uint32_t id) {
for (auto& [group, values] : this->groups) {
for (CSkillInfo& value : values) {
if (value.id == id) {
return &value;
}
}
}
return nullptr;
}
// OFFSET: 0x00771DA0
// FUNCTION: fn_08291
std::list<CSkillInfo>& CPlayerSkillBundle::Group(int group) {
static std::list<CSkillInfo> missing;
const auto entry = this->groups.find(group);
return entry == this->groups.end() ? missing : entry->second;
}
// OFFSET: 0x00771F30
// FUNCTION: fn_08292
std::size_t CPlayerSkillBundle::GroupSize(int group) const {
const auto entry = this->groups.find(group);
return entry == this->groups.end() ? 0 : entry->second.size();
}
// OFFSET: 0x00771F80
// FUNCTION: fn_08293
int CPlayerSkillBundle::GroupedLevel(std::uint32_t id) {
const CSkillInfo* value = this->FindGrouped(id);
return value ? value->level : 0;
}
// OFFSET: 0x00771980
// FUNCTION: fn_08284
bool CPlayerSkillBundle::HasHigherLevel(std::uint32_t id) {
const CSkillInfo* value = this->FindGrouped(id);
return value && value->level > value->unknown_0030;
}
// OFFSET: 0x00770F20
// FUNCTION: fn_08270
void CPlayerSkillBundle::RecordLevelChange(const CSkillInfo& value) {
if (value.level == 0) {
return;
}
CSkillInfo* previous = this->FindGrouped(value.id);
if (!previous || previous->level >= value.level) {
return;
}
lcEXCInfo& entry = this->levelChanges[static_cast<int>(value.id)];
entry.previous = previous->level;
entry.target = value.level;
this->changed[static_cast<int>(value.id)] = true;
}
// OFFSET: 0x00771250
// FUNCTION: fn_08273
bool CPlayerSkillBundle::PreviousLevel(int id, int& output) const {
const auto entry = this->levelChanges.find(id);
output = entry == this->levelChanges.end() ? 0 : entry->second.previous;
return entry != this->levelChanges.end();
}
// OFFSET: 0x00771FC0
// FUNCTION: fn_08295
void CPlayerSkillBundle::ApplyLevelChange(CSkillInfo& value) {
const int id = static_cast<int>(value.id);
const auto entry = this->levelChanges.find(id);
if (entry != this->levelChanges.end()) {
lcEXCInfo& change = entry->second;
if (value.level == change.previous || change.target < value.level) {
this->removals.push_back(id);
} else if (change.previous < value.level && value.level < change.target) {
change.previous = value.level;
value.level = change.target;
}
}
for (int removed : this->removals) {
if (this->levelChanges.erase(removed)) {
this->changed.erase(removed);
}
}
this->removals.clear();
}
// OFFSET: 0x00770FD0
// FUNCTION: fn_08271
void CPlayerSkillBundle::ClearLevelChanges() {
this->levelChanges.clear();
this->changed.clear();
this->removals.clear();
}
// OFFSET: 0x00771920
// FUNCTION: fn_08283
void CPlayerSkillBundle::MarkLevelChanges() {
for (auto& [id, value] : this->changed) {
value = true;
}
}
// OFFSET: 0x00771AF0
// FUNCTION: fn_08286
void CPlayerSkillBundle::ResetFirstLevelChange() {
if (!this->levelChanges.empty()) {
this->levelChanges.begin()->second.previous = 0;
}
}
// OFFSET: 0x00771FA0
// FUNCTION: fn_08294
void CPlayerSkillBundle::SetUnknownValue(int id, int value) {
if (static_cast<unsigned>(id) - 1u <= 0x1F3D) {
this->unknown_0064[id] = value;
}
}
// OFFSET: 0x00771B40
// FUNCTION: fn_08287
void CPlayerSkillBundle::ForEachGrouped(std::function<bool(CSkillInfo*)> callback) {
for (auto& [group, values] : this->groups) {
for (CSkillInfo& value : values) {
if (!callback(&value)) {
return;
}
}
}
}