import type { GameState, AchievementDefinition } from '@ai-tycoon/shared'; import { processEconomy } from './systems/economySystem'; import { processInfrastructure } from './systems/infrastructureSystem'; import { computeCapacity, finalizeCompute } 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 { processCompetitors } from './systems/competitorSystem'; import { processData } from './systems/dataSystem'; import { checkEraTransition } from './systems/eraSystem'; import { processAchievements } from './systems/achievementSystem'; import { computeValuation } from './systems/fundingSystem'; import { getResearchBonuses } from './systems/researchBonuses'; export interface TickResult { state: Partial; notifications: TickNotification[]; } export interface TickNotification { title: string; message: string; type: 'info' | 'success' | 'warning' | 'danger'; action?: { label: string; page?: string; modelsTab?: string }; } let cachedAchievementDefs: AchievementDefinition[] | null = null; export function setAchievementDefinitions(defs: AchievementDefinition[]) { cachedAchievementDefs = defs; } export function processTick(state: GameState): Partial { const notifications: TickNotification[] = []; const researchBonuses = getResearchBonuses(state.research.completedResearch); const infraResult = processInfrastructure(state, researchBonuses); const infrastructure = infraResult.infrastructure; notifications.push(...infraResult.notifications); const stateWithInfra = { ...state, infrastructure }; const modelResult = processModels(stateWithInfra, researchBonuses); for (const completed of modelResult.completedModels) { notifications.push({ title: 'Training Complete', message: `${completed.name} is ready! Capability: ${completed.rawCapability.toFixed(1)}/100. Deploy it to start earning revenue.`, type: 'success', action: { label: 'Go to Families', page: 'models', modelsTab: 'models' }, }); } notifications.push(...modelResult.notifications); const stateWithModels = { ...stateWithInfra, models: modelResult.modelsState }; const capacity = computeCapacity(state, infrastructure, researchBonuses); const market = processMarket(stateWithModels, capacity.tokensPerSecondCapacity, capacity.effectiveInferenceFlops, researchBonuses); const compute = finalizeCompute(capacity, market.totalTokenDemand, state.compute.computeHistory, state.meta.tickCount); 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 reputationResult = processReputation(stateWithTalent, researchBonuses); const { _safetyIncident, ...reputation } = reputationResult; if (_safetyIncident) { notifications.push({ title: 'Safety Incident!', message: 'Your AI model caused a safety incident. Public trust and safety record damaged.', type: 'danger', }); } if (modelResult.reputationHit > 0) { reputation.publicPerception = Math.max(0, reputation.publicPerception - modelResult.reputationHit); reputation.score = Math.round( reputation.safetyRecord * 0.3 + reputation.publicPerception * 0.3 + reputation.employeeSatisfaction * 0.2 + reputation.regulatoryStanding * 0.2, ); } const extraCosts = infraResult.repairCosts + modelResult.legalCosts; const economy = processEconomy(stateWithTalent, market, infrastructure, extraCosts); const data = processData(stateWithTalent); const competitors = processCompetitors(stateWithTalent); 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 valuation = computeValuation({ ...stateWithTalent, economy, reputation, research: researchResult.research }); const updatedEconomy = { ...economy, funding: { ...economy.funding, valuation }, }; const stateForAchievements: GameState = { ...stateWithTalent, meta, economy: updatedEconomy, infrastructure, compute, research: researchResult.research, models: modelResult.modelsState, market: market.marketState, reputation, data, competitors, achievements: state.achievements, }; const achievementResult = cachedAchievementDefs ? processAchievements(stateForAchievements, cachedAchievementDefs) : { achievements: state.achievements, newAchievements: [] }; for (const name of achievementResult.newAchievements) { notifications.push({ title: 'Achievement Unlocked!', message: name, type: 'success', }); } const result: Partial = { meta, economy: updatedEconomy, infrastructure, compute, research: researchResult.research, models: modelResult.modelsState, market: market.marketState, talent, reputation, data, competitors, achievements: achievementResult.achievements, }; (result as Record)['_notifications'] = notifications; return result; }