Bump MVP map to 80², lock world-view camera, resolve doc rot
Resolves the rimlike docs audit. Decisions made this session: - Map: 40² → 80² for MVP slice; architecture sized to ~120² ceiling. Pawn count unchanged (3 start / 6 cap) — 'split-the-difference' sizing rather than frontier-feel scale. - World-view camera (locked): pinch + drag-pan + double-tap-centre. Storyteller alerts include 'Go there' tap. No minimap, no follow-cam in MVP. New ui.md section captures this. - Storyteller cooldowns: per-event AND per-category — both gates must pass. Resolves design.md/architecture.md disagreement. - MAX_STACKS_PER_THOUGHT = 5 (was named-but-unset). - Hauling no-destination fallback: drop after 3 retry passes, surface a passive 'No stockpile accepts X' alert. - Container all-neighbors-blocked: hold then drop after ~5 sim s to avoid deadlock. - Auto-roof big-room UX: emits room_too_large signal when BFS hits the ≤8-cell cap; UI surfaces a 'split with an interior wall' banner. Threshold + exact wording added to memory.md TODOs. Doc rot cleaned in design.md and architecture.md: removed the stale '8 work categories' intermediate sections (canonical 9-list lives later in each file). Updated architecture.md perf claims for the new map size. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d233cef12f
commit
c5dadedab0
4 changed files with 52 additions and 19 deletions
|
|
@ -97,15 +97,17 @@ Multipliers drive sim tick stepping per render frame. At 60 Hz render with 20 Hz
|
|||
- Ultra (12×): 240 ticks/sec (4 ticks per render frame)
|
||||
- Pause: zero ticks queued
|
||||
|
||||
Per-tick budget at Ultra: ~4 ms to stay in 60 fps render. Achievable for our scope (3–6 pawns, < 500 entities, ≤ 60×60 tiles).
|
||||
Per-tick budget at Ultra: ~4 ms to stay in 60 fps render. Achievable for our scope (3–6 pawns, < 500 entities, **80×80 MVP map; sized to a 120² ceiling**). At 80² the AStarGrid2D has 6.4k nodes; longest path ≤ 160 tiles; full A* runs sub-millisecond on a mid-range phone. At 120² (22.5k nodes) it's still well under a millisecond per query.
|
||||
|
||||
### Pawn movement
|
||||
|
||||
| Speed | Real-time crossing of 40-tile map | Feel |
|
||||
| Speed | Real-time crossing of 80-tile map (corner-to-corner) | Feel |
|
||||
|---|---|---|
|
||||
| 1× (1 tile / 0.5 s) | ~20 s | Watchable, deliberate |
|
||||
| Fast (5×) | ~4 s | Snappy, default cadence |
|
||||
| Ultra (12×) | ~1.7 s | Almost teleporting |
|
||||
| 1× (1 tile / 0.5 s) | ~80 s | Watchable, deliberate |
|
||||
| Fast (5×) | ~16 s | Snappy, default cadence |
|
||||
| Ultra (12×) | ~7 s | Almost teleporting |
|
||||
|
||||
Travel times are roughly 2× the original 40-tile estimates. A wolf spawning at the map edge gives ~20 s real-time lead at Fast — meaningful warning, not tedious.
|
||||
|
||||
This mostly absorbs the "walking-speed problem" surfaced earlier — Fast as default keeps a 5-min day from feeling like watching paint dry.
|
||||
|
||||
|
|
@ -260,6 +262,10 @@ walk_to(item.cell) → pick_up(item, capped_at_carry_capacity)
|
|||
|
||||
Carry capacity capped at one stack of one type. Multi-type carry is v2.
|
||||
|
||||
**No-destination fallback.** If `find_best_destination_for(item)` returns null on three consecutive periodic-flow passes (~15 sim seconds), the item is dropped where it lies, taken off the dirty set, and a passive "*No stockpile accepts X*" alert is queued. This prevents `_dirty_items` from cycling forever when the player has zero matching storage. The alert clears the moment a matching destination opens up (it re-enters the dirty set on the next storage-change event).
|
||||
|
||||
**Container all-neighbors-blocked.** `best_drop_position(from)` returns the closest free 4-neighbor of the container. If all four are blocked, the hauler holds the carry and re-tries on the next pass; if still blocked after ~5 sim seconds the carry gets dropped on the hauler's current tile (same fallback as above) so it doesn't deadlock.
|
||||
|
||||
### Container build flow
|
||||
|
||||
1. Player taps Build → Furniture → Crate.
|
||||
|
|
@ -322,6 +328,8 @@ func compute_mood(p: Pawn) -> float:
|
|||
return clamp(m, 0, 100)
|
||||
```
|
||||
|
||||
`MAX_STACKS_PER_THOUGHT = 5`. Caps "saw corpse" / "ate without table" / "slept on floor" pile-ups so a single thought type can't deterministically tank mood by itself; the player still loses points from variety, which matches the Rimworld feel.
|
||||
|
||||
Thought registry (data file) drives content. Each thought entry knows:
|
||||
- Trigger: what game event creates it (saw_corpse from EntityProximity, slept_well from JobComplete, hungry from NeedThreshold, …)
|
||||
- Lifetime: persistent (driven by ongoing state) or event (decays after N hours)
|
||||
|
|
@ -375,7 +383,7 @@ func recompute_light(affected_cells: Array[Vector2i]):
|
|||
|
||||
Recomputed only when a light source is added/removed/state-changes (turned off due to fuel, etc.). Cheap.
|
||||
|
||||
**Render side:** at night, world rendered with darkness shader; the shader samples `light_map` to brighten tiles. Phone GPU runs this comfortably for 60×60 tiles.
|
||||
**Render side:** at night, world rendered with darkness shader; the shader samples `light_map` to brighten tiles. Phone GPU runs this comfortably for the MVP 80×80 map (and the 120² ceiling) — light recompute touches only cells inside the affected light's radius (max_radius=8 → ≤ 200 cells), not the whole map.
|
||||
|
||||
**Mood integration:** `is_lit(cell)` returns `light_map[cell] > 0.2`. Fires "In darkness" thought for pawns in unlit tiles at night.
|
||||
|
||||
|
|
@ -450,10 +458,6 @@ Decay: zero — dirtiness only goes down via Cleaning.
|
|||
|
||||
8th WorkProvider in the existing pawn AI. Scans dirty tiles in/near rooms with priority bias toward indoor tiles. Job toils: walk → clean (timed by Manual Labor skill) → set dirtiness to 0.
|
||||
|
||||
### Updated WorkProvider list (8)
|
||||
|
||||
Construction · Mining · Hauling · **Cleaning** · Cooking · Plant · Doctor · Combat
|
||||
|
||||
## Production: workbenches, recipes, bills
|
||||
|
||||
For player rules and recipe lists, see [`design.md`](./design.md). This section is data + AI plug-in.
|
||||
|
|
@ -889,6 +893,9 @@ func build_weighted_pool() -> Dictionary:
|
|||
var pool = {}
|
||||
for ev in EVENT_REGISTRY.values():
|
||||
if not ev.trigger.matches(World.state, current_day): continue
|
||||
# Both gates must pass: per-event AND per-category cooldown.
|
||||
# Per-event prevents the *same* event repeating within its individual cooldown.
|
||||
# Per-category enforces the design.md pacing rule (no two threats within 3 days, etc.).
|
||||
if recently_fired(ev.id, ev.cooldown_days): continue
|
||||
if recently_fired_category(ev.category, CATEGORY_COOLDOWN[ev.category]): continue
|
||||
var w = ev.weight * tension_modifier(ev.category)
|
||||
|
|
@ -982,6 +989,8 @@ func on_wall_change(cell: Vector2i):
|
|||
|
||||
`bfs_finds_exit(start)`: flood from `start`, treating walls as blockers; return true if we reach the map edge or a No-Roof designated cell within 8 steps. Fast at our scale (8² = 64 cells worst case per BFS, called on each candidate within the affected radius — still microseconds).
|
||||
|
||||
**Big-room feedback.** When `bfs_finds_exit` returns true *because the BFS ran out of steps without escaping or roofing* (i.e. the area is enclosed but larger than the cap), the EnclosureDetector emits a `room_too_large` signal carrying the centroid cell. The UI raises a one-shot ambient banner: "*This area is too large to roof. Split it with an interior wall.*" Threshold and exact UX wording TBD — see `memory.md` Open questions.
|
||||
|
||||
When a wall is destroyed: candidates are re-evaluated; some may flip from roof to no-roof.
|
||||
|
||||
### No-Roof designation
|
||||
|
|
@ -1070,7 +1079,7 @@ Children of a `World` node, tile-aligned positions:
|
|||
|
||||
### Pathfinding
|
||||
|
||||
`AStarGrid2D`, one grid the size of the map. Walkable derived from TileMap data + furniture occupancy. Update affected cells on build/destroy/door-state-change. Microseconds at 60×60.
|
||||
`AStarGrid2D`, one grid the size of the map. Walkable derived from TileMap data + furniture occupancy. Update affected cells on build/destroy/door-state-change (one cell per change → O(1)). Sub-millisecond per path query at 80²; still well under a millisecond at the 120² ceiling.
|
||||
|
||||
### Saving
|
||||
|
||||
|
|
@ -1078,7 +1087,7 @@ Per layer, `tilemap.get_used_cells_by_id(layer)` → JSON. Plus furniture entiti
|
|||
|
||||
### Performance
|
||||
|
||||
60×60 × 5 layers = 18k tiles, GPU-batched in one draw call per layer. ~100–500 entity nodes at peak. Comfortable 60fps on a mid-range phone with headroom. iOS export needs Mac/Xcode; Android export from Linux is fine.
|
||||
80×80 × 5 layers = 32k tiles (MVP); 120×120 × 5 = 72k tiles (ceiling). GPU-batched in one draw call per layer regardless of cell count, so the bump is essentially free for the renderer. ~100–500 entity nodes at peak. Comfortable 60 fps on a mid-range phone with headroom. iOS export needs Mac/Xcode; Android export from Linux is fine.
|
||||
|
||||
## What lives elsewhere
|
||||
|
||||
|
|
|
|||
|
|
@ -175,10 +175,6 @@ Floor tiles accumulate `dirtiness: float (0..100)`:
|
|||
|
||||
Mostly low-skill chore work — gives Manual-Labor pawns something to do when not building/mining/hauling.
|
||||
|
||||
### Updated work category list (now 8)
|
||||
|
||||
Construction · Mining · Hauling · **Cleaning** · Cooking · Plant · Doctor · Combat
|
||||
|
||||
## Production chains & workbenches
|
||||
|
||||
2-step chains where it makes medieval sense; 1-step where simpler is fine. Going Medieval / Banished flow without runaway recipe authoring.
|
||||
|
|
@ -540,6 +536,8 @@ When walls form an enclosed area ≤ 8 cells across, the interior **auto-roofs**
|
|||
|
||||
Matches the player's mental model: *"I built four walls, now there's a room."*
|
||||
|
||||
**Big-room UX (open):** the ≤8-cell cap silently fails on rooms larger than 8×8. When the player encloses a too-large area, we should surface "this area is too large to roof — split it with an interior wall." Exact threshold + UI treatment is TBD (see `memory.md` Open questions).
|
||||
|
||||
### "No-roof" designation
|
||||
|
||||
Designation type: paint cells inside an enclosure to forbid auto-roofing. Useful for courtyards, fire pits, gardens. Same paint UX as stockpile zones.
|
||||
|
|
|
|||
15
docs/ui.md
15
docs/ui.md
|
|
@ -610,11 +610,24 @@ Top bar also shows season + day-of-season ("Spring 4/12"). Tap → seasonal fore
|
|||
|
||||
Wet pawns have a subtle drip particle + slight sprite tint until they dry off. Players can quickly spot "Bob is soaked, why?" without opening the pawn detail screen.
|
||||
|
||||
## World view camera (locked)
|
||||
|
||||
The camera/navigation model on the main world view, decided 2026-05-10 alongside the bump from a 40² to an 80² map.
|
||||
|
||||
- **Pinch-zoom**: between a "strategic" zoom (whole-map-ish on tablet, ~1/4 of the map on phone) and a "close" zoom (~16 tiles wide on phone, sprite-readable). No fixed zoom levels — smooth.
|
||||
- **Drag-pan**: one-finger drag on empty world tiles. Drag on a pawn = select-and-drag-issue-order (long-press-then-drag for multi-select rectangle).
|
||||
- **Double-tap to centre**: double-tap on a pawn portrait, alert banner, or the world centres the camera there with a brief animated pan.
|
||||
- **No follow-camera**: selecting a pawn does **not** lock the view to them. Selection persists across pans so the player can scroll to a build site and issue an order without losing their pawn.
|
||||
- **Jump-to-alert**: every storyteller alert / banner / event modal includes a *Go there* tap that pans-and-centres the camera on the relevant tile (raid spawn, downed pawn, fire, etc.). Replaces the "where is this happening?" minimap need.
|
||||
- **No minimap in MVP**. Reasoning: phone screen real estate is precious, and *Jump-to-alert* + double-tap-on-portrait covers the navigation needs at 80². Revisit if playtest shows people getting lost.
|
||||
- **Speed / pause buttons** stay fixed at the top regardless of camera state.
|
||||
|
||||
Layered on the world view: select (tap empty pawn), inspect (long-press anything), build mode (bottom-sheet → paint), designation paint (bottom-sheet → designate type → paint).
|
||||
|
||||
## Screens still to design
|
||||
|
||||
These are open work for future sessions. Listed roughly in importance.
|
||||
|
||||
- **World view** — camera/select/orders. The screen the player sees most. Tap targets, long-press menus, pinch-zoom, multi-select (for multi-pawn orders).
|
||||
- **Build drawer** — bottom-sheet tabs (Walls / Floors / Furniture / Production / Designate). Designation paint mode. Material-pick UI when a build can use multiple materials.
|
||||
- **Alerts / storyteller event** — modal vs. ambient, dismissal, history of past prompts.
|
||||
- **Day-summary / end-of-day** — a recap card showing what changed today; gives short sessions a stopping point.
|
||||
|
|
|
|||
17
memory.md
17
memory.md
|
|
@ -37,7 +37,7 @@ Distilled from the brainstorm. Each lock has a "why" — change with deliberate
|
|||
| **Goal scaffolding** | Light storyteller prompts | Soft, dismissible nudges give each short session shape without forcing scenarios. |
|
||||
| **Combat** | Realtime with auto-pause on threat | Rimworld-feel; touch-friendly. |
|
||||
| **Health** | Single HP per pawn + status effects (Bleeding/Sick/Tired/Hungry/Wet/Cold/Downed/...) | ~80% of the drama for ~5% of Rimworld's health-system code. |
|
||||
| **Scale** | 3–6 pawns, 30×30 to 60×60 tile maps | Readable on a phone; cheap to simulate. |
|
||||
| **Scale** | 3–6 pawns, **80×80** MVP map (architecture sized to ~120² ceiling) | Roughly Stardew-farm size; readable when zoomed in, doesn't fit a phone screen — forces the world-view camera (pinch / pan / jump-to-alert) rather than strategic-overview-on-phone. |
|
||||
| **Priority levels** | 5 (Critical / High / Normal / When idle / Off) | Matches Rimworld + Going Medieval contract. |
|
||||
| **Failure state** | Ghost colony — no game over; storyteller drops wanderer in 3–5 days | Mobile-friendly; preserves player investment. |
|
||||
|
||||
|
|
@ -72,6 +72,7 @@ Distilled from the brainstorm. Each lock has a "why" — change with deliberate
|
|||
- **Stockpile/container UI**: 4×4 chip grid for the 16 filter categories; same UI for floor zones and crates.
|
||||
- **Storyteller events**: ambient banners for nudges/seasonal/lore; modal auto-pause for wanderer/threat/disease/milestone. Events log + "while you were away" digest at resume.
|
||||
- **Indoor tint** marks "this is inside" without needing roof rendering — matches Stardew/Rimworld convention.
|
||||
- **World-view camera**: pinch-zoom + drag-pan + double-tap-to-center; selected pawn does **not** force-follow. Storyteller alerts/banners include a *Go there* tap that pans the camera to the event tile. **No minimap in MVP** — revisit if playtest shows people getting lost on the 80² map.
|
||||
|
||||
### Art strategy
|
||||
|
||||
|
|
@ -94,6 +95,7 @@ These are concrete checks to run before serious construction begins. Total ~75 m
|
|||
|
||||
### Design topics still open
|
||||
|
||||
- [ ] **Auto-roof big-room UX**: the ≤8-cell BFS cap silently fails on rooms larger than 8×8. Decide whether to (a) keep the cap and surface "this area is too large to roof — split with an interior wall" hint when the player encloses one, (b) bump the cap to ~16 with the same hint at the new threshold, or (c) detect any enclosed area regardless of size. Affects `EnclosureDetector` + a new room-feedback UI.
|
||||
- [ ] **Onboarding / first 60 seconds**: mobile-specific. Don't copy Rimworld's tutorial.
|
||||
- [ ] **Touch UI for non-priority screens**: world view, build drawer, alerts, day-summary, pawn detail. See `docs/ui.md` "Screens still to design."
|
||||
- [ ] **Background time / "while you were away" mechanic** — locked to no background simulation in MVP; revisit if it feels bad in playtest.
|
||||
|
|
@ -120,7 +122,7 @@ These are concrete checks to run before serious construction begins. Total ~75 m
|
|||
Same scope as locked in `~/claude/ideas/rimlike/plan.md`. Realistic timeline 3–6 months solo for an MVP this rich.
|
||||
|
||||
- **1 biome** (temperate forest, ElvGames Forest Tileset 4 Seasons; Ventilatore foliage accents).
|
||||
- **1 map**, ~40×40 tiles, fixed seed for now.
|
||||
- **1 map**, **80×80 tiles**, fixed seed for now.
|
||||
- **3 starting pawns** ("settlers" / "villagers"), each with name + portrait + one-sentence backstory.
|
||||
- **Verbs**: chop wood, mine stone & ore, build walls/floors/furniture/crates, plant/harvest crops (3–4 types), cook meals (recipes), haul, repair, clean.
|
||||
- **Needs**: hunger, sleep, mood (~13 distinct thoughts, soft breaks at sustained mood < 25).
|
||||
|
|
@ -143,6 +145,17 @@ Same scope as locked in `~/claude/ideas/rimlike/plan.md`. Realistic timeline 3
|
|||
### 2026-05-10
|
||||
- Promoted from `~/claude/ideas/rimlike/` (single multi-hour brainstorm session).
|
||||
- Scaffolded `projects/rimlike/` from `_templates/project/`. Customized `CLAUDE.md`. Distilled `plan.md` into this `memory.md`. Moved companion files (design / architecture / ui / art) into `docs/`. `git init`, first commit "Initial scaffold". Created Forgejo repo `rimlike` (private), set HTTPS remote, pushed `main`. Archived idea folder to `~/claude/archive/ideas/rimlike/`.
|
||||
- Wired Godot MCP Pro: `.mcp.json`, `.claude/settings.local.json` allowlist, three project-local subagents (`quick-edit`, `researcher`, `gdscript-refactor`). Added the MCP-Pro and tiered-delegation sections to `CLAUDE.md`. Editor plugin / `addons/godot_mcp/` re-copy still pending Godot project scaffold.
|
||||
- Reviewed `docs/` against `memory.md` and `CLAUDE.md`. Decisions made:
|
||||
- **Map size bumped from 40² → 80²** for the MVP slice; architecture sized to ~120² ceiling. Pawn count stays at 3 start / 6 cap (frontier feel was rejected in favor of "split-the-difference" sizing — Stardew-farm scale, not Going-Medieval scale).
|
||||
- **World-view camera** = pinch-zoom + drag-pan + double-tap-to-center; storyteller alerts include a *Go there* tap. No minimap in MVP. No follow-cam (avoids fighting the player when issuing build orders across the map).
|
||||
- Storyteller cooldown semantics: **per-event AND per-category, both gates must pass** (resolves the design.md vs architecture.md disagreement).
|
||||
- `MAX_STACKS_PER_THOUGHT = 5` (was named-but-unset).
|
||||
- Hauling-loop fallback: items that fail to find any valid destination after 3 retry passes drop on the floor and surface as a passive "No stockpile accepts X" alert.
|
||||
- Cleaned up doc rot in `docs/design.md` and `docs/architecture.md` — both had stale "8 work categories" intermediate sections still next to the canonical "9" lists. Removed the (8) snapshots.
|
||||
- Updated `docs/architecture.md` perf assumptions (60² → 80² with 120² ceiling).
|
||||
- `docs/ui.md` got a new **World view camera (locked)** section; removed the world-view bullet from "Screens still to design".
|
||||
- Open: auto-roof big-room UX (added to TODOs above) — the ≤8-cell BFS cap silently fails on bigger rooms; player feedback path needs a decision before EnclosureDetector lands.
|
||||
|
||||
## External references
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue