Implemented Bounty Class Functionality

This commit is contained in:
Rafal Swierczek 2023-09-27 16:43:33 +01:00
parent 44e0a6bc2d
commit 52af66afec
3 changed files with 229 additions and 10 deletions

View File

@ -11,17 +11,120 @@ ABountyClass::ABountyClass()
} }
// Called when the game starts or when spawned
void ABountyClass::BeginPlay() void ABountyClass::BeginPlay()
{ {
Super::BeginPlay(); Super::BeginPlay();
SpawnCheckpoints();
} }
// Called every frame
void ABountyClass::Tick(float DeltaTime) void ABountyClass::Tick(float DeltaTime)
{ {
Super::Tick(DeltaTime); Super::Tick(DeltaTime);
} }
void ABountyClass::SpawnCheckpoints()
{
// Spawn all checkpoints associated with this bounty and store them in order
FActorSpawnParameters SpawnParameters;
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
for(TSubclassOf<ACheckpointClass> CheckpointClass : CheckpointsToSpawn)
{
if (CheckpointClass == nullptr)
{
// An unassigned checkpoint class can lead to undefined behaviour, hence the fatal log
UE_LOG(LogTemp, Fatal, TEXT("A checkpoint class wasn't set for %s"), *BountyTitle);
return;
}
FVector Loc = CheckpointClass.GetDefaultObject()->GetCheckpointSpawnTransform().GetLocation();
FRotator Rot = CheckpointClass.GetDefaultObject()->GetCheckpointSpawnTransform().GetRotation().Rotator();
ACheckpointClass* SpawnedCheckpoint = Cast<ACheckpointClass>(GetWorld()->SpawnActor<AActor>(CheckpointClass, Loc, Rot, SpawnParameters));
BountyCheckpoints.Add(SpawnedCheckpoint);
}
// Activate the first checkpoint and listen for its completion
BountyCheckpoints[0]->Active = true;
BountyCheckpoints[0]->CompletedCheckpoint.AddDynamic(this, &ABountyClass::IncrementBountyCheckpoint);
}
void ABountyClass::IncrementBountyCheckpoint()
{
// Broadcast that the first Checkpoint has been completed so that side bounties can be destroyed
if (!BountyStarted)
{
BountyStarted = true;
CompletedFirstCheckpoint.Broadcast();
}
// Bounty Completion Condition
if (BountyCheckpoints.Num() <= MinCPsRequiredForCompletion)
{
Completed = true;
BountyCheckpoints[0]->Active = false;
BountyCheckpoints[0]->Destroy();
BountyCheckpoints.RemoveAt(0);
UE_LOG(LogTemp, Warning, TEXT(" You've Completed the Bounty!! Well done"));
return;
}
if (BountyCheckpoints[0] == nullptr)
{
UE_LOG(LogTemp, Fatal, TEXT("Missing checkpoint in bounty checkpoints, could've failed to spawn or cast"));
return;
}
// Destroy Actor and Shrink Array
BountyCheckpoints[0]->Active = false;
BountyCheckpoints[0]->Destroy();
BountyCheckpoints.RemoveAt(0);
// Set the new checkpoint in pos 0 to be active and listen for it's completion
BountyCheckpoints[0]->Active = true;
BountyCheckpoints[0]->CompletedCheckpoint.AddDynamic(this, &ABountyClass::IncrementBountyCheckpoint);
}
void ABountyClass::CollectRewards_Implementation()
{
UE_LOG(LogTemp, Warning, TEXT("The player has gained $%d for completing the bounty!"), RewardMoney);
}
void ABountyClass::UpdateBountyCheckpoints(TMap<int, TSubclassOf<ACheckpointClass>> ReplacementCheckpoints)
{
if (ReplacementCheckpoints.IsEmpty())
{
UE_LOG(LogTemp, Warning, TEXT("No Replacement Steps found"));
return;
}
FActorSpawnParameters SpawnParameters;
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
for (auto ReplacementCheckpoint : ReplacementCheckpoints)
{
BountyCheckpoints[ReplacementCheckpoint.Key]->Destroy();
ReplacementCheckpointClass = ReplacementCheckpoint.Value;
FVector Loc = ReplacementCheckpointClass.GetDefaultObject()->GetCheckpointSpawnTransform().GetLocation();
FRotator Rot = ReplacementCheckpointClass.GetDefaultObject()->GetCheckpointSpawnTransform().GetRotation().Rotator();
ACheckpointClass* SpawnedCheckpoint = Cast<ACheckpointClass>(GetWorld()->SpawnActor<AActor>(ReplacementCheckpoint.Value, Loc, Rot, SpawnParameters));
if (SpawnedCheckpoint == nullptr)
{
UE_LOG(LogTemp, Fatal, TEXT("The new checkpoint hasn't spawned in properly or can't be cast to"));
return;
}
BountyCheckpoints[ReplacementCheckpoint.Key] = SpawnedCheckpoint;
if (ReplacementCheckpoint.Key == 0)
{
BountyCheckpoints[ReplacementCheckpoint.Key]->Active = true;
BountyCheckpoints[ReplacementCheckpoint.Key]->CompletedCheckpoint.AddDynamic(this, &ABountyClass::IncrementBountyCheckpoint);
}
}
}

View File

@ -3,24 +3,140 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "CheckpointClass.h"
#include "GameFramework/Actor.h" #include "GameFramework/Actor.h"
#include "BountyClass.generated.h" #include "BountyClass.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FCompletedFirstCheckpoint)
UCLASS() UCLASS()
class ENDLESSVENDETTA_API ABountyClass : public AActor class ENDLESSVENDETTA_API ABountyClass : public AActor
{ {
GENERATED_BODY() GENERATED_BODY()
public: // Used to temp store value of incoming replacement checkpoint class
// Sets default values for this actor's properties TSubclassOf<ACheckpointClass> ReplacementCheckpointClass;
ABountyClass();
bool BountyStarted = false;
protected: protected:
// ------- Properties Set in Editor --------------
UPROPERTY(EditDefaultsOnly, Category = "Bounty")
TArray<TSubclassOf<ACheckpointClass>> CheckpointsToSpawn;
UPROPERTY(EditDefaultsOnly, Category = "Bounty")
int RewardMoney = 0;
UPROPERTY(EditDefaultsOnly, Category = "Bounty")
FString BountyTitle;
UPROPERTY(EditDefaultsOnly, Category = "Bounty")
FString BountyDesc;
// -----------------------------------------------
bool Completed = false;
/**
* Default is 2 as final step in most Bounties is to return to ship,
* which can't be completed. Change to 1 if that's not the case.
*/
int MinCPsRequiredForCompletion = 2;
// Spawned in Checkpoints for this Bounty
TArray<ACheckpointClass*> BountyCheckpoints;
// Spawns and stores this Bounties Checkpoints in order
void SpawnCheckpoints();
// Called when the game starts or when spawned // Called when the game starts or when spawned
virtual void BeginPlay() override; virtual void BeginPlay() override;
public: public:
// Broadcast when first checkpoint from this bounty is completed
FCompletedFirstCheckpoint CompletedFirstCheckpoint;
// ------ Getters for Bounty and Checkpoint Properties ------
bool IsCompleted()
{
return Completed;
}
FString GetBountyTitle()
{
return BountyTitle;
}
FString GetBountyDesc()
{
return BountyDesc;
}
FVector GetCheckpointLocation()
{
if (BountyCheckpoints.IsEmpty() || BountyCheckpoints[0] == nullptr)
{
return FVector(0, 0, 0);
}
return BountyCheckpoints[0]->GetCheckpointSpawnTransform().GetLocation();
}
FVector GetActiveWaypointLocation()
{
if (BountyCheckpoints.IsEmpty() || BountyCheckpoints[0] == nullptr)
{
return FVector(0, 0, 0);
}
return BountyCheckpoints[0]->GetWaypointLoc();
}
UTexture2D* GetActiveWaypointIcon()
{
if (BountyCheckpoints.IsEmpty() || BountyCheckpoints[0] == nullptr)
{
return nullptr;
}
return BountyCheckpoints[0]->GetWaypointIcon();
}
FString GetCheckpointDescription()
{
if (BountyCheckpoints.IsEmpty() || BountyCheckpoints[0] == nullptr)
{
return FString("No more Bounty checkpoints, check BountyClass.h GetCheckpointDescription()");
}
return BountyCheckpoints[0]->GetCheckpointDesc();
}
// ----------------------------------------------------------
// Sets default values for this actor's properties
ABountyClass();
// Called every frame // Called every frame
virtual void Tick(float DeltaTime) override; virtual void Tick(float DeltaTime) override;
// Called when a checkpoint is completed, handles moving onto next checkpoint and discarding the old one
UFUNCTION()
virtual void IncrementBountyCheckpoint();
// Collect Money in C++, any other special reward will be implemented in BP if neccessary
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
void CollectRewards();
void DestroyReturnToShipStep()
{
if (BountyCheckpoints.Num() > 1)
{
UE_LOG(LogTemp, Warning, TEXT("Didn't Destroy final step as more than one steps still left in Bounty"));
}
BountyCheckpoints[0]->Destroy();
}
// Called by Bounty Director, replaces specified checkpoints to alter Bounty when player completes a side bounty
void UpdateBountyCheckpoints(TMap<int, TSubclassOf<ACheckpointClass>> ReplacementCheckpoints);
}; };