// Project Lab - NHTV Igad #include "UnrealProject.h" #include "AbilityEventGroup.h" #include "NetworkCharacter.h" #include "NPCBase.h" AAbilityEventGroup::AAbilityEventGroup() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; channelEvent = false; stunWhileChannel = true; progressionType = EAbilityEventGroupProgressionType::Continue; duration = 1.0f; m_endEventSend = false; m_hasBeenDestroyed = false; allowRotateWhileChannel = false; } void AAbilityEventGroup::BeginPlay() { check(Role == ROLE_Authority); Super::BeginPlay(); m_life = 0.0f; if(!character || character->IsActorBeingDestroyed()) { m_MoveToNextGroup(); } else { // Handle the destruction of the caster character->OnDestroyed.AddDynamic(this, &AAbilityEventGroup::m_OnCharacterDestroyed); } } void AAbilityEventGroup::EndPlay(const EEndPlayReason::Type EndPlayReason) { check(Role == ROLE_Authority); if(EndPlayReason == EEndPlayReason::Destroyed) { Super::EndPlay(EndPlayReason); AAbilityEventGroup* nextGroup = nullptr; if(m_nextGroups.Num() > 0) { //GWPRINT(L"Move next"); nextGroup = SpawnSequence(character, abilityInfo, abilityState, m_nextGroups); } m_SendEndEvent(nextGroup); } } void AAbilityEventGroup::Tick(float DeltaTime) { Super::Tick(DeltaTime); if(IsPendingKill()) return; m_life += DeltaTime; if(progressionType == EAbilityEventGroupProgressionType::Continue) { if(m_life >= duration || m_continue) m_MoveToNextGroup(); } else { if(m_continue) m_MoveToNextGroup(); } } void AAbilityEventGroup::m_OnCharacterDestroyed() { m_MoveToNextGroup(); } void AAbilityEventGroup::m_MoveToNextGroup() { if(m_hasBeenDestroyed) return; m_hasBeenDestroyed = true; if(IsValid(this) && !IsPendingKillPending()) Destroy(); } void AAbilityEventGroup::m_SendEndEvent(AAbilityEventGroup* next) { if(!m_endEventSend) { onAbilityEventGroupEnded.Broadcast(abilityInfo, this, next); m_endEventSend = true; } } void AAbilityEventGroup::Interrupt() { //GPRINT("Interrupting ability"); if(IsPendingKill()) return; m_nextGroups.Empty(); // Don't execute any follow up events m_hasBeenDestroyed = true; } void AAbilityEventGroup::TransitionTo(class AAbilityEventGroup* newGroup) { check(newGroup); check(abilityInfo); check(abilityState); newGroup->character = character; newGroup->abilityInfo = abilityInfo; newGroup->abilityState = abilityState; newGroup->m_nextGroups = m_nextGroups; m_nextGroups.Empty(); m_SendEndEvent(newGroup); //GWPRINT(L"TransitionTo next"); m_MoveToNextGroup(); } void AAbilityEventGroup::NextGroup() { m_continue = true; } ANetworkCharacter* AAbilityEventGroup::GetTarget() { ANPCBase* creature = Cast(character); if(creature) { return creature->target; } return nullptr; } float AAbilityEventGroup::GetLifetimeRate() const { float rate = m_life / duration; return FMath::Fmod(rate, 1.0f + FLT_EPSILON); } float AAbilityEventGroup::GetLifetime() const { return m_life; } AAbilityEventGroup* AAbilityEventGroup::SpawnSequence(ANetworkCharacter* character, class UAbilityInfo* abilityInfo, class AAbilityState* abilityState, TArray> groups) { UWorld* world = character->GetWorld(); check(world); check(groups.Num() > 0); AAbilityEventGroup* group = world->SpawnActorDeferred(groups[0], FTransform::Identity); check(group); check(abilityInfo); check(abilityState); group->character = character; group->abilityState = abilityState; group->abilityInfo = abilityInfo; groups.RemoveAt(0); group->m_nextGroups = groups; UGameplayStatics::FinishSpawningActor(group, FTransform::Identity); return group; }