Add research tasks
This commit is contained in:
parent
3844e28f76
commit
ed2102ce24
@ -20,6 +20,10 @@ export function createActionHandler(name: string, scheduler: Scheduler): ActionC
|
|||||||
return new constructor(scheduler);
|
return new constructor(scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function err(msg: string): never {
|
||||||
|
throw new ActionError(msg);
|
||||||
|
}
|
||||||
|
|
||||||
export class ActionController {
|
export class ActionController {
|
||||||
protected scheduler: Scheduler;
|
protected scheduler: Scheduler;
|
||||||
constructor(scheduler: Scheduler) {
|
constructor(scheduler: Scheduler) {
|
||||||
@ -29,11 +33,7 @@ export class ActionController {
|
|||||||
async run(args: Args, task: Task) {}
|
async run(args: Args, task: Task) {}
|
||||||
|
|
||||||
ensureSameVillage(args: Args, task: Task) {
|
ensureSameVillage(args: Args, task: Task) {
|
||||||
let villageId = args.villageId;
|
let villageId = args.villageId || err('Undefined village id');
|
||||||
if (villageId === undefined) {
|
|
||||||
throw new ActionError('Undefined village id');
|
|
||||||
}
|
|
||||||
|
|
||||||
const activeVillageId = grabActiveVillageId();
|
const activeVillageId = grabActiveVillageId();
|
||||||
if (villageId !== activeVillageId) {
|
if (villageId !== activeVillageId) {
|
||||||
throw new TryLaterError(aroundMinutes(1), 'Not same village');
|
throw new TryLaterError(aroundMinutes(1), 'Not same village');
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ActionController, registerAction } from './ActionController';
|
import { ActionController, err, registerAction } from './ActionController';
|
||||||
import { ActionError, GrabError, TryLaterError } from '../Errors';
|
import { GrabError, TryLaterError } from '../Errors';
|
||||||
import { clickBuildButton } from '../Page/BuildingPage';
|
import { clickBuildButton } from '../Page/BuildingPage/BuildingPage';
|
||||||
import { aroundMinutes } from '../utils';
|
import { aroundMinutes } from '../utils';
|
||||||
import { Args } from '../Queue/Args';
|
import { Args } from '../Queue/Args';
|
||||||
import { Task } from '../Queue/TaskProvider';
|
import { Task } from '../Queue/TaskProvider';
|
||||||
@ -8,14 +8,9 @@ import { Task } from '../Queue/TaskProvider';
|
|||||||
@registerAction
|
@registerAction
|
||||||
export class BuildBuildingAction extends ActionController {
|
export class BuildBuildingAction extends ActionController {
|
||||||
async run(args: Args, task: Task): Promise<any> {
|
async run(args: Args, task: Task): Promise<any> {
|
||||||
this.ensureSameVillage(args, task);
|
|
||||||
|
|
||||||
const buildTypeId = args.buildTypeId;
|
|
||||||
if (buildTypeId === undefined) {
|
|
||||||
throw new ActionError('Undefined build type id');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
this.ensureSameVillage(args, task);
|
||||||
|
const buildTypeId = args.buildTypeId || err('Undefined build type id');
|
||||||
clickBuildButton(buildTypeId);
|
clickBuildButton(buildTypeId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof GrabError) {
|
if (e instanceof GrabError) {
|
||||||
|
22
src/Action/ResearchAction.ts
Normal file
22
src/Action/ResearchAction.ts
Normal file
@ -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<any> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,7 @@
|
|||||||
import { ActionController, registerAction } from './ActionController';
|
import { ActionController, err, registerAction } from './ActionController';
|
||||||
import { AbortTaskError, ActionError, TryLaterError } from '../Errors';
|
import { AbortTaskError, TryLaterError } from '../Errors';
|
||||||
import { Resources } from '../Core/Resources';
|
import { Resources } from '../Core/Resources';
|
||||||
import { Coordinates, Village } from '../Core/Village';
|
import { Coordinates, Village } from '../Core/Village';
|
||||||
import { clickSendButton, fillSendResourcesForm, grabMerchantsInfo } from '../Page/BuildingPage';
|
|
||||||
import { grabVillageResources } from '../Page/ResourcesBlock';
|
import { grabVillageResources } from '../Page/ResourcesBlock';
|
||||||
import { grabActiveVillageId, grabVillageList } from '../Page/VillageBlock';
|
import { grabActiveVillageId, grabVillageList } from '../Page/VillageBlock';
|
||||||
import { SendResourcesTask } from '../Task/SendResourcesTask';
|
import { SendResourcesTask } from '../Task/SendResourcesTask';
|
||||||
@ -10,10 +9,7 @@ import { aroundMinutes, timestamp } from '../utils';
|
|||||||
import { VillageStorage } from '../Storage/VillageStorage';
|
import { VillageStorage } from '../Storage/VillageStorage';
|
||||||
import { Args } from '../Queue/Args';
|
import { Args } from '../Queue/Args';
|
||||||
import { Task } from '../Queue/TaskProvider';
|
import { Task } from '../Queue/TaskProvider';
|
||||||
|
import { clickSendButton, fillSendResourcesForm, grabMerchantsInfo } from '../Page/BuildingPage/MarketPage';
|
||||||
function err(msg: string): never {
|
|
||||||
throw new ActionError(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
const TIMEOUT = 15;
|
const TIMEOUT = 15;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ActionController, registerAction } from './ActionController';
|
import { ActionController, registerAction } from './ActionController';
|
||||||
import { grabContractResources } from '../Page/BuildingPage';
|
import { grabContractResources } from '../Page/BuildingPage/BuildingPage';
|
||||||
import { Args } from '../Queue/Args';
|
import { Args } from '../Queue/Args';
|
||||||
import { Task } from '../Queue/TaskProvider';
|
import { Task } from '../Queue/TaskProvider';
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ActionController, registerAction } from './ActionController';
|
import { ActionController, registerAction } from './ActionController';
|
||||||
import { GrabError, TryLaterError } from '../Errors';
|
import { GrabError, TryLaterError } from '../Errors';
|
||||||
import { clickUpgradeButton } from '../Page/BuildingPage';
|
import { clickUpgradeButton } from '../Page/BuildingPage/BuildingPage';
|
||||||
import { aroundMinutes } from '../utils';
|
import { aroundMinutes } from '../utils';
|
||||||
import { Args } from '../Queue/Args';
|
import { Args } from '../Queue/Args';
|
||||||
import { Task } from '../Queue/TaskProvider';
|
import { Task } from '../Queue/TaskProvider';
|
||||||
@ -8,9 +8,8 @@ import { Task } from '../Queue/TaskProvider';
|
|||||||
@registerAction
|
@registerAction
|
||||||
export class UpgradeBuildingAction extends ActionController {
|
export class UpgradeBuildingAction extends ActionController {
|
||||||
async run(args: Args, task: Task): Promise<any> {
|
async run(args: Args, task: Task): Promise<any> {
|
||||||
this.ensureSameVillage(args, task);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
this.ensureSameVillage(args, task);
|
||||||
clickUpgradeButton();
|
clickUpgradeButton();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof GrabError) {
|
if (e instanceof GrabError) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
export const WAREHOUSE_ID = 10;
|
export const WAREHOUSE_ID = 10;
|
||||||
export const GARNER_ID = 11;
|
export const GARNER_ID = 11;
|
||||||
|
export const FORGE_ID = 13;
|
||||||
export const COLLECTION_POINT_ID = 16;
|
export const COLLECTION_POINT_ID = 16;
|
||||||
export const MARKET_ID = 17;
|
export const MARKET_ID = 17;
|
||||||
export const QUARTERS_ID = 19;
|
export const QUARTERS_ID = 19;
|
||||||
|
@ -125,13 +125,13 @@ export class Executor {
|
|||||||
this.scheduler.clearActions();
|
this.scheduler.clearActions();
|
||||||
|
|
||||||
if (err instanceof AbortTaskError) {
|
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);
|
this.scheduler.removeTask(task.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err instanceof TryLaterError) {
|
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);
|
this.scheduler.postponeTask(task.id, err.seconds);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Grabber } from './Grabber';
|
import { Grabber } from './Grabber';
|
||||||
import { grabActiveVillageId } from '../Page/VillageBlock';
|
import { grabActiveVillageId } from '../Page/VillageBlock';
|
||||||
import { VillageStorage } from '../Storage/VillageStorage';
|
import { VillageStorage } from '../Storage/VillageStorage';
|
||||||
import { grabIncomingMerchants } from '../Page/BuildingPage';
|
|
||||||
import { isMarketSendResourcesPage } from '../Page/PageDetectors';
|
import { isMarketSendResourcesPage } from '../Page/PageDetectors';
|
||||||
|
import { grabIncomingMerchants } from '../Page/BuildingPage/MarketPage';
|
||||||
|
|
||||||
export class MarketPageGrabber extends Grabber {
|
export class MarketPageGrabber extends Grabber {
|
||||||
grab(): void {
|
grab(): void {
|
||||||
|
@ -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(`<div style="padding: 8px"><a id="${btnId}" href="#">Построить</a></div>`);
|
|
||||||
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 = `<div style="padding: 8px"><a id="${id}" href="#">В очередь</a></div>`;
|
|
||||||
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(`<div style="padding: 8px 0"><a id="${id}" href="#">Обучить</a></div>`);
|
|
||||||
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(`<div style="padding: 8px">
|
|
||||||
<a id="${id1}" href="#">Отправить</a> /
|
|
||||||
<a id="${id10}" href="#">x10</a> /
|
|
||||||
<a id="${id100}" href="#">x100</a> /
|
|
||||||
<a id="${id1000}" href="#">x1000</a>
|
|
||||||
</div>`);
|
|
||||||
|
|
||||||
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<IncomingMerchant> {
|
|
||||||
const result: Array<IncomingMerchant> = [];
|
|
||||||
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;
|
|
||||||
}
|
|
71
src/Page/BuildingPage/BuildingPage.ts
Normal file
71
src/Page/BuildingPage/BuildingPage.ts
Normal file
@ -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(`<div style="padding: 8px"><a id="${btnId}" href="#">Построить</a></div>`);
|
||||||
|
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 = `<div style="padding: 8px"><a id="${id}" href="#">В очередь</a></div>`;
|
||||||
|
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);
|
||||||
|
}
|
59
src/Page/BuildingPage/ForgePage.ts
Normal file
59
src/Page/BuildingPage/ForgePage.ts
Normal file
@ -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(`<div style="padding: 8px">
|
||||||
|
<a id="${id}" href="#">Исследовать</a>
|
||||||
|
</div>`);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
76
src/Page/BuildingPage/MarketPage.ts
Normal file
76
src/Page/BuildingPage/MarketPage.ts
Normal file
@ -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(`<div style="padding: 8px">
|
||||||
|
<a id="${id1}" href="#">Отправить</a> /
|
||||||
|
<a id="${id10}" href="#">x10</a> /
|
||||||
|
<a id="${id100}" href="#">x100</a> /
|
||||||
|
<a id="${id1000}" href="#">x1000</a>
|
||||||
|
</div>`);
|
||||||
|
|
||||||
|
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<IncomingMerchant> {
|
||||||
|
const result: Array<IncomingMerchant> = [];
|
||||||
|
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;
|
||||||
|
}
|
32
src/Page/BuildingPage/TrooperPage.ts
Normal file
32
src/Page/BuildingPage/TrooperPage.ts
Normal file
@ -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(`<div style="padding: 8px 0"><a id="${id}" href="#">Обучить</a></div>`);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -4,18 +4,17 @@ import { Scheduler } from '../Scheduler';
|
|||||||
import { TrainTroopTask } from '../Task/TrainTroopTask';
|
import { TrainTroopTask } from '../Task/TrainTroopTask';
|
||||||
import { grabActiveVillageId, grabVillageList } from './VillageBlock';
|
import { grabActiveVillageId, grabVillageList } from './VillageBlock';
|
||||||
import { ConsoleLogger, Logger } from '../Logger';
|
import { ConsoleLogger, Logger } from '../Logger';
|
||||||
import {
|
import { createBuildButton, createUpgradeButton } from './BuildingPage/BuildingPage';
|
||||||
createBuildButton,
|
|
||||||
createSendResourcesButton,
|
|
||||||
createTrainTroopButtons,
|
|
||||||
createUpgradeButton,
|
|
||||||
} from './BuildingPage';
|
|
||||||
import { BuildBuildingTask } from '../Task/BuildBuildingTask';
|
import { BuildBuildingTask } from '../Task/BuildBuildingTask';
|
||||||
import { Resources } from '../Core/Resources';
|
import { Resources } from '../Core/Resources';
|
||||||
import { Coordinates } from '../Core/Village';
|
import { Coordinates } from '../Core/Village';
|
||||||
import { SendResourcesTask } from '../Task/SendResourcesTask';
|
import { SendResourcesTask } from '../Task/SendResourcesTask';
|
||||||
import { EMBASSY_ID, HORSE_STABLE_ID, QUARTERS_ID } from '../Core/Buildings';
|
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 {
|
export class BuildingPageController {
|
||||||
private scheduler: Scheduler;
|
private scheduler: Scheduler;
|
||||||
@ -53,6 +52,10 @@ export class BuildingPageController {
|
|||||||
if (isMarketSendResourcesPage()) {
|
if (isMarketSendResourcesPage()) {
|
||||||
createSendResourcesButton((res, crd, scale) => this.onSendResources(res, crd, scale));
|
createSendResourcesButton((res, crd, scale) => this.onSendResources(res, crd, scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isForgePage()) {
|
||||||
|
createResearchButtons((res, unitId) => this.onResearch(res, unitId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onScheduleBuildBuilding(buildTypeId: number, resources: Resources) {
|
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)}`);
|
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`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { elClassId, getNumber, parseLocation } from '../utils';
|
import { elClassId, getNumber, parseLocation } from '../utils';
|
||||||
import { MARKET_ID } from '../Core/Buildings';
|
import { FORGE_ID, MARKET_ID } from '../Core/Buildings';
|
||||||
|
|
||||||
export interface BuildingPageAttributes {
|
export interface BuildingPageAttributes {
|
||||||
buildId: number;
|
buildId: number;
|
||||||
@ -40,3 +40,11 @@ export function isMarketSendResourcesPage(): boolean {
|
|||||||
const { buildTypeId, tabId } = getBuildingPageAttributes();
|
const { buildTypeId, tabId } = getBuildingPageAttributes();
|
||||||
return buildTypeId === MARKET_ID && tabId === 5;
|
return buildTypeId === MARKET_ID && tabId === 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isForgePage(): boolean {
|
||||||
|
if (!isBuildingPage()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const { buildTypeId } = getBuildingPageAttributes();
|
||||||
|
return buildTypeId === FORGE_ID;
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@ export interface Args {
|
|||||||
trainCount?: number;
|
trainCount?: number;
|
||||||
resources?: ResourcesInterface;
|
resources?: ResourcesInterface;
|
||||||
coordinates?: CoordinatesInterface;
|
coordinates?: CoordinatesInterface;
|
||||||
|
unitId?: number;
|
||||||
level?: number;
|
level?: number;
|
||||||
selector?: string;
|
selector?: string;
|
||||||
path?: string;
|
path?: string;
|
||||||
|
24
src/Task/ResearchTask.ts
Normal file
24
src/Task/ResearchTask.ts
Normal file
@ -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<ActionDefinition> {
|
||||||
|
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]];
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,7 @@
|
|||||||
import { TaskController, registerTask, ActionDefinition } from './TaskController';
|
import { TaskController, registerTask, ActionDefinition } from './TaskController';
|
||||||
import { GoToPageAction } from '../Action/GoToPageAction';
|
import { GoToPageAction } from '../Action/GoToPageAction';
|
||||||
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
|
|
||||||
import { path } from '../utils';
|
import { path } from '../utils';
|
||||||
import { UpgradeResourceToLevel } from '../Action/UpgradeResourceToLevel';
|
import { UpgradeResourceToLevel } from '../Action/UpgradeResourceToLevel';
|
||||||
import { Action } from '../Queue/ActionQueue';
|
|
||||||
import { Args } from '../Queue/Args';
|
|
||||||
import { Task } from '../Queue/TaskProvider';
|
import { Task } from '../Queue/TaskProvider';
|
||||||
|
|
||||||
@registerTask
|
@registerTask
|
||||||
@ -12,7 +9,7 @@ export class ResourcesToLevel extends TaskController {
|
|||||||
defineActions(task: Task): Array<ActionDefinition> {
|
defineActions(task: Task): Array<ActionDefinition> {
|
||||||
return [
|
return [
|
||||||
[GoToPageAction.name, { path: path('/dorf1.php', { newdid: task.args.villageId }) }],
|
[GoToPageAction.name, { path: path('/dorf1.php', { newdid: task.args.villageId }) }],
|
||||||
[UpgradeResourceToLevel.name, {}],
|
[UpgradeResourceToLevel.name],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,9 @@ export class SendResourcesTask extends TaskController {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
[GoToPageAction.name, { path: pagePath }],
|
[GoToPageAction.name, { path: pagePath }],
|
||||||
[SendResourcesAction.name, {}],
|
[SendResourcesAction.name],
|
||||||
[ClickButtonAction.name, { selector: '#enabledButton.green.sendRessources' }],
|
[ClickButtonAction.name, { selector: '#enabledButton.green.sendRessources' }],
|
||||||
[CompleteTaskAction.name, {}],
|
[CompleteTaskAction.name],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ export function createTaskHandler(name: string, scheduler: Scheduler): TaskContr
|
|||||||
return new constructor(scheduler);
|
return new constructor(scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ActionDefinition = [string, Args];
|
export type ActionDefinition = [string] | [string, Args];
|
||||||
|
|
||||||
export class TaskController {
|
export class TaskController {
|
||||||
protected scheduler: Scheduler;
|
protected scheduler: Scheduler;
|
||||||
@ -41,7 +41,11 @@ export class TaskController {
|
|||||||
const args: Args = { ...task.args, taskId: task.id };
|
const args: Args = { ...task.args, taskId: task.id };
|
||||||
const commands: Array<Action> = [];
|
const commands: Array<Action> = [];
|
||||||
for (let def of this.defineActions(task)) {
|
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));
|
commands.push(new Action(CompleteTaskAction.name, args));
|
||||||
return commands;
|
return commands;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { TaskController, registerTask } from './TaskController';
|
import { registerTask, TaskController } from './TaskController';
|
||||||
import { GoToPageAction } from '../Action/GoToPageAction';
|
import { GoToPageAction } from '../Action/GoToPageAction';
|
||||||
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
|
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
|
||||||
import { TrainTrooperAction } from '../Action/TrainTrooperAction';
|
import { TrainTrooperAction } from '../Action/TrainTrooperAction';
|
||||||
@ -19,10 +19,8 @@ export class TrainTroopTask extends TaskController {
|
|||||||
s: args.sheetId,
|
s: args.sheetId,
|
||||||
};
|
};
|
||||||
|
|
||||||
const pagePath = path('/build.php', pathArgs);
|
|
||||||
|
|
||||||
this.scheduler.scheduleActions([
|
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(TrainTrooperAction.name, args),
|
||||||
new Action(CompleteTaskAction.name, args),
|
new Action(CompleteTaskAction.name, args),
|
||||||
]);
|
]);
|
||||||
|
Loading…
Reference in New Issue
Block a user