Game
The turn engine of **Helsinki Life**. Mounted on `mount_rules` by the scene entrypoint; it is the only thing that writes `HL.state()`.
Game
The turn engine of Helsinki Life. Mounted on mount_rules by the scene
entrypoint; it is the only thing that writes HL.state().
What it owns
- Setup - the title and the player-count card,
HL.resetState, the openingintrobeat. - The turn - spin 1–10, walk the board a tile at a time along
tile.next, the Pasila fork, halting on a STOP-kind tile, and the landing. - Resolution - paydays (paid on ENTERING the tile, so a pawn walking over one is paid too), tuition on the Kumpula study tiles, the degree at Graduation, event cards, the career / home / fork choices, the wedding and family beats, Suomenlinna, and the ranking.
HL.actions- every entry buttoggleOverview(stage's).play.inputMap- activated foract,navigate,backandpause, so the whole game is playable from a keyboard, a pad or the touch overlay with no other slice present.
How a turn runs
TURN act → spin()
SPIN spinSeconds → spinResult, then the walk
MOVE stepSeconds/tile → moveStep per tile · a fork raises a CHOICE mid-walk
landSeconds → moveEnd, then the tile resolves
EVENT a card is up → confirm() closes it (not before cardMinSeconds)
CHOICE an option list → choose(index)
→ the next player, or OVER when every pawn is at Suomenlinna
Timing is a one-shot timer list ticked from the frame hook, so pause() freezes
a spin mid-turn and nothing runs behind the pause card. The hook is update in
play and editorUpdate while the clock is held, each driving the body once.
Two ways in, one set of calls
The screens slice puts the cards up and activates menu.inputMap, which stands
the play group down; its buttons then call the same HL.actions. With no
screens slice the map here stays live and drives the identical calls from
act / navigate / back / pause. Both paths end in spin, confirm,
choose and pause.
act reads the phase: title → the setup card, setup → deal, intro → cut the
flyover, turn → spin, choice → take the focused option, event → close the card,
paused → resume, over → play again.
Beyond the documented actions
HL.actions carries five more entries the screens slice can use, and they are
this component's:
| Call | What it does |
|---|---|
beginSetup() | Title → the setup card |
phase() | Where the game is, before HL.state() exists |
setupInfo() | { count, names } of the pending game |
setPlayerCount(n) / setPlayerName(i, name) | Edit that pending game |
focusOption(delta) | Step the focus of the open choice, or the player count |
Two extra bus events go with them: setupChanged { count, names } and
choiceFocus { index, choice }.
The deck
game.deck.deck is asked for first and re-resolved on every new game, so the
deck slice's cards, careers and homes land as soon as they exist. Without it -
or if a call into it fails - game.rules.FallbackDeck deals instead, so a turn
always has a card. Every deck call is guarded; a broken deck degrades to the
fallback rather than stopping the game.
Fields the player record grows
HL.newPlayer declares the shape; this component adds degreeCareer (true once
the Kumpula graduate has taken the job the degree opened), so the upgrade is
offered once.
Listeners
HL.clearListeners() is deliberately never called. Every other slice subscribes
in its awake and would not subscribe again; clearing on a restart would leave
the board, the pieces, the screens and the sound deaf for the rest of the
session. A restart re-deals the state instead.
Scoped to this part · feeds back into the world's score.