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>
124 lines
4.0 KiB
TypeScript
124 lines
4.0 KiB
TypeScript
import type { GameState, EventDefinition } from '@ai-tycoon/shared';
|
|
import { processEconomy } from './systems/economySystem';
|
|
import { processInfrastructure } from './systems/infrastructureSystem';
|
|
import { processCompute } from './systems/computeSystem';
|
|
import { processResearch } from './systems/researchSystem';
|
|
import { processModels } from './systems/modelSystem';
|
|
import { processMarket } from './systems/marketSystem';
|
|
import { processReputation } from './systems/reputationSystem';
|
|
import { processTalent } from './systems/talentSystem';
|
|
import { processEvents } from './systems/eventSystem';
|
|
import { processCompetitors } from './systems/competitorSystem';
|
|
import { processData } from './systems/dataSystem';
|
|
import { checkEraTransition } from './systems/eraSystem';
|
|
|
|
export interface TickResult {
|
|
state: Partial<GameState>;
|
|
notifications: TickNotification[];
|
|
}
|
|
|
|
export interface TickNotification {
|
|
title: string;
|
|
message: string;
|
|
type: 'info' | 'success' | 'warning' | 'danger';
|
|
}
|
|
|
|
let cachedEventDefs: EventDefinition[] | null = null;
|
|
|
|
export function setEventDefinitions(defs: EventDefinition[]) {
|
|
cachedEventDefs = defs;
|
|
}
|
|
|
|
export function processTick(state: GameState): Partial<GameState> {
|
|
const notifications: TickNotification[] = [];
|
|
|
|
const infrastructure = processInfrastructure(state);
|
|
|
|
const stateWithInfra = { ...state, infrastructure };
|
|
const modelResult = processModels(stateWithInfra);
|
|
|
|
if (modelResult.modelCompleted) {
|
|
notifications.push({
|
|
title: 'Training Complete',
|
|
message: `${modelResult.modelCompleted.name} is ready! Benchmark: ${modelResult.modelCompleted.benchmarkScore.toFixed(1)}/100`,
|
|
type: 'success',
|
|
});
|
|
}
|
|
|
|
const stateWithModels = { ...stateWithInfra, models: modelResult.modelsState };
|
|
const market = processMarket(stateWithModels, state.compute);
|
|
|
|
const compute = processCompute(state, infrastructure);
|
|
compute.tokensPerSecondDemand = market.totalTokenDemand;
|
|
compute.inferenceUtilization = compute.tokensPerSecondCapacity > 0
|
|
? Math.min(1, market.totalTokenDemand / compute.tokensPerSecondCapacity)
|
|
: 0;
|
|
|
|
const talent = processTalent(stateWithModels);
|
|
const stateWithTalent = { ...stateWithModels, talent };
|
|
const researchResult = processResearch(stateWithTalent, compute);
|
|
|
|
if (researchResult.researchCompleted) {
|
|
notifications.push({
|
|
title: 'Research Complete',
|
|
message: `${researchResult.researchCompleted} has been unlocked!`,
|
|
type: 'success',
|
|
});
|
|
}
|
|
|
|
const reputation = processReputation(stateWithTalent);
|
|
const economy = processEconomy(stateWithTalent, market, infrastructure);
|
|
const data = processData(stateWithTalent);
|
|
const competitors = processCompetitors(stateWithTalent);
|
|
|
|
const eventResult = cachedEventDefs
|
|
? processEvents(stateWithTalent, cachedEventDefs)
|
|
: { events: state.events, newEvents: [] };
|
|
|
|
for (const evt of eventResult.newEvents) {
|
|
notifications.push({
|
|
title: evt.title,
|
|
message: evt.description,
|
|
type: evt.category === 'regulatory' ? 'warning' : 'info',
|
|
});
|
|
}
|
|
|
|
const tickCount = state.meta.tickCount + 1;
|
|
|
|
let meta = {
|
|
...state.meta,
|
|
tickCount,
|
|
lastTickTimestamp: Date.now(),
|
|
totalPlayTime: state.meta.totalPlayTime + 1,
|
|
};
|
|
|
|
const newEra = checkEraTransition({ ...stateWithTalent, economy, reputation, research: researchResult.research });
|
|
if (newEra) {
|
|
meta = { ...meta, currentEra: newEra };
|
|
notifications.push({
|
|
title: 'Era Transition!',
|
|
message: `Your company has entered the ${newEra === 'scaleup' ? 'Scale-up' : newEra === 'bigtech' ? 'Big Tech' : 'AGI'} era!`,
|
|
type: 'success',
|
|
});
|
|
}
|
|
|
|
const result: Partial<GameState> = {
|
|
meta,
|
|
economy,
|
|
infrastructure,
|
|
compute,
|
|
research: researchResult.research,
|
|
models: modelResult.modelsState,
|
|
market: market.marketState,
|
|
talent,
|
|
reputation,
|
|
data,
|
|
competitors,
|
|
events: eventResult.events,
|
|
};
|
|
|
|
(result as Record<string, unknown>)['_notifications'] = notifications;
|
|
|
|
return result;
|
|
}
|