246 lines
6.9 KiB
C++
246 lines
6.9 KiB
C++
#include "Contents/ClientSkills.h"
|
|
#include "Script/LuaScript.h"
|
|
#include "UI/UIWindow.h"
|
|
#include "UI/WindowManagerWindows.h"
|
|
|
|
#include <bit>
|
|
#include <cstring>
|
|
|
|
namespace {
|
|
CSkillInfo Find(const std::list<CSkillInfo>& values, std::uint32_t id) {
|
|
for (const CSkillInfo& value : values) {
|
|
if (value.id == id) {
|
|
return value;
|
|
}
|
|
}
|
|
return CSkillInfo(-1);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00E1DF20
|
|
// FUNCTION: fn_23886
|
|
bool ClientSkills::HasEffect(std::uint32_t id) const {
|
|
for (const ActiveSkillEffect& effect : this->effects) {
|
|
if (effect.id == id) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// OFFSET: 0x00E096F0
|
|
// FUNCTION: fn_23782
|
|
CSkillInfo ClientSkills::LookupFirst(std::uint32_t id) const {
|
|
return Find(this->firstRange, id);
|
|
}
|
|
// OFFSET: 0x00E09A10
|
|
// FUNCTION: fn_23787
|
|
CSkillInfo ClientSkills::LookupOther(std::uint32_t id) const {
|
|
return Find(this->otherRanges, id);
|
|
}
|
|
// OFFSET: 0x00E095B0
|
|
// FUNCTION: fn_23780
|
|
CSkillInfo ClientSkills::LookupAdditional(std::uint32_t id) const {
|
|
return Find(this->additional, id);
|
|
}
|
|
|
|
// OFFSET: 0x00E088A0
|
|
// FUNCTION: fn_23767
|
|
CSkillInfo ClientSkills::Lookup(std::uint32_t id) const {
|
|
if (id - 8000u <= 60) {
|
|
return this->LookupFirst(id);
|
|
}
|
|
if (id - 8200u <= 41 || id - 8400u <= 57) {
|
|
return this->LookupOther(id);
|
|
}
|
|
if (id - 10000u <= 19) {
|
|
return this->LookupAdditional(id);
|
|
}
|
|
return this->bundle.Lookup(id, this->classMode, this->HasEffect(1717), this->HasEffect(1716));
|
|
}
|
|
|
|
// OFFSET: 0x00E25240
|
|
// FUNCTION: fn_23904
|
|
void SkillWindows::Notify() {
|
|
if (this->first) {
|
|
this->first->SendMsg(nullptr, 23, 0, 0, 0, 0);
|
|
}
|
|
|
|
if (this->second) {
|
|
this->second->SendMsg(nullptr, 23, 0, 0, 0, 0);
|
|
}
|
|
|
|
if (UIWindow* window = this->windows.LookupWindow(159)) {
|
|
window->SendMsg(nullptr, 23, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00E08530
|
|
// FUNCTION: fn_23762
|
|
void ClientSkills::Remove(std::uint32_t id, SkillWindows& windows) {
|
|
if (CSkillInfo* skill = this->bundle.FindGrouped(id)) {
|
|
int previous;
|
|
if (this->bundle.PreviousLevel(std::bit_cast<int>(id), previous)) {
|
|
skill->level = previous;
|
|
}
|
|
|
|
windows.Notify();
|
|
return;
|
|
}
|
|
|
|
this->bundle.Remove(id);
|
|
if (this->bundle.RemoveExtra(id, windows.windows)) {
|
|
windows.Notify();
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00DE0E40
|
|
// FUNCTION: fn_23474
|
|
int SkillUseLevels::Lookup(int id) const {
|
|
const auto value = static_cast<std::uint32_t>(id);
|
|
if (value - 1u <= 0x1F3Du) {
|
|
return this->use[value];
|
|
}
|
|
|
|
if (id > 10000) {
|
|
return this->additional[value - 10000u];
|
|
}
|
|
|
|
if (value - 8000u <= 60u) {
|
|
return this->homunculus[value - 8000u];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// OFFSET: 0x00E07540
|
|
bool ClientSkills::Update(
|
|
const CSkillInfo& value,
|
|
unsigned char notify,
|
|
unsigned char updateUnknown000C,
|
|
LuaScript& script,
|
|
const SkillUseLevels& levels,
|
|
SkillWindows& windows
|
|
) {
|
|
{
|
|
// Keep the original snapshot: Lua/window callbacks may mutate the input.
|
|
CSkillInfo snapshot(value);
|
|
const auto update = [](CSkillInfo& target, const CSkillInfo& source, bool copy000C, bool copy0030) {
|
|
target.level = source.level;
|
|
std::memcpy(&target.unknown_0014, &source.unknown_0014, sizeof(target.unknown_0014));
|
|
std::memcpy(&target.unknown_001C, &source.unknown_001C, sizeof(target.unknown_001C));
|
|
std::memcpy(&target.unknown_0018, &source.unknown_0018, sizeof(target.unknown_0018));
|
|
if (copy000C) {
|
|
std::memcpy(&target.unknown_000C, &source.unknown_000C, sizeof(target.unknown_000C));
|
|
}
|
|
if (copy0030) {
|
|
target.unknown_0030 = source.unknown_0030;
|
|
}
|
|
target.unknown_0034 = source.unknown_0034;
|
|
};
|
|
|
|
CSkillInfo* grouped = this->bundle.FindGrouped(snapshot.id);
|
|
if (grouped) {
|
|
update(*grouped, snapshot, true, true);
|
|
} else if (snapshot.available) {
|
|
if (CSkillInfo* extra = this->bundle.FindExtra(snapshot.id)) {
|
|
update(*extra, snapshot, true, false);
|
|
} else {
|
|
snapshot.unknown_0024 = UINT32_MAX;
|
|
snapshot.unknown_002C = 0;
|
|
this->bundle.AddExtra(snapshot, windows.windows);
|
|
}
|
|
}
|
|
|
|
if (grouped || snapshot.available) {
|
|
if (CSkillInfo::UsesLevel(script, std::bit_cast<int>(snapshot.id)) && snapshot.level != 0) {
|
|
const int saved = levels.Lookup(std::bit_cast<int>(snapshot.id));
|
|
if (saved <= 0 || saved > snapshot.level) {
|
|
this->bundle.SetUnknownValue(std::bit_cast<int>(snapshot.id), snapshot.level);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CSkillInfo* existing = this->bundle.Find(value.id)) {
|
|
existing->level = value.level;
|
|
std::memcpy(&existing->unknown_0014, &value.unknown_0014, sizeof(existing->unknown_0014));
|
|
std::memcpy(&existing->unknown_001C, &value.unknown_001C, sizeof(existing->unknown_001C));
|
|
std::memcpy(&existing->unknown_0018, &value.unknown_0018, sizeof(existing->unknown_0018));
|
|
if (updateUnknown000C == 1) {
|
|
std::memcpy(&existing->unknown_000C, &value.unknown_000C, sizeof(existing->unknown_000C));
|
|
}
|
|
existing->unknown_0030 = value.unknown_0030;
|
|
existing->unknown_0034 = value.unknown_0034;
|
|
if (notify == 1) {
|
|
windows.Notify();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
this->bundle.Add(value);
|
|
if (notify != 0) {
|
|
windows.Notify();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// OFFSET: 0x00E251C0
|
|
// FUNCTION: fn_23902
|
|
// OFFSET: 0x00E25200
|
|
// FUNCTION: fn_23903
|
|
void CompanionSkills::Notify() {
|
|
if (this->window) {
|
|
this->window->SendMsg(nullptr, 23, 0, 0, 0, 0);
|
|
}
|
|
|
|
if (this->sharedWindow) {
|
|
this->sharedWindow->SendMsg(nullptr, 23, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00E072F0
|
|
// FUNCTION: fn_23741
|
|
// OFFSET: 0x00E07380
|
|
// FUNCTION: fn_23742
|
|
bool CompanionSkills::Update(const CSkillInfo& value, unsigned char notify) {
|
|
for (CSkillInfo& skill : this->skills) {
|
|
if (skill.id == value.id) {
|
|
skill.level = value.level;
|
|
std::memcpy(&skill.unknown_0014, &value.unknown_0014, sizeof(skill.unknown_0014));
|
|
std::memcpy(&skill.unknown_001C, &value.unknown_001C, sizeof(skill.unknown_001C));
|
|
std::memcpy(&skill.unknown_0018, &value.unknown_0018, sizeof(skill.unknown_0018));
|
|
std::memcpy(&skill.unknown_000C, &value.unknown_000C, sizeof(skill.unknown_000C));
|
|
skill.unknown_0034 = value.unknown_0034;
|
|
|
|
if (notify) {
|
|
this->Notify();
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
this->skills.push_back(value);
|
|
if (notify) {
|
|
this->Notify();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// OFFSET: 0x00E07290
|
|
// FUNCTION: fn_23740
|
|
bool ClientSkills::UpdateAdditional(const CSkillInfo& value, int) {
|
|
for (CSkillInfo& skill : this->additional) {
|
|
if (skill.id == value.id) {
|
|
skill.level = value.level;
|
|
std::memcpy(&skill.unknown_0014, &value.unknown_0014, sizeof(skill.unknown_0014));
|
|
std::memcpy(&skill.unknown_001C, &value.unknown_001C, sizeof(skill.unknown_001C));
|
|
std::memcpy(&skill.unknown_0018, &value.unknown_0018, sizeof(skill.unknown_0018));
|
|
skill.unknown_0034 = value.unknown_0034;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
this->additional.push_back(value);
|
|
return true;
|
|
}
|