/** * ProgressionSystem.js * ==================== * Manages building upgrades and player progression * - House upgrades (5 levels) * - Barn upgrades (4 levels) * - Storage upgrades (4 levels) * - Greenhouse upgrades * * Integrates with RecipeSystem for upgrade crafting * * @author NovaFarma Team * @date 2025-12-22 */ export default class ProgressionSystem { constructor(scene) { this.scene = scene; // Building levels (current state) this.buildingLevels = { house: 1, // Max: 5 barn: 1, // Max: 4 storage: 1, // Max: 4 greenhouse: 1 // Max: 3 }; // Building sprites (references to map objects) this.buildingSprites = { house: null, barn: null, storage: null, greenhouse: null }; // Upgrade requirements data this.upgradeData = this.loadUpgradeData(); // Upgrade benefits this.upgradeBenefits = this.defineUpgradeBenefits(); // Load saved progress this.loadProgress(); console.log('📈 ProgressionSystem initialized'); } loadUpgradeData() { return { house: { maxLevel: 5, levels: { 2: { name: 'Bedroom Addition', description: 'Adds a bedroom - can get married!', materials: { wood: 100, stone: 50, gold: 500 }, craftTime: 10000, blueprint: 'blueprint_house_2' }, 3: { name: 'Kitchen Expansion', description: 'Larger kitchen - cook better meals', materials: { wood: 200, stone: 100, gold: 1500 }, craftTime: 15000, blueprint: 'blueprint_house_3' }, 4: { name: 'Second Floor', description: 'Two stories - children can have rooms', materials: { wood: 400, stone: 200, iron_ingot: 50, gold: 3500 }, craftTime: 20000, blueprint: 'blueprint_house_4' }, 5: { name: 'Mansion', description: 'Ultimate house - full family home', materials: { wood: 800, stone: 400, iron_ingot: 100, gold: 7500 }, craftTime: 30000, blueprint: 'blueprint_house_5' } } }, barn: { maxLevel: 4, levels: { 2: { name: 'Barn Extension', description: 'Hold 8 animals, adds milking station', materials: { wood: 75, stone: 30, gold: 400 }, craftTime: 8000, blueprint: 'blueprint_barn_2' }, 3: { name: 'Large Barn', description: 'Hold 12 animals, auto-feeder', materials: { wood: 150, stone: 75, iron_ingot: 20, gold: 1000 }, craftTime: 12000, blueprint: 'blueprint_barn_3' }, 4: { name: 'Deluxe Barn', description: 'Hold 16 animals, auto-petter', materials: { wood: 300, stone: 150, iron_ingot: 50, gold: 2500 }, craftTime: 18000, blueprint: 'blueprint_barn_4' } } }, storage: { maxLevel: 4, levels: { 2: { name: 'Upgraded Chest', description: 'Inventory +40 slots', materials: { wood: 50, stone: 25, gold: 300 }, craftTime: 5000, blueprint: null // Available from start }, 3: { name: 'Large Warehouse', description: 'Inventory +80 slots', materials: { wood: 100, stone: 50, iron_ingot: 15, gold: 800 }, craftTime: 8000, blueprint: 'blueprint_storage_3' }, 4: { name: 'Massive Storehouse', description: 'Inventory +120 slots', materials: { wood: 200, stone: 100, iron_ingot: 30, gold: 2000 }, craftTime: 12000, blueprint: 'blueprint_storage_4' } } }, greenhouse: { maxLevel: 3, levels: { 2: { name: 'Medium Greenhouse', description: 'Grow 20 crops year-round', materials: { wood: 80, glass: 50, gold: 600 }, craftTime: 10000, blueprint: 'blueprint_greenhouse_2' }, 3: { name: 'Large Greenhouse', description: 'Grow 50 crops year-round', materials: { wood: 160, glass: 100, iron_ingot: 25, gold: 1500 }, craftTime: 15000, blueprint: 'blueprint_greenhouse_3' } } } }; } defineUpgradeBenefits() { return { house: { 1: { bedrooms: 0, kitchen: 'basic', canMarry: false }, 2: { bedrooms: 1, kitchen: 'basic', canMarry: true }, 3: { bedrooms: 1, kitchen: 'upgraded', canMarry: true, cookingBonus: 1.25 }, 4: { bedrooms: 3, kitchen: 'upgraded', canMarry: true, canHaveKids: true, cookingBonus: 1.5 }, 5: { bedrooms: 5, kitchen: 'deluxe', canMarry: true, canHaveKids: true, maxKids: 3, cookingBonus: 2.0 } }, barn: { 1: { capacity: 4, autoFeeder: false, autoPetter: false }, 2: { capacity: 8, autoFeeder: false, autoPetter: false, hasMilkingStation: true }, 3: { capacity: 12, autoFeeder: true, autoPetter: false, hasMilkingStation: true }, 4: { capacity: 16, autoFeeder: true, autoPetter: true, hasMilkingStation: true } }, storage: { 1: { slots: 40 }, 2: { slots: 80 }, 3: { slots: 160 }, 4: { slots: 280 } }, greenhouse: { 1: { capacity: 10, seasonal: false }, 2: { capacity: 20, seasonal: false }, 3: { capacity: 50, seasonal: false, qualityBonus: 1.5 } } }; } // ===== UPGRADE CHECKS ===== canUpgrade(buildingType) { const currentLevel = this.buildingLevels[buildingType]; const maxLevel = this.upgradeData[buildingType].maxLevel; // Check if already max level if (currentLevel >= maxLevel) { return { canUpgrade: false, reason: `Already at max level (${maxLevel})` }; } const nextLevel = currentLevel + 1; const requirements = this.getUpgradeRequirements(buildingType, nextLevel); if (!requirements) { return { canUpgrade: false, reason: 'Upgrade data not found' }; } // Check if blueprint is unlocked (if required) if (requirements.blueprint) { const recipeId = `${buildingType}_upgrade_${nextLevel}`; if (this.scene.recipeSystem && !this.scene.recipeSystem.unlockedRecipes.has(recipeId)) { return { canUpgrade: false, reason: 'Blueprint not unlocked' }; } } // Check materials const missingMaterials = []; for (const [item, quantity] of Object.entries(requirements.materials)) { const hasQuantity = this.getItemQuantity(item); if (hasQuantity < quantity) { missingMaterials.push({ item: item, need: quantity, have: hasQuantity }); } } if (missingMaterials.length > 0) { return { canUpgrade: false, reason: 'Missing materials', missing: missingMaterials }; } return { canUpgrade: true, nextLevel }; } // ===== UPGRADE EXECUTION ===== upgrade(buildingType) { const check = this.canUpgrade(buildingType); if (!check.canUpgrade) { this.scene.uiSystem?.showError(check.reason); console.warn('Cannot upgrade', buildingType, ':', check.reason); return false; } const currentLevel = this.buildingLevels[buildingType]; const nextLevel = check.nextLevel; const requirements = this.getUpgradeRequirements(buildingType, nextLevel); // Consume resources this.consumeResources(requirements.materials); // Show upgrade progress UI this.scene.uiSystem?.showUpgradeProgress(buildingType, requirements); // Wait for construction time this.scene.time.delayedCall(requirements.craftTime, () => { this.completeUpgrade(buildingType, nextLevel); }); // Emit event this.scene.events.emit('upgradeStarted', { buildingType, fromLevel: currentLevel, toLevel: nextLevel, requirements }); console.log(`🏗️ Started upgrading ${buildingType} to level ${nextLevel}`); return true; } completeUpgrade(buildingType, newLevel) { const oldLevel = this.buildingLevels[buildingType]; // Update level this.buildingLevels[buildingType] = newLevel; // Update sprite this.updateBuildingSprite(buildingType, newLevel); // Apply benefits const benefits = this.getBenefits(buildingType, newLevel); this.applyBenefits(buildingType, benefits); // Save progress this.saveProgress(); // Show notification const upgradeInfo = this.getUpgradeRequirements(buildingType, newLevel); this.scene.uiSystem?.showNotification({ title: `${buildingType.toUpperCase()} UPGRADED!`, message: upgradeInfo.description, icon: buildingType, duration: 5000, color: '#00FF00' }); // Emit event this.scene.events.emit('upgradeComplete', { buildingType, oldLevel, newLevel, benefits }); console.log(`✅ ${buildingType} upgraded to level ${newLevel}`); } updateBuildingSprite(buildingType, level) { const sprite = this.buildingSprites[buildingType]; if (!sprite) { console.warn(`Building sprite not found for ${buildingType}`); return; } // Update frame based on level (assumes sprite sheet has frames for each level) // Frame index = level - 1 (0-indexed) const frameIndex = level - 1; if (sprite.setFrame) { sprite.setFrame(frameIndex); } else if (sprite.setTexture) { // If using separate textures per level sprite.setTexture(`${buildingType}_level_${level}`); } // Play upgrade animation (optional) if (this.scene.particleSystem) { this.scene.particleSystem.createUpgradeEffect(sprite.x, sprite.y); } console.log(`🖼️ Updated ${buildingType} sprite to level ${level}`); } applyBenefits(buildingType, benefits) { // Apply building-specific benefits switch (buildingType) { case 'house': if (benefits.canMarry) { this.scene.events.emit('marriageUnlocked'); } if (benefits.canHaveKids) { this.scene.events.emit('kidsUnlocked'); } // Update cooking multiplier if (this.scene.farmingSystem) { this.scene.farmingSystem.cookingMultiplier = benefits.cookingBonus || 1.0; } break; case 'barn': // Update animal capacity if (this.scene.animalSystem) { this.scene.animalSystem.maxAnimals = benefits.capacity; this.scene.animalSystem.autoFeeder = benefits.autoFeeder; this.scene.animalSystem.autoPetter = benefits.autoPetter; } break; case 'storage': // Update inventory capacity if (this.scene.inventorySystem) { this.scene.inventorySystem.maxSlots = benefits.slots; } break; case 'greenhouse': // Update greenhouse capacity if (this.scene.farmingSystem) { this.scene.farmingSystem.greenhouseCapacity = benefits.capacity; this.scene.farmingSystem.greenhouseQualityBonus = benefits.qualityBonus || 1.0; } break; } console.log(`✨ Applied benefits for ${buildingType}:`, benefits); } // ===== HELPER FUNCTIONS ===== registerBuildingSprite(buildingType, sprite) { this.buildingSprites[buildingType] = sprite; // Set initial sprite frame based on current level const currentLevel = this.buildingLevels[buildingType]; this.updateBuildingSprite(buildingType, currentLevel); console.log(`📍 Registered ${buildingType} sprite at level ${currentLevel}`); } getUpgradeRequirements(buildingType, level) { return this.upgradeData[buildingType]?.levels[level]; } getBenefits(buildingType, level) { return this.upgradeBenefits[buildingType]?.[level]; } getCurrentBenefits(buildingType) { const level = this.buildingLevels[buildingType]; return this.getBenefits(buildingType, level); } consumeResources(materials) { for (const [item, quantity] of Object.entries(materials)) { this.removeItem(item, quantity); } console.log('💰 Consumed resources:', materials); } // ===== INVENTORY INTEGRATION ===== getItemQuantity(itemId) { if (this.scene.inventorySystem) { return this.scene.inventorySystem.getQuantity(itemId); } return this.scene.player?.inventory?.[itemId] || 0; } removeItem(itemId, quantity) { if (this.scene.inventorySystem) { this.scene.inventorySystem.removeItem(itemId, quantity); } else if (this.scene.player?.inventory) { this.scene.player.inventory[itemId] -= quantity; } } // ===== DATA PERSISTENCE ===== saveProgress() { const data = { buildingLevels: this.buildingLevels, timestamp: Date.now() }; localStorage.setItem('buildingProgress', JSON.stringify(data)); console.log('💾 Saved building progress'); } loadProgress() { const saved = localStorage.getItem('buildingProgress'); if (saved) { const data = JSON.parse(saved); this.buildingLevels = data.buildingLevels; console.log('📂 Loaded building progress:', this.buildingLevels); } } // ===== GETTERS ===== getLevel(buildingType) { return this.buildingLevels[buildingType]; } getMaxLevel(buildingType) { return this.upgradeData[buildingType]?.maxLevel; } isMaxLevel(buildingType) { return this.getLevel(buildingType) >= this.getMaxLevel(buildingType); } getNextUpgradeInfo(buildingType) { const currentLevel = this.getLevel(buildingType); const nextLevel = currentLevel + 1; const maxLevel = this.getMaxLevel(buildingType); if (currentLevel >= maxLevel) { return null; } return { currentLevel, nextLevel, maxLevel, requirements: this.getUpgradeRequirements(buildingType, nextLevel), benefits: this.getBenefits(buildingType, nextLevel), canUpgrade: this.canUpgrade(buildingType) }; } getAllUpgradeInfo() { const info = {}; for (const buildingType of Object.keys(this.buildingLevels)) { info[buildingType] = this.getNextUpgradeInfo(buildingType); } return info; } getProgressPercentage(buildingType) { const current = this.getLevel(buildingType); const max = this.getMaxLevel(buildingType); return (current / max) * 100; } getTotalProgress() { const buildings = Object.keys(this.buildingLevels); let totalCurrent = 0; let totalMax = 0; for (const building of buildings) { totalCurrent += this.getLevel(building); totalMax += this.getMaxLevel(building); } return { current: totalCurrent, max: totalMax, percentage: (totalCurrent / totalMax) * 100 }; } // ===== CLEANUP ===== destroy() { this.saveProgress(); this.buildingSprites = {}; } }