fix(ui): complete live targeted healing flow
Route ACE server commands through the existing chat path, bind the retail paperdoll hit mask instead of its obscured viewport, and prefer authoritative private health vitals. Record the user-confirmed live gate and pin the production DAT widget type in tests.
This commit is contained in:
parent
eb6229394a
commit
05f6222865
11 changed files with 181 additions and 24 deletions
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
||||
namespace AcDream.App.Tests.UI.Layout;
|
||||
|
|
@ -50,7 +51,11 @@ public sealed class RetailFixtureConformanceTests
|
|||
Assert.NotNull(Find(root, InventoryController.ContentsGridId));
|
||||
Assert.NotNull(Find(root, InventoryController.ContainerListId));
|
||||
Assert.NotNull(Find(root, InventoryController.BurdenMeterId));
|
||||
Assert.NotNull(Find(root, 0x100001D5u)); // mounted paperdoll viewport
|
||||
Assert.NotNull(Find(root, PaperdollController.DollViewportId));
|
||||
Assert.NotNull(Find(root, PaperdollController.DollDragMaskId));
|
||||
|
||||
var layout = FixtureLoader.LoadInventory();
|
||||
Assert.IsType<UiButton>(layout.FindElement(PaperdollController.DollDragMaskId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -73,6 +73,25 @@ public sealed class RetailUiInteractionFlowTests
|
|||
Width = 56,
|
||||
Height = 20,
|
||||
};
|
||||
var dollViewport = new UiViewport
|
||||
{
|
||||
DatElementId = PaperdollController.DollViewportId,
|
||||
Left = 270,
|
||||
Top = 80,
|
||||
Width = 70,
|
||||
Height = 90,
|
||||
};
|
||||
var dollDragMask = new UiButton(
|
||||
new ElementInfo { Id = PaperdollController.DollDragMaskId, Type = 1 },
|
||||
static _ => (0u, 0, 0))
|
||||
{
|
||||
DatElementId = PaperdollController.DollDragMaskId,
|
||||
Left = 270,
|
||||
Top = 80,
|
||||
Width = 70,
|
||||
Height = 90,
|
||||
ZOrder = 1,
|
||||
};
|
||||
var meter = new UiMeter
|
||||
{
|
||||
DatElementId = InventoryController.BurdenMeterId,
|
||||
|
|
@ -107,6 +126,8 @@ public sealed class RetailUiInteractionFlowTests
|
|||
[InventoryController.ContentsScrollbarId] = scrollbar,
|
||||
[ChestArmorSlotId] = chestArmor,
|
||||
[SlotsButtonId] = slotsButton,
|
||||
[PaperdollController.DollViewportId] = dollViewport,
|
||||
[PaperdollController.DollDragMaskId] = dollDragMask,
|
||||
};
|
||||
|
||||
layoutRoot.AddChild(grid);
|
||||
|
|
@ -114,6 +135,8 @@ public sealed class RetailUiInteractionFlowTests
|
|||
layoutRoot.AddChild(mainPack);
|
||||
layoutRoot.AddChild(chestArmor);
|
||||
layoutRoot.AddChild(slotsButton);
|
||||
layoutRoot.AddChild(dollViewport);
|
||||
layoutRoot.AddChild(dollDragMask);
|
||||
layoutRoot.AddChild(meter);
|
||||
layoutRoot.AddChild(titleText);
|
||||
layoutRoot.AddChild(burdenText);
|
||||
|
|
@ -260,6 +283,23 @@ public sealed class RetailUiInteractionFlowTests
|
|||
Assert.False(interaction.IsTargetModeActive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InventoryTargetUse_thenPaperdollBodyClick_selfTargetsThroughUiRoot()
|
||||
{
|
||||
var h = new Harness();
|
||||
h.SeedHealthKit();
|
||||
var interaction = h.BindInventoryInteraction();
|
||||
h.BindPaperdoll(interaction);
|
||||
var probe = h.Probe();
|
||||
|
||||
Assert.True(probe.DoubleClickItem(HealthKit, ItemDragSource.Inventory));
|
||||
Assert.True(interaction.IsTargetModeActive);
|
||||
Assert.True(probe.ClickElement(PaperdollController.DollDragMaskId));
|
||||
|
||||
Assert.Equal(new[] { (HealthKit, Player) }, h.UseWithTarget);
|
||||
Assert.False(interaction.IsTargetModeActive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InventoryTargetUse_invalidInventoryItem_isConsumedWithoutSelectionFallback()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -136,4 +136,12 @@ public sealed class WeenieErrorMessagesTests
|
|||
"You fail to affect Drudge because they cannot be harmed!",
|
||||
WeenieErrorMessages.Format(0x004F, "Drudge"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_HealingTargetAlreadyFull_SubstitutesParam()
|
||||
{
|
||||
Assert.Equal(
|
||||
"+Acdream is already at full health!",
|
||||
WeenieErrorMessages.Format(0x04FF, "+Acdream"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,14 +68,16 @@ public class ChatCommandRouterTests
|
|||
Assert.DoesNotContain(log.Snapshot(), e => e.Text.Contains("Unknown command"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServerCommandWithArgs_PublishesAtFormAsSay_EvenOnChannelDefault()
|
||||
[Theory]
|
||||
[InlineData("/ci 629 5")]
|
||||
[InlineData("@ci 629 5")]
|
||||
public void ServerCommandWithArgs_PublishesCanonicalAtFormAsSay_EvenOnChannelDefault(string command)
|
||||
{
|
||||
// Commands resolve before channel routing (retail behavior):
|
||||
// even with Fellowship as the active input channel, a command
|
||||
// goes out as Say/Talk — the only wire action ACE parses @ on.
|
||||
var (vm, _, bus) = Fixture();
|
||||
var outcome = ChatCommandRouter.Submit("/ci 629 5", vm, bus, ChatChannelKind.Fellowship);
|
||||
var outcome = ChatCommandRouter.Submit(command, vm, bus, ChatChannelKind.Fellowship);
|
||||
Assert.Equal(SubmitOutcome.Sent, outcome);
|
||||
Assert.Equal(ChatChannelKind.Say, bus.Last!.Channel);
|
||||
Assert.Equal("@ci 629 5", bus.Last.Text);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,33 @@ public sealed class VitalsVMTests
|
|||
Assert.Equal(0.42f, vm.HealthPercent, precision: 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HealthPercent_LocalPrivateVitalOverridesStaleCombatPercent()
|
||||
{
|
||||
var combat = new CombatState();
|
||||
uint guid = 0x5000_0042u;
|
||||
combat.OnUpdateHealth(guid, 1f);
|
||||
|
||||
var local = new LocalPlayerState();
|
||||
local.OnVitalUpdate(vitalId: 2u, ranks: 50u, start: 50u, xp: 0u, current: 1u);
|
||||
var vm = new VitalsVM(combat, local);
|
||||
vm.SetLocalPlayerGuid(guid);
|
||||
|
||||
Assert.Equal(0.01f, vm.HealthPercent, precision: 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HealthPercent_ReadsCurrentOnlyPrivateVitalDeltaWithoutStaleCache()
|
||||
{
|
||||
var local = new LocalPlayerState();
|
||||
local.OnVitalUpdate(vitalId: 2u, ranks: 50u, start: 50u, xp: 0u, current: 100u);
|
||||
var vm = new VitalsVM(new CombatState(), local);
|
||||
|
||||
local.OnVitalCurrent(vitalId: 2u, current: 25u);
|
||||
|
||||
Assert.Equal(0.25f, vm.HealthPercent, precision: 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HealthPercent_ReturnsOne_WhenGuidUnknown()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue