using OTGIntegrated.Combat; using UnityEngine; namespace OTGIntegrated.Abilities { [RequireComponent(typeof(Collider))] public sealed class FireballEffect : AbilityEffect { public float speed = 16f; public float radius = 0.35f; public LayerMask hitMask = ~0; private AbilityContext context; private Vector3 direction; private float remainingLife; private bool active; private void Awake() { Collider ownCollider = GetComponent(); ownCollider.isTrigger = true; } public override void Activate(AbilityContext context) { this.context = context; direction = context.Forward; remainingLife = Mathf.Max(0.5f, context.Ability.range / Mathf.Max(1f, speed)); active = true; transform.position = context.Origin + direction * 0.9f; transform.rotation = Quaternion.LookRotation(direction, Vector3.up); } private void Update() { if (!active) { return; } float step = speed * Time.deltaTime; if (Physics.SphereCast(transform.position, radius, direction, out RaycastHit hit, step, hitMask, QueryTriggerInteraction.Ignore)) { ApplyHit(hit.collider); return; } transform.position += direction * step; remainingLife -= Time.deltaTime; if (remainingLife <= 0f) { Destroy(gameObject); } } private void OnTriggerEnter(Collider other) { if (active) { ApplyHit(other); } } private void ApplyHit(Collider hitCollider) { if (hitCollider == null || context.Caster == null || hitCollider.transform == context.Caster || hitCollider.GetComponentInParent() != null) { return; } Damageable damageable = hitCollider.GetComponentInParent(); if (damageable != null && damageable.IsAlive) { float finalDamage = context.Ability.damage + (context.Stats != null ? context.Stats.Damage : 0f); damageable.TakeDamage(finalDamage, context.Caster.gameObject); } Destroy(gameObject); } } }