using UnityEngine;
using System.Collections.Generic;
using System.Linq;
///
/// Tracks active fights between runners and monsters
/// Provides fight data for UI display and camera zoom operations
///
public class FightTracker : MonoBehaviour
{
[SerializeField] private float fightDisplayDuration = 3f; // How long to display fights after they end
// Internal fight tracking structure
private class ActiveFight
{
public AIAgent runner;
public Monster monster;
public MazeRoom room;
public float startTime;
public float endTime = float.MaxValue; // While fighting, this is MaxValue
public bool isActive => endTime == float.MaxValue;
}
private List activeFights = new();
private Dictionary<(AIAgent, Monster), ActiveFight> fightLookup = new();
private static FightTracker instance;
public static FightTracker Instance
{
get
{
if (instance == null)
{
var go = new GameObject("FightTracker");
instance = go.AddComponent();
}
return instance;
}
}
///
/// Called when a runner starts fighting a monster
///
public void StartFight(AIAgent runner, Monster monster)
{
if (runner == null || monster == null) return;
if (runner.IsDead || monster.IsDead) return;
var key = (runner, monster);
if (fightLookup.ContainsKey(key)) return; // Already tracking this fight
var fight = new ActiveFight
{
runner = runner,
monster = monster,
room = monster.HomeRoom,
startTime = Time.time
};
activeFights.Add(fight);
fightLookup[key] = fight;
}
///
/// Called when a fight ends (runner or monster dies, or they separate)
///
public void EndFight(AIAgent runner, Monster monster)
{
if (runner == null || monster == null) return;
var key = (runner, monster);
if (fightLookup.TryGetValue(key, out var fight))
{
fight.endTime = Time.time;
fightLookup.Remove(key);
}
}
///
/// Gets all fights that should currently be displayed (active + recent)
///
public List GetDisplayFights()
{
var displayFights = new List();
// Clean up old completed fights and null entries
activeFights.RemoveAll(f =>
{
// Remove if either fighter was destroyed
if (f.runner == null || f.monster == null)
return true;
float timeSinceEnd = Time.time - f.endTime;
return !f.isActive && timeSinceEnd > fightDisplayDuration;
});
// Convert to display format and sort
foreach (var fight in activeFights)
{
// Skip if either fighter is null (shouldn't happen due to RemoveAll, but safe)
if (fight.runner == null || fight.monster == null)
continue;
displayFights.Add(new FightData
{
runnerName = fight.runner.AgentName,
runnerId = fight.runner.AgentId,
monsterType = $"Monster_{fight.monster.GetHashCode()}",
room = fight.room,
isActive = fight.isActive,
timeSinceEnd = fight.isActive ? 0f : Time.time - fight.endTime,
runner = fight.runner,
monster = fight.monster
});
}
// Sort by number of participants in same room (descending), then by active status
displayFights = displayFights
.OrderByDescending(f => CountFightsInRoom(f.room))
.ThenByDescending(f => f.isActive)
.ToList();
return displayFights;
}
///
/// Count how many fights are happening in a specific room
///
private int CountFightsInRoom(MazeRoom room)
{
return activeFights.Count(f => f.room.Id == room.Id);
}
///
/// Gets total number of fighters in a room (runners + monsters)
///
public int GetFighterCountInRoom(MazeRoom room)
{
var fightersInRoom = activeFights.Where(f => f.room.Id == room.Id).ToList();
var uniqueRunners = new HashSet(fightersInRoom.Select(f => f.runner));
var uniqueMonsters = new HashSet(fightersInRoom.Select(f => f.monster));
return uniqueRunners.Count + uniqueMonsters.Count;
}
void Awake()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else if (instance != this)
{
Destroy(gameObject);
}
}
void Update()
{
// Periodically clean up dead fighters
activeFights.RemoveAll(f => f.runner == null || f.runner.IsDead || f.monster == null || f.monster.IsDead);
}
}
///
/// Display-friendly fight data
///
public struct FightData
{
public string runnerName;
public int runnerId;
public string monsterType;
public MazeRoom room;
public bool isActive;
public float timeSinceEnd;
public AIAgent runner;
public Monster monster;
public string GetDisplayText()
{
return $"{runnerName} vs {monsterType}";
}
public string GetRoomInfo()
{
return $"Room {room.Id}";
}
}