feat: implement Active Disciplines system
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 31s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 31s
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
// ─── Discipline Store Slice ────────────────────────────────────────────────────
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import type { DisciplineState } from '../types/disciplines';
|
||||
import {
|
||||
calculateManaDrain,
|
||||
calculateStatBonus,
|
||||
canProceedDiscipline,
|
||||
} from '../utils/discipline-math';
|
||||
import { baseDisciplines } from '../data/disciplines/base';
|
||||
import { enchanterDisciplines } from '../data/disciplines/enchanter';
|
||||
import { fabricatorDisciplines } from '../data/disciplines/fabricator';
|
||||
import { invokerDisciplines } from '../data/disciplines/invoker';
|
||||
import { MAX_CONCURRENT_DISCIPLINES } from '../types/disciplines';
|
||||
|
||||
const ALL_DISCIPLINES = [
|
||||
...baseDisciplines,
|
||||
...enchanterDisciplines,
|
||||
...fabricatorDisciplines,
|
||||
...invokerDisciplines,
|
||||
];
|
||||
const DISCIPLINE_MAP = Object.fromEntries(ALL_DISCIPLINES.map((d) => [d.id, d]));
|
||||
|
||||
export interface DisciplineStoreState {
|
||||
disciplines: Record<string, DisciplineState>;
|
||||
activeIds: string[];
|
||||
concurrentLimit: number;
|
||||
totalXP: number;
|
||||
}
|
||||
|
||||
export interface DisciplineStoreActions {
|
||||
activate: (id: string, gameState?: { elements?: Record<string, { unlocked?: boolean }> }) => void;
|
||||
deactivate: (id: string) => void;
|
||||
processTick: (mana: { rawMana: number; elements: Record<string, { current: number }> }) => {
|
||||
rawMana: number;
|
||||
elements: Record<string, { current: number }>;
|
||||
};
|
||||
}
|
||||
|
||||
export type DisciplineStore = DisciplineStoreState & DisciplineStoreActions;
|
||||
|
||||
export const useDisciplineStore = create<DisciplineStore>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
disciplines: {},
|
||||
activeIds: [],
|
||||
concurrentLimit: MAX_CONCURRENT_DISCIPLINES,
|
||||
totalXP: 0,
|
||||
|
||||
activate(id, gameState) {
|
||||
set((s) => {
|
||||
const def = DISCIPLINE_MAP[id];
|
||||
if (!def) return s;
|
||||
if (s.activeIds.includes(id)) return s;
|
||||
|
||||
const nonPaused = s.activeIds.filter((aid) => {
|
||||
const d = s.disciplines[aid];
|
||||
return d && !d.paused;
|
||||
}).length;
|
||||
if (nonPaused >= s.concurrentLimit) return s;
|
||||
if (!canProceedDiscipline(id, gameState)) return s;
|
||||
|
||||
const existing = s.disciplines[id] || { id, xp: 0, paused: false };
|
||||
return {
|
||||
disciplines: { ...s.disciplines, [id]: { ...existing, paused: false } },
|
||||
activeIds: [...s.activeIds, id],
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
deactivate(id) {
|
||||
set((s) => ({
|
||||
activeIds: s.activeIds.filter((aid) => aid !== id),
|
||||
}));
|
||||
},
|
||||
|
||||
processTick(mana) {
|
||||
const s = get();
|
||||
let rawMana = mana.rawMana;
|
||||
const elements = { ...mana.elements };
|
||||
let newXP = s.totalXP;
|
||||
|
||||
for (const id of s.activeIds) {
|
||||
const disc = s.disciplines[id];
|
||||
if (!disc) continue;
|
||||
if (disc.paused) continue;
|
||||
|
||||
const def = DISCIPLINE_MAP[id];
|
||||
if (!def) continue;
|
||||
|
||||
const drain = calculateManaDrain(def.drainBase, disc.xp, def.difficultyFactor);
|
||||
const element = elements[def.manaType];
|
||||
const available = def.manaType === 'raw' ? rawMana : element?.current;
|
||||
|
||||
if (!available || available < drain) {
|
||||
disc.paused = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (def.manaType === 'raw') {
|
||||
rawMana -= drain;
|
||||
} else {
|
||||
elements[def.manaType].current -= drain;
|
||||
}
|
||||
|
||||
disc.xp += 1;
|
||||
newXP += 1;
|
||||
}
|
||||
|
||||
const newLimit = Math.min(
|
||||
MAX_CONCURRENT_DISCIPLINES + Math.floor(newXP / 500),
|
||||
MAX_CONCURRENT_DISCIPLINES + 3
|
||||
);
|
||||
|
||||
set({
|
||||
disciplines: s.disciplines,
|
||||
totalXP: newXP,
|
||||
concurrentLimit: Math.max(s.concurrentLimit, newLimit),
|
||||
});
|
||||
|
||||
return { rawMana, elements };
|
||||
},
|
||||
}),
|
||||
{ name: 'mana-loop-discipline-store' }
|
||||
)
|
||||
);
|
||||
Reference in New Issue
Block a user