Game Systems: RecipeSystem + ProgressionSystem + BreedingSystem implemented
This commit is contained in:
527
src/systems/ProgressionSystem.js
Normal file
527
src/systems/ProgressionSystem.js
Normal file
@@ -0,0 +1,527 @@
|
||||
/**
|
||||
* 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 = {};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user