// 🎮 GAME SCENE - MEADOW AWAKENING VERSION (Hytale Style) // "3x Blink to Wake Up + Virus Fog + Hytale UI + Emotional Memories" // Updated: January 20, 2026 import Animal from '../entities/Animal.js'; import MemoryHeartUI from '../ui/MemoryHeartUI.js'; class GameScene extends Phaser.Scene { constructor() { super({ key: 'GameScene' }); this.player = null; this.cursors = null; this.controls = null; this.isSprinting = false; this.lastMoveTime = 0; // Awakening State this.amnesiaMode = false; this.blinkCount = 0; this.isFullyAwake = false; this.virusFog = null; // Animal System this.animals = []; this.memoryHeartUI = null; } preload() { // Load heart icon for memory UI this.load.image('heart_icon', 'assets/slike/items/ui/MOJE_SLIKE_KONCNA_ostalo_vmesnik_ikone_heart_icon_style32.png'); // Optional: Load heartbeat sound this.load.audio('heartbeat', 'assets/audio/_NEW/369017__patobottos__heartbeats-61.wav'); } create(data) { console.log('🎮 GameScene Started'); console.log('📦 START DATA:', data); // 1. ENVIRONMENT (Black background default) this.cameras.main.setBackgroundColor('#000000'); // 2. TILEMAP or GENERATED WORLD // Use a simple large grass field for the Meadow Awakening const mapWidth = 2000; const mapHeight = 2000; this.add.tileSprite(0, 0, mapWidth, mapHeight, 'ground_grass') .setOrigin(0, 0) .setScrollFactor(1) // Moves with camera .setDepth(-100); // 3. PLAYER SETUP const centerX = mapWidth / 2; const centerY = mapHeight / 2; this.player = this.physics.add.sprite(centerX, centerY, 'kai_idle'); this.player.setScale(0.5); // Adjust as needed this.player.setCollideWorldBounds(true); this.physics.world.setBounds(0, 0, mapWidth, mapHeight); // 4. CAMERA this.cameras.main.startFollow(this.player, true, 0.1, 0.1); this.cameras.main.setZoom(0.8); // Default zoom // 5. INPUTS this.cursors = this.input.keyboard.createCursorKeys(); this.keys = this.input.keyboard.addKeys({ E: Phaser.Input.Keyboard.KeyCodes.E, SHIFT: Phaser.Input.Keyboard.KeyCodes.SHIFT }); // 6. AMNESIA / AWAKENING MODE if (data && data.startMode === 'AMNESIA_WAKEUP') { this.startAmnesiaMode(data.backgroundMusic); } else { // Normal start this.isFullyAwake = true; } // 7. DECORATIONS (Trees, Grass) this.addStarterCampDecoration(centerX, centerY); // 8. ANIMAL SYSTEM & MEMORY UI this.initializeAnimalSystem(); } initializeAnimalSystem() { console.log('🐕 Initializing animal system...'); // Create memory heart UI this.memoryHeartUI = new MemoryHeartUI(this); // Example: Add a domestic dog near player // (Replace with actual dog sprite when available) const dog = new Animal(this, 600, 600, 'kai_idle', 'domestic'); dog.animalName = 'Rex (family dog)'; this.animals.push(dog); console.log(`✅ Added ${this.animals.length} animals to scene`); } update(time, delta) { // AWAKENING LOGIC if (this.amnesiaMode && !this.isFullyAwake) { // Listen for 'E' press to blink if (Phaser.Input.Keyboard.JustDown(this.keys.E)) { this.handleBlink(); } return; // Block movement while waking up } // NORMAL MOVEMENT LOGIC this.handlePlayerMovement(); // UPDATE ANIMALS (proximity detection) if (this.player && this.animals) { this.animals.forEach(animal => animal.update(this.player)); } } startAmnesiaMode(music) { console.log('😵 AMNESIA MODE: Kai is dizzy on the meadow.'); this.amnesiaMode = true; this.blinkCount = 0; // Keep music from intro this.introMusic = music; // VISUAL EFFECTS (Blurry, Dark) this.cameras.main.setZoom(2.0); // Detailed close up on grass/face this.cameras.main.setAlpha(0.6); // Dim // Overlay (Blackout) this.amnesiaOverlay = this.add.rectangle( this.cameras.main.width / 2, this.cameras.main.height / 2, this.cameras.main.width, this.cameras.main.height, 0x000000, 0.9 ).setScrollFactor(0).setDepth(10000); // Wobbly Camera Effect this.cameras.main.shake(10000, 0.005); // Constant subtle shake // PROMPT this.wakeupText = this.add.text( this.cameras.main.width / 2, this.cameras.main.height - 100, "PRESS [E] TO OPEN EYES", { fontFamily: 'Verdana', fontSize: '24px', color: '#ffffff', stroke: '#000000', strokeThickness: 4 } ).setOrigin(0.5).setScrollFactor(0).setDepth(10001); // Prompt Animation this.tweens.add({ targets: this.wakeupText, alpha: 0.5, yoyo: true, repeat: -1, duration: 800 }); } handleBlink() { this.blinkCount++; console.log(`👁️ Blink ${this.blinkCount}/3`); // 1. Flash Black (Blink sensation) this.cameras.main.flash(300, 0, 0, 0); // 2. Improve Vision (Reduce Blur/Darkness) const progress = this.blinkCount / 3; // Reduce Overlay const newAlpha = 0.9 - (progress * 0.9); this.tweens.add({ targets: this.amnesiaOverlay, alpha: newAlpha, duration: 200 }); // Reset Camera Zoom step by step const currentZoom = this.cameras.main.zoom; const targetZoom = 2.0 - (progress * 1.2); // 2.0 -> 0.8 this.tweens.add({ targets: this.cameras.main, zoom: targetZoom, duration: 500 }); // Update Text this.wakeupText.setText(`[E] ... (${this.blinkCount}/3)`); if (this.blinkCount >= 3) { this.finishWakingUp(); } } finishWakingUp() { console.log('🌅 Kai is FULLY AWAKE!'); this.isFullyAwake = true; this.amnesiaMode = false; // Cleanup UI this.wakeupText.destroy(); if (this.amnesiaOverlay) this.amnesiaOverlay.destroy(); // Reset Camera completely this.cameras.main.zoomTo(0.8, 1000); this.cameras.main.shake(0); // Stop shake this.cameras.main.setAlpha(1); // START QUEST BANNER (Hytale Style) this.showHytaleBanner("NAJDI ZATOČIŠČE V KLETI", 0xFFD700); // Gold // START VIRUS FOG this.startVirusFog(); } showHytaleBanner(text, color) { const width = this.cameras.main.width; const banner = this.add.container(width / 2, -100).setScrollFactor(0); // Background Bar const bg = this.add.graphics(); bg.fillStyle(0x000000, 0.85); bg.fillRoundedRect(-350, -35, 700, 70, 10); bg.lineStyle(3, color, 1); bg.strokeRoundedRect(-350, -35, 700, 70, 10); // Text const txt = this.add.text(0, 0, text, { fontFamily: 'Verdana, Arial, sans-serif', fontSize: '28px', color: '#FFFFFF', fontStyle: 'bold', shadow: { offsetX: 2, offsetY: 2, color: '#000000', blur: 4, stroke: true, fill: true } }).setOrigin(0.5); banner.add([bg, txt]); banner.setDepth(9999); this.add.existing(banner); // Animation: Drop Down -> Wait -> Slide Up this.tweens.add({ targets: banner, y: 100, duration: 1000, ease: 'Bounce.out', onComplete: () => { this.time.delayedCall(4000, () => { this.tweens.add({ targets: banner, y: -150, duration: 800, ease: 'Back.in' }); }); } }); } startVirusFog() { console.log('☣️ VIRUS FOG & METER STARTED'); // METER UI this.virusMeterBox = this.add.container(this.cameras.main.width - 250, 40).setScrollFactor(0).setDepth(9000); const bg = this.add.rectangle(0, 0, 220, 24, 0x000000, 0.8).setOrigin(0, 0.5).setStrokeStyle(1, 0xffffff, 0.5); const barBg = this.add.rectangle(10, 0, 200, 10, 0x333333).setOrigin(0, 0.5); const barFill = this.add.rectangle(10, 0, 0, 10, 0x2ecc71).setOrigin(0, 0.5); // Green const icon = this.add.text(-20, 0, "☣️", { fontSize: '20px' }).setOrigin(0.5); const label = this.add.text(10, -20, "VIRUS EXPOSURE", { fontFamily: 'Verdana', fontSize: '10px', color: '#2ecc71' }).setOrigin(0, 0.5); this.virusMeterBox.add([bg, barBg, barFill, icon, label]); this.virusBar = barFill; // FOG LOGIC (Accumulation) this.virusLevel = 0; this.time.addEvent({ delay: 100, loop: true, callback: () => { // Determine if exposed (simple logic: always exposed on meadow) const isExposed = true; if (isExposed) { this.virusLevel += 0.05; // Slow buildup if (this.virusLevel > 100) this.virusLevel = 100; // Update UI this.virusBar.width = (this.virusLevel / 100) * 200; // Update Screen Tint (Green Fog) const tintFactor = this.virusLevel / 200; // max 0.5 alpha this.cameras.main.setBackgroundColor(Phaser.Display.Color.Interpolate.ColorWithColor( new Phaser.Display.Color(0, 0, 0), new Phaser.Display.Color(46, 204, 113), // #2ecc71 100, this.virusLevel )); // Optional: Add fog overlay sprite here if needed } } }); } handlePlayerMovement() { if (!this.player || !this.player.body) return; const speed = this.keys.SHIFT.isDown ? 300 : 160; this.player.body.setVelocity(0); let moved = false; if (this.cursors.left.isDown) { this.player.body.setVelocityX(-speed); this.player.flipX = true; moved = true; } else if (this.cursors.right.isDown) { this.player.body.setVelocityX(speed); this.player.flipX = false; moved = true; } if (this.cursors.up.isDown) { this.player.body.setVelocityY(-speed); moved = true; } else if (this.cursors.down.isDown) { this.player.body.setVelocityY(speed); moved = true; } if (moved) { this.player.play('kai_run', true); // Ensure animation exists } else { this.player.play('kai_idle', true); // Ensure animation exists } } addStarterCampDecoration(centerX, centerY) { // Placeholder for existing decoration code (simplified for overwrite) console.log('🌲 Decorations placeholder...'); // Add some trees/rocks manually or proceed with empty field for now // (User did not ask for complex map generation in this request) } }