using BumpCombat.Constants; using UnityEngine; namespace BumpCombat.Defense { [DisallowMultipleComponent] public sealed class DefenseTower : MonoBehaviour { private DefensePrototypeController owner; private DefenseConstants tuning; private float attackCooldown; private TextMesh label; public DefenseTowerKind Kind { get; private set; } public int PadIndex { get; private set; } public bool IsOperational => isActiveAndEnabled && owner != null && owner.CanOperateTowers; public void Configure( DefensePrototypeController controller, DefenseTowerKind kind, int padIndex, DefenseConstants constants) { owner = controller; Kind = kind; PadIndex = padIndex; tuning = constants; CreateVisuals(); if (Kind == DefenseTowerKind.Summon) { for (int i = 0; i < tuning.SummonUnitCount; i++) { GameObject unitObject = new($"Summon Unit {i + 1}"); unitObject.transform.SetParent(transform, false); unitObject.transform.localPosition = new Vector3( (i - (tuning.SummonUnitCount - 1) * 0.5f) * 0.42f, -0.5f, 0f); DefenseSummonUnit unit = unitObject.AddComponent(); unit.Configure(this, controller, unitObject.transform.localPosition); } } } private void Update() { if (!IsOperational || Kind != DefenseTowerKind.Direct) { return; } attackCooldown -= Time.deltaTime; if (attackCooldown > 0f) { return; } float interval = Kind == DefenseTowerKind.Direct ? tuning.DirectTowerAttackInterval : tuning.SummonAttackInterval; if (owner.TryAttackFromTower(this)) { attackCooldown = Mathf.Max(0.05f, interval); } } private void CreateVisuals() { SpriteRenderer renderer = gameObject.GetComponent(); if (renderer == null) { renderer = gameObject.AddComponent(); } renderer.sprite = DefensePrototypeController.WhiteSprite; renderer.color = Kind == DefenseTowerKind.Direct ? new Color32(65, 211, 240, 255) : new Color32(244, 154, 74, 255); renderer.sortingOrder = 8; transform.localScale = new Vector3(0.72f, 0.72f, 1f); GameObject crown = new("Tower Crown"); crown.transform.SetParent(transform, false); crown.transform.localPosition = new Vector3(0f, 0.42f, 0f); crown.transform.localScale = new Vector3(0.42f, 0.22f, 1f); SpriteRenderer crownRenderer = crown.AddComponent(); crownRenderer.sprite = DefensePrototypeController.WhiteSprite; crownRenderer.color = Color.white; crownRenderer.sortingOrder = 9; GameObject labelObject = new("Tower Label"); labelObject.transform.SetParent(transform, false); labelObject.transform.localPosition = new Vector3(0f, 0.85f, 0f); label = labelObject.AddComponent(); label.text = Kind == DefenseTowerKind.Direct ? "DIRECT" : "SUMMON"; label.anchor = TextAnchor.MiddleCenter; label.alignment = TextAlignment.Center; label.characterSize = 0.16f; label.fontSize = 32; label.color = Color.white; label.GetComponent().sortingOrder = 10; } public bool TryAttack(DefenseRouteAgent target) { if (target == null || owner == null) { return false; } float damage = Kind == DefenseTowerKind.Direct ? tuning.DirectTowerDamage : tuning.SummonDamage; return owner.TryApplyTowerDamage(this, target, damage); } } }