Initial commit
This commit is contained in:
Executable
+180
@@ -0,0 +1,180 @@
|
||||
// ─── Pact Slice ───────────────────────────────────────────────────────────────
|
||||
// Manages guardian pacts, signing, and mana unlocking
|
||||
|
||||
import type { StateCreator } from 'zustand';
|
||||
import type { GameState } from '../types';
|
||||
import { GUARDIANS, ELEMENTS } from '../constants';
|
||||
import { computePactMultiplier, computePactInsightMultiplier } from './computed';
|
||||
|
||||
export interface PactSlice {
|
||||
// State
|
||||
signedPacts: number[];
|
||||
pendingPactOffer: number | null;
|
||||
maxPacts: number;
|
||||
pactSigningProgress: {
|
||||
floor: number;
|
||||
progress: number;
|
||||
required: number;
|
||||
manaCost: number;
|
||||
} | null;
|
||||
signedPactDetails: Record<number, {
|
||||
floor: number;
|
||||
guardianId: string;
|
||||
signedAt: { day: number; hour: number };
|
||||
skillLevels: Record<string, number>;
|
||||
}>;
|
||||
pactInterferenceMitigation: number;
|
||||
pactSynergyUnlocked: boolean;
|
||||
|
||||
// Actions
|
||||
acceptPact: (floor: number) => void;
|
||||
declinePact: (floor: number) => void;
|
||||
|
||||
// Computed getters
|
||||
getPactMultiplier: () => number;
|
||||
getPactInsightMultiplier: () => number;
|
||||
}
|
||||
|
||||
export const createPactSlice = (
|
||||
set: StateCreator<GameState>['set'],
|
||||
get: () => GameState
|
||||
): PactSlice => ({
|
||||
signedPacts: [],
|
||||
pendingPactOffer: null,
|
||||
maxPacts: 1,
|
||||
pactSigningProgress: null,
|
||||
signedPactDetails: {},
|
||||
pactInterferenceMitigation: 0,
|
||||
pactSynergyUnlocked: false,
|
||||
|
||||
acceptPact: (floor: number) => {
|
||||
const state = get();
|
||||
const guardian = GUARDIANS[floor];
|
||||
if (!guardian || state.signedPacts.includes(floor)) return;
|
||||
|
||||
const maxPacts = 1 + (state.prestigeUpgrades.pactCapacity || 0);
|
||||
if (state.signedPacts.length >= maxPacts) {
|
||||
set({
|
||||
log: [`⚠️ Cannot sign more pacts! Maximum: ${maxPacts}.`, ...state.log.slice(0, 49)],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const baseCost = guardian.signingCost.mana;
|
||||
const discount = Math.min((state.prestigeUpgrades.pactDiscount || 0) * 0.1, 0.5);
|
||||
const manaCost = Math.floor(baseCost * (1 - discount));
|
||||
|
||||
if (state.rawMana < manaCost) {
|
||||
set({
|
||||
log: [`⚠️ Need ${manaCost} mana to sign pact with ${guardian.name}!`, ...state.log.slice(0, 49)],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const baseTime = guardian.signingCost.time;
|
||||
const haste = Math.min((state.prestigeUpgrades.pactHaste || 0) * 0.1, 0.5);
|
||||
const signingTime = Math.max(1, baseTime * (1 - haste));
|
||||
|
||||
set({
|
||||
rawMana: state.rawMana - manaCost,
|
||||
pactSigningProgress: {
|
||||
floor,
|
||||
progress: 0,
|
||||
required: signingTime,
|
||||
manaCost,
|
||||
},
|
||||
pendingPactOffer: null,
|
||||
currentAction: 'study',
|
||||
log: [`📜 Beginning pact signing with ${guardian.name}... (${signingTime}h, ${manaCost} mana)`, ...state.log.slice(0, 49)],
|
||||
});
|
||||
},
|
||||
|
||||
declinePact: (floor: number) => {
|
||||
const state = get();
|
||||
const guardian = GUARDIANS[floor];
|
||||
if (!guardian) return;
|
||||
|
||||
set({
|
||||
pendingPactOffer: null,
|
||||
log: [`🚫 Declined pact with ${guardian.name}.`, ...state.log.slice(0, 49)],
|
||||
});
|
||||
},
|
||||
|
||||
getPactMultiplier: () => computePactMultiplier(get()),
|
||||
getPactInsightMultiplier: () => computePactInsightMultiplier(get()),
|
||||
});
|
||||
|
||||
// Process pact signing progress (called during tick)
|
||||
export function processPactSigning(state: GameState, deltaHours: number): Partial<GameState> {
|
||||
if (!state.pactSigningProgress) return {};
|
||||
|
||||
const progress = state.pactSigningProgress.progress + deltaHours;
|
||||
const log = [...state.log];
|
||||
|
||||
if (progress >= state.pactSigningProgress.required) {
|
||||
const floor = state.pactSigningProgress.floor;
|
||||
const guardian = GUARDIANS[floor];
|
||||
if (!guardian || state.signedPacts.includes(floor)) {
|
||||
return { pactSigningProgress: null };
|
||||
}
|
||||
|
||||
const signedPacts = [...state.signedPacts, floor];
|
||||
const signedPactDetails = {
|
||||
...state.signedPactDetails,
|
||||
[floor]: {
|
||||
floor,
|
||||
guardianId: guardian.element,
|
||||
signedAt: { day: state.day, hour: state.hour },
|
||||
skillLevels: {},
|
||||
},
|
||||
};
|
||||
|
||||
// Unlock mana types
|
||||
let elements = { ...state.elements };
|
||||
for (const elemId of guardian.unlocksMana) {
|
||||
if (elements[elemId]) {
|
||||
elements = {
|
||||
...elements,
|
||||
[elemId]: { ...elements[elemId], unlocked: true },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Check for compound element unlocks
|
||||
const unlockedSet = new Set(
|
||||
Object.entries(elements)
|
||||
.filter(([, e]) => e.unlocked)
|
||||
.map(([id]) => id)
|
||||
);
|
||||
|
||||
for (const [elemId, elemDef] of Object.entries(ELEMENTS)) {
|
||||
if (elemDef.recipe && !elements[elemId]?.unlocked) {
|
||||
const canUnlock = elemDef.recipe.every(comp => unlockedSet.has(comp));
|
||||
if (canUnlock) {
|
||||
elements = {
|
||||
...elements,
|
||||
[elemId]: { ...elements[elemId], unlocked: true },
|
||||
};
|
||||
log.unshift(`🔮 ${elemDef.name} mana unlocked through component synergy!`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.unshift(`📜 Pact with ${guardian.name} signed! ${guardian.unlocksMana.map(e => ELEMENTS[e]?.name || e).join(', ')} mana unlocked!`);
|
||||
|
||||
return {
|
||||
signedPacts,
|
||||
signedPactDetails,
|
||||
elements,
|
||||
pactSigningProgress: null,
|
||||
log,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
pactSigningProgress: {
|
||||
...state.pactSigningProgress,
|
||||
progress,
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user