import { inject, injectable } from "tsyringe"; import { ItemHelper } from "../helpers/ItemHelper"; import { Item } from "../models/eft/common/tables/IItem"; import { ITemplateItem } from "../models/eft/common/tables/ITemplateItem"; import { BaseClasses } from "../models/enums/BaseClasses"; import { ConfigTypes } from "../models/enums/ConfigTypes"; import { IBotConfig } from "../models/spt/config/IBotConfig"; import { ILogger } from "../models/spt/utils/ILogger"; import { ConfigServer } from "../servers/ConfigServer"; export class BotModLimits { scope: ItemCount; scopeMax: number; scopeBaseTypes: string[]; flashlightLaser: ItemCount; flashlightLaserMax: number; flashlgihtLaserBaseTypes: string[]; } export class ItemCount { count: number; } @injectable() export class BotWeaponModLimitService { protected botConfig: IBotConfig; constructor( @inject("WinstonLogger") protected logger: ILogger, @inject("ConfigServer") protected configServer: ConfigServer, @inject("ItemHelper") protected itemHelper: ItemHelper ) { this.botConfig = this.configServer.getConfig(ConfigTypes.BOT); } /** * Initalise mod limits to be used when generating a weapon * @param botRole "assault", "bossTagilla" or "pmc" * @returns BotModLimits object */ public getWeaponModLimits(botRole: string): BotModLimits { return { scope: {count: 0}, scopeMax: this.botConfig.equipment[botRole]?.weaponModLimits?.scopeLimit, scopeBaseTypes: [BaseClasses.OPTIC_SCOPE, BaseClasses.ASSAULT_SCOPE, BaseClasses.COLLIMATOR, BaseClasses.COMPACT_COLLIMATOR, BaseClasses.SPECIAL_SCOPE], flashlightLaser: {count: 0}, flashlightLaserMax: this.botConfig.equipment[botRole]?.weaponModLimits?.lightLaserLimit, flashlgihtLaserBaseTypes: [BaseClasses.TACTICAL_COMBO, BaseClasses.FLASHLIGHT, BaseClasses.PORTABLE_RANGE_FINDER] }; } /** * Check if weapon mod item is on limited list + has surpassed the limit set for it * Exception: Always allow ncstar backup mount * Exception: Always allow scopes with a scope for a parent * Exception: Always disallow mounts that hold only scopes once scope limit reached * Exception: Always disallow mounts that hold only flashlights once flashlight limit reached * @param botRole role the bot has e.g. assault * @param modTemplate mods template data * @param modLimits limits set for weapon being generated for this bot * @param modsParent The parent of the mod to be checked * @returns true if over item limit */ public weaponModHasReachedLimit(botRole: string, modTemplate: ITemplateItem, modLimits: BotModLimits, modsParent: ITemplateItem, weapon: Item[]): boolean { // If mod or mods parent is the NcSTAR MPR45 Backup mount, allow it as it looks cool const ncSTARTpl = "5649a2464bdc2d91118b45a8"; if (modsParent._id === ncSTARTpl || modTemplate._id === ncSTARTpl) { // If weapon already has a longer ranged scope on it, allow ncstar to be spawned if (weapon.some(x => this.itemHelper.isOfBaseclasses(x._tpl, [BaseClasses.ASSAULT_SCOPE, BaseClasses.OPTIC_SCOPE, BaseClasses.SPECIAL_SCOPE]))) { return false; } return true; } // mods parent is scope and mod is scope, allow it (adds those mini-sights to the tops of sights) const modIsScope = this.itemHelper.isOfBaseclasses(modTemplate._id, modLimits.scopeBaseTypes); if (this.itemHelper.isOfBaseclasses(modsParent._id, modLimits.scopeBaseTypes) && modIsScope) { return false; } // If mod is a scope, return if limit reached if (modIsScope) { return this.weaponModLimitReached(modTemplate._id, modLimits.scope, modLimits.scopeMax, botRole); } // Mod is a mount that can hold only scopes and limit is reached (dont want to add empty mounts if limit is reached) if (this.itemHelper.isOfBaseclass(modTemplate._id, BaseClasses.MOUNT) && modTemplate._props.Slots.some(x => x._name === "mod_scope") && modTemplate._props.Slots.length === 1 && modLimits.scope.count >= modLimits.scopeMax) { return true; } // If mod is a light/laser, return if limit reached const modIsLightOrLaser = this.itemHelper.isOfBaseclasses(modTemplate._id, modLimits.flashlgihtLaserBaseTypes); if (modIsLightOrLaser) { return this.weaponModLimitReached(modTemplate._id, modLimits.flashlightLaser, modLimits.flashlightLaserMax, botRole); } // Mod is a mount that can hold only flashlights ad limit is reached (dont want to add empty mounts if limit is reached) if (this.itemHelper.isOfBaseclass(modTemplate._id, BaseClasses.MOUNT) && modTemplate._props.Slots.some(x => x._name === "mod_flashlight") && modTemplate._props.Slots.length === 1 && modLimits.scope.count >= modLimits.scopeMax) { return true; } return false; } /** * Check if the specific item type on the weapon has reached the set limit * @param modTpl log mod tpl if over type limit * @param currentCount current number of this item on gun * @param maxLimit mod limit allowed * @param botRole role of bot we're checking weapon of * @returns true if limit reached */ // eslint-disable-next-line @typescript-eslint/no-unused-vars protected weaponModLimitReached(modTpl: string, currentCount: { count: number; }, maxLimit: number, botRole: string): boolean { // No value or 0 if (!maxLimit) { return false; } // Has mod limit for bot type been reached if (currentCount.count >= maxLimit) { //this.logger.debug(`[${botRole}] scope limit reached! tried to add ${modTpl} but scope count is ${currentCount.count}`); return true; } // Increment scope count currentCount.count++; return false; } }