/** * VISUAL ENHANCEMENT SYSTEM * Central system for managing visual effects, animations, and polish */ class VisualEnhancementSystem { constructor(scene) { this.scene = scene; this.enabled = true; // Sub-systems this.animatedTextures = new Map(); this.weatherEffects = []; this.lightSources = []; this.shadows = []; this.particles = []; // Settings this.settings = { animatedTextures: true, weatherEffects: true, dynamicLighting: true, shadows: true, fogOfWar: false, particleQuality: 'high', // low, medium, high, ultra animationQuality: 'high', screenShake: true, transitions: true }; // Animation timers this.waterAnimTime = 0; this.treeAnimTime = 0; this.fireAnimTime = 0; this.loadSettings(); this.init(); console.log('✅ Visual Enhancement System initialized'); } init() { this.initAnimatedTextures(); this.initWeatherEffects(); this.initLightingSystem(); this.initShadowSystem(); this.initParticleSystem(); } // ========== ANIMATED TEXTURES ========== initAnimatedTextures() { if (!this.settings.animatedTextures) return; // Create water animation frames this.createWaterAnimation(); // Create fire animation this.createFireAnimation(); // Create tree leaf animation this.createTreeAnimation(); console.log('🎬 Animated textures initialized'); } createWaterAnimation() { // Water flow animation (4 frames) const frames = []; for (let i = 0; i < 4; i++) { const graphics = this.scene.add.graphics(); graphics.fillStyle(0x4488ff, 1); graphics.fillRect(0, 0, 64, 64); // Add wave pattern graphics.lineStyle(2, 0x6699ff, 0.5); for (let y = 0; y < 64; y += 8) { const offset = Math.sin((y + i * 16) * 0.1) * 4; graphics.lineBetween(0, y + offset, 64, y + offset); } graphics.generateTexture('water_anim_' + i, 64, 64); graphics.destroy(); frames.push('water_anim_' + i); } this.animatedTextures.set('water', { frames, currentFrame: 0, speed: 200 // ms per frame }); } createFireAnimation() { // Fire flickering (3 frames) const frames = []; const colors = [0xff6600, 0xff8800, 0xffaa00]; for (let i = 0; i < 3; i++) { const graphics = this.scene.add.graphics(); graphics.fillStyle(colors[i], 1); graphics.fillCircle(16, 16, 12 + i * 2); graphics.generateTexture('fire_anim_' + i, 32, 32); graphics.destroy(); frames.push('fire_anim_' + i); } this.animatedTextures.set('fire', { frames, currentFrame: 0, speed: 150 }); } createTreeAnimation() { // Tree leaf rustling (subtle movement) console.log('🌳 Tree animation ready'); } updateAnimatedTextures(delta) { if (!this.settings.animatedTextures) return; this.waterAnimTime += delta; this.fireAnimTime += delta; // Update water const water = this.animatedTextures.get('water'); if (water && this.waterAnimTime > water.speed) { water.currentFrame = (water.currentFrame + 1) % water.frames.length; this.waterAnimTime = 0; } // Update fire const fire = this.animatedTextures.get('fire'); if (fire && this.fireAnimTime > fire.speed) { fire.currentFrame = (fire.currentFrame + 1) % fire.frames.length; this.fireAnimTime = 0; } } // ========== WEATHER EFFECTS ========== initWeatherEffects() { if (!this.settings.weatherEffects) return; console.log('🌦️ Weather effects initialized'); } createSnowEffect() { const emitter = this.scene.add.particles(0, 0, 'particle_white', { x: { min: 0, max: this.scene.cameras.main.width }, y: -10, speedY: { min: 50, max: 100 }, speedX: { min: -20, max: 20 }, scale: { min: 0.3, max: 0.8 }, alpha: { min: 0.5, max: 1 }, lifespan: 10000, frequency: 50, quantity: 2 }); emitter.setScrollFactor(0); this.weatherEffects.push(emitter); return emitter; } createRainEffect() { const emitter = this.scene.add.particles(0, 0, 'particle_white', { x: { min: 0, max: this.scene.cameras.main.width }, y: -10, speedY: { min: 400, max: 600 }, speedX: { min: -50, max: -30 }, scaleX: 0.1, scaleY: 0.5, alpha: 0.6, lifespan: 2000, frequency: 10, quantity: 5, tint: 0x88ccff }); emitter.setScrollFactor(0); this.weatherEffects.push(emitter); return emitter; } createLightningFlash() { const flash = this.scene.add.rectangle( this.scene.cameras.main.centerX, this.scene.cameras.main.centerY, this.scene.cameras.main.width, this.scene.cameras.main.height, 0xffffff, 0.8 ); flash.setScrollFactor(0); flash.setDepth(10000); this.scene.tweens.add({ targets: flash, alpha: 0, duration: 200, onComplete: () => flash.destroy() }); } createFogEffect() { // Atmospheric fog overlay - covers entire screen const fogOverlay = this.scene.add.graphics(); fogOverlay.setScrollFactor(0); fogOverlay.setDepth(8000); // Above game, below UI fogOverlay.setAlpha(0.4); // Semi-transparent // Create fog particles for movement effect const fogParticles = this.scene.add.particles(0, 0, 'particle_white', { x: { min: 0, max: this.scene.cameras.main.width }, y: { min: 0, max: this.scene.cameras.main.height }, speedX: { min: -10, max: 10 }, speedY: { min: -5, max: 5 }, scale: { min: 2, max: 4 }, alpha: { min: 0.1, max: 0.3 }, lifespan: 10000, frequency: 100, quantity: 3, tint: 0xcccccc, blendMode: 'SCREEN' }); fogParticles.setScrollFactor(0); fogParticles.setDepth(8001); // Animated fog overlay let fogTime = 0; const updateFog = () => { fogTime += 0.01; fogOverlay.clear(); const cam = this.scene.cameras.main; // Draw multiple layers of fog for depth for (let layer = 0; layer < 3; layer++) { const offset = Math.sin(fogTime + layer) * 50; const alpha = 0.1 + layer * 0.05; fogOverlay.fillStyle(0xffffff, alpha); // Draw wavy fog shapes for (let i = 0; i < 5; i++) { const x = (i * cam.width / 4) + offset; const y = (layer * 100) + Math.cos(fogTime + i) * 30; fogOverlay.fillCircle(x, y, 200 + layer * 50); } } }; // Update fog animation every frame this.scene.events.on('update', updateFog); this.weatherEffects.push({ overlay: fogOverlay, particles: fogParticles, update: updateFog, destroy: () => { fogOverlay.destroy(); fogParticles.destroy(); this.scene.events.off('update', updateFog); } }); console.log('🌫️ Atmospheric fog effect created'); return { overlay: fogOverlay, particles: fogParticles }; } // ========== LIGHTING SYSTEM ========== initLightingSystem() { if (!this.settings.dynamicLighting) return; this.lightingLayer = this.scene.add.layer(); this.lightingLayer.setDepth(5000); console.log('💡 Lighting system initialized'); } addLight(x, y, radius = 100, color = 0xffaa00, intensity = 0.6) { if (!this.settings.dynamicLighting) return null; // Create radial gradient light const light = this.scene.add.graphics(); const gradient = light.createRadialGradient( radius, radius, 0, radius, radius, radius ); gradient.addColorStop(0, `rgba(${(color >> 16) & 0xff}, ${(color >> 8) & 0xff}, ${color & 0xff}, ${intensity})`); gradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); light.fillStyle(color, intensity); light.fillCircle(radius, radius, radius); light.setPosition(x - radius, y - radius); light.setBlendMode(Phaser.BlendModes.ADD); light.setDepth(5001); const lightObj = { graphics: light, x, y, radius, color, intensity, flickering: false }; this.lightSources.push(lightObj); return lightObj; } addTorch(x, y) { const torch = this.addLight(x, y, 80, 0xff6600, 0.5); if (torch) { torch.flickering = true; } return torch; } updateLighting(delta) { if (!this.settings.dynamicLighting) return; // Update flickering lights for (const light of this.lightSources) { if (light.flickering) { const flicker = 0.4 + Math.random() * 0.2; light.graphics.setAlpha(flicker); } } // Update ambient lighting based on time of day if (this.scene.weatherSystem) { const time = this.scene.weatherSystem.gameTime; const isNight = time < 6 || time > 18; if (isNight) { // Darker at night this.scene.cameras.main.setAlpha(0.7); } else { this.scene.cameras.main.setAlpha(1.0); } } } // ========== SHADOW SYSTEM ========== initShadowSystem() { if (!this.settings.shadows) return; console.log('🌑 Shadow system initialized'); } addShadow(entity, offsetX = 0, offsetY = 10, width = 40, height = 15) { if (!this.settings.shadows) return null; const shadow = this.scene.add.ellipse( entity.x + offsetX, entity.y + offsetY, width, height, 0x000000, 0.3 ); shadow.setDepth(0); const shadowObj = { entity, shadow, offsetX, offsetY }; this.shadows.push(shadowObj); return shadow; } updateShadows() { if (!this.settings.shadows) return; // Get time of day for shadow opacity let opacity = 0.3; if (this.scene.weatherSystem) { const time = this.scene.weatherSystem.gameTime; // Darker shadows at noon, lighter at dawn/dusk opacity = 0.2 + Math.abs(Math.sin((time / 24) * Math.PI * 2)) * 0.3; } // Update shadow positions for (const { entity, shadow, offsetX, offsetY } of this.shadows) { if (entity.sprite) { shadow.x = entity.sprite.x + offsetX; shadow.y = entity.sprite.y + offsetY; shadow.setAlpha(opacity); } } } // ========== PARTICLE SYSTEM ========== initParticleSystem() { // Create particle textures this.createParticleTextures(); console.log('✨ Particle system initialized'); } createParticleTextures() { // White particle const white = this.scene.add.graphics(); white.fillStyle(0xffffff, 1); white.fillCircle(4, 4, 4); white.generateTexture('particle_white', 8, 8); white.destroy(); // Sparkle const sparkle = this.scene.add.graphics(); sparkle.fillStyle(0xffff00, 1); sparkle.fillCircle(3, 3, 3); sparkle.generateTexture('particle_sparkle', 6, 6); sparkle.destroy(); // Heart const heart = this.scene.add.graphics(); heart.fillStyle(0xff0066, 1); heart.fillCircle(3, 3, 3); heart.fillCircle(5, 3, 3); heart.fillTriangle(1, 4, 7, 4, 4, 8); heart.generateTexture('particle_heart', 8, 8); heart.destroy(); } createHeartParticles(x, y) { const emitter = this.scene.add.particles(x, y, 'particle_heart', { speed: { min: 20, max: 50 }, angle: { min: -120, max: -60 }, scale: { start: 1, end: 0 }, alpha: { start: 1, end: 0 }, lifespan: 1000, quantity: 5, blendMode: 'ADD' }); this.scene.time.delayedCall(1000, () => emitter.destroy()); return emitter; } createSparkleEffect(x, y) { const emitter = this.scene.add.particles(x, y, 'particle_sparkle', { speed: { min: 10, max: 30 }, scale: { start: 1, end: 0 }, alpha: { start: 1, end: 0 }, lifespan: 800, quantity: 10, blendMode: 'ADD' }); this.scene.time.delayedCall(800, () => emitter.destroy()); return emitter; } createCheckmarkEffect(x, y) { const checkmark = this.scene.add.text(x, y, '✓', { fontSize: '32px', color: '#00ff00', fontStyle: 'bold' }); checkmark.setOrigin(0.5); checkmark.setDepth(10000); this.scene.tweens.add({ targets: checkmark, y: y - 50, alpha: 0, scale: 2, duration: 1000, ease: 'Power2', onComplete: () => checkmark.destroy() }); } // ========== SCREEN EFFECTS ========== screenShake(intensity = 10, duration = 300) { if (!this.settings.screenShake) return; this.scene.cameras.main.shake(duration, intensity / 1000); } screenFlash(color = 0xffffff, duration = 200) { this.scene.cameras.main.flash(duration, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff ); } fadeOut(duration = 500, callback) { if (!this.settings.transitions) { if (callback) callback(); return; } this.scene.cameras.main.fadeOut(duration, 0, 0, 0); if (callback) { this.scene.cameras.main.once('camerafadeoutcomplete', callback); } } fadeIn(duration = 500) { if (!this.settings.transitions) return; this.scene.cameras.main.fadeIn(duration, 0, 0, 0); } // ========== BUILDING EFFECTS ========== createConstructionEffect(x, y) { // Dust particles during construction const emitter = this.scene.add.particles(x, y, 'particle_white', { speed: { min: 20, max: 40 }, scale: { start: 0.5, end: 0 }, alpha: { start: 0.5, end: 0 }, lifespan: 1000, quantity: 3, frequency: 100, tint: 0x996633 }); return emitter; } createSmokeEffect(x, y) { // Chimney smoke const emitter = this.scene.add.particles(x, y, 'particle_white', { speedY: { min: -30, max: -50 }, speedX: { min: -10, max: 10 }, scale: { start: 0.3, end: 1 }, alpha: { start: 0.5, end: 0 }, lifespan: 2000, frequency: 500, quantity: 1, tint: 0x888888 }); return emitter; } // ========== FARM AUTOMATION VISUALS ========== createPowerGridEffect(x1, y1, x2, y2) { // Electric arc between power sources const graphics = this.scene.add.graphics(); graphics.lineStyle(2, 0x00ffff, 0.8); // Draw lightning-like connection const steps = 5; const points = []; for (let i = 0; i <= steps; i++) { const t = i / steps; const x = x1 + (x2 - x1) * t + (Math.random() - 0.5) * 10; const y = y1 + (y2 - y1) * t + (Math.random() - 0.5) * 10; points.push({ x, y }); } graphics.beginPath(); graphics.moveTo(points[0].x, points[0].y); for (let i = 1; i < points.length; i++) { graphics.lineTo(points[i].x, points[i].y); } graphics.strokePath(); // Fade out this.scene.tweens.add({ targets: graphics, alpha: 0, duration: 200, onComplete: () => graphics.destroy() }); } createMutantGlow(entity, color = 0x00ff00) { // Radioactive glow for mutants const glow = this.scene.add.circle( entity.x, entity.y, 30, color, 0.3 ); glow.setBlendMode(Phaser.BlendModes.ADD); glow.setDepth(entity.depth - 1); // Pulsing animation this.scene.tweens.add({ targets: glow, scale: { from: 1, to: 1.2 }, alpha: { from: 0.3, to: 0.1 }, duration: 1000, yoyo: true, repeat: -1 }); return glow; } // ========== UPDATE ========== update(delta) { this.updateAnimatedTextures(delta); this.updateLighting(delta); this.updateShadows(); } // ========== SETTINGS ========== saveSettings() { localStorage.setItem('novafarma_visual_enhancements', JSON.stringify(this.settings)); } loadSettings() { const saved = localStorage.getItem('novafarma_visual_enhancements'); if (saved) { this.settings = { ...this.settings, ...JSON.parse(saved) }; } } destroy() { if (this.lightingLayer) this.lightingLayer.destroy(); for (const { shadow } of this.shadows) { shadow.destroy(); } for (const effect of this.weatherEffects) { effect.destroy(); } console.log('✨ Visual Enhancement System destroyed'); } }