narejeno
This commit is contained in:
475
src/systems/CookingSystem.js
Normal file
475
src/systems/CookingSystem.js
Normal file
@@ -0,0 +1,475 @@
|
||||
/**
|
||||
* COOKING & RECIPE SYSTEM
|
||||
* Complete cooking system with recipes, food buffs, spoilage, and skill progression
|
||||
*/
|
||||
class CookingSystem {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
this.enabled = true;
|
||||
|
||||
// Recipes
|
||||
this.recipes = new Map();
|
||||
this.knownRecipes = new Set();
|
||||
|
||||
// Cooking stations
|
||||
this.cookingStations = new Map();
|
||||
|
||||
// Active cooking
|
||||
this.activeCooking = [];
|
||||
|
||||
// Food items
|
||||
this.foodItems = new Map();
|
||||
|
||||
// Cooking skill
|
||||
this.cookingLevel = 1;
|
||||
this.cookingXP = 0;
|
||||
|
||||
// Settings
|
||||
this.settings = {
|
||||
spoilageRate: 0.01, // 1% per minute
|
||||
xpPerRecipe: 10,
|
||||
xpScaling: 1.5
|
||||
};
|
||||
|
||||
this.loadProgress();
|
||||
this.init();
|
||||
|
||||
console.log('✅ Cooking System initialized');
|
||||
}
|
||||
|
||||
init() {
|
||||
this.defineRecipes();
|
||||
this.defineCookingStations();
|
||||
console.log('🍳 Cooking system ready');
|
||||
}
|
||||
|
||||
// ========== RECIPES ==========
|
||||
|
||||
defineRecipes() {
|
||||
// Basic recipes
|
||||
this.defineRecipe('wheat_bread', {
|
||||
name: 'Wheat Bread',
|
||||
ingredients: { wheat: 3, water: 1 },
|
||||
cookTime: 30, // seconds
|
||||
cookingStation: 'oven',
|
||||
buffs: { hunger: 50, health: 10 },
|
||||
buffDuration: 0, // permanent (hunger/health)
|
||||
spoilTime: 300, // 5 minutes
|
||||
xp: 10,
|
||||
requiredLevel: 1
|
||||
});
|
||||
|
||||
this.defineRecipe('vegetable_soup', {
|
||||
name: 'Vegetable Soup',
|
||||
ingredients: { carrot: 2, potato: 2, water: 1 },
|
||||
cookTime: 45,
|
||||
cookingStation: 'stove',
|
||||
buffs: { hunger: 60, health: 15, stamina: 20 },
|
||||
buffDuration: 180, // 3 minutes
|
||||
spoilTime: 240,
|
||||
xp: 15,
|
||||
requiredLevel: 2
|
||||
});
|
||||
|
||||
this.defineRecipe('grilled_meat', {
|
||||
name: 'Grilled Meat',
|
||||
ingredients: { raw_meat: 1 },
|
||||
cookTime: 20,
|
||||
cookingStation: 'grill',
|
||||
buffs: { hunger: 70, health: 20, strength: 15 },
|
||||
buffDuration: 300, // 5 minutes
|
||||
spoilTime: 180,
|
||||
xp: 20,
|
||||
requiredLevel: 3
|
||||
});
|
||||
|
||||
this.defineRecipe('mutant_stew', {
|
||||
name: 'Mutant Stew',
|
||||
ingredients: { mutant_meat: 2, carrot: 3, potato: 2, water: 1 },
|
||||
cookTime: 60,
|
||||
cookingStation: 'cauldron',
|
||||
buffs: { hunger: 80, health: 30, strength: 25, speed: 15 },
|
||||
buffDuration: 600, // 10 minutes
|
||||
spoilTime: 360,
|
||||
xp: 50,
|
||||
requiredLevel: 5
|
||||
});
|
||||
|
||||
this.defineRecipe('golden_apple_pie', {
|
||||
name: 'Golden Apple Pie',
|
||||
ingredients: { golden_apple: 1, wheat: 5, sugar: 3 },
|
||||
cookTime: 90,
|
||||
cookingStation: 'oven',
|
||||
buffs: { hunger: 100, health: 50, all_stats: 20 },
|
||||
buffDuration: 900, // 15 minutes
|
||||
spoilTime: 600,
|
||||
xp: 100,
|
||||
requiredLevel: 10
|
||||
});
|
||||
}
|
||||
|
||||
defineRecipe(id, data) {
|
||||
this.recipes.set(id, {
|
||||
id,
|
||||
...data,
|
||||
discovered: false
|
||||
});
|
||||
}
|
||||
|
||||
// ========== COOKING STATIONS ==========
|
||||
|
||||
defineCookingStations() {
|
||||
this.cookingStations.set('stove', {
|
||||
name: 'Stove',
|
||||
cost: { iron: 10, wood: 5 },
|
||||
cookingSpeed: 1.0
|
||||
});
|
||||
|
||||
this.cookingStations.set('oven', {
|
||||
name: 'Oven',
|
||||
cost: { iron: 15, stone: 20 },
|
||||
cookingSpeed: 1.2
|
||||
});
|
||||
|
||||
this.cookingStations.set('grill', {
|
||||
name: 'Grill',
|
||||
cost: { iron: 8, wood: 10 },
|
||||
cookingSpeed: 0.8
|
||||
});
|
||||
|
||||
this.cookingStations.set('cauldron', {
|
||||
name: 'Cauldron',
|
||||
cost: { iron: 20, magic_crystal: 1 },
|
||||
cookingSpeed: 1.5
|
||||
});
|
||||
}
|
||||
|
||||
// ========== COOKING ==========
|
||||
|
||||
canCook(recipeId) {
|
||||
const recipe = this.recipes.get(recipeId);
|
||||
if (!recipe) return false;
|
||||
|
||||
// Check level
|
||||
if (this.cookingLevel < recipe.requiredLevel) {
|
||||
console.log(`❌ Requires cooking level ${recipe.requiredLevel}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check ingredients
|
||||
if (!this.scene.inventorySystem) return false;
|
||||
|
||||
for (const [ingredient, amount] of Object.entries(recipe.ingredients)) {
|
||||
const has = this.scene.inventorySystem.getItemCount(ingredient);
|
||||
if (has < amount) {
|
||||
console.log(`❌ Missing ${ingredient}: ${has}/${amount}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
startCooking(recipeId, stationType) {
|
||||
if (!this.canCook(recipeId)) return false;
|
||||
|
||||
const recipe = this.recipes.get(recipeId);
|
||||
const station = this.cookingStations.get(stationType);
|
||||
|
||||
if (!station) {
|
||||
console.log('❌ Invalid cooking station');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (recipe.cookingStation !== stationType) {
|
||||
console.log(`❌ Requires ${recipe.cookingStation}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Consume ingredients
|
||||
for (const [ingredient, amount] of Object.entries(recipe.ingredients)) {
|
||||
this.scene.inventorySystem.removeItem(ingredient, amount);
|
||||
}
|
||||
|
||||
// Start cooking
|
||||
const cookTime = recipe.cookTime / station.cookingSpeed;
|
||||
const cooking = {
|
||||
recipeId,
|
||||
startTime: Date.now(),
|
||||
cookTime: cookTime * 1000, // convert to ms
|
||||
station: stationType
|
||||
};
|
||||
|
||||
this.activeCooking.push(cooking);
|
||||
|
||||
// Discover recipe
|
||||
if (!recipe.discovered) {
|
||||
this.discoverRecipe(recipeId);
|
||||
}
|
||||
|
||||
console.log(`🍳 Started cooking ${recipe.name} (${cookTime}s)`);
|
||||
return true;
|
||||
}
|
||||
|
||||
updateCooking(delta) {
|
||||
const now = Date.now();
|
||||
|
||||
for (let i = this.activeCooking.length - 1; i >= 0; i--) {
|
||||
const cooking = this.activeCooking[i];
|
||||
const elapsed = now - cooking.startTime;
|
||||
|
||||
if (elapsed >= cooking.cookTime) {
|
||||
// Cooking complete!
|
||||
this.completeCooking(cooking);
|
||||
this.activeCooking.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
completeCooking(cooking) {
|
||||
const recipe = this.recipes.get(cooking.recipeId);
|
||||
|
||||
// Create food item
|
||||
const food = this.createFoodItem(recipe);
|
||||
|
||||
// Add to inventory
|
||||
if (this.scene.inventorySystem) {
|
||||
this.scene.inventorySystem.addItem(cooking.recipeId, 1);
|
||||
}
|
||||
|
||||
// Grant XP
|
||||
this.addCookingXP(recipe.xp);
|
||||
|
||||
// Visual effect
|
||||
if (this.scene.visualEnhancements) {
|
||||
const player = this.scene.player;
|
||||
if (player) {
|
||||
const pos = player.getPosition();
|
||||
this.scene.visualEnhancements.createSparkleEffect(pos.x, pos.y);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ Cooked ${recipe.name}!`);
|
||||
}
|
||||
|
||||
createFoodItem(recipe) {
|
||||
const food = {
|
||||
id: `food_${Date.now()}`,
|
||||
recipeId: recipe.id,
|
||||
name: recipe.name,
|
||||
buffs: recipe.buffs,
|
||||
buffDuration: recipe.buffDuration,
|
||||
createdTime: Date.now(),
|
||||
spoilTime: recipe.spoilTime * 1000,
|
||||
spoiled: false
|
||||
};
|
||||
|
||||
this.foodItems.set(food.id, food);
|
||||
return food;
|
||||
}
|
||||
|
||||
// ========== EATING ==========
|
||||
|
||||
eatFood(foodId) {
|
||||
const food = this.foodItems.get(foodId);
|
||||
if (!food) return false;
|
||||
|
||||
// Check if spoiled
|
||||
if (this.isSpoiled(food)) {
|
||||
console.log('🤢 Food is spoiled!');
|
||||
// Negative effects
|
||||
if (this.scene.statsSystem) {
|
||||
this.scene.statsSystem.health -= 10;
|
||||
}
|
||||
this.foodItems.delete(foodId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Apply buffs
|
||||
this.applyFoodBuffs(food);
|
||||
|
||||
// Remove food
|
||||
this.foodItems.delete(foodId);
|
||||
|
||||
console.log(`😋 Ate ${food.name}!`);
|
||||
return true;
|
||||
}
|
||||
|
||||
applyFoodBuffs(food) {
|
||||
const buffs = food.buffs;
|
||||
|
||||
// Permanent buffs (hunger, health)
|
||||
if (this.scene.statsSystem) {
|
||||
if (buffs.hunger) {
|
||||
this.scene.statsSystem.hunger = Math.min(100, this.scene.statsSystem.hunger + buffs.hunger);
|
||||
}
|
||||
if (buffs.health) {
|
||||
this.scene.statsSystem.health = Math.min(this.scene.statsSystem.maxHealth, this.scene.statsSystem.health + buffs.health);
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary buffs
|
||||
if (food.buffDuration > 0) {
|
||||
this.applyTemporaryBuffs(buffs, food.buffDuration);
|
||||
}
|
||||
}
|
||||
|
||||
applyTemporaryBuffs(buffs, duration) {
|
||||
// Apply buffs for duration
|
||||
const buffData = {
|
||||
buffs,
|
||||
startTime: Date.now(),
|
||||
duration: duration * 1000
|
||||
};
|
||||
|
||||
// Store active buffs (would integrate with player stats)
|
||||
console.log(`✨ Buffs active for ${duration}s:`, buffs);
|
||||
|
||||
// Schedule buff removal
|
||||
setTimeout(() => {
|
||||
console.log('⏰ Buffs expired');
|
||||
}, duration * 1000);
|
||||
}
|
||||
|
||||
// ========== SPOILAGE ==========
|
||||
|
||||
updateSpoilage(delta) {
|
||||
const now = Date.now();
|
||||
|
||||
for (const food of this.foodItems.values()) {
|
||||
const age = now - food.createdTime;
|
||||
|
||||
if (age > food.spoilTime) {
|
||||
food.spoiled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isSpoiled(food) {
|
||||
const age = Date.now() - food.createdTime;
|
||||
return age > food.spoilTime;
|
||||
}
|
||||
|
||||
// ========== RECIPE DISCOVERY ==========
|
||||
|
||||
discoverRecipe(recipeId) {
|
||||
const recipe = this.recipes.get(recipeId);
|
||||
if (!recipe) return;
|
||||
|
||||
recipe.discovered = true;
|
||||
this.knownRecipes.add(recipeId);
|
||||
|
||||
console.log(`📖 Discovered recipe: ${recipe.name}!`);
|
||||
|
||||
// Achievement
|
||||
if (this.scene.uiGraphics && this.knownRecipes.size >= 10) {
|
||||
this.scene.uiGraphics.unlockAchievement('master_chef');
|
||||
}
|
||||
|
||||
this.saveProgress();
|
||||
}
|
||||
|
||||
tryDiscoverRecipe(ingredients) {
|
||||
// Try to match ingredients to unknown recipes
|
||||
for (const [recipeId, recipe] of this.recipes.entries()) {
|
||||
if (recipe.discovered) continue;
|
||||
|
||||
// Check if ingredients match
|
||||
const matches = this.matchIngredients(ingredients, recipe.ingredients);
|
||||
if (matches) {
|
||||
this.discoverRecipe(recipeId);
|
||||
return recipe;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
matchIngredients(provided, required) {
|
||||
const providedKeys = Object.keys(provided).sort();
|
||||
const requiredKeys = Object.keys(required).sort();
|
||||
|
||||
if (providedKeys.length !== requiredKeys.length) return false;
|
||||
|
||||
for (let i = 0; i < providedKeys.length; i++) {
|
||||
if (providedKeys[i] !== requiredKeys[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== SKILL PROGRESSION ==========
|
||||
|
||||
addCookingXP(amount) {
|
||||
this.cookingXP += amount;
|
||||
|
||||
// Level up check
|
||||
const xpNeeded = this.getCookingXPForLevel(this.cookingLevel + 1);
|
||||
if (this.cookingXP >= xpNeeded) {
|
||||
this.levelUpCooking();
|
||||
}
|
||||
|
||||
this.saveProgress();
|
||||
}
|
||||
|
||||
getCookingXPForLevel(level) {
|
||||
return Math.floor(100 * Math.pow(this.settings.xpScaling, level - 1));
|
||||
}
|
||||
|
||||
levelUpCooking() {
|
||||
this.cookingLevel++;
|
||||
this.cookingXP = 0;
|
||||
|
||||
console.log(`🎉 Cooking level up! Now level ${this.cookingLevel}`);
|
||||
|
||||
// Visual effect
|
||||
if (this.scene.visualEnhancements) {
|
||||
const player = this.scene.player;
|
||||
if (player) {
|
||||
const pos = player.getPosition();
|
||||
this.scene.visualEnhancements.createSparkleEffect(pos.x, pos.y);
|
||||
}
|
||||
}
|
||||
|
||||
this.saveProgress();
|
||||
}
|
||||
|
||||
// ========== UPDATE ==========
|
||||
|
||||
update(delta) {
|
||||
this.updateCooking(delta);
|
||||
this.updateSpoilage(delta);
|
||||
}
|
||||
|
||||
// ========== PERSISTENCE ==========
|
||||
|
||||
saveProgress() {
|
||||
const data = {
|
||||
cookingLevel: this.cookingLevel,
|
||||
cookingXP: this.cookingXP,
|
||||
knownRecipes: Array.from(this.knownRecipes)
|
||||
};
|
||||
|
||||
localStorage.setItem('novafarma_cooking', JSON.stringify(data));
|
||||
}
|
||||
|
||||
loadProgress() {
|
||||
const saved = localStorage.getItem('novafarma_cooking');
|
||||
if (saved) {
|
||||
try {
|
||||
const data = JSON.parse(saved);
|
||||
this.cookingLevel = data.cookingLevel || 1;
|
||||
this.cookingXP = data.cookingXP || 0;
|
||||
this.knownRecipes = new Set(data.knownRecipes || []);
|
||||
console.log('✅ Cooking progress loaded');
|
||||
} catch (error) {
|
||||
console.error('Failed to load cooking progress:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.saveProgress();
|
||||
console.log('🍳 Cooking System destroyed');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user