using System.Collections.Generic; using Cielonos.MainGame.Buffs.Character; using Cielonos.MainGame.Characters; using Cielonos.MainGame.UI; using SLSUtilities.FunctionalAnimation; using SLSUtilities.General; using SLSUtilities.WwiseAssistance; using UnityEngine; namespace Cielonos.MainGame.Inventory.Collections { public partial class FutureWand : MainWeaponBase { private bool _isHoldingAttack; public CharacterBase currentTarget; public override void OnEquipped() { base.OnEquipped(); RegisterFunctionsToAnimSc(); if(!player.inputSc.IsMoving) PlayTargetedAnimation("Equip"); viewObjects["Wand"].SetFadeAnim(0.5f); //PlayerCanvas.MainWeaponUIArea.displayer.SetFrameOutline(1); } public override void OnPrimaryPress() { if (!_isHoldingAttack && player.inputSc.IsHoldingSpecialA) { PlayTargetedAnimation("HoldAttackStart", currentTarget); _isHoldingAttack = true; return; } if (functionSm["LightAttack"].IsAvailable() && fullBodyFuncAnimSm.CheckPlayability()) { comboSm.main.NextCombo("L"); functionSm["LightAttack"].Execute(); currentTarget = CombatManager.EnemySm.GetNearestEnemy(25f); if (currentTarget != null) { PlayTargetedAnimation("Attack" + comboSm.main.GetCurrentNodeName(), currentTarget, 5f); } else { PlayTargetedAnimation("Attack" + comboSm.main.GetCurrentNodeName()); } } } public override void OnPrimaryRelease() { if (_isHoldingAttack) { string animName = player.animationSc.fullBodyFuncAnimSm.currentRuntimeFuncAnim?.animationName; if(animName == "HoldAttackLoop" || animName == "HoldAttackStart") { PlayTargetedAnimation("HoldAttackEnd"); } } _isHoldingAttack = false; } public override void OnSecondaryPress() { if (_isHoldingAttack) return; if (functionSm["HeavyAttack"].IsAvailable() && fullBodyFuncAnimSm.CheckPlayability()) { comboSm.main.NextCombo("R"); functionSm["HeavyAttack"].Execute(); currentTarget = CombatManager.EnemySm.GetNearestEnemy(25f); if (currentTarget != null) { PlayTargetedAnimation("Attack" + comboSm.main.GetCurrentNodeName(), currentTarget, 5f); } else { PlayTargetedAnimation("Attack" + comboSm.main.GetCurrentNodeName()); } } } } public partial class FutureWand { private void FAPF_GenerateBoltOnWand(RuntimeFuncAnim rtFuncAnim) { CustomFunction.PC_StringStringFloat p = rtFuncAnim.GetParams(); GenerateProjectile(p.str0, attackData[p.str1], currentTarget, p.float0); } private void FAPF_GenerateBoltOnHand(RuntimeFuncAnim rtFuncAnim) { CustomFunction.PC_StringStringFloat p = rtFuncAnim.GetParams(); GenerateProjectile(p.str0, attackData[p.str1], currentTarget, p.float0, true, player.bodyPartsSc.leftHand); } private void FAPF_GenerateUltimateBeam(RuntimeFuncAnim rtFuncAnim) { CustomFunction.PC_StringString p = rtFuncAnim.GetParams(); GenerateUltimateBeam(p.str0, attackData[p.str1]); } private void FAPF_GenerateGroundArea(RuntimeFuncAnim rtFuncAnim) { CustomFunction.PC_StringString p = rtFuncAnim.GetParams(); GenerateGroundArea(p.str0, attackData[p.str1]); } private void FAPF_GenerateMultipleBolts(RuntimeFuncAnim rtFuncAnim) { CustomFunction.PC_StringStringFloat p = rtFuncAnim.GetParams(); List targets = CombatManager.EnemySm.GetEnemiesInRadius(player.transform.position, 25f); if (targets.Count > 0) vfxData.SpawnMuzzleVFX(p.str0, player, muzzle); foreach (Enemy target in targets) { GenerateProjectile(p.str0, attackData[p.str1], target, p.float0, false); } } } public partial class FutureWand { private Transform muzzle => viewObjects["Wand"].functionalParts["Muzzle"].transform; } public partial class FutureWand { private void GenerateProjectile(string vfxName, AttackUnit attackUnit, CharacterBase target, float speed, bool hasMuzzleEffect = true, Transform muzzle = null) { if (hasMuzzleEffect) { muzzle ??= this.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) .SetHitSubmodule() .SetAdaptiveTraceMoveModule(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(1f); AudioManager.Post(AK.EVENTS.FUTUREWAND_NORMALBOLTRELEASE, projectile.gameObject); } else if (vfxName == "CubicBolt") { projectile.hitSm.AddHitSound(AK.EVENTS.FUTUREWAND_MEDIUMATTACKHIT); projectile.SetImpulseSubmodule().WithDynamicForce(2f); AudioManager.Post(AK.EVENTS.FUTUREWAND_CUBICBOLTRELEASE, projectile.gameObject); } int fusionStack = attackUnit.GetSubmodule().GetParameter("Buff_Fusion_Stack"); projectile.hitSm.AddHitEvent((enemy, hitPosition) => { new Fusion(fusionStack).Apply(enemy); SubscribeFusionExplode(enemy); if (!projectile.tags.Contains("Separation") && HasExtender()) { List nearbyEnemies = CombatManager.EnemySm.GetEnemiesInRadius(hitPosition, 25f).Exclude(enemy as Enemy); if (nearbyEnemies.Count > 0) { Projectile separation = vfxData.SpawnVFX(vfxName, player, hitPosition, Quaternion.identity).GetComponentInChildren(); nearbyEnemies.TryGetRandom(out Enemy randomTarget); Vector3 sepDirection = (randomTarget.centerPoint.position - hitPosition).normalized; separation.Initialize(player, this, false, 1, Fraction.Enemy) .SetAttackSubmodule(attackUnit) .SetTimeSubmodule(10f) .SetHitSubmodule() .SetLinearDirectionMoveModule(sepDirection, speed, 5f); separation.tags.Add("Separation"); separation.hitSm.AddCheckedObject(enemy.gameObject); separation.SetRaycastSubmodule(default, 0.25f, 0.5f); } } }); } 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 (!HasExtender()) { 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) .SetAttackSubmodule(attackUnit) .SetTimeSubmodule(3f, 0.1f, 0.9f) .SetHitSubmodule(0.1f, 8) .SetLinearDirectionMoveModule(player.transform.forward, 25f, -50f, false, false, false); } area.SetImpulseSubmodule().WithSuction(4f); area.hitSm.AddHitSound(AK.EVENTS.FUTUREWAND_WEAKATTACKHIT); int fusionStack = attackUnit.GetSubmodule().GetParameter("Buff_Fusion_Stack"); area.hitSm.AddHitEvent((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) .SetHitSubmodule(); area.SetImpulseSubmodule().WithCustomForce(player.transform.forward * 10f); area.hitSm.AddHitSound(AK.EVENTS.FUTUREWAND_MEDIUMATTACKHIT); AudioManager.Post(AK.EVENTS.FUTUREWAND_ULTIMATEBEAMPOWERUP, area.gameObject); area.timeSm.AddScheduleAction(() => { AudioManager.Post(AK.EVENTS.FUTUREWAND_ULTIMATEBEAMSHOOT); feedbackSc.PlayFeedback("UltimateBeamShoot"); }, 0f); } private void GenerateSquareExpandingAura(string vfxName) { vfxData.SpawnMuzzleVFX(vfxName, player, muzzle); NormalArea area = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren(); area.Initialize(player, this, Fraction.Enemy) .SetAttackSubmodule(attackData["SquareAura"]) .SetTimeSubmodule(4f, 0.2f, 2.8f) .SetHitSubmodule() .SetTransformSubmodule(); //audioContainer.PlaySoundFX("SquareAura", area.gameObject, true); area.transformSm.ApplyScaleMove(Vector3.one, Vector3.one * 50, 1f, EaseType.OutQuart); 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(); } }; } } public partial class FutureWand { private const string FUSION_EXPLODE_KEY = nameof(FutureWand); /// /// 订阅目标身上 Fusion Buff 的引爆事件,当引爆来源为 FutureWand 时执行专属效果。 /// 字典 Key 天然去重,无需手动 -= +=。 /// private void SubscribeFusionExplode(CharacterBase enemy) { Fusion fusion = enemy.buffSm.GetBuff(); if (fusion == null) return; fusion.onExploded[FUSION_EXPLODE_KEY] = new PrioritizedAction(OnFusionExploded); } private void OnFusionExploded(Fusion fusion, AttackAreaBase triggerArea) { if (triggerArea == null || triggerArea.itemSource != this) return; new Decay(50).Apply(fusion.attachedCharacter); } } }