Refactor airdrop loot generation to account for armor plate changes

This commit is contained in:
Dev 2024-01-18 23:25:08 +00:00
parent ea0d8224e6
commit 310762d66d
5 changed files with 81 additions and 28 deletions

View File

@ -30,9 +30,13 @@
},
"loot": {
"mixed": {
"presetCount": {
"weaponPresetCount": {
"min": 3,
"max": 5
},
"armorPresetCount": {
"min": 1,
"max": 3
},
"itemCount": {
"min": 12,
@ -155,9 +159,13 @@
"allowBossItems": false
},
"weaponArmor": {
"presetCount": {
"weaponPresetCount": {
"min": 6,
"max": 8
},
"armorPresetCount": {
"min": 3,
"max": 5
},
"itemCount": {
"min": 10,
@ -251,9 +259,13 @@
"allowBossItems": false
},
"foodMedical": {
"presetCount": {
"min": 3,
"max": 5
"weaponPresetCount": {
"min": 0,
"max": 0
},
"armorPresetCount": {
"min": 0,
"max": 0
},
"itemCount": {
"min": 17,
@ -334,9 +346,13 @@
"allowBossItems": false
},
"barter": {
"presetCount": {
"min": 3,
"max": 5
"weaponPresetCount": {
"min": 0,
"max": 0
},
"armorPresetCount": {
"min": 0,
"max": 0
},
"itemCount": {
"min": 16,

View File

@ -208,7 +208,8 @@ export class LocationController
}
return {
presetCount: lootSettingsByType.presetCount,
weaponPresetCount: lootSettingsByType.weaponPresetCount,
armorPresetCount: lootSettingsByType.armorPresetCount,
itemCount: lootSettingsByType.itemCount,
weaponCrateCount: lootSettingsByType.weaponCrateCount,
itemBlacklist: lootSettingsByType.itemBlacklist,

View File

@ -105,14 +105,27 @@ export class LootGenerator
}
}
const globalDefaultPresets = Object.entries(tables.globals.ItemPresets).filter((x) =>
x[1]._encyclopedia !== undefined
);
const randomisedPresetCount = this.randomUtil.getInt(options.presetCount.min, options.presetCount.max);
const globalDefaultPresets = Object.values(this.presetHelper.getDefaultPresets());
// Filter default presets to just weapons
const weaponDefaultPresets = globalDefaultPresets.filter(preset => this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON));
const randomisedWeaponPresetCount = this.randomUtil.getInt(options.weaponPresetCount.min, options.weaponPresetCount.max);
const itemBlacklistArray = Array.from(itemBlacklist);
for (let index = 0; index < randomisedPresetCount; index++)
for (let index = 0; index < randomisedWeaponPresetCount; index++)
{
if (!this.findAndAddRandomPresetToLoot(globalDefaultPresets, itemTypeCounts, itemBlacklistArray, result))
if (!this.findAndAddRandomPresetToLoot(weaponDefaultPresets, itemTypeCounts, itemBlacklistArray, result))
{
index--;
}
}
// Filter default presets to just armors and then filter again by protection level
const armorDefaultPresets = globalDefaultPresets.filter(preset => this.itemHelper.armorItemCanHoldMods(preset._encyclopedia));
const levelFilteredArmorPresets = armorDefaultPresets.filter(armor => this.armorIsDesiredProtectionLevel(armor, options));
const randomisedArmorPresetCount = this.randomUtil.getInt(options.armorPresetCount.min, options.armorPresetCount.max);
for (let index = 0; index < randomisedArmorPresetCount; index++)
{
if (!this.findAndAddRandomPresetToLoot(levelFilteredArmorPresets, itemTypeCounts, itemBlacklistArray, result))
{
index--;
}
@ -121,6 +134,29 @@ export class LootGenerator
return result;
}
/**
* Filter armor items by their main plates protection level
* @param armor Armor preset
* @param options Loot request options
* @returns True item passes checks
*/
protected armorIsDesiredProtectionLevel(armor: IPreset, options: LootRequest): boolean
{
const frontPlate = armor._items.find(mod => mod?.slotId?.toLowerCase() === "front_plate");
if (frontPlate)
{
const plateDb = this.itemHelper.getItem(frontPlate._tpl);
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
}
const helmetTop = armor._items.find(mod => mod?.slotId?.toLowerCase() === "helmet_top");
if (helmetTop)
{
const plateDb = this.itemHelper.getItem(helmetTop._tpl);
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
}
}
/**
* Construct item limit record to hold max and current item count for each item type
* @param limits limits as defined in config
@ -160,6 +196,12 @@ export class LootGenerator
return false;
}
// Skip armors as they need to come from presets
if (this.itemHelper.armorItemCanHoldMods(randomItem._id))
{
return false;
}
const newLootItem: LootItem = {
id: this.hashUtil.generate(),
tpl: randomItem._id,
@ -167,15 +209,6 @@ export class LootGenerator
stackCount: 1,
};
// Check if armor has level in allowed whitelist
if (randomItem._parent === BaseClasses.ARMOR || randomItem._parent === BaseClasses.VEST)
{
if (!options.armorLevelWhitelist.includes(Number(randomItem._props.armorClass)))
{
return false;
}
}
// Special case - handle items that need a stackcount > 1
if (randomItem._props.StackMaxSize > 1)
{
@ -224,14 +257,14 @@ export class LootGenerator
* @returns true if preset was valid and added to pool
*/
protected findAndAddRandomPresetToLoot(
globalDefaultPresets: [string, IPreset][],
globalDefaultPresets: IPreset[],
itemTypeCounts: Record<string, { current: number; max: number; }>,
itemBlacklist: string[],
result: LootItem[],
): boolean
{
// Choose random preset and get details from item.json using encyclopedia value (encyclopedia === tplId)
const randomPreset = this.randomUtil.getArrayValue(globalDefaultPresets)[1];
const randomPreset = this.randomUtil.getArrayValue(globalDefaultPresets);
if (!randomPreset?._encyclopedia)
{
this.logger.debug(`Airdrop - preset with id: ${randomPreset._id} lacks encyclopedia property, skipping`);

View File

@ -44,7 +44,9 @@ export interface AirdropChancePercent
export interface AirdropLoot
{
/** Min/max of weapons inside crate */
presetCount?: MinMax;
weaponPresetCount?: MinMax;
/** Min/max of armors (head/chest/rig) inside crate */
armorPresetCount?: MinMax;
/** Min/max of items inside crate */
itemCount: MinMax;
/** Min/max of sealed weapon boxes inside crate */

View File

@ -2,7 +2,8 @@ import { MinMax } from "@spt-aki/models/common/MinMax";
export interface LootRequest
{
presetCount: MinMax;
weaponPresetCount: MinMax;
armorPresetCount: MinMax;
itemCount: MinMax;
weaponCrateCount: MinMax;
itemBlacklist: string[];