Game-Server/Client/js/systems/CraftingSystem.js
2026-01-24 16:47:19 -04:00

652 lines
23 KiB
JavaScript

/**
* Galaxy Strike Online - Crafting System
* Handles item crafting, recipes, and crafting skill progression
*/
class CraftingSystem extends BaseSystem {
constructor(gameEngine) {
super(gameEngine);
this.recipes = new Map();
this.currentCategory = 'weapons';
this.selectedRecipe = null;
this.initializeRecipes();
}
initializeRecipes() {
// Weapon Recipes
this.addRecipe('basic_blaster', {
name: 'Basic Blaster',
category: 'weapons',
description: 'A simple energy blaster for beginners',
requirements: {
weapon_crafting: 1,
crafting: 1
},
materials: [
{ id: 'iron_ore', quantity: 5 },
{ id: 'energy_crystal', quantity: 2 }
],
results: [
{ id: 'basic_blaster', quantity: 1 }
],
experience: 10,
craftingTime: 3000 // 3 seconds
});
this.addRecipe('enhanced_blaster', {
name: 'Enhanced Blaster',
category: 'weapons',
description: 'An improved blaster with better damage output',
requirements: {
weapon_crafting: 3,
crafting: 5
},
materials: [
{ id: 'iron_ore', quantity: 10 },
{ id: 'energy_crystal', quantity: 5 },
{ id: 'copper_wire', quantity: 3 }
],
results: [
{ id: 'enhanced_blaster', quantity: 1 }
],
experience: 25,
craftingTime: 5000 // 5 seconds
});
this.addRecipe('laser_sniper_rifle', {
name: 'Laser Sniper Rifle',
category: 'weapons',
description: 'A long-range precision laser weapon',
requirements: {
weapon_crafting: 3,
crafting: 5
},
materials: [
{ id: 'advanced_circuitboard', quantity: 2 },
{ id: 'energy_crystal', quantity: 8 },
{ id: 'steel_plate', quantity: 5 },
{ id: 'copper_wire', quantity: 4 }
],
results: [
{ id: 'laser_sniper_rifle', quantity: 1 }
],
experience: 40,
craftingTime: 8000 // 8 seconds
});
this.addRecipe('plasma_cannon', {
name: 'Plasma Cannon',
category: 'weapons',
description: 'A devastating plasma-based weapon',
requirements: {
weapon_crafting: 5,
crafting: 7
},
materials: [
{ id: 'advanced_components', quantity: 3 },
{ id: 'energy_crystal', quantity: 12 },
{ id: 'steel_plate', quantity: 8 },
{ id: 'battery', quantity: 3 }
],
results: [
{ id: 'plasma_cannon', quantity: 1 }
],
experience: 60,
craftingTime: 12000 // 12 seconds
});
// Armor Recipes
this.addRecipe('basic_armor', {
name: 'Basic Armor',
category: 'armor',
description: 'Light armor providing basic protection',
requirements: {
armor_forging: 1,
crafting: 1
},
materials: [
{ id: 'iron_ore', quantity: 8 },
{ id: 'leather', quantity: 3 }
],
results: [
{ id: 'basic_armor', quantity: 1 }
],
experience: 15,
craftingTime: 4000 // 4 seconds
});
this.addRecipe('reinforced_armor', {
name: 'Reinforced Armor',
category: 'armor',
description: 'Heavy armor with enhanced protection',
requirements: {
armor_forging: 4,
crafting: 6
},
materials: [
{ id: 'iron_ore', quantity: 15 },
{ id: 'steel_plate', quantity: 5 },
{ id: 'leather', quantity: 5 }
],
results: [
{ id: 'reinforced_armor', quantity: 1 }
],
experience: 35,
craftingTime: 6000 // 6 seconds
});
// Item Recipes
this.addRecipe('health_kit', {
name: 'Health Kit',
category: 'items',
description: 'A medical kit that restores health',
requirements: {
crafting: 2
},
materials: [
{ id: 'herbs', quantity: 3 },
{ id: 'bandages', quantity: 2 }
],
results: [
{ id: 'health_kit', quantity: 3 }
],
experience: 5,
craftingTime: 2000 // 2 seconds
});
this.addRecipe('basic_circuit', {
name: 'Basic Circuit',
category: 'items',
description: 'Create a basic electronic circuit',
requirements: {
crafting: 3
},
materials: [
{ id: 'basic_circuitboard', quantity: 1 },
{ id: 'copper_wire', quantity: 2 }
],
results: [
{ id: 'basic_circuit', quantity: 1 }
],
experience: 8,
craftingTime: 2500 // 2.5 seconds
});
this.addRecipe('advanced_circuit', {
name: 'Advanced Circuit',
category: 'items',
description: 'Create an advanced electronic circuit',
requirements: {
crafting: 5
},
materials: [
{ id: 'advanced_circuitboard', quantity: 1 },
{ id: 'energy_crystal', quantity: 2 },
{ id: 'copper_wire', quantity: 3 }
],
results: [
{ id: 'advanced_circuit', quantity: 1 }
],
experience: 15,
craftingTime: 4000 // 4 seconds
});
this.addRecipe('electronic_device', {
name: 'Electronic Device',
category: 'items',
description: 'Create a complex electronic device',
requirements: {
crafting: 7
},
materials: [
{ id: 'advanced_components', quantity: 1 },
{ id: 'battery', quantity: 2 },
{ id: 'common_circuitboard', quantity: 1 }
],
results: [
{ id: 'electronic_device', quantity: 1 }
],
experience: 20,
craftingTime: 5000 // 5 seconds
});
// Ship Component Recipes
this.addRecipe('shield_generator', {
name: 'Shield Generator',
category: 'ships',
description: 'A basic shield generator for ship protection',
requirements: {
engineering: 2,
crafting: 4
},
materials: [
{ id: 'energy_crystal', quantity: 8 },
{ id: 'steel_plate', quantity: 5 },
{ id: 'copper_wire', quantity: 4 }
],
results: [
{ id: 'shield_generator', quantity: 1 }
],
experience: 30,
craftingTime: 8000 // 8 seconds
});
this.addRecipe('engine_upgrade', {
name: 'Engine Upgrade',
category: 'ships',
description: 'An upgrade that improves ship engine performance',
requirements: {
engineering: 5,
crafting: 7
},
materials: [
{ id: 'steel_plate', quantity: 10 },
{ id: 'energy_crystal', quantity: 6 },
{ id: 'rare_metal', quantity: 2 }
],
results: [
{ id: 'engine_upgrade', quantity: 1 }
],
experience: 50,
craftingTime: 10000 // 10 seconds
});
this.addRecipe('quantum_computer', {
name: 'Quantum Computer',
category: 'ships',
description: 'Advanced quantum computer for high-end ship systems',
requirements: {
engineering: 8,
crafting: 10
},
materials: [
{ id: 'advanced_components', quantity: 3 },
{ id: 'energy_crystal', quantity: 8 },
{ id: 'rare_metal', quantity: 4 },
{ id: 'copper_wire', quantity: 6 }
],
results: [
{ id: 'quantum_computer', quantity: 1 }
],
experience: 100,
craftingTime: 15000 // 15 seconds
});
}
addRecipe(id, recipe) {
recipe.id = id;
recipe.unlocked = false;
this.recipes.set(id, recipe);
}
update(deltaTime) {
// Check for newly unlocked recipes
this.checkRecipeUnlocks();
}
checkRecipeUnlocks() {
const skillSystem = this.game.systems.skillSystem;
if (!skillSystem) return;
for (const [id, recipe] of this.recipes) {
if (!recipe.unlocked) {
let canCraft = true;
// Check skill requirements
if (recipe.requirements) {
for (const [skillName, requiredLevel] of Object.entries(recipe.requirements)) {
const skillLevel = skillSystem.getSkillLevel(skillName);
if (skillLevel < requiredLevel) {
canCraft = false;
break;
}
}
}
if (canCraft) {
recipe.unlocked = true;
console.log(`[CRAFTING] Recipe unlocked: ${recipe.name}`);
}
}
}
}
getRecipesByCategory(category) {
return Array.from(this.recipes.values())
.filter(recipe => recipe.category === category);
}
canCraftRecipe(recipeId) {
const recipe = this.recipes.get(recipeId);
if (!recipe) return false;
// Check skill requirements
if (recipe.requirements) {
const skillSystem = this.game.systems.skillSystem;
if (!skillSystem) return false;
for (const [skillName, requiredLevel] of Object.entries(recipe.requirements)) {
const skillLevel = skillSystem.getSkillLevel(skillName);
if (skillLevel < requiredLevel) {
return false;
}
}
}
// Check materials
if (recipe.materials) {
for (const material of recipe.materials) {
const inventory = this.game.systems.inventory;
if (!inventory || !inventory.hasItem(material.id, material.quantity)) {
return false;
}
}
}
return true;
}
getMissingMaterials(recipeId) {
const recipe = this.recipes.get(recipeId);
if (!recipe || !recipe.materials) return [];
const missing = [];
const inventory = this.game.systems.inventory;
console.log(`[CRAFTING DEBUG] Checking materials for recipe: ${recipe.name}`);
console.log(`[CRAFTING DEBUG] Inventory system:`, inventory);
for (const material of recipe.materials) {
let currentCount = 0;
// Safely get current material count
if (inventory && typeof inventory.getItemCount === 'function') {
try {
currentCount = inventory.getItemCount(material.id);
// Ensure we have a valid number
currentCount = typeof currentCount === 'number' && !isNaN(currentCount) ? currentCount : 0;
} catch (error) {
console.log(`[CRAFTING DEBUG] Error getting count for ${material.id}:`, error);
currentCount = 0;
}
console.log(`[CRAFTING DEBUG] Material ${material.id}: current=${currentCount}, required=${material.quantity}`);
} else {
console.log(`[CRAFTING DEBUG] Inventory or getItemCount not available for ${material.id}`);
currentCount = 0;
}
// Ensure required quantity is also a valid number
const requiredQuantity = typeof material.quantity === 'number' && !isNaN(material.quantity) ? material.quantity : 0;
// Check if we have enough materials
if (currentCount < requiredQuantity) {
missing.push({
id: material.id,
required: requiredQuantity,
current: currentCount,
missing: Math.max(0, requiredQuantity - currentCount)
});
}
}
console.log(`[CRAFTING DEBUG] Missing materials:`, missing);
return missing;
}
async craftRecipe(recipeId) {
const recipe = this.recipes.get(recipeId);
if (!recipe) {
console.error(`[CRAFTING] Recipe not found: ${recipeId}`);
return false;
}
if (!this.canCraftRecipe(recipeId)) {
console.log(`[CRAFTING] Cannot craft recipe: ${recipe.name}`);
return false;
}
console.log(`[CRAFTING] Starting to craft: ${recipe.name}`);
// Remove materials
if (recipe.materials) {
for (const material of recipe.materials) {
this.game.systems.inventory.removeItem(material.id, material.quantity);
}
}
// Add crafting experience
if (recipe.experience) {
this.game.systems.skillSystem.awardCraftingExperience(recipe.experience);
}
// Wait for crafting time
await new Promise(resolve => setTimeout(resolve, recipe.craftingTime));
// Add results to inventory
if (recipe.results) {
for (const result of recipe.results) {
this.game.systems.inventory.addItem(result.id, result.quantity);
}
}
// Update quest progress
if (this.game.systems.questSystem) {
this.game.systems.questSystem.onItemCrafted();
}
console.log(`[CRAFTING] Successfully crafted: ${recipe.name}`);
return true;
}
selectRecipe(recipeId) {
this.selectedRecipe = this.recipes.get(recipeId);
return this.selectedRecipe;
}
getSelectedRecipe() {
return this.selectedRecipe;
}
updateUI() {
this.updateRecipeList();
this.updateCraftingDetails();
this.updateCraftingInfo();
}
updateRecipeList() {
const recipeListElement = document.getElementById('recipeList');
if (!recipeListElement) return;
const recipes = this.getRecipesByCategory(this.currentCategory);
recipeListElement.innerHTML = '';
if (recipes.length === 0) {
recipeListElement.innerHTML = '<p class="no-recipes">No recipes available in this category</p>';
return;
}
recipes.forEach(recipe => {
const recipeElement = document.createElement('div');
recipeElement.className = 'recipe-item';
recipeElement.dataset.recipeId = recipe.id;
const canCraft = this.canCraftRecipe(recipe.id);
const missingMaterials = this.getMissingMaterials(recipe.id);
// Check if recipe is unlocked (skill requirements met)
const skillSystem = this.game.systems.skillSystem;
let skillRequirementsMet = true;
if (recipe.requirements && skillSystem) {
for (const [skillName, requiredLevel] of Object.entries(recipe.requirements)) {
const skillLevel = skillSystem.getSkillLevel(skillName);
if (skillLevel < requiredLevel) {
skillRequirementsMet = false;
break;
}
}
}
// Apply styling based on status
if (!skillRequirementsMet) {
recipeElement.classList.add('locked');
} else if (!canCraft) {
recipeElement.classList.add('missing-materials');
} else {
recipeElement.classList.add('can-craft');
}
// Generate requirements text
const requirementsText = recipe.requirements ?
Object.entries(recipe.requirements).map(([skill, level]) => `${skill}: ${level}`).join(', ') : 'None';
// Generate materials with missing status
const materialsHtml = recipe.materials ? recipe.materials.map(mat => {
const missing = missingMaterials.find(m => m.id === mat.id);
const currentCount = missing ? missing.current : 0;
const requiredCount = mat.quantity || 0;
if (missing) {
return `<div class="material-item missing">
<span class="material-name">${mat.id}</span>
<span class="material-quantity">${currentCount}/${requiredCount}</span>
</div>`;
} else {
return `<div class="material-item">
<span class="material-name">${mat.id}</span>
<span class="material-quantity">${currentCount}/${requiredCount}</span>
</div>`;
}
}).join('') : '';
recipeElement.innerHTML = `
<div class="recipe-header">
<h4>${recipe.name}</h4>
<span class="recipe-level">Level ${requirementsText}</span>
</div>
<div class="recipe-description">${recipe.description}</div>
<div class="recipe-materials">
${materialsHtml}
</div>
${missingMaterials.length > 0 ? `
<div class="missing-materials-text">
<i class="fas fa-exclamation-triangle"></i>
Missing: ${missingMaterials.map(m => `${m.missing}x ${m.id}`).join(', ')}
</div>
` : ''}
<div class="recipe-time">
<i class="fas fa-clock"></i>
<span>${recipe.craftingTime / 1000}s</span>
</div>
`;
recipeElement.addEventListener('click', () => {
this.selectRecipe(recipe.id);
this.updateCraftingDetails();
});
recipeListElement.appendChild(recipeElement);
});
}
updateCraftingDetails() {
const detailsElement = document.getElementById('craftingDetails');
if (!detailsElement) return;
if (!this.selectedRecipe) {
detailsElement.innerHTML = `
<div class="selected-recipe">
<h3>Select a Recipe</h3>
<p>Choose a recipe from the list to see details and craft items.</p>
</div>
`;
return;
}
const recipe = this.selectedRecipe;
const canCraft = this.canCraftRecipe(recipe.id);
detailsElement.innerHTML = `
<div class="selected-recipe">
<h3>${recipe.name}</h3>
<p class="recipe-description">${recipe.description}</p>
<div class="recipe-requirements">
<h4>Requirements:</h4>
${recipe.requirements ? Object.entries(recipe.requirements).map(([skill, level]) =>
`<div class="requirement-item">
<span class="skill-name">${skill}</span>
<span class="skill-level">Level ${level}</span>
</div>`
).join('') : '<p>No special requirements</p>'}
</div>
<div class="recipe-materials-needed">
<h4>Materials Needed:</h4>
${recipe.materials ? recipe.materials.map(mat =>
`<div class="material-needed">
<span class="material-name">${mat.id}</span>
<span class="material-needed">x${mat.quantity}</span>
<span class="material-have">Have: ${this.game.systems.inventory?.getItemCount(mat.id) || 0}</span>
</div>`
).join('') : '<p>No materials needed</p>'}
</div>
<div class="recipe-results">
<h4>Results:</h4>
${recipe.results ? recipe.results.map(result =>
`<div class="result-item">
<span class="result-name">${result.id}</span>
<span class="result-quantity">x${result.quantity}</span>
</div>`
).join('') : ''}
</div>
<div class="recipe-info">
<div class="experience-reward">
<i class="fas fa-star"></i>
<span>${recipe.experience} XP</span>
</div>
<div class="crafting-time">
<i class="fas fa-clock"></i>
<span>${recipe.craftingTime / 1000} seconds</span>
</div>
</div>
<button class="btn btn-primary craft-btn ${canCraft ? '' : 'disabled'}"
${canCraft ? `onclick="window.game.systems.crafting.craftRecipe('${recipe.id}')"` : 'disabled'}>
${canCraft ? 'Craft Item' : 'Cannot Craft'}
</button>
</div>
`;
}
updateCraftingInfo() {
const skillSystem = this.game.systems.skillSystem;
if (!skillSystem) return;
const craftingLevel = skillSystem.getSkillLevel('crafting');
const craftingExp = skillSystem.getSkillExperience('crafting');
const expNeeded = skillSystem.getExperienceNeeded('crafting');
const levelElement = document.getElementById('craftingLevel');
const expElement = document.getElementById('craftingExp');
if (levelElement) levelElement.textContent = craftingLevel;
if (expElement) expElement.textContent = `${craftingExp}/${expNeeded}`;
}
switchCategory(category) {
this.currentCategory = category;
this.selectedRecipe = null;
this.updateUI();
}
}
// Export for use in GameEngine
if (typeof module !== 'undefined' && module.exports) {
module.exports = CraftingSystem;
}