fix: SLOT_NAMES export and refactor: split crafting-slice.ts into modules
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m51s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m51s
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
// ─── Equipment Crafting System ──────────────────────────────────────────────
|
||||
// Equipment crafting functions extracted from crafting-slice.ts
|
||||
|
||||
import type { EquipmentInstance, EquipmentCraftingProgress } from './types';
|
||||
import { CRAFTING_RECIPES, canCraftRecipe, type CraftingRecipe } from './data/crafting-recipes';
|
||||
import { EQUIPMENT_TYPES } from './data/equipment';
|
||||
import { generateInstanceId } from './crafting-utils';
|
||||
|
||||
// ─── Equipment Crafting Validation ──────────────────────────────────────────
|
||||
|
||||
// Check if equipment crafting can start
|
||||
export function canStartEquipmentCrafting(
|
||||
blueprintId: string,
|
||||
hasBlueprint: boolean,
|
||||
materials: Record<string, number>,
|
||||
currentMana: number,
|
||||
currentAction: string
|
||||
): { canCraft: boolean; reason?: string; recipe?: CraftingRecipe; missingMaterials?: Record<string, number>; missingMana?: number } {
|
||||
if (currentAction !== 'meditate') {
|
||||
return { canCraft: false, reason: 'Must be in meditate state' };
|
||||
}
|
||||
|
||||
const recipe = CRAFTING_RECIPES[blueprintId];
|
||||
if (!recipe) {
|
||||
return { canCraft: false, reason: 'Invalid blueprint' };
|
||||
}
|
||||
|
||||
if (!hasBlueprint) {
|
||||
return { canCraft: false, reason: 'Blueprint not acquired' };
|
||||
}
|
||||
|
||||
const { canCraft, missingMaterials } = canCraftRecipe(recipe, materials, currentMana);
|
||||
|
||||
if (!canCraft) {
|
||||
const missingMana = Math.max(0, recipe.manaCost - currentMana);
|
||||
return {
|
||||
canCraft: false,
|
||||
reason: missingMana > 0 ? 'Insufficient mana' : 'Missing materials',
|
||||
recipe,
|
||||
missingMaterials,
|
||||
missingMana: missingMana > 0 ? missingMana : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
return { canCraft: true, recipe };
|
||||
}
|
||||
|
||||
// ─── Equipment Crafting Execution ───────────────────────────────────────────
|
||||
|
||||
// Deduct crafting costs and initialize progress
|
||||
export interface CraftingInitResult {
|
||||
recipe: CraftingRecipe;
|
||||
newMaterials: Record<string, number>;
|
||||
manaCost: number;
|
||||
progress: EquipmentCraftingProgress;
|
||||
}
|
||||
|
||||
export function initializeEquipmentCrafting(
|
||||
blueprintId: string,
|
||||
materials: Record<string, number>,
|
||||
currentMana: number
|
||||
): CraftingInitResult {
|
||||
const recipe = CRAFTING_RECIPES[blueprintId];
|
||||
|
||||
// Deduct materials
|
||||
const newMaterials = { ...materials };
|
||||
for (const [matId, amount] of Object.entries(recipe.materials)) {
|
||||
newMaterials[matId] = (newMaterials[matId] || 0) - amount;
|
||||
if (newMaterials[matId] <= 0) {
|
||||
delete newMaterials[matId];
|
||||
}
|
||||
}
|
||||
|
||||
// Create progress
|
||||
const progress: EquipmentCraftingProgress = {
|
||||
blueprintId,
|
||||
equipmentTypeId: recipe.equipmentTypeId,
|
||||
progress: 0,
|
||||
required: recipe.craftTime,
|
||||
manaSpent: recipe.manaCost,
|
||||
};
|
||||
|
||||
return {
|
||||
recipe,
|
||||
newMaterials,
|
||||
manaCost: recipe.manaCost,
|
||||
progress,
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Crafting Progress ──────────────────────────────────────────────────────
|
||||
|
||||
// Calculate crafting progress after a tick
|
||||
export interface CraftingTickResult {
|
||||
progress: number;
|
||||
isComplete: boolean;
|
||||
}
|
||||
|
||||
export function calculateCraftingTick(currentProgress: number, required: number): CraftingTickResult {
|
||||
const progress = currentProgress + 0.04; // HOURS_PER_TICK
|
||||
return {
|
||||
progress,
|
||||
isComplete: progress >= required,
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Crafting Completion ───────────────────────────────────────────────────
|
||||
|
||||
// Create equipment instance from completed crafting
|
||||
export function completeEquipmentCrafting(
|
||||
blueprintId: string,
|
||||
recipe: CraftingRecipe
|
||||
): {
|
||||
instanceId: string;
|
||||
instance: EquipmentInstance;
|
||||
logMessage: string;
|
||||
} {
|
||||
const equipType = EQUIPMENT_TYPES[recipe.equipmentTypeId];
|
||||
if (!equipType) {
|
||||
throw new Error(`Invalid equipment type: ${recipe.equipmentTypeId}`);
|
||||
}
|
||||
|
||||
const instanceId = `equip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
const newInstance: EquipmentInstance = {
|
||||
instanceId,
|
||||
typeId: recipe.equipmentTypeId,
|
||||
name: recipe.name,
|
||||
enchantments: [],
|
||||
usedCapacity: 0,
|
||||
totalCapacity: equipType.baseCapacity,
|
||||
rarity: recipe.rarity,
|
||||
quality: 100,
|
||||
tags: [],
|
||||
};
|
||||
|
||||
return {
|
||||
instanceId,
|
||||
instance: newInstance,
|
||||
logMessage: `🔨 Crafted ${recipe.name}!`,
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Crafting Cancellation ──────────────────────────────────────────────────
|
||||
|
||||
// Cancel active crafting and refund partial resources
|
||||
export interface CraftingCancelResult {
|
||||
manaRefund: number;
|
||||
logMessage: string;
|
||||
}
|
||||
|
||||
export function cancelEquipmentCrafting(blueprintId: string, manaSpent: number): CraftingCancelResult {
|
||||
const recipe = CRAFTING_RECIPES[blueprintId];
|
||||
if (!recipe) {
|
||||
return {
|
||||
manaRefund: 0,
|
||||
logMessage: 'Invalid crafting recipe.',
|
||||
};
|
||||
}
|
||||
|
||||
// Refund 50% of mana
|
||||
const manaRefund = Math.floor(manaSpent * 0.5);
|
||||
|
||||
return {
|
||||
manaRefund,
|
||||
logMessage: `🚫 Equipment crafting cancelled. Refunded ${manaRefund} mana.`,
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Recipe Information ─────────────────────────────────────────────────────
|
||||
|
||||
export function getRecipe(blueprintId: string): CraftingRecipe | null {
|
||||
return CRAFTING_RECIPES[blueprintId] || null;
|
||||
}
|
||||
|
||||
export function getCraftableRecipes(
|
||||
blueprints: string[],
|
||||
materials: Record<string, number>,
|
||||
currentMana: number
|
||||
): CraftingRecipe[] {
|
||||
const craftable: CraftingRecipe[] = [];
|
||||
|
||||
for (const blueprintId of blueprints) {
|
||||
const recipe = CRAFTING_RECIPES[blueprintId];
|
||||
if (!recipe) continue;
|
||||
|
||||
const { canCraft } = canCraftRecipe(recipe, materials, currentMana);
|
||||
if (canCraft) {
|
||||
craftable.push(recipe);
|
||||
}
|
||||
}
|
||||
|
||||
return craftable;
|
||||
}
|
||||
|
||||
// ─── Material Management ────────────────────────────────────────────────────
|
||||
|
||||
// Delete materials from inventory
|
||||
export function deleteMaterials(materialId: string, amount: number, materials: Record<string, number>): {
|
||||
newMaterials: Record<string, number>;
|
||||
deleted: number;
|
||||
} {
|
||||
const currentAmount = materials[materialId] || 0;
|
||||
const deleted = Math.min(amount, currentAmount);
|
||||
const remaining = Math.max(0, currentAmount - amount);
|
||||
const newMaterials = { ...materials };
|
||||
|
||||
if (remaining <= 0) {
|
||||
delete newMaterials[materialId];
|
||||
} else {
|
||||
newMaterials[materialId] = remaining;
|
||||
}
|
||||
|
||||
return {
|
||||
newMaterials,
|
||||
deleted,
|
||||
};
|
||||
}
|
||||
|
||||
// Get total material count
|
||||
export function getMaterialCount(materials: Record<string, number>, materialId: string): number {
|
||||
return materials[materialId] || 0;
|
||||
}
|
||||
|
||||
// Add materials to inventory
|
||||
export function addMaterials(materials: Record<string, number>, materialId: string, amount: number): Record<string, number> {
|
||||
const newMaterials = { ...materials };
|
||||
newMaterials[materialId] = (newMaterials[materialId] || 0) + amount;
|
||||
return newMaterials;
|
||||
}
|
||||
Reference in New Issue
Block a user