refactor(runtime): own combat and magic intent
Move attack build/repeat state, combat-mode policy, authoritative auto-target transitions, and spell-cast intent beneath RuntimeActionState. Keep App as the input, world-query, DAT-policy, transport, and presentation adapter while preserving retail request and busy ordering. Add direct/graphical parity, reset, failure, and instance-isolation coverage. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
parent
81b31857c6
commit
20df9d155d
49 changed files with 1949 additions and 634 deletions
|
|
@ -1,99 +0,0 @@
|
|||
using AcDream.App.Combat;
|
||||
using AcDream.Core.Combat;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Core.Selection;
|
||||
|
||||
namespace AcDream.App.Tests.Combat;
|
||||
|
||||
public sealed class CombatTargetControllerTests
|
||||
{
|
||||
[Fact]
|
||||
public void DeadSelectedTarget_AutoTargetEnabled_SelectsClosestReplacement()
|
||||
{
|
||||
var combat = new CombatState();
|
||||
combat.SetCombatMode(CombatMode.Melee);
|
||||
var selection = new SelectionState();
|
||||
selection.Select(0x50000001u, SelectionChangeSource.World);
|
||||
int calls = 0;
|
||||
using var controller = new CombatTargetController(
|
||||
combat,
|
||||
selection,
|
||||
autoTarget: () => true,
|
||||
selectClosestTarget: () =>
|
||||
{
|
||||
calls++;
|
||||
selection.Select(0x50000002u, SelectionChangeSource.System);
|
||||
return 0x50000002u;
|
||||
});
|
||||
|
||||
controller.OnMotionApplied(0x50000001u, MotionCommand.Dead);
|
||||
|
||||
Assert.Equal(1, calls);
|
||||
Assert.Equal(0x50000002u, selection.SelectedObjectId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeadSelectedTarget_AutoTargetDisabled_LeavesSelectionClear()
|
||||
{
|
||||
var combat = new CombatState();
|
||||
combat.SetCombatMode(CombatMode.Melee);
|
||||
var selection = new SelectionState();
|
||||
selection.Select(0x50000001u, SelectionChangeSource.World);
|
||||
int calls = 0;
|
||||
using var controller = new CombatTargetController(
|
||||
combat, selection, () => false, () => { calls++; return null; });
|
||||
|
||||
controller.OnMotionApplied(0x50000001u, MotionCommand.Dead);
|
||||
|
||||
Assert.Equal(0, calls);
|
||||
Assert.Null(selection.SelectedObjectId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeadSelectedTarget_NonCombatMode_DoesNotAutoTarget()
|
||||
{
|
||||
var combat = new CombatState();
|
||||
var selection = new SelectionState();
|
||||
selection.Select(0x50000001u, SelectionChangeSource.World);
|
||||
int calls = 0;
|
||||
using var controller = new CombatTargetController(
|
||||
combat, selection, () => true, () => { calls++; return null; });
|
||||
|
||||
controller.OnMotionApplied(0x50000001u, MotionCommand.Dead);
|
||||
|
||||
Assert.Equal(0, calls);
|
||||
Assert.Null(selection.SelectedObjectId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeadUnselectedObject_DoesNotDisturbCurrentTarget()
|
||||
{
|
||||
var combat = new CombatState();
|
||||
combat.SetCombatMode(CombatMode.Missile);
|
||||
var selection = new SelectionState();
|
||||
selection.Select(0x50000002u, SelectionChangeSource.World);
|
||||
using var controller = new CombatTargetController(
|
||||
combat, selection, () => true, () => throw new InvalidOperationException());
|
||||
|
||||
controller.OnMotionApplied(0x50000001u, MotionCommand.Dead);
|
||||
|
||||
Assert.Equal(0x50000002u, selection.SelectedObjectId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SessionReset_DoesNotAcquireTargetFromDepartingWorld()
|
||||
{
|
||||
var combat = new CombatState();
|
||||
combat.SetCombatMode(CombatMode.Missile);
|
||||
var selection = new SelectionState();
|
||||
selection.Select(0x50000002u, SelectionChangeSource.World);
|
||||
int calls = 0;
|
||||
using var controller = new CombatTargetController(
|
||||
combat, selection, () => true, () => { calls++; return null; });
|
||||
|
||||
selection.Reset();
|
||||
|
||||
Assert.Equal(0, calls);
|
||||
Assert.Null(selection.SelectedObjectId);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue