Add research queue: queue multiple projects, auto-promote on completion, RP refund on dequeue
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { GameState, ResearchState, ComputeState } from '@ai-tycoon/shared';
|
||||
import type { GameState, ResearchState, ActiveResearch, ComputeState } from '@ai-tycoon/shared';
|
||||
import { TECH_TREE } from '../data/techTree';
|
||||
|
||||
export interface ResearchTickResult {
|
||||
@@ -6,6 +6,42 @@ export interface ResearchTickResult {
|
||||
researchCompleted: string | null;
|
||||
}
|
||||
|
||||
function promoteFromQueue(
|
||||
research: ResearchState,
|
||||
state: GameState,
|
||||
): ResearchState {
|
||||
const queue = research.researchQueue;
|
||||
if (queue.length === 0) return research;
|
||||
|
||||
const eraOrder = ['startup', 'scaleup', 'bigtech', 'agi'];
|
||||
const currentEraIdx = eraOrder.indexOf(state.meta.currentEra);
|
||||
const completed = research.completedResearch;
|
||||
|
||||
for (let i = 0; i < queue.length; i++) {
|
||||
const id = queue[i];
|
||||
const node = TECH_TREE.find(n => n.id === id);
|
||||
if (!node) continue;
|
||||
if (eraOrder.indexOf(node.era) > currentEraIdx) continue;
|
||||
if (node.prerequisites.some(p => !completed.includes(p))) continue;
|
||||
|
||||
const active: ActiveResearch = {
|
||||
researchId: id,
|
||||
progressTicks: 0,
|
||||
totalTicks: node.cost.ticks,
|
||||
allocatedResearchers: state.talent.departments.research.headcount,
|
||||
allocatedCompute: node.cost.compute,
|
||||
};
|
||||
|
||||
return {
|
||||
...research,
|
||||
activeResearch: active,
|
||||
researchQueue: [...queue.slice(0, i), ...queue.slice(i + 1)],
|
||||
};
|
||||
}
|
||||
|
||||
return research;
|
||||
}
|
||||
|
||||
export function processResearch(state: GameState, compute: ComputeState): ResearchTickResult {
|
||||
const active = state.research.activeResearch;
|
||||
if (!active) return { research: state.research, researchCompleted: null };
|
||||
@@ -17,13 +53,18 @@ export function processResearch(state: GameState, compute: ComputeState): Resear
|
||||
const newProgress = active.progressTicks + speedMultiplier;
|
||||
|
||||
if (newProgress >= active.totalTicks) {
|
||||
const completedResearch = {
|
||||
...state.research,
|
||||
completedResearch: [...state.research.completedResearch, active.researchId],
|
||||
activeResearch: null,
|
||||
researchPoints: state.research.researchPoints + 1,
|
||||
};
|
||||
|
||||
return {
|
||||
research: {
|
||||
...state.research,
|
||||
completedResearch: [...state.research.completedResearch, active.researchId],
|
||||
activeResearch: null,
|
||||
researchPoints: state.research.researchPoints + 1,
|
||||
},
|
||||
research: promoteFromQueue(completedResearch, {
|
||||
...state,
|
||||
research: completedResearch,
|
||||
}),
|
||||
researchCompleted: active.researchId,
|
||||
};
|
||||
}
|
||||
@@ -40,10 +81,12 @@ export function processResearch(state: GameState, compute: ComputeState): Resear
|
||||
export function getAvailableResearch(state: GameState): typeof TECH_TREE {
|
||||
const eraOrder = ['startup', 'scaleup', 'bigtech', 'agi'];
|
||||
const currentEraIdx = eraOrder.indexOf(state.meta.currentEra);
|
||||
const queuedIds = new Set(state.research.researchQueue);
|
||||
|
||||
return TECH_TREE.filter(node => {
|
||||
if (state.research.completedResearch.includes(node.id)) return false;
|
||||
if (state.research.activeResearch?.researchId === node.id) return false;
|
||||
if (queuedIds.has(node.id)) return false;
|
||||
if (eraOrder.indexOf(node.era) > currentEraIdx) return false;
|
||||
if (node.prerequisites.some(p => !state.research.completedResearch.includes(p))) return false;
|
||||
if (node.cost.researchPoints > state.research.researchPoints) return false;
|
||||
|
||||
Reference in New Issue
Block a user