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
+196 -12
View File
@@ -43,7 +43,27 @@ VAR current_episode_bucket = -> empty_bucket
VAR current_episode_start = -> empty_bucket
VAR current_episode_end = -> empty_bucket
VAR current_game_bucket = -> game_bucket
VAR current_companion_transition_bucket = -> empty_bucket
VAR claimed_choice_gates = ()
VAR turn_index = 0
VAR entered_rooms = ()
VAR room_look_available = false
VAR room_enter_turn = 0
VAR traversal_previous_location = loc_train_compartment
VAR traversal_next_location = loc_train_compartment
VAR timers_1 = ()
VAR timers_2 = ()
VAR timers_3 = ()
VAR timers_4 = ()
VAR timers_5 = ()
VAR timers_6 = ()
VAR timers_7 = ()
VAR timers_8 = ()
VAR timers_9 = ()
VAR timers_10 = ()
VAR timers_11 = ()
VAR timers_ready = ()
VAR timers_claimed = ()
VAR contact_seen = ()
VAR contact_present = ()
@@ -83,6 +103,8 @@ VAR slot_late_night_episode = no_episode
// helper logic.
=== TURN ===
~ turn_index = turn_index + 1
~ timer_tick()
-> provide_choices
@@ -97,7 +119,10 @@ VAR slot_late_night_episode = no_episode
{
- room_seen_on_enter():
<- current_moment_bucket
<- current_room_look_bucket
{
- room_look_available && room_look_unused_since_enter():
<- current_room_look_bucket
}
- else:
<- current_room_entry_bucket
<- current_moment_bucket
@@ -148,6 +173,115 @@ VAR slot_late_night_episode = no_episode
-> DONE
// ============================================================================
// TURN TIMERS
// ============================================================================
// Generic named countdown timers for authored content.
//
// Timer IDs are LIST values declared in the root file. A timer is started by
// name and duration:
//
// ~ timer_start(train_lunch_order, 3)
//
// The same timer name can only exist once. Starting it again first removes it
// from every countdown, ready, and claimed bucket, then places it at the new
// duration. Durations 1..10 mean "after this many later player choices"; the
// current choice that starts the timer does not consume one of those turns.
//
// Every TURN advances timers centrally. When a countdown expires, the timer
// remains in timers_ready until content claims it. timer_due(timer_id) returns
// true if the timer is ready or already claimed this turn. On the first true
// ready check it moves the timer from ready to claimed. Claimed timers remain
// queryable for the rest of the current turn and are cleared by the next TURN.
//
// Use timer_due_if(timer_id, available) for choice conditions with additional
// story-state requirements. It only claims the timer if available is true.
// Use timer_claim(timer_id) inside chosen content when that content makes the
// timer-controlled event happen before its natural expiry.
=== function timer_tick() ===
~ timers_claimed = ()
~ timers_ready += timers_1
~ timers_1 = timers_2
~ timers_2 = timers_3
~ timers_3 = timers_4
~ timers_4 = timers_5
~ timers_5 = timers_6
~ timers_6 = timers_7
~ timers_7 = timers_8
~ timers_8 = timers_9
~ timers_9 = timers_10
~ timers_10 = timers_11
~ timers_11 = ()
=== function timer_remove(timer_id) ===
~ timers_1 -= timer_id
~ timers_2 -= timer_id
~ timers_3 -= timer_id
~ timers_4 -= timer_id
~ timers_5 -= timer_id
~ timers_6 -= timer_id
~ timers_7 -= timer_id
~ timers_8 -= timer_id
~ timers_9 -= timer_id
~ timers_10 -= timer_id
~ timers_11 -= timer_id
~ timers_ready -= timer_id
~ timers_claimed -= timer_id
=== function timer_start(timer_id, turns) ===
~ timer_remove(timer_id)
{
- turns <= 1:
~ timers_2 += timer_id
- turns == 2:
~ timers_3 += timer_id
- turns == 3:
~ timers_4 += timer_id
- turns == 4:
~ timers_5 += timer_id
- turns == 5:
~ timers_6 += timer_id
- turns == 6:
~ timers_7 += timer_id
- turns == 7:
~ timers_8 += timer_id
- turns == 8:
~ timers_9 += timer_id
- turns == 9:
~ timers_10 += timer_id
- else:
~ timers_11 += timer_id
}
=== function timer_due(timer_id) ===
{
- timers_claimed ? timer_id:
~ return true
- timers_ready ? timer_id:
~ timers_ready -= timer_id
~ timers_claimed += timer_id
~ return true
- else:
~ return false
}
=== function timer_due_if(timer_id, available) ===
{
- not available:
~ return false
- else:
~ return timer_due(timer_id)
}
=== function timer_claim(timer_id) ===
~ timer_remove(timer_id)
~ timers_claimed += timer_id
=== function timer_pending(timer_id) ===
~ return timers_1 ? timer_id || timers_2 ? timer_id || timers_3 ? timer_id || timers_4 ? timer_id || timers_5 ? timer_id || timers_6 ? timer_id || timers_7 ? timer_id || timers_8 ? timer_id || timers_9 ? timer_id || timers_10 ? timer_id || timers_11 ? timer_id || timers_ready ? timer_id || timers_claimed ? timer_id
// ============================================================================
// INTRO / CHARACTER-GENERATION VARIABLES
// ============================================================================
@@ -444,11 +578,11 @@ VAR route_eccentric = 0
=== run_episode(episode_to_run) ===
{
- episode_to_run == episode_train_intro:
-> enter_episode(episode_train_intro, mid_morning, -> train_intro_start, -> train_intro_end, -> train_intro_episode_bucket) -> train_intro_start
-> enter_episode(episode_train_intro, mid_morning, -> train_intro_start, -> train_intro_end, -> train_intro_episode_bucket, -> train_companion_transition_bucket) -> train_intro_start
- episode_to_run == episode_station_midday:
-> enter_episode(episode_station_midday, noon, -> station_midday, -> station_midday_end, -> station_midday_episode_bucket) -> station_midday
-> enter_episode(episode_station_midday, noon, -> station_midday, -> station_midday_end, -> station_midday_episode_bucket, -> empty_bucket) -> station_midday
- episode_to_run == episode_carriage_ride:
-> enter_episode(episode_carriage_ride, afternoon, -> carriage_ride, -> carriage_ride_end, -> carriage_ride_episode_bucket) -> carriage_ride
-> enter_episode(episode_carriage_ride, afternoon, -> carriage_ride, -> carriage_ride_end, -> carriage_ride_episode_bucket, -> empty_bucket) -> carriage_ride
- episode_to_run == episode_first_dinner:
-> pre_dinner_transition
- else:
@@ -473,10 +607,11 @@ VAR route_eccentric = 0
// - outcome_is(value), outcome_move_to(value): query/set the last slot outcome.
//
// Structural helper:
// - enter_episode(value, slot, start_bucket, end_bucket, episode_bucket) is a
// tunnel used by run_episode. It installs the episode's start/end/bucket
// targets and resets the slot outcome. It should be called from timetable
// dispatch, not from random room content.
// - enter_episode(value, slot, start_bucket, end_bucket, episode_bucket,
// companion_transition_bucket) is a tunnel used by run_episode. It installs
// the episode's start/end/content buckets, the optional companion traversal
// prose bucket, and resets the slot outcome. It should be called from
// timetable dispatch, not from random room content.
=== function episode(value) ===
~ return active_episode == value
@@ -494,6 +629,7 @@ VAR route_eccentric = 0
~ current_episode_bucket = -> empty_bucket
~ current_episode_start = -> empty_bucket
~ current_episode_end = -> empty_bucket
~ current_companion_transition_bucket = -> empty_bucket
~ last_slot_outcome = outcome
=== function episode_active(value) ===
@@ -540,9 +676,12 @@ 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,
// then update the contact manager.
// record traversal origin/destination, then update the contact manager.
// - accompanied_by(character): true when character is in the companion list.
// - companion_join(character), companion_leave(character): update companions.
// - traversal_from(location), traversal_to(location), traversal_between(a, b):
// true for the movement that just entered the current room. Use only inside
// companion transition buckets.
// - 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.
@@ -556,7 +695,8 @@ VAR route_eccentric = 0
//
// Structural helper:
// - enter_room(location, entry_bucket, look_bucket, exit_bucket, moment_bucket)
// moves Valerie, updates companions, and installs the active room buckets.
// moves Valerie, updates companions, prints the active companion transition
// bucket, and installs the active room buckets.
// Room knots should normally do nothing except call enter_room and then TURN.
//
// Internal helper:
@@ -568,14 +708,21 @@ VAR route_eccentric = 0
// 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.
// the one-shot entry text.
// - room_look_unused_since_enter() uses Ink visit tracking to hide the look
// bucket after it was used during the current room visit. Chapter content must
// not create custom look flags or call room helpers manually.
=== function loc(value) ===
~ return current_location == value
=== function loc_move_to(value) ===
~ temp previous_location = current_location
~ traversal_previous_location = previous_location
~ traversal_next_location = value
~ current_location = value
~ move_companions_to(value)
~ room_update_on_move(previous_location, value)
~ contact_update()
=== function loc_is(value) ===
@@ -590,6 +737,15 @@ VAR route_eccentric = 0
=== function companion_leave(character) ===
~ companions -= character
=== function traversal_from(location) ===
~ return traversal_previous_location == location
=== function traversal_to(location) ===
~ return traversal_next_location == location
=== function traversal_between(origin, destination) ===
~ return traversal_from(origin) && traversal_to(destination)
=== function present(character) ===
~ return characters_at(current_location) ? character
@@ -678,15 +834,43 @@ VAR route_eccentric = 0
~ contact_rejoined = ()
~ contact_transition_fresh = false
=== enter_episode(value, slot, start_bucket, end_bucket, episode_bucket) ===
=== function room_update_on_move(previous_location, next_location) ===
{
- previous_location != next_location:
~ room_enter_turn = turn_index
{
- entered_rooms ? next_location:
~ room_look_available = true
- else:
~ room_look_available = false
}
~ entered_rooms += next_location
- not (entered_rooms ? next_location):
~ room_enter_turn = turn_index
~ room_look_available = false
~ entered_rooms += next_location
}
=== function room_look_unused_since_enter() ===
~ temp turns_since_look = TURNS_SINCE(current_room_look_bucket)
{
- turns_since_look < 0:
~ return true
- else:
~ return turn_index - turns_since_look < room_enter_turn
}
=== enter_episode(value, slot, start_bucket, end_bucket, episode_bucket, companion_transition_bucket) ===
~ episode_start(value, slot)
~ current_episode_start = start_bucket
~ current_episode_end = end_bucket
~ current_episode_bucket = episode_bucket
~ current_companion_transition_bucket = companion_transition_bucket
->->
=== enter_room(location, entry_bucket, look_bucket, exit_bucket, moment_bucket) ===
~ loc_move_to(location)
-> current_companion_transition_bucket ->
~ current_room_entry_bucket = entry_bucket
~ current_moment_bucket = moment_bucket
~ current_room_look_bucket = look_bucket