Rewrite hero resource action
try to detect hero village before balancing
This commit is contained in:
parent
8e8b358b91
commit
2d9c3f94e7
@ -1,71 +1,30 @@
|
||||
import { ActionController, registerAction } from './ActionController';
|
||||
import { Args } from '../Common';
|
||||
import { Task } from '../Storage/TaskQueue';
|
||||
import { getNumber, trimPrefix } from '../utils';
|
||||
import { AbortTaskError, ActionError } from '../Errors';
|
||||
|
||||
interface Resource {
|
||||
type: number;
|
||||
value: number;
|
||||
}
|
||||
|
||||
const ALL = 0;
|
||||
import { grabResources } from '../Page/ResourcesBlock';
|
||||
import { changeHeroResource, grabCurrentHeroResource } from '../Page/HeroPage';
|
||||
import { HeroAllResources } from '../Game';
|
||||
|
||||
@registerAction
|
||||
export class BalanceHeroResourcesAction extends ActionController {
|
||||
async run(args: Args, task: Task): Promise<any> {
|
||||
const res = this.getResources();
|
||||
const currentType = this.getCurrentHeroResource(task);
|
||||
console.log('RESOURCES', res);
|
||||
const resources = grabResources().asList();
|
||||
const currentType = grabCurrentHeroResource();
|
||||
|
||||
console.log('RESOURCES', resources);
|
||||
console.log('CURRENT TYPE', currentType);
|
||||
const sorted = res.sort((x, y) => x.value - y.value);
|
||||
|
||||
const sorted = resources.sort((x, y) => x.value - y.value);
|
||||
const min = sorted[0];
|
||||
const max = sorted[sorted.length - 1];
|
||||
const delta = max.value - min.value;
|
||||
const eps = max.value / 10;
|
||||
|
||||
console.log('MIN', min, 'MAX', max, 'DELTA', delta, 'EPS', eps);
|
||||
const resType = delta > eps ? min.type : ALL;
|
||||
|
||||
const resType = delta > eps ? min.type : HeroAllResources;
|
||||
if (resType !== currentType) {
|
||||
this.changeToHeroResource(task, resType);
|
||||
changeHeroResource(resType);
|
||||
}
|
||||
}
|
||||
|
||||
private getResources(): Array<Resource> {
|
||||
const res = this.state.get('resources');
|
||||
const resList: Array<Resource> = [];
|
||||
for (let r in res) {
|
||||
const type = getNumber(r);
|
||||
const value = getNumber(res[r]);
|
||||
resList.push({ type, value });
|
||||
}
|
||||
return resList;
|
||||
}
|
||||
|
||||
private getCurrentHeroResource(task: Task): number {
|
||||
for (let type of [0, 1, 2, 3, 4]) {
|
||||
const input = jQuery(`#resourceHero${type}`);
|
||||
if (input.length !== 1) {
|
||||
throw new ActionError(task.id, `Hero resource ${type} not found`);
|
||||
}
|
||||
if (input.prop('checked')) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private changeToHeroResource(task: Task, type: number) {
|
||||
const input = jQuery(`#resourceHero${type}`);
|
||||
if (input.length !== 1) {
|
||||
throw new ActionError(task.id, `Hero resource ${type} not found`);
|
||||
}
|
||||
|
||||
const btn = jQuery('#saveHeroAttributes');
|
||||
if (btn.length !== 1) {
|
||||
throw new ActionError(task.id, `Hero resource button not found`);
|
||||
}
|
||||
|
||||
input.trigger('click');
|
||||
btn.trigger('click');
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { ActionController, registerAction } from './ActionController';
|
||||
import { Args } from '../Common';
|
||||
import { Task } from '../Storage/TaskQueue';
|
||||
import { BuildingQueueFullError } from '../Errors';
|
||||
import { grabActiveVillageId } from '../Page/EveryPage';
|
||||
import { grabActiveVillageId } from '../Page/VillageBlock';
|
||||
|
||||
@registerAction
|
||||
export class CheckBuildingRemainingTimeAction extends ActionController {
|
||||
|
32
src/Action/GoToHeroVillageAction.ts
Normal file
32
src/Action/GoToHeroVillageAction.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { ActionController, registerAction } from './ActionController';
|
||||
import { Args } from '../Common';
|
||||
import { Task } from '../Storage/TaskQueue';
|
||||
import { grabVillageList } from '../Page/VillageBlock';
|
||||
import { grabHeroVillage } from '../Page/HeroPage';
|
||||
import { path } from '../utils';
|
||||
|
||||
@registerAction
|
||||
export class GoToHeroVillageAction extends ActionController {
|
||||
async run(args: Args, task: Task): Promise<any> {
|
||||
const heroVillageId = this.getHeroVillageId();
|
||||
if (heroVillageId) {
|
||||
window.location.assign(path('/hero.php', { newdid: heroVillageId }));
|
||||
}
|
||||
}
|
||||
|
||||
private getHeroVillageId(): number | undefined {
|
||||
const villages = grabVillageList();
|
||||
const heroVillage = grabHeroVillage();
|
||||
|
||||
console.log('VILLAGES', villages);
|
||||
console.log('HERO VILLAGE', heroVillage);
|
||||
|
||||
for (let village of villages) {
|
||||
if (village.name === heroVillage) {
|
||||
return village.id;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
@ -3,13 +3,11 @@ import { markPage, waitForLoad } from '../utils';
|
||||
import { Scheduler } from '../Scheduler';
|
||||
import { TaskQueueRenderer } from '../TaskQueueRenderer';
|
||||
import { BuildPage } from '../Page/BuildPage';
|
||||
import {
|
||||
grabActiveVillageId,
|
||||
onResourceSlotCtrlClick,
|
||||
showBuildingSlotIds,
|
||||
showFieldsSlotIds,
|
||||
} from '../Page/EveryPage';
|
||||
|
||||
import { UpgradeBuildingTask } from '../Task/UpgradeBuildingTask';
|
||||
import { grabResources } from '../Page/ResourcesBlock';
|
||||
import { grabActiveVillageId, grabVillageList } from '../Page/VillageBlock';
|
||||
import { onResourceSlotCtrlClick, showBuildingSlotIds, showFieldsSlotIds } from '../Page/SlotBlock';
|
||||
|
||||
export class Dashboard {
|
||||
private readonly version: string;
|
||||
@ -30,6 +28,12 @@ export class Dashboard {
|
||||
this.renderTaskQueue();
|
||||
setInterval(() => this.renderTaskQueue(), 5000);
|
||||
|
||||
const res = grabResources();
|
||||
this.log('RES', res);
|
||||
|
||||
const villages = grabVillageList();
|
||||
this.log('VILL', villages);
|
||||
|
||||
const villageId = grabActiveVillageId();
|
||||
|
||||
const tasks = this.scheduler.getTaskItems();
|
||||
|
@ -1,5 +1,12 @@
|
||||
import { TaskId } from './Storage/TaskQueue';
|
||||
|
||||
export class GrabError extends Error {
|
||||
constructor(msg: string = '') {
|
||||
super(msg);
|
||||
Object.setPrototypeOf(this, GrabError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
export class ActionError extends Error {
|
||||
readonly taskId: TaskId;
|
||||
constructor(taskId: TaskId, msg: string = '') {
|
||||
|
82
src/Game.ts
Normal file
82
src/Game.ts
Normal file
@ -0,0 +1,82 @@
|
||||
export enum ResourceType {
|
||||
Lumber = 1,
|
||||
Clay = 2,
|
||||
Iron = 3,
|
||||
Crop = 4,
|
||||
}
|
||||
|
||||
export const ResourceMapping: ReadonlyArray<{ num: number; type: ResourceType }> = [
|
||||
{ num: 1, type: ResourceType.Lumber },
|
||||
{ num: 2, type: ResourceType.Clay },
|
||||
{ num: 3, type: ResourceType.Iron },
|
||||
{ num: 4, type: ResourceType.Crop },
|
||||
];
|
||||
|
||||
export type ResourceList = Array<{ num: number; type: ResourceType; value: number }>;
|
||||
|
||||
export class Resources {
|
||||
readonly lumber: number;
|
||||
readonly clay: number;
|
||||
readonly iron: number;
|
||||
readonly crop: number;
|
||||
readonly warehouse: number;
|
||||
readonly granary: number;
|
||||
constructor(lumber: number, clay: number, iron: number, crop: number, warehouse: number, granary: number) {
|
||||
this.lumber = lumber;
|
||||
this.clay = clay;
|
||||
this.iron = iron;
|
||||
this.crop = crop;
|
||||
this.warehouse = warehouse;
|
||||
this.granary = granary;
|
||||
}
|
||||
|
||||
getByType(type: ResourceType): number {
|
||||
switch (type) {
|
||||
case ResourceType.Lumber:
|
||||
return this.lumber;
|
||||
case ResourceType.Clay:
|
||||
return this.clay;
|
||||
case ResourceType.Iron:
|
||||
return this.iron;
|
||||
case ResourceType.Crop:
|
||||
return this.crop;
|
||||
}
|
||||
}
|
||||
|
||||
asList(): ResourceList {
|
||||
const result: ResourceList = [];
|
||||
for (let mp of ResourceMapping) {
|
||||
result.push({ num: mp.num, type: mp.type, value: this.getByType(mp.type) });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export class Coordinates {
|
||||
readonly x: number;
|
||||
readonly y: number;
|
||||
constructor(x: number, y: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
export class Village {
|
||||
readonly id: number;
|
||||
readonly name: string;
|
||||
readonly active: boolean;
|
||||
readonly crd: Coordinates;
|
||||
constructor(id: number, name: string, active: boolean, crd: Coordinates) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.active = active;
|
||||
this.crd = crd;
|
||||
}
|
||||
}
|
||||
|
||||
export type VillageList = Array<Village>;
|
||||
|
||||
export type HeroAllResourcesType = 'all';
|
||||
export const HeroAllResources: HeroAllResourcesType = 'all';
|
||||
|
||||
export type HeroResourceType = ResourceType | HeroAllResourcesType;
|
@ -2,7 +2,7 @@ import { elClassId, split, uniqId } from '../utils';
|
||||
import { UpgradeBuildingTask } from '../Task/UpgradeBuildingTask';
|
||||
import { Scheduler } from '../Scheduler';
|
||||
import { TrainTroopTask } from '../Task/TrainTroopTask';
|
||||
import { grabActiveVillageId } from './EveryPage';
|
||||
import { grabActiveVillageId } from './VillageBlock';
|
||||
|
||||
const QUARTERS_ID = 19;
|
||||
|
||||
|
52
src/Page/HeroPage.ts
Normal file
52
src/Page/HeroPage.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { GrabError } from '../Errors';
|
||||
import { HeroAllResources, HeroResourceType, ResourceMapping, ResourceType } from '../Game';
|
||||
|
||||
export function grabCurrentHeroResource(): HeroResourceType {
|
||||
for (let mp of ResourceMapping) {
|
||||
if (checkHeroResourceType(mp.num)) {
|
||||
return mp.type;
|
||||
}
|
||||
}
|
||||
return HeroAllResources;
|
||||
}
|
||||
|
||||
function checkHeroResourceType(typeAsNumber: number): boolean {
|
||||
const input = jQuery(`#resourceHero${typeAsNumber}`);
|
||||
if (input.length !== 1) {
|
||||
throw new GrabError(`Hero resource ${typeAsNumber} not found`);
|
||||
}
|
||||
return !!input.prop('checked');
|
||||
}
|
||||
|
||||
export function changeHeroResource(type: HeroResourceType) {
|
||||
const typeAsNumber = heroResourceTypeToNumber(type);
|
||||
const input = jQuery(`#resourceHero${typeAsNumber}`);
|
||||
if (input.length !== 1) {
|
||||
throw new GrabError(`Hero resource ${typeAsNumber} not found`);
|
||||
}
|
||||
|
||||
const btn = jQuery('#saveHeroAttributes');
|
||||
if (btn.length !== 1) {
|
||||
throw new GrabError(`Hero resource button not found`);
|
||||
}
|
||||
|
||||
input.trigger('click');
|
||||
btn.trigger('click');
|
||||
}
|
||||
|
||||
function heroResourceTypeToNumber(type: HeroResourceType): number {
|
||||
if (type === HeroAllResources) {
|
||||
return 0;
|
||||
}
|
||||
return type as ResourceType;
|
||||
}
|
||||
|
||||
export function grabHeroVillage(): string | undefined {
|
||||
const status = jQuery('.heroStatusMessage').text();
|
||||
const hrefText = jQuery('.heroStatusMessage a').text();
|
||||
if (status.includes('в родной деревне')) {
|
||||
return hrefText || undefined;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
39
src/Page/ResourcesBlock.ts
Normal file
39
src/Page/ResourcesBlock.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { Resources, ResourceType } from '../Game';
|
||||
import { GrabError } from '../Errors';
|
||||
import { getNumber } from '../utils';
|
||||
|
||||
export function grabResources(): Resources {
|
||||
const lumber = grabResource(ResourceType.Lumber);
|
||||
const clay = grabResource(ResourceType.Clay);
|
||||
const iron = grabResource(ResourceType.Iron);
|
||||
const crop = grabResource(ResourceType.Crop);
|
||||
|
||||
const warehouse = grabCapacity('warehouse');
|
||||
const granary = grabCapacity('granary');
|
||||
|
||||
return new Resources(lumber, clay, iron, crop, warehouse, granary);
|
||||
}
|
||||
|
||||
function findStockBarElement() {
|
||||
const stockBarElement = jQuery('#stockBar');
|
||||
if (stockBarElement.length !== 1) {
|
||||
throw new GrabError('Stock Bar not found');
|
||||
}
|
||||
return stockBarElement;
|
||||
}
|
||||
|
||||
function grabResource(type: number): number {
|
||||
const resElement = findStockBarElement().find(`#l${type}`);
|
||||
if (resElement.length !== 1) {
|
||||
throw new GrabError(`Resource #${type} not found`);
|
||||
}
|
||||
return getNumber(resElement.text().replace(/[^0-9]/g, ''));
|
||||
}
|
||||
|
||||
function grabCapacity(type: string): number {
|
||||
const capacityElement = findStockBarElement().find(`.${type} .capacity .value`);
|
||||
if (capacityElement.length !== 1) {
|
||||
throw new GrabError(`Capacity #${type} not found`);
|
||||
}
|
||||
return getNumber(capacityElement.text().replace(/[^0-9]/g, ''));
|
||||
}
|
@ -1,13 +1,5 @@
|
||||
import * as URLParse from 'url-parse';
|
||||
import { elClassId, getNumber } from '../utils';
|
||||
|
||||
export function grabActiveVillageId(): number {
|
||||
const href = jQuery('#sidebarBoxVillagelist a.active').attr('href');
|
||||
const p = new URLParse(href || '', true);
|
||||
console.log('VILLAGE REF', href, p);
|
||||
return getNumber(p.query.newdid);
|
||||
}
|
||||
|
||||
interface Slot {
|
||||
el: HTMLElement;
|
||||
buildId: number;
|
40
src/Page/VillageBlock.ts
Normal file
40
src/Page/VillageBlock.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { Coordinates, Village, VillageList } from '../Game';
|
||||
import { GrabError } from '../Errors';
|
||||
import * as URLParse from 'url-parse';
|
||||
import { getNumber } from '../utils';
|
||||
|
||||
export function grabVillageList(): VillageList {
|
||||
const villageList: VillageList = [];
|
||||
const $elements = getVillageListItems();
|
||||
$elements.each((idx, el) => {
|
||||
villageList.push(grabVillageInfo(jQuery(el)));
|
||||
});
|
||||
return villageList;
|
||||
}
|
||||
|
||||
export function grabActiveVillageId(): number {
|
||||
const villageList = grabVillageList();
|
||||
for (let village of villageList) {
|
||||
if (village.active) {
|
||||
return village.id;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getVillageListItems() {
|
||||
const $elements = jQuery('#sidebarBoxVillagelist ul li a');
|
||||
if ($elements.length === 0) {
|
||||
throw new GrabError('Village list items not found');
|
||||
}
|
||||
return $elements;
|
||||
}
|
||||
|
||||
function grabVillageInfo($el): Village {
|
||||
const href = $el.attr('href');
|
||||
const parsedHref = new URLParse(href || '', true);
|
||||
const id = getNumber(parsedHref.query.newdid);
|
||||
const name = $el.find('.name').text();
|
||||
const active = $el.hasClass('active');
|
||||
return new Village(id, name, active, new Coordinates(0, 0));
|
||||
}
|
@ -3,24 +3,20 @@ import { Task } from '../Storage/TaskQueue';
|
||||
import { TaskController, registerTask } from './TaskController';
|
||||
import { GoToPageAction } from '../Action/GoToPageAction';
|
||||
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
|
||||
import { GrabVillageResourcesAction } from '../Action/GrabVillageResourcesAction';
|
||||
import { BalanceHeroResourcesAction } from '../Action/BalanceHeroResourcesAction';
|
||||
import { path } from '../utils';
|
||||
import { GoToHeroVillageAction } from '../Action/GoToHeroVillageAction';
|
||||
|
||||
@registerTask
|
||||
export class BalanceHeroResourcesTask extends TaskController {
|
||||
async run(task: Task) {
|
||||
const args: Args = { ...task.args, taskId: task.id };
|
||||
this.scheduler.scheduleActions([
|
||||
new Command(GoToPageAction.name, {
|
||||
...args,
|
||||
path: path('/dorf1.php'),
|
||||
}),
|
||||
new Command(GrabVillageResourcesAction.name, args),
|
||||
new Command(GoToPageAction.name, {
|
||||
...args,
|
||||
path: path('/hero.php'),
|
||||
}),
|
||||
new Command(GoToHeroVillageAction.name, args),
|
||||
new Command(BalanceHeroResourcesAction.name, args),
|
||||
new Command(CompleteTaskAction.name, args),
|
||||
]);
|
||||
|
Loading…
Reference in New Issue
Block a user