spt_modpack/user/mods/AlgorithmicLevelProgression/src/LoadoutChanges/utils.ts
2025-07-18 15:52:20 -05:00

1996 lines
62 KiB
TypeScript

import { ICustomizationItem } from "@spt/models/eft/common/tables/ICustomizationItem";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import { ISuit } from "@spt/models/eft/common/tables/ITrader";
import {
IEquipmentFilterDetails,
EquipmentFilters,
IBotConfig,
IRandomisationDetails,
IWeightingAdjustmentDetails,
} from "@spt/models/spt/config/IBotConfig";
import advancedConfig from "../../config/advancedConfig.json";
import config, { levelRange } from "../../config/config.json";
import { MinMax } from "../../types/models/common/MinMax";
import {
IAppearance,
IInventory,
IMods,
} from "../../types/models/eft/common/tables/IBotType";
import InternalBlacklist from "./InternalBlacklist";
import mappedPresets from "../Constants/mappedPresets.json";
export const saveToFile = (data, filePath) => {
var fs = require("fs");
let dir = __dirname;
let dirArray = dir.split("\\");
const directory = `${dirArray[dirArray.length - 5]}/${
dirArray[dirArray.length - 4]
}/${dirArray[dirArray.length - 3]}/${dirArray[dirArray.length - 2]}/`;
fs.writeFile(
directory + filePath,
JSON.stringify(data, null, 4),
function (err) {
if (err) throw err;
}
);
};
export const headwearParent = "5a341c4086f77401f2541505";
export const AmmoParent = "5485a8684bdc2da71d8b4567";
export const magParent = "5448bc234bdc2d3c308b4569";
export const barterParent = "5448eb774bdc2d0a728b4567";
export const keyMechanical = "5c99f98d86f7745c314214b3";
export const stimParent = "5448f3a64bdc2d60728b456a";
export const painKillerParent = "5448f3a14bdc2d27728b4569";
export const medicalParent = "5448f3ac4bdc2dce718b4569";
export const medKitParent = "5448f39d4bdc2d0a728b4568";
export const FoodDrinkParent = "543be6674bdc2df1348b4569";
export const medsParent = "543be5664bdc2dd4348b4569";
export const modParent = "5448fe124bdc2da5018b4567";
export const masterMod = "55802f4a4bdc2ddb688b4569";
export const moneyParent = "543be5dd4bdc2deb348b4569";
export const sightParent = "5448fe7a4bdc2d6f028b456b";
export const stockParent = "55818a594bdc2db9688b456a";
export const pistolGripParent = "55818a684bdc2ddd698b456d";
export const muzzleParent = "5448fe394bdc2d0d028b456c";
export const receiverParent = "55818a304bdc2db5418b457d";
export const gasblockParent = "56ea9461d2720b67698b456f";
export const barrelParent = "555ef6e44bdc2de9068b457e";
export const handguardParent = "55818a104bdc2db9688b4569";
export const chargeParent = "55818a104bdc2db9688b4569";
export const mountParent = "55818b224bdc2dde698b456f";
export const weaponParent = "5422acb9af1c889c16000029";
export const armorParent = "57bef4c42459772e8d35a53b";
export const rigParent = "5448e5284bdc2dcb718b4567";
export const armorPlateParent = "644120aa86ffbe10ee032b6f";
export enum SightType {
AssaultScope = "55818add4bdc2d5b648b456f",
Collimator = "55818ad54bdc2ddc698b4569",
CompactCollimator = "55818acf4bdc2dde698b456b",
OpticScope = "55818ae44bdc2dde698b456c",
SpecialScope = "55818aeb4bdc2ddc698b456a",
ThermalVision = "5d21f59b6dbe99052b54ef83",
NightVision = "5a2c3a9486f774688b05e574",
}
export const weaponTypeNameToId = {
SniperRifle: "5447b6254bdc2dc3278b4568",
MarksmanRifle: "5447b6194bdc2d67278b4567",
AssaultCarbine: "5447b5fc4bdc2d87278b4567",
AssaultRifle: "5447b5f14bdc2d61278b4567",
MachineGun: "5447bed64bdc2d97278b4568",
Smg: "5447b5e04bdc2d62278b4567",
SpecialWeapon: "5447bee84bdc2dc3278b4569",
Shotgun: "5447b6094bdc2dc3278b4567",
Pistol: "5447b5cf4bdc2d65278b4567",
Revolver: "617f1ef5e8b54b0998387733",
GrenadeLauncher: "5447bedf4bdc2d87278b4568",
};
export const addToModsObject = (
mods: { "1": {}; "2": {}; "3": {}; "4": {} },
_tpl: string,
items: Record<string, ITemplateItem>,
loyaltyLevel: number,
slotId: string = ""
) => {
switch (true) {
case checkParentRecursive(_tpl, items, [magParent]):
if (!mods[loyaltyLevel]?.["mod_magazine"])
mods[loyaltyLevel]["mod_magazine"] = [];
mods[loyaltyLevel]["mod_magazine"].push(_tpl);
break;
case slotId !== "hideout":
if (!mods[loyaltyLevel]?.[slotId]) mods[loyaltyLevel][slotId] = [];
mods[loyaltyLevel][slotId].push(_tpl);
break;
// case checkParentRecursive(_tpl, items, Object.values(SightType)):
// if (!mods[loyaltyLevel]?.["mod_scope"]) mods[loyaltyLevel]["mod_scope"] = []
// mods[loyaltyLevel]["mod_scope"].push(_tpl)
// break;
// case checkParentRecursive(_tpl, items, [pistolGripParent]):
// if (!mods[loyaltyLevel]?.["mod_pistol_grip"]) mods[loyaltyLevel]["mod_pistol_grip"] = []
// mods[loyaltyLevel]["mod_pistol_grip"].push(_tpl)
// break;
// case checkParentRecursive(_tpl, items, [stockParent]):
// if (!mods[loyaltyLevel]?.["mod_stock"]) mods[loyaltyLevel]["mod_stock"] = []
// mods[loyaltyLevel]["mod_stock"].push(_tpl)
// break;
// case checkParentRecursive(_tpl, items, [muzzleParent]):
// if (!mods[loyaltyLevel]?.["mod_muzzle"]) mods[loyaltyLevel]["mod_muzzle"] = []
// mods[loyaltyLevel]["mod_muzzle"].push(_tpl)
// break;
// case checkParentRecursive(_tpl, items, [receiverParent]):
// if (!mods[loyaltyLevel]?.["mod_reciever"]) mods[loyaltyLevel]["mod_reciever"] = []
// mods[loyaltyLevel]["mod_reciever"].push(_tpl)
// break;
// case checkParentRecursive(_tpl, items, [gasblockParent]):
// if (!mods[loyaltyLevel]?.["mod_gas_block"]) mods[loyaltyLevel]["mod_gas_block"] = []
// mods[loyaltyLevel]["mod_gas_block"].push(_tpl)
// break;
// case checkParentRecursive(_tpl, items, [barrelParent]):
// if (!mods[loyaltyLevel]?.["mod_barrel"]) mods[loyaltyLevel]["mod_barrel"] = []
// mods[loyaltyLevel]["mod_barrel"].push(_tpl)
// break;
// case checkParentRecursive(_tpl, items, [handguardParent]):
// if (!mods[loyaltyLevel]?.["mod_handguard"]) mods[loyaltyLevel]["mod_handguard"] = []
// mods[loyaltyLevel]["mod_handguard"].push(_tpl)
// break;
// case checkParentRecursive(_tpl, items, [chargeParent]):
// if (!mods[loyaltyLevel]?.["mod_charge"]) mods[loyaltyLevel]["mod_charge"] = []
// mods[loyaltyLevel]["mod_charge"].push(_tpl)
// break;
// case checkParentRecursive(_tpl, items, [mountParent]):
// if (!mods[loyaltyLevel]?.["mod_mount"]) mods[loyaltyLevel]["mod_mount"] = []
// mods[loyaltyLevel]["mod_mount"].push(_tpl)
// break;
default:
break;
}
};
export const addKeysToPockets = (
traderItems: Set<string>,
items: Record<string, ITemplateItem>,
inventory: IInventory
) => {
traderItems.forEach((id) => {
if (
id &&
items[id]?._parent &&
checkParentRecursive(id, items, [keyMechanical])
) {
inventory.items.Pockets[id] = 1;
inventory.items.Backpack[id] = 1;
inventory.items.TacticalVest[id] = 1;
}
});
// inventory.items.Pockets = deDupeArr(inventory.items.Pockets);
// inventory.items.Backpack = deDupeArr(inventory.items.Backpack);
// inventory.items.TacticalVest = deDupeArr(inventory.items.TacticalVest);
};
export const setupMods = (mods: Record<string, Record<string, string[]>>) => {
Object.keys(mods).forEach((numstr) => {
const num = Number(numstr);
Object.keys(mods[num]).forEach((mod) => {
mods[num][mod] = deDupeArr(mods[num][mod]);
if (mods[num + 1]) {
if (!mods[num + 1]?.[mod]) mods[num + 1][mod] = mods[num][mod];
else {
mods[num + 1][mod].push(...mods[num][mod]);
}
}
});
});
};
export const reduceEquipmentChancesTo1 = (inventory: IInventory) => {
Object.keys(inventory.equipment).forEach((equipType) => {
Object.keys(inventory.equipment[equipType]).forEach((id) => {
if (inventory.equipment[equipType][id] !== 0) {
inventory.equipment[equipType][id] = 1;
}
});
});
};
export const reduceAmmoChancesTo1 = (inventory: IInventory) => {
Object.keys(inventory.Ammo).forEach((caliber) => {
Object.keys(inventory.Ammo[caliber]).forEach((id) => {
if (inventory.Ammo[caliber][id] !== 0) {
inventory.Ammo[caliber][id] = 1;
}
});
});
};
export const deDupeArr = (arr: any[]) => [...new Set(arr)];
export const checkParentRecursive = (
parentId: string,
items: Record<string, ITemplateItem>,
queryIds: string[]
): boolean => {
if (queryIds.includes(parentId)) return true;
if (!items?.[parentId]?._parent) return false;
return checkParentRecursive(items[parentId]._parent, items, queryIds);
};
export const cloneDeep = (objectToClone: any) =>
JSON.parse(JSON.stringify(objectToClone));
export const isObject = (item) => {
return item && typeof item === "object" && !Array.isArray(item);
};
export const mergeDeep = (target, ...sources) => {
if (!sources.length) return target;
const source = sources.shift();
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) Object.assign(target, { [key]: {} });
mergeDeep(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}
return mergeDeep(target, ...sources);
};
export const getArmorRating = (
{ _props: { Slots, Weight }, _name, _id }: ITemplateItem,
items: Record<string, ITemplateItem>
): number => {
let armorClassWithCoverage = 1;
if (Slots?.length > 0) {
Slots.forEach((mod) => {
const multiplier =
(mod._props.filters[0]?.armorColliders?.length ||
mod._props.filters[0]?.armorPlateColliders?.length) * 3;
if (mod._props.filters[0]?.Plate !== undefined) {
const plateId =
mod._props.filters[0].Plate === ""
? mod._props.filters[0].Filter[0]
: mod._props.filters[0].Plate;
if (plateId) {
const armorClass = Number(items[plateId]?._props?.armorClass || 0);
if (armorClass > 0) {
armorClassWithCoverage += armorClass * multiplier;
if (armorClass >= 3) armorClassWithCoverage += multiplier;
}
}
}
});
}
// console.log(armorClassWithCoverage, _name, _id);
return armorClassWithCoverage;
};
export const getAmmoWeighting = ({
_props: { PenetrationPower, Damage, InitialSpeed, ProjectileCount },
_id,
_name,
}: ITemplateItem): number => {
let penBonus = (PenetrationPower - 20) * 10;
if (penBonus < 0) penBonus = 0;
const damBonus =
ProjectileCount > 1 ? Damage * ProjectileCount * 0.1 : Damage;
let speedBonus = InitialSpeed > 600 ? 10 : 0;
const rating = Math.round(penBonus + speedBonus + damBonus);
// if (rating > 20) console.log(rating || 3, _name)
return rating || 3;
};
export const getHeadwearRating = (
item: ITemplateItem,
items: Record<string, ITemplateItem>
) => {
let rating = getArmorRating(item, items);
const hasNvg = !!item._props.Slots.find((slot) => slot._name === "mod_nvg");
if (hasNvg) rating += 2;
if (item._props?.BlocksEarpiece) rating *= 0.2;
// console.log(
// Math.round(rating * 1.5 - item._props.Weight),
// "-",
// item._name,
// rating,
// item._props.Weight,
// item._props?.BlocksEarpiece,
// hasNvg,
// item._id
// );
return Math.round(rating * 1.5 - item._props.Weight) || 1;
};
export const getEquipmentType = (
id: string,
items: Record<string, ITemplateItem>
) => {
const equipmentKeys = Object.keys(equipmentIdMapper);
for (let index = 0; index < equipmentKeys.length; index++) {
const key = equipmentKeys[index] as
| keyof typeof equipmentIdMapper
| undefined;
if (checkParentRecursive(id, items, equipmentIdMapper[key])) {
return key;
}
}
};
export const getHighestScoringAmmoValue = (
ammoWeight: Record<string, number>
): number => {
let highestValue = 1;
let highestKey = "";
for (const key in ammoWeight) {
const value = ammoWeight[key];
if (value > highestValue) {
highestValue = value;
highestKey = key;
}
}
// console.log(highestKey, highestValue)
return highestValue;
};
export const getWeaponWeighting = (
{
_props: {
Ergonomics,
BoltAction,
weapClass,
weapFireType,
RecoilForceUp,
ReloadMode,
} = {},
_name,
_id,
}: ITemplateItem,
highestScoringAmmo: number
): number => {
let ammo = highestScoringAmmo;
let gun = Ergonomics;
if (_id === "5bfd297f0db834001a669119") ammo * 0.7; //Make mosin infantry less desirable
if (weapFireType.length === 1 && weapFireType.includes("single"))
ammo = ammo * 0.8;
if (ReloadMode.includes("OnlyBarrel")) ammo = ammo / 4;
if (RecoilForceUp > 200) ammo = ammo * 0.8;
if (BoltAction) ammo = ammo / 2;
if (weapFireType.includes("fullauto")) ammo = ammo * 1.2;
if (weapClass !== "pistol" && RecoilForceUp < 100) ammo * 1.2;
if (
new Set(["64ca3d3954fc657e230529cc", "64637076203536ad5600c990"]).has(_id)
) {
gun *= 0.5;
}
const finalValue = Math.round(gun + ammo);
// if (finalValue > 5) console.log(finalValue > 0 ? finalValue : 1, Math.round(ammo), Math.round(gun), _name, weapClass)
return finalValue > 1 ? finalValue : 1;
};
export const getBackPackInternalGridValue = ({
_props: { Grids, Weight } = {},
_name,
_id,
}: ITemplateItem): number => {
let total = 0;
Grids.forEach(({ _props }) => {
total += _props?.cellsH * _props?.cellsV;
// if the backpack can't hold "Items" give it a severe lower ranking
if (
_props.filters?.[0]?.Filter?.length &&
!_props.filters?.[0]?.Filter?.includes("54009119af1c881c07000029")
) {
total = total / 6;
}
});
// if (total > 20) total += 20;
total = Math.round(total - Weight) * 5;
if (total < 0) total = 1;
// console.log(total, _name, Weight);
if (["6034d103ca006d2dca39b3f0", "6038d614d10cbf667352dd44"].includes(_id)) {
total = Math.round(total * 0.7);
}
return total > 1 ? total : 1;
};
export const getTacticalVestValue = (
item: ITemplateItem,
items: Record<string, ITemplateItem>
): number => {
const { Grids } = item._props;
let spaceTotal = 0;
Grids.forEach(({ _props }) => {
spaceTotal += _props?.cellsH * _props?.cellsV;
});
if (spaceTotal > 12) spaceTotal += 20;
spaceTotal = Math.round(spaceTotal - item._props.Weight);
const armorRating = getArmorRating(item, items) * 0.8;
// console.log(
// Math.round(
// armorRating > spaceTotal ? armorRating + spaceTotal : spaceTotal * 2
// ),
// armorRating > spaceTotal ? "armor" : "vest",
// item._name,
// item._id
// );
return Math.round(
armorRating > spaceTotal ? armorRating + spaceTotal : spaceTotal * 2
);
};
export const equipmentIdMapper = {
Headwear: [headwearParent],
Earpiece: ["5645bcb74bdc2ded0b8b4578"],
FaceCover: ["5a341c4686f77469e155819e"],
Eyewear: ["5448e5724bdc2ddf718b4568"],
ArmBand: ["5b3f15d486f77432d0509248"],
ArmorVest: ["5448e54d4bdc2dcc718b4568"],
TacticalVest: ["5448e5284bdc2dcb718b4567"],
Pockets: ["557596e64bdc2dc2118b4571"],
Backpack: ["5448e53e4bdc2d60728b4567"],
FirstPrimaryWeapon: [
"5447b5fc4bdc2d87278b4567",
"5447b5f14bdc2d61278b4567",
"5447bedf4bdc2d87278b4568",
"5447bed64bdc2d97278b4568",
"5447b6194bdc2d67278b4567",
"5447b6094bdc2dc3278b4567",
"5447b5e04bdc2d62278b4567",
"5447b6254bdc2dc3278b4568",
"5447bee84bdc2dc3278b4569",
],
// SecondPrimaryWeapon: [],
Holster: ["617f1ef5e8b54b0998387733", "5447b5cf4bdc2d65278b4567"],
Scabbard: ["5447e1d04bdc2dff2f8b4567"],
// mod_magazine: [
// "5448bc234bdc2d3c308b4569",
// "610720f290b75a49ff2e5e25"
// ],
// // Stock: ["55818a594bdc2db9688b456a"],
// mod_scope: [...Object.values(SightType)],
};
export type oneToFive = "1" | "2" | "3" | "4" | "5";
export const getCurrentLevelRange = (
currentLevel: number
): oneToFive | undefined => {
for (const key in levelRange) {
const { min, max } = levelRange[key] as MinMax;
if (currentLevel >= min && currentLevel <= max) return key as oneToFive;
}
};
export const numList = [1, 2, 3, 4, 5];
export const arrSum = (arr: number[]): number => arr.reduce((a, b) => a + b, 0);
export const setupBaseWhiteList = (): IEquipmentFilterDetails[] => {
return numList.map((num) => ({
levelRange: levelRange[num],
equipment: {},
cartridge: {},
}));
};
export type TradersMasterList = {
1: Set<string>;
2: Set<string>;
3: Set<string>;
4: Set<string>;
5: Set<string>;
};
export const setWhitelists = (
items: Record<string, ITemplateItem>,
botConfig: IBotConfig,
tradersMasterList: TradersMasterList,
mods: Record<string, Record<string, string[]>>
) => {
numList.forEach((num, index) => {
const loyalty = num;
const whitelist = botConfig.equipment.pmc.whitelist;
const itemList = [...tradersMasterList[loyalty]];
whitelist[index].equipment = {
...whitelist[index].equipment,
...mods[num],
};
itemList.forEach((id) => {
const item = items[id];
const parent = item._parent;
const equipmentType = getEquipmentType(parent, items);
switch (true) {
// Check if revolver shotgun
case id === "60db29ce99594040e04c4a27":
whitelist[index].equipment["FirstPrimaryWeapon"] = [
...(whitelist[index].equipment["FirstPrimaryWeapon"]
? whitelist[index].equipment["FirstPrimaryWeapon"]
: []),
id,
];
break;
// Check if sawed-off shotgun
case id === "64748cb8de82c85eaf0a273a":
whitelist[index].equipment["Holster"] = [
...(whitelist[index].equipment["Holster"]
? whitelist[index].equipment["Holster"]
: []),
id,
];
break;
case !!equipmentType:
whitelist[index].equipment[equipmentType] = [
...(whitelist[index].equipment[equipmentType]
? whitelist[index].equipment[equipmentType]
: []),
id,
];
break;
default:
break;
}
});
if (!!whitelist[index + 1]) {
whitelist[index + 1].equipment = cloneDeep(whitelist[index].equipment);
}
});
// console.log(JSON.stringify(botConfig.equipment.pmc.whitelist))
};
export const buildEmptyWeightAdjustments =
(): IWeightingAdjustmentDetails[] => {
return numList.map((num) => ({
levelRange: levelRange[num],
ammo: {
add: {},
edit: {},
},
equipment: {
add: {},
edit: {},
},
clothing: {
add: {},
edit: {},
},
}));
};
const multiplyAndRound = (num1: number, num2: number): number =>
Math.round(num1 * num2);
const setWeightItem = (
weight: IWeightingAdjustmentDetails,
equipmentType: string,
id: string,
rating: number,
tierMultiplier: number
) => {
// if (add) {
// weight.equipment.add[equipmentType] = {
// ...weight.equipment.add[equipmentType] || {},
// [id]: rating
// }
// } else {
weight.equipment.edit[equipmentType] = {
...(weight.equipment.edit[equipmentType] || {}),
[id]: multiplyAndRound(rating, tierMultiplier) || 1,
};
// }
};
export const setWeightingAdjustments = (
items: Record<string, ITemplateItem>,
botConfig: IBotConfig,
tradersMasterList: TradersMasterList,
mods: Record<string, Record<string, string[]>>
) => {
const weight = botConfig.equipment.pmc.weightingAdjustmentsByBotLevel;
const itemsForNextLevel = {};
numList.forEach((num, index) => {
const loyalty = num;
const itemList = [...tradersMasterList[loyalty]];
const finalList = [
...new Set([
...(advancedConfig.forbiddenBullets[num] || []),
...(itemsForNextLevel[num] || []),
...itemList,
]),
];
// First edit ammo
finalList.forEach((id) => {
if (num < 4 && combinedForbiddenBullets.has(id)) return; //console.log(num, items[id]._name, id)
const item = items[id];
const parent = item._parent;
// Ammo Parent
if (checkParentRecursive(parent, items, [AmmoParent])) {
const calibre = item._props.Caliber || item._props.ammoCaliber;
if (num + 1 < 6) {
if (!itemsForNextLevel[num + 1])
itemsForNextLevel[num + 1] = new Set([]);
itemsForNextLevel[num + 1].add(id);
}
if (!weight[index]?.ammo.edit?.[calibre]) {
weight[index].ammo.edit = {
...weight[index].ammo.edit,
[calibre]: {},
};
}
const ammoWeight = getAmmoWeighting(item);
weight[index].ammo.edit[calibre] = {
...(weight[index].ammo.edit[calibre] || {}),
[id]: ammoWeight,
};
}
});
});
//Make bad ammos worse, better ones better
numList.forEach((num, index) => {
Object.keys(weight[index].ammo.edit).forEach((caliber) => {
const caliberList = Object.keys(weight[index].ammo.edit[caliber]).sort(
(a, b) =>
weight[index].ammo.edit[caliber][b] -
weight[index].ammo.edit[caliber][a]
);
caliberList.forEach((id, rank) => {
if (caliberList.length > 1 && rank > 0) {
if (rank > 3) weight[index].ammo.edit[caliber][id] = 5;
const modifier = (caliberList.length - rank) / caliberList.length;
weight[index].ammo.edit[caliber][id] =
Math.round(weight[index].ammo.edit[caliber][id] * modifier) || 5;
if (weight[index].ammo.edit[caliber][id] === 1)
weight[index].ammo.edit[caliber][id] = 5;
}
});
});
// console.log(JSON.stringify(weight[index].ammo.edit))
});
//Make best ammos have a chance of use at lower level
weight.reverse().forEach((currentItem, index) => {
const nextItem = weight?.[index + 1];
if (nextItem) {
Object.keys(nextItem.ammo.edit).forEach((caliber) => {
if (currentItem.ammo.edit[caliber]) {
const max = Math.max(...Object.values(nextItem.ammo.edit[caliber]));
const maxValueForHighTier = Math.round(
config.higherTierAmmoChance * max
);
const nextAmmoIdList = new Set(
Object.keys(nextItem.ammo.edit[caliber] || {})
);
const currentTierItemList = Object.keys(
currentItem.ammo.edit[caliber]
)
.filter(
(id) =>
!nextAmmoIdList.has(id) &&
currentItem.ammo.edit[caliber][id] > maxValueForHighTier
)
.sort(
(a, b) =>
currentItem.ammo.edit[caliber][b] -
currentItem.ammo.edit[caliber][a]
);
currentTierItemList.forEach((id, rank) => {
weight[index + 1].ammo.edit[caliber][id] = Math.round(
maxValueForHighTier / (currentTierItemList.length - rank)
);
});
}
});
}
});
weight.reverse();
// Apply randomness
weight.forEach(({ ammo }, index) => {
Object.keys(ammo.edit).forEach((calbr) => {
const list = weight[index].ammo.edit[calbr];
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 * config.randomness.Ammo
);
if (weight[index].ammo.edit[calbr][key]) {
weight[index].ammo.edit[calbr][key] = Math.abs(
amountAfterAdjustment
);
}
}
});
}
});
});
// saveToFile(weight, "refDBS/weight1.json"); //------------------------------------------------------------------------------
// for (const category in weight.ammo.edit) {
// const randomnessMultiplier = config?.randomness?.[category];
// if (!randomnessMultiplier) return;
// const list = weight[index].equipment.edit[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[index].equipment.edit[category][key]) {
// weight[index].equipment.edit[category][key] = Math.abs(
// amountAfterAdjustment
// );
// }
// }
// });
// }
// }
// saveToFile(weight, "refDBS/weight1.json");
//------------------------------------------------------------------------------
numList.forEach((actualNum, index) => {
numList.forEach((num) => {
if (num > actualNum) return;
const itemList = [...tradersMasterList[num]];
itemList.forEach((id) => {
const item = items[id];
const parent = item._parent;
const equipmentType = getEquipmentType(parent, items);
const itemIsArmor = Number(item._props.armorClass) > 0;
const isLowList = actualNum - num >= (itemIsArmor ? 1 : 3);
const tierMultiplier = isLowList ? 0 : num / actualNum;
if (equipmentType) {
if (!weight[index]?.equipment?.edit?.[equipmentType]) {
weight[index].equipment.edit = {
...weight[index].equipment.edit,
[equipmentType]: {},
};
}
}
switch (equipmentType) {
case "FirstPrimaryWeapon":
case "Holster":
if (num + 1 < 6) {
if (!itemsForNextLevel[num + 1])
itemsForNextLevel[num + 1] = new Set([]);
itemsForNextLevel[num + 1].add(id);
}
const calibre = item._props.Caliber || item._props.ammoCaliber;
const highestScoringAmmo = getHighestScoringAmmoValue(
weight[index].ammo.edit[calibre]
);
const weaponRating = getWeaponWeighting(item, highestScoringAmmo);
switch (id) {
// Check if revolver shotgun
case "60db29ce99594040e04c4a27":
setWeightItem(
weight[index],
"FirstPrimaryWeapon",
id,
weaponRating,
tierMultiplier
);
break;
// Check if sawed-off shotgun
case "64748cb8de82c85eaf0a273a":
setWeightItem(
weight[index],
"Holster",
id,
weaponRating,
tierMultiplier
);
break;
default:
setWeightItem(
weight[index],
equipmentType,
id,
weaponRating,
tierMultiplier
);
break;
}
break;
case "Headwear":
const rating = getHeadwearRating(item, items);
setWeightItem(
weight[index],
equipmentType,
id,
Math.round(rating),
tierMultiplier
);
break;
case "Earpiece":
const ambientVolumeBonus = item?._props?.AmbientVolume * -1;
const compressorBonus = item?._props?.CompressorVolume * -0.5;
setWeightItem(
weight[index],
equipmentType,
id,
Math.round(compressorBonus + ambientVolumeBonus),
tierMultiplier
);
break;
case "FaceCover":
setWeightItem(
weight[index],
equipmentType,
id,
Math.round(
(item._props.BlocksHeadwear ? 0.1 : 1) *
(item._props.ExamineExperience || 0) +
(item._props.LootExperience || 0)
),
tierMultiplier
);
break;
case "ArmorVest":
const armorRating = getArmorRating(item, items);
setWeightItem(
weight[index],
equipmentType,
id,
armorRating,
tierMultiplier
);
break;
case "ArmBand":
setWeightItem(weight[index], equipmentType, id, 20, tierMultiplier);
break;
case "Scabbard":
setWeightItem(
weight[index],
equipmentType,
id,
Math.round(
(item._props.StabPenetration || 0) +
(item._props.SlashPenetration || 0) +
(item._props.ExamineExperience || 0) +
(item._props.LootExperience || 0)
),
tierMultiplier
);
break;
case "Eyewear":
setWeightItem(
weight[index],
equipmentType,
id,
Math.round(
item._props.LootExperience + item._props.BlindnessProtection * 5
) || 3,
tierMultiplier
);
break;
case "Backpack":
const backpackInternalGridValue =
getBackPackInternalGridValue(item);
setWeightItem(
weight[index],
equipmentType,
id,
backpackInternalGridValue,
tierMultiplier
);
break;
case "TacticalVest":
const tacticalVestWeighting = getTacticalVestValue(item, items);
setWeightItem(
weight[index],
equipmentType,
id,
tacticalVestWeighting,
tierMultiplier
);
break;
default:
// switch (true) {
// case checkParentRecursive(id, items, [medsParent]):
// setWeightItem(
// weight[index],
// "SecuredContainer",
// id,
// num * 10,
// tierMultiplier
// );
// break;
// default:
// break;
// }
break;
}
});
});
for (const category in weight[index].equipment.edit) {
const randomnessMultiplier = config?.randomness?.[category];
if (!randomnessMultiplier) return;
const list = weight[index].equipment.edit[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[index].equipment.edit[category][key]) {
weight[index].equipment.edit[category][key] = Math.abs(
amountAfterAdjustment
);
}
}
});
}
}
});
// const list: { [key: string]: string[] } = {}
// tradersMasterList[5].forEach(id => {
// const parent = items[id]?._parent
// if (!parent) return
// const equipmentType = getEquipmentType(parent, items)
// if (equipmentType) {
// if (!list?.[equipmentType]) list[equipmentType] = []
// list[equipmentType].push(id)
// } else if (checkParentRecursive(parent, items, [AmmoParent])) {
// if (!list?.["ammo"]) list["ammo"] = []
// list.ammo.push(id)
// }
// })
// saveToFile({ list }, "refDBS/tier5.json")
};
export const addAllMedsToInventory = (
traderList: Set<string>,
inventory: IInventory,
items: Record<string, ITemplateItem>
) => {
traderList.forEach((id) => {
if (checkParentRecursive(id, items, [medsParent])) {
if (
inventory.equipment.SecuredContainer?.[id] ||
inventory.equipment.SecuredContainer[id] !== 1
) {
// console.log(items[id]._name);
inventory.equipment.SecuredContainer[id] = 1;
}
}
});
};
export const combineWhitelist = (equipmentFilters: EquipmentFilters) => {
const combinedWhitelist = {
levelRange: {
min: 1,
max: 99,
},
equipment: {},
cartridge: {},
};
equipmentFilters.whitelist.forEach((list, index) => {
for (const key in list) {
if (key !== "levelRange") {
for (const subKey in list[key]) {
const value = equipmentFilters.whitelist[index]?.[key]?.[subKey];
if (value) {
combinedWhitelist[key][subKey] = deDupeArr([
...(!!combinedWhitelist[key][subKey]
? combinedWhitelist[key][subKey]
: []),
...value,
]);
}
}
}
}
});
equipmentFilters.whitelist = [combinedWhitelist];
// saveToFile(equipmentFilters.whitelist, "refDBS/equipmentFilters.json");
};
const addRecursive = (
modId: string,
items: Record<string, ITemplateItem>,
weaponId: string,
mods: IMods,
count = 0
) => {
if (count > 115) return false;
const newModObject = {};
let pass = false;
if (items[modId]?._props?.Slots?.length > 0) {
items[modId]._props.Slots.forEach((mod) => {
if (mod._props?.filters?.[0]?.Filter?.length) {
newModObject[mod._name] = mod._props.filters[0].Filter.filter((id) => {
if (blacklistedItems.has(id)) return false;
count += 1;
addRecursive(id, items, weaponId, mods, count);
return true;
});
pass = true;
}
});
}
if (pass && Object.keys(newModObject).length) {
mods[modId] = newModObject;
}
};
export const buildOutModsObject = (
traderList: Set<string>,
items: Record<string, ITemplateItem>,
inventory: IInventory,
botConfig: IBotConfig
) => {
traderList.forEach((id) => {
const item = items[id];
const newModObject = {} as Record<string, string[]>;
if (
!blacklistedItems.has(id) &&
checkParentRecursive(item._parent, items, [
magParent,
weaponParent,
headwearParent,
armorParent,
rigParent,
])
) {
switch (true) {
case checkParentRecursive(item._parent, items, [magParent]):
// if (item?._props?.Height * item?._props?.Width < 3) {
const bulletList =
item?._props?.Cartridges?.[0]?._props?.filters?.[0]?.Filter.filter(
(_tpl) => !!_tpl && !blacklistedItems.has(_tpl)
);
if (bulletList) {
newModObject["cartridges"] = bulletList;
inventory.mods[id] = newModObject;
}
// } else {
// config.debug &&
// console.warn(
// id,
// item._name,
// item?._props?.Cartridges?.[0]?._max_count
// );
// }
break;
case checkParentRecursive(item._parent, items, [weaponParent]): //Weapon
if (item?._props?.Slots?.length > 0) {
item._props.Slots.forEach((mod) => {
// newModObject[mod._name] = mod._props?.filters[0].Filter.filter((_tpl) => !!_tpl && !blacklistedItems.has(_tpl) && checkForScopeTypeRecursive(_tpl, items, id, inventory.mods))
// } else
if (mod._props?.filters?.[0]?.Filter?.length) {
newModObject[mod._name] = mod._props.filters[0].Filter.filter(
(_tpl) => {
if (!!_tpl && !blacklistedItems.has(_tpl)) {
addRecursive(_tpl, items, id, inventory.mods);
return true;
}
return false;
}
);
}
});
}
if (
item._props?.Chambers?.[0]?._name === "patron_in_weapon" &&
item._props?.Chambers?.[0]?._props?.filters?.[0]?.Filter?.length
) {
newModObject["patron_in_weapon"] =
item._props.Chambers[0]._props?.filters[0].Filter.filter(
(_tpl) => !!_tpl && !blacklistedItems.has(_tpl)
);
}
if (Object.keys(newModObject)) {
inventory.mods[id] = newModObject;
}
break;
case checkParentRecursive(item._parent, items, [
armorParent,
rigParent,
headwearParent,
]): //armor/vest
if (item?._props?.Slots?.length > 0) {
const newModObject = {};
item._props.Slots.forEach((mod) => {
newModObject[mod._name] = mod._props.filters[0].Filter.filter(
(_tpl) => {
addRecursive(_tpl, items, id, inventory.mods);
return !!_tpl && !blacklistedItems.has(_tpl);
}
);
// }
});
inventory.mods[id] = newModObject;
}
break;
default:
// console.log(items[item._parent]._name, id)
break;
}
}
});
traderList.forEach((id) => {
const item = items[id];
const newModObject = mappedPresets[id]
? mappedPresets[id]
: ({} as Record<string, string[]>);
if (
!inventory.mods[id] &&
!blacklistedItems.has(id) &&
checkParentRecursive(item._parent, items, [modParent])
) {
if (item?._props?.Slots?.length > 0) {
item._props.Slots.forEach((mod) => {
if (mod._props?.filters?.[0]?.Filter?.length) {
switch (true) {
case mod._name?.includes("scope") &&
checkParentRecursive(item._parent, items, [
handguardParent,
gasblockParent,
]) /*gasblockParent,*/:
if (!newModObject[mod._name]) newModObject[mod._name] = [];
break;
// case mod._name?.includes("scope"):
// newModObject[mod._name] = mod._props?.filters[0].Filter.filter((_tpl) => siteWhiteList["5447bedf4bdc2d87278b4568"].includes(_tpl))
// console.log(item._name, newModObject[mod._name])
default:
newModObject[mod._name] = deDupeArr([
...(newModObject[mod._name] ? newModObject[mod._name] : []),
...mod._props?.filters[0].Filter.filter(
(_tpl) => !blacklistedItems.has(_tpl)
),
]);
break;
}
}
});
if (Object.keys(newModObject)) {
inventory.mods[id] = newModObject;
}
}
}
});
// console.log(JSON.stringify(inventory.mods))
};
export const buildInitialRandomization = (
items: Record<string, ITemplateItem>,
botConfig: IBotConfig,
traderList: TradersMasterList,
lootingBotsDetected: boolean
) => {
const randomizationItems: IRandomisationDetails[] = [];
numList.forEach((num, index) => {
const range = levelRange[num];
const newItem: IRandomisationDetails = {
levelRange: range,
randomisedArmorSlots: ["TacticalVest", "ArmorVest"],
randomisedWeaponModSlots: [],
equipment: {
Headwear: [75, 85, 99, 99, 99][index],
Earpiece: [55, 75, 95, 100, 100][index],
FaceCover: [25, 35, 65, 75, 90][index],
ArmorVest: index < 2 ? 100 : 70, // [99, 99, 99, 99, 99][index],
ArmBand: [25, 45, 59, 69, 80][index],
// TacticalVest: [96, 96, 99, 99, 99][index],
Pockets: [25, 45, 59, 69, 80][index],
SecondPrimaryWeapon: [0, 0, 0, 0, 5][index],
SecuredContainer: 100,
Scabbard: [1, 5, 5, 10, 40][index],
FirstPrimaryWeapon: [85, 98, 99, 99, 99][index],
Holster: [1, 5, 10, 10, 25][index],
Eyewear: [15, 25, 40, 60, 75][index],
Backpack: [70, 85, 90, 99, 99][index],
},
generation: {
stims: {
weights: [
{
"0": 5,
"1": 1,
},
{
"0": 3,
"1": 1,
},
{
"0": 2,
"1": 1,
},
{
"0": 6,
"1": 5,
"2": 1,
},
{
"0": 5,
"1": 5,
"2": 1,
},
][index],
whitelist: {
...(randomizationItems[index - 1]?.generation.stims.whitelist ||
{}),
},
},
drugs: {
weights: [
{
"0": 1,
"1": 3,
},
{
"0": 1,
"1": 4,
},
{
"0": 1,
"1": 5,
},
{
"0": 0,
"1": 5,
"2": 1,
},
{
"0": 0,
"1": 3,
"2": 1,
},
][index],
whitelist: {
...(randomizationItems[index - 1]?.generation.drugs.whitelist ||
{}),
},
},
healing: {
weights: [
{
"0": 1,
"1": 6,
},
{
"0": 1,
"1": 8,
},
{
"0": 1,
"1": 12,
},
{
"0": 1,
"1": 25,
"2": 5,
},
{
"0": 0,
"1": 3,
"2": 1,
},
][index],
whitelist: {
...(randomizationItems[index - 1]?.generation.healing.whitelist ||
{}),
},
},
grenades: {
weights: [
{
"0": 1,
"1": 1,
},
{
"0": 2,
"1": 2,
"2": 1,
},
{
"0": 1,
"1": 2,
"2": 1,
},
{
"0": 1,
"1": 2,
"2": 2,
},
{
"0": 0,
"1": 2,
"2": 2,
"3": 1,
},
][index],
whitelist: {
...(randomizationItems[index - 1]?.generation.grenades.whitelist ||
{}),
},
},
backpackLoot: {
weights: lootingBotsDetected
? {
"0": 1,
}
: [
{
"0": 1,
"1": 2,
"2": 2,
"3": 1,
"4": 1,
},
{
"0": 1,
"1": 1,
"2": 2,
"3": 2,
"4": 2,
"5": 1,
},
{
"0": 0,
"1": 1,
"2": 1,
"3": 1,
"4": 2,
"5": 2,
"6": 1,
"7": 1,
},
{
"0": 0,
"1": 0,
"2": 1,
"3": 1,
"4": 3,
"5": 2,
"6": 2,
"7": 1,
},
{
"0": 0,
"1": 0,
"2": 0,
"3": 0,
"4": 1,
"5": 1,
"6": 3,
"7": 2,
"8": 2,
},
][index],
whitelist: {},
},
pocketLoot: {
weights: lootingBotsDetected
? {
"0": 1,
}
: [
{
"0": 4,
"1": 1,
"2": 1,
},
{
"0": 3,
"1": 2,
"2": 1,
},
{
"0": 2,
"1": 2,
"2": 1,
"3": 1,
},
{
"0": 1,
"1": 2,
"2": 1,
"3": 1,
},
{
"0": 1,
"1": 1,
"2": 2,
"3": 1,
},
][index],
whitelist: {},
},
vestLoot: {
weights: lootingBotsDetected
? {
"0": 1,
}
: [
{
"0": 3,
"1": 1,
"2": 1,
},
{
"0": 2,
"1": 2,
"2": 1,
"4": 1,
},
{
"0": 1,
"1": 1,
"2": 2,
"3": 2,
"5": 2,
},
{
"0": 1,
"1": 1,
"2": 1,
"3": 2,
"4": 2,
"5": 2,
},
{
"0": 0,
"1": 2,
"3": 2,
"4": 1,
"5": 1,
},
][index],
whitelist: {},
},
magazines: {
weights: [
{
"0": 0,
"1": 1,
"2": 1,
},
{
"0": 0,
"1": 1,
"2": 1,
},
{
"0": 0,
"1": 0,
"2": 1,
"3": 1,
},
{
"0": 0,
"1": 0,
"2": 1,
"3": 1,
},
{
"0": 0,
"1": 0,
"2": 1,
"3": 1,
},
][index],
whitelist: botConfig.equipment.pmc?.whitelist[index]?.equipment
?.mod_magazine
? (() => {
const result = {};
botConfig.equipment.pmc.whitelist[
index
]?.equipment?.mod_magazine.forEach((item) => {
result[item] = 1;
});
return result;
})()
: {},
},
},
weaponMods: {
mod_barrel: [5, 20, 35, 55, 65][index],
mod_bipod: [1, 10, 5, 11, 50][index],
mod_flashlight: [5, 35, 65, 80, 90][index],
mod_foregrip: [10, 40, 70, 90, 95][index],
mod_handguard: [5, 40, 70, 90, 95][index],
mod_launcher: [0, 0, 5, 15, 50][index],
mod_magazine: [50, 60, 80, 90, 95][index],
mod_magazine_000: [0, 0, 25, 75, 90][index],
mod_mount: [75, 95, 100, 100, 100][index],
mod_mount_000: [20, 45, 75, 90, 95][index],
mod_mount_001: [20, 45, 75, 90, 95][index],
mod_mount_002: [20, 45, 75, 90, 95][index],
mod_mount_003: [20, 45, 75, 90, 95][index],
mod_mount_004: [20, 45, 75, 90, 95][index],
mod_mount_005: [20, 45, 75, 90, 95][index],
mod_mount_006: [20, 45, 75, 90, 95][index],
mod_muzzle: [5, 15, 35, 70, 100][index],
mod_muzzle_000: [5, 15, 55, 100, 100][index],
mod_muzzle_001: [5, 15, 80, 100, 100][index],
mod_equipment: [15, 25, 45, 75, 90][index],
mod_equipment_000: [0, 0, 10, 35, 45][index],
mod_equipment_001: [0, 0, 10, 35, 45][index],
mod_equipment_002: [0, 0, 10, 35, 45][index],
mod_pistol_grip_akms: [1, 25, 45, 55, 80][index],
mod_pistol_grip: [1, 25, 45, 65, 80][index],
mod_scope: [30, 70, 100, 100, 100][index],
mod_scope_000: [30, 80, 100, 100, 100][index],
mod_scope_001: [30, 80, 100, 100, 100][index],
mod_scope_002: [30, 80, 100, 100, 100][index],
mod_scope_003: [30, 80, 100, 100, 100][index],
mod_tactical: [15, 30, 65, 70, 95][index],
mod_tactical_2: 0,
mod_tactical001: [5, 25, 45, 70, 85][index],
mod_tactical002: [5, 25, 45, 70, 85][index],
mod_tactical_000: [1, 5, 10, 45, 65][index],
mod_tactical_001: [1, 5, 10, 45, 65][index],
mod_tactical_002: [15, 30, 55, 70, 95][index],
mod_tactical_003: [15, 30, 55, 70, 95][index],
mod_charge: [10, 20, 55, 70, 95][index],
mod_stock: [5, 15, 55, 70, 95][index],
mod_stock_000: 99,
// "mod_stock_001": [1, 10, 15, 20][index],
mod_stock_akms: 100,
mod_sight_front: [90, 40, 5, 0, 0][index],
mod_sight_rear: [90, 40, 5, 0, 0][index],
// "mod_reciever": 100,
// "mod_gas_block": [1, 10, 15, 20][index],
mod_pistolgrip: [1, 15, 45, 55, 90][index],
// "mod_trigger": 1,
// "mod_hammer": 1,
// "mod_catch": 1
},
equipmentMods: {
mod_nvg: 0,
back_plate: [80, 90, 100, 100, 100][index],
front_plate: [80, 90, 100, 100, 100][index],
left_side_plate: [50, 80, 90, 90, 100][index],
right_side_plate: [50, 80, 90, 90, 100][index],
mod_flashlight: [5, 25, 35, 45, 70][index],
mod_equipment: [15, 25, 25, 35, 70][index],
mod_equipment_000: [0, 0, 0, 5, 20][index],
mod_equipment_001: [0, 0, 5, 15, 25][index],
mod_equipment_002: [0, 0, 5, 15, 25][index],
},
};
traderList[num].forEach((id) => {
const item = items[id];
const parent = item._parent;
switch (true) {
case checkParentRecursive(
parent,
items,
num >= 3 ? [painKillerParent, stimParent] : [painKillerParent]
): //stims
// console.log(id, item._name, 5 - index);
newItem.generation.stims.whitelist[id] = num * num * 5;
break;
case checkParentRecursive(parent, items, [medicalParent]): //drugs
newItem.generation.drugs.whitelist[id] = num * num * 5;
break;
case checkParentRecursive(parent, items, [medKitParent]): //meds
newItem.generation.healing.whitelist[id] = num * num * 5;
// medkitsAdd[num].forEach((addId: string) => {
// newItem.generation.healing.whitelist[addId] = num * num * 5;
// });
// medkitsRemove[num].forEach((removeId: string) => {
// delete newItem.generation.healing.whitelist[removeId];
// });
break;
case checkParentRecursive(parent, items, ["543be6564bdc2df4348b4568"]): //ThrowWeap
if (items[id]._props.ThrowType !== "smoke_grenade") {
newItem.generation.grenades.whitelist[id] = num * num * 5;
}
break;
default:
break;
}
});
randomizationItems.push(newItem);
});
botConfig.lootItemResourceRandomization["pmc"] = {
food: {
resourcePercent: 50,
chanceMaxResourcePercent: 90,
},
meds: {
resourcePercent: 50,
chanceMaxResourcePercent: 70,
},
};
botConfig.equipment.pmc["forceStock"] = advancedConfig.forceStock;
botConfig.equipment.pmc.randomisation = randomizationItems;
// console.log(JSON.stringify(randomizationItems));
};
export const buildInitialUsecAppearance = (
appearance: IAppearance,
items: Record<string, ICustomizationItem>
) => {
appearance.feet = {
"5cde95ef7d6c8b04713c4f2d": 15,
};
appearance.body = {
"5cde95d97d6c8b647a3769b0": 15,
};
Object.keys(items).forEach((itemId) => {
const item = items[itemId];
if (item?._props?.Side?.includes("Usec"))
switch (true) {
case item._props.BodyPart === "Head":
if (!appearance.head[itemId]) appearance.head[itemId] = 10;
break;
case item._props.BodyPart === "Hands":
if (!appearance.hands[itemId]) appearance.hands[itemId] = 10;
break;
default:
break;
}
});
};
export const buildInitialBearAppearance = (
appearance: IAppearance,
items: Record<string, ICustomizationItem>
) => {
appearance.feet = {
"5cc085bb14c02e000e67a5c5": 10,
};
appearance.body = {
"5cc0858d14c02e000c6bea66": 10,
};
Object.keys(items).forEach((itemId) => {
const item = items[itemId];
if (item?._props?.Side?.includes("Bear"))
switch (true) {
case item._props.BodyPart === "Head":
if (!appearance.head[itemId]) appearance.head[itemId] = 10;
break;
case item._props.BodyPart === "Hands":
if (!appearance.hands[itemId]) appearance.hands[itemId] = 10;
break;
// case item._parent === "5fc100cf95572123ae738483":
// if (!appearance.voice.includes(item._name)) appearance.voice.push(item._name)
// break;
default:
break;
}
});
};
export const buildClothingWeighting = (
suit: ISuit[],
items: Record<string, ICustomizationItem>,
botConfig: IBotConfig,
usecAppearance: IAppearance,
bearAppearance: IAppearance
) => {
buildInitialUsecAppearance(usecAppearance, items);
buildInitialBearAppearance(bearAppearance, items);
const levels = Object.values(levelRange);
suit.forEach(
({ suiteId, requirements: { profileLevel, loyaltyLevel } = {} }) => {
if (!profileLevel || !suiteId || loyaltyLevel === undefined) return;
if (profileLevel === 0) profileLevel = 1;
const index = levels.findIndex(({ min, max }) => {
if (profileLevel >= min && profileLevel <= max) {
return true;
}
});
if (index === -1)
return console.log(
"Unable to find index for clothing item",
items[suiteId]?._name
);
const clothingAdjust =
botConfig.equipment.pmc.weightingAdjustmentsByBotLevel[index].clothing;
if (index === undefined) return console.log("Empty index for: ", suiteId);
if (items[suiteId]?._props?.Body) {
switch (true) {
case !!items[suiteId]?._name?.toLowerCase().includes("bear"):
bearAppearance.body[items[suiteId]._props.Body] = 1;
break;
case !!items[suiteId]?._name?.toLowerCase().includes("usec"):
usecAppearance.body[items[suiteId]._props.Body] = 1;
break;
default:
bearAppearance.body[items[suiteId]._props.Body] = 1;
usecAppearance.body[items[suiteId]._props.Body] = 1;
break;
}
if (!clothingAdjust?.edit["body"]) clothingAdjust.edit["body"] = {};
clothingAdjust.edit["body"][items[suiteId]._props.Body] =
10 + index * 30;
}
if (items[suiteId]?._props?.Feet) {
switch (true) {
case !!items[suiteId]?._name?.toLowerCase().includes("bear"):
bearAppearance.feet[items[suiteId]._props.Feet] = 1;
break;
case !!items[suiteId]?._name?.toLowerCase().includes("usec"):
usecAppearance.feet[items[suiteId]._props.Feet] = 1;
break;
default:
bearAppearance.feet[items[suiteId]._props.Feet] = 1;
usecAppearance.feet[items[suiteId]._props.Feet] = 1;
break;
}
if (!clothingAdjust?.edit["feet"]) clothingAdjust.edit["feet"] = {};
clothingAdjust.edit["feet"][items[suiteId]._props.Feet] =
10 + index * 30;
}
}
);
// console.log(JSON.stringify(clothingAdjust))
// saveToFile(items, "/customization.json")
// saveToFile(bearAppearance, "/bear.json")
// saveToFile(usecAppearance, "/usec.json")
// saveToFile(clothingAdjust, "/clothingWeighting.json")
};
export const weaponTypes = {
"5447b6254bdc2dc3278b4568": [SightType.AssaultScope, SightType.OpticScope], // SniperRifle
"5447b6194bdc2d67278b4567": [SightType.AssaultScope, SightType.OpticScope], // MarksmanRifle
"5447b5fc4bdc2d87278b4567": [SightType.Collimator, SightType.AssaultScope], // AssaultCarbine
"5447b5f14bdc2d61278b4567": [
SightType.CompactCollimator,
SightType.Collimator,
SightType.AssaultScope,
], // AssaultRifle
"5447bed64bdc2d97278b4568": [
SightType.CompactCollimator,
SightType.Collimator,
], // MachineGun
"5447b5e04bdc2d62278b4567": [
SightType.CompactCollimator,
SightType.Collimator,
], // Smg
"5447bee84bdc2dc3278b4569": [
SightType.CompactCollimator,
SightType.Collimator,
], // SpecialWeapon
"5447b6094bdc2dc3278b4567": [
SightType.CompactCollimator,
SightType.Collimator,
], // Shotgun
"5447b5cf4bdc2d65278b4567": [
SightType.CompactCollimator,
SightType.Collimator,
], // Pistol
"617f1ef5e8b54b0998387733": [
SightType.CompactCollimator,
SightType.Collimator,
], // Revolver
"5447bedf4bdc2d87278b4568": [
SightType.CompactCollimator,
SightType.Collimator,
], // GrenadeLauncher
};
export const buildWeaponSightWhitelist = (
items: Record<string, ITemplateItem>,
botConfig: IBotConfig,
{ 1: a, 2: b, 3: c, 4: d, 5: e }: TradersMasterList
) => {
delete botConfig.equipment.pmc.weaponSightWhitelist;
// botConfig.equipment.pmc.weaponSightWhitelist = {};
return;
const sightWhitelist = botConfig.equipment.pmc.weaponSightWhitelist;
const traderItems = [...new Set([...a, ...b, ...c, ...d, ...e])]; //, ...d
const blacklist = new Set(InternalBlacklist);
traderItems.forEach((id) => {
if (blacklist.has(id)) return;
if (checkParentRecursive(id, items, Object.values(SightType))) {
for (const key in weaponTypes) {
const sightsToCheck = weaponTypes[key];
if (checkParentRecursive(id, items, sightsToCheck)) {
if (!sightWhitelist[key]) sightWhitelist[key] = [];
sightWhitelist[key].push(id);
}
}
}
});
// console.log(JSON.stringify(sightWhitelist))
};
export const buildBlacklist = (
items: Record<string, ITemplateItem>,
botConfig: IBotConfig,
mods: { "1": {}; "2": {}; "3": {}; "4": {}; "5": {} }
) => {
delete botConfig.equipment.pmc.blacklist[0].equipment.mod_magazine;
const currentBlacklist = cloneDeep(botConfig.equipment.pmc.blacklist[0]);
botConfig.equipment.pmc.blacklist = [];
const blacklist = botConfig.equipment.pmc.blacklist;
// const itemsToAddToBlacklist = ["mod_scope", "mod_magazine"]
numList.forEach((num, index) => {
const modList = mods[num];
const range = levelRange[num];
const loyalty = num;
const base = { ...cloneDeep(currentBlacklist), levelRange: range };
if (index < 2) {
numList.splice(0, index + 2).forEach((numInner) => {
Object.keys(mods[numInner]).forEach((key) => {
if (!base.equipment[key]) base.equipment[key] = [];
base.equipment[key].push(...mods[numInner][key]);
});
});
}
blacklist.push(base);
});
};
export const deleteBlacklistedItemsFromInventory = (
inventory: IInventory,
blacklist: Set<string>
) => {
Object.keys(inventory.items).forEach((key) => {
Object.keys(inventory.items[key]).forEach((id) => {
if (blacklist.has(id)) delete inventory.items[key][id];
});
});
Object.keys(inventory.Ammo).forEach((calibre) => {
Object.keys(inventory.Ammo[calibre]).forEach((ammoKey) => {
if (blacklist.has(ammoKey)) {
delete inventory.Ammo[calibre][ammoKey];
// console.log(calibre, ammoKey, inventory.Ammo[calibre][ammoKey]);
}
});
});
Object.keys(inventory.mods).forEach((key) => {
if (blacklist.has(key)) {
delete inventory.mods[key];
} else {
Object.keys(inventory.mods?.[key]).forEach((modtype) => {
if (inventory.mods[key][modtype]?.length) {
inventory.mods[key][modtype].filter((id) => !blacklist.has(id));
}
});
}
});
};
export const ensureAllAmmoInSecuredContainer = (inventory: IInventory) => {
const ammo = Object.keys(inventory.Ammo)
.map((calbr) => Object.keys(inventory.Ammo[calbr]))
.flat();
inventory?.items?.SecuredContainer || {};
ammo.forEach((id) => {
if (!inventory?.items?.SecuredContainer?.[id]) {
inventory.items.SecuredContainer[id] = 1;
}
});
// const sortedAmmo = ammo.sort(
// (a, b) => getAmmoWeighting(items[a]) - getAmmoWeighting(items[b])
// );
// saveToFile({ sortedAmmo }, "refDBS/ammoList.json");
};
export const fixEmptyChancePlates = (botConfig: IBotConfig) => {
const armorPlateWeighting = botConfig.equipment.pmc.armorPlateWeighting;
for (const key in armorPlateWeighting) {
for (const subKey in armorPlateWeighting[key]) {
if (!armorPlateWeighting[key][subKey]?.min) {
for (const num in armorPlateWeighting[key][subKey]) {
if (armorPlateWeighting[key][subKey][num] === 0) {
armorPlateWeighting[key][subKey][num] = 1;
}
}
}
}
}
};
export const addBossSecuredContainer = (inventory: IInventory) => {
inventory.equipment.SecuredContainer = {
"5c0a794586f77461c458f892": 1,
};
};
export const combinedForbiddenBullets = new Set(
Object.values(advancedConfig.forbiddenBullets).flat(1)
);
export const blacklistedItems = new Set([
...config.customBlacklist,
...InternalBlacklist,
]);