using Godosa.Core.Runs; using Godosa.Core.Runs.Scripts; using Xunit; using static Godosa.Core.Tests.Runs.Scripts.ScriptRunnerTests; namespace Godosa.Core.Tests.Runs.Scripts; /// Multi-click verbs (walk-path, fight, travel-to): a poll may hand the runner more input; the plan plays from /// the next frame (its frame 0), the action is not polled until it is sent. public sealed class ActionInputTests { [Fact] public void PollInput_PlaysFromTheNextFrame_ThenPollsAgain() { var g = new FakeGame(); var polls = new List(); var follow = new InputPlan([new(0, new InputEvent(InputKind.KeyDown, Key: "B")), new(2, new InputEvent(InputKind.KeyUp, Key: "B"))]); g.ActionTable["walk"] = new FakeAction(VerbKind.Player, _ => new ActionStart(new InputPlan([new(0, new InputEvent(InputKind.KeyDown, Key: "A"))])), n => { polls.Add(n); return n == 1 ? StepStatus.Input(follow) : StepStatus.Done; }); var (r, output) = Run("format 1\nmode player\nwalk\nlog done", g); Assert.True(r.Outcome == RunOutcome.Passed, string.Join("\n", output)); Assert.Equal(["A", "B", "B"], g.Sent.Select(s => s.Event.Key)); var a = g.Sent[0].Frame; Assert.Equal(a + 1, g.Sent[1].Frame); // polled after frame a → B on the next frame Assert.Equal(a + 3, g.Sent[2].Frame); // its frame 2 Assert.Equal([1, 2], polls); // no poll while the follow-up plan is unsent Assert.Contains("done", output); } [Fact] public void PollInput_HalfSent_ReleasedOnFailure() { var g = new FakeGame(); var follow = new InputPlan([new(0, new InputEvent(InputKind.KeyDown, Key: "B")), new(50, new InputEvent(InputKind.KeyUp, Key: "B"))]); g.ActionTable["walk"] = new FakeAction(VerbKind.Player, _ => new ActionStart(), n => StepStatus.Input(follow)); var (r, _) = Run("format 1\nmode player\nwalk", g, new ScriptRunOptions { StepCap = 10 }); Assert.Equal(RunOutcome.Failed, r.Outcome); Assert.Equal(InputKind.KeyUp, g.Sent[^1].Event.Kind); // the held key is let go } }