CombatResolver.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. namespace MazeGen
  4. {
  5. /// <summary>
  6. /// Skeleton for resolving combat between an agent and monsters in a room.
  7. /// This is NOT a full implementation - you'll need to expand this with:
  8. /// - Turn order calculation
  9. /// - Action resolution (attack, defend, ability)
  10. /// - Damage calculation
  11. /// - Status effects
  12. /// - Ability cooldowns
  13. ///
  14. /// This provides just the structure and basic helper functions.
  15. /// </summary>
  16. public class CombatResolver
  17. {
  18. public enum CombatOutcome
  19. {
  20. AgentVictory,
  21. AgentDefeated,
  22. Fleeing // Agent escaped before resolution
  23. }
  24. /// <summary>
  25. /// Simulate combat between an agent and the monsters in this room.
  26. /// Returns the outcome. You'll need to expand this significantly for a real system.
  27. /// </summary>
  28. public static CombatOutcome ResolveCombat(MazeAgent agent, MonsterEncounter encounter)
  29. {
  30. if (encounter == null || !encounter.HasLivingMonsters)
  31. return CombatOutcome.AgentVictory; // No fight needed
  32. // TODO: Implement full combat loop
  33. // 1. Build turn order from Speed stats
  34. var turnOrder = BuildTurnOrder(agent, encounter);
  35. // 2. Simulate turns until victory/defeat
  36. int maxRounds = 100; // Prevent infinite loops during development
  37. int round = 0;
  38. while (round < maxRounds && agent.CharacterSheet.Stats.IsAlive && encounter.HasLivingMonsters)
  39. {
  40. round++;
  41. // Execute each turn in order
  42. foreach (var turn in turnOrder)
  43. {
  44. if (turn.IsAgent)
  45. {
  46. ExecuteAgentTurn(agent, encounter);
  47. }
  48. else
  49. {
  50. ExecuteMonsterTurn(turn.MonsterIndex, agent, encounter);
  51. }
  52. // Check win conditions each turn
  53. if (!agent.CharacterSheet.Stats.IsAlive)
  54. return CombatOutcome.AgentDefeated;
  55. if (!encounter.HasLivingMonsters)
  56. return CombatOutcome.AgentVictory;
  57. }
  58. }
  59. if (agent.CharacterSheet.Stats.IsAlive && !encounter.HasLivingMonsters)
  60. return CombatOutcome.AgentVictory;
  61. return CombatOutcome.AgentDefeated;
  62. }
  63. /// <summary>
  64. /// Determine turn order based on Speed stats.
  65. /// Higher speed = earlier in turn order.
  66. /// </summary>
  67. private static List<(bool IsAgent, int MonsterIndex)> BuildTurnOrder(MazeAgent agent, MonsterEncounter encounter)
  68. {
  69. var order = new List<(bool, int)>();
  70. // Agent's speed
  71. float agentInitiative = agent.CharacterSheet.GetEffectiveSpeed();
  72. order.Add((true, -1)); // IsAgent=true, MonsterIndex unused
  73. // Each monster's speed
  74. for (int i = 0; i < encounter.Monsters.Count; i++)
  75. {
  76. if (!encounter.Monsters[i].IsDefeated)
  77. {
  78. float monsterInitiative = encounter.Monsters[i].CharacterSheet.GetEffectiveSpeed();
  79. order.Add((false, i));
  80. }
  81. }
  82. // Sort by initiative (higher = first)
  83. // TODO: Implement proper sorting by speed
  84. // order.Sort((a, b) => ...)
  85. return order;
  86. }
  87. /// <summary>
  88. /// Execute the agent's turn. Pick a target and attack.
  89. /// This is a stub - implement your action selection here.
  90. /// </summary>
  91. private static void ExecuteAgentTurn(MazeAgent agent, MonsterEncounter encounter)
  92. {
  93. // TODO: Implement agent decision (which monster to target, what ability to use)
  94. // For now, just attack the first alive monster
  95. for (int i = 0; i < encounter.Monsters.Count; i++)
  96. {
  97. if (!encounter.Monsters[i].IsDefeated)
  98. {
  99. AttackMonster(agent, encounter, i);
  100. break;
  101. }
  102. }
  103. }
  104. /// <summary>
  105. /// Execute one monster's turn. They attack the agent.
  106. /// This is a stub - add AI/decision logic here.
  107. /// </summary>
  108. private static void ExecuteMonsterTurn(int monsterIndex, MazeAgent agent, MonsterEncounter encounter)
  109. {
  110. if (monsterIndex < 0 || monsterIndex >= encounter.Monsters.Count)
  111. return;
  112. var monster = encounter.Monsters[monsterIndex];
  113. if (monster.IsDefeated)
  114. return;
  115. // TODO: Implement monster AI (target selection, ability choice, etc.)
  116. // For now, just attack the agent
  117. AttackAgent(monster, agent);
  118. }
  119. /// <summary>
  120. /// Calculate and apply damage when agent attacks a monster.
  121. /// Stub - expand with damage types, abilities, modifiers, etc.
  122. /// </summary>
  123. private static void AttackMonster(MazeAgent agent, MonsterEncounter encounter, int targetIndex)
  124. {
  125. var target = encounter.Monsters[targetIndex];
  126. // Simple attack: agent's attack vs target's defense
  127. float baseDamage = agent.CharacterSheet.GetEffectiveAttack();
  128. float damage = target.CharacterSheet.Stats.CalculateDamageReduction(baseDamage);
  129. Debug.Log($"{agent.Name} attacks {target.Template.MonsterName} for {damage} damage");
  130. target.CharacterSheet.Stats.TakeDamage(damage);
  131. if (target.IsDefeated)
  132. {
  133. Debug.Log($"{target.Template.MonsterName} defeated!");
  134. // TODO: Award loot to agent
  135. }
  136. }
  137. /// <summary>
  138. /// Calculate and apply damage when monster attacks agent.
  139. /// Stub - expand similarly to AttackMonster.
  140. /// </summary>
  141. private static void AttackAgent(MonsterEncounter.MonsterInstance attacker, MazeAgent target)
  142. {
  143. float baseDamage = attacker.CharacterSheet.GetEffectiveAttack();
  144. float damage = target.CharacterSheet.Stats.CalculateDamageReduction(baseDamage);
  145. Debug.Log($"{attacker.Template.MonsterName} attacks {target.Name} for {damage} damage");
  146. target.CharacterSheet.Stats.TakeDamage(damage);
  147. if (!target.CharacterSheet.Stats.IsAlive)
  148. {
  149. Debug.Log($"{target.Name} defeated!");
  150. target.Die();
  151. }
  152. }
  153. /// <summary>
  154. /// Award loot from a defeated monster to the agent.
  155. /// Stub - implement inventory/pickup logic.
  156. /// </summary>
  157. private static void AwardLoot(MonsterEncounter.MonsterInstance monster, MazeAgent agent)
  158. {
  159. // TODO: Implement loot pickup
  160. // var loot = monster.Template.GetRandomLoot();
  161. // if (loot != null)
  162. // agent.CharacterSheet.AddToInventory(loot);
  163. }
  164. }
  165. }