Added wardrobe
This commit is contained in:
@@ -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();
|
||||
}
|
||||
+8
-5
@@ -14,9 +14,10 @@ UCLASS(Abstract)
|
||||
class NAKEDDESIRE_API UEquipmentSlotMenuWidget : public UCommonUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
|
||||
public:
|
||||
void Init(EClothingSlotType InSlotType);
|
||||
// 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; }
|
||||
|
||||
@@ -28,7 +29,7 @@ protected:
|
||||
|
||||
private:
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
TObjectPtr<UButton> DropClothingBtn;
|
||||
TObjectPtr<UButton> RemoveClothingBtn;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<ANakedDesireCharacter> Player;
|
||||
@@ -36,6 +37,8 @@ private:
|
||||
UPROPERTY()
|
||||
EClothingSlotType SlotType;
|
||||
|
||||
bool bAtWardrobe = false;
|
||||
|
||||
UFUNCTION()
|
||||
void OnDropClothingClicked();
|
||||
};
|
||||
void OnRemoveClothingClicked();
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "EquipmentSlotMenuWidget.h"
|
||||
|
||||
#include "Components/Button.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "NakedDesire/Clothing/ClothingManager.h"
|
||||
#include "NakedDesire/Player/NakedDesireCharacter.h"
|
||||
|
||||
void UEquipmentSlotMenuWidget::Init(const EClothingSlotType InSlotType)
|
||||
{
|
||||
SlotType = InSlotType;
|
||||
}
|
||||
|
||||
void UEquipmentSlotMenuWidget::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
|
||||
Player = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
|
||||
|
||||
DropClothingBtn->OnClicked.AddUniqueDynamic(this, &UEquipmentSlotMenuWidget::OnDropClothingClicked);
|
||||
}
|
||||
|
||||
void UEquipmentSlotMenuWidget::OnDropClothingClicked()
|
||||
{
|
||||
Player->ClothingManager->DropClothing(SlotType);
|
||||
OnActionPerformed.Broadcast();
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
#include "Components/Button.h"
|
||||
#include "Components/CanvasPanel.h"
|
||||
#include "Components/CanvasPanelSlot.h"
|
||||
#include "EquipmentPanelWidget.h"
|
||||
#include "EquipmentSlotMenuWidget.h"
|
||||
#include "EquipmentSlotWidget.h"
|
||||
#include "Equipment/EquipmentPanelWidget.h"
|
||||
#include "Equipment/EquipmentSlotMenuWidget.h"
|
||||
#include "Equipment/EquipmentSlotWidget.h"
|
||||
#include "NakedDesire/Global/PlayerPreviewCaptureSubsystem.h"
|
||||
|
||||
void UInventoryScreenWidget::NativeOnActivated()
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "WardrobeInventoryWidget.h"
|
||||
#include "Components/VerticalBox.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
||||
#include "NakedDesire/Inventory/InventorySubsystem.h"
|
||||
#include "WardrobeItemWidget.h"
|
||||
|
||||
void UWardrobeInventoryWidget::Init()
|
||||
{
|
||||
if (UInventorySubsystem* Inventory = GetInventory())
|
||||
Inventory->OnWardrobeChanged.AddUniqueDynamic(this, &UWardrobeInventoryWidget::HandleWardrobeChanged);
|
||||
|
||||
RenderItems();
|
||||
}
|
||||
|
||||
void UWardrobeInventoryWidget::NativeDestruct()
|
||||
{
|
||||
if (UInventorySubsystem* Inventory = GetInventory())
|
||||
Inventory->OnWardrobeChanged.RemoveDynamic(this, &UWardrobeInventoryWidget::HandleWardrobeChanged);
|
||||
|
||||
Super::NativeDestruct();
|
||||
}
|
||||
|
||||
UInventorySubsystem* UWardrobeInventoryWidget::GetInventory() const
|
||||
{
|
||||
UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(GetWorld());
|
||||
return GameInstance ? GameInstance->GetSubsystem<UInventorySubsystem>() : nullptr;
|
||||
}
|
||||
|
||||
void UWardrobeInventoryWidget::HandleWardrobeChanged()
|
||||
{
|
||||
RenderItems();
|
||||
}
|
||||
|
||||
void UWardrobeInventoryWidget::HandleItemClicked(UWardrobeItemWidget* ItemWidget)
|
||||
{
|
||||
if (!ItemWidget)
|
||||
return;
|
||||
|
||||
if (UInventorySubsystem* Inventory = GetInventory())
|
||||
Inventory->EquipFromWardrobe(ItemWidget->GetClothingItemInstance());
|
||||
}
|
||||
|
||||
void UWardrobeInventoryWidget::RenderItems()
|
||||
{
|
||||
if (!ItemsList || !WardrobeItemWidgetClass)
|
||||
return;
|
||||
|
||||
UInventorySubsystem* Inventory = GetInventory();
|
||||
if (!Inventory)
|
||||
return;
|
||||
|
||||
ItemsList->ClearChildren();
|
||||
|
||||
for (UItemInstance* Item : Inventory->GetWardrobeItems())
|
||||
{
|
||||
// Wardrobe holds any UItemInstance (phones / toys land here too, §6.5 / §9.9); the
|
||||
// clothing widget only renders clothing for now — other types get their own widgets later.
|
||||
UClothingItemInstance* Clothing = Cast<UClothingItemInstance>(Item);
|
||||
if (!Clothing)
|
||||
continue;
|
||||
|
||||
UWardrobeItemWidget* NewItemWidget = CreateWidget<UWardrobeItemWidget>(this, WardrobeItemWidgetClass);
|
||||
NewItemWidget->SetClothingItemInstance(Clothing);
|
||||
NewItemWidget->OnItemClicked.BindUObject(this, &UWardrobeInventoryWidget::HandleItemClicked);
|
||||
ItemsList->AddChild(NewItemWidget);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CommonUserWidget.h"
|
||||
#include "WardrobeInventoryWidget.generated.h"
|
||||
|
||||
class UVerticalBox;
|
||||
class UWardrobeItemWidget;
|
||||
class UInventorySubsystem;
|
||||
|
||||
UCLASS(Abstract)
|
||||
class NAKEDDESIRE_API UWardrobeInventoryWidget : public UCommonUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TSubclassOf<UWardrobeItemWidget> WardrobeItemWidgetClass;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
TObjectPtr<UVerticalBox> ItemsList;
|
||||
|
||||
public:
|
||||
void Init();
|
||||
|
||||
protected:
|
||||
virtual void NativeDestruct() override;
|
||||
|
||||
private:
|
||||
UInventorySubsystem* GetInventory() const;
|
||||
|
||||
UFUNCTION()
|
||||
void HandleWardrobeChanged();
|
||||
|
||||
void HandleItemClicked(UWardrobeItemWidget* ItemWidget);
|
||||
void RenderItems();
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "WardrobeItemWidget.h"
|
||||
#include "CommonTextBlock.h"
|
||||
#include "Components/Image.h"
|
||||
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
||||
|
||||
void UWardrobeItemWidget::SetClothingItemInstance(UClothingItemInstance* InItemInstance)
|
||||
{
|
||||
ClothingItemInstance = InItemInstance;
|
||||
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
void UWardrobeItemWidget::NativeOnClicked()
|
||||
{
|
||||
Super::NativeOnClicked();
|
||||
|
||||
OnItemClicked.ExecuteIfBound(this);
|
||||
}
|
||||
|
||||
void UWardrobeItemWidget::UpdateVisuals()
|
||||
{
|
||||
if (!ClothingItemInstance)
|
||||
return;
|
||||
|
||||
IconImage->SetBrushFromTexture(ClothingItemInstance->GetClothingItemDefinition()->Icon);
|
||||
NameText->SetText(ClothingItemInstance->GetClothingItemDefinition()->Name);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CommonButtonBase.h"
|
||||
#include "WardrobeItemWidget.generated.h"
|
||||
|
||||
class UCommonTextBlock;
|
||||
class UClothingItemInstance;
|
||||
class UImage;
|
||||
|
||||
UCLASS(Abstract)
|
||||
class NAKEDDESIRE_API UWardrobeItemWidget : public UCommonButtonBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UClothingItemInstance> ClothingItemInstance;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
TObjectPtr<UImage> IconImage;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
TObjectPtr<UCommonTextBlock> NameText;
|
||||
|
||||
public:
|
||||
void SetClothingItemInstance(UClothingItemInstance* InItemInstance);
|
||||
UClothingItemInstance* GetClothingItemInstance() const { return ClothingItemInstance; }
|
||||
|
||||
DECLARE_DELEGATE_OneParam(FOnWardrobeItemClickedSignature, UWardrobeItemWidget* ItemWidget)
|
||||
FOnWardrobeItemClickedSignature OnItemClicked;
|
||||
|
||||
protected:
|
||||
virtual void NativeOnClicked() override;
|
||||
|
||||
private:
|
||||
void UpdateVisuals();
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "WardrobeScreenWidget.h"
|
||||
|
||||
#include "Components/Button.h"
|
||||
#include "Components/CanvasPanel.h"
|
||||
#include "Components/CanvasPanelSlot.h"
|
||||
#include "NakedDesire/UI/Inventory/Equipment/EquipmentPanelWidget.h"
|
||||
#include "NakedDesire/UI/Inventory/Equipment/EquipmentSlotMenuWidget.h"
|
||||
#include "NakedDesire/UI/Inventory/Equipment/EquipmentSlotWidget.h"
|
||||
#include "WardrobeInventoryWidget.h"
|
||||
|
||||
void UWardrobeScreenWidget::NativeOnActivated()
|
||||
{
|
||||
Super::NativeOnActivated();
|
||||
|
||||
if (WardrobeInventory)
|
||||
WardrobeInventory->Init();
|
||||
|
||||
if (!EquipmentSlotMenuWidget && EquipmentSlotMenuWidgetClass)
|
||||
{
|
||||
// Host the slot menu in the same canvas as the blocker, matching UInventoryScreenWidget.
|
||||
if (UCanvasPanel* MenuCanvas = Cast<UCanvasPanel>(MenuBlocker->GetParent()))
|
||||
{
|
||||
EquipmentSlotMenuWidget = CreateWidget<UEquipmentSlotMenuWidget>(this, EquipmentSlotMenuWidgetClass);
|
||||
if (UCanvasPanelSlot* CanvasSlot = Cast<UCanvasPanelSlot>(MenuCanvas->AddChild(EquipmentSlotMenuWidget)))
|
||||
{
|
||||
CanvasSlot->SetAutoSize(true);
|
||||
CanvasSlot->SetAnchors(FAnchors(0.f, 0.f));
|
||||
CanvasSlot->SetZOrder(1);
|
||||
}
|
||||
|
||||
EquipmentSlotMenuWidget->OnActionPerformed.AddUObject(this, &UWardrobeScreenWidget::CloseMenu);
|
||||
}
|
||||
|
||||
if (EquipmentPanel)
|
||||
EquipmentPanel->OnSlotClicked.BindUObject(this, &UWardrobeScreenWidget::HandleSlotClicked);
|
||||
|
||||
if (MenuBlocker)
|
||||
MenuBlocker->OnClicked.AddUniqueDynamic(this, &UWardrobeScreenWidget::CloseMenu);
|
||||
}
|
||||
|
||||
CloseMenu();
|
||||
}
|
||||
|
||||
void UWardrobeScreenWidget::HandleSlotClicked(UEquipmentSlotWidget* SlotWidget)
|
||||
{
|
||||
if (!EquipmentSlotMenuWidget || !SlotWidget)
|
||||
return;
|
||||
|
||||
const bool bMenuOpen = EquipmentSlotMenuWidget->GetVisibility() != ESlateVisibility::Collapsed;
|
||||
if (bMenuOpen && EquipmentSlotMenuWidget->GetSlotType() == SlotWidget->GetSlotType())
|
||||
{
|
||||
CloseMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
// At the wardrobe the "remove" action stores the garment instead of dropping it on the ground.
|
||||
EquipmentSlotMenuWidget->Init(SlotWidget->GetSlotType(), /*bAtWardrobe=*/true);
|
||||
|
||||
if (UCanvasPanelSlot* MenuSlot = Cast<UCanvasPanelSlot>(EquipmentSlotMenuWidget->Slot))
|
||||
{
|
||||
if (UCanvasPanel* MenuCanvas = Cast<UCanvasPanel>(MenuBlocker->GetParent()))
|
||||
{
|
||||
const FGeometry& SlotGeom = SlotWidget->GetCachedGeometry();
|
||||
const FVector2D AbsPos = SlotGeom.GetAbsolutePosition() + FVector2D(SlotGeom.GetAbsoluteSize().X, 0.f);
|
||||
MenuSlot->SetPosition(MenuCanvas->GetCachedGeometry().AbsoluteToLocal(AbsPos));
|
||||
}
|
||||
}
|
||||
|
||||
MenuBlocker->SetVisibility(ESlateVisibility::Visible);
|
||||
EquipmentSlotMenuWidget->SetVisibility(ESlateVisibility::Visible);
|
||||
}
|
||||
|
||||
void UWardrobeScreenWidget::CloseMenu()
|
||||
{
|
||||
if (EquipmentSlotMenuWidget)
|
||||
EquipmentSlotMenuWidget->SetVisibility(ESlateVisibility::Collapsed);
|
||||
|
||||
if (MenuBlocker)
|
||||
MenuBlocker->SetVisibility(ESlateVisibility::Collapsed);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CommonActivatableWidget.h"
|
||||
#include "WardrobeScreenWidget.generated.h"
|
||||
|
||||
class UButton;
|
||||
class UWardrobeInventoryWidget;
|
||||
class UEquipmentPanelWidget;
|
||||
class UEquipmentSlotMenuWidget;
|
||||
class UEquipmentSlotWidget;
|
||||
|
||||
UCLASS(Abstract)
|
||||
class NAKEDDESIRE_API UWardrobeScreenWidget : public UCommonActivatableWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
protected:
|
||||
virtual void NativeOnActivated() override;
|
||||
|
||||
private:
|
||||
UPROPERTY(EditDefaultsOnly, Category = "UI")
|
||||
TSubclassOf<UEquipmentSlotMenuWidget> EquipmentSlotMenuWidgetClass;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UEquipmentSlotMenuWidget> EquipmentSlotMenuWidget;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
TObjectPtr<UEquipmentPanelWidget> EquipmentPanel;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
TObjectPtr<UWardrobeInventoryWidget> WardrobeInventory;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
TObjectPtr<UButton> MenuBlocker;
|
||||
|
||||
void HandleSlotClicked(UEquipmentSlotWidget* SlotWidget);
|
||||
|
||||
UFUNCTION()
|
||||
void CloseMenu();
|
||||
};
|
||||
Reference in New Issue
Block a user