feat(sasch40): major overhaul with doodle jump, party bunker, and guitar hero

- Add global settings & pause modal (gear icon) with mute and reset, removing obsolete bag button
- Extend Prologue with Flo Maier (castle fire game over & Löschzug restart) and Viktor (vampire bite game over & Knoblauch restart)
- Rebuild Akt II as 3-level vertical Doodle Jump climber to rescue sisters Saskia, Maja, and Miriam with custom pixel portraits
- Update Akt III Schankraum with seamless oak floor, double-tap 'Luke zum Party Bunker', duel intro modals, and Hansi's departure in Hinterland
- Rebuild Akt IV as 3-lane medieval Guitar Hero rock concert with live crowd meter, combo multipliers, and Hansi duo
- Update AGENTS.md architectural documentation and playtest test suite
This commit is contained in:
Moritz Graf
2026-09-24 18:22:28 +02:00
parent 6374ba9e8a
commit 8a0b65c3fa
22 changed files with 2307 additions and 1250 deletions
+250 -242
View File
@@ -72,113 +72,161 @@ async function runPlaytest() {
await new Promise(r => setTimeout(r, 1000));
// 2. PROLOGUE SCREEN (Balcony Scene)
console.log('📸 02: Capturing Prologue Screen (Verifying banner/portrait alignment)...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '02_prologue_screen.png') });
console.log('📸 02a: Capturing Prologue Screen (NAT opening)...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '02a_prologue_nat.png') });
// Advance Prologue Dialogues
await page.waitForSelector('.choice-btn', { timeout: 5000 });
const firstChoice = await page.$('.choice-btn');
if (firstChoice) {
await firstChoice.click();
await new Promise(r => setTimeout(r, 800));
console.log('📸 02b: Capturing Prologue Mop Dialog...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '02b_prologue_mop.png') });
}
// Click first choice -> Flo Maier arrives
const natChoice = await page.$('.choice-btn');
if (natChoice) await natChoice.click();
await new Promise(r => setTimeout(r, 800));
// Advance to Platformer
const mopChoice = await page.$('.choice-btn');
if (mopChoice) {
await mopChoice.click();
await new Promise(r => setTimeout(r, 1000));
}
console.log('📸 02b: Capturing Flo Maier Feierdeifl arrives...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '02b_prologue_flo_feierdeifl.png') });
// 3. PLATFORMER PRE-LEVEL START SCREEN (Act II)
console.log('📸 03: Capturing Platformer Start Screen Modal...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '03_platformer_start_modal.png') });
// Test Game Over branch: "Ja freilich, zünd ois o, Flo!"
const fireChoice = await page.$('.choice-btn:nth-child(1)');
if (fireChoice) await fireChoice.click();
await new Promise(r => setTimeout(r, 800));
// Click Start Act Button on the modal
const startPlatformerBtn = await page.$('.start-act-btn');
if (startPlatformerBtn) {
await startPlatformerBtn.click();
console.log('📸 02c: Capturing Flo Maier Game Over (fiery castle)...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '02c_prologue_flo_game_over.png') });
// Reset via Löschzug
const resetFireBtn = await page.$('.game-over-btn');
if (resetFireBtn) await resetFireBtn.click();
await new Promise(r => setTimeout(r, 800));
// Skip NAT to Flo again
const natChoice2 = await page.$('.choice-btn');
if (natChoice2) await natChoice2.click();
await new Promise(r => setTimeout(r, 600));
// Decline Flo Maier -> Viktor arrives
const declineFloBtn = await page.$('.choice-btn:nth-child(2)');
if (declineFloBtn) await declineFloBtn.click();
await new Promise(r => setTimeout(r, 800));
console.log('📸 02d: Capturing Viktor Partyvampir arrives...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '02d_prologue_viktor_vampire.png') });
// Test Game Over branch: "Ja geil, mach mi unsterblich!"
const biteChoice = await page.$('.choice-btn:nth-child(1)');
if (biteChoice) await biteChoice.click();
await new Promise(r => setTimeout(r, 800));
console.log('📸 02e: Capturing Viktor Game Over (glitter dust in sun)...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '02e_prologue_viktor_game_over.png') });
// Reset via Knoblauch
const resetVampBtn = await page.$('.game-over-btn');
if (resetVampBtn) await resetVampBtn.click();
await new Promise(r => setTimeout(r, 800));
// Advance to Mop safely: NAT -> Flo (decline) -> Viktor (decline) -> Mop
const natC = await page.$('.choice-btn');
if (natC) await natC.click();
await new Promise(r => setTimeout(r, 500));
const floC = await page.$('.choice-btn:nth-child(2)');
if (floC) await floC.click();
await new Promise(r => setTimeout(r, 500));
const vikC = await page.$('.choice-btn:nth-child(2)');
if (vikC) await vikC.click();
await new Promise(r => setTimeout(r, 800));
console.log('📸 02f: Capturing Mop Dialogue (Sister Rescue Quest)...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '02f_prologue_mop.png') });
// Advance to Akt II (Doodle Jump Schwesternrettung)
const startAkt2Btn = await page.$('.choice-btn');
if (startAkt2Btn) await startAkt2Btn.click();
await new Promise(r => setTimeout(r, 1000));
// 3. AKT II: DOODLE JUMP SCHWESTERNRETTUNG
console.log('📸 03a: Capturing Akt II Doodle Jump Start Modal...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '03a_doodle_jump_intro_modal.png') });
// Click Start Act Button on modal
const startDoodleBtn = await page.$('.start-act-btn');
if (startDoodleBtn) {
await startDoodleBtn.click();
await new Promise(r => setTimeout(r, 800));
}
// 4. PLATFORMER GAMEPLAY
console.log('📸 04: Capturing Platformer Gameplay...');
const btnA = await page.$('.btn-a');
if (btnA) {
await btnA.click();
await new Promise(r => setTimeout(r, 300));
}
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '04_platformer_gameplay.png') });
// Capture Gameplay (Bouncing up platforms)
console.log('📸 03b: Capturing Doodle Jump Gameplay...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '03b_doodle_jump_gameplay.png') });
// 5. TAVERN: SCHANKRAUM (Gaststube)
// Trigger Sister 1 Rescue (Saskia)
await page.evaluate(() => {
const app = document.querySelector('#app')?.__vue_app__;
const comp = app?._instance?.subTree?.children?.[1]?.children?.[0]?.component?.subTree?.children?.[0]?.component?.ctx;
// Alternatively trigger rescue directly via store or component
const pinia = app?.config?.globalProperties?.$pinia;
const store = pinia?._s.get('game');
if (store) {
store.addKronkorken(3);
store.addBeer();
}
});
// 4. TAVERN: SCHANKRAUM (Gaststube with Seamless Oak Floor)
console.log('🍺 Advancing to Tavern Act (Schankraum)...');
await page.evaluate(() => {
const app = document.querySelector('#app')?.__vue_app__;
if (app && app.config?.globalProperties?.$pinia) {
const pinia = app.config.globalProperties.$pinia;
for (const [id, store] of pinia._s.entries()) {
if (id === 'game') store.setAct('tavern');
}
}
const pinia = app?.config?.globalProperties?.$pinia;
const store = pinia?._s.get('game');
if (store) store.setAct('tavern');
});
await new Promise(r => setTimeout(r, 1000));
console.log('📸 05: Capturing Tavern Gaststube (Schankraum)...');
console.log('📸 05: Capturing Tavern Schankraum (seamless oak floor)...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '05_tavern_schankraum.png') });
// Test Verena Hotspot
console.log('👥 Testing Verena Dialog...');
const verenaBtn = await page.$('.hotspot-verena');
if (verenaBtn) {
await verenaBtn.click();
await new Promise(r => setTimeout(r, 700));
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '06_tavern_verena_dialog.png') });
const actionBtn = await page.$('.dialog-actions .action-btn');
if (actionBtn) await actionBtn.click();
await new Promise(r => setTimeout(r, 400));
// Test Double-Click / Double-Tap on Trapdoor to unlock Party Bunker
console.log('🚪 Testing double-click / double-tap on oak floor trapdoor...');
const trapdoor = await page.$('.trapdoor-hotspot');
if (trapdoor) {
// First click: triggers subtle sound, still closed
await trapdoor.click();
await new Promise(r => setTimeout(r, 150));
// Second click within 450ms: unlocks Party Bunker!
await trapdoor.click();
await new Promise(r => setTimeout(r, 1000));
console.log('📸 12b: Capturing Secret VIP Party Bunker...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '12b_tavern_party_bunker_vip.png') });
// Click Pü in Party Bunker
const pueBtn = await page.$('.hotspot-pue');
if (pueBtn) {
await pueBtn.click();
await new Promise(r => setTimeout(r, 700));
console.log('📸 13: Capturing Pü Dialog...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '13_tavern_pue_dialog.png') });
const actionBtn = await page.$('.dialog-actions .action-btn');
if (actionBtn) await actionBtn.click();
await new Promise(r => setTimeout(r, 400));
}
// Return to Schankraum
const backToSchankraum = await page.$('.hotspot-door-back-vip');
if (backToSchankraum) {
await backToSchankraum.click();
await new Promise(r => setTimeout(r, 800));
console.log('📸 12: Capturing Schankraum with revealed Luke zum Party Bunker...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '12_tavern_party_bunker_trapdoor.png') });
}
}
// Test Armend Hotspot
console.log('🔨 Testing Armend Dialog...');
const armendBtn = await page.$('.hotspot-armend');
if (armendBtn) {
await armendBtn.click();
await new Promise(r => setTimeout(r, 700));
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '07_tavern_armend_dialog.png') });
const actionBtn = await page.$('.dialog-actions .action-btn');
if (actionBtn) await actionBtn.click();
await new Promise(r => setTimeout(r, 400));
}
// 5b. TAVERN: NEBENRAUM (Amy painting & Zuluman Mirror)
// Test Nebenraum (Atelier with Amy & Zuluman Mirror)
console.log('🎨 Navigating to Nebenraum (Kemenate / Atelier)...');
const nebenraumDoor = await page.$('.hotspot-door-nebenraum');
if (nebenraumDoor) {
await nebenraumDoor.click();
} else {
const nrTab = await page.$('.room-tab:nth-child(2)');
if (nrTab) await nrTab.click();
}
await new Promise(r => setTimeout(r, 1000));
const nrTab = await page.$('.room-tab:nth-child(2)');
if (nrTab) await nrTab.click();
await new Promise(r => setTimeout(r, 800));
console.log('📸 05b: Capturing Nebenraum (Atelier & Mirror)...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '05b_tavern_nebenraum.png') });
// Test Amy in Nebenraum
console.log('🎨 Testing Amy Dialog in Nebenraum...');
const amyBtn = await page.$('.hotspot-amy-nebenraum');
if (amyBtn) {
await amyBtn.click();
await new Promise(r => setTimeout(r, 700));
console.log('📸 05c: Capturing Amy Dialog...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '05c_tavern_amy_dialog.png') });
const actionBtn = await page.$('.dialog-actions .action-btn');
if (actionBtn) await actionBtn.click();
await new Promise(r => setTimeout(r, 400));
}
// Test Zuluman Mirror in Nebenraum
console.log('🪞 Testing Zuluman Magic Mirror in Nebenraum...');
const mirrorBtn = await page.$('.hotspot-mirror-nebenraum');
if (mirrorBtn) {
await mirrorBtn.click();
@@ -190,54 +238,46 @@ async function runPlaytest() {
await new Promise(r => setTimeout(r, 400));
}
// 6. TAVERN: MARKTPLATZ (Mario with spinning chainsaws & NAT on stage)
// Test Marktplatz & Wildschwein Duel
console.log('🎪 Navigating to Marktplatz...');
const marktplatzTab = await page.$('.room-tab:nth-child(3)');
if (marktplatzTab) {
await marktplatzTab.click();
await new Promise(r => setTimeout(r, 1000));
console.log('📸 08: Capturing Marktplatz (Mario chainsaws & NAT stage)...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '08_tavern_marktplatz.png') });
if (marktplatzTab) await marktplatzTab.click();
await new Promise(r => setTimeout(r, 800));
// Click Mario
const marioBtn = await page.$('.hotspot-mario');
if (marioBtn) {
await marioBtn.click();
await new Promise(r => setTimeout(r, 700));
console.log('📸 09: Capturing Mario Dialog...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '09_tavern_mario_dialog.png') });
const actionBtn = await page.$('.dialog-actions .action-btn');
if (actionBtn) await actionBtn.click();
await new Promise(r => setTimeout(r, 400));
}
console.log('📸 08: Capturing Marktplatz...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '08_tavern_marktplatz.png') });
// Click NAT (Josef) & Test Wildschwein Duell
const natBtn = await page.$('.hotspot-nat');
if (natBtn) {
await natBtn.click();
await new Promise(r => setTimeout(r, 700));
console.log('📸 09b: Capturing NAT (Josef) Dialog...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '09b_tavern_nat_dialog.png') });
// Start Wild Boar Duel
console.log('🐗 Launching Wildschwein-Schnick-Schnack-Schnuck Duel...');
const startBoarBtn = await page.$('.dialog-actions .action-btn');
if (startBoarBtn) {
await startBoarBtn.click();
const natBtn = await page.$('.hotspot-nat');
if (natBtn) {
await natBtn.click();
await new Promise(r => setTimeout(r, 700));
console.log('📸 09b: Capturing NAT Dialog...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '09b_tavern_nat_dialog.png') });
// Click "🐗 Zum Wildschwein-Duell!" -> opens INTRO MODAL
const startBoarIntroBtn = await page.$('.dialog-actions .action-btn');
if (startBoarIntroBtn) {
await startBoarIntroBtn.click();
await new Promise(r => setTimeout(r, 800));
console.log('📸 09c: Capturing Wildschwein Duel INTRO modal...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '09c_tavern_boar_duel_intro.png') });
// Start Duel from Intro
const startBoarDuelBtn = await page.$('.start-duel-action-btn');
if (startBoarDuelBtn) {
await startBoarDuelBtn.click();
await new Promise(r => setTimeout(r, 800));
console.log('📸 09c: Capturing Wildschwein Duel Modal...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '09c_tavern_boar_duel.png') });
// Play a move: Keiler!
// Play Keiler
const keilerBtn = await page.$('.boar-choice-btn:nth-child(1)');
if (keilerBtn) {
await keilerBtn.click();
await new Promise(r => setTimeout(r, 600));
console.log('📸 09d: Capturing Boar Duel Clash...');
console.log('📸 09d: Capturing Boar Duel Round Clash (verifying unhighlighted buttons)...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '09d_tavern_boar_duel_round.png') });
}
// Close Boar Duel modal
// Close modal via ✕
const closeBoarBtn = await page.$('.boar-duel-box .duel-close-btn');
if (closeBoarBtn) {
await closeBoarBtn.click();
@@ -247,162 +287,130 @@ async function runPlaytest() {
}
}
// 7. TAVERN: HINTERLAND (Mane hiking)
// Test Hinterland (Mane & Hansi departing toward Münchanien)
console.log('🌲 Navigating to Hinterland...');
const hinterlandTab = await page.$('.room-tab:nth-child(4)');
if (hinterlandTab) {
await hinterlandTab.click();
await new Promise(r => setTimeout(r, 1000));
console.log('📸 10: Capturing Hinterland (Mane hiking)...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '10_tavern_hinterland.png') });
if (hinterlandTab) await hinterlandTab.click();
await new Promise(r => setTimeout(r, 1000));
// Click Mane
const maneBtn = await page.$('.hotspot-mane');
if (maneBtn) {
await maneBtn.click();
await new Promise(r => setTimeout(r, 700));
console.log('📸 11: Capturing Mane Dialog...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '11_tavern_mane_dialog.png') });
const actionBtn = await page.$('.dialog-actions .action-btn');
if (actionBtn) await actionBtn.click();
await new Promise(r => setTimeout(r, 400));
}
console.log('📸 10: Capturing Hinterland (Mane & Hansi departing toward Münchanien)...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '10_tavern_hinterland.png') });
// Click Hansi to hear about departure and evening concert
const hansiBtn = await page.$('.hotspot-hansi');
if (hansiBtn) {
await hansiBtn.click();
await new Promise(r => setTimeout(r, 700));
console.log('📸 11: Capturing Hansi Departure Dialog...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '11_tavern_hansi_dialog.png') });
const actionBtn = await page.$('.dialog-actions .action-btn');
if (actionBtn) await actionBtn.click();
await new Promise(r => setTimeout(r, 400));
}
// 8. TAVERN: SECRET HINTERZIMMER (VIP Rave via Luke zum Hinterraum)
console.log('🗝️ Returning to Schankraum to check Luke zum Hinterraum (trapdoor)...');
const schankraumTab = await page.$('.room-tab:nth-child(1)');
if (schankraumTab) {
await schankraumTab.click();
await new Promise(r => setTimeout(r, 600));
}
console.log('🪩 Triggering Luke zum Hinterraum Easter Egg...');
const trapdoor = await page.$('.trapdoor-hotspot');
if (trapdoor) {
await trapdoor.click();
await new Promise(r => setTimeout(r, 1000));
console.log('📸 12: Capturing Secret VIP Hinterzimmer...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '12_tavern_hinterzimmer_vip.png') });
// Click Pü in Hinterzimmer
const pueBtn = await page.$('.hotspot-pue');
if (pueBtn) {
await pueBtn.click();
await new Promise(r => setTimeout(r, 700));
console.log('📸 13: Capturing Pü Dialog...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '13_tavern_pue_dialog.png') });
const actionBtn = await page.$('.dialog-actions .action-btn');
if (actionBtn) await actionBtn.click();
await new Promise(r => setTimeout(r, 400));
}
}
// 9. GSTANZL DUEL
console.log('⚔️ Testing Gstanzl-Duel and [✕] Exit Button...');
const backToGaststube = await page.$('.hotspot-door-back-vip');
if (backToGaststube) {
await backToGaststube.click();
await new Promise(r => setTimeout(r, 600));
}
// Test Gstanzl Duel Intro & Gameplay
console.log('⚔️ Testing Gstanzl-Fechten Intro & Minigame...');
const duelBtn = await page.$('.duel-trigger');
if (duelBtn) {
await duelBtn.click();
await new Promise(r => setTimeout(r, 700));
console.log('📸 15: Capturing Gstanzl Duel with [✕] button...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '15_tavern_gstanzl_duel.png') });
// Test the [✕] close button
const closeDuelBtn = await page.$('.duel-close-btn');
if (closeDuelBtn) {
console.log('Testing duel exit via [✕] button...');
await closeDuelBtn.click();
await new Promise(r => setTimeout(r, 600));
const duelClosed = await page.$('.duel-box') === null;
console.log('Duel modal closed successfully by [✕]:', duelClosed);
console.log('📸 15a: Capturing Gstanzl Duel INTRO modal...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '15a_tavern_gstanzl_intro.png') });
const startGstanzlBtn = await page.$('.start-duel-action-btn');
if (startGstanzlBtn) {
await startGstanzlBtn.click();
await new Promise(r => setTimeout(r, 700));
console.log('📸 15b: Capturing Gstanzl Duel Round...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '15b_tavern_gstanzl_duel.png') });
// Close via ✕
const closeDuelBtn = await page.$('.duel-box .duel-close-btn');
if (closeDuelBtn) {
await closeDuelBtn.click();
await new Promise(r => setTimeout(r, 400));
}
}
}
// Test reload persistence in Tavern Act
console.log('💾 Testing game state reload persistence...');
const stateBeforeReload = await page.evaluate(() => {
const app = document.querySelector('#app')?.__vue_app__;
const pinia = app?.config?.globalProperties?.$pinia;
const s = pinia?._s.get('game');
return s ? { currentAct: s.currentAct, kronkorken: s.kronkorken, beers: s.beers } : null;
});
console.log('State before reload:', stateBeforeReload);
await page.reload({ waitUntil: 'networkidle0' });
await new Promise(r => setTimeout(r, 1000));
const stateAfterReload = await page.evaluate(() => {
const app = document.querySelector('#app')?.__vue_app__;
const pinia = app?.config?.globalProperties?.$pinia;
const s = pinia?._s.get('game');
return s ? { currentAct: s.currentAct, kronkorken: s.kronkorken, beers: s.beers } : null;
});
console.log('State after reload:', stateAfterReload);
// 10. PARTY EXPRESS (Act IV)
console.log('🚂 Advancing to Party Express (Act IV)...');
// 5. AKT IV: MITTELALTER GUITAR HERO (HANSIS ABSCHIEDSKONZERT)
console.log('🎸 Advancing to Akt IV (Mittelalter Guitar Hero)...');
await page.evaluate(() => {
const app = document.querySelector('#app')?.__vue_app__;
if (app && app.config?.globalProperties?.$pinia) {
const pinia = app.config.globalProperties.$pinia;
for (const [id, store] of pinia._s.entries()) {
if (id === 'game') store.setAct('party_express');
}
}
const pinia = app?.config?.globalProperties?.$pinia;
const store = pinia?._s.get('game');
if (store) store.setAct('party_express');
});
await new Promise(r => setTimeout(r, 1000));
console.log('📸 16: Capturing Party Express Start Screen Modal...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '16_party_express_start_modal.png') });
// Start Party Express
const startExpressBtn = await page.$('.start-act-btn');
if (startExpressBtn) {
await startExpressBtn.click();
console.log('📸 16: Capturing Lute Hero Start Screen Modal...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '16_lute_hero_start_modal.png') });
// Start Concert
const startConcertBtn = await page.$('.start-act-btn');
if (startConcertBtn) {
await startConcertBtn.click();
await new Promise(r => setTimeout(r, 800));
}
console.log('📸 17: Capturing Party Express Gameplay (Redesigned Bollerwagen)...');
// Serve beer
const throwBeerBtn = await page.$('.throw-beer-btn');
if (throwBeerBtn) {
await throwBeerBtn.click();
await new Promise(r => setTimeout(r, 400));
}
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '17_party_express_gameplay.png') });
// Hit string buttons
console.log('🎸 Hitting lute strings...');
const btnLane0 = await page.$('.btn-lane-0');
const btnLane1 = await page.$('.btn-lane-1');
const btnLane2 = await page.$('.btn-lane-2');
if (btnLane0) await btnLane0.click();
await new Promise(r => setTimeout(r, 200));
if (btnLane1) await btnLane1.click();
await new Promise(r => setTimeout(r, 200));
if (btnLane2) await btnLane2.click();
await new Promise(r => setTimeout(r, 300));
// 11. FINALE / CERTIFICATE (Act V)
console.log('📸 17: Capturing Castle Stage Rock Concert Gameplay...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '17_lute_hero_gameplay.png') });
// 6. AKT V: FINALE & CERTIFICATE
console.log('👑 Advancing to Finale Certificate (Act V)...');
await page.evaluate(() => {
const app = document.querySelector('#app')?.__vue_app__;
if (app && app.config?.globalProperties?.$pinia) {
const pinia = app.config.globalProperties.$pinia;
for (const [id, store] of pinia._s.entries()) {
if (id === 'game') {
store.addKronkorken(35);
store.serveGuest();
store.serveGuest();
store.setAct('finale');
}
}
const pinia = app?.config?.globalProperties?.$pinia;
const store = pinia?._s.get('game');
if (store) {
store.addKronkorken(35);
store.serveGuest();
store.serveGuest();
store.setAct('finale');
}
});
await new Promise(r => setTimeout(r, 1500));
console.log('📸 18: Capturing Certificate Modal...');
console.log('📸 18: Capturing Certificate Screen...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '18_certificate_screen.png') });
// Test NOCHMAL SPIELEN button
// Test Settings Modal (Gear icon ⚙️)
console.log('⚙️ Testing Settings Modal (Pause, Mute, Reset)...');
const settingsBtn = await page.$('.settings-toggle-btn');
if (settingsBtn) {
await settingsBtn.click();
await new Promise(r => setTimeout(r, 700));
console.log('📸 19: Capturing Settings & Pause Modal...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '19_settings_pause_modal.png') });
// Click Resume
const resumeBtn = await page.$('.resume-btn');
if (resumeBtn) {
await resumeBtn.click();
await new Promise(r => setTimeout(r, 500));
}
}
// Test NOCHMAL SPIELEN button on certificate
console.log('🔄 Testing NOCHMAL SPIELEN button...');
const restartBtn = await page.$('.restart-btn');
if (restartBtn) {
await restartBtn.click();
await new Promise(r => setTimeout(r, 1000));
console.log('📸 19: Capturing post-restart Intro screen...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '19_post_restart_intro.png') });
console.log('📸 20: Capturing post-restart Intro screen...');
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '20_post_restart_intro.png') });
}
// Verify all images loaded properly