// 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 "the_twilight_abyss/PlayerTemp/TempCharacter.h" // Sets default values ATurnBaseCombatV2::ATurnBaseCombatV2() { if (HUDWidget == nullptr) { static ConstructorHelpers::FClassFinder HUDWidgetClass(TEXT("/Game/Blueprints/Combat_UI/Combat_UI")); HUDWidget = HUDWidgetClass.Class; static ConstructorHelpers::FClassFinder StatusEffectThornsClassFinder(TEXT("/Game/Blueprints/StatusEffects/BP_Thorns")); ThornsStatusEffect = StatusEffectThornsClassFinder.Class; static ConstructorHelpers::FClassFinder StatusEffectDOTClassFinder(TEXT("/Game/Blueprints/StatusEffects/BP_DamageOverTime")); DOTStatusEffect = StatusEffectDOTClassFinder.Class; static ConstructorHelpers::FClassFinder DeathScreenWidgetClass(TEXT("/Game/Blueprints/Death_UI/Death_UI")); DeathScreenWidgetSubclass = DeathScreenWidgetClass.Class; } } void ATurnBaseCombatV2::StartCombat(AActor* Enemy) { if (Enemy == nullptr) return; UBlackboardComponent* EnemyBlackboard = Cast(Enemy->GetInstigatorController())->GetBlackboardComponent(); if (EnemyBlackboard->GetValueAsBool("IsInCombat")) return; EnemyBlackboard->SetValueAsBool("IsInCombat", true); FProperty* HealthProperty = Enemy->GetClass()->FindPropertyByName(FName("Health")); int32* EnemyHealthPtr = HealthProperty->ContainerPtrToValuePtr(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(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(GetWorld()->GetFirstPlayerController()->GetPawn()); PlayerPawn->bUseControllerRotationYaw = true; PlayerPawn->bUseControllerRotationPitch = true; //Enable Character Movement if (ACharacter* PlayerCharacter = Cast(GetWorld()->GetFirstPlayerController()->GetPawn())) { PlayerCharacter->EnableInput(GetWorld()->GetFirstPlayerController()); } //Set to Game Mode Only APlayerController* PlayerController = GetWorld()->GetFirstPlayerController(); PlayerController->SetInputMode(FInputModeGameOnly()); PlayerController->bShowMouseCursor = false; } void ATurnBaseCombatV2::BeginPlay() { Super::BeginPlay(); TArray AllCharacterActorsInScene; UGameplayStatics::GetAllActorsOfClassWithTag(GetWorld(), AActor::StaticClass(), FName("Player"), AllCharacterActorsInScene); for (AActor* Actor : AllCharacterActorsInScene) { PlayerActor = Cast(Actor); } PlayerHealth = &Cast(PlayerActor)->Health; HUD = CreateWidget(GetWorld(), HUDWidget); TArray PlayerChildActors; PlayerActor->GetAllChildActors(PlayerChildActors, false); PlayerWidget = Cast(PlayerChildActors[0]->GetComponentByClass(UWidgetComponent::StaticClass())); PlayerWidget->InitWidget(); BookHUD = PlayerWidget->GetWidget(); TurnIndicatorTextBlock = Cast(HUD->GetWidgetFromName("TurnIndicator")); CurrentComboTextBlock = Cast(BookHUD->GetWidgetFromName("CurrentCombo")); CurrentComboTextBlock1 = Cast(BookHUD->GetWidgetFromName("CurrentCombo_1")); CurrentComboTextBlock2 = Cast(BookHUD->GetWidgetFromName("CurrentCombo_2")); BattleLogTextBlock = Cast(HUD->GetWidgetFromName("BattleLog")); PlayerHealthBar = Cast(BookHUD->GetWidgetFromName("PlayerHealthBar")); EnemyHealthBar = Cast(HUD->GetWidgetFromName("EnemyHealthBar")); ProbertiumResourceBar = Cast(BookHUD->GetWidgetFromName("ProbertiumResourceBar")); EisResourceBar = Cast(BookHUD->GetWidgetFromName("EisResourceBar")); AzosResourceBar = Cast(BookHUD->GetWidgetFromName("AzosResourceBar")); IroquoidResourceBar = Cast(BookHUD->GetWidgetFromName("IroquoidResourceBar")); CastButton = Cast(HUD->GetWidgetFromName("CastButton")); PButton = Cast(HUD->GetWidgetFromName("PButton")); EButton = Cast(HUD->GetWidgetFromName("EButton")); AButton = Cast(HUD->GetWidgetFromName("AButton")); IButton = Cast(HUD->GetWidgetFromName("IButton")); BackspaceButton = Cast(HUD->GetWidgetFromName("BackspaceButton")); RunButton = Cast(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(PlayerActor->GetComponentByClass(UStatusSystem::StaticClass())); if (Combo == "AAE") { UStatusEffect* TempThornsStatusEffect = NewObject(PlayerActor, ThornsStatusEffect); StatusSystem->AddStatusEffect(TempThornsStatusEffect, 1, false); StatusEffects.Add(TempThornsStatusEffect); AddBattleLogMessage("Player Casted Thorns"); } else if (Combo == "PPI") { UStatusEffect* TempDOTStatusEffect = NewObject(PlayerActor, DOTStatusEffect); StatusSystem->AddStatusEffect(TempDOTStatusEffect, 1, false); StatusEffects.Add(TempDOTStatusEffect); AddBattleLogMessage("Player Casted DOT"); } } if (GunEffect) { const UStaticMeshComponent* GunComponent = Cast(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)); OnPlayerTurn.Broadcast(PlayerActor, EnemyActor); break; case false: // Enemy Turn DamagePlayer(*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(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(EnemyActor->GetInstigatorController())->GetBlackboardComponent(); EnemyBlackboard->SetValueAsBool("IsInCombat", false); EndCombat(); } void ATurnBaseCombatV2::UpdateComboString(FString NewCombo) const { CurrentComboTextBlock->SetText(FText::FromString("?")); CurrentComboTextBlock1->SetText(FText::FromString("?")); CurrentComboTextBlock2->SetText(FText::FromString("?")); if (IsValidCombo(NewCombo)) CurrentComboTextBlock->SetText(FText::FromString(NewCombo)); if (NewCombo.Len() == 1) { CurrentComboTextBlock1->SetText(FText::FromString(NewCombo)); } else if (NewCombo.Len() == 2) { CurrentComboTextBlock1->SetText(FText::FromString(NewCombo.LeftChop(1))); CurrentComboTextBlock2->SetText(FText::FromString(NewCombo.RightChop(1))); } } void ATurnBaseCombatV2::UpdateActionPoints() const { return; } void ATurnBaseCombatV2::AddBattleLogMessage(FString Message) { BattleLog.Append(Message + "\n"); UpdateBattleLog(); } void ATurnBaseCombatV2::ClearBattleLog() { BattleLog = ""; } void ATurnBaseCombatV2::UpdateBattleLog() { TArray 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(); }