Added Game Code Base

This commit is contained in:
Philip W 2023-03-18 01:48:33 +00:00
parent c08d8291e4
commit 10ca9843a2
95 changed files with 1525 additions and 71 deletions

View File

@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/modules.xml
/.idea.COMP250_1_2101327_AI.iml
/projectSettingsUpdater.xml
/contentModel.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="ASK" />
<option name="description" value="" />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Azos/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Iroquoid/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Probertium/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -1,6 +1,6 @@
[/Script/EngineSettings.GameMapsSettings]
GameDefaultMap=/Game/ThirdPerson/Maps/ThirdPersonMap.ThirdPersonMap
EditorStartupMap=/Game/ThirdPerson/Maps/ThirdPersonMap.ThirdPersonMap
GameDefaultMap=/Game/Main.Main
EditorStartupMap=/Game/Main.Main
GlobalDefaultGameMode="/Script/COMP250_1_2101327_AI.COMP250_1_2101327_AIGameMode"
[/Script/Engine.RendererSettings]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
COMP250_1_2101327_AI/Content/BungeeMan/CR_BungeeMan.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
COMP250_1_2101327_AI/Content/BungeeMan/Main.umap (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
COMP250_1_2101327_AI/Content/BungeeMan/SKM_BungeeMan.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
COMP250_1_2101327_AI/Content/BungeeMan/SK_BungeeMan.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
COMP250_1_2101327_AI/Content/Fonts/Adistro-8MePB.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
COMP250_1_2101327_AI/Content/Fonts/Adistro-8MePB_Font.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
COMP250_1_2101327_AI/Content/Fonts/Adistro-Font.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
COMP250_1_2101327_AI/Content/Fonts/Adistro_Font.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
COMP250_1_2101327_AI/Content/Fonts/Hachicro.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
COMP250_1_2101327_AI/Content/Fonts/Hachicro_Font.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
COMP250_1_2101327_AI/Content/Images/Status/Buffs/glow.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
COMP250_1_2101327_AI/Content/Main.umap (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,32 @@
[/Script/HoloLensPlatformEditor.HoloLensTargetSettings]
bBuildForEmulation=False
bBuildForDevice=True
bUseNameForLogo=True
bBuildForRetailWindowsStore=False
bAutoIncrementVersion=False
bShouldCreateAppInstaller=False
AppInstallerInstallationURL=
HoursBetweenUpdateChecks=0
bEnablePIXProfiling=False
TileBackgroundColor=(B=64,G=0,R=0,A=255)
SplashScreenBackgroundColor=(B=64,G=0,R=0,A=255)
+PerCultureResources=(CultureId="",Strings=(PackageDisplayName="",PublisherDisplayName="",PackageDescription="",ApplicationDisplayName="",ApplicationDescription=""),Images=())
TargetDeviceFamily=Windows.Holographic
MinimumPlatformVersion=
MaximumPlatformVersionTested=10.0.18362.0
MaxTrianglesPerCubicMeter=500.000000
SpatialMeshingVolumeSize=20.000000
CompilerVersion=Default
Windows10SDKVersion=10.0.18362.0
+CapabilityList=internetClientServer
+CapabilityList=privateNetworkClientServer
+Uap2CapabilityList=spatialPerception
bSetDefaultCapabilities=False
SpatializationPlugin=
SourceDataOverridePlugin=
ReverbPlugin=
OcclusionPlugin=
SoundCueCookQualityIndex=-1

View File

@ -8,6 +8,8 @@ public class COMP250_1_2101327_AI : ModuleRules
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "EnhancedInput" });
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "EnhancedInput", "Niagara", "UMG", "AIModule" });
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
}
}

View File

@ -0,0 +1,32 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "PlayerCharacter.h"
// Sets default values
APlayerCharacter::APlayerCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void APlayerCharacter::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void APlayerCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}

View File

@ -0,0 +1,31 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "PlayerCharacter.generated.h"
UCLASS()
class COMP250_1_2101327_AI_API APlayerCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
APlayerCharacter();
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float Health = 100.0f;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};

View File

@ -0,0 +1,59 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "StatusEffect.h"
#include "StatusSystem.h"
#include "Kismet/GameplayStatics.h"
#include "TurnBaseCombatV2.h"
#include "Components/TextBlock.h"
void UStatusEffect::Invoke(AActor* Character, float TimeOfInit)
{
GetWorld()->GetTimerManager().SetTimer(ExpiryTimerHandle, [this, Character, TimeOfInit] { CheckForExpiry(TimeOfInit, Character); }, 1, true, 0);
}
void UStatusEffect::OnExpiry(AActor* Character)
{
GetWorld()->GetTimerManager().ClearTimer(ExpiryTimerHandle);
UStatusSystem* StatusSystem = Cast<UStatusSystem>(Character->GetComponentByClass(UStatusSystem::StaticClass()));
if (StatusSystem->GetActiveStatusEffect(this).StatusIcon == nullptr) return;
StatusSystem->GetActiveStatusEffect(this).StatusIcon->RemoveFromParent();
StatusSystem->RemoveStatusEffect(this);
ATurnBaseCombatV2* CombatSystem = Cast<ATurnBaseCombatV2>(GetWorld()->GetGameState());
CombatSystem->OnPlayerTurn.Remove(OnPlayerTurnDelegateHandle);
CombatSystem->OnEnemyTurn.Remove(OnEnemyTurnDelegateHandle);
}
void UStatusEffect::OnPlayerTurn(AActor* Character, AActor* Enemy)
{
return;
}
void UStatusEffect::OnEnemyTurn(AActor* Enemy, AActor* Character)
{
TickDown(Character);
}
void UStatusEffect::OnStatusEffectAdd(AActor* Character)
{
ATurnBaseCombatV2* CombatSystem = Cast<ATurnBaseCombatV2>(GetWorld()->GetGameState());
OnPlayerTurnDelegateHandle = CombatSystem->OnPlayerTurn.AddUObject(this, &UStatusEffect::OnPlayerTurn);
OnEnemyTurnDelegateHandle = CombatSystem->OnEnemyTurn.AddUObject(this, &UStatusEffect::OnEnemyTurn);
}
void UStatusEffect::TickDown(AActor* Character)
{
UStatusSystem* StatusSystem = Cast<UStatusSystem>(Character->GetComponentByClass(UStatusSystem::StaticClass()));
UTextBlock* StatusText = Cast<UTextBlock>(StatusSystem->GetActiveStatusEffect(this).StatusIcon->GetWidgetFromName(TEXT("DurationText")));
StatusText->SetText(FText::FromString(FString::FromInt(BaseDuration)));
}
void UStatusEffect::CheckForExpiry(const float TimeOfExpiry, AActor* Character)
{
if (TimeOfExpiry <= UGameplayStatics::GetRealTimeSeconds(GetWorld())) OnExpiry(Character);
UStatusSystem* StatusSystem = Cast<UStatusSystem>(Character->GetComponentByClass(UStatusSystem::StaticClass()));
if (StatusSystem->GetActiveStatusEffect(this).StatusIcon == nullptr) return;
UTextBlock* StatusText = Cast<UTextBlock>(StatusSystem->GetActiveStatusEffect(this).StatusIcon->GetWidgetFromName(TEXT("DurationText")));
StatusText->SetText(FText::FromString(FString::FromInt(TimeOfExpiry - UGameplayStatics::GetRealTimeSeconds(GetWorld()))));
}

View File

@ -0,0 +1,53 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "StatusEffect.generated.h"
/**
*
*/
UCLASS(Abstract, Blueprintable)
class COMP250_1_2101327_AI_API UStatusEffect : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Name;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Description;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool IsForCombatOnly = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float BaseDuration;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UTexture2D* Icon;
UFUNCTION()
virtual void Invoke(AActor* Character, float TimeOfExpiry);
UFUNCTION()
virtual void OnExpiry(AActor* Character);
UFUNCTION()
virtual void OnPlayerTurn(AActor* Character, AActor* Enemy);
UFUNCTION()
virtual void OnEnemyTurn(AActor* Enemy, AActor* Character);
UFUNCTION()
virtual void OnStatusEffectAdd(AActor* Character);
UFUNCTION()
virtual void TickDown(AActor* Character);
protected:
UPROPERTY()
FTimerHandle ExpiryTimerHandle;
UFUNCTION()
void CheckForExpiry(float TimeOfExpiry, AActor* Character);
FDelegateHandle OnPlayerTurnDelegateHandle;
FDelegateHandle OnEnemyTurnDelegateHandle;
};

View File

@ -0,0 +1,17 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "DamageOverTime.h"
#include "COMP250_1_2101327_AI/TurnBasedCombatV2/TurnBaseCombatV2.h"
void UDamageOverTime::OnEnemyTurn(AActor* Enemy, AActor* Character)
{
ATurnBaseCombatV2* CombatSystem = Cast<ATurnBaseCombatV2>(GetWorld()->GetGameState());
CombatSystem->DamageEnemy(DamagePerTurn, "DOT");
BaseDuration -= 1.0f;
Super::OnEnemyTurn(Enemy, Character);
if (BaseDuration <= 0.0f)
{
OnExpiry(Character);
}
}

View File

@ -0,0 +1,23 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "../StatusEffect.h"
#include "DamageOverTime.generated.h"
/**
*
*/
UCLASS()
class COMP250_1_2101327_AI_API UDamageOverTime : public UStatusEffect
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float DamagePerTurn = 6.0f;
//virtual void Invoke(AActor* Character, float TimeOfExpiry) override;
//virtual void OnExpiry(AActor* Character) override;
virtual void OnEnemyTurn(AActor* Enemy, AActor* Character) override;
};

View File

@ -0,0 +1,30 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "HealOverTime.h"
#include "COMP250_1_2101327_AI/Player/PlayerCharacter.h"
void UHealOverTime::Heal(AActor* Character, const float Amount) const
{
if (APlayerCharacter* CastedCharacter = Cast<APlayerCharacter>(Character); CastedCharacter->Health < 100)
{
CastedCharacter->Health += Amount;
}
else
{
CastedCharacter->Health = 100;
}
}
void UHealOverTime::Invoke(AActor* Character, float TimeOfExpiry)
{
Super::Invoke(Character, TimeOfExpiry);
GetWorld()->GetTimerManager().SetTimer(HealTimerHandle, [this, Character] { Heal(Character, 1); }, 1, true, 0);
}
void UHealOverTime::OnExpiry(AActor* Character)
{
GetWorld()->GetTimerManager().ClearTimer(HealTimerHandle);
Super::OnExpiry(Character);
}

View File

@ -0,0 +1,25 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "../StatusEffect.h"
#include "HealOverTime.generated.h"
/**
*
*/
UCLASS()
class COMP250_1_2101327_AI_API UHealOverTime : public UStatusEffect
{
GENERATED_BODY()
protected:
UFUNCTION()
void Heal(AActor* Character, float Amount) const;
public:
FTimerHandle HealTimerHandle;
virtual void Invoke(AActor* Character, float TimeOfExpiry) override;
virtual void OnExpiry(AActor* Character) override;
};

View File

@ -0,0 +1,28 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Thorns.h"
#include "COMP250_1_2101327_AI/TurnBasedCombatV2/TurnBaseCombatV2.h"
void UThorns::Invoke(AActor* Character, float TimeOfExpiry)
{
Super::Invoke(Character, TimeOfExpiry);
}
void UThorns::OnExpiry(AActor* Character)
{
Super::OnExpiry(Character);
}
void UThorns::OnEnemyTurn(AActor* Enemy, AActor* Character)
{
ATurnBaseCombatV2* CombatSystem = Cast<ATurnBaseCombatV2>(GetWorld()->GetGameState());
CombatSystem->DamageEnemy(DamagePerTurn, "thorns");
BaseDuration -= 1.0f;
Super::OnEnemyTurn(Enemy, Character);
if (BaseDuration <= 0.0f)
{
OnExpiry(Character);
}
}

View File

@ -0,0 +1,24 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "../StatusEffect.h"
#include "Thorns.generated.h"
/**
*
*/
UCLASS()
class COMP250_1_2101327_AI_API UThorns : public UStatusEffect
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float DamagePerTurn = 3.0f;
virtual void Invoke(AActor* Character, float TimeOfExpiry) override;
virtual void OnExpiry(AActor* Character) override;
virtual void OnEnemyTurn(AActor* Enemy, AActor* Character) override;
};

View File

@ -0,0 +1,86 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "StatusSystem.h"
#include <Runtime/Engine/Classes/Kismet/GameplayStatics.h>
#include "Blueprint/UserWidget.h"
#include "Components/Image.h"
#include "Components/TextBlock.h"
// Sets default values for this component's properties
UStatusSystem::UStatusSystem()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
static ConstructorHelpers::FClassFinder<UUserWidget> HUDStatusIndicatorsWidgetClassFinder(TEXT("/Game/Blueprints/Status_UI/StatusIndicator"));
HUDStatusIndicatorsWidget = HUDStatusIndicatorsWidgetClassFinder.Class;
static ConstructorHelpers::FClassFinder<UUserWidget> HUDStatusIconWidgetClassFinder(TEXT("/Game/Blueprints/Status_UI/StatusIcon"));
HUDStatusIconWidget = HUDStatusIconWidgetClassFinder.Class;
}
// Called when the game starts
void UStatusSystem::BeginPlay()
{
Super::BeginPlay();
HUDStatusIndicators = CreateWidget<UUserWidget>(GetWorld(), HUDStatusIndicatorsWidget);
HUDStatusIndicators->AddToViewport();
StatusIconsBox = Cast<UWrapBox>(HUDStatusIndicators->GetWidgetFromName(TEXT("StatusIndicators")));
}
// Called every frame
void UStatusSystem::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}
void UStatusSystem::AddStatusEffect(UStatusEffect* StatusEffect, const float DurationMultiplier, const bool Invoke)
{
FActiveStatusEffect NewStatusEffect;
NewStatusEffect.StatusEffect = StatusEffect;
NewStatusEffect.TimeInitiated = UGameplayStatics::GetRealTimeSeconds(GetWorld());
if (StatusEffect->IsForCombatOnly)
{
NewStatusEffect.TimeTillExpiry = StatusEffect->BaseDuration * DurationMultiplier;
}
else
{
NewStatusEffect.TimeTillExpiry = UGameplayStatics::GetRealTimeSeconds(GetWorld()) + StatusEffect->BaseDuration * DurationMultiplier;
}
NewStatusEffect.StatusIcon = CreateWidget<UUserWidget>(GetWorld(), HUDStatusIconWidget);
UImage* StatusIconImage = Cast<UImage>(NewStatusEffect.StatusIcon->GetWidgetFromName(TEXT("StatusIconImage")));
StatusIconImage->SetBrushFromTexture(StatusEffect->Icon);
StatusIconsBox->AddChild(NewStatusEffect.StatusIcon);
NewStatusEffect.StatusEffect->OnStatusEffectAdd(GetOwner());
UTextBlock* StatusText = Cast<UTextBlock>(NewStatusEffect.StatusIcon->GetWidgetFromName(TEXT("DurationText")));
StatusText->SetText(FText::FromString(FString::FromInt(NewStatusEffect.TimeTillExpiry)));
if (Invoke) NewStatusEffect.StatusEffect->Invoke(GetOwner(), NewStatusEffect.TimeTillExpiry);
ActiveStatusEffects.Add(NewStatusEffect);
}
void UStatusSystem::RemoveStatusEffect(UStatusEffect* StatusEffect)
{
if (ActiveStatusEffects.Contains(FActiveStatusEffect{0, 0, StatusEffect, nullptr}))
{
ActiveStatusEffects.Remove(FActiveStatusEffect{0, 0, StatusEffect, nullptr});
}
else
{
UE_LOG(LogTemp, Warning, TEXT("StatusEffect not found in ActiveStatusEffects"));
}
}
FActiveStatusEffect UStatusSystem::GetActiveStatusEffect(UStatusEffect* StatusEffect)
{
if (ActiveStatusEffects.Contains(FActiveStatusEffect{0, 0, StatusEffect, nullptr}))
{
return ActiveStatusEffects[ActiveStatusEffects.Find(FActiveStatusEffect{0, 0, StatusEffect, nullptr})];
}
UE_LOG(LogTemp, Warning, TEXT("StatusEffect not found in ActiveStatusEffects"));
return FActiveStatusEffect();
}

View File

@ -0,0 +1,70 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "StatusEffect.h"
#include "Components/WrapBox.h"
#include "StatusSystem.generated.h"
USTRUCT()
struct FActiveStatusEffect
{
GENERATED_BODY()
UPROPERTY()
float TimeInitiated;
UPROPERTY()
float TimeTillExpiry;
UPROPERTY()
UStatusEffect* StatusEffect;
UPROPERTY()
UUserWidget* StatusIcon;
bool operator==(const FActiveStatusEffect& Comp) const
{
return StatusEffect == Comp.StatusEffect;
}
};
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class COMP250_1_2101327_AI_API UStatusSystem : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UStatusSystem();
UPROPERTY()
TSubclassOf<UUserWidget> HUDStatusIndicatorsWidget;
UPROPERTY()
TSubclassOf<UUserWidget> HUDStatusIconWidget;
UPROPERTY()
UUserWidget* HUDStatusIndicators;
UPROPERTY()
UWrapBox* StatusIconsBox;
UPROPERTY()
TArray<FActiveStatusEffect> ActiveStatusEffects;
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
UFUNCTION()
void AddStatusEffect(UStatusEffect* StatusEffect, float DurationMultiplier = 1.0f, bool Invoke = true);
UFUNCTION()
void RemoveStatusEffect(UStatusEffect* StatusEffect);
UFUNCTION()
FActiveStatusEffect GetActiveStatusEffect(UStatusEffect* StatusEffect);
};

View File

@ -0,0 +1,501 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "TurnBaseCombatV2.h"
#include "CoreMinimal.h"
#include "AIController.h"
#include "StatusSystem.h"
#include "Blueprint/UserWidget.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Components/TextBlock.h"
#include "Components/ProgressBar.h"
#include "GameFramework/Character.h"
#include "Kismet/GameplayStatics.h"
#include "COMP250_1_2101327_AI/Player/PlayerCharacter.h"
#include "UObject/UnrealTypePrivate.h"
// Sets default values
ATurnBaseCombatV2::ATurnBaseCombatV2()
{
if (HUDWidget == nullptr)
{
static ConstructorHelpers::FClassFinder<UUserWidget> HUDWidgetClass(TEXT("/Game/Blueprints/Combat_UI/Combat_UI"));
HUDWidget = HUDWidgetClass.Class;
static ConstructorHelpers::FClassFinder<UStatusEffect> StatusEffectThornsClassFinder(TEXT("/Game/Blueprints/StatusEffects/BP_Thorns"));
ThornsStatusEffect = StatusEffectThornsClassFinder.Class;
static ConstructorHelpers::FClassFinder<UStatusEffect> StatusEffectDOTClassFinder(TEXT("/Game/Blueprints/StatusEffects/BP_DamageOverTime"));
DOTStatusEffect = StatusEffectDOTClassFinder.Class;
//static ConstructorHelpers::FClassFinder<UUserWidget> DeathScreenWidgetClass(TEXT("/Game/Blueprints/Death_UI/Death_UI"));
//DeathScreenWidgetSubclass = DeathScreenWidgetClass.Class;
}
}
void ATurnBaseCombatV2::StartCombat(AActor* Enemy)
{
if (Enemy == nullptr) return;
UBlackboardComponent* EnemyBlackboard = Cast<AAIController>(Enemy->GetInstigatorController())->GetBlackboardComponent();
if (EnemyBlackboard->GetValueAsBool("IsInCombat")) return;
EnemyBlackboard->SetValueAsBool("IsInCombat", true);
FProperty* HealthProperty = Enemy->GetClass()->FindPropertyByName(FName("Health"));
int32* EnemyHealthPtr = HealthProperty->ContainerPtrToValuePtr<int32>(Enemy);
EnemyHealth = EnemyHealthPtr;
if (EnemyBlackboard->GetValueAsBool("Sight"))
{
//bEnemyHasExtraTurn = true;
SwitchTurn();
}
else
{
bPlayerHasExtraTurn = true;
}
if (HUD->IsInViewport()) return;
HUD->AddToViewport();
EnemyActor = Enemy;
ProbertiumResource = 10;
EisResource = 10;
AzosResource = 10;
IroquoidResource = 10;
//Disable Character Movement
if (ACharacter* PlayerCharacter = Cast<ACharacter>(GetWorld()->GetFirstPlayerController()->GetPawn()))
{
PlayerCharacter->DisableInput(GetWorld()->GetFirstPlayerController());
}
//Set to UI Mode Only
APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
PlayerController->SetInputMode(FInputModeUIOnly());
PlayerController->bShowMouseCursor = true;
FVector Direction = Enemy->GetActorLocation() - PlayerActor->GetActorLocation();
Direction.Normalize();
FRotator LookAtRotation = FRotationMatrix::MakeFromX(Direction).Rotator();
LookAtRotation.Pitch = -9.0f;
PlayerController->SetControlRotation(LookAtRotation);
//DrawDebugPoint(GetWorld(), Enemy->GetActorLocation(), 10, FColor::Red, false, 10);
CurrentComboString = "";
UpdateComboString(CurrentComboString);
RevertActionPoints();
UpdateActionPoints();
UpdateResourceBars();
ClearBattleLog();
}
void ATurnBaseCombatV2::EndCombat()
{
bEnemyHasExtraTurn = false;
bPlayerHasExtraTurn = false;
for (UStatusEffect* StatusEffect : StatusEffects)
{
StatusEffect->OnExpiry(PlayerActor);
}
HUD->RemoveFromParent();
APawn* PlayerPawn = Cast<APawn>(GetWorld()->GetFirstPlayerController()->GetPawn());
PlayerPawn->bUseControllerRotationYaw = true;
PlayerPawn->bUseControllerRotationPitch = true;
//Enable Character Movement
if (ACharacter* PlayerCharacter = Cast<ACharacter>(GetWorld()->GetFirstPlayerController()->GetPawn()))
{
PlayerCharacter->EnableInput(GetWorld()->GetFirstPlayerController());
}
//Set to Game Mode Only
APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
PlayerController->SetInputMode(FInputModeGameOnly());
PlayerController->bShowMouseCursor = false;
}
// void ATurnBaseCombatV2::FKeyPressed()
// {
// PButtonOnClick();
// }
//
// void ATurnBaseCombatV2::WKeyPressed()
// {
// EButtonOnClick();
// }
void ATurnBaseCombatV2::BeginPlay()
{
Super::BeginPlay();
TArray<AActor*> AllCharacterActorsInScene;
UGameplayStatics::GetAllActorsOfClassWithTag(GetWorld(), AActor::StaticClass(), FName("Player"), AllCharacterActorsInScene);
for (AActor* Actor : AllCharacterActorsInScene)
{
PlayerActor = Cast<AActor>(Actor);
}
PlayerHealth = &Cast<APlayerCharacter>(PlayerActor)->Health;
HUD = CreateWidget<UUserWidget>(GetWorld(), HUDWidget);
TurnIndicatorTextBlock = Cast<UTextBlock>(HUD->GetWidgetFromName("TurnIndicator"));
CurrentComboTextBlock = Cast<UTextBlock>(HUD->GetWidgetFromName("CurrentCombo"));
ActionPointsTextBlock = Cast<UTextBlock>(HUD->GetWidgetFromName("ActionPoints"));
BattleLogTextBlock = Cast<UTextBlock>(HUD->GetWidgetFromName("BattleLog"));
PlayerHealthBar = Cast<UProgressBar>(HUD->GetWidgetFromName("PlayerHealthBar"));
EnemyHealthBar = Cast<UProgressBar>(HUD->GetWidgetFromName("EnemyHealthBar"));
ProbertiumResourceBar = Cast<UProgressBar>(HUD->GetWidgetFromName("ProbertiumResourceBar"));
EisResourceBar = Cast<UProgressBar>(HUD->GetWidgetFromName("EisResourceBar"));
AzosResourceBar = Cast<UProgressBar>(HUD->GetWidgetFromName("AzosResourceBar"));
IroquoidResourceBar = Cast<UProgressBar>(HUD->GetWidgetFromName("IroquoidResourceBar"));
CastButton = Cast<UButton>(HUD->GetWidgetFromName("CastButton"));
PButton = Cast<UButton>(HUD->GetWidgetFromName("PButton"));
EButton = Cast<UButton>(HUD->GetWidgetFromName("EButton"));
AButton = Cast<UButton>(HUD->GetWidgetFromName("AButton"));
IButton = Cast<UButton>(HUD->GetWidgetFromName("IButton"));
BackspaceButton = Cast<UButton>(HUD->GetWidgetFromName("BackspaceButton"));
RunButton = Cast<UButton>(HUD->GetWidgetFromName("RunButton"));
CastButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::CastButtonOnClick);
PButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::PButtonOnClick);
EButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::EButtonOnClick);
AButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::AButtonOnClick);
IButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::IButtonOnClick);
BackspaceButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::BackspaceButtonOnClick);
RunButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::RunButtonOnClick);
}
void ATurnBaseCombatV2::ExecuteCast(FString Combo)
{
if (!IsValidCombo(Combo))
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Invalid Combo"));
for (int i = 0; i < Combo.Len(); i++)
{
if (Combo[i] == 'P')
{
ProbertiumResource += 1;
}
else if (Combo[i] == 'E')
{
EisResource += 1;
}
else if (Combo[i] == 'A')
{
AzosResource += 1;
}
else if (Combo[i] == 'I')
{
IroquoidResource += 1;
}
}
CurrentComboString = "";
UpdateComboString(CurrentComboString);
RevertActionPoints();
UpdateActionPoints();
UpdateResourceBars();
return;
}
if (IsSpecialCombo(Combo))
{
UStatusSystem* StatusSystem = Cast<UStatusSystem>(PlayerActor->GetComponentByClass(UStatusSystem::StaticClass()));
if (Combo == "AAE")
{
UStatusEffect* TempThornsStatusEffect = NewObject<UStatusEffect>(PlayerActor, ThornsStatusEffect);
StatusSystem->AddStatusEffect(TempThornsStatusEffect, 1, false);
StatusEffects.Add(TempThornsStatusEffect);
AddBattleLogMessage("Player Casted Thorns");
}
else if (Combo == "PPI")
{
UStatusEffect* TempDOTStatusEffect = NewObject<UStatusEffect>(PlayerActor, DOTStatusEffect);
StatusSystem->AddStatusEffect(TempDOTStatusEffect, 1, false);
StatusEffects.Add(TempDOTStatusEffect);
AddBattleLogMessage("Player Casted DOT");
}
}
if (GunEffect)
{
const UStaticMeshComponent* GunComponent = Cast<UStaticMeshComponent>(PlayerActor->GetComponentsByTag(UPrimitiveComponent::StaticClass(), FName("Gun"))[0]);
const FVector GunLocationOffset = GunComponent->GetSocketTransform("Muzzle").TransformPosition(FVector(-100, 0, 0));
UNiagaraFunctionLibrary::SpawnSystemAtLocation(GetWorld(), GunEffect, GunLocationOffset, PlayerActor->GetActorRotation());
}
CurrentComboString = "";
UpdateComboString(CurrentComboString);
RevertActionPoints();
UpdateActionPoints();
//Damage Calculation
switch (bIsPlayerTurn)
{
case true:
// Player Turn
DamageEnemy(*ValidCombos.Find(Combo));
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, FString::Printf(TEXT("Enemy Damaged %d"), *ValidCombos.Find(Combo)));
OnPlayerTurn.Broadcast(PlayerActor, EnemyActor);
break;
case false:
// Enemy Turn
DamagePlayer(*ValidCombos.Find(Combo));
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, FString::Printf(TEXT("Player Damaged %d"), *ValidCombos.Find(Combo)));
OnEnemyTurn.Broadcast(EnemyActor, PlayerActor);
break;
}
//Ends Combat if either the player or enemy is dead
if (*EnemyHealth <= 0)
{
EndCombat();
EnemyActor->Destroy();
return;
}
if (*PlayerHealth <= 0)
{
//EndCombat();
DeathScreenWidget = CreateWidget<UUserWidget>(GetWorld(), DeathScreenWidgetSubclass);
DeathScreenWidget->AddToViewport();
return;
}
if (!bPlayerHasExtraTurn)
{
SwitchTurn();
}
bPlayerHasExtraTurn = false;
}
void ATurnBaseCombatV2::UseActionPoint()
{
ActiveActionPoints += 1;
UpdateActionPoints();
}
void ATurnBaseCombatV2::ReuseActionPoint()
{
ActiveActionPoints -= 1;
UpdateActionPoints();
}
void ATurnBaseCombatV2::RevertActionPoints()
{
ActiveActionPoints = 0;
UpdateActionPoints();
}
void ATurnBaseCombatV2::DamagePlayer(int Damage, FString DamageType)
{
*PlayerHealth -= FMath::Clamp(Damage, 0, 100);
UpdateProgressBars();
AddBattleLogMessage("Player was damaged for " + FString::FromInt(Damage) + " HP by " + DamageType + ".");
}
void ATurnBaseCombatV2::DamageEnemy(int Damage, FString DamageType)
{
*EnemyHealth -= FMath::Clamp(Damage, 0, 100);
UpdateProgressBars();
AddBattleLogMessage("Enemy was damaged for " + FString::FromInt(Damage) + " HP by " + DamageType + ".");
}
void ATurnBaseCombatV2::UpdateProgressBars() const
{
PlayerHealthBar->SetPercent(*PlayerHealth / 100.0f);
EnemyHealthBar->SetPercent(*EnemyHealth / 100.0f);
}
bool ATurnBaseCombatV2::IsValidCombo(const FString Combo) const
{
return ValidCombos.Contains(Combo);
}
bool ATurnBaseCombatV2::IsSpecialCombo(const FString Combo) const
{
return SpecialCombos.Contains(Combo);
}
void ATurnBaseCombatV2::SwitchTurn()
{
//TurnIndicatorTextBlock->SetText(FText::FromString(bIsPlayerTurn ? "Enemy Turn" : "Player Turn"));
//bIsPlayerTurn = !bIsPlayerTurn;
TurnIndicatorTextBlock->SetText(FText::FromString("Enemy Turn"));
ToggleButtons();
FTimerHandle UnusedHandle;
GetWorldTimerManager().SetTimer(UnusedHandle, this, &ATurnBaseCombatV2::EnemyTurn, 2.0f, false);
//activeActor = bIsPlayerTurn ? enemyActor : playerActor;
}
void ATurnBaseCombatV2::CastButtonOnClick()
{
ExecuteCast(CurrentComboString);
}
void ATurnBaseCombatV2::PButtonOnClick()
{
if (ActiveActionPoints >= DefaultActionPoints)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Action Points"));
return;
}
if (ProbertiumResource <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Probertium"));
return;
}
UseActionPoint();
CurrentComboString.AppendChar('P');
UpdateComboString(CurrentComboString);
ProbertiumResource -= 1;
UpdateResourceBars();
}
void ATurnBaseCombatV2::EButtonOnClick()
{
if (ActiveActionPoints >= DefaultActionPoints)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Action Points"));
return;
}
if (EisResource <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Eis"));
return;
}
UseActionPoint();
CurrentComboString.AppendChar('E');
UpdateComboString(CurrentComboString);
EisResource -= 1;
UpdateResourceBars();
}
void ATurnBaseCombatV2::AButtonOnClick()
{
if (ActiveActionPoints >= DefaultActionPoints)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Action Points"));
return;
}
if (AzosResource <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Azos"));
return;
}
UseActionPoint();
CurrentComboString.AppendChar('A');
UpdateComboString(CurrentComboString);
AzosResource -= 1;
UpdateResourceBars();
}
void ATurnBaseCombatV2::IButtonOnClick()
{
if (ActiveActionPoints >= DefaultActionPoints)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Action Points"));
return;
}
if (IroquoidResource <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Iroquoid"));
return;
}
UseActionPoint();
CurrentComboString.AppendChar('I');
UpdateComboString(CurrentComboString);
IroquoidResource -= 1;
UpdateResourceBars();
}
void ATurnBaseCombatV2::BackspaceButtonOnClick()
{
if (CurrentComboString.Len() <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Blank Combo"));
return;
}
ReuseActionPoint();
if (CurrentComboString.Right(1) == "P")
{
ProbertiumResource += 1;
}
else if (CurrentComboString.Right(1) == "E")
{
EisResource += 1;
}
else if (CurrentComboString.Right(1) == "A")
{
AzosResource += 1;
}
else if (CurrentComboString.Right(1) == "I")
{
IroquoidResource += 1;
}
CurrentComboString.RemoveAt(CurrentComboString.Len() - 1);
UpdateComboString(CurrentComboString);
UpdateResourceBars();
}
void ATurnBaseCombatV2::RunButtonOnClick()
{
UBlackboardComponent* EnemyBlackboard = Cast<AAIController>(EnemyActor->GetInstigatorController())->GetBlackboardComponent();
EnemyBlackboard->SetValueAsBool("IsInCombat", false);
EndCombat();
}
void ATurnBaseCombatV2::UpdateComboString(FString NewCombo) const
{
CurrentComboTextBlock->SetText(FText::FromString(NewCombo));
}
void ATurnBaseCombatV2::UpdateActionPoints() const
{
ActionPointsTextBlock->SetText(FText::FromString(FString::FromInt(DefaultActionPoints - ActiveActionPoints)));
}
void ATurnBaseCombatV2::AddBattleLogMessage(FString Message)
{
BattleLog.Append(Message + "\n");
UpdateBattleLog();
}
void ATurnBaseCombatV2::ClearBattleLog()
{
BattleLog = "";
}
void ATurnBaseCombatV2::UpdateBattleLog()
{
TArray<FString> TempArray;
if (const int32 LineCount = BattleLog.ParseIntoArray(TempArray, TEXT("\n"), true); LineCount > 10)
{
ClearBattleLog();
}
BattleLogTextBlock->SetText(FText::FromString(BattleLog));
}
void ATurnBaseCombatV2::UpdateResourceBars() const
{
ProbertiumResourceBar->SetPercent(ProbertiumResource / 10.0f);
EisResourceBar->SetPercent(EisResource / 10.0f);
AzosResourceBar->SetPercent(AzosResource / 10.0f);
IroquoidResourceBar->SetPercent(IroquoidResource / 10.0f);
}
void ATurnBaseCombatV2::ToggleButtons() const
{
PButton->SetIsEnabled(!PButton->GetIsEnabled());
EButton->SetIsEnabled(!EButton->GetIsEnabled());
AButton->SetIsEnabled(!AButton->GetIsEnabled());
IButton->SetIsEnabled(!IButton->GetIsEnabled());
BackspaceButton->SetIsEnabled(!BackspaceButton->GetIsEnabled());
CastButton->SetIsEnabled(!CastButton->GetIsEnabled());
RunButton->SetIsEnabled(!RunButton->GetIsEnabled());
}
void ATurnBaseCombatV2::EnemyTurn()
{
DamagePlayer(10);
OnEnemyTurn.Broadcast(EnemyActor, PlayerActor);
TurnIndicatorTextBlock->SetText(FText::FromString("Player Turn"));
ToggleButtons();
}

View File

@ -0,0 +1,212 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/Button.h"
#include "Components/ProgressBar.h"
#include "Components/TextBlock.h"
#include "StatusEffect.h"
#include "NiagaraComponent.h"
#include "NiagaraFunctionLibrary.h"
#include "GameFramework/GameStateBase.h"
#include "StatusEffects/Thorns.h"
#include "TurnBaseCombatV2.generated.h"
class UNiagaraSystem;
UCLASS()
class COMP250_1_2101327_AI_API ATurnBaseCombatV2 : public AGameStateBase
{
GENERATED_BODY()
public:
ATurnBaseCombatV2();
int* EnemyHealth = nullptr;
float* PlayerHealth = nullptr;
UPROPERTY(EditDefaultsOnly)
int DefaultActionPoints = 3;
UPROPERTY(EditDefaultsOnly)
int ActiveActionPoints = 0;
UPROPERTY(EditDefaultsOnly)
int ProbertiumResource = 10;
UPROPERTY(EditDefaultsOnly)
int EisResource = 10;
UPROPERTY(EditDefaultsOnly)
int AzosResource = 10;
UPROPERTY(EditDefaultsOnly)
int IroquoidResource = 10;
UPROPERTY(EditDefaultsOnly)
UNiagaraSystem* GunEffect;
UPROPERTY(VisibleAnywhere)
AActor* PlayerActor;
UPROPERTY(VisibleAnywhere)
AActor* EnemyActor;
// AActor* ActiveActor;
UPROPERTY(BlueprintReadWrite)
UUserWidget* HUD;
/*
TODO:
Reference Player Inventory
*/
UPROPERTY(EditAnywhere)
TSubclassOf<UUserWidget> HUDWidget;
UPROPERTY(EditAnywhere)
TMap<FString, int32> ValidCombos =
{
{"P", 5},
{"PP", 15},
{"PPP", 20},
{"E", 5},
{"EE", 15},
{"EEE", 20},
{"A", 5},
{"AA", 15},
{"AAA", 20},
{"I", 5},
{"II", 15},
{"III", 20},
{"IA", 15},
{"IIA", 20},
{"EP", 15},
{"EEP", 20},
{"AE", 15},
{"AAE", 20},
{"PI", 15},
{"PPI", 20}
};
UPROPERTY(EditAnywhere)
TMap<FString, FString> SpecialCombos =
{
//{"IIA", "ReduceActSpeed"},
//{"EEP", "AreaOfEffect"},
{"AAE", "Thorns"},
{"PPI", "DamageOverTime"}
};
FString BattleLog;
UFUNCTION(BlueprintCallable)
void StartCombat(AActor* Enemy);
UFUNCTION(BlueprintCallable)
void EndCombat();
// UFUNCTION(BlueprintCallable)
// void FKeyPressed();
// UFUNCTION(BlueprintCallable)
// void WKeyPressed();
DECLARE_EVENT_TwoParams(ATurnBaseCombatV2, FOnPlayerTurn, AActor*, AActor*);
DECLARE_EVENT_TwoParams(ATurnBaseCombatV2, FOnEnemyTurn, AActor*, AActor*);
FOnPlayerTurn OnPlayerTurn;
FOnEnemyTurn OnEnemyTurn;
void DamagePlayer(int Damage, FString DamageType = "unknown");
void DamageEnemy(int Damage, FString DamageType = "unknown");
protected:
virtual void BeginPlay() override;
void ExecuteCast(FString Combo);
void UseActionPoint();
void ReuseActionPoint();
void RevertActionPoints();
void UpdateProgressBars() const;
bool bPlayerHasExtraTurn = false;
bool bEnemyHasExtraTurn = false;
private:
bool IsValidCombo(FString Combo) const;
bool IsSpecialCombo(FString Combo) const;
UPROPERTY()
TSubclassOf<UStatusEffect> ThornsStatusEffect;
UPROPERTY()
TSubclassOf<UStatusEffect> DOTStatusEffect;
UPROPERTY()
TArray<UStatusEffect*> StatusEffects;
UPROPERTY(VisibleAnywhere)
bool bIsPlayerTurn = true;
UPROPERTY(VisibleAnywhere)
FString CurrentComboString = "";
void SwitchTurn();
UPROPERTY(VisibleAnywhere)
UTextBlock* TurnIndicatorTextBlock;
UPROPERTY(VisibleAnywhere)
UTextBlock* CurrentComboTextBlock;
UPROPERTY(VisibleAnywhere)
UTextBlock* BattleLogTextBlock;
UPROPERTY(VisibleAnywhere)
UTextBlock* ActionPointsTextBlock;
UPROPERTY(VisibleAnywhere)
UProgressBar* PlayerHealthBar;
UPROPERTY(VisibleAnywhere)
UProgressBar* EnemyHealthBar;
UPROPERTY(VisibleAnywhere)
UProgressBar* ProbertiumResourceBar;
UPROPERTY(VisibleAnywhere)
UProgressBar* EisResourceBar;
UPROPERTY(VisibleAnywhere)
UProgressBar* AzosResourceBar;
UPROPERTY(VisibleAnywhere)
UProgressBar* IroquoidResourceBar;
UPROPERTY(VisibleAnywhere)
UButton* CastButton;
UPROPERTY(VisibleAnywhere)
UButton* PButton;
UPROPERTY(VisibleAnywhere)
UButton* EButton;
UPROPERTY(VisibleAnywhere)
UButton* AButton;
UPROPERTY(VisibleAnywhere)
UButton* IButton;
UPROPERTY(VisibleAnywhere)
UButton* BackspaceButton;
UPROPERTY(VisibleAnywhere)
UButton* RunButton;
UFUNCTION()
void CastButtonOnClick();
UFUNCTION()
void PButtonOnClick();
UFUNCTION()
void EButtonOnClick();
UFUNCTION()
void AButtonOnClick();
UFUNCTION()
void IButtonOnClick();
UFUNCTION()
void BackspaceButtonOnClick();
UFUNCTION()
void RunButtonOnClick();
void UpdateComboString(FString NewCombo) const;
void UpdateActionPoints() const;
void AddBattleLogMessage(FString Message);
void ClearBattleLog();
void UpdateBattleLog();
void UpdateResourceBars() const;
void ToggleButtons() const;
void EnemyTurn();
UPROPERTY()
UUserWidget* DeathScreenWidget;
UPROPERTY()
TSubclassOf<UUserWidget> DeathScreenWidgetSubclass;
};

View File

@ -1,60 +0,0 @@
# Introduction
This is the ***ROOT*** folder for the unreal game project.
_NOTE - Unreal has blur enabled by default, disable this in project settings if you don't want blur._
# Adding UE5 Game Project
1. Open unreal, select a template, and create the project template anywhere.
2. Open the ***ROOT*** folder of the UE5 project you just created and copy `yourgame.uproject`, `Content`. `Config`, and `Source` into this folder.
3. If your `yourgame.uproject` file & `Content`. `Config`, `Source` folders are in the same directory as the repositories `.gitignore` file, then your setup is correct.
Once you've completed the above steps you're ready to open the project and start working.
# Opening The Project: For Programmers
If you're a programmer and plan on doing work in C++ you should right click the `yourgame.uproject` file and select the `Generate Visual Studio project files` option. When this is complete double click the `yourgame.sln` file and run the game from Visual Studio by clicking `Local Windows Debugger`. Whenever you code in C++ you should close UE5 and recompile it from VS.
If you are not doing anything in C++, then you can open the project straight from double clicking `yourgame.uproject`. Make sure you click yes on the prompt asking to compile. UE5 will take awhile to open because it's compiling C++ binaries in the background.
If UE5 is bing weird delete all the cache files/folders & generated files/folders, then lauch it from Visual Studio so it's forced to compile everything correctly and you will catch any compiler bugs if anything is wrong.
# Common Visual Studio/C++ Problems
### Too Much Unreal
If you are trying to run UE5 from Visual Studio, then close any other UE5 executable windows you have open. If Unreal is already running when you launch it from Visual Studio then it will sometimes prevent Visual Studio from being able to correctly compile your C++ files, which results in a compiler error.
To fix this close all open instances of Unreal Engine. Once you've done that everything will be fine and you should be able to run Unreal from Visual Studio.
### I'm getting an error with the build.bat in the Visual Studio error console
This happens when certain executables are already running in the background and haven't shutdown when they're meant to. To fix this open task manager and close `HUB for UE5 runtime traces...` and close every instance of `Runtime Broker` you can find.
Once you've done this, Visual Studio will work again and you can compile code.
# Fixing UE5 Setup
### dotnet is not recognized as an internal or external command
If you get an error similar to this one when generating visual studio project files or opening the project for the first time, it's because `.NET 6` is not installed or its environment path is not set.
To fix this locate `C:\program files\dotnet`, and delete the `dotnet` folder if it exists. If it doesn't exist, then don't do anything.
Next download the .NET 6 SDK ([.NET 6 download here](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)) and install it. _(do not download `ASP.NET Core Runtime`, `.NET Desktop Runtime`, `.NET Runtime`, or any other SDK - just the plain `.NET 6` SDK that has everything included)_
This will fix the dotnet error.
### I don't know how to setup VS2022 for Unreal Engine 5
Follow this guide: [Setting Up Visual Studio Environment for C++](https://docs.unrealengine.com/5.1/en-US/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine/)

View File

@ -1,13 +1,53 @@
# COMP250 Project Proposal
# WARNING!!!
## Computing Artifact Outline
Do not put in development or completed project assets in this repository. When you import assets into unreal they're taken into unreal and changed into `.uasset` files. Because of this it's wasteful to put the original development assets in the game repository. Doing so bloats the project and increases cloning times of the project for everyone.
The computing artifact I am proposing is a combat artificial intelligence attached to an enemy non-player character for a small turn based strategy game with the focus of resource management and combo building. In this game you have a limited set of resources that can be used to build combos to attack an opponent and defend yourself. Combos vary in resource costs and which resource is required for it to be cast. To win you must defeat the opponent by reducing their health to 0.
The combat artificial intelligence must be able to find the optimal set of combos and actions to defeat their opponent.
Instead you should have another repo that uses the [art-lfs-repo](https://github.falmouth.ac.uk/Games-Academy/art-lfs-repo) template. This is where you put your development assets like your models and textures while working on them, including your completed ones. Then when you're done, you import them into Unreal Engine (and UE5 will store the files internally in its own format).
## Artifact Specialism
This computing artifact is suitable for the specified specialism of Artificial Intelligence as it falls under the specified contract of non-player character behaviour. The computing artifact will apply a goal-directed behaviour system. The combat artificial intelligence will be using the Goal Oriented Action Planning (GOAP) (Suyikno and Setiawan 2019) artificial intelligence to guide and action the resource management and combo build to aim for the goal of eliminating the player. GOAP is a form of artificial intelligence planning system that is used in computer games to generate intelligent behaviour for non-player characters (NPCs). It operates by identifying a goal state and a set of actions that can be taken to achieve the goal, and then use search algorithms such as Depth First Search (DFS) or Breadth First Search (BFS) against a tree to find the most cost effective plan that will achieve the goal by executing the available actions in the generated order. (Brent Owens 2014)
## Potential Applications
# UE5 Stucture & Organisation
A combat artificial intelligence can use GOAP to become more adaptable and intelligent in its decision-making, which makes it a useful tool for game designers who want to develop entertaining and challenging gameplay. Combat can become more strategic and sophisticated with the help of GOAP providing players with a more immersive gaming experience.
This artificial intelligence is not only limited to resource management and combo-building features if more parameters are included in the GOAP system for example weather conditions, or stealth conditions. The artificial intelligence can take these into account when deciding what actions to take. This can be used in a stealth game where the artificial intelligence must sneak past enemies or in a survival game where the artificial intelligence must avoid the weather conditions. (Mitchell 2015)
## Existing Solutions
Current existing solutions using the Goal Oriented Action Planning artificial intelligence is the game F.E.A.R. (2005) (Monolith Productions 2005).
GOAP was originally designed for F.E.A.R, an example of actions to complete their goals that were included in their artificial intelligence:
* Moving into a position in the world.
* Playing an animation.
* Interacting with a smart object (an item in the world that artificial intelligence characters can interact with) (AIandGames 2020)
Another example of a project using the Goal Oriented Action Planning artificial intelligence is a Third Year Undergraduate Dissertation Project called StarPlanner by Panagiotis Peikidis to play the game StarCraft. (Peikidis 2010)
Both of these projects use the Goal Oriented Action Planning artificial intelligence to plan and execute actions to achieve a goal or goals. The main goal in F.E.A.R. is to kill the player and the goal in StarPlanner is to win the game. These projects convey the effectiveness of the Goal Oriented Action Planning artificial intelligence in a game environment in a combat setting.
## Development Plan & Scope
The development plan for this computing artifact will consist of 6 weeks of development split into 5 milestones. The first milestone will be to research and understand the Goal Oriented Action Planning artificial intelligence and how it can be applied to a combat artificial intelligence and to decide which search algorithm will be the most optimal for this specific case. The second milestone will be to build the game. The third milestone will be to implement the resource management and combo-building features into the combat artificial intelligence including the costs of each action. The fourth milestone will be to test the combat artificial intelligence and make any necessary changes by adjusting the costs. The fifth milestone will be to polish the combat artificial intelligence, make any final changes and bug fixes.
## Practiced Based Research
This constitutes as practice based research as it is a project in which will analyze artificial intelligence systems and apply them. In this case finite state machines and behaviour trees. The project will compare the feasibility of these systems and the effectiveness of the Goal Oriented Action Planning artificial intelligence and apply these techniques in a game environment.
*Word Count: 786*
## References
AIANDGAMES. 2020. ÔÇÿBuilding the AI of F.E.A.R. With Goal Oriented Action Planning, AI and GamesÔÇÖ. AI and Games [online]. Available at: https://www.aiandgames.com/2020/05/06/ai-101-goap-fear/.
BRENT OWENS, Brent. 2014. ÔÇÿGoal Oriented Action Planning for a Smarter AIÔÇÖ. Game Development Envato Tuts+ [online]. Available at: https://gamedevelopment.tutsplus.com/tutorials/goal-oriented-action-planning-for-a-smarter-ai--cms-20793.
MITCHELL, Jared. 2015. ÔÇÿGoal-Oriented Action Planning ResearchÔÇÖ. Jared Mitchell [online]. Available at: https://jaredemitchell.com/goal-oriented-action-planning-research/.
MONOLITH PRODUCTIONS. 2005. ÔÇÿF.E.A.R.ÔÇÖ.
PEIKIDIS, Panagiotis. 2010. ÔÇÿPanagiotis Peikidis - 3rd Year ProjectÔÇÖ. pekalicious.github.io [online]. Available at: https://pekalicious.github.io/StarPlanner/ [accessed 5 Feb 2023].
SUYIKNO, D A and A SETIAWAN. 2019. ÔÇÿFeasible NPC Hiding Behaviour Using Goal Oriented Action Planning in Case of HideandSeek 3D Game SimulationÔÇÖ. In 2019 Fourth International Conference on Informatics and Computing (ICIC). 1ÔÇô6.
1. [UE5 Directory Structure](https://docs.unrealengine.com/5.1/en-US/unreal-engine-directory-structure/)
2. [UE5 Asset Naming Conventions](https://docs.unrealengine.com/5.1/en-US/recommended-asset-naming-conventions-in-unreal-engine-projects/)