| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192 |
- namespace MazeGen
- {
- /// <summary>
- /// When the threat is too high to fight, tries to sneak out of the room.
- /// If the sneak fails, declares a forced fight instead.
- /// </summary>
- public class SneakAwayDecision : AgentDecision
- {
- private CombatDirector _director;
- private float _retreatThreshold;
- public override string DecisionName => "Sneak Away";
- public SneakAwayDecision(CombatDirector director, float retreatThreshold)
- {
- _director = director;
- _retreatThreshold = retreatThreshold;
- }
- public override bool CanExecute(MazeAgent agent)
- {
- if (agent == null || _director == null) return false;
- if (agent.IsEngaged) return false;
- Room room = agent.CurrentRoom;
- if (room == null || room.Encounter == null || !room.Encounter.HasLivingMonsters)
- return false;
- // Already failed here before
- if (agent.HasFledFrom(room.Id))
- return false;
- // Would we reject this threat level?
- float threat = room.Encounter.GetPerceivedChallengeRating(agent.CharacterSheet);
- float effectiveThreshold = GetEffectiveReteatThreshold(agent);
- return threat > effectiveThreshold;
- }
- public override bool Execute(MazeAgent agent)
- {
- // Try to sneak
- if (_director.TrySneakOut(agent, out float odds))
- {
- // Successfully sneaked away
- return false; // Return false so MoveOn can proceed this same tick
- }
- else
- {
- // Sneak failed - now forced to fight
- Room room = agent.CurrentRoom;
- int hostiles = room.Encounter.AliveMonsterCount;
- _director.DeclareFight(room, agent, $"was caught trying to sneak out past {hostiles} hostile(s)");
- return true; // Consumed the turn
- }
- }
- public override void Think(MazeAgent agent)
- {
- Room room = agent.CurrentRoom;
- float threat = room.Encounter.GetPerceivedChallengeRating(agent.CharacterSheet);
- float effectiveThreshold = GetEffectiveReteatThreshold(agent);
- int hostiles = room.Encounter.AliveMonsterCount;
- agent.Thoughts.Add(ThoughtKind.Avoid,
- $"Peeked: {hostiles} hostile(s) at threat {threat:0.00}, over my limit {effectiveThreshold:0.00} - trying to slip out instead of fighting.");
- if (_director.TrySneakOut(agent, out float odds))
- agent.Thoughts.Add(ThoughtKind.Sneak, $"Slipped away unnoticed ({odds:P0} odds).");
- else
- agent.Thoughts.Add(ThoughtKind.Sneak, $"Botched the sneak ({odds:P0} odds) - they've seen me, no choice but to fight.");
- }
- private float GetEffectiveReteatThreshold(MazeAgent agent)
- {
- CharacterSheet sheet = agent.CharacterSheet;
- float maxHealth = sheet.Stats.MaxHealth;
- if (maxHealth <= 0) return _retreatThreshold;
- float healthPercent = sheet.Stats.CurrentHealth / maxHealth;
- if (healthPercent < 0.3f)
- return _retreatThreshold * 0.5f;
- else if (healthPercent < 0.5f)
- {
- float t = (healthPercent - 0.3f) / 0.2f;
- return UnityEngine.Mathf.Lerp(_retreatThreshold * 0.5f, _retreatThreshold, t);
- }
- return _retreatThreshold;
- }
- }
- }
|