Refactor airdrop loot generation to account for armor plate changes
This commit is contained in:
parent
ea0d8224e6
commit
310762d66d
@ -30,9 +30,13 @@
|
|||||||
},
|
},
|
||||||
"loot": {
|
"loot": {
|
||||||
"mixed": {
|
"mixed": {
|
||||||
"presetCount": {
|
"weaponPresetCount": {
|
||||||
"min": 3,
|
"min": 3,
|
||||||
"max": 5
|
"max": 5
|
||||||
|
},
|
||||||
|
"armorPresetCount": {
|
||||||
|
"min": 1,
|
||||||
|
"max": 3
|
||||||
},
|
},
|
||||||
"itemCount": {
|
"itemCount": {
|
||||||
"min": 12,
|
"min": 12,
|
||||||
@ -155,9 +159,13 @@
|
|||||||
"allowBossItems": false
|
"allowBossItems": false
|
||||||
},
|
},
|
||||||
"weaponArmor": {
|
"weaponArmor": {
|
||||||
"presetCount": {
|
"weaponPresetCount": {
|
||||||
"min": 6,
|
"min": 6,
|
||||||
"max": 8
|
"max": 8
|
||||||
|
},
|
||||||
|
"armorPresetCount": {
|
||||||
|
"min": 3,
|
||||||
|
"max": 5
|
||||||
},
|
},
|
||||||
"itemCount": {
|
"itemCount": {
|
||||||
"min": 10,
|
"min": 10,
|
||||||
@ -251,9 +259,13 @@
|
|||||||
"allowBossItems": false
|
"allowBossItems": false
|
||||||
},
|
},
|
||||||
"foodMedical": {
|
"foodMedical": {
|
||||||
"presetCount": {
|
"weaponPresetCount": {
|
||||||
"min": 3,
|
"min": 0,
|
||||||
"max": 5
|
"max": 0
|
||||||
|
},
|
||||||
|
"armorPresetCount": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 0
|
||||||
},
|
},
|
||||||
"itemCount": {
|
"itemCount": {
|
||||||
"min": 17,
|
"min": 17,
|
||||||
@ -334,9 +346,13 @@
|
|||||||
"allowBossItems": false
|
"allowBossItems": false
|
||||||
},
|
},
|
||||||
"barter": {
|
"barter": {
|
||||||
"presetCount": {
|
"weaponPresetCount": {
|
||||||
"min": 3,
|
"min": 0,
|
||||||
"max": 5
|
"max": 0
|
||||||
|
},
|
||||||
|
"armorPresetCount": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 0
|
||||||
},
|
},
|
||||||
"itemCount": {
|
"itemCount": {
|
||||||
"min": 16,
|
"min": 16,
|
||||||
|
@ -208,7 +208,8 @@ export class LocationController
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
presetCount: lootSettingsByType.presetCount,
|
weaponPresetCount: lootSettingsByType.weaponPresetCount,
|
||||||
|
armorPresetCount: lootSettingsByType.armorPresetCount,
|
||||||
itemCount: lootSettingsByType.itemCount,
|
itemCount: lootSettingsByType.itemCount,
|
||||||
weaponCrateCount: lootSettingsByType.weaponCrateCount,
|
weaponCrateCount: lootSettingsByType.weaponCrateCount,
|
||||||
itemBlacklist: lootSettingsByType.itemBlacklist,
|
itemBlacklist: lootSettingsByType.itemBlacklist,
|
||||||
|
@ -105,14 +105,27 @@ export class LootGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalDefaultPresets = Object.entries(tables.globals.ItemPresets).filter((x) =>
|
const globalDefaultPresets = Object.values(this.presetHelper.getDefaultPresets());
|
||||||
x[1]._encyclopedia !== undefined
|
|
||||||
);
|
// Filter default presets to just weapons
|
||||||
const randomisedPresetCount = this.randomUtil.getInt(options.presetCount.min, options.presetCount.max);
|
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);
|
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--;
|
index--;
|
||||||
}
|
}
|
||||||
@ -121,6 +134,29 @@ export class LootGenerator
|
|||||||
return result;
|
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
|
* Construct item limit record to hold max and current item count for each item type
|
||||||
* @param limits limits as defined in config
|
* @param limits limits as defined in config
|
||||||
@ -160,6 +196,12 @@ export class LootGenerator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip armors as they need to come from presets
|
||||||
|
if (this.itemHelper.armorItemCanHoldMods(randomItem._id))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const newLootItem: LootItem = {
|
const newLootItem: LootItem = {
|
||||||
id: this.hashUtil.generate(),
|
id: this.hashUtil.generate(),
|
||||||
tpl: randomItem._id,
|
tpl: randomItem._id,
|
||||||
@ -167,15 +209,6 @@ export class LootGenerator
|
|||||||
stackCount: 1,
|
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
|
// Special case - handle items that need a stackcount > 1
|
||||||
if (randomItem._props.StackMaxSize > 1)
|
if (randomItem._props.StackMaxSize > 1)
|
||||||
{
|
{
|
||||||
@ -224,14 +257,14 @@ export class LootGenerator
|
|||||||
* @returns true if preset was valid and added to pool
|
* @returns true if preset was valid and added to pool
|
||||||
*/
|
*/
|
||||||
protected findAndAddRandomPresetToLoot(
|
protected findAndAddRandomPresetToLoot(
|
||||||
globalDefaultPresets: [string, IPreset][],
|
globalDefaultPresets: IPreset[],
|
||||||
itemTypeCounts: Record<string, { current: number; max: number; }>,
|
itemTypeCounts: Record<string, { current: number; max: number; }>,
|
||||||
itemBlacklist: string[],
|
itemBlacklist: string[],
|
||||||
result: LootItem[],
|
result: LootItem[],
|
||||||
): boolean
|
): boolean
|
||||||
{
|
{
|
||||||
// Choose random preset and get details from item.json using encyclopedia value (encyclopedia === tplId)
|
// 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)
|
if (!randomPreset?._encyclopedia)
|
||||||
{
|
{
|
||||||
this.logger.debug(`Airdrop - preset with id: ${randomPreset._id} lacks encyclopedia property, skipping`);
|
this.logger.debug(`Airdrop - preset with id: ${randomPreset._id} lacks encyclopedia property, skipping`);
|
||||||
|
@ -44,7 +44,9 @@ export interface AirdropChancePercent
|
|||||||
export interface AirdropLoot
|
export interface AirdropLoot
|
||||||
{
|
{
|
||||||
/** Min/max of weapons inside crate */
|
/** 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 */
|
/** Min/max of items inside crate */
|
||||||
itemCount: MinMax;
|
itemCount: MinMax;
|
||||||
/** Min/max of sealed weapon boxes inside crate */
|
/** Min/max of sealed weapon boxes inside crate */
|
||||||
|
@ -2,7 +2,8 @@ import { MinMax } from "@spt-aki/models/common/MinMax";
|
|||||||
|
|
||||||
export interface LootRequest
|
export interface LootRequest
|
||||||
{
|
{
|
||||||
presetCount: MinMax;
|
weaponPresetCount: MinMax;
|
||||||
|
armorPresetCount: MinMax;
|
||||||
itemCount: MinMax;
|
itemCount: MinMax;
|
||||||
weaponCrateCount: MinMax;
|
weaponCrateCount: MinMax;
|
||||||
itemBlacklist: string[];
|
itemBlacklist: string[];
|
||||||
|
Loading…
Reference in New Issue
Block a user