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

Improved performance of completion quests picking items to return

(cherry picked from commit f04382c9bb9722645a1954ec12d34d45f31d2c53)
This commit is contained in:
Dev 2024-08-15 11:09:42 +01:00
parent 093afe002c
commit 37fb49bffa

View File

@ -28,6 +28,7 @@ import { inject, injectable } from "tsyringe";
@injectable()
export class RepeatableQuestGenerator {
protected questConfig: IQuestConfig;
protected maxRandomNumberAttempts = 6;
constructor(
@inject("PrimaryLogger") protected logger: ILogger,
@ -516,24 +517,44 @@ export class RepeatableQuestGenerator {
// Draw items to ask player to retrieve
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++) {
let randomNumber = this.randomUtil.randInt(itemSelection.length);
while (randomNumbersUsed.includes(randomNumber) && randomNumbersUsed.length !== itemSelection.length) {
randomNumber = this.randomUtil.randInt(itemSelection.length);
let chosenItemIndex = this.randomUtil.randInt(itemSelection.length);
let found = false;
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]);
let minValue = completionConfig.minRequestedAmount;
let maxValue = completionConfig.maxRequestedAmount;
if (this.itemHelper.isOfBaseclass(itemSelected[0], BaseClasses.AMMO)) {
// Prevent multiple ammo requirements from being picked, stop after 6 attempts
if (isAmmo > 0 && isAmmo < 6) {
// Prevent multiple ammo requirements from being picked
if (isAmmo > 0 && isAmmo < this.maxRandomNumberAttempts) {
isAmmo++;
i--;
continue;
}
isAmmo++;
@ -542,21 +563,23 @@ export class RepeatableQuestGenerator {
}
let value = minValue;
// get the value range within budget
// Get the value range within budget
maxValue = Math.min(maxValue, Math.floor(roublesBudget / itemUnitPrice));
if (maxValue > minValue) {
// if it doesn't blow the budget we have for the request, draw a random amount of the selected
// item type to be requested
// If it doesn't blow the budget we have for the request, draw a random amount of the selected
// Item type to be requested
value = this.randomUtil.randInt(minValue, maxValue + 1);
}
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));
if (roublesBudget > 0) {
// reduce the list possible items to fulfill the new budget constraint
itemSelection = itemSelection.filter((x) => this.itemHelper.getItemPrice(x[0]) < roublesBudget);
// Reduce the list possible items to fulfill the new budget constraint
itemSelection = itemSelection.filter(
(dbItem) => this.itemHelper.getItemPrice(dbItem[0]) < roublesBudget,
);
if (itemSelection.length === 0) {
break;
}