diff --git a/src/DashboardView/VillageStateList.vue b/src/DashboardView/VillageStateList.vue
index 40a48cd..a8cecff 100644
--- a/src/DashboardView/VillageStateList.vue
+++ b/src/DashboardView/VillageStateList.vue
@@ -68,6 +68,9 @@
diff --git a/src/VillageController.ts b/src/VillageController.ts
index 82cdef6..4375a43 100644
--- a/src/VillageController.ts
+++ b/src/VillageController.ts
@@ -35,7 +35,7 @@ export class VillageController {
}
getReadyProductionTask(): Task | undefined {
- return this.taskCollection.getReadyForProductionTask();
+ return this.state.firstReadyTask;
}
addTask(name: string, args: Args) {
diff --git a/src/VillageState.ts b/src/VillageState.ts
index e30e7b4..1b97f6a 100644
--- a/src/VillageState.ts
+++ b/src/VillageState.ts
@@ -4,10 +4,11 @@ import { VillageStorage } from './Storage/VillageStorage';
import { calcGatheringTimings, GatheringTime } from './Core/GatheringTimings';
import { VillageRepositoryInterface } from './VillageRepository';
import { VillageNotFound } from './Errors';
-import { ProductionQueue, OrderedProductionQueues } from './Core/ProductionQueue';
+import { ProductionQueue } from './Core/ProductionQueue';
import { Task } from './Queue/TaskProvider';
import { timestamp } from './utils';
-import { VillageTaskCollection } from './VillageTaskCollection';
+import { QueueTasks, VillageTaskCollection } from './VillageTaskCollection';
+import { TrainTroopTask } from './Task/TrainTroopTask';
interface VillageStorageState {
resources: Resources;
@@ -42,6 +43,7 @@ interface ResourceLineState {
interface VillageProductionQueueState {
queue: ProductionQueue;
+ tasks: Array;
isActive: boolean;
currentTaskFinishTimestamp: number;
currentTaskFinishSeconds: number;
@@ -50,6 +52,10 @@ interface VillageProductionQueueState {
taskCount: number;
}
+interface VillageProductionQueueStateDict {
+ [queue: string]: VillageProductionQueueState;
+}
+
interface VillageOwnState {
/**
* Village id
@@ -68,6 +74,8 @@ interface VillageOwnState {
upperCriticalLevel: Resources;
storageOptimumFullness: Resources;
isOverflowing: boolean;
+ queues: VillageProductionQueueStateDict;
+ firstReadyTask: Task | undefined;
/**
* Required resources for nearest task
*/
@@ -82,7 +90,6 @@ interface VillageOwnState {
totalRequired: ResourceLineState;
incomingResources: Resources;
settings: VillageSettings;
- queues: { [queue: string]: VillageProductionQueueState | undefined };
}
interface VillageOwnStateDictionary {
@@ -96,7 +103,7 @@ export interface VillageState extends VillageOwnState {
commitments: Resources;
}
-function calcResourceBalance(
+function makeResourceBalance(
resources: Resources,
current: Resources,
performance: Resources
@@ -109,7 +116,7 @@ function calcResourceBalance(
};
}
-function calcStorageBalance(
+function makeStorageBalance(
resources: Resources,
storage: Resources,
performance: Resources
@@ -153,28 +160,29 @@ function taskResourceReducer(resources: Resources, task: Task) {
}
function createProductionQueueState(
- queue: ProductionQueue,
- storage: VillageStorage,
- taskCollection: VillageTaskCollection
+ taskQueueInfo: QueueTasks,
+ storage: VillageStorage
): VillageProductionQueueState {
+ const queue = taskQueueInfo.queue;
+ const tasks = taskQueueInfo.tasks;
const resources = storage.getResources();
const performance = storage.getResourcesPerformance();
- const tasks = taskCollection.getTasksInProductionQueue(queue);
const firstTaskResources = tasks.slice(0, 1).reduce(taskResourceReducer, Resources.zero());
const allTaskResources = tasks.reduce(taskResourceReducer, Resources.zero());
- const taskEndingTimestamp = storage.getQueueTaskEnding(queue);
+ const taskEndingTimestamp = taskQueueInfo.finishTs;
return {
queue,
+ tasks,
isActive: tasks.length !== 0 || taskEndingTimestamp > timestamp(),
currentTaskFinishTimestamp: taskEndingTimestamp,
currentTaskFinishSeconds: Math.max(
taskEndingTimestamp ? taskEndingTimestamp - timestamp() : 0,
0
),
- firstTask: calcResourceBalance(firstTaskResources, resources, performance),
- allTasks: calcResourceBalance(allTaskResources, resources, performance),
+ firstTask: makeResourceBalance(firstTaskResources, resources, performance),
+ allTasks: makeResourceBalance(allTaskResources, resources, performance),
taskCount: tasks.length,
};
}
@@ -183,25 +191,54 @@ function createAllProductionQueueStates(
storage: VillageStorage,
taskCollection: VillageTaskCollection
) {
- let result: { [queue: string]: VillageProductionQueueState } = {};
- for (let queue of OrderedProductionQueues) {
- result[queue] = createProductionQueueState(queue, storage, taskCollection);
+ let result: VillageProductionQueueStateDict = {};
+ for (let taskQueueInfo of taskCollection.getQueueGroupedTasks()) {
+ result[taskQueueInfo.queue] = createProductionQueueState(taskQueueInfo, storage);
}
return result;
}
+function getReadyForProductionTask(
+ queues: VillageProductionQueueStateDict,
+ maxResourcesForTask: Resources
+): Task | undefined {
+ const nowTs = timestamp();
+ const firstReadyGroup = Object.values(queues).find(
+ group => group.currentTaskFinishTimestamp <= nowTs && group.tasks.length !== 0
+ );
+ if (!firstReadyGroup) {
+ return undefined;
+ }
+
+ return firstReadyGroup.tasks.find(
+ t =>
+ t.name === TrainTroopTask.name ||
+ !t.args.resources ||
+ maxResourcesForTask.allGreaterOrEqual(Resources.fromObject(t.args.resources))
+ );
+}
+
+function getReadyTaskRequiredResources(task: Task | undefined): Resources {
+ if (task && task.args.resources) {
+ return Resources.fromObject(task.args.resources);
+ }
+ return Resources.zero();
+}
+
function createVillageOwnState(
village: Village,
storage: VillageStorage,
taskCollection: VillageTaskCollection
): VillageOwnState {
const resources = storage.getResources();
- const resourceStorage = storage.getResourceStorage();
+ const storageResources = Resources.fromStorage(storage.getResourceStorage());
const performance = storage.getResourcesPerformance();
- const upperCriticalLevel = Resources.fromStorage(resourceStorage).sub(performance.scale(1));
- const storageOptimumFullness = Resources.fromStorage(resourceStorage).sub(performance.scale(3));
+ const upperCriticalLevel = storageResources.sub(performance.scale(1));
+ const storageOptimumFullness = storageResources.sub(performance.scale(3));
const isOverflowing = upperCriticalLevel.anyLower(resources);
- const requiredResources = taskCollection.getReadyTaskRequiredResources();
+ const queues = createAllProductionQueueStates(storage, taskCollection);
+ const firstReadyTask = getReadyForProductionTask(queues, storageOptimumFullness);
+ const requiredResources = getReadyTaskRequiredResources(firstReadyTask);
const frontierResources = taskCollection.getFrontierResources();
const totalRequiredResources = taskCollection.getAllTasksRequiredResources();
@@ -210,16 +247,17 @@ function createVillageOwnState(
village,
resources,
performance,
- storage: calcStorageBalance(resources, Resources.fromStorage(resourceStorage), performance),
- required: calcResourceBalance(requiredResources, resources, performance),
+ storage: makeStorageBalance(resources, storageResources, performance),
+ required: makeResourceBalance(requiredResources, resources, performance),
upperCriticalLevel,
storageOptimumFullness,
isOverflowing,
- frontierRequired: calcResourceBalance(frontierResources, resources, performance),
- totalRequired: calcResourceBalance(totalRequiredResources, resources, performance),
+ queues,
+ firstReadyTask,
+ frontierRequired: makeResourceBalance(frontierResources, resources, performance),
+ totalRequired: makeResourceBalance(totalRequiredResources, resources, performance),
incomingResources: calcIncomingResources(storage),
settings: storage.getSettings(),
- queues: createAllProductionQueueStates(storage, taskCollection),
};
}
diff --git a/src/VillageTaskCollection.ts b/src/VillageTaskCollection.ts
index 2f9f4fc..b06041a 100644
--- a/src/VillageTaskCollection.ts
+++ b/src/VillageTaskCollection.ts
@@ -8,9 +8,8 @@ import { ContractAttributes, ContractType } from './Core/Contract';
import { UpgradeBuildingTask } from './Task/UpgradeBuildingTask';
import { ForgeImprovementTask } from './Task/ForgeImprovementTask';
import * as _ from 'underscore';
-import { TrainTroopTask } from './Task/TrainTroopTask';
-interface QueueTasks {
+export interface QueueTasks {
queue: ProductionQueue;
tasks: Array;
finishTs: number;
@@ -61,7 +60,7 @@ export class VillageTaskCollection {
this.removeTasks(t => t.id === taskId);
}
- private getQueueGroupedTasks(): Array {
+ getQueueGroupedTasks(): Array {
const tasks = this.storage.getTasks();
const result: Array = [];
for (let queue of OrderedProductionQueues) {
@@ -74,28 +73,6 @@ export class VillageTaskCollection {
return result;
}
- getTasksInProductionQueue(queue: ProductionQueue): Array {
- return this.storage.getTasks().filter(isInQueue(queue));
- }
-
- getReadyForProductionTask(): Task | undefined {
- const groups = this.getQueueGroupedTasks();
- const nowTs = timestamp();
- const firstReadyGroup = groups.find(g => g.finishTs <= nowTs && g.tasks.length !== 0);
- if (!firstReadyGroup) {
- return undefined;
- }
-
- const maxCapacity = Resources.fromStorage(this.storage.getResourceStorage());
-
- return firstReadyGroup.tasks.find(
- t =>
- t.name === TrainTroopTask.name ||
- !t.args.resources ||
- maxCapacity.allGreaterOrEqual(Resources.fromObject(t.args.resources))
- );
- }
-
postponeTask(taskId: TaskId, seconds: number) {
const modifyTime = withTime(timestamp() + seconds);
this.modifyTasks(task => task.id === taskId, modifyTime);
@@ -116,14 +93,6 @@ export class VillageTaskCollection {
}
}
- getReadyTaskRequiredResources(): Resources {
- const first = this.getReadyForProductionTask();
- if (first && first.args.resources) {
- return Resources.fromObject(first.args.resources);
- }
- return Resources.zero();
- }
-
getFrontierResources(): Resources {
let result = Resources.zero();
const groups = this.getQueueGroupedTasks();