Add hero resource switch
This commit is contained in:
		
							
								
								
									
										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; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user