Files
novafarma/src/systems/CraftingTablesSystem.js

575 lines
17 KiB
JavaScript

/**
* CRAFTING TABLES SYSTEM - Recipe Management & Item Creation
* Part of: Home Upgrade & Customization System
* Created: January 4, 2026
*
* Features:
* - Small crafting table (50 basic recipes)
* - Large planning table (100+ advanced recipes)
* - Recipe unlocking system
* - Ingredient checking
* - Batch crafting
* - Gronk's expedition integration
*/
class CraftingTablesSystem {
constructor(game) {
this.game = game;
this.player = game.player;
// Table types
this.tables = {
SMALL: {
id: 'small_table',
name: 'Small Crafting Table',
cost: 0,
unlocked: true,
maxRecipes: 50,
craftingSpeed: 1.0,
sprite: 'interior_table_small.png',
description: 'A basic workbench for simple crafting.',
categories: ['tools_wooden', 'repairs', 'food_basic', 'potions_beginner']
},
LARGE: {
id: 'large_table',
name: 'Large Planning Table',
cost: 5000,
requirements: {
metGronk: true,
questCompleted: 'builders_vision'
},
unlocked: false,
maxRecipes: 100,
craftingSpeed: 1.5,
sprite: 'interior_table_large.png',
description: 'An advanced table for complex projects and expeditions.',
categories: ['tools_wooden', 'repairs', 'food_basic', 'potions_beginner',
'expedition_planning', 'mechanisms', 'weapons_advanced', 'gronk_special']
}
};
// Crafting recipes database
this.recipes = this.initializeRecipes();
// Player's current table
this.currentTable = { ...this.tables.SMALL };
// Unlocked recipes
this.unlockedRecipes = [];
// Crafting state
this.isCrafting = false;
this.craftingQueue = [];
this.currentCraft = null;
}
/**
* Initialize all crafting recipes
*/
initializeRecipes() {
return {
// TOOLS - WOODEN TIER
wooden_hoe: {
id: 'wooden_hoe',
name: 'Wooden Hoe',
category: 'tools_wooden',
table: 'SMALL',
ingredients: {
wood: 10,
rope: 2
},
output: {
item: 'wooden_hoe',
quantity: 1
},
craftTime: 5, // seconds
unlocked: true,
description: 'Basic farming tool for tilling soil.'
},
wooden_pickaxe: {
id: 'wooden_pickaxe',
name: 'Wooden Pickaxe',
category: 'tools_wooden',
table: 'SMALL',
ingredients: {
wood: 15,
stone: 5
},
output: {
item: 'wooden_pickaxe',
quantity: 1
},
craftTime: 8,
unlocked: true,
description: 'Basic mining tool for breaking rocks.'
},
// REPAIRS
locket_cleaning: {
id: 'locket_cleaning',
name: 'Clean Ana\'s Locket',
category: 'repairs',
table: 'SMALL',
ingredients: {
cloth: 1,
water: 1
},
output: {
item: 'locket_clean',
quantity: 1
},
craftTime: 3,
unlocked: false,
questRequired: 'memory_lane',
description: 'Restore Ana\'s precious locket to its former shine.'
},
// FOOD - BASIC
sandwich: {
id: 'sandwich',
name: 'Sandwich',
category: 'food_basic',
table: 'SMALL',
ingredients: {
bread: 2,
cheese: 1
},
output: {
item: 'sandwich',
quantity: 1
},
craftTime: 2,
energy_restore: 20,
unlocked: true,
description: 'A simple but filling meal.'
},
salad: {
id: 'salad',
name: 'Garden Salad',
category: 'food_basic',
table: 'SMALL',
ingredients: {
lettuce: 3,
tomato: 2,
cucumber: 1
},
output: {
item: 'salad',
quantity: 1
},
craftTime: 3,
energy_restore: 25,
unlocked: true,
description: 'Fresh vegetables in a healthy mix.'
},
// POTIONS - BEGINNER
healing_potion_basic: {
id: 'healing_potion_basic',
name: 'Basic Healing Potion',
category: 'potions_beginner',
table: 'SMALL',
ingredients: {
red_herb: 2,
water: 1,
glass_bottle: 1
},
output: {
item: 'healing_potion_basic',
quantity: 1
},
craftTime: 10,
health_restore: 50,
unlocked: false,
skillRequired: { alchemy: 1 },
description: 'Restores 50 HP.'
},
// EXPEDITION PLANNING (Large Table Only)
expedition_map: {
id: 'expedition_map',
name: 'Expedition Map',
category: 'expedition_planning',
table: 'LARGE',
ingredients: {
paper: 5,
ink: 2,
compass: 1
},
output: {
item: 'expedition_map',
quantity: 1
},
craftTime: 20,
unlocked: false,
npcRequired: 'gronk',
description: 'Required for planning expeditions with Gronk.'
},
expedition_supplies: {
id: 'expedition_supplies',
name: 'Expedition Supplies',
category: 'expedition_planning',
table: 'LARGE',
ingredients: {
rope: 10,
torch: 5,
food_rations: 20,
water_bottle: 10
},
output: {
item: 'expedition_supplies',
quantity: 1
},
craftTime: 30,
unlocked: false,
npcRequired: 'gronk',
description: 'Everything needed for a successful expedition.'
},
// COMPLEX MECHANISMS (Large Table Only)
automated_sprinkler: {
id: 'automated_sprinkler',
name: 'Automated Sprinkler',
category: 'mechanisms',
table: 'LARGE',
ingredients: {
iron_pipe: 10,
gears: 5,
water_pump: 1
},
output: {
item: 'automated_sprinkler',
quantity: 1
},
craftTime: 60,
unlocked: false,
skillRequired: { engineering: 3 },
description: 'Waters crops automatically in a 3x3 area.'
},
// ADVANCED WEAPONS (Large Table Only)
steel_sword: {
id: 'steel_sword',
name: 'Steel Sword',
category: 'weapons_advanced',
table: 'LARGE',
ingredients: {
steel_ingot: 5,
leather: 2,
ruby: 1
},
output: {
item: 'steel_sword',
quantity: 1
},
craftTime: 45,
damage: 50,
unlocked: false,
skillRequired: { combat: 5 },
description: 'A powerful blade forged from steel.'
},
// GRONK SPECIAL (Large Table Only)
gronk_explosive: {
id: 'gronk_explosive',
name: 'Gronk\'s Explosive',
category: 'gronk_special',
table: 'LARGE',
ingredients: {
gunpowder: 5,
wire: 3,
metal_casing: 1,
gronks_secret_ingredient: 1
},
output: {
item: 'gronk_explosive',
quantity: 3
},
craftTime: 90,
unlocked: false,
npcRequired: 'gronk',
relationshipRequired: { gronk: 7 },
description: 'BOOM! Gronk\'s special explosive for clearing obstacles.'
}
};
}
/**
* Purchase Large Planning Table
*/
purchaseLargeTable() {
const largeTable = this.tables.LARGE;
// Check if already purchased
if (largeTable.unlocked) {
return { success: false, message: 'You already own the Large Table!' };
}
// Check requirements
if (!this.player.hasMetNPC('gronk')) {
return {
success: false,
message: 'You need to meet Gronk first!'
};
}
if (!this.player.hasCompletedQuest('builders_vision')) {
return {
success: false,
message: 'Complete "Builder\'s Vision" quest first!'
};
}
// Check cost
if (this.player.money < largeTable.cost) {
return {
success: false,
message: `Not enough money! Need ${largeTable.cost}g`
};
}
// Purchase
this.player.money -= largeTable.cost;
largeTable.unlocked = true;
this.currentTable = { ...largeTable };
// Unlock advanced recipes
this.unlockAdvancedRecipes();
return {
success: true,
message: `Purchased ${largeTable.name} for ${largeTable.cost}g!`
};
}
/**
* Unlock advanced recipes when Large Table is purchased
*/
unlockAdvancedRecipes() {
Object.values(this.recipes).forEach(recipe => {
if (recipe.table === 'LARGE' && !recipe.npcRequired && !recipe.skillRequired) {
recipe.unlocked = true;
}
});
}
/**
* Check if player can craft a recipe
*/
canCraft(recipeId) {
const recipe = this.recipes[recipeId];
if (!recipe) {
return { canCraft: false, reason: 'Recipe not found' };
}
// Check if recipe is unlocked
if (!recipe.unlocked) {
return { canCraft: false, reason: 'Recipe locked' };
}
// Check table requirement
if (recipe.table === 'LARGE' && !this.tables.LARGE.unlocked) {
return { canCraft: false, reason: 'Requires Large Planning Table' };
}
// Check NPC requirement
if (recipe.npcRequired && !this.player.hasMetNPC(recipe.npcRequired)) {
return { canCraft: false, reason: `Requires meeting ${recipe.npcRequired}` };
}
// Check relationship requirement
if (recipe.relationshipRequired) {
for (const [npc, level] of Object.entries(recipe.relationshipRequired)) {
if (this.player.getRelationshipLevel(npc) < level) {
return {
canCraft: false,
reason: `Requires ${level}+ hearts with ${npc}`
};
}
}
}
// Check skill requirement
if (recipe.skillRequired) {
for (const [skill, level] of Object.entries(recipe.skillRequired)) {
if (this.player.getSkillLevel(skill) < level) {
return {
canCraft: false,
reason: `Requires ${skill} level ${level}`
};
}
}
}
// Check ingredients
const missingIngredients = [];
for (const [ingredient, amount] of Object.entries(recipe.ingredients)) {
const playerAmount = this.player.inventory.getItemCount(ingredient);
if (playerAmount < amount) {
missingIngredients.push({
item: ingredient,
have: playerAmount,
need: amount
});
}
}
if (missingIngredients.length > 0) {
return {
canCraft: false,
reason: 'Missing ingredients',
missingIngredients: missingIngredients
};
}
return { canCraft: true };
}
/**
* Start crafting a recipe
*/
craft(recipeId, quantity = 1) {
const canCraftCheck = this.canCraft(recipeId);
if (!canCraftCheck.canCraft) {
return {
success: false,
message: canCraftCheck.reason,
missingIngredients: canCraftCheck.missingIngredients
};
}
const recipe = this.recipes[recipeId];
// Remove ingredients
for (const [ingredient, amount] of Object.entries(recipe.ingredients)) {
this.player.inventory.removeItem(ingredient, amount * quantity);
}
// Calculate craft time (with table speed bonus)
const tableSpeed = this.currentTable.craftingSpeed;
const totalTime = (recipe.craftTime / tableSpeed) * quantity;
// Add to crafting queue
const craftJob = {
recipe: recipe,
quantity: quantity,
timeRemaining: totalTime,
totalTime: totalTime
};
this.craftingQueue.push(craftJob);
// Start crafting if not already crafting
if (!this.isCrafting) {
this.startNextCraft();
}
return {
success: true,
message: `Crafting ${quantity}x ${recipe.name}... (${Math.floor(totalTime)}s)`,
craftJob: craftJob
};
}
/**
* Start next craft in queue
*/
startNextCraft() {
if (this.craftingQueue.length === 0) {
this.isCrafting = false;
this.currentCraft = null;
return;
}
this.isCrafting = true;
this.currentCraft = this.craftingQueue[0];
// Emit crafting started event
this.game.emit('craftingStarted', {
recipe: this.currentCraft.recipe,
quantity: this.currentCraft.quantity,
time: this.currentCraft.totalTime
});
}
/**
* Update crafting progress
*/
update(deltaTime) {
if (!this.isCrafting || !this.currentCraft) return;
// Decrease time remaining
this.currentCraft.timeRemaining -= deltaTime;
// Check if completed
if (this.currentCraft.timeRemaining <= 0) {
this.completeCraft();
}
}
/**
* Complete current craft
*/
completeCraft() {
if (!this.currentCraft) return;
const recipe = this.currentCraft.recipe;
const quantity = this.currentCraft.quantity;
// Add crafted item to inventory
this.player.inventory.addItem(
recipe.output.item,
recipe.output.quantity * quantity
);
// Show completion message
this.game.showMessage(
`✅ Crafted ${quantity}x ${recipe.name}!`
);
// Emit crafting completed event
this.game.emit('craftingCompleted', {
recipe: recipe,
quantity: quantity
});
// Remove from queue
this.craftingQueue.shift();
// Start next craft
this.startNextCraft();
}
/**
* Get all available recipes for current table
*/
getAvailableRecipes() {
return Object.values(this.recipes).filter(recipe => {
// Filter by table type
if (recipe.table === 'LARGE' && !this.tables.LARGE.unlocked) {
return false;
}
return recipe.unlocked;
});
}
/**
* Get crafting UI data
*/
getCraftingUIData() {
return {
currentTable: this.currentTable,
isCrafting: this.isCrafting,
currentCraft: this.currentCraft,
queue: this.craftingQueue,
availableRecipes: this.getAvailableRecipes(),
largeTableUnlocked: this.tables.LARGE.unlocked
};
}
}