using UnityEngine; namespace MazeGen { /// /// Right-side panel showing detailed info about the followed agent: /// - Vitals (room, HP, stats, equipment) /// - Inventory listing (equipped + unequipped items) /// - Decision narration (newest first) /// - Global combat log /// public class InfoPanelUI { private Vector2 thoughtScroll; private Vector2 combatLogScroll; private CombatDirector director; public InfoPanelUI(CombatDirector combatDirector) { director = combatDirector; } public void Draw(MazeAgent followedAgent) { float width = 400f; float x = Screen.width - width - 10f; float height = Screen.height - 20f; GUILayout.BeginArea(new Rect(x, 10f, width, height), GUI.skin.box); if (followedAgent == null) { GUILayout.Label("AGENT THOUGHTS AND INFO", GUI.skin.box); GUILayout.Label("Click an agent on the left to follow it and read what it's thinking."); } else { DrawAgentInfo(followedAgent, height, Color.white); } GUILayout.EndArea(); } private void DrawAgentInfo(MazeAgent agent, float panelHeight, Color agentColor) { CharacterSheet sheet = agent.CharacterSheet; GUI.color = agentColor; GUILayout.Label($"{agent.DisplayName.ToUpperInvariant()} - {DescribeStatus(agent)}", GUI.skin.box); GUI.color = Color.white; // Vitals GUILayout.Label($"Room {agent.CurrentRoom?.Id.ToString() ?? "?"} New rooms seen: {agent.NewRoomsVisited} Path: {agent.PathHistory.Count} hop(s)"); GUILayout.Label($"HP {sheet.Stats.CurrentHealth:0.#}/{sheet.Stats.MaxHealth:0.#} ATK {sheet.GetEffectiveAttack():0.#} DEF {sheet.GetEffectiveDefense():0.#} SPD {sheet.GetEffectiveSpeed():0.#}"); GUILayout.Label($"Weapon: {sheet.EquippedWeapon?.ItemName ?? "none"} Armor: {sheet.EquippedArmor?.ItemName ?? "none"}"); // Threat assessment for current room Room room = agent.CurrentRoom; int hostiles = room?.Encounter != null ? room.Encounter.AliveMonsterCount : 0; GUILayout.Label(hostiles > 0 ? $"This room: {hostiles} living hostile(s), threat {room.Encounter.GetPerceivedChallengeRating(sheet):0.00}" : "This room: clear"); // Inventory listing GUILayout.Space(4); DrawInventory(sheet); GUILayout.Space(4); GUILayout.Label("Thoughts (newest first):"); thoughtScroll = GUILayout.BeginScrollView(thoughtScroll, GUILayout.Height(Mathf.Max(80f, panelHeight * 0.30f))); var thoughts = agent.Thoughts.Entries; for (int i = thoughts.Count - 1; i >= 0; i--) { Thought thought = thoughts[i]; GUI.color = AgentThoughtLog.ColorFor(thought.Kind); GUILayout.Label($"[{thought.Time:0.0}s] {thought.Text}"); } GUI.color = Color.white; GUILayout.EndScrollView(); GUILayout.Space(4); GUILayout.Label("Combat log (all fights):"); combatLogScroll = GUILayout.BeginScrollView(combatLogScroll, GUILayout.Height(Mathf.Max(100f, panelHeight * 0.25f))); var log = director.CombatLog; for (int i = log.Count - 1; i >= 0; i--) GUILayout.Label(log[i]); GUILayout.EndScrollView(); } private void DrawInventory(CharacterSheet sheet) { GUILayout.Label("Inventory:", GUI.skin.box); if (sheet.Inventory.Count == 0) { GUILayout.Label("(Empty)"); return; } foreach (var item in sheet.Inventory) { string itemType = item is Consumable ? "[Consumable]" : item is Weapon ? "[Weapon]" : "[Item]"; string details = ""; if (item is Consumable cons) { if (cons.HealthBonus > 0) details = $" +{cons.HealthBonus:0.#} HP"; } else if (item is Weapon weap) { details = $" (ATK +{weap.AttackBonus:0.#})"; } else if (item is Armor armor) { details = $" (DEF +{armor.DefenseBonus:0.#})"; } GUI.color = new Color(0.7f, 0.85f, 1f); GUILayout.Label($" {itemType} {item.ItemName}{details}"); } GUI.color = Color.white; } private string DescribeStatus(MazeAgent agent) { if (agent.IsDead) return "dead"; if (agent.IsFinished) return "reached exit"; if (agent.IsEngaged) return "fighting"; return $"exploring ({agent.CharacterSheet.Stats.CurrentHealth:0}hp)"; } } }