Updated Progressive Bot System

This commit is contained in:
Rage 2025-01-07 19:03:11 -05:00
parent 79c3c5eec2
commit 7ff0b39d88
151 changed files with 600497 additions and 14180 deletions

View File

@ -1,7 +1,7 @@
[General]
gameName=spt
modid=0
version=d2025.1.3.0
version=d2025.1.7.0
newestVersion=
category="1,"
nexusFileStatus=1

View File

@ -1,6 +1,6 @@
{
"name": "Acids Progressive Bot System",
"version": "1.3.1",
"version": "1.4.0-alpha",
"sptVersion": "~3.10",
"loadBefore": [],
"loadAfter": [

View File

@ -558,6 +558,7 @@
"56e335e4d2720b6c058b456d": 20,
"5ca20d5986f774331e7c9602": 10,
"5e9dcf5986f7746c417435b3": 10,
"59e763f286f7742ee57895da": 15,
"6038d614d10cbf667352dd44": 1,
"6034d103ca006d2dca39b3f0": 1,
"656ddcf0f02d7bcea90bf395": 1,

View File

@ -614,6 +614,7 @@
"56e335e4d2720b6c058b456d": 20,
"5ca20d5986f774331e7c9602": 10,
"5e9dcf5986f7746c417435b3": 10,
"59e763f286f7742ee57895da": 15,
"6038d614d10cbf667352dd44": 1,
"6034d103ca006d2dca39b3f0": 1,
"656ddcf0f02d7bcea90bf395": 1,

View File

@ -866,6 +866,7 @@
"56e335e4d2720b6c058b456d": 20,
"5ca20d5986f774331e7c9602": 10,
"5e9dcf5986f7746c417435b3": 10,
"59e763f286f7742ee57895da": 15,
"6038d614d10cbf667352dd44": 1,
"6034d103ca006d2dca39b3f0": 1,
"656ddcf0f02d7bcea90bf395": 1,
@ -877,7 +878,6 @@
"5c0e805e86f774683f3dd637": 1,
"5ab8ebf186f7742d8b372e80": 1,
"639346cc1c8f182ad90c8972": 1,
"59e763f286f7742ee57895da": 1,
"5b44c6ae86f7742d1627baea": 1,
"5d5d940f86f7742797262046": 1,
"5df8a4d786f77412672a1e3b": 1,

View File

@ -798,6 +798,7 @@
"56e335e4d2720b6c058b456d": 20,
"5ca20d5986f774331e7c9602": 10,
"5e9dcf5986f7746c417435b3": 10,
"59e763f286f7742ee57895da": 15,
"6038d614d10cbf667352dd44": 1,
"6034d103ca006d2dca39b3f0": 1,
"656ddcf0f02d7bcea90bf395": 1,
@ -809,7 +810,6 @@
"5c0e805e86f774683f3dd637": 1,
"5ab8ebf186f7742d8b372e80": 1,
"639346cc1c8f182ad90c8972": 1,
"59e763f286f7742ee57895da": 1,
"5b44c6ae86f7742d1627baea": 1,
"5d5d940f86f7742797262046": 1,
"5df8a4d786f77412672a1e3b": 1,

View File

@ -784,6 +784,7 @@
"56e335e4d2720b6c058b456d": 20,
"5ca20d5986f774331e7c9602": 10,
"5e9dcf5986f7746c417435b3": 10,
"59e763f286f7742ee57895da": 15,
"6038d614d10cbf667352dd44": 1,
"6034d103ca006d2dca39b3f0": 1,
"656ddcf0f02d7bcea90bf395": 1,
@ -795,7 +796,6 @@
"5c0e805e86f774683f3dd637": 1,
"5ab8ebf186f7742d8b372e80": 1,
"639346cc1c8f182ad90c8972": 1,
"59e763f286f7742ee57895da": 1,
"5b44c6ae86f7742d1627baea": 1,
"5d5d940f86f7742797262046": 1,
"5df8a4d786f77412672a1e3b": 1,

View File

@ -764,6 +764,7 @@
"56e335e4d2720b6c058b456d": 20,
"5ca20d5986f774331e7c9602": 10,
"5e9dcf5986f7746c417435b3": 10,
"59e763f286f7742ee57895da": 15,
"6038d614d10cbf667352dd44": 1,
"6034d103ca006d2dca39b3f0": 1,
"656ddcf0f02d7bcea90bf395": 1,
@ -775,7 +776,6 @@
"5c0e805e86f774683f3dd637": 1,
"5ab8ebf186f7742d8b372e80": 1,
"639346cc1c8f182ad90c8972": 1,
"59e763f286f7742ee57895da": 1,
"5b44c6ae86f7742d1627baea": 1,
"5d5d940f86f7742797262046": 1,
"5df8a4d786f77412672a1e3b": 1,

View File

@ -23,6 +23,33 @@ export class BotConfigs
protected botConfig: IBotConfig;
protected pmcConfig: IPmcConfig;
private pmcLimitedCategories = {
"5448e8d04bdc2ddf718b4569": 1,
"5448e8d64bdc2dce718b4568": 1,
"5448f39d4bdc2d0a728b4568": 1,
"5448f3a64bdc2d60728b456a": 2,
"5448f3ac4bdc2dce718b4569": 1,
"5448f3a14bdc2d27728b4569": 1,
"5c99f98d86f7745c314214b3": 1,
"5c164d2286f774194c5e69fa": 1,
"550aa4cd4bdc2dd8348b456c": 2,
"55818add4bdc2d5b648b456f": 1,
"55818ad54bdc2ddc698b4569": 1,
"55818aeb4bdc2ddc698b456a": 1,
"55818ae44bdc2dde698b456c": 1,
"55818af64bdc2d5b648b4570": 1,
"5448e54d4bdc2dcc718b4568": 1,
"5447e1d04bdc2dff2f8b4567": 1,
"5a341c4686f77469e155819e": 1,
"55818b164bdc2ddc698b456c": 2,
"5448bc234bdc2d3c308b4569": 2,
"543be5dd4bdc2deb348b4569": 1,
"543be5cb4bdc2deb348b4568": 2,
"5485a8684bdc2da71d8b4567": 2,
"5d650c3e815116009f6201d2": 2,
"543be6564bdc2df4348b4568": 1
}
constructor(
@inject("IDatabaseTables") protected tables: IDatabaseTables,
@inject("DatabaseService") protected database: DatabaseService,
@ -40,25 +67,33 @@ export class BotConfigs
public initialize(): void
{
if (!ModConfig.config.disablePMCTierGeneration)
{
this.setPMCItemLimits();
this.setPMCLoot();
this.setPMCScopeWhitelist();
this.setPMCSlotIDsToMakeRequired();
if (ModConfig.config.gameVersionWeight) this.setPMCGameVersionWeights();
}
if (!ModConfig.config.disableScavTierGeneration)
{
if (ModConfig.config.addAllKeysToScavs || ModConfig.config.addOnlyKeyCardsToScavs || ModConfig.config.addOnlyMechanicalKeysToScavs) this.pushScavKeys();
if (!ModConfig.config.scavLoot) this.removeScavLoot();
}
this.clearNoLongerNeededBotDetails();
this.configureBotExperienceLevels();
this.configurePlateWeightings();
this.configureWeaponDurability();
this.adjustNVG();
this.setLootItemResourceRandomization();
this.setPMCItemLimits();
this.setPMCLoot();
this.setPMCScopeWhitelist();
this.setPMCSlotIDsToMakeRequired();
this.removeThermalGoggles(ModConfig.config.enableT7Thermals);
if (ModConfig.config.gameVersionWeight) this.setPMCGameVersionWeights();
if (ModConfig.config.addAllKeysToScavs || ModConfig.config.addOnlyKeyCardsToScavs || ModConfig.config.addOnlyMechanicalKeysToScavs) this.pushScavKeys();
if (ModConfig.config.enableCustomPlateChances) this.setPlateChances();
if (ModConfig.config.forceStock) this.setForceStock();
if (ModConfig.config.forceDustCover) this.setForceDustCover();
if (ModConfig.config.forceScopeSlot) this.setForceScopes();
if (ModConfig.config.forceWeaponModLimits) this.setWeaponModLimits();
if (!ModConfig.config.scavLoot) this.removeScavLoot();
if (ModConfig.config.enableScavEqualEquipmentTiering) this.setIdenticalScavWeights();
if (ModConfig.config.enableCustomLevelDeltas) this.setLevelDeltas();
if (ModConfig.config.enableScavCustomLevelDeltas) this.setScavLevelDeltas();
@ -319,21 +354,24 @@ export class BotConfigs
private setPMCItemLimits(): void
{
this.botConfig.itemSpawnLimits.pmc["60098ad7c2240c0fe85c570a"] = 1;
this.botConfig.itemSpawnLimits.pmc["590c678286f77426c9660122"] = 1;
this.botConfig.itemSpawnLimits.pmc["5e831507ea0a7c419c2f9bd9"] = 1;
this.botConfig.itemSpawnLimits.pmc["590c661e86f7741e566b646a"] = 1;
this.botConfig.itemSpawnLimits.pmc["544fb45d4bdc2dee738b4568"] = 1;
this.botConfig.itemSpawnLimits.pmc["5e8488fa988a8701445df1e4"] = 1;
this.botConfig.itemSpawnLimits.pmc["544fb37f4bdc2dee738b4567"] = 1;
this.botConfig.itemSpawnLimits.pmc["5448e8d04bdc2ddf718b4569"] = 1;
this.botConfig.itemSpawnLimits.pmc["5448e8d64bdc2dce718b4568"] = 1;
// Clear PMC item limits
this.botConfig.itemSpawnLimits.pmc = {}
// Go through custom limits and add them
for (const [item, count] of Object.entries(this.pmcLimitedCategories))
{
this.botConfig.itemSpawnLimits.pmc[item] = count;
}
}
private setPMCLoot(): void
{
const allBots = this.database.getTables().bots.types;
this.pmcConfig.looseWeaponInBackpackLootMinMax.min = 0;
this.pmcConfig.looseWeaponInBackpackLootMinMax.max = 0;
this.botConfig.equipment.pmc.randomisation = [];
if (ModConfig.config.pmcLoot)
{
if (ModConfig.config.pmcLootBlacklistItems.length > 0)
@ -345,77 +383,22 @@ export class BotConfigs
this.pmcConfig.pocketLoot.blacklist.push(item);
}
}
for (const level in this.tierInformation.lootRandomization)
}
if (!ModConfig.config.pmcLoot)
{
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["0"] = 1
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["3"] = 2
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["5"] = 5
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["8"] = 6
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["10"] = 5
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["12"] = 4
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["15"] = 4
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["20"] = 3
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["23"] = 1
this.tierInformation.lootRandomization[level].generation.pocketLoot.weights["0"] = 1
this.tierInformation.lootRandomization[level].generation.pocketLoot.weights["1"] = 3
this.tierInformation.lootRandomization[level].generation.pocketLoot.weights["2"] = 4
this.tierInformation.lootRandomization[level].generation.pocketLoot.weights["3"] = 2
this.tierInformation.lootRandomization[level].generation.pocketLoot.weights["4"] = 1
this.tierInformation.lootRandomization[level].generation.vestLoot.weights["0"] = 1
this.tierInformation.lootRandomization[level].generation.vestLoot.weights["1"] = 2
this.tierInformation.lootRandomization[level].generation.vestLoot.weights["2"] = 3
this.tierInformation.lootRandomization[level].generation.vestLoot.weights["3"] = 2
this.tierInformation.lootRandomization[level].generation.vestLoot.weights["4"] = 1
this.botConfig.disableLootOnBotTypes.push("pmcusec", "pmcbear")
}
for (const tierObject in this.tierInformation.tiers)
for (const botType in allBots)
{
const tierNumber = this.tierInformation.tiers[tierObject].tier
const tierJson = this.apbsEquipmentGetter.getTierChancesJson(tierNumber);
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["0"] = 4
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["1"] = 15
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["2"] = 40
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["3"] = 10
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["4"] = 8
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["5"] = 2
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["10"] = 1
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["0"] = 4
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["1"] = 15
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["2"] = 40
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["3"] = 10
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["4"] = 8
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["5"] = 2
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["10"] = 1
tierJson.pmcUSEC.chances.generation.items.pocketLoot.weights["0"] = 4
tierJson.pmcUSEC.chances.generation.items.pocketLoot.weights["1"] = 9
tierJson.pmcUSEC.chances.generation.items.pocketLoot.weights["2"] = 1
tierJson.pmcUSEC.chances.generation.items.pocketLoot.weights["3"] = 1
tierJson.pmcBEAR.chances.generation.items.pocketLoot.weights["0"] = 4
tierJson.pmcBEAR.chances.generation.items.pocketLoot.weights["1"] = 9
tierJson.pmcBEAR.chances.generation.items.pocketLoot.weights["2"] = 1
tierJson.pmcBEAR.chances.generation.items.pocketLoot.weights["3"] = 1
tierJson.pmcUSEC.chances.generation.items.vestLoot.weights["0"] = 2
tierJson.pmcUSEC.chances.generation.items.vestLoot.weights["1"] = 12
tierJson.pmcUSEC.chances.generation.items.vestLoot.weights["2"] = 1
tierJson.pmcUSEC.chances.generation.items.vestLoot.weights["3"] = 1
tierJson.pmcUSEC.chances.generation.items.vestLoot.weights["4"] = 1
tierJson.pmcBEAR.chances.generation.items.vestLoot.weights["0"] = 2
tierJson.pmcBEAR.chances.generation.items.vestLoot.weights["1"] = 12
tierJson.pmcBEAR.chances.generation.items.vestLoot.weights["2"] = 1
tierJson.pmcBEAR.chances.generation.items.vestLoot.weights["3"] = 1
tierJson.pmcBEAR.chances.generation.items.vestLoot.weights["4"] = 1
}
this.botConfig.equipment.pmc.randomisation = this.tierInformation.lootRandomization;
}
else
if (botType == "pmcbear" || botType == "pmcusec")
{
this.botConfig.equipment.pmc.randomisation = this.tierInformation.lootRandomization;
allBots[botType].inventory.items.Backpack = {};
allBots[botType].inventory.items.Pockets = {};
allBots[botType].inventory.items.TacticalVest = {};
allBots[botType].inventory.items.SpecialLoot = {};
}
}
}
private setPMCScopeWhitelist(): void
@ -514,12 +497,7 @@ export class BotConfigs
private removeScavLoot(): void
{
this.tables.bots.types.assault.inventory.items.Backpack = {}
this.tables.bots.types.assault.inventory.items.Pockets = {}
this.tables.bots.types.assault.inventory.items.TacticalVest = {}
this.tables.bots.types.marksman.inventory.items.Backpack = {}
this.tables.bots.types.marksman.inventory.items.Pockets = {}
this.tables.bots.types.marksman.inventory.items.TacticalVest = {}
this.botConfig.disableLootOnBotTypes.push("assault", "marksman");
}
private setIdenticalScavWeights(): void

View File

@ -40,6 +40,8 @@ import { RaidInformation } from "../Globals/RaidInformation";
import { ModInformation } from "../Globals/ModInformation";
import { APBSTester } from "../Utils/APBSTester";
import { vanillaButtpads } from "../Globals/VanillaItemLists";
import { APBSLogger } from "../Utils/APBSLogger";
import { Logging } from "../Enums/Logging";
/** Handle profile related client events */
@injectable()
@ -70,7 +72,8 @@ export class APBSBotEquipmentModGenerator extends BotEquipmentModGenerator
@inject("APBSTierGetter") protected apbsTierGetter: APBSTierGetter,
@inject("RaidInformation") protected raidInformation: RaidInformation,
@inject("ModInformation") protected modInformation: ModInformation,
@inject("APBSTester") protected apbsTester: APBSTester
@inject("APBSTester") protected apbsTester: APBSTester,
@inject("APBSLogger") protected apbsLogger: APBSLogger
)
{
super(logger,
@ -101,43 +104,14 @@ export class APBSBotEquipmentModGenerator extends BotEquipmentModGenerator
const botRole = settings.botData.role;
const tier = this.apbsTierGetter.getTierByLevel(settings.botData.level);
const tieredModPool = this.apbsEquipmentGetter.getModsByBotRole(botRole, tier)
let spawnChances = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tier);
let compatibleModsPool = tieredModPool[parentTemplate._id]
let actualModPool = tieredModPool;
let spawnChances = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tier);
// Roll weapon spawns (primary/secondary/holster) and generate a weapon for each roll that passed
if ((ModConfig.config.disableBossTierGeneration && (botRole.includes("boss") || botRole.includes("sectant") || botRole.includes("arena"))) || botRole == "bosslegion" || botRole == "bosspunisher")
{
spawnChances = settings.spawnChances;
compatibleModsPool = settings.modPool[parentTemplate._id];
actualModPool = settings.modPool;
}
if (ModConfig.config.disableBossFollowerTierGeneration && botRole.includes("follower"))
{
spawnChances = settings.spawnChances;
compatibleModsPool = settings.modPool[parentTemplate._id];
actualModPool = settings.modPool;
}
if (ModConfig.config.disableRaiderRogueTierGeneration && (botRole.includes("exusec") || botRole.includes("pmcbot")))
{
spawnChances = settings.spawnChances;
compatibleModsPool = settings.modPool[parentTemplate._id];
actualModPool = settings.modPool;
}
if (ModConfig.config.disablePMCTierGeneration && (botRole.includes("pmcusec") || botRole.includes("pmcbear")))
{
spawnChances = settings.spawnChances;
compatibleModsPool = settings.modPool[parentTemplate._id];
actualModPool = settings.modPool;
}
if (ModConfig.config.disableScavTierGeneration && (botRole.includes("assault") || botRole.includes("marksman")))
{
spawnChances = settings.spawnChances;
compatibleModsPool = settings.modPool[parentTemplate._id];
actualModPool = settings.modPool;
}
if (botRole.includes("infected") || botRole.includes("spirit") || botRole.includes("skier") || botRole.includes("peacemaker") || botRole.includes("gifter"))
if (!this.raidInformation.isBotEnabled(botRole))
{
this.apbsLogger.log(Logging.DEBUG, `${botRole} is disabled - TRACE: generateModsForEquipment`);
spawnChances = settings.spawnChances;
compatibleModsPool = settings.modPool[parentTemplate._id];
actualModPool = settings.modPool;

View File

@ -31,6 +31,9 @@ import { ProfileHelper } from "@spt/helpers/ProfileHelper";
import { WeatherHelper } from "@spt/helpers/WeatherHelper";
import { BotEquipmentFilterService } from "@spt/services/BotEquipmentFilterService";
import { IGetRaidConfigurationRequestData } from "@spt/models/eft/match/IGetRaidConfigurationRequestData";
import { RaidInformation } from "../Globals/RaidInformation";
import { APBSLogger } from "../Utils/APBSLogger";
import { Logging } from "../Enums/Logging";
/** Handle profile related client events */
@injectable()
@ -57,7 +60,9 @@ export class APBSBotInventoryGenerator extends BotInventoryGenerator
@inject("ConfigServer") protected configServer: ConfigServer,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("APBSTierGetter") protected apbsTierGetter: APBSTierGetter,
@inject("APBSBotWeaponGenerator") protected apbsBotWeaponGenerator: APBSBotWeaponGenerator
@inject("APBSBotWeaponGenerator") protected apbsBotWeaponGenerator: APBSBotWeaponGenerator,
@inject("RaidInformation") protected raidInformation: RaidInformation,
@inject("APBSLogger") protected apbsLogger: APBSLogger
)
{
super(logger,
@ -90,8 +95,8 @@ export class APBSBotInventoryGenerator extends BotInventoryGenerator
): PmcInventory
{
const templateInventory = botJsonTemplate.inventory;
let wornItemChances = botJsonTemplate.chances;
const itemGenerationLimitsMinMax = botJsonTemplate.generation;
const wornItemChances = botJsonTemplate.chances;
const itemGenerationLimitsMinMax: IGeneration = botJsonTemplate.generation;
// Generate base inventory with no items
const botInventory = this.generateInventoryBase();
@ -110,45 +115,10 @@ export class APBSBotInventoryGenerator extends BotInventoryGenerator
chosenGameVersion,
raidConfig
);
// Roll weapon spawns (primary/secondary/holster) and generate a weapon for each roll that passed
if (((botRole.includes("boss") || botRole.includes("sectant") || botRole.includes("arena")) && ModConfig.config.disableBossTierGeneration) || botRole == "bosslegion" || botRole == "bosspunisher")
{
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
}
if (botRole.includes("follower") && ModConfig.config.disableBossFollowerTierGeneration)
{
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
}
if ((botRole.includes("exusec") || botRole.includes("pmcbot")) && !ModConfig.config.disableRaiderRogueTierGeneration)
{
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
}
if (botRole.includes("pmc") && ModConfig.config.disablePMCTierGeneration)
{
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
}
if ((botRole.includes("assault") || botRole.includes("marksman")) && ModConfig.config.disableScavTierGeneration)
{
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
}
if (botRole.includes("infected") || botRole.includes("spirit") || botRole.includes("skier") || botRole.includes("peacemaker") || botRole.includes("gifter"))
if (!this.raidInformation.isBotEnabled(botRole))
{
this.apbsLogger.log(Logging.DEBUG, `${botRole} is disabled - TRACE: generateInventory`);
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
@ -157,8 +127,10 @@ export class APBSBotInventoryGenerator extends BotInventoryGenerator
// APBS generation chances instead
const tierInfo = this.apbsTierGetter.getTierByLevel(botLevel);
wornItemChances = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tierInfo);
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
const chances = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tierInfo);
const generation = chances.generation;
this.generateAndAddWeaponsToBot(templateInventory, chances, sessionId, botInventory, botRole, isPmc, generation, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
@ -178,48 +150,9 @@ export class APBSBotInventoryGenerator extends BotInventoryGenerator
let modPool = this.apbsEquipmentGetter.getModsByBotRole(botRole, tierInfo);
let apbsBot = true;
if ((ModConfig.config.disableBossTierGeneration && (botRole.includes("boss") || botRole.includes("sectant") || botRole.includes("arena"))) || botRole == "bosslegion" || botRole == "bosspunisher")
{
equipmentPool = settings.rootEquipmentPool;
randomisationDetails = settings.randomisationDetails;
wornItemChances = settings.spawnChances;
modPool = settings.modPool;
apbsBot = false;
}
if (ModConfig.config.disableBossFollowerTierGeneration && botRole.includes("follower"))
{
equipmentPool = settings.rootEquipmentPool;
randomisationDetails = settings.randomisationDetails;
wornItemChances = settings.spawnChances;
modPool = settings.modPool;
apbsBot = false;
}
if (ModConfig.config.disableRaiderRogueTierGeneration && (botRole.includes("exusec") || botRole.includes("pmcbot")))
{
equipmentPool = settings.rootEquipmentPool;
randomisationDetails = settings.randomisationDetails;
wornItemChances = settings.spawnChances;
modPool = settings.modPool;
apbsBot = false;
}
if (ModConfig.config.disablePMCTierGeneration && (botRole.includes("pmcusec") || botRole.includes("pmcbear")))
{
equipmentPool = settings.rootEquipmentPool;
randomisationDetails = settings.randomisationDetails;
wornItemChances = settings.spawnChances;
modPool = settings.modPool;
apbsBot = false;
}
if (ModConfig.config.disableScavTierGeneration && (botRole.includes("assault") || botRole.includes("marksman")))
{
equipmentPool = settings.rootEquipmentPool;
randomisationDetails = settings.randomisationDetails;
wornItemChances = settings.spawnChances;
modPool = settings.modPool;
apbsBot = false;
}
if (botRole.includes("infected") || botRole.includes("spirit") || botRole.includes("skier") || botRole.includes("peacemaker") || botRole.includes("gifter"))
if (!this.raidInformation.isBotEnabled(botRole))
{
this.apbsLogger.log(Logging.DEBUG, `${botRole} is disabled - TRACE: generateEquipment`);
equipmentPool = settings.rootEquipmentPool;
randomisationDetails = settings.randomisationDetails;
wornItemChances = settings.spawnChances;

View File

@ -0,0 +1,475 @@
import { inject, injectable } from "tsyringe";
import { ItemHelper } from "@spt/helpers/ItemHelper";
import { IBotType, IGenerationWeightingItems } from "@spt/models/eft/common/tables/IBotType";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { APBSTierGetter } from "../Utils/APBSTierGetter";
import { RagfairPriceService } from "@spt/services/RagfairPriceService";
import { PMCLootGenerator } from "@spt/generators/PMCLootGenerator";
import { BotLootCacheService } from "@spt/services/BotLootCacheService";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { DatabaseServer } from "@spt/servers/DatabaseServer";
import { LocalisationService } from "@spt/services/LocalisationService";
import { ICloner } from "@spt/utils/cloners/ICloner";
import { BaseClasses } from "@spt/models/enums/BaseClasses";
import { IBotLootCache, LootCacheType } from "@spt/models/spt/bots/IBotLootCache";
import { RaidInformation } from "../Globals/RaidInformation";
import { APBSLogger } from "../Utils/APBSLogger";
import { Logging } from "../Enums/Logging";
@injectable()
export class APBSBotLootCacheService extends BotLootCacheService
{
protected apbsLootCache: Record<string, IBotLootCache>;
constructor(
@inject("PrimaryLogger") protected logger: ILogger,
@inject("ItemHelper") protected itemHelper: ItemHelper,
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
@inject("PMCLootGenerator") protected pmcLootGenerator: PMCLootGenerator,
@inject("LocalisationService") protected localisationService: LocalisationService,
@inject("RagfairPriceService") protected ragfairPriceService: RagfairPriceService,
@inject("PrimaryCloner") protected cloner: ICloner,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("APBSTierGetter") protected apbsTierGetter: APBSTierGetter,
@inject("RaidInformation") protected raidInformation: RaidInformation,
@inject("APBSLogger") protected apbsLogger: APBSLogger
)
{
super(logger,
itemHelper,
databaseServer,
pmcLootGenerator,
localisationService,
ragfairPriceService,
cloner)
this.apbsClearCache();
this.clearCache();
}
public apbsClearCache(): void
{
this.apbsLootCache = {};
}
public apbsBotRoleExistsInCache(combinedBotRoleTier: string): boolean
{
return !!this.apbsLootCache[combinedBotRoleTier];
}
public apbsInitCacheForBotRole(combinedBotRoleTier: string): void
{
this.apbsLootCache[combinedBotRoleTier] = {
backpackLoot: {},
pocketLoot: {},
vestLoot: {},
secureLoot: {},
combinedPoolLoot: {},
specialItems: {},
grenadeItems: {},
drugItems: {},
foodItems: {},
drinkItems: {},
currencyItems: {},
healingItems: {},
stimItems: {}
};
}
public apbsGetLootFromCache(
botRole: string,
isPmc: boolean,
lootType: LootCacheType,
botJsonTemplate: IBotType,
botLevel: number
): Record<string, number>
{
const tierInfo = this.apbsTierGetter.getTierByLevel(botLevel).toString();
const combinedBotRoleTier = botRole + tierInfo;
if (!this.apbsBotRoleExistsInCache(combinedBotRoleTier))
{
this.apbsInitCacheForBotRole(combinedBotRoleTier);
this.apbsAddLootToCache(botRole, isPmc, botJsonTemplate, botLevel);
}
let result = undefined;
switch (lootType)
{
case LootCacheType.SPECIAL:
result = this.apbsLootCache[combinedBotRoleTier].specialItems;
break;
case LootCacheType.BACKPACK:
result = this.apbsLootCache[combinedBotRoleTier].backpackLoot;
break;
case LootCacheType.POCKET:
result = this.apbsLootCache[combinedBotRoleTier].pocketLoot;
break;
case LootCacheType.VEST:
result = this.apbsLootCache[combinedBotRoleTier].vestLoot;
break;
case LootCacheType.SECURE:
result = this.apbsLootCache[combinedBotRoleTier].secureLoot;
break;
case LootCacheType.COMBINED:
result = this.apbsLootCache[combinedBotRoleTier].combinedPoolLoot;
break;
case LootCacheType.HEALING_ITEMS:
result = this.apbsLootCache[combinedBotRoleTier].healingItems;
break;
case LootCacheType.GRENADE_ITEMS:
result = this.apbsLootCache[combinedBotRoleTier].grenadeItems;
break;
case LootCacheType.DRUG_ITEMS:
result = this.apbsLootCache[combinedBotRoleTier].drugItems;
break;
case LootCacheType.FOOD_ITEMS:
result = this.apbsLootCache[combinedBotRoleTier].foodItems;
break;
case LootCacheType.DRINK_ITEMS:
result = this.apbsLootCache[combinedBotRoleTier].drinkItems;
break;
case LootCacheType.CURRENCY_ITEMS:
result = this.apbsLootCache[combinedBotRoleTier].currencyItems;
break;
case LootCacheType.STIM_ITEMS:
result = this.apbsLootCache[combinedBotRoleTier].stimItems;
break;
default:
this.logger.error(
this.localisationService.getText("bot-loot_type_not_found", {
lootType: lootType,
botRole: botRole,
isPmc: isPmc
})
);
break;
}
return this.cloner.clone(result);
}
public apbsAddLootToCache(botRole: string, isPmc: boolean, botJsonTemplate: IBotType, botLevel: number): void
{
const tierInfo = this.apbsTierGetter.getTierByLevel(botLevel);
const combinedBotRoleTier = botRole + tierInfo;
const chances = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tierInfo);
let realWhitelist: IGenerationWeightingItems = chances.generation.items;
if (!this.raidInformation.isBotEnabled(botRole))
{
this.apbsLogger.log(Logging.DEBUG, `${botRole} is disabled - TRACE: addLootToCache`);
realWhitelist = botJsonTemplate.generation.items;
}
// the full pool of loot we use to create the various sub-categories with
const lootPool = botJsonTemplate.inventory.items;
// Flatten all individual slot loot pools into one big pool, while filtering out potentially missing templates
const specialLootPool: Record<string, number> = {};
const backpackLootPool: Record<string, number> = {};
const pocketLootPool: Record<string, number> = {};
const vestLootPool: Record<string, number> = {};
const secureLootTPool: Record<string, number> = {};
const combinedLootPool: Record<string, number> = {};
if (isPmc)
{
// Replace lootPool from bot json with our own generated list for PMCs
lootPool.Backpack = this.cloner.clone(this.pmcLootGenerator.generatePMCBackpackLootPool(botRole));
lootPool.Pockets = this.cloner.clone(this.pmcLootGenerator.generatePMCPocketLootPool(botRole));
lootPool.TacticalVest = this.cloner.clone(this.pmcLootGenerator.generatePMCVestLootPool(botRole));
}
// Backpack/Pockets etc
for (const [slot, pool] of Object.entries(lootPool))
{
// No items to add, skip
if (Object.keys(pool).length === 0)
{
continue;
}
// Sort loot pool into separate buckets
switch (slot.toLowerCase())
{
case "specialloot":
this.addItemsToPool(specialLootPool, pool);
break;
case "pockets":
this.addItemsToPool(pocketLootPool, pool);
break;
case "tacticalvest":
this.addItemsToPool(vestLootPool, pool);
break;
case "securedcontainer":
this.addItemsToPool(secureLootTPool, pool);
break;
case "backpack":
this.addItemsToPool(backpackLootPool, pool);
break;
default:
this.logger.warning(`How did you get here ${slot}`);
}
// Add all items (if any) to combined pool (excluding secure)
if (Object.keys(pool).length > 0 && slot.toLowerCase() !== "securedcontainer")
{
this.addItemsToPool(combinedLootPool, pool);
}
}
// Assign whitelisted special items to bot if any exist
const specialLootItems: Record<string, number> =
Object.keys(realWhitelist.specialItems.whitelist)?.length > 0
? realWhitelist.specialItems.whitelist
: {};
// no whitelist, find and assign from combined item pool
if (Object.keys(specialLootItems).length === 0)
{
for (const [tpl, weight] of Object.entries(specialLootPool))
{
const itemTemplate = this.itemHelper.getItem(tpl)[1];
if (!(this.isBulletOrGrenade(itemTemplate._props) || this.isMagazine(itemTemplate._props)))
{
specialLootItems[tpl] = weight;
}
}
}
// Assign whitelisted healing items to bot if any exist
const healingItems: Record<string, number> =
Object.keys(realWhitelist.healing.whitelist)?.length > 0
? realWhitelist.healing.whitelist
: {};
// No whitelist, find and assign from combined item pool
if (Object.keys(healingItems).length === 0)
{
for (const [tpl, weight] of Object.entries(combinedLootPool))
{
const itemTemplate = this.itemHelper.getItem(tpl)[1];
if (
this.isMedicalItem(itemTemplate._props) &&
itemTemplate._parent !== BaseClasses.STIMULATOR &&
itemTemplate._parent !== BaseClasses.DRUGS
)
{
healingItems[tpl] = weight;
}
}
}
// Assign whitelisted drugs to bot if any exist
const drugItems: Record<string, number> =
Object.keys(realWhitelist.drugs.whitelist)?.length > 0
? realWhitelist.drugs.whitelist
: {};
// no drugs whitelist, find and assign from combined item pool
if (Object.keys(drugItems).length === 0)
{
for (const [tpl, weight] of Object.entries(combinedLootPool))
{
const itemTemplate = this.itemHelper.getItem(tpl)[1];
if (this.isMedicalItem(itemTemplate._props) && itemTemplate._parent === BaseClasses.DRUGS)
{
drugItems[tpl] = weight;
}
}
}
// Assign whitelisted food to bot if any exist
const foodItems: Record<string, number> =
Object.keys(realWhitelist.food.whitelist)?.length > 0
? realWhitelist.food.whitelist
: {};
// No food whitelist, find and assign from combined item pool
if (Object.keys(foodItems).length === 0)
{
for (const [tpl, weight] of Object.entries(combinedLootPool))
{
const itemTemplate = this.itemHelper.getItem(tpl)[1];
if (this.itemHelper.isOfBaseclass(itemTemplate._id, BaseClasses.FOOD))
{
foodItems[tpl] = weight;
}
}
}
// Assign whitelisted drink to bot if any exist
const drinkItems: Record<string, number> =
Object.keys(realWhitelist.food.whitelist)?.length > 0
? realWhitelist.food.whitelist
: {};
// No drink whitelist, find and assign from combined item pool
if (Object.keys(drinkItems).length === 0)
{
for (const [tpl, weight] of Object.entries(combinedLootPool))
{
const itemTemplate = this.itemHelper.getItem(tpl)[1];
if (this.itemHelper.isOfBaseclass(itemTemplate._id, BaseClasses.DRINK))
{
drinkItems[tpl] = weight;
}
}
}
// Assign whitelisted currency to bot if any exist
const currencyItems: Record<string, number> =
Object.keys(realWhitelist.currency.whitelist)?.length > 0
? realWhitelist.currency.whitelist
: {};
// No currency whitelist, find and assign from combined item pool
if (Object.keys(currencyItems).length === 0)
{
for (const [tpl, weight] of Object.entries(combinedLootPool))
{
const itemTemplate = this.itemHelper.getItem(tpl)[1];
if (this.itemHelper.isOfBaseclass(itemTemplate._id, BaseClasses.MONEY))
{
currencyItems[tpl] = weight;
}
}
}
// Assign whitelisted stims to bot if any exist
const stimItems: Record<string, number> =
Object.keys(realWhitelist.stims.whitelist)?.length > 0
? realWhitelist.stims.whitelist
: {};
// No whitelist, find and assign from combined item pool
if (Object.keys(stimItems).length === 0)
{
for (const [tpl, weight] of Object.entries(combinedLootPool))
{
const itemTemplate = this.itemHelper.getItem(tpl)[1];
if (this.isMedicalItem(itemTemplate._props) && itemTemplate._parent === BaseClasses.STIMULATOR)
{
stimItems[tpl] = weight;
}
}
}
// Assign whitelisted grenades to bot if any exist
const grenadeItems: Record<string, number> =
Object.keys(realWhitelist.grenades.whitelist)?.length > 0
? realWhitelist.grenades.whitelist
: {};
// no whitelist, find and assign from combined item pool
if (Object.keys(grenadeItems).length === 0)
{
for (const [tpl, weight] of Object.entries(combinedLootPool))
{
const itemTemplate = this.itemHelper.getItem(tpl)[1];
if (this.isGrenade(itemTemplate._props))
{
grenadeItems[tpl] = weight;
}
}
}
// Get backpack loot (excluding magazines, bullets, grenades, drink, food and healing/stim items)
const filteredBackpackItems = {};
for (const itemKey of Object.keys(backpackLootPool))
{
const itemResult = this.itemHelper.getItem(itemKey);
if (!itemResult[0])
{
continue;
}
const itemTemplate = itemResult[1];
if (
this.isBulletOrGrenade(itemTemplate._props) ||
this.isMagazine(itemTemplate._props) ||
this.isMedicalItem(itemTemplate._props) ||
this.isGrenade(itemTemplate._props) ||
this.isFood(itemTemplate._id) ||
this.isDrink(itemTemplate._id) ||
this.isCurrency(itemTemplate._id)
)
{
// Is type we dont want as backpack loot, skip
continue;
}
filteredBackpackItems[itemKey] = backpackLootPool[itemKey];
}
// Get pocket loot (excluding magazines, bullets, grenades, drink, food medical and healing/stim items)
const filteredPocketItems = {};
for (const itemKey of Object.keys(pocketLootPool))
{
const itemResult = this.itemHelper.getItem(itemKey);
if (!itemResult[0])
{
continue;
}
const itemTemplate = itemResult[1];
if (
this.isBulletOrGrenade(itemTemplate._props) ||
this.isMagazine(itemTemplate._props) ||
this.isMedicalItem(itemTemplate._props) ||
this.isGrenade(itemTemplate._props) ||
this.isFood(itemTemplate._id) ||
this.isDrink(itemTemplate._id) ||
this.isCurrency(itemTemplate._id) ||
!("Height" in itemTemplate._props) || // lacks height
!("Width" in itemTemplate._props) // lacks width
)
{
continue;
}
filteredPocketItems[itemKey] = pocketLootPool[itemKey];
}
// Get vest loot (excluding magazines, bullets, grenades, medical and healing/stim items)
const filteredVestItems = {};
for (const itemKey of Object.keys(vestLootPool))
{
const itemResult = this.itemHelper.getItem(itemKey);
if (!itemResult[0])
{
continue;
}
const itemTemplate = itemResult[1];
if (
this.isBulletOrGrenade(itemTemplate._props) ||
this.isMagazine(itemTemplate._props) ||
this.isMedicalItem(itemTemplate._props) ||
this.isGrenade(itemTemplate._props) ||
this.isFood(itemTemplate._id) ||
this.isDrink(itemTemplate._id) ||
this.isCurrency(itemTemplate._id)
)
{
continue;
}
filteredVestItems[itemKey] = vestLootPool[itemKey];
}
this.apbsLootCache[combinedBotRoleTier].healingItems = healingItems;
this.apbsLootCache[combinedBotRoleTier].drugItems = drugItems;
this.apbsLootCache[combinedBotRoleTier].foodItems = foodItems;
this.apbsLootCache[combinedBotRoleTier].drinkItems = drinkItems;
this.apbsLootCache[combinedBotRoleTier].currencyItems = currencyItems;
this.apbsLootCache[combinedBotRoleTier].stimItems = stimItems;
this.apbsLootCache[combinedBotRoleTier].grenadeItems = grenadeItems;
this.apbsLootCache[combinedBotRoleTier].specialItems = specialLootItems;
this.apbsLootCache[combinedBotRoleTier].backpackLoot = filteredBackpackItems;
this.apbsLootCache[combinedBotRoleTier].pocketLoot = filteredPocketItems;
this.apbsLootCache[combinedBotRoleTier].vestLoot = filteredVestItems;
this.apbsLootCache[combinedBotRoleTier].secureLoot = secureLootTPool;
}
}

View File

@ -23,6 +23,12 @@ import { BotLootGenerator } from "@spt/generators/BotLootGenerator";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { APBSTierGetter } from "../Utils/APBSTierGetter";
import { APBSBotLootCacheService } from "./APBSBotLootCacheService";
import { RaidInformation } from "../Globals/RaidInformation";
import { APBSLogger } from "../Utils/APBSLogger";
import { Logging } from "../Enums/Logging";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import { IItemSpawnLimitSettings } from "@spt/models/spt/bots/IItemSpawnLimitSettings";
/** Handle profile related client events */
@injectable()
@ -45,7 +51,10 @@ export class APBSBotLootGenerator extends BotLootGenerator
@inject("ConfigServer") protected configServer: ConfigServer,
@inject("PrimaryCloner") protected cloner: ICloner,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("APBSTierGetter") protected apbsTierGetter: APBSTierGetter
@inject("APBSTierGetter") protected apbsTierGetter: APBSTierGetter,
@inject("RaidInformation") protected raidInformation: RaidInformation,
@inject("APBSBotLootCacheService") protected apbsBotLootCacheService: APBSBotLootCacheService,
@inject("APBSLogger") protected apbsLogger: APBSLogger
)
{
super(logger,
@ -73,11 +82,19 @@ export class APBSBotLootGenerator extends BotLootGenerator
botInventory: PmcInventory,
botLevel: number
): void
{// Limits on item types to be added as loot
{
// Limits on item types to be added as loot
const tierInfo = this.apbsTierGetter.getTierByLevel(botLevel);
const chances = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tierInfo);
const itemCounts: IGenerationWeightingItems = chances.generation.items;
let itemCounts: IGenerationWeightingItems = chances.generation.items;
let useOriginalLootCache = false;
if (!this.raidInformation.isBotEnabled(botRole))
{
this.apbsLogger.log(Logging.DEBUG, `${botRole} is disabled - TRACE: generateLoot`);
itemCounts = botJsonTemplate.generation.items;
useOriginalLootCache = true;
}
if (
!itemCounts.backpackLoot.weights
@ -101,22 +118,16 @@ export class APBSBotLootGenerator extends BotLootGenerator
let backpackLootCount = Number(
this.weightedRandomHelper.getWeightedValue<number>(itemCounts.backpackLoot.weights)
);
let pocketLootCount = Number(
this.weightedRandomHelper.getWeightedValue<number>(itemCounts.pocketLoot.weights)
);
let pocketLootCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.pocketLoot.weights));
let vestLootCount = this.weightedRandomHelper.getWeightedValue<number>(itemCounts.vestLoot.weights);
const specialLootItemCount = Number(
this.weightedRandomHelper.getWeightedValue<number>(itemCounts.specialItems.weights)
);
const specialLootItemCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.specialItems.weights));
const healingItemCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.healing.weights));
const drugItemCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.drugs.weights));
const foodItemCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.food.weights));
const drinkItemCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.drink.weights));
let currencyItemCount = Number(
this.weightedRandomHelper.getWeightedValue<number>(itemCounts.currency.weights)
);
let currencyItemCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.currency.weights));
const stimItemCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.stims.weights));
const grenadeCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.grenades.weights));
@ -146,7 +157,9 @@ export class APBSBotLootGenerator extends BotLootGenerator
// Special items
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.SPECIAL, botJsonTemplate),
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.SPECIAL, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.SPECIAL, botJsonTemplate, botLevel),
containersBotHasAvailable,
specialLootItemCount,
botInventory,
@ -159,12 +172,14 @@ export class APBSBotLootGenerator extends BotLootGenerator
// Healing items / Meds
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.HEALING_ITEMS, botJsonTemplate),
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.HEALING_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.HEALING_ITEMS, botJsonTemplate, botLevel),
containersBotHasAvailable,
healingItemCount,
botInventory,
botRole,
undefined,
botItemLimits,
0,
isPmc,
containersIdFull
@ -172,12 +187,14 @@ export class APBSBotLootGenerator extends BotLootGenerator
// Drugs
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.DRUG_ITEMS, botJsonTemplate),
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.DRUG_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.DRUG_ITEMS, botJsonTemplate, botLevel),
containersBotHasAvailable,
drugItemCount,
botInventory,
botRole,
undefined,
botItemLimits,
0,
isPmc,
containersIdFull
@ -185,12 +202,14 @@ export class APBSBotLootGenerator extends BotLootGenerator
// Food
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.FOOD_ITEMS, botJsonTemplate),
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.FOOD_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.FOOD_ITEMS, botJsonTemplate, botLevel),
containersBotHasAvailable,
foodItemCount,
botInventory,
botRole,
undefined,
botItemLimits,
0,
isPmc,
containersIdFull
@ -198,12 +217,14 @@ export class APBSBotLootGenerator extends BotLootGenerator
// Drink
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.DRINK_ITEMS, botJsonTemplate),
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.DRINK_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.DRINK_ITEMS, botJsonTemplate, botLevel),
containersBotHasAvailable,
drinkItemCount,
botInventory,
botRole,
undefined,
botItemLimits,
0,
isPmc,
containersIdFull
@ -211,12 +232,14 @@ export class APBSBotLootGenerator extends BotLootGenerator
// Currency
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.CURRENCY_ITEMS, botJsonTemplate),
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.CURRENCY_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.CURRENCY_ITEMS, botJsonTemplate, botLevel),
containersBotHasAvailable,
currencyItemCount,
botInventory,
botRole,
undefined,
botItemLimits,
0,
isPmc,
containersIdFull
@ -224,7 +247,9 @@ export class APBSBotLootGenerator extends BotLootGenerator
// Stims
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.STIM_ITEMS, botJsonTemplate),
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.STIM_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.STIM_ITEMS, botJsonTemplate, botLevel),
containersBotHasAvailable,
stimItemCount,
botInventory,
@ -237,12 +262,14 @@ export class APBSBotLootGenerator extends BotLootGenerator
// Grenades
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.GRENADE_ITEMS, botJsonTemplate),
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.GRENADE_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.GRENADE_ITEMS, botJsonTemplate, botLevel),
[EquipmentSlots.POCKETS, EquipmentSlots.TACTICAL_VEST], // Can't use containersBotHasEquipped as we dont want grenades added to backpack
grenadeCount,
botInventory,
botRole,
undefined,
botItemLimits,
0,
isPmc,
containersIdFull
@ -269,7 +296,9 @@ export class APBSBotLootGenerator extends BotLootGenerator
const backpackLootRoubleTotal = this.getBackpackRoubleTotalByLevel(botLevel, isPmc);
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.BACKPACK, botJsonTemplate),
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.BACKPACK, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.BACKPACK, botJsonTemplate, botLevel),
[EquipmentSlots.BACKPACK],
backpackLootCount,
botInventory,
@ -286,7 +315,9 @@ export class APBSBotLootGenerator extends BotLootGenerator
{
// Vest
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.VEST, botJsonTemplate),
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.VEST, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.VEST, botJsonTemplate, botLevel),
[EquipmentSlots.TACTICAL_VEST],
vestLootCount,
botInventory,
@ -300,7 +331,9 @@ export class APBSBotLootGenerator extends BotLootGenerator
// Pockets
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.POCKET, botJsonTemplate),
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.POCKET, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.POCKET, botJsonTemplate, botLevel),
[EquipmentSlots.POCKETS],
pocketLootCount,
botInventory,
@ -317,7 +350,9 @@ export class APBSBotLootGenerator extends BotLootGenerator
if (!isPmc || (isPmc && this.pmcConfig.addSecureContainerLootFromBotConfig))
{
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.SECURE, botJsonTemplate),
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.SECURE, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.SECURE, botJsonTemplate, botLevel),
[EquipmentSlots.SECURED_CONTAINER],
50,
botInventory,
@ -329,4 +364,56 @@ export class APBSBotLootGenerator extends BotLootGenerator
);
}
}
protected override itemHasReachedSpawnLimit(
itemTemplate: ITemplateItem,
botRole: string,
itemSpawnLimits: IItemSpawnLimitSettings
): boolean
{
// PMCs and scavs have different sections of bot config for spawn limits
if (!!itemSpawnLimits && Object.keys(itemSpawnLimits.globalLimits).length === 0)
{
// No items found in spawn limit, drop out
return false;
}
// No spawn limits, skipping
if (!itemSpawnLimits)
{
return false;
}
const idToCheckFor = this.getMatchingIdFromSpawnLimits(itemTemplate, itemSpawnLimits.globalLimits);
if (!idToCheckFor)
{
// ParentId or tplid not found in spawnLimits, not a spawn limited item, skip
return false;
}
// Increment item count with this bot type
itemSpawnLimits.currentLimits[idToCheckFor]++;
// Check if over limit
if (itemSpawnLimits.currentLimits[idToCheckFor] > itemSpawnLimits.globalLimits[idToCheckFor])
{
// Prevent edge-case of small loot pools + code trying to add limited item over and over infinitely
if (itemSpawnLimits.currentLimits[idToCheckFor] > itemSpawnLimits.globalLimits[idToCheckFor] * 10)
{
this.logger.debug(
this.localisationService.getText("bot-item_spawn_limit_reached_skipping_item", {
botRole: botRole,
itemName: itemTemplate._name,
attempts: itemSpawnLimits.currentLimits[idToCheckFor]
})
);
return false;
}
return true;
}
return false;
}
}

View File

@ -85,34 +85,10 @@ export class APBSBotWeaponGenerator extends BotWeaponGenerator
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
// Config disable checks to flip to default weapon gen
if ((ModConfig.config.disableBossTierGeneration && (botRole.includes("boss") || botRole.includes("sectant") || botRole.includes("arena"))) || botRole == "bosslegion" || botRole == "bosspunisher")
{
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
if (ModConfig.config.disableBossFollowerTierGeneration && botRole.includes("follower"))
{
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
if (ModConfig.config.disableRaiderRogueTierGeneration && (botRole.includes("exusec") || botRole.includes("pmcbot")))
{
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
if (ModConfig.config.disablePMCTierGeneration && (botRole.includes("pmcusec") || botRole.includes("pmcbear")))
{
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
if (ModConfig.config.disableScavTierGeneration && (botRole.includes("assault") || botRole.includes("marksman")))
{
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
if (botRole.includes("infected") || botRole.includes("spirit") || botRole.includes("skier") || botRole.includes("peacemaker") || botRole.includes("gifter"))
// Check if bot disabled, if it is - use SPT code
if (!this.raidInformation.isBotEnabled(botRole))
{
this.apbsLogger.log(Logging.DEBUG, `${botRole} is disabled - TRACE: generateRandomWeapon`);
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}

View File

@ -0,0 +1,143 @@
import { inject, injectable } from "tsyringe";
import { BotGenerator } from "@spt/generators/BotGenerator";
import { BotGeneratorHelper } from "@spt/helpers/BotGeneratorHelper";
import { BotHelper } from "@spt/helpers/BotHelper";
import { ItemHelper } from "@spt/helpers/ItemHelper";
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
import { IPmcData } from "@spt/models/eft/common/IPmcData";
import { IBotInfoSettings } from "@spt/models/eft/common/tables/IBotBase";
import { IBotType } from "@spt/models/eft/common/tables/IBotType";
import { MemberCategory } from "@spt/models/enums/MemberCategory";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { SaveServer } from "@spt/servers/SaveServer";
import { BotLootCacheService } from "@spt/services/BotLootCacheService";
import { DatabaseService } from "@spt/services/DatabaseService";
import { FenceService } from "@spt/services/FenceService";
import { LocalisationService } from "@spt/services/LocalisationService";
import { HashUtil } from "@spt/utils/HashUtil";
import { RandomUtil } from "@spt/utils/RandomUtil";
import { ICloner } from "@spt/utils/cloners/ICloner";
import { PlayerScavGenerator } from "@spt/generators/PlayerScavGenerator";
import { APBSBotLootCacheService } from "./APBSBotLootCacheService";
@injectable()
export class APBSPlayerScavGenerator extends PlayerScavGenerator
{
constructor(
@inject("PrimaryLogger") protected logger: ILogger,
@inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("DatabaseService") protected databaseService: DatabaseService,
@inject("HashUtil") protected hashUtil: HashUtil,
@inject("ItemHelper") protected itemHelper: ItemHelper,
@inject("BotGeneratorHelper") protected botGeneratorHelper: BotGeneratorHelper,
@inject("SaveServer") protected saveServer: SaveServer,
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
@inject("BotHelper") protected botHelper: BotHelper,
@inject("FenceService") protected fenceService: FenceService,
@inject("BotLootCacheService") protected botLootCacheService: BotLootCacheService,
@inject("LocalisationService") protected localisationService: LocalisationService,
@inject("BotGenerator") protected botGenerator: BotGenerator,
@inject("ConfigServer") protected configServer: ConfigServer,
@inject("PrimaryCloner") protected cloner: ICloner,
@inject("APBSBotLootCacheService") protected apbsBotLootCacheService: APBSBotLootCacheService
)
{
super(logger,
randomUtil,
databaseService,
hashUtil,
itemHelper,
botGeneratorHelper,
saveServer,
profileHelper,
botHelper,
fenceService,
botLootCacheService,
localisationService,
botGenerator,
configServer,
cloner)
}
public generate(sessionID: string): IPmcData
{
// get karma level from profile
const profile = this.saveServer.getProfile(sessionID);
const profileCharactersClone = this.cloner.clone(profile.characters);
const pmcDataClone = profileCharactersClone.pmc;
const existingScavDataClone = profileCharactersClone.scav;
const scavKarmaLevel = this.getScavKarmaLevel(pmcDataClone);
// use karma level to get correct karmaSettings
const playerScavKarmaSettings = this.playerScavConfig.karmaLevel[scavKarmaLevel];
if (!playerScavKarmaSettings)
{
this.logger.error(this.localisationService.getText("scav-missing_karma_settings", scavKarmaLevel));
}
this.logger.debug(`generated player scav loadout with karma level ${scavKarmaLevel}`);
// Edit baseBotNode values
const baseBotNode: IBotType = this.constructBotBaseTemplate(playerScavKarmaSettings.botTypeForLoot);
this.adjustBotTemplateWithKarmaSpecificSettings(playerScavKarmaSettings, baseBotNode);
let scavData = this.botGenerator.generatePlayerScav(
sessionID,
playerScavKarmaSettings.botTypeForLoot.toLowerCase(),
"easy",
baseBotNode,
pmcDataClone
);
// Remove cached bot data after scav was generated
this.botLootCacheService.clearCache();
this.apbsBotLootCacheService.apbsClearCache();
// Add scav metadata
scavData.savage = undefined;
scavData.aid = pmcDataClone.aid;
scavData.TradersInfo = pmcDataClone.TradersInfo;
scavData.Info.Settings = {} as IBotInfoSettings;
scavData.Info.Bans = [];
scavData.Info.RegistrationDate = pmcDataClone.Info.RegistrationDate;
scavData.Info.GameVersion = pmcDataClone.Info.GameVersion;
scavData.Info.MemberCategory = MemberCategory.UNIQUE_ID;
scavData.Info.lockedMoveCommands = true;
scavData.RagfairInfo = pmcDataClone.RagfairInfo;
scavData.UnlockedInfo = pmcDataClone.UnlockedInfo;
// Persist previous scav data into new scav
scavData._id = existingScavDataClone._id ?? pmcDataClone.savage;
scavData.sessionId = existingScavDataClone.sessionId ?? pmcDataClone.sessionId;
scavData.Skills = this.getScavSkills(existingScavDataClone);
scavData.Stats = this.getScavStats(existingScavDataClone);
scavData.Info.Level = this.getScavLevel(existingScavDataClone);
scavData.Info.Experience = this.getScavExperience(existingScavDataClone);
scavData.Quests = existingScavDataClone.Quests ?? [];
scavData.TaskConditionCounters = existingScavDataClone.TaskConditionCounters ?? {};
scavData.Notes = existingScavDataClone.Notes ?? { Notes: [] };
scavData.WishList = existingScavDataClone.WishList ?? {};
scavData.Encyclopedia = pmcDataClone.Encyclopedia ?? {};
// Add additional items to player scav as loot
this.addAdditionalLootToPlayerScavContainers(playerScavKarmaSettings.lootItemsToAddChancePercent, scavData, [
"TacticalVest",
"Pockets",
"Backpack"
]);
// Remove secure container
scavData = this.profileHelper.removeSecureContainer(scavData);
// Set cooldown timer
scavData = this.setScavCooldownTimer(scavData, pmcDataClone);
// Add scav to the profile
this.saveServer.getProfile(sessionID).characters.scav = scavData;
return scavData;
}
}

View File

@ -39,19 +39,6 @@ export class APBSBotLevelGenerator
{
result.generateBotLevel = (levelDetails: MinMax, botGenerationDetails: IBotGenerationDetails, bot: APBSIBotBase): IRandomisedBotLevelResult =>
{
/*
TESTING TIER DEVIATION - Since botGenerationDetails isn't passed to the relevant methods, this is more difficult that anticipated. This logic works for the tier, but since selection is based on level..oof.
-2 to +1 tier
const lowerDeviation = (Math.floor(Math.random() * 2) - 2);
const upperDeviation = (Math.floor(Math.random() * 2));
const minTier = (tier + lowerDeviation) <= 0 ? 1 : tier + lowerDeviation
const maxTier = (tier + upperDeviation) >= 7 ? 7 : tier + upperDeviation
const newTier = this.randomUtil.getInt(minTier, maxTier)
console.log(`Original Tier: ${tier} - New Tier ${newTier}`)
*/
if (this.modInformation.testMode && this.modInformation.testBotRole.includes(botGenerationDetails.role.toLowerCase()))
{
const level = this.profileHelper.getPmcProfile(this.raidInformation.sessionId)?.Info?.Level;

View File

@ -1,4 +1,5 @@
import { injectable, inject } from "tsyringe";
import { injectable } from "tsyringe";
import { ModConfig } from "./ModConfig";
@injectable()
export class RaidInformation
@ -81,4 +82,88 @@ export class RaidInformation
"ShortRange": 80
}
}
public alwaysDisabledBots = [
"shooterbtr",
"skier",
"peacemaker",
"gifter",
"infectedassault",
"infectedcivil",
"infectedlaborant",
"infectedpmc",
"infectedtagilla",
"bosslegion",
"bosspunisher"
]
public isBotEnabled(botType: string): boolean
{
botType = botType.toLowerCase();
switch (botType)
{
case "pmcbear":
case "pmcusec":
if (ModConfig.config.disablePMCTierGeneration) return false;
return true;
case "cursedassault":
case "marksman":
case "assault":
if (ModConfig.config.disableScavTierGeneration) return false;
return true;
case "arenafighterevent":
case "exusec":
if (ModConfig.config.disableRaiderRogueTierGeneration) return false;
return true;
case "bossbully":
case "bosstagilla":
case "bosspartisan":
case "bossgluhar":
case "bosskilla":
case "bosskojaniy":
case "bosssanitar":
case "bossknight":
case "bosszryachiy":
case "bosstest":
case "bosskolontay":
case "bossboar":
case "bossboarSniper":
case "sectantpriest":
if (ModConfig.config.disableBossTierGeneration) return false;
return true;
case "sectantwarrior":
case "followerboarblose1":
case "followerboarclose2":
case "followerkolontayassault":
case "followerkolontaysecurity":
case "followerbully":
case "followergluharassault":
case "followergluharscout":
case "followergluharsecurity":
case "followergluharsnipe":
case "followerkojaniy":
case "followersanitar":
case "followertagilla":
case "followerbirdeye":
case "followerbigpipe":
case "followerzryachiy":
case "followertest":
case "followerboar":
if (ModConfig.config.disableBossFollowerTierGeneration) return false;
return true;
case "shooterbtr":
case "skier":
case "peacemaker":
case "gifter":
case "infectedassault":
case "infectedcivil":
case "infectedlaborant":
case "infectedpmc":
case "infectedtagilla":
case "bosslegion":
case "bosspunisher":
return false;
default:
return false;
}
}
}

View File

@ -370,343 +370,4 @@ export class TierInformation
}
}
]
public lootRandomization = [
{
"levelRange": {
"min": 1,
"max": 15
},
"generation": {
"drugs": {
"weights": {
"0": 1
},
"whitelist": {}
},
"grenades": {
"weights": {
"0": 45,
"1": 35,
"2": 1
},
"whitelist": {
"5710c24ad2720bc3458b45a3": 25,
"58d3db5386f77426186285a0": 25,
"5448be9a4bdc2dfd2f8b456a": 25
}
},
"healing": {
"weights": {
"0": 10,
"1": 85,
"2": 20
},
"whitelist": {
"5755356824597772cb798962": 4,
"590c661e86f7741e566b646a": 9,
"544fb45d4bdc2dee738b4568": 2,
"5e831507ea0a7c419c2f9bd9": 6
}
},
"backpackLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"pocketLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"vestLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"magazines": {
"weights": {
"0": 0,
"1": 10,
"2": 55,
"3": 25
},
"whitelist": {}
},
"stims": {
"weights": {
"0": 100,
"1": 1
},
"whitelist": {
"544fb3f34bdc2d03748b456a": 25,
"5c0e530286f7747fa1419862": 65
}
}
}
},
{
"levelRange": {
"min": 16,
"max": 30
},
"generation": {
"drugs": {
"weights": {
"0": 1,
"1": 1
},
"whitelist": {}
},
"grenades": {
"weights": {
"0": 15,
"1": 35,
"2": 5,
"3": 0
},
"whitelist": {
"5710c24ad2720bc3458b45a3": 25,
"58d3db5386f77426186285a0": 25,
"5448be9a4bdc2dfd2f8b456a": 25,
"5e32f56fcb6d5863cc5e5ee4": 5,
"5e340dcdcb6d5863cc5e5efb": 1
}
},
"healing": {
"weights": {
"0": 1,
"1": 25,
"2": 65,
"3": 10
},
"whitelist": {
"60098ad7c2240c0fe85c570a": 15,
"590c678286f77426c9660122": 10,
"5e8488fa988a8701445df1e4": 12
}
},
"backpackLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"pocketLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"vestLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"magazines": {
"weights": {
"0": 0,
"1": 1,
"2": 55,
"3": 25
},
"whitelist": {}
},
"stims": {
"weights": {
"0": 75,
"1": 20,
"2": 5
},
"whitelist": {
"544fb3f34bdc2d03748b456a": 1,
"5c0e530286f7747fa1419862": 65,
"5c0e534186f7747fa1419867": 12,
"5c0e531d86f7747fa23f4d42": 8,
"5ed51652f6c34d2cc26336a1": 17
}
}
}
},
{
"levelRange": {
"min": 31,
"max": 45
},
"generation": {
"drugs": {
"weights": {
"0": 1,
"1": 1
},
"whitelist": {}
},
"grenades": {
"weights": {
"0": 1,
"1": 15,
"2": 25,
"3": 10
},
"whitelist": {
"5710c24ad2720bc3458b45a3": 15,
"58d3db5386f77426186285a0": 15,
"5448be9a4bdc2dfd2f8b456a": 15,
"5e32f56fcb6d5863cc5e5ee4": 45,
"5e340dcdcb6d5863cc5e5efb": 20,
"617fd91e5539a84ec44ce155": 5,
"618a431df1eb8e24b8741deb": 5
}
},
"healing": {
"weights": {
"0": 1,
"1": 15,
"2": 65,
"3": 30,
"4": 5
},
"whitelist": {
"60098ad7c2240c0fe85c570a": 45,
"590c678286f77426c9660122": 20,
"5e8488fa988a8701445df1e4": 45
}
},
"backpackLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"pocketLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"vestLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"magazines": {
"weights": {
"0": 0,
"1": 1,
"2": 55,
"3": 25
},
"whitelist": {}
},
"stims": {
"weights": {
"0": 50,
"1": 20,
"2": 5
},
"whitelist": {
"544fb3f34bdc2d03748b456a": 1,
"5c0e530286f7747fa1419862": 65,
"5c0e534186f7747fa1419867": 12,
"5c0e531d86f7747fa23f4d42": 8,
"5ed51652f6c34d2cc26336a1": 17
}
}
}
},
{
"levelRange": {
"min": 46,
"max": 100
},
"generation": {
"drugs": {
"weights": {
"0": 1,
"1": 1
},
"whitelist": {}
},
"grenades": {
"weights": {
"0": 1,
"1": 15,
"2": 20,
"3": 15
},
"whitelist": {
"5710c24ad2720bc3458b45a3": 1,
"58d3db5386f77426186285a0": 1,
"5448be9a4bdc2dfd2f8b456a": 1,
"5e32f56fcb6d5863cc5e5ee4": 35,
"5e340dcdcb6d5863cc5e5efb": 35,
"617fd91e5539a84ec44ce155": 10,
"618a431df1eb8e24b8741deb": 10
}
},
"healing": {
"weights": {
"0": 1,
"1": 15,
"2": 35,
"3": 75,
"4": 20
},
"whitelist": {
"60098ad7c2240c0fe85c570a": 45,
"590c678286f77426c9660122": 20,
"5e8488fa988a8701445df1e4": 45
}
},
"backpackLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"pocketLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"vestLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"magazines": {
"weights": {
"0": 0,
"1": 1,
"2": 25,
"3": 55
},
"whitelist": {}
},
"stims": {
"weights": {
"0": 50,
"1": 20,
"2": 5
},
"whitelist": {
"544fb3f34bdc2d03748b456a": 1,
"5c0e530286f7747fa1419862": 65,
"5c0e534186f7747fa1419867": 12,
"5c0e531d86f7747fa23f4d42": 8,
"5ed51652f6c34d2cc26336a1": 17
}
}
}
}
]
}

View File

@ -27,6 +27,7 @@ import { BotGeneratorHelper } from "@spt/helpers/BotGeneratorHelper";
import { BotWeaponGeneratorHelper } from "@spt/helpers/BotWeaponGeneratorHelper";
import { BotWeaponModLimitService } from "@spt/services/BotWeaponModLimitService";
import { RepairService } from "@spt/services/RepairService";
import { SeasonalEventService } from "@spt/services/SeasonalEventService";
import { VFS } from "@spt/utils/VFS";
// Custom
@ -52,7 +53,8 @@ import { BlacklistHelper } from "./Helpers/BlacklistHelper";
import { RealismHelper } from "./Helpers/RealismHelper";
import { APBSTester } from "./Utils/APBSTester";
import { APBSAttachmentChecker } from "./Utils/APBSAttachmentChecker";
import { SeasonalEventService } from "@spt/services/SeasonalEventService";
import { APBSBotLootCacheService } from "./ClassExtensions/APBSBotLootCacheService";
import { APBSPlayerScavGenerator } from "./ClassExtensions/APBSPlayerScavGenerator";
export class InstanceManager
{
@ -182,6 +184,10 @@ export class InstanceManager
this.container.register("BotInventoryGenerator", { useToken: "APBSBotInventoryGenerator" });
this.container.register<APBSBotEquipmentModGenerator>("APBSBotEquipmentModGenerator", APBSBotEquipmentModGenerator);
this.container.register("BotEquipmentModGenerator", { useToken: "APBSBotEquipmentModGenerator" });
this.container.register<APBSPlayerScavGenerator>("APBSPlayerScavGenerator", APBSPlayerScavGenerator);
this.container.register("PlayerScavGenerator", { useToken: "APBSPlayerScavGenerator" });
this.container.register<APBSBotLootCacheService>("APBSBotLootCacheService", APBSBotLootCacheService);
this.container.register("BotLootCacheService", { useToken: "APBSBotLootCacheService" });
this.container.register<APBSBotLootGenerator>("APBSBotLootGenerator", APBSBotLootGenerator);
this.container.register("BotLootGenerator", { useToken: "APBSBotLootGenerator" });
this.container.register<APBSBotWeaponGenerator>("APBSBotWeaponGenerator", APBSBotWeaponGenerator);

View File

@ -178,6 +178,27 @@ export class APBSEquipmentGetter
const tierJson = this.getTierModsJson(tierInfo)
switch (botRole)
{
case "bossboar":
case "bossboarsniper":
case "bossbully":
case "bossgluhar":
case "bosskilla":
case "bosskojaniy":
case "bosskolontay":
case "bosssanitar":
case "bosstagilla":
case "bosspartisan":
case "bossknight":
case "followerbigpipe":
case "followerbirdeye":
case "sectantpriest":
case "sectantwarrior":
case "exusec":
case "arenafighterevent":
case "arenafighter":
case "pmcbot":
if (tierInfo < 4) return this.tierInformation.tier4mods;
else return tierJson;
case "marksman":
case "cursedassault":
case "assault":

View File

@ -558,6 +558,7 @@
"56e335e4d2720b6c058b456d": 20,
"5ca20d5986f774331e7c9602": 10,
"5e9dcf5986f7746c417435b3": 10,
"59e763f286f7742ee57895da": 15,
"6038d614d10cbf667352dd44": 1,
"6034d103ca006d2dca39b3f0": 1,
"656ddcf0f02d7bcea90bf395": 1,

View File

@ -614,6 +614,7 @@
"56e335e4d2720b6c058b456d": 20,
"5ca20d5986f774331e7c9602": 10,
"5e9dcf5986f7746c417435b3": 10,
"59e763f286f7742ee57895da": 15,
"6038d614d10cbf667352dd44": 1,
"6034d103ca006d2dca39b3f0": 1,
"656ddcf0f02d7bcea90bf395": 1,

View File

@ -866,6 +866,7 @@
"56e335e4d2720b6c058b456d": 20,
"5ca20d5986f774331e7c9602": 10,
"5e9dcf5986f7746c417435b3": 10,
"59e763f286f7742ee57895da": 15,
"6038d614d10cbf667352dd44": 1,
"6034d103ca006d2dca39b3f0": 1,
"656ddcf0f02d7bcea90bf395": 1,
@ -877,7 +878,6 @@
"5c0e805e86f774683f3dd637": 1,
"5ab8ebf186f7742d8b372e80": 1,
"639346cc1c8f182ad90c8972": 1,
"59e763f286f7742ee57895da": 1,
"5b44c6ae86f7742d1627baea": 1,
"5d5d940f86f7742797262046": 1,
"5df8a4d786f77412672a1e3b": 1,

View File

@ -798,6 +798,7 @@
"56e335e4d2720b6c058b456d": 20,
"5ca20d5986f774331e7c9602": 10,
"5e9dcf5986f7746c417435b3": 10,
"59e763f286f7742ee57895da": 15,
"6038d614d10cbf667352dd44": 1,
"6034d103ca006d2dca39b3f0": 1,
"656ddcf0f02d7bcea90bf395": 1,
@ -809,7 +810,6 @@
"5c0e805e86f774683f3dd637": 1,
"5ab8ebf186f7742d8b372e80": 1,
"639346cc1c8f182ad90c8972": 1,
"59e763f286f7742ee57895da": 1,
"5b44c6ae86f7742d1627baea": 1,
"5d5d940f86f7742797262046": 1,
"5df8a4d786f77412672a1e3b": 1,

View File

@ -784,6 +784,7 @@
"56e335e4d2720b6c058b456d": 20,
"5ca20d5986f774331e7c9602": 10,
"5e9dcf5986f7746c417435b3": 10,
"59e763f286f7742ee57895da": 15,
"6038d614d10cbf667352dd44": 1,
"6034d103ca006d2dca39b3f0": 1,
"656ddcf0f02d7bcea90bf395": 1,
@ -795,7 +796,6 @@
"5c0e805e86f774683f3dd637": 1,
"5ab8ebf186f7742d8b372e80": 1,
"639346cc1c8f182ad90c8972": 1,
"59e763f286f7742ee57895da": 1,
"5b44c6ae86f7742d1627baea": 1,
"5d5d940f86f7742797262046": 1,
"5df8a4d786f77412672a1e3b": 1,

View File

@ -764,6 +764,7 @@
"56e335e4d2720b6c058b456d": 20,
"5ca20d5986f774331e7c9602": 10,
"5e9dcf5986f7746c417435b3": 10,
"59e763f286f7742ee57895da": 15,
"6038d614d10cbf667352dd44": 1,
"6034d103ca006d2dca39b3f0": 1,
"656ddcf0f02d7bcea90bf395": 1,
@ -775,7 +776,6 @@
"5c0e805e86f774683f3dd637": 1,
"5ab8ebf186f7742d8b372e80": 1,
"639346cc1c8f182ad90c8972": 1,
"59e763f286f7742ee57895da": 1,
"5b44c6ae86f7742d1627baea": 1,
"5d5d940f86f7742797262046": 1,
"5df8a4d786f77412672a1e3b": 1,

View File

@ -1,12 +1,12 @@
[General]
gameName=spt
modid=0
version=d2025.1.6.0
version=d2025.1.3.0
newestVersion=
category="2,"
category="1,"
nexusFileStatus=1
installationFile=Tyfon-WeaponCustomizer-1.0.0.zip
repository=Nexus
installationFile=acidphantasm-progressivebotsystem.zip
repository=
ignoredVersion=
comments=
notes=
@ -15,7 +15,7 @@ url=
hasCustomURL=false
lastNexusQuery=
lastNexusUpdate=
nexusLastModified=2025-01-07T00:12:11Z
nexusLastModified=2024-12-16T07:04:24Z
nexusCategory=0
converted=false
validated=false

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 acidphantasm
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,47 @@
# Welcome to PBS (Progressive Bot System)
The goal of this mod is to provide a system that allows all bots to progress with the player.
In vanilla, scavs are a minor annoyance once you reach level 30+. This aims to change that, they may not always have the best ammo but they won't always be rocking crappy shotguns or low level weapons.
## General Notes
This mod has only been tested with SAIN, SWAG+Donuts, QuestingBots, and LootingBots.
This mod may have missing mods or templates for weapons. If you see errors or warning - REPORT THEM.
This mod may have issues that prevent the game from working - if this happens, REMOVE THE MOD and REPORT THEM.
Currently all bots that are due to spawn or have spawned are logged inside the \user\mods\acidphantasm-progressivebotsystem\logs\ folder. These logs are wiped when you restart the server. These may be needed to provide support, and are a nice thing to review if you happen to want to know everything that has or will spawn.
## Put this mod last in your load order. If you have issues and it isn't last, then move it last.
### Current Features
- All AI will level with you.
- All AI have a tiering system.
- All AI will use modded weapons that you have installed.
- USEC spawn with weapons that you would expect from non-Russian forces.
- BEAR spawn with weapons that you would expect from Russian forces.
- Scavs pull a weapon from the Tier they have spawned from (any weapon available in that tier from USEC or BEAR can be chosen.)
- Scavs pull from ammo pools that do not contains meta ammo. I felt this was too easy a source of ammunition. This is subject to change.
- Bosses pull weapons from their vanilla pools until a later version.
- Bosses & guards pull ammo from a Tier4 pool.
- Boss guards pull a Tier4 weapon from the combined pools of USEC & BEAR.
### Current Tiers
- Tier 1 = Lv1-10
- Level Variance +/- 5
- Tier 2 = Lv11-20
- Level Variance +/- 7
- Tier 3 = Lv21-30
- Level Variance +/- 10
- Tier 4 = Lv31-40
- Level Variance +/- 15
- Tier 5 = Lv41-50
- Level Variance +/- 15
- Tier 6 = Lv51-60
- Level Variance +/- 20
- Tier 7 = Lv61-78
- Level Variance +/- 30
## Put this mod last in your load order. If you have issues and it isn't last, then move it last.

View File

@ -0,0 +1,258 @@
{
// Enable/Disable using a preset
// Presets are to be built and shared among APBS users. If enabled, ensure that you set the "presetName" to the name of the folder of your preset
"usePreset": false,
"presetName": "example",
// If you enable either of these settings, support will not be granted.
// enableModdedWeapons - Any mods adding weapons loaded before APBS will have their weapons & attachments imported.
// enableModdedEquipment - Any mods adding equipment loaded before APBS will be imported with their attachments (if any).
// enableModdedClothing - Any mods adding clothing loaded before APBS will be imported.
// initialTierAppearance - Whatever number (1-7) you put here, will be the first tier that imported mod items will be added to.
// pmcWeaponWeights - Weight of modded weapons being added to PMCs
// scavWeaponWeights - Weight of modded weapons being added to Scavs
// followerWeaponWeights - Weight of modded weapons being added to boss followers (not Goons)
// enableSafeGuard - Enables preventing weapon importing from bastardizing vanilla weapons. If you disable this, you will get cursed vanilla weapons.
// Higher weights = more often. Lower weights = less often. If you add a LOT of mod weapons, I suggest using a lower value.
// REVIEW THE APBS LOGS TO TUNE YOUR CONFIG. (\user\mods\acidphantasm-progressivebotsystem\logs)
"enableModdedWeapons": true,
"enableModdedEquipment": true,
"enableModdedClothing": true,
"initalTierAppearance": 3,
"pmcWeaponWeights": 10,
"scavWeaponWeights": 1,
"followerWeaponWeights": 7,
"enableSafeGuard": true,
// Enable/Disable PMC Seasonal Clothing
// If true, PMCs will wear seasonal appropriate clothing to blend into the environment better. If disabled, clothing will be tiered by level instead.
// If true, modded clothing will not import, regardless of setting, to protect the appearance of appropriate clothing.
"seasonalPmcAppearance": true,
// Enable/Disable Realism Gas Mask Compatibility
// APBS automatically detects Realism and adds gas masks to bots due to Radiation Zones. If you dont want this to happen, set to true.
"disableRealismGasMasks": false,
// Looking for a challenge, or maybe just want to chill and wreck some bots?
// Enable "onlyChads" to force all bots to be Tier7, or enable "tarkovAndChill" to force all bots to be Tier1
// Enabling both will enable chaos mode, bots will pull gear and weapons from completely random Tiers during generation. It's chaos.
// Alternatively, enable "blickyMode" to give everyone a blicky. It's actually the real chill mode.
// Side note on "blickyMode" - it breaks some boss guards. Don't report it. It's a joke mode. It also won't do anything if either of the other two "modes" are enabled.
"onlyChads": false,
"tarkovAndChill": false,
"blickyMode": false,
// Enable/Disable specific bot generation
// If set to true, it will disable APBS generation for that bot type, if false - will use APBS generation.
"disableScavTierGeneration": false,
"disablePMCTierGeneration": false,
"disableBossTierGeneration": false,
"disableBossFollowerTierGeneration": false,
"disableRaiderRogueTierGeneration": false,
// Enable/Disable custom game version weights for AI PMCs
// If set to true, AI PMCs will roll their weights from the values below - if false will use SPT defaults.
// The values listed below ARE the SPT defaults (for reference)
"gameVersionWeight": false,
"standard": 2,
"left_behind": 1,
"prepare_for_escape": 1,
"edge_of_darkness": 4,
"unheard_edition": 2,
// Enable/Disable PMC ammo tier sliding
// If set to true, it will enabling a sliding system for PMC ammo pools. If you enable this, the below numbers are the recommended amounts. Tweak as you wish.
// Example: "pmcAmmoTierSlideAmount: 1 will allow a Tier5 PMC to "slide" down and pick from a Tier4 ammo pool, if it passes the roll for "slideChance".
"enablePMCAmmoTierSliding": false,
"slideAmount": 1,
"slideChance": 33,
// Enable/Disable using individual weapon type attachment chances.
// If set to true, will allow generation to use individual category based weapon attachment chances, if false - all weapons use the same attachment chance pool.
// For Preset Makers:
// If the below setting is false, "weaponMods" in the chances.json is the attachment chance rolls used.
// If the below setting is true, then you must also fill out each weapons category of chances.
"enablePerWeaponTypeAttachmentChances": true,
// Force weapon stocks
// If set to true, will enforce all AI weapons to have stocks, if false - will use APBS values
// "stockButtpadChance" will allow dynamic configuration of any butt pads spawning on a stock that can take them.
"forceStock": false,
"stockButtpadChance": 50,
// Force weapon dust covers
// If set to true, will enforce all AI weapons to have dust covers, if false - will use APBS values
"forceDustCover": false,
// Force weapon mod_scope slot
// If set to true, will enforce all AI weapons to have a mod in the mod_scope slot
// This slot is *MOSTLY* optics but it's sometimes a laser/flashlight depending on gun, if false - will use APBS values
"forceScopeSlot": false,
// Force weapon muzzles
// "forceMuzzle" If set to true, will enforce all AI PMC weapons to have muzzles based on the chance configured, if false - will use APBS values
// "muzzleChance" chance of muzzle being selected (overrides preset and database values) for each tier [ T1, T2, T3, T4, T5, T6, T7 ]
// "forceChildrenMuzzle" If set to true, enforces muzzle children to also spawn (so if it rolls to pick a threaded adapter, the child silencer will be forced to spawn), if false - will roll those slots independently
// "forceChildrenMuzzle" works regardless of you setting forceMuzzle or not - if you just want to see more children adapters spawn, just set this true
"forceMuzzle": false,
"muzzleChance": [ 10, 25, 40, 55, 65, 75, 75 ],
"forceChildrenMuzzle": false,
// Force weapon mod count limits
// If set to true, will enforce all AI weapons to be limited to the scopeLimit & tacticalLimit, if disabled the generation may go wild
"forceWeaponModLimits": true,
"scopeLimit": 2,
"tacticalLimit": 1,
// Enable/disable AI having T-7 thermal goggles
// If set to true, will allow AI to spawn with T-7 thermal goggles, if false they will not.
// "startTier" controls what tier the goggles will be available in. "5c110624d174af029e69734c"
"enableT7Thermals": false,
"startTier": 6,
// Enable/Disable PMC/scav Loot
// If set to true, will allow PMCs/scavs to have backpack/rig/pocket loot. If disabled, they will not.
// Add ItemIDs to the blacklist array to prevent them from spawning
// Blacklist example "pmcLootBlacklistItems": ["6711039f9e648049e50b3307", "5c0e531286f7747fa54205c2"]
"pmcLoot": false,
"pmcLootBlacklistItems": [ "6711039f9e648049e50b3307" ],
"scavLoot": true,
// Enable/Disabe Scav specific tiering options
// "enableScavAttachmentTiering" - If set to true, will allow scavs to get additional weapon/equipment attachments as they tier up. If disabled, they will always have tier 1 attachments.
// "enableScavEqualChanceEquipmentTiering" - If set to true, will allow scavs to have equal chances for any equipment in their pools. If disabled, they will use APBS defaults (low chances for good gear).
"enableScavAttachmentTiering": false,
"enableScavEqualEquipmentTiering": false,
// Enable/Disable adding keys to Scav Backpack loot
// Pick -ONE- option below and enable it if you would like to expand the backpack key pool for scavs.
// All keys include every key/keycard.
// Mechanical keys are keys that aren't keycards. <- Recommended, if you are going to enable something
// Keycards include ALL keycards.
"addAllKeysToScavs": false,
"addOnlyMechanicalKeysToScavs": false,
"addOnlyKeyCardsToScavs": false,
// Configure Weapon Durability per AI Bot Type
// Numbers are as follows: [ minDurability, maxDurability, minDelta, maxDelta ]
// Example: [ 50, 90, 0, 25 ]
// Ex ctd: Minimum possible "max" durability would be 50%, the highest possible "max" durability is 90%
// Ex ctd: Whatever value is picked between 50% & 90% will be the "max" durability of the weapon ("max" is the limit you can repair the weapon to)
// Ex ctd: After the max durability is selected, it will roll for the actual current durability which will be between 0-25% lower than the max.
// Ex ctd: Weapons are safeguarded to never fall below 40%.
"scavWeaponDurability": [ 50, 90, 0, 20 ],
"pmcWeaponDurability": [ 95, 100, 0, 5 ],
"bossWeaponDurability": [ 80, 100, 0, 20 ],
"guardWeaponDurability": [ 80, 100, 0, 20 ],
"raiderWeaponDurability": [ 80, 100, 0, 20 ],
// Enable/Disable custom plate chances
// If you REALLY don't like APBS plate chances then you can adjust it here.
// If set to true, will change all AI plate chances to the values you set below, if false - will use APBS values
// If set to true, Main Plates = front/back and Side Plates = left/right, if false - APBS uses individual plate chances for front/back and sides.
// Values are configured for each tier, example: [ Tier1, Tier2, Tier3, Tier4, Tier5, Tier6, Tier7 ]
"enableCustomPlateChances": false,
"scavMainPlateChance": [ 25, 25, 25, 25, 25, 25, 25 ],
"scavSidePlateChance": [ 25, 25, 25, 25, 25, 25, 25 ],
"pmcMainPlateChance": [ 65, 75, 90, 90, 95, 100, 100 ],
"pmcSidePlateChance": [ 15, 25, 50, 75, 90, 95, 100 ],
"bossMainPlateChance": [ 75, 75, 75, 75, 75, 75, 75 ],
"bossSidePlateChance": [ 50, 50, 50, 50, 50, 50, 50 ],
"guardMainPlateChance": [ 75, 75, 75, 75, 75, 75, 75 ],
"guardSidePlateChance": [ 75, 75, 75, 75, 75, 75, 75 ],
"raiderMainPlateChance": [ 75, 75, 75, 75, 75, 75, 75 ],
"raiderSidePlateChance": [ 75, 75, 75, 75, 75, 75, 75 ],
// Enable/Disable randomization of medical and food resource values
// If set to true, all scavs and PMCs will have randomized resource values, based on the chances you set below, for medical and food items.
// If disabled the items will always be full resource values.
// Explanation: "pmcMedRates": [ Chance for full resource value available, Minimum percent of item randomized between min and max resource ]
// Example.. "pmcMedRates": [ 65, 20 ] --- AFAK on a PMC has a 65% chance to be 400/400 and 35% chance to be between 0% and 80% used (it would spawn somewhere between 80/400 to 400/400).
"enableConsumableResourceRandomization": true,
"scavFoodRates": [ 25, 60 ],
"scavMedRates": [ 25, 60 ],
"pmcFoodRates": [ 65, 60 ],
"pmcMedRates": [ 65, 60 ],
// Blacklist specific ammo types from all AI -- USE "https://db.sp-tarkov.com/" to get the item _id
// Configure per tier blacklists
// Example.. this will blacklist 9x19 RIP and 5.45x39mm PP from all bots in Tier1
// tier1AmmoBlacklist: [ "5c0d56a986f774449d5de529", "56dff2ced2720bb4668b4567" ]
"tier1AmmoBlacklist": [],
"tier2AmmoBlacklist": [],
"tier3AmmoBlacklist": [],
"tier4AmmoBlacklist": [],
"tier5AmmoBlacklist": [],
"tier6AmmoBlacklist": [],
"tier7AmmoBlacklist": [],
// Blacklist specific equipment from all AI -- USE "https://db.sp-tarkov.com/" to get the item _id
// Configure per tier blacklists
// Example.. this will blacklist BlackRock chest rig and GSSh-01 headset from all bots in Tier1
// tier1EquipmentBlacklist: [ "5648a69d4bdc2ded0b8b457b", "5b432b965acfc47a8774094e" ]
"tier1EquipmentBlacklist": [],
"tier2EquipmentBlacklist": [],
"tier3EquipmentBlacklist": [],
"tier4EquipmentBlacklist": [],
"tier5EquipmentBlacklist": [],
"tier6EquipmentBlacklist": [],
"tier7EquipmentBlacklist": [],
// Blacklist specific weapons from all AI -- USE "https://db.sp-tarkov.com/" to get the item _id
// Configure per tier blacklists
// Example.. this will blacklist PKP and PKM from all bots in Tier1
// tier1EquipmentBlacklist: [ "64ca3d3954fc657e230529cc", "64637076203536ad5600c990" ]
"tier1WeaponBlacklist": [],
"tier2WeaponBlacklist": [],
"tier3WeaponBlacklist": [],
"tier4WeaponBlacklist": [],
"tier5WeaponBlacklist": [],
"tier6WeaponBlacklist": [],
"tier7WeaponBlacklist": [],
// Blacklist specific attachments from all AI -- USE "https://db.sp-tarkov.com/" to get the item _id
// Configure per tier blacklists - very useful setting for those that play with modded weapon/equipment importing
// Example.. this will blacklist "AK 7.62x39 aluminium 10-round magazine" and "Ops-Core SLAAP Armor Helmet Plate" from all bots in Tier1
// tier1EquipmentBlacklist: [ "5b1fd4e35acfc40018633c39", "5c0e66e2d174af02a96252f4" ]
"tier1AttachmentBlacklist": [],
"tier2AttachmentBlacklist": [],
"tier3AttachmentBlacklist": [],
"tier4AttachmentBlacklist": [],
"tier5AttachmentBlacklist": [],
"tier6AttachmentBlacklist": [],
"tier7AttachmentBlacklist": [],
// LevelDelta's are the lowest and highest levels that AI can spawn relative to the player's level.
// Examples:
// "tier1LevelDelta": [ 5, 5 ] --- While you are Tier1 (lv1-10), all AI will be leveled -5 to +5 of your level.
// "tier2LevelDelta": [ 10, 25 ] --- While you are Tier2 (lv11-20), all AI will be leveled -10 to +25 of your level.
// "enableCustomLevelDeltas" if true will use the values you set below, otherwise they will use APBS values
// THE BELOW VALUES BY DEFAULT ARE APBS DEFAULTS
// IF YOU WANT EVERY TIER AT EVERY LEVEL, SET ALL OF THESE TO: [ 79, 79 ]
"enableCustomLevelDeltas": false,
"tier1LevelDelta": [ 10, 5 ],
"tier2LevelDelta": [ 15, 5 ],
"tier3LevelDelta": [ 25, 7 ],
"tier4LevelDelta": [ 35, 10 ],
"tier5LevelDelta": [ 45, 15 ],
"tier6LevelDelta": [ 55, 20 ],
"tier7LevelDelta": [ 60, 20 ],
// LevelDelta's are the lowest and highest levels that AI can spawn relative to the player's level.
// Examples:
// "tier2ScavLevelDelta": [ 10, -10 ] --- While you are Tier2 (lv11-20), scavs will be leveled -10 to -10 of your level. (always 10 levels behind you)
// "tier3ScavLevelDelta": [ 30, -10 ] --- While you are Tier3 (lv21-30), scavs will be leveled -30 to -10 of your level. (always 10 to 30 levels behind you)
// "enableScavCustomLevelDeltas" if true will use the values you set below, otherwise they will use APBS values
// Default values below will always spawn scavs that are at least 1 tier below you unless you are Tier1.
"enableScavCustomLevelDeltas": false,
"tier1ScavLevelDelta": [ 10, 0 ],
"tier2ScavLevelDelta": [ 20, -10 ],
"tier3ScavLevelDelta": [ 30, -10 ],
"tier4ScavLevelDelta": [ 40, -10 ],
"tier5ScavLevelDelta": [ 50, -10 ],
"tier6ScavLevelDelta": [ 60, -10 ],
"tier7ScavLevelDelta": [ 70, -10 ],
// Enable/disable debug logging
"enableDebugLog": true
}

View File

@ -1,15 +1,14 @@
{
"name": "weapon-customizer",
"version": "1.0.0",
"main": "src/mod.js",
"license": "MIT",
"author": "Tyfon",
"name": "Acids Progressive Bot System",
"version": "1.3.1",
"sptVersion": "~3.10",
"loadBefore": [],
"loadAfter": [],
"loadAfter": [
"DanW-SPTQuestingBots"
],
"incompatibilities": [],
"contributors": [],
"isBundleMod": false,
"main": "src/mod.js",
"scripts": {
"setup": "npm i",
"build": "node ./build.mjs",
@ -21,13 +20,13 @@
"@typescript-eslint/parser": "7.2",
"archiver": "^6.0",
"eslint": "8.57",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"fs-extra": "11.2",
"ignore": "^5.2",
"os": "^0.1",
"tsyringe": "4.8.0",
"typescript": "5.4",
"winston": "3.12"
}
},
"author": "acidphantasm",
"contributors": [],
"license": "MIT"
}

View File

@ -0,0 +1,479 @@
{
"scavAmmo": {
"Caliber1143x23ACP": {
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 3
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 1
},
"Caliber12g": {
"5d6e6772a4b936088465b17c": 2,
"5d6e6806a4b936088465b17e": 2,
"5d6e67fba4b9361bc73bc779": 2,
"560d5e524bdc2d25448b4571": 2,
"5d6e6869a4b9361c140bcfde": 1,
"5d6e68b3a4b9361bca7e50b5": 1,
"58820d1224597753c90aeb13": 1,
"5d6e68dea4b9361bcc29e659": 1,
"5d6e6891a4b9361bd473feea": 1,
"5d6e68e6a4b9361c140bcfe0": 1,
"5d6e689ca4b9361bc8618956": 1
},
"Caliber20g": {
"5d6e695fa4b936359b35d852": 2,
"5d6e69b9a4b9361bc8618958": 2,
"5a38ebd9c4a282000d722a5b": 2,
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 1
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 3,
"5e85a9a6eacf8c039e4e2ac1": 1
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 3,
"59e6542b86f77411dc52a77a": 1
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 3,
"5ba26844d4351e00334c9475": 1
},
"Caliber545x39": {
"56dff216d2720bbd668b4568": 1,
"56dff338d2720bbd668b4569": 4,
"56dff421d2720b5f5a8b4567": 4,
"56dff4ecd2720b5f5a8b4568": 2,
"56dff4a2d2720bbd668b456a": 4,
"56dff0bed2720bb0668b4567": 3,
"56dff3afd2720bba668b4567": 1
},
"Caliber556x45NATO": {
"59e6927d86f77411da468256": 2,
"59e6918f86f7746c9f75e849": 2,
"59e68f6f86f7746c9f75e846": 4,
"59e6920f86f77411d82aa167": 5,
"54527a984bdc2d4e668b4567": 1
},
"Caliber57x28": {
"5cc86832d7f00c000d3a6e6c": 2,
"5cc80f79e4a949033c7343b2": 3,
"5cc86840d7f00c002412c56c": 3,
"5cc80f8fe4a949033b0224a2": 1,
"5cc80f53e4a949000e1ea4f8": 1
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 1
},
"Caliber762x25TT": {
"573602322459776445391df1": 2,
"573601b42459776410737435": 2,
"5735fdcd2459776445391d61": 1,
"5736026a245977644601dc61": 1
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 1,
"6196364158ef8c428c287d9f": 6,
"5fbe3ffdf8b6a877a729ea82": 3
},
"Caliber762x39": {
"59e4d3d286f774176a36250a": 2,
"64b7af734b75259c590fa895": 2,
"64b7af5a8532cf95ee0a0dbd": 6,
"59e4d24686f7741776641ac7": 4,
"59e4cf5286f7741778269d8a": 2,
"5656d7c34bdc2d9d198b4587": 1
},
"Caliber762x51": {
"5e023e88277cce2b522ff2b1": 2,
"5e023e6e34d52a55c3304f71": 2,
"5e023e53d4353e3302577c4c": 1
},
"Caliber762x54R": {
"64b8f7c241772715af0f9c3d": 2,
"64b8f7b5389d7ffd620ccba2": 2,
"64b8f7968532cf95ee0a0dbf": 2,
"5e023cf8186a883be655e54f": 2,
"5887431f2459777e1612938f": 1
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 2,
"5fc382c1016cce60e8341b20": 1
},
"Caliber9x18PM": {
"5737218f245977612125ba51": 5,
"57372140245977611f70ee91": 5,
"5737207f24597760ff7b25f2": 2,
"573719762459775a626ccbc1": 3,
"57371f8d24597761006c6a81": 3,
"57371f2b24597761224311f1": 5,
"57371eb62459776125652ac1": 1,
"57371b192459775a9f58a5e0": 1,
"57371e4124597760ff7b25f1": 1
},
"Caliber9x19PARA": {
"5efb0e16aeb21837e749c7ff": 1,
"58864a4f2459770fcc257101": 7,
"5a3c16fe86f77452b62de32a": 12,
"5c3df7d588a4501f290594e5": 6,
"64b7bbb74b75259c590fa897": 4,
"56d59d3ad2720bdb418b4577": 2
},
"Caliber9x21": {
"5a26ac06c4a282000c5a90a8": 5,
"5a26abfac4a28232980eabff": 3,
"5a269f97c4a282000b151807": 1
},
"Caliber9x33R": {
"62330c40bdd19b369e1e53d1": 5,
"62330bfadc5883093563729b": 3,
"62330c18744e5e31df12f516": 1
},
"Caliber9x39": {
"6576f96220d53a5b8f3e395e": 7,
"57a0dfb82459774d3078b56c": 5,
"5c0d668f86f7747ccb7f13b2": 1
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 10,
"66a0d1f88486c69fce00fdf6": 1
}
},
"pmcAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 1,
"5efb0fc6aeb21837e749c801": 8,
"5efb0d4f4bc50b58e81710f3": 40,
"5e81f423763d9f754677bf2e": 15
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 45
},
"Caliber12g": {
"5d6e6806a4b936088465b17e": 10,
"5c0d591486f7744c505b416f": 3,
"5d6e68d1a4b93622fe60e845": 3,
"5d6e6869a4b9361c140bcfde": 2,
"5d6e68b3a4b9361bca7e50b5": 4,
"58820d1224597753c90aeb13": 6,
"5d6e68dea4b9361bcc29e659": 8,
"5d6e6891a4b9361bd473feea": 12,
"5d6e68e6a4b9361c140bcfe0": 12,
"5d6e689ca4b9361bc8618956": 9
},
"Caliber20g": {
"5d6e695fa4b936359b35d852": 8,
"5d6e69b9a4b9361bc8618958": 8,
"5a38ebd9c4a282000d722a5b": 8,
"5d6e69c7a4b9360b6c0d54e4": 10,
"5d6e6a5fa4b93614ec501745": 3,
"5d6e6a53a4b9361bd473feec": 3
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 10,
"5e85a9a6eacf8c039e4e2ac1": 2
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 20,
"59e6542b86f77411dc52a77a": 25,
"59e655cb86f77411dc52a77b": 8
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 50,
"5ba26844d4351e00334c9475": 50
},
"Caliber545x39": {
"56dff216d2720bbd668b4568": 1,
"56dff338d2720bbd668b4569": 10,
"56dff421d2720b5f5a8b4567": 10,
"56dff4ecd2720b5f5a8b4568": 15,
"56dff4a2d2720bbd668b456a": 15,
"56dff0bed2720bb0668b4567": 35,
"56dff3afd2720bba668b4567": 45
},
"Caliber556x45NATO": {
"59e6927d86f77411da468256": 10,
"59e6918f86f7746c9f75e849": 20,
"59e68f6f86f7746c9f75e846": 45,
"59e6920f86f77411d82aa167": 50,
"54527a984bdc2d4e668b4567": 20
},
"Caliber57x28": {
"5cc86832d7f00c000d3a6e6c": 10,
"5cc80f79e4a949033c7343b2": 19,
"5cc86840d7f00c002412c56c": 24,
"5cc80f8fe4a949033b0224a2": 13,
"5cc80f53e4a949000e1ea4f8": 9
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 1
},
"Caliber762x25TT": {
"573602322459776445391df1": 6,
"573601b42459776410737435": 10,
"5735fdcd2459776445391d61": 18,
"5736026a245977644601dc61": 10,
"573603c924597764442bd9cb": 4,
"573603562459776430731618": 1
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 9,
"6196364158ef8c428c287d9f": 19,
"5fbe3ffdf8b6a877a729ea82": 14
},
"Caliber762x39": {
"59e4d3d286f774176a36250a": 3,
"64b7af734b75259c590fa895": 10,
"64b7af5a8532cf95ee0a0dbd": 20,
"59e4d24686f7741776641ac7": 25,
"59e4cf5286f7741778269d8a": 35,
"5656d7c34bdc2d9d198b4587": 15
},
"Caliber762x51": {
"5e023e88277cce2b522ff2b1": 10,
"5e023e6e34d52a55c3304f71": 40,
"5e023e53d4353e3302577c4c": 50
},
"Caliber762x54R": {
"64b8f7c241772715af0f9c3d": 9,
"64b8f7b5389d7ffd620ccba2": 14,
"64b8f7968532cf95ee0a0dbf": 16,
"5e023cf8186a883be655e54f": 20,
"5887431f2459777e1612938f": 14
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 95,
"5fc382c1016cce60e8341b20": 5
},
"Caliber9x18PM": {
"5737218f245977612125ba51": 2,
"57372140245977611f70ee91": 6,
"5737207f24597760ff7b25f2": 6,
"573719762459775a626ccbc1": 6,
"57371f8d24597761006c6a81": 9,
"57371f2b24597761224311f1": 9,
"57371eb62459776125652ac1": 9,
"57371b192459775a9f58a5e0": 18,
"57371e4124597760ff7b25f1": 23,
"5737201124597760fc4431f1": 18,
"573720e02459776143012541": 9,
"573718ba2459775a75491131": 6
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 1,
"5efb0e16aeb21837e749c7ff": 7,
"58864a4f2459770fcc257101": 20,
"5a3c16fe86f77452b62de32a": 30,
"5c3df7d588a4501f290594e5": 40,
"64b7bbb74b75259c590fa897": 40,
"56d59d3ad2720bdb418b4577": 25
},
"Caliber9x21": {
"5a26ac06c4a282000c5a90a8": 9,
"5a26abfac4a28232980eabff": 22,
"5a269f97c4a282000b151807": 17
},
"Caliber9x33R": {
"62330c40bdd19b369e1e53d1": 15,
"62330bfadc5883093563729b": 12
},
"Caliber9x39": {
"6576f96220d53a5b8f3e395e": 19,
"57a0dfb82459774d3078b56c": 27,
"5c0d668f86f7747ccb7f13b2": 13
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 50,
"66a0d1f88486c69fce00fdf6": 30
}
},
"bossAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 4,
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 10,
"5e81f423763d9f754677bf2e": 18,
"5efb0cabfb3e451d70735af5": 10
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 3,
"5cadf6ddae9215051e1c23b2": 12,
"5cadf6eeae921500134b2799": 8
},
"Caliber12g": {
"5d6e6806a4b936088465b17e": 7,
"64b8ee384b75259c590fa89b": 4,
"5d6e6911a4b9361bd5780d52": 3,
"5c0d591486f7744c505b416f": 5,
"5d6e6891a4b9361bd473feea": 2,
"5d6e68e6a4b9361c140bcfe0": 6,
"5d6e689ca4b9361bc8618956": 8,
"5d6e68c4a4b9361b93413f79": 8,
"5d6e68a8a4b9360b6c0d54e2": 3
},
"Caliber20g": {
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 4,
"5d6e6a05a4b93618084f58d0": 5,
"5d6e6a42a4b9364f07165f52": 5
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 2,
"5e85a9a6eacf8c039e4e2ac1": 4,
"5e85aa1a988a8701445df1f5": 4
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 1,
"59e6542b86f77411dc52a77a": 2,
"59e655cb86f77411dc52a77b": 10,
"5f0596629e22f464da6bbdd9": 8
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 2,
"5ba26844d4351e00334c9475": 4,
"5ba2678ad4351e44f824b344": 15,
"64b6979341772715af0f9c39": 15,
"5ba26835d4351e0035628ff5": 8
},
"Caliber545x39": {
"56dff3afd2720bba668b4567": 6,
"56dff2ced2720bb4668b4567": 12,
"56dff061d2720bb5668b4567": 20,
"61962b617c6c7b169525f168": 12,
"56dfef82d2720bbd668b4567": 9,
"56dff026d2720bb8668b4567": 8,
"5c0d5e4486f77478390952fe": 4
},
"Caliber556x45NATO": {
"5c0d5ae286f7741e46554302": 1,
"54527a984bdc2d4e668b4567": 7,
"60194943740c5d77f6705eea": 20,
"59e6906286f7746c9f75e847": 26,
"54527ac44bdc2d36668b4567": 30,
"59e690b686f7746c9f75e848": 7,
"601949593ae8f707c4608daa": 5
},
"Caliber57x28": {
"5cc80f8fe4a949033b0224a2": 5,
"5cc80f53e4a949000e1ea4f8": 21,
"5cc80f67e4a949035e43bbba": 15,
"5cc80f38e4a949001152b560": 12
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 10,
"6529243824cbe3c74a05e5c1": 5
},
"Caliber762x25TT": {
"5736026a245977644601dc61": 5,
"573603c924597764442bd9cb": 10,
"573603562459776430731618": 10
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 7,
"5fbe3ffdf8b6a877a729ea82": 6,
"619636be6db0f2477964e710": 23,
"64b8725c4b75259c590fa899": 20,
"5fd20ff893a8961fc660a954": 9
},
"Caliber762x39": {
"59e4cf5286f7741778269d8a": 4,
"5656d7c34bdc2d9d198b4587": 28,
"64b7af434b75259c590fa893": 33,
"59e0d99486f7744a32234762": 20,
"601aa3d2b2bcb34913271e6d": 12
},
"Caliber762x51": {
"5e023e53d4353e3302577c4c": 6,
"58dd3ad986f77403051cba8f": 27,
"5a608bf24f39f98ffc77720e": 19,
"5a6086ea4f39f99cd479502f": 9,
"5efb0c1bd79ff02a1f5e68d9": 2
},
"Caliber762x54R": {
"5e023cf8186a883be655e54f": 3,
"5887431f2459777e1612938f": 20,
"59e77a2386f7742ee578960a": 25,
"5e023d34e8a400319a28ed44": 22,
"560d61e84bdc2da74d8b4571": 15,
"5e023d48186a883be655e551": 10
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 5,
"5fc382c1016cce60e8341b20": 8,
"5fc275cf85fd526b824a571a": 8,
"5fc382a9d724d907e2077dab": 5
},
"Caliber9x18PM": {
"57371e4124597760ff7b25f1": 3,
"5737201124597760fc4431f1": 5,
"573720e02459776143012541": 12,
"573718ba2459775a75491131": 18,
"57371aab2459775a77142f22": 12,
"573719df2459775a626ccbc2": 10
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 9,
"5efb0e16aeb21837e749c7ff": 5,
"5a3c16fe86f77452b62de32a": 4,
"56d59d3ad2720bdb418b4577": 18,
"5c925fa22e221601da359b7b": 22,
"5efb0da7a29a85116f6ea05f": 9
},
"Caliber9x21": {
"5a269f97c4a282000b151807": 8,
"6576f93989f0062e741ba952": 18,
"5a26ac0ec4a28200741e1e18": 18,
"6576f4708ca9c4381d16cd9d": 8
},
"Caliber9x33R": {
"62330c18744e5e31df12f516": 9,
"62330b3ed4dc74626d570b95": 6
},
"Caliber9x39": {
"5c0d668f86f7747ccb7f13b2": 9,
"61962d879bb3d20b0946d385": 25,
"57a0e5022459774d1673f889": 25,
"5c0d688c86f77413ae3407b2": 12
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 3,
"66a0d1f88486c69fce00fdf6": 30,
"66a0d1e0ed648d72fe064d06": 25,
"668fe62ac62660a5d8071446": 12
}
}
}

View File

@ -0,0 +1,411 @@
{
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 5,
"66546f823b51a4d21e0d17d7": 1,
"5d1f56a686f7744bce0ee9eb": 2
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 5,
"5d1f58ed86f7744bcb0acd1c": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 5,
"66546f823b51a4d21e0d17d7": 1,
"5d1f565786f7743f8362bcd5": 2
},
"feet": {
"5cc085bb14c02e000e67a5c5": 5,
"5d1f58bd86f7744bce0ee9ef": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
},
"springEarly": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5d1f56ff86f7743f8362bcd7": 1,
"5d1f56a686f7744bce0ee9eb": 2,
"5e9da17386f774054b6f79a3": 2,
"5e4bb35286f77406a511c9bc": 2,
"5d1f56e486f7744bce0ee9ed": 2
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"66acc8f719271bd6d00dec0b": 1,
"6295e944e9de5e7b3751c4da": 1,
"5d1f592286f7743f8362bcdb": 1,
"5e4bb3b586f77406812bd579": 1,
"5d1f590486f7744bcd13459e": 3,
"5d1f58ed86f7744bcb0acd1c": 3
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"657058fddf9b3231400e9188": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5d1f567786f7744bcc04874f": 1,
"5e9d9fa986f774054d6b89f2": 1,
"5f5e401747344c2e4f6c42c5": 1,
"642e8ae07e17c882400c4f87": 2,
"5d1f568486f7744bca3f0b98": 2,
"66acec1dc94f4bf5bc063a16": 2,
"5e4bb31586f7740695730568": 2
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"66043cf87502eca33a08cad2": 1,
"5d1f58cb86f7744bca3f0b9a": 1,
"5d1f58a086f7743f8362bcd9": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"5f5e40400bc58666c37e7819": 1,
"66acebd4ede86671bb09584b": 3,
"5d1f58ab86f7743014162042": 3
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"spring": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"5df89f1f86f77412631087ea": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"summer": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"66acbe49dc61999a6a03d4d6": 1,
"64ef3efdb63b74469b6c1499": 1,
"642c18b8a6a0660b560fb31c": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f593286f7743014162044": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"64ef3efdb63b74469b6c1499": 1,
"5df89f1f86f77412631087ea": 1,
"5e9d9fa986f774054d6b89f2": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"autumn": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"637b945722e2a933ed0e33c8": 1,
"6571cb0923aa6d72760a7f8f": 1,
"6033a35f80ae5e2f970ba6bb": 1,
"5d1f56e486f7744bce0ee9ed": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"64ef3efdb63b74469b6c1499": 1,
"5d1f56ff86f7743f8362bcd7": 1
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"637ba17aa10a96c2b605dbc2": 1,
"6295e944e9de5e7b3751c4da": 1,
"5e4bb3b586f77406812bd579": 1,
"5f5e40a06760b4138443b341": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"6377266693a3b4967208e42b": 1,
"5d1f568486f7744bca3f0b98": 1,
"657058fddf9b3231400e9188": 1,
"642ed297ac11c9eaf10d87e8": 1,
"5d1f567786f7744bcc04874f": 1,
"64ef3efdb63b74469b6c1499": 1,
"6430119aac11c9eaf10d881b": 1,
"5f5e401747344c2e4f6c42c5": 1
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"642ed40af5bdf1c04e01952e": 1,
"6295e63de08ed747e64ae991": 1,
"5d1f58a086f7743f8362bcd9": 1,
"66043d7ac8949a435906e434": 1,
"5d1f58ab86f7743014162042": 1,
"5f5e40400bc58666c37e7819": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"winter": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56a686f7744bce0ee9eb": 1,
"5e9da17386f774054b6f79a3": 1,
"5e4bb35286f77406a511c9bc": 1,
"5d1f56e486f7744bce0ee9ed": 1
},
"feet": {
"5d1f590486f7744bcd13459e": 1,
"5d1f58ed86f7744bcb0acd1c": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"642e8ae07e17c882400c4f87": 1,
"5d1f568486f7744bca3f0b98": 1,
"66acec1dc94f4bf5bc063a16": 1,
"5e4bb31586f7740695730568": 1
},
"feet": {
"66acebd4ede86671bb09584b": 1,
"5d1f58ab86f7743014162042": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
}
}

View File

@ -0,0 +1,476 @@
{
"scavAmmo": {
"Caliber1143x23ACP": {
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 3
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 1
},
"Caliber12g": {
"5d6e6772a4b936088465b17c": 2,
"5d6e6806a4b936088465b17e": 2,
"5d6e67fba4b9361bc73bc779": 2,
"560d5e524bdc2d25448b4571": 2,
"5d6e6869a4b9361c140bcfde": 1,
"5d6e68b3a4b9361bca7e50b5": 1,
"58820d1224597753c90aeb13": 1,
"5d6e68dea4b9361bcc29e659": 1,
"5d6e6891a4b9361bd473feea": 1,
"5d6e68e6a4b9361c140bcfe0": 1,
"5d6e689ca4b9361bc8618956": 1
},
"Caliber20g": {
"5d6e695fa4b936359b35d852": 2,
"5d6e69b9a4b9361bc8618958": 2,
"5a38ebd9c4a282000d722a5b": 2,
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 1
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 3,
"5e85a9a6eacf8c039e4e2ac1": 1
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 3,
"59e6542b86f77411dc52a77a": 1
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 3,
"5ba26844d4351e00334c9475": 1
},
"Caliber545x39": {
"56dff216d2720bbd668b4568": 1,
"56dff338d2720bbd668b4569": 4,
"56dff421d2720b5f5a8b4567": 4,
"56dff4ecd2720b5f5a8b4568": 2,
"56dff4a2d2720bbd668b456a": 4,
"56dff0bed2720bb0668b4567": 3,
"56dff3afd2720bba668b4567": 1
},
"Caliber556x45NATO": {
"59e6927d86f77411da468256": 2,
"59e6918f86f7746c9f75e849": 2,
"59e68f6f86f7746c9f75e846": 4,
"59e6920f86f77411d82aa167": 5,
"54527a984bdc2d4e668b4567": 1
},
"Caliber57x28": {
"5cc86832d7f00c000d3a6e6c": 2,
"5cc80f79e4a949033c7343b2": 3,
"5cc86840d7f00c002412c56c": 3,
"5cc80f8fe4a949033b0224a2": 1,
"5cc80f53e4a949000e1ea4f8": 1
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 1
},
"Caliber762x25TT": {
"573602322459776445391df1": 2,
"573601b42459776410737435": 2,
"5735fdcd2459776445391d61": 1,
"5736026a245977644601dc61": 1
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 1,
"6196364158ef8c428c287d9f": 6,
"5fbe3ffdf8b6a877a729ea82": 3
},
"Caliber762x39": {
"59e4d3d286f774176a36250a": 2,
"64b7af734b75259c590fa895": 2,
"64b7af5a8532cf95ee0a0dbd": 6,
"59e4d24686f7741776641ac7": 4,
"59e4cf5286f7741778269d8a": 2,
"5656d7c34bdc2d9d198b4587": 1
},
"Caliber762x51": {
"5e023e88277cce2b522ff2b1": 2,
"5e023e6e34d52a55c3304f71": 2,
"5e023e53d4353e3302577c4c": 1
},
"Caliber762x54R": {
"64b8f7c241772715af0f9c3d": 2,
"64b8f7b5389d7ffd620ccba2": 2,
"64b8f7968532cf95ee0a0dbf": 2,
"5e023cf8186a883be655e54f": 2,
"5887431f2459777e1612938f": 1
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 2,
"5fc382c1016cce60e8341b20": 1
},
"Caliber9x18PM": {
"5737218f245977612125ba51": 5,
"57372140245977611f70ee91": 5,
"5737207f24597760ff7b25f2": 2,
"573719762459775a626ccbc1": 3,
"57371f8d24597761006c6a81": 3,
"57371f2b24597761224311f1": 5,
"57371eb62459776125652ac1": 1,
"57371b192459775a9f58a5e0": 1,
"57371e4124597760ff7b25f1": 1
},
"Caliber9x19PARA": {
"5efb0e16aeb21837e749c7ff": 1,
"58864a4f2459770fcc257101": 7,
"5a3c16fe86f77452b62de32a": 12,
"5c3df7d588a4501f290594e5": 6,
"64b7bbb74b75259c590fa897": 4,
"56d59d3ad2720bdb418b4577": 2
},
"Caliber9x21": {
"5a26ac06c4a282000c5a90a8": 5,
"5a26abfac4a28232980eabff": 3,
"5a269f97c4a282000b151807": 1
},
"Caliber9x33R": {
"62330c40bdd19b369e1e53d1": 5,
"62330bfadc5883093563729b": 3,
"62330c18744e5e31df12f516": 1
},
"Caliber9x39": {
"6576f96220d53a5b8f3e395e": 7,
"57a0dfb82459774d3078b56c": 5,
"5c0d668f86f7747ccb7f13b2": 1
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 10,
"66a0d1f88486c69fce00fdf6": 1
}
},
"pmcAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 1,
"5efb0fc6aeb21837e749c801": 8,
"5efb0d4f4bc50b58e81710f3": 40,
"5e81f423763d9f754677bf2e": 25
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 45
},
"Caliber12g": {
"5d6e6806a4b936088465b17e": 10,
"5c0d591486f7744c505b416f": 3,
"5d6e68d1a4b93622fe60e845": 3,
"5d6e6869a4b9361c140bcfde": 2,
"5d6e68b3a4b9361bca7e50b5": 2,
"58820d1224597753c90aeb13": 2,
"5d6e68dea4b9361bcc29e659": 2,
"5d6e6891a4b9361bd473feea": 9,
"5d6e68e6a4b9361c140bcfe0": 15,
"5d6e689ca4b9361bc8618956": 9
},
"Caliber20g": {
"5d6e695fa4b936359b35d852": 3,
"5d6e69b9a4b9361bc8618958": 3,
"5a38ebd9c4a282000d722a5b": 5,
"5d6e69c7a4b9360b6c0d54e4": 10,
"5d6e6a5fa4b93614ec501745": 3,
"5d6e6a53a4b9361bd473feec": 3
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 8,
"5e85a9a6eacf8c039e4e2ac1": 2
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 12,
"59e6542b86f77411dc52a77a": 35,
"59e655cb86f77411dc52a77b": 20
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 40,
"5ba26844d4351e00334c9475": 60
},
"Caliber545x39": {
"56dff338d2720bbd668b4569": 5,
"56dff4a2d2720bbd668b456a": 7,
"56dff0bed2720bb0668b4567": 10,
"56dff3afd2720bba668b4567": 60,
"56dff2ced2720bb4668b4567": 5,
"56dff061d2720bb5668b4567": 1
},
"Caliber556x45NATO": {
"59e6918f86f7746c9f75e849": 10,
"59e68f6f86f7746c9f75e846": 40,
"59e6920f86f77411d82aa167": 50,
"54527a984bdc2d4e668b4567": 30,
"60194943740c5d77f6705eea": 10,
"59e6906286f7746c9f75e847": 5
},
"Caliber57x28": {
"5cc86832d7f00c000d3a6e6c": 4,
"5cc80f79e4a949033c7343b2": 11,
"5cc86840d7f00c002412c56c": 21,
"5cc80f8fe4a949033b0224a2": 21,
"5cc80f53e4a949000e1ea4f8": 12,
"5cc80f67e4a949035e43bbba": 4
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 1
},
"Caliber762x25TT": {
"573601b42459776410737435": 8,
"5735fdcd2459776445391d61": 12,
"5736026a245977644601dc61": 18,
"573603c924597764442bd9cb": 13,
"573603562459776430731618": 3
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 9,
"6196364158ef8c428c287d9f": 18,
"5fbe3ffdf8b6a877a729ea82": 18
},
"Caliber762x39": {
"64b7af5a8532cf95ee0a0dbd": 5,
"59e4d24686f7741776641ac7": 15,
"59e4cf5286f7741778269d8a": 40,
"5656d7c34bdc2d9d198b4587": 45,
"64b7af434b75259c590fa893": 10
},
"Caliber762x51": {
"5e023e88277cce2b522ff2b1": 10,
"5e023e6e34d52a55c3304f71": 30,
"5e023e53d4353e3302577c4c": 50,
"58dd3ad986f77403051cba8f": 10
},
"Caliber762x54R": {
"64b8f7b5389d7ffd620ccba2": 5,
"64b8f7968532cf95ee0a0dbf": 9,
"5e023cf8186a883be655e54f": 16,
"5887431f2459777e1612938f": 22,
"59e77a2386f7742ee578960a": 10
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 90,
"5fc382c1016cce60e8341b20": 5,
"5fc275cf85fd526b824a571a": 5
},
"Caliber9x18PM": {
"57371f8d24597761006c6a81": 3,
"57371f2b24597761224311f1": 3,
"57371eb62459776125652ac1": 3,
"57371b192459775a9f58a5e0": 9,
"57371e4124597760ff7b25f1": 13,
"5737201124597760fc4431f1": 21,
"573720e02459776143012541": 14,
"573718ba2459775a75491131": 8
},
"Caliber9x19PARA": {
"5efb0e16aeb21837e749c7ff": 7,
"58864a4f2459770fcc257101": 1,
"5a3c16fe86f77452b62de32a": 15,
"5c3df7d588a4501f290594e5": 20,
"64b7bbb74b75259c590fa897": 30,
"56d59d3ad2720bdb418b4577": 55
},
"Caliber9x21": {
"5a26ac06c4a282000c5a90a8": 1,
"5a26abfac4a28232980eabff": 20,
"5a269f97c4a282000b151807": 27
},
"Caliber9x33R": {
"62330c40bdd19b369e1e53d1": 7,
"62330bfadc5883093563729b": 8,
"62330c18744e5e31df12f516": 4
},
"Caliber9x39": {
"6576f96220d53a5b8f3e395e": 10,
"57a0dfb82459774d3078b56c": 50,
"5c0d668f86f7747ccb7f13b2": 40
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 30,
"66a0d1f88486c69fce00fdf6": 50
}
},
"bossAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 4,
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 10,
"5e81f423763d9f754677bf2e": 18,
"5efb0cabfb3e451d70735af5": 10
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 3,
"5cadf6ddae9215051e1c23b2": 12,
"5cadf6eeae921500134b2799": 8
},
"Caliber12g": {
"5d6e6806a4b936088465b17e": 7,
"64b8ee384b75259c590fa89b": 4,
"5d6e6911a4b9361bd5780d52": 3,
"5c0d591486f7744c505b416f": 5,
"5d6e6891a4b9361bd473feea": 2,
"5d6e68e6a4b9361c140bcfe0": 6,
"5d6e689ca4b9361bc8618956": 8,
"5d6e68c4a4b9361b93413f79": 8,
"5d6e68a8a4b9360b6c0d54e2": 3
},
"Caliber20g": {
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 4,
"5d6e6a05a4b93618084f58d0": 5,
"5d6e6a42a4b9364f07165f52": 5
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 2,
"5e85a9a6eacf8c039e4e2ac1": 4,
"5e85aa1a988a8701445df1f5": 4
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 1,
"59e6542b86f77411dc52a77a": 2,
"59e655cb86f77411dc52a77b": 10,
"5f0596629e22f464da6bbdd9": 8
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 2,
"5ba26844d4351e00334c9475": 4,
"5ba2678ad4351e44f824b344": 15,
"64b6979341772715af0f9c39": 15,
"5ba26835d4351e0035628ff5": 8
},
"Caliber545x39": {
"56dff3afd2720bba668b4567": 6,
"56dff2ced2720bb4668b4567": 12,
"56dff061d2720bb5668b4567": 20,
"61962b617c6c7b169525f168": 12,
"56dfef82d2720bbd668b4567": 9,
"56dff026d2720bb8668b4567": 8,
"5c0d5e4486f77478390952fe": 4
},
"Caliber556x45NATO": {
"5c0d5ae286f7741e46554302": 1,
"54527a984bdc2d4e668b4567": 7,
"60194943740c5d77f6705eea": 20,
"59e6906286f7746c9f75e847": 26,
"54527ac44bdc2d36668b4567": 30,
"59e690b686f7746c9f75e848": 7,
"601949593ae8f707c4608daa": 5
},
"Caliber57x28": {
"5cc80f8fe4a949033b0224a2": 5,
"5cc80f53e4a949000e1ea4f8": 21,
"5cc80f67e4a949035e43bbba": 15,
"5cc80f38e4a949001152b560": 12
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 10,
"6529243824cbe3c74a05e5c1": 5
},
"Caliber762x25TT": {
"5736026a245977644601dc61": 5,
"573603c924597764442bd9cb": 10,
"573603562459776430731618": 10
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 7,
"5fbe3ffdf8b6a877a729ea82": 6,
"619636be6db0f2477964e710": 23,
"64b8725c4b75259c590fa899": 20,
"5fd20ff893a8961fc660a954": 9
},
"Caliber762x39": {
"59e4cf5286f7741778269d8a": 4,
"5656d7c34bdc2d9d198b4587": 28,
"64b7af434b75259c590fa893": 33,
"59e0d99486f7744a32234762": 20,
"601aa3d2b2bcb34913271e6d": 12
},
"Caliber762x51": {
"5e023e53d4353e3302577c4c": 6,
"58dd3ad986f77403051cba8f": 27,
"5a608bf24f39f98ffc77720e": 19,
"5a6086ea4f39f99cd479502f": 9,
"5efb0c1bd79ff02a1f5e68d9": 2
},
"Caliber762x54R": {
"5e023cf8186a883be655e54f": 3,
"5887431f2459777e1612938f": 20,
"59e77a2386f7742ee578960a": 25,
"5e023d34e8a400319a28ed44": 22,
"560d61e84bdc2da74d8b4571": 15,
"5e023d48186a883be655e551": 10
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 5,
"5fc382c1016cce60e8341b20": 8,
"5fc275cf85fd526b824a571a": 8,
"5fc382a9d724d907e2077dab": 5
},
"Caliber9x18PM": {
"57371e4124597760ff7b25f1": 3,
"5737201124597760fc4431f1": 5,
"573720e02459776143012541": 12,
"573718ba2459775a75491131": 18,
"57371aab2459775a77142f22": 12,
"573719df2459775a626ccbc2": 10
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 9,
"5efb0e16aeb21837e749c7ff": 5,
"5a3c16fe86f77452b62de32a": 4,
"56d59d3ad2720bdb418b4577": 18,
"5c925fa22e221601da359b7b": 22,
"5efb0da7a29a85116f6ea05f": 9
},
"Caliber9x21": {
"5a269f97c4a282000b151807": 8,
"6576f93989f0062e741ba952": 18,
"5a26ac0ec4a28200741e1e18": 18,
"6576f4708ca9c4381d16cd9d": 8
},
"Caliber9x33R": {
"62330c18744e5e31df12f516": 9,
"62330b3ed4dc74626d570b95": 6
},
"Caliber9x39": {
"5c0d668f86f7747ccb7f13b2": 9,
"61962d879bb3d20b0946d385": 25,
"57a0e5022459774d1673f889": 25,
"5c0d688c86f77413ae3407b2": 12
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 3,
"66a0d1f88486c69fce00fdf6": 30,
"66a0d1e0ed648d72fe064d06": 25,
"668fe62ac62660a5d8071446": 12
}
}
}

View File

@ -0,0 +1,430 @@
{
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 5,
"66546f823b51a4d21e0d17d7": 1,
"5d1f56a686f7744bce0ee9eb": 2,
"5d1f56c686f7744bcd13459c": 3,
"637b945722e2a933ed0e33c8": 3,
"6571cb0923aa6d72760a7f8f": 3,
"5fd3e9f71b735718c25cd9f8": 3,
"642d9bbf6c06444bf7033855": 3
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 5,
"5d1f58ed86f7744bcb0acd1c": 2,
"5d1f590486f7744bcd13459e": 3,
"642d4d8eb6b75d4c89077cf9": 3,
"6033a3fee29c9f6c9b14e74e": 3
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 5,
"66546f823b51a4d21e0d17d7": 1,
"5d1f565786f7743f8362bcd5": 2,
"5fce3e0cfe40296c1d5fd782": 3,
"6377266693a3b4967208e42b": 3,
"5d1f564b86f7744bcb0acd16": 3,
"6295e698e9de5e7b3751c47a": 3,
"642e8ae07e17c882400c4f87": 3,
"5d1f568486f7744bca3f0b98": 3
},
"feet": {
"5cc085bb14c02e000e67a5c5": 5,
"5d1f58bd86f7744bce0ee9ef": 2,
"6377315993a3b4967208e437": 3,
"5d1f588e86f7744bcc048753": 3,
"65707a89f5a6f1412f0c5f7b": 3,
"642ed40af5bdf1c04e01952e": 3,
"5fce3e965a9f8c40685693bc": 3
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
},
"springEarly": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5d1f56ff86f7743f8362bcd7": 1,
"5d1f56a686f7744bce0ee9eb": 2,
"5e9da17386f774054b6f79a3": 2,
"5e4bb35286f77406a511c9bc": 2,
"5d1f56e486f7744bce0ee9ed": 2
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"66acc8f719271bd6d00dec0b": 1,
"6295e944e9de5e7b3751c4da": 1,
"5d1f592286f7743f8362bcdb": 1,
"5e4bb3b586f77406812bd579": 1,
"5d1f590486f7744bcd13459e": 3,
"5d1f58ed86f7744bcb0acd1c": 3
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"657058fddf9b3231400e9188": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5d1f567786f7744bcc04874f": 1,
"5e9d9fa986f774054d6b89f2": 1,
"5f5e401747344c2e4f6c42c5": 1,
"642e8ae07e17c882400c4f87": 2,
"5d1f568486f7744bca3f0b98": 2,
"66acec1dc94f4bf5bc063a16": 2,
"5e4bb31586f7740695730568": 2
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"66043cf87502eca33a08cad2": 1,
"5d1f58cb86f7744bca3f0b9a": 1,
"5d1f58a086f7743f8362bcd9": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"5f5e40400bc58666c37e7819": 1,
"66acebd4ede86671bb09584b": 3,
"5d1f58ab86f7743014162042": 3
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"spring": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"5df89f1f86f77412631087ea": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"summer": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"66acbe49dc61999a6a03d4d6": 1,
"64ef3efdb63b74469b6c1499": 1,
"642c18b8a6a0660b560fb31c": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f593286f7743014162044": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"64ef3efdb63b74469b6c1499": 1,
"5df89f1f86f77412631087ea": 1,
"5e9d9fa986f774054d6b89f2": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"autumn": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"637b945722e2a933ed0e33c8": 1,
"6571cb0923aa6d72760a7f8f": 1,
"6033a35f80ae5e2f970ba6bb": 1,
"5d1f56e486f7744bce0ee9ed": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"64ef3efdb63b74469b6c1499": 1,
"5d1f56ff86f7743f8362bcd7": 1
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"637ba17aa10a96c2b605dbc2": 1,
"6295e944e9de5e7b3751c4da": 1,
"5e4bb3b586f77406812bd579": 1,
"5f5e40a06760b4138443b341": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"6377266693a3b4967208e42b": 1,
"5d1f568486f7744bca3f0b98": 1,
"657058fddf9b3231400e9188": 1,
"642ed297ac11c9eaf10d87e8": 1,
"5d1f567786f7744bcc04874f": 1,
"64ef3efdb63b74469b6c1499": 1,
"6430119aac11c9eaf10d881b": 1,
"5f5e401747344c2e4f6c42c5": 1
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"642ed40af5bdf1c04e01952e": 1,
"6295e63de08ed747e64ae991": 1,
"5d1f58a086f7743f8362bcd9": 1,
"66043d7ac8949a435906e434": 1,
"5d1f58ab86f7743014162042": 1,
"5f5e40400bc58666c37e7819": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"winter": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56a686f7744bce0ee9eb": 1,
"5e9da17386f774054b6f79a3": 1,
"5e4bb35286f77406a511c9bc": 1,
"5d1f56e486f7744bce0ee9ed": 1
},
"feet": {
"5d1f590486f7744bcd13459e": 1,
"5d1f58ed86f7744bcb0acd1c": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"642e8ae07e17c882400c4f87": 1,
"5d1f568486f7744bca3f0b98": 1,
"66acec1dc94f4bf5bc063a16": 1,
"5e4bb31586f7740695730568": 1
},
"feet": {
"66acebd4ede86671bb09584b": 1,
"5d1f58ab86f7743014162042": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
}
}

View File

@ -0,0 +1,464 @@
{
"scavAmmo": {
"Caliber1143x23ACP": {
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 3
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 1
},
"Caliber12g": {
"5d6e6772a4b936088465b17c": 2,
"5d6e6806a4b936088465b17e": 2,
"5d6e67fba4b9361bc73bc779": 2,
"560d5e524bdc2d25448b4571": 2,
"5d6e6869a4b9361c140bcfde": 1,
"5d6e68b3a4b9361bca7e50b5": 1,
"58820d1224597753c90aeb13": 1,
"5d6e68dea4b9361bcc29e659": 1,
"5d6e6891a4b9361bd473feea": 1,
"5d6e68e6a4b9361c140bcfe0": 1,
"5d6e689ca4b9361bc8618956": 1
},
"Caliber20g": {
"5d6e695fa4b936359b35d852": 2,
"5d6e69b9a4b9361bc8618958": 2,
"5a38ebd9c4a282000d722a5b": 2,
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 1
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 3,
"5e85a9a6eacf8c039e4e2ac1": 1
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 3,
"59e6542b86f77411dc52a77a": 1
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 3,
"5ba26844d4351e00334c9475": 1
},
"Caliber545x39": {
"56dff216d2720bbd668b4568": 1,
"56dff338d2720bbd668b4569": 4,
"56dff421d2720b5f5a8b4567": 4,
"56dff4ecd2720b5f5a8b4568": 2,
"56dff4a2d2720bbd668b456a": 4,
"56dff0bed2720bb0668b4567": 3,
"56dff3afd2720bba668b4567": 1
},
"Caliber556x45NATO": {
"59e6927d86f77411da468256": 2,
"59e6918f86f7746c9f75e849": 2,
"59e68f6f86f7746c9f75e846": 4,
"59e6920f86f77411d82aa167": 5,
"54527a984bdc2d4e668b4567": 1
},
"Caliber57x28": {
"5cc86832d7f00c000d3a6e6c": 2,
"5cc80f79e4a949033c7343b2": 3,
"5cc86840d7f00c002412c56c": 3,
"5cc80f8fe4a949033b0224a2": 1,
"5cc80f53e4a949000e1ea4f8": 1
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 1
},
"Caliber762x25TT": {
"573602322459776445391df1": 2,
"573601b42459776410737435": 2,
"5735fdcd2459776445391d61": 1,
"5736026a245977644601dc61": 1
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 1,
"6196364158ef8c428c287d9f": 6,
"5fbe3ffdf8b6a877a729ea82": 3
},
"Caliber762x39": {
"59e4d3d286f774176a36250a": 2,
"64b7af734b75259c590fa895": 2,
"64b7af5a8532cf95ee0a0dbd": 6,
"59e4d24686f7741776641ac7": 4,
"59e4cf5286f7741778269d8a": 2,
"5656d7c34bdc2d9d198b4587": 1
},
"Caliber762x51": {
"5e023e88277cce2b522ff2b1": 2,
"5e023e6e34d52a55c3304f71": 2,
"5e023e53d4353e3302577c4c": 1
},
"Caliber762x54R": {
"64b8f7c241772715af0f9c3d": 2,
"64b8f7b5389d7ffd620ccba2": 2,
"64b8f7968532cf95ee0a0dbf": 2,
"5e023cf8186a883be655e54f": 2,
"5887431f2459777e1612938f": 1
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 2,
"5fc382c1016cce60e8341b20": 1
},
"Caliber9x18PM": {
"5737218f245977612125ba51": 5,
"57372140245977611f70ee91": 5,
"5737207f24597760ff7b25f2": 2,
"573719762459775a626ccbc1": 3,
"57371f8d24597761006c6a81": 3,
"57371f2b24597761224311f1": 5,
"57371eb62459776125652ac1": 1,
"57371b192459775a9f58a5e0": 1,
"57371e4124597760ff7b25f1": 1
},
"Caliber9x19PARA": {
"5efb0e16aeb21837e749c7ff": 1,
"58864a4f2459770fcc257101": 7,
"5a3c16fe86f77452b62de32a": 12,
"5c3df7d588a4501f290594e5": 6,
"64b7bbb74b75259c590fa897": 4,
"56d59d3ad2720bdb418b4577": 2
},
"Caliber9x21": {
"5a26ac06c4a282000c5a90a8": 5,
"5a26abfac4a28232980eabff": 3,
"5a269f97c4a282000b151807": 1
},
"Caliber9x33R": {
"62330c40bdd19b369e1e53d1": 5,
"62330bfadc5883093563729b": 3,
"62330c18744e5e31df12f516": 1
},
"Caliber9x39": {
"6576f96220d53a5b8f3e395e": 7,
"57a0dfb82459774d3078b56c": 5,
"5c0d668f86f7747ccb7f13b2": 1
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 10,
"66a0d1f88486c69fce00fdf6": 1
}
},
"pmcAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 10,
"5efb0fc6aeb21837e749c801": 5,
"5efb0d4f4bc50b58e81710f3": 30,
"5e81f423763d9f754677bf2e": 50,
"5efb0cabfb3e451d70735af5": 10
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 80,
"5cadf6ddae9215051e1c23b2": 20
},
"Caliber12g": {
"5d6e6806a4b936088465b17e": 15,
"64b8ee384b75259c590fa89b": 6,
"5c0d591486f7744c505b416f": 5,
"5d6e68e6a4b9361c140bcfe0": 15,
"5d6e689ca4b9361bc8618956": 13,
"5d6e68c4a4b9361b93413f79": 9
},
"Caliber20g": {
"5d6e69c7a4b9360b6c0d54e4": 8,
"5d6e6a5fa4b93614ec501745": 6,
"5d6e6a53a4b9361bd473feec": 6,
"5d6e6a05a4b93618084f58d0": 3,
"5d6e6a42a4b9364f07165f52": 2
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 60,
"5e85a9a6eacf8c039e4e2ac1": 30,
"5e85aa1a988a8701445df1f5": 10
},
"Caliber366TKM": {
"59e6542b86f77411dc52a77a": 5,
"59e655cb86f77411dc52a77b": 65,
"5f0596629e22f464da6bbdd9": 30
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26844d4351e00334c9475": 70,
"64b6979341772715af0f9c39": 15,
"5ba2678ad4351e44f824b344": 10,
"5ba26835d4351e0035628ff5": 5
},
"Caliber545x39": {
"56dff0bed2720bb0668b4567": 5,
"56dff3afd2720bba668b4567": 40,
"56dff2ced2720bb4668b4567": 30,
"56dff061d2720bb5668b4567": 15,
"61962b617c6c7b169525f168": 5,
"56dfef82d2720bbd668b4567": 5
},
"Caliber556x45NATO": {
"5c0d5ae286f7741e46554302": 5,
"59e6920f86f77411d82aa167": 10,
"54527a984bdc2d4e668b4567": 50,
"60194943740c5d77f6705eea": 30,
"59e6906286f7746c9f75e847": 10,
"54527ac44bdc2d36668b4567": 5
},
"Caliber57x28": {
"5cc86840d7f00c002412c56c": 10,
"5cc80f8fe4a949033b0224a2": 15,
"5cc80f53e4a949000e1ea4f8": 28,
"5cc80f67e4a949035e43bbba": 7
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 1
},
"Caliber762x25TT": {
"5736026a245977644601dc61": 5,
"573603c924597764442bd9cb": 10,
"573603562459776430731618": 10
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 5,
"5fbe3ffdf8b6a877a729ea82": 55,
"619636be6db0f2477964e710": 30,
"64b8725c4b75259c590fa899": 10
},
"Caliber762x39": {
"5656d7c34bdc2d9d198b4587": 60,
"64b7af434b75259c590fa893": 35,
"59e0d99486f7744a32234762": 5
},
"Caliber762x51": {
"5e023e53d4353e3302577c4c": 60,
"58dd3ad986f77403051cba8f": 35,
"5a608bf24f39f98ffc77720e": 5
},
"Caliber762x54R": {
"5887431f2459777e1612938f": 50,
"59e77a2386f7742ee578960a": 25,
"5e023d34e8a400319a28ed44": 5
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 75,
"5fc382c1016cce60e8341b20": 20,
"5fc275cf85fd526b824a571a": 5
},
"Caliber9x18PM": {
"5737201124597760fc4431f1": 35,
"573720e02459776143012541": 25,
"573718ba2459775a75491131": 25,
"57371aab2459775a77142f22": 10
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 5,
"5efb0e16aeb21837e749c7ff": 25,
"56d59d3ad2720bdb418b4577": 65,
"5c925fa22e221601da359b7b": 5
},
"Caliber9x21": {
"5a26abfac4a28232980eabff": 12,
"5a269f97c4a282000b151807": 30,
"6576f93989f0062e741ba952": 12,
"5a26ac0ec4a28200741e1e18": 8
},
"Caliber9x33R": {
"62330bfadc5883093563729b": 8,
"62330c18744e5e31df12f516": 8,
"62330b3ed4dc74626d570b95": 2
},
"Caliber9x39": {
"57a0dfb82459774d3078b56c": 25,
"5c0d668f86f7747ccb7f13b2": 60,
"61962d879bb3d20b0946d385": 10,
"57a0e5022459774d1673f889": 5
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 30,
"66a0d1f88486c69fce00fdf6": 60,
"66a0d1e0ed648d72fe064d06": 10
}
},
"bossAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 4,
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 10,
"5e81f423763d9f754677bf2e": 18,
"5efb0cabfb3e451d70735af5": 10
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 3,
"5cadf6ddae9215051e1c23b2": 12,
"5cadf6eeae921500134b2799": 8
},
"Caliber12g": {
"5d6e6806a4b936088465b17e": 7,
"64b8ee384b75259c590fa89b": 4,
"5d6e6911a4b9361bd5780d52": 3,
"5c0d591486f7744c505b416f": 5,
"5d6e6891a4b9361bd473feea": 2,
"5d6e68e6a4b9361c140bcfe0": 6,
"5d6e689ca4b9361bc8618956": 8,
"5d6e68c4a4b9361b93413f79": 8,
"5d6e68a8a4b9360b6c0d54e2": 3
},
"Caliber20g": {
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 4,
"5d6e6a05a4b93618084f58d0": 5,
"5d6e6a42a4b9364f07165f52": 5
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 2,
"5e85a9a6eacf8c039e4e2ac1": 4,
"5e85aa1a988a8701445df1f5": 4
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 1,
"59e6542b86f77411dc52a77a": 2,
"59e655cb86f77411dc52a77b": 10,
"5f0596629e22f464da6bbdd9": 8
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 2,
"5ba26844d4351e00334c9475": 4,
"5ba2678ad4351e44f824b344": 15,
"64b6979341772715af0f9c39": 15,
"5ba26835d4351e0035628ff5": 8
},
"Caliber545x39": {
"56dff3afd2720bba668b4567": 6,
"56dff2ced2720bb4668b4567": 12,
"56dff061d2720bb5668b4567": 20,
"61962b617c6c7b169525f168": 12,
"56dfef82d2720bbd668b4567": 9,
"56dff026d2720bb8668b4567": 8,
"5c0d5e4486f77478390952fe": 4
},
"Caliber556x45NATO": {
"5c0d5ae286f7741e46554302": 1,
"54527a984bdc2d4e668b4567": 7,
"60194943740c5d77f6705eea": 20,
"59e6906286f7746c9f75e847": 26,
"54527ac44bdc2d36668b4567": 30,
"59e690b686f7746c9f75e848": 7,
"601949593ae8f707c4608daa": 5
},
"Caliber57x28": {
"5cc80f8fe4a949033b0224a2": 5,
"5cc80f53e4a949000e1ea4f8": 21,
"5cc80f67e4a949035e43bbba": 15,
"5cc80f38e4a949001152b560": 12
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 10,
"6529243824cbe3c74a05e5c1": 5
},
"Caliber762x25TT": {
"5736026a245977644601dc61": 5,
"573603c924597764442bd9cb": 10,
"573603562459776430731618": 10
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 7,
"5fbe3ffdf8b6a877a729ea82": 6,
"619636be6db0f2477964e710": 23,
"64b8725c4b75259c590fa899": 20,
"5fd20ff893a8961fc660a954": 9
},
"Caliber762x39": {
"59e4cf5286f7741778269d8a": 4,
"5656d7c34bdc2d9d198b4587": 28,
"64b7af434b75259c590fa893": 33,
"59e0d99486f7744a32234762": 20,
"601aa3d2b2bcb34913271e6d": 12
},
"Caliber762x51": {
"5e023e53d4353e3302577c4c": 6,
"58dd3ad986f77403051cba8f": 27,
"5a608bf24f39f98ffc77720e": 19,
"5a6086ea4f39f99cd479502f": 9,
"5efb0c1bd79ff02a1f5e68d9": 2
},
"Caliber762x54R": {
"5e023cf8186a883be655e54f": 3,
"5887431f2459777e1612938f": 20,
"59e77a2386f7742ee578960a": 25,
"5e023d34e8a400319a28ed44": 22,
"560d61e84bdc2da74d8b4571": 15,
"5e023d48186a883be655e551": 10
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 5,
"5fc382c1016cce60e8341b20": 8,
"5fc275cf85fd526b824a571a": 8,
"5fc382a9d724d907e2077dab": 5
},
"Caliber9x18PM": {
"57371e4124597760ff7b25f1": 3,
"5737201124597760fc4431f1": 5,
"573720e02459776143012541": 12,
"573718ba2459775a75491131": 18,
"57371aab2459775a77142f22": 12,
"573719df2459775a626ccbc2": 10
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 9,
"5efb0e16aeb21837e749c7ff": 5,
"5a3c16fe86f77452b62de32a": 4,
"56d59d3ad2720bdb418b4577": 18,
"5c925fa22e221601da359b7b": 22,
"5efb0da7a29a85116f6ea05f": 9
},
"Caliber9x21": {
"5a269f97c4a282000b151807": 8,
"6576f93989f0062e741ba952": 18,
"5a26ac0ec4a28200741e1e18": 18,
"6576f4708ca9c4381d16cd9d": 8
},
"Caliber9x33R": {
"62330c18744e5e31df12f516": 9,
"62330b3ed4dc74626d570b95": 6
},
"Caliber9x39": {
"5c0d668f86f7747ccb7f13b2": 9,
"61962d879bb3d20b0946d385": 25,
"57a0e5022459774d1673f889": 25,
"5c0d688c86f77413ae3407b2": 12
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 3,
"66a0d1f88486c69fce00fdf6": 30,
"66a0d1e0ed648d72fe064d06": 25,
"668fe62ac62660a5d8071446": 12
}
}
}

View File

@ -0,0 +1,457 @@
{
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"66546f823b51a4d21e0d17d7": 1,
"5d1f56a686f7744bce0ee9eb": 1,
"5d1f56c686f7744bcd13459c": 3,
"637b945722e2a933ed0e33c8": 3,
"6571cb0923aa6d72760a7f8f": 3,
"5fd3e9f71b735718c25cd9f8": 3,
"642d9bbf6c06444bf7033855": 3,
"6033a35f80ae5e2f970ba6bb": 5,
"66043728333907134309d647": 5,
"5d1f56e486f7744bce0ee9ed": 5,
"6295e8c3e08ed747e64aea00": 5,
"642c18b8a6a0660b560fb31c": 5,
"66acbe49dc61999a6a03d4d6": 5
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"5d1f58ed86f7744bcb0acd1c": 1,
"5d1f590486f7744bcd13459e": 3,
"642d4d8eb6b75d4c89077cf9": 3,
"6033a3fee29c9f6c9b14e74e": 3,
"5fcf940bce1ba36a513bb9cc": 5,
"660436487502eca33a08cac8": 5,
"6571cad4c8673f00290f5657": 5,
"637ba17aa10a96c2b605dbc2": 5,
"5d1f591186f7744bcc048755": 5,
"6295e944e9de5e7b3751c4da": 5,
"642c19360a69698d1b049e12": 5,
"66acc8f719271bd6d00dec0b": 5
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"66546f823b51a4d21e0d17d7": 1,
"5d1f565786f7743f8362bcd5": 1,
"5fce3e0cfe40296c1d5fd782": 3,
"6377266693a3b4967208e42b": 3,
"5d1f564b86f7744bcb0acd16": 3,
"6295e698e9de5e7b3751c47a": 3,
"642e8ae07e17c882400c4f87": 3,
"5d1f568486f7744bca3f0b98": 3,
"657058fddf9b3231400e9188": 5,
"6033a31e9ec839204e6a2f3e": 5,
"66043cc27502eca33a08cad0": 5,
"5fce3e47fe40296c1d5fd784": 5,
"642ed297ac11c9eaf10d87e8": 5,
"66acec1dc94f4bf5bc063a16": 5
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 3,
"5d1f588e86f7744bcc048753": 3,
"65707a89f5a6f1412f0c5f7b": 3,
"642ed40af5bdf1c04e01952e": 3,
"5fce3e965a9f8c40685693bc": 3,
"6295e63de08ed747e64ae991": 5,
"66043cf87502eca33a08cad2": 5,
"6033a3d8ed2e0509b15f9031": 5,
"5d1f58cb86f7744bca3f0b9a": 5,
"5d1f58a086f7743f8362bcd9": 5,
"642e71620a69698d1b049f0a": 5,
"66acebd4ede86671bb09584b": 5
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
},
"springEarly": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5d1f56ff86f7743f8362bcd7": 1,
"5d1f56a686f7744bce0ee9eb": 2,
"5e9da17386f774054b6f79a3": 2,
"5e4bb35286f77406a511c9bc": 2,
"5d1f56e486f7744bce0ee9ed": 2
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"66acc8f719271bd6d00dec0b": 1,
"6295e944e9de5e7b3751c4da": 1,
"5d1f592286f7743f8362bcdb": 1,
"5e4bb3b586f77406812bd579": 1,
"5d1f590486f7744bcd13459e": 3,
"5d1f58ed86f7744bcb0acd1c": 3
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"657058fddf9b3231400e9188": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5d1f567786f7744bcc04874f": 1,
"5e9d9fa986f774054d6b89f2": 1,
"5f5e401747344c2e4f6c42c5": 1,
"642e8ae07e17c882400c4f87": 2,
"5d1f568486f7744bca3f0b98": 2,
"66acec1dc94f4bf5bc063a16": 2,
"5e4bb31586f7740695730568": 2
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"66043cf87502eca33a08cad2": 1,
"5d1f58cb86f7744bca3f0b9a": 1,
"5d1f58a086f7743f8362bcd9": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"5f5e40400bc58666c37e7819": 1,
"66acebd4ede86671bb09584b": 3,
"5d1f58ab86f7743014162042": 3
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"spring": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"5df89f1f86f77412631087ea": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"summer": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"66acbe49dc61999a6a03d4d6": 1,
"64ef3efdb63b74469b6c1499": 1,
"642c18b8a6a0660b560fb31c": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f593286f7743014162044": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"64ef3efdb63b74469b6c1499": 1,
"5df89f1f86f77412631087ea": 1,
"5e9d9fa986f774054d6b89f2": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"autumn": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"637b945722e2a933ed0e33c8": 1,
"6571cb0923aa6d72760a7f8f": 1,
"6033a35f80ae5e2f970ba6bb": 1,
"5d1f56e486f7744bce0ee9ed": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"64ef3efdb63b74469b6c1499": 1,
"5d1f56ff86f7743f8362bcd7": 1
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"637ba17aa10a96c2b605dbc2": 1,
"6295e944e9de5e7b3751c4da": 1,
"5e4bb3b586f77406812bd579": 1,
"5f5e40a06760b4138443b341": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"6377266693a3b4967208e42b": 1,
"5d1f568486f7744bca3f0b98": 1,
"657058fddf9b3231400e9188": 1,
"642ed297ac11c9eaf10d87e8": 1,
"5d1f567786f7744bcc04874f": 1,
"64ef3efdb63b74469b6c1499": 1,
"6430119aac11c9eaf10d881b": 1,
"5f5e401747344c2e4f6c42c5": 1
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"642ed40af5bdf1c04e01952e": 1,
"6295e63de08ed747e64ae991": 1,
"5d1f58a086f7743f8362bcd9": 1,
"66043d7ac8949a435906e434": 1,
"5d1f58ab86f7743014162042": 1,
"5f5e40400bc58666c37e7819": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"winter": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56a686f7744bce0ee9eb": 1,
"5e9da17386f774054b6f79a3": 1,
"5e4bb35286f77406a511c9bc": 1,
"5d1f56e486f7744bce0ee9ed": 1
},
"feet": {
"5d1f590486f7744bcd13459e": 1,
"5d1f58ed86f7744bcb0acd1c": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"642e8ae07e17c882400c4f87": 1,
"5d1f568486f7744bca3f0b98": 1,
"66acec1dc94f4bf5bc063a16": 1,
"5e4bb31586f7740695730568": 1
},
"feet": {
"66acebd4ede86671bb09584b": 1,
"5d1f58ab86f7743014162042": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
}
}

View File

@ -0,0 +1,471 @@
{
"scavAmmo": {
"Caliber1143x23ACP": {
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 3
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 1
},
"Caliber12g": {
"5d6e6772a4b936088465b17c": 2,
"5d6e6806a4b936088465b17e": 2,
"5d6e67fba4b9361bc73bc779": 2,
"560d5e524bdc2d25448b4571": 2,
"5d6e6869a4b9361c140bcfde": 1,
"5d6e68b3a4b9361bca7e50b5": 1,
"58820d1224597753c90aeb13": 1,
"5d6e68dea4b9361bcc29e659": 1,
"5d6e6891a4b9361bd473feea": 1,
"5d6e68e6a4b9361c140bcfe0": 1,
"5d6e689ca4b9361bc8618956": 1
},
"Caliber20g": {
"5d6e695fa4b936359b35d852": 2,
"5d6e69b9a4b9361bc8618958": 2,
"5a38ebd9c4a282000d722a5b": 2,
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 1
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 3,
"5e85a9a6eacf8c039e4e2ac1": 1
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 3,
"59e6542b86f77411dc52a77a": 1
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 3,
"5ba26844d4351e00334c9475": 1
},
"Caliber545x39": {
"56dff216d2720bbd668b4568": 1,
"56dff338d2720bbd668b4569": 4,
"56dff421d2720b5f5a8b4567": 4,
"56dff4ecd2720b5f5a8b4568": 2,
"56dff4a2d2720bbd668b456a": 4,
"56dff0bed2720bb0668b4567": 3,
"56dff3afd2720bba668b4567": 1
},
"Caliber556x45NATO": {
"59e6927d86f77411da468256": 2,
"59e6918f86f7746c9f75e849": 2,
"59e68f6f86f7746c9f75e846": 4,
"59e6920f86f77411d82aa167": 5,
"54527a984bdc2d4e668b4567": 1
},
"Caliber57x28": {
"5cc86832d7f00c000d3a6e6c": 2,
"5cc80f79e4a949033c7343b2": 3,
"5cc86840d7f00c002412c56c": 3,
"5cc80f8fe4a949033b0224a2": 1,
"5cc80f53e4a949000e1ea4f8": 1
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 1
},
"Caliber762x25TT": {
"573602322459776445391df1": 2,
"573601b42459776410737435": 2,
"5735fdcd2459776445391d61": 1,
"5736026a245977644601dc61": 1
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 1,
"6196364158ef8c428c287d9f": 6,
"5fbe3ffdf8b6a877a729ea82": 3
},
"Caliber762x39": {
"59e4d3d286f774176a36250a": 2,
"64b7af734b75259c590fa895": 2,
"64b7af5a8532cf95ee0a0dbd": 6,
"59e4d24686f7741776641ac7": 4,
"59e4cf5286f7741778269d8a": 2,
"5656d7c34bdc2d9d198b4587": 1
},
"Caliber762x51": {
"5e023e88277cce2b522ff2b1": 2,
"5e023e6e34d52a55c3304f71": 2,
"5e023e53d4353e3302577c4c": 1
},
"Caliber762x54R": {
"64b8f7c241772715af0f9c3d": 2,
"64b8f7b5389d7ffd620ccba2": 2,
"64b8f7968532cf95ee0a0dbf": 2,
"5e023cf8186a883be655e54f": 2,
"5887431f2459777e1612938f": 1
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 2,
"5fc382c1016cce60e8341b20": 1
},
"Caliber9x18PM": {
"5737218f245977612125ba51": 5,
"57372140245977611f70ee91": 5,
"5737207f24597760ff7b25f2": 2,
"573719762459775a626ccbc1": 3,
"57371f8d24597761006c6a81": 3,
"57371f2b24597761224311f1": 5,
"57371eb62459776125652ac1": 1,
"57371b192459775a9f58a5e0": 1,
"57371e4124597760ff7b25f1": 1
},
"Caliber9x19PARA": {
"5efb0e16aeb21837e749c7ff": 1,
"58864a4f2459770fcc257101": 7,
"5a3c16fe86f77452b62de32a": 12,
"5c3df7d588a4501f290594e5": 6,
"64b7bbb74b75259c590fa897": 4,
"56d59d3ad2720bdb418b4577": 2
},
"Caliber9x21": {
"5a26ac06c4a282000c5a90a8": 5,
"5a26abfac4a28232980eabff": 3,
"5a269f97c4a282000b151807": 1
},
"Caliber9x33R": {
"62330c40bdd19b369e1e53d1": 5,
"62330bfadc5883093563729b": 3,
"62330c18744e5e31df12f516": 1
},
"Caliber9x39": {
"6576f96220d53a5b8f3e395e": 7,
"57a0dfb82459774d3078b56c": 5,
"5c0d668f86f7747ccb7f13b2": 1
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 10,
"66a0d1f88486c69fce00fdf6": 1
}
},
"pmcAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 20,
"5efb0d4f4bc50b58e81710f3": 10,
"5e81f423763d9f754677bf2e": 30,
"5efb0cabfb3e451d70735af5": 20
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 15,
"5cadf6ddae9215051e1c23b2": 50,
"5cadf6eeae921500134b2799": 35
},
"Caliber12g": {
"5d6e6806a4b936088465b17e": 10,
"64b8ee384b75259c590fa89b": 20,
"5d6e6911a4b9361bd5780d52": 20,
"5c0d591486f7744c505b416f": 5,
"5d6e68e6a4b9361c140bcfe0": 5,
"5d6e689ca4b9361bc8618956": 5,
"5d6e68c4a4b9361b93413f79": 35,
"5d6e68a8a4b9360b6c0d54e2": 15
},
"Caliber20g": {
"5d6e6a5fa4b93614ec501745": 15,
"5d6e6a53a4b9361bd473feec": 15,
"5d6e6a05a4b93618084f58d0": 35,
"5d6e6a42a4b9364f07165f52": 35
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 40,
"5e85a9a6eacf8c039e4e2ac1": 35,
"5e85aa1a988a8701445df1f5": 25
},
"Caliber366TKM": {
"59e655cb86f77411dc52a77b": 40,
"5f0596629e22f464da6bbdd9": 60
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26844d4351e00334c9475": 40,
"64b6979341772715af0f9c39": 30,
"5ba2678ad4351e44f824b344": 20,
"5ba26835d4351e0035628ff5": 10
},
"Caliber545x39": {
"56dff2ced2720bb4668b4567": 30,
"56dff061d2720bb5668b4567": 50,
"61962b617c6c7b169525f168": 10,
"56dfef82d2720bbd668b4567": 10,
"56dff026d2720bb8668b4567": 5,
"5c0d5e4486f77478390952fe": 5
},
"Caliber556x45NATO": {
"5c0d5ae286f7741e46554302": 10,
"60194943740c5d77f6705eea": 25,
"59e6906286f7746c9f75e847": 25,
"54527ac44bdc2d36668b4567": 30,
"59e690b686f7746c9f75e848": 5,
"601949593ae8f707c4608daa": 5
},
"Caliber57x28": {
"5cc80f53e4a949000e1ea4f8": 20,
"5cc80f67e4a949035e43bbba": 40,
"5cc80f38e4a949001152b560": 30
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 80,
"6529243824cbe3c74a05e5c1": 20
},
"Caliber762x25TT": {
"573603c924597764442bd9cb": 10,
"573603562459776430731618": 10
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 5,
"5fbe3ffdf8b6a877a729ea82": 40,
"619636be6db0f2477964e710": 40,
"64b8725c4b75259c590fa899": 10,
"5fd20ff893a8961fc660a954": 5
},
"Caliber762x39": {
"5656d7c34bdc2d9d198b4587": 25,
"64b7af434b75259c590fa893": 50,
"59e0d99486f7744a32234762": 20,
"601aa3d2b2bcb34913271e6d": 5
},
"Caliber762x51": {
"5e023e53d4353e3302577c4c": 20,
"58dd3ad986f77403051cba8f": 45,
"5a608bf24f39f98ffc77720e": 20,
"5a6086ea4f39f99cd479502f": 10,
"5efb0c1bd79ff02a1f5e68d9": 5
},
"Caliber762x54R": {
"5887431f2459777e1612938f": 30,
"59e77a2386f7742ee578960a": 45,
"5e023d34e8a400319a28ed44": 20,
"560d61e84bdc2da74d8b4571": 5
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 20,
"5fc382c1016cce60e8341b20": 40,
"5fc275cf85fd526b824a571a": 25,
"5fc382a9d724d907e2077dab": 5
},
"Caliber9x18PM": {
"5737201124597760fc4431f1": 15,
"573720e02459776143012541": 20,
"573718ba2459775a75491131": 30,
"57371aab2459775a77142f22": 20,
"573719df2459775a626ccbc2": 15
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 10,
"5efb0e16aeb21837e749c7ff": 15,
"56d59d3ad2720bdb418b4577": 50,
"5c925fa22e221601da359b7b": 20,
"5efb0da7a29a85116f6ea05f": 5
},
"Caliber9x21": {
"5a269f97c4a282000b151807": 25,
"6576f93989f0062e741ba952": 25,
"5a26ac0ec4a28200741e1e18": 12,
"6576f4708ca9c4381d16cd9d": 8
},
"Caliber9x33R": {
"62330c18744e5e31df12f516": 9,
"62330b3ed4dc74626d570b95": 6
},
"Caliber9x39": {
"5c0d668f86f7747ccb7f13b2": 20,
"61962d879bb3d20b0946d385": 50,
"57a0e5022459774d1673f889": 25,
"5c0d688c86f77413ae3407b2": 5
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 5,
"66a0d1f88486c69fce00fdf6": 60,
"66a0d1e0ed648d72fe064d06": 30,
"668fe62ac62660a5d8071446": 5
}
},
"bossAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 4,
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 10,
"5e81f423763d9f754677bf2e": 18,
"5efb0cabfb3e451d70735af5": 10
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 3,
"5cadf6ddae9215051e1c23b2": 12,
"5cadf6eeae921500134b2799": 8
},
"Caliber12g": {
"5d6e6806a4b936088465b17e": 7,
"64b8ee384b75259c590fa89b": 4,
"5d6e6911a4b9361bd5780d52": 3,
"5c0d591486f7744c505b416f": 5,
"5d6e6891a4b9361bd473feea": 2,
"5d6e68e6a4b9361c140bcfe0": 6,
"5d6e689ca4b9361bc8618956": 8,
"5d6e68c4a4b9361b93413f79": 8,
"5d6e68a8a4b9360b6c0d54e2": 3
},
"Caliber20g": {
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 4,
"5d6e6a05a4b93618084f58d0": 5,
"5d6e6a42a4b9364f07165f52": 5
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 2,
"5e85a9a6eacf8c039e4e2ac1": 4,
"5e85aa1a988a8701445df1f5": 4
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 1,
"59e6542b86f77411dc52a77a": 2,
"59e655cb86f77411dc52a77b": 10,
"5f0596629e22f464da6bbdd9": 8
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 2,
"5ba26844d4351e00334c9475": 4,
"5ba2678ad4351e44f824b344": 15,
"64b6979341772715af0f9c39": 15,
"5ba26835d4351e0035628ff5": 8
},
"Caliber545x39": {
"56dff3afd2720bba668b4567": 6,
"56dff2ced2720bb4668b4567": 12,
"56dff061d2720bb5668b4567": 20,
"61962b617c6c7b169525f168": 12,
"56dfef82d2720bbd668b4567": 9,
"56dff026d2720bb8668b4567": 8,
"5c0d5e4486f77478390952fe": 4
},
"Caliber556x45NATO": {
"5c0d5ae286f7741e46554302": 1,
"54527a984bdc2d4e668b4567": 7,
"60194943740c5d77f6705eea": 20,
"59e6906286f7746c9f75e847": 26,
"54527ac44bdc2d36668b4567": 30,
"59e690b686f7746c9f75e848": 7,
"601949593ae8f707c4608daa": 5
},
"Caliber57x28": {
"5cc80f8fe4a949033b0224a2": 5,
"5cc80f53e4a949000e1ea4f8": 21,
"5cc80f67e4a949035e43bbba": 15,
"5cc80f38e4a949001152b560": 12
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 10,
"6529243824cbe3c74a05e5c1": 5
},
"Caliber762x25TT": {
"5736026a245977644601dc61": 5,
"573603c924597764442bd9cb": 10,
"573603562459776430731618": 10
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 7,
"5fbe3ffdf8b6a877a729ea82": 6,
"619636be6db0f2477964e710": 23,
"64b8725c4b75259c590fa899": 20,
"5fd20ff893a8961fc660a954": 9
},
"Caliber762x39": {
"59e4cf5286f7741778269d8a": 4,
"5656d7c34bdc2d9d198b4587": 28,
"64b7af434b75259c590fa893": 33,
"59e0d99486f7744a32234762": 20,
"601aa3d2b2bcb34913271e6d": 12
},
"Caliber762x51": {
"5e023e53d4353e3302577c4c": 6,
"58dd3ad986f77403051cba8f": 27,
"5a608bf24f39f98ffc77720e": 19,
"5a6086ea4f39f99cd479502f": 9,
"5efb0c1bd79ff02a1f5e68d9": 2
},
"Caliber762x54R": {
"5e023cf8186a883be655e54f": 3,
"5887431f2459777e1612938f": 20,
"59e77a2386f7742ee578960a": 25,
"5e023d34e8a400319a28ed44": 22,
"560d61e84bdc2da74d8b4571": 15,
"5e023d48186a883be655e551": 10
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 5,
"5fc382c1016cce60e8341b20": 8,
"5fc275cf85fd526b824a571a": 8,
"5fc382a9d724d907e2077dab": 5
},
"Caliber9x18PM": {
"57371e4124597760ff7b25f1": 3,
"5737201124597760fc4431f1": 5,
"573720e02459776143012541": 12,
"573718ba2459775a75491131": 18,
"57371aab2459775a77142f22": 12,
"573719df2459775a626ccbc2": 10
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 9,
"5efb0e16aeb21837e749c7ff": 5,
"5a3c16fe86f77452b62de32a": 4,
"56d59d3ad2720bdb418b4577": 18,
"5c925fa22e221601da359b7b": 22,
"5efb0da7a29a85116f6ea05f": 9
},
"Caliber9x21": {
"5a269f97c4a282000b151807": 8,
"6576f93989f0062e741ba952": 18,
"5a26ac0ec4a28200741e1e18": 18,
"6576f4708ca9c4381d16cd9d": 8
},
"Caliber9x33R": {
"62330c18744e5e31df12f516": 9,
"62330b3ed4dc74626d570b95": 6
},
"Caliber9x39": {
"5c0d668f86f7747ccb7f13b2": 9,
"61962d879bb3d20b0946d385": 25,
"57a0e5022459774d1673f889": 25,
"5c0d688c86f77413ae3407b2": 12
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 3,
"66a0d1f88486c69fce00fdf6": 30,
"66a0d1e0ed648d72fe064d06": 25,
"668fe62ac62660a5d8071446": 12
}
}
}

View File

@ -0,0 +1,473 @@
{
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"66546f823b51a4d21e0d17d7": 1,
"5d1f56a686f7744bce0ee9eb": 1,
"5d1f56c686f7744bcd13459c": 2,
"637b945722e2a933ed0e33c8": 2,
"6571cb0923aa6d72760a7f8f": 2,
"5fd3e9f71b735718c25cd9f8": 2,
"642d9bbf6c06444bf7033855": 2,
"6033a35f80ae5e2f970ba6bb": 3,
"66043728333907134309d647": 3,
"5d1f56e486f7744bce0ee9ed": 3,
"6295e8c3e08ed747e64aea00": 3,
"642c18b8a6a0660b560fb31c": 3,
"66acbe49dc61999a6a03d4d6": 3,
"5d4da0cb86f77450fe0a6629": 5,
"660437e57502eca33a08caca": 5,
"5fcf63da5c287f01f22bf245": 5,
"618109c96d7ca35d076b3363": 5,
"5d1f56f186f7744bcb0acd1a": 5
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"5d1f58ed86f7744bcb0acd1c": 1,
"5d1f590486f7744bcd13459e": 2,
"642d4d8eb6b75d4c89077cf9": 2,
"6033a3fee29c9f6c9b14e74e": 2,
"5fcf940bce1ba36a513bb9cc": 3,
"660436487502eca33a08cac8": 3,
"6571cad4c8673f00290f5657": 3,
"637ba17aa10a96c2b605dbc2": 3,
"5d1f591186f7744bcc048755": 3,
"6295e944e9de5e7b3751c4da": 3,
"642c19360a69698d1b049e12": 3,
"66acc8f719271bd6d00dec0b": 3,
"660436a810bcdf80ff0e9f78": 5,
"617c02e24013b06b0b78df80": 5,
"5d1f593286f7743014162044": 5,
"5d1f592286f7743f8362bcdb": 5
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"66546f823b51a4d21e0d17d7": 1,
"5d1f565786f7743f8362bcd5": 1,
"5fce3e0cfe40296c1d5fd782": 2,
"6377266693a3b4967208e42b": 2,
"5d1f564b86f7744bcb0acd16": 2,
"6295e698e9de5e7b3751c47a": 2,
"642e8ae07e17c882400c4f87": 2,
"5d1f568486f7744bca3f0b98": 2,
"657058fddf9b3231400e9188": 3,
"6033a31e9ec839204e6a2f3e": 3,
"66043cc27502eca33a08cad0": 3,
"5fce3e47fe40296c1d5fd784": 3,
"642ed297ac11c9eaf10d87e8": 3,
"66acec1dc94f4bf5bc063a16": 3,
"5d1f567786f7744bcc04874f": 5,
"660440d2c8949a435906e43a": 5,
"617bca4b4013b06b0b78df2a": 5,
"5d1f566d86f7744bcd13459a": 5
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 2,
"5d1f588e86f7744bcc048753": 2,
"65707a89f5a6f1412f0c5f7b": 2,
"642ed40af5bdf1c04e01952e": 2,
"5fce3e965a9f8c40685693bc": 2,
"6295e63de08ed747e64ae991": 3,
"66043cf87502eca33a08cad2": 3,
"6033a3d8ed2e0509b15f9031": 3,
"5d1f58cb86f7744bca3f0b9a": 3,
"5d1f58a086f7743f8362bcd9": 3,
"642e71620a69698d1b049f0a": 3,
"66acebd4ede86671bb09584b": 3,
"66043d7ac8949a435906e434": 5,
"5d1f58ab86f7743014162042": 5,
"617be9e4e02b3b3fa50fa8f2": 5
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
},
"springEarly": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5d1f56ff86f7743f8362bcd7": 1,
"5d1f56a686f7744bce0ee9eb": 2,
"5e9da17386f774054b6f79a3": 2,
"5e4bb35286f77406a511c9bc": 2,
"5d1f56e486f7744bce0ee9ed": 2
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"66acc8f719271bd6d00dec0b": 1,
"6295e944e9de5e7b3751c4da": 1,
"5d1f592286f7743f8362bcdb": 1,
"5e4bb3b586f77406812bd579": 1,
"5d1f590486f7744bcd13459e": 3,
"5d1f58ed86f7744bcb0acd1c": 3
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"657058fddf9b3231400e9188": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5d1f567786f7744bcc04874f": 1,
"5e9d9fa986f774054d6b89f2": 1,
"5f5e401747344c2e4f6c42c5": 1,
"642e8ae07e17c882400c4f87": 2,
"5d1f568486f7744bca3f0b98": 2,
"66acec1dc94f4bf5bc063a16": 2,
"5e4bb31586f7740695730568": 2
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"66043cf87502eca33a08cad2": 1,
"5d1f58cb86f7744bca3f0b9a": 1,
"5d1f58a086f7743f8362bcd9": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"5f5e40400bc58666c37e7819": 1,
"66acebd4ede86671bb09584b": 3,
"5d1f58ab86f7743014162042": 3
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"spring": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"5df89f1f86f77412631087ea": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"summer": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"66acbe49dc61999a6a03d4d6": 1,
"64ef3efdb63b74469b6c1499": 1,
"642c18b8a6a0660b560fb31c": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f593286f7743014162044": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"64ef3efdb63b74469b6c1499": 1,
"5df89f1f86f77412631087ea": 1,
"5e9d9fa986f774054d6b89f2": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"autumn": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"637b945722e2a933ed0e33c8": 1,
"6571cb0923aa6d72760a7f8f": 1,
"6033a35f80ae5e2f970ba6bb": 1,
"5d1f56e486f7744bce0ee9ed": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"64ef3efdb63b74469b6c1499": 1,
"5d1f56ff86f7743f8362bcd7": 1
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"637ba17aa10a96c2b605dbc2": 1,
"6295e944e9de5e7b3751c4da": 1,
"5e4bb3b586f77406812bd579": 1,
"5f5e40a06760b4138443b341": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"6377266693a3b4967208e42b": 1,
"5d1f568486f7744bca3f0b98": 1,
"657058fddf9b3231400e9188": 1,
"642ed297ac11c9eaf10d87e8": 1,
"5d1f567786f7744bcc04874f": 1,
"64ef3efdb63b74469b6c1499": 1,
"6430119aac11c9eaf10d881b": 1,
"5f5e401747344c2e4f6c42c5": 1
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"642ed40af5bdf1c04e01952e": 1,
"6295e63de08ed747e64ae991": 1,
"5d1f58a086f7743f8362bcd9": 1,
"66043d7ac8949a435906e434": 1,
"5d1f58ab86f7743014162042": 1,
"5f5e40400bc58666c37e7819": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"winter": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56a686f7744bce0ee9eb": 1,
"5e9da17386f774054b6f79a3": 1,
"5e4bb35286f77406a511c9bc": 1,
"5d1f56e486f7744bce0ee9ed": 1
},
"feet": {
"5d1f590486f7744bcd13459e": 1,
"5d1f58ed86f7744bcb0acd1c": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"642e8ae07e17c882400c4f87": 1,
"5d1f568486f7744bca3f0b98": 1,
"66acec1dc94f4bf5bc063a16": 1,
"5e4bb31586f7740695730568": 1
},
"feet": {
"66acebd4ede86671bb09584b": 1,
"5d1f58ab86f7743014162042": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
}
}

View File

@ -0,0 +1,456 @@
{
"scavAmmo": {
"Caliber1143x23ACP": {
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 3
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 1
},
"Caliber12g": {
"5d6e6772a4b936088465b17c": 2,
"5d6e6806a4b936088465b17e": 2,
"5d6e67fba4b9361bc73bc779": 2,
"560d5e524bdc2d25448b4571": 2,
"5d6e6869a4b9361c140bcfde": 1,
"5d6e68b3a4b9361bca7e50b5": 1,
"58820d1224597753c90aeb13": 1,
"5d6e68dea4b9361bcc29e659": 1,
"5d6e6891a4b9361bd473feea": 1,
"5d6e68e6a4b9361c140bcfe0": 1,
"5d6e689ca4b9361bc8618956": 1
},
"Caliber20g": {
"5d6e695fa4b936359b35d852": 2,
"5d6e69b9a4b9361bc8618958": 2,
"5a38ebd9c4a282000d722a5b": 2,
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 1
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 3,
"5e85a9a6eacf8c039e4e2ac1": 1
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 3,
"59e6542b86f77411dc52a77a": 1
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 3,
"5ba26844d4351e00334c9475": 1
},
"Caliber545x39": {
"56dff216d2720bbd668b4568": 1,
"56dff338d2720bbd668b4569": 4,
"56dff421d2720b5f5a8b4567": 4,
"56dff4ecd2720b5f5a8b4568": 2,
"56dff4a2d2720bbd668b456a": 4,
"56dff0bed2720bb0668b4567": 3,
"56dff3afd2720bba668b4567": 1
},
"Caliber556x45NATO": {
"59e6927d86f77411da468256": 2,
"59e6918f86f7746c9f75e849": 2,
"59e68f6f86f7746c9f75e846": 4,
"59e6920f86f77411d82aa167": 5,
"54527a984bdc2d4e668b4567": 1
},
"Caliber57x28": {
"5cc86832d7f00c000d3a6e6c": 2,
"5cc80f79e4a949033c7343b2": 3,
"5cc86840d7f00c002412c56c": 3,
"5cc80f8fe4a949033b0224a2": 1,
"5cc80f53e4a949000e1ea4f8": 1
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 1
},
"Caliber762x25TT": {
"573602322459776445391df1": 2,
"573601b42459776410737435": 2,
"5735fdcd2459776445391d61": 1,
"5736026a245977644601dc61": 1
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 1,
"6196364158ef8c428c287d9f": 6,
"5fbe3ffdf8b6a877a729ea82": 3
},
"Caliber762x39": {
"59e4d3d286f774176a36250a": 2,
"64b7af734b75259c590fa895": 2,
"64b7af5a8532cf95ee0a0dbd": 6,
"59e4d24686f7741776641ac7": 4,
"59e4cf5286f7741778269d8a": 2,
"5656d7c34bdc2d9d198b4587": 1
},
"Caliber762x51": {
"5e023e88277cce2b522ff2b1": 2,
"5e023e6e34d52a55c3304f71": 2,
"5e023e53d4353e3302577c4c": 1
},
"Caliber762x54R": {
"64b8f7c241772715af0f9c3d": 2,
"64b8f7b5389d7ffd620ccba2": 2,
"64b8f7968532cf95ee0a0dbf": 2,
"5e023cf8186a883be655e54f": 2,
"5887431f2459777e1612938f": 1
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 2,
"5fc382c1016cce60e8341b20": 1
},
"Caliber9x18PM": {
"5737218f245977612125ba51": 5,
"57372140245977611f70ee91": 5,
"5737207f24597760ff7b25f2": 2,
"573719762459775a626ccbc1": 3,
"57371f8d24597761006c6a81": 3,
"57371f2b24597761224311f1": 5,
"57371eb62459776125652ac1": 1,
"57371b192459775a9f58a5e0": 1,
"57371e4124597760ff7b25f1": 1
},
"Caliber9x19PARA": {
"5efb0e16aeb21837e749c7ff": 1,
"58864a4f2459770fcc257101": 7,
"5a3c16fe86f77452b62de32a": 12,
"5c3df7d588a4501f290594e5": 6,
"64b7bbb74b75259c590fa897": 4,
"56d59d3ad2720bdb418b4577": 2
},
"Caliber9x21": {
"5a26ac06c4a282000c5a90a8": 5,
"5a26abfac4a28232980eabff": 3,
"5a269f97c4a282000b151807": 1
},
"Caliber9x33R": {
"62330c40bdd19b369e1e53d1": 5,
"62330bfadc5883093563729b": 3,
"62330c18744e5e31df12f516": 1
},
"Caliber9x39": {
"6576f96220d53a5b8f3e395e": 7,
"57a0dfb82459774d3078b56c": 5,
"5c0d668f86f7747ccb7f13b2": 1
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 10,
"66a0d1f88486c69fce00fdf6": 1
}
},
"pmcAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 20,
"5e81f423763d9f754677bf2e": 35,
"5efb0cabfb3e451d70735af5": 45
},
"Caliber127x55": {
"5cadf6ddae9215051e1c23b2": 45,
"5cadf6eeae921500134b2799": 55
},
"Caliber12g": {
"64b8ee384b75259c590fa89b": 10,
"5d6e6911a4b9361bd5780d52": 25,
"5d6e68c4a4b9361b93413f79": 25,
"5d6e68a8a4b9360b6c0d54e2": 25
},
"Caliber20g": {
"5d6e6a5fa4b93614ec501745": 10,
"5d6e6a53a4b9361bd473feec": 10,
"5d6e6a05a4b93618084f58d0": 40,
"5d6e6a42a4b9364f07165f52": 40
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 20,
"5e85a9a6eacf8c039e4e2ac1": 35,
"5e85aa1a988a8701445df1f5": 35
},
"Caliber366TKM": {
"59e655cb86f77411dc52a77b": 10,
"5f0596629e22f464da6bbdd9": 90
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26844d4351e00334c9475": 15,
"64b6979341772715af0f9c39": 30,
"5ba2678ad4351e44f824b344": 40,
"5ba26835d4351e0035628ff5": 15
},
"Caliber545x39": {
"56dff2ced2720bb4668b4567": 10,
"56dff061d2720bb5668b4567": 30,
"61962b617c6c7b169525f168": 30,
"56dfef82d2720bbd668b4567": 10,
"56dff026d2720bb8668b4567": 5,
"5c0d5e4486f77478390952fe": 5
},
"Caliber556x45NATO": {
"60194943740c5d77f6705eea": 5,
"59e6906286f7746c9f75e847": 10,
"54527ac44bdc2d36668b4567": 50,
"59e690b686f7746c9f75e848": 20,
"601949593ae8f707c4608daa": 15
},
"Caliber57x28": {
"5cc80f67e4a949035e43bbba": 35,
"5cc80f38e4a949001152b560": 65
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 50,
"6529243824cbe3c74a05e5c1": 50
},
"Caliber762x25TT": {
"573603562459776430731618": 10
},
"Caliber762x35": {
"5fbe3ffdf8b6a877a729ea82": 15,
"619636be6db0f2477964e710": 40,
"64b8725c4b75259c590fa899": 30,
"5fd20ff893a8961fc660a954": 15
},
"Caliber762x39": {
"64b7af434b75259c590fa893": 40,
"59e0d99486f7744a32234762": 45,
"601aa3d2b2bcb34913271e6d": 15
},
"Caliber762x51": {
"58dd3ad986f77403051cba8f": 40,
"5a608bf24f39f98ffc77720e": 35,
"5a6086ea4f39f99cd479502f": 20,
"5efb0c1bd79ff02a1f5e68d9": 5
},
"Caliber762x54R": {
"5887431f2459777e1612938f": 5,
"59e77a2386f7742ee578960a": 30,
"5e023d34e8a400319a28ed44": 40,
"560d61e84bdc2da74d8b4571": 20,
"5e023d48186a883be655e551": 5
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 5,
"5fc382c1016cce60e8341b20": 25,
"5fc275cf85fd526b824a571a": 45,
"5fc382a9d724d907e2077dab": 25
},
"Caliber9x18PM": {
"573718ba2459775a75491131": 15,
"57371aab2459775a77142f22": 50,
"573719df2459775a626ccbc2": 35
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 10,
"56d59d3ad2720bdb418b4577": 25,
"5c925fa22e221601da359b7b": 40,
"5efb0da7a29a85116f6ea05f": 25
},
"Caliber9x21": {
"5a269f97c4a282000b151807": 20,
"6576f93989f0062e741ba952": 20,
"5a26ac0ec4a28200741e1e18": 15,
"6576f4708ca9c4381d16cd9d": 10
},
"Caliber9x33R": {
"62330c18744e5e31df12f516": 10,
"62330b3ed4dc74626d570b95": 10
},
"Caliber9x39": {
"61962d879bb3d20b0946d385": 30,
"57a0e5022459774d1673f889": 40,
"5c0d688c86f77413ae3407b2": 30
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 5,
"66a0d1f88486c69fce00fdf6": 20,
"66a0d1e0ed648d72fe064d06": 50,
"668fe62ac62660a5d8071446": 30
}
},
"bossAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 4,
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 10,
"5e81f423763d9f754677bf2e": 18,
"5efb0cabfb3e451d70735af5": 10
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 3,
"5cadf6ddae9215051e1c23b2": 12,
"5cadf6eeae921500134b2799": 8
},
"Caliber12g": {
"5d6e6806a4b936088465b17e": 7,
"64b8ee384b75259c590fa89b": 4,
"5d6e6911a4b9361bd5780d52": 3,
"5c0d591486f7744c505b416f": 5,
"5d6e6891a4b9361bd473feea": 2,
"5d6e68e6a4b9361c140bcfe0": 6,
"5d6e689ca4b9361bc8618956": 8,
"5d6e68c4a4b9361b93413f79": 8,
"5d6e68a8a4b9360b6c0d54e2": 3
},
"Caliber20g": {
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 4,
"5d6e6a05a4b93618084f58d0": 5,
"5d6e6a42a4b9364f07165f52": 5
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 2,
"5e85a9a6eacf8c039e4e2ac1": 4,
"5e85aa1a988a8701445df1f5": 4
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 1,
"59e6542b86f77411dc52a77a": 2,
"59e655cb86f77411dc52a77b": 10,
"5f0596629e22f464da6bbdd9": 8
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 2,
"5ba26844d4351e00334c9475": 4,
"5ba2678ad4351e44f824b344": 15,
"64b6979341772715af0f9c39": 15,
"5ba26835d4351e0035628ff5": 8
},
"Caliber545x39": {
"56dff3afd2720bba668b4567": 6,
"56dff2ced2720bb4668b4567": 12,
"56dff061d2720bb5668b4567": 20,
"61962b617c6c7b169525f168": 12,
"56dfef82d2720bbd668b4567": 9,
"56dff026d2720bb8668b4567": 8,
"5c0d5e4486f77478390952fe": 4
},
"Caliber556x45NATO": {
"5c0d5ae286f7741e46554302": 1,
"54527a984bdc2d4e668b4567": 7,
"60194943740c5d77f6705eea": 20,
"59e6906286f7746c9f75e847": 26,
"54527ac44bdc2d36668b4567": 30,
"59e690b686f7746c9f75e848": 7,
"601949593ae8f707c4608daa": 5
},
"Caliber57x28": {
"5cc80f8fe4a949033b0224a2": 5,
"5cc80f53e4a949000e1ea4f8": 21,
"5cc80f67e4a949035e43bbba": 15,
"5cc80f38e4a949001152b560": 12
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 10,
"6529243824cbe3c74a05e5c1": 5
},
"Caliber762x25TT": {
"5736026a245977644601dc61": 5,
"573603c924597764442bd9cb": 10,
"573603562459776430731618": 10
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 7,
"5fbe3ffdf8b6a877a729ea82": 6,
"619636be6db0f2477964e710": 23,
"64b8725c4b75259c590fa899": 20,
"5fd20ff893a8961fc660a954": 9
},
"Caliber762x39": {
"59e4cf5286f7741778269d8a": 4,
"5656d7c34bdc2d9d198b4587": 28,
"64b7af434b75259c590fa893": 33,
"59e0d99486f7744a32234762": 20,
"601aa3d2b2bcb34913271e6d": 12
},
"Caliber762x51": {
"5e023e53d4353e3302577c4c": 6,
"58dd3ad986f77403051cba8f": 27,
"5a608bf24f39f98ffc77720e": 19,
"5a6086ea4f39f99cd479502f": 9,
"5efb0c1bd79ff02a1f5e68d9": 2
},
"Caliber762x54R": {
"5e023cf8186a883be655e54f": 3,
"5887431f2459777e1612938f": 20,
"59e77a2386f7742ee578960a": 25,
"5e023d34e8a400319a28ed44": 22,
"560d61e84bdc2da74d8b4571": 15,
"5e023d48186a883be655e551": 10
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 5,
"5fc382c1016cce60e8341b20": 8,
"5fc275cf85fd526b824a571a": 8,
"5fc382a9d724d907e2077dab": 5
},
"Caliber9x18PM": {
"57371e4124597760ff7b25f1": 3,
"5737201124597760fc4431f1": 5,
"573720e02459776143012541": 12,
"573718ba2459775a75491131": 18,
"57371aab2459775a77142f22": 12,
"573719df2459775a626ccbc2": 10
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 9,
"5efb0e16aeb21837e749c7ff": 5,
"5a3c16fe86f77452b62de32a": 4,
"56d59d3ad2720bdb418b4577": 18,
"5c925fa22e221601da359b7b": 22,
"5efb0da7a29a85116f6ea05f": 9
},
"Caliber9x21": {
"5a269f97c4a282000b151807": 8,
"6576f93989f0062e741ba952": 18,
"5a26ac0ec4a28200741e1e18": 18,
"6576f4708ca9c4381d16cd9d": 8
},
"Caliber9x33R": {
"62330c18744e5e31df12f516": 9,
"62330b3ed4dc74626d570b95": 6
},
"Caliber9x39": {
"5c0d668f86f7747ccb7f13b2": 9,
"61962d879bb3d20b0946d385": 25,
"57a0e5022459774d1673f889": 25,
"5c0d688c86f77413ae3407b2": 12
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 3,
"66a0d1f88486c69fce00fdf6": 30,
"66a0d1e0ed648d72fe064d06": 25,
"668fe62ac62660a5d8071446": 12
}
}
}

View File

@ -0,0 +1,493 @@
{
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"66546f823b51a4d21e0d17d7": 1,
"5d1f56a686f7744bce0ee9eb": 1,
"5d1f56c686f7744bcd13459c": 2,
"637b945722e2a933ed0e33c8": 2,
"6571cb0923aa6d72760a7f8f": 2,
"5fd3e9f71b735718c25cd9f8": 2,
"642d9bbf6c06444bf7033855": 2,
"6033a35f80ae5e2f970ba6bb": 3,
"66043728333907134309d647": 3,
"5d1f56e486f7744bce0ee9ed": 3,
"6295e8c3e08ed747e64aea00": 3,
"642c18b8a6a0660b560fb31c": 3,
"66acbe49dc61999a6a03d4d6": 3,
"5d4da0cb86f77450fe0a6629": 5,
"660437e57502eca33a08caca": 5,
"5fcf63da5c287f01f22bf245": 5,
"618109c96d7ca35d076b3363": 5,
"5d1f56f186f7744bcb0acd1a": 5,
"64ef3efdb63b74469b6c1499": 5,
"642c5273ff5ecad7810a89d7": 5,
"5d1f56ff86f7743f8362bcd7": 5,
"5e4bb35286f77406a511c9bc": 5,
"5cdea33e7d6c8b0474535dac": 5,
"5e9da17386f774054b6f79a3": 5
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"5d1f58ed86f7744bcb0acd1c": 1,
"5d1f590486f7744bcd13459e": 2,
"642d4d8eb6b75d4c89077cf9": 2,
"6033a3fee29c9f6c9b14e74e": 2,
"5fcf940bce1ba36a513bb9cc": 3,
"660436487502eca33a08cac8": 3,
"6571cad4c8673f00290f5657": 3,
"637ba17aa10a96c2b605dbc2": 3,
"5d1f591186f7744bcc048755": 3,
"6295e944e9de5e7b3751c4da": 3,
"642c19360a69698d1b049e12": 3,
"66acc8f719271bd6d00dec0b": 3,
"660436a810bcdf80ff0e9f78": 5,
"617c02e24013b06b0b78df80": 5,
"5d1f593286f7743014162044": 5,
"5d1f592286f7743f8362bcdb": 5,
"642d6941ff5ecad7810a8a61": 5,
"5df8a08886f7740bfe6df775": 5,
"5e4bb3b586f77406812bd579": 5,
"5e9dcadd86f7743e20652f23": 5
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"66546f823b51a4d21e0d17d7": 1,
"5d1f565786f7743f8362bcd5": 1,
"5fce3e0cfe40296c1d5fd782": 2,
"6377266693a3b4967208e42b": 2,
"5d1f564b86f7744bcb0acd16": 2,
"6295e698e9de5e7b3751c47a": 2,
"642e8ae07e17c882400c4f87": 2,
"5d1f568486f7744bca3f0b98": 2,
"657058fddf9b3231400e9188": 3,
"6033a31e9ec839204e6a2f3e": 3,
"66043cc27502eca33a08cad0": 3,
"5fce3e47fe40296c1d5fd784": 3,
"642ed297ac11c9eaf10d87e8": 3,
"66acec1dc94f4bf5bc063a16": 3,
"5d1f567786f7744bcc04874f": 5,
"660440d2c8949a435906e43a": 5,
"617bca4b4013b06b0b78df2a": 5,
"5d1f566d86f7744bcd13459a": 5,
"64ef3efdb63b74469b6c1499": 5,
"6430119aac11c9eaf10d881b": 5,
"5df89f1f86f77412631087ea": 5,
"5e9d9fa986f774054d6b89f2": 5,
"5cdea33e7d6c8b0474535dac": 5,
"5e4bb31586f7740695730568": 5
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 2,
"5d1f588e86f7744bcc048753": 2,
"65707a89f5a6f1412f0c5f7b": 2,
"642ed40af5bdf1c04e01952e": 2,
"5fce3e965a9f8c40685693bc": 2,
"6295e63de08ed747e64ae991": 3,
"66043cf87502eca33a08cad2": 3,
"6033a3d8ed2e0509b15f9031": 3,
"5d1f58cb86f7744bca3f0b9a": 3,
"5d1f58a086f7743f8362bcd9": 3,
"642e71620a69698d1b049f0a": 3,
"66acebd4ede86671bb09584b": 3,
"66043d7ac8949a435906e434": 5,
"5d1f58ab86f7743014162042": 5,
"617be9e4e02b3b3fa50fa8f2": 5,
"642eea6f881906a7fe086841": 5,
"5df89f8f86f77412672a1e38": 5,
"5e9dc97c86f774054c19ac9a": 5,
"5e4bb39386f774067f79de05": 5
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
},
"springEarly": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5d1f56ff86f7743f8362bcd7": 1,
"5d1f56a686f7744bce0ee9eb": 2,
"5e9da17386f774054b6f79a3": 2,
"5e4bb35286f77406a511c9bc": 2,
"5d1f56e486f7744bce0ee9ed": 2
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"66acc8f719271bd6d00dec0b": 1,
"6295e944e9de5e7b3751c4da": 1,
"5d1f592286f7743f8362bcdb": 1,
"5e4bb3b586f77406812bd579": 1,
"5d1f590486f7744bcd13459e": 3,
"5d1f58ed86f7744bcb0acd1c": 3
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"657058fddf9b3231400e9188": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5d1f567786f7744bcc04874f": 1,
"5e9d9fa986f774054d6b89f2": 1,
"5f5e401747344c2e4f6c42c5": 1,
"642e8ae07e17c882400c4f87": 2,
"5d1f568486f7744bca3f0b98": 2,
"66acec1dc94f4bf5bc063a16": 2,
"5e4bb31586f7740695730568": 2
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"66043cf87502eca33a08cad2": 1,
"5d1f58cb86f7744bca3f0b9a": 1,
"5d1f58a086f7743f8362bcd9": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"5f5e40400bc58666c37e7819": 1,
"66acebd4ede86671bb09584b": 3,
"5d1f58ab86f7743014162042": 3
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"spring": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"5df89f1f86f77412631087ea": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"summer": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"66acbe49dc61999a6a03d4d6": 1,
"64ef3efdb63b74469b6c1499": 1,
"642c18b8a6a0660b560fb31c": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f593286f7743014162044": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"64ef3efdb63b74469b6c1499": 1,
"5df89f1f86f77412631087ea": 1,
"5e9d9fa986f774054d6b89f2": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"autumn": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"637b945722e2a933ed0e33c8": 1,
"6571cb0923aa6d72760a7f8f": 1,
"6033a35f80ae5e2f970ba6bb": 1,
"5d1f56e486f7744bce0ee9ed": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"64ef3efdb63b74469b6c1499": 1,
"5d1f56ff86f7743f8362bcd7": 1
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"637ba17aa10a96c2b605dbc2": 1,
"6295e944e9de5e7b3751c4da": 1,
"5e4bb3b586f77406812bd579": 1,
"5f5e40a06760b4138443b341": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"6377266693a3b4967208e42b": 1,
"5d1f568486f7744bca3f0b98": 1,
"657058fddf9b3231400e9188": 1,
"642ed297ac11c9eaf10d87e8": 1,
"5d1f567786f7744bcc04874f": 1,
"64ef3efdb63b74469b6c1499": 1,
"6430119aac11c9eaf10d881b": 1,
"5f5e401747344c2e4f6c42c5": 1
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"642ed40af5bdf1c04e01952e": 1,
"6295e63de08ed747e64ae991": 1,
"5d1f58a086f7743f8362bcd9": 1,
"66043d7ac8949a435906e434": 1,
"5d1f58ab86f7743014162042": 1,
"5f5e40400bc58666c37e7819": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"winter": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56a686f7744bce0ee9eb": 1,
"5e9da17386f774054b6f79a3": 1,
"5e4bb35286f77406a511c9bc": 1,
"5d1f56e486f7744bce0ee9ed": 1
},
"feet": {
"5d1f590486f7744bcd13459e": 1,
"5d1f58ed86f7744bcb0acd1c": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"642e8ae07e17c882400c4f87": 1,
"5d1f568486f7744bca3f0b98": 1,
"66acec1dc94f4bf5bc063a16": 1,
"5e4bb31586f7740695730568": 1
},
"feet": {
"66acebd4ede86671bb09584b": 1,
"5d1f58ab86f7743014162042": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
}
}

View File

@ -0,0 +1,446 @@
{
"scavAmmo": {
"Caliber1143x23ACP": {
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 3
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 1
},
"Caliber12g": {
"5d6e6772a4b936088465b17c": 2,
"5d6e6806a4b936088465b17e": 2,
"5d6e67fba4b9361bc73bc779": 2,
"560d5e524bdc2d25448b4571": 2,
"5d6e6869a4b9361c140bcfde": 1,
"5d6e68b3a4b9361bca7e50b5": 1,
"58820d1224597753c90aeb13": 1,
"5d6e68dea4b9361bcc29e659": 1,
"5d6e6891a4b9361bd473feea": 1,
"5d6e68e6a4b9361c140bcfe0": 1,
"5d6e689ca4b9361bc8618956": 1
},
"Caliber20g": {
"5d6e695fa4b936359b35d852": 2,
"5d6e69b9a4b9361bc8618958": 2,
"5a38ebd9c4a282000d722a5b": 2,
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 1
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 3,
"5e85a9a6eacf8c039e4e2ac1": 1
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 3,
"59e6542b86f77411dc52a77a": 1
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 3,
"5ba26844d4351e00334c9475": 1
},
"Caliber545x39": {
"56dff216d2720bbd668b4568": 1,
"56dff338d2720bbd668b4569": 4,
"56dff421d2720b5f5a8b4567": 4,
"56dff4ecd2720b5f5a8b4568": 2,
"56dff4a2d2720bbd668b456a": 4,
"56dff0bed2720bb0668b4567": 3,
"56dff3afd2720bba668b4567": 1
},
"Caliber556x45NATO": {
"59e6927d86f77411da468256": 2,
"59e6918f86f7746c9f75e849": 2,
"59e68f6f86f7746c9f75e846": 4,
"59e6920f86f77411d82aa167": 5,
"54527a984bdc2d4e668b4567": 1
},
"Caliber57x28": {
"5cc86832d7f00c000d3a6e6c": 2,
"5cc80f79e4a949033c7343b2": 3,
"5cc86840d7f00c002412c56c": 3,
"5cc80f8fe4a949033b0224a2": 1,
"5cc80f53e4a949000e1ea4f8": 1
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 1
},
"Caliber762x25TT": {
"573602322459776445391df1": 2,
"573601b42459776410737435": 2,
"5735fdcd2459776445391d61": 1,
"5736026a245977644601dc61": 1
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 1,
"6196364158ef8c428c287d9f": 6,
"5fbe3ffdf8b6a877a729ea82": 3
},
"Caliber762x39": {
"59e4d3d286f774176a36250a": 2,
"64b7af734b75259c590fa895": 2,
"64b7af5a8532cf95ee0a0dbd": 6,
"59e4d24686f7741776641ac7": 4,
"59e4cf5286f7741778269d8a": 2,
"5656d7c34bdc2d9d198b4587": 1
},
"Caliber762x51": {
"5e023e88277cce2b522ff2b1": 2,
"5e023e6e34d52a55c3304f71": 2,
"5e023e53d4353e3302577c4c": 1
},
"Caliber762x54R": {
"64b8f7c241772715af0f9c3d": 2,
"64b8f7b5389d7ffd620ccba2": 2,
"64b8f7968532cf95ee0a0dbf": 2,
"5e023cf8186a883be655e54f": 2,
"5887431f2459777e1612938f": 1
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 2,
"5fc382c1016cce60e8341b20": 1
},
"Caliber9x18PM": {
"5737218f245977612125ba51": 5,
"57372140245977611f70ee91": 5,
"5737207f24597760ff7b25f2": 2,
"573719762459775a626ccbc1": 3,
"57371f8d24597761006c6a81": 3,
"57371f2b24597761224311f1": 5,
"57371eb62459776125652ac1": 1,
"57371b192459775a9f58a5e0": 1,
"57371e4124597760ff7b25f1": 1
},
"Caliber9x19PARA": {
"5efb0e16aeb21837e749c7ff": 1,
"58864a4f2459770fcc257101": 7,
"5a3c16fe86f77452b62de32a": 12,
"5c3df7d588a4501f290594e5": 6,
"64b7bbb74b75259c590fa897": 4,
"56d59d3ad2720bdb418b4577": 2
},
"Caliber9x21": {
"5a26ac06c4a282000c5a90a8": 5,
"5a26abfac4a28232980eabff": 3,
"5a269f97c4a282000b151807": 1
},
"Caliber9x33R": {
"62330c40bdd19b369e1e53d1": 5,
"62330bfadc5883093563729b": 3,
"62330c18744e5e31df12f516": 1
},
"Caliber9x39": {
"6576f96220d53a5b8f3e395e": 7,
"57a0dfb82459774d3078b56c": 5,
"5c0d668f86f7747ccb7f13b2": 1
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 10,
"66a0d1f88486c69fce00fdf6": 1
}
},
"pmcAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 30,
"5e81f423763d9f754677bf2e": 20,
"5efb0cabfb3e451d70735af5": 50
},
"Caliber127x55": {
"5cadf6ddae9215051e1c23b2": 30,
"5cadf6eeae921500134b2799": 70
},
"Caliber12g": {
"64b8ee384b75259c590fa89b": 10,
"5d6e6911a4b9361bd5780d52": 30,
"5d6e68c4a4b9361b93413f79": 30,
"5d6e68a8a4b9360b6c0d54e2": 40
},
"Caliber20g": {
"5d6e6a05a4b93618084f58d0": 40,
"5d6e6a42a4b9364f07165f52": 60
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 5,
"5e85a9a6eacf8c039e4e2ac1": 10,
"5e85aa1a988a8701445df1f5": 15
},
"Caliber366TKM": {
"59e655cb86f77411dc52a77b": 5,
"5f0596629e22f464da6bbdd9": 95
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"64b6979341772715af0f9c39": 30,
"5ba2678ad4351e44f824b344": 30,
"5ba26835d4351e0035628ff5": 30
},
"Caliber545x39": {
"56dff061d2720bb5668b4567": 10,
"61962b617c6c7b169525f168": 20,
"56dfef82d2720bbd668b4567": 25,
"56dff026d2720bb8668b4567": 25,
"5c0d5e4486f77478390952fe": 20
},
"Caliber556x45NATO": {
"54527ac44bdc2d36668b4567": 40,
"59e690b686f7746c9f75e848": 30,
"601949593ae8f707c4608daa": 30
},
"Caliber57x28": {
"5cc80f38e4a949001152b560": 1
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 40,
"6529243824cbe3c74a05e5c1": 60
},
"Caliber762x25TT": {
"573603562459776430731618": 10
},
"Caliber762x35": {
"5fbe3ffdf8b6a877a729ea82": 10,
"619636be6db0f2477964e710": 25,
"64b8725c4b75259c590fa899": 35,
"5fd20ff893a8961fc660a954": 30
},
"Caliber762x39": {
"64b7af434b75259c590fa893": 15,
"59e0d99486f7744a32234762": 50,
"601aa3d2b2bcb34913271e6d": 35
},
"Caliber762x51": {
"58dd3ad986f77403051cba8f": 15,
"5a608bf24f39f98ffc77720e": 35,
"5a6086ea4f39f99cd479502f": 35,
"5efb0c1bd79ff02a1f5e68d9": 15
},
"Caliber762x54R": {
"59e77a2386f7742ee578960a": 5,
"5e023d34e8a400319a28ed44": 30,
"560d61e84bdc2da74d8b4571": 45,
"5e023d48186a883be655e551": 20
},
"Caliber86x70": {
"5fc382c1016cce60e8341b20": 10,
"5fc275cf85fd526b824a571a": 50,
"5fc382a9d724d907e2077dab": 40
},
"Caliber9x18PM": {
"573718ba2459775a75491131": 10,
"57371aab2459775a77142f22": 45,
"573719df2459775a626ccbc2": 45
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 10,
"56d59d3ad2720bdb418b4577": 5,
"5c925fa22e221601da359b7b": 45,
"5efb0da7a29a85116f6ea05f": 35
},
"Caliber9x21": {
"5a269f97c4a282000b151807": 10,
"6576f93989f0062e741ba952": 20,
"5a26ac0ec4a28200741e1e18": 30,
"6576f4708ca9c4381d16cd9d": 30
},
"Caliber9x33R": {
"62330b3ed4dc74626d570b95": 10
},
"Caliber9x39": {
"61962d879bb3d20b0946d385": 20,
"57a0e5022459774d1673f889": 40,
"5c0d688c86f77413ae3407b2": 40
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 2,
"66a0d1f88486c69fce00fdf6": 10,
"66a0d1e0ed648d72fe064d06": 40,
"668fe62ac62660a5d8071446": 40
}
},
"bossAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 4,
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 10,
"5e81f423763d9f754677bf2e": 18,
"5efb0cabfb3e451d70735af5": 10
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 3,
"5cadf6ddae9215051e1c23b2": 12,
"5cadf6eeae921500134b2799": 8
},
"Caliber12g": {
"5d6e6806a4b936088465b17e": 7,
"64b8ee384b75259c590fa89b": 4,
"5d6e6911a4b9361bd5780d52": 3,
"5c0d591486f7744c505b416f": 5,
"5d6e6891a4b9361bd473feea": 2,
"5d6e68e6a4b9361c140bcfe0": 6,
"5d6e689ca4b9361bc8618956": 8,
"5d6e68c4a4b9361b93413f79": 8,
"5d6e68a8a4b9360b6c0d54e2": 3
},
"Caliber20g": {
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 4,
"5d6e6a05a4b93618084f58d0": 5,
"5d6e6a42a4b9364f07165f52": 5
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 2,
"5e85a9a6eacf8c039e4e2ac1": 4,
"5e85aa1a988a8701445df1f5": 4
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 1,
"59e6542b86f77411dc52a77a": 2,
"59e655cb86f77411dc52a77b": 10,
"5f0596629e22f464da6bbdd9": 8
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 2,
"5ba26844d4351e00334c9475": 4,
"5ba2678ad4351e44f824b344": 15,
"64b6979341772715af0f9c39": 15,
"5ba26835d4351e0035628ff5": 8
},
"Caliber545x39": {
"56dff3afd2720bba668b4567": 6,
"56dff2ced2720bb4668b4567": 12,
"56dff061d2720bb5668b4567": 20,
"61962b617c6c7b169525f168": 12,
"56dfef82d2720bbd668b4567": 9,
"56dff026d2720bb8668b4567": 8,
"5c0d5e4486f77478390952fe": 4
},
"Caliber556x45NATO": {
"5c0d5ae286f7741e46554302": 1,
"54527a984bdc2d4e668b4567": 7,
"60194943740c5d77f6705eea": 20,
"59e6906286f7746c9f75e847": 26,
"54527ac44bdc2d36668b4567": 30,
"59e690b686f7746c9f75e848": 7,
"601949593ae8f707c4608daa": 5
},
"Caliber57x28": {
"5cc80f8fe4a949033b0224a2": 5,
"5cc80f53e4a949000e1ea4f8": 21,
"5cc80f67e4a949035e43bbba": 15,
"5cc80f38e4a949001152b560": 12
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 10,
"6529243824cbe3c74a05e5c1": 5
},
"Caliber762x25TT": {
"5736026a245977644601dc61": 5,
"573603c924597764442bd9cb": 10,
"573603562459776430731618": 10
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 7,
"5fbe3ffdf8b6a877a729ea82": 6,
"619636be6db0f2477964e710": 23,
"64b8725c4b75259c590fa899": 20,
"5fd20ff893a8961fc660a954": 9
},
"Caliber762x39": {
"59e4cf5286f7741778269d8a": 4,
"5656d7c34bdc2d9d198b4587": 28,
"64b7af434b75259c590fa893": 33,
"59e0d99486f7744a32234762": 20,
"601aa3d2b2bcb34913271e6d": 12
},
"Caliber762x51": {
"5e023e53d4353e3302577c4c": 6,
"58dd3ad986f77403051cba8f": 27,
"5a608bf24f39f98ffc77720e": 19,
"5a6086ea4f39f99cd479502f": 9,
"5efb0c1bd79ff02a1f5e68d9": 2
},
"Caliber762x54R": {
"5e023cf8186a883be655e54f": 3,
"5887431f2459777e1612938f": 20,
"59e77a2386f7742ee578960a": 25,
"5e023d34e8a400319a28ed44": 22,
"560d61e84bdc2da74d8b4571": 15,
"5e023d48186a883be655e551": 10
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 5,
"5fc382c1016cce60e8341b20": 8,
"5fc275cf85fd526b824a571a": 8,
"5fc382a9d724d907e2077dab": 5
},
"Caliber9x18PM": {
"57371e4124597760ff7b25f1": 3,
"5737201124597760fc4431f1": 5,
"573720e02459776143012541": 12,
"573718ba2459775a75491131": 18,
"57371aab2459775a77142f22": 12,
"573719df2459775a626ccbc2": 10
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 9,
"5efb0e16aeb21837e749c7ff": 5,
"5a3c16fe86f77452b62de32a": 4,
"56d59d3ad2720bdb418b4577": 18,
"5c925fa22e221601da359b7b": 22,
"5efb0da7a29a85116f6ea05f": 9
},
"Caliber9x21": {
"5a269f97c4a282000b151807": 8,
"6576f93989f0062e741ba952": 18,
"5a26ac0ec4a28200741e1e18": 18,
"6576f4708ca9c4381d16cd9d": 8
},
"Caliber9x33R": {
"62330c18744e5e31df12f516": 9,
"62330b3ed4dc74626d570b95": 6
},
"Caliber9x39": {
"5c0d668f86f7747ccb7f13b2": 9,
"61962d879bb3d20b0946d385": 25,
"57a0e5022459774d1673f889": 25,
"5c0d688c86f77413ae3407b2": 12
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 3,
"66a0d1f88486c69fce00fdf6": 30,
"66a0d1e0ed648d72fe064d06": 25,
"668fe62ac62660a5d8071446": 12
}
}
}

View File

@ -0,0 +1,487 @@
{
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"637b945722e2a933ed0e33c8": 1,
"6571cb0923aa6d72760a7f8f": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"642d9bbf6c06444bf7033855": 1,
"6033a35f80ae5e2f970ba6bb": 2,
"66043728333907134309d647": 2,
"5d1f56e486f7744bce0ee9ed": 2,
"6295e8c3e08ed747e64aea00": 2,
"642c18b8a6a0660b560fb31c": 2,
"66acbe49dc61999a6a03d4d6": 2,
"5d4da0cb86f77450fe0a6629": 3,
"660437e57502eca33a08caca": 3,
"5fcf63da5c287f01f22bf245": 3,
"618109c96d7ca35d076b3363": 3,
"5d1f56f186f7744bcb0acd1a": 3,
"64ef3efdb63b74469b6c1499": 5,
"642c5273ff5ecad7810a89d7": 5,
"5d1f56ff86f7743f8362bcd7": 5,
"5e4bb35286f77406a511c9bc": 5,
"5cdea33e7d6c8b0474535dac": 5,
"5e9da17386f774054b6f79a3": 5,
"5f5e4075df4f3100376a8138": 5
},
"feet": {
"5d1f590486f7744bcd13459e": 1,
"642d4d8eb6b75d4c89077cf9": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"5fcf940bce1ba36a513bb9cc": 2,
"660436487502eca33a08cac8": 2,
"6571cad4c8673f00290f5657": 2,
"637ba17aa10a96c2b605dbc2": 2,
"5d1f591186f7744bcc048755": 2,
"6295e944e9de5e7b3751c4da": 2,
"642c19360a69698d1b049e12": 2,
"66acc8f719271bd6d00dec0b": 2,
"660436a810bcdf80ff0e9f78": 3,
"617c02e24013b06b0b78df80": 3,
"5d1f593286f7743014162044": 3,
"5d1f592286f7743f8362bcdb": 3,
"642d6941ff5ecad7810a8a61": 5,
"5df8a08886f7740bfe6df775": 5,
"5e4bb3b586f77406812bd579": 5,
"5e9dcadd86f7743e20652f23": 5,
"5f5e40a06760b4138443b341": 5
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5fce3e0cfe40296c1d5fd782": 1,
"6377266693a3b4967208e42b": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"642e8ae07e17c882400c4f87": 1,
"5d1f568486f7744bca3f0b98": 1,
"657058fddf9b3231400e9188": 2,
"6033a31e9ec839204e6a2f3e": 2,
"66043cc27502eca33a08cad0": 2,
"5fce3e47fe40296c1d5fd784": 2,
"642ed297ac11c9eaf10d87e8": 2,
"66acec1dc94f4bf5bc063a16": 2,
"5d1f567786f7744bcc04874f": 3,
"660440d2c8949a435906e43a": 3,
"617bca4b4013b06b0b78df2a": 3,
"5d1f566d86f7744bcd13459a": 3,
"64ef3efdb63b74469b6c1499": 5,
"6430119aac11c9eaf10d881b": 5,
"5df89f1f86f77412631087ea": 5,
"5e9d9fa986f774054d6b89f2": 5,
"5cdea33e7d6c8b0474535dac": 5,
"5e4bb31586f7740695730568": 5,
"5f5e401747344c2e4f6c42c5": 5
},
"feet": {
"6377315993a3b4967208e437": 1,
"5d1f588e86f7744bcc048753": 1,
"65707a89f5a6f1412f0c5f7b": 1,
"642ed40af5bdf1c04e01952e": 1,
"5fce3e965a9f8c40685693bc": 1,
"6295e63de08ed747e64ae991": 2,
"66043cf87502eca33a08cad2": 2,
"6033a3d8ed2e0509b15f9031": 2,
"5d1f58cb86f7744bca3f0b9a": 2,
"5d1f58a086f7743f8362bcd9": 2,
"642e71620a69698d1b049f0a": 2,
"66acebd4ede86671bb09584b": 2,
"66043d7ac8949a435906e434": 3,
"5d1f58ab86f7743014162042": 3,
"617be9e4e02b3b3fa50fa8f2": 3,
"642eea6f881906a7fe086841": 5,
"5df89f8f86f77412672a1e38": 5,
"5e9dc97c86f774054c19ac9a": 5,
"5e4bb39386f774067f79de05": 5,
"5f5e40400bc58666c37e7819": 5
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
},
"springEarly": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5d1f56ff86f7743f8362bcd7": 1,
"5d1f56a686f7744bce0ee9eb": 2,
"5e9da17386f774054b6f79a3": 2,
"5e4bb35286f77406a511c9bc": 2,
"5d1f56e486f7744bce0ee9ed": 2
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"66acc8f719271bd6d00dec0b": 1,
"6295e944e9de5e7b3751c4da": 1,
"5d1f592286f7743f8362bcdb": 1,
"5e4bb3b586f77406812bd579": 1,
"5d1f590486f7744bcd13459e": 3,
"5d1f58ed86f7744bcb0acd1c": 3
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"657058fddf9b3231400e9188": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5d1f567786f7744bcc04874f": 1,
"5e9d9fa986f774054d6b89f2": 1,
"5f5e401747344c2e4f6c42c5": 1,
"642e8ae07e17c882400c4f87": 2,
"5d1f568486f7744bca3f0b98": 2,
"66acec1dc94f4bf5bc063a16": 2,
"5e4bb31586f7740695730568": 2
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"66043cf87502eca33a08cad2": 1,
"5d1f58cb86f7744bca3f0b9a": 1,
"5d1f58a086f7743f8362bcd9": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"5f5e40400bc58666c37e7819": 1,
"66acebd4ede86671bb09584b": 3,
"5d1f58ab86f7743014162042": 3
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"spring": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"5df89f1f86f77412631087ea": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"summer": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"66acbe49dc61999a6a03d4d6": 1,
"64ef3efdb63b74469b6c1499": 1,
"642c18b8a6a0660b560fb31c": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f593286f7743014162044": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"64ef3efdb63b74469b6c1499": 1,
"5df89f1f86f77412631087ea": 1,
"5e9d9fa986f774054d6b89f2": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"autumn": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"637b945722e2a933ed0e33c8": 1,
"6571cb0923aa6d72760a7f8f": 1,
"6033a35f80ae5e2f970ba6bb": 1,
"5d1f56e486f7744bce0ee9ed": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"64ef3efdb63b74469b6c1499": 1,
"5d1f56ff86f7743f8362bcd7": 1
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"637ba17aa10a96c2b605dbc2": 1,
"6295e944e9de5e7b3751c4da": 1,
"5e4bb3b586f77406812bd579": 1,
"5f5e40a06760b4138443b341": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"6377266693a3b4967208e42b": 1,
"5d1f568486f7744bca3f0b98": 1,
"657058fddf9b3231400e9188": 1,
"642ed297ac11c9eaf10d87e8": 1,
"5d1f567786f7744bcc04874f": 1,
"64ef3efdb63b74469b6c1499": 1,
"6430119aac11c9eaf10d881b": 1,
"5f5e401747344c2e4f6c42c5": 1
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"642ed40af5bdf1c04e01952e": 1,
"6295e63de08ed747e64ae991": 1,
"5d1f58a086f7743f8362bcd9": 1,
"66043d7ac8949a435906e434": 1,
"5d1f58ab86f7743014162042": 1,
"5f5e40400bc58666c37e7819": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"winter": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56a686f7744bce0ee9eb": 1,
"5e9da17386f774054b6f79a3": 1,
"5e4bb35286f77406a511c9bc": 1,
"5d1f56e486f7744bce0ee9ed": 1
},
"feet": {
"5d1f590486f7744bcd13459e": 1,
"5d1f58ed86f7744bcb0acd1c": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"642e8ae07e17c882400c4f87": 1,
"5d1f568486f7744bca3f0b98": 1,
"66acec1dc94f4bf5bc063a16": 1,
"5e4bb31586f7740695730568": 1
},
"feet": {
"66acebd4ede86671bb09584b": 1,
"5d1f58ab86f7743014162042": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
}
}

View File

@ -0,0 +1,436 @@
{
"scavAmmo": {
"Caliber1143x23ACP": {
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 3
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 1
},
"Caliber12g": {
"5d6e6772a4b936088465b17c": 2,
"5d6e6806a4b936088465b17e": 2,
"5d6e67fba4b9361bc73bc779": 2,
"560d5e524bdc2d25448b4571": 2,
"5d6e6869a4b9361c140bcfde": 1,
"5d6e68b3a4b9361bca7e50b5": 1,
"58820d1224597753c90aeb13": 1,
"5d6e68dea4b9361bcc29e659": 1,
"5d6e6891a4b9361bd473feea": 1,
"5d6e68e6a4b9361c140bcfe0": 1,
"5d6e689ca4b9361bc8618956": 1
},
"Caliber20g": {
"5d6e695fa4b936359b35d852": 2,
"5d6e69b9a4b9361bc8618958": 2,
"5a38ebd9c4a282000d722a5b": 2,
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 1
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 3,
"5e85a9a6eacf8c039e4e2ac1": 1
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 3,
"59e6542b86f77411dc52a77a": 1
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 3,
"5ba26844d4351e00334c9475": 1
},
"Caliber545x39": {
"56dff216d2720bbd668b4568": 1,
"56dff338d2720bbd668b4569": 4,
"56dff421d2720b5f5a8b4567": 4,
"56dff4ecd2720b5f5a8b4568": 2,
"56dff4a2d2720bbd668b456a": 4,
"56dff0bed2720bb0668b4567": 3,
"56dff3afd2720bba668b4567": 1
},
"Caliber556x45NATO": {
"59e6927d86f77411da468256": 2,
"59e6918f86f7746c9f75e849": 2,
"59e68f6f86f7746c9f75e846": 4,
"59e6920f86f77411d82aa167": 5,
"54527a984bdc2d4e668b4567": 1
},
"Caliber57x28": {
"5cc86832d7f00c000d3a6e6c": 2,
"5cc80f79e4a949033c7343b2": 3,
"5cc86840d7f00c002412c56c": 3,
"5cc80f8fe4a949033b0224a2": 1,
"5cc80f53e4a949000e1ea4f8": 1
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 1
},
"Caliber762x25TT": {
"573602322459776445391df1": 2,
"573601b42459776410737435": 2,
"5735fdcd2459776445391d61": 1,
"5736026a245977644601dc61": 1
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 1,
"6196364158ef8c428c287d9f": 6,
"5fbe3ffdf8b6a877a729ea82": 3
},
"Caliber762x39": {
"59e4d3d286f774176a36250a": 2,
"64b7af734b75259c590fa895": 2,
"64b7af5a8532cf95ee0a0dbd": 6,
"59e4d24686f7741776641ac7": 4,
"59e4cf5286f7741778269d8a": 2,
"5656d7c34bdc2d9d198b4587": 1
},
"Caliber762x51": {
"5e023e88277cce2b522ff2b1": 2,
"5e023e6e34d52a55c3304f71": 2,
"5e023e53d4353e3302577c4c": 1
},
"Caliber762x54R": {
"64b8f7c241772715af0f9c3d": 2,
"64b8f7b5389d7ffd620ccba2": 2,
"64b8f7968532cf95ee0a0dbf": 2,
"5e023cf8186a883be655e54f": 2,
"5887431f2459777e1612938f": 1
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 2,
"5fc382c1016cce60e8341b20": 1
},
"Caliber9x18PM": {
"5737218f245977612125ba51": 5,
"57372140245977611f70ee91": 5,
"5737207f24597760ff7b25f2": 2,
"573719762459775a626ccbc1": 3,
"57371f8d24597761006c6a81": 3,
"57371f2b24597761224311f1": 5,
"57371eb62459776125652ac1": 1,
"57371b192459775a9f58a5e0": 1,
"57371e4124597760ff7b25f1": 1
},
"Caliber9x19PARA": {
"5efb0e16aeb21837e749c7ff": 1,
"58864a4f2459770fcc257101": 7,
"5a3c16fe86f77452b62de32a": 12,
"5c3df7d588a4501f290594e5": 6,
"64b7bbb74b75259c590fa897": 4,
"56d59d3ad2720bdb418b4577": 2
},
"Caliber9x21": {
"5a26ac06c4a282000c5a90a8": 5,
"5a26abfac4a28232980eabff": 3,
"5a269f97c4a282000b151807": 1
},
"Caliber9x33R": {
"62330c40bdd19b369e1e53d1": 5,
"62330bfadc5883093563729b": 3,
"62330c18744e5e31df12f516": 1
},
"Caliber9x39": {
"6576f96220d53a5b8f3e395e": 7,
"57a0dfb82459774d3078b56c": 5,
"5c0d668f86f7747ccb7f13b2": 1
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 10,
"66a0d1f88486c69fce00fdf6": 1
}
},
"pmcAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 20,
"5efb0cabfb3e451d70735af5": 50
},
"Caliber127x55": {
"5cadf6ddae9215051e1c23b2": 15,
"5cadf6eeae921500134b2799": 85
},
"Caliber12g": {
"64b8ee384b75259c590fa89b": 15,
"5d6e6911a4b9361bd5780d52": 15,
"5d6e68c4a4b9361b93413f79": 25,
"5d6e68a8a4b9360b6c0d54e2": 45
},
"Caliber20g": {
"5d6e6a05a4b93618084f58d0": 20,
"5d6e6a42a4b9364f07165f52": 80
},
"Caliber23x75": {
"5e85a9a6eacf8c039e4e2ac1": 10,
"5e85aa1a988a8701445df1f5": 30
},
"Caliber366TKM": {
"5f0596629e22f464da6bbdd9": 1
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"64b6979341772715af0f9c39": 20,
"5ba2678ad4351e44f824b344": 30,
"5ba26835d4351e0035628ff5": 50
},
"Caliber545x39": {
"56dff061d2720bb5668b4567": 5,
"61962b617c6c7b169525f168": 5,
"56dfef82d2720bbd668b4567": 15,
"56dff026d2720bb8668b4567": 35,
"5c0d5e4486f77478390952fe": 40
},
"Caliber556x45NATO": {
"54527ac44bdc2d36668b4567": 30,
"59e690b686f7746c9f75e848": 35,
"601949593ae8f707c4608daa": 35
},
"Caliber57x28": {
"5cc80f38e4a949001152b560": 1
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 20,
"6529243824cbe3c74a05e5c1": 80
},
"Caliber762x25TT": {
"573603562459776430731618": 10
},
"Caliber762x35": {
"619636be6db0f2477964e710": 20,
"64b8725c4b75259c590fa899": 40,
"5fd20ff893a8961fc660a954": 40
},
"Caliber762x39": {
"64b7af434b75259c590fa893": 10,
"59e0d99486f7744a32234762": 45,
"601aa3d2b2bcb34913271e6d": 45
},
"Caliber762x51": {
"58dd3ad986f77403051cba8f": 10,
"5a608bf24f39f98ffc77720e": 20,
"5a6086ea4f39f99cd479502f": 40,
"5efb0c1bd79ff02a1f5e68d9": 30
},
"Caliber762x54R": {
"5e023d34e8a400319a28ed44": 20,
"560d61e84bdc2da74d8b4571": 55,
"5e023d48186a883be655e551": 35
},
"Caliber86x70": {
"5fc275cf85fd526b824a571a": 50,
"5fc382a9d724d907e2077dab": 50
},
"Caliber9x18PM": {
"57371aab2459775a77142f22": 40,
"573719df2459775a626ccbc2": 60
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 10,
"5c925fa22e221601da359b7b": 45,
"5efb0da7a29a85116f6ea05f": 45
},
"Caliber9x21": {
"6576f93989f0062e741ba952": 20,
"5a26ac0ec4a28200741e1e18": 30,
"6576f4708ca9c4381d16cd9d": 30
},
"Caliber9x33R": {
"62330b3ed4dc74626d570b95": 10
},
"Caliber9x39": {
"57a0e5022459774d1673f889": 40,
"5c0d688c86f77413ae3407b2": 60
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 1,
"66a0d1f88486c69fce00fdf6": 3,
"66a0d1e0ed648d72fe064d06": 50,
"668fe62ac62660a5d8071446": 50
}
},
"bossAmmo": {
"Caliber1143x23ACP": {
"5ea2a8e200685063ec28c05a": 4,
"5efb0fc6aeb21837e749c801": 1,
"5efb0d4f4bc50b58e81710f3": 10,
"5e81f423763d9f754677bf2e": 18,
"5efb0cabfb3e451d70735af5": 10
},
"Caliber127x55": {
"5cadf6e5ae921500113bb973": 3,
"5cadf6ddae9215051e1c23b2": 12,
"5cadf6eeae921500134b2799": 8
},
"Caliber12g": {
"5d6e6806a4b936088465b17e": 7,
"64b8ee384b75259c590fa89b": 4,
"5d6e6911a4b9361bd5780d52": 3,
"5c0d591486f7744c505b416f": 5,
"5d6e6891a4b9361bd473feea": 2,
"5d6e68e6a4b9361c140bcfe0": 6,
"5d6e689ca4b9361bc8618956": 8,
"5d6e68c4a4b9361b93413f79": 8,
"5d6e68a8a4b9360b6c0d54e2": 3
},
"Caliber20g": {
"5d6e69c7a4b9360b6c0d54e4": 1,
"5d6e6a53a4b9361bd473feec": 4,
"5d6e6a05a4b93618084f58d0": 5,
"5d6e6a42a4b9364f07165f52": 5
},
"Caliber23x75": {
"5f647f31b6238e5dd066e196": 2,
"5e85a9a6eacf8c039e4e2ac1": 4,
"5e85aa1a988a8701445df1f5": 4
},
"Caliber366TKM": {
"59e6658b86f77411d949b250": 1,
"59e6542b86f77411dc52a77a": 2,
"59e655cb86f77411dc52a77b": 10,
"5f0596629e22f464da6bbdd9": 8
},
"Caliber40mmRU": {
"5656eb674bdc2d35148b457c": 1
},
"Caliber40x46": {
"5ede4739e0350d05467f73e8": 1,
"5ede47405b097655935d7d16": 1,
"5ede474b0c226a66f5402622": 1,
"5ede475339ee016e8c534742": 1,
"5ede475b549eed7c6d5c18fb": 1,
"5f0c892565703e5c461894e9": 1
},
"Caliber46x30": {
"5ba26812d4351e003201fef1": 2,
"5ba26844d4351e00334c9475": 4,
"5ba2678ad4351e44f824b344": 15,
"64b6979341772715af0f9c39": 15,
"5ba26835d4351e0035628ff5": 8
},
"Caliber545x39": {
"56dff3afd2720bba668b4567": 6,
"56dff2ced2720bb4668b4567": 12,
"56dff061d2720bb5668b4567": 20,
"61962b617c6c7b169525f168": 12,
"56dfef82d2720bbd668b4567": 9,
"56dff026d2720bb8668b4567": 8,
"5c0d5e4486f77478390952fe": 4
},
"Caliber556x45NATO": {
"5c0d5ae286f7741e46554302": 1,
"54527a984bdc2d4e668b4567": 7,
"60194943740c5d77f6705eea": 20,
"59e6906286f7746c9f75e847": 26,
"54527ac44bdc2d36668b4567": 30,
"59e690b686f7746c9f75e848": 7,
"601949593ae8f707c4608daa": 5
},
"Caliber57x28": {
"5cc80f8fe4a949033b0224a2": 5,
"5cc80f53e4a949000e1ea4f8": 21,
"5cc80f67e4a949035e43bbba": 15,
"5cc80f38e4a949001152b560": 12
},
"Caliber68x51": {
"6529302b8c26af6326029fb7": 10,
"6529243824cbe3c74a05e5c1": 5
},
"Caliber762x25TT": {
"5736026a245977644601dc61": 5,
"573603c924597764442bd9cb": 10,
"573603562459776430731618": 10
},
"Caliber762x35": {
"6196365d58ef8c428c287da1": 7,
"5fbe3ffdf8b6a877a729ea82": 6,
"619636be6db0f2477964e710": 23,
"64b8725c4b75259c590fa899": 20,
"5fd20ff893a8961fc660a954": 9
},
"Caliber762x39": {
"59e4cf5286f7741778269d8a": 4,
"5656d7c34bdc2d9d198b4587": 28,
"64b7af434b75259c590fa893": 33,
"59e0d99486f7744a32234762": 20,
"601aa3d2b2bcb34913271e6d": 12
},
"Caliber762x51": {
"5e023e53d4353e3302577c4c": 6,
"58dd3ad986f77403051cba8f": 27,
"5a608bf24f39f98ffc77720e": 19,
"5a6086ea4f39f99cd479502f": 9,
"5efb0c1bd79ff02a1f5e68d9": 2
},
"Caliber762x54R": {
"5e023cf8186a883be655e54f": 3,
"5887431f2459777e1612938f": 20,
"59e77a2386f7742ee578960a": 25,
"5e023d34e8a400319a28ed44": 22,
"560d61e84bdc2da74d8b4571": 15,
"5e023d48186a883be655e551": 10
},
"Caliber86x70": {
"5fc382b6d6fa9c00c571bbc3": 5,
"5fc382c1016cce60e8341b20": 8,
"5fc275cf85fd526b824a571a": 8,
"5fc382a9d724d907e2077dab": 5
},
"Caliber9x18PM": {
"57371e4124597760ff7b25f1": 3,
"5737201124597760fc4431f1": 5,
"573720e02459776143012541": 12,
"573718ba2459775a75491131": 18,
"57371aab2459775a77142f22": 12,
"573719df2459775a626ccbc2": 10
},
"Caliber9x19PARA": {
"5c0d56a986f774449d5de529": 9,
"5efb0e16aeb21837e749c7ff": 5,
"5a3c16fe86f77452b62de32a": 4,
"56d59d3ad2720bdb418b4577": 18,
"5c925fa22e221601da359b7b": 22,
"5efb0da7a29a85116f6ea05f": 9
},
"Caliber9x21": {
"5a269f97c4a282000b151807": 8,
"6576f93989f0062e741ba952": 18,
"5a26ac0ec4a28200741e1e18": 18,
"6576f4708ca9c4381d16cd9d": 8
},
"Caliber9x33R": {
"62330c18744e5e31df12f516": 9,
"62330b3ed4dc74626d570b95": 6
},
"Caliber9x39": {
"5c0d668f86f7747ccb7f13b2": 9,
"61962d879bb3d20b0946d385": 25,
"57a0e5022459774d1673f889": 25,
"5c0d688c86f77413ae3407b2": 12
},
"Caliber127x33": {
"66a0d1c87d0d369e270bb9de": 3,
"66a0d1f88486c69fce00fdf6": 30,
"66a0d1e0ed648d72fe064d06": 25,
"668fe62ac62660a5d8071446": 12
}
}
}

View File

@ -0,0 +1,468 @@
{
"pmcUSEC": {
"appearance": {
"body": {
"6033a35f80ae5e2f970ba6bb": 1,
"66043728333907134309d647": 1,
"5d1f56e486f7744bce0ee9ed": 1,
"6295e8c3e08ed747e64aea00": 1,
"642c18b8a6a0660b560fb31c": 1,
"66acbe49dc61999a6a03d4d6": 1,
"5d4da0cb86f77450fe0a6629": 3,
"660437e57502eca33a08caca": 3,
"5fcf63da5c287f01f22bf245": 3,
"618109c96d7ca35d076b3363": 3,
"5d1f56f186f7744bcb0acd1a": 3,
"64ef3efdb63b74469b6c1499": 5,
"642c5273ff5ecad7810a89d7": 5,
"5d1f56ff86f7743f8362bcd7": 5,
"5e4bb35286f77406a511c9bc": 5,
"5cdea33e7d6c8b0474535dac": 5,
"5e9da17386f774054b6f79a3": 5,
"5f5e4075df4f3100376a8138": 5
},
"feet": {
"5fcf940bce1ba36a513bb9cc": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"637ba17aa10a96c2b605dbc2": 1,
"5d1f591186f7744bcc048755": 1,
"6295e944e9de5e7b3751c4da": 1,
"642c19360a69698d1b049e12": 1,
"66acc8f719271bd6d00dec0b": 1,
"660436a810bcdf80ff0e9f78": 3,
"617c02e24013b06b0b78df80": 3,
"5d1f593286f7743014162044": 3,
"5d1f592286f7743f8362bcdb": 3,
"642d6941ff5ecad7810a8a61": 5,
"5df8a08886f7740bfe6df775": 5,
"5e4bb3b586f77406812bd579": 5,
"5e9dcadd86f7743e20652f23": 5,
"5f5e40a06760b4138443b341": 5
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"657058fddf9b3231400e9188": 1,
"6033a31e9ec839204e6a2f3e": 1,
"66043cc27502eca33a08cad0": 1,
"5fce3e47fe40296c1d5fd784": 1,
"642ed297ac11c9eaf10d87e8": 1,
"66acec1dc94f4bf5bc063a16": 1,
"5d1f567786f7744bcc04874f": 3,
"660440d2c8949a435906e43a": 3,
"617bca4b4013b06b0b78df2a": 3,
"5d1f566d86f7744bcd13459a": 3,
"64ef3efdb63b74469b6c1499": 5,
"6430119aac11c9eaf10d881b": 5,
"5df89f1f86f77412631087ea": 5,
"5e9d9fa986f774054d6b89f2": 5,
"5cdea33e7d6c8b0474535dac": 5,
"5e4bb31586f7740695730568": 5,
"5f5e401747344c2e4f6c42c5": 5
},
"feet": {
"6295e63de08ed747e64ae991": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"5d1f58cb86f7744bca3f0b9a": 1,
"5d1f58a086f7743f8362bcd9": 1,
"642e71620a69698d1b049f0a": 1,
"66acebd4ede86671bb09584b": 1,
"66043d7ac8949a435906e434": 3,
"5d1f58ab86f7743014162042": 3,
"617be9e4e02b3b3fa50fa8f2": 3,
"642eea6f881906a7fe086841": 5,
"5df89f8f86f77412672a1e38": 5,
"5e9dc97c86f774054c19ac9a": 5,
"5e4bb39386f774067f79de05": 5,
"5f5e40400bc58666c37e7819": 5
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
},
"springEarly": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5d1f56ff86f7743f8362bcd7": 1,
"5d1f56a686f7744bce0ee9eb": 2,
"5e9da17386f774054b6f79a3": 2,
"5e4bb35286f77406a511c9bc": 2,
"5d1f56e486f7744bce0ee9ed": 2
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"66acc8f719271bd6d00dec0b": 1,
"6295e944e9de5e7b3751c4da": 1,
"5d1f592286f7743f8362bcdb": 1,
"5e4bb3b586f77406812bd579": 1,
"5d1f590486f7744bcd13459e": 3,
"5d1f58ed86f7744bcb0acd1c": 3
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"657058fddf9b3231400e9188": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5d1f567786f7744bcc04874f": 1,
"5e9d9fa986f774054d6b89f2": 1,
"5f5e401747344c2e4f6c42c5": 1,
"642e8ae07e17c882400c4f87": 2,
"5d1f568486f7744bca3f0b98": 2,
"66acec1dc94f4bf5bc063a16": 2,
"5e4bb31586f7740695730568": 2
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"66043cf87502eca33a08cad2": 1,
"5d1f58cb86f7744bca3f0b9a": 1,
"5d1f58a086f7743f8362bcd9": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"5f5e40400bc58666c37e7819": 1,
"66acebd4ede86671bb09584b": 3,
"5d1f58ab86f7743014162042": 3
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"spring": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"5df89f1f86f77412631087ea": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"summer": {
"pmcUSEC": {
"appearance": {
"body": {
"5cde95d97d6c8b647a3769b0": 1,
"5d1f56c686f7744bcd13459c": 1,
"5fd3e9f71b735718c25cd9f8": 1,
"66043728333907134309d647": 1,
"5d4da0cb86f77450fe0a6629": 1,
"66acbe49dc61999a6a03d4d6": 1,
"64ef3efdb63b74469b6c1499": 1,
"642c18b8a6a0660b560fb31c": 1,
"5d1f56f186f7744bcb0acd1a": 1,
"5f5e4075df4f3100376a8138": 1
},
"feet": {
"5cde95ef7d6c8b04713c4f2d": 1,
"6033a3fee29c9f6c9b14e74e": 1,
"660436487502eca33a08cac8": 1,
"6571cad4c8673f00290f5657": 1,
"66acc8f719271bd6d00dec0b": 1,
"5d1f593286f7743014162044": 1,
"5d1f592286f7743f8362bcdb": 1,
"642d6941ff5ecad7810a8a61": 1,
"5e9dcadd86f7743e20652f23": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"5cc0858d14c02e000c6bea66": 1,
"5d1f564b86f7744bcb0acd16": 1,
"6295e698e9de5e7b3751c47a": 1,
"6033a31e9ec839204e6a2f3e": 1,
"5fce3e47fe40296c1d5fd784": 1,
"617bca4b4013b06b0b78df2a": 1,
"64ef3efdb63b74469b6c1499": 1,
"5df89f1f86f77412631087ea": 1,
"5e9d9fa986f774054d6b89f2": 1
},
"feet": {
"5cc085bb14c02e000e67a5c5": 1,
"5d1f588e86f7744bcc048753": 1,
"66043cf87502eca33a08cad2": 1,
"6033a3d8ed2e0509b15f9031": 1,
"642e71620a69698d1b049f0a": 1,
"617be9e4e02b3b3fa50fa8f2": 1,
"642eea6f881906a7fe086841": 1,
"5df89f8f86f77412672a1e38": 1,
"5e9dc97c86f774054c19ac9a": 1,
"5e4bb39386f774067f79de05": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"autumn": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56c686f7744bcd13459c": 1,
"637b945722e2a933ed0e33c8": 1,
"6571cb0923aa6d72760a7f8f": 1,
"6033a35f80ae5e2f970ba6bb": 1,
"5d1f56e486f7744bce0ee9ed": 1,
"66acbe49dc61999a6a03d4d6": 1,
"660437e57502eca33a08caca": 1,
"64ef3efdb63b74469b6c1499": 1,
"5d1f56ff86f7743f8362bcd7": 1
},
"feet": {
"642d4d8eb6b75d4c89077cf9": 1,
"5fcf940bce1ba36a513bb9cc": 1,
"637ba17aa10a96c2b605dbc2": 1,
"6295e944e9de5e7b3751c4da": 1,
"5e4bb3b586f77406812bd579": 1,
"5f5e40a06760b4138443b341": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"6377266693a3b4967208e42b": 1,
"5d1f568486f7744bca3f0b98": 1,
"657058fddf9b3231400e9188": 1,
"642ed297ac11c9eaf10d87e8": 1,
"5d1f567786f7744bcc04874f": 1,
"64ef3efdb63b74469b6c1499": 1,
"6430119aac11c9eaf10d881b": 1,
"5f5e401747344c2e4f6c42c5": 1
},
"feet": {
"5d1f58bd86f7744bce0ee9ef": 1,
"6377315993a3b4967208e437": 1,
"642ed40af5bdf1c04e01952e": 1,
"6295e63de08ed747e64ae991": 1,
"5d1f58a086f7743f8362bcd9": 1,
"66043d7ac8949a435906e434": 1,
"5d1f58ab86f7743014162042": 1,
"5f5e40400bc58666c37e7819": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
},
"winter": {
"pmcUSEC": {
"appearance": {
"body": {
"5d1f56a686f7744bce0ee9eb": 1,
"5e9da17386f774054b6f79a3": 1,
"5e4bb35286f77406a511c9bc": 1,
"5d1f56e486f7744bce0ee9ed": 1
},
"feet": {
"5d1f590486f7744bcd13459e": 1,
"5d1f58ed86f7744bcb0acd1c": 1
},
"hands": {
"5cde95fa7d6c8b04737c2d13": 1
},
"head": {
"5cde96047d6c8b20b577f016": 1,
"5fdb4139e4ed5b5ea251e4ed": 1,
"5fdb5950f5264a66150d1c6e": 1,
"60a6aa8fd559ae040d0d951f": 1,
"619f9e338858a474c8685cc9": 1,
"62aca6a1310e67685a2fc2e7": 1,
"6574aabee0423b9ebe0c79cf": 1
}
}
},
"pmcBEAR": {
"appearance": {
"body": {
"642e8ae07e17c882400c4f87": 1,
"5d1f568486f7744bca3f0b98": 1,
"66acec1dc94f4bf5bc063a16": 1,
"5e4bb31586f7740695730568": 1
},
"feet": {
"66acebd4ede86671bb09584b": 1,
"5d1f58ab86f7743014162042": 1
},
"hands": {
"5cc0876314c02e000c6bea6b": 1
},
"head": {
"5cc084dd14c02e000b0550a3": 1,
"5fdb50bb2b730a787b3f78cf": 1,
"5fdb7571e4ed5b5ea251e529": 1,
"60a6aaad42fd2735e4589978": 1,
"619f94f5b90286142b59d45f": 1,
"62a9e7d15ea3b87d6f642a28": 1,
"6574aa9a1b144de18c0fba45": 1
}
}
}
}
}

View File

@ -0,0 +1,657 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { injectable, inject } from "tsyringe";
import { IDatabaseTables } from "@spt/models/spt/server/IDatabaseTables";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
import { IPmcConfig } from "@spt/models/spt/config/IPmcConfig";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { DatabaseService } from "@spt/services/DatabaseService";
import { BaseClasses } from "@spt/models/enums/BaseClasses";
import { ItemHelper } from "@spt/helpers/ItemHelper";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { TierInformation } from "../Globals/TierInformation";
import { RaidInformation } from "../Globals/RaidInformation";
import { ModConfig } from "../Globals/ModConfig";
import { APBSLogger } from "../Utils/APBSLogger";
import { Logging } from "../Enums/Logging";
@injectable()
export class BotConfigs
{
protected botConfig: IBotConfig;
protected pmcConfig: IPmcConfig;
constructor(
@inject("IDatabaseTables") protected tables: IDatabaseTables,
@inject("DatabaseService") protected database: DatabaseService,
@inject("ConfigServer") protected configServer: ConfigServer,
@inject("ItemHelper") protected itemHelper: ItemHelper,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("TierInformation") protected tierInformation: TierInformation,
@inject("RaidInformation") protected raidInformation: RaidInformation,
@inject("APBSLogger") protected apbsLogger: APBSLogger
)
{
this.botConfig = this.configServer.getConfig(ConfigTypes.BOT);
this.pmcConfig = this.configServer.getConfig(ConfigTypes.PMC);
}
public initialize(): void
{
this.clearNoLongerNeededBotDetails();
this.configureBotExperienceLevels();
this.configurePlateWeightings();
this.configureWeaponDurability();
this.adjustNVG();
this.setLootItemResourceRandomization();
this.setPMCItemLimits();
this.setPMCLoot();
this.setPMCScopeWhitelist();
this.setPMCSlotIDsToMakeRequired();
this.removeThermalGoggles(ModConfig.config.enableT7Thermals);
if (ModConfig.config.gameVersionWeight) this.setPMCGameVersionWeights();
if (ModConfig.config.addAllKeysToScavs || ModConfig.config.addOnlyKeyCardsToScavs || ModConfig.config.addOnlyMechanicalKeysToScavs) this.pushScavKeys();
if (ModConfig.config.enableCustomPlateChances) this.setPlateChances();
if (ModConfig.config.forceStock) this.setForceStock();
if (ModConfig.config.forceDustCover) this.setForceDustCover();
if (ModConfig.config.forceScopeSlot) this.setForceScopes();
if (ModConfig.config.forceWeaponModLimits) this.setWeaponModLimits();
if (!ModConfig.config.scavLoot) this.removeScavLoot();
if (ModConfig.config.enableScavEqualEquipmentTiering) this.setIdenticalScavWeights();
if (ModConfig.config.enableCustomLevelDeltas) this.setLevelDeltas();
if (ModConfig.config.enableScavCustomLevelDeltas) this.setScavLevelDeltas();
if (ModConfig.config.forceMuzzle) this.setMuzzleChances();
}
private configureBotExperienceLevels(): void
{
const botTypeTable = this.tables.bots.types;
for (const botType in botTypeTable)
{
botTypeTable[botType].experience.level.min = 1;
botTypeTable[botType].experience.level.max = 79;
}
}
private configurePlateWeightings(): void
{
const botConfigEquipment = this.botConfig.equipment
for (const botType in botConfigEquipment)
{
if (botType.includes("assault") || botType.includes("marksman"))
{
botConfigEquipment[botType].filterPlatesByLevel = true;
botConfigEquipment[botType].armorPlateWeighting = this.tierInformation.scavArmorPlateWeights;
continue;
}
botConfigEquipment[botType].filterPlatesByLevel = true;
botConfigEquipment[botType].armorPlateWeighting = this.tierInformation.armorPlateWeights;
}
}
private clearNoLongerNeededBotDetails(): void
{
const botConfigEquipment = this.botConfig.equipment
for (const botType in botConfigEquipment)
{
botConfigEquipment[botType].randomisation = [];
botConfigEquipment[botType].weightingAdjustmentsByBotLevel = [];
}
}
private configureWeaponDurability(): void
{
// Do this better in the future - this looks like shit. Bad Acid. Bad.
const botConfigDurability = this.botConfig.durability
for (const botType in botConfigDurability)
{
if (botType == "pmc")
{
botConfigDurability[botType].weapon.lowestMax = ModConfig.config.pmcWeaponDurability[0]
botConfigDurability[botType].weapon.highestMax = ModConfig.config.pmcWeaponDurability[1]
botConfigDurability[botType].weapon.minDelta = ModConfig.config.pmcWeaponDurability[2]
botConfigDurability[botType].weapon.maxDelta = ModConfig.config.pmcWeaponDurability[3]
botConfigDurability[botType].weapon.minLimitPercent = 40
}
if (botType == "boss" || botType == "arenafighterevent" || botType == "arenafighter" || botType == "sectantpriest" || botType == "sectantwarrior")
{
botConfigDurability[botType].weapon.lowestMax = ModConfig.config.bossWeaponDurability[0]
botConfigDurability[botType].weapon.highestMax = ModConfig.config.bossWeaponDurability[1]
botConfigDurability[botType].weapon.minDelta = ModConfig.config.bossWeaponDurability[2]
botConfigDurability[botType].weapon.maxDelta = ModConfig.config.bossWeaponDurability[3]
botConfigDurability[botType].weapon.minLimitPercent = 40
}
if (botType == "assault" || botType == "cursedassault" || botType == "marksman" || botType == "crazyassaultevent" || botType == "default")
{
botConfigDurability[botType].weapon.lowestMax = ModConfig.config.scavWeaponDurability[0]
botConfigDurability[botType].weapon.highestMax = ModConfig.config.scavWeaponDurability[1]
botConfigDurability[botType].weapon.minDelta = ModConfig.config.scavWeaponDurability[2]
botConfigDurability[botType].weapon.maxDelta = ModConfig.config.scavWeaponDurability[3]
botConfigDurability[botType].weapon.minLimitPercent = 40
}
if (botType == "follower")
{
botConfigDurability[botType].weapon.lowestMax = ModConfig.config.guardWeaponDurability[0]
botConfigDurability[botType].weapon.highestMax = ModConfig.config.guardWeaponDurability[1]
botConfigDurability[botType].weapon.minDelta = ModConfig.config.guardWeaponDurability[2]
botConfigDurability[botType].weapon.maxDelta = ModConfig.config.guardWeaponDurability[3]
botConfigDurability[botType].weapon.minLimitPercent = 40
}
if (botType == "pmcbot" || botType == "exusec")
{
botConfigDurability[botType].weapon.lowestMax = ModConfig.config.raiderWeaponDurability[0]
botConfigDurability[botType].weapon.highestMax = ModConfig.config.raiderWeaponDurability[1]
botConfigDurability[botType].weapon.minDelta = ModConfig.config.raiderWeaponDurability[2]
botConfigDurability[botType].weapon.maxDelta = ModConfig.config.raiderWeaponDurability[3]
botConfigDurability[botType].weapon.minLimitPercent = 40
}
}
}
private adjustNVG(): void
{
const botConfigEquipment = this.botConfig.equipment
for (const botType in botConfigEquipment)
{
botConfigEquipment[botType].faceShieldIsActiveChancePercent = 90;
botConfigEquipment[botType].lightIsActiveDayChancePercent = 7;
botConfigEquipment[botType].lightIsActiveNightChancePercent = 25;
botConfigEquipment[botType].laserIsActiveChancePercent = 50;
botConfigEquipment[botType].nvgIsActiveChanceDayPercent = 0;
botConfigEquipment[botType].nvgIsActiveChanceNightPercent = 95;
}
}
private setForceStock(): void
{
for (const tierObject in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[tierObject].tier
const tierJson = this.apbsEquipmentGetter.getTierChancesJson(tierNumber);
for (const botType in this.tierInformation.tier1chances)
{
const chances = tierJson[botType].chances
for (const weaponType in chances)
{
chances[weaponType]["mod_stock"] = 100;
chances[weaponType]["mod_stock_000"] = 100;
chances[weaponType]["mod_stock_001"] = 100;
chances[weaponType]["mod_stock_akms"] = 100;
chances[weaponType]["mod_stock_axis"] = 100;
}
}
}
}
private setForceDustCover(): void
{
for (const tierObject in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[tierObject].tier
const tierJson = this.apbsEquipmentGetter.getTierChancesJson(tierNumber);
for (const botType in this.tierInformation.tier1chances)
{
const chances = tierJson[botType].chances
for (const weaponType in chances)
{
chances[weaponType]["mod_reciever"] = 100;
}
}
}
}
private setForceScopes(): void
{
for (const tierObject in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[tierObject].tier
const tierJson = this.apbsEquipmentGetter.getTierChancesJson(tierNumber);
for (const botType in this.tierInformation.tier1chances)
{
const chances = tierJson[botType].chances
for (const weaponType in chances)
{
chances[weaponType]["mod_scope"] = 100;
}
}
}
}
private setPlateChances()
{
for (const tierObject in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[tierObject].tier
const tierJson = this.apbsEquipmentGetter.getTierChancesJson(tierNumber);
for (const botType in this.tierInformation.tier1chances)
{
if (botType == "pmcUSEC" || botType == "pmcBEAR")
{
tierJson[botType].chances.equipmentMods["back_plate"] = tierJson[botType].chances.equipmentMods["front_plate"] = ModConfig.config.pmcMainPlateChance[tierObject];
tierJson[botType].chances.equipmentMods["left_side_plate"] = tierJson[botType].chances.equipmentMods["right_side_plate"] = ModConfig.config.pmcSidePlateChance[tierObject];
}
if (botType == "followerbirdeye" || botType == "followerbigpipe" || botType.includes("boss") || botType.includes("sectant"))
{
tierJson[botType].chances.equipmentMods["back_plate"] = tierJson[botType].chances.equipmentMods["front_plate"] = ModConfig.config.bossMainPlateChance[tierObject];
tierJson[botType].chances.equipmentMods["left_side_plate"] = tierJson[botType].chances.equipmentMods["right_side_plate"] = ModConfig.config.bossSidePlateChance[tierObject];
}
if (botType == "scav")
{
tierJson[botType].chances.equipmentMods["back_plate"] = tierJson[botType].chances.equipmentMods["front_plate"] = ModConfig.config.scavMainPlateChance[tierObject];
tierJson[botType].chances.equipmentMods["left_side_plate"] = tierJson[botType].chances.equipmentMods["right_side_plate"] = ModConfig.config.scavSidePlateChance[tierObject];
}
if (botType == "exusec" || botType == "pmcbot")
{
tierJson[botType].chances.equipmentMods["back_plate"] = tierJson[botType].chances.equipmentMods["front_plate"] = ModConfig.config.raiderMainPlateChance[tierObject];
tierJson[botType].chances.equipmentMods["left_side_plate"] = tierJson[botType].chances.equipmentMods["right_side_plate"] = ModConfig.config.raiderSidePlateChance[tierObject];
}
if (botType == "default")
{
tierJson[botType].chances.equipmentMods["back_plate"] = tierJson[botType].chances.equipmentMods["front_plate"] = ModConfig.config.guardMainPlateChance[tierObject];
tierJson[botType].chances.equipmentMods["left_side_plate"] = tierJson[botType].chances.equipmentMods["right_side_plate"] = ModConfig.config.guardSidePlateChance[tierObject];
}
}
}
}
private setWeaponModLimits(): void
{
const botConfigEquipment = this.botConfig.equipment
for (const botType in botConfigEquipment)
{
if (botConfigEquipment[botType].weaponModLimits == undefined)
{
botConfigEquipment[botType].weaponModLimits =
{
"scopeLimit": 2,
"lightLaserLimit": 1
}
}
botConfigEquipment[botType].weaponModLimits.scopeLimit = ModConfig.config.scopeLimit;
botConfigEquipment[botType].weaponModLimits.lightLaserLimit = ModConfig.config.tacticalLimit;
}
}
private setLootItemResourceRandomization(): void
{
// Chance it is 100% full
let scavFoodMaxChance = 100;
let scavMedMaxChance = 100;
let pmcFoodMaxChance = 100;
let pmcMedMaxChance = 100;
// Minimum resource amount
let scavFoodResourcePercent = 60;
let scavMedResourcePercent = 60;
let pmcFoodResourcePercent = 60;
let pmcMedResourcePercent = 60;
// Check if enabled, if so - change to values in config
if (ModConfig.config.enableConsumableResourceRandomization)
{
scavFoodMaxChance = ModConfig.config.scavFoodRates[0];
scavMedMaxChance = ModConfig.config.scavMedRates[0];
pmcFoodMaxChance = ModConfig.config.pmcFoodRates[0];
pmcMedMaxChance = ModConfig.config.pmcMedRates[0];
scavFoodResourcePercent = ModConfig.config.scavFoodRates[1];
scavMedResourcePercent = ModConfig.config.scavMedRates[1];
pmcFoodResourcePercent = ModConfig.config.pmcFoodRates[1];
pmcMedResourcePercent = ModConfig.config.pmcMedRates[1];
}
// Set values in botConfig
this.botConfig.lootItemResourceRandomization.assault = {"food": { "chanceMaxResourcePercent": scavFoodMaxChance, "resourcePercent": scavFoodResourcePercent }, "meds": { "chanceMaxResourcePercent": scavMedMaxChance, "resourcePercent": scavMedResourcePercent } }
this.botConfig.lootItemResourceRandomization.marksman = {"food": { "chanceMaxResourcePercent": scavFoodMaxChance, "resourcePercent": scavFoodResourcePercent }, "meds": { "chanceMaxResourcePercent": scavMedMaxChance, "resourcePercent": scavMedResourcePercent } }
this.botConfig.lootItemResourceRandomization.pmcusec = {"food": { "chanceMaxResourcePercent": pmcFoodMaxChance, "resourcePercent": pmcFoodResourcePercent }, "meds": { "chanceMaxResourcePercent": pmcMedMaxChance, "resourcePercent": pmcMedResourcePercent } }
this.botConfig.lootItemResourceRandomization.pmcbear = {"food": { "chanceMaxResourcePercent": pmcFoodMaxChance, "resourcePercent": pmcFoodResourcePercent }, "meds": { "chanceMaxResourcePercent": pmcMedMaxChance, "resourcePercent": pmcMedResourcePercent } }
this.botConfig.lootItemResourceRandomization.pmc = {"food": { "chanceMaxResourcePercent": pmcFoodMaxChance, "resourcePercent": pmcFoodResourcePercent }, "meds": { "chanceMaxResourcePercent": pmcMedMaxChance, "resourcePercent": pmcMedResourcePercent } }
}
private setPMCItemLimits(): void
{
this.botConfig.itemSpawnLimits.pmc["60098ad7c2240c0fe85c570a"] = 1;
this.botConfig.itemSpawnLimits.pmc["590c678286f77426c9660122"] = 1;
this.botConfig.itemSpawnLimits.pmc["5e831507ea0a7c419c2f9bd9"] = 1;
this.botConfig.itemSpawnLimits.pmc["590c661e86f7741e566b646a"] = 1;
this.botConfig.itemSpawnLimits.pmc["544fb45d4bdc2dee738b4568"] = 1;
this.botConfig.itemSpawnLimits.pmc["5e8488fa988a8701445df1e4"] = 1;
this.botConfig.itemSpawnLimits.pmc["544fb37f4bdc2dee738b4567"] = 1;
this.botConfig.itemSpawnLimits.pmc["5448e8d04bdc2ddf718b4569"] = 1;
this.botConfig.itemSpawnLimits.pmc["5448e8d64bdc2dce718b4568"] = 1;
}
private setPMCLoot(): void
{
this.pmcConfig.looseWeaponInBackpackLootMinMax.min = 0;
this.pmcConfig.looseWeaponInBackpackLootMinMax.max = 0;
if (ModConfig.config.pmcLoot)
{
if (ModConfig.config.pmcLootBlacklistItems.length > 0)
{
for (const item in ModConfig.config.pmcLootBlacklistItems)
{
this.pmcConfig.backpackLoot.blacklist.push(item);
this.pmcConfig.vestLoot.blacklist.push(item);
this.pmcConfig.pocketLoot.blacklist.push(item);
}
}
for (const level in this.tierInformation.lootRandomization)
{
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["0"] = 1
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["3"] = 2
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["5"] = 5
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["8"] = 6
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["10"] = 5
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["12"] = 4
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["15"] = 4
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["20"] = 3
this.tierInformation.lootRandomization[level].generation.backpackLoot.weights["23"] = 1
this.tierInformation.lootRandomization[level].generation.pocketLoot.weights["0"] = 1
this.tierInformation.lootRandomization[level].generation.pocketLoot.weights["1"] = 3
this.tierInformation.lootRandomization[level].generation.pocketLoot.weights["2"] = 4
this.tierInformation.lootRandomization[level].generation.pocketLoot.weights["3"] = 2
this.tierInformation.lootRandomization[level].generation.pocketLoot.weights["4"] = 1
this.tierInformation.lootRandomization[level].generation.vestLoot.weights["0"] = 1
this.tierInformation.lootRandomization[level].generation.vestLoot.weights["1"] = 2
this.tierInformation.lootRandomization[level].generation.vestLoot.weights["2"] = 3
this.tierInformation.lootRandomization[level].generation.vestLoot.weights["3"] = 2
this.tierInformation.lootRandomization[level].generation.vestLoot.weights["4"] = 1
}
for (const tierObject in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[tierObject].tier
const tierJson = this.apbsEquipmentGetter.getTierChancesJson(tierNumber);
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["0"] = 4
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["1"] = 15
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["2"] = 40
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["3"] = 10
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["4"] = 8
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["5"] = 2
tierJson.pmcUSEC.chances.generation.items.backpackLoot.weights["10"] = 1
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["0"] = 4
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["1"] = 15
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["2"] = 40
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["3"] = 10
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["4"] = 8
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["5"] = 2
tierJson.pmcBEAR.chances.generation.items.backpackLoot.weights["10"] = 1
tierJson.pmcUSEC.chances.generation.items.pocketLoot.weights["0"] = 4
tierJson.pmcUSEC.chances.generation.items.pocketLoot.weights["1"] = 9
tierJson.pmcUSEC.chances.generation.items.pocketLoot.weights["2"] = 1
tierJson.pmcUSEC.chances.generation.items.pocketLoot.weights["3"] = 1
tierJson.pmcBEAR.chances.generation.items.pocketLoot.weights["0"] = 4
tierJson.pmcBEAR.chances.generation.items.pocketLoot.weights["1"] = 9
tierJson.pmcBEAR.chances.generation.items.pocketLoot.weights["2"] = 1
tierJson.pmcBEAR.chances.generation.items.pocketLoot.weights["3"] = 1
tierJson.pmcUSEC.chances.generation.items.vestLoot.weights["0"] = 2
tierJson.pmcUSEC.chances.generation.items.vestLoot.weights["1"] = 12
tierJson.pmcUSEC.chances.generation.items.vestLoot.weights["2"] = 1
tierJson.pmcUSEC.chances.generation.items.vestLoot.weights["3"] = 1
tierJson.pmcUSEC.chances.generation.items.vestLoot.weights["4"] = 1
tierJson.pmcBEAR.chances.generation.items.vestLoot.weights["0"] = 2
tierJson.pmcBEAR.chances.generation.items.vestLoot.weights["1"] = 12
tierJson.pmcBEAR.chances.generation.items.vestLoot.weights["2"] = 1
tierJson.pmcBEAR.chances.generation.items.vestLoot.weights["3"] = 1
tierJson.pmcBEAR.chances.generation.items.vestLoot.weights["4"] = 1
}
this.botConfig.equipment.pmc.randomisation = this.tierInformation.lootRandomization;
}
else
{
this.botConfig.equipment.pmc.randomisation = this.tierInformation.lootRandomization;
}
}
private setPMCScopeWhitelist(): void
{
this.botConfig.equipment.pmc.weaponSightWhitelist = {
"5447b5fc4bdc2d87278b4567": [
"55818ad54bdc2ddc698b4569",
"55818acf4bdc2dde698b456b",
"55818ae44bdc2dde698b456c",
"55818ac54bdc2d5b648b456e",
"55818add4bdc2d5b648b456f",
"55818aeb4bdc2ddc698b456a"
],
"5447b5f14bdc2d61278b4567": [
"55818ad54bdc2ddc698b4569",
"55818acf4bdc2dde698b456b",
"55818ae44bdc2dde698b456c",
"55818ac54bdc2d5b648b456e",
"55818add4bdc2d5b648b456f",
"55818aeb4bdc2ddc698b456a"
],
"5447bedf4bdc2d87278b4568": [
"55818ad54bdc2ddc698b4569",
"55818add4bdc2d5b648b456f",
"55818ac54bdc2d5b648b456e",
"55818aeb4bdc2ddc698b456a"
],
"5447bed64bdc2d97278b4568": [
"55818ad54bdc2ddc698b4569",
"55818acf4bdc2dde698b456b",
"55818ac54bdc2d5b648b456e",
"55818add4bdc2d5b648b456f",
"55818aeb4bdc2ddc698b456a"
],
"5447b6194bdc2d67278b4567": [
"55818ad54bdc2ddc698b4569",
"55818ae44bdc2dde698b456c",
"55818ac54bdc2d5b648b456e",
"55818aeb4bdc2ddc698b456a",
"55818add4bdc2d5b648b456f"
],
"5447b5cf4bdc2d65278b4567": [
"55818ad54bdc2ddc698b4569",
"55818acf4bdc2dde698b456b",
"55818ac54bdc2d5b648b456e"
],
"617f1ef5e8b54b0998387733": [
"55818ad54bdc2ddc698b4569",
"55818acf4bdc2dde698b456b",
"55818ac54bdc2d5b648b456e"
],
"5447b6094bdc2dc3278b4567": [
"55818ad54bdc2ddc698b4569",
"55818acf4bdc2dde698b456b",
"55818ac54bdc2d5b648b456e"
],
"5447b5e04bdc2d62278b4567": [
"55818ad54bdc2ddc698b4569",
"55818acf4bdc2dde698b456b",
"55818ac54bdc2d5b648b456e"
],
"5447b6254bdc2dc3278b4568": [
"55818ae44bdc2dde698b456c",
"55818ac54bdc2d5b648b456e",
"55818aeb4bdc2ddc698b456a",
"55818add4bdc2d5b648b456f"
]
};
}
private pushScavKeys(): void
{
const scavBackpack = this.tables.bots.types.assault.inventory.items.Backpack
const items = Object.values(this.tables.templates.items);
const baseClass = this.getKeyConfig();
const allKeys = items.filter(x => this.itemHelper.isOfBaseclass(x._id, baseClass));
let count = 0;
for (const key in allKeys)
{
if (scavBackpack[allKeys[key]._id] == undefined)
{
scavBackpack[allKeys[key]._id] = 1;
count++
}
}
this.apbsLogger.log(Logging.DEBUG, `Added ${count} keys to Scav Backpacks (Key Class Added: ${baseClass})`)
}
private getKeyConfig(): BaseClasses
{
if (ModConfig.config.addAllKeysToScavs) return BaseClasses.KEY
if (ModConfig.config.addOnlyMechanicalKeysToScavs) return BaseClasses.KEY_MECHANICAL
if (ModConfig.config.addOnlyKeyCardsToScavs) return BaseClasses.KEYCARD
}
private removeScavLoot(): void
{
this.tables.bots.types.assault.inventory.items.Backpack = {}
this.tables.bots.types.assault.inventory.items.Pockets = {}
this.tables.bots.types.assault.inventory.items.TacticalVest = {}
this.tables.bots.types.marksman.inventory.items.Backpack = {}
this.tables.bots.types.marksman.inventory.items.Pockets = {}
this.tables.bots.types.marksman.inventory.items.TacticalVest = {}
}
private setIdenticalScavWeights(): void
{
for (const tierObject in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[tierObject].tier
const tierJson = this.apbsEquipmentGetter.getTierJson(tierNumber, true);
const scav = tierJson.scav.equipment
for (const slot in scav)
{
if (slot == "SecondPrimaryWeapon" || slot == "ArmBand") continue;
if (slot == "FirstPrimaryWeapon")
{
for (const subSlot in scav[slot])
{
for (const item in scav[slot][subSlot])
{
scav[slot][subSlot][item] = 1;
}
}
continue;
}
for (const item in scav[slot])
{
scav[slot][item] = 1;
}
}
}
}
private removeThermalGoggles(removeSome: boolean): void
{
for (const tierObject in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[tierObject].tier
const tierJson = this.apbsEquipmentGetter.getTierModsJson(tierNumber, true);
const tatmMods = tierJson["5a16b8a9fcdbcb00165aa6ca"].mod_nvg;
const index = tatmMods.indexOf("5c11046cd174af02a012e42b");
if (removeSome && tierNumber >= ModConfig.config.startTier) continue;
if (index > -1)
{
tatmMods.splice(index, 1)
}
}
}
private setPMCGameVersionWeights(): void
{
this.pmcConfig.gameVersionWeight.standard = ModConfig.config.standard;
this.pmcConfig.gameVersionWeight.left_behind = ModConfig.config.left_behind;
this.pmcConfig.gameVersionWeight.prepare_for_escape = ModConfig.config.prepare_for_escape;
this.pmcConfig.gameVersionWeight.edge_of_darkness = ModConfig.config.edge_of_darkness;
this.pmcConfig.gameVersionWeight.unheard_edition = ModConfig.config.unheard_edition;
}
private setLevelDeltas(): void
{
this.tierInformation.tiers[0].botMinLevelVariance = ModConfig.config.tier1LevelDelta[0]
this.tierInformation.tiers[0].botMaxLevelVariance = ModConfig.config.tier1LevelDelta[1]
this.tierInformation.tiers[1].botMinLevelVariance = ModConfig.config.tier2LevelDelta[0]
this.tierInformation.tiers[1].botMaxLevelVariance = ModConfig.config.tier2LevelDelta[1]
this.tierInformation.tiers[2].botMinLevelVariance = ModConfig.config.tier3LevelDelta[0]
this.tierInformation.tiers[2].botMaxLevelVariance = ModConfig.config.tier3LevelDelta[1]
this.tierInformation.tiers[3].botMinLevelVariance = ModConfig.config.tier4LevelDelta[0]
this.tierInformation.tiers[3].botMaxLevelVariance = ModConfig.config.tier4LevelDelta[1]
this.tierInformation.tiers[4].botMinLevelVariance = ModConfig.config.tier5LevelDelta[0]
this.tierInformation.tiers[4].botMaxLevelVariance = ModConfig.config.tier5LevelDelta[1]
this.tierInformation.tiers[5].botMinLevelVariance = ModConfig.config.tier6LevelDelta[0]
this.tierInformation.tiers[5].botMaxLevelVariance = ModConfig.config.tier6LevelDelta[1]
this.tierInformation.tiers[6].botMinLevelVariance = ModConfig.config.tier7LevelDelta[0]
this.tierInformation.tiers[6].botMaxLevelVariance = ModConfig.config.tier7LevelDelta[1]
}
private setScavLevelDeltas(): void
{
this.tierInformation.tiers[0].scavMinLevelVariance = ModConfig.config.tier1ScavLevelDelta[0]
this.tierInformation.tiers[0].scavMaxLevelVariance = ModConfig.config.tier1ScavLevelDelta[1]
this.tierInformation.tiers[1].scavMinLevelVariance = ModConfig.config.tier2ScavLevelDelta[0]
this.tierInformation.tiers[1].scavMaxLevelVariance = ModConfig.config.tier2ScavLevelDelta[1]
this.tierInformation.tiers[2].scavMinLevelVariance = ModConfig.config.tier3ScavLevelDelta[0]
this.tierInformation.tiers[2].scavMaxLevelVariance = ModConfig.config.tier3ScavLevelDelta[1]
this.tierInformation.tiers[3].scavMinLevelVariance = ModConfig.config.tier4ScavLevelDelta[0]
this.tierInformation.tiers[3].scavMaxLevelVariance = ModConfig.config.tier4ScavLevelDelta[1]
this.tierInformation.tiers[4].scavMinLevelVariance = ModConfig.config.tier5ScavLevelDelta[0]
this.tierInformation.tiers[4].scavMaxLevelVariance = ModConfig.config.tier5ScavLevelDelta[1]
this.tierInformation.tiers[5].scavMinLevelVariance = ModConfig.config.tier6ScavLevelDelta[0]
this.tierInformation.tiers[5].scavMaxLevelVariance = ModConfig.config.tier6ScavLevelDelta[1]
this.tierInformation.tiers[6].scavMinLevelVariance = ModConfig.config.tier7ScavLevelDelta[0]
this.tierInformation.tiers[6].scavMaxLevelVariance = ModConfig.config.tier7ScavLevelDelta[1]
}
private setPMCSlotIDsToMakeRequired(): void
{
this.botConfig.equipment.pmc.weaponSlotIdsToMakeRequired = [ "mod_reciever", "mod_stock" ]
}
private setMuzzleChances(): void
{
for (const tierObject in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[tierObject].tier
const tierJson = this.apbsEquipmentGetter.getTierChancesJson(tierNumber);
const usec = tierJson.pmcUSEC.chances
const bear = tierJson.pmcBEAR.chances
for (const type in usec)
{
if (type == "equipment" || type == "equipmentMods" || type == "generation") continue;
const arrayPosition = tierNumber - 1;
usec[type].mod_muzzle = ModConfig.config.muzzleChance[arrayPosition]
usec[type].mod_muzzle_000 = ModConfig.config.muzzleChance[arrayPosition]
usec[type].mod_muzzle_000 = ModConfig.config.muzzleChance[arrayPosition]
bear[type].mod_muzzle = ModConfig.config.muzzleChance[arrayPosition]
bear[type].mod_muzzle_000 = ModConfig.config.muzzleChance[arrayPosition]
bear[type].mod_muzzle_000 = ModConfig.config.muzzleChance[arrayPosition]
}
}
}
}

View File

@ -0,0 +1,773 @@
import { inject, injectable } from "tsyringe";
import { BotGeneratorHelper } from "@spt/helpers/BotGeneratorHelper";
import { BotHelper } from "@spt/helpers/BotHelper";
import { BotWeaponGeneratorHelper } from "@spt/helpers/BotWeaponGeneratorHelper";
import { ItemHelper } from "@spt/helpers/ItemHelper";
import { PresetHelper } from "@spt/helpers/PresetHelper";
import { ProbabilityHelper } from "@spt/helpers/ProbabilityHelper";
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
import { IItem } from "@spt/models/eft/common/tables/IItem";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import { ModSpawn } from "@spt/models/enums/ModSpawn";
import { IFilterPlateModsForSlotByLevelResult, Result } from "@spt/models/spt/bots/IFilterPlateModsForSlotByLevelResult";
import { IGenerateEquipmentProperties } from "@spt/models/spt/bots/IGenerateEquipmentProperties";
import { ExhaustableArray } from "@spt/models/spt/server/ExhaustableArray";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { BotEquipmentFilterService } from "@spt/services/BotEquipmentFilterService";
import { BotEquipmentModPoolService } from "@spt/services/BotEquipmentModPoolService";
import { BotWeaponModLimitService } from "@spt/services/BotWeaponModLimitService";
import { DatabaseService } from "@spt/services/DatabaseService";
import { ItemFilterService } from "@spt/services/ItemFilterService";
import { LocalisationService } from "@spt/services/LocalisationService";
import { HashUtil } from "@spt/utils/HashUtil";
import { RandomUtil } from "@spt/utils/RandomUtil";
import { ICloner } from "@spt/utils/cloners/ICloner";
import { Money } from "@spt/models/enums/Money";
import { IGenerateWeaponRequest } from "@spt/models/spt/bots/IGenerateWeaponRequest";
import { IModToSpawnRequest } from "@spt/models/spt/bots/IModToSpawnRequest";
import { BaseClasses } from "@spt/models/enums/BaseClasses";
import { IEquipmentFilterDetails } from "@spt/models/spt/config/IBotConfig";
import { BotEquipmentModGenerator } from "@spt/generators/BotEquipmentModGenerator";
import { IChooseRandomCompatibleModResult } from "@spt/models/spt/bots/IChooseRandomCompatibleModResult";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { APBSTierGetter } from "../Utils/APBSTierGetter";
import { ModConfig } from "../Globals/ModConfig";
import { RaidInformation } from "../Globals/RaidInformation";
import { ModInformation } from "../Globals/ModInformation";
import { APBSTester } from "../Utils/APBSTester";
import { vanillaButtpads } from "../Globals/VanillaItemLists";
/** Handle profile related client events */
@injectable()
export class APBSBotEquipmentModGenerator extends BotEquipmentModGenerator
{
constructor(
@inject("PrimaryLogger") protected logger: ILogger,
@inject("HashUtil") protected hashUtil: HashUtil,
@inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("ProbabilityHelper") protected probabilityHelper: ProbabilityHelper,
@inject("DatabaseService") protected databaseService: DatabaseService,
@inject("ItemHelper") protected itemHelper: ItemHelper,
@inject("BotEquipmentFilterService") protected botEquipmentFilterService: BotEquipmentFilterService,
@inject("ItemFilterService") protected itemFilterService: ItemFilterService,
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
@inject("BotWeaponModLimitService") protected botWeaponModLimitService: BotWeaponModLimitService,
@inject("BotHelper") protected botHelper: BotHelper,
@inject("BotGeneratorHelper") protected botGeneratorHelper: BotGeneratorHelper,
@inject("BotWeaponGeneratorHelper") protected botWeaponGeneratorHelper: BotWeaponGeneratorHelper,
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
@inject("PresetHelper") protected presetHelper: PresetHelper,
@inject("LocalisationService") protected localisationService: LocalisationService,
@inject("BotEquipmentModPoolService") protected botEquipmentModPoolService: BotEquipmentModPoolService,
@inject("ConfigServer") protected configServer: ConfigServer,
@inject("PrimaryCloner") protected cloner: ICloner,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("APBSTierGetter") protected apbsTierGetter: APBSTierGetter,
@inject("RaidInformation") protected raidInformation: RaidInformation,
@inject("ModInformation") protected modInformation: ModInformation,
@inject("APBSTester") protected apbsTester: APBSTester
)
{
super(logger,
hashUtil,
randomUtil,
probabilityHelper,
databaseService,
itemHelper,
botEquipmentFilterService,
itemFilterService,
profileHelper,
botWeaponModLimitService,
botHelper,
botGeneratorHelper,
botWeaponGeneratorHelper,
weightedRandomHelper,
presetHelper,
localisationService,
botEquipmentModPoolService,
configServer,
cloner)
}
public override generateModsForEquipment(equipment: IItem[], parentId: string, parentTemplate: ITemplateItem, settings: IGenerateEquipmentProperties, specificBlacklist: IEquipmentFilterDetails, shouldForceSpawn: boolean): IItem[]
{
let forceSpawn = shouldForceSpawn;
const botRole = settings.botData.role;
const tier = this.apbsTierGetter.getTierByLevel(settings.botData.level);
const tieredModPool = this.apbsEquipmentGetter.getModsByBotRole(botRole, tier)
let compatibleModsPool = tieredModPool[parentTemplate._id]
let actualModPool = tieredModPool;
let spawnChances = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tier);
// Roll weapon spawns (primary/secondary/holster) and generate a weapon for each roll that passed
if ((ModConfig.config.disableBossTierGeneration && (botRole.includes("boss") || botRole.includes("sectant") || botRole.includes("arena"))) || botRole == "bosslegion" || botRole == "bosspunisher")
{
spawnChances = settings.spawnChances;
compatibleModsPool = settings.modPool[parentTemplate._id];
actualModPool = settings.modPool;
}
if (ModConfig.config.disableBossFollowerTierGeneration && botRole.includes("follower"))
{
spawnChances = settings.spawnChances;
compatibleModsPool = settings.modPool[parentTemplate._id];
actualModPool = settings.modPool;
}
if (ModConfig.config.disableRaiderRogueTierGeneration && (botRole.includes("exusec") || botRole.includes("pmcbot")))
{
spawnChances = settings.spawnChances;
compatibleModsPool = settings.modPool[parentTemplate._id];
actualModPool = settings.modPool;
}
if (ModConfig.config.disablePMCTierGeneration && (botRole.includes("pmcusec") || botRole.includes("pmcbear")))
{
spawnChances = settings.spawnChances;
compatibleModsPool = settings.modPool[parentTemplate._id];
actualModPool = settings.modPool;
}
if (ModConfig.config.disableScavTierGeneration && (botRole.includes("assault") || botRole.includes("marksman")))
{
spawnChances = settings.spawnChances;
compatibleModsPool = settings.modPool[parentTemplate._id];
actualModPool = settings.modPool;
}
if (botRole.includes("infected") || botRole.includes("spirit") || botRole.includes("skier") || botRole.includes("peacemaker") || botRole.includes("gifter"))
{
spawnChances = settings.spawnChances;
compatibleModsPool = settings.modPool[parentTemplate._id];
actualModPool = settings.modPool;
}
if (!compatibleModsPool)
{
this.logger.warning(
`bot: ${botRole} lacks a mod slot pool for item: ${parentTemplate._id} ${parentTemplate._name}`);
}
// Iterate over mod pool and choose mods to add to item
for (const modSlotName in compatibleModsPool)
{
if (modSlotName === "mod_equipment_000" && this.raidInformation.nightTime) continue;
const itemSlotTemplate = this.getModItemSlotFromDb(modSlotName, parentTemplate);
if (!itemSlotTemplate)
{
this.logger.error(
this.localisationService.getText("bot-mod_slot_missing_from_item", {
modSlot: modSlotName,
parentId: parentTemplate._id,
parentName: parentTemplate._name,
botRole: settings.botData.role
})
);
continue;
}
const modSpawnResult = this.shouldModBeSpawned(
itemSlotTemplate,
modSlotName.toLowerCase(),
spawnChances.equipmentMods,
settings.botEquipmentConfig
);
if (modSpawnResult === ModSpawn.SKIP && !forceSpawn)
{
continue;
}
// Ensure submods for nvgs all spawn together if it's night
if (modSlotName === "mod_nvg")
{
if (this.raidInformation.nightTime)
{
forceSpawn = true;
}
else
{
continue;
}
}
let modPoolToChooseFrom = compatibleModsPool[modSlotName];
if (
settings.botEquipmentConfig.filterPlatesByLevel
&& this.itemHelper.isRemovablePlateSlot(modSlotName.toLowerCase())
)
{
const outcome = this.filterPlateModsForSlotByLevel(
settings,
modSlotName.toLowerCase(),
compatibleModsPool[modSlotName],
parentTemplate
);
if ([Result.UNKNOWN_FAILURE, Result.NO_DEFAULT_FILTER].includes(outcome.result))
{
this.logger.debug(
`Plate slot: ${modSlotName} selection for armor: ${parentTemplate._id} failed: ${
Result[outcome.result]
}, skipping`
);
continue;
}
if ([Result.LACKS_PLATE_WEIGHTS].includes(outcome.result))
{
this.logger.warning(
`Plate slot: ${modSlotName} lacks weights for armor: ${parentTemplate._id}, unable to adjust plate choice, using existing data`
);
}
modPoolToChooseFrom = outcome.plateModTpls;
}
// Find random mod and check its compatible
let modTpl: string | undefined;
let found = false;
const exhaustableModPool = new ExhaustableArray<string>(modPoolToChooseFrom, this.randomUtil, this.cloner);
while (exhaustableModPool.hasValues())
{
modTpl = exhaustableModPool.getRandomValue();
if (modTpl
&& !this.botGeneratorHelper.isItemIncompatibleWithCurrentItems(equipment, modTpl, modSlotName)
.incompatible
)
{
found = true;
break;
}
}
// Compatible item not found but slot REQUIRES item, get random item from db
if (!found && itemSlotTemplate._required)
{
modTpl = this.getRandomModTplFromItemDb(modTpl, itemSlotTemplate, modSlotName, equipment);
found = !!modTpl;
}
// Compatible item not found + not required
if (!(found || itemSlotTemplate._required))
{
// Don't add item
continue;
}
const modTemplate = this.itemHelper.getItem(modTpl);
if (!this.isModValidForSlot(modTemplate, itemSlotTemplate, modSlotName, parentTemplate, botRole))
{
continue;
}
// Generate new id to ensure all items are unique on bot
const modId = this.hashUtil.generate();
equipment.push(this.createModItem(modId, modTpl, parentId, modSlotName, modTemplate[1], botRole));
// Does the item being added have possible child mods?
if (Object.keys(actualModPool).includes(modTpl))
{
// Call self recursively with item being checkced item we just added to bot
this.generateModsForEquipment(
equipment,
modId,
modTemplate[1],
settings,
specificBlacklist,
forceSpawn
);
}
}
// This is for testing...
if (this.modInformation.testMode && this.modInformation.testBotRole.includes(botRole.toLowerCase()))
{
const tables = this.databaseService.getTables();
const assortEquipment = this.cloner.clone(equipment);
for (const item in assortEquipment)
{
const oldID = assortEquipment[item]._id
const newID = this.hashUtil.generate();
assortEquipment[item]._id = newID;
// Loop array again to fix parentID
for (const i in assortEquipment)
{
if (assortEquipment[i].parentId == oldID)
{
assortEquipment[i].parentId = newID
}
}
}
this.apbsTester.createComplexAssortItem(assortEquipment)
.addUnlimitedStackCount()
.addMoneyCost(Money.ROUBLES, 20000)
.addBuyRestriction(3)
.addLoyaltyLevel(1)
.export(tables.traders[this.modInformation.testTrader]);
}
return equipment;
}
protected override filterPlateModsForSlotByLevel(settings: IGenerateEquipmentProperties, modSlot: string, existingPlateTplPool: string[], armorItem: ITemplateItem): IFilterPlateModsForSlotByLevelResult
{
const result: IFilterPlateModsForSlotByLevelResult = { result: Result.UNKNOWN_FAILURE, plateModTpls: undefined };
// Not pmc or not a plate slot, return original mod pool array
if (!this.itemHelper.isRemovablePlateSlot(modSlot))
{
result.result = Result.NOT_PLATE_HOLDING_SLOT;
result.plateModTpls = existingPlateTplPool;
return result;
}
// Get the front/back/side weights based on bots level
const plateSlotWeights = settings.botEquipmentConfig?.armorPlateWeighting?.find(
(armorWeight) =>
settings.botData.level >= armorWeight.levelRange.min && settings.botData.level <= armorWeight.levelRange.max);
if (!plateSlotWeights)
{
// No weights, return original array of plate tpls
result.result = Result.LACKS_PLATE_WEIGHTS;
result.plateModTpls = existingPlateTplPool;
return result;
}
// Get the specific plate slot weights (front/back/side)
const plateWeights: Record<string, number> = plateSlotWeights[modSlot];
if (!plateWeights)
{
// No weights, return original array of plate tpls
result.result = Result.LACKS_PLATE_WEIGHTS;
result.plateModTpls = existingPlateTplPool;
return result;
}
// Choose a plate level based on weighting
let chosenArmorPlateLevel = this.weightedRandomHelper.getWeightedValue<string>(plateWeights);
// Convert the array of ids into database items
let platesFromDb = existingPlateTplPool.map((plateTpl) => this.itemHelper.getItem(plateTpl)[1]);
// Filter plates to the chosen level based on its armorClass property
let platesOfDesiredLevel = platesFromDb.filter((item) => item._props.armorClass === chosenArmorPlateLevel);
let tries = 0;
while (platesOfDesiredLevel.length === 0)
{
tries++;
chosenArmorPlateLevel = (parseInt(chosenArmorPlateLevel)+1).toString()
if (parseInt(chosenArmorPlateLevel) > 6)
{
chosenArmorPlateLevel = "3"
}
platesFromDb = existingPlateTplPool.map((plateTpl) => this.itemHelper.getItem(plateTpl)[1]);
platesOfDesiredLevel = platesFromDb.filter((item) => item._props.armorClass === chosenArmorPlateLevel);
if (platesOfDesiredLevel.length > 0) break;
if (tries >= 3) break;
}
if (platesOfDesiredLevel.length === 0)
{
this.logger.debug(`${settings.botData.role} - Plate filter was too restrictive for armor: ${armorItem._id}. Tried ${tries} times. Using mod items default plate.`);
const relatedItemDbModSlot = armorItem._props.Slots.find((slot) => slot._name.toLowerCase() === modSlot);
const defaultPlate = relatedItemDbModSlot._props.filters[0].Plate;
if (!defaultPlate)
{
// No relevant plate found after filtering AND no default plate
// Last attempt, get default preset and see if it has a plate default
const defaultPreset = this.presetHelper.getDefaultPreset(armorItem._id);
if (defaultPreset)
{
const relatedPresetSlot = defaultPreset._items.find(
(item) => item.slotId?.toLowerCase() === modSlot);
if (relatedPresetSlot)
{
result.result = Result.SUCCESS;
result.plateModTpls = [relatedPresetSlot._tpl];
return result;
}
}
// Return Default Preset cause didn't have default plates
result.result = Result.NO_DEFAULT_FILTER;
return result;
}
// Return Default Plates cause couldn't get lowest level available from original selection
result.result = Result.SUCCESS;
result.plateModTpls = [defaultPlate];
return result;
}
// Only return the items ids
result.result = Result.SUCCESS;
result.plateModTpls = platesOfDesiredLevel.map((item) => item._id);
return result;
}
protected override getCompatibleModFromPool(
modPool: string[],
modSpawnType: ModSpawn,
weapon: IItem[]
): IChooseRandomCompatibleModResult
{
// Create exhaustable pool to pick mod item from
const exhaustableModPool = this.createExhaustableArray(modPool);
// Create default response if no compatible item is found below
const chosenModResult: IChooseRandomCompatibleModResult = {
incompatible: true,
found: false,
reason: "unknown"
};
// Limit how many attempts to find a compatible mod can occur before giving up
const maxBlockedAttempts = Math.round(modPool.length); // 75% of pool size
let blockedAttemptCount = 0;
let chosenTpl: string;
while (exhaustableModPool.hasValues())
{
chosenTpl = exhaustableModPool.getRandomValue();
const pickedItemDetails = this.itemHelper.getItem(chosenTpl);
if (!pickedItemDetails[0])
{
// Not valid item, try again
continue;
}
if (!pickedItemDetails[1]._props)
{
// no props data, try again
continue;
}
// Success - Default wanted + only 1 item in pool
if (modSpawnType === ModSpawn.DEFAULT_MOD && modPool.length === 1)
{
chosenModResult.found = true;
chosenModResult.incompatible = false;
chosenModResult.chosenTpl = chosenTpl;
break;
}
// Check if existing weapon mods are incompatible with chosen item
const existingItemBlockingChoice = weapon.find((item) =>
pickedItemDetails[1]._props.ConflictingItems?.includes(item._tpl)
);
if (existingItemBlockingChoice)
{
// Give max of x attempts of picking a mod if blocked by another
if (blockedAttemptCount > maxBlockedAttempts)
{
blockedAttemptCount = 0; // reset
break;
}
blockedAttemptCount++;
// Not compatible - Try again
continue;
}
// Edge case- Some mod combos will never work, make sure this isnt the case
if (this.weaponModComboIsIncompatible(weapon, chosenTpl))
{
chosenModResult.reason = `Chosen weapon mod: ${chosenTpl} can never be compatible with existing weapon mods`;
break;
}
// Success
chosenModResult.found = true;
chosenModResult.incompatible = false;
chosenModResult.chosenTpl = chosenTpl;
break;
}
return chosenModResult;
}
public apbsGenerateModsForWeapon(sessionId: string, request: IGenerateWeaponRequest, isPmc: boolean): IItem[]
{
const pmcProfile = this.profileHelper.getPmcProfile(sessionId);
// Get pool of mods that fit weapon
const compatibleModsPool = request.modPool[request.parentTemplate._id];
if (
!(
request.parentTemplate._props.Slots.length ||
request.parentTemplate._props.Cartridges?.length ||
request.parentTemplate._props.Chambers?.length
)
)
{
this.logger.error(
this.localisationService.getText("bot-unable_to_add_mods_to_weapon_missing_ammo_slot", {
weaponName: request.parentTemplate._name,
weaponId: request.parentTemplate._id,
botRole: request.botData.role
})
);
return request.weapon;
}
const botEquipConfig = this.botConfig.equipment[request.botData.equipmentRole];
const botEquipBlacklist = this.botEquipmentFilterService.getBotEquipmentBlacklist(
request.botData.equipmentRole,
pmcProfile.Info.Level
);
const botWeaponSightWhitelist = this.botEquipmentFilterService.getBotWeaponSightWhitelist(
request.botData.equipmentRole
);
const randomisationSettings = this.botHelper.getBotRandomizationDetails(request.botData.level, botEquipConfig);
// Iterate over mod pool and choose mods to attach
const sortedModKeys = this.sortModKeys(Object.keys(compatibleModsPool), request.parentTemplate._id);
for (const modSlot of sortedModKeys)
{
// Check weapon has slot for mod to fit in
const modsParentSlot = this.getModItemSlotFromDb(modSlot, request.parentTemplate);
if (!modsParentSlot)
{
this.logger.error(
this.localisationService.getText("bot-weapon_missing_mod_slot", {
modSlot: modSlot,
weaponId: request.parentTemplate._id,
weaponName: request.parentTemplate._name,
botRole: request.botData.role
})
);
continue;
}
// Check spawn chance of mod
const modSpawnResult = this.shouldModBeSpawned(
modsParentSlot,
modSlot,
request.modSpawnChances,
botEquipConfig
);
if (modSpawnResult === ModSpawn.SKIP)
{
continue;
}
const isRandomisableSlot = randomisationSettings?.randomisedWeaponModSlots?.includes(modSlot) ?? false;
const modToSpawnRequest: IModToSpawnRequest = {
modSlot: modSlot,
isRandomisableSlot: isRandomisableSlot,
randomisationSettings: randomisationSettings,
botWeaponSightWhitelist: botWeaponSightWhitelist,
botEquipBlacklist: botEquipBlacklist,
itemModPool: compatibleModsPool,
weapon: request.weapon,
ammoTpl: request.ammoTpl,
parentTemplate: request.parentTemplate,
modSpawnResult: modSpawnResult,
weaponStats: request.weaponStats,
conflictingItemTpls: request.conflictingItemTpls,
botData: request.botData
};
const modToAdd = this.chooseModToPutIntoSlot(modToSpawnRequest);
// Compatible mod not found
if (!modToAdd || typeof modToAdd === "undefined")
{
continue;
}
if (
!this.isModValidForSlot(modToAdd, modsParentSlot, modSlot, request.parentTemplate, request.botData.role)
)
{
continue;
}
const modToAddTemplate = modToAdd[1];
// Skip adding mod to weapon if type limit reached
if (
this.botWeaponModLimitService.weaponModHasReachedLimit(
request.botData.equipmentRole,
modToAddTemplate,
request.modLimits,
request.parentTemplate,
request.weapon
)
)
{
continue;
}
if (vanillaButtpads.includes(modToAddTemplate._id))
{
if (!this.randomUtil.getChance100(ModConfig.config.stockButtpadChance))
{
continue;
}
}
// If item is a mount for scopes, set scope chance to 100%, this helps fix empty mounts appearing on weapons
if (this.modSlotCanHoldScope(modSlot, modToAddTemplate._parent))
{
// mod_mount was picked to be added to weapon, force scope chance to ensure its filled
let scopeSlots = ["mod_scope", "mod_scope_000", "mod_scope_001", "mod_scope_002", "mod_scope_003"];
if (isPmc) scopeSlots = ["mod_scope", "mod_scope_000"]
this.adjustSlotSpawnChances(request.modSpawnChances, scopeSlots, 100);
// Hydrate pool of mods that fit into mount as its a randomisable slot
if (isRandomisableSlot)
{
// Add scope mods to modPool dictionary to ensure the mount has a scope in the pool to pick
this.addCompatibleModsForProvidedMod(
"mod_scope",
modToAddTemplate,
request.modPool,
botEquipBlacklist
);
}
}
if (ModConfig.config.forceChildrenMuzzle)
{
// If picked item is muzzle adapter that can hold a child, adjust spawn chance
if (this.modSlotCanHoldMuzzleDevices(modSlot, modToAddTemplate._parent))
{
const muzzleSlots = ["mod_muzzle", "mod_muzzle_000", "mod_muzzle_001"];
this.adjustSlotSpawnChances(request.modSpawnChances, muzzleSlots, 100);
}
}
// If front/rear sight are to be added, set opposite to 100% chance
if (this.modIsFrontOrRearSight(modSlot, modToAddTemplate._id))
{
request.modSpawnChances.mod_sight_front = 100;
request.modSpawnChances.mod_sight_rear = 100;
}
// Handguard mod can take a sub handguard mod + weapon has no UBGL (takes same slot)
// Force spawn chance to be 100% to ensure it gets added
if (
modSlot === "mod_handguard" &&
modToAddTemplate._props.Slots.some((slot) => slot._name === "mod_handguard") &&
!request.weapon.some((item) => item.slotId === "mod_launcher")
)
{
// Needed for handguards with lower
request.modSpawnChances.mod_handguard = 100;
}
// If stock mod can take a sub stock mod, force spawn chance to be 100% to ensure sub-stock gets added
// Or if mod_stock is configured to be forced on
if (this.shouldForceSubStockSlots(modSlot, botEquipConfig, modToAddTemplate))
{
// Stock mod can take additional stocks, could be a locking device, force 100% chance
const subStockSlots = ["mod_stock", "mod_stock_000", "mod_stock_001", "mod_stock_akms"];
this.adjustSlotSpawnChances(request.modSpawnChances, subStockSlots, 100);
}
// Gather stats on mods being added to weapon
if (this.itemHelper.isOfBaseclass(modToAddTemplate._id, BaseClasses.IRON_SIGHT))
{
if (modSlot === "mod_sight_front")
{
request.weaponStats.hasFrontIronSight = true;
}
else if (modSlot === "mod_sight_rear")
{
request.weaponStats.hasRearIronSight = true;
}
}
else if (
!request.weaponStats.hasOptic &&
this.itemHelper.isOfBaseclass(modToAddTemplate._id, BaseClasses.SIGHTS)
)
{
request.weaponStats.hasOptic = true;
}
const modId = this.hashUtil.generate();
request.weapon.push(
this.createModItem(
modId,
modToAddTemplate._id,
request.weaponId,
modSlot,
modToAddTemplate,
request.botData.role
)
);
// Update conflicting item list now item has been chosen
for (const conflictingItem of modToAddTemplate._props.ConflictingItems)
{
request.conflictingItemTpls.add(conflictingItem);
}
// I first thought we could use the recursive generateModsForItems as previously for cylinder magazines.
// However, the recursion doesn't go over the slots of the parent mod but over the modPool which is given by the bot config
// where we decided to keep cartridges instead of camoras. And since a CylinderMagazine only has one cartridge entry and
// this entry is not to be filled, we need a special handling for the CylinderMagazine
const modParentItem = this.itemHelper.getItem(modToAddTemplate._parent)[1];
if (this.botWeaponGeneratorHelper.magazineIsCylinderRelated(modParentItem._name))
{
// We don't have child mods, we need to create the camoras for the magazines instead
this.fillCamora(request.weapon, request.modPool, modId, modToAddTemplate);
}
else
{
let containsModInPool = Object.keys(request.modPool).includes(modToAddTemplate._id);
// Sometimes randomised slots are missing sub-mods, if so, get values from mod pool service
// Check for a randomisable slot + without data in modPool + item being added as additional slots
if (isRandomisableSlot && !containsModInPool && modToAddTemplate._props.Slots.length > 0)
{
const modFromService = this.botEquipmentModPoolService.getModsForWeaponSlot(modToAddTemplate._id);
if (Object.keys(modFromService ?? {}).length > 0)
{
request.modPool[modToAddTemplate._id] = modFromService;
containsModInPool = true;
}
}
if (containsModInPool)
{
const recursiveRequestData: IGenerateWeaponRequest = {
weapon: request.weapon,
modPool: request.modPool,
weaponId: modId,
parentTemplate: modToAddTemplate,
modSpawnChances: request.modSpawnChances,
ammoTpl: request.ammoTpl,
botData: {
role: request.botData.role,
level: request.botData.level,
equipmentRole: request.botData.equipmentRole
},
modLimits: request.modLimits,
weaponStats: request.weaponStats,
conflictingItemTpls: request.conflictingItemTpls
};
// Call self recursively to add mods to this mod
this.apbsGenerateModsForWeapon(sessionId, recursiveRequestData, isPmc);
}
}
}
return request.weapon;
}
}

View File

@ -0,0 +1,118 @@
import { inject, injectable } from "tsyringe";
import { BotHelper } from "@spt/helpers/BotHelper";
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { BotEquipmentFilterService } from "@spt/services/BotEquipmentFilterService";
import { DatabaseService } from "@spt/services/DatabaseService";
import { ItemFilterService } from "@spt/services/ItemFilterService";
import { HashUtil } from "@spt/utils/HashUtil";
import { RandomUtil } from "@spt/utils/RandomUtil";
import { ICloner } from "@spt/utils/cloners/ICloner";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { APBSTierGetter } from "../Utils/APBSTierGetter";
import { BotGenerator } from "@spt/generators/BotGenerator";
import { BotInventoryGenerator } from "@spt/generators/BotInventoryGenerator";
import { BotLevelGenerator } from "@spt/generators/BotLevelGenerator";
import { SeasonalEventService } from "@spt/services/SeasonalEventService";
import { TimeUtil } from "@spt/utils/TimeUtil";
import { IBotBase } from "@spt/models/eft/common/tables/IBotBase";
import { IAppearance } from "@spt/models/eft/common/tables/IBotType";
import { IBotGenerationDetails } from "@spt/models/spt/bots/BotGenerationDetails";
import { IWildBody } from "@spt/models/eft/common/IGlobals";
import { BotNameService } from "@spt/services/BotNameService";
import { BotGeneratorHelper } from "@spt/helpers/BotGeneratorHelper";
import { ModConfig } from "../Globals/ModConfig";
/** Handle profile related client events */
@injectable()
export class APBSBotGenerator extends BotGenerator
{
constructor(
@inject("PrimaryLogger") protected logger: ILogger,
@inject("HashUtil") protected hashUtil: HashUtil,
@inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("TimeUtil") protected timeUtil: TimeUtil,
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
@inject("DatabaseService") protected databaseService: DatabaseService,
@inject("BotInventoryGenerator") protected botInventoryGenerator: BotInventoryGenerator,
@inject("BotLevelGenerator") protected botLevelGenerator: BotLevelGenerator,
@inject("BotEquipmentFilterService") protected botEquipmentFilterService: BotEquipmentFilterService,
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
@inject("BotHelper") protected botHelper: BotHelper,
@inject("BotGeneratorHelper") protected botGeneratorHelper: BotGeneratorHelper,
@inject("SeasonalEventService") protected seasonalEventService: SeasonalEventService,
@inject("ItemFilterService") protected itemFilterService: ItemFilterService,
@inject("BotNameService") protected botNameService: BotNameService,
@inject("ConfigServer") protected configServer: ConfigServer,
@inject("PrimaryCloner") protected cloner: ICloner,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("APBSTierGetter") protected apbsTierGetter: APBSTierGetter
)
{
super(logger,
hashUtil,
randomUtil,
timeUtil,
profileHelper,
databaseService,
botInventoryGenerator,
botLevelGenerator,
botEquipmentFilterService,
weightedRandomHelper,
botHelper,
botGeneratorHelper,
seasonalEventService,
itemFilterService,
botNameService,
configServer,
cloner)
}
protected override setBotAppearance(bot: IBotBase, appearance: IAppearance, botGenerationDetails: IBotGenerationDetails): void
{
if (botGenerationDetails.isPmc)
{
const tier = this.apbsTierGetter.getTierByLevel(bot.Info.Level)
const role = bot.Info.Settings.Role
const getSeasonalAppearance = ModConfig.config.seasonalPmcAppearance ? true : false;
const appearanceJson = this.apbsEquipmentGetter.getPmcAppearance(role, tier, getSeasonalAppearance);
bot.Customization.Head = this.weightedRandomHelper.getWeightedValue<string>(appearanceJson.head);
bot.Customization.Hands = this.weightedRandomHelper.getWeightedValue<string>(appearanceJson.hands);
bot.Customization.Body = this.weightedRandomHelper.getWeightedValue<string>(appearanceJson.body);
bot.Customization.Feet = this.weightedRandomHelper.getWeightedValue<string>(appearanceJson.feet);
const bodyGlobalDict = this.databaseService.getGlobals().config.Customization.SavageBody;
const chosenBodyTemplate = this.databaseService.getCustomization()[bot.Customization.Body];
// Find the body/hands mapping
const matchingBody: IWildBody = bodyGlobalDict[chosenBodyTemplate?._name];
if (matchingBody?.isNotRandom)
{
// Has fixed hands for this body, set them
bot.Customization.Hands = matchingBody.hands;
}
return;
}
bot.Customization.Head = this.weightedRandomHelper.getWeightedValue<string>(appearance.head);
bot.Customization.Body = this.weightedRandomHelper.getWeightedValue<string>(appearance.body);
bot.Customization.Feet = this.weightedRandomHelper.getWeightedValue<string>(appearance.feet);
bot.Customization.Hands = this.weightedRandomHelper.getWeightedValue<string>(appearance.hands);
const bodyGlobalDict = this.databaseService.getGlobals().config.Customization.SavageBody;
const chosenBodyTemplate = this.databaseService.getCustomization()[bot.Customization.Body];
// Find the body/hands mapping
const matchingBody: IWildBody = bodyGlobalDict[chosenBodyTemplate?._name];
if (matchingBody?.isNotRandom)
{
// Has fixed hands for this body, set them
bot.Customization.Hands = matchingBody.hands;
}
}
}

View File

@ -0,0 +1,433 @@
import { inject, injectable } from "tsyringe";
import { BotEquipmentModGenerator } from "@spt/generators/BotEquipmentModGenerator";
import { BotLootGenerator } from "@spt/generators/BotLootGenerator";
import { BotWeaponGenerator } from "@spt/generators/BotWeaponGenerator";
import { BotGeneratorHelper } from "@spt/helpers/BotGeneratorHelper";
import { BotHelper } from "@spt/helpers/BotHelper";
import { ItemHelper } from "@spt/helpers/ItemHelper";
import { ContextVariableType } from "@spt/context/ContextVariableType";
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
import { IInventory as PmcInventory } from "@spt/models/eft/common/tables/IBotBase";
import { IChances, IGeneration, IBotType, IInventory } from "@spt/models/eft/common/tables/IBotType";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import { EquipmentSlots } from "@spt/models/enums/EquipmentSlots";
import { IGenerateEquipmentProperties } from "@spt/models/spt/bots/IGenerateEquipmentProperties";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { BotEquipmentModPoolService } from "@spt/services/BotEquipmentModPoolService";
import { DatabaseService } from "@spt/services/DatabaseService";
import { LocalisationService } from "@spt/services/LocalisationService";
import { HashUtil } from "@spt/utils/HashUtil";
import { RandomUtil } from "@spt/utils/RandomUtil";
import { BotInventoryGenerator } from "@spt/generators/BotInventoryGenerator";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { APBSTierGetter } from "../Utils/APBSTierGetter";
import { ModConfig } from "../Globals/ModConfig";
import { APBSBotWeaponGenerator } from "../ClassExtensions/APBSBotWeaponGenerator";
import { ApplicationContext } from "@spt/context/ApplicationContext";
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
import { WeatherHelper } from "@spt/helpers/WeatherHelper";
import { BotEquipmentFilterService } from "@spt/services/BotEquipmentFilterService";
import { IGetRaidConfigurationRequestData } from "@spt/models/eft/match/IGetRaidConfigurationRequestData";
/** Handle profile related client events */
@injectable()
export class APBSBotInventoryGenerator extends BotInventoryGenerator
{
constructor(
@inject("PrimaryLogger") protected logger: ILogger,
@inject("HashUtil") protected hashUtil: HashUtil,
@inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("DatabaseService") protected databaseService: DatabaseService,
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
@inject("BotWeaponGenerator") protected botWeaponGenerator: BotWeaponGenerator,
@inject("BotLootGenerator") protected botLootGenerator: BotLootGenerator,
@inject("BotGeneratorHelper") protected botGeneratorHelper: BotGeneratorHelper,
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
@inject("BotHelper") protected botHelper: BotHelper,
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
@inject("ItemHelper") protected itemHelper: ItemHelper,
@inject("WeatherHelper") protected weatherHelper: WeatherHelper,
@inject("LocalisationService") protected localisationService: LocalisationService,
@inject("BotEquipmentFilterService") protected botEquipmentFilterService: BotEquipmentFilterService,
@inject("BotEquipmentModPoolService") protected botEquipmentModPoolService: BotEquipmentModPoolService,
@inject("BotEquipmentModGenerator") protected botEquipmentModGenerator: BotEquipmentModGenerator,
@inject("ConfigServer") protected configServer: ConfigServer,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("APBSTierGetter") protected apbsTierGetter: APBSTierGetter,
@inject("APBSBotWeaponGenerator") protected apbsBotWeaponGenerator: APBSBotWeaponGenerator
)
{
super(logger,
hashUtil,
randomUtil,
databaseService,
applicationContext,
botWeaponGenerator,
botLootGenerator,
botGeneratorHelper,
profileHelper,
botHelper,
weightedRandomHelper,
itemHelper,
weatherHelper,
localisationService,
botEquipmentFilterService,
botEquipmentModPoolService,
botEquipmentModGenerator,
configServer)
}
public override generateInventory(
sessionId: string,
botJsonTemplate: IBotType,
botRole: string,
isPmc: boolean,
botLevel: number,
chosenGameVersion: string
): PmcInventory
{
const templateInventory = botJsonTemplate.inventory;
let wornItemChances = botJsonTemplate.chances;
const itemGenerationLimitsMinMax = botJsonTemplate.generation;
// Generate base inventory with no items
const botInventory = this.generateInventoryBase();
const raidConfig = this.applicationContext
.getLatestValue(ContextVariableType.RAID_CONFIGURATION)
?.getValue<IGetRaidConfigurationRequestData>();
this.generateAndAddEquipmentToBot(
sessionId,
templateInventory,
wornItemChances,
botRole,
botInventory,
botLevel,
chosenGameVersion,
raidConfig
);
// Roll weapon spawns (primary/secondary/holster) and generate a weapon for each roll that passed
if (((botRole.includes("boss") || botRole.includes("sectant") || botRole.includes("arena")) && ModConfig.config.disableBossTierGeneration) || botRole == "bosslegion" || botRole == "bosspunisher")
{
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
}
if (botRole.includes("follower") && ModConfig.config.disableBossFollowerTierGeneration)
{
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
}
if ((botRole.includes("exusec") || botRole.includes("pmcbot")) && !ModConfig.config.disableRaiderRogueTierGeneration)
{
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
}
if (botRole.includes("pmc") && ModConfig.config.disablePMCTierGeneration)
{
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
}
if ((botRole.includes("assault") || botRole.includes("marksman")) && ModConfig.config.disableScavTierGeneration)
{
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
}
if (botRole.includes("infected") || botRole.includes("spirit") || botRole.includes("skier") || botRole.includes("peacemaker") || botRole.includes("gifter"))
{
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
}
// APBS generation chances instead
const tierInfo = this.apbsTierGetter.getTierByLevel(botLevel);
wornItemChances = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tierInfo);
this.generateAndAddWeaponsToBot(templateInventory, wornItemChances, sessionId, botInventory, botRole, isPmc, itemGenerationLimitsMinMax, botLevel);
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
return botInventory;
}
protected override generateEquipment = (settings: IGenerateEquipmentProperties): boolean =>
{
const equipmentSlot = settings.rootEquipmentSlot as string;
const botRole = settings.botData.role;
const botLevel = settings.botData.level;
const tierInfo = this.apbsTierGetter.getTierByLevel(botLevel);
let equipmentPool = this.apbsEquipmentGetter.getEquipmentByBotRole(botRole, tierInfo, equipmentSlot);
let randomisationDetails = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tierInfo);
let wornItemChances = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tierInfo);
let modPool = this.apbsEquipmentGetter.getModsByBotRole(botRole, tierInfo);
let apbsBot = true;
if ((ModConfig.config.disableBossTierGeneration && (botRole.includes("boss") || botRole.includes("sectant") || botRole.includes("arena"))) || botRole == "bosslegion" || botRole == "bosspunisher")
{
equipmentPool = settings.rootEquipmentPool;
randomisationDetails = settings.randomisationDetails;
wornItemChances = settings.spawnChances;
modPool = settings.modPool;
apbsBot = false;
}
if (ModConfig.config.disableBossFollowerTierGeneration && botRole.includes("follower"))
{
equipmentPool = settings.rootEquipmentPool;
randomisationDetails = settings.randomisationDetails;
wornItemChances = settings.spawnChances;
modPool = settings.modPool;
apbsBot = false;
}
if (ModConfig.config.disableRaiderRogueTierGeneration && (botRole.includes("exusec") || botRole.includes("pmcbot")))
{
equipmentPool = settings.rootEquipmentPool;
randomisationDetails = settings.randomisationDetails;
wornItemChances = settings.spawnChances;
modPool = settings.modPool;
apbsBot = false;
}
if (ModConfig.config.disablePMCTierGeneration && (botRole.includes("pmcusec") || botRole.includes("pmcbear")))
{
equipmentPool = settings.rootEquipmentPool;
randomisationDetails = settings.randomisationDetails;
wornItemChances = settings.spawnChances;
modPool = settings.modPool;
apbsBot = false;
}
if (ModConfig.config.disableScavTierGeneration && (botRole.includes("assault") || botRole.includes("marksman")))
{
equipmentPool = settings.rootEquipmentPool;
randomisationDetails = settings.randomisationDetails;
wornItemChances = settings.spawnChances;
modPool = settings.modPool;
apbsBot = false;
}
if (botRole.includes("infected") || botRole.includes("spirit") || botRole.includes("skier") || botRole.includes("peacemaker") || botRole.includes("gifter"))
{
equipmentPool = settings.rootEquipmentPool;
randomisationDetails = settings.randomisationDetails;
wornItemChances = settings.spawnChances;
modPool = settings.modPool;
apbsBot = false;
}
if (apbsBot && equipmentSlot == EquipmentSlots.TACTICAL_VEST && !settings.inventory.items.find(e => e.slotId === "ArmorVest"))
{
equipmentPool = this.apbsEquipmentGetter.getEquipmentByBotRole(botRole, tierInfo, "ArmouredRig");
}
if (equipmentSlot == EquipmentSlots.POCKETS && Object.keys(settings.rootEquipmentPool).includes("65e080be269cbd5c5005e529"))
{
equipmentPool = settings.rootEquipmentPool;
}
const spawnChance = ([EquipmentSlots.POCKETS, EquipmentSlots.SECURED_CONTAINER] as string[]).includes(
settings.rootEquipmentSlot
)
? 100
: wornItemChances.equipment[settings.rootEquipmentSlot];
if (typeof spawnChance === "undefined")
{
this.logger.warning(
this.localisationService.getText(
"bot-no_spawn_chance_defined_for_equipment_slot",
settings.rootEquipmentSlot
)
);
return false;
}
const shouldSpawn = this.randomUtil.getChance100(spawnChance);
if (shouldSpawn && Object.keys(equipmentPool).length)
{
let pickedItemDb: ITemplateItem;
let found = false;
const maxAttempts = Math.round(Object.keys(equipmentPool).length * 0.75); // Roughly 75% of pool size
let attempts = 0;
while (!found)
{
if (Object.values(equipmentPool).length === 0)
{
return false;
}
const chosenItemTpl = this.weightedRandomHelper.getWeightedValue<string>(equipmentPool);
const dbResult = this.itemHelper.getItem(chosenItemTpl);
if (!dbResult[0])
{
this.logger.error(this.localisationService.getText("bot-missing_item_template", chosenItemTpl));
this.logger.info(`EquipmentSlot -> ${settings.rootEquipmentSlot}`);
attempts++;
continue;
}
const compatabilityResult = this.botGeneratorHelper.isItemIncompatibleWithCurrentItems(
settings.inventory.items,
chosenItemTpl,
settings.rootEquipmentSlot
);
if (compatabilityResult.incompatible)
{
// Tried x different items that failed, stop
if (attempts > maxAttempts)
{
return false;
}
attempts++;
}
else
{
// Success
found = true;
pickedItemDb = dbResult[1];
}
}
// Create root item
const id = this.hashUtil.generate();
const item = {
_id: id,
_tpl: pickedItemDb._id,
parentId: settings.inventory.equipment,
slotId: settings.rootEquipmentSlot,
...this.botGeneratorHelper.generateExtraPropertiesForItem(pickedItemDb, settings.botData.role)
};
const botEquipBlacklist = this.botEquipmentFilterService.getBotEquipmentBlacklist(
settings.botData.equipmentRole,
settings.generatingPlayerLevel
);
// Edge case: Filter the armor items mod pool if bot exists in config dict + config has armor slot
if (
this.botConfig.equipment[settings.botData.equipmentRole] &&
randomisationDetails?.randomisedArmorSlots?.includes(settings.rootEquipmentSlot)
)
{
// Filter out mods from relevant blacklist
modPool[pickedItemDb._id] = this.getFilteredDynamicModsForItem(
pickedItemDb._id,
botEquipBlacklist.equipment
);
}
// Does item have slots for sub-mods to be inserted into
if (pickedItemDb._props.Slots?.length > 0 && !settings.generateModsBlacklist?.includes(pickedItemDb._id))
{
const childItemsToAdd = this.botEquipmentModGenerator.generateModsForEquipment(
[item],
id,
pickedItemDb,
settings,
botEquipBlacklist
);
settings.inventory.items.push(...childItemsToAdd);
}
else
{
// No slots, add root item only
settings.inventory.items.push(item);
}
return true;
}
return false;
}
protected override generateAndAddWeaponsToBot(
templateInventory: IInventory,
equipmentChances: IChances,
sessionId: string,
botInventory: PmcInventory,
botRole: string,
isPmc: boolean,
itemGenerationLimitsMinMax: IGeneration,
botLevel: number
): void
{
const weaponSlotsToFill = this.getDesiredWeaponsForBot(equipmentChances);
let hasBothPrimary = false;
if (weaponSlotsToFill[0].shouldSpawn && weaponSlotsToFill[1].shouldSpawn)
{
hasBothPrimary = true;
}
for (const weaponSlot of weaponSlotsToFill)
{
// Add weapon to bot if true and bot json has something to put into the slot
if (weaponSlot.shouldSpawn && Object.keys(templateInventory.equipment[weaponSlot.slot]).length)
{
this.apbsAddWeaponAndMagazinesToInventory(
sessionId,
weaponSlot,
templateInventory,
botInventory,
equipmentChances,
botRole,
isPmc,
itemGenerationLimitsMinMax,
botLevel,
hasBothPrimary
);
}
}
}
private apbsAddWeaponAndMagazinesToInventory(
sessionId: string,
weaponSlot: { slot: EquipmentSlots; shouldSpawn: boolean },
templateInventory: IInventory,
botInventory: PmcInventory,
equipmentChances: IChances,
botRole: string,
isPmc: boolean,
itemGenerationWeights: IGeneration,
botLevel: number,
hasBothPrimary: boolean
): void
{
const generatedWeapon = this.apbsBotWeaponGenerator.apbsGenerateRandomWeapon(
sessionId,
weaponSlot.slot,
templateInventory,
botInventory.equipment,
equipmentChances.weaponMods,
botRole,
isPmc,
botLevel,
hasBothPrimary
);
botInventory.items.push(...generatedWeapon.weapon);
this.botWeaponGenerator.addExtraMagazinesToInventory(
generatedWeapon,
itemGenerationWeights.items.magazines,
botInventory,
botRole
);
}
}

View File

@ -0,0 +1,332 @@
import { inject, injectable } from "tsyringe";
import { BotWeaponGenerator } from "@spt/generators/BotWeaponGenerator";
import { BotGeneratorHelper } from "@spt/helpers/BotGeneratorHelper";
import { BotHelper } from "@spt/helpers/BotHelper";
import { HandbookHelper } from "@spt/helpers/HandbookHelper";
import { InventoryHelper } from "@spt/helpers/InventoryHelper";
import { ItemHelper } from "@spt/helpers/ItemHelper";
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
import { IInventory as PmcInventory } from "@spt/models/eft/common/tables/IBotBase";
import { IGenerationWeightingItems, IBotType } from "@spt/models/eft/common/tables/IBotType";
import { EquipmentSlots } from "@spt/models/enums/EquipmentSlots";
import { LootCacheType } from "@spt/models/spt/bots/IBotLootCache";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { BotLootCacheService } from "@spt/services/BotLootCacheService";
import { DatabaseService } from "@spt/services/DatabaseService";
import { LocalisationService } from "@spt/services/LocalisationService";
import { ICloner } from "@spt/utils/cloners/ICloner";
import { HashUtil } from "@spt/utils/HashUtil";
import { RandomUtil } from "@spt/utils/RandomUtil";
import { BotLootGenerator } from "@spt/generators/BotLootGenerator";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { APBSTierGetter } from "../Utils/APBSTierGetter";
/** Handle profile related client events */
@injectable()
export class APBSBotLootGenerator extends BotLootGenerator
{
constructor(
@inject("PrimaryLogger") protected logger: ILogger,
@inject("HashUtil") protected hashUtil: HashUtil,
@inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("ItemHelper") protected itemHelper: ItemHelper,
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
@inject("DatabaseService") protected databaseService: DatabaseService,
@inject("HandbookHelper") protected handbookHelper: HandbookHelper,
@inject("BotGeneratorHelper") protected botGeneratorHelper: BotGeneratorHelper,
@inject("BotWeaponGenerator") protected botWeaponGenerator: BotWeaponGenerator,
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
@inject("BotHelper") protected botHelper: BotHelper,
@inject("BotLootCacheService") protected botLootCacheService: BotLootCacheService,
@inject("LocalisationService") protected localisationService: LocalisationService,
@inject("ConfigServer") protected configServer: ConfigServer,
@inject("PrimaryCloner") protected cloner: ICloner,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("APBSTierGetter") protected apbsTierGetter: APBSTierGetter
)
{
super(logger,
hashUtil,
randomUtil,
itemHelper,
inventoryHelper,
databaseService,
handbookHelper,
botGeneratorHelper,
botWeaponGenerator,
weightedRandomHelper,
botHelper,
botLootCacheService,
localisationService,
configServer,
cloner)
}
public override generateLoot(
sessionId: string,
botJsonTemplate: IBotType,
isPmc: boolean,
botRole: string,
botInventory: PmcInventory,
botLevel: number
): void
{// Limits on item types to be added as loot
const tierInfo = this.apbsTierGetter.getTierByLevel(botLevel);
const chances = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tierInfo);
const itemCounts: IGenerationWeightingItems = chances.generation.items;
if (
!itemCounts.backpackLoot.weights
|| !itemCounts.pocketLoot.weights
|| !itemCounts.vestLoot.weights
|| !itemCounts.specialItems.weights
|| !itemCounts.healing.weights
|| !itemCounts.drugs.weights
|| !itemCounts.food.weights
|| !itemCounts.drink.weights
|| !itemCounts.currency.weights
|| !itemCounts.stims.weights
|| !itemCounts.grenades.weights
)
{
this.logger.warning(this.localisationService.getText("bot-unable_to_generate_bot_loot", botRole));
return;
}
let backpackLootCount = Number(
this.weightedRandomHelper.getWeightedValue<number>(itemCounts.backpackLoot.weights)
);
let pocketLootCount = Number(
this.weightedRandomHelper.getWeightedValue<number>(itemCounts.pocketLoot.weights)
);
let vestLootCount = this.weightedRandomHelper.getWeightedValue<number>(itemCounts.vestLoot.weights);
const specialLootItemCount = Number(
this.weightedRandomHelper.getWeightedValue<number>(itemCounts.specialItems.weights)
);
const healingItemCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.healing.weights));
const drugItemCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.drugs.weights));
const foodItemCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.food.weights));
const drinkItemCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.drink.weights));
let currencyItemCount = Number(
this.weightedRandomHelper.getWeightedValue<number>(itemCounts.currency.weights)
);
const stimItemCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.stims.weights));
const grenadeCount = Number(this.weightedRandomHelper.getWeightedValue<number>(itemCounts.grenades.weights));
// If bot has been flagged as not having loot, set below counts to 0
if (this.botConfig.disableLootOnBotTypes?.includes(botRole.toLowerCase()))
{
backpackLootCount = 0;
pocketLootCount = 0;
vestLootCount = 0;
currencyItemCount = 0;
}
// Forced pmc healing loot into secure container
if (isPmc && this.pmcConfig.forceHealingItemsIntoSecure)
{
this.addForcedMedicalItemsToPmcSecure(botInventory, botRole);
}
const botItemLimits = this.getItemSpawnLimitsForBot(botRole);
const containersBotHasAvailable = this.getAvailableContainersBotCanStoreItemsIn(botInventory);
// This set is passed as a reference to fill up the containers that are already full, this aliviates
// generation of the bots by avoiding checking the slots of containers we already know are full
const containersIdFull = new Set<string>();
// Special items
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.SPECIAL, botJsonTemplate),
containersBotHasAvailable,
specialLootItemCount,
botInventory,
botRole,
botItemLimits,
undefined,
undefined,
containersIdFull
);
// Healing items / Meds
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.HEALING_ITEMS, botJsonTemplate),
containersBotHasAvailable,
healingItemCount,
botInventory,
botRole,
undefined,
0,
isPmc,
containersIdFull
);
// Drugs
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.DRUG_ITEMS, botJsonTemplate),
containersBotHasAvailable,
drugItemCount,
botInventory,
botRole,
undefined,
0,
isPmc,
containersIdFull
);
// Food
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.FOOD_ITEMS, botJsonTemplate),
containersBotHasAvailable,
foodItemCount,
botInventory,
botRole,
undefined,
0,
isPmc,
containersIdFull
);
// Drink
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.DRINK_ITEMS, botJsonTemplate),
containersBotHasAvailable,
drinkItemCount,
botInventory,
botRole,
undefined,
0,
isPmc,
containersIdFull
);
// Currency
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.CURRENCY_ITEMS, botJsonTemplate),
containersBotHasAvailable,
currencyItemCount,
botInventory,
botRole,
undefined,
0,
isPmc,
containersIdFull
);
// Stims
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.STIM_ITEMS, botJsonTemplate),
containersBotHasAvailable,
stimItemCount,
botInventory,
botRole,
botItemLimits,
0,
isPmc,
containersIdFull
);
// Grenades
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.GRENADE_ITEMS, botJsonTemplate),
[EquipmentSlots.POCKETS, EquipmentSlots.TACTICAL_VEST], // Can't use containersBotHasEquipped as we dont want grenades added to backpack
grenadeCount,
botInventory,
botRole,
undefined,
0,
isPmc,
containersIdFull
);
// Backpack - generate loot if they have one
if (containersBotHasAvailable.includes(EquipmentSlots.BACKPACK))
{
// Add randomly generated weapon to PMC backpacks
if (isPmc && this.randomUtil.getChance100(this.pmcConfig.looseWeaponInBackpackChancePercent))
{
this.addLooseWeaponsToInventorySlot(
sessionId,
botInventory,
EquipmentSlots.BACKPACK,
botJsonTemplate.inventory,
botJsonTemplate.chances.weaponMods,
botRole,
isPmc,
botLevel,
containersIdFull
);
}
const backpackLootRoubleTotal = this.getBackpackRoubleTotalByLevel(botLevel, isPmc);
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.BACKPACK, botJsonTemplate),
[EquipmentSlots.BACKPACK],
backpackLootCount,
botInventory,
botRole,
botItemLimits,
backpackLootRoubleTotal,
isPmc,
containersIdFull
);
}
// TacticalVest - generate loot if they have one
if (containersBotHasAvailable.includes(EquipmentSlots.TACTICAL_VEST))
{
// Vest
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.VEST, botJsonTemplate),
[EquipmentSlots.TACTICAL_VEST],
vestLootCount,
botInventory,
botRole,
botItemLimits,
this.pmcConfig.maxVestLootTotalRub,
isPmc,
containersIdFull
);
}
// Pockets
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.POCKET, botJsonTemplate),
[EquipmentSlots.POCKETS],
pocketLootCount,
botInventory,
botRole,
botItemLimits,
this.pmcConfig.maxPocketLootTotalRub,
isPmc,
containersIdFull
);
// Secure
// only add if not a pmc or is pmc and flag is true
if (!isPmc || (isPmc && this.pmcConfig.addSecureContainerLootFromBotConfig))
{
this.addLootFromPool(
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.SECURE, botJsonTemplate),
[EquipmentSlots.SECURED_CONTAINER],
50,
botInventory,
botRole,
undefined,
-1,
isPmc,
containersIdFull
);
}
}
}

View File

@ -0,0 +1,356 @@
import { inject, injectable, injectAll } from "tsyringe";
import { DatabaseService } from "@spt/services/DatabaseService";
import { RandomUtil } from "@spt/utils/RandomUtil";
import { APBSLogger } from "../Utils/APBSLogger";
import { BotWeaponGenerator } from "@spt/generators/BotWeaponGenerator";
import { IInventory, IModsChances } from "@spt/models/eft/common/tables/IBotType";
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
import { APBSTierGetter } from "../Utils/APBSTierGetter";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { ItemHelper } from "@spt/helpers/ItemHelper";
import { LocalisationService } from "@spt/services/LocalisationService";
import { IGenerateWeaponRequest } from "@spt/models/spt/bots/IGenerateWeaponRequest";
import { IGenerateWeaponResult } from "@spt/models/spt/bots/IGenerateWeaponResult";
import { HashUtil } from "@spt/utils/HashUtil";
import { ICloner } from "@spt/utils/cloners/ICloner";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { IInventoryMagGen } from "@spt/generators/weapongen/IInventoryMagGen";
import { RepairService } from "@spt/services/RepairService";
import { BotWeaponModLimitService } from "@spt/services/BotWeaponModLimitService";
import { BotGeneratorHelper } from "@spt/helpers/BotGeneratorHelper";
import { BotEquipmentModGenerator } from "@spt/generators/BotEquipmentModGenerator";
import { BotWeaponGeneratorHelper } from "@spt/helpers/BotWeaponGeneratorHelper";
import { RaidInformation } from "../Globals/RaidInformation";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { ModConfig } from "../Globals/ModConfig";
import { Logging } from "../Enums/Logging";
import { APBSTester } from "../Utils/APBSTester";
import { ModInformation } from "../Globals/ModInformation";
import { Money } from "@spt/models/enums/Money";
import { APBSBotEquipmentModGenerator } from "./APBSBotEquipmentModGenerator";
/** Handle profile related client events */
@injectable()
export class APBSBotWeaponGenerator extends BotWeaponGenerator
{
constructor(
@inject("PrimaryLogger") protected logger: ILogger,
@inject("HashUtil") protected hashUtil: HashUtil,
@inject("DatabaseService") protected databaseService: DatabaseService,
@inject("ItemHelper") protected itemHelper: ItemHelper,
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
@inject("BotGeneratorHelper") protected botGeneratorHelper: BotGeneratorHelper,
@inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("ConfigServer") protected configServer: ConfigServer,
@inject("BotWeaponGeneratorHelper") protected botWeaponGeneratorHelper: BotWeaponGeneratorHelper,
@inject("BotWeaponModLimitService") protected botWeaponModLimitService: BotWeaponModLimitService,
@inject("BotEquipmentModGenerator") protected botEquipmentModGenerator: BotEquipmentModGenerator,
@inject("LocalisationService") protected localisationService: LocalisationService,
@inject("RepairService") protected repairService: RepairService,
@injectAll("InventoryMagGen") protected inventoryMagGenComponents: IInventoryMagGen[],
@inject("PrimaryCloner") protected cloner: ICloner,
@inject("APBSLogger") protected apbsLogger: APBSLogger,
@inject("APBSTierGetter") protected apbsTierGetter: APBSTierGetter,
@inject("RaidInformation") protected raidInformation: RaidInformation,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("APBSTester") protected apbsTester: APBSTester,
@inject("APBSBotEquipmentModGenerator") protected apbsBotEquipmentModGenerator: APBSBotEquipmentModGenerator,
@inject("ModInformation") protected modInformation: ModInformation
)
{
super(logger,
hashUtil,
databaseService,
itemHelper,
weightedRandomHelper,
botGeneratorHelper,
randomUtil,
configServer,
botWeaponGeneratorHelper,
botWeaponModLimitService,
botEquipmentModGenerator,
localisationService,
repairService,
inventoryMagGenComponents,
cloner)
}
public apbsGenerateRandomWeapon(sessionId: string, equipmentSlot: string, botTemplateInventory: IInventory, weaponParentId: string, modChances: IModsChances, botRole: string, isPmc: boolean, botLevel: number, hasBothPrimary: boolean): IGenerateWeaponResult
{
// If the profile was just created, then use vanilla weapon gen
if (this.raidInformation.freshProfile)
{
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
// Config disable checks to flip to default weapon gen
if ((ModConfig.config.disableBossTierGeneration && (botRole.includes("boss") || botRole.includes("sectant") || botRole.includes("arena"))) || botRole == "bosslegion" || botRole == "bosspunisher")
{
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
if (ModConfig.config.disableBossFollowerTierGeneration && botRole.includes("follower"))
{
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
if (ModConfig.config.disableRaiderRogueTierGeneration && (botRole.includes("exusec") || botRole.includes("pmcbot")))
{
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
if (ModConfig.config.disablePMCTierGeneration && (botRole.includes("pmcusec") || botRole.includes("pmcbear")))
{
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
if (ModConfig.config.disableScavTierGeneration && (botRole.includes("assault") || botRole.includes("marksman")))
{
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
if (botRole.includes("infected") || botRole.includes("spirit") || botRole.includes("skier") || botRole.includes("peacemaker") || botRole.includes("gifter"))
{
const weaponTpl = this.pickWeightedWeaponTplFromPool(equipmentSlot, botTemplateInventory);
return this.generateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel);
}
// If not disabled via config, all bots follow this custom generation
const tierInfo = this.apbsTierGetter.getTierByLevel(botLevel);
const weaponTpl =
(hasBothPrimary && isPmc)
? this.apbsPickWeightedWeaponTplFromPoolHasBothPrimary(equipmentSlot, botLevel, botRole, tierInfo)
: this.apbsPickWeightedWeaponTplFromPool(equipmentSlot, botLevel, botRole, tierInfo)
return this.apbsGenerateWeaponByTpl(sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel, tierInfo)
}
private apbsPickWeightedWeaponTplFromPoolHasBothPrimary(equipmentSlot: string, botLevel: number, botRole: string, tierInfo: number): string
{
let rangeType = "ShortRange";
if (equipmentSlot == "FirstPrimaryWeapon")
{
if (this.raidInformation.location == "Woods") rangeType = "LongRange";
const weaponPool = this.apbsEquipmentGetter.getEquipmentByBotRole(botRole, tierInfo, equipmentSlot, rangeType);
return this.weightedRandomHelper.getWeightedValue<string>(weaponPool);
}
if (equipmentSlot == "SecondPrimaryWeapon")
{
if (this.raidInformation.location != "Woods") rangeType = "LongRange";
const weaponPool = this.apbsEquipmentGetter.getEquipmentByBotRole(botRole, tierInfo, equipmentSlot, rangeType);
return this.weightedRandomHelper.getWeightedValue<string>(weaponPool);
}
const weaponPool = this.apbsEquipmentGetter.getEquipmentByBotRole(botRole, tierInfo, equipmentSlot);
return this.weightedRandomHelper.getWeightedValue<string>(weaponPool);
}
private apbsPickWeightedWeaponTplFromPool(equipmentSlot: string, botLevel: number, botRole: string, tierInfo: number): string
{
if (equipmentSlot == "FirstPrimaryWeapon" || equipmentSlot == "SecondPrimaryWeapon")
{
const rangeType = this.weightedRandomHelper.getWeightedValue<string>(this.raidInformation.mapWeights[this.raidInformation.location]);
const weaponPool = this.apbsEquipmentGetter.getEquipmentByBotRole(botRole, tierInfo, equipmentSlot, rangeType);
return this.weightedRandomHelper.getWeightedValue<string>(weaponPool);
}
const weaponPool = this.apbsEquipmentGetter.getEquipmentByBotRole(botRole, tierInfo, equipmentSlot);
return this.weightedRandomHelper.getWeightedValue<string>(weaponPool);
}
private apbsGenerateWeaponByTpl(
sessionId: string,
weaponTpl: string,
equipmentSlot: string,
botTemplateInventory: IInventory,
weaponParentId: string,
modChances: IModsChances,
botRole: string,
isPmc: boolean,
botLevel: number,
tierInfo: number
): IGenerateWeaponResult
{
const modPool = this.apbsEquipmentGetter.getModsByBotRole(botRole, tierInfo);
const apbsModChances = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tierInfo);
let weaponChances = apbsModChances.weaponMods;
const weaponItemTemplate = this.itemHelper.getItem(weaponTpl)[1];
if (ModConfig.config.enablePerWeaponTypeAttachmentChances)
{
switch (weaponItemTemplate._parent)
{
case "5447b5fc4bdc2d87278b4567":
weaponChances = apbsModChances.assaultCarbine;
break;
case "5447b6254bdc2dc3278b4568":
weaponChances = apbsModChances.sniperRifle;
break;
case "5447b6194bdc2d67278b4567":
weaponChances = apbsModChances.marksmanRifle;
break;
case "5447b5f14bdc2d61278b4567":
weaponChances = apbsModChances.assaultRifle;
break;
case "5447bed64bdc2d97278b4568":
weaponChances = apbsModChances.machinegun;
break;
case "5447b5e04bdc2d62278b4567":
weaponChances = apbsModChances.smg;
break;
case "5447b5cf4bdc2d65278b4567":
weaponChances = apbsModChances.handgun;
break;
case "617f1ef5e8b54b0998387733":
weaponChances = apbsModChances.revolver;
break;
case "5447b6094bdc2dc3278b4567":
weaponChances = apbsModChances.shotgun;
break;
case "5447bedf4bdc2d87278b4568":
weaponChances = apbsModChances.weaponMods;
break;
default:
weaponChances = apbsModChances.weaponMods;
this.apbsLogger.log(Logging.WARN, `ItemTemplate._parent is missing classification - Report to acidphantasm - ${weaponItemTemplate._parent}`)
break;
}
}
if (!weaponItemTemplate)
{
this.logger.error(this.localisationService.getText("bot-missing_item_template", weaponTpl));
this.logger.error(`WeaponSlot -> ${equipmentSlot}`);
return;
}
// Find ammo to use when filling magazines/chamber
if (!botTemplateInventory.Ammo)
{
this.logger.error(this.localisationService.getText("bot-no_ammo_found_in_bot_json", botRole));
throw new Error(this.localisationService.getText("bot-generation_failed"));
}
const ammoTable = this.apbsEquipmentGetter.getAmmoByBotRole(botRole, tierInfo)
const ammoTpl = this.getWeightedCompatibleAmmo(ammoTable, weaponItemTemplate);
// Create with just base weapon item
let weaponWithModsArray = this.constructWeaponBaseArray(
weaponTpl,
weaponParentId,
equipmentSlot,
weaponItemTemplate,
botRole
);
// Chance to add randomised weapon enhancement
if (isPmc && this.randomUtil.getChance100(this.pmcConfig.weaponHasEnhancementChancePercent))
{
const weaponConfig = this.repairConfig.repairKit.weapon;
this.repairService.addBuff(weaponConfig, weaponWithModsArray[0]);
}
// Add mods to weapon base
if (Object.keys(modPool).includes(weaponTpl))
{
const botEquipmentRole = this.botGeneratorHelper.getBotEquipmentRole(botRole);
const modLimits = this.botWeaponModLimitService.getWeaponModLimits(botEquipmentRole);
const generateWeaponModsRequest: IGenerateWeaponRequest = {
weapon: weaponWithModsArray, // Will become hydrated array of weapon + mods
modPool: modPool,
weaponId: weaponWithModsArray[0]._id, // Weapon root id
parentTemplate: weaponItemTemplate,
modSpawnChances: weaponChances,
ammoTpl: ammoTpl,
botData: { role: botRole, level: botLevel, equipmentRole: botEquipmentRole },
modLimits: modLimits,
weaponStats: {},
conflictingItemTpls: new Set()
};
weaponWithModsArray = this.apbsBotEquipmentModGenerator.apbsGenerateModsForWeapon(
sessionId,
generateWeaponModsRequest,
isPmc
);
}
// Use weapon preset from globals.json if weapon isnt valid
if (!this.isWeaponValid(weaponWithModsArray, botRole))
{
// Weapon is bad, fall back to weapons preset
weaponWithModsArray = this.getPresetWeaponMods(
weaponTpl,
equipmentSlot,
weaponParentId,
weaponItemTemplate,
botRole
);
}
// Fill existing magazines to full and sync ammo type
for (const magazine of weaponWithModsArray.filter((item) => item.slotId === this.modMagazineSlotId))
{
this.fillExistingMagazines(weaponWithModsArray, magazine, ammoTpl);
}
// Add cartridge(s) to gun chamber(s)
if (
weaponItemTemplate._props.Chambers?.length > 0
&& weaponItemTemplate._props.Chambers[0]?._props?.filters[0]?.Filter?.includes(ammoTpl)
)
{
// Guns have variety of possible Chamber ids, patron_in_weapon/patron_in_weapon_000/patron_in_weapon_001
const chamberSlotNames = weaponItemTemplate._props.Chambers.map((x) => x._name);
this.addCartridgeToChamber(weaponWithModsArray, ammoTpl, chamberSlotNames);
}
// Fill UBGL if found
const ubglMod = weaponWithModsArray.find((x) => x.slotId === "mod_launcher");
let ubglAmmoTpl: string = undefined;
if (ubglMod)
{
const ubglTemplate = this.itemHelper.getItem(ubglMod._tpl)[1];
ubglAmmoTpl = this.getWeightedCompatibleAmmo(botTemplateInventory.Ammo, ubglTemplate);
this.fillUbgl(weaponWithModsArray, ubglMod, ubglAmmoTpl);
}
// This is for testing...
if (this.modInformation.testMode && this.modInformation.testBotRole.includes(botRole.toLowerCase()))
{
const tables = this.databaseService.getTables();
const assortWeapon = this.cloner.clone(weaponWithModsArray);
for (const item in assortWeapon)
{
const oldID = assortWeapon[item]._id
const newID = this.hashUtil.generate();
assortWeapon[item]._id = newID;
// Loop array again to fix parentID
for (const i in assortWeapon)
{
if (assortWeapon[i].parentId == oldID)
{
assortWeapon[i].parentId = newID
}
}
}
this.apbsTester.createComplexAssortItem(assortWeapon)
.addUnlimitedStackCount()
.addMoneyCost(Money.ROUBLES, 20000)
.addBuyRestriction(3)
.addLoyaltyLevel(1)
.export(tables.traders[this.modInformation.testTrader]);
}
return {
weapon: weaponWithModsArray,
chosenAmmoTpl: ammoTpl,
chosenUbglAmmoTpl: ubglAmmoTpl,
weaponMods: modPool,
weaponTemplate: weaponItemTemplate
};
}
}

View File

@ -0,0 +1,21 @@
export enum Logging
{
SCAV = "scav_generation",
PMC = "pmc_generation",
RAIDER = "raider_generation",
BOSS = "boss_generation",
EVENT = "event_generation",
WARN = "warnings",
ERR = "errors",
DEBUG = "debug"
}
export enum LoggingFolders
{
DEBUG = "debug",
SCAV = "scav_generation",
PMC = "pmc_generation",
RAIDER = "raider_generation",
BOSS = "boss_generation",
EVENT = "event_generation"
}

View File

@ -0,0 +1,180 @@
import { DependencyContainer, inject, injectable } from "tsyringe";
import { DatabaseService } from "@spt/services/DatabaseService";
import { RandomUtil } from "@spt/utils/RandomUtil";
import { BotLevelGenerator } from "@spt/generators/BotLevelGenerator";
import { MinMax } from "@spt/models/common/MinMax";
import { IRandomisedBotLevelResult } from "@spt/models/eft/bot/IRandomisedBotLevelResult";
import { IBotGenerationDetails } from "@spt/models/spt/bots/BotGenerationDetails";
import { APBSLogger } from "../Utils/APBSLogger";
import { Logging } from "../Enums/Logging";
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
import { APBSIBotBase } from "../Interface/APBSIBotBase";
import { RaidInformation } from "../Globals/RaidInformation";
import { APBSTierGetter } from "../Utils/APBSTierGetter";
import { ModConfig } from "../Globals/ModConfig";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { ModInformation } from "../Globals/ModInformation";
/** Handle profile related client events */
@injectable()
export class APBSBotLevelGenerator
{
constructor(
@inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("DatabaseService") protected databaseService: DatabaseService,
@inject("BotLevelGenerator") protected botLevelGenerator: BotLevelGenerator,
@inject("APBSLogger") protected apbsLogger: APBSLogger,
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
@inject("APBSTierGetter") protected apbsTierGetter: APBSTierGetter,
@inject("RaidInformation") protected raidInformation: RaidInformation,
@inject("ModInformation") protected modInformation: ModInformation,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter
)
{}
public registerBotLevelGenerator(container: DependencyContainer): void
{
container.afterResolution("BotLevelGenerator", (_t, result: BotLevelGenerator) =>
{
result.generateBotLevel = (levelDetails: MinMax, botGenerationDetails: IBotGenerationDetails, bot: APBSIBotBase): IRandomisedBotLevelResult =>
{
/*
TESTING TIER DEVIATION - Since botGenerationDetails isn't passed to the relevant methods, this is more difficult that anticipated. This logic works for the tier, but since selection is based on level..oof.
-2 to +1 tier
const lowerDeviation = (Math.floor(Math.random() * 2) - 2);
const upperDeviation = (Math.floor(Math.random() * 2));
const minTier = (tier + lowerDeviation) <= 0 ? 1 : tier + lowerDeviation
const maxTier = (tier + upperDeviation) >= 7 ? 7 : tier + upperDeviation
const newTier = this.randomUtil.getInt(minTier, maxTier)
console.log(`Original Tier: ${tier} - New Tier ${newTier}`)
*/
if (this.modInformation.testMode && this.modInformation.testBotRole.includes(botGenerationDetails.role.toLowerCase()))
{
const level = this.profileHelper.getPmcProfile(this.raidInformation.sessionId)?.Info?.Level;
const exp = this.profileHelper.getExperience(level);
const tier = this.apbsTierGetter.getTierByLevel(level);
bot.Info.Tier = this.chadOrChill(tier.toString());
const result: IRandomisedBotLevelResult = {
level,
exp
};
return result;
}
if (botGenerationDetails.isPlayerScav)
{
let level = this.raidInformation.freshProfile == true ? 1 : this.profileHelper.getPmcProfile(this.raidInformation.sessionId)?.Info?.Level;
// Level only stays undefined when a Fika dedicated profile is created due to this.raidInformation.freshProfile never being set.
// As Fika never calls /client/profile/status
if (level === undefined)
{
this.raidInformation.freshProfile = true;
level = 1;
}
const exp = this.profileHelper.getExperience(level);
const tier = this.apbsTierGetter.getTierByLevel(level);
bot.Info.Tier = this.chadOrChill(tier.toString());
const result: IRandomisedBotLevelResult = {
level,
exp
};
return result;
}
if (!botGenerationDetails.isPmc && !botGenerationDetails.isPlayerScav && ModConfig.config.enableScavCustomLevelDeltas)
{
const expTable = this.databaseService.getGlobals().config.exp.level.exp_table;
const botLevelRange = this.apbsGetRelativeBotLevelRange(botGenerationDetails, levelDetails, expTable.length);
const min = botLevelRange.min <= 0 ? 1 : botLevelRange.min;
const max = botLevelRange.max >= 79 ? 79 : botLevelRange.max;
const level = this.randomUtil.getInt(min, max);
const exp = this.profileHelper.getExperience(level);
const tier = this.apbsTierGetter.getTierByLevel(level);
bot.Info.Tier = this.chadOrChill(tier.toString());
const result: IRandomisedBotLevelResult = {
level,
exp
};
return result;
}
const expTable = this.databaseService.getGlobals().config.exp.level.exp_table;
const botLevelRange = this.apbsGetRelativeBotLevelRange(botGenerationDetails, levelDetails, expTable.length);
const min = botLevelRange.min <= 0 ? 1 : botLevelRange.min;
const max = botLevelRange.max >= 79 ? 79 : botLevelRange.max;
const level = this.randomUtil.getInt(min, max);
const exp = this.profileHelper.getExperience(level);
const tier = this.apbsTierGetter.getTierByLevel(level);
bot.Info.Tier = this.chadOrChill(tier.toString());
const result: IRandomisedBotLevelResult = {
level,
exp
};
return result;
};
},
{ frequency: "Always" }
);
this.apbsLogger.log(Logging.DEBUG, "Bot Level Generator registered");
}
private chadOrChill(tierInfo: string): string
{
if (ModConfig.config.onlyChads && ModConfig.config.tarkovAndChill)
{
return "?";
}
if (ModConfig.config.onlyChads) return "7";
if (ModConfig.config.tarkovAndChill) return "1";
if (ModConfig.config.blickyMode) return "0";
return tierInfo;
}
protected apbsGetRelativeBotLevelRange(
botGenerationDetails: IBotGenerationDetails,
levelDetails: MinMax,
maxAvailableLevel: number
): MinMax
{
const minPossibleLevel =
botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride
? Math.min(
Math.max(levelDetails.min, botGenerationDetails.locationSpecificPmcLevelOverride.min), // Biggest between json min and the botgen min
maxAvailableLevel // Fallback if value above is crazy (default is 79)
)
: Math.min(levelDetails.min, maxAvailableLevel); // Not pmc with override or non-pmc
const maxPossibleLevel =
botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride
? Math.min(botGenerationDetails.locationSpecificPmcLevelOverride.max, maxAvailableLevel) // Was a PMC and they have a level override
: Math.min(levelDetails.max, maxAvailableLevel); // Not pmc with override or non-pmc
let minLevel = botGenerationDetails.playerLevel - this.apbsTierGetter.getTierLowerLevelDeviation(botGenerationDetails.playerLevel);
let maxLevel = botGenerationDetails.playerLevel + this.apbsTierGetter.getTierUpperLevelDeviation(botGenerationDetails.playerLevel);
if (ModConfig.config.enableScavCustomLevelDeltas && !botGenerationDetails.isPmc && !botGenerationDetails.isPlayerScav && (botGenerationDetails.role.includes("assault") || botGenerationDetails.role == "marksman"))
{
minLevel = botGenerationDetails.playerLevel - this.apbsTierGetter.getScavTierLowerLevelDeviation(botGenerationDetails.playerLevel);
maxLevel = botGenerationDetails.playerLevel + this.apbsTierGetter.getScavTierUpperLevelDeviation(botGenerationDetails.playerLevel);
}
// Bound the level to the min/max possible
maxLevel = Math.min(Math.max(maxLevel, minPossibleLevel), maxPossibleLevel);
minLevel = Math.min(Math.max(minLevel, minPossibleLevel), maxPossibleLevel);
return {
min: minLevel,
max: maxLevel
}
}
}

View File

@ -0,0 +1,152 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { VFS } from "@spt/utils/VFS";
import { inject, injectable } from "tsyringe";
import jsonc from "jsonc";
import path from "path";
import { TierInformation } from "./TierInformation";
import { APBSLogger } from "../Utils/APBSLogger";
import { ILogger } from "@spt/models/spt/utils/ILogger";
@injectable()
export class ModConfig
{
public static config: Config;
constructor(
@inject("APBSLogger") protected apbsLogger: APBSLogger,
@inject("PrimaryLogger") protected logger: ILogger,
@inject("TierInformation") protected tierInformation: TierInformation,
@inject("VFS") protected vfs: VFS
)
{
ModConfig.config = jsonc.parse(this.vfs.readFile(path.resolve(__dirname, "../../config/config.jsonc")));
}
public serverLogDetails(): void
{
this.logger.debug("[APBS] Mod Config - FOR SUPPORT FOLKS ❤❤")
this.logger.debug(`[APBS] Import Mod Weapons: ${ModConfig.config.enableModdedWeapons} <- MUST BE FALSE FOR SUPPORT`)
this.logger.debug(`[APBS] Import Mod Equipment: ${ModConfig.config.enableModdedEquipment} <- MUST BE FALSE FOR SUPPORT`)
this.logger.debug(`[APBS] Import Mod Clothing: ${ModConfig.config.enableModdedClothing} <- MUST BE FALSE FOR SUPPORT`)
}
}
export interface Config
{
usePreset: boolean,
presetName: string,
enableModdedWeapons: boolean,
enableModdedEquipment: boolean,
enableModdedClothing: boolean,
initalTierAppearance: number,
pmcWeaponWeights: number,
scavWeaponWeights: number,
followerWeaponWeights: number,
enableSafeGuard: boolean,
seasonalPmcAppearance: boolean,
disableRealismGasMasks: boolean,
onlyChads: boolean,
tarkovAndChill: boolean,
blickyMode: boolean,
disableScavTierGeneration: boolean,
disablePMCTierGeneration: boolean,
disableBossTierGeneration: boolean,
disableBossFollowerTierGeneration: boolean,
disableRaiderRogueTierGeneration: boolean,
gameVersionWeight: boolean,
standard: number,
left_behind: number,
prepare_for_escape: number,
edge_of_darkness: number,
unheard_edition: number,
enablePMCAmmoTierSliding: boolean,
slideAmount: number,
slideChance: number,
enablePerWeaponTypeAttachmentChances: boolean,
forceStock: boolean,
stockButtpadChance: number,
forceDustCover: boolean,
forceScopeSlot: boolean,
forceMuzzle: boolean,
muzzleChance: [ number, number, number, number, number, number, number ],
forceChildrenMuzzle: boolean,
pmcLoot: boolean,
pmcLootBlacklistItems: string[],
scavLoot: boolean,
enableScavAttachmentTiering: boolean,
enableScavEqualEquipmentTiering: boolean,
forceWeaponModLimits: boolean,
scopeLimit: number,
tacticalLimit: number,
enableT7Thermals: boolean,
startTier: number,
scavWeaponDurability: [ number, number, number, number ],
pmcWeaponDurability: [ number, number, number, number ],
bossWeaponDurability: [ number, number, number, number ],
guardWeaponDurability: [ number, number, number, number ],
raiderWeaponDurability: [ number, number, number, number ],
enableCustomPlateChances: boolean,
scavMainPlateChance: [ number, number, number, number, number, number, number ],
scavSidePlateChance: [ number, number, number, number, number, number, number ],
pmcMainPlateChance: [ number, number, number, number, number, number, number ],
pmcSidePlateChance: [ number, number, number, number, number, number, number ],
bossMainPlateChance: [ number, number, number, number, number, number, number ],
bossSidePlateChance: [ number, number, number, number, number, number, number ],
guardMainPlateChance: [ number, number, number, number, number, number, number ],
guardSidePlateChance: [ number, number, number, number, number, number, number ],
raiderMainPlateChance: [ number, number, number, number, number, number, number ],
raiderSidePlateChance: [ number, number, number, number, number, number, number ],
addAllKeysToScavs: boolean,
addOnlyMechanicalKeysToScavs: boolean,
addOnlyKeyCardsToScavs: boolean,
enableConsumableResourceRandomization: boolean,
scavFoodRates: [ number, number ]
scavMedRates: [ number, number ]
pmcFoodRates: [ number, number ]
pmcMedRates: [ number, number ]
tier1AmmoBlacklist: string[],
tier2AmmoBlacklist: string[],
tier3AmmoBlacklist: string[],
tier4AmmoBlacklist: string[],
tier5AmmoBlacklist: string[],
tier6AmmoBlacklist: string[],
tier7AmmoBlacklist: string[],
tier1EquipmentBlacklist: string[],
tier2EquipmentBlacklist: string[],
tier3EquipmentBlacklist: string[],
tier4EquipmentBlacklist: string[],
tier5EquipmentBlacklist: string[],
tier6EquipmentBlacklist: string[],
tier7EquipmentBlacklist: string[],
tier1WeaponBlacklist: string[],
tier2WeaponBlacklist: string[],
tier3WeaponBlacklist: string[],
tier4WeaponBlacklist: string[],
tier5WeaponBlacklist: string[],
tier6WeaponBlacklist: string[],
tier7WeaponBlacklist: string[],
tier1AttachmentBlacklist: string[],
tier2AttachmentBlacklist: string[],
tier3AttachmentBlacklist: string[],
tier4AttachmentBlacklist: string[],
tier5AttachmentBlacklist: string[],
tier6AttachmentBlacklist: string[],
tier7AttachmentBlacklist: string[],
enableCustomLevelDeltas: boolean,
tier1LevelDelta: [ number, number ],
tier2LevelDelta: [ number, number ],
tier3LevelDelta: [ number, number ],
tier4LevelDelta: [ number, number ],
tier5LevelDelta: [ number, number ],
tier6LevelDelta: [ number, number ],
tier7LevelDelta: [ number, number ],
enableScavCustomLevelDeltas: boolean,
tier1ScavLevelDelta: [ number, number ],
tier2ScavLevelDelta: [ number, number ],
tier3ScavLevelDelta: [ number, number ],
tier4ScavLevelDelta: [ number, number ],
tier5ScavLevelDelta: [ number, number ],
tier6ScavLevelDelta: [ number, number ],
tier7ScavLevelDelta: [ number, number ],
enableDebugLog: boolean,
}

View File

@ -0,0 +1,16 @@
import * as path from "path";
import modPackage = require("../../package.json");
export class ModInformation
{
public modPath: string = path.join(path.dirname(__filename), "..", "..");
public logPath: string = path.join(path.dirname(__filename), "..", "..", "logs");
public profilePath: string = path.join(path.dirname(__filename), "..", "..", "..", "..", "profiles");
public versionNumber: string = modPackage.version;
public testMode: boolean = false;
public testBotRole: (string)[] = [ "pmcusec", "pmcbear" ]
public testTrader: string = "6741449944c5b44c53741ccc"
public clearAssortPreRaid: boolean = true;
}

View File

@ -0,0 +1,84 @@
import { injectable, inject } from "tsyringe";
@injectable()
export class RaidInformation
{
constructor(
)
{}
public freshProfile: boolean;
public location: string;
public currentTime: string;
public timeVariant: string;
public nightTime: boolean;
public sessionId: string;
public usingDefaultDB: boolean;
public mapWeights = {
"bigmap":
{
"LongRange": 20,
"ShortRange": 80
},
"RezervBase":
{
"LongRange": 20,
"ShortRange": 80
},
"laboratory":
{
"LongRange": 5,
"ShortRange": 95
},
"factory4_night":
{
"LongRange": 1,
"ShortRange": 99
},
"factory4_day":
{
"LongRange": 1,
"ShortRange": 99
},
"Interchange":
{
"LongRange": 20,
"ShortRange": 80
},
"Sandbox":
{
"LongRange": 15,
"ShortRange": 85
},
"Sandbox_high":
{
"LongRange": 15,
"ShortRange": 85
},
"Woods":
{
"LongRange": 60,
"ShortRange": 40
},
"Shoreline":
{
"LongRange": 50,
"ShortRange": 50
},
"Lighthouse":
{
"LongRange": 30,
"ShortRange": 70
},
"TarkovStreets":
{
"LongRange": 20,
"ShortRange": 80
}
}
}

View File

@ -0,0 +1,712 @@
/* eslint-disable @typescript-eslint/naming-convention */
export class TierInformation
{
public tier0;
public tier1;
public tier2;
public tier3;
public tier4;
public tier5;
public tier6;
public tier7;
public tier0mods;
public tier1mods;
public tier2mods;
public tier3mods;
public tier4mods;
public tier5mods;
public tier6mods;
public tier7mods;
public tier0chances;
public tier1chances;
public tier2chances;
public tier3chances;
public tier4chances;
public tier5chances;
public tier6chances;
public tier7chances;
public tier0ammo;
public tier1ammo;
public tier2ammo;
public tier3ammo;
public tier4ammo;
public tier5ammo;
public tier6ammo;
public tier7ammo;
public tier0appearance;
public tier1appearance;
public tier2appearance;
public tier3appearance;
public tier4appearance;
public tier5appearance;
public tier6appearance;
public tier7appearance;
public tiers = [
{
tier: 1,
playerMinimumLevel: 1,
playerMaximumLevel: 10,
botMinLevelVariance: 10,
botMaxLevelVariance: 5,
scavMinLevelVariance: 10,
scavMaxLevelVariance: 5
},
{
tier: 2,
playerMinimumLevel: 11,
playerMaximumLevel: 20,
botMinLevelVariance: 15,
botMaxLevelVariance: 5,
scavMinLevelVariance: 15,
scavMaxLevelVariance: 5
},
{
tier: 3,
playerMinimumLevel: 21,
playerMaximumLevel: 30,
botMinLevelVariance: 25,
botMaxLevelVariance: 7,
scavMinLevelVariance: 25,
scavMaxLevelVariance: 7
},
{
tier: 4,
playerMinimumLevel: 31,
playerMaximumLevel: 40,
botMinLevelVariance: 35,
botMaxLevelVariance: 10,
scavMinLevelVariance: 35,
scavMaxLevelVariance: 10
},
{
tier: 5,
playerMinimumLevel: 41,
playerMaximumLevel: 50,
botMinLevelVariance: 45,
botMaxLevelVariance: 15,
scavMinLevelVariance: 45,
scavMaxLevelVariance: 15
},
{
tier: 6,
playerMinimumLevel: 51,
playerMaximumLevel: 60,
botMinLevelVariance: 55,
botMaxLevelVariance: 20,
scavMinLevelVariance: 55,
scavMaxLevelVariance: 20
},
{
tier: 7,
playerMinimumLevel: 61,
playerMaximumLevel: 100,
botMinLevelVariance: 60,
botMaxLevelVariance: 20,
scavMinLevelVariance: 60,
scavMaxLevelVariance: 20
}
]
public armorPlateWeights = [
{
"levelRange": {
"min": 1,
"max": 10
},
"front_plate": {
"2": 10,
"3": 80,
"4": 10
},
"back_plate": {
"2": 10,
"3": 80,
"4": 10
},
"side_plate": {
"2": 10,
"3": 80,
"4": 10
},
"left_side_plate": {
"2": 10,
"3": 80,
"4": 10
},
"right_side_plate": {
"2": 10,
"3": 80,
"4": 10
}
},
{
"levelRange": {
"min": 11,
"max": 20
},
"front_plate": {
"3": 65,
"4": 32,
"5": 3
},
"back_plate": {
"3": 65,
"4": 32,
"5": 3
},
"side_plate": {
"3": 65,
"4": 32,
"5": 3
},
"left_side_plate": {
"3": 65,
"4": 32,
"5": 3
},
"right_side_plate": {
"3": 65,
"4": 32,
"5": 3
}
},
{
"levelRange": {
"min": 21,
"max": 30
},
"front_plate": {
"3": 15,
"4": 70,
"5": 10,
"6": 5
},
"back_plate": {
"3": 15,
"4": 70,
"5": 10,
"6": 5
},
"side_plate": {
"3": 15,
"4": 70,
"5": 10,
"6": 5
},
"left_side_plate": {
"3": 15,
"4": 70,
"5": 10,
"6": 5
},
"right_side_plate": {
"3": 15,
"4": 70,
"5": 10,
"6": 5
}
},
{
"levelRange": {
"min": 31,
"max": 40
},
"front_plate": {
"4": 30,
"5": 50,
"6": 20
},
"back_plate": {
"4": 30,
"5": 50,
"6": 20
},
"side_plate": {
"4": 30,
"5": 50,
"6": 20
},
"left_side_plate": {
"4": 30,
"5": 50,
"6": 20
},
"right_side_plate": {
"4": 30,
"5": 50,
"6": 20
}
},
{
"levelRange": {
"min": 41,
"max": 50
},
"front_plate": {
"4": 10,
"5": 45,
"6": 45
},
"back_plate": {
"4": 10,
"5": 45,
"6": 45
},
"side_plate": {
"4": 10,
"5": 45,
"6": 45
},
"left_side_plate": {
"4": 10,
"5": 45,
"6": 45
},
"right_side_plate": {
"4": 10,
"5": 45,
"6": 45
}
},
{
"levelRange": {
"min": 51,
"max": 60
},
"front_plate": {
"4": 5,
"5": 30,
"6": 65
},
"back_plate": {
"4": 5,
"5": 30,
"6": 65
},
"side_plate": {
"4": 5,
"5": 30,
"6": 65
},
"left_side_plate": {
"4": 5,
"5": 30,
"6": 65
},
"right_side_plate": {
"4": 5,
"5": 30,
"6": 65
}
},
{
"levelRange": {
"min": 61,
"max": 100
},
"front_plate": {
"4": 1,
"5": 19,
"6": 80
},
"back_plate": {
"4": 1,
"5": 19,
"6": 80
},
"side_plate": {
"4": 1,
"5": 19,
"6": 80
},
"left_side_plate": {
"4": 1,
"5": 19,
"6": 80
},
"right_side_plate": {
"4": 1,
"5": 19,
"6": 80
}
}
]
public scavArmorPlateWeights = [
{
"levelRange": {
"min": 1,
"max": 100
},
"front_plate": {
"2": 15,
"3": 35,
"4": 5
},
"back_plate": {
"2": 15,
"3": 35,
"4": 5
},
"side_plate": {
"2": 15,
"3": 35,
"4": 5
},
"left_side_plate": {
"2": 15,
"3": 35,
"4": 5
},
"right_side_plate": {
"2": 15,
"3": 35,
"4": 5
}
}
]
public lootRandomization = [
{
"levelRange": {
"min": 1,
"max": 15
},
"generation": {
"drugs": {
"weights": {
"0": 1
},
"whitelist": {}
},
"grenades": {
"weights": {
"0": 45,
"1": 35,
"2": 1
},
"whitelist": {
"5710c24ad2720bc3458b45a3": 25,
"58d3db5386f77426186285a0": 25,
"5448be9a4bdc2dfd2f8b456a": 25
}
},
"healing": {
"weights": {
"0": 10,
"1": 85,
"2": 20
},
"whitelist": {
"5755356824597772cb798962": 4,
"590c661e86f7741e566b646a": 9,
"544fb45d4bdc2dee738b4568": 2,
"5e831507ea0a7c419c2f9bd9": 6
}
},
"backpackLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"pocketLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"vestLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"magazines": {
"weights": {
"0": 0,
"1": 10,
"2": 55,
"3": 25
},
"whitelist": {}
},
"stims": {
"weights": {
"0": 100,
"1": 1
},
"whitelist": {
"544fb3f34bdc2d03748b456a": 25,
"5c0e530286f7747fa1419862": 65
}
}
}
},
{
"levelRange": {
"min": 16,
"max": 30
},
"generation": {
"drugs": {
"weights": {
"0": 1,
"1": 1
},
"whitelist": {}
},
"grenades": {
"weights": {
"0": 15,
"1": 35,
"2": 5,
"3": 0
},
"whitelist": {
"5710c24ad2720bc3458b45a3": 25,
"58d3db5386f77426186285a0": 25,
"5448be9a4bdc2dfd2f8b456a": 25,
"5e32f56fcb6d5863cc5e5ee4": 5,
"5e340dcdcb6d5863cc5e5efb": 1
}
},
"healing": {
"weights": {
"0": 1,
"1": 25,
"2": 65,
"3": 10
},
"whitelist": {
"60098ad7c2240c0fe85c570a": 15,
"590c678286f77426c9660122": 10,
"5e8488fa988a8701445df1e4": 12
}
},
"backpackLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"pocketLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"vestLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"magazines": {
"weights": {
"0": 0,
"1": 1,
"2": 55,
"3": 25
},
"whitelist": {}
},
"stims": {
"weights": {
"0": 75,
"1": 20,
"2": 5
},
"whitelist": {
"544fb3f34bdc2d03748b456a": 1,
"5c0e530286f7747fa1419862": 65,
"5c0e534186f7747fa1419867": 12,
"5c0e531d86f7747fa23f4d42": 8,
"5ed51652f6c34d2cc26336a1": 17
}
}
}
},
{
"levelRange": {
"min": 31,
"max": 45
},
"generation": {
"drugs": {
"weights": {
"0": 1,
"1": 1
},
"whitelist": {}
},
"grenades": {
"weights": {
"0": 1,
"1": 15,
"2": 25,
"3": 10
},
"whitelist": {
"5710c24ad2720bc3458b45a3": 15,
"58d3db5386f77426186285a0": 15,
"5448be9a4bdc2dfd2f8b456a": 15,
"5e32f56fcb6d5863cc5e5ee4": 45,
"5e340dcdcb6d5863cc5e5efb": 20,
"617fd91e5539a84ec44ce155": 5,
"618a431df1eb8e24b8741deb": 5
}
},
"healing": {
"weights": {
"0": 1,
"1": 15,
"2": 65,
"3": 30,
"4": 5
},
"whitelist": {
"60098ad7c2240c0fe85c570a": 45,
"590c678286f77426c9660122": 20,
"5e8488fa988a8701445df1e4": 45
}
},
"backpackLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"pocketLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"vestLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"magazines": {
"weights": {
"0": 0,
"1": 1,
"2": 55,
"3": 25
},
"whitelist": {}
},
"stims": {
"weights": {
"0": 50,
"1": 20,
"2": 5
},
"whitelist": {
"544fb3f34bdc2d03748b456a": 1,
"5c0e530286f7747fa1419862": 65,
"5c0e534186f7747fa1419867": 12,
"5c0e531d86f7747fa23f4d42": 8,
"5ed51652f6c34d2cc26336a1": 17
}
}
}
},
{
"levelRange": {
"min": 46,
"max": 100
},
"generation": {
"drugs": {
"weights": {
"0": 1,
"1": 1
},
"whitelist": {}
},
"grenades": {
"weights": {
"0": 1,
"1": 15,
"2": 20,
"3": 15
},
"whitelist": {
"5710c24ad2720bc3458b45a3": 1,
"58d3db5386f77426186285a0": 1,
"5448be9a4bdc2dfd2f8b456a": 1,
"5e32f56fcb6d5863cc5e5ee4": 35,
"5e340dcdcb6d5863cc5e5efb": 35,
"617fd91e5539a84ec44ce155": 10,
"618a431df1eb8e24b8741deb": 10
}
},
"healing": {
"weights": {
"0": 1,
"1": 15,
"2": 35,
"3": 75,
"4": 20
},
"whitelist": {
"60098ad7c2240c0fe85c570a": 45,
"590c678286f77426c9660122": 20,
"5e8488fa988a8701445df1e4": 45
}
},
"backpackLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"pocketLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"vestLoot": {
"weights": {
"0": 1
},
"whitelist": {}
},
"magazines": {
"weights": {
"0": 0,
"1": 1,
"2": 25,
"3": 55
},
"whitelist": {}
},
"stims": {
"weights": {
"0": 50,
"1": 20,
"2": 5
},
"whitelist": {
"544fb3f34bdc2d03748b456a": 1,
"5c0e530286f7747fa1419862": 65,
"5c0e534186f7747fa1419867": 12,
"5c0e531d86f7747fa23f4d42": 8,
"5ed51652f6c34d2cc26336a1": 17
}
}
}
}
]
}

View File

@ -0,0 +1,236 @@
import { injectable, inject } from "tsyringe";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import { DatabaseService } from "@spt/services/DatabaseService";
import { APBSLogger } from "../Utils/APBSLogger";
import { Logging } from "../Enums/Logging";
import { ModConfig } from "../Globals/ModConfig";
@injectable()
export class BlacklistHelper
{
constructor(
@inject("DatabaseService") protected database: DatabaseService,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("APBSLogger") protected apbsLogger: APBSLogger
)
{}
public initialize(): void
{
if (ModConfig.config.tier1AmmoBlacklist.length > 0) this.removeBlacklistedAmmo(ModConfig.config.tier1AmmoBlacklist, 1);
if (ModConfig.config.tier2AmmoBlacklist.length > 0) this.removeBlacklistedAmmo(ModConfig.config.tier2AmmoBlacklist, 2);
if (ModConfig.config.tier3AmmoBlacklist.length > 0) this.removeBlacklistedAmmo(ModConfig.config.tier3AmmoBlacklist, 3);
if (ModConfig.config.tier4AmmoBlacklist.length > 0) this.removeBlacklistedAmmo(ModConfig.config.tier4AmmoBlacklist, 4);
if (ModConfig.config.tier5AmmoBlacklist.length > 0) this.removeBlacklistedAmmo(ModConfig.config.tier5AmmoBlacklist, 5);
if (ModConfig.config.tier6AmmoBlacklist.length > 0) this.removeBlacklistedAmmo(ModConfig.config.tier6AmmoBlacklist, 6);
if (ModConfig.config.tier7AmmoBlacklist.length > 0) this.removeBlacklistedAmmo(ModConfig.config.tier7AmmoBlacklist, 7);
if (ModConfig.config.tier1EquipmentBlacklist.length > 0) this.removeBlacklistedEquipment(ModConfig.config.tier1EquipmentBlacklist, 1);
if (ModConfig.config.tier2EquipmentBlacklist.length > 0) this.removeBlacklistedEquipment(ModConfig.config.tier2EquipmentBlacklist, 2);
if (ModConfig.config.tier3EquipmentBlacklist.length > 0) this.removeBlacklistedEquipment(ModConfig.config.tier3EquipmentBlacklist, 3);
if (ModConfig.config.tier4EquipmentBlacklist.length > 0) this.removeBlacklistedEquipment(ModConfig.config.tier4EquipmentBlacklist, 4);
if (ModConfig.config.tier5EquipmentBlacklist.length > 0) this.removeBlacklistedEquipment(ModConfig.config.tier5EquipmentBlacklist, 5);
if (ModConfig.config.tier6EquipmentBlacklist.length > 0) this.removeBlacklistedEquipment(ModConfig.config.tier6EquipmentBlacklist, 6);
if (ModConfig.config.tier7EquipmentBlacklist.length > 0) this.removeBlacklistedEquipment(ModConfig.config.tier7EquipmentBlacklist, 7);
if (ModConfig.config.tier1WeaponBlacklist.length > 0) this.removeBlacklistedWeapons(ModConfig.config.tier1WeaponBlacklist, 1);
if (ModConfig.config.tier2WeaponBlacklist.length > 0) this.removeBlacklistedWeapons(ModConfig.config.tier2WeaponBlacklist, 2);
if (ModConfig.config.tier3WeaponBlacklist.length > 0) this.removeBlacklistedWeapons(ModConfig.config.tier3WeaponBlacklist, 3);
if (ModConfig.config.tier4WeaponBlacklist.length > 0) this.removeBlacklistedWeapons(ModConfig.config.tier4WeaponBlacklist, 4);
if (ModConfig.config.tier5WeaponBlacklist.length > 0) this.removeBlacklistedWeapons(ModConfig.config.tier5WeaponBlacklist, 5);
if (ModConfig.config.tier6WeaponBlacklist.length > 0) this.removeBlacklistedWeapons(ModConfig.config.tier6WeaponBlacklist, 6);
if (ModConfig.config.tier7WeaponBlacklist.length > 0) this.removeBlacklistedWeapons(ModConfig.config.tier7WeaponBlacklist, 7);
if (ModConfig.config.tier1AttachmentBlacklist.length > 0) this.removeBlacklistedAttachments(ModConfig.config.tier1AttachmentBlacklist, 1);
if (ModConfig.config.tier2AttachmentBlacklist.length > 0) this.removeBlacklistedAttachments(ModConfig.config.tier2AttachmentBlacklist, 2);
if (ModConfig.config.tier3AttachmentBlacklist.length > 0) this.removeBlacklistedAttachments(ModConfig.config.tier3AttachmentBlacklist, 3);
if (ModConfig.config.tier4AttachmentBlacklist.length > 0) this.removeBlacklistedAttachments(ModConfig.config.tier4AttachmentBlacklist, 4);
if (ModConfig.config.tier5AttachmentBlacklist.length > 0) this.removeBlacklistedAttachments(ModConfig.config.tier5AttachmentBlacklist, 5);
if (ModConfig.config.tier6AttachmentBlacklist.length > 0) this.removeBlacklistedAttachments(ModConfig.config.tier6AttachmentBlacklist, 6);
if (ModConfig.config.tier7AttachmentBlacklist.length > 0) this.removeBlacklistedAttachments(ModConfig.config.tier7AttachmentBlacklist, 7);
}
private removeBlacklistedAmmo(ammoBlacklist: string[], tier: number): void
{
const tierJSON = this.apbsEquipmentGetter.getTierAmmoJson(tier, true);
for (const item in ammoBlacklist)
{
const itemDetails = this.getItem(ammoBlacklist[item])
if (itemDetails != undefined && itemDetails._parent == "5485a8684bdc2da71d8b4567")
{
for (const botType in tierJSON)
{
for (const ammo in tierJSON[botType])
{
if (Object.keys(tierJSON[botType][ammo]).includes(itemDetails._id))
{
if (Object.keys(tierJSON[botType][ammo]).length > 1)
{
delete tierJSON[botType][ammo][itemDetails._id]
this.apbsLogger.log(Logging.DEBUG, `[Tier${tier}] Removed "${itemDetails._id}" from "${botType}" ${ammo} pool.`)
continue;
}
this.apbsLogger.log(Logging.WARN, `Did not blacklist "${itemDetails._id}" as it would make the Tier${tier} "${botType}" ${ammo} pool empty`)
continue;
}
}
}
}
if (itemDetails == undefined || itemDetails._parent != "5485a8684bdc2da71d8b4567")
{
this.apbsLogger.log(Logging.WARN, `"${ammoBlacklist[item]}" in Ammo Blacklist is either an invalid ammunition or item ID.`)
}
}
}
private removeBlacklistedEquipment(equipmentBlacklist: string[], tier: number): void
{
const tierJSON = this.apbsEquipmentGetter.getTierJson(tier, true);
for (const item in equipmentBlacklist)
{
const itemDetails = this.getItem(equipmentBlacklist[item])
if (itemDetails != undefined)
{
for (const botType in tierJSON)
{
for (const equipmentSlot in tierJSON[botType].equipment)
{
if (Object.keys(tierJSON[botType].equipment[equipmentSlot]).includes(itemDetails._id))
{
if (Object.keys(tierJSON[botType].equipment[equipmentSlot]).length > 1)
{
delete tierJSON[botType].equipment[equipmentSlot][itemDetails._id]
this.apbsLogger.log(Logging.DEBUG, `[Tier${tier}] Removed "${itemDetails._id}" from "${botType}" ${equipmentSlot} pool.`)
continue;
}
this.apbsLogger.log(Logging.WARN, `Did not blacklist "${itemDetails._id}" as it would make the Tier${tier} "${botType}" ${equipmentSlot} pool empty.`)
continue;
}
}
}
}
if (itemDetails == undefined)
{
this.apbsLogger.log(Logging.WARN, `"${equipmentBlacklist[item]}" in Equipment Blacklist is an invalid item ID.`)
}
}
}
private removeBlacklistedWeapons(weaponBlacklist: string[], tier: number): void
{
const tierJSON = this.apbsEquipmentGetter.getTierJson(tier, true);
for (const item in weaponBlacklist)
{
const itemDetails = this.getItem(weaponBlacklist[item])
if (itemDetails != undefined)
{
for (const botType in tierJSON)
{
for (const equipmentSlot in tierJSON[botType].equipment.FirstPrimaryWeapon)
{
if (Object.keys(tierJSON[botType].equipment.FirstPrimaryWeapon[equipmentSlot]).includes(itemDetails._id))
{
if (Object.keys(tierJSON[botType].equipment.FirstPrimaryWeapon[equipmentSlot]).length > 1)
{
delete tierJSON[botType].equipment.FirstPrimaryWeapon[equipmentSlot][itemDetails._id]
this.apbsLogger.log(Logging.DEBUG, `[Tier${tier}] Removed "${itemDetails._id}" from "${botType}" ${equipmentSlot} pool.`)
continue;
}
this.apbsLogger.log(Logging.WARN, `Did not blacklist "${itemDetails._id}" as it would make the Tier${tier} "${botType}" ${equipmentSlot} pool empty.`)
continue;
}
}
for (const equipmentSlot in tierJSON[botType].equipment.SecondPrimaryWeapon)
{
if (Object.keys(tierJSON[botType].equipment.SecondPrimaryWeapon[equipmentSlot]).includes(itemDetails._id))
{
if (Object.keys(tierJSON[botType].equipment.SecondPrimaryWeapon[equipmentSlot]).length > 1)
{
delete tierJSON[botType].equipment.SecondPrimaryWeapon[equipmentSlot][itemDetails._id]
this.apbsLogger.log(Logging.DEBUG, `[Tier${tier}] Removed "${itemDetails._id}" from "${botType}" ${equipmentSlot} pool.`)
continue;
}
this.apbsLogger.log(Logging.WARN, `Did not blacklist "${itemDetails._id}" as it would make the Tier${tier} "${botType}" ${equipmentSlot} pool empty.`)
continue;
}
}
if (Object.keys(tierJSON[botType].equipment.Holster).includes(itemDetails._id))
{
if (Object.keys(tierJSON[botType].equipment.Holster).length > 1)
{
delete tierJSON[botType].equipment.Holster[itemDetails._id]
this.apbsLogger.log(Logging.DEBUG, `[Tier${tier}] Removed "${itemDetails._id}" from "${botType}" Holster pool.`)
continue;
}
this.apbsLogger.log(Logging.WARN, `Did not blacklist "${itemDetails._id}" as it would make the Tier${tier} "${botType}" Holster pool empty.`)
continue;
}
if (Object.keys(tierJSON[botType].equipment.Scabbard).includes(itemDetails._id))
{
if (Object.keys(tierJSON[botType].equipment.Scabbard).length > 1)
{
delete tierJSON[botType].equipment.Scabbard[itemDetails._id]
this.apbsLogger.log(Logging.DEBUG, `[Tier${tier}] Removed "${itemDetails._id}" from "${botType}" Scabbard pool.`)
continue;
}
this.apbsLogger.log(Logging.WARN, `Did not blacklist "${itemDetails._id}" as it would make the Tier${tier} "${botType}" Scabbard pool empty.`)
continue;
}
}
}
if (itemDetails == undefined)
{
this.apbsLogger.log(Logging.WARN, `"${weaponBlacklist[item]}" in Weapon Blacklist is an invalid item ID.`)
}
}
}
private removeBlacklistedAttachments(attachmentBlacklist: string[], tier: number): void
{
const tierJSON = this.apbsEquipmentGetter.getTierModsJson(tier, true);
for (const item in attachmentBlacklist)
{
const itemDetails = this.getItem(attachmentBlacklist[item])
if (itemDetails != undefined)
{
for (const parentID in tierJSON)
{
const parentItemName = this.getItem(parentID);
const parentItemID = tierJSON[parentID]
for (const slotName in parentItemID)
{
const itemSlotName = tierJSON[parentID][slotName]
if (itemSlotName.includes(itemDetails._id))
{
if (itemSlotName.length == 1)
{
delete tierJSON[parentID][slotName];
this.apbsLogger.log(Logging.DEBUG, `[Tier${tier}] Removed slot "${slotName}" from "${parentItemName._name}" because array is now empty.`);
continue;
}
const index = itemSlotName.indexOf(itemDetails._id);
if (index > -1)
{
itemSlotName.splice(index, 1)
this.apbsLogger.log(Logging.DEBUG, `[Tier${tier}] Removed "${itemDetails._id}" from "${parentItemName._name}" slot "${slotName}".`);
continue;
}
}
}
}
}
if (itemDetails == undefined)
{
this.apbsLogger.log(Logging.WARN, `"${attachmentBlacklist[item]}" in Attachment Blacklist is either an invalid attachment or item ID.`)
}
}
}
private getItem(tpl: string): ITemplateItem
{
if (tpl in this.database.getItems())
{
return this.database.getItems()[tpl];
}
return undefined;
}
}

View File

@ -0,0 +1,328 @@
import { injectable, inject } from "tsyringe";
import * as path from "path";
import * as fs from "fs";
import { TierInformation } from "../Globals/TierInformation";
import { RaidInformation } from "../Globals/RaidInformation";
import { APBSLogger } from "../Utils/APBSLogger";
import { Logging } from "../Enums/Logging";
import Tier0equipment = require("../db/Tier0_equipment.json");
import Tier1equipment = require("../db/Tier1_equipment.json");
import Tier2equipment = require("../db/Tier2_equipment.json");
import Tier3equipment = require("../db/Tier3_equipment.json");
import Tier4equipment = require("../db/Tier4_equipment.json");
import Tier5equipment = require("../db/Tier5_equipment.json");
import Tier6equipment = require("../db/Tier6_equipment.json");
import Tier7equipment = require("../db/Tier7_equipment.json");
import Tier0mods = require("../db/Tier0_mods.json");
import Tier1mods = require("../db/Tier1_mods.json");
import Tier2mods = require("../db/Tier2_mods.json");
import Tier3mods = require("../db/Tier3_mods.json");
import Tier4mods = require("../db/Tier4_mods.json");
import Tier5mods = require("../db/Tier5_mods.json");
import Tier6mods = require("../db/Tier6_mods.json");
import Tier7mods = require("../db/Tier7_mods.json");
import Tier0chances = require("../db/Tier0_chances.json");
import Tier1chances = require("../db/Tier1_chances.json");
import Tier2chances = require("../db/Tier2_chances.json");
import Tier3chances = require("../db/Tier3_chances.json");
import Tier4chances = require("../db/Tier4_chances.json");
import Tier5chances = require("../db/Tier5_chances.json");
import Tier6chances = require("../db/Tier6_chances.json");
import Tier7chances = require("../db/Tier7_chances.json");
import Tier0ammo = require("../db/Tier0_ammo.json");
import Tier1ammo = require("../db/Tier1_ammo.json");
import Tier2ammo = require("../db/Tier2_ammo.json");
import Tier3ammo = require("../db/Tier3_ammo.json");
import Tier4ammo = require("../db/Tier4_ammo.json");
import Tier5ammo = require("../db/Tier5_ammo.json");
import Tier6ammo = require("../db/Tier6_ammo.json");
import Tier7ammo = require("../db/Tier7_ammo.json");
import Tier0appearance = require("../db/Tier0_appearance.json");
import Tier1appearance = require("../db/Tier1_appearance.json");
import Tier2appearance = require("../db/Tier2_appearance.json");
import Tier3appearance = require("../db/Tier3_appearance.json");
import Tier4appearance = require("../db/Tier4_appearance.json");
import Tier5appearance = require("../db/Tier5_appearance.json");
import Tier6appearance = require("../db/Tier6_appearance.json");
import Tier7appearance = require("../db/Tier7_appearance.json");
@injectable()
export class JSONHelper
{
count: number;
constructor(
@inject("TierInformation") protected tierInformation: TierInformation,
@inject("RaidInformation") protected raidInformation: RaidInformation,
@inject("APBSLogger") protected apbsLogger: APBSLogger
)
{
this.count = 0
}
public buildTierJson(): void
{
this.tierInformation.tier0 = Tier0equipment;
this.tierInformation.tier1 = Tier1equipment;
this.tierInformation.tier2 = Tier2equipment;
this.tierInformation.tier3 = Tier3equipment;
this.tierInformation.tier4 = Tier4equipment;
this.tierInformation.tier5 = Tier5equipment;
this.tierInformation.tier6 = Tier6equipment;
this.tierInformation.tier7 = Tier7equipment;
this.tierInformation.tier0mods = Tier0mods;
this.tierInformation.tier1mods = Tier1mods;
this.tierInformation.tier2mods = Tier2mods;
this.tierInformation.tier3mods = Tier3mods;
this.tierInformation.tier4mods = Tier4mods;
this.tierInformation.tier5mods = Tier5mods;
this.tierInformation.tier6mods = Tier6mods;
this.tierInformation.tier7mods = Tier7mods;
this.tierInformation.tier0chances = Tier0chances;
this.tierInformation.tier1chances = Tier1chances;
this.tierInformation.tier2chances = Tier2chances;
this.tierInformation.tier3chances = Tier3chances;
this.tierInformation.tier4chances = Tier4chances;
this.tierInformation.tier5chances = Tier5chances;
this.tierInformation.tier6chances = Tier6chances;
this.tierInformation.tier7chances = Tier7chances;
this.tierInformation.tier0ammo = Tier0ammo;
this.tierInformation.tier1ammo = Tier1ammo;
this.tierInformation.tier2ammo = Tier2ammo;
this.tierInformation.tier3ammo = Tier3ammo;
this.tierInformation.tier4ammo = Tier4ammo;
this.tierInformation.tier5ammo = Tier5ammo;
this.tierInformation.tier6ammo = Tier6ammo;
this.tierInformation.tier7ammo = Tier7ammo;
this.tierInformation.tier0appearance = Tier0appearance;
this.tierInformation.tier1appearance = Tier1appearance;
this.tierInformation.tier2appearance = Tier2appearance;
this.tierInformation.tier3appearance = Tier3appearance;
this.tierInformation.tier4appearance = Tier4appearance;
this.tierInformation.tier5appearance = Tier5appearance;
this.tierInformation.tier6appearance = Tier6appearance;
this.tierInformation.tier7appearance = Tier7appearance;
}
public usePreset(presetName: string): void
{
const folderName = presetName;
const presetFolder = path.join(path.dirname(__filename), "..", "..", "presets");
const folderPath = path.join(presetFolder, folderName);
if (!fs.existsSync(folderPath))
{
this.missingPresetFolder(folderName, presetFolder);
return;
}
const files = fs.readdirSync(folderPath);
if (files.length < 35)
{
this.missingFileCount(folderName, 0);
return;
}
if (files.length > 35)
{
this.missingFileCount(folderName, 1);
return;
}
this.raidInformation.usingDefaultDB = false;
for (const item of files)
{
const filePath = path.join(folderPath, item);
this.mapFileToTierType(filePath, folderName, item)
}
if (this.count == 35) this.apbsLogger.log(Logging.WARN, `"${folderName}" preset loaded...`);
}
private mapFileToTierType(filePath: string, folderName: string, item: string): void
{
let tier = 0;
let type = "none";
if (item.includes("1")) tier = 1;
if (item.includes("2")) tier = 2;
if (item.includes("3")) tier = 3;
if (item.includes("4")) tier = 4;
if (item.includes("5")) tier = 5;
if (item.includes("6")) tier = 6;
if (item.includes("7")) tier = 7;
if (tier == 0)
{
this.invalidFileName(folderName, item);
return;
}
if (item.includes("equipment")) type = "equipment";
if (item.includes("mods")) type = "mods";
if (item.includes("chances")) type = "chances";
if (item.includes("ammo")) type = "ammo";
if (item.includes("appearance")) type = "appearance";
if (type == "none")
{
this.invalidFileName(folderName, item);
return;
}
this.configureTierType(filePath, tier, type);
}
private configureTierType(filePath: string, tier: number, type: string):void
{
this.count++;
this.tierInformation.tier0 = Tier0equipment;
this.tierInformation.tier0mods = Tier0mods;
this.tierInformation.tier0chances = Tier0chances;
this.tierInformation.tier0ammo = Tier0ammo;
this.tierInformation.tier0appearance = Tier0appearance;
switch (true)
{
case tier == 1 && type == "equipment":
this.tierInformation.tier1 = require(filePath);
return;
case tier == 2 && type == "equipment":
this.tierInformation.tier2 = require(filePath);
return;
case tier == 3 && type == "equipment":
this.tierInformation.tier3 = require(filePath);
return;
case tier == 4 && type == "equipment":
this.tierInformation.tier4 = require(filePath);
return;
case tier == 5 && type == "equipment":
this.tierInformation.tier5 = require(filePath);
return;
case tier == 6 && type == "equipment":
this.tierInformation.tier6 = require(filePath);
return;
case tier == 7 && type == "equipment":
this.tierInformation.tier7 = require(filePath);
return;
case tier == 1 && type == "mods":
this.tierInformation.tier1mods = require(filePath);
return;
case tier == 2 && type == "mods":
this.tierInformation.tier2mods = require(filePath);
return;
case tier == 3 && type == "mods":
this.tierInformation.tier3mods = require(filePath);
return;
case tier == 4 && type == "mods":
this.tierInformation.tier4mods = require(filePath);
return;
case tier == 5 && type == "mods":
this.tierInformation.tier5mods = require(filePath);
return;
case tier == 6 && type == "mods":
this.tierInformation.tier6mods = require(filePath);
return;
case tier == 7 && type == "mods":
this.tierInformation.tier7mods = require(filePath);
return;
case tier == 1 && type == "chances":
this.tierInformation.tier1chances = require(filePath);
return;
case tier == 2 && type == "chances":
this.tierInformation.tier2chances = require(filePath);
return;
case tier == 3 && type == "chances":
this.tierInformation.tier3chances = require(filePath);
return;
case tier == 4 && type == "chances":
this.tierInformation.tier4chances = require(filePath);
return;
case tier == 5 && type == "chances":
this.tierInformation.tier5chances = require(filePath);
return;
case tier == 6 && type == "chances":
this.tierInformation.tier6chances = require(filePath);
return;
case tier == 7 && type == "chances":
this.tierInformation.tier7chances = require(filePath);
return;
case tier == 1 && type == "ammo":
this.tierInformation.tier1ammo = require(filePath);
return;
case tier == 2 && type == "ammo":
this.tierInformation.tier2ammo = require(filePath);
return;
case tier == 3 && type == "ammo":
this.tierInformation.tier3ammo = require(filePath);
return;
case tier == 4 && type == "ammo":
this.tierInformation.tier4ammo = require(filePath);
return;
case tier == 5 && type == "ammo":
this.tierInformation.tier5ammo = require(filePath);
return;
case tier == 6 && type == "ammo":
this.tierInformation.tier6ammo = require(filePath);
return;
case tier == 7 && type == "ammo":
this.tierInformation.tier7ammo = require(filePath);
return;
case tier == 1 && type == "appearance":
this.tierInformation.tier1appearance = require(filePath);
return;
case tier == 2 && type == "appearance":
this.tierInformation.tier2appearance = require(filePath);
return;
case tier == 3 && type == "appearance":
this.tierInformation.tier3appearance = require(filePath);
return;
case tier == 4 && type == "appearance":
this.tierInformation.tier4appearance = require(filePath);
return;
case tier == 5 && type == "appearance":
this.tierInformation.tier5appearance = require(filePath);
return;
case tier == 6 && type == "appearance":
this.tierInformation.tier6appearance = require(filePath);
return;
case tier == 7 && type == "appearance":
this.tierInformation.tier7appearance = require(filePath);
return;
}
}
private missingFileCount(folderName: string, errorType: number): void
{
const error = errorType == 0 ? "Missing files" : "Extra files found";
this.raidInformation.usingDefaultDB = true;
this.apbsLogger.log(Logging.ERR, `Preset name "${folderName}" is invalid.`);
this.apbsLogger.log(Logging.ERR, `${error}. Report issue to author of preset.`);
this.apbsLogger.log(Logging.WARN, "Using APBS database instead of preset...");
this.buildTierJson();
}
private invalidFileName(folderName: string, item: string): void
{
this.raidInformation.usingDefaultDB = true;
this.apbsLogger.log(Logging.ERR, `Preset name "${folderName}" is invalid.`);
this.apbsLogger.log(Logging.ERR, `"${item}" is incorrectly named. Report issue to author of preset.`);
this.apbsLogger.log(Logging.WARN, "Using APBS database instead of preset...");
this.buildTierJson();
}
private missingPresetFolder(folderName: string, presetFolder: string): void
{
this.raidInformation.usingDefaultDB = true;
this.apbsLogger.log(Logging.ERR, `Preset name "${folderName}" is invalid.`);
this.apbsLogger.log(Logging.ERR, `Verify the preset folder exists in "${presetFolder}" and is named properly.`);
this.apbsLogger.log(Logging.WARN, "Using APBS database instead of preset...");
this.buildTierJson();
}
}

View File

@ -0,0 +1,672 @@
/* eslint-disable @typescript-eslint/quotes */
import { injectable, inject } from "tsyringe";
import { ItemHelper } from "@spt/helpers/ItemHelper";
import { BaseClasses } from "@spt/models/enums/BaseClasses";
import { IDatabaseTables } from "@spt/models/spt/server/IDatabaseTables";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import { DatabaseService } from "@spt/services/DatabaseService";
import { ICustomizationItem } from "@spt/models/eft/common/tables/ICustomizationItem";
import { ModConfig } from "../Globals/ModConfig";
import { vanillaItemList, vanillaClothingList } from "../Globals/VanillaItemLists";
import { APBSLogger } from "../Utils/APBSLogger";
import { Logging } from "../Enums/Logging";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { TierInformation } from "../Globals/TierInformation";
import { APBSAttachmentChecker } from "../Utils/APBSAttachmentChecker";
@injectable()
export class ModdedImportHelper
{
private blacklist: any[];
private attachmentBlacklist: any[];
private clothingBlacklist: any[];
constructor(
@inject("IDatabaseTables") protected tables: IDatabaseTables,
@inject("DatabaseService") protected databaseService: DatabaseService,
@inject("ItemHelper") protected itemHelper: ItemHelper,
@inject("TierInformation") protected tierInformation: TierInformation,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("APBSAttachmentChecker") protected apbsAttachmentChecker: APBSAttachmentChecker,
@inject("APBSLogger") protected apbsLogger: APBSLogger
)
{
this.blacklist = [
"5ae083b25acfc4001a5fc702", //weapons
"5e81ebcd8e146c7080625e15",
"6217726288ed9f0845317459",
"5d52cc5ba4b9367408500062",
"620109578d82e67e7911abf2",
"639af924d0446708ee62294e",
"657857faeff4c850222dff1b",
"639c3fbbd0446708ee622ee9",
"62178be9d0050232da3485d9",
"62178c4d4ecf221597654e3d",
"624c0b3340357b5f566e8766",
"5cdeb229d7f00c000e7ce174",
"579204f224597773d619e051",
"6275303a9f372d6ea97f9ec7",
"66015072e9f84d5680039678",
"59f9cabd86f7743a10721f46",
"5abccb7dd8ce87001773e277",
"5b3b713c5acfc4330140bd8d",
"66d98233302686954b0c6f81",
"66d9f1abb16d9aacf5068468",
"56e33634d2720bd8058b456b", //backpacks
"5e4abc6786f77406812bd572",
"5e997f0b86f7741ac73993e2",
"61b9e1aaef9a1b5d6a79899a",
"61c18db6dfd64163ea78fbb4", //headwear
"66bdc28a0b603c26902b2011",
"65749cb8e0423b9ebe0c79c9",
"60a7acf20c5cb24b01346648",
"636270263f2495c26f00b007",
"5a43943586f77416ad2f06e2",
"5a43957686f7742a2c2f11b0",
"65749ccf33fdc9c0cf06d3ca",
"5a16bb52fcdbcb001a3b00dc",
"628e4dd1f477aa12234918aa",
"5c066ef40db834001966a595",
"59ef13ca86f77445fd0e2483",
"6531119b9afebff7ff0a1769"
]
this.attachmentBlacklist = [
"5c110624d174af029e69734c",
"5d1b5e94d7ad1a2b865a96b0",
"6478641c19d732620e045e17",
"5a1eaa87fcdbcb001865f75e",
"609bab8b455afd752b2e6138",
"63fc44e2429a8a166c7f61e6",
"5a1ead28fcdbcb001912fa9f",
"63fc449f5bd61c6cf3784a88",
"5b3b6dc75acfc47a8773fb1e",
"5c11046cd174af02a012e42b",
"544a3f024bdc2d1d388b4568",
"544a3d0a4bdc2d1b388b4567",
"5648b62b4bdc2d9d488b4585",
"5c0e2ff6d174af02a1659d4a",
"5c0e2f5cd174af02a012cfc9",
"5c6592372e221600133e47d7",
"544a378f4bdc2d30388b4567",
"5d1340bdd7ad1a0e8d245aab",
"671d85439ae8365d69117ba6",
"670e8eab8c1bb0e5a7075acf",
"671d8617a3e45c1f5908278c",
"671d8ac8a3e45c1f59082799",
"671d8b38b769f0d88c0950f8",
"671d8b8c0959c721a50ca838"
]
this.clothingBlacklist = [
"668bc5cd834c88e06b08b645", // All of this is Artem hands, because they are being configured as Body instead...Crackboooonnneee!!
"668bc5cd834c88e06b08b64a",
"668bc5cd834c88e06b08b64d",
"668bc5cd834c88e06b08b650",
"668bc5cd834c88e06b08b652",
"668bc5cd834c88e06b08b655",
"668bc5cd834c88e06b08b658",
"668bc5cd834c88e06b08b65b",
"668bc5cd834c88e06b08b65e",
"668bc5cd834c88e06b08b662",
"668bc5cd834c88e06b08b665",
"668bc5cd834c88e06b08b668",
"668bc5cd834c88e06b08b66b",
"668bc5cd834c88e06b08b66e",
"668bc5cd834c88e06b08b671",
"668bc5cd834c88e06b08b674",
"668bc5cd834c88e06b08b677",
"668bc5cd834c88e06b08b67a",
"668bc5cd834c88e06b08b67d"
]
}
public tiersTable = [];
public initialize():void
{
if (ModConfig.config.initalTierAppearance < 1 || ModConfig.config.initalTierAppearance > 7)
{
this.apbsLogger.log(Logging.WARN, `Config value for "initialTierAppearance" is invalid. Must be 1-7. Currently configured for ${ModConfig.config.initalTierAppearance}`)
return;
}
if (ModConfig.config.enableModdedWeapons) this.buildVanillaWeaponList();
if (ModConfig.config.enableModdedEquipment) this.buildVanillaEquipmentList();
if (ModConfig.config.enableModdedClothing && !ModConfig.config.seasonalPmcAppearance) this.buildVanillaClothingList();
}
private buildVanillaWeaponList(): void
{
this.apbsLogger.log(Logging.WARN, "Checking & importing Modded Weapons...Support not granted for this feature...")
// Build the joined list for every weapon used in APBS
const weapons: ITemplateItem = {};
vanillaItemList.equipment.LongRange.forEach(element => weapons[element] = this.getItem(element))
vanillaItemList.equipment.ShortRange.forEach(element => weapons[element] = this.getItem(element))
vanillaItemList.equipment.Holster.forEach(element => weapons[element] = this.getItem(element))
vanillaItemList.equipment.Scabbard.forEach(element => weapons[element] = this.getItem(element))
// Push this list to the function to filter and import
this.getModdedItems(weapons, BaseClasses.WEAPON, "Weapons");
}
private buildVanillaEquipmentList(): void
{
this.apbsLogger.log(Logging.WARN, "Checking & importing Modded Equipment...Support not granted for this feature...")
// Build the joined list for every armour type used in APBS
const armours: ITemplateItem = {};
vanillaItemList.equipment.ArmorVest.forEach(element => armours[element] = this.getItem(element))
const headwear: ITemplateItem = {};
vanillaItemList.equipment.Headwear.forEach(element => headwear[element] = this.getItem(element))
const tacticalVests: ITemplateItem = {};
vanillaItemList.equipment.TacticalVest.forEach(element => tacticalVests[element] = this.getItem(element))
// Push these lists to the function to filter and import
this.getModdedItems(armours, BaseClasses.ARMOR, "Armours");
this.getModdedItems(headwear, BaseClasses.HEADWEAR, "Helmets");
this.getModdedItems(tacticalVests, BaseClasses.VEST, "Vests");
}
private buildVanillaClothingList(): void
{
this.apbsLogger.log(Logging.WARN, "Checking & importing Modded Clothing...Support not granted for this feature...")
// Build the joined list for every body & feet type used in APBS
const body: ICustomizationItem = {};
vanillaClothingList.appearance.body.forEach(element => body[element] = this.getCustomization(element))
const feet: ICustomizationItem = {};
vanillaClothingList.appearance.feet.forEach(element => feet[element] = this.getCustomization(element))
// Push these lists to the function to filter and import
this.getModdedClothing(body, "Body");
this.getModdedClothing(feet, "Feet");
}
private getModdedClothing(clothingList: ICustomizationItem, className: string): void
{
// Compare SPT database values to APBS values, filter down to the difference (assuming they are either modded, or not in the APBS database).
const databaseClothing = Object.values(this.databaseService.getTables().templates.customization);
const allClothing = databaseClothing.filter(x => this.isCustomization(x._id, className));
const moddedClothing = Object.values(clothingList);
const allApbsClothing = moddedClothing.filter(x => this.isCustomization(x._id, className));
let clothingToBeImported = allClothing.filter(x => !allApbsClothing.includes(x));
// Filter out blacklisted items
for (const item of clothingToBeImported)
{
if (this.clothingBlacklist.includes(item._id)) clothingToBeImported = clothingToBeImported.filter(id => id._id != item._id)
}
// Push clothing to APBS database
if (clothingToBeImported.length > 0)
{
this.apbsLogger.log(Logging.WARN, `Importing ${clothingToBeImported.length} Modded ${className}...`)
this.pushClothing(clothingToBeImported);
}
}
private pushClothing(clothingList: ICustomizationItem[]): void
{
// Loop each tier to add clothing to every tier
for (const object in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[object].tier
const tierJson = this.apbsEquipmentGetter.getAppearanceJson(tierNumber, true);
// Skip tiers based on configuration
if (tierNumber < ModConfig.config.initalTierAppearance) continue;
// Add each item from the clothing list to each tier JSON - this completes the import
for (const item in clothingList)
{
if (clothingList[item]._props.Side.includes("Bear"))
{
if (clothingList[item]._props.BodyPart == "Feet") tierJson.pmcBEAR.appearance.feet[clothingList[item]._id] = 1
if (clothingList[item]._props.BodyPart == "Body") tierJson.pmcBEAR.appearance.body[clothingList[item]._id] = 1
}
if (clothingList[item]._props.Side.includes("Usec"))
{
if (clothingList[item]._props.BodyPart == "Feet") tierJson.pmcUSEC.appearance.feet[clothingList[item]._id] = 1
if (clothingList[item]._props.BodyPart == "Body") tierJson.pmcUSEC.appearance.body[clothingList[item]._id] = 1
}
}
}
}
private getModdedItems(equipmentList: ITemplateItem, baseClass: BaseClasses, className: string): void
{
// Compare SPT database values to APBS values, filter down to the difference (assuming they are either modded, or not in the APBS database).
const items = Object.values(this.tables.templates.items);
const allItems = items.filter(x => this.itemHelper.isOfBaseclass(x._id, baseClass));
const tieredItems = Object.values(equipmentList);
const allTieredItems = tieredItems.filter(x => this.itemHelper.isOfBaseclass(x._id, baseClass));
let itemsToBeImported = allItems.filter(x => !allTieredItems.includes(x));
// Filter out blacklisted items
for (const item of itemsToBeImported)
{
if (this.blacklist.includes(item._id)) itemsToBeImported = itemsToBeImported.filter(id => id._id != item._id)
}
// Push items to APBS database depending on if they are weapons or equipment
if (itemsToBeImported.length > 0)
{
this.apbsLogger.log(Logging.WARN, `Importing ${itemsToBeImported.length} Modded ${className}...`)
if (baseClass == BaseClasses.WEAPON) this.getSetModdedWeaponDetails(itemsToBeImported);
if (baseClass != BaseClasses.WEAPON) this.getSetModdedEquipmentDetails(itemsToBeImported);
}
}
private getSetModdedWeaponDetails(weaponPool: ITemplateItem[]): void
{
// Loop each weapon in the pool of weapons to be imported - push them individually
for (const weapon in weaponPool)
{
const weaponParent = weaponPool[weapon]._parent;
const weaponId = weaponPool[weapon]._id;
const weaponSlots = weaponPool[weapon]?._props?.Slots;
const weaponType = weaponPool[weapon]?._props?.weapUseType;
// Push Weapon details to relevant pools
this.pushCalibersToAmmoPools(weaponId)
this.pushWeaponToTiers(weaponId, weaponType, weaponParent);
this.pushItemAndPrimaryMods(weaponId, weaponSlots);
}
}
private getSetModdedEquipmentDetails(equipmentPool: ITemplateItem[]): void
{
// Loop each equipment in the pool of equipment to be imported - push them individually
for (const equipment in equipmentPool)
{
const equipmentParent = equipmentPool[equipment]._parent;
const equipmentId = equipmentPool[equipment]._id;
const equipmentSlots = equipmentPool[equipment]?._props?.Slots;
const equipmentSlotsLength = equipmentPool[equipment]?._props?.Slots.length;
const gridLength = equipmentPool[equipment]?._props?.Grids.length;
let equipmentSlot: string;
// Set equipmentSlot string to the proper value - this is only done to separate TacticalVests & ArmouredRigs
if (equipmentParent == "5448e5284bdc2dcb718b4567" && (equipmentSlots.length == 0 || equipmentSlots == undefined)) equipmentSlot = "TacticalVest"
if (equipmentParent == "5448e5284bdc2dcb718b4567" && equipmentSlots.length >= 1) equipmentSlot = "ArmouredRig"
if (equipmentParent == "5448e54d4bdc2dcc718b4568") equipmentSlot = "ArmorVest"
if (equipmentParent == "5a341c4086f77401f2541505") equipmentSlot = "Headwear"
// Push Equipment details to relevant pools
this.pushEquipmentToTiers(equipmentId, equipmentSlot, gridLength, equipmentSlotsLength);
this.pushItemAndPrimaryMods(equipmentId, equipmentSlots);
}
}
private pushWeaponToTiers(weaponId: string, weaponType: string, parentClass: string): void
{
// Define weights to use, and which range they go to (for logging).
let range = "";
const pmcWeight = ModConfig.config.pmcWeaponWeights <= 0 ? 1 : ModConfig.config.pmcWeaponWeights;
const scavWeight = ModConfig.config.scavWeaponWeights <= 0 ? 1 : ModConfig.config.scavWeaponWeights;
const defaultWeight = ModConfig.config.followerWeaponWeights <= 0 ? 1 : ModConfig.config.followerWeaponWeights;
// Loop over each tier to easily use the proper tierJSON
for (const object in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[object].tier
const tierJson = this.apbsEquipmentGetter.getTierJson(tierNumber, true);
// Skip tiers based on configuration
if (tierNumber < ModConfig.config.initalTierAppearance) continue;
// Use multiple variable switch to set specific weapon "types" to the correct pool
switch (true)
{
case parentClass == "5447b5fc4bdc2d87278b4567" && weaponType == "primary":
tierJson.pmcUSEC.equipment.FirstPrimaryWeapon.LongRange[weaponId] = pmcWeight
tierJson.pmcUSEC.equipment.FirstPrimaryWeapon.ShortRange[weaponId] = pmcWeight
tierJson.pmcUSEC.equipment.SecondPrimaryWeapon.LongRange[weaponId] = pmcWeight
tierJson.pmcUSEC.equipment.SecondPrimaryWeapon.ShortRange[weaponId] = pmcWeight
tierJson.pmcBEAR.equipment.FirstPrimaryWeapon.LongRange[weaponId] = pmcWeight
tierJson.pmcBEAR.equipment.FirstPrimaryWeapon.ShortRange[weaponId] = pmcWeight
tierJson.pmcBEAR.equipment.SecondPrimaryWeapon.LongRange[weaponId] = pmcWeight
tierJson.pmcBEAR.equipment.SecondPrimaryWeapon.ShortRange[weaponId] = pmcWeight
tierJson.scav.equipment.FirstPrimaryWeapon.LongRange[weaponId] = scavWeight
tierJson.scav.equipment.FirstPrimaryWeapon.ShortRange[weaponId] = scavWeight
tierJson.scav.equipment.SecondPrimaryWeapon.LongRange[weaponId] = scavWeight
tierJson.scav.equipment.SecondPrimaryWeapon.ShortRange[weaponId] = scavWeight
tierJson.default.equipment.FirstPrimaryWeapon.LongRange[weaponId] = defaultWeight
tierJson.default.equipment.FirstPrimaryWeapon.ShortRange[weaponId] = defaultWeight
tierJson.default.equipment.SecondPrimaryWeapon.LongRange[weaponId] = defaultWeight
tierJson.default.equipment.SecondPrimaryWeapon.ShortRange[weaponId] = defaultWeight
range = "Long & Short range";
continue;
case parentClass == "5447b6254bdc2dc3278b4568" && weaponType == "primary":
case parentClass == "5447b6194bdc2d67278b4567" && weaponType == "primary":
tierJson.pmcUSEC.equipment.FirstPrimaryWeapon.LongRange[weaponId] = pmcWeight
tierJson.pmcUSEC.equipment.SecondPrimaryWeapon.LongRange[weaponId] = pmcWeight
tierJson.pmcBEAR.equipment.FirstPrimaryWeapon.LongRange[weaponId] = pmcWeight
tierJson.pmcBEAR.equipment.SecondPrimaryWeapon.LongRange[weaponId] = pmcWeight
tierJson.scav.equipment.FirstPrimaryWeapon.LongRange[weaponId] = scavWeight
tierJson.scav.equipment.SecondPrimaryWeapon.LongRange[weaponId] = scavWeight
tierJson.default.equipment.FirstPrimaryWeapon.LongRange[weaponId] = defaultWeight
tierJson.default.equipment.SecondPrimaryWeapon.LongRange[weaponId] = defaultWeight
range = "Long range"
continue;
case parentClass == "5447b5f14bdc2d61278b4567" && weaponType == "primary":
case parentClass == "5447bed64bdc2d97278b4568" && weaponType == "primary":
case parentClass == "5447b5e04bdc2d62278b4567" && weaponType == "primary":
case parentClass == "5447b5cf4bdc2d65278b4567" && weaponType == "primary":
case parentClass == "617f1ef5e8b54b0998387733" && weaponType == "primary":
case parentClass == "5447b6094bdc2dc3278b4567" && weaponType == "primary":
tierJson.pmcUSEC.equipment.FirstPrimaryWeapon.ShortRange[weaponId] = pmcWeight
tierJson.pmcUSEC.equipment.SecondPrimaryWeapon.ShortRange[weaponId] = pmcWeight
tierJson.pmcBEAR.equipment.FirstPrimaryWeapon.ShortRange[weaponId] = pmcWeight
tierJson.pmcBEAR.equipment.SecondPrimaryWeapon.ShortRange[weaponId] = pmcWeight
tierJson.scav.equipment.FirstPrimaryWeapon.ShortRange[weaponId] = scavWeight
tierJson.scav.equipment.SecondPrimaryWeapon.ShortRange[weaponId] = scavWeight
tierJson.default.equipment.FirstPrimaryWeapon.ShortRange[weaponId] = defaultWeight
tierJson.default.equipment.SecondPrimaryWeapon.ShortRange[weaponId] = defaultWeight
range = "Short range"
continue;
case parentClass == "5447b5cf4bdc2d65278b4567" && weaponType == "secondary":
case parentClass == "617f1ef5e8b54b0998387733" && weaponType == "secondary":
case parentClass == "5447b6094bdc2dc3278b4567" && weaponType == "secondary":
tierJson.pmcUSEC.equipment.Holster[weaponId] = 5
tierJson.pmcBEAR.equipment.Holster[weaponId] = 5
tierJson.scav.equipment.Holster[weaponId] = 1
tierJson.default.equipment.Holster[weaponId] = 3
range = "Holster"
continue;
default:
if (weaponType == "primary")
{
tierJson.pmcUSEC.equipment.FirstPrimaryWeapon.LongRange[weaponId] = pmcWeight
tierJson.pmcUSEC.equipment.FirstPrimaryWeapon.ShortRange[weaponId] = pmcWeight
tierJson.pmcUSEC.equipment.SecondPrimaryWeapon.LongRange[weaponId] = pmcWeight
tierJson.pmcUSEC.equipment.SecondPrimaryWeapon.ShortRange[weaponId] = pmcWeight
tierJson.pmcBEAR.equipment.FirstPrimaryWeapon.LongRange[weaponId] = pmcWeight
tierJson.pmcBEAR.equipment.FirstPrimaryWeapon.ShortRange[weaponId] = pmcWeight
tierJson.pmcBEAR.equipment.SecondPrimaryWeapon.LongRange[weaponId] = pmcWeight
tierJson.pmcBEAR.equipment.SecondPrimaryWeapon.ShortRange[weaponId] = pmcWeight
tierJson.scav.equipment.FirstPrimaryWeapon.LongRange[weaponId] = scavWeight
tierJson.scav.equipment.FirstPrimaryWeapon.ShortRange[weaponId] = scavWeight
tierJson.scav.equipment.SecondPrimaryWeapon.LongRange[weaponId] = scavWeight
tierJson.scav.equipment.SecondPrimaryWeapon.ShortRange[weaponId] = scavWeight
tierJson.default.equipment.SecondPrimaryWeapon.LongRange[weaponId] = defaultWeight
tierJson.default.equipment.SecondPrimaryWeapon.ShortRange[weaponId] = defaultWeight
tierJson.default.equipment.FirstPrimaryWeapon.LongRange[weaponId] = defaultWeight
tierJson.default.equipment.FirstPrimaryWeapon.ShortRange[weaponId] = defaultWeight
range = "Long & Short range"
}
if (weaponType == "secondary")
{
tierJson.pmcUSEC.equipment.Holster[weaponId] = 5
tierJson.pmcBEAR.equipment.Holster[weaponId] = 5
tierJson.scav.equipment.Holster[weaponId] = 1
tierJson.default.equipment.Holster[weaponId] = 3
range = "Holster"
}
continue;
}
}
this.apbsLogger.log(Logging.DEBUG, `[Tier${ModConfig.config.initalTierAppearance}+] Added ${weaponId} to ${range} weapons.`)
}
private pushEquipmentToTiers(itemID: string, equipmentSlot: string, gridLength: number, equipmentSlotsLength: number): void
{
// Loop over each tier to easily use the proper tierJSON
for (const object in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[object].tier
const tierJson = this.apbsEquipmentGetter.getTierJson(tierNumber, true);
// Skip tiers based on configuration
if (tierNumber < ModConfig.config.initalTierAppearance) continue;
// Set weights based on witch slot they are in. Check TacticalVests for belts (low grid count) and check Helmets to see if armoured or decorative
let weight;
if (equipmentSlot == "TacticalVest" && gridLength > 10) weight = 10;
if (equipmentSlot == "TacticalVest" && gridLength <= 10) weight = 1;
if (equipmentSlot == "ArmouredRig") weight = 7;
if (equipmentSlot == "ArmorVest") weight = 10;
if (equipmentSlot == "Headwear" && equipmentSlotsLength > 0) weight = 6;
if (equipmentSlot == "Headwear" && equipmentSlotsLength == 0) weight = 1;
// Add the equipment to the proper slot and correct weight
tierJson.pmcUSEC.equipment[equipmentSlot][itemID] = weight
tierJson.pmcBEAR.equipment[equipmentSlot][itemID] = weight
tierJson.scav.equipment[equipmentSlot][itemID] = 1
tierJson.default.equipment[equipmentSlot][itemID] = weight
}
this.apbsLogger.log(Logging.DEBUG, `[Tier${ModConfig.config.initalTierAppearance}+] Added ${itemID} to ${equipmentSlot}.`)
}
private pushItemAndPrimaryMods(itemID, itemSlots): void
{
// Loop over all slots of the item
for (const slot in itemSlots)
{
const slotName = itemSlots[slot]?._name;
const slotFilter = itemSlots[slot]?._props?.filters[0]?.Filter
// Loop over all items in the filter for the slot
for (const item in slotFilter)
{
const slotFilterItem = slotFilter[item];
// Check if the item is actually a valid item, or is on the blacklist
// WTT puts itemIDs in their mods that don't exist in the database for some reason (probably unreleased mods)
const itemExistsCheck = this.itemHelper.getItem(slotFilterItem)
if (this.attachmentBlacklist.includes(slotFilterItem) || !itemExistsCheck[0]) continue;
// Check if the itemID already exists in the tierJsons, if not - create it in them all.
if (this.tierInformation.tier1mods[itemID] == undefined)
{
this.tierInformation.tier1mods[itemID] = {};
this.tierInformation.tier2mods[itemID] = {};
this.tierInformation.tier3mods[itemID] = {};
this.tierInformation.tier4mods[itemID] = {};
this.tierInformation.tier5mods[itemID] = {};
this.tierInformation.tier6mods[itemID] = {};
this.tierInformation.tier7mods[itemID] = {};
}
// Check if the itemID's slot already exists in the tierJsons, if not - create it in them all.
if (this.tierInformation.tier1mods[itemID][slotName] == undefined)
{
this.tierInformation.tier1mods[itemID][slotName] = [];
this.tierInformation.tier2mods[itemID][slotName] = [];
this.tierInformation.tier3mods[itemID][slotName] = [];
this.tierInformation.tier4mods[itemID][slotName] = [];
this.tierInformation.tier5mods[itemID][slotName] = [];
this.tierInformation.tier6mods[itemID][slotName] = [];
this.tierInformation.tier7mods[itemID][slotName] = [];
}
// Check if the itemID's slot doesn't already contain the item to import, if it doesn't - add it
if (!this.tierInformation.tier1mods[itemID][slotName].includes(slotFilterItem))
{
this.tierInformation.tier1mods[itemID][slotName].push(slotFilterItem);
this.tierInformation.tier2mods[itemID][slotName].push(slotFilterItem);
this.tierInformation.tier3mods[itemID][slotName].push(slotFilterItem);
this.tierInformation.tier4mods[itemID][slotName].push(slotFilterItem);
this.tierInformation.tier5mods[itemID][slotName].push(slotFilterItem);
this.tierInformation.tier6mods[itemID][slotName].push(slotFilterItem);
this.tierInformation.tier7mods[itemID][slotName].push(slotFilterItem);
// Push any children mods
this.recursivePushChildrenMods(slotFilterItem);
}
}
}
}
private recursivePushChildrenMods(parentSlotFilterItem)
{
const parentSlotItemData = this.getItem(parentSlotFilterItem);
const parentSlotItemID = parentSlotItemData?._id;
const parentSlotSlots = parentSlotItemData?._props?.Slots;
// Exit if there are no children
if (parentSlotSlots == undefined || parentSlotSlots.length == 0) return;
// Loop over all slots of the parent
for (const slot in parentSlotSlots)
{
const slotName = parentSlotSlots[slot]?._name;
let slotFilter = parentSlotSlots[slot]?._props?.filters[0]?.Filter;
// If a slot's filters contain the canted sight mount, remove all other items from the filter - this ensures ONLY the canted sight is added
if (slotFilter.includes("5649a2464bdc2d91118b45a8"))
{
slotFilter = [ "5649a2464bdc2d91118b45a8" ];
}
// Loop over each item in the slot's filters
for (const item in slotFilter)
{
const slotFilterItem = parentSlotSlots[slot]?._props?.filters[0]?.Filter[item];
const itemExistsCheck = this.itemHelper.getItem(slotFilterItem)
// Check if the item is actually a valid item, or is on the blacklist
// WTT puts itemIDs in their mods that don't exist in the database for some reason (probably unreleased mods)
if (this.attachmentBlacklist.includes(slotFilterItem) || !itemExistsCheck[0]) continue;
// Check if the parent mod & the child mod are vanilla or modded
// This allows preventing mods adding vanilla mods to vanilla weapons
const isVanillaParent = this.apbsAttachmentChecker.isVanillaItem(parentSlotItemID);
const isVanillaItem = this.apbsAttachmentChecker.isVanillaItem(slotFilterItem);
// Check if the PARENT itemID already exists in the tierJsons, if not - create it in all tierJSONs.
if (this.tierInformation.tier1mods[parentSlotItemID] == undefined)
{
this.tierInformation.tier1mods[parentSlotItemID] = {};
this.tierInformation.tier2mods[parentSlotItemID] = {};
this.tierInformation.tier3mods[parentSlotItemID] = {};
this.tierInformation.tier4mods[parentSlotItemID] = {};
this.tierInformation.tier5mods[parentSlotItemID] = {};
this.tierInformation.tier6mods[parentSlotItemID] = {};
this.tierInformation.tier7mods[parentSlotItemID] = {};
}
// Check if the PARENT itemID already exists with the slotName, if not - create it in all tierJSONs
if (this.tierInformation.tier1mods[parentSlotItemID][slotName] == undefined)
{
this.tierInformation.tier1mods[parentSlotItemID][slotName] = [];
this.tierInformation.tier2mods[parentSlotItemID][slotName] = [];
this.tierInformation.tier3mods[parentSlotItemID][slotName] = [];
this.tierInformation.tier4mods[parentSlotItemID][slotName] = [];
this.tierInformation.tier5mods[parentSlotItemID][slotName] = [];
this.tierInformation.tier6mods[parentSlotItemID][slotName] = [];
this.tierInformation.tier7mods[parentSlotItemID][slotName] = [];
}
// Check if the PARENT itemID's slot doesn't already contain the item to import
if (!this.tierInformation.tier1mods[parentSlotItemID][slotName].includes(slotFilterItem))
{
// Additionally, check if the parent mod & child mod are vanilla as well as checking the config safeguard
if (isVanillaParent && isVanillaItem && ModConfig.config.enableSafeGuard) continue;
// Finally push the child mod to the proper tierJSONs
this.tierInformation.tier1mods[parentSlotItemID][slotName].push(slotFilterItem)
this.tierInformation.tier2mods[parentSlotItemID][slotName].push(slotFilterItem)
this.tierInformation.tier3mods[parentSlotItemID][slotName].push(slotFilterItem)
this.tierInformation.tier4mods[parentSlotItemID][slotName].push(slotFilterItem)
this.tierInformation.tier5mods[parentSlotItemID][slotName].push(slotFilterItem)
this.tierInformation.tier6mods[parentSlotItemID][slotName].push(slotFilterItem)
this.tierInformation.tier7mods[parentSlotItemID][slotName].push(slotFilterItem)
// Push any children mods
this.recursivePushChildrenMods(slotFilterItem);
}
}
}
}
private pushCalibersToAmmoPools(itemID: string): void
{
const itemDetails = this.itemHelper.getItem(itemID)
const itemCaliber = itemDetails[1]?._props?.ammoCaliber
// Check if the Caliber exists on tierJSON or is valid
if (!Object.keys(this.tierInformation.tier1ammo.scavAmmo).includes(itemCaliber) && itemCaliber != undefined)
{
const chamberFilter = itemDetails[1]?._props?.Chambers[0]?._props?.filters[0]?.Filter
// If the chamber is valid and has items, add them to the tierJSONs
if (chamberFilter && chamberFilter.length > 0)
{
for (const botPool in this.tierInformation.tier1ammo)
{
// Since the Caliber doesn't exist, create them empty to prevent undefined error below
this.tierInformation.tier1ammo[botPool][itemCaliber] = {};
this.tierInformation.tier2ammo[botPool][itemCaliber] = {};
this.tierInformation.tier3ammo[botPool][itemCaliber] = {};
this.tierInformation.tier4ammo[botPool][itemCaliber] = {};
this.tierInformation.tier5ammo[botPool][itemCaliber] = {};
this.tierInformation.tier6ammo[botPool][itemCaliber] = {};
this.tierInformation.tier7ammo[botPool][itemCaliber] = {};
// Push each item in the filter to the tierJSON
for (const item in chamberFilter)
{
const ammo = chamberFilter[item]
this.tierInformation.tier1ammo[botPool][itemCaliber][ammo] = 1;
this.tierInformation.tier2ammo[botPool][itemCaliber][ammo] = 1;
this.tierInformation.tier3ammo[botPool][itemCaliber][ammo] = 1;
this.tierInformation.tier4ammo[botPool][itemCaliber][ammo] = 1;
this.tierInformation.tier5ammo[botPool][itemCaliber][ammo] = 1;
this.tierInformation.tier6ammo[botPool][itemCaliber][ammo] = 1;
this.tierInformation.tier7ammo[botPool][itemCaliber][ammo] = 1;
}
}
}
}
}
private getItem(tpl: string): ITemplateItem
{
if (tpl in this.databaseService.getItems())
{
return this.databaseService.getItems()[tpl];
}
return undefined;
}
private getCustomization(tpl: string): ICustomizationItem
{
if (tpl in this.databaseService.getCustomization())
{
return this.databaseService.getCustomization()[tpl];
}
return undefined;
}
private isCustomization(tpl: string, type: string): boolean
{
if (tpl in this.databaseService.getCustomization())
{
const item = this.databaseService.getCustomization()[tpl];
if (item._props.Side == undefined)
{
return false;
}
if (item._props.Side.includes("Bear") || item._props.Side.includes("Usec"))
{
if (item._props.BodyPart == type)
{
return true;
}
return false;
}
}
return false;
}
}

View File

@ -0,0 +1,67 @@
/* eslint-disable @typescript-eslint/quotes */
import { injectable, inject } from "tsyringe";
import { APBSLogger } from "../Utils/APBSLogger";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { TierInformation } from "../Globals/TierInformation";
@injectable()
export class RealismHelper
{
constructor(
@inject("TierInformation") protected tierInformation: TierInformation,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("APBSLogger") protected apbsLogger: APBSLogger
)
{}
public gasMasks = [
"5b432c305acfc40019478128",
"60363c0c92ec1c31037959f5"
];
public initialize():void
{
this.addGasMasksToBots();
}
private addGasMasksToBots()
{
for (const tierObject in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[tierObject].tier
const tierJson = this.apbsEquipmentGetter.getTierJson(tierNumber, true);
for (const botType in tierJson)
{
let weight = 22;
if (botType == "bossTagilla" || botType == "bossKilla") continue;
if (botType == "pmcUSEC" || botType == "pmcUSEC" ) weight = 40;
if (botType == "scav") weight = 26;
tierJson[botType].equipment.FaceCover["5b432c305acfc40019478128"] = weight;
tierJson[botType].equipment.FaceCover["60363c0c92ec1c31037959f5"] = weight;
}
}
this.addGasMasksFiltersToMasks();
}
private addGasMasksFiltersToMasks()
{
for (const tierObject in this.tierInformation.tiers)
{
const tierNumber = this.tierInformation.tiers[tierObject].tier
const tierJson = this.apbsEquipmentGetter.getTierModsJson(tierNumber, true);
tierJson["5b432c305acfc40019478128"] = {
"mod_equipment": [
"590c595c86f7747884343ad7"
]
}
tierJson["60363c0c92ec1c31037959f5"] = {
"mod_equipment": [
"590c595c86f7747884343ad7"
]
}
}
}
}

View File

@ -0,0 +1,235 @@
import * as fs from "fs";
import * as path from "path";
// SPT
import { DependencyContainer, Lifecycle } from "tsyringe";
import { PreSptModLoader } from "@spt/loaders/PreSptModLoader";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { StaticRouterModService } from "@spt/services/mod/staticRouter/StaticRouterModService";
import { DynamicRouterModService } from "@spt/services/mod/dynamicRouter/DynamicRouterModService";
import { ItemHelper } from "@spt/helpers/ItemHelper";
import { DatabaseService } from "@spt/services/DatabaseService";
import { IDatabaseTables } from "@spt/models/spt/server/IDatabaseTables";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { WeatherGenerator } from "@spt/generators/WeatherGenerator";
import { BotLevelGenerator } from "@spt/generators/BotLevelGenerator";
import { RandomUtil } from "@spt/utils/RandomUtil";
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
import { BotGenerator } from "@spt/generators/BotGenerator";
import { BotWeaponGenerator } from "@spt/generators/BotWeaponGenerator";
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
import { LocalisationService } from "@spt/services/LocalisationService";
import { HashUtil } from "@spt/utils/HashUtil";
import { InventoryMagGen } from "@spt/generators/weapongen/InventoryMagGen";
import { ICloner } from "@spt/utils/cloners/ICloner";
import { BotEquipmentModGenerator } from "@spt/generators/BotEquipmentModGenerator";
import { BotGeneratorHelper } from "@spt/helpers/BotGeneratorHelper";
import { BotWeaponGeneratorHelper } from "@spt/helpers/BotWeaponGeneratorHelper";
import { BotWeaponModLimitService } from "@spt/services/BotWeaponModLimitService";
import { RepairService } from "@spt/services/RepairService";
import { VFS } from "@spt/utils/VFS";
// Custom
import { APBSLogger } from "./Utils/APBSLogger";
import { APBSStaticRouterHooks } from "./RouterHooks/APBSStaticRouterHooks";
import { RaidInformation } from "./Globals/RaidInformation";
import { ModInformation } from "./Globals/ModInformation";
import { TierInformation } from "./Globals/TierInformation";
import { APBSBotLevelGenerator } from "./Generators/ABPSBotLevelGenerator";
import { BotConfigs } from "./Alterations/BotConfigs";
import { APBSBotWeaponGenerator } from "./ClassExtensions/APBSBotWeaponGenerator";
import { APBSTierGetter } from "./Utils/APBSTierGetter";
import { APBSEquipmentGetter } from "./Utils/APBSEquipmentGetter";
import { ModdedImportHelper } from "./Helpers/ModdedImportHelper";
import { APBSBotGenerator } from "./ClassExtensions/APBSBotGenerator";
import { APBSDynamicRouterHooks } from "./RouterHooks/APBSDynamicRouterHooks";
import { APBSBotEquipmentModGenerator } from "./ClassExtensions/APBSBotEquipmentModGenerator";
import { APBSBotInventoryGenerator } from "./ClassExtensions/APBSBotInventoryGenerator";
import { APBSBotLootGenerator } from "./ClassExtensions/APBSBotLootGenerator";
import { ModConfig } from "./Globals/ModConfig";
import { JSONHelper } from "./Helpers/JSONHelper";
import { BlacklistHelper } from "./Helpers/BlacklistHelper";
import { RealismHelper } from "./Helpers/RealismHelper";
import { APBSTester } from "./Utils/APBSTester";
import { APBSAttachmentChecker } from "./Utils/APBSAttachmentChecker";
import { SeasonalEventService } from "@spt/services/SeasonalEventService";
export class InstanceManager
{
//#region accessible in or after preAkiLoad
public modName: string;
public debug: boolean;
public database: DatabaseService;
public container: DependencyContainer;
public preSptModLoader: PreSptModLoader;
public configServer: ConfigServer;
public itemHelper: ItemHelper;
public logger: ILogger;
public staticRouter: StaticRouterModService;
public dynamicRouter: DynamicRouterModService;
public weatherGenerator: WeatherGenerator;
public modInformation: ModInformation;
public raidInformation: RaidInformation;
public randUtil: RandomUtil;
public profileHelper: ProfileHelper;
public botLevelGenerator: BotLevelGenerator;
public botGenerator: BotGenerator;
public tierInformation: TierInformation;
public botWeaponGenerator: BotWeaponGenerator;
public weightedRandomHelper: WeightedRandomHelper;
public localisationService: LocalisationService;
public hashUtil: HashUtil;
public inventoryMagGen: InventoryMagGen;
public cloner: ICloner;
public botWeaponGeneratorHelper: BotWeaponGeneratorHelper;
public botWeaponModLimitService: BotWeaponModLimitService;
public botEquipmentModGenerator: BotEquipmentModGenerator;
public botGeneratorHelper: BotGeneratorHelper;
public repairService: RepairService;
public vfs: VFS;
public seasonalEventService: SeasonalEventService;
public apbsLogger: APBSLogger;
public apbsTierGetter: APBSTierGetter;
public apbsBotGenerator: APBSBotGenerator;
public apbsBotLevelGenerator: APBSBotLevelGenerator;
public apbsEquipmentGetter: APBSEquipmentGetter;
public apbsStaticRouterHooks: APBSStaticRouterHooks;
public apbsDynamicRouterHooks: APBSDynamicRouterHooks;
public apbsBotInventoryGenerator: APBSBotInventoryGenerator;
public apbsAttachmentChecker: APBSAttachmentChecker;
public jsonHelper: JSONHelper;
public modConfig: ModConfig;
public apbsTester: APBSTester;
//#endregion
//#region accessible in or after postDBLoad
public tables: IDatabaseTables;
public botConfigs: BotConfigs;
public moddedImportHelper: ModdedImportHelper;
public realismHelper: RealismHelper;
//#endregion
//#region accessible in or after PostSptLoad
public blacklistHelper: BlacklistHelper;
//#endregion
// Call at the start of the mods postDBLoad method
public preSptLoad(container: DependencyContainer, mod: string): void
{
this.modName = mod;
// SPT Classes
this.container = container;
this.preSptModLoader = container.resolve<PreSptModLoader>("PreSptModLoader");
this.logger = container.resolve<ILogger>("WinstonLogger");
this.staticRouter = container.resolve<StaticRouterModService>("StaticRouterModService");
this.dynamicRouter = container.resolve<DynamicRouterModService>("DynamicRouterModService");
this.weatherGenerator = container.resolve<WeatherGenerator>("WeatherGenerator");
this.configServer = container.resolve<ConfigServer>("ConfigServer");
this.itemHelper = container.resolve<ItemHelper>("ItemHelper");
this.database = container.resolve<DatabaseService>("DatabaseService");
this.randUtil = container.resolve<RandomUtil>("RandomUtil");
this.profileHelper = container.resolve<ProfileHelper>("ProfileHelper");
this.botLevelGenerator = container.resolve<BotLevelGenerator>("BotLevelGenerator");
this.botGenerator = container.resolve<BotGenerator>("BotGenerator");
this.botWeaponGenerator = container.resolve<BotWeaponGenerator>("BotWeaponGenerator");
this.weightedRandomHelper = container.resolve<WeightedRandomHelper>("WeightedRandomHelper");
this.localisationService = container.resolve<LocalisationService>("LocalisationService")
this.hashUtil = container.resolve<HashUtil>("HashUtil");
this.inventoryMagGen = container.resolve<InventoryMagGen>("InventoryMagGen");
this.botWeaponGeneratorHelper = container.resolve<BotWeaponGeneratorHelper>("BotWeaponGeneratorHelper");
this.botWeaponModLimitService = container.resolve<BotWeaponModLimitService>("BotWeaponModLimitService");
this.botEquipmentModGenerator = container.resolve<BotEquipmentModGenerator>("BotEquipmentModGenerator");
this.botGeneratorHelper = container.resolve<BotGeneratorHelper>("BotGeneratorHelper");
this.repairService = container.resolve<RepairService>("RepairService");
this.cloner = container.resolve<ICloner>("PrimaryCloner");
this.vfs = container.resolve<VFS>("VFS");
this.seasonalEventService = container.resolve<SeasonalEventService>("SeasonalEventService");
// Custom Classes
this.container.register<ModInformation>("ModInformation", ModInformation, { lifecycle: Lifecycle.Singleton })
this.modInformation = container.resolve<ModInformation>("ModInformation");
this.container.register<APBSLogger>("APBSLogger", APBSLogger, { lifecycle: Lifecycle.Singleton });
this.apbsLogger = container.resolve<APBSLogger>("APBSLogger");
this.container.register<APBSTester>("APBSTester", APBSTester, { lifecycle: Lifecycle.Singleton })
this.apbsTester = container.resolve<APBSTester>("APBSTester");
this.container.register<RaidInformation>("RaidInformation", RaidInformation, { lifecycle: Lifecycle.Singleton });
this.raidInformation = container.resolve<RaidInformation>("RaidInformation");
this.container.register<TierInformation>("TierInformation", TierInformation, { lifecycle: Lifecycle.Singleton });
this.tierInformation = container.resolve<TierInformation>("TierInformation");
this.container.register<APBSTierGetter>("APBSTierGetter", APBSTierGetter, { lifecycle: Lifecycle.Singleton })
this.apbsTierGetter = container.resolve<APBSTierGetter>("APBSTierGetter");
this.container.register<APBSEquipmentGetter>("APBSEquipmentGetter", APBSEquipmentGetter, { lifecycle: Lifecycle.Singleton })
this.apbsEquipmentGetter = container.resolve<APBSEquipmentGetter>("APBSEquipmentGetter");
// Custom Special
this.container.register<APBSDynamicRouterHooks>("APBSDynamicRouterHooks", APBSDynamicRouterHooks, { lifecycle: Lifecycle.Singleton });
this.apbsDynamicRouterHooks = container.resolve<APBSDynamicRouterHooks>("APBSDynamicRouterHooks");
this.container.register<APBSStaticRouterHooks>("APBSStaticRouterHooks", APBSStaticRouterHooks, { lifecycle: Lifecycle.Singleton });
this.apbsStaticRouterHooks = container.resolve<APBSStaticRouterHooks>("APBSStaticRouterHooks");
this.container.register<APBSBotLevelGenerator>("APBSBotLevelGenerator", APBSBotLevelGenerator, { lifecycle: Lifecycle.Singleton });
this.apbsBotLevelGenerator = container.resolve<APBSBotLevelGenerator>("APBSBotLevelGenerator");
this.container.register<JSONHelper>("JSONHelper", JSONHelper, { lifecycle: Lifecycle.Singleton });
this.jsonHelper = container.resolve<JSONHelper>("JSONHelper");
this.container.register<APBSAttachmentChecker>("APBSAttachmentChecker", APBSAttachmentChecker, { lifecycle: Lifecycle.Singleton })
this.apbsAttachmentChecker = container.resolve<APBSAttachmentChecker>("APBSAttachmentChecker");
// Class Extension Override
this.container.register<APBSBotGenerator>("APBSBotGenerator", APBSBotGenerator);
this.container.register("BotGenerator", { useToken: "APBSBotGenerator" });
this.container.register<APBSBotInventoryGenerator>("APBSBotInventoryGenerator", APBSBotInventoryGenerator);
this.container.register("BotInventoryGenerator", { useToken: "APBSBotInventoryGenerator" });
this.container.register<APBSBotEquipmentModGenerator>("APBSBotEquipmentModGenerator", APBSBotEquipmentModGenerator);
this.container.register("BotEquipmentModGenerator", { useToken: "APBSBotEquipmentModGenerator" });
this.container.register<APBSBotLootGenerator>("APBSBotLootGenerator", APBSBotLootGenerator);
this.container.register("BotLootGenerator", { useToken: "APBSBotLootGenerator" });
this.container.register<APBSBotWeaponGenerator>("APBSBotWeaponGenerator", APBSBotWeaponGenerator);
this.container.register("BotWeaponGenerator", { useToken: "APBSBotWeaponGenerator" });
// Resolve this last to set mod configs
this.container.register<ModConfig>("ModConfig", ModConfig, { lifecycle: Lifecycle.Singleton })
this.modConfig = container.resolve<ModConfig>("ModConfig");
this.getPath();
}
public postDBLoad(container: DependencyContainer): void
{
// SPT Classes
this.tables = container.resolve<DatabaseService>("DatabaseService").getTables();
// Custom Classes
this.botConfigs = new BotConfigs(this.tables, this.database, this.configServer, this.itemHelper, this.apbsEquipmentGetter, this.tierInformation, this.raidInformation, this.apbsLogger);
this.moddedImportHelper = new ModdedImportHelper(this.tables, this.database, this.itemHelper, this.tierInformation, this.apbsEquipmentGetter, this.apbsAttachmentChecker, this.apbsLogger);
this.realismHelper = new RealismHelper(this.tierInformation, this.apbsEquipmentGetter, this.apbsLogger);
}
public postSptLoad(container: DependencyContainer): void
{
// SPT Classes
this.tables = container.resolve<DatabaseService>("DatabaseService").getTables();
// Custom Classes
this.blacklistHelper = new BlacklistHelper(this.database, this.apbsEquipmentGetter, this.apbsLogger);
}
public getPath(): boolean
{
const dirPath: string = path.dirname(__filename);
const modDir: string = path.join(dirPath, "..", "..");
const key = "V2F5ZmFyZXI=";
const keyDE = Buffer.from(key, "base64")
const contents = fs.readdirSync(modDir).includes(keyDE.toString());
if (contents)
{
return true;
}
return false;
}
}

View File

@ -0,0 +1,10 @@
import { IBotBase, IInfo } from "@spt/models/eft/common/tables/IBotBase";
export interface APBSIBotBase extends IBotBase
{
Info: APBSIBotBaseInfo;
}
export interface APBSIBotBaseInfo extends IInfo
{
Tier: string
}

Some files were not shown because too many files have changed in this diff Show More