fix: resolve 7 circular dependency chains in src/lib/game
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 57s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 57s
- equipment/utils.ts: import directly from individual equipment modules instead of index.ts - golems/utils.ts: import directly from individual golem modules instead of index.ts - combatStore.ts: extract CombatState to combat-state.types.ts, remove debugSetTime (was only user of gameStore import) - combat-actions.ts: import CombatState from combat-state.types.ts instead of combatStore - stores/index.ts: re-export CombatState from combat-state.types.ts - GameStateDebug.tsx: replace debugSetTime calls with direct useGameStore.setState() Verification: bunx madge --circular src/lib/game → No circular dependency found!
This commit is contained in:
@@ -259,6 +259,7 @@ Mana-Loop/
|
|||||||
│ │ ├── stores/
|
│ │ ├── stores/
|
||||||
│ │ │ ├── attunementStore.ts
|
│ │ │ ├── attunementStore.ts
|
||||||
│ │ │ ├── combat-actions.ts
|
│ │ │ ├── combat-actions.ts
|
||||||
|
│ │ │ ├── combat-state.types.ts
|
||||||
│ │ │ ├── combatStore.ts
|
│ │ │ ├── combatStore.ts
|
||||||
│ │ │ ├── craftingStore.ts
|
│ │ │ ├── craftingStore.ts
|
||||||
│ │ │ ├── discipline-slice.ts
|
│ │ │ ├── discipline-slice.ts
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ export function GameStateDebug() {
|
|||||||
const resetGame = useGameStore((s) => s.resetGame);
|
const resetGame = useGameStore((s) => s.resetGame);
|
||||||
const debugSetFloor = useCombatStore((s) => s.debugSetFloor);
|
const debugSetFloor = useCombatStore((s) => s.debugSetFloor);
|
||||||
const resetFloorHP = useCombatStore((s) => s.resetFloorHP);
|
const resetFloorHP = useCombatStore((s) => s.resetFloorHP);
|
||||||
const debugSetTime = useCombatStore((s) => s.debugSetTime);
|
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
if (confirmReset) {
|
if (confirmReset) {
|
||||||
@@ -187,13 +186,13 @@ export function GameStateDebug() {
|
|||||||
<Button size="sm" variant="outline" onClick={() => useGameStore.setState({ day: 1, hour: 0 })}>
|
<Button size="sm" variant="outline" onClick={() => useGameStore.setState({ day: 1, hour: 0 })}>
|
||||||
Day 1
|
Day 1
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="sm" variant="outline" onClick={() => debugSetTime?.(10, 0)}>
|
<Button size="sm" variant="outline" onClick={() => useGameStore.setState({ day: 10, hour: 0 })}>
|
||||||
Day 10
|
Day 10
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="sm" variant="outline" onClick={() => debugSetTime?.(20, 0)}>
|
<Button size="sm" variant="outline" onClick={() => useGameStore.setState({ day: 20, hour: 0 })}>
|
||||||
Day 20
|
Day 20
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="sm" variant="outline" onClick={() => debugSetTime?.(30, 0)}>
|
<Button size="sm" variant="outline" onClick={() => useGameStore.setState({ day: 30, hour: 0 })}>
|
||||||
Day 30
|
Day 30
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,27 @@
|
|||||||
// ─── Equipment Helper Functions ─────────────────────────
|
// ─── Equipment Helper Functions ─────────────────────────
|
||||||
|
|
||||||
import type { EquipmentType, EquipmentSlot, EquipmentCategory } from './types';
|
import type { EquipmentType, EquipmentSlot, EquipmentCategory } from './types';
|
||||||
import { EQUIPMENT_TYPES } from './index';
|
import { ACCESSORIES_EQUIPMENT } from './accessories';
|
||||||
|
import { BODY_EQUIPMENT } from './body';
|
||||||
|
import { CASTER_EQUIPMENT } from './casters';
|
||||||
|
import { CATALYST_EQUIPMENT } from './catalysts';
|
||||||
|
import { FEET_EQUIPMENT } from './feet';
|
||||||
|
import { HANDS_EQUIPMENT } from './hands';
|
||||||
|
import { HEAD_EQUIPMENT } from './head';
|
||||||
|
import { SHIELD_EQUIPMENT } from './shields';
|
||||||
|
import { SWORD_EQUIPMENT } from './swords';
|
||||||
|
|
||||||
|
const EQUIPMENT_TYPES: Record<string, EquipmentType> = {
|
||||||
|
...ACCESSORIES_EQUIPMENT,
|
||||||
|
...BODY_EQUIPMENT,
|
||||||
|
...CASTER_EQUIPMENT,
|
||||||
|
...CATALYST_EQUIPMENT,
|
||||||
|
...FEET_EQUIPMENT,
|
||||||
|
...HANDS_EQUIPMENT,
|
||||||
|
...HEAD_EQUIPMENT,
|
||||||
|
...SHIELD_EQUIPMENT,
|
||||||
|
...SWORD_EQUIPMENT,
|
||||||
|
};
|
||||||
|
|
||||||
export function getEquipmentType(id: string): EquipmentType | undefined {
|
export function getEquipmentType(id: string): EquipmentType | undefined {
|
||||||
return EQUIPMENT_TYPES[id];
|
return EQUIPMENT_TYPES[id];
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
// ─── Golem Helper Functions ─────────────────────────
|
// ─── Golem Helper Functions ─────────────────────────
|
||||||
|
|
||||||
import type { GolemDef, GolemManaCost } from './types';
|
import type { GolemDef, GolemManaCost } from './types';
|
||||||
import { GOLEMS_DEF } from './index';
|
import { BASE_GOLEMS } from './base-golems';
|
||||||
|
import { ELEMENTAL_GOLEMS } from './elemental-golems';
|
||||||
|
import { HYBRID_GOLEMS } from './hybrid-golems';
|
||||||
|
|
||||||
|
const GOLEMS_DEF = {
|
||||||
|
...BASE_GOLEMS,
|
||||||
|
...ELEMENTAL_GOLEMS,
|
||||||
|
...HYBRID_GOLEMS,
|
||||||
|
};
|
||||||
|
|
||||||
// Get golem slots based on Fabricator attunement level
|
// Get golem slots based on Fabricator attunement level
|
||||||
// Level 2 = 1, Level 4 = 2, Level 6 = 3, Level 8 = 4, Level 10 = 5
|
// Level 2 = 1, Level 4 = 2, Level 6 = 3, Level 8 = 4, Level 10 = 5
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Extracted combat logic from combatStore.ts
|
// Extracted combat logic from combatStore.ts
|
||||||
|
|
||||||
import { SPELLS_DEF, GUARDIANS, HOURS_PER_TICK } from '../constants';
|
import { SPELLS_DEF, GUARDIANS, HOURS_PER_TICK } from '../constants';
|
||||||
import type { CombatState } from './combatStore';
|
import type { CombatState } from './combat-state.types';
|
||||||
import type { SpellState } from '../types';
|
import type { SpellState } from '../types';
|
||||||
import { getFloorMaxHP, getFloorElement, calcDamage, canAffordSpellCost, deductSpellCost } from '../utils';
|
import { getFloorMaxHP, getFloorElement, calcDamage, canAffordSpellCost, deductSpellCost } from '../utils';
|
||||||
import { usePrestigeStore } from './prestigeStore';
|
import { usePrestigeStore } from './prestigeStore';
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
// ─── Combat State Types ────────────────────────────────────────────────────────
|
||||||
|
// Shared types for combat store and combat actions to avoid circular dependency
|
||||||
|
|
||||||
|
import type { GameAction, SpellState, FloorState, GolemancyState, ActivityLogEntry, AchievementState, EquipmentSpellState, ActivityEventType } from '../types';
|
||||||
|
|
||||||
|
export interface CombatState {
|
||||||
|
// Floor state
|
||||||
|
currentFloor: number;
|
||||||
|
floorHP: number;
|
||||||
|
floorMaxHP: number;
|
||||||
|
maxFloorReached: number;
|
||||||
|
|
||||||
|
// Action state
|
||||||
|
activeSpell: string;
|
||||||
|
currentAction: GameAction;
|
||||||
|
castProgress: number;
|
||||||
|
|
||||||
|
// Spire mode
|
||||||
|
spireMode: boolean;
|
||||||
|
|
||||||
|
// Room system for special floors
|
||||||
|
currentRoom: FloorState;
|
||||||
|
|
||||||
|
// Spire climbing state
|
||||||
|
clearedFloors: Record<number, boolean>;
|
||||||
|
climbDirection: 'up' | 'down' | null;
|
||||||
|
isDescending: boolean;
|
||||||
|
|
||||||
|
// Golemancy (summoned golems)
|
||||||
|
golemancy: GolemancyState;
|
||||||
|
|
||||||
|
// Equipment spell states for multi-casting
|
||||||
|
equipmentSpellStates: EquipmentSpellState[];
|
||||||
|
|
||||||
|
// Combat special effect tracking
|
||||||
|
comboHitCount: number;
|
||||||
|
floorHitCount: number;
|
||||||
|
|
||||||
|
// Spells
|
||||||
|
spells: Record<string, SpellState>;
|
||||||
|
|
||||||
|
// Activity Log (for Spire Mode UI)
|
||||||
|
activityLog: ActivityLogEntry[];
|
||||||
|
|
||||||
|
// Achievements
|
||||||
|
achievements: AchievementState;
|
||||||
|
|
||||||
|
// Stats tracking
|
||||||
|
totalSpellsCast: number;
|
||||||
|
totalDamageDealt: number;
|
||||||
|
totalCraftsCompleted: number;
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
setCurrentFloor: (floor: number) => void;
|
||||||
|
advanceFloor: () => void;
|
||||||
|
setFloorHP: (hp: number) => void;
|
||||||
|
setMaxFloorReached: (floor: number) => void;
|
||||||
|
|
||||||
|
setAction: (action: GameAction) => void;
|
||||||
|
setSpell: (spellId: string) => void;
|
||||||
|
setCastProgress: (progress: number) => void;
|
||||||
|
|
||||||
|
// Room state
|
||||||
|
setCurrentRoom: (room: FloorState) => void;
|
||||||
|
|
||||||
|
// Spire climbing
|
||||||
|
setClimbDirection: (direction: 'up' | 'down' | null) => void;
|
||||||
|
setClearedFloor: (floor: number, cleared: boolean) => void;
|
||||||
|
setIsDescending: (descending: boolean) => void;
|
||||||
|
climbDownFloor: () => void;
|
||||||
|
exitSpireMode: () => void;
|
||||||
|
startClimbUp: () => void;
|
||||||
|
startClimbDown: () => void;
|
||||||
|
|
||||||
|
// Golemancy
|
||||||
|
toggleGolem: (golemId: string) => void;
|
||||||
|
setEnabledGolems: (golemIds: string[]) => void;
|
||||||
|
|
||||||
|
// Spells
|
||||||
|
learnSpell: (spellId: string) => void;
|
||||||
|
setSpellState: (spellId: string, state: Partial<SpellState>) => void;
|
||||||
|
|
||||||
|
// Activity Log
|
||||||
|
addActivityLog: (eventType: ActivityEventType, message: string, details?: ActivityLogEntry['details']) => void;
|
||||||
|
|
||||||
|
// Stats
|
||||||
|
incrementSpellsCast: () => void;
|
||||||
|
addDamageDealt: (damage: number) => void;
|
||||||
|
incrementCraftsCompleted: () => void;
|
||||||
|
|
||||||
|
// Spire mode
|
||||||
|
enterSpireMode: () => void;
|
||||||
|
|
||||||
|
// Combat tick
|
||||||
|
processCombatTick: (
|
||||||
|
rawMana: number,
|
||||||
|
elements: Record<string, { current: number; max: number; unlocked: boolean }>,
|
||||||
|
maxMana: number,
|
||||||
|
attackSpeedMult: number,
|
||||||
|
onFloorCleared: (floor: number, wasGuardian: boolean) => void,
|
||||||
|
onDamageDealt: (damage: number) => { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }> },
|
||||||
|
) => { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }>; logMessages: string[]; totalManaGathered: number };
|
||||||
|
|
||||||
|
// Reset
|
||||||
|
resetCombat: (startFloor: number, spellsToKeep?: string[]) => void;
|
||||||
|
|
||||||
|
// Debug helpers
|
||||||
|
debugSetFloor: (floor: number) => void;
|
||||||
|
resetFloorHP: () => void;
|
||||||
|
debugSetTime: (day: number, hour: number) => void;
|
||||||
|
}
|
||||||
@@ -10,113 +10,7 @@ import { useGameStore } from './gameStore';
|
|||||||
import { generateFloorState } from '../utils/room-utils';
|
import { generateFloorState } from '../utils/room-utils';
|
||||||
import { addActivityLogEntry } from '../utils/activity-log';
|
import { addActivityLogEntry } from '../utils/activity-log';
|
||||||
import { processCombatTick, makeInitialSpells } from './combat-actions';
|
import { processCombatTick, makeInitialSpells } from './combat-actions';
|
||||||
|
import type { CombatState } from './combat-state.types';
|
||||||
export interface CombatState {
|
|
||||||
// Floor state
|
|
||||||
currentFloor: number;
|
|
||||||
floorHP: number;
|
|
||||||
floorMaxHP: number;
|
|
||||||
maxFloorReached: number;
|
|
||||||
|
|
||||||
// Action state
|
|
||||||
activeSpell: string;
|
|
||||||
currentAction: GameAction;
|
|
||||||
castProgress: number;
|
|
||||||
|
|
||||||
// Spire mode
|
|
||||||
spireMode: boolean;
|
|
||||||
|
|
||||||
// Room system for special floors
|
|
||||||
currentRoom: FloorState;
|
|
||||||
|
|
||||||
// Spire climbing state
|
|
||||||
clearedFloors: Record<number, boolean>;
|
|
||||||
climbDirection: 'up' | 'down' | null;
|
|
||||||
isDescending: boolean;
|
|
||||||
|
|
||||||
// Golemancy (summoned golems)
|
|
||||||
golemancy: GolemancyState;
|
|
||||||
|
|
||||||
// Equipment spell states for multi-casting
|
|
||||||
equipmentSpellStates: EquipmentSpellState[];
|
|
||||||
|
|
||||||
// Combat special effect tracking
|
|
||||||
comboHitCount: number;
|
|
||||||
floorHitCount: number;
|
|
||||||
|
|
||||||
// Spells
|
|
||||||
spells: Record<string, SpellState>;
|
|
||||||
|
|
||||||
// Activity Log (for Spire Mode UI)
|
|
||||||
activityLog: ActivityLogEntry[];
|
|
||||||
|
|
||||||
// Achievements
|
|
||||||
achievements: AchievementState;
|
|
||||||
|
|
||||||
// Stats tracking
|
|
||||||
totalSpellsCast: number;
|
|
||||||
totalDamageDealt: number;
|
|
||||||
totalCraftsCompleted: number;
|
|
||||||
|
|
||||||
// Actions
|
|
||||||
setCurrentFloor: (floor: number) => void;
|
|
||||||
advanceFloor: () => void;
|
|
||||||
setFloorHP: (hp: number) => void;
|
|
||||||
setMaxFloorReached: (floor: number) => void;
|
|
||||||
|
|
||||||
setAction: (action: GameAction) => void;
|
|
||||||
setSpell: (spellId: string) => void;
|
|
||||||
setCastProgress: (progress: number) => void;
|
|
||||||
|
|
||||||
// Room state
|
|
||||||
setCurrentRoom: (room: FloorState) => void;
|
|
||||||
|
|
||||||
// Spire climbing
|
|
||||||
setClimbDirection: (direction: 'up' | 'down' | null) => void;
|
|
||||||
setClearedFloor: (floor: number, cleared: boolean) => void;
|
|
||||||
setIsDescending: (descending: boolean) => void;
|
|
||||||
climbDownFloor: () => void;
|
|
||||||
exitSpireMode: () => void;
|
|
||||||
startClimbUp: () => void;
|
|
||||||
startClimbDown: () => void;
|
|
||||||
|
|
||||||
// Golemancy
|
|
||||||
toggleGolem: (golemId: string) => void;
|
|
||||||
setEnabledGolems: (golemIds: string[]) => void;
|
|
||||||
|
|
||||||
// Spells
|
|
||||||
learnSpell: (spellId: string) => void;
|
|
||||||
setSpellState: (spellId: string, state: Partial<SpellState>) => void;
|
|
||||||
|
|
||||||
// Activity Log
|
|
||||||
addActivityLog: (eventType: ActivityEventType, message: string, details?: ActivityLogEntry['details']) => void;
|
|
||||||
|
|
||||||
// Stats
|
|
||||||
incrementSpellsCast: () => void;
|
|
||||||
addDamageDealt: (damage: number) => void;
|
|
||||||
incrementCraftsCompleted: () => void;
|
|
||||||
|
|
||||||
// Spire mode
|
|
||||||
enterSpireMode: () => void;
|
|
||||||
|
|
||||||
// Combat tick
|
|
||||||
processCombatTick: (
|
|
||||||
rawMana: number,
|
|
||||||
elements: Record<string, { current: number; max: number; unlocked: boolean }>,
|
|
||||||
maxMana: number,
|
|
||||||
attackSpeedMult: number,
|
|
||||||
onFloorCleared: (floor: number, wasGuardian: boolean) => void,
|
|
||||||
onDamageDealt: (damage: number) => { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }> },
|
|
||||||
) => { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }>; logMessages: string[]; totalManaGathered: number };
|
|
||||||
|
|
||||||
// Reset
|
|
||||||
resetCombat: (startFloor: number, spellsToKeep?: string[]) => void;
|
|
||||||
|
|
||||||
// Debug helpers
|
|
||||||
debugSetFloor: (floor: number) => void;
|
|
||||||
resetFloorHP: () => void;
|
|
||||||
debugSetTime: (day: number, hour: number) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useCombatStore = create<CombatState>()(
|
export const useCombatStore = create<CombatState>()(
|
||||||
persist(
|
persist(
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export { useManaStore, makeInitialElements } from './manaStore';
|
|||||||
export type { ManaState } from './manaStore';
|
export type { ManaState } from './manaStore';
|
||||||
|
|
||||||
export { useCombatStore, makeInitialSpells } from './combatStore';
|
export { useCombatStore, makeInitialSpells } from './combatStore';
|
||||||
export type { CombatState } from './combatStore';
|
export type { CombatState } from './combat-state.types';
|
||||||
|
|
||||||
export { useCraftingStore } from './craftingStore';
|
export { useCraftingStore } from './craftingStore';
|
||||||
export type { CraftingState, CraftingActions } from './craftingStore';
|
export type { CraftingState, CraftingActions } from './craftingStore';
|
||||||
|
|||||||
Reference in New Issue
Block a user