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

This commit is contained in:
Refactoring Agent
2026-05-02 10:59:36 +02:00
parent dc38445225
commit c9ae2576f4
14 changed files with 2213 additions and 942 deletions
+277
View File
@@ -0,0 +1,277 @@
// ─── Crafting Loot Inventory System ────────────────────────────────────────────
// Loot inventory functions extracted from crafting-slice.ts
import type { LootInventory } from './types';
import type { CraftingRecipe } from './data/crafting-recipes';
// ─── Inventory Queries ──────────────────────────────────────────────────────
// Get material count
export function getMaterialCount(inventory: LootInventory, materialId: string): number {
return inventory.materials[materialId] || 0;
}
// Check if has blueprint
export function hasBlueprint(inventory: LootInventory, blueprintId: string): boolean {
return inventory.blueprints.includes(blueprintId);
}
// Check if has any materials
export function hasMaterials(inventory: LootInventory): boolean {
return Object.keys(inventory.materials).length > 0;
}
// Get total number of unique materials
export function getUniqueMaterialCount(inventory: LootInventory): number {
return Object.keys(inventory.materials).length;
}
// Get total material stacks (sum of all quantities)
export function getTotalMaterialStacks(inventory: LootInventory): number {
return Object.values(inventory.materials).reduce((sum, qty) => sum + qty, 0);
}
// ─── Inventory Modifications ────────────────────────────────────────────────
// Add materials to inventory
export function addMaterial(inventory: LootInventory, materialId: string, amount: number): LootInventory {
const currentAmount = inventory.materials[materialId] || 0;
return {
...inventory,
materials: {
...inventory.materials,
[materialId]: currentAmount + amount,
},
};
}
// Add multiple materials at once
export function addMaterials(
inventory: LootInventory,
materials: Record<string, number>
): LootInventory {
const newMaterials = { ...inventory.materials };
for (const [matId, amount] of Object.entries(materials)) {
newMaterials[matId] = (newMaterials[matId] || 0) + amount;
}
return {
...inventory,
materials: newMaterials,
};
}
// Remove materials from inventory
export function removeMaterial(inventory: LootInventory, materialId: string, amount: number): {
inventory: LootInventory;
removed: number;
} {
const currentAmount = inventory.materials[materialId] || 0;
const removed = Math.min(amount, currentAmount);
const remaining = Math.max(0, currentAmount - amount);
const newMaterials = { ...inventory.materials };
if (remaining <= 0) {
delete newMaterials[materialId];
} else {
newMaterials[materialId] = remaining;
}
return {
inventory: {
...inventory,
materials: newMaterials,
},
removed,
};
}
// Delete materials completely (admin/debug operation)
export function deleteMaterial(inventory: LootInventory, materialId: string): LootInventory {
const newMaterials = { ...inventory.materials };
delete newMaterials[materialId];
return {
...inventory,
materials: newMaterials,
};
}
// Clear all materials
export function clearMaterials(inventory: LootInventory): LootInventory {
return {
...inventory,
materials: {},
};
}
// ─── Blueprint Management ──────────────────────────────────────────────────
// Add a blueprint
export function addBlueprint(inventory: LootInventory, blueprintId: string): LootInventory {
if (inventory.blueprints.includes(blueprintId)) {
return inventory;
}
return {
...inventory,
blueprints: [...inventory.blueprints, blueprintId],
};
}
// Remove a blueprint
export function removeBlueprint(inventory: LootInventory, blueprintId: string): LootInventory {
return {
...inventory,
blueprints: inventory.blueprints.filter(id => id !== blueprintId),
};
}
// Check and remove consumed blueprint (if single-use)
export function consumeBlueprint(inventory: LootInventory, blueprintId: string): LootInventory {
// Blueprints are persistent for now, but this function provides future flexibility
return inventory;
}
// ─── Recipe Material Checks ─────────────────────────────────────────────────
// Check if specific materials are available
export function checkMaterialsAvailable(
inventory: LootInventory,
required: Record<string, number>
): { hasAll: boolean; missing: Record<string, number> } {
const missing: Record<string, number> = {};
let hasAll = true;
for (const [matId, amount] of Object.entries(required)) {
const available = inventory.materials[matId] || 0;
if (available < amount) {
missing[matId] = amount - available;
hasAll = false;
}
}
return { hasAll, missing };
}
// Deduct recipe materials
export function deductRecipeMaterials(
inventory: LootInventory,
recipeMaterials: Record<string, number>
): LootInventory {
const newMaterials = { ...inventory.materials };
for (const [matId, amount] of Object.entries(recipeMaterials)) {
const newAmount = (newMaterials[matId] || 0) - amount;
if (newAmount <= 0) {
delete newMaterials[matId];
} else {
newMaterials[matId] = newAmount;
}
}
return {
...inventory,
materials: newMaterials,
};
}
// ─── Inventory Filters & Sorting ────────────────────────────────────────────
export interface MaterialWithInfo {
id: string;
quantity: number;
name: string;
rarity: string;
}
// Get all materials with their info
export function getAllMaterials(inventory: LootInventory): MaterialWithInfo[] {
return Object.entries(inventory.materials).map(([id, quantity]) => ({
id,
quantity,
name: id, // Could be replaced with lookup from LOOT_DROPS
rarity: 'common', // Could be replaced with lookup
}));
}
// Filter materials by minimum quantity
export function filterMaterialsByQuantity(
inventory: LootInventory,
minQuantity: number
): Record<string, number> {
const filtered: Record<string, number> = {};
for (const [id, qty] of Object.entries(inventory.materials)) {
if (qty >= minQuantity) {
filtered[id] = qty;
}
}
return filtered;
}
// ─── Crafting Availability ─────────────────────────────────────────────────
// Check if can craft a recipe
export function canCraftFromInventory(
inventory: LootInventory,
recipe: CraftingRecipe,
currentMana: number
): { canCraft: boolean; reason?: string; missingMaterials?: Record<string, number>; missingMana?: number } {
const { hasAll, missing } = checkMaterialsAvailable(inventory, recipe.materials);
if (!hasAll) {
return { canCraft: false, missingMaterials: missing };
}
if (currentMana < recipe.manaCost) {
return {
canCraft: false,
missingMana: recipe.manaCost - currentMana,
reason: 'Insufficient mana',
};
}
if (!inventory.blueprints.includes(recipe.id)) {
return { canCraft: false, reason: 'Blueprint not acquired' };
}
return { canCraft: true };
}
// Get all craftable recipes from inventory
export function getCraftableRecipes(
inventory: LootInventory,
recipes: Record<string, CraftingRecipe>,
currentMana: number
): CraftingRecipe[] {
const craftable: CraftingRecipe[] = [];
for (const blueprintId of inventory.blueprints) {
const recipe = recipes[blueprintId];
if (!recipe) continue;
const { canCraft } = canCraftFromInventory(inventory, recipe, currentMana);
if (canCraft) {
craftable.push(recipe);
}
}
return craftable;
}
// ─── Inventory Statistics ──────────────────────────────────────────────────
export interface InventoryStats {
totalUniqueMaterials: number;
totalMaterialStacks: number;
totalBlueprints: number;
craftableItems: string[];
}
export function getInventoryStats(inventory: LootInventory): InventoryStats {
const totalUniqueMaterials = Object.keys(inventory.materials).length;
const totalMaterialStacks = Object.values(inventory.materials).reduce((sum, qty) => sum + qty, 0);
const totalBlueprints = inventory.blueprints.length;
return {
totalUniqueMaterials,
totalMaterialStacks,
totalBlueprints,
craftableItems: [], // Would need recipes to compute
};
}