Files
ProjectEleri/Source/ProjectEleri/Private/EleriPlayerController.cpp

1306 lines
42 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "EleriPlayerController.h"
#include "EnhancedInputComponent.h"
#include "GameFramework/Character.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "ProjectEleri/System/MainBlueprintFunctionLibrary.h"
#include "ProjectEleri/Components/MoveActorsComponent.h"
#include "../GameObjects/RemovableStaticMeshActor.h"
#include "Kismet/GameplayStatics.h"
#include "BookOfAlchemyManager.h"
#include "AlchemyManager.h"
#include "TimerManager.h"
#include "ProjectEleri/UI/CalendarScreen.h"
#include "ProjectEleri/UI/InteractionWidget.h"
#include "UI/AlchemyWidget.h"
#include "UI/EleriBaseWidget.h"
#include "ProjectEleri/GameObjects/BookActor.h"
#include "UI/TradeWidget.h"
#include "ProjectEleri/Public/UI/SelectionManager.h"
#include "ProjectEleri/DialogueSystem/DialogueWidget.h"
#include "Subsystem/InteractionSubsystem.h"
#include "Interface/InteractableActorInterface.h"
#include "EngineUtils.h"
#include "Components/StatForgeComponent.h"
#include "Helpers/StatForgeFunctionLibrary.h"
#include "ProjectEleri/Data/StatDefinitions.h"
#include "ProjectEleri/Items/SeedBedActor.h"
#include "ProjectEleri/Settings/EleriGameSettings.h"
#include "ProjectEleri/System/EleriGameplayTags.h"
AEleriPlayerController::AEleriPlayerController(const FObjectInitializer &ObjectInitializer)
: Super(ObjectInitializer)
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.bTickEvenWhenPaused = true;
}
void AEleriPlayerController::BeginPlay()
{
Super::BeginPlay();
PlayerCharacter = Cast<AMyCharacter>(GetCharacter());
MoveActorsComp = PlayerCharacter->GetComponentByClass<UMoveActorsComponent>();
MainGameUI = CreateWidget<UMainGameWidget>(this, MainGameWidgetBlueprint);
MainGameUI->AddToViewport();
if (UCharacterMovementComponent *CharMovement = PlayerCharacter->GetCharacterMovement())
{
CharMovement->MaxWalkSpeed = MinMovementSpeed;
}
MovementComponent = PlayerCharacter->GetComponentByClass<UCharacterMovementComponent>();
MovementDirection = FVector2D(0, -1);
bFlying = false;
BookOfAlchemyManager = Cast<ABookOfAlchemyManager>(UGameplayStatics::GetActorOfClass(GetWorld(), ABookOfAlchemyManager::StaticClass()));
AlchemyManager = Cast<AAlchemyManager>(UGameplayStatics::GetActorOfClass(GetWorld(), AAlchemyManager::StaticClass()));
SelectionManagerInventorySlots = NewObject<USelectionManager>();
ToggleMovement(true);
}
void AEleriPlayerController::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
ToggleMovement(true);
Super::EndPlay(EndPlayReason);
}
void AEleriPlayerController::ToggleMovement(bool bActive)
{
UStatForgeComponent* StatForgeComponent = UMainBlueprintFunctionLibrary::GetStatForgeComponentFromPlayer(this);
if (!StatForgeComponent) return;
if (bActive)
{
StatForgeComponent->RemoveGameplayStatEffect(MovementDisabledEffect);
return;
}
const UEleriGameSettings* GameSettings = UEleriGameSettings::GetEleriGameSettings();
ensure(GameSettings);
MovementDisabledEffect = StatForgeComponent->ApplyGameplayStatEffect(GameSettings->MovementDisableEffectClass, TMap<FName, float>());
}
void AEleriPlayerController::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (ACharacter *Char = GetCharacter())
{
if (UCharacterMovementComponent *CharMovement = Char->GetCharacterMovement())
{
if (CharMovement->IsFalling())
{
CharMovement->GravityScale = 25;
}
else
{
CharMovement->GravityScale = 3;
}
}
}
if (!ActorsOverlappingWith.IsEmpty())
{
for (int32 i = 0; i < ActorsOverlappingWith.Num(); i++)
{
if (!ActorsOverlappingWith[i]->Implements<UInteractableActorInterface>() || !IInteractableActorInterface::Execute_IsInteractable(ActorsOverlappingWith[i]))
{
RemoveInteractableObject(ActorsOverlappingWith[i]);
i--;
}
}
if (!IsInMenu() && !bIsInteractionMenuVisible)
{
ToggleInteractionMenu(true);
}
else if (IsInMenu() && bIsInteractionMenuVisible)
{
ToggleInteractionMenu(false);
}
}
if (TickBookAnimating)
{
TickBookTimer -= DeltaTime;
if (TickBookTimer <= 0.f)
{
DisableBookAnimating();
}
}
}
// BIND INPUT
void AEleriPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
// Make sure that we are using a UEnhancedInputComponent; if not, the project is not configured correctly.
if (UEnhancedInputComponent *PlayerEnhancedInputComponent = Cast<UEnhancedInputComponent>(InputComponent))
{
if (MoveAction)
{
PlayerEnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AEleriPlayerController::OnMove);
}
if (StartFlyingAction)
{
PlayerEnhancedInputComponent->BindAction(StartFlyingAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnStartFlyingAction);
}
if (SprintAction)
{
PlayerEnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnSprint);
PlayerEnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Completed, this, &AEleriPlayerController::OnStopSprint);
PlayerEnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Triggered, this, &AEleriPlayerController::OnFlyDownwardsAction);
}
if (JumpAction)
{
PlayerEnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnJump);
PlayerEnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &AEleriPlayerController::OnStopJump);
PlayerEnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &AEleriPlayerController::OnFlyUpwardsAction);
}
if (LookAction)
{
PlayerEnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AEleriPlayerController::OnLook);
}
if (ToggleCameraLook)
{
PlayerEnhancedInputComponent->BindAction(ToggleCameraLook, ETriggerEvent::Started, this, &AEleriPlayerController::OnLookEnable);
PlayerEnhancedInputComponent->BindAction(ToggleCameraLook, ETriggerEvent::Completed, this, &AEleriPlayerController::OnLookDisable);
}
if (WateringAction)
{
PlayerEnhancedInputComponent->BindAction(WateringAction, ETriggerEvent::Started, this,
&AEleriPlayerController::OnWateringActionStart);
PlayerEnhancedInputComponent->BindAction(WateringAction, ETriggerEvent::Completed, this,
&AEleriPlayerController::OnWateringActionEnd);
}
if (WateringThrowAction)
{
PlayerEnhancedInputComponent->BindAction(WateringThrowAction, ETriggerEvent::Started, this,
&AEleriPlayerController::OnWateringThrowAction);
}
if (OpenMainMenuAction)
{
PlayerEnhancedInputComponent->BindAction(OpenMainMenuAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnMainMenuToggle);
}
if (InventoryAction)
{
PlayerEnhancedInputComponent->BindAction(InventoryAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnInventoryToggle);
}
if (BookAction)
{
PlayerEnhancedInputComponent->BindAction(BookAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnBookToggle);
}
if (OrdersAction)
{
PlayerEnhancedInputComponent->BindAction(OrdersAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnOrdersToggle);
}
if (CalendarAction)
{
PlayerEnhancedInputComponent->BindAction(CalendarAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnCalendarToggle);
}
if (InteractAction)
{
PlayerEnhancedInputComponent->BindAction(InteractAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnInteract);
}
if (InteractExitAction)
{
PlayerEnhancedInputComponent->BindAction(InteractExitAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnInteractExit);
}
if (WaterSeedAction)
{
PlayerEnhancedInputComponent->BindAction(WaterSeedAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnHarvestSeed);
}
if (UiBackAction)
{
PlayerEnhancedInputComponent->BindAction(UiBackAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnControllerBackAction);
}
if (UiTabLeftAction)
{
PlayerEnhancedInputComponent->BindAction(UiTabLeftAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnControllerTabLeftAction);
}
if (UiTabRightAction)
{
PlayerEnhancedInputComponent->BindAction(UiTabRightAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnControllerTabRightAction);
}
//---------------------
// OBJECT REMOVAL INPUTS
//---------------------
if (StartObjectRemovalModeAction)
{
PlayerEnhancedInputComponent->BindAction(StartObjectRemovalModeAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnStartObjectRemovalAction);
}
if (RemoveAction)
{
PlayerEnhancedInputComponent->BindAction(RemoveAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnRemoveAction);
}
if (ExitRemoveModeAction)
{
PlayerEnhancedInputComponent->BindAction(ExitRemoveModeAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnExitRemoveModeAction);
}
if (StartMovingAction)
{
PlayerEnhancedInputComponent->BindAction(StartMovingAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnStartMovingAction);
}
if (PlaceObjectAction)
{
PlayerEnhancedInputComponent->BindAction(PlaceObjectAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnPlaceObjectAction);
}
if (RotateObjectAction)
{
PlayerEnhancedInputComponent->BindAction(RotateObjectAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnRotateObjectAction);
}
if (ToggleGridAction)
{
PlayerEnhancedInputComponent->BindAction(ToggleGridAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnToggleGridAction);
}
//---------------------
// BOOK INPUTS
//---------------------
if (BookNextPageAction)
{
PlayerEnhancedInputComponent->BindAction(BookNextPageAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnBookNextPage);
}
if (BookPreviousPageAction)
{
PlayerEnhancedInputComponent->BindAction(BookPreviousPageAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnBookPreviousPage);
}
if (BookItemTabAction)
{
PlayerEnhancedInputComponent->BindAction(BookItemTabAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnBookItemTab);
}
if (BookPotionTabAction)
{
PlayerEnhancedInputComponent->BindAction(BookPotionTabAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnBookPotionTab);
}
if (BookNextLetterAction)
{
PlayerEnhancedInputComponent->BindAction(BookNextLetterAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnBookNextLetter);
}
if (BookPreviousLetterAction)
{
PlayerEnhancedInputComponent->BindAction(BookPreviousLetterAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnBookPreviousLetter);
}
if (BookExitAction)
{
PlayerEnhancedInputComponent->BindAction(BookExitAction, ETriggerEvent::Started, this, &AEleriPlayerController::OnBookExit);
}
//---------------------
// ALCHEMY INPUTS
//---------------------
if (AlchemyStirringDirectionalInput)
{
PlayerEnhancedInputComponent->BindAction(AlchemyStirringDirectionalInput, ETriggerEvent::Triggered, this,
&AEleriPlayerController::OnAlchemyStirringDirectionInput);
}
if (AlchemyConfirmInput)
{
PlayerEnhancedInputComponent->BindAction(AlchemyConfirmInput, ETriggerEvent::Started, this,
&AEleriPlayerController::OnAlchemyConfirmInput);
}
//---------------------
// INTERACTION MENU INPUTS
//---------------------
if (InteractionMenuSelectAction)
{
PlayerEnhancedInputComponent->BindAction(InteractionMenuSelectAction, ETriggerEvent::Started, this,
&AEleriPlayerController::OnInteractionMenuSelectAction);
}
if (InteractionMenuUpAction)
{
PlayerEnhancedInputComponent->BindAction(InteractionMenuUpAction, ETriggerEvent::Started, this,
&AEleriPlayerController::OnInteractionMenuUpAction);
}
if (InteractionMenuDownAction)
{
PlayerEnhancedInputComponent->BindAction(InteractionMenuDownAction, ETriggerEvent::Started, this,
&AEleriPlayerController::OnInteractionMenuDownAction);
}
}
}
// INIT
void AEleriPlayerController::ClientRestart_Implementation(APawn *NewPawn)
{
Super::ClientRestart_Implementation(NewPawn);
// Get the Enhanced Input Local Player Subsystem from the Local Player related to our Player Controller.
if (UEnhancedInputLocalPlayerSubsystem *Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
{
// PawnClientRestart can run more than once in an Actor's lifetime, so start by clearing out any leftover mappings.
Subsystem->ClearAllMappings();
// Add each mapping context, along with their priority values. Higher values outprioritize lower values.
Subsystem->AddMappingContext(MovementContext, 1);
// Subsystem->AddMappingContext(MainUiContext, 2);
Subsystem->AddMappingContext(UiContext, 3);
Subsystem->AddMappingContext(ActionContext, 4);
}
}
// LOCOMOTION INPUT
void AEleriPlayerController::OnMove(const FInputActionValue &Value)
{
if (IsInMenu())
return;
const FVector2D AnalogueValue = Value.Get<FInputActionValue::Axis2D>();
MovementDirection = AnalogueValue;
if (PlayerCharacter)
{
if (UStatForgeFunctionLibrary::HasTag(CharacterState::MovementDisabled, PlayerCharacter))
{
return;
}
const float AppliedMovementVelocity = UStatForgeFunctionLibrary::GetStatValue(FStat::MovementSpeedMultiplier, PlayerCharacter);
const FVector ForwardVec = PlayerCharacter->GetPlayerCamera()->GetForwardVector();
const FVector RightVec = PlayerCharacter->GetPlayerCamera()->GetRightVector();
PlayerCharacter->AddMovementInput(ForwardVec, MovementDirection.Y * AppliedMovementVelocity);
PlayerCharacter->AddMovementInput(RightVec, MovementDirection.X * AppliedMovementVelocity);
}
}
void AEleriPlayerController::OnSprint(const FInputActionValue &Value)
{
if (IsInMenu() || Watering)
return;
ACharacter *Char = GetCharacter();
if (Char != nullptr && !bFlying)
{
MovementVelocity = 13.0f;
if (UCharacterMovementComponent *CharMovement = Char->GetCharacterMovement())
{
CharMovement->MaxWalkSpeed = MaxMovementSpeed;
}
}
}
void AEleriPlayerController::OnStopSprint(const FInputActionValue &Value)
{
ACharacter *Char = GetCharacter();
if (Char != nullptr)
{
MovementVelocity = 1.0f;
if (UCharacterMovementComponent *CharMovement = Char->GetCharacterMovement())
{
CharMovement->MaxWalkSpeed = MinMovementSpeed;
}
}
}
void AEleriPlayerController::OnJump(const FInputActionValue &Value)
{
if (IsInMenu() || Watering)
return;
ACharacter *Char = GetCharacter();
if (Char != nullptr && !bFlying)
{
Char->Jump();
}
}
void AEleriPlayerController::OnStopJump(const FInputActionValue &Value)
{
ACharacter *Char = GetCharacter();
if (Char != nullptr)
{
Char->StopJumping();
}
}
void AEleriPlayerController::OnLook(const FInputActionValue &Value)
{
if (IsInMenu())
return;
FVector2D AnalogueValue = Value.Get<FInputActionValue::Axis2D>();
if (PlayerCharacter != nullptr)
{
AddYawInput(AnalogueValue.X);
AddPitchInput(AnalogueValue.Y);
}
}
void AEleriPlayerController::OnLookEnable(const FInputActionValue &Value)
{
if (IsInMenu())
return;
AMyCharacter *Char = Cast<AMyCharacter>(GetCharacter());
if (Char != nullptr)
{
Char->RotateCam = true;
}
}
void AEleriPlayerController::OnLookDisable(const FInputActionValue &Value)
{
if (IsInMenu())
return;
AMyCharacter *Char = Cast<AMyCharacter>(GetCharacter());
if (Char != nullptr)
{
Char->RotateCam = false;
}
}
void AEleriPlayerController::OnWateringActionStart(const FInputActionValue &Value)
{
if (!PlayerCharacter ||
PlayerCharacter->CurrentlyDoing != ECurrentlyDoing::NOTHING ||
MainGameUI->IsAlchemyOpen() ||
IsInMenu())
return;
Watering = true;
PlayerCharacter->BeginWatering();
OnWatering.Broadcast(Watering);
OnChangeInputContext.Broadcast(2);
ToggleMovement(false);
}
void AEleriPlayerController::OnWateringActionEnd(const FInputActionValue &Value)
{
if (!PlayerCharacter ||
PlayerCharacter->CurrentlyDoing != ECurrentlyDoing::NOTHING ||
!Watering)
return;
Watering = false;
PlayerCharacter->EndWatering();
OnWatering.Broadcast(Watering);
OnChangeInputContext.Broadcast(1);
ToggleMovement(true);
}
void AEleriPlayerController::OnWateringThrowAction(const FInputActionValue &Value)
{
if (!PlayerCharacter ||
!Watering ||
PlayerCharacter->CurrentlyDoing != ECurrentlyDoing::NOTHING)
return;
PlayerCharacter->ThrowWaterBall();
OnChangeInputContext.Broadcast(1);
}
void AEleriPlayerController::OnStartFlyingAction(const FInputActionValue &Value)
{
if (bAnimatingFlying)
return;
bAnimatingFlying = true;
bFlying = !bFlying;
if (bFlying)
{
MovementComponent->AddImpulse(FVector::UpVector * 400000.f, false);
FTimerHandle FlyTimerHandle;
GetWorld()->GetTimerManager().SetTimer(FlyTimerHandle, FTimerDelegate::CreateLambda([this]
{
if (bFlying)
{
MovementComponent->Velocity = FVector::ZeroVector;
MovementComponent->SetMovementMode(EMovementMode::MOVE_Flying);
} }),
0.25f, false);
}
else
{
MovementComponent->SetMovementMode(EMovementMode::MOVE_Walking);
}
if (UEnhancedInputLocalPlayerSubsystem *Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
{
// PawnClientRestart can run more than once in an Actor's lifetime, so start by clearing out any leftover mappings.
if (bFlying)
{
Subsystem->RemoveMappingContext(MovementContext);
Subsystem->AddMappingContext(FlyingContext, 1);
}
else
{
Subsystem->RemoveMappingContext(FlyingContext);
Subsystem->AddMappingContext(MovementContext, 1);
}
}
if (PlayerCharacter)
{
PlayerCharacter->ToggleBroomActor(bFlying);
PlayerCharacter->SetNewCameraPitches(bFlying ? -30 : PlayerCharacter->CameraPitchMin, bFlying ? 30 : PlayerCharacter->CameraPitchMax);
PlayerCharacter->OnToggleFlying(bFlying);
}
OnPlayerToggleFlying.Broadcast(bFlying);
}
void AEleriPlayerController::OnFlyUpwardsAction(const FInputActionValue &Value)
{
ACharacter *Char = GetCharacter();
if (bFlying)
{
float AnalogueValue = Value.Get<FInputActionValue::Axis1D>();
Char->AddMovementInput(Char->GetActorUpVector(), AnalogueValue);
}
}
void AEleriPlayerController::OnFlyDownwardsAction(const FInputActionValue &Value)
{
ACharacter *Char = GetCharacter();
if (bFlying)
{
float AnalogueValue = Value.Get<FInputActionValue::Axis1D>();
Char->AddMovementInput(Char->GetActorUpVector(), -AnalogueValue);
}
}
void AEleriPlayerController::OnStartObjectRemovalAction(const FInputActionValue &Value)
{
if (MoveActorsComp->MovingActor)
{
ExitRemoveMode();
return;
}
if (IsInMenu() || Paused)
return;
MoveActorsComp->StartObjectRemoval(!MoveActorsComp->IsRemovingMode());
PlacingStuff = !MoveActorsComp->IsRemovingMode();
// Get the Enhanced Input Local Player Subsystem from the Local Player related to our Player Controller.
if (UEnhancedInputLocalPlayerSubsystem *Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
{
Subsystem->AddMappingContext(RemoveModeContext, 8);
}
OnRemovalModeToggle.Broadcast(true);
}
void AEleriPlayerController::OnRemoveAction(const FInputActionValue &Value)
{
if (MoveActorsComp->MovingActor)
{
MoveActorsComp->PlaceableActionUsed(ERemovalAction::REMOVE);
MoveActorsComp->MovingActor = nullptr;
}
}
void AEleriPlayerController::ExitRemoveMode()
{
if (MoveActorsComp->MovingActor)
{
MoveActorsComp->PlaceableActionUsed(ERemovalAction::EXIT);
MoveActorsComp->StartObjectRemoval(false);
if (IsValid(MoveActorsComp->MovingActor))
{
MoveActorsComp->MovingActor->Place(true);
}
MoveActorsComp->RemoveObjectForPlacing();
}
else
{
MoveActorsComp->StartObjectRemoval(false);
}
PlayerCharacter->bAlreadyInteracting = false;
PlayerCharacter->CurrentlyDoing = ECurrentlyDoing::NOTHING;
PlacingStuff = false;
OnRemovalModeToggle.Broadcast(false);
}
void AEleriPlayerController::OnExitRemoveModeAction(const FInputActionValue &Value)
{
ExitRemoveMode();
}
void AEleriPlayerController::OnStartMovingAction(const FInputActionValue &Value)
{
if (MoveActorsComp->MovingActor)
{
MoveActorsComp->PlaceableActionUsed(ERemovalAction::START_MOVE);
MoveActorsComp->StartObjectRemoval(false);
}
}
void AEleriPlayerController::OnPlaceObjectAction(const FInputActionValue &Value)
{
if (MoveActorsComp->MovingActor && !MoveActorsComp->MovingActor->CanPlace())
return;
if (MoveActorsComp->MovingActor)
{
UItemDatabase* ItemDatabase = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<UItemDatabase>();
UInventoryComponent *Inventory = UMainBlueprintFunctionLibrary::GetPlayerInventory(this);
UItemDataAsset* DataAsset = MoveActorsComp->MovingActor->ItemDataAsset;
if (!MoveActorsComp->PlaceableActionUsed(ERemovalAction::PLACE))
return;
int32 StackCount = Inventory->GetStackForItem(DataAsset->GetPrimaryAssetId(), false);
if (StackCount > 0)
{
ensure(ItemDatabase);
ItemDatabase->SpawnDecorationItem(DataAsset);
}
}
else
{
OnInteract(Value);
}
}
void AEleriPlayerController::OnRotateObjectAction(const FInputActionValue &Value)
{
float RotateForward = Value.Get<FInputActionValue::Axis1D>();
if (MoveActorsComp->MovingActor)
MoveActorsComp->MovingActor->Rotate(RotateForward > 0);
}
void AEleriPlayerController::OnToggleGridAction(const FInputActionValue &Value)
{
if (MoveActorsComp)
{
MoveActorsComp->ToggleGridMovement();
}
}
void AEleriPlayerController::AddInteractableObject(UObject *ObjectToAdd)
{
if (IsValid(ObjectToAdd) && ObjectToAdd->Implements<UInteractableActorInterface>() && IInteractableActorInterface::Execute_IsInteractable(ObjectToAdd))
{
FText InteractableText = IInteractableActorInterface::Execute_GetInteractionText(ObjectToAdd);
if (UMainGameWidget *MainWidget = UMainBlueprintFunctionLibrary::GetMainGameWidget(this))
{
if (UInteractionWidget *InteractionWidget = MainWidget->GetInteractionWidget())
{
InteractionWidget->PushInteractableObject(ObjectToAdd, InteractableText);
}
}
ActorsOverlappingWith.Add(ObjectToAdd);
}
if (!ActorsOverlappingWith.IsEmpty())
{
ToggleInteractionMenu(true);
}
if (ActorsOverlappingWith.Num() == 1)
{
SelectedInteractable = ActorsOverlappingWith[0];
}
}
void AEleriPlayerController::RemoveInteractableObject(UObject *ObjectToAdd)
{
if (IsPaused())
return;
if (IsValid(ObjectToAdd) && ObjectToAdd->Implements<UInteractableActorInterface>())
{
FText InteractableText = IInteractableActorInterface::Execute_GetInteractionText(ObjectToAdd);
if (UMainGameWidget *MainWidget = UMainBlueprintFunctionLibrary::GetMainGameWidget(this))
{
if (UInteractionWidget *InteractionWidget = MainWidget->GetInteractionWidget())
{
InteractionWidget->PopInteractableObject(ObjectToAdd);
}
}
}
ActorsOverlappingWith.Remove(ObjectToAdd);
if (SelectedInteractable == ObjectToAdd)
{
SelectedInteractable = nullptr;
if (!ActorsOverlappingWith.IsEmpty())
{
SelectedInteractable = ActorsOverlappingWith[ActorsOverlappingWith.Num() - 1];
}
}
if (ActorsOverlappingWith.IsEmpty())
{
ToggleInteractionMenu(true);
}
}
void AEleriPlayerController::ToggleInteractionMenu(bool bActive)
{
bIsInteractionMenuVisible = bActive;
if (UMainGameWidget *MainWidget = UMainBlueprintFunctionLibrary::GetMainGameWidget(this))
{
if (UInteractionWidget *InteractionWidget = MainWidget->GetInteractionWidget())
{
InteractionWidget->OnDisplayInteractionMenu.Broadcast(bActive);
}
if (UEnhancedInputLocalPlayerSubsystem *Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
{
// if (bActive)
// Subsystem->AddMappingContext(InteractionMenuContext, 15);
// else
// Subsystem->RemoveMappingContext(InteractionMenuContext);
}
}
}
void AEleriPlayerController::OnInteractionMenuSelectAction(const FInputActionValue &Value)
{
}
void AEleriPlayerController::OnInteractionMenuUpAction(const FInputActionValue &Value)
{
if (UMainGameWidget *MainWidget = UMainBlueprintFunctionLibrary::GetMainGameWidget(this))
{
if (UInteractionWidget *InteractionWidget = MainWidget->GetInteractionWidget())
{
SelectedInteractable = InteractionWidget->SelectInteractableObject(false);
}
}
}
void AEleriPlayerController::OnInteractionMenuDownAction(const FInputActionValue &Value)
{
if (UMainGameWidget *MainWidget = UMainBlueprintFunctionLibrary::GetMainGameWidget(this))
{
if (UInteractionWidget *InteractionWidget = MainWidget->GetInteractionWidget())
{
SelectedInteractable = InteractionWidget->SelectInteractableObject(true);
}
}
}
void AEleriPlayerController::OnControllerUpAction(const FInputActionValue &Value)
{
if (IsInMenu())
{
OnUiButtonPressed.Broadcast(UiInputType::UP);
}
}
void AEleriPlayerController::OnControllerDownAction(const FInputActionValue &Value)
{
if (IsInMenu())
{
OnUiButtonPressed.Broadcast(UiInputType::DOWN);
}
}
void AEleriPlayerController::OnControllerLeftAction(const FInputActionValue &Value)
{
if (IsInMenu())
{
OnUiButtonPressed.Broadcast(UiInputType::LEFT);
}
}
void AEleriPlayerController::OnControllerRightAction(const FInputActionValue &Value)
{
if (IsInMenu())
{
OnUiButtonPressed.Broadcast(UiInputType::RIGHT);
}
}
void AEleriPlayerController::OnControllerConfirmAction(const FInputActionValue &Value)
{
if (MainGameUI->GetWidgetStack().IsEmpty())
{
return;
}
MainGameUI->GetWidgetStack()[MainGameUI->GetWidgetStack().Num() - 1]->HandleUiInputAction(EEleriUIInputAction::Select);
}
void AEleriPlayerController::OnControllerBackAction(const FInputActionValue &Value)
{
OnUiButtonPressed.Broadcast(UiInputType::BACK);
if (MainGameUI->GetWidgetStack().IsEmpty())
{
return;
}
MainGameUI->GetWidgetStack()[MainGameUI->GetWidgetStack().Num() - 1]->HandleUiInputAction(EEleriUIInputAction::Back);
}
void AEleriPlayerController::OnControllerTabLeftAction(const FInputActionValue &Value)
{
if (MainGameUI->GetWidgetStack().IsEmpty())
{
return;
}
MainGameUI->GetWidgetStack()[MainGameUI->GetWidgetStack().Num() - 1]->HandleUiInputAction(EEleriUIInputAction::TabLeft);
}
void AEleriPlayerController::OnControllerTabRightAction(const FInputActionValue &Value)
{
if (MainGameUI->GetWidgetStack().IsEmpty())
{
return;
}
MainGameUI->GetWidgetStack()[MainGameUI->GetWidgetStack().Num() - 1]->HandleUiInputAction(EEleriUIInputAction::TabRight);
}
// UI BIND
void AEleriPlayerController::OnMainMenuToggle(const FInputActionValue &Value)
{
if (!IsValid(MainGameUI))
return;
if (MainGameUI->IsMainMenuOpen())
{
CloseMainMenu();
}
else
{
OpenMainMenu();
}
}
void AEleriPlayerController::OnInventoryToggle(const FInputActionValue &Value)
{
if (Paused || (IsInMenu() && !MainGameUI->IsInventoryOpen()) || !MoveActorsComp || MoveActorsComp->IsRemovingMode())
return;
OpenInventory(false, false, nullptr, TArray<EInventoryTabType>());
}
void AEleriPlayerController::OnBookToggle(const FInputActionValue &Value)
{
if (Paused || IsDialogueOpen() || (IsInMenu() && !MainGameUI->IsBookOpen()) || !MoveActorsComp || MoveActorsComp->IsRemovingMode())
return;
OpenBookOfAlchemy(nullptr);
}
void AEleriPlayerController::OnOrdersToggle(const FInputActionValue &Value)
{
if (Paused || IsDialogueOpen() || IsInMenu() || !MoveActorsComp || MoveActorsComp->IsRemovingMode())
return;
if (OrdersOpen)
{
CloseOrdersUI();
}
else
{
}
}
void AEleriPlayerController::OnCalendarToggle(const FInputActionValue &Value)
{
if (Paused || IsDialogueOpen() || (IsInMenu() && !MainGameUI->IsCalendarOpen()) || !MoveActorsComp || MoveActorsComp->IsRemovingMode())
return;
OpenCalendarWindow();
}
void AEleriPlayerController::OnBookNextPage(const FInputActionValue &Value)
{
if (!IsValid(BookOfAlchemyManager))
return;
BookOfAlchemyManager->FlipPage(true);
}
void AEleriPlayerController::OnBookPreviousPage(const FInputActionValue &Value)
{
if (!IsValid(BookOfAlchemyManager))
return;
BookOfAlchemyManager->FlipPage(false);
}
void AEleriPlayerController::OnBookItemTab(const FInputActionValue &Value)
{
if (!IsValid(BookOfAlchemyManager))
return;
BookOfAlchemyManager->SwitchTab(0);
}
void AEleriPlayerController::OnBookPotionTab(const FInputActionValue &Value)
{
if (!IsValid(BookOfAlchemyManager))
return;
BookOfAlchemyManager->SwitchTab(1);
}
void AEleriPlayerController::OnBookNextLetter(const FInputActionValue &Value)
{
if (!IsValid(BookOfAlchemyManager))
return;
BookOfAlchemyManager->SelectLetter(BookOfAlchemyManager->GetNextPreviousLetter(BookOfAlchemyManager->CurrentlySelectedLetter, true));
}
void AEleriPlayerController::OnBookPreviousLetter(const FInputActionValue &Value)
{
if (!IsValid(BookOfAlchemyManager))
return;
BookOfAlchemyManager->SelectLetter(BookOfAlchemyManager->GetNextPreviousLetter(BookOfAlchemyManager->CurrentlySelectedLetter, false));
}
void AEleriPlayerController::OnBookExit(const FInputActionValue &Value)
{
// CloseBookOfAlchemy();
}
void AEleriPlayerController::OnAlchemyStirringDirectionInput(const FInputActionValue &Value)
{
if (!PlayerCharacter)
return;
AlchemyManager->SetStirringDirection(Value.Get<FInputActionValue::Axis2D>());
}
void AEleriPlayerController::OnAlchemyConfirmInput(const FInputActionValue &Value)
{
if (!PlayerCharacter)
return;
AlchemyManager->MinigameConfirmInput();
}
UUserWidget *AEleriPlayerController::OpenInventory(bool JustSelecting, bool Shop, UInventoryComponent *Inventory, TArray<EInventoryTabType> RestrictTabs, bool bSelectMultiple, bool bShowDescription, bool bShowPropertyMap)
{
UInventoryComponent *PlayerInventory = Cast<UInventoryComponent>(PlayerCharacter->GetComponentByClass(UInventoryComponent::StaticClass()));
if (!IsValid(PlayerInventory))
return nullptr;
// If we pass nothing into this function we're opening the player inventory
// If we pass something we're opening a shop/trade and the other inventory is the npc inventory
UInventoryComponent *MainInv = PlayerInventory;
UInventoryComponent *OtherInv = IsValid(Inventory) ? Inventory : nullptr;
MainGameUI->OpenWidget(MainGameUI->GetInventoryWidget());
//MainGameUI->GetInventoryWidget()->ToggleWidget(true);
MainGameUI->GetInventoryWidget()->Setup(MainInv, OtherInv, Shop, JustSelecting, RestrictTabs, bSelectMultiple, bShowDescription, bShowPropertyMap);
return MainGameUI->GetInventoryWidget();
}
void AEleriPlayerController::CloseInventory()
{
MainGameUI->CloseWidget(MainGameUI->GetInventoryWidget());
}
UUserWidget *AEleriPlayerController::OpenBookOfAlchemy(UItemDataAsset *ItemToPresent)
{
if (!IsValid(PlayerCharacter->GetBook()) || bBookAnimating)
return nullptr;
bBookAnimating = true;
MainGameUI->GetBookWidget()->Setup(ItemToPresent, false);
PlayerCharacter->ToggleBook(true);
MainGameUI->OpenWidget(MainGameUI->GetBookWidget());
MainGameUI->ToggleGameMenu(false);
// Get the Enhanced Input Local Player Subsystem from the Local Player related to our Player Controller.
if (UEnhancedInputLocalPlayerSubsystem *Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
{
// If for whatever reason...
Subsystem->RemoveMappingContext(BookModeContext);
// Add each mapping context, along with their priority values. Higher values outprioritize lower values.
Subsystem->AddMappingContext(BookModeContext, 98);
}
TickBookAnimating = true;
return MainGameUI->GetBookWidget();
}
void AEleriPlayerController::CloseBookOfAlchemy()
{
if (bBookAnimating)
return;
bBookAnimating = true;
// for the animation of closing
FTimerHandle TimerHandle;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateLambda([this]()
{
MainGameUI->ToggleGameMenu(true);
}), 0.5f, false);
// Get the Enhanced Input Local Player Subsystem from the Local Player related to our Player Controller.
if (UEnhancedInputLocalPlayerSubsystem *Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
{
Subsystem->RemoveMappingContext(BookModeContext);
}
TickBookAnimating = true;
}
void AEleriPlayerController::DisableBookAnimating()
{
bBookAnimating = false;
TickBookAnimating = false;
TickBookTimer = 0.6f;
}
void AEleriPlayerController::CloseOrdersUI()
{
OrdersOpen = false;
OrdersUI->RemoveFromParent();
if (MenuStack.Num() == 0)
{
SetShowMouseCursor(false);
SetInputMode(FInputModeGameOnly());
}
}
UMainMenuWidget *AEleriPlayerController::OpenMainMenu()
{
if (!IsValid(MainGameUI))
return nullptr;
MainGameUI->OpenWidget(MainGameUI->GetMainMenuWidget());
return MainGameUI->GetMainMenuWidget();
}
void AEleriPlayerController::CloseMainMenu()
{
MainGameUI->CloseWidget(MainGameUI->GetMainMenuWidget());
}
UEleriBaseWidget *AEleriPlayerController::ToggleAlchemyMenu(bool bOpen)
{
if (MainGameUI->AnyWidgetOpen())
return nullptr;
MainGameUI->OpenWidget(MainGameUI->GetAlchemyWidget());
return MainGameUI->GetAlchemyWidget();
}
UEleriBaseWidget *AEleriPlayerController::ToggleDialogueWindow(bool bOpen)
{
if (!IsValid(MainGameUI->GetDialogueWidget()))
return nullptr;
bOpen? MainGameUI->OpenWidget(MainGameUI->GetDialogueWidget()) : MainGameUI->CloseWidget(MainGameUI->GetDialogueWidget());
return MainGameUI->GetDialogueWidget();
}
UEleriBaseWidget *AEleriPlayerController::ToggleNotificationWindow(bool bOpen)
{
if (!IsValid(MainGameUI->GetBigNotificationWidget()))
return nullptr;
if (MainGameUI->IsBigNotificationOpen())
{
MainGameUI->CloseWidget(MainGameUI->GetBigNotificationWidget());
}
else
{
MainGameUI->OpenWidget(MainGameUI->GetBigNotificationWidget());
}
return MainGameUI->GetBigNotificationWidget();
}
UTradeWidget *AEleriPlayerController::OpenTradeWindow(UInventoryComponent *Inventory, const TArray<EInventoryTabType>& InRestrictTabs)
{
if (!IsValid(PlayerCharacter))
return nullptr;
if (UMainGameWidget *MainWidget = GetMainGameWidget())
{
MainWidget->OpenTradeWidget(Inventory, InRestrictTabs);
return MainGameUI->GetTradeWidget();
}
return nullptr;
}
UCalendarScreen* AEleriPlayerController::OpenCalendarWindow()
{
MainGameUI->OpenWidget(MainGameUI->GetCalendarWidget());
return MainGameUI->GetCalendarWidget();
}
UEleriBaseWidget* AEleriPlayerController::OpenBazarWindow() {
MainGameUI->OpenWidget(MainGameUI->GetBazarWidget());
return MainGameUI->GetBazarWidget();
}
void AEleriPlayerController::ToggleBazarInput(bool bActive)
{
}
void AEleriPlayerController::OnInteract(const FInputActionValue &Value)
{
if (!IsValid(PlayerCharacter))
return;
if (PlayerCharacter->GetIsPlanting())
{
TryPlantSelectedSeed();
return;
}
// Ask the InteractionSystem plugin's subsystem for the closest valid interactable
// and fire the interaction on it if we have one.
if (AActor *ClosestInteractable = UInteractionSubsystem::GetClosestInteractable(this))
{
IInteractableActorInterface::Execute_Interact(ClosestInteractable, PlayerCharacter);
}
PlayerCharacter->OnInteract.Broadcast();
}
void AEleriPlayerController::OnInteractExit(const FInputActionValue &Value)
{
if (!IsValid(PlayerCharacter))
return;
if (PlayerCharacter->GetIsPlanting())
{
ClearSeedToPlant();
return;
}
PlayerCharacter->OnInteractExit.Broadcast();
OnChangeInputContext.Broadcast(1);
}
void AEleriPlayerController::OnHarvestSeed(const FInputActionValue &Value)
{
}
// PLANTING
void AEleriPlayerController::SetSeedToPlant(UItemDataAsset *SeedData, bool bHighQuality)
{
// Anything that is not a seed that fits into a seed bed is rejected, the UI cannot leave us in a bad state
SeedToPlant = ASeedBedActor::IsPlantableSeedData(SeedData) ? SeedData : nullptr;
bSeedToPlantHighQuality = IsValid(SeedToPlant) && bHighQuality;
// Selecting a seed is what starts the planting, the beds in range light up for it right away
if (IsValid(SeedToPlant))
{
SetPlantingMode(true);
}
}
void AEleriPlayerController::ClearSeedToPlant()
{
if (!IsValid(SeedToPlant) && !bSeedToPlantHighQuality)
return;
SeedToPlant = nullptr;
bSeedToPlantHighQuality = false;
// Nothing is being planted anymore, so the beds stop being highlighted
if (IsPlantingModeActive())
{
SetPlantingMode(false);
}
}
bool AEleriPlayerController::IsPlantingModeActive() const
{
return IsValid(PlayerCharacter) && PlayerCharacter->GetIsPlanting();
}
void AEleriPlayerController::SetPlantingMode(bool bActive)
{
if (!IsValid(PlayerCharacter))
return;
PlayerCharacter->SetPlanting(bActive);
}
void AEleriPlayerController::TryPlantSelectedSeed()
{
if (!IsValid(PlayerCharacter))
return;
// A seed that is not plantable anymore, for example when the inventory was emptied, drops out of planting
if (!ASeedBedActor::IsPlantableSeedData(SeedToPlant))
{
ClearSeedToPlant();
return;
}
ASeedBedActor *SeedBed = PlayerCharacter->GetClosestSeedBedActor();
if (!IsValid(SeedBed))
return;
const FVector PlayerLocation = PlayerCharacter->GetActorLocation();
FIntVector2 SlotCoordinate = SeedBed->GetHighlightedSlotIndex();
if (SlotCoordinate == FIntVector2::NoneValue)
return;
UInventoryComponent *Inventory = UMainBlueprintFunctionLibrary::GetPlayerInventory(this);
if (!IsValid(Inventory))
return;
// The seed is paid for before it is planted, so a slot can never hold a seed the inventory never had
const FPrimaryAssetId SeedAssetId = SeedToPlant->GetPrimaryAssetId();
if (Inventory->HasItem(SeedAssetId, true) <= 0)
return;
if (!SeedBed->PlantSeedInSlot(SlotCoordinate, SeedToPlant, bSeedToPlantHighQuality))
return;
Inventory->RemoveItemFromInventory(SeedAssetId, 1, true);
if (Inventory->HasItem(SeedAssetId, true) == INDEX_NONE)
{
ClearSeedToPlant();
}
}
void AEleriPlayerController::StartMinigame(EMinigameType MinigameType, const TSoftObjectPtr<UBaseMinigameDataAsset> &DataAsset)
{
if (!IsValid(PlayerCharacter) ||
!IsValid(MainGameUI) ||
MainGameUI->IsAnyMinigameOpen() ||
MinigameType == EMinigameType::NONE)
return;
MainGameUI->ToggleMinigamesWidget(MinigameType, DataAsset);
}
void AEleriPlayerController::CloseMinigame(int32 Score)
{
if (!IsValid(PlayerCharacter) || !IsValid(MainGameUI) || !MainGameUI->IsAnyMinigameOpen())
return;
MainGameUI->ToggleMinigamesWidget(EMinigameType::NONE, nullptr);
if (OnMinigameComplete.IsBound())
{
OnMinigameComplete.Execute(Score);
}
}