haxis/Source/UnrealProject/Abilities/BlueprintAbilityLibrary.cpp

326 lines
9.6 KiB
C++

#include "UnrealProject.h"
#include "BlueprintAbilityLibrary.h"
#include "DealDamageProxy.h"
#include "AbilityEventGroup.h"
#include "AbilityTriggerBase.h"
#include "Modifier.h"
#include "NetworkCharacter.h"
#include "ProjectileBase.h"
#include "Class.h"
ULib::ULib(const FObjectInitializer& init)
: Super(init)
{
}
AActor* ULib::BeginSpawning2(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass)
{
return UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, FTransform());
}
AActor* ULib::FinishSpawning2(class AActor* Actor)
{
if(!Actor)
return nullptr;
return UGameplayStatics::FinishSpawningActor(Actor, FTransform());
}
AActor* ULib::BeginSpawningGroup(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass)
{
if(!WorldContextObject->GetWorld()->GetAuthGameMode())
return nullptr;
AActor* actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, FTransform());
if(!actor)
return nullptr;
AAbilityEventGroup* newGroup = Cast<AAbilityEventGroup>(actor);
check(newGroup);
AAbilityEventGroup* parent = Cast<AAbilityEventGroup>(WorldContextObject);
//GWPRINT(L"Parent = " + parent);
if(!parent)
{
GWERROR(L"Cannot call FinishSpawningGroup from any other source than AAbilityEventGroup");
newGroup->Destroy();
return nullptr;
}
parent->TransitionTo(newGroup);
return newGroup;
}
AActor* ULib::FinishSpawningGroup(class AActor* Actor)
{
if(!Actor)
return nullptr;
return FinishSpawning2(Actor);
}
AActor* ULib::BeginSpawningModifier(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass)
{
if(!WorldContextObject->GetWorld()->GetAuthGameMode())
return nullptr;
AActor* actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, FTransform());
if(!actor)
return nullptr;
AModifier* newModifier = Cast<AModifier>(actor);
check(newModifier);
ADealDamageProxy* damageProxy = Cast<ADealDamageProxy>(WorldContextObject);
if(damageProxy)
{
newModifier->character = damageProxy->character;
newModifier->abilityInfo = damageProxy->abilityInfo;
}
else
{
GWERROR(L"Cannot spawn modifier from a source that is not a ADealDamageProxy");
newModifier->Destroy();
return nullptr;
}
return newModifier;
}
AActor* ULib::FinishSpawningModifier(class AActor* Actor, class ANetworkCharacter* target)
{
if(!IsValid(Actor))
return nullptr;
AModifier* mod = Cast<AModifier>(Actor);
if(!IsValid(target))
{
FString name = "<none>";
if(mod->abilityInfo)
name = mod->abilityInfo->GetName();
GWERROR(L"Modifier needs a target (spawned by " + name + L")");
Actor->Destroy();
return nullptr;
}
//GWPRINT(L"Modifier Target = " + target);
ModifierManager* mm = target->GetModifierManager();
if(!mm)
{
GWWARNING(L"Can't spawn modifier on a target that doesn't have a modifier manager. Might be in the process of destroying");
Actor->Destroy();
return nullptr;
}
mod->target = target;
check(mod);
mm->AddModifier(mod);
return FinishSpawning2(Actor);
}
AActor* ULib::BeginSpawningTrigger(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass, const FTransform& SpawnTransform)
{
if(!WorldContextObject->GetWorld()->GetAuthGameMode())
return nullptr;
AActor* actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, SpawnTransform);
if(!actor)
return nullptr;
AAbilityTriggerBase* newTrigger = Cast<AAbilityTriggerBase>(actor);
check(newTrigger);
ADealDamageProxy* damageProxy = Cast<ADealDamageProxy>(WorldContextObject);
if(damageProxy)
{
newTrigger->character = damageProxy->character;
newTrigger->abilityInfo = damageProxy->abilityInfo;
}
else
{
GWERROR(L"Cannot spawn trigger from a source that is not a ADealDamageProxy");
actor->Destroy();
return nullptr;
}
return newTrigger;
}
AActor* ULib::FinishSpawningTrigger(class AActor* Actor, const FTransform & SpawnTransform)
{
if(!Actor)
return nullptr;
return UGameplayStatics::FinishSpawningActor(Actor, SpawnTransform);
}
AActor* ULib::BeginSpawningProjectile(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass, const FTransform& SpawnTransform)
{
if(!WorldContextObject->GetWorld()->GetAuthGameMode())
return nullptr;
AActor* actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, SpawnTransform);
if(!actor)
return nullptr;
AProjectileBase* newProjectile = Cast<AProjectileBase>(actor);
check(newProjectile);
ADealDamageProxy* damageProxy = Cast<ADealDamageProxy>(WorldContextObject);
if(damageProxy)
{
newProjectile->character = damageProxy->character;
newProjectile->abilityInfo = damageProxy->abilityInfo;
}
else
{
GWERROR(L"Cannot spawn projectile from a source that is not a ADealDamageProxy");
actor->Destroy();
return nullptr;
}
return newProjectile;
}
AActor* ULib::FinishSpawningProjectile(class AActor* Actor, const FTransform& SpawnTransform)
{
return UGameplayStatics::FinishSpawningActor(Actor, SpawnTransform);
}
bool ULib::IsContainedInCone(FVector origin, FVector forward, float coneAngle, AActor* other)
{
if(other->IsPendingKillPending())
return false;
//always hits at 360 degrees
if(coneAngle >= 360.0f)
return true;
FVector dist = other->GetActorLocation() - origin;
dist.Normalize();
forward.Normalize();
float dot = FVector::DotProduct(dist, forward);
float angle = acosf(dot);
float tempMaxAngle = coneAngle / 360;
tempMaxAngle *= PI;
bool ret = tempMaxAngle > angle;
return ret;
}
int32 ULib::CharacterConeOverlap(UObject* WorldContextObject, FVector origin, float coneRadius,
FCharacterConeOverlapCallback callback, FVector forward, float coneAngle, EAbilityFilter filter)
{
UWorld* world = GEngine->GetWorldFromContextObject(WorldContextObject);
check(world);
if(world->GetAuthGameMode() == nullptr)
return 0;
m_overlapResultArray.Empty();
// Get the character
ANetworkCharacter* character = Cast<ANetworkCharacter>(WorldContextObject);
if(!character)
{
ADealDamageProxy* proxy = Cast<ADealDamageProxy>(WorldContextObject);
if(!proxy)
{
GWERROR(L"CharacterConeOverlap failed, no caller character or proxy");
return 0;
}
character = proxy->character;
}
FCollisionShape shape;
shape.SetCapsule(coneRadius, 400.0f);
TArray<FOverlapResult> overlaps;
if(!world->OverlapMultiByObjectType(
overlaps, origin, FQuat::Identity,
FCollisionObjectQueryParams::AllDynamicObjects, shape,
FCollisionQueryParams::DefaultQueryParam))
{
return 0;
}
TArray<class ANetworkCharacter*> test;
if(callback.IsBound())
{
for(int32 i = 0; i < overlaps.Num(); i++)
{
FOverlapResult& overlap = overlaps[i];
ANetworkCharacter* target = Cast<ANetworkCharacter>(overlap.GetActor());
if (target && (overlap.Component->GetCollisionProfileName() == FName("Units") || overlap.Component->GetCollisionProfileName() == FName("Players")) &&
IsContainedInCone(origin, forward, coneAngle, target) &&
ULib::CheckAbilityFilter(filter, character, target))
{
callback.Execute(target);
m_overlapResultArray.Add(target);
}
}
}
// = test;
return overlaps.Num();
}
int32 ULib::ClosestCharacterConeOverlap(UObject* WorldContextObject, FVector origin, float coneRadius,
FClosestCharacterConeOverlapCallback callback, FVector forward, float coneAngle, EAbilityFilter filter)
{
UWorld* world = GEngine->GetWorldFromContextObject(WorldContextObject);
check(world);
if (world->GetAuthGameMode() == nullptr)
return 0;
// Get the character
ANetworkCharacter* character = Cast<ANetworkCharacter>(WorldContextObject);
if (!character)
{
ADealDamageProxy* proxy = Cast<ADealDamageProxy>(WorldContextObject);
if (!proxy)
{
GWERROR(L"CharacterConeOverlap failed, no caller character or proxy");
return 0;
}
character = proxy->character;
}
FCollisionShape shape;
shape.SetCapsule(coneRadius, 400.0f);
TArray<FOverlapResult> overlaps;
if (!world->OverlapMultiByObjectType(
overlaps, origin, FQuat::Identity,
FCollisionObjectQueryParams::AllDynamicObjects, shape,
FCollisionQueryParams::DefaultQueryParam))
{
return 0;
}
ANetworkCharacter* closest = nullptr;
float dist = 9999999999999.0f;
if (callback.IsBound())
{
for (int32 i = 0; i < overlaps.Num(); i++)
{
FOverlapResult& overlap = overlaps[i];
ANetworkCharacter* target = Cast<ANetworkCharacter>(overlap.GetActor());
if (target && IsContainedInCone(origin, forward, coneAngle, target) && ULib::CheckAbilityFilter(filter, character, target))
{
if ((target->GetActorLocation() - origin).Size() < dist)
{
closest = target;
dist = (target->GetActorLocation() - origin).Size();
}
}
}
}
if(closest)
callback.Execute(closest);
return overlaps.Num();
}
TArray<ANetworkCharacter*> ULib::m_overlapResultArray;
bool ULib::CheckAbilityFilter(EAbilityFilter filter, class ANetworkCharacter* self, class ANetworkCharacter* other)
{
if(!self)
return false;
if(!other)
return false;
if(((uint8)filter & ABILITY_FILTER_ENEMY) != 0)
{
if(self->GetTeam() != other->GetTeam())
return true;
}
if(((uint8)filter & ABILITY_FILTER_ALLY) != 0)
{
if(self->GetTeam() == other->GetTeam())
return true;
}
return false;
}
TArray<ANetworkCharacter*>ULib::GetCharacterOverlaps()
{
TArray<ANetworkCharacter*> returnArray;
for (ANetworkCharacter* character : m_overlapResultArray)
{
if(IsValid(character))
returnArray.Add(character);
}
return returnArray;
}