NEO-93: Address code review — AAA tests, single-call advance, windup fix.
Co-authored-by: Cursor <cursoragent@cursor.com>pull/131/head
parent
eed176d226
commit
d3f178b5fb
|
|
@ -35,8 +35,8 @@ public sealed class NpcRuntimeOperationsTests
|
||||||
var (runtime, threat, behavior) = CreateFixture();
|
var (runtime, threat, behavior) = CreateFixture();
|
||||||
// Act
|
// Act
|
||||||
Advance(T0, runtime, threat, behavior);
|
Advance(T0, runtime, threat, behavior);
|
||||||
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
||||||
// Assert
|
// Assert
|
||||||
|
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
||||||
Assert.Equal(NpcBehaviorState.Idle, snapshot.BehaviorState);
|
Assert.Equal(NpcBehaviorState.Idle, snapshot.BehaviorState);
|
||||||
Assert.Null(snapshot.ActiveTelegraph);
|
Assert.Null(snapshot.ActiveTelegraph);
|
||||||
}
|
}
|
||||||
|
|
@ -49,8 +49,8 @@ public sealed class NpcRuntimeOperationsTests
|
||||||
SetHolder(threat, PrototypeNpcRegistry.PrototypeNpcMeleeId);
|
SetHolder(threat, PrototypeNpcRegistry.PrototypeNpcMeleeId);
|
||||||
// Act
|
// Act
|
||||||
Advance(T0, runtime, threat, behavior);
|
Advance(T0, runtime, threat, behavior);
|
||||||
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
||||||
// Assert
|
// Assert
|
||||||
|
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
||||||
Assert.Equal(NpcBehaviorState.Aggro, snapshot.BehaviorState);
|
Assert.Equal(NpcBehaviorState.Aggro, snapshot.BehaviorState);
|
||||||
Assert.Equal(T0, snapshot.PhaseStartedUtc);
|
Assert.Equal(T0, snapshot.PhaseStartedUtc);
|
||||||
Assert.Null(snapshot.ActiveTelegraph);
|
Assert.Null(snapshot.ActiveTelegraph);
|
||||||
|
|
@ -64,8 +64,8 @@ public sealed class NpcRuntimeOperationsTests
|
||||||
runtime.LastAdvancedUtc = T0;
|
runtime.LastAdvancedUtc = T0;
|
||||||
// Act
|
// Act
|
||||||
Advance(T0.AddSeconds(10), runtime, threat, behavior);
|
Advance(T0.AddSeconds(10), runtime, threat, behavior);
|
||||||
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
||||||
// Assert
|
// Assert
|
||||||
|
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
||||||
Assert.Equal(NpcBehaviorState.Idle, snapshot.BehaviorState);
|
Assert.Equal(NpcBehaviorState.Idle, snapshot.BehaviorState);
|
||||||
Assert.Null(snapshot.ActiveTelegraph);
|
Assert.Null(snapshot.ActiveTelegraph);
|
||||||
}
|
}
|
||||||
|
|
@ -79,8 +79,8 @@ public sealed class NpcRuntimeOperationsTests
|
||||||
Advance(T0, runtime, threat, behavior);
|
Advance(T0, runtime, threat, behavior);
|
||||||
// Act
|
// Act
|
||||||
Advance(T0.AddSeconds(3), runtime, threat, behavior);
|
Advance(T0.AddSeconds(3), runtime, threat, behavior);
|
||||||
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
||||||
// Assert
|
// Assert
|
||||||
|
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
||||||
Assert.Equal(NpcBehaviorState.TelegraphWindup, snapshot.BehaviorState);
|
Assert.Equal(NpcBehaviorState.TelegraphWindup, snapshot.BehaviorState);
|
||||||
Assert.Equal(T0.AddSeconds(3), snapshot.PhaseStartedUtc);
|
Assert.Equal(T0.AddSeconds(3), snapshot.PhaseStartedUtc);
|
||||||
Assert.NotNull(snapshot.ActiveTelegraph);
|
Assert.NotNull(snapshot.ActiveTelegraph);
|
||||||
|
|
@ -95,13 +95,13 @@ public sealed class NpcRuntimeOperationsTests
|
||||||
Advance(T0, runtime, threat, behavior);
|
Advance(T0, runtime, threat, behavior);
|
||||||
// Act
|
// Act
|
||||||
Advance(T0.AddSeconds(2.9), runtime, threat, behavior);
|
Advance(T0.AddSeconds(2.9), runtime, threat, behavior);
|
||||||
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
||||||
// Assert
|
// Assert
|
||||||
|
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
||||||
Assert.Equal(NpcBehaviorState.Aggro, snapshot.BehaviorState);
|
Assert.Equal(NpcBehaviorState.Aggro, snapshot.BehaviorState);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void AdvanceAll_ShouldCompleteMeleeWindupDuration_BeforeAttackExecute()
|
public void AdvanceAll_ShouldRemainTelegraphWindup_BeforeMeleeWindupCompletes()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var (runtime, threat, behavior) = CreateFixture();
|
var (runtime, threat, behavior) = CreateFixture();
|
||||||
|
|
@ -110,14 +110,27 @@ public sealed class NpcRuntimeOperationsTests
|
||||||
Advance(T0.AddSeconds(3), runtime, threat, behavior);
|
Advance(T0.AddSeconds(3), runtime, threat, behavior);
|
||||||
// Act
|
// Act
|
||||||
Advance(T0.AddSeconds(4.4), runtime, threat, behavior);
|
Advance(T0.AddSeconds(4.4), runtime, threat, behavior);
|
||||||
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var duringWindup);
|
|
||||||
Advance(T0.AddSeconds(4.5), runtime, threat, behavior);
|
|
||||||
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var afterWindup);
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(NpcBehaviorState.TelegraphWindup, duringWindup.BehaviorState);
|
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
||||||
Assert.Equal(NpcBehaviorState.Recover, afterWindup.BehaviorState);
|
Assert.Equal(NpcBehaviorState.TelegraphWindup, snapshot.BehaviorState);
|
||||||
Assert.Equal(T0.AddSeconds(4.5), afterWindup.PhaseStartedUtc);
|
}
|
||||||
Assert.Null(afterWindup.ActiveTelegraph);
|
|
||||||
|
[Fact]
|
||||||
|
public void AdvanceAll_ShouldEnterRecover_WhenMeleeWindupCompletes()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var (runtime, threat, behavior) = CreateFixture();
|
||||||
|
SetHolder(threat, PrototypeNpcRegistry.PrototypeNpcMeleeId);
|
||||||
|
Advance(T0, runtime, threat, behavior);
|
||||||
|
Advance(T0.AddSeconds(3), runtime, threat, behavior);
|
||||||
|
Advance(T0.AddSeconds(4.4), runtime, threat, behavior);
|
||||||
|
// Act
|
||||||
|
Advance(T0.AddSeconds(4.5), runtime, threat, behavior);
|
||||||
|
// Assert
|
||||||
|
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
||||||
|
Assert.Equal(NpcBehaviorState.Recover, snapshot.BehaviorState);
|
||||||
|
Assert.Equal(T0.AddSeconds(4.5), snapshot.PhaseStartedUtc);
|
||||||
|
Assert.Null(snapshot.ActiveTelegraph);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -131,8 +144,24 @@ public sealed class NpcRuntimeOperationsTests
|
||||||
Advance(T0.AddSeconds(4.5), runtime, threat, behavior);
|
Advance(T0.AddSeconds(4.5), runtime, threat, behavior);
|
||||||
// Act
|
// Act
|
||||||
Advance(T0.AddSeconds(7.5), runtime, threat, behavior);
|
Advance(T0.AddSeconds(7.5), runtime, threat, behavior);
|
||||||
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
||||||
// Assert
|
// Assert
|
||||||
|
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
||||||
|
Assert.Equal(NpcBehaviorState.TelegraphWindup, snapshot.BehaviorState);
|
||||||
|
Assert.Equal(T0.AddSeconds(7.5), snapshot.PhaseStartedUtc);
|
||||||
|
Assert.NotNull(snapshot.ActiveTelegraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AdvanceAll_ShouldRunFullMeleeCycle_ToSecondTelegraph_InSingleAdvanceCall()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var (runtime, threat, behavior) = CreateFixture();
|
||||||
|
SetHolder(threat, PrototypeNpcRegistry.PrototypeNpcMeleeId);
|
||||||
|
Advance(T0, runtime, threat, behavior);
|
||||||
|
// Act
|
||||||
|
Advance(T0.AddSeconds(7.5), runtime, threat, behavior, maxDeltaSeconds: 10);
|
||||||
|
// Assert
|
||||||
|
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
||||||
Assert.Equal(NpcBehaviorState.TelegraphWindup, snapshot.BehaviorState);
|
Assert.Equal(NpcBehaviorState.TelegraphWindup, snapshot.BehaviorState);
|
||||||
Assert.Equal(T0.AddSeconds(7.5), snapshot.PhaseStartedUtc);
|
Assert.Equal(T0.AddSeconds(7.5), snapshot.PhaseStartedUtc);
|
||||||
Assert.NotNull(snapshot.ActiveTelegraph);
|
Assert.NotNull(snapshot.ActiveTelegraph);
|
||||||
|
|
@ -149,16 +178,35 @@ public sealed class NpcRuntimeOperationsTests
|
||||||
_ = threat.TryClearHolder(PrototypeNpcRegistry.PrototypeNpcMeleeId);
|
_ = threat.TryClearHolder(PrototypeNpcRegistry.PrototypeNpcMeleeId);
|
||||||
// Act
|
// Act
|
||||||
Advance(T0.AddSeconds(3.5), runtime, threat, behavior);
|
Advance(T0.AddSeconds(3.5), runtime, threat, behavior);
|
||||||
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
||||||
// Assert
|
// Assert
|
||||||
|
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
||||||
Assert.Equal(NpcBehaviorState.Idle, snapshot.BehaviorState);
|
Assert.Equal(NpcBehaviorState.Idle, snapshot.BehaviorState);
|
||||||
Assert.Null(snapshot.ActiveTelegraph);
|
Assert.Null(snapshot.ActiveTelegraph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("prototype_npc_ranged", 4.0)]
|
||||||
|
[InlineData("prototype_npc_elite", 5.0)]
|
||||||
|
public void AdvanceAll_ShouldEnterTelegraph_AtCatalogCooldownForArchetype(
|
||||||
|
string npcInstanceId,
|
||||||
|
double attackCooldownSeconds)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var (runtime, threat, behavior) = CreateFixture();
|
||||||
|
SetHolder(threat, npcInstanceId);
|
||||||
|
Advance(T0, runtime, threat, behavior);
|
||||||
|
// Act
|
||||||
|
Advance(T0.AddSeconds(attackCooldownSeconds), runtime, threat, behavior);
|
||||||
|
// Assert
|
||||||
|
runtime.TryGet(npcInstanceId, out var snapshot);
|
||||||
|
Assert.Equal(NpcBehaviorState.TelegraphWindup, snapshot.BehaviorState);
|
||||||
|
Assert.Equal(T0.AddSeconds(attackCooldownSeconds), snapshot.PhaseStartedUtc);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("prototype_npc_ranged", 4.0, 2.0)]
|
[InlineData("prototype_npc_ranged", 4.0, 2.0)]
|
||||||
[InlineData("prototype_npc_elite", 5.0, 2.5)]
|
[InlineData("prototype_npc_elite", 5.0, 2.5)]
|
||||||
public void AdvanceAll_ShouldUseCatalogTimings_ForEachArchetype(
|
public void AdvanceAll_ShouldEnterRecover_AfterCatalogWindupForArchetype(
|
||||||
string npcInstanceId,
|
string npcInstanceId,
|
||||||
double attackCooldownSeconds,
|
double attackCooldownSeconds,
|
||||||
double telegraphWindupSeconds)
|
double telegraphWindupSeconds)
|
||||||
|
|
@ -167,22 +215,15 @@ public sealed class NpcRuntimeOperationsTests
|
||||||
var (runtime, threat, behavior) = CreateFixture();
|
var (runtime, threat, behavior) = CreateFixture();
|
||||||
SetHolder(threat, npcInstanceId);
|
SetHolder(threat, npcInstanceId);
|
||||||
Advance(T0, runtime, threat, behavior);
|
Advance(T0, runtime, threat, behavior);
|
||||||
// Act
|
|
||||||
Advance(T0.AddSeconds(attackCooldownSeconds), runtime, threat, behavior);
|
Advance(T0.AddSeconds(attackCooldownSeconds), runtime, threat, behavior);
|
||||||
runtime.TryGet(npcInstanceId, out var telegraphSnapshot);
|
// Act
|
||||||
Advance(
|
Advance(T0.AddSeconds(attackCooldownSeconds + telegraphWindupSeconds), runtime, threat, behavior);
|
||||||
T0.AddSeconds(attackCooldownSeconds + telegraphWindupSeconds),
|
|
||||||
runtime,
|
|
||||||
threat,
|
|
||||||
behavior);
|
|
||||||
runtime.TryGet(npcInstanceId, out var recoverSnapshot);
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(NpcBehaviorState.TelegraphWindup, telegraphSnapshot.BehaviorState);
|
runtime.TryGet(npcInstanceId, out var snapshot);
|
||||||
Assert.Equal(T0.AddSeconds(attackCooldownSeconds), telegraphSnapshot.PhaseStartedUtc);
|
Assert.Equal(NpcBehaviorState.Recover, snapshot.BehaviorState);
|
||||||
Assert.Equal(NpcBehaviorState.Recover, recoverSnapshot.BehaviorState);
|
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
T0.AddSeconds(attackCooldownSeconds + telegraphWindupSeconds),
|
T0.AddSeconds(attackCooldownSeconds + telegraphWindupSeconds),
|
||||||
recoverSnapshot.PhaseStartedUtc);
|
snapshot.PhaseStartedUtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -192,10 +233,10 @@ public sealed class NpcRuntimeOperationsTests
|
||||||
var (runtime, threat, behavior) = CreateFixture();
|
var (runtime, threat, behavior) = CreateFixture();
|
||||||
SetHolder(threat, PrototypeNpcRegistry.PrototypeNpcMeleeId);
|
SetHolder(threat, PrototypeNpcRegistry.PrototypeNpcMeleeId);
|
||||||
Advance(T0, runtime, threat, behavior);
|
Advance(T0, runtime, threat, behavior);
|
||||||
// Act — 10s gap with 5s cap should not reach second telegraph (needs 7.5s from aggro start)
|
// Act
|
||||||
Advance(T0.AddSeconds(10), runtime, threat, behavior, maxDeltaSeconds: 5);
|
Advance(T0.AddSeconds(10), runtime, threat, behavior, maxDeltaSeconds: 5);
|
||||||
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
|
||||||
// Assert
|
// Assert
|
||||||
|
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
|
||||||
Assert.Equal(NpcBehaviorState.Recover, snapshot.BehaviorState);
|
Assert.Equal(NpcBehaviorState.Recover, snapshot.BehaviorState);
|
||||||
Assert.Equal(T0.AddSeconds(4.5), snapshot.PhaseStartedUtc);
|
Assert.Equal(T0.AddSeconds(4.5), snapshot.PhaseStartedUtc);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -171,19 +171,13 @@ public static class NpcRuntimeOperations
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = phaseEnd;
|
cursor = phaseEnd;
|
||||||
WriteState(
|
|
||||||
runtimeStore,
|
|
||||||
npcInstanceId,
|
|
||||||
NpcBehaviorState.AttackExecute,
|
|
||||||
cursor,
|
|
||||||
activeTelegraph: null);
|
|
||||||
WriteState(
|
WriteState(
|
||||||
runtimeStore,
|
runtimeStore,
|
||||||
npcInstanceId,
|
npcInstanceId,
|
||||||
NpcBehaviorState.Recover,
|
NpcBehaviorState.Recover,
|
||||||
cursor,
|
cursor,
|
||||||
activeTelegraph: null);
|
activeTelegraph: null);
|
||||||
// telemetry: telegraph_fired / npc_state_transition (NEO-96); NEO-95 applies attackDamage at windup complete
|
// telemetry: telegraph_fired / npc_state_transition (NEO-96); logical attack_execute → recover (NEO-95 applies attackDamage)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue