diff --git a/docs/circular-deps.txt b/docs/circular-deps.txt index fc7bf2e..3481919 100644 --- a/docs/circular-deps.txt +++ b/docs/circular-deps.txt @@ -1,5 +1,5 @@ # Circular Dependencies -Generated: 2026-06-13T11:02:39.214Z +Generated: 2026-06-13T11:42:23.525Z Found: 4 circular chain(s) — these MUST be fixed before modifying involved files. 1. 1) data/guardian-encounters.ts > data/guardian-procedural.ts diff --git a/docs/dependency-graph.json b/docs/dependency-graph.json index 1218209..755a312 100644 --- a/docs/dependency-graph.json +++ b/docs/dependency-graph.json @@ -1,6 +1,6 @@ { "_meta": { - "generated": "2026-06-13T11:02:37.078Z", + "generated": "2026-06-13T11:42:21.085Z", "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." }, @@ -555,6 +555,8 @@ "data/guardian-encounters.ts", "effects/discipline-effects.ts", "stores/combat-damage.ts", + "stores/combat-invocation.ts", + "stores/combat-melee.ts", "stores/combat-state.types.ts", "stores/dot-runtime.ts", "stores/golem-combat-actions.ts", @@ -581,6 +583,24 @@ "stores/prestigeStore.ts", "utils/spire-utils.ts" ], + "stores/combat-invocation.ts": [ + "constants.ts", + "data/guardian-encounters.ts", + "effects/discipline-effects.ts", + "stores/combat-damage.ts", + "stores/combat-state.types.ts", + "types.ts", + "utils/index.ts", + "utils/invocation-utils.ts" + ], + "stores/combat-melee.ts": [ + "constants.ts", + "data/guardian-encounters.ts", + "stores/combat-damage.ts", + "stores/combat-state.types.ts", + "types.ts", + "utils/index.ts" + ], "stores/combat-reset.ts": [ "stores/combat-actions.ts", "stores/combat-state.types.ts", @@ -589,7 +609,8 @@ "utils/spire-utils.ts" ], "stores/combat-state.types.ts": [ - "types.ts" + "types.ts", + "utils/invocation-utils.ts" ], "stores/combatStore.ts": [ "data/guardian-encounters.ts", @@ -934,6 +955,13 @@ "utils/result.ts", "utils/safe-persist.ts" ], + "utils/invocation-utils.ts": [ + "constants/spells.ts", + "data/guardian-encounters.ts", + "types.ts", + "utils/combat-utils.ts", + "utils/mana-utils.ts" + ], "utils/mana-utils.ts": [ "constants.ts", "data/attunements.ts", diff --git a/src/lib/game/stores/combat-actions.ts b/src/lib/game/stores/combat-actions.ts index 0323118..7343a87 100644 --- a/src/lib/game/stores/combat-actions.ts +++ b/src/lib/game/stores/combat-actions.ts @@ -134,6 +134,7 @@ export function processCombatTick( // ─── Spell casting (only when a valid spell is configured) ──────────────── if (spellDef) { const disciplineEffects = computeDisciplineEffects(); + // AC-13: Pact affinity cast speed bonus already applied to attackSpeedMult by gameStore const totalAttackSpeed = attackSpeedMult; const spellCastSpeed = spellDef.castSpeed || 1; const progressPerTick = HOURS_PER_TICK * spellCastSpeed * totalAttackSpeed; @@ -205,7 +206,7 @@ export function processCombatTick( const isESpellAoe = !!eSpellDef.isAoe; const eSpellCastSpeed = eSpellDef.castSpeed || 1; - const eProgressPerTick = HOURS_PER_TICK * eSpellCastSpeed * attackSpeedMult; + const eProgressPerTick = HOURS_PER_TICK * eSpellCastSpeed * totalAttackSpeed; let eCastProgress = (eSpell.castProgress || 0) + eProgressPerTick; let eSafetyCounter = 0; diff --git a/src/lib/game/stores/combat-invocation.ts b/src/lib/game/stores/combat-invocation.ts index 6f2ebeb..604e481 100644 --- a/src/lib/game/stores/combat-invocation.ts +++ b/src/lib/game/stores/combat-invocation.ts @@ -15,7 +15,6 @@ import { selectInvocationSpell, deductInvocationSpellCost, computeChargeFillRate, - computeCastSpeedBonus, computeCostMultiplier, computeDrainRateMultiplier, computeDrainPerTick, @@ -172,12 +171,9 @@ function processActiveInvocation( const drainPerTick = computeDrainPerTick(invSpellDef.cost.amount, drainMult); invocationCharge = Math.max(0, invocationCharge - drainPerTick); - // Accumulate cast progress with pact affinity bonus - const pactAffinity = disciplineEffects.bonuses.pactAffinityBonus || 0; - const castSpeedBonus = computeCastSpeedBonus(pactAffinity); - const effectiveAttackSpeed = attackSpeedMult * (1 + castSpeedBonus); + // Cast progress uses attackSpeedMult which already includes pact affinity bonus (AC-12/AC-13) const invCastSpeed = invSpellDef.castSpeed || 1; - const invProgressPerTick = HOURS_PER_TICK * invCastSpeed * effectiveAttackSpeed; + const invProgressPerTick = HOURS_PER_TICK * invCastSpeed * attackSpeedMult; const newCastProgress = activeInvocation.castProgress + invProgressPerTick; if (newCastProgress >= 1 && floorHP > 0) { diff --git a/src/lib/game/stores/gameStore.ts b/src/lib/game/stores/gameStore.ts index 97f5365..9b7bab4 100644 --- a/src/lib/game/stores/gameStore.ts +++ b/src/lib/game/stores/gameStore.ts @@ -32,6 +32,7 @@ import type { TickContext, TickWrites } from './tick-pipeline'; import type { GameCoordinatorState } from './gameStore.types'; import type { EnemyState } from '../types'; import { applyEnemyDefenses as applyEnemyDefensesFromPipeline } from './pipelines/combat-tick'; +import { computeAttackSpeedMultFromPactAffinity } from '../utils/invocation-utils'; // Track paused conversions already logged to avoid flooding the activity log every tick const loggedPausedConversions = new Set(); @@ -289,8 +290,13 @@ export const useGameStore = create()( })); useCombatStore.setState({ equipmentSpellStates }); + // AC-12/AC-13: Pact affinity cast speed bonus (prestige + discipline) + const attackSpeedMult = computeAttackSpeedMultFromPactAffinity( + ctx.prestige.prestigeUpgrades.pactAffinity || 0, + disciplineEffects.bonuses.pactAffinityBonus || 0, + ); const cr = useCombatStore.getState().processCombatTick( - rawMana, elements, maxMana, 1, + rawMana, elements, maxMana, attackSpeedMult, combatCbs.onFloorCleared, combatCbs.makeOnDamageDealt(() => rawMana, () => elements, defCtx, addLog), ctx.prestige.signedPacts, diff --git a/src/lib/game/utils/invocation-utils.ts b/src/lib/game/utils/invocation-utils.ts index 48e0059..c485fc5 100644 --- a/src/lib/game/utils/invocation-utils.ts +++ b/src/lib/game/utils/invocation-utils.ts @@ -198,6 +198,21 @@ export function computeDrainRateMultiplier(disciplineBonuses: DisciplineBonuses) return Math.max(MIN_DRAIN_MULTIPLIER, BASE_DRAIN_MULTIPLIER + reduction); } +// ─── Pact Affinity Attack Speed ─────────────────────────────────────────────── + +/** + * Compute the effective attack speed multiplier from pact affinity. + * Combines prestige upgrade + discipline bonus, applies diminishing returns formula. + * Used by gameStore to compute the attackSpeedMult passed to processCombatTick. + */ +export function computeAttackSpeedMultFromPactAffinity( + pactAffinityUpgrade: number, + pactAffinityBonus: number, +): number { + const total = pactAffinityUpgrade + pactAffinityBonus; + return 1 * (1 + computeCastSpeedBonus(total)); +} + // ─── Drain Per Tick ──────────────────────────────────────────────────────────── /**