// © 2025 Naked People Team. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "GameFramework/Character.h" #include "InputAction.h" #include "InputMappingContext.h" #include "NakedDesire/Clothing/BodyPart.h" #include "NakedDesire/Global/Gait.h" #include "NakedDesire/Global/Stance.h" #include "Perception/AISightTargetInterface.h" #include "NakedDesireCharacter.generated.h" class UInteractionComponent; class ANakedDesireHUD; class UClothingItemDefinition; class UClothingItemInstance; class UClothingSlotsData; class UAIPerceptionStimuliSourceComponent; class UClothingManager; class UClothingVisualsComponent; class UCensorshipComponent; class UStatsManager; class ANPCAIController; class ULocationData; DECLARE_MULTICAST_DELEGATE_OneParam(FOnNoticedSignature, ANPCAIController*); UCLASS(config=Game) class ANakedDesireCharacter : public ACharacter, public IAISightTargetInterface { GENERATED_BODY() public: ANakedDesireCharacter(); // Input UPROPERTY(EditDefaultsOnly, Category = "Input") UInputMappingContext* MappingContext; UPROPERTY(EditDefaultsOnly, Category = "Input") UInputAction* LookAction; UPROPERTY(EditDefaultsOnly, Category = "Input") UInputAction* MoveAction; UPROPERTY(EditDefaultsOnly, Category = "Input") UInputAction* RunAction; UPROPERTY(EditDefaultsOnly, Category = "Input") UInputAction* CrouchAction; UPROPERTY(EditDefaultsOnly, Category = "Input") UInputAction* EquipmentAction; UPROPERTY(EditDefaultsOnly, Category = "Input") UInputAction* InteractAction; // Clothing slot meshes are spawned per equipped slot at runtime by ClothingVisualsComponent. UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing") UClothingVisualsComponent* ClothingVisualsComponent; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship") UStaticMeshComponent* BoobLCensorship; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship") UStaticMeshComponent* BoobRCensorship; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship") UStaticMeshComponent* VaginaCensorship; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship") UStaticMeshComponent* AnalCensorship; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship") UCensorshipComponent* CensorshipComponent; UPROPERTY(EditDefaultsOnly, Category = "Clothing") TObjectPtr SlotsData; // Components UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing") UClothingManager* ClothingManager; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) UStatsManager* StatsManager; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) UAIPerceptionStimuliSourceComponent* StimuliSourceComponent; UPROPERTY(EditDefaultsOnly, Category = "Interaction") TObjectPtr InteractionComponent; // Variables UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) float WalkSpeed = 250.0f; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) float RunSpeed = 500.0f; float XP = 0.0f; UPROPERTY() ULocationData* CurrentArea = nullptr; FOnNoticedSignature OnNoticed; void NotifyNoticed(ANPCAIController* NPCController); void SetIsRunning(bool Value); UFUNCTION(BlueprintPure) EGait GetGait() const; virtual void Tick(float DeltaTime) override; virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override; virtual void NotifyControllerChanged() override; virtual void BeginPlay() override; virtual UAISense_Sight::EVisibilityResult CanBeSeenFrom(const FCanBeSeenFromContext& Context, FVector& OutSeenLocation, int32& OutNumberOfLoSChecksPerformed, int32& OutNumberOfAsyncLosCheckRequested, float& OutSightStrength, int32* UserData = nullptr, const FOnPendingVisibilityQueryProcessedDelegate* Delegate = nullptr) override; // Player exposure as read by an observer at ObserverLocation, in [0, 3]: the sum over the // LOS-visible body regions (top -> Boobs, bottom -> Ass + Genitals) of (1 - effective coverage) // for parts below ObservationRevealThreshold. 0 means nothing revealing is visible to them. // Queried per observing NPC each tick by UStatsManager to drive embarrassment (GDD §7.1). float GetObservedExposureFrom(const FVector& ObserverLocation, const AActor* IgnoreActor); // Below this effective coverage [0,1] a body part reads as "revealing": observers notice it and // it contributes to embarrassment. At or above it the part is treated as decently covered. UPROPERTY(EditDefaultsOnly, Category = "Observation") float ObservationRevealThreshold = 0.9f; private: EGait Gait = EGait::Walk; EStance Stance = EStance::Stand; void OnLook(const FInputActionValue& Value); void OnMove(const FInputActionValue& Value); void OnRunPress(const FInputActionValue& Value); void OnRunRelease(const FInputActionValue& Value); void OnCrouchToggle(const FInputActionValue& Value); void OnEquipmentPress(const FInputActionValue& Value); void OnInteractPress(const FInputActionValue& Value); bool CheckSight(const FVector& StartLocation, const FVector& EndLocation, FHitResult& HitResult, const AActor* IgnoreActor); // Traces observer->boobs_root and observer->pelvis for line of sight (top / bottom regions), // then sums (1 - coverage) over the revealing parts in each LOS-visible region. The out-bools // report raw line of sight per region (before coverage), used to pick a seen location. float ComputeObservedExposure(const FVector& ObserverLocation, const AActor* IgnoreActor, bool& bOutTopVisible, bool& bOutBottomVisible); // (1 - effective coverage) when BodyPart is below ObservationRevealThreshold, else 0. float RevealAmount(EBodyPart BodyPart); UFUNCTION(Exec) void LogTest(); UPROPERTY() TObjectPtr HUD; };