326 lines
9.6 KiB
C++
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;
|
|
} |