HAxis sos

This commit is contained in:
guus
2018-08-11 16:46:35 +02:00
commit 510654f8a1
480 changed files with 54126 additions and 0 deletions

View File

@@ -0,0 +1,354 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "NPCBase.h"
#include "NetworkDoor.h"
#include "DefaultGameMode.h"
#include "CreatureSpawn.h"
#include "Modifier.h"
#include "NativeModifiers.h"
#include "NetworkPlayer.h"
#include "TouhouBoss.h"
ACreatureSpawn::ACreatureSpawn()
{
respawnTime = 5;
m_respawnTimer = 0;
spawnContinuous = true;
spawnTrigger = CreateDefaultSubobject<USphereComponent>(TEXT("Sphere"));
spawnTrigger->SetCollisionProfileName(TEXT("PlayerOverlap"));
spawnTrigger->AttachTo(RootComponent);
spawnTrigger->OnComponentBeginOverlap.AddDynamic(this, &ACreatureSpawn::OnOverlapBegin);
spawnTrigger->OnComponentEndOverlap.AddDynamic(this, &ACreatureSpawn::OnOverlapEnd);
spawnTrigger->SetSphereRadius(3000);
spawnTrigger->SetVisibility(false);
}
void ACreatureSpawn::BeginPlay()
{
Super::BeginPlay();
if (Role != ROLE_Authority)
return;
if (aggroRadius < 0) aggroRadius = 0;
if (respawnTime < 0) respawnTime = 0;
if (spawns.Num() == 0)
{
JWARNING("Empty spawner in scene");
return;
}
else if (spawns.Num() != 1 && isBoss)
{
FWARNING("Unexpected amount of spawners for boss");
}
// Calculate spawn sub positions
if (spawns.Num() > 1)
{
float angle = (360.0f) / 180.0f * PI;
float anglestep = (angle) / (spawns.Num() + 1);
float rot = angle * 0.5f;
for (int32 i = 0; i < spawns.Num(); i++)
{
float f = cosf(rot);
float r = sinf(rot);
rot += anglestep;
if (hasGeneral)
{
m_resetPoints.Add(GetActorLocation() + FVector(f * 200, r * 200, 0));
}
else m_resetPoints.Add(FVector(formationPoints[i].X,formationPoints[i].Y,0) + GetActorLocation());
}
}
else if (spawns.Num() == 1)
m_resetPoints.Add(GetActorLocation());
m_respawnTimer = -1.0f;
}
void ACreatureSpawn::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
}
void ACreatureSpawn::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (Role != ROLE_Authority)
return;
UWorld* const world = GetWorld();
if (!world) return;
m_respawnTimer = m_respawnTimer > 0 ? (m_respawnTimer - DeltaTime) : 0;
/*if (m_nearbyPlayers.empty())
{
// Despawn if there are no players nearby and the timer is depleted
if (m_respawnTimer <= 0)
{
// m_DespawnMobs();
}
}
else
{*/
// Respawn time mobs if the timer has ran out and we are missing mobs
if (m_respawnTimer <= 0 && m_mobCount != m_mobs.Num() && spawnContinuous)
m_RespawnMobs();
// }
// No mobs to update
if (m_mobs.Num() == 0)
return;
// Decrement respawntime
bool anyIdle = false;
for (int32 i = 0; i < spawns.Num(); i++)
{
if (!spawns[i] || !m_mobs[i])
continue;
// Check if any mob is idle
const FVector2D mobPos = FVector2D(m_mobs[i]->GetActorLocation().X, m_mobs[i]->GetActorLocation().Y);
const FVector2D targetPos = FVector2D(SpawnResetPosition().X, SpawnResetPosition().Y);
const float distSqr = FVector2D::DistSquared(mobPos, targetPos);
if (!m_mobs[i]->target && distSqr < deaggroRadius*deaggroRadius)
anyIdle = true;
}
//// We can start attacking if any mob is idle and there is a player nearby
//if (anyIdle)
//{
// for (int32 i = 0; i < spawns.Num(); i++)
// {
// if (m_mobs[i] == nullptr)
// continue;
// //find the biggest threat of the enemies
// ANetworkCharacter* threat = m_GetBiggestThreat(i);
// if (m_mobs[i]->target != nullptr)
// continue;
// const FVector2D mobPos = FVector2D(m_mobs[i]->GetActorLocation().X, m_mobs[i]->GetActorLocation().Y);
// const FVector2D targetPos = FVector2D(m_resetPoints[i].X, m_resetPoints[i].Y);
// const float distSqr = FVector2D::DistSquared(mobPos, targetPos);
// if (distSqr < aggroRadius * aggroRadius)// (m_mobs[i]->collisionRadius*m_mobs[i]->collisionRadius)*collisionScaler)
// {
// FPRINT("idledistsettarget");
// m_mobs[i]->target = threat;
// }
//
// }
//}
if (isBoss && m_mobs.Num() == 1)
{
UWorld* const world = GetWorld();
if (!world) return;
ADefaultGameMode* mode = Cast<ADefaultGameMode>(world->GetAuthGameMode());
if (!mode) return;
//check if it is more than 1 team
int teamcount = 0;
int32 team = 0;
for (auto iter = m_nearbyPlayers.begin(); iter != m_nearbyPlayers.end(); iter++)
{
ANetworkCharacter* player = *iter;
if ((player->GetActorLocation() - GetActorLocation()).Size() < aggroRadius)
{
if (teamcount == 0)
{
team = player->GetTeam();
teamcount++;
}
else if (team != player->GetTeam())
{
teamcount++;
break;
}
}
}
if (teamcount > 1 && m_invulnerableModifier == nullptr)
{
if (m_mobs[0] != nullptr)
{
ModifierManager* manager = m_mobs[0]->GetModifierManager();
TSubclassOf<ADamageTakenModifier> subclass = ADamageTakenModifier::StaticClass();
m_invulnerableModifier = GetWorld()->SpawnActor<AModifier>(subclass);
if (m_invulnerableModifier != nullptr)
{
Cast<ADamageTakenModifier>(m_invulnerableModifier)->damageTakenMultiplier = 0.0f;
m_invulnerableModifier->character = m_mobs[0];
manager->AddModifier(m_invulnerableModifier);
Cast<ATouhouBoss>(m_mobs[0])->SetShield(true);
}
else
{
FPRINT("failed to spawn m_invulnerableModifier in creaturespawn");
}
}
}
else if (teamcount <2 && m_invulnerableModifier != nullptr)
{
m_invulnerableModifier->ForceDestroy();
m_invulnerableModifier = nullptr;
}
}
}
int32 ACreatureSpawn::OnMobDie(class ANPCBase* mob)
{
const int32 idx = Super::OnMobDie(mob);
m_respawnTimer = respawnTime;
if (m_mobCount == 0)
{
for (int32 i = 0; i < doorsToOpen.Num(); i++)
{
if (doorsToOpen[i])
doorsToOpen[i]->SetDoorState(false);
}
}
return idx;
}
void ACreatureSpawn::SpawnMobs()
{
m_RespawnMobs();
}
void ACreatureSpawn::OnOverlapBegin(AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (!OtherActor)
return;
if (!OtherActor->IsA(ANetworkCharacter::StaticClass()))
return;
ANetworkCharacter* player = Cast<ANetworkCharacter>(OtherActor);
if(player)
m_OnPlayerEnterOverlap(*player);
}
void ACreatureSpawn::OnOverlapEnd(AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (!OtherActor)
return;
if (!OtherActor->IsA(ANetworkCharacter::StaticClass()))
return;
ANetworkCharacter* player = Cast<ANetworkCharacter>(OtherActor);
if(player)
m_OnPlayerExitOverlap(*player);
}
void ACreatureSpawn::m_DespawnMobs()
{
for (int32 i = 0; i < m_mobs.Num(); i++)
{
if (m_mobs[i])
{
m_mobs[i]->UnsetSpawn();
m_mobs[i]->Destroy();
m_mobs[i] = nullptr;
}
}
for (int32 i = 0; i < doorsToOpen.Num(); i++)
{
if (doorsToOpen[i])
doorsToOpen[i]->SetDoorState(false);
}
formationEnemies.Empty();
m_mobCount = 0;
}
void ACreatureSpawn::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();
FVector spawnVector = FVector();
spawnTransform.SetLocation(m_resetPoints[i] + FVector(0, 0, 120));
if (SpawnLocation.Num()>0)
{
int randnum = rand() % SpawnLocation.Num();
spawnTransform = SpawnLocation[randnum]->GetTransform();
FVector rotation = FVector(GetActorLocation() - spawnTransform.GetLocation());
spawnTransform.SetRotation(FQuat(rotation.Rotation()));
//spawnVector = SpawnLocation->GetActorLocation() - GetActorLocation();
//spawnTransform.SetLocation(spawnVector);
}
ANPCBase* character = world->SpawnActorDeferred<ANPCBase>(spawns[i], spawnTransform, nullptr, nullptr, ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
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;
}
void ACreatureSpawn::GetNewTarget(class ANPCBase* mob)
{
if (mob == nullptr)
return;
int32 index = -1;
for (ANPCBase* currentMob : m_mobs)
{
index++;
if (mob != currentMob)
continue;
ANetworkCharacter* threat = nullptr;
bool end = false;
//keeps looping to make sure if the biggest threat is not in aggrorange it still works;
int32 biggestThreat = -1;
float dist = 1e34;
for (ANetworkCharacter *character:m_nearbyPlayers)
{
if (character->GetTeam() == (int)team)
continue;
//check if it is bigger than the last biggestThreat
const FVector2D spawnpost = FVector2D(GetActorLocation().X, GetActorLocation().Y);
const FVector2D targetPos = FVector2D(character->GetActorLocation().X, character->GetActorLocation().Y);
const float distSqr = FVector2D::DistSquared(spawnpost, targetPos);
//making sure the new biggest thread is withing the aggroRadius
if (distSqr < aggroRadius * aggroRadius&&dist>distSqr)
{
dist = distSqr;
threat = character;
}
}
m_resetTimer = resetTimer;
currentMob->target = threat;
return;
}
return;
}

View File

@@ -0,0 +1,54 @@
// Project Lab - NHTV Igad
#pragma once
#include "SpawnerBase.h"
#include "CreatureSpawn.generated.h"
UCLASS()
class ACreatureSpawn : public ASpawnerBase
{
GENERATED_BODY()
public:
ACreatureSpawn();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float DeltaTime) override;
UPROPERTY(EditAnywhere, Category = "Switch Components")
TArray<class ANetworkDoor*> doorsToOpen;
UPROPERTY(EditAnywhere)
float respawnTime;
UPROPERTY(EditAnywhere, Category = "Switch Components")
class USphereComponent* spawnTrigger;
UPROPERTY(EditAnywhere, Category = "Gamestate Components")
bool isBoss;
UPROPERTY(EditAnywhere, Category = "Gamestate Components")
bool spawnContinuous;
UFUNCTION()
void OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void OnOverlapEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
virtual int32 OnMobDie(class ANPCBase* mob) override;
virtual void GetNewTarget(class ANPCBase* mob) override;
void SpawnMobs();
protected:
virtual void m_RespawnMobs();
private:
TArray<FVector> m_resetPoints;
float m_respawnTimer;
class AModifier* m_invulnerableModifier;
void m_DespawnMobs();
};

View File

@@ -0,0 +1,244 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "CreatureSpawnComponent.h"
#include "SpawnerBase.h"
#include "GeneralEnemy.h"
#include "OffensiveEnemy.h"
#include "RangedEnemy.h"
#include "EnemyBase.h"
#define CONEARCVERTEXCOUNT 50
UCreatureSpawnComponent::UCreatureSpawnComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
ShapeColor = FColor(223, 149, 157, 255);
spawnerBase = Cast<ASpawnerBase>(GetAttachmentRootActor());
bUseEditorCompositing = true;
}
FPrimitiveSceneProxy* UCreatureSpawnComponent::CreateSceneProxy()
{
class FDrawConeSceneProxy : public FPrimitiveSceneProxy
{
public:
const UCreatureSpawnComponent* component;
FDrawConeSceneProxy(const UCreatureSpawnComponent* InComponent)
: FPrimitiveSceneProxy(InComponent)
, spawnerBase(InComponent->spawnerBase)
, bDrawOnlyIfSelected(InComponent->bDrawOnlyIfSelected)
, component(InComponent)
{
bWillEverBeLit = false;
}
virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_GetDynamicMeshElements_DrawDynamicElements);
const FMatrix& LocalToWorld = GetLocalToWorld();
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
const FSceneView* View = Views[ViewIndex];
FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);
if (spawnerBase)
{
FTransform transform = component->GetAttachParent()->GetComponentTransform();
FVector base = transform.GetLocation();
const float scale = 1.0f / 180.0f * PI;
float baseRot = (360.0f - transform.GetRotation().Euler().Z) * scale;
//FVector forward = FVector(1, 0, 0).RotateAngleAxis(0.0f, FVector(0, 0, 1));
//FVector right = FVector(0, 1, 0).RotateAngleAxis(0.0f, FVector(0, 0, 1));
FVector forward = FVector(1, 0, 0);
FVector right = FVector(0, 1, 0);
float angle = (360.0f) / 180.0f * PI;
FVector linePoints[CONEARCVERTEXCOUNT];
float anglestep = (angle) / (CONEARCVERTEXCOUNT - 1);
float rot = baseRot - angle * 0.5f;
for (int i = 0; i < CONEARCVERTEXCOUNT; i++)
{
float f = cosf(rot);
float r = sinf(rot);
linePoints[i] = base + (forward * f - right * r) * spawnerBase->aggroRadius;
rot += anglestep;
}
for (int i = 0; i < CONEARCVERTEXCOUNT - 1; i++)
{
PDI->DrawLine(linePoints[i], linePoints[i + 1], ShapeColor, SDPG_World);
}
for (int i = 0; i < CONEARCVERTEXCOUNT; i++)
{
float f = cosf(rot);
float r = sinf(rot);
linePoints[i] = base + (forward * f - right * r) * spawnerBase->deaggroRadius;
rot += anglestep;
}
for (int i = 0; i < CONEARCVERTEXCOUNT - 1; i++)
{
PDI->DrawLine(linePoints[i], linePoints[i + 1], FColor(0,0,255), SDPG_World);
}
FVector last = spawnerBase->GetActorLocation();
FVector first;
for (int32 i = 0; i < spawnerBase->controlPoints.Num(); i++)
{
FTransform transform = component->GetAttachParent()->GetComponentTransform();
FVector base = transform.GetLocation() + FVector(spawnerBase->controlPoints[i].X, spawnerBase->controlPoints[i].Y, 0);
if (i == 0)
first = base;
const float scale = 1.0f / 180.0f * PI;
float baseRot = (360.0f - transform.GetRotation().Euler().Z) * scale;
//FVector forward = FVector(1, 0, 0).RotateAngleAxis(0.0f, FVector(0, 0, 1));
//FVector right = FVector(0, 1, 0).RotateAngleAxis(0.0f, FVector(0, 0, 1));
FVector forward = FVector(1, 0, 0);
FVector right = FVector(0, 1, 0);
float angle = (360.0f) / 180.0f * PI;
FVector linePoints[CONEARCVERTEXCOUNT];
float anglestep = (angle) / (CONEARCVERTEXCOUNT - 1);
float rot = baseRot - angle * 0.5f;
for (int i = 0; i < CONEARCVERTEXCOUNT; i++)
{
float f = cosf(rot);
float r = sinf(rot);
linePoints[i] = base + (forward * f - right * r) * spawnerBase->drawingRadius;
rot += anglestep;
}
for (int i = 0; i < CONEARCVERTEXCOUNT - 1; i++)
{
PDI->DrawLine(linePoints[i], linePoints[i + 1], ShapeColor, SDPG_World);
}
PDI->DrawLine(base, last, ShapeColor, SDPG_World);
last = base;
//PDI->DrawLine(base, linePoints[CONEARCVERTEXCOUNT - 1], ShapeColor, SDPG_World);
}
if (spawnerBase->isConnected)
PDI->DrawLine(first, last, ShapeColor, SDPG_World);
for (int32 i = 0; i < spawnerBase->formationPoints.Num(); i++)
{
FColor formationColor = FColor(100, 100, 100);
//AEnemyBase *creature = (dynamic_cast<AGeneralEnemy*>(spawnerBase->spawns[i]));
FTransform transform = component->GetAttachParent()->GetComponentTransform();
FVector base = transform.GetLocation() + spawnerBase->GetActorRotation().RotateVector( FVector(spawnerBase->formationPoints[i].X, spawnerBase->formationPoints[i].Y, 0))*spawnerBase->formationScale;
if (i == 0)
first = base;
const float scale = 1.0f / 180.0f * PI;
float baseRot = (360.0f - transform.GetRotation().Euler().Z) * scale;
//FVector forward = FVector(1, 0, 0).RotateAngleAxis(0.0f, FVector(0, 0, 1));
//FVector right = FVector(0, 1, 0).RotateAngleAxis(0.0f, FVector(0, 0, 1));
FVector forward = FVector(1, 0, 0);
FVector right = FVector(0, 1, 0);
float angle = (360.0f) / 180.0f * PI;
FVector linePoints[CONEARCVERTEXCOUNT];
float anglestep = (angle) / (CONEARCVERTEXCOUNT - 1);
float rot = baseRot - angle * 0.5f;
for (int j = 0; j < CONEARCVERTEXCOUNT; j++)
{
float f = cosf(rot);
float r = sinf(rot);
linePoints[j] = base + (forward * f - right * r) * spawnerBase->drawingRadius;
rot += anglestep;
}
if (i >= spawnerBase->spawns.Num())
{
formationColor.B = 10;
formationColor.G = 10;
formationColor.R = 10;
}
else
{
if ((spawnerBase->spawns[i])->IsChildOf(AGeneralEnemy::StaticClass()))
{
formationColor.B = 255;
formationColor.G = 255;
formationColor.R = 255;
}
else
{
formationColor.B = 42;
formationColor.G = 42;
formationColor.R = 42;
}
if ((spawnerBase->spawns[i])->IsChildOf(ARangedEnemy::StaticClass())&& !spawnerBase->spawns[i]->IsChildOf(AGeneralEnemy::StaticClass()))
{
formationColor.B = 0;
formationColor.G = 255;
formationColor.R = 0;
}
if ((spawnerBase->spawns[i])->IsChildOf(AOffensiveEnemy::StaticClass()))
{
formationColor.B = 0;
formationColor.G = 0;
formationColor.R = 255;
}
}
for (int j = 0; j < CONEARCVERTEXCOUNT - 1; j++)
{
PDI->DrawLine(linePoints[j], linePoints[j + 1], formationColor, SDPG_World);
}
if (i < spawnerBase->formationRotation.Num())
{
PDI->DrawLine(base, base+(FRotator(0, spawnerBase->formationRotation[i],0).RotateVector( spawnerBase->GetActorForwardVector())* spawnerBase->drawingRadius), formationColor, SDPG_World);
}
else PDI->DrawLine(base, base + (spawnerBase->GetActorForwardVector())* spawnerBase->drawingRadius, formationColor, SDPG_World);
// PDI->DrawLine(base, last, formationColor, SDPG_World);
last = base;
//PDI->DrawLine(base, linePoints[CONEARCVERTEXCOUNT - 1], ShapeColor, SDPG_World);
}
//if (spawnerBase->isConnected)
// PDI->DrawLine(first, last, ShapeColor, SDPG_World);
}
}
}
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override
{
FPrimitiveViewRelevance Result;
Result.bDrawRelevance = IsSelected();
Result.bDynamicRelevance = true;
Result.bShadowRelevance = IsShadowCast(View);
Result.bEditorPrimitiveRelevance = UseEditorCompositing(View);
return Result;
}
virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
private:
const uint32 bDrawOnlyIfSelected : 1;
const ASpawnerBase* spawnerBase;
const FColor ShapeColor = FColor(255, 0, 0, 255);
const FTransform transform;
};
return new FDrawConeSceneProxy(this);
}

View File

@@ -0,0 +1,22 @@
// Project Lab - NHTV Igad
#pragma once
#include "Components/CapsuleComponent.h"
#include "CreatureSpawnComponent.generated.h"
/**
*
*/
class ASpawnerBase;
UCLASS()
class UNREALPROJECT_API UCreatureSpawnComponent : public UCapsuleComponent
{
GENERATED_UCLASS_BODY()
public:
ASpawnerBase* spawnerBase;
virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
};

View File

@@ -0,0 +1,41 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "KOTHBossSpawner.h"
#include "NPCBase.h"
void AKOTHBossSpawner::BeginPlay()
{
Super::BeginPlay();
for (TActorIterator<ASpawnerBase>actorIt(GetWorld()); actorIt; ++actorIt)
{
ASpawnerBase *spawn = *actorIt;
if (!spawn->possesable)
spawn->SetTeam((int)team);
}
}
void AKOTHBossSpawner::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
}
void AKOTHBossSpawner::Tick(float deltaTime)
{
Super::Tick(deltaTime);
}
bool AKOTHBossSpawner::IsBossAlive() const
{
if(m_mobs.Num() > 0)
{
if(IsValid(m_mobs[0]))
return true;
}
return false;
}
void AKOTHBossSpawner::m_RespawnMobs()
{
if (IsContested(m_currentTeam) && m_currentTeam<5)
{
return;
}
Super::m_RespawnMobs();
}

View File

@@ -0,0 +1,26 @@
// Project Lab - NHTV Igad
#pragma once
#include "Spawners/KOTHSpawnerBase.h"
#include "KOTHBossSpawner.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AKOTHBossSpawner : public AKOTHSpawnerBase
{
GENERATED_BODY()
public:
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float deltaTime)override;
// Check if the KOTH boss is currently alive
bool IsBossAlive() const;
protected:
virtual void m_RespawnMobs()override;
private:
};

View File

@@ -0,0 +1,78 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "NPCBase.h"
#include "NetworkDoor.h"
#include "DefaultGameMode.h"
#include "KOTHMinionSpawner.h"
#include "KOTHBossSpawner.h"
#include "NetworkCharacter.h"
AKOTHMinionSpawner::AKOTHMinionSpawner(const FObjectInitializer& init)
: Super(init)
{
respawnTime = 5;
// m_respawnTimer = 0;
spawnContinuous = true;
}
void AKOTHMinionSpawner::BeginPlay()
{
Super::BeginPlay();
if (Role == ROLE_Authority)
{
kothagroRadius = aggroRadius;
kothdeagroRadius = deaggroRadius;
for (TActorIterator<AKOTHBossSpawner>bSpawn(GetWorld()); bSpawn; ++bSpawn)
{
if (bSpawn)
bossSpawner = *bSpawn;
}
Super::m_RespawnMobs();
}
}
void AKOTHMinionSpawner::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (!HasAuthority())
return;
// Reset the camp to the NPC team after an amount of time(captureTime)
m_captureTimer -= DeltaTime;
if (m_captureTimer < 0 && (int)team < 5)
{
SetTeam((int)(NPCTeam::Team1));
m_reset = true;
}
}
void AKOTHMinionSpawner::GetNewTarget(ANPCBase* mob)
{
if (team == bossSpawner->team || (int)team>5)
{
aggroRadius = kothagroRadius;
deaggroRadius = kothdeagroRadius;
Super::GetNewTarget(mob);
return;
}
for (ANPCBase* bMob : bossSpawner->m_mobs)
{
aggroRadius = 1e34;
deaggroRadius = 1e34;
ANetworkCharacter* threat = Cast<ANetworkCharacter>(bMob);
if (threat)
mob->target = threat;
}
}
void AKOTHMinionSpawner::m_RespawnMobs()
{
if (((int)team < 5 || m_reset))
{
Super::m_RespawnMobs();
}
}

View File

@@ -0,0 +1,30 @@
// Project Lab - NHTV Igad
#pragma once
#include "Spawners/KOTHSpawnerBase.h"
#include "KOTHMinionSpawner.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AKOTHMinionSpawner : public AKOTHSpawnerBase
{
GENERATED_BODY()
public:
AKOTHMinionSpawner(const FObjectInitializer& init);
virtual void GetNewTarget(class ANPCBase* mob)override;
virtual void BeginPlay()override;
virtual void Tick(float deltaTime) override;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "KOTH Spawner Properties")
FText CampName;
private:
virtual void m_RespawnMobs()override;
float kothagroRadius;
float kothdeagroRadius;
};

View File

@@ -0,0 +1,132 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "KOTHSpawnerBase.h"
#include "NetworkPlayer.h"
#include "KOTHBossSpawner.h"
AKOTHSpawnerBase::AKOTHSpawnerBase(const FObjectInitializer& init)
{
captureRadius = 500;
captureTime = 30;
possesionTime = 1;
captureParticle = CreateDefaultSubobject<UParticleSystemComponent>("PossessParticle");
captureParticle->AttachTo(RootComponent);
}
void AKOTHSpawnerBase::BeginPlay()
{
Super::BeginPlay();
// Assign team
m_currentTeam = (int)team;
beingCaptured = false;
}
void AKOTHSpawnerBase::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// Run capture polling code on host
if(Role == ROLE_Authority)
{
if(beingCaptured)
{
bool capture = false;
auto nearbyPlayers = GetNearbyPlayers();
// Check contested condition
if (m_mobCount == 0 && (nearbyPlayers.Num() <= 2))
{
if (nearbyPlayers.Num() > 0 && !IsContested(nearbyPlayers[0]->GetTeam()) && (int)team != nearbyPlayers[0]->GetTeam())
{
capture = true;
if (bossSpawner)
{
if ((int)bossSpawner->team == nearbyPlayers[0]->GetTeam() || (int)team < 5)
{
capture = false;
}
}
}
}
if(capture)
{
m_possesionTimer += DeltaTime;
if(m_possesionTimer > possesionTime)
{
// Nearby team captures camp
m_ExeCaptureCamp(nearbyPlayers[0]->GetTeam());
}
}
else
{
m_possesionTimer = 0;
}
}
}
}
void AKOTHSpawnerBase::m_ExeCaptureCamp_Implementation(int32 targetTeam)
{
if(Role == ROLE_Authority)
{
SetTeam(targetTeam);
onCampCaptured.Broadcast(targetTeam);
m_captureTimer = captureTime;
m_currentTeam = (int)NPCTeam::Team1;
beingCaptured = false;
m_reset = false;
}
// Callback
OnEndCaptureCamp(targetTeam);
onEndCapture.Broadcast(targetTeam);
// Deactivate capture particle
captureParticle->DeactivateSystem();
}
void AKOTHSpawnerBase::m_OnCampCleared()
{
Super::m_OnCampCleared();
if(Role == ROLE_Authority)
{
beingCaptured = true;
}
// Callback
OnBeginCaptureCamp();
onBeginCapture.Broadcast();
// Enable capture particle
if(captureParticle->Template)
{
captureParticle->bAutoDestroy = false;
captureParticle->ResetParticles();
captureParticle->ActivateSystem();
}
}
void AKOTHSpawnerBase::CaptureCamp(int targetTeam)
{
Super::CaptureCamp(targetTeam);
m_currentTeam = targetTeam;
m_possesionTimer = 0;
}
bool AKOTHSpawnerBase::IsContested(int32 targetTeam) const
{
for(ANetworkCharacter* character : m_nearbyPlayers)
{
ANetworkPlayer* player = Cast<ANetworkPlayer>(character);
if(player && player->GetTeam() != targetTeam && FVector::DistSquared(GetActorLocation(), player->GetActorLocation()) < captureRadius * captureRadius)
return true;
}
return false;
}

View File

@@ -0,0 +1,70 @@
// Project Lab - NHTV Igad
#pragma once
#include "Spawners/CreatureSpawn.h"
#include "KOTHSpawnerBase.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AKOTHSpawnerBase : public ACreatureSpawn
{
GENERATED_BODY()
public:
AKOTHSpawnerBase(const FObjectInitializer& init);
void BeginPlay() override;
void Tick(float DeltaTime) override;
// Overrided capture camp behaviour
virtual void CaptureCamp(int team) override;
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnBeginCapture);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnEndCapture, int32, targetTeam);
UFUNCTION(BlueprintImplementableEvent, Category = "KOTH Spawner")
void OnBeginCaptureCamp();
UFUNCTION(BlueprintImplementableEvent, Category = "KOTH Spawner")
void OnEndCaptureCamp(int32 targetTeam);
UPROPERTY(BlueprintAssignable)
FOnBeginCapture onBeginCapture;
UPROPERTY(BlueprintAssignable)
FOnEndCapture onEndCapture;
UFUNCTION(BlueprintCallable, Category = "KOTH Spawner")
bool IsContested(int32 targetTeam) const;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCampCaptured, int32, targetTeam);
UPROPERTY(BlueprintAssignable, Category = "Game")
FOnCampCaptured onCampCaptured;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Capture Particle")
UParticleSystemComponent* captureParticle;
UPROPERTY(BlueprintReadOnly, Category = "KOTH Spawner Properties")
bool beingCaptured;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "KOTH Spawner Properties")
float captureRadius;
// The duration the camp is captured for
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "KOTH Spawner Properties")
float captureTime;
// The time it takes to capture a camp
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "KOTH Spawner Properties")
float possesionTime;
class AKOTHBossSpawner* bossSpawner;
protected:
// Handle to start the capture process
void m_OnCampCleared() override;
// Called when a camp is no longer contested and should be captured by the target team
UFUNCTION(NetMulticast, Reliable)
void m_ExeCaptureCamp(int32 targetTeam);
float m_captureTimer;
float m_possesionTimer;
int m_currentTeam;
bool m_reset;
};

View File

@@ -0,0 +1,20 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "LobbySpawn.h"
ALobbySpawn::ALobbySpawn()
{
displayMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
displayMesh->bHiddenInGame = true;
displayMesh->bGenerateOverlapEvents = false;
displayMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
displayArrow = CreateDefaultSubobject<UArrowComponent>(TEXT("Arrow"));
assignedTeam = 0;
}
void ALobbySpawn::BeginPlay()
{
Super::BeginPlay();
}

View File

@@ -0,0 +1,25 @@
// Project Lab - NHTV Igad
#pragma once
#include "GameFramework/Actor.h"
#include "LobbySpawn.generated.h"
UCLASS()
class UNREALPROJECT_API ALobbySpawn : public AActor
{
GENERATED_BODY()
public:
ALobbySpawn();
virtual void BeginPlay() override;
UPROPERTY(EditAnywhere, Category = "Gamestate Components")
int32 assignedTeam;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Display)
class UStaticMeshComponent* displayMesh;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Display)
class UArrowComponent* displayArrow;
};

View File

@@ -0,0 +1,259 @@
// 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;
}

View File

@@ -0,0 +1,39 @@
// Project Lab - NHTV Igad
#pragma once
#include "SpawnerBase.h"
#include "PatrolSpawn.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API APatrolSpawn : public ASpawnerBase
{
GENERATED_BODY()
public:
APatrolSpawn();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float DeltaTime) override;
virtual FVector SpawnResetPosition() override;
UPROPERTY(EditAnywhere)
float respawnTime;
UPROPERTY(EditAnywhere, Category = "Gamestate Components")
bool spawnContinuous;
void SpawnMobs();
private:
float m_respawnTimer;
TArray<FVector> m_controlPoints;
int32 m_controlPointSign;
int32 m_currentControlPoint;
TArray<float> m_respawnTimers;
FVector m_lastPosition;
bool m_isPulled;
void m_RespawnMobs();
class ANetworkPlayer* m_GetClosestPlayer();
};

View File

@@ -0,0 +1,26 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "DefaultGameMode.h"
#include "PlayerSpawn.h"
APlayerSpawn::APlayerSpawn()
{
displayMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
displayMesh->bHiddenInGame = true;
displayMesh->bGenerateOverlapEvents = false;
displayMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
displayArrow = CreateDefaultSubobject<UArrowComponent>(TEXT("Arrow"));
assignedTeam = 0;
}
void APlayerSpawn::BeginPlay()
{
if (Role != ROLE_Authority)
return;
ADefaultGameMode* mode = Cast<ADefaultGameMode>(GetWorld()->GetAuthGameMode());
if (mode)
mode->RegisterPlayerSpawn(*this);
}

View File

@@ -0,0 +1,25 @@
// Project Lab - NHTV Igad
#pragma once
#include "GameFramework/Actor.h"
#include "PlayerSpawn.generated.h"
UCLASS()
class UNREALPROJECT_API APlayerSpawn : public AActor
{
GENERATED_BODY()
public:
APlayerSpawn();
virtual void BeginPlay() override;
UPROPERTY(EditAnywhere, Category = "Gamestate Components")
int32 assignedTeam;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Display)
class UStaticMeshComponent* displayMesh;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Display)
class UArrowComponent* displayArrow;
};

View File

@@ -0,0 +1,476 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "NetworkSwitchComponent.h"
#include "CreatureSpawnComponent.h"
#include "DefaultGameMode.h"
#include "SpawnerBase.h"
#include "NPCBase.h"
#include "NetworkCharacter.h"
#include "NetworkPlayer.h"
#include "EnemyBase.h"
#include "GeneralEnemy.h"
#include "MiniBossCreature.h"
ASpawnerBase::ASpawnerBase()
{
PrimaryActorTick.bCanEverTick = true;
USceneComponent* spawnerRoot = CreateDefaultSubobject<USceneComponent>("Spawner Root");
RootComponent = spawnerRoot;
displayMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
displayMesh->bHiddenInGame = true;
displayMesh->bGenerateOverlapEvents = false;
displayMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
displayMesh->AttachTo(RootComponent);
// Kill particle effect
killParticle = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Kill Particle1"));
killParticle->AttachTo(RootComponent);
displayArrow = CreateDefaultSubobject<UArrowComponent>(TEXT("Arrow"));
displayArrow->AttachTo(displayMesh);
displayDoors = CreateDefaultSubobject<UNetworkSwitchComponent>(TEXT("Visualizer"));
displayDoors->AttachTo(displayMesh);
visualizerComponent = CreateDefaultSubobject<UCreatureSpawnComponent>(TEXT("Control points visualizer"));
visualizerComponent->AttachTo(displayMesh);
team = NPCTeam::Team1;
aggroRadius = 800;
deaggroRadius = aggroRadius;
m_mobCount = 0;
formationScale = 1.0f;
formationDistance = 100;
formationRadius = 100;
resetTimer = 30;
dropKeyFragmentIndex = 0;
hasDroppedKey = false;
bReplicates = true;
bAlwaysRelevant = true;
}
void ASpawnerBase::BeginPlay()
{
Super::BeginPlay();
TArray<AActor*> test;
GetAttachedActors(test);
for (int i = 0; i < test.Num(); i++)
{
if (Cast<ANPCBase>(test[i]))
{
spawns.Add(test[i]->GetClass());
formationPoints.Add(FVector2D(test[i]->GetActorLocation() - GetActorLocation()));
formationRotation.Add(test[i]->GetActorRotation().Yaw);
//RPRINT("mobs" + spawns[i]->GetName());
if (Role == ROLE_Authority)
{
Cast<ANPCBase>(test[i])->UnsetSpawn();
}
(test[i])->Destroy();
(test[i]) = nullptr;
}
else
{
SpawnLocation.Add(test[i]);
}
}
for (int32 i = 0; i < spawns.Num(); i++)
m_mobs.Add(nullptr);
m_threatMap.SetNum(m_mobs.Num());
for (int i = 0; i < spawns.Num(); i++)
{
if (i != 0 && spawns[i]->IsChildOf(AGeneralEnemy::StaticClass()))
{
Swap(spawns[i], spawns[0]);
Swap(formationPoints[i], formationPoints[0]);
Swap(formationRotation[i], formationRotation[0]);
}
}
TArray<FHitResult> hitResult;
GetWorld()->LineTraceMultiByChannel(hitResult, GetActorLocation(), GetActorLocation() + GetActorUpVector()*-10000.0f, ECollisionChannel::ECC_WorldStatic, FCollisionQueryParams(FName(L"spawnerPlacementTrace"),true));
bool hit = false;
float distance = BIG_NUMBER;
FVector impactLocation;
for (int i = 0; i < hitResult.Num(); i++)
{
if (FVector::Dist(FVector(hitResult[i].ImpactPoint), GetActorLocation()) < distance&&FVector(hitResult[i].ImpactPoint)!= GetActorLocation())
{
distance = FVector::Dist(FVector(hitResult[i].ImpactPoint), GetActorLocation());
impactLocation = FVector(hitResult[i].ImpactPoint);
hit = true;
}
}
// Correct spawner position when it can move to the ground below it
if (hit)
{
this->SetActorLocation(FVector(GetActorLocation().X, GetActorLocation().Y, impactLocation.Z));
}
for (int i = 0; i < formationPoints.Num(); i++)
{
formationPoints[i] = FVector2D(GetActorRotation().RotateVector(FVector(formationPoints[i].X, formationPoints[i].Y, 0)));
formationPoints[i] *= formationScale;
}
if (spawns.Num() > formationPoints.Num())
{
int difference = spawns.Num() - formationPoints.Num();
for (int i = 0; i < difference; i++)
{
formationPoints.Add(FVector2D());
}
}
if (spawns.Num() > formationRotation.Num())
{
int difference = spawns.Num() - formationRotation.Num();
for (int i = 0; i < difference; i++)
{
formationRotation.Add(0);
}
}
}
void ASpawnerBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if (Role != ROLE_Authority)
return;
for (int32 i = 0; i < m_mobs.Num(); i++)
{
if (m_mobs[i])
{
m_mobs[i]->UnsetSpawn();
m_mobs[i] = nullptr;
}
}
formationEnemies.Empty();
m_nearbyPlayers.clear();
}
void ASpawnerBase::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// if (formationEnemies.Num() > spawns.Num())
// formationEnemies.Empty();
bool reset = false;
m_resetTimer -= DeltaTime;
if (m_resetTimer <= 0)
{
reset = true;
}
for (int i = 0; i < m_mobs.Num(); i++)
{
if (m_mobs[i] == nullptr)
continue;
if (reset)
{
ForceResetTarget(m_mobs[i]);
}
if (m_mobs[i]->IsA(AEnemyBase::StaticClass()))
{
Cast<AEnemyBase>(m_mobs[i])->hasGeneral = hasGeneral;
}
if (m_mobs[i]->IsA(AGeneralEnemy::StaticClass()))
{
AGeneralEnemy* asGeneral = Cast<AGeneralEnemy>(m_mobs[i]);
if (formationEnemies != asGeneral->formationEnemies)
{
asGeneral->formationEnemies = formationEnemies;
}
}
}
}
int32 ASpawnerBase::OnMobDie(class ANPCBase* mob)
{
check(m_mobCount > 0);
check(Role == ROLE_Authority);
int32 idx = -1;
for (int32 i = 0; i < spawns.Num(); i++)
{
if (m_mobs[i] == mob)
{
if (m_mobs[i]->IsA(AGeneralEnemy::StaticClass()))
{
formationEnemies.Empty();
}
if (m_mobs[i]->IsA(AEnemyBase::StaticClass()))
{
AEnemyBase* asEnemyBase = Cast<AEnemyBase>(m_mobs[i]);
if (asEnemyBase->hasGeneral)
formationEnemies.Remove(asEnemyBase);
}
m_mobCount--;
if(m_mobCount == 0)
{
OnCampCleared();
}
m_mobs[i] = nullptr;
idx = i;
m_threatMap[i].clear();
break;
}
}
check(idx >= 0);
return idx;
}
void ASpawnerBase::OnCampCleared_Implementation()
{
if(killParticle->Template)
{
killParticle->ResetParticles();
killParticle->ActivateSystem();
}
m_OnCampCleared();
}
int32 ASpawnerBase::GetAliveMobCount()
{
return m_mobCount;
}
FVector ASpawnerBase::SpawnResetPosition()
{
return GetActorLocation();
}
void ASpawnerBase::m_OnPlayerEnterOverlap(class ANetworkCharacter& player)
{
auto find = m_nearbyPlayers.find(&player);
if (find != m_nearbyPlayers.end())
return;
ANetworkPlayer* playerCast = Cast<ANetworkPlayer>(&player);
if (IsValid(playerCast))
{
playerCast->AddThreatLevel_Client(threatLevel);
}
// Player was succesfully added
m_nearbyPlayers.emplace(&player);
//adding the threat to all mobs
/* for (int32 i = 0; i < m_mobs.Num(); i++)
{
if (m_mobs[i] == nullptr)
continue;
// auto ret = m_threatMap[i].emplace(&player, 0);
if (!ret.second)
{
FPRINT("failed to add player to creaturemap ");
}
}*/
}
void ASpawnerBase::m_OnPlayerExitOverlap(class ANetworkCharacter& player)
{
auto find = m_nearbyPlayers.find(&player);
if (find == m_nearbyPlayers.end())
{
FERROR("leaving player was not found in the nearbyPlayers");
return;
}
ANetworkPlayer* playerCast = Cast<ANetworkPlayer>(&player);
if (IsValid(playerCast))
{
playerCast->RemoveThreatLevel_Client(threatLevel);
}
// Player was succesfully removed
m_nearbyPlayers.erase(find);
}
class ANetworkPlayer* ASpawnerBase::m_GetBiggestThreat(int32 index)
{
ANetworkPlayer* ret = nullptr;
int32 biggestThreat = -1;
for (auto cpair : m_threatMap[index])
{
if (cpair.second > biggestThreat)
{
biggestThreat = cpair.second;
ret = cpair.first;
}
}
return ret;
}
void ASpawnerBase::m_OnMobSpawn(int32 index)
{
ANPCBase* creature = m_mobs[index];
if (creature == nullptr)
{
FWARNING("creature is null at spawn");
return;
}
if (creature->IsA(AGeneralEnemy::StaticClass()))
{
AGeneralEnemy* asGeneral = Cast<AGeneralEnemy>(creature);
asGeneral->formationPoints = formationPoints;
}
else
{
if (creature->IsA(AEnemyBase::StaticClass()))
formationEnemies.Add(Cast<AEnemyBase>(creature));
}
m_threatMap[index].clear();
/* for (ANetworkPlayer* player : m_nearbyPlayers)
{
auto ret = m_threatMap[index].insert(std::pair<ANetworkPlayer*, int32>(player, 0));
if (!ret.second)
{
FPRINT("adding failed");
}
}*/
if (creature->IsA(AMiniBossCreature::StaticClass()) && dropKeyFragmentIndex >= keyFragmentMin && dropKeyFragmentIndex <= keyFragmentMax)
Cast<AMiniBossCreature>(creature)->keyDropped = PlayerKeyType(dropKeyFragmentIndex);
}
class ANetworkPlayer* ASpawnerBase::GetClosestPlayer()
{
if (m_nearbyPlayers.empty())
return nullptr;
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;
const float aggroSqr = aggroRadius * aggroRadius;
for (ANetworkCharacter* character :m_nearbyPlayers)
{
ANetworkPlayer *player = Cast<ANetworkPlayer>(character);
if (player)
{
// ANetworkPlayer* player = Cast<ANetworkPlayer>(*iter);
const float distSqr = FVector2D::DistSquared(FVector2D(this->GetActorLocation()), FVector2D(player->GetActorLocation()));
if (distSqr < closestDist && distSqr <= aggroSqr)
{
closest = player;
closestDist = distSqr;
}
}
}
return closest;
}
void ASpawnerBase::AddThreat(class ANPCBase* creature, class ANetworkPlayer* character, int32 threat)
{
if (creature == nullptr || creature->IsPendingKill() || character == nullptr || character->IsPendingKill())
return;
//find the creaturemap
int32 index = 0;
bool found = false;
for (ANPCBase* mob : m_mobs)
{
if (creature == mob)
{
found = true;
break;
}
index++;
}
if (!found)
{
FERROR("creature not part of threatMap");
return;
}
//find the player
map<class ANetworkPlayer*, int32>::iterator it = m_threatMap[index].find(character);
if (it == m_threatMap[index].end())
{
FERROR("character not part of creatureMap");
return;
}
it->second += threat;
}
void ASpawnerBase::GetNewTarget(class ANPCBase* mob)
{
return;
}
void ASpawnerBase::ForceResetTarget(class ANPCBase* mob)
{
mob->target = nullptr;
}
void ASpawnerBase::ForceSetTarget(class ANPCBase* mob,class ANetworkPlayer* target)
{
mob->target = target;
}
void ASpawnerBase::SetTeam(int newTeam)
{
team = (NPCTeam)newTeam;
for (int i = 0; i < m_mobs.Num(); i++)
{
if (!IsValid(m_mobs[i]))
continue;
m_mobs[i]->SetTeam(newTeam);
if (!m_mobs[i]->target)
continue;
if(m_mobs[i]->target->GetTeam() == newTeam)
m_mobs[i]->target = nullptr;
}
}
void ASpawnerBase::CaptureCamp(int team)
{
SetTeam(team);
}
TArray<ANetworkPlayer*> ASpawnerBase::GetNearbyPlayers()
{
TArray<ANetworkPlayer*> players;
for(ANetworkCharacter* character : m_nearbyPlayers)
{
ANetworkPlayer* player = Cast<ANetworkPlayer>(character);
if(player)
{
players.Add(player);
}
}
return players;
}
void ASpawnerBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ASpawnerBase, team);
}

View File

@@ -0,0 +1,126 @@
// Project Lab - NHTV Igad
#pragma once
#include "GameFramework/Actor.h"
#include <unordered_set>
#include <map>
using std::unordered_set;
using std::map;
#include "SpawnerBase.generated.h"
UENUM(BlueprintType)
enum class NPCTeam : uint8
{
Team1 = 50,
};
UCLASS()
class ASpawnerBase : public AActor
{
GENERATED_BODY()
public:
ASpawnerBase();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float DeltaTime) override;
virtual void GetNewTarget(class ANPCBase* mob);
UFUNCTION(BlueprintCallable, Category="Capture")
virtual void CaptureCamp(int team);
void ForceSetTarget(class ANPCBase* mob,class ANetworkPlayer* target);
void ForceResetTarget(class ANPCBase* mob);
void SetTeam(int team);
class ANetworkPlayer* GetClosestPlayer();
// Call when the camp is killed entirely
UFUNCTION(NetMulticast, Reliable)
void OnCampCleared();
void AddThreat(class ANPCBase* creature, class ANetworkPlayer* character, int32 threat);
virtual int32 OnMobDie(class ANPCBase* mob);
virtual FVector SpawnResetPosition();
int32 GetAliveMobCount();
// m_nearbyPlayers but as ANetworkPlayer array instead of ANetworkCharacter's
TArray<class ANetworkPlayer*> GetNearbyPlayers();
UPROPERTY(EditAnywhere)
float aggroRadius;
UPROPERTY(EditAnywhere)
float deaggroRadius;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FMod")
float threatLevel;
UPROPERTY(EditAnywhere, Replicated)
NPCTeam team;
UPROPERTY(EditAnywhere)
FColor debugColorCode;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Display)
class UStaticMeshComponent* displayMesh;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Display)
class UArrowComponent* displayArrow;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Display)
class UNetworkSwitchComponent* displayDoors;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Kill Particle")
UParticleSystemComponent* killParticle;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<TSubclassOf<class ANPCBase>> spawns;
UPROPERTY(EditAnywhere, Category = "Spawn Settings")
float drawingRadius;
UPROPERTY(EditAnywhere, Category = "Spawn Settings")
float collisionScaler;
UPROPERTY(EditAnywhere, Category = "Spawn Settings")
float resetTimer;
UPROPERTY(EditAnywhere, Category = "Spawn Settings")
bool possesable;
UPROPERTY(EditAnywhere, Category = "Spawn Settings")
TArray<AActor*> SpawnLocation;
bool isConnected;
UPROPERTY(EditAnywhere, Category = "Switch Components")
class UCreatureSpawnComponent* visualizerComponent;
UPROPERTY(EditAnywhere, Category = "ControlPoints Settings")
TArray<FVector2D> controlPoints;
UPROPERTY(EditAnywhere, Category = "Formation Settings")
float formationDistance;
UPROPERTY(EditAnywhere, Category = "Formation Settings")
float formationRadius;
TArray<FVector2D> formationPoints;
TArray<float> formationRotation;
UPROPERTY(EditAnywhere, Category = "Formation Settings")
float formationScale;
TArray<class AEnemyBase*> formationEnemies;
bool hasGeneral;
UPROPERTY(EditAnywhere, Category = "Miniboss")
int32 dropKeyFragmentIndex;
bool hasDroppedKey;
TArray<class ANPCBase*> m_mobs;
protected:
virtual void m_OnCampCleared() {};
virtual void m_OnPlayerEnterOverlap(class ANetworkCharacter& player);
virtual void m_OnPlayerExitOverlap(class ANetworkCharacter& player);
class ANetworkPlayer* m_GetBiggestThreat(int32 index);
void m_OnMobSpawn(int32 index);
int32 m_mobCount;
unordered_set<class ANetworkCharacter*> m_nearbyPlayers;
TArray<map<class ANetworkPlayer*, int32>> m_threatMap;
float m_resetTimer;
//float formationDistance = 0;
//float formationRadius = 0;
};