chore: golemancy redesign cleanup — remove orphaned legacy code and update docs
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m19s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m19s
This commit is contained in:
+11
-31
@@ -768,43 +768,23 @@ Level 8: 4 slots
|
||||
Level 10: 5 slots
|
||||
```
|
||||
|
||||
### Golem Types (10 Total — undergoing redesign, see issue #268)
|
||||
### Component-Based Construction
|
||||
|
||||
#### Base Golems (1)
|
||||
Golems are designed by assembling **three mandatory components** plus optional enchantments:
|
||||
|
||||
| Golem | Element | Damage | Speed | HP | Pierce | Unlock |
|
||||
|-------|---------|--------|-------|----|--------|--------|
|
||||
| Earth Golem | Earth | 8 | 1.5/s | 50 | 15% | Fabricator 2 |
|
||||
|
||||
#### Elemental Variant Golems (3)
|
||||
|
||||
| Golem | Element | Damage | Speed | HP | Pierce | Unlock |
|
||||
|-------|---------|--------|-------|----|--------|--------|
|
||||
| Steel Golem | Metal | 12 | 1.2/s | 60 | 35% | Metal mana unlocked |
|
||||
| Crystal Golem | Crystal | 18 | 1.0/s | 40 | 25% | Crystal mana unlocked |
|
||||
| Sand Golem | Sand | 10 | 2.0/hr | 45 | 15% | Sand mana unlocked |
|
||||
|
||||
#### Hybrid Golems (6) — Require Enchanter 5 + Fabricator 5
|
||||
|
||||
| Golem | Elements | Damage | Speed | HP | Pierce | Special |
|
||||
|-------|----------|--------|-------|----|--------|---------|
|
||||
| Lava Golem | Earth + Fire | 15 | 1.0/s | 70 | 20% | AOE 2 |
|
||||
| Galvanic Golem | Metal + Lightning | 10 | 3.5/s | 45 | 45% | Fast |
|
||||
| Obsidian Golem | Earth + Dark | 25 | 0.8/s | 55 | 50% | High damage |
|
||||
| Prism Golem | Crystal + Light | 28 | 2.0/hr | 60 | 45% | AOE 3 |
|
||||
| Quicksilver Golem | Metal + Water | 14 | 4.0/hr | 55 | 35% | Very fast |
|
||||
| Voidstone Golem | Earth + Void | 40 | 0.6/s | 100 | 60% | AOE 3, ultimate |
|
||||
|
||||
### Golem Combat
|
||||
|
||||
> ⚠ The golemancy system is undergoing a full redesign (see issue #268). The current data definitions exist but are disconnected from the combat pipeline.
|
||||
| Component | Role | Count | Examples |
|
||||
|-----------|------|-------|----------|
|
||||
| **Core** | Power source: mana types, capacity, regen, upkeep, duration | 4 (Basic, Intermediate, Advanced, Guardian) | Basic Core (Earth only), Guardian Core (all guardian mana types) |
|
||||
| **Frame** | Combat stats: damage, speed, armor pierce, magic affinity, special | 7 (Earth, Sand, Frost, Crystal, Steel, Shadowglass, Crystal-Steel Hybrid) | Earth (balanced), Shadowglass (fast + AoE), Crystal-Steel Hybrid (guardian constructs) |
|
||||
| **Mind Circuit** | Behavior: basic attacks, spell casting, spell cycling | 4 (Simple, Intermediate, Advanced, Guardian) | Simple (basic only), Guardian (cycle all spells) |
|
||||
| **Enchantments** | Sword effects on basic attacks (optional) | 8 | Burn, Slow, Shock, Weaken, Armor Pierce, Crit Chance |
|
||||
|
||||
**Player upkeep formula:**
|
||||
```
|
||||
progressPerTick = HOURS_PER_TICK × attackSpeed × efficiencyBonus
|
||||
damage = baseDamage × (1 + golemMasteryBonus)
|
||||
Upkeep per hour = Core.manaRegen × 2
|
||||
```
|
||||
|
||||
Golems last `1 + golemLongevity` floors. Maintenance cost multiplier: `1 - (golemSiphon × 0.1)`.
|
||||
Golems last `Core.maxRoomDuration` rooms (3–8 depending on core tier). Stats are derived from components via `computeGolemStats()`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Circular Dependencies
|
||||
Generated: 2026-06-06T16:37:23.532Z
|
||||
Generated: 2026-06-06T17:19:20.910Z
|
||||
|
||||
No circular dependencies found. ✅
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"_meta": {
|
||||
"generated": "2026-06-06T16:37:21.673Z",
|
||||
"generated": "2026-06-06T17:19:19.033Z",
|
||||
"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."
|
||||
},
|
||||
@@ -557,6 +557,8 @@
|
||||
],
|
||||
"stores/combat-descent-actions.ts": [
|
||||
"data/guardian-encounters.ts",
|
||||
"effects/discipline-effects.ts",
|
||||
"stores/attunementStore.ts",
|
||||
"stores/combat-state.types.ts",
|
||||
"stores/golem-combat-actions.ts",
|
||||
"stores/manaStore.ts",
|
||||
|
||||
@@ -253,7 +253,7 @@ study-fabricator-recipes (root)
|
||||
|---|---|
|
||||
| `src/lib/game/data/attunements.ts` | Fabricator definition |
|
||||
| `src/lib/game/data/disciplines/fabricator.ts` | Fabricator disciplines (5) |
|
||||
| `src/lib/game/data/golems/` | Golem definitions (10 golems) |
|
||||
| `src/lib/game/data/golems/` | Golem component definitions (4 cores, 7 frames, 4 mind circuits, 8 enchantments) |
|
||||
| `src/lib/game/crafting-fabricator.ts` | Fabrication crafting logic |
|
||||
| `src/lib/game/data/fabricator-recipes.ts` | Core equipment recipes |
|
||||
| `src/lib/game/data/fabricator-material-recipes.ts` | Material recipes |
|
||||
|
||||
@@ -550,4 +550,4 @@ Directly determines base golem slots: `floor(fabricatorLevel / 2)`.
|
||||
| `src/lib/game/stores/golem-combat-actions.ts` | Golem combat actions (rewrite) |
|
||||
| `src/lib/game/stores/pipelines/golem-combat.ts` | Golem combat pipeline (rewrite) |
|
||||
| `src/components/game/tabs/GolemancyTab.tsx` | Golemancy UI (major rewrite — design builder) |
|
||||
| `docs/specs/spire-combat-spec.md §9` | Authoritative runtime spec (needs update) |
|
||||
| `docs/specs/spire-combat-spec.md §9` | Authoritative runtime spec |
|
||||
@@ -414,68 +414,81 @@ At peak incursion (day 30), regen falls to 5% of base. Practical effects:
|
||||
|
||||
### 9.1 Overview
|
||||
|
||||
Golemancy is the **Fabricator attunement's** combat contribution. Golems are
|
||||
summoned automatically at room entry, fight alongside the player, and disappear
|
||||
after a fixed number of rooms or if their maintenance cost cannot be met.
|
||||
Golemancy is the **Fabricator attunement's** combat contribution. Players design
|
||||
custom golems from components (Core + Frame + Mind Circuit + Enchantments), then
|
||||
configure a loadout. Golems are summoned automatically at room entry, fight alongside
|
||||
the player, and disappear after a fixed number of rooms or if their maintenance cost
|
||||
cannot be met.
|
||||
|
||||
### 9.2 Golem Loadout (Outside Spire)
|
||||
|
||||
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 spire. The loadout defines which golem designs to attempt to summon and in what
|
||||
order. This configuration persists across rooms but not across spire runs.
|
||||
|
||||
### 9.3 Summoning on Room Entry
|
||||
|
||||
When the player enters a new combat room:
|
||||
When the player enters a new combat room, `summonGolemsOnRoomEntry()` iterates the
|
||||
loadout in priority order:
|
||||
|
||||
```
|
||||
onRoomEntry():
|
||||
for each golem in golemLoadout:
|
||||
if player has enough mana of golem.summonCostType >= golem.summonCost:
|
||||
deductMana(golem.summonCost, golem.summonCostType)
|
||||
summonGolemsOnRoomEntry(loadout, rawMana, elements, currentFloor, existingActiveGolems, disciplineSlotsBonus, fabricatorLevel):
|
||||
for each entry in loadout:
|
||||
if !entry.enabled → skip
|
||||
if activeGolems.length >= totalSlots → break // max 7
|
||||
if already active → skip
|
||||
resolve components (Core, Frame, Mind Circuit) from design
|
||||
stats = computeGolemStats(componentDesign)
|
||||
if player can afford stats.totalSummonCost:
|
||||
deduct summon cost from player mana
|
||||
activeGolems.push({
|
||||
...golemDef,
|
||||
roomsRemaining: golemDef.maxRoomDuration,
|
||||
designId: entry.designId,
|
||||
summonedFloor: currentFloor,
|
||||
attackProgress: 0,
|
||||
roomsRemaining: stats.maxRoomDuration,
|
||||
currentMana: stats.manaCapacity, // starts full
|
||||
spellCastIndex: 0,
|
||||
})
|
||||
activityLog("${golem.name} summoned")
|
||||
else:
|
||||
activityLog("Not enough mana to summon ${golem.name} — skipped")
|
||||
log "Not enough mana — skipped"
|
||||
```
|
||||
|
||||
Total slots = `min(7, floor(fabricatorLevel / 2) + disciplineBonus)`.
|
||||
|
||||
Golems that could not be summoned (insufficient mana) are **not re-attempted**
|
||||
within the same room. They will be attempted again on the next room entry.
|
||||
|
||||
### 9.4 Golem Combat
|
||||
|
||||
Each active golem attacks on its own `attackProgress` timer, identical to swords:
|
||||
Each active golem attacks on its own `attackProgress` timer:
|
||||
|
||||
```
|
||||
golemProgress += HOURS_PER_TICK × golem.attackSpeed
|
||||
while golemProgress >= 1:
|
||||
dmg = golem.baseDamage
|
||||
// Apply golem's own elemental type if it has one
|
||||
if golem.element:
|
||||
dmg ×= getElementalBonus(golem.element, enemy.element)
|
||||
// Apply golem special effects (DoT, armor pierce, AoE, etc.)
|
||||
applyGolemEffects(golem, dmg, enemy)
|
||||
applyDamageToRoom(dmg)
|
||||
golemProgress -= 1
|
||||
attackProgress += HOURS_PER_TICK × frame.attackSpeed
|
||||
while attackProgress >= 1:
|
||||
if mindCircuit has spells && golem.currentMana >= spellCost:
|
||||
cast spell: damage = baseSpellDamage × frame.magicAffinity
|
||||
golem.currentMana -= spellCost
|
||||
spellCastIndex = (spellCastIndex + 1) % selectedSpells.length
|
||||
else:
|
||||
dmg = frame.baseDamage × (1 + frame.armorPierce)
|
||||
apply enchantment effects (burn, slow, etc.)
|
||||
applyDamageToRoom(dmg)
|
||||
attackProgress -= 1
|
||||
```
|
||||
|
||||
Golems ignore Executioner and Berserker discipline specials.
|
||||
|
||||
### 9.5 Maintenance Cost
|
||||
|
||||
Each tick, each active golem checks its maintenance cost:
|
||||
Each tick, `processGolemMaintenance()` checks upkeep for each active golem:
|
||||
|
||||
```
|
||||
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")
|
||||
upkeepPerTick = core.manaRegen × 2 × HOURS_PER_TICK
|
||||
if player has enough of core.primaryManaType:
|
||||
deduct upkeepPerTick from player element mana
|
||||
else:
|
||||
dismiss(golem)
|
||||
log "${name} dismissed — insufficient mana for upkeep"
|
||||
```
|
||||
|
||||
A dismissed golem is **not re-summoned mid-room**. It will be re-attempted on the
|
||||
@@ -483,13 +496,14 @@ next room entry if mana has recovered.
|
||||
|
||||
### 9.6 Room Duration Limit
|
||||
|
||||
`countdownGolemRoomDuration()` runs on room clear:
|
||||
|
||||
```
|
||||
onRoomCleared():
|
||||
for each activeGolem:
|
||||
activeGolem.roomsRemaining -= 1
|
||||
if activeGolem.roomsRemaining <= 0:
|
||||
dismiss(golem)
|
||||
activityLog("${golem.name} has faded after ${maxRoomDuration} rooms")
|
||||
for each activeGolem:
|
||||
golem.roomsRemaining -= 1
|
||||
if golem.roomsRemaining <= 0:
|
||||
dismiss(golem)
|
||||
log "${name} has faded after ${maxRoomDuration} rooms"
|
||||
```
|
||||
|
||||
Room duration ticks down on room clear, not on room entry — golems persist through
|
||||
@@ -497,25 +511,38 @@ the full room they were summoned in.
|
||||
|
||||
### 9.7 Golem Data Shape
|
||||
|
||||
The runtime active golem type (`RuntimeActiveGolem` in `types/game.ts`):
|
||||
|
||||
```typescript
|
||||
interface GolemDefinition {
|
||||
id: string;
|
||||
name: string;
|
||||
tier: number; // 1–4 (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;
|
||||
interface RuntimeActiveGolem {
|
||||
designId: string; // Reference to the player's GolemDesign
|
||||
summonedFloor: number; // Floor when golem was summoned
|
||||
attackProgress: number; // Progress toward next attack (accumulated)
|
||||
roomsRemaining: number; // Rooms before golem fades
|
||||
currentMana: number; // Current mana in golem's own pool
|
||||
spellCastIndex: number; // For alternating/cycling spell circuits
|
||||
}
|
||||
```
|
||||
|
||||
The serialized design type (`SerializedGolemDesign` in `types/game.ts`):
|
||||
|
||||
```typescript
|
||||
interface SerializedGolemDesign {
|
||||
id: string;
|
||||
name: string;
|
||||
coreId: string;
|
||||
frameId: string;
|
||||
mindCircuitId: string;
|
||||
enchantmentIds: string[];
|
||||
selectedManaTypes: string[];
|
||||
selectedSpells: string[];
|
||||
}
|
||||
```
|
||||
|
||||
Golem stats are computed from components via `computeGolemStats()` in
|
||||
`data/golems/utils.ts`, which sums summon costs from all components and derives
|
||||
upkeep from `core.manaRegen × 2`.
|
||||
|
||||
---
|
||||
|
||||
## 10. In-Game Time Display
|
||||
@@ -545,7 +572,7 @@ They are **in scope for the implementation this spec describes**:
|
||||
| Mage barrier recharge | `MODIFIER_CONFIG.mage.barrierRechargeRate` | Data-only | Tick in `onDamageDealt` §5.2 |
|
||||
| Guardian armor | `GuardianDef.armor` | Data-only | Add check to guardian pipeline §5.3 |
|
||||
| DoT / debuff system | Spell/enchantment type defs | **Implemented** — `dot-runtime.ts` complete and wired into combat tick; curse amplification added (issue #286) | Verified working |
|
||||
| Golemancy combat | Full golem data exists | Disconnected | Implement per §9 |
|
||||
| Golemancy combat | Full golem data + runtime | **Implemented** — component-based system complete | Verified working |
|
||||
| Sword melee attacks | Weapon type exists | **Implemented** — meleeProgress with enemy defense application (issue #285) | Add `meleeProgress` per §3.1 |
|
||||
| AoE target distribution | `SpellDefinition.aoe` flag | Partial | Implement per §3.2 |
|
||||
| `elemMasteryBonus` | Stub in `calcDamage` | Hardcoded `1` | Future — leave as `1` for now |
|
||||
|
||||
Reference in New Issue
Block a user