using System.Collections.Generic; using Cielonos.MainGame.Buffs.Character; using Cielonos.MainGame.Characters; using Cielonos.MainGame.Effects.Feedback; using Lean.Pool; using SLSUtilities.General; using SLSUtilities.WwiseAssistance; using UnityEngine; namespace Cielonos.MainGame.Inventory.Collections { public partial class FutureWand { private readonly List _activeSpinAreas = new List(); private const float NormalBoltSpeed = 10f; private const float CubicBoltSpeed = 15f; private int _spinAreaUpgradeCount = 0; /// /// 召回当前在战场中飞旋的法盘区域。 /// private void RecallAllSpinAreas() { for (int i = _activeSpinAreas.Count - 1; i >= 0; i--) { var area = _activeSpinAreas[i]; if (area == null) { _activeSpinAreas.RemoveAt(i); continue; } if (area.moveSm is AttackAreaBase.BoomerangMoveSubmodule boomerangSm) { boomerangSm.TriggerReturn(); } } } private void GenerateLightning(string vfxName, AttackUnit attackUnit, CharacterBase target, Vector3 position = default) { if (target == null && position == default) return; vfxData.SpawnMuzzleVFX(vfxName, player, Muzzle); NormalArea lightning = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren(); lightning.Initialize(player, this, Fraction.Enemy) .SetAttackSubmodule(attackUnit) .SetTimeSubmodule(2f, 0.1f, 0.04f) .SetHitSubmodule(); lightning.eventSm.onHit.Add((enemy, hitPosition) => { new LightningBuff().Apply(enemy, player, this); feedbackSc.PlayFeedback("LightningHit"); }); Vector3 spawnPosition = target != null ? target.transform.position : position; lightning.topParent.transform.position = spawnPosition; AudioManager.Post(AK.EVENTS.FUTUREWAND_MEDIUMATTACKHIT, spawnPosition); } private void GenerateGroundArea(string vfxName, AttackUnit attackUnit) { vfxData.SpawnMuzzleVFX(vfxName, player, Muzzle); NormalArea area = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren(); AudioManager.Post(AK.EVENTS.FUTUREWAND_GROUNDAREA, area.gameObject); if (!_hasBlackHoleDisplacer) { area.Initialize(player, this, Fraction.Enemy) .SetAttackSubmodule(attackUnit) .SetTimeSubmodule(3f, 0.2f, 0.8f) .SetHitSubmodule(0.1f, 4); } else { area.Initialize(player, this, Fraction.Enemy); ApplyBlackHoleDisplacer(area, attackUnit); } area.SetTractionSubmodule(6f); area.hitSm.AddHitSound(AK.EVENTS.FUTUREWAND_WEAKATTACKHIT); int fusionStack = GetBaseFusionStack(attackUnit); area.eventSm.onHit.Add((enemy, hitPosition) => { new Fusion(fusionStack).Apply(enemy); SubscribeFusionExplode(enemy); }); } private void GenerateUltimateBeam(string vfxName, AttackUnit attackUnit) { vfxData.SpawnMuzzleVFX(vfxName, player, Muzzle); NormalArea area = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren(); area.Initialize(player, this, Fraction.Enemy) .SetAttackSubmodule(attackUnit) .SetTimeSubmodule(5f, 0.6f, 0.04f) .SetHitSubmodule(); area.SetImpulseSubmodule().WithCustomForce(player.transform.forward * 15f); area.hitSm.AddHitSound(AK.EVENTS.FUTUREWAND_MEDIUMATTACKHIT); AudioManager.Post(AK.EVENTS.FUTUREWAND_ULTIMATEBEAMPOWERUP, area.gameObject); area.AddScheduleAction(() => { AudioManager.Post(AK.EVENTS.FUTUREWAND_ULTIMATEBEAMSHOOT); feedbackSc.PlayFeedback("UltimateBeamShoot"); }, 0.6f); } private void GenerateTornado(string vfxName, AttackUnit attackUnit, CharacterBase target, float speed) { vfxData.SpawnMuzzleVFX(vfxName, player, Muzzle); NormalArea area = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren(); area.Initialize(player, this, Fraction.Enemy) .SetAttackSubmodule(attackUnit) .SetTimeSubmodule(2f, 0f, 1.5f) .SetHitSubmodule() .SetLinearDirectionMoveModule(player.transform.forward, speed, 0f, true, false, false) //.SetAdaptiveTraceMoveSubmodule(target, speed, 5f, 180f, 30f, player.transform.forward, detectRadius: 25f, stopWhenHit: true) .SetTransformSubmodule(); area.SetImpulseSubmodule(1f).WithDynamicForce(30f); //(area.moveSm as TraceMoveSubmodule)?.WithKeepFlat(true); AudioManager.Post(AK.EVENTS.FUTUREWAND_TORNADO); area.hitSm.AddHitSound(AK.EVENTS.FUTUREWAND_WEAKATTACKHIT); int fusionStack = GetBaseFusionStack(attackUnit); area.eventSm.onHit.Add((enemy, hitPosition) => { new Fusion(fusionStack).Apply(enemy); SubscribeFusionExplode(enemy); }); } private void GenerateProjectile(string vfxName, AttackUnit attackUnit, CharacterBase target, bool hasMuzzleEffect = true, Transform muzzle = null) { float speed = vfxName == "CubicBolt" ? CubicBoltSpeed : NormalBoltSpeed; if (hasMuzzleEffect) { muzzle ??= Muzzle; vfxData.SpawnMuzzleVFX(vfxName, player, muzzle); } Projectile projectile = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren(); Vector3 direction = player.transform.forward; if (target != null) { direction = (target.CenterPoint.position - projectile.transform.position).normalized; } projectile.Initialize(player, this, false, 1, Fraction.Enemy) .SetAttackSubmodule(attackUnit) .SetTimeSubmodule(10f, 0f, 10f) .SetHitSubmodule() .SetAdaptiveTraceMoveSubmodule(target, speed, 5f, 180f, 30f, direction, detectRadius: 25f) .SetRaycastSubmodule(default, 0.25f, 0.5f); if (vfxName == "NormalBolt") { projectile.hitSm.AddHitSound(AK.EVENTS.FUTUREWAND_WEAKATTACKHIT); projectile.SetImpulseSubmodule().WithDynamicForce(2f); projectile.eventSm.onHit.Add((enemy, hitPosition)=> { feedbackSc.PlayFeedback("NormalBoltHit", rt => { rt.Action("Camera").amplitude = GetBoltHitShakeAmplitude(hitPosition, 0.035f, -0.035f, 0.04f); }); }); AudioManager.Post(AK.EVENTS.FUTUREWAND_NORMALBOLTRELEASE, projectile.gameObject); } else if (vfxName == "CubicBolt") { projectile.hitSm.AddHitSound(AK.EVENTS.FUTUREWAND_MEDIUMATTACKHIT); projectile.SetImpulseSubmodule().WithDynamicForce(4f); projectile.eventSm.onHit.Add((enemy, hitPosition) => { feedbackSc.PlayFeedback("CubicBoltHit", rt => { rt.Action("Camera").amplitude = GetBoltHitShakeAmplitude(hitPosition, 0.055f, -0.05f, 0.065f); }); }); AudioManager.Post(AK.EVENTS.FUTUREWAND_CUBICBOLTRELEASE, projectile.gameObject); } int fusionStack = GetBaseFusionStack(attackUnit); if (_hasFusionChargeCore) { fusionStack = ApplyFusionChargeCore(fusionStack, vfxName); } projectile.eventSm.onHit.Add((enemy, hitPosition) => { new Fusion(fusionStack).Apply(enemy); SubscribeFusionExplode(enemy); if (_hasMissileSeparationMembrane) { TryGenerateMissileSeparation(projectile, vfxName, attackUnit, enemy, hitPosition, speed); } }); } private Vector3 GetBoltHitShakeAmplitude(Vector3 hitPosition, float horizontalStrength, float verticalKick, float depthKick) { return FeedbackVectorUtility.ScreenHitPositionToAmplitude( hitPosition, MainGameManager.Player.viewSc.playerCamera, horizontalStrength, verticalKick, depthKick); } private void GenerateSpinArea(string vfxName, AttackUnit attackUnit) { AttackUnit upgradedAttackUnit = attackUnit.Clone(); float damageMultiplier = 0.75f + _spinAreaUpgradeCount * 0.25f; upgradedAttackUnit.startDamage *= damageMultiplier; vfxData.SpawnMuzzleVFX(vfxName, player, Muzzle); NormalArea area = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren(); area.Initialize(player, this, Fraction.Enemy) .SetAttackSubmodule(upgradedAttackUnit) .SetTimeSubmodule(int.MaxValue, 0.5f, int.MaxValue, null, Shrink) .SetHitSubmodule(0.25f, int.MaxValue) .SetBoomerangMoveSubmodule(PrimaryTarget, 10f, 0f, 360f, 0f, player.transform.forward) .SetTransformSubmodule(); (area.moveSm as AttackAreaBase.BoomerangMoveSubmodule) !.WithAutoReturn(2f + _spinAreaUpgradeCount * 3f) .WithCatch(1.5f, Shrink) .WithTargeting(true, 25f) .WithKeepFlat(true) .WithReturnParameters(20f, 10f, float.MaxValue, 0f); area.transformSm.ApplyScaleMove(Vector3.zero, Vector3.one * 3, 0.5f, EaseType.OutQuad); area.SetImpulseSubmodule().WithSuction(4f); AudioManager.Post(AK.EVENTS.FUTUREWAND_SPINAREARELEASE); area.hitSm.AddHitSound(AK.EVENTS.FUTUREWAND_WEAKATTACKHIT); int fusionStack = GetBaseFusionStack(upgradedAttackUnit); area.eventSm.onHit.Add((enemy, hitPosition) => { new Fusion(fusionStack).Apply(enemy); SubscribeFusionExplode(enemy); }); _spinAreaUpgradeCount = 0; _activeSpinAreas.Add(area); return; void Shrink() { if(area == null) return; area.transformSm.Reset().ApplyScaleMove(Vector3.one * 3, Vector3.zero, 0.5f, EaseType.OutQuad); area.AddScheduleAction(() => LeanPool.Despawn(area.topParent.gameObject), 0.5f); _activeSpinAreas.Remove(area); } } } } /*area.updateAction = () => // 消除敌方投射物 { if (area.timeSm.enablingTimer > 3f) { return; } List toBeRemoved = new List(); foreach (Projectile projectile in CombatManager.AttackAreaSm.enemyAttackAreas.activeProjectiles) { if (area.areaCollider.IsPointInside(projectile.topParent.transform.position)) { toBeRemoved.Add(projectile); } } foreach (Projectile projectile in toBeRemoved) { projectile.Explode(); } };*/