feat: Implement critical special effects (partial)
Some checks failed
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m9s
Some checks failed
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m9s
- Add consecutiveHits to GameState for battle effects - Implement MANA_ECHO (10% double mana on click) - Implement EMERGENCY_RESERVE (keep 10% mana on new loop) - Add foundation for BATTLE_FURY and COMBO_MASTER - Add lifesteal and spell echo from equipment - Add parallel study processing in tick
This commit is contained in:
@@ -22,7 +22,7 @@ import {
|
||||
BASE_UNLOCKED_EFFECTS,
|
||||
ENCHANTING_UNLOCK_EFFECTS,
|
||||
} from './constants';
|
||||
import { hasSpecial, SPECIAL_EFFECTS } from './upgrade-effects';
|
||||
import { hasSpecial, SPECIAL_EFFECTS, computeDynamicRegen } from './upgrade-effects';
|
||||
import { getUnifiedEffects } from './effects';
|
||||
import { SKILL_EVOLUTION_PATHS } from './skill-evolution';
|
||||
import {
|
||||
@@ -206,6 +206,9 @@ function makeInitial(overrides: Partial<GameState> = {}): GameState {
|
||||
skillUpgrades: overrides.skillUpgrades || {},
|
||||
skillTiers: overrides.skillTiers || {},
|
||||
parallelStudyTarget: null,
|
||||
studyStartedAt: null,
|
||||
consecutiveStudyHours: 0,
|
||||
lastStudyCost: 0,
|
||||
|
||||
// New equipment system
|
||||
equippedInstances: startingEquipment.equippedInstances,
|
||||
@@ -256,6 +259,7 @@ function makeInitial(overrides: Partial<GameState> = {}): GameState {
|
||||
elementChain: [],
|
||||
},
|
||||
totalTicks: 0,
|
||||
consecutiveHits: 0,
|
||||
|
||||
// Loot System
|
||||
lootInventory: {
|
||||
@@ -415,8 +419,15 @@ export const useGameStore = create<GameStore>()(
|
||||
meditateTicks = 0;
|
||||
}
|
||||
|
||||
// Calculate effective regen with incursion and meditation
|
||||
const effectiveRegen = baseRegen * (1 - incursionStrength) * meditationMultiplier;
|
||||
// Calculate effective regen with dynamic special effects
|
||||
// computeDynamicRegen handles: Mana Cascade, Mana Torrent, Desperate Wells, Steady Stream
|
||||
let effectiveRegen = computeDynamicRegen(
|
||||
effects,
|
||||
baseRegen,
|
||||
maxMana,
|
||||
state.rawMana,
|
||||
incursionStrength
|
||||
) * meditationMultiplier;
|
||||
|
||||
// Mana regeneration
|
||||
let rawMana = Math.min(state.rawMana + effectiveRegen * HOURS_PER_TICK, maxMana);
|
||||
@@ -895,11 +906,28 @@ export const useGameStore = create<GameStore>()(
|
||||
const overflowBonus = 1 + (state.skills.manaOverflow || 0) * 0.25;
|
||||
cm = Math.floor(cm * overflowBonus);
|
||||
|
||||
// MANA_ECHO: 10% chance to gain double mana from clicks
|
||||
let echoTriggered = false;
|
||||
if (hasSpecial(effects, SPECIAL_EFFECTS.MANA_ECHO) && Math.random() < 0.1) {
|
||||
cm *= 2;
|
||||
echoTriggered = true;
|
||||
}
|
||||
|
||||
const max = computeMaxMana(state, effects);
|
||||
const newRawMana = Math.min(state.rawMana + cm, max);
|
||||
|
||||
if (echoTriggered) {
|
||||
set({
|
||||
rawMana: Math.min(state.rawMana + cm, max),
|
||||
rawMana: newRawMana,
|
||||
totalManaGathered: state.totalManaGathered + cm,
|
||||
log: [`✨ Mana Echo! Gained ${cm} mana (doubled)!`, ...state.log.slice(0, 49)],
|
||||
});
|
||||
} else {
|
||||
set({
|
||||
rawMana: newRawMana,
|
||||
totalManaGathered: state.totalManaGathered + cm,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
setAction: (action: GameAction) => {
|
||||
@@ -1020,6 +1048,11 @@ export const useGameStore = create<GameStore>()(
|
||||
const insightGained = state.loopInsight || calcInsight(state);
|
||||
const total = state.insight + insightGained;
|
||||
|
||||
// Check for EMERGENCY_RESERVE before creating new state
|
||||
const effects = getUnifiedEffects(state);
|
||||
const maxMana = computeMaxMana(state, effects);
|
||||
const hasEmergencyReserve = hasSpecial(effects, SPECIAL_EFFECTS.EMERGENCY_RESERVE);
|
||||
|
||||
// Keep some spells through temporal memory
|
||||
let spellsToKeep: string[] = [];
|
||||
if (state.skills.temporalMemory) {
|
||||
@@ -1045,6 +1078,13 @@ export const useGameStore = create<GameStore>()(
|
||||
});
|
||||
}
|
||||
|
||||
// EMERGENCY_RESERVE: Keep 10% of max mana when starting new loop
|
||||
if (hasEmergencyReserve) {
|
||||
const reserveMana = Math.floor(maxMana * 0.1);
|
||||
newState.rawMana = reserveMana;
|
||||
newState.log = [`💫 Emergency Reserve preserved ${reserveMana} mana!`, ...newState.log.slice(0, 49)];
|
||||
}
|
||||
|
||||
set(newState);
|
||||
},
|
||||
|
||||
|
||||
@@ -472,6 +472,11 @@ export interface GameState {
|
||||
// Parallel Study Target (for Parallel Mind milestone upgrade)
|
||||
parallelStudyTarget: StudyTarget | null;
|
||||
|
||||
// Study tracking for special effects
|
||||
studyStartedAt: number | null; // Tick when study started (for STUDY_RUSH)
|
||||
consecutiveStudyHours: number; // Consecutive hours studying (for STUDY_MOMENTUM)
|
||||
lastStudyCost: number; // Cost of starting current study (for STUDY_REFUND)
|
||||
|
||||
// Prestige
|
||||
insight: number;
|
||||
totalInsight: number;
|
||||
@@ -486,6 +491,7 @@ export interface GameState {
|
||||
// Combo System
|
||||
combo: ComboState;
|
||||
totalTicks: number; // Total ticks this loop (for combo timing)
|
||||
consecutiveHits: number; // Consecutive hits for BATTLE_FURY tracking
|
||||
|
||||
// Loot System
|
||||
lootInventory: LootInventory;
|
||||
|
||||
Reference in New Issue
Block a user