Fix contact transitions and dining car access
This commit is contained in:
+31
-5
@@ -78,11 +78,12 @@ Author-facing helper functions live in `data/ink-src/eibenreith/helpers.ink` and
|
||||
- `time_*`, `day_*`, `slot_*`, `episode_*`: timetable and episode control.
|
||||
- `meal_*`: arrival-day meal plan.
|
||||
- `loc_*`, `enter_room`, `present`, `companion_*`: traversal, room setup, and companion presence.
|
||||
- `first_meeting(character)`, `reunion(character)`, `parting(character)`: contact-manager transitions for the one choice surface after a character first appears, reappears, or stops being present.
|
||||
- `alone`, `alone_with(character)`: privacy checks for dialogue that should only surface without witnesses or with exactly one companion.
|
||||
- `state_*`: ordered high-watermark encounter/progress state.
|
||||
- `mark`, `has`, `lacks`: exact checklist facts.
|
||||
- `tutorial`: returns true once and marks the tutorial as shown.
|
||||
- `claim_choice_gate(gate)`: transient choice-surface arbitration. Use only to allow at most one choice from a prioritized family, especially `#auto` groups.
|
||||
- `claim_choice_gate_if(gate, available)`: transient choice-surface arbitration. Use only to allow at most one valid choice from a prioritized family, especially `#auto` groups.
|
||||
- `rel_*`: relationship counters and two-value relationship-axis queries.
|
||||
|
||||
Relationship counters use only the standard value pairs declared in `characters.ink`:
|
||||
@@ -131,24 +132,49 @@ Use route and relationship helpers only as heuristics. They should color tone, s
|
||||
|
||||
## Choice-Surface Gates
|
||||
|
||||
`claim_choice_gate(gate)` returns true only for the first condition that claims the given gate while the current choice surface is being built. It is reset automatically at the start of `provide_choices`.
|
||||
`claim_choice_gate_if(gate, available)` returns true only for the first valid condition that claims the given gate while the current choice surface is being built. It is reset automatically at the start of `provide_choices`.
|
||||
|
||||
Use it when several choices can be valid at the same time but the surface must offer only one of them. The main use case is prioritized `#auto` families:
|
||||
|
||||
```ink
|
||||
* {state_reached(freshen_up_done)} {claim_choice_gate(return_auto)} [AUTO: Viktors Rückkehr nach Frischmachen] #auto:return(2)
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(freshen_up_done))} [AUTO: Viktors Rückkehr nach Frischmachen] #auto
|
||||
...
|
||||
-> TURN
|
||||
|
||||
* {state_reached(explore_train_done)} {claim_choice_gate(return_auto)} [AUTO: Viktors Rückkehr nach Erkundung] #auto:return(2)
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(explore_train_done))} [AUTO: Viktors Rückkehr nach Erkundung] #auto
|
||||
...
|
||||
-> TURN
|
||||
```
|
||||
|
||||
The source order of the atoms is the priority order. Auto choices are not randomized by the UI; the first ready auto choice is selected like a normal Ink choice. The gate prevents lower-priority choices from surfacing on the same choice build. Put `claim_choice_gate(...)` last in the condition list, after all ordinary availability checks, so a false candidate cannot consume the gate. The shared `#auto:key(delay)` prevents the same auto family from firing again too soon on later builds. Use the colon form for keyed auto tags on choice lines; bracketed `#auto[key](delay)` is not Ink-compatible there.
|
||||
The source order of the atoms is the priority order. Auto choices are not randomized by the UI; the first ready auto choice is selected like a normal Ink choice. The gate prevents lower-priority choices from surfacing on the same choice build. Use `claim_choice_gate_if(gate, available)` when availability is conditional; pass the whole availability expression as the second parameter so false candidates cannot consume the gate.
|
||||
|
||||
Do not use gates as story memory. World state belongs in Ink callbacks, `state_*` progress chains, or `mark/has/lacks` facts.
|
||||
|
||||
## Character Contact Manager
|
||||
|
||||
Character contact is managed centrally in `helpers.ink`. Authors should not add room-specific flags such as `viktor_back_in_compartment`, `met_viktor_here`, or `seen_viktor_leave`. `loc_move_to(...)` updates the player location, moves active companions, and refreshes contact state.
|
||||
|
||||
Use:
|
||||
|
||||
```ink
|
||||
{present(viktor)}
|
||||
{first_meeting(viktor)}
|
||||
{reunion(viktor)}
|
||||
{parting(viktor)}
|
||||
{alone()}
|
||||
{alone_with(viktor)}
|
||||
```
|
||||
|
||||
`first_meeting`, `reunion`, and `parting` are transition checks. They are true only for the first choice surface after the transition happened. The next turn clears them centrally in `provide_choices`. Authors must not call `contact_clear_transitions()` or any other cleanup helper from content. This makes the transitions suitable for immediate one-shot auto reactions:
|
||||
|
||||
```ink
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(freshen_up_done))} [AUTO: Viktors Rückkehr nach Frischmachen] #auto
|
||||
...
|
||||
-> TURN
|
||||
```
|
||||
|
||||
Companions are characters in the `companions` list. When Valerie traverses with `loc_move_to(...)`, companions automatically move to the new location before contact is updated. `companion_join(character)` and `companion_leave(character)` only change whether a character follows Valerie; they are not story-memory flags. Character starting positions and initial companion state belong in episode setup. If several characters are placed manually before play resumes, call `contact_sync()` once after setup to establish contact without firing a meeting or reunion reaction.
|
||||
|
||||
## Implemented Tag Forms
|
||||
|
||||
Use bracket tags for titles, filenames, and longer text:
|
||||
|
||||
+4
-2
@@ -39,11 +39,13 @@ Eibenreith authored content uses a mandatory bucket architecture. Rooms are inst
|
||||
|
||||
`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 should use Ink helpers instead of repeating location checks. `present(character)` checks whether an NPC is in the current room. `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.
|
||||
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.
|
||||
|
||||
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(gate)` to allow only the first valid item in source order. This is mainly for `#auto` families such as Viktor return comments. The helper is transient and resets at the start of every `provide_choices`; it must not be used as story memory.
|
||||
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.
|
||||
|
||||
## Choice Text Perspective
|
||||
|
||||
|
||||
+170
-141
@@ -19,9 +19,9 @@
|
||||
// ============================================================================
|
||||
|
||||
=== train_intro_start ===
|
||||
~ loc_move_to(loc_train_compartment)
|
||||
~ character_move_to(viktor, loc_train_compartment)
|
||||
~ companion_join(viktor)
|
||||
~ loc_move_to(loc_train_compartment)
|
||||
~ contact_sync()
|
||||
|
||||
Der Zug hat Wien hinter sich gelassen, doch du hast Wien noch nicht hinter dir gelassen. #chapter[Das Abteil] #music[Kaiserpunk Waltz.mp3](crossfade, loop, lead=8)
|
||||
|
||||
@@ -122,7 +122,7 @@ Für alle Fremden ist er nun dein Sekretär. Er öffnet Türen, trägt Gepäck,
|
||||
#alert[Links erscheinen Entscheidungen. Du kannst sie mit der Maus wählen oder mit der angezeigten Taste auslösen. Das hervorgehobene Wort beschreibt, was Valerie versucht; Kürzel wie L für Schaue oder X für Untersuche folgen Textadventure-Gewohnheiten.]
|
||||
}
|
||||
|
||||
* {state_reached(freshen_up_started)} {state_before(freshen_up_done)} {claim_choice_gate(return_auto)} [AUTO: Viktors Rückkehr nach unerledigtem Frischmachen] #auto:return(2)
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(freshen_up_started) && state_before(freshen_up_done))} [AUTO: Viktors Rückkehr nach unerledigtem Frischmachen] #auto
|
||||
Viktor hebt den Blick. Du bist zu rasch zurück, um die Begründung erfüllt zu haben, mit der du gegangen bist.
|
||||
|
||||
„Das war ein sehr kurzer Augenblick“, sagt er.
|
||||
@@ -131,7 +131,7 @@ Für alle Fremden ist er nun dein Sekretär. Er öffnet Türen, trägt Gepäck,
|
||||
~ rel_inc(viktor_closed)
|
||||
-> TURN
|
||||
|
||||
* {state_reached(freshen_up_done)} {claim_choice_gate(return_auto)} [AUTO: Viktors Rückkehr nach Frischmachen] #auto:return(2)
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(freshen_up_done))} [AUTO: Viktors Rückkehr nach Frischmachen] #auto
|
||||
Viktor hebt den Blick, als du wieder eintrittst. Er bemerkt zuerst nicht dein Gesicht, sondern die Arbeit daran: glattere Nadeln, kühlere Hände, ein Blick, der wieder dort sitzt, wo andere ihn erwarten.
|
||||
|
||||
„Besser?“, fragt er.
|
||||
@@ -140,7 +140,7 @@ Für alle Fremden ist er nun dein Sekretär. Er öffnet Türen, trägt Gepäck,
|
||||
~ rel_inc(viktor_reliable)
|
||||
-> TURN
|
||||
|
||||
* {state_reached(explore_train_started)} {state_before(explore_train_done)} {claim_choice_gate(return_auto)} [AUTO: Viktors Rückkehr nach kurzer Erkundung] #auto:return(2)
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(explore_train_started) && state_before(explore_train_done))} [AUTO: Viktors Rückkehr nach kurzer Erkundung] #auto
|
||||
Viktor hebt den Blick und sieht nicht zu deinem Gesicht, sondern zu deinen Schuhen, als könne der Gang Staub genug verraten.
|
||||
|
||||
„Und?“, fragt er. „Reicht der Zug weiter, als er sollte?“
|
||||
@@ -149,7 +149,7 @@ Für alle Fremden ist er nun dein Sekretär. Er öffnet Türen, trägt Gepäck,
|
||||
~ rel_inc(viktor_insightful)
|
||||
-> TURN
|
||||
|
||||
* {state_reached(explore_train_done)} {claim_choice_gate(return_auto)} [AUTO: Viktors Rückkehr nach Erkundung] #auto:return(2)
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(explore_train_done))} [AUTO: Viktors Rückkehr nach Erkundung] #auto
|
||||
Viktor hebt den Blick und sieht nicht zu deinem Gesicht, sondern zu deinen Schuhen, als könne der Gang Staub genug verraten.
|
||||
|
||||
„Und?“, fragt er. „Reicht der Zug weiter, als er sollte?“
|
||||
@@ -158,7 +158,7 @@ Für alle Fremden ist er nun dein Sekretär. Er öffnet Türen, trägt Gepäck,
|
||||
~ rel_inc(viktor_insightful)
|
||||
-> TURN
|
||||
|
||||
* {state_reached(mirror_started)} {state_before(mirror_done)} {claim_choice_gate(return_auto)} [AUTO: Viktors Rückkehr ohne Spiegel] #auto:return(2)
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(mirror_started) && state_before(mirror_done))} [AUTO: Viktors Rückkehr ohne Spiegel] #auto
|
||||
Viktor hebt den Blick. Dein Hut sitzt wie zuvor, dein Gesicht auch.
|
||||
|
||||
„Der Spiegel war offenbar streng“, sagt er.
|
||||
@@ -167,14 +167,14 @@ Für alle Fremden ist er nun dein Sekretär. Er öffnet Türen, trägt Gepäck,
|
||||
~ rel_inc(viktor_closed)
|
||||
-> TURN
|
||||
|
||||
* {state_reached(mirror_done)} {claim_choice_gate(return_auto)} [AUTO: Viktors Rückkehr nach Spiegel] #auto:return(2)
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(mirror_done))} [AUTO: Viktors Rückkehr nach Spiegel] #auto
|
||||
Viktor hebt den Blick. Der Hut sitzt fester, die Nadeln besser, und dein Gesicht ist wieder die Fassung, in der Fremde es lesen sollen.
|
||||
|
||||
„Gut“, sagt er. Nicht schön, nicht besser. Gut. Ein dienstliches Urteil über eine gesellschaftliche Oberfläche.
|
||||
~ rel_inc(viktor_reliable)
|
||||
-> TURN
|
||||
|
||||
* {state_reached(privacy_started)} {state_before(privacy_taken)} {claim_choice_gate(return_auto)} [AUTO: Viktors Rückkehr ohne Augenblick allein] #auto:return(2)
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(privacy_started) && state_before(privacy_taken))} [AUTO: Viktors Rückkehr ohne Augenblick allein] #auto
|
||||
Viktor hebt den Blick. Du bist gegangen, um Aufsicht loszuwerden, und warst doch kaum lange genug fort, um sie wirklich abzuschütteln.
|
||||
|
||||
„Hat der Augenblick genügt?“
|
||||
@@ -183,14 +183,14 @@ Für alle Fremden ist er nun dein Sekretär. Er öffnet Türen, trägt Gepäck,
|
||||
~ rel_inc(viktor_insightful)
|
||||
-> TURN
|
||||
|
||||
* {state_reached(privacy_taken)} {claim_choice_gate(return_auto)} [AUTO: Viktors Rückkehr nach privatem Augenblick] #auto:return(2)
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(privacy_taken))} [AUTO: Viktors Rückkehr nach privatem Augenblick] #auto
|
||||
Viktor hebt den Blick. Für eine kleine Weile gehörte dein Gesicht nur dir. Das merkt er, und weil er nicht dumm ist, benennt er es nicht.
|
||||
|
||||
„Wir fahren noch“, sagt er nur.
|
||||
~ rel_inc(viktor_open)
|
||||
-> TURN
|
||||
|
||||
* {state_reached(unwell_started)} {state_before(unwell_managed)} {claim_choice_gate(return_auto)} [AUTO: Viktors Rückkehr nach Unwohlsein] #auto:return(2)
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(unwell_started) && state_before(unwell_managed))} [AUTO: Viktors Rückkehr nach Unwohlsein] #auto
|
||||
Viktor hebt den Blick. Die Sorge kommt schneller als sein Misstrauen.
|
||||
|
||||
„Setzen Sie sich“, sagt er. „Langsam.“
|
||||
@@ -199,7 +199,7 @@ Für alle Fremden ist er nun dein Sekretär. Er öffnet Türen, trägt Gepäck,
|
||||
~ rel_inc(viktor_open)
|
||||
-> TURN
|
||||
|
||||
* {state_reached(unwell_managed)} {claim_choice_gate(return_auto)} [AUTO: Viktors Rückkehr nach Erleichterung] #auto:return(2)
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(unwell_managed))} [AUTO: Viktors Rückkehr nach Erleichterung] #auto
|
||||
Viktor hebt den Blick, prüft deinen Gang und lässt die Frage in der Mappe verschwinden, aus der sie nie ganz herauskam.
|
||||
|
||||
„Besser?“, fragt er.
|
||||
@@ -253,119 +253,14 @@ Für alle Fremden ist er nun dein Sekretär. Er öffnet Türen, trägt Gepäck,
|
||||
-> TURN
|
||||
|
||||
+ (asked_viktor_role) {has(class_def)}
|
||||
{lacks(route_language_def)} [__Stelle Viktor__: Wegen seiner Rolle zur Rede.]
|
||||
~ state_reach(ViktorRelationFrame.escort_present)
|
||||
~ state_reach(ViktorRelationFrame.secretary_cover_understood)
|
||||
{lacks(route_language_def)} [__Prüfe Viktor__: „Welche Aufgabe haben Sie wirklich, Herr Nowak?“]
|
||||
-> viktor_role_dialogue ->
|
||||
-> TURN
|
||||
|
||||
{tutorial(tut_dialog_intro):
|
||||
#alert[Steht eine Entscheidung in Anführungszeichen, spricht Valerie diese Zeile aus. Das hervorgehobene Verb benennt die soziale Bewegung der Antwort.]
|
||||
}
|
||||
|
||||
Viktor legt den Vordruck zurück in die Mappe. Du lässt ihm einen Augenblick, den Riemen zu schließen, und nimmst ihm dann die Bequemlichkeit, nur Sekretär zu sein.
|
||||
|
||||
* * [__Wahre Form__: „Welche Zeile betrifft Sie, Herr Nowak?“]
|
||||
„Welche Zeile betrifft Sie, Herr Nowak?“
|
||||
~ route_inc(route_composure)
|
||||
~ rel_inc(viktor_reliable)
|
||||
~ rel_inc(viktor_closed)
|
||||
Er sieht dich an, als habe er gehofft, du würdest höflicher ausweichen. „Auf dem Papier: Sekretär. In der Praxis: Begleitung.“
|
||||
|
||||
* * [__Prüfe__: „Wer hat angeordnet, dass ich nicht allein reise?“]
|
||||
„Wer hat angeordnet, dass ich nicht allein reise?“
|
||||
~ route_inc(route_detective)
|
||||
~ rel_inc(viktor_insightful)
|
||||
~ rel_inc(viktor_bold)
|
||||
„Die Stelle, die vermeiden möchte, dass diese Reise nach einer Anordnung aussieht.“
|
||||
|
||||
* * [__Entwaffne__: „Soll ich Sie Sekretär nennen, damit wir beide uns wohler fühlen?“]
|
||||
„Soll ich Sie Sekretär nennen, damit wir beide uns wohler fühlen?“
|
||||
~ route_inc(route_lover)
|
||||
~ rel_inc(viktor_open)
|
||||
~ rel_inc(viktor_unreliable)
|
||||
„Mich macht das Wort nicht wohler“, sagt er. „Aber es macht andere Leute weniger aufmerksam.“
|
||||
|
||||
* * [__Schütze dich__: „Wessen Sicherheit meinen Sie, wenn Sie von meiner Begleitung sprechen?“]
|
||||
„Wessen Sicherheit meinen Sie, wenn Sie von meiner Begleitung sprechen?“
|
||||
~ route_inc(route_sapphic)
|
||||
~ rel_inc(viktor_closed)
|
||||
~ rel_inc(viktor_insightful)
|
||||
Er antwortet nicht sofort. „Ihre. Die der Gastgeber. Und, falls die Berichte stimmen, die der Menschen, die nicht gefragt wurden.“
|
||||
|
||||
* * [__Verplappere dich__: „Ich weiß nicht, ob ich einen Sekretär, einen Wächter oder einen Zeugen vor mir habe.“]
|
||||
„Ich weiß nicht, ob ich einen Sekretär, einen Wächter oder einen Zeugen vor mir habe.“
|
||||
~ route_inc(route_careless)
|
||||
~ rel_inc(viktor_unreliable)
|
||||
~ rel_inc(viktor_passive)
|
||||
Etwas an seiner Aufmerksamkeit wird vorsichtiger. „Das ist immerhin näher an der Wahrheit als Sekretär.“
|
||||
|
||||
* * [__Benenne__: „Sie reisen mit, damit Wien später sagen kann, es habe aufgepasst.“]
|
||||
„Sie reisen mit, damit Wien später sagen kann, es habe aufgepasst.“
|
||||
~ route_inc(route_eccentric)
|
||||
~ rel_inc(viktor_bold)
|
||||
~ rel_inc(viktor_adversarial)
|
||||
„Wien sagt vieles später“, sagt Viktor. „Meistens mit saubereren Händen als vorher.“
|
||||
|
||||
-
|
||||
~ mark(route_language_def)
|
||||
~ state_reach(ValerieWorkingMask.social_strategy_established)
|
||||
-> briefing
|
||||
|
||||
|
||||
- (briefing)
|
||||
~ state_reach(ViktorRelationFrame.handler_role_understood)
|
||||
|
||||
Viktor öffnet die Mappe und nimmt ein Memorandum heraus. Diesmal behält er es nicht bei sich, sondern legt es so vor dich, dass du lesen kannst. #gloss[Memorandum](Amtliche Denkschrift. Lang genug, um Zuständigkeit zu behaupten, kurz genug, um gefährliche Dinge nicht beim Namen nennen zu müssen.)
|
||||
|
||||
„Beim Umstieg erwartet uns eine Kutsche aus Hohenreith“, sagt er. „Ihren Gastgebern wurde mitgeteilt, ich sei Ihnen bei Korrespondenz, Reiseangelegenheiten und praktischen Vorkehrungen behilflich. Mehr müssen sie vorerst nicht wissen.“ #gloss[Korrespondenz](Briefwechsel. Die vornehme Kunst, Absichten so lange zu falten, bis sie in ein Kuvert passen.)
|
||||
|
||||
* * [__Präzisiere__: „Was wissen sie, was vermuten sie, und was soll ich prüfen dürfen?“]
|
||||
„Was wissen sie, was vermuten sie, und was soll ich prüfen dürfen?“
|
||||
~ route_inc(route_detective)
|
||||
~ rel_inc(viktor_reliable)
|
||||
„Sie wissen, dass Sie empfohlen kommen. Sie vermuten, dass Sie Störungen ohne Polizei, Priester oder Presse beilegen könnten. Ihnen ist gestattet, Betrug, Zwang, Gefährdung der öffentlichen Ordnung oder glaubwürdige, derzeit nicht einzuordnende Erscheinungen zu prüfen.“
|
||||
|
||||
* * [__Spotte__: „Wie fürsorglich. Der Staat erspart ihnen die Wörter.“]
|
||||
„Wie fürsorglich. Der Staat erspart ihnen die Wörter.“
|
||||
~ route_inc(route_eccentric)
|
||||
~ rel_inc(viktor_adversarial)
|
||||
„Der Staat erspart Unruhe, wenn er kann“, sagt Viktor. „Oder verteilt sie wenigstens an die richtigen Personen.“
|
||||
|
||||
* * [__Wahre Form__: „Die Familie bekommt eine Dame. Die Akten bekommen eine Konsultation. Sie bekommen Spielraum.“]
|
||||
„Die Familie bekommt eine Dame. Die Akten bekommen eine Konsultation. Sie bekommen Spielraum.“
|
||||
~ route_inc(route_composure)
|
||||
~ rel_inc(viktor_reliable)
|
||||
„Eine Zusammenfassung, die ich nicht unterschreiben würde. Aber ich würde ihr nicht widersprechen.“
|
||||
|
||||
-
|
||||
~ state_reach(CourtMission.household_affair_named)
|
||||
~ state_reach(CourtMission.supernatural_pretext_named)
|
||||
|
||||
Das Memorandum ist nicht lang. Es nennt nur, was für die Reise nötig ist.
|
||||
|
||||
Ein gräflicher Haushalt. Ein Jagdhaus in der Obersteiermark, nicht der Hauptsitz der Familie. Berichte über Störungen unter Dienerschaft und Dorfbewohnern. Kein Einschreiten der Polizei erbeten. Keine öffentliche kirchliche Untersuchung erwünscht. Keine Presse. Deine Anwesenheit ist als diskrete Konsultation auf Wunsch der Familie zu erklären. Herr Nowak dient zur Unterstützung praktischer Angelegenheiten. #gloss[Jagdhaus](Adeliger Landsitz für Jagden und kurze Aufenthalte. Weniger Hauptsitz als Bühne für Gäste, Förster, Gewehre und Geheimnisse.) #gloss[Obersteiermark](Der gebirgige Norden der Steiermark. Wälder, Eisen, enge Täler und ein Wetter, das sich nicht für Wiener Empfindlichkeiten interessiert.) #gloss[Dienerschaft](Die Bediensteten eines Hauses. Offiziell Teil der Ordnung, praktisch ihr Gedächtnis.)
|
||||
|
||||
* * [__Entlarve__: „Das ist nicht die ganze Weisung.“]
|
||||
„Das ist nicht die ganze Weisung.“
|
||||
~ route_inc(route_detective)
|
||||
~ rel_inc(viktor_insightful)
|
||||
Viktor fragt nicht, woher du es weißt. „Es gibt immer noch eine weitere Weisung.“
|
||||
|
||||
* * [__Benenne__: „Wien vertraut uns beiden so wenig, dass es Misstrauen aufteilen musste.“]
|
||||
„Wien vertraut uns beiden so wenig, dass es Misstrauen aufteilen musste.“
|
||||
~ route_inc(route_eccentric)
|
||||
~ rel_inc(viktor_adversarial)
|
||||
Viktor fragt nicht, woher du es weißt. „Es gibt immer noch eine weitere Weisung.“
|
||||
|
||||
* * [__Zügle dich__: „Dann behalten Sie sie. Ich werde merken, wann sie zwischen uns steht.“]
|
||||
„Dann behalten Sie sie. Ich werde merken, wann sie zwischen uns steht.“
|
||||
~ route_inc(route_composure)
|
||||
~ rel_inc(viktor_reliable)
|
||||
„Das halte ich für wahrscheinlich.“
|
||||
|
||||
-
|
||||
~ state_reach(CourtMission.hidden_instruction_revealed)
|
||||
~ state_reach(ViktorRelationFrame.skepticism_registered)
|
||||
-> train_compartment
|
||||
+ {state_reached(dining_car_seen)}
|
||||
{meal(meal_unset)} [__Schlage Viktor vor__: „Wir könnten im Speisewagen essen.“]
|
||||
-> dining_plan_dialogue ->
|
||||
-> TURN
|
||||
|
||||
* (read_hohenreith_request) {has(class_def)}
|
||||
{lacks(belief_def)} [__Verlange__: Zu sehen, weshalb du gerufen wurdest.]
|
||||
@@ -414,30 +309,149 @@ Für alle Fremden ist er nun dein Sekretär. Er öffnet Türen, trägt Gepäck,
|
||||
~ mark(belief_def)
|
||||
-> train_compartment
|
||||
|
||||
+ {state_reached(dining_car_seen)}
|
||||
{meal(meal_unset)} [__Schlage vor__: Die Mittagsfrage zu klären.]
|
||||
-> DONE
|
||||
|
||||
|
||||
=== dining_plan_dialogue ===
|
||||
„Wir könnten im Speisewagen essen.“
|
||||
|
||||
„Beim Umstieg“, sagt Viktor, „wird Zeit sein, wenn wir sie nicht verlieren. Speisewagen, Bahnhofsrestauration oder nur etwas Kleines im Abteil. Alles spart etwas und kostet etwas.“ #gloss[Bahnhofsrestauration](Gastwirtschaft am Bahnhof. Reisezeit wird dort zu Suppe, Kaffee, Gedränge und sehr genauer Beobachtung von Gepäck und Stand.)
|
||||
|
||||
* * [__Wähle__: Jetzt mit Viktor in den Speisewagen zu gehen.]
|
||||
* [__Wähle__: Jetzt mit Viktor in den Speisewagen zu gehen.]
|
||||
~ meal_choose(dining_car)
|
||||
~ companion_join(viktor)
|
||||
Der Speisewagen ist kontrollierter als ein Bahnhof und öffentlicher als dieses Abteil. Man schaut dort mit Besteck in der Hand; das macht den Blick nicht freundlicher, nur gesellschaftsfähiger.
|
||||
|
||||
Viktor schließt die Mappe, steht auf und reicht dir nicht den Arm, sondern die Gelegenheit, ihn anzunehmen. Gemeinsam geht ihr in Fahrtrichtung durch die Wagen, bis der schmale Luxus des Speisewagens euch aufnimmt.
|
||||
-> train_dining_car
|
||||
-> train_dining_car_transition
|
||||
|
||||
* * [__Wähle__: Am Bahnhof zu essen.]
|
||||
* [__Wähle__: Am Bahnhof zu essen.]
|
||||
~ meal_choose(station_restaurant)
|
||||
Der Bahnhof ist lauter, unsauberer, ehrlicher. Man erfährt selten mehr über eine Ordnung, als wenn sie Suppe bestellt, Trinkgeld gibt und auf die Uhr sieht.
|
||||
|
||||
* * [__Wähle__: Nur Tee, Gebäck und Ruhe zu verlangen.]
|
||||
* [__Wähle__: Nur Tee, Gebäck und Ruhe zu verlangen.]
|
||||
~ meal_choose(light_refreshment)
|
||||
Du sparst Zeit, nicht Erschöpfung. Der Körper führt über solche Rechnungen eigene Bücher, und er ist selten nachsichtig.
|
||||
|
||||
-
|
||||
-> train_compartment
|
||||
->->
|
||||
|
||||
-> DONE
|
||||
|
||||
=== viktor_role_dialogue ===
|
||||
~ state_reach(ViktorRelationFrame.escort_present)
|
||||
~ state_reach(ViktorRelationFrame.secretary_cover_understood)
|
||||
|
||||
{tutorial(tut_dialog_intro):
|
||||
#alert[Steht eine Entscheidung in Anführungszeichen, spricht Valerie diese Zeile aus. Das hervorgehobene Verb benennt die soziale Bewegung der Antwort.]
|
||||
}
|
||||
|
||||
„Welche Aufgabe haben Sie wirklich, Herr Nowak?“
|
||||
|
||||
Viktor legt den Vordruck zurück in die Mappe. Du lässt ihm einen Augenblick, den Riemen zu schließen, und nimmst ihm dann die Bequemlichkeit, nur Sekretär zu sein.
|
||||
|
||||
* [__Wahre Form__: „Welche Zeile betrifft Sie, Herr Nowak?“]
|
||||
„Welche Zeile betrifft Sie, Herr Nowak?“
|
||||
~ route_inc(route_composure)
|
||||
~ rel_inc(viktor_reliable)
|
||||
~ rel_inc(viktor_closed)
|
||||
Er sieht dich an, als habe er gehofft, du würdest höflicher ausweichen. „Auf dem Papier: Sekretär. In der Praxis: Begleitung.“
|
||||
|
||||
* [__Prüfe__: „Wer hat angeordnet, dass ich nicht allein reise?“]
|
||||
„Wer hat angeordnet, dass ich nicht allein reise?“
|
||||
~ route_inc(route_detective)
|
||||
~ rel_inc(viktor_insightful)
|
||||
~ rel_inc(viktor_bold)
|
||||
„Die Stelle, die vermeiden möchte, dass diese Reise nach einer Anordnung aussieht.“
|
||||
|
||||
* [__Entwaffne__: „Soll ich Sie Sekretär nennen, damit wir beide uns wohler fühlen?“]
|
||||
„Soll ich Sie Sekretär nennen, damit wir beide uns wohler fühlen?“
|
||||
~ route_inc(route_lover)
|
||||
~ rel_inc(viktor_open)
|
||||
~ rel_inc(viktor_unreliable)
|
||||
„Mich macht das Wort nicht wohler“, sagt er. „Aber es macht andere Leute weniger aufmerksam.“
|
||||
|
||||
* [__Schütze dich__: „Wessen Sicherheit meinen Sie, wenn Sie von meiner Begleitung sprechen?“]
|
||||
„Wessen Sicherheit meinen Sie, wenn Sie von meiner Begleitung sprechen?“
|
||||
~ route_inc(route_sapphic)
|
||||
~ rel_inc(viktor_closed)
|
||||
~ rel_inc(viktor_insightful)
|
||||
Er antwortet nicht sofort. „Ihre. Die der Gastgeber. Und, falls die Berichte stimmen, die der Menschen, die nicht gefragt wurden.“
|
||||
|
||||
* [__Verplappere dich__: „Ich weiß nicht, ob ich einen Sekretär, einen Wächter oder einen Zeugen vor mir habe.“]
|
||||
„Ich weiß nicht, ob ich einen Sekretär, einen Wächter oder einen Zeugen vor mir habe.“
|
||||
~ route_inc(route_careless)
|
||||
~ rel_inc(viktor_unreliable)
|
||||
~ rel_inc(viktor_passive)
|
||||
Etwas an seiner Aufmerksamkeit wird vorsichtiger. „Das ist immerhin näher an der Wahrheit als Sekretär.“
|
||||
|
||||
* [__Benenne__: „Sie reisen mit, damit Wien später sagen kann, es habe aufgepasst.“]
|
||||
„Sie reisen mit, damit Wien später sagen kann, es habe aufgepasst.“
|
||||
~ route_inc(route_eccentric)
|
||||
~ rel_inc(viktor_bold)
|
||||
~ rel_inc(viktor_adversarial)
|
||||
„Wien sagt vieles später“, sagt Viktor. „Meistens mit saubereren Händen als vorher.“
|
||||
|
||||
-
|
||||
~ mark(route_language_def)
|
||||
~ state_reach(ValerieWorkingMask.social_strategy_established)
|
||||
-> briefing
|
||||
|
||||
|
||||
= briefing
|
||||
~ state_reach(ViktorRelationFrame.handler_role_understood)
|
||||
|
||||
Viktor öffnet die Mappe und nimmt ein Memorandum heraus. Diesmal behält er es nicht bei sich, sondern legt es so vor dich, dass du lesen kannst. #gloss[Memorandum](Amtliche Denkschrift. Lang genug, um Zuständigkeit zu behaupten, kurz genug, um gefährliche Dinge nicht beim Namen nennen zu müssen.)
|
||||
|
||||
„Beim Umstieg erwartet uns eine Kutsche aus Hohenreith“, sagt er. „Ihren Gastgebern wurde mitgeteilt, ich sei Ihnen bei Korrespondenz, Reiseangelegenheiten und praktischen Vorkehrungen behilflich. Mehr müssen sie vorerst nicht wissen.“ #gloss[Korrespondenz](Briefwechsel. Die vornehme Kunst, Absichten so lange zu falten, bis sie in ein Kuvert passen.)
|
||||
|
||||
* [__Präzisiere__: „Was wissen sie, was vermuten sie, und was soll ich prüfen dürfen?“]
|
||||
„Was wissen sie, was vermuten sie, und was soll ich prüfen dürfen?“
|
||||
~ route_inc(route_detective)
|
||||
~ rel_inc(viktor_reliable)
|
||||
„Sie wissen, dass Sie empfohlen kommen. Sie vermuten, dass Sie Störungen ohne Polizei, Priester oder Presse beilegen könnten. Ihnen ist gestattet, Betrug, Zwang, Gefährdung der öffentlichen Ordnung oder glaubwürdige, derzeit nicht einzuordnende Erscheinungen zu prüfen.“
|
||||
|
||||
* [__Spotte__: „Wie fürsorglich. Der Staat erspart ihnen die Wörter.“]
|
||||
„Wie fürsorglich. Der Staat erspart ihnen die Wörter.“
|
||||
~ route_inc(route_eccentric)
|
||||
~ rel_inc(viktor_adversarial)
|
||||
„Der Staat erspart Unruhe, wenn er kann“, sagt Viktor. „Oder verteilt sie wenigstens an die richtigen Personen.“
|
||||
|
||||
* [__Wahre Form__: „Die Familie bekommt eine Dame. Die Akten bekommen eine Konsultation. Sie bekommen Spielraum.“]
|
||||
„Die Familie bekommt eine Dame. Die Akten bekommen eine Konsultation. Sie bekommen Spielraum.“
|
||||
~ route_inc(route_composure)
|
||||
~ rel_inc(viktor_reliable)
|
||||
„Eine Zusammenfassung, die ich nicht unterschreiben würde. Aber ich würde ihr nicht widersprechen.“
|
||||
|
||||
-
|
||||
~ state_reach(CourtMission.household_affair_named)
|
||||
~ state_reach(CourtMission.supernatural_pretext_named)
|
||||
|
||||
Das Memorandum ist nicht lang. Es nennt nur, was für die Reise nötig ist.
|
||||
|
||||
Ein gräflicher Haushalt. Ein Jagdhaus in der Obersteiermark, nicht der Hauptsitz der Familie. Berichte über Störungen unter Dienerschaft und Dorfbewohnern. Kein Einschreiten der Polizei erbeten. Keine öffentliche kirchliche Untersuchung erwünscht. Keine Presse. Deine Anwesenheit ist als diskrete Konsultation auf Wunsch der Familie zu erklären. Herr Nowak dient zur Unterstützung praktischer Angelegenheiten. #gloss[Jagdhaus](Adeliger Landsitz für Jagden und kurze Aufenthalte. Weniger Hauptsitz als Bühne für Gäste, Förster, Gewehre und Geheimnisse.) #gloss[Obersteiermark](Der gebirgige Norden der Steiermark. Wälder, Eisen, enge Täler und ein Wetter, das sich nicht für Wiener Empfindlichkeiten interessiert.) #gloss[Dienerschaft](Die Bediensteten eines Hauses. Offiziell Teil der Ordnung, praktisch ihr Gedächtnis.)
|
||||
|
||||
* [__Entlarve__: „Das ist nicht die ganze Weisung.“]
|
||||
„Das ist nicht die ganze Weisung.“
|
||||
~ route_inc(route_detective)
|
||||
~ rel_inc(viktor_insightful)
|
||||
Viktor fragt nicht, woher du es weißt. „Es gibt immer noch eine weitere Weisung.“
|
||||
|
||||
* [__Benenne__: „Wien vertraut uns beiden so wenig, dass es Misstrauen aufteilen musste.“]
|
||||
„Wien vertraut uns beiden so wenig, dass es Misstrauen aufteilen musste.“
|
||||
~ route_inc(route_eccentric)
|
||||
~ rel_inc(viktor_adversarial)
|
||||
Viktor fragt nicht, woher du es weißt. „Es gibt immer noch eine weitere Weisung.“
|
||||
|
||||
* [__Zügle dich__: „Dann behalten Sie sie. Ich werde merken, wann sie zwischen uns steht.“]
|
||||
„Dann behalten Sie sie. Ich werde merken, wann sie zwischen uns steht.“
|
||||
~ route_inc(route_composure)
|
||||
~ rel_inc(viktor_reliable)
|
||||
„Das halte ich für wahrscheinlich.“
|
||||
|
||||
-
|
||||
~ state_reach(CourtMission.hidden_instruction_revealed)
|
||||
~ state_reach(ViktorRelationFrame.skepticism_registered)
|
||||
->->
|
||||
|
||||
|
||||
=== train_compartment_entry ===
|
||||
@@ -668,9 +682,6 @@ Im nächsten Wagen riecht der Gang stärker nach Kohle, feuchter Wolle und kalte
|
||||
Das Schild ist klein, emailliert und sachlich. Es verspricht nichts als Wasser, Spiegel und Verriegelung. Gerade deshalb wirkt es in diesem Zug beinahe intim.
|
||||
-> TURN
|
||||
|
||||
* [__Prüfe__: Die Tür zum Speisewagen.]
|
||||
Durch das Glas in Fahrtrichtung blitzt gelegentlich Weiß auf: Tücher, Hemdmanschetten, ein Kellnerärmel. Der Speisewagen ist kein Raum, den man zufällig betritt. Man erscheint dort, und dieses Erscheinen braucht eine Begründung.
|
||||
-> TURN
|
||||
-> DONE
|
||||
|
||||
|
||||
@@ -696,11 +707,8 @@ Der dritte Wagen ist praktischer gebaut. Türen stehen enger, der Boden antworte
|
||||
~ state_reach_if_started(unwell_managed)
|
||||
-> train_washroom
|
||||
|
||||
+ {state_before(dining_car_seen)} [__Sieh nach__: Was hinter der Tür in Fahrtrichtung liegt. #key:s]
|
||||
~ state_reach(dining_car_seen)
|
||||
~ state_reach_if_started(explore_train_done)
|
||||
Du öffnest die Tür in Fahrtrichtung nur weit genug, um hineinzusehen. Dahinter liegt der Speisewagen: weiße Tücher, Glas, Besteck, Kellner mit ruhigen Händen. Allein weiterzugehen wäre auffällig; mit Viktor wäre es eine Mahlzeit.
|
||||
-> TURN
|
||||
+ [__Öffne__: Die Tür in Fahrtrichtung. #key:s]
|
||||
-> train_dining_car_transition
|
||||
-> DONE
|
||||
|
||||
|
||||
@@ -708,6 +716,27 @@ Der dritte Wagen ist praktischer gebaut. Türen stehen enger, der Boden antworte
|
||||
// ROOM: DINING CAR
|
||||
// ============================================================================
|
||||
|
||||
=== train_dining_car_transition ===
|
||||
{
|
||||
- state_before(dining_car_seen):
|
||||
~ state_reach(dining_car_seen)
|
||||
~ state_reach_if_started(explore_train_done)
|
||||
Du öffnest die Tür in Fahrtrichtung nur weit genug, um hineinzusehen. Dahinter liegt der Speisewagen: weiße Tücher, Glas, Besteck, Kellner mit ruhigen Händen. Allein weiterzugehen wäre auffällig; mit Viktor wäre es eine Mahlzeit.
|
||||
}
|
||||
{
|
||||
- not present(viktor):
|
||||
Der Speisewagen ist kein Raum, den man zufällig betritt. Man erscheint dort, und dieses Erscheinen braucht eine Begründung. Ohne Viktor wäre es Neugier. Mit ihm könnte es Mittagessen sein.
|
||||
-> TURN
|
||||
- else:
|
||||
{loc(loc_train_compartment):
|
||||
Ihr geht in Fahrtrichtung durch den ersten Korridor, über die schwankenden Verbindungen, vorbei an Abteiltüren, Waschraumschild und blanken Griffen. Der Speisewagen wartet nicht, aber er nimmt euch auf, als hätte er euch erwartet.
|
||||
- else:
|
||||
Viktor öffnet die Tür in Fahrtrichtung für dich. Aus der Grenze wird ein Auftritt: Tischtücher, Glas, Kellnerhände und der kurze prüfende Blick jener Reisenden, die ihr Essen für Privatheit halten.
|
||||
}
|
||||
-> train_dining_car
|
||||
}
|
||||
|
||||
|
||||
=== train_dining_car ===
|
||||
-> enter_room(loc_train_dining_car, -> train_dining_car_entry, -> train_dining_car_look, -> train_dining_car_exits, -> train_dining_car_bucket) -> TURN
|
||||
|
||||
@@ -787,7 +816,7 @@ Der Speisewagen ist schmaler Luxus in Bewegung: Tische mit zu weißen Tüchern,
|
||||
=== train_dining_car_exits ===
|
||||
+ {present(viktor)} [__Beende__: Das Essen und kehre mit Viktor ins Abteil zurück. #key:n]
|
||||
Der Speisewagen entlässt euch mit Glasgeräusch und Kohlenrauch. Ihr geht gegen die Fahrtrichtung zurück, durch den praktischen Wagen, den zweiten Wagen und den ersten Korridor, bis Viktor die Tür zu eurem Abteil öffnet.
|
||||
~ character_move_to(viktor, loc_train_compartment)
|
||||
~ loc_move_to(loc_train_compartment)
|
||||
~ companion_leave(viktor)
|
||||
-> train_compartment
|
||||
-> DONE
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
|
||||
=== station_midday ===
|
||||
~ state_reach(meal_plan_chosen)
|
||||
~ character_move_to(viktor, loc_station_platform)
|
||||
~ companion_join(viktor)
|
||||
~ loc_move_to(loc_station_platform)
|
||||
~ contact_sync()
|
||||
|
||||
Die Station ist klein genug, dass der Zug kurz verlegen wirkt, als er dort hält. #chapter[Der Bahnhof] #image[muerzzuschlag.png](portrait)
|
||||
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
|
||||
|
||||
=== carriage_ride ===
|
||||
~ character_move_to(viktor, loc_carriage)
|
||||
~ companion_join(viktor)
|
||||
~ loc_move_to(loc_carriage)
|
||||
~ contact_sync()
|
||||
|
||||
Die Kutsche lässt die Station hinter sich und damit das letzte leicht erkennbare Zeichen der Monarchie. #chapter[Die Kutschenfahrt] #music[Kaiserpunk Jodler.mp3](crossfade, loop, lead=4)
|
||||
|
||||
|
||||
@@ -3877,9 +3877,9 @@ Komplexe Encounter sollen bevorzugt in mehrere parallele Progress-Tracker zerleg
|
||||
|
||||
Zusätzlich gibt es unabhängige Facts mit `mark`, `has` und `lacks`. Diese sind nur für zusammengehörige Gruppen einzelner Facts gedacht, die unabhängig voneinander wahr sein können und keine Reihenfolge implizieren, etwa Tutorial gesehen, Mahlzeit am Bahnhof genommen, öffentliche Form gewahrt oder beschädigt. Solche Facts sind keine Callbacks, solange sie nicht ein konkretes abgespieltes Contentstück ersetzen.
|
||||
|
||||
Für Choice-Surface-Arbitration gibt es `claim_choice_gate(gate)`. Dieser Helper ist kein Story-State. Er wird am Anfang jedes `provide_choices` zurückgesetzt und gibt innerhalb dieses einen Choice-Aufbaus nur beim ersten gültigen Claim für dasselbe Gate `true` zurück. Er wird verwendet, wenn mehrere Atome gleichzeitig gültig sein können, aber höchstens eines davon auf der Oberfläche erscheinen darf. Der wichtigste Fall sind priorisierte `#auto`-Familien wie Viktors Rückkehrkommentare.
|
||||
Für Choice-Surface-Arbitration gibt es `claim_choice_gate_if(gate, available)`. Dieser Helper ist kein Story-State. Er wird am Anfang jedes `provide_choices` zurückgesetzt und gibt innerhalb dieses einen Choice-Aufbaus nur beim ersten gültigen Claim für dasselbe Gate `true` zurück. Er wird verwendet, wenn mehrere Atome gleichzeitig gültig sein können, aber höchstens eines davon auf der Oberfläche erscheinen darf. Der wichtigste Fall sind priorisierte `#auto`-Familien wie Viktors Rückkehrkommentare.
|
||||
|
||||
Die Reihenfolge der Atome im Bucket ist dann die Priorität. Auto-Choices werden vom Client getrennt behandelt, nicht randomisiert und wie normale Ink-Choices ausgelöst. Ein gemeinsamer Auto-Key wie `#auto:return(2)` taktet die Familie über mehrere Choice-Turns; `claim_choice_gate(return_auto)` verhindert mehrere Treffer im selben Choice-Aufbau. Der Gate-Claim steht immer als letzte Bedingung hinter den normalen Verfügbarkeitsbedingungen, damit eine falsche Kandidaten-Choice das Gate nicht verbraucht. Auf Choice-Zeilen wird für keyed Auto-Tags die Doppelpunktform verwendet, weil `#auto[return](2)` dort von Ink nicht akzeptiert wird.
|
||||
Die Reihenfolge der Atome im Bucket ist dann die Priorität. Auto-Choices werden vom Client getrennt behandelt, nicht randomisiert und wie normale Ink-Choices ausgelöst. `claim_choice_gate_if(return_auto, available)` verhindert mehrere Treffer im selben Choice-Aufbau. Rückkehrkommentare müssen in ihrer `available`-Bedingung zusätzlich über den Contact Manager gegated werden, zum Beispiel mit `reunion(viktor)`. Die vollständige Verfügbarkeitsbedingung wird als zweiter Parameter übergeben, damit falsche Kandidaten das Gate nicht verbrauchen.
|
||||
|
||||
Regel: Wenn die spätere Zeile „du hast damals genau X getan“ bedeutet, ist es ein Callback und soll über ein Ink-Label laufen. Wenn sie „du wirkst auf mich inzwischen wie Y“ bedeutet, ist es eine Heuristik. Wenn sie „diese Wissens- oder Plotlinie ist jetzt mindestens so weit“ bedeutet, ist es ein Encounter State. Wenn sie „dieses unabhängige Ergebnis gilt“ bedeutet, ist es ein Fact. Wenn ein Vorgang auch nur begonnen und vollendet kennt, aber Vollendung den Beginn voraussetzt, ist es bereits ein Encounter State.
|
||||
|
||||
@@ -3892,15 +3892,30 @@ Nie zulässig:
|
||||
|
||||
## 12.5.2 Companion- und Privacy-Helfer
|
||||
|
||||
Für Dialoge, die nur ohne Zeugen oder nur mit einer bestimmten Begleitfigur auftauchen sollen:
|
||||
Der Contact Manager in `helpers.ink` verwaltet, welche getrackten Figuren gerade anwesend sind, welche Valerie zum ersten Mal trifft, welche sie nach einer Trennung wieder sieht und welche gerade nicht mehr anwesend sind. Kapiteldateien dürfen dafür keine raumspezifischen Flags wie `viktor_returned_to_compartment` oder `seen_viktor_leave` anlegen.
|
||||
|
||||
`loc_move_to(location)` setzt Valeries Ort, bewegt alle Figuren in `companions` mit und aktualisiert danach den Kontaktzustand. `companion_join(character)` und `companion_leave(character)` steuern nur, ob eine Figur Valerie bei Traversal folgt. Sie sind keine Erinnerungsflags. Startpositionen von Figuren und die anfängliche Begleitung gehören in das Episode-Setup. Wenn ein Setup mehrere Figuren manuell platziert, wird danach `contact_sync()` verwendet, damit der Anfangszustand ohne künstliche Wiedersehens- oder Erstbegegnungsreaktion gesetzt ist.
|
||||
|
||||
Für Dialoge, die nur ohne Zeugen, nur mit einer bestimmten Begleitfigur oder nur direkt nach einem Kontaktwechsel auftauchen sollen:
|
||||
|
||||
```ink
|
||||
{present(viktor): ...}
|
||||
{first_meeting(viktor): ...}
|
||||
{reunion(viktor): ...}
|
||||
{parting(viktor): ...}
|
||||
{alone(): ...}
|
||||
{alone_with(viktor): ...}
|
||||
```
|
||||
|
||||
`present(character)` prüft, ob die Figur im aktuellen Raum ist. `alone()` ist wahr, wenn keine getrackte Figur im Raum ist. `alone_with(character)` ist wahr, wenn genau diese Figur anwesend ist. Bei neuen getrackten Figuren muss die Helper-Implementierung erweitert werden, damit `alone()` und `alone_with()` nicht still zu eng bleiben.
|
||||
`present(character)` prüft, ob die Figur im aktuellen Raum ist. `first_meeting(character)`, `reunion(character)` und `parting(character)` gelten nur für die erste Choice-Oberfläche direkt nach dem Kontaktwechsel. Der nächste Turn löscht diese Transitionen automatisch in `provide_choices`. Kapitelinhalt darf Contact-Transitionen nur abfragen, niemals manuell löschen oder verbrauchen.
|
||||
|
||||
```ink
|
||||
+ {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(freshen_up_done))} [AUTO: Viktors Rückkehr nach Frischmachen] #auto
|
||||
...
|
||||
-> TURN
|
||||
```
|
||||
|
||||
`alone()` ist wahr, wenn keine getrackte Figur im Raum ist. `alone_with(character)` ist wahr, wenn genau diese Figur anwesend ist. Bei neuen getrackten Figuren muss die Helper-Implementierung an einer Stelle erweitert werden, damit Presence, Contact Transitions und Privacy Checks gemeinsam korrekt bleiben.
|
||||
|
||||
## 12.6 Conditionals
|
||||
|
||||
|
||||
@@ -45,6 +45,14 @@ VAR current_episode_end = -> empty_bucket
|
||||
VAR current_game_bucket = -> game_bucket
|
||||
VAR claimed_choice_gates = ()
|
||||
|
||||
VAR contact_seen = ()
|
||||
VAR contact_present = ()
|
||||
VAR contact_arrived = ()
|
||||
VAR contact_departed = ()
|
||||
VAR contact_first_met = ()
|
||||
VAR contact_rejoined = ()
|
||||
VAR contact_transition_fresh = false
|
||||
|
||||
VAR slot_early_morning_episode = no_episode
|
||||
VAR slot_mid_morning_episode = episode_train_intro
|
||||
VAR slot_noon_episode = episode_station_midday
|
||||
@@ -81,6 +89,12 @@ VAR slot_late_night_episode = no_episode
|
||||
=== provide_choices ===
|
||||
~ claimed_choice_gates = ()
|
||||
{
|
||||
- contact_transition_fresh:
|
||||
~ contact_transition_fresh = false
|
||||
- else:
|
||||
~ contact_clear_transitions()
|
||||
}
|
||||
{
|
||||
- room_seen_on_enter():
|
||||
<- current_moment_bucket
|
||||
<- current_room_look_bucket
|
||||
@@ -107,11 +121,11 @@ VAR slot_late_night_episode = no_episode
|
||||
// mark/has/lacks facts.
|
||||
//
|
||||
// Example:
|
||||
// Put claim_choice_gate last in the condition list. Earlier conditions should
|
||||
// prove that the choice is valid before this side-effecting helper consumes the
|
||||
// gate.
|
||||
// Use claim_choice_gate_if when the choice has any availability condition. Pass
|
||||
// the whole availability expression as the second parameter so invalid choices
|
||||
// cannot consume the gate while Ink is checking the surface.
|
||||
//
|
||||
// * {state_reached(freshen_up_done)} {claim_choice_gate(return_auto)} [...] #auto:return(2)
|
||||
// * {claim_choice_gate_if(return_auto, reunion(viktor) && state_reached(freshen_up_done))} [...] #auto
|
||||
=== function claim_choice_gate(gate) ===
|
||||
{
|
||||
- claimed_choice_gates ? gate:
|
||||
@@ -121,6 +135,14 @@ VAR slot_late_night_episode = no_episode
|
||||
~ return true
|
||||
}
|
||||
|
||||
=== function claim_choice_gate_if(gate, available) ===
|
||||
{
|
||||
- not available:
|
||||
~ return false
|
||||
- else:
|
||||
~ return claim_choice_gate(gate)
|
||||
}
|
||||
|
||||
|
||||
=== empty_bucket ===
|
||||
-> DONE
|
||||
@@ -517,10 +539,17 @@ VAR route_eccentric = 0
|
||||
//
|
||||
// Author-facing helpers:
|
||||
// - loc(value), loc_is(value): true when Valerie is at location.
|
||||
// - loc_move_to(value): move Valerie and all current companions to location.
|
||||
// - loc_move_to(value): move Valerie and all current companions to location,
|
||||
// then update the contact manager.
|
||||
// - accompanied_by(character): true when character is in the companion list.
|
||||
// - companion_join(character), companion_leave(character): update companions.
|
||||
// - present(character): true when a character's location equals current_location.
|
||||
// - first_meeting(character): true on the choice surface where Valerie meets
|
||||
// that tracked character for the first time.
|
||||
// - reunion(character): true on the choice surface where Valerie sees a known
|
||||
// tracked character again after they were apart.
|
||||
// - parting(character): true on the choice surface after a tracked character
|
||||
// has just stopped being present.
|
||||
// - alone(): true when no tracked NPC is currently present with Valerie.
|
||||
// - alone_with(character): true when exactly the given tracked NPC is present.
|
||||
// - character_move_to(character, location): move a known NPC independently.
|
||||
@@ -532,6 +561,12 @@ VAR route_eccentric = 0
|
||||
//
|
||||
// Internal helper:
|
||||
// - move_companions_to(location) is used by loc_move_to().
|
||||
// - contact_update() refreshes first-meeting, reunion, and parting transitions.
|
||||
// - contact_sync() establishes current contact without transitions, useful
|
||||
// after episode setup that places multiple characters at once.
|
||||
// - contact_clear_transitions() is called internally by provide_choices. Content
|
||||
// must not consume or clear contact transitions manually.
|
||||
// - characters_at(location) must be extended when a new tracked NPC is added.
|
||||
// - room_seen_on_enter() is used by provide_choices() to decide whether to show
|
||||
// the one-shot entry text or the repeat look action.
|
||||
|
||||
@@ -541,6 +576,7 @@ VAR route_eccentric = 0
|
||||
=== function loc_move_to(value) ===
|
||||
~ current_location = value
|
||||
~ move_companions_to(value)
|
||||
~ contact_update()
|
||||
|
||||
=== function loc_is(value) ===
|
||||
~ return current_location == value
|
||||
@@ -555,12 +591,16 @@ VAR route_eccentric = 0
|
||||
~ companions -= character
|
||||
|
||||
=== function present(character) ===
|
||||
{
|
||||
- character == viktor:
|
||||
~ return viktor_location == current_location
|
||||
- else:
|
||||
~ return false
|
||||
}
|
||||
~ return characters_at(current_location) ? character
|
||||
|
||||
=== function first_meeting(character) ===
|
||||
~ return contact_first_met ? character
|
||||
|
||||
=== function reunion(character) ===
|
||||
~ return contact_rejoined ? character
|
||||
|
||||
=== function parting(character) ===
|
||||
~ return contact_departed ? character
|
||||
|
||||
=== function alone() ===
|
||||
~ return not present(viktor)
|
||||
@@ -578,6 +618,7 @@ VAR route_eccentric = 0
|
||||
- character == viktor:
|
||||
~ viktor_location = location
|
||||
}
|
||||
~ contact_update()
|
||||
|
||||
=== function move_companions_to(location) ===
|
||||
{
|
||||
@@ -585,6 +626,58 @@ VAR route_eccentric = 0
|
||||
~ viktor_location = location
|
||||
}
|
||||
|
||||
=== function characters_at(location) ===
|
||||
~ temp result = ()
|
||||
{
|
||||
- viktor_location == location:
|
||||
~ result += viktor
|
||||
}
|
||||
~ return result
|
||||
|
||||
=== function contact_sync() ===
|
||||
~ contact_present = characters_at(current_location)
|
||||
~ contact_seen += contact_present
|
||||
~ contact_arrived = ()
|
||||
~ contact_departed = ()
|
||||
~ contact_first_met = ()
|
||||
~ contact_rejoined = ()
|
||||
~ contact_transition_fresh = false
|
||||
|
||||
=== function contact_update() ===
|
||||
~ temp previous = contact_present
|
||||
~ contact_present = characters_at(current_location)
|
||||
~ contact_arrived = ()
|
||||
~ contact_departed = ()
|
||||
~ contact_first_met = ()
|
||||
~ contact_rejoined = ()
|
||||
{
|
||||
- (contact_present ? viktor) && not (previous ? viktor):
|
||||
~ contact_arrived += viktor
|
||||
{
|
||||
- contact_seen ? viktor:
|
||||
~ contact_rejoined += viktor
|
||||
- else:
|
||||
~ contact_first_met += viktor
|
||||
}
|
||||
}
|
||||
{
|
||||
- (previous ? viktor) && not (contact_present ? viktor):
|
||||
~ contact_departed += viktor
|
||||
}
|
||||
~ contact_seen += contact_present
|
||||
~ contact_transition_fresh = false
|
||||
{
|
||||
- contact_arrived || contact_departed || contact_first_met || contact_rejoined:
|
||||
~ contact_transition_fresh = true
|
||||
}
|
||||
|
||||
=== function contact_clear_transitions() ===
|
||||
~ contact_arrived = ()
|
||||
~ contact_departed = ()
|
||||
~ contact_first_met = ()
|
||||
~ contact_rejoined = ()
|
||||
~ contact_transition_fresh = false
|
||||
|
||||
=== enter_episode(value, slot, start_bucket, end_bucket, episode_bucket) ===
|
||||
~ episode_start(value, slot)
|
||||
~ current_episode_start = start_bucket
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user