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(); } } /// /// 初始化技能依赖的属性 /// /// false->初始化失败 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; PrintString("asdafdasdf"); if (bIsEventBinded) return true; TDelegate Delegate = new TDelegate(); Delegate.BindUFunction(this, "OnGamePlayTagAddOrRemove"); Owner.BindGameplayTagAddOrRemove(FoxData.SecondStageCastTag, Delegate); Owner.BindGameplayTagAddOrRemove(FoxData.LastStageCastTag, Delegate); bIsEventBinded = true; return true; } /// /// 获取当前大招的阶段 /// /// 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; } } /// /// 当被授予技能时,立刻获得可释放第一段大招的常驻Tag /// /// /// public override void OnGiveAbility(FGameplayAbilityActorInfo actorInfo, FGameplayAbilitySpec spec) { base.OnGiveAbility(actorInfo, spec); InitAbilityOnce(); if (FoxData == null || ASC == null) return; UBusyGameplayEffectSubSystem EffectSubSystem = GetGameInstanceSubsystem(); 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(); 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(); 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; } } // 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