fix: replace arcaneShard with elementally attuned materials in Fabricator recipes
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m32s

This commit is contained in:
2026-05-27 12:56:06 +02:00
parent 2c88d3c395
commit cbeb0b50ad
5 changed files with 64 additions and 32 deletions
@@ -5,7 +5,7 @@ import {
refundCraftMaterials,
} from '../crafting-utils';
function makeRecipe(materials = { manaCrystalDust: 5, arcaneShard: 2 }, manaCost = 100): any {
function makeRecipe(materials = { manaCrystalDust: 5, earthShard: 2 }, manaCost = 100): any {
return {
id: 'test',
equipmentTypeId: 'oakStaff',
@@ -22,7 +22,7 @@ function makeRecipe(materials = { manaCrystalDust: 5, arcaneShard: 2 }, manaCost
describe('checkRecipeMaterials', () => {
it('should return canCraft true when all materials present', () => {
const result = checkRecipeMaterials(makeRecipe(), { manaCrystalDust: 5, arcaneShard: 2 });
const result = checkRecipeMaterials(makeRecipe(), { manaCrystalDust: 5, earthShard: 2 });
expect(result.canCraft).toBe(true);
expect(result.missingMaterials).toEqual({});
});
@@ -30,23 +30,23 @@ describe('checkRecipeMaterials', () => {
it('should return canCraft false when missing materials', () => {
const result = checkRecipeMaterials(makeRecipe(), { manaCrystalDust: 3 });
expect(result.canCraft).toBe(false);
expect(result.missingMaterials).toEqual({ manaCrystalDust: 2, arcaneShard: 2 });
expect(result.missingMaterials).toEqual({ manaCrystalDust: 2, earthShard: 2 });
});
it('should return canCraft false when materials are empty', () => {
const result = checkRecipeMaterials(makeRecipe(), {} as any);
expect(result.canCraft).toBe(false);
expect(result.missingMaterials).toEqual({ manaCrystalDust: 5, arcaneShard: 2 });
expect(result.missingMaterials).toEqual({ manaCrystalDust: 5, earthShard: 2 });
});
it('should handle partial shortage', () => {
const result = checkRecipeMaterials(makeRecipe(), { manaCrystalDust: 4, arcaneShard: 2 });
const result = checkRecipeMaterials(makeRecipe(), { manaCrystalDust: 4, earthShard: 2 });
expect(result.canCraft).toBe(false);
expect(result.missingMaterials).toEqual({ manaCrystalDust: 1 });
});
it('should handle excess materials', () => {
const result = checkRecipeMaterials(makeRecipe(), { manaCrystalDust: 10, arcaneShard: 5 });
const result = checkRecipeMaterials(makeRecipe(), { manaCrystalDust: 10, earthShard: 5 });
expect(result.canCraft).toBe(true);
expect(result.missingMaterials).toEqual({});
});
@@ -61,28 +61,28 @@ describe('checkRecipeMaterials', () => {
describe('deductRecipeMaterials', () => {
it('should deduct materials correctly', () => {
const result = deductRecipeMaterials(makeRecipe(), { manaCrystalDust: 10, arcaneShard: 5 });
const result = deductRecipeMaterials(makeRecipe(), { manaCrystalDust: 10, earthShard: 5 });
expect(result.manaCrystalDust).toBe(5);
expect(result.arcaneShard).toBe(3);
expect(result.earthShard).toBe(3);
});
it('should remove materials that reach zero', () => {
const result = deductRecipeMaterials(makeRecipe(), { manaCrystalDust: 5, arcaneShard: 2 });
const result = deductRecipeMaterials(makeRecipe(), { manaCrystalDust: 5, earthShard: 2 });
expect(result.manaCrystalDust).toBeUndefined();
expect(result.arcaneShard).toBeUndefined();
expect(result.earthShard).toBeUndefined();
});
it('should not go below zero', () => {
const result = deductRecipeMaterials(makeRecipe(), { manaCrystalDust: 3, arcaneShard: 1 });
const result = deductRecipeMaterials(makeRecipe(), { manaCrystalDust: 3, earthShard: 1 });
// 3 - 5 = -2 → removed, 1 - 2 = -1 → removed
expect(result.manaCrystalDust).toBeUndefined();
expect(result.arcaneShard).toBeUndefined();
expect(result.earthShard).toBeUndefined();
});
it('should preserve other materials', () => {
const result = deductRecipeMaterials(makeRecipe(), {
manaCrystalDust: 10,
arcaneShard: 5,
earthShard: 5,
elementalCore: 3,
});
expect(result.elementalCore).toBe(3);
@@ -96,12 +96,12 @@ describe('deductRecipeMaterials', () => {
describe('refundCraftMaterials', () => {
it('should refund at default 50% rate', () => {
// Default recipe: { manaCrystalDust: 5, arcaneShard: 2 }
// Default recipe: { manaCrystalDust: 5, earthShard: 2 }
// 50% of 5 = 2.5 → floor = 2
// 50% of 2 = 1 → floor = 1
const result = refundCraftMaterials(makeRecipe());
expect(result.manaCrystalDust).toBe(2);
expect(result.arcaneShard).toBe(1);
expect(result.earthShard).toBe(1);
});
it('should refund at custom rate', () => {
@@ -109,13 +109,13 @@ describe('refundCraftMaterials', () => {
// 75% of 2 = 1.5 → floor = 1
const result = refundCraftMaterials(makeRecipe(), 0.75);
expect(result.manaCrystalDust).toBe(3);
expect(result.arcaneShard).toBe(1);
expect(result.earthShard).toBe(1);
});
it('should refund zero at 0% rate', () => {
const result = refundCraftMaterials(makeRecipe(), 0);
expect(result.manaCrystalDust).toBe(0);
expect(result.arcaneShard).toBe(0);
expect(result.earthShard).toBe(0);
});
it('should refund full at 100% rate', () => {
@@ -123,7 +123,7 @@ describe('refundCraftMaterials', () => {
// 100% of 2 = 2
const result = refundCraftMaterials(makeRecipe(), 1);
expect(result.manaCrystalDust).toBe(5);
expect(result.arcaneShard).toBe(2);
expect(result.earthShard).toBe(2);
});
it('should floor fractional refunds', () => {
+12 -12
View File
@@ -35,7 +35,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
manaType: 'earth',
equipmentTypeId: 'wizardHat',
slot: 'head',
materials: { manaCrystalDust: 4, arcaneShard: 2 },
materials: { manaCrystalDust: 4, earthShard: 2 },
manaCost: 200,
craftTime: 3,
rarity: 'uncommon',
@@ -48,7 +48,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
manaType: 'earth',
equipmentTypeId: 'scholarRobe',
slot: 'body',
materials: { manaCrystalDust: 8, arcaneShard: 4, elementalCore: 1 },
materials: { manaCrystalDust: 8, earthShard: 4, elementalCore: 1 },
manaCost: 500,
craftTime: 6,
rarity: 'rare',
@@ -61,7 +61,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
manaType: 'earth',
equipmentTypeId: 'travelerBoots',
slot: 'feet',
materials: { manaCrystalDust: 3, arcaneShard: 1 },
materials: { manaCrystalDust: 3, earthShard: 1 },
manaCost: 150,
craftTime: 2,
rarity: 'uncommon',
@@ -76,7 +76,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
manaType: 'metal',
equipmentTypeId: 'steelBlade',
slot: 'mainHand',
materials: { manaCrystalDust: 6, arcaneShard: 3, elementalCore: 2 },
materials: { manaCrystalDust: 6, metalShard: 3, elementalCore: 2 },
manaCost: 400,
craftTime: 5,
rarity: 'rare',
@@ -89,7 +89,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
manaType: 'metal',
equipmentTypeId: 'metalSpellFocus',
slot: 'offHand',
materials: { manaCrystalDust: 7, arcaneShard: 4, elementalCore: 1 },
materials: { manaCrystalDust: 7, metalShard: 4, elementalCore: 1 },
manaCost: 450,
craftTime: 5,
rarity: 'rare',
@@ -102,7 +102,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
manaType: 'metal',
equipmentTypeId: 'spellweaveGloves',
slot: 'hands',
materials: { manaCrystalDust: 4, arcaneShard: 2 },
materials: { manaCrystalDust: 4, metalShard: 2 },
manaCost: 250,
craftTime: 3,
rarity: 'uncommon',
@@ -117,7 +117,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
manaType: 'crystal',
equipmentTypeId: 'crystalWand',
slot: 'mainHand',
materials: { manaCrystalDust: 10, arcaneShard: 5, elementalCore: 3 },
materials: { manaCrystalDust: 10, crystalShard: 5, elementalCore: 3 },
manaCost: 600,
craftTime: 6,
rarity: 'epic',
@@ -130,7 +130,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
manaType: 'crystal',
equipmentTypeId: 'silverRing',
slot: 'accessory1',
materials: { manaCrystalDust: 5, arcaneShard: 3, elementalCore: 1 },
materials: { manaCrystalDust: 5, crystalShard: 3, elementalCore: 1 },
manaCost: 350,
craftTime: 3,
rarity: 'rare',
@@ -143,7 +143,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
manaType: 'crystal',
equipmentTypeId: 'silverAmulet',
slot: 'accessory2',
materials: { manaCrystalDust: 6, arcaneShard: 3, elementalCore: 2 },
materials: { manaCrystalDust: 6, crystalShard: 3, elementalCore: 2 },
manaCost: 400,
craftTime: 4,
rarity: 'rare',
@@ -158,7 +158,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
manaType: 'sand',
equipmentTypeId: 'travelerBoots',
slot: 'feet',
materials: { manaCrystalDust: 3, arcaneShard: 1 },
materials: { manaCrystalDust: 3, sandShard: 1 },
manaCost: 120,
craftTime: 2,
rarity: 'uncommon',
@@ -171,7 +171,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
manaType: 'sand',
equipmentTypeId: 'spellweaveGloves',
slot: 'hands',
materials: { manaCrystalDust: 3, arcaneShard: 2 },
materials: { manaCrystalDust: 3, sandShard: 2 },
manaCost: 140,
craftTime: 2,
rarity: 'uncommon',
@@ -184,7 +184,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
manaType: 'sand',
equipmentTypeId: 'scholarRobe',
slot: 'body',
materials: { manaCrystalDust: 5, arcaneShard: 2, elementalCore: 1 },
materials: { manaCrystalDust: 5, sandShard: 2, elementalCore: 1 },
manaCost: 300,
craftTime: 4,
rarity: 'rare',
+32
View File
@@ -20,6 +20,38 @@ export const LOOT_DROPS: Record<string, LootDrop> = {
minFloor: 10,
dropChance: 0.10,
},
earthShard: {
id: 'earthShard',
name: 'Earth Attuned Shard',
rarity: 'uncommon',
type: 'material',
minFloor: 10,
dropChance: 0.08,
},
metalShard: {
id: 'metalShard',
name: 'Metal Attuned Shard',
rarity: 'rare',
type: 'material',
minFloor: 20,
dropChance: 0.06,
},
crystalShard: {
id: 'crystalShard',
name: 'Crystal Attuned Shard',
rarity: 'rare',
type: 'material',
minFloor: 30,
dropChance: 0.05,
},
sandShard: {
id: 'sandShard',
name: 'Sand Attuned Shard',
rarity: 'uncommon',
type: 'material',
minFloor: 15,
dropChance: 0.07,
},
elementalCore: {
id: 'elementalCore',
name: 'Elemental Core',