283c7c7932
CI / build-and-push (push) Successful in 37s
Add compute history time-series (capacity vs demand chart), revenue vs expenses dual-line chart, enhanced system status (training allocation, network uptime, model freshness), active operations panel, market position bars, and competitor snapshot. Stat cards expand from 3 to 6 as player progresses through eras. Graceful v9→v10 save migration preserves existing games. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
168 lines
5.9 KiB
TypeScript
168 lines
5.9 KiB
TypeScript
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<GameState>;
|
|
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<GameState> {
|
|
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<GameState> = {
|
|
meta,
|
|
economy: updatedEconomy,
|
|
infrastructure,
|
|
compute,
|
|
research: researchResult.research,
|
|
models: modelResult.modelsState,
|
|
market: market.marketState,
|
|
talent,
|
|
reputation,
|
|
data,
|
|
competitors,
|
|
achievements: achievementResult.achievements,
|
|
};
|
|
|
|
(result as Record<string, unknown>)['_notifications'] = notifications;
|
|
|
|
return result;
|
|
}
|