init
This commit is contained in:
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
@@ -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"
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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" );
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user