diff --git a/project/assets/configs/location.json b/project/assets/configs/location.json index aa88bed2..da95d927 100644 --- a/project/assets/configs/location.json +++ b/project/assets/configs/location.json @@ -1100,9 +1100,13 @@ }, "equipmentLootSettings": { "modSpawnChancePercent": { - "mod_nvg": 20, + "mod_nvg": 5, "front_plate": 50, - "back_plate": 50 + "back_plate": 50, + "mod_equipment_000": 5, + "mod_equipment_001": 5, + "mod_equipment_002": 5, + "mod_mount": 5 } } } diff --git a/project/src/generators/BotLootGenerator.ts b/project/src/generators/BotLootGenerator.ts index df647cc3..73fb8cba 100644 --- a/project/src/generators/BotLootGenerator.ts +++ b/project/src/generators/BotLootGenerator.ts @@ -346,15 +346,7 @@ export class BotLootGenerator // Must add soft inserts/plates else if (this.itemHelper.isOfBaseclasses(itemToAddTemplate._id, [BaseClasses.ARMOR, BaseClasses.HEADWEAR, BaseClasses.VEST])) { - // TODO - replace with config values - const modIncludeedChances = { - mod_nvg: 10, - front_plate: 10, - back_plate: 10, - side_plate: 10 - - } - itemsToAdd = this.itemHelper.addChildSlotItems(itemsToAdd, itemToAddTemplate, modIncludeedChances); + itemsToAdd = this.itemHelper.addChildSlotItems(itemsToAdd, itemToAddTemplate, null, true); } // Attempt to add item to container(s) diff --git a/project/src/helpers/ItemHelper.ts b/project/src/helpers/ItemHelper.ts index b00ddfa9..6794fdf4 100644 --- a/project/src/helpers/ItemHelper.ts +++ b/project/src/helpers/ItemHelper.ts @@ -1173,13 +1173,21 @@ export class ItemHelper * @param itemToAdd array with single object (root item) * @param itemToAddTemplate Db tempalte for root item * @param modSpawnChanceDict Optional dictionary of mod name + % chance mod will be included in item (e.g. front_plate: 100) - * @returns + * @param requiredOnly Only add required mods + * @returns Item with children */ - public addChildSlotItems(itemToAdd: Item[], itemToAddTemplate: ITemplateItem, modSpawnChanceDict: Record = null): Item[] + public addChildSlotItems(itemToAdd: Item[], itemToAddTemplate: ITemplateItem, modSpawnChanceDict: Record = null, requiredOnly = false): Item[] { const result = itemToAdd; + const incompatibleModTpls: Set = new Set(); for (const slot of itemToAddTemplate._props.Slots) { + // If only required mods is requested, skip non-essential + if (requiredOnly && !slot._required) + { + continue; + } + // Roll chance for non-required slot mods if (modSpawnChanceDict && !slot._required) { @@ -1194,26 +1202,68 @@ export class ItemHelper } } - const possibleTplsForSlot = slot._props.filters[0].Filter ?? []; - if (possibleTplsForSlot.length === 0) + const itemPool = slot._props.filters[0].Filter ?? []; + const chosenTpl = this.getCompatibleTplFromArray(itemPool, incompatibleModTpls); + if (!chosenTpl) { - this.logger.warning(`Unable to add mod to item: ${itemToAddTemplate._id} ${itemToAddTemplate._name} slot: ${slot._name} as the db pool is empty, skipping`); + this.logger.debug(`Unable to add mod to item: ${itemToAddTemplate._id} ${itemToAddTemplate._name} slot: ${slot._name} as no compatible tpl could be found in pool of ${itemPool.length}, skipping`); continue; } - result.push( - { - _id: this.hashUtil.generate(), - _tpl: this.randomUtil.getArrayValue(possibleTplsForSlot), // Choose random tpl from array of compatible - parentId: result[0]._id, - slotId: slot._name - } - ) + const moditemToAdd = { + _id: this.hashUtil.generate(), + _tpl: chosenTpl, + parentId: result[0]._id, + slotId: slot._name + }; + result.push(moditemToAdd); + + const modItemDbDetails = this.getItem(moditemToAdd._tpl)[1]; + + // Include conflicting items of newly added mod in pool to be used for next mod choice + // biome-ignore lint/complexity/noForEach: + modItemDbDetails._props.ConflictingItems.forEach(incompatibleModTpls.add, incompatibleModTpls); } return result; } + + /** + * Get a compatible tpl from the array provided where it is not found in the provided incompatible mod tpls parameter + * @param possibleTpls Tpls to randomply choose from + * @param incompatibleModTpls Incompatible tpls to not allow + * @returns Chosen tpl or null + */ + public getCompatibleTplFromArray(possibleTpls: string[], incompatibleModTpls: Set): string + { + if (possibleTpls.length === 0) + { + return null; + } + + let chosenTpl = null; + let count = 0; + while (!chosenTpl) + { + // Loop over choosing a random tpl until one is found or count varaible reaches the same size as the possible tpls array + const tpl = this.randomUtil.getArrayValue(possibleTpls); + if (incompatibleModTpls.has(tpl)) + { + // Incompatible tpl was chosen, try again + count++ + if (count >= possibleTpls.length) + { + return null; + } + continue; + } + + chosenTpl = tpl; + } + + return chosenTpl; + } } namespace ItemHelper