// Copyright Team Lumi. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "GameFramework/Character.h" #include "Logging/LogMacros.h" #include "LumiStance.h" #include "WizardingCentral/UserWidgets/SpellOverlay.h" #include "WizardingCentral/Utils/OneDollar/UniStrokeRecognizer.h" #include "LumiCharacter.generated.h" class USpringArmComponent; class UCameraComponent; struct FInputActionValue; DECLARE_DYNAMIC_MULTICAST_DELEGATE(FJumpDelegate); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FStanceChangedDelegate, ELumiStance, OldStance, ELumiStance, NewStance); static const FString PlayerStanceEnumPath = TEXT("/Game/Player/E_PlayerStance"); enum ELumiSpellState { Idle, Casting, Recognizing, Training }; UCLASS() class WIZARDINGCENTRAL_API ALumiCharacter : public ACharacter { GENERATED_BODY() /** Camera boom positioning the camera behind the character */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera", meta = (AllowPrivateAccess = "true")) TObjectPtr CameraBoom; /** Follow camera */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera", meta = (AllowPrivateAccess = "true")) TObjectPtr FollowCamera; UPROPERTY(BlueprintReadWrite, Category = "Spell", meta = (AllowPrivateAccess = "true")) TObjectPtr SpellOverlay; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spell", meta = (AllowPrivateAccess = "true")) TSubclassOf SpellOverlayClass; /** The default boom offset */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera", meta = (AllowPrivateAccess = "true")) FVector DefaultBoomOffset = FVector(0.0f, 60.0f, 30.0f); /** The boom offset when aiming */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera", meta = (AllowPrivateAccess = "true")) FVector AimBoomOffset = FVector(200.0f, 65.0f, 45.0f); /** The current stance of the character */ UPROPERTY(BlueprintReadWrite, meta = (AllowPrivateAccess = "true")) ELumiStance CurrentStance = ELumiStance::Default; /** The stamina of the character */ UPROPERTY(BlueprintReadWrite, Category = "Stamina", meta = (AllowPrivateAccess = "true")) double Stamina = 10.0; UPROPERTY(BlueprintReadWrite, Category = "Stamina", meta = (AllowPrivateAccess = "true")) double MaxStamina = 10.0; bool bIsDrawing; // TODO: Remove this, use the spell state instead bool bIsTraining = false; // TODO: Implement training public: /* Spell System */ ELumiSpellState SpellSystemState; FUniStrokeRecognizer* SpellRecognizer; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spell", meta = (AllowPrivateAccess = "true")) TObjectPtr SpellTemplatesTable = nullptr; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spell", meta = (AllowPrivateAccess = "true")) TSubclassOf SpellTrainWidgetClass; UPROPERTY(BlueprintReadWrite, Category = "Spell", meta = (AllowPrivateAccess = "true")) TObjectPtr SpellTrainWidget = nullptr; /** * Sets default values for this character's properties */ ALumiCharacter(); /** * Getter for @property CurrentStance * * @return The current stance of the character */ ELumiStance GetCurrentStance() const; // Grab /** * Callback for when the grab action is triggered * @param Value The value of the input action */ void OnGrabActionTriggered(const FInputActionValue& Value); // Jump /** * Callback for when the jump action is started * @param Value The value of the input action */ void OnJumpActionStarted(const FInputActionValue& Value); /** * Callback for when the jump action is ongoing * @param Value The value of the input action */ void OnJumpActionOngoing(const FInputActionValue& Value); /** * Callback for when the jump action is completed * @param Value The value of the input action */ void OnJumpActionCompleted(const FInputActionValue& Value); // Move /** * Callback for when the move action is triggered * @param Value The value of the input action */ void OnMoveActionTriggered(const FInputActionValue& Value); // Look /** * Callback for when the look action is triggered * @param Value The value of the input action */ void OnLookActionTriggered(const FInputActionValue& Value); void OnSpellActionStarted(); void OnSpellActionCompleted(); void OnSpellPositionActionTriggered(const FInputActionValue& Value); void OnSpellTrainSwitchActionCompleted(); UFUNCTION(BlueprintCallable, Category = "Spell") void SetIsTraining(const bool bTraining); UFUNCTION(BlueprintCallable, Category = "Spell") void HideTrainWidget(); UFUNCTION(BlueprintCallable, Category = "Spell") void ShowTrainWidget(); UFUNCTION(BlueprintCallable, Category = "Spell") void AddSpellTemplateToTable(const FString& Name); protected: /** * Set the stance of the character * * @param NewStance The new stance to set * @return The stance before the new stance was set */ UFUNCTION(BlueprintCallable, Category = "Stance") ELumiStance SetCurrentStance(ELumiStance NewStance); /** * Event called when the character switches to the default stance */ UFUNCTION(BlueprintNativeEvent, Category = "Stance") void OnDefaultStance(); /** * Event called when the character switches to the magic stance */ UFUNCTION(BlueprintNativeEvent, Category = "Stance") void OnMagicStance(); /** * Check if the character has jumped the maximum number of times * * @return True if the character cannot jump anymore, false otherwise */ UFUNCTION(BlueprintPure, Category = "LumiCharacter") bool IsLastJump() const; /** * Called when the game starts or when spawned */ virtual void BeginPlay() override; private: bool GetPlayerController(APlayerController*& LumiController) const; void LoadSpellTemplates() const; void CastSpell(); // Delegates ------------------------------------------------------------------------------------------------------- UPROPERTY(BlueprintAssignable, Category = "Input") FJumpDelegate OnJumpStarted; UPROPERTY(BlueprintAssignable, Category = "Stance") FStanceChangedDelegate OnStanceChanged; };