Add hero resource switch

This commit is contained in:
Anton Vakhrushev 2020-04-04 15:41:18 +03:00
parent 6e85f9f443
commit d85490958b
8 changed files with 151 additions and 13 deletions

View File

@ -1,12 +1,13 @@
# Travian automation # Travian automation
- [ ] Автоматическая отправка набегов на учетные записи или автоматическая отправка волн атак
- [x] Автоматическая отправка героя в приключение
- [x] Автоматическое начало строительства зданий и/или ресурсных полей - [x] Автоматическое начало строительства зданий и/или ресурсных полей
- [ ] Автоматический скан карты
- [ ] Автоматический скан статистики других игроков
- [ ] Автоматическая отправка ресурсов на другие учетные записи
- [x] Автоматическое обучение войск - [x] Автоматическое обучение войск
- [x] Автоматическая отправка героя в приключение
- [x] Автоматическое переключение ресурсов героя
- [ ] Автоматическая отправка набегов на учетные записи или автоматическая отправка волн атак
- [ ] Автоматический скан карты
- [ ] Автоматическая отправка ресурсов на другие учетные записи
- [ ] Автоматическое размещение ставок на аукционе - [ ] Автоматическое размещение ставок на аукционе
- [ ] Автоматический запуск празднований - [ ] Автоматический запуск празднований
- [ ] Сканирование статистики других игроков
- [ ] Сканирование собственных деревень для отображения ресурсов и информации в одном месте - [ ] Сканирование собственных деревень для отображения ресурсов и информации в одном месте

View File

@ -0,0 +1,71 @@
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;
@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);
console.log('CURRENT TYPE', currentType);
const sorted = res.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;
if (resType !== currentType) {
this.changeToHeroResource(task, 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');
}
}

View File

@ -2,6 +2,7 @@ import { ActionController, registerAction } from './ActionController';
import { Args } from '../Common'; import { Args } from '../Common';
import { Task } from '../Storage/TaskQueue'; import { Task } from '../Storage/TaskQueue';
import { ActionError } from '../Errors'; import { ActionError } from '../Errors';
import { getNumber } from '../utils';
@registerAction @registerAction
export class GrabHeroAttributesAction extends ActionController { export class GrabHeroAttributesAction extends ActionController {
@ -10,13 +11,11 @@ export class GrabHeroAttributesAction extends ActionController {
if (healthElement.length !== 1) { if (healthElement.length !== 1) {
throw new ActionError(task.id, 'Health dom element not found'); throw new ActionError(task.id, 'Health dom element not found');
} }
const text = healthElement.text(); const text = healthElement.text();
let normalized = text.replace(/[^0-9]/g, ''); let normalized = text.replace(/[^0-9]/g, '');
const value = Number(normalized);
if (isNaN(value)) {
throw new ActionError(task.id, `Health value "${text}" (${normalized}) couldn't be converted to number`);
}
const value = getNumber(normalized);
this.state.set('hero', { health: value }); this.state.set('hero', { health: value });
} }
} }

View File

@ -0,0 +1,36 @@
import { ActionController, registerAction } from './ActionController';
import { Args } from '../Common';
import { Task } from '../Storage/TaskQueue';
import { getNumber } from '../utils';
import { ActionError } from '../Errors';
const LUMBER = 1;
const CLAY = 2;
const IRON = 3;
const CROP = 4;
@registerAction
export class GrabVillageResourcesAction extends ActionController {
async run(args: Args, task: Task): Promise<any> {
const lumber = this.grabResource(task, LUMBER);
const clay = this.grabResource(task, CLAY);
const iron = this.grabResource(task, IRON);
const crop = this.grabResource(task, CROP);
this.state.set('resources', { [LUMBER]: lumber, [CLAY]: clay, [IRON]: iron, [CROP]: crop });
}
private grabResource(task: Task, type: number): number {
const stockBarElement = jQuery('#stockBar');
if (stockBarElement.length !== 1) {
throw new ActionError(task.id, 'Stock Bar not found');
}
const resElement = stockBarElement.find(`#l${type}`);
if (resElement.length !== 1) {
throw new ActionError(task.id, `Resource #${type} not found`);
}
return getNumber(resElement.text().replace(/[^0-9]/g, ''));
}
}

View File

@ -22,7 +22,7 @@ export class TrainTrooperAction extends ActionController {
const maxCount = getNumber(countLink.text()); const maxCount = getNumber(countLink.text());
if (maxCount < trainCount) { if (maxCount < trainCount) {
throw new TryLaterError(task.id, 10 * 60, `Max count ${maxCount} less then need ${trainCount}`); throw new TryLaterError(task.id, 20 * 60, `Max count ${maxCount} less then need ${trainCount}`);
} }
const input = block.find(`input[name="t${troopId}"]`); const input = block.find(`input[name="t${troopId}"]`);

View File

@ -9,6 +9,7 @@ import { createAction } from './Action/ActionController';
import { createTask } from './Task/TaskController'; import { createTask } from './Task/TaskController';
import { SendOnAdventureTask } from './Task/SendOnAdventureTask'; import { SendOnAdventureTask } from './Task/SendOnAdventureTask';
import { GameState } from './Storage/GameState'; import { GameState } from './Storage/GameState';
import { BalanceHeroResourcesTask } from './Task/BalanceHeroResourcesTask';
export class Scheduler { export class Scheduler {
private readonly version: string; private readonly version: string;
@ -33,8 +34,11 @@ export class Scheduler {
this.scheduleHeroAdventure(); this.scheduleHeroAdventure();
setInterval(() => this.scheduleHeroAdventure(), 3600 * 1000); setInterval(() => this.scheduleHeroAdventure(), 3600 * 1000);
this.scheduleResGrab();
setInterval(() => this.scheduleResGrab(), 600 * 1000);
while (true) { while (true) {
await this.doLoopStep(); await this.doTaskProcessingStep();
} }
} }
@ -49,7 +53,13 @@ export class Scheduler {
} }
} }
private async doLoopStep() { private scheduleResGrab() {
if (!this.taskQueue.hasNamed(BalanceHeroResourcesTask.name)) {
this.taskQueue.push(new Command(BalanceHeroResourcesTask.name, {}), timestamp());
}
}
private async doTaskProcessingStep() {
await sleepShort(); await sleepShort();
const currentTs = timestamp(); const currentTs = timestamp();
const taskCommand = this.taskQueue.get(currentTs); const taskCommand = this.taskQueue.get(currentTs);

View File

@ -0,0 +1,22 @@
import { Args, Command } from '../Common';
import { Task } from '../Storage/TaskQueue';
import { TaskController, registerTask } from './TaskController';
import { GoToPageAction } from '../Action/GoToPageAction';
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
import { TrainTrooperAction } from '../Action/TrainTrooperAction';
import { GrabVillageResourcesAction } from '../Action/GrabVillageResourcesAction';
import { BalanceHeroResourcesAction } from '../Action/BalanceHeroResourcesAction';
@registerTask
export class BalanceHeroResourcesTask extends TaskController {
async run(task: Task) {
const args: Args = { ...task.cmd.args, taskId: task.id };
this.scheduler.scheduleActions([
new Command(GoToPageAction.name, { ...args, path: '/dorf1.php' }),
new Command(GrabVillageResourcesAction.name, args),
new Command(GoToPageAction.name, { ...args, path: 'hero.php' }),
new Command(BalanceHeroResourcesAction.name, args),
new Command(CompleteTaskAction.name, args),
]);
}
}

View File

@ -4,7 +4,6 @@ import { Scheduler } from '../Scheduler';
const taskMap: { [name: string]: Function | undefined } = {}; const taskMap: { [name: string]: Function | undefined } = {};
export function registerTask(constructor: Function) { export function registerTask(constructor: Function) {
console.log('REGISTER TASK', constructor.name);
taskMap[constructor.name] = constructor; taskMap[constructor.name] = constructor;
} }