Added wardrobe

This commit is contained in:
2026-05-31 21:00:55 +03:00
parent 3f51679553
commit 80be766e2c
39 changed files with 787 additions and 111 deletions
@@ -0,0 +1,73 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "EquipmentPanelWidget.h"
#include "EquipmentSlotWidget.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Clothing/ClothingManager.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
void UEquipmentPanelWidget::NativeConstruct()
{
Super::NativeConstruct();
InitSlotTypes();
const ANakedDesireCharacter* Player = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
const TArray<UEquipmentSlotWidget*> AllSlots = {
NipplesSlot, AnalSlot, VaginaSlot,
HeadSlot, NeckSlot, FaceSlot, EyesSlot,
BodysuitSlot, TopSlot, BottomSlot,
UnderwearTopSlot, UnderwearBottomSlot,
SocksSlot, FootwearSlot, OuterwearSlot,
WristRestraintSlot, AnkleRestraintSlot, NeckRestraintSlot
};
for (UEquipmentSlotWidget* SlotWidget : AllSlots)
{
if (SlotWidget)
{
SlotWidget->OnEquipmentSlotClicked.BindUObject(this, &UEquipmentPanelWidget::HandleSlotClicked);
if (UClothingItemInstance* Item = Player->ClothingManager->GetSlotClothing(SlotWidget->GetSlotType()))
SlotWidget->SetItem(Item);
else
SlotWidget->ClearItem();
}
}
}
void UEquipmentPanelWidget::NativePreConstruct()
{
Super::NativePreConstruct();
InitSlotTypes();
}
void UEquipmentPanelWidget::HandleSlotClicked(UEquipmentSlotWidget* SlotWidget)
{
OnSlotClicked.ExecuteIfBound(SlotWidget);
}
void UEquipmentPanelWidget::InitSlotTypes()
{
if (NipplesSlot) NipplesSlot->SetSlotType(EClothingSlotType::Nipples);
if (AnalSlot) AnalSlot->SetSlotType(EClothingSlotType::Anal);
if (VaginaSlot) VaginaSlot->SetSlotType(EClothingSlotType::Vagina);
if (HeadSlot) HeadSlot->SetSlotType(EClothingSlotType::Head);
if (NeckSlot) NeckSlot->SetSlotType(EClothingSlotType::Neck);
if (FaceSlot) FaceSlot->SetSlotType(EClothingSlotType::Face);
if (EyesSlot) EyesSlot->SetSlotType(EClothingSlotType::Eyes);
if (BodysuitSlot) BodysuitSlot->SetSlotType(EClothingSlotType::Bodysuit);
if (TopSlot) TopSlot->SetSlotType(EClothingSlotType::Top);
if (BottomSlot) BottomSlot->SetSlotType(EClothingSlotType::Bottom);
if (UnderwearTopSlot) UnderwearTopSlot->SetSlotType(EClothingSlotType::UnderwearTop);
if (UnderwearBottomSlot) UnderwearBottomSlot->SetSlotType(EClothingSlotType::UnderwearBottom);
if (SocksSlot) SocksSlot->SetSlotType(EClothingSlotType::Socks);
if (FootwearSlot) FootwearSlot->SetSlotType(EClothingSlotType::Footwear);
if (OuterwearSlot) OuterwearSlot->SetSlotType(EClothingSlotType::Outerwear);
if (WristRestraintSlot) WristRestraintSlot->SetSlotType(EClothingSlotType::WristRestraint);
if (AnkleRestraintSlot) AnkleRestraintSlot->SetSlotType(EClothingSlotType::AnkleRestraint);
if (NeckRestraintSlot) NeckRestraintSlot->SetSlotType(EClothingSlotType::NeckRestraint);
}
@@ -0,0 +1,81 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "CommonUserWidget.h"
#include "EquipmentPanelWidget.generated.h"
class UEquipmentSlotWidget;
UCLASS(Abstract)
class NAKEDDESIRE_API UEquipmentPanelWidget : public UCommonUserWidget
{
GENERATED_BODY()
public:
DECLARE_DELEGATE_OneParam(FOnSlotClicked, UEquipmentSlotWidget*);
FOnSlotClicked OnSlotClicked;
protected:
virtual void NativeConstruct() override;
virtual void NativePreConstruct() override;
private:
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> NipplesSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> AnalSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> VaginaSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> HeadSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> NeckSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> FaceSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> EyesSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> BodysuitSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> TopSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> BottomSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> UnderwearTopSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> UnderwearBottomSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> SocksSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> FootwearSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> OuterwearSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> WristRestraintSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> AnkleRestraintSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> NeckRestraintSlot;
void HandleSlotClicked(UEquipmentSlotWidget* SlotWidget);
void InitSlotTypes();
};
@@ -0,0 +1,48 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "EquipmentSlotMenuWidget.h"
#include "Components/Button.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Clothing/ClothingItemInstance.h"
#include "NakedDesire/Clothing/ClothingManager.h"
#include "NakedDesire/Inventory/InventorySubsystem.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
void UEquipmentSlotMenuWidget::Init(const EClothingSlotType InSlotType, const bool bInAtWardrobe)
{
SlotType = InSlotType;
bAtWardrobe = bInAtWardrobe;
}
void UEquipmentSlotMenuWidget::NativeConstruct()
{
Super::NativeConstruct();
Player = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
RemoveClothingBtn->OnClicked.AddUniqueDynamic(this, &UEquipmentSlotMenuWidget::OnRemoveClothingClicked);
}
void UEquipmentSlotMenuWidget::OnRemoveClothingClicked()
{
if (Player && Player->ClothingManager)
{
if (bAtWardrobe)
{
// At the wardrobe the garment is stored, not dropped on the ground.
if (UClothingItemInstance* Equipped = Player->ClothingManager->GetSlotClothing(SlotType))
{
if (UInventorySubsystem* Inventory = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<UInventorySubsystem>())
Inventory->UnequipToWardrobe(Equipped);
}
}
else
{
Player->ClothingManager->DropClothing(SlotType);
}
}
OnActionPerformed.Broadcast();
}
@@ -0,0 +1,44 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "CommonUserWidget.h"
#include "NakedDesire/Clothing/ClothingSlotType.h"
#include "EquipmentSlotMenuWidget.generated.h"
class ANakedDesireCharacter;
class UButton;
UCLASS(Abstract)
class NAKEDDESIRE_API UEquipmentSlotMenuWidget : public UCommonUserWidget
{
GENERATED_BODY()
public:
// bInAtWardrobe makes Remove store the garment in the wardrobe instead of dropping it (§6.5).
void Init(EClothingSlotType InSlotType, bool bInAtWardrobe = false);
EClothingSlotType GetSlotType() const { return SlotType; }
DECLARE_MULTICAST_DELEGATE(FOnActionPerformed);
FOnActionPerformed OnActionPerformed;
protected:
virtual void NativeConstruct() override;
private:
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> RemoveClothingBtn;
UPROPERTY()
TObjectPtr<ANakedDesireCharacter> Player;
UPROPERTY()
EClothingSlotType SlotType;
bool bAtWardrobe = false;
UFUNCTION()
void OnRemoveClothingClicked();
};
@@ -0,0 +1,86 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "EquipmentSlotWidget.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Clothing/ClothingItemDefinition.h"
#include "NakedDesire/Clothing/ClothingItemInstance.h"
#include "NakedDesire/Clothing/ClothingManager.h"
#include "NakedDesire/Clothing/ClothingSlotsData.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
void UEquipmentSlotWidget::SetItem(UClothingItemInstance* InItem)
{
ClothingItemInstance = InItem;
IconImage->SetBrushFromTexture(InItem->GetClothingItemDefinition()->Icon);
IconImage->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
PlaceholderImage->SetVisibility(ESlateVisibility::Hidden);
SetIsEnabled(true);
}
void UEquipmentSlotWidget::ClearItem()
{
ClothingItemInstance = nullptr;
IconImage->SetBrushFromTexture(nullptr);
IconImage->SetVisibility(ESlateVisibility::Hidden);
PlaceholderImage->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
SetIsEnabled(false);
}
void UEquipmentSlotWidget::NativeOnClicked()
{
Super::NativeOnClicked();
OnEquipmentSlotClicked.ExecuteIfBound(this);
}
void UEquipmentSlotWidget::NativePreConstruct()
{
Super::NativePreConstruct();
InitSlotVisuals();
}
void UEquipmentSlotWidget::OnClothingEquip(UClothingItemInstance* InClothingItemInstance)
{
if (InClothingItemInstance->GetClothingItemDefinition()->SlotType != SlotType)
return;
SetItem(InClothingItemInstance);
}
void UEquipmentSlotWidget::OnClothingUnequip(UClothingItemInstance* InClothingItemInstance)
{
if (InClothingItemInstance->GetClothingItemDefinition()->SlotType != SlotType)
return;
ClearItem();
}
void UEquipmentSlotWidget::InitSlotVisuals()
{
if (!ClothingSlotsData)
return;
const FClothingSlotData& SlotData = ClothingSlotsData->Slots[SlotType];
PlaceholderImage->SetBrushFromTexture(SlotData.Icon);
}
void UEquipmentSlotWidget::SetSlotType(const EClothingSlotType InSlotType)
{
SlotType = InSlotType;
InitSlotVisuals();
}
void UEquipmentSlotWidget::NativeConstruct()
{
Super::NativeConstruct();
const ANakedDesireCharacter* Player = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
Player->ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &UEquipmentSlotWidget::OnClothingEquip);
Player->ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &UEquipmentSlotWidget::OnClothingUnequip);
}
@@ -0,0 +1,60 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "CommonButtonBase.h"
#include "Components/Image.h"
#include "NakedDesire/Clothing/ClothingSlotType.h"
#include "EquipmentSlotWidget.generated.h"
class UEquipmentSlotMenuWidget;
class ANakedDesireCharacter;
class UClothingSlotsData;
class UClothingItemInstance;
UCLASS(Abstract)
class NAKEDDESIRE_API UEquipmentSlotWidget : public UCommonButtonBase
{
GENERATED_BODY()
public:
void SetItem(UClothingItemInstance* InItem);
void ClearItem();
EClothingSlotType GetSlotType() const { return SlotType; }
void SetSlotType(EClothingSlotType InSlotType);
virtual void NativeConstruct() override;
DECLARE_DELEGATE_OneParam(FOnEquipmentSlotClicked, UEquipmentSlotWidget* EquipmentSLotWidget)
FOnEquipmentSlotClicked OnEquipmentSlotClicked;
protected:
virtual void NativeOnClicked() override;
virtual void NativePreConstruct() override;
UPROPERTY(EditDefaultsOnly)
TObjectPtr<UClothingSlotsData> ClothingSlotsData;
private:
UPROPERTY(meta = (BindWIdget))
TObjectPtr<UImage> PlaceholderImage;
UPROPERTY(meta = (BindWIdget))
TObjectPtr<UImage> IconImage;
UPROPERTY()
TObjectPtr<UClothingItemInstance> ClothingItemInstance = nullptr;
UPROPERTY()
EClothingSlotType SlotType = EClothingSlotType::Anal;
UFUNCTION()
void OnClothingEquip(UClothingItemInstance* InClothingItemInstance);
UFUNCTION()
void OnClothingUnequip(UClothingItemInstance* InClothingItemInstance);
void InitSlotVisuals();
};