using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; public class OpponentDragSpawner : MonoBehaviour, IRoundCallback, IManaChangeCallback, IDragDropListener { [SerializeField] Opponent opponent; [SerializeField] Color disabledPreviewSpriteColor = new Color(0.5f, 0.5f, 0.5f, 1f); [SerializeField] Color disabledCostTextColor = Color.red; [SerializeField] List<AudioClip> spawnOpponentSfx; int placedOpponentCount = 0; bool currentlyPlacingNew = false; Image previewSprite; Text costText; Color defaultCostTextColor; BaseCameraController cameraController; void Start() { previewSprite = transform.Find("OpponentImage").GetComponent<Image>(); costText = transform.Find("Cost").GetComponent<Text>(); defaultCostTextColor = costText.color; previewSprite.sprite = opponent.enemySprite; cameraController = Camera.main.GetComponent<BaseCameraController>(); var eventTrigger = GetComponent<EventTrigger>(); var beginDragEvent = new EventTrigger.Entry(); beginDragEvent.eventID = EventTriggerType.BeginDrag; beginDragEvent.callback.AddListener((data) => OnBeginDrag((PointerEventData)data)); eventTrigger.triggers.Add(beginDragEvent); StatsManager.instance.manaChangeCallbacks.Add(this); RoundController.instance.roundCallbacks.Add(this); DragDestroyController.instance.listeners.Add(this); UpdateDisplayStates(); } void OnBeginDrag(PointerEventData eventData) { if (RoundController.instance.roundRunning || !StatsManager.instance.ModifyMana(GetNextOpponentCost())) { return; } var newEnemy = Instantiate(opponent.enemyPrefab); DragDestroyController.instance.HandoffEnemy(newEnemy); cameraController.PlayRandomGlobalAudioClip(spawnOpponentSfx); placedOpponentCount++; currentlyPlacingNew = true; UpdateDisplayStates(); } void UpdateDisplayStates() { // Enemies call `OnEnemyDeleted()` when they are destroyed. This also happens // when exiting the game though. This is probably a hacky solution, but w/e if (costText.IsDestroyed()) { return; } var nextCost = GetNextOpponentCost(); costText.text = (-nextCost).ToString(); var canBuy = StatsManager.instance.CanModifyMana(nextCost); previewSprite.color = canBuy && !RoundController.instance.roundRunning ? Color.white : disabledPreviewSpriteColor; costText.color = canBuy ? defaultCostTextColor : disabledCostTextColor; } int GetNextOpponentCost() { return (int)(-opponent.enemyCost * Mathf.Pow(1 + opponent.costMultiplier, placedOpponentCount)); } void RecalculatePlacedOpponentsCount() { placedOpponentCount = 0; foreach (var enemy in RoundController.instance.placedEnemies) { if (enemy.opponentType == opponent) { placedOpponentCount++; } } UpdateDisplayStates(); } public void OnEnemyPlaced(GameObject enemy, Opponent opponent, bool validPosition) { if (opponent == this.opponent) { if (!validPosition && currentlyPlacingNew) { // Enemy placed in invalid position; will be destroyed and refunded Destroy(enemy); placedOpponentCount--; StatsManager.instance.ModifyMana(-GetNextOpponentCost()); } currentlyPlacingNew = false; UpdateDisplayStates(); } } public void OnEnemyDeleted(GameObject enemy, Opponent opponent) { if (opponent == this.opponent) { placedOpponentCount--; StatsManager.instance.ModifyMana(-GetNextOpponentCost()); UpdateDisplayStates(); } } public void OnRoundStart() { UpdateDisplayStates(); } public void OnRoundEnd(bool won) { // To make sure this is called _after_ enemies might have destroyed itself in this callback Invoke(nameof(RecalculatePlacedOpponentsCount), 0.01f); UpdateDisplayStates(); } public void OnManaChanged(int oldValue, int newValue) { UpdateDisplayStates(); } }