bourgade/src/update.ts

97 lines
3.3 KiB
TypeScript
Raw Normal View History

import { produce } from 'immer';
2024-11-05 12:06:44 +01:00
import { getBuilding, getProduction, getStorage, getUnitSource, shuffle } 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 => {
2024-11-04 18:43:03 +01:00
if (state.victory) {
return state;
}
return produce(state, (V: VillageState) => {
// Advance building construction.
V.buildings.filter(b => b.state.upgrade.isUpgrading).forEach(b => {
b.state.upgrade.remainingTime -= delta;
if (b.state.upgrade.remainingTime <= 0) {
b.level++;
b.state.upgrade.isUpgrading = false;
}
});
2024-11-05 11:35:32 +01:00
// 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;
2024-11-05 11:35:32 +01:00
});
2024-11-05 12:06:44 +01:00
// Kill units if food is negative.
if (V.resources.food < 0) {
// Choose a unit type at random.
const type = shuffle(Object.keys(V.units).filter(t => V.units[t] > 0))[0];
// Kill one unit of that type.
V.units[type]--;
}
2024-11-05 11:35:32 +01:00
// 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];
}
2024-10-23 11:59:50 +02:00
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;
}
});
2024-11-04 18:43:03 +01:00
// Check if the game is won.
if (V.resources.culture >= 2000) {
2024-11-04 18:43:03 +01:00
V.victory = true;
}
return V;
});
});
lastFrame = timestamp;
}