diff --git a/src/Action/ActionController.ts b/src/Action/ActionController.ts index a47d365..9fe2ecf 100644 --- a/src/Action/ActionController.ts +++ b/src/Action/ActionController.ts @@ -20,6 +20,10 @@ export function createActionHandler(name: string, scheduler: Scheduler): ActionC return new constructor(scheduler); } +export function err(msg: string): never { + throw new ActionError(msg); +} + export class ActionController { protected scheduler: Scheduler; constructor(scheduler: Scheduler) { @@ -29,11 +33,7 @@ export class ActionController { async run(args: Args, task: Task) {} ensureSameVillage(args: Args, task: Task) { - let villageId = args.villageId; - if (villageId === undefined) { - throw new ActionError('Undefined village id'); - } - + let villageId = args.villageId || err('Undefined village id'); const activeVillageId = grabActiveVillageId(); if (villageId !== activeVillageId) { throw new TryLaterError(aroundMinutes(1), 'Not same village'); diff --git a/src/Action/BuildBuildingAction.ts b/src/Action/BuildBuildingAction.ts index 23b6a1e..5be3c94 100644 --- a/src/Action/BuildBuildingAction.ts +++ b/src/Action/BuildBuildingAction.ts @@ -1,6 +1,6 @@ -import { ActionController, registerAction } from './ActionController'; -import { ActionError, GrabError, TryLaterError } from '../Errors'; -import { clickBuildButton } from '../Page/BuildingPage'; +import { ActionController, err, registerAction } from './ActionController'; +import { GrabError, TryLaterError } from '../Errors'; +import { clickBuildButton } from '../Page/BuildingPage/BuildingPage'; import { aroundMinutes } from '../utils'; import { Args } from '../Queue/Args'; import { Task } from '../Queue/TaskProvider'; @@ -8,14 +8,9 @@ import { Task } from '../Queue/TaskProvider'; @registerAction export class BuildBuildingAction extends ActionController { async run(args: Args, task: Task): Promise { - this.ensureSameVillage(args, task); - - const buildTypeId = args.buildTypeId; - if (buildTypeId === undefined) { - throw new ActionError('Undefined build type id'); - } - try { + this.ensureSameVillage(args, task); + const buildTypeId = args.buildTypeId || err('Undefined build type id'); clickBuildButton(buildTypeId); } catch (e) { if (e instanceof GrabError) { diff --git a/src/Action/ResearchAction.ts b/src/Action/ResearchAction.ts new file mode 100644 index 0000000..88f621f --- /dev/null +++ b/src/Action/ResearchAction.ts @@ -0,0 +1,22 @@ +import { ActionController, err, registerAction } from './ActionController'; +import { GrabError, TryLaterError } from '../Errors'; +import { aroundMinutes } from '../utils'; +import { Args } from '../Queue/Args'; +import { Task } from '../Queue/TaskProvider'; +import { clickResearchButton } from '../Page/BuildingPage/ForgePage'; + +@registerAction +export class ResearchAction extends ActionController { + async run(args: Args, task: Task): Promise { + try { + this.ensureSameVillage(args, task); + const unitId = args.unitId || err('No unitId in args'); + clickResearchButton(unitId); + } catch (e) { + if (e instanceof GrabError) { + throw new TryLaterError(aroundMinutes(15), e.message); + } + throw e; + } + } +} diff --git a/src/Action/SendResourcesAction.ts b/src/Action/SendResourcesAction.ts index 4f7b171..9e12786 100644 --- a/src/Action/SendResourcesAction.ts +++ b/src/Action/SendResourcesAction.ts @@ -1,8 +1,7 @@ -import { ActionController, registerAction } from './ActionController'; -import { AbortTaskError, ActionError, TryLaterError } from '../Errors'; +import { ActionController, err, registerAction } from './ActionController'; +import { AbortTaskError, TryLaterError } from '../Errors'; import { Resources } from '../Core/Resources'; import { Coordinates, Village } from '../Core/Village'; -import { clickSendButton, fillSendResourcesForm, grabMerchantsInfo } from '../Page/BuildingPage'; import { grabVillageResources } from '../Page/ResourcesBlock'; import { grabActiveVillageId, grabVillageList } from '../Page/VillageBlock'; import { SendResourcesTask } from '../Task/SendResourcesTask'; @@ -10,10 +9,7 @@ import { aroundMinutes, timestamp } from '../utils'; import { VillageStorage } from '../Storage/VillageStorage'; import { Args } from '../Queue/Args'; import { Task } from '../Queue/TaskProvider'; - -function err(msg: string): never { - throw new ActionError(msg); -} +import { clickSendButton, fillSendResourcesForm, grabMerchantsInfo } from '../Page/BuildingPage/MarketPage'; const TIMEOUT = 15; diff --git a/src/Action/UpdateBuildingTaskResourcesAction.ts b/src/Action/UpdateBuildingTaskResourcesAction.ts index 1c9cb23..8dc3b4e 100644 --- a/src/Action/UpdateBuildingTaskResourcesAction.ts +++ b/src/Action/UpdateBuildingTaskResourcesAction.ts @@ -1,5 +1,5 @@ import { ActionController, registerAction } from './ActionController'; -import { grabContractResources } from '../Page/BuildingPage'; +import { grabContractResources } from '../Page/BuildingPage/BuildingPage'; import { Args } from '../Queue/Args'; import { Task } from '../Queue/TaskProvider'; diff --git a/src/Action/UpgradeBuildingAction.ts b/src/Action/UpgradeBuildingAction.ts index 24dd37b..b16a94d 100644 --- a/src/Action/UpgradeBuildingAction.ts +++ b/src/Action/UpgradeBuildingAction.ts @@ -1,6 +1,6 @@ import { ActionController, registerAction } from './ActionController'; import { GrabError, TryLaterError } from '../Errors'; -import { clickUpgradeButton } from '../Page/BuildingPage'; +import { clickUpgradeButton } from '../Page/BuildingPage/BuildingPage'; import { aroundMinutes } from '../utils'; import { Args } from '../Queue/Args'; import { Task } from '../Queue/TaskProvider'; @@ -8,9 +8,8 @@ import { Task } from '../Queue/TaskProvider'; @registerAction export class UpgradeBuildingAction extends ActionController { async run(args: Args, task: Task): Promise { - this.ensureSameVillage(args, task); - try { + this.ensureSameVillage(args, task); clickUpgradeButton(); } catch (e) { if (e instanceof GrabError) { diff --git a/src/Core/Buildings.ts b/src/Core/Buildings.ts index 44f3d94..c905696 100644 --- a/src/Core/Buildings.ts +++ b/src/Core/Buildings.ts @@ -1,5 +1,6 @@ export const WAREHOUSE_ID = 10; export const GARNER_ID = 11; +export const FORGE_ID = 13; export const COLLECTION_POINT_ID = 16; export const MARKET_ID = 17; export const QUARTERS_ID = 19; diff --git a/src/Executor.ts b/src/Executor.ts index 29c6eef..100d364 100644 --- a/src/Executor.ts +++ b/src/Executor.ts @@ -125,13 +125,13 @@ export class Executor { this.scheduler.clearActions(); if (err instanceof AbortTaskError) { - this.logger.warn('ABORT TASK', task.id); + this.logger.warn('ABORT TASK', task.id, 'MSG', err.message); this.scheduler.removeTask(task.id); return; } if (err instanceof TryLaterError) { - this.logger.warn('TRY', task.id, 'AFTER', err.seconds); + this.logger.warn('TRY', task.id, 'AFTER', err.seconds, 'MSG', err.message); this.scheduler.postponeTask(task.id, err.seconds); return; } diff --git a/src/Grabber/MarketPageGrabber.ts b/src/Grabber/MarketPageGrabber.ts index 74aa7dd..c67dd3c 100644 --- a/src/Grabber/MarketPageGrabber.ts +++ b/src/Grabber/MarketPageGrabber.ts @@ -1,8 +1,8 @@ import { Grabber } from './Grabber'; import { grabActiveVillageId } from '../Page/VillageBlock'; import { VillageStorage } from '../Storage/VillageStorage'; -import { grabIncomingMerchants } from '../Page/BuildingPage'; import { isMarketSendResourcesPage } from '../Page/PageDetectors'; +import { grabIncomingMerchants } from '../Page/BuildingPage/MarketPage'; export class MarketPageGrabber extends Grabber { grab(): void { diff --git a/src/Page/BuildingPage.ts b/src/Page/BuildingPage.ts deleted file mode 100644 index 69d69ce..0000000 --- a/src/Page/BuildingPage.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { GrabError } from '../Errors'; -import { elClassId, getNumber, trimPrefix, uniqId } from '../utils'; -import { Resources } from '../Core/Resources'; -import { Coordinates } from '../Core/Village'; -import { IncomingMerchant } from '../Core/Market'; - -export function clickBuildButton(typeId: number) { - const section = jQuery(`#contract_building${typeId}`); - if (section.length !== 1) { - throw new GrabError('No build section'); - } - const btn = section.find('.contractLink button.green.new'); - if (btn.length !== 1) { - throw new GrabError('No build button, try later'); - } - btn.trigger('click'); -} - -export function createBuildButton(onClickHandler: (buildTypeId: number, resources: Resources) => void) { - const $els = jQuery('[id^=contract_building]'); - $els.each((idx, el) => { - const $el = jQuery(el); - const buildTypeId = getNumber(trimPrefix($el.attr('id') || '', 'contract_building')); - const btnId = uniqId(); - const resElement = $el.find('.resourceWrapper .resource'); - const resources = grabResourcesFromList(resElement); - $el.append(`
Построить
`); - jQuery(`#${btnId}`).on('click', evt => { - evt.preventDefault(); - onClickHandler(buildTypeId, resources); - }); - }); -} - -export function clickUpgradeButton() { - const btn = jQuery('.upgradeButtonsContainer .section1 button.green.build'); - if (btn.length !== 1) { - throw new GrabError('No upgrade button, try later'); - } - btn.trigger('click'); -} - -export function createUpgradeButton(onClickHandler: (resources: Resources) => void) { - const upgradeContainer = jQuery('.upgradeButtonsContainer .section1'); - if (upgradeContainer.length !== 1) { - return; - } - const id = uniqId(); - const btn = `
В очередь
`; - upgradeContainer.append(btn); - const resources = grabContractResources(); - jQuery(`#${id}`).on('click', evt => { - evt.preventDefault(); - onClickHandler(resources); - }); -} - -function grabResourcesFromList($els: JQuery) { - const getText = (n: number) => - jQuery($els.get(n)) - .find('.value') - .text(); - const grab = (n: number) => getNumber(getText(n)); - return new Resources(grab(0), grab(1), grab(2), grab(3)); -} - -export function grabContractResources(): Resources { - const $els = jQuery('#contract .resource'); - if ($els.length === 0) { - throw new GrabError('No resource contract element'); - } - return grabResourcesFromList($els); -} - -export function createTrainTroopButtons( - onClickHandler: (troopId: number, resources: Resources, count: number) => void -) { - const troopBlocks = jQuery('.action.troop:not(.empty) .innerTroopWrapper'); - if (troopBlocks.length === 0) { - throw new GrabError('No troop blocks'); - } - troopBlocks.each((idx, el) => { - const $el = jQuery(el); - const troopId = elClassId($el.attr('class'), 'troop'); - if (troopId === undefined) { - return; - } - const id = uniqId(); - $el.find('.details').append(`
Обучить
`); - const resElement = $el.find('.resourceWrapper .resource'); - const resources = grabResourcesFromList(resElement); - jQuery(`#${id}`).on('click', evt => { - evt.preventDefault(); - const input = $el.find(`input[name="t${troopId}"]`); - const count = getNumber(input.val()); - if (count > 0) { - onClickHandler(troopId, resources, count); - } - }); - }); -} - -interface SendResourcesClickHandler { - (resources: Resources, crd: Coordinates, scale: number): void; -} - -export function createSendResourcesButton(onClickHandler: SendResourcesClickHandler) { - const id1 = uniqId(); - const id10 = uniqId(); - const id100 = uniqId(); - const id1000 = uniqId(); - - jQuery('#button').before(`
- Отправить / - x10 / - x100 / - x1000 -
`); - - const createHandler = (handler: SendResourcesClickHandler, scale: number) => (evt: JQuery.Event) => { - evt.preventDefault(); - const sendSelect = jQuery('#send_select'); - const resources = new Resources( - getNumber(sendSelect.find('#r1').val()), - getNumber(sendSelect.find('#r2').val()), - getNumber(sendSelect.find('#r3').val()), - getNumber(sendSelect.find('#r4').val()) - ); - const crd = new Coordinates(getNumber(jQuery('#xCoordInput').val()), getNumber(jQuery('#yCoordInput').val())); - onClickHandler(resources, crd, scale); - }; - - jQuery(`#${id1}`).on('click', createHandler(onClickHandler, 1)); - jQuery(`#${id10}`).on('click', createHandler(onClickHandler, 10)); - jQuery(`#${id100}`).on('click', createHandler(onClickHandler, 100)); - jQuery(`#${id1000}`).on('click', createHandler(onClickHandler, 1000)); -} - -export function grabMerchantsInfo() { - const available = getNumber(jQuery('.merchantsAvailable').text()); - const carry = getNumber(jQuery('.carry b').text()); - return { available, carry }; -} - -export function fillSendResourcesForm(resources: Resources, crd: Coordinates) { - const sendSelect = jQuery('#send_select'); - sendSelect.find('#r1').val(resources.lumber); - sendSelect.find('#r2').val(resources.clay); - sendSelect.find('#r3').val(resources.iron); - sendSelect.find('#r4').val(resources.crop); - jQuery('#xCoordInput').val(crd.x); - jQuery('#yCoordInput').val(crd.y); -} - -export function clickSendButton() { - jQuery('#enabledButton').trigger('click'); -} - -export function grabIncomingMerchants(): ReadonlyArray { - const result: Array = []; - const root = jQuery('#merchantsOnTheWay .ownMerchants'); - root.find('.traders').each((idx, el) => { - const $el = jQuery(el); - result.push( - new IncomingMerchant( - grabResourcesFromList($el.find('.resourceWrapper .resources')), - getNumber($el.find('.timer').attr('value')) - ) - ); - }); - return result; -} diff --git a/src/Page/BuildingPage/BuildingPage.ts b/src/Page/BuildingPage/BuildingPage.ts new file mode 100644 index 0000000..bc34ee5 --- /dev/null +++ b/src/Page/BuildingPage/BuildingPage.ts @@ -0,0 +1,71 @@ +import { GrabError } from '../../Errors'; +import { getNumber, trimPrefix, uniqId } from '../../utils'; +import { Resources } from '../../Core/Resources'; + +export function clickBuildButton(typeId: number) { + const section = jQuery(`#contract_building${typeId}`); + if (section.length !== 1) { + throw new GrabError('No build section'); + } + const btn = section.find('.contractLink button.green.new'); + if (btn.length !== 1) { + throw new GrabError('No build button, try later'); + } + btn.trigger('click'); +} + +export function createBuildButton(onClickHandler: (buildTypeId: number, resources: Resources) => void) { + const $els = jQuery('[id^=contract_building]'); + $els.each((idx, el) => { + const $el = jQuery(el); + const buildTypeId = getNumber(trimPrefix($el.attr('id') || '', 'contract_building')); + const btnId = uniqId(); + const resElement = $el.find('.resourceWrapper .resource'); + const resources = grabResourcesFromList(resElement); + $el.append(``); + jQuery(`#${btnId}`).on('click', evt => { + evt.preventDefault(); + onClickHandler(buildTypeId, resources); + }); + }); +} + +export function clickUpgradeButton() { + const btn = jQuery('.upgradeButtonsContainer .section1 button.green.build'); + if (btn.length !== 1) { + throw new GrabError('No upgrade button, try later'); + } + btn.trigger('click'); +} + +export function createUpgradeButton(onClickHandler: (resources: Resources) => void) { + const upgradeContainer = jQuery('.upgradeButtonsContainer .section1'); + if (upgradeContainer.length !== 1) { + return; + } + const id = uniqId(); + const btn = ``; + upgradeContainer.append(btn); + const resources = grabContractResources(); + jQuery(`#${id}`).on('click', evt => { + evt.preventDefault(); + onClickHandler(resources); + }); +} + +export function grabResourcesFromList($els: JQuery) { + const getText = (n: number) => + jQuery($els.get(n)) + .find('.value') + .text(); + const grab = (n: number) => getNumber(getText(n)); + return new Resources(grab(0), grab(1), grab(2), grab(3)); +} + +export function grabContractResources(): Resources { + const $els = jQuery('#contract .resource'); + if ($els.length === 0) { + throw new GrabError('No resource contract element'); + } + return grabResourcesFromList($els); +} diff --git a/src/Page/BuildingPage/ForgePage.ts b/src/Page/BuildingPage/ForgePage.ts new file mode 100644 index 0000000..9b2cd9c --- /dev/null +++ b/src/Page/BuildingPage/ForgePage.ts @@ -0,0 +1,59 @@ +import { elClassId, getNumber, uniqId } from '../../utils'; +import { Resources } from '../../Core/Resources'; +import { grabResourcesFromList } from './BuildingPage'; +import { GrabError } from '../../Errors'; + +interface ResearchClickHandler { + (resources: Resources, unitId: number): void; +} + +export function createResearchButtons(onClickHandler: ResearchClickHandler) { + const $els = jQuery('.research'); + $els.each((index, $el) => createResearchButton(jQuery($el), onClickHandler)); +} + +function createResearchButton($el: JQuery, onClickHandler: ResearchClickHandler) { + const unitId = grabUnitId($el); + const resElement = $el.find('.resourceWrapper .resource'); + const resources = grabResourcesFromList(resElement); + + const id = uniqId(); + $el.find('.cta').after(``); + + jQuery(`#${id}`).on('click', evt => { + evt.preventDefault(); + onClickHandler(resources, unitId); + }); +} + +function grabUnitId($el: JQuery) { + const unitImg = $el.find('img.unit'); + return getNumber(elClassId(unitImg.attr('class'), 'u')); +} + +export function clickResearchButton(unitId: number) { + const $blockEl = findResearchBlockByUnitId(unitId); + if ($blockEl === undefined) { + throw new GrabError(`No research block for unit ${unitId}`); + } + const $btn = $blockEl.find('button.green.contracting'); + if ($btn.length !== 1) { + throw new GrabError(`No research button for unit ${unitId}`); + } + $btn.trigger('click'); +} + +function findResearchBlockByUnitId(unitId: number): JQuery | undefined { + const $els = jQuery('.research'); + let $blockEl: JQuery | undefined = undefined; + $els.each((index, el) => { + const $el = jQuery(el); + const blockUnitId = grabUnitId($el); + if (blockUnitId === unitId && $blockEl === undefined) { + $blockEl = $el; + } + }); + return $blockEl; +} diff --git a/src/Page/BuildingPage/MarketPage.ts b/src/Page/BuildingPage/MarketPage.ts new file mode 100644 index 0000000..1b6c8a6 --- /dev/null +++ b/src/Page/BuildingPage/MarketPage.ts @@ -0,0 +1,76 @@ +import { getNumber, uniqId } from '../../utils'; +import { Resources } from '../../Core/Resources'; +import { Coordinates } from '../../Core/Village'; +import { IncomingMerchant } from '../../Core/Market'; +import { grabResourcesFromList } from './BuildingPage'; + +interface SendResourcesClickHandler { + (resources: Resources, crd: Coordinates, scale: number): void; +} + +export function createSendResourcesButton(onClickHandler: SendResourcesClickHandler) { + const id1 = uniqId(); + const id10 = uniqId(); + const id100 = uniqId(); + const id1000 = uniqId(); + + jQuery('#button').before(`
+ Отправить / + x10 / + x100 / + x1000 +
`); + + const createHandler = (handler: SendResourcesClickHandler, scale: number) => (evt: JQuery.Event) => { + evt.preventDefault(); + const sendSelect = jQuery('#send_select'); + const resources = new Resources( + getNumber(sendSelect.find('#r1').val()), + getNumber(sendSelect.find('#r2').val()), + getNumber(sendSelect.find('#r3').val()), + getNumber(sendSelect.find('#r4').val()) + ); + const crd = new Coordinates(getNumber(jQuery('#xCoordInput').val()), getNumber(jQuery('#yCoordInput').val())); + onClickHandler(resources, crd, scale); + }; + + jQuery(`#${id1}`).on('click', createHandler(onClickHandler, 1)); + jQuery(`#${id10}`).on('click', createHandler(onClickHandler, 10)); + jQuery(`#${id100}`).on('click', createHandler(onClickHandler, 100)); + jQuery(`#${id1000}`).on('click', createHandler(onClickHandler, 1000)); +} + +export function grabMerchantsInfo() { + const available = getNumber(jQuery('.merchantsAvailable').text()); + const carry = getNumber(jQuery('.carry b').text()); + return { available, carry }; +} + +export function fillSendResourcesForm(resources: Resources, crd: Coordinates) { + const sendSelect = jQuery('#send_select'); + sendSelect.find('#r1').val(resources.lumber); + sendSelect.find('#r2').val(resources.clay); + sendSelect.find('#r3').val(resources.iron); + sendSelect.find('#r4').val(resources.crop); + jQuery('#xCoordInput').val(crd.x); + jQuery('#yCoordInput').val(crd.y); +} + +export function clickSendButton() { + jQuery('#enabledButton').trigger('click'); +} + +export function grabIncomingMerchants(): ReadonlyArray { + const result: Array = []; + const root = jQuery('#merchantsOnTheWay .ownMerchants'); + root.find('.traders').each((idx, el) => { + const $el = jQuery(el); + result.push( + new IncomingMerchant( + grabResourcesFromList($el.find('.resourceWrapper .resources')), + getNumber($el.find('.timer').attr('value')) + ) + ); + }); + return result; +} diff --git a/src/Page/BuildingPage/TrooperPage.ts b/src/Page/BuildingPage/TrooperPage.ts new file mode 100644 index 0000000..5d2b24c --- /dev/null +++ b/src/Page/BuildingPage/TrooperPage.ts @@ -0,0 +1,32 @@ +import { Resources } from '../../Core/Resources'; +import { GrabError } from '../../Errors'; +import { elClassId, getNumber, uniqId } from '../../utils'; +import { grabResourcesFromList } from './BuildingPage'; + +export function createTrainTroopButtons( + onClickHandler: (troopId: number, resources: Resources, count: number) => void +) { + const troopBlocks = jQuery('.action.troop:not(.empty) .innerTroopWrapper'); + if (troopBlocks.length === 0) { + throw new GrabError('No troop blocks'); + } + troopBlocks.each((idx, el) => { + const $el = jQuery(el); + const troopId = elClassId($el.attr('class'), 'troop'); + if (troopId === undefined) { + return; + } + const id = uniqId(); + $el.find('.details').append(``); + const resElement = $el.find('.resourceWrapper .resource'); + const resources = grabResourcesFromList(resElement); + jQuery(`#${id}`).on('click', evt => { + evt.preventDefault(); + const input = $el.find(`input[name="t${troopId}"]`); + const count = getNumber(input.val()); + if (count > 0) { + onClickHandler(troopId, resources, count); + } + }); + }); +} diff --git a/src/Page/BuildingPageController.ts b/src/Page/BuildingPageController.ts index a728b8f..85099c1 100644 --- a/src/Page/BuildingPageController.ts +++ b/src/Page/BuildingPageController.ts @@ -4,18 +4,17 @@ import { Scheduler } from '../Scheduler'; import { TrainTroopTask } from '../Task/TrainTroopTask'; import { grabActiveVillageId, grabVillageList } from './VillageBlock'; import { ConsoleLogger, Logger } from '../Logger'; -import { - createBuildButton, - createSendResourcesButton, - createTrainTroopButtons, - createUpgradeButton, -} from './BuildingPage'; +import { createBuildButton, createUpgradeButton } from './BuildingPage/BuildingPage'; import { BuildBuildingTask } from '../Task/BuildBuildingTask'; import { Resources } from '../Core/Resources'; import { Coordinates } from '../Core/Village'; import { SendResourcesTask } from '../Task/SendResourcesTask'; import { EMBASSY_ID, HORSE_STABLE_ID, QUARTERS_ID } from '../Core/Buildings'; -import { BuildingPageAttributes, isMarketSendResourcesPage } from './PageDetectors'; +import { BuildingPageAttributes, isForgePage, isMarketSendResourcesPage } from './PageDetectors'; +import { createTrainTroopButtons } from './BuildingPage/TrooperPage'; +import { createSendResourcesButton } from './BuildingPage/MarketPage'; +import { createResearchButtons } from './BuildingPage/ForgePage'; +import { ResearchTask } from '../Task/ResearchTask'; export class BuildingPageController { private scheduler: Scheduler; @@ -53,6 +52,10 @@ export class BuildingPageController { if (isMarketSendResourcesPage()) { createSendResourcesButton((res, crd, scale) => this.onSendResources(res, crd, scale)); } + + if (isForgePage()) { + createResearchButtons((res, unitId) => this.onResearch(res, unitId)); + } } private onScheduleBuildBuilding(buildTypeId: number, resources: Resources) { @@ -101,4 +104,16 @@ export class BuildingPageController { }); notify(`Send resources ${JSON.stringify(resources)} from ${villageId} to ${JSON.stringify(coordinates)}`); } + + private onResearch(resources: Resources, unitId: number) { + const villageId = grabActiveVillageId(); + this.scheduler.scheduleTask(ResearchTask.name, { + villageId, + buildTypeId: this.attributes.buildTypeId, + buildId: this.attributes.buildId, + unitId, + resources, + }); + notify(`Researching ${unitId} scheduled`); + } } diff --git a/src/Page/PageDetectors.ts b/src/Page/PageDetectors.ts index cbb7120..6cbc044 100644 --- a/src/Page/PageDetectors.ts +++ b/src/Page/PageDetectors.ts @@ -1,5 +1,5 @@ import { elClassId, getNumber, parseLocation } from '../utils'; -import { MARKET_ID } from '../Core/Buildings'; +import { FORGE_ID, MARKET_ID } from '../Core/Buildings'; export interface BuildingPageAttributes { buildId: number; @@ -40,3 +40,11 @@ export function isMarketSendResourcesPage(): boolean { const { buildTypeId, tabId } = getBuildingPageAttributes(); return buildTypeId === MARKET_ID && tabId === 5; } + +export function isForgePage(): boolean { + if (!isBuildingPage()) { + return false; + } + const { buildTypeId } = getBuildingPageAttributes(); + return buildTypeId === FORGE_ID; +} diff --git a/src/Queue/Args.ts b/src/Queue/Args.ts index 613a8e8..f4a089e 100644 --- a/src/Queue/Args.ts +++ b/src/Queue/Args.ts @@ -16,6 +16,7 @@ export interface Args { trainCount?: number; resources?: ResourcesInterface; coordinates?: CoordinatesInterface; + unitId?: number; level?: number; selector?: string; path?: string; diff --git a/src/Task/ResearchTask.ts b/src/Task/ResearchTask.ts new file mode 100644 index 0000000..49ba720 --- /dev/null +++ b/src/Task/ResearchTask.ts @@ -0,0 +1,24 @@ +import { TaskController, registerTask, ActionDefinition } from './TaskController'; +import { GoToPageAction } from '../Action/GoToPageAction'; +import { CompleteTaskAction } from '../Action/CompleteTaskAction'; +import { TrainTrooperAction } from '../Action/TrainTrooperAction'; +import { path } from '../utils'; +import { Action } from '../Queue/ActionQueue'; +import { Args } from '../Queue/Args'; +import { Task } from '../Queue/TaskProvider'; +import { ResearchAction } from '../Action/ResearchAction'; + +@registerTask +export class ResearchTask extends TaskController { + defineActions(task: Task): Array { + const args = task.args; + + const pathArgs = { + newdid: args.villageId, + gid: args.buildTypeId || undefined, + id: args.buildId || undefined, + }; + + return [[GoToPageAction.name, { ...args, path: path('/build.php', pathArgs) }], [ResearchAction.name]]; + } +} diff --git a/src/Task/ResourcesToLevel.ts b/src/Task/ResourcesToLevel.ts index d5c5cf0..e5083c3 100644 --- a/src/Task/ResourcesToLevel.ts +++ b/src/Task/ResourcesToLevel.ts @@ -1,10 +1,7 @@ import { TaskController, registerTask, ActionDefinition } from './TaskController'; import { GoToPageAction } from '../Action/GoToPageAction'; -import { CompleteTaskAction } from '../Action/CompleteTaskAction'; import { path } from '../utils'; import { UpgradeResourceToLevel } from '../Action/UpgradeResourceToLevel'; -import { Action } from '../Queue/ActionQueue'; -import { Args } from '../Queue/Args'; import { Task } from '../Queue/TaskProvider'; @registerTask @@ -12,7 +9,7 @@ export class ResourcesToLevel extends TaskController { defineActions(task: Task): Array { return [ [GoToPageAction.name, { path: path('/dorf1.php', { newdid: task.args.villageId }) }], - [UpgradeResourceToLevel.name, {}], + [UpgradeResourceToLevel.name], ]; } } diff --git a/src/Task/SendResourcesTask.ts b/src/Task/SendResourcesTask.ts index c9dd41d..665c0f7 100644 --- a/src/Task/SendResourcesTask.ts +++ b/src/Task/SendResourcesTask.ts @@ -26,9 +26,9 @@ export class SendResourcesTask extends TaskController { return [ [GoToPageAction.name, { path: pagePath }], - [SendResourcesAction.name, {}], + [SendResourcesAction.name], [ClickButtonAction.name, { selector: '#enabledButton.green.sendRessources' }], - [CompleteTaskAction.name, {}], + [CompleteTaskAction.name], ]; } } diff --git a/src/Task/TaskController.ts b/src/Task/TaskController.ts index 735bece..8f84303 100644 --- a/src/Task/TaskController.ts +++ b/src/Task/TaskController.ts @@ -19,7 +19,7 @@ export function createTaskHandler(name: string, scheduler: Scheduler): TaskContr return new constructor(scheduler); } -export type ActionDefinition = [string, Args]; +export type ActionDefinition = [string] | [string, Args]; export class TaskController { protected scheduler: Scheduler; @@ -41,7 +41,11 @@ export class TaskController { const args: Args = { ...task.args, taskId: task.id }; const commands: Array = []; for (let def of this.defineActions(task)) { - commands.push(new Action(def[0], { ...args, ...def[1] })); + if (def.length === 1) { + commands.push(new Action(def[0], args)); + } else { + commands.push(new Action(def[0], { ...args, ...def[1] })); + } } commands.push(new Action(CompleteTaskAction.name, args)); return commands; diff --git a/src/Task/TrainTroopTask.ts b/src/Task/TrainTroopTask.ts index cefc16f..9d5d081 100644 --- a/src/Task/TrainTroopTask.ts +++ b/src/Task/TrainTroopTask.ts @@ -1,4 +1,4 @@ -import { TaskController, registerTask } from './TaskController'; +import { registerTask, TaskController } from './TaskController'; import { GoToPageAction } from '../Action/GoToPageAction'; import { CompleteTaskAction } from '../Action/CompleteTaskAction'; import { TrainTrooperAction } from '../Action/TrainTrooperAction'; @@ -19,10 +19,8 @@ export class TrainTroopTask extends TaskController { s: args.sheetId, }; - const pagePath = path('/build.php', pathArgs); - this.scheduler.scheduleActions([ - new Action(GoToPageAction.name, { ...args, path: pagePath }), + new Action(GoToPageAction.name, { ...args, path: path('/build.php', pathArgs) }), new Action(TrainTrooperAction.name, args), new Action(CompleteTaskAction.name, args), ]);