From af33625a5c0e927f2801a1a179b82a6418117777 Mon Sep 17 00:00:00 2001 From: Dev Date: Sun, 28 Jul 2024 00:12:04 +0100 Subject: [PATCH] Improved `pickWeaponModTplForSlotFromPool()`, now pre-sorts mod pool prior to adding it to `exhaustableModPool` and processing --- .../generators/BotEquipmentModGenerator.ts | 43 ++++++++++++++----- project/src/helpers/BotGeneratorHelper.ts | 26 +++++------ 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/project/src/generators/BotEquipmentModGenerator.ts b/project/src/generators/BotEquipmentModGenerator.ts index 01a81647..c517b202 100644 --- a/project/src/generators/BotEquipmentModGenerator.ts +++ b/project/src/generators/BotEquipmentModGenerator.ts @@ -847,12 +847,29 @@ export class BotEquipmentModGenerator { modSlotName: string, ): IChooseRandomCompatibleModResult { let chosenTpl: string; - const exhaustableModPool = new ExhaustableArray(modPool, this.randomUtil, this.cloner); + + // Filter out incompatable mods from pool + let preFilteredModPool = this.getFilteredModPool(modPool, weapon); + if (preFilteredModPool.length === 0) { + return { + incompatible: true, + found: false, + reason: `Unable to add mod to ${ModSpawn[choiceTypeEnum]} slot: ${modSlotName}. All: ${modPool.length} had conflicts`, + }; + } + + // Filter mod pool to only items that appear in parents allowed list + preFilteredModPool = preFilteredModPool.filter((tpl) => parentSlot._props.filters[0].Filter.includes(tpl)); + if (preFilteredModPool.length === 0) { + return { incompatible: true, found: false, reason: "No mods found in parents allowed list" }; + } + + // Create pool to pick mod item from + const exhaustableModPool = new ExhaustableArray(preFilteredModPool, this.randomUtil, this.cloner); let chosenModResult: IChooseRandomCompatibleModResult = { incompatible: true, found: false, reason: "unknown" }; - const modParentFilterList = parentSlot._props.filters[0].Filter; // How many times can a mod for the slot be blocked before we stop trying - const maxBlockedAttempts = Math.round(modPool.length * 0.75); // Roughly 75% of pool size + const maxBlockedAttempts = Math.round(modPool.length * 0.75); // 75% of pool size let blockedAttemptCount = 0; while (exhaustableModPool.hasValues()) { chosenTpl = exhaustableModPool.getRandomValue(); @@ -865,13 +882,6 @@ export class BotEquipmentModGenerator { break; } - // Check chosen item is on the allowed list of the parent - const isOnModParentFilterList = modParentFilterList.includes(chosenTpl); - if (!isOnModParentFilterList) { - // Try again - continue; - } - chosenModResult = this.botGeneratorHelper.isWeaponModIncompatibleWithCurrentMods( weapon, chosenTpl, @@ -905,6 +915,19 @@ export class BotEquipmentModGenerator { return chosenModResult; } + /** + * Get a list of mod tpls that are compatible with the current weapon + * @param initialModPool + * @param weapon + * @returns string array of compatible mod tpls with weapon + */ + protected getFilteredModPool(initialModPool: string[], weapon: Item[]): string[] { + const equippedItemsDb = weapon.map((item) => this.itemHelper.getItem(item._tpl)[1]); + const conflicingItemsList = equippedItemsDb.flatMap((item) => item._props.ConflictingItems); + + return initialModPool.filter((tpl) => !conflicingItemsList.includes(tpl)); + } + /** * Filter mod pool down based on various criteria: * Is slot flagged as randomisable diff --git a/project/src/helpers/BotGeneratorHelper.ts b/project/src/helpers/BotGeneratorHelper.ts index fe1cfa3e..b8190767 100644 --- a/project/src/helpers/BotGeneratorHelper.ts +++ b/project/src/helpers/BotGeneratorHelper.ts @@ -250,13 +250,18 @@ export class BotGeneratorHelper { return { Durability: currentDurability, MaxDurability: maxDurability }; } + /** + * Perform validation checks on mod tpl against rest of weapon child items + * @param weapon all items in weapon + * @param tplToCheck Chosen tpl + * @param modSlot Slot mod will be placed in + * @returns IChooseRandomCompatibleModResult + */ public isWeaponModIncompatibleWithCurrentMods( - itemsEquipped: Item[], + weapon: Item[], tplToCheck: string, modSlot: string, ): IChooseRandomCompatibleModResult { - // TODO: Can probably be optimized to cache itemTemplates as items are added to inventory - const equippedItemsDb = itemsEquipped.map((item) => this.itemHelper.getItem(item._tpl)[1]); const itemToEquipDb = this.itemHelper.getItem(tplToCheck); const itemToEquip = itemToEquipDb[1]; @@ -284,19 +289,8 @@ export class BotGeneratorHelper { return { incompatible: true, found: false, reason: `item: ${tplToCheck} does not have a _props field` }; } - // Check if any of the current weapon mod templates have the incoming item defined as incompatible - const blockingItem = equippedItemsDb.find((x) => x._props.ConflictingItems?.includes(tplToCheck)); - if (blockingItem) { - return { - incompatible: true, - found: false, - reason: `Cannot add: ${tplToCheck} ${itemToEquip._name} to slot: ${modSlot}. Blocked by: ${blockingItem._id} ${blockingItem._name}`, - slotBlocked: true, - }; - } - - // Check inverse to above, if the incoming item has any existing mods in its conflicting items array - const blockingModItem = itemsEquipped.find((item) => itemToEquip._props.ConflictingItems?.includes(item._tpl)); + // Check for existing weapon mods being incompatable with new item + const blockingModItem = weapon.find((item) => itemToEquip._props.ConflictingItems?.includes(item._tpl)); if (blockingModItem) { return { incompatible: true,