Checkpoint before character generator cleanup

This commit is contained in:
2026-05-25 16:21:44 +02:00
parent eef90f3471
commit 40ef48b279
80 changed files with 21597 additions and 744 deletions
+19 -1
View File
@@ -25,6 +25,16 @@ The production client must tolerate speech being unavailable. The safe TTS provi
Ink source files and game UI localization files must be saved as UTF-8 and must contain the real written characters. German text uses full umlauts and special characters directly, for example `ä`, `ö`, `ü`, `Ä`, `Ö`, `Ü`, `ß`, and German quotation marks `„…“`. Do not transliterate German into `ae`, `oe`, `ue`, or `ss` as an encoding workaround.
## Agent Editing Safety
These rules are mandatory for AI/Codex work on authored text:
- Do not alter authored prose, Ink text, generated character text, documentation prose, or localization text through regex, bulk replacement, or scripted text rewrites.
- Use `apply_patch` only for text edits.
- For PowerShell commands that read or display text, set `$OutputEncoding` and `[Console]::OutputEncoding` to UTF-8 first.
- Before large text work, create a git check-in.
- Edit entry by entry, inspect each edited entry after changing it, and proceed sequentially. No generated shortcuts.
## Ink Authoring State
Use Ink's built-in visit state for simple facts such as "this knot has been shown". Do not create parallel boolean flags for knot visits.
@@ -37,16 +47,24 @@ Use `mark`, `has`, and `lacks` only for a coherent group of independent facts th
Eibenreith authored content uses a mandatory bucket architecture. Rooms are installed through `enter_room(location, entry, look, exits, bucket)`. The active choice surface collects choices in this order: moment, room entry/look, exits, episode, game. Chosen atomic content ends with `-> TURN`; bucket/provider knots end with `-> DONE`. Authored chapter files must not call the internal `provide_choices` implementation directly.
The canonical format for conditioned atomic bucket weaves is a multi-line choice header: choice marker, one precondition per following header line, then the choice text on its own header line. Example: `* {condition_one}` / ` {condition_two}` / ` [__Verb Charakter__: "..."]`. Naked condition lines before a choice do not gate that choice and are forbidden for bucket atoms. Visibility conditions belong in the choice header, not in the branch body.
`helpers.ink` owns global helper variables, helper functions, `TURN`, and active choice-surface dispatch. `buckets.ink` owns the game-wide bucket. Even when empty, `game_bucket` remains a real content bucket and must stay available for cross-episode game material.
Companion-aware dialogue and reunion reactions must use the central Ink contact manager instead of room-specific flags. `present(character)` checks whether an NPC is in the current room. `first_meeting(character)`, `reunion(character)`, and `parting(character)` are one-choice-surface transition helpers created by traversal and cleared automatically by the next turn. Authored content may query these helpers but must never clear or consume contact transitions manually. `alone()` is true when no tracked NPC is present. `alone_with(character)` is true when exactly that tracked NPC is present, and is intended for private dialogue options.
`loc_move_to(location)` updates Valerie's current location, moves active companions, and refreshes contact state. `companion_join(character)` and `companion_leave(character)` only control whether a character follows Valerie through traversal; they are not story-memory flags. Episode setup is responsible for initial character locations and companion state. After manual multi-character setup, call `contact_sync()` to establish current contact without firing first-meeting or reunion transitions.
`loc_move_to(location)` updates Valerie's current location, records traversal origin and destination, moves active companions, and refreshes contact state. `companion_join(character)` and `companion_leave(character)` only control whether a character follows Valerie through traversal; they are not story-memory flags. Episode setup is responsible for initial character locations and companion state. After manual multi-character setup, call `contact_sync()` to establish current contact without firing first-meeting or reunion transitions.
Episodes may install an optional companion transition bucket through `enter_episode(value, slot, start_bucket, end_bucket, episode_bucket, companion_transition_bucket)`. The room engine plays that bucket centrally on every `enter_room(...)` after movement. Companion traversal prose belongs there and should use `accompanied_by(character)` together with `traversal_from(...)`, `traversal_to(...)`, or `traversal_between(origin, destination)`. Do not duplicate companion-following narration inside individual exits unless the exit has genuinely unique story action.
Room look commands are lifecycle-managed by the Ink room engine. The look bucket passed to `enter_room(...)` is offered only after Valerie re-enters a room she has previously left. Once the current look bucket has been selected during this room visit, shared Ink visit tracking hides it until the next leave-and-reenter cycle. Authored room look content must keep the `#key:l` convention and must not add custom seen/look flags.
Player-choice impact uses three distinct mechanisms. Cascades use semantic state chains when a choice changes the route, episode outcome, or later structure. Callbacks use named facts for exact remembered choices. Heuristics use route counters and relationship-matrix queries to color tone or summarize repeated patterns. Do not use a route heuristic when the later text needs to remember one specific earlier line.
When multiple choices from one prioritized family can appear on the same choice surface, use `claim_choice_gate_if(gate, available)` to allow only the first valid item in source order. This is mainly for `#auto` families such as Viktor return comments, which should also include a contact transition such as `reunion(viktor)` in their availability expression. The helper is transient and resets at the start of every `provide_choices`; it must not be used as story memory.
Delayed events that should advance while arbitrary bucket content is chosen use named turn timers. Timer IDs are LIST values. `timer_start(timer_id, turns)` restarts that named timer after removing it from all timer buckets. Expired timers remain ready until `timer_due(...)` or `timer_due_if(...)` claims them; claimed timers remain visible for the current turn and are cleared centrally by the next `TURN`. Content must not implement private countdown variables for reusable timed behavior.
## Choice Text Perspective
Choice text must describe the player character's intention before the action is taken. Do not write choices from a post-hoc author perspective that reveals what the branch will discover. For example, use "try the door" before the destination is known, not "go to the second-class cars"; use automatic or hidden events for things the player character cannot control, such as the train entering a tunnel.