The random events (GPU shortages, regulatory hearings, PR crises, etc.) added interruption without enough gameplay value. Removed all event types, definitions (~1800 lines of event data), the event processor, EventModal UI, store actions, and tick integration. Updated docs to reflect the removal. Bundle size drops ~47kB. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,84 +0,0 @@
|
||||
import { AlertTriangle, Newspaper, Building2, Users, TrendingUp, X } from 'lucide-react';
|
||||
import { useGameStore } from '@/store';
|
||||
import type { ActiveEvent, EventCategory } from '@ai-tycoon/shared';
|
||||
|
||||
const CATEGORY_ICONS: Record<EventCategory, typeof AlertTriangle> = {
|
||||
industry: Newspaper,
|
||||
regulatory: Building2,
|
||||
pr: Users,
|
||||
internal: AlertTriangle,
|
||||
market: TrendingUp,
|
||||
};
|
||||
|
||||
const CATEGORY_COLORS: Record<EventCategory, string> = {
|
||||
industry: 'border-blue-500/50 bg-blue-500/5',
|
||||
regulatory: 'border-yellow-500/50 bg-yellow-500/5',
|
||||
pr: 'border-purple-500/50 bg-purple-500/5',
|
||||
internal: 'border-orange-500/50 bg-orange-500/5',
|
||||
market: 'border-green-500/50 bg-green-500/5',
|
||||
};
|
||||
|
||||
export function EventModal() {
|
||||
const activeEvents = useGameStore((s) => s.events.activeEvents);
|
||||
const resolveEvent = useGameStore((s) => s.resolveEvent);
|
||||
|
||||
if (activeEvents.length === 0) return null;
|
||||
|
||||
const event = activeEvents[0];
|
||||
const Icon = CATEGORY_ICONS[event.category];
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/60 flex items-center justify-center z-50 p-4">
|
||||
<div className={`bg-surface-900 border-2 rounded-xl max-w-lg w-full shadow-2xl ${CATEGORY_COLORS[event.category]}`}>
|
||||
<div className="p-5">
|
||||
<div className="flex items-start justify-between mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Icon size={20} className="text-accent-light" />
|
||||
<h3 className="text-lg font-bold">{event.title}</h3>
|
||||
</div>
|
||||
<span className="text-xs text-surface-400 uppercase">{event.category}</span>
|
||||
</div>
|
||||
|
||||
<p className="text-sm text-surface-300 mb-5 leading-relaxed">{event.description}</p>
|
||||
|
||||
<div className="space-y-2">
|
||||
{event.choices.map((choice, idx) => (
|
||||
<button
|
||||
key={idx}
|
||||
onClick={() => resolveEvent(event.instanceId, idx)}
|
||||
className="w-full text-left bg-surface-800 hover:bg-surface-700 border border-surface-600 hover:border-surface-500 rounded-lg p-3 transition-all group"
|
||||
>
|
||||
<div className="text-sm font-medium group-hover:text-accent-light transition-colors">
|
||||
{choice.label}
|
||||
</div>
|
||||
<div className="text-xs text-surface-400 mt-1">{choice.description}</div>
|
||||
<div className="flex gap-2 mt-2">
|
||||
{choice.consequences.map((c, i) => (
|
||||
<ConsequenceTag key={i} type={c.type} value={c.value} />
|
||||
))}
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ConsequenceTag({ type, value }: { type: string; value: number }) {
|
||||
const isPositive = value > 0;
|
||||
const label = type === 'money' ? `$${Math.abs(value).toLocaleString()}`
|
||||
: type === 'reputation' ? `${Math.abs(value)} rep`
|
||||
: type === 'talent' ? `${Math.abs(value)} talent`
|
||||
: type === 'research_speed' ? `${Math.round(Math.abs(value) * 100)}% R&D`
|
||||
: `${type}: ${value}`;
|
||||
|
||||
return (
|
||||
<span className={`text-[10px] px-1.5 py-0.5 rounded ${
|
||||
isPositive ? 'bg-success/20 text-success' : 'bg-danger/20 text-danger'
|
||||
}`}>
|
||||
{isPositive ? '+' : '-'}{label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -32,7 +32,7 @@ export function OfflineCatchUp({ missedTicks, onComplete }: { missedTicks: numbe
|
||||
meta: s.meta, economy: s.economy, infrastructure: s.infrastructure,
|
||||
compute: s.compute, research: s.research, models: s.models,
|
||||
market: s.market, competitors: s.competitors, talent: s.talent,
|
||||
data: s.data, reputation: s.reputation, events: s.events,
|
||||
data: s.data, reputation: s.reputation,
|
||||
achievements: s.achievements,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Sidebar } from './Sidebar';
|
||||
import { TopBar } from './TopBar';
|
||||
import { ToastContainer } from '@/components/common/ToastContainer';
|
||||
import { EventModal } from '@/components/game/EventModal';
|
||||
import { useGameStore } from '@/store';
|
||||
import { DashboardPage } from '@/pages/DashboardPage';
|
||||
import { InfrastructurePage } from '@/pages/InfrastructurePage';
|
||||
@@ -29,7 +28,6 @@ export function MainLayout() {
|
||||
</main>
|
||||
</div>
|
||||
<ToastContainer />
|
||||
<EventModal />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { GameEngine, setEventDefinitions, setAchievementDefinitions, EVENT_DEFINITIONS, ACHIEVEMENT_DEFINITIONS } from '@ai-tycoon/game-engine';
|
||||
import { GameEngine, setAchievementDefinitions, ACHIEVEMENT_DEFINITIONS } from '@ai-tycoon/game-engine';
|
||||
import type { TickNotification } from '@ai-tycoon/game-engine';
|
||||
import { useGameStore } from '@/store';
|
||||
|
||||
@@ -11,7 +11,6 @@ export function useGameLoop(skip = false) {
|
||||
useEffect(() => {
|
||||
if (!companyName || skip) return;
|
||||
|
||||
setEventDefinitions(EVENT_DEFINITIONS);
|
||||
setAchievementDefinitions(ACHIEVEMENT_DEFINITIONS);
|
||||
|
||||
const engine = new GameEngine({
|
||||
@@ -29,7 +28,6 @@ export function useGameLoop(skip = false) {
|
||||
talent: state.talent,
|
||||
data: state.data,
|
||||
reputation: state.reputation,
|
||||
events: state.events,
|
||||
achievements: state.achievements,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -21,7 +21,7 @@ export function FinancePage() {
|
||||
meta: state.meta, economy: state.economy, infrastructure: state.infrastructure,
|
||||
compute: state.compute, research: state.research, models: state.models,
|
||||
market: state.market, competitors: state.competitors, talent: state.talent,
|
||||
data: state.data, reputation: state.reputation, events: state.events,
|
||||
data: state.data, reputation: state.reputation,
|
||||
achievements: state.achievements,
|
||||
};
|
||||
const fundingStatus = canRaiseFunding(gameStateForFunding);
|
||||
|
||||
@@ -5,9 +5,9 @@ import type {
|
||||
EconomyState, InfrastructureState, ComputeState,
|
||||
ResearchState, ModelsState, MarketState,
|
||||
CompetitorState, TalentState, DataState,
|
||||
ReputationState, EventState, AchievementState,
|
||||
ReputationState, AchievementState,
|
||||
DataCenter, DCTier, RackSkuId, TrainingJob,
|
||||
ActiveResearch, EventConsequence, OwnedDataset, LocationId,
|
||||
ActiveResearch, OwnedDataset, LocationId,
|
||||
} from '@ai-tycoon/shared';
|
||||
import type { FundingRoundType, OverloadPolicy, TuningPreset, ModelTuning } from '@ai-tycoon/shared';
|
||||
import {
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
INITIAL_ECONOMY, INITIAL_INFRASTRUCTURE, INITIAL_COMPUTE,
|
||||
INITIAL_RESEARCH, INITIAL_MODELS, INITIAL_MARKET,
|
||||
INITIAL_COMPETITORS, INITIAL_TALENT, INITIAL_DATA,
|
||||
INITIAL_REPUTATION, INITIAL_EVENTS, INITIAL_ACHIEVEMENTS,
|
||||
INITIAL_REPUTATION, INITIAL_ACHIEVEMENTS,
|
||||
DC_TIER_CONFIGS, RACK_SKU_CONFIGS,
|
||||
PIPELINE_ORDER_BASE_TICKS, DC_UPGRADE_COST_FRACTION, DC_UPGRADE_INCREMENT,
|
||||
FUNDING_ROUNDS,
|
||||
@@ -57,7 +57,6 @@ interface Actions {
|
||||
setProductPricing: (productLineId: string, field: string, value: number) => void;
|
||||
toggleProductLine: (productLineId: string) => void;
|
||||
startResearch: (research: ActiveResearch) => void;
|
||||
resolveEvent: (instanceId: string, choiceIndex: number) => void;
|
||||
hireDepartment: (departmentId: string, count: number) => void;
|
||||
purchaseDataset: (dataset: OwnedDataset, cost: number) => void;
|
||||
raiseFunding: (roundType: FundingRoundType) => void;
|
||||
@@ -93,7 +92,6 @@ const initialGameState: GameState = {
|
||||
talent: INITIAL_TALENT,
|
||||
data: INITIAL_DATA,
|
||||
reputation: INITIAL_REPUTATION,
|
||||
events: INITIAL_EVENTS,
|
||||
achievements: INITIAL_ACHIEVEMENTS,
|
||||
};
|
||||
|
||||
@@ -293,55 +291,6 @@ export const useGameStore = create<Store>()(
|
||||
};
|
||||
}),
|
||||
|
||||
resolveEvent: (instanceId, choiceIndex) => set((s) => {
|
||||
const event = s.events.activeEvents.find(e => e.instanceId === instanceId);
|
||||
if (!event) return s;
|
||||
|
||||
const choice = event.choices[choiceIndex];
|
||||
if (!choice) return s;
|
||||
|
||||
let money = s.economy.money;
|
||||
let reputation = { ...s.reputation };
|
||||
let talent = { ...s.talent };
|
||||
const consequences = choice.consequences;
|
||||
|
||||
for (const c of consequences) {
|
||||
switch (c.type) {
|
||||
case 'money': money += c.value; break;
|
||||
case 'reputation': reputation = { ...reputation, score: Math.min(100, Math.max(0, reputation.score + c.value)), publicPerception: Math.min(100, Math.max(0, reputation.publicPerception + c.value)) }; break;
|
||||
case 'regulation': reputation = { ...reputation, regulatoryStanding: Math.min(100, Math.max(0, reputation.regulatoryStanding + c.value)) }; break;
|
||||
case 'talent': {
|
||||
const dept = c.target as keyof typeof talent.departments | undefined;
|
||||
if (dept && talent.departments[dept]) {
|
||||
talent = { ...talent, departments: { ...talent.departments, [dept]: { ...talent.departments[dept], headcount: Math.max(0, talent.departments[dept].headcount + c.value) } } };
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
economy: { ...s.economy, money: Math.max(0, money) },
|
||||
reputation,
|
||||
talent,
|
||||
events: {
|
||||
...s.events,
|
||||
activeEvents: s.events.activeEvents.filter(e => e.instanceId !== instanceId),
|
||||
eventHistory: [
|
||||
...s.events.eventHistory,
|
||||
{
|
||||
eventId: event.eventId,
|
||||
instanceId,
|
||||
title: event.title,
|
||||
category: event.category,
|
||||
tick: s.meta.tickCount,
|
||||
chosenOptionIndex: choiceIndex,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}),
|
||||
|
||||
hireDepartment: (departmentId, count) => set((s) => {
|
||||
const costPerHire = 2000;
|
||||
const totalCost = costPerHire * count;
|
||||
|
||||
Reference in New Issue
Block a user