fix: replace arcaneShard with elementally attuned materials in Fabricator recipes
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m32s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m32s
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# Circular Dependencies
|
# Circular Dependencies
|
||||||
Generated: 2026-05-27T10:30:41.282Z
|
Generated: 2026-05-27T10:40:00.800Z
|
||||||
|
|
||||||
No circular dependencies found. ✅
|
No circular dependencies found. ✅
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"generated": "2026-05-27T10:30:39.543Z",
|
"generated": "2026-05-27T10:39:58.930Z",
|
||||||
"description": "Import dependency graph for src/lib/game. Keys are files, values are arrays of files they import.",
|
"description": "Import dependency graph for src/lib/game. Keys are files, values are arrays of files they import.",
|
||||||
"usage": "To find what a file affects, search for its path in the VALUES. To find what a file depends on, look at its KEY entry."
|
"usage": "To find what a file affects, search for its path in the VALUES. To find what a file depends on, look at its KEY entry."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
refundCraftMaterials,
|
refundCraftMaterials,
|
||||||
} from '../crafting-utils';
|
} from '../crafting-utils';
|
||||||
|
|
||||||
function makeRecipe(materials = { manaCrystalDust: 5, arcaneShard: 2 }, manaCost = 100): any {
|
function makeRecipe(materials = { manaCrystalDust: 5, earthShard: 2 }, manaCost = 100): any {
|
||||||
return {
|
return {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
equipmentTypeId: 'oakStaff',
|
equipmentTypeId: 'oakStaff',
|
||||||
@@ -22,7 +22,7 @@ function makeRecipe(materials = { manaCrystalDust: 5, arcaneShard: 2 }, manaCost
|
|||||||
|
|
||||||
describe('checkRecipeMaterials', () => {
|
describe('checkRecipeMaterials', () => {
|
||||||
it('should return canCraft true when all materials present', () => {
|
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.canCraft).toBe(true);
|
||||||
expect(result.missingMaterials).toEqual({});
|
expect(result.missingMaterials).toEqual({});
|
||||||
});
|
});
|
||||||
@@ -30,23 +30,23 @@ describe('checkRecipeMaterials', () => {
|
|||||||
it('should return canCraft false when missing materials', () => {
|
it('should return canCraft false when missing materials', () => {
|
||||||
const result = checkRecipeMaterials(makeRecipe(), { manaCrystalDust: 3 });
|
const result = checkRecipeMaterials(makeRecipe(), { manaCrystalDust: 3 });
|
||||||
expect(result.canCraft).toBe(false);
|
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', () => {
|
it('should return canCraft false when materials are empty', () => {
|
||||||
const result = checkRecipeMaterials(makeRecipe(), {} as any);
|
const result = checkRecipeMaterials(makeRecipe(), {} as any);
|
||||||
expect(result.canCraft).toBe(false);
|
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', () => {
|
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.canCraft).toBe(false);
|
||||||
expect(result.missingMaterials).toEqual({ manaCrystalDust: 1 });
|
expect(result.missingMaterials).toEqual({ manaCrystalDust: 1 });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle excess materials', () => {
|
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.canCraft).toBe(true);
|
||||||
expect(result.missingMaterials).toEqual({});
|
expect(result.missingMaterials).toEqual({});
|
||||||
});
|
});
|
||||||
@@ -61,28 +61,28 @@ describe('checkRecipeMaterials', () => {
|
|||||||
|
|
||||||
describe('deductRecipeMaterials', () => {
|
describe('deductRecipeMaterials', () => {
|
||||||
it('should deduct materials correctly', () => {
|
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.manaCrystalDust).toBe(5);
|
||||||
expect(result.arcaneShard).toBe(3);
|
expect(result.earthShard).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove materials that reach zero', () => {
|
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.manaCrystalDust).toBeUndefined();
|
||||||
expect(result.arcaneShard).toBeUndefined();
|
expect(result.earthShard).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not go below zero', () => {
|
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
|
// 3 - 5 = -2 → removed, 1 - 2 = -1 → removed
|
||||||
expect(result.manaCrystalDust).toBeUndefined();
|
expect(result.manaCrystalDust).toBeUndefined();
|
||||||
expect(result.arcaneShard).toBeUndefined();
|
expect(result.earthShard).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should preserve other materials', () => {
|
it('should preserve other materials', () => {
|
||||||
const result = deductRecipeMaterials(makeRecipe(), {
|
const result = deductRecipeMaterials(makeRecipe(), {
|
||||||
manaCrystalDust: 10,
|
manaCrystalDust: 10,
|
||||||
arcaneShard: 5,
|
earthShard: 5,
|
||||||
elementalCore: 3,
|
elementalCore: 3,
|
||||||
});
|
});
|
||||||
expect(result.elementalCore).toBe(3);
|
expect(result.elementalCore).toBe(3);
|
||||||
@@ -96,12 +96,12 @@ describe('deductRecipeMaterials', () => {
|
|||||||
|
|
||||||
describe('refundCraftMaterials', () => {
|
describe('refundCraftMaterials', () => {
|
||||||
it('should refund at default 50% rate', () => {
|
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 5 = 2.5 → floor = 2
|
||||||
// 50% of 2 = 1 → floor = 1
|
// 50% of 2 = 1 → floor = 1
|
||||||
const result = refundCraftMaterials(makeRecipe());
|
const result = refundCraftMaterials(makeRecipe());
|
||||||
expect(result.manaCrystalDust).toBe(2);
|
expect(result.manaCrystalDust).toBe(2);
|
||||||
expect(result.arcaneShard).toBe(1);
|
expect(result.earthShard).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should refund at custom rate', () => {
|
it('should refund at custom rate', () => {
|
||||||
@@ -109,13 +109,13 @@ describe('refundCraftMaterials', () => {
|
|||||||
// 75% of 2 = 1.5 → floor = 1
|
// 75% of 2 = 1.5 → floor = 1
|
||||||
const result = refundCraftMaterials(makeRecipe(), 0.75);
|
const result = refundCraftMaterials(makeRecipe(), 0.75);
|
||||||
expect(result.manaCrystalDust).toBe(3);
|
expect(result.manaCrystalDust).toBe(3);
|
||||||
expect(result.arcaneShard).toBe(1);
|
expect(result.earthShard).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should refund zero at 0% rate', () => {
|
it('should refund zero at 0% rate', () => {
|
||||||
const result = refundCraftMaterials(makeRecipe(), 0);
|
const result = refundCraftMaterials(makeRecipe(), 0);
|
||||||
expect(result.manaCrystalDust).toBe(0);
|
expect(result.manaCrystalDust).toBe(0);
|
||||||
expect(result.arcaneShard).toBe(0);
|
expect(result.earthShard).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should refund full at 100% rate', () => {
|
it('should refund full at 100% rate', () => {
|
||||||
@@ -123,7 +123,7 @@ describe('refundCraftMaterials', () => {
|
|||||||
// 100% of 2 = 2
|
// 100% of 2 = 2
|
||||||
const result = refundCraftMaterials(makeRecipe(), 1);
|
const result = refundCraftMaterials(makeRecipe(), 1);
|
||||||
expect(result.manaCrystalDust).toBe(5);
|
expect(result.manaCrystalDust).toBe(5);
|
||||||
expect(result.arcaneShard).toBe(2);
|
expect(result.earthShard).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should floor fractional refunds', () => {
|
it('should floor fractional refunds', () => {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
|
|||||||
manaType: 'earth',
|
manaType: 'earth',
|
||||||
equipmentTypeId: 'wizardHat',
|
equipmentTypeId: 'wizardHat',
|
||||||
slot: 'head',
|
slot: 'head',
|
||||||
materials: { manaCrystalDust: 4, arcaneShard: 2 },
|
materials: { manaCrystalDust: 4, earthShard: 2 },
|
||||||
manaCost: 200,
|
manaCost: 200,
|
||||||
craftTime: 3,
|
craftTime: 3,
|
||||||
rarity: 'uncommon',
|
rarity: 'uncommon',
|
||||||
@@ -48,7 +48,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
|
|||||||
manaType: 'earth',
|
manaType: 'earth',
|
||||||
equipmentTypeId: 'scholarRobe',
|
equipmentTypeId: 'scholarRobe',
|
||||||
slot: 'body',
|
slot: 'body',
|
||||||
materials: { manaCrystalDust: 8, arcaneShard: 4, elementalCore: 1 },
|
materials: { manaCrystalDust: 8, earthShard: 4, elementalCore: 1 },
|
||||||
manaCost: 500,
|
manaCost: 500,
|
||||||
craftTime: 6,
|
craftTime: 6,
|
||||||
rarity: 'rare',
|
rarity: 'rare',
|
||||||
@@ -61,7 +61,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
|
|||||||
manaType: 'earth',
|
manaType: 'earth',
|
||||||
equipmentTypeId: 'travelerBoots',
|
equipmentTypeId: 'travelerBoots',
|
||||||
slot: 'feet',
|
slot: 'feet',
|
||||||
materials: { manaCrystalDust: 3, arcaneShard: 1 },
|
materials: { manaCrystalDust: 3, earthShard: 1 },
|
||||||
manaCost: 150,
|
manaCost: 150,
|
||||||
craftTime: 2,
|
craftTime: 2,
|
||||||
rarity: 'uncommon',
|
rarity: 'uncommon',
|
||||||
@@ -76,7 +76,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
|
|||||||
manaType: 'metal',
|
manaType: 'metal',
|
||||||
equipmentTypeId: 'steelBlade',
|
equipmentTypeId: 'steelBlade',
|
||||||
slot: 'mainHand',
|
slot: 'mainHand',
|
||||||
materials: { manaCrystalDust: 6, arcaneShard: 3, elementalCore: 2 },
|
materials: { manaCrystalDust: 6, metalShard: 3, elementalCore: 2 },
|
||||||
manaCost: 400,
|
manaCost: 400,
|
||||||
craftTime: 5,
|
craftTime: 5,
|
||||||
rarity: 'rare',
|
rarity: 'rare',
|
||||||
@@ -89,7 +89,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
|
|||||||
manaType: 'metal',
|
manaType: 'metal',
|
||||||
equipmentTypeId: 'metalSpellFocus',
|
equipmentTypeId: 'metalSpellFocus',
|
||||||
slot: 'offHand',
|
slot: 'offHand',
|
||||||
materials: { manaCrystalDust: 7, arcaneShard: 4, elementalCore: 1 },
|
materials: { manaCrystalDust: 7, metalShard: 4, elementalCore: 1 },
|
||||||
manaCost: 450,
|
manaCost: 450,
|
||||||
craftTime: 5,
|
craftTime: 5,
|
||||||
rarity: 'rare',
|
rarity: 'rare',
|
||||||
@@ -102,7 +102,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
|
|||||||
manaType: 'metal',
|
manaType: 'metal',
|
||||||
equipmentTypeId: 'spellweaveGloves',
|
equipmentTypeId: 'spellweaveGloves',
|
||||||
slot: 'hands',
|
slot: 'hands',
|
||||||
materials: { manaCrystalDust: 4, arcaneShard: 2 },
|
materials: { manaCrystalDust: 4, metalShard: 2 },
|
||||||
manaCost: 250,
|
manaCost: 250,
|
||||||
craftTime: 3,
|
craftTime: 3,
|
||||||
rarity: 'uncommon',
|
rarity: 'uncommon',
|
||||||
@@ -117,7 +117,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
|
|||||||
manaType: 'crystal',
|
manaType: 'crystal',
|
||||||
equipmentTypeId: 'crystalWand',
|
equipmentTypeId: 'crystalWand',
|
||||||
slot: 'mainHand',
|
slot: 'mainHand',
|
||||||
materials: { manaCrystalDust: 10, arcaneShard: 5, elementalCore: 3 },
|
materials: { manaCrystalDust: 10, crystalShard: 5, elementalCore: 3 },
|
||||||
manaCost: 600,
|
manaCost: 600,
|
||||||
craftTime: 6,
|
craftTime: 6,
|
||||||
rarity: 'epic',
|
rarity: 'epic',
|
||||||
@@ -130,7 +130,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
|
|||||||
manaType: 'crystal',
|
manaType: 'crystal',
|
||||||
equipmentTypeId: 'silverRing',
|
equipmentTypeId: 'silverRing',
|
||||||
slot: 'accessory1',
|
slot: 'accessory1',
|
||||||
materials: { manaCrystalDust: 5, arcaneShard: 3, elementalCore: 1 },
|
materials: { manaCrystalDust: 5, crystalShard: 3, elementalCore: 1 },
|
||||||
manaCost: 350,
|
manaCost: 350,
|
||||||
craftTime: 3,
|
craftTime: 3,
|
||||||
rarity: 'rare',
|
rarity: 'rare',
|
||||||
@@ -143,7 +143,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
|
|||||||
manaType: 'crystal',
|
manaType: 'crystal',
|
||||||
equipmentTypeId: 'silverAmulet',
|
equipmentTypeId: 'silverAmulet',
|
||||||
slot: 'accessory2',
|
slot: 'accessory2',
|
||||||
materials: { manaCrystalDust: 6, arcaneShard: 3, elementalCore: 2 },
|
materials: { manaCrystalDust: 6, crystalShard: 3, elementalCore: 2 },
|
||||||
manaCost: 400,
|
manaCost: 400,
|
||||||
craftTime: 4,
|
craftTime: 4,
|
||||||
rarity: 'rare',
|
rarity: 'rare',
|
||||||
@@ -158,7 +158,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
|
|||||||
manaType: 'sand',
|
manaType: 'sand',
|
||||||
equipmentTypeId: 'travelerBoots',
|
equipmentTypeId: 'travelerBoots',
|
||||||
slot: 'feet',
|
slot: 'feet',
|
||||||
materials: { manaCrystalDust: 3, arcaneShard: 1 },
|
materials: { manaCrystalDust: 3, sandShard: 1 },
|
||||||
manaCost: 120,
|
manaCost: 120,
|
||||||
craftTime: 2,
|
craftTime: 2,
|
||||||
rarity: 'uncommon',
|
rarity: 'uncommon',
|
||||||
@@ -171,7 +171,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
|
|||||||
manaType: 'sand',
|
manaType: 'sand',
|
||||||
equipmentTypeId: 'spellweaveGloves',
|
equipmentTypeId: 'spellweaveGloves',
|
||||||
slot: 'hands',
|
slot: 'hands',
|
||||||
materials: { manaCrystalDust: 3, arcaneShard: 2 },
|
materials: { manaCrystalDust: 3, sandShard: 2 },
|
||||||
manaCost: 140,
|
manaCost: 140,
|
||||||
craftTime: 2,
|
craftTime: 2,
|
||||||
rarity: 'uncommon',
|
rarity: 'uncommon',
|
||||||
@@ -184,7 +184,7 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [
|
|||||||
manaType: 'sand',
|
manaType: 'sand',
|
||||||
equipmentTypeId: 'scholarRobe',
|
equipmentTypeId: 'scholarRobe',
|
||||||
slot: 'body',
|
slot: 'body',
|
||||||
materials: { manaCrystalDust: 5, arcaneShard: 2, elementalCore: 1 },
|
materials: { manaCrystalDust: 5, sandShard: 2, elementalCore: 1 },
|
||||||
manaCost: 300,
|
manaCost: 300,
|
||||||
craftTime: 4,
|
craftTime: 4,
|
||||||
rarity: 'rare',
|
rarity: 'rare',
|
||||||
|
|||||||
@@ -20,6 +20,38 @@ export const LOOT_DROPS: Record<string, LootDrop> = {
|
|||||||
minFloor: 10,
|
minFloor: 10,
|
||||||
dropChance: 0.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: {
|
elementalCore: {
|
||||||
id: 'elementalCore',
|
id: 'elementalCore',
|
||||||
name: 'Elemental Core',
|
name: 'Elemental Core',
|
||||||
|
|||||||
Reference in New Issue
Block a user