diff --git a/PLAN.md b/PLAN.md index 6ba17f37..6e1b605a 100644 --- a/PLAN.md +++ b/PLAN.md @@ -13,7 +13,7 @@ State of the C++ module as of the latest pass. File references use `Source/Naked ### 1.1 Implemented - **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`). +- **Definition / instance split (GDD §6.1, §17.4)** — `Clothing/ClothingItem.h` is the immutable `UPrimaryDataAsset` definition. Most fields align with the current GDD: `Coverage`, `CanExpose`, `ContainerSlots` (typed S/M/L via `EGarmentContainerSlotType` + `FGarmentContainerSlot`), `ProgressionPath`, plus rendering data (`SkeletalMesh`, `Materials`, `StaticMesh`). The `IsUnderwear` and `IsRestrictive` fields also exist but **no longer match the locked spec** (§20 #20, §20 #21) — see §1.4 for the removal / migration work. - **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. @@ -33,7 +33,7 @@ State of the C++ module as of the latest pass. File references use `Source/Naked - **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 (§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`). Food-buff hookpoints (per-rate multipliers for stamina regen, embarrassment-gain resistance, lust-gain resistance — see GDD §6.7) are not in place; future Phase 10 work depends on the attribute simulation accepting external multipliers cleanly. -- **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. +- **Coverage (§6.3.2)** — `UClothingItem::Coverage` exists; `ClothingManager::IsBodyTypeExposed` (`ClothingManager.cpp:14-25`) is still binary. No `GetEffectiveCoverage(EBodyPart)` function. **The locked formula is now `max(coverage)` across garments covering a body part** — not sum, and no underwear halving (§20 #20). `UClothingItem::IsUnderwear` is dead spec and should be removed during the Phase 1 cleanup. - **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, no Accept lifecycle (§13.1 / §13.2), no path-filtering on the generator (§13.4). - **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). @@ -57,7 +57,7 @@ State of the C++ module as of the latest pass. File references use `Source/Naked - **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. +- **Restrictions system (§6.3.7 / §10.4.1)** — `IsRestrictive` boolean exists on `UClothingItem` but is now stale spec. The locked design is a **per-item `restrictions` list** with granular entries (`BlockRun`, `BlockCrouch`, `BlockPhoneUse`, `BlockItemPickup`, `BlockMasturbate`, `BlockExposeAction`, and parameterized `BlockSlotChange(slot)`). No code enforcement of any restriction flag; no Key-based unlock flow; no DBD-style unlock minigame (§10.4.1). - **Bodysuit exclusion rule (§6.5)** — when implementing the new slot enum, `ClothingManager` must auto-unequip `Top`/`Bottom`/`UnderwearTop`/`UnderwearBottom` on bodysuit equip, and vice versa. - **Toy slots (§6.5)** — `Nipples`, `Anal`, `Vagina` are now **toy slots** (not body-clothing slots, not body-parts conflict). Independent; all three can be active. Items in these slots are sex toys from the Adult Shop (§10.4), follow standard item-identity rules, do **not** contribute to coverage, and may modify lust / embarrassment / pulse plus add audible vibration NPCs may detect. - **Adult shop, gym, beauty salon, café, convenience store** — none. @@ -66,6 +66,14 @@ State of the C++ module as of the latest pass. File references use `Source/Naked - **Underwear selling (§15.1)** — absent. Backed by the `DeliverItemTo` typed objective (player-owned source only, §13.4). - **Endless mode flag (§3.3)** — absent. - **Pulse attribute (§7.5)** — absent (new in the updated GDD). +- **Hunger / max-energy decay (§7.3)** — absent. The new model has two layers of max energy: **base max** (gym progression) and **effective max** (decays via hunger). Eating any food restores effective max to base max as a universal built-in effect. Sleep does **not** clear hunger. `StatsManager` currently has only `MaxEnergy = 1000.0f` (`StatsManager.h:20`) — no hunger field, no decay tick, no eat-restores-hunger hook. +- **Police chase loss precedence (§4.4)** — when a chase is active and another loss fires, capture wins. No code logic for this yet (no chase exists, no precedence resolution in the loss path). +- **Holding-cell cutscene (§4.4)** — short non-interactive cutscene played when police capture and player can't pay. Time fast-forwards to next morning. Replaces the earlier "skip days proportional to debt" prose. Absent in code (no capture path exists yet). +- **Casino (§10.4.2)** — entire new location. Main floor (slots, blackjack, roulette), VIP room with per-day entrance fee, strip-game variants of blackjack and roulette that bet clothing items, lost-and-found inventory that retains `UItemInstance` identity for lost garments, mixed pacing (slots instant; table games burn in-game minutes), no poker. Significant scope: 3 minigames + VIP gating + strip-bet flow + lost-and-found UI. +- **Phone models + Electronics Shop (§9.9 / §10.4)** — three-tier phone (Starter / Mid / Pro) with three stat axes per tier (`camera quality`, `livestream quality`, `battery capacity`). New Electronics Shop location sells Mid and Pro. **Player can own multiple phones simultaneously**; only the equipped phone is active. Battery is per-phone-instance; hot-swap at the apartment wardrobe. Profile-side state (gallery, followers, history) does not move when swapping phones. +- **Restraint unlock minigame (§10.4.1)** — DBD-style skill checks. Successful hits speed up removal; misses have no penalty; no fail state. Restraint always comes off when the baseline timer expires. Absent (no restraint flow exists). +- **Instant commission rewards (§13.1 / §13.2 / §3.1 / §4.3)** — money / XP / followers credit at the moment of commission completion, not on return home. `UMissionsManager::CollectRewards` (`MissionsManager.cpp:35-51`) currently batches rewards into a manual "collect" call — this needs to be replaced with immediate crediting on `OnMissionCompleted`. +- **Hiding spots for ground items (§6.3.4)** — new bullet in the GDD that adds a hiding-spot concept; collides with the §4.4 "sleep = guaranteed loss" rule. Spec needs clarification before code (see Working notes). - **GAS adoption (§17.2)** — `StatsManager` is still a bespoke `UActorComponent`; no `UAttributeSet`, no `GameplayEffect`-driven modifiers. ### 1.4 Conflicts to resolve @@ -111,6 +119,9 @@ State of the C++ module as of the latest pass. File references use `Source/Naked - **`Money` representation** — `ANakedDesireCharacter::Money` is `int` (`NakedDesireCharacter.h:132`); `UGlobalSaveGameData::Money` is `float` (`GlobalSaveGameData.h:27`). Pick one authoritative location and one type. - **`STARTING_MONEY`** macro defined in `Constants.h:8` but unreferenced. Either wire it into save / character init or remove. - **`ClothingItemInstance` has no public constructor / factory** — `ClothingItem` pointer is `protected` with no `Init(UClothingItem*)`. Wardrobe / BuyItem flows rely on `EditAnywhere Instanced` design-time population, which won't support runtime purchase or save-driven hydration. +- **`UClothingItem::IsUnderwear` is dead spec** — `ClothingItem.h:82`. The locked design (§20 #20) drops the field entirely; `coverage` is authored directly to reflect the "just underwear" discount. Remove the field and any references during Phase 1. +- **`UClothingItem::IsRestrictive` is dead spec** — `ClothingItem.h:76`. The locked design (§20 #21) replaces the boolean with a granular `restrictions` list. Remove the boolean and add a `TArray` (or equivalent) supporting `BlockRun`, `BlockCrouch`, `BlockPhoneUse`, `BlockItemPickup`, `BlockMasturbate`, `BlockExposeAction`, and `BlockSlotChange(slot)`. Restriction evaluation is the union across all equipped items. +- **`UClothingItem` per-body-part coverage TODO is now resolved against** — `ClothingItem.h:61` carries `// TODO: Add coverage per body part`. The locked spec uses a single `coverage` value per item (multi body parts via `covers` set + `max()` formula, §6.3.2). The TODO comment should be removed; per-body-part coverage is intentionally not the model. - **`StatsManager::TickComponent` energy drain** — drains energy at a flat `0.9f` per tick (`StatsManager.cpp:26`) regardless of activity. GDD §7.3 specifies per-activity modifiers. - **`NPCSpawner` day window** — uses `Hours >= 9 && < 21` for "day" (`NPCSpawner.cpp:40`); GDD §10.1 says `08:00–20:00`. Off by one hour on each end. @@ -118,18 +129,25 @@ State of the C++ module as of the latest pass. File references use `Source/Naked - **Loss resolver** must not strip equipped clothing (§4.4). - **Energy = 0** must trigger a "cutscene → apartment → sleep" flow, not a teleport (§4.4). - **Embarrassment = max** must fade to apartment with **no extra cost** (no time skip, no money penalty, no rep hit) — GDD §4.4. + - **Police chase precedence (§4.4):** if a chase is active when any other loss fires, the loss resolves as police capture — chase wins. + - **Police capture, can't pay (§4.4):** short non-interactive holding-cell cutscene + time skip to next morning. Replaces the earlier "skip days proportional to debt" model. - **Theft** is a chance-based model with grace periods and flat per-tick `P_theft`, not a ramping curve (§6.3.4). - - **Sleep** is the deterministic side of clothing loss — guaranteed loss of every clothing item left outside the apartment (§4.4). - - **No Helper NPC**; restraint removal is **Key + timed unlock only** (§10.4.1). - - **Masturbation** is **Slut-path gated** — generator must filter `PerformAction(masturbate)` for non-Slut players; quick-action entry must hide until unlocked (§5.1 / §7.2 / §14.1). + - **Sleep** is the deterministic side of clothing loss — guaranteed loss of every clothing item left outside the apartment (§4.4). Hiding-spots bullet in §6.3.4 currently contradicts this — see Working notes. + - **No Helper NPC**; restraint removal is **Key + timed-unlock action with a DBD-style skill-check minigame** (§10.4.1). Successful checks speed up removal; missed checks have no penalty; restraint always comes off when the baseline timer expires. + - **Per-item `restrictions` list** replaces `IsRestrictive` boolean (§6.3.7). Granular vocabulary: `BlockRun`, `BlockCrouch`, `BlockPhoneUse`, `BlockItemPickup`, `BlockMasturbate`, `BlockExposeAction`, parameterized `BlockSlotChange(slot)`. Restrictions union across equipped items. + - **Coverage math** is `max()` across garments covering a body part — not sum. No underwear halving; the `IsUnderwear` flag is removed entirely (§6.3.2). + - **Hunger / max-energy decay (§7.3):** two-layer max energy — base (gym) and effective (decays via hunger, restored by eating). Eating any food triggers the restoration as a universal built-in effect. Sleep does not clear hunger. + - **Masturbation** is **Slut-path gated** — generator must filter `PerformAction(masturbate)` for non-Slut players; quick-action entry must hide until unlocked (§5.1 / §7.2 / §14.1). (Note: the README has a current contradiction about home-masturbation for non-Slut players — see Working notes.) - **Police** spawn day **and** night while `wanted` (§7.7 / §10.3). - **XP is a single shared pool, not per-path** — Phase 9 implementation must use a shared XP counter; a path's level is derived from how many upgrades the player has bought from that path's attribute pool (§5, §7.10). - - **Commission lifecycle:** explicit Accept required for daily *and* weekly; un-accepted commissions carry no penalty; weekly rewards now include followers (§13.1 / §13.2). + - **Commission lifecycle:** explicit Accept required for daily *and* weekly; un-accepted commissions carry no penalty; weekly rewards now include followers (§13.1 / §13.2). **Rewards land instantly on completion** — money / XP / followers credit at the moment the commission completes; no return-to-home "collect rewards" step. Replace the manual `UMissionsManager::CollectRewards` flow with immediate crediting on `OnMissionCompleted`. - **Commission generator** must respect `pathRequirement` (incl. `None` = path-neutral) and filter templates whose steps reference path-locked actions (§13.4). `failurePenalty` field is canonical; generator supplies tier-scaled default when empty. - **`DeliverItemTo`** must source from player inventory only; commission does not auto-issue items. Worn-underwear sales (§15.1) are the canonical use case (§13.4). - **Livestream → follower trickle** via `FollowerGainCalculator` per tick; signed by reputation. Tip requests give an additional bonus on completion (§9.1.1 / §13.5). - - **Locations locked for launch:** Beach + Train Station are in; School exterior and Hot springs were cut. Vertical slice is the basic shop set only (§10.4, §18.1). - - **Food vocabulary locked:** 2 instant effects + 4 timed buffs; same-type stacks additively up to a cap; never poison (§6.7). + - **Phone models (§9.9):** three tiers with three stat axes each (camera quality, livestream quality, battery capacity). Bought at the new Electronics Shop. Player may own multiple phones; gallery / followers / stats live on the profile (not the phone); battery is per-phone-instance. + - **Casino (§10.4 / §10.4.2):** main floor (slots / blackjack / roulette, money only), VIP room (per-day entrance fee), strip-game blackjack and roulette tables in VIP that bet clothing. Lost garments go to a casino lost-and-found inventory that retains `UItemInstance` identity. Mixed pacing. + - **Locations locked for launch:** Beach + Train Station + Casino + Electronics Shop are in; School exterior and Hot springs were cut. Vertical slice is the basic shop set only (§10.4, §18.1). + - **Food vocabulary locked:** 2 instant effects (energy restore, lust decrease) + 4 timed buffs (stamina regen +, max stamina +, embarrassment-gain resistance, lust-gain resistance); same-type stacks additively up to a cap; never poison (§6.7). Plus the universal "eating restores effective max energy" hunger reset. --- @@ -157,6 +175,8 @@ Phase estimates are rough and assume one engineer. Adjust as we go. - **Reshape `EClothingSlotType` to the locked 18-slot list (§1.4 table).** Add `Outerwear`, `WristRestraint`, `AnkleRestraint`, `NeckRestraint`. Rename `Bra → UnderwearTop`, `Panties → UnderwearBottom`, `Body → Bodysuit`, `Shoes → Footwear`. Add four new `USkeletalMeshComponent`s in `NakedDesireCharacter` for the new slots. Update BP references in lockstep. - **Implement Bodysuit exclusion** in `ClothingManager::PutOnClothing` (auto-unequip `Top`/`Bottom`/`UnderwearTop`/`UnderwearBottom`; vice versa). - **Define toy items**: either a new `USexToyItem : UItemInstance` (recommended) or extend `UClothingItem` with a toy variant. Toy items target `Nipples` / `Anal` / `Vagina` slots, carry lust / embarrassment / pulse modifier fields, and an optional NPC-audible-vibration flag. Do not contribute to coverage. +- **Drop dead spec from `UClothingItem`**: remove `IsUnderwear` (`ClothingItem.h:82`) and `IsRestrictive` (`ClothingItem.h:76`); remove the `// TODO: Add coverage per body part` comment on line 61 (resolved against — single `coverage` is locked spec). +- **Replace `IsRestrictive` with a `restrictions` list** on `UClothingItem`: `TArray` (struct with `ERestrictionType` enum + optional `EClothingSlotType` parameter for `BlockSlotChange`). No runtime enforcement yet (Phase 4 / 10 own that) — Phase 1 just needs the data field, the struct, and the enum. - Money: pick one authoritative location (`UGlobalSaveGameData`), make `ANakedDesireCharacter::Money` a read-through. Apply `STARTING_MONEY` at new-save creation. Reconcile int vs. float. - Remove dead `UClothingList` forward declarations. @@ -180,12 +200,14 @@ Phase estimates are rough and assume one engineer. Adjust as we go. - `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: + - **Police chase precedence**: if a chase is active (between detection and the disengage timer, §10.3), force `Cause = PoliceCapture` regardless of what triggered the loss. Chase always wins. - Equipped clothing **stays** equipped (do not strip). - Bag placed in world: mark its world record for deletion. - Loose clothing on ground: leave as-is at this stage; sleep step finalizes any guaranteed loss. - **Energy = 0**: trigger a cutscene → apartment → sleep cycle → guaranteed loss of every world clothing outside the apartment. - **Embarrassment = max**: fade to apartment. **No extra cost** (no time skip, no money, no rep). - - **Police capture**: fade to apartment, deduct money penalty, queue skipped days for the unpaid remainder, clear `wanted`. + - **Police capture (can pay)**: fade to apartment, deduct money penalty, clear `wanted`. + - **Police capture (can't pay)**: short non-interactive holding-cell cutscene; time fast-forwards to next morning; debt settled; clear `wanted`. Already-accepted commissions still expire at day end with their normal `failurePenalty` — the cutscene does not pause the day clock. - Wire `StatsManager::IncreaseEmbarrassment` max-hit and energy-zero into `USessionLossResolver`. Replace `EndGameEmbarrassed` BP-event with the C++ path. - Add a debug overlay showing the current loss state and what would be lost if a given cause fired. @@ -195,7 +217,8 @@ Phase estimates are rough and assume one engineer. Adjust as we go. - Decision: GAS vs. extended `StatsManager`. Recommend GAS — the embarrassment formula has Pulse, Recognition, Coverage, Day/Night, per-NPC-type weights, and food-buff multipliers (§7.1, §6.7), which is exactly what `UGameplayEffect` is shaped for. - Add Lust (§7.2), **Pulse (§7.5)**, Recognition (§7.6), Wanted (§7.7), Reputation (§7.8), Followers (§7.9). Money remains in the save schema directly (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 `0.0f` stub in `StatsManager::TickComponent`. +- **Hunger / max-energy decay (§7.3):** add a second layer to max energy. `baseMaxEnergy` (gym progression) stays; introduce `effectiveMaxEnergy` (decays at `maxEnergyDecayRate` per in-game hour toward a floor). Eating any food sets `effectiveMaxEnergy` back to `baseMaxEnergy` as a universal hook in the eat-item flow. Sleep does **not** reset hunger. Health Tracker (§9.7) surfaces effective max alongside current energy. +- Implement `GetEffectiveCoverage(EBodyPart)` on `ClothingManager` per §6.3.2 — **`max()` across garments covering the part** (no sum, no underwear halving). Replace the `0.0f` stub in `StatsManager::TickComponent`. - Lust → masturbate action (Slut-path gated, §7.2). Block the action in BP / quick-action when the player has no Slut investment. - **Pulse simulation:** rises with running, masturbation, exposure events; decays toward baseline at rest. Modifies embarrassment and lust gain rates (§7.5). - Recognition rise from Blogger photo events; **face-cover bypass via `Face` + `Eyes` slots** (§7.6); reduction via news-site reporting (§11.1). @@ -210,7 +233,7 @@ Phase estimates are rough and assume one engineer. Adjust as we go. ### Phase 5 — Time + calendar + rent + sleep (3–4 days) - `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. +- Sleep action on apartment bed: triggers the same path as energy-zero (§4.4) for the "items left outside" cleanup, restores energy (clamped to current effective max), autosaves, advances calendar. **Charges the equipped phone to 100%** (§9.8). **Does NOT reset hunger** (§7.3) — only eating clears effective-max decay. - Weekly rent transaction at week boundary; eviction if money insufficient (game over (run), §3.3). - **Weekly follower-income auto-deposit** to the bank at week boundary (§7.9, §9.4). - Endless-mode flag on `UGlobalSaveGameData`; rent-eviction branch checks it. @@ -243,9 +266,10 @@ Phase estimates are rough and assume one engineer. Adjust as we go. - Both daily and weekly require explicit Accept on the forum. - Un-accepted commissions carry no penalty; accepted-but-failed apply the template's `failurePenalty`. - Weekly rewards include followers; weekly `failurePenalty` is heavier than daily. +- **Instant rewards on completion (§13.1 / §13.2 / §3.1 / §4.3):** money wires to the bank, XP credits to the shared pool, followers update on the profile **at the moment of completion** — not on return home. Replace the current `UMissionsManager::CollectRewards` batched flow with immediate crediting in `OnMissionCompleted`. There is no "collect rewards" step at the apartment. - **Generator rules:** respect `pathRequirement` (incl. `None`); filter path-locked-action templates by player path investment; substitute a tier-scaled default penalty when `failurePenalty` is empty. -**Exit criteria:** daily commissions regenerate from templates each in-game day; weekly arc is distinct; explicit Accept committed flow works end-to-end; failed accepts deduct the template penalty; un-accepted commissions never penalize the player. +**Exit criteria:** daily commissions regenerate from templates each in-game day; weekly arc is distinct; explicit Accept committed flow works end-to-end; rewards credit instantly on completion (no return-home gate); failed accepts deduct the template penalty; un-accepted commissions never penalize the player. ### Phase 8 — Phone + forum UI + battery + livestream (3–4 weeks) @@ -267,8 +291,15 @@ Phase estimates are rough and assume one engineer. Adjust as we go. - **Tip requests:** phone popup with Accept / Decline + countdown. Accept = spawn live objective tracker (reuse Phase 7 primitives). Complete = tip lands + small follower bonus. Fail = viewer count drops (less passive income for the remainder); no rep hit. Decline / timeout = no effect. - Photo system: render-to-texture (§17.6 / §21 Q5 — recommended). - Wire `TakePhotoAtLocation` commission step to actual photo events. +- **Phone models + Electronics Shop (§9.9 / §10.4):** + - 3 tiers (Starter / Mid / Pro). Each is a `UClothingItem`-style data asset (or dedicated `UPhoneItem` definition) with `CameraQuality`, `LivestreamQuality`, `BatteryCapacity` multipliers. + - Starter is owned at game start. Mid and Pro are bought in-person at the new **Electronics Shop** location (interactable like Wardrobe / Adult Shop). + - Player can own multiple phones simultaneously — store them in the wardrobe / inventory as regular `UItemInstance`s. Only the equipped phone is active. + - Hot-swap from the apartment wardrobe; battery percentage is per-phone-instance and **does not transfer** on swap. + - Profile state (gallery, follower count, livestream history) lives on the player profile, never on the phone — swapping phones does not move or duplicate this state. + - `CameraQuality` multiplies `exposureScore` for photo posts (§13.5). `LivestreamQuality` multiplies per-tick `streamQualityScore`. `BatteryCapacity` multiplies the total charge budget (drain rates unchanged). -**Exit criteria:** end-to-end photo loop (capture → gallery → post → follower count updates). Livestream can be started, run while the phone is placed, generate trickle followers + donations, accept and complete a tip request for a bonus, end with payout. Battery drain visibly different per app; charger and powerbank both restore charge; 0% hard-shutdown behaves correctly. +**Exit criteria:** end-to-end photo loop (capture → gallery → post → follower count updates). Livestream can be started, run while the phone is placed, generate trickle followers + donations, accept and complete a tip request for a bonus, end with payout. Battery drain visibly different per app; charger and powerbank both restore charge; 0% hard-shutdown behaves correctly. Buying a Mid / Pro phone at the Electronics Shop adds it to the wardrobe; equipping it visibly improves photo / stream gain rates per the multipliers. ### Phase 9 — Path progression + content authoring (2 weeks) @@ -285,17 +316,25 @@ Phase estimates are rough and assume one engineer. Adjust as we go. - Bag inventory (§6.4) — uses Phase 2's `AItemActor` for world placement. - **Food (§6.7):** - Implement the locked vocabulary: 2 instant effects (energy restore, lust decrease) + 4 timed buffs (stamina regen +, max stamina +, embarrassment-gain resistance, lust-gain resistance). + - Universal built-in effect: every food restores effective max energy to base max (hunger reset; §7.3 hookpoint from Phase 4). - Stacking: different types parallel; same type additive to a per-type cap. - Three cooking minigames (slice / stir / cook); scoring modulates buff strength; never poison. - Gym / beauty salon / adult shop / café / convenience store (§10.4). Convenience Store stocks powerbanks (Phase 8 dep). Adult Shop stocks toy items for the three toy slots (Phase 1 dep). - 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. +- **Theft model (§6.3.4)** — implement `T_grace` / `T_grace_bag` grace timers and per-tick `P_theft` chance roll. No ramp. Hiding-spot mechanic is currently spec-ambiguous (see Working notes) — coordinate before implementing. +- Expose action (§6.3.6) — read `CanExpose` per garment, blocked by overlapping coverage. Also blocked when `BlockExposeAction` is active in the restrictions set. +- **Restrictions enforcement (§6.3.7 / §10.4.1):** + - Wire each `Block*` flag into the relevant subsystem (`BlockRun` into movement, `BlockPhoneUse` into `PhoneSubsystem`, `BlockMasturbate` into the quick action, `BlockSlotChange(slot)` into `ClothingManager::PutOnClothing` / `RemoveClothing`, etc.). + - **Restraint removal:** Key + timed-unlock action with a **DBD-style skill-check minigame** (§10.4.1). Rotating pointer + target zone; hits speed up removal; misses do nothing; no fail state. Restraint always comes off when the baseline timer expires. +- **Casino (§10.4 / §10.4.2):** new location, significant scope. + - Three game UIs: slots (instant single-button), blackjack (vs. dealer NPC, in-game-minute pacing), roulette (multi-bet single spin, in-game-minute pacing). No poker. + - VIP room interactable: pay per-day entrance fee at reception; access flag clears at next day boundary. + - Strip-game blackjack and roulette tables in VIP: bet a clothing item from an equipped slot. Lost garments transfer to a **casino lost-and-found** safe inventory keyed to the player; retains `UItemInstance` identity per §6.1. Reclaim by winning back at the same table or paying a flat buy-back fee at reception. + - Wire casino income/loss into the Bank app income breakdown (§9.4). - Underwear selling (§15.1) — Feetex drop-box or location drop-off variant. Backed by `DeliverItemTo(npcOrLocation)` from Phase 7. - Wanted-poster takedown (§10.3) — interaction + spawn placement pass. - Beach + Train Station locations (§10.4) for full-launch scope. -- Final tuning of all §21 numbers (theft, food caps, battery, tip-request distribution, embarrassment / lust / energy / pulse rates, face-cover magnitudes, etc.). +- Final tuning of all §21 numbers (theft, food caps, battery, tip-request distribution, embarrassment / lust / energy / pulse rates, face-cover magnitudes, casino RTP + VIP fee, phone-tier multipliers, restraint minigame parameters, hunger decay, etc.). --- @@ -309,4 +348,9 @@ Use this section for in-flight decisions, blockers, and open questions that emer - **Toy items vs. clothing items:** the `UClothingItem` schema (coverage, `CanExpose`, `IsRestrictive`) doesn't fit sex toys cleanly. Strongly recommend a separate `USexToyItem : UItemInstance` (with `LustModifier`, `EmbarrassmentModifier`, `PulseModifier`, `VibrationAudible` fields) rather than overloading `UClothingItem`. Decide before Phase 1 toy work begins. - **XP is a single shared pool** (GDD §5, §7.10). Do not introduce per-path XP counters in Phase 9 or earlier — a path's level is derived from how much the player has invested into that path's attribute pool. - **Food buff hookpoints belong in Phase 4** (attribute multiplier interface), even though the food items themselves ship in Phase 10. Leave the seams; don't retrofit later. +- **Hunger hookpoint also belongs in Phase 4.** Add `effectiveMaxEnergy` + decay tick when adding Lust / Pulse / etc., so Phase 10's food items only need to call an existing reset method. +- **README contradiction — follower income cadence.** §7.9 line 433 says "Followers generate money each day"; §9.4 and §13.3 say weekly auto-deposit at week boundary. Don't pick one in code until the GDD is reconciled. Phase 5 implementation depends on resolution. +- **README contradiction — hiding spots vs sleep loss.** §6.3.4's new "Hiding spots" bullet says items have a *chance* of theft after sleep, but §4.4 says sleep = guaranteed loss of anything outside. Phase 10 theft work must wait until the GDD resolves whether hiding spots are an explicit exception to the sleep rule or only affect in-session theft chance. +- **README contradiction — masturbation gating.** §7.2 says non-Slut players "must accept the max-lust handicaps... until they go home and masturbate in home before sleep" — but §5.1 has masturbation as a Slut-path unlock. Phase 4 masturbate-action work needs the spec reconciled: either home masturbation is universally available (with public masturbation gated by path) or non-Slut players cannot masturbate at all. +- **Stale §5.3 Slave path text** in the README still says "(cuffs require NPC help to remove)" — contradicts the Key + minigame removal flow. Phase 6 / Phase 10 work should not implement an NPC removal path; if encountered, treat it as stale documentation. - _empty beyond this point_ diff --git a/README.md b/README.md index 440fe9b4..6b46e21a 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ A sandbox exhibitionist life-sim where the player accepts fetish commissions fro Yumi, while browsing the internet after a rent increase, discovers a hidden fetish forum that pays for exposure-themed commissions. After completing her first task she realizes she enjoys it. She begins taking commissions to cover rent and explore the new feelings. ### 2.2 Setting -A modern Japanese-style city. Currency is Yen. The city is the entire playable map: residential, commercial, parks, alleys, a beach, a train station, a gym, a beauty salon, multiple shop types, the player's apartment. See §10.4 for the locked location list. +A modern Japanese-style city. Currency is Yen. The city is the entire playable map: residential, commercial, parks, alleys, a beach, a train station, a casino, a gym, a beauty salon, an electronics shop, multiple other shop types, the player's apartment. See §10.4 for the locked location list. ### 2.3 Tone Sexual, playful, transgressive. The player character is a willing participant, not a victim. The "stalker" NPC is the only non-consensual antagonist and exists as a session-loss threat, not a narrative one. @@ -58,8 +58,8 @@ Sexual, playful, transgressive. The player character is a willing participant, n 2. Plan: check commissions, check bank, check pending deliveries, check news/recognition. 3. Equip outfit from wardrobe. Pack bag (optional). 4. Leave the house → **session begins**. -5. Travel to commission locations, complete tasks, manage attributes. -6. Return home → **session ends**, rewards finalized, optional sleep. +5. Travel to commission locations, complete tasks, manage attributes. Each completion immediately wires money to the bank, credits XP, and updates followers — no return-to-home collection step. +6. Return home → **session ends**, optional sleep. 7. Spend earnings (shops, gym, beauty salon), level up attributes, post photos. 8. Repeat. Pay rent at end of week. @@ -88,10 +88,14 @@ Triggered by leaving the apartment. Snapshots current equipment, attributes, and - The player can freely re-enter the apartment to safely end the session at any time. ### 4.3 Session end (safe) -Player returns home. All carried items persist. Rewards from completed commissions are finalized. Embarrassment resets toward baseline. If a Snitch reported the player to police during the session (§10.2), the player keeps the `wanted` tag even after a safe return — see §7.7. +Player returns home. All carried items persist. Embarrassment resets toward baseline. Commission rewards (money, XP, followers) are *not* finalized at session end — they were already credited at the moment each commission completed (§13.1 / §13.2). If a Snitch reported the player to police during the session (§10.2), the player keeps the `wanted` tag even after a safe return — see §7.7. ### 4.4 Session end (loss) -Triggered by any session-loss condition (§3.3). On loss: +Triggered by any session-loss condition (§3.3). + +**Precedence — police chase wins.** If the player is being actively chased by police (between detection and the disengage timer, §10.3) at the moment another loss condition fires, the loss is **always resolved as police capture**. The cops catch them as they collapse or freeze; the chase outcome supersedes embarrassment-max and energy-zero outcomes (including the energy-zero sleep cutscene). This applies whether or not the player has the `wanted` tag in advance — being mid-chase is the trigger, not the tag. + +On loss: - **The player returns to the apartment.** The route home depends on the cause: - **Energy = 0** — a cutscene plays of the player trudging home, exhausted, and going to bed. The player never sleeps outside; the apartment bed is the only sleep location. Time advances by one sleep cycle. - **Embarrassment = max** — fade to apartment. No extra cost beyond the session loss itself (no time skip, no money penalty, no reputation hit). @@ -101,7 +105,7 @@ Triggered by any session-loss condition (§3.3). On loss: - **Unequipped clothing left on the ground** can be lost two ways: 1. **In-session theft** — a chance-based roll while the player is away from the item. See §6.3.4 for the model. 2. **Sleep** — any clothing left outside the apartment when the player sleeps is **guaranteed** lost. This fires both for the energy-zero cutscene (forced sleep) and for voluntary sleep at home with items still outside. -- **Police capture** during pursuit applies a money penalty. If the player can't cover it, they skip days until the debt clears; the number of skipped days scales with the unpaid amount. Capture also clears the `wanted` tag (§7.7). +- **Police capture** during pursuit applies a money penalty. If the player can cover it, the debt is paid and they are returned to the apartment. If they **can't cover it**, a short cutscene plays of the player in a **holding cell**, then time fast-forwards to the next in-game morning — the night served settles the penalty, no money is owed afterward. The cutscene is non-interactive; the player does not actually inhabit the cell. Capture clears the `wanted` tag (§7.7) in either case. Already-accepted commissions still expire at day end with their normal `failurePenalty` (§13.4); the cutscene does not pause that clock. > **Implementation note:** session loss must be a clearly defined transactional state. All "what gets lost" logic should live in a single SessionLossResolver to keep this deterministic and debuggable. @@ -145,7 +149,7 @@ Each path has a level (e.g., 1–10). Level gates clothing, missions, and attrib ### 6.2 Carriable item categories - **Clothing** (§6.3) - **Bags** (§6.4) -- **Phone** (one — special, §9) +- **Phone** (one active at a time, but the player may own multiple models simultaneously — §9, §9.9) - **Consumables** (food, §6.7) - **Toys** — sex toys for the toy slots (§6.5). Bought at the Adult Shop (§10.4). @@ -157,11 +161,10 @@ Attributes per clothing instance: - `covers` — set of body parts: `{ boobs, ass, genitals, ... }`. - `progressionPath` — Slut / Exhibitionist / Slave / None. - `color` — primary color enum. -- `coverage` — float [0,1]. -- `isUnderwear` — bool. If true, effective coverage = `coverage / 2`. +- `coverage` — float [0,1]. Authored per item to reflect how much it conceals — including the psychological "this is just underwear" discount. There is no separate underwear flag; an item in `UnderwearTop` / `UnderwearBottom` is simply authored with a lower `coverage` than a similarly-sized non-underwear garment. - `condition` — float [0,1]. Starts at 1.0 (new). Decreases via §6.3.4. - `canExpose` — list of body parts this garment can momentarily reveal without unequipping (e.g., coat → boobs, ass). -- `isRestrictive` — bool. If true, restricts hand use; requires NPC to remove. +- `restrictions` — list of restriction entries that fire while this item is equipped (e.g., wrist cuffs block phone use and changing top clothing; ankle cuffs block running). Most items have an empty list. See §6.3.7 for the full vocabulary. - `containerSlots` — optional inventory (e.g., pants pocket for phone). #### 6.3.1 Container slots @@ -171,10 +174,12 @@ Container slot allows player to carry items there. #### 6.3.2 Coverage resolution For each body part `b`: -- Find the set of equipped garments covering `b`. -- Effective coverage of `b` = `min(max(effectiveCoverage of garments covering b), 100%)` where `effectiveCoverage = isUnderwear ? coverage/2 : coverage`. +- Find the set of equipped garments whose `covers` set includes `b`. +- Effective coverage of `b` = `max(coverage of garments covering b)`. Only the highest-coverage garment per body part counts; layering does not stack. - Body part is "exposed" if effective coverage = 0. -- Lower total coverage → faster embarrassment gain when observed (§7.1). +- Lower coverage → faster embarrassment gain when observed (§7.1). + +Authoring guidance: underwear in `UnderwearTop` / `UnderwearBottom` should be authored with lower `coverage` than equivalently-shaped outerwear in `Top` / `Bottom`, so being seen in just underwear correctly reads as more exposed than being seen in a thin shirt of the same physical coverage. The math itself does not special-case underwear — the value in the editor is the contribution, full stop. #### 6.3.3 Equipping & unequipping - Equip/unequip anywhere in the world via the quick action menu. @@ -203,9 +208,36 @@ Theft applies to lose clothing on the ground and to bags placed in the world (se - Blocked if another garment covers the same part (e.g., pants block coat's ass-expose). - While exposed, the body part counts as fully uncovered for embarrassment math. -#### 6.3.7 Restrictive clothing* -- Cuffs, restrain bars and similar items lock hand-dependent actions (using phone, picking up items, masturbating). -- Can be removed by having key and spending some time to remove it. +#### 6.3.7 Restrictions +Each clothing item carries an optional `restrictions` list. Most items have none. Restraint-slot items (§6.5 slots 13–15) declare meaningful lists; a few non-restraint items (heels, tight skirts) can declare lighter restrictions too. + +Restrictions are the union of all entries on all equipped items — any restraint that declares a given flag activates it for the player, regardless of which equipped item provides it. + +Vocabulary: + +| Restriction | Effect while at least one equipped item declares it | +|--------------------------|------------------------------------------------------------------------------------------------------------------| +| `BlockRun` | Player cannot run. Movement capped at walk speed. | +| `BlockCrouch` | Player cannot enter the crouch state. | +| `BlockPhoneUse` | The phone (§9) is unusable — no apps, no camera, no livestream, even when in hand / pocket / bag. | +| `BlockItemPickup` | Cannot pick up world items. | +| `BlockMasturbate` | The masturbate quick action (§14.1) is disabled. A commission objective requiring masturbation cannot progress until cleared. | +| `BlockExposeAction` | The per-garment expose action (§6.3.6) is disabled. | +| `BlockSlotChange(slot)` | The named equipment slot cannot be (un)equipped while the declaring item is on. Multiple `BlockSlotChange(...)` entries on one item are allowed and stack. | + +Authored examples: + +- **Wrist cuffs** (`WristRestraint`): `BlockPhoneUse`, `BlockItemPickup`, `BlockMasturbate`, `BlockExposeAction`, `BlockSlotChange(Top)`, `BlockSlotChange(Outerwear)`, `BlockSlotChange(UnderwearTop)`, `BlockSlotChange(Bodysuit)`. +- **Ankle cuffs** (`AnkleRestraint`): `BlockRun`, `BlockSlotChange(Bottom)`, `BlockSlotChange(Footwear)`, `BlockSlotChange(Socks)`, `BlockSlotChange(UnderwearBottom)`. +- **Spreader bar** (`AnkleRestraint`): same as ankle cuffs, plus `BlockCrouch`. +- **High heels** (`Footwear`, non-restraint): `BlockRun` only. +- **Tight pencil skirt** (`Bottom`, non-restraint): `BlockRun`, `BlockCrouch`. + +**Removal:** +- Restraint-slot items typically declare `BlockSlotChange()`, which means the player cannot remove them via normal unequip. These require the Key + timed-unlock action in §10.4.1. +- Non-restraint restrictive items (heels, skirts) remove via normal unequip as long as no other equipped item is blocking the slot change. + +**Commission interaction:** an accepted commission whose objective needs a blocked action (e.g., `PerformAction(masturbate)` with `BlockMasturbate` active) does not auto-fail; it simply cannot progress until the restriction is cleared. The commission's day / week deadline still applies normally. ### 6.4 Bags - Bag is an equippable item with its own inventory. @@ -265,7 +297,7 @@ Sex toys are bought from the Adult Shop (§10.4) and follow the standard item-id #### Other equipment - **Bag slot** — 1 (see §6.4). -- **Hand slot** — 1. Holds one carriable item at a time (phone, food, key, etc.). Any item in `WristRestraint` disables all hand-dependent actions (§6.3.7). +- **Hand slot** — 1. Holds one carriable item at a time (phone, food, key, etc.). Hand-dependent actions (phone use, item pickup, masturbate, expose action) are disabled when an equipped item declares the corresponding `Block*` restriction (§6.3.7); wrist cuffs are the canonical case. #### Container slots - Each equipped clothing item may expose container slots (e.g., pants pocket). The equipped bag exposes container slots as well. Each container slot has a size class (S / M / L, §6.3.1) that constrains what fits. @@ -285,8 +317,11 @@ Sex toys are bought from the Adult Shop (§10.4) and follow the standard item-id Food items live in the `UItemInstance` system (§6.1). They come from two sources: **ingredients** at the Convenience Store (require cooking) and **pre-made** food at the Café (eat immediately). Eating consumes the item and applies any combination of the effects below. -**Instant effects** (one-shot on consumption, no timer): -- **Energy restore** — adds a fixed amount of energy (§7.3). +**Built-in effect** (applies on any eating action, not per-food authored): +- **Effective max energy fully restored** — eating resets the hunger decay (§7.3). Effective max energy returns to the base max. This effect is universal — every food, no matter how small, fully clears hunger. + +**Instant effects** (one-shot on consumption, no timer, per-food authored): +- **Energy restore** — adds a fixed amount of current energy (§7.3), clamped to the (just-restored) effective max. - **Lust decrease** — subtracts a fixed amount of lust. Particularly relevant for non-Slut players who cannot masturbate to reset lust (§7.2). **Timed buffs** (run for a per-item duration): @@ -345,8 +380,15 @@ All attributes update in real time. Indoor and outdoor behavior is identical — - `energyDrainMasturbateModifier` (masturbation) - Recovered during sleep at `energyRecoveryRate`. - Hard floor at 0 → session lost. -- Max raised by gym training. -- Low energy reduces effective max stamina (see §7.4). +- Low effective energy reduces effective max stamina (see §7.4). + +**Max energy has two layers:** +- **Base max energy** — the player's underlying ceiling. Raised by gym training (the progression lever). +- **Effective max energy** — the *current* ceiling on energy. This is what the player's energy bar can actually reach. Effective max **decays over time** at a hunger rate (`maxEnergyDecayRate`, TBD per §21), down to a floor (TBD, expressed as a fraction of base max) so the player is never fully starved into a forced game-over. +- **Eating any food (§6.7) restores effective max energy fully to base max** — this restoration overrides all other buffs and is the canonical way to reset hunger. It is a built-in effect of the eating action, not a per-food authored flag; every food does it. +- Recovered energy (sleep, instant-restore foods) is always clamped to effective max — sleeping does not also reset hunger; only eating does. + +Together these mean a player who never eats slowly loses their available energy headroom each day, even with full sleep. The 90-day campaign forces a steady food cadence rather than allowing pure sleep cycling. ### 7.4 Stamina - Used for running and other burst physical actions. @@ -419,12 +461,14 @@ The phone is battery-powered (§9.8). A dead phone is unusable until charged — - **Front camera** — held in hand, framed selfie shot. - **Back camera** — phone is placed in the world via `place camera` action. A floating window shows the camera's view. Photos are triggered via hotkey while the camera is placed. - All photos saved to **Gallery**. +- Photo follower gain is multiplied by the equipped phone's **camera quality** stat (§9.9). Better phone → more followers per equivalent shot. ### 9.1.1 Livestream - Available at any time via the phone, regardless of whether the player is holding it or it is placed in the world. - Same dual-mode setup as the camera: front-facing while held, back-facing when placed. - Generates donation income in real time. Income rate scales with exposure visible in the stream (similar logic to photo follower-gain math, but continuous). - Also grows **followers** in a continuous trickle. The live `streamQualityScore` is fed into `FollowerGainCalculator` (§13.5) per tick at a tunable rate; gains accumulate over the stream. Reputation sign applies — streaming with negative reputation shrinks the audience instead of growing it. +- `streamQualityScore` is multiplied by the equipped phone's **livestream quality** stat (§9.9). Better phone → higher donation rate and faster follower trickle from an identical scene. - Recommended implementation: livestream is a `StreamSession` object owned by the phone, tickable, with `viewerCount`, `tipRate`, and `streamQualityScore` (a function of what the camera sees and player attributes). - Ending the stream returns earnings to the bank and finalizes the accumulated follower delta. - **Tip requests.** During an active stream, viewers post named action requests with a fixed yen reward attached. Each request is a small commission expressed in the §13.4 typed objective vocabulary — e.g. `ExposeBodyPart(boobs, 8s)` for a small tip, `BeFullyNaked(15s)` for a medium tip, `TakePhotoAtLocation(fountain)` for a large tip. The full tip-size range is wide; occasional high-roller requests pay several times a normal commission for correspondingly demanding objectives. @@ -453,6 +497,7 @@ The phone is the primary access point for the forum. See §13. ### 9.7 Health Tracker - Displays the player's attribute readouts (energy, stamina, lust, embarrassment, recognition). +- Shows **effective max energy** alongside current energy so the player can read hunger state (§7.3) — the gap between base max and effective max is the "how hungry am I" signal. ### 9.8 Battery The phone has a finite battery that drains while powered on and recharges at the apartment. @@ -472,6 +517,31 @@ The phone has a finite battery that drains while powered on and recharges at the - The phone can still accept a powerbank charge from the player's inventory — consuming a powerbank wakes the phone at the powerbank's restore percentage. Without a powerbank, the phone stays dead until the player reaches an apartment charger. - **Sleep.** Sleeping at the apartment always charges the phone to 100%, whether or not the player explicitly docked it on the charger. This applies equally to voluntary sleep and to the energy-zero cutscene (§4.4) — that cutscene's sleep cycle includes the charge-to-full step. - **Persistence.** Current battery percentage is part of the phone's `UItemInstance` state and persists across saves. +- **Capacity scales with phone tier** — total charge budget is multiplied by the equipped phone's **battery capacity** stat (§9.9). Per-app drain rates are unchanged; a Pro phone simply has more battery to spend. + +### 9.9 Phone models + +Three phone models exist. The starter model is owned at game start; the other two are purchased at the **Electronics Shop** (§10.4). The player may **own multiple phones simultaneously** — they are regular `UItemInstance` items (§6.1) that live in the wardrobe / inventory, and only the *equipped* phone is active per the §9 usage rules. + +| Tier | Model name | Camera quality | Livestream quality | Battery capacity | Source | +|------|-----------|----------------|--------------------|------------------|-----------------------| +| 1 | Starter | 1.0× | 1.0× | 1.0× | Owned at game start | +| 2 | Mid | > 1.0× (TBD) | > 1.0× (TBD) | > 1.0× (TBD) | Electronics Shop | +| 3 | Pro | highest (TBD) | highest (TBD) | highest (TBD) | Electronics Shop | + +Stat axes: +- **Camera quality** — multiplier on the `exposureScore` input to `FollowerGainCalculator` (§13.5) when posting a photo. A better camera turns the same scene into a higher-follower-gain photo. +- **Livestream quality** — multiplier on the per-tick `streamQualityScore` (§9.1.1). Better optics + mic → higher donation rate and faster follower trickle. +- **Battery capacity** — multiplier on total charge budget (§9.8). Per-app drain rates are unchanged; the better phone simply runs longer between charges. + +The multipliers apply to **new** photos and stream ticks only. Buying a Pro phone never retroactively improves a tier-1 photo already posted. + +**Switching phones:** +- Hot-swap at the apartment wardrobe. Equipping a different phone moves the previously-equipped phone back to the wardrobe. +- **Battery percentage is per-phone-instance.** Swapping does not transfer charge — a Pro phone left uncharged stays uncharged when you swap to it. +- **Gallery, livestream history, and account state live on the player profile**, not the phone. Swapping never loses photos, follower count, or stream stats. + +Tier prices and exact stat multipliers are TBD per §21. --- @@ -513,18 +583,53 @@ Sleeping at home fast-forwards 8 hours. - **Gym** — increase max energy. Costs energy in the process. Costs money. - **Beauty salon** — boobs size, ass size, makeup, hairstyle, hair color. - **Adult shop** — Buy sex toys for the `Nipples`, `Anal`, and `Vagina` toy slots (§6.5). +- **Electronics shop** — Buy upgraded phone models. Sells the Mid and Pro tiers (§9.9). In-person only; no online variant. - **Streets / parks / alleys** — commission space. - **Beach** — open sand, daytime crowds, nighttime privacy. Strong fit for exhibitionist / swimwear content. - **Train station** — platforms, concourses. Dense voyeur space; an indoor-transit setting distinct from streets. +- **Casino** — money-and-clothing gambling. Main floor + VIP room. See §10.4.2. The location set above is **locked for launch**. School exterior and hot springs (onsen) were considered and explicitly cut. #### 10.4.1 Cuff / restraint removal -Restrictive clothing (§6.3.7) is removed by **Key + timed unlock action**: +A restraint that blocks its own slot (i.e., declares `BlockSlotChange()`, §6.3.7) cannot be removed by normal unequip and requires the **Key + timed unlock action**: - The player must possess the matching key for the restraint instance. -- Performing the unlock takes time; movement and all other actions are disabled for the duration. +- Performing the unlock takes time; movement and all other actions are disabled for the duration. The restraint always comes off when the timer completes — the only question is *how quickly*. +- **Unlock minigame.** While the unlock action runs, a DBD-style skill-check minigame plays: a rotating pointer sweeps a circular meter that includes a small target zone, and the player presses a hotkey when the pointer crosses the zone. Each **successful hit advances the removal progress faster** than the baseline tick. **Missed checks carry no penalty** — they simply fail to grant the speed bonus, and the baseline timer keeps ticking down. There is no noise alert, no key loss, no fail state. The minigame is a pure accelerator for engaged players; impatient or unskilled players can ignore the checks and wait out the baseline timer. +- Per-restraint baseline timer length, skill-check frequency, target-zone size, and per-hit speed bonus are TBD per §21. - There is no Helper NPC, no adult-shop unlock service, and no break-out option. If the player loses the key, the restraint stays on until a key is acquired again. +#### 10.4.2 Casino +The casino is a location for spending time and (potentially) earning money. It splits into a **main floor** (always open) and a **VIP room** (gated; see below). The house edge means the expected value per session is intentionally negative — variance is the appeal, not steady income. + +**Games (main floor):** +- **Slots** — single-button pull, instant outcome. Small-to-medium bets per pull. Pure RNG; rapid chase loop. Time cost is the player's choice — keep pulling as long as you want. +- **Blackjack** — vs. a dealer NPC. Skill-light card game. Each hand burns a few in-game minutes (dealer + decision pacing). +- **Roulette** — multiple bet types on a single spin. Each round burns a couple of in-game minutes. + +The mixed pacing is deliberate: slots are the "fast burn," tables are the "time investment." Spending an afternoon at blackjack visibly eats into the commission window. + +**VIP room:** +- Access is **gated by a per-day entrance fee** paid at the reception. One payment grants access for the rest of the in-game day; access expires at the next day boundary and must be paid again. No permanent unlock, no progression-based gating — anyone with enough money in the bank can enter, but every visit-day costs. +- Higher bet limits (higher floor on losses, higher ceiling on wins). +- Lower NPC density and a permissive dress code — nudity is socially accepted inside the VIP room, so the few NPCs present contribute less embarrassment than the main floor would. +- Strip-game tables live exclusively in the VIP room. +- The entrance fee functions as a built-in negative EV floor — even a winning night at the tables has to clear the day's entry cost before it's net profit. + +**Strip variants (VIP-only):** +- A separate set of blackjack and roulette tables let the player bet **clothing items** as stakes (in addition to, or instead of, money). +- Losing a hand transfers the bet garment from the player's equipped slot to the **casino lost-and-found** — a safe inventory at the casino reception. The garment retains its `UItemInstance` identity (§6.1); it is not destroyed. +- Reclaiming a lost garment: win it back at the same table, or buy it back at reception for a flat fee (TBD). +- Strip outcomes don't bypass the normal embarrassment model — being stripped at the table and then walking out through the VIP room (low NPC density) or the main floor (higher density) still ticks embarrassment per §7.1. + +**Player attributes during casino play:** +- Casino games themselves do not drive embarrassment, lust, energy, or pulse. Only the normal observation-driven model applies based on what other NPCs in the room can see. +- Energy is not consumed by gambling actions; food, sleep, and run-driven drain remain the only energy levers. + +**Economy hook:** +- Casino is both an income source and a money sink. Net EV per session is negative on average; spikes are possible. +- Casino income is logged in the Bank app's income breakdown (§9.4) as a distinct line item; net losses appear in the corresponding spending breakdown. + --- ## 11. PC (at home) @@ -563,12 +668,14 @@ The forum is accessed via phone or PC. It is both diegetic and the primary missi - The player must **accept** a weekly mission from the forum before it counts as committed (same accept lifecycle as daily commissions in §13.2). Un-accepted weekly missions stay visible as goals and carry no penalty. - An accepted weekly mission that the player fails to complete by the end of the week is marked failed and applies the template's `failurePenalty` (§13.4), which is heavier than the daily equivalent. - A mission visible on the board that requires a path level the player hasn't reached is shown for context but cannot be accepted yet. +- **Rewards land instantly on completion** — money wires to the bank, XP credits to the shared pool (§7.10), and followers update on the profile. There is no return-to-home "collect rewards" step. ### 13.2 Daily commissions - Generated at day start, semi-random, weighted by path progression. - Rewards: money, XP, followers. - The player must **accept** a daily commission from the forum to commit to it. Accepted commissions that aren't completed by day end trigger the template's `failurePenalty` (§13.4) — typically a reputation / followers loss. Un-accepted commissions sitting on the board carry no penalty; they are offers, not obligations. - Multiple commissions can be accepted simultaneously; there is no built-in cap. The day timer is the natural limit on workload. +- **Rewards land instantly on completion** — money wires to the bank (visible in §9.4 as a commission-completion line item), XP credits to the shared pool, followers update on the profile. No return-to-home step is required. ### 13.3 Profile - View stats, progression, path levels, posted photos. @@ -623,7 +730,7 @@ Example commissions from the brief that should be representable: ``` followerGain = base(exposureScore) * reputationFactor * (1 / log(followerCount + e)) ``` -- **`exposureScore`** is the input — for a posted photo it is computed from exposed body parts + visible coverage in that photo; for a livestream tick it is the current `streamQualityScore` (§9.1.1). +- **`exposureScore`** is the input — for a posted photo it is computed from exposed body parts + visible coverage in that photo, then multiplied by the equipped phone's **camera quality** stat (§9.9); for a livestream tick it is the current `streamQualityScore`, which already includes the phone's **livestream quality** multiplier (§9.1.1). - **`reputationFactor`** is **signed**. Positive / neutral reputation → positive `followerGain` (followers grow). Negative reputation → negative `followerGain` (followers shrink). This is the §7.8 "positive vs. negative reputation" branch expressed in one number. - The `1 / log(followerCount + e)` term enforces diminishing returns: at `followerCount = 0` the divisor is `1.0`; growth slows as the audience grows. @@ -671,6 +778,7 @@ Forum, bank, gallery, shops are all in-fiction screens (phone/PC). Avoid out-of- - **Feetex shipping** — drop the item in a Feetex shipping box at the post office or convenience store. Payment arrives 1 in-game day later (mirrors Feetex's existing 1-day delivery delay). - **Drop-off** — travel to a specified location (varies per order) and leave the underwear there. Immediate payment, but the location may be in a high-risk area depending on the order. Tactical trade-off: convenience vs. drop-off-style commission tension. - Photo posts (indirect) and accumulated followers — drive the weekly **passive follower income** (§7.9). Higher follower count → larger weekly payout and larger commission payouts. +- **Casino winnings (§10.4.2)** — high-variance, negative-EV-on-average. Not a reliable income source; treat as gambling, not as a salary. ### 15.2 Costs - Weekly rent — **flat across the campaign**. No escalation, no event-driven spikes. The pressure comes from the 90-day timer and other expenses, not from a moving rent target. @@ -678,6 +786,7 @@ Forum, bank, gallery, shops are all in-fiction screens (phone/PC). Avoid out-of- - Food / ingredients. - Gym membership / beauty salon. - Adult shop. +- **Casino losses (§10.4.2)** — the dominant cost over time, by design. Strip-game losses additionally cost clothing inventory (reclaimable but not free). ### 15.3 Tuning targets (placeholder) | Tier | Daily income | Weekly rent | Notes | @@ -771,7 +880,7 @@ Clothing, commissions, food, NPC templates all live as `DataAssets` (or DataTabl ### 18.2 Full launch target (TBD) - 60+ clothing items. - All NPC types polished, multiple visual variants each. -- Full city, 4+ districts, including the **Beach** and **Train Station** locations (§10.4) added on top of the vertical-slice shop set. +- Full city, 4+ districts, including the **Beach**, **Train Station**, **Casino** (main floor + VIP room), and **Electronics Shop** locations (§10.4) added on top of the vertical-slice shop set. - 100+ commission templates. - All 3 paths leveled to cap with distinct content. @@ -805,10 +914,19 @@ Decisions previously open, now fixed: 9. **Cuff/restraint removal:** Key + timed unlock action only. No Helper NPC, no paid adult-shop service. See §10.4.1. 10. **Voice commands:** Not used. Hotkey-driven only. 11. **Equipment slot list:** 18 slots, locked. Body clothing (8): `Outerwear`, `Top`, `Bottom`, `UnderwearTop`, `UnderwearBottom`, `Bodysuit` (exclusive with the prior four), `Socks`, `Footwear`. Accessories (4): `Head`, `Face`, `Eyes`, `Neck`. Restraints (3, independent): `WristRestraint`, `AnkleRestraint`, `NeckRestraint`. Toys (3, independent): `Nipples`, `Anal`, `Vagina`. Face-cover bypass for recognition is driven by `Face` and `Eyes`. Toys do not contribute to coverage. See §6.5 for the full table. -12. **City location list:** locked for launch. Apartment, Convenience Store, Café, Clothing Shops, Gym, Beauty Salon, Adult Shop, Streets / Parks / Alleys, **Beach**, **Train Station**. School exterior and hot springs (onsen) were considered and cut. Vertical slice (§18.1) covers everything except Beach and Train Station — those are full-launch additions. See §10.4. +12. **City location list:** locked for launch. Apartment, Convenience Store, Café, Clothing Shops, Gym, Beauty Salon, Adult Shop, Electronics Shop, Streets / Parks / Alleys, **Beach**, **Train Station**, **Casino**. School exterior and hot springs (onsen) were considered and cut. Vertical slice (§18.1) covers the basic shop set; Beach, Train Station, Casino, and Electronics Shop are full-launch additions. See §10.4. 13. **Attribute level-up cost:** XP only. XP is a single shared pool (not per-path); the player chooses which path's attribute pool to spend it on, and may eventually max all three. No money, no separate currency. See §7.10. 14. **Food effect vocabulary:** locked. Two instant effects (energy restore, lust decrease) plus four timed buffs (stamina regen +, max stamina +, embarrassment-gain resistance, lust-gain resistance). Stacking: different types parallel; same type additive up to a per-type cap. No pulse buffs, no caffeine trickle. See §6.7. 15. **Carriable categories:** locked. Clothing, Bags, Phone, Consumables (food), Toys. No other gadget categories beyond the phone. See §6.2. +16. **Casino:** added to the city (§10.4, §10.4.2). Main floor (slots, blackjack, roulette — money only). VIP room — **gated by a per-day entrance fee** (no permanent unlock; pay each day you want in). Permissive dress code; strip-game blackjack and roulette tables that bet clothing. No poker. Mixed pacing: slots instant, table games take in-game minutes. Net EV negative — variance is the appeal. +17. **Police capture, can't pay:** short non-interactive holding-cell cutscene, then time fast-forwards to the next morning. The night served settles the debt; no money owed afterward. Replaces the earlier "skip days proportional to unpaid amount" rule. See §4.4. +18. **Loss precedence during a police chase:** if the player is actively being chased by police (per §10.3) and any other loss condition fires (embarrassment max, energy zero), the loss resolves as **police capture** — the chase wins. The cops catch the player as they collapse. Applies even without a prior `wanted` tag. See §4.4. +19. **Phone models:** 3 tiers (Starter / Mid / Pro). Three stat axes per tier — camera quality (photo follower-gain multiplier), livestream quality (`streamQualityScore` multiplier), and battery capacity (total charge budget multiplier). Bought in-person at the new Electronics Shop (§10.4). Player may own multiple phones simultaneously; gallery / followers live on the profile, battery is per-phone-instance. See §9.9. +20. **No `isUnderwear` flag on clothing.** Coverage math no longer special-cases underwear. Authors set `coverage` directly to reflect concealment (including the psychological "just underwear" discount); the value in the editor is the contribution to coverage math. See §6.3 / §6.3.2. +21. **Per-item restrictions list replaces `isRestrictive` boolean.** Each clothing item carries an optional `restrictions` list with granular entries: `BlockRun`, `BlockCrouch`, `BlockPhoneUse`, `BlockItemPickup`, `BlockMasturbate`, `BlockExposeAction`, and parameterized `BlockSlotChange(slot)`. Restrictions union across equipped items. Restraints typically declare `BlockSlotChange()` to force the §10.4.1 Key removal flow. Non-restraint items (heels, tight skirts) can declare lighter restrictions. See §6.3.7. +22. **Restraint-removal unlock minigame.** DBD-style skill-check minigame (rotating pointer + target zone). Successful hits **speed up** the removal. Missed checks have **no penalty** — they just don't grant the speed bonus. The restraint always comes off when the baseline timer expires. No noise alerts, no key loss, no fail state. See §10.4.1. +23. **Commission rewards land on completion, not on return home.** Money wires to the bank instantly, XP credits to the shared pool, followers update on the profile. No "collect rewards" step at the apartment. See §13.1 / §13.2 / §4.3 / §3.1. +24. **Hunger via max-energy decay.** Effective max energy decays over time (a hunger rate); eating any food restores effective max to base max as a built-in universal effect (no per-food authoring). Sleep restores current energy but does NOT reset hunger — only eating does. Floors at a TBD fraction of base max so the player can't be starved into a forced game-over. See §7.3 / §6.7. ## 21. Open Design Questions @@ -827,6 +945,10 @@ These remain genuinely unresolved and should be addressed during implementation: 11. Livestream tip-request tuning (§9.1.1): request frequency curve vs. viewer count, tip-size distribution (including high-roller frequency), countdown length on the accept popup, and the per-failure viewer-count drop magnitude. 12. Face-cover recognition resistance per slot (§7.6, §6.5): per-slot resistance magnitudes for `Face` and `Eyes` and the stacking curve. 13. Food tuning (§6.7): instant-effect amounts (energy restore, lust decrease), per-buff durations and magnitudes, per-type stacking caps, and the cooking-minigame scoring → buff-strength curve. +14. Casino tuning (§10.4.2): RTP per game (slots, blackjack, roulette), bet ranges per tier (main vs. VIP), the **VIP per-day entrance fee**, in-game-minutes burned per table-game round, and the strip-garment buy-back fee. +15. Phone-tier tuning (§9.9): exact multiplier values for Mid and Pro on each of the three stat axes (camera quality, livestream quality, battery capacity), and the Electronics Shop purchase prices for each tier. +16. Restraint unlock-minigame tuning (§10.4.1): per-restraint baseline timer length, skill-check frequency, target-zone size, and per-hit speed bonus. +17. Hunger tuning (§7.3): `maxEnergyDecayRate` (effective max energy lost per in-game hour), the effective-max floor as a fraction of base max, and any per-food bonus on top of the universal full-restore (if we ever want a "big meal heals you faster" lever). ---