Add hero adventures task
This commit is contained in:
		
							
								
								
									
										14
									
								
								src/Action/ClickButtonAction.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/Action/ClickButtonAction.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | import ActionController from './ActionController'; | ||||||
|  | import { Args } from '../Common'; | ||||||
|  | import { Task } from '../Storage/TaskQueue'; | ||||||
|  |  | ||||||
|  | export default class ClickButtonAction extends ActionController { | ||||||
|  |     static NAME = 'click_button'; | ||||||
|  |     async run(args: Args, task: Task): Promise<any> { | ||||||
|  |         const el = jQuery(args.selector); | ||||||
|  |         if (el.length === 1) { | ||||||
|  |             console.log('CLICK BUTTON', el); | ||||||
|  |             el.trigger('click'); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								src/Action/CompleteTaskAction.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/Action/CompleteTaskAction.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | import ActionController from './ActionController'; | ||||||
|  | import { Args } from '../Common'; | ||||||
|  | import { Task } from '../Storage/TaskQueue'; | ||||||
|  | import Scheduler from '../Scheduler'; | ||||||
|  |  | ||||||
|  | export default class CompleteTaskAction extends ActionController { | ||||||
|  |     static NAME = 'complete_task'; | ||||||
|  |     private scheduler: Scheduler; | ||||||
|  |  | ||||||
|  |     constructor(scheduler: Scheduler) { | ||||||
|  |         super(); | ||||||
|  |         this.scheduler = scheduler; | ||||||
|  |     } | ||||||
|  |     async run(args: Args, task: Task): Promise<any> { | ||||||
|  |         this.scheduler.completeTask(task.id); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								src/Action/GrabHeroAttributesAction.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/Action/GrabHeroAttributesAction.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | import ActionController from './ActionController'; | ||||||
|  | import { Args } from '../Common'; | ||||||
|  | import { Task } from '../Storage/TaskQueue'; | ||||||
|  | import { ActionError } from '../Errors'; | ||||||
|  | import { GameState } from '../Storage/GameState'; | ||||||
|  |  | ||||||
|  | export default class GrabHeroAttributesAction extends ActionController { | ||||||
|  |     static NAME = 'grab_hero_attributes'; | ||||||
|  |     private state: GameState; | ||||||
|  |  | ||||||
|  |     constructor(state: GameState) { | ||||||
|  |         super(); | ||||||
|  |         this.state = state; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async run(args: Args, task: Task): Promise<any> { | ||||||
|  |         const healthElement = jQuery( | ||||||
|  |             '#attributes .attribute.health .powervalue .value' | ||||||
|  |         ); | ||||||
|  |         if (healthElement.length !== 1) { | ||||||
|  |             throw new ActionError(task.id, 'Health dom element not found'); | ||||||
|  |         } | ||||||
|  |         const text = healthElement.text(); | ||||||
|  |         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` | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.state.set('hero', { health: value }); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										71
									
								
								src/Action/SendOnAdventureAction.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/Action/SendOnAdventureAction.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | |||||||
|  | import ActionController from './ActionController'; | ||||||
|  | import { Args } from '../Common'; | ||||||
|  | import { Task } from '../Storage/TaskQueue'; | ||||||
|  | import { GameState } from '../Storage/GameState'; | ||||||
|  | import { trimPrefix } from '../utils'; | ||||||
|  | import { AbortTaskError } from '../Errors'; | ||||||
|  |  | ||||||
|  | const HARD = 0; | ||||||
|  | const NORMAL = 3; | ||||||
|  |  | ||||||
|  | interface Adventure { | ||||||
|  |     el: HTMLElement; | ||||||
|  |     level: number; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default class SendOnAdventureAction extends ActionController { | ||||||
|  |     static NAME = 'send_on_adventure'; | ||||||
|  |     private state: GameState; | ||||||
|  |  | ||||||
|  |     constructor(state: GameState) { | ||||||
|  |         super(); | ||||||
|  |         this.state = state; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async run(args: Args, task: Task): Promise<any> { | ||||||
|  |         const adventures = this.findAdventures(); | ||||||
|  |  | ||||||
|  |         console.log('ADVENTURES', adventures); | ||||||
|  |  | ||||||
|  |         adventures.sort((x, y) => x.level - y.level); | ||||||
|  |  | ||||||
|  |         const easiest = adventures.shift(); | ||||||
|  |         const hero = this.state.get('hero') || {}; | ||||||
|  |  | ||||||
|  |         console.log('EASIEST', easiest); | ||||||
|  |         console.log('HERO', hero); | ||||||
|  |  | ||||||
|  |         if (easiest && hero.health) { | ||||||
|  |             if (easiest.level === NORMAL && hero.health >= 30) { | ||||||
|  |                 return jQuery(easiest.el) | ||||||
|  |                     .find('td.goTo .gotoAdventure') | ||||||
|  |                     .trigger('click'); | ||||||
|  |             } | ||||||
|  |             if (easiest.level === HARD && hero.health >= 50) { | ||||||
|  |                 return jQuery(easiest.el) | ||||||
|  |                     .find('td.goTo .gotoAdventure') | ||||||
|  |                     .trigger('click'); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         throw new AbortTaskError(task.id, 'No suitable adventure'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private findAdventures(): Array<Adventure> { | ||||||
|  |         const adventures: Array<Adventure> = []; | ||||||
|  |  | ||||||
|  |         jQuery('tr[id^=adventure]').each((index, el) => { | ||||||
|  |             const imgClass = | ||||||
|  |                 jQuery(el) | ||||||
|  |                     .find('.difficulty img') | ||||||
|  |                     .attr('class') | ||||||
|  |                     ?.toString() || ''; | ||||||
|  |             const level = Number(trimPrefix(imgClass, 'adventureDifficulty')); | ||||||
|  |             if (!isNaN(level)) { | ||||||
|  |                 adventures.push({ el, level: level }); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         return adventures; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -6,23 +6,15 @@ import { Task } from '../Storage/TaskQueue'; | |||||||
|  |  | ||||||
| export default class UpgradeBuildingAction extends ActionController { | export default class UpgradeBuildingAction extends ActionController { | ||||||
|     static NAME = 'upgrade_building'; |     static NAME = 'upgrade_building'; | ||||||
|     private scheduler: Scheduler; |  | ||||||
|  |  | ||||||
|     constructor(scheduler: Scheduler) { |  | ||||||
|         super(); |  | ||||||
|         this.scheduler = scheduler; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async run(args: Args, task: Task): Promise<any> { |     async run(args: Args, task: Task): Promise<any> { | ||||||
|         const btn = jQuery( |         const btn = jQuery( | ||||||
|             '.upgradeButtonsContainer .section1 button.green.build' |             '.upgradeButtonsContainer .section1 button.green.build' | ||||||
|         ); |         ); | ||||||
|         if (btn.length === 1) { |  | ||||||
|             this.scheduler.completeTask(task.id); |         if (btn.length !== 1) { | ||||||
|             btn.trigger('click'); |  | ||||||
|         } else { |  | ||||||
|             throw new TryLaterError(5 * 60, 'No upgrade button, try later'); |             throw new TryLaterError(5 * 60, 'No upgrade button, try later'); | ||||||
|         } |         } | ||||||
|         return null; |  | ||||||
|  |         btn.trigger('click'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| import * as URLParse from 'url-parse'; | import * as URLParse from 'url-parse'; | ||||||
| import { markPage, uniqId, waitForLoad } from './utils'; | import { markPage, trimPrefix, uniqId, waitForLoad } from './utils'; | ||||||
| import Scheduler from './Scheduler'; | import Scheduler from './Scheduler'; | ||||||
| import UpgradeBuildingTask from './Task/UpgradeBuildingTask'; | import UpgradeBuildingTask from './Task/UpgradeBuildingTask'; | ||||||
| import { Command } from './Common'; | import { Command } from './Common'; | ||||||
|   | |||||||
| @@ -1,5 +1,23 @@ | |||||||
| import { TaskId } from './Storage/TaskQueue'; | import { TaskId } from './Storage/TaskQueue'; | ||||||
|  |  | ||||||
|  | export class ActionError extends Error { | ||||||
|  |     readonly id: TaskId; | ||||||
|  |     constructor(id: TaskId, msg: string = '') { | ||||||
|  |         super(msg); | ||||||
|  |         this.id = id; | ||||||
|  |         Object.setPrototypeOf(this, ActionError.prototype); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class AbortTaskError extends Error { | ||||||
|  |     readonly id: TaskId; | ||||||
|  |     constructor(id: TaskId, msg: string = '') { | ||||||
|  |         super(msg); | ||||||
|  |         this.id = id; | ||||||
|  |         Object.setPrototypeOf(this, AbortTaskError.prototype); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| export class TryLaterError extends Error { | export class TryLaterError extends Error { | ||||||
|     readonly seconds: number; |     readonly seconds: number; | ||||||
|     readonly id: TaskId; |     readonly id: TaskId; | ||||||
| @@ -18,6 +36,6 @@ export class BuildingQueueFullError extends Error { | |||||||
|         super(msg); |         super(msg); | ||||||
|         this.id = id; |         this.id = id; | ||||||
|         this.seconds = seconds; |         this.seconds = seconds; | ||||||
|         Object.setPrototypeOf(this, TryLaterError.prototype); |         Object.setPrototypeOf(this, BuildingQueueFullError.prototype); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1 +0,0 @@ | |||||||
| export default class GameState {} |  | ||||||
| @@ -1,7 +1,11 @@ | |||||||
| import { markPage, sleepShort, timestamp } from './utils'; | import { markPage, sleepShort, timestamp } from './utils'; | ||||||
| import UpgradeBuildingTask from './Task/UpgradeBuildingTask'; | import UpgradeBuildingTask from './Task/UpgradeBuildingTask'; | ||||||
| import UpgradeBuildingAction from './Action/UpgradeBuildingAction'; | import UpgradeBuildingAction from './Action/UpgradeBuildingAction'; | ||||||
| import { BuildingQueueFullError, TryLaterError } from './Errors'; | import { | ||||||
|  |     AbortTaskError, | ||||||
|  |     BuildingQueueFullError, | ||||||
|  |     TryLaterError, | ||||||
|  | } from './Errors'; | ||||||
| import { TaskQueue, TaskList, Task, TaskId } from './Storage/TaskQueue'; | import { TaskQueue, TaskList, Task, TaskId } from './Storage/TaskQueue'; | ||||||
| import ActionQueue from './Storage/ActionQueue'; | import ActionQueue from './Storage/ActionQueue'; | ||||||
| import { Args, Command } from './Common'; | import { Args, Command } from './Common'; | ||||||
| @@ -10,16 +14,24 @@ import ActionController from './Action/ActionController'; | |||||||
| import TaskController from './Task/TaskController'; | import TaskController from './Task/TaskController'; | ||||||
| import GoToPageAction from './Action/GoToPageAction'; | import GoToPageAction from './Action/GoToPageAction'; | ||||||
| import CheckBuildingRemainingTimeAction from './Action/CheckBuildingRemainingTimeAction'; | import CheckBuildingRemainingTimeAction from './Action/CheckBuildingRemainingTimeAction'; | ||||||
|  | import SendOnAdventureTask from './Task/SendOnAdventureTask'; | ||||||
|  | import GrabHeroAttributesAction from './Action/GrabHeroAttributesAction'; | ||||||
|  | import { GameState } from './Storage/GameState'; | ||||||
|  | import CompleteTaskAction from './Action/CompleteTaskAction'; | ||||||
|  | import SendOnAdventureAction from './Action/SendOnAdventureAction'; | ||||||
|  | import ClickButtonAction from './Action/ClickButtonAction'; | ||||||
|  |  | ||||||
| export default class Scheduler { | export default class Scheduler { | ||||||
|     private readonly version: string; |     private readonly version: string; | ||||||
|     private taskQueue: TaskQueue; |     private taskQueue: TaskQueue; | ||||||
|     private actionQueue: ActionQueue; |     private actionQueue: ActionQueue; | ||||||
|  |     private gameState: GameState; | ||||||
|  |  | ||||||
|     constructor(version: string) { |     constructor(version: string) { | ||||||
|         this.version = version; |         this.version = version; | ||||||
|         this.taskQueue = new TaskQueue(); |         this.taskQueue = new TaskQueue(); | ||||||
|         this.actionQueue = new ActionQueue(); |         this.actionQueue = new ActionQueue(); | ||||||
|  |         this.gameState = new GameState(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async run() { |     async run() { | ||||||
| @@ -27,7 +39,10 @@ export default class Scheduler { | |||||||
|         markPage('Executor', this.version); |         markPage('Executor', this.version); | ||||||
|  |  | ||||||
|         this.renderTaskQueue(); |         this.renderTaskQueue(); | ||||||
|         setInterval(() => this.renderTaskQueue(), 5000); |         setInterval(() => this.renderTaskQueue(), 5 * 1000); | ||||||
|  |  | ||||||
|  |         this.scheduleHeroAdventure(); | ||||||
|  |         setInterval(() => this.scheduleHeroAdventure(), 3600 * 1000); | ||||||
|  |  | ||||||
|         while (true) { |         while (true) { | ||||||
|             await this.doLoopStep(); |             await this.doLoopStep(); | ||||||
| @@ -39,6 +54,15 @@ export default class Scheduler { | |||||||
|         new TaskQueueRenderer().render(this.taskQueue.seeItems()); |         new TaskQueueRenderer().render(this.taskQueue.seeItems()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private scheduleHeroAdventure() { | ||||||
|  |         if (!this.taskQueue.hasNamed(SendOnAdventureTask.NAME)) { | ||||||
|  |             this.taskQueue.push( | ||||||
|  |                 new Command(SendOnAdventureTask.NAME, {}), | ||||||
|  |                 timestamp() | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private async doLoopStep() { |     private async doLoopStep() { | ||||||
|         await sleepShort(); |         await sleepShort(); | ||||||
|         const currentTs = timestamp(); |         const currentTs = timestamp(); | ||||||
| @@ -51,7 +75,7 @@ export default class Scheduler { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const actionCommand = this.popActionCommand(); |         const actionCommand = this.actionQueue.pop(); | ||||||
|  |  | ||||||
|         this.log('CURRENT TASK', taskCommand); |         this.log('CURRENT TASK', taskCommand); | ||||||
|         this.log('CURRENT ACTION', actionCommand); |         this.log('CURRENT ACTION', actionCommand); | ||||||
| @@ -67,7 +91,7 @@ export default class Scheduler { | |||||||
|  |  | ||||||
|     private async processTaskCommand(task: Task) { |     private async processTaskCommand(task: Task) { | ||||||
|         const taskController = this.createTaskControllerByName(task.cmd.name); |         const taskController = this.createTaskControllerByName(task.cmd.name); | ||||||
|         this.log('PROCESS TASK CONTROLLER', taskController, task); |         this.log('PROCESS TASK', task.cmd.name, task, taskController); | ||||||
|         if (taskController) { |         if (taskController) { | ||||||
|             taskController.run(task); |             taskController.run(task); | ||||||
|         } |         } | ||||||
| @@ -75,7 +99,7 @@ export default class Scheduler { | |||||||
|  |  | ||||||
|     private async processActionCommand(cmd: Command, task: Task) { |     private async processActionCommand(cmd: Command, task: Task) { | ||||||
|         const actionController = this.createActionControllerByName(cmd.name); |         const actionController = this.createActionControllerByName(cmd.name); | ||||||
|         this.log('PROCESS ACTION CONTROLLER', cmd.name, actionController); |         this.log('PROCESS ACTION', cmd.name, actionController); | ||||||
|         if (actionController) { |         if (actionController) { | ||||||
|             await this.runAction(actionController, cmd.args, task); |             await this.runAction(actionController, cmd.args, task); | ||||||
|         } |         } | ||||||
| @@ -104,31 +128,37 @@ export default class Scheduler { | |||||||
|         switch (taskName) { |         switch (taskName) { | ||||||
|             case UpgradeBuildingTask.NAME: |             case UpgradeBuildingTask.NAME: | ||||||
|                 return new UpgradeBuildingTask(this); |                 return new UpgradeBuildingTask(this); | ||||||
|  |             case SendOnAdventureTask.NAME: | ||||||
|  |                 return new SendOnAdventureTask(this); | ||||||
|         } |         } | ||||||
|         this.logError('TASK NOT FOUND', taskName); |         this.logError('TASK NOT FOUND', taskName); | ||||||
|         return undefined; |         return undefined; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private popActionCommand(): Command | undefined { |  | ||||||
|         const actionItem = this.actionQueue.pop(); |  | ||||||
|         if (actionItem === undefined) { |  | ||||||
|             return undefined; |  | ||||||
|         } |  | ||||||
|         return actionItem; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private createActionControllerByName( |     private createActionControllerByName( | ||||||
|         actonName: string |         actonName: string | ||||||
|     ): ActionController | undefined { |     ): ActionController | undefined { | ||||||
|         if (actonName === UpgradeBuildingAction.NAME) { |  | ||||||
|             return new UpgradeBuildingAction(this); |  | ||||||
|         } |  | ||||||
|         if (actonName === GoToPageAction.NAME) { |         if (actonName === GoToPageAction.NAME) { | ||||||
|             return new GoToPageAction(); |             return new GoToPageAction(); | ||||||
|         } |         } | ||||||
|  |         if (actonName === ClickButtonAction.NAME) { | ||||||
|  |             return new ClickButtonAction(); | ||||||
|  |         } | ||||||
|  |         if (actonName === CompleteTaskAction.NAME) { | ||||||
|  |             return new CompleteTaskAction(this); | ||||||
|  |         } | ||||||
|  |         if (actonName === UpgradeBuildingAction.NAME) { | ||||||
|  |             return new UpgradeBuildingAction(); | ||||||
|  |         } | ||||||
|         if (actonName === CheckBuildingRemainingTimeAction.NAME) { |         if (actonName === CheckBuildingRemainingTimeAction.NAME) { | ||||||
|             return new CheckBuildingRemainingTimeAction(); |             return new CheckBuildingRemainingTimeAction(); | ||||||
|         } |         } | ||||||
|  |         if (actonName === GrabHeroAttributesAction.NAME) { | ||||||
|  |             return new GrabHeroAttributesAction(this.gameState); | ||||||
|  |         } | ||||||
|  |         if (actonName === SendOnAdventureAction.NAME) { | ||||||
|  |             return new SendOnAdventureAction(this.gameState); | ||||||
|  |         } | ||||||
|         this.logError('ACTION NOT FOUND', actonName); |         this.logError('ACTION NOT FOUND', actonName); | ||||||
|         return undefined; |         return undefined; | ||||||
|     } |     } | ||||||
| @@ -138,14 +168,17 @@ export default class Scheduler { | |||||||
|             await action.run(args, task); |             await action.run(args, task); | ||||||
|         } catch (e) { |         } catch (e) { | ||||||
|             console.warn('ACTION ABORTED', e.message); |             console.warn('ACTION ABORTED', e.message); | ||||||
|  |             this.actionQueue.clear(); | ||||||
|  |             if (e instanceof AbortTaskError) { | ||||||
|  |                 console.warn('ABORT TASK', e.id); | ||||||
|  |                 this.completeTask(e.id); | ||||||
|  |             } | ||||||
|             if (e instanceof TryLaterError) { |             if (e instanceof TryLaterError) { | ||||||
|                 console.warn('TRY', task.id, 'AFTER', e.seconds); |                 console.warn('TRY', task.id, 'AFTER', e.seconds); | ||||||
|                 this.actionQueue.clear(); |  | ||||||
|                 this.taskQueue.postpone(task.id, timestamp() + e.seconds); |                 this.taskQueue.postpone(task.id, timestamp() + e.seconds); | ||||||
|             } |             } | ||||||
|             if (e instanceof BuildingQueueFullError) { |             if (e instanceof BuildingQueueFullError) { | ||||||
|                 console.warn('BUILDING QUEUE FULL, TRY ALL AFTER', e.seconds); |                 console.warn('BUILDING QUEUE FULL, TRY ALL AFTER', e.seconds); | ||||||
|                 this.actionQueue.clear(); |  | ||||||
|                 this.taskQueue.modify( |                 this.taskQueue.modify( | ||||||
|                     t => t.cmd.name === UpgradeBuildingTask.NAME, |                     t => t.cmd.name === UpgradeBuildingTask.NAME, | ||||||
|                     t => t.withTime(timestamp() + e.seconds) |                     t => t.withTime(timestamp() + e.seconds) | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								src/Storage/GameState.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/Storage/GameState.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | const NAMESPACE = 'game_state:v1'; | ||||||
|  |  | ||||||
|  | function join(x: string, y: string) { | ||||||
|  |     return x.replace(/[:]+$/g, '') + ':' + y.replace(/^[:]+/g, ''); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class GameState { | ||||||
|  |     get(key: string): any { | ||||||
|  |         this.log('GET', key); | ||||||
|  |         try { | ||||||
|  |             const serialized = localStorage.getItem(join(NAMESPACE, key)); | ||||||
|  |             return JSON.parse(serialized || 'null'); | ||||||
|  |         } catch (e) { | ||||||
|  |             if (e instanceof SyntaxError) { | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |             throw e; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     has(key: string): boolean { | ||||||
|  |         return localStorage.getItem(join(NAMESPACE, key)) === null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     set(key: string, value: any) { | ||||||
|  |         let serialized = JSON.stringify(value); | ||||||
|  |         this.log('SET', key, serialized); | ||||||
|  |         localStorage.setItem(join(NAMESPACE, key), serialized); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private log(...args) { | ||||||
|  |         console.log('GAME STATE:', ...args); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -49,6 +49,15 @@ export class TaskQueue { | |||||||
|         return readyItems[0]; |         return readyItems[0]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     has(predicate: (t: Task) => boolean): boolean { | ||||||
|  |         const [matched, _] = this.split(predicate); | ||||||
|  |         return matched.length > 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     hasNamed(name: string): boolean { | ||||||
|  |         return this.has(t => t.cmd.name === name); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     modify(predicate: (t: Task) => boolean, modifier: (t: Task) => Task) { |     modify(predicate: (t: Task) => boolean, modifier: (t: Task) => Task) { | ||||||
|         const [matched, other] = this.split(predicate); |         const [matched, other] = this.split(predicate); | ||||||
|         const modified = matched.map(modifier); |         const modified = matched.map(modifier); | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								src/Task/SendOnAdventureTask.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/Task/SendOnAdventureTask.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | import Scheduler from '../Scheduler'; | ||||||
|  | import { Args, Command } from '../Common'; | ||||||
|  | import { Task } from '../Storage/TaskQueue'; | ||||||
|  | import TaskController from './TaskController'; | ||||||
|  | import GoToPageAction from '../Action/GoToPageAction'; | ||||||
|  | import GrabHeroAttributesAction from '../Action/GrabHeroAttributesAction'; | ||||||
|  | import CompleteTaskAction from '../Action/CompleteTaskAction'; | ||||||
|  | import SendOnAdventureAction from '../Action/SendOnAdventureAction'; | ||||||
|  | import ClickButtonAction from '../Action/ClickButtonAction'; | ||||||
|  |  | ||||||
|  | export default class SendOnAdventureTask extends TaskController { | ||||||
|  |     static NAME = 'send_on_adventure'; | ||||||
|  |     private scheduler: Scheduler; | ||||||
|  |  | ||||||
|  |     constructor(scheduler: Scheduler) { | ||||||
|  |         super(); | ||||||
|  |         this.scheduler = scheduler; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     name(): string { | ||||||
|  |         return SendOnAdventureTask.NAME; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     run(task: Task) { | ||||||
|  |         const args: Args = { ...task.cmd.args, taskId: task.id }; | ||||||
|  |         this.scheduler.scheduleActions([ | ||||||
|  |             new Command(GoToPageAction.NAME, { ...args, path: 'hero.php' }), | ||||||
|  |             new Command(GrabHeroAttributesAction.NAME, args), | ||||||
|  |             new Command(GoToPageAction.NAME, { | ||||||
|  |                 ...args, | ||||||
|  |                 path: '/hero.php?t=3', | ||||||
|  |             }), | ||||||
|  |             new Command(SendOnAdventureAction.NAME, args), | ||||||
|  |             new Command(ClickButtonAction.NAME, { | ||||||
|  |                 ...args, | ||||||
|  |                 selector: '.adventureSendButton button', | ||||||
|  |             }), | ||||||
|  |             new Command(CompleteTaskAction.NAME, args), | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,5 +1,6 @@ | |||||||
| import { Task } from '../Storage/TaskQueue'; | import { Task } from '../Storage/TaskQueue'; | ||||||
|  |  | ||||||
| export default abstract class TaskController { | export default abstract class TaskController { | ||||||
|  |     abstract name(): string; | ||||||
|     abstract run(task: Task); |     abstract run(task: Task); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import { Task } from '../Storage/TaskQueue'; | |||||||
| import TaskController from './TaskController'; | import TaskController from './TaskController'; | ||||||
| import GoToPageAction from '../Action/GoToPageAction'; | import GoToPageAction from '../Action/GoToPageAction'; | ||||||
| import CheckBuildingRemainingTimeAction from '../Action/CheckBuildingRemainingTimeAction'; | import CheckBuildingRemainingTimeAction from '../Action/CheckBuildingRemainingTimeAction'; | ||||||
|  | import CompleteTaskAction from '../Action/CompleteTaskAction'; | ||||||
|  |  | ||||||
| export default class UpgradeBuildingTask extends TaskController { | export default class UpgradeBuildingTask extends TaskController { | ||||||
|     static NAME = 'upgrade_building'; |     static NAME = 'upgrade_building'; | ||||||
| @@ -15,6 +16,10 @@ export default class UpgradeBuildingTask extends TaskController { | |||||||
|         this.scheduler = scheduler; |         this.scheduler = scheduler; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     name(): string { | ||||||
|  |         return UpgradeBuildingTask.NAME; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     run(task: Task) { |     run(task: Task) { | ||||||
|         console.log('RUN', UpgradeBuildingTask.NAME, 'with', task); |         console.log('RUN', UpgradeBuildingTask.NAME, 'with', task); | ||||||
|         const args: Args = { ...task.cmd.args, taskId: task.id }; |         const args: Args = { ...task.cmd.args, taskId: task.id }; | ||||||
| @@ -26,6 +31,7 @@ export default class UpgradeBuildingTask extends TaskController { | |||||||
|                 path: '/build.php?id=' + args.id, |                 path: '/build.php?id=' + args.id, | ||||||
|             }), |             }), | ||||||
|             new Command(UpgradeBuildingAction.NAME, args), |             new Command(UpgradeBuildingAction.NAME, args), | ||||||
|  |             new Command(CompleteTaskAction.NAME, args), | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -30,6 +30,10 @@ export function timestamp(): number { | |||||||
|     return Math.floor(Date.now() / 1000); |     return Math.floor(Date.now() / 1000); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export function trimPrefix(text: string, prefix: string): string { | ||||||
|  |     return text.startsWith(prefix) ? text.substr(prefix.length) : text; | ||||||
|  | } | ||||||
|  |  | ||||||
| export function markPage(text: string, version: string) { | export function markPage(text: string, version: string) { | ||||||
|     jQuery('body').append( |     jQuery('body').append( | ||||||
|         '<div style="' + |         '<div style="' + | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user