Files
Moto 0e61a77346 Add comprehensive design and specification documentation (#1)
* Write the Unreal documentation set: design, steps, ideas, decisions and specs

Rewrites the design and engineering docs of the two earlier Unity projects
(Adventurer Guild, Project Malleable) for an Unreal Engine 5 prototype that
builds and proves three things in order: a movement controller, fighting and
crafting. Neither earlier core loop is carried; their ideas are catalogued as
features with what each needs.

- Docs/Design.md: the human summary (pillars, fixed decisions, glossary)
- Docs/Steps.md: a ladder of fifteen proofs, the first six in full
- Docs/Ideas.md: salvaged ideas from both projects, none scheduled
- Docs/Decisions.md: D-01..D-36, open decisions OD-01..OD-08, deferrals
- Docs/Spec/: notation, Architecture, Movement, Interaction, Combat,
  Crafting, Networking, Telemetry, UI, written as Unreal C++ skeletons
- CLAUDE.md and README.md for the repository


* Add the stat block: one attribute set on every body, every influence an effect

Every body (player, enemy, NPC) carries the same UStatBlockAttributeSet, and
every outside influence on it is a gameplay effect: base values, buffs,
debuffs, ground surfaces, carried weight, gear, being downed. Counters are
tags and attributes on the receiver: immunity blocks by tag, resistance
scales by attribute, cleanse removes by tag. Same status from several
sources: strongest wins; different statuses multiply.

- Docs/Spec/Stats.md: the block, effects and their five sources (abilities,
  areas, surfaces, items, the world), stacking, counters, readers, tests
- Movement: the movement component's tagged speed-multiplier map is removed;
  speed is tuning times the MoveSpeed attribute; the ground surface trace
  turns mud into an effect; the gym gets mud and ice patches
- Combat: the attribute set moves to Stats; enemies and kits carry
  FStatBlockDefaults; the funnel reads MagicResist and Immune.Damage tags;
  taunt and mark are statuses
- Interaction: carried weight is GE_Encumbered against CarryCapacity
- Crafting: class bonuses are the WorkSpeed and WorkQuality attributes;
  enchantments may grant a holder effect
- Steps: step 5 builds the block with mud, a volume and an immunity
- Decisions D-37 and D-38; design summary, CLAUDE.md, indexes, worklog
2026-09-15 17:54:00 +03:00

10 KiB

Ideas

The two earlier projects, Adventurer Guild and Project Malleable, each designed a whole game around a core loop. This project keeps neither loop. It keeps the ideas, reshaped as features a world could hold rather than as the thing the game is about, and it keeps them here rather than in the specs so that none of them can be smuggled into a step as if it were already decided.

Each entry says what the idea is, which mechanism is worth keeping, what it would need, and what it must not break. "Adopted" means the idea already lives in a spec. Nothing here is scheduled.

From Adventurer Guild

Contracts and the board

Take a parchment off a wall, go and do it, come back and have it stamped. The mechanism worth keeping is the stamp: a ritual at the end of a job where the value is counted out in front of everyone, which is a better stopping point than a results screen because it gives a group a shared moment. Contracts as data (a target, a count, a reward, a standing requirement) and progress reported through one funnel from combat kills and item deliveries. Needs: a place to put the board, a reason to want the reward. Must not: replace playing with fetching; a contract is a reason to go somewhere, not the game.

The cart

A physical, pushable container that carries the haul out. Tips, spills a fraction, gets righted. Pushed from the handles by taking them (an interaction), which routes movement input into the cart. The mechanism worth keeping is hauling as a physical problem: what you bring back is what fits and what you managed not to lose. Needs: somewhere to haul from and to; the physics of a pushed body on a server. Must not: be the only way to carry things; hands and (later) containers come first.

Grief verbs and the recoverability contract

Shove, take from the cart, heal-launch, tip the cart. Adopted as a rule in Combat.md: any verb that lets one player inconvenience another must have a recovery that takes less time than the verb did, and none may down, kill or permanently deprive. Every such verb emits grief_action. The verbs themselves arrive with the systems they act on.

Down, revive, bleed-out, wipe

Adopted whole in Combat.md.

Seeded generation

A dungeon generated from a seed on every peer, byte-identical, so the server replicates eight bytes instead of megabytes. The determinism rules (own random stream, integer grid, ordered collections, no physics, no time), a critical path the cart can traverse, side branches that split the party, a shortcut door that only opens from the deep side, rooms as one-cell tiles in folders, typed spawn anchors with always/chance/budget rules, weighted pools, and an append-only pass that guarantees a contract's target exists. The mechanism worth keeping is all of it; it is the most worked-through part of the earlier project. Needs: a reason to have instanced places. Must not: assume one instance per server or that generation runs on the client only; both hold in the earlier design and both survive the move.

Party-size scaling

Sublinear enemy budget (1.0, 1.75, 2.4, 3.0) and role relaxation below three players. Adopted as a reserved rule in Combat.md, applied to a count for now.

Reputation, tiers, zones, upgrades

Standing that gates content, tiers that pay more, an upgrade bench where gold buys modifiers that combat pulls by name (GetModifier("cart.capacity")), and the cross-class gear rule. The pull direction is the mechanism: combat asks for its numbers, progression never pushes into combat. The signature guardrail is adopted as the bSignature flag. Needs: a currency, a reason to spend. Must not: become per-body state; it lives on the player.

The hall as hub and lobby

You launch into a place, not a menu. The lobby is a board by the door, readiness is a plinth you stand on, class is a locker with racks, and everyone is physically together before the run. The mechanism is the lobby is a room. Needs: a second map and session travel. Must not: assume a listen server; the room is on the same server the world is.

Steam lobbies and the friends-list join

Every launch hosts a lobby of one; opening it to friends is a physical act; a friend's "join game" carries them in. Needs: a session layer in front of the server. Must not: put a session type inside gameplay code.

Content authoring tools

Weighted pools, typed anchors, a tile template with red doorway volumes and a footprint validator, a project content catalogue feeding dropdowns, and one browser window over every content asset. The engine's data validation and asset manager do half of this natively. Needs: enough content to hunt through. Must not: arrive before the third tileset.

The design system

A palette by role, one label component, one theme, meaning never on hue alone. Adopted in UI.md; the parchment-and-ink look itself is not.

From Project Malleable

Orders as tickets on a rail

A customer hands over a parchment; it hangs on a rail from the desk to the workshop; taking it off is the claim; clipping it to a station shows what that station is working; handing it back with the item is the delivery. The spec on the ticket is explicit (family, required tags, minimum quality) and matched by one pure function that also explains why an item does not match. Five customer tiers as data, archetypes with patience and reactions. The mechanism is demand as a physical object you can pick up, hand over and drop. Needs: a shop, an economy, customers. Must not: be the only source of demand once players are the adventurers.

The economy

Gold only. A payout split 20/40/40 between base, quality and speed against a tier price, clamped so the ceiling belongs to the order and profit is margin. A shared wallet with per-player attribution. A front shop with bid and ask prices, NPC valuation computed independently so player prices cannot mint money, and haggling as a turn-based exchange with a truthful likelihood meter. Needs: everything above it. Must not: introduce a lying surface; every gauge in this project tells the truth and a haggling meter that dramatised would poison the others.

Storage as a place

No shop-wide inventory, no stack counters, no station pulling from a container across the room. Containers with slots, designated floor areas typed by what they hold, reservations per object so two players racing for the last ingot find out at claim time, nothing destroyed by a full container, and a satchel bought later that adds pocket slots (2, 3, 4, 6, 8, 10). The mechanism is hauling is the game, and the substance object model already assumes it. Needs: more things than hands can hold. Must not: add an abstract bank; the object model's cost is only affordable because storage caps the count.

Crafting domains as professions

Five domains mapped one to one to five crafting classes (Forge Worker, Woodworker, Enchanter, Shopkeep, Quartermaster) with speed and quality bonuses that never lock anything. Three domains are adopted as the station gate in Crafting.md. The open question worth a real session: this project has combat kits; are crafting professions a second axis on the same player, a choice against a kit, or folded into kits? Needs: that decision. Must not: gate a station on a class; the rule is bonuses, never locks.

Stations you place, upgrade and pack

Movable stations on a grid, per-station upgrades with a mesh per tier so level reads across the room, fittings as visible sub-upgrades in named sockets, and stations repackaged into a carryable crate rather than sold, so nothing is lost and no gold comes back. Needs: a place that is yours. Must not: put station state on the actor's Blueprint; it is a replicated record.

World events as a modifier service

A standalone service any system asks for its own modifier (GetModifier(PriceBias, tag)), events as assets with scopes and channels, seeded per world, pushable from outside. The mechanism is consumers ask, they never test for an event. Needs: a second system that wants tuning from outside. Must not: be consulted from inside an activity tick.

Travel and the town

The cart as the travel system: sit in it, pick a destination, cut to the scene. A town with a purchase surface and a small bounded warehouse, staged so that a local town cannot smuggle in shared population or a marketplace before the service that hosts them exists. Needs: a second place. Must not: make the warehouse a bank.

Persistence and portable characters

Worlds keep the relationship, characters belong to the player and travel between worlds; ironman days with no rewinds and a mid-day autosave; records as idempotent snapshots with schema versions and recomputed derived fields; a provider interface with a local implementation forever. Adopted as the identity and persistence seams in Networking.md; the day, the world record and the character record are not built.

The service posture

Dedicated servers, a validation layer behind the simulation, three responsiveness tiers, ask-then-show, no rollback of visible world state, lag compensation only where timing is scored, and an incident doctrine (detect, contain with a modifier push, trace by object id, remediate surgically, restore last). Adopted as posture in Networking.md and Telemetry.md. The layers themselves are not built and nothing in gameplay code would change when they are.

Adventure contracts, turned inside out

Malleable sent NPC parties out with your gear to bring rare substances back. Here the players are the party. The loop that closes when the three feels exist: craft a weapon, fight with it, bring back what only fighting finds, craft something better. Rare substances as drops and finds with provenance already in the data model (Provenance.Found, SourceObjectIds). This is the most likely next step after fifteen and it is deliberately not written as one.

Discovery at scale, alloys, deciphering

Generated glyphs discovered like skill unlocks (with the constraint that the composition path never changes and any seed is global), a kiln that alloys two raw types (with the constraint that nobody hard-codes one-to-one processing), and customer requests as rough descriptions to interpret rather than specs to read. Each is its own session. Must not: happen by accident in a step about something else.