ludic/packages/ludic.clock
2026-09-28 20:13:58 +03:00
..
tests refactor(packages): 0.R5 - a question no longer starts its state - 64 lazy starts ('if st.x == null { st.x = ... }' inside a getter) are the state's defaults, gear__ensure is gone, and ludic migrate state --tighten took mut off 208 package parameters: things_all, thing_find, gear_charge, gear_level, jobs_state and the rest read 2026-09-27 00:51:03 +03:00
calendar.ludic wip(0.S3): packages and examples migrated again from their pre-0.S sources in one run 2026-09-25 15:31:34 +03:00
index.ludic refactor(packages): the mechanic packages use ludic_base only, and ask through ports 2026-09-25 05:36:11 +03:00
package.ludic feat(ludic.clock): the hours, the day, the moon and a calendar as a mechanic package 2026-09-25 04:20:47 +03:00
queries.ludic ludic.clock: clock_hhmm reads a table of the day's times made with the state; ludic.minimap: minimap_pin past the end is one kept empty mark; ludic.ui: ev_text's memo miss is its own declared function 2026-09-28 17:57:30 +03:00
README.md refactor(packages): the mechanic packages use ludic_base only, and ask through ports 2026-09-25 05:36:11 +03:00
state.ludic ludic.clock: clock_hhmm reads a table of the day's times made with the state; ludic.minimap: minimap_pin past the end is one kept empty mark; ludic.ui: ev_text's memo miss is its own declared function 2026-09-28 17:57:30 +03:00
system.ludic feat(base): 0.R4 - a queue keeps its own count, so every package verb takes only its own state; ludic migrate state --prune 2026-09-26 04:19:56 +03:00
verbs.ludic ludic.fishing, net, clock: their dice made once and seeded again, never made again per reset; ludic.minimap's near list kept, its marks and grid declared 2026-09-28 20:13:58 +03:00

ludic.clock

One clock for a whole world: the hour, the day, the moon's place in its month, and where the day falls in a calendar the game describes - month, year and season as a pure function of the day. Uses ludic.base and nothing else.

import "ludic.clock"

The clock never runs the morning. A day turning - past midnight, or by clock_new_day after a night slept - is a DayTurned fact on clock_days(), and the game drains it into whatever its morning is (weather, restocking, the animals' day). Only the machine that owns the world moves the hour; another machine is told it (clock_set_hours, clock_set_day, clock_set_moon).

The port

export port ClockWorld {
  owns_world: fn() -> bool = ...    # does this machine run the world? (unbound: yes)
  rest_scale: fn() -> float = ...   # how much everyone's rest speeds the clock (unbound: 1)
  seed: fn() -> int = ...           # a seed for a new trip's moon (unbound: 1)
}

The game fills it once, where it is put together, and may leave any member out:

bind ClockWorld { owns_world: fn ses_owns_world, rest_scale: fn rt_rest_scale, seed: fn rt_clock_seed }

API

bind ClockWorld { ... } the port (a declaration, not a call)
clock_config(start_hours, night_from, night_to) when a trip starts, and which hours are night
clock_config_moon(days, lo, hi) the moon's month in days, and the part of it a new trip starts in
clock_calendar(month_days, season_of_month) a month's length, and each month's season (the list's length is the year)
clock_set_scale(s), clock_scale() game seconds per real second
clock_rate(), clock_hours_in(dt) the rate with the rest included, and the game hours dt real seconds are worth
clock_advance(gh) run the hours on (the system's tick does this from Tick.hours); past midnight the day turns
clock_new_day() turn the day now (the caller sets the hour first)
clock_reset() day one at the start hour, the moon from the seed
clock_day(), clock_hours(), clock_moon(), clock_hhmm(), clock_is_night() what the world asks
clock_month(), clock_year(), clock_day_of_month(), clock_season(), clock_days_to_change() today in the calendar
clock_month_of(d), clock_year_of(d), clock_day_of_month_of(d), clock_season_of(d), clock_days_to_change_from(d), clock_first_day_of(season) any day in the calendar
clock_days() -> Queue<DayTurned> the facts: { day, how }, how one of DAY_STAYED_UP, DAY_SLEPT
clock_system() -> System "clock", PH_INPUT (first, so every later system reads this frame's hour): reset, tick, and its save section (clock_save, clock_load: day, hours, moon)

Tests

ludic build packages/ludic.clock/tests/clock_test.ludic --headless -o /tmp/clock_test && /tmp/clock_test