haxis/Source/UnrealProject/Spawners/PatrolSpawn.cpp

259 lines
6.7 KiB
C++

// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "PatrolSpawn.h"
#include "NPCBase.h"
#include "DefaultGameMode.h"
#include "NetworkPlayer.h"
APatrolSpawn::APatrolSpawn()
{
respawnTime = 5;
m_respawnTimer = 0;
spawnContinuous = true;
}
void APatrolSpawn::BeginPlay()
{
Super::BeginPlay();
if (Role != ROLE_Authority)
return;
FName name;
if (aggroRadius < 0) aggroRadius = 0;
if (respawnTime < 0) respawnTime = 0;
if (spawns.Num() == 0)
{
JWARNING("Empty spawner in scene");
return;
}
for (int i = 0; i < controlPoints.Num(); i++)
m_controlPoints.Add(FVector(controlPoints[i].X + this->GetActorLocation().X, controlPoints[i].Y + this->GetActorLocation().Y, this->GetActorLocation().Z));
m_controlPointSign = 1;
m_isPulled = false;
m_currentControlPoint = 0;
m_lastPosition = GetActorLocation();
//SpawnMobs();
}
void APatrolSpawn::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
}
void APatrolSpawn::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (Role != ROLE_Authority)
return;
UWorld* const world = GetWorld();
if (!world) return;
check(m_mobs.Num() == spawns.Num());
m_respawnTimer = m_respawnTimer > 0 ? (m_respawnTimer - DeltaTime) : 0;
if (m_respawnTimer <= 0 && m_mobCount != m_mobs.Num() && spawnContinuous)
m_RespawnMobs();
if (m_mobs.Num() == 0)
return;
// Respawn the mobs
/* if (spawnContinuous)
m_RespawnMobs();*/
if (m_controlPoints.Num() <= 0)
{
RWARNING("There are no control points");
return;
}
bool anyIdle = false;
for (int32 i = 0; i < spawns.Num(); i++)
{
if (!spawns[i])
continue;
if (i == 0 && m_mobs[i] != nullptr)
{
if (m_isPulled == false)
{
RPRINT("testing");
m_lastPosition = m_mobs[i]->GetActorLocation();
}
else if (!m_mobs[i]->target)
{
const FVector2D mobPos = FVector2D(m_mobs[i]->GetActorLocation().X, m_mobs[i]->GetActorLocation().Y);
const float distSqr = FVector2D::DistSquared(mobPos, FVector2D(m_lastPosition.X, m_lastPosition.Y));
if (distSqr < (m_mobs[i]->collisionRadius*m_mobs[i]->collisionRadius)*collisionScaler)
m_isPulled = false;
}
// Any of the mobs not doing anything?
const FVector2D mobPos = FVector2D(m_mobs[i]->GetActorLocation().X, m_mobs[i]->GetActorLocation().Y);
const float distSqr = FVector2D::DistSquared(mobPos, FVector2D(m_lastPosition.X, m_lastPosition.Y));
////// Regeneration (hardcoded, remove in future)
if (!m_mobs[i]->target && distSqr < aggroRadius*aggroRadius)
{
anyIdle = true;
}
}
}
if (m_mobs[0] != nullptr && m_isPulled)
{
m_mobs[0]->SetControlPoint(m_lastPosition);
for (int i = 1; i < m_mobs.Num(); i++)
{
m_mobs[i]->SetControlPoint(m_lastPosition);
}
}
ADefaultGameMode* const mode = Cast<ADefaultGameMode>(world->GetAuthGameMode());
if (mode)
{
FVector controlLocation = GetActorLocation();
// check if there are some controll points
if (m_mobs[0] != nullptr && !m_isPulled)
{
if (FVector2D::DistSquared(FVector2D(m_mobs[0]->GetActorLocation().X, m_mobs[0]->GetActorLocation().Y), FVector2D(m_controlPoints[m_currentControlPoint].X, m_controlPoints[m_currentControlPoint].Y)) < 10000)
{
m_currentControlPoint += m_controlPointSign;
if (m_currentControlPoint >= m_controlPoints.Num() || m_currentControlPoint < 0)
{
m_controlPointSign *= -1;
m_currentControlPoint += m_controlPointSign;
if (isConnected)
{
m_currentControlPoint = 0;
m_controlPointSign *= -1;
}
}
}
// set new control location
controlLocation = m_controlPoints[m_currentControlPoint];
m_mobs[0]->SetControlPoint(controlLocation);
if (m_mobs.Num() > 1)
{
for (int i = 1; i < m_mobs.Num(); i++)
{
m_mobs[i]->SetControlPoint(m_lastPosition);
}
}
}
if (anyIdle && !m_isPulled)
{
/*// Find the closest player (in aggroRadius)
ANetworkCharacter* closest = nullptr;
float closestDist = BIG_NUMBER;
TArray<ANetworkCharacter*> players = mode->GetPlayers();
const float aggroSqr = aggroRadius * aggroRadius;
for (int32 i = 0; i < players.Num(); i++)
{
const float distSqr = FVector::DistSquared(m_mobs[0]->GetActorLocation(), players[i]->GetActorLocation());
if (distSqr < closestDist && distSqr <= aggroSqr)
{
closest = players[i];
closestDist = distSqr;
}
}*/
ANetworkPlayer* closest = m_GetClosestPlayer();
if (closest)
{
// Attack the closest player
for (int32 i = 0; i < spawns.Num(); i++)
{
if (m_mobs[i] == nullptr)
continue;
m_mobs[i]->target = (closest);
m_isPulled = true;
}
}
}
}
}
FVector APatrolSpawn::SpawnResetPosition()
{
return m_lastPosition;
}
void APatrolSpawn::SpawnMobs()
{
m_RespawnMobs();
}
void APatrolSpawn::m_RespawnMobs()
{
UWorld* const world = GetWorld();
if (!world)
return;
for (int32 i = 0; i < m_mobs.Num(); i++)
{
if (!spawns[i])
continue;
if (m_mobs[i] == nullptr)
{
// Respawn!
FTransform spawnTransform = GetTransform();
if (hasGeneral)
{
spawnTransform.SetLocation(FVector(formationPoints[i].X, formationPoints[i].Y,0) + GetActorLocation());
}
else
{
spawnTransform.SetLocation(GetActorLocation() + FVector(0, 0, 120));
}
spawnTransform.SetRotation(FRotator(GetActorRotation() + FRotator(0, formationRotation[i], 0)).Quaternion());
ANPCBase* character = world->SpawnActorDeferred<ANPCBase>(spawns[i], spawnTransform, nullptr, nullptr, ESpawnActorCollisionHandlingMethod());
character->SetSpawn(this);
character->SetTeam((int32)team);
m_mobs[i] = character;
m_mobCount++;
m_OnMobSpawn(i);
UGameplayStatics::FinishSpawningActor(character, spawnTransform);
character->SpawnDefaultController();
}
}
m_respawnTimer = respawnTime;
}
class ANetworkPlayer* APatrolSpawn::m_GetClosestPlayer()
{
UWorld* const world = GetWorld();
if (!world)
return nullptr;
ADefaultGameMode* const mode = Cast<ADefaultGameMode>(world->GetAuthGameMode());
if (!mode)
return nullptr;
// Find the closest player (in aggroRadius)
ANetworkPlayer* closest = nullptr;
float closestDist = BIG_NUMBER;
TArray<ANetworkPlayer*> players = mode->GetPlayers();
const float aggroSqr = aggroRadius * aggroRadius;
for (int32 i = 0; i < players.Num(); i++)
{
const float distSqr = FVector2D::DistSquared(FVector2D(m_mobs[0]->GetActorLocation()), FVector2D(players[i]->GetActorLocation()));
if (distSqr < closestDist && distSqr <= aggroSqr)
{
closest = players[i];
closestDist = distSqr;
}
}
return closest;
}