657 lines
25 KiB
C#
657 lines
25 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using TMPro;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
/// <summary>
|
|
/// MatchResultUI — Unified VICTORY / DEFEAT end-of-match panel.
|
|
/// Works for both Cash System (team 3v3) and Practice (1v1) modes.
|
|
///
|
|
/// Stats auto-populate based on mode:
|
|
/// Cash System → Kills, Cash Deposited, Cash Stolen, Damage
|
|
/// Practice → Kills, Deaths, Assists, Damage
|
|
///
|
|
/// Hierarchy (from scene):
|
|
/// Stats (root, this script)
|
|
/// ├─ continue (Button)
|
|
/// ├─ restart (Button)
|
|
/// ├─ Title — result header "VICTORY" / "DEFEAT"
|
|
/// ├─ Title(1) — score text "24 VICTORY 20"
|
|
/// ├─ Playerstatsui
|
|
/// │ ├─ PlayerName
|
|
/// │ ├─ kills
|
|
/// │ ├─ deaths
|
|
/// │ ├─ assists
|
|
/// │ └─ damage
|
|
/// ├─ Enemystatsui
|
|
/// │ ├─ EnemyName
|
|
/// │ ├─ kills
|
|
/// │ ├─ deaths
|
|
/// │ ├─ assists
|
|
/// │ └─ damage
|
|
/// └─ Victory tab
|
|
/// </summary>
|
|
public class MatchResultUI : MonoBehaviour
|
|
{
|
|
[Header("Panel Root")]
|
|
[Tooltip("The root panel that gets shown/hidden. If null, uses this.gameObject.")]
|
|
[SerializeField] private GameObject rootPanel;
|
|
|
|
[Header("Header")]
|
|
[SerializeField] private TextMeshProUGUI resultHeaderText; // "VICTORY" / "DEFEAT"
|
|
[SerializeField] private TextMeshProUGUI scoreText; // "24 VICTORY 20" style
|
|
|
|
[Header("Team Names")]
|
|
[SerializeField] private TextMeshProUGUI playerTeamLabel; // e.g. "CHEETAH WIN!"
|
|
[SerializeField] private TextMeshProUGUI enemyTeamLabel; // e.g. "RABBIT LOSE!"
|
|
|
|
[Header("Player Stats Texts")]
|
|
[Tooltip("Player/team name text inside Playerstatsui")]
|
|
[SerializeField] private TextMeshProUGUI playerNameText;
|
|
[Tooltip("Stat row 1 — Kills (both modes)")]
|
|
[SerializeField] private TextMeshProUGUI playerKillsText;
|
|
[Tooltip("Stat row 2 — Deaths (practice) / Cash Deposited (cash system)")]
|
|
[SerializeField] private TextMeshProUGUI playerDeathsText;
|
|
[Tooltip("Stat row 3 — Assists (practice) / Cash Stolen (cash system)")]
|
|
[SerializeField] private TextMeshProUGUI playerAssistsText;
|
|
[Tooltip("Stat row 4 — Damage (both modes)")]
|
|
[SerializeField] private TextMeshProUGUI playerDamageText;
|
|
|
|
[Header("Enemy Stats Texts")]
|
|
[Tooltip("Enemy/team name text inside Enemystatsui")]
|
|
[SerializeField] private TextMeshProUGUI enemyNameText;
|
|
[SerializeField] private TextMeshProUGUI enemyKillsText;
|
|
[SerializeField] private TextMeshProUGUI enemyDeathsText;
|
|
[SerializeField] private TextMeshProUGUI enemyAssistsText;
|
|
[SerializeField] private TextMeshProUGUI enemyDamageText;
|
|
|
|
[Header("Buttons")]
|
|
[SerializeField] private Button continueButton;
|
|
[SerializeField] private Button restartButton;
|
|
|
|
[Header("Colors")]
|
|
[SerializeField] private Color victoryColor = new Color(1f, 0.84f, 0f); // Gold
|
|
[SerializeField] private Color defeatColor = new Color(0.96f, 0.26f, 0.21f); // Red
|
|
[SerializeField] private Color panelBgColor = new Color(0.08f, 0.12f, 0.18f, 0.92f);
|
|
|
|
[Header("Audio")]
|
|
[SerializeField] private AudioClip victorySFX;
|
|
[SerializeField] private AudioClip defeatSFX;
|
|
[SerializeField] private AudioClip buttonClickSFX;
|
|
[SerializeField] private float sfxVolume = 1f;
|
|
|
|
[Header("Animation")]
|
|
[SerializeField] private float revealDuration = 0.6f;
|
|
|
|
// runtime
|
|
private AudioSource _audio;
|
|
private CanvasGroup _canvasGroup;
|
|
private float _savedFixedDeltaTime;
|
|
|
|
private static MatchResultUI _instance;
|
|
public static MatchResultUI Instance => _instance;
|
|
|
|
/// <summary>
|
|
/// Ensures a MatchResultUI instance exists in the scene.
|
|
/// Finds inactive instances first, or creates a minimal one with buttons on the existing Canvas.
|
|
/// Call from CashSystemManager.Start() so end-of-match always shows a panel.
|
|
/// </summary>
|
|
public static void EnsureExists()
|
|
{
|
|
if (_instance != null) return;
|
|
|
|
// 1. Try to find an inactive instance already in the scene
|
|
MatchResultUI[] all = Resources.FindObjectsOfTypeAll<MatchResultUI>();
|
|
foreach (var m in all)
|
|
{
|
|
if (m.gameObject.scene.name == null) continue;
|
|
// Activate parents top-down first, then the object itself
|
|
List<GameObject> chain = new List<GameObject>();
|
|
Transform t = m.transform;
|
|
while (t != null)
|
|
{
|
|
if (!t.gameObject.activeSelf)
|
|
chain.Add(t.gameObject);
|
|
t = t.parent;
|
|
}
|
|
for (int i = chain.Count - 1; i >= 0; i--)
|
|
chain[i].SetActive(true);
|
|
|
|
if (_instance != null)
|
|
{
|
|
DevLog.Log("[MatchResultUI] Found existing inactive panel, activated it");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 2. Create a minimal panel on an existing Canvas
|
|
Canvas canvas = Object.FindObjectOfType<Canvas>();
|
|
if (canvas == null)
|
|
{
|
|
GameObject canvasObj = new GameObject("UICanvas");
|
|
canvas = canvasObj.AddComponent<Canvas>();
|
|
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
|
canvas.sortingOrder = 100;
|
|
canvasObj.AddComponent<UnityEngine.UI.CanvasScaler>();
|
|
canvasObj.AddComponent<UnityEngine.UI.GraphicRaycaster>();
|
|
}
|
|
|
|
GameObject panelRoot = new GameObject("MatchResultUI_Auto");
|
|
panelRoot.transform.SetParent(canvas.transform, false);
|
|
|
|
RectTransform rt = panelRoot.AddComponent<RectTransform>();
|
|
rt.anchorMin = Vector2.zero;
|
|
rt.anchorMax = Vector2.one;
|
|
rt.offsetMin = Vector2.zero;
|
|
rt.offsetMax = Vector2.zero;
|
|
|
|
// Background
|
|
Image bg = panelRoot.AddComponent<Image>();
|
|
bg.color = new Color(0.08f, 0.12f, 0.18f, 0.92f);
|
|
|
|
// Result header
|
|
GameObject headerObj = new GameObject("ResultHeader");
|
|
headerObj.transform.SetParent(panelRoot.transform, false);
|
|
RectTransform hrt = headerObj.AddComponent<RectTransform>();
|
|
hrt.anchorMin = new Vector2(0.2f, 0.7f);
|
|
hrt.anchorMax = new Vector2(0.8f, 0.9f);
|
|
hrt.offsetMin = Vector2.zero;
|
|
hrt.offsetMax = Vector2.zero;
|
|
TextMeshProUGUI headerTxt = headerObj.AddComponent<TextMeshProUGUI>();
|
|
headerTxt.text = "MATCH RESULT";
|
|
headerTxt.fontSize = 80;
|
|
headerTxt.alignment = TextAlignmentOptions.Center;
|
|
headerTxt.color = Color.white;
|
|
|
|
// Score text
|
|
GameObject scoreObj = new GameObject("ScoreText");
|
|
scoreObj.transform.SetParent(panelRoot.transform, false);
|
|
RectTransform srt = scoreObj.AddComponent<RectTransform>();
|
|
srt.anchorMin = new Vector2(0.2f, 0.55f);
|
|
srt.anchorMax = new Vector2(0.8f, 0.7f);
|
|
srt.offsetMin = Vector2.zero;
|
|
srt.offsetMax = Vector2.zero;
|
|
TextMeshProUGUI scoreTxt = scoreObj.AddComponent<TextMeshProUGUI>();
|
|
scoreTxt.text = "";
|
|
scoreTxt.fontSize = 48;
|
|
scoreTxt.alignment = TextAlignmentOptions.Center;
|
|
scoreTxt.color = Color.white;
|
|
|
|
// Continue button
|
|
Button continueBtn = CreateAutoButton(panelRoot.transform, "Continue",
|
|
new Vector2(0.25f, 0.1f), new Vector2(0.48f, 0.22f), new Color(0.2f, 0.7f, 0.3f));
|
|
|
|
// Restart button
|
|
Button restartBtn = CreateAutoButton(panelRoot.transform, "Restart",
|
|
new Vector2(0.52f, 0.1f), new Vector2(0.75f, 0.22f), new Color(0.8f, 0.4f, 0.1f));
|
|
|
|
MatchResultUI ui = panelRoot.AddComponent<MatchResultUI>();
|
|
ui.resultHeaderText = headerTxt;
|
|
ui.scoreText = scoreTxt;
|
|
ui.continueButton = continueBtn;
|
|
ui.restartButton = restartBtn;
|
|
|
|
DevLog.Log("[MatchResultUI] Auto-created minimal result panel on Canvas");
|
|
}
|
|
|
|
private static Button CreateAutoButton(Transform parent, string label,
|
|
Vector2 anchorMin, Vector2 anchorMax, Color bgColor)
|
|
{
|
|
GameObject btnObj = new GameObject(label + "Button");
|
|
btnObj.transform.SetParent(parent, false);
|
|
RectTransform brt = btnObj.AddComponent<RectTransform>();
|
|
brt.anchorMin = anchorMin;
|
|
brt.anchorMax = anchorMax;
|
|
brt.offsetMin = Vector2.zero;
|
|
brt.offsetMax = Vector2.zero;
|
|
Image btnBg = btnObj.AddComponent<Image>();
|
|
btnBg.color = bgColor;
|
|
Button btn = btnObj.AddComponent<Button>();
|
|
|
|
GameObject btnLabelObj = new GameObject("Label");
|
|
btnLabelObj.transform.SetParent(btnObj.transform, false);
|
|
RectTransform lrt = btnLabelObj.AddComponent<RectTransform>();
|
|
lrt.anchorMin = Vector2.zero;
|
|
lrt.anchorMax = Vector2.one;
|
|
lrt.offsetMin = Vector2.zero;
|
|
lrt.offsetMax = Vector2.zero;
|
|
TextMeshProUGUI txt = btnLabelObj.AddComponent<TextMeshProUGUI>();
|
|
txt.text = label;
|
|
txt.fontSize = 42;
|
|
txt.alignment = TextAlignmentOptions.Center;
|
|
txt.color = Color.white;
|
|
|
|
return btn;
|
|
}
|
|
|
|
// ─── Lifecycle ───────────────────────────────────────────
|
|
|
|
private void Awake()
|
|
{
|
|
_instance = this;
|
|
if (rootPanel == null) rootPanel = gameObject;
|
|
|
|
_audio = GetComponent<AudioSource>();
|
|
if (_audio == null) _audio = gameObject.AddComponent<AudioSource>();
|
|
_audio.playOnAwake = false;
|
|
_audio.spatialBlend = 0f;
|
|
|
|
_canvasGroup = rootPanel.GetComponent<CanvasGroup>();
|
|
if (_canvasGroup == null) _canvasGroup = rootPanel.AddComponent<CanvasGroup>();
|
|
|
|
// Ensure MatchStatTracker exists to record stats from match start
|
|
if (MatchStatTracker.Instance == null)
|
|
{
|
|
GameObject trackerObj = new GameObject("MatchStatTracker");
|
|
trackerObj.AddComponent<MatchStatTracker>();
|
|
}
|
|
|
|
// IMPORTANT: Do NOT use SetActive(false) — that disables the MonoBehaviour
|
|
// and unsubscribes from GameEvents.OnMatchResult.
|
|
// Instead hide via CanvasGroup so the script stays alive.
|
|
HideImmediate();
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
GameEvents.OnMatchResult += OnMatchResult;
|
|
|
|
// Wire button listeners
|
|
WireButtonListeners();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
GameEvents.OnMatchResult -= OnMatchResult;
|
|
|
|
if (continueButton != null) continueButton.onClick.RemoveListener(OnContinueClicked);
|
|
if (restartButton != null) restartButton.onClick.RemoveListener(OnRestartClicked);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Late-wire buttons — handles auto-created panels where buttons
|
|
/// are assigned after Awake/OnEnable.
|
|
/// </summary>
|
|
private void Start()
|
|
{
|
|
WireButtonListeners();
|
|
}
|
|
|
|
private void WireButtonListeners()
|
|
{
|
|
if (continueButton != null)
|
|
{
|
|
continueButton.onClick.RemoveListener(OnContinueClicked);
|
|
continueButton.onClick.AddListener(OnContinueClicked);
|
|
}
|
|
if (restartButton != null)
|
|
{
|
|
restartButton.onClick.RemoveListener(OnRestartClicked);
|
|
restartButton.onClick.AddListener(OnRestartClicked);
|
|
}
|
|
}
|
|
|
|
// ─── Event ───────────────────────────────────────────────
|
|
|
|
private void OnMatchResult(bool playerWon)
|
|
{
|
|
Show(playerWon);
|
|
}
|
|
|
|
// ─── Public API ──────────────────────────────────────────
|
|
|
|
/// <summary>Show the result screen. Called automatically via GameEvents or manually.</summary>
|
|
public void Show(bool playerWon)
|
|
{
|
|
DevLog.Log($"[MatchResultUI] Show(playerWon={playerWon})");
|
|
rootPanel.SetActive(true);
|
|
// Don't set alpha here — RevealRoutine fades from 0 to 1
|
|
_canvasGroup.alpha = 0f;
|
|
_canvasGroup.blocksRaycasts = false;
|
|
_canvasGroup.interactable = false;
|
|
|
|
// Pause game so combat freezes behind the result panel
|
|
_savedFixedDeltaTime = Time.fixedDeltaTime;
|
|
Time.timeScale = 0f;
|
|
// NOTE: Do NOT set fixedDeltaTime to 0 — timeScale=0 already pauses FixedUpdate.
|
|
// Setting fixedDeltaTime=0 caused an infinite loop / hard freeze.
|
|
|
|
bool isCashSystem = SelectionOptions.Instance != null && SelectionOptions.Instance.isCashSystemSelected;
|
|
|
|
// ── Header ──
|
|
if (resultHeaderText != null)
|
|
{
|
|
resultHeaderText.text = playerWon ? "VICTORY" : "DEFEAT";
|
|
resultHeaderText.color = playerWon ? victoryColor : defeatColor;
|
|
}
|
|
|
|
// ── Scores ──
|
|
if (isCashSystem)
|
|
PopulateCashSystemScores(playerWon);
|
|
else
|
|
PopulatePracticeScores(playerWon);
|
|
|
|
// ── Team labels ──
|
|
PopulateTeamLabels(playerWon, isCashSystem);
|
|
|
|
// ── Stats ──
|
|
if (isCashSystem)
|
|
PopulateCashSystemStats();
|
|
else
|
|
PopulatePracticeStats();
|
|
|
|
// ── Sound ──
|
|
AudioClip clip = playerWon ? victorySFX : defeatSFX;
|
|
if (clip != null) _audio.PlayOneShot(clip, sfxVolume);
|
|
|
|
// ── Animate ──
|
|
StartCoroutine(RevealRoutine());
|
|
}
|
|
|
|
// ─── Cash System Stats ───────────────────────────────────
|
|
|
|
private void PopulateCashSystemScores(bool playerWon)
|
|
{
|
|
CashSystemManager mgr = CashSystemManager.Instance;
|
|
float playerScore = 0f, enemyScore = 0f;
|
|
if (mgr != null)
|
|
{
|
|
var pv = mgr.GetVault("Player");
|
|
var ev = mgr.GetVault("Enemy");
|
|
if (pv != null) playerScore = pv.StoredCash;
|
|
if (ev != null) enemyScore = ev.StoredCash;
|
|
}
|
|
|
|
if (scoreText != null)
|
|
{
|
|
string resultWord = playerWon ? "VICTORY" : "DEFEAT";
|
|
scoreText.text = $"{playerScore:F0} {resultWord} {enemyScore:F0}";
|
|
}
|
|
}
|
|
|
|
private void PopulateCashSystemStats()
|
|
{
|
|
CashSystemManager mgr = CashSystemManager.Instance;
|
|
if (mgr == null) { ClearStats(true); return; }
|
|
|
|
MatchStatTracker tracker = MatchStatTracker.Instance;
|
|
|
|
var playerChars = mgr.GetTeamCharacters("Player");
|
|
var enemyChars = mgr.GetTeamCharacters("Enemy");
|
|
|
|
// Get vault totals for the score header
|
|
var pv = mgr.GetVault("Player");
|
|
var ev = mgr.GetVault("Enemy");
|
|
float playerVaultTotal = pv != null ? pv.StoredCash : 0f;
|
|
float enemyVaultTotal = ev != null ? ev.StoredCash : 0f;
|
|
|
|
int pKills = 0;
|
|
float pDeposited = 0f, pStolen = 0f, pCollected = 0f;
|
|
int eKills = 0;
|
|
float eDeposited = 0f, eStolen = 0f, eCollected = 0f;
|
|
|
|
if (tracker != null)
|
|
{
|
|
foreach (var s in tracker.GetTeamStats(playerChars))
|
|
{
|
|
pKills += s.kills;
|
|
pDeposited += s.cashDeposited;
|
|
pStolen += s.cashStolen;
|
|
pCollected += s.cashCollected;
|
|
}
|
|
foreach (var s in tracker.GetTeamStats(enemyChars))
|
|
{
|
|
eKills += s.kills;
|
|
eDeposited += s.cashDeposited;
|
|
eStolen += s.cashStolen;
|
|
eCollected += s.cashCollected;
|
|
}
|
|
}
|
|
|
|
// Player side — Cash System stats (4 text slots used smartly for cash data)
|
|
SetStatText(playerNameText, "PLAYER TEAM");
|
|
SetStatText(playerKillsText, $"Vault Total: ${playerVaultTotal:F0}");
|
|
SetStatText(playerDeathsText, $"Cash Deposited: ${pDeposited:F0}");
|
|
SetStatText(playerAssistsText, $"Cash Stolen: ${pStolen:F0}");
|
|
SetStatText(playerDamageText, $"Eliminations: {pKills}");
|
|
|
|
// Enemy side
|
|
SetStatText(enemyNameText, "ENEMY TEAM");
|
|
SetStatText(enemyKillsText, $"Vault Total: ${enemyVaultTotal:F0}");
|
|
SetStatText(enemyDeathsText, $"Cash Deposited: ${eDeposited:F0}");
|
|
SetStatText(enemyAssistsText, $"Cash Stolen: ${eStolen:F0}");
|
|
SetStatText(enemyDamageText, $"Eliminations: {eKills}");
|
|
}
|
|
|
|
// ─── Practice / 1v1 Stats ────────────────────────────────
|
|
|
|
private void PopulatePracticeScores(bool playerWon)
|
|
{
|
|
if (scoreText != null)
|
|
{
|
|
scoreText.text = playerWon ? "VICTORY" : "DEFEAT";
|
|
}
|
|
}
|
|
|
|
private void PopulatePracticeStats()
|
|
{
|
|
MatchStatTracker tracker = MatchStatTracker.Instance;
|
|
|
|
// In practice mode: find Player and Enemy tagged objects
|
|
GameObject playerObj = GameObject.FindGameObjectWithTag("Player");
|
|
GameObject enemyObj = GameObject.FindGameObjectWithTag("Enemy");
|
|
|
|
int pKills = 0, pDeaths = 0, pAssists = 0;
|
|
float pDamage = 0f;
|
|
int eKills = 0, eDeaths = 0, eAssists = 0;
|
|
float eDamage = 0f;
|
|
|
|
if (tracker != null)
|
|
{
|
|
if (playerObj != null)
|
|
{
|
|
var s = tracker.GetStats(playerObj);
|
|
pKills = s.kills;
|
|
pDeaths = s.deaths;
|
|
pAssists = s.assists;
|
|
pDamage = s.damageDealt;
|
|
}
|
|
if (enemyObj != null)
|
|
{
|
|
var s = tracker.GetStats(enemyObj);
|
|
eKills = s.kills;
|
|
eDeaths = s.deaths;
|
|
eAssists = s.assists;
|
|
eDamage = s.damageDealt;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Fallback from HealthNew
|
|
if (playerObj != null) FallbackSingle(playerObj, out pKills, out pDeaths, out pDamage);
|
|
if (enemyObj != null) FallbackSingle(enemyObj, out eKills, out eDeaths, out eDamage);
|
|
}
|
|
|
|
// Get actual character display names for practice mode
|
|
string playerName = GetCharacterDisplayName(playerObj, "PLAYER");
|
|
string enemyName = GetCharacterDisplayName(enemyObj, "ENEMY");
|
|
|
|
// Player side — practice labels (K/D/A + Damage)
|
|
SetStatText(playerNameText, playerName);
|
|
SetStatText(playerKillsText, $"Kills: {pKills}");
|
|
SetStatText(playerDeathsText, $"Deaths: {pDeaths}");
|
|
SetStatText(playerAssistsText, $"Assists: {pAssists}");
|
|
SetStatText(playerDamageText, $"Damage: {pDamage:F0}");
|
|
|
|
// Enemy side
|
|
SetStatText(enemyNameText, enemyName);
|
|
SetStatText(enemyKillsText, $"Kills: {eKills}");
|
|
SetStatText(enemyDeathsText, $"Deaths: {eDeaths}");
|
|
SetStatText(enemyAssistsText, $"Assists: {eAssists}");
|
|
SetStatText(enemyDamageText, $"Damage: {eDamage:F0}");
|
|
}
|
|
|
|
// ─── Common Helpers ──────────────────────────────────────
|
|
|
|
private void PopulateTeamLabels(bool playerWon, bool isCashSystem)
|
|
{
|
|
if (isCashSystem)
|
|
{
|
|
if (playerTeamLabel != null)
|
|
playerTeamLabel.text = playerWon ? "PLAYER TEAM WIN!" : "PLAYER TEAM LOSE!";
|
|
if (enemyTeamLabel != null)
|
|
enemyTeamLabel.text = playerWon ? "ENEMY TEAM LOSE!" : "ENEMY TEAM WIN!";
|
|
}
|
|
else
|
|
{
|
|
// Practice mode — use actual character names
|
|
GameObject playerObj = GameObject.FindGameObjectWithTag("Player");
|
|
GameObject enemyObj = GameObject.FindGameObjectWithTag("Enemy");
|
|
string pName = GetCharacterDisplayName(playerObj, "YOU");
|
|
string eName = GetCharacterDisplayName(enemyObj, "ENEMY");
|
|
|
|
if (playerTeamLabel != null)
|
|
playerTeamLabel.text = playerWon ? $"{pName} WIN!" : $"{pName} LOSE!";
|
|
if (enemyTeamLabel != null)
|
|
enemyTeamLabel.text = playerWon ? $"{eName} LOSE!" : $"{eName} WIN!";
|
|
}
|
|
}
|
|
|
|
/// <summary>Get the display name for a character GameObject (e.g. "WINDHAM").</summary>
|
|
private string GetCharacterDisplayName(GameObject character, string fallback)
|
|
{
|
|
if (character == null) return fallback;
|
|
if (CharacterPrefabManager.Instance != null)
|
|
{
|
|
string name = CharacterPrefabManager.Instance.GetCharacterDisplayName(character);
|
|
if (!string.IsNullOrEmpty(name)) return name.ToUpper();
|
|
}
|
|
return character.name.Replace("(Clone)", "").Trim().ToUpper();
|
|
}
|
|
|
|
private void SetStatText(TextMeshProUGUI tmp, string value)
|
|
{
|
|
if (tmp != null) tmp.text = value;
|
|
}
|
|
|
|
private void ClearStats(bool isCashSystem = false)
|
|
{
|
|
if (isCashSystem)
|
|
{
|
|
SetStatText(playerNameText, "PLAYER TEAM");
|
|
SetStatText(playerKillsText, "Vault Total: $0");
|
|
SetStatText(playerDeathsText, "Cash Deposited: $0");
|
|
SetStatText(playerAssistsText, "Cash Stolen: $0");
|
|
SetStatText(playerDamageText, "Eliminations: 0");
|
|
SetStatText(enemyNameText, "ENEMY TEAM");
|
|
SetStatText(enemyKillsText, "Vault Total: $0");
|
|
SetStatText(enemyDeathsText, "Cash Deposited: $0");
|
|
SetStatText(enemyAssistsText, "Cash Stolen: $0");
|
|
SetStatText(enemyDamageText, "Eliminations: 0");
|
|
}
|
|
else
|
|
{
|
|
SetStatText(playerNameText, "PLAYER");
|
|
SetStatText(playerKillsText, "Kills: 0");
|
|
SetStatText(playerDeathsText, "Deaths: 0");
|
|
SetStatText(playerAssistsText, "Assists: 0");
|
|
SetStatText(playerDamageText, "Damage: 0");
|
|
SetStatText(enemyNameText, "ENEMY");
|
|
SetStatText(enemyKillsText, "Kills: 0");
|
|
SetStatText(enemyDeathsText, "Deaths: 0");
|
|
SetStatText(enemyAssistsText, "Assists: 0");
|
|
SetStatText(enemyDamageText, "Damage: 0");
|
|
}
|
|
}
|
|
|
|
/// <summary>Fallback stats from HealthNew for a team list.</summary>
|
|
private void FallbackStats(List<GameObject> team, out int kills, out int deaths, out float damage)
|
|
{
|
|
kills = 0; deaths = 0; damage = 0f;
|
|
if (team == null) return;
|
|
foreach (var c in team)
|
|
{
|
|
if (c == null) continue;
|
|
var h = c.GetComponent<HealthNew>();
|
|
if (h == null) continue;
|
|
if (h.isDead) deaths++;
|
|
damage += Mathf.Max(0, h.maxHealth - h.currentHealth);
|
|
}
|
|
}
|
|
|
|
/// <summary>Fallback stats from HealthNew for a single character.</summary>
|
|
private void FallbackSingle(GameObject character, out int kills, out int deaths, out float damage)
|
|
{
|
|
kills = 0; deaths = 0; damage = 0f;
|
|
if (character == null) return;
|
|
var h = character.GetComponent<HealthNew>();
|
|
if (h == null) return;
|
|
if (h.isDead) deaths = 1;
|
|
damage = Mathf.Max(0, h.maxHealth - h.currentHealth);
|
|
}
|
|
|
|
/// <summary>Hide panel via CanvasGroup — keeps MonoBehaviour alive.</summary>
|
|
private void HideImmediate()
|
|
{
|
|
_canvasGroup.alpha = 0f;
|
|
_canvasGroup.blocksRaycasts = false;
|
|
_canvasGroup.interactable = false;
|
|
}
|
|
|
|
// ─── Animation ───────────────────────────────────────────
|
|
|
|
private IEnumerator RevealRoutine()
|
|
{
|
|
_canvasGroup.alpha = 0f;
|
|
_canvasGroup.blocksRaycasts = true;
|
|
_canvasGroup.interactable = true;
|
|
float elapsed = 0f;
|
|
while (elapsed < revealDuration)
|
|
{
|
|
elapsed += Time.unscaledDeltaTime;
|
|
_canvasGroup.alpha = Mathf.Clamp01(elapsed / revealDuration);
|
|
yield return null;
|
|
}
|
|
_canvasGroup.alpha = 1f;
|
|
}
|
|
|
|
// ─── Button Callbacks ────────────────────────────────────
|
|
|
|
private void OnContinueClicked()
|
|
{
|
|
PlayButtonClick();
|
|
|
|
// Restore time before scene transition
|
|
Time.timeScale = 1f;
|
|
Time.fixedDeltaTime = _savedFixedDeltaTime;
|
|
GameEvents.ClearAll();
|
|
|
|
GameStatsManager statsManager = FindObjectOfType<GameStatsManager>();
|
|
if (statsManager != null)
|
|
statsManager.match_end();
|
|
else
|
|
UnityEngine.SceneManagement.SceneManager.LoadScene("MenuScene");
|
|
}
|
|
|
|
private void OnRestartClicked()
|
|
{
|
|
PlayButtonClick();
|
|
|
|
// Restore time before scene transition
|
|
Time.timeScale = 1f;
|
|
Time.fixedDeltaTime = _savedFixedDeltaTime;
|
|
GameEvents.ClearAll();
|
|
|
|
// Mode flags are preserved on SelectionOptions (DontDestroyOnLoad)
|
|
UnityEngine.SceneManagement.SceneManager.LoadScene(
|
|
UnityEngine.SceneManagement.SceneManager.GetActiveScene().name);
|
|
}
|
|
|
|
private void PlayButtonClick()
|
|
{
|
|
if (buttonClickSFX != null && _audio != null)
|
|
_audio.PlayOneShot(buttonClickSFX, sfxVolume);
|
|
}
|
|
}
|