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
+60
View File
@@ -0,0 +1,60 @@
import { useGameStore } from '@/store';
import { ACHIEVEMENT_DEFINITIONS } from '@ai-tycoon/game-engine';
import {
Trophy, Lock, Server, Brain, Rocket, DollarSign, Sprout, Users,
Globe, Sparkles, TrendingUp, Building2, Atom, Cpu, FlaskConical,
GitBranch, Zap,
} from 'lucide-react';
const ICON_MAP: Record<string, React.ComponentType<{ size?: number; className?: string }>> = {
Trophy, Server, Brain, Rocket, DollarSign, Sprout, Users,
Globe, Sparkles, TrendingUp, Building2, Atom, Cpu, FlaskConical,
GitBranch, Zap,
};
export function AchievementsPage() {
const unlocked = useGameStore((s) => s.achievements.unlocked);
const unlockedIds = new Set(unlocked.map(a => a.id));
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<h2 className="text-2xl font-bold">Achievements</h2>
<span className="text-sm text-surface-400">
{unlocked.length} / {ACHIEVEMENT_DEFINITIONS.length} unlocked
</span>
</div>
<div className="grid grid-cols-3 gap-4">
{ACHIEVEMENT_DEFINITIONS.map(def => {
const isUnlocked = unlockedIds.has(def.id);
const IconComponent = ICON_MAP[def.icon] ?? Trophy;
return (
<div
key={def.id}
className={`rounded-xl border p-4 transition-all ${
isUnlocked
? 'bg-surface-900 border-accent/40 shadow-lg shadow-accent/5'
: 'bg-surface-900/50 border-surface-700 opacity-60'
}`}
>
<div className="flex items-start gap-3">
<div className={`p-2 rounded-lg ${isUnlocked ? 'bg-accent/20 text-accent-light' : 'bg-surface-800 text-surface-500'}`}>
{isUnlocked ? <IconComponent size={20} /> : <Lock size={20} />}
</div>
<div>
<h4 className={`font-semibold text-sm ${isUnlocked ? '' : 'text-surface-400'}`}>{def.name}</h4>
<p className="text-xs text-surface-400 mt-0.5">{def.description}</p>
{isUnlocked && (
<p className="text-xs text-accent mt-1">Unlocked</p>
)}
</div>
</div>
</div>
);
})}
</div>
</div>
);
}