Add troopers training
This commit is contained in:
parent
2bad0e1b5d
commit
500e266517
@ -2,12 +2,15 @@ import { ResourcesInterface } from './Game';
|
|||||||
import { TaskId } from './Queue/TaskQueue';
|
import { TaskId } from './Queue/TaskQueue';
|
||||||
|
|
||||||
export interface Args {
|
export interface Args {
|
||||||
|
taskId?: TaskId;
|
||||||
villageId?: number;
|
villageId?: number;
|
||||||
buildId?: number;
|
buildId?: number;
|
||||||
categoryId?: number;
|
categoryId?: number;
|
||||||
|
tabId?: number;
|
||||||
buildTypeId?: number;
|
buildTypeId?: number;
|
||||||
|
troopId?: number;
|
||||||
|
trainCount?: number;
|
||||||
resources?: ResourcesInterface;
|
resources?: ResourcesInterface;
|
||||||
taskId?: TaskId;
|
|
||||||
[name: string]: any;
|
[name: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { getNumber, parseLocation, uniqId, waitForLoad } from './utils';
|
import { elClassId, getNumber, parseLocation, uniqId, waitForLoad } from './utils';
|
||||||
import { Scheduler } from './Scheduler';
|
import { Scheduler } from './Scheduler';
|
||||||
import { BuildPage } from './Page/BuildPage';
|
import { BuildingPageController } from './Page/BuildingPageController';
|
||||||
import { UpgradeBuildingTask } from './Task/UpgradeBuildingTask';
|
import { UpgradeBuildingTask } from './Task/UpgradeBuildingTask';
|
||||||
import { grabActiveVillageId, grabVillageList } from './Page/VillageBlock';
|
import { grabActiveVillageId, grabVillageList } from './Page/VillageBlock';
|
||||||
import {
|
import {
|
||||||
@ -127,7 +127,13 @@ export class ControlPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (p.pathname === '/build.php') {
|
if (p.pathname === '/build.php') {
|
||||||
new BuildPage(this.scheduler, getNumber(p.query.id), getNumber(p.query.category, 1)).run();
|
const buildPage = new BuildingPageController(this.scheduler, {
|
||||||
|
buildId: getNumber(p.query.id),
|
||||||
|
buildTypeId: getNumber(elClassId(jQuery('#build').attr('class'), 'gid')),
|
||||||
|
categoryId: getNumber(p.query.category, 1),
|
||||||
|
tabId: getNumber(p.query.s, 0),
|
||||||
|
});
|
||||||
|
buildPage.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.createControlPanel(state);
|
this.createControlPanel(state);
|
||||||
|
28
src/Game.ts
28
src/Game.ts
@ -42,10 +42,14 @@ export class Resources implements ResourcesInterface {
|
|||||||
this.crop = crop;
|
this.crop = crop;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromObject(obj: ResourcesInterface) {
|
static fromObject(obj: ResourcesInterface): Resources {
|
||||||
return new Resources(obj.lumber, obj.clay, obj.iron, obj.crop);
|
return new Resources(obj.lumber, obj.clay, obj.iron, obj.crop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static fromStorage(warehouse: number, granary: number): Resources {
|
||||||
|
return new Resources(warehouse, warehouse, warehouse, granary);
|
||||||
|
}
|
||||||
|
|
||||||
getByType(type: ResourceType): number {
|
getByType(type: ResourceType): number {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ResourceType.Lumber:
|
case ResourceType.Lumber:
|
||||||
@ -66,6 +70,28 @@ export class Resources implements ResourcesInterface {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scale(n: number): Resources {
|
||||||
|
return new Resources(this.lumber * n, this.clay * n, this.iron * n, this.crop * n);
|
||||||
|
}
|
||||||
|
|
||||||
|
add(other: Resources): Resources {
|
||||||
|
return new Resources(
|
||||||
|
this.lumber + other.lumber,
|
||||||
|
this.clay + other.clay,
|
||||||
|
this.iron + other.iron,
|
||||||
|
this.crop + other.crop
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub(other: Resources): Resources {
|
||||||
|
return new Resources(
|
||||||
|
this.lumber - other.lumber,
|
||||||
|
this.clay - other.clay,
|
||||||
|
this.iron - other.iron,
|
||||||
|
this.crop - other.crop
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResourceStorage {
|
export class ResourceStorage {
|
||||||
|
@ -1,89 +0,0 @@
|
|||||||
import { elClassId, notify, split, uniqId } from '../utils';
|
|
||||||
import { UpgradeBuildingTask } from '../Task/UpgradeBuildingTask';
|
|
||||||
import { Scheduler } from '../Scheduler';
|
|
||||||
import { TrainTroopTask } from '../Task/TrainTroopTask';
|
|
||||||
import { grabActiveVillageId } from './VillageBlock';
|
|
||||||
import { ConsoleLogger, Logger } from '../Logger';
|
|
||||||
import { createBuildButton, createUpgradeButton, grabContractResources } from './BuildingPage';
|
|
||||||
import { BuildBuildingTask } from '../Task/BuildBuildingTask';
|
|
||||||
|
|
||||||
const QUARTERS_ID = 19;
|
|
||||||
|
|
||||||
export class BuildPage {
|
|
||||||
private scheduler: Scheduler;
|
|
||||||
private readonly buildId: number;
|
|
||||||
private readonly logger;
|
|
||||||
private readonly categoryId: number;
|
|
||||||
|
|
||||||
constructor(scheduler: Scheduler, buildId: number, categoryId: number) {
|
|
||||||
this.scheduler = scheduler;
|
|
||||||
this.buildId = buildId;
|
|
||||||
this.categoryId = categoryId;
|
|
||||||
this.logger = new ConsoleLogger(this.constructor.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
run() {
|
|
||||||
const buildTypeId = elClassId(jQuery('#build').attr('class') || '', 'gid');
|
|
||||||
this.logger.log('BUILD PAGE DETECTED', 'ID', this.buildId, 'TYPE', buildTypeId);
|
|
||||||
|
|
||||||
createBuildButton(buildTypeId => this.onScheduleBuildBuilding(buildTypeId));
|
|
||||||
createUpgradeButton(() => this.onScheduleUpgradeBuilding());
|
|
||||||
|
|
||||||
if (buildTypeId === QUARTERS_ID) {
|
|
||||||
this.createTrainTroopButton();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private onScheduleBuildBuilding(buildTypeId: number) {
|
|
||||||
const buildId = this.buildId;
|
|
||||||
const categoryId = this.categoryId;
|
|
||||||
const villageId = grabActiveVillageId();
|
|
||||||
const resources = grabContractResources();
|
|
||||||
this.scheduler.scheduleTask(BuildBuildingTask.name, { villageId, buildId, categoryId, buildTypeId, resources });
|
|
||||||
notify(`Building ${buildId} scheduled`);
|
|
||||||
}
|
|
||||||
|
|
||||||
private onScheduleUpgradeBuilding() {
|
|
||||||
const buildId = this.buildId;
|
|
||||||
const villageId = grabActiveVillageId();
|
|
||||||
const resources = grabContractResources();
|
|
||||||
this.scheduler.scheduleTask(UpgradeBuildingTask.name, { villageId, buildId, resources });
|
|
||||||
notify(`Upgrading ${buildId} scheduled`);
|
|
||||||
}
|
|
||||||
|
|
||||||
private createTrainTroopButton() {
|
|
||||||
const troopBlocks = jQuery('#nonFavouriteTroops .action.troop:not(.empty) .innerTroopWrapper');
|
|
||||||
troopBlocks.each((idx, el) => {
|
|
||||||
const troopId = elClassId(jQuery(el).attr('class') || '', 'troop');
|
|
||||||
this.logger.log('TROOP', troopId);
|
|
||||||
if (troopId) {
|
|
||||||
const id = uniqId();
|
|
||||||
jQuery(el)
|
|
||||||
.find('.details')
|
|
||||||
.append(`<div style="padding: 8px 0"><a id="${id}" href="#">Обучить</a></div>`);
|
|
||||||
jQuery(`#${id}`).on('click', evt => {
|
|
||||||
evt.preventDefault();
|
|
||||||
this.onTrainTroopClick(this.buildId, troopId, el);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private onTrainTroopClick(buildId: number, troopId: number, el: HTMLElement) {
|
|
||||||
this.logger.log('TRAIN TROOPERS', 'TROOP ID', troopId, 'BUILDING ID', buildId);
|
|
||||||
const villageId = grabActiveVillageId();
|
|
||||||
const input = jQuery(el).find(`input[name="t${troopId}"]`);
|
|
||||||
const count = Number(input.val());
|
|
||||||
if (!isNaN(count) && count > 0) {
|
|
||||||
this.logger.log('PREPARE TO TRAIN', count, 'TROOPERS');
|
|
||||||
for (let n of split(count)) {
|
|
||||||
this.scheduler.scheduleTask(TrainTroopTask.name, {
|
|
||||||
villageId,
|
|
||||||
buildId,
|
|
||||||
troopId,
|
|
||||||
trainCount: n,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,8 @@
|
|||||||
import { GrabError } from '../Errors';
|
import { GrabError } from '../Errors';
|
||||||
import { getNumber, trimPrefix, uniqId } from '../utils';
|
import { elClassId, getNumber, split, trimPrefix, uniqId } from '../utils';
|
||||||
import { Resources } from '../Game';
|
import { Resources } from '../Game';
|
||||||
|
import { grabActiveVillageId } from './VillageBlock';
|
||||||
|
import { TrainTroopTask } from '../Task/TrainTroopTask';
|
||||||
|
|
||||||
export function clickBuildButton(typeId: number) {
|
export function clickBuildButton(typeId: number) {
|
||||||
const section = jQuery(`#contract_building${typeId}`);
|
const section = jQuery(`#contract_building${typeId}`);
|
||||||
@ -52,16 +54,47 @@ export function createUpgradeButton(onClickHandler: () => void) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function grabResourcesFromList($els) {
|
||||||
|
const getText = n =>
|
||||||
|
jQuery($els.get(n))
|
||||||
|
.find('.value')
|
||||||
|
.text();
|
||||||
|
const grab = n => getNumber(getText(n));
|
||||||
|
return new Resources(grab(0), grab(1), grab(2), grab(3));
|
||||||
|
}
|
||||||
|
|
||||||
export function grabContractResources(): Resources {
|
export function grabContractResources(): Resources {
|
||||||
const $els = jQuery('#contract .resource');
|
const $els = jQuery('#contract .resource');
|
||||||
if ($els.length === 0) {
|
if ($els.length === 0) {
|
||||||
throw new GrabError('No resource contract element');
|
throw new GrabError('No resource contract element');
|
||||||
}
|
}
|
||||||
const grab = n =>
|
return grabResourcesFromList($els);
|
||||||
getNumber(
|
}
|
||||||
jQuery($els.get(n))
|
|
||||||
.find('.value')
|
export function createTrainTroopButtons(
|
||||||
.text()
|
onClickHandler: (troopId: number, resources: Resources, count: number) => void
|
||||||
);
|
) {
|
||||||
return new Resources(grab(0), grab(1), grab(2), grab(3));
|
const troopBlocks = jQuery('.action.troop:not(.empty) .innerTroopWrapper');
|
||||||
|
if (troopBlocks.length === 0) {
|
||||||
|
throw new GrabError('No troop blocks');
|
||||||
|
}
|
||||||
|
troopBlocks.each((idx, el) => {
|
||||||
|
const $el = jQuery(el);
|
||||||
|
const troopId = elClassId($el.attr('class'), 'troop');
|
||||||
|
if (troopId === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const id = uniqId();
|
||||||
|
$el.find('.details').append(`<div style="padding: 8px 0"><a id="${id}" href="#">Обучить</a></div>`);
|
||||||
|
const resElement = $el.find('.resourceWrapper .resource');
|
||||||
|
const resources = grabResourcesFromList(resElement);
|
||||||
|
jQuery(`#${id}`).on('click', evt => {
|
||||||
|
evt.preventDefault();
|
||||||
|
const input = $el.find(`input[name="t${troopId}"]`);
|
||||||
|
const count = getNumber(input.val());
|
||||||
|
if (count > 0) {
|
||||||
|
onClickHandler(troopId, resources, count);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
87
src/Page/BuildingPageController.ts
Normal file
87
src/Page/BuildingPageController.ts
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import { elClassId, notify, split, uniqId } from '../utils';
|
||||||
|
import { UpgradeBuildingTask } from '../Task/UpgradeBuildingTask';
|
||||||
|
import { Scheduler } from '../Scheduler';
|
||||||
|
import { TrainTroopTask } from '../Task/TrainTroopTask';
|
||||||
|
import { grabActiveVillageId } from './VillageBlock';
|
||||||
|
import { ConsoleLogger, Logger } from '../Logger';
|
||||||
|
import { createBuildButton, createTrainTroopButtons, createUpgradeButton, grabContractResources } from './BuildingPage';
|
||||||
|
import { BuildBuildingTask } from '../Task/BuildBuildingTask';
|
||||||
|
import { Resources } from '../Game';
|
||||||
|
|
||||||
|
const QUARTERS_ID = 19;
|
||||||
|
const HORSE_STABLE_ID = 20;
|
||||||
|
const EMBASSY_ID = 25;
|
||||||
|
|
||||||
|
export interface BuildingPageAttributes {
|
||||||
|
buildId: number;
|
||||||
|
buildTypeId: number;
|
||||||
|
categoryId: number;
|
||||||
|
tabId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BuildingPageController {
|
||||||
|
private scheduler: Scheduler;
|
||||||
|
private readonly attributes: BuildingPageAttributes;
|
||||||
|
private readonly logger;
|
||||||
|
|
||||||
|
constructor(scheduler: Scheduler, attributes: BuildingPageAttributes) {
|
||||||
|
this.scheduler = scheduler;
|
||||||
|
this.attributes = attributes;
|
||||||
|
this.logger = new ConsoleLogger(this.constructor.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
run() {
|
||||||
|
const buildTypeId = this.attributes.buildTypeId;
|
||||||
|
this.logger.log('BUILD PAGE DETECTED', 'ID', this.attributes.buildId, 'TYPE', buildTypeId);
|
||||||
|
|
||||||
|
createBuildButton(buildTypeId => this.onScheduleBuildBuilding(buildTypeId));
|
||||||
|
createUpgradeButton(() => this.onScheduleUpgradeBuilding());
|
||||||
|
|
||||||
|
if (buildTypeId === QUARTERS_ID) {
|
||||||
|
createTrainTroopButtons((troopId, res, count) => this.onScheduleTrainTroopers(troopId, res, count));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buildTypeId === HORSE_STABLE_ID) {
|
||||||
|
createTrainTroopButtons((troopId, res, count) => this.onScheduleTrainTroopers(troopId, res, count));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buildTypeId === EMBASSY_ID && this.attributes.tabId === 1) {
|
||||||
|
createTrainTroopButtons((troopId, res, count) => this.onScheduleTrainTroopers(troopId, res, count));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onScheduleBuildBuilding(buildTypeId: number) {
|
||||||
|
const buildId = this.attributes.buildId;
|
||||||
|
const categoryId = this.attributes.categoryId;
|
||||||
|
const villageId = grabActiveVillageId();
|
||||||
|
const resources = grabContractResources();
|
||||||
|
this.scheduler.scheduleTask(BuildBuildingTask.name, { villageId, buildId, categoryId, buildTypeId, resources });
|
||||||
|
notify(`Building ${buildId} scheduled`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onScheduleUpgradeBuilding() {
|
||||||
|
const buildId = this.attributes.buildId;
|
||||||
|
const villageId = grabActiveVillageId();
|
||||||
|
const resources = grabContractResources();
|
||||||
|
this.scheduler.scheduleTask(UpgradeBuildingTask.name, { villageId, buildId, resources });
|
||||||
|
notify(`Upgrading ${buildId} scheduled`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onScheduleTrainTroopers(troopId: number, resources: Resources, count: number) {
|
||||||
|
const tabId = this.attributes.tabId;
|
||||||
|
for (let chunk of split(count)) {
|
||||||
|
const args = {
|
||||||
|
villageId: grabActiveVillageId(),
|
||||||
|
buildId: this.attributes.buildId,
|
||||||
|
buildTypeId: this.attributes.buildTypeId,
|
||||||
|
tabId,
|
||||||
|
troopId,
|
||||||
|
resources: resources.scale(chunk),
|
||||||
|
trainCount: chunk,
|
||||||
|
};
|
||||||
|
console.log('TRAIN TROOP', args);
|
||||||
|
this.scheduler.scheduleTask(TrainTroopTask.name, args);
|
||||||
|
}
|
||||||
|
notify(`Training ${count} troopers scheduled`);
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@ interface Slot {
|
|||||||
function slotElements(prefix: string): Array<Slot> {
|
function slotElements(prefix: string): Array<Slot> {
|
||||||
const result: Array<Slot> = [];
|
const result: Array<Slot> = [];
|
||||||
jQuery('.level.colorLayer').each((idx, el) => {
|
jQuery('.level.colorLayer').each((idx, el) => {
|
||||||
const buildId = getNumber(elClassId(jQuery(el).attr('class') || '', prefix));
|
const buildId = getNumber(elClassId(jQuery(el).attr('class'), prefix));
|
||||||
result.push({ el, buildId });
|
result.push({ el, buildId });
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
@ -58,7 +58,7 @@ export function onResourceSlotCtrlClick(cb: (buildId: number) => void): void {
|
|||||||
|
|
||||||
function slotToDepositMapper(slot: Slot): ResourceDeposit {
|
function slotToDepositMapper(slot: Slot): ResourceDeposit {
|
||||||
const el = slot.el;
|
const el = slot.el;
|
||||||
const classes = jQuery(el).attr('class') || '';
|
const classes = jQuery(el).attr('class');
|
||||||
const buildId = getNumber(elClassId(classes, 'buildingSlot'));
|
const buildId = getNumber(elClassId(classes, 'buildingSlot'));
|
||||||
const level = getNumber(elClassId(classes, 'level'));
|
const level = getNumber(elClassId(classes, 'level'));
|
||||||
const type = getNumber(elClassId(classes, 'gid'));
|
const type = getNumber(elClassId(classes, 'gid'));
|
||||||
|
@ -121,7 +121,7 @@ export class Scheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getVillageRequiredResources(villageId): ResourcesInterface | undefined {
|
getVillageRequiredResources(villageId): ResourcesInterface | undefined {
|
||||||
const tasks = this.taskQueue.seeItems().filter(t => isBuildingTask(t.name) && sameVillage(villageId, t.args));
|
const tasks = this.taskQueue.seeItems().filter(t => sameVillage(villageId, t.args) && t.args.resources);
|
||||||
const first = tasks.shift();
|
const first = tasks.shift();
|
||||||
if (first && first.args.resources) {
|
if (first && first.args.resources) {
|
||||||
return first.args.resources;
|
return first.args.resources;
|
||||||
|
@ -10,11 +10,18 @@ import { path } from '../utils';
|
|||||||
export class TrainTroopTask extends TaskController {
|
export class TrainTroopTask extends TaskController {
|
||||||
async run(task: Task) {
|
async run(task: Task) {
|
||||||
const args: Args = { ...task.args, taskId: task.id };
|
const args: Args = { ...task.args, taskId: task.id };
|
||||||
|
|
||||||
|
const pathArgs = {
|
||||||
|
newdid: args.villageId,
|
||||||
|
gid: args.buildTypeId || undefined,
|
||||||
|
id: args.buildId || undefined,
|
||||||
|
s: args.tabId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const pagePath = path('/build.php', pathArgs);
|
||||||
|
|
||||||
this.scheduler.scheduleActions([
|
this.scheduler.scheduleActions([
|
||||||
new Command(GoToPageAction.name, {
|
new Command(GoToPageAction.name, { ...args, path: pagePath }),
|
||||||
...args,
|
|
||||||
path: path('/build.php', { newdid: args.villageId, id: args.buildId }),
|
|
||||||
}),
|
|
||||||
new Command(TrainTrooperAction.name, args),
|
new Command(TrainTrooperAction.name, args),
|
||||||
new Command(CompleteTaskAction.name, args),
|
new Command(CompleteTaskAction.name, args),
|
||||||
]);
|
]);
|
||||||
|
14
src/utils.ts
14
src/utils.ts
@ -53,23 +53,23 @@ export function trimPrefix(text: string, prefix: string): string {
|
|||||||
return text.startsWith(prefix) ? text.substr(prefix.length) : text;
|
return text.startsWith(prefix) ? text.substr(prefix.length) : text;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function elClassId(classes: string, prefix: string): number | undefined {
|
export function elClassId(classes: string | undefined, prefix: string): number | undefined {
|
||||||
|
if (classes === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
let result: number | undefined = undefined;
|
let result: number | undefined = undefined;
|
||||||
classes.split(/\s/).forEach(part => {
|
classes.split(/\s/).forEach(part => {
|
||||||
if (part.startsWith(prefix)) {
|
if (part.startsWith(prefix)) {
|
||||||
result = Number(part.substr(prefix.length));
|
result = toNumber(part.substr(prefix.length));
|
||||||
if (isNaN(result)) {
|
|
||||||
result = undefined;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* split(n: number) {
|
export function* split(n: number, from: number = 2, to: number = 6) {
|
||||||
let c = n;
|
let c = n;
|
||||||
while (c > 0) {
|
while (c > 0) {
|
||||||
const next = 2 + Math.floor(Math.random() * 3);
|
const next = from + Math.floor(Math.random() * (to - from));
|
||||||
if (next < c) {
|
if (next < c) {
|
||||||
yield next;
|
yield next;
|
||||||
c -= next;
|
c -= next;
|
||||||
|
Loading…
Reference in New Issue
Block a user