using UnityEngine;
using UnityEngine.UI;
using TMPro;
///
/// Programmatically builds the complete in-game HUD inside the InGame canvas (Client.unity).
///
/// Call BuildNow() explicitly from GameManager.OnSceneLoaded BEFORE BindClientScene(),
/// so that GameManager_UI can find the newly created elements by name.
///
/// Named GameObjects created as direct children of InGame canvas (required by Transform.Find):
/// • ActionButton — Button + TMP child; shown/hidden by GameManager_Tasks.UpdateProximity()
/// • SabotagePanel — warning banner at top (contains "SabotageTimer" TMP_Text)
/// • MeetingPanel — voting/meeting overlay (populated by GameManager_UI.ShowMeetingPanel)
/// • GameEndPanel — end-of-game overlay (contains "GameEndText" TMP_Text)
///
/// Named TMP_Text descendants (found by GameManager_UI.FindTMP — any depth):
/// • KillCooldown — shown to impostors during kill cooldown
/// • TaskList — crewmate task names
/// • TaskProgress — global task completion "X/Y tasks"
/// • SabotageTimer — countdown inside SabotagePanel
/// • GameEndText — win/lose result text inside GameEndPanel
/// • (Role already exists in the scene)
///
/// Additional elements managed by this script:
/// • RecenterBtn — calls MapCameraController.Instance.Recenter()
///
public class InGameHUDBuilder : MonoBehaviour
{
// ── Color palette ─────────────────────────────────────────────────────────
private static readonly Color C_BG = new Color(0.05f, 0.06f, 0.12f, 0.80f);
private static readonly Color C_BAR_BG = new Color(0.03f, 0.04f, 0.08f, 0.90f);
private static readonly Color C_ACCENT = new Color(0.20f, 0.60f, 1.00f, 1.00f);
private static readonly Color C_GREEN = new Color(0.18f, 0.75f, 0.30f, 1.00f);
private static readonly Color C_RED = new Color(0.76f, 0.19f, 0.19f, 1.00f);
private static readonly Color C_ORANGE = new Color(0.95f, 0.55f, 0.10f, 1.00f);
private bool _built;
// ── Entry points ──────────────────────────────────────────────────────────
/// Called from GameManager.OnSceneLoaded before BindClientScene.
public void BuildNow()
{
if (_built) return;
_built = true;
Build();
}
void Start()
{
if (!_built) Build(); // safety fallback
}
// ── Build ─────────────────────────────────────────────────────────────────
void Build()
{
var rt = GetComponent();
if (rt == null) return;
// ── Top bar: role is already in scene, add kill-cooldown ─────────────
BuildTopBar(rt);
// ── Right task panel ──────────────────────────────────────────────────
BuildTaskPanel(rt);
// ── Task progress (above bottom bar) ─────────────────────────────────
BuildTaskProgress(rt);
// ── Bottom bar: action button + recenter ──────────────────────────────
BuildBottomBar(rt);
// ── Action button (DIRECT child — Transform.Find requirement) ─────────
BuildActionButton(rt);
// ── Sabotage panel (DIRECT child) ─────────────────────────────────────
BuildSabotagePanel(rt);
// ── Meeting panel (DIRECT child) ──────────────────────────────────────
BuildMeetingPanel(rt);
// ── Game-end panel (DIRECT child) ─────────────────────────────────────
BuildGameEndPanel(rt);
}
// ── Section builders ──────────────────────────────────────────────────────
void BuildTopBar(RectTransform parent)
{
// Thin semi-transparent header at very top
var bar = AddChild("_TopBar", parent);
Anchor(bar, new Vector2(0f, 1f), new Vector2(1f, 1f));
bar.sizeDelta = new Vector2(0f, 90f);
bar.anchoredPosition = new Vector2(0f, 0f);
bar.pivot = new Vector2(0.5f, 1f);
AddImage(bar.gameObject, C_BAR_BG);
// Kill cooldown (right side) — starts hidden
var cd = AddChild("KillCooldown", bar);
Anchor(cd, new Vector2(0.5f, 0f), new Vector2(1f, 1f));
cd.offsetMin = new Vector2(0f, 6f);
cd.offsetMax = new Vector2(-12f, -6f);
var cdTmp = cd.gameObject.AddComponent();
cdTmp.text = "";
cdTmp.fontSize = 32;
cdTmp.color = C_ORANGE;
cdTmp.fontStyle = FontStyles.Bold;
cdTmp.alignment = TextAlignmentOptions.MidlineRight;
cd.gameObject.SetActive(false);
}
void BuildTaskPanel(RectTransform parent)
{
// Right-side floating panel (always visible during game)
var panel = AddChild("_TaskPanel", parent);
Anchor(panel, new Vector2(1f, 0.35f), new Vector2(1f, 0.88f));
panel.pivot = new Vector2(1f, 0.5f);
panel.sizeDelta = new Vector2(280f, 0f);
panel.anchoredPosition = Vector2.zero;
AddImage(panel.gameObject, C_BG);
// "MY TASKS" header
var hdr = AddChild("_Header", panel);
Anchor(hdr, new Vector2(0f, 1f), new Vector2(1f, 1f));
hdr.pivot = new Vector2(0.5f, 1f);
hdr.sizeDelta = new Vector2(0f, 44f);
hdr.anchoredPosition = Vector2.zero;
AddImage(hdr.gameObject, C_ACCENT * new Color(1, 1, 1, 0.6f));
var hdrTmp = AddTextChild(hdr, "_HeaderTxt", "MY TASKS", 26, FontStyles.Bold, TextAlignmentOptions.Center);
hdrTmp.color = Color.white;
// Task list body
var body = AddChild("TaskList", panel);
Anchor(body, new Vector2(0f, 0f), new Vector2(1f, 1f));
body.offsetMin = new Vector2(8f, 8f);
body.offsetMax = new Vector2(-8f, -48f);
var taskTmp = body.gameObject.AddComponent();
taskTmp.text = "";
taskTmp.fontSize = 22;
taskTmp.color = Color.white;
taskTmp.alignment = TextAlignmentOptions.TopLeft;
}
void BuildTaskProgress(RectTransform parent)
{
var prog = AddChild("TaskProgress", parent);
Anchor(prog, new Vector2(0f, 0f), new Vector2(1f, 0f));
prog.pivot = new Vector2(0.5f, 0f);
prog.sizeDelta = new Vector2(-20f, 40f);
prog.anchoredPosition = new Vector2(0f, 120f); // above bottom bar
var tmp = prog.gameObject.AddComponent();
tmp.text = "";
tmp.fontSize = 28;
tmp.color = Color.white;
tmp.fontStyle = FontStyles.Bold;
tmp.alignment = TextAlignmentOptions.Center;
}
void BuildBottomBar(RectTransform parent)
{
var bar = AddChild("_BottomBar", parent);
Anchor(bar, new Vector2(0f, 0f), new Vector2(1f, 0f));
bar.pivot = new Vector2(0.5f, 0f);
bar.sizeDelta = new Vector2(0f, 110f);
bar.anchoredPosition = Vector2.zero;
AddImage(bar.gameObject, C_BAR_BG);
// Recenter button (bottom-right of bar)
var recBtn = AddChild("_RecenterBtn", bar);
Anchor(recBtn, new Vector2(0.82f, 0.08f), new Vector2(0.98f, 0.92f));
var recBg = AddImage(recBtn.gameObject, C_ACCENT);
var recButton = recBtn.gameObject.AddComponent