diff --git a/src/systems/TimeSystem.js b/src/systems/TimeSystem.js new file mode 100644 index 0000000..22c54bc --- /dev/null +++ b/src/systems/TimeSystem.js @@ -0,0 +1,447 @@ +/** + * TimeSystem.js + * ============= + * KRVAVA Ε½ETEV - Complete Day/Night Cycle System (Phase 18) + * + * Features: + * - 25-minute days (4 time periods) + * - Dynamic lighting system + * - Time-based gameplay mechanics + * - Sleep system with collapse + * - Morning/Night bonuses + * - Werewolf spawns at night + * + * @author NovaFarma Team + * @date 2025-12-23 + */ + +export default class TimeSystem { + constructor(scene) { + this.scene = scene; + + // Time configuration + this.dayLength = 25 * 60 * 1000; // 25 minutes in ms + this.currentTime = 6 * 60; // Start at 6:00 AM (in minutes) + this.totalMinutes = 24 * 60; // 1440 minutes in a day + + // Time periods (in hours) + this.timePeriods = { + morning: { start: 6, end: 12, name: 'Morning', icon: 'πŸŒ…' }, + day: { start: 12, end: 18, name: 'Day', icon: 'β˜€οΈ' }, + evening: { start: 18, end: 21, name: 'Evening', icon: 'πŸŒ†' }, + night: { start: 21, end: 6, name: 'Night', icon: 'πŸŒ™' } + }; + + // Game state + this.dayNumber = 1; + this.season = 'spring'; // 'spring', 'summer', 'fall', 'winter' + this.isPaused = false; + + // Sleep system + this.playerEnergy = 100; + this.lastSleptTime = 0; + this.hoursAwake = 0; + this.collapseWarningShown = false; + + // Lighting + this.ambientLight = null; + this.currentLightColor = 0xFFFFFF; + + // Gameplay modifiers + this.zombieEfficiency = 1.0; + this.hostileSpawnRate = 1.0; + this.werewolfActive = false; + + console.log('⏰ TimeSystem initialized'); + + // Start time progression + this.startTime(); + } + + /** + * Start time progression + */ + startTime() { + // Time progression (1 real second = 0.576 game minutes) + this.timeInterval = setInterval(() => { + if (!this.isPaused) { + this.updateTime(1000); // Update every second + } + }, 1000); + + console.log('⏰ Time started at 6:00 AM, Day 1'); + } + + /** + * Update time + */ + updateTime(deltaMs) { + // Calculate game minutes passed + const gameMinutesPassed = (deltaMs / this.dayLength) * this.totalMinutes; + + this.currentTime += gameMinutesPassed; + this.hoursAwake += gameMinutesPassed / 60; + + // Check for new day + if (this.currentTime >= this.totalMinutes) { + this.newDay(); + } + + // Update systems + this.updateLighting(); + this.updateGameplayModifiers(); + this.checkSleepDeprivation(); + } + + /** + * New day + */ + newDay() { + this.currentTime = this.currentTime % this.totalMinutes; + this.dayNumber++; + + console.log(`πŸŒ… Day ${this.dayNumber} begins!`); + + // Check season change (every 28 days) + if (this.dayNumber % 28 === 0) { + this.changeSeason(); + } + + this.showNotification({ + title: `Day ${this.dayNumber}`, + text: `πŸŒ… ${this.getCurrentPeriod().name} - ${this.season}`, + icon: 'πŸ“…' + }); + } + + /** + * Change season + */ + changeSeason() { + const seasons = ['spring', 'summer', 'fall', 'winter']; + const currentIndex = seasons.indexOf(this.season); + this.season = seasons[(currentIndex + 1) % 4]; + + console.log(`πŸ‚ Season changed to: ${this.season}`); + + this.showNotification({ + title: 'Season Changed!', + text: `πŸ‚ Now: ${this.season.toUpperCase()}`, + icon: 'πŸ“…' + }); + } + + /** + * Get current time period + */ + getCurrentPeriod() { + const hour = Math.floor(this.currentTime / 60); + + if (hour >= 6 && hour < 12) return this.timePeriods.morning; + if (hour >= 12 && hour < 18) return this.timePeriods.day; + if (hour >= 18 && hour < 21) return this.timePeriods.evening; + return this.timePeriods.night; + } + + /** + * Update lighting + */ + updateLighting() { + const period = this.getCurrentPeriod(); + let targetColor; + + switch (period.name) { + case 'Morning': + targetColor = 0xFFE4B5; // Moccasin (warm morning light) + break; + case 'Day': + targetColor = 0xFFFFFF; // Full white + break; + case 'Evening': + targetColor = 0xFFA500; // Orange (sunset) + break; + case 'Night': + targetColor = 0x191970; // Midnight blue + break; + } + + // Smooth transition + if (this.currentLightColor !== targetColor) { + this.currentLightColor = targetColor; + this.applyLighting(targetColor); + } + } + + /** + * Apply lighting to scene + */ + applyLighting(color) { + // TODO: Apply to actual scene + // this.scene.cameras.main.setTint(color); + console.log(`πŸ’‘ Lighting changed: ${color.toString(16)}`); + } + + /** + * Update gameplay modifiers + */ + updateGameplayModifiers() { + const period = this.getCurrentPeriod(); + const hour = Math.floor(this.currentTime / 60); + + // Morning bonus (6:00 - 12:00) + if (period.name === 'Morning') { + this.zombieEfficiency = 1.2; // +20% + this.hostileSpawnRate = 0.5; // 50% reduction + this.werewolfActive = false; + } + // Day (12:00 - 18:00) + else if (period.name === 'Day') { + this.zombieEfficiency = 1.0; + this.hostileSpawnRate = 1.0; + this.werewolfActive = false; + } + // Evening (18:00 - 21:00) + else if (period.name === 'Evening') { + this.zombieEfficiency = 0.9; + this.hostileSpawnRate = 1.5; + this.werewolfActive = false; + } + // Night (21:00 - 6:00) + else { + this.zombieEfficiency = 0.7; // -30% + this.hostileSpawnRate = 2.0; // 2x spawns! + this.werewolfActive = true; + + // Werewolf spawn chance + if (Math.random() < 0.01) { // 1% per update + this.spawnWerewolf(); + } + } + } + + /** + * Spawn werewolf + */ + spawnWerewolf() { + console.log('🐺 Werewolf spawned!'); + + this.showNotification({ + title: 'WEREWOLF!', + text: '🐺 Dangerous creature appeared!', + icon: '⚠️' + }); + + // TODO: Actual werewolf spawn + } + + /** + * Check sleep deprivation + */ + checkSleepDeprivation() { + const hour = Math.floor(this.currentTime / 60); + + // Energy decreases based on hours awake + if (this.hoursAwake > 16) { + this.playerEnergy = Math.max(0, 100 - ((this.hoursAwake - 16) * 10)); + } + + // Warning at 1:00 AM if still awake + if (hour === 1 && !this.collapseWarningShown) { + this.collapseWarningShown = true; + + this.showNotification({ + title: 'EXHAUSTED!', + text: '😴 You need sleep! Will collapse at 2 AM!', + icon: '⚠️' + }); + } + + // Force collapse at 2:00 AM + if (hour === 2 && this.hoursAwake > 20) { + this.forceCollapse(); + } + } + + /** + * Sleep in bed + */ + sleep() { + console.log('😴 Going to sleep...'); + + // Calculate sleep duration (sleep until 6 AM) + const hour = Math.floor(this.currentTime / 60); + let hoursToSleep; + + if (hour >= 6) { + // Sleep until tomorrow's 6 AM + hoursToSleep = (30 - hour); // Hours until midnight + 6 + } else { + // Sleep until today's 6 AM + hoursToSleep = 6 - hour; + } + + // Advance time + this.currentTime += hoursToSleep * 60; + if (this.currentTime >= this.totalMinutes) { + this.newDay(); + } + + // Restore energy + this.playerEnergy = 100; + this.hoursAwake = 0; + this.lastSleptTime = this.dayNumber; + this.collapseWarningShown = false; + + // Save game + this.saveGame(); + + console.log(`😴 Slept for ${hoursToSleep} hours. Energy restored!`); + + this.showNotification({ + title: 'Well Rested!', + text: `😴 Slept ${hoursToSleep} hours. Day ${this.dayNumber}`, + icon: '✨' + }); + + return true; + } + + /** + * Force collapse (didn't sleep) + */ + forceCollapse() { + console.log('πŸ’€ Collapsed from exhaustion!'); + + this.showNotification({ + title: 'COLLAPSED!', + text: 'πŸ’€ You passed out from exhaustion!', + icon: '⚠️' + }); + + // Lose some items/money as penalty + // TODO: Apply penalties + + // Force sleep + this.sleep(); + } + + /** + * Save game + */ + saveGame() { + try { + const saveData = { + time: this.currentTime, + day: this.dayNumber, + season: this.season, + energy: this.playerEnergy + }; + + localStorage.setItem('krvava_zetev_time', JSON.stringify(saveData)); + console.log('πŸ’Ύ Game saved (sleep)'); + } catch (error) { + console.error('Failed to save game:', error); + } + } + + /** + * Load game + */ + loadGame() { + try { + const saved = localStorage.getItem('krvava_zetev_time'); + if (saved) { + const data = JSON.parse(saved); + this.currentTime = data.time; + this.dayNumber = data.day; + this.season = data.season; + this.playerEnergy = data.energy; + + console.log(`πŸ“₯ Game loaded: Day ${this.dayNumber}, ${this.getTimeString()}`); + return true; + } + } catch (error) { + console.error('Failed to load game:', error); + } + return false; + } + + /** + * Get time as string + */ + getTimeString() { + const totalMinutes = Math.floor(this.currentTime); + const hours = Math.floor(totalMinutes / 60) % 24; + const minutes = totalMinutes % 60; + + const period = hours >= 12 ? 'PM' : 'AM'; + const displayHours = hours % 12 || 12; + + return `${displayHours}:${minutes.toString().padStart(2, '0')} ${period}`; + } + + /** + * Get current info + */ + getTimeInfo() { + const period = this.getCurrentPeriod(); + + return { + time: this.getTimeString(), + day: this.dayNumber, + season: this.season, + period: period.name, + periodIcon: period.icon, + energy: this.playerEnergy, + hoursAwake: Math.floor(this.hoursAwake), + zombieEfficiency: this.zombieEfficiency, + hostileSpawnRate: this.hostileSpawnRate, + werewolfActive: this.werewolfActive + }; + } + + /** + * Pause time + */ + pauseTime() { + this.isPaused = true; + console.log('⏸️ Time paused'); + } + + /** + * Resume time + */ + resumeTime() { + this.isPaused = false; + console.log('▢️ Time resumed'); + } + + /** + * Set time (for testing) + */ + setTime(hour, minute = 0) { + this.currentTime = (hour * 60) + minute; + console.log(`⏰ Time set to ${this.getTimeString()}`); + } + + /** + * Cleanup + */ + destroy() { + if (this.timeInterval) { + clearInterval(this.timeInterval); + } + } + + /** + * Helper: Show notification + */ + showNotification(notification) { + console.log(`πŸ“’ ${notification.icon} ${notification.title}: ${notification.text}`); + + const ui = this.scene.scene.get('UIScene'); + if (ui && ui.showNotification) { + ui.showNotification(notification); + } + } +}