Add Week 2 depth systems: research, events, competitors, talent, data

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>
This commit is contained in:
2026-04-24 17:30:24 -04:00
parent d1d3eb4bf2
commit 8c9555bc08
19 changed files with 3166 additions and 21 deletions
+57 -9
View File
@@ -1,4 +1,4 @@
import type { GameState } from '@ai-tycoon/shared';
import type { GameState, EventDefinition } from '@ai-tycoon/shared';
import { processEconomy } from './systems/economySystem';
import { processInfrastructure } from './systems/infrastructureSystem';
import { processCompute } from './systems/computeSystem';
@@ -7,6 +7,10 @@ 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>;
@@ -19,6 +23,12 @@ export interface TickNotification {
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[] = [];
@@ -46,27 +56,65 @@ export function processTick(state: GameState): Partial<GameState> {
const talent = processTalent(stateWithModels);
const stateWithTalent = { ...stateWithModels, talent };
const research = processResearch(stateWithTalent, compute);
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: {
...state.meta,
tickCount,
lastTickTimestamp: Date.now(),
totalPlayTime: state.meta.totalPlayTime + 1,
},
meta,
economy,
infrastructure,
compute,
research,
research: researchResult.research,
models: modelResult.modelsState,
market: market.marketState,
talent,
reputation,
data,
competitors,
events: eventResult.events,
};
(result as Record<string, unknown>)['_notifications'] = notifications;