Skip to content

Merge dev → main (automated)#596

Closed
SorraTheOrc wants to merge 109 commits into
mainfrom
release/dev-to-main-20260617142841
Closed

Merge dev → main (automated)#596
SorraTheOrc wants to merge 109 commits into
mainfrom
release/dev-to-main-20260617142841

Conversation

@SorraTheOrc

Copy link
Copy Markdown
Member

Automated release created by ship skill.

Version: v0.1.1

Map added 30 commits June 10, 2026 02:33
Replace manual hand and pile rendering with shared HandView and PileView
components. The Mind now uses:

- HandView for human and AI hand layout (card positioning, selection,
  click handling).
- PileView for the play pile (top card sprite, count overlay).

Mind-specific adaptations:
- CardTextureResolver type made generic (any parameter) to support
  MindCard which has numeric  instead of /.
- Lazy texture loading via applyEnsuredTexture for human hand cards
  (placeholder back texture, updated when real textures are ready).
- Pile value text overlay (numeric display) remains Mind-specific.
- HandView.setCards accepts Card[]; MindCard[] cast via 'as any' for
  texture resolver compatibility.

Tests updated:
- MindRenderer tests now call createHands() before render methods.
- HandView/PileView mocks return proper mock sprites for inspection.

Files changed:
- src/ui/HandView.ts: Generic CardTextureResolver, Card[] parameter
- example-games/the-mind/scenes/MindRenderer.ts: HandView + PileView usage
- example-games/the-mind/scenes/TheMindScene.ts: call createHands()
- tests/the-mind/mind-renderer.test.ts: Updated mocks and setup
…eractivity control

Fix critical bug where Golf's discard pile was wrapped in ArrayPileAdapter
(which expects a plain array) but was actually a Pile<Card> object. This
caused peek() to return undefined and getCardTexture to crash on undefined.faceUp.

Changes:
- GolfRenderer: Pass discard Pile directly to setPile() instead of wrapping
- GolfRenderer: Use CardPile<Card> type for discard parameter
- PileView: Add setVisible() handling for empty/non-empty piles
- PileView: Add setInteractive(flag) method for replay mode support
- GolfRenderer: Disable pile view interactivity in replay mode
- GolfScene.browser.test.ts: Fix Stock/Discard assertions to use startsWith
- pileView.test.ts: Add setVisible mock
- GymHandPile.test.ts: Add setVisible mock
…Migration smoke test

Root cause: Test assertions used incorrect region coordinates and label
text expectations that didn't match the actual rendered output after
HandView/PileView migration.

Fixes:
1. 'pile renders non-trivial content' - Updated region coordinates to
   match actual PileView position (center of screen) and increased
   wait frames for rendering.
2. 'status text renders non-trivial content' - Updated region to
   top-right corner where status labels are rendered (level/lives).
3. 'scene contains expected display objects' - Replaced assertions for
   'PILE', 'Your Hand', 'AI Hand' labels (which don't exist after
   migration) with assertions for actual text objects present:
   'The Mind' header, 'Level N / 8', 'Lives: ❤', and card-back images.
   Also increased wait frames from 8 to 16 for reliable rendering.
- Keep human-played card sprites visible at pile position after animation
- Keep AI-played card sprites visible at pile position after animation
- Set correct face-up texture and depth for played cards
- Cards now remain visible showing the card that was played

Fixes: Cards disappearing at end of animation
…Market Rows step

Replaced DOM button elements with Phaser Text objects using the input
system (setInteractive + on('pointerdown')). The original DOM buttons
lost their onclick handlers after the measurement detach/reattach cycle
required for tooltip positioning in Phaser 4 RC.

Changes:
- Replaced DOM button creation with Phaser Text objects for Exit Tutorial
  and Continue/Start Full Game buttons
- Used setInteractive({ useHandCursor: true }) for proper cursor feedback
- Added pointerover/pointerout hover effects for visual feedback
- Maintained the same visual appearance and styling as before
- Removed the DOM measurement cycle that caused event handler loss
…red tutorial steps

The Continue button was showing for all steps but only worked for steps
with requiredAction 'confirm' or 'acknowledge'. For steps requiring
actual game actions (select-business, place-business, etc.), clicking
Continue did nothing because confirmTutorialStep() returns early.

Fix: Only show the Continue button for steps where it actually works.
Action-required steps (T3-T9) now only show 'Exit Tutorial' button,
while confirm/acknowledge steps (T1-T2, T10) show both buttons.
…on-required tutorial steps"

This reverts commit 324b6fb.
…ibility

1. Updated T3 (Market Rows) body text to give clear instructions:
   - Changed from 'Businesses go on your street...' to 'Click a business
     card (top row) to buy it. Businesses go on your street to earn income.
     Investments (bottom row) give one-time effects.'

2. Only show Continue button for steps where it actually works:
   - Steps with requiredAction 'confirm' or 'acknowledge' show Continue
   - Steps requiring actual game actions (select-business, etc.) only show
     Exit Tutorial button
   - Last step (T10) shows Start Full Game button

This ensures all visible buttons are functional and the player knows what
action to take during action-required tutorial steps.
…business

The tutorial wasn't advancing from T3 (select-business) to T4 (place-business)
because onTutorialActionComplete('select-business') was never called after the
player selected a business card. This caused onSlotClick to reject the placement
because isTutorialActionAllowed('place-business') returned false (tutorial still
at T3).

Fix: Call onTutorialActionComplete('select-business') after the player
successfully selects a business card and enters placement mode.
Reordered tutorial steps so that T5 is now 'Incident Queue' (was T6)
and T6 is now 'End Turn' (was T5). This makes more sense narratively
because players should learn about incidents before ending their turn.

Updated tests to reflect the new step order.
The Incident Queue step (T5) has requiredAction 'acknowledge-queue', but
the Continue button was only shown for 'confirm' or 'acknowledge'. Updated
the condition to include 'acknowledge-queue' so players can click Continue
after acknowledging the incident queue.
…ctions

1. Updated T7 body text to specifically mention 'Grand Opening Sale' event
   card so the player knows which card to buy.

2. Added onTutorialActionComplete('buy-event') call in the afterTransfer
   callback of onEventCardClick. Previously the tutorial never advanced
   after buying an event card because this call was missing.

Now the tutorial correctly advances from T7 (Held Event Card) to T8
(Upgrade Concept) after the player buys an event card.
… tutorial

Update TutorialOverlayManager.browser.test.ts and TutorialOverlayHighlights.browser.test.ts to cover all 13 unified tutorial steps (T1-T13).

Changes:
- MainStreetTutorialHints.ts: Fix step badge to use UNIFIED_TUTORIAL_STEPS/UNIFIED_TUTORIAL_STEP_COUNT
  and change isLast check from T10 to T13 for the 13-step unified system
- TutorialOverlayManager.browser.test.ts: Use step IDs instead of numeric indices
  for showStepAndGetHighlight; add tests for T8, T11, T12, T13 steps;
  cover all 9 highlight zones including completionModal and centerModal
- TutorialOverlayHighlights.browser.test.ts: Fix step index mapping for
  end-turn (T6, index 5) and help-button (T10, index 9) screenshots;
  add investments row T12 and completion modal T13 screenshot tests;
  add coverage test for all 13 unified step highlight zones

Related-Work: CG-0MQ8MWTK7003FF9S
…ial system

- Export resolveZoneToAnchor for testability
- Add NULL_ZONE_NAMES constant (centerModal, completionModal)
- Update null zone tests to use simulated resolveZoneToAnchor logic
  that exercises SLL composition directly
- Add per-zone tests verifying known zones return valid rects
- Add bounds-matching test comparing simulate to computeExpectedZoneBounds
- Add unknown zone test verifying composed layout returns undefined

Related-Work: CG-0MQ8MX4XK002PN6Q
…ied set

Remove legacy TUTORIAL_STEPS array and TutorialStep interface from
MainStreetTutorialHints.ts. Remove TUTORIAL_STEP_DEFS and TUTORIAL_STEP_COUNT
from TutorialFlow.ts.

Migrate the reference-mode showStep() method to use UNIFIED_TUTORIAL_STEPS
with SLL-based highlight zone resolution via zoneToAnchor(), replacing the
old anchor-function-based rendering.

Remove the corresponding legacy test block from tutorial-flow.test.ts.

Related-Work: CG-0MQ8MXYN8008GC22
…method

- Replace showStep(stepIndex, isActionComplete?) with single-param showStep(stepIndex)
- Add setActionCompletePredicate() method for action gate callback registration
- Remove showActionGatedStep() method (fully replaced by unified showStep)
- Update MainStreetLifecycleManager.showTutorialStepOverlay() to use
  setActionCompletePredicate() + showStep() pattern
- Update test files to use showStep() instead of showActionGatedStep()
- Remove unused imports (getCurrentStep, UNIFIED_TUTORIAL_STEPS,
  TutorialControllerState) from TutorialHints and LifecycleManager

Related-Work: CG-0MQ8MZH310009T3Q
…e lifecycle manager

- Remove tce:play-tutorial and tce:replay-tutorial event listeners from
  MainStreetLifecycleManager (reference mode is gone)
- Remove Tutorial Replay button and confirmation modal from SettingsPanel
- Update Tools help section to remove tutorial replay reference
- Remove replay-tutorial test from tutorial-offer-modal.test.ts
- TutorialOfferModal still offers guided mode to first-time players
- Tutorial completion persists via the unified system

Related-Work: CG-0MQ8MZZPY002LG6V
- Update TutorialFlow.ts and MainStreetTutorialHints.ts module comments to reflect the unified tutorial system
- Update MainStreetLifecycleManager.ts comment to reference T1-T13 instead of T1-T10
- Update docs/DEVELOPER.md tutorial section to reference T1-T13 and TutorialActionType
- Update docs/main-street/playtest-scenarios.md to reference UNIFIED_TUTORIAL_STEPS and UnifiedTutorialStepDef instead of stale TUTORIAL_STEPS references to removed MainStreetTutorialOverlayManager.ts
- Remove stale 'non-interactive' description from MainStreetTutorialHints module comment

Related-Work: CG-0MQ8N0EY0006IYSD
- MainStreetLifecycleManager: Added forceShowOffer option when ?tutorial=1 URL param is present
- TutorialOfferModal: Removed stale 'Settings menu' reference from body text since replay tutorial was removed

This allows players to force the tutorial to show by visiting:
  http://localhost:3000/?tutorial=1
1. Fixed marketBusinessRow height in main-street-tutorial.layout.json
   - Reduced height from 0.302778 to 0.158333 to not overlap investments row

2. Fixed setActionCompletePredicate in MainStreetLifecycleManager
   - Now reads current controller state from scene instead of captured closure
   - Returns true when step has advanced (action is complete) vs false when still active
   - This enables the Continue button after place-business action completes

3. Removed stale 'Settings menu' reference from TutorialOfferModal
- Removed disabled state check on DOM Continue button - now re-evaluates predicate at click time
- Removed disabled state check on canvas fallback Continue button - same fix
- This allows the Continue button to work after place-business action completes
- Renamed step title from 'Market Rows' to 'Market Business Row'
- Added clarification that bottom row shows Investment cards separately
…ation

- Changed h from 0.158333 to 0.144444 (104px) to correctly highlight only business row
- Updated test to expect single-row height instead of combined two-row height
- When Continue is clicked on action step after action already completed,
  the method now shows the next step overlay instead of returning early
- This ensures the flow continues smoothly when user clicks Continue after
  performing the required action
- Removed 600ms delay in onTutorialActionComplete so the next step
  overlay shows immediately after the action completes
- This ensures smooth transition from select-business to place-business step
- When clicking Continue on an action step that has already completed,
  the method now properly calls completeCurrentStep to advance the tutorial
- This ensures the flow continues from select-business to place-business
- Added getActionCompletePredicate method to MainStreetTutorialHints
- Updated confirmTutorialStep to check predicate result before advancing
- This ensures the Continue button works correctly after action completes
Covers all 13 tutorial steps (T1-T13):
- Confirm steps: verify Next button advances correctly
- Action steps: perform required game actions, verify overlay transitions
- Screenshot at key transition points for debugging

Tests live at tests/e2e/main-street-tutorial-e2e.browser.test.ts
Run with: npm run test:browser -- tests/e2e/main-street-tutorial-e2e.browser.test.ts
Map added 28 commits June 15, 2026 23:34
… in E2E tutorial tests

Commit 512de51 renamed state.market.business to state.market.development
when implementing the Development market row, but the E2E test helpers
still referenced the old property name, causing all interactive tutorial
tests to silently no-op.

Changes:
- Rename s.state?.market?.business to s.state?.market?.development in
  clickRequiredBusinessCard, clickStreetSlot, and the seed verification test
- Update deterministic card assertion (index 1 is now Barbershop instead of
  Laundromat due to community-space cards in the development deck)

Tests: 12/12 browser tests pass, 3310/3310 unit tests pass, build succeeds.
…stle

- Add BeleagueredCastleSaveLoad.ts with:
  - State serialization/deserialization (serializeBCState / deserializeBCState)
  - bcStateSerializer compatible with SaveLoadStore
  - saveBCSnapshot / loadBCSnapshot checkpoint helpers
  - Constants for schema version, game type, and slot ID

- Modify BeleagueredCastleScene.ts:
  - Initialize SaveLoadStore and TranscriptStore in create()
  - Save checkpoint after deal completes (onDealComplete)
  - Auto-save transcript on game end (win, loss, auto-complete win)
  - Add saveCheckpoint() and autoSaveTranscript() helper methods

- Modify BeleagueredCastleTurnController.ts:
  - Add onSaveCheckpoint callback to TurnControllerCallbacks
  - Call onSaveCheckpoint after each player move and after auto-complete

- Add tests/beleaguered-castle/save-load-autosave.test.ts:
  - Save/load round-trip with state equality verification
  - Post-deal checkpoint restoration
  - Serialization round-trip verification
  - SaveLoadStore direct API usage test
  - Transcript autosave persistence (win and loss)
  - Full round-trip: checkpoint + transcript persisted and retrievable

All AC-1 through AC-7 satisfied.
…d Castle

- Add checkForSavedGameAndStart() in create() that loads checkpoint on boot
- Add showResumeOverlay() with 'Resume' and 'New Game' buttons
- Add restoreFromCheckpoint() to restore game state, skip deal animation
- Add clearCheckpointAndStartFresh() to overwrite checkpoint and restart
- Add startFreshGame() extracted from original create() logic
- Add 5 new tests covering checkpoint existence, state restoration,
  separate store instances, autosave compatibility, and checkpoint clearing

All 128 BC tests pass.
- Fix state object replacement bug: restoreFromCheckpoint() now mutates
  the existing game state's piles (clear + push) instead of replacing
  the state object. The renderer and turn controller hold references to
  the original object — replacing it left them pointing at stale state.

- Fix async deal-animation timing: startFreshGame() is now called
  synchronously in create() (preserving original timing for layout
  tests), and the async checkpoint check runs on the next frame via
  Phaser's time.delayedCall. This prevents the deal animation from
  being deferred to a Promise microtask.

- Fix 'New Game' on resume overlay: clearCheckpointAndStartFresh()
  now uses clearBCSnapshot() to DELETE the checkpoint before restarting,
  instead of saving a fresh state (which would re-trigger the resume
  overlay on restart).

- Add clearBCSnapshot() to BeleagueredCastleSaveLoad.ts — wraps
  SaveLoadStore.remove() for clean checkpoint deletion.
… fresh deal

- No deal animation starts until after the async checkpoint check resolves
- If checkpoint found: show resume overlay over empty board (no fake deal)
  so when user clicks Resume the board appears from saved state instantly
- If no checkpoint: start deal animation on the next frame via
  Phaser time.delayedCall(0, ...)
- If loadBCSnapshot errors: fall through to a fresh game so BC is
  still playable even if storage is unavailable

This eliminates the jarring UX of seeing a fresh deal start,
then getting interrupted by the resume overlay, then having the
state replaced.
…n failure

The discardSelected() method previously moved card data model updates
(card.faceUp = false; discardPile.push(card)) to the animation completion
callback. If the animation never fired its completion event (e.g., texture
missing, scene destroyed), the card became orphaned - removed from hand
but never added to discardPile.

Fix: Synchronously update the data model (faceUp, push to discardPile)
before starting the discard animation. The animation now only handles UI
cleanup (selection, highlights, HandView/PileView refresh). This ensures
the card is always in discardPile (or hand before splice) at all times.

Added 10 tests in tests/gym/GymHandPileDiscardConsistency.test.ts covering:
- Card immediately in discardPile after splice, before animation completes
- Card not orphaned when animation completion event never fires
- Card is in either hand or discardPile at all times
- Normal animated discard still works
- Reduced-motion discard works
- Invalid/out-of-range selection does nothing
- Sequential discards all land in discardPile
- Source-level verification of fix pattern
…-contained per slider (only active during drag)

Changes:
- src/ui/GymSceneUtils.ts: createSlider now self-manages pointermove/pointerup
  listeners, registering only on pointerdown and unregistering on pointerup/destroy
- example-games/gym/scenes/GymHandPileScene.ts: removed scene-level
  pointermove/pointerup forwarding; sliders handle their own lifecycle
- tests/gym/GymHandPileDiscardConsistency.test.ts: removed source-inspection
  test for old shutdown pattern (no longer needed)
- tests/gym/GymSceneUtils.smoke.test.ts: added 5 new tests covering
  self-contained listener registration, unregistration, backward-compatible
  external calls, destroy cleanup, and multi-slider isolation

Resolves acceptance criteria:
- Zero active pointermove handlers when no slider is dragged
- Each dragged slider gets its own handler (not forwarded to all three)
- All sliders continue to work identically
- Full test suite passes
…PileScene

Added a  method to GymHandPileScene that properly cleans up
all scene-created objects when the scene shuts down. Registered the
method as a  event listener in  to integrate with
Phaser 4's scene lifecycle.

Cleanup includes:
- Stopping and nullifying activeMoveTween
- Destroying highlightGraphics (if created) and clearing highlightLabels
- Destroying arcSlider, spacingSlider, and rotationSlider components
- Destroying HandView, deckView, and discardView UI components
- Destroying layoutLabel, dragLabel, and dragButton text objects
- Destroying logTexts and clearing internal state arrays
- Unregistering the shutdown listener to prevent double-calls

All cleanup is wrapped in try/catch guards and null-checks for safety.
The base class (GymSceneBase) already handles helpPanel/helpButton
cleanup via its own shutdown listener.

Added test file tests/gym/GymHandPileShutdown.test.ts with 12 tests
verifying method presence, event registration, and cleanup completeness.
…mHandPileScene

- Unified CardDiscardedPayload in GameEventEmitter.ts: added cardId?,
  made playerIndex optional (backward compatible)
- Added 'card:discarded' (colon) event to GameEventMap in GameEventEmitter.ts
- Removed duplicate CardDiscardedPayload from discardCard.ts, now
  imports from core-engine and re-exports
- Removed all (gameEvents as any) casts from GymHandPileScene.ts
  discardSelected() — .on(), .removeAllListeners(), and discardCard()
  gameEvents parameter now type-checked properly
- Fixed (slider.hitArea.input as any).enabled cast in setSliderVisible()
  — Phaser's InteractiveObject.enabled is properly typed
- Updated GymHandPileDiscardConsistency.test.ts to remove casts
- All 188 unit test files pass, TypeScript and Vite builds clean
… createSlider

- Create src/ui/Slider.ts with a Slider class (constructor, setValue, getValue, destroy, onValueChange)
- Self-contained pointermove/pointerup listeners (only active during drag)
- No handlePointerMove/handlePointerUp on the public API
- Remove createSlider, SliderOptions, SliderResult from src/ui/GymSceneUtils.ts
- Update src/ui/index.ts barrel to export Slider/SliderOptions from ./Slider
- Update GymHandPileScene to use new Slider(...) instead of createSlider(...)
- Migrate slider tests from tests/gym/GymSceneUtils.smoke.test.ts to tests/ui/Slider.test.ts
- Add 15 unit tests for the new Slider class covering construction, value management, self-contained listener lifecycle, and cleanup
- All 27 relevant tests pass (15 slider + 11 remaining smoke + 1 spacing check)
- npm test and npm run build both succeed
…GymHandPileScene

- Add src/ui/HighlightManager.ts — lightweight class managing named
  highlight zones with two styles (fill/border), individual lifetimes,
  and timer cleanup
- Add tests/ui/HighlightManager.test.ts — 19 unit tests covering zone
  creation, auto-clear, manual clear, style switching, and destroy
- Export HighlightManager from src/ui/index.ts barrel file
- Migrate example-games/gym/scenes/GymHandPileScene.ts:
  - Remove HIGHLIGHT_COLOR / HIGHLIGHT_ALPHA constants
  - Replace highlightGraphics/highlightLabels with highlightManager
  - showValidMoves() uses addZone() with 3000ms lifetime
  - highlightDropZones() uses addZone() for drag feedback
  - clearHighlights() delegates to highlightManager.clearAll()
  - shutdown() calls highlightManager.destroy()
- Update GymHandPileShutdown.test.ts for new highlightManager property
- Update GymHandPileHighlights.browser.test.ts for new API
…r layout

- Add optional 'centerX' property to HandViewOptions
- Store as private _centerX, used in computeCardPositions() and
  animateAddCard() to anchor hand at a fixed horizontal centre
- Add setCenterX(x: number | undefined) public method for runtime updates
- Update GymHandPileScene to use centerX: GAME_W/2 instead of static HAND_BASE_X
- Carry forward pre-existing Slider import migration in Gym scene
- Add 21 unit tests in tests/ui/handView.centerX.test.ts covering:
  construction, spacing changes, addCard/removeCard, arc layout,
  backward compatibility, vertical mode, setCenterX runtime updates,
  reduced-motion mode, and edge cases

Acceptance criteria: hand stays centered at GAME_W/2 after spacing,
draw, discard, and recall operations.
Adds [ < Prev ] and [ Next > ] buttons to all Gym demo scenes extending
GymSceneBase.initHeader(), positioned to the right of the [ Menu ] button
on the same Y line (SCENE_HEADER_Y = 14). Navigation wraps around using
the GYM_SCENE_CATALOGUE ordering.

Changes:
- GymRegistry.ts: Added getAdjacentGymSceneKey() exported helper function
  for wrap-around scene navigation logic
- GymSceneBase.ts: Added prevButton/nextButton protected properties and
  createNavButton() private method; modified initHeader() to create the
  buttons with style matching [ Menu ] (12px font, #aaccaa color, #88ff88
  hover)
- GymSceneHeaderNavigation.test.ts: 8 new unit tests verifying wrap-around
  navigation (first→last, last→first), middle-adjacent navigation, unknown
  key handling, and Router scene exclusion
- docs/gym/GYM_INDEX.md, example-games/gym/README.md: Updated with
  navigation documentation
- Add triggerTranscriptDownload() helper for browser file download
- Add 'Export Transcript' button to end-of-round overlay in GolfScene
- Add showErrorExportOverlay() for crash-time transcript export
- Add window.onerror handler in GolfScene for error-triggered export
- Increase overlay box height from 300 to 350 to accommodate new button
- Add browser test verifying export button exists and is interactive
- Create scripts/contact-sheet.ts using sharp to composite turn
  screenshots into a grid with turn number labels (4 columns,
  225x175 thumbnails, labeled SVG overlays)
- Integrate contact sheet generation into replay.ts: call after
  replay loop completes, include contactSheetPath in summary
- Update ReplaySummary interface with optional contactSheetPath
- Build and all tests pass
- Add Engine Event System section to docs/DEVELOPER.md with
  event types table, subscribing/emitting examples, global
  access (window.__GAME_EVENTS__), and PhaserEventBridge docs
- Add Contact Sheet section documenting contact-sheet.png
  output, grid layout, and sharp-based generation
- Add In-Game Transcript Export Button section documenting
  end-of-round and error-triggered export
- Add troubleshooting entries for: dev server not running,
  unsupported transcript version, IndexedDB quota issues,
  Playwright not installed
…n mechanism and tests

Implementation:
- Add initUndoRedoButtons(onUndo, onRedo) to CardGameScene
- Add refreshUndoRedoButtons(canUndo, canRedo) to CardGameScene
- Resolution-independent positioning relative to settings button
- Buttons parented into hudContainer at depth 1000
- shutdownBase() cleanup for undo/redo buttons

Tests:
- 14 unit tests for button creation, alpha state, cleanup, opt-in
- 4 browser tests for overlap verification at 1280x720, 1024x768, 1920x1080
- All 3413 unit tests + 4 browser tests pass
…o shared undo/redo mechanism

- Removed undoButton/redoButton from BeleagueredCastleRenderer
- Removed createActionButton calls and refreshUndoRedoButtons method
- Added this.initUndoRedoButtons() in BeleagueredCastleScene.create()
- Added this.initUndoRedoButtons() in restoreFromCheckpoint()
- Replaced bcRenderer.refreshUndoRedoButtons with this.refreshUndoRedoButtons
- Added 4 browser tests verifying migration and no overlap
- All 3413 unit tests + 8 BC browser tests pass
…d undo/redo mechanism

- Removed undo/redo button creation from refreshActionButtons()
- Removed smallW local variable (no longer needed)
- Updated getSectionRectsForTest() action width calculation
- Added initUndoRedoButtons() call in MainStreetLifecycleManager
- All 3413 unit tests + 13 MS browser tests pass
- Updated docs/DEVELOPER.md CardGameScene section with
  initUndoRedoButtons and refreshUndoRedoButtons API docs
- Added usage example in the scene lifecycle pattern
- Added description of resolution-independent positioning
- JSDoc was already added in the implementation commit
…buttons

- Replace text-based [ Undo ] / [ Redo ] buttons with
  createActionButton visual buttons
- Store button references and mirror refreshUndoRedoButtons
  alpha pattern (1.0 enabled, 0.5 disabled) in updateDisplay()
- Update help text to reference 'action buttons' instead of
  bracketed labels
- All 7 Gym undo/redo unit tests pass
…dUndoRedoButtons utility

Extract undo/redo button creation + positioning logic from
CardGameScene.initUndoRedoButtons() into a standalone exported
function createStandardUndoRedoButtons() in Renderer/index.ts.

This allows any scene (including GymUndoRedoScene which extends
Phaser.Scene, not CardGameScene) to use the standard-positioned
undo/redo buttons via the shared mechanism.

Changes:
- src/ui/Renderer/index.ts: Add createStandardUndoRedoButtons()
  standalone function with StandardUndoRedoButtons interface
- src/ui/CardGameScene.ts: initUndoRedoButtons() now delegates
  to createStandardUndoRedoButtons()
- example-games/gym/scenes/GymUndoRedoScene.ts: Replace custom
  createActionButton calls with createStandardUndoRedoButtons()
- tests/ui/CardGameScene.test.ts: Update mock and tests for the
  new delegation pattern; remove opt-in test no longer valid
  (BC always initializes undo/redo in create())

All 3411 unit + 11 browser tests pass.
- Added COMMON_SFX_KEYS constant object in SoundManager.ts for cross-game keys
  (UI_CLICK, TURN_CHANGE, ROUND_END, SCORE_REVEAL)
- Added namespace collision protection to SoundManager via namespace option
- Added clearRegistrations(), has(), keys() methods to SoundManager
- Added audioPathWithFallback() helper to CardGameScene for per-game audio dirs
  with default fallback
- Migrated Beleaguered Castle, Lost Cities, The Mind from game-specific prefixes
  (bc-sfx-, lc-sfx-, mind-sfx-) to standard sfx- prefix
- Migrated Main Street from ms- prefix to sfx- prefix
- Added namespace-scoped Phaser audio keys for collision protection across all 8 games
  (golf, sushi-go, feudalism, beleaguered-castle, lost-cities, the-mind, main-street)
- Created assets/audio/default/ with shared fallback sounds
- Created per-game audio directories (assets/audio/golf/, sushi-go/, feudalism/)
  with copies of shared audio files
- Created docs/SFX_CONVENTION.md documenting the naming convention
- Updated docs/DEVELOPER.md with SFX convention reference
- Updated all tests to use new sfx- prefix convention
- Updated sfx-tf-mapping.ts with new sfx- prefix keys
… feedback for safe auto-moves in Beleaguered Castle

- Added isSafeAutoMove parameter to TurnControllerCallbacks.onAutoCompleteVisual
  to distinguish safe auto-moves from endgame auto-complete
- Modified executePlayerMove to pass isSafeAutoMove=true when triggering
  auto-move visual playback
- Updated BeleagueredCastleScene.runAutoCompleteVisuals to accept the
  isSafeAutoMove flag and use card-to-foundation sound/event for safe
  auto-moves vs auto-complete-card for endgame auto-complete
- For safe auto-moves: plays sfx-card-to-foundation end sound via
  moveGameObject and emits card-to-foundation game event per card,
  providing consistent audio feedback with manual foundation moves
- Interaction remains blocked during playback via existing
  turnController.autoCompleting flag
- Added 3 new tests:
  * Verifies onAutoCompleteVisual is called with isSafeAutoMove=true
    when safe auto-moves are triggered (seed 5)
  * Verifies callback is NOT called when no safe auto-moves exist
    (seed 4, tableau-to-tableau move)
  * Verifies startAutoComplete calls callback without isSafeAutoMove
    for endgame auto-complete
@SorraTheOrc

Copy link
Copy Markdown
Member Author

Closed as superceded by 597

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.

1 participant