diff --git a/project/src/generators/BotLootGenerator.ts b/project/src/generators/BotLootGenerator.ts index 646159a2..7c73d131 100644 --- a/project/src/generators/BotLootGenerator.ts +++ b/project/src/generators/BotLootGenerator.ts @@ -344,7 +344,7 @@ export class BotLootGenerator this.randomiseAmmoStackSize(isPmc, itemToAddTemplate, itemsToAdd[0]); } // Must add soft inserts/plates - else if (this.itemHelper.itemCanRequireArmorInserts(itemToAddTemplate._id)) + else if (this.itemHelper.itemRequiresSoftInserts(itemToAddTemplate._id)) { itemsToAdd = this.itemHelper.addChildSlotItems(itemsToAdd, itemToAddTemplate, null, true); } diff --git a/project/src/generators/LocationGenerator.ts b/project/src/generators/LocationGenerator.ts index fd223ec6..2c2f4455 100644 --- a/project/src/generators/LocationGenerator.ts +++ b/project/src/generators/LocationGenerator.ts @@ -861,7 +861,7 @@ export class LocationGenerator ); itemWithMods.push(...magazineItem); } - else if (this.itemHelper.itemCanRequireArmorInserts(chosenTpl)) + else if (this.itemHelper.armorItemCanHoldMods(chosenTpl)) { itemWithMods.push({ _id: this.objectId.generate(), @@ -1071,8 +1071,9 @@ export class LocationGenerator // Replace existing magazine with above array items.splice(items.indexOf(items[0]), 1, ...magazineWithCartridges); } - else if (this.itemHelper.itemCanRequireArmorInserts(chosenTpl)) + else if (this.itemHelper.armorItemCanHoldMods(chosenTpl)) { + // We make base item above, at start of function, no need to do it here if (itemTemplate._props.Slots?.length > 0) { items = this.itemHelper.addChildSlotItems(items, itemTemplate, this.locationConfig.equipmentLootSettings.modSpawnChancePercent); diff --git a/project/src/helpers/ItemHelper.ts b/project/src/helpers/ItemHelper.ts index 98ff427e..bf06224e 100644 --- a/project/src/helpers/ItemHelper.ts +++ b/project/src/helpers/ItemHelper.ts @@ -105,11 +105,47 @@ export class ItemHelper * @param itemTpl item to check * @returns Does item have the possibility ot need soft inserts */ - public itemCanRequireArmorInserts(itemTpl: string): boolean + public armorItemCanHoldMods(itemTpl: string): boolean { return this.isOfBaseclasses(itemTpl, [BaseClasses.HEADWEAR, BaseClasses.VEST, BaseClasses.ARMOR]); } + /** + * Does the provided item tpl require soft inserts to become a valid armor item + * @param itemTpl Item tpl to check + * @returns True if it needs armor inserts + */ + public itemRequiresSoftInserts(itemTpl: string): boolean + { + // not a slot that takes soft-inserts + if (!this.armorItemCanHoldMods(itemTpl)) + { + return false; + } + + // Check is an item + const itemDbDetails = this.getItem(itemTpl); + if (!itemDbDetails[0]) + { + return false; + } + + // Has no slots + if (!(itemDbDetails[1]._props.Slots ?? []).length) + { + return false; + } + + // Check if item has slots that match soft insert name ids + const softInsertSlotIds = ["groin", "soft_armor_back", "soft_armor_front", "soft_armor_left", "soft_armor_right", "shoulder_l", "shoulder_r", "collar"]; + if (itemDbDetails[1]._props.Slots.find(slot => softInsertSlotIds.includes(slot._name.toLowerCase()))) + { + return true; + } + + return false; + } + /** * Returns the item price based on the handbook or as a fallback from the prices.json if the item is not * found in the handbook. If the price can't be found at all return 0 diff --git a/project/src/helpers/QuestHelper.ts b/project/src/helpers/QuestHelper.ts index 2672984a..5cfbb775 100644 --- a/project/src/helpers/QuestHelper.ts +++ b/project/src/helpers/QuestHelper.ts @@ -267,8 +267,8 @@ export class QuestHelper const mods: Item[] = []; const rootItem = questReward.items[0]; - // Is armor item that needs inserts / plates - if (questReward.items.length === 1 && this.itemHelper.itemCanRequireArmorInserts(rootItem._tpl)) + // Is armor item that may need inserts / plates + if (questReward.items.length === 1 && this.itemHelper.armorItemCanHoldMods(rootItem._tpl)) { // Attempt to pull default preset from globals and add child items to reward this.generateArmorRewardChildSlots(rootItem, questReward); diff --git a/project/src/services/FenceService.ts b/project/src/services/FenceService.ts index aeb4c7d9..c41ebfee 100644 --- a/project/src/services/FenceService.ts +++ b/project/src/services/FenceService.ts @@ -403,7 +403,7 @@ export class FenceService protected createAssorts(assortCount: number, assorts: ITraderAssort, loyaltyLevel: number): void { const fenceAssort = this.databaseServer.getTables().traders[Traders.FENCE].assort; - const defaultWeaponPresets = this.presetHelper.getDefaultPresets(); + const defaultPresets = this.presetHelper.getDefaultPresets(); const fenceAssortIds = Object.keys(fenceAssort.loyal_level_items); const itemTypeCounts = this.initItemLimitCounter(this.traderConfig.fence.itemTypeLimits); @@ -412,7 +412,7 @@ export class FenceService // Add presets const maxPresetCount = Math.round(assortCount * (this.traderConfig.fence.maxPresetsPercent / 100)); const randomisedPresetCount = this.randomUtil.getInt(0, maxPresetCount); - this.addPresets(randomisedPresetCount, defaultWeaponPresets, assorts, loyaltyLevel); + this.addPresets(randomisedPresetCount, defaultPresets, assorts, loyaltyLevel); } protected addItemAssorts( @@ -481,7 +481,7 @@ export class FenceService rootItemToPush.upd.UnlimitedCount = false; // Need to add mods to armors so they dont show as red in the trade screen - if (this.itemHelper.itemCanRequireArmorInserts(rootItemToPush._tpl)) + if (this.itemHelper.itemRequiresSoftInserts(rootItemToPush._tpl)) { this.addModsToArmorModSlots(itemsToPush, itemDbDetails); } @@ -594,25 +594,25 @@ export class FenceService } /** - * Add preset weapons to fence presets + * Add weapon/armor presets to fence * @param assortCount how many assorts to add to assorts - * @param defaultWeaponPresets a dictionary of default weapon presets + * @param defaultPresets a dictionary of default weapon presets * @param assorts object to add presets to * @param loyaltyLevel loyalty level to requre item at */ protected addPresets( desiredPresetCount: number, - defaultWeaponPresets: Record, + defaultPresets: Record, assorts: ITraderAssort, loyaltyLevel: number, ): void { let presetCount = 0; - const presetKeys = Object.keys(defaultWeaponPresets); + const presetKeys = Object.keys(defaultPresets); for (let index = 0; index < desiredPresetCount; index++) { const presetId = presetKeys[this.randomUtil.getInt(0, presetKeys.length - 1)]; - const preset = defaultWeaponPresets[presetId]; + const preset = defaultPresets[presetId]; // Check we're under preset limit if (presetCount > desiredPresetCount) @@ -626,12 +626,12 @@ export class FenceService continue; } - // Construct weapon + mods + // Construct preset + mods const weaponAndMods: Item[] = this.itemHelper.replaceIDs( null, - this.jsonUtil.clone(defaultWeaponPresets[preset._id]._items), + this.jsonUtil.clone(defaultPresets[preset._id]._items), ); - this.removeRandomPartsOfWeapon(weaponAndMods); + this.removeRandomModsOfItem(weaponAndMods); for (let i = 0; i < weaponAndMods.length; i++) { const mod = weaponAndMods[i]; @@ -676,42 +676,48 @@ export class FenceService /** * Remove parts of a weapon prior to being listed on flea - * @param weaponAndMods Weapon to remove parts from + * @param itemAndMods Weapon to remove parts from */ - protected removeRandomPartsOfWeapon(weaponAndMods: Item[]): void + protected removeRandomModsOfItem(itemAndMods: Item[]): void { // Items to be removed from inventory const toDelete: string[] = []; - // Loop over insurance items, find items to delete from player inventory - for (const weaponMod of weaponAndMods) + // Find mods to remove from item that could've been scavenged by other players in-raid + for (const itemMod of itemAndMods) { - if (this.presetModItemWillBeRemoved(weaponMod, toDelete)) + if (this.presetModItemWillBeRemoved(itemMod, toDelete)) { // Skip if not an item - const itemDbDetails = this.itemHelper.getItem(weaponMod._tpl); + const itemDbDetails = this.itemHelper.getItem(itemMod._tpl); if (!itemDbDetails[0]) { continue; } // Is a mod and can't be edited in-raid - if (weaponMod.slotId !== "hideout" && !itemDbDetails[1]._props.RaidModdable) + if (itemMod.slotId !== "hideout" && !itemDbDetails[1]._props.RaidModdable) + { + continue; + } + + const slotDetails = itemDbDetails[1]._props.Slots.find(slot => slot._name === itemMod.slotId); + if (slotDetails?._required) { continue; } // Remove item and its sub-items to prevent orphans - toDelete.push(...this.itemHelper.findAndReturnChildrenByItems(weaponAndMods, weaponMod._id)); + toDelete.push(...this.itemHelper.findAndReturnChildrenByItems(itemAndMods, itemMod._id)); } } // Reverse loop and remove items - for (let index = weaponAndMods.length - 1; index >= 0; --index) + for (let index = itemAndMods.length - 1; index >= 0; --index) { - if (toDelete.includes(weaponAndMods[index]._id)) + if (toDelete.includes(itemAndMods[index]._id)) { - weaponAndMods.splice(index, 1); + itemAndMods.splice(index, 1); } } } diff --git a/project/src/services/InsuranceService.ts b/project/src/services/InsuranceService.ts index 09c63d5e..b1afff83 100644 --- a/project/src/services/InsuranceService.ts +++ b/project/src/services/InsuranceService.ts @@ -302,7 +302,7 @@ export class InsuranceService if (itemClientInsuranceData || itemIsSoftInsert) { - // Get baseline item to return, clone pre raid item + // Get baseline item to return, clone pre-raid item const itemToReturn: Item = this.jsonUtil.clone(preRaidItem); // Add upd if it doesnt exist @@ -311,7 +311,7 @@ export class InsuranceService itemToReturn.upd = {}; } - // Check for slotid values that need to be updated and adjust + // Check for slotId values that need to be updated and adjust this.updateSlotIdValue(pmcData.Inventory.equipment, itemToReturn); // Remove location property