Files
Mana-Loop/docs/specs/attunements/enchanter/systems/room-enchantments-spec.md
T
n8n-gitea 718aed38b1
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m21s
feat: implement Transference Channel system for Enchanter attunement
- Add isChanneling, channelSpeedMultiplier, channelDrainRate to CombatState
- Add startChanneling/stopChanneling actions to combat store
- Add transference-channeling discipline with 3 perks (channel-efficiency, channel-power, channel-mastery)
- Add channelIntensity and channelEfficiency to KNOWN_BONUS_STATS
- Create combat-channel.ts with drain + speed multiplier computation
- Apply channel speed multiplier to equipment spells and melee attacks
- Add Channel Transference hold-button UI to SpireCombatPage
- Add compact channel status indicator to SpireCombatControls
- Channel state resets on spire exit, persists across room transitions
- All 1235 existing tests pass
2026-06-14 21:56:20 +02:00

573 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Room Enchantments System — Design Spec
> Describes the Room Enchantments system: a semi-combat, semi-preparation system for the
> Enchanter attunement. Footwear enchantments passively stamp the room with elemental auras
> during combat. The longer the fight, the more the room becomes the Enchanter's weapon.
---
## 1. Objective
The Enchanter currently has no active combat system. The enchanting pipeline (Design →
Prepare → Apply) is entirely offline. The Room Enchantments system adds an **always-on
combat presence** that scales with time: as the Enchanter fights in a room, their enchanted
footwear gradually covers the room with elemental aura effects that damage enemies, apply
debuffs, or buff the player.
**Design goals:**
- Give the Enchanter an active combat identity distinct from Invocation (parallel cast
track) and Golemancy (summoned units): the **environmental controller**
- Create a "semi-combat, semi-preparation" loop: choose footwear enchantments offline,
then they work passively during combat with no active input required
- Give transference mana a combat application through the `boots_sigil_transference`
enchantment and the coverage-rate discipline
- Make longer fights (especially guardians) more rewarding the longer they go
- Keep the system simple: one coverage meter, linear scaling, no thresholds or activation
decisions during combat
---
## 2. Identity
| Property | Value |
|---|---|
| **System name** | Room Enchantments |
| **Attunement** | Enchanter |
| **Equipment slot** | Feet |
| **Core resource** | Coverage meter (0100) per room |
| **Primary mana** | Transference (discipline fuel + transference sigil regen) |
| **Combat role** | Environmental aura control — scales with time-in-combat |
| **Preparation** | Enchant boots via the existing Design → Prepare → Apply pipeline |
| **Active element** | None — entirely passive during combat |
### Attunement Comparison
| Attunement | Combat Identity | Scaling | Player Input |
|---|---|---|---|
| Invoker | Parallel auto-cast (guardian spells) | Charge meter fill/spend | Auto-activate |
| Fabricator | Summoned golems (independent actors) | Golem maintenance | Design golems offline |
| **Enchanter** | **Environmental aura control** | **Time-in-combat coverage** | **Enchant boots offline** |
---
## 3. Core Mechanic: The Coverage Meter
### 3.1 The Meter
Each room has a single **coverage meter** from 0 to 100, stored on `FloorState`:
```typescript
// Addition to FloorState in types/game.ts
roomEnchantment: {
coverage: number; // 0-100, current coverage percentage
} | null; // null when no footwear room enchantments are equipped
```
- `null` when the player has no footwear with room enchantment sigils equipped.
- Initialized to `{ coverage: 0 }` on room entry if footwear has room enchantments.
- Resets to 0 on every room transition (fresh room, fresh canvas).
### 3.2 Coverage Growth
Coverage grows by a flat amount per combat tick:
```
coveragePerTick = baseRate + disciplineBonus
where:
baseRate = 0.2
disciplineBonus = roomCoverageRateBonus (from the `room-coverage-rate` capped perk)
```
At base rate (no discipline bonus):
- 0.2 per tick → 500 ticks to reach 100
- At 200ms/tick → **100 seconds real time** to full coverage
Coverage growth requires ALL of the following:
1. Player is in `climb` action
2. Current room has living enemies (`floorHP > 0`)
3. Player has at least one footwear room enchantment equipped
Coverage does **NOT** scale with cast speed, attack speed, transference spending, or any
other stat. It is purely time-based. This is intentional — the system is designed to be
zero-input during combat.
### 3.3 Coverage Cap
Coverage is hard-capped at 100. Once full, room enchantments operate at full strength and
stop accumulating.
---
## 4. Enchantment Definitions
### 4.1 Effect Category
Room enchantments use `category: 'special'` with unique `specialId` values, following the
exact same pattern as existing equipment effects (e.g., `sword_fire``specialId:
'fireBlade'`). They are defined alongside existing enchantment definitions.
Allowed equipment category: `['feet']` only.
### 4.2 Effect Structure
```typescript
// Room enchantment effects use the same EnchantmentEffectDef type
// category: 'special'
// effect.type: 'special'
// effect.specialId: a unique string handled by the room enchantment tick processor
```
The `specialId` is a new convention: `room_<element>_<effectType>` (e.g.,
`room_fire_damage`, `room_frost_debuff`, `room_transference_buff`).
> **Note:** Room enchantment `specialId` values use the game's existing mana type names
> (e.g., `death` not `poison`, `transference` not `arcane`) for consistency with the
> 22 defined mana types.
### 4.3 Scaling Formula
Each room enchantment's effect scales linearly with coverage:
```
effectMagnitude = baseMagnitude × (coverage / 100)
```
Examples:
- `boots_sigil_fire` at 25% coverage: burn = 5 × 0.25 = **1.25 damage/tick** to all enemies
- `boots_sigil_fire` at 50% coverage: burn = 5 × 0.50 = **2.5 damage/tick** to all enemies
- `boots_sigil_fire` at 100% coverage: burn = 5 × 1.00 = **5 damage/tick** to all enemies
All magnitudes are floating-point. Damage per tick is applied as-is (not rounded per
tick; rounding only occurs on display).
### 4.4 Enchantment Table
| Enchant ID | Name | specialId | Effect Type | Base Magnitude (at 100%) | Capacity Cost |
|---|---|---|---|---|---|
| `boots_sigil_fire` | Blazing Footsteps | `room_fire_damage` | Room DoT (burn all enemies) | 5 dmg/tick | 30 |
| `boots_sigil_frost` | Frozen Trail | `room_frost_debuff` | Enemy slow | 10% slow | 25 |
| `boots_sigil_death` | Necrotic Tread | `room_death_damage` | Room DoT (death all enemies) | 3 dmg/tick | 25 |
| `boots_sigil_lightning` | Shocking Stride | `room_lightning_damage` | Single-target chain dmg | 3 dmg/tick random enemy | 28 |
| `boots_sigil_dark` | Shadow Patch | `room_dark_dodge_debuff` | Enemy dodge reduction | 10% dodge | 22 |
| `boots_sigil_earth` | Scoured Earth | `room_earth_armor_debuff` | Enemy armor reduction | 5% armor | 28 |
| `boots_sigil_transference_ground` | Transference Grounds | `room_transference_buff` | Player cast speed | +5% cast speed | 20 |
| `boots_sigil_transference_path` | Conductive Path | `room_transference_regen` | Transference mana regen | +10%/hr regen | 20 |
All costs fit within footwear capacity range (1535), meaning players can fit 12 room
enchantments per pair of boots.
### 4.5 Effect Application Rules
**DoT effects** (damage over time: fire, death, lightning):
- Applied to ALL living enemies in the room each tick
- Bypass armor — room-wide DoT ignores enemy armor, dodge, and barrier
- Do NOT apply to dead enemies (hp ≤ 0)
- For single-target effects (lightning): target is chosen randomly among living enemies
each tick
**Debuff effects** (frost slow, dark dodge reduction, dark armor reduction):
- Applied as a modifier to all living enemies, recalculated each tick based on current
coverage
- Slow: reduces enemy dodge chance (negative value subtracted from base dodge)
- Dodge reduction: directly reduces enemy dodge chance
- Armor reduction: directly reduces enemy effectiveArmor (minimum 0)
- Applied at the end of the room enchantment phase (after the DoT/debuff phase). Debuffs
take effect on the **next** tick — there is a one-tick delay before reduced dodge/armor
affects incoming attacks. This is intentional: the room enchantment phase runs late in
the tick pipeline.
**Buff/Regen effects** (transference cast speed, transference regen):
- Applied as a modifier to the player's combat bonuses, recalculated each tick
- Stored in the combat tick result and factored into existing `computeAllEffects()` math
- Cast speed: added to `attackSpeedMultiplier` as `1 + (baseBonus × coverage%)`
- Transference regen: added to transference mana regen per hour as `baseRegen × coverage%`
> **Note on debuff timing:** Because the room enchantment phase runs after the DoT/debuff
> phase in the tick pipeline, debuffs (frost slow, dark dodge reduction, dark armor reduction)
> are applied to enemy state at the end of the tick. The modified enemy stats take effect
> on the **following** tick when the enemy defense pipeline runs. This means there is always
> a one-tick delay between coverage growth and debuff impact on incoming attacks.
### 4.6 Stacking Multiple Enchantments
If the player has two room enchantments on their boots (e.g., `boots_sigil_fire` +
`boots_sigil_frost`):
- Both share the same coverage meter (there is only one)
- Both scale off the same coverage percentage
- Both apply their effects independently each tick
- Total capacity cost must fit within the footwear's total capacity
---
## 5. State Changes
### 5.1 FloorState (`types/game.ts`)
```typescript
export interface FloorState {
// ... all existing fields ...
// Room enchantment state — null when no footwear room enchants are equipped
roomEnchantment: {
coverage: number; // 0-100
} | null;
}
```
### 5.2 Combat Store Additions
The combat store needs a new field to persist the previous room's coverage across room
transitions (for the `resonant-stamps` perk). Add to `CombatState` in
`combat-state.types.ts`:
```typescript
// Room enchantment carryover (for resonant-stamps perk)
lastRoomCoverage: number; // 0-20, carryover from previous room, resets on spire exit
```
And the corresponding action:
```typescript
setLastRoomCoverage: (value: number) => void;
```
### 5.3 Combat Processing
The room enchantment tick is processed in `combat-actions.ts``processCombatTick()`,
executed in the tick pipeline immediately after the DoT/debuff phase:
```
Tick order in processCombatTick:
1. Golem maintenance
2. Active spell casting
3. Equipment spell states
4. Invocation tick
5. Melee attacks
6. Golem attacks
7. DoT/debuff tick processing
8. ── Room enchantment tick ← NEW
> **File size note:** `combat-actions.ts` is currently 377 lines. Adding the room
> enchantment phase may push it toward the 400-line limit. If so, extract the phase
> logic into a new file (e.g., `combat-room-enchantments.ts`) and call it from
> `processCombatTick`.
```
### 5.4 New Utility File
A new file `src/lib/game/utils/room-enchantments-utils.ts` exports:
```typescript
// Compute coverage per tick from discipline stats
export function computeCoveragePerTick(disciplineBonus: number): number;
// Apply all room enchantment effects for one tick
// Returns updated { enemies, rawMana, elementStates, playerBuffs }
export function applyRoomEnchantmentTick(params: {
coverage: number;
auraMagnitude: number; // roomEnchantmentAuraMagnitude from discipline effects
equippedRoomEnchantments: Array<{ specialId: string; baseMagnitude: number }>;
enemies: EnemyState[];
rawMana: number;
elements: Record<string, { current: number; max: number; unlocked: boolean }>;
}): {
enemies: EnemyState[];
rawMana: number;
elements: Record<string, { current: number; max: number; unlocked: boolean }>;
playerBuffs: {
castSpeedBonus: number;
transferenceRegenBonus: number;
};
};
// Get list of room enchantment effects from equipped footwear
export function getEquippedRoomEnchantments(
equippedInstances: Record<string, string | null>,
equipmentInstances: Record<string, EquipmentInstance>,
): Array<{ specialId: string; baseMagnitude: number }>;
```
### 5.5 Room Transition Behavior
Coverage resets on every room transition. This is handled in the existing
`advanceRoomOrFloor()` flow in `combat-descent-actions.ts`:
- When a new `FloorState` is generated (via `generateSpireFloorState()`), the new room
starts with `roomEnchantment: null`
- Just before the `FloorState` is finalized, the current room's coverage is saved to
`lastRoomCoverage` on the combat store (capped at 20 if `resonant-stamps` perk is
active, otherwise 0)
- At the start of the combat tick, if `roomEnchantment` is null and the player has
footwear room enchantments equipped, it is initialized to
`{ coverage: lastRoomCoverage }`
- If the player has no footwear room enchantments, it stays null and the room
enchantment tick is skipped entirely
- `lastRoomCoverage` resets to 0 on spire exit
---
## 6. Discipline Integration
### 6.1 New Discipline: Room Enchanting
A new Enchanter discipline that directly enhances the Room Enchantment system.
**Definition:**
| Field | Value |
|---|---|
| **ID** | `room-enchanting` |
| **Name** | Room Enchanting |
| **Attunement** | `enchanter` |
| **Mana Type** | `transference` |
| **Base Cost** | 10 |
| **Stat Bonus** | `roomEnchantmentAuraMagnitude` +0.10 (base) |
| **Scaling Factor** | 100 |
| **Difficulty Factor** | 150 |
| **Drain Base** | 3 |
**Main stat: `roomEnchantmentAuraMagnitude`**
This stat is a multiplier on all room enchantment aura magnitudes:
```
effectMagnitude = baseMagnitude × coverage% × (1 + roomEnchantmentAuraMagnitude)
```
The stat scales with XP via the standard discipline math:
```
StatBonus = baseValue × (XP / scalingFactor)^0.65
= 0.10 × (XP / 100)^0.65
```
This replaces the old `empowered-auras` perk — the main stat now continuously scales
aura strength, while a new capped perk handles coverage rate.
**Magnitude scaling at key XP levels:**
| XP | Stat Bonus | Magnitude Multiplier | Fire DoT @ 100% coverage |
|---|---|---|---|
| 0 | +0.000 | 1.000× | 5.00 dmg/tick |
| 100 | +0.100 | 1.100× | 5.50 dmg/tick |
| 300 | +0.204 | 1.204× | 6.02 dmg/tick |
| 500 | +0.285 | 1.285× | 6.42 dmg/tick |
| 1000 | +0.447 | 1.447× | 7.23 dmg/tick |
| 2000 | +0.701 | 1.701× | 8.50 dmg/tick |
**Perks:**
| Perk ID | Type | Threshold | Bonus | Description |
|---|---|---|---|---|
| `room-coverage-rate` | `capped` | 100 | Coverage rate +0.03/tick per tier, max 4 tiers | Room fills faster with each tier |
| `resonant-stamps` | `once` | 500 | Carry 20% coverage between rooms (max 20% starting coverage) | Head start on each room, but never instant |
**Perk details:**
- **`room-coverage-rate`** (capped, threshold 100 XP, interval 150 XP, max 4 tiers): Each
tier adds +0.03/tick to the coverage growth rate. Tier progression: 1 tier at 100 XP,
2 tiers at 250 XP, 3 tiers at 400 XP, 4 tiers at 550 XP (capped).
| Tiers | Rate Bonus | Total Rate | Seconds to Fill |
|---|---|---|---|
| 0 (no perk) | +0.00 | 0.20/tick | 100.0s |
| 1 (100 XP) | +0.03 | 0.23/tick | 87.0s |
| 2 (250 XP) | +0.06 | 0.26/tick | 76.9s |
| 3 (400 XP) | +0.09 | 0.29/tick | 69.0s |
| 4 (550 XP) | +0.12 | 0.32/tick | 62.5s |
At max tier (4), the room fills in ~62.5 seconds instead of 100 seconds — a 37.5%
speedup. The perk is capped so coverage always requires meaningful combat time.
- **`resonant-stamps`** (once @ 500 XP): When transitioning between rooms on the same
floor, the carryover is computed as `min(20, previousRoom.coverage × 0.2)`. This means
20% of the previous room's coverage value carries over, capped at a maximum of 20
percentage points. Examples: ending at 80% → next room starts at 16%; ending at 100% →
next room starts at 20% (the cap). This ensures the player always needs to actively
build coverage during combat — the perk provides a head start but never eliminates the
buildup phase.
**State persistence:** The carryover value is stored in `lastRoomCoverage` on the
combat store (see §5.2). When `advanceRoomOrFloor()` generates a new `FloorState`
with `roomEnchantment: null`, the room enchantment tick reads `lastRoomCoverage` to
initialize the new room's starting coverage. This field persists across room
transitions within a climb but resets to 0 on spire exit.
**Combined progression at key XP levels (stat + capped perk):**
| XP | Coverage Rate | Magnitude | Fire DoT @ 100% | Time to Fill |
|---|---|---|---|---|
| 0 | 0.20/tick | 1.000× | 5.00 dmg/tick | 100.0s |
| 100 | 0.23/tick | 1.100× | 5.50 dmg/tick | 87.0s |
| 300 | 0.26/tick | 1.204× | 6.02 dmg/tick | 76.9s |
| 500 | 0.29/tick | 1.285× | 6.42 dmg/tick | 69.0s |
| 1000 | 0.32/tick | 1.447× | 7.23 dmg/tick | 62.5s |
| 2000 | 0.32/tick | 1.701× | 8.50 dmg/tick | 62.5s |
The capped perk maxes out at 550 XP (4 tiers, 0.32/tick, 62.5s). Beyond that, only the
main stat continues to grow, increasing aura magnitude. At 2000 XP, the room still takes
62.5 seconds to fill but fire does 8.50 dmg/tick instead of 5.00 — a 70% damage
increase from the main stat alone.
### 6.2 Discipline Dependency
```
room-enchanting (root — no prerequisites)
```
This is a root discipline with no prerequisites, making it available as soon as the
Enchanter attunement is active.
### 6.3 Stat Registration
The new stat `roomEnchantmentAuraMagnitude` must be added to:
- `KNOWN_BONUS_STATS` in `discipline-effects.ts`
- The `addBonus()` routing in `computeDisciplineEffects()` (no special routing needed —
it's a standard bonus stat)
### 6.4 Enchantment Unlock Perks
Room enchantment effects are unlocked via perks on the new discipline:
| Perk ID | Type | Threshold | Unlocks |
|---|---|---|---|
| `room-sigil-fire` | `once` | 50 | `boots_sigil_fire` |
| `room-sigil-frost` | `once` | 75 | `boots_sigil_frost` |
| `room-sigil-death` | `once` | 100 | `boots_sigil_death` |
| `room-sigil-lightning` | `once` | 125 | `boots_sigil_lightning` |
| `room-sigil-dark` | `once` | 150 | `boots_sigil_dark` |
| `room-sigil-earth` | `once` | 175 | `boots_sigil_earth` |
| `room-sigil-transference-ground` | `once` | 100 | `boots_sigil_transference_ground` |
| `room-sigil-transference-path` | `once` | 125 | `boots_sigil_transference_path` |
---
## 7. Data Flow Summary
```
gameStore.tick()
→ buildTickContext() [snapshots all stores]
→ processCombatTick() [combat-actions.ts]
→ ... (golem, spell, equipment, invocation, melee, DoT phases) ...
→ Room Enchantment Phase:
1. If roomEnchantment is null and player has footwear room enchants:
Initialize roomEnchantment = { coverage: lastRoomCoverage }
2. If roomEnchantment is not null AND floorHP > 0:
a. coverage += 0.2 + roomCoverageRateBonus
b. Clamp coverage to 100
c. Magnitude multiplier = 1.0 + roomEnchantmentAuraMagnitude
d. For each equipped room enchantment:
- Compute magnitude = baseMagnitude × (coverage / 100) × magnitude multiplier
e. Apply to enemies (DoT/debuffs) or player (buffs)
f. Recalculate floorHP from updated enemy HP
→ applyTickWrites() [writes combat store changes back]
On room transition (advanceRoomOrFloor):
→ Before generating new FloorState, save current coverage to combat store:
lastRoomCoverage = resonant-stamps active ? min(20, currentRoom.coverage * 0.2) : 0
→ New FloorState generated with roomEnchantment: null
→ Room enchantment tick reads lastRoomCoverage to initialize starting coverage
```
---
## 8. UI Changes
### 8.1 RoomDisplay Component
Add a **Room Enchantment Bar** to the combat room display in `RoomDisplay.tsx`, shown
only when the player has footwear room enchantments equipped and the room has living
enemies:
```
┌─────────────────────────────────────────────┐
│ 🔥 Blazing Footsteps ████████████░░░░ 62% │
│ → Enemies burning: 3.1 dmg/tick │
│❄️ Frozen Trail ████████████░░░░ 62% │
│ → Enemies slowed: 6.2% │
└─────────────────────────────────────────────┘
```
- Progress bar showing coverage percentage (0100%)
- Color-coded by element (fire = red, frost = blue, etc.)
- Shows current effect magnitude in text below each bar
- Only displayed when `roomEnchantment` is not null
### 8.2 Enchantment Designer
Room enchantment effects appear in the existing `EffectSelector` component under a new
"Room" filter category (or under "Special" with a "Room Only" tag). They are only
selectable when the equipment type being designed for is in the `feet` category.
### 8.3 No New Tabs
The room enchantment system does not require a new tab. All information is visible in
the existing SpireCombatPage layout and the existing CraftingTab enchantment designer.
---
## 9. Acceptance Criteria
| # | Criterion |
|---|---|
| AC-1 | `roomEnchantment` field exists on `FloorState` and defaults to `null`. |
| AC-2 | Coverage initializes to `{ coverage: 0 }` on room entry when footwear has room enchantments equipped. |
| AC-3 | Coverage resets to 0 on every room transition (new room = fresh coverage). |
| AC-4 | Coverage grows at 0.2 per tick while in `climb` action with living enemies. |
| AC-5 | Coverage is hard-capped at 100. |
| AC-6 | Coverage does NOT grow when `floorHP <= 0` or `currentAction !== 'climb'`. |
| AC-7 | At base rate (no discipline), coverage reaches 100 in ~100 seconds real time (500 ticks). |
| AC-8 | Room DoT effects (fire, death, lightning) apply to ALL living enemies each tick, bypassing armor. |
| AC-9 | Room debuff effects (frost slow, dark dodge reduction, earth armor reduction) modify enemy stats at end of room enchantment phase (one-tick delay before affecting incoming attacks). |
| AC-10 | Room buff effects (transference cast speed, transference regen) are factored into player stat computation. |
| AC-11 | Effect magnitudes scale linearly: `baseMagnitude × (coverage / 100)`. |
| AC-12 | Multiple room enchantments on one pair of boots share the same coverage meter and apply independently. |
| AC-13 | Total capacity cost of room enchantments must fit within footwear capacity (1535). |
| AC-14 | The `room-enchanting` discipline uses transference mana and has `roomEnchantmentAuraMagnitude` as its stat. |
| AC-15 | `room-coverage-rate` capped perk adds +0.03/tick per tier, max 4 tiers. |
| AC-16 | `room-coverage-rate` capped perk reaches max 4 tiers at 550 XP (0.12/tick, 62.5s to fill). |
| AC-17 | `resonant-stamps` once perk computes carryover as `min(20, previousRoom.coverage × 0.2)`, stored in `lastRoomCoverage` on the combat store. |
| AC-18 | Room enchantment effects are unlocked via discipline perks at the specified XP thresholds. |
| AC-19 | Room enchantment effects only appear in the EffectSelector when designing for `feet` equipment. |
| AC-20 | RoomDisplay shows coverage bar and current effect magnitudes when room enchantments are active. |
| AC-21 | Existing saves without `roomEnchantment` field default to `null` (backward compatible). |
| AC-22 | Existing saves without `roomEnchantmentAuraMagnitude` stat default to 0 (backward compatible). |
---
## 10. Files Reference
| File | Role |
|---|---|
| `src/lib/game/types/game.ts` | Add `roomEnchantment` field to `FloorState` |
| `src/lib/game/data/enchantments/special-effects.ts` | Add room enchantment effect definitions (8 effects) |
| `src/lib/game/data/disciplines/enchanter.ts` | Add `room-enchanting` discipline definition with perks |
> **Implementation note:** `enchanter.ts` currently has 4 disciplines (146 lines). Adding
> `room-enchanting` with its ~8 unlock perks may push it toward the 400-line limit.
> If so, create a new file `enchanter-combat.ts` (following the existing pattern of
> `enchanter-utility.ts`, `enchanter-spells.ts`, etc.) and re-export from
> `data/disciplines/index.ts`.
| `src/lib/game/effects/discipline-effects.ts` | Add `roomEnchantmentAuraMagnitude` to `KNOWN_BONUS_STATS` |
| `src/lib/game/stores/combat-actions.ts` | Add room enchantment phase in `processCombatTick` (after DoT phase) |
| `src/lib/game/utils/room-enchantments-utils.ts` | **NEW** — Coverage computation, effect application, equipment scanning |
| `src/components/game/tabs/SpireCombatPage/RoomDisplay.tsx` | Add coverage bar and effect magnitude display |
| `src/components/game/crafting/EnchantmentDesigner/EffectSelector.tsx` | Show room enchantments when designing for feet |
| `docs/specs/attunements/enchanter/systems/room-enchantments-spec.md` | **THIS FILE** |
---
## 11. Out of Scope
- Active player input during combat (no button to spend transference for faster coverage)
- Coverage scaling with cast speed, attack speed, or any combat stat
- Coverage persisting between rooms at launch (added only via `resonant-stamps` perk)
- Room enchantments on non-footwear equipment slots
- Room enchantments interacting with golem combat
- Room enchantments affecting non-combat rooms (library, recovery, treasure, puzzle)
- Visual effects / animations for the coverage bar (UI-only indicator in v1)
- Room enchantment effects that heal the player (violates no-healing rule)
- More than 8 room enchantment types in v1
- Composite or exotic element room sigils in v1 (base 7 + transference only)