/** * CROP GROWTH & SEASON SYSTEM * Manages dynamic crop growth through 8 stages + 4 seasonal variations * Integrates with Faza 1 crop sprites (corn, tomatoes, carrots, potatoes, lettuce, pumpkin) */ class CropGrowthSeasonSystem { constructor(scene) { this.scene = scene; // Growth system constants this.GROWTH_STAGES = 8; this.SEASONS = ['spring', 'summer', 'fall', 'winter']; // Active crops in world this.crops = new Map(); // cropId -> {type, stage, season, sprite, growthTimer} // Growth rates (minutes per stage in real time) this.growthRates = { corn: 5, tomatoes: 4, carrots: 3, potatoes: 4, lettuce: 2, pumpkin: 6 }; // Seasonal color tints (applied to environment, NOT crops) this.seasonalTints = { spring: 0x8BC34A, // Fresh green summer: 0xFFC107, // Bright yellow-gold fall: 0xFF9800, // Orange-amber winter: 0x2196F3 // Cool blue }; // Current season (synced with TimeSystem) this.currentSeason = 'spring'; // Environment layer (sky/ambient tint) this.environmentTint = null; } /** * Initialize system */ init() { // Create environment tint overlay this.createEnvironmentTint(); // Subscribe to season changes from TimeSystem if (this.scene.time_system) { this.scene.events.on('seasonChanged', this.onSeasonChange, this); } console.log('🌱 CropGrowthSeasonSystem initialized'); } /** * Create environment tint overlay for seasonal color shifts */ createEnvironmentTint() { // Create semi-transparent overlay const width = this.scene.cameras.main.width; const height = this.scene.cameras.main.height; this.environmentTint = this.scene.add.rectangle( width / 2, height / 2, width * 2, // Make it larger to cover camera movement height * 2, this.seasonalTints[this.currentSeason], 0.15 // 15% opacity ); this.environmentTint.setScrollFactor(1); // Moves with camera this.environmentTint.setDepth(1000); // Above most objects this.environmentTint.setBlendMode(Phaser.BlendModes.MULTIPLY); } /** * Handle season change */ onSeasonChange(newSeason) { console.log(`🍂 Season changing to: ${newSeason}`); this.currentSeason = newSeason; // Animate environment tint transition if (this.environmentTint) { this.scene.tweens.add({ targets: this.environmentTint, tint: this.seasonalTints[newSeason], duration: 2000, ease: 'Sine.easeInOut' }); } // Update all existing crops to new season sprites this.updateAllCropsForSeason(newSeason); } /** * Plant a crop */ plantCrop(x, y, cropType) { const cropId = `crop_${Date.now()}_${Math.random()}`; // Load sprite for current season, stage 1 const spritePath = this.getCropSpritePath(cropType, this.currentSeason, 1); // Create sprite const sprite = this.scene.add.sprite(x, y, spritePath); sprite.setDepth(2); // Above ground // Store crop data this.crops.set(cropId, { id: cropId, type: cropType, stage: 1, season: this.currentSeason, sprite: sprite, growthTimer: 0, x: x, y: y }); console.log(`🌱 Planted ${cropType} at ${x},${y}`); return cropId; } /** * Get crop sprite path based on type, season, and stage */ getCropSpritePath(cropType, season, stage) { // Path: assets/crops/faza1/{type}/{season}/stage{N}.png return `crops/faza1/${this.normalizeCropName(cropType)}/${season}/stage${stage}`; } /** * Normalize crop names to match folder structure */ normalizeCropName(cropType) { const nameMap = { 'tomatoes': 'tomatoes', 'tomato': 'tomatoes', 'carrots': 'carrots', 'carrot': 'carrots', 'potatoes': 'potatos', // Note: folder is 'potatos' not 'potatoes' 'potato': 'potatos', 'lettuce': 'lettuces', 'pumpkin': 'pumpkins', 'corn': 'corn' }; return nameMap[cropType.toLowerCase()] || cropType.toLowerCase(); } /** * Update crop growth (called every frame or fixed interval) */ update(deltaTime) { for (const [cropId, crop] of this.crops.entries()) { // Don't grow if already at max stage or dead if (crop.stage >= this.GROWTH_STAGES) { continue; } // Increment growth timer crop.growthTimer += deltaTime / 1000; // Convert to seconds // Check if it's time to advance stage const growthRate = this.growthRates[crop.type] || 5; const secondsPerStage = growthRate * 60; // Convert to seconds if (crop.growthTimer >= secondsPerStage) { this.advanceCropStage(cropId); crop.growthTimer = 0; // Reset timer } } } /** * Advance crop to next growth stage */ advanceCropStage(cropId) { const crop = this.crops.get(cropId); if (!crop) return; // Advance stage crop.stage = Math.min(crop.stage + 1, this.GROWTH_STAGES); // Update sprite const newSpritePath = this.getCropSpritePath(crop.type, crop.season, crop.stage); crop.sprite.setTexture(newSpritePath); console.log(`🌾 ${crop.type} advanced to stage ${crop.stage}`); // Special events if (crop.stage === 6) { // HARVEST READY this.scene.events.emit('cropReady', { cropId, crop }); // Add visual indicator (glow effect) this.addHarvestGlow(crop.sprite); } if (crop.stage === 7) { console.warn(`⚠️ ${crop.type} is overripe! Harvest soon or it will die.`); } if (crop.stage === 8) { console.log(`💀 ${crop.type} has died.`); // Crop is now dead (stage 8) } } /** * Add glow effect to harvest-ready crops */ addHarvestGlow(sprite) { // Pulsing glow animation this.scene.tweens.add({ targets: sprite, alpha: 0.7, duration: 800, yoyo: true, repeat: -1, ease: 'Sine.easeInOut' }); } /** * Harvest a crop */ harvestCrop(cropId) { const crop = this.crops.get(cropId); if (!crop) return null; // Can only harvest at stage 6 (perfect) or 5-7 (acceptable) if (crop.stage < 5 || crop.stage === 8) { console.warn(`Cannot harvest ${crop.type} at stage ${crop.stage}`); return null; } // Calculate yield based on stage let yield_quality = 1.0; if (crop.stage === 6) { yield_quality = 1.5; // Perfect harvest bonus } else if (crop.stage === 7) { yield_quality = 0.7; // Overripe penalty } // Remove crop crop.sprite.destroy(); this.crops.delete(cropId); console.log(`✅ Harvested ${crop.type} with ${yield_quality}x quality`); return { type: crop.type, quality: yield_quality, stage: crop.stage }; } /** * Update all crops when season changes */ updateAllCropsForSeason(newSeason) { for (const [cropId, crop] of this.crops.entries()) { crop.season = newSeason; // Update sprite to new season const newSpritePath = this.getCropSpritePath(crop.type, newSeason, crop.stage); crop.sprite.setTexture(newSpritePath); } console.log(`🍂 Updated ${this.crops.size} crops for ${newSeason}`); } /** * Get crop info */ getCropInfo(cropId) { return this.crops.get(cropId); } /** * Save system state */ save() { const cropsData = []; for (const [cropId, crop] of this.crops.entries()) { cropsData.push({ id: cropId, type: crop.type, stage: crop.stage, season: crop.season, growthTimer: crop.growthTimer, x: crop.x, y: crop.y }); } return { currentSeason: this.currentSeason, crops: cropsData }; } /** * Load system state */ load(data) { if (data.currentSeason) { this.currentSeason = data.currentSeason; this.onSeasonChange(this.currentSeason); } if (data.crops) { // Recreate crops for (const cropData of data.crops) { const spritePath = this.getCropSpritePath(cropData.type, cropData.season, cropData.stage); const sprite = this.scene.add.sprite(cropData.x, cropData.y, spritePath); sprite.setDepth(2); this.crops.set(cropData.id, { ...cropData, sprite: sprite }); } } console.log(`📂 Loaded ${this.crops.size} crops`); } } // Export for use in GameScene if (typeof module !== 'undefined' && module.exports) { module.exports = CropGrowthSeasonSystem; }