using Theriapolis.Core.Rules.Combat; namespace Theriapolis.Core.Entities.Ai; /// /// "Move toward target, attack when in reach" — the baseline aggressive /// melee behavior. Used by Brigand* and Patrol templates that aren't /// scripted to flee. /// public sealed class BrigandBehavior : INpcBehavior { public void TakeTurn(Combatant self, AiContext ctx) { if (self.IsDown) return; var target = ctx.FindClosestHostile(self); if (target is null) return; var attack = self.AttackOptions[0]; // Move budget: 5 ft. = 1 tactical tile per d20 standard. int tiles = ctx.Encounter.CurrentTurn.RemainingMovementFt / 5; while (!ReachAndCover.IsInReach(self, target, attack) && tiles > 0) { var next = ReachAndCover.StepToward(self.Position, target.Position); if (next.X == self.Position.X && next.Y == self.Position.Y) break; self.Position = next; ctx.Encounter.AppendLog(CombatLogEntry.Kind.Move, $"{self.Name} moves to ({(int)next.X},{(int)next.Y})."); tiles--; } int consumedTiles = (ctx.Encounter.CurrentTurn.RemainingMovementFt / 5) - tiles; ctx.Encounter.CurrentTurn.ConsumeMovement(consumedTiles * 5); if (!ReachAndCover.IsInReach(self, target, attack)) return; Resolver.AttemptAttack(ctx.Encounter, self, target, attack); ctx.Encounter.CurrentTurn.ConsumeAction(); } }