diff --git a/.claude/skills/bulbapedia-tests/SKILL.md b/.claude/skills/bulbapedia-tests/SKILL.md index 57d34db..4c5aa79 100644 --- a/.claude/skills/bulbapedia-tests/SKILL.md +++ b/.claude/skills/bulbapedia-tests/SKILL.md @@ -107,6 +107,12 @@ Follow the existing conventions — `Scripts/Moves/DrainTests.cs` and division, overflow guards). - Cover the negative cases the description implies (non-contact move → no trigger, holding an item → no boost, attacker already fainted, null `BattleData`, ...). +- **Write the test even when the behavior is not implemented at all.** A described behavior the + script simply lacks (a missing check, a missing effect, a missing interface) still gets a test + encoding the correct Gen VII behavior — it will fail and be marked `[TestFailing]` in step 5, + which is the point: the gap stays tracked in the suite instead of in a report nobody rereads. + "Not implemented" is never a reason to skip writing the test, and reporting a known deviation + as a prose note instead of a `[TestFailing]` test is not acceptable. - `LibraryHelpers.LoadLibrary()` is available when a test genuinely needs the full Gen7 library (e.g. looking up real move data); prefer pure mocks otherwise. diff --git a/PkmnLib.Dynamic/AI/AIHelpers.cs b/PkmnLib.Dynamic/AI/AIHelpers.cs index 2d76774..147b2dd 100644 --- a/PkmnLib.Dynamic/AI/AIHelpers.cs +++ b/PkmnLib.Dynamic/AI/AIHelpers.cs @@ -40,6 +40,9 @@ public static class AIHelpers /// public uint Damage => 0; + /// + public bool HasExecuted => false; + /// public TypeIdentifier? Type { get; init; } diff --git a/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs b/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs index a3b1c83..0a8be67 100644 --- a/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs +++ b/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs @@ -142,6 +142,7 @@ public static class MoveTurnExecutor if (isInvulnerable) { battle.EventHook.Invoke(new MoveInvulnerableEvent(executingMove, target)); + executingMove.RunScriptHook(x => x.OnAfterHits(executingMove, target)); return; } @@ -311,6 +312,7 @@ public static class MoveTurnExecutor } } } + hitData.HasExecuted = true; } if (numberOfHits == 0) diff --git a/PkmnLib.Dynamic/Models/ExecutingMove.cs b/PkmnLib.Dynamic/Models/ExecutingMove.cs index dd71c42..2a632e5 100644 --- a/PkmnLib.Dynamic/Models/ExecutingMove.cs +++ b/PkmnLib.Dynamic/Models/ExecutingMove.cs @@ -32,6 +32,11 @@ public interface IHitData /// uint Damage { get; } + /// + /// Gets set to true after the hit has fully executed, and has not been interrupted by anything. + /// + bool HasExecuted { get; } + /// /// The type of the hit. Null if the move is typeless. /// @@ -78,6 +83,9 @@ public record HitData : IHitData /// public uint Damage { get; internal set; } + /// + public bool HasExecuted { get; internal set; } + /// public TypeIdentifier? Type { get; internal set; } diff --git a/PkmnLib.Dynamic/ScriptHandling/Script.cs b/PkmnLib.Dynamic/ScriptHandling/Script.cs index 2fa8cf2..9b82830 100644 --- a/PkmnLib.Dynamic/ScriptHandling/Script.cs +++ b/PkmnLib.Dynamic/ScriptHandling/Script.cs @@ -14,6 +14,13 @@ public abstract class Script : IDeepCloneable, IScriptOnRemove { internal event Action