0
0
mirror of https://github.com/sp-tarkov/server.git synced 2025-02-13 09:50:43 -05:00

Added ability to filter out PMC loot items from pool based on its value, configured via pmc.json/lootItemLimitsRub

This commit is contained in:
Chomp 2025-01-07 20:28:41 +00:00
parent 2d7fdc0dc2
commit 6a2afe2fa7
5 changed files with 102 additions and 6 deletions

View File

@ -1149,7 +1149,7 @@
"backpackLoot": { "backpackLoot": {
"weights": { "weights": {
"0": 3, "0": 3,
"1": 5, "1": 7,
"2": 12, "2": 12,
"3": 20, "3": 20,
"4": 8, "4": 8,

View File

@ -717,6 +717,40 @@
"value": 2500000 "value": 2500000
} }
], ],
"lootItemLimitsRub": [
{
"min": 46,
"max": 64,
"backpack": {
"min": 5000,
"max": 0
},
"pocket": {
"min": 5000,
"max": 0
},
"vest": {
"min": 5000,
"max": 0
}
},
{
"min": 65,
"max": 100,
"backpack": {
"min": 10000,
"max": 0
},
"pocket": {
"min": 10000,
"max": 0
},
"vest": {
"min": 10000,
"max": 0
}
}
],
"maxPocketLootTotalRub": 50000, "maxPocketLootTotalRub": 50000,
"maxVestLootTotalRub": 50000, "maxVestLootTotalRub": 50000,
"convertIntoPmcChance": { "convertIntoPmcChance": {

View File

@ -16,7 +16,7 @@ import { ItemAddedResult } from "@spt/models/enums/ItemAddedResult";
import { LootCacheType } from "@spt/models/spt/bots/IBotLootCache"; import { LootCacheType } from "@spt/models/spt/bots/IBotLootCache";
import { IItemSpawnLimitSettings } from "@spt/models/spt/bots/IItemSpawnLimitSettings"; import { IItemSpawnLimitSettings } from "@spt/models/spt/bots/IItemSpawnLimitSettings";
import { IBotConfig } from "@spt/models/spt/config/IBotConfig"; import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
import { IPmcConfig } from "@spt/models/spt/config/IPmcConfig"; import { IMinMaxLootItemValue, IPmcConfig } from "@spt/models/spt/config/IPmcConfig";
import type { ILogger } from "@spt/models/spt/utils/ILogger"; import type { ILogger } from "@spt/models/spt/utils/ILogger";
import { ConfigServer } from "@spt/servers/ConfigServer"; import { ConfigServer } from "@spt/servers/ConfigServer";
import { BotLootCacheService } from "@spt/services/BotLootCacheService"; import { BotLootCacheService } from "@spt/services/BotLootCacheService";
@ -243,6 +243,8 @@ export class BotLootGenerator {
containersIdFull, containersIdFull,
); );
const itemPriceLimits = this.getSingleItemLootPriceLimits(botLevel, isPmc);
// Backpack - generate loot if they have one // Backpack - generate loot if they have one
if (containersBotHasAvailable.includes(EquipmentSlots.BACKPACK)) { if (containersBotHasAvailable.includes(EquipmentSlots.BACKPACK)) {
// Add randomly generated weapon to PMC backpacks // Add randomly generated weapon to PMC backpacks
@ -262,7 +264,13 @@ export class BotLootGenerator {
const backpackLootRoubleTotal = this.getBackpackRoubleTotalByLevel(botLevel, isPmc); const backpackLootRoubleTotal = this.getBackpackRoubleTotalByLevel(botLevel, isPmc);
this.addLootFromPool( this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.BACKPACK, botJsonTemplate), this.botLootCacheService.getLootFromCache(
botRole,
isPmc,
LootCacheType.BACKPACK,
botJsonTemplate,
itemPriceLimits?.backpack,
),
[EquipmentSlots.BACKPACK], [EquipmentSlots.BACKPACK],
backpackLootCount, backpackLootCount,
botInventory, botInventory,
@ -278,7 +286,13 @@ export class BotLootGenerator {
if (containersBotHasAvailable.includes(EquipmentSlots.TACTICAL_VEST)) { if (containersBotHasAvailable.includes(EquipmentSlots.TACTICAL_VEST)) {
// Vest // Vest
this.addLootFromPool( this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.VEST, botJsonTemplate), this.botLootCacheService.getLootFromCache(
botRole,
isPmc,
LootCacheType.VEST,
botJsonTemplate,
itemPriceLimits?.vest,
),
[EquipmentSlots.TACTICAL_VEST], [EquipmentSlots.TACTICAL_VEST],
vestLootCount, vestLootCount,
botInventory, botInventory,
@ -292,7 +306,13 @@ export class BotLootGenerator {
// Pockets // Pockets
this.addLootFromPool( this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.POCKET, botJsonTemplate), this.botLootCacheService.getLootFromCache(
botRole,
isPmc,
LootCacheType.POCKET,
botJsonTemplate,
itemPriceLimits?.pocket,
),
[EquipmentSlots.POCKETS], [EquipmentSlots.POCKETS],
pocketLootCount, pocketLootCount,
botInventory, botInventory,
@ -333,12 +353,23 @@ export class BotLootGenerator {
const matchingValue = this.pmcConfig.maxBackpackLootTotalRub.find( const matchingValue = this.pmcConfig.maxBackpackLootTotalRub.find(
(minMaxValue) => botLevel >= minMaxValue.min && botLevel <= minMaxValue.max, (minMaxValue) => botLevel >= minMaxValue.min && botLevel <= minMaxValue.max,
); );
return matchingValue.value; return matchingValue?.value;
} }
return 0; return 0;
} }
protected getSingleItemLootPriceLimits(botLevel: number, isPmc: boolean): IMinMaxLootItemValue | undefined {
if (isPmc) {
const matchingValue = this.pmcConfig.lootItemLimitsRub.find(
(minMaxValue) => botLevel >= minMaxValue.min && botLevel <= minMaxValue.max,
);
return matchingValue;
}
return undefined;
}
/** /**
* Get an array of the containers a bot has on them (pockets/backpack/vest) * Get an array of the containers a bot has on them (pockets/backpack/vest)
* @param botInventory Bot to check * @param botInventory Bot to check

View File

@ -35,6 +35,7 @@ export interface IPmcConfig extends IBaseConfig {
/** What 'brain' does a PMC use, keyed by map and side (USEC/BEAR) key: map location, value: type for usec/bear */ /** What 'brain' does a PMC use, keyed by map and side (USEC/BEAR) key: map location, value: type for usec/bear */
pmcType: Record<string, Record<string, Record<string, number>>>; pmcType: Record<string, Record<string, Record<string, number>>>;
maxBackpackLootTotalRub: IMinMaxLootValue[]; maxBackpackLootTotalRub: IMinMaxLootValue[];
lootItemLimitsRub: IMinMaxLootItemValue[];
maxPocketLootTotalRub: number; maxPocketLootTotalRub: number;
maxVestLootTotalRub: number; maxVestLootTotalRub: number;
/** Percentage chance a bot from a wave is converted into a PMC, first key = map, second key = bot wildspawn type (assault/exusec), value: min+max chance to be converted */ /** Percentage chance a bot from a wave is converted into a PMC, first key = map, second key = bot wildspawn type (assault/exusec), value: min+max chance to be converted */
@ -80,3 +81,9 @@ export interface ISlotLootSettings {
export interface IMinMaxLootValue extends MinMax { export interface IMinMaxLootValue extends MinMax {
value: number; value: number;
} }
export interface IMinMaxLootItemValue extends MinMax {
backpack: MinMax;
pocket: MinMax;
vest: MinMax;
}

View File

@ -1,5 +1,6 @@
import { PMCLootGenerator } from "@spt/generators/PMCLootGenerator"; import { PMCLootGenerator } from "@spt/generators/PMCLootGenerator";
import { ItemHelper } from "@spt/helpers/ItemHelper"; import { ItemHelper } from "@spt/helpers/ItemHelper";
import { MinMax } from "@spt/models/common/MinMax";
import { IBotType } from "@spt/models/eft/common/tables/IBotType"; import { IBotType } from "@spt/models/eft/common/tables/IBotType";
import { IProps, ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem"; import { IProps, ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import { BaseClasses } from "@spt/models/enums/BaseClasses"; import { BaseClasses } from "@spt/models/enums/BaseClasses";
@ -40,6 +41,7 @@ export class BotLootCacheService {
* @param isPmc is the bot a pmc * @param isPmc is the bot a pmc
* @param lootType what type of loot is needed (backpack/pocket/stim/vest etc) * @param lootType what type of loot is needed (backpack/pocket/stim/vest etc)
* @param botJsonTemplate Base json db file for the bot having its loot generated * @param botJsonTemplate Base json db file for the bot having its loot generated
* @param itemPriceMinMax OPTIONAL - min max limit of loot item price
* @returns ITemplateItem array * @returns ITemplateItem array
*/ */
public getLootFromCache( public getLootFromCache(
@ -47,6 +49,7 @@ export class BotLootCacheService {
isPmc: boolean, isPmc: boolean,
lootType: LootCacheType, lootType: LootCacheType,
botJsonTemplate: IBotType, botJsonTemplate: IBotType,
itemPriceMinMax?: MinMax,
): Record<string, number> { ): Record<string, number> {
if (!this.botRoleExistsInCache(botRole)) { if (!this.botRoleExistsInCache(botRole)) {
this.initCacheForBotRole(botRole); this.initCacheForBotRole(botRole);
@ -105,6 +108,27 @@ export class BotLootCacheService {
break; break;
} }
if (itemPriceMinMax) {
const filteredResult = Object.entries(result).filter(([key, val]) => {
const itemPrice = this.itemHelper.getItemPrice(key);
if (itemPriceMinMax?.min && itemPriceMinMax?.max) {
return itemPrice >= itemPriceMinMax?.min && itemPrice <= itemPriceMinMax?.max;
}
if (itemPriceMinMax?.min && !itemPriceMinMax?.max) {
return itemPrice >= itemPriceMinMax?.min;
}
if (!itemPriceMinMax?.min && itemPriceMinMax?.max) {
return itemPrice <= itemPriceMinMax?.max;
}
return false;
});
return this.cloner.clone(Object.fromEntries(filteredResult));
}
return this.cloner.clone(result); return this.cloner.clone(result);
} }