bourgade/src/utils.ts

154 lines
4.3 KiB
TypeScript
Raw Normal View History

import units from "./data/units";
2024-11-05 10:59:25 +00:00
import type { BuildingType, CostType, ProductionType, ResourcesType } from "./types";
import type { VillageState } from "./village";
2024-11-05 10:59:25 +00:00
function _reduceResources(acc: ResourcesType, item: ResourcesType): ResourcesType {
return {
wood: acc.wood + item.wood,
stone: acc.stone + item.stone,
iron: acc.iron + item.iron,
food: acc.food + item.food,
2024-11-05 10:59:25 +00:00
culture: acc.culture + item.culture,
};
}
2024-11-05 10:59:25 +00:00
export function getEmptyResources(): ResourcesType {
return {
wood: 0,
stone: 0,
iron: 0,
food: 0,
2024-11-05 10:59:25 +00:00
culture: 0,
};
}
2024-11-05 10:59:25 +00:00
export function getProduction(villageState: VillageState): ResourcesType {
2024-11-05 10:35:32 +00:00
let production = getEmptyResources();
// Add buildings production and intake.
production = villageState.buildings
.filter(b => b.behavior.production && b.level > 0)
.map(b => {
if (b.behavior.production) {
return b.behavior.production(villageState, b);
}
})
2024-11-05 10:35:32 +00:00
.reduce(_reduceResources, production);
2024-11-05 10:59:25 +00:00
// Add units production and intake.
2024-11-05 10:35:32 +00:00
['philosopher'].forEach(type => {
const unit = getUnitSource(type);
const unitCount = villageState.units[type] || 0;
2024-11-05 10:59:25 +00:00
// Add food intake.
2024-11-05 10:35:32 +00:00
const intakePerMinute = unit.behavior.foodIntakePerMinute * unitCount;
production.food -= intakePerMinute;
2024-11-05 10:59:25 +00:00
// Add culture production for Philosophers.
if (type === 'philosopher') {
const outputPerMinute = unit.behavior.culturePerMinute;
production.culture += outputPerMinute * unitCount;
}
2024-11-05 10:35:32 +00:00
});
return production;
}
export function getStorage(villageState: VillageState): ProductionType {
return villageState.buildings
.filter(b => b.behavior.storage && b.level > 0)
.map(b => {
if (b.behavior.storage) {
return b.behavior.storage(villageState, b);
}
})
.reduce(_reduceResources, getEmptyResources());
}
export function getBuilding(V: VillageState, buildingId: number): BuildingType {
2024-10-24 13:12:21 +00:00
const building = V.buildings.find(b => b.id === buildingId);
if (!building) {
throw new Error(`Cannot find building with id "${buildingId}"`);
}
return building;
}
export function getUnitSource(unitType: string) {
const unit = units.find(u => u.type === unitType);
if (unit === undefined) {
throw new Error(`Unknown unit type: "${unitType}"`);
}
return unit;
}
export function getKeysAsNumbers(dict: Object): Array<number> {
return Object.keys(dict).map(i => parseInt(i)).sort((a, b) => a - b);
}
/**
* Creates an array of shuffled values, using a version of the
* [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
*
* @since 0.1.0
* @category Array
* @param {Array} array The array to shuffle.
* @returns {Array} Returns the new shuffled array.
* @example
*
* shuffle([1, 2, 3, 4])
* // => [4, 1, 3, 2]
*/
export function shuffle<T>(array: Array<T>): Array<T> {
const length = array.length;
if (!length) {
return [];
}
let index = -1;
const lastIndex = length - 1;
const result = [ ...array ];
while (++index < length) {
const rand = index + Math.floor(Math.random() * (lastIndex - index + 1));
[ result[rand], result[index] ] = [ result[index], result[rand] ];
}
return result;
}
export function enqueueBuilding(V: VillageState, building: BuildingType) {
const ongoingUpgrades = V.queue.filter(q => q.id === building.id);
const level = building.level + 1 + ongoingUpgrades.length;
const remainingTime = 1000 * level;
V.queue.push({
id: building.id,
remainingTime,
});
}
export function getBuildingUpgradeCost(V: VillageState, building: BuildingType): CostType {
const ongoingUpgrades = V.queue.filter(q => q.id === building.id);
const level = building.level + ongoingUpgrades.length + 1;
return building.cost(level);
}
export function canPayBuildingCost(V: VillageState, building: BuildingType): boolean {
const cost = getBuildingUpgradeCost(V, building);
return !(
cost.wood > V.resources.wood
|| cost.stone > V.resources.stone
|| cost.iron > V.resources.iron
|| cost.food > V.resources.food
);
}