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,655 @@
# Enchanting System — Design Spec
> Describes the three-stage enchanting pipeline: Design → Prepare → Apply.
> Covers stage timings, mana costs, auto-transitions, enchantment capacity system,
> full enchantment effect categories, disenchanting, and discipline perk interactions.
---
## 1. Objective
Enchanting is the Enchanter attunement's primary system for enhancing equipment. It
transforms raw mana and materials into permanent equipment bonuses through a
three-stage pipeline. The player creates reusable designs, prepares equipment by
stripping existing enchantments, then applies designs to prepared equipment.
**Design goals:**
- Three distinct stages encourage planning and resource management
- Capacity and stacking systems allow deep customization of individual items
- Discipline perks progressively unlock more powerful enchantment types
- Mana costs scale with design complexity, creating meaningful trade-offs
- Auto-transitions keep the pipeline flowing without manual state management
---
## 2. Controls / API
### 2.1 Player Actions
| Action | Stage | Trigger |
|---|---|---|
| **Create Design** | Design | Select effects, name design, click "Create Design" |
| **Start Prepare** | Prepare | Select equipped item, click "Prepare" |
| **Apply Enchantment** | Apply | Select saved design + prepared item, click "Apply" |
| **Disenchant** | Prepare | Initiate prepare on already-enchanted equipment (enchantments removed) |
| **Cancel** | Any | Click "Cancel" during any active stage |
### 2.2 Auto-Transitions
- Design complete → returns to idle (Meditate)
- Prepare complete → returns to idle (Meditate), item gains "Ready for Enchantment" tag
- Apply complete → returns to idle (Meditate), selection state resets
---
## 3. Stage 1: Design
### 3.1 Flow
1. Player selects an equipment type from the type selector
2. Player adds effects from the unlocked pool via the EffectSelector
3. Player sets stack count per effect (up to `maxStacks`)
4. Player names the design
5. Player clicks "Create Design" → design begins
6. `designProgress` accumulates at `HOURS_PER_TICK` per tick
7. When `designProgress >= requiredTime` → design saved to `completedDesigns`
### 3.2 Timing Formula
```
calculateDesignTime(effects):
time = 1 // base 1 hour
for each effect: time += 0.5 * stacks
return time
```
| Design Complexity | Time |
|---|---|
| 1 effect, 1 stack | 1.5 hours |
| 3 effects, 1 stack each | 2.5 hours |
| 2 effects, 3 stacks each | 4.0 hours |
Progress per tick: `HOURS_PER_TICK = 0.04` hours.
### 3.3 Hasty Enchanter (Special Effect)
If the player has the `HASTY_ENCHANTER` special effect and the design is a **repeat**
(re-creating a previously completed design):
```
time *= 0.75 // 25% faster
```
### 3.4 Instant Designs (Special Effect)
Per tick, if the player has the `INSTANT_DESIGNS` special effect:
```typescript
const INSTANT_DESIGN_CHANCE = 0.10; // 10%
if (Math.random() < INSTANT_DESIGN_CHANCE) {
designProgress = requiredTime; // instant completion
}
```
### 3.5 Dual Design Slot
A second concurrent design slot is available when:
- The first design slot has an active design (`designProgress` exists)
- The second slot is empty (`designProgress2 === null`)
- The player has the `ENCHANT_MASTERY` special boolean
### 3.6 Design Mana Cost
**None.** The Design stage has no mana cost.
### 3.7 Design Validation
- `enchantingLevel >= 1` (enchanter attunement must be active)
- Each effect must exist in `ENCHANTMENT_EFFECTS`
- Each effect's `allowedEquipmentCategories` must include the equipment's category
- Stacks cannot exceed the effect's `maxStacks`
### 3.8 Enchanting XP Award
```typescript
calculateEnchantingXP(capacityUsed: number): number {
return Math.max(1, Math.floor(capacityUsed / 10));
}
```
Awarded to Enchanter attunement XP on design completion. This is **Attunement XP**,
not discipline XP.
---
## 4. Stage 2: Prepare
### 4.1 Flow
1. Player selects an equipped item to prepare
2. System checks: `'Ready for Enchantment'` tag required if item was previously prepared
3. If item has existing enchantments, a confirmation dialog warns they will be removed
4. Player confirms → preparation begins
5. Mana is deducted over the prep duration
6. On completion: all enchantments removed, `usedCapacity` reset to 0, rarity reset to `'common'`, `'Ready for Enchantment'` tag added
### 4.2 Timing Formula
```
calculatePrepTime(equipmentCapacity):
time = 2 + floor(equipmentCapacity / 50)
```
| Capacity | Prep Time |
|---|---|
| 15 (shoes) | 2 hours |
| 30 (body) | 2 hours |
| 50 (caster) | 3 hours |
| 80 (robe) | 3 hours |
### 4.3 Mana Cost Formula
```
totalMana = equipmentCapacity × 10
manaPerHour = totalMana / prepTime
manaPerTick = manaPerHour × HOURS_PER_TICK
```
| Capacity | Total Mana Cost |
|---|---|
| 15 | 150 |
| 30 | 300 |
| 50 | 500 |
| 80 | 800 |
### 4.4 Disenchant Recovery
When preparing equipment that has existing enchantments, mana is partially recovered:
```
recoveryRate = 0.10 + disenchantLevel × 0.20
manaRecovered = Σ floor(enchantment.actualCost × recoveryRate)
```
| Disenchant Level | Recovery Rate |
|---|---|
| 0 | 10% |
| 1 | 30% |
| 2 | 50% |
| 3 | 70% |
| 4 | 90% |
| 5 | 110% |
> **Note:** `disenchantLevel` is currently hardcoded to `0` in the codebase, so the
> effective recovery rate is always **10%**.
### 4.5 Cancellation Refund
```
remainingFraction = (required - progress) / required
refundRate = remainingFraction + (1 - remainingFraction) × 0.5
manaRefund = floor(manaSpent × refundRate)
```
Unspent progress gets 100% refund; spent progress gets 50% refund; blended proportionally.
---
## 5. Stage 3: Apply
### 5.1 Flow
1. Player selects a saved design and a prepared equipment instance
2. System validates: `currentAction === 'meditate'`, item has `'Ready for Enchantment'` tag, capacity fits
3. Player clicks "Apply" → application begins
4. Mana is deducted per hour over the application duration
5. On completion: design's effects applied to equipment, `usedCapacity` updated, design consumed
### 5.2 Timing Formula
```
calculateApplicationTime(design):
time = 2 + Σ(stacks) for all effects in design
```
| Design | Apply Time |
|---|---|
| 1 effect, 1 stack | 3 hours |
| 3 effects, 1 stack each | 5 hours |
| 2 effects, 3 stacks each | 8 hours |
### 5.3 Mana Cost Formula
```
manaPerHour = 20 + Σ(stacks × 5) for all effects
manaPerTick = manaPerHour × HOURS_PER_TICK
```
| Design | Mana/Hour |
|---|---|
| 1 effect, 1 stack | 25 |
| 3 effects, 1 stack each | 35 |
| 2 effects, 3 stacks each | 50 |
### 5.4 Free Enchant Chances
Per tick, the system checks for free enchant chances. These are **additive**:
| Special Effect | Chance |
|---|---|
| `ENCHANT_PRESERVATION` | 25% |
| `THRIFTY_ENCHANTER` | 10% |
| `OPTIMIZED_ENCHANTING` | 25% |
| **Maximum combined** | **60%** |
On trigger: `applicationProgress = requiredTime` (instant completion for that tick),
**no mana consumed** for that tick.
### 5.5 Pure Essence (Special Effect)
If the player has the `PURE_ESSENCE` special effect:
```typescript
const PURE_ESSENCE_STACK_BONUS = 1.25;
const PURE_ESSENCE_COST_CAP = 100;
if (effect.baseCapacityCost < PURE_ESSENCE_COST_CAP) {
actualStacks = Math.ceil(baseStacks × PURE_ESSENCE_STACK_BONUS);
}
```
Effects with `baseCapacityCost < 100` get **25% more stacks** (rounded up).
### 5.6 Cancellation Refund
Same formula as Prepare stage (§4.5).
---
## 6. Enchantment Capacity System
### 6.1 Base Capacity Per Equipment Type
| Category | Equipment | Base Capacity |
|---|---|---|
| **Caster** | basicStaff | 50 |
| | apprenticeWand | 35 |
| | oakStaff | 65 |
| | crystalWand | 45 |
| | arcanistStaff | 80 |
| | battlestaff | 70 |
| **Catalyst** | basicCatalyst | 40 |
| | fireCatalyst | 55 |
| | voidCatalyst | 75 |
| **Sword** | ironBlade | 30 |
| | steelBlade | 40 |
| | crystalBlade | 55 |
| | arcanistBlade | 65 |
| | voidBlade | 50 |
| **Head** | clothHood | 25 |
| | apprenticeCap | 30 |
| | wizardHat | 45 |
| | arcanistCirclet | 40 |
| | battleHelm | 50 |
| **Body** | civilianShirt | 30 |
| | apprenticeRobe | 45 |
| | scholarRobe | 55 |
| | battleRobe | 65 |
| | arcanistRobe | 80 |
| **Hands** | civilianGloves | 20 |
| | apprenticeGloves | 30 |
| | spellweaveGloves | 40 |
| | combatGauntlets | 35 |
| **Feet** | civilianShoes | 15 |
| | apprenticeBoots | 25 |
| | travelerBoots | 30 |
| | battleBoots | 35 |
| **Accessory** | copperRing | 15 |
| | silverRing | 25 |
| | goldRing | 35 |
| | signetRing | 30 |
| | copperAmulet | 20 |
| | silverAmulet | 30 |
| | crystalPendant | 45 |
| | manaBrooch | 40 |
| | arcanistPendant | 55 |
| | voidTouchedRing | 50 |
### 6.2 Stacking Cost Formula
```
calculateEffectCapacityCost(effectId, stacks, efficiencyBonus):
totalCost = 0
for i in 0..stacks-1:
stackMultiplier = 1 + (i × 0.2)
totalCost += baseCapacityCost × stackMultiplier
return floor(totalCost × (1 - efficiencyBonus))
```
| Stack Index | Multiplier |
|---|---|
| 0 (1st) | 1.0× |
| 1 (2nd) | 1.2× |
| 2 (3rd) | 1.4× |
| 3 (4th) | 1.6× |
| 4 (5th) | 1.8× |
Example: 3 stacks of a cost-20 effect:
`20×1.0 + 20×1.2 + 20×1.4 = 20 + 24 + 28 = 72` capacity used.
### 6.3 Efficiency Bonus
The `efficiencyBonus` reduces total capacity cost. Sources include discipline perks
(e.g., Crafting Efficiency discipline from Fabricator pool). Applied as:
`totalCost × (1 - efficiencyBonus)`.
---
## 7. Enchantment Effect Categories
### 7.1 Spell Effects (category: `'spell'`) — Casters only
**Basic Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_manaBolt` | Mana Bolt | 50 | 1 |
| `spell_manaStrike` | Mana Strike | 40 | 1 |
| `spell_fireball` | Fireball | 80 | 1 |
| `spell_emberShot` | Ember Shot | 60 | 1 |
| `spell_waterJet` | Water Jet | 70 | 1 |
| `spell_iceShard` | Ice Shard | 75 | 1 |
| `spell_gust` | Gust | 60 | 1 |
| `spell_stoneBullet` | Stone Bullet | 80 | 1 |
| `spell_lightLance` | Light Lance | 95 | 1 |
| `spell_shadowBolt` | Shadow Bolt | 95 | 1 |
| `spell_drain` | Drain | 85 | 1 |
| `spell_rotTouch` | Rot Touch | 80 | 1 |
| `spell_windSlash` | Wind Slash | 72 | 1 |
| `spell_rockSpike` | Rock Spike | 88 | 1 |
| `spell_radiance` | Radiance | 80 | 1 |
| `spell_darkPulse` | Dark Pulse | 68 | 1 |
**Tier 2 Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_inferno` | Inferno | 180 | 1 |
| `spell_tidalWave` | Tidal Wave | 175 | 1 |
| `spell_hurricane` | Hurricane | 170 | 1 |
| `spell_earthquake` | Earthquake | 200 | 1 |
| `spell_solarFlare` | Solar Flare | 190 | 1 |
| `spell_voidRift` | Void Rift | 175 | 1 |
| `spell_flameWave` | Flame Wave | 165 | 1 |
| `spell_iceStorm` | Ice Storm | 170 | 1 |
| `spell_windBlade` | Wind Blade | 155 | 1 |
| `spell_stoneBarrage` | Stone Barrage | 175 | 1 |
| `spell_divineSmite` | Divine Smite | 175 | 1 |
| `spell_shadowStorm` | Shadow Storm | 168 | 1 |
| `spell_soulRend` | Soul Rend | 170 | 1 |
**Tier 3 Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_pyroclasm` | Pyroclasm | 400 | 1 |
| `spell_tsunami` | Tsunami | 380 | 1 |
| `spell_meteorStrike` | Meteor Strike | 420 | 1 |
| `spell_cosmicStorm` | Cosmic Storm | 370 | 1 |
| `spell_heavenLight` | Heaven's Light | 390 | 1 |
| `spell_oblivion` | Oblivion | 385 | 1 |
| `spell_deathMark` | Death Mark | 370 | 1 |
**Legendary Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_stellarNova` | Stellar Nova | 600 | 1 |
| `spell_voidCollapse` | Void Collapse | 550 | 1 |
| `spell_crystalShatter` | Crystal Shatter | 500 | 1 |
**Lightning Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_spark` | Spark | 70 | 1 |
| `spell_lightningBolt` | Lightning Bolt | 90 | 1 |
| `spell_chainLightning` | Chain Lightning | 160 | 1 |
| `spell_stormCall` | Storm Call | 190 | 1 |
| `spell_thunderStrike` | Thunder Strike | 350 | 1 |
**Frost Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_frostBite` | Frost Bite | 78 | 1 |
| `spell_iceShard` | Ice Shard | 95 | 1 |
| `spell_frostNova` | Frost Nova | 165 | 1 |
| `spell_glacialSpike` | Glacial Spike | 200 | 1 |
| `spell_absoluteZero` | Absolute Zero | 380 | 1 |
**Metal Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_metalShard` | Metal Shard | 85 | 1 |
| `spell_ironFist` | Iron Fist | 120 | 1 |
| `spell_steelTempest` | Steel Tempest | 190 | 1 |
| `spell_furnaceBlast` | Furnace Blast | 400 | 1 |
**Sand Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_sandBlast` | Sand Blast | 72 | 1 |
| `spell_sandstorm` | Sandstorm | 100 | 1 |
| `spell_desertWind` | Desert Wind | 155 | 1 |
| `spell_duneCollapse` | Dune Collapse | 300 | 1 |
**BlackFlame Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_blackFire` | Black Fire | 82 | 1 |
| `spell_shadowEmber` | Shadow Ember | 105 | 1 |
| `spell_darkInferno` | Dark Inferno | 175 | 1 |
| `spell_umbralBlaze` | Umbral Blaze | 210 | 1 |
| `spell_hellfireCurse` | Hellfire Curse | 410 | 1 |
**Radiant Flames Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_radiantBurst` | Radiant Burst | 85 | 1 |
| `spell_holyFlame` | Holy Flame | 108 | 1 |
| `spell_blindingSun` | Blinding Sun | 180 | 1 |
| `spell_purifyingFire` | Purifying Fire | 215 | 1 |
| `spell_supernovaBlast` | Supernova Blast | 420 | 1 |
**Miasma Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_toxicCloud` | Toxic Cloud | 76 | 1 |
| `spell_plagueTouch` | Plague Touch | 100 | 1 |
| `spell_miasmaBurst` | Miasma Burst | 165 | 1 |
| `spell_pestilence` | Pestilence | 195 | 1 |
| `spell_deathMiasma` | Death Miasma | 390 | 1 |
**Shadow Glass Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_shadowSpike` | Shadow Spike | 88 | 1 |
| `spell_darkShard` | Dark Shard | 115 | 1 |
| `spell_obsidianStorm` | Obsidian Storm | 185 | 1 |
| `spell_voidBlade` | Void Blade | 225 | 1 |
| `spell_shadowGlassCataclysm` | Shadow Glass Cataclysm | 415 | 1 |
**Exotic Spells:**
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `spell_soulPierce` | Soul Pierce | 500 | 1 |
| `spell_spiritBlast` | Spirit Blast | 650 | 1 |
| `spell_temporalWarp` | Temporal Warp | 520 | 1 |
| `spell_chronoStasis` | Chrono Stasis | 680 | 1 |
| `spell_plasmaBolt` | Plasma Bolt | 510 | 1 |
| `spell_plasmaStorm` | Plasma Storm | 660 | 1 |
### 7.2 Mana Effects (category: `'mana'`)
**General Mana** — Allowed on: `['caster', 'catalyst', 'head', 'body', 'accessory']`
| Effect ID | Name | Description | Base Cost | Max Stacks |
|---|---|---|---|---|
| `mana_cap_50` | Mana Reserve | +50 max mana | 20 | 3 |
| `mana_cap_100` | Mana Reservoir | +100 max mana | 35 | 3 |
| `mana_regen_1` | Trickle | +1 mana/hour regen | 15 | 5 |
| `mana_regen_2` | Stream | +2 mana/hour regen | 28 | 4 |
| `mana_regen_5` | River | +5 mana/hour regen | 50 | 3 |
| `click_mana_1` | Mana Tap | +1 mana per click | 20 | 5 |
| `click_mana_3` | Mana Surge | +3 mana per click | 35 | 3 |
**Weapon Mana** — Allowed on: `['caster', 'catalyst', 'sword']`
| Effect ID | Name | Base Cost | Max Stacks |
|---|---|---|---|
| `weapon_mana_cap_20` | Mana Cell | 25 | 5 |
| `weapon_mana_cap_50` | Mana Vessel | 50 | 3 |
| `weapon_mana_cap_100` | Mana Core | 80 | 2 |
| `weapon_mana_regen_1` | Mana Wick | 20 | 5 |
| `weapon_mana_regen_2` | Mana Siphon | 35 | 3 |
| `weapon_mana_regen_5` | Mana Well | 60 | 2 |
**Per-Element Capacity** — Allowed on: `['caster', 'catalyst', 'head', 'body', 'accessory']`
Generated for each non-utility element (21 elements). Three tiers per element:
- `{element}_cap_10`: cost 30, max 5 stacks
- `{element}_cap_25`: cost 60, max 3 stacks
- `{element}_cap_50`: cost 100, max 2 stacks
### 7.3 Combat Effects (category: `'combat'`) — Casters, Hands
| Effect ID | Name | Description | Base Cost | Max Stacks |
|---|---|---|---|---|
| `damage_5` | Minor Power | +5 base damage | 15 | 5 |
| `damage_10` | Moderate Power | +10 base damage | 28 | 4 |
| `damage_pct_10` | Amplification | +10% damage | 30 | 3 |
| `crit_5` | Sharp Edge | +5% crit chance | 20 | 4 |
| `attack_speed_10` | Swift Casting | +10% attack speed | 22 | 4 |
### 7.4 Elemental Effects (category: `'elemental'`) — Casters, Swords
| Effect ID | Name | Description | Base Cost | Max Stacks |
|---|---|---|---|---|
| `sword_fire` | Fire Enchant | Burns enemies | 40 | 1 |
| `sword_frost` | Frost Enchant | Prevents dodge | 40 | 1 |
| `sword_lightning` | Lightning Enchant | 30% armor pierce | 50 | 1 |
| `sword_void` | Void Enchant | +20% damage | 60 | 1 |
### 7.5 Utility Effects (category: `'utility'`)
| Effect ID | Name | Base Cost | Max Stacks | Allowed On |
|---|---|---|---|---|
| `meditate_10` | Meditative Focus | 18 | 5 | head, body, accessory |
| `study_10` | Quick Study | 22 | 4 | caster, catalyst, head, body, hands, feet, accessory |
| `insight_5` | Insightful | 25 | 4 | head, accessory |
### 7.6 Special Effects (category: `'special'`)
| Effect ID | Name | Base Cost | Max Stacks | Allowed On |
|---|---|---|---|---|
| `spell_echo_10` | Echo Chamber | 60 | 2 | caster |
| `guardian_dmg_10` | Bane | 35 | 3 | caster, catalyst, accessory |
| `overpower_80` | Overpower | 55 | 1 | caster, hands |
| `first_strike` | First Strike | 45 | 1 | caster, hands |
| `combo_master` | Combo Master | 65 | 1 | caster, hands |
| `adrenaline_rush` | Adrenaline Rush | 50 | 1 | caster, hands |
### 7.7 Defense Effects (category: `'defense'`)
**Empty** — No defense effects are currently defined.
---
## 8. Discipline Perks That Affect Enchanting
| Discipline | Perk | Threshold | Effect |
|---|---|---|---|
| Enchantment Crafting | `enchant-1` (infinite) | 150 XP | +5 enchantPower per tier |
| Enchantment Crafting | `enchant-2` (capped) | 300 XP | +10 enchantPower/tier, max 3 |
| Study Basic Weapon Enchantments | `basic-weapon-fire` | 50 XP | Unlocks `sword_fire` |
| Study Basic Weapon Enchantments | `basic-weapon-frost` | 100 XP | Unlocks `sword_frost` |
| Study Basic Weapon Enchantments | `basic-weapon-lightning` | 150 XP | Unlocks `sword_lightning` |
| Study Advanced Weapon Enchantments | `advanced-weapon-void` | 100 XP | Unlocks `sword_void` |
| Study Advanced Weapon Enchantments | `advanced-weapon-damage-5` | 150 XP | Unlocks `damage_5` |
| Study Advanced Weapon Enchantments | `advanced-weapon-crit` | 200 XP | Unlocks `crit_5` |
| Study Advanced Weapon Enchantments | `advanced-weapon-attack-speed` | 250 XP | Unlocks `attack_speed_10` |
| Study Utility Enchantments | `utility-meditate` | 50 XP | Unlocks `meditate_10` |
| Study Utility Enchantments | `utility-study` | 100 XP | Unlocks `study_10` |
| Study Utility Enchantments | `utility-insight` | 150 XP | Unlocks `insight_5` |
| Study Mana Enchantments | `mana-cap-50` | 75 XP | Unlocks `mana_cap_50` |
| Study Mana Enchantments | `mana-cap-100` | 150 XP | Unlocks `mana_cap_100` |
| Study Mana Enchantments | `mana-regen-1` | 100 XP | Unlocks `mana_regen_1` |
| Study Mana Enchantments | `mana-regen-2` | 200 XP | Unlocks `mana_regen_2` |
| Study Mana Enchantments | `click-mana-1` | 125 XP | Unlocks `click_mana_1` |
| Study Mana Enchantments | `click-mana-3` | 225 XP | Unlocks `click_mana_3` |
| Study Basic Spell Enchantments | 8 perks | 50150 XP | Unlock 8 basic spell enchants |
| Study Intermediate Spell Enchantments | 6 perks | 80120 XP | Unlock 6 intermediate spell enchants |
| Study Advanced Spell Enchantments | 10 perks | 100200 XP | Unlock 10 advanced spell enchants |
| Study Special Enchantments | 6 perks | 80200 XP | Unlock 6 special enchants |
---
## 9. Attunement Level Interactions
Enchanter level does **not** directly affect enchanting mechanics (timings, costs,
capacity). It affects:
1. **Raw mana regen**: `0.5 × 1.5^(level-1)` per hour — more raw mana for enchanting
2. **Transference conversion**: `0.2 × 1.5^(level-1)` per hour — more transference mana for Enchanter disciplines
3. **Enchanting XP → Attunement XP**: 1 Enchanter XP per 10 capacity used
---
## 10. Acceptance Criteria
| # | Criterion |
|---|---|
| AC-1 | Design stage takes `1 + 0.5 × totalStacks` hours; progress accumulates at 0.04 hours/tick. |
| AC-2 | Hasty Enchanter reduces design time by 25% on repeat designs only. |
| AC-3 | Instant Designs has a 10% chance per tick to complete the design immediately. |
| AC-4 | Dual design slot is available when Enchant Mastery is active and first slot is occupied. |
| AC-5 | Prepare stage takes `2 + floor(capacity/50)` hours and costs `capacity × 10` total mana. |
| AC-6 | Prepare removes all enchantments, resets usedCapacity to 0, resets rarity to 'common'. |
| AC-7 | Disenchant recovery rate is `0.10 + disenchantLevel × 0.20` of each enchantment's actual cost. |
| AC-8 | Apply stage takes `2 + totalStacks` hours and costs `20 + sum(stacks × 5)` mana/hour. |
| AC-9 | Free enchant chances are additive (max 60%) and skip mana cost for that tick. |
| AC-10 | Pure Essence grants 1.25× stacks (ceil) for effects with base cost < 100. |
| AC-11 | Stacking cost formula: `baseCost × (1 + i × 0.2)` for stack index i, reduced by efficiencyBonus. |
| AC-12 | Cancellation refunds unspent progress at 100% and spent progress at 50%, blended. |
| AC-13 | All enchantment effects are gated behind discipline perk thresholds and cannot be used until unlocked. |
| AC-14 | Equipment type capacity limits are enforced — designs exceeding capacity are rejected. |
| AC-15 | Spell effects can only be applied to caster equipment. |
---
## 11. Files Reference
| File | Role |
|---|---|
| `src/lib/game/crafting-design.ts` | Design stage logic, timing, validation |
| `src/lib/game/crafting-prep.ts` | Prepare stage logic, disenchant recovery |
| `src/lib/game/crafting-apply.ts` | Apply stage logic, free enchant, Pure Essence |
| `src/lib/game/crafting-utils.ts` | Shared utilities, capacity cost, cancellation refund |
| `src/lib/game/crafting-attunements.ts` | Attunement-crafting integration, enchanting XP |
| `src/lib/game/data/enchantments/` | All enchantment effect definitions (7 categories) |
| `src/lib/game/crafting-actions/design-actions.ts` | Design stage store actions |
| `src/lib/game/crafting-actions/preparation-actions.ts` | Prepare stage store actions |
| `src/lib/game/crafting-actions/application-actions.ts` | Apply stage store actions |
| `src/lib/game/crafting-actions/disenchant-actions.ts` | Disenchant action |
| `src/components/game/tabs/CraftingTab.tsx` | Crafting tab wrapper |
| `src/components/game/crafting/EnchantmentDesigner.tsx` | Design UI |
| `src/components/game/crafting/EnchantmentPreparer.tsx` | Prepare UI |
| `src/components/game/crafting/EnchantmentApplier.tsx` | Apply UI |