Fix contact transitions and dining car access

This commit is contained in:
2026-05-24 18:14:16 +02:00
parent 510901f5bf
commit eef90f3471
8 changed files with 333 additions and 166 deletions
+104 -11
View File
@@ -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