magicciv/.project/objectives/p1-03-tutorial-overlay.md
Natalie 763366d01c feat(@projects/@magic-civilization): mark tutorial and hotkey sheets as complete
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-04-17 11:11:47 -07:00

5.8 KiB

id title priority status scope owner updated_at evidence
p1-03 First-run tutorial / onboarding overlay p1 done game1 shipwright 2026-04-17
src/game/engine/scenes/hud/tutorial_overlay.tscn
src/game/engine/scenes/hud/tutorial_overlay.gd
src/game/engine/scenes/world_map/world_map.gd
src/game/engine/scenes/world_map/camera.gd
src/game/engine/scenes/city/city_screen.gd
src/game/engine/scenes/menus/options.tscn
src/game/engine/scenes/menus/options.gd
src/game/engine/src/autoloads/event_bus.gd
src/game/engine/tests/unit/test_tutorial_overlay.gd
src/game/engine/tests/unit/test_tutorial_event_chain.gd
src/game/engine/tests/unit/test_tutorial_hotkey_wiring.gd
src/game/engine/src/autoloads/settings_manager.gd
public/games/age-of-dwarves/vocabulary.json

Summary

First-run tutorial overlay walks new players through the seven core 4X actions with a live-event chain. Each step subscribes to the matching EventBus signal on enter and auto-advances when the player performs the action — no click-through required, but Skip, Back, and Next remain available at every step. SettingsManager("gameplay", "tutorial_completed") persists completion so the overlay never reshows unless the player hits Replay on next start in the options screen.

Step descriptors live in TutorialOverlay._STEPS; adding a step means one entry plus a matching handler method — tests, proof scenes, and counter rendering all read total_steps() from the array length.

Acceptance

  • ✓ Tutorial scene + controller present at src/game/engine/scenes/hud/tutorial_overlay.{tscn,gd} (class_name TutorialOverlay, layer=100).
  • ✓ Trigger on first game boot. world_map.gd::_mount_hud_overlays() (invoked from _start_game() in the non-arena branch) calls TutorialOverlayScript.should_show_on_first_run() and instantiates the scene when it returns true. After completion/skip, tutorial_completed=true prevents reshow. Covered by test_tutorial_hotkey_wiring.gd::test_tutorial_reset_flag_flips_should_show.
  • ✓ 7-step chain per spec (Move camera / Select founder / Found first city / Queue a unit / End turn / Open tech tree / Research first tech). Steps in tutorial_overlay.gd::_STEPS listen for camera_panned, unit_selected (filtered to human's founder/settler), city_founded (human), production_queued (human), turn_ended (human), tech_tree_opened (human), tech_research_started (human). Three new EventBus signals added: camera_panned, production_queued, tech_tree_opened. Emission sites:
    • camera.gd::_maybe_emit_pan() — debounced at 8px from last emit, called from keyboard + edge-pan + drag paths.
    • city_screen.gd::_on_buildable_item_activated() — fires after _city.add_to_queue().
    • world_map.gd::_toggle_tech_tree() — fires on open path only (not close). Tutorial auto-advances on signal; predicate filter on each handler ensures only human-sourced events count (AI actions never advance). Covered by test_tutorial_event_chain.gd10/10 passing on apricot (Godot 4.6.2, GUT 9.6.0): one test per step asserting the correct signal advances the correct step, plus negative tests asserting AI-sourced signals do NOT advance (test_step_3_advances_only_on_human_city_founded, test_step_4/5/6_*), plus test_all_seven_signals_registered_on_event_bus walking EventBus.get_signal_list().
  • ✓ Dismissible per step — Skip Tutorial button present on every step; Esc also skips via _unhandled_key_input. Enter/Space advances manually. tutorial_skipped and tutorial_completed EventBus signals emit on teardown. Covered by test_tutorial_overlay.gd::test_skip_* (4 tests) and test_step_advanced_signal_fires_with_satisfied_step_index.
  • ✓ All-off toggle in options.tscnResetTutorialRow in the Gameplay section with ResetTutorialButton ("Replay on next start"). Pressing it calls SettingsManager.set_setting("gameplay", "tutorial_completed", false), persisting to user://settings.cfg; button label flips to options_tutorial_reset_done ("Tutorial will replay") for visual confirmation. Covered by test_tutorial_hotkey_wiring.gd::test_options_reset_tutorial_vocab_exists
    • test_tutorial_reset_flag_flips_should_show.
  • ✓ Persistence round-trip — test_persistence_round_trip_prevents_reshow (in test_tutorial_overlay.gd) skips, reloads settings.cfg from disk, confirms should_show_on_first_run() == false.
  • ✓ All strings vocab-resolved — titles, bodies, action-required hints, done marker, Skip/Back/Next labels all flow through ThemeVocabulary.lookup(). New vocab keys added: tutorial_step_6_title/body/action, tutorial_step_7_title/body/action, tutorial_action_required, tutorial_action_done, tutorial_step_{1..5}_action.

Tests

  • test_tutorial_overlay.gd — 8/8 passing (step advance, step back, skip, signal emission, completion frees, persistence, settings round-trip).
  • test_tutorial_event_chain.gd — 10/10 passing (7-step event chain, structural 7-step assertion, step_advanced signal, all-7-signals registered on EventBus).
  • test_tutorial_hotkey_wiring.gd — 7/7 passing (reset flag flip, world_map mount-path preload resolution, options vocab keys).

25/25 tutorial tests green on apricot.

Integration

  • world_map.gd mounts the overlay on first game boot when should_show_on_first_run() is true.
  • camera.gd, city_screen.gd, and world_map.gd emit the three new EventBus signals (camera_panned, production_queued, tech_tree_opened) so any future consumer (telemetry, achievement tracker) can subscribe alongside the tutorial.
  • options.tscn + options.gd expose the reset control for players who want to replay the tutorial after finishing it.