using AcDream.App.UI; using AcDream.App.UI.Layout; using AcDream.Core.Spells; namespace AcDream.App.Tests.UI.Layout; public sealed class EffectsIndicatorControllerTests { private static (uint, int, int) NoTex(uint _) => (0u, 0, 0); [Fact] public void AuthoredFixture_BuildsRetailIndicatorButtons() { ElementInfo info = FixtureLoader.LoadIndicatorsInfos(); Assert.Equal(0x10000610u, info.Id); Assert.Equal(150f, info.Width); Assert.Equal(30f, info.Height); ImportedLayout layout = LayoutImporter.Build(info, NoTex, datFont: null); Assert.IsType(layout.FindElement(EffectsIndicatorController.HelpfulButtonId)); Assert.IsType(layout.FindElement(EffectsIndicatorController.HarmfulButtonId)); } [Fact] public void Enchantments_GhostAndEnableMatchingIndicator_ThenClickCorrectPanel() { var table = SpellTable.LoadFromReader(new StringReader( "Spell ID,Name,Flags [Hex]\n42,Boon,0x4\n43,Bane,0x0\n")); var spellbook = new Spellbook(table); ImportedLayout layout = BuildSyntheticLayout(); var toggled = new List(); using EffectsIndicatorController controller = EffectsIndicatorController.Bind( layout, spellbook, toggled.Add)!; UiButton helpful = Assert.IsType( layout.FindElement(EffectsIndicatorController.HelpfulButtonId)); UiButton harmful = Assert.IsType( layout.FindElement(EffectsIndicatorController.HarmfulButtonId)); Assert.False(helpful.Enabled); Assert.False(harmful.Enabled); spellbook.OnEnchantmentAdded(new ActiveEnchantmentRecord( 42u, 10u, 60f, 1u, Bucket: 4u, SpellCategory: 42u)); spellbook.OnEnchantmentAdded(new ActiveEnchantmentRecord( 43u, 11u, 60f, 2u, Bucket: 8u, SpellCategory: 43u)); Assert.False(helpful.Enabled); Assert.False(harmful.Enabled); spellbook.OnEnchantmentAdded(new ActiveEnchantmentRecord( 42u, 1u, 60f, 1u, Bucket: 1u, SpellCategory: 99u, PowerLevel: 1u)); Assert.True(helpful.Enabled); Assert.False(harmful.Enabled); helpful.OnEvent(new UiEvent(0, helpful, UiEventType.Click)); Assert.Equal([RetailPanelCatalog.PositiveEffects], toggled); spellbook.OnEnchantmentAdded(new ActiveEnchantmentRecord( 43u, 1u, 60f, 2u, Bucket: 2u, SpellCategory: 99u, PowerLevel: 7u)); // The harmful spell wins the shared category in the effects list, but // retail's raw registry counters keep both indicator types enabled. Assert.True(helpful.Enabled); Assert.True(harmful.Enabled); harmful.OnEvent(new UiEvent(0, harmful, UiEventType.Click)); Assert.Equal( [RetailPanelCatalog.PositiveEffects, RetailPanelCatalog.NegativeEffects], toggled); spellbook.OnEnchantmentRemoved(1u, 42u); Assert.False(helpful.Enabled); Assert.True(harmful.Enabled); } private static ImportedLayout BuildSyntheticLayout() { var root = new ElementInfo { Id = 1u, Type = 3u, Width = 150f, Height = 30f }; var helpful = ButtonInfo(EffectsIndicatorController.HelpfulButtonId); var harmful = ButtonInfo(EffectsIndicatorController.HarmfulButtonId); return LayoutImporter.BuildFromInfos(root, [helpful, harmful], NoTex, null); } private static ElementInfo ButtonInfo(uint id) { var info = new ElementInfo { Id = id, Type = EffectsIndicatorController.RetailClassId, Width = 20f, Height = 20f, DefaultStateId = UiButtonStateMachine.Normal, }; info.States[UiButtonStateMachine.Normal] = new UiStateInfo { Id = UiButtonStateMachine.Normal, Name = "Normal", }; info.States[UiButtonStateMachine.Ghosted] = new UiStateInfo { Id = UiButtonStateMachine.Ghosted, Name = "Ghosted", }; return info; } }