4.7 KiB
4.7 KiB
| id | title | priority | scope | owner | status | updated_at | design | evidence | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| p3-15 | Local hotseat multiplayer — multiple humans alternating on one device | p3 | game1 | shipwright | done | 2026-06-19 | .project/designs/p3-15-hotseat-multiplayer-design.md |
|
Context
Owner scope override (2026-06-19): Game 1 was documented single-human vs AI; the
owner promoted local hotseat (2+ humans alternating on one device) into scope.
The per-player view substrate already exists (fog keyed on player_index,
renderers take a local-player, input routes through get_current_player(),
is_human is serialized). The gap is: setup can't mark >1 slot human, the view is
locked to slot 0, and there's no pass-the-device hand-off.
Full design: .project/designs/p3-15-hotseat-multiplayer-design.md.
Acceptance
- ✓ Setup lets a slot be Human ("" controller sentinel); a 2-human duel is constructible;
create_playerhonors it. —game_setup.gd"Human" picker option (HUMAN_CONTROLLER_ID);loading_screen.gd:114now derivesis_humanfrom the controller id (was hardcodedi==0). - ✓
world_map._set_view_player(idx)re-points fog/units/cities/overlay + recomputes displayed fog; called on each human turn start. —world_map.gd_set_view_player; smoke log alternatesview → player 0/1. - ✓ Pass-the-device hand-off overlay shown on every human turn in hotseat (board hidden until Ready); input gated until Ready. —
hotseat_handoff.gd;_awaiting_handoffgates_handle_hex_click+_on_end_turn_pressed. - ✓ Player A never sees player B's view. — Screenshot proof (
hotseat_view_proof.tscn, 2026-06-19): the SAME game rendered from each human's view shows two different fogged worlds (Alice = arid region around her start; Bjorn = forested region around his) — switching the view re-fogs the whole map to the other player's knowledge. Plus the hand-off occlusion proof: magenta "secret" board fully hidden by the opaque panel (hotseat_handoff_proof.tscn). - ✓ Save/resume of a hotseat roster;
is_humanround-trips. —mid_run.saveholds"is_human":true×2; resume keeps the view alternating 0/1 (both humans survive). - ✓ Single-human regression: with 1 human, no hand-off, behaviour identical. — Default auto_play run: 0 hotseat log lines, same progression (2 converged + 2 founded), exit 0.
- ✓ Runtime-proven on plum. — 2-human auto_play smoke (
AUTO_PLAY_HUMANS=2, exit 0, no errors) + hand-off visual proof render. - ✓ Player names: each slot has a name field in setup (humans editable);
player_namesflows payload →loading_screen→player_name. AI slots are named after their clan (PersonalityAssigner, deduped). Proof:AUTO_PLAY_PLAYER_NAMES="Alice,Bob"→ view showsplayer 0 (Alice)/player 1 (Bob); 1-human+AI run named AI "Tinkersmith"/"Deepforge"; setup-screen render shows the name fields + per-slot Human/AI pickers.
Per-player opening + randomized order (2026-06-19)
- ✓ Randomized turn order —
GameState.randomize_turn_order()(seeded Fisher-Yates, deterministic per map seed) setsturn_order;next_player()rotates through it for the whole game (sequential fallback when unset). Called fromloading_screenafter players are created. Proof: 3-player game ordered[0, 2, 1]. - ✓ Per-player opening — the opening is no longer a shared cinematic.
turn_managerrotates players during the prologue and advances the start-script to the next display-turn only when the round wraps. Result: turn −1 for each player, then a round of 0, then founding → normal turn 1. AI players auto-advance their opening turns (no dispatch — units/cities don't exist yet,start_turngates on_is_in_prologue()). Each human sees their own wanderers (view-switch + hotseat hand-off now fire during the opening too), camera framed on their convergence centroid. Proof: 2-/3-player traces + hotseat run (view flips Alice/Bjorn from turn −1). - ✓ GUT test —
tests/unit/test_turn_order.gd(5/5): permutation completeness, per-seed determinism, sequential fallback,is_last_in_roundposition tracking. - AI-turn view stays on the last human (brief, overlaid by
ai_turn_overlay). - Test harness hooks:
AUTO_PLAY_HUMANS=N,AUTO_PLAY_PLAYER_NAMES, hand-off auto-passes underAUTO_PLAY,_set_view_player+ opening rounds log underAUTO_PLAY.