Fixed issue that would cause repeatable completion quests to get stuck in an infinite loop

Improved performance of completion quests picking items to return
This commit is contained in:
Dev 2024-08-15 11:09:42 +01:00
parent f46694a169
commit f04382c9bb

View File

@ -28,6 +28,7 @@ import { inject, injectable } from "tsyringe";
@injectable() @injectable()
export class RepeatableQuestGenerator { export class RepeatableQuestGenerator {
protected questConfig: IQuestConfig; protected questConfig: IQuestConfig;
protected maxRandomNumberAttempts = 6;
constructor( constructor(
@inject("PrimaryLogger") protected logger: ILogger, @inject("PrimaryLogger") protected logger: ILogger,
@ -516,24 +517,44 @@ export class RepeatableQuestGenerator {
// Draw items to ask player to retrieve // Draw items to ask player to retrieve
let isAmmo = 0; let isAmmo = 0;
const randomNumbersUsed = [];
// Store the indexes of items we are asking player to provide
const usedItemIndexes = new Set();
for (let i = 0; i < distinctItemsToRetrieveCount; i++) { for (let i = 0; i < distinctItemsToRetrieveCount; i++) {
let randomNumber = this.randomUtil.randInt(itemSelection.length); let chosenItemIndex = this.randomUtil.randInt(itemSelection.length);
while (randomNumbersUsed.includes(randomNumber) && randomNumbersUsed.length !== itemSelection.length) { let found = false;
randomNumber = this.randomUtil.randInt(itemSelection.length);
for (let i = 0; i < this.maxRandomNumberAttempts; i++) {
if (usedItemIndexes.has(chosenItemIndex)) {
chosenItemIndex = this.randomUtil.randInt(itemSelection.length);
} else {
found = true;
break;
}
} }
randomNumbersUsed.push(randomNumber); if (!found) {
this.logger.error(
this.localisationService.getText("repeatable-no_reward_item_found_in_price_range", {
minPrice: 0,
roublesBudget: roublesBudget,
}),
);
const itemSelected = itemSelection[randomNumber]; return undefined;
}
usedItemIndexes.add(chosenItemIndex);
const itemSelected = itemSelection[chosenItemIndex];
const itemUnitPrice = this.itemHelper.getItemPrice(itemSelected[0]); const itemUnitPrice = this.itemHelper.getItemPrice(itemSelected[0]);
let minValue = completionConfig.minRequestedAmount; let minValue = completionConfig.minRequestedAmount;
let maxValue = completionConfig.maxRequestedAmount; let maxValue = completionConfig.maxRequestedAmount;
if (this.itemHelper.isOfBaseclass(itemSelected[0], BaseClasses.AMMO)) { if (this.itemHelper.isOfBaseclass(itemSelected[0], BaseClasses.AMMO)) {
// Prevent multiple ammo requirements from being picked, stop after 6 attempts // Prevent multiple ammo requirements from being picked
if (isAmmo > 0 && isAmmo < 6) { if (isAmmo > 0 && isAmmo < this.maxRandomNumberAttempts) {
isAmmo++; isAmmo++;
i--; i--;
continue; continue;
} }
isAmmo++; isAmmo++;
@ -542,21 +563,23 @@ export class RepeatableQuestGenerator {
} }
let value = minValue; let value = minValue;
// get the value range within budget // Get the value range within budget
maxValue = Math.min(maxValue, Math.floor(roublesBudget / itemUnitPrice)); maxValue = Math.min(maxValue, Math.floor(roublesBudget / itemUnitPrice));
if (maxValue > minValue) { if (maxValue > minValue) {
// if it doesn't blow the budget we have for the request, draw a random amount of the selected // If it doesn't blow the budget we have for the request, draw a random amount of the selected
// item type to be requested // Item type to be requested
value = this.randomUtil.randInt(minValue, maxValue + 1); value = this.randomUtil.randInt(minValue, maxValue + 1);
} }
roublesBudget -= value * itemUnitPrice; roublesBudget -= value * itemUnitPrice;
// push a CompletionCondition with the item and the amount of the item // Push a CompletionCondition with the item and the amount of the item
quest.conditions.AvailableForFinish.push(this.generateCompletionAvailableForFinish(itemSelected[0], value)); quest.conditions.AvailableForFinish.push(this.generateCompletionAvailableForFinish(itemSelected[0], value));
if (roublesBudget > 0) { if (roublesBudget > 0) {
// reduce the list possible items to fulfill the new budget constraint // Reduce the list possible items to fulfill the new budget constraint
itemSelection = itemSelection.filter((x) => this.itemHelper.getItemPrice(x[0]) < roublesBudget); itemSelection = itemSelection.filter(
(dbItem) => this.itemHelper.getItemPrice(dbItem[0]) < roublesBudget,
);
if (itemSelection.length === 0) { if (itemSelection.length === 0) {
break; break;
} }