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()
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;
}