259 lines
8.9 KiB
C#
259 lines
8.9 KiB
C#
using UnityEngine;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using Unity.VisualScripting;
|
||
using DG.Tweening;
|
||
|
||
public class ClawScoreManager : MonoBehaviour
|
||
{
|
||
public static ClawScoreManager Instance;
|
||
public System.Action<int> ApplyExternalDelta;
|
||
|
||
public event Action<int> 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<int> OnScoreAdded;
|
||
public event Action<float> OnTimeAdded;
|
||
public event Action<float> OnPlatformSlow; // pass duration
|
||
public event Action<float> OnPlatformTurbo; // pass duration
|
||
public event Action<float> OnPlatformFreeze; // pass duration
|
||
public event Action<float> OnClawDisabled; // pass duration
|
||
public event Action<float> OnClawJam; // pass duration
|
||
public event Action<ClawBubbleType[]> OnComboAchieved;
|
||
|
||
private int score = 0;
|
||
|
||
// NEW: per-type collected counts
|
||
private readonly Dictionary<ClawBubbleType, int> collectedCounts = new Dictionary<ClawBubbleType, int>();
|
||
public IReadOnlyDictionary<ClawBubbleType, int> CollectedCounts => collectedCounts;
|
||
public int GetCount(ClawBubbleType t) => collectedCounts.TryGetValue(t, out var c) ? c : 0;
|
||
|
||
private readonly Queue<ClawBubbleType> comboQueue = new Queue<ClawBubbleType>();
|
||
private readonly Queue<ClawBubbleType> starQueue = new Queue<ClawBubbleType>();
|
||
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;
|
||
|
||
ApplyExternalDelta = (amt) => { if (amt != 0) AddScore(amt); };
|
||
}
|
||
|
||
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)
|
||
// ... existing switch (type) {...}
|
||
|
||
if (crystalPrimed && points > 0)
|
||
{
|
||
points = Mathf.RoundToInt(points * crystalNextGrabMultiplier);
|
||
crystalPrimed = false;
|
||
}
|
||
|
||
// NEW <20> allow active mode to change points (or apply penalty)
|
||
if (ClawGameModeManager.Instance != null)
|
||
points = ClawGameModeManager.Instance.ModifyPointsBeforeApply(type, points);
|
||
|
||
if (points != 0) AddScore(points);
|
||
|
||
// NEW <20> inform mode that a collection resolved
|
||
if (ClawGameModeManager.Instance != null)
|
||
ClawGameModeManager.Instance.NotifyBubbleResolved(type, points);
|
||
|
||
if (ClawBubbleSpawner.Instance)
|
||
ClawBubbleSpawner.Instance.NotifyBubbleGrabbed(type);
|
||
|
||
//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<ClawGrabCoin>();
|
||
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") + " <sprite name=ball>";
|
||
|
||
// 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<ClawGrabCoin>();
|
||
// scoreFX.transform.SetSiblingIndex(3);
|
||
// if (amount > 0)
|
||
// scoreFX.score.text = "+";
|
||
// scoreFX.score.text += amount + "<sprite name=ball>";
|
||
// 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<ClawBubbleType> 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();
|
||
}
|
||
}
|
||
}
|