refactor: Replace natural-regen disciplines with mana conversion speed disciplines
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m25s

- Add conversionRate + sourceManaTypes fields to DisciplineDefinition
- Rewrite elemental-regen.ts: 8 base disciplines now convert raw→element
- Rewrite elemental-regen-advanced.ts: 6 composite/exotic disciplines with proper source recipes
- Update discipline-effects.ts: produce conversion entries instead of regen bonuses
- Update gameStore.ts tick: drain source mana types, add to target element
- Update discipline-slice.ts: gate activation on source mana type access
- Update discipline-math.ts: resolve mana type IDs to 'X mana' display names
- Update DisciplinesTab.tsx: show conversion info, source requirements, and lock state
- Update DisciplineDebugSection.tsx: pass elements to activate()
- Update effects.ts: remove regen_{element} merge (no longer produced)
This commit is contained in:
2026-05-26 20:40:11 +02:00
parent 1c1bbf8017
commit 46013a15c8
12 changed files with 430 additions and 263 deletions
+22 -4
View File
@@ -23,11 +23,19 @@ const KNOWN_BONUS_STATS = new Set([
'elementCapBonus',
]);
export function computeDisciplineEffects(_state?: DisciplineStoreState): {
export interface DisciplineEffectsResult {
bonuses: Record<string, number>;
multipliers: Record<string, number>;
specials: Set<string>;
} {
/**
* Conversion entries: for each active discipline with a conversionRate,
* maps target mana type → { rate, sourceManaTypes }.
* The tick pipeline drains source mana types and adds to the target.
*/
conversions: Record<string, { rate: number; sourceManaTypes: string[] }>;
}
export function computeDisciplineEffects(_state?: DisciplineStoreState): DisciplineEffectsResult {
const { disciplines } = useDisciplineStore.getState();
const activeDiscs = Object.entries(disciplines)
.filter(([, disc]) => disc && disc.xp > 0)
@@ -37,6 +45,7 @@ export function computeDisciplineEffects(_state?: DisciplineStoreState): {
const bonuses: Record<string, number> = {};
const multipliers: Record<string, number> = {};
const specials = new Set<string>();
const conversions: Record<string, { rate: number; sourceManaTypes: string[] }> = {};
function addBonus(stat: string, amount: number) {
bonuses[stat] = (bonuses[stat] || 0) + amount;
@@ -49,6 +58,16 @@ export function computeDisciplineEffects(_state?: DisciplineStoreState): {
addBonus(def.statBonus.stat, statBonus);
}
// Conversion entry — if this discipline defines conversionRate
if (def.conversionRate && def.sourceManaTypes && def.sourceManaTypes.length > 0) {
// Scale the conversion rate by the stat bonus multiplier
const scaledRate = def.conversionRate + statBonus;
conversions[def.manaType] = {
rate: scaledRate,
sourceManaTypes: def.sourceManaTypes,
};
}
// Perk unlocks
const perks = getUnlockedPerks(def, disc.xp);
for (const perk of perks) {
@@ -56,7 +75,6 @@ export function computeDisciplineEffects(_state?: DisciplineStoreState): {
if (perk.bonus) {
addBonus(perk.bonus.stat, perk.bonus.amount);
} else if (!perk.unlocksEffects) {
// Fallback: qualitative perk with no structured bonus — add as special flag
specials.add(perk.id);
}
// Perks with unlocksEffects are handled by discipline-slice.ts processTick()
@@ -83,5 +101,5 @@ export function computeDisciplineEffects(_state?: DisciplineStoreState): {
}
}
return { bonuses, multipliers, specials };
return { bonuses, multipliers, specials, conversions };
}