feat(items): port retail shared cooldown overlays
Preserve public shared-cooldown metadata, resolve the authoritative cooldown enchantment with retail expiry semantics, and project the exact ten DAT-authored radial steps through the shared retained item-slot architecture. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
19e8863f4e
commit
6b1ae4fb76
27 changed files with 875 additions and 20 deletions
|
|
@ -17,6 +17,9 @@ namespace AcDream.Core.Spells;
|
|||
/// </summary>
|
||||
public sealed class Spellbook
|
||||
{
|
||||
public const uint CooldownSpellOffset = 0x8000u;
|
||||
public const uint CooldownBucket = 8u;
|
||||
|
||||
private readonly Dictionary<uint, float> _learnedSpells = new();
|
||||
private readonly Dictionary<uint, ActiveEnchantmentRecord> _activeById = new();
|
||||
private readonly Dictionary<uint, List<uint>> _enchantmentOrderByBucket = new();
|
||||
|
|
@ -240,6 +243,46 @@ public sealed class Spellbook
|
|||
if (changed) NotifyEnchantmentsChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retail <c>CEnchantmentRegistry::OnCooldown @ 0x005943C0</c>.
|
||||
/// Scans the cooldown list head-to-tail, stops at the first shared-group
|
||||
/// match, and removes that node when its monotonic lifetime has expired.
|
||||
/// </summary>
|
||||
public bool OnCooldown(
|
||||
uint cooldownId,
|
||||
double currentTime,
|
||||
out double remaining)
|
||||
{
|
||||
remaining = 0d;
|
||||
if (cooldownId == 0u
|
||||
|| !_enchantmentOrderByBucket.TryGetValue(
|
||||
CooldownBucket,
|
||||
out List<uint>? order))
|
||||
return false;
|
||||
|
||||
uint cooldownSpellId = unchecked(cooldownId + CooldownSpellOffset);
|
||||
for (int index = 0; index < order.Count; index++)
|
||||
{
|
||||
uint identity = order[index];
|
||||
if (!_activeById.TryGetValue(
|
||||
identity,
|
||||
out ActiveEnchantmentRecord record)
|
||||
|| (record.SpellId & 0xFFFFu) != cooldownSpellId)
|
||||
continue;
|
||||
|
||||
remaining = record.Duration + record.StartTime - currentTime;
|
||||
if (remaining > 0d)
|
||||
return true;
|
||||
|
||||
RemoveActiveEnchantment(identity, out _);
|
||||
EnchantmentRemoved?.Invoke(record);
|
||||
NotifyEnchantmentsChanged();
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retail EnchantmentRegistry::PurgeEnchantments (0x00594DE0): purge only
|
||||
/// finite-duration multiplicative/additive enchantments. Vitae, cooldowns,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue