Added phone item

This commit is contained in:
2026-05-31 21:54:33 +03:00
parent f94dce1bfb
commit 65bd932473
13 changed files with 229 additions and 32 deletions
@@ -7,7 +7,10 @@
#include "NakedDesire/Clothing/ClothingItemDefinition.h"
#include "NakedDesire/Clothing/ClothingItemInstance.h"
#include "NakedDesire/Clothing/ClothingManager.h"
#include "NakedDesire/Items/ItemDefinition.h"
#include "NakedDesire/Items/ItemInstance.h"
#include "NakedDesire/Phone/PhoneItemDefinition.h"
#include "NakedDesire/Phone/PhoneItemInstance.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
#include "NakedDesire/SaveGame/GlobalSaveGameData.h"
#include "NakedDesire/SaveGame/ItemSaveRecord.h"
@@ -19,6 +22,12 @@ const TArray<TObjectPtr<UItemInstance>>& UInventorySubsystem::GetWardrobeItems()
return WardrobeItems;
}
UPhoneItemInstance* UInventorySubsystem::GetEquippedPhone()
{
EnsureHydrated();
return EquippedPhone;
}
void UInventorySubsystem::AddToWardrobe(UItemInstance* Item)
{
EnsureHydrated();
@@ -37,6 +46,12 @@ void UInventorySubsystem::EquipFromWardrobe(UItemInstance* Item)
{
EnsureHydrated();
if (UPhoneItemInstance* Phone = Cast<UPhoneItemInstance>(Item))
{
EquipPhone(Phone);
return;
}
UClothingItemInstance* Clothing = Cast<UClothingItemInstance>(Item);
if (!Clothing || !Clothing->GetClothingItemDefinition())
return;
@@ -74,6 +89,12 @@ void UInventorySubsystem::UnequipToWardrobe(UItemInstance* Item)
{
EnsureHydrated();
if (UPhoneItemInstance* Phone = Cast<UPhoneItemInstance>(Item))
{
UnequipPhone(Phone);
return;
}
UClothingItemInstance* Clothing = Cast<UClothingItemInstance>(Item);
if (!Clothing || !Clothing->GetClothingItemDefinition())
return;
@@ -90,6 +111,45 @@ void UInventorySubsystem::UnequipToWardrobe(UItemInstance* Item)
OnWardrobeChanged.Broadcast();
}
void UInventorySubsystem::EquipPhone(UPhoneItemInstance* Phone)
{
if (!Phone || Phone == EquippedPhone)
return;
UGlobalSaveGameData* Save = GetSave();
// Hot-swap: the previously equipped phone returns to the wardrobe (§9.9).
if (EquippedPhone)
{
if (Save)
Save->RemoveEquippedItem(EquippedPhone);
StoreItem(EquippedPhone);
}
UnstoreItem(Phone);
EquippedPhone = Phone;
if (Save)
Save->AddEquippedItem(Phone);
OnPhoneChanged.Broadcast(EquippedPhone);
OnWardrobeChanged.Broadcast();
}
void UInventorySubsystem::UnequipPhone(UPhoneItemInstance* Phone)
{
if (!Phone || EquippedPhone != Phone)
return;
if (UGlobalSaveGameData* Save = GetSave())
Save->RemoveEquippedItem(Phone);
EquippedPhone = nullptr;
StoreItem(Phone);
OnPhoneChanged.Broadcast(nullptr);
OnWardrobeChanged.Broadcast();
}
void UInventorySubsystem::EnsureHydrated()
{
UGlobalSaveGameData* Save = GetSave();
@@ -108,6 +168,23 @@ void UInventorySubsystem::EnsureHydrated()
if (UItemInstance* Instance = UItemInstance::CreateFromRecord(this, Record))
WardrobeItems.Add(Instance);
}
// Only the phone is hydrated from the equipped bucket here; equipped clothing is owned and
// hydrated by the per-character UClothingManager. Pre-check the definition type so we don't
// mint throwaway clothing instances.
EquippedPhone = nullptr;
for (const FItemSaveRecord& Record : Save->GetEquippedItems())
{
const UItemDefinition* Definition = Record.Definition.LoadSynchronous();
if (!Definition || !Definition->IsA<UPhoneItemDefinition>())
continue;
if (UPhoneItemInstance* Phone = Cast<UPhoneItemInstance>(UItemInstance::CreateFromRecord(this, Record)))
{
EquippedPhone = Phone;
break;
}
}
}
void UInventorySubsystem::StoreItem(UItemInstance* Item)
@@ -9,8 +9,10 @@
class UItemInstance;
class UClothingManager;
class UGlobalSaveGameData;
class UPhoneItemInstance;
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnWardrobeChangedSignature);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPhoneChangedSignature, UPhoneItemInstance*, Phone);
/**
* Runtime owner of the off-body item store (the apartment wardrobe, GDD §6.5 / §10.4).
@@ -31,9 +33,16 @@ public:
UPROPERTY(BlueprintAssignable)
FOnWardrobeChangedSignature OnWardrobeChanged;
// Fires when the phone slot changes; broadcasts the newly-equipped phone, or nullptr when emptied.
UPROPERTY(BlueprintAssignable)
FOnPhoneChangedSignature OnPhoneChanged;
/** Live wardrobe instances (off-body, mirrored from the save). */
const TArray<TObjectPtr<UItemInstance>>& GetWardrobeItems();
/** The phone occupying the dedicated phone slot (§6.5 / §9.9), or nullptr if none is equipped. */
UPhoneItemInstance* GetEquippedPhone();
/** Bring an item into the wardrobe (purchase, world-return). */
void AddToWardrobe(UItemInstance* Item);
@@ -51,12 +60,18 @@ private:
void StoreItem(UItemInstance* Item); // live list + save bucket, no broadcast
void UnstoreItem(UItemInstance* Item); // live list + save bucket, no broadcast
void EquipPhone(UPhoneItemInstance* Phone); // hot-swaps the previous phone back to the wardrobe
void UnequipPhone(UPhoneItemInstance* Phone); // stores the phone back in the wardrobe
UClothingManager* GetPlayerClothingManager() const;
UGlobalSaveGameData* GetSave() const;
UPROPERTY()
TArray<TObjectPtr<UItemInstance>> WardrobeItems;
UPROPERTY()
TObjectPtr<UPhoneItemInstance> EquippedPhone;
// The save the live list was built from; re-hydrate when this changes (e.g. load game).
TWeakObjectPtr<UGlobalSaveGameData> HydratedSave;
};