using NUnit.Framework; using BaseGames.AI; using BaseGames.Enemies; namespace BaseGames.Tests.EditMode.AI { public class DeathModuleTests { // 从一个活着的态出发,发 Died 信号进入死亡链。 static AiRuntime RunWithDeath(IDeathModule m, FakeAiContext ctx) { var b = new BrainBuilder(); AiStateFragments.Locomotion(b, "Alive", LocomotionMode.Patrol); m.Build(b); b.Entry("Alive"); b.Global().To(m.EntryState).OnEvent(AiSignal.Died); return new AiRuntime(b.Build(), ctx); } [Test] public void TerminalDeath_EntersAndStays_NoAbility() { var ctx = new FakeAiContext(); var rt = RunWithDeath(new TerminalDeath(), ctx); rt.Send(AiSignal.Died); rt.Tick(0.1f); Assert.AreEqual(TerminalDeath.Death, rt.CurrentStateName); Assert.AreEqual(0, ctx.C.Used.Count); // 演出走物理状态机,AI 不触发能力 rt.Tick(0.1f); Assert.AreEqual(TerminalDeath.Death, rt.CurrentStateName); } [Test] public void AbilityDeath_TriggersOnce_DoesNotLoop() { var ctx = new FakeAiContext(); var rt = RunWithDeath(new AbilityDeath("die"), ctx); rt.Send(AiSignal.Died); rt.Tick(0.1f); Assert.AreEqual(1, ctx.C.Used.Count); ctx.C.Running = null; // 演出播完 rt.Tick(0.1f); rt.Tick(0.1f); Assert.AreEqual(1, ctx.C.Used.Count); // 不重播 } [Test] public void TwoStageDeath_PreThenFinal() { var ctx = new FakeAiContext(); var rt = RunWithDeath(new TwoStageDeath("die_pre", "die"), ctx); rt.Send(AiSignal.Died); rt.Tick(0.1f); Assert.AreEqual(TwoStageDeath.DeathPre, rt.CurrentStateName); CollectionAssert.Contains(ctx.C.Used, "die_pre"); rt.Tick(0.1f); Assert.AreEqual(TwoStageDeath.DeathPre, rt.CurrentStateName); // 前段还在跑 ctx.C.Running = null; // 前段结束 rt.Tick(0.1f); Assert.AreEqual(TwoStageDeath.Death, rt.CurrentStateName); CollectionAssert.Contains(ctx.C.Used, "die"); } [Test] public void AbilityDeath_Build_Throws_WhenAbilityMissing() { var b = new BrainBuilder(); Assert.Throws(() => new AbilityDeath().Build(b)); } } }