Files
novafarma/src/systems/FarmingSystem.js
NovaFarma Dev 8c0cc90908 PART 3: POLISH & EFFECTS - 100% COMPLETE! (Phase 29)
COMPLETED FEATURES:

PART 1: IMMEDIATE INTEGRATION (30 min)
-  Crafting system integration verified
-  Created comprehensive test plans
-  INTEGRATION_TEST_PLAN.md
-  QUICK_START_TEST.md

PART 3: POLISH & EFFECTS (2h 5min) - 100% DONE!

Phase 5C: Lighting & Shadows (20 min)
-  LightingSystem.js (215 lines)
- Dynamic player shadow with time-of-day opacity
- Auto-torch at night (flickering effect)
- Campfire creation API
- Light source management

Phase 5B: Enhanced Weather (25 min)
-  WeatherEnhancementsSystem.js (245 lines)
- Dynamic wind system (strength + direction)
- Wind affects rain particles
- Tree sway animations
- Smooth weather transitions (2s fade)
- Wind info API (speed km/h, compass)

Phase 5D: UI Polish (20 min)
-  UIPolishSystem.js (330 lines)
- Fade in/out & slide animations
- Button hover effects with sound
- Tooltips (auto + manual, cursor follow)
- Pulse, shake, flash animations
- Typewriter text effect
- Number counter animation
- Smooth scroll support

Phase 5E: Particle Effects (30 min)
-  ParticleEnhancementsSystem.js (450 lines)
- Craft sparkles (golden burst)
- Walk dust clouds (grass/dirt only)
- Harvest bursts (crop-colored!)
- Dig/till soil particles
- Plant sparkles
- Level up / damage / heal effects
- Integrated with CraftingSystem & FarmingSystem

 STATS:
- 4 new systems created (~1,240 lines)
- 5 documentation files
- 30+ new features
- 7 files modified
- Total time: 2h 35min

 GAME NOW HAS:
- Dynamic shadows & lighting
- Wind-affected weather
- Complete UI animation toolkit
- Enhanced particle effects for all actions

Files modified:
- index.html (4 new script tags)
- GameScene.js (4 system initializations + update calls)
- CraftingSystem.js (craft sparkles on completion)
- FarmingSystem.js (dig/plant/harvest particles)
- TASKS.md (Phase 29 updated)
- FINAL_IMPLEMENTATION_ROADMAP.md (PART 3 100% complete)
2025-12-15 16:42:09 +01:00

265 lines
7.8 KiB
JavaScript

class FarmingSystem {
constructor(scene) {
this.scene = scene;
this.crops = []; // Active crops in world
// Crop definitions
this.cropTypes = {
'carrot': {
name: 'Carrot',
growthStages: 4,
daysPerStage: 1,
sellPrice: 10,
seedCost: 5
},
'wheat': {
name: 'Wheat',
growthStages: 4,
daysPerStage: 2,
sellPrice: 15,
seedCost: 8
}
};
}
// Till soil at grid position
tillSoil(gridX, gridY) {
if (!this.scene.terrainSystem) return false;
// 🌱 CHECK MICRO FARM BOUNDARY!
if (this.scene.microFarmSystem && !this.scene.microFarmSystem.isTileUnlocked(gridX, gridY)) {
console.log('❌ Cannot till outside farm boundary!');
// Show error message
if (this.scene.events) {
this.scene.events.emit('show-floating-text', {
x: gridX * 48,
y: gridY * 48,
text: '🚫 Unlock farm first!',
color: '#ff0000'
});
}
return false;
}
// Check if already tilled
const key = `${gridX},${gridY}`;
if (this.isTilled(gridX, gridY)) {
console.log('Already tilled!');
return false;
}
// Mark as tilled in terrain
if (!this.scene.terrainSystem.tilledSoil) {
this.scene.terrainSystem.tilledSoil = new Set();
}
this.scene.terrainSystem.tilledSoil.add(key);
// Visual feedback - place tilled soil sprite
const screenPos = this.scene.iso.toScreen(gridX, gridY);
if (this.scene.textures.exists('soil_tilled')) {
const sprite = this.scene.add.sprite(screenPos.x, screenPos.y, 'soil_tilled');
sprite.setOrigin(0.5, 1);
sprite.setScale(1.0);
sprite.setDepth(this.scene.iso.getDepth(gridX, gridY) - 1); // Below crops
// Store reference
if (!this.scene.terrainSystem.tilledSprites) {
this.scene.terrainSystem.tilledSprites = new Map();
}
this.scene.terrainSystem.tilledSprites.set(key, sprite);
}
// Play dig sound
if (this.scene.soundManager) {
this.scene.soundManager.playDig();
}
// ✨ PARTICLE EFFECT - Dig particles
if (this.scene.particleEnhancements) {
this.scene.particleEnhancements.digParticles(screenPos.x, screenPos.y);
}
console.log(`✅ Tilled soil at (${gridX}, ${gridY})`);
return true;
}
isTilled(gridX, gridY) {
if (!this.scene.terrainSystem || !this.scene.terrainSystem.tilledSoil) return false;
return this.scene.terrainSystem.tilledSoil.has(`${gridX},${gridY}`);
}
// Plant seed
plantSeed(gridX, gridY, cropType) {
if (!this.isTilled(gridX, gridY)) {
console.log('Need to till soil first!');
return false;
}
// Check if already has crop
if (this.getCropAt(gridX, gridY)) {
console.log('Already has a crop!');
return false;
}
// Create crop
const crop = {
gridX,
gridY,
type: cropType,
stage: 0,
daysInStage: 0,
plantedDay: this.scene.timeSystem ? this.scene.timeSystem.day : 0
};
this.crops.push(crop);
// Visual - create sprite
this.updateCropSprite(crop);
// Update farm stats
if (this.scene.farmStats) {
this.scene.farmStats.cropsPlanted++;
}
// Play plant sound
if (this.scene.soundManager) {
this.scene.soundManager.playPlant();
}
// ✨ PARTICLE EFFECT - Plant sparkle
if (this.scene.particleEnhancements) {
const screenPos = this.scene.iso.toScreen(gridX, gridY);
this.scene.particleEnhancements.plantSparkle(screenPos.x, screenPos.y);
}
console.log(`🌱 Planted ${cropType} at (${gridX}, ${gridY})`);
return true;
}
getCropAt(gridX, gridY) {
return this.crops.find(c => c.gridX === gridX && c.gridY === gridY);
}
updateCropSprite(crop) {
const screenPos = this.scene.iso.toScreen(crop.gridX, crop.gridY);
// Remove old sprite
if (crop.sprite) {
crop.sprite.destroy();
}
// Determine texture based on stage
let textureKey = `crop_${crop.type}_stage_${crop.stage}`;
// Fallback textures
if (!this.scene.textures.exists(textureKey)) {
textureKey = 'carrots_stages'; // Use carrot stages as fallback
}
if (this.scene.textures.exists(textureKey)) {
crop.sprite = this.scene.add.sprite(screenPos.x, screenPos.y, textureKey);
crop.sprite.setOrigin(0.5, 1);
crop.sprite.setScale(0.8);
crop.sprite.setDepth(this.scene.iso.getDepth(crop.gridX, crop.gridY));
}
}
// Harvest crop
harvestCrop(gridX, gridY) {
const crop = this.getCropAt(gridX, gridY);
if (!crop) return false;
const cropDef = this.cropTypes[crop.type];
const isRipe = crop.stage >= (cropDef.growthStages - 1);
if (!isRipe) {
console.log('Crop not ready yet!');
return false;
}
// Give items
if (this.scene.inventorySystem) {
this.scene.inventorySystem.addItem(crop.type, 1);
}
// Give gold
const goldEarned = cropDef.sellPrice;
if (this.scene.inventorySystem) {
this.scene.inventorySystem.gold += goldEarned;
}
// Update farm stats
if (this.scene.farmStats) {
this.scene.farmStats.totalHarvested++;
this.scene.farmStats.goldEarned += goldEarned;
}
// Remove crop
if (crop.sprite) crop.sprite.destroy();
this.crops = this.crops.filter(c => c !== crop);
// Play harvest sound
if (this.scene.soundManager) {
this.scene.soundManager.playHarvest();
}
console.log(`🌾 Harvested ${crop.type}! (+${goldEarned} gold)`);
// ✨ PARTICLE EFFECT - Harvest burst
const screenPos = this.scene.iso.toScreen(gridX, gridY);
if (this.scene.particleEnhancements) {
this.scene.particleEnhancements.harvestBurst(screenPos.x, screenPos.y, crop.type);
}
// Show floating text
if (this.scene.events) {
this.scene.events.emit('show-floating-text', {
x: screenPos.x,
y: screenPos.y - 30,
text: `+${goldEarned}g`,
color: '#FFD700'
});
}
return true;
}
// Update - called each game day
updateDay() {
this.crops.forEach(crop => {
const cropDef = this.cropTypes[crop.type];
crop.daysInStage++;
// Advance stage?
if (crop.daysInStage >= cropDef.daysPerStage) {
crop.daysInStage = 0;
crop.stage++;
// Cap at max stage
if (crop.stage >= cropDef.growthStages) {
crop.stage = cropDef.growthStages - 1;
}
// Update visual
this.updateCropSprite(crop);
console.log(`🌱 Crop grew! Stage ${crop.stage}/${cropDef.growthStages - 1}`);
}
});
}
// Update - called each frame
update() {
// Update sprite depths if camera moved
this.crops.forEach(crop => {
if (crop.sprite) {
crop.sprite.setDepth(this.scene.iso.getDepth(crop.gridX, crop.gridY));
}
});
}
}