import { Upgrade, ResourceList, Status, BuildingLight, BuildingType, BuildingList } from "../types"; import { stringToStatus, stringToResourceType, getEmptyResourceList } from "../typesHelper"; import { Page, ElementHandle } from 'puppeteer'; import { openPannel } from "./pannel"; const COST_SELECTOR = '[class=costs]'; const getBuildingUpgradeUrl = async (status: Status, elem: ElementHandle): Promise => { if (status === 'on') { return await elem.evaluate(e => { const button = e.querySelector('button'); if (!button) return undefined; return button.getAttribute('data-target'); }); } return undefined; }; // Page should have upgrade pannel open const getUpgradeCosts = async (page: Page): Promise => { const costElem = await page.$(COST_SELECTOR); const resourcesElem = await costElem.$$('[class*=resource]'); const costs = getEmptyResourceList(); await Promise.all(resourcesElem.map(async resourceElem => { const { value, classname } = await resourceElem.evaluate(elem => ({ value: Number(elem.getAttribute('data-value')), classname: elem.getAttribute('class'), })); const resource = stringToResourceType(classname.split(' ').find(c => stringToResourceType(c))); if (!resource) throw new Error(`Can't find resource in ${classname}`); costs[resource] = value; })); return costs; }; const parseDateInterval = (time: string): number => { let total = 0; let offset = time.length - 1; let factor = 0; let streak = 0; let currNb = 0; while (offset >= 0) { const c = time.charAt(offset); if (isNaN(Number(c))) { total += currNb * factor; factor = 0; streak = 0; currNb = 0; } else { const nb = Number(c); currNb += nb * (10 ** streak); streak += 1; } if (c === 'S') factor = 1; if (c === 'M') factor = 60; if (c === 'D') factor = 60 * 24; if (c === 'Y') factor = 60 * 24 * 365; offset -= 1; } return total; }; // Page should have upgrade pannel open const getUpgradeTime = async (page: Page): Promise => { const buildTimeDiv = await page.$('[class="build_duration"]'); const timeElem = await buildTimeDiv.$('time'); const timeString = await timeElem.evaluate(e => e.getAttribute('datetime')); return parseDateInterval(timeString); }; const loadUpgrade = async (status: Status, id: number, elem: ElementHandle, page: Page): Promise => { await openPannel(page, elem, id); return { costs: await getUpgradeCosts(page), url: await getBuildingUpgradeUrl(status, elem), time: await getUpgradeTime(page), }; }; export const loadBuildingLight = async (elem: ElementHandle, page: Page): Promise => { const id = Number(await elem.evaluate(e => e.getAttribute('data-technology'))); const status = stringToStatus(await elem.evaluate(e => e.getAttribute('data-status'))); const level = await elem.evaluate(e => { let levelElem = e.querySelector('[class=level]'); if (!levelElem) levelElem = e.querySelector('[class=amount]'); return Number(levelElem.getAttribute('data-value')) + Number(levelElem.getAttribute('data-bonus')); }); const building: BuildingLight = { id, status, level, upgrade: await loadUpgrade(status, id, elem, page), }; return building; }; export async function loadBuildings( page: Page, allTypes: T[], silenceError: boolean = false, selector: string = "[data-technology]", ): Promise> { const elems = await page.$$(selector); const buildings: BuildingList = {}; for (const elem of elems) { const classnames = (await elem.evaluate(e => e.getAttribute('class'))).split(' '); const type: T | undefined = allTypes.find(t => classnames.some(c => c.toLowerCase() === t.toLowerCase())); if (!type) { if (!silenceError) console.error(`Unkown building type ${classnames} not in ${allTypes}`); continue; } const building = await loadBuildingLight(elem, page); buildings[type] = { ...building, type, __elem: elem, }; } return buildings; }