using UnityEngine; using System; using System.Collections.Generic; using Unity.VisualScripting; using DG.Tweening; public class ClawScoreManager : MonoBehaviour { public static ClawScoreManager Instance; public event Action OnScoreChanged; // passes TOTAL score public int CurrentScore => score; [Header("Scoring")] public int wolfPoints = 100; public int goldenWolfJackpot = 1000; public int starPoints = 50; public int comboBonus = 300; public int starSuperBonus = 500; [Header("Multipliers")] public float crystalNextGrabMultiplier = 2f; private bool crystalPrimed = false; [Header("Timers & Effects")] public float addTimeSeconds = 5f; // Sand Dial public float slowDuration = 5f; // Clock public float turboDuration = 5f; // Turbo public float freezeDuration = 2f; // Freeze public float bombDisableSeconds = 3f; // Bomb public float shockJamSeconds = 2f; // Shock // Events others can subscribe to public event Action OnScoreAdded; public event Action OnTimeAdded; public event Action OnPlatformSlow; // pass duration public event Action OnPlatformTurbo; // pass duration public event Action OnPlatformFreeze; // pass duration public event Action OnClawDisabled; // pass duration public event Action OnClawJam; // pass duration public event Action OnComboAchieved; private int score = 0; // NEW: per-type collected counts private readonly Dictionary collectedCounts = new Dictionary(); public IReadOnlyDictionary CollectedCounts => collectedCounts; public int GetCount(ClawBubbleType t) => collectedCounts.TryGetValue(t, out var c) ? c : 0; private readonly Queue comboQueue = new Queue(); private readonly Queue starQueue = new Queue(); public GameObject ScoreUIObj; public Transform canvasTransform; void Awake() { Instance = this; // init counts for all enum values foreach (ClawBubbleType t in Enum.GetValues(typeof(ClawBubbleType))) if (!collectedCounts.ContainsKey(t)) collectedCounts[t] = 0; } public void EvaluateBubble(ClawBubbleType type) { Debug.Log("EvaluateBubble: " + type); // count every collected bubble collectedCounts[type] = GetCount(type) + 1; int points = 0; switch (type) { case ClawBubbleType.Wolf: points += wolfPoints; EnqueueCombo(type, comboQueue, 3, () => { AddScore(comboBonus); OnComboAchieved?.Invoke(new[] { ClawBubbleType.Wolf, ClawBubbleType.Wolf, ClawBubbleType.Wolf }); }); break; case ClawBubbleType.GoldenWolf: points += goldenWolfJackpot; break; case ClawBubbleType.Star: points += starPoints; EnqueueCombo(ClawBubbleType.Star, starQueue, 3, () => { AddScore(starSuperBonus); OnComboAchieved?.Invoke(new[] { ClawBubbleType.Star, ClawBubbleType.Star, ClawBubbleType.Star }); }); break; case ClawBubbleType.Crystal: // primes next-grab multiplier crystalPrimed = true; break; case ClawBubbleType.Time: OnTimeAdded?.Invoke(addTimeSeconds); Debug.Log("TimeAdded Function"); break; case ClawBubbleType.Freeze: OnPlatformFreeze?.Invoke(freezeDuration); break; case ClawBubbleType.Turbo: OnPlatformTurbo?.Invoke(turboDuration); break; case ClawBubbleType.Bomb: OnClawDisabled?.Invoke(bombDisableSeconds); OnPlatformTurbo?.Invoke(turboDuration); break; case ClawBubbleType.Shock: OnClawJam?.Invoke(shockJamSeconds); break; } // Apply crystal multiplier if primed (and we actually scored) if (crystalPrimed && points > 0) { points = Mathf.RoundToInt(points * crystalNextGrabMultiplier); crystalPrimed = false; } if (points > 0) AddScore(points); // Tell spawner to introduce new targets if (ClawBubbleSpawner.Instance) ClawBubbleSpawner.Instance.NotifyBubbleGrabbed(type); } private void AddScore(int amount) { // If nothing to add or missing FX/canvas, just apply immediately. if (amount == 0 || ScoreUIObj == null || canvasTransform == null) { score += amount; OnScoreAdded?.Invoke(amount); OnScoreChanged?.Invoke(score); return; } const float MOVE_DURATION = 1f; const float START_DELAY = 1.1f; const int SIBLING_INDEX = 3; // Spawn FX var go = Instantiate(ScoreUIObj, canvasTransform); go.transform.SetSiblingIndex(Mathf.Min(SIBLING_INDEX, go.transform.parent.childCount - 1)); var scoreFX = go.GetComponent(); if (scoreFX == null || scoreFX.score == null) { // If prefab is misconfigured, still apply score to avoid losing points. Destroy(go); score += amount; OnScoreAdded?.Invoke(amount); OnScoreChanged?.Invoke(score); return; } // Text with + / - automatically scoreFX.score.text = amount.ToString("+0;-0;0") + " "; // Choose a move target (child 0 if present, else root) Transform target = go.transform.childCount > 0 ? go.transform.GetChild(0) : go.transform; bool applied = false; void ApplyScoreOnce() { if (applied) return; applied = true; score += amount; OnScoreAdded?.Invoke(amount); OnScoreChanged?.Invoke(score); } // Animate (prefer anchored pos for UI) var rt = target as RectTransform; if (rt != null) { DOTween.Sequence() .AppendInterval(START_DELAY) .Append(rt.DOAnchorPos(Vector2.zero, MOVE_DURATION)) .SetUpdate(true) // ignores timescale; good for UI .OnComplete(ApplyScoreOnce) .OnKill(ApplyScoreOnce); } else { DOTween.Sequence() .AppendInterval(START_DELAY) .Append(target.DOLocalMove(Vector3.zero, MOVE_DURATION)) .SetUpdate(true) .OnComplete(ApplyScoreOnce) .OnKill(ApplyScoreOnce); } } //private void AddScore(int amount) //{ // ClawGrabCoin scoreFX = Instantiate(ScoreUIObj, canvasTransform).GetComponent(); // scoreFX.transform.SetSiblingIndex(3); // if (amount > 0) // scoreFX.score.text = "+"; // scoreFX.score.text += amount + ""; // scoreFX.transform.GetChild(0).transform.DOLocalMove(Vector3.zero, 1).SetDelay(1.75f).OnComplete(() => // { // score += amount; // OnScoreAdded?.Invoke(amount); // delta // OnScoreChanged?.Invoke(score); // total // }); //} private void EnqueueCombo(ClawBubbleType t, Queue q, int target, Action onCombo) { q.Enqueue(t); while (q.Count > target) q.Dequeue(); if (q.Count == target) { var arr = q.ToArray(); bool allSame = true; for (int i = 1; i < arr.Length; i++) if (arr[i] != arr[0]) { allSame = false; break; } if (allSame) onCombo?.Invoke(); } } }