0
0
mirror of https://github.com/sp-tarkov/server.git synced 2025-02-13 09:50:43 -05:00
server/project/src/services/BotEquipmentModPoolService.ts

193 lines
6.9 KiB
TypeScript
Raw Normal View History

import { ItemHelper } from "@spt/helpers/ItemHelper";
import { Mods } from "@spt/models/eft/common/tables/IBotType";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import { BaseClasses } from "@spt/models/enums/BaseClasses";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { DatabaseService } from "@spt/services/DatabaseService";
import { LocalisationService } from "@spt/services/LocalisationService";
import { VFS } from "@spt/utils/VFS";
import { inject, injectable } from "tsyringe";
2023-03-03 15:23:46 +00:00
/** Store a mapping between weapons, their slots and the items that fit those slots */
@injectable()
export class BotEquipmentModPoolService {
2023-03-03 15:23:46 +00:00
protected botConfig: IBotConfig;
protected weaponModPool: Mods = {};
protected gearModPool: Mods = {};
protected weaponPoolGenerated = false;
protected armorPoolGenerated = false;
constructor(
@inject("PrimaryLogger") protected logger: ILogger,
2023-03-03 15:23:46 +00:00
@inject("VFS") protected vfs: VFS,
@inject("ItemHelper") protected itemHelper: ItemHelper,
@inject("DatabaseService") protected databaseService: DatabaseService,
2023-07-19 11:00:34 +01:00
@inject("LocalisationService") protected localisationService: LocalisationService,
2023-11-15 20:35:05 -05:00
@inject("ConfigServer") protected configServer: ConfigServer,
) {
2023-03-03 15:23:46 +00:00
this.botConfig = this.configServer.getConfig(ConfigTypes.BOT);
}
/**
* Store dictionary of mods for each item passed in
* @param items items to find related mods and store in modPool
*/
protected generatePool(items: ITemplateItem[], poolType: string): void {
if (!items) {
2024-05-21 12:40:16 +01:00
this.logger.error(this.localisationService.getText("bot-unable_to_generate_item_pool_no_items", poolType));
return;
}
2023-05-15 17:22:54 +01:00
// Get weapon or gear pool
2023-11-15 20:35:05 -05:00
const pool = poolType === "weapon" ? this.weaponModPool : this.gearModPool;
for (const item of items) {
if (!item._props) {
2023-11-15 20:35:05 -05:00
this.logger.error(
this.localisationService.getText("bot-item_missing_props_property", {
itemTpl: item._id,
name: item._name,
}),
);
continue;
2023-03-03 15:23:46 +00:00
}
// skip item witout slots
if (!item._props.Slots || item._props.Slots.length === 0) {
2023-03-03 15:23:46 +00:00
continue;
}
// Add tpl to pool when missing
if (!pool[item._id]) {
2023-03-03 15:23:46 +00:00
pool[item._id] = {};
}
// No slots, skip
if (!item._props.Slots) {
return;
}
for (const slot of item._props.Slots) {
2023-03-03 15:23:46 +00:00
const itemsThatFit = slot._props.filters[0].Filter;
for (const itemToAdd of itemsThatFit) {
if (!pool[item._id][slot._name]) {
2023-03-03 15:23:46 +00:00
pool[item._id][slot._name] = [];
}
2023-11-15 20:35:05 -05:00
2023-03-03 15:23:46 +00:00
// only add item to pool if it doesnt already exist
if (!pool[item._id][slot._name].some((x) => x === itemToAdd)) {
2023-03-03 15:23:46 +00:00
pool[item._id][slot._name].push(itemToAdd);
// Check item added into array for slots, need to iterate over those
const subItemDetails = this.itemHelper.getItem(itemToAdd)[1];
const hasSubItemsToAdd = subItemDetails?._props?.Slots?.length ?? 0 > 0;
if (hasSubItemsToAdd && !pool[subItemDetails._id]) {
// Recursive call
this.generatePool([subItemDetails], poolType);
}
2023-11-15 20:35:05 -05:00
}
2023-03-03 15:23:46 +00:00
}
}
}
}
/**
* Empty the mod pool
*/
public resetPool(): void {
2023-03-03 15:23:46 +00:00
this.weaponModPool = {};
}
/**
* Get array of compatible mods for an items mod slot (generate pool if it doesnt exist already)
* @param itemTpl item to look up
* @param slotName slot to get compatible mods for
* @returns tpls that fit the slot
*/
public getCompatibleModsForWeaponSlot(itemTpl: string, slotName: string): string[] {
if (!this.weaponPoolGenerated) {
2023-03-03 15:23:46 +00:00
// Get every weapon in db and generate mod pool
this.generateWeaponPool();
}
return this.weaponModPool[itemTpl][slotName];
}
/**
* Get array of compatible mods for an items mod slot (generate pool if it doesnt exist already)
* @param itemTpl item to look up
* @param slotName slot to get compatible mods for
* @returns tpls that fit the slot
*/
public getCompatibleModsFoGearSlot(itemTpl: string, slotName: string): string[] {
if (!this.armorPoolGenerated) {
2023-03-03 15:23:46 +00:00
this.generateGearPool();
}
return this.gearModPool[itemTpl][slotName];
}
/**
* Get mods for a piece of gear by its tpl
* @param itemTpl items tpl to look up mods for
* @returns Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value
*/
public getModsForGearSlot(itemTpl: string): Record<string, string[]> {
if (!this.armorPoolGenerated) {
2023-03-03 15:23:46 +00:00
this.generateGearPool();
}
return this.gearModPool[itemTpl];
}
/**
* Get mods for a weapon by its tpl
* @param itemTpl Weapons tpl to look up mods for
* @returns Dictionary of mods (keys are mod slot names) with array of compatible mod tpls as value
*/
public getModsForWeaponSlot(itemTpl: string): Record<string, string[]> {
if (!this.weaponPoolGenerated) {
2023-03-03 15:23:46 +00:00
this.generateWeaponPool();
}
return this.weaponModPool[itemTpl];
}
/**
* Create weapon mod pool and set generated flag to true
*/
protected generateWeaponPool(): void {
const weapons = Object.values(this.databaseService.getItems()).filter(
(item) => item._type === "Item" && this.itemHelper.isOfBaseclass(item._id, BaseClasses.WEAPON),
2023-11-15 20:35:05 -05:00
);
2023-03-03 15:23:46 +00:00
this.generatePool(weapons, "weapon");
// Flag pool as being complete
this.weaponPoolGenerated = true;
}
/**
* Create gear mod pool and set generated flag to true
*/
protected generateGearPool(): void {
const gear = Object.values(this.databaseService.getItems()).filter(
(item) =>
item._type === "Item" &&
this.itemHelper.isOfBaseclasses(item._id, [
BaseClasses.ARMORED_EQUIPMENT,
BaseClasses.VEST,
BaseClasses.ARMOR,
BaseClasses.HEADWEAR,
]),
2023-11-15 20:35:05 -05:00
);
2023-03-03 15:23:46 +00:00
this.generatePool(gear, "gear");
// Flag pool as being complete
this.armorPoolGenerated = true;
}
2023-11-15 20:35:05 -05:00
}