This document shows how to integrate the combat system into MazeSceneBuilder and MazeGenerator.
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<Monster>("Monsters/");
if (startingWeapons == null || startingWeapons.Length == 0)
startingWeapons = Resources.LoadAll<Weapon>("Items/Weapons/");
if (startingArmor == null || startingArmor.Length == 0)
startingArmor = Resources.LoadAll<Armor>("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<MazeAgentController>();
controller.Initialize(agent, generator, agentColor);
var brain = agentGOs[i].AddComponent<AutonomousAgentBrain>();
brain.Initialize(
controller,
generator,
initialAgentDelay + i * 0.2f,
decisionInterval,
exploreChance,
retreatThreshold,
() => IsLevelEnded()
);
}
}
}
In MazeGenerator.BuildRoom() or GenerateConnectedRoom(), add:
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:
[SerializeField] private Monster[] monsterPool;
[SerializeField] private float encounterChance = 0.7f;
[SerializeField] private int minMonstersPerRoom = 1;
[SerializeField] private int maxMonstersPerRoom = 3;
When an agent enters a room, check for combat:
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;
}
}
The AutonomousAgentBrain now automatically:
To adjust agent personality:
// Brave agents with low retreat threshold
brain.Initialize(..., retreatThreshold: 0.5f, ...);
// Cautious agents with high threshold
brain.Initialize(..., retreatThreshold: 3.0f, ...);
Scale monster stats by depth:
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");
}
After combat victory:
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.