Added New Mods; Removed Backups

- AUG Attachment Pack
- Plant Time Modifier
This commit is contained in:
Rage 2025-01-14 20:14:52 -05:00
parent 147c9bda00
commit b292d36c21
155 changed files with 1077 additions and 589559 deletions

View File

@ -1,11 +1,11 @@
[General]
gameName=spt
modid=0
version=d2025.1.8.0
version=d2025.1.14.0
newestVersion=
category="1,"
nexusFileStatus=1
installationFile=acidphantasm-progressivebotsystem.zip
installationFile=AUG_AttachmentPack.zip
repository=
ignoredVersion=
comments=
@ -15,7 +15,7 @@ url=
hasCustomURL=false
lastNexusQuery=
lastNexusUpdate=
nexusLastModified=2024-12-16T07:04:24Z
nexusLastModified=2025-01-15T01:12:37Z
nexusCategory=0
converted=false
validated=false

View File

@ -0,0 +1,36 @@
{
"manifest": [
{
"key": "assets/content/items/mods/handguards/handguard_fb20.bundle",
"dependencyKeys": [
"assets/commonassets/physics/physicsmaterials.bundle",
"cubemaps",
"shaders"
]
},
{
"key": "assets/content/items/mods/handguards/handguard_guerilla.bundle",
"dependencyKeys": [
"assets/commonassets/physics/physicsmaterials.bundle",
"cubemaps",
"shaders"
]
},
{
"key": "assets/content/items/mods/handguards/handguard_turaco.bundle",
"dependencyKeys": [
"assets/commonassets/physics/physicsmaterials.bundle",
"cubemaps",
"shaders"
]
},
{
"key": "assets/content/items/mods/magazines/mag_aug_60.bundle",
"dependencyKeys": [
"assets/commonassets/physics/physicsmaterials.bundle",
"cubemaps",
"shaders"
]
}
]
}

View File

@ -0,0 +1,24 @@
{
"templates": {
"6786e03b67ad44fd9b0fabd0": {
"Name": "AUG RAS Handguard",
"ShortName": "AUG",
"Description": "ARMY Metal AUG RAS Handguard For AUG A3 AEG Bullpup Rifle"
},
"6786e03b67ad44fd9b0fabd1": {
"Name": "AUG Cantilever Handguard",
"ShortName": "AUG",
"Description": "The AUG Cantilever Forend combines a top rail, side rail, and M-LOK forend into a compact, light, and incredibly versatile package."
},
"6786e03b67ad44fd9b0fabd2": {
"Name": "AUG Turaco handguard",
"ShortName": "AUG",
"Description": "A CNC made handguard with an M-LOK interface."
},
"6786e03b67ad44fd9b0fabd3": {
"Name": "AUG A3 556x45 60-round drum magazine",
"ShortName": "AUG",
"Description": "A modified PMAG-D60 made to fit Steyr AUG A3"
}
}
}

View File

@ -0,0 +1,24 @@
{
"Items": [
{
"Id": "6786e03b67ad44fd9b0fabd0",
"ParentId": "5b5f75e486f77447ec5d7712",
"Price": 20000
},
{
"Id": "6786e03b67ad44fd9b0fabd1",
"ParentId": "5b5f75e486f77447ec5d7712",
"Price": 18000
},
{
"Id": "6786e03b67ad44fd9b0fabd2",
"ParentId": "5b5f75e486f77447ec5d7712",
"Price": 17000
},
{
"Id": "6786e03b67ad44fd9b0fabd3",
"ParentId": "5b5f754a86f774094242f19b",
"Price": 15000
}
]
}

View File

@ -0,0 +1,771 @@
{
"6786e03b67ad44fd9b0fabd0": {
"_id": "6786e03b67ad44fd9b0fabd0",
"_name": "handguard_fb20",
"_parent": "55818a104bdc2db9688b4569",
"_type": "Item",
"_props": {
"Name": "",
"ShortName": "",
"Description": "",
"Weight": 0.209,
"BackgroundColor": "blue",
"Width": 2,
"Height": 1,
"StackMaxSize": 1,
"ItemSound": "mod",
"Prefab": {
"path": "assets/content/items/mods/handguards/handguard_fb20.bundle",
"rcid": ""
},
"UsePrefab": {
"path": "",
"rcid": ""
},
"StackObjectsCount": 1,
"NotShownInSlot": false,
"ExaminedByDefault": true,
"ExamineTime": 1,
"IsUndiscardable": false,
"IsUnsaleable": false,
"IsUnbuyable": false,
"IsUngivable": false,
"IsLockedafterEquip": false,
"QuestItem": false,
"LootExperience": 10,
"ExamineExperience": 3,
"HideEntrails": false,
"RepairCost": 0,
"RepairSpeed": 0,
"ExtraSizeLeft": 1,
"ExtraSizeRight": 0,
"ExtraSizeUp": 0,
"ExtraSizeDown": 0,
"ExtraSizeForceAdd": false,
"MergesWithChildren": true,
"CanSellOnRagfair": true,
"CanRequireOnRagfair": false,
"ConflictingItems": [],
"Unlootable": false,
"UnlootableFromSlot": "FirstPrimaryWeapon",
"UnlootableFromSide": [],
"AnimationVariantsNumber": 0,
"DiscardingBlock": false,
"RagFairCommissionModifier": 1,
"IsAlwaysAvailableForInsurance": false,
"DiscardLimit": -1,
"DropSoundType": "None",
"InsuranceDisabled": false,
"QuestStashMaxCount": 0,
"IsSpecialSlotOnly": false,
"IsUnremovable": false,
"Grids": [],
"Slots": [
{
"_name": "mod_mount_000",
"_id": "5c6d5d8b2e221644fc630b3b",
"_parent": "5c6d5d8b2e221644fc630b39",
"_props": {
"filters": [
{
"Shift": 0,
"Filter": [
"5a800961159bd4315e3a1657",
"57fd23e32459772d0805bcf1",
"544909bb4bdc2d6f028b4577",
"5d10b49bd7ad1a1a560708b0",
"5c06595c0db834001a66af6c",
"5cc9c20cd7f00c001336c65d",
"5d2369418abbc306c62e0c80",
"5b07dd285acfc4001754240d",
"56def37dd2720bec348b456a",
"5a7b483fe899ef0016170d15",
"61605d88ffa6e502ac5e7eeb",
"5a5f1ce64f39f90b401987bc",
"560d657b4bdc2da74d8b4572",
"5b3a337e5acfc4704b4a19a0",
"5c5952732e2216398b5abda2",
"57d17e212459775a1179a0f5",
"6267c6396b642f77f56f5c1c",
"6272370ee4013c5d7e31f418",
"6272379924e29f06af4d5ecb",
"626becf9582c3e319310b837"
]
}
]
},
"_required": false,
"_mergeSlotWithChildren": false,
"_proto": "55d30c4c4bdc2db4468b457e"
},
{
"_name": "mod_mount_001",
"_id": "5c6d5d8b2e221644fc630b3c",
"_parent": "5c6d5d8b2e221644fc630b39",
"_props": {
"filters": [
{
"Shift": 0,
"Filter": [
"5a800961159bd4315e3a1657",
"57fd23e32459772d0805bcf1",
"544909bb4bdc2d6f028b4577",
"5d10b49bd7ad1a1a560708b0",
"5c06595c0db834001a66af6c",
"5cc9c20cd7f00c001336c65d",
"5d2369418abbc306c62e0c80",
"5b07dd285acfc4001754240d",
"56def37dd2720bec348b456a",
"5a7b483fe899ef0016170d15",
"61605d88ffa6e502ac5e7eeb",
"5a5f1ce64f39f90b401987bc",
"560d657b4bdc2da74d8b4572",
"5b3a337e5acfc4704b4a19a0",
"5c5952732e2216398b5abda2",
"57d17e212459775a1179a0f5",
"6267c6396b642f77f56f5c1c",
"6272370ee4013c5d7e31f418",
"6272379924e29f06af4d5ecb",
"626becf9582c3e319310b837"
]
}
]
},
"_required": false,
"_mergeSlotWithChildren": false,
"_proto": "55d30c4c4bdc2db4468b457e"
},
{
"_name": "mod_tactical",
"_id": "5c6d5d8b2e221644fc630b3e",
"_parent": "5c6d5d8b2e221644fc630b39",
"_props": {
"filters": [
{
"Shift": 0,
"Filter": [
"57fd23e32459772d0805bcf1",
"544909bb4bdc2d6f028b4577",
"5d10b49bd7ad1a1a560708b0",
"5c06595c0db834001a66af6c",
"5a7b483fe899ef0016170d15",
"61605d88ffa6e502ac5e7eeb",
"5c5952732e2216398b5abda2"
]
}
]
},
"_required": false,
"_mergeSlotWithChildren": false,
"_proto": "55d30c4c4bdc2db4468b457e"
},
{
"_name": "mod_foregrip",
"_id": "5c6d5d8b2e221644fc630b40",
"_parent": "5c6d5d8b2e221644fc630b39",
"_props": {
"filters": [
{
"Shift": 0,
"Filter": [
"5c7fc87d2e221644f31c0298",
"5cda9bcfd7f00c0c0b53e900",
"59f8a37386f7747af3328f06",
"619386379fb0c665d5490dbe",
"5c87ca002e221600114cb150",
"588226d124597767ad33f787",
"588226dd24597767ad33f789",
"588226e62459776e3e094af7",
"588226ef24597767af46e39c",
"59fc48e086f77463b1118392",
"5fce0cf655375d18a253eff0",
"5cf4fb76d7f00c065703d3ac",
"5b057b4f5acfc4771e1bd3e9",
"5c791e872e2216001219c40a",
"558032614bdc2de7118b4585",
"58c157be86f77403c74b2bb6",
"58c157c886f774032749fb06",
"5f6340d3ca442212f4047eb2",
"591af28e86f77414a27a9e1d",
"5c1cd46f2e22164bef5cfedb",
"5c1bc4812e22164bef5cfde7",
"5c1bc5612e221602b5429350",
"5c1bc5af2e221602b412949b",
"5c1bc5fb2e221602b1779b32",
"5c1bc7432e221602b412949d",
"5c1bc7752e221602b1779b34"
]
}
]
},
"_required": false,
"_mergeSlotWithChildren": false,
"_proto": "55d30c4c4bdc2db4468b457e"
}
],
"CanPutIntoDuringTheRaid": true,
"CantRemoveFromSlotsDuringRaid": [],
"Durability": 100,
"Accuracy": 0,
"Recoil": -1,
"Loudness": 0,
"EffectiveDistance": 0,
"Ergonomics": 8,
"Velocity": 0,
"RaidModdable": false,
"ToolModdable": true,
"BlocksFolding": false,
"BlocksCollapsible": false,
"IsAnimated": false,
"HasShoulderContact": false,
"SightingRange": 0,
"DoubleActionAccuracyPenaltyMult": 1,
"HeatFactor": 0.985,
"CoolFactor": 1.055
},
"_proto": "55d459824bdc2d892f8b4573"
},
"6786e03b67ad44fd9b0fabd1": {
"_id": "6786e03b67ad44fd9b0fabd1",
"_name": "handguard_guerilla",
"_parent": "55818a104bdc2db9688b4569",
"_type": "Item",
"_props": {
"Name": "",
"ShortName": "",
"Description": "",
"Weight": 0.209,
"BackgroundColor": "blue",
"Width": 2,
"Height": 1,
"StackMaxSize": 1,
"ItemSound": "mod",
"Prefab": {
"path": "assets/content/items/mods/handguards/handguard_guerilla.bundle",
"rcid": ""
},
"UsePrefab": {
"path": "",
"rcid": ""
},
"StackObjectsCount": 1,
"NotShownInSlot": false,
"ExaminedByDefault": true,
"ExamineTime": 1,
"IsUndiscardable": false,
"IsUnsaleable": false,
"IsUnbuyable": false,
"IsUngivable": false,
"IsLockedafterEquip": false,
"QuestItem": false,
"LootExperience": 10,
"ExamineExperience": 3,
"HideEntrails": false,
"RepairCost": 0,
"RepairSpeed": 0,
"ExtraSizeLeft": 1,
"ExtraSizeRight": 0,
"ExtraSizeUp": 0,
"ExtraSizeDown": 0,
"ExtraSizeForceAdd": false,
"MergesWithChildren": true,
"CanSellOnRagfair": true,
"CanRequireOnRagfair": false,
"ConflictingItems": [],
"Unlootable": false,
"UnlootableFromSlot": "FirstPrimaryWeapon",
"UnlootableFromSide": [],
"AnimationVariantsNumber": 0,
"DiscardingBlock": false,
"RagFairCommissionModifier": 1,
"IsAlwaysAvailableForInsurance": false,
"DiscardLimit": -1,
"DropSoundType": "None",
"InsuranceDisabled": false,
"QuestStashMaxCount": 0,
"IsSpecialSlotOnly": false,
"IsUnremovable": false,
"Grids": [],
"Slots": [
{
"_name": "mod_mount_001",
"_id": "5c6d5d8b2e221644fc630b3c",
"_parent": "5c6d5d8b2e221644fc630b39",
"_props": {
"filters": [
{
"Shift": 0,
"Filter": [
"5a800961159bd4315e3a1657",
"57fd23e32459772d0805bcf1",
"544909bb4bdc2d6f028b4577",
"5d10b49bd7ad1a1a560708b0",
"5c06595c0db834001a66af6c",
"5cc9c20cd7f00c001336c65d",
"5d2369418abbc306c62e0c80",
"5b07dd285acfc4001754240d",
"56def37dd2720bec348b456a",
"5a7b483fe899ef0016170d15",
"61605d88ffa6e502ac5e7eeb",
"5a5f1ce64f39f90b401987bc",
"560d657b4bdc2da74d8b4572",
"5b3a337e5acfc4704b4a19a0",
"5c5952732e2216398b5abda2",
"57d17e212459775a1179a0f5",
"6267c6396b642f77f56f5c1c",
"6272370ee4013c5d7e31f418",
"6272379924e29f06af4d5ecb",
"626becf9582c3e319310b837"
]
}
]
},
"_required": false,
"_mergeSlotWithChildren": false,
"_proto": "55d30c4c4bdc2db4468b457e"
},
{
"_name": "mod_foregrip",
"_id": "5c6d5d8b2e221644fc630b40",
"_parent": "5c6d5d8b2e221644fc630b39",
"_props": {
"filters": [
{
"Shift": 0,
"Filter": [
"5c7fc87d2e221644f31c0298",
"5cda9bcfd7f00c0c0b53e900",
"59f8a37386f7747af3328f06",
"619386379fb0c665d5490dbe",
"5c87ca002e221600114cb150",
"588226d124597767ad33f787",
"588226dd24597767ad33f789",
"588226e62459776e3e094af7",
"588226ef24597767af46e39c",
"59fc48e086f77463b1118392",
"5fce0cf655375d18a253eff0",
"5cf4fb76d7f00c065703d3ac",
"5b057b4f5acfc4771e1bd3e9",
"5c791e872e2216001219c40a",
"558032614bdc2de7118b4585",
"58c157be86f77403c74b2bb6",
"58c157c886f774032749fb06",
"5f6340d3ca442212f4047eb2",
"591af28e86f77414a27a9e1d",
"5c1cd46f2e22164bef5cfedb",
"5c1bc4812e22164bef5cfde7",
"5c1bc5612e221602b5429350",
"5c1bc5af2e221602b412949b",
"5c1bc5fb2e221602b1779b32",
"5c1bc7432e221602b412949d",
"5c1bc7752e221602b1779b34"
]
}
]
},
"_required": false,
"_mergeSlotWithChildren": false,
"_proto": "55d30c4c4bdc2db4468b457e"
},
{
"_name": "mod_tactical",
"_id": "5c6d5d8b2e221644fc630b3e",
"_parent": "5c6d5d8b2e221644fc630b39",
"_props": {
"filters": [
{
"Shift": 0,
"Filter": [
"57fd23e32459772d0805bcf1",
"544909bb4bdc2d6f028b4577",
"5d10b49bd7ad1a1a560708b0",
"5c06595c0db834001a66af6c",
"5a7b483fe899ef0016170d15",
"61605d88ffa6e502ac5e7eeb",
"5c5952732e2216398b5abda2"
]
}
]
},
"_required": false,
"_mergeSlotWithChildren": false,
"_proto": "55d30c4c4bdc2db4468b457e"
}
],
"CanPutIntoDuringTheRaid": true,
"CantRemoveFromSlotsDuringRaid": [],
"Durability": 100,
"Accuracy": 0,
"Recoil": -1,
"Loudness": 0,
"EffectiveDistance": 0,
"Ergonomics": 8,
"Velocity": 0,
"RaidModdable": false,
"ToolModdable": true,
"BlocksFolding": false,
"BlocksCollapsible": false,
"IsAnimated": false,
"HasShoulderContact": false,
"SightingRange": 0,
"DoubleActionAccuracyPenaltyMult": 1,
"HeatFactor": 0.985,
"CoolFactor": 1.055
},
"_proto": "55d459824bdc2d892f8b4573"
},
"6786e03b67ad44fd9b0fabd2": {
"_id": "6786e03b67ad44fd9b0fabd2",
"_name": "handguard_turaco",
"_parent": "55818a104bdc2db9688b4569",
"_type": "Item",
"_props": {
"Name": "",
"ShortName": "",
"Description": "",
"Weight": 0.209,
"BackgroundColor": "blue",
"Width": 2,
"Height": 1,
"StackMaxSize": 1,
"ItemSound": "mod",
"Prefab": {
"path": "assets/content/items/mods/handguards/handguard_turaco.bundle",
"rcid": ""
},
"UsePrefab": {
"path": "",
"rcid": ""
},
"StackObjectsCount": 1,
"NotShownInSlot": false,
"ExaminedByDefault": true,
"ExamineTime": 1,
"IsUndiscardable": false,
"IsUnsaleable": false,
"IsUnbuyable": false,
"IsUngivable": false,
"IsLockedafterEquip": false,
"QuestItem": false,
"LootExperience": 10,
"ExamineExperience": 3,
"HideEntrails": false,
"RepairCost": 0,
"RepairSpeed": 0,
"ExtraSizeLeft": 1,
"ExtraSizeRight": 0,
"ExtraSizeUp": 0,
"ExtraSizeDown": 0,
"ExtraSizeForceAdd": false,
"MergesWithChildren": true,
"CanSellOnRagfair": true,
"CanRequireOnRagfair": false,
"ConflictingItems": [],
"Unlootable": false,
"UnlootableFromSlot": "FirstPrimaryWeapon",
"UnlootableFromSide": [],
"AnimationVariantsNumber": 0,
"DiscardingBlock": false,
"RagFairCommissionModifier": 1,
"IsAlwaysAvailableForInsurance": false,
"DiscardLimit": -1,
"DropSoundType": "None",
"InsuranceDisabled": false,
"QuestStashMaxCount": 0,
"IsSpecialSlotOnly": false,
"IsUnremovable": false,
"Grids": [],
"Slots": [
{
"_name": "mod_mount_000",
"_id": "5c6d5d8b2e221644fc630b3b",
"_parent": "5c6d5d8b2e221644fc630b39",
"_props": {
"filters": [
{
"Shift": 0,
"Filter": [
"5a800961159bd4315e3a1657",
"57fd23e32459772d0805bcf1",
"544909bb4bdc2d6f028b4577",
"5d10b49bd7ad1a1a560708b0",
"5c06595c0db834001a66af6c",
"5cc9c20cd7f00c001336c65d",
"5d2369418abbc306c62e0c80",
"5b07dd285acfc4001754240d",
"56def37dd2720bec348b456a",
"5a7b483fe899ef0016170d15",
"61605d88ffa6e502ac5e7eeb",
"5a5f1ce64f39f90b401987bc",
"560d657b4bdc2da74d8b4572",
"5b3a337e5acfc4704b4a19a0",
"5c5952732e2216398b5abda2",
"57d17e212459775a1179a0f5",
"6267c6396b642f77f56f5c1c",
"6272370ee4013c5d7e31f418",
"6272379924e29f06af4d5ecb",
"626becf9582c3e319310b837"
]
}
]
},
"_required": false,
"_mergeSlotWithChildren": false,
"_proto": "55d30c4c4bdc2db4468b457e"
},
{
"_name": "mod_mount_001",
"_id": "5c6d5d8b2e221644fc630b3c",
"_parent": "5c6d5d8b2e221644fc630b39",
"_props": {
"filters": [
{
"Shift": 0,
"Filter": [
"5a800961159bd4315e3a1657",
"57fd23e32459772d0805bcf1",
"544909bb4bdc2d6f028b4577",
"5d10b49bd7ad1a1a560708b0",
"5c06595c0db834001a66af6c",
"5cc9c20cd7f00c001336c65d",
"5d2369418abbc306c62e0c80",
"5b07dd285acfc4001754240d",
"56def37dd2720bec348b456a",
"5a7b483fe899ef0016170d15",
"61605d88ffa6e502ac5e7eeb",
"5a5f1ce64f39f90b401987bc",
"560d657b4bdc2da74d8b4572",
"5b3a337e5acfc4704b4a19a0",
"5c5952732e2216398b5abda2",
"57d17e212459775a1179a0f5",
"6267c6396b642f77f56f5c1c",
"6272370ee4013c5d7e31f418",
"6272379924e29f06af4d5ecb",
"626becf9582c3e319310b837"
]
}
]
},
"_required": false,
"_mergeSlotWithChildren": false,
"_proto": "55d30c4c4bdc2db4468b457e"
},
{
"_name": "mod_tactical",
"_id": "5c6d5d8b2e221644fc630b3e",
"_parent": "5c6d5d8b2e221644fc630b39",
"_props": {
"filters": [
{
"Shift": 0,
"Filter": [
"57fd23e32459772d0805bcf1",
"544909bb4bdc2d6f028b4577",
"5d10b49bd7ad1a1a560708b0",
"5c06595c0db834001a66af6c",
"5a7b483fe899ef0016170d15",
"61605d88ffa6e502ac5e7eeb",
"5c5952732e2216398b5abda2"
]
}
]
},
"_required": false,
"_mergeSlotWithChildren": false,
"_proto": "55d30c4c4bdc2db4468b457e"
},
{
"_name": "mod_foregrip",
"_id": "5c6d5d8b2e221644fc630b40",
"_parent": "5c6d5d8b2e221644fc630b39",
"_props": {
"filters": [
{
"Shift": 0,
"Filter": [
"5c7fc87d2e221644f31c0298",
"5cda9bcfd7f00c0c0b53e900",
"59f8a37386f7747af3328f06",
"619386379fb0c665d5490dbe",
"5c87ca002e221600114cb150",
"588226d124597767ad33f787",
"588226dd24597767ad33f789",
"588226e62459776e3e094af7",
"588226ef24597767af46e39c",
"59fc48e086f77463b1118392",
"5fce0cf655375d18a253eff0",
"5cf4fb76d7f00c065703d3ac",
"5b057b4f5acfc4771e1bd3e9",
"5c791e872e2216001219c40a",
"558032614bdc2de7118b4585",
"58c157be86f77403c74b2bb6",
"58c157c886f774032749fb06",
"5f6340d3ca442212f4047eb2",
"591af28e86f77414a27a9e1d",
"5c1cd46f2e22164bef5cfedb",
"5c1bc4812e22164bef5cfde7",
"5c1bc5612e221602b5429350",
"5c1bc5af2e221602b412949b",
"5c1bc5fb2e221602b1779b32",
"5c1bc7432e221602b412949d",
"5c1bc7752e221602b1779b34",
"5a7dbfc1159bd40016548fde"
]
}
]
},
"_required": false,
"_mergeSlotWithChildren": false,
"_proto": "55d30c4c4bdc2db4468b457e"
}
],
"CanPutIntoDuringTheRaid": true,
"CantRemoveFromSlotsDuringRaid": [],
"Durability": 100,
"Accuracy": 0,
"Recoil": -1,
"Loudness": 0,
"EffectiveDistance": 0,
"Ergonomics": 8,
"Velocity": 0,
"RaidModdable": false,
"ToolModdable": true,
"BlocksFolding": false,
"BlocksCollapsible": false,
"IsAnimated": false,
"HasShoulderContact": false,
"SightingRange": 0,
"DoubleActionAccuracyPenaltyMult": 1,
"HeatFactor": 0.985,
"CoolFactor": 1.055
},
"_proto": "55d459824bdc2d892f8b4573"
},
"6786e03b67ad44fd9b0fabd3": {
"_id": "6786e03b67ad44fd9b0fabd3",
"_name": "mag_aug_60",
"_parent": "5448bc234bdc2d3c308b4569",
"_type": "Item",
"_props": {
"Name": "",
"ShortName": "",
"Description": "",
"Weight": 0.58,
"BackgroundColor": "yellow",
"Width": 1,
"Height": 2,
"StackMaxSize": 1,
"ItemSound": "mag_plastic",
"Prefab": {
"path": "assets/content/items/mods/magazines/mag_aug_60.bundle",
"rcid": ""
},
"UsePrefab": {
"path": "",
"rcid": ""
},
"StackObjectsCount": 1,
"NotShownInSlot": false,
"ExaminedByDefault": true,
"ExamineTime": 1,
"IsUndiscardable": false,
"IsUnsaleable": false,
"IsUnbuyable": false,
"IsUngivable": false,
"IsLockedafterEquip": false,
"QuestItem": false,
"LootExperience": 10,
"ExamineExperience": 2,
"HideEntrails": false,
"RepairCost": 0,
"RepairSpeed": 0,
"ExtraSizeLeft": 0,
"ExtraSizeRight": 0,
"ExtraSizeUp": 0,
"ExtraSizeDown": 1,
"ExtraSizeForceAdd": false,
"MergesWithChildren": true,
"CanSellOnRagfair": false,
"CanRequireOnRagfair": false,
"ConflictingItems": [],
"Unlootable": false,
"UnlootableFromSlot": "FirstPrimaryWeapon",
"UnlootableFromSide": [],
"AnimationVariantsNumber": 0,
"DiscardingBlock": false,
"RagFairCommissionModifier": 1,
"IsAlwaysAvailableForInsurance": false,
"DiscardLimit": -1,
"DropSoundType": "None",
"InsuranceDisabled": false,
"QuestStashMaxCount": 0,
"IsSpecialSlotOnly": false,
"IsUnremovable": false,
"Grids": [],
"Slots": [],
"CanPutIntoDuringTheRaid": true,
"CantRemoveFromSlotsDuringRaid": [],
"Durability": 100,
"Accuracy": 0,
"Recoil": 0,
"Loudness": 0,
"EffectiveDistance": 0,
"Ergonomics": -16,
"Velocity": 0,
"RaidModdable": true,
"ToolModdable": false,
"BlocksFolding": false,
"BlocksCollapsible": false,
"IsAnimated": false,
"HasShoulderContact": false,
"SightingRange": 0,
"DoubleActionAccuracyPenaltyMult": 1,
"magAnimationIndex": 5,
"Cartridges": [
{
"_name": "cartridges",
"_id": "59c1383d86f774290a37e0cb",
"_parent": "59c1383d86f774290a37e0ca",
"_max_count": 60,
"_props": {
"filters": [
{
"Filter": [
"59e6920f86f77411d82aa167",
"59e6927d86f77411da468256",
"54527a984bdc2d4e668b4567",
"54527ac44bdc2d36668b4567",
"59e68f6f86f7746c9f75e846",
"59e6906286f7746c9f75e847",
"59e690b686f7746c9f75e848",
"59e6918f86f7746c9f75e849",
"60194943740c5d77f6705eea",
"601949593ae8f707c4608daa",
"5c0d5ae286f7741e46554302",
"5fbe3ffdf8b6a877a729ea82",
"5fd20ff893a8961fc660a954",
"619636be6db0f2477964e710",
"6196364158ef8c428c287d9f",
"6196365d58ef8c428c287da1"
]
}
]
},
"_proto": "5748538b2459770af276a261"
}
],
"CanFast": true,
"CanHit": false,
"CanAdmin": false,
"LoadUnloadModifier": 60,
"CheckTimeModifier": 20,
"CheckOverride": 0,
"ReloadMagType": "ExternalMagazine",
"VisibleAmmoRangesString": "1-3",
"MalfunctionChance": 0.3,
"TagColor": 0,
"TagName": ""
},
"_proto": "55802d5f4bdc2dac148b458e"
}
}

View File

@ -0,0 +1,87 @@
{
"traderId":"5935c25fb3acc3127c3d8cd9",
"assorts":{
"items":[
{
"_id":"6786e03b67ad44fd9b0fabd0",
"_tpl":"6786e03b67ad44fd9b0fabd0",
"parentId":"hideout",
"slotId":"hideout",
"upd":{
"UnlimitedCount":true,
"StackObjectsCount":999999
}
},
{
"_id":"6786e03b67ad44fd9b0fabd1",
"_tpl":"6786e03b67ad44fd9b0fabd1",
"parentId":"hideout",
"slotId":"hideout",
"upd":{
"UnlimitedCount":true,
"StackObjectsCount":999999
}
},
{
"_id":"6786e03b67ad44fd9b0fabd2",
"_tpl":"6786e03b67ad44fd9b0fabd2",
"parentId":"hideout",
"slotId":"hideout",
"upd":{
"UnlimitedCount":true,
"StackObjectsCount":999999
}
},
{
"_id":"6786e03b67ad44fd9b0fabd3",
"_tpl":"6786e03b67ad44fd9b0fabd3",
"parentId":"hideout",
"slotId":"hideout",
"upd":{
"UnlimitedCount":true,
"StackObjectsCount":999999
}
}
],
"barter_scheme":{
"6786e03b67ad44fd9b0fabd0":[
[
{
"count":21000,
"_tpl":"5449016a4bdc2d6f028b456f"
}
]
],
"6786e03b67ad44fd9b0fabd1":[
[
{
"count":21000,
"_tpl":"5449016a4bdc2d6f028b456f"
}
]
],
"6786e03b67ad44fd9b0fabd2":[
[
{
"count":21000,
"_tpl":"5449016a4bdc2d6f028b456f"
}
]
],
"6786e03b67ad44fd9b0fabd3":[
[
{
"count":21000,
"_tpl":"5449016a4bdc2d6f028b456f"
}
]
]
},
"loyal_level_items":{
"6786e03b67ad44fd9b0fabd0":3,
"6786e03b67ad44fd9b0fabd1":3,
"6786e03b67ad44fd9b0fabd2":3,
"6786e03b67ad44fd9b0fabd3":3
}
}
}

View File

@ -0,0 +1,103 @@
"use strict";
let mydb;
class Mod {
postDBLoad(container) {
// Credit Banner
console.log(`
=======================================
| AUG Attachment Pack |
| Created by: KoKaZ93 |
| 3.10 Port made by: GMAK3R |
=======================================
`);
const modLoader = container.resolve("PreSptModLoader");
const importerUtil = container.resolve("ImporterUtil");
const db = container.resolve("DatabaseServer").getTables();
const locales = db.locales.global;
const items = db.templates.items;
const handbook = db.templates.handbook.Items;
const peacekeeper = db.traders["5935c25fb3acc3127c3d8cd9"];
mydb = importerUtil.loadRecursive(`${modLoader.getModPath("AUG_AttachmentPack")}database/`);
for (const item in mydb.templates.items) {
items[item] = mydb.templates.items[item];
}
for (const item of mydb.templates.handbook.Items) {
handbook.push(item);
}
for (const item of mydb.traders.assort.assorts.items) {
peacekeeper.assort.items.push(item);
}
for (const bc in mydb.traders.assort.assorts.barter_scheme) {
peacekeeper.assort.barter_scheme[bc] = mydb.traders.assort.assorts.barter_scheme[bc];
}
for (const level in mydb.traders.assort.assorts.loyal_level_items) {
peacekeeper.assort.loyal_level_items[level] = mydb.traders.assort.assorts.loyal_level_items[level];
}
for (const localeID in locales) {
if (localeID == "en") {
for (const [itemId, template] of Object.entries(mydb.locales.en.templates)) {
for (const [key, value] of Object.entries(template)) {
locales[localeID][`${itemId} ${key}`] = value;
}
}
}
}
Mod.addHandguardToFilters(db);
Mod.addMagazineToFilters(db);
}
static addHandguardToFilters(db) {
const isItemSlotsExist = (item) =>
item._props && item._props.Slots && item._props.Slots.length > 0;
const attachmentToAdd = ["6786e03b67ad44fd9b0fabd0", "6786e03b67ad44fd9b0fabd1", "6786e03b67ad44fd9b0fabd2"];
const attachmentItemId = "634e61b0767cb15c4601a877";
for (const item of Object.values(db.templates.items)) {
if (isItemSlotsExist(item)) {
for (const slot of item._props.Slots) {
if (slot._props.filters.some((filter) => filter.Filter.includes(attachmentItemId))) {
slot._props.filters.forEach((filter) => {
if (filter.Filter.includes(attachmentItemId)) {
filter.Filter.push(...attachmentToAdd);
}
});
}
}
}
}
}
static addMagazineToFilters(db) {
const isItemSlotsExist = (item) =>
item._props && item._props.Slots && item._props.Slots.length > 0;
const attachmentToAdd = "6786e03b67ad44fd9b0fabd3";
const attachmentItemId = "630e1adbbd357927e4007c09";
for (const item of Object.values(db.templates.items)) {
if (isItemSlotsExist(item)) {
for (const slot of item._props.Slots) {
if (slot._props.filters.some((filter) => filter.Filter.includes(attachmentItemId))) {
slot._props.filters.forEach((filter) => {
if (filter.Filter.includes(attachmentItemId)) {
filter.Filter.push(attachmentToAdd);
}
});
}
}
}
}
}
}
module.exports = { mod: new Mod() };

View File

@ -0,0 +1,9 @@
{
"name": "AUG Attachment Pack",
"author": "KoKaZ93",
"license": "CC BY-NC-SA 3.0",
"version": "1.0.4",
"sptVersion": "3.10.x",
"main": "mod.js",
"isBundleMod": true
}

View File

@ -1,29 +0,0 @@
name: "tagged-release"
on: push
jobs:
tagged-release:
name: "Tagged Release"
runs-on: "ubuntu-latest"
permissions:
contents: write
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 2
- name: Print package.json version (before)
id: versionstep
run: |
echo "version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
working-directory: ${{ github.workspace }}
- uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: ${{ steps.versionstep.outputs.version }}
title: "MOAR ${{ steps.versionstep.outputs.version }}"
prerelease: false
files: |
./dist/*.zip

View File

@ -1,15 +0,0 @@
branches:
- main
- name: staging
prerelease: true
debug: true
ci: true
dryRun: false
plugins:
- "@semantic-release/commit-analyzer"
- "@semantic-release/release-notes-generator"
- "@semantic-release/github"
- "@semantic-release/npm"
- - "@semantic-release/git"
- assets: ["package.json"]
message: "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 Dushaoan
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

@ -1,12 +0,0 @@
{
"live-like": 25,
"more-scavs": 8,
"more-pmcs": 8,
"more-scavs-and-pmcs": 5,
"main-boss-roaming": 5,
"sniper-buddies": 4,
"boss-invasion": 2,
"rogue-invasion": 0,
"raider-invasion": 0,
"insanity": 0
}

View File

@ -1,65 +0,0 @@
{
"live-like": {},
"more-scavs": {
"moreScavGroups": true,
"scavMaxGroupSize": 5,
"scavWaveQuantity": 1.2
},
"more-pmcs": {
"morePmcGroups": true,
"pmcMaxGroupSize": 5,
"pmcWaveQuantity": 1.2
},
"more-scavs-and-pmcs": {
"maxBotCap": 30,
"moreScavGroups": true,
"scavMaxGroupSize": 5,
"morePmcGroups": true,
"pmcMaxGroupSize": 5,
"scavWaveQuantity": 1.2,
"pmcWaveQuantity": 1.2,
"mainBossChanceBuff": 25
},
"boss-invasion": {
"bossOpenZones": true,
"bossInvasion": true,
"bossInvasionSpawnChance": 10,
"mainBossChanceBuff": 25,
"gradualBossInvasion": true
},
"rogue-invasion": {
"randomRaiderGroup": true,
"randomRaiderGroupChance": 50
},
"raider-invasion": {
"randomRaiderGroup": true,
"randomRaiderGroupChance": 50
},
"insanity": {
"scavWaveDistribution": 0.4,
"scavWaveQuantity": 1.3,
"pmcWaveQuantity": 1.3,
"maxBotCap": 30,
"maxBotPerZone": 9,
"moreScavGroups": true,
"morePmcGroups": true,
"pmcMaxGroupSize": 6,
"scavMaxGroupSize": 6,
"snipersHaveFriends": true,
"bossOpenZones": true,
"randomRaiderGroup": true,
"randomRaiderGroupChance": 50,
"randomRogueGroup": true,
"randomRogueGroupChance": 50,
"mainBossChanceBuff": 50,
"bossInvasion": true,
"bossInvasionSpawnChance": 10
},
"main-boss-roaming": {
"bossOpenZones": true,
"mainBossChanceBuff": 35
},
"sniper-buddies": {
"snipersHaveFriends": true
}
}

View File

@ -1,63 +0,0 @@
{
"ADD_THESE_TO_A_MAP_TO_OVERRIDE_OR_ADD_A_BOSS_TO_A_MAP": {
"BOSS_NAME_EXAMPLE": "CHANCE_OF_SPAWNING_PERCENT",
"sectantPriest": 0,
"arenaFighterEvent": 0,
"bossBoarSniper": 0,
"pmcBot": 0,
"bossZryachiy": 0,
"exUsec": 0,
"crazyAssaultEvent": 0,
"peacemaker": 0,
"bossKojaniy": 0,
"bossGluhar": 0,
"bossSanitar": 0,
"bossKilla": 0,
"bossTagilla": 0,
"bossKnight": 0,
"bossBoar": 0,
"bossKolontay": 0,
"bossPartisan": 0,
"bossBully": 0
},
"customs": {
"bossKnight": 30,
"bossPartisan": 30,
"bossBully": 30
},
"factoryDay": {
"bossTagilla": 30
},
"factoryNight": {
"bossTagilla": 30
},
"interchange": {
"bossKilla": 30
},
"laboratory": {},
"lighthouse": {
"bossKnight": 30,
"bossPartisan": 30
},
"rezervbase": {
"bossGluhar": 30
},
"shoreline": {
"bossKnight": 30,
"bossPartisan": 30,
"bossSanitar": 30
},
"tarkovstreets": {
"bossBoar": 30,
"bossKolontay": 30
},
"woods": {
"bossKojaniy": 30,
"bossKnight": 30,
"bossPartisan": 30
},
"gzLow": {},
"gzHigh": {
"bossKolontay": 30
}
}

View File

@ -1,46 +0,0 @@
{
"enableBotSpawning": true,
"pmcDifficulty": 0.6,
"scavDifficulty": 0.3,
"scavWaveDistribution": 0.3,
"scavWaveQuantity": 0.5,
"startingPmcs": false,
"pmcWaveDistribution": 0.8,
"pmcWaveQuantity": 1.6,
"zombiesEnabled": false,
"zombieWaveDistribution": 0.5,
"zombieWaveQuantity": 1,
"zombieHealth": 1,
"maxBotCap": 25,
"maxBotPerZone": 7,
"moreScavGroups": false,
"morePmcGroups": false,
"pmcMaxGroupSize": 4,
"scavMaxGroupSize": 4,
"snipersHaveFriends": false,
"bossOpenZones": false,
"randomRaiderGroup": false,
"randomRaiderGroupChance": 10,
"randomRogueGroup": false,
"randomRogueGroupChance": 10,
"disableBosses": false,
"mainBossChanceBuff": 0,
"bossInvasion": false,
"bossInvasionSpawnChance": 5,
"gradualBossInvasion": true,
"debug": false
}

View File

@ -1,149 +0,0 @@
{
"customs": {
"spawnMinDistance": 30,
"pmcWaveCount": 12,
"scavWaveCount": 21,
"zombieWaveCount": 9,
"scavHotZones": [
"ZoneDormitory",
"ZoneCrossRoad",
"ZoneGasStation"
],
"pmcHotZones": [
"ZoneDormitory",
"ZoneGasStation",
"ZoneCustoms"
]
},
"factoryDay": {
"spawnMinDistance": 20,
"maxBotCapOverride": 12,
"maxBotPerZoneOverride": 10,
"pmcWaveCount": 8,
"scavWaveCount": 9,
"zombieWaveCount": 6
},
"factoryNight": {
"spawnMinDistance": 20,
"maxBotCapOverride": 12,
"maxBotPerZoneOverride": 10,
"pmcWaveCount": 8,
"scavWaveCount": 9,
"zombieWaveCount": 6
},
"interchange": {
"spawnMinDistance": 40,
"pmcWaveCount": 14,
"scavWaveCount": 32,
"zombieWaveCount": 12,
"scavHotZones": [
"ZoneCenterBot",
"ZoneCenter"
],
"pmcHotZones": [
"ZoneIDEA",
"ZoneOLI",
"ZoneCenter"
]
},
"laboratory": {
"spawnMinDistance": 20,
"pmcWaveCount": 10,
"scavWaveCount": 0,
"zombieWaveCount": 12
},
"lighthouse": {
"spawnMinDistance": 40,
"pmcWaveCount": 12,
"scavWaveCount": 20,
"zombieWaveCount": 10,
"scavHotZones": [
"Zone_LongRoad",
"Zone_Village"
],
"pmcHotZones": [
"Zone_DestroyedHouse",
"Zone_Chalet",
"Zone_Village"
]
},
"rezervbase": {
"spawnMinDistance": 40,
"pmcWaveCount": 11,
"scavWaveCount": 24,
"zombieWaveCount": 9,
"scavHotZones": [
"ZoneRailStrorage",
"ZoneBunkerStorage",
"ZoneBarrack"
],
"pmcHotZones": [
"ZoneBarrack",
"ZoneBunkerStorage"
]
},
"shoreline": {
"spawnMinDistance": 40,
"pmcWaveCount": 14,
"scavWaveCount": 32,
"zombieWaveCount": 12,
"scavHotZones": [
"ZoneSanatorium1",
"ZoneGasStation",
"ZonePowerStation",
"ZoneBusStation",
"ZoneStartVillage"
],
"pmcHotZones": [
"ZoneSanatorium2",
"ZoneGasStation",
"ZonePowerStation"
]
},
"tarkovstreets": {
"spawnMinDistance": 40,
"pmcWaveCount": 16,
"scavWaveCount": 28,
"zombieWaveCount": 13,
"scavHotZones": [
"ZoneHotel_2",
"ZoneHotel_1",
"ZoneConstruction",
"ZoneCarShowroom"
],
"pmcHotZones": [
"ZoneSanatorium2",
"ZoneCinema",
"ZoneConcordiaParking"
]
},
"woods": {
"spawnMinDistance": 40,
"pmcWaveCount": 14,
"scavWaveCount": 28,
"zombieWaveCount": 10,
"scavHotZones": [
"ZoneWoodCutter",
"ZoneClearVill",
"ZoneScavBase2",
"ZoneRedHouse"
],
"pmcHotZones": [
"ZoneWoodCutter",
"ZoneBigRocks",
"ZoneHighRocks"
]
},
"gzLow": {
"spawnMinDistance": 30,
"pmcWaveCount": 10,
"scavWaveCount": 18,
"zombieWaveCount": 9
},
"gzHigh": {
"spawnMinDistance": 30,
"pmcWaveCount": 12,
"scavWaveCount": 18,
"zombieWaveCount": 9
}
}

View File

@ -1,25 +0,0 @@
{
"name": "MOAR",
"version": "2.6.1",
"main": "src/mod.js",
"license": "MIT",
"author": "DewardianDev",
"sptVersion": "^3.10.x",
"scripts": {
"setup": "npm i",
"build": "node ./packageBuild.ts"
},
"devDependencies": {
"@semantic-release/git": "^10.0.1",
"@types/node": "16.18.10",
"@typescript-eslint/eslint-plugin": "5.46.1",
"@typescript-eslint/parser": "5.46.1",
"bestzip": "2.2.1",
"eslint": "8.30.0",
"fs-extra": "11.1.0",
"glob": "8.0.3",
"semantic-release": "^24.2.0",
"tsyringe": "4.7.0",
"typescript": "4.9.4"
}
}

View File

@ -1,11 +0,0 @@
import config from "../config/config.json";
import { ILocationBase } from "@spt/models/eft/common/ILocationBase";
export class globalValues {
public static baseConfig: typeof config = undefined;
public static overrideConfig: Partial<typeof config> = undefined;
public static locationsBase: ILocationBase[] = undefined;
public static currentPreset: string = "";
public static forcedPreset: string = "custom";
public static addedMapZones: Record<string, string[]> = {};
}

View File

@ -1,168 +0,0 @@
import { DependencyContainer } from "tsyringe";
import { buildWaves } from "../Spawning/Spawning";
import { StaticRouterModService } from "@spt/services/mod/staticRouter/StaticRouterModService";
import { DynamicRouterModService } from "@spt/services/mod/dynamicRouter/DynamicRouterModService";
import { globalValues } from "../GlobalValues";
import { kebabToTitle } from "../utils";
import PresetWeightingsConfig from "../../config/PresetWeightings.json";
export const setupRoutes = (container: DependencyContainer) => {
const staticRouterModService = container.resolve<StaticRouterModService>(
"StaticRouterModService"
);
const dynamicRouterModService = container.resolve<DynamicRouterModService>(
"DynamicRouterModService"
);
// Make buildwaves run on game end
staticRouterModService.registerStaticRouter(
`moarUpdater`,
[
{
url: "/client/match/local/end",
action: async (_url, info, sessionId, output) => {
buildWaves(container);
return output;
},
},
],
"moarUpdater"
);
staticRouterModService.registerStaticRouter(
`moarGetCurrentPreset`,
[
{
url: "/moar/currentPreset",
action: async () => {
return globalValues.forcedPreset || "random";
},
},
],
"moarGetCurrentPreset"
);
staticRouterModService.registerStaticRouter(
`moarGetAnnouncePreset`,
[
{
url: "/moar/announcePreset",
action: async () => {
if (globalValues.forcedPreset?.toLowerCase() === "random") {
return globalValues.currentPreset;
}
return globalValues.forcedPreset || globalValues.currentPreset;
},
},
],
"moarGetAnnouncePreset"
);
staticRouterModService.registerStaticRouter(
`getDefaultConfig`,
[
{
url: "/moar/getDefaultConfig",
action: async () => {
return JSON.stringify(globalValues.baseConfig);
},
},
],
"getDefaultConfig"
);
staticRouterModService.registerStaticRouter(
`getServerConfigWithOverrides`,
[
{
url: "/moar/getServerConfigWithOverrides",
action: async () => {
return JSON.stringify({
...(globalValues.baseConfig || {}),
...(globalValues.overrideConfig || {}),
});
},
},
],
"getServerConfigWithOverrides"
);
staticRouterModService.registerStaticRouter(
`getServerConfigWithOverrides`,
[
{
url: "/moar/getServerConfigWithOverrides",
action: async () => {
return JSON.stringify({
...globalValues.baseConfig,
...globalValues.overrideConfig,
});
},
},
],
"getServerConfigWithOverrides"
);
staticRouterModService.registerStaticRouter(
`moarGetPresetsList`,
[
{
url: "/moar/getPresets",
action: async () => {
let result = [
...Object.keys(PresetWeightingsConfig).map((preset) => ({
Name: kebabToTitle(preset),
Label: preset,
})),
{ Name: "Random", Label: "random" },
{ Name: "Custom", Label: "custom" },
];
return JSON.stringify({ data: result });
},
},
],
"moarGetPresetsList"
);
staticRouterModService.registerStaticRouter(
"setOverrideConfig",
[
{
url: "/moar/setOverrideConfig",
action: async (
url: string,
overrideConfig: typeof globalValues.overrideConfig = {},
sessionID,
output
) => {
globalValues.overrideConfig = overrideConfig;
buildWaves(container);
return "Success";
},
},
],
"setOverrideConfig"
);
staticRouterModService.registerStaticRouter(
"moarSetPreset",
[
{
url: "/moar/setPreset",
action: async (url: string, { Preset }, sessionID, output) => {
globalValues.forcedPreset = Preset;
buildWaves(container);
return `Current Preset: ${kebabToTitle(
globalValues.forcedPreset || "Random"
)}`;
},
},
],
"moarSetPreset"
);
};

View File

@ -1,154 +0,0 @@
import { IBotConfig } from "@spt/models/spt/config/IBotConfig.d";
import { IPmcConfig } from "@spt/models/spt/config/IPmcConfig.d";
import { DatabaseServer } from "@spt/servers/DatabaseServer";
import _config from "../../config/config.json";
import _mapConfig from "../../config/mapConfig.json";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { DependencyContainer } from "tsyringe";
import { globalValues } from "../GlobalValues";
import { cloneDeep, getRandomPresetOrCurrentlySelectedPreset } from "../utils";
import { ILocationConfig } from "@spt/models/spt/config/ILocationConfig.d";
import { originalMapList } from "./constants";
import { buildBossWaves } from "./buildBossWaves";
import buildZombieWaves from "./buildZombieWaves";
import buildScavMarksmanWaves from "./buildScavMarksmanWaves";
import buildPmcs from "./buildPmcs";
import { setEscapeTimeOverrides } from "./utils";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import updateSpawnLocations from "./updateSpawnLocations";
export const buildWaves = (container: DependencyContainer) => {
const configServer = container.resolve<ConfigServer>("ConfigServer");
const Logger = container.resolve<ILogger>("WinstonLogger");
const pmcConfig = configServer.getConfig<IPmcConfig>(ConfigTypes.PMC);
const botConfig = configServer.getConfig<IBotConfig>(ConfigTypes.BOT);
const locationConfig = configServer.getConfig<ILocationConfig>(
ConfigTypes.LOCATION
);
locationConfig.rogueLighthouseSpawnTimeSettings.waitTimeSeconds = 60;
locationConfig.enableBotTypeLimits = false;
locationConfig.fitLootIntoContainerAttempts = 1; // Move to ALP
locationConfig.addCustomBotWavesToMaps = false;
locationConfig.customWaves = { boss: {}, normal: {} };
const databaseServer = container.resolve<DatabaseServer>("DatabaseServer");
const { locations, bots, globals } = databaseServer.getTables();
let config = cloneDeep(globalValues.baseConfig) as typeof _config;
const preset = getRandomPresetOrCurrentlySelectedPreset();
Object.keys(globalValues.overrideConfig).forEach((key) => {
if (config[key] !== globalValues.overrideConfig[key]) {
config.debug &&
console.log(
`[MOAR] overrideConfig ${key} changed from ${config[key]} to ${globalValues.overrideConfig[key]}`
);
config[key] = globalValues.overrideConfig[key];
}
});
// Set from preset if preset above is not empty
Object.keys(preset).forEach((key) => {
if (config[key] !== preset[key]) {
config.debug &&
console.log(
`[MOAR] preset ${globalValues.currentPreset}: ${key} changed from ${config[key]} to ${preset[key]}`
);
config[key] = preset[key];
}
});
config.debug &&
console.log(
globalValues.forcedPreset === "custom"
? "custom"
: globalValues.currentPreset
);
const {
bigmap: customs,
factory4_day: factoryDay,
factory4_night: factoryNight,
interchange,
laboratory,
lighthouse,
rezervbase,
shoreline,
tarkovstreets,
woods,
sandbox: gzLow,
sandbox_high: gzHigh,
} = locations;
let locationList = [
customs,
factoryDay,
factoryNight,
interchange,
laboratory,
lighthouse,
rezervbase,
shoreline,
tarkovstreets,
woods,
gzLow,
gzHigh,
];
// This resets all locations to original state
if (!globalValues.locationsBase) {
globalValues.locationsBase = locationList.map(({ base }) =>
cloneDeep(base)
);
} else {
locationList = locationList.map((item, key) => ({
...item,
base: cloneDeep(globalValues.locationsBase[key]),
}));
}
pmcConfig.convertIntoPmcChance = {
default: {
assault: { min: 0, max: 0 },
cursedassault: { min: 0, max: 0 },
pmcbot: { min: 0, max: 0 },
exusec: { min: 0, max: 0 },
arenafighter: { min: 0, max: 0 },
arenafighterevent: { min: 0, max: 0 },
crazyassaultevent: { min: 0, max: 0 },
},
factory4_day: { assault: { min: 0, max: 0 } },
laboratory: { pmcbot: { min: 0, max: 0 } },
rezervbase: { pmcbot: { min: 0, max: 0 } },
};
updateSpawnLocations(locationList);
setEscapeTimeOverrides(locationList, _mapConfig, Logger, config);
// Make main waves
buildScavMarksmanWaves(config, locationList, botConfig);
// BOSS RELATED STUFF!
buildBossWaves(config, locationList);
//Zombies
if (config.zombiesEnabled) {
buildZombieWaves(config, locationList, bots);
}
buildPmcs(config, locationList);
originalMapList.forEach((name, index) => {
if (!locations[name]) {
console.log("[MOAR] OH CRAP we have a problem!", name);
} else {
locations[name] = locationList[index];
}
});
};

View File

@ -1,278 +0,0 @@
import { ILocation } from "@spt/models/eft/common/ILocation";
import _config from "../../config/config.json";
import bossConfig from "../../config/bossConfig.json";
import mapConfig from "../../config/mapConfig.json";
import {
bossesToRemoveFromPool,
configLocations,
mainBossNameList,
originalMapList,
} from "./constants";
import { buildBossBasedWave, shuffle } from "./utils";
import { IBossLocationSpawn } from "@spt/models/eft/common/ILocationBase";
import { cloneDeep } from "../utils";
export function buildBossWaves(
config: typeof _config,
locationList: ILocation[]
) {
let {
randomRaiderGroup,
randomRaiderGroupChance,
randomRogueGroup,
randomRogueGroupChance,
mainBossChanceBuff,
bossInvasion,
bossInvasionSpawnChance,
disableBosses,
bossOpenZones,
gradualBossInvasion,
} = config;
const bossList = mainBossNameList.filter(
(bossName) => !["bossKnight"].includes(bossName)
);
const allBosses: Record<string, IBossLocationSpawn> = {};
for (const key in locationList) {
locationList[key].base.BossLocationSpawn.forEach((boss) => {
if (!allBosses[boss.BossName]) {
allBosses[boss.BossName] = boss;
}
});
}
// CreateBossList
const bosses: Record<string, IBossLocationSpawn> = {};
for (let indx = 0; indx < locationList.length; indx++) {
// Disable Bosses
if (disableBosses && !!locationList[indx].base?.BossLocationSpawn) {
locationList[indx].base.BossLocationSpawn = [];
} else {
//Remove all other spawns from pool now that we have the spawns zone list
locationList[indx].base.BossLocationSpawn = locationList[
indx
].base.BossLocationSpawn.filter(
(boss) => !bossesToRemoveFromPool.has(boss.BossName)
);
const location = locationList[indx];
const defaultBossSettings =
mapConfig?.[configLocations[indx]]?.defaultBossSettings;
// Sets bosses spawn chance from settings
if (
location?.base?.BossLocationSpawn &&
defaultBossSettings &&
Object.keys(defaultBossSettings)?.length
) {
const filteredBossList = Object.keys(defaultBossSettings).filter(
(name) => defaultBossSettings[name]?.BossChance !== undefined
);
if (filteredBossList?.length) {
filteredBossList.forEach((bossName) => {
location.base.BossLocationSpawn =
location.base.BossLocationSpawn.map((boss) => ({
...boss,
...(boss.BossName === bossName
? { BossChance: defaultBossSettings[bossName].BossChance }
: {}),
}));
});
}
}
if (randomRaiderGroup) {
const raiderWave = buildBossBasedWave(
randomRaiderGroupChance,
"1,2,2,2,3",
"pmcBot",
"pmcBot",
"",
locationList[indx].base.EscapeTimeLimit
);
location.base.BossLocationSpawn.push(raiderWave);
}
if (randomRogueGroup) {
const rogueWave = buildBossBasedWave(
randomRogueGroupChance,
"1,2,2,2,3",
"exUsec",
"exUsec",
"",
locationList[indx].base.EscapeTimeLimit
);
location.base.BossLocationSpawn.push(rogueWave);
}
//Add each boss from each map to bosses object
const filteredBosses = location.base.BossLocationSpawn?.filter(
({ BossName }) => mainBossNameList.includes(BossName)
);
if (filteredBosses.length) {
for (let index = 0; index < filteredBosses.length; index++) {
const boss = filteredBosses[index];
if (
!bosses[boss.BossName] ||
(bosses[boss.BossName] &&
bosses[boss.BossName].BossChance < boss.BossChance)
) {
bosses[boss.BossName] = { ...boss };
}
}
}
}
}
if (!disableBosses) {
// Make boss Invasion
if (bossInvasion) {
if (bossInvasionSpawnChance) {
bossList.forEach((bossName) => {
if (bosses[bossName])
bosses[bossName].BossChance = bossInvasionSpawnChance;
});
}
for (let key = 0; key < locationList.length; key++) {
//Gather bosses to avoid duplicating.
let bossLocations = "";
const duplicateBosses = [
...locationList[key].base.BossLocationSpawn.filter(
({ BossName, BossZone }) => {
bossLocations += BossZone + ",";
return bossList.includes(BossName);
}
).map(({ BossName }) => BossName),
"bossKnight", // So knight doesn't invade
];
const uniqueBossZones = bossOpenZones
? ""
: [
...new Set(
bossLocations
.split(",")
.filter(
(zone) => !!zone && !zone.toLowerCase().includes("snipe")
)
),
].join(",");
//Build bosses to add
const bossesToAdd = shuffle<IBossLocationSpawn[]>(Object.values(bosses))
.filter(({ BossName }) => !duplicateBosses.includes(BossName))
.map((boss, j) => ({
...boss,
BossZone: uniqueBossZones,
BossEscortAmount:
boss.BossEscortAmount === "0" ? boss.BossEscortAmount : "1",
...(gradualBossInvasion ? { Time: j * 20 + 1 } : {}),
}));
// UpdateBosses
locationList[key].base.BossLocationSpawn = [
...locationList[key].base.BossLocationSpawn,
...bossesToAdd,
];
}
}
let hasChangedBossSpawns = false;
// console.log(Object.keys(allBosses));
configLocations.forEach((mapName, index) => {
const bossLocationSpawn = locationList[index].base.BossLocationSpawn;
const mapBossConfig: Record<string, number> = cloneDeep(
bossConfig[mapName] || {}
);
// if (Object.keys(mapBossConfig).length === 0) console.log(name, "empty");
const adjusted = new Set<string>([]);
bossLocationSpawn.forEach(({ BossName, BossChance }, bossIndex) => {
if (typeof mapBossConfig[BossName] === "number") {
if (BossChance !== mapBossConfig[BossName]) {
if (!hasChangedBossSpawns) {
console.log(
`\n[MOAR]: --- Adjusting default boss spawn rates --- `
);
hasChangedBossSpawns = true;
}
console.log(
`[MOAR]: ${mapName} ${BossName}: ${locationList[index].base.BossLocationSpawn[bossIndex].BossChance} => ${mapBossConfig[BossName]}`
);
locationList[index].base.BossLocationSpawn[bossIndex].BossChance =
mapBossConfig[BossName];
}
adjusted.add(BossName);
}
});
const bossesToAdd = Object.keys(mapBossConfig)
.filter(
(adjustName) => !adjusted.has(adjustName) && !!allBosses[adjustName]
)
.map((bossName) => {
`[MOAR]: Adding non-default boss ${bossName} to ${originalMapList[index]}`;
const newBoss: IBossLocationSpawn = cloneDeep(
allBosses[bossName] || {}
);
newBoss.BossChance = mapBossConfig[bossName];
// console.log(
// "Adding boss",
// bossName,
// "to ",
// originalMapList[index],
// "spawn chance =>",
// mapBossConfig[bossName]
// );
return newBoss;
});
// console.log(bossesToAdd);
if (bossOpenZones || mainBossChanceBuff) {
locationList[index].base?.BossLocationSpawn?.forEach((boss, key) => {
if (bossList.includes(boss.BossName)) {
if (bossOpenZones) {
locationList[index].base.BossLocationSpawn[key] = {
...locationList[index].base.BossLocationSpawn[key],
BossZone: "",
};
}
if (!!boss.BossChance && mainBossChanceBuff > 0) {
locationList[index].base.BossLocationSpawn[key] = {
...locationList[index].base.BossLocationSpawn[key],
BossChance:
boss.BossChance + mainBossChanceBuff > 100
? 100
: Math.round(boss.BossChance + mainBossChanceBuff),
};
}
}
});
}
locationList[index].base.BossLocationSpawn = [
...locationList[index].base.BossLocationSpawn,
...bossesToAdd,
];
bossesToAdd.length &&
console.log(
`[MOAR] Adding the following bosses to map ${
configLocations[index]
}: ${bossesToAdd.map(({ BossName }) => BossName)}`
);
});
if (hasChangedBossSpawns) {
console.log(
`[MOAR]: --- Adjusting default boss spawn rates complete --- \n`
);
}
}
}

View File

@ -1,87 +0,0 @@
import { ILocation } from "@spt/models/eft/common/ILocation";
import _config from "../../config/config.json";
import mapConfig from "../../config/mapConfig.json";
import {
bossesToRemoveFromPool,
defaultEscapeTimes,
defaultHostility,
} from "./constants";
import { buildPmcWaves, MapSettings, shuffle } from "./utils";
import { saveToFile } from "../utils";
export default function buildPmcs(
config: typeof _config,
locationList: ILocation[]
) {
for (let index = 0; index < locationList.length; index++) {
const mapSettingsList = Object.keys(mapConfig) as Array<
keyof typeof mapConfig
>;
const map = mapSettingsList[index];
locationList[index].base.BotLocationModifier.AdditionalHostilitySettings =
defaultHostility;
const { pmcHotZones = [] } = (mapConfig?.[map] as MapSettings) || {};
let pmcZones = shuffle<string[]>([
...new Set(
[...locationList[index].base.SpawnPointParams]
.filter(
({ Categories, BotZoneName }) =>
!!BotZoneName &&
(Categories.includes("Player") ||
(map === "laboratory" &&
!BotZoneName.includes("BotZoneGate"))) &&
!BotZoneName.includes("snipe")
)
.map(({ BotZoneName, ...rest }) => {
return BotZoneName;
})
),
...pmcHotZones,
]);
// Make labs have only named zones
if (map === "laboratory") {
pmcZones = new Array(10).fill(pmcZones).flat(1);
// console.log(pmcZones);
}
const timeLimit = locationList[index].base.EscapeTimeLimit * 60;
const { pmcWaveCount } = mapConfig[map];
const escapeTimeLimitRatio = Math.round(
locationList[index].base.EscapeTimeLimit / defaultEscapeTimes[map]
);
const totalWaves = Math.round(
pmcWaveCount * config.pmcWaveQuantity * escapeTimeLimitRatio
);
// console.log(pmcZones.length, totalWaves);
const numberOfZoneless = totalWaves - pmcZones.length;
if (numberOfZoneless > 0) {
const addEmpty = new Array(numberOfZoneless).fill("");
pmcZones = shuffle<string[]>([...pmcZones, ...addEmpty]);
}
// if (map === "laboratory") console.log(numberOfZoneless, pmcZones);
if (config.debug) {
console.log(`${map} PMC count ${totalWaves} \n`);
escapeTimeLimitRatio !== 1 &&
console.log(
`${map} PMC wave count changed from ${pmcWaveCount} to ${totalWaves} due to escapeTimeLimit adjustment`
);
}
const waves = buildPmcWaves(pmcWaveCount, timeLimit, config, pmcZones);
// if (map === "laboratory")
// console.log(waves.map(({ BossZone }) => BossZone));
// apply our new waves
locationList[index].base.BossLocationSpawn = [
...waves,
...locationList[index].base.BossLocationSpawn,
];
}
}

View File

@ -1,226 +0,0 @@
import { ILocation } from "@spt/models/eft/common/ILocation";
import _config from "../../config/config.json";
import mapConfig from "../../config/mapConfig.json";
import {
configLocations,
defaultEscapeTimes,
defaultHostility,
originalMapList,
} from "./constants";
import { MapSettings, shuffle, waveBuilder } from "./utils";
import { IWave, WildSpawnType } from "@spt/models/eft/common/ILocationBase";
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
import { saveToFile } from "../utils";
export default function buildScavMarksmanWaves(
config: typeof _config,
locationList: ILocation[],
botConfig: IBotConfig
) {
let {
debug,
maxBotCap,
scavWaveQuantity,
scavWaveDistribution,
snipersHaveFriends,
maxBotPerZone,
scavMaxGroupSize,
scavDifficulty,
moreScavGroups,
} = config;
for (let index = 0; index < locationList.length; index++) {
const mapSettingsList = Object.keys(mapConfig) as Array<
keyof typeof mapConfig
>;
const map = mapSettingsList[index];
locationList[index].base = {
...locationList[index].base,
...{
NewSpawn: false,
OcculsionCullingEnabled: true,
OfflineNewSpawn: false,
OfflineOldSpawn: true,
OldSpawn: true,
BotSpawnCountStep: 0,
},
};
locationList[index].base.NonWaveGroupScenario.Enabled = false;
locationList[index].base["BotStartPlayer"] = 0;
if (
locationList[index].base.BotStop <
locationList[index].base.EscapeTimeLimit * 60
) {
locationList[index].base.BotStop =
locationList[index].base.EscapeTimeLimit * 60;
}
const {
maxBotPerZoneOverride,
maxBotCapOverride,
EscapeTimeLimit,
scavHotZones,
} = (mapConfig?.[map] as MapSettings) || {};
// Set per map EscapeTimeLimit
if (EscapeTimeLimit) {
locationList[index].base.EscapeTimeLimit = EscapeTimeLimit;
locationList[index].base.exit_access_time = EscapeTimeLimit + 1;
}
// Set default or per map maxBotCap
if (maxBotCapOverride || maxBotCap) {
const capToSet = maxBotCapOverride || maxBotCap;
// console.log(map, capToSet, maxBotCapOverride, maxBotCap);
locationList[index].base.BotMax = capToSet;
locationList[index].base.BotMaxPvE = capToSet;
botConfig.maxBotCap[originalMapList[index]] = capToSet;
}
// Adjust botZone quantity
if (maxBotPerZoneOverride || maxBotPerZone) {
const BotPerZone = maxBotPerZoneOverride || maxBotPerZone;
// console.log(map, BotPerZone, maxBotPerZoneOverride, maxBotPerZone);
locationList[index].base.MaxBotPerZone = BotPerZone;
}
const sniperLocations = new Set(
[...locationList[index].base.SpawnPointParams]
.filter(
({ Categories, Sides, BotZoneName }) =>
!!BotZoneName &&
Sides.includes("Savage") &&
!Categories.includes("Boss")
)
.filter(
({ BotZoneName, DelayToCanSpawnSec }) =>
BotZoneName?.toLowerCase().includes("snipe") ||
DelayToCanSpawnSec > 300
)
.map(({ BotZoneName }) => BotZoneName)
);
if (sniperLocations.size) {
locationList[index].base.MinMaxBots = [
{
WildSpawnType: "marksman",
max: sniperLocations.size * 5,
min: sniperLocations.size,
},
];
}
const scavZones = shuffle<string[]>([
...new Set(
[...locationList[index].base.SpawnPointParams]
.filter(
({ Categories, Sides, BotZoneName }) =>
!!BotZoneName &&
Sides.includes("Savage") &&
!Categories.includes("Boss")
)
.map(({ BotZoneName }) => BotZoneName)
.filter((name) => !sniperLocations.has(name))
),
]);
// Reduced Zone Delay
locationList[index].base.SpawnPointParams = locationList[
index
].base.SpawnPointParams.map((spawn) => ({
...spawn,
DelayToCanSpawnSec:
spawn.DelayToCanSpawnSec > 20
? Math.round(spawn.DelayToCanSpawnSec / 10)
: spawn.DelayToCanSpawnSec,
}));
const timeLimit = locationList[index].base.EscapeTimeLimit * 60;
const { scavWaveCount } = mapConfig[map];
const escapeTimeLimitRatio = Math.round(
locationList[index].base.EscapeTimeLimit / defaultEscapeTimes[map]
);
// Scavs
const scavTotalWaveCount = Math.round(
scavWaveCount * scavWaveQuantity * escapeTimeLimitRatio
);
config.debug &&
escapeTimeLimitRatio !== 1 &&
console.log(
`${map} Scav wave count changed from ${scavWaveCount} to ${scavTotalWaveCount} due to escapeTimeLimit adjustment`
);
let snipers = waveBuilder(
sniperLocations.size,
Math.round(timeLimit / 4),
0.5,
WildSpawnType.MARKSMAN,
0.7,
false,
2,
[],
shuffle([...sniperLocations]),
80,
false,
true
);
if (snipersHaveFriends)
snipers = snipers.map((wave) => ({
...wave,
slots_min: 0,
...(snipersHaveFriends && wave.slots_max < 2
? { slots_min: 1, slots_max: 2 }
: {}),
}));
const scavWaves = waveBuilder(
scavTotalWaveCount,
timeLimit,
scavWaveDistribution,
WildSpawnType.ASSAULT,
scavDifficulty,
false,
scavMaxGroupSize,
map === "gzHigh" ? [] : scavZones,
scavHotZones,
0,
false,
!!moreScavGroups
);
if (debug) {
let totalscav = 0;
scavWaves.forEach(({ slots_max }) => (totalscav += slots_max));
console.log(configLocations[index]);
console.log(
"Scavs:",
totalscav,
"configVal",
Math.round((totalscav / scavWaveCount) * 100) / 100,
"configWaveCount",
scavWaveCount,
"waveCount",
scavWaves.length,
"\n"
);
}
// const finalSniperWaves = snipers?.map(({ ...rest }, snipKey) => ({
// ...rest,
// number: snipKey,
// time_min: snipKey * 120,
// time_max: snipKey * 120 + 120,
// }));
// if (map === "customs") saveToFile({ scavWaves }, "scavWaves.json");
locationList[index].base.waves = [...snipers, ...scavWaves]
.sort(({ time_min: a }, { time_min: b }) => a - b)
.map((wave, i) => ({ ...wave, number: i + 1 }));
}
}

View File

@ -1,80 +0,0 @@
import { ILocation } from "@spt/models/eft/common/ILocation";
import _config from "../../config/config.json";
import mapConfig from "../../config/mapConfig.json";
import { configLocations, defaultEscapeTimes } from "./constants";
import {
buildZombie,
getHealthBodyPartsByPercentage,
zombieTypes,
} from "./utils";
import { IBots } from "@spt/models/spt/bots/IBots";
export default function buildZombieWaves(
config: typeof _config,
locationList: ILocation[],
bots: IBots
) {
let { debug, zombieWaveDistribution, zombieWaveQuantity, zombieHealth } =
config;
const zombieBodyParts = getHealthBodyPartsByPercentage(zombieHealth);
zombieTypes.forEach((type) => {
bots.types?.[type]?.health?.BodyParts?.forEach((_, index) => {
bots.types[type].health.BodyParts[index] = zombieBodyParts;
});
});
for (let indx = 0; indx < locationList.length; indx++) {
const location = locationList[indx].base;
const mapSettingsList = Object.keys(mapConfig) as Array<
keyof typeof mapConfig
>;
const map = mapSettingsList[indx];
const { zombieWaveCount } = mapConfig?.[configLocations[indx]];
// if (location.Events?.Halloween2024?.MaxCrowdAttackSpawnLimit)
// location.Events.Halloween2024.MaxCrowdAttackSpawnLimit = 100;
// if (location.Events?.Halloween2024?.CrowdCooldownPerPlayerSec)
// location.Events.Halloween2024.CrowdCooldownPerPlayerSec = 60;
// if (location.Events?.Halloween2024?.CrowdCooldownPerPlayerSec)
// location.Events.Halloween2024.CrowdsLimit = 10;
// if (location.Events?.Halloween2024?.CrowdAttackSpawnParams)
// location.Events.Halloween2024.CrowdAttackSpawnParams = [];
if (!zombieWaveCount) return;
const escapeTimeLimitRatio = Math.round(
locationList[indx].base.EscapeTimeLimit / defaultEscapeTimes[map]
);
const zombieTotalWaveCount = Math.round(
zombieWaveCount * zombieWaveQuantity * escapeTimeLimitRatio
);
config.debug &&
escapeTimeLimitRatio !== 1 &&
console.log(
`${map} Zombie wave count changed from ${zombieWaveCount} to ${zombieTotalWaveCount} due to escapeTimeLimit adjustment`
);
const zombieWaves = buildZombie(
zombieTotalWaveCount,
location.EscapeTimeLimit,
zombieWaveDistribution,
9999
);
debug &&
console.log(
configLocations[indx],
" generated ",
zombieWaves.length,
"Zombies"
);
location.BossLocationSpawn.push(...zombieWaves);
// console.log(zombieWaves[0], zombieWaves[7]);
}
}

View File

@ -1,204 +0,0 @@
export const defaultHostility = [
{
AlwaysEnemies: [
"bossTest",
"followerTest",
"bossKilla",
"bossKojaniy",
"followerKojaniy",
"cursedAssault",
"bossGluhar",
"followerGluharAssault",
"followerGluharSecurity",
"followerGluharScout",
"followerGluharSnipe",
"followerSanitar",
"bossSanitar",
"test",
"assaultGroup",
"sectantWarrior",
"sectantPriest",
"bossTagilla",
"followerTagilla",
"bossKnight",
"followerBigPipe",
"followerBirdEye",
"bossBoar",
"followerBoar",
"arenaFighter",
"arenaFighterEvent",
"bossBoarSniper",
"crazyAssaultEvent",
"sectactPriestEvent",
"followerBoarClose1",
"followerBoarClose2",
"bossKolontay",
"followerKolontayAssault",
"followerKolontaySecurity",
"shooterBTR",
"bossPartisan",
"spiritWinter",
"spiritSpring",
"peacemaker",
"skier",
"assault",
"marksman",
"pmcUSEC",
"pmcBEAR",
"exUsec",
"pmcBot",
"bossBully",
],
AlwaysFriends: [
"bossZryachiy",
"followerZryachiy",
"peacefullZryachiyEvent",
"ravangeZryachiyEvent",
"gifter",
],
BearEnemyChance: 100,
BearPlayerBehaviour: "AlwaysEnemies",
BotRole: "pmcBEAR",
ChancedEnemies: [],
Neutral: [],
SavagePlayerBehaviour: "AlwaysEnemies",
UsecEnemyChance: 100,
UsecPlayerBehaviour: "AlwaysEnemies",
Warn: ["sectactPriestEvent"],
},
{
AlwaysEnemies: [
"bossTest",
"followerTest",
"bossKilla",
"bossKojaniy",
"followerKojaniy",
"cursedAssault",
"bossGluhar",
"followerGluharAssault",
"followerGluharSecurity",
"followerGluharScout",
"followerGluharSnipe",
"followerSanitar",
"bossSanitar",
"test",
"assaultGroup",
"sectantWarrior",
"sectantPriest",
"bossTagilla",
"followerTagilla",
"bossKnight",
"followerBigPipe",
"followerBirdEye",
"bossBoar",
"followerBoar",
"arenaFighter",
"arenaFighterEvent",
"bossBoarSniper",
"crazyAssaultEvent",
"sectactPriestEvent",
"followerBoarClose1",
"followerBoarClose2",
"bossKolontay",
"followerKolontayAssault",
"followerKolontaySecurity",
"shooterBTR",
"bossPartisan",
"spiritWinter",
"spiritSpring",
"peacemaker",
"skier",
"assault",
"marksman",
"pmcUSEC",
"pmcBEAR",
"exUsec",
"pmcBot",
"bossBully",
],
AlwaysFriends: [
"bossZryachiy",
"followerZryachiy",
"peacefullZryachiyEvent",
"ravangeZryachiyEvent",
"gifter",
],
BearEnemyChance: 100,
BearPlayerBehaviour: "AlwaysEnemies",
BotRole: "pmcUSEC",
ChancedEnemies: [],
Neutral: [],
SavagePlayerBehaviour: "AlwaysEnemies",
UsecEnemyChance: 100,
UsecPlayerBehaviour: "AlwaysEnemies",
Warn: ["sectactPriestEvent"],
},
];
export const configLocations = [
"customs",
"factoryDay",
"factoryNight",
"interchange",
"laboratory",
"lighthouse",
"rezervbase",
"shoreline",
"tarkovstreets",
"woods",
"gzLow",
"gzHigh",
];
export const originalMapList = [
"bigmap",
"factory4_day",
"factory4_night",
"interchange",
"laboratory",
"lighthouse",
"rezervbase",
"shoreline",
"tarkovstreets",
"woods",
"sandbox",
"sandbox_high",
];
export const bossesToRemoveFromPool = new Set([
"assault",
"pmcBEAR",
"pmcUSEC",
"infectedAssault",
"infectedTagilla",
"infectedLaborant",
"infectedCivil",
]);
export const mainBossNameList = [
"bossKojaniy",
"bossGluhar",
"bossSanitar",
"bossKilla",
"bossTagilla",
"bossKnight",
"bossBoar",
"bossKolontay",
"bossPartisan",
"bossBully",
];
export const defaultEscapeTimes = {
customs: 40,
factoryDay: 20,
factoryNight: 25,
interchange: 40,
laboratory: 35,
lighthouse: 40,
rezervbase: 40,
shoreline: 45,
tarkovstreets: 50,
woods: 40,
gzLow: 35,
gzHigh: 35,
};

View File

@ -1,38 +0,0 @@
import { ILocation } from "@spt/models/eft/common/ILocation";
import { configLocations } from "./constants";
import mapConfig from "../../config/mapConfig.json";
export default function updateSpawnLocations(locationList: ILocation[]) {
for (let index = 0; index < locationList.length; index++) {
const map = configLocations[index];
const limit = mapConfig[map].spawnMinDistance;
// console.log("\n" + map);
locationList[index].base.SpawnPointParams.forEach(
(
{ ColliderParams, BotZoneName, DelayToCanSpawnSec, Categories, Sides },
innerIndex
) => {
if (
ColliderParams?._props?.Radius !== undefined &&
ColliderParams?._props?.Radius < limit &&
!BotZoneName?.toLowerCase().includes("snipe") &&
DelayToCanSpawnSec < 300
) {
// console.log(
// "----",
// ColliderParams._props.Radius,
// "=>",
// limit,
// BotZoneName
// );
locationList[index].base.SpawnPointParams[
innerIndex
].ColliderParams._props.Radius = limit;
}
}
);
}
}

View File

@ -1,430 +0,0 @@
import {
IBossLocationSpawn,
IWave,
WildSpawnType,
} from "@spt/models/eft/common/ILocationBase";
import _config from "../../config/config.json";
import { ILocation } from "@spt/models/eft/common/ILocation";
import { defaultEscapeTimes } from "./constants";
import { ILogger } from "@spt/models/spt/utils/ILogger";
export const waveBuilder = (
totalWaves: number,
timeLimit: number,
waveDistribution: number,
wildSpawnType: "marksman" | "assault",
difficulty: number,
isPlayer: boolean,
maxSlots: number,
combinedZones: string[] = [],
specialZones: string[] = [],
offset?: number,
starting?: boolean,
moreGroups?: boolean
): IWave[] => {
if (totalWaves === 0) return [];
const averageTime = timeLimit / totalWaves;
const firstHalf = Math.round(averageTime * (1 - waveDistribution));
const secondHalf = Math.round(averageTime * (1 + waveDistribution));
let timeStart = offset || 0;
const waves: IWave[] = [];
let maxSlotsReached = Math.round(1.3 * totalWaves);
while (
totalWaves > 0 &&
(waves.length < totalWaves || specialZones.length > 0)
) {
const accelerate = totalWaves > 5 && waves.length < totalWaves / 3;
const stage = Math.round(
waves.length < Math.round(totalWaves * 0.5)
? accelerate
? firstHalf / 3
: firstHalf
: secondHalf
);
const min = !offset && waves.length < 1 ? 0 : timeStart;
const max = !offset && waves.length < 1 ? 0 : timeStart + 10;
if (waves.length >= 1 || offset) timeStart = timeStart + stage;
const BotPreset = getDifficulty(difficulty);
// console.log(wildSpawnType, BotPreset);
// Math.round((1 - waves.length / totalWaves) * maxSlots) || 1;
let slotMax = Math.round(
(moreGroups ? Math.random() : Math.random() * Math.random()) * maxSlots
);
if (slotMax < 1) slotMax = 1;
const slotMin = (Math.round(Math.random() * slotMax) || 1) - 1;
waves.push({
BotPreset,
BotSide: getBotSide(wildSpawnType),
SpawnPoints: getZone(
specialZones,
combinedZones,
waves.length >= totalWaves
),
isPlayers: isPlayer,
slots_max: slotMax,
slots_min: slotMin,
time_min: starting || !max ? -1 : min,
time_max: starting || !max ? -1 : max,
WildSpawnType: wildSpawnType as WildSpawnType,
number: waves.length,
sptId: wildSpawnType + waves.length,
SpawnMode: ["regular", "pve"],
});
maxSlotsReached -= slotMax;
// if (wildSpawnType === "assault") console.log(slotMax, maxSlotsReached);
if (maxSlotsReached <= 0) break;
}
// console.log(waves.map(({ slots_min }) => slots_min));
return waves;
};
const getZone = (specialZones, combinedZones, specialOnly) => {
if (!specialOnly && combinedZones.length)
return combinedZones[
Math.round((combinedZones.length - 1) * Math.random())
];
if (specialZones.length) return specialZones.pop();
return "";
};
export const getDifficulty = (diff: number) => {
const randomNumb = Math.random() + diff;
switch (true) {
case randomNumb < 0.55:
return "easy";
case randomNumb < 1.4:
return "normal";
case randomNumb < 1.85:
return "hard";
default:
return "impossible";
}
};
export const shuffle = <n>(array: any): n => {
let currentIndex = array.length,
randomIndex;
// While there remain elements to shuffle.
while (currentIndex != 0) {
// Pick a remaining element.
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex],
array[currentIndex],
];
}
return array;
};
const getBotSide = (
spawnType: "marksman" | "assault" | "pmcBEAR" | "pmcUSEC"
) => {
switch (spawnType) {
case "pmcBEAR":
return "Bear";
case "pmcUSEC":
return "Usec";
default:
return "Savage";
}
};
export const buildBossBasedWave = (
BossChance: number,
BossEscortAmount: string,
BossEscortType: string,
BossName: string,
BossZone: string,
raidTime?: number
): IBossLocationSpawn => {
return {
BossChance,
BossDifficult: "normal",
BossEscortAmount,
BossEscortDifficult: "normal",
BossEscortType,
BossName,
BossPlayer: false,
BossZone,
Delay: 0,
ForceSpawn: false,
IgnoreMaxBots: true,
RandomTimeSpawn: false,
Time: raidTime ? Math.round(Math.random() * (raidTime * 5)) : -1,
Supports: null,
TriggerId: "",
TriggerName: "",
spawnMode: ["regular", "pve"],
};
};
export const zombieTypes = [
"infectedassault",
"infectedpmc",
"infectedlaborant",
"infectedcivil",
];
export const zombieTypesCaps = [
"infectedAssault",
"infectedPmc",
"infectedLaborant",
"infectedCivil",
];
export const getRandomDifficulty = (num: number = 1.5) =>
getDifficulty(Math.round(Math.random() * num * 10) / 10);
export const getRandomZombieType = () =>
zombieTypesCaps[Math.round((zombieTypesCaps.length - 1) * Math.random())];
export const buildPmcWaves = (
totalWaves: number,
escapeTimeLimit: number,
config: typeof _config,
bossZones: string[]
): IBossLocationSpawn[] => {
let {
pmcMaxGroupSize,
pmcDifficulty,
startingPmcs,
morePmcGroups,
pmcWaveDistribution,
} = config;
const averageTime = escapeTimeLimit / totalWaves;
const firstHalf = Math.round(averageTime * (1 - pmcWaveDistribution));
const secondHalf = Math.round(averageTime * (1 + pmcWaveDistribution));
let timeStart = -1;
const waves: IBossLocationSpawn[] = [];
let maxSlotsReached = totalWaves;
while (totalWaves > 0) {
let bossEscortAmount = Math.round(
(morePmcGroups ? 1 : Math.random()) *
Math.random() *
(pmcMaxGroupSize - 1)
);
if (bossEscortAmount < 0) bossEscortAmount = 0;
const accelerate = totalWaves > 5 && waves.length < totalWaves / 3;
const stage = startingPmcs
? 10
: Math.round(
waves.length < Math.round(totalWaves * 0.5)
? accelerate
? firstHalf / 3
: firstHalf
: secondHalf
);
if (waves.length >= 1) timeStart = timeStart + stage;
// console.log(timeStart, BossEscortAmount);
const side = Math.random() > 0.5 ? "pmcBEAR" : "pmcUSEC";
const BossDifficult = getDifficulty(pmcDifficulty);
waves.push({
BossChance: 9999,
BossDifficult,
BossEscortAmount: bossEscortAmount.toString(),
BossEscortDifficult: "normal",
BossEscortType: side,
BossName: side,
BossPlayer: false,
BossZone: bossZones.pop() || "",
Delay: 0,
DependKarma: false,
DependKarmaPVE: false,
ForceSpawn: true,
IgnoreMaxBots: true,
RandomTimeSpawn: false,
Time: timeStart,
Supports: null,
TriggerId: "",
TriggerName: "",
spawnMode: ["regular", "pve"],
});
maxSlotsReached -= 1 + bossEscortAmount;
if (maxSlotsReached <= 0) break;
}
return waves;
};
export const buildZombie = (
totalWaves: number,
escapeTimeLimit: number,
waveDistribution: number,
BossChance: number = 100
): IBossLocationSpawn[] => {
const averageTime = (escapeTimeLimit * 60) / totalWaves;
const firstHalf = Math.round(averageTime * (1 - waveDistribution));
const secondHalf = Math.round(averageTime * (1 + waveDistribution));
let timeStart = 90;
const waves: IBossLocationSpawn[] = [];
let maxSlotsReached = Math.round(1.3 * totalWaves);
while (totalWaves > 0) {
const accelerate = totalWaves > 5 && waves.length < totalWaves / 3;
const stage = Math.round(
waves.length < Math.round(totalWaves * 0.5)
? accelerate
? firstHalf / 3
: firstHalf
: secondHalf
);
if (waves.length >= 1) timeStart = timeStart + stage;
const main = getRandomZombieType();
waves.push({
BossChance,
BossDifficult: "normal",
BossEscortAmount: "0",
BossEscortDifficult: "normal",
BossEscortType: main,
BossName: main,
BossPlayer: false,
BossZone: "",
Delay: 0,
IgnoreMaxBots: true,
RandomTimeSpawn: false,
Time: timeStart,
Supports: new Array(
Math.round(Math.random() * 4) /* <= 4 AddthistoConfig */
)
.fill("")
.map(() => ({
BossEscortType: getRandomZombieType(),
BossEscortDifficult: ["normal"],
BossEscortAmount: "1",
})),
TriggerId: "",
TriggerName: "",
spawnMode: ["regular", "pve"],
});
maxSlotsReached -= 1 + waves[waves.length - 1].Supports.length;
if (maxSlotsReached <= 0) break;
}
return waves;
};
export interface MapSettings {
EscapeTimeLimit?: number;
maxBotPerZoneOverride?: number;
maxBotCapOverride?: number;
pmcHotZones?: string[];
scavHotZones?: string[];
pmcWaveCount: number;
scavWaveCount: number;
zombieWaveCount: number;
}
export const getHealthBodyPartsByPercentage = (num: number) => {
const num35 = Math.round(35 * num);
const num100 = Math.round(100 * num);
const num70 = Math.round(70 * num);
const num80 = Math.round(80 * num);
return {
Head: {
min: num35,
max: num35,
},
Chest: {
min: num100,
max: num100,
},
Stomach: {
min: num100,
max: num100,
},
LeftArm: {
min: num70,
max: num70,
},
RightArm: {
min: num70,
max: num70,
},
LeftLeg: {
min: num80,
max: num80,
},
RightLeg: {
min: num80,
max: num80,
},
};
};
export interface MapConfigType {
spawnMinDistance: number;
pmcWaveCount: number;
scavWaveCount: number;
zombieWaveCount?: number;
scavHotZones?: string[];
pmcHotZones?: string[];
EscapeTimeLimitOverride?: number;
}
export const setEscapeTimeOverrides = (
locationList: ILocation[],
mapConfig: Record<string, MapConfigType>,
logger: ILogger,
config: typeof _config
) => {
for (let index = 0; index < locationList.length; index++) {
const mapSettingsList = Object.keys(mapConfig) as Array<
keyof typeof mapConfig
>;
const map = mapSettingsList[index];
const override = mapConfig[map].EscapeTimeLimitOverride;
const hardcodedEscapeLimitMax = 5;
if (
!override &&
locationList[index].base.EscapeTimeLimit / defaultEscapeTimes[map] >
hardcodedEscapeLimitMax
) {
const maxLimit = defaultEscapeTimes[map] * hardcodedEscapeLimitMax;
logger.warning(
`[MOAR] EscapeTimeLimit set too high on ${map}\nEscapeTimeLimit changed from ${locationList[index].base.EscapeTimeLimit} => ${maxLimit}\n`
);
locationList[index].base.EscapeTimeLimit = maxLimit;
}
if (override && locationList[index].base.EscapeTimeLimit !== override) {
console.log(
`[Moar] Set ${map}'s Escape time limit to ${override} from ${locationList[index].base.EscapeTimeLimit}\n`
);
locationList[index].base.EscapeTimeLimit = override;
locationList[index].base.EscapeTimeLimitCoop = override;
locationList[index].base.EscapeTimeLimitPVE = override;
}
if (
config.startingPmcs &&
locationList[index].base.EscapeTimeLimit / defaultEscapeTimes[map] > 2
) {
logger.warning(
`[MOAR] Average EscapeTimeLimit is too high (greater than 2x) to enable starting PMCS\nStarting PMCS has been turned off to prevent performance issues.\n`
);
config.startingPmcs = false;
}
}
};

View File

@ -1,28 +0,0 @@
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { DependencyContainer } from "tsyringe";
import config from "../../config/config.json";
import presets from "../../config/Presets.json";
import presetWeightings from "../../config/PresetWeightings.json";
export default function checkPresetLogic(container: DependencyContainer) {
const Logger = container.resolve<ILogger>("WinstonLogger");
for (const key in presetWeightings) {
if (presets[key] === undefined) {
Logger.error(
`\n[MOAR]: No preset found in PresetWeightings.json for preset "${key}" in Presets.json`
);
}
}
for (const key in presets) {
const preset = presets[key];
for (const id in preset) {
if (config[id] === undefined) {
Logger.error(
`\n[MOAR]: No associated key found in config.json called "${id}" for preset "${key}" in Presets.json`
);
}
}
}
}

View File

@ -1,160 +0,0 @@
import { DependencyContainer } from "tsyringe";
import {
ISeasonalEventConfig,
ISeasonalEvent,
} from "@spt/models/spt/config/ISeasonalEventConfig.d";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { SeasonalEventService } from "@spt/services/SeasonalEventService";
import { zombieTypesCaps } from "../Spawning/utils";
export const baseZombieSettings = (enabled: boolean, count: number) =>
({
enabled,
name: "zombies",
type: "Zombies",
startDay: "1",
startMonth: "1",
endDay: "31",
endMonth: "12",
settings: {
enableSummoning: false,
removeEntryRequirement: [],
replaceBotHostility: true,
zombieSettings: {
enabled: true,
mapInfectionAmount: {
Interchange: count === -1 ? randomNumber100() : count,
Lighthouse: count === -1 ? randomNumber100() : count,
RezervBase: count === -1 ? randomNumber100() : count,
Sandbox: count === -1 ? randomNumber100() : count,
Shoreline: count === -1 ? randomNumber100() : count,
TarkovStreets: count === -1 ? randomNumber100() : count,
Woods: count === -1 ? randomNumber100() : count,
bigmap: count === -1 ? randomNumber100() : count,
factory4: count === -1 ? randomNumber100() : count,
laboratory: count === -1 ? randomNumber100() : count,
},
disableBosses: [],
disableWaves: [],
},
},
} as unknown as ISeasonalEvent);
const randomNumber100 = () => Math.round(Math.random() * 100);
export const resetCurrentEvents = (
container: DependencyContainer,
enabled: boolean,
zombieWaveQuantity: number,
random: boolean = false
) => {
const configServer = container.resolve<ConfigServer>("ConfigServer");
const eventConfig = configServer.getConfig<ISeasonalEventConfig>(
ConfigTypes.SEASONAL_EVENT
);
let percentToShow = random ? -1 : Math.round(zombieWaveQuantity * 100);
if (percentToShow > 100) percentToShow = 100;
eventConfig.events = [baseZombieSettings(enabled, percentToShow)];
const seasonalEventService = container.resolve<SeasonalEventService>(
"SeasonalEventService"
) as any;
// First we need to clear any existing data
seasonalEventService.currentlyActiveEvents = [];
seasonalEventService.christmasEventActive = false;
seasonalEventService.halloweenEventActive = false;
// Then re-calculate the cached data
seasonalEventService.cacheActiveEvents();
// seasonalEventService.addEventBossesToMaps("halloweenzombies");
};
export const setUpZombies = (container: DependencyContainer) => {
const configServer = container.resolve<ConfigServer>("ConfigServer");
const eventConfig = configServer.getConfig<ISeasonalEventConfig>(
ConfigTypes.SEASONAL_EVENT
);
eventConfig.events = [baseZombieSettings(false, 100)];
// eventConfig.eventBossSpawns = {
// zombies: eventConfig.eventBossSpawns.halloweenzombies,
// };
eventConfig.eventGear[eventConfig.events[0].name] = {};
eventConfig.hostilitySettingsForEvent.zombies.default =
eventConfig.hostilitySettingsForEvent.zombies.default
.filter(({ BotRole }) => !["pmcBEAR", "pmcUSEC"].includes(BotRole))
.map((host) => ({
...host,
AlwaysEnemies: [
"infectedAssault",
"infectedPmc",
"infectedCivil",
"infectedLaborant",
"infectedTagilla",
"pmcBEAR",
"pmcUSEC",
],
AlwaysNeutral: [
"marksman",
"assault",
"bossTest",
"bossBully",
"followerTest",
"bossKilla",
"bossKojaniy",
"followerKojaniy",
"pmcBot",
"cursedAssault",
"bossGluhar",
"followerGluharAssault",
"followerGluharSecurity",
"followerGluharScout",
"followerGluharSnipe",
"followerSanitar",
"bossSanitar",
"test",
"assaultGroup",
"sectantWarrior",
"sectantPriest",
"bossTagilla",
"followerTagilla",
"exUsec",
"gifter",
"bossKnight",
"followerBigPipe",
"followerBirdEye",
"bossZryachiy",
"followerZryachiy",
"bossBoar",
"followerBoar",
"arenaFighter",
"arenaFighterEvent",
"bossBoarSniper",
"crazyAssaultEvent",
"peacefullZryachiyEvent",
"sectactPriestEvent",
"ravangeZryachiyEvent",
"followerBoarClose1",
"followerBoarClose2",
"bossKolontay",
"followerKolontayAssault",
"followerKolontaySecurity",
"shooterBTR",
"bossPartisan",
"spiritWinter",
"spiritSpring",
"peacemaker",
"skier",
],
SavagePlayerBehaviour: "Neutral",
BearPlayerBehaviour: "AlwaysEnemies",
UsecPlayerBehaviour: "AlwaysEnemies",
}));
// console.log(eventConfig.hostilitySettingsForEvent.zombies.default);
};

View File

@ -1,29 +0,0 @@
import { DependencyContainer } from "tsyringe";
import { IPostSptLoadMod } from "@spt/models/external/IPostSptLoadMod";
import { IPreSptLoadMod } from "@spt/models/external/IPreSptLoadMod";
import { enableBotSpawning } from "../config/config.json";
import { buildWaves } from "./Spawning/Spawning";
import config from "../config/config.json";
import { globalValues } from "./GlobalValues";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { setupRoutes } from "./Routes/routes";
import checkPresetLogic from "./Tests/checkPresets";
class Moar implements IPostSptLoadMod, IPreSptLoadMod {
preSptLoad(container: DependencyContainer): void {
if (enableBotSpawning) setupRoutes(container);
}
postSptLoad(container: DependencyContainer): void {
if (enableBotSpawning) {
checkPresetLogic(container);
globalValues.baseConfig = config;
globalValues.overrideConfig = {};
const logger = container.resolve<ILogger>("WinstonLogger");
logger.info("\n[MOAR]: Starting up, may the bots ever be in your favour!");
buildWaves(container);
}
}
}
module.exports = { mod: new Moar() };

View File

@ -1,57 +0,0 @@
import PresetWeightings from "../config/PresetWeightings.json";
import Presets from "../config/Presets.json";
import { globalValues } from "./GlobalValues";
export const saveToFile = (data, filePath) => {
var fs = require("fs");
let dir = __dirname;
let dirArray = dir.split("\\");
const directory = `${dirArray[dirArray.length - 4]}/${
dirArray[dirArray.length - 3]
}/${dirArray[dirArray.length - 2]}/`;
fs.writeFile(
directory + filePath,
JSON.stringify(data, null, 4),
function (err) {
if (err) throw err;
}
);
};
export const cloneDeep = (objectToClone: any) =>
JSON.parse(JSON.stringify(objectToClone));
export const getRandomPresetOrCurrentlySelectedPreset = () => {
switch (true) {
case globalValues.forcedPreset.toLowerCase() === "custom":
return {};
case !globalValues.forcedPreset:
globalValues.forcedPreset = "random";
break;
case globalValues.forcedPreset === "random":
break;
default:
return Presets[globalValues.forcedPreset];
}
const all = [];
const itemKeys = Object.keys(PresetWeightings);
for (const key of itemKeys) {
for (let i = 0; i < PresetWeightings[key]; i++) {
all.push(key);
}
}
const preset: string = all[Math.round(Math.random() * (all.length - 1))];
globalValues.currentPreset = preset;
return Presets[preset];
};
export const kebabToTitle = (str: string): string =>
str
.split("-")
.map((word) => word.slice(0, 1).toUpperCase() + word.slice(1))
.join(" ");

View File

@ -1,11 +1,11 @@
[General]
gameName=spt
modid=0
version=d2024.12.31.0
version=d2025.1.14.0
newestVersion=
category="1,"
nexusFileStatus=1
installationFile=DewardianDev-MOAR-2.6.1.zip
installationFile=utjan.PlantTimeModifier-1.2.0.zip
repository=Nexus
ignoredVersion=
comments=
@ -15,7 +15,7 @@ url=
hasCustomURL=false
lastNexusQuery=
lastNexusUpdate=
nexusLastModified=2024-12-16T06:46:30Z
nexusLastModified=2025-01-15T01:13:31Z
nexusCategory=0
converted=false
validated=false

View File

@ -1,21 +0,0 @@
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

@ -1,47 +0,0 @@
# 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

@ -1,264 +0,0 @@
{
// 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 bots having the chance to roll ammo choice for rig magazines after selecting ammo choice for weapon
// "enableBotsToRollAmmoAgain" If set to true, AI PMCs will roll their ammo choice for additional magazines based on the chance configured - if false all magazines will always have the same ammo selected for the weapon.
// "chanceToRollAmmoAgain" chance out of 100 that bot will roll ammo again for each subsequent additional magazine they spawn with in their rig.
"enableBotsToRollAmmoAgain": true,
"chanceToRollAmmoAgain": 50,
// 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": [ 10, 25 ],
"scavMedRates": [ 10, 25 ],
"pmcFoodRates": [ 10, 25 ],
"pmcMedRates": [ 10, 25 ],
// 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": true,
"tier1LevelDelta": [ 10, 5 ], // 1-10
"tier2LevelDelta": [ 20, 5 ], // 11-20
"tier3LevelDelta": [ 25, 7 ], // 21-30
"tier4LevelDelta": [ 35, 10 ], // 31-40
"tier5LevelDelta": [ 40, 15 ], // 41-50
"tier6LevelDelta": [ 50, 20 ], // 51-60
"tier7LevelDelta": [ 55, 20 ], // 61-79
// 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 ], // 1-10
"tier2ScavLevelDelta": [ 10, -10 ], // 11-20
"tier3ScavLevelDelta": [ 15, -10 ], // 21-30
"tier4ScavLevelDelta": [ 20, -10 ], // 31-40
"tier5ScavLevelDelta": [ 30, -10 ], // 41-50
"tier6ScavLevelDelta": [ 40, -10 ], // 51-60
"tier7ScavLevelDelta": [ 50, -10 ], // 61-79
// Enable/disable debug logging
"enableDebugLog": true
}

View File

@ -1,32 +0,0 @@
{
"name": "Acids Progressive Bot System",
"version": "1.4.0",
"sptVersion": "~3.10",
"loadBefore": [],
"loadAfter": [
"DanW-SPTQuestingBots"
],
"incompatibilities": [],
"isBundleMod": false,
"main": "src/mod.js",
"scripts": {
"setup": "npm i",
"build": "node ./build.mjs",
"buildinfo": "node ./build.mjs --verbose"
},
"devDependencies": {
"@types/node": "20.11",
"@typescript-eslint/eslint-plugin": "7.2",
"@typescript-eslint/parser": "7.2",
"archiver": "^6.0",
"eslint": "8.57",
"fs-extra": "11.2",
"ignore": "^5.2",
"tsyringe": "4.8.0",
"typescript": "5.4",
"winston": "3.12"
},
"author": "acidphantasm",
"contributors": [],
"license": "MIT"
}

View File

@ -1,479 +0,0 @@
{
"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

@ -1,411 +0,0 @@
{
"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

@ -1,476 +0,0 @@
{
"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

@ -1,430 +0,0 @@
{
"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

@ -1,464 +0,0 @@
{
"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

@ -1,457 +0,0 @@
{
"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

@ -1,471 +0,0 @@
{
"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

@ -1,473 +0,0 @@
{
"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

@ -1,456 +0,0 @@
{
"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

@ -1,493 +0,0 @@
{
"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

@ -1,446 +0,0 @@
{
"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

@ -1,487 +0,0 @@
{
"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

@ -1,436 +0,0 @@
{
"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

@ -1,468 +0,0 @@
{
"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

@ -1,635 +0,0 @@
/* 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;
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": 4
}
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
{
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.removeThermalGoggles(ModConfig.config.enableT7Thermals);
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.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
{
// 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)
{
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);
}
}
}
if (!ModConfig.config.pmcLoot)
{
this.botConfig.disableLootOnBotTypes.push("pmcusec", "pmcbear")
}
for (const botType in allBots)
{
if (botType == "pmcbear" || botType == "pmcusec")
{
allBots[botType].inventory.items.Backpack = {};
allBots[botType].inventory.items.Pockets = {};
allBots[botType].inventory.items.TacticalVest = {};
allBots[botType].inventory.items.SpecialLoot = {};
}
}
}
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.botConfig.disableLootOnBotTypes.push("assault", "marksman", "cursedassault", "assaultgroup", "crazyassaultevent");
}
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

@ -1,752 +0,0 @@
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";
import { APBSLogger } from "../Utils/APBSLogger";
import { RealismHelper } from "../Helpers/RealismHelper";
/** 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,
@inject("APBSLogger") protected apbsLogger: APBSLogger,
@inject("RealismHelper") protected realismHelper: RealismHelper
)
{
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 spawnChances = this.apbsEquipmentGetter.getSpawnChancesByBotRole(botRole, tier);
let compatibleModsPool = tieredModPool[parentTemplate._id]
let actualModPool = tieredModPool;
if (!this.raidInformation.isBotEnabled(botRole))
{
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;
if (modSlotName === "mod_equipment" && this.realismHelper.gasMasks.includes(parentTemplate._id) && this.realismHelper.realismDetected == true)
{
forceSpawn = true;
}
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

@ -1,118 +0,0 @@
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

@ -1,375 +0,0 @@
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";
import { RaidInformation } from "../Globals/RaidInformation";
import { APBSLogger } from "../Utils/APBSLogger";
import { Logging } from "../Enums/Logging";
/** 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,
@inject("RaidInformation") protected raidInformation: RaidInformation,
@inject("APBSLogger") protected apbsLogger: APBSLogger
)
{
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;
const wornItemChances = botJsonTemplate.chances;
const itemGenerationLimitsMinMax: IGeneration = 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
);
if (!this.raidInformation.isBotEnabled(botRole))
{
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);
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;
}
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 (!this.raidInformation.isBotEnabled(botRole))
{
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);
if (this.raidInformation.isBotEnabled(botRole) && ModConfig.config.enableBotsToRollAmmoAgain)
{
this.apbsBotWeaponGenerator.apbsAddExtraMagazinesToInventory(
generatedWeapon,
itemGenerationWeights.items.magazines,
botInventory,
botRole,
botLevel
);
return;
}
this.botWeaponGenerator.addExtraMagazinesToInventory(
generatedWeapon,
itemGenerationWeights.items.magazines,
botInventory,
botRole
);
}
}

View File

@ -1,474 +0,0 @@
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))
{
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

@ -1,418 +0,0 @@
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";
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()
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,
@inject("RaidInformation") protected raidInformation: RaidInformation,
@inject("APBSBotLootCacheService") protected apbsBotLootCacheService: APBSBotLootCacheService,
@inject("APBSLogger") protected apbsLogger: APBSLogger
)
{
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);
let itemCounts: IGenerationWeightingItems = chances.generation.items;
let useOriginalLootCache = false;
if (!this.raidInformation.isBotEnabled(botRole))
{
itemCounts = botJsonTemplate.generation.items;
useOriginalLootCache = true;
}
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(
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.SPECIAL, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.SPECIAL, botJsonTemplate, botLevel),
containersBotHasAvailable,
specialLootItemCount,
botInventory,
botRole,
botItemLimits,
undefined,
undefined,
containersIdFull
);
// Healing items / Meds
this.addLootFromPool(
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.HEALING_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.HEALING_ITEMS, botJsonTemplate, botLevel),
containersBotHasAvailable,
healingItemCount,
botInventory,
botRole,
botItemLimits,
0,
isPmc,
containersIdFull
);
// Drugs
this.addLootFromPool(
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.DRUG_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.DRUG_ITEMS, botJsonTemplate, botLevel),
containersBotHasAvailable,
drugItemCount,
botInventory,
botRole,
botItemLimits,
0,
isPmc,
containersIdFull
);
// Food
this.addLootFromPool(
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.FOOD_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.FOOD_ITEMS, botJsonTemplate, botLevel),
containersBotHasAvailable,
foodItemCount,
botInventory,
botRole,
botItemLimits,
0,
isPmc,
containersIdFull
);
// Drink
this.addLootFromPool(
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.DRINK_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.DRINK_ITEMS, botJsonTemplate, botLevel),
containersBotHasAvailable,
drinkItemCount,
botInventory,
botRole,
botItemLimits,
0,
isPmc,
containersIdFull
);
// Currency
this.addLootFromPool(
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.CURRENCY_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.CURRENCY_ITEMS, botJsonTemplate, botLevel),
containersBotHasAvailable,
currencyItemCount,
botInventory,
botRole,
botItemLimits,
0,
isPmc,
containersIdFull
);
// Stims
this.addLootFromPool(
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.STIM_ITEMS, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.STIM_ITEMS, botJsonTemplate, botLevel),
containersBotHasAvailable,
stimItemCount,
botInventory,
botRole,
botItemLimits,
0,
isPmc,
containersIdFull
);
// Grenades
this.addLootFromPool(
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,
botItemLimits,
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(
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.BACKPACK, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.BACKPACK, botJsonTemplate, botLevel),
[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(
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.VEST, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.VEST, botJsonTemplate, botLevel),
[EquipmentSlots.TACTICAL_VEST],
vestLootCount,
botInventory,
botRole,
botItemLimits,
this.pmcConfig.maxVestLootTotalRub,
isPmc,
containersIdFull
);
}
// Pockets
this.addLootFromPool(
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.POCKET, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.POCKET, botJsonTemplate, botLevel),
[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(
useOriginalLootCache ?
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.SECURE, botJsonTemplate) :
this.apbsBotLootCacheService.apbsGetLootFromCache(botRole, isPmc, LootCacheType.SECURE, botJsonTemplate, botLevel),
[EquipmentSlots.SECURED_CONTAINER],
50,
botInventory,
botRole,
undefined,
-1,
isPmc,
containersIdFull
);
}
}
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

@ -1,394 +0,0 @@
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 as PmcInventory } from "@spt/models/eft/common/tables/IBotBase";
import { IGenerationData, 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";
import { APBSInventoryMagGen } from "../InventoryMagGen/APBSInventoryMagGen";
import { APBSIInventoryMagGen } from "../InventoryMagGen/APBSIInventoryMagGen";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
/** 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,
@injectAll("APBSInventoryMagGen") protected apbsInventoryMagGenComponents: APBSIInventoryMagGen[]
)
{
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);
}
// Check if bot disabled, if it is - use SPT code
if (!this.raidInformation.isBotEnabled(botRole))
{
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
};
}
public apbsAddExtraMagazinesToInventory(
generatedWeaponResult: IGenerateWeaponResult,
magWeights: IGenerationData,
inventory: PmcInventory,
botRole: string,
botLevel: number
): void
{
const weaponAndMods = generatedWeaponResult.weapon;
const weaponTemplate = generatedWeaponResult.weaponTemplate;
const magazineTpl = this.getMagazineTplFromWeaponTemplate(weaponAndMods, weaponTemplate, botRole);
const magTemplate = this.itemHelper.getItem(magazineTpl)[1];
if (!magTemplate)
{
this.logger.error(this.localisationService.getText("bot-unable_to_find_magazine_item", magazineTpl));
return;
}
const ammoTemplate = this.itemHelper.getItem(generatedWeaponResult.chosenAmmoTpl)[1];
if (!ammoTemplate)
{
this.logger.error(
this.localisationService.getText("bot-unable_to_find_ammo_item", generatedWeaponResult.chosenAmmoTpl)
);
return;
}
// Has an UBGL
if (generatedWeaponResult.chosenUbglAmmoTpl)
{
this.addUbglGrenadesToBotInventory(weaponAndMods, generatedWeaponResult, inventory);
}
const apbsInventoryMagGenModel = new APBSInventoryMagGen(
magWeights,
magTemplate,
weaponTemplate,
ammoTemplate,
inventory,
botRole,
botLevel
);
this.apbsInventoryMagGenComponents
.find((v) => v.canHandleInventoryMagGen(apbsInventoryMagGenModel))
.process(apbsInventoryMagGenModel);
// Add x stacks of bullets to SecuredContainer (bots use a magic mag packing skill to reload instantly)
this.addAmmoToSecureContainer(
this.botConfig.secureContainerAmmoStackCount,
generatedWeaponResult.chosenAmmoTpl,
ammoTemplate._props.StackMaxSize,
inventory
);
}
}

View File

@ -1,143 +0,0 @@
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

@ -1,21 +0,0 @@
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

@ -1,167 +0,0 @@
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 =>
{
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

@ -1,154 +0,0 @@
/* 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,
enableBotsToRollAmmoAgain: boolean,
chanceToRollAmmoAgain: number,
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

@ -1,16 +0,0 @@
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

@ -1,169 +0,0 @@
import { injectable } from "tsyringe";
import { ModConfig } from "./ModConfig";
@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
}
}
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

@ -1,373 +0,0 @@
/* 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: 10,
botMaxLevelVariance: 5,
scavMinLevelVariance: 10,
scavMaxLevelVariance: 5
},
{
tier: 3,
playerMinimumLevel: 21,
playerMaximumLevel: 30,
botMinLevelVariance: 15,
botMaxLevelVariance: 7,
scavMinLevelVariance: 15,
scavMaxLevelVariance: 7
},
{
tier: 4,
playerMinimumLevel: 31,
playerMaximumLevel: 40,
botMinLevelVariance: 20,
botMaxLevelVariance: 10,
scavMinLevelVariance: 20,
scavMaxLevelVariance: 10
},
{
tier: 5,
playerMinimumLevel: 41,
playerMaximumLevel: 50,
botMinLevelVariance: 30,
botMaxLevelVariance: 15,
scavMinLevelVariance: 30,
scavMaxLevelVariance: 15
},
{
tier: 6,
playerMinimumLevel: 51,
playerMaximumLevel: 60,
botMinLevelVariance: 40,
botMaxLevelVariance: 20,
scavMinLevelVariance: 40,
scavMaxLevelVariance: 20
},
{
tier: 7,
playerMinimumLevel: 61,
playerMaximumLevel: 100,
botMinLevelVariance: 50,
botMaxLevelVariance: 20,
scavMinLevelVariance: 50,
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
}
}
]
}

View File

@ -1,236 +0,0 @@
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

@ -1,328 +0,0 @@
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

@ -1,672 +0,0 @@
/* 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

@ -1,70 +0,0 @@
/* 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 realismDetected: boolean = false;
public gasMasks = [
"5b432c305acfc40019478128",
"60363c0c92ec1c31037959f5"
];
public initialize():void
{
this.realismDetected = true;
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

@ -1,265 +0,0 @@
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 { SeasonalEventService } from "@spt/services/SeasonalEventService";
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 { APBSBotLootCacheService } from "./ClassExtensions/APBSBotLootCacheService";
import { APBSPlayerScavGenerator } from "./ClassExtensions/APBSPlayerScavGenerator";
import { APBSExternalInventoryMagGen } from "./InventoryMagGen/APBSExternalInventoryMagGen";
import { APBSMethodHolder } from "./InventoryMagGen/APBSMethodHolder";
import { APBSBarrelInventoryMagGen } from "./InventoryMagGen/APBSBarrelInventoryMagGen";
import { APBSInternalMagazineInventoryMagGen } from "./InventoryMagGen/APBSInternalMagazineInventoryMagGen";
import { APBSUbglExternalMagGen } from "./InventoryMagGen/APBSUbglExternalMagGen";
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;
public apbsExternalInventoryMagGen: APBSExternalInventoryMagGen;
public apbsMethodHolder: APBSMethodHolder;
//#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");
this.container.register<APBSMethodHolder>("APBSMethodHolder", APBSMethodHolder, { lifecycle: Lifecycle.Singleton });
this.apbsMethodHolder = container.resolve<APBSMethodHolder>("APBSMethodHolder");
this.container.register<RealismHelper>("RealismHelper", { useClass: RealismHelper })
this.container.register<APBSBotWeaponGenerator>("APBSBotWeaponGenerator", APBSBotWeaponGenerator);
this.container.register<APBSBarrelInventoryMagGen>("APBSBarrelInventoryMagGen", { useClass: APBSBarrelInventoryMagGen })
this.container.register<APBSExternalInventoryMagGen>("APBSExternalInventoryMagGen", { useClass: APBSExternalInventoryMagGen })
this.container.register<APBSInternalMagazineInventoryMagGen>("APBSInternalMagazineInventoryMagGen", { useClass: APBSInternalMagazineInventoryMagGen })
this.container.register<APBSUbglExternalMagGen>("APBSUbglExternalMagGen", { useClass: APBSUbglExternalMagGen })
this.container.registerType("APBSInventoryMagGen", "APBSBarrelInventoryMagGen");
this.container.registerType("APBSInventoryMagGen", "APBSExternalInventoryMagGen");
this.container.registerType("APBSInventoryMagGen", "APBSInternalMagazineInventoryMagGen");
this.container.registerType("APBSInventoryMagGen", "APBSUbglExternalMagGen");
// 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<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("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

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

View File

@ -1,51 +0,0 @@
import { IInventoryMagGen } from "@spt/generators/weapongen/IInventoryMagGen";
import { InventoryMagGen } from "@spt/generators/weapongen/InventoryMagGen";
import { BotWeaponGeneratorHelper } from "@spt/helpers/BotWeaponGeneratorHelper";
import { RandomUtil } from "@spt/utils/RandomUtil";
import { inject, injectable } from "tsyringe";
import { APBSIInventoryMagGen } from "./APBSIInventoryMagGen";
import { APBSInventoryMagGen } from "./APBSInventoryMagGen";
@injectable()
export class APBSBarrelInventoryMagGen implements APBSIInventoryMagGen
{
constructor(
@inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("BotWeaponGeneratorHelper") protected botWeaponGeneratorHelper: BotWeaponGeneratorHelper
)
{}
getPriority(): number
{
return 50;
}
canHandleInventoryMagGen(inventoryMagGen: APBSInventoryMagGen): boolean
{
return inventoryMagGen.getWeaponTemplate()._props.ReloadMode === "OnlyBarrel";
}
process(inventoryMagGen: APBSInventoryMagGen): void
{
// Can't be done by _props.ammoType as grenade launcher shoots grenades with ammoType of "buckshot"
let randomisedAmmoStackSize: number;
if (inventoryMagGen.getAmmoTemplate()._props.StackMaxRandom === 1)
{
// doesnt stack
randomisedAmmoStackSize = this.randomUtil.getInt(3, 6);
}
else
{
randomisedAmmoStackSize = this.randomUtil.getInt(
inventoryMagGen.getAmmoTemplate()._props.StackMinRandom,
inventoryMagGen.getAmmoTemplate()._props.StackMaxRandom
);
}
this.botWeaponGeneratorHelper.addAmmoIntoEquipmentSlots(
inventoryMagGen.getAmmoTemplate()._id,
randomisedAmmoStackSize,
inventoryMagGen.getPmcInventory()
);
}
}

View File

@ -1,203 +0,0 @@
import { IInventoryMagGen } from "@spt/generators/weapongen/IInventoryMagGen";
import { InventoryMagGen } from "@spt/generators/weapongen/InventoryMagGen";
import { BotGeneratorHelper } from "@spt/helpers/BotGeneratorHelper";
import { BotWeaponGeneratorHelper } from "@spt/helpers/BotWeaponGeneratorHelper";
import { ItemHelper } from "@spt/helpers/ItemHelper";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import { EquipmentSlots } from "@spt/models/enums/EquipmentSlots";
import { ItemAddedResult } from "@spt/models/enums/ItemAddedResult";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { LocalisationService } from "@spt/services/LocalisationService";
import { RandomUtil } from "@spt/utils/RandomUtil";
import { inject, injectable } from "tsyringe";
import { APBSIInventoryMagGen } from "./APBSIInventoryMagGen";
import { APBSInventoryMagGen } from "./APBSInventoryMagGen";
import { APBSEquipmentGetter } from "../Utils/APBSEquipmentGetter";
import { APBSTierGetter } from "../Utils/APBSTierGetter";
import { APBSMethodHolder } from "./APBSMethodHolder";
import { BaseClasses } from "@spt/models/enums/BaseClasses";
import { ModConfig } from "../Globals/ModConfig";
@injectable()
export class APBSExternalInventoryMagGen implements APBSIInventoryMagGen
{
constructor(
@inject("PrimaryLogger") protected logger: ILogger,
@inject("ItemHelper") protected itemHelper: ItemHelper,
@inject("LocalisationService") protected localisationService: LocalisationService,
@inject("BotWeaponGeneratorHelper") protected botWeaponGeneratorHelper: BotWeaponGeneratorHelper,
@inject("BotGeneratorHelper") protected botGeneratorHelper: BotGeneratorHelper,
@inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("APBSEquipmentGetter") protected apbsEquipmentGetter: APBSEquipmentGetter,
@inject("APBSTierGetter") protected apbsTierGetter: APBSTierGetter,
@inject("APBSMethodHolder") protected apbsMethodHolder: APBSMethodHolder
)
{}
getPriority(): number
{
return 99;
}
canHandleInventoryMagGen(inventoryMagGen: APBSInventoryMagGen): boolean
{
if (inventoryMagGen.getWeaponTemplate()._props.ReloadMode === "OnlyBarrel") return false;
if (inventoryMagGen.getMagazineTemplate()._props.ReloadMagType === "InternalMagazine") return false;
if (inventoryMagGen.getWeaponTemplate()._parent === BaseClasses.UBGL) return false;
return true; // Fallback, if code reaches here it means no other implementation can handle this type of magazine
}
process(inventoryMagGen: APBSInventoryMagGen): void
{
// Cout of attempts to fit a magazine into bot inventory
let fitAttempts = 0;
// Magazine Db template
let magTemplate = inventoryMagGen.getMagazineTemplate();
let magazineTpl = magTemplate._id;
const weapon = inventoryMagGen.getWeaponTemplate();
const attemptedMagBlacklist: string[] = [];
const defaultMagazineTpl = this.botWeaponGeneratorHelper.getWeaponsDefaultMagazineTpl(weapon);
const randomizedMagazineCount = Number(
this.botWeaponGeneratorHelper.getRandomizedMagazineCount(inventoryMagGen.getMagCount())
);
const tierInfo = this.apbsTierGetter.getTierByLevel(inventoryMagGen.getBotLevel());
const ammoTable = this.apbsEquipmentGetter.getAmmoByBotRole(inventoryMagGen.getBotRole(), tierInfo)
for (let i = 0; i < randomizedMagazineCount; i++)
{
let selectedAmmoForMag = inventoryMagGen.getAmmoTemplate()._id;
if (ModConfig.config.enableBotsToRollAmmoAgain && this.randomUtil.getChance100(ModConfig.config.chanceToRollAmmoAgain))
{
selectedAmmoForMag = this.apbsMethodHolder.getWeightedCompatibleAmmo(ammoTable, weapon);
}
const magazineWithAmmo = this.botWeaponGeneratorHelper.createMagazineWithAmmo(
magazineTpl,
selectedAmmoForMag,
magTemplate
);
const fitsIntoInventory = this.botGeneratorHelper.addItemWithChildrenToEquipmentSlot(
[EquipmentSlots.TACTICAL_VEST, EquipmentSlots.POCKETS],
magazineWithAmmo[0]._id,
magazineTpl,
magazineWithAmmo,
inventoryMagGen.getPmcInventory()
);
if (fitsIntoInventory === ItemAddedResult.NO_CONTAINERS)
{
// No containers to fit magazines, stop trying
break;
}
// No space for magazine and we haven't reached desired magazine count
if (fitsIntoInventory === ItemAddedResult.NO_SPACE && i < randomizedMagazineCount)
{
// Prevent infinite loop by only allowing 5 attempts at fitting a magazine into inventory
if (fitAttempts > 5)
{
this.logger.debug(
`Failed ${fitAttempts} times to add magazine ${magazineTpl} to bot inventory, stopping`
);
break;
}
/* We were unable to fit at least the minimum amount of magazines,
* so we fallback to default magazine and try again.
* Temporary workaround to Killa spawning with no extra mags if he spawns with a drum mag */
if (magazineTpl === defaultMagazineTpl)
{
// We were already on default - stop here to prevent infinite looping
break;
}
// Add failed magazine tpl to blacklist
attemptedMagBlacklist.push(magazineTpl);
// Set chosen magazine tpl to the weapons default magazine tpl and try to fit into inventory next loop
magazineTpl = defaultMagazineTpl;
magTemplate = this.itemHelper.getItem(magazineTpl)[1];
if (!magTemplate)
{
this.logger.error(
this.localisationService.getText("bot-unable_to_find_default_magazine_item", magazineTpl)
);
break;
}
// Edge case - some weapons (SKS) have an internal magazine as default, choose random non-internal magazine to add to bot instead
if (magTemplate._props.ReloadMagType === "InternalMagazine")
{
const result = this.getRandomExternalMagazineForInternalMagazineGun(
inventoryMagGen.getWeaponTemplate()._id,
attemptedMagBlacklist
);
if (!result?._id)
{
this.logger.debug(
`Unable to add additional magazine into bot inventory for weapon: ${weapon._name}, attempted: ${fitAttempts} times`
);
break;
}
magazineTpl = result._id;
magTemplate = result;
fitAttempts++;
}
// Reduce loop counter by 1 to ensure we get full cout of desired magazines
i--;
}
if (fitsIntoInventory === ItemAddedResult.SUCCESS)
{
// Reset fit counter now it succeeded
fitAttempts = 0;
}
}
}
/**
* Get a random compatible external magazine for a weapon, exclude internal magazines from possible pool
* @param weaponTpl Weapon to get mag for
* @returns tpl of magazine
*/
protected getRandomExternalMagazineForInternalMagazineGun(
weaponTpl: string,
magazineBlacklist: string[]
): ITemplateItem | undefined
{
// The mag Slot data for the weapon
const magSlot = this.itemHelper.getItem(weaponTpl)[1]._props.Slots.find((x) => x._name === "mod_magazine");
if (!magSlot)
{
return undefined;
}
// All possible mags that fit into the weapon excluding blacklisted
const magazinePool = magSlot._props.filters[0].Filter.filter((x) => !magazineBlacklist.includes(x)).map(
(x) => this.itemHelper.getItem(x)[1]
);
if (!magazinePool)
{
return undefined;
}
// Non-internal magazines that fit into the weapon
const externalMagazineOnlyPool = magazinePool.filter((x) => x._props.ReloadMagType !== "InternalMagazine");
if (!externalMagazineOnlyPool || externalMagazineOnlyPool?.length === 0)
{
return undefined;
}
// Randomly chosen external magazine
return this.randomUtil.getArrayValue(externalMagazineOnlyPool);
}
}

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