DeclareFightDecision.cs 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. namespace MazeGen
  2. {
  3. /// <summary>
  4. /// Declares a fight with monsters in the current room if the threat level is acceptable.
  5. /// Uses a health-aware retreat threshold: lower health = more defensive.
  6. /// </summary>
  7. public class DeclareFightDecision : AgentDecision
  8. {
  9. private CombatDirector _director;
  10. private float _retreatThreshold;
  11. public override string DecisionName => "Declare Fight";
  12. public DeclareFightDecision(CombatDirector director, float retreatThreshold)
  13. {
  14. _director = director;
  15. _retreatThreshold = retreatThreshold;
  16. }
  17. public override bool CanExecute(MazeAgent agent)
  18. {
  19. if (agent == null || _director == null) return false;
  20. if (agent.IsEngaged) return false;
  21. Room room = agent.CurrentRoom;
  22. if (room == null || room.Encounter == null || !room.Encounter.HasLivingMonsters)
  23. return false;
  24. // Already failed here before
  25. if (agent.HasFledFrom(room.Id))
  26. return false;
  27. // Would we accept this threat level?
  28. float threat = room.Encounter.GetPerceivedChallengeRating(agent.CharacterSheet);
  29. float effectiveThreshold = GetEffectiveReteatThreshold(agent);
  30. return threat <= effectiveThreshold;
  31. }
  32. public override bool Execute(MazeAgent agent)
  33. {
  34. Room room = agent.CurrentRoom;
  35. float threat = room.Encounter.GetPerceivedChallengeRating(agent.CharacterSheet);
  36. int hostiles = room.Encounter.AliveMonsterCount;
  37. _director.DeclareFight(room, agent, $"sized up {hostiles} hostile(s) at threat {threat:0.00} and attacked");
  38. return true;
  39. }
  40. public override void Think(MazeAgent agent)
  41. {
  42. Room room = agent.CurrentRoom;
  43. float threat = room.Encounter.GetPerceivedChallengeRating(agent.CharacterSheet);
  44. float effectiveThreshold = GetEffectiveReteatThreshold(agent);
  45. int hostiles = room.Encounter.AliveMonsterCount;
  46. agent.Thoughts.Add(ThoughtKind.Fight,
  47. $"Peeked: {hostiles} hostile(s), threat {threat:0.00} vs my limit {effectiveThreshold:0.00} - engaging. Fight starts in {_director.JoinWindowSeconds:0.0}s, hopefully someone joins.");
  48. }
  49. private float GetEffectiveReteatThreshold(MazeAgent agent)
  50. {
  51. CharacterSheet sheet = agent.CharacterSheet;
  52. float maxHealth = sheet.Stats.MaxHealth;
  53. if (maxHealth <= 0) return _retreatThreshold;
  54. float healthPercent = sheet.Stats.CurrentHealth / maxHealth;
  55. if (healthPercent < 0.3f)
  56. return _retreatThreshold * 0.5f;
  57. else if (healthPercent < 0.5f)
  58. {
  59. float t = (healthPercent - 0.3f) / 0.2f;
  60. return UnityEngine.Mathf.Lerp(_retreatThreshold * 0.5f, _retreatThreshold, t);
  61. }
  62. return _retreatThreshold;
  63. }
  64. }
  65. }