updated plan
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APLCrashReporter_002EBuild_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FShared_003FEpic_0020Games_003FUE_005F5_002E7_003FEngine_003FSource_003FThirdParty_003FPLCrashReporter_003FPLCrashReporter_002EBuild_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
@@ -12,63 +12,86 @@ State of the C++ module as of the latest pass. File references use `Source/Naked
|
||||
|
||||
### 1.1 Implemented
|
||||
|
||||
- **Modular character w/ per-slot meshes** — `Player/NakedDesireCharacter.cpp:40-67` creates 14 skeletal mesh components, one per clothing slot. Aligns with GDD §17.6.
|
||||
- **Equip / unequip / drop event** — `Clothing/ClothingManager.cpp:88-172` (slot-based, broadcasts `OnClothingEquip / Unequip / Dropped`).
|
||||
- **Basic perception** — `Player/NakedDesireCharacter.cpp:167-203` implements `IAISightTargetInterface::CanBeSeenFrom` against `boobs_root` and `pelvis` bones with line-of-sight checks. Foundation for GDD §7.1.
|
||||
- **AI sight + behavior tree** — `NPC/NPCAIController.cpp` runs a BT with `Player` / `TargetLocation` blackboard. `NPC/NPCSpawner.cpp` does proximity-gated spawning with day / night caps.
|
||||
- **Mission framework** — `Mission` → `MissionGoal` → `GoalRestriction` composition (`MissionBuilder/`). Two goals (`FlashGoal`, `MinTimeGoal`), three restrictions (`EquipClothing`, `ExposeBodyPart`, `Location`).
|
||||
- **Item identity scaffold (GDD §6.1)** — `Items/ItemInstance.h` defines `UItemInstance` as an abstract `UObject` with a stable `FGuid InstanceID`, auto-assigned in `PostInitProperties` and refreshed in `PostDuplicate`. `Clothing/ClothingItemInstance.h` inherits from it and holds per-instance `Condition`, a pointer to the immutable `UClothingItem` definition, and a `StoredItems` array for container slots.
|
||||
- **Definition / instance split (GDD §6.1, §17.4)** — `Clothing/ClothingItem.h` is the immutable `UPrimaryDataAsset` definition with GDD-aligned fields: `Coverage`, `IsUnderwear`, `CanExpose`, `IsRestrictive`, `ContainerSlots` (typed S/M/L via `EGarmentContainerSlotType` + `FGarmentContainerSlot`), `ProgressionPath`, plus rendering data (`SkeletalMesh`, `Materials`, `StaticMesh`).
|
||||
- **Progression path enum (GDD §5)** — `Progression/ProgressionPath.h` defines `EProgressionPath { None, Slut, Exhibitionist, Slave }`. Used on `UClothingItem::ProgressionPath`.
|
||||
- **Body-part enum (GDD §6.3)** — `Clothing/BodyPart.h` defines `EBodyPart { None, Boobs, Ass, Genitals }`. Used on `UClothingItem::CanExpose`.
|
||||
- **Save scaffolding (GDD §16)** — `SaveGame/SaveSubsystem.h/.cpp` (`UGameInstanceSubsystem`), `SaveGame/ItemSaveRecord.h` (generic `{ InstanceId, Definition, Condition, ParentId }`). `Global/Constants.h` now uses `DefaultSaveSlotName` instead of a single `SLOT_NAME` macro.
|
||||
- **Observation-driven embarrassment (GDD §7.1)** — `NPC/NPCAIController.cpp:56-69` listens to `OnTargetPerceptionUpdated` and forwards bSensed transitions to `Stats/StatsManager::SetObserved`. `Stats/StatsManager::TickComponent` (`StatsManager.cpp:23-38`) now gates gain vs. decay on `ObserverCount` instead of unconditional decay. Foundation for Phase 4.
|
||||
- **Modular character w/ per-slot meshes** — `Player/NakedDesireCharacter.cpp:40-67` creates 14 skeletal mesh components, one per `EClothingSlotType`. Aligns with GDD §17.6.
|
||||
- **Equip / unequip / drop event** — `Clothing/ClothingManager.cpp:88-163` (slot-based, broadcasts `OnClothingEquip / Unequip / Dropped` with `UClothingItemInstance*`).
|
||||
- **Censorship toggle** — compliance feature on `NakedDesireCharacter` (`BoobL/R`, `Front/BackBottom` static meshes), driven by `UNakedDesireUserSettings`.
|
||||
- **AI sight + behavior tree** — `NPC/NPCAIController.cpp` runs a BT with `Player` / `TargetLocation` / `SpawnLocation` blackboard keys. `NPC/NPCSpawner.cpp` proximity-gated spawn with day / night caps.
|
||||
- **Mission framework** — `Mission` → `MissionGoal` → `GoalRestriction` composition (`MissionBuilder/`). Two goals (`FlashGoal`, `MinTimeGoal`), three restrictions (`EquipClothing`, `ExposeBodyPart`, `Location`). Iterate-and-mutate bug in `MissionsManager::RefreshDailyMissions` resolved (`MissionsManager.cpp:53-68`).
|
||||
- **Daily-mission OOB guarded** — `NakedDesireGameMode::RefreshDailyMissions` now clamps `DaysPassed` to the authored array bounds (`NakedDesireGameMode.cpp:70-71`). Still a hand-authored list (see §1.3).
|
||||
- **Location triggers** — `Locations/LocationTrigger`, `Locations/LocationData` via gameplay tags (GDD §10.4 area foundation).
|
||||
- **Censorship toggle** — compliance feature on `NakedDesireCharacter` (BoobL/R, Front/BackBottom static meshes), driven by user settings.
|
||||
- **Movement** — `EnhancedInput`, walk / run / crouch (`NakedDesireCharacter.cpp:115-127`), stamina-gated run (`Tick` lines 91-113).
|
||||
- **Wardrobe interactable** — `Interactables/Wardrobe.h` holds `ClothingItems[]`; `NakedDesireGameMode::BuyItem` charges money and pushes into wardrobe.
|
||||
- **Wardrobe interactable** — `Interactables/Wardrobe.h` holds `TArray<TObjectPtr<UClothingItemInstance>> ClothingItems`; `NakedDesireGameMode::BuyItem` charges money and pushes into the wardrobe.
|
||||
|
||||
### 1.2 Partially implemented (deviates from GDD)
|
||||
|
||||
- **Item identity (§6.1)** — `Clothing/ClothingItemData.h:14-27` exists as an "instance" UObject but has no unique ID and no per-instance state (no condition, color, coverage float, isUnderwear, canExpose, isRestrictive, containerSlots). `SaveGame/ClothingItemSaveData.h` only stores a `TSoftObjectPtr<UClothingItem>` — it saves the *template*, not the instance. Directly violates the "every item is a unique physical instance" rule.
|
||||
- **Save system (§16)** — `SaveGame/GlobalSaveGameData.h` only persists `HaveSeenTutorial`, `Money`, and two clothing lists. No world items, NPCs, time, mission state, recognition / reputation / followers, or wanted flag. Save fires only on explicit Blueprint call; load only happens in `ANakedDesireCharacter::BeginPlay`.
|
||||
- **Attributes (§7)** — `Stats/StatsManager.h:17-31` has only Embarrassment, Energy, Stamina. Missing Lust, Recognition, Reputation, Followers, Wanted. No GAS. `TickComponent` (`StatsManager.cpp:23-28`) unconditionally drains energy and decays embarrassment — observation-driven gain is not wired in C++.
|
||||
- **Coverage (§6.3.1)** — `ClothingManager::IsBodyTypeExposed` (`ClothingManager.cpp:14-25`) is binary. No coverage float, no underwear halving, no max-of-covering-garments math.
|
||||
- **Body parts (§6.3)** — only `FrontTop / FrontBottom / BackBottom` exist (`Player/PrivateBodyPartType.h:14-20`). GDD references boobs, ass, genitals as distinct parts.
|
||||
- **Mission system** — composable goals work but lacks the typed objective steps from §13.4 (`BeFullyNakedNearNPCs`, `WalkNakedDistance`, `MoveDistanceFromClothing`, `BeObservedByNPCType`, `TakePhotoAtLocation`, `DeliverItemTo`). Missions are hand-authored in `MissionsConfig`.
|
||||
- **Day / night** — affects spawn caps (`NPCSpawner.cpp:40-41`) but not embarrassment rate, NPC type weights, or police spawning.
|
||||
- **Save subsystem (GDD §16)** — scaffolded but **not actually wired through gameplay**. `USaveSubsystem::SaveGame` (`SaveSubsystem.cpp:10-13`) delegates to `UGlobalSaveGameData::SaveGame`, which creates a *fresh empty* `UGlobalSaveGameData` (`GlobalSaveGameData.cpp:45-53`) and writes it — i.e., it does not capture the live player / wardrobe / world state at all. `USaveSubsystem::LoadGame` calls the static loader but discards the result without applying it (`SaveSubsystem.cpp:5-8`). `ClothingManager::HydrateClothing` (`ClothingManager.cpp:66-73`) is an empty stub with the previous logic commented out. Exit criterion of Phase 1 (round-trip an item with modified condition) is not met yet.
|
||||
- **Item identity → world (§6.1)** — `UItemInstance` GUIDs exist, but no item has been promoted to a world `AActor`. `ClothingManager::DropClothing` (`ClothingManager.cpp:156-163`) still only broadcasts `OnClothingDropped` — no spawn, no parent reassignment in any registry.
|
||||
- **Attributes (§7)** — `StatsManager` covers Embarrassment, Energy, Stamina with observation-driven gain now correctly tied to NPC perception. Missing: Lust, Pulse (new, §7.5), Recognition, Reputation, Followers, Wanted. Coverage weighting in the gain formula is stubbed at `0.0f` with a TODO marker (`StatsManager.cpp:30-32`).
|
||||
- **Coverage (§6.3.2)** — `UClothingItem::Coverage` and `IsUnderwear` exist on the definition, but `ClothingManager::IsBodyTypeExposed` (`ClothingManager.cpp:14-25`) is still binary. No `GetEffectiveCoverage(EBodyPart)` function, no underwear-halving, no sum-of-garments math.
|
||||
- **Body-part enums — duplicated** — both `Player/PrivateBodyPartType.h` (`EPrivateBodyPartType { FrontBottom, BackBottom, FrontTop }`) and `Clothing/BodyPart.h` (`EBodyPart { Boobs, Ass, Genitals }`) exist. `UClothingItem::CoveredBodyParts` uses the **old** enum; `UClothingItem::CanExpose` uses the **new** one. Half-migrated.
|
||||
- **Mission system** — composable goals work but lacks the typed objective steps from §13.4 (`BeFullyNaked`, `BeFullyNakedNearNPCs`, `WalkNakedDistance`, `MoveDistanceFromClothing`, `BeObservedByNPCType`, `TakePhotoAtLocation`, `DeliverItemTo`). Missions still hand-authored in `MissionsConfig::DailyMissions` keyed by day index — no procedural generation.
|
||||
- **Day / night** — `NPCSpawner.cpp:38-41` reads `GetCurrentTime().Hours` and gates spawn cap, but does not affect embarrassment gain, NPC type weighting, or police spawning (see §1.3).
|
||||
|
||||
### 1.3 Missing
|
||||
|
||||
- **Session system (§4)** — no `USessionManager`, no session start / end events, no `SessionLossResolver`. Game-over on embarrassment is a single `EndGameEmbarrassed` Blueprint event in `NakedDesireGameMode`; none of §4.4's item-drop logic is implemented.
|
||||
- **Three progression paths (§5)** — no path enum on `UClothingItem`, no Path XP, no path levels, no path-gated content.
|
||||
- **Session system (GDD §4)** — no `USessionManager`, no session start / end events, no `USessionLossResolver`. Game-over on embarrassment is a single `EndGameEmbarrassed` BP event in `NakedDesireGameMode`; none of §4.4's behavior (energy-zero cutscene to home, bag-placed-in-world loss, sleep-deterministic clothing loss) is implemented.
|
||||
- **Three progression paths runtime (§5)** — enum exists; no path XP, no per-path level, no path-gated unlocks at runtime, no level-up flow.
|
||||
- **Phone (§9)** — entire system absent: camera, gallery, livestream, bank, Feetex, maps, health tracker.
|
||||
- **Forum (§13)** — no `UCommissionTemplate`, no procedural generation, no weekly missions distinct from daily, no profile / followers, no posting photos.
|
||||
- **Photo & livestream** — absent.
|
||||
- **NPC types (§10.2)** — only one generic `ANPC` class. No Walker / Stalker / Paparazzi / Snitch / Harasser / Helper, no Police, no Wanted-poster mechanic.
|
||||
- **Calendar, rent, sleep (§2.4, §15.2)** — `DaysPassed` increments in `NakedDesireGameMode::OnHourChanged(4)`, but no week, no rent, no eviction, no sleep action.
|
||||
- **Item-world AActor (§6.1)** — clothing drops broadcast a delegate but no `AItemActor` exists.
|
||||
- **NPC types (§10.2)** — only one generic `ANPC` class. No Walker / Stalker / Blogger / Snitch / Harasser, no Police, no Wanted-poster mechanic.
|
||||
- **Calendar, rent, sleep (§2.4, §15.2)** — `DaysPassed` increments in `NakedDesireGameMode::OnHourChanged(4)`, but no week, no rent, no eviction, no sleep action, no apartment bed interaction.
|
||||
- **Item-world AActor (§6.1)** — no `AItemActor` / `AClothingPickup` base.
|
||||
- **Bag inventory (§6.4)** — absent.
|
||||
- **Rip & tear, theft (§6.3.3-4)** — absent.
|
||||
- **Expose action (§6.3.5)** — absent.
|
||||
- **Restrictive clothing (§6.3.6)** — absent.
|
||||
- **Theft (§6.3.4)** — new chance-based model (per-tick `P_theft` after grace period) not implemented. No theft timer / probability code at all.
|
||||
- **Rip & tear (§6.3.5)** — absent. `UClothingItemInstance::Condition` is read-only in code; no decrement source.
|
||||
- **Expose action (§6.3.6)** — `CanExpose` data exists on the definition; runtime action absent.
|
||||
- **Restrictive clothing (§6.3.7 / §10.4.1)** — `IsRestrictive` field exists; no enforcement of hand-action locks, no Key-based unlock flow.
|
||||
- **Adult shop, gym, beauty salon, cafe, convenience store** — none.
|
||||
- **Food / consumables (§6.6)** — absent.
|
||||
- **Recognition, wanted state, news (§7.5–7.6, §11.1)** — absent.
|
||||
- **Food / consumables (§6.7)** — absent.
|
||||
- **Recognition, wanted state, news (§7.6–§7.7, §11.1)** — absent.
|
||||
- **Underwear selling (§15.1)** — absent.
|
||||
- **Endless mode flag (§3.3)** — absent.
|
||||
- **Pulse attribute (§7.5)** — absent (new in the updated GDD).
|
||||
- **GAS adoption (§17.2)** — `StatsManager` is still a bespoke `UActorComponent`; no `UAttributeSet`, no `GameplayEffect`-driven modifiers.
|
||||
|
||||
### 1.4 Conflicts to resolve
|
||||
|
||||
- **`EClothingSlotType` (`Clothing/ClothingSlotType.h`)** treats `Nipples / Anal / Vagina` as equipment slots; GDD treats those as body parts. Slot list also lacks `Outerwear`, `Accessory`, `Restraint`. Slot vocabulary needs a cleanup pass.
|
||||
- **`Money` lives on `ANakedDesireCharacter`** (`NakedDesireCharacter.h:139`) as `int Money = 300000`, and also as a field on `UGlobalSaveGameData`. Duplicate state. Default 300k vs. ~20k weekly rent (§15.3) — test value.
|
||||
- **`MissionsManager::RefreshDailyMissions`** (`MissionBuilder/MissionsManager.cpp:53-68`) has a remove-while-iterating bug; `OnComplete.RemoveAll(this)` is called on the *mission*, not on the manager handle.
|
||||
- **`NakedDesireGameMode::RefreshDailyMissions`** indexes `MissionsConfig->DailyMissions[DaysPassed]` — crashes past the authored array and contradicts §13.4 procedural generation.
|
||||
- **`StatsManager::TickComponent` unconditionally decays embarrassment** (`StatsManager.cpp:27`). §7.1 says decay should happen only when not observed; today no observation-driven gain offsets it.
|
||||
- **Save constant `SLOT_NAME "Slot2"`** (`Global/Constants.h:5`) — magic single-slot save, no multi-save support.
|
||||
- **`UClothingItemData` is `EditInlineNew`** and stored inline in `UClothingList::ClothingItems`. Instances live inside the list asset, not as standalone objects with stable identity. Direct conflict with §6.1.
|
||||
- **`SaveGame` UPROPERTY typo** — `GlobalSaveGameData.h:35` declares `UPROPERTY(SaceGame)` instead of `SaveGame` on `DaysPassed`. The field will not serialize. (Likely also blocks Unreal Header Tool warnings; needs a clean rebuild after the fix.)
|
||||
- **`EClothingSlotType`** (`Clothing/ClothingSlotType.h`) still includes `Nipples`, `Anal`, `Vagina` as equipment slots — those are body parts per the GDD. Slot list also lacks `Outerwear`, `Accessory`, `Restraint` (GDD §6.3 / §21 Q1). The character builds 14 skeletal mesh components against these values (`NakedDesireCharacter.cpp:40-67`), so the cleanup needs a matching content / BP pass.
|
||||
- **Two competing body-part enums** — `EPrivateBodyPartType` vs. `EBodyPart`. `ClothingItem::CoveredBodyParts` uses one, `ClothingItem::CanExpose` uses the other. The censorship / observation code paths in `NakedDesireCharacter` and `ClothingManager` are still on `EPrivateBodyPartType`. Pick one (recommend `EBodyPart`) and migrate.
|
||||
- **`USaveSubsystem::SaveGame` writes an empty save** — it does not pull state from the live world before writing (`SaveSubsystem.cpp:10-13`, `GlobalSaveGameData.cpp:45-53`). Any "save" call at present destroys progress rather than persisting it. Highest-priority correctness bug.
|
||||
- **`USaveSubsystem::LoadGame` ignores the loaded object** — the static returns a populated `UGlobalSaveGameData`, the subsystem stores nothing and applies nothing.
|
||||
- **`UClothingList`** forward-declared in `GlobalSaveGameData.h:11` and `Wardrobe` / save records no longer use it. Dead reference; remove.
|
||||
- **`Money` representation** — `ANakedDesireCharacter::Money` is `int` (`NakedDesireCharacter.h:132`), `UGlobalSaveGameData::Money` is `float` (`GlobalSaveGameData.h:27`). The earlier "Resolve Money duplication" commit consolidated the field locations but the type mismatch and the routing-through-save story are unfinished — verify which is authoritative before adding economy systems on top.
|
||||
- **`STARTING_MONEY`** macro added to `Constants.h:8` but no code references it. Either wire it into the player / save init, or remove.
|
||||
- **`ClothingItemInstance` has no public constructor / factory** — `ClothingItem` pointer is `protected` with no `Init(UClothingItem*)`. Wardrobe / BuyItem flows currently `EditAnywhere Instanced` populate the array at design-time, which works for the existing test level but won't support runtime purchase or save-driven hydration.
|
||||
- **`StatsManager::TickComponent` energy drain** — drains energy at a flat `0.9f` per tick (`StatsManager.cpp:26`) regardless of activity, indoor / outdoor, or modifiers. GDD §7.3 specifies per-activity modifiers (`energyDrainRunModifier`, etc.).
|
||||
- **`NPCSpawner` day window** — uses `Hours >= 9 && < 21` for "day" (`NPCSpawner.cpp:40`), GDD §10.1 says the day phase is `08:00 → 20:00`. Off-by-one and an hour offset.
|
||||
- **GDD shifts not yet reflected in code:**
|
||||
- Phase 4-era loss resolver work must avoid stripping equipped clothing — GDD §4.4 now says equipped items are **never** force-removed on loss.
|
||||
- Energy = 0 must trigger a "cutscene to apartment + sleep" flow, not a teleport (GDD §4.4).
|
||||
- Theft is now a chance-based model with grace periods (`T_grace`, `T_grace_bag`) and flat per-tick `P_theft`, not a ramping curve (GDD §6.3.4).
|
||||
- Sleep is the deterministic side of clothing loss — guaranteed loss of every item left outside the apartment (GDD §4.4).
|
||||
- No Helper NPC, no adult-shop unlock; restraint removal is Key + timed unlock only (GDD §10.4.1).
|
||||
- Masturbation gating is Slut-path only (GDD §5.1 / §7.2 / §14.1).
|
||||
- Police spawn day **and** night while `wanted` (GDD §7.7 / §10.3) — current spawner has no police path at all, but record this when it's built.
|
||||
|
||||
---
|
||||
|
||||
## 2. Architectural premise
|
||||
|
||||
The item-identity rule (§6.1) and the save contract (§16.3) are load-bearing. Clothing condition, world drops, session loss, theft, the bag, and the forum's "post a photo of *this* specific worn item" all depend on stable per-instance state.
|
||||
The item-identity rule (§6.1) and the save contract (§16.3) are still load-bearing. With the definition / instance split in place, the next bottleneck is **wiring serialization through gameplay**: condition mutation, world drops, container parent links, hydration on load. Until that round-trip works, content on top of the current system has no durable home.
|
||||
|
||||
Until Phase 1 lands, content authored on top of the current system needs migration. Do not build the higher phases first.
|
||||
The session-system + loss resolver (Phase 3) is the second pin. Several GDD shifts (equipped-never-dropped, energy-zero cutscene, sleep-deterministic clothing loss) move complexity from §4.4 prose into a single deterministic resolver. Build it once, well.
|
||||
|
||||
GAS adoption (§17.2) remains deferred until Phase 4. Adding new attributes to the bespoke `StatsManager` in the meantime is fine — keep them additive and easy to migrate.
|
||||
|
||||
---
|
||||
|
||||
@@ -76,93 +99,129 @@ Until Phase 1 lands, content authored on top of the current system needs migrati
|
||||
|
||||
Phase estimates are rough and assume one engineer. Adjust as we go.
|
||||
|
||||
### Phase 1 — Item identity + save foundation (1–2 weeks)
|
||||
### Phase 1 — Finish item identity + save round-trip (1 week)
|
||||
|
||||
- Split `UClothingItem` (immutable definition, `UPrimaryDataAsset`) from a new `UItemInstance` UObject with `FGuid InstanceId` and mutable state (`Condition`, `Color`, container parent, world transform). Make `UClothingItemInstance : UItemInstance`.
|
||||
- Add to the definition: `Coverage` float, `IsUnderwear`, `CanExpose` list, `IsRestrictive`, `ContainerSlots`, `ProgressionPath` enum.
|
||||
- Enumerate slots cleanly — split slot vs. body-part vocabulary (resolves §1.4 conflict).
|
||||
- Replace `FClothingItemSaveData` with a generic `FItemSaveRecord { Guid, DefinitionPath, InstanceState, Location, ParentRef }`.
|
||||
- Introduce `USaveSubsystem` (GameInstance subsystem) that orchestrates serialization across player, world items, time, missions, attributes, recognition.
|
||||
- Convert single-slot `SLOT_NAME` to a slot-name argument.
|
||||
Most of the structural work is done. What remains is connecting the pieces so an item modified at runtime survives a save / load cycle.
|
||||
|
||||
**Exit criteria:** an item dropped in the world, with its condition modified, survives save / load with the same GUID and condition value.
|
||||
- Fix the `SaceGame` UPROPERTY typo on `DaysPassed` (`GlobalSaveGameData.h:35`).
|
||||
- Add `UClothingItemInstance::Init(UClothingItem* Definition)` (or a static factory) so instances can be constructed at runtime — not just `Instanced` at design-time.
|
||||
- Make `USaveSubsystem::SaveGame` actually pull live state into a `UGlobalSaveGameData`: player money, equipped items, wardrobe items, calendar, observation-attribute snapshot. Cover `WardrobeItems` and `EquippedItems` arrays via `FItemSaveRecord` populated from current `UClothingItemInstance`s (Guid, definition soft pointer, condition, parent guid).
|
||||
- Make `USaveSubsystem::LoadGame` actually apply the loaded data: rebuild `UClothingItemInstance`s from records, push into the wardrobe array and `ClothingManager` slots. Replace the commented-out `ClothingManager::HydrateClothing` with the real hydration.
|
||||
- Unify `EPrivateBodyPartType` and `EBodyPart` (recommend keeping `EBodyPart`, retiring the legacy enum). Update `ClothingItem::CoveredBodyParts`, `ClothingManager::IsBodyTypeExposed`, censorship checks in `NakedDesireCharacter`, and the BT / observation paths.
|
||||
- Slot vocabulary pass: drop `Nipples` / `Anal` / `Vagina` from `EClothingSlotType`, add `Outerwear` / `Accessory` / `Restraint`. Update the character's mesh component layout and any BP references in lockstep.
|
||||
- Money: pick one authoritative location (`UGlobalSaveGameData` is the natural choice; `ANakedDesireCharacter::Money` becomes a cached read-through). Apply `STARTING_MONEY` at new-save creation. Convert character field to match save type.
|
||||
- Remove the dead `UClothingList` forward declarations.
|
||||
|
||||
**Exit criteria:**
|
||||
1. Item dropped at runtime, condition modified, save → quit → load reproduces the same `FGuid`, condition value, and slot / wardrobe membership.
|
||||
2. `EBodyPart` is the only body-part enum in use.
|
||||
3. Slot list matches GDD §6.3 / §21 Q1 decision.
|
||||
4. A new game starts with `STARTING_MONEY` and rent / purchase flows debit the canonical money field.
|
||||
|
||||
### Phase 2 — World item actors + drop / pickup (1 week)
|
||||
|
||||
- `AItemActor` base wrapping a `UItemInstance*`. `AClothingPickup : AItemActor`.
|
||||
- Hook `ClothingManager::DropClothing` to spawn `AClothingPickup` at the player location with the actual instance reference (no template copy).
|
||||
- Pickup interaction via existing `InteractionManager`.
|
||||
- `AItemActor` base wrapping a `UItemInstance*` (in `Items/`). Spawn transform, owning instance pointer, SaveGame-tagged.
|
||||
- `AClothingPickup : AItemActor` with a visual representation (use `UClothingItem::StaticMesh` when set, fallback to skeletal mesh impostor).
|
||||
- Hook `ClothingManager::DropClothing` to spawn `AClothingPickup` at the player location with the actual instance reference — *not* a template copy. Reparent the instance from "equipped slot" to "world".
|
||||
- Pickup interaction via existing `UInteractionManager` + `IInteractionTarget`. Pickup re-parents the instance into wardrobe or directly into the matching slot.
|
||||
- `USaveSubsystem` extension: serialize `AClothingPickup`s as `FItemSaveRecord`s with world transform.
|
||||
|
||||
**Exit criteria:** unequip → world actor appears → re-pick-up restores the same instance to the slot.
|
||||
**Exit criteria:** unequip → world pickup actor appears → save / reload → pickup is still there at the same transform with the same instance ID → pick up restores the same instance to the slot.
|
||||
|
||||
### Phase 3 — Session system + loss resolver (1 week)
|
||||
|
||||
- `USessionManager` (GameMode component). Apartment `LocationTrigger` flag drives session start / end.
|
||||
- `USessionLossResolver` — single class, per §4 implementation note. Takes the loss cause and runs §4.4 deterministically over the new world-item registry.
|
||||
- Wire `StatsManager::IncreaseEmbarrassment` max-hit and energy-zero into the resolver.
|
||||
- `USessionManager` (subsystem on `UNakedDesireGameInstance` or a `UWorldSubsystem`). Apartment `ALocationTrigger` flag drives session start / end. Emits `OnSessionStart` / `OnSessionEnd` with cause.
|
||||
- `USessionLossResolver` — single class, one method `ResolveLoss(ESessionLossCause Cause)`. Implements GDD §4.4:
|
||||
- Equipped clothing **stays** equipped (do not strip).
|
||||
- Bag placed in world: mark its world record for deletion.
|
||||
- Loose clothing on ground: leave as-is (theft chance has been running through Phase ?-7 logic; sleep step is what finalizes).
|
||||
- Energy=0 path: trigger a cutscene → apartment → sleep cycle → guaranteed loss of every world clothing outside the apartment safe zone.
|
||||
- Embarrassment-max / police-capture path: fade to apartment, no sleep cycle, no forced clothing loss.
|
||||
- Police-capture: deduct money penalty, queue skipped days for the unpaid remainder, clear `wanted`.
|
||||
- Wire `StatsManager::IncreaseEmbarrassment` max-hit and energy-zero into `USessionLossResolver`. Replace `EndGameEmbarrassed` BP-event with the C++ path.
|
||||
- Add a debug overlay that shows the current loss state and what would be lost if a given cause fired.
|
||||
|
||||
**Exit criteria:** lose to embarrassment → equipped clothing spawns as world actors at the loss location, persists through save.
|
||||
**Exit criteria:** all four code paths (safe end, embarrassment max, energy zero, police capture) produce the §4.4 outcomes deterministically. Inventory state after each loss matches the §6.6 summary table 1:1.
|
||||
|
||||
### Phase 4 — Attributes refactor (1 week)
|
||||
### Phase 4 — Attributes refactor (1–2 weeks)
|
||||
|
||||
- Decide GAS vs. extended `StatsManager` (recommend GAS per §17.2; embarrassment formula has many modifiers that GAS effects model cleanly).
|
||||
- Add Lust, Recognition, Reputation, Followers, Wanted.
|
||||
- Move observation-driven embarrassment gain out of BP into the C++ pipeline (use the existing `CanBeSeenFrom` result + per-NPC type weights).
|
||||
- Add Lust + masturbate action + blackout vision effect.
|
||||
- Add Recognition with face-cover bypass + Wanted bool.
|
||||
- Decision: GAS vs. extended `StatsManager`. Recommend GAS — the embarrassment formula now has Pulse, Recognition, Coverage, Day/Night, and per-NPC-type weights as modifiers (§7.1), which is exactly what `UGameplayEffect` is shaped for.
|
||||
- Add Lust (§7.2), Pulse (§7.5, **new**), Recognition (§7.6), Wanted (§7.7), Reputation (§7.8), Followers (§7.9). Money should be the only attribute that also lives in the save schema directly (since it has non-attribute side effects).
|
||||
- Implement `GetEffectiveCoverage(EBodyPart)` on `ClothingManager` per §6.3.2 (sum of garments covering the part, underwear halved, clamped to 1.0). Replace the `CoverageWeight = 0.0f` stub in `StatsManager::TickComponent`.
|
||||
- Lust → masturbate action (Slut-path gated, §7.2). Block the action in BP / quick-action when the player's Slut path level is 0.
|
||||
- Pulse simulation: rises with running, masturbation, exposure events; decays toward baseline at rest. Modifies embarrassment / lust gain (§7.5).
|
||||
- Recognition rise from Blogger photo events; face-cover bypass; reduce via news-site reporting (§11.1).
|
||||
- Debug overlay extension: live values + active modifier sources for every attribute.
|
||||
|
||||
**Exit criteria:** observed-while-exposed gains embarrassment from C++; unobserved decays; both rates are inspectable in a debug overlay.
|
||||
**Exit criteria:**
|
||||
1. Observed-while-exposed embarrassment gain reads coverage and modifiers from the attribute system (no more `0.0f` stub).
|
||||
2. Lust + Pulse simulate correctly and visibly influence embarrassment in a playtest scenario.
|
||||
3. Recognition increases after a (mocked) photo event and decreases after a news-report action.
|
||||
|
||||
### Phase 5 — Time + calendar + rent + sleep (3–4 days)
|
||||
|
||||
- `UTimeOfDaySubsystem` replacing the BP-implementable time on `NakedDesireGameMode`. 90-day calendar, week boundary, rent transaction.
|
||||
- Sleep action on apartment bed: time-skip + energy restore + autosave.
|
||||
- Endless-mode flag on the save.
|
||||
- `UTimeOfDaySubsystem` replacing the BP-implementable time on `NakedDesireGameMode`. 90-day calendar, week boundary, day phase `08:00–20:00` (fix the 09–21 mismatch in `NPCSpawner.cpp:40`).
|
||||
- Sleep action on apartment bed: triggers the same path as energy-zero (§4.4) for the "items left outside" cleanup, restores energy, autosaves, advances calendar.
|
||||
- Weekly rent transaction at week boundary; eviction if money insufficient (`game over (run)`, §3.3).
|
||||
- Endless-mode flag on `UGlobalSaveGameData`; rent-eviction branch checks it.
|
||||
|
||||
**Exit criteria:** play through 7 in-game days, get charged rent at week boundary, eviction triggers on insufficient funds.
|
||||
**Exit criteria:** play through 7 in-game days, get charged rent at the week boundary, eviction triggers on insufficient funds, endless-mode disables eviction.
|
||||
|
||||
### Phase 6 — NPC types + recognition pipeline (1–2 weeks)
|
||||
|
||||
- `ENPCType` enum, type-specific BT branches or per-type controller subclasses.
|
||||
- Walker / Stalker / Paparazzi / Snitch / Harasser / Helper / Police.
|
||||
- Recognition flow: Paparazzi photo → article → news site → "report" reduces recognition.
|
||||
- `ENPCType` enum, type-specific BT branches or per-type controller subclasses: Walker / Stalker / Blogger / Snitch / Harasser. **No Helper** (cuff removal is Key-only per §10.4.1).
|
||||
- Police as a separate AI controller / spawn pipeline. Patrols spawn day and night while `wanted` (§7.7 / §10.3). Detection logic (`face hidden?` + coverage threshold) → chase → break-LOS timer.
|
||||
- Wanted-poster mechanic: spawn posters in the city; tearing all down clears `wanted` (§10.3).
|
||||
- Recognition flow: Blogger sight + photo event → article → news-site article state → "report" reduces recognition.
|
||||
- Wire Snitch's "report to police" → immediate police spawn this session + sets `wanted` (§7.7).
|
||||
|
||||
**Exit criteria:** each NPC type observably distinct behavior; recognition rises after paparazzi exposure and can be reduced via news report.
|
||||
**Exit criteria:** every listed NPC type observably distinct; recognition rises after a Blogger event and can be reduced via news report; Snitch report triggers police spawn and the `wanted` tag that persists across sessions until posters torn down or capture.
|
||||
|
||||
### Phase 7 — Commission template system (1–2 weeks)
|
||||
|
||||
- Replace `MissionsConfig`'s hand-authored daily list with `UCommissionTemplate` + procedural generation per §13.4.
|
||||
- Add typed objective steps as new `UMissionGoal` subclasses (`BeFullyNakedNearNPCs`, `WalkNakedDistance`, `MoveDistanceFromClothing`, `BeObservedByNPCType`, `TakePhotoAtLocation`).
|
||||
- Weekly vs. daily generation pass.
|
||||
- Add typed objective steps as new `UMissionGoal` subclasses:
|
||||
- `BeFullyNaked(duration)` (new in §13.4)
|
||||
- `BeFullyNakedNearNPCs(count, duration)`
|
||||
- `WalkNakedDistance(meters)`
|
||||
- `MoveDistanceFromClothing(meters)`
|
||||
- `BeObservedByNPCType(type, durationOrCount)`
|
||||
- `TakePhotoAtLocation(locationTag)` (requires phone work from Phase 8 — gate this objective until then)
|
||||
- `DeliverItemTo(npcOrLocation)`
|
||||
- Path-tagged XP (§5). Generation weights against player path progression.
|
||||
- Weekly-vs-daily generation pass.
|
||||
|
||||
**Exit criteria:** daily commissions regenerate from templates each in-game day; weekly arc is distinct; failed commissions deduct reputation.
|
||||
|
||||
### Phase 8 — Phone + forum UI (2–3 weeks)
|
||||
|
||||
- Phone as a holdable / pocketable `AItemActor`.
|
||||
- Apps: Camera + Gallery, Livestream (`StreamSession` tick object), Bank, Feetex, Maps, Health Tracker, Forum.
|
||||
- Photo system: pick render-to-texture (§17.6) — recommended for in-fiction photo posts.
|
||||
- Phone as an `AItemActor` (Phase 2 base) with hand / pocket / bag location semantics (§9).
|
||||
- Apps: Camera + Gallery, Livestream (`UStreamSession` tickable UObject — works while phone is held *or* placed, §9.1.1 exception), Bank, Feetex, Maps, Health Tracker, Forum.
|
||||
- Photo system: render-to-texture (§17.6 / §21 Q6 — recommended).
|
||||
- Wire `TakePhotoAtLocation` commission step to actual photo events.
|
||||
|
||||
**Exit criteria:** end-to-end photo loop — equip phone, capture photo, view in gallery, post to forum, follower count updates.
|
||||
**Exit criteria:** end-to-end photo loop — equip phone, capture photo, view in gallery, post to forum, follower count updates. Livestream can be started, run while the phone is set down, and ended with payout deposited.
|
||||
|
||||
### Phase 9 — Path progression + content authoring (2 weeks)
|
||||
|
||||
- Path XP per path, level gating on clothing / missions / attribute upgrades.
|
||||
- Author the vertical-slice content set from §18.1.
|
||||
- Author the vertical-slice content set from GDD §18.1 (15-20 clothing items, 3 bag variants, 8 food items, 20 commission templates, 1 functional district).
|
||||
- Masturbation gating (§5.1, §7.2) — actually hide the quick-action entry until Slut path level 1.
|
||||
|
||||
**Exit criteria:** all three paths have at least 5 unlockable items and 3 path-specific commission templates.
|
||||
**Exit criteria:** all three paths have at least 5 unlockable items and 3 path-specific commission templates. Slut-path-locked actions are correctly hidden / gated.
|
||||
|
||||
### Phase 10 — Remaining systems & polish
|
||||
|
||||
- Bag inventory (§6.4).
|
||||
- Food / cooking (§6.6).
|
||||
- Gym / beauty salon / adult shop (§10.4).
|
||||
- Rip and tear (§6.3.4).
|
||||
- Theft timer (§6.3.3).
|
||||
- Expose action (§6.3.5).
|
||||
- Restrictive-clothing flow (§6.3.6, §10.4.1).
|
||||
- Underwear selling (§15.1).
|
||||
- Wanted-poster takedown (§10.3).
|
||||
- Bag inventory (§6.4) — uses Phase 2's `AItemActor` for world placement.
|
||||
- Food / cooking (§6.7) — three minigames per the GDD (slice, stir, cook).
|
||||
- Gym / beauty salon / adult shop / cafe / convenience store (§10.4).
|
||||
- Rip & tear (§6.3.5).
|
||||
- Theft model (§6.3.4) — implement `T_grace` / `T_grace_bag` grace timers and per-tick `P_theft` chance roll. No ramp.
|
||||
- Expose action (§6.3.6) — read `CanExpose` per garment, blocked by overlapping coverage.
|
||||
- Restrictive-clothing flow (§6.3.7 / §10.4.1) — Key + timed unlock action. Lock hand-dependent actions while restrained.
|
||||
- Underwear selling (§15.1) — Feetex drop-box or location drop-off variant.
|
||||
- Wanted-poster takedown (§10.3) — interaction + spawn placement pass.
|
||||
- Final tuning: `T_grace`, `T_grace_bag`, `P_theft`, embarrassment / lust / energy / pulse rates (§21).
|
||||
|
||||
---
|
||||
|
||||
@@ -170,4 +229,7 @@ Phase estimates are rough and assume one engineer. Adjust as we go.
|
||||
|
||||
Use this section for in-flight decisions, blockers, and open questions that emerge during a phase. Move resolved items into the README's §20 "Resolved Design Decisions" or into git history.
|
||||
|
||||
- _empty_
|
||||
- **Phase 1 critical path:** the save-write-without-state bug is the most damaging current issue — any "save" call destroys progress. Fix the SaveSubsystem before anything else builds on save behaviour.
|
||||
- **Body-part enum migration:** the existing censorship code in `NakedDesireCharacter::OnClothingEquip` / `OnClothingUnequip` reads `EPrivateBodyPartType`. Migration to `EBodyPart` must update that path or the censorship visibility will silently desync.
|
||||
- **Slot-vocabulary cleanup will break BP references** — coordinate before deleting `Nipples` / `Anal` / `Vagina` from `EClothingSlotType`. The character constructor creates skeletal-mesh components keyed to those names; expect BPs in `Content/Blueprints/Player` to need a touch.
|
||||
- _empty beyond this point_
|
||||
Reference in New Issue
Block a user