Files
novafarma/EMERGENCY_SYSTEMS_RECOVERY/CropGrowthSeasonSystem.js
2026-01-16 02:43:46 +01:00

343 lines
9.6 KiB
JavaScript

/**
* 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;
}