fix: Elemental Mana Capacity disciplines now increase element capacity
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m23s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m23s
- Add optional baseMax field to ElementState to track prestige-derived max separately from bonuses - Add computeElementMaxWithBonuses action to manaStore that computes max = baseMax + per-element bonus - Apply per-element cap bonuses from disciplines and equipment in game tick (elementCap_* keys) - Fix resetMana to use correct prestige key (elementalAttune instead of nonexistent elemMax) - Add store migration (v1->v2) to populate baseMax for existing saved games - Extract pact ritual processing to pipelines/pact-ritual.ts - Extract element cap bonus utilities to utils/element-cap-bonus.ts - Fix inline element types in crafting-fabricator.ts - Update test fixtures to include baseMax in element literals Fixes #185
This commit is contained in:
@@ -39,6 +39,13 @@ export interface ManaActions {
|
||||
setElementMax: (max: number) => void;
|
||||
craftComposite: (target: string, recipe: string[]) => Result<void>;
|
||||
|
||||
/**
|
||||
* Compute and apply per-element max from baseMax + bonuses.
|
||||
* Caller provides the bonus map (elementCap_* from disciplines/equipment).
|
||||
* This sets max = baseMax + bonus for each element, preventing double-counting.
|
||||
*/
|
||||
computeElementMaxWithBonuses: (perElementBonuses: Record<string, number>) => void;
|
||||
|
||||
// Helper for gameStore coordination
|
||||
processConvertAction: (rawMana: number) => { rawMana: number; elements: Record<string, ElementState> } | null;
|
||||
|
||||
@@ -64,6 +71,7 @@ export const useManaStore = create<ManaStore>()(
|
||||
{
|
||||
current: 0,
|
||||
max: 10,
|
||||
baseMax: 10,
|
||||
unlocked: BASE_UNLOCKED_ELEMENTS.includes(k),
|
||||
}
|
||||
])
|
||||
@@ -148,10 +156,27 @@ export const useManaStore = create<ManaStore>()(
|
||||
|
||||
setElementMax: (max: number) => {
|
||||
set((state) => ({
|
||||
elements: Object.fromEntries(Object.entries(state.elements).map(([k, v]) => [k, { ...v, max }])) as Record<string, ElementState>,
|
||||
elements: Object.fromEntries(Object.entries(state.elements).map(([k, v]) => [k, { ...v, max, baseMax: v.baseMax ?? max }])) as Record<string, ElementState>,
|
||||
}));
|
||||
},
|
||||
|
||||
computeElementMaxWithBonuses: (perElementBonuses: Record<string, number>) => {
|
||||
set((state) => {
|
||||
const newElements = { ...state.elements };
|
||||
let changed = false;
|
||||
for (const [element, bonus] of Object.entries(perElementBonuses)) {
|
||||
if (newElements[element] && bonus > 0) {
|
||||
const newMax = (newElements[element].baseMax ?? newElements[element].max) + bonus;
|
||||
if (newElements[element].max !== newMax) {
|
||||
newElements[element] = { ...newElements[element], max: newMax };
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed ? { elements: newElements } : state;
|
||||
});
|
||||
},
|
||||
|
||||
craftComposite: (target: string, recipe: string[]) => {
|
||||
const state = get();
|
||||
const costs: Record<string, number> = {};
|
||||
@@ -162,12 +187,13 @@ export const useManaStore = create<ManaStore>()(
|
||||
}
|
||||
|
||||
const newElems = { ...state.elements };
|
||||
const baseMax = state.elements[target]?.baseMax ?? 10;
|
||||
for (const [r, amt] of Object.entries(costs)) {
|
||||
newElems[r] = { ...newElems[r], current: newElems[r].current - amt };
|
||||
}
|
||||
|
||||
const targetElem = newElems[target];
|
||||
newElems[target] = { ...(targetElem || { current: 0, max: 10, unlocked: false }), current: (targetElem?.current || 0) + 1, unlocked: true };
|
||||
newElems[target] = { ...(targetElem || { current: 0, max: 10, baseMax: 10, unlocked: false }), current: (targetElem?.current || 0) + 1, unlocked: true, baseMax };
|
||||
set({ elements: newElems });
|
||||
return okVoid();
|
||||
},
|
||||
@@ -191,7 +217,7 @@ export const useManaStore = create<ManaStore>()(
|
||||
resetMana: (
|
||||
prestigeUpgrades: Record<string, number>,
|
||||
) => {
|
||||
const elementMax = 10 + (prestigeUpgrades.elemMax || 0) * 5;
|
||||
const elementMax = 10 + (prestigeUpgrades.elementalAttune || 0) * 25;
|
||||
const startingMana = 10 + (prestigeUpgrades.manaStart || 0) * 10;
|
||||
set({ rawMana: startingMana, meditateTicks: 0, totalManaGathered: 0, elements: makeInitialElements(elementMax, prestigeUpgrades) });
|
||||
},
|
||||
@@ -199,8 +225,19 @@ export const useManaStore = create<ManaStore>()(
|
||||
{
|
||||
storage: createSafeStorage(),
|
||||
name: 'mana-loop-mana',
|
||||
version: 1,
|
||||
version: 2,
|
||||
partialize: (state) => ({ rawMana: state.rawMana, meditateTicks: state.meditateTicks, totalManaGathered: state.totalManaGathered, elements: state.elements }),
|
||||
migrate: (persistedState: any, _version) => {
|
||||
// Migration: add baseMax to elements that don't have it
|
||||
if (persistedState && persistedState.elements) {
|
||||
for (const k of Object.keys(persistedState.elements)) {
|
||||
if (persistedState.elements[k].baseMax === undefined) {
|
||||
persistedState.elements[k].baseMax = persistedState.elements[k].max ?? 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
return persistedState;
|
||||
},
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -214,7 +251,7 @@ export function makeInitialElements(
|
||||
const elements: Record<string, ElementState> = {};
|
||||
for (const k of Object.keys(ELEMENTS)) {
|
||||
const isUnlocked = BASE_UNLOCKED_ELEMENTS.includes(k);
|
||||
elements[k] = { current: isUnlocked ? elemStart : 0, max: elementMax, unlocked: isUnlocked };
|
||||
elements[k] = { current: isUnlocked ? elemStart : 0, max: elementMax, baseMax: elementMax, unlocked: isUnlocked };
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user