Merge branch 'dev' into Shaders

# Conflicts:
#	Content/Levels/Top_layer_level.umap
This commit is contained in:
Philip W 2023-01-31 02:04:48 +00:00
commit a15054656e
45 changed files with 341 additions and 1058 deletions

BIN
Content/Assets/Objects/Blue_Jelly/BlueJelly_Cylinder.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Assets/Objects/Blue_Jelly/BlueJelly_Mball_009.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Assets/Objects/Blue_Jelly/Material_001.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Assets/Objects/Blue_Jelly/Material_002.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Assets/Objects/Red_Jelly/Material_001.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Assets/Objects/Red_Jelly/Material_002.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Assets/Objects/Red_Jelly/Redjelly_Cylinder.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Assets/Objects/Red_Jelly/Redjelly_Mball_009.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/BlueprintAI/AI/AIBruh.uasset (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/BlueprintAI/AI/BT_Bruh.uasset (Stored with Git LFS)

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
Content/Levels/CombatTest.umap (Stored with Git LFS)

Binary file not shown.

BIN
Content/Levels/MerchantPrototype.umap (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Levels/Testing/CopyStalagite.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Levels/Testing/DestructableEnvironment.umap (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Levels/Testing/Stalagite_GeometryCollection.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Levels/Top_layer_level.umap (Stored with Git LFS)

Binary file not shown.

View File

@ -1,4 +1,6 @@
Combat Spread Sheet: Combat Spread Sheet:
https://docs.google.com/spreadsheets/d/1s_uxjS8ir1pbt4-ofdOVpSPaQZVC8x9gQzS78bzE3KI/edit#gid=0 https://docs.google.com/spreadsheets/d/1s_uxjS8ir1pbt4-ofdOVpSPaQZVC8x9gQzS78bzE3KI/edit#gid=0
https://docs.google.com/document/d/1Y6eYoKQPw9n8gl7p030fmtPjfJcE132YHAvwL7Gk4jk/edit

View File

@ -9,6 +9,7 @@
#include "GameFramework/Character.h" #include "GameFramework/Character.h"
#include "Components/WidgetComponent.h" #include "Components/WidgetComponent.h"
#include "Kismet/KismetMathLibrary.h" #include "Kismet/KismetMathLibrary.h"
#include "the_twilight_abyss/PlayerTemp/TempCharacter.h"
// Sets default values // Sets default values
@ -23,6 +24,40 @@ void AInteraction::BeginPlay()
{ {
Super::BeginPlay(); Super::BeginPlay();
//Character & Camera refs
TempCharacterRef = Cast<ATempCharacter>(GetWorld()->GetFirstPlayerController()->GetCharacter());
MainCamera = Cast<UCameraComponent>(TempCharacterRef->FindComponentByClass<UCameraComponent>());
//Item refs
TargetHealingLocation = HealingItem->GetActorLocation();
TargetBuffLocation = BuffItem->GetActorLocation();
// Dialog refs
ShopDialogWidget = CreateWidget<UUserWidget>(GetWorld(), ShopDialog);
ShopDialogWidget->SetVisibility(ESlateVisibility::Hidden);
ShopDialogWidget->AddToViewport();
//Item Selector refs
ItemSelectorWidget = CreateWidget<UUserWidget>(GetWorld(), ItemSelector);
ItemSelectorWidget->SetVisibility(ESlateVisibility::Hidden);
ItemSelectorWidget->AddToViewport();
//We are getting the property of interaction since we need a reference for when we cast in BP and we need the reference to be self
Property = ItemSelectorWidget->GetClass()->FindPropertyByName("publicActor");
//Confirm Buy refs
BuyBuffTextWidget = CreateWidget<UUserWidget>(GetWorld(), BuyBuffText);
BuyBuffTextWidget->SetVisibility(ESlateVisibility::Hidden);
BuyBuffTextWidget->AddToViewport();
//We are getting the property of interaction since we need a reference for when we cast in BP and we need the reference to be self
BuyBuffProperty = BuyBuffTextWidget->GetClass()->FindPropertyByName("publicActor");
BuyHealingTextWidget = CreateWidget<UUserWidget>(GetWorld(), BuyHealingText);
BuyHealingTextWidget->SetVisibility(ESlateVisibility::Hidden);
BuyHealingTextWidget->AddToViewport();
//We are getting the property of interaction since we need a reference for when we cast in BP and we need the reference to be self
BuyHealingProperty = BuyHealingTextWidget->GetClass()->FindPropertyByName("publicActor");
} }
// Called every frame // Called every frame
@ -35,14 +70,17 @@ void AInteraction::Tick(float DeltaTime)
void AInteraction::OnInteract() void AInteraction::OnInteract()
{ {
bDisableShopDialMove = true; bDisableShopDialMove = true;
ShopDialogWidget = CreateWidget<UUserWidget>(GetWorld(), ShopDialog);
if (ShopDialogWidget == nullptr) if (ShopDialogWidget == nullptr)
{ {
UE_LOG(LogTemp, Display, TEXT("ShopDialogWidget is null"));
return; return;
} }
else else
{ {
ShopDialogWidget->AddToViewport(0); //Shop Widget to visible
ShopDialogWidget->SetVisibility(ESlateVisibility::Visible);
//Call a custom event in a blueprint called "PlayText"
ShopDialogWidget->CallFunctionByNameWithArguments(TEXT("PlayText"), *GLog, nullptr, true);
} }
//handles the widget disappearing from the viewport //handles the widget disappearing from the viewport
FTimerHandle WidgetTimer; FTimerHandle WidgetTimer;
@ -53,13 +91,22 @@ void AInteraction::OnInteract()
void AInteraction::RemoveWidget() void AInteraction::RemoveWidget()
{ {
bisDisabled = true; bisDisabled = true;
ShopDialogWidget->RemoveFromViewport(); //Setting ShopWidgetText back to hidden
ShopDialogWidget->SetVisibility(ESlateVisibility::Hidden);
if (ShopDialogWidget->IsVisible())
{
return;
}
else
{
UE_LOG(LogTemp, Display, TEXT("You cant open this widget when this widget is open"));
}
UE_LOG(LogTemp, Display, TEXT("setting isDisabled to true")); UE_LOG(LogTemp, Display, TEXT("setting isDisabled to true"));
ItemSelectorWidget = CreateWidget<UUserWidget>(GetWorld(), ItemSelector);
FProperty* Property = ItemSelectorWidget->GetClass()->FindPropertyByName("publicActor");
if (Property == nullptr) if (Property == nullptr)
{ {
UE_LOG(LogTemp, Error, TEXT("Property not found")); UE_LOG(LogTemp, Error, TEXT("Property not found"));
return;
} }
else else
{ {
@ -72,7 +119,7 @@ void AInteraction::RemoveWidget()
} }
else else
{ {
ItemSelectorWidget->AddToViewport(0); ItemSelectorWidget->SetVisibility(ESlateVisibility::Visible);
bisDisabled = false; bisDisabled = false;
} }
} }
@ -80,9 +127,7 @@ void AInteraction::RemoveWidget()
void AInteraction::CameraLeftMover() void AInteraction::CameraLeftMover()
{ {
UE_LOG(LogTemp, Display, TEXT("Button Left is being pressed")); UE_LOG(LogTemp, Display, TEXT("Button Left is being pressed"));
TempCharacter = GetWorld()->GetFirstPlayerController()->GetCharacter(); if (TempCharacterRef == nullptr || BuyHealingProperty == nullptr)
MainCamera = Cast<UCameraComponent>(TempCharacter->FindComponentByClass<UCameraComponent>());
if (TempCharacter == nullptr)
{ {
UE_LOG(LogTemp, Display, TEXT("Character not found in Interaction.cpp")); UE_LOG(LogTemp, Display, TEXT("Character not found in Interaction.cpp"));
return; return;
@ -90,18 +135,21 @@ void AInteraction::CameraLeftMover()
else else
{ {
UE_LOG(LogTemp, Display, TEXT("Character Found in interaction.cpp")); UE_LOG(LogTemp, Display, TEXT("Character Found in interaction.cpp"));
if (MainCamera == nullptr) if (MainCamera == nullptr || HealingItem == nullptr)
{ {
UE_LOG(LogTemp, Display, TEXT("Camera not found in Interaction.cpp")); UE_LOG(LogTemp, Display, TEXT("Camera not found in Interaction.cpp"));
return; return;
} }
else else
{ {
FVector TargetLocation = FVector(5700,-1270,4040); FObjectPropertyBase* ObjectProperty = static_cast<FObjectPropertyBase*>(BuyHealingProperty);
FVector CameraLocation = MainCamera->GetComponentLocation(); ObjectProperty->SetObjectPropertyValue(ObjectProperty->ContainerPtrToValuePtr<void>(BuyHealingTextWidget), this);
FRotator CameraRotation = UKismetMathLibrary::FindLookAtRotation(CameraLocation, TargetLocation);
CameraLocation = MainCamera->GetComponentLocation();
FRotator CameraRotation = UKismetMathLibrary::FindLookAtRotation(CameraLocation, TargetHealingLocation);
MainCamera->SetWorldRotation(CameraRotation); MainCamera->SetWorldRotation(CameraRotation);
MainCamera->SetFieldOfView(40); MainCamera->SetFieldOfView(40);
BuyHealingTextWidget->SetVisibility(ESlateVisibility::Visible);
} }
} }
} }
@ -109,9 +157,7 @@ void AInteraction::CameraLeftMover()
void AInteraction::CameraRightMover() void AInteraction::CameraRightMover()
{ {
UE_LOG(LogTemp, Display, TEXT("Button Right is being pressed")); UE_LOG(LogTemp, Display, TEXT("Button Right is being pressed"));
TempCharacter = GetWorld()->GetFirstPlayerController()->GetCharacter(); if (TempCharacterRef == nullptr || BuyBuffProperty == nullptr)
MainCamera = Cast<UCameraComponent>(TempCharacter->FindComponentByClass<UCameraComponent>());
if (TempCharacter == nullptr)
{ {
UE_LOG(LogTemp, Display, TEXT("Character not found in Interaction.cpp")); UE_LOG(LogTemp, Display, TEXT("Character not found in Interaction.cpp"));
return; return;
@ -119,18 +165,45 @@ void AInteraction::CameraRightMover()
else else
{ {
UE_LOG(LogTemp, Display, TEXT("Character Found in interaction.cpp")); UE_LOG(LogTemp, Display, TEXT("Character Found in interaction.cpp"));
if (MainCamera == nullptr) if (MainCamera == nullptr || BuffItem == nullptr)
{ {
UE_LOG(LogTemp, Display, TEXT("Camera not found in Interaction.cpp")); UE_LOG(LogTemp, Display, TEXT("Camera not found in Interaction.cpp"));
return; return;
} }
else else
{ {
FVector TargetLocation = FVector(5260, -840, 4070); FObjectPropertyBase* ObjectProperty = static_cast<FObjectPropertyBase*>(BuyBuffProperty);
FVector CameraLocation = MainCamera->GetComponentLocation(); ObjectProperty->SetObjectPropertyValue(ObjectProperty->ContainerPtrToValuePtr<void>(BuyBuffTextWidget), this);
FRotator CameraRotation = UKismetMathLibrary::FindLookAtRotation(CameraLocation, TargetLocation);
CameraLocation = MainCamera->GetComponentLocation();
FRotator CameraRotation = UKismetMathLibrary::FindLookAtRotation(CameraLocation, TargetBuffLocation);
MainCamera->SetWorldRotation(CameraRotation); MainCamera->SetWorldRotation(CameraRotation);
MainCamera->SetFieldOfView(40); MainCamera->SetFieldOfView(40);
BuyBuffTextWidget->SetVisibility(ESlateVisibility::Visible);
} }
} }
} }
void AInteraction::CancelPurchase()
{
BuyBuffTextWidget->SetVisibility(ESlateVisibility::Hidden);
BuyHealingTextWidget->SetVisibility(ESlateVisibility::Hidden);
}
void AInteraction::ExitScreen()
{
if (TempCharacterRef == nullptr)
{
UE_LOG(LogTemp, Display, TEXT("TempCharacterRef in Interaction.cpp not found"));
return;
}
else
{
TempCharacterRef->InputEnabler();
ItemSelectorWidget->SetVisibility(ESlateVisibility::Hidden);
}
}

View File

@ -5,6 +5,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Camera/CameraComponent.h" #include "Camera/CameraComponent.h"
#include "GameFramework/Actor.h" #include "GameFramework/Actor.h"
#include "the_twilight_abyss/PlayerTemp/TempCharacter.h"
#include "Interaction.generated.h" #include "Interaction.generated.h"
UCLASS() UCLASS()
@ -24,12 +25,18 @@ public:
// Called every frame // Called every frame
virtual void Tick(float DeltaTime) override; virtual void Tick(float DeltaTime) override;
UPROPERTY(EditAnywhere) UPROPERTY(EditAnywhere, Category= "Widgets")
TSubclassOf<UUserWidget> ShopDialog; TSubclassOf<UUserWidget> ShopDialog;
UPROPERTY(EditAnywhere) UPROPERTY(EditAnywhere, Category= "Widgets")
TSubclassOf<UUserWidget> ItemSelector; TSubclassOf<UUserWidget> ItemSelector;
UPROPERTY(EditAnywhere, Category = "Widgets")
TSubclassOf<UUserWidget> BuyBuffText;
UPROPERTY(EditAnywhere, Category = "Widgets")
TSubclassOf<UUserWidget> BuyHealingText;
virtual void OnInteract(); virtual void OnInteract();
virtual void RemoveWidget(); virtual void RemoveWidget();
@ -39,8 +46,14 @@ public:
UPROPERTY() UPROPERTY()
UUserWidget* ItemSelectorWidget; UUserWidget* ItemSelectorWidget;
UPROPERTY()
UUserWidget* BuyBuffTextWidget;
UPROPERTY(EditAnywhere) UPROPERTY()
UUserWidget* BuyHealingTextWidget;
UPROPERTY(EditAnywhere, Category= "Widgets")
float WaitTimer = 8.0f; float WaitTimer = 8.0f;
UPROPERTY() UPROPERTY()
@ -48,6 +61,7 @@ public:
UPROPERTY() UPROPERTY()
bool bDisableShopDialMove = false; bool bDisableShopDialMove = false;
UFUNCTION(BlueprintCallable, Category= "ButtonLeft") UFUNCTION(BlueprintCallable, Category= "ButtonLeft")
virtual void CameraLeftMover(); virtual void CameraLeftMover();
@ -58,7 +72,29 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera") UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera")
UCameraComponent* MainCamera; UCameraComponent* MainCamera;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Player") UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Items")
ACharacter* TempCharacter; AActor* HealingItem;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Items")
AActor* BuffItem;
UFUNCTION(BlueprintCallable, Category = "ConfirmButtons")
virtual void CancelPurchase();
UFUNCTION(BlueprintCallable, Category = "ConfirmButtons")
virtual void ExitScreen();
UPROPERTY(EditAnywhere, Category = "Player")
ATempCharacter* TempCharacterRef;
private:
FVector TargetHealingLocation;
FVector TargetBuffLocation;
FVector CameraLocation;
FProperty* Property;
FProperty* BuyBuffProperty;
FProperty* BuyHealingProperty;
}; };

View File

@ -101,18 +101,35 @@ void ATempCharacter::LineTraceLogic()
if (AInteraction* MyInteractable = Cast<AInteraction>(OutHit.GetActor())) if (AInteraction* MyInteractable = Cast<AInteraction>(OutHit.GetActor()))
{ {
DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 1.0f); if (MyInteractable->ShopDialogWidget->IsVisible())
MyInteractable->OnInteract();
UE_LOG(LogTemp, Display, TEXT("OnInteract activated"));
UE_LOG(LogTemp, Display, TEXT("HIT: %s"), *OutHit.GetActor()->GetName());
// While loop to check bisDisabled var until it changes to true
while (MyInteractable->bisDisabled == false || MyInteractable->bDisableShopDialMove == false)
{ {
if (MyInteractable->bisDisabled == true || MyInteractable->bDisableShopDialMove == true) UE_LOG(LogTemp, Display, TEXT("ShopKeeper text is visible"));
bShopKeeperText = true;
return;
}
//if there is no text on screen this triggers
else
{
if (MyInteractable->ItemSelectorWidget->IsVisible())
{ {
InputDisabler(); return;
break; }
else
{
DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 1.0f);
MyInteractable->OnInteract();
UE_LOG(LogTemp, Display, TEXT("OnInteract activated"));
UE_LOG(LogTemp, Display, TEXT("HIT: %s"), *OutHit.GetActor()->GetName());
// While loop to check bisDisabled var until it changes to true
while (MyInteractable->bisDisabled == false || MyInteractable->bDisableShopDialMove == false)
{
if (MyInteractable->bisDisabled == true || MyInteractable->bDisableShopDialMove == true)
{
InputDisabler();
break;
}
}
} }
} }
} }
@ -122,6 +139,7 @@ void ATempCharacter::LineTraceLogic()
void ATempCharacter::InputDisabler() void ATempCharacter::InputDisabler()
{ {
UE_LOG(LogTemp, Display, TEXT("Disabling playermovement")); UE_LOG(LogTemp, Display, TEXT("Disabling playermovement"));
//GetWorld()->GetFirstPlayerController()->InputComponent->RemoveActionBinding("Interact", IE_Pressed);
GetWorld()->GetFirstPlayerController()->SetIgnoreLookInput(true); GetWorld()->GetFirstPlayerController()->SetIgnoreLookInput(true);
GetWorld()->GetFirstPlayerController()->SetIgnoreMoveInput(true); GetWorld()->GetFirstPlayerController()->SetIgnoreMoveInput(true);
GetWorld()->GetFirstPlayerController()->bShowMouseCursor = true; GetWorld()->GetFirstPlayerController()->bShowMouseCursor = true;
@ -150,6 +168,7 @@ void ATempCharacter::InputEnabler()
GetWorld()->GetFirstPlayerController()->bShowMouseCursor = false; GetWorld()->GetFirstPlayerController()->bShowMouseCursor = false;
GetWorld()->GetFirstPlayerController()->bEnableClickEvents = false; GetWorld()->GetFirstPlayerController()->bEnableClickEvents = false;
GetWorld()->GetFirstPlayerController()->bEnableMouseOverEvents = false; GetWorld()->GetFirstPlayerController()->bEnableMouseOverEvents = false;
//GetWorld()->GetFirstPlayerController()->InputComponent->BindAction("Interact", IE_Pressed, this, &ATempCharacter::KeyPressed);
TraceDistance = 300; TraceDistance = 300;
ThisCamera = Cast<UCameraComponent>(this->FindComponentByClass<UCameraComponent>()); ThisCamera = Cast<UCameraComponent>(this->FindComponentByClass<UCameraComponent>());
if (ThisCamera == nullptr) if (ThisCamera == nullptr)
@ -161,7 +180,6 @@ void ATempCharacter::InputEnabler()
ThisCamera->SetWorldLocation(OriginalCameraLocation); ThisCamera->SetWorldLocation(OriginalCameraLocation);
ThisCamera->SetWorldRotation(OriginalCameraRotation); ThisCamera->SetWorldRotation(OriginalCameraRotation);
ThisCamera->FieldOfView = OriginalCameraFOV; ThisCamera->FieldOfView = OriginalCameraFOV;
//ulog the originalcameralocation value //ulog the originalcameralocation value
UE_LOG(LogTemp, Display, TEXT("Original Camera Location: %s"), *OriginalCameraLocation.ToString()); UE_LOG(LogTemp, Display, TEXT("Original Camera Location: %s"), *OriginalCameraLocation.ToString());
} }

View File

@ -31,7 +31,10 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Inventory, meta = (AllowPrivateAccess = "true")) UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Inventory, meta = (AllowPrivateAccess = "true"))
class UInventoryComponent* Inventory; //Using the InventoryComponent class class UInventoryComponent* Inventory; //Using the InventoryComponent class
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Widgets")
UUserWidget* ItemSelectorWidget;
// Called to bind functionality to input // Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
@ -43,6 +46,8 @@ public:
void InputDisabler(); void InputDisabler();
void LineTraceLogic(); void LineTraceLogic();
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category= "Health") UPROPERTY(BlueprintReadWrite, EditAnywhere, Category= "Health")
float Health; float Health;
@ -70,5 +75,7 @@ public:
UFUNCTION(BlueprintCallable, Category= "Items") UFUNCTION(BlueprintCallable, Category= "Items")
void BuyItem(); void BuyItem();
bool bShopKeeperText = false;
}; };

View File

@ -1,319 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "RealTimeCombat.h"
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/TextBlock.h"
#include "Components/ProgressBar.h"
#include "Kismet/GameplayStatics.h"
ARealTimeCombat::ARealTimeCombat()
{
PrimaryActorTick.bCanEverTick = true;
if (HUDWidget == nullptr)
{
// Load the HUD widget from the specified path
static ConstructorHelpers::FClassFinder<UUserWidget> HUDWidgetClass(TEXT("/Game/Blueprints/Combat_UI/Combat_UI_RT"));
HUDWidget = HUDWidgetClass.Class;
}
}
void ARealTimeCombat::StartCombat()
{
if (HUD->IsInViewport()) return;
HUD->AddToViewport();
bStartTimer = true;
//EnemyActor = Enemy;
// if (APlayerController* PC = Cast<APlayerController>(GetWorld()->GetFirstPlayerController()))
// {
// PC->bShowMouseCursor = true;
// PC->bEnableClickEvents = true;
// PC->bEnableMouseOverEvents = true;
// }
}
void ARealTimeCombat::EndCombat()
{
//Remove the HUD from the viewport
HUD->RemoveFromViewport();
}
void ARealTimeCombat::OnMouseClick()
{
ExecuteCast(CurrentComboString);
}
void ARealTimeCombat::OnQPress()
{
if (ActiveActionPoints <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Action Points"));
return;
}
if (IronResource <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Iron"));
return;
}
UseActionPoint();
CurrentComboString.AppendChar('F');
UpdateComboString(CurrentComboString);
IronResource -= 1;
UpdateResourceBars();
}
void ARealTimeCombat::OnEPress()
{
if (ActiveActionPoints <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Action Points"));
return;
}
if (SulfurResource <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Sulfur"));
return;
}
UseActionPoint();
CurrentComboString.AppendChar('W');
UpdateComboString(CurrentComboString);
SulfurResource -= 1;
UpdateResourceBars();
}
void ARealTimeCombat::OnBackspacePress()
{
if (CurrentComboString.Len() <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Blank Combo"));
return;
}
ReuseActionPoint();
if (CurrentComboString.Right(1) == "F")
{
IronResource += 1;
}
else if (CurrentComboString.Right(1) == "W")
{
SulfurResource += 1;
}
CurrentComboString.RemoveAt(CurrentComboString.Len() - 1);
UpdateComboString(CurrentComboString);
UpdateResourceBars();
}
void ARealTimeCombat::BeginPlay()
{
Super::BeginPlay();
TArray<AActor*> AllCharacterActorsInScene;
UGameplayStatics::GetAllActorsOfClassWithTag(GetWorld(), AActor::StaticClass(), FName("Enemy"), AllCharacterActorsInScene);
for (AActor* Actor : AllCharacterActorsInScene)
{
EnemyActor = Cast<AActor>(Actor);
}
UGameplayStatics::GetAllActorsOfClassWithTag(GetWorld(), AActor::StaticClass(), FName("Player"), AllCharacterActorsInScene);
for (AActor* Actor : AllCharacterActorsInScene)
{
PlayerActor = Cast<AActor>(Actor);
}
HUD = CreateWidget<UUserWidget>(GetWorld(), HUDWidget);
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"));
IronResourceBar = Cast<UProgressBar>(HUD->GetWidgetFromName("IronResourceBar"));
SulfurResourceBar = Cast<UProgressBar>(HUD->GetWidgetFromName("SulfurResourceBar"));
ActionPointsBar = Cast<UProgressBar>(HUD->GetWidgetFromName("ActionPointsBar"));
}
void ARealTimeCombat::ExecuteCast(FString Combo)
{
if (!IsValidCombo(Combo))
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Invalid Combo"));
//For each character in the current combo add back the resource
for (int i = 0; i < Combo.Len(); i++)
{
if (Combo[i] == 'F')
{
IronResource += 1;
}
else if (Combo[i] == 'W')
{
SulfurResource += 1;
}
}
CurrentComboString = "";
UpdateComboString(CurrentComboString);
RevertActionPoints();
UpdateActionPoints();
UpdateResourceBars();
return;
}
CurrentComboString = "";
UpdateComboString(CurrentComboString);
RevertActionPoints();
UpdateActionPoints();
if (!HitEnemy())
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Missed"));
return;
}
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)));
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)));
break;
}
//End Combat if either the player or enemy is dead
if (EnemyHealth <= 0)
{
EndCombat();
EnemyActor->Destroy();
return;
}
if (PlayerHealth <= 0)
{
EndCombat();
return;
}
// SwitchTurn();
}
void ARealTimeCombat::UseActionPoint()
{
if (HeldActionPoints > 0 && ActiveActionPoints <= HeldActionPoints)
{
ActiveActionPoints -= 1;
UpdateActionPoints();
}
}
void ARealTimeCombat::ReuseActionPoint()
{
ActiveActionPoints += 1;
UpdateActionPoints();
}
void ARealTimeCombat::RevertActionPoints()
{
ActiveActionPoints = HeldActionPoints;
UpdateActionPoints();
}
void ARealTimeCombat::DamagePlayer(int Damage)
{
PlayerHealth -= FMath::Clamp(Damage, 0, 100);
UpdateProgressBars();
AddBattleLogMessage("Player was damaged for " + FString::FromInt(Damage) + " damage.");
}
void ARealTimeCombat::DamageEnemy(int Damage)
{
EnemyHealth -= FMath::Clamp(Damage, 0, 100);
UpdateProgressBars();
AddBattleLogMessage("Enemy was damaged for " + FString::FromInt(Damage) + " damage.");
}
void ARealTimeCombat::UpdateProgressBars() const
{
PlayerHealthBar->SetPercent(PlayerHealth / 100.0f);
EnemyHealthBar->SetPercent(EnemyHealth / 100.0f);
}
void ARealTimeCombat::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
if (ActionPointsTimer >= 1.0f && HeldActionPoints < MaxActionPoints && bStartTimer)
{
HeldActionPoints += 1;
ActiveActionPoints += 1;
UpdateActionPoints();
ActionPointsTimer = 0.0f;
}
else
{
ActionPointsTimer += DeltaSeconds;
ActionPointsBar->SetPercent(ActionPointsTimer);
}
}
bool ARealTimeCombat::IsValidCombo(FString Combo) const
{
return ValidCombos.Contains(Combo);
}
void ARealTimeCombat::UpdateComboString(FString NewCombo) const
{
CurrentComboTextBlock->SetText(FText::FromString(NewCombo));
}
void ARealTimeCombat::UpdateActionPoints() const
{
ActionPointsTextBlock->SetText(FText::FromString(FString::FromInt(ActiveActionPoints)));
}
void ARealTimeCombat::AddBattleLogMessage(FString Message)
{
BattleLog.Append(Message + "\n");
UpdateBattleLog();
}
void ARealTimeCombat::ClearBattleLog()
{
BattleLog = "";
}
void ARealTimeCombat::UpdateBattleLog()
{
TArray<FString> TempArray;
if (const int32 LineCount = BattleLog.ParseIntoArray(TempArray, TEXT("\n"), true); LineCount > 10)
{
ClearBattleLog();
}
BattleLogTextBlock->SetText(FText::FromString(BattleLog));
}
void ARealTimeCombat::UpdateResourceBars() const
{
IronResourceBar->SetPercent(IronResource / 10.0f);
SulfurResourceBar->SetPercent(SulfurResource / 10.0f);
}
bool ARealTimeCombat::HitEnemy() const
{
FHitResult HitResult;
FVector Start = PlayerActor->GetActorLocation();
FVector End = PlayerActor->GetActorForwardVector() * 1000.0f + Start;
FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(PlayerActor);
if (GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Pawn, CollisionParams))
{
DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 5.0f, 0, 10.0f);
if (HitResult.GetActor() == EnemyActor)
{
return true;
}
}
DrawDebugLine(GetWorld(), Start, End, FColor::Red, false, 5.0f, 0, 10.0f);
return false;
}

View File

@ -1,127 +0,0 @@
// 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 "GameFramework/GameStateBase.h"
#include "RealTimeCombat.generated.h"
UCLASS()
class THE_TWILIGHT_ABYSS_API ARealTimeCombat : public AGameStateBase
{
GENERATED_BODY()
ARealTimeCombat();
UPROPERTY(EditDefaultsOnly)
int PlayerHealth = 100;
UPROPERTY(EditDefaultsOnly)
int EnemyHealth = 100;
UPROPERTY(EditDefaultsOnly)
int MaxActionPoints = 3;
UPROPERTY(EditDefaultsOnly)
int ActiveActionPoints = 0;
UPROPERTY(EditDefaultsOnly)
int IronResource = 10; // F
UPROPERTY(EditDefaultsOnly)
int SulfurResource = 10; // W
UPROPERTY(VisibleAnywhere)
AActor* PlayerActor;
UPROPERTY(VisibleAnywhere)
AActor* EnemyActor;
// AActor* ActiveActor;
/*
TODO:
Reference Player Inventory
*/
UPROPERTY(EditAnywhere)
TSubclassOf<UUserWidget> HUDWidget;
UPROPERTY(EditAnywhere)
TMap<FString, int32> ValidCombos =
{
{"F", 10},
{"W", 10},
{"WW", 15},
{"FW", 20},
{"FFW", 30}
};
FString BattleLog;
UFUNCTION(BlueprintCallable)
void StartCombat();
UFUNCTION(BlueprintCallable)
void EndCombat();
UFUNCTION(BlueprintCallable)
void OnMouseClick();
UFUNCTION(BlueprintCallable)
void OnQPress();
UFUNCTION(BlueprintCallable)
void OnEPress();
UFUNCTION(BlueprintCallable)
void OnBackspacePress();
protected:
virtual void BeginPlay() override;
void ExecuteCast(FString Combo);
void UseActionPoint();
void ReuseActionPoint();
void RevertActionPoints();
void DamagePlayer(int Damage);
void DamageEnemy(int Damage);
void UpdateProgressBars() const;
virtual void Tick(float DeltaSeconds) override;
private:
bool IsValidCombo(FString Combo) const;
float ActionPointsTimer = 0.0f;
int HeldActionPoints = 0;
UPROPERTY()
UUserWidget* HUD;
UPROPERTY(VisibleAnywhere)
bool bIsPlayerTurn = true;
UPROPERTY(VisibleAnywhere)
FString CurrentComboString = "";
UPROPERTY(VisibleAnywhere)
UTextBlock* CurrentComboTextBlock;
UPROPERTY(VisibleAnywhere)
UTextBlock* BattleLogTextBlock;
UPROPERTY(VisibleAnywhere)
UTextBlock* ActionPointsTextBlock;
UPROPERTY(VisibleAnywhere)
UProgressBar* PlayerHealthBar;
UPROPERTY(VisibleAnywhere)
UProgressBar* EnemyHealthBar;
UPROPERTY(VisibleAnywhere)
UProgressBar* IronResourceBar;
UPROPERTY(VisibleAnywhere)
UProgressBar* SulfurResourceBar;
UPROPERTY(VisibleAnywhere)
UProgressBar* ActionPointsBar;
void UpdateComboString(FString NewCombo) const;
void UpdateActionPoints() const;
void AddBattleLogMessage(FString Message);
void ClearBattleLog();
void UpdateBattleLog();
void UpdateResourceBars() const;
bool HitEnemy() const;
bool bStartTimer = false;
};

View File

@ -1,35 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "PlayerCharacterCombatTest.h"
// Sets default values
APlayerCharacterCombatTest::APlayerCharacterCombatTest()
{
// 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;
Tags.Add(FName("Character"));
}
// Called when the game starts or when spawned
void APlayerCharacterCombatTest::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void APlayerCharacterCombatTest::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void APlayerCharacterCombatTest::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}

View File

@ -1,29 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "PlayerCharacterCombatTest.generated.h"
UCLASS()
class THE_TWILIGHT_ABYSS_API APlayerCharacterCombatTest : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
APlayerCharacterCombatTest();
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

@ -1,297 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "TurnBaseCombat.h"
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/TextBlock.h"
#include "Components/ProgressBar.h"
#include "Kismet/GameplayStatics.h"
ATurnBaseCombat::ATurnBaseCombat()
{
if (HUDWidget == nullptr)
{
// Load the HUD widget from the specified path
static ConstructorHelpers::FClassFinder<UUserWidget> HUDWidgetClass(TEXT("/Game/Blueprints/Combat_UI/Combat_UI"));
HUDWidget = HUDWidgetClass.Class;
}
}
void ATurnBaseCombat::StartCombat(AActor* Enemy)
{
if (HUD->IsInViewport()) return;
HUD->AddToViewport();
EnemyActor = Enemy;
if (APlayerController* PC = Cast<APlayerController>(GetWorld()->GetFirstPlayerController()))
{
PC->bShowMouseCursor = true;
PC->bEnableClickEvents = true;
PC->bEnableMouseOverEvents = true;
}
}
void ATurnBaseCombat::EndCombat()
{
//Remove the HUD from the viewport
HUD->RemoveFromViewport();
}
void ATurnBaseCombat::BeginPlay()
{
Super::BeginPlay();
TArray<AActor*> AllCharacterActorsInScene;
UGameplayStatics::GetAllActorsOfClassWithTag(GetWorld(), AActor::StaticClass(), FName("Character"), AllCharacterActorsInScene);
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"));
IronResourceBar = Cast<UProgressBar>(HUD->GetWidgetFromName("IronResourceBar"));
SulfurResourceBar = Cast<UProgressBar>(HUD->GetWidgetFromName("SulfurResourceBar"));
CastButton = Cast<UButton>(HUD->GetWidgetFromName("CastButton"));
FButton = Cast<UButton>(HUD->GetWidgetFromName("FButton"));
WButton = Cast<UButton>(HUD->GetWidgetFromName("WButton"));
BackspaceButton = Cast<UButton>(HUD->GetWidgetFromName("BackspaceButton"));
CastButton->OnClicked.AddDynamic(this, &ATurnBaseCombat::CastButtonOnClick);
FButton->OnClicked.AddDynamic(this, &ATurnBaseCombat::FButtonOnClick);
WButton->OnClicked.AddDynamic(this, &ATurnBaseCombat::WButtonOnClick);
BackspaceButton->OnClicked.AddDynamic(this, &ATurnBaseCombat::BackspaceButtonOnClick);
}
void ATurnBaseCombat::ExecuteCast(FString Combo)
{
if (!IsValidCombo(Combo))
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Invalid Combo"));
//For each character in the current combo add back the resource
for (int i = 0; i < Combo.Len(); i++)
{
if (Combo[i] == 'F')
{
IronResource += 1;
}
else if (Combo[i] == 'W')
{
SulfurResource += 1;
}
}
CurrentComboString = "";
UpdateComboString(CurrentComboString);
RevertActionPoints();
UpdateActionPoints();
UpdateResourceBars();
return;
}
CurrentComboString = "";
UpdateComboString(CurrentComboString);
RevertActionPoints();
UpdateActionPoints();
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)));
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)));
break;
}
//End Combat if either the player or enemy is dead
if (EnemyHealth <= 0)
{
EndCombat();
EnemyActor->Destroy();
return;
}
if (PlayerHealth <= 0)
{
EndCombat();
return;
}
SwitchTurn();
}
void ATurnBaseCombat::UseActionPoint()
{
ActiveActionPoints += 1;
UpdateActionPoints();
}
void ATurnBaseCombat::ReuseActionPoint()
{
ActiveActionPoints -= 1;
UpdateActionPoints();
}
void ATurnBaseCombat::RevertActionPoints()
{
ActiveActionPoints = 0;
UpdateActionPoints();
}
void ATurnBaseCombat::DamagePlayer(int Damage)
{
PlayerHealth -= FMath::Clamp(Damage, 0, 100);
UpdateProgressBars();
AddBattleLogMessage("Player was damaged for " + FString::FromInt(Damage) + " damage.");
}
void ATurnBaseCombat::DamageEnemy(int Damage)
{
EnemyHealth -= FMath::Clamp(Damage, 0, 100);
UpdateProgressBars();
AddBattleLogMessage("Enemy was damaged for " + FString::FromInt(Damage) + " damage.");
}
void ATurnBaseCombat::UpdateProgressBars() const
{
PlayerHealthBar->SetPercent(PlayerHealth / 100.0f);
EnemyHealthBar->SetPercent(EnemyHealth / 100.0f);
}
bool ATurnBaseCombat::IsValidCombo(FString Combo) const
{
return ValidCombos.Contains(Combo);
}
void ATurnBaseCombat::SwitchTurn()
{
//TurnIndicatorTextBlock->SetText(FText::FromString(bIsPlayerTurn ? "Enemy Turn" : "Player Turn"));
//bIsPlayerTurn = !bIsPlayerTurn;
TurnIndicatorTextBlock->SetText(FText::FromString("Enemy Turn"));
ToggleButtons();
//wait for 2 seconds
FTimerHandle UnusedHandle;
GetWorldTimerManager().SetTimer(UnusedHandle, this, &ATurnBaseCombat::EnemyTurn, 2.0f, false);
//activeActor = bIsPlayerTurn ? enemyActor : playerActor;
}
void ATurnBaseCombat::CastButtonOnClick()
{
ExecuteCast(CurrentComboString);
}
void ATurnBaseCombat::FButtonOnClick()
{
if (ActiveActionPoints >= DefaultActionPoints)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Action Points"));
return;
}
if (IronResource <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Iron"));
return;
}
UseActionPoint();
CurrentComboString.AppendChar('F');
UpdateComboString(CurrentComboString);
IronResource -= 1;
UpdateResourceBars();
}
void ATurnBaseCombat::WButtonOnClick()
{
if (ActiveActionPoints >= DefaultActionPoints)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Action Points"));
return;
}
if (SulfurResource <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("No More Sulfur"));
return;
}
UseActionPoint();
CurrentComboString.AppendChar('W');
UpdateComboString(CurrentComboString);
SulfurResource -= 1;
UpdateResourceBars();
}
void ATurnBaseCombat::BackspaceButtonOnClick()
{
if (CurrentComboString.Len() <= 0)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Blank Combo"));
return;
}
ReuseActionPoint();
if (CurrentComboString.Right(1) == "F")
{
IronResource += 1;
}
else if (CurrentComboString.Right(1) == "W")
{
SulfurResource += 1;
}
CurrentComboString.RemoveAt(CurrentComboString.Len() - 1);
UpdateComboString(CurrentComboString);
UpdateResourceBars();
}
void ATurnBaseCombat::UpdateComboString(FString NewCombo) const
{
CurrentComboTextBlock->SetText(FText::FromString(NewCombo));
}
void ATurnBaseCombat::UpdateActionPoints() const
{
ActionPointsTextBlock->SetText(FText::FromString(FString::FromInt(ActiveActionPoints)));
}
void ATurnBaseCombat::AddBattleLogMessage(FString Message)
{
BattleLog.Append(Message + "\n");
UpdateBattleLog();
}
void ATurnBaseCombat::ClearBattleLog()
{
BattleLog = "";
}
void ATurnBaseCombat::UpdateBattleLog()
{
TArray<FString> TempArray;
if (const int32 LineCount = BattleLog.ParseIntoArray(TempArray, TEXT("\n"), true); LineCount > 10)
{
ClearBattleLog();
}
BattleLogTextBlock->SetText(FText::FromString(BattleLog));
}
void ATurnBaseCombat::UpdateResourceBars() const
{
IronResourceBar->SetPercent(IronResource / 10.0f);
SulfurResourceBar->SetPercent(SulfurResource / 10.0f);
}
void ATurnBaseCombat::ToggleButtons() const
{
FButton->SetIsEnabled(!FButton->bIsEnabled);
WButton->SetIsEnabled(!WButton->bIsEnabled);
BackspaceButton->SetIsEnabled(!BackspaceButton->bIsEnabled);
CastButton->SetIsEnabled(!CastButton->bIsEnabled);
}
void ATurnBaseCombat::EnemyTurn()
{
DamagePlayer(10);
TurnIndicatorTextBlock->SetText(FText::FromString("Player Turn"));
ToggleButtons();
}

View File

@ -1,145 +0,0 @@
// 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 "GameFramework/GameStateBase.h"
#include "TurnBaseCombat.generated.h"
/**
*
*/
UCLASS()
class THE_TWILIGHT_ABYSS_API ATurnBaseCombat : public AGameStateBase
{
GENERATED_BODY()
public:
ATurnBaseCombat();
UPROPERTY(EditDefaultsOnly)
int PlayerHealth = 100;
UPROPERTY(EditDefaultsOnly)
int EnemyHealth = 100;
UPROPERTY(EditDefaultsOnly)
int DefaultActionPoints = 3;
UPROPERTY(EditDefaultsOnly)
int ActiveActionPoints = 0;
UPROPERTY(EditDefaultsOnly)
int IronResource = 10; // F
UPROPERTY(EditDefaultsOnly)
int SulfurResource = 10; // W
// AActor* PlayerActor;
UPROPERTY(VisibleAnywhere)
AActor* EnemyActor;
// AActor* ActiveActor;
/*
TODO:
Reference Player Inventory
*/
UPROPERTY(EditAnywhere)
TSubclassOf<UUserWidget> HUDWidget;
UPROPERTY(EditAnywhere)
TMap<FString, int32> ValidCombos =
{
{"F", 10},
{"W", 10},
{"WW", 15},
{"FW", 20},
{"FFW", 30}
};
FString BattleLog;
UFUNCTION(BlueprintCallable)
void StartCombat(AActor* Enemy);
UFUNCTION(BlueprintCallable)
void EndCombat();
protected:
virtual void BeginPlay() override;
void ExecuteCast(FString Combo);
void UseActionPoint();
void ReuseActionPoint();
void RevertActionPoints();
void DamagePlayer(int Damage);
void DamageEnemy(int Damage);
void UpdateProgressBars() const;
private:
bool IsValidCombo(FString Combo) const;
UPROPERTY()
UUserWidget* HUD;
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* IronResourceBar;
UPROPERTY(VisibleAnywhere)
UProgressBar* SulfurResourceBar;
UPROPERTY(VisibleAnywhere)
UButton* CastButton;
UPROPERTY(VisibleAnywhere)
UButton* FButton;
UPROPERTY(VisibleAnywhere)
UButton* WButton;
UPROPERTY(VisibleAnywhere)
UButton* BackspaceButton;
UFUNCTION()
void CastButtonOnClick();
UFUNCTION()
void FButtonOnClick();
UFUNCTION()
void WButtonOnClick();
UFUNCTION()
void BackspaceButtonOnClick();
void UpdateComboString(FString NewCombo) const;
void UpdateActionPoints() const;
void AddBattleLogMessage(FString Message);
void ClearBattleLog();
void UpdateBattleLog();
void UpdateResourceBars() const;
void ToggleButtons() const;
void EnemyTurn();
};

View File

@ -24,11 +24,11 @@ void UHoldToInitCombat::BeginPlay()
Super::BeginPlay(); Super::BeginPlay();
InitCombatWidget = CreateWidget<UUserWidget>(GetWorld(), InitCombatWidgetClass); InitCombatWidget = CreateWidget<UUserWidget>(GetWorld(), InitCombatWidgetClass);
UInputComponent* playerInputComponent = GetWorld()->GetFirstPlayerController()->InputComponent; UInputComponent* PlayerInputComponent = GetWorld()->GetFirstPlayerController()->InputComponent;
//Bind Right Mouse Button to the function OnRightClickDown //Bind Right Mouse Button to the function OnRightClickDown
playerInputComponent->BindAction("RightClick", IE_Pressed, this, &UHoldToInitCombat::OnRightClickDown); PlayerInputComponent->BindAction("RightClick", IE_Pressed, this, &UHoldToInitCombat::OnRightClickDown);
//Bind Right Mouse Button to the function OnRightClickUp //Bind Right Mouse Button to the function OnRightClickUp
playerInputComponent->BindAction("RightClick", IE_Released, this, &UHoldToInitCombat::OnRightClickUp); PlayerInputComponent->BindAction("RightClick", IE_Released, this, &UHoldToInitCombat::OnRightClickUp);
} }
@ -37,17 +37,22 @@ void UHoldToInitCombat::TickComponent(float DeltaTime, ELevelTick TickType, FAct
{ {
Super::TickComponent(DeltaTime, TickType, ThisTickFunction); Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
//If the player is holding down the right mouse button for 3 seconds, then the player will enter combat mode // //If the player is holding down the right mouse button for 3 seconds, then the player will enter combat mode
if (bRightClickDown && RightClickDownTime < 0.1f) // if (bRightClickDown && RightClickDownTime < 0.1f)
// {
// RightClickDownTime += DeltaTime;
// }
// else if (bRightClickDown && RightClickDownTime >= 0.1f)
// {
// //Enter Combat Mode
// Cast<ATurnBaseCombatV2>(GetWorld()->GetGameState())->StartCombat(TargetEnemy);
// //UBlackboardComponent* TargetEnemyBlackboard = Cast<UBlackboardComponent>(TargetEnemy->GetComponentByClass(UBlackboardComponent::StaticClass()));
// //TargetEnemyBlackboard->SetValueAsBool("IsInCombat", true);
// OnRightClickUp();
// }
if (bRightClickDown)
{ {
RightClickDownTime += DeltaTime;
}
else if (bRightClickDown && RightClickDownTime >= 0.1f)
{
//Enter Combat Mode
Cast<ATurnBaseCombatV2>(GetWorld()->GetGameState())->StartCombat(TargetEnemy); Cast<ATurnBaseCombatV2>(GetWorld()->GetGameState())->StartCombat(TargetEnemy);
//UBlackboardComponent* TargetEnemyBlackboard = Cast<UBlackboardComponent>(TargetEnemy->GetComponentByClass(UBlackboardComponent::StaticClass()));
//TargetEnemyBlackboard->SetValueAsBool("IsInCombat", true);
OnRightClickUp(); OnRightClickUp();
} }
} }
@ -58,7 +63,17 @@ void UHoldToInitCombat::OnRightClickDown()
{ {
TargetEnemy = RightClickHit; TargetEnemy = RightClickHit;
bRightClickDown = true; bRightClickDown = true;
InitCombatWidget->AddToViewport(); //InitCombatWidget->AddToViewport();
}
if (GunEffect)
{
//Get Player Actor
const AActor* PlayerActor = GetWorld()->GetFirstPlayerController()->GetPawn();
//Get Static Mesh Location on the player actor
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());
} }
} }
@ -68,29 +83,29 @@ void UHoldToInitCombat::OnRightClickUp()
RightClickDownTime = 0.0f; RightClickDownTime = 0.0f;
if (InitCombatWidget->IsInViewport()) if (InitCombatWidget->IsInViewport())
{ {
InitCombatWidget->RemoveFromViewport(); InitCombatWidget->RemoveFromParent();
} }
} }
AActor* UHoldToInitCombat::LookingAtEnemy() const AActor* UHoldToInitCombat::LookingAtEnemy() const
{ {
FVector Start = GetOwner()->GetActorLocation(); FVector Start = GetOwner()->GetActorLocation();
FVector End = GetOwner()->GetActorForwardVector() * 1500.0f + Start; FVector End = GetOwner()->GetActorForwardVector() * 1000.0f + Start;
FCollisionQueryParams CollisionParams; FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(GetOwner()); CollisionParams.AddIgnoredActor(GetOwner());
if (FHitResult HitResult; GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Pawn, CollisionParams)) if (FHitResult HitResult; GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Pawn, CollisionParams))
{ {
DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 5.0f, 0, 10.0f); //DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 5.0f, 0, 10.0f);
if (HitResult.GetActor()->Tags.Contains("Enemy")) if (HitResult.GetActor()->Tags.Contains("Enemy"))
{ {
return HitResult.GetActor(); return HitResult.GetActor();
} }
if (HitResult.GetActor()->Tags.Contains("Break")) if (HitResult.GetActor()->Tags.Contains("Break"))
{ {
HitResult.GetActor()->Destroy(); HitResult.GetActor()->Destroy();
return nullptr; return nullptr;
} }
} }
DrawDebugLine(GetWorld(), Start, End, FColor::Red, false, 5.0f, 0, 10.0f); //DrawDebugLine(GetWorld(), Start, End, FColor::Red, false, 5.0f, 0, 10.0f);
return nullptr; return nullptr;
} }

View File

@ -4,8 +4,11 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Components/ActorComponent.h" #include "Components/ActorComponent.h"
#include "NiagaraComponent.h"
#include "NiagaraFunctionLibrary.h"
#include "HoldToInitCombat.generated.h" #include "HoldToInitCombat.generated.h"
class UNiagaraSystem;
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class THE_TWILIGHT_ABYSS_API UHoldToInitCombat : public UActorComponent class THE_TWILIGHT_ABYSS_API UHoldToInitCombat : public UActorComponent
@ -20,6 +23,9 @@ public:
UPROPERTY() UPROPERTY()
TSubclassOf<UUserWidget> InitCombatWidgetClass; TSubclassOf<UUserWidget> InitCombatWidgetClass;
UPROPERTY(EditDefaultsOnly)
UNiagaraSystem* GunEffect;
protected: protected:
// Called when the game starts // Called when the game starts
virtual void BeginPlay() override; virtual void BeginPlay() override;

View File

@ -3,16 +3,18 @@
#include "TurnBaseCombatV2.h" #include "TurnBaseCombatV2.h"
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "AIController.h"
#include "Blueprint/UserWidget.h" #include "Blueprint/UserWidget.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Components/TextBlock.h" #include "Components/TextBlock.h"
#include "Components/ProgressBar.h" #include "Components/ProgressBar.h"
#include "GameFramework/Character.h" #include "GameFramework/Character.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "the_twilight_abyss/PlayerTemp/TempCharacter.h"
// Sets default values // Sets default values
ATurnBaseCombatV2::ATurnBaseCombatV2() ATurnBaseCombatV2::ATurnBaseCombatV2()
{ {
if (HUDWidget == nullptr) if (HUDWidget == nullptr)
{ {
// Load the HUD widget from the specified path // Load the HUD widget from the specified path
@ -23,10 +25,23 @@ ATurnBaseCombatV2::ATurnBaseCombatV2()
void ATurnBaseCombatV2::StartCombat(AActor* Enemy) 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 (HUD->IsInViewport()) return; if (HUD->IsInViewport()) return;
HUD->AddToViewport(); HUD->AddToViewport();
EnemyActor = Enemy; EnemyActor = Enemy;
IronResource = 10;
SulfurResource = 10;
if (APlayerController* PC = Cast<APlayerController>(GetWorld()->GetFirstPlayerController())) if (APlayerController* PC = Cast<APlayerController>(GetWorld()->GetFirstPlayerController()))
{ {
PC->bShowMouseCursor = true; PC->bShowMouseCursor = true;
@ -48,7 +63,7 @@ void ATurnBaseCombatV2::StartCombat(AActor* Enemy)
void ATurnBaseCombatV2::EndCombat() void ATurnBaseCombatV2::EndCombat()
{ {
//Remove the HUD from the viewport //Remove the HUD from the viewport
HUD->RemoveFromViewport(); HUD->RemoveFromParent();
APawn* PlayerPawn = Cast<APawn>(GetWorld()->GetFirstPlayerController()->GetPawn()); APawn* PlayerPawn = Cast<APawn>(GetWorld()->GetFirstPlayerController()->GetPawn());
PlayerPawn->bUseControllerRotationYaw = true; PlayerPawn->bUseControllerRotationYaw = true;
PlayerPawn->bUseControllerRotationPitch = true; PlayerPawn->bUseControllerRotationPitch = true;
@ -57,6 +72,17 @@ void ATurnBaseCombatV2::EndCombat()
{ {
PlayerCharacter->EnableInput(GetWorld()->GetFirstPlayerController()); PlayerCharacter->EnableInput(GetWorld()->GetFirstPlayerController());
} }
if (APlayerController* PC = Cast<APlayerController>(GetWorld()->GetFirstPlayerController()))
{
PC->bShowMouseCursor = false;
PC->bEnableClickEvents = false;
PC->bEnableMouseOverEvents = false;
}
GetWorld()->GetFirstPlayerController()->SetIgnoreLookInput(false);
GetWorld()->GetFirstPlayerController()->SetIgnoreMoveInput(false);
GetWorld()->GetFirstPlayerController()->bShowMouseCursor = false;
GetWorld()->GetFirstPlayerController()->bEnableClickEvents = false;
GetWorld()->GetFirstPlayerController()->bEnableMouseOverEvents = false;
} }
void ATurnBaseCombatV2::FKeyPressed() void ATurnBaseCombatV2::FKeyPressed()
@ -80,6 +106,7 @@ void ATurnBaseCombatV2::BeginPlay()
{ {
PlayerActor = Cast<AActor>(Actor); PlayerActor = Cast<AActor>(Actor);
} }
PlayerHealth = &Cast<ATempCharacter>(PlayerActor)->Health;
HUD = CreateWidget<UUserWidget>(GetWorld(), HUDWidget); HUD = CreateWidget<UUserWidget>(GetWorld(), HUDWidget);
@ -95,10 +122,12 @@ void ATurnBaseCombatV2::BeginPlay()
FButton = Cast<UButton>(HUD->GetWidgetFromName("FButton")); FButton = Cast<UButton>(HUD->GetWidgetFromName("FButton"));
WButton = Cast<UButton>(HUD->GetWidgetFromName("WButton")); WButton = Cast<UButton>(HUD->GetWidgetFromName("WButton"));
BackspaceButton = Cast<UButton>(HUD->GetWidgetFromName("BackspaceButton")); BackspaceButton = Cast<UButton>(HUD->GetWidgetFromName("BackspaceButton"));
RunButton = Cast<UButton>(HUD->GetWidgetFromName("RunButton"));
CastButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::CastButtonOnClick); CastButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::CastButtonOnClick);
FButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::FButtonOnClick); FButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::FButtonOnClick);
WButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::WButtonOnClick); WButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::WButtonOnClick);
BackspaceButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::BackspaceButtonOnClick); BackspaceButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::BackspaceButtonOnClick);
RunButton->OnClicked.AddDynamic(this, &ATurnBaseCombatV2::RunButtonOnClick);
} }
void ATurnBaseCombatV2::ExecuteCast(FString Combo) void ATurnBaseCombatV2::ExecuteCast(FString Combo)
@ -153,13 +182,13 @@ void ATurnBaseCombatV2::ExecuteCast(FString Combo)
break; break;
} }
//End Combat if either the player or enemy is dead //End Combat if either the player or enemy is dead
if (EnemyHealth <= 0) if (*EnemyHealth <= 0)
{ {
EndCombat(); EndCombat();
EnemyActor->Destroy(); EnemyActor->Destroy();
return; return;
} }
if (PlayerHealth <= 0) if (*PlayerHealth <= 0)
{ {
EndCombat(); EndCombat();
return; return;
@ -188,22 +217,22 @@ void ATurnBaseCombatV2::RevertActionPoints()
void ATurnBaseCombatV2::DamagePlayer(int Damage) void ATurnBaseCombatV2::DamagePlayer(int Damage)
{ {
PlayerHealth -= FMath::Clamp(Damage, 0, 100); *PlayerHealth -= FMath::Clamp(Damage, 0, 100);
UpdateProgressBars(); UpdateProgressBars();
AddBattleLogMessage("Player was damaged for " + FString::FromInt(Damage) + " damage."); AddBattleLogMessage("Player was damaged for " + FString::FromInt(Damage) + " damage.");
} }
void ATurnBaseCombatV2::DamageEnemy(int Damage) void ATurnBaseCombatV2::DamageEnemy(int Damage)
{ {
EnemyHealth -= FMath::Clamp(Damage, 0, 100); *EnemyHealth -= FMath::Clamp(Damage, 0, 100);
UpdateProgressBars(); UpdateProgressBars();
AddBattleLogMessage("Enemy was damaged for " + FString::FromInt(Damage) + " damage."); AddBattleLogMessage("Enemy was damaged for " + FString::FromInt(Damage) + " damage.");
} }
void ATurnBaseCombatV2::UpdateProgressBars() const void ATurnBaseCombatV2::UpdateProgressBars() const
{ {
PlayerHealthBar->SetPercent(PlayerHealth / 100.0f); PlayerHealthBar->SetPercent(*PlayerHealth / 100.0f);
EnemyHealthBar->SetPercent(EnemyHealth / 100.0f); EnemyHealthBar->SetPercent(*EnemyHealth / 100.0f);
} }
bool ATurnBaseCombatV2::IsValidCombo(FString Combo) const bool ATurnBaseCombatV2::IsValidCombo(FString Combo) const
@ -220,7 +249,7 @@ void ATurnBaseCombatV2::SwitchTurn()
//wait for 2 seconds //wait for 2 seconds
FTimerHandle UnusedHandle; FTimerHandle UnusedHandle;
GetWorldTimerManager().SetTimer(UnusedHandle, this, &ATurnBaseCombatV2::EnemyTurn, 2.0f, false); GetWorldTimerManager().SetTimer(UnusedHandle, this, &ATurnBaseCombatV2::EnemyTurn, 2.0f, false);
//activeActor = bIsPlayerTurn ? enemyActor : playerActor; //activeActor = bIsPlayerTurn ? enemyActor : playerActor;
} }
@ -288,6 +317,14 @@ void ATurnBaseCombatV2::BackspaceButtonOnClick()
UpdateResourceBars(); UpdateResourceBars();
} }
void ATurnBaseCombatV2::RunButtonOnClick()
{
UBlackboardComponent* EnemyBlackboard = Cast<AAIController>(EnemyActor->GetInstigatorController())->GetBlackboardComponent();
EnemyBlackboard->SetValueAsBool("IsInCombat", false);
EndCombat();
}
void ATurnBaseCombatV2::UpdateComboString(FString NewCombo) const void ATurnBaseCombatV2::UpdateComboString(FString NewCombo) const
{ {
CurrentComboTextBlock->SetText(FText::FromString(NewCombo)); CurrentComboTextBlock->SetText(FText::FromString(NewCombo));
@ -295,7 +332,7 @@ void ATurnBaseCombatV2::UpdateComboString(FString NewCombo) const
void ATurnBaseCombatV2::UpdateActionPoints() const void ATurnBaseCombatV2::UpdateActionPoints() const
{ {
ActionPointsTextBlock->SetText(FText::FromString(FString::FromInt(ActiveActionPoints))); ActionPointsTextBlock->SetText(FText::FromString(FString::FromInt(DefaultActionPoints - ActiveActionPoints)));
} }
void ATurnBaseCombatV2::AddBattleLogMessage(FString Message) void ATurnBaseCombatV2::AddBattleLogMessage(FString Message)
@ -331,6 +368,7 @@ void ATurnBaseCombatV2::ToggleButtons() const
WButton->SetIsEnabled(!WButton->GetIsEnabled()); WButton->SetIsEnabled(!WButton->GetIsEnabled());
BackspaceButton->SetIsEnabled(!BackspaceButton->GetIsEnabled()); BackspaceButton->SetIsEnabled(!BackspaceButton->GetIsEnabled());
CastButton->SetIsEnabled(!CastButton->GetIsEnabled()); CastButton->SetIsEnabled(!CastButton->GetIsEnabled());
RunButton->SetIsEnabled(!RunButton->GetIsEnabled());
} }
void ATurnBaseCombatV2::EnemyTurn() void ATurnBaseCombatV2::EnemyTurn()
@ -338,4 +376,4 @@ void ATurnBaseCombatV2::EnemyTurn()
DamagePlayer(10); DamagePlayer(10);
TurnIndicatorTextBlock->SetText(FText::FromString("Player Turn")); TurnIndicatorTextBlock->SetText(FText::FromString("Player Turn"));
ToggleButtons(); ToggleButtons();
} }

View File

@ -21,10 +21,8 @@ class THE_TWILIGHT_ABYSS_API ATurnBaseCombatV2 : public AGameStateBase
public: public:
ATurnBaseCombatV2(); ATurnBaseCombatV2();
UPROPERTY(EditDefaultsOnly) int* EnemyHealth = nullptr;
int PlayerHealth = 100; float* PlayerHealth = nullptr;
UPROPERTY(EditDefaultsOnly)
int EnemyHealth = 100;
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
int DefaultActionPoints = 3; int DefaultActionPoints = 3;
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
@ -128,6 +126,9 @@ private:
UPROPERTY(VisibleAnywhere) UPROPERTY(VisibleAnywhere)
UButton* BackspaceButton; UButton* BackspaceButton;
UPROPERTY(VisibleAnywhere)
UButton* RunButton;
UFUNCTION() UFUNCTION()
void CastButtonOnClick(); void CastButtonOnClick();
@ -140,6 +141,9 @@ private:
UFUNCTION() UFUNCTION()
void BackspaceButtonOnClick(); void BackspaceButtonOnClick();
UFUNCTION()
void RunButtonOnClick();
void UpdateComboString(FString NewCombo) const; void UpdateComboString(FString NewCombo) const;
void UpdateActionPoints() const; void UpdateActionPoints() const;

View File

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

View File

@ -9,6 +9,7 @@ public class the_twilight_abyssEditorTarget : TargetRules
{ {
Type = TargetType.Editor; Type = TargetType.Editor;
DefaultBuildSettings = BuildSettingsVersion.V2; DefaultBuildSettings = BuildSettingsVersion.V2;
IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_1;
ExtraModuleNames.AddRange( new string[] { "the_twilight_abyss" } ); ExtraModuleNames.AddRange( new string[] { "the_twilight_abyss" } );
} }
} }

View File

@ -1,3 +1,7 @@
# The Twilight Abyss # The Twilight Abyss
## By Team 2:13 ## By Team 2:13
### Character Dialogue
https://docs.google.com/spreadsheets/d/13iVCQuveBiaihpREnY145OZi5QT-1sseNoI0A5v8D1o/edit?usp=sharing

View File

@ -30,6 +30,10 @@
"Mac", "Mac",
"Linux" "Linux"
] ]
},
{
"Name": "ApexDestruction",
"Enabled": true
} }
], ],
"TargetPlatforms": [ "TargetPlatforms": [