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)
265 lines
7.8 KiB
JavaScript
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));
|
|
}
|
|
});
|
|
}
|
|
}
|