# Integration Example: Wiring Combat into Your Maze This document shows how to integrate the combat system into `MazeSceneBuilder` and `MazeGenerator`. ## Step 1: Load Resources in MazeSceneBuilder ```csharp public class MazeSceneBuilder : MonoBehaviour { [SerializeField] private int agentCount = 5; [SerializeField] private float initialAgentDelay = 1f; [SerializeField] private float decisionInterval = 0.5f; [SerializeField] private float exploreChance = 0.7f; [SerializeField] private float retreatThreshold = 1.5f; // NEW: Combat system setup [SerializeField] private Monster[] monsterPool; [SerializeField] private Weapon[] startingWeapons; [SerializeField] private Armor[] startingArmor; [SerializeField] private float encounterChance = 0.7f; [SerializeField] private int minMonstersPerRoom = 1; [SerializeField] private int maxMonstersPerRoom = 3; private void Start() { // ... existing code ... // NEW: Load resources if not assigned in inspector if (monsterPool == null || monsterPool.Length == 0) monsterPool = Resources.LoadAll("Monsters/"); if (startingWeapons == null || startingWeapons.Length == 0) startingWeapons = Resources.LoadAll("Items/Weapons/"); if (startingArmor == null || startingArmor.Length == 0) startingArmor = Resources.LoadAll("Items/Armor/"); // ... generate maze, then spawn agents with equipment ... GenerateAgents(); } private void GenerateAgents() { for (int i = 0; i < agentCount; i++) { var startRoom = graph.StartRooms[i % graph.StartRooms.Count]; // NEW: Create character sheet with starting equipment var stats = new CharacterStats(); var sheet = new CharacterSheet(stats); // Randomly assign starting equipment if (startingWeapons.Length > 0) sheet.EquipWeapon(startingWeapons[Random.Range(0, startingWeapons.Length)]); if (startingArmor.Length > 0) sheet.EquipArmor(startingArmor[Random.Range(0, startingArmor.Length)]); // Create agent with character sheet var agent = new MazeAgent($"Agent_{i}", startRoom, sheet); // ... rest of agent setup ... var controller = agentGOs[i].AddComponent(); controller.Initialize(agent, generator, agentColor); var brain = agentGOs[i].AddComponent(); brain.Initialize( controller, generator, initialAgentDelay + i * 0.2f, decisionInterval, exploreChance, retreatThreshold, () => IsLevelEnded() ); } } } ``` ## Step 2: Spawn Encounters in MazeGenerator In `MazeGenerator.BuildRoom()` or `GenerateConnectedRoom()`, add: ```csharp private void BuildRoom(...) { // ... existing room creation code ... // NEW: Spawn encounter if configured if (ShouldSpawnEncounter()) { var encounter = new MonsterEncounter(); encounter.SpawnMonsters( monsterPool, minMonstersPerRoom, maxMonstersPerRoom ); room.Encounter = encounter; } return room; } private bool ShouldSpawnEncounter() { if (monsterPool == null || monsterPool.Length == 0) return false; // Don't spawn in start/exit rooms // (You can customize this logic) return Random.value < encounterChance; } ``` Add config fields to `MazeGenerator`: ```csharp [SerializeField] private Monster[] monsterPool; [SerializeField] private float encounterChance = 0.7f; [SerializeField] private int minMonstersPerRoom = 1; [SerializeField] private int maxMonstersPerRoom = 3; ``` ## Step 3: Trigger Combat in MazeAgentController When an agent enters a room, check for combat: ```csharp public class MazeAgentController : MonoBehaviour { private void Update() { // ... existing movement code ... // NEW: Check for combat when entering a room if (ReachedCurrentRoom()) { if (_agent.CurrentRoom.Encounter != null && _agent.CurrentRoom.Encounter.HasLivingMonsters) { StartCombat(); } } } private void StartCombat() { var outcome = CombatResolver.ResolveCombat(_agent, _agent.CurrentRoom.Encounter); switch (outcome) { case CombatResolver.CombatOutcome.AgentVictory: Debug.Log($"{_agent.Name} won the fight!"); // Award loot, heal, etc. break; case CombatResolver.CombatOutcome.AgentDefeated: Debug.Log($"{_agent.Name} was defeated!"); // Agent is now dead (IsFinished=true or manually marked) // They stop moving automatically break; case CombatResolver.CombatOutcome.Fleeing: Debug.Log($"{_agent.Name} fled the encounter!"); // Force agent back through previous exit (optional) break; } // TODO: Update UI, audio, etc. } private bool ReachedCurrentRoom() { // Check if agent's position matches their current room's position float distance = Vector2.Distance(transform.position, _agent.CurrentRoom.Position); return distance < 0.5f; } } ``` ## Step 4: Wire Up the Peek Mechanic (Already Active) The `AutonomousAgentBrain` now automatically: 1. Evaluates threat in adjacent rooms 2. Prefers safer exits when possible 3. Only enters dangerous rooms if it's the only option To adjust agent personality: ```csharp // Brave agents with low retreat threshold brain.Initialize(..., retreatThreshold: 0.5f, ...); // Cautious agents with high threshold brain.Initialize(..., retreatThreshold: 3.0f, ...); ``` ## Step 5: Test 1. Open the scene in Unity 2. Create some Monster, Weapon, and Armor assets via Create menu 3. Assign them to the inspector fields (or save to Resources/ paths) 4. Play 5. Watch agents avoid dangerous rooms and engage in combat ## Advanced: Per-Agent Difficulty Scale monster stats by depth: ```csharp private void ScaleMonsterByDepth(MonsterEncounter.MonsterInstance monster, Room room) { float depthScale = 1f + (room.DepthFromStart * 0.1f); monster.CharacterSheet.ApplyTemporaryBonus("depth_scale", monster.CharacterSheet.Stats.Attack * depthScale, "attack"); } ``` ## Advanced: Dynamic Loot After combat victory: ```csharp private void AwardLoot(MazeAgent victor, MonsterEncounter encounter) { foreach (var monster in encounter.Monsters) { if (monster.IsDefeated) { var loot = monster.Template.GetRandomLoot(); if (loot != null) victor.CharacterSheet.AddToInventory(loot); } } } ``` Then implement inventory UI to let agents view/manage items. --- See `Combat/README.md` for detailed architecture, and `CombatResolver.cs` for where to expand combat logic.