// 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 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(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 AllCharacterActorsInScene; UGameplayStatics::GetAllActorsOfClassWithTag(GetWorld(), AActor::StaticClass(), FName("Character"), AllCharacterActorsInScene); HUD = CreateWidget(GetWorld(), HUDWidget); TurnIndicatorTextBlock = Cast(HUD->GetWidgetFromName("TurnIndicator")); CurrentComboTextBlock = Cast(HUD->GetWidgetFromName("CurrentCombo")); ActionPointsTextBlock = Cast(HUD->GetWidgetFromName("ActionPoints")); BattleLogTextBlock = Cast(HUD->GetWidgetFromName("BattleLog")); PlayerHealthBar = Cast(HUD->GetWidgetFromName("PlayerHealthBar")); EnemyHealthBar = Cast(HUD->GetWidgetFromName("EnemyHealthBar")); IronResourceBar = Cast(HUD->GetWidgetFromName("IronResourceBar")); SulfurResourceBar = Cast(HUD->GetWidgetFromName("SulfurResourceBar")); CastButton = Cast(HUD->GetWidgetFromName("CastButton")); FButton = Cast(HUD->GetWidgetFromName("FButton")); WButton = Cast(HUD->GetWidgetFromName("WButton")); BackspaceButton = Cast(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 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(); }