259 lines
9.3 KiB
C++
259 lines
9.3 KiB
C++
// © 2025 Naked People Team. All Rights Reserved.
|
|
|
|
#include "NakedDesireCharacter.h"
|
|
#include "NakedDesire/Clothing/ClothingManager.h"
|
|
#include "GameFramework/CharacterMovementComponent.h"
|
|
#include "NakedDesire/MissionBuilder/MissionsManager.h"
|
|
#include "NakedDesire/Stats/StatsManager.h"
|
|
#include "EnhancedInputComponent.h"
|
|
#include "EnhancedInputSubsystems.h"
|
|
#include "Kismet/GameplayStatics.h"
|
|
#include "Internationalization/Text.h"
|
|
#include "NakedDesire/Censorship/CensorshipComponent.h"
|
|
#include "NakedDesire/Clothing/ClothingItemDefinition.h"
|
|
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
|
#include "NakedDesire/Clothing/ClothingVisualsComponent.h"
|
|
#include "NakedDesire/Global/Constants.h"
|
|
#include "NakedDesire/Global/NakedDesireHUD.h"
|
|
#include "NakedDesire/Global/NakedDesireUserSettings.h"
|
|
#include "NakedDesire/Interaction/InteractionComponent.h"
|
|
#include "NakedDesire/UI/GameLayoutWidget.h"
|
|
#include "Perception/AIPerceptionStimuliSourceComponent.h"
|
|
#include "Perception/AISense_Sight.h"
|
|
|
|
ANakedDesireCharacter::ANakedDesireCharacter()
|
|
{
|
|
GetCharacterMovement()->MaxWalkSpeed = WalkSpeed;
|
|
|
|
bUseControllerRotationYaw = false;
|
|
|
|
GetCharacterMovement()->bOrientRotationToMovement = true;
|
|
GetCharacterMovement()->GetNavAgentPropertiesRef().bCanCrouch = true;
|
|
|
|
ClothingManager = CreateDefaultSubobject<UClothingManager>("Clothing Manager");
|
|
StatsManager = CreateDefaultSubobject<UStatsManager>("Stats Manager");
|
|
MissionsManager = CreateDefaultSubobject<UMissionsManager>("Missions Manager");
|
|
|
|
ClothingVisualsComponent = CreateDefaultSubobject<UClothingVisualsComponent>(TEXT("Clothing Visuals Component"));
|
|
|
|
BoobLCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Boob L Censorship"));
|
|
BoobLCensorship->SetupAttachment(GetMesh(), FName(TEXT("boob_l")));
|
|
BoobRCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Boob R Censorship"));
|
|
BoobRCensorship->SetupAttachment(GetMesh(), FName(TEXT("boob_r")));
|
|
VaginaCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Vagina Censorship"));
|
|
VaginaCensorship->SetupAttachment(GetMesh(), FName(TEXT("pelvis")));
|
|
AnalCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Anal Censorship"));
|
|
AnalCensorship->SetupAttachment(GetMesh(), FName(TEXT("pelvis")));
|
|
|
|
CensorshipComponent = CreateDefaultSubobject<UCensorshipComponent>(TEXT("Censorship Component"));
|
|
|
|
StimuliSourceComponent = CreateDefaultSubobject<UAIPerceptionStimuliSourceComponent>(TEXT("Stimuli Source Component"));
|
|
InteractionComponent = CreateDefaultSubobject<UInteractionComponent>(TEXT("Interaction Component"));
|
|
}
|
|
|
|
EGait ANakedDesireCharacter::GetGait() const
|
|
{
|
|
return Gait;
|
|
}
|
|
|
|
void ANakedDesireCharacter::Tick(float DeltaTime)
|
|
{
|
|
Super::Tick(DeltaTime);
|
|
|
|
if (StatsManager->Stamina == 0 && Gait == EGait::Run)
|
|
{
|
|
SetIsRunning(false);
|
|
}
|
|
|
|
if (Gait == EGait::Run && GetCharacterMovement()->Velocity.SizeSquared2D() > 100 && StatsManager->Stamina > 0)
|
|
{
|
|
GetCharacterMovement()->MaxWalkSpeed = RunSpeed;
|
|
StatsManager->DecreaseStamina(7 * DeltaTime);
|
|
}
|
|
else
|
|
{
|
|
GetCharacterMovement()->MaxWalkSpeed = WalkSpeed;
|
|
if (StatsManager->Stamina < StatsManager->MaxStamina)
|
|
{
|
|
StatsManager->IncreaseStamina(15 * DeltaTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ANakedDesireCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
|
{
|
|
Super::SetupPlayerInputComponent(PlayerInputComponent);
|
|
|
|
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent))
|
|
{
|
|
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ANakedDesireCharacter::OnLook);
|
|
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ANakedDesireCharacter::OnMove);
|
|
EnhancedInputComponent->BindAction(RunAction, ETriggerEvent::Started, this, &ANakedDesireCharacter::OnRunPress);
|
|
EnhancedInputComponent->BindAction(RunAction, ETriggerEvent::Completed, this, &ANakedDesireCharacter::OnRunRelease);
|
|
EnhancedInputComponent->BindAction(CrouchAction, ETriggerEvent::Completed, this, &ANakedDesireCharacter::OnCrouchToggle);
|
|
EnhancedInputComponent->BindAction(EquipmentAction, ETriggerEvent::Started, this, &ANakedDesireCharacter::OnEquipmentPress);
|
|
EnhancedInputComponent->BindAction(InteractAction, ETriggerEvent::Started, this, &ANakedDesireCharacter::OnInteractPress);
|
|
}
|
|
}
|
|
|
|
void ANakedDesireCharacter::NotifyControllerChanged()
|
|
{
|
|
Super::NotifyControllerChanged();
|
|
|
|
if (const APlayerController* PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
|
|
{
|
|
if (const ULocalPlayer* LocalPlayer = PC->GetLocalPlayer())
|
|
{
|
|
if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
|
|
{
|
|
if (MappingContext)
|
|
{
|
|
InputSystem->AddMappingContext(MappingContext, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ANakedDesireCharacter::BeginPlay()
|
|
{
|
|
Super::BeginPlay();
|
|
|
|
StimuliSourceComponent->RegisterForSense(TSubclassOf<UAISense_Sight>());
|
|
StimuliSourceComponent->RegisterWithPerceptionSystem();
|
|
|
|
// Initialize after Super::BeginPlay so clothing hydration has populated the
|
|
// equipped set; both components sync from that final state.
|
|
ClothingVisualsComponent->Initialize(GetMesh(), ClothingManager);
|
|
CensorshipComponent->Initialize(ClothingManager, BoobLCensorship, BoobRCensorship, VaginaCensorship, AnalCensorship);
|
|
|
|
HUD = Cast<ANakedDesireHUD>(UGameplayStatics::GetPlayerController(GetWorld(), 0)->GetHUD());
|
|
}
|
|
|
|
UAISense_Sight::EVisibilityResult ANakedDesireCharacter::CanBeSeenFrom(const FCanBeSeenFromContext& Context,
|
|
FVector& OutSeenLocation, int32& OutNumberOfLoSChecksPerformed, int32& OutNumberOfAsyncLosCheckRequested,
|
|
float& OutSightStrength, int32* UserData, const FOnPendingVisibilityQueryProcessedDelegate* Delegate)
|
|
{
|
|
const FVector StartLocation = Context.ObserverLocation;
|
|
const FVector BoobsBoneLocation = GetMesh()->GetBoneLocation(FName(TEXT("boobs_root")));
|
|
const FVector PelvisBoneLocation = GetMesh()->GetBoneLocation(FName(TEXT("pelvis")));
|
|
|
|
OutNumberOfLoSChecksPerformed++;
|
|
|
|
FHitResult BoobsHitResult;
|
|
const bool BoobsHit = CheckSight(StartLocation, BoobsBoneLocation, BoobsHitResult, Context.IgnoreActor);
|
|
|
|
FHitResult PelvisHitResult;
|
|
const bool PelvisHit = CheckSight(StartLocation, PelvisBoneLocation, PelvisHitResult, Context.IgnoreActor);
|
|
|
|
if ((!BoobsHit || BoobsHitResult.GetActor() == this) && ClothingManager->IsBodyPartExposed(EBodyPart::Boobs))
|
|
{
|
|
UE_LOG(LogTemp, Warning, TEXT("Boobs hit"));
|
|
OutSeenLocation = BoobsBoneLocation;
|
|
OutSightStrength = 1.0f;
|
|
return UAISense_Sight::EVisibilityResult::Visible;
|
|
}
|
|
|
|
if ((!PelvisHit || PelvisHitResult.GetActor() == this) &&
|
|
(ClothingManager->IsBodyPartExposed(EBodyPart::Ass) || ClothingManager->IsBodyPartExposed(EBodyPart::Genitals)))
|
|
{
|
|
UE_LOG(LogTemp, Warning, TEXT("Pelvis hit"));
|
|
OutSeenLocation = PelvisBoneLocation;
|
|
OutSightStrength = 1.0f;
|
|
return UAISense_Sight::EVisibilityResult::Visible;
|
|
}
|
|
|
|
UE_LOG(LogTemp, Warning, TEXT("Not visoble"));
|
|
|
|
return UAISense_Sight::EVisibilityResult::NotVisible;
|
|
}
|
|
|
|
bool ANakedDesireCharacter::CheckSight(const FVector& StartLocation, const FVector& EndLocation, FHitResult& HitResult,
|
|
const AActor* IgnoreActor)
|
|
{
|
|
FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(AILineOfSight), true);
|
|
QueryParams.AddIgnoredActor(IgnoreActor);
|
|
QueryParams.AddIgnoredActor(this); // ignore self
|
|
|
|
const bool bHit = GetWorld()->LineTraceSingleByChannel(
|
|
HitResult,
|
|
StartLocation,
|
|
EndLocation,
|
|
ECC_Visibility,
|
|
QueryParams
|
|
);
|
|
|
|
// DrawDebugLine(GetWorld(), StartLocation, EndLocation, bHit ? FColor::Red : FColor::Green, false, 1.0f);
|
|
|
|
return bHit;
|
|
}
|
|
|
|
void ANakedDesireCharacter::LogTest()
|
|
{
|
|
UClothingItemInstance* ClothingItemInstance = ClothingManager->GetSlotClothing(EClothingSlotType::UnderwearTop);
|
|
UE_LOG(LogTemp, Warning, TEXT("ANakedDesireCharacter::LogTest %s"), *ClothingItemInstance->GetInstanceId().ToString());
|
|
}
|
|
|
|
void ANakedDesireCharacter::OnLook(const FInputActionValue& Value)
|
|
{
|
|
const FVector2D MouseValue = Value.Get<FVector2D>();
|
|
|
|
AddControllerYawInput(MouseValue.X);
|
|
AddControllerPitchInput(MouseValue.Y);
|
|
}
|
|
|
|
void ANakedDesireCharacter::OnMove(const FInputActionValue& Value)
|
|
{
|
|
const FVector2D MoveInput = Value.Get<FVector2D>();
|
|
const FRotator Rotator = Controller->GetControlRotation();
|
|
const FRotationMatrix Direction = FRotationMatrix(FRotator(0, Rotator.Yaw, 0));
|
|
const FVector ForwardDirection = Direction.GetUnitAxis(EAxis::X);
|
|
const FVector RightDirection = Direction.GetUnitAxis(EAxis::Y);
|
|
|
|
AddMovementInput(ForwardDirection, MoveInput.Y);
|
|
AddMovementInput(RightDirection, MoveInput.X);
|
|
}
|
|
|
|
void ANakedDesireCharacter::OnRunPress(const FInputActionValue& Value)
|
|
{
|
|
SetIsRunning(true);
|
|
}
|
|
|
|
void ANakedDesireCharacter::OnRunRelease(const FInputActionValue& Value)
|
|
{
|
|
SetIsRunning(false);
|
|
}
|
|
|
|
void ANakedDesireCharacter::OnCrouchToggle(const FInputActionValue& Value)
|
|
{
|
|
if (GetCharacterMovement()->IsCrouching())
|
|
{
|
|
UnCrouch();
|
|
}
|
|
else
|
|
{
|
|
Crouch();
|
|
}
|
|
}
|
|
|
|
void ANakedDesireCharacter::OnEquipmentPress(const FInputActionValue& Value)
|
|
{
|
|
HUD->GetGameLayoutWidget()->OpenInventory();
|
|
}
|
|
|
|
void ANakedDesireCharacter::OnInteractPress(const FInputActionValue& Value)
|
|
{
|
|
InteractionComponent->Interact();
|
|
}
|
|
|
|
void ANakedDesireCharacter::NotifyNoticed(ANPCAIController* NPCController)
|
|
{
|
|
OnNoticed.Broadcast(NPCController);
|
|
}
|
|
|
|
void ANakedDesireCharacter::SetIsRunning(const bool Value)
|
|
{
|
|
Gait = Value ? EGait::Run : EGait::Walk;
|
|
GetCharacterMovement()->MaxWalkSpeed = Gait == EGait::Run ? RunSpeed : WalkSpeed;
|
|
}
|