Files
AIHostingTycoon/packages/game-engine/src/systems/economySystem.ts
T
josh 416b6bfe8d
Balance Check / balance-simulation (push) Successful in 11m19s
Balance Check / multi-run-balance (push) Has been cancelled
CI / build-and-push (push) Successful in 40s
Add research money costs, longer research times, era-scaled talent costs, and persona strategy
Research now costs money (drained per-tick) with ~2.5-3.5x longer durations by category.
Early-game talent budget costs reduced via era multiplier (startup 0.2x → bigtech 1.0x).
New seed-driven PersonaStrategy with 8 axes of variation for meaningful multi-run testing.
CI multi-run switched from greedy to persona strategy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-26 16:14:27 -04:00

68 lines
2.4 KiB
TypeScript

import type { GameState, EconomyState, InfrastructureState } from '@ai-tycoon/shared';
import { FINANCIAL_SNAPSHOT_INTERVAL, MAX_FINANCIAL_HISTORY, REGULATION_COMPLIANCE_PER_CAPABILITY } from '@ai-tycoon/shared';
import { TECH_TREE } from '../data/techTree';
import type { MarketTickResult } from './marketSystem';
export function processEconomy(
state: GameState,
market: MarketTickResult,
infrastructure: InfrastructureState,
extraCosts: number = 0,
): EconomyState {
const revenue = market.apiRevenue + market.subscriptionRevenue;
let infraExpenses = 0;
for (const cluster of infrastructure.clusters) {
for (const campus of cluster.campuses) {
for (const dc of campus.dataCenters) {
infraExpenses += dc.energyCostPerTick + dc.maintenanceCostPerTick;
}
}
}
const talentExpenses = state.talent.totalSalaryPerTick;
const dataExpenses = state.data.partnerships.reduce((sum, p) => sum + p.costPerTick, 0);
const bestCapability = state.models.bestDeployedModelScore;
const eraIdx = ['startup', 'scaleup', 'bigtech', 'agi'].indexOf(state.meta.currentEra);
const complianceCost = bestCapability > 30 ? bestCapability * REGULATION_COMPLIANCE_PER_CAPABILITY * (1 + eraIdx * 0.5) / 100 : 0;
const devRelExpenses = state.market.developerEcosystem.devRelSpending;
let researchExpenses = 0;
if (state.research.activeResearch) {
const node = TECH_TREE.find(n => n.id === state.research.activeResearch!.researchId);
if (node) {
researchExpenses = node.cost.money / node.cost.ticks;
}
}
const expenses = infraExpenses + talentExpenses + dataExpenses + complianceCost + devRelExpenses + researchExpenses + extraCosts;
const money = state.economy.money + revenue - expenses;
const financialHistory = [...state.economy.financialHistory];
if (state.meta.tickCount % FINANCIAL_SNAPSHOT_INTERVAL === 0) {
financialHistory.push({
tick: state.meta.tickCount,
money,
revenue,
expenses,
valuation: state.economy.funding.valuation,
});
if (financialHistory.length > MAX_FINANCIAL_HISTORY) {
financialHistory.shift();
}
}
return {
...state.economy,
money: Math.max(0, money),
totalRevenue: state.economy.totalRevenue + revenue,
totalExpenses: state.economy.totalExpenses + expenses,
revenuePerTick: revenue,
expensesPerTick: expenses,
financialHistory,
};
}