using System.Collections.Generic; using SepCore.CustomUtility; using SepCore.Definition; using DG.Tweening; using SepCore.Entity; using UnityEngine; using UnityGameFramework.Runtime; namespace SepCore.Entity { public class WeaponLightning : WeaponBase { [SerializeField] private float _takeOffDuration = 0.3f; [SerializeField] private float _flyToTargetDuration = 0.2f; [SerializeField] private float _strikeDuration = 0.1f; [SerializeField] private float _returnDuration = 0.22f; [SerializeField] private float _hoverHeight = 15f; [SerializeField] private int _maxHitColliders = 32; private Sequence _attackSequence; private Transform _attackParent; private Vector3 _lockedStrikePoint; private Collider[] _hitResults; private readonly HashSet _hitEntityIds = new(); public float HitRadius => WeaponData.GetParamFloat(ParamType.HitRadius); private IWeaponAttackEffect _attackEffect; protected override void BuildStates() { RegisterState(new WeaponLightningIdleState()); RegisterState(new WeaponLightningSeekState()); RegisterState(new WeaponLightningAimState()); RegisterState(new WeaponLightningAttackState()); } public override void Attack() { StopAttackTween(false); FaceTargetImmediately(); _isAttacking = true; _lockedStrikePoint = ResolveStrikePoint(); _attackParent = CachedTransform.parent; CachedTransform.SetParent(null); Vector3 takeOffPosition = CachedTransform.position; Vector3 hoverPosition = _lockedStrikePoint + Vector3.up * Mathf.Max(0.1f, _hoverHeight); _attackSequence = DOTween.Sequence(); _attackSequence.Append(CachedTransform.DOMove(takeOffPosition, _takeOffDuration).SetEase(Ease.OutQuad)); _attackSequence.Append(CachedTransform.DOMove(hoverPosition, _flyToTargetDuration).SetEase(Ease.OutSine)); _attackSequence.AppendCallback(() => CachedTransform.LookAt(_lockedStrikePoint)); _attackSequence.Append(CachedTransform.DOMove(_lockedStrikePoint, _strikeDuration).SetEase(Ease.InQuad)); _attackSequence.AppendCallback(() => { _attackEffect.Play(this, _lockedStrikePoint, _target, HitRadius); ApplyGroundAreaDamage(); if (_attackParent != null) { CachedTransform.SetParent(_attackParent); } }); _attackSequence.Append(CachedTransform.DOLocalMove(Vector3.zero, _returnDuration).SetEase(Ease.OutSine)); _attackSequence.AppendCallback(() => { _isAttacking = false; _attackSequence = null; _attackParent = null; }); } private Vector3 ResolveStrikePoint() { if (_target != null && _target.Available) { return _target.CachedTransform.position; } return CachedTransform.position; } private void ApplyGroundAreaDamage() { float radius = HitRadius; if (radius <= 0f) return; if (TryQueueAreaCollisionQuery(_lockedStrikePoint, radius, Mathf.Max(1, _maxHitColliders))) { return; } if (_hitResults == null || _hitResults.Length == 0) return; int hitCount = Physics.OverlapSphereNonAlloc(_lockedStrikePoint, radius, _hitResults, _hitMask, QueryTriggerInteraction.Collide); float radiusSqr = radius * radius; _hitEntityIds.Clear(); for (int i = 0; i < hitCount; i++) { Collider collider = _hitResults[i]; if (collider == null) continue; TargetableObject targetable = collider.GetComponentInParent(); if (targetable == null || !targetable.Available || targetable.IsDead) continue; if (!_hitEntityIds.Add(targetable.Id)) continue; Vector3 delta = targetable.CachedTransform.position - _lockedStrikePoint; delta.y = 0f; if (delta.sqrMagnitude > radiusSqr) continue; AIUtility.PerformCollision(targetable, this); } } protected override bool OnWeaponShow(object userData) { int colliderCapacity = Mathf.Max(1, _maxHitColliders); if (_hitResults == null || _hitResults.Length != colliderCapacity) { _hitResults = new Collider[colliderCapacity]; } _attackEffect = new LightningStrikeAttackEffect(); return true; } protected override void OnWeaponHide(object userData) { StopAttackTween(true); _attackEffect = null; } protected override void OnWeaponDetach(EntityLogic parentEntity, object userData) { StopAttackTween(true); base.OnWeaponDetach(parentEntity, userData); } protected override void OnEnabledChanged(bool enabled) { if (!enabled) { StopAttackTween(true); } } private void StopAttackTween(bool resetTransform) { if (_attackSequence != null) { _attackSequence.Kill(); _attackSequence = null; } _isAttacking = false; if (resetTransform) { if (_attackParent != null) { CachedTransform.SetParent(_attackParent); CachedTransform.localPosition = Vector3.zero; } else if (CachedTransform.parent != null) { CachedTransform.localPosition = Vector3.zero; } CachedTransform.rotation = _cachedRotation; } _attackParent = null; _hitEntityIds.Clear(); } } }