// 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(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 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(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(world->GetAuthGameMode()); if (!mode) return nullptr; // Find the closest player (in aggroRadius) ANetworkPlayer* closest = nullptr; float closestDist = BIG_NUMBER; TArray 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; }