8c9555bc08
Tech tree with 21 research nodes across 5 categories (infrastructure, efficiency, generation, specialization, safety). Research page with category-grouped cards, progress tracking, prerequisite gating. Event engine with 34 events across industry/regulatory/PR/internal/market categories, weighted random firing, cooldowns, expiry, and choice modal with consequence preview. Events auto-expire with default choice. Competitor system with 3 rival AI labs (Prometheus AI, Nexus Labs, Titan Computing), personality-driven milestone progression, and comparison UI. Talent page with department hiring, headcount management, and key hire recruitment from a pool of 10 named characters with special abilities. Data marketplace with 8 purchasable datasets, user data flywheel from subscribers, and data system processing in tick loop. Era transition system checks revenue/capability/reputation thresholds. All new systems integrated into tick processor with notifications. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
70 lines
2.0 KiB
TypeScript
70 lines
2.0 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|
import { GameEngine, setEventDefinitions, EVENT_DEFINITIONS } from '@ai-tycoon/game-engine';
|
|
import type { TickNotification } from '@ai-tycoon/game-engine';
|
|
import { useGameStore } from '@/store';
|
|
|
|
export function useGameLoop(skip = false) {
|
|
const engineRef = useRef<GameEngine | null>(null);
|
|
const companyName = useGameStore((s) => s.meta.companyName);
|
|
const gameSpeed = useGameStore((s) => s.meta.gameSpeed);
|
|
|
|
useEffect(() => {
|
|
if (!companyName || skip) return;
|
|
|
|
setEventDefinitions(EVENT_DEFINITIONS);
|
|
|
|
const engine = new GameEngine({
|
|
getState: () => {
|
|
const state = useGameStore.getState();
|
|
return {
|
|
meta: state.meta,
|
|
economy: state.economy,
|
|
infrastructure: state.infrastructure,
|
|
compute: state.compute,
|
|
research: state.research,
|
|
models: state.models,
|
|
market: state.market,
|
|
competitors: state.competitors,
|
|
talent: state.talent,
|
|
data: state.data,
|
|
reputation: state.reputation,
|
|
events: state.events,
|
|
achievements: state.achievements,
|
|
};
|
|
},
|
|
setState: (partial) => {
|
|
const notifications = (partial as Record<string, unknown>)['_notifications'] as TickNotification[] | undefined;
|
|
delete (partial as Record<string, unknown>)['_notifications'];
|
|
|
|
useGameStore.getState().updateState(partial);
|
|
|
|
if (notifications?.length) {
|
|
const store = useGameStore.getState();
|
|
for (const n of notifications) {
|
|
store.addNotification({
|
|
title: n.title,
|
|
message: n.message,
|
|
type: n.type,
|
|
tick: store.meta.tickCount,
|
|
});
|
|
}
|
|
}
|
|
},
|
|
});
|
|
|
|
engineRef.current = engine;
|
|
engine.start();
|
|
|
|
return () => {
|
|
engine.stop();
|
|
engineRef.current = null;
|
|
};
|
|
}, [companyName, skip]);
|
|
|
|
useEffect(() => {
|
|
if (engineRef.current) {
|
|
engineRef.current.setSpeed(gameSpeed);
|
|
}
|
|
}, [gameSpeed]);
|
|
}
|