658 lines
23 KiB
JavaScript
658 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;
|
|
|
|
// Update UI only if in multiplayer mode or game is actively running
|
|
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
|
|
|
if (shouldUpdateUI) {
|
|
this.updateUI();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Export for use in GameEngine
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = CraftingSystem;
|
|
}
|