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
|
|
@ -212,6 +212,22 @@ public sealed class ClientObjectTableTests
|
|||
Assert.Equal("desc", item.Properties.Strings[100]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateProperties_projects_assessed_shared_cooldown_metadata()
|
||||
{
|
||||
var repo = new ClientObjectTable();
|
||||
var item = MakeItem(100);
|
||||
repo.AddOrUpdate(item);
|
||||
var patch = new PropertyBundle();
|
||||
patch.Ints[ClientObjectTable.SharedCooldownPropertyId] = 42;
|
||||
patch.Floats[ClientObjectTable.CooldownDurationPropertyId] = 30d;
|
||||
|
||||
repo.UpdateProperties(100, patch);
|
||||
|
||||
Assert.Equal(42u, item.CooldownId);
|
||||
Assert.Equal(30d, item.CooldownDuration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Clear_RemovesAllItems()
|
||||
{
|
||||
|
|
|
|||
22
tests/AcDream.Core.Tests/Items/ItemCooldownDisplayTests.cs
Normal file
22
tests/AcDream.Core.Tests/Items/ItemCooldownDisplayTests.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
using AcDream.Core.Items;
|
||||
namespace AcDream.Core.Tests.Items;
|
||||
|
||||
public sealed class ItemCooldownDisplayTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(10.0, 10.0, 10)]
|
||||
[InlineData(10.0, 9.0, 10)]
|
||||
[InlineData(10.0, 8.999, 9)]
|
||||
[InlineData(10.0, 5.0, 6)]
|
||||
[InlineData(10.0, 0.001, 1)]
|
||||
[InlineData(10.0, 0.0, 0)]
|
||||
[InlineData(0.0, 5.0, 0)]
|
||||
public void GetOverlayStep_matches_retail_truncation(
|
||||
double duration,
|
||||
double remaining,
|
||||
int expected)
|
||||
=> Assert.Equal(
|
||||
expected,
|
||||
ItemCooldownDisplay.GetOverlayStep(duration, remaining));
|
||||
|
||||
}
|
||||
|
|
@ -160,6 +160,87 @@ public sealed class SpellbookTests
|
|||
Assert.Equal(0, book.ActiveCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnCooldown_removes_first_expired_match_then_reveals_next_record()
|
||||
{
|
||||
var book = new Spellbook();
|
||||
var expired = new ActiveEnchantmentRecord(
|
||||
SpellId: 0x802Au,
|
||||
LayerId: 1u,
|
||||
Duration: 5d,
|
||||
CasterGuid: 0u,
|
||||
Bucket: Spellbook.CooldownBucket,
|
||||
StartTime: 0d);
|
||||
var active = expired with
|
||||
{
|
||||
LayerId = 2u,
|
||||
Duration = 30d,
|
||||
StartTime = 10d,
|
||||
};
|
||||
book.ReplaceManifest(
|
||||
new Dictionary<uint, float>(),
|
||||
[expired, active],
|
||||
Array.Empty<IReadOnlyList<uint>>(),
|
||||
Array.Empty<(uint Id, uint Amount)>(),
|
||||
0u);
|
||||
ActiveEnchantmentRecord? removed = null;
|
||||
book.EnchantmentRemoved += record => removed = record;
|
||||
|
||||
Assert.False(book.OnCooldown(
|
||||
0x2Au,
|
||||
currentTime: 20d,
|
||||
out double expiredRemaining));
|
||||
Assert.Equal(-15d, expiredRemaining);
|
||||
Assert.Equal(expired, removed);
|
||||
Assert.Equal(1, book.ActiveCount);
|
||||
|
||||
Assert.True(book.OnCooldown(
|
||||
0x2Au,
|
||||
currentTime: 20d,
|
||||
out double activeRemaining));
|
||||
Assert.Equal(20d, activeRemaining);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnCooldown_ignores_same_spell_outside_cooldown_registry()
|
||||
{
|
||||
var book = new Spellbook();
|
||||
book.OnEnchantmentAdded(new ActiveEnchantmentRecord(
|
||||
SpellId: 0x802Au,
|
||||
LayerId: 1u,
|
||||
Duration: 30d,
|
||||
CasterGuid: 0u,
|
||||
Bucket: 1u,
|
||||
StartTime: 10d));
|
||||
|
||||
Assert.False(book.OnCooldown(
|
||||
0x2Au,
|
||||
currentTime: 20d,
|
||||
out double remaining));
|
||||
Assert.Equal(0d, remaining);
|
||||
Assert.Equal(1, book.ActiveCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnCooldown_zero_group_is_inactive_and_does_not_remove()
|
||||
{
|
||||
var book = new Spellbook();
|
||||
book.OnEnchantmentAdded(new ActiveEnchantmentRecord(
|
||||
SpellId: 0x8000u,
|
||||
LayerId: 1u,
|
||||
Duration: 30d,
|
||||
CasterGuid: 0u,
|
||||
Bucket: Spellbook.CooldownBucket,
|
||||
StartTime: 10d));
|
||||
|
||||
Assert.False(book.OnCooldown(
|
||||
cooldownId: 0u,
|
||||
currentTime: 20d,
|
||||
out double remaining));
|
||||
Assert.Equal(0d, remaining);
|
||||
Assert.Equal(1, book.ActiveCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnPurgeAll_RemovesOnlyFiniteMultAndAddEnchantments()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue