fix(items): preserve wand stance and corpse use order
Keep active-combat AutoWield intent through ACE's pre-wield transition and queued trailing peace notice, while allowing explicit combat input to supersede it. Queue one-shot item interactions until the frame's movement edge has been serialized, so a movement release cannot cancel ACE's server-side corpse approach callback. Release build succeeds and all 5,890 runnable tests pass with five intentional skips. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
0392c6d721
commit
e6dd8bf6fa
10 changed files with 303 additions and 22 deletions
|
|
@ -655,6 +655,89 @@ public sealed class ItemInteractionControllerTests
|
|||
Assert.Empty(h.CombatModeRequests);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BowToWand_inActiveCombat_reassertsMagicAfterAceTrailingPeace()
|
||||
{
|
||||
var h = new Harness();
|
||||
h.Combat.SetCombatMode(CombatMode.Missile);
|
||||
const uint bow = 0x50000B93u;
|
||||
const uint wand = 0x50000B94u;
|
||||
h.Objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = bow,
|
||||
Name = "Shortbow",
|
||||
Type = ItemType.MissileWeapon,
|
||||
CombatUse = 2,
|
||||
ValidLocations = EquipMask.MissileWeapon,
|
||||
});
|
||||
h.Objects.MoveItem(bow, Player, -1, EquipMask.MissileWeapon);
|
||||
h.AddContained(wand, item =>
|
||||
{
|
||||
item.Name = "Training Wand";
|
||||
item.Type = ItemType.Caster;
|
||||
item.CombatUse = 2;
|
||||
item.ValidLocations = EquipMask.Held;
|
||||
});
|
||||
|
||||
Assert.True(h.Controller.ActivateItem(wand));
|
||||
Assert.Equal(new[] { (bow, Player, 0) }, h.Puts);
|
||||
|
||||
// ACE begins the old weapon's stance shuffle before confirming the
|
||||
// replacement wield.
|
||||
h.Combat.SetCombatMode(CombatMode.Melee);
|
||||
h.Combat.SetCombatMode(CombatMode.NonCombat);
|
||||
h.Objects.MoveItem(bow, Player, 0, EquipMask.None);
|
||||
Assert.Equal(new[] { (wand, (uint)EquipMask.Held) }, h.Wields);
|
||||
|
||||
Assert.True(h.Objects.ApplyConfirmedServerWield(
|
||||
wand,
|
||||
Player,
|
||||
EquipMask.Held));
|
||||
h.Combat.SetCombatMode(CombatMode.Magic);
|
||||
Assert.Empty(h.CombatModeRequests);
|
||||
|
||||
// The queued dequip callback publishes one final Peace after ACE has
|
||||
// already selected Magic. Reassert only at that ordered boundary.
|
||||
h.Combat.SetCombatMode(CombatMode.NonCombat);
|
||||
|
||||
Assert.Equal(new[] { CombatMode.Magic }, h.CombatModeRequests);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExplicitCombatRequest_cancelsPendingAutoWieldSettlement()
|
||||
{
|
||||
var h = new Harness();
|
||||
h.Combat.SetCombatMode(CombatMode.Missile);
|
||||
const uint bow = 0x50000B95u;
|
||||
const uint wand = 0x50000B96u;
|
||||
h.Objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = bow,
|
||||
Type = ItemType.MissileWeapon,
|
||||
ValidLocations = EquipMask.MissileWeapon,
|
||||
});
|
||||
h.Objects.MoveItem(bow, Player, -1, EquipMask.MissileWeapon);
|
||||
h.AddContained(wand, item =>
|
||||
{
|
||||
item.Type = ItemType.Caster;
|
||||
item.ValidLocations = EquipMask.Held;
|
||||
});
|
||||
|
||||
Assert.True(h.Controller.ActivateItem(wand));
|
||||
h.Combat.SetCombatMode(CombatMode.NonCombat);
|
||||
h.Objects.MoveItem(bow, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerWield(
|
||||
wand,
|
||||
Player,
|
||||
EquipMask.Held));
|
||||
h.Combat.SetCombatMode(CombatMode.Magic);
|
||||
|
||||
h.Controller.NotifyExplicitCombatModeRequest();
|
||||
h.Combat.SetCombatMode(CombatMode.NonCombat);
|
||||
|
||||
Assert.Empty(h.CombatModeRequests);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ActiveWeaponReplacement_serverSettlesDirectly_doesNotReassertLaterPeace()
|
||||
{
|
||||
|
|
@ -678,7 +761,6 @@ public sealed class ItemInteractionControllerTests
|
|||
});
|
||||
|
||||
Assert.True(h.Controller.ActivateItem(bow));
|
||||
h.Combat.SetCombatMode(CombatMode.Melee);
|
||||
h.Objects.MoveItem(wand, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerWield(
|
||||
bow, Player, EquipMask.MissileWeapon));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue