diff --git a/projects/sasch40/frontend/public/assets/characters/flo_maier/portrait.jpg b/projects/sasch40/frontend/public/assets/characters/flo_maier/portrait.jpg new file mode 100644 index 0000000..b39a4ae Binary files /dev/null and b/projects/sasch40/frontend/public/assets/characters/flo_maier/portrait.jpg differ diff --git a/projects/sasch40/frontend/public/assets/characters/mane/portrait.jpg b/projects/sasch40/frontend/public/assets/characters/mane/portrait.jpg index e856595..19e6c34 100644 Binary files a/projects/sasch40/frontend/public/assets/characters/mane/portrait.jpg and b/projects/sasch40/frontend/public/assets/characters/mane/portrait.jpg differ diff --git a/projects/sasch40/frontend/public/assets/characters/mario/portrait.jpg b/projects/sasch40/frontend/public/assets/characters/mario/portrait.jpg index 9fba1fb..92726c0 100644 Binary files a/projects/sasch40/frontend/public/assets/characters/mario/portrait.jpg and b/projects/sasch40/frontend/public/assets/characters/mario/portrait.jpg differ diff --git a/projects/sasch40/frontend/public/assets/characters/pue/portrait.jpg b/projects/sasch40/frontend/public/assets/characters/pue/portrait.jpg index ecb9c2c..9adfd16 100644 Binary files a/projects/sasch40/frontend/public/assets/characters/pue/portrait.jpg and b/projects/sasch40/frontend/public/assets/characters/pue/portrait.jpg differ diff --git a/projects/sasch40/frontend/public/assets/characters/sascha/portrait.jpg b/projects/sasch40/frontend/public/assets/characters/sascha/portrait.jpg index c716891..7012dde 100644 Binary files a/projects/sasch40/frontend/public/assets/characters/sascha/portrait.jpg and b/projects/sasch40/frontend/public/assets/characters/sascha/portrait.jpg differ diff --git a/projects/sasch40/frontend/public/assets/characters/viktor/portrait.jpg b/projects/sasch40/frontend/public/assets/characters/viktor/portrait.jpg new file mode 100644 index 0000000..41f7e24 Binary files /dev/null and b/projects/sasch40/frontend/public/assets/characters/viktor/portrait.jpg differ diff --git a/projects/sasch40/frontend/public/assets/scenes/hinterland.jpg b/projects/sasch40/frontend/public/assets/scenes/hinterland.jpg new file mode 100644 index 0000000..f6b80e3 Binary files /dev/null and b/projects/sasch40/frontend/public/assets/scenes/hinterland.jpg differ diff --git a/projects/sasch40/frontend/public/assets/scenes/hinterzimmer.jpg b/projects/sasch40/frontend/public/assets/scenes/hinterzimmer.jpg new file mode 100644 index 0000000..4c18a7a Binary files /dev/null and b/projects/sasch40/frontend/public/assets/scenes/hinterzimmer.jpg differ diff --git a/projects/sasch40/frontend/public/assets/scenes/marktplatz.jpg b/projects/sasch40/frontend/public/assets/scenes/marktplatz.jpg new file mode 100644 index 0000000..81fae32 Binary files /dev/null and b/projects/sasch40/frontend/public/assets/scenes/marktplatz.jpg differ diff --git a/projects/sasch40/frontend/public/assets/scenes/tavern.jpg b/projects/sasch40/frontend/public/assets/scenes/tavern.jpg index d35fbd5..2c9a67e 100644 Binary files a/projects/sasch40/frontend/public/assets/scenes/tavern.jpg and b/projects/sasch40/frontend/public/assets/scenes/tavern.jpg differ diff --git a/projects/sasch40/frontend/scripts/playtest.mjs b/projects/sasch40/frontend/scripts/playtest.mjs index e2066d9..10bc7bd 100644 --- a/projects/sasch40/frontend/scripts/playtest.mjs +++ b/projects/sasch40/frontend/scripts/playtest.mjs @@ -9,7 +9,7 @@ if (!fs.existsSync(SCREENSHOTS_DIR)) { } async function runPlaytest() { - console.log('🚀 Starting Chrome Playtest for Saschas Kronkorken Kreuzzug...'); + console.log('🚀 Starting Comprehensive Chrome Playtest for Saschas Kronkorken Kreuzzug...'); const logs = []; const errors = []; @@ -60,165 +60,206 @@ async function runPlaytest() { try { console.log('🌐 Navigating to https://sasch40.haumdaucher.de...'); - await page.goto('https://sasch40.haumdaucher.de', { waitUntil: 'networkidle0', timeout: 30000 }); + await page.goto('https://sasch40.haumdaucher.de', { waitUntil: 'networkidle0', timeout: 35000 }); - // 1. INTRO SCREEN - console.log('📸 Capturing Intro Screen...'); + // 1. INTRO / PREQUEL SCREEN + console.log('📸 01: Capturing Intro Screen...'); await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '01_intro_screen.png') }); - // Inspect layout and controls presence in Intro - const introControlsVisible = await page.evaluate(() => { - const dpad = document.querySelector('.dpad'); - const intro = document.querySelector('.intro-screen'); - const chassis = document.querySelector('.gameboy-chassis'); - return { - hasDpad: !!dpad, - dpadOffsetHeight: dpad ? (dpad.offsetHeight > 0) : false, - hasIntro: !!intro, - layoutClass: chassis ? chassis.className : '' - }; - }); - console.log('Intro Layout Check:', introControlsVisible); - // Click Start Button console.log('🖱️ Clicking Start Button...'); await page.click('.start-btn'); await new Promise(r => setTimeout(r, 1000)); - // 2. PROLOGUE SCREEN - console.log('📸 Capturing Prologue Screen...'); + // 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') }); // Advance Prologue Dialogues - console.log('💬 Advancing Prologue Dialogues (clicking choice buttons)...'); - // Click choice 1 on 'start' 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('📸 Capturing Mop Appears Prologue Dialogue...'); + console.log('📸 02b: Capturing Prologue Mop Dialog...'); await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '02b_prologue_mop.png') }); } - // Click choice on 'mop_appears' -> triggers 'startPlatformer' + // Advance to Platformer const mopChoice = await page.$('.choice-btn'); if (mopChoice) { await mopChoice.click(); - await new Promise(r => setTimeout(r, 1200)); + await new Promise(r => setTimeout(r, 1000)); } - // 3. PLATFORMER SCREEN - console.log('📸 Capturing Platformer (Jump & Run)...'); - await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '03_platformer_screen.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') }); - const platformerControls = await page.evaluate(() => { - const dpad = document.querySelector('.dpad'); - const btnA = document.querySelector('.btn-a'); - const canvas = document.querySelector('canvas'); - return { - hasDpad: !!dpad, - hasBtnA: !!btnA, - hasCanvas: !!canvas, - canvasW: canvas?.width, - canvasH: canvas?.height - }; - }); - console.log('Platformer Controls Check:', platformerControls); + // Click Start Act Button on the modal + const startPlatformerBtn = await page.$('.start-act-btn'); + if (startPlatformerBtn) { + await startPlatformerBtn.click(); + await new Promise(r => setTimeout(r, 800)); + } - // Test Jump & Move - console.log('🎮 Testing Jump & Move Controls in Platformer...'); + // 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, 400)); - await btnA.click(); - await new Promise(r => setTimeout(r, 400)); - } - const dpadRight = await page.$('.dpad-right'); - if (dpadRight) { - await dpadRight.hover(); - await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '03b_platformer_jump.png') }); + await new Promise(r => setTimeout(r, 300)); } + await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '04_platformer_gameplay.png') }); - // Directly set act to 'tavern' to test Tavern Point & Click - console.log('🍺 Advancing to Tavern Act...'); + // 5. TAVERN: SCHANKRAUM (Gaststube) + console.log('🍺 Advancing to Tavern Act (Schankraum)...'); await page.evaluate(() => { - const chassis = document.querySelector('.gameboy-chassis'); - // access pinia store from window if exposed, or trigger level finish - // We can click the level finish or evaluate store change - window.dispatchEvent(new CustomEvent('test-set-act', { detail: 'tavern' })); - }); - - // Check if act switched, or use page.evaluate to trigger store change - await page.evaluate(() => { - // Find Pinia root if possible const app = document.querySelector('#app')?.__vue_app__; if (app && app.config?.globalProperties?.$pinia) { const pinia = app.config.globalProperties.$pinia; - // find game store for (const [id, store] of pinia._s.entries()) { - if (id === 'game') { - store.setAct('tavern'); - } + if (id === 'game') store.setAct('tavern'); } } }); - await new Promise(r => setTimeout(r, 1000)); - console.log('📸 Capturing Tavern Screen...'); - await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '04_tavern_screen.png') }); + console.log('📸 05: Capturing Tavern Gaststube (Schankraum)...'); + await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '05_tavern_schankraum.png') }); - // Test Tavern Hotspots - console.log('👥 Testing Verena Hotspot...'); + // 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, 800)); - await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '05_tavern_verena_dialog.png') }); + 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, 500)); + await new Promise(r => setTimeout(r, 400)); } - console.log('🔨 Testing Armend Hotspot...'); + // 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, 800)); - await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '06_tavern_armend_dialog.png') }); + 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, 500)); + await new Promise(r => setTimeout(r, 400)); } - console.log('🪞 Testing Zuluman Magic Mirror Hotspot...'); + // 6. TAVERN: MARKTPLATZ (Mario with spinning chainsaws) + console.log('🎪 Navigating to Marktplatz...'); + const marktplatzTab = await page.$('.room-tab:nth-child(2)'); + if (marktplatzTab) { + await marktplatzTab.click(); + await new Promise(r => setTimeout(r, 1000)); + console.log('📸 08: Capturing Marktplatz (Mario chainsaws)...'); + await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '08_tavern_marktplatz.png') }); + + // 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)); + } + } + + // 7. TAVERN: HINTERLAND (Mane hiking) + console.log('🌲 Navigating to Hinterland...'); + const hinterlandTab = await page.$('.room-tab:nth-child(3)'); + 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') }); + + // 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)); + } + } + + // 8. TAVERN: SECRET HINTERZIMMER (VIP Rave via Secret Tap) + console.log('🗝️ Returning to Schankraum to trigger Secret Tap...'); + const schankraumTab = await page.$('.room-tab:nth-child(1)'); + if (schankraumTab) { + await schankraumTab.click(); + await new Promise(r => setTimeout(r, 600)); + } + + console.log('🪩 Triggering Secret Tap Easter Egg...'); + const secretTap = await page.$('.secret-tap-hotspot'); + if (secretTap) { + await secretTap.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. ZULUMAN MAGIC MIRROR & GSTANZL DUEL + console.log('🪞 Testing Zuluman Magic Mirror...'); + const backToGaststube = await page.$('.hotspot-door-back-vip'); + if (backToGaststube) { + await backToGaststube.click(); + await new Promise(r => setTimeout(r, 600)); + } const mirrorBtn = await page.$('.hotspot-mirror'); if (mirrorBtn) { await mirrorBtn.click(); - await new Promise(r => setTimeout(r, 800)); - await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '07_tavern_zuluman_mirror.png') }); + await new Promise(r => setTimeout(r, 700)); + console.log('📸 14: Capturing Zuluman Mirror...'); + await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '14_tavern_zuluman_mirror.png') }); const closeBtn = await page.$('.mirror-box .action-btn'); if (closeBtn) await closeBtn.click(); - await new Promise(r => setTimeout(r, 500)); + await new Promise(r => setTimeout(r, 400)); } console.log('⚔️ Testing Gstanzl-Duel...'); const duelBtn = await page.$('.duel-trigger'); if (duelBtn) { await duelBtn.click(); - await new Promise(r => setTimeout(r, 800)); - await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '08_tavern_gstanzl_duel.png') }); - - // Answer Gstanzl question - const correctOption = await page.$('.option-btn'); - if (correctOption) { - await correctOption.click(); - await new Promise(r => setTimeout(r, 600)); + await new Promise(r => setTimeout(r, 700)); + console.log('📸 15: Capturing Gstanzl Duel...'); + await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '15_tavern_gstanzl_duel.png') }); + const firstAnswer = await page.$('.choice-btn'); + if (firstAnswer) { + await firstAnswer.click(); + await new Promise(r => setTimeout(r, 500)); } + // Close duel if won or modal + const actionBtn = await page.$('.duel-box .action-btn'); + if (actionBtn) await actionBtn.click(); } - // 4. PARTY EXPRESS (Act IV) + // 10. PARTY EXPRESS (Act IV) console.log('🚂 Advancing to Party Express (Act IV)...'); await page.evaluate(() => { const app = document.querySelector('#app')?.__vue_app__; @@ -230,10 +271,26 @@ async function runPlaytest() { } }); await new Promise(r => setTimeout(r, 1000)); - console.log('📸 Capturing Party Express...'); - await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '09_party_express.png') }); + console.log('📸 16: Capturing Party Express Start Screen Modal...'); + await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '16_party_express_start_modal.png') }); - // 5. FINALE / CERTIFICATE (Act V) + // Start Party Express + const startExpressBtn = await page.$('.start-act-btn'); + if (startExpressBtn) { + await startExpressBtn.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') }); + + // 11. FINALE / CERTIFICATE (Act V) console.log('👑 Advancing to Finale Certificate (Act V)...'); await page.evaluate(() => { const app = document.querySelector('#app')?.__vue_app__; @@ -241,7 +298,7 @@ async function runPlaytest() { const pinia = app.config.globalProperties.$pinia; for (const [id, store] of pinia._s.entries()) { if (id === 'game') { - store.addKronkorken(25); + store.addKronkorken(35); store.serveGuest(); store.serveGuest(); store.setAct('finale'); @@ -250,10 +307,10 @@ async function runPlaytest() { } }); await new Promise(r => setTimeout(r, 1500)); - console.log('📸 Capturing Certificate Modal...'); - await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '10_certificate_screen.png') }); + console.log('📸 18: Capturing Certificate Modal...'); + await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '18_certificate_screen.png') }); - // Check images in document + // Verify all images loaded properly const brokenImages = await page.evaluate(() => { const imgs = Array.from(document.querySelectorAll('img')); return imgs @@ -265,7 +322,7 @@ async function runPlaytest() { console.log('Total Console Logs:', logs.length); console.log('Console Errors:', errors); console.log('Failed Requests:', failedRequests); - console.log('Broken Images on Certificate Page:', brokenImages); + console.log('Broken Images:', brokenImages); const report = { timestamp: new Date().toISOString(), diff --git a/projects/sasch40/frontend/src/components/GameBoyFrame.vue b/projects/sasch40/frontend/src/components/GameBoyFrame.vue index a148c76..215f7f1 100644 --- a/projects/sasch40/frontend/src/components/GameBoyFrame.vue +++ b/projects/sasch40/frontend/src/components/GameBoyFrame.vue @@ -43,9 +43,9 @@ function toggleInventory() {
+ Der Hof-Bass wummert, der Bollerwagen ist poliert!
+ König Sascha zieht mit der Reichs-Soundanlage über die Festmeile von Haumdaucher. Deine Freunde stehen durstig am Straßenrand!
+
+ Hört die Kunde, edler König Sascha!
+ Deine Untertanen dürsten im ganzen Herzogtum nach frischem Gerstensaft. Doch ohne deine 40 heiligen Kronkorken bleiben die Fässer versiegelt!
+