import units from "./data/units"; import type { BuildingType, CostType, ProductionType, ResourcesType } from "./types"; import type { VillageState } from "./village"; 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, culture: acc.culture + item.culture, }; } export function getEmptyResources(): ResourcesType { return { wood: 0, stone: 0, iron: 0, food: 0, culture: 0, }; } export function getProduction(villageState: VillageState): ResourcesType { 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); } }) .reduce(_reduceResources, production); // Add units production and intake. ['philosopher'].forEach(type => { const unit = getUnitSource(type); const unitCount = villageState.units[type] || 0; // Add food intake. const intakePerMinute = unit.behavior.foodIntakePerMinute * unitCount; production.food -= intakePerMinute; // Add culture production for Philosophers. if (type === 'philosopher') { const outputPerMinute = unit.behavior.culturePerMinute; production.culture += outputPerMinute * unitCount; } }); 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 { 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 { 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(array: Array): Array { 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 ); }