World / Game Flow

How a shard campaign run moves from tavern entry to exploration, chat, combat, and back again.

This page documents the live runtime loop: a shard campaign launches through the tavern, the hexmap enters exploration, room chat stays active inside that loop, combat interrupts through a phase transition, and resolved encounters return the run to exploration with continuity state still intact.

Player-facing loop

Think of the run as one persistent shard cycle. Tavern entry sets the stage, exploration handles movement and discovery, chat covers in-room conversation, encounter mode takes over when danger commits, and the run returns to exploration when the fight resolves.

  • A shard campaign and selected character define the launch context.
  • Startup narration and room state are delivered before free exploration begins.
  • Chat is part of exploration, not a separate world map or menu mode.
  • Combat is a temporary phase shift, not a separate campaign instance.

System-facing loop

The runtime stays server-authoritative. Hexmap bootstraps the launch payload, GameCoordinator loads the current state and unseen events, phase handlers route intents, and the server returns canonical game state, available actions, events, and narration after each meaningful step.

  • HexMapController hydrates launch context and dungeon payload.
  • GameCoordinatorService ensures game_state, campaign_clock, and initial startup events exist.
  • PhaseManager merges server state so exploration and encounter data stay in sync.
  • Narration, chat, world mutations, and combat state all flow back through the same runtime shell.

Primary campaign loop

End-to-end run lifecycle

This is the top-level player journey for an active campaign run.

flowchart TD A[Campaign selected] --> B[Tavern entrance] B --> C[Choose active character] C --> D[Launch hexmap runtime] D --> E[Load canonical game state] E --> F[Startup room_entered event and narration] F --> G[Exploration phase] G --> H[Movement, search, rest, inspect] G --> I[Room chat with NPCs or GM] H --> J{Threat committed or hostile action?} I --> G J -- No --> G J -- Yes --> K[Transition to encounter] K --> L[Combat loop] L --> M{Encounter resolved?} M -- No --> L M -- Yes --> N[Return to exploration] N --> O{Continue run or leave session?} O -- Continue --> G O -- Leave --> P[Persist campaign state for next session]

Key points

  • The tavern is the first in-world location for a campaign run.
  • Exploration is the default phase after startup state has been applied.
  • Combat returns to the same persistent campaign state instead of forking a new run.

Launch and tavern startup

How the run boots into the first room

The launch path starts before the player can move: route selection, state hydration, startup narration, and the first encounter-ready room view.

flowchart LR A[/campaigns/{campaign_id}/tavernentrance/] --> B[Select character] B --> C[/hexmap with campaign and character context/] C --> D[HexMapController hydrates launch context] D --> E[Load dungeon payload and room entities] E --> F[GameCoordinatorService getFullState] F --> G[Ensure game_state and campaign_clock] G --> H[Bootstrap startup room_entered event if missing] H --> I[Return initial events, round, turn, actions, and phase] I --> J[GameCoordinator applies initial state] J --> K[Narration overlay and MP3 playback] K --> L[Encounter begins in the tavern]

Key points

  • Startup narration is delivered as a real room_entered event.
  • Campaign clock and current phase are part of the canonical state payload.
  • The client processes initial events before normal polling continues.

Encounter room loop

Movement, investigation, turn order, and room-state updates

Encounter is the default runtime loop on the hexmap. Room actions, movement, and conversation stay in this one framework.

flowchart TD A[Encounter phase active] --> B[Current actor chooses an intent] B --> C{Intent type} C -->|Transition| D[Server validates connected room and moves party] C -->|Search| E[Run encounter search] C -->|End / choose not to act| F[Log explicit turn-ending decision] C -->|Talk| G[Open room chat or direct chat] D --> H[Server updates game_state, round/turn, and event log] E --> H F --> H G --> I[Chat reply and transcript update] H --> J{Next actor?} J --> K[Emit round_start / turn_start as needed] I --> M[Encounter remains active] K --> M M --> A

Key points

  • Movement, search, talk, and explicit end-turn/no-action choices stay in encounter.
  • Room narration is first-visit gated and emitted through the event pipeline.
  • Chat can update world context without forcing a phase change.

Chat loop

Conversation inside the current room

Room chat runs inside the live hexmap shell so players can converse without leaving the run. The GM path can be deterministic, cached, or algorithm-backed; NPC room reactions and private channels each have their own generation operations.

flowchart TD A[Player sends room message] --> B[RoomChatService persists player message] B --> C{Channel type} C -->|Room| D[Resolve room context, intent, cache, deterministic shortcuts] C -->|Private whisper or ability channel| E[Generation call: channel_npc_reply] D --> F{Deterministic or cache hit?} F -- Yes --> G[Return GM reply without generation call] F -- No --> H[Generation call: room_chat_gm_reply] H --> I{Mechanical actions invalid?} I -- Yes --> J[Generation call: room_chat_gm_retry] I -- No --> K[Accept parsed GM reply] J --> K G --> L{Room NPC interjections enabled?} K --> L E --> M[Return private NPC reply] L -- No --> N[Send final chat payload to UI] L -- Yes --> O[Per candidate NPC: generation call npc_interjection_eval_single] O --> P{NPC should speak?} P -- No --> Q[Log NPC choose_not_to_act] P -- Yes --> R[Generation call: npc_room_dialogue] Q --> N R --> N M --> N N --> S[UI updates transcript inside encounter]

Key points

  • Room channel GM narration uses operation `room_chat_gm_reply`, with optional `room_chat_gm_retry` if authoritative action validation fails.
  • Private channels bypass the GM layer and go straight to `channel_npc_reply` for in-character NPC speech.
  • Room interjections are two-stage: `npc_interjection_eval_single` decides whether an NPC speaks, then `npc_room_dialogue` generates the actual line for NPCs that passed.
  • Deterministic shortcuts and GM response cache hits can skip some or all generation calls for low-variance turns.

Chat workflow detail

Every generation call in the chat pipeline

These are the concrete generation operations used by RoomChatService. They do not all fire on every turn; the pipeline branches based on channel type, deterministic shortcuts, response cache hits, and whether NPC interjections are even eligible.

Order Operation When it runs Purpose
1 room_chat_gm_reply Room channel only, after deterministic handling and cache lookup both miss. Primary GM narration/action generation for the current player turn.
2 room_chat_gm_retry Only after the primary GM reply proposed mechanical actions that failed authoritative validation. Regenerates the GM reply using a reality snapshot and validation errors.
3 npc_interjection_eval_single Room channel only, once per candidate NPC after the GM reply, excluding directly addressed NPCs that are already forced into consideration. Binary SPEAK/PASS gate to decide whether a specific NPC should take a turn this round.
4 npc_room_dialogue Only for NPCs that passed the interjection gate, unless a deterministic NPC response already handled them. Produces the actual in-room spoken line for that NPC.
A channel_npc_reply Private whisper/ability channels instead of the room GM path. Generates the direct in-character NPC reply for that private channel conversation.

Branching rules

  • If the turn is handled by deterministic room logic, the chat response can complete with zero generation calls.
  • If a low-variance GM narration turn hits the response cache, the GM reply also completes with zero GM generation calls.
  • Private channels use channel_npc_reply instead of room_chat_gm_reply.
  • Each candidate interjecting NPC is evaluated separately, so crowded rooms can trigger multiple npc_interjection_eval_single calls and multiple npc_room_dialogue calls in one player turn.

Combat loop

Encounter phase from initiation through resolution

Combat takes over when the run commits to a hostile encounter, then hands control back after the encounter ends.

flowchart TD A[Encounter phase starts] --> B[Create or sync combat encounter] B --> C[Roll initiative and build turn order] C --> D[Active combatant turn] D --> E{Whose turn?} E -->|Player| F[Choose strike, stride, spell, skill, interact, end turn] E -->|NPC| G[Auto-play algorithm or fallback turn] F --> H[Combat API validates and resolves action] G --> H H --> I[Update HP, conditions, positions, logs, and world delta] I --> J{Encounter over?} J -- No --> K[Advance turn and round] K --> D J -- Yes --> L[End encounter and emit narration] L --> M[Transition back to exploration]

Key points

  • Encounter state stays server-authoritative through combat APIs and services.
  • NPC turns can auto-play through algorithmic or fallback logic.
  • Resolved encounters transition back to exploration instead of trapping the run in combat mode.

Authority and transition flow

How client actions become canonical state

The client proposes intent; the server returns the state that actually counts.

flowchart LR A[Player click or action] --> B[GameCoordinatorApi] B --> C[GameCoordinatorController] C --> D[Phase-specific handler] D --> E[Update game_state, campaign_clock, events, and world state] E --> F[Return canonical state and available actions] F --> G[PhaseManager merges server state] G --> H[Hexmap UI, action rail, chat, and narration refresh]

Key points

  • Phase handlers own the rules for exploration, encounter, and downtime transitions.
  • The action rail, narration overlay, and current phase all refresh from returned state.
  • This is why campaign time, room narration, and combat phase changes must stay aligned with server responses.