feat: implement DoT/debuff runtime system (spec §6, AC-12, AC-13)
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m18s

- Add ActiveEffect, EffectType types to game.ts; activeEffects + effectiveArmor on EnemyState
- Add SpellOnHitEffect + onHitEffect field to SpellDefinition
- Wire onHitEffect to fire (burn), death (curse), lightning (armor_corrode), frost (freeze), soul (bypassArmor burn)
- Add applyOnHitEffect() — applies on-hit effect on successful spell hit (spec §6.2)
- Add processDoTPhase() — ticks all active effects after weapon/golem attacks (spec §6.3)
- Add bypassArmor/bypassBarrier support in applyEnemyDefenses() (AC-13)
- Export standalone applyEnemyDefenses from combat-tick.ts for DoT pipeline
- Split DoT runtime into separate dot-runtime.ts (135 lines) to keep combat-actions.ts under 400 lines
- Update all enemy generation sites with activeEffects/effectiveArmor defaults
- Fix test helpers for new required fields

All 921 tests pass (45 test files)
This commit is contained in:
2026-06-03 18:38:01 +02:00
parent a2cdf6d21c
commit b506f0bcc3
30 changed files with 3272 additions and 71 deletions
@@ -0,0 +1,333 @@
# Golemancy System — Design Spec
> Describes the Fabricator attunement's combat system: golem types, loadout
> configuration, summoning lifecycle, maintenance costs, room duration, combat
> behavior, and discipline interactions.
>
> **⚠ Spec-defined, implementation pending.** This spec is based on
> `docs/specs/spire-combat-spec.md` §9 and represents the intended design.
> The current code has golem data defined but disconnected from the combat pipeline.
---
## 1. Objective
Golemancy is the Fabricator attunement's combat contribution. The player configures
a golem loadout outside the spire, then golems are automatically summoned at each
room entry, fight alongside the player, and disappear after a fixed number of rooms
or if their maintenance cost cannot be met.
**Design goals:**
- Golems provide parallel combat damage independent of the player's spells
- Different golem types offer tactical variety (single-target, AoE, fast, tanky)
- Maintenance cost and room duration create resource management decisions
- Hybrid golems require dual-attunement investment (Enchanter 5 + Fabricator 5)
- Golem loadout configuration outside spire allows strategic planning
---
## 2. Golem Slot Formula
Golem slots come from **two sources** that add together:
### 2.1 From Attunement Level
```
attunementSlots = floor(fabricatorLevel / 2)
```
| Fabricator Level | Slots |
|---|---|
| 1 | 0 |
| 23 | 1 |
| 45 | 2 |
| 67 | 3 |
| 89 | 4 |
| 10 | 5 |
### 2.2 From Discipline
The Golem Crafting discipline provides:
- Base `golemCapacity`: +2
- Perk `golem-2` (capped, threshold 500, maxTier 2): +1 per tier = up to +2
**Maximum total golem slots: 5 (attunement) + 2 (discipline) = 7**
> **Note:** The AGENTS.md states `floor(fabricatorLevel / 2)` with max 5 at level 10.
> The discipline-based capacity is additive on top of this.
---
## 3. Golem Loadout Configuration
The player configures a **golem loadout** from the Golemancy tab before entering
the spire. The loadout defines which golems to attempt to summon and in what order.
This configuration persists across rooms but not across spire runs.
The loadout is a prioritized list of golem IDs. On each room entry, the system
iterates the loadout in order, attempting to summon each golem.
---
## 4. All 10 Golem Types
### 4.1 Base Golems (1)
| Field | Earth Golem |
|---|---|
| **ID** | `earthGolem` |
| **Tier** | 1 |
| **Element** | Earth |
| **Damage** | 8 |
| **Attack Speed** | 1.5/hr |
| **HP** (display) | 50 |
| **Armor Pierce** | 15% |
| **AoE** | No |
| **Max Room Duration** | 3 |
| **Summon Cost** | 10 earth |
| **Maintenance Cost** | 0.5 earth/hr |
| **Unlock** | Fabricator level 2 |
### 4.2 Elemental Golems (3)
| Field | Steel Golem | Crystal Golem | Sand Golem |
|---|---|---|---|
| **ID** | `steelGolem` | `crystalGolem` | `sandGolem` |
| **Tier** | 2 | 3 | 2 |
| **Element** | Metal | Crystal | Sand |
| **Damage** | 12 | 18 | 10 |
| **Attack Speed** | 1.2/hr | 1.0/hr | 2.0/hr |
| **HP** (display) | 60 | 40 | 45 |
| **Armor Pierce** | 35% | 25% | 15% |
| **AoE** | No | No | **Yes (2 targets)** |
| **Max Room Duration** | 3 | 4 | 3 |
| **Summon Cost** | 8 metal + 5 earth | 6 crystal + 3 earth | 10 sand + 4 earth |
| **Maintenance Cost** | 0.6 metal + 0.2 earth/hr | 0.4 crystal + 0.2 earth/hr | 0.6 sand + 0.25 earth/hr |
| **Unlock** | Metal mana unlocked | Crystal mana unlocked | Sand mana unlocked |
### 4.3 Hybrid Golems (6) — Require Enchanter 5 + Fabricator 5
| Field | Lava Golem | Galvanic Golem | Obsidian Golem |
|---|---|---|---|
| **ID** | `lavaGolem` | `galvanicGolem` | `obsidianGolem` |
| **Tier** | 3 | 3 | 4 |
| **Elements** | Earth + Fire | Metal + Lightning | Earth + Dark |
| **Damage** | 15 | 10 | 25 |
| **Attack Speed** | 1.0/hr | 3.5/hr | 0.8/hr |
| **HP** (display) | 70 | 45 | 55 |
| **Armor Pierce** | 20% | 45% | 50% |
| **AoE** | **Yes (2 targets)** | No | No |
| **Max Room Duration** | 4 | 4 | 5 |
| **Summon Cost** | 15 earth + 12 fire | 12 metal + 8 lightning | 18 earth + 10 dark |
| **Maintenance Cost** | 0.6 earth + 0.7 fire/hr | 0.4 metal + 0.7 lightning/hr | 0.5 earth + 0.6 dark/hr |
| **Special** | Burn DoT | Lightning Speed | Devastating Strike |
| **Unlock** | Enchanter 5 + Fabricator 5 | Enchanter 5 + Fabricator 5 | Enchanter 5 + Fabricator 5 |
| Field | Prism Golem | Quicksilver Golem | Voidstone Golem |
|---|---|---|---|
| **ID** | `prismGolem` | `quicksilverGolem` | `voidstoneGolem` |
| **Tier** | 4 | 3 | 4 |
| **Elements** | Crystal + Light | Metal + Water | Earth + Void |
| **Damage** | 28 | 14 | **40** |
| **Attack Speed** | 2.0/hr | **4.0/hr** | 0.6/hr |
| **HP** (display) | 60 | 55 | **100** |
| **Armor Pierce** | 45% | 35% | **60%** |
| **AoE** | **Yes (3 targets)** | No | **Yes (3 targets)** |
| **Max Room Duration** | 5 | 4 | 5 |
| **Summon Cost** | 16 crystal + 10 light | 10 metal + 8 water | 22 earth + 14 void |
| **Maintenance Cost** | 0.6 crystal + 0.6 light/hr | 0.4 metal + 0.4 water/hr | 0.5 earth + 0.9 void/hr |
| **Special** | Piercing Beams | Flow (evasion) | Void Infusion |
| **Unlock** | Enchanter 5 + Fabricator 5 | Enchanter 5 + Fabricator 5 | Enchanter 5 + Fabricator 5 |
### 4.4 Summary Table
| Golem | Tier | DMG | SPD | HP | Pierce | AoE | Targets | Rooms | Unlock |
|---|---|---|---|---|---|---|---|---|---|
| Earth | 1 | 8 | 1.5 | 50 | 15% | No | 1 | 3 | Fabricator Lv2 |
| Steel | 2 | 12 | 1.2 | 60 | 35% | No | 1 | 3 | Metal mana |
| Crystal | 3 | 18 | 1.0 | 40 | 25% | No | 1 | 4 | Crystal mana |
| Sand | 2 | 10 | 2.0 | 45 | 15% | Yes | 2 | 3 | Sand mana |
| Lava | 3 | 15 | 1.0 | 70 | 20% | Yes | 2 | 4 | Ench5+Fab5 |
| Galvanic | 3 | 10 | 3.5 | 45 | 45% | No | 1 | 4 | Ench5+Fab5 |
| Obsidian | 4 | 25 | 0.8 | 55 | 50% | No | 1 | 5 | Ench5+Fab5 |
| Prism | 4 | 28 | 2.0 | 60 | 45% | Yes | 3 | 5 | Ench5+Fab5 |
| Quicksilver | 3 | 14 | 4.0 | 55 | 35% | No | 1 | 4 | Ench5+Fab5 |
| Voidstone | 4 | 40 | 0.6 | 100 | 60% | Yes | 3 | 5 | Ench5+Fab5 |
---
## 5. Summoning on Room Entry
When the player enters a new combat room:
```
onRoomEntry():
for each golem in golemLoadout:
if player has enough mana of golem.summonCostType >= golem.summonCost:
deductMana(golem.summonCost, golem.summonCostType)
activeGolems.push({
...golemDef,
roomsRemaining: golemDef.maxRoomDuration,
attackProgress: 0,
})
activityLog("${golem.name} summoned")
else:
activityLog("Not enough mana to summon ${golem.name} — skipped")
```
**Key rules:**
- Golems that cannot be summoned (insufficient mana) are **not re-attempted** within the same room
- Failed golems will be attempted again on the next room entry
- Summoning order follows the loadout priority list
---
## 6. Golem Combat
Each active golem attacks on its own `attackProgress` timer, identical to swords:
```
golemProgress += HOURS_PER_TICK × golem.attackSpeed
while golemProgress >= 1:
dmg = golem.baseDamage
if golem.element:
dmg ×= getElementalBonus(golem.element, enemy.element)
applyGolemEffects(golem, dmg, enemy)
applyDamageToRoom(dmg)
golemProgress -= 1
```
**Key rules:**
- Golems ignore Executioner and Berserker discipline specials
- AoE golems distribute damage across multiple targets
- Elemental matchup applies if the golem has an element
---
## 7. Maintenance Cost
Each tick, each active golem checks its maintenance cost:
```
tickGolemMaintenance(golem):
if player mana[golem.maintenanceCostType] >= golem.maintenanceCost × HOURS_PER_TICK:
deductMana(golem.maintenanceCost × HOURS_PER_TICK, golem.maintenanceCostType)
else:
dismiss(golem)
activityLog("${golem.name} dismissed — insufficient ${golem.maintenanceCostType} mana")
```
**Key rules:**
- A dismissed golem is **not re-summoned mid-room**
- It will be re-attempted on the next room entry if mana has recovered
- Maintenance is checked every tick, not just on room transitions
---
## 8. Room Duration Limit
```
onRoomCleared():
for each activeGolem:
activeGolem.roomsRemaining -= 1
if activeGolem.roomsRemaining <= 0:
dismiss(golem)
activityLog("${golem.name} has faded after ${maxRoomDuration} rooms")
```
**Key rules:**
- Room duration ticks down on room **clear**, not on room **entry**
- Golems persist through the full room they were summoned in
- When `roomsRemaining` reaches 0, the golem is dismissed
---
## 9. Golem Data Shape
```typescript
interface GolemDefinition {
id: string;
name: string;
tier: number; // 14 (determines general power)
baseDamage: number;
attackSpeed: number; // attacks per in-game hour
element?: ElementType; // optional elemental type for matchup
maxRoomDuration: number; // rooms before disappearing
summonCost: number;
summonCostType: ElementType | 'raw';
maintenanceCost: number; // per in-game hour
maintenanceCostType: ElementType | 'raw';
onHitEffect?: GolemHitEffect; // DoT, AoE, etc.
armorPierce?: number; // 0-1, bypasses this fraction of enemy armor
aoe?: boolean;
aoeTargets?: number;
}
```
---
## 10. Discipline Interactions
### 10.1 Golem Crafting Discipline
| Perk | Effect |
|---|---|
| `golem-1` (once @ 200 XP) | Unlocks golem summoning ability |
| `golem-2` (capped @ 500, maxTier 2) | +1 Golem Capacity per tier (max +2) |
### 10.2 Fabricator Level
Directly determines base golem slots: `floor(fabricatorLevel / 2)`.
### 10.3 Dual Attunement Requirement
All 6 hybrid golems require **Enchanter 5 + Fabricator 5**. This means the player
must have both attunements active and leveled to at least 5 to access the most
powerful golem types.
---
## 11. Known Gaps / Implementation Status
| Feature | Status |
|---|---|
| Golem data definitions | ✅ Complete (10 golems in `data/golems/`) |
| Golem loadout UI | ✅ Partial (GolemancyTab exists) |
| Summoning on room entry | ❌ Not wired into combat tick |
| Maintenance cost per tick | ❌ Not wired into combat tick |
| Room duration tracking | ❌ Not wired into room clear |
| Golem combat (attack timer) | ❌ Not wired into combat tick |
| Golemancy combat pipeline | ❌ `golem-combat-actions.ts` exists but disconnected |
---
## 12. Acceptance Criteria
| # | Criterion |
|---|---|
| AC-1 | Golem slots = `floor(fabricatorLevel / 2)` + discipline bonus. |
| AC-2 | Golems are summoned on room entry if mana allows; failed summons are skipped for that room. |
| AC-3 | Each golem attacks on its own timer using its `attackSpeed` stat. |
| AC-4 | Elemental matchup applies to golem attacks when the golem has an element. |
| AC-5 | AoE golems distribute damage across `aoeTargets` enemies. |
| AC-6 | Maintenance cost is deducted each tick; golems dismiss if cost cannot be met. |
| AC-7 | Dismissed golems are not re-summoned mid-room. |
| AC-8 | Room duration ticks down on room clear, not entry. |
| AC-9 | Golems disappear after `maxRoomDuration` rooms. |
| AC-10 | Hybrid golems require Enchanter 5 + Fabricator 5. |
| AC-11 | Golem loadout is configured outside the spire and persists across rooms. |
| AC-12 | Golem HP is display-only; golems don't take damage from enemies. |
---
## 13. Files Reference
| File | Role |
|---|---|
| `src/lib/game/data/golems/golems-data.ts` | All 10 golem definitions |
| `src/lib/game/data/golems/types.ts` | Golem type definitions |
| `src/lib/game/data/disciplines/fabricator.ts` | Golem Crafting discipline |
| `src/lib/game/stores/golem-combat-actions.ts` | Golem combat actions (disconnected) |
| `src/lib/game/stores/pipelines/golem-combat.ts` | Golem combat pipeline (disconnected) |
| `src/components/game/tabs/GolemancyTab.tsx` | Golemancy UI |
| `docs/specs/spire-combat-spec.md` §9 | Authoritative golemancy spec |
@@ -0,0 +1,347 @@
# Item Fabrication System — Design Spec
> Describes the Fabricator attunement's crafting system: recipe categories, unlock
> gates, material costs, crafting flow, and how fabricated items differ from base loot.
---
## 1. Objective
Item Fabrication is the Fabricator attunement's non-combat crafting system. It allows
the player to craft materials and equipment using mana and component items. Recipes
are unlocked through Fabricator discipline perks, and the resulting equipment can
carry pre-applied enchantments, making fabrication a parallel path to the Enchanter's
enchanting system.
**Design goals:**
- Fabricated equipment provides an alternative to loot drops
- Material crafting creates a multi-tier resource pipeline
- Discipline-gated recipe unlocks reward Fabricator attunement investment
- Pre-applied enchantments on crafted gear offer unique combinations
- Crafting Efficiency discipline reduces material costs
---
## 2. Recipe Categories
### 2.1 Overview
| Category | File | Count | Unlock Gate |
|---|---|---|---|
| Material Recipes | `fabricator-material-recipes.ts` | 15 | None (base recipes) |
| Core Equipment (Elemental) | `fabricator-recipes.ts` | 12 | Study Fabricator Recipes discipline |
| Wizard Branch | `fabricator-wizard-recipes.ts` | 14 | Study Wizard Equipment discipline |
| Physical Branch | `fabricator-physical-recipes.ts` | 7 | Study Physical Equipment discipline |
| **Total** | | **48** | |
### 2.2 Recipe Type Structure
```typescript
interface FabricatorRecipe {
id: string;
name: string;
description: string;
manaType: string; // Mana type required (must be unlocked)
equipmentTypeId: string; // Equipment type ID produced
slot: EquipmentSlot; // Slot the equipment occupies
materials: Record<string, number>; // materialId -> count required
manaCost: number; // Mana cost in the recipe's mana type
craftTime: number; // Craft time in hours
rarity: 'common' | 'uncommon' | 'rare' | 'epic' | 'legendary';
gearTrait: string; // Flavor text for gear properties
bonusEnchantments?: AppliedEnchantment[]; // Pre-applied enchantments
recipeType?: 'equipment' | 'material';
resultMaterial?: string; // For material recipes: material ID produced
resultAmount?: number; // For material recipes: how many are produced
}
```
---
## 3. Material Recipes
### 3.1 Tier 1: Basic Materials
| ID | Name | Mana Type | Mana Cost | Input | Output | Time |
|---|---|---|---|---|---|---|
| `manaCrystal` | Mana Crystal | raw | 500 | — | 1× manaCrystal | 1h |
| `manaCrystalDustCraft` | Mana Crystal Dust | raw | 10 | 1× manaCrystal | 2× manaCrystalDust | 1h |
### 3.2 Tier 2: Elemental Crystals
All cost 100 of the respective element mana, take 1 hour, produce 1 crystal.
| ID | Mana Type | Element |
|---|---|---|
| `fireCrystal` | fire | Fire |
| `waterCrystal` | water | Water |
| `airCrystal` | air | Air |
| `earthCrystal` | earth | Earth |
| `lightCrystal` | light | Light |
| `darkCrystal` | dark | Dark |
| `metalCrystal` | metal | Metal |
| `crystalCrystal` | crystal | Crystal |
### 3.3 Tier 3: Shards and Cores
| ID | Mana Type | Mana Cost | Input | Output | Time |
|---|---|---|---|---|---|
| `earthShardCraft` | earth | 50 | 1× earthCrystal | 1× earthShard | 1h |
| `elementalCore` | raw | 100 | 10× manaCrystal | 1× elementalCore | 10h |
### 3.4 Tier 4: Advanced Materials
| ID | Mana Type | Mana Cost | Input | Output | Time |
|---|---|---|---|---|---|
| `aetherWeave` | air | 500 | 3× airCrystal, 3× lightCrystal, 2× elementalCore | 1× aetherWeave | 12h |
| `voidCloth` | dark | 500 | 3× airCrystal, 3× darkCrystal, 2× voidEssence | 1× voidCloth | 12h |
| `liquidCrystalLattice` | crystal | 800 | 5× crystalCrystal, 3× elementalCore, 2× voidEssence, 1× celestialFragment | 1× liquidCrystalLattice | 20h |
### 3.5 Material Dependency Chain
```
Raw Mana (500) → Mana Crystal (1)
Mana Crystal (1) + Raw Mana (10) → Mana Crystal Dust (2)
Mana Crystal (1) + Element Mana (100) → Element Crystal (1) [per element]
Element Crystal (1) + Element Mana (50) → Element Shard (1) [earth only]
Mana Crystal (10) + Raw Mana (100) → Elemental Core (1) [10hr]
Air Crystal (3) + Light Crystal (3) + Elemental Core (2) → Aether Weave (1) [12hr]
Air Crystal (3) + Dark Crystal (3) + Void Essence (2) → Void Cloth (1) [12hr]
Crystal Crystal (5) + Elemental Core (3) + Void Essence (2) + Celestial Fragment (1) → Liquid Crystal Lattice (1) [20hr]
```
---
## 4. Equipment Recipes
### 4.1 Earth Gear (Unlock: Study Fabricator Recipes @ 50 XP)
| ID | Name | Slot | Mana Cost | Materials | Rarity | Time |
|---|---|---|---|---|---|---|
| `earthHelm` | Earthen Helm | head | 200 earth | 4× manaCrystalDust, 2× earthShard | uncommon | 3h |
| `earthChest` | Stoneguard Armor | body | 500 earth | 8× manaCrystalDust, 4× earthShard, 1× elementalCore | rare | 6h |
| `earthBoots` | Stonegreaves | feet | 150 earth | 3× manaCrystalDust, 1× earthShard | uncommon | 2h |
### 4.2 Metal Gear (Unlock: Study Fabricator Recipes @ 100 XP)
| ID | Name | Slot | Mana Cost | Materials | Rarity | Time |
|---|---|---|---|---|---|---|
| `metalBlade` | Metal Blade | mainHand | 400 metal | 6× manaCrystalDust, 3× metalShard, 2× elementalCore | rare | 5h |
| `metalShield` | Metal Spell Focus | offHand | 450 metal | 7× manaCrystalDust, 4× metalShard, 1× elementalCore | rare | 5h |
| `metalGloves` | Metalweave Gauntlets | hands | 250 metal | 4× manaCrystalDust, 2× metalShard | uncommon | 3h |
### 4.3 Sand Gear (Unlock: Study Fabricator Recipes @ 150 XP)
| ID | Name | Slot | Mana Cost | Materials | Rarity | Time |
|---|---|---|---|---|---|---|
| `sandBoots` | Sandstrider Boots | feet | 120 sand | 3× manaCrystalDust, 1× sandShard | uncommon | 2h |
| `sandGloves` | Sandweave Gloves | hands | 140 sand | 3× manaCrystalDust, 2× sandShard | uncommon | 2h |
| `sandVest` | Sandcloth Vest | body | 300 sand | 5× manaCrystalDust, 2× sandShard, 1× elementalCore | rare | 4h |
### 4.4 Crystal Gear (Unlock: Study Fabricator Recipes @ 200 XP)
| ID | Name | Slot | Mana Cost | Materials | Rarity | Time |
|---|---|---|---|---|---|---|
| `crystalWand` | Crystal Focus Wand | mainHand | 600 crystal | 10× manaCrystalDust, 5× crystalShard, 3× elementalCore | epic | 6h |
| `crystalRing` | Crystal Ring | accessory1 | 350 crystal | 5× manaCrystalDust, 3× crystalShard, 1× elementalCore | rare | 3h |
| `crystalAmulet` | Crystal Pendant | accessory2 | 400 crystal | 6× manaCrystalDust, 3× crystalShard, 2× elementalCore | rare | 4h |
### 4.5 Wizard Branch (Unlock: Study Wizard Equipment discipline)
| ID | Name | Slot | Unlock (XP) | Mana Cost | Materials | Rarity | Time |
|---|---|---|---|---|---|---|---|
| `oakStaff` | Oak Staff | mainHand | 50 | 200 earth | 5× manaCrystalDust, 2× earthShard | uncommon | 3h |
| `arcanistStaff` | Arcanist Staff | mainHand | 100 | 700 crystal | 12× manaCrystalDust, 6× crystalShard, 3× elementalCore | epic | 8h |
| `battlestaff` | Battlestaff | mainHand | 150 | 500 metal | 8× manaCrystalDust, 4× metalShard, 2× elementalCore | rare | 6h |
| `arcanistCirclet` | Arcanist Circlet | head | 150 | 300 crystal | 6× manaCrystalDust, 2× crystalShard, 1× lightCrystal | rare | 4h |
| `arcanistRobe` | Arcanist Robe | body | 150 | 800 crystal | 14× manaCrystalDust, 7× crystalShard, 3× elementalCore | epic | 8h |
| `voidCatalyst` | Void Catalyst | mainHand | 200 | 600 crystal | 10× manaCrystalDust, 3× darkCrystal, 2× voidEssence, 2× elementalCore | epic | 7h |
| `arcanistPendant` | Arcanist Pendant | accessory1 | 250 | 500 crystal | 8× manaCrystalDust, 4× crystalShard, 2× elementalCore | epic | 5h |
**Advanced Wizard Gear:**
| ID | Name | Slot | Mana Cost | Materials | Rarity | Time |
|---|---|---|---|---|---|---|
| `aetherRobe` | Aetherweave Robe | body | 1200 crystal | 3× aetherWeave, 15× manaCrystalDust, 8× crystalShard, 4× elementalCore | legendary | 15h |
| `aetherCirclet` | Aetherweave Circlet | head | 900 crystal | 2× aetherWeave, 10× manaCrystalDust, 3× lightCrystal, 3× elementalCore | epic | 10h |
| `voidRobe` | Voidweave Robe | body | 1200 sand | 3× voidCloth, 15× manaCrystalDust, 8× crystalShard, 3× voidEssence | legendary | 15h |
| `voidCowl` | Voidweave Cowl | head | 900 sand | 2× voidCloth, 10× manaCrystalDust, 3× darkCrystal, 2× voidEssence | epic | 10h |
| `latticeStaff` | Crystal Lattice Staff | mainHand | 2000 crystal | 2× liquidCrystalLattice, 2× aetherWeave, 2× voidCloth, 5× elementalCore | legendary | 25h |
| `latticeAmulet` | Crystal Lattice Amulet | accessory1 | 1500 crystal | 1× liquidCrystalLattice, 5× crystalCrystal, 4× elementalCore, 2× voidEssence | legendary | 18h |
### 4.6 Physical Branch (Unlock: Study Physical Equipment discipline)
| ID | Name | Slot | Unlock (XP) | Mana Cost | Materials | Rarity | Time |
|---|---|---|---|---|---|---|---|
| `crystalBlade` | Crystal Blade | mainHand | 50 | 500 crystal | 8× manaCrystalDust, 4× crystalShard, 2× elementalCore | rare | 5h |
| `arcanistBlade` | Arcanist Blade | mainHand | 100 | 600 metal | 10× manaCrystalDust, 5× metalShard, 3× elementalCore | epic | 7h |
| `voidBlade` | Void-Touched Blade | mainHand | 150 | 550 crystal | 9× manaCrystalDust, 3× darkCrystal, 2× voidEssence, 2× elementalCore | epic | 6h |
| `battleHelm` | Battle Helm | head | 200 | 350 metal | 6× manaCrystalDust, 3× metalShard, 1× elementalCore | rare | 4h |
| `battleRobe` | Battle Robe | body | 200 | 400 sand | 8× manaCrystalDust, 3× sandShard, 2× elementalCore | rare | 5h |
| `battleBoots` | Battle Boots | feet | 250 | 180 sand | 4× manaCrystalDust, 2× sandShard | uncommon | 3h |
| `combatGauntlets` | Combat Gauntlets | hands | 300 | 300 metal | 5× manaCrystalDust, 2× metalShard, 1× elementalCore | uncommon | 3h |
---
## 5. Recipe Unlock Gates
### 5.1 Study Fabricator Recipes Discipline
| XP Threshold | Recipes Unlocked |
|---|---|
| 50 | Earth gear (helm, chest, boots) |
| 100 | Metal gear (blade, shield, gloves) |
| 150 | Sand gear (boots, gloves, vest) |
| 200 | Crystal gear (wand, ring, amulet) |
### 5.2 Study Wizard Equipment Discipline
| XP Threshold | Recipes Unlocked |
|---|---|
| 50 | Oak Staff |
| 100 | Arcanist Staff |
| 150 | Battlestaff, Arcanist Circlet, Arcanist Robe |
| 200 | Void Catalyst |
| 250 | Arcanist Pendant |
| 300 | (advanced recipes via material availability) |
### 5.3 Study Physical Equipment Discipline
| XP Threshold | Recipes Unlocked |
|---|---|
| 50 | Crystal Blade |
| 100 | Arcanist Blade |
| 150 | Void Blade |
| 200 | Battle Helm, Battle Robe |
| 250 | Battle Boots |
| 300 | Combat Gauntlets |
---
## 6. Crafting Flow
### 6.1 Pre-Craft Checks
```
checkFabricatorCosts(recipe, materials, rawMana, elements):
- Verify all material counts are sufficient
- Verify mana (raw or elemental) is sufficient
- Return { canCraft, missingMana, missingMaterials }
```
### 6.2 Crafting Execution
```
executeMaterialCraft(recipe, materials):
1. Deduct mana cost from raw or elemental pool
2. Deduct input materials from inventory
3. Add resultAmount of resultMaterial to inventory
makeFabricatorProgress(recipeId, equipmentTypeId, craftTime, manaCost):
1. Create EquipmentCraftingProgress object
2. blueprintId = "fabricator-{recipeId}"
3. Progress accumulates at HOURS_PER_TICK per tick
4. On completion: create equipment instance with bonusEnchantments
```
### 6.3 Cancellation Refund
```
remainingFraction = (required - progress) / required
refundRate = remainingFraction + (1 - remainingFraction) × 0.5
manaRefund = floor(manaSpent × refundRate)
materialRefund = floor(materialsSpent × 0.5)
```
---
## 7. Crafting Efficiency Discipline Interaction
The **Crafting Efficiency** discipline provides:
| Source | Effect |
|---|---|
| Base stat bonus | `craftingCostReduction` +15 |
| Perk `efficiency-1` (once @ 300 XP) | +10% Crafting Cost Reduction |
The `craftingCostReduction` stat reduces material costs for all fabrication recipes.
Applied as: `actualCost = baseCost × (1 - craftingCostReduction / 100)`.
At maximum: 15 (base) + 10 (perk) = **25% cost reduction**.
---
## 8. How Fabricated Items Differ from Base Loot
| Property | Loot Drops | Fabricated Items |
|---|---|---|
| **Source** | Enemy drops, treasure rooms | Crafting recipes |
| **Enchantments** | None (must be enchanted) | Pre-applied `bonusEnchantments` |
| **Rarity** | Random (commonlegendary) | Fixed per recipe |
| **Quality** | Random (0100) | Fixed per recipe |
| **Stats** | Base for type | Base for type + enchantment bonuses |
| **Control** | None (random) | Full (player chooses recipe) |
Fabricated items are created with `bonusEnchantments` — pre-applied enchantment
objects with `effectId`, `stacks`, and `actualCost`. These enchantments are
permanent and cannot be removed without the Enchanter's disenchant process.
---
## 9. Equipment Types Producible via Fabrication
| Slot | Equipment Types |
|---|---|
| mainHand | Metal Blade, Crystal Focus Wand, Oak Staff, Arcanist Staff, Battlestaff, Void Catalyst, Crystal Lattice Staff |
| offHand | Metal Spell Focus |
| head | Earthen Helm, Arcanist Circlet, Aetherweave Circlet, Voidweave Cowl, Battle Helm |
| body | Stoneguard Armor, Sandcloth Vest, Arcanist Robe, Aetherweave Robe, Voidweave Robe, Battle Robe |
| hands | Metalweave Gauntlets, Sandweave Gloves, Combat Gauntlets |
| feet | Stonegreaves, Sandstrider Boots, Battle Boots |
| accessory1 | Crystal Ring, Arcanist Pendant, Crystal Lattice Amulet |
| accessory2 | Crystal Pendant |
---
## 10. Rarity Distribution
| Rarity | Count | Examples |
|---|---|---|
| common | 2 | Mana Crystal Dust, Earth Shard |
| uncommon | 14 | Earth gear, Sand gear, Oak Staff, Battle Boots, Combat Gauntlets, Mana Crystal |
| rare | 14 | Earth Chest, Metal gear, Crystal Ring/Amulet, Sand Vest, Crystal Blade, Battle Helm/Robe |
| epic | 10 | Crystal Wand, Arcanist Staff/Robe, Void Blade/Catalyst, Arcanist Pendant, Aether Circlet, Void Cowl |
| legendary | 5 | Aether Robe, Void Robe, Lattice Staff, Lattice Amulet, Liquid Crystal Lattice |
---
## 11. Acceptance Criteria
| # | Criterion |
|---|---|
| AC-1 | All 48 recipes are accessible when the Fabricator attunement is active. |
| AC-2 | Recipe unlock gates fire at the correct discipline XP thresholds. |
| AC-3 | Material crafting correctly consumes mana and input materials, producing the correct output. |
| AC-4 | Equipment crafting produces items with the correct pre-applied enchantments. |
| AC-5 | Crafting Efficiency discipline reduces material costs by the correct percentage. |
| AC-6 | Cancellation refunds mana at the blended rate (100% unspent, 50% spent) and materials at 50%. |
| AC-7 | Fabricated items cannot be crafted without the required mana type unlocked. |
| AC-8 | Material dependency chain is correct: Mana Crystal → Element Crystal → Elemental Core → Advanced Materials. |
| AC-9 | Craft time ranges from 1h (basic materials) to 25h (Crystal Lattice Staff). |
| AC-10 | Mana cost ranges from 10 (Mana Crystal Dust) to 2000 (Crystal Lattice Staff). |
---
## 12. Files Reference
| File | Role |
|---|---|
| `src/lib/game/data/fabricator-material-recipes.ts` | Material recipes (15) |
| `src/lib/game/data/fabricator-recipes.ts` | Core equipment recipes (12) |
| `src/lib/game/data/fabricator-wizard-recipes.ts` | Wizard branch recipes (14) |
| `src/lib/game/data/fabricator-physical-recipes.ts` | Physical branch recipes (7) |
| `src/lib/game/data/fabricator-recipe-types.ts` | Recipe type definitions |
| `src/lib/game/crafting-fabricator.ts` | Fabrication crafting logic |
| `src/lib/game/data/disciplines/fabricator.ts` | Fabricator disciplines (5) |
| `src/components/game/tabs/CraftingTab.tsx` | Crafting tab wrapper |
| `src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx` | Fabricator crafting UI |