/** * MicroFarmExpansionSystem.js * ============================ * KRVAVA Ε½ETEV - Micro Farm & Expansion System (Phase 37) * * Features: * - 8x8 starting micro farm * - Expansion system (2x2 tiles at a time) * - Land type mechanics (Grass, Forest, Rocky, Swamp) * - Zombie clearing crews * - Resource costs * - Tutorial integration * * @author NovaFarma Team * @date 2025-12-23 */ export default class MicroFarmExpansionSystem { constructor(scene) { this.scene = scene; // Farm grid (tile-based) this.farmSize = { width: 8, height: 8 }; // Starting size this.maxSize = { width: 64, height: 64 }; // Maximum farm size this.tileSize = 48; // Pixels per tile // Expansion state this.unlockedTiles = new Set(); this.expansionQueue = []; // Land types this.landTypes = new Map(); // Tutorial state this.tutorialComplete = false; this.tutorialStep = 0; console.log('🌾 MicroFarmExpansionSystem initialized'); // Initialize starting farm this.initializeStartingFarm(); // Register land types this.registerLandTypes(); } /** * Initialize 8x8 starting micro farm */ initializeStartingFarm() { const centerX = Math.floor(this.maxSize.width / 2); const centerY = Math.floor(this.maxSize.height / 2); // Unlock center 8x8 area for (let x = centerX - 4; x < centerX + 4; x++) { for (let y = centerY - 4; y < centerY + 4; y++) { const tileKey = `${x},${y}`; this.unlockedTiles.add(tileKey); // Mark as grass (cleared) this.landTypes.set(tileKey, { type: 'grass', cleared: true, fertility: 100 }); } } console.log(`βœ… Micro farm initialized: 8x8 tiles (64 tiles total)`); console.log(` Center: (${centerX}, ${centerY})`); // Show starting area this.visualizeFarm(); // Start tutorial this.startTutorial(); } /** * Register land types */ registerLandTypes() { // Land type definitions const types = { grass: { name: 'Grass', icon: '🌿', clearingRequired: false, clearingCost: { zlatniki: 0 }, fertility: 100 }, forest: { name: 'Forest', icon: '🌲', clearingRequired: true, clearingCost: { zlatniki: 50, wood: 0 }, // Get wood from clearing clearingTask: 'chop_trees', clearingTime: 60, // seconds fertility: 80 }, rocky: { name: 'Rocky', icon: '⛰️', clearingRequired: true, clearingCost: { zlatniki: 100, stone: 0 }, // Get stone from clearing clearingTask: 'mine_rocks', clearingTime: 90, fertility: 50 }, swamp: { name: 'Swamp', icon: 'πŸ’§', clearingRequired: true, clearingCost: { zlatniki: 150 }, clearingTask: 'drain_water', clearingTime: 120, fertility: 90 // High fertility after drainage! } }; console.log(`βœ… Registered ${Object.keys(types).length} land types`); } /** * Expand farm by 2x2 area */ expandFarm(direction) { const expansionSize = 2; // Expand by 2x2 tiles const cost = this.calculateExpansionCost(direction); // Check if player can afford if (!this.canAffordExpansion(cost)) { this.showNotification({ title: 'Cannot Expand', text: `Need ${cost.zlatniki}Ε½, ${cost.wood || 0} Wood, ${cost.stone || 0} Stone`, icon: 'πŸ’°' }); return false; } // Get expansion tiles const newTiles = this.getExpansionTiles(direction, expansionSize); if (newTiles.length === 0) { this.showNotification({ title: 'Cannot Expand', text: 'Maximum farm size reached or invalid direction!', icon: '🚫' }); return false; } // Pay cost this.payExpansionCost(cost); // Add to expansion queue this.queueExpansion(newTiles); console.log(`🌾 Expanding farm ${direction}: +${newTiles.length} tiles`); this.showNotification({ title: 'Expansion Started!', text: `🌾 Expanding ${direction}! Send zombies to clear the land!`, icon: '🚜' }); return true; } /** * Get tiles for expansion */ getExpansionTiles(direction, size) { const tiles = []; const bounds = this.getCurrentBounds(); switch (direction) { case 'north': for (let x = bounds.minX; x <= bounds.maxX; x++) { for (let y = bounds.minY - size; y < bounds.minY; y++) { tiles.push({ x, y }); } } break; case 'south': for (let x = bounds.minX; x <= bounds.maxX; x++) { for (let y = bounds.maxY + 1; y <= bounds.maxY + size; y++) { tiles.push({ x, y }); } } break; case 'east': for (let x = bounds.maxX + 1; x <= bounds.maxX + size; x++) { for (let y = bounds.minY; y <= bounds.maxY; y++) { tiles.push({ x, y }); } } break; case 'west': for (let x = bounds.minX - size; x < bounds.minX; x++) { for (let y = bounds.minY; y <= bounds.maxY; y++) { tiles.push({ x, y }); } } break; } // Filter out already unlocked tiles return tiles.filter(tile => !this.unlockedTiles.has(`${tile.x},${tile.y}`)); } /** * Get current farm bounds */ getCurrentBounds() { let minX = Infinity, minY = Infinity; let maxX = -Infinity, maxY = -Infinity; this.unlockedTiles.forEach(tileKey => { const [x, y] = tileKey.split(',').map(Number); minX = Math.min(minX, x); minY = Math.min(minY, y); maxX = Math.max(maxX, x); maxY = Math.max(maxY, y); }); return { minX, minY, maxX, maxY }; } /** * Calculate expansion cost */ calculateExpansionCost(direction) { const baseZlatniki = 100; const currentSize = this.unlockedTiles.size; // Cost increases with farm size const zlatniki = baseZlatniki + Math.floor(currentSize / 10) * 50; return { zlatniki: zlatniki, wood: 10, stone: 5 }; } /** * Check if player can afford expansion */ canAffordExpansion(cost) { // TODO: Check actual player resources // For now, return true return true; } /** * Pay expansion cost */ payExpansionCost(cost) { console.log(`πŸ’° Paid: ${cost.zlatniki}Ε½, ${cost.wood} Wood, ${cost.stone} Stone`); // TODO: Actually deduct from player inventory } /** * Queue expansion for zombie clearing */ queueExpansion(tiles) { tiles.forEach(tile => { const tileKey = `${tile.x},${tile.y}`; // Randomly assign land type const landType = this.getRandomLandType(); this.landTypes.set(tileKey, { type: landType, cleared: landType === 'grass', // Grass is pre-cleared fertility: this.getLandTypeFertility(landType), clearingProgress: 0 }); this.expansionQueue.push({ tileKey: tileKey, tile: tile, landType: landType, status: 'queued' }); }); console.log(`πŸ“‹ Queued ${tiles.length} tiles for expansion`); } /** * Get random land type */ getRandomLandType() { const types = ['grass', 'forest', 'rocky', 'swamp']; const weights = [40, 30, 20, 10]; // Grass more common const total = weights.reduce((a, b) => a + b, 0); let random = Math.random() * total; for (let i = 0; i < types.length; i++) { random -= weights[i]; if (random <= 0) return types[i]; } return 'grass'; } /** * Get land type fertility */ getLandTypeFertility(type) { const fertility = { grass: 100, forest: 80, rocky: 50, swamp: 90 }; return fertility[type] || 100; } /** * Send zombies to clear land */ sendZombiesToClear(tileKey, zombieIds) { const land = this.landTypes.get(tileKey); if (!land) { console.error(`Tile ${tileKey} not found!`); return false; } if (land.cleared) { console.log(`Tile ${tileKey} already cleared!`); return false; } console.log(`🧟 Sending ${zombieIds.length} zombies to clear ${land.type} at ${tileKey}`); // Set zombies to clearing task // TODO: Integrate with ZombieSystem // Start clearing progress land.clearingProgress = 0; land.clearingZombies = zombieIds; land.clearingStartTime = Date.now(); return true; } /** * Update clearing progress */ updateClearingProgress(delta) { this.landTypes.forEach((land, tileKey) => { if (!land.cleared && land.clearingZombies) { // Progress based on number of zombies const zombieCount = land.clearingZombies.length; const progressRate = zombieCount * 0.01; // 1% per zombie per second land.clearingProgress += progressRate * (delta / 1000); // Check if complete if (land.clearingProgress >= 100) { this.completeLandClearing(tileKey); } } }); } /** * Complete land clearing */ completeLandClearing(tileKey) { const land = this.landTypes.get(tileKey); if (!land) return; land.cleared = true; land.clearingProgress = 100; land.clearingZombies = null; // Add tile to unlocked this.unlockedTiles.add(tileKey); // Grant clearing rewards this.grantClearingRewards(land.type); console.log(`βœ… Land cleared: ${tileKey} (${land.type})`); this.showNotification({ title: 'Land Cleared!', text: `βœ… ${this.getLandTypeIcon(land.type)} ${land.type} tile ready for farming!`, icon: 'πŸŽ‰' }); } /** * Grant clearing rewards */ grantClearingRewards(landType) { const rewards = { forest: { wood: 10 }, rocky: { stone: 15 }, swamp: { clay: 5 } }; const reward = rewards[landType]; if (reward) { console.log(`🎁 Clearing rewards:`, reward); // TODO: Add to inventory } } /** * Get land type icon */ getLandTypeIcon(type) { const icons = { grass: '🌿', forest: '🌲', rocky: '⛰️', swamp: 'πŸ’§' }; return icons[type] || '❓'; } /** * Tutorial system */ startTutorial() { this.tutorialStep = 1; this.showNotification({ title: 'Welcome to Your Micro Farm!', text: '🌾 You start with an 8x8 plot. Expand by clearing surrounding land!', icon: 'πŸ“š' }); // TODO: Show tutorial UI with steps } /** * Visualize farm (console) */ visualizeFarm() { const bounds = this.getCurrentBounds(); console.log('🌾 FARM MAP:'); for (let y = bounds.minY; y <= bounds.maxY; y++) { let row = ''; for (let x = bounds.minX; x <= bounds.maxX; x++) { const tileKey = `${x},${y}`; if (this.unlockedTiles.has(tileKey)) { const land = this.landTypes.get(tileKey); row += land.cleared ? 'βœ…' : '⏳'; } else { row += 'πŸ”’'; } } console.log(row); } } /** * Get farm info */ getFarmInfo() { return { unlockedTiles: this.unlockedTiles.size, bounds: this.getCurrentBounds(), expansionQueue: this.expansionQueue.length, tutorialComplete: this.tutorialComplete }; } /** * 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); } } /** * Update system */ update(delta) { // Update clearing progress this.updateClearingProgress(delta); } }