feat(ALP)

This commit is contained in:
GetParanoid 2025-07-18 15:52:20 -05:00
parent ff3ab9a974
commit 6aac2af208
26 changed files with 63289 additions and 0 deletions

View file

@ -0,0 +1,29 @@
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: "ALP ${{ steps.versionstep.outputs.version }}"
prerelease: false
files: |
./dist/*.zip

View file

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

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

View file

@ -0,0 +1,650 @@
{
"DO NOT CHANGE ANYTHING HERE": "DON't ASK FOR HELP IF YOU DO!",
"forceStock": true,
"daytimeSilencerCutoff": -22,
"forbiddenBullets": {
"3": [],
"4": [
"5d6e68a8a4b9360b6c0d54e2",
"5efb0da7a29a85116f6ea05f",
"5efb0cabfb3e451d70735af5",
"5a26ac0ec4a28200741e1e18",
"5cc80f38e4a949001152b560",
"5ba26835d4351e0035628ff5",
"61962d879bb3d20b0946d385",
"5c0d688c86f77413ae3407b2",
"61962b617c6c7b169525f168",
"56dff026d2720bb8668b4567",
"5c0d5e4486f77478390952fe",
"59e690b686f7746c9f75e848",
"601949593ae8f707c4608daa",
"59e0d99486f7744a32234762",
"601aa3d2b2bcb34913271e6d",
"5fd20ff893a8961fc660a954",
"5a6086ea4f39f99cd479502f",
"5efb0c1bd79ff02a1f5e68d9",
"560d61e84bdc2da74d8b4571",
"5e023d48186a883be655e551",
"5cadf6eeae921500134b2799",
"5fc382a9d724d907e2077dab"
],
"5": []
},
"locations": {
"bigmap": {
"sightConfiguration": {
"SniperRifle": ["OpticScope", "AssaultScope"],
"MarksmanRifle": ["OpticScope", "AssaultScope", "Collimator"],
"AssaultCarbine": ["AssaultScope", "Collimator", "CompactCollimator"],
"AssaultRifle": ["AssaultScope", "Collimator", "CompactCollimator"],
"MachineGun": ["Collimator", "CompactCollimator"],
"Smg": ["Collimator", "CompactCollimator"],
"SpecialWeapon": ["Collimator", "CompactCollimator"],
"Shotgun": ["Collimator", "CompactCollimator"],
"Pistol": ["Collimator", "CompactCollimator"],
"Revolver": ["Collimator", "CompactCollimator"],
"GrenadeLauncher": ["Collimator", "CompactCollimator"]
},
"weightingAdjustments": {
"FirstPrimaryWeapon": {
"AssaultCarbine": 1.2,
"AssaultRifle": 1.3,
"GrenadeLauncher": 1,
"MachineGun": 1.2,
"MarksmanRifle": 0.7,
"Revolver": 1.2,
"Shotgun": 1.2,
"Smg": 1.3,
"SniperRifle": 0.7
}
}
},
"factory4_day": {
"sightConfiguration": {
"SniperRifle": ["Collimator", "CompactCollimator"],
"MarksmanRifle": ["Collimator", "CompactCollimator"],
"AssaultCarbine": ["Collimator", "CompactCollimator"],
"AssaultRifle": ["Collimator", "CompactCollimator"],
"MachineGun": ["Collimator", "CompactCollimator"],
"Smg": ["Collimator", "CompactCollimator"],
"SpecialWeapon": ["Collimator", "CompactCollimator"],
"Shotgun": ["Collimator", "CompactCollimator"],
"Pistol": ["Collimator", "CompactCollimator"],
"Revolver": ["Collimator", "CompactCollimator"],
"GrenadeLauncher": ["Collimator", "CompactCollimator"]
},
"weightingAdjustments": {
"FirstPrimaryWeapon": {
"AssaultCarbine": 0.8,
"AssaultRifle": 1.2,
"GrenadeLauncher": 1.5,
"MachineGun": 1.2,
"MarksmanRifle": 0.3,
"Revolver": 1.5,
"Shotgun": 1.2,
"Smg": 1.5,
"SniperRifle": 0.3
}
}
},
"factory4_night": {
"sightConfiguration": {
"SniperRifle": ["Collimator", "CompactCollimator"],
"MarksmanRifle": ["Collimator", "CompactCollimator"],
"AssaultCarbine": ["Collimator", "CompactCollimator"],
"AssaultRifle": ["Collimator", "CompactCollimator"],
"MachineGun": ["Collimator", "CompactCollimator"],
"Smg": ["Collimator", "CompactCollimator"],
"SpecialWeapon": ["Collimator", "CompactCollimator"],
"Shotgun": ["Collimator", "CompactCollimator"],
"Pistol": ["Collimator", "CompactCollimator"],
"Revolver": ["Collimator", "CompactCollimator"],
"GrenadeLauncher": ["Collimator", "CompactCollimator"]
},
"weightingAdjustments": {
"FirstPrimaryWeapon": {
"AssaultCarbine": 0.8,
"AssaultRifle": 1.2,
"GrenadeLauncher": 1.5,
"MachineGun": 1.2,
"MarksmanRifle": 0.3,
"Revolver": 1.5,
"Shotgun": 1.2,
"Smg": 1.5,
"SniperRifle": 0.3
}
}
},
"interchange": {
"sightConfiguration": {
"SniperRifle": ["OpticScope", "AssaultScope"],
"MarksmanRifle": ["OpticScope", "AssaultScope", "Collimator"],
"AssaultCarbine": ["AssaultScope", "Collimator"],
"AssaultRifle": ["AssaultScope", "Collimator", "CompactCollimator"],
"MachineGun": ["Collimator", "CompactCollimator"],
"Smg": ["Collimator", "CompactCollimator"],
"SpecialWeapon": ["Collimator", "CompactCollimator"],
"Shotgun": ["Collimator", "CompactCollimator"],
"Pistol": ["Collimator", "CompactCollimator"],
"Revolver": ["Collimator", "CompactCollimator"],
"GrenadeLauncher": ["Collimator", "CompactCollimator"]
},
"weightingAdjustments": {
"FirstPrimaryWeapon": {
"AssaultCarbine": 1.1,
"AssaultRifle": 1.2,
"GrenadeLauncher": 1,
"MachineGun": 1,
"MarksmanRifle": 1.2,
"Revolver": 0.6,
"Shotgun": 0.6,
"Smg": 0.6,
"SniperRifle": 1.1
}
}
},
"laboratory": {
"sightConfiguration": {
"SniperRifle": [
"AssaultScope",
"Collimator",
"CompactCollimator",
"ThermalVision"
],
"MarksmanRifle": [
"AssaultScope",
"Collimator",
"CompactCollimator",
"ThermalVision"
],
"AssaultCarbine": [
"AssaultScope",
"Collimator",
"CompactCollimator",
"ThermalVision"
],
"AssaultRifle": [
"AssaultScope",
"Collimator",
"CompactCollimator",
"ThermalVision"
],
"MachineGun": ["Collimator", "CompactCollimator", "ThermalVision"],
"Smg": ["Collimator", "CompactCollimator"],
"SpecialWeapon": ["Collimator", "CompactCollimator"],
"Shotgun": ["Collimator", "CompactCollimator"],
"Pistol": ["Collimator", "CompactCollimator"],
"Revolver": ["Collimator", "CompactCollimator"],
"GrenadeLauncher": ["Collimator", "CompactCollimator"]
},
"weightingAdjustments": {
"FirstPrimaryWeapon": {
"AssaultCarbine": 0.8,
"AssaultRifle": 1.3,
"GrenadeLauncher": 1.3,
"MachineGun": 1.2,
"MarksmanRifle": 0.3,
"Revolver": 1.2,
"Shotgun": 1.2,
"Smg": 1.3,
"SniperRifle": 0.3
}
}
},
"lighthouse": {
"sightConfiguration": {
"SniperRifle": ["OpticScope", "AssaultScope"],
"MarksmanRifle": ["OpticScope", "AssaultScope"],
"AssaultCarbine": ["AssaultScope"],
"AssaultRifle": ["AssaultScope", "Collimator"],
"MachineGun": ["Collimator", "CompactCollimator"],
"Smg": ["Collimator", "CompactCollimator"],
"SpecialWeapon": ["Collimator", "CompactCollimator"],
"Shotgun": ["Collimator", "CompactCollimator"],
"Pistol": ["Collimator", "CompactCollimator"],
"Revolver": ["Collimator", "CompactCollimator"],
"GrenadeLauncher": ["Collimator", "CompactCollimator"]
},
"weightingAdjustments": {
"FirstPrimaryWeapon": {
"AssaultCarbine": 1.5,
"AssaultRifle": 1,
"GrenadeLauncher": 0.8,
"MachineGun": 0.7,
"MarksmanRifle": 2,
"Revolver": 0.2,
"Shotgun": 0.2,
"Smg": 0.2,
"SniperRifle": 2
}
}
},
"rezervbase": {
"sightConfiguration": {
"SniperRifle": ["OpticScope", "AssaultScope"],
"MarksmanRifle": ["OpticScope", "AssaultScope"],
"AssaultCarbine": ["AssaultScope", "Collimator", "CompactCollimator"],
"AssaultRifle": ["AssaultScope", "Collimator", "CompactCollimator"],
"MachineGun": ["Collimator", "CompactCollimator"],
"Smg": ["Collimator", "CompactCollimator"],
"SpecialWeapon": ["Collimator", "CompactCollimator"],
"Shotgun": ["Collimator", "CompactCollimator"],
"Pistol": ["Collimator", "CompactCollimator"],
"Revolver": ["Collimator", "CompactCollimator"],
"GrenadeLauncher": ["Collimator", "CompactCollimator"]
},
"weightingAdjustments": {
"FirstPrimaryWeapon": {
"AssaultCarbine": 1.3,
"AssaultRifle": 1,
"GrenadeLauncher": 0.8,
"MachineGun": 0.8,
"MarksmanRifle": 1.6,
"Revolver": 0.3,
"Shotgun": 0.3,
"Smg": 0.5,
"SniperRifle": 1.6
}
}
},
"shoreline": {
"sightConfiguration": {
"SniperRifle": ["OpticScope", "AssaultScope"],
"MarksmanRifle": ["OpticScope", "AssaultScope"],
"AssaultCarbine": ["AssaultScope"],
"AssaultRifle": ["AssaultScope", "Collimator"],
"MachineGun": ["Collimator", "CompactCollimator"],
"Smg": ["Collimator", "CompactCollimator"],
"SpecialWeapon": ["Collimator", "CompactCollimator"],
"Shotgun": ["Collimator", "CompactCollimator"],
"Pistol": ["Collimator", "CompactCollimator"],
"Revolver": ["Collimator", "CompactCollimator"],
"GrenadeLauncher": ["Collimator", "CompactCollimator"]
},
"weightingAdjustments": {
"FirstPrimaryWeapon": {
"AssaultCarbine": 1.5,
"AssaultRifle": 1,
"GrenadeLauncher": 0.8,
"MachineGun": 0.7,
"MarksmanRifle": 2,
"Revolver": 0.2,
"Shotgun": 0.2,
"Smg": 0.2,
"SniperRifle": 2
}
}
},
"tarkovstreets": {
"sightConfiguration": {
"SniperRifle": ["OpticScope", "AssaultScope"],
"MarksmanRifle": ["OpticScope", "AssaultScope"],
"AssaultCarbine": ["AssaultScope", "Collimator", "CompactCollimator"],
"AssaultRifle": ["AssaultScope", "Collimator", "CompactCollimator"],
"MachineGun": ["Collimator", "CompactCollimator"],
"Smg": ["Collimator", "CompactCollimator"],
"SpecialWeapon": ["Collimator", "CompactCollimator"],
"Shotgun": ["Collimator", "CompactCollimator"],
"Pistol": ["Collimator", "CompactCollimator"],
"Revolver": ["Collimator", "CompactCollimator"],
"GrenadeLauncher": ["Collimator", "CompactCollimator"]
},
"weightingAdjustments": {
"FirstPrimaryWeapon": {
"AssaultCarbine": 1.2,
"AssaultRifle": 1.2,
"GrenadeLauncher": 1,
"MachineGun": 1,
"MarksmanRifle": 1,
"Revolver": 1,
"Shotgun": 1,
"Smg": 1.3,
"SniperRifle": 0.8
}
}
},
"sandbox_high": {
"sightConfiguration": {
"SniperRifle": ["OpticScope", "AssaultScope"],
"MarksmanRifle": ["OpticScope", "AssaultScope"],
"AssaultCarbine": ["AssaultScope", "Collimator", "CompactCollimator"],
"AssaultRifle": ["AssaultScope", "Collimator", "CompactCollimator"],
"MachineGun": ["Collimator", "CompactCollimator"],
"Smg": ["Collimator", "CompactCollimator"],
"SpecialWeapon": ["Collimator", "CompactCollimator"],
"Shotgun": ["Collimator", "CompactCollimator"],
"Pistol": ["Collimator", "CompactCollimator"],
"Revolver": ["Collimator", "CompactCollimator"],
"GrenadeLauncher": ["Collimator", "CompactCollimator"]
},
"weightingAdjustments": {
"FirstPrimaryWeapon": {
"AssaultCarbine": 1.2,
"AssaultRifle": 1.2,
"GrenadeLauncher": 1,
"MachineGun": 1,
"MarksmanRifle": 1,
"Revolver": 1,
"Shotgun": 1,
"Smg": 1.3,
"SniperRifle": 0.8
}
}
},
"sandbox": {
"sightConfiguration": {
"SniperRifle": ["OpticScope", "AssaultScope"],
"MarksmanRifle": ["OpticScope", "AssaultScope"],
"AssaultCarbine": ["AssaultScope", "Collimator", "CompactCollimator"],
"AssaultRifle": ["AssaultScope", "Collimator", "CompactCollimator"],
"MachineGun": ["Collimator", "CompactCollimator"],
"Smg": ["Collimator", "CompactCollimator"],
"SpecialWeapon": ["Collimator", "CompactCollimator"],
"Shotgun": ["Collimator", "CompactCollimator"],
"Pistol": ["Collimator", "CompactCollimator"],
"Revolver": ["Collimator", "CompactCollimator"],
"GrenadeLauncher": ["Collimator", "CompactCollimator"]
},
"weightingAdjustments": {
"FirstPrimaryWeapon": {
"AssaultCarbine": 1.2,
"AssaultRifle": 1.2,
"GrenadeLauncher": 1,
"MachineGun": 1,
"MarksmanRifle": 1,
"Revolver": 1,
"Shotgun": 1,
"Smg": 1.3,
"SniperRifle": 0.8
}
}
},
"woods": {
"sightConfiguration": {
"SniperRifle": ["OpticScope", "AssaultScope"],
"MarksmanRifle": ["OpticScope", "AssaultScope"],
"AssaultCarbine": ["OpticScope", "AssaultScope"],
"AssaultRifle": ["AssaultScope", "Collimator"],
"MachineGun": ["Collimator", "CompactCollimator"],
"Smg": ["Collimator", "CompactCollimator"],
"SpecialWeapon": ["Collimator", "CompactCollimator"],
"Shotgun": ["Collimator", "CompactCollimator"],
"Pistol": ["Collimator", "CompactCollimator"],
"Revolver": ["Collimator", "CompactCollimator"],
"GrenadeLauncher": ["Collimator", "CompactCollimator"]
},
"weightingAdjustments": {
"FirstPrimaryWeapon": {
"AssaultCarbine": 1.5,
"AssaultRifle": 1,
"GrenadeLauncher": 0.8,
"MachineGun": 0.7,
"MarksmanRifle": 2,
"Revolver": 0.2,
"Shotgun": 0.2,
"Smg": 0.2,
"SniperRifle": 2
}
}
}
},
"otherBotTypes": {
"assault": {
"weaponSlotIdsToMakeRequired": [],
"randomisation": [
{
"levelRange": {
"min": 1,
"max": 79
},
"generation": {
"specialItems": {
"weights": {
"0": 1
},
"whitelist": {}
},
"healing": {
"weights": {
"0": 5,
"1": 2,
"2": 1
},
"whitelist": {}
},
"drugs": {
"weights": {
"0": 5,
"1": 2
},
"whitelist": {}
},
"stims": {
"weights": {
"0": 20,
"1": 1
},
"whitelist": {}
},
"backpackLoot": {
"weights": {
"0": 4,
"1": 5,
"2": 5,
"3": 4,
"4": 4,
"5": 2,
"6": 2,
"8": 1
},
"whitelist": {}
},
"pocketLoot": {
"weights": {
"0": 1,
"1": 3,
"2": 1
},
"whitelist": {}
},
"vestLoot": {
"weights": {
"0": 1,
"1": 3,
"2": 2,
"3": 1,
"6": 1
},
"whitelist": {}
},
"magazines": {
"weights": {
"0": 1,
"1": 5,
"2": 5,
"3": 1
},
"whitelist": {}
},
"grenades": {
"weights": {
"0": 3,
"1": 1
},
"whitelist": {
"5710c24ad2720bc3458b45a3": 1,
"5a0c27731526d80618476ac4": 1,
"619256e5f8af2c1a4e1f5d92": 1,
"5e32f56fcb6d5863cc5e5ee4": 1,
"5e340dcdcb6d5863cc5e5efb": 1
}
}
},
"equipment": {
"ArmBand": 0,
"ArmorVest": 50,
"Backpack": 44,
"Earpiece": 0,
"Eyewear": 26,
"FaceCover": 47,
"FirstPrimaryWeapon": 92,
"Headwear": 74,
"Holster": 7,
"Pockets": 100,
"Scabbard": 80,
"SecondPrimaryWeapon": 0,
"SecuredContainer": 100,
"TacticalVest": 100
},
"equipmentMods": {
"front_plate": 60,
"back_plate": 60,
"left_side_plate": 15,
"right_side_plate": 15,
"mod_equipment": 10,
"mod_equipment_000": 0,
"mod_equipment_001": 0,
"mod_equipment_002": 0,
"mod_mount": 0,
"mod_nvg": 0
},
"weaponMods": {
"mod_reciever": 99,
"mod_stock_akms": 90,
"mod_stock": 90,
"mod_sight_front": 50,
"mod_sight_rear": 50,
"mod_flashlight": 50,
"mod_muzzle": 5,
"mod_tactical": 10,
"mod_handguard": 0,
"mod_charge": 0,
"mod_equipment": 0,
"mod_equipment_000": 0,
"mod_equipment_001": 0,
"mod_equipment_002": 0,
"mod_foregrip": 0,
"mod_launcher": 0,
"mod_magazine": 0,
"mod_mount": 0,
"mod_mount_000": 0,
"mod_mount_001": 0,
"mod_nvg": 0,
"mod_pistol_grip": 0,
"mod_scope": 0,
"mod_scope_000": 0,
"mod_scope_001": 0,
"mod_scope_002": 0,
"mod_scope_003": 0,
"mod_tactical_000": 0,
"mod_tactical_001": 0,
"mod_tactical_002": 0,
"mod_tactical_003": 0,
"mod_stock_000": 0,
"mod_stock_001": 0,
"mod_barrel": 0,
"mod_bipod": 0,
"mod_mount_002": 0,
"mod_mount_003": 0,
"mod_mount_004": 0,
"mod_mount_005": 0,
"mod_mount_006": 0,
"mod_muzzle_000": 5,
"mod_muzzle_001": 1,
"mod_pistol_grip_akms": 0,
"mod_tactical001": 0,
"mod_tactical002": 0,
"mod_tactical_2": 0,
"mod_gas_block": 0,
"mod_pistolgrip": 0,
"mod_trigger": 0,
"mod_hammer": 0,
"mod_catch": 0
}
}
],
"armorPlateWeighting": [
{
"levelRange": {
"min": 1,
"max": 99
},
"front_plate": {
"2": 25,
"3": 5,
"4": 1,
"5": 1,
"6": 1
},
"back_plate": {
"2": 25,
"3": 5,
"4": 1,
"5": 1,
"6": 1
},
"side_plate": {
"2": 25,
"3": 5,
"4": 1,
"5": 1,
"6": 1
},
"left_side_plate": {
"2": 25,
"3": 5,
"4": 1,
"5": 1,
"6": 1
},
"right_side_plate": {
"2": 25,
"3": 5,
"4": 1,
"5": 1,
"6": 1
}
}
],
"blacklist": [
{
"levelRange": {
"min": 1,
"max": 99
},
"equipment": {
"mod_magazine": [
"5b1fb3e15acfc4001637f068",
"59e5f5a486f7746c530b3ce2"
],
"mod_stock_akms": ["5a0c59791526d8dba737bba7"],
"mod_stock": [
"5a0c59791526d8dba737bba7",
"59ecc28286f7746d7a68aa8c",
"5b222d335acfc4771e1be099",
"5ac78eaf5acfc4001926317a",
"626a8ae89e664a2e2a75f409",
"5649b2314bdc2d79388b4576"
],
"mod_handguard": [
"5648ae314bdc2d3d1c8b457f",
"5827272a24597748c74bdeea",
"5648b4534bdc2d3d1c8b4580"
]
},
"cartridge": {}
}
],
"whitelist": [
{
"levelRange": {
"min": 1,
"max": 99
},
"equipment": {},
"cartridge": {}
}
]
}
}
}

View file

@ -0,0 +1,63 @@
{
"enableProgressionChanges": true,
"enableLevelChanges": true,
"leveledClothing": true,
"enableNonPMCBotChanges": true,
"enableLootChanges": true,
"questUnlockedItemsShifted": true,
"tradedItemsShifted": true,
"addCustomTraderItems": false,
"customTradersToExclude": [
"insertTheTraderNameToIgnoreTheirItems",
"CustomTradersNamesWillPrintToConsoleIfFoundAndaddCustomTraderItemsIsSetToTrue"
],
"customBlacklist": [
"get id's from here https://db.sp-tarkov.com/search/",
"5example3208of34not8f83real8a1id"
],
"levelRange": {
"1": {
"min": 1,
"max": 14
},
"2": {
"min": 15,
"max": 28
},
"3": {
"min": 29,
"max": 39
},
"4": {
"min": 40,
"max": 55
},
"5": {
"min": 56,
"max": 100
}
},
"botRangeAtLevel": {
"1": [12, 5, 1, 1, 0],
"2": [8, 10, 5, 2, 1],
"3": [6, 8, 10, 5, 2],
"4": [4, 6, 8, 7, 3],
"5": [2, 4, 6, 9, 4]
},
"strictEquipmentTiering": true,
"higherTierAmmoChance": 0.3,
"randomness": {
"Ammo": 0.3,
"Holster": 0.2,
"Headwear": 0.3,
"FirstPrimaryWeapon": 0.3,
"Earpiece": 0.2,
"Backpack": 0.2,
"Eyewear": 0.5,
"TacticalVest": 0.1,
"ArmorVest": 0.1,
"FaceCover": 0.3
},
"forceCached": false,
"debug": false
}

View file

@ -0,0 +1,596 @@
{
"addRandomizedKeysToScavs": true,
"lootDisparityMultiplier": 1,
"percentageOfKeysInSpawnPool": 0.3,
"scavLootBlacklist": [],
"additionalScavLoot": ["5c94bbff86f7747ee735c08f"],
"botAmmoRandomness": 0.1,
"botEquipmentRandomness": 0.3,
"ignoreList": ["add names of bot types here you DONT want alp to touch"],
"Example_______IgnoreList": [
"bosspartisan",
"bossbully",
"bosstagilla",
"bossgluhar",
"bosskilla",
"bosskojaniy",
"bosssanitar",
"bosskolontay",
"bossknight"
],
"nonPmcBots": {
"bossboar": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"AllowSniperRifles": false,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Holster": [0, 0.5],
"FirstPrimaryWeapon": [0.5, 0.9],
"Backpack": [0, 0],
"Ammo": [0.1, 0.5],
"ArmorVest": [0, 0.5],
"TacticalVest": [0, 0.4],
"Headwear": [0, 0.6],
"FaceCover": [0.1, 0.4],
"Eyewear": [0, 0.3],
"BasePlateChance": 40,
"SidePlateChance": 20
},
"bosspartisan": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"AllowSniperRifles": false,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Holster": [0, 0.5],
"FirstPrimaryWeapon": [0, 0.5],
"Backpack": [0, 0],
"Ammo": [0.1, 0.5],
"ArmorVest": [0.3, 0.7],
"TacticalVest": [0.2, 0.6],
"Headwear": [0, 0.6],
"FaceCover": [0.1, 0.4],
"Eyewear": [0, 0.3],
"BasePlateChance": 40,
"SidePlateChance": 20
},
"bossbully": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"AllowSniperRifles": false,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Holster": [0, 0],
"FirstPrimaryWeapon": [0.3, 0.7],
"Backpack": [0, 0],
"Ammo": [0.5, 1],
"ArmorVest": [0.2, 0.5],
"TacticalVest": [0.1, 0.4],
"Headwear": [0.3, 1],
"FaceCover": [0.5, 1],
"Eyewear": [0, 0],
"BasePlateChance": 50,
"SidePlateChance": 30
},
"bosstagilla": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Holster": [0, 0],
"FirstPrimaryWeapon": [0.4, 0.7],
"Backpack": [0, 0],
"Ammo": [0.5, 1],
"ArmorVest": [0.3, 0.7],
"TacticalVest": [0.3, 0.7],
"Headwear": [0.5, 1],
"FaceCover": [0.5, 1],
"Eyewear": [0, 0],
"BasePlateChance": 90,
"SidePlateChance": 60
},
"bossgluhar": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Holster": [0, 0],
"FirstPrimaryWeapon": [0.4, 0.7],
"Backpack": [0, 0],
"Ammo": [0.5, 1],
"ArmorVest": [0.3, 0.7],
"TacticalVest": [0.3, 0.7],
"Headwear": [0.5, 1],
"FaceCover": [0.5, 1],
"Eyewear": [0, 0],
"BasePlateChance": 90,
"SidePlateChance": 60
},
"bosskilla": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Holster": [0, 0],
"FirstPrimaryWeapon": [0.4, 0.7],
"Backpack": [0, 0],
"Ammo": [0.5, 1],
"ArmorVest": [0.3, 0.7],
"TacticalVest": [0.3, 0.7],
"Headwear": [0.5, 1],
"FaceCover": [0.5, 1],
"Eyewear": [0, 0],
"BasePlateChance": 90,
"SidePlateChance": 60
},
"bosskojaniy": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Holster": [0, 0],
"FirstPrimaryWeapon": [0.4, 0.7],
"Backpack": [0, 0],
"Ammo": [0.5, 1],
"ArmorVest": [0.3, 0.7],
"TacticalVest": [0.3, 0.7],
"Headwear": [0.5, 1],
"FaceCover": [0.5, 1],
"Eyewear": [0, 0],
"BasePlateChance": 90,
"SidePlateChance": 60
},
"bosssanitar": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Holster": [0, 0],
"FirstPrimaryWeapon": [0.4, 0.7],
"Backpack": [0, 0],
"Ammo": [0.5, 1],
"ArmorVest": [0.3, 0.7],
"TacticalVest": [0.3, 0.7],
"Headwear": [0.5, 1],
"FaceCover": [0.5, 1],
"Eyewear": [0, 0],
"BasePlateChance": 90,
"SidePlateChance": 60
},
"bosskolontay": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Holster": [0, 0],
"FirstPrimaryWeapon": [0.4, 0.7],
"Backpack": [0, 0],
"Ammo": [0.5, 1],
"ArmorVest": [0.3, 0.7],
"TacticalVest": [0.3, 0.7],
"Headwear": [0.5, 1],
"FaceCover": [0.5, 1],
"Eyewear": [0, 0],
"BasePlateChance": 90,
"SidePlateChance": 60
},
"bossknight": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Holster": [0, 0],
"FirstPrimaryWeapon": [0.4, 0.7],
"Backpack": [0, 0],
"Ammo": [0.5, 1],
"ArmorVest": [0, 0],
"TacticalVest": [0, 0],
"Headwear": [0, 0],
"FaceCover": [0, 0],
"Eyewear": [0, 0],
"BasePlateChance": 90,
"SidePlateChance": 60
},
"followersanitar": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Earpiece": [0, 0.3],
"Backpack": [0, 0.4],
"Ammo": [0.4, 0.8],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.3, 0.7],
"Headwear": [0, 0.6],
"FaceCover": [0, 0.3],
"Eyewear": [0.2, 0.6],
"BasePlateChance": 70,
"SidePlateChance": 50
},
"followerkolontayassault": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Earpiece": [0, 0.3],
"Backpack": [0, 0.4],
"Ammo": [0.4, 0.8],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.3, 0.7],
"Headwear": [0, 0.6],
"FaceCover": [0, 0.3],
"Eyewear": [0.2, 0.6],
"BasePlateChance": 70,
"SidePlateChance": 50
},
"followerkolontaysecurity": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Earpiece": [0, 0.3],
"Backpack": [0, 0.4],
"Ammo": [0.4, 0.8],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.3, 0.7],
"Headwear": [0, 0.6],
"FaceCover": [0, 0.3],
"Eyewear": [0.2, 0.6],
"BasePlateChance": 70,
"SidePlateChance": 50
},
"followerboarclose1": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Earpiece": [0, 0.3],
"Backpack": [0, 0.4],
"Ammo": [0.4, 0.8],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.3, 0.7],
"Headwear": [0, 0.6],
"FaceCover": [0, 0.3],
"Eyewear": [0.2, 0.6],
"BasePlateChance": 70,
"SidePlateChance": 50
},
"followerboarclose2": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Earpiece": [0, 0.3],
"Backpack": [0, 0.4],
"Ammo": [0.4, 0.8],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.3, 0.7],
"Headwear": [0, 0.6],
"FaceCover": [0, 0.3],
"Eyewear": [0.2, 0.6],
"BasePlateChance": 70,
"SidePlateChance": 50
},
"followerbully": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Earpiece": [0, 0.3],
"Backpack": [0, 0.4],
"Ammo": [0.4, 0.8],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.3, 0.7],
"Headwear": [0, 0.6],
"FaceCover": [0, 0.3],
"Eyewear": [0.2, 0.6],
"BasePlateChance": 70,
"SidePlateChance": 50
},
"followergluharscout": {
"AllowSniperRifles": true,
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Earpiece": [0, 0.3],
"Backpack": [0, 0.4],
"Ammo": [0.4, 0.8],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.3, 0.7],
"Headwear": [0, 0.6],
"FaceCover": [0, 0.3],
"Eyewear": [0.2, 0.6],
"BasePlateChance": 70,
"SidePlateChance": 50
},
"followerbigpipe": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"AllowSniperRifles": false,
"Holster": [0, 0],
"FirstPrimaryWeapon": [0.6, 0.9],
"Backpack": [0, 0],
"Ammo": [0.5, 1],
"ArmorVest": [0, 0],
"TacticalVest": [0, 0],
"Headwear": [0, 0],
"FaceCover": [0, 0],
"Eyewear": [0, 0],
"BasePlateChance": 90,
"SidePlateChance": 60
},
"followerbirdeye": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"AllowSniperRifles": true,
"Holster": [0, 0],
"FirstPrimaryWeapon": [0.6, 0.9],
"Backpack": [0, 0],
"Ammo": [0.5, 1],
"ArmorVest": [0, 0],
"TacticalVest": [0, 0],
"Headwear": [0, 0],
"FaceCover": [0, 0],
"Eyewear": [0, 0],
"BasePlateChance": 90,
"SidePlateChance": 60
},
"followergluharassault": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Earpiece": [0, 0.3],
"Backpack": [0, 0.4],
"Ammo": [0.4, 0.8],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.3, 0.7],
"Headwear": [0, 0.6],
"FaceCover": [0, 0.3],
"Eyewear": [0.2, 0.6],
"BasePlateChance": 70,
"SidePlateChance": 50
},
"followergluharsecurity": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Earpiece": [0, 0.3],
"Backpack": [0, 0.4],
"Ammo": [0.4, 0.8],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.3, 0.7],
"Headwear": [0, 0.6],
"FaceCover": [0, 0.3],
"Eyewear": [0.2, 0.6],
"BasePlateChance": 70,
"SidePlateChance": 50
},
"followerboar": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Earpiece": [0, 0.3],
"Backpack": [0, 0.4],
"Ammo": [0.4, 0.8],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.3, 0.7],
"Headwear": [0, 0.6],
"FaceCover": [0, 0.3],
"Eyewear": [0.2, 0.6],
"BasePlateChance": 70,
"SidePlateChance": 50
},
"followerkojaniy": {
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"Earpiece": [0, 0.3],
"Backpack": [0, 0.4],
"Ammo": [0.4, 0.8],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.3, 0.7],
"Headwear": [0, 0.6],
"FaceCover": [0, 0.3],
"Eyewear": [0.2, 0.6],
"BasePlateChance": 70,
"SidePlateChance": 50
},
"infectedpmc": {
"tiers": [
[1, 24],
[25, 100]
],
"Earpiece": [0, 0.4],
"Headwear": [0.3, 0.9],
"FaceCover": [0, 0.9],
"Eyewear": [0, 0.9],
"BasePlateChance": 60,
"SidePlateChance": 20
},
"infectedassault": {
"tiers": [
[1, 24],
[25, 100]
],
"Earpiece": [0, 0.2],
"Headwear": [0.3, 0.9],
"FaceCover": [0, 0.9],
"Eyewear": [0, 0.9],
"BasePlateChance": 60,
"SidePlateChance": 20
},
"infectedcivil": {
"tiers": [
[1, 24],
[25, 100]
],
"Headwear": [0, 0.3],
"FaceCover": [0, 0.9],
"Eyewear": [0, 0.4],
"BasePlateChance": 60,
"SidePlateChance": 20
},
"infectedlaborant": {
"tiers": [
[1, 24],
[25, 100]
],
"Headwear": [0, 0.3],
"FaceCover": [0, 0],
"Eyewear": [0.3, 0.9],
"BasePlateChance": 60,
"SidePlateChance": 20
},
"assault": {
"tiers": [
[1, 9],
[12, 15],
[16, 29],
[30, 100]
],
"Ammo": [0, 0.4],
"Holster": [0, 0.6],
"FirstPrimaryWeapon": [0, 0.6],
"Backpack": [0, 0.3],
"ArmorVest": [0, 0.4],
"TacticalVest": [0, 0.3],
"Headwear": [0, 0.4],
"FaceCover": [0, 0.5],
"Eyewear": [0, 0.5],
"BasePlateChance": 60,
"SidePlateChance": 10
},
"marksman": {
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"AllowSniperRifles": true,
"HasModdedWeapons": false,
"FirstPrimaryWeapon": [0, 0.8],
"Backpack": [0, 0.3],
"Ammo": [0.3, 0.8],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.3, 0.6],
"Headwear": [0.3, 0.6],
"FaceCover": [0, 0.5],
"BasePlateChance": 60,
"SidePlateChance": 10
},
"pmcbot": {
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"forceOnlyArmoredRigWhenNoArmor": true,
"HasModdedWeapons": true,
"Ammo": [0.4, 0.6],
"ArmorVest": [0.3, 0.6],
"TacticalVest": [0.2, 0.6],
"Headwear": [0.1, 0.5],
"FaceCover": [0.2, 0.6],
"Eyewear": [0, 0.5],
"BasePlateChance": 90
},
"exusec": {
"tiers": [
[1, 14],
[15, 24],
[25, 100]
],
"forceOnlyArmoredRigWhenNoArmor": true,
"Earpiece": [0, 0.4],
"HasModdedWeapons": true,
"Ammo": [0.6, 0.8],
"ArmorVest": [0.4, 0.7],
"TacticalVest": [0.4, 0.7],
"Headwear": [0.5, 0.8],
"FaceCover": [0.2, 0.6],
"Eyewear": [0, 0.5],
"BasePlateChance": 90
}
},
"arenafighterevent": "because no",
"arenafighter": "because no"
}

View file

@ -0,0 +1,28 @@
{
"name": "AlgorithmicLevelProgression",
"version": "5.5.0-RC1",
"main": "src/mod.js",
"license": "MIT",
"author": "DewardianDev",
"sptVersion": "^3.11.x",
"scripts": {
"build": "node ./packageBuild.ts"
},
"devDependencies": {
"@types/node": "20.11",
"@semantic-release/git": "^10.0.1",
"semantic-release": "^24.2.0",
"@typescript-eslint/eslint-plugin": "7.2",
"@typescript-eslint/parser": "7.2",
"archiver": "^6.0",
"bestzip": "2.2.1",
"eslint": "8.57",
"fs-extra": "11.2",
"glob": "8.0.3",
"ignore": "^5.2",
"os": "^0.1",
"tsyringe": "4.8.0",
"typescript": "5.4",
"winston": "3.12"
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,208 @@
export default {
Scabbard: [
"54491bb74bdc2d09088b4567",
"57cd379a24597778e7682ecf",
"57e26ea924597715ca604a09",
"57e26fc7245977162a14b800",
"5bc9c1e2d4351e00367fbcf0",
"5c010e350db83400232feec7",
"5c07df7f0db834001b73588a",
"5fc64ea372b0dd78d51159dc",
"601948682627df266209af05",
"63495c500c297e20065a08b1",
],
Backpack: [
"56e335e4d2720b6c058b456d",
"56e33634d2720bd8058b456b",
"59e763f286f7742ee57895da",
"5e997f0b86f7741ac73993e2",
"5f5e45cc5021ce62144be7aa",
"6034d103ca006d2dca39b3f0",
"61b9e1aaef9a1b5d6a79899a",
"628bc7fb408e2b2e9c0801b1",
"628e1ffc83ec92260c0f437f",
],
Headwear: [
"572b7d8524597762b472f9d1",
"572b7fa124597762b472f9d2",
"59e7708286f7742cbd762753",
"59e770f986f7742cbe3164ef",
"59ef13ca86f77445fd0e2483",
"5a43943586f77416ad2f06e2",
"5a43957686f7742a2c2f11b0",
"5aa2b89be5b5b0001569311f",
"5aa2b8d7e5b5b00014028f4a",
"5aa7e276e5b5b000171d0647",
"5ab8f20c86f7745cdb629fb2",
"5b4329075acfc400153b78ff",
"5bd073c986f7747f627e796c",
"5c08f87c0db8340019124324",
"5c0d2727d174af02a012cf58",
"5c0e874186f7745dc7616606",
"5ca20ee186f774799474abc2",
"5d96141523f0ea1b7f2aacab",
"5df8a58286f77412631087ed",
"5e4bfc1586f774264f7582d3",
"5ea05cf85ad9772e6624305d",
"5ea17ca01412a1425304d1c0",
"5f60b34a41e30a4ab12a6947",
"5f60c74e3b85f6263c145586",
"5f99418230835532b445e954",
"5f994730c91ed922dd355de3",
"603618feffd42c541047f771",
"603619720ca681766b6a0fc4",
"60361a7497633951dc245eb4",
"60361b0b5a45383c122086a1",
"60361b5a9a15b10d96792291",
"6040de02647ad86262233012",
"60a7acf20c5cb24b01346648",
"60bf74184a63fc79b60c57f6",
"618aef6d0a5a59657e5f55ee",
"61bca7cda0eae612383adf57",
"61c18db6dfd64163ea78fbb4",
"628e4dd1f477aa12234918aa",
"636270263f2495c26f00b007",
],
FaceCover: [
"572b7fa524597762b747ce82",
"59e7715586f7742ee5789605",
"5b4326435acfc433000ed01d",
"5b432c305acfc40019478128",
"5bd06f5d86f77427101ad47c",
"5bd0716d86f774171822ef4b",
"5bd071d786f7747e707b93a3",
"5bd073a586f7747e6f135799",
"5c1a1e3f2e221602b66cc4c2",
"5e54f76986f7740366043752",
"5e54f79686f7744022011103",
"5e71f6be86f77429f2683c44",
"5e71fad086f77422443d4604",
"5fd8d28367cb5e077335170f",
"60363c0c92ec1c31037959f5",
"607f201b3c672b3b3a24a800",
"60a7ad2a2198820d95707a2e",
"60a7ad3a0c5cb24b0134664a",
"6176a40f0b8c0312ac75a3d3",
"6176a48d732a664031271438",
"62963c18dbc8ab5f0d382d0b",
"62a09dd4621468534a797ac7",
"62a09e08de7ac81993580532",
"62a5c2c98ec41a51b34739c0",
"62a5c333ec21e50cad3b5dc6",
"62a5c41e8ec41a51b34739c3",
"62a61bbf8ec41a51b34758d2",
"635267ab3c89e2112001f826",
"63626d904aa74b8fe30ab426",
],
Eyewear: [
"59e770b986f7742cbd762754",
"5aa2b923e5b5b000137b7589",
"5aa2b9aee5b5b00015693121",
"5e71f70186f77429ee09f183",
"61c18d83b00456371a66814b",
"62a09e410b9d3c46de5b6e78",
],
Holster: ["5b3b713c5acfc4330140bd8d"],
ArmorVest: [
"5b44cf1486f77431723e3d05",
"5c0e541586f7747fa54205c9",
"5c0e625a86f7742d77340f62",
"5c0e655586f774045612eeb2",
"5fd4c474dd870108a754b241",
"6038b4b292ec1c3103795a0b",
"6038b4ca92ec1c3103795a0d",
"607f20859ee58b18e41ecd90",
"62a09d79de7ac81993580530",
],
FirstPrimaryWeapon: [
"6275303a9f372d6ea97f9ec7",
"5bf3e0490db83400196199af",
"5de7bd7bfd6b4e6e2276dc25",
"639af924d0446708ee62294e",
"639c3fbbd0446708ee622ee9",
"64637076203536ad5600c990",
"64ca3d3954fc657e230529cc",
],
ammo: [
"5c0d56a986f774449d5de529",
"5c0d591486f7744c505b416f",
"5c0d5ae286f7741e46554302",
"5d70e500a4b9364de70d38ce",
"5ede4739e0350d05467f73e8",
"5ede47405b097655935d7d16",
"5ede474b0c226a66f5402622",
"5ede475339ee016e8c534742",
"5f0c892565703e5c461894e9",
"64b8ee384b75259c590fa89b",
"5d6e68a8a4b9360b6c0d54e2",
"5efb0cabfb3e451d70735af5",
"5a26ac0ec4a28200741e1e18",
"5cc80f38e4a949001152b560",
"61962d879bb3d20b0946d385",
"5c0d688c86f77413ae3407b2",
"56dff026d2720bb8668b4567",
"5c0d5e4486f77478390952fe",
"59e690b686f7746c9f75e848",
"5fd20ff893a8961fc660a954",
"5a6086ea4f39f99cd479502f",
"560d61e84bdc2da74d8b4571",
"5cadf6eeae921500134b2799",
"5fc382a9d724d907e2077dab",
],
TacticalVest: [
"5c0e9f2c86f77432297fe0a3",
"5f5f41f56760b4138443b352",
"5fd4c4fa16cac650092f6771",
"5fd4c5477a8d854fa0105061",
"6040dd4ddcf9592f401632d2",
"609e860ebd219504d8507525",
"628b9784bcf6e2659e09b8a2",
"628b9c7d45122232a872358f",
"628baf0b967de16aab5a4f36",
"63611865ba5b90db0c0399d1",
"64a536392d2c4e6e970f4121",
"64a5366719bab53bd203bf33",
],
Earpiece: [
"5e4d34ca86f774264f758330",
"5f60cd6cf2bcbb675b00dac6",
"628e4e576d783146b124c64d",
],
ArmBand: [
"5f9949d869e2777a0e779ba5",
"60b0f988c4449e4cb624c1da",
"619bc61e86e01e16f839a999",
"619bdd8886e01e16f839a99c",
"619bddc6c9546643a67df6ee",
"619bddffc9546643a67df6f0",
"619bde3dc9546643a67df6f2",
"619bde7fc9546643a67df6f4",
"619bdeb986e01e16f839a99e",
"619bdef8c9546643a67df6f6",
"619bdf9cc9546643a67df6f8",
"619bdfd4c9546643a67df6fa",
],
StimsMeds: [
"5751a89d24597722aa0e8db0",
"5755383e24597772cb798966",
"5ed515c8d380ab312177c0fa",
"5ed515e03a40a50460332579",
"5ed515ece452db0eb56fc028",
"5ed515f6915ec335206e4152",
"5ed5160a87bb8443d10680b5",
"5ed51652f6c34d2cc26336a1",
"5ed5166ad380ab312177c100",
"5fca138c2a7b221b2852a5c6",
"5fca13ca637ee0341a484f46",
"637b60c3b7afa97bfc3d7001",
"637b612fb7afa97bfc3d7005",
"637b6179104668754b72f8f5",
"637b620db7afa97bfc3d7009",
"637b6251104668754b72f8f9",
],
Grenades: [
"5e340dcdcb6d5863cc5e5efb",
"617fd91e5539a84ec44ce155",
"618a431df1eb8e24b8741deb",
],
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,78 @@
import { IBotBase } from "../../types/models/eft/common/tables/IBotBase";
import { IBotGenerationDetails } from "../../types/models/spt/bots/BotGenerationDetails";
import { IRandomisedBotLevelResult } from "../../types/models/eft/bot/IRandomisedBotLevelResult";
import { MinMax } from "../../types/models/common/MinMax";
import { DependencyContainer } from "tsyringe";
import { botRangeAtLevel, levelRange } from "../../config/config.json";
import { getCurrentLevelRange } from "../LoadoutChanges/utils";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { BotLevelGenerator } from "@spt/generators/BotLevelGenerator";
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
import config from "../../config/config.json";
import { IPmcConfig } from "@spt/models/spt/config/IPmcConfig";
export default function BotLevelChanges(
container: DependencyContainer
): undefined {
const profileHelper = container.resolve<ProfileHelper>("ProfileHelper");
const botLevelGenerator =
container.resolve<BotLevelGenerator>("BotLevelGenerator");
const configServer = container.resolve<ConfigServer>("ConfigServer");
const pmcConfig = configServer.getConfig<IPmcConfig>(ConfigTypes.PMC);
pmcConfig.botRelativeLevelDeltaMax = 1;
container.afterResolution(
"BotLevelGenerator",
(_t, result: BotLevelGenerator) => {
result.generateBotLevel = (
levelDetails: MinMax,
botGenerationDetails: IBotGenerationDetails,
bot: IBotBase
): IRandomisedBotLevelResult => {
if (!botGenerationDetails.isPmc)
return botLevelGenerator.generateBotLevel(
levelDetails,
botGenerationDetails,
bot
);
const { playerLevel } = botGenerationDetails;
const currentLevelRange = getCurrentLevelRange(playerLevel);
const currentRangeArray = botRangeAtLevel[currentLevelRange];
const test = currentRangeArray.map((val, k) => ({
levelRange: k + 1,
val: Math.random() * val,
}));
const randomizedRange = test.sort((a, b) => b.val - a.val)[0]
.levelRange;
const range = { ...levelRange[randomizedRange] } as MinMax;
if (range.max > 79) {
range.max = 79;
}
if (range.min > 70) {
range.min = 50;
}
const level =
Math.round((range.max - range.min) * Math.random()) + range.min;
const final = {
level,
exp: profileHelper.getExperience(level),
};
// debug && console.log(final)
return final;
};
},
{ frequency: "Always" }
);
config.debug &&
console.log("Algorthimic Progression: BotLevelGenerator registered");
}

View file

@ -0,0 +1,37 @@
import { DependencyContainer } from "tsyringe";
import { buildClothingWeighting, cloneDeep } from "./utils";
import { DatabaseServer } from "@spt/servers/DatabaseServer";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { globalValues } from "./GlobalValues";
export default function ClothingChanges(
container: DependencyContainer
): undefined {
const databaseServer = container.resolve<DatabaseServer>("DatabaseServer");
const tables = databaseServer.getTables();
const configServer = container.resolve<ConfigServer>("ConfigServer");
const botConfig = configServer.getConfig<IBotConfig>(ConfigTypes.BOT);
const usecAppearance = tables.bots.types.usec.appearance;
const bearAppearance = tables.bots.types.bear.appearance;
const traders = tables.traders;
const customization = tables.templates.customization;
let allTradersSuits = Object.values(traders)
.filter(({ suits }) => !!suits?.length)
.map(({ suits }) => suits)
.flat(1);
buildClothingWeighting(
allTradersSuits,
customization,
botConfig,
usecAppearance,
bearAppearance
);
globalValues.originalBotTypes = cloneDeep(tables.bots.types);
globalValues.originalWeighting = cloneDeep(botConfig.equipment.pmc);
}

View file

@ -0,0 +1,24 @@
import { IInventory } from "@spt/models/eft/common/tables/IBotType";
export const fixSpecificItemIssues = (inventory: IInventory) => {
const removeAccentScopeList = new Set([
"6171407e50224f204c1da3c5", // Recknagel Era-Tac 30mm ring scope mount
"61713cc4d8e3106d9806c109", // Recknagel Era-Tac 34mm ring scope mount
"5b2389515acfc4771e1be0c0", // Burris AR-P.E.P.R. 30mm ring scope mount
"5addc00b5acfc4001669f144", // M14 Vltor CASV-14 rail system
"5a37ca54c4a282000d72296a", // JP Enterprises Flat-Top 30mm ring scope mount
"5aa66c72e5b5b00016327c93", // Nightforce Magmount 34mm ring scope mount with Ruggedized Accessory Platform
]);
removeAccentScopeList.forEach((id) => {
if (inventory.mods?.[id]?.mod_scope_001) {
inventory.mods[id].mod_scope_001 = [];
}
if (inventory.mods?.[id]?.mod_scope_002) {
inventory.mods[id].mod_scope_002 = [];
}
if (inventory.mods?.[id]?.mod_scope_003) {
inventory.mods[id].mod_scope_003 = [];
}
});
};

View file

@ -0,0 +1,241 @@
import { cloneDeep, mergeDeep, saveToFile } from "./utils";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { IDatabaseTables } from "@spt/models/spt/server/IDatabaseTables";
import config from "../../config/config.json";
import advancedConfig from "../../config/advancedConfig.json";
import {
EquipmentFilters,
IBotConfig,
} from "@spt/models/spt/config/IBotConfig";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { IBotType } from "@spt/models/eft/common/tables/IBotType";
import {
cullModItems,
makeMapSpecificWeaponWeightings,
makeRandomisationAdjustments,
updateScopes,
} from "./OnGameStartUtils";
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
import {
StoredWeightingAdjustmentDetails,
buffScavGearAsLevel,
setPlateWeightings,
} from "../NonPmcBotChanges/NonPmcUtils";
export class globalValues {
public static Logger: ILogger;
public static profileHelper: ProfileHelper;
public static storedEquipmentValues: Record<
string,
StoredWeightingAdjustmentDetails[]
> = {};
public static tables: IDatabaseTables;
public static originalBotTypes: Record<string, IBotType>;
public static config = config;
public static advancedConfig = advancedConfig;
public static originalWeighting: EquipmentFilters;
public static configServer: ConfigServer;
public static updateInventory(
currentLevel: number,
location: keyof typeof advancedConfig.locations
) {
const items = this.tables.templates.items;
const nameList = Object.keys(this.storedEquipmentValues);
if (!nameList.length || !currentLevel) return;
const botConfig = this.configServer.getConfig<IBotConfig>(ConfigTypes.BOT);
const firstPrimaryWeaponMultiplier =
advancedConfig.locations[location].weightingAdjustments
.FirstPrimaryWeapon;
nameList.forEach((botName) => {
const copiedInventory = cloneDeep(
this.originalBotTypes[botName].inventory
);
const currentLevelIndex = this.storedEquipmentValues[botName].findIndex(
({ levelRange: { min, max } }) =>
currentLevel <= max && currentLevel >= min
);
const weightingToUpdate =
this.storedEquipmentValues[botName][currentLevelIndex];
if (!weightingToUpdate) return;
if (weightingToUpdate?.ammo) {
for (const caliber in weightingToUpdate.ammo) {
copiedInventory.Ammo[caliber] = {
...copiedInventory.Ammo[caliber],
...weightingToUpdate.ammo[caliber],
};
}
}
if (weightingToUpdate?.equipment) {
for (const equipmentType in weightingToUpdate.equipment) {
copiedInventory.equipment[equipmentType] = {
...copiedInventory.equipment[equipmentType],
...weightingToUpdate.equipment[equipmentType],
};
try {
//update weapon type weightings per map here
if (
equipmentType === "FirstPrimaryWeapon" &&
botName !== "marksman"
) {
// console.log("Updating", botName, " weapons for map", location);
const firstPrimary: Record<string, number> = cloneDeep(
copiedInventory.equipment[equipmentType]
);
const firstPrimaryKeys = Object.keys(firstPrimary);
firstPrimaryKeys?.forEach((weaponId) => {
const parentId = items[weaponId]?._parent;
const parent = items?.[parentId]?._name;
if (parent && firstPrimaryWeaponMultiplier[parent]) {
const multiplier =
(firstPrimaryWeaponMultiplier[parent] - 1) / 2 + 1;
copiedInventory.equipment[equipmentType][weaponId] =
Math.round(multiplier * firstPrimary[weaponId]);
// if (botName === "assault") {
// console.log(
// multiplier,
// location,
// botName,
// firstPrimary[weaponId],
// " to ",
// copiedInventory.equipment[equipmentType][weaponId],
// parent,
// items[weaponId]._name
// );
// }
} else {
console.log(
`[AlgorithmicLevelProgression]: Unable to set map settings for bot ${botName}'s item ${items[weaponId]._name} - ${weaponId} `
);
}
});
}
} catch (error) {
`[AlgorithmicLevelProgression]: Failed to update bot ${botName}'s ${equipmentType}`;
}
}
if (botName === "assault") {
//adjust randomization
buffScavGearAsLevel(botConfig.equipment[botName], currentLevelIndex);
}
setPlateWeightings(
botName,
botConfig.equipment[botName],
currentLevelIndex
);
// if (botName === "assault") {
// saveToFile(this.tables.bots.types[botName], `refDBS/assault.json`);
// }
}
this.tables.bots.types[botName].inventory = copiedInventory;
});
}
public static setValuesForLocation(
location: keyof typeof advancedConfig.locations,
hours: number
) {
if (location === "factory4_day") hours = 12;
if (location === "factory4_night") hours = 1;
if (location === "laboratory") hours = 12;
this.config.debug &&
this.Logger.info(
`Algorthimic LevelProgression: Setting up values for map ${location}`
);
const botConfig = this.configServer.getConfig<IBotConfig>(ConfigTypes.BOT);
const mapWeightings =
advancedConfig.locations?.[location]?.weightingAdjustments;
const items = this.tables.templates.items;
if (!mapWeightings) {
return this.Logger.warning(
`Algorthimic LevelProgression: did not recognize 'location': ${location}, using defaults`
);
}
if (!this.originalWeighting) {
return this.Logger.error(
`Algorthimic LevelProgression: 'originalWeighting' was not set correctly`
);
}
if (!items) {
return this.Logger.error(
`Algorthimic LevelProgression: 'items' was not set correctly`
);
}
const finalEquipment: EquipmentFilters = cloneDeep(this.originalWeighting);
const isNight = hours < 7 || hours >= 19;
config.debug &&
console.log(
"The server thinks it is ",
isNight ? "NIGHT" : "DAY",
hours,
" do appropriate things."
);
const randomisation = finalEquipment.randomisation;
makeRandomisationAdjustments(
isNight,
this.originalWeighting,
randomisation,
location
);
const originalBotTypesCopy: Record<string, IBotType> = cloneDeep(
this.originalBotTypes
);
cullModItems(
originalBotTypesCopy.usec.inventory.mods,
isNight,
items,
location
);
updateScopes(
originalBotTypesCopy.usec.inventory.mods,
isNight,
items,
location
);
originalBotTypesCopy.bear.inventory.mods =
originalBotTypesCopy.usec.inventory.mods;
const pmcWeighting = finalEquipment.weightingAdjustmentsByBotLevel;
makeMapSpecificWeaponWeightings(
location,
items,
this.originalWeighting,
pmcWeighting
);
// saveToFile(originalBotTypesCopy.usec.inventory.mods, "updated.json")
// saveToFile(originalBotTypesCopy.usec.inventory, "refDBS/usecInventoryRef.json")
// saveToFile(finalEquipment, "finalEquipment.json");
// saveToFile(this.originalWeighting, "originalWeighting.json")
botConfig.equipment.pmc = finalEquipment;
this.tables.bots.types = originalBotTypesCopy;
}
}

View file

@ -0,0 +1,271 @@
export default [
"544a3f024bdc2d1d388b4568", //ELCAN Specter OS4x assault scope
///
"5af99e9186f7747c447120b8", // Bad pockets
"60c7272c204bc17802313365",
"627a4e6b255f7527fb05a0f6",
"64cbd95a29b9b4283e216ff5",
///
"622b4f54dc8dcc0ba8742f85", //HK G36 Hensoldt HKV ZF 1.5x carry handle
"622b4d7df9cfc87d675d2ded", //HK G36 Hensoldt HKV 3x carry handle
// armasight vulcan universal base
// Geissele Super Precision 30mm
"5aa66a9be5b5b0214e506e89", // Nightforce Magmount 34mm ring scope mount > stupid long scope mount
"5a1ead28fcdbcb001912fa9f", // Reap-ir Mount
"5c86592b2e2216000e69e77c", // IEA Mil-Optics KH/F 34mm one-piece magmount <Stupid Long distance scopes>
"5c11046cd174af02a012e42b", // Wilcox Interface for PVS-7 > Thermal night vision connector
"5ea058e01dbce517f324b3e2", // Tac-Kek Heavy Trooper mask for Ops-Core-type helmets
"5c0558060db834001b735271", // GPNVG-18 Night Vision goggles
"5648b62b4bdc2d9d488b4585", // gp-34
"5e99711486f7744bfc4af328", // Sanitarsmedkit
"5d52cc5ba4b9367408500062",
"6087e570b998180e9f76dc24",
"58ac60eb86f77401897560ff", // golden balaclava!
"6241c316234b593b5676b637", // bb ammo
"5cdeb229d7f00c000e7ce174", // stationary gun
"5943d9c186f7745a13413ac9", // shrapnel bullets?
"5996f6cb86f774678763a6ca", // shrapnel bullets?
"5996f6fc86f7745e585b4de3", // shrapnel bullets?
"63b35f281745dd52341e5da7", // shrapnel bullets?
"5d2f2ab648f03550091993ca", // shrapnel bullets?
"5cde8864d7f00c0010373be1",
"64b9cf0ac12b9c38db26923a", // << no idea
"627a137bf21bc425b06ab944",
"610720f290b75a49ff2e5e25",
"5996f6d686f77467977ba6cc", // shrapnel bullets?
"5ae083b25acfc4001a5fc702", // Master hand ?
"544a3d0a4bdc2d1b388b4567",
"5a16bb52fcdbcb001a3b00dc", // skull lock
"5a1eaa87fcdbcb001865f75e", // reap-ir
"5d1b5e94d7ad1a2b865a96b0", // flir
"5c066ef40db834001966a595", // helmet_armasight_nvg_googles_mask
"5a0c59791526d8dba737bba7", // butt pad
"57371aab2459775a77142f22",
//small mags
"57838f0b2459774a256959b2",
"5aaa5e60e5b5b000140293d6",
"5b1fd4e35acfc40018633c39",
"59e5d83b86f7745aed03d262",
"5b7bef1e5acfc43d82528402",
"617130016c780c1e710c9a24",
"55d4837c4bdc2d1d4e8b456c",
"5c503ac82e221602b21d6e9a",
"6241c2c2117ad530666a5108",
//large mags
// "55d485804bdc2d8c2f8b456b", shotgun 153/155 extended /7/8
// "56deeefcd2720bc8328b4568", shotgun 153/155 extended /7/8
// "5882163224597757561aa920", shotgun 153/155 extended /7/8
"5a78832ec5856700155a6ca3",
"5a966f51a2750c00156aacf6",
"5cf8f3b0d7f00c00217872ef",
"625ff2eb9f5537057932257d",
"625ff3046d721f05d93bf2ee",
"625ff31daaaa8c1130599f64",
"627bce33f21bc425b06ab967",
"564ca9df4bdc2d35148b4569",
// '55d481904bdc2d8c2f8b456a', //45 round ak
"55d482194bdc2d1d4e8b456b",
"5bed625c0db834001c062946",
"55d485be4bdc2d962f8b456f",
"5cbdc23eae9215001136a407",
"5c6175362e221600133e3b94",
"5cfe8010d7ad1a59283b14c6",
"61695095d92c473c7702147a",
"61695095d92c473c7702147a",
"59c1383d86f774290a37e0ca",
"5c6592372e221600133e47d7",
"544a37c44bdc2d25388b4567",
"5a718f958dc32e00094b97e7",
"5c5db6742e2216000f1b2852",
"5a351711c4a282000b1521a4",
"5addccf45acfc400185c2989",
"5b7bef9c5acfc43d102852ec",
// "5b1fb3e15acfc4001637f068", 40 round ak
// "59e5f5a486f7746c530b3ce2", 40 round
// "544a378f4bdc2d30388b4567", 40 round
// "5d1340bdd7ad1a0e8d245aab", 40-round 556 45
// "630e295c984633f1fb0e7c30",
// "5ba26586d4351e44f824b340", MP7 40
"5c5db6652e221600113fba51",
"5cffa483d7ad1a049e54ef1c",
"5d52d479a4b936793d58c76b",
// stm-9
// stocks
"5c0faeddd174af02a962601f",
"5d120a10d7ad1a4e1026ba85",
"5b0800175acfc400153aebd4",
"5947e98b86f774778f1448bc",
"5947eab886f77475961d96c5",
// "602e3f1254072b51b239f713",
"5c793fb92e221644f31bfb64",
"5c793fc42e221600114ca25d",
"591aef7986f774139d495f03",
"591af10186f774139d495f0e",
"627254cc9c563e6e442c398f",
"638de3603a1a4031d8260b8c",
"5a33ca0fc4a282000d72292f",
// Saiga-9 9x19 carbine
// stocks
"5cf50fc5d7f00c056c53f83c", //AK-74M CAA AKTS AK74 buffer tube > 25
"5ac78eaf5acfc4001926317a", //AK-74M/AK-100 Zenit PT Lock >2
//Full Size AK mods
// stocks
// "628a6678ccaab13006640e49", //AKM/AK-74 RD AK to M4 buffer tube adapter > 17
"5b222d335acfc4771e1be099", //AKM/AK-74 Zenit PT Lock > 1
"59ecc28286f7746d7a68aa8c", // AK-74U Zenit PT Lock > 1
"5839a40f24597726f856b511", // bufferTubes > 21
"5cf518cfd7f00c065b422214",
"5649b2314bdc2d79388b4576",
"5b04473a5acfc40018632f70", //beefy Stock
"5e217ba4c1434648c13568cd", //Red funky stock
"5b0e794b5acfc47a877359b2", // Zhokov black
"6087e2a5232e5a31c233d552", //Archangel
//DustCovers
"59d6507c86f7741b846413a2", // AKM dust cover (6P1 0-1) allowing one
"59e6449086f7746c9f75e822",
"628a665a86cbd9750d2ff5e5",
"5649af094bdc2df8348b4586",
"5ac50da15acfc4001718d287",
//bullets that think they are guns
"624c0b3340357b5f566e8766",
"624c0b3340357b5f566e8766",
"6217726288ed9f0845317459",
"62178be9d0050232da3485d9",
//Mosin shorty,
"5bfd36ad0db834001c38ef66",
"5bfd36290db834001966869a",
"5a16b9fffcdbcb0176308b34",
"5c07c9660db834001a66b588",
"5d2f25bc48f03502573e5d85",
"5a7c74b3e899ef0014332c29",
//Waffle 545
"615d8f8567085e45ef1409ca",
//Mosin stocks
"5bbdb870d4351e00367fb67d",
"5bae13bad4351e00320204af",
//IR lasers
"57fd23e32459772d0805bcf1",
"544909bb4bdc2d6f028b4577",
"5d10b49bd7ad1a1a560708b0",
"5c06595c0db834001a66af6c",
"5c5952732e2216398b5abda2",
"5a5f1ce64f39f90b401987bc",
"61605d88ffa6e502ac5e7eeb",
//pistolGrips
"5b07db875acfc40dc528a5f6",
"615d8faecabb9b7ad90f4d5d",
"59db3acc86f7742a2c4ab912",
"59db3b0886f77429d72fb895",
"59db3a1d86f77429e05b4e92",
"5d025cc1d7ad1a53845279ef",
"5f6341043ada5942720e2dc5",
"6087e663132d4d12c81fd96b",
"5e2192a498a36665e8337386",
"5cf54404d7f00c108840b2ef",
"5b30ac585acfc433000eb79c",
"628a664bccaab13006640e47",
"628c9ab845c59e5b80768a81",
"5c6bf4aa2e2216001219b0ae",
"5649ae4a4bdc2d1b2b8b4588",
"6113c3586c780c1e710c90bc",
"6113cce3d92c473c770200c7",
"6113cc78d3a39d50044c065a",
"5b7d679f5acfc4001a5c4024",
//Handguards
"595cfa8b86f77427437e845b",
"595cf16b86f77427440c32e2",
"55f84c3c4bdc2d5f408b4576",
"619b5db699fb192e7430664f",
"5b2cfa535acfc432ff4db7a0",
"5c9a25172e2216000f20314e",
"55f84c3c4bdc2d5f408b4576",
"588b56d02459771481110ae2",
"5c9a26332e2216001219ea70",
"5ea16ada09aa976f2e7a51be",
"5ea16acdfadf1d18c87b0784",
"5d4405f0a4b9361e6a4e6bd9",
"5c78f2492e221600114c9f04",
"5c78f2612e221600114c9f0d",
"6034e3e20ddce744014cb878",
"6034e3d953a60014f970617b",
"6034e3cb0ddce744014cb870",
"5c6d5d8b2e221644fc630b39",
"5d00e0cbd7ad1a6c6566a42d",
"5d00f63bd7ad1a59283b1c1e",
"6087e0336d0bd7580617bb7a",
"63888bbd28e5cc32cc09d2b6",
//Foregrips
"5fc0f9b5d724d907e2077d82",
"5cda9bcfd7f00c0c0b53e900",
"59f8a37386f7747af3328f06",
"5a7dbfc1159bd40016548fde",
"619386379fb0c665d5490dbe",
"5de8fbad2fbe23140d3ee9c4",
"5b057b4f5acfc4771e1bd3e9",
"5c791e872e2216001219c40a",
"5f6340d3ca442212f4047eb2",
"591af28e86f77414a27a9e1d",
"5c1bc5612e221602b5429350",
"5c1cd46f2e22164bef5cfedb",
"5c1bc5af2e221602b412949b",
"648c1a965043c4052a4f8505", // Ebudal (bad stim)
"5d02778e86f774203e7dedbe", // CMS surgical kit
"5d02797c86f774203f38e30a", // Surv kit
"590c657e86f77412b013051d", //grizzly
"5d1c702ad7ad1a632267f429", //long handgun stock
"620109578d82e67e7911abf2", // signal pistol
"62178c4d4ecf221597654e3d",
"624c0570c9b794431568f5d5",
"624c09da2cec124eb67c1046",
"624c09e49b98e019a3315b66",
"624c09cfbc2e27219346d955",
"62389aaba63f32501b1b444f", // signal ammo
"62389ba9a63f32501b1b4451",
"62389bc9423ed1685422dc57",
"62389be94d5d474bf712e709",
"635267f063651329f75a4ee8",
"633a98eab8b0506e48497c1a", // sr-2m 20 round mag
"5caf1041ae92157c28402e3f", // ash12 10 round
"5d0a29fed7ad1a002769ad08",
"62811f461d5df4475f46a332",
"6275303a9f372d6ea97f9ec7", //revolver grenadeLauncher
"6422e1ea3c0f06190302161a", //SVT-40 7.62x54R 10-round magazine
"5c471c442e221602b542a6f8", //SVD 7.62x54R 10-round magazine
"57d14e1724597714010c3f4b", //PP-91 "Kedr" 9x18PM 20-round magazine
"5d2f213448f0355009199284", //HK MP5 9x19 20-round magazine
"5a43957686f7742a2c2f11b0", //Santahat
"639af924d0446708ee62294e", // FN40GL Mk2
"639c3fbbd0446708ee622ee9", // FN40GL Mk25e81ebcd8e146c7080625e15
"5e81ebcd8e146c7080625e15", // FN40GL Mk2 40mm grenade launcher
"59f32c3b86f77472a31742f0", // dogtags
"59f32bb586f774757e1e8442", // dogtags
"6662e9f37fa79a6d83730fa0", // dogtags
"6662ea05f6259762c56f3189", // dogtags
"6662e9aca7e0b43baa3d5f74", // dogtags
"6662e9cda7e0b43baa3d5f76", // dogtags
"5b9b9020e7ef6f5716480215", // dogtags
"65392f611406374f82152ba5", // mount_all_gbrs_hydra_micro_kit
"653931da5db71d30ab1d6296", // GBRS Aimpoint Hydra Mount Kit (FDE)
"618b9682a3884f56c957ca78", //Reptilia ROF-90 RMR mount for Geissele scope mounts
"618ba92152ecee1505530bd3", //Reptilia ROF-90 RMR mount for Geissele scope mounts ddc
"6601546f86889319850bd566",
"66015072e9f84d5680039678",
"66015dc4aaad2f54cb04c56a",
"5d70e500a4b9364de70d38ce",
"670e8eab8c1bb0e5a7075acf", //mag_pm_izhmeh_9x18pm_999_infectedMagazin
"671d85439ae8365d69117ba6", //mag_tt_toz_std_762x25tt_999_infectedMagazin
"671d8617a3e45c1f5908278c", //mag_mp443_izhmeh_std_9x19_999_infectedMagazin
"671d8ac8a3e45c1f59082799", //mag_glock_glock_w_pad_9x19_999_fde_Infected
"671d8b38b769f0d88c0950f8", //mag_m1911_colt_m45a1_std_1143x23_999_infected
"671d8b8c0959c721a50ca838", //mag_usp_hk_usp_tactical_1143x23_999_infected
"628120f210e26c1f344e6558", // mxc broken mod
"66d98233302686954b0c6f81", // RSP-30 reactive signal cartridge (Blue)
];
//5d0a29fed7ad1a002769ad08
//62811f461d5df4475f46a332
//56ea70acd2720b844b8b4594 optic
// 6275303a9f372d6ea97f9ec7

View file

@ -0,0 +1,69 @@
import { StaticRouterModService } from "@spt/services/mod/staticRouter/StaticRouterModService";
import { DependencyContainer } from "tsyringe";
import { globalValues } from "./GlobalValues";
import { WeatherController } from "@spt/controllers/WeatherController";
import { saveToFile } from "./utils";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
import { enableNonPMCBotChanges } from "../../config/config.json";
export const LocationUpdater = (container: DependencyContainer): undefined => {
const staticRouterModService = container.resolve<StaticRouterModService>(
"StaticRouterModService"
);
const weatherController =
container.resolve<WeatherController>("WeatherController");
staticRouterModService.registerStaticRouter(
`AlgorithmicLevelProgressionMapUpdater`,
[
{
url: "/client/match/local/start",
action: async (_url, info, sessionId, output) => {
const time = weatherController.generate().time;
const hours = getTime(time, info.timeVariant === "PAST" ? 12 : 0);
// console.log("hours", hours);
try {
globalValues.setValuesForLocation(
info.location.toLowerCase(),
hours
);
if (enableNonPMCBotChanges) {
const pmcData =
globalValues.profileHelper.getPmcProfile(sessionId);
globalValues.updateInventory(
pmcData?.Info?.Level || 1,
info.location.toLowerCase()
);
}
console.log("Algorthimic LevelProgression: Loaded");
} catch (error) {
console.log(
`"Algorthimic LevelProgression: failed to make equipment changes.
` + error?.message
);
}
return output;
},
},
],
"aki"
);
globalValues.config.debug &&
console.log(
"Algorthimic LevelProgression: Custom router AlgorithmicLevelProgressionMapUpdater Registered"
);
};
function getTime(time: string, hourDiff: number): number {
let [hours, minutes] = time.split(":");
if (hourDiff == 12 && parseInt(hours) >= 12) {
return Math.abs(parseInt(hours) - hourDiff);
}
return Math.abs(parseInt(hours) + hourDiff);
}

View file

@ -0,0 +1,181 @@
import { IBotType } from "@spt/models/eft/common/tables/IBotType";
import { IHandbookBase } from "@spt/models/eft/common/tables/IHandbookBase";
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
import {
blacklistedItems,
checkParentRecursive,
keyMechanical,
saveToFile,
} from "./utils";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import { IPmcConfig } from "@spt/models/spt/config/IPmcConfig";
import nonPmcBotConfig from "../../config/nonPmcBotConfig.json";
import { BaseClasses } from "@spt/models/enums/BaseClasses";
export const buildLootChanges = (
items: Record<string, ITemplateItem>,
handbook: IHandbookBase,
prices: Record<string, number>,
_: IPmcConfig,
botConfig: IBotConfig,
types: Record<string, IBotType>
) => {
const assaultInventory = types.assault.inventory;
const handbookMapper = {} as Record<string, number>;
// Zero out all current items
for (const key in assaultInventory.items.Backpack) {
assaultInventory.items.Backpack[key] = 1;
}
for (const key in assaultInventory.items.Pockets) {
assaultInventory.items.Pockets[key] = 1;
}
for (const key in assaultInventory.items.TacticalVest) {
assaultInventory.items.TacticalVest[key] = 1;
}
handbook.Items.forEach(({ Id, Price }) => {
handbookMapper[Id] = Price;
});
const getFleaPrice = (itemID: string): number => {
if (typeof prices[itemID] != "undefined") {
return prices[itemID];
} else {
return handbookMapper[itemID];
}
};
const newToAdd = {
[BaseClasses.BARTER_ITEM]: 50,
[BaseClasses.HOUSEHOLD_GOODS]: 50,
[BaseClasses.FOOD_DRINK]: 50,
[BaseClasses.ELECTRONICS]: 1,
[BaseClasses.JEWELRY]: 2,
[BaseClasses.OTHER]: 1,
[BaseClasses.TOOL]: 5,
[BaseClasses.REPAIR_KITS]: 1,
[BaseClasses.MONEY]: 1,
"60b0f6c058e0b0481a09ad11": 1, //gingy
"62a09d3bcf4a99369e262447": 1, //wallet
"5783c43d2459774bbe137486": 1, //walletz
};
if (nonPmcBotConfig.addRandomizedKeysToScavs) {
newToAdd[BaseClasses.KEY_MECHANICAL] = 1;
}
const itemsToRemove = new Set([
BaseClasses.AMMO_BOX,
BaseClasses.GEAR_MOD,
BaseClasses.SILENCER,
BaseClasses.KNIFE,
BaseClasses.ASSAULT_SCOPE,
BaseClasses.COLLIMATOR,
BaseClasses.SPECIAL_SCOPE,
BaseClasses.OPTIC_SCOPE,
BaseClasses.FOREGRIP,
BaseClasses.ARMOR,
BaseClasses.VEST,
BaseClasses.TACTICAL_COMBO,
]);
const addList = Object.keys(newToAdd);
const removeList = [...itemsToRemove];
//limit keys on scavs
botConfig.itemSpawnLimits.assault[BaseClasses.KEY_MECHANICAL] = 1;
const randomlyAllowKey = (id) => {
if (
checkParentRecursive(id, items, [BaseClasses.KEY_MECHANICAL]) &&
Math.random() > nonPmcBotConfig.percentageOfKeysInSpawnPool
) {
// console.log(items[id]._name);
return false;
}
return true;
};
const scavLootBlacklist = new Set(nonPmcBotConfig.scavLootBlacklist);
const loot = Object.keys(items).filter(
(id) =>
!scavLootBlacklist.has(id) &&
!blacklistedItems.has(id) &&
randomlyAllowKey(id) &&
checkParentRecursive(id, items, addList) &&
!checkParentRecursive(id, items, [BaseClasses.MONEY, ...removeList]) &&
!items[id]?._props?.QuestItem &&
!!getFleaPrice(id)
);
const importedCustomLoot = nonPmcBotConfig?.additionalScavLoot.filter(
(id) => !!items[id] && !!getFleaPrice(id)
);
const configmultiplier = 100 / nonPmcBotConfig.lootDisparityMultiplier;
const allLoot = [...loot, ...importedCustomLoot]
.map((id) => ({
id,
value: Math.round(getFleaPrice(id) / configmultiplier) || 1,
name: items[id]._name,
}))
.sort(({ value: b }, { value: a }) => b - a);
const reverseLoot = [...allLoot].reverse().map(({ value }) => value);
const top = reverseLoot[Math.round(reverseLoot.length * 0.15)];
const bottom = reverseLoot[Math.round(allLoot.length * 0.7)];
const finalValues: Record<string, number> = {};
allLoot.forEach(({ value, id, name }, index) => {
let rarity = reverseLoot[index];
switch (true) {
case reverseLoot[index] > top:
rarity = top;
break;
case reverseLoot[index] < bottom:
rarity = Math.round(
rarity * (0.3 / nonPmcBotConfig.lootDisparityMultiplier)
);
break;
default:
}
if (checkParentRecursive(id, items, [keyMechanical])) {
rarity = Math.round(rarity * (Math.random() * Math.random())) || 1;
}
finalValues[id] = rarity;
});
// saveToFile(finalValues, "refDBS/allLoot.json");
assaultInventory.items.Backpack = finalValues;
assaultInventory.items.Pockets = finalValues;
assaultInventory.items.TacticalVest = finalValues;
// botConfig.walletLoot.chancePercent = 35;
// botConfig.walletLoot.walletTplPool = [];
itemsToRemove.forEach((id) => {
if (botConfig.itemSpawnLimits.assault[id])
delete botConfig.itemSpawnLimits.assault[id];
if (assaultInventory.items.Backpack[id])
delete assaultInventory.items.Backpack[id];
if (assaultInventory.items.TacticalVest[id])
delete assaultInventory.items.TacticalVest[id];
if (assaultInventory.items.Pockets[id])
delete assaultInventory.items.Pockets[id];
});
Object.keys(newToAdd).forEach((id) => {
botConfig.itemSpawnLimits.assault[id] = newToAdd[id];
botConfig.itemSpawnLimits.assaultgroup[id] = newToAdd[id];
});
return finalValues;
};

View file

@ -0,0 +1,373 @@
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import {
EquipmentFilters,
IRandomisationDetails,
IWeightingAdjustmentDetails,
} from "@spt/models/spt/config/IBotConfig";
import advancedConfig from "../../config/advancedConfig.json";
import { IBotType, IMods } from "@spt/models/eft/common/tables/IBotType";
import {
SightType,
checkParentRecursive,
cloneDeep,
mountParent,
muzzleParent,
sightParent,
weaponParent,
weaponTypeNameToId,
} from "./utils";
import InternalBlacklist from "./InternalBlacklist";
import { globalValues } from "./GlobalValues";
export const makeRandomisationAdjustments = (
isNight: boolean,
originalWeight: EquipmentFilters,
randomisation: IRandomisationDetails[],
location: keyof typeof advancedConfig.locations
) => {
const noNvgNeeded = ["factory4_day", "factory4_night", "laboratory"].includes(
location
);
// levelRange: MinMax;
// generation?: Record<string, GenerationData>;
// /** Mod slots that should be fully randomised -ignores mods from bottype.json and instaed creates a pool using items.json */
// randomisedWeaponModSlots?: string[];
// /** Armor slots that should be randomised e.g. 'Headwear, Armband' */
// randomisedArmorSlots?: string[];
// /** Equipment chances */
// equipment?: Record<string, number>;
// /** Weapon mod chances */
// weaponMods?: Record<string, number>;
// /** Equipment mod chances */
// equipmentMods?: Record<string, number>;
originalWeight.randomisation.forEach((_, index) => {
// NVG's
if (
!noNvgNeeded &&
randomisation?.[index]?.equipmentMods?.mod_nvg !== undefined
) {
randomisation[index].equipmentMods.mod_nvg = isNight
? (index + 1) * 18
: 0;
if (randomisation[index].equipmentMods.mod_nvg > 100)
randomisation[index].equipmentMods.mod_nvg = 100;
}
// Silencers??
if (randomisation?.[index]?.weaponMods?.mod_muzzle !== undefined) {
randomisation[index].weaponMods.mod_muzzle += isNight ? 18 : 0;
if (randomisation[index].weaponMods.mod_muzzle > 100)
randomisation[index].weaponMods.mod_muzzle = 100;
}
// Flashlights
if (
location === "laboratory" ||
randomisation?.[index]?.weaponMods?.mod_flashlight !== undefined
) {
randomisation[index].weaponMods.mod_flashlight += isNight ? 45 : 0;
if (randomisation[index].weaponMods.mod_flashlight > 100)
randomisation[index].weaponMods.mod_flashlight = 100;
}
if (location === "laboratory") {
[
"mod_equipment",
"mod_equipment_000",
"mod_equipment_001",
"mod_equipment_002", //TODO: check if this is still needed
"mod_pistol_grip_akms",
"mod_tactical",
"mod_tactical_2",
"mod_tactical001",
"mod_tactical002",
"mod_tactical_000",
"mod_tactical_001",
"mod_tactical_002",
"mod_tactical_003",
].forEach((modName) => {
if (randomisation?.[index]?.weaponMods?.[modName] !== undefined) {
randomisation[index].weaponMods[modName] += 30;
if (randomisation[index].weaponMods[modName] > 100)
randomisation[index].weaponMods[modName] = 100;
}
});
}
});
};
export const makeMapSpecificWeaponWeightings = (
location: keyof typeof advancedConfig.locations,
items: Record<string, ITemplateItem>,
originalWeight: EquipmentFilters,
pmcWeighting: IWeightingAdjustmentDetails[]
) => {
const firstPrimaryWeaponTypes =
advancedConfig.locations[location].weightingAdjustments.FirstPrimaryWeapon;
originalWeight.weightingAdjustmentsByBotLevel.forEach((weightTier, index) => {
const firstPrimary = weightTier.equipment.edit.FirstPrimaryWeapon;
const firstPrimaryKeys = Object.keys(firstPrimary);
firstPrimaryKeys?.forEach((weaponId) => {
const parentId = items[weaponId]?._parent;
const parent = items?.[parentId]?._name;
if (parent && firstPrimaryWeaponTypes[parent]) {
const multiplier = firstPrimaryWeaponTypes[parent];
pmcWeighting[index].equipment.edit.FirstPrimaryWeapon[weaponId] =
Math.round(multiplier * firstPrimary[weaponId]);
// console.log(firstPrimary[weaponId], " to ", pmcWeighting[index].equipment.edit.FirstPrimaryWeapon[weaponId], parent, items[weaponId]._name)
} else {
console.log(
`Algorthimic LevelProgression: Unable to set map settings for ${items[weaponId]._name} - ${weaponId} `
);
}
});
});
};
export const cullModItems = (
mods: IMods,
isNight: boolean,
items: Record<string, ITemplateItem>,
location: keyof typeof advancedConfig.locations
) => {
const cullList: Set<string> = new Set([
...(isNight ? nightTimeCullList : dayTimeCullList),
...InternalBlacklist,
]);
if (location === "laboratory") {
cullList.delete("5a1ead28fcdbcb001912fa9f");
cullList.delete("5c11046cd174af02a012e42b");
cullList.delete("5a1eaa87fcdbcb001865f75e");
cullList.delete("5d1b5e94d7ad1a2b865a96b0");
cullList.delete("5ea058e01dbce517f324b3e2");
}
for (let key in mods) {
if (
cullList.has(key) ||
!checkDaytimeSilencer(key, isNight, items, cullList)
) {
delete mods[key];
} else {
for (const modType in mods[key]) {
if (mods?.[key]?.[modType].length) {
mods[key][modType] = mods[key][modType].filter(
(id) =>
!cullList.has(id) &&
checkDaytimeSilencer(id, isNight, items, cullList)
);
if (
mods[key][modType].length === 0 &&
Object.keys(mods[key]).length === 1
) {
delete mods[key];
}
}
}
}
}
};
const checkDaytimeSilencer = (
id: string,
isNight: boolean,
items: Record<string, ITemplateItem>,
cullList: Set<string>
) => {
const item = items[id];
if (!item?._props) return false;
switch (true) {
case !isNight &&
checkParentRecursive(id, items, [muzzleParent]) &&
item._props.Loudness < globalValues.advancedConfig.daytimeSilencerCutoff:
// console.log(item._name);
cullList.add(id);
return false;
default:
break;
}
return true;
};
const nightTimeCullList = [
"5cc9c20cd7f00c001336c65d", // tactical_all_ncstar_tactical_blue_laser
"560d657b4bdc2da74d8b4572", // tactical_all_zenit_2p_kleh_vis_laser
];
const dayTimeCullList = [
"5b3b6dc75acfc47a8773fb1e",
"644a3df63b0b6f03e101e065", // tactical_all_bemeyers_mawl_c1_plus
"5b3a337e5acfc4704b4a19a0", // tactical_all_zenit_2u_kleh
"626becf9582c3e319310b837", // tactical_all_insight_wmx200
"57fd23e32459772d0805bcf1", // tactical_all_holosun_ls321
"544909bb4bdc2d6f028b4577", // tactical_all_insight_anpeq15
];
const smgUpperRails = new Set([
"5926dad986f7741f82604363",
"5a966ec8a2750c00171b3f36",
"602e63fb6335467b0c5ac94d",
"5894a5b586f77426d2590767",
"5de8e67c4a9f347bc92edbd7",
]);
const marksmanUpperRails = new Set([
"5df8e4080b92095fd441e594",
"5dfcd0e547101c39625f66f9",
]);
export const updateScopes = (
mods: IMods,
isNight: boolean,
items: Record<string, ITemplateItem>,
location: keyof typeof advancedConfig.locations
) => {
const weaponTypeMapper = buildOutWeaponTypeMapper(location, isNight);
for (let key in mods) {
if (
smgUpperRails.has(key) ||
marksmanUpperRails.has(key) ||
checkParentRecursive(key, items, [weaponParent])
) {
const parent = items[key]._parent;
let scopeTypes = weaponTypeMapper[parent];
if (smgUpperRails.has(key)) {
scopeTypes = weaponTypeMapper[weaponTypeNameToId.Smg];
}
if (marksmanUpperRails.has(key)) {
scopeTypes = weaponTypeMapper[weaponTypeNameToId.MarksmanRifle];
}
if (!scopeTypes) {
// console.log("UNABLE TO FIND PARENT FOR", key, items[key]._name)
break;
}
if (!!mods[key]?.mod_scope?.length) {
const result = mods[key].mod_scope.filter(
(id) =>
scopeTypes.has(items[id]?._parent) ||
checkIfChildHasScopes(id, items, scopeTypes, mods)
);
if (result.length) mods[key].mod_scope = result;
}
if (!!mods[key]?.mod_mount) {
const mountResult = mods[key].mod_mount.filter(
(id) =>
scopeTypes.has(items[id]?._parent) ||
checkIfChildHasScopes(id, items, scopeTypes, mods, true)
);
// console.log(key, items[key]._name, mods[key].mod_mount.length, mountResult.length)
if (mountResult.length) mods[key].mod_mount = mountResult;
mods[key]?.mod_mount;
}
[
"mod_mount_001",
"mod_mount_002",
"mod_mount_003",
"mod_mount_004",
].forEach((mountType) => {
if (!!mods[key]?.[mountType]) {
const mountResult = mods[key][mountType].filter(
(id) =>
!checkParentRecursive(id, items, [mountParent, sightParent]) ||
(items[id]?._parent === mountParent && !mods[id]?.mod_scope) ||
scopeTypes.has(items[id]?._parent) ||
checkIfChildHasScopes(id, items, scopeTypes, mods, true)
);
// console.log(mountType, key, items[key]._name, mods[key][mountType].length, mountResult.length)
if (mountResult.length) mods[key][mountType] = mountResult;
mods[key]?.[mountType];
}
});
if (!!mods[key]?.mod_reciever) {
const receiverScopetypes = checkAssaultScopeTypes(
items,
key,
scopeTypes,
weaponTypeMapper
);
const receiverResult = mods[key].mod_reciever.filter(
(id) =>
scopeTypes.has(items[id]?._parent) ||
checkIfChildHasScopes(id, items, receiverScopetypes, mods, true)
);
// console.log(key, items[key]._name, mods[key].mod_reciever.length, receiverResult.length)
if (receiverResult?.length) mods[key].mod_reciever = receiverResult;
mods[key]?.mod_reciever;
}
}
}
};
const akType = "reciever_ak";
const checkAssaultScopeTypes = (
items: Record<string, ITemplateItem>,
id: string,
originalScopeType: Set<string>,
weaponTypeMapper: Record<string, Set<string>>
) => {
if (items[id]?._name?.includes(akType))
return weaponTypeMapper["5447b5f14bdc2d61278b4567"]; //assault rifle type
return originalScopeType;
};
const checkIfChildHasScopes = (
id: string,
items: Record<string, ITemplateItem>,
scopeTypes: Set<string>,
mods: IMods,
clean?: boolean
) => {
const result = !!mods[id]?.mod_scope?.find((scopeId) =>
scopeTypes.has(items[scopeId]?._parent)
);
if (result && clean) {
const filtered = mods[id]?.mod_scope.filter(
(id) =>
scopeTypes.has(items[id]?._parent) ||
checkIfChildHasScopes(id, items, scopeTypes, mods)
);
if (filtered?.length) mods[id].mod_scope = filtered;
}
return result;
};
const buildOutWeaponTypeMapper = (
location: keyof typeof advancedConfig.locations,
isNight: boolean
) => {
const mapper: Record<string, Set<string>> = {};
const sightConfiguration = cloneDeep(
advancedConfig.locations[location].sightConfiguration
);
if (isNight) {
["SniperRifle", "MarksmanRifle", "AssaultCarbine", "AssaultRifle"].forEach(
(type) => {
sightConfiguration[type].push("NightVision");
}
);
}
for (const weaponType in sightConfiguration) {
const weaponTypeUUID = weaponTypeNameToId[weaponType];
mapper[weaponTypeUUID] = new Set(
sightConfiguration[weaponType].map((name) => SightType[name])
);
}
return mapper;
};
// check if item is scope, if so ignore (allow for child scopes)
// check if item is weapon, if so, filter mod_scope
// if scope, check
// if "55818b224bdc2dde698b456f" Mount, check if any mod_scope within contain correct scopes, if not remove

View file

@ -0,0 +1,655 @@
import { IPmcConfig } from "./../../types/models/spt/config/IPmcConfig.d";
import { DependencyContainer } from "tsyringe";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { DatabaseServer } from "@spt/servers/DatabaseServer";
import advancedConfig from "../../config/advancedConfig.json";
import config from "../../config/config.json";
import { IBotConfig } from "../../types/models/spt/config/IBotConfig.d";
import {
addBossSecuredContainer,
addToModsObject,
AmmoParent,
armorPlateParent,
blacklistedItems,
buildEmptyWeightAdjustments,
buildInitialRandomization,
buildOutModsObject,
buildWeaponSightWhitelist,
checkParentRecursive,
cloneDeep,
combineWhitelist,
deleteBlacklistedItemsFromInventory,
ensureAllAmmoInSecuredContainer,
fixEmptyChancePlates,
getEquipmentType,
magParent,
moneyParent,
numList,
reduceAmmoChancesTo1,
reduceEquipmentChancesTo1,
saveToFile,
setupBaseWhiteList,
setupMods,
setWeightingAdjustments,
setWhitelists,
TradersMasterList,
} from "./utils";
import Tier5 from "../Constants/Tier5";
import botConfigequipmentpmc from "../Cache/botConfigequipmentpmc.json";
import tablesbotstypesusec from "../Cache/tablesbotstypesusec.json";
import { buildLootChanges } from "./LootChanges";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { fixSpecificItemIssues } from "./FixSpecificScopeIssues";
export default function ProgressionChanges(
container: DependencyContainer
): undefined {
const databaseServer = container.resolve<DatabaseServer>("DatabaseServer");
const tables = databaseServer.getTables();
const configServer = container.resolve<ConfigServer>("ConfigServer");
// const presets = tables.globals.ItemPresets;
// let mappedPresets = {};
// Object.values(presets).forEach((preset) => {
// if (preset._encyclopedia) {
// const newPreset = {};
// let mainId = "";
// const otherPresets = {};
// const mapper = {};
// preset._items.forEach((item) => {
// if (item._tpl === preset._encyclopedia) {
// mainId = item._id;
// }
// if (item.parentId && item.slotId) {
// mapper[item._id] = item._tpl;
// if (item.parentId === mainId) {
// if (!newPreset[item.slotId]) newPreset[item.slotId] = [];
// newPreset[item.slotId].push(item._tpl);
// } else {
// if (!otherPresets[mapper[item.parentId]])
// otherPresets[mapper[item.parentId]] = {};
// if (!otherPresets[mapper[item.parentId]][item.slotId]) {
// otherPresets[mapper[item.parentId]][item.slotId] = [item._tpl];
// } else {
// otherPresets[mapper[item.parentId]][item.slotId].push(item._tpl);
// }
// }
// }
// });
// mappedPresets[preset._encyclopedia] = newPreset;
// if (Object.keys(otherPresets))
// mappedPresets = { ...mappedPresets, ...otherPresets };
// }
// });
// saveToFile(mappedPresets, "Constants/mappedPresets.json");
const botConfig = configServer.getConfig<IBotConfig>(ConfigTypes.BOT);
const pmcConfig = configServer.getConfig<IPmcConfig>(ConfigTypes.PMC);
const Logger = container.resolve<ILogger>("WinstonLogger");
const items = tables.templates.items;
const traders = tables.traders;
const usecInventory = tables.bots.types.usec.inventory;
const bearInventory = tables.bots.types.bear.inventory;
const prices = tables.templates.prices;
const handbook = tables.templates.handbook;
let loot: Record<string, number> = {};
if (config.enableLootChanges && !config.forceCached) {
try {
loot = buildLootChanges(
items,
handbook,
prices,
pmcConfig,
botConfig,
tables.bots.types
);
} catch (error) {
Logger.error(
"Algorthimic Progression: buildLootChanges failed, maybe try turning off 'enableLootChanges', \nError: " +
error
);
}
}
if (botConfig.secureContainerAmmoStackCount < 80)
botConfig.secureContainerAmmoStackCount = 80;
if (!pmcConfig.forceHealingItemsIntoSecure)
pmcConfig.forceHealingItemsIntoSecure = true;
pmcConfig.looseWeaponInBackpackChancePercent = 2;
pmcConfig.looseWeaponInBackpackLootMinMax = { min: 0, max: 1 };
if (config?.forceCached !== true) {
try {
const tradersToInclude = [
"Prapor",
"Therapist",
"Skier",
"Peacekeeper",
"Mechanic",
"Ragman",
"Jaeger",
"Arena",
];
const tradersToExclude = [
"Unknown",
"caretaker",
"Fence",
"БТР",
...config.customTradersToExclude,
];
const traderList = Object.values(traders).filter(({ base }) => {
if (config.addCustomTraderItems) {
return !tradersToExclude.includes(base.nickname);
}
return tradersToInclude.includes(base.nickname);
});
botConfig.equipment.pmc.nvgIsActiveChanceNightPercent = 85;
botConfig.equipment.pmc.lightIsActiveNightChancePercent = 45;
botConfig.equipment.pmc.lightIsActiveDayChancePercent = 25;
botConfig.equipment.pmc.laserIsActiveChancePercent = 90;
botConfig.equipment.pmc.armorPlateWeighting = [
{
levelRange: {
min: 1,
max: 99,
},
front_plate: {
"1": 1,
"2": 3,
"3": 15,
"4": 35,
"5": 15,
"6": 5,
},
back_plate: {
"1": 1,
"2": 3,
"3": 15,
"4": 35,
"5": 15,
"6": 5,
},
side_plate: {
"1": 1,
"2": 3,
"3": 15,
"4": 35,
"5": 15,
"6": 5,
},
left_side_plate: {
"1": 1,
"2": 3,
"3": 15,
"4": 35,
"5": 15,
"6": 5,
},
right_side_plate: {
"1": 1,
"2": 3,
"3": 15,
"4": 35,
"5": 15,
"6": 5,
},
},
];
// botConfig.equipment.pmc.forceOnlyArmoredRigWhenNoArmor = false;
botConfig.equipment.pmc.faceShieldIsActiveChancePercent = 100;
botConfig.equipment.pmc.weightingAdjustmentsByBotLevel =
buildEmptyWeightAdjustments();
// >>>>>>>>>>>>>>> Working tradersMasterList <<<<<<<<<<<<<<<<<<
const tradersMasterList: TradersMasterList = {
1: new Set(["572b7adb24597762ae139821", "5fd4c4fa16cac650092f6771"]),
2: new Set(),
3: new Set(),
4: new Set(),
5: new Set(Object.values(Tier5).flat(1)),
};
const mods = { "1": {}, "2": {}, "3": {}, "4": {}, "5": {} };
// SetBaseWhitelist
botConfig.equipment.pmc.whitelist = setupBaseWhiteList();
traderList.forEach(
(
{
base: { nickname },
questassort,
assort: {
items: tradeItems,
loyal_level_items,
barter_scheme,
} = {},
},
index
) => {
if (!tradeItems || !nickname) return;
if (
config.addCustomTraderItems &&
![...tradersToExclude, ...tradersToInclude].includes(nickname)
) {
console.log(
`[AlgorithmicLevelProgression]: Attempting to add items for custom trader > ${nickname}!`
);
}
tradeItems.forEach(({ _tpl, _id, parentId, slotId }) => {
if (
blacklistedItems.has(_tpl) ||
checkParentRecursive(_tpl, items, [armorPlateParent])
)
return; //Remove blacklisted items and bullets
const item = items[_tpl];
if (!item)
return console.log(
"[AlgorithmicLevelProgression]: Skipping custom item: ",
_tpl,
" for trader: ",
nickname
);
const parent = item._parent;
if (!parent || !items[parent])
return console.log(
"[AlgorithmicLevelProgression]: Skipping custom item: ",
_tpl,
" for trader: ",
nickname
);
const equipmentType = getEquipmentType(parent, items);
switch (true) {
//Add Ammo
case checkParentRecursive(parent, items, [AmmoParent]):
const calibre = item._props.Caliber || item._props.ammoCaliber;
if (calibre) {
usecInventory.Ammo[calibre] = {
...(usecInventory.Ammo[calibre] || {}),
[_tpl]: 1,
};
bearInventory.Ammo[calibre] = {
...(bearInventory.Ammo[calibre] || {}),
[_tpl]: 1,
};
// usecInventory.items.SecuredContainer[_tpl] = 1;
// bearInventory.items.SecuredContainer[_tpl] = 1;
} else {
console.log(
item._name,
" likely has the incorrect calibre: ",
calibre
);
}
break;
case checkParentRecursive(parent, items, [magParent]):
// usecInventory.items.SecuredContainer[_tpl] = 1;
// bearInventory.items.SecuredContainer[_tpl] = 1;
break;
// case equipmentType === "mod_scope":
// break;
// Check if revolver shotgun
case _tpl === "60db29ce99594040e04c4a27":
if (!usecInventory.equipment["FirstPrimaryWeapon"])
usecInventory.equipment["FirstPrimaryWeapon"] = {};
if (!bearInventory.equipment["FirstPrimaryWeapon"])
bearInventory.equipment["FirstPrimaryWeapon"] = {};
usecInventory.equipment["FirstPrimaryWeapon"][_tpl] = 1;
bearInventory.equipment["FirstPrimaryWeapon"][_tpl] = 1;
break;
// Check if sawed-off shotgun
case _tpl === "64748cb8de82c85eaf0a273a":
if (!usecInventory.equipment["Holster"])
usecInventory.equipment["Holster"] = {};
if (!bearInventory.equipment["Holster"])
bearInventory.equipment["Holster"] = {};
usecInventory.equipment["Holster"][_tpl] = 1;
bearInventory.equipment["Holster"][_tpl] = 1;
break;
// Add matching equipment
case !!equipmentType:
if (!usecInventory.equipment[equipmentType])
usecInventory.equipment[equipmentType] = {};
if (!bearInventory.equipment[equipmentType])
bearInventory.equipment[equipmentType] = {};
usecInventory.equipment[equipmentType][_tpl] = 1;
bearInventory.equipment[equipmentType][_tpl] = 1;
break;
default:
break;
}
const loyaltyLevel =
loyal_level_items[_id] || loyal_level_items[parentId];
//Set trader list for levels
if (loyaltyLevel) {
const barterSchemeRef =
barter_scheme[_id] || barter_scheme[parentId];
switch (true) {
// If large magazine
case checkParentRecursive(_tpl, items, [magParent]) &&
item?._props?.Cartridges?.[0]?._max_count > 39:
// if (item?._props?.Cartridges?.[0]?._max_count > 39) {
// tradersMasterList[5].add(_tpl)
// return
// }
// tradersMasterList[loyaltyLevel].add(_tpl)
// addToModsObject(mods, _tpl, items, loyaltyLevel, slotId)
break;
// Check if its a quest unlocked trade
case !!questassort.success[_id]:
if (!config?.questUnlockedItemsShifted) {
tradersMasterList[loyaltyLevel].add(_tpl);
addToModsObject(mods, _tpl, items, loyaltyLevel, slotId);
} else {
if (loyaltyLevel === 4) {
tradersMasterList[4].add(_tpl);
addToModsObject(mods, _tpl, items, 4, slotId);
} else {
tradersMasterList[loyaltyLevel + 1].add(_tpl);
addToModsObject(
mods,
_tpl,
items,
loyaltyLevel + 1,
slotId
);
}
}
break;
// Only add the item if it's a cash trade or if tradeItems are not shifted
case items[barterSchemeRef?.[0]?.[0]?._tpl]?._parent ===
moneyParent || !config?.tradedItemsShifted:
tradersMasterList[loyaltyLevel].add(_tpl);
addToModsObject(mods, _tpl, items, loyaltyLevel, slotId);
break;
// Then it's a tradeItem
default:
if (loyaltyLevel + 2 > 4) {
tradersMasterList[4].add(_tpl);
addToModsObject(mods, _tpl, items, 4, slotId);
} else {
tradersMasterList[loyaltyLevel + 2].add(_tpl);
addToModsObject(
mods,
_tpl,
items,
loyaltyLevel + 2,
slotId
);
}
break;
}
}
});
}
);
//Setup beast mod level 5
tradersMasterList[5].forEach((id) => {
if (blacklistedItems.has(id)) {
tradersMasterList[5].delete(id);
} else {
const item = items[id];
const parent = items[id]?._parent;
if (!item || !parent) return;
const equipmentType = getEquipmentType(parent, items);
switch (true) {
case checkParentRecursive(parent, items, [AmmoParent]):
const calibre = item._props.Caliber || item._props.ammoCaliber;
if (calibre) {
usecInventory.Ammo[calibre] = {
...(usecInventory.Ammo[calibre] || {}),
[id]: 1,
};
bearInventory.Ammo[calibre] = {
...(bearInventory.Ammo[calibre] || {}),
[id]: 1,
};
}
break;
case !!equipmentType:
if (!usecInventory.equipment[equipmentType])
usecInventory.equipment[equipmentType] = {};
if (!bearInventory.equipment[equipmentType])
bearInventory.equipment[equipmentType] = {};
usecInventory.equipment[equipmentType][id] = 1;
bearInventory.equipment[equipmentType][id] = 1;
break;
default:
break;
}
}
});
const combinedNumList = new Set([
...tradersMasterList[1],
...tradersMasterList[2],
...tradersMasterList[3],
...tradersMasterList[4],
]);
//TODO: keep an eye on this.. this might be a bad idea.
const combinedNumWith5List = new Set([
...combinedNumList,
...tradersMasterList[5],
]);
buildWeaponSightWhitelist(items, botConfig, tradersMasterList);
buildOutModsObject(combinedNumWith5List, items, usecInventory, botConfig);
bearInventory.mods = cloneDeep(usecInventory.mods);
setupMods(mods);
// lets disable this for now
// addKeysToPockets(combinedNumList, items, tables.bots.types.assault.inventory);
//Make everything level 1 in equipment
reduceEquipmentChancesTo1(usecInventory);
reduceEquipmentChancesTo1(bearInventory);
reduceAmmoChancesTo1(usecInventory);
reduceAmmoChancesTo1(bearInventory);
// Eliminates duplicate id's in later levels
numList.forEach((num) => {
tradersMasterList[num].forEach((id) => {
numList.slice(num, 5).forEach((numListNum) => {
tradersMasterList[numListNum].delete(id);
});
});
});
if (botConfig.equipment.pmc.blacklist?.[0]?.equipment) {
if (
!botConfig.equipment.pmc.blacklist?.[0]?.equipment?.FirstPrimaryWeapon
)
botConfig.equipment.pmc.blacklist[0].equipment.FirstPrimaryWeapon =
[];
if (!botConfig.equipment.pmc.blacklist?.[0]?.equipment?.mod_scope)
botConfig.equipment.pmc.blacklist[0].equipment.mod_scope = [];
if (!botConfig.equipment.pmc.blacklist?.[0]?.equipment?.mod_handguard)
botConfig.equipment.pmc.blacklist[0].equipment.mod_handguard = [];
if (!botConfig.equipment.pmc.blacklist?.[0]?.equipment?.Headwear)
botConfig.equipment.pmc.blacklist[0].equipment.Headwear = [];
botConfig.equipment.pmc.blacklist[0].equipment.FirstPrimaryWeapon.push(
"624c0b3340357b5f566e8766",
"624c0b3340357b5f566e8766",
"6217726288ed9f0845317459",
"62389be94d5d474bf712e709"
);
botConfig.equipment.pmc.blacklist[0].equipment.mod_scope.push(
"544a3d0a4bdc2d1b388b4567"
);
botConfig.equipment.pmc.blacklist[0].equipment.mod_stock.push(
"5a0c59791526d8dba737bba7"
);
botConfig.equipment.pmc.blacklist[0].equipment.Headwear.push(
"5c066ef40db834001966a595"
);
}
setWhitelists(items, botConfig, tradersMasterList, mods);
setWeightingAdjustments(items, botConfig, tradersMasterList, mods);
let lootingBotsDetected = false;
if (
tables?.bots?.types?.bear?.generation?.items?.backpackLoot?.weights &&
new Set(
Object.values(
tables?.bots?.types?.bear?.generation?.items?.backpackLoot.weights
)
).size === 1
) {
console.log(
"[AlgorithmicLevelProgression] Looting bots detected, removing pmc loot"
);
lootingBotsDetected = true;
}
buildInitialRandomization(
items,
botConfig,
tradersMasterList,
lootingBotsDetected
);
deleteBlacklistedItemsFromInventory(usecInventory, blacklistedItems);
deleteBlacklistedItemsFromInventory(bearInventory, blacklistedItems);
// add ai2 and surv to bot containerq
// cms
usecInventory.items.SecuredContainer["5d02778e86f774203e7dedbe"] = 1;
bearInventory.items.SecuredContainer["5d02778e86f774203e7dedbe"] = 1;
// ai2
usecInventory.items.SecuredContainer["5755356824597772cb798962"] = 1;
bearInventory.items.SecuredContainer["5755356824597772cb798962"] = 1;
// Splint
usecInventory.items.SecuredContainer["5af0454c86f7746bf20992e8"] = 1;
bearInventory.items.SecuredContainer["5af0454c86f7746bf20992e8"] = 1;
// Esmarch5e831507ea0a7c419c2f9bd9
usecInventory.items.SecuredContainer["5e831507ea0a7c419c2f9bd9"] = 1;
bearInventory.items.SecuredContainer["5e831507ea0a7c419c2f9bd9"] = 1;
// ensureAllAmmoInSecuredContainer(usecInventory);
// ensureAllAmmoInSecuredContainer(bearInventory);
addBossSecuredContainer(usecInventory);
addBossSecuredContainer(bearInventory);
// addAllMedsToInventory(combinedNumWith5List, usecInventory, items);
fixEmptyChancePlates(botConfig);
fixSpecificItemIssues(usecInventory);
fixSpecificItemIssues(bearInventory);
tables.bots.types.usec.inventory = usecInventory;
tables.bots.types.bear.inventory = bearInventory;
tables.bots.types.bear.inventory = tables.bots.types.usec.inventory; // TESTING << REMOVE IF SLOWER
} catch (error) {
config.forceCached = true;
throw Error(
"Failed to dynamically update items, likely a mod conflict, turning on forceCached and will try again! \nError: " +
error
);
}
} else {
botConfig.equipment.pmc = botConfigequipmentpmc as any;
tables.bots.types.usec = tablesbotstypesusec as any;
tables.bots.types.bear = tablesbotstypesusec as any;
}
if (config.strictEquipmentTiering === false) {
combineWhitelist(botConfig.equipment.pmc);
}
Object.keys(advancedConfig.otherBotTypes).forEach((botType) => {
botConfig.equipment[botType] = {
...botConfig.equipment[botType],
...advancedConfig.otherBotTypes[botType],
};
});
if (
tables?.bots?.types?.assault?.generation?.items?.backpackLoot?.weights &&
new Set(
Object.values(
tables.bots.types.assault.generation.items.backpackLoot.weights
)
).size === 1
) {
console.log(
"[AlgorithmicLevelProgression] Looting bots detected, removing scav loot"
);
const generation = (botConfig.equipment.assault.randomisation[0] as any)
.generation;
generation.backpackLoot = {
...(generation.looseLoot || {}),
weights: { "0": 1 },
whitelist: {},
};
generation.pocketLoot = {
...(generation.looseLoot || {}),
weights: { "0": 1 },
whitelist: {},
};
generation.vestLoot = {
...(generation.looseLoot || {}),
weights: { "0": 1 },
whitelist: {},
};
}
// saveToFile(botConfig, "botConfig.json");
// saveToFile(pmcConfig, "pmcConfig.json");
// tables.bots.types.usec
// botConfig.equipment.pmc
// saveToFile(tables.bots.types.usec, `Cache/tablesbotstypesusec.json`);
// saveToFile(botConfig.equipment.pmc, `Cache/botConfigequipmentpmc.json`);
config.debug ||
(config.forceCached &&
console.log("Algorthimic Progression: Progression Changes completed"));
}
//59ef13ca86f77445fd0e2483
//5b4329f05acfc47a86086aa1

View file

@ -0,0 +1,25 @@
import { DependencyContainer } from "tsyringe";
import { globalValues } from "./GlobalValues";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { cloneDeep } from "./utils";
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { DatabaseServer } from "@spt/servers/DatabaseServer";
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
export const SetupLocationGlobals = (
container: DependencyContainer
): undefined => {
const configServer = container.resolve<ConfigServer>("ConfigServer");
const botConfig = configServer.getConfig<IBotConfig>(ConfigTypes.BOT);
const databaseServer = container.resolve<DatabaseServer>("DatabaseServer");
const profileHelper = container.resolve<ProfileHelper>("ProfileHelper");
const tables = databaseServer.getTables();
globalValues.Logger = container.resolve("WinstonLogger");
globalValues.tables = tables;
globalValues.profileHelper = profileHelper;
globalValues.originalBotTypes = cloneDeep(tables.bots.types);
globalValues.configServer = configServer;
globalValues.originalWeighting = cloneDeep(botConfig.equipment.pmc);
// globalValues.setValuesForLocation("woods", 1);
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,750 @@
import {
IEquipment,
IInventory,
IMods,
} from "@spt/models/eft/common/tables/IBotType";
import { EquipmentFilters } from "@spt/models/spt/config/IBotConfig";
import {
armorParent,
blacklistedItems,
checkParentRecursive,
cloneDeep,
deleteBlacklistedItemsFromInventory,
getAmmoWeighting,
getArmorRating,
getBackPackInternalGridValue,
getTacticalVestValue,
getWeaponWeighting,
headwearParent,
rigParent,
saveToFile,
weaponTypeNameToId,
} from "../LoadoutChanges/utils";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import advancedConfig from "../../config/advancedConfig.json";
import nonPmcBotConfig from "../../config/nonPmcBotConfig.json";
import { MinMax } from "@spt/models/common/MinMax";
import { inventory as cachedInventory } from "../Cache/tablesbotstypesusec.json";
import { weightingAdjustmentsByBotLevel as botWeights } from "../Cache/botConfigequipmentpmc.json";
import tieredItems from "../Constants/tieredItems.json";
import mappedPresets from "../Constants/mappedPresets.json";
import { IPreset } from "@spt/models/eft/common/IGlobals";
const objectToOrderedList = (
equipment: Record<string, number>,
items: Record<string, ITemplateItem>
) =>
Object.keys(equipment)
.sort((a, b) => equipment[a] - equipment[b])
.map((id) => ({ id, value: equipment[id], name: items[id]._name }));
const blackList = new Set<string>([
"5e4abc6786f77406812bd572",
"628bc7fb408e2b2e9c0801b1",
"5b3b713c5acfc4330140bd8d",
"5e997f0b86f7741ac73993e2",
"5c0126f40db834002a125382",
"601948682627df266209af05",
"63495c500c297e20065a08b1",
"59ef13ca86f77445fd0e2483",
"670e8eab8c1bb0e5a7075acf", //mag_pm_izhmeh_9x18pm_999_infectedMagazin
"671d85439ae8365d69117ba6", //mag_tt_toz_std_762x25tt_999_infectedMagazin
"671d8617a3e45c1f5908278c", //mag_mp443_izhmeh_std_9x19_999_infectedMagazin
"671d8ac8a3e45c1f59082799", //mag_glock_glock_w_pad_9x19_999_fde_Infected
"671d8b38b769f0d88c0950f8", //mag_m1911_colt_m45a1_std_1143x23_999_infected
"671d8b8c0959c721a50ca838", //mag_usp_hk_usp_tactical_1143x23_999_infected
"628120f210e26c1f344e6558", // mxc broken mag
]);
const makeRare = new Set<string>([
"6038b4ca92ec1c3103795a0d",
"6038b4b292ec1c3103795a0b",
"5fd4c474dd870108a754b241",
"628b9c7d45122232a872358f",
"628baf0b967de16aab5a4f36",
"628b9784bcf6e2659e09b8a2",
"628baf0b967de16aab5a4f36",
"5c0e541586f7747fa54205c9",
"5bffdd7e0db834001b734a1a",
]);
export const buldTieredItemTypes = (items: Record<string, ITemplateItem>) => {
const result = {};
botWeights.forEach((weight, index) => {
if (index < 4)
// Prevents boss related gear appearing on normal bots
for (const key in weight.equipment.edit) {
Object.keys(weight.equipment.edit[key]).forEach((id) => {
if (blackList.has(id)) return;
if (!result[key]) result[key] = {};
result[key][id] = Math.max(
result[key][id] || 1,
weight.equipment.edit[key][id]
);
});
}
});
for (const key in result) {
for (const id in result[key]) {
if (makeRare.has(id)) {
result[key][id] = result[key][id] * 3;
}
}
}
for (const key in result) {
const equipmentSet = result[key] as Record<string, number>;
result[key] = objectToOrderedList(equipmentSet, items);
}
// AMMO
const ammo = {};
for (const caliber in cachedInventory.Ammo) {
for (const ammoId in cachedInventory.Ammo[caliber]) {
if (items[ammoId]) {
ammo[ammoId] = getAmmoWeighting(items[ammoId]);
}
}
}
result["Ammo"] = objectToOrderedList(ammo, items);
const map = {};
for (const key in result) {
result[key].forEach(({ id, value }) => {
map[id] = value;
});
}
result["mapper"] = map;
return result;
};
export interface BotUpdateInterface {
tiers: Array<number[]>;
HasModdedWeapons?: boolean;
AllowSniperRifles?: boolean;
Ammo: number[];
TacticalVest?: number[];
ArmorVest?: number[];
Backpack?: number[];
Earpiece?: number[];
Eyewear?: number[];
Headwear?: number[];
FaceCover?: number[];
// Scabbard?: number[];
FirstPrimary?: number[];
Holster?: number[];
BasePlateChance: number;
SidePlateChance?: number;
}
const equipmentTypesTochange = new Set([
"TacticalVest",
"ArmorVest",
"Backpack",
"Earpiece",
"Eyewear",
"Headwear",
"FaceCover",
// "Scabbard",
"FirstPrimaryWeapon",
"Holster",
]);
const getRating = (id: string, dflt = 10) => tieredItems.mapper[id] || dflt;
export const normalizeMedianInventoryValues = (inventory: IInventory) => {
for (const caliber in inventory.Ammo) {
let highest = 0;
Object.values(inventory.Ammo[caliber]).forEach((value) => {
if (value > highest) highest = value;
});
const multiplier = 100 / highest;
Object.keys(inventory.Ammo[caliber]).forEach((id) => {
inventory.Ammo[caliber][id] =
Math.round(inventory.Ammo[caliber][id] * multiplier) || 10;
});
}
for (const equipmentType in inventory.equipment) {
if (equipmentTypesTochange.has(equipmentType)) {
let highest = 0;
Object.values(inventory.equipment[equipmentType]).forEach(
(value: number) => {
if (value > highest) highest = value;
}
);
const multiplier = 200 / highest;
Object.keys(inventory.equipment[equipmentType]).forEach((id) => {
inventory.equipment[equipmentType][id] =
Math.round(inventory.equipment[equipmentType][id] * multiplier) || 10;
});
}
}
};
export const addItemsToBotInventory = (
inventory: IInventory,
botToUpdate: BotUpdateInterface,
items: Record<string, ITemplateItem>,
isMarksman = false
) => {
const { Ammo: botToUpdateAmmo, BasePlateChance, ...equipment } = botToUpdate;
const ammoToAdd = new Set<string>([]);
Object.keys(tieredItems).forEach((key) => {
if (equipment[key]) {
const equipmentStart = equipment[key][0];
const equipmentEnd = equipment[key][1];
if (equipmentStart || equipmentEnd) {
const startIndex = Math.floor(tieredItems[key].length * equipmentStart);
const endIndex = Math.floor(tieredItems[key].length * equipmentEnd);
tieredItems[key]
.slice(startIndex, endIndex)
.forEach(({ id, value }) => {
if (
(!botToUpdate.AllowSniperRifles &&
checkParentRecursive(id, items, [
weaponTypeNameToId.SniperRifle,
weaponTypeNameToId.MarksmanRifle,
])) ||
(isMarksman &&
key === "FirstPrimaryWeapon" &&
!checkParentRecursive(id, items, [
weaponTypeNameToId.SniperRifle,
weaponTypeNameToId.MarksmanRifle,
weaponTypeNameToId.AssaultCarbine,
]))
) {
// if (isMarksman && key === "FirstPrimaryWeapon")
// console.log(items[id]._name);
return;
}
if (blacklistedItems.has(id) || blackList.has(id)) return;
if (!inventory.equipment[key][id]) {
inventory.equipment[key][id] = value;
}
const item = items[id];
if (inventory.mods[id]) return;
switch (key) {
case "Headwear":
case "ArmorVest":
case "TacticalVest":
if (!inventory.mods[id]) {
const newModObject = {};
item._props.Slots.forEach((mod) => {
if (mod._props.filters[0].Plate) {
newModObject[mod._name] = newModObject[mod._name] = [
mod._props.filters[0].Plate,
];
}
});
inventory.mods[id] = newModObject;
}
break;
case "FirstPrimaryWeapon":
case "Holster":
if (!cachedInventory.mods[id] || !mappedPresets[id]) {
break;
}
inventory.mods[id] = mappedPresets[id];
// if (isMarksman) console.log(items[id]._name);
if (cachedInventory.mods[id]["patron_in_weapon"]) {
mappedPresets[id]["patron_in_weapon"] =
cachedInventory.mods[id]["patron_in_weapon"];
}
if (cachedInventory.mods[id]["patron_in_weapon_000"]) {
mappedPresets[id]["patron_in_weapon_000"] =
cachedInventory.mods[id]["patron_in_weapon_000"];
}
if (cachedInventory.mods[id]["patron_in_weapon_001"]) {
mappedPresets[id]["patron_in_weapon_001"] =
cachedInventory.mods[id]["patron_in_weapon_001"];
}
const ammo = [
...(cachedInventory.mods[id]["patron_in_weapon"]
? cachedInventory.mods[id]["patron_in_weapon"]
: []),
...(cachedInventory.mods[id]["patron_in_weapon_000"]
? cachedInventory.mods[id]["patron_in_weapon_000"]
: []),
...(cachedInventory.mods[id]["patron_in_weapon_001"]
? cachedInventory.mods[id]["patron_in_weapon_001"]
: []),
];
ammo.forEach((id) => {
ammoToAdd.add(id);
});
break;
default:
break;
}
});
}
}
});
if (botToUpdate?.Ammo?.[1] > 0) {
const Ammo = tieredItems.Ammo;
const ammoStart = botToUpdateAmmo[0];
const ammoEnd = botToUpdateAmmo[1];
if (ammoStart || ammoEnd) {
const startIndex = Math.floor(Ammo.length * ammoStart);
const endIndex = Math.floor(Ammo.length * ammoEnd);
const toAddAmmo = [...ammoToAdd]
.map((id) => ({
id,
value: tieredItems.mapper[id],
}))
.sort((a, b) => a.value - b.value);
const toAddAmmoStartIndex = Math.floor(toAddAmmo.length * ammoStart);
const toAddAmmoEndIndex = Math.floor(toAddAmmo.length * ammoEnd);
[
...toAddAmmo.slice(toAddAmmoStartIndex, toAddAmmoEndIndex),
...Ammo.slice(startIndex, endIndex),
].forEach(({ id, value }) => {
const calibre =
items[id]?._props?.Caliber || items[id]?._props?.ammoCaliber;
if (
calibre &&
inventory.Ammo[calibre] &&
!inventory.Ammo?.[calibre]?.[id]
) {
inventory.Ammo[calibre][id] = value;
}
});
}
}
// Add all plates to all equipment for all bots <<PLATE VARIETY>>
Object.keys(inventory.mods).forEach((id) => {
if (
!checkParentRecursive(id, items, [headwearParent]) &&
checkParentRecursive(id, items, [armorParent, rigParent])
) {
const item = items[id];
if (item?._props?.Slots?.length > 0) {
// if (!inventory.mods[id]) {
const newModObject = {};
item._props.Slots.forEach((mod) => {
if (mod._props.filters[0].Plate) {
newModObject[mod._name] = mod._props.filters[0].Filter;
}
});
if (Object.keys(newModObject).length) inventory.mods[id] = newModObject;
}
}
});
const itemsToAdd = new Set<string>([]);
Object.keys(inventory.mods).forEach((id) => {
Object.values(inventory.mods[id])
.flat(1)
.forEach((item) => {
if (!inventory.mods[item]) itemsToAdd.add(item);
});
});
while (itemsToAdd.size) {
const [id] = itemsToAdd;
if (!inventory.mods[id]) {
if (mappedPresets[id]) {
inventory.mods[id] = mappedPresets[id];
} else if (cachedInventory.mods[id]) {
inventory.mods[id] = cachedInventory.mods[id];
}
}
itemsToAdd.delete(id);
}
deleteBlacklistedItemsFromInventory(inventory, blackList);
};
const defaultRandomisation = [
{
levelRange: {
min: 1,
max: 100,
},
equipmentMods: { mod_nvg: 0 },
},
];
export const setPlateWeightings = (
name: string,
equipmentFilters: EquipmentFilters,
index: number
) => {
equipmentFilters.armorPlateWeighting = [
{
levelRange: {
min: 1,
max: 100,
},
front_plate: {
"1": 1,
"2": 3,
"3": 20,
"4": 20,
"5": 4,
"6": 1,
},
back_plate: {
"1": 1,
"2": 3,
"3": 20,
"4": 20,
"5": 4,
"6": 1,
},
side_plate: {
"1": 1,
"2": 3,
"3": 20,
"4": 20,
"5": 4,
"6": 1,
},
left_side_plate: {
"1": 1,
"2": 3,
"3": 20,
"4": 20,
"5": 4,
"6": 1,
},
right_side_plate: {
"1": 1,
"2": 3,
"3": 20,
"4": 20,
"5": 4,
"6": 1,
},
},
] as any;
if (!nonPmcBotConfig.nonPmcBots?.[name]?.BasePlateChance) {
return;
}
//=========================================
// UPDATE PLATE SPAWN CHANCE
if (!equipmentFilters?.randomisation) {
equipmentFilters.randomisation = defaultRandomisation;
}
const randomizationToUpdate = cloneDeep(equipmentFilters.randomisation[0]);
if (nonPmcBotConfig.nonPmcBots[name].BasePlateChance < 101) {
let front = nonPmcBotConfig.nonPmcBots[name].BasePlateChance + index * 15;
if (front > 100) front = 100;
randomizationToUpdate.equipmentMods["front_plate"] = front;
let back =
nonPmcBotConfig.nonPmcBots[name].BasePlateChance - 20 + index * 15;
if (back > 100) back = 100;
randomizationToUpdate.equipmentMods["back_plate"] = back;
}
if (nonPmcBotConfig.nonPmcBots?.[name]?.SidePlateChance) {
["left_side_plate", "right_side_plate"].forEach((key) => {
let value = nonPmcBotConfig.nonPmcBots[name].SidePlateChance + index * 10;
if (value > 100) value = 100;
if (value < 0) value = 0;
randomizationToUpdate.equipmentMods[key] = value;
});
} else {
["left_side_plate", "right_side_plate"].forEach((key) => {
let value =
nonPmcBotConfig.nonPmcBots[name].BasePlateChance - 30 + index * 10;
if (value > 100) value = 100;
if (value < 0) value = 0;
randomizationToUpdate.equipmentMods[key] = value;
});
}
// console.log(name, randomizationToUpdate.equipmentMods);
equipmentFilters.randomisation[0] = randomizationToUpdate;
//=========================================
};
export const buffScavGearAsLevel = (
equipmentFilters: EquipmentFilters,
index: number
) => {
equipmentFilters.weightingAdjustmentsByPlayerLevel = [
{
levelRange: {
min: 1,
max: 99,
},
},
];
if (!index) return;
const randomizationToUpdate = cloneDeep(
advancedConfig.otherBotTypes.assault.randomisation[0]
);
[
"Headwear",
"Earpiece",
"ArmorVest",
"FaceCover",
// "Scabbard",
"Eyewear",
"Backpack",
].forEach((key) => {
randomizationToUpdate.equipment[key] += index * 15;
if (randomizationToUpdate.equipment[key] > 99)
randomizationToUpdate.equipment[key] = 99;
});
equipmentFilters.randomisation[0] = randomizationToUpdate;
equipmentFilters.blacklist = advancedConfig.otherBotTypes.assault.blacklist;
equipmentFilters.whitelist = advancedConfig.otherBotTypes.assault.whitelist;
};
export interface StoredWeightingAdjustmentDetails {
levelRange: MinMax;
ammo: Record<string, Record<string, number>>;
equipment: Record<string, Record<string, number>>;
}
export const buildEmptyWeightAdjustmentsByDevision = (
botToUpdate: BotUpdateInterface
): StoredWeightingAdjustmentDetails[] => {
const { tiers } = botToUpdate;
const result = [];
tiers.forEach((tier) => {
result.push({
levelRange: {
min: tier[0],
max: tier[1],
},
ammo: {},
equipment: {},
});
});
return result as StoredWeightingAdjustmentDetails[];
};
export const applyValuesToStoredEquipment = (
inventory: IInventory,
items: Record<string, ITemplateItem>,
storedWeightingAdjustmentDetails: StoredWeightingAdjustmentDetails[]
) => {
const ammoList = {};
Object.keys(inventory.Ammo).forEach((key) => {
ammoList[key] = [];
Object.keys(inventory.Ammo[key]).forEach((id) => {
//Zero out ammo
ammoList[key].push({
id,
rating: getAmmoWeighting(items[id]), // + inventory.Ammo[key][id],
});
});
});
Object.keys(ammoList).forEach((key) => {
ammoList[key] = ammoList[key].sort((a, b) => a.rating - b.rating);
});
const equipmentList = {};
Object.keys(inventory.equipment).forEach((key: keyof IEquipment) => {
if (equipmentTypesTochange.has(key)) {
equipmentList[key] = [];
Object.keys(inventory.equipment[key]).forEach((id) => {
//Zero out equipment
if (key === "FirstPrimaryWeapon" || key === "Holster") {
const defAmmoWeight = getAmmoWeighting(
items[items[id]._props.defAmmo]
);
equipmentList[key].push({
id,
rating: getRating(id),
// + inventory.equipment[key][id],
});
} else {
equipmentList[key].push({
id,
rating: getRating(id), //+ inventory.equipment[key][id],
});
}
});
}
});
Object.keys(equipmentList).forEach((key) => {
equipmentList[key] = equipmentList[key].sort((a, b) => a.rating - b.rating);
});
const division = storedWeightingAdjustmentDetails.length;
for (let index = 0; index < division; index++) {
const currentLevelRange = storedWeightingAdjustmentDetails[index];
Object.keys(ammoList).forEach((key) => {
const listPortion = ammoList[key];
const quantityPerLevel = Math.round(listPortion.length / division);
const resultingList = (listPortion as Array<{ id; rating }>).slice(
0,
index === division - 1
? listPortion.length
: index * quantityPerLevel + quantityPerLevel
);
resultingList.forEach(({ id, rating }) => {
if (!currentLevelRange.ammo[key]) currentLevelRange.ammo[key] = {};
currentLevelRange.ammo[key][id] =
Math.round(rating + rating * (index * 0.4)) + inventory.Ammo[key][id];
});
});
Object.keys(equipmentList).forEach((key: keyof IEquipment) => {
const listPortion = equipmentList[key];
const quantityPerLevel = Math.round(listPortion.length / division);
const resultingList = (listPortion as Array<{ id; rating }>).slice(
0,
index === division - 1
? listPortion.length
: index * quantityPerLevel + quantityPerLevel
);
resultingList.forEach(({ id, rating }) => {
if (!currentLevelRange.equipment[key])
currentLevelRange.equipment[key] = {};
currentLevelRange.equipment[key][id] =
Math.round(rating + rating * (index * 0.4)) +
inventory.equipment[key][id];
});
});
}
storedWeightingAdjustmentDetails.forEach((_, index) => {
const weight = storedWeightingAdjustmentDetails[index];
Object.keys(weight.ammo).forEach((caliber) => {
const caliberList = Object.keys(weight.ammo[caliber]).sort(
(a, b) => weight.ammo[caliber][b] - weight.ammo[caliber][a]
);
caliberList.forEach((id, rank) => {
if (caliberList.length > 1 && rank > 0) {
if (rank > 3) {
weight.ammo[caliber][id] = Math.round(
weight.ammo[caliber][id] * 0.5
);
} else {
const modifier = (caliberList.length - rank) / caliberList.length;
weight.ammo[caliber][id] =
Math.round(weight.ammo[caliber][id] * modifier) || 1;
}
}
});
});
// Apply randomness
for (const category in weight.ammo) {
const randomnessMultiplier = nonPmcBotConfig.botAmmoRandomness;
if (!randomnessMultiplier) return;
const list = weight.ammo[category];
const keys = Object.keys(list);
const sortedValues = Object.values(list).sort((a, b) => a - b);
const middleIndex = 0 + Math.round((sortedValues.length - 1) / 2);
const medianValue = sortedValues[middleIndex];
const highestValue = sortedValues[sortedValues.length - 1];
const lowestValue = sortedValues[0];
const betterValue = Math.round(
(medianValue + highestValue + lowestValue) / 3
);
if (betterValue > 1) {
keys.forEach((key) => {
const valToAdjust = list[key];
if (valToAdjust > 5) {
const adjustedAmountMax = betterValue - valToAdjust;
const amountAfterAdjustment = Math.round(
valToAdjust + adjustedAmountMax * randomnessMultiplier
);
if (weight.ammo[category][key]) {
weight.ammo[category][key] = Math.abs(amountAfterAdjustment);
}
}
});
}
}
// Fix weapon weightings
Object.keys(weight.equipment?.FirstPrimaryWeapon || []).forEach((id) => {
const calibre =
items[id]?._props?.Caliber || items[id]?._props?.ammoCaliber;
if (calibre && weight.ammo[calibre]) {
let highestRating = 0;
Object.keys(weight.ammo[calibre]).forEach((key) => {
if (weight.ammo[calibre][key] > highestRating) {
highestRating = weight.ammo[calibre][key];
}
});
if (highestRating) {
weight.equipment.FirstPrimaryWeapon[id] = getWeaponWeighting(
items[id],
highestRating
);
}
}
});
for (const category in weight.equipment) {
const randomnessMultiplier = nonPmcBotConfig.botEquipmentRandomness;
if (!randomnessMultiplier) return;
const list = weight.equipment[category];
const keys = Object.keys(list);
const sortedValues = Object.values(list).sort((a, b) => a - b);
const middleIndex = 0 + Math.round((sortedValues.length - 1) / 2);
const medianValue = sortedValues[middleIndex];
const highestValue = sortedValues[sortedValues.length - 1];
const lowestValue = sortedValues[0];
const betterValue = Math.round(
(medianValue + highestValue + lowestValue) / 3
);
if (betterValue > 1) {
keys.forEach((key) => {
const valToAdjust = list[key];
if (valToAdjust > 5) {
const adjustedAmountMax = betterValue - valToAdjust;
const amountAfterAdjustment = Math.round(
valToAdjust + adjustedAmountMax * randomnessMultiplier
);
if (weight.equipment[category][key]) {
weight.equipment[category][key] = Math.abs(amountAfterAdjustment);
}
}
});
}
}
});
};

View file

@ -0,0 +1,134 @@
import { DependencyContainer } from "tsyringe";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { DatabaseServer } from "@spt/servers/DatabaseServer";
import config from "../../config/config.json";
import nonPmcBotConfig from "../../config/nonPmcBotConfig.json";
import { IBotConfig } from "../../types/models/spt/config/IBotConfig";
import {
addItemsToBotInventory,
applyValuesToStoredEquipment,
buildEmptyWeightAdjustmentsByDevision,
buldTieredItemTypes,
normalizeMedianInventoryValues,
} from "./NonPmcUtils";
import { saveToFile } from "../LoadoutChanges/utils";
import { globalValues } from "../LoadoutChanges/GlobalValues";
import { ConfigServer } from "@spt/servers/ConfigServer";
export default function SetupNonPMCBotChanges(
container: DependencyContainer
): undefined {
const databaseServer = container.resolve<DatabaseServer>("DatabaseServer");
const tables = databaseServer.getTables();
const items = tables.templates.items;
const botsForUpdate = nonPmcBotConfig?.nonPmcBots;
const configServer = container.resolve<ConfigServer>("ConfigServer");
// const tieredItemTypes = buldTieredItemTypes(items);
// saveToFile(tieredItemTypes, "Constants/tieredItems.json");
const botConfig = configServer.getConfig<IBotConfig>(ConfigTypes.BOT);
Object.keys(botsForUpdate).forEach((name) => {
if (nonPmcBotConfig.ignoreList.includes(name)) return;
if (botConfig.equipment?.[name]?.weightingAdjustmentsByPlayerLevel) {
botConfig.equipment[name].weightingAdjustmentsByPlayerLevel = [];
}
if (
botConfig.equipment[name] &&
!botConfig.equipment[name]?.forceOnlyArmoredRigWhenNoArmor &&
nonPmcBotConfig.nonPmcBots[name].forceOnlyArmoredRigWhenNoArmor
) {
botConfig.equipment[name]["forceOnlyArmoredRigWhenNoArmor"] = true;
}
if (!tables.bots.types[name]?.inventory?.Ammo) return;
const inventory = tables.bots.types[name].inventory;
const chances = tables.bots.types[name].chances;
if (name !== "assault") {
Object.keys(nonPmcBotConfig.nonPmcBots[name]).forEach((key) => {
if (
chances.equipment[key] !== undefined &&
chances.equipment[key] < 30 &&
nonPmcBotConfig.nonPmcBots[name][key][1] > 0
) {
switch (key) {
case "Scabbard":
break;
case "Backpack":
case "Holster":
case "Eyewear":
case "FaceCover":
case "Earpiece":
chances.equipment[key] = 30;
break;
default:
if (name.includes("infected")) {
chances.equipment[key] = 50;
break;
}
chances.equipment[key] = 70;
break;
}
}
});
if (chances.equipment.SecondPrimaryWeapon) {
chances.equipment.SecondPrimaryWeapon = 10;
} else {
chances.equipment.SecondPrimaryWeapon = 0;
}
// console.log("\n");
}
// if (name === "marksman") {
// saveToFile(tables.bots.types[name].inventory, `refDBS/marksman.json`);
// }
// console.log("\n", name);
addItemsToBotInventory(
inventory,
nonPmcBotConfig.nonPmcBots[name],
items,
name === "marksman"
);
if (nonPmcBotConfig.nonPmcBots[name].HasModdedWeapons) {
inventory.mods = tables.bots.types.usec.inventory.mods;
}
normalizeMedianInventoryValues(inventory);
const storedEquipmentValues = buildEmptyWeightAdjustmentsByDevision(
nonPmcBotConfig.nonPmcBots[name]
);
applyValuesToStoredEquipment(inventory, items, storedEquipmentValues);
// if (name === "marksman") {
// saveToFile(tables.bots.types[name].inventory, `refDBS/marksman2.json`);
// }
globalValues.storedEquipmentValues[name] = storedEquipmentValues;
});
// console.log(bots);
// saveToFile(
// globalValues.storedEquipmentValues,
// `refDBS/storedEquipmentValues.json`
// );
// saveToFile(botConfig.equipment.assault, "refDBS/equipmentAssault.json");
// saveToFile(
// globalValues.tables.bots.types["assault"]?.inventory,
// `NonPmcBotChanges/botsRef/storedAssault.json`
// );
config.debug &&
console.log("Algorthimic Progression: nonPmcBots equipment stored!");
}

View file

@ -0,0 +1,83 @@
import { IPreSptLoadMod } from "@spt/models/external/IPreSptLoadMod";
/* eslint-disable @typescript-eslint/naming-convention */
import { DependencyContainer } from "tsyringe";
import { IPostSptLoadMod } from "@spt/models/external/IPostSptLoadMod";
import { IPostDBLoadMod } from "@spt/models/external/IPostDBLoadMod";
import BotLevelChanges from "./LevelChanges/BotLevelChanges";
import {
enableProgressionChanges,
enableLevelChanges,
enableNonPMCBotChanges,
leveledClothing,
} from "../config/config.json";
import ProgressionChanges from "./LoadoutChanges/ProgressionChanges";
import { SetupLocationGlobals } from "./LoadoutChanges/SetupLocationGlobals";
import { LocationUpdater } from "./LoadoutChanges/LocationUpdater";
import SetupNonPMCBotChanges from "./NonPmcBotChanges/SetupNonPMCBotChanges";
import ClothingChanges from "./LoadoutChanges/ClothingChanges";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { globalValues } from "./LoadoutChanges/GlobalValues";
import { cloneDeep } from "./LoadoutChanges/utils";
import { DatabaseServer } from "@spt/servers/DatabaseServer";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
class AlgorithmicLevelProgression
implements IPreSptLoadMod, IPostDBLoadMod, IPostSptLoadMod
{
preSptLoad(container: DependencyContainer): void {
enableLevelChanges && BotLevelChanges(container);
enableProgressionChanges && LocationUpdater(container);
}
postDBLoad(container: DependencyContainer): void {
if (enableProgressionChanges) {
try {
ProgressionChanges(container);
} catch (error) {
const Logger = container.resolve<ILogger>("WinstonLogger");
const hasForceCachedChanged = !!error?.message?.includes("forceCached");
if (hasForceCachedChanged) {
Logger.error(
`Algorithmic Level Progression failed to make progression changes.
Trying again using "forceCached" enabled.
Try changing your mod loader so ALP is earlier than mods that add custom items to avoid this message in the future.
Error: ` + error?.message
);
ProgressionChanges(container);
} else {
Logger.error(
`Algorithmic Level Progression failed to make progression changes.
Try changing your mod loader so ALP is earlier than mods that add custom items
Error: ` + error?.message
);
}
}
SetupLocationGlobals(container);
}
enableNonPMCBotChanges && SetupNonPMCBotChanges(container);
const databaseServer = container.resolve<DatabaseServer>("DatabaseServer");
const tables = databaseServer.getTables();
const configServer = container.resolve<ConfigServer>("ConfigServer");
const botConfig = configServer.getConfig<IBotConfig>(ConfigTypes.BOT);
globalValues.originalBotTypes = cloneDeep(tables.bots.types);
globalValues.originalWeighting = cloneDeep(botConfig.equipment.pmc);
// globalValues.updateInventory(1, "woods"); // REMOVE
}
postSptLoad(container: DependencyContainer): void {
try {
leveledClothing && ClothingChanges(container);
} catch (error) {
const Logger = container.resolve<ILogger>("WinstonLogger");
Logger.error(
`Algorithmic Level Progression failed to makeclothing changes.
Try turning off custom clothing in the config!
Error: ` + error?.message
);
}
}
}
module.exports = { mod: new AlgorithmicLevelProgression() };