rodecomp/Source/UI/Shortcuts/ShortcutCooldowns.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

193 lines
6.2 KiB
C++

#include "UI/Shortcuts/ShortcutCooldowns.h"
#include <algorithm>
#include <cstring>
#include <windows.h>
#include <timeapi.h>
namespace {
// OFFSET: 0x00E1DCA0
// FUNCTION: fn_23875
bool IsFirstRange(unsigned id) {
return id - 8000u <= 60;
}
// OFFSET: 0x00E1DD20
// FUNCTION: fn_23878
bool IsOtherRange(unsigned id) {
return id - 8200u <= 41 || id - 8400u <= 57;
}
}
// OFFSET: 0x00D42070
// FUNCTION: fn_21827
void ShortcutCooldowns::LoadSnapshot(
const void* packet, const std::list<ShortcutCooldownIcon>& mainIcons, const std::list<ShortcutCooldownIcon>& alternateIcons, int replayMode,
const std::uint32_t& serverTick
) {
this->records.clear();
const auto* bytes = static_cast<const unsigned char*>(packet);
std::int16_t size;
std::memcpy(&size, bytes + 2, sizeof(size));
const int count = (size - 2) / 10;
for (int index = 0; index < count; ++index) {
const unsigned char* source = bytes + 4 + index * 10;
std::uint16_t id;
std::uint32_t duration;
std::uint32_t remaining;
std::memcpy(&id, source, sizeof(id));
std::memcpy(&duration, source + 2, sizeof(duration));
std::memcpy(&remaining, source + 6, sizeof(remaining));
const std::uint32_t now = replayMode == 1 ? serverTick : timeGetTime();
ShortcutCooldownRecord value{id, now + remaining, duration, {}, {}};
for (const ShortcutCooldownIcon& icon : mainIcons) {
if (icon.id == id) {
value.main.emplace_back(icon.slot, icon.x, icon.y, duration, now, duration - remaining, 0);
}
}
for (const ShortcutCooldownIcon& icon : alternateIcons) {
if (icon.id == id) {
value.alternate.emplace_back(icon.slot, icon.x, icon.y, duration, now, duration - remaining, 0);
}
}
this->records.push_back(value);
}
}
// OFFSET: 0x00D41990
// FUNCTION: fn_21826
void ShortcutCooldowns::ApplyStart(
const void* packet, const std::list<ShortcutCooldownIcon>& mainIcons, const std::list<ShortcutCooldownIcon>& alternateIcons, int replayMode,
const std::uint32_t& serverTick
) {
const auto* bytes = static_cast<const unsigned char*>(packet);
std::uint16_t id;
std::uint32_t duration;
std::memcpy(&id, bytes + 2, sizeof(id));
std::memcpy(&duration, bytes + 4, sizeof(duration));
const std::uint32_t now = replayMode == 1 ? serverTick : timeGetTime();
ShortcutCooldownRecord value{id, now + duration, duration, {}, {}};
const auto find = [&]() {
return std::find_if(this->records.begin(), this->records.end(), [&](const ShortcutCooldownRecord& record) { return record.id == id; });
};
for (const ShortcutCooldownIcon& icon : mainIcons) {
if (icon.id != id) {
continue;
}
const auto entry = find();
if (entry == this->records.end()) {
value.main.emplace_back(icon.slot, icon.x, icon.y, duration, now, 0, 0);
this->records.push_back(value);
} else {
const auto slot = std::find_if(entry->main.begin(), entry->main.end(), [&](const CooldownState& state) { return state.slot == icon.slot; });
if (slot == entry->main.end()) {
entry->main.emplace_back(icon.slot, icon.x, icon.y, duration, now, 0, 0);
} else {
this->records.erase(entry);
value.main.emplace_back(icon.slot, icon.x, icon.y, duration, now, 0, 0);
this->records.push_back(value);
}
}
}
for (const ShortcutCooldownIcon& icon : alternateIcons) {
if (icon.id == id && find() == this->records.end()) {
value.alternate.emplace_back(icon.slot, icon.x, icon.y, duration, now, 0, 0);
this->records.push_back(value);
}
}
}
// INLINED
bool ShortcutCooldowns::RotateRows(int amount, int bank, int& rotation0, int& rotation1, const CooldownClock& clock) {
const int rows = amount < 4 ? amount : amount % 4;
if (rows <= 0) {
return false;
}
if (bank == 0 || bank == 1) {
int& rotation = bank == 0 ? rotation0 : rotation1;
rotation += rows;
if (rotation >= 4) {
rotation -= 4;
}
}
const std::uint32_t now = clock.Now();
for (auto entry = this->records.begin(); entry != this->records.end();) {
if (entry->end <= now) {
entry = this->records.erase(entry);
continue;
}
for (CooldownState& state : entry->main) {
state.slot -= 9 * rows;
state.y -= 33 * rows;
if (state.slot < 0) {
state.slot += 36;
state.y += 132;
}
}
++entry;
}
return true;
}
// INLINED
void ShortcutCooldowns::PaintMain(
const std::list<ShortcutCooldownIcon>& icons, int rows, int x, int y, CooldownDrawing& drawing, const CooldownClock& clock, RenderCommandPool& pool,
CRenderSystemBase& system
) {
const int limit = rows * 33 + 4;
this->Paint(icons, &ShortcutCooldownRecord::main, limit, x, y, drawing, clock, pool, system);
}
// INLINED
void ShortcutCooldowns::PaintAlternate(
const std::list<ShortcutCooldownIcon>& icons, int x, int y, CooldownDrawing& drawing, const CooldownClock& clock, RenderCommandPool& pool,
CRenderSystemBase& system
) {
this->Paint(icons, &ShortcutCooldownRecord::alternate, 0, x, y, drawing, clock, pool, system);
}
// INLINED
void ShortcutCooldowns::Paint(
const std::list<ShortcutCooldownIcon>& icons, std::list<CooldownState> ShortcutCooldownRecord::* values, int limit, int x, int y, CooldownDrawing& drawing,
const CooldownClock& clock, RenderCommandPool& pool, CRenderSystemBase& system
) {
const std::uint32_t now = clock.Now();
for (auto entry = this->records.begin(); entry != this->records.end();) {
if (entry->end <= now) {
entry = this->records.erase(entry);
continue;
}
std::list<CooldownState>& states = (*entry).*values;
for (const ShortcutCooldownIcon& icon : icons) {
if (entry->id == icon.id || (entry->id == 577 && !IsFirstRange(icon.id)) || (entry->id == 9999 && (IsFirstRange(icon.id) || IsOtherRange(icon.id)))) {
const auto previous = std::find_if(states.begin(), states.end(), [&](const CooldownState& state) { return state.slot == icon.slot; });
if (previous == states.end()) {
states.emplace_back(icon.slot, icon.x, icon.y, entry->duration, entry->end - entry->duration, 0, 0);
}
}
}
for (CooldownState& state : states) {
drawing.Draw(0, 0, 12, 12, state, limit, x, y, clock, pool, system);
}
++entry;
}
}