Change hero balance action

Target - required by next build resources
This commit is contained in:
Anton Vakhrushev 2020-04-18 18:56:32 +03:00
parent 236135f1ca
commit 809b54e0b9
9 changed files with 172 additions and 27 deletions

View File

@ -1,25 +1,53 @@
import { ActionController, registerAction } from './ActionController';
import { Args } from '../Common';
import { Task } from '../Storage/TaskQueue';
import { grabResources } from '../Page/ResourcesBlock';
import { grabResources, grabResourceStorage } from '../Page/ResourcesBlock';
import { changeHeroResource, grabCurrentHeroResource } from '../Page/HeroPage';
import { HeroAllResources } from '../Game';
import { HeroAllResources, Resources } from '../Game';
import { grabActiveVillageId } from '../Page/VillageBlock';
@registerAction
export class BalanceHeroResourcesAction extends ActionController {
async run(args: Args, task: Task): Promise<any> {
const resourcesAsList = grabResources().asList();
const resources = this.getRequirements();
const resourcesAsList = resources.asList();
const currentType = grabCurrentHeroResource();
const sorted = resourcesAsList.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;
const sorted = resourcesAsList.sort((x, y) => y.value - x.value);
const maxRequirement = sorted[0];
const minRequirement = sorted[sorted.length - 1];
const delta = maxRequirement.value - minRequirement.value;
const eps = maxRequirement.value / 10;
const resType = delta > eps ? min.type : HeroAllResources;
const resType = delta > eps ? maxRequirement.type : HeroAllResources;
if (resType !== currentType) {
changeHeroResource(resType);
}
}
private getRequirements() {
const resources = grabResources();
const villageId = grabActiveVillageId();
const requiredResources = this.scheduler.getVillageRequiredResources(villageId);
if (requiredResources) {
return new Resources(
requiredResources.lumber - resources.lumber,
requiredResources.clay - resources.clay,
requiredResources.iron - resources.iron,
requiredResources.crop - resources.crop
);
}
const storage = grabResourceStorage();
return new Resources(
storage.warehouse - resources.lumber,
storage.warehouse - resources.clay,
storage.warehouse - resources.iron,
storage.granary - resources.crop
);
}
}

View File

@ -0,0 +1,21 @@
import { ActionController, registerAction } from './ActionController';
import { Args } from '../Common';
import { Task } from '../Storage/TaskQueue';
import { grabContractResources } from '../Page/BuildingPage';
@registerAction
export class UpdateBuildingTaskResourcesAction extends ActionController {
async run(args: Args, task: Task): Promise<any> {
const buildingTaskId = args.taskId;
if (buildingTaskId === undefined) {
return;
}
try {
const resources = grabContractResources();
this.scheduler.updateResources(buildingTaskId, resources);
} catch (e) {
return;
}
}
}

View File

@ -1,4 +1,5 @@
import { ResourcesInterface } from './Game';
import { TaskId } from './Storage/TaskQueue';
export interface Args {
villageId?: number;
@ -6,6 +7,7 @@ export interface Args {
categoryId?: number;
buildTypeId?: number;
resources?: ResourcesInterface;
taskId?: TaskId;
[name: string]: any;
}

View File

@ -72,6 +72,7 @@ export class ControlPanel {
const storage = state.getResourceStorage();
const performance = state.getResourcesPerformance();
const buildQueueInfo = state.getBuildingQueueInfo();
const requiredResources = scheduler.getVillageRequiredResources(village.id);
return {
id: village.id,
name: village.name,
@ -85,6 +86,10 @@ export class ControlPanel {
clay_hour: performance.clay,
iron_hour: performance.iron,
crop_hour: performance.crop,
lumber_need: requiredResources && requiredResources.lumber,
clay_need: requiredResources && requiredResources.clay,
iron_need: requiredResources && requiredResources.iron,
crop_need: requiredResources && requiredResources.crop,
warehouse: storage.warehouse,
granary: storage.granary,
buildRemainingSeconds: buildQueueInfo.seconds,

View File

@ -41,12 +41,30 @@
</td>
<td class="right" v-text="village.granary"></td>
</tr>
<tr class="required-line">
<td class="right">След:</td>
<td class="right" v-text="village.lumber_need || ''"></td>
<td class="right" v-text="village.clay_need || ''"></td>
<td class="right" v-text="village.iron_need || ''"></td>
<td class="right" v-text="village.crop_need || ''"></td>
<td></td>
<td></td>
</tr>
<tr class="required-line">
<td class="right">Необх:</td>
<td class="right" v-text="village.lumber_need - village.lumber || ''"></td>
<td class="right" v-text="village.clay_need - village.clay || ''"></td>
<td class="right" v-text="village.iron_need - village.iron || ''"></td>
<td class="right" v-text="village.crop_need - village.crop || ''"></td>
<td></td>
<td></td>
</tr>
<tr class="performance-line">
<td class="right small" v-text="secondsToTime(village.buildRemainingSeconds)"></td>
<td class="right small">+{{ village.lumber_hour }}</td>
<td class="right small">+{{ village.clay_hour }}</td>
<td class="right small">+{{ village.iron_hour }}</td>
<td class="right small">+{{ village.crop_hour }}</td>
<td class="right" v-text="secondsToTime(village.buildRemainingSeconds)"></td>
<td class="right">+{{ village.lumber_hour }}</td>
<td class="right">+{{ village.clay_hour }}</td>
<td class="right">+{{ village.iron_hour }}</td>
<td class="right">+{{ village.crop_hour }}</td>
<td></td>
<td></td>
</tr>
@ -130,6 +148,12 @@ export default {
.performance-line td {
padding: 0 4px 4px;
font-size: 90%;
}
.required-line td {
padding: 0 4px 4px;
font-size: 90%;
}
.village-table td.active {
@ -144,10 +168,6 @@ export default {
text-align: right;
}
.small {
font-size: 90%;
}
.village-quick-link {
display: inline-block;
}

View File

@ -42,6 +42,10 @@ export class Resources implements ResourcesInterface {
this.crop = crop;
}
static fromObject(obj: ResourcesInterface) {
return new Resources(obj.lumber, obj.clay, obj.iron, obj.crop);
}
getByType(type: ResourceType): number {
switch (type) {
case ResourceType.Lumber:

View File

@ -8,6 +8,8 @@ import { ConsoleLogger, Logger } from './Logger';
import { BuildBuildingTask } from './Task/BuildBuildingTask';
import { GrabVillageState } from './Task/GrabVillageState';
import { ActionQueue } from './Storage/ActionQueue';
import { Resources, ResourcesInterface } from './Game';
import { UpdateResourceContracts } from './Task/UpdateResourceContracts';
export class Scheduler {
private taskQueue: TaskQueue;
@ -20,17 +22,18 @@ export class Scheduler {
this.logger = new ConsoleLogger(this.constructor.name);
// this.taskQueue.push(GrabVillageState.name, {}, timestamp());
// this.taskQueue.push(UpdateResourceContracts.name, {}, timestamp());
// this.taskQueue.push(BalanceHeroResourcesTask.name, {}, timestamp());
this.scheduleUniqTask(3600, SendOnAdventureTask.name);
this.scheduleUniqTask(1200, BalanceHeroResourcesTask.name);
this.scheduleUniqTask(180, GrabVillageState.name);
this.createUniqTaskTimer(3600, SendOnAdventureTask.name);
this.createUniqTaskTimer(1200, BalanceHeroResourcesTask.name);
this.createUniqTaskTimer(180, GrabVillageState.name);
this.createUniqTaskTimer(300, UpdateResourceContracts.name);
}
private scheduleUniqTask(seconds: number, name: string, args: Args = {}) {
public createUniqTaskTimer(seconds: number, name: string, args: Args = {}) {
const taskScheduler = () => {
if (!this.taskQueue.has(t => t.name === name)) {
this.scheduleTask(name, args, timestamp() + Math.min(seconds, 5 * 60));
}
this.scheduleUniqTask(name, args, timestamp() + Math.min(seconds, 5 * 60));
};
taskScheduler();
setInterval(taskScheduler, seconds * 1000);
@ -63,6 +66,13 @@ export class Scheduler {
}
}
scheduleUniqTask(name: string, args: Args, ts?: number | undefined): void {
let alreadyHasTask = this.taskQueue.has(t => t.name === name);
if (!alreadyHasTask) {
this.scheduleTask(name, args, ts);
}
}
completeTask(id: TaskId) {
this.taskQueue.remove(id);
this.actionQueue.clear();
@ -87,6 +97,13 @@ export class Scheduler {
);
}
updateResources(taskId: TaskId, resources: Resources): void {
this.taskQueue.modify(
t => t.id === taskId,
t => withResources(t, resources)
);
}
scheduleActions(actions: Array<Command>): void {
this.actionQueue.assign(actions);
}
@ -94,6 +111,15 @@ export class Scheduler {
clearActions() {
this.actionQueue.clear();
}
getVillageRequiredResources(villageId): ResourcesInterface | undefined {
const tasks = this.taskQueue.seeItems().filter(t => isBuildingTask(t.name) && sameVillage(villageId, t.args));
const first = tasks.shift();
if (first && first.args.resources) {
return first.args.resources;
}
return undefined;
}
}
function isBuildingTask(taskName: string) {
@ -104,10 +130,14 @@ function sameVillage(villageId: number | undefined, args: Args) {
return villageId !== undefined && args.villageId === villageId;
}
export function withTime(task: Task, ts: number): Task {
function withTime(task: Task, ts: number): Task {
return new Task(task.id, ts, task.name, task.args);
}
function withResources(task: Task, resources: ResourcesInterface): Task {
return new Task(task.id, task.ts, task.name, { ...task.args, resources });
}
function calculateTimeToPushAfter(tasks: TaskList, predicate: (t: Task) => boolean, ts: number | undefined): number {
const normalizedTs = ts || timestamp();
const queuedTaskIndex = findLastIndex(tasks, predicate);

View File

@ -107,7 +107,7 @@ export class TaskQueue {
}
private flushItems(items: TaskList): void {
const normalized = items.sort((x, y) => x.ts - y.ts);
const normalized = items.sort((x, y) => x.ts - y.ts || x.id.localeCompare(y.id));
this.storage.set(QUEUE_NAME, normalized);
}
}

View File

@ -0,0 +1,35 @@
import { Args, Command } from '../Common';
import { Task } from '../Storage/TaskQueue';
import { TaskController, registerTask } from './TaskController';
import { GoToPageAction } from '../Action/GoToPageAction';
import { path } from '../utils';
import { UpgradeBuildingTask } from './UpgradeBuildingTask';
import { UpdateBuildingTaskResourcesAction } from '../Action/UpdateBuildingTaskResourcesAction';
import { CompleteTaskAction } from '../Action/CompleteTaskAction';
@registerTask
export class UpdateResourceContracts extends TaskController {
async run(task: Task) {
const args: Args = { ...task.args, taskId: task.id };
const actions: Array<Command> = [];
const tasks = this.scheduler.getTaskItems();
for (let task of tasks) {
const { villageId, buildId } = task.args;
if (task.name === UpgradeBuildingTask.name && villageId && buildId) {
actions.push(
new Command(GoToPageAction.name, {
...args,
path: path('/build.php', { newdid: villageId, id: buildId }),
})
);
actions.push(new Command(UpdateBuildingTaskResourcesAction.name, { ...args, taskId: task.id }));
}
}
actions.push(new Command(CompleteTaskAction.name, args));
this.scheduler.scheduleActions(actions);
}
}