import { produce } from 'immer'; import { getBuilding, getProduction, getStorage, getUnitSource } from './utils'; import village, { type VillageState } from "./village"; import type { ProductionType } from './types'; let lastFrame: number; export default function update(timestamp: number) { if (!lastFrame) { lastFrame = timestamp; return; } const delta = timestamp - lastFrame; village.update(state => { if (state.victory) { return state; } return produce(state, (V: VillageState) => { // Advance building construction. if (V.queue.length) { V.queue[0].remainingTime -= delta; if (V.queue[0].remainingTime <= 0) { const building = getBuilding(V, V.queue[0].id); building.level++; V.queue.shift(); } } // Make all buildings and units produce and consume. const productionPerMinute = getProduction(V); const storage = getStorage(V); Object.keys(productionPerMinute).forEach((key) => { const resource = key as keyof ProductionType; const outputPerMinute = productionPerMinute[resource]; const outputPerMilisecond = outputPerMinute / 60.0 / 1000.0; V.resources[resource] += outputPerMilisecond * delta; }); // Make sure resources do not overflow. Object.keys(productionPerMinute).forEach((key) => { const resource = key as keyof ProductionType; if (V.resources[resource] > storage[resource]) { V.resources[resource] = storage[resource]; } else if (V.resources[resource] < 0) { V.resources[resource] = 0; } }); // Recruit units. V.buildings.forEach(b => { if (!b.state.recruitment || !b.state.recruitment.count) { return; } const recruitment = b.state.recruitment; recruitment.elapsedTime += delta; const timeToRecruit = b.behavior.units?.recruitmentTime(V, b) * 1000; if (recruitment.elapsedTime >= timeToRecruit) { const unitType = b.behavior.units?.type || ''; if (!V.units.hasOwnProperty(unitType)) { V.units[unitType] = 0; } V.units[unitType]++; recruitment.count--; recruitment.elapsedTime = (recruitment.count === 0) ? 0 : timeToRecruit - recruitment.elapsedTime; } }); // Check if the game is won. if (V.resources.culture >= 2000) { V.victory = true; } return V; }); }); lastFrame = timestamp; }