2023-03-03 15:23:46 +00:00
|
|
|
import { inject, injectable } from "tsyringe";
|
|
|
|
|
2023-10-19 17:21:17 +00:00
|
|
|
import { PMCLootGenerator } from "@spt-aki/generators/PMCLootGenerator";
|
|
|
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
|
|
|
import { IBotType } from "@spt-aki/models/eft/common/tables/IBotType";
|
|
|
|
import { ITemplateItem, Props } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
|
|
|
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
|
|
|
|
import { IBotLootCache, LootCacheType } from "@spt-aki/models/spt/bots/IBotLootCache";
|
|
|
|
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
|
|
|
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
|
|
|
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
|
|
|
import { RagfairPriceService } from "@spt-aki/services/RagfairPriceService";
|
|
|
|
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
2023-03-03 15:23:46 +00:00
|
|
|
|
|
|
|
@injectable()
|
|
|
|
export class BotLootCacheService
|
|
|
|
{
|
2023-03-22 14:49:24 +00:00
|
|
|
protected lootCache: Record<string, IBotLootCache>;
|
2023-03-03 15:23:46 +00:00
|
|
|
|
|
|
|
constructor(
|
|
|
|
@inject("WinstonLogger") protected logger: ILogger,
|
|
|
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
2023-03-17 18:20:16 +00:00
|
|
|
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
2023-03-03 15:23:46 +00:00
|
|
|
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
|
|
|
@inject("PMCLootGenerator") protected pmcLootGenerator: PMCLootGenerator,
|
|
|
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
2023-11-13 11:13:25 -05:00
|
|
|
@inject("RagfairPriceService") protected ragfairPriceService: RagfairPriceService,
|
2023-03-03 15:23:46 +00:00
|
|
|
)
|
|
|
|
{
|
|
|
|
this.clearCache();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-04-24 11:57:19 +01:00
|
|
|
* Remove cached bot loot data
|
2023-03-03 15:23:46 +00:00
|
|
|
*/
|
|
|
|
public clearCache(): void
|
|
|
|
{
|
|
|
|
this.lootCache = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the fully created loot array, ordered by price low to high
|
|
|
|
* @param botRole bot to get loot for
|
|
|
|
* @param isPmc is the bot a pmc
|
|
|
|
* @param lootType what type of loot is needed (backpack/pocket/stim/vest etc)
|
2023-03-17 18:20:16 +00:00
|
|
|
* @param botJsonTemplate Base json db file for the bot having its loot generated
|
2023-03-03 15:23:46 +00:00
|
|
|
* @returns ITemplateItem array
|
|
|
|
*/
|
2023-11-13 11:13:25 -05:00
|
|
|
public getLootFromCache(
|
|
|
|
botRole: string,
|
|
|
|
isPmc: boolean,
|
|
|
|
lootType: LootCacheType,
|
|
|
|
botJsonTemplate: IBotType,
|
2024-02-21 17:36:27 +00:00
|
|
|
): Record<string, number>
|
2023-03-03 15:23:46 +00:00
|
|
|
{
|
|
|
|
if (!this.botRoleExistsInCache(botRole))
|
|
|
|
{
|
|
|
|
this.initCacheForBotRole(botRole);
|
2023-03-17 18:20:16 +00:00
|
|
|
this.addLootToCache(botRole, isPmc, botJsonTemplate);
|
2023-03-03 15:23:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (lootType)
|
|
|
|
{
|
|
|
|
case LootCacheType.SPECIAL:
|
|
|
|
return this.lootCache[botRole].specialItems;
|
|
|
|
case LootCacheType.BACKPACK:
|
|
|
|
return this.lootCache[botRole].backpackLoot;
|
|
|
|
case LootCacheType.POCKET:
|
|
|
|
return this.lootCache[botRole].pocketLoot;
|
|
|
|
case LootCacheType.VEST:
|
|
|
|
return this.lootCache[botRole].vestLoot;
|
2024-01-18 12:07:32 +00:00
|
|
|
case LootCacheType.SECURE:
|
|
|
|
return this.lootCache[botRole].secureLoot;
|
2023-03-03 15:23:46 +00:00
|
|
|
case LootCacheType.COMBINED:
|
|
|
|
return this.lootCache[botRole].combinedPoolLoot;
|
|
|
|
case LootCacheType.HEALING_ITEMS:
|
|
|
|
return this.lootCache[botRole].healingItems;
|
|
|
|
case LootCacheType.GRENADE_ITEMS:
|
|
|
|
return this.lootCache[botRole].grenadeItems;
|
|
|
|
case LootCacheType.DRUG_ITEMS:
|
|
|
|
return this.lootCache[botRole].drugItems;
|
|
|
|
case LootCacheType.STIM_ITEMS:
|
|
|
|
return this.lootCache[botRole].stimItems;
|
|
|
|
default:
|
2023-11-13 11:13:25 -05:00
|
|
|
this.logger.error(
|
|
|
|
this.localisationService.getText("bot-loot_type_not_found", {
|
|
|
|
lootType: lootType,
|
|
|
|
botRole: botRole,
|
|
|
|
isPmc: isPmc,
|
|
|
|
}),
|
|
|
|
);
|
2023-03-03 15:23:46 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate loot for a bot and store inside a private class property
|
|
|
|
* @param botRole bots role (assault / pmcBot etc)
|
|
|
|
* @param isPmc Is the bot a PMC (alteres what loot is cached)
|
2023-03-17 18:20:16 +00:00
|
|
|
* @param botJsonTemplate db template for bot having its loot generated
|
2023-03-03 15:23:46 +00:00
|
|
|
*/
|
2023-03-17 18:20:16 +00:00
|
|
|
protected addLootToCache(botRole: string, isPmc: boolean, botJsonTemplate: IBotType): void
|
2023-03-03 15:23:46 +00:00
|
|
|
{
|
2023-03-17 18:20:16 +00:00
|
|
|
// the full pool of loot we use to create the various sub-categories with
|
|
|
|
const lootPool = botJsonTemplate.inventory.items;
|
|
|
|
|
2023-03-03 15:23:46 +00:00
|
|
|
// Flatten all individual slot loot pools into one big pool, while filtering out potentially missing templates
|
2024-02-21 17:36:27 +00:00
|
|
|
const specialLootPool: Record<string, number> = {};
|
|
|
|
const backpackLootPool: Record<string, number> = {};
|
|
|
|
const pocketLootPool: Record<string, number> = {};
|
|
|
|
const vestLootPool: Record<string, number> = {};
|
|
|
|
const secureLootTPool: Record<string, number> = {};
|
|
|
|
const combinedLootPool: Record<string, number> = {};
|
2023-03-03 15:23:46 +00:00
|
|
|
|
|
|
|
if (isPmc)
|
|
|
|
{
|
2024-02-21 17:36:27 +00:00
|
|
|
// Replace lootPool from bot json with our own generated list for PMCs
|
2024-02-22 16:34:15 +00:00
|
|
|
lootPool.Backpack = this.jsonUtil.clone(this.pmcLootGenerator.generatePMCBackpackLootPool(botRole));
|
|
|
|
lootPool.Pockets = this.jsonUtil.clone(this.pmcLootGenerator.generatePMCPocketLootPool(botRole));
|
|
|
|
lootPool.TacticalVest = this.jsonUtil.clone(this.pmcLootGenerator.generatePMCVestLootPool(botRole));
|
2023-03-03 15:23:46 +00:00
|
|
|
}
|
|
|
|
|
2024-02-21 17:36:27 +00:00
|
|
|
// Backpack/Pockets etc
|
2023-03-03 15:23:46 +00:00
|
|
|
for (const [slot, pool] of Object.entries(lootPool))
|
|
|
|
{
|
2023-03-17 18:20:16 +00:00
|
|
|
// No items to add, skip
|
2024-02-21 17:36:27 +00:00
|
|
|
if (Object.keys(pool).length === 0)
|
2023-03-03 15:23:46 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-03-17 18:20:16 +00:00
|
|
|
// Sort loot pool into separate buckets
|
2023-03-03 15:23:46 +00:00
|
|
|
switch (slot.toLowerCase())
|
|
|
|
{
|
|
|
|
case "specialloot":
|
2024-02-21 17:36:27 +00:00
|
|
|
this.addItemsToPool(specialLootPool, pool);
|
2023-03-03 15:23:46 +00:00
|
|
|
break;
|
|
|
|
case "pockets":
|
2024-02-21 17:36:27 +00:00
|
|
|
this.addItemsToPool(pocketLootPool, pool);
|
2023-03-03 15:23:46 +00:00
|
|
|
break;
|
|
|
|
case "tacticalvest":
|
2024-02-21 17:36:27 +00:00
|
|
|
this.addItemsToPool(vestLootPool, pool);
|
2023-03-03 15:23:46 +00:00
|
|
|
break;
|
|
|
|
case "securedcontainer":
|
2024-02-21 17:36:27 +00:00
|
|
|
this.addItemsToPool(secureLootTPool, pool);
|
|
|
|
break;
|
|
|
|
case "backpack":
|
|
|
|
this.addItemsToPool(backpackLootPool, pool);
|
2023-03-03 15:23:46 +00:00
|
|
|
break;
|
|
|
|
default:
|
2024-02-21 17:36:27 +00:00
|
|
|
this.logger.warning(`How did you get here ${slot}`);
|
2023-03-03 15:23:46 +00:00
|
|
|
}
|
2023-11-13 11:13:25 -05:00
|
|
|
|
2024-02-21 17:36:27 +00:00
|
|
|
// Add all items (if any) to combined pool (excluding secure)
|
|
|
|
if (Object.keys(pool).length > 0 && slot.toLowerCase() !== "securedcontainer")
|
|
|
|
{
|
|
|
|
this.addItemsToPool(combinedLootPool, pool);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assign whitelisted special items to bot if any exist
|
|
|
|
const specialLootItems: Record<string, number> =
|
|
|
|
(Object.keys(botJsonTemplate.generation.items.specialItems.whitelist)?.length > 0)
|
|
|
|
? botJsonTemplate.generation.items.specialItems.whitelist
|
|
|
|
: {};
|
|
|
|
|
|
|
|
// no whitelist, find and assign from combined item pool
|
|
|
|
if (Object.keys(specialLootItems).length === 0)
|
|
|
|
{
|
|
|
|
for (const [tpl, weight] of Object.entries(specialLootPool))
|
|
|
|
{
|
|
|
|
const itemTemplate = this.itemHelper.getItem(tpl)[1];
|
|
|
|
if (!(this.isBulletOrGrenade(itemTemplate._props) || this.isMagazine(itemTemplate._props)))
|
|
|
|
{
|
|
|
|
specialLootItems[tpl] = weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assign whitelisted healing items to bot if any exist
|
|
|
|
const healingItems: Record<string, number> =
|
|
|
|
(Object.keys(botJsonTemplate.generation.items.healing.whitelist)?.length > 0)
|
|
|
|
? botJsonTemplate.generation.items.healing.whitelist
|
|
|
|
: {};
|
|
|
|
|
|
|
|
// No whitelist, find and assign from combined item pool
|
|
|
|
if (Object.keys(healingItems).length === 0)
|
|
|
|
{
|
|
|
|
for (const [tpl, weight] of Object.entries(combinedLootPool))
|
|
|
|
{
|
|
|
|
const itemTemplate = this.itemHelper.getItem(tpl)[1];
|
|
|
|
if (
|
|
|
|
this.isMedicalItem(itemTemplate._props)
|
|
|
|
&& itemTemplate._parent !== BaseClasses.STIMULATOR
|
|
|
|
&& itemTemplate._parent !== BaseClasses.DRUGS
|
|
|
|
)
|
|
|
|
{
|
|
|
|
healingItems[tpl] = weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assign whitelisted drugs to bot if any exist
|
|
|
|
const drugItems: Record<string, number> =
|
|
|
|
(Object.keys(botJsonTemplate.generation.items.drugs.whitelist)?.length > 0)
|
|
|
|
? botJsonTemplate.generation.items.drugs.whitelist
|
|
|
|
: {};
|
|
|
|
|
|
|
|
// no whitelist, find and assign from combined item pool
|
|
|
|
if (Object.keys(drugItems).length === 0)
|
|
|
|
{
|
|
|
|
for (const [tpl, weight] of Object.entries(combinedLootPool))
|
2023-03-03 15:23:46 +00:00
|
|
|
{
|
2024-02-21 17:36:27 +00:00
|
|
|
const itemTemplate = this.itemHelper.getItem(tpl)[1];
|
|
|
|
if (this.isMedicalItem(itemTemplate._props) && itemTemplate._parent === BaseClasses.DRUGS)
|
|
|
|
{
|
|
|
|
drugItems[tpl] = weight;
|
|
|
|
}
|
2023-03-03 15:23:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-27 23:44:23 +00:00
|
|
|
// Assign whitelisted stims to bot if any exist
|
2024-02-21 17:36:27 +00:00
|
|
|
const stimItems: Record<string, number> =
|
|
|
|
(Object.keys(botJsonTemplate.generation.items.stims.whitelist)?.length > 0)
|
|
|
|
? botJsonTemplate.generation.items.stims.whitelist
|
|
|
|
: {};
|
|
|
|
|
|
|
|
// No whitelist, find and assign from combined item pool
|
|
|
|
if (Object.keys(stimItems).length === 0)
|
|
|
|
{
|
|
|
|
for (const [tpl, weight] of Object.entries(combinedLootPool))
|
|
|
|
{
|
|
|
|
const itemTemplate = this.itemHelper.getItem(tpl)[1];
|
|
|
|
if (this.isMedicalItem(itemTemplate._props) && itemTemplate._parent === BaseClasses.STIMULATOR)
|
|
|
|
{
|
|
|
|
stimItems[tpl] = weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-27 23:44:23 +00:00
|
|
|
// Assign whitelisted grenades to bot if any exist
|
2024-02-21 17:36:27 +00:00
|
|
|
const grenadeItems: Record<string, number> =
|
|
|
|
(Object.keys(botJsonTemplate.generation.items.grenades.whitelist)?.length > 0)
|
|
|
|
? botJsonTemplate.generation.items.grenades.whitelist
|
|
|
|
: {};
|
|
|
|
|
|
|
|
// no whitelist, find and assign from combined item pool
|
|
|
|
if (Object.keys(grenadeItems).length === 0)
|
|
|
|
{
|
|
|
|
for (const [tpl, weight] of Object.entries(combinedLootPool))
|
|
|
|
{
|
|
|
|
const itemTemplate = this.itemHelper.getItem(tpl)[1];
|
|
|
|
if (this.isGrenade(itemTemplate._props))
|
|
|
|
{
|
|
|
|
grenadeItems[tpl] = weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get backpack loot (excluding magazines, bullets, grenades and healing items)
|
|
|
|
const filteredBackpackItems = {};
|
|
|
|
for (const itemKey of Object.keys(backpackLootPool))
|
|
|
|
{
|
|
|
|
const itemResult = this.itemHelper.getItem(itemKey);
|
|
|
|
if (!itemResult[0])
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const itemTemplate = itemResult[1];
|
|
|
|
if (
|
2024-02-27 23:44:23 +00:00
|
|
|
this.isBulletOrGrenade(itemTemplate._props)
|
|
|
|
|| this.isMagazine(itemTemplate._props)
|
|
|
|
|| this.isMedicalItem(itemTemplate._props)
|
|
|
|
|| this.isGrenade(itemTemplate._props)
|
2024-02-21 17:36:27 +00:00
|
|
|
)
|
|
|
|
{
|
2024-02-27 23:44:23 +00:00
|
|
|
// Is type we dont want as backpack loot, skip
|
|
|
|
continue;
|
2024-02-21 17:36:27 +00:00
|
|
|
}
|
2024-02-27 23:44:23 +00:00
|
|
|
|
|
|
|
filteredBackpackItems[itemKey] = backpackLootPool[itemKey];
|
2024-02-21 17:36:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get pocket loot (excluding magazines, bullets, grenades, medical and healing items)
|
|
|
|
const filteredPocketItems = {};
|
|
|
|
for (const itemKey of Object.keys(pocketLootPool))
|
|
|
|
{
|
|
|
|
const itemResult = this.itemHelper.getItem(itemKey);
|
|
|
|
if (!itemResult[0])
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const itemTemplate = itemResult[1];
|
|
|
|
if (
|
2024-02-27 23:44:23 +00:00
|
|
|
this.isBulletOrGrenade(itemTemplate._props)
|
|
|
|
|| this.isMagazine(itemTemplate._props)
|
|
|
|
|| this.isMedicalItem(itemTemplate._props)
|
|
|
|
|| this.isGrenade(itemTemplate._props)
|
|
|
|
|| !("Height" in itemTemplate._props) // lacks height
|
|
|
|
|| !("Width" in itemTemplate._props) // lacks width
|
2024-02-21 17:36:27 +00:00
|
|
|
)
|
|
|
|
{
|
2024-02-27 23:44:23 +00:00
|
|
|
continue;
|
2024-02-21 17:36:27 +00:00
|
|
|
}
|
2024-02-27 23:44:23 +00:00
|
|
|
|
|
|
|
filteredPocketItems[itemKey] = pocketLootPool[itemKey];
|
2024-02-21 17:36:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get vest loot (excluding magazines, bullets, grenades, medical and healing items)
|
|
|
|
const filteredVestItems = {};
|
|
|
|
for (const itemKey of Object.keys(vestLootPool))
|
|
|
|
{
|
|
|
|
const itemResult = this.itemHelper.getItem(itemKey);
|
|
|
|
if (!itemResult[0])
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const itemTemplate = itemResult[1];
|
|
|
|
if (
|
2024-02-27 23:44:23 +00:00
|
|
|
this.isBulletOrGrenade(itemTemplate._props)
|
|
|
|
|| this.isMagazine(itemTemplate._props)
|
|
|
|
|| this.isMedicalItem(itemTemplate._props)
|
|
|
|
|| this.isGrenade(itemTemplate._props)
|
2024-02-21 17:36:27 +00:00
|
|
|
)
|
|
|
|
{
|
2024-02-27 23:44:23 +00:00
|
|
|
continue;
|
2024-02-21 17:36:27 +00:00
|
|
|
}
|
2024-02-27 23:44:23 +00:00
|
|
|
|
|
|
|
filteredVestItems[itemKey] = vestLootPool[itemKey];
|
2024-02-21 17:36:27 +00:00
|
|
|
}
|
|
|
|
|
2023-03-03 15:23:46 +00:00
|
|
|
this.lootCache[botRole].healingItems = healingItems;
|
|
|
|
this.lootCache[botRole].drugItems = drugItems;
|
|
|
|
this.lootCache[botRole].stimItems = stimItems;
|
|
|
|
this.lootCache[botRole].grenadeItems = grenadeItems;
|
|
|
|
|
|
|
|
this.lootCache[botRole].specialItems = specialLootItems;
|
2024-02-21 17:36:27 +00:00
|
|
|
this.lootCache[botRole].backpackLoot = filteredBackpackItems;
|
|
|
|
this.lootCache[botRole].pocketLoot = filteredPocketItems;
|
|
|
|
this.lootCache[botRole].vestLoot = filteredVestItems;
|
|
|
|
this.lootCache[botRole].secureLoot = secureLootTPool;
|
2023-03-03 15:23:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add unique items into combined pool
|
2024-02-21 17:36:27 +00:00
|
|
|
* @param poolToAddTo Pool of items to add to
|
2023-03-03 15:23:46 +00:00
|
|
|
* @param itemsToAdd items to add to combined pool if unique
|
|
|
|
*/
|
2024-02-21 17:36:27 +00:00
|
|
|
protected addUniqueItemsToPool(poolToAddTo: ITemplateItem[], itemsToAdd: ITemplateItem[]): void
|
2023-03-03 15:23:46 +00:00
|
|
|
{
|
2024-02-21 17:36:27 +00:00
|
|
|
if (poolToAddTo.length === 0)
|
2023-03-03 15:23:46 +00:00
|
|
|
{
|
2024-02-21 17:36:27 +00:00
|
|
|
poolToAddTo.push(...itemsToAdd);
|
2023-03-03 15:23:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-02-21 17:36:27 +00:00
|
|
|
const mergedItemPools = [...poolToAddTo, ...itemsToAdd];
|
2023-03-03 15:23:46 +00:00
|
|
|
|
|
|
|
// Save only unique array values
|
2023-11-13 11:13:25 -05:00
|
|
|
const uniqueResults = [...new Set([].concat(...mergedItemPools))];
|
2024-02-21 17:36:27 +00:00
|
|
|
poolToAddTo.splice(0, poolToAddTo.length);
|
|
|
|
poolToAddTo.push(...uniqueResults);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected addItemsToPool(poolToAddTo: Record<string, number>, poolOfItemsToAdd: Record<string, number>): void
|
|
|
|
{
|
|
|
|
for (const tpl in poolOfItemsToAdd)
|
|
|
|
{
|
|
|
|
// Skip adding items that already exist
|
|
|
|
if (poolToAddTo[tpl])
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
poolToAddTo[tpl] = poolOfItemsToAdd[tpl];
|
|
|
|
}
|
2023-03-03 15:23:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Ammo/grenades have this property
|
2023-11-13 11:13:25 -05:00
|
|
|
* @param props
|
|
|
|
* @returns
|
2023-03-03 15:23:46 +00:00
|
|
|
*/
|
|
|
|
protected isBulletOrGrenade(props: Props): boolean
|
|
|
|
{
|
|
|
|
return ("ammoType" in props);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal and external magazine have this property
|
2023-11-13 11:13:25 -05:00
|
|
|
* @param props
|
|
|
|
* @returns
|
2023-03-03 15:23:46 +00:00
|
|
|
*/
|
|
|
|
protected isMagazine(props: Props): boolean
|
|
|
|
{
|
|
|
|
return ("ReloadMagType" in props);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Medical use items (e.g. morphine/lip balm/grizzly)
|
2023-11-13 11:13:25 -05:00
|
|
|
* @param props
|
|
|
|
* @returns
|
2023-03-03 15:23:46 +00:00
|
|
|
*/
|
|
|
|
protected isMedicalItem(props: Props): boolean
|
|
|
|
{
|
|
|
|
return ("medUseTime" in props);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Grenades have this property (e.g. smoke/frag/flash grenades)
|
2023-11-13 11:13:25 -05:00
|
|
|
* @param props
|
|
|
|
* @returns
|
2023-03-03 15:23:46 +00:00
|
|
|
*/
|
|
|
|
protected isGrenade(props: Props): boolean
|
|
|
|
{
|
|
|
|
return ("ThrowType" in props);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if a bot type exists inside the loot cache
|
|
|
|
* @param botRole role to check for
|
|
|
|
* @returns true if they exist
|
|
|
|
*/
|
|
|
|
protected botRoleExistsInCache(botRole: string): boolean
|
|
|
|
{
|
|
|
|
return !!this.lootCache[botRole];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If lootcache is null, init with empty property arrays
|
|
|
|
* @param botRole Bot role to hydrate
|
|
|
|
*/
|
|
|
|
protected initCacheForBotRole(botRole: string): void
|
|
|
|
{
|
|
|
|
this.lootCache[botRole] = {
|
2024-02-21 17:36:27 +00:00
|
|
|
backpackLoot: {},
|
|
|
|
pocketLoot: {},
|
|
|
|
vestLoot: {},
|
|
|
|
secureLoot: {},
|
|
|
|
combinedPoolLoot: {},
|
|
|
|
|
|
|
|
specialItems: {},
|
|
|
|
grenadeItems: {},
|
|
|
|
drugItems: {},
|
|
|
|
healingItems: {},
|
|
|
|
stimItems: {},
|
2023-03-03 15:23:46 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compares two item prices by their flea (or handbook if that doesnt exist) price
|
|
|
|
* -1 when a < b
|
|
|
|
* 0 when a === b
|
|
|
|
* 1 when a > b
|
2023-11-13 11:13:25 -05:00
|
|
|
* @param itemAPrice
|
|
|
|
* @param itemBPrice
|
|
|
|
* @returns
|
2023-03-03 15:23:46 +00:00
|
|
|
*/
|
|
|
|
protected compareByValue(itemAPrice: number, itemBPrice: number): number
|
|
|
|
{
|
|
|
|
// If item A has no price, it should be moved to the back when sorting
|
|
|
|
if (!itemAPrice)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!itemBPrice)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (itemAPrice < itemBPrice)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (itemAPrice > itemBPrice)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2023-11-13 11:13:25 -05:00
|
|
|
}
|