This commit is contained in:
2026-05-17 22:44:49 +03:00
commit 26fedadcd8
9071 changed files with 44364 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
// © 2025 Naked People Team. All Rights Reserved.
using UnrealBuildTool;
using System.Collections.Generic;
public class NakedDesireTarget : TargetRules
{
public NakedDesireTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Game;
DefaultBuildSettings = BuildSettingsVersion.V6;
IncludeOrderVersion = EngineIncludeOrderVersion.Latest;
ExtraModuleNames.Add("NakedDesire");
}
}
@@ -0,0 +1,4 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "ClothingItem.h"
@@ -0,0 +1,49 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ClothingSlotType.h"
#include "Engine/DataAsset.h"
#include "NakedDesire/Player/PrivateBodyPartType.h"
#include "ClothingItem.generated.h"
/**
*
*/
UCLASS(BlueprintType)
class NAKEDDESIRE_API UClothingItem : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
FText Name;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
UTexture2D* Icon;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
EClothingSlotType SlotType;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
USkeletalMesh* SkeletalMesh;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TMap<FName, UMaterialInstance*> Materials;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
UStaticMesh* StaticMesh;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
int BasePrice;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TArray<EPrivateBodyPartType> CoveredBodyParts;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (EditCondition = "SlotType == EClothingSlotType::Shoes", Category = "Shoes"))
float ShoesOffset = 0.0f;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
bool UseLeaderPose = false;
};
@@ -0,0 +1,25 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "ClothingItemData.h"
#include "../SaveGame/ClothingItemSaveData.h"
FClothingItemSaveData UClothingItemData::ToSaveData() const
{
FClothingItemSaveData SaveData;
SaveData.ClothingItem = Info;
return SaveData;
}
UClothingItemData* UClothingItemData::CreateFromSaveData(const FClothingItemSaveData& SaveData)
{
UClothingItem* ClothingItem = SaveData.ClothingItem.LoadSynchronous();
UClothingItemData* ClothingItemData = NewObject<UClothingItemData>();
ClothingItemData->Info = ClothingItem;
return ClothingItemData;
}
@@ -0,0 +1,27 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ClothingItem.h"
#include "ClothingItemData.generated.h"
struct FClothingItemSaveData;
/**
*
*/
UCLASS(EditInlineNew, BlueprintType)
class NAKEDDESIRE_API UClothingItemData : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly)
UClothingItem* Info = nullptr;
UFUNCTION(BlueprintCallable)
FClothingItemSaveData ToSaveData() const;
UFUNCTION(BlueprintCallable)
static UClothingItemData* CreateFromSaveData(const FClothingItemSaveData& SaveData);
};
@@ -0,0 +1,5 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "ClothingList.h"
@@ -0,0 +1,22 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "ClothingList.generated.h"
class UClothingItemData;
/**
*
*/
UCLASS()
class NAKEDDESIRE_API UClothingList : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Instanced)
TArray<UClothingItemData*> ClothingItems;
};
@@ -0,0 +1,186 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "ClothingManager.h"
#include "ClothingItemData.h"
#include "GameFramework/Character.h"
#include "NakedDesire/SaveGame/GlobalSaveGameData.h"
UClothingManager::UClothingManager()
{
PrimaryComponentTick.bCanEverTick = false;
}
bool UClothingManager::IsBodyTypeExposed(const EPrivateBodyPartType PrivateBodyPartType)
{
for (const auto& ClothingSlot : ClothingSlots)
{
if (ClothingSlot.ClothingData && ClothingSlot.ClothingData->Info->CoveredBodyParts.Contains(PrivateBodyPartType))
{
return false;
}
}
return true;
}
bool UClothingManager::GetClothingSlotData(const EClothingSlotType ClothingSlotType, FClothingSlotData& OutClothingSlotData)
{
for (const auto& ClothingSlot : ClothingSlots)
{
if (ClothingSlot.ClothingSlotType == ClothingSlotType)
{
OutClothingSlotData = ClothingSlot;
return true;
}
}
return false;
}
void UClothingManager::SetClothingSlotItem(const EClothingSlotType ClothingSlotType, UClothingItemData* ClothingItem)
{
for (FClothingSlotData& ClothingSlot : ClothingSlots)
{
if (ClothingSlot.ClothingSlotType == ClothingSlotType)
{
ClothingSlot.ClothingData = ClothingItem;
}
}
}
TArray<UClothingItemData*> UClothingManager::GetEquippedClothing()
{
TArray<UClothingItemData*> EquippedClothingItems;
for (FClothingSlotData ClothingSlot : ClothingSlots)
{
if (ClothingSlot.ClothingData)
{
EquippedClothingItems.Add(ClothingSlot.ClothingData);
}
}
return EquippedClothingItems;
}
void UClothingManager::HydrateClothing(UGlobalSaveGameData* SaveGameData)
{
for (const FClothingItemSaveData& ClothingItemSaveData : SaveGameData->PlayerClothing)
{
UClothingItemData* ClothingItemData = UClothingItemData::CreateFromSaveData(ClothingItemSaveData);
PutOnClothing(ClothingItemData);
}
}
float UClothingManager::GetHeelHeight()
{
if (FClothingSlotData ClothingSlotData; GetClothingSlotData(EClothingSlotType::Shoes, ClothingSlotData))
{
if (ClothingSlotData.ClothingData)
{
return ClothingSlotData.ClothingData->Info->ShoesOffset;
}
}
return 0;
}
void UClothingManager::PutOnClothing(UClothingItemData* ClothingData)
{
if (!ClothingData)
{
return;
}
const EClothingSlotType ClothingSlotType = ClothingData->Info->SlotType;
FClothingSlotData ClothingSlotData;
GetClothingSlotData(ClothingSlotType, ClothingSlotData);
ClothingSlotData.MeshComponent->SetSkeletalMesh(ClothingData->Info->SkeletalMesh);
if (!ClothingData->Info->Materials.IsEmpty())
{
for (const TPair<FName, UMaterialInstance*>& Material : ClothingData->Info->Materials)
{
ClothingSlotData.MeshComponent->SetMaterialByName(Material.Key, Material.Value);
}
}
SetClothingSlotItem(ClothingSlotType, ClothingData);
if (ClothingData->Info->UseLeaderPose)
{
ClothingSlotData.MeshComponent->SetLeaderPoseComponent(Cast<ACharacter>(GetOwner())->GetMesh());
}
OnClothingEquip.Broadcast(ClothingData);
}
void UClothingManager::TakeClothing(UClothingItemData* ClothingData)
{
if (!ClothingData->Info)
{
return;
}
FClothingSlotData ClothingSlotData;
GetClothingSlotData(ClothingData->Info->SlotType, ClothingSlotData);
if (ClothingSlotData.ClothingData->Info)
{
DropClothing(ClothingData->Info->SlotType);
}
ClothingSlotData.ClothingData = ClothingData;
PutOnClothing(ClothingData);
}
UClothingItemData* UClothingManager::RemoveClothing(const EClothingSlotType ClothingSlotType)
{
FClothingSlotData ClothingSlotData;
if (!GetClothingSlotData(ClothingSlotType, ClothingSlotData) || !ClothingSlotData.ClothingData)
{
UE_LOG(LogTemp, Error, TEXT("Couldn't find clothing slot"));
return nullptr;
}
UClothingItemData* ClothingData = ClothingSlotData.ClothingData;
SetClothingSlotItem(ClothingSlotType, nullptr);
USkeletalMeshComponent* MeshComponent = ClothingSlotData.MeshComponent;
MeshComponent->SetSkeletalMesh(nullptr);
if (ClothingData->Info->UseLeaderPose)
{
ClothingSlotData.MeshComponent->SetLeaderPoseComponent(nullptr);
}
OnClothingUnequip.Broadcast(ClothingData);
return ClothingData;
}
void UClothingManager::DropClothing(const EClothingSlotType ClothingType)
{
const UClothingItemData* ClothingData = RemoveClothing(ClothingType);
if (!ClothingData)
{
return;
}
OnClothingDropped.Broadcast(ClothingData);
}
bool UClothingManager::IsClothingTypeOn(const EClothingSlotType ClothingType)
{
FClothingSlotData ClothingSlotData;
GetClothingSlotData(ClothingType, ClothingSlotData);
const bool IsTypeOn = ClothingSlotData.ClothingData != nullptr;
return IsTypeOn;
}
bool UClothingManager::IsPartiallyNaked()
{
return IsBodyTypeExposed(EPrivateBodyPartType::BackBottom) || IsBodyTypeExposed(EPrivateBodyPartType::FrontBottom) || IsBodyTypeExposed(EPrivateBodyPartType::FrontTop);
}
@@ -0,0 +1,79 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ClothingSlotData.h"
#include "Components/ActorComponent.h"
#include "NakedDesire/Player/PrivateBodyPartType.h"
#include "ClothingManager.generated.h"
// TODO: Check clothing colors
class UGlobalSaveGameData;
class AClothingPickup;
class UClothingItemData;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnClothingChangeSignature, const UClothingItemData*, ClothingData);
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class NAKEDDESIRE_API UClothingManager : public UActorComponent
{
GENERATED_BODY()
public:
UClothingManager();
UPROPERTY(BlueprintReadWrite, Category = "Clothing Manager|Clothing")
USkeletalMeshComponent* RootMesh = nullptr;
UPROPERTY(BlueprintReadWrite, Category = "Clothing Manager|Clothing")
TArray<FClothingSlotData> ClothingSlots;
UPROPERTY(BlueprintAssignable)
FOnClothingChangeSignature OnClothingEquip;
UPROPERTY(BlueprintAssignable)
FOnClothingChangeSignature OnClothingUnequip;
UPROPERTY(BlueprintAssignable)
FOnClothingChangeSignature OnClothingDropped;
UFUNCTION(BlueprintCallable)
void PutOnClothing(UClothingItemData* ClothingData);
UFUNCTION(BlueprintCallable)
void DropClothing(const EClothingSlotType ClothingType);
UFUNCTION(BlueprintCallable)
bool IsClothingTypeOn(const EClothingSlotType ClothingType);
UFUNCTION(BlueprintCallable)
bool IsPartiallyNaked();
UFUNCTION(BlueprintCallable)
bool IsBodyTypeExposed(EPrivateBodyPartType PrivateBodyPartType);
UFUNCTION(BlueprintCallable)
void TakeClothing(UClothingItemData* ClothingData);
UFUNCTION(BlueprintCallable)
UClothingItemData* RemoveClothing(EClothingSlotType ClothingSlotType);
UFUNCTION(BlueprintCallable)
bool GetClothingSlotData(EClothingSlotType ClothingSlotType, FClothingSlotData& OutClothingSlotData);
UFUNCTION(BlueprintCallable)
void SetClothingSlotItem(const EClothingSlotType ClothingSlotType, UClothingItemData* ClothingItem);
UFUNCTION(BlueprintCallable)
TArray<UClothingItemData*> GetEquippedClothing();
void HydrateClothing(UGlobalSaveGameData* SaveGameData);
UFUNCTION(BlueprintPure)
float GetHeelHeight();
};
@@ -0,0 +1,45 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ClothingSlotType.h"
#include "ClothingSlotData.generated.h"
enum class EClothingSlotType : uint8;
class UClothingItemData;
/**
*
*/
USTRUCT(BlueprintType)
struct NAKEDDESIRE_API FClothingSlotData
{
GENERATED_BODY()
FClothingSlotData()
: MeshComponent(nullptr), ClothingSlotType(EClothingSlotType::Anal), ClothingData(nullptr), Name(FText::GetEmpty())
{
}
FClothingSlotData(USkeletalMeshComponent* MeshComponent, const EClothingSlotType ClothingSlotType, UClothingItemData* ClothingData, const FText& Name)
{
this->MeshComponent = MeshComponent;
this->ClothingSlotType = ClothingSlotType;
this->ClothingData = ClothingData;
this->Name = Name;
}
UPROPERTY(BlueprintReadWrite, Category = "Clothing")
USkeletalMeshComponent* MeshComponent = nullptr;
UPROPERTY(BlueprintReadWrite, Category = "Clothing")
EClothingSlotType ClothingSlotType = EClothingSlotType::Anal;
UPROPERTY(BlueprintReadWrite, Category = "Clothing")
UClothingItemData* ClothingData = nullptr;
UPROPERTY(BlueprintReadWrite, Category = "Clothing")
FText Name = FText::GetEmpty();
};
@@ -0,0 +1,27 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
/**
*
*/
UENUM(BlueprintType)
enum class EClothingSlotType : uint8
{
Nipples,
Anal,
Vagina,
Head,
Neck,
Face,
Eyes,
Body,
Top,
Bottom,
Bra,
Panties,
Socks,
Shoes,
};
@@ -0,0 +1,14 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "ClothingSlotWidgetData.generated.h"
USTRUCT(BlueprintType)
struct NAKEDDESIRE_API FClothingSlotWidgetData
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly)
UTexture2D* PlaceholderIcon = nullptr;
};
@@ -0,0 +1,5 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "ClothingSlotWidgetsInfo.h"
@@ -0,0 +1,22 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ClothingSlotWidgetData.h"
#include "ClothingSlotType.h"
#include "Engine/DataAsset.h"
#include "ClothingSlotWidgetsInfo.generated.h"
/**
*
*/
UCLASS()
class NAKEDDESIRE_API UClothingSlotInfo : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly)
TMap<EClothingSlotType, FClothingSlotWidgetData> ClothingSlotsData;
};
+15
View File
@@ -0,0 +1,15 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
/**
*
*/
UENUM(BlueprintType)
enum class EAirMode : uint8
{
OnGround,
InAir
};
+8
View File
@@ -0,0 +1,8 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#define SLOT_NAME "Slot2"
#define SLOT_PLAYER 0
#define IS_DEMO false
+15
View File
@@ -0,0 +1,15 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
/**
*
*/
UENUM(BlueprintType)
enum class EGait : uint8
{
Walk,
Run
};
+15
View File
@@ -0,0 +1,15 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
/**
*
*/
UENUM(BlueprintType)
enum class EMovementState : uint8
{
Idle,
Moving
};
@@ -0,0 +1,4 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "NakedDesireGameInstance.h"
@@ -0,0 +1,15 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "NakedDesireGameInstance.generated.h"
/**
*
*/
UCLASS()
class NAKEDDESIRE_API UNakedDesireGameInstance : public UGameInstance
{
GENERATED_BODY()
};
@@ -0,0 +1,70 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "NakedDesireGameMode.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Clothing/ClothingItemData.h"
#include "UObject/ConstructorHelpers.h"
#include "NakedDesire/Interactables/Wardrobe.h"
#include "NakedDesire/MissionBuilder/MissionsConfig.h"
#include "NakedDesire/MissionBuilder/MissionsManager.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
void ANakedDesireGameMode::RestartGame()
{
UGameplayStatics::OpenLevel(this, "City");
}
AWardrobe* ANakedDesireGameMode::GetWardrobe() const
{
return Wardrobe;
}
void ANakedDesireGameMode::BuyItem(UClothingItemData* ClothingItem)
{
ANakedDesireCharacter* Player = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
if (!Player)
{
return;
}
if (Player->Money < ClothingItem->Info->BasePrice)
{
return;
}
Player->Money -= ClothingItem->Info->BasePrice;
Wardrobe->ClothingItems.Add(ClothingItem);
}
void ANakedDesireGameMode::OnHourChanged(int32 Hour)
{
if (Hour == 4)
{
DaysPassed++;
RefreshDailyMissions();
}
}
void ANakedDesireGameMode::BeginPlay()
{
Super::BeginPlay();
if (AActor* FoundActor = UGameplayStatics::GetActorOfClass(GetWorld(), AWardrobe::StaticClass()))
{
if (AWardrobe* WardrobeActor = Cast<AWardrobe>(FoundActor))
{
Wardrobe = WardrobeActor;
}
}
}
void ANakedDesireGameMode::RefreshDailyMissions()
{
ANakedDesireCharacter* Player = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
if (!Player)
{
return;
}
Player->MissionsManager->RefreshDailyMissions(MissionsConfig->DailyMissions[DaysPassed].Missions);
}
@@ -0,0 +1,62 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "NakedDesireGameMode.generated.h"
class UMissionsConfig;
class AWardrobe;
class UClothingItemData;
UCLASS(minimalapi)
class ANakedDesireGameMode : public AGameModeBase
{
GENERATED_BODY()
UPROPERTY()
AWardrobe* Wardrobe = nullptr;
UPROPERTY(EditDefaultsOnly)
UMissionsConfig* MissionsConfig;
int32 DaysPassed = 0;
public:
int NoticeCount = 0;
void RestartGame();
UFUNCTION(BlueprintPure, BlueprintImplementableEvent)
FTimecode GetCurrentTime() const;
UFUNCTION(BlueprintPure, BlueprintImplementableEvent)
int32 GetDaysElapsed() const;
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable)
void SetCurrentTime(FTimecode TimeCode);
UFUNCTION(BlueprintPure)
AWardrobe* GetWardrobe() const;
UFUNCTION(BlueprintImplementableEvent)
void EndGameEmbarrassed();
UFUNCTION(BlueprintCallable)
void BuyItem(UClothingItemData* ClothingItem);
UFUNCTION(BlueprintCallable)
void OnHourChanged(int32 Hour);
protected:
virtual void BeginPlay() override;
private:
void RefreshDailyMissions();
};
@@ -0,0 +1,60 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "NakedDesireUserSettings.h"
void UNakedDesireUserSettings::SetGlobalVolume(float Value)
{
GlobalVolume = Value;
}
float UNakedDesireUserSettings::GetGlobalVolume() const
{
return GlobalVolume;
}
void UNakedDesireUserSettings::SetIsCensorshipEnabled(bool Value)
{
IsCensorshipEnabled = Value;
}
bool UNakedDesireUserSettings::GetIsCensorshipEnabled() const
{
return IsCensorshipEnabled;
}
bool UNakedDesireUserSettings::GetHasAcceptedDisclaimer() const
{
return HasAcceptedDisclaimer;
}
void UNakedDesireUserSettings::SetHasAcceptedDisclaimer(bool Value)
{
HasAcceptedDisclaimer = Value;
}
void UNakedDesireUserSettings::SaveSettings()
{
Super::SaveSettings();
OnSettingsChanged.Broadcast(this);
}
void UNakedDesireUserSettings::ApplyNonResolutionSettings()
{
Super::ApplyNonResolutionSettings();
OnSettingsChanged.Broadcast(this);
}
void UNakedDesireUserSettings::ApplySettings(bool bCheckForCommandLineOverrides)
{
Super::ApplySettings(bCheckForCommandLineOverrides);
OnSettingsChanged.Broadcast(this);
}
UNakedDesireUserSettings* UNakedDesireUserSettings::GetNakedDesireUserSettings()
{
return Cast<UNakedDesireUserSettings>(Super::GetGameUserSettings());
}
@@ -0,0 +1,57 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameUserSettings.h"
#include "NakedDesireUserSettings.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnSettingsChanged, class UNakedDesireUserSettings*, Settings);
/**
*
*/
UCLASS()
class NAKEDDESIRE_API UNakedDesireUserSettings : public UGameUserSettings
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
static UNakedDesireUserSettings* GetNakedDesireUserSettings();
UFUNCTION(BlueprintCallable)
void SetGlobalVolume(float Value);
UFUNCTION(BlueprintPure)
float GetGlobalVolume() const;
UFUNCTION(BlueprintCallable)
void SetIsCensorshipEnabled(bool Value);
UFUNCTION(BlueprintPure)
bool GetIsCensorshipEnabled() const;
UFUNCTION(BlueprintPure)
bool GetHasAcceptedDisclaimer() const;
UFUNCTION(BlueprintCallable)
void SetHasAcceptedDisclaimer(bool Value);
virtual void SaveSettings() override;
virtual void ApplyNonResolutionSettings() override;
virtual void ApplySettings(bool bCheckForCommandLineOverrides) override;
UPROPERTY(BlueprintAssignable)
FOnSettingsChanged OnSettingsChanged;
protected:
UPROPERTY(Config)
float GlobalVolume = 0.5f;
UPROPERTY(Config)
bool IsCensorshipEnabled = false;
UPROPERTY(Config)
bool HasAcceptedDisclaimer = false;
};
+15
View File
@@ -0,0 +1,15 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
/**
*
*/
UENUM(BlueprintType)
enum class EStance : uint8
{
Stand,
Crouch
};
+16
View File
@@ -0,0 +1,16 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "Utils.h"
#include "Constants.h"
FString UUtils::GetSlotName()
{
return SLOT_NAME;
}
int UUtils::GetSlotPlayer()
{
return SLOT_PLAYER;
}
+23
View File
@@ -0,0 +1,23 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Utils.generated.h"
/**
*
*/
UCLASS()
class NAKEDDESIRE_API UUtils : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintPure)
static FString GetSlotName();
UFUNCTION(BlueprintCallable, BlueprintPure)
static int GetSlotPlayer();
};
@@ -0,0 +1,55 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "InteractableBase.h"
#include "Components/WidgetComponent.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/InteractionSystem/InteractionManager.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
AInteractableBase::AInteractableBase()
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.TickInterval = 0.25f;
RootSceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
RootComponent = RootSceneComponent;
WidgetAnchor = CreateDefaultSubobject<USceneComponent>(TEXT("Widget Anchor"));
WidgetAnchor->SetupAttachment(RootComponent);
InteractionTrigger = CreateDefaultSubobject<UWidgetComponent>(TEXT("Interaction Trigger"));
InteractionTrigger->SetupAttachment(WidgetAnchor);
InteractionTrigger->SetDrawSize(FVector2D(35, 35));
InteractionTrigger->SetWidgetSpace(EWidgetSpace::Screen);
InteractionTrigger->SetWindowFocusable(false);
}
void AInteractableBase::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
if (!Player)
{
if (ACharacter* PlayerCharacter = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0))
{
Player = Cast<ANakedDesireCharacter>(PlayerCharacter);
}
}
if (Player)
{
const TScriptInterface<IInteractionTarget> NearestInteractionTarget = Player->InteractionManager->GetNearestInteractionTarget();
if (NearestInteractionTarget.GetObject() == this)
{
InteractionTrigger->SetVisibility(true);
}
else
{
InteractionTrigger->SetVisibility(false);
}
}
}
@@ -0,0 +1,35 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "NakedDesire/InteractionSystem/InteractionTarget.h"
#include "InteractableBase.generated.h"
class ANakedDesireCharacter;
class UWidgetComponent;
UCLASS()
class NAKEDDESIRE_API AInteractableBase : public AActor, public IInteractionTarget
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly)
USceneComponent* RootSceneComponent = nullptr;
UPROPERTY(EditDefaultsOnly)
USceneComponent* WidgetAnchor = nullptr;
UPROPERTY(EditDefaultsOnly)
UWidgetComponent* InteractionTrigger = nullptr;
UPROPERTY()
ANakedDesireCharacter* Player = nullptr;
public:
AInteractableBase();
protected:
virtual void Tick(float DeltaSeconds) override;
};
@@ -0,0 +1,5 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "Wardrobe.h"
@@ -0,0 +1,20 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "InteractableBase.h"
#include "GameFramework/Actor.h"
#include "Wardrobe.generated.h"
class UClothingItemData;
UCLASS(Blueprintable)
class NAKEDDESIRE_API AWardrobe : public AInteractableBase
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Instanced)
TArray<UClothingItemData*> ClothingItems;
};
@@ -0,0 +1,41 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "InteractionManager.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
UInteractionManager::UInteractionManager()
{
PrimaryComponentTick.bCanEverTick = false;
}
void UInteractionManager::OnTargetEnter(const TScriptInterface<IInteractionTarget>& Target)
{
InteractionTargets.Add(Target);
}
void UInteractionManager::OnTargetExit(const TScriptInterface<IInteractionTarget>& Target)
{
InteractionTargets.Remove(Target);
}
TScriptInterface<IInteractionTarget> UInteractionManager::GetNearestInteractionTarget()
{
const ANakedDesireCharacter* Player = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
TScriptInterface<IInteractionTarget> Target;
for (const auto& Elem : InteractionTargets)
{
const AActor* Actor = Cast<AActor>(Elem.GetObject());
const AActor* TargetActor = Target ? Cast<AActor>(Target.GetObject()) : nullptr;
if (!Target || FVector::Distance(Player->GetActorLocation(), Actor->GetActorLocation()) < FVector::Distance(Player->GetActorLocation(), TargetActor->GetActorLocation()))
{
Target = Elem;
}
}
return Target;
}
@@ -0,0 +1,27 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "InteractionTarget.h"
#include "Components/ActorComponent.h"
#include "InteractionManager.generated.h"
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class NAKEDDESIRE_API UInteractionManager : public UActorComponent
{
GENERATED_BODY()
UPROPERTY()
TArray<TScriptInterface<IInteractionTarget>> InteractionTargets;
public:
UInteractionManager();
void OnTargetEnter(const TScriptInterface<IInteractionTarget>& Target);
void OnTargetExit(const TScriptInterface<IInteractionTarget>& Target);
UFUNCTION(BlueprintCallable)
TScriptInterface<IInteractionTarget> GetNearestInteractionTarget();
};
@@ -0,0 +1,4 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "InteractionTarget.h"
@@ -0,0 +1,27 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "InteractionTarget.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UInteractionTarget : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class NAKEDDESIRE_API IInteractionTarget
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Interaction Target")
void Interact();
};
@@ -0,0 +1,4 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "LocationData.h"
@@ -0,0 +1,24 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "Engine/DataAsset.h"
#include "LocationData.generated.h"
/**
*
*/
UCLASS()
class NAKEDDESIRE_API ULocationData : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly)
FGameplayTag Tag;
UPROPERTY(EditDefaultsOnly)
FText Name;
};
@@ -0,0 +1,21 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "LocationTrigger.h"
#include "Components/BoxComponent.h"
ALocationTrigger::ALocationTrigger()
{
PrimaryActorTick.bCanEverTick = false;
BoxTrigger = CreateDefaultSubobject<UBoxComponent>("Box Trigger");
RootComponent = BoxTrigger;
}
ULocationData* ALocationTrigger::GetLocationData() const
{
return LocationData;
}
@@ -0,0 +1,27 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "LocationTrigger.generated.h"
class ULocationData;
class UBoxComponent;
UCLASS()
class NAKEDDESIRE_API ALocationTrigger : public AActor
{
GENERATED_BODY()
UPROPERTY(BlueprintReadOnly, meta = (AllowPrivateAccess))
UBoxComponent* BoxTrigger;
UPROPERTY(EditAnywhere)
ULocationData* LocationData;
public:
ALocationTrigger();
ULocationData* GetLocationData() const;
};
@@ -0,0 +1,27 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "GoalRestriction.h"
void UGoalRestriction::Init(ANakedDesireCharacter* PlayerCharacter)
{
IsSuccess = false;
Player = PlayerCharacter;
OnUpdate.Broadcast(this);
}
void UGoalRestriction::Complete()
{
Complete(true);
}
void UGoalRestriction::Complete(const bool Value)
{
IsSuccess = Value;
OnUpdate.Broadcast(this);
}
FText UGoalRestriction::GetDescription() const
{
return FText::GetEmpty();
}
@@ -0,0 +1,44 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "GoalRestriction.generated.h"
class ANakedDesireCharacter;
class UGoalRestriction;
DECLARE_MULTICAST_DELEGATE_OneParam(FMissionRestrictionUpdateSignature, UGoalRestriction*);
/**
*
*/
UCLASS(EditInlineNew, BlueprintType)
class NAKEDDESIRE_API UGoalRestriction : public UObject
{
GENERATED_BODY()
public:
FMissionRestrictionUpdateSignature OnUpdate;
UFUNCTION(BlueprintPure)
bool GetIsSuccess() const
{
return IsSuccess;
}
virtual void Init(ANakedDesireCharacter* PlayerCharacter);
virtual void Complete();
virtual void Complete(bool Value);
virtual void Stop() {};
UFUNCTION(BlueprintPure)
virtual FText GetDescription() const;
protected:
UPROPERTY()
ANakedDesireCharacter* Player = nullptr;
bool IsSuccess = false;
};
@@ -0,0 +1,65 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "FlashGoal.h"
#include "NakedDesire/NPC/NPCAIController.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
#define LOCTEXT_NAMESPACE "Missions.Goals.Flash"
const FText GoalsFlashSingle = LOCTEXT("Description.Single", "Flash someone {BodyPart} once");
const FText GoalsFlashMultiple = LOCTEXT("Description.Multiple", "Flash {BodyPart} to {PeopleCount} people");
#undef LOCTEXT_NAMESPACE
void UFlashGoal::Init(ANakedDesireCharacter* PlayerCharacter)
{
Super::Init(PlayerCharacter);
PlayerNoticedHandle = PlayerCharacter->OnNoticed.AddUObject(this, &UFlashGoal::OnPlayerNoticed);
}
void UFlashGoal::Complete()
{
Super::Complete();
Player->OnNoticed.Remove(PlayerNoticedHandle);
}
FText UFlashGoal::GetDescription() const
{
const FText BodyTypeString = UPrivateBodyPartType::GetString(BodyType);
if (RequiredFlashCount == 1)
{
return FText::Format(GoalsFlashSingle,
FFormatNamedArguments
{
{TEXT("BodyPart"), BodyTypeString}
});
}
return FText::Format(GoalsFlashMultiple,
FFormatNamedArguments
{
{TEXT("BodyPart"), BodyTypeString},
{TEXT("PeopleCount"), RequiredFlashCount}
});
}
void UFlashGoal::OnPlayerNoticed(ANPCAIController* NPC)
{
if (IsCompleted || !CheckRestrictions())
{
return;
}
if (!NoticedActors.Contains(NPC))
{
NoticedActors.Add(NPC);
}
if (NoticedActors.Num() >= RequiredFlashCount)
{
Complete();
}
}
@@ -0,0 +1,37 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "NakedDesire/MissionBuilder/MissionGoal.h"
#include "NakedDesire/Player/PrivateBodyPartType.h"
#include "FlashGoal.generated.h"
class ANPCAIController;
/**
*
*/
UCLASS(EditInlineNew)
class NAKEDDESIRE_API UFlashGoal : public UMissionGoal
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly, meta = (ClampMin = 1))
int RequiredFlashCount = 1;
UPROPERTY(EditDefaultsOnly)
EPrivateBodyPartType BodyType;
FDelegateHandle PlayerNoticedHandle;
UPROPERTY()
TSet<AActor*> NoticedActors;
public:
virtual void Init(ANakedDesireCharacter* PlayerCharacter) override;
virtual void Complete() override;
virtual FText GetDescription() const override;
private:
void OnPlayerNoticed(ANPCAIController* NPC);
};
@@ -0,0 +1,42 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "MinTimeGoal.h"
#define LOCTEXT_NAMESPACE "Missions.Goals.MinTime"
const FText GoalsMinTimeDescription = LOCTEXT("Description", "Do following at least {MinTime} seconds");
#undef LOCTEXT_NAMESPACE
FText UMinTimeGoal::GetDescription() const
{
return FText::Format(GoalsMinTimeDescription,
FFormatNamedArguments
{
{TEXT("MinTime"), MinTime}
});
}
void UMinTimeGoal::OnRestrictionUpdated(UGoalRestriction* Restriction)
{
Super::OnRestrictionUpdated(Restriction);
if (CheckRestrictions())
{
if (!TimerHandle.IsValid())
{
GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &UMinTimeGoal::TimeIsUp, MinTime, false);
}
}
else
{
if (TimerHandle.IsValid())
{
GetWorld()->GetTimerManager().ClearTimer(TimerHandle);
}
}
}
void UMinTimeGoal::TimeIsUp()
{
Complete();
}
@@ -0,0 +1,30 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "../MissionGoal.h"
#include "MinTimeGoal.generated.h"
/**
*
*/
UCLASS(EditInlineNew)
class NAKEDDESIRE_API UMinTimeGoal : public UMissionGoal
{
GENERATED_BODY()
public:
virtual FText GetDescription() const override;
protected:
virtual void OnRestrictionUpdated(UGoalRestriction* Restriction) override;
private:
UPROPERTY(EditDefaultsOnly)
float MinTime = 3.f;
FTimerHandle TimerHandle;
void TimeIsUp();
};
@@ -0,0 +1,63 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "Mission.h"
#include "MissionGoal.h"
void UMission::Init(ANakedDesireCharacter* PlayerCharacter)
{
Player = PlayerCharacter;
for (const auto& Goal : Goals)
{
Goal->Init(Player);
auto Handle = Goal->OnUpdate.AddUObject(this, &UMission::OnGoalUpdated);
GoalUpdateHandles.Add(Handle);
}
}
void UMission::OnGoalUpdated(UMissionGoal* MissionGoal)
{
if (IsCompleted)
{
return;
}
if (CheckGoals())
{
Complete();
}
}
void UMission::Complete()
{
IsCompleted = true;
for (const auto& Goal : Goals)
{
for (const auto& Handle : GoalUpdateHandles)
{
Goal->OnUpdate.Remove(Handle);
}
}
OnComplete.Broadcast(this);
}
bool UMission::CheckGoals()
{
if (IsCompleted)
{
return true;
}
for (const auto& Goal : Goals)
{
if (!Goal->GetIsCompleted() || !Goal->CheckRestrictions())
{
return false;
}
}
return true;
}
@@ -0,0 +1,67 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "Mission.generated.h"
DECLARE_MULTICAST_DELEGATE_OneParam(FMissionCompleteSignature, class UMission*);
class UMissionGoal;
class ANakedDesireCharacter;
class UGoalRestriction;
/**
*
*/
UCLASS(EditInlineNew, BlueprintType)
class NAKEDDESIRE_API UMission : public UObject
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly, Instanced)
TArray<UMissionGoal*> Goals;
UPROPERTY(EditDefaultsOnly)
int MoneyReward = 0;
bool IsCompleted = false;
TArray<FDelegateHandle> GoalUpdateHandles;
public:
FMissionCompleteSignature OnComplete;
void Init(ANakedDesireCharacter* PlayerCharacter);
UFUNCTION(BlueprintPure)
int GetMoneyReward() const
{
return MoneyReward;
}
UFUNCTION(BlueprintPure)
TArray<UMissionGoal*> GetGoals() const
{
return Goals;
}
UFUNCTION(BlueprintPure)
bool GetIsCompleted() const
{
return IsCompleted;
}
protected:
UPROPERTY()
ANakedDesireCharacter* Player = nullptr;
private:
UFUNCTION()
void OnGoalUpdated(UMissionGoal* MissionGoal);
void Complete();
bool CheckGoals();
};
@@ -0,0 +1,70 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "MissionGoal.h"
#include "GoalRestriction.h"
void UMissionGoal::Init(ANakedDesireCharacter* PlayerCharacter)
{
Player = PlayerCharacter;
for (const auto& Elem : Restrictions)
{
Elem->Init(Player);
auto Handle = Elem->OnUpdate.AddUObject(this, &UMissionGoal::OnRestrictionUpdated);
RestrictionUpdateHandles.Add(Handle);
}
}
void UMissionGoal::Complete()
{
if (!CheckRestrictions())
{
return;
}
IsCompleted = true;
for (const auto& Restriction : Restrictions)
{
Restriction->Stop();
for (const auto& Handle : RestrictionUpdateHandles)
{
Restriction->OnUpdate.Remove(Handle);
}
}
OnUpdate.Broadcast(this);
}
bool UMissionGoal::CheckRestrictions()
{
if (IsCompleted)
{
return true;
}
for (const auto& Restriction : Restrictions)
{
if (!Restriction->GetIsSuccess())
{
return false;
}
}
return true;
}
FText UMissionGoal::GetDescription() const
{
return FText::GetEmpty();
}
void UMissionGoal::OnRestrictionUpdated(UGoalRestriction* Restriction)
{
if (IsCompleted)
{
return;
}
OnUpdate.Broadcast(this);
}
@@ -0,0 +1,58 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "MissionGoal.generated.h"
class ANakedDesireCharacter;
class UMissionGoal;
class UGoalRestriction;
DECLARE_MULTICAST_DELEGATE_OneParam(FGoalUpdateSignature, UMissionGoal*);
/**
*
*/
UCLASS(EditInlineNew, BlueprintType)
class NAKEDDESIRE_API UMissionGoal : public UObject
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly, Instanced)
TArray<UGoalRestriction*> Restrictions;
TArray<FDelegateHandle> RestrictionUpdateHandles;
public:
virtual void Init(ANakedDesireCharacter* PlayerCharacter);
virtual void Complete();
UFUNCTION(BlueprintPure)
bool GetIsCompleted() const
{
return IsCompleted;
}
UFUNCTION(BlueprintPure)
TArray<UGoalRestriction*> GetRestrictions() const
{
return Restrictions;
}
FGoalUpdateSignature OnUpdate;
bool CheckRestrictions();
UFUNCTION(BlueprintPure)
virtual FText GetDescription() const;
protected:
UPROPERTY()
ANakedDesireCharacter* Player = nullptr;
virtual void OnRestrictionUpdated(UGoalRestriction* Restriction);
bool IsCompleted = false;
};
@@ -0,0 +1,4 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "MissionsConfig.h"
@@ -0,0 +1,34 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "MissionsConfig.generated.h"
class UMission;
USTRUCT()
struct NAKEDDESIRE_API FMissionsConfigItem
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly, Instanced)
TArray<UMission*> Missions;
};
/**
*
*/
UCLASS()
class NAKEDDESIRE_API UMissionsConfig : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly)
TArray<FMissionsConfigItem> DailyMissions;
UPROPERTY(EditDefaultsOnly)
TArray<FMissionsConfigItem> WeeklyMissions;
};
@@ -0,0 +1,69 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "MissionsManager.h"
#include "Mission.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
UMissionsManager::UMissionsManager()
{
PrimaryComponentTick.bCanEverTick = false;
}
void UMissionsManager::BeginPlay()
{
Super::BeginPlay();
Player = Cast<ANakedDesireCharacter>(GetOwner());
UE_LOG(LogTemp, Warning, TEXT("Player is NULL %s"), Player == nullptr ? TEXT("True") : TEXT("False"));
for (const auto& Mission : AvailableMissions)
{
Mission->Init(Player);
Mission->OnComplete.AddUObject(this, &UMissionsManager::CompleteMission);
}
}
void UMissionsManager::CompleteMission(UMission* Mission)
{
CompletedMissions.Add(Mission);
AvailableMissions.Remove(Mission);
OnMissionCompleted.Broadcast(Mission);
}
void UMissionsManager::CollectRewards()
{
if (CompletedMissions.IsEmpty())
{
return;
}
int TotalReward = 0;
for (const UMission* Mission : CompletedMissions)
{
TotalReward += Mission->GetMoneyReward();
}
Player->Money += TotalReward;
CompletedMissions.Empty();
OnRewardsCollected.Broadcast(TotalReward);
}
void UMissionsManager::RefreshDailyMissions(const TArray<UMission*>& NewMissions)
{
for (auto Mission : AvailableMissions)
{
Mission->OnComplete.RemoveAll(this);
AvailableMissions.Remove(Mission);
}
AvailableMissions.Append(NewMissions);
for (auto Mission : AvailableMissions)
{
Mission->Init(Player);
Mission->OnComplete.AddUObject(this, &UMissionsManager::CompleteMission);
}
}
@@ -0,0 +1,49 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "MissionsManager.generated.h"
class UMission;
class ANakedDesireCharacter;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMissionCompletedSignature, UMission*, Mission);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnRewardsCollected, int, Reward);
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class NAKEDDESIRE_API UMissionsManager : public UActorComponent
{
GENERATED_BODY()
UPROPERTY()
ANakedDesireCharacter* Player = nullptr;
public:
UMissionsManager();
UPROPERTY(EditDefaultsOnly, Instanced, BlueprintReadOnly)
TArray<UMission*> AvailableMissions;
UPROPERTY(BlueprintReadWrite)
TArray<UMission*> CompletedMissions;
UPROPERTY(BlueprintAssignable)
FOnMissionCompletedSignature OnMissionCompleted;
UPROPERTY(BlueprintAssignable)
FOnRewardsCollected OnRewardsCollected;
void CompleteMission(UMission* Mission);
UFUNCTION(BlueprintCallable)
void CollectRewards();
UFUNCTION()
void RefreshDailyMissions(const TArray<UMission*>& NewMissions);
protected:
virtual void BeginPlay() override;
};
@@ -0,0 +1,110 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "EquipClothingRestriction.h"
#include "NakedDesire/Clothing/ClothingItem.h"
#include "NakedDesire/Clothing/ClothingItemData.h"
#include "NakedDesire/Clothing/ClothingManager.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
#define LOCTEXT_NAMESPACE "Missions.Restriction.EquipClothing"
const FText RestrictionEquipClothingDescriptionSingle = LOCTEXT("Description.Single", "Equip {ItemName}");
const FText RestrictionEquipClothingDescriptionMultiple = LOCTEXT("Description.Multiple", "Equip one of: {ItemNames}");
#undef LOCTEXT_NAMESPACE
void UEquipClothingRestriction::Init(ANakedDesireCharacter* PlayerCharacter)
{
Super::Init(PlayerCharacter);
if (!ClothingEquippedDelegateHandle.IsValid())
{
Player->ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &UEquipClothingRestriction::OnClothingEquipped);
}
if (!ClothingUnequippedDelegateHandle.IsValid())
{
Player->ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &UEquipClothingRestriction::OnClothingUnequipped);
}
CheckClothing();
}
void UEquipClothingRestriction::Stop()
{
Super::Stop();
Player->ClothingManager->OnClothingEquip.Remove(this, TEXT("OnClothingEquipped"));
Player->ClothingManager->OnClothingUnequip.Remove(this, TEXT("OnClothingUnequipped"));
}
FText UEquipClothingRestriction::GetDescription() const
{
if (ClothingItems.Num() == 1 && ClothingItems[0])
{
return FText::Format(RestrictionEquipClothingDescriptionSingle,
FFormatNamedArguments
{
{TEXT("ItemName"), ClothingItems[0]->Name}
});
}
FString Items = TEXT("");
for (const auto& Item : ClothingItems)
{
if (Item)
{
Items += Item->Name.ToString() + ", ";
}
}
return FText::Format(RestrictionEquipClothingDescriptionMultiple,
FFormatNamedArguments
{
{TEXT("ItemNames"), FText::FromString(Items)}
});
}
void UEquipClothingRestriction::OnClothingEquipped(const UClothingItemData* ClothingData)
{
const bool IsTargetClothing = ClothingItems.FindByPredicate([&ClothingData](const UClothingItem* Item)
{
return Item && Item->Name.EqualTo(ClothingData->Info->Name);
}) != nullptr;
if (IsTargetClothing)
{
Complete();
}
}
void UEquipClothingRestriction::OnClothingUnequipped(const UClothingItemData* ClothingData)
{
const bool IsTargetClothing = ClothingItems.FindByPredicate([&ClothingData](const UClothingItem* Item)
{
return Item && Item->Name.EqualTo(ClothingData->Info->Name);
}) != nullptr;
if (IsTargetClothing)
{
Init(Player);
}
}
void UEquipClothingRestriction::CheckClothing()
{
for (const FClothingSlotData& ClothingSlot : Player->ClothingManager->ClothingSlots)
{
if (!ClothingSlot.ClothingData)
{
continue;
}
const bool IsTargetClothing = ClothingItems.FindByPredicate([&ClothingSlot](const UClothingItem* Item)
{
return Item && Item->Name.EqualTo(ClothingSlot.ClothingData->Info->Name);
}) != nullptr;
if (IsTargetClothing)
{
Complete();
return;
}
}
}
@@ -0,0 +1,39 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "NakedDesire/MissionBuilder/GoalRestriction.h"
#include "EquipClothingRestriction.generated.h"
class UClothingItem;
class UClothingItemData;
/**
*
*/
UCLASS(EditInlineNew)
class NAKEDDESIRE_API UEquipClothingRestriction : public UGoalRestriction
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly, meta = (ToolTip =
"One of provided clothing items should be equipped by player. If multiple clothing items required provide multiple restrictions"))
TArray<UClothingItem*> ClothingItems;
public:
virtual void Init(ANakedDesireCharacter* PlayerCharacter) override;
virtual void Stop() override;
virtual FText GetDescription() const override;
private:
FDelegateHandle ClothingEquippedDelegateHandle;
FDelegateHandle ClothingUnequippedDelegateHandle;
UFUNCTION()
void OnClothingEquipped(const UClothingItemData* ClothingData);
UFUNCTION()
void OnClothingUnequipped(const UClothingItemData* ClothingData);
void CheckClothing();
};
@@ -0,0 +1,81 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "ExposeBodyPartRestriction.h"
#include "NakedDesire/Clothing/ClothingItemData.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
#include "NakedDesire/Clothing/ClothingManager.h"
#define LOCTEXT_NAMESPACE "Missions.Restrictions.ExposeBodyPart"
const FText RestrictionsExposeBodyPartDescription = LOCTEXT("Description", "Expose {BodyPart}");
#undef LOCTEXT_NAMESPACE
void UExposeBodyPartRestriction::Init(ANakedDesireCharacter* PlayerCharacter)
{
Super::Init(PlayerCharacter);
PlayerCharacter->ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &UExposeBodyPartRestriction::EquipClothing);
PlayerCharacter->ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &UExposeBodyPartRestriction::UnequipClothing);
CheckClothing();
}
void UExposeBodyPartRestriction::Stop()
{
Super::Stop();
Player->ClothingManager->OnClothingEquip.Remove(this, TEXT("ClothingEquip"));
Player->ClothingManager->OnClothingUnequip.Remove(this, TEXT("ClothingUnequip"));
}
FText UExposeBodyPartRestriction::GetDescription() const
{
FText Part = UPrivateBodyPartType::GetString(BodyPart);
return FText::Format(RestrictionsExposeBodyPartDescription,
FFormatNamedArguments
{
{TEXT("BodyPart"), Part}
});
}
void UExposeBodyPartRestriction::EquipClothing(const UClothingItemData* ClothingData)
{
if (IsSuccess && ClothingData->Info->CoveredBodyParts.Contains(BodyPart))
{
Init(Player);
}
}
void UExposeBodyPartRestriction::UnequipClothing(const UClothingItemData* ClothingData)
{
if (IsSuccess)
{
return;
}
CheckClothing();
}
void UExposeBodyPartRestriction::CheckClothing()
{
if (!Player || !Player->ClothingManager || Player->ClothingManager->ClothingSlots.IsEmpty())
{
return;
}
const FClothingSlotData* TargetClothingItem = Player->ClothingManager->ClothingSlots.FindByPredicate([this](const FClothingSlotData& ClothingSlot)
{
if (ClothingSlot.ClothingData)
{
return ClothingSlot.ClothingData->Info->CoveredBodyParts.Contains(BodyPart);
}
return false;
});
if (!TargetClothingItem)
{
Complete();
}
}
@@ -0,0 +1,38 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "NakedDesire/Player/PrivateBodyPartType.h"
#include "NakedDesire/MissionBuilder/GoalRestriction.h"
#include "ExposeBodyPartRestriction.generated.h"
class UClothingItemData;
/**
*
*/
UCLASS(EditInlineNew)
class NAKEDDESIRE_API UExposeBodyPartRestriction : public UGoalRestriction
{
GENERATED_BODY()
FDelegateHandle EquipClothingHandle;
FDelegateHandle UnequipClothingHandle;
UPROPERTY(EditDefaultsOnly)
EPrivateBodyPartType BodyPart;
protected:
virtual void Init(ANakedDesireCharacter* PlayerCharacter) override;
virtual void Stop() override;
virtual FText GetDescription() const override;
private:
UFUNCTION()
void EquipClothing(const UClothingItemData* ClothingData);
UFUNCTION()
void UnequipClothing(const UClothingItemData* ClothingData);
void CheckClothing();
};
@@ -0,0 +1,51 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "LocationRestriction.h"
#include "NakedDesire/Locations/LocationData.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
#define LOCTEXT_NAMESPACE "Missions.Restrictions.Location"
const FText RestrictionsLocationDescription = LOCTEXT("Description", "Visit {LocationName}");
#undef LOCTEXT_NAMESPACE
void ULocationRestriction::Init(ANakedDesireCharacter* PlayerCharacter)
{
Super::Init(PlayerCharacter);
AreaEnterHandle = PlayerCharacter->OnAreaEnter.AddUObject(this, &ULocationRestriction::OnAreaEnter);
AreaExitHandle = PlayerCharacter->OnAreaExit.AddUObject(this, &ULocationRestriction::OnAreaExit);
}
void ULocationRestriction::Stop()
{
Super::Stop();
Player->OnAreaEnter.Remove(AreaEnterHandle);
Player->OnAreaExit.Remove(AreaExitHandle);
}
FText ULocationRestriction::GetDescription() const
{
return FText::Format(RestrictionsLocationDescription,
FFormatNamedArguments
{
{TEXT("LocationName"), TargetLocation->Name}
});
}
void ULocationRestriction::OnAreaEnter(ULocationData* LocationData)
{
if (!IsSuccess && LocationData->Tag.MatchesTag(TargetLocation->Tag))
{
Complete();
}
}
void ULocationRestriction::OnAreaExit(ULocationData* LocationData)
{
if (IsSuccess && LocationData->Tag.MatchesTag(TargetLocation->Tag))
{
Init(Player);
}
}
@@ -0,0 +1,32 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "NakedDesire/MissionBuilder/GoalRestriction.h"
#include "LocationRestriction.generated.h"
class ULocationData;
/**
*
*/
UCLASS()
class NAKEDDESIRE_API ULocationRestriction : public UGoalRestriction
{
GENERATED_BODY()
FDelegateHandle AreaEnterHandle;
FDelegateHandle AreaExitHandle;
UPROPERTY(EditDefaultsOnly)
ULocationData* TargetLocation;
protected:
virtual void Init(ANakedDesireCharacter* PlayerCharacter) override;
virtual void Stop() override;
virtual FText GetDescription() const override;
private:
void OnAreaEnter(ULocationData* LocationData);
void OnAreaExit(ULocationData* LocationData);
};
+24
View File
@@ -0,0 +1,24 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "NPC.h"
#include "GameFramework/CharacterMovementComponent.h"
ANPC::ANPC()
{
PrimaryActorTick.bCanEverTick = false;
GetCharacterMovement()->MaxWalkSpeed = 200.0f;
GetCharacterMovement()->bUseControllerDesiredRotation = true;
GetCharacterMovement()->bOrientRotationToMovement = false;
bUseControllerRotationYaw = false;
AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
}
void ANPC::Destroyed()
{
Super::Destroyed();
OnDestroyed.Broadcast(this);
}
+25
View File
@@ -0,0 +1,25 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "NPC.generated.h"
class ANPC;
DECLARE_MULTICAST_DELEGATE_OneParam(FOnNPCDestroyed, ANPC* NPC);
UCLASS()
class NAKEDDESIRE_API ANPC : public ACharacter
{
GENERATED_BODY()
public:
ANPC();
FOnNPCDestroyed OnDestroyed;
protected:
virtual void Destroyed() override;
};
@@ -0,0 +1,39 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "NPCAIController.h"
#include "NavigationSystem.h"
#include "NPCTargetLocation.h"
#include "AI/NavigationSystemBase.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Global/NakedDesireGameMode.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
void ANPCAIController::SetShouldReactToPlayer(const bool Value)
{
Blackboard->SetValueAsBool(FName(TEXT("ShouldReactToPlayer")), Value);
}
void ANPCAIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
NavigationSystem = FNavigationSystem::GetCurrent<UNavigationSystemV1>(GetWorld());
GameMode = Cast<ANakedDesireGameMode>(UGameplayStatics::GetGameMode(GetWorld()));
RunBehaviorTree(BehaviorTreeAsset);
const FVector SpawnLocation = InPawn->GetActorLocation();
TArray<AActor*> TargetActors;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), ANPCTargetLocation::StaticClass(), TargetActors);
const int RandomIndex = FMath::RandRange(0, TargetActors.Num() - 1);
Blackboard->SetValueAsVector("TargetLocation", TargetActors[RandomIndex]->GetActorLocation());
Blackboard->SetValueAsVector("SpawnLocation", SpawnLocation);
PlayerCharacter = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
Blackboard->SetValueAsObject("Player", PlayerCharacter);
}
+38
View File
@@ -0,0 +1,38 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "DetourCrowdAIController.h"
#include "NPCAIController.generated.h"
class ANakedDesireGameMode;
class UNavigationSystemV1;
class ANakedDesireCharacter;
/**
*
*/
UCLASS()
class NAKEDDESIRE_API ANPCAIController : public ADetourCrowdAIController
{
GENERATED_BODY()
UPROPERTY()
ANakedDesireCharacter* PlayerCharacter = nullptr;
UPROPERTY()
const UNavigationSystemV1* NavigationSystem = nullptr;
UPROPERTY()
ANakedDesireGameMode* GameMode = nullptr;
UPROPERTY(EditDefaultsOnly)
UBehaviorTree* BehaviorTreeAsset = nullptr;
public:
UFUNCTION(BlueprintCallable)
void SetShouldReactToPlayer(bool Value);
protected:
virtual void OnPossess(APawn* InPawn) override;
};
+58
View File
@@ -0,0 +1,58 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "NPCSpawner.h"
#include "NPC.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Global/NakedDesireGameMode.h"
ANPCSpawner::ANPCSpawner()
{
PrimaryActorTick.bCanEverTick = false;
}
void ANPCSpawner::BeginPlay()
{
Super::BeginPlay();
PlayerCharacter = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0);
FTimerHandle TimerHandle;
const int32 RandomDelay = FMath::RandRange(5, 30);
GetWorldTimerManager().SetTimer(TimerHandle, this, &ANPCSpawner::OnTimerTick, 30, true, RandomDelay);
OnTimerTick();
if (AGameModeBase* CurrentGameMode = UGameplayStatics::GetGameMode(GetWorld()))
{
GameMode = Cast<ANakedDesireGameMode>(CurrentGameMode);
}
}
void ANPCSpawner::OnTimerTick()
{
if (!PlayerCharacter || !GameMode)
{
return;
}
const bool IsPlayerClose = FVector::Dist(PlayerCharacter->GetActorLocation(), GetActorLocation()) < 5000;
const FTimecode CurrentTime = GameMode->GetCurrentTime();
const bool IsDay = CurrentTime.Hours >= 9.0f && CurrentTime.Hours < 21.00f;
const bool CanSpawnMore = IsDay ? NPCs.Num() < MaxCountDay : NPCs.Num() < MaxCountNight;
if (CanSpawnMore && PlayerCharacter && IsPlayerClose && (FMath::RandBool() && !AlwaysSpawn))
{
FActorSpawnParameters SpawnParameters;
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
const int RandomIndex = FMath::RandRange(0, NPCClasses.Num() - 1);
ANPC* NewNPC = GetWorld()->SpawnActor<ANPC>(NPCClasses[RandomIndex], GetActorLocation(), GetActorRotation(), SpawnParameters);
NewNPC->OnDestroyed.AddUObject(this, &ANPCSpawner::OnNPCDestroyed);
NPCs.Add(NewNPC);
}
}
void ANPCSpawner::OnNPCDestroyed(ANPC* NPC)
{
NPCs.Remove(NPC);
}
+49
View File
@@ -0,0 +1,49 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "NPCSpawner.generated.h"
class ANakedDesireGameMode;
class ANPC;
UCLASS()
class NAKEDDESIRE_API ANPCSpawner : public AActor
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly)
TArray<TSubclassOf<ANPC>> NPCClasses;
UPROPERTY(EditAnywhere)
bool AlwaysSpawn = false;
UPROPERTY()
ACharacter* PlayerCharacter = nullptr;
bool IsPlayerInRange = false;
UPROPERTY()
ANakedDesireGameMode* GameMode = nullptr;
UPROPERTY()
TArray<ANPC*> NPCs;
UPROPERTY(EditAnywhere, meta = (ClampMin = 1, ClampMax = 30, UIMin = 1, UIMax = 30))
int MaxCountDay = 10;
UPROPERTY(EditAnywhere, meta = (ClampMin = 1, ClampMax = 30, UIMin = 1, UIMax = 30))
int MaxCountNight = 5;
public:
ANPCSpawner();
protected:
virtual void BeginPlay() override;
private:
void OnTimerTick();
void OnNPCDestroyed(ANPC* NPC);
};
@@ -0,0 +1,11 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "NPCTargetLocation.h"
// Sets default values
ANPCTargetLocation::ANPCTargetLocation()
{
PrimaryActorTick.bCanEverTick = false;
}
@@ -0,0 +1,16 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "NPCTargetLocation.generated.h"
UCLASS()
class NAKEDDESIRE_API ANPCTargetLocation : public AActor
{
GENERATED_BODY()
public:
ANPCTargetLocation();
};
+17
View File
@@ -0,0 +1,17 @@
// © 2025 Naked People Team. All Rights Reserved.
using UnrealBuildTool;
public class NakedDesire : ModuleRules
{
public NakedDesire(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[]
{
"Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput", "UMG", "CommonUI", "NavigationSystem",
"AIModule", "GameplayTags"
});
}
}
+7
View File
@@ -0,0 +1,7 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "NakedDesire.h"
#include "Modules/ModuleManager.h"
IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, NakedDesire, "NakedDesire" );
+5
View File
@@ -0,0 +1,5 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
@@ -0,0 +1,450 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "NakedDesireCharacter.h"
#include "NakedDesire/Locations/LocationTrigger.h"
#include "NakedDesire/Clothing/ClothingManager.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "NakedDesire/InteractionSystem/InteractionManager.h"
#include "NakedDesire/InteractionSystem/InteractionTarget.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/Clothing/ClothingItemData.h"
#include "NakedDesire/Global/Constants.h"
#include "NakedDesire/Global/NakedDesireUserSettings.h"
#include "NakedDesire/SaveGame/GlobalSaveGameData.h"
#include "Perception/AIPerceptionStimuliSourceComponent.h"
#include "Perception/AISense_Sight.h"
ANakedDesireCharacter::ANakedDesireCharacter()
{
GetCharacterMovement()->MaxWalkSpeed = WalkSpeed;
GetCapsuleComponent()->OnComponentBeginOverlap.AddUniqueDynamic(this, &ANakedDesireCharacter::OnBeginOverlap);
GetCapsuleComponent()->OnComponentEndOverlap.AddUniqueDynamic(this, &ANakedDesireCharacter::OnEndOverlap);
bUseControllerRotationYaw = false;
GetCharacterMovement()->bOrientRotationToMovement = true;
GetCharacterMovement()->GetNavAgentPropertiesRef().bCanCrouch = true;
ClothingManager = CreateDefaultSubobject<UClothingManager>("Clothing Manager");
StatsManager = CreateDefaultSubobject<UStatsManager>("Stats Manager");
MissionsManager = CreateDefaultSubobject<UMissionsManager>("Missions Manager");
InteractionManager = CreateDefaultSubobject<UInteractionManager>("Interaction Manager");
NipplesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Nipples");
NipplesMeshComponent->SetupAttachment(GetMesh());
AnalMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Anal");
AnalMeshComponent->SetupAttachment(GetMesh());
VaginaMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Vagina");
VaginaMeshComponent->SetupAttachment(GetMesh());
HeadMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Head");
HeadMeshComponent->SetupAttachment(GetMesh());
NeckMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Neck");
NeckMeshComponent->SetupAttachment(GetMesh());
FaceMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Face");
FaceMeshComponent->SetupAttachment(GetMesh());
EyesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Eyes");
EyesMeshComponent->SetupAttachment(GetMesh());
BodyMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Body");
BodyMeshComponent->SetupAttachment(GetMesh());
TopMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Top");
TopMeshComponent->SetupAttachment(GetMesh());
BottomMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Bottom");
BottomMeshComponent->SetupAttachment(GetMesh());
BraMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Bra");
BraMeshComponent->SetupAttachment(GetMesh());
PantiesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Panties");
PantiesMeshComponent->SetupAttachment(GetMesh());
SocksMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Socks");
SocksMeshComponent->SetupAttachment(GetMesh());
ShoesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Shoes");
ShoesMeshComponent->SetupAttachment(GetMesh());
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")));
FrontBottomCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Front Bottom Censorship"));
FrontBottomCensorship->SetupAttachment(GetMesh(), FName(TEXT("pelvis")));
BackBottomCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Back Bottom Censorship"));
BackBottomCensorship->SetupAttachment(GetMesh(), FName(TEXT("pelvis")));
StimuliSourceComponent = CreateDefaultSubobject<UAIPerceptionStimuliSourceComponent>(TEXT("Stimuli Source Component"));
}
EGait ANakedDesireCharacter::GetGait() const
{
return Gait;
}
EStance ANakedDesireCharacter::GetStance() const
{
return Stance;
}
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);
}
}
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();
UGlobalSaveGameData* SaveGameData = UGlobalSaveGameData::LoadOrCreateSaveGame(DefaultPlayerClothing, DefaultWardrobeClothing);
SetupClothingSlots();
ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &ANakedDesireCharacter::OnClothingEquip);
ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &ANakedDesireCharacter::OnClothingUnequip);
UNakedDesireUserSettings::GetNakedDesireUserSettings()->OnSettingsChanged.AddUniqueDynamic(this, &ANakedDesireCharacter::OnSettingsChanged);
ClothingManager->HydrateClothing(SaveGameData);
}
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->IsBodyTypeExposed(EPrivateBodyPartType::FrontTop))
{
UE_LOG(LogTemp, Warning, TEXT("Boobs hit"));
OutSeenLocation = BoobsBoneLocation;
OutSightStrength = 1.0f;
return UAISense_Sight::EVisibilityResult::Visible;
}
if ((!PelvisHit || PelvisHitResult.GetActor() == this) &&
(ClothingManager->IsBodyTypeExposed(EPrivateBodyPartType::BackBottom) || ClothingManager->IsBodyTypeExposed(EPrivateBodyPartType::FrontBottom)))
{
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::OnBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor->Implements<UInteractionTarget>())
{
InteractionManager->OnTargetEnter(OtherActor);
}
if (const ALocationTrigger* AreaTrigger = Cast<ALocationTrigger>(OtherActor))
{
CurrentArea = AreaTrigger->GetLocationData();
OnAreaEnter.Broadcast(CurrentArea);
}
}
void ANakedDesireCharacter::OnEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (OtherActor->Implements<UInteractionTarget>())
{
InteractionManager->OnTargetExit(OtherActor);
}
if (const ALocationTrigger* AreaTrigger = Cast<ALocationTrigger>(OtherActor))
{
CurrentArea = nullptr;
OnAreaExit.Broadcast(AreaTrigger->GetLocationData());
}
}
void ANakedDesireCharacter::OnClothingEquip(const UClothingItemData* ClothingItemData)
{
if (ClothingItemData->Info->CoveredBodyParts.Contains(EPrivateBodyPartType::BackBottom))
{
BackBottomCensorship->SetVisibility(false);
}
if (ClothingItemData->Info->CoveredBodyParts.Contains(EPrivateBodyPartType::FrontBottom))
{
FrontBottomCensorship->SetVisibility(false);
}
if (ClothingItemData->Info->CoveredBodyParts.Contains(EPrivateBodyPartType::FrontTop))
{
BoobLCensorship->SetVisibility(false);
BoobRCensorship->SetVisibility(false);
}
}
void ANakedDesireCharacter::OnClothingUnequip(const UClothingItemData* ClothingItemData)
{
if (!UNakedDesireUserSettings::GetNakedDesireUserSettings()->GetIsCensorshipEnabled() && !IS_DEMO)
{
return;
}
if (ClothingManager->IsBodyTypeExposed(EPrivateBodyPartType::BackBottom))
{
BackBottomCensorship->SetVisibility(true);
}
if (ClothingManager->IsBodyTypeExposed(EPrivateBodyPartType::FrontBottom))
{
FrontBottomCensorship->SetVisibility(true);
}
if (ClothingManager->IsBodyTypeExposed(EPrivateBodyPartType::FrontTop))
{
BoobLCensorship->SetVisibility(true);
BoobRCensorship->SetVisibility(true);
}
}
void ANakedDesireCharacter::OnSettingsChanged(UNakedDesireUserSettings* Settings)
{
if (Settings->GetIsCensorshipEnabled())
{
if (ClothingManager->IsBodyTypeExposed(EPrivateBodyPartType::BackBottom))
{
BackBottomCensorship->SetVisibility(true);
}
if (ClothingManager->IsBodyTypeExposed(EPrivateBodyPartType::FrontBottom))
{
FrontBottomCensorship->SetVisibility(true);
}
if (ClothingManager->IsBodyTypeExposed(EPrivateBodyPartType::FrontTop))
{
BoobLCensorship->SetVisibility(true);
BoobRCensorship->SetVisibility(true);
}
}
else if (!IS_DEMO)
{
BackBottomCensorship->SetVisibility(false);
FrontBottomCensorship->SetVisibility(false);
BoobLCensorship->SetVisibility(false);
BoobRCensorship->SetVisibility(false);
}
}
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::SetupClothingSlots()
{
#define LOCTEXT_NAMESPACE "ClothingSlots"
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
NipplesMeshComponent, EClothingSlotType::Nipples,
nullptr,
LOCTEXT("Nipples", "Nipples")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
AnalMeshComponent, EClothingSlotType::Anal,
nullptr,
LOCTEXT("Anal", "Anal")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
VaginaMeshComponent, EClothingSlotType::Vagina,
nullptr,
LOCTEXT("Vagina", "Vagina")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
HeadMeshComponent, EClothingSlotType::Head,
nullptr,
LOCTEXT("Head", "Head")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
NeckMeshComponent, EClothingSlotType::Neck,
nullptr,
LOCTEXT("Neck", "Neck")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
FaceMeshComponent, EClothingSlotType::Face,
nullptr,
LOCTEXT("Face", "Face")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
EyesMeshComponent, EClothingSlotType::Eyes,
nullptr,
LOCTEXT("Eyes", "Eyes")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
BodyMeshComponent, EClothingSlotType::Body,
nullptr,
LOCTEXT("Body", "Body")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
TopMeshComponent, EClothingSlotType::Top,
nullptr,
LOCTEXT("Top", "Top")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
BottomMeshComponent, EClothingSlotType::Bottom,
nullptr,
LOCTEXT("Bottom", "Bottom")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
BraMeshComponent, EClothingSlotType::Bra,
nullptr,
LOCTEXT("Bra", "Bra")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
PantiesMeshComponent, EClothingSlotType::Panties,
nullptr,
LOCTEXT("Panties", "Panties")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
SocksMeshComponent, EClothingSlotType::Socks,
nullptr,
LOCTEXT("Socks", "Socks")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
ShoesMeshComponent, EClothingSlotType::Shoes,
nullptr,
LOCTEXT("Shoes", "Shoes")));
#undef LOCTEXT_NAMESPACE
}
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;
}
@@ -0,0 +1,197 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InputAction.h"
#include "InputMappingContext.h"
#include "NakedDesire/Global/Gait.h"
#include "NakedDesire/Global/NakedDesireUserSettings.h"
#include "NakedDesire/Global/Stance.h"
#include "Perception/AISightTargetInterface.h"
#include "NakedDesireCharacter.generated.h"
class UAIPerceptionStimuliSourceComponent;
class UClothingItemData;
class UClothingList;
struct FClothingSlotData;
class UInteractionManager;
class UClothingPickerWidget;
class UClothingManager;
class UStatsManager;
class UMissionsManager;
class ANPCAIController;
class ULocationData;
DECLARE_MULTICAST_DELEGATE_OneParam(FOnNoticedSignature, ANPCAIController*);
DECLARE_MULTICAST_DELEGATE_OneParam(FOnAreaChangeSignature, ULocationData*);
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;
// Clothing
UPROPERTY(EditDefaultsOnly, Category = "Clothing Manager|Clothing")
UClothingList* DefaultPlayerClothing = nullptr;
UPROPERTY(EditDefaultsOnly, Category = "Clothing Manager|Clothing")
UClothingList* DefaultWardrobeClothing = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* NipplesMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* AnalMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* VaginaMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* HeadMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* NeckMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* FaceMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* EyesMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* BodyMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* TopMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* BottomMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* BraMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* PantiesMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* SocksMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
USkeletalMeshComponent* ShoesMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
UStaticMeshComponent* BoobLCensorship;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
UStaticMeshComponent* BoobRCensorship;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
UStaticMeshComponent* FrontBottomCensorship;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
UStaticMeshComponent* BackBottomCensorship;
// Components
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
UClothingManager* ClothingManager;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
UStatsManager* StatsManager;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
UMissionsManager* MissionsManager;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
UInteractionManager* InteractionManager;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
UAIPerceptionStimuliSourceComponent* StimuliSourceComponent;
// Variables
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float WalkSpeed = 250.0f;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float RunSpeed = 500.0f;
UPROPERTY(BlueprintReadWrite)
int Money = 300000;
int XP = 0;
UPROPERTY()
ULocationData* CurrentArea = nullptr;
FOnNoticedSignature OnNoticed;
FOnAreaChangeSignature OnAreaEnter;
FOnAreaChangeSignature OnAreaExit;
void NotifyNoticed(ANPCAIController* NPCController);
void SetIsRunning(bool Value);
UFUNCTION(BlueprintPure)
EGait GetGait() const;
UFUNCTION(BlueprintPure)
EStance GetStance() const;
protected:
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;
private:
EGait Gait = EGait::Walk;
EStance Stance = EStance::Stand;
UFUNCTION()
void OnBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void OnEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex);
UFUNCTION()
void OnClothingEquip(const UClothingItemData* ClothingItemData);
UFUNCTION()
void OnClothingUnequip(const UClothingItemData* ClothingItemData);
UFUNCTION()
void OnSettingsChanged(UNakedDesireUserSettings* Settings);
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 SetupClothingSlots();
bool CheckSight(const FVector& StartLocation, const FVector& EndLocation, FHitResult& HitResult, const AActor* IgnoreActor);
};
@@ -0,0 +1,136 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "PlayerCinematic.h"
#include "NakedDesireCharacter.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Clothing/ClothingItemData.h"
#include "NakedDesire/Clothing/ClothingManager.h"
// Sets default values
APlayerCinematic::APlayerCinematic()
{
PrimaryActorTick.bCanEverTick = false;
NipplesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Nipples"));
NipplesMeshComponent->SetupAttachment(GetMesh());
AnalMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Anal"));
AnalMeshComponent->SetupAttachment(GetMesh());
VaginaMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Vagina"));
VaginaMeshComponent->SetupAttachment(GetMesh());
HeadMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Head"));
HeadMeshComponent->SetupAttachment(GetMesh());
NeckMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Neck"));
NeckMeshComponent->SetupAttachment(GetMesh());
FaceMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Face"));
FaceMeshComponent->SetupAttachment(GetMesh());
EyesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Eyes"));
EyesMeshComponent->SetupAttachment(GetMesh());
BodyMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Body"));
BodyMeshComponent->SetupAttachment(GetMesh());
TopMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Top"));
TopMeshComponent->SetupAttachment(GetMesh());
BottomMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Bottom"));
BottomMeshComponent->SetupAttachment(GetMesh());
BraMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Bra"));
BraMeshComponent->SetupAttachment(GetMesh());
PantiesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Panties"));
PantiesMeshComponent->SetupAttachment(GetMesh());
SocksMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Socks"));
SocksMeshComponent->SetupAttachment(GetMesh());
ShoesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Shoes"));
ShoesMeshComponent->SetupAttachment(GetMesh());
}
void APlayerCinematic::BeginPlay()
{
Super::BeginPlay();
Player = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
if (!Player)
{
return;
}
Player->ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &APlayerCinematic::OnClothingEquip);
Player->ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &APlayerCinematic::OnClothingUnequip);
for (const UClothingItemData* ClothingItemData : Player->ClothingManager->GetEquippedClothing())
{
EquipClothing(ClothingItemData);
}
}
void APlayerCinematic::OnClothingEquip(const UClothingItemData* ClothingData)
{
EquipClothing(ClothingData);
}
void APlayerCinematic::OnClothingUnequip(const UClothingItemData* ClothingData)
{
UnequipClothing(ClothingData);
}
USkeletalMeshComponent* APlayerCinematic::GetMeshByType(const EClothingSlotType SlotType) const
{
switch (SlotType)
{
case EClothingSlotType::Nipples:
return NipplesMeshComponent;
case EClothingSlotType::Anal:
return AnalMeshComponent;
case EClothingSlotType::Vagina:
return VaginaMeshComponent;
case EClothingSlotType::Head:
return HeadMeshComponent;
case EClothingSlotType::Neck:
return NeckMeshComponent;
case EClothingSlotType::Face:
return FaceMeshComponent;
case EClothingSlotType::Eyes:
return EyesMeshComponent;
case EClothingSlotType::Body:
return BodyMeshComponent;
case EClothingSlotType::Top:
return TopMeshComponent;
case EClothingSlotType::Bottom:
return BottomMeshComponent;
case EClothingSlotType::Bra:
return BraMeshComponent;
case EClothingSlotType::Panties:
return PantiesMeshComponent;
case EClothingSlotType::Socks:
return SocksMeshComponent;
case EClothingSlotType::Shoes:
return ShoesMeshComponent;
default:
return NipplesMeshComponent;
}
}
void APlayerCinematic::EquipClothing(const UClothingItemData* ClothingData)
{
USkeletalMeshComponent* MeshComponent = GetMeshByType(ClothingData->Info->SlotType);
MeshComponent->SetSkeletalMesh(ClothingData->Info->SkeletalMesh);
if (ClothingData->Info->UseLeaderPose)
{
MeshComponent->SetLeaderPoseComponent(GetMesh());
}
if (!ClothingData->Info->Materials.IsEmpty())
{
for (const TPair<FName, UMaterialInstance*>& Material : ClothingData->Info->Materials)
{
MeshComponent->SetMaterialByName(Material.Key, Material.Value);
}
}
}
void APlayerCinematic::UnequipClothing(const UClothingItemData* ClothingData)
{
USkeletalMeshComponent* MeshComponent = GetMeshByType(ClothingData->Info->SlotType);
MeshComponent->SetSkeletalMesh(nullptr);
MeshComponent->SetLeaderPoseComponent(nullptr);
}
@@ -0,0 +1,79 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "NakedDesire/Clothing/ClothingSlotType.h"
#include "PlayerCinematic.generated.h"
class UClothingItemData;
class ANakedDesireCharacter;
UCLASS()
class NAKEDDESIRE_API APlayerCinematic : public ACharacter
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* NipplesMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* AnalMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* VaginaMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* HeadMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* NeckMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* FaceMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* EyesMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* BodyMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* TopMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* BottomMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* BraMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* PantiesMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* SocksMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* ShoesMeshComponent;
UPROPERTY()
ANakedDesireCharacter* Player;
public:
APlayerCinematic();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnClothingEquip(const UClothingItemData* ClothingData);
UFUNCTION()
void OnClothingUnequip(const UClothingItemData* ClothingData);
USkeletalMeshComponent* GetMeshByType(const EClothingSlotType SlotType) const;
void EquipClothing(const UClothingItemData* ClothingData);
void UnequipClothing(const UClothingItemData* ClothingData);
};
@@ -0,0 +1,140 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "PlayerImpostor.h"
#include "NakedDesireCharacter.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Clothing/ClothingManager.h"
APlayerImpostor::APlayerImpostor()
{
PrimaryActorTick.bCanEverTick = false;
RootSceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
SetRootComponent(RootSceneComponent);
Mesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("RootMesh"));
Mesh->SetupAttachment(RootComponent);
NipplesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Nipples"));
NipplesMeshComponent->SetupAttachment(GetMesh());
AnalMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Anal"));
AnalMeshComponent->SetupAttachment(GetMesh());
VaginaMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Vagina"));
VaginaMeshComponent->SetupAttachment(GetMesh());
HeadMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Head"));
HeadMeshComponent->SetupAttachment(GetMesh());
NeckMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Neck"));
NeckMeshComponent->SetupAttachment(GetMesh());
FaceMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Face"));
FaceMeshComponent->SetupAttachment(GetMesh());
EyesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Eyes"));
EyesMeshComponent->SetupAttachment(GetMesh());
BodyMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Body"));
BodyMeshComponent->SetupAttachment(GetMesh());
TopMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Top"));
TopMeshComponent->SetupAttachment(GetMesh());
BottomMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Bottom"));
BottomMeshComponent->SetupAttachment(GetMesh());
BraMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Bra"));
BraMeshComponent->SetupAttachment(GetMesh());
PantiesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Panties"));
PantiesMeshComponent->SetupAttachment(GetMesh());
SocksMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Socks"));
SocksMeshComponent->SetupAttachment(GetMesh());
ShoesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Shoes"));
ShoesMeshComponent->SetupAttachment(GetMesh());
}
void APlayerImpostor::OnClothingEquip(const UClothingItemData* ClothingData)
{
EquipClothing(ClothingData);
}
void APlayerImpostor::OnClothingUnequip(const UClothingItemData* ClothingData)
{
UnequipClothing(ClothingData);
}
void APlayerImpostor::BeginPlay()
{
Super::BeginPlay();
Player = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
if (!Player)
{
return;
}
Player->ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &APlayerImpostor::OnClothingEquip);
Player->ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &APlayerImpostor::OnClothingUnequip);
for (const UClothingItemData* ClothingItemData : Player->ClothingManager->GetEquippedClothing())
{
EquipClothing(ClothingItemData);
}
}
USkeletalMeshComponent* APlayerImpostor::GetMeshByType(const EClothingSlotType SlotType) const
{
switch (SlotType)
{
case EClothingSlotType::Nipples:
return NipplesMeshComponent;
case EClothingSlotType::Anal:
return AnalMeshComponent;
case EClothingSlotType::Vagina:
return VaginaMeshComponent;
case EClothingSlotType::Head:
return HeadMeshComponent;
case EClothingSlotType::Neck:
return NeckMeshComponent;
case EClothingSlotType::Face:
return FaceMeshComponent;
case EClothingSlotType::Eyes:
return EyesMeshComponent;
case EClothingSlotType::Body:
return BodyMeshComponent;
case EClothingSlotType::Top:
return TopMeshComponent;
case EClothingSlotType::Bottom:
return BottomMeshComponent;
case EClothingSlotType::Bra:
return BraMeshComponent;
case EClothingSlotType::Panties:
return PantiesMeshComponent;
case EClothingSlotType::Socks:
return SocksMeshComponent;
case EClothingSlotType::Shoes:
return ShoesMeshComponent;
default:
return NipplesMeshComponent;
}
}
void APlayerImpostor::EquipClothing(const UClothingItemData* ClothingData)
{
USkeletalMeshComponent* MeshComponent = GetMeshByType(ClothingData->Info->SlotType);
MeshComponent->SetSkeletalMesh(ClothingData->Info->SkeletalMesh);
if (ClothingData->Info->UseLeaderPose)
{
MeshComponent->SetLeaderPoseComponent(GetMesh());
}
if (!ClothingData->Info->Materials.IsEmpty())
{
for (const TPair<FName, UMaterialInstance*>& Material : ClothingData->Info->Materials)
{
MeshComponent->SetMaterialByName(Material.Key, Material.Value);
}
}
}
void APlayerImpostor::UnequipClothing(const UClothingItemData* ClothingData)
{
USkeletalMeshComponent* MeshComponent = GetMeshByType(ClothingData->Info->SlotType);
MeshComponent->SetSkeletalMesh(nullptr);
MeshComponent->SetLeaderPoseComponent(nullptr);
}
@@ -0,0 +1,86 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "NakedDesire/Clothing/ClothingItemData.h"
#include "NakedDesire/Clothing/ClothingSlotType.h"
#include "PlayerImpostor.generated.h"
class ANakedDesireCharacter;
UCLASS()
class NAKEDDESIRE_API APlayerImpostor : public APawn
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true))
USceneComponent* RootSceneComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true))
USkeletalMeshComponent* Mesh;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* NipplesMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* AnalMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* VaginaMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* HeadMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* NeckMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* FaceMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* EyesMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* BodyMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* TopMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* BottomMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* BraMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* PantiesMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* SocksMeshComponent;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
USkeletalMeshComponent* ShoesMeshComponent;
UPROPERTY()
ANakedDesireCharacter* Player;
public:
APlayerImpostor();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnClothingEquip(const UClothingItemData* ClothingData);
UFUNCTION()
void OnClothingUnequip(const UClothingItemData* ClothingData);
USkeletalMeshComponent* GetMesh() const { return Mesh; };
USkeletalMeshComponent* GetMeshByType(const EClothingSlotType SlotType) const;
void EquipClothing(const UClothingItemData* ClothingData);
void UnequipClothing(const UClothingItemData* ClothingData);
};
@@ -0,0 +1,42 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "PrivateBodyPartType.generated.h"
#define LOCTEXT_NAMESPACE "Missions.BodyType"
const FText BackBottom = LOCTEXT("BackBottom", "back bottom");
const FText FrontBottom = LOCTEXT("FrontBottom", "front bottom");
const FText FrontTop = LOCTEXT("FrontTop", "front top");
#undef LOCTEXT_NAMESPACE
UENUM(BlueprintType)
enum class EPrivateBodyPartType : uint8
{
FrontBottom = 0,
BackBottom = 1,
FrontTop = 2
};
UCLASS()
class UPrivateBodyPartType : public UObject
{
GENERATED_BODY()
public:
static FText GetString(const EPrivateBodyPartType BodyType)
{
switch (BodyType)
{
case EPrivateBodyPartType::BackBottom:
return BackBottom;
case EPrivateBodyPartType::FrontBottom:
return FrontBottom;
case EPrivateBodyPartType::FrontTop:
return FrontTop;
default:
return FText::GetEmpty();
}
}
};
@@ -0,0 +1,20 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "ClothingItemSaveData.generated.h"
class UClothingItem;
/**
*
*/
USTRUCT(BlueprintType)
struct FClothingItemSaveData
{
GENERATED_BODY()
UPROPERTY()
TSoftObjectPtr<UClothingItem> ClothingItem;
};
@@ -0,0 +1,67 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "GlobalSaveGameData.h"
#include "NakedDesire/Global/Constants.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Clothing/ClothingItemData.h"
#include "NakedDesire/Clothing/ClothingList.h"
UGlobalSaveGameData* UGlobalSaveGameData::CreateNewSaveGame(TArray<UClothingItemData*> CurrentWardrobeClothing, TArray<UClothingItemData*> CurrentPlayerClothing)
{
UGlobalSaveGameData* NewSave = Cast<UGlobalSaveGameData>(
UGameplayStatics::CreateSaveGameObject(UGlobalSaveGameData::StaticClass())
);
if (!NewSave)
{
return nullptr;
}
for (const UClothingItemData* Item : CurrentWardrobeClothing)
{
NewSave->WardrobeClothing.Add(Item->ToSaveData());
}
for (const UClothingItemData* Item : CurrentPlayerClothing)
{
NewSave->PlayerClothing.Add(Item->ToSaveData());
}
return NewSave;
}
UGlobalSaveGameData* UGlobalSaveGameData::LoadOrCreateSaveGame(UClothingList* DefaultPlayerClothing, UClothingList* DefaultWardrobeClothing)
{
if (UGameplayStatics::DoesSaveGameExist(SLOT_NAME, SLOT_PLAYER))
{
return Cast<UGlobalSaveGameData>(
UGameplayStatics::LoadGameFromSlot(SLOT_NAME, SLOT_PLAYER)
);
}
UGlobalSaveGameData* NewSave = nullptr;
if (DefaultWardrobeClothing && DefaultPlayerClothing)
{
NewSave = CreateNewSaveGame(DefaultWardrobeClothing->ClothingItems, DefaultPlayerClothing->ClothingItems);
}
if (NewSave)
{
UGameplayStatics::SaveGameToSlot(NewSave, SLOT_NAME, SLOT_PLAYER);
}
return NewSave;
}
bool UGlobalSaveGameData::SaveGame(const TArray<UClothingItemData*> CurrentWardrobeClothing,
const TArray<UClothingItemData*> CurrentPlayerClothing)
{
if (UGlobalSaveGameData* SaveGame = CreateNewSaveGame(CurrentWardrobeClothing, CurrentPlayerClothing))
{
return UGameplayStatics::SaveGameToSlot(SaveGame, SLOT_NAME, SLOT_PLAYER);
}
return false;
}
@@ -0,0 +1,41 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ClothingItemSaveData.h"
#include "GameFramework/SaveGame.h"
#include "GlobalSaveGameData.generated.h"
class UClothingList;
class UClothingItemData;
/**
*
*/
UCLASS()
class NAKEDDESIRE_API UGlobalSaveGameData : public USaveGame
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, SaveGame)
bool HaveSeenTutorial = false;
UPROPERTY(BlueprintReadWrite, SaveGame)
float Money = 0;
UPROPERTY(BlueprintReadWrite)
TArray<FClothingItemSaveData> WardrobeClothing;
UPROPERTY(BlueprintReadWrite)
TArray<FClothingItemSaveData> PlayerClothing;
UFUNCTION(BlueprintCallable)
static UGlobalSaveGameData* LoadOrCreateSaveGame(UClothingList* DefaultPlayerClothing, UClothingList* DefaultWardrobeClothing);
UFUNCTION(BlueprintCallable)
static bool SaveGame(TArray<UClothingItemData*> CurrentWardrobeClothing, TArray<UClothingItemData*> CurrentPlayerClothing);
private:
static UGlobalSaveGameData* CreateNewSaveGame(TArray<UClothingItemData*> CurrentWardrobeClothing, TArray<UClothingItemData*> CurrentPlayerClothing);
};
+70
View File
@@ -0,0 +1,70 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "StatsManager.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Global/NakedDesireGameMode.h"
UStatsManager::UStatsManager()
{
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.TickInterval = 1.0f;
}
void UStatsManager::BeginPlay()
{
Super::BeginPlay();
EmbarrassmentUpdate.Broadcast(Embarrassment, MaxEmbarrassment);
StaminaUpdate.Broadcast(Stamina, MaxStamina);
EnergyUpdate.Broadcast(Energy, MaxEnergy);
}
void UStatsManager::TickComponent(float DeltaTime, enum ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction)
{
DecreaseEnergy(0.9f);
DecreaseEmbarrassment(1.0f);
}
void UStatsManager::IncreaseEmbarrassment(const float Amount)
{
Embarrassment = FMath::Clamp(Embarrassment + Amount, 0, MaxEmbarrassment);
EmbarrassmentUpdate.Broadcast(Embarrassment, MaxEmbarrassment);
if (Embarrassment == MaxEmbarrassment)
{
ANakedDesireGameMode* GameMode = Cast<ANakedDesireGameMode>(UGameplayStatics::GetGameMode(this));
GameMode->EndGameEmbarrassed();
}
}
void UStatsManager::DecreaseEmbarrassment(const float Amount)
{
Embarrassment = FMath::Clamp(Embarrassment - Amount, 0, MaxEmbarrassment);
EmbarrassmentUpdate.Broadcast(Embarrassment, MaxEmbarrassment);
}
void UStatsManager::DecreaseStamina(const float Amount)
{
Stamina = FMath::Clamp(Stamina - Amount, 0, MaxStamina);
StaminaUpdate.Broadcast(Stamina, MaxStamina);
}
void UStatsManager::IncreaseStamina(const float Amount)
{
Stamina = FMath::Clamp(Stamina + Amount, 0, MaxStamina);
StaminaUpdate.Broadcast(Stamina, MaxStamina);
}
void UStatsManager::DecreaseEnergy(const float Amount)
{
Energy = FMath::Clamp(Energy - Amount, 0, MaxEnergy);
EnergyUpdate.Broadcast(Energy, MaxEnergy);
}
void UStatsManager::RestoreEnergy()
{
Energy = MaxEnergy;
EnergyUpdate.Broadcast(Energy, MaxEnergy);
}
+49
View File
@@ -0,0 +1,49 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "StatsManager.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FAttributeUpdateSignature, float, CurrentValue, float, MaxValue);
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class NAKEDDESIRE_API UStatsManager : public UActorComponent
{
GENERATED_BODY()
float Embarrassment = 0.0f;
float MaxEmbarrassment = 100.0f;
float Energy = 1000.0f;
float MaxEnergy = 1000.0f;
public:
UStatsManager();
protected:
virtual void BeginPlay() override;
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
public:
float Stamina = 100.0f;
float MaxStamina = 100.0f;
UFUNCTION(BlueprintCallable)
void IncreaseEmbarrassment(float Amount);
void DecreaseEmbarrassment(float Amount);
void DecreaseStamina(float Amount);
void IncreaseStamina(float Amount);
void DecreaseEnergy(float Amount);
void RestoreEnergy();
UPROPERTY(BlueprintAssignable)
FAttributeUpdateSignature EmbarrassmentUpdate;
UPROPERTY(BlueprintAssignable)
FAttributeUpdateSignature StaminaUpdate;
UPROPERTY(BlueprintAssignable)
FAttributeUpdateSignature EnergyUpdate;
};
+15
View File
@@ -0,0 +1,15 @@
// © 2025 Naked People Team. All Rights Reserved.
using UnrealBuildTool;
using System.Collections.Generic;
public class NakedDesireEditorTarget : TargetRules
{
public NakedDesireEditorTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Editor;
DefaultBuildSettings = BuildSettingsVersion.V6;
IncludeOrderVersion = EngineIncludeOrderVersion.Latest;
ExtraModuleNames.Add("NakedDesire");
}
}