| 
									
										
										
										
											2025-10-26 15:46:04 +08:00
										 |  |  |  | using Level.Role; | 
					
						
							|  |  |  |  | using UnrealSharp; | 
					
						
							|  |  |  |  | using UnrealSharp.Attributes; | 
					
						
							|  |  |  |  | using UnrealSharp.BusyRabbit; | 
					
						
							|  |  |  |  | using UnrealSharp.CoreUObject; | 
					
						
							|  |  |  |  | using UnrealSharp.Engine; | 
					
						
							|  |  |  |  | using UnrealSharp.GameplayAbilities; | 
					
						
							|  |  |  |  | using UnrealSharp.GameplayTags; | 
					
						
							|  |  |  |  | using UnrealSharp.SpinePlugin; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | namespace GameAbilitySystem.Ability.Role.Fox; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | [UClass] | 
					
						
							|  |  |  |  | public class UFoxUltimate : UBusyGameAbility | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     protected bool bIsEventBinded = false; | 
					
						
							|  |  |  |  |     protected ABusyFoxRole? Owner = null; | 
					
						
							|  |  |  |  |     protected UFoxUltimateDataAsset? FoxData = null; | 
					
						
							|  |  |  |  |     protected UBusyAbilitySystemComponent? ASC = null; | 
					
						
							|  |  |  |  |     protected FActiveGameplayEffectHandle CastStateHandle; | 
					
						
							|  |  |  |  |     protected FActiveGameplayEffectHandle SkillStateHandle; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     protected FActiveGameplayEffectHandle AccelerateHandle;  // 大招移动速度增加的Effect | 
					
						
							|  |  |  |  |     protected FActiveGameplayEffectHandle SprintHandle;      // 大招三阶移速再次增加的Effect | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     [UFunction()] | 
					
						
							|  |  |  |  |     protected void OnGamePlayTagAddOrRemove(FGameplayTag tag, int isAdd) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         if (isAdd == 0 && !IsActive) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             CommitAbilityCooldown(); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /// <summary> | 
					
						
							|  |  |  |  |     /// 初始化技能依赖的属性 | 
					
						
							|  |  |  |  |     /// </summary> | 
					
						
							|  |  |  |  |     /// <returns>false->初始化失败</returns> | 
					
						
							|  |  |  |  |     protected bool InitAbilityOnce() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         Owner = OwningActorFromActorInfo as ABusyFoxRole; | 
					
						
							|  |  |  |  |         if (Owner == null) return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         FoxData = Data as UFoxUltimateDataAsset; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         ASC = AbilitySystemLibrary.GetAbilitySystemComponent(Owner) as UBusyAbilitySystemComponent; | 
					
						
							|  |  |  |  |         if (FoxData == null || ASC == null) return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (bIsEventBinded) return true; | 
					
						
							|  |  |  |  |         TDelegate<GameplayTagAddOrRemoveDelegate> Delegate = new TDelegate<GameplayTagAddOrRemoveDelegate>(); | 
					
						
							|  |  |  |  |         Delegate.BindUFunction(this, "OnGamePlayTagAddOrRemove"); | 
					
						
							|  |  |  |  |         Owner.BindGameplayTagAddOrRemove(FoxData.SecondStageCastTag, Delegate); | 
					
						
							|  |  |  |  |         Owner.BindGameplayTagAddOrRemove(FoxData.LastStageCastTag, Delegate); | 
					
						
							|  |  |  |  |         bIsEventBinded = true; | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /// <summary> | 
					
						
							|  |  |  |  |     /// 获取当前大招的阶段 | 
					
						
							|  |  |  |  |     /// </summary> | 
					
						
							|  |  |  |  |     /// <returns></returns> | 
					
						
							|  |  |  |  |     protected int GetCurrentAbilityStage() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         if (ASC == null || FoxData == null) return 0; | 
					
						
							|  |  |  |  |         if (ASC.HasMatchingGameplayTag(FoxData.LastStageCastTag)) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             return 3; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         if (ASC.HasMatchingGameplayTag(FoxData.SecondStageCastTag)) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             return 2; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         else if (ASC.HasMatchingGameplayTag(FoxData.FirstStageCastTag)) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             return 1; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return 0; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     protected override void ActivateAbilityFromEvent(FGameplayEventData eventData) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         base.ActivateAbilityFromEvent(eventData); | 
					
						
							|  |  |  |  |         if (!InitAbilityOnce()) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             EndAbility(); | 
					
						
							|  |  |  |  |             return; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (Owner == null || !CommitAbilityCost(Owner)) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             EndAbility(); | 
					
						
							|  |  |  |  |             return; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         int stage = GetCurrentAbilityStage(); | 
					
						
							|  |  |  |  |         if (stage != 0) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             TriggerAbility(stage); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         else | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             EndAbility(); | 
					
						
							|  |  |  |  |             return; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /// <summary> | 
					
						
							|  |  |  |  |     /// 当被授予技能时,立刻获得可释放第一段大招的常驻Tag | 
					
						
							|  |  |  |  |     /// </summary> | 
					
						
							|  |  |  |  |     /// <param name="actorInfo"></param> | 
					
						
							|  |  |  |  |     /// <param name="spec"></param> | 
					
						
							|  |  |  |  |     public override void OnGiveAbility(FGameplayAbilityActorInfo actorInfo, FGameplayAbilitySpec spec) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         base.OnGiveAbility(actorInfo, spec); | 
					
						
							|  |  |  |  |         InitAbilityOnce(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (FoxData == null || ASC == null) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         UBusyGameplayEffectSubSystem EffectSubSystem = GetGameInstanceSubsystem<UBusyGameplayEffectSubSystem>(); | 
					
						
							|  |  |  |  |         if (EffectSubSystem == null) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         UGameplayEffect effect = EffectSubSystem.GetTagGrantEffectWithDuration( | 
					
						
							|  |  |  |  |             new FGameplayTagContainer(FoxData.FirstStageCastTag), | 
					
						
							|  |  |  |  |             new FGameplayTagContainer(), 0 | 
					
						
							|  |  |  |  |         ); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         FGameplayEffectSpecHandle handle = UBusyAscLibrary.MakeGameplayEffectSpecHandle(ASC, effect, 1); | 
					
						
							|  |  |  |  |         ASC.ApplyGameplayEffectSpecToSelf(handle); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     protected bool ApplayCastEffect(FGameplayTag CastTag) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         UBusyGameplayEffectSubSystem EffectSubSystem = GetGameInstanceSubsystem<UBusyGameplayEffectSubSystem>(); | 
					
						
							|  |  |  |  |         if (ASC == null || EffectSubSystem == null || FoxData == null) return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         ASC.RemoveActiveGameplayEffect(CastStateHandle); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (CastTag.IsValid) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             UGameplayEffect cast_effect = EffectSubSystem.GetTagGrantEffectWithDuration( | 
					
						
							|  |  |  |  |                 new FGameplayTagContainer(CastTag), | 
					
						
							|  |  |  |  |                 new FGameplayTagContainer(), FoxData.RecastWindow | 
					
						
							|  |  |  |  |             ); | 
					
						
							|  |  |  |  |             FGameplayEffectSpecHandle CastSpecHandle = UBusyAscLibrary.MakeGameplayEffectSpecHandle(ASC, cast_effect, 1); | 
					
						
							|  |  |  |  |             CastStateHandle = ASC.ApplyGameplayEffectSpecToSelf(CastSpecHandle); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     protected bool ApplyEffect(FGameplayTag stateTag, FGameplayTag CastTag) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         UBusyGameplayEffectSubSystem EffectSubSystem = GetGameInstanceSubsystem<UBusyGameplayEffectSubSystem>(); | 
					
						
							|  |  |  |  |         if (ASC == null || EffectSubSystem == null || FoxData == null) return false; | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         ApplayCastEffect(CastTag); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         ASC.RemoveActiveGameplayEffect(SkillStateHandle); | 
					
						
							|  |  |  |  |         UGameplayEffect state_effect = EffectSubSystem.GetTagGrantEffectWithDuration( | 
					
						
							|  |  |  |  |             new FGameplayTagContainer(stateTag), | 
					
						
							|  |  |  |  |             new FGameplayTagContainer(), 0 | 
					
						
							|  |  |  |  |         ); | 
					
						
							|  |  |  |  |         FGameplayEffectSpecHandle stateSpecHandle = UBusyAscLibrary.MakeGameplayEffectSpecHandle(ASC, state_effect, 1); | 
					
						
							|  |  |  |  |         SkillStateHandle = ASC.ApplyGameplayEffectSpecToSelf(stateSpecHandle); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     protected bool TriggerAbility(int stage) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         if (FoxData == null) return false; | 
					
						
							|  |  |  |  |         if (stage == 1) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             if (!ApplyEffect(FoxData.FirstStageTag, FoxData.SecondStageCastTag)) return false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         else if (stage == 2) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             if (!ApplyEffect(FoxData.SecondStageTag, new FGameplayTag())) return false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         else if(stage == 3) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             if (!ApplyEffect(FoxData.LastStageTag, new FGameplayTag())) return false; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         PlayAnimation(stage); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     protected string GetAnimationName(FVector2D direction, int stage) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         string animation_name_prefix = ""; | 
					
						
							|  |  |  |  |         if (direction.X >= 0) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             animation_name_prefix = "Ultimate/Right/"; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         else | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             animation_name_prefix = "Ultimate/Left/"; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (stage == 1) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             return animation_name_prefix + "UltimateStage1"; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         else if (stage == 2) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             return animation_name_prefix + "UltimateStage2"; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         else if (stage == 3) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             return animation_name_prefix + "UltimateStage3"; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return ""; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     [UFunction()] | 
					
						
							|  |  |  |  |     protected void OnAnimationComplete(UTrackEntry Entry) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         Entry.AnimationComplete.Remove(OnAnimationComplete); | 
					
						
							|  |  |  |  |         if (ASC != null) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             if (ASC.HasMatchingGameplayTag(FoxData.LastStageTag)) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 CommitAbilityCooldown(); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             ASC.RemoveActiveGameplayEffect(SkillStateHandle); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         EndAbility(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     [UFunction()] | 
					
						
							|  |  |  |  |     protected void OnTailBeginOverlay(UPrimitiveComponent OverlappedComponent, AActor OtherActor, | 
					
						
							|  |  |  |  |         UPrimitiveComponent OtherComp, int OtherBodyIndex, bool bFromSweep, FHitResult SweepResult) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         if (ASC == null || FoxData == null) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         bool bIsStage2 = ASC.HasMatchingGameplayTag(FoxData.SecondStageTag); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (bIsStage2 && !ASC.HasMatchingGameplayTag(FoxData.LastStageCastTag)) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             ApplayCastEffect(FoxData.LastStageCastTag); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     [UFunction()] | 
					
						
							|  |  |  |  |     protected void OnAnimationEvent(UTrackEntry Entry, FSpineEvent Event) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         if (ASC == null || FoxData == null || Owner == null) return; | 
					
						
							|  |  |  |  |         if (Event.Name == "OnSpeedChange") | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             AccelerateHandle = MakeAccelerate(FoxData.LastStageSprintSpeedFactor, 1); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         else if (Event.Name == "OnSpeedReset") | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             ASC.RemoveActiveGameplayEffect(AccelerateHandle); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         else if (Event.Name == "OnDamageBegin") | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             Owner.SetTailCollisionEnabled(true); | 
					
						
							|  |  |  |  |             Owner.FoxTailCollision.OnComponentBeginOverlap.Add(OnTailBeginOverlay); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         else if (Event.Name == "OnDamageEnd") | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             Owner.SetTailCollisionEnabled(false); | 
					
						
							|  |  |  |  |             Owner.FoxTailCollision.OnComponentBeginOverlap.Remove(OnTailBeginOverlay); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     protected FActiveGameplayEffectHandle MakeAccelerate(float SpeedFactor, float TotalTime) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         GetAbilityEffectSpecHandle("Accelerate", ASC, 1, out FGameplayEffectSpecHandle handle); | 
					
						
							|  |  |  |  |         AbilitySystemLibrary.AssignTagSetByCallerMagnitude( | 
					
						
							|  |  |  |  |             handle, UBusyGameplayLibrary.RequestGameplayTag("Effect.Factor"),  SpeedFactor | 
					
						
							|  |  |  |  |         ); | 
					
						
							|  |  |  |  |         AbilitySystemLibrary.AssignTagSetByCallerMagnitude( | 
					
						
							|  |  |  |  |             handle, UBusyGameplayLibrary.RequestGameplayTag("Effect.Duration"), TotalTime | 
					
						
							|  |  |  |  |         ); | 
					
						
							|  |  |  |  |         return ApplyGameplayEffectSpecToOwner(handle); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     protected bool PlayAnimation(int stage) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         FVector2D AbilityDirection = new FVector2D(0, 1); | 
					
						
							|  |  |  |  |         if (UGameplayStatics.GetPlayerController(0) is ALevelPlayerController PC) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             PC.GetCursorDirection(out AbilityDirection); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         string AnimationName = GetAnimationName(AbilityDirection, stage); | 
					
						
							|  |  |  |  |         if (AnimationName == "") return false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         USpineSkeletonAnimationComponent Animation = Owner.SpineAnimationComponent; | 
					
						
							|  |  |  |  |         UTrackEntry AnimEntry = Animation.SetAnimation(0, AnimationName, false); | 
					
						
							|  |  |  |  |         AnimEntry.AnimationEvent.Add(OnAnimationEvent); | 
					
						
							|  |  |  |  |         AnimEntry.AnimationComplete.Add(OnAnimationComplete); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         float TotalTime = AnimEntry.GetAnimationEnd(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (stage == 1) MakeAccelerate(FoxData.FirstStageSpeedFactor, TotalTime); | 
					
						
							|  |  |  |  |         else if (stage == 2) MakeAccelerate(FoxData.SecondStageSpeedFactor, TotalTime); | 
					
						
							|  |  |  |  |         else if (stage == 3) MakeAccelerate(FoxData.LastStageNormalSpeedFactor, TotalTime); | 
					
						
							|  |  |  |  |         Owner.MovementComponent.ActivateSprint(AbilityDirection, TotalTime); | 
					
						
							|  |  |  |  |         return true; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-10-25 05:53:20 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | // function FoxUltimate:ctor() | 
					
						
							|  |  |  |  | //     self.ultimate_phase = 1  -- 大招阶段 | 
					
						
							|  |  |  |  | //     self.active_recast_handle = nil | 
					
						
							|  |  |  |  | //     self.active_accelerate_handle = nil | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | //     self.overlap_delegate_handle = nil | 
					
						
							|  |  |  |  | //     self.tag_add_or_remove_delegate = nil | 
					
						
							|  |  |  |  | // end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // function FoxUltimate:OnAnimationComplete(entry) | 
					
						
							|  |  |  |  | //     local new_phase = self.ultimate_phase + 1 | 
					
						
							|  |  |  |  | //     if new_phase > 3 then | 
					
						
							|  |  |  |  | //         self.ultimate_phase = 1 | 
					
						
							|  |  |  |  | //     else | 
					
						
							|  |  |  |  | //         self.ultimate_phase = new_phase | 
					
						
							|  |  |  |  | //     end | 
					
						
							|  |  |  |  | //     print("FoxUltimate:OnAnimationComplete", self.ultimate_phase) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | //     if not self.asc:HasMatchingGameplayTag(self.recast_tag) then | 
					
						
							|  |  |  |  | //         self.ultimate_phase = 1 | 
					
						
							|  |  |  |  | //         self:K2_CommitAbilityCooldown(false, false) | 
					
						
							|  |  |  |  | //     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | //     entry.AnimationComplete:Clear() | 
					
						
							|  |  |  |  | //     entry.AnimationEvent:Clear() | 
					
						
							|  |  |  |  | //     self:K2_EndAbility() | 
					
						
							|  |  |  |  | // end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 |