Fix issue with weapon/equipment mod selection where it would ignore settings when mod slot was required
Fix JSON errors in bot.json
This commit is contained in:
parent
fc9e3f9f59
commit
fd7050b0ac
@ -891,6 +891,7 @@
|
||||
"mod_foregrip": 10,
|
||||
"mod_handguard": 10,
|
||||
"mod_launcher": 0,
|
||||
"mod_reciever": 15,
|
||||
"mod_magazine": 10,
|
||||
"mod_mount": 15,
|
||||
"mod_mount_000": 10,
|
||||
@ -1120,7 +1121,7 @@
|
||||
"TacticalVest": {
|
||||
"6034d0230ca681766b6a0fb5": 120,
|
||||
"6034cf5fffd42c541047f72e": 150,
|
||||
"597867e986f7741b265c6bd3": 120
|
||||
"59e7635f86f7742cbf2c1095": 120
|
||||
},
|
||||
"Backpack": {
|
||||
},
|
||||
@ -1131,11 +1132,9 @@
|
||||
"edit": {
|
||||
"ArmorVest": {
|
||||
"5648a7494bdc2d9d488b4583": 290,
|
||||
"5c0e446786f7742013381639": 210,
|
||||
"5b44d22286f774172b0c9de8": 280,
|
||||
"5c0e5bab86f77461f55ed1f3": 280,
|
||||
"5c0e5edb86f77461f55ed1f7": 270,
|
||||
|
||||
"5ab8e4ed86f7742d8e50c7fa": 260,
|
||||
"5df8a2ca86f7740bfe6df777": 185,
|
||||
"64be79c487d1510151095552": 270,
|
||||
@ -1144,7 +1143,6 @@
|
||||
"5e4abb5086f77406975c9342": 4,
|
||||
"6038b4ca92ec1c3103795a0d": 4,
|
||||
"6038b4b292ec1c3103795a0b": 4,
|
||||
"628dc750b910320f4c27a732": 4,
|
||||
"5b44cd8b86f774503d30cba2": 4,
|
||||
"5ca21c6986f77479963115a7": 4,
|
||||
"5b44d0de86f774503d30cba8": 4,
|
||||
@ -1154,6 +1152,7 @@
|
||||
"545cdb794bdc2d3a198b456a": 4
|
||||
},
|
||||
"TacticalVest": {
|
||||
"5c0e446786f7742013381639": 210,
|
||||
"5e4abfed86f77406a2713cf7": 200,
|
||||
"5d5d8ca986f7742798716522": 200,
|
||||
"5d5d646386f7742797261fd9": 230,
|
||||
@ -1167,6 +1166,7 @@
|
||||
"60a3c68c37ea821725773ef5": 1,
|
||||
"5e4ac41886f77406a511c9a8": 1,
|
||||
"5b44cad286f77402a54ae7e5": 1,
|
||||
"628dc750b910320f4c27a732": 1,
|
||||
"5c0e3eb886f7742015526062": 230,
|
||||
"572b7adb24597762ae139821": 250,
|
||||
"544a5caa4bdc2d1a388b4568": 50,
|
||||
|
@ -5615,7 +5615,8 @@
|
||||
"5926dad986f7741f82604363"
|
||||
],
|
||||
"mod_muzzle": [
|
||||
"5926e16e86f7742f5a0f7ecb"
|
||||
"5926e16e86f7742f5a0f7ecb",
|
||||
"5c0000c00db834001a6697fc"
|
||||
],
|
||||
"mod_sight_rear": [
|
||||
"5926d2be86f774134d668e4e"
|
||||
|
@ -5612,7 +5612,8 @@
|
||||
"5926dad986f7741f82604363"
|
||||
],
|
||||
"mod_muzzle": [
|
||||
"5926e16e86f7742f5a0f7ecb"
|
||||
"5926e16e86f7742f5a0f7ecb",
|
||||
"5c0000c00db834001a6697fc"
|
||||
],
|
||||
"mod_sight_rear": [
|
||||
"5926d2be86f774134d668e4e"
|
||||
|
@ -13,6 +13,7 @@ import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||
import { ITemplateItem, Slot } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
||||
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
|
||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||
import { ModSpawn } from "@spt-aki/models/enums/ModSpawn";
|
||||
import { EquipmentFilterDetails, IBotConfig } from "@spt-aki/models/spt/config/IBotConfig";
|
||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||
@ -97,8 +98,8 @@ export class BotEquipmentModGenerator
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(this.shouldModBeSpawned(itemSlotTemplate, modSlotName.toLowerCase(), settings.spawnChances.equipmentMods) || forceSpawn))
|
||||
const modSpawnResult = this.shouldModBeSpawned(itemSlotTemplate, modSlotName.toLowerCase(), settings.spawnChances.equipmentMods);
|
||||
if (modSpawnResult === ModSpawn.SKIP && !forceSpawn)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -151,7 +152,7 @@ export class BotEquipmentModGenerator
|
||||
// Compatible item not found but slot REQUIRES item, get random item from db
|
||||
if (!found && itemSlotTemplate._required)
|
||||
{
|
||||
modTpl = this.getModTplFromItemDb(modTpl, itemSlotTemplate, modSlotName, equipment);
|
||||
modTpl = this.getRandomModTplFromItemDb(modTpl, itemSlotTemplate, modSlotName, equipment);
|
||||
found = !!modTpl;
|
||||
}
|
||||
|
||||
@ -251,7 +252,8 @@ export class BotEquipmentModGenerator
|
||||
this.logger.debug(`Plate filter was too restrictive for armor: ${armorItem._id}, unable to find plates of level: ${chosenArmorPlateLevel}. Using mod items default plate`);
|
||||
|
||||
const relatedItemDbModSlot = armorItem._props.Slots.find(slot => slot._name.toLowerCase() === modSlot);
|
||||
if (!relatedItemDbModSlot._props.filters[0].Plate)
|
||||
const defaultPlate = relatedItemDbModSlot._props.filters[0].Plate
|
||||
if (!defaultPlate)
|
||||
{
|
||||
// No relevant plate found after filtering AND no default plate
|
||||
|
||||
@ -275,7 +277,7 @@ export class BotEquipmentModGenerator
|
||||
}
|
||||
|
||||
result.result = Result.SUCCESS;
|
||||
result.plateModTpls = [relatedItemDbModSlot._props.filters[0].Plate];
|
||||
result.plateModTpls = [defaultPlate];
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -292,7 +294,7 @@ export class BotEquipmentModGenerator
|
||||
* @param sessionId session id
|
||||
* @param weapon Weapon to add mods to
|
||||
* @param modPool Pool of compatible mods to attach to weapon
|
||||
* @param weaponParentId parentId of weapon
|
||||
* @param weaponId parentId of weapon
|
||||
* @param parentTemplate Weapon which mods will be generated on
|
||||
* @param modSpawnChances Mod spawn chances
|
||||
* @param ammoTpl Ammo tpl to use when generating magazines/cartridges
|
||||
@ -306,7 +308,7 @@ export class BotEquipmentModGenerator
|
||||
sessionId: string,
|
||||
weapon: Item[],
|
||||
modPool: Mods,
|
||||
weaponParentId: string,
|
||||
weaponId: string,
|
||||
parentTemplate: ITemplateItem,
|
||||
modSpawnChances: ModsChances,
|
||||
ammoTpl: string,
|
||||
@ -366,7 +368,8 @@ export class BotEquipmentModGenerator
|
||||
}
|
||||
|
||||
// Check spawn chance of mod
|
||||
if (!this.shouldModBeSpawned(modsParentSlot, modSlot, modSpawnChances))
|
||||
const modSpawnResult = this.shouldModBeSpawned(modsParentSlot, modSlot, modSpawnChances);
|
||||
if (modSpawnResult === ModSpawn.SKIP)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -381,6 +384,7 @@ export class BotEquipmentModGenerator
|
||||
weapon,
|
||||
ammoTpl,
|
||||
parentTemplate,
|
||||
modSpawnResult
|
||||
);
|
||||
|
||||
// Compatible mod not found
|
||||
@ -465,7 +469,7 @@ export class BotEquipmentModGenerator
|
||||
|
||||
const modId = this.hashUtil.generate();
|
||||
weapon.push(
|
||||
this.createModItem(modId, modToAddTemplate._id, weaponParentId, modSlot, modToAddTemplate, botRole),
|
||||
this.createModItem(modId, modToAddTemplate._id, weaponId, modSlot, modToAddTemplate, botRole),
|
||||
);
|
||||
|
||||
// I first thought we could use the recursive generateModsForItems as previously for cylinder magazines.
|
||||
@ -684,24 +688,28 @@ export class BotEquipmentModGenerator
|
||||
|
||||
/**
|
||||
* Randomly choose if a mod should be spawned, 100% for required mods OR mod is ammo slot
|
||||
* never return true for an item that has 0% spawn chance
|
||||
* @param itemSlot slot the item sits in
|
||||
* @param modSlot slot the mod sits in
|
||||
* @param modSpawnChances Chances for various mod spawns
|
||||
* @returns boolean true if it should spawn
|
||||
* @returns ModSpawn.SPAWN when mod should be spawned, ModSpawn.DEFAULT_MOD when default mod should spawn, ModSpawn.SKIP when mod is skipped
|
||||
*/
|
||||
protected shouldModBeSpawned(itemSlot: Slot, modSlot: string, modSpawnChances: ModsChances): boolean
|
||||
protected shouldModBeSpawned(itemSlot: Slot, modSlot: string, modSpawnChances: ModsChances): ModSpawn
|
||||
{
|
||||
const modSpawnChance = itemSlot._required || this.getAmmoContainers().includes(modSlot) // Required OR it is ammo
|
||||
? 100
|
||||
: modSpawnChances[modSlot];
|
||||
|
||||
if (modSpawnChance === 100)
|
||||
const slotRequired = itemSlot._required;
|
||||
if (this.getAmmoContainers().includes(modSlot))
|
||||
{
|
||||
return true;
|
||||
return ModSpawn.SPAWN
|
||||
}
|
||||
const spawnMod = this.probabilityHelper.rollChance(modSpawnChances[modSlot]);
|
||||
if (!spawnMod && slotRequired)
|
||||
{
|
||||
// Mod is required but spawn chance roll failed, choose default mod spawn for slot
|
||||
return ModSpawn.DEFAULT_MOD;
|
||||
}
|
||||
|
||||
return this.probabilityHelper.rollChance(modSpawnChance);
|
||||
return spawnMod
|
||||
? ModSpawn.SPAWN
|
||||
: ModSpawn.SKIP;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -713,7 +721,7 @@ export class BotEquipmentModGenerator
|
||||
* @param weapon array with only weapon tpl in it, ready for mods to be added
|
||||
* @param ammoTpl ammo tpl to use if slot requires a cartridge to be added (e.g. mod_magazine)
|
||||
* @param parentTemplate Parent item the mod will go into
|
||||
* @returns ITemplateItem
|
||||
* @returns itemHelper.getItem() result
|
||||
*/
|
||||
protected chooseModToPutIntoSlot(
|
||||
modSlot: string,
|
||||
@ -724,11 +732,15 @@ export class BotEquipmentModGenerator
|
||||
weapon: Item[],
|
||||
ammoTpl: string,
|
||||
parentTemplate: ITemplateItem,
|
||||
modSpawnResult: ModSpawn
|
||||
): [boolean, ITemplateItem]
|
||||
{
|
||||
/** Chosen mod tpl */
|
||||
let modTpl: string;
|
||||
let found = false;
|
||||
/** Slot mod will fill */
|
||||
const parentSlot = parentTemplate._props.Slots.find((i) => i._name === modSlot);
|
||||
const weaponTemplate = this.itemHelper.getItem(weapon[0]._tpl)[1];
|
||||
|
||||
// It's ammo, use predefined ammo parameter
|
||||
if (this.getAmmoContainers().includes(modSlot) && modSlot !== "mod_magazine")
|
||||
@ -737,15 +749,11 @@ export class BotEquipmentModGenerator
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get randomised pool of mods if this is a slot we randomise
|
||||
if (isRandomisableSlot)
|
||||
{
|
||||
itemModPool[modSlot] = this.getDynamicModPool(parentTemplate._id, modSlot, botEquipBlacklist);
|
||||
}
|
||||
|
||||
// Ensure there's a pool of mods to pick from
|
||||
if (!(itemModPool[modSlot] || parentSlot._required))
|
||||
let modPool = this.getModPoolForSlot(itemModPool, modSpawnResult, parentTemplate, weaponTemplate, modSlot, botEquipBlacklist, isRandomisableSlot);
|
||||
if (!(modPool || parentSlot._required))
|
||||
{
|
||||
// Nothing in mod pool + item not required
|
||||
this.logger.debug(
|
||||
`Mod pool for slot: ${modSlot} on item: ${parentTemplate._name} was empty, skipping mod`,
|
||||
);
|
||||
@ -756,18 +764,18 @@ export class BotEquipmentModGenerator
|
||||
if (modSlot.includes("mod_scope") && botWeaponSightWhitelist)
|
||||
{
|
||||
// scope pool has more than one scope
|
||||
if (itemModPool[modSlot].length > 1)
|
||||
if (modPool.length > 1)
|
||||
{
|
||||
itemModPool[modSlot] = this.filterSightsByWeaponType(
|
||||
modPool = this.filterSightsByWeaponType(
|
||||
weapon[0],
|
||||
itemModPool[modSlot],
|
||||
modPool,
|
||||
botWeaponSightWhitelist,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Pick random mod and check it's compatible
|
||||
const exhaustableModPool = new ExhaustableArray(itemModPool[modSlot], this.randomUtil, this.jsonUtil);
|
||||
const exhaustableModPool = new ExhaustableArray(modPool, this.randomUtil, this.jsonUtil);
|
||||
let modCompatibilityResult: { incompatible: boolean; reason: string; } = {
|
||||
incompatible: false,
|
||||
reason: "",
|
||||
@ -799,7 +807,7 @@ export class BotEquipmentModGenerator
|
||||
// Get random mod to attach from items db for required slots if none found above
|
||||
if (!found && parentSlot !== undefined && parentSlot._required)
|
||||
{
|
||||
modTpl = this.getModTplFromItemDb(modTpl, parentSlot, modSlot, weapon);
|
||||
modTpl = this.getRandomModTplFromItemDb(modTpl, parentSlot, modSlot, weapon);
|
||||
found = !!modTpl;
|
||||
}
|
||||
|
||||
@ -826,6 +834,54 @@ export class BotEquipmentModGenerator
|
||||
return this.itemHelper.getItem(modTpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter mod pool down based on various criteria:
|
||||
* Is slot flagged as randomisable
|
||||
* Is slot required
|
||||
* Is slot flagged as default mod only
|
||||
* @param itemModPool Existing pool of mods to choose
|
||||
* @param modSpawnResult outcome of random roll to select if mod should be added
|
||||
* @param parentTemplate Mods parent
|
||||
* @param weaponTemplate Mods root parent (weapon/equipment)
|
||||
* @param modSlot name of mod slot to choose for
|
||||
* @param botEquipBlacklist
|
||||
* @param isRandomisableSlot is flagged as a randomisable slot
|
||||
* @returns
|
||||
*/
|
||||
protected getModPoolForSlot(
|
||||
itemModPool: Record<string, string[]>,
|
||||
modSpawnResult: ModSpawn,
|
||||
parentTemplate: ITemplateItem,
|
||||
weaponTemplate: ITemplateItem,
|
||||
modSlot: string,
|
||||
botEquipBlacklist: EquipmentFilterDetails,
|
||||
isRandomisableSlot: boolean): string[]
|
||||
{
|
||||
// Mod is flagged as being default only, try and find it in globals
|
||||
if (modSpawnResult === ModSpawn.DEFAULT_MOD)
|
||||
{
|
||||
const defaultWeaponPreset = this.presetHelper.getDefaultPreset(weaponTemplate._id)
|
||||
const matchingMod = defaultWeaponPreset._items.find(item => item?.slotId?.toLowerCase() === modSlot.toLowerCase());
|
||||
if (matchingMod)
|
||||
{
|
||||
return [matchingMod._tpl];
|
||||
}
|
||||
|
||||
this.logger.warning(`No default: ${modSlot} mod found on: ${weaponTemplate._name}`);
|
||||
|
||||
// Couuldnt find default in globals, use existing mod pool data
|
||||
return itemModPool[modSlot];
|
||||
}
|
||||
|
||||
if (isRandomisableSlot)
|
||||
{
|
||||
return this.getDynamicModPool(parentTemplate._id, modSlot, botEquipBlacklist);
|
||||
}
|
||||
|
||||
// Required mod is not default or randomisable, use existing pool
|
||||
return itemModPool[modSlot];
|
||||
}
|
||||
|
||||
/**
|
||||
* Temp fix to prevent certain combinations of weapons with mods that are known to be incompatible
|
||||
* @param weapon Weapon
|
||||
@ -888,7 +944,7 @@ export class BotEquipmentModGenerator
|
||||
* @param items items to ensure picked mod is compatible with
|
||||
* @returns item tpl
|
||||
*/
|
||||
protected getModTplFromItemDb(modTpl: string, parentSlot: Slot, modSlot: string, items: Item[]): string
|
||||
protected getRandomModTplFromItemDb(modTpl: string, parentSlot: Slot, modSlot: string, items: Item[]): string
|
||||
{
|
||||
// Find compatible mods and make an array of them
|
||||
const allowedItems = parentSlot._props.filters[0].Filter;
|
||||
|
@ -175,7 +175,7 @@ export class BotWeaponGenerator
|
||||
sessionId,
|
||||
weaponWithModsArray,
|
||||
modPool,
|
||||
weaponWithModsArray[0]._id,
|
||||
weaponWithModsArray[0]._id, // Weapon root id
|
||||
weaponItemTemplate,
|
||||
modChances,
|
||||
ammoTpl,
|
||||
|
5
project/src/models/enums/ModSpawn.ts
Normal file
5
project/src/models/enums/ModSpawn.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export enum ModSpawn {
|
||||
DEFAULT_MOD,
|
||||
SPAWN,
|
||||
SKIP
|
||||
}
|
Loading…
Reference in New Issue
Block a user