Refactor oh how bot equipment items are generated.
Now uses blacklist data from bot.json when picking equipment mods Equipment gen now passes same BotData object as weapon mod gen Pass botEquipmentRole via request object instead of calculating it every item slot Fixed `getFilteredDynamicModsForItem()` being hard coded to use first blacklist object regardless of which one matched the bot level
This commit is contained in:
parent
a3816ad271
commit
ed92c6802c
@ -1432,7 +1432,7 @@
|
|||||||
"65392f611406374f82152ba5",
|
"65392f611406374f82152ba5",
|
||||||
"653931da5db71d30ab1d6296"
|
"653931da5db71d30ab1d6296"
|
||||||
],
|
],
|
||||||
"mod_nvg": ["5c11046cd174af02a012e42b", "5c110624d174af029e69734c"],
|
"mod_nvg": ["5c11046cd174af02a012e42b"],
|
||||||
"mod_reciever": ["5d4405aaa4b9361e6a4e6bd3"],
|
"mod_reciever": ["5d4405aaa4b9361e6a4e6bd3"],
|
||||||
"mod_stock": ["5cde739cd7f00c0010373bd3"],
|
"mod_stock": ["5cde739cd7f00c0010373bd3"],
|
||||||
"mod_rear_sight": ["5a0ed824fcdbcb0176308b0d"],
|
"mod_rear_sight": ["5a0ed824fcdbcb0176308b0d"],
|
||||||
|
@ -70,7 +70,8 @@ export class BotEquipmentModGenerator {
|
|||||||
* @param equipment Equipment item to add mods to
|
* @param equipment Equipment item to add mods to
|
||||||
* @param modPool Mod list to choose frm
|
* @param modPool Mod list to choose frm
|
||||||
* @param parentId parentid of item to add mod to
|
* @param parentId parentid of item to add mod to
|
||||||
* @param parentTemplate template objet of item to add mods to
|
* @param parentTemplate Template object of item to add mods to
|
||||||
|
* @param specificBlacklist The relevant blacklist from bot.json equipment dictionary
|
||||||
* @param forceSpawn should this mod be forced to spawn
|
* @param forceSpawn should this mod be forced to spawn
|
||||||
* @returns Item + compatible mods as an array
|
* @returns Item + compatible mods as an array
|
||||||
*/
|
*/
|
||||||
@ -79,19 +80,22 @@ export class BotEquipmentModGenerator {
|
|||||||
parentId: string,
|
parentId: string,
|
||||||
parentTemplate: ITemplateItem,
|
parentTemplate: ITemplateItem,
|
||||||
settings: IGenerateEquipmentProperties,
|
settings: IGenerateEquipmentProperties,
|
||||||
|
specificBlacklist: EquipmentFilterDetails,
|
||||||
shouldForceSpawn = false,
|
shouldForceSpawn = false,
|
||||||
): IItem[] {
|
): IItem[] {
|
||||||
let forceSpawn = shouldForceSpawn;
|
let forceSpawn = shouldForceSpawn;
|
||||||
|
|
||||||
|
// Get mod pool for the desired item
|
||||||
const compatibleModsPool = settings.modPool[parentTemplate._id];
|
const compatibleModsPool = settings.modPool[parentTemplate._id];
|
||||||
if (!compatibleModsPool) {
|
if (!compatibleModsPool) {
|
||||||
this.logger.warning(
|
this.logger.warning(
|
||||||
`bot: ${settings.botRole} lacks a mod slot pool for item: ${parentTemplate._id} ${parentTemplate._name}`,
|
`bot: ${settings.botData.role} lacks a mod slot pool for item: ${parentTemplate._id} ${parentTemplate._name}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over mod pool and choose mods to add to item
|
// Iterate over mod pool and choose mods to add to item
|
||||||
for (const modSlotName in compatibleModsPool) {
|
for (const modSlotName in compatibleModsPool) {
|
||||||
|
// Get the templates slot object from db
|
||||||
const itemSlotTemplate = this.getModItemSlotFromDb(modSlotName, parentTemplate);
|
const itemSlotTemplate = this.getModItemSlotFromDb(modSlotName, parentTemplate);
|
||||||
if (!itemSlotTemplate) {
|
if (!itemSlotTemplate) {
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
@ -99,7 +103,7 @@ export class BotEquipmentModGenerator {
|
|||||||
modSlot: modSlotName,
|
modSlot: modSlotName,
|
||||||
parentId: parentTemplate._id,
|
parentId: parentTemplate._id,
|
||||||
parentName: parentTemplate._name,
|
parentName: parentTemplate._name,
|
||||||
botRole: settings.botRole,
|
botRole: settings.botData.role,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -126,6 +130,13 @@ export class BotEquipmentModGenerator {
|
|||||||
// Get pool of items we can add for this slot
|
// Get pool of items we can add for this slot
|
||||||
let modPoolToChooseFrom = compatibleModsPool[modSlotName];
|
let modPoolToChooseFrom = compatibleModsPool[modSlotName];
|
||||||
|
|
||||||
|
// Filter the pool of items in blacklist
|
||||||
|
const filteredModPool = this.filterModsByBlacklist(modPoolToChooseFrom, specificBlacklist, modSlotName);
|
||||||
|
if (filteredModPool.length > 0) {
|
||||||
|
// use filtered pool as it has items in it
|
||||||
|
modPoolToChooseFrom = filteredModPool;
|
||||||
|
}
|
||||||
|
|
||||||
// Slot can hold armor plates + we are filtering possible items by bot level, handle
|
// Slot can hold armor plates + we are filtering possible items by bot level, handle
|
||||||
if (
|
if (
|
||||||
settings.botEquipmentConfig.filterPlatesByLevel &&
|
settings.botEquipmentConfig.filterPlatesByLevel &&
|
||||||
@ -186,18 +197,35 @@ export class BotEquipmentModGenerator {
|
|||||||
|
|
||||||
// Get chosen mods db template and check it fits into slot
|
// Get chosen mods db template and check it fits into slot
|
||||||
const modTemplate = this.itemHelper.getItem(modTpl);
|
const modTemplate = this.itemHelper.getItem(modTpl);
|
||||||
if (!this.isModValidForSlot(modTemplate, itemSlotTemplate, modSlotName, parentTemplate, settings.botRole)) {
|
if (
|
||||||
|
!this.isModValidForSlot(
|
||||||
|
modTemplate,
|
||||||
|
itemSlotTemplate,
|
||||||
|
modSlotName,
|
||||||
|
parentTemplate,
|
||||||
|
settings.botData.role,
|
||||||
|
)
|
||||||
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate new id to ensure all items are unique on bot
|
// Generate new id to ensure all items are unique on bot
|
||||||
const modId = this.hashUtil.generate();
|
const modId = this.hashUtil.generate();
|
||||||
equipment.push(this.createModItem(modId, modTpl, parentId, modSlotName, modTemplate[1], settings.botRole));
|
equipment.push(
|
||||||
|
this.createModItem(modId, modTpl, parentId, modSlotName, modTemplate[1], settings.botData.role),
|
||||||
|
);
|
||||||
|
|
||||||
// Does item being added exist in mod pool - has its own mod pool
|
// Does item being added exist in mod pool - has its own mod pool
|
||||||
if (Object.keys(settings.modPool).includes(modTpl)) {
|
if (Object.keys(settings.modPool).includes(modTpl)) {
|
||||||
// Call self again with mod being added as item to add child mods to
|
// Call self again with mod being added as item to add child mods to
|
||||||
this.generateModsForEquipment(equipment, modId, modTemplate[1], settings, forceSpawn);
|
this.generateModsForEquipment(
|
||||||
|
equipment,
|
||||||
|
modId,
|
||||||
|
modTemplate[1],
|
||||||
|
settings,
|
||||||
|
specificBlacklist,
|
||||||
|
forceSpawn,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +262,8 @@ export class BotEquipmentModGenerator {
|
|||||||
// Get the front/back/side weights based on bots level
|
// Get the front/back/side weights based on bots level
|
||||||
const plateSlotWeights = settings.botEquipmentConfig?.armorPlateWeighting?.find(
|
const plateSlotWeights = settings.botEquipmentConfig?.armorPlateWeighting?.find(
|
||||||
(armorWeight) =>
|
(armorWeight) =>
|
||||||
settings.botLevel >= armorWeight.levelRange.min && settings.botLevel <= armorWeight.levelRange.max,
|
settings.botData.level >= armorWeight.levelRange.min &&
|
||||||
|
settings.botData.level <= armorWeight.levelRange.max,
|
||||||
);
|
);
|
||||||
if (!plateSlotWeights) {
|
if (!plateSlotWeights) {
|
||||||
// No weights, return original array of plate tpls
|
// No weights, return original array of plate tpls
|
||||||
@ -726,25 +755,26 @@ export class BotEquipmentModGenerator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Randomly choose if a mod should be spawned, 100% for required mods OR mod is ammo slot
|
* Randomly choose if a mod should be spawned, 100% for required mods OR mod is ammo slot
|
||||||
* @param itemSlot slot the item sits in
|
* @param itemSlot slot the item sits in from db
|
||||||
* @param modSlot slot the mod sits in
|
* @param modSlotName Name of slot the mod sits in
|
||||||
* @param modSpawnChances Chances for various mod spawns
|
* @param modSpawnChances Chances for various mod spawns
|
||||||
* @param botEquipConfig Various config settings for generating this type of bot
|
* @param botEquipConfig Various config settings for generating this type of bot
|
||||||
* @returns ModSpawn.SPAWN when mod should be spawned, ModSpawn.DEFAULT_MOD when default mod should spawn, ModSpawn.SKIP when mod is skipped
|
* @returns ModSpawn.SPAWN when mod should be spawned, ModSpawn.DEFAULT_MOD when default mod should spawn, ModSpawn.SKIP when mod is skipped
|
||||||
*/
|
*/
|
||||||
protected shouldModBeSpawned(
|
protected shouldModBeSpawned(
|
||||||
itemSlot: ISlot,
|
itemSlot: ISlot,
|
||||||
modSlot: string,
|
modSlotName: string,
|
||||||
modSpawnChances: IModsChances,
|
modSpawnChances: IModsChances,
|
||||||
botEquipConfig: EquipmentFilters,
|
botEquipConfig: EquipmentFilters,
|
||||||
): ModSpawn {
|
): ModSpawn {
|
||||||
const slotRequired = itemSlot._required;
|
const slotRequired = itemSlot._required;
|
||||||
if (this.getAmmoContainers().includes(modSlot)) {
|
if (this.getAmmoContainers().includes(modSlotName)) {
|
||||||
|
// Always force mags/cartridges in weapon to spawn
|
||||||
return ModSpawn.SPAWN;
|
return ModSpawn.SPAWN;
|
||||||
}
|
}
|
||||||
const spawnMod = this.probabilityHelper.rollChance(modSpawnChances[modSlot]);
|
const spawnMod = this.probabilityHelper.rollChance(modSpawnChances[modSlotName]);
|
||||||
if (!spawnMod && (slotRequired || botEquipConfig.weaponSlotIdsToMakeRequired?.includes(modSlot))) {
|
if (!spawnMod && (slotRequired || botEquipConfig.weaponSlotIdsToMakeRequired?.includes(modSlotName))) {
|
||||||
// Mod is required but spawn chance roll failed, choose default mod spawn for slot
|
// Edge case: Mod is required but spawn chance roll failed, choose default mod spawn for slot
|
||||||
return ModSpawn.DEFAULT_MOD;
|
return ModSpawn.DEFAULT_MOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1249,11 +1279,7 @@ export class BotEquipmentModGenerator {
|
|||||||
const supportedSubMods = desiredSlotObject._props.filters[0].Filter;
|
const supportedSubMods = desiredSlotObject._props.filters[0].Filter;
|
||||||
if (supportedSubMods) {
|
if (supportedSubMods) {
|
||||||
// Filter mods
|
// Filter mods
|
||||||
let filteredMods = this.filterWeaponModsByBlacklist(
|
let filteredMods = this.filterModsByBlacklist(supportedSubMods, botEquipBlacklist, desiredSlotName);
|
||||||
supportedSubMods,
|
|
||||||
botEquipBlacklist,
|
|
||||||
desiredSlotName,
|
|
||||||
);
|
|
||||||
if (filteredMods.length === 0) {
|
if (filteredMods.length === 0) {
|
||||||
this.logger.warning(
|
this.logger.warning(
|
||||||
this.localisationService.getText("bot-unable_to_filter_mods_all_blacklisted", {
|
this.localisationService.getText("bot-unable_to_filter_mods_all_blacklisted", {
|
||||||
@ -1289,7 +1315,7 @@ export class BotEquipmentModGenerator {
|
|||||||
this.botEquipmentModPoolService.getCompatibleModsForWeaponSlot(parentItemId, modSlot),
|
this.botEquipmentModPoolService.getCompatibleModsForWeaponSlot(parentItemId, modSlot),
|
||||||
);
|
);
|
||||||
|
|
||||||
const filteredMods = this.filterWeaponModsByBlacklist(modsFromDynamicPool, botEquipBlacklist, modSlot);
|
const filteredMods = this.filterModsByBlacklist(modsFromDynamicPool, botEquipBlacklist, modSlot);
|
||||||
if (filteredMods.length === 0) {
|
if (filteredMods.length === 0) {
|
||||||
this.logger.warning(
|
this.logger.warning(
|
||||||
this.localisationService.getText("bot-unable_to_filter_mod_slot_all_blacklisted", modSlot),
|
this.localisationService.getText("bot-unable_to_filter_mod_slot_all_blacklisted", modSlot),
|
||||||
@ -1307,7 +1333,7 @@ export class BotEquipmentModGenerator {
|
|||||||
* @param modSlot Slot mods belong to
|
* @param modSlot Slot mods belong to
|
||||||
* @returns Filtered array of mod tpls
|
* @returns Filtered array of mod tpls
|
||||||
*/
|
*/
|
||||||
protected filterWeaponModsByBlacklist(
|
protected filterModsByBlacklist(
|
||||||
allowedMods: string[],
|
allowedMods: string[],
|
||||||
botEquipBlacklist: EquipmentFilterDetails,
|
botEquipBlacklist: EquipmentFilterDetails,
|
||||||
modSlot: string,
|
modSlot: string,
|
||||||
|
@ -6,6 +6,7 @@ import { BotWeaponGenerator } from "@spt/generators/BotWeaponGenerator";
|
|||||||
import { BotGeneratorHelper } from "@spt/helpers/BotGeneratorHelper";
|
import { BotGeneratorHelper } from "@spt/helpers/BotGeneratorHelper";
|
||||||
import { BotHelper } from "@spt/helpers/BotHelper";
|
import { BotHelper } from "@spt/helpers/BotHelper";
|
||||||
import { ItemHelper } from "@spt/helpers/ItemHelper";
|
import { ItemHelper } from "@spt/helpers/ItemHelper";
|
||||||
|
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
|
||||||
import { WeatherHelper } from "@spt/helpers/WeatherHelper";
|
import { WeatherHelper } from "@spt/helpers/WeatherHelper";
|
||||||
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
|
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
|
||||||
import { IInventory as PmcInventory } from "@spt/models/eft/common/tables/IBotBase";
|
import { IInventory as PmcInventory } from "@spt/models/eft/common/tables/IBotBase";
|
||||||
@ -20,6 +21,7 @@ import { IGenerateEquipmentProperties } from "@spt/models/spt/bots/IGenerateEqui
|
|||||||
import { EquipmentFilterDetails, IBotConfig } from "@spt/models/spt/config/IBotConfig";
|
import { EquipmentFilterDetails, IBotConfig } from "@spt/models/spt/config/IBotConfig";
|
||||||
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||||
import { ConfigServer } from "@spt/servers/ConfigServer";
|
import { ConfigServer } from "@spt/servers/ConfigServer";
|
||||||
|
import { BotEquipmentFilterService } from "@spt/services/BotEquipmentFilterService";
|
||||||
import { BotEquipmentModPoolService } from "@spt/services/BotEquipmentModPoolService";
|
import { BotEquipmentModPoolService } from "@spt/services/BotEquipmentModPoolService";
|
||||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||||
import { LocalisationService } from "@spt/services/LocalisationService";
|
import { LocalisationService } from "@spt/services/LocalisationService";
|
||||||
@ -40,11 +42,13 @@ export class BotInventoryGenerator {
|
|||||||
@inject("BotWeaponGenerator") protected botWeaponGenerator: BotWeaponGenerator,
|
@inject("BotWeaponGenerator") protected botWeaponGenerator: BotWeaponGenerator,
|
||||||
@inject("BotLootGenerator") protected botLootGenerator: BotLootGenerator,
|
@inject("BotLootGenerator") protected botLootGenerator: BotLootGenerator,
|
||||||
@inject("BotGeneratorHelper") protected botGeneratorHelper: BotGeneratorHelper,
|
@inject("BotGeneratorHelper") protected botGeneratorHelper: BotGeneratorHelper,
|
||||||
|
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||||
@inject("BotHelper") protected botHelper: BotHelper,
|
@inject("BotHelper") protected botHelper: BotHelper,
|
||||||
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
|
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
|
||||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||||
@inject("WeatherHelper") protected weatherHelper: WeatherHelper,
|
@inject("WeatherHelper") protected weatherHelper: WeatherHelper,
|
||||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
|
@inject("BotEquipmentFilterService") protected botEquipmentFilterService: BotEquipmentFilterService,
|
||||||
@inject("BotEquipmentModPoolService") protected botEquipmentModPoolService: BotEquipmentModPoolService,
|
@inject("BotEquipmentModPoolService") protected botEquipmentModPoolService: BotEquipmentModPoolService,
|
||||||
@inject("BotEquipmentModGenerator") protected botEquipmentModGenerator: BotEquipmentModGenerator,
|
@inject("BotEquipmentModGenerator") protected botEquipmentModGenerator: BotEquipmentModGenerator,
|
||||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
@ -83,6 +87,7 @@ export class BotInventoryGenerator {
|
|||||||
?.getValue<IGetRaidConfigurationRequestData>();
|
?.getValue<IGetRaidConfigurationRequestData>();
|
||||||
|
|
||||||
this.generateAndAddEquipmentToBot(
|
this.generateAndAddEquipmentToBot(
|
||||||
|
sessionId,
|
||||||
templateInventory,
|
templateInventory,
|
||||||
wornItemChances,
|
wornItemChances,
|
||||||
botRole,
|
botRole,
|
||||||
@ -142,6 +147,7 @@ export class BotInventoryGenerator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add equipment to a bot
|
* Add equipment to a bot
|
||||||
|
* @param sessionId Session id
|
||||||
* @param templateInventory bot/x.json data from db
|
* @param templateInventory bot/x.json data from db
|
||||||
* @param wornItemChances Chances items will be added to bot
|
* @param wornItemChances Chances items will be added to bot
|
||||||
* @param botRole Role bot has (assault/pmcBot)
|
* @param botRole Role bot has (assault/pmcBot)
|
||||||
@ -150,6 +156,7 @@ export class BotInventoryGenerator {
|
|||||||
* @param chosenGameVersion Game version for bot, only really applies for PMCs
|
* @param chosenGameVersion Game version for bot, only really applies for PMCs
|
||||||
*/
|
*/
|
||||||
protected generateAndAddEquipmentToBot(
|
protected generateAndAddEquipmentToBot(
|
||||||
|
sessionId: string,
|
||||||
templateInventory: IInventory,
|
templateInventory: IInventory,
|
||||||
wornItemChances: IChances,
|
wornItemChances: IChances,
|
||||||
botRole: string,
|
botRole: string,
|
||||||
@ -193,8 +200,16 @@ export class BotInventoryGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get profile of player generating bots, we use their level later on
|
||||||
|
const pmcProfile = this.profileHelper.getPmcProfile(sessionId);
|
||||||
|
const botEquipmentRole = this.botGeneratorHelper.getBotEquipmentRole(botRole);
|
||||||
|
|
||||||
|
// Iterate over all equipment slots of bot, do it in specifc order to reduce conflicts
|
||||||
|
// e.g. ArmorVest should be generated after TactivalVest
|
||||||
|
// or FACE_COVER before HEADWEAR
|
||||||
for (const equipmentSlot in templateInventory.equipment) {
|
for (const equipmentSlot in templateInventory.equipment) {
|
||||||
// Weapons have special generation and will be generated separately; ArmorVest should be generated after TactivalVest
|
// Skip some slots as they need to be done in a specific order + with specific parameter values
|
||||||
|
// e.g. Weapons
|
||||||
if (excludedSlots.includes(equipmentSlot)) {
|
if (excludedSlots.includes(equipmentSlot)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -204,73 +219,74 @@ export class BotInventoryGenerator {
|
|||||||
rootEquipmentPool: templateInventory.equipment[equipmentSlot],
|
rootEquipmentPool: templateInventory.equipment[equipmentSlot],
|
||||||
modPool: templateInventory.mods,
|
modPool: templateInventory.mods,
|
||||||
spawnChances: wornItemChances,
|
spawnChances: wornItemChances,
|
||||||
botRole: botRole,
|
botData: { role: botRole, level: botLevel, equipmentRole: botEquipmentRole },
|
||||||
botLevel: botLevel,
|
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails,
|
randomisationDetails: randomistionDetails,
|
||||||
|
generatingPlayerLevel: pmcProfile.Info.Level,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate below in specific order
|
// Generate below in specific order
|
||||||
this.generateEquipment({
|
this.generateEquipment({
|
||||||
rootEquipmentSlot: EquipmentSlots.POCKETS,
|
rootEquipmentSlot: EquipmentSlots.POCKETS,
|
||||||
|
// Unheard profiles have unique sized pockets, TODO - handle this somewhere else in a better way
|
||||||
rootEquipmentPool:
|
rootEquipmentPool:
|
||||||
chosenGameVersion === GameEditions.UNHEARD
|
chosenGameVersion === GameEditions.UNHEARD
|
||||||
? { [ItemTpl.POCKETS_1X4_TUE]: 1 }
|
? { [ItemTpl.POCKETS_1X4_TUE]: 1 }
|
||||||
: templateInventory.equipment.Pockets,
|
: templateInventory.equipment.Pockets,
|
||||||
modPool: templateInventory.mods,
|
modPool: templateInventory.mods,
|
||||||
spawnChances: wornItemChances,
|
spawnChances: wornItemChances,
|
||||||
botRole: botRole,
|
botData: { role: botRole, level: botLevel, equipmentRole: botEquipmentRole },
|
||||||
botLevel: botLevel,
|
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails,
|
randomisationDetails: randomistionDetails,
|
||||||
generateModsBlacklist: [ItemTpl.POCKETS_1X4_TUE],
|
generateModsBlacklist: [ItemTpl.POCKETS_1X4_TUE],
|
||||||
|
generatingPlayerLevel: pmcProfile.Info.Level,
|
||||||
});
|
});
|
||||||
this.generateEquipment({
|
this.generateEquipment({
|
||||||
rootEquipmentSlot: EquipmentSlots.FACE_COVER,
|
rootEquipmentSlot: EquipmentSlots.FACE_COVER,
|
||||||
rootEquipmentPool: templateInventory.equipment.FaceCover,
|
rootEquipmentPool: templateInventory.equipment.FaceCover,
|
||||||
modPool: templateInventory.mods,
|
modPool: templateInventory.mods,
|
||||||
spawnChances: wornItemChances,
|
spawnChances: wornItemChances,
|
||||||
botRole: botRole,
|
botData: { role: botRole, level: botLevel, equipmentRole: botEquipmentRole },
|
||||||
botLevel: botLevel,
|
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails,
|
randomisationDetails: randomistionDetails,
|
||||||
|
generatingPlayerLevel: pmcProfile.Info.Level,
|
||||||
});
|
});
|
||||||
this.generateEquipment({
|
this.generateEquipment({
|
||||||
rootEquipmentSlot: EquipmentSlots.HEADWEAR,
|
rootEquipmentSlot: EquipmentSlots.HEADWEAR,
|
||||||
rootEquipmentPool: templateInventory.equipment.Headwear,
|
rootEquipmentPool: templateInventory.equipment.Headwear,
|
||||||
modPool: templateInventory.mods,
|
modPool: templateInventory.mods,
|
||||||
spawnChances: wornItemChances,
|
spawnChances: wornItemChances,
|
||||||
botRole: botRole,
|
botData: { role: botRole, level: botLevel, equipmentRole: botEquipmentRole },
|
||||||
botLevel: botLevel,
|
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails,
|
randomisationDetails: randomistionDetails,
|
||||||
|
generatingPlayerLevel: pmcProfile.Info.Level,
|
||||||
});
|
});
|
||||||
this.generateEquipment({
|
this.generateEquipment({
|
||||||
rootEquipmentSlot: EquipmentSlots.EARPIECE,
|
rootEquipmentSlot: EquipmentSlots.EARPIECE,
|
||||||
rootEquipmentPool: templateInventory.equipment.Earpiece,
|
rootEquipmentPool: templateInventory.equipment.Earpiece,
|
||||||
modPool: templateInventory.mods,
|
modPool: templateInventory.mods,
|
||||||
spawnChances: wornItemChances,
|
spawnChances: wornItemChances,
|
||||||
botRole: botRole,
|
botData: { role: botRole, level: botLevel, equipmentRole: botEquipmentRole },
|
||||||
botLevel: botLevel,
|
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails,
|
randomisationDetails: randomistionDetails,
|
||||||
|
generatingPlayerLevel: pmcProfile.Info.Level,
|
||||||
});
|
});
|
||||||
const hasArmorVest = this.generateEquipment({
|
const hasArmorVest = this.generateEquipment({
|
||||||
rootEquipmentSlot: EquipmentSlots.ARMOR_VEST,
|
rootEquipmentSlot: EquipmentSlots.ARMOR_VEST,
|
||||||
rootEquipmentPool: templateInventory.equipment.ArmorVest,
|
rootEquipmentPool: templateInventory.equipment.ArmorVest,
|
||||||
modPool: templateInventory.mods,
|
modPool: templateInventory.mods,
|
||||||
spawnChances: wornItemChances,
|
spawnChances: wornItemChances,
|
||||||
botRole: botRole,
|
botData: { role: botRole, level: botLevel, equipmentRole: botEquipmentRole },
|
||||||
botLevel: botLevel,
|
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails,
|
randomisationDetails: randomistionDetails,
|
||||||
|
generatingPlayerLevel: pmcProfile.Info.Level,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Bot has no armor vest and flagged to be forceed to wear armored rig in this event
|
// Bot has no armor vest and flagged to be forceed to wear armored rig in this event
|
||||||
@ -295,11 +311,11 @@ export class BotInventoryGenerator {
|
|||||||
rootEquipmentPool: templateInventory.equipment.TacticalVest,
|
rootEquipmentPool: templateInventory.equipment.TacticalVest,
|
||||||
modPool: templateInventory.mods,
|
modPool: templateInventory.mods,
|
||||||
spawnChances: wornItemChances,
|
spawnChances: wornItemChances,
|
||||||
botRole: botRole,
|
botData: { role: botRole, level: botLevel, equipmentRole: botEquipmentRole },
|
||||||
botLevel: botLevel,
|
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails,
|
randomisationDetails: randomistionDetails,
|
||||||
|
generatingPlayerLevel: pmcProfile.Info.Level,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,6 +376,7 @@ export class BotInventoryGenerator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a piece of equipment with mods to inventory from the provided pools
|
* Add a piece of equipment with mods to inventory from the provided pools
|
||||||
|
* @param sessionId Session id
|
||||||
* @param settings Values to adjust how item is chosen and added to bot
|
* @param settings Values to adjust how item is chosen and added to bot
|
||||||
* @returns true when item added
|
* @returns true when item added
|
||||||
*/
|
*/
|
||||||
@ -381,11 +398,13 @@ export class BotInventoryGenerator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Roll dice on equipment item
|
||||||
const shouldSpawn = this.randomUtil.getChance100(spawnChance);
|
const shouldSpawn = this.randomUtil.getChance100(spawnChance);
|
||||||
if (shouldSpawn && Object.keys(settings.rootEquipmentPool).length) {
|
if (shouldSpawn && Object.keys(settings.rootEquipmentPool).length) {
|
||||||
let pickedItemDb: ITemplateItem;
|
let pickedItemDb: ITemplateItem;
|
||||||
let found = false;
|
let found = false;
|
||||||
|
|
||||||
|
// Limit attempts to find a compatible item as its expensive to check them all
|
||||||
const maxAttempts = Math.round(Object.keys(settings.rootEquipmentPool).length * 0.75); // Roughly 75% of pool size
|
const maxAttempts = Math.round(Object.keys(settings.rootEquipmentPool).length * 0.75); // Roughly 75% of pool size
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
while (!found) {
|
while (!found) {
|
||||||
@ -398,7 +417,7 @@ export class BotInventoryGenerator {
|
|||||||
|
|
||||||
if (!dbResult[0]) {
|
if (!dbResult[0]) {
|
||||||
this.logger.error(this.localisationService.getText("bot-missing_item_template", chosenItemTpl));
|
this.logger.error(this.localisationService.getText("bot-missing_item_template", chosenItemTpl));
|
||||||
this.logger.info(`EquipmentSlot -> ${settings.rootEquipmentSlot}`);
|
this.logger.debug(`EquipmentSlot -> ${settings.rootEquipmentSlot}`);
|
||||||
|
|
||||||
// remove picked item
|
// remove picked item
|
||||||
delete settings.rootEquipmentPool[chosenItemTpl];
|
delete settings.rootEquipmentPool[chosenItemTpl];
|
||||||
@ -408,6 +427,7 @@ export class BotInventoryGenerator {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is the chosen item compatible with other items equipped
|
||||||
const compatibilityResult = this.botGeneratorHelper.isItemIncompatibleWithCurrentItems(
|
const compatibilityResult = this.botGeneratorHelper.isItemIncompatibleWithCurrentItems(
|
||||||
settings.inventory.items,
|
settings.inventory.items,
|
||||||
chosenItemTpl,
|
chosenItemTpl,
|
||||||
@ -438,32 +458,38 @@ export class BotInventoryGenerator {
|
|||||||
_tpl: pickedItemDb._id,
|
_tpl: pickedItemDb._id,
|
||||||
parentId: settings.inventory.equipment,
|
parentId: settings.inventory.equipment,
|
||||||
slotId: settings.rootEquipmentSlot,
|
slotId: settings.rootEquipmentSlot,
|
||||||
...this.botGeneratorHelper.generateExtraPropertiesForItem(pickedItemDb, settings.botRole),
|
...this.botGeneratorHelper.generateExtraPropertiesForItem(pickedItemDb, settings.botData.role),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use dynamic mod pool if enabled in config for this bot
|
const botEquipBlacklist = this.botEquipmentFilterService.getBotEquipmentBlacklist(
|
||||||
const botEquipmentRole = this.botGeneratorHelper.getBotEquipmentRole(settings.botRole);
|
settings.botData.equipmentRole,
|
||||||
|
settings.generatingPlayerLevel,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Edge case: Filter the armor items mod pool if bot exists in config dict + config has armor slot
|
||||||
if (
|
if (
|
||||||
this.botConfig.equipment[botEquipmentRole] &&
|
this.botConfig.equipment[settings.botData.equipmentRole] &&
|
||||||
settings.randomisationDetails?.randomisedArmorSlots?.includes(settings.rootEquipmentSlot)
|
settings.randomisationDetails?.randomisedArmorSlots?.includes(settings.rootEquipmentSlot)
|
||||||
) {
|
) {
|
||||||
|
// Filter out mods from relevant blacklist
|
||||||
settings.modPool[pickedItemDb._id] = this.getFilteredDynamicModsForItem(
|
settings.modPool[pickedItemDb._id] = this.getFilteredDynamicModsForItem(
|
||||||
pickedItemDb._id,
|
pickedItemDb._id,
|
||||||
this.botConfig.equipment[botEquipmentRole].blacklist,
|
botEquipBlacklist.equipment,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Item has slots, fill them
|
// Does item have slots for sub-mods to be inserted into
|
||||||
if (pickedItemDb._props.Slots?.length > 0 && !settings.generateModsBlacklist?.includes(pickedItemDb._id)) {
|
if (pickedItemDb._props.Slots?.length > 0 && !settings.generateModsBlacklist?.includes(pickedItemDb._id)) {
|
||||||
const childItemsToAdd = this.botEquipmentModGenerator.generateModsForEquipment(
|
const childItemsToAdd = this.botEquipmentModGenerator.generateModsForEquipment(
|
||||||
[item],
|
[item],
|
||||||
id,
|
id,
|
||||||
pickedItemDb,
|
pickedItemDb,
|
||||||
settings,
|
settings,
|
||||||
|
botEquipBlacklist,
|
||||||
);
|
);
|
||||||
settings.inventory.items.push(...childItemsToAdd);
|
settings.inventory.items.push(...childItemsToAdd);
|
||||||
} else {
|
} else {
|
||||||
// No slots, push root item only
|
// No slots, add root item only
|
||||||
settings.inventory.items.push(item);
|
settings.inventory.items.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,17 +502,17 @@ export class BotInventoryGenerator {
|
|||||||
/**
|
/**
|
||||||
* Get all possible mods for item and filter down based on equipment blacklist from bot.json config
|
* Get all possible mods for item and filter down based on equipment blacklist from bot.json config
|
||||||
* @param itemTpl Item mod pool is being retrieved and filtered
|
* @param itemTpl Item mod pool is being retrieved and filtered
|
||||||
* @param equipmentBlacklist blacklist to filter mod pool with
|
* @param equipmentBlacklist Blacklist to filter mod pool with
|
||||||
* @returns Filtered pool of mods
|
* @returns Filtered pool of mods
|
||||||
*/
|
*/
|
||||||
protected getFilteredDynamicModsForItem(
|
protected getFilteredDynamicModsForItem(
|
||||||
itemTpl: string,
|
itemTpl: string,
|
||||||
equipmentBlacklist: EquipmentFilterDetails[],
|
equipmentBlacklist: Record<string, string[]>,
|
||||||
): Record<string, string[]> {
|
): Record<string, string[]> {
|
||||||
const modPool = this.botEquipmentModPoolService.getModsForGearSlot(itemTpl);
|
const modPool = this.botEquipmentModPoolService.getModsForGearSlot(itemTpl);
|
||||||
for (const modSlot of Object.keys(modPool ?? [])) {
|
for (const modSlot of Object.keys(modPool ?? [])) {
|
||||||
const blacklistedMods = equipmentBlacklist[0]?.equipment[modSlot] || [];
|
const blacklistedMods = equipmentBlacklist[modSlot] ?? [];
|
||||||
const filteredMods = modPool[modSlot].filter((x) => !blacklistedMods.includes(x));
|
const filteredMods = modPool[modSlot].filter((slotName) => !blacklistedMods.includes(slotName));
|
||||||
|
|
||||||
if (filteredMods.length > 0) {
|
if (filteredMods.length > 0) {
|
||||||
modPool[modSlot] = filteredMods;
|
modPool[modSlot] = filteredMods;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { IInventory as PmcInventory } from "@spt/models/eft/common/tables/IBotBase";
|
import { IInventory as PmcInventory } from "@spt/models/eft/common/tables/IBotBase";
|
||||||
import { IChances, IMods } from "@spt/models/eft/common/tables/IBotType";
|
import { IChances, IMods } from "@spt/models/eft/common/tables/IBotType";
|
||||||
import { EquipmentFilters, RandomisationDetails } from "@spt/models/spt/config/IBotConfig";
|
import { EquipmentFilters, RandomisationDetails } from "@spt/models/spt/config/IBotConfig";
|
||||||
|
import { IBotData } from "./IGenerateWeaponRequest";
|
||||||
|
|
||||||
export interface IGenerateEquipmentProperties {
|
export interface IGenerateEquipmentProperties {
|
||||||
/** Root Slot being generated */
|
/** Root Slot being generated */
|
||||||
@ -10,14 +11,13 @@ export interface IGenerateEquipmentProperties {
|
|||||||
modPool: IMods;
|
modPool: IMods;
|
||||||
/** Dictionary of mod items and their chance to spawn for this bot type */
|
/** Dictionary of mod items and their chance to spawn for this bot type */
|
||||||
spawnChances: IChances;
|
spawnChances: IChances;
|
||||||
/** Role being generated for */
|
/** Bot-specific properties */
|
||||||
botRole: string;
|
botData: IBotData;
|
||||||
/** Level of bot being generated */
|
|
||||||
botLevel: number;
|
|
||||||
inventory: PmcInventory;
|
inventory: PmcInventory;
|
||||||
botEquipmentConfig: EquipmentFilters;
|
botEquipmentConfig: EquipmentFilters;
|
||||||
/** Settings from bot.json to adjust how item is generated */
|
/** Settings from bot.json to adjust how item is generated */
|
||||||
randomisationDetails: RandomisationDetails;
|
randomisationDetails: RandomisationDetails;
|
||||||
/** OPTIONAL - Do not generate mods for tpls in this array */
|
/** OPTIONAL - Do not generate mods for tpls in this array */
|
||||||
generateModsBlacklist?: string[];
|
generateModsBlacklist?: string[];
|
||||||
|
generatingPlayerLevel: number;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user