Add Week 3 polish and late-game features

VC funding system (seed through IPO with requirements gating), 15
achievements with engine checker, model tuning presets and unlockable
sliders, overload policy controls, open-source mechanic with reputation
boost, enhanced Recharts analytics (subscriber/reputation/revenue vs
expenses charts), M&A acquisition system, sidebar NEW badges on era
transitions, tutorial hints, and wired-up settings toggles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-24 17:56:40 -04:00
parent 8ea6c771a1
commit 8a8b49d934
20 changed files with 907 additions and 75 deletions
+26 -8
View File
@@ -1,6 +1,7 @@
import { Swords, TrendingUp, Shield, Users, Brain } from 'lucide-react';
import { Swords, TrendingUp, Shield, Users, Brain, ShoppingCart } from 'lucide-react';
import { useGameStore } from '@/store';
import { formatMoney, formatNumber } from '@ai-tycoon/shared';
import type { Era } from '@ai-tycoon/shared';
const ARCHETYPE_LABELS: Record<string, string> = {
'safety-first': 'Safety-First Lab',
@@ -24,6 +25,10 @@ export function CompetitorsPage() {
const playerBest = useGameStore((s) =>
s.models.trainedModels.reduce((best, m) => Math.max(best, m.benchmarkScore), 0),
);
const era = useGameStore((s) => s.meta.currentEra);
const money = useGameStore((s) => s.economy.money);
const acquireCompetitor = useGameStore((s) => s.acquireCompetitor);
const canAcquire = (era: Era) => era === 'bigtech' || era === 'agi';
return (
<div className="space-y-6">
@@ -75,13 +80,26 @@ export function CompetitorsPage() {
{ARCHETYPE_LABELS[rival.archetype]}
</span>
</div>
<span className={`text-xs px-2 py-1 rounded-full ${
rival.status === 'active' ? 'bg-success/20 text-success' :
rival.status === 'acquired' ? 'bg-blue-500/20 text-blue-400' :
'bg-surface-700 text-surface-400'
}`}>
{rival.status}
</span>
<div className="flex items-center gap-2">
{canAcquire(era) && rival.status === 'active' && (
<button
onClick={() => acquireCompetitor(rival.id)}
disabled={money < rival.estimatedRevenue * 500 + rival.estimatedCapability * 100_000}
className="flex items-center gap-1 bg-blue-600/20 hover:bg-blue-600/30 text-blue-400 border border-blue-600/30 rounded px-3 py-1.5 text-xs disabled:opacity-40 disabled:cursor-not-allowed"
title={`Cost: ${formatMoney(rival.estimatedRevenue * 500 + rival.estimatedCapability * 100_000)}`}
>
<ShoppingCart size={12} />
Acquire
</button>
)}
<span className={`text-xs px-2 py-1 rounded-full ${
rival.status === 'active' ? 'bg-success/20 text-success' :
rival.status === 'acquired' ? 'bg-blue-500/20 text-blue-400' :
'bg-surface-700 text-surface-400'
}`}>
{rival.status}
</span>
</div>
</div>
<div className="grid grid-cols-4 gap-4">