Skip to content

fix: drain quest events between commands in _execute_cheat - #86

Merged
rmstdope merged 7 commits into
mainfrom
fix-cheat-quest-completion
Apr 21, 2026
Merged

rmstdope merged 7 commits into
mainfrom
fix-cheat-quest-completion

Conversation

@rmstdope

@rmstdope rmstdope commented Apr 21, 2026 •

Copy link
Copy Markdown
Owner

Fixes #85.

Problem

CommandParser._execute_cheat() ran all cheat commands in one pass without ever calling next_activated_quest() / next_updated_quest() / next_completed_quest() between commands.

The Act 1 cheat sequence takes the Rare Flower and later gives it to Mira, all within the same batch. Because no quest processing happened mid-sequence, OhDeerOhDeerQuest stayed in non_activated_quests. When the web frontend's pollQuestEvents() finally ran after the cheat, it activated the quest but check_completion returned False — the flower was no longer in the inventory or any room.

Changes

Python engine

  • Quest-drain fix (CommandParser._execute_cheat): drain next_activated_quest / next_updated_quest / next_completed_quest after each command, matching the behaviour of dev_execute_commands.
  • Faded Photograph in cheat sequence: added search, take faded photograph, examine faded photograph, give faded photograph to grandmother so the Faded Photograph side quest is also completed by cheat act 1.
  • Remove Lost Letter quest: LostLetterQuest (and its flags in Act1StoryFlags.py) were a dead stub whose trigger/completion flags were never set by any game code. Removed to avoid confusion.

Web frontend

  • Act transition modals (useGameStore.ts): when a command finishes an act (acceptInput becomes false), triggerActTransitionModals() is now called automatically, driving ACT_TRANSITION → ACT_INTRO → ACT_RUNNING and showing the transition text and new act intro as popup modals — the same UX as game startup. Previously the game silently blocked input with no visual feedback (not fixable on mobile where the input field is read-only).
  • Added isActRunning(): boolean and advanceToRunning(): string[] to the GameBridge interface.

E2E / mobile

  • Fixed 3 pre-existing e2e test failures (introduced by the mobile-drawer PR feat: move action buttons to mobile drawer to fix toolbar overflow #83): strict-mode locator for SidePanel, scoped TopBar button assertions, and emitAndClose now uses try/finally so the drawer always closes even if a handler throws.
  • Added data-testid to SidePanel and TopBar to support stable selectors.
  • Added test-results/ and playwright-report/ to the root .gitignore.

Tests

  • New integration test: test_cheat_act_1_completes_all_side_quests_and_leaves_main_active — verifies every side quest defined in act.quests is completed and only the main quest remains active after cheat act 1.
  • DummyGameState stub added to test_CommandParser.py so unit tests compile after _execute_cheat started accessing self.game.state.
  • 5 new unit tests for act-transition modal flow in useGameStore.test.ts.
  • 472 Python + 259 web unit + 35 e2e tests pass.

Formatting constraints verified

The cheat sequence completes the entire golden path in one call, which
means items like Rare Flower are taken AND given away before the frontend
ever calls pollQuestEvents(). Because _execute_cheat never called
next_activated_quest / next_completed_quest between commands, the
'Oh deer, oh deer' quest was never activated during the cheat, and by
the time the frontend drained quest events afterward, check_completion
returned False (the flower was already with Mira).

Fix: add the same quest-draining loop that dev_execute_commands already
uses, inside _execute_cheat — one pass after each command.

Also add DummyGameState stub to test_CommandParser.py so the three
existing cheat unit tests still compile and pass.

Test: test_cheat_act_1_completes_oh_deer_oh_deer_quest (new, in
test_Integration.py) fails before the fix and passes after.
… quest

- Add 'search', 'take faded photograph', 'examine faded photograph' and
  'give faded photograph to grandmother' to the Act 1 cheat command list
  so the Faded Photograph quest is triggered and completed by cheat act 1
- Remove the unimplemented LostLetter quest (class, story flags, Act1 registration)
  whose trigger/completion flags were never set by any game action
- Update the integration test to expect The Faded Photograph in completed
  side quests and drop the LostLetter import / exclusion note
…tion

When a command completes an act, automatically drive the transition
from ACT_TRANSITION -> ACT_INTRO -> ACT_RUNNING and show the transition
message and new act intro as popup modals (same UX as game startup).

Previously the game would silently block input with no visual feedback,
requiring the user to press Enter (not possible on mobile with a readonly
input field) twice to advance - causing the game to appear stuck.

The fix:
- Add triggerActTransitionModals() that calls b.advanceToRunning() to
  collect both the 'Act Complete!' text and new act intro text, then
  queues them as modals ('🏆 Act Complete!' + '📖 Act Intro')
- Sets pendingLookOnDismiss so look() + quest activation fires after
  the intro modal is dismissed (same as game startup)
- Hook is called from submitCommand() when acceptInput becomes false
  and no modal is showing (direct transition, no quest events)
- Hook is also called from dismissModal() when the last quest-completion
  modal is dismissed but input is still blocked (transition after quests)
- Add isActRunning(): boolean and advanceToRunning(): string[] to the
  GameBridge interface (already in useBridge.ts and mock)
- 5 new unit tests covering all transition scenarios

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a cheat-mode quest progression bug by ensuring quest activation/update/completion events are drained between each cheat command, so quest state stays consistent with mid-sequence inventory/story changes (Fixes #85).

Changes:

  • Drain next_activated_quest() / next_updated_quest() / next_completed_quest() between commands in CommandParser._execute_cheat().
  • Add web-store handling + tests for act-transition modal sequencing via new bridge methods (isActRunning, advanceToRunning).
  • Remove the Act 1 “Lost Letter” quest and its story flags/references.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
web/src/stores/useGameStore.ts Adds act-transition detection and modal queuing driven by bridge state.
web/src/stores/useGameStore.test.ts Adds unit tests for act transition modal flow and look-on-dismiss behavior.
src/retroquest/engine/CommandParser.py Drains quest events after each cheat command; adjusts Act 1 cheat command sequence.
tests/retroquest/engine/test_CommandParser.py Extends test stub game state so cheat parsing continues to work in unit tests.
tests/retroquest/act1/test_Integration.py Adds integration coverage asserting cheat act 1 completes side quests as expected.
src/retroquest/act1/quests/LostLetter.py Removes the Lost Letter quest implementation.
src/retroquest/act1/Act1StoryFlags.py Removes Lost Letter-related flags.
src/retroquest/act1/Act1.py Removes LostLetterQuest from Act 1 quest registration.

Comment thread src/retroquest/act1/Act1.py
Comment thread tests/retroquest/act1/test_Integration.py Outdated
Comment thread web/src/stores/useGameStore.ts
Comment thread src/retroquest/act1/Act1StoryFlags.py
- Add data-testid='side-panel' to SidePanel.vue so the sidebar
  visibility test has a specific locator (the generic .max-md:hidden
  class now matches 6 elements, causing a strict-mode violation)
- Add data-testid='top-bar' to TopBar.vue so toolbar-button tests
  can be scoped to the TopBar; the Quick Action Bar in CommandInput
  also has an always-visible Help button with the same text
- Use try/finally in MobileDrawer.emitAndClose so the drawer always
  closes even if the action handler (e.g. store.saveGame) throws
  (bridge not initialized in e2e mock context)
- Update e2e/game.spec.ts tests 1-3 to use the new data-testid
  selectors and scoped getByRole queries

All 35 e2e + 259 unit + 472 Python tests pass.
Formatting constraints verified.
- Act1StoryFlags.py: update module docstring to remove reference to
  'finding the lost letter' (those flags were removed in this PR);
  replace with 'faded photograph' which is the actual discovery flag
- test_Integration.py: derive expected_side_quests from act.quests
  filtered by is_main() instead of a hard-coded list, so the test
  stays in sync automatically when quests are added or renamed;
  capture before cheat execution since act.quests is drained during cheat
@rmstdope
rmstdope merged commit e264e25 into main Apr 21, 2026
7 checks passed
@rmstdope
rmstdope deleted the fix-cheat-quest-completion branch April 21, 2026 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: cheat act 1 does not complete Oh deer, oh deer quest

2 participants