using BardFrontline.Core; using System.Text.Json; static class PressureTests { static Actor Self(params uint[] states) => new(1, "self", 60000, 60000, 0, false, true, false, 0, [.. states]); static Actor Enemy(ulong id = 10, uint hp = 30000) => new(id, "enemy", hp, 60000, 18, true, true, false, 0, []); static CombatSnapshot Snap(params uint[] states) => new(Self(states), 10000, 10000, true, false, 10, false, [Enemy()], [], 0); static Settings Config() => new() { Burst = BurstStrategy.Pressure }; static ActionDecision? Decide(CombatSnapshot s, Settings c, params Skill[] ready) => new Rotation().Decide(s, c, new Fake(ready)); static void Is(Skill skill, ActionDecision? d) => Suite.Equal(skill, d?.Skill); public static void Run(Suite suite) { suite.Run("Pressure opt-in preserves serialized modes and original default", () => { Suite.Equal(BurstStrategy.Normal, new Settings().Burst); foreach (var mode in Enum.GetValues()) { var c = JsonSerializer.Deserialize(JsonSerializer.Serialize(new Settings { Burst = mode }))!; c.Normalize(); Suite.Equal(mode, c.Burst); } Suite.Equal(0, (int)BurstStrategy.Normal); Suite.Equal(1, (int)BurstStrategy.AlignBuffs); Suite.Equal(2, (int)BurstStrategy.ManualWindow); }); suite.Run("Pressure releases regular Eagle before Harmonic and filler without changing default", () => { var s = Snap(Statuses.March, Statuses.RoleEagle); Skill[] ready = [Skill.HarmonicArrow, Skill.PowerfulShot, Skill.EagleEyeShot]; Is(Skill.HarmonicArrow, Decide(s, new(), ready)); Is(Skill.EagleEyeShot, Decide(s, Config(), ready)); }); suite.Run("Pressure uses silence before filler and still avoids overwriting Repertoire", () => { Is(Skill.PowerfulShot, Decide(Snap(), new(), Skill.PowerfulShot, Skill.SilentNocturne)); Is(Skill.SilentNocturne, Decide(Snap(), Config(), Skill.PowerfulShot, Skill.SilentNocturne)); Is(Skill.HarmonicArrow, Decide(Snap(Statuses.Repertoire), Config(), Skill.SilentNocturne, Skill.HarmonicArrow)); }); suite.Run("Pressure consumes ready procs before multiple Harmonic charges and normal Eagle", () => { foreach (var (status, skill) in new[] { (Statuses.Repertoire, Skill.PitchPerfect), (Statuses.BlastReady, Skill.BlastArrow) }) { var s = Snap(Statuses.March, status, Statuses.RoleEagle) with { HarmonicCharges = 4 }; Is(skill, Decide(s, Config(), skill, Skill.HarmonicArrow, Skill.EagleEyeShot)); Is(Skill.HarmonicArrow, Decide(s, new(), skill, Skill.HarmonicArrow, Skill.EagleEyeShot)); } }); suite.Run("Pressure preserves opener buffs Encore and Eagle finisher precedence", () => { Is(Skill.ApexArrow, Decide(Snap(Statuses.RoleEagle), Config(), Skill.ApexArrow, Skill.EagleEyeShot, Skill.HarmonicArrow)); Is(Skill.Bravery, Decide(Snap(Statuses.RoleBravery, Statuses.RoleEagle), Config(), Skill.Bravery, Skill.EagleEyeShot)); Is(Skill.FinalFantasia, Decide(Snap(Statuses.RoleEagle) with { LimitFull = true }, Config(), Skill.FinalFantasia, Skill.EagleEyeShot)); Is(Skill.EncoreOfLight, Decide(Snap(Statuses.EncoreReady, Statuses.RoleEagle), Config(), Skill.EncoreOfLight, Skill.EagleEyeShot)); Is(Skill.EagleEyeShot, Decide(Snap(Statuses.EncoreReady, Statuses.RoleEagle) with { Enemies = [Enemy(hp: 9000)] }, Config(), Skill.EncoreOfLight, Skill.EagleEyeShot)); }); suite.Run("Pressure respects strict Eagle reservation and unavailable ability fallback", () => { var s = Snap(Statuses.RoleEagle); var c = Config(); c.EagleStrategy = EagleStrategy.FinisherOnly; Is(Skill.PowerfulShot, Decide(s, c, Skill.PowerfulShot, Skill.EagleEyeShot)); c = Config(); c.DisabledSkills = [Skill.EagleEyeShot, Skill.SilentNocturne]; Is(Skill.PowerfulShot, Decide(s, c, Skill.PowerfulShot, Skill.EagleEyeShot, Skill.SilentNocturne)); var f = new Fake(Skill.EagleEyeShot, Skill.PowerfulShot); f.Charges[Skill.EagleEyeShot] = 0; Is(Skill.PowerfulShot, new Rotation().Decide(s, Config(), f)); }); suite.Run("Pressure never holds charges or buffs for alignment", () => { var s = Snap() with { HarmonicCharges = 1, HarmonicReadySeconds = 0 }; foreach (var skill in new[] { Skill.HarmonicArrow, Skill.Bravery, Skill.Dervish, Skill.FinalFantasia }) Suite.True(Strategy.HoldReason(skill, s, Config()) == null); Is(Skill.HarmonicArrow, Decide(s, Config(), Skill.HarmonicArrow, Skill.PowerfulShot)); }); suite.Run("Pressure waives extra instant damage weave margin but excludes casts and backstep", () => { var w = new WeaveTiming(); for (var i = 0; i < 3; i++) { w.Submitted(i * 2, false); w.Observe(i * 2 + 1.2, true, 0, false, false); } foreach (var adaptive in new[] { true, false }) foreach (var skill in new[] { Skill.HarmonicArrow, Skill.PitchPerfect, Skill.BlastArrow, Skill.ApexArrow, Skill.EagleEyeShot, Skill.SilentNocturne, Skill.Bravery, Skill.Dervish, Skill.FinalFantasia }) { Suite.True(!w.Allows(.1f, skill, adaptive)); Suite.True(w.Allows(.1f, skill, adaptive, BurstStrategy.Pressure)); Suite.True(!w.Allows(.1f, skill, adaptive, BurstStrategy.Pressure, casting: true)); } Suite.True(!w.Allows(.1f, Skill.RepellingShot, true, BurstStrategy.Pressure)); Suite.True(!w.Allows(.1f, Skill.PowerfulShot, true, BurstStrategy.Pressure)); }); suite.Run("Pressure retains survival Guard manual pause and attack switches", () => { var s = Snap(Statuses.RoleEagle); Is(Skill.Guard, Decide(s with { Player = Self(Statuses.RoleEagle) with { Hp = 8000 } }, Config(), Skill.Guard, Skill.EagleEyeShot)); Is(Skill.Recuperate, Decide(s with { Player = Self(Statuses.RoleEagle) with { Hp = 40000 } }, Config(), Skill.Recuperate, Skill.EagleEyeShot)); Suite.True(Decide(s with { ManualControl = true }, Config(), Skill.EagleEyeShot) == null); Suite.True(Decide(s with { Player = Self(Statuses.RoleEagle, Statuses.Guard) }, Config(), Skill.EagleEyeShot) == null); var c = Config(); c.AutoAttack = false; Suite.True(Decide(s, c, Skill.EagleEyeShot, Skill.SilentNocturne) == null); }); suite.Run("Pressure keeps player-first targeting and Eagle off objectives", () => { var objective = Enemy(11, 1000) with { IsObjective = true }; var s = Snap(Statuses.RoleEagle) with { Enemies = [objective, Enemy()] }; Suite.Equal(10ul, Decide(s, Config(), Skill.EagleEyeShot, Skill.HarmonicArrow)!.TargetId); Is(Skill.HarmonicArrow, Decide(s with { Enemies = [objective] }, Config(), Skill.EagleEyeShot, Skill.HarmonicArrow)); }); suite.Run("Pressure does not move backstep ahead of filler or override manual backstep", () => { var s = Snap() with { Enemies = [Enemy() with { Distance = 8 }] }; Is(Skill.PowerfulShot, Decide(s, Config(), Skill.RepellingShot, Skill.PowerfulShot)); var c = Config(); c.ManualRepelling = true; Suite.True(Decide(s, c, Skill.RepellingShot) == null); }); suite.Run("Pressure burst falls back to filler after spending cooldowns and consuming proc", () => { var s = Snap(Statuses.March, Statuses.RoleEagle); Is(Skill.EagleEyeShot, Decide(s, Config(), Skill.EagleEyeShot, Skill.SilentNocturne, Skill.HarmonicArrow, Skill.PowerfulShot)); Is(Skill.SilentNocturne, Decide(s, Config(), Skill.SilentNocturne, Skill.HarmonicArrow, Skill.PowerfulShot)); Is(Skill.PitchPerfect, Decide(s with { Player = Self(Statuses.March, Statuses.RoleEagle, Statuses.Repertoire) }, Config(), Skill.PitchPerfect, Skill.HarmonicArrow)); Is(Skill.HarmonicArrow, Decide(s, Config(), Skill.HarmonicArrow, Skill.PowerfulShot)); Is(Skill.PowerfulShot, Decide(s, Config(), Skill.PowerfulShot)); }); } }