diff --git a/project/src/generators/LootGenerator.ts b/project/src/generators/LootGenerator.ts index e92392d2..3065af69 100644 --- a/project/src/generators/LootGenerator.ts +++ b/project/src/generators/LootGenerator.ts @@ -2,12 +2,13 @@ import { InventoryHelper } from "@spt/helpers/InventoryHelper"; import { ItemHelper } from "@spt/helpers/ItemHelper"; import { PresetHelper } from "@spt/helpers/PresetHelper"; import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper"; +import { MinMax } from "@spt/models/common/MinMax"; import { IPreset } from "@spt/models/eft/common/IGlobals"; import { IItem } from "@spt/models/eft/common/tables/IItem"; import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem"; import { BaseClasses } from "@spt/models/enums/BaseClasses"; import { ISealedAirdropContainerSettings, RewardDetails } from "@spt/models/spt/config/IInventoryConfig"; -import { LootRequest } from "@spt/models/spt/services/LootRequest"; +import { ILootRequest } from "@spt/models/spt/services/ILootRequest"; import { ILogger } from "@spt/models/spt/utils/ILogger"; import { DatabaseService } from "@spt/services/DatabaseService"; import { ItemFilterService } from "@spt/services/ItemFilterService"; @@ -40,7 +41,7 @@ export class LootGenerator { * @param options parameters to adjust how loot is generated * @returns An array of loot items */ - public createRandomLoot(options: LootRequest): IItem[] { + public createRandomLoot(options: ILootRequest): IItem[] { const result: IItem[] = []; const itemTypeCounts = this.initItemLimitCounter(options.itemLimits); @@ -74,7 +75,7 @@ export class LootGenerator { const { itemPool, blacklist } = this.getItemRewardPool( options.itemBlacklist, options.itemTypeWhitelist, - options.useRewarditemBlacklist, + options.useRewardItemBlacklist, options.allowBossItems, ); @@ -153,13 +154,19 @@ export class LootGenerator { return result; } - public createForcedLoot(airdropConfig: LootRequest) { + /** + * Generate An array of items + * TODO - handle weapon presets/ammo packs + * @param forcedLootDict Dictionary of item tpls with minmax values + * @returns Array of IItem + */ + public createForcedLoot(forcedLootDict: Record): IItem[] { const result: IItem[] = []; - const forcedItems = Object.keys(airdropConfig.forcedLoot); + const forcedItems = Object.keys(forcedLootDict); for (const tpl of forcedItems) { - const details = airdropConfig.forcedLoot[tpl]; + const details = forcedLootDict[tpl]; const randomisedItemCount = this.randomUtil.getInt(details.min, details.max); // Add forced loot item to result @@ -179,6 +186,14 @@ export class LootGenerator { return result; } + /** + * Get pool of items from item db that fit passed in param criteria + * @param itemTplBlacklist Prevent these items + * @param itemTypeWhitelist Only allow these items + * @param useRewardItemBlacklist Should item.json reward item config be used + * @param allowBossItems Should boss items be allowed in result + * @returns results of filtering + blacklist used + */ protected getItemRewardPool( itemTplBlacklist: string[], itemTypeWhitelist: string[], @@ -216,7 +231,7 @@ export class LootGenerator { * @param options Loot request options - armor level etc * @returns True if item has desired armor level */ - protected isArmorOfDesiredProtectionLevel(armor: IPreset, options: LootRequest): boolean { + protected isArmorOfDesiredProtectionLevel(armor: IPreset, options: ILootRequest): boolean { const relevantSlots = ["front_plate", "helmet_top", "soft_armor_front"]; for (const slotId of relevantSlots) { const armorItem = armor._items.find((item) => item?.slotId?.toLowerCase() === slotId); @@ -258,7 +273,7 @@ export class LootGenerator { protected findAndAddRandomItemToLoot( items: [string, ITemplateItem][], itemTypeCounts: Record, - options: LootRequest, + options: ILootRequest, result: IItem[], ): boolean { const randomItem = this.randomUtil.getArrayValue(items)[1]; @@ -305,7 +320,7 @@ export class LootGenerator { * @param options loot options * @returns stack count */ - protected getRandomisedStackCount(item: ITemplateItem, options: LootRequest): number { + protected getRandomisedStackCount(item: ITemplateItem, options: ILootRequest): number { let min = item._props.StackMinRandom; let max = item._props.StackMaxSize; diff --git a/project/src/models/spt/config/ITraderConfig.ts b/project/src/models/spt/config/ITraderConfig.ts index 88516d8a..9ae08169 100644 --- a/project/src/models/spt/config/ITraderConfig.ts +++ b/project/src/models/spt/config/ITraderConfig.ts @@ -1,6 +1,6 @@ import { MinMax } from "@spt/models/common/MinMax"; import { IBaseConfig } from "@spt/models/spt/config/IBaseConfig"; -import { LootRequest } from "@spt/models/spt/services/LootRequest"; +import { ILootRequest } from "@spt/models/spt/services/ILootRequest"; export interface ITraderConfig extends IBaseConfig { kind: "spt-trader"; @@ -57,7 +57,7 @@ export interface IItemDurabilityCurrentMax { max: MinMax; } -export interface CoopExtractReward extends LootRequest { +export interface CoopExtractReward extends ILootRequest { sendGift: boolean; messageLocaleIds: string[]; giftExpiryHours: number; diff --git a/project/src/models/spt/services/ILootRequest.ts b/project/src/models/spt/services/ILootRequest.ts new file mode 100644 index 00000000..4d9f8215 --- /dev/null +++ b/project/src/models/spt/services/ILootRequest.ts @@ -0,0 +1,35 @@ +import { MinMax } from "@spt/models/common/MinMax"; +import { AirdropTypeEnum } from "@spt/models/enums/AirdropType"; + +export interface ILootRequest { + /** Count of weapons to generate */ + weaponPresetCount: MinMax; + /** Count of armor to generate */ + armorPresetCount: MinMax; + /** Count of items to generate */ + itemCount: MinMax; + /** Count of sealed weapon crates to generate */ + weaponCrateCount: MinMax; + /** Item tpl blacklist to exclude */ + itemBlacklist: string[]; + /** Item tpl whitelist to pick from */ + itemTypeWhitelist: string[]; + /** key: item base type: value: max count */ + itemLimits: Record; + itemStackLimits: Record; + /** Allowed armor plate levels 2/3/4/5/6 for armor generated */ + armorLevelWhitelist: number[]; + /** Should boss items be included in allowed items */ + allowBossItems: boolean; + /** Should item.json item reward blacklist be used */ + useRewardItemBlacklist?: boolean; + /** Should forced loot be used instead of randomised loot */ + useForcedLoot?: boolean; + /** Item tpls + count of items to force include */ + forcedLoot?: Record; +} + +export interface IAirdropLootRequest extends ILootRequest { + /** Airdrop icon used by client to show crate type */ + icon?: AirdropTypeEnum; +} diff --git a/project/src/models/spt/services/LootRequest.ts b/project/src/models/spt/services/LootRequest.ts deleted file mode 100644 index f0d62ee7..00000000 --- a/project/src/models/spt/services/LootRequest.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MinMax } from "@spt/models/common/MinMax"; -import { AirdropTypeEnum } from "@spt/models/enums/AirdropType"; - -export interface LootRequest { - weaponPresetCount: MinMax; - armorPresetCount: MinMax; - itemCount: MinMax; - weaponCrateCount: MinMax; - itemBlacklist: string[]; - itemTypeWhitelist: string[]; - /** key: item base type: value: max count */ - itemLimits: Record; - itemStackLimits: Record; - armorLevelWhitelist: number[]; - allowBossItems: boolean; - useRewarditemBlacklist?: boolean; - useForcedLoot?: boolean; - forcedLoot?: Record; -} - -export interface IAirdropLootRequest extends LootRequest { - icon?: AirdropTypeEnum; -} diff --git a/project/src/services/AirdropService.ts b/project/src/services/AirdropService.ts index 466e89bc..0f6fe349 100644 --- a/project/src/services/AirdropService.ts +++ b/project/src/services/AirdropService.ts @@ -8,7 +8,7 @@ import { AirdropTypeEnum, SptAirdropTypeEnum } from "@spt/models/enums/AirdropTy import { ConfigTypes } from "@spt/models/enums/ConfigTypes"; import { ItemTpl } from "@spt/models/enums/ItemTpl"; import { IAirdropConfig, IAirdropLoot } from "@spt/models/spt/config/IAirdropConfig"; -import { IAirdropLootRequest, LootRequest } from "@spt/models/spt/services/LootRequest"; +import { IAirdropLootRequest, ILootRequest } from "@spt/models/spt/services/ILootRequest"; import { ILogger } from "@spt/models/spt/utils/ILogger"; import { ConfigServer } from "@spt/servers/ConfigServer"; import { DatabaseService } from "@spt/services/DatabaseService"; @@ -54,18 +54,19 @@ export class AirdropService { * Handle client/location/getAirdropLoot * Get loot for an airdrop container * Generates it randomly based on config/airdrop.json values + * @param forcedAirdropType OPTIONAL - Desired airdrop type, randomised when not provided * @returns Array of LootItem objects */ public generateAirdropLoot(forcedAirdropType = null): IGetAirdropLootResponse { const airdropType = forcedAirdropType ? forcedAirdropType : this.chooseAirdropType(); - this.logger.debug(`Chose ${airdropType} for airdrop loot`); + this.logger.debug(`Chose: ${airdropType} for airdrop loot`); // Common/weapon/etc const airdropConfig = this.getAirdropLootConfigByType(airdropType); // generate loot to put into airdrop crate const crateLoot = airdropConfig.useForcedLoot - ? this.lootGenerator.createForcedLoot(airdropConfig) + ? this.lootGenerator.createForcedLoot(airdropConfig.forcedLoot) : this.lootGenerator.createRandomLoot(airdropConfig); // Create airdrop crate and add to result in first spot