Add hero resource switch
This commit is contained in:
parent
6e85f9f443
commit
d85490958b
11
README.md
11
README.md
@ -1,12 +1,13 @@
|
|||||||
# Travian automation
|
# Travian automation
|
||||||
|
|
||||||
- [ ] Автоматическая отправка набегов на учетные записи или автоматическая отправка волн атак
|
|
||||||
- [x] Автоматическая отправка героя в приключение
|
|
||||||
- [x] Автоматическое начало строительства зданий и/или ресурсных полей
|
- [x] Автоматическое начало строительства зданий и/или ресурсных полей
|
||||||
- [ ] Автоматический скан карты
|
|
||||||
- [ ] Автоматический скан статистики других игроков
|
|
||||||
- [ ] Автоматическая отправка ресурсов на другие учетные записи
|
|
||||||
- [x] Автоматическое обучение войск
|
- [x] Автоматическое обучение войск
|
||||||
|
- [x] Автоматическая отправка героя в приключение
|
||||||
|
- [x] Автоматическое переключение ресурсов героя
|
||||||
|
- [ ] Автоматическая отправка набегов на учетные записи или автоматическая отправка волн атак
|
||||||
|
- [ ] Автоматический скан карты
|
||||||
|
- [ ] Автоматическая отправка ресурсов на другие учетные записи
|
||||||
- [ ] Автоматическое размещение ставок на аукционе
|
- [ ] Автоматическое размещение ставок на аукционе
|
||||||
- [ ] Автоматический запуск празднований
|
- [ ] Автоматический запуск празднований
|
||||||
|
- [ ] Сканирование статистики других игроков
|
||||||
- [ ] Сканирование собственных деревень для отображения ресурсов и информации в одном месте
|
- [ ] Сканирование собственных деревень для отображения ресурсов и информации в одном месте
|
||||||
|
71
src/Action/BalanceHeroResourcesAction.ts
Normal file
71
src/Action/BalanceHeroResourcesAction.ts
Normal 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');
|
||||||
|
}
|
||||||
|
}
|
@ -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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
36
src/Action/GrabVillageResourcesAction.ts
Normal file
36
src/Action/GrabVillageResourcesAction.ts
Normal 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, ''));
|
||||||
|
}
|
||||||
|
}
|
@ -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}"]`);
|
||||||
|
@ -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);
|
||||||
|
22
src/Task/BalanceHeroResourcesTask.ts
Normal file
22
src/Task/BalanceHeroResourcesTask.ts
Normal 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),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user