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,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
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user