using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.UI; public class ScoreManager : MonoBehaviour { public int totalScore; public int heat; public static ScoreManager Instance; public Slider heatBar; public PlayerInput playerInput; public Button heatButton; public GameObject heatBarFill; public TextMeshProUGUI scoreText; public TextMeshProUGUI nearMissMultiplierText; public int minHeatValue = 200; public int nearMissMultiplier = 0; // ========================= // ADAPTIVE SYSTEM STATE // ========================= [HideInInspector] public float noInteractionTimer = 0f; public float interactionWindow = 3f; [HideInInspector] public bool hadHeatUsage = false; private float heatPressure = 0f; // 🔥 NEW: persistent pressure system void Awake() { if (Instance == null) Instance = this; else Destroy(gameObject); heatButton.interactable = false; if (heatBarFill != null) heatBarFill.SetActive(false); } void Update() { noInteractionTimer += Time.deltaTime; } // ========================= // SCORE // ========================= public void SyncTextScore(bool shake) { if (scoreText == null) return; scoreText.text = totalScore.ToString("D8"); if (shake) VFXManager.Instance.TextShake(scoreText, 30f, 0.2f); } public void SyncTextMultiplier(float shakeRatio) { if (nearMissMultiplierText == null) return; nearMissMultiplierText.text = "x" + nearMissMultiplier; float intensity = 30f + Mathf.Log10(shakeRatio + 1f) * 6f; VFXManager.Instance.TextShake(nearMissMultiplierText, intensity, 0.2f); } // ========================= // SCORE EVENTS // ========================= public void AddNearMiss(int nearMissScore) { totalScore += nearMissScore * nearMissMultiplier; SyncTextScore(true); noInteractionTimer = 0f; } public void AddNormalPoint(int normalPoint) { totalScore += normalPoint; SyncTextScore(false); noInteractionTimer = 0f; } // ========================= // HEAT SYSTEM (FINAL BALANCE) // ========================= public void AddHeat(int addedHeat) { float difficultyFactor = Mathf.Lerp(1.2f, 0.7f, heatPressure); heat += Mathf.RoundToInt(addedHeat * difficultyFactor); if (heatBar != null) heatBar.value = heat; if (heatBarFill != null) heatBarFill.SetActive(true); if (heat >= minHeatValue) heatButton.interactable = true; } public void HeatButton() { // 💥 reward totalScore += 200; SyncTextScore(true); // reset heat heat = 0; if (heatBar != null) heatBar.value = 0; heatButton.interactable = false; if (heatBarFill != null) heatBarFill.SetActive(false); hadHeatUsage = true; noInteractionTimer = 0f; // 🎥 VFX VFXManager.Instance.SlowMo(0.7f, 1f); VFXManager.Instance.ScreenShake(0.25f, 0.4f); VFXManager.Instance.TextShake(scoreText, 0.3f, 0.3f); // ========================= // 💣 GUARANTEED BULLET WIPE // ========================= // 1. snapshot (freeze current state) var snapshot = new List(playerInput.bullets); // 2. clear source immediately (stop new logic interfering) playerInput.bullets.Clear(); // 3. destroy safely for (int i = 0; i < snapshot.Count; i++) { if (snapshot[i] != null) Destroy(snapshot[i]); } // 4. optional: clear spawner list if exists // (VERY IMPORTANT if you still use it elsewhere) // BulletSpawner should expose ClearBullets() } // ========================= // MULTIPLIER SYSTEM // ========================= public void NearMissMultiplierManager(bool isNearMiss) { if (isNearMiss) nearMissMultiplier++; else nearMissMultiplier = 0; if (nearMissMultiplierText != null) { nearMissMultiplierText.gameObject.SetActive(nearMissMultiplier >= 1); SyncTextMultiplier(nearMissMultiplier); } } // ========================= // EXTERNAL ACCESS FOR SPAWNER // ========================= public float GetDifficultyModifier() { float baseDifficulty = Mathf.Clamp01( 1f - Mathf.Exp(-Time.time / 30f) ); float pressure = heatPressure * 0.1f; float floor = 0.25f + nearMissMultiplier * 0.03f; return Mathf.Clamp01(Mathf.Max(baseDifficulty + pressure, floor)); } }