Add sending overflow resources
This commit is contained in:
parent
74cfeb6075
commit
d29e95f511
@ -9,7 +9,11 @@ import { clickSendButton, fillSendResourcesForm } from '../Page/BuildingPage/Mar
|
||||
import { VillageState } from '../VillageState';
|
||||
import { MerchantsInfo } from '../Core/Market';
|
||||
import { goToMarketSendResourcesPage, goToResourceViewPage } from '../Task/ActionBundles';
|
||||
import { ResourceTransferCalculator, ResourceTransferReport } from '../ResourceTransfer';
|
||||
import {
|
||||
compareReports,
|
||||
ResourceTransferCalculator,
|
||||
ResourceTransferReport,
|
||||
} from '../ResourceTransfer';
|
||||
import { ResourceTransferStorage } from '../Storage/ResourceTransferStorage';
|
||||
import { path } from '../Helpers/Path';
|
||||
import { MARKET_ID } from '../Core/Buildings';
|
||||
@ -29,7 +33,7 @@ export class FindSendResourcesPath extends ActionController {
|
||||
}
|
||||
}
|
||||
|
||||
reports.sort((r1, r2) => r2.score - r1.score);
|
||||
reports.sort(compareReports);
|
||||
|
||||
const bestReport = reports.shift();
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['value', 'max', 'speed'],
|
||||
props: ['value', 'warning', 'critical', 'full'],
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
@ -13,31 +13,18 @@ export default {
|
||||
return this.value;
|
||||
},
|
||||
percent() {
|
||||
return Math.floor((this.value / this.max) * 100);
|
||||
return Math.floor((this.value / this.full) * 100);
|
||||
},
|
||||
title() {
|
||||
if (this.speed < 0) {
|
||||
const time = this.fractionalHourToTime(this.value / this.speed);
|
||||
return `${this.value}, ${this.percent}%, опустеет через ${time}`;
|
||||
} else {
|
||||
const time = this.fractionalHourToTime((this.max - this.value) / this.speed);
|
||||
return `${this.value}, ${this.percent}%, заполнится через ${time}`;
|
||||
}
|
||||
return `${this.value}/${this.full}, ${this.percent}%`;
|
||||
},
|
||||
classes() {
|
||||
return {
|
||||
warning: this.percent >= 70 && this.percent < 95,
|
||||
bad: this.percent >= 95,
|
||||
warning: this.value >= this.warning && this.value < this.critical,
|
||||
bad: this.value >= this.critical,
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
fractionalHourToTime(value) {
|
||||
const hours = Math.floor(value);
|
||||
const minutes = Math.round((value - hours) * 60);
|
||||
return `${hours}:${String(minutes).padStart(2, '0')}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -30,52 +30,40 @@
|
||||
<td class="right">
|
||||
<filling
|
||||
:value="villageState.resources.lumber"
|
||||
:max="villageState.storage.capacity.lumber"
|
||||
:speed="villageState.performance.lumber"
|
||||
:warning="villageState.storageOptimumFullness.lumber"
|
||||
:critical="villageState.upperCriticalLevel.lumber"
|
||||
:full="villageState.storage.capacity.lumber"
|
||||
></filling>
|
||||
</td>
|
||||
<td class="right">
|
||||
<filling
|
||||
:value="villageState.resources.clay"
|
||||
:max="villageState.storage.capacity.clay"
|
||||
:speed="villageState.performance.clay"
|
||||
:warning="villageState.storageOptimumFullness.clay"
|
||||
:critical="villageState.upperCriticalLevel.clay"
|
||||
:full="villageState.storage.capacity.clay"
|
||||
></filling>
|
||||
</td>
|
||||
<td class="right">
|
||||
<filling
|
||||
:value="villageState.resources.iron"
|
||||
:max="villageState.storage.capacity.iron"
|
||||
:speed="villageState.performance.iron"
|
||||
:warning="villageState.storageOptimumFullness.iron"
|
||||
:critical="villageState.upperCriticalLevel.iron"
|
||||
:full="villageState.storage.capacity.iron"
|
||||
></filling>
|
||||
</td>
|
||||
<td class="right">
|
||||
<filling
|
||||
:value="villageState.resources.crop"
|
||||
:max="villageState.storage.capacity.crop"
|
||||
:speed="villageState.performance.crop"
|
||||
:warning="villageState.storageOptimumFullness.crop"
|
||||
:critical="villageState.upperCriticalLevel.crop"
|
||||
:full="villageState.storage.capacity.crop"
|
||||
></filling>
|
||||
</td>
|
||||
<td class="right" v-text="storageTime(villageState)"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr class="performance-line">
|
||||
<td class="right">Прирост:</td>
|
||||
<td class="right">
|
||||
<resource :value="villageState.performance.lumber"></resource>
|
||||
</td>
|
||||
<td class="right">
|
||||
<resource :value="villageState.performance.clay"></resource>
|
||||
</td>
|
||||
<td class="right">
|
||||
<resource :value="villageState.performance.iron"></resource>
|
||||
</td>
|
||||
<td class="right">
|
||||
<resource :value="villageState.performance.crop"></resource>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<resource-line :title="'Прирост:'" :resources="villageState.performance" />
|
||||
|
||||
<resource-line
|
||||
v-if="isExtended(villageState.id)"
|
||||
@ -84,43 +72,11 @@
|
||||
:resources="villageState.upperCriticalLevel"
|
||||
/>
|
||||
|
||||
<tr class="required-line" v-if="villageState.required.active">
|
||||
<td class="right">След. задача:</td>
|
||||
<td class="right">
|
||||
<resource
|
||||
:value="villageState.required.resources.lumber"
|
||||
:hide-zero="true"
|
||||
:color="false"
|
||||
:sign="false"
|
||||
></resource>
|
||||
</td>
|
||||
<td class="right">
|
||||
<resource
|
||||
:value="villageState.required.resources.clay"
|
||||
:hide-zero="true"
|
||||
:color="false"
|
||||
:sign="false"
|
||||
></resource>
|
||||
</td>
|
||||
<td class="right">
|
||||
<resource
|
||||
:value="villageState.required.resources.iron"
|
||||
:hide-zero="true"
|
||||
:color="false"
|
||||
:sign="false"
|
||||
></resource>
|
||||
</td>
|
||||
<td class="right">
|
||||
<resource
|
||||
:value="villageState.required.resources.crop"
|
||||
:hide-zero="true"
|
||||
:color="false"
|
||||
:sign="false"
|
||||
></resource>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<resource-line
|
||||
v-if="villageState.required.active"
|
||||
:title="'След. задача:'"
|
||||
:resources="villageState.required.resources"
|
||||
/>
|
||||
|
||||
<resource-line
|
||||
v-if="villageState.required.active"
|
||||
@ -169,6 +125,8 @@
|
||||
:title="'Крит. уровень:'"
|
||||
:hint="'Критический уровень'"
|
||||
:hide-zero="true"
|
||||
:color="false"
|
||||
:sign="false"
|
||||
:resources="villageState.upperCriticalLevel"
|
||||
/>
|
||||
|
||||
@ -177,6 +135,8 @@
|
||||
:title="'Опт. уровень:'"
|
||||
:hint="'Оптимальный уровень'"
|
||||
:hide-zero="true"
|
||||
:color="false"
|
||||
:sign="false"
|
||||
:resources="villageState.storageOptimumFullness"
|
||||
/>
|
||||
|
||||
@ -192,6 +152,11 @@
|
||||
"
|
||||
>$->{{ s.village.name }}</a
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="normal-line">
|
||||
<td class="right" colspan="7">
|
||||
<a class="village-quick-link" :href="quartersPath(villageState.village)">Казармы</a>
|
||||
<a class="village-quick-link" :href="horseStablePath(villageState.village)"
|
||||
>Конюшни</a
|
||||
|
@ -2,16 +2,16 @@
|
||||
<tr class="resource-line">
|
||||
<td class="title" v-text="title" :title="hint"></td>
|
||||
<td class="lumber">
|
||||
<resource :value="resources.lumber" :hide-zero="hideZero" />
|
||||
<resource :value="resources.lumber" :hide-zero="hideZero" :color="color" :sign="sign" />
|
||||
</td>
|
||||
<td class="clay">
|
||||
<resource :value="resources.clay" :hide-zero="hideZero" />
|
||||
<resource :value="resources.clay" :hide-zero="hideZero" :color="color" :sign="sign" />
|
||||
</td>
|
||||
<td class="iron">
|
||||
<resource :value="resources.iron" :hide-zero="hideZero" />
|
||||
<resource :value="resources.iron" :hide-zero="hideZero" :color="color" :sign="sign" />
|
||||
</td>
|
||||
<td class="crop">
|
||||
<resource :value="resources.crop" :hide-zero="hideZero" />
|
||||
<resource :value="resources.crop" :hide-zero="hideZero" :color="color" :sign="sign" />
|
||||
</td>
|
||||
<td class="time1" v-text="time1"></td>
|
||||
<td class="time2" v-text="time2"></td>
|
||||
@ -48,6 +48,14 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
color: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
sign: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,11 +1,26 @@
|
||||
import { VillageFactory } from './VillageFactory';
|
||||
import { ResourcesInterface } from './Core/Resources';
|
||||
import { Resources, ResourcesInterface } from './Core/Resources';
|
||||
import { VillageController } from './VillageController';
|
||||
|
||||
export interface ResourceTransferScore {
|
||||
amount: number;
|
||||
overflow: boolean;
|
||||
}
|
||||
|
||||
export interface ResourceTransferReport {
|
||||
fromVillageId: number;
|
||||
toVillageId: number;
|
||||
resources: ResourcesInterface;
|
||||
score: number;
|
||||
score: ResourceTransferScore;
|
||||
}
|
||||
|
||||
export function compareReports(r1: ResourceTransferReport, r2: ResourceTransferReport): number {
|
||||
if (r1.score.overflow !== r2.score.overflow) {
|
||||
const o1 = r1.score.overflow ? 1 : 0;
|
||||
const o2 = r2.score.overflow ? 1 : 0;
|
||||
return o2 - o1;
|
||||
}
|
||||
return r2.score.amount - r1.score.amount;
|
||||
}
|
||||
|
||||
export class ResourceTransferCalculator {
|
||||
@ -15,20 +30,21 @@ export class ResourceTransferCalculator {
|
||||
}
|
||||
|
||||
calc(fromVillageId: number, toVillageId: number): ResourceTransferReport {
|
||||
const senderState = this.factory.createState(fromVillageId);
|
||||
const senderController = this.factory.createController(fromVillageId);
|
||||
const senderStorage = this.factory.createStorage(fromVillageId);
|
||||
const sender = this.factory.createController(fromVillageId);
|
||||
const recipient = this.factory.createController(toVillageId);
|
||||
|
||||
const recipientController = this.factory.createController(toVillageId);
|
||||
let [senderReadyResources, recipientNeedResources] = this.getTransferResourcePair(
|
||||
sender,
|
||||
recipient
|
||||
);
|
||||
|
||||
const multiplier = sender.getSendResourcesMultiplier();
|
||||
senderReadyResources = senderReadyResources.downTo(multiplier);
|
||||
recipientNeedResources = recipientNeedResources.upTo(multiplier);
|
||||
|
||||
const multiplier = senderState.settings.sendResourcesMultiplier;
|
||||
const senderReadyResources = senderController
|
||||
.getAvailableForSendResources()
|
||||
.downTo(multiplier);
|
||||
const recipientNeedResources = recipientController.getRequiredResources().upTo(multiplier);
|
||||
const contractResources = senderReadyResources.min(recipientNeedResources);
|
||||
|
||||
const merchantsInfo = senderStorage.getMerchantsInfo();
|
||||
const merchantsInfo = sender.getMerchantsInfo();
|
||||
const merchantsCapacity = merchantsInfo.available * merchantsInfo.carry;
|
||||
|
||||
let readyToTransfer = contractResources;
|
||||
@ -50,7 +66,21 @@ export class ResourceTransferCalculator {
|
||||
fromVillageId,
|
||||
toVillageId,
|
||||
resources: readyToTransfer,
|
||||
score: readyToTransfer.amount(),
|
||||
score: {
|
||||
amount: readyToTransfer.amount(),
|
||||
overflow: sender.getState().isOverflowing,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private getTransferResourcePair(
|
||||
sender: VillageController,
|
||||
recipient: VillageController
|
||||
): [Resources, Resources] {
|
||||
if (sender.getState().isOverflowing) {
|
||||
return [sender.getOverflowResources(), recipient.getAvailableToReceiveResources()];
|
||||
}
|
||||
|
||||
return [sender.getFreeResources(), recipient.getRequiredResources()];
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,10 @@ export class ResourceTransferStorage {
|
||||
iron: 0,
|
||||
crop: 0,
|
||||
},
|
||||
score: 0,
|
||||
score: {
|
||||
amount: 0,
|
||||
overflow: false,
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
@ -5,14 +5,23 @@ import { VillageState } from './VillageState';
|
||||
import { Resources } from './Core/Resources';
|
||||
import { TryLaterError } from './Errors';
|
||||
import { aroundMinutes } from './utils';
|
||||
import { MerchantsInfo } from './Core/Market';
|
||||
import { VillageStorage } from './Storage/VillageStorage';
|
||||
|
||||
export class VillageController {
|
||||
private readonly villageId: number;
|
||||
private readonly storage: VillageStorage;
|
||||
private readonly taskCollection: VillageTaskCollection;
|
||||
private readonly state: VillageState;
|
||||
|
||||
constructor(villageId: number, taskCollection: VillageTaskCollection, state: VillageState) {
|
||||
constructor(
|
||||
villageId: number,
|
||||
storage: VillageStorage,
|
||||
taskCollection: VillageTaskCollection,
|
||||
state: VillageState
|
||||
) {
|
||||
this.villageId = villageId;
|
||||
this.storage = storage;
|
||||
this.taskCollection = taskCollection;
|
||||
this.state = state;
|
||||
}
|
||||
@ -21,6 +30,10 @@ export class VillageController {
|
||||
return this.villageId;
|
||||
}
|
||||
|
||||
getState(): VillageState {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
getReadyProductionTask(): Task | undefined {
|
||||
return this.taskCollection.getReadyForProductionTask();
|
||||
}
|
||||
@ -37,7 +50,22 @@ export class VillageController {
|
||||
this.taskCollection.postponeTask(taskId, seconds);
|
||||
}
|
||||
|
||||
getAvailableForSendResources(): Resources {
|
||||
getMerchantsInfo(): MerchantsInfo {
|
||||
return this.storage.getMerchantsInfo();
|
||||
}
|
||||
|
||||
getSendResourcesMultiplier(): number {
|
||||
return this.state.settings.sendResourcesMultiplier;
|
||||
}
|
||||
|
||||
getOverflowResources(): Resources {
|
||||
const limit = this.state.storageOptimumFullness;
|
||||
const currentResources = this.state.resources;
|
||||
|
||||
return currentResources.sub(limit).max(Resources.zero());
|
||||
}
|
||||
|
||||
getFreeResources(): Resources {
|
||||
const balance = this.state.required.balance;
|
||||
const free = balance.max(Resources.zero());
|
||||
|
||||
@ -57,11 +85,11 @@ export class VillageController {
|
||||
}
|
||||
|
||||
getRequiredResources(): Resources {
|
||||
const performance = this.state.performance;
|
||||
const maxPossibleToStore = this.state.storage.capacity.sub(performance);
|
||||
const maxPossibleToStore = this.state.storageOptimumFullness;
|
||||
const currentResources = this.state.resources;
|
||||
const incomingResources = this.state.incomingResources;
|
||||
const requirementResources = this.state.required.resources;
|
||||
|
||||
const missingResources = requirementResources
|
||||
.min(maxPossibleToStore)
|
||||
.sub(incomingResources)
|
||||
@ -78,4 +106,11 @@ export class VillageController {
|
||||
|
||||
return missingResources;
|
||||
}
|
||||
|
||||
getAvailableToReceiveResources(): Resources {
|
||||
const maxPossibleToStore = this.state.storageOptimumFullness;
|
||||
const currentResources = this.state.resources;
|
||||
|
||||
return maxPossibleToStore.sub(currentResources).max(Resources.zero());
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ export class VillageFactory {
|
||||
const village = this.villageRepository.get(villageId);
|
||||
return new VillageController(
|
||||
village.id,
|
||||
this.createStorage(village.id),
|
||||
this.createTaskCollection(village.id),
|
||||
this.createState(village.id)
|
||||
);
|
||||
|
@ -67,6 +67,7 @@ interface VillageOwnState {
|
||||
storage: VillageStorageState;
|
||||
upperCriticalLevel: Resources;
|
||||
storageOptimumFullness: Resources;
|
||||
isOverflowing: boolean;
|
||||
/**
|
||||
* Required resources for nearest task
|
||||
*/
|
||||
@ -197,8 +198,9 @@ function createVillageOwnState(
|
||||
const resources = storage.getResources();
|
||||
const resourceStorage = storage.getResourceStorage();
|
||||
const performance = storage.getResourcesPerformance();
|
||||
const upperCriticalLevel = Resources.fromStorage(resourceStorage).sub(performance.scale(2));
|
||||
const storageOptimumFullness = Resources.fromStorage(resourceStorage).sub(performance.scale(3));
|
||||
const upperCriticalLevel = Resources.fromStorage(resourceStorage).sub(performance.scale(1));
|
||||
const storageOptimumFullness = Resources.fromStorage(resourceStorage).sub(performance.scale(2));
|
||||
const isOverflowing = upperCriticalLevel.anyLower(resources);
|
||||
const requiredResources = taskCollection.getReadyTaskRequiredResources();
|
||||
const frontierResources = taskCollection.getFrontierResources();
|
||||
const totalRequiredResources = taskCollection.getAllTasksRequiredResources();
|
||||
@ -212,6 +214,7 @@ function createVillageOwnState(
|
||||
required: calcResourceBalance(requiredResources, resources, performance),
|
||||
upperCriticalLevel,
|
||||
storageOptimumFullness,
|
||||
isOverflowing,
|
||||
frontierRequired: calcResourceBalance(frontierResources, resources, performance),
|
||||
totalRequired: calcResourceBalance(totalRequiredResources, resources, performance),
|
||||
incomingResources: calcIncomingResources(storage),
|
||||
|
Loading…
Reference in New Issue
Block a user