// © 2025 Naked People Team. All Rights Reserved. #include "NPCSpawner.h" #include "NPC.h" #include "Kismet/GameplayStatics.h" #include "NakedDesire/Global/NakedDesireGameMode.h" ANPCSpawner::ANPCSpawner() { PrimaryActorTick.bCanEverTick = false; } void ANPCSpawner::BeginPlay() { Super::BeginPlay(); PlayerCharacter = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0); FTimerHandle TimerHandle; const int32 RandomDelay = FMath::RandRange(5, 30); GetWorldTimerManager().SetTimer(TimerHandle, this, &ANPCSpawner::OnTimerTick, 30, true, RandomDelay); OnTimerTick(); if (AGameModeBase* CurrentGameMode = UGameplayStatics::GetGameMode(GetWorld())) { GameMode = Cast(CurrentGameMode); } } void ANPCSpawner::OnTimerTick() { if (!PlayerCharacter || !GameMode) { return; } const bool IsPlayerClose = FVector::Dist(PlayerCharacter->GetActorLocation(), GetActorLocation()) < 5000; const FTimecode CurrentTime = GameMode->GetCurrentTime(); const bool IsDay = CurrentTime.Hours >= 9.0f && CurrentTime.Hours < 21.00f; const bool CanSpawnMore = IsDay ? NPCs.Num() < MaxCountDay : NPCs.Num() < MaxCountNight; if (CanSpawnMore && PlayerCharacter && IsPlayerClose && (FMath::RandBool() && !AlwaysSpawn)) { FActorSpawnParameters SpawnParameters; SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn; const int RandomIndex = FMath::RandRange(0, NPCClasses.Num() - 1); ANPC* NewNPC = GetWorld()->SpawnActor(NPCClasses[RandomIndex], GetActorLocation(), GetActorRotation(), SpawnParameters); NewNPC->OnDestroyed.AddUObject(this, &ANPCSpawner::OnNPCDestroyed); NPCs.Add(NewNPC); } } void ANPCSpawner::OnNPCDestroyed(ANPC* NPC) { NPCs.Remove(NPC); }