diff --git a/project/src/helpers/AssortHelper.ts b/project/src/helpers/AssortHelper.ts index 43ac41bb..04148c2c 100644 --- a/project/src/helpers/AssortHelper.ts +++ b/project/src/helpers/AssortHelper.ts @@ -12,25 +12,30 @@ import { LocalisationService } from "@spt-aki/services/LocalisationService"; @injectable() export class AssortHelper { - constructor( @inject("WinstonLogger") protected logger: ILogger, @inject("ItemHelper") protected itemHelper: ItemHelper, @inject("DatabaseServer") protected databaseServer: DatabaseServer, @inject("LocalisationService") protected localisationService: LocalisationService, - @inject("QuestHelper") protected questHelper: QuestHelper + @inject("QuestHelper") protected questHelper: QuestHelper, ) - { } + {} /** - * Remove assorts from a trader that have not been unlocked yet (via player completing corrisponding quest) + * Remove assorts from a trader that have not been unlocked yet (via player completing corresponding quest) * @param pmcProfile Player profile * @param traderId Traders id the assort belongs to * @param traderAssorts All assort items from same trader * @param mergedQuestAssorts Dict of quest assort to quest id unlocks for all traders (key = started/failed/complete) * @returns Assort items minus locked quest assorts */ - public stripLockedQuestAssort(pmcProfile: IPmcData, traderId: string, traderAssorts: ITraderAssort, mergedQuestAssorts: Record>, flea = false): ITraderAssort + public stripLockedQuestAssort( + pmcProfile: IPmcData, + traderId: string, + traderAssorts: ITraderAssort, + mergedQuestAssorts: Record>, + flea = false, + ): ITraderAssort { // Trader assort does not always contain loyal_level_items if (!traderAssorts.loyal_level_items) @@ -67,20 +72,26 @@ export class AssortHelper * @param assortId Assort to look for linked quest id * @returns quest id + array of quest status the assort should show for */ - protected getQuestIdAndStatusThatShowAssort(mergedQuestAssorts: Record>, assortId: string): { questId: string; status: QuestStatus[]; } + protected getQuestIdAndStatusThatShowAssort( + mergedQuestAssorts: Record>, + assortId: string, + ): {questId: string; status: QuestStatus[];} { if (assortId in mergedQuestAssorts.started) { // Assort unlocked by starting quest, assort is visible to player when : started or ready to hand in + handed in - return { questId: mergedQuestAssorts.started[assortId], status: [QuestStatus.Started, QuestStatus.AvailableForFinish, QuestStatus.Success]}; + return { + questId: mergedQuestAssorts.started[assortId], + status: [QuestStatus.Started, QuestStatus.AvailableForFinish, QuestStatus.Success], + }; } else if (assortId in mergedQuestAssorts.success) { - return { questId: mergedQuestAssorts.success[assortId], status: [QuestStatus.Success]}; + return {questId: mergedQuestAssorts.success[assortId], status: [QuestStatus.Success]}; } else if (assortId in mergedQuestAssorts.fail) { - return { questId: mergedQuestAssorts.fail[assortId], status: [QuestStatus.Fail]}; + return {questId: mergedQuestAssorts.fail[assortId], status: [QuestStatus.Fail]}; } return undefined; @@ -152,4 +163,4 @@ export class AssortHelper return assort; } -} \ No newline at end of file +} diff --git a/project/src/helpers/BotDifficultyHelper.ts b/project/src/helpers/BotDifficultyHelper.ts index 83688c7e..59c4a9bb 100644 --- a/project/src/helpers/BotDifficultyHelper.ts +++ b/project/src/helpers/BotDifficultyHelper.ts @@ -23,22 +23,27 @@ export class BotDifficultyHelper @inject("RandomUtil") protected randomUtil: RandomUtil, @inject("LocalisationService") protected localisationService: LocalisationService, @inject("BotHelper") protected botHelper: BotHelper, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.pmcConfig = this.configServer.getConfig(ConfigTypes.PMC); } - public getPmcDifficultySettings(pmcType: "bear"|"usec", difficulty: string, usecType: string, bearType: string): Difficulty + public getPmcDifficultySettings( + pmcType: "bear" | "usec", + difficulty: string, + usecType: string, + bearType: string, + ): Difficulty { const difficultySettings = this.getDifficultySettings(pmcType, difficulty); - const friendlyType = pmcType === "bear" - ? bearType - : usecType; - const enemyType = pmcType === "bear" - ? usecType - : bearType; + const friendlyType = pmcType === "bear" ? + bearType : + usecType; + const enemyType = pmcType === "bear" ? + usecType : + bearType; this.botHelper.addBotToEnemyList(difficultySettings, this.pmcConfig.enemyTypes, friendlyType); // Add generic bot types to enemy list this.botHelper.addBotToEnemyList(difficultySettings, [enemyType, friendlyType], ""); // add same/opposite side to enemy list @@ -61,14 +66,23 @@ export class BotDifficultyHelper { // get fallback this.logger.warning(this.localisationService.getText("bot-unable_to_get_bot_fallback_to_assault", type)); - this.databaseServer.getTables().bots.types[type] = this.jsonUtil.clone(this.databaseServer.getTables().bots.types.assault); + this.databaseServer.getTables().bots.types[type] = this.jsonUtil.clone( + this.databaseServer.getTables().bots.types.assault, + ); } const difficultySettings = this.botHelper.getBotTemplate(type).difficulty[difficulty]; if (!difficultySettings) { - this.logger.warning(this.localisationService.getText("bot-unable_to_get_bot_difficulty_fallback_to_assault", {botType: type, difficulty: difficulty})); - this.databaseServer.getTables().bots.types[type].difficulty[difficulty] = this.jsonUtil.clone(this.databaseServer.getTables().bots.types.assault.difficulty[difficulty]); + this.logger.warning( + this.localisationService.getText("bot-unable_to_get_bot_difficulty_fallback_to_assault", { + botType: type, + difficulty: difficulty, + }), + ); + this.databaseServer.getTables().bots.types[type].difficulty[difficulty] = this.jsonUtil.clone( + this.databaseServer.getTables().bots.types.assault.difficulty[difficulty], + ); } return this.jsonUtil.clone(difficultySettings); @@ -77,14 +91,14 @@ export class BotDifficultyHelper /** * Get difficulty settings for a PMC * @param type "usec" / "bear" - * @param difficulty what difficulty to retrieve + * @param difficulty what difficulty to retrieve * @returns Difficulty object */ protected getDifficultySettings(type: string, difficulty: string): Difficulty { - let difficultySetting = this.pmcConfig.difficulty.toLowerCase() === "asonline" - ? difficulty - : this.pmcConfig.difficulty.toLowerCase(); + let difficultySetting = this.pmcConfig.difficulty.toLowerCase() === "asonline" ? + difficulty : + this.pmcConfig.difficulty.toLowerCase(); difficultySetting = this.convertBotDifficultyDropdownToBotDifficulty(difficultySetting); @@ -117,4 +131,4 @@ export class BotDifficultyHelper { return this.randomUtil.getArrayValue(["easy", "normal", "hard", "impossible"]); } -} \ No newline at end of file +} diff --git a/project/src/helpers/BotGeneratorHelper.ts b/project/src/helpers/BotGeneratorHelper.ts index 21ae5ade..eab60729 100644 --- a/project/src/helpers/BotGeneratorHelper.ts +++ b/project/src/helpers/BotGeneratorHelper.ts @@ -19,7 +19,7 @@ import { JsonUtil } from "@spt-aki/utils/JsonUtil"; import { RandomUtil } from "@spt-aki/utils/RandomUtil"; @injectable() -export class BotGeneratorHelper +export class BotGeneratorHelper { protected botConfig: IBotConfig; protected pmcConfig: IPmcConfig; @@ -32,8 +32,8 @@ export class BotGeneratorHelper @inject("ItemHelper") protected itemHelper: ItemHelper, @inject("ApplicationContext") protected applicationContext: ApplicationContext, @inject("LocalisationService") protected localisationService: LocalisationService, - @inject("ConfigServer") protected configServer: ConfigServer - ) + @inject("ConfigServer") protected configServer: ConfigServer, + ) { this.botConfig = this.configServer.getConfig(ConfigTypes.BOT); this.pmcConfig = this.configServer.getConfig(ConfigTypes.PMC); @@ -46,93 +46,113 @@ export class BotGeneratorHelper * @param botRole Used by weapons to randomize the durability values. Null for non-equipped items * @returns Item Upd object with extra properties */ - public generateExtraPropertiesForItem(itemTemplate: ITemplateItem, botRole?: string): { upd?: Upd } + public generateExtraPropertiesForItem(itemTemplate: ITemplateItem, botRole?: string): {upd?: Upd;} { // Get raid settings, if no raid, default to day - const raidSettings = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue(); + const raidSettings = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue< + IGetRaidConfigurationRequestData + >(); const raidIsNight = raidSettings?.timeVariant === "PAST"; const itemProperties: Upd = {}; - if (itemTemplate._props.MaxDurability) + if (itemTemplate._props.MaxDurability) { - if (itemTemplate._props.weapClass) // Is weapon - { + if (itemTemplate._props.weapClass) + { // Is weapon itemProperties.Repairable = this.generateWeaponRepairableProperties(itemTemplate, botRole); } - else if (itemTemplate._props.armorClass) // Is armor - { + else if (itemTemplate._props.armorClass) + { // Is armor itemProperties.Repairable = this.generateArmorRepairableProperties(itemTemplate, botRole); } } - if (itemTemplate._props.HasHinge) + if (itemTemplate._props.HasHinge) { - itemProperties.Togglable = { On: true }; + itemProperties.Togglable = {On: true}; } - if (itemTemplate._props.Foldable) + if (itemTemplate._props.Foldable) { - itemProperties.Foldable = { Folded: false }; + itemProperties.Foldable = {Folded: false}; } - if (itemTemplate._props.weapFireType?.length) + if (itemTemplate._props.weapFireType?.length) { - if (itemTemplate._props.weapFireType.includes("fullauto")) + if (itemTemplate._props.weapFireType.includes("fullauto")) { - itemProperties.FireMode = { FireMode: "fullauto" }; + itemProperties.FireMode = {FireMode: "fullauto"}; } - else + else { - itemProperties.FireMode = { FireMode: this.randomUtil.getArrayValue(itemTemplate._props.weapFireType) }; + itemProperties.FireMode = {FireMode: this.randomUtil.getArrayValue(itemTemplate._props.weapFireType)}; } } - if (itemTemplate._props.MaxHpResource) + if (itemTemplate._props.MaxHpResource) { - itemProperties.MedKit = { HpResource: this.getRandomizedResourceValue(itemTemplate._props.MaxHpResource, this.botConfig.lootItemResourceRandomization[botRole]?.meds) }; + itemProperties.MedKit = { + HpResource: this.getRandomizedResourceValue( + itemTemplate._props.MaxHpResource, + this.botConfig.lootItemResourceRandomization[botRole]?.meds, + ), + }; } - if (itemTemplate._props.MaxResource && itemTemplate._props.foodUseTime) + if (itemTemplate._props.MaxResource && itemTemplate._props.foodUseTime) { - itemProperties.FoodDrink = { HpPercent: this.getRandomizedResourceValue(itemTemplate._props.MaxResource, this.botConfig.lootItemResourceRandomization[botRole]?.food) }; + itemProperties.FoodDrink = { + HpPercent: this.getRandomizedResourceValue( + itemTemplate._props.MaxResource, + this.botConfig.lootItemResourceRandomization[botRole]?.food, + ), + }; } if (itemTemplate._parent === BaseClasses.FLASHLIGHT) { // Get chance from botconfig for bot type - const lightLaserActiveChance = raidIsNight - ? this.getBotEquipmentSettingFromConfig(botRole, "lightIsActiveNightChancePercent", 50) - : this.getBotEquipmentSettingFromConfig(botRole, "lightIsActiveDayChancePercent", 25); - itemProperties.Light = { IsActive: (this.randomUtil.getChance100(lightLaserActiveChance)), SelectedMode: 0 }; + const lightLaserActiveChance = raidIsNight ? + this.getBotEquipmentSettingFromConfig(botRole, "lightIsActiveNightChancePercent", 50) : + this.getBotEquipmentSettingFromConfig(botRole, "lightIsActiveDayChancePercent", 25); + itemProperties.Light = {IsActive: (this.randomUtil.getChance100(lightLaserActiveChance)), SelectedMode: 0}; } else if (itemTemplate._parent === BaseClasses.TACTICAL_COMBO) { // Get chance from botconfig for bot type, use 50% if no value found - const lightLaserActiveChance = this.getBotEquipmentSettingFromConfig(botRole, "laserIsActiveChancePercent", 50); - itemProperties.Light = { IsActive: (this.randomUtil.getChance100(lightLaserActiveChance)), SelectedMode: 0 }; + const lightLaserActiveChance = this.getBotEquipmentSettingFromConfig( + botRole, + "laserIsActiveChancePercent", + 50, + ); + itemProperties.Light = {IsActive: (this.randomUtil.getChance100(lightLaserActiveChance)), SelectedMode: 0}; } - if (itemTemplate._parent === BaseClasses.NIGHTVISION) + if (itemTemplate._parent === BaseClasses.NIGHTVISION) { // Get chance from botconfig for bot type - const nvgActiveChance = raidIsNight - ? this.getBotEquipmentSettingFromConfig(botRole, "nvgIsActiveChanceNightPercent", 90) - : this.getBotEquipmentSettingFromConfig(botRole, "nvgIsActiveChanceDayPercent", 15); - itemProperties.Togglable = { On: (this.randomUtil.getChance100(nvgActiveChance)) }; + const nvgActiveChance = raidIsNight ? + this.getBotEquipmentSettingFromConfig(botRole, "nvgIsActiveChanceNightPercent", 90) : + this.getBotEquipmentSettingFromConfig(botRole, "nvgIsActiveChanceDayPercent", 15); + itemProperties.Togglable = {On: (this.randomUtil.getChance100(nvgActiveChance))}; } // Togglable face shield - if (itemTemplate._props.HasHinge && itemTemplate._props.FaceShieldComponent) + if (itemTemplate._props.HasHinge && itemTemplate._props.FaceShieldComponent) { // Get chance from botconfig for bot type, use 75% if no value found - const faceShieldActiveChance = this.getBotEquipmentSettingFromConfig(botRole, "faceShieldIsActiveChancePercent", 75); - itemProperties.Togglable = { On: (this.randomUtil.getChance100(faceShieldActiveChance)) }; + const faceShieldActiveChance = this.getBotEquipmentSettingFromConfig( + botRole, + "faceShieldIsActiveChancePercent", + 75, + ); + itemProperties.Togglable = {On: (this.randomUtil.getChance100(faceShieldActiveChance))}; } - return Object.keys(itemProperties).length - ? { upd: itemProperties } - : {}; + return Object.keys(itemProperties).length ? + {upd: itemProperties} : + {}; } /** @@ -153,8 +173,10 @@ export class BotGeneratorHelper return maxResource; } - return this.randomUtil.getInt(this.randomUtil.getPercentOfValue(randomizationValues.resourcePercent, maxResource, 0), maxResource); - + return this.randomUtil.getInt( + this.randomUtil.getPercentOfValue(randomizationValues.resourcePercent, maxResource, 0), + maxResource, + ); } /** @@ -164,22 +186,38 @@ export class BotGeneratorHelper * @param defaultValue default value for the chance of activation if the botrole or bot equipment role is null * @returns Percent chance to be active */ - protected getBotEquipmentSettingFromConfig(botRole: string, setting: keyof EquipmentFilters, defaultValue: number): number + protected getBotEquipmentSettingFromConfig( + botRole: string, + setting: keyof EquipmentFilters, + defaultValue: number, + ): number { - if (!botRole) + if (!botRole) { return defaultValue; } const botEquipmentSettings = this.botConfig.equipment[this.getBotEquipmentRole(botRole)]; if (!botEquipmentSettings) { - this.logger.warning(this.localisationService.getText("bot-missing_equipment_settings", {botRole: botRole, setting: setting, defaultValue: defaultValue})); + this.logger.warning( + this.localisationService.getText("bot-missing_equipment_settings", { + botRole: botRole, + setting: setting, + defaultValue: defaultValue, + }), + ); return defaultValue; } - if (botEquipmentSettings[setting] === undefined || typeof botEquipmentSettings[setting] !== "number") + if (botEquipmentSettings[setting] === undefined || typeof botEquipmentSettings[setting] !== "number") { - this.logger.warning(this.localisationService.getText("bot-missing_equipment_settings_property", {botRole: botRole, setting: setting, defaultValue: defaultValue})); + this.logger.warning( + this.localisationService.getText("bot-missing_equipment_settings_property", { + botRole: botRole, + setting: setting, + defaultValue: defaultValue, + }), + ); return defaultValue; } @@ -193,14 +231,18 @@ export class BotGeneratorHelper * @param botRole type of bot being generated for * @returns Repairable object */ - protected generateWeaponRepairableProperties(itemTemplate: ITemplateItem, botRole: string): Repairable + protected generateWeaponRepairableProperties(itemTemplate: ITemplateItem, botRole: string): Repairable { const maxDurability = this.durabilityLimitsHelper.getRandomizedMaxWeaponDurability(itemTemplate, botRole); - const currentDurability = this.durabilityLimitsHelper.getRandomizedWeaponDurability(itemTemplate, botRole, maxDurability); + const currentDurability = this.durabilityLimitsHelper.getRandomizedWeaponDurability( + itemTemplate, + botRole, + maxDurability, + ); return { Durability: currentDurability, - MaxDurability: maxDurability + MaxDurability: maxDurability, }; } @@ -210,7 +252,7 @@ export class BotGeneratorHelper * @param botRole type of bot being generated for * @returns Repairable object */ - protected generateArmorRepairableProperties(itemTemplate: ITemplateItem, botRole: string): Repairable + protected generateArmorRepairableProperties(itemTemplate: ITemplateItem, botRole: string): Repairable { let maxDurability: number; let currentDurability: number; @@ -219,15 +261,19 @@ export class BotGeneratorHelper maxDurability = itemTemplate._props.MaxDurability; currentDurability = itemTemplate._props.MaxDurability; } - else + else { maxDurability = this.durabilityLimitsHelper.getRandomizedMaxArmorDurability(itemTemplate, botRole); - currentDurability = this.durabilityLimitsHelper.getRandomizedArmorDurability(itemTemplate, botRole, maxDurability); + currentDurability = this.durabilityLimitsHelper.getRandomizedArmorDurability( + itemTemplate, + botRole, + maxDurability, + ); } return { Durability: currentDurability, - MaxDurability: maxDurability + MaxDurability: maxDurability, }; } @@ -238,54 +284,81 @@ export class BotGeneratorHelper * @param equipmentSlot Slot the item will be placed into * @returns false if no incompatibilities, also has incompatibility reason */ - public isItemIncompatibleWithCurrentItems(items: Item[], tplToCheck: string, equipmentSlot: string): { incompatible: boolean, reason: string } + public isItemIncompatibleWithCurrentItems( + items: Item[], + tplToCheck: string, + equipmentSlot: string, + ): {incompatible: boolean; reason: string;} { // Skip slots that have no incompatibilities - if (["Scabbard", "Backpack", "SecureContainer", "Holster", "ArmBand"].includes(equipmentSlot)) + if (["Scabbard", "Backpack", "SecureContainer", "Holster", "ArmBand"].includes(equipmentSlot)) { - return { incompatible: false, reason: "" }; + return {incompatible: false, reason: ""}; } // TODO: Can probably be optimized to cache itemTemplates as items are added to inventory - const equippedItems = items.map(i => this.databaseServer.getTables().templates.items[i._tpl]); + const equippedItems = items.map((i) => this.databaseServer.getTables().templates.items[i._tpl]); const item = this.itemHelper.getItem(tplToCheck); const itemToCheck = item[1]; if (!item[0]) { - this.logger.warning(this.localisationService.getText("bot-invalid_item_compatibility_check", {itemTpl: tplToCheck, slot: equipmentSlot})); + this.logger.warning( + this.localisationService.getText("bot-invalid_item_compatibility_check", { + itemTpl: tplToCheck, + slot: equipmentSlot, + }), + ); } if (!itemToCheck._props) { - this.logger.warning(this.localisationService.getText("bot-compatibility_check_missing_props", {id: itemToCheck._id, name: itemToCheck._name, slot: equipmentSlot})); + this.logger.warning( + this.localisationService.getText("bot-compatibility_check_missing_props", { + id: itemToCheck._id, + name: itemToCheck._name, + slot: equipmentSlot, + }), + ); } // Does an equipped item have a property that blocks the desired item - check for prop "BlocksX" .e.g BlocksEarpiece / BlocksFaceCover - let blockingItem = equippedItems.find(x => x._props[`Blocks${equipmentSlot}`]); - if (blockingItem) + let blockingItem = equippedItems.find((x) => x._props[`Blocks${equipmentSlot}`]); + if (blockingItem) { - //this.logger.warning(`1 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._name} - ${equipmentSlot}`); - return { incompatible: true, reason: `${tplToCheck} ${itemToCheck._name} in slot: ${equipmentSlot} blocked by: ${blockingItem._id} ${blockingItem._name}` }; + // this.logger.warning(`1 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._name} - ${equipmentSlot}`); + return { + incompatible: true, + reason: + `${tplToCheck} ${itemToCheck._name} in slot: ${equipmentSlot} blocked by: ${blockingItem._id} ${blockingItem._name}`, + }; } // Check if any of the current inventory templates have the incoming item defined as incompatible - blockingItem = equippedItems.find(x => x._props.ConflictingItems?.includes(tplToCheck)); - if (blockingItem) + blockingItem = equippedItems.find((x) => x._props.ConflictingItems?.includes(tplToCheck)); + if (blockingItem) { - //this.logger.warning(`2 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._props.Name} - ${equipmentSlot}`); - return { incompatible: true, reason: `${tplToCheck} ${itemToCheck._name} in slot: ${equipmentSlot} blocked by: ${blockingItem._id} ${blockingItem._name}` }; + // this.logger.warning(`2 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._props.Name} - ${equipmentSlot}`); + return { + incompatible: true, + reason: + `${tplToCheck} ${itemToCheck._name} in slot: ${equipmentSlot} blocked by: ${blockingItem._id} ${blockingItem._name}`, + }; } // Check if the incoming item has any inventory items defined as incompatible - const blockingInventoryItem = items.find(x => itemToCheck._props.ConflictingItems?.includes(x._tpl)); - if (blockingInventoryItem) + const blockingInventoryItem = items.find((x) => itemToCheck._props.ConflictingItems?.includes(x._tpl)); + if (blockingInventoryItem) { - //this.logger.warning(`3 incompatibility found between - ${itemToEquip[1]._name} and ${blockingInventoryItem._tpl} - ${equipmentSlot}`) - return { incompatible: true, reason: `${tplToCheck} blocks existing item ${blockingInventoryItem._tpl} in slot ${blockingInventoryItem.slotId}` }; + // this.logger.warning(`3 incompatibility found between - ${itemToEquip[1]._name} and ${blockingInventoryItem._tpl} - ${equipmentSlot}`) + return { + incompatible: true, + reason: + `${tplToCheck} blocks existing item ${blockingInventoryItem._tpl} in slot ${blockingInventoryItem.slotId}`, + }; } - return { incompatible: false, reason: "" }; + return {incompatible: false, reason: ""}; } /** @@ -293,11 +366,13 @@ export class BotGeneratorHelper * @param botRole Role to convert * @returns Equipment role (e.g. pmc / assault / bossTagilla) */ - public getBotEquipmentRole(botRole: string): string + public getBotEquipmentRole(botRole: string): string { - return ([this.pmcConfig.usecType.toLowerCase(), this.pmcConfig.bearType.toLowerCase()].includes(botRole.toLowerCase())) - ? "pmc" - : botRole; + return ([this.pmcConfig.usecType.toLowerCase(), this.pmcConfig.bearType.toLowerCase()].includes( + botRole.toLowerCase(), + )) ? + "pmc" : + botRole; } } @@ -309,15 +384,15 @@ export class ExhaustableArray constructor( private itemPool: T[], private randomUtil: RandomUtil, - private jsonUtil: JsonUtil - ) + private jsonUtil: JsonUtil, + ) { this.pool = this.jsonUtil.clone(itemPool); } - public getRandomValue(): T + public getRandomValue(): T { - if (!this.pool?.length) + if (!this.pool?.length) { return null; } @@ -328,9 +403,9 @@ export class ExhaustableArray return toReturn; } - public getFirstValue(): T + public getFirstValue(): T { - if (!this.pool?.length) + if (!this.pool?.length) { return null; } @@ -340,13 +415,13 @@ export class ExhaustableArray return toReturn; } - public hasValues(): boolean + public hasValues(): boolean { - if (this.pool?.length) + if (this.pool?.length) { return true; } return false; } -} \ No newline at end of file +} diff --git a/project/src/helpers/BotHelper.ts b/project/src/helpers/BotHelper.ts index bdcfca4e..71f718b7 100644 --- a/project/src/helpers/BotHelper.ts +++ b/project/src/helpers/BotHelper.ts @@ -24,15 +24,13 @@ export class BotHelper @inject("DatabaseServer") protected databaseServer: DatabaseServer, @inject("RandomUtil") protected randomUtil: RandomUtil, @inject("LocalisationService") protected localisationService: LocalisationService, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.botConfig = this.configServer.getConfig(ConfigTypes.BOT); this.pmcConfig = this.configServer.getConfig(ConfigTypes.PMC); } - - /** * Get a template object for the specified botRole from bots.types db * @param role botRole to get template for @@ -71,7 +69,7 @@ export class BotHelper public isBotBoss(botRole: string): boolean { - return this.botConfig.bosses.some(x => x.toLowerCase() === botRole?.toLowerCase()); + return this.botConfig.bosses.some((x) => x.toLowerCase() === botRole?.toLowerCase()); } public isBotFollower(botRole: string): boolean @@ -187,13 +185,15 @@ export class BotHelper public rollChanceToBePmc(role: string, botConvertMinMax: MinMax): boolean { - return role.toLowerCase() in this.pmcConfig.convertIntoPmcChance - && this.randomUtil.getChance100(this.randomUtil.getInt(botConvertMinMax.min, botConvertMinMax.max)); + return role.toLowerCase() in this.pmcConfig.convertIntoPmcChance && + this.randomUtil.getChance100(this.randomUtil.getInt(botConvertMinMax.min, botConvertMinMax.max)); } public botRoleIsPmc(botRole: string): boolean { - return [this.pmcConfig.usecType.toLowerCase(), this.pmcConfig.bearType.toLowerCase()].includes(botRole.toLowerCase()); + return [this.pmcConfig.usecType.toLowerCase(), this.pmcConfig.bearType.toLowerCase()].includes( + botRole.toLowerCase(), + ); } /** @@ -209,8 +209,8 @@ export class BotHelper { return null; } - - return botEquipConfig.randomisation.find(x => botLevel >= x.levelRange.min && botLevel <= x.levelRange.max); + + return botEquipConfig.randomisation.find((x) => botLevel >= x.levelRange.min && botLevel <= x.levelRange.max); } /** @@ -219,9 +219,9 @@ export class BotHelper */ public getRandomizedPmcRole(): string { - return (this.randomUtil.getChance100(this.pmcConfig.isUsec)) - ? this.pmcConfig.usecType - : this.pmcConfig.bearType; + return (this.randomUtil.getChance100(this.pmcConfig.isUsec)) ? + this.pmcConfig.usecType : + this.pmcConfig.bearType; } /** @@ -248,8 +248,8 @@ export class BotHelper */ protected getRandomizedPmcSide(): string { - return (this.randomUtil.getChance100(this.pmcConfig.isUsec)) - ? "Usec" - : "Bear"; + return (this.randomUtil.getChance100(this.pmcConfig.isUsec)) ? + "Usec" : + "Bear"; } -} \ No newline at end of file +} diff --git a/project/src/helpers/BotWeaponGeneratorHelper.ts b/project/src/helpers/BotWeaponGeneratorHelper.ts index 5493198c..3a0631e1 100644 --- a/project/src/helpers/BotWeaponGeneratorHelper.ts +++ b/project/src/helpers/BotWeaponGeneratorHelper.ts @@ -29,9 +29,9 @@ export class BotWeaponGeneratorHelper @inject("InventoryHelper") protected inventoryHelper: InventoryHelper, @inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper, @inject("LocalisationService") protected localisationService: LocalisationService, - @inject("ContainerHelper") protected containerHelper: ContainerHelper + @inject("ContainerHelper") protected containerHelper: ContainerHelper, ) - { } + {} /** * Get a randomized number of bullets for a specific magazine @@ -61,7 +61,7 @@ export class BotWeaponGeneratorHelper /* Get the amount of bullets that would fit in the internal magazine * and multiply by how many magazines were supposed to be created */ - return chamberBulletCount * randomizedMagazineCount; + return chamberBulletCount * randomizedMagazineCount; } /** @@ -71,8 +71,8 @@ export class BotWeaponGeneratorHelper */ public getRandomizedMagazineCount(magCounts: GenerationData): number { - //const range = magCounts.max - magCounts.min; - //return this.randomUtil.getBiasedRandomNumber(magCounts.min, magCounts.max, Math.round(range * 0.75), 4); + // const range = magCounts.max - magCounts.min; + // return this.randomUtil.getBiasedRandomNumber(magCounts.min, magCounts.max, Math.round(range * 0.75), 4); return this.weightedRandomHelper.getWeightedValue(magCounts.weights); } @@ -98,7 +98,7 @@ export class BotWeaponGeneratorHelper { const magazine: Item[] = [{ _id: this.hashUtil.generate(), - _tpl: magazineTpl + _tpl: magazineTpl, }]; this.itemHelper.fillMagazineWithCartridge(magazine, magTemplate, ammoTpl, 1); @@ -113,12 +113,17 @@ export class BotWeaponGeneratorHelper * @param inventory bot inventory to add cartridges to * @param equipmentSlotsToAddTo what equipment slots should bullets be added into */ - public addAmmoIntoEquipmentSlots(ammoTpl: string, cartridgeCount: number, inventory: Inventory, equipmentSlotsToAddTo: EquipmentSlots[] = [EquipmentSlots.TACTICAL_VEST, EquipmentSlots.POCKETS] ): void + public addAmmoIntoEquipmentSlots( + ammoTpl: string, + cartridgeCount: number, + inventory: Inventory, + equipmentSlotsToAddTo: EquipmentSlots[] = [EquipmentSlots.TACTICAL_VEST, EquipmentSlots.POCKETS], + ): void { const ammoItems = this.itemHelper.splitStack({ _id: this.hashUtil.generate(), _tpl: ammoTpl, - upd: { StackObjectsCount: cartridgeCount } + upd: {StackObjectsCount: cartridgeCount}, }); for (const ammoItem of ammoItems) @@ -128,7 +133,8 @@ export class BotWeaponGeneratorHelper ammoItem._id, ammoItem._tpl, [ammoItem], - inventory); + inventory, + ); if (result === ItemAddedResult.NO_SPACE) { @@ -151,22 +157,32 @@ export class BotWeaponGeneratorHelper * TODO - move into BotGeneratorHelper, this is not the class for it * Adds an item with all its children into specified equipmentSlots, wherever it fits. * @param equipmentSlots Slot to add item+children into - * @param parentId - * @param parentTpl + * @param parentId + * @param parentTpl * @param itemWithChildren Item to add * @param inventory Inventory to add item+children into * @returns a `boolean` indicating item was added */ - public addItemWithChildrenToEquipmentSlot(equipmentSlots: string[], parentId: string, parentTpl: string, itemWithChildren: Item[], inventory: Inventory): ItemAddedResult + public addItemWithChildrenToEquipmentSlot( + equipmentSlots: string[], + parentId: string, + parentTpl: string, + itemWithChildren: Item[], + inventory: Inventory, + ): ItemAddedResult { for (const slot of equipmentSlots) { // Get container to put item into - const container = inventory.items.find(i => i.slotId === slot); + const container = inventory.items.find((i) => i.slotId === slot); if (!container) { // Desired equipment container (e.g. backpack) not found - this.logger.debug(`Unable to add item: ${itemWithChildren[0]._tpl} to: ${slot}, slot missing/bot generated without equipment`); + this.logger.debug( + `Unable to add item: ${ + itemWithChildren[0]._tpl + } to: ${slot}, slot missing/bot generated without equipment`, + ); continue; } @@ -202,10 +218,12 @@ export class BotWeaponGeneratorHelper } // Get all base level items in backpack - const containerItems = inventory.items.filter(i => i.parentId === container._id && i.slotId === slotGrid._name); + const containerItems = inventory.items.filter((i) => + i.parentId === container._id && i.slotId === slotGrid._name + ); // Get a copy of base level items we can iterate over - const containerItemsToCheck = containerItems.filter(x => x.slotId === slotGrid._name); + const containerItemsToCheck = containerItems.filter((x) => x.slotId === slotGrid._name); for (const item of containerItemsToCheck) { // Look for children on items, insert into array if found @@ -218,14 +236,19 @@ export class BotWeaponGeneratorHelper } // Get rid of items free/used spots in current grid - const slotGridMap = this.inventoryHelper.getContainerMap(slotGrid._props.cellsH, slotGrid._props.cellsV, containerItems, container._id); + const slotGridMap = this.inventoryHelper.getContainerMap( + slotGrid._props.cellsH, + slotGrid._props.cellsV, + containerItems, + container._id, + ); // Try to fit item into grid const findSlotResult = this.containerHelper.findSlotForItem(slotGridMap, itemSize[0], itemSize[1]); // Open slot found, add item to inventory if (findSlotResult.success) { - const parentItem = itemWithChildren.find(i => i._id === parentId); + const parentItem = itemWithChildren.find((i) => i._id === parentId); // Set items parent to container id parentItem.parentId = container._id; @@ -233,7 +256,7 @@ export class BotWeaponGeneratorHelper parentItem.location = { x: findSlotResult.x, y: findSlotResult.y, - r: findSlotResult.rotation ? 1 : 0 + r: findSlotResult.rotation ? 1 : 0, }; inventory.items.push(...itemWithChildren); @@ -284,4 +307,4 @@ export class BotWeaponGeneratorHelper return true; } -} \ No newline at end of file +} diff --git a/project/src/helpers/ContainerHelper.ts b/project/src/helpers/ContainerHelper.ts index bb88c4bc..cfd16c6b 100644 --- a/project/src/helpers/ContainerHelper.ts +++ b/project/src/helpers/ContainerHelper.ts @@ -43,7 +43,7 @@ export class ContainerHelper /** * Try to rotate if there is enough room for the item * Only occupies one grid of items, no rotation required - * */ + */ if (!foundSlot && itemWidth * itemHeight > 1) { foundSlot = this.locateSlot(container2D, containerX, containerY, x, y, itemHeight, itemWidth); @@ -77,7 +77,15 @@ export class ContainerHelper * @param itemH Items height * @returns True - slot found */ - protected locateSlot(container2D: number[][], containerX: number, containerY: number, x: number, y: number, itemW: number, itemH: number): boolean + protected locateSlot( + container2D: number[][], + containerX: number, + containerY: number, + x: number, + y: number, + itemW: number, + itemH: number, + ): boolean { let foundSlot = true; @@ -124,7 +132,14 @@ export class ContainerHelper * @param rotate is item rotated * @returns Location to place item */ - public fillContainerMapWithItem(container2D: number[][], x: number, y: number, itemW: number, itemH: number, rotate: boolean): number[][] + public fillContainerMapWithItem( + container2D: number[][], + x: number, + y: number, + itemW: number, + itemH: number, + rotate: boolean, + ): number[][] { const itemWidth = rotate ? itemH : itemW; const itemHeight = rotate ? itemW : itemH; @@ -146,4 +161,4 @@ export class ContainerHelper return container2D; } -} \ No newline at end of file +} diff --git a/project/src/helpers/DialogueHelper.ts b/project/src/helpers/DialogueHelper.ts index c54a8e4c..49ac0d91 100644 --- a/project/src/helpers/DialogueHelper.ts +++ b/project/src/helpers/DialogueHelper.ts @@ -4,7 +4,13 @@ import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { NotificationSendHelper } from "@spt-aki/helpers/NotificationSendHelper"; import { NotifierHelper } from "@spt-aki/helpers/NotifierHelper"; import { Item } from "@spt-aki/models/eft/common/tables/IItem"; -import { Dialogue, Message, MessageContent, MessageItems, MessagePreview } from "@spt-aki/models/eft/profile/IAkiProfile"; +import { + Dialogue, + Message, + MessageContent, + MessageItems, + MessagePreview, +} from "@spt-aki/models/eft/profile/IAkiProfile"; import { MessageType } from "@spt-aki/models/enums/MessageType"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { DatabaseServer } from "@spt-aki/servers/DatabaseServer"; @@ -24,9 +30,9 @@ export class DialogueHelper @inject("NotifierHelper") protected notifierHelper: NotifierHelper, @inject("NotificationSendHelper") protected notificationSendHelper: NotificationSendHelper, @inject("LocalisationService") protected localisationService: LocalisationService, - @inject("ItemHelper") protected itemHelper: ItemHelper + @inject("ItemHelper") protected itemHelper: ItemHelper, ) - { } + {} /** * @deprecated Use MailSendService.sendMessage() or helpers @@ -35,7 +41,7 @@ export class DialogueHelper { const result: MessageContent = { templateId: templateId, - type: messageType + type: messageType, }; if (maxStoreTime) @@ -49,7 +55,13 @@ export class DialogueHelper /** * @deprecated Use MailSendService.sendMessage() or helpers */ - public addDialogueMessage(dialogueID: string, messageContent: MessageContent, sessionID: string, rewards: Item[] = [], messageType = MessageType.NPC_TRADER): void + public addDialogueMessage( + dialogueID: string, + messageContent: MessageContent, + sessionID: string, + rewards: Item[] = [], + messageType = MessageType.NPC_TRADER, + ): void { const dialogueData = this.saveServer.getProfile(sessionID).dialogues; const isNewDialogue = !(dialogueID in dialogueData); @@ -63,7 +75,7 @@ export class DialogueHelper messages: [], pinned: false, new: 0, - attachmentsNew: 0 + attachmentsNew: 0, }; dialogueData[dialogueID] = dialogue; @@ -79,7 +91,7 @@ export class DialogueHelper const stashId = this.hashUtil.generate(); items = { stash: stashId, - data: [] + data: [], }; rewards = this.itemHelper.replaceIDs(null, rewards); @@ -95,7 +107,12 @@ export class DialogueHelper if (!itemTemplate) { // Can happen when modded items are insured + mod is removed - this.logger.error(this.localisationService.getText("dialog-missing_item_template", {tpl: reward._tpl, type: MessageType[messageContent.type]})); + this.logger.error( + this.localisationService.getText("dialog-missing_item_template", { + tpl: reward._tpl, + type: MessageType[messageContent.type], + }), + ); continue; } @@ -132,7 +149,9 @@ export class DialogueHelper items: items, maxStorageTime: messageContent.maxStorageTime, systemData: messageContent.systemData ? messageContent.systemData : undefined, - profileChangeEvents: (messageContent.profileChangeEvents?.length === 0) ? messageContent.profileChangeEvents : undefined + profileChangeEvents: (messageContent.profileChangeEvents?.length === 0) ? + messageContent.profileChangeEvents : + undefined, }; if (!message.templateId) @@ -145,7 +164,10 @@ export class DialogueHelper // Offer Sold notifications are now separate from the main notification if (messageContent.type === MessageType.FLEAMARKET_MESSAGE && messageContent.ragfair) { - const offerSoldMessage = this.notifierHelper.createRagfairOfferSoldNotification(message, messageContent.ragfair); + const offerSoldMessage = this.notifierHelper.createRagfairOfferSoldNotification( + message, + messageContent.ragfair, + ); this.notificationSendHelper.sendMessage(sessionID, offerSoldMessage); message.type = MessageType.MESSAGE_WITH_ITEMS; // Should prevent getting the same notification popup twice } @@ -156,7 +178,7 @@ export class DialogueHelper /** * Get the preview contents of the last message in a dialogue. - * @param dialogue + * @param dialogue * @returns MessagePreview */ public getMessagePreview(dialogue: Dialogue): MessagePreview @@ -167,7 +189,7 @@ export class DialogueHelper dt: message?.dt, type: message?.type, templateId: message?.templateId, - uid: dialogue._id + uid: dialogue._id, }; if (message?.text) @@ -185,17 +207,17 @@ export class DialogueHelper /** * Get the item contents for a particular message. - * @param messageID - * @param sessionID + * @param messageID + * @param sessionID * @param itemId Item being moved to inventory - * @returns + * @returns */ public getMessageItemContents(messageID: string, sessionID: string, itemId: string): Item[] { const dialogueData = this.saveServer.getProfile(sessionID).dialogues; for (const dialogueId in dialogueData) { - const message = dialogueData[dialogueId].messages.find(x => x._id === messageID); + const message = dialogueData[dialogueId].messages.find((x) => x._id === messageID); if (!message) { continue; @@ -211,7 +233,7 @@ export class DialogueHelper // Check reward count when item being moved isn't in reward list // if count is 0, it means after this move the reward array will be empty and all rewards collected - const rewardItemCount = message.items.data.filter(x => x._id !== itemId ); + const rewardItemCount = message.items.data.filter((x) => x._id !== itemId); if (rewardItemCount.length === 0) { message.rewardCollected = true; @@ -240,4 +262,4 @@ export class DialogueHelper return profile.dialogues; } -} \ No newline at end of file +} diff --git a/project/src/helpers/DurabilityLimitsHelper.ts b/project/src/helpers/DurabilityLimitsHelper.ts index 61d8edc9..f888d30c 100644 --- a/project/src/helpers/DurabilityLimitsHelper.ts +++ b/project/src/helpers/DurabilityLimitsHelper.ts @@ -15,7 +15,7 @@ export class DurabilityLimitsHelper constructor( @inject("RandomUtil") protected randomUtil: RandomUtil, @inject("BotHelper") protected botHelper: BotHelper, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.botConfig = this.configServer.getConfig(ConfigTypes.BOT); @@ -172,12 +172,14 @@ export class DurabilityLimitsHelper const maxDelta = this.getMaxWeaponDeltaFromConfig(botRole); const delta = this.randomUtil.getInt(minDelta, maxDelta); const result = maxDurability - delta; - const durabilityValueMinLimit = Math.round((this.getMinWeaponLimitPercentFromConfig(botRole) / 100) * maxDurability); + const durabilityValueMinLimit = Math.round( + (this.getMinWeaponLimitPercentFromConfig(botRole) / 100) * maxDurability, + ); // Dont let weapon dura go below the percent defined in config - return (result >= durabilityValueMinLimit) - ? result - : durabilityValueMinLimit; + return (result >= durabilityValueMinLimit) ? + result : + durabilityValueMinLimit; } protected generateArmorDurability(botRole: string, maxDurability: number): number @@ -186,12 +188,14 @@ export class DurabilityLimitsHelper const maxDelta = this.getMaxArmorDeltaFromConfig(botRole); const delta = this.randomUtil.getInt(minDelta, maxDelta); const result = maxDurability - delta; - const durabilityValueMinLimit = Math.round((this.getMinArmorLimitPercentFromConfig(botRole) / 100) * maxDurability); + const durabilityValueMinLimit = Math.round( + (this.getMinArmorLimitPercentFromConfig(botRole) / 100) * maxDurability, + ); // Dont let armor dura go below the percent defined in config - return (result >= durabilityValueMinLimit) - ? result - : durabilityValueMinLimit; + return (result >= durabilityValueMinLimit) ? + result : + durabilityValueMinLimit; } protected getMinWeaponDeltaFromConfig(botRole: string): number @@ -234,7 +238,7 @@ export class DurabilityLimitsHelper return this.botConfig.durability.default.armor.maxDelta; } - protected getMinArmorLimitPercentFromConfig (botRole: string): number + protected getMinArmorLimitPercentFromConfig(botRole: string): number { if (this.botConfig.durability[botRole]) { @@ -244,7 +248,7 @@ export class DurabilityLimitsHelper return this.botConfig.durability.default.armor.minLimitPercent; } - protected getMinWeaponLimitPercentFromConfig (botRole: string): number + protected getMinWeaponLimitPercentFromConfig(botRole: string): number { if (this.botConfig.durability[botRole]) { @@ -253,4 +257,4 @@ export class DurabilityLimitsHelper return this.botConfig.durability.default.weapon.minLimitPercent; } -} \ No newline at end of file +} diff --git a/project/src/helpers/GameEventHelper.ts b/project/src/helpers/GameEventHelper.ts index 14f3097e..b6b677c2 100644 --- a/project/src/helpers/GameEventHelper.ts +++ b/project/src/helpers/GameEventHelper.ts @@ -12,10 +12,9 @@ export class GameEventHelper constructor( @inject("DatabaseServer") protected databaseServer: DatabaseServer, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.seasonalEventConfig = this.configServer.getConfig(ConfigTypes.SEASONAL_EVENT); } - -} \ No newline at end of file +} diff --git a/project/src/helpers/HandbookHelper.ts b/project/src/helpers/HandbookHelper.ts index b674daeb..bc93a88d 100644 --- a/project/src/helpers/HandbookHelper.ts +++ b/project/src/helpers/HandbookHelper.ts @@ -29,7 +29,7 @@ export class LookupCollection @injectable() export class HandbookHelper -{ +{ protected lookupCacheGenerated = false; protected handbookPriceCache = new LookupCollection(); @@ -89,7 +89,7 @@ export class HandbookHelper return this.handbookPriceCache.items.byId.get(tpl); } - const handbookItem = this.databaseServer.getTables().templates.handbook.Items.find(x => x.Id === tpl); + const handbookItem = this.databaseServer.getTables().templates.handbook.Items.find((x) => x.Id === tpl); if (!handbookItem) { const newValue = 0; @@ -103,7 +103,7 @@ export class HandbookHelper /** * Get all items in template with the given parent category - * @param parentId + * @param parentId * @returns string array */ public templatesWithParent(parentId: string): string[] @@ -113,7 +113,7 @@ export class HandbookHelper /** * Does category exist in handbook cache - * @param category + * @param category * @returns true if exists in cache */ public isCategory(category: string): boolean @@ -123,7 +123,7 @@ export class HandbookHelper /** * Get all items associated with a categories parent - * @param categoryParent + * @param categoryParent * @returns string array */ public childrenCategories(categoryParent: string): string[] @@ -164,4 +164,4 @@ export class HandbookHelper const price = this.getTemplatePrice(currencyTypeTo); return price ? Math.round(roubleCurrencyCount / price) : 0; } -} \ No newline at end of file +} diff --git a/project/src/helpers/HealthHelper.ts b/project/src/helpers/HealthHelper.ts index d1443f94..7a67f1f2 100644 --- a/project/src/helpers/HealthHelper.ts +++ b/project/src/helpers/HealthHelper.ts @@ -21,7 +21,7 @@ export class HealthHelper @inject("WinstonLogger") protected logger: ILogger, @inject("TimeUtil") protected timeUtil: TimeUtil, @inject("SaveServer") protected saveServer: SaveServer, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.healthConfig = this.configServer.getConfig(ConfigTypes.HEALTH); @@ -36,11 +36,11 @@ export class HealthHelper { const profile = this.saveServer.getProfile(sessionID); - if (!profile.vitality) // Occurs on newly created profiles - { + if (!profile.vitality) + { // Occurs on newly created profiles profile.vitality = { health: null, - effects: null + effects: null, }; } profile.vitality.health = { @@ -53,7 +53,7 @@ export class HealthHelper LeftArm: 0, RightArm: 0, LeftLeg: 0, - RightLeg: 0 + RightLeg: 0, }; profile.vitality.effects = { @@ -63,7 +63,7 @@ export class HealthHelper LeftArm: {}, RightArm: {}, LeftLeg: {}, - RightLeg: {} + RightLeg: {}, }; return profile; @@ -77,7 +77,13 @@ export class HealthHelper * @param addEffects Should effects be added or removed (default - add) * @param deleteExistingEffects Should all prior effects be removed before apply new ones */ - public saveVitality(pmcData: IPmcData, request: ISyncHealthRequestData, sessionID: string, addEffects = true, deleteExistingEffects = true): void + public saveVitality( + pmcData: IPmcData, + request: ISyncHealthRequestData, + sessionID: string, + addEffects = true, + deleteExistingEffects = true, + ): void { const postRaidBodyParts = request.Health; // post raid health settings const profile = this.saveServer.getProfile(sessionID); @@ -96,20 +102,26 @@ export class HealthHelper { profileEffects[bodyPart] = postRaidBodyParts[bodyPart].Effects; } - if (request.IsAlive === true) // is player alive, not is limb alive - { + if (request.IsAlive === true) + { // is player alive, not is limb alive profileHealth[bodyPart] = postRaidBodyParts[bodyPart].Current; } else { - profileHealth[bodyPart] = pmcData.Health.BodyParts[bodyPart].Health.Maximum * this.healthConfig.healthMultipliers.death; + profileHealth[bodyPart] = pmcData.Health.BodyParts[bodyPart].Health.Maximum * + this.healthConfig.healthMultipliers.death; } } // Add effects to body parts if (addEffects) { - this.saveEffects(pmcData, sessionID, this.jsonUtil.clone(this.saveServer.getProfile(sessionID).vitality.effects), deleteExistingEffects); + this.saveEffects( + pmcData, + sessionID, + this.jsonUtil.clone(this.saveServer.getProfile(sessionID).vitality.effects), + deleteExistingEffects, + ); } // Adjust hydration/energy/temp and limb hp @@ -159,7 +171,10 @@ export class HealthHelper if (target === 0) { // Blacked body part - target = Math.round(pmcData.Health.BodyParts[healthModifier].Health.Maximum * this.healthConfig.healthMultipliers.blacked); + target = Math.round( + pmcData.Health.BodyParts[healthModifier].Health.Maximum * + this.healthConfig.healthMultipliers.blacked, + ); } pmcData.Health.BodyParts[healthModifier].Health.Current = Math.round(target); @@ -176,7 +191,12 @@ export class HealthHelper * @param bodyPartsWithEffects dict of body parts with effects that should be added to profile * @param addEffects Should effects be added back to profile */ - protected saveEffects(pmcData: IPmcData, sessionId: string, bodyPartsWithEffects: Effects, deleteExistingEffects = true): void + protected saveEffects( + pmcData: IPmcData, + sessionId: string, + bodyPartsWithEffects: Effects, + deleteExistingEffects = true, + ): void { if (!this.healthConfig.save.effects) { @@ -208,7 +228,9 @@ export class HealthHelper // Sometimes the value can be Infinity instead of -1, blame HealthListener.cs in modules if (time === "Infinity") { - this.logger.warning(`Effect ${effectType} found with value of Infinity, changed to -1, this is an issue with HealthListener.cs`); + this.logger.warning( + `Effect ${effectType} found with value of Infinity, changed to -1, this is an issue with HealthListener.cs`, + ); time = -1; } this.addEffect(pmcData, bodyPart, effectType, time); @@ -236,7 +258,7 @@ export class HealthHelper profileBodyPart.Effects = {}; } - profileBodyPart.Effects[effectType] = { Time: duration }; + profileBodyPart.Effects[effectType] = {Time: duration}; // Delete empty property to prevent client bugs if (this.isEmpty(profileBodyPart.Effects)) @@ -245,7 +267,7 @@ export class HealthHelper } } - protected isEmpty(map: Record): boolean + protected isEmpty(map: Record): boolean { for (const key in map) { @@ -257,4 +279,4 @@ export class HealthHelper return true; } -} \ No newline at end of file +} diff --git a/project/src/helpers/HideoutHelper.ts b/project/src/helpers/HideoutHelper.ts index 7be211db..cf88cb96 100644 --- a/project/src/helpers/HideoutHelper.ts +++ b/project/src/helpers/HideoutHelper.ts @@ -48,7 +48,7 @@ export class HideoutHelper @inject("InventoryHelper") protected inventoryHelper: InventoryHelper, @inject("PlayerService") protected playerService: PlayerService, @inject("LocalisationService") protected localisationService: LocalisationService, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.hideoutConfig = this.configServer.getConfig(ConfigTypes.HIDEOUT); @@ -61,9 +61,13 @@ export class HideoutHelper * @param sessionID Session id * @returns client response */ - public registerProduction(pmcData: IPmcData, body: IHideoutSingleProductionStartRequestData | IHideoutContinuousProductionStartRequestData, sessionID: string): IItemEventRouterResponse + public registerProduction( + pmcData: IPmcData, + body: IHideoutSingleProductionStartRequestData | IHideoutContinuousProductionStartRequestData, + sessionID: string, + ): IItemEventRouterResponse { - const recipe = this.databaseServer.getTables().hideout.production.find(p => p._id === body.recipeId); + const recipe = this.databaseServer.getTables().hideout.production.find((p) => p._id === body.recipeId); if (!recipe) { this.logger.error(this.localisationService.getText("hideout-missing_recipe_in_db", body.recipeId)); @@ -71,7 +75,8 @@ export class HideoutHelper return this.httpResponse.appendErrorToOutput(this.eventOutputHolder.getOutput(sessionID)); } - const modifiedProductionTime = recipe.productionTime - this.getCraftingSkillProductionTimeReduction(pmcData, recipe.productionTime); + const modifiedProductionTime = recipe.productionTime - + this.getCraftingSkillProductionTimeReduction(pmcData, recipe.productionTime); // @Important: Here we need to be very exact: // - normal recipe: Production time value is stored in attribute "productionType" with small "p" @@ -80,7 +85,11 @@ export class HideoutHelper { pmcData.Hideout.Production = {}; } - pmcData.Hideout.Production[body.recipeId] = this.initProduction(body.recipeId, modifiedProductionTime, recipe.needFuelForAllProductionTime); + pmcData.Hideout.Production[body.recipeId] = this.initProduction( + body.recipeId, + modifiedProductionTime, + recipe.needFuelForAllProductionTime, + ); } /** @@ -100,14 +109,14 @@ export class HideoutHelper Interrupted: false, NeedFuelForAllProductionTime: needFuelForAllProductionTime, // Used when sending to client needFuelForAllProductionTime: needFuelForAllProductionTime, // used when stored in production.json - SkipTime: 0 + SkipTime: 0, }; } /** * Is the provided object a Production type - * @param productive - * @returns + * @param productive + * @returns */ public isProductionType(productive: Productive): productive is Production { @@ -124,12 +133,15 @@ export class HideoutHelper // Handle additional changes some bonuses need before being added switch (bonus.type) { - case "StashSize": { + case "StashSize": + { // Find stash item and adjust tpl to new tpl from bonus - const stashItem = pmcData.Inventory.items.find(x => x._id === pmcData.Inventory.stash); + const stashItem = pmcData.Inventory.items.find((x) => x._id === pmcData.Inventory.stash); if (!stashItem) { - this.logger.warning(`Unable to apply StashSize bonus, stash with id: ${pmcData.Inventory.stash} not found`); + this.logger.warning( + `Unable to apply StashSize bonus, stash with id: ${pmcData.Inventory.stash} not found`, + ); } stashItem._tpl = bonus.templateId; @@ -140,7 +152,7 @@ export class HideoutHelper pmcData.Health.Energy.Maximum += bonus.value; break; case "TextBonus": - //Delete values before they're added to profile + // Delete values before they're added to profile delete bonus.value; delete bonus.passive; delete bonus.production; @@ -173,15 +185,19 @@ export class HideoutHelper * @param pmcData Player profile * @returns Properties */ - protected getHideoutProperties(pmcData: IPmcData): { btcFarmCGs: number; isGeneratorOn: boolean; waterCollectorHasFilter: boolean; } + protected getHideoutProperties( + pmcData: IPmcData, + ): {btcFarmCGs: number; isGeneratorOn: boolean; waterCollectorHasFilter: boolean;} { - const bitcoinFarm = pmcData.Hideout.Areas.find(x => x.type === HideoutAreas.BITCOIN_FARM); - const bitcoinCount = bitcoinFarm?.slots.filter(slot => slot.item).length ?? 0; // Get slots with an item property + const bitcoinFarm = pmcData.Hideout.Areas.find((x) => x.type === HideoutAreas.BITCOIN_FARM); + const bitcoinCount = bitcoinFarm?.slots.filter((slot) => slot.item).length ?? 0; // Get slots with an item property const hideoutProperties = { btcFarmCGs: bitcoinCount, - isGeneratorOn: pmcData.Hideout.Areas.find(x => x.type === HideoutAreas.GENERATOR)?.active ?? false, - waterCollectorHasFilter: this.doesWaterCollectorHaveFilter(pmcData.Hideout.Areas.find(x => x.type === HideoutAreas.WATER_COLLECTOR)) + isGeneratorOn: pmcData.Hideout.Areas.find((x) => x.type === HideoutAreas.GENERATOR)?.active ?? false, + waterCollectorHasFilter: this.doesWaterCollectorHaveFilter( + pmcData.Hideout.Areas.find((x) => x.type === HideoutAreas.WATER_COLLECTOR), + ), }; return hideoutProperties; @@ -189,23 +205,27 @@ export class HideoutHelper protected doesWaterCollectorHaveFilter(waterCollector: HideoutArea): boolean { - if (waterCollector.level === 3) // can put filters in from L3 - { + if (waterCollector.level === 3) + { // can put filters in from L3 // Has filter in at least one slot - return waterCollector.slots.some(x => x.item); + return waterCollector.slots.some((x) => x.item); } - + // No Filter return false; } - + /** * Update progress timer for water collector * @param pmcData profile to update * @param productionId id of water collection production to update * @param hideoutProperties Hideout properties */ - protected updateWaterCollectorProductionTimer(pmcData: IPmcData, productionId: string, hideoutProperties: { btcFarmCGs?: number; isGeneratorOn: boolean; waterCollectorHasFilter: boolean; }): void + protected updateWaterCollectorProductionTimer( + pmcData: IPmcData, + productionId: string, + hideoutProperties: {btcFarmCGs?: number; isGeneratorOn: boolean; waterCollectorHasFilter: boolean;}, + ): void { const timeElapsed = this.getTimeElapsedSinceLastServerTick(pmcData, hideoutProperties.isGeneratorOn); if (hideoutProperties.waterCollectorHasFilter) @@ -219,7 +239,10 @@ export class HideoutHelper * @param pmcData Profile to check for productions and update * @param hideoutProperties Hideout properties */ - protected updateProductionTimers(pmcData: IPmcData, hideoutProperties: { btcFarmCGs: number; isGeneratorOn: boolean; waterCollectorHasFilter: boolean; }): void + protected updateProductionTimers( + pmcData: IPmcData, + hideoutProperties: {btcFarmCGs: number; isGeneratorOn: boolean; waterCollectorHasFilter: boolean;}, + ): void { const recipes = this.databaseServer.getTables().hideout.production; @@ -255,12 +278,16 @@ export class HideoutHelper if (prodId === HideoutHelper.bitcoinFarm) { - pmcData.Hideout.Production[prodId] = this.updateBitcoinFarm(pmcData, hideoutProperties.btcFarmCGs, hideoutProperties.isGeneratorOn); + pmcData.Hideout.Production[prodId] = this.updateBitcoinFarm( + pmcData, + hideoutProperties.btcFarmCGs, + hideoutProperties.isGeneratorOn, + ); continue; } // Other recipes not covered by above - const recipe = recipes.find(r => r._id === prodId); + const recipe = recipes.find((r) => r._id === prodId); if (!recipe) { this.logger.error(this.localisationService.getText("hideout-missing_recipe_for_area", prodId)); @@ -277,9 +304,14 @@ export class HideoutHelper * @param pmcData Player profile * @param prodId Production id being crafted * @param recipe Recipe data being crafted - * @param hideoutProperties + * @param hideoutProperties */ - protected updateProductionProgress(pmcData: IPmcData, prodId: string, recipe: IHideoutProduction, hideoutProperties: { btcFarmCGs?: number; isGeneratorOn: boolean; waterCollectorHasFilter?: boolean; }): void + protected updateProductionProgress( + pmcData: IPmcData, + prodId: string, + recipe: IHideoutProduction, + hideoutProperties: {btcFarmCGs?: number; isGeneratorOn: boolean; waterCollectorHasFilter?: boolean;}, + ): void { // Production is complete, no need to do any calculations if (this.doesProgressMatchProductionTime(pmcData, prodId)) @@ -321,7 +353,8 @@ export class HideoutHelper */ protected updateScavCaseProductionTimer(pmcData: IPmcData, productionId: string): void { - const timeElapsed = (this.timeUtil.getTimestamp() - pmcData.Hideout.Production[productionId].StartTimestamp) - pmcData.Hideout.Production[productionId].Progress; + const timeElapsed = (this.timeUtil.getTimestamp() - pmcData.Hideout.Production[productionId].StartTimestamp) - + pmcData.Hideout.Production[productionId].Progress; pmcData.Hideout.Production[productionId].Progress += timeElapsed; } @@ -331,7 +364,11 @@ export class HideoutHelper * @param pmcData Profile to update areas of * @param hideoutProperties hideout properties */ - protected updateAreasWithResources(sessionID: string, pmcData: IPmcData, hideoutProperties: { btcFarmCGs: number; isGeneratorOn: boolean; waterCollectorHasFilter: boolean; }): void + protected updateAreasWithResources( + sessionID: string, + pmcData: IPmcData, + hideoutProperties: {btcFarmCGs: number; isGeneratorOn: boolean; waterCollectorHasFilter: boolean;}, + ): void { for (const area of pmcData.Hideout.Areas) { @@ -361,9 +398,10 @@ export class HideoutHelper { // 1 resource last 14 min 27 sec, 1/14.45/60 = 0.00115 // 10-10-2021 From wiki, 1 resource last 12 minutes 38 seconds, 1/12.63333/60 = 0.00131 - let fuelDrainRate = this.databaseServer.getTables().hideout.settings.generatorFuelFlowRate * this.hideoutConfig.runIntervalSeconds; + let fuelDrainRate = this.databaseServer.getTables().hideout.settings.generatorFuelFlowRate * + this.hideoutConfig.runIntervalSeconds; // implemented moddable bonus for fuel consumption bonus instead of using solar power variable as before - const fuelBonus = pmcData.Bonuses.find(b => b.type === "FuelConsumption"); + const fuelBonus = pmcData.Bonuses.find((b) => b.type === "FuelConsumption"); const fuelBonusPercent = 1.0 - (fuelBonus ? Math.abs(fuelBonus.value) : 0) / 100; fuelDrainRate *= fuelBonusPercent; // Hideout management resource consumption bonus: @@ -376,9 +414,9 @@ export class HideoutHelper { if (generatorArea.slots[i].item) { - let resourceValue = (generatorArea.slots[i].item[0].upd?.Resource) - ? generatorArea.slots[i].item[0].upd.Resource.Value - : null; + let resourceValue = (generatorArea.slots[i].item[0].upd?.Resource) ? + generatorArea.slots[i].item[0].upd.Resource.Value : + null; if (resourceValue === 0) { continue; @@ -386,9 +424,9 @@ export class HideoutHelper else if (!resourceValue) { const fuelItem = HideoutHelper.expeditionaryFuelTank; - resourceValue = generatorArea.slots[i].item[0]._tpl === fuelItem - ? 60 - fuelDrainRate - : 100 - fuelDrainRate; + resourceValue = generatorArea.slots[i].item[0]._tpl === fuelItem ? + 60 - fuelDrainRate : + 100 - fuelDrainRate; pointsConsumed = fuelDrainRate; } else @@ -400,7 +438,7 @@ export class HideoutHelper resourceValue = Math.round(resourceValue * 10000) / 10000; pointsConsumed = Math.round(pointsConsumed * 10000) / 10000; - //check unit consumed for increment skill point + // check unit consumed for increment skill point if (pmcData && Math.floor(pointsConsumed / 10) >= 1) { this.profileHelper.addSkillPointsToPlayer(pmcData, SkillTypes.HIDEOUT_MANAGEMENT, 1); @@ -432,7 +470,12 @@ export class HideoutHelper } } - protected updateWaterCollector(sessionId: string, pmcData: IPmcData, area: HideoutArea, isGeneratorOn: boolean): void + protected updateWaterCollector( + sessionId: string, + pmcData: IPmcData, + area: HideoutArea, + isGeneratorOn: boolean, + ): void { // Skip water collector when not level 3 (cant collect until 3) if (area.level !== 3) @@ -454,7 +497,7 @@ export class HideoutHelper recipeId: HideoutHelper.waterCollector, Action: "HideoutSingleProductionStart", items: [], - timestamp: this.timeUtil.getTimestamp() + timestamp: this.timeUtil.getTimestamp(), }; this.registerProduction(pmcData, recipe, sessionId); @@ -469,14 +512,24 @@ export class HideoutHelper * @param pmcData Player profile * @returns Updated HideoutArea object */ - protected updateWaterFilters(waterFilterArea: HideoutArea, production: Production, isGeneratorOn: boolean, pmcData: IPmcData): HideoutArea + protected updateWaterFilters( + waterFilterArea: HideoutArea, + production: Production, + isGeneratorOn: boolean, + pmcData: IPmcData, + ): HideoutArea { let filterDrainRate = this.getWaterFilterDrainRate(pmcData); const productionTime = this.getTotalProductionTimeSeconds(HideoutHelper.waterCollector); const secondsSinceServerTick = this.getTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn); - - filterDrainRate = this.adjustWaterFilterDrainRate(secondsSinceServerTick, productionTime, production.Progress, filterDrainRate); - + + filterDrainRate = this.adjustWaterFilterDrainRate( + secondsSinceServerTick, + productionTime, + production.Progress, + filterDrainRate, + ); + // Production hasn't completed let pointsConsumed = 0; if (production.Progress < productionTime) @@ -489,9 +542,9 @@ export class HideoutHelper if (waterFilterArea.slots[i].item) { // How many units of filter are left - let resourceValue = (waterFilterArea.slots[i].item[0].upd?.Resource) - ? waterFilterArea.slots[i].item[0].upd.Resource.Value - : null; + let resourceValue = (waterFilterArea.slots[i].item[0].upd?.Resource) ? + waterFilterArea.slots[i].item[0].upd.Resource.Value : + null; if (!resourceValue) { // None left @@ -500,7 +553,8 @@ export class HideoutHelper } else { - pointsConsumed = (waterFilterArea.slots[i].item[0].upd.Resource.UnitsConsumed || 0) + filterDrainRate; + pointsConsumed = (waterFilterArea.slots[i].item[0].upd.Resource.UnitsConsumed || 0) + + filterDrainRate; resourceValue -= filterDrainRate; } @@ -537,19 +591,25 @@ export class HideoutHelper } /** - * Get an adjusted water filter drain rate based on time elapsed since last run, + * Get an adjusted water filter drain rate based on time elapsed since last run, * handle edge case when craft time has gone on longer than total production time * @param secondsSinceServerTick Time passed * @param totalProductionTime Total time collecting water - * @param productionProgress how far water collector has progressed - * @param baseFilterDrainRate Base drain rate - * @returns + * @param productionProgress how far water collector has progressed + * @param baseFilterDrainRate Base drain rate + * @returns */ - protected adjustWaterFilterDrainRate(secondsSinceServerTick: number, totalProductionTime: number, productionProgress: number, baseFilterDrainRate: number): number + protected adjustWaterFilterDrainRate( + secondsSinceServerTick: number, + totalProductionTime: number, + productionProgress: number, + baseFilterDrainRate: number, + ): number { - const drainRateMultiplier = secondsSinceServerTick > totalProductionTime - ? (totalProductionTime - productionProgress) // more time passed than prod time, get total minus the current progress - : secondsSinceServerTick; + const drainRateMultiplier = secondsSinceServerTick > totalProductionTime ? + (totalProductionTime - productionProgress) // more time passed than prod time, get total minus the current progress + : + secondsSinceServerTick; // Multiply drain rate by calculated multiplier baseFilterDrainRate *= drainRateMultiplier; @@ -578,16 +638,16 @@ export class HideoutHelper */ protected getTotalProductionTimeSeconds(prodId: string): number { - const recipe = this.databaseServer.getTables().hideout.production.find(prod => prod._id === prodId); + const recipe = this.databaseServer.getTables().hideout.production.find((prod) => prod._id === prodId); return (recipe.productionTime || 0); } /** * Create a upd object using passed in parameters - * @param stackCount - * @param resourceValue - * @param resourceUnitsConsumed + * @param stackCount + * @param resourceValue + * @param resourceUnitsConsumed * @returns Upd */ protected getAreaUpdObject(stackCount: number, resourceValue: number, resourceUnitsConsumed: number): Upd @@ -596,8 +656,8 @@ export class HideoutHelper StackObjectsCount: stackCount, Resource: { Value: resourceValue, - UnitsConsumed: resourceUnitsConsumed - } + UnitsConsumed: resourceUnitsConsumed, + }, }; } @@ -608,7 +668,8 @@ export class HideoutHelper Lasts for 17 hours 38 minutes and 49 seconds (23 hours 31 minutes and 45 seconds with elite hideout management skill), 300/17.64694/60/60 = 0.004722 */ - let filterDrainRate = this.databaseServer.getTables().hideout.settings.airFilterUnitFlowRate * this.hideoutConfig.runIntervalSeconds; + let filterDrainRate = this.databaseServer.getTables().hideout.settings.airFilterUnitFlowRate * + this.hideoutConfig.runIntervalSeconds; // Hideout management resource consumption bonus: const hideoutManagementConsumptionBonus = 1.0 - this.getHideoutManagementConsumptionBonus(pmcData); filterDrainRate *= hideoutManagementConsumptionBonus; @@ -618,9 +679,9 @@ export class HideoutHelper { if (airFilterArea.slots[i].item) { - let resourceValue = (airFilterArea.slots[i].item[0].upd?.Resource) - ? airFilterArea.slots[i].item[0].upd.Resource.Value - : null; + let resourceValue = (airFilterArea.slots[i].item[0].upd?.Resource) ? + airFilterArea.slots[i].item[0].upd.Resource.Value : + null; if (!resourceValue) { resourceValue = 300 - filterDrainRate; @@ -634,7 +695,7 @@ export class HideoutHelper resourceValue = Math.round(resourceValue * 10000) / 10000; pointsConsumed = Math.round(pointsConsumed * 10000) / 10000; - //check unit consumed for increment skill point + // check unit consumed for increment skill point if (pmcData && Math.floor(pointsConsumed / 10) >= 1) { this.profileHelper.addSkillPointsToPlayer(pmcData, SkillTypes.HIDEOUT_MANAGEMENT, 1); @@ -647,8 +708,8 @@ export class HideoutHelper StackObjectsCount: 1, Resource: { Value: resourceValue, - UnitsConsumed: pointsConsumed - } + UnitsConsumed: pointsConsumed, + }, }; this.logger.debug(`Air filter: ${resourceValue} filter left on slot ${i + 1}`); break; // Break here to avoid updating all filters @@ -662,11 +723,13 @@ export class HideoutHelper } } } - + protected updateBitcoinFarm(pmcData: IPmcData, btcFarmCGs: number, isGeneratorOn: boolean): Production { const btcProd = pmcData.Hideout.Production[HideoutHelper.bitcoinFarm]; - const bitcoinProdData = this.databaseServer.getTables().hideout.production.find(p => p._id === "5d5c205bd582a50d042a3c0e"); + const bitcoinProdData = this.databaseServer.getTables().hideout.production.find((p) => + p._id === "5d5c205bd582a50d042a3c0e" + ); const coinSlotCount = this.getBTCSlots(pmcData); // Full on bitcoins, halt progress @@ -718,7 +781,8 @@ export class HideoutHelper } */ // BSG finally fixed their settings, they now get loaded from the settings and used in the client - const coinCraftTimeSeconds = bitcoinProdData.productionTime / (1 + (btcFarmCGs - 1) * this.databaseServer.getTables().hideout.settings.gpuBoostRate); + const coinCraftTimeSeconds = bitcoinProdData.productionTime / + (1 + (btcFarmCGs - 1) * this.databaseServer.getTables().hideout.settings.gpuBoostRate); while (btcProd.Progress > coinCraftTimeSeconds) { if (btcProd.Products.length < coinSlotCount) @@ -753,8 +817,8 @@ export class HideoutHelper _id: this.hashUtil.generate(), _tpl: "59faff1d86f7746c51718c9c", upd: { - StackObjectsCount: 1 - } + StackObjectsCount: 1, + }, }); btcProd.Progress -= coinCraftTimeSeconds; @@ -767,13 +831,17 @@ export class HideoutHelper * @param recipe Hideout production recipe being crafted we need the ticks for * @returns Amount of time elapsed in seconds */ - protected getTimeElapsedSinceLastServerTick(pmcData: IPmcData, isGeneratorOn: boolean, recipe: IHideoutProduction = null): number + protected getTimeElapsedSinceLastServerTick( + pmcData: IPmcData, + isGeneratorOn: boolean, + recipe: IHideoutProduction = null, + ): number { // Reduce time elapsed (and progress) when generator is off let timeElapsed = this.timeUtil.getTimestamp() - pmcData.Hideout.sptUpdateLastRunTimestamp; - if (recipe?.areaType === HideoutAreas.LAVATORY) // Lavatory works at 100% when power is on / off - { + if (recipe?.areaType === HideoutAreas.LAVATORY) + { // Lavatory works at 100% when power is on / off return timeElapsed; } @@ -792,7 +860,9 @@ export class HideoutHelper */ protected getBTCSlots(pmcData: IPmcData): number { - const bitcoinProduction = this.databaseServer.getTables().hideout.production.find(p => p._id === HideoutHelper.bitcoinFarm); + const bitcoinProduction = this.databaseServer.getTables().hideout.production.find((p) => + p._id === HideoutHelper.bitcoinFarm + ); const productionSlots = bitcoinProduction?.productionLimitCount || 3; const hasManagementSkillSlots = this.profileHelper.hasEliteSkillLevel(SkillTypes.HIDEOUT_MANAGEMENT, pmcData); const managementSlotsCount = this.getBitcoinMinerContainerSlotSize() || 2; @@ -805,7 +875,8 @@ export class HideoutHelper */ protected getBitcoinMinerContainerSlotSize(): number { - return this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.BitcoinFarm.Container; + return this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.BitcoinFarm + .Container; } /** @@ -826,11 +897,13 @@ export class HideoutHelper // at level 1 you already get 0.5%, so it goes up until level 50. For some reason the wiki // says that it caps at level 51 with 25% but as per dump data that is incorrect apparently let roundedLevel = Math.floor(hideoutManagementSkill.Progress / 100); - roundedLevel = (roundedLevel === 51) - ? roundedLevel - 1 - : roundedLevel; + roundedLevel = (roundedLevel === 51) ? + roundedLevel - 1 : + roundedLevel; - return (roundedLevel * this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.ConsumptionReductionPerLevel) / 100; + return (roundedLevel * + this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement + .ConsumptionReductionPerLevel) / 100; } /** @@ -841,7 +914,7 @@ export class HideoutHelper */ protected getCraftingSkillProductionTimeReduction(pmcData: IPmcData, productionTime: number): number { - const craftingSkill = pmcData.Skills.Common.find(x=> x.Id === SkillTypes.CRAFTING); + const craftingSkill = pmcData.Skills.Common.find((x) => x.Id === SkillTypes.CRAFTING); if (!craftingSkill) { return productionTime; @@ -865,7 +938,11 @@ export class HideoutHelper * @param sessionId Session id * @returns IItemEventRouterResponse */ - public getBTC(pmcData: IPmcData, request: IHideoutTakeProductionRequestData, sessionId: string): IItemEventRouterResponse + public getBTC( + pmcData: IPmcData, + request: IHideoutTakeProductionRequestData, + sessionId: string, + ): IItemEventRouterResponse { const output = this.eventOutputHolder.getOutput(sessionId); @@ -875,7 +952,7 @@ export class HideoutHelper { const errorMsg = this.localisationService.getText("hideout-no_bitcoins_to_collect"); this.logger.error(errorMsg); - + return this.httpResponse.appendErrorToOutput(output, errorMsg); } @@ -911,9 +988,9 @@ export class HideoutHelper items: [{ // eslint-disable-next-line @typescript-eslint/naming-convention item_id: HideoutHelper.bitcoin, - count: pmcData.Hideout.Production[HideoutHelper.bitcoinFarm].Products.length + count: pmcData.Hideout.Production[HideoutHelper.bitcoinFarm].Products.length, }], - tid: "ragfair" + tid: "ragfair", }; } @@ -923,9 +1000,9 @@ export class HideoutHelper */ public unlockHideoutWallInProfile(pmcProfile: IPmcData): void { - const waterCollector = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WATER_COLLECTOR); - const medStation = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.MEDSTATION); - const wall = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.EMERGENCY_WALL); + const waterCollector = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WATER_COLLECTOR); + const medStation = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.MEDSTATION); + const wall = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.EMERGENCY_WALL); // No collector or med station, skip if (!(waterCollector && medStation)) @@ -947,9 +1024,9 @@ export class HideoutHelper */ protected hideoutImprovementIsComplete(improvement: IHideoutImprovement): boolean { - return improvement?.completed - ? true - : false; + return improvement?.completed ? + true : + false; } /** @@ -961,10 +1038,13 @@ export class HideoutHelper for (const improvementId in pmcProfile.Hideout.Improvement) { const improvementDetails = pmcProfile.Hideout.Improvement[improvementId]; - if (improvementDetails.completed === false && improvementDetails.improveCompleteTimestamp < this.timeUtil.getTimestamp()) + if ( + improvementDetails.completed === false && + improvementDetails.improveCompleteTimestamp < this.timeUtil.getTimestamp() + ) { improvementDetails.completed = true; } } } -} \ No newline at end of file +} diff --git a/project/src/helpers/HttpServerHelper.ts b/project/src/helpers/HttpServerHelper.ts index 613bfa9e..e6db7dee 100644 --- a/project/src/helpers/HttpServerHelper.ts +++ b/project/src/helpers/HttpServerHelper.ts @@ -18,11 +18,11 @@ export class HttpServerHelper json: "application/json", png: "image/png", svg: "image/svg+xml", - txt: "text/plain" + txt: "text/plain", }; constructor( - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.httpConfig = this.configServer.getConfig(ConfigTypes.HTTP); @@ -60,7 +60,7 @@ export class HttpServerHelper public sendTextJson(resp: any, output: any): void { // eslint-disable-next-line @typescript-eslint/naming-convention - resp.writeHead(200, "OK", { "Content-Type": this.mime["json"] }); + resp.writeHead(200, "OK", {"Content-Type": this.mime["json"]}); resp.end(output); } -} \ No newline at end of file +} diff --git a/project/src/helpers/InRaidHelper.ts b/project/src/helpers/InRaidHelper.ts index a286c137..bc4d02c5 100644 --- a/project/src/helpers/InRaidHelper.ts +++ b/project/src/helpers/InRaidHelper.ts @@ -39,7 +39,7 @@ export class InRaidHelper @inject("PaymentHelper") protected paymentHelper: PaymentHelper, @inject("LocalisationService") protected localisationService: LocalisationService, @inject("ProfileFixerService") protected profileFixerService: ProfileFixerService, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.lostOnDeathConfig = this.configServer.getConfig(ConfigTypes.LOST_ON_DEATH); @@ -95,8 +95,13 @@ export class InRaidHelper { return acc + standingForKill; } - this.logger.warning(this.localisationService.getText("inraid-missing_standing_for_kill", {victimSide: victim.Side, victimRole: victim.Role})); - + this.logger.warning( + this.localisationService.getText("inraid-missing_standing_for_kill", { + victimSide: victim.Side, + victimRole: victim.Role, + }), + ); + return acc; }, existingFenceStanding); @@ -116,7 +121,7 @@ export class InRaidHelper // Scavs and bosses return botTypes[victim.Role.toLowerCase()]?.experience?.standingForKill; } - + // PMCs - get by bear/usec return botTypes[victim.Side.toLowerCase()]?.experience?.standingForKill; } @@ -131,7 +136,11 @@ export class InRaidHelper * @param sessionID Session id * @returns Reset profile object */ - public updateProfileBaseStats(profileData: IPmcData, saveProgressRequest: ISaveProgressRequestData, sessionID: string): IPmcData + public updateProfileBaseStats( + profileData: IPmcData, + saveProgressRequest: ISaveProgressRequestData, + sessionID: string, + ): IPmcData { // remove old skill fatigue this.resetSkillPointsEarnedDuringRaid(saveProgressRequest.profile); @@ -168,7 +177,9 @@ export class InRaidHelper if (matchingPreRaidCounter.value !== postRaidValue) { - this.logger.error(`Backendcounter: ${backendCounterKey} value is different post raid, old: ${matchingPreRaidCounter.value} new: ${postRaidValue}`); + this.logger.error( + `Backendcounter: ${backendCounterKey} value is different post raid, old: ${matchingPreRaidCounter.value} new: ${postRaidValue}`, + ); } } @@ -199,7 +210,6 @@ export class InRaidHelper return profileData; } - /** * Look for quests not are now status = fail that were not failed pre-raid and run the failQuest() function * @param sessionId Player id @@ -207,7 +217,12 @@ export class InRaidHelper * @param preRaidQuests Quests prior to starting raid * @param postRaidQuests Quest after raid */ - protected processFailedQuests(sessionId: string, pmcData: IPmcData, preRaidQuests: IQuestStatus[], postRaidQuests: IQuestStatus[]): void + protected processFailedQuests( + sessionId: string, + pmcData: IPmcData, + preRaidQuests: IQuestStatus[], + postRaidQuests: IQuestStatus[], + ): void { if (!preRaidQuests) { @@ -219,7 +234,7 @@ export class InRaidHelper for (const postRaidQuest of postRaidQuests) { // Find matching pre-raid quest - const preRaidQuest = preRaidQuests?.find(x => x.qid === postRaidQuest.qid); + const preRaidQuest = preRaidQuests?.find((x) => x.qid === postRaidQuest.qid); if (preRaidQuest) { // Post-raid quest is failed but wasn't pre-raid @@ -230,12 +245,11 @@ export class InRaidHelper const failBody: IFailQuestRequestData = { Action: "QuestComplete", qid: postRaidQuest.qid, - removeExcessItems: true + removeExcessItems: true, }; this.questHelper.failQuest(pmcData, failBody, sessionId); } } - } } @@ -252,7 +266,10 @@ export class InRaidHelper * @param saveProgressRequest post-raid request * @param profileData player profile on server */ - protected transferPostRaidLimbEffectsToProfile(saveProgressRequest: ISaveProgressRequestData, profileData: IPmcData): void + protected transferPostRaidLimbEffectsToProfile( + saveProgressRequest: ISaveProgressRequestData, + profileData: IPmcData, + ): void { // Iterate over each body part for (const bodyPartId in saveProgressRequest.profile.Health.BodyParts) @@ -287,7 +304,10 @@ export class InRaidHelper * @param tradersServerProfile Server * @param tradersClientProfile Client */ - protected applyTraderStandingAdjustments(tradersServerProfile: Record, tradersClientProfile: Record): void + protected applyTraderStandingAdjustments( + tradersServerProfile: Record, + tradersClientProfile: Record, + ): void { for (const traderId in tradersClientProfile) { @@ -356,12 +376,13 @@ export class InRaidHelper public removeSpawnedInSessionPropertyFromItems(postRaidProfile: IPostRaidPmcData): IPostRaidPmcData { const dbItems = this.databaseServer.getTables().templates.items; - const itemsToRemovePropertyFrom = postRaidProfile.Inventory.items.filter(x => + const itemsToRemovePropertyFrom = postRaidProfile.Inventory.items.filter((x) => { // Has upd object + upd.SpawnedInSession property + not a quest item - return "upd" in x && "SpawnedInSession" in x.upd - && !dbItems[x._tpl]._props.QuestItem - && !(this.inRaidConfig.keepFiRSecureContainerOnDeath && this.itemHelper.itemIsInsideContainer(x, "SecuredContainer", postRaidProfile.Inventory.items)); + return "upd" in x && "SpawnedInSession" in x.upd && + !dbItems[x._tpl]._props.QuestItem && + !(this.inRaidConfig.keepFiRSecureContainerOnDeath && + this.itemHelper.itemIsInsideContainer(x, "SecuredContainer", postRaidProfile.Inventory.items)); }); for (const item of itemsToRemovePropertyFrom) @@ -409,7 +430,7 @@ export class InRaidHelper public deleteInventory(pmcData: IPmcData, sessionID: string): void { // Get inventory item ids to remove from players profile - const itemIdsToDeleteFromProfile = this.getInventoryItemsLostOnDeath(pmcData).map(x => x._id); + const itemIdsToDeleteFromProfile = this.getInventoryItemsLostOnDeath(pmcData).map((x) => x._id); for (const itemId of itemIdsToDeleteFromProfile) { this.inventoryHelper.removeItem(pmcData, itemId, sessionID); @@ -426,30 +447,30 @@ export class InRaidHelper */ protected getInventoryItemsLostOnDeath(pmcProfile: IPmcData): Item[] { - const inventoryItems = pmcProfile.Inventory.items ?? []; + const inventoryItems = pmcProfile.Inventory.items ?? []; const equipment = pmcProfile?.Inventory?.equipment; const questRaidItems = pmcProfile?.Inventory?.questRaidItems; - return inventoryItems.filter(x => + return inventoryItems.filter((x) => { // Keep items flagged as kept after death if (this.isItemKeptAfterDeath(pmcProfile, x)) { return false; } - + // Remove normal items or quest raid items if (x.parentId === equipment || x.parentId === questRaidItems) { return true; } - + // Pocket items are not lost on death if (x.slotId.startsWith("pocket")) { return true; } - + return false; }); } @@ -461,13 +482,13 @@ export class InRaidHelper */ protected getBaseItemsInRigPocketAndBackpack(pmcData: IPmcData): Item[] { - const rig = pmcData.Inventory.items.find(x => x.slotId === "TacticalVest"); - const pockets = pmcData.Inventory.items.find(x => x.slotId === "Pockets"); - const backpack = pmcData.Inventory.items.find(x => x.slotId === "Backpack"); + const rig = pmcData.Inventory.items.find((x) => x.slotId === "TacticalVest"); + const pockets = pmcData.Inventory.items.find((x) => x.slotId === "Pockets"); + const backpack = pmcData.Inventory.items.find((x) => x.slotId === "Backpack"); - const baseItemsInRig = pmcData.Inventory.items.filter(x => x.parentId === rig?._id); - const baseItemsInPockets = pmcData.Inventory.items.filter(x => x.parentId === pockets?._id); - const baseItemsInBackpack = pmcData.Inventory.items.filter(x => x.parentId === backpack?._id); + const baseItemsInRig = pmcData.Inventory.items.filter((x) => x.parentId === rig?._id); + const baseItemsInPockets = pmcData.Inventory.items.filter((x) => x.parentId === pockets?._id); + const baseItemsInBackpack = pmcData.Inventory.items.filter((x) => x.parentId === backpack?._id); return [...baseItemsInRig, ...baseItemsInPockets, ...baseItemsInBackpack]; } @@ -539,7 +560,7 @@ export class InRaidHelper "pocket1", "pocket2", "pocket3", - "pocket4" + "pocket4", ]; let inventoryItems: Item[] = []; @@ -574,7 +595,7 @@ export class InRaidHelper // Add these new found items to our list of inventory items inventoryItems = [ ...inventoryItems, - ...foundItems + ...foundItems, ]; // Now find the children of these items @@ -583,4 +604,4 @@ export class InRaidHelper return inventoryItems; } -} \ No newline at end of file +} diff --git a/project/src/helpers/InventoryHelper.ts b/project/src/helpers/InventoryHelper.ts index a8843b33..793a80b1 100644 --- a/project/src/helpers/InventoryHelper.ts +++ b/project/src/helpers/InventoryHelper.ts @@ -32,11 +32,11 @@ import { JsonUtil } from "@spt-aki/utils/JsonUtil"; export interface OwnerInventoryItems { /** Inventory items from source */ - from: Item[] + from: Item[]; /** Inventory items at destination */ - to: Item[] - sameInventory: boolean, - isMail: boolean + to: Item[]; + sameInventory: boolean; + isMail: boolean; } @injectable() @@ -58,7 +58,7 @@ export class InventoryHelper @inject("ContainerHelper") protected containerHelper: ContainerHelper, @inject("ProfileHelper") protected profileHelper: ProfileHelper, @inject("LocalisationService") protected localisationService: LocalisationService, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.inventoryConfig = this.configServer.getConfig(ConfigTypes.INVENTORY); @@ -76,7 +76,16 @@ export class InventoryHelper * @param useSortingTable Allow items to go into sorting table when stash has no space * @returns IItemEventRouterResponse */ - public addItem(pmcData: IPmcData, request: IAddItemRequestData, output: IItemEventRouterResponse, sessionID: string, callback: () => void, foundInRaid = false, addUpd = null, useSortingTable = false): IItemEventRouterResponse + public addItem( + pmcData: IPmcData, + request: IAddItemRequestData, + output: IItemEventRouterResponse, + sessionID: string, + callback: () => void, + foundInRaid = false, + addUpd = null, + useSortingTable = false, + ): IItemEventRouterResponse { const itemLib: Item[] = []; // TODO: what is the purpose of this property const itemsToAdd: IAddItemTempObject[] = []; @@ -85,19 +94,21 @@ export class InventoryHelper { if (requestItem.item_id in this.databaseServer.getTables().globals.ItemPresets) { - const presetItems = this.jsonUtil.clone(this.databaseServer.getTables().globals.ItemPresets[requestItem.item_id]._items); + const presetItems = this.jsonUtil.clone( + this.databaseServer.getTables().globals.ItemPresets[requestItem.item_id]._items, + ); itemLib.push(...presetItems); requestItem.isPreset = true; requestItem.item_id = presetItems[0]._id; } else if (this.paymentHelper.isMoneyTpl(requestItem.item_id)) { - itemLib.push({ _id: requestItem.item_id, _tpl: requestItem.item_id }); + itemLib.push({_id: requestItem.item_id, _tpl: requestItem.item_id}); } else if (request.tid === Traders.FENCE) { const fenceItems = this.fenceService.getRawFenceAssorts().items; - const itemIndex = fenceItems.findIndex(i => i._id === requestItem.item_id); + const itemIndex = fenceItems.findIndex((i) => i._id === requestItem.item_id); if (itemIndex === -1) { this.logger.debug(`Tried to buy item ${requestItem.item_id} from fence that no longer exists`); @@ -105,20 +116,25 @@ export class InventoryHelper return this.httpResponse.appendErrorToOutput(output, message); } - const purchasedItemWithChildren = this.itemHelper.findAndReturnChildrenAsItems(fenceItems, requestItem.item_id); + const purchasedItemWithChildren = this.itemHelper.findAndReturnChildrenAsItems( + fenceItems, + requestItem.item_id, + ); addUpd = purchasedItemWithChildren[0].upd; // Must persist the fence upd properties (e.g. durability/currentHp) itemLib.push(...purchasedItemWithChildren); } else if (request.tid === "RandomLootContainer") { - itemLib.push({ _id: requestItem.item_id, _tpl: requestItem.item_id }); + itemLib.push({_id: requestItem.item_id, _tpl: requestItem.item_id}); } else { // Only grab the relevant trader items and add unique values const traderItems = this.traderAssortHelper.getAssort(sessionID, request.tid).items; const relevantItems = this.itemHelper.findAndReturnChildrenAsItems(traderItems, requestItem.item_id); - const toAdd = relevantItems.filter(traderItem => !itemLib.some(item => traderItem._id === item._id)); // what's this + const toAdd = relevantItems.filter((traderItem) => + !itemLib.some((item) => traderItem._id === item._id) + ); // what's this itemLib.push(...toAdd); } @@ -133,7 +149,15 @@ export class InventoryHelper for (const itemToAdd of itemsToAdd) { - const errorOutput = this.placeItemInInventory(itemToAdd, stashFS2D, sortingTableFS2D, itemLib, pmcData.Inventory, useSortingTable, output); + const errorOutput = this.placeItemInInventory( + itemToAdd, + stashFS2D, + sortingTableFS2D, + itemLib, + pmcData.Inventory, + useSortingTable, + output, + ); if (errorOutput) { return errorOutput; @@ -151,9 +175,9 @@ export class InventoryHelper catch (err) { // Callback failed - const message = typeof err === "string" - ? err - : this.localisationService.getText("http-unknown_error"); + const message = typeof err === "string" ? + err : + this.localisationService.getText("http-unknown_error"); return this.httpResponse.appendErrorToOutput(output, message); } @@ -163,7 +187,7 @@ export class InventoryHelper { let idForItemToAdd = this.hashUtil.generate(); const toDo: string[][] = [[itemToAdd.itemRef._id, idForItemToAdd]]; // WHAT IS THIS?! - let upd: Upd = { StackObjectsCount: itemToAdd.count }; + let upd: Upd = {StackObjectsCount: itemToAdd.count}; // If item being added is preset, load preset's upd data too. if (itemToAdd.isPreset) @@ -191,7 +215,7 @@ export class InventoryHelper // add ragfair upd properties if (addUpd) { - upd = { ...addUpd, ...upd }; + upd = {...addUpd, ...upd}; } // Hideout items need to be marked as found in raid @@ -200,7 +224,7 @@ export class InventoryHelper { upd.SpawnedInSession = true; } - + // Remove invalid properties prior to adding to inventory if (upd.UnlimitedCount !== undefined) { @@ -222,8 +246,8 @@ export class InventoryHelper _tpl: itemToAdd.itemRef._tpl, parentId: itemToAdd.containerId, slotId: "hideout", - location: { x: itemToAdd.location.x, y: itemToAdd.location.y, r: itemToAdd.location.rotation ? 1 : 0 }, - upd: this.jsonUtil.clone(upd) + location: {x: itemToAdd.location.x, y: itemToAdd.location.y, r: itemToAdd.location.rotation ? 1 : 0}, + upd: this.jsonUtil.clone(upd), }); pmcData.Inventory.items.push({ @@ -231,8 +255,8 @@ export class InventoryHelper _tpl: itemToAdd.itemRef._tpl, parentId: itemToAdd.containerId, slotId: "hideout", - location: { x: itemToAdd.location.x, y: itemToAdd.location.y, r: itemToAdd.location.rotation ? 1 : 0 }, - upd: this.jsonUtil.clone(upd) // Clone upd to prevent multi-purchases of same item referencing same upd object in memory + location: {x: itemToAdd.location.x, y: itemToAdd.location.y, r: itemToAdd.location.rotation ? 1 : 0}, + upd: this.jsonUtil.clone(upd), // Clone upd to prevent multi-purchases of same item referencing same upd object in memory }); if (this.itemHelper.isOfBaseclass(itemToAdd.itemRef._tpl, BaseClasses.AMMO_BOX)) @@ -255,7 +279,7 @@ export class InventoryHelper // If its from ItemPreset, load preset's upd data too. if (itemToAdd.isPreset) { - upd = { StackObjectsCount: itemToAdd.count }; + upd = {StackObjectsCount: itemToAdd.count}; for (const updID in itemLib[tmpKey].upd) { @@ -278,8 +302,9 @@ export class InventoryHelper location: { x: itemToAdd.location.x, y: itemToAdd.location.y, - r: "Horizontal" }, - upd: this.jsonUtil.clone(upd) + r: "Horizontal", + }, + upd: this.jsonUtil.clone(upd), }); pmcData.Inventory.items.push({ @@ -290,8 +315,9 @@ export class InventoryHelper location: { x: itemToAdd.location.x, y: itemToAdd.location.y, - r: "Horizontal" }, - upd: this.jsonUtil.clone(upd) + r: "Horizontal", + }, + upd: this.jsonUtil.clone(upd), }); } else @@ -310,7 +336,7 @@ export class InventoryHelper parentId: toDo[0][1], slotId: slotID, ...itemLocation, - upd: this.jsonUtil.clone(upd) + upd: this.jsonUtil.clone(upd), }); pmcData.Inventory.items.push({ @@ -319,7 +345,7 @@ export class InventoryHelper parentId: toDo[0][1], slotId: itemLib[tmpKey].slotId, ...itemLocation, - upd: this.jsonUtil.clone(upd) + upd: this.jsonUtil.clone(upd), }); this.logger.debug(`Added ${itemLib[tmpKey]._tpl} with id: ${idForItemToAdd} to inventory`); } @@ -340,13 +366,21 @@ export class InventoryHelper * @param itemToAdd Item to add to inventory * @param stashFS2D Two dimentional stash map * @param sortingTableFS2D Two dimentional sorting table stash map - * @param itemLib + * @param itemLib * @param pmcData Player profile * @param useSortingTable Should sorting table be used for overflow items when no inventory space for item * @param output Client output object * @returns Client error output if placing item failed */ - protected placeItemInInventory(itemToAdd: IAddItemTempObject, stashFS2D: number[][], sortingTableFS2D: number[][], itemLib: Item[], playerInventory: Inventory, useSortingTable: boolean, output: IItemEventRouterResponse): IItemEventRouterResponse + protected placeItemInInventory( + itemToAdd: IAddItemTempObject, + stashFS2D: number[][], + sortingTableFS2D: number[][], + itemLib: Item[], + playerInventory: Inventory, + useSortingTable: boolean, + output: IItemEventRouterResponse, + ): IItemEventRouterResponse { const itemSize = this.getItemSize(itemToAdd.itemRef._tpl, itemToAdd.itemRef._id, itemLib); @@ -360,16 +394,26 @@ export class InventoryHelper try { - stashFS2D = this.containerHelper.fillContainerMapWithItem(stashFS2D, findSlotResult.x, findSlotResult.y, itemSizeX, itemSizeY, false); // TODO: rotation not passed in, bad? + stashFS2D = this.containerHelper.fillContainerMapWithItem( + stashFS2D, + findSlotResult.x, + findSlotResult.y, + itemSizeX, + itemSizeY, + false, + ); // TODO: rotation not passed in, bad? } catch (err) { - const errorText = typeof err === "string" - ? ` -> ${err}` - : ""; + const errorText = typeof err === "string" ? + ` -> ${err}` : + ""; this.logger.error(this.localisationService.getText("inventory-fill_container_failed", errorText)); - return this.httpResponse.appendErrorToOutput(output, this.localisationService.getText("inventory-no_stash_space")); + return this.httpResponse.appendErrorToOutput( + output, + this.localisationService.getText("inventory-no_stash_space"), + ); } // Store details for object, incuding container item will be placed in itemToAdd.containerId = playerInventory.stash; @@ -377,7 +421,7 @@ export class InventoryHelper x: findSlotResult.x, y: findSlotResult.y, r: findSlotResult.rotation ? 1 : 0, - rotation: findSlotResult.rotation + rotation: findSlotResult.rotation, }; // Success! exit @@ -387,19 +431,33 @@ export class InventoryHelper // Space not found in main stash, use sorting table if (useSortingTable) { - const findSortingSlotResult = this.containerHelper.findSlotForItem(sortingTableFS2D, itemSize[0], itemSize[1]); + const findSortingSlotResult = this.containerHelper.findSlotForItem( + sortingTableFS2D, + itemSize[0], + itemSize[1], + ); const itemSizeX = findSortingSlotResult.rotation ? itemSize[1] : itemSize[0]; const itemSizeY = findSortingSlotResult.rotation ? itemSize[0] : itemSize[1]; try { - sortingTableFS2D = this.containerHelper.fillContainerMapWithItem(sortingTableFS2D, findSortingSlotResult.x, findSortingSlotResult.y, itemSizeX, itemSizeY, false); // TODO: rotation not passed in, bad? + sortingTableFS2D = this.containerHelper.fillContainerMapWithItem( + sortingTableFS2D, + findSortingSlotResult.x, + findSortingSlotResult.y, + itemSizeX, + itemSizeY, + false, + ); // TODO: rotation not passed in, bad? } catch (err) { const errorText = typeof err === "string" ? ` -> ${err}` : ""; this.logger.error(this.localisationService.getText("inventory-fill_container_failed", errorText)); - return this.httpResponse.appendErrorToOutput(output, this.localisationService.getText("inventory-no_stash_space")); + return this.httpResponse.appendErrorToOutput( + output, + this.localisationService.getText("inventory-no_stash_space"), + ); } // Store details for object, incuding container item will be placed in @@ -408,12 +466,15 @@ export class InventoryHelper x: findSortingSlotResult.x, y: findSortingSlotResult.y, r: findSortingSlotResult.rotation ? 1 : 0, - rotation: findSortingSlotResult.rotation + rotation: findSortingSlotResult.rotation, }; } else { - return this.httpResponse.appendErrorToOutput(output, this.localisationService.getText("inventory-no_stash_space")); + return this.httpResponse.appendErrorToOutput( + output, + this.localisationService.getText("inventory-no_stash_space"), + ); } } @@ -427,7 +488,14 @@ export class InventoryHelper * @param output object to send to client * @param foundInRaid should ammo be FiR */ - protected hydrateAmmoBoxWithAmmo(pmcData: IPmcData, itemToAdd: IAddItemTempObject, parentId: string, sessionID: string, output: IItemEventRouterResponse, foundInRaid: boolean): void + protected hydrateAmmoBoxWithAmmo( + pmcData: IPmcData, + itemToAdd: IAddItemTempObject, + parentId: string, + sessionID: string, + output: IItemEventRouterResponse, + foundInRaid: boolean, + ): void { const itemInfo = this.itemHelper.getItem(itemToAdd.itemRef._tpl)[1]; const stackSlots = itemInfo._props.StackSlots; @@ -450,7 +518,7 @@ export class InventoryHelper parentId: parentId, slotId: "cartridges", location: location, - upd: { StackObjectsCount: ammoStackSize } + upd: {StackObjectsCount: ammoStackSize}, }; if (foundInRaid) @@ -472,7 +540,6 @@ export class InventoryHelper } /** - * * @param assortItems Items to add to inventory * @param requestItem Details of purchased item to add to inventory * @param result Array split stacks are added to @@ -488,18 +555,21 @@ export class InventoryHelper const itemToAdd: IAddItemTempObject = { itemRef: item, count: requestItem.count, - isPreset: requestItem.isPreset }; + isPreset: requestItem.isPreset, + }; // Split stacks if the size is higher than allowed by items StackMaxSize property let maxStackCount = 1; if (requestItem.count > itemDetails._props.StackMaxSize) { let remainingCountOfItemToAdd = requestItem.count; - const calc = requestItem.count - (Math.floor(requestItem.count / itemDetails._props.StackMaxSize) * itemDetails._props.StackMaxSize); + const calc = requestItem.count - + (Math.floor(requestItem.count / itemDetails._props.StackMaxSize) * + itemDetails._props.StackMaxSize); - maxStackCount = (calc > 0) - ? maxStackCount + Math.floor(remainingCountOfItemToAdd / itemDetails._props.StackMaxSize) - : Math.floor(remainingCountOfItemToAdd / itemDetails._props.StackMaxSize); + maxStackCount = (calc > 0) ? + maxStackCount + Math.floor(remainingCountOfItemToAdd / itemDetails._props.StackMaxSize) : + Math.floor(remainingCountOfItemToAdd / itemDetails._props.StackMaxSize); // Iterate until totalCountOfPurchasedItem is 0 for (let i = 0; i < maxStackCount; i++) @@ -542,7 +612,12 @@ export class InventoryHelper * @param output Existing IItemEventRouterResponse object to append data to, creates new one by default if not supplied * @returns IItemEventRouterResponse */ - public removeItem(profile: IPmcData, itemId: string, sessionID: string, output: IItemEventRouterResponse = undefined): IItemEventRouterResponse + public removeItem( + profile: IPmcData, + itemId: string, + sessionID: string, + output: IItemEventRouterResponse = undefined, + ): IItemEventRouterResponse { if (!itemId) { @@ -559,14 +634,14 @@ export class InventoryHelper // We have output object, inform client of item deletion if (output) { - output.profileChanges[sessionID].items.del.push({ _id: itemId }); + output.profileChanges[sessionID].items.del.push({_id: itemId}); } for (const childId of itemToRemoveWithChildren) { // We expect that each inventory item and each insured item has unique "_id", respective "itemId". // Therefore we want to use a NON-Greedy function and escape the iteration as soon as we find requested item. - const inventoryIndex = inventoryItems.findIndex(item => item._id === childId); + const inventoryIndex = inventoryItems.findIndex((item) => item._id === childId); if (inventoryIndex > -1) { inventoryItems.splice(inventoryIndex, 1); @@ -574,10 +649,12 @@ export class InventoryHelper if (inventoryIndex === -1) { - this.logger.warning(`Unable to remove item with Id: ${childId} as it was not found in inventory ${profile._id}`); + this.logger.warning( + `Unable to remove item with Id: ${childId} as it was not found in inventory ${profile._id}`, + ); } - const insuredIndex = insuredItems.findIndex(item => item.itemId === childId); + const insuredIndex = insuredItems.findIndex((item) => item.itemId === childId); if (insuredIndex > -1) { insuredItems.splice(insuredIndex, 1); @@ -587,7 +664,11 @@ export class InventoryHelper return output; } - public removeItemAndChildrenFromMailRewards(sessionId: string, removeRequest: IInventoryRemoveRequestData, output: IItemEventRouterResponse): IItemEventRouterResponse + public removeItemAndChildrenFromMailRewards( + sessionId: string, + removeRequest: IInventoryRemoveRequestData, + output: IItemEventRouterResponse, + ): IItemEventRouterResponse { const fullProfile = this.profileHelper.getFullProfile(sessionId); @@ -595,18 +676,23 @@ export class InventoryHelper const dialogs = Object.values(fullProfile.dialogues); for (const dialog of dialogs) { - const messageWithReward = dialog.messages.find(x => x._id === removeRequest.fromOwner.id); + const messageWithReward = dialog.messages.find((x) => x._id === removeRequest.fromOwner.id); if (messageWithReward) { // Find item + any possible children and remove them from mails items array - const itemWithChildern = this.itemHelper.findAndReturnChildrenAsItems(messageWithReward.items.data, removeRequest.item); + const itemWithChildern = this.itemHelper.findAndReturnChildrenAsItems( + messageWithReward.items.data, + removeRequest.item, + ); for (const itemToDelete of itemWithChildern) { // Get index of item to remove from reward array + remove it const indexOfItemToRemove = messageWithReward.items.data.indexOf(itemToDelete); if (indexOfItemToRemove === -1) { - this.logger.error(`Unable to remove item: ${removeRequest.item} from mail: ${removeRequest.fromOwner.id} as item could not be found, restart client immediately to prevent data corruption`); + this.logger.error( + `Unable to remove item: ${removeRequest.item} from mail: ${removeRequest.fromOwner.id} as item could not be found, restart client immediately to prevent data corruption`, + ); continue; } messageWithReward.items.data.splice(indexOfItemToRemove, 1); @@ -622,10 +708,18 @@ export class InventoryHelper return output; } - public removeItemByCount(pmcData: IPmcData, itemId: string, count: number, sessionID: string, output: IItemEventRouterResponse = undefined): IItemEventRouterResponse + public removeItemByCount( + pmcData: IPmcData, + itemId: string, + count: number, + sessionID: string, + output: IItemEventRouterResponse = undefined, + ): IItemEventRouterResponse { if (!itemId) + { return output; + } const itemsToReduce = this.itemHelper.findAndReturnChildrenAsItems(pmcData.Inventory.items, itemId); let remainingCount = count; @@ -644,11 +738,15 @@ export class InventoryHelper itemToReduce.upd.StackObjectsCount -= remainingCount; remainingCount = 0; if (output) + { output.profileChanges[sessionID].items.change.push(itemToReduce); + } } if (remainingCount === 0) + { break; + } } return output; @@ -666,7 +764,11 @@ export class InventoryHelper // note from 2027: there IS a thing i didn't explore and that is Merges With Children // -> Prepares item Width and height returns [sizeX, sizeY] - protected getSizeByInventoryItemHash(itemTpl: string, itemID: string, inventoryItemHash: InventoryHelper.InventoryItemHash): number[] + protected getSizeByInventoryItemHash( + itemTpl: string, + itemID: string, + inventoryItemHash: InventoryHelper.InventoryItemHash, + ): number[] { const toDo = [itemID]; const result = this.itemHelper.getItem(itemTpl); @@ -681,7 +783,10 @@ export class InventoryHelper // Item found but no _props property if (tmpItem && !tmpItem._props) { - this.localisationService.getText("inventory-item_missing_props_property", {itemTpl: itemTpl, itemName: tmpItem?._name}); + this.localisationService.getText("inventory-item_missing_props_property", { + itemTpl: itemTpl, + itemName: tmpItem?._name, + }); } // No item object or getItem() returned false @@ -711,11 +816,11 @@ export class InventoryHelper const skipThisItems: string[] = [ BaseClasses.BACKPACK, BaseClasses.SEARCHABLE_ITEM, - BaseClasses.SIMPLE_CONTAINER + BaseClasses.SIMPLE_CONTAINER, ]; const rootFolded = rootItem.upd?.Foldable && rootItem.upd.Foldable.Folded === true; - //The item itself is collapsible + // The item itself is collapsible if (foldableWeapon && (foldedSlot === undefined || foldedSlot === "") && rootFolded) { outX -= tmpItem._props.SizeReduceRight; @@ -729,7 +834,7 @@ export class InventoryHelper { for (const item of inventoryItemHash.byParentId[toDo[0]]) { - //Filtering child items outside of mod slots, such as those inside containers, without counting their ExtraSize attribute + // Filtering child items outside of mod slots, such as those inside containers, without counting their ExtraSize attribute if (item.slotId.indexOf("mod_") < 0) { continue; @@ -741,7 +846,12 @@ export class InventoryHelper const itemResult = this.itemHelper.getItem(item._tpl); if (!itemResult[0]) { - this.logger.error(this.localisationService.getText("inventory-get_item_size_item_not_found_by_tpl", item._tpl)); + this.logger.error( + this.localisationService.getText( + "inventory-get_item_size_item_not_found_by_tpl", + item._tpl, + ), + ); } const itm = itemResult[1]; @@ -781,7 +891,7 @@ export class InventoryHelper return [ outX + sizeLeft + sizeRight + forcedLeft + forcedRight, - outY + sizeUp + sizeDown + forcedUp + forcedDown + outY + sizeUp + sizeDown + forcedUp + forcedDown, ]; } @@ -789,7 +899,7 @@ export class InventoryHelper { const inventoryItemHash: InventoryHelper.InventoryItemHash = { byItemId: {}, - byParentId: {} + byParentId: {}, }; for (const item of inventoryItem) @@ -832,8 +942,14 @@ export class InventoryHelper const tmpSize = this.getSizeByInventoryItemHash(item._tpl, item._id, inventoryItemHash); const iW = tmpSize[0]; // x const iH = tmpSize[1]; // y - const fH = (((item.location as Location).r === 1 || (item.location as Location).r === "Vertical" || (item.location as Location).rotation === "Vertical") ? iW : iH); - const fW = (((item.location as Location).r === 1 || (item.location as Location).r === "Vertical" || (item.location as Location).rotation === "Vertical") ? iH : iW); + const fH = ((item.location as Location).r === 1 || (item.location as Location).r === "Vertical" || + (item.location as Location).rotation === "Vertical") ? + iW : + iH; + const fW = ((item.location as Location).r === 1 || (item.location as Location).r === "Vertical" || + (item.location as Location).rotation === "Vertical") ? + iH : + iW; const fillTo = (item.location as Location).x + fW; for (let y = 0; y < fH; y++) @@ -844,7 +960,12 @@ export class InventoryHelper } catch (e) { - this.logger.error(this.localisationService.getText("inventory-unable_to_fill_container", {id: item._id, error: e})); + this.logger.error( + this.localisationService.getText("inventory-unable_to_fill_container", { + id: item._id, + error: e, + }), + ); } } } @@ -860,7 +981,10 @@ export class InventoryHelper * @param sessionId Session id / playerid * @returns OwnerInventoryItems with inventory of player/scav to adjust */ - public getOwnerInventoryItems(request: IInventoryMoveRequestData | IInventorySplitRequestData | IInventoryMergeRequestData, sessionId: string): OwnerInventoryItems + public getOwnerInventoryItems( + request: IInventoryMoveRequestData | IInventorySplitRequestData | IInventoryMergeRequestData, + sessionId: string, + ): OwnerInventoryItems { let isSameInventory = false; const pmcItems = this.profileHelper.getPmcProfile(sessionId).Inventory.items; @@ -878,9 +1002,9 @@ export class InventoryHelper else if (request.fromOwner.type.toLocaleLowerCase() === "mail") { // Split requests dont use 'use' but 'splitItem' property - const item = "splitItem" in request - ? request.splitItem - : request.item; + const item = "splitItem" in request ? + request.splitItem : + request.item; fromInventoryItems = this.dialogueHelper.getMessageItemContents(request.fromOwner.id, sessionId, item); fromType = "mail"; } @@ -908,7 +1032,7 @@ export class InventoryHelper from: fromInventoryItems, to: toInventoryItems, sameInventory: isSameInventory, - isMail: fromType === "mail" + isMail: fromType === "mail", }; } @@ -921,7 +1045,12 @@ export class InventoryHelper protected getStashSlotMap(pmcData: IPmcData, sessionID: string): number[][] { const playerStashSize = this.getPlayerStashSize(sessionID); - return this.getContainerMap(playerStashSize[0], playerStashSize[1], pmcData.Inventory.items, pmcData.Inventory.stash); + return this.getContainerMap( + playerStashSize[0], + playerStashSize[1], + pmcData.Inventory.items, + pmcData.Inventory.stash, + ); } protected getSortingTableSlotMap(pmcData: IPmcData): number[][] @@ -936,7 +1065,7 @@ export class InventoryHelper */ protected getPlayerStashSize(sessionID: string): Record { - //this sets automatically a stash size from items.json (its not added anywhere yet cause we still use base stash) + // this sets automatically a stash size from items.json (its not added anywhere yet cause we still use base stash) const stashTPL = this.getStashType(sessionID); if (!stashTPL) { @@ -948,12 +1077,12 @@ export class InventoryHelper this.logger.error(this.localisationService.getText("inventory-stash_not_found", stashTPL)); } - const stashX = stashItemDetails[1]._props.Grids[0]._props.cellsH !== 0 - ? stashItemDetails[1]._props.Grids[0]._props.cellsH - : 10; - const stashY = stashItemDetails[1]._props.Grids[0]._props.cellsV !== 0 - ? stashItemDetails[1]._props.Grids[0]._props.cellsV - : 66; + const stashX = stashItemDetails[1]._props.Grids[0]._props.cellsH !== 0 ? + stashItemDetails[1]._props.Grids[0]._props.cellsH : + 10; + const stashY = stashItemDetails[1]._props.Grids[0]._props.cellsV !== 0 ? + stashItemDetails[1]._props.Grids[0]._props.cellsV : + 66; return [stashX, stashY]; } @@ -965,7 +1094,7 @@ export class InventoryHelper protected getStashType(sessionID: string): string { const pmcData = this.profileHelper.getPmcProfile(sessionID); - const stashObj = pmcData.Inventory.items.find(item => item._id === pmcData.Inventory.stash); + const stashObj = pmcData.Inventory.items.find((item) => item._id === pmcData.Inventory.stash); if (!stashObj) { this.logger.error(this.localisationService.getText("inventory-unable_to_find_stash")); @@ -987,7 +1116,7 @@ export class InventoryHelper const idsToMove = this.itemHelper.findAndReturnChildrenByItems(fromItems, body.item); for (const itemId of idsToMove) { - const itemToMove = fromItems.find(x => x._id === itemId); + const itemToMove = fromItems.find((x) => x._id === itemId); if (!itemToMove) { this.logger.error(`Unable to find item to move: ${itemId}`); @@ -1022,16 +1151,20 @@ export class InventoryHelper /** * Internal helper function to move item within the same profile_f. * @param pmcData profile to edit - * @param inventoryItems - * @param moveRequest + * @param inventoryItems + * @param moveRequest * @returns True if move was successful */ - public moveItemInternal(pmcData: IPmcData, inventoryItems: Item[], moveRequest: IInventoryMoveRequestData): {success: boolean, errorMessage?: string} + public moveItemInternal( + pmcData: IPmcData, + inventoryItems: Item[], + moveRequest: IInventoryMoveRequestData, + ): {success: boolean; errorMessage?: string;} { this.handleCartridges(inventoryItems, moveRequest); // Find item we want to 'move' - const matchingInventoryItem = inventoryItems.find(x => x._id === moveRequest.item); + const matchingInventoryItem = inventoryItems.find((x) => x._id === moveRequest.item); if (!matchingInventoryItem) { const errorMesage = `Unable to move item: ${moveRequest.item}, cannot find in inventory`; @@ -1040,12 +1173,19 @@ export class InventoryHelper return {success: false, errorMessage: errorMesage}; } - this.logger.debug(`${moveRequest.Action} item: ${moveRequest.item} from slotid: ${matchingInventoryItem.slotId} to container: ${moveRequest.to.container}`); + this.logger.debug( + `${moveRequest.Action} item: ${moveRequest.item} from slotid: ${matchingInventoryItem.slotId} to container: ${moveRequest.to.container}`, + ); // don't move shells from camora to cartridges (happens when loading shells into mts-255 revolver shotgun) if (matchingInventoryItem.slotId.includes("camora_") && moveRequest.to.container === "cartridges") { - this.logger.warning(this.localisationService.getText("inventory-invalid_move_to_container", {slotId: matchingInventoryItem.slotId, container: moveRequest.to.container})); + this.logger.warning( + this.localisationService.getText("inventory-invalid_move_to_container", { + slotId: matchingInventoryItem.slotId, + container: moveRequest.to.container, + }), + ); return {success: true}; } @@ -1059,7 +1199,6 @@ export class InventoryHelper if ("location" in moveRequest.to) { matchingInventoryItem.location = moveRequest.to.location; - } else { @@ -1085,8 +1224,8 @@ export class InventoryHelper if (pmcData.Inventory.fastPanel[itemKey] === itemBeingMoved._id) { // Get moved items parent - const itemParent = pmcData.Inventory.items.find(x => x._id === itemBeingMoved.parentId); - + const itemParent = pmcData.Inventory.items.find((x) => x._id === itemBeingMoved.parentId); + // Empty out id if item is moved to a container other than pocket/rig if (itemParent && !(itemParent.slotId?.startsWith("Pockets") || itemParent.slotId === "TacticalVest")) { @@ -1099,8 +1238,8 @@ export class InventoryHelper } /** - * Internal helper function to handle cartridges in inventory if any of them exist. - */ + * Internal helper function to handle cartridges in inventory if any of them exist. + */ protected handleCartridges(items: Item[], body: IInventoryMoveRequestData): void { // -> Move item to different place - counts with equipping filling magazine etc @@ -1140,7 +1279,7 @@ namespace InventoryHelper { export interface InventoryItemHash { - byItemId: Record - byParentId: Record + byItemId: Record; + byParentId: Record; } -} \ No newline at end of file +} diff --git a/project/src/helpers/ItemHelper.ts b/project/src/helpers/ItemHelper.ts index 2de92170..f0451687 100644 --- a/project/src/helpers/ItemHelper.ts +++ b/project/src/helpers/ItemHelper.ts @@ -29,7 +29,7 @@ class ItemHelper BaseClasses.SORTING_TABLE, BaseClasses.INVENTORY, BaseClasses.STATIONARY_CONTAINER, - BaseClasses.POCKETS + BaseClasses.POCKETS, ]; constructor( @@ -44,7 +44,7 @@ class ItemHelper @inject("ItemBaseClassService") protected itemBaseClassService: ItemBaseClassService, @inject("ItemFilterService") protected itemFilterService: ItemFilterService, @inject("LocalisationService") protected localisationService: LocalisationService, - @inject("LocaleService") protected localeService: LocaleService + @inject("LocaleService") protected localeService: LocaleService, ) {} @@ -68,11 +68,11 @@ class ItemHelper } // Is item valid - return !itemDetails[1]._props.QuestItem - && itemDetails[1]._type === "Item" - && invalidBaseTypes.every(x => !this.isOfBaseclass(tpl, x)) - && this.getItemPrice(tpl) > 0 - && !this.itemFilterService.isItemBlacklisted(tpl); + return !itemDetails[1]._props.QuestItem && + itemDetails[1]._type === "Item" && + invalidBaseTypes.every((x) => !this.isOfBaseclass(tpl, x)) && + this.getItemPrice(tpl) > 0 && + !this.itemFilterService.isItemBlacklisted(tpl); } /** @@ -177,7 +177,7 @@ class ItemHelper if (item.upd === undefined) { item.upd = { - StackObjectsCount: 1 + StackObjectsCount: 1, }; } @@ -244,8 +244,8 @@ class ItemHelper slotId: slotId, location: 0, upd: { - StackObjectsCount: count - } + StackObjectsCount: count, + }, }; stackSlotItems.push(stackSlotItem); } @@ -352,7 +352,6 @@ class ItemHelper return result; } - /** * Get a quality value based on a repairable items (weapon/armor) current state between current and max durability * @param itemDetails Db details for item we want quality value for @@ -365,7 +364,9 @@ class ItemHelper // Edge case, max durability is below durability if (repairable.Durability > repairable.MaxDurability) { - this.logger.warning(`Max durability: ${repairable.MaxDurability} for item id: ${item._id} was below Durability: ${repairable.Durability}, adjusting values to match`); + this.logger.warning( + `Max durability: ${repairable.MaxDurability} for item id: ${item._id} was below Durability: ${repairable.Durability}, adjusting values to match`, + ); repairable.MaxDurability = repairable.Durability; } @@ -377,9 +378,9 @@ class ItemHelper // Weapon // Get max dura from props, if it isnt there use repairable max dura value - const maxDurability = (itemDetails._props.MaxDurability) - ? itemDetails._props.MaxDurability - : repairable.MaxDurability; + const maxDurability = (itemDetails._props.MaxDurability) ? + itemDetails._props.MaxDurability : + repairable.MaxDurability; const durability = repairable.Durability / maxDurability; if (!durability) @@ -434,7 +435,7 @@ class ItemHelper continue; } - if (childItem.parentId === baseItemId && !list.find(item => childItem._id === item._id)) + if (childItem.parentId === baseItemId && !list.find((item) => childItem._id === item._id)) { list.push(...this.findAndReturnChildrenAsItems(items, childItem._id)); } @@ -455,7 +456,7 @@ class ItemHelper for (const itemFromAssort of assort) { - if (itemFromAssort.parentId === itemIdToFind && !list.find(item => itemFromAssort._id === item._id)) + if (itemFromAssort.parentId === itemIdToFind && !list.find((item) => itemFromAssort._id === item._id)) { list.push(itemFromAssort); list = list.concat(this.findAndReturnChildrenByAssort(itemFromAssort._id, assort)); @@ -472,8 +473,10 @@ class ItemHelper */ public hasBuyRestrictions(itemToCheck: Item): boolean { - if (itemToCheck.upd?.BuyRestrictionCurrent !== undefined - && itemToCheck.upd?.BuyRestrictionMax !== undefined) + if ( + itemToCheck.upd?.BuyRestrictionCurrent !== undefined && + itemToCheck.upd?.BuyRestrictionMax !== undefined + ) { return true; } @@ -571,18 +574,18 @@ class ItemHelper public findBarterItems(by: "tpl" | "id", items: Item[], barterItemId: string): Item[] { // find required items to take after buying (handles multiple items) - const barterIDs = typeof barterItemId === "string" - ? [barterItemId] - : barterItemId; + const barterIDs = typeof barterItemId === "string" ? + [barterItemId] : + barterItemId; let barterItems: Item[] = []; for (const barterID of barterIDs) { - const filterResult = items.filter(item => + const filterResult = items.filter((item) => { - return by === "tpl" - ? (item._tpl === barterID) - : (item._id === barterID); + return by === "tpl" ? + (item._tpl === barterID) : + (item._id === barterID); }); barterItems = Object.assign(barterItems, filterResult); @@ -615,17 +618,19 @@ class ItemHelper { // Insured items shouldn't be renamed // only works for pmcs. - if (insuredItems?.find(insuredItem => insuredItem.itemId === item._id)) + if (insuredItems?.find((insuredItem) => insuredItem.itemId === item._id)) { continue; } // Do not replace important ID's - if (item._id === pmcData.Inventory.equipment - || item._id === pmcData.Inventory.questRaidItems - || item._id === pmcData.Inventory.questStashItems - || item._id === pmcData.Inventory.sortingTable - || item._id === pmcData.Inventory.stash) + if ( + item._id === pmcData.Inventory.equipment || + item._id === pmcData.Inventory.questRaidItems || + item._id === pmcData.Inventory.questStashItems || + item._id === pmcData.Inventory.sortingTable || + item._id === pmcData.Inventory.stash + ) { continue; } @@ -804,7 +809,9 @@ class ItemHelper let isRequiredSlot = false; if (parentTemplate[0] && parentTemplate[1]?._props?.Slots) { - isRequiredSlot = parentTemplate[1]._props.Slots.some(slot => slot._name === item.slotId && slot._required); + isRequiredSlot = parentTemplate[1]._props.Slots.some((slot) => + slot._name === item.slotId && slot._required + ); } return itemTemplate[0] && parentTemplate[0] && !(isNotRaidModdable || isRequiredSlot); @@ -865,7 +872,7 @@ class ItemHelper */ public getItemSize(items: Item[], rootItemId: string): ItemHelper.ItemSize { - const rootTemplate = this.getItem(items.filter(x => x._id === rootItemId)[0]._tpl)[1]; + const rootTemplate = this.getItem(items.filter((x) => x._id === rootItemId)[0]._tpl)[1]; const width = rootTemplate._props.Width; const height = rootTemplate._props.Height; @@ -897,13 +904,15 @@ class ItemHelper sizeUp = sizeUp < itemTemplate._props.ExtraSizeUp ? itemTemplate._props.ExtraSizeUp : sizeUp; sizeDown = sizeDown < itemTemplate._props.ExtraSizeDown ? itemTemplate._props.ExtraSizeDown : sizeDown; sizeLeft = sizeLeft < itemTemplate._props.ExtraSizeLeft ? itemTemplate._props.ExtraSizeLeft : sizeLeft; - sizeRight = sizeRight < itemTemplate._props.ExtraSizeRight ? itemTemplate._props.ExtraSizeRight : sizeRight; + sizeRight = sizeRight < itemTemplate._props.ExtraSizeRight ? + itemTemplate._props.ExtraSizeRight : + sizeRight; } } return { width: width + sizeLeft + sizeRight + forcedLeft + forcedRight, - height: height + sizeUp + sizeDown + forcedUp + forcedDown + height: height + sizeUp + sizeDown + forcedUp + forcedDown, }; } @@ -945,15 +954,15 @@ class ItemHelper while (currentStoredCartridgeCount < ammoBoxMaxCartridgeCount) { const remainingSpace = ammoBoxMaxCartridgeCount - currentStoredCartridgeCount; - const cartridgeCountToAdd = (remainingSpace < maxPerStack) - ? remainingSpace - : maxPerStack; + const cartridgeCountToAdd = (remainingSpace < maxPerStack) ? + remainingSpace : + maxPerStack; // Add cartridge item into items array ammoBox.push(this.createCartridges(ammoBox[0]._id, cartridgeTpl, cartridgeCountToAdd, location)); currentStoredCartridgeCount += cartridgeCountToAdd; - location ++; + location++; } } @@ -967,7 +976,7 @@ class ItemHelper public itemIsInsideContainer(item: Item, desiredContainerSlotId: string, items: Item[]): boolean { // Get items parent - const parent = items.find(x => x._id === item.parentId); + const parent = items.find((x) => x._id === item.parentId); if (!parent) { // No parent, end of line, not inside container @@ -997,7 +1006,7 @@ class ItemHelper magTemplate: ITemplateItem, staticAmmoDist: Record, caliber: string = undefined, - minSizePercent = 0.25 + minSizePercent = 0.25, ): void { // no caliber defined, choose one at random @@ -1028,7 +1037,7 @@ class ItemHelper magazine: Item[], magTemplate: ITemplateItem, cartridgeTpl: string, - minSizePercent = 0.25 + minSizePercent = 0.25, ): void { // Get cartrdge properties and max allowed stack size @@ -1037,7 +1046,10 @@ class ItemHelper // Get max number of cartridges in magazine, choose random value between min/max const magazineCartridgeMaxCount = magTemplate._props.Cartridges[0]._max_count; - const desiredStackCount = this.randomUtil.getInt(Math.round(minSizePercent * magazineCartridgeMaxCount), magazineCartridgeMaxCount); + const desiredStackCount = this.randomUtil.getInt( + Math.round(minSizePercent * magazineCartridgeMaxCount), + magazineCartridgeMaxCount, + ); // Loop over cartridge count and add stacks to magazine let currentStoredCartridgeCount = 0; @@ -1045,9 +1057,9 @@ class ItemHelper while (currentStoredCartridgeCount < desiredStackCount) { // Get stack size of cartridges - let cartridgeCountToAdd = (desiredStackCount <= cartridgeMaxStackSize) - ? desiredStackCount - : cartridgeMaxStackSize; + let cartridgeCountToAdd = (desiredStackCount <= cartridgeMaxStackSize) ? + desiredStackCount : + cartridgeMaxStackSize; // Ensure we don't go over the max stackcount size const remainingSpace = desiredStackCount - currentStoredCartridgeCount; @@ -1060,7 +1072,7 @@ class ItemHelper magazine.push(this.createCartridges(magazine[0]._id, cartridgeTpl, cartridgeCountToAdd, location)); currentStoredCartridgeCount += cartridgeCountToAdd; - location ++; + location++; } } @@ -1075,11 +1087,11 @@ class ItemHelper const calibers = [ ...new Set( ammoTpls.filter( - (x: string) => this.getItem(x)[0] + (x: string) => this.getItem(x)[0], ).map( - (x: string) => this.getItem(x)[1]._props.Caliber - ) - ) + (x: string) => this.getItem(x)[1]._props.Caliber, + ), + ), ]; return this.randomUtil.drawRandomFromList(calibers)[0]; } @@ -1096,7 +1108,7 @@ class ItemHelper for (const icd of staticAmmoDist[caliber]) { ammoArray.push( - new ProbabilityObject(icd.tpl, icd.relativeProbability) + new ProbabilityObject(icd.tpl, icd.relativeProbability), ); } return ammoArray.draw(1)[0]; @@ -1118,7 +1130,7 @@ class ItemHelper parentId: parentId, slotId: "cartridges", location: location, - upd: { StackObjectsCount: stackCount } + upd: {StackObjectsCount: stackCount}, }; } @@ -1149,7 +1161,9 @@ class ItemHelper public getItemTplsOfBaseType(desiredBaseType: string): string[] { - return Object.values(this.databaseServer.getTables().templates.items).filter(x => x._parent === desiredBaseType).map(x =>x._id); + return Object.values(this.databaseServer.getTables().templates.items).filter((x) => + x._parent === desiredBaseType + ).map((x) => x._id); } } @@ -1157,10 +1171,9 @@ namespace ItemHelper { export interface ItemSize { - width: number - height: number + width: number; + height: number; } } -export { ItemHelper }; - +export {ItemHelper}; diff --git a/project/src/helpers/NotificationSendHelper.ts b/project/src/helpers/NotificationSendHelper.ts index 32e81201..f70a6290 100644 --- a/project/src/helpers/NotificationSendHelper.ts +++ b/project/src/helpers/NotificationSendHelper.ts @@ -16,14 +16,14 @@ export class NotificationSendHelper @inject("WebSocketServer") protected webSocketServer: WebSocketServer, @inject("HashUtil") protected hashUtil: HashUtil, @inject("SaveServer") protected saveServer: SaveServer, - @inject("NotificationService") protected notificationService: NotificationService + @inject("NotificationService") protected notificationService: NotificationService, ) {} /** * Send notification message to the appropriate channel - * @param sessionID - * @param notificationMessage + * @param sessionID + * @param notificationMessage */ public sendMessage(sessionID: string, notificationMessage: INotification): void { @@ -44,7 +44,12 @@ export class NotificationSendHelper * @param messageText Text to send player * @param messageType Underlying type of message being sent */ - public sendMessageToPlayer(sessionId: string, senderDetails: IUserDialogInfo, messageText: string, messageType: MessageType): void + public sendMessageToPlayer( + sessionId: string, + senderDetails: IUserDialogInfo, + messageText: string, + messageType: MessageType, + ): void { const dialog = this.getDialog(sessionId, messageType, senderDetails); @@ -57,7 +62,7 @@ export class NotificationSendHelper text: messageText, hasRewards: undefined, rewardCollected: undefined, - items: undefined + items: undefined, }; dialog.messages.push(message); @@ -65,7 +70,7 @@ export class NotificationSendHelper type: NotificationType.NEW_MESSAGE, eventId: message._id, dialogId: message.uid, - message: message + message: message, }; this.sendMessage(sessionId, notification); } @@ -80,7 +85,9 @@ export class NotificationSendHelper protected getDialog(sessionId: string, messageType: MessageType, senderDetails: IUserDialogInfo): Dialogue { // Use trader id if sender is trader, otherwise use nickname - const key = (senderDetails.info.MemberCategory === MemberCategory.TRADER) ? senderDetails._id : senderDetails.info.Nickname; + const key = (senderDetails.info.MemberCategory === MemberCategory.TRADER) ? + senderDetails._id : + senderDetails.info.Nickname; const dialogueData = this.saveServer.getProfile(sessionId).dialogues; const isNewDialogue = !(key in dialogueData); let dialogue: Dialogue = dialogueData[key]; @@ -95,11 +102,11 @@ export class NotificationSendHelper pinned: false, new: 0, attachmentsNew: 0, - Users: (senderDetails.info.MemberCategory === MemberCategory.TRADER) ? undefined : [senderDetails] + Users: (senderDetails.info.MemberCategory === MemberCategory.TRADER) ? undefined : [senderDetails], }; dialogueData[key] = dialogue; } return dialogue; } -} \ No newline at end of file +} diff --git a/project/src/helpers/NotifierHelper.ts b/project/src/helpers/NotifierHelper.ts index d4acdf13..4f340086 100644 --- a/project/src/helpers/NotifierHelper.ts +++ b/project/src/helpers/NotifierHelper.ts @@ -12,11 +12,11 @@ export class NotifierHelper */ protected defaultNotification: INotification = { type: NotificationType.PING, - eventId: "ping" + eventId: "ping", }; constructor( - @inject("HttpServerHelper") protected httpServerHelper: HttpServerHelper + @inject("HttpServerHelper") protected httpServerHelper: HttpServerHelper, ) {} @@ -29,22 +29,25 @@ export class NotifierHelper * Create a new notification that displays the "Your offer was sold!" prompt and removes sold offer from "My Offers" on clientside * @param dialogueMessage Message from dialog that was sent * @param ragfairData Ragfair data to attach to notification - * @returns + * @returns */ - public createRagfairOfferSoldNotification(dialogueMessage: Message, ragfairData: MessageContentRagfair): INotification + public createRagfairOfferSoldNotification( + dialogueMessage: Message, + ragfairData: MessageContentRagfair, + ): INotification { return { type: NotificationType.RAGFAIR_OFFER_SOLD, eventId: dialogueMessage._id, dialogId: dialogueMessage.uid, - ...ragfairData + ...ragfairData, }; } /** * Create a new notification with the specified dialogueMessage object - * @param dialogueMessage - * @returns + * @param dialogueMessage + * @returns */ public createNewMessageNotification(dialogueMessage: Message): INotification { @@ -52,7 +55,7 @@ export class NotifierHelper type: NotificationType.NEW_MESSAGE, eventId: dialogueMessage._id, dialogId: dialogueMessage.uid, - message: dialogueMessage + message: dialogueMessage, }; } @@ -60,4 +63,4 @@ export class NotifierHelper { return `${this.httpServerHelper.getWebsocketUrl()}/notifierServer/getwebsocket/${sessionID}`; } -} \ No newline at end of file +} diff --git a/project/src/helpers/PaymentHelper.ts b/project/src/helpers/PaymentHelper.ts index e49e4521..a835ab31 100644 --- a/project/src/helpers/PaymentHelper.ts +++ b/project/src/helpers/PaymentHelper.ts @@ -11,7 +11,7 @@ export class PaymentHelper protected inventoryConfig: IInventoryConfig; constructor( - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.inventoryConfig = this.configServer.getConfig(ConfigTypes.INVENTORY); @@ -24,14 +24,16 @@ export class PaymentHelper */ public isMoneyTpl(tpl: string): boolean { - return [Money.DOLLARS, Money.EUROS, Money.ROUBLES, ...this.inventoryConfig.customMoneyTpls].some(element => element === tpl); + return [Money.DOLLARS, Money.EUROS, Money.ROUBLES, ...this.inventoryConfig.customMoneyTpls].some((element) => + element === tpl + ); } /** - * Gets currency TPL from TAG - * @param {string} currency - * @returns string - */ + * Gets currency TPL from TAG + * @param {string} currency + * @returns string + */ public getCurrency(currency: string): string { switch (currency) @@ -46,4 +48,4 @@ export class PaymentHelper return ""; } } -} \ No newline at end of file +} diff --git a/project/src/helpers/PresetHelper.ts b/project/src/helpers/PresetHelper.ts index f48b8767..c973fd98 100644 --- a/project/src/helpers/PresetHelper.ts +++ b/project/src/helpers/PresetHelper.ts @@ -12,9 +12,9 @@ export class PresetHelper constructor( @inject("JsonUtil") protected jsonUtil: JsonUtil, - @inject("DatabaseServer") protected databaseServer: DatabaseServer + @inject("DatabaseServer") protected databaseServer: DatabaseServer, ) - { } + {} public hydratePresetStore(input: Record): void { @@ -26,7 +26,7 @@ export class PresetHelper if (!this.defaultPresets) { this.defaultPresets = Object.values(this.databaseServer.getTables().globals.ItemPresets) - .filter(x => x._encyclopedia !== undefined) + .filter((x) => x._encyclopedia !== undefined) .reduce((acc, cur) => { acc[cur._id] = cur; @@ -112,4 +112,4 @@ export class PresetHelper return ""; } -} \ No newline at end of file +} diff --git a/project/src/helpers/ProbabilityHelper.ts b/project/src/helpers/ProbabilityHelper.ts index f00963e3..f2815447 100644 --- a/project/src/helpers/ProbabilityHelper.ts +++ b/project/src/helpers/ProbabilityHelper.ts @@ -8,9 +8,9 @@ export class ProbabilityHelper { constructor( @inject("WinstonLogger") protected logger: ILogger, - @inject("RandomUtil") protected randomUtil: RandomUtil + @inject("RandomUtil") protected randomUtil: RandomUtil, ) - { } + {} /** * Chance to roll a number out of 100 @@ -20,6 +20,6 @@ export class ProbabilityHelper */ public rollChance(chance: number, scale = 1): boolean { - return (this.randomUtil.getInt(1, 100 * scale)/ (1 * scale)) <= chance; + return (this.randomUtil.getInt(1, 100 * scale) / (1 * scale)) <= chance; } -} \ No newline at end of file +} diff --git a/project/src/helpers/ProfileHelper.ts b/project/src/helpers/ProfileHelper.ts index 74576d48..f852b50c 100644 --- a/project/src/helpers/ProfileHelper.ts +++ b/project/src/helpers/ProfileHelper.ts @@ -27,9 +27,9 @@ export class ProfileHelper @inject("DatabaseServer") protected databaseServer: DatabaseServer, @inject("ItemHelper") protected itemHelper: ItemHelper, @inject("ProfileSnapshotService") protected profileSnapshotService: ProfileSnapshotService, - @inject("LocalisationService") protected localisationService: LocalisationService + @inject("LocalisationService") protected localisationService: LocalisationService, ) - { } + {} /** * Remove/reset a completed quest condtion from players profile quest data @@ -41,7 +41,7 @@ export class ProfileHelper for (const questId in questConditionId) { const conditionId = questConditionId[questId]; - const profileQuest = pmcData.Quests.find(x => x.qid === questId); + const profileQuest = pmcData.Quests.find((x) => x.qid === questId); // Find index of condition in array const index = profileQuest.completedConditions.indexOf(conditionId); @@ -51,7 +51,7 @@ export class ProfileHelper profileQuest.completedConditions.splice(index, 1); } } - } + } /** * Get all profiles from server @@ -97,7 +97,12 @@ export class ProfileHelper * @param scavProfile post-raid scav profile * @returns updated profile array */ - protected postRaidXpWorkaroundFix(sessionId: string, output: IPmcData[], pmcProfile: IPmcData, scavProfile: IPmcData): IPmcData[] + protected postRaidXpWorkaroundFix( + sessionId: string, + output: IPmcData[], + pmcProfile: IPmcData, + scavProfile: IPmcData, + ): IPmcData[] { const clonedPmc = this.jsonUtil.clone(pmcProfile); const clonedScav = this.jsonUtil.clone(scavProfile); @@ -119,7 +124,7 @@ export class ProfileHelper /** * Check if a nickname is used by another profile loaded by the server - * @param nicknameRequest + * @param nicknameRequest * @param sessionID Session id * @returns True if already used */ @@ -133,8 +138,10 @@ export class ProfileHelper continue; } - if (!this.sessionIdMatchesProfileId(profile.info.id, sessionID) - && this.nicknameMatches(profile.characters.pmc.Info.LowerNickname, nicknameRequest.nickname)) + if ( + !this.sessionIdMatchesProfileId(profile.info.id, sessionID) && + this.nicknameMatches(profile.characters.pmc.Info.LowerNickname, nicknameRequest.nickname) + ) { return true; } @@ -211,7 +218,7 @@ export class ProfileHelper public getDefaultAkiDataObject(): any { return { - version: this.getServerVersion() + version: this.getServerVersion(), }; } @@ -221,10 +228,10 @@ export class ProfileHelper { return undefined; } - + return this.saveServer.getProfile(sessionID); } - + public getPmcProfile(sessionID: string): IPmcData { const fullProfile = this.getFullProfile(sessionID); @@ -232,10 +239,10 @@ export class ProfileHelper { return undefined; } - + return this.saveServer.getProfile(sessionID).characters.pmc; } - + public getScavProfile(sessionID: string): IPmcData { return this.saveServer.getProfile(sessionID).characters.scav; @@ -253,24 +260,24 @@ export class ProfileHelper DamageHistory: { LethalDamagePart: "Head", LethalDamage: undefined, - BodyParts: [] + BodyParts: [], }, DroppedItems: [], ExperienceBonusMult: 0, FoundInRaidItems: [], LastPlayerState: undefined, LastSessionDate: 0, - OverallCounters: { Items: [] }, - SessionCounters: { Items: [] }, + OverallCounters: {Items: []}, + SessionCounters: {Items: []}, SessionExperienceMult: 0, SurvivorClass: "Unknown", TotalInGameTime: 0, TotalSessionExperience: 0, - Victims: [] - } + Victims: [], + }, }; } - + protected isWiped(sessionID: string): boolean { return this.saveServer.getProfile(sessionID).info.wipe; @@ -289,14 +296,17 @@ export class ProfileHelper public removeSecureContainer(profile: IPmcData): IPmcData { const items = profile.Inventory.items; - const secureContainer = items.find(x => x.slotId === "SecuredContainer"); + const secureContainer = items.find((x) => x.slotId === "SecuredContainer"); if (secureContainer) { // Find and remove container + children - const childItemsInSecureContainer = this.itemHelper.findAndReturnChildrenByItems(items, secureContainer._id); + const childItemsInSecureContainer = this.itemHelper.findAndReturnChildrenByItems( + items, + secureContainer._id, + ); // Remove child items + secure container - profile.Inventory.items = items.filter(x => !childItemsInSecureContainer.includes(x._id)); + profile.Inventory.items = items.filter((x) => !childItemsInSecureContainer.includes(x._id)); } return profile; @@ -340,7 +350,7 @@ export class ProfileHelper return false; } - return !!profile.aki.receivedGifts.find(x => x.giftId === giftId); + return !!profile.aki.receivedGifts.find((x) => x.giftId === giftId); } /** @@ -350,7 +360,7 @@ export class ProfileHelper */ public incrementStatCounter(counters: CounterKeyValue[], keyToIncrement: string): void { - const stat = counters.find(x => x.Key.includes(keyToIncrement)); + const stat = counters.find((x) => x.Key.includes(keyToIncrement)); if (stat) { stat.Value++; @@ -371,7 +381,7 @@ export class ProfileHelper return false; } - const profileSkill = profileSkills.find(x => x.Id === skillType); + const profileSkill = profileSkills.find((x) => x.Id === skillType); if (!profileSkill) { this.logger.warning(`Unable to check for elite skill ${skillType}, not found in profile`); @@ -387,13 +397,20 @@ export class ProfileHelper * @param pointsToAdd Points to add * @param pmcProfile Player profile with skill * @param useSkillProgressRateMultipler Skills are multiplied by a value in globals, default is off to maintain compatibility with legacy code - * @returns + * @returns */ - public addSkillPointsToPlayer(pmcProfile: IPmcData, skill: SkillTypes, pointsToAdd: number, useSkillProgressRateMultipler = false): void + public addSkillPointsToPlayer( + pmcProfile: IPmcData, + skill: SkillTypes, + pointsToAdd: number, + useSkillProgressRateMultipler = false, + ): void { if (!pointsToAdd || pointsToAdd < 0) { - this.logger.error(this.localisationService.getText("player-attempt_to_increment_skill_with_negative_value", skill)); + this.logger.error( + this.localisationService.getText("player-attempt_to_increment_skill_with_negative_value", skill), + ); return; } @@ -405,7 +422,7 @@ export class ProfileHelper return; } - const profileSkill = profileSkills.find(x => x.Id === skill); + const profileSkill = profileSkills.find((x) => x.Id === skill); if (!profileSkill) { this.logger.error(this.localisationService.getText("quest-no_skill_found", skill)); @@ -426,7 +443,7 @@ export class ProfileHelper public getSkillFromProfile(pmcData: IPmcData, skill: SkillTypes): Common { - const skillToReturn = pmcData.Skills.Common.find(x => x.Id === skill); + const skillToReturn = pmcData.Skills.Common.find((x) => x.Id === skill); if (!skillToReturn) { this.logger.warning(`Profile ${pmcData.sessionId} does not have a skill named: ${skill}`); @@ -435,4 +452,4 @@ export class ProfileHelper return skillToReturn; } -} \ No newline at end of file +} diff --git a/project/src/helpers/QuestConditionHelper.ts b/project/src/helpers/QuestConditionHelper.ts index f964551f..b47ba161 100644 --- a/project/src/helpers/QuestConditionHelper.ts +++ b/project/src/helpers/QuestConditionHelper.ts @@ -1,4 +1,3 @@ - import { injectable } from "tsyringe"; import { AvailableForConditions } from "@spt-aki/models/eft/common/tables/IQuest"; @@ -6,29 +5,45 @@ import { AvailableForConditions } from "@spt-aki/models/eft/common/tables/IQuest @injectable() export class QuestConditionHelper { - public getQuestConditions(q: AvailableForConditions[], furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null): AvailableForConditions[] + public getQuestConditions( + q: AvailableForConditions[], + furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null, + ): AvailableForConditions[] { return this.filterConditions(q, "Quest", furtherFilter); } - public getLevelConditions(q: AvailableForConditions[], furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null): AvailableForConditions[] + public getLevelConditions( + q: AvailableForConditions[], + furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null, + ): AvailableForConditions[] { return this.filterConditions(q, "Level", furtherFilter); } - public getLoyaltyConditions(q: AvailableForConditions[], furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null): AvailableForConditions[] + public getLoyaltyConditions( + q: AvailableForConditions[], + furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null, + ): AvailableForConditions[] { return this.filterConditions(q, "TraderLoyalty", furtherFilter); } - public getStandingConditions(q: AvailableForConditions[], furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null): AvailableForConditions[] + public getStandingConditions( + q: AvailableForConditions[], + furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null, + ): AvailableForConditions[] { return this.filterConditions(q, "TraderStanding", furtherFilter); } - protected filterConditions(q: AvailableForConditions[], questType: string, furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null): AvailableForConditions[] + protected filterConditions( + q: AvailableForConditions[], + questType: string, + furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null, + ): AvailableForConditions[] { - const filteredQuests = q.filter(c => + const filteredQuests = q.filter((c) => { if (c._parent === questType) { @@ -43,4 +58,4 @@ export class QuestConditionHelper return filteredQuests; } -} \ No newline at end of file +} diff --git a/project/src/helpers/QuestHelper.ts b/project/src/helpers/QuestHelper.ts index f87daba9..18893d95 100644 --- a/project/src/helpers/QuestHelper.ts +++ b/project/src/helpers/QuestHelper.ts @@ -53,25 +53,25 @@ export class QuestHelper @inject("LocalisationService") protected localisationService: LocalisationService, @inject("TraderHelper") protected traderHelper: TraderHelper, @inject("MailSendService") protected mailSendService: MailSendService, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.questConfig = this.configServer.getConfig(ConfigTypes.QUEST); } /** - * Get status of a quest in player profile by its id - * @param pmcData Profile to search - * @param questId Quest id to look up - * @returns QuestStatus enum - */ + * Get status of a quest in player profile by its id + * @param pmcData Profile to search + * @param questId Quest id to look up + * @returns QuestStatus enum + */ public getQuestStatus(pmcData: IPmcData, questId: string): QuestStatus { - const quest = pmcData.Quests?.find(q => q.qid === questId); + const quest = pmcData.Quests?.find((q) => q.qid === questId); - return quest - ? quest.status - : QuestStatus.Locked; + return quest ? + quest.status : + QuestStatus.Locked; } /** @@ -97,7 +97,12 @@ export class QuestHelper case "=": return playerLevel === condition._props.value; default: - this.logger.error(this.localisationService.getText("quest-unable_to_find_compare_condition", condition._props.compareMethod)); + this.logger.error( + this.localisationService.getText( + "quest-unable_to_find_compare_condition", + condition._props.compareMethod, + ), + ); return false; } } @@ -181,7 +186,7 @@ export class QuestHelper /** * Get quest name by quest id * @param questId id to get - * @returns + * @returns */ public getQuestNameFromLocale(questId: string): string { @@ -189,7 +194,6 @@ export class QuestHelper return this.localeService.getLocaleDb()[questNameKey]; } - /** * Check if trader has sufficient loyalty to fulfill quest requirement * @param questProperties Quest props @@ -242,7 +246,7 @@ export class QuestHelper return current !== required; case "==": return current === required; - + default: this.logger.error(this.localisationService.getText("quest-compare_operator_unhandled", compareMethod)); @@ -274,9 +278,11 @@ export class QuestHelper // separate base item and mods, fix stacks if (item._id === reward.target) { - if ((item.parentId !== undefined) && (item.parentId === "hideout") - && (item.upd !== undefined) && (item.upd.StackObjectsCount !== undefined) - && (item.upd.StackObjectsCount > 1)) + if ( + (item.parentId !== undefined) && (item.parentId === "hideout") && + (item.upd !== undefined) && (item.upd.StackObjectsCount !== undefined) && + (item.upd.StackObjectsCount > 1) + ) { item.upd.StackObjectsCount = 1; } @@ -307,7 +313,7 @@ export class QuestHelper items.push(this.jsonUtil.clone(mod)); } - rewardItems = rewardItems.concat( this.ragfairServerHelper.reparentPresets(target, items)); + rewardItems = rewardItems.concat(this.ragfairServerHelper.reparentPresets(target, items)); } return rewardItems; @@ -323,9 +329,11 @@ export class QuestHelper { // Iterate over all rewards with the desired status, flatten out items that have a type of Item const questRewards = quest.rewards[QuestStatus[status]] - .flatMap((reward: Reward) => reward.type === "Item" - ? this.processReward(reward) - : []); + .flatMap((reward: Reward) => + reward.type === "Item" ? + this.processReward(reward) : + [] + ); return questRewards; } @@ -336,9 +344,13 @@ export class QuestHelper * @param newState State the new quest should be in when returned * @param acceptedQuest Details of accepted quest from client */ - public getQuestReadyForProfile(pmcData: IPmcData, newState: QuestStatus, acceptedQuest: IAcceptQuestRequestData): IQuestStatus + public getQuestReadyForProfile( + pmcData: IPmcData, + newState: QuestStatus, + acceptedQuest: IAcceptQuestRequestData, + ): IQuestStatus { - const existingQuest = pmcData.Quests.find(q => q.qid === acceptedQuest.qid); + const existingQuest = pmcData.Quests.find((q) => q.qid === acceptedQuest.qid); if (existingQuest) { // Quest exists, update its status @@ -360,12 +372,12 @@ export class QuestHelper qid: acceptedQuest.qid, startTime: this.timeUtil.getTimestamp(), status: newState, - statusTimers: {} + statusTimers: {}, }; - + // Check if quest has a prereq to be placed in a 'pending' state const questDbData = this.getQuestFromDb(acceptedQuest.qid, pmcData); - const waitTime = questDbData.conditions.AvailableForStart.find(x => x._props.availableAfter > 0); + const waitTime = questDbData.conditions.AvailableForStart.find((x) => x._props.availableAfter > 0); if (waitTime && acceptedQuest.type !== "repeatable") { // Quest should be put into 'pending' state @@ -392,18 +404,18 @@ export class QuestHelper { // Get quest acceptance data from profile const profile: IPmcData = this.profileHelper.getPmcProfile(sessionID); - const startedQuestInProfile = profile.Quests.find(x => x.qid === startedQuestId); + const startedQuestInProfile = profile.Quests.find((x) => x.qid === startedQuestId); - // Get quests that + // Get quests that const eligibleQuests = this.getQuestsFromDb().filter((quest) => { // Quest is accessible to player when the accepted quest passed into param is started // e.g. Quest A passed in, quest B is looped over and has requirement of A to be started, include it - const acceptedQuestCondition = quest.conditions.AvailableForStart.find(x => + const acceptedQuestCondition = quest.conditions.AvailableForStart.find((x) => { - return x._parent === "Quest" - && x._props.target === startedQuestId - && x._props.status[0] === QuestStatus.Started; + return x._parent === "Quest" && + x._props.target === startedQuestId && + x._props.status[0] === QuestStatus.Started; }); // Not found, skip quest @@ -412,7 +424,9 @@ export class QuestHelper return false; } - const standingRequirements = this.questConditionHelper.getStandingConditions(quest.conditions.AvailableForStart); + const standingRequirements = this.questConditionHelper.getStandingConditions( + quest.conditions.AvailableForStart, + ); for (const condition of standingRequirements) { if (!this.traderStandingRequirementCheck(condition._props, profile)) @@ -421,7 +435,9 @@ export class QuestHelper } } - const loyaltyRequirements = this.questConditionHelper.getLoyaltyConditions(quest.conditions.AvailableForStart); + const loyaltyRequirements = this.questConditionHelper.getLoyaltyConditions( + quest.conditions.AvailableForStart, + ); for (const condition of loyaltyRequirements) { if (!this.traderLoyaltyLevelRequirementCheck(condition._props, profile)) @@ -431,7 +447,8 @@ export class QuestHelper } // Include if quest found in profile and is started or ready to hand in - return startedQuestInProfile && ([QuestStatus.Started, QuestStatus.AvailableForFinish].includes(startedQuestInProfile.status)); + return startedQuestInProfile && + ([QuestStatus.Started, QuestStatus.AvailableForFinish].includes(startedQuestInProfile.status)); }); return this.getQuestsWithOnlyLevelRequirementStartCondition(eligibleQuests); @@ -446,17 +463,18 @@ export class QuestHelper public failedUnlocked(failedQuestId: string, sessionId: string): IQuest[] { const profile = this.profileHelper.getPmcProfile(sessionId); - const profileQuest = profile.Quests.find(x => x.qid === failedQuestId); + const profileQuest = profile.Quests.find((x) => x.qid === failedQuestId); const quests = this.getQuestsFromDb().filter((q) => { const acceptedQuestCondition = q.conditions.AvailableForStart.find( - c => + (c) => { - return c._parent === "Quest" - && c._props.target === failedQuestId - && c._props.status[0] === QuestStatus.Fail; - }); + return c._parent === "Quest" && + c._props.target === failedQuestId && + c._props.status[0] === QuestStatus.Fail; + }, + ); if (!acceptedQuestCondition) { @@ -490,7 +508,9 @@ export class QuestHelper { if (this.paymentHelper.isMoneyTpl(reward.items[0]._tpl)) { - reward.items[0].upd.StackObjectsCount += Math.round(reward.items[0].upd.StackObjectsCount * multiplier / 100); + reward.items[0].upd.StackObjectsCount += Math.round( + reward.items[0].upd.StackObjectsCount * multiplier / 100, + ); } } } @@ -507,9 +527,15 @@ export class QuestHelper * @param sessionID Session id * @param output ItemEvent router response */ - public changeItemStack(pmcData: IPmcData, itemId: string, newStackSize: number, sessionID: string, output: IItemEventRouterResponse): void + public changeItemStack( + pmcData: IPmcData, + itemId: string, + newStackSize: number, + sessionID: string, + output: IItemEventRouterResponse, + ): void { - const inventoryItemIndex = pmcData.Inventory.items.findIndex(item => item._id === itemId); + const inventoryItemIndex = pmcData.Inventory.items.findIndex((item) => item._id === itemId); if (inventoryItemIndex < 0) { this.logger.error(this.localisationService.getText("quest-item_not_found_in_inventory", itemId)); @@ -532,7 +558,7 @@ export class QuestHelper { // this case is probably dead Code right now, since the only calling function // checks explicitly for Value > 0. - output.profileChanges[sessionID].items.del.push({ _id: itemId }); + output.profileChanges[sessionID].items.del.push({_id: itemId}); pmcData.Inventory.items.splice(inventoryItemIndex, 1); } } @@ -543,7 +569,11 @@ export class QuestHelper * @param sessionId Session id * @param item Item that was adjusted */ - protected addItemStackSizeChangeIntoEventResponse(output: IItemEventRouterResponse, sessionId: string, item: Item): void + protected addItemStackSizeChangeIntoEventResponse( + output: IItemEventRouterResponse, + sessionId: string, + item: Item, + ): void { output.profileChanges[sessionId].items.change.push({ _id: item._id, @@ -552,8 +582,8 @@ export class QuestHelper slotId: item.slotId, location: item.location, upd: { - StackObjectsCount: item.upd.StackObjectsCount - } + StackObjectsCount: item.upd.StackObjectsCount, + }, }); } @@ -580,7 +610,7 @@ export class QuestHelper public getQuestWithOnlyLevelRequirementStartCondition(quest: IQuest): IQuest { quest = this.jsonUtil.clone(quest); - quest.conditions.AvailableForStart = quest.conditions.AvailableForStart.filter(q => q._parent === "Level"); + quest.conditions.AvailableForStart = quest.conditions.AvailableForStart.filter((q) => q._parent === "Level"); return quest; } @@ -593,7 +623,12 @@ export class QuestHelper * @param output Client output * @returns Item event router response */ - public failQuest(pmcData: IPmcData, failRequest: IFailQuestRequestData, sessionID: string, output: IItemEventRouterResponse = null): IItemEventRouterResponse + public failQuest( + pmcData: IPmcData, + failRequest: IFailQuestRequestData, + sessionID: string, + output: IItemEventRouterResponse = null, + ): IItemEventRouterResponse { // Prepare response to send back client if (!output) @@ -613,7 +648,7 @@ export class QuestHelper MessageType.QUEST_FAIL, quest.failMessageText, questRewards, - this.timeUtil.getHoursAsSeconds(this.questConfig.redeemTime) + this.timeUtil.getHoursAsSeconds(this.questConfig.redeemTime), ); output.profileChanges[sessionID].quests.push(this.failedUnlocked(failRequest.qid, sessionID)); @@ -647,7 +682,7 @@ export class QuestHelper // Check daily/weekly objects for (const repeatableType of pmcData.RepeatableQuests) { - quest = repeatableType.activeQuests.find(x => x._id === questId); + quest = repeatableType.activeQuests.find((x) => x._id === questId); if (quest) { break; @@ -668,7 +703,10 @@ export class QuestHelper { // blank or is a guid, use description instead const startedMessageText = this.getQuestLocaleIdFromDb(startedMessageTextId); - if (!startedMessageText || startedMessageText.trim() === "" || startedMessageText.toLowerCase() === "test" || startedMessageText.length === 24) + if ( + !startedMessageText || startedMessageText.trim() === "" || startedMessageText.toLowerCase() === "test" || + startedMessageText.length === 24 + ) { return questDescriptionId; } @@ -696,7 +734,7 @@ export class QuestHelper public updateQuestState(pmcData: IPmcData, newQuestState: QuestStatus, questId: string): void { // Find quest in profile, update status to desired status - const questToUpdate = pmcData.Quests.find(quest => quest.qid === questId); + const questToUpdate = pmcData.Quests.find((quest) => quest.qid === questId); if (questToUpdate) { questToUpdate.status = newQuestState; @@ -713,8 +751,14 @@ export class QuestHelper * @param questResponse Response to send back to client * @returns Array of reward objects */ - public applyQuestReward(pmcData: IPmcData, questId: string, state: QuestStatus, sessionId: string, questResponse: IItemEventRouterResponse): Reward[] - { + public applyQuestReward( + pmcData: IPmcData, + questId: string, + state: QuestStatus, + sessionId: string, + questResponse: IItemEventRouterResponse, + ): Reward[] + { let questDetails = this.getQuestFromDb(questId, pmcData); if (!questDetails) { @@ -722,7 +766,7 @@ export class QuestHelper return []; } - + // Check for and apply intel center money bonus if it exists const questMoneyRewardBonus = this.getQuestMoneyRewardBonus(pmcData); if (questMoneyRewardBonus > 0) @@ -738,7 +782,11 @@ export class QuestHelper switch (reward.type) { case QuestRewardType.SKILL: - this.profileHelper.addSkillPointsToPlayer(pmcData, reward.target as SkillTypes, Number(reward.value)); + this.profileHelper.addSkillPointsToPlayer( + pmcData, + reward.target as SkillTypes, + Number(reward.value), + ); break; case QuestRewardType.EXPERIENCE: this.profileHelper.addExperienceToPmc(sessionId, parseInt(reward.value)); // this must occur first as the output object needs to take the modified profile exp value @@ -759,10 +807,22 @@ export class QuestHelper this.logger.debug("Not implemented stash rows reward yet"); break; case QuestRewardType.PRODUCTIONS_SCHEME: - this.findAndAddHideoutProductionIdToProfile(pmcData, reward, questDetails, sessionId, questResponse); + this.findAndAddHideoutProductionIdToProfile( + pmcData, + reward, + questDetails, + sessionId, + questResponse, + ); break; default: - this.logger.error(this.localisationService.getText("quest-reward_type_not_handled", {rewardType: reward.type, questId: questId, questName: questDetails.QuestName})); + this.logger.error( + this.localisationService.getText("quest-reward_type_not_handled", { + rewardType: reward.type, + questId: questId, + questName: questDetails.QuestName, + }), + ); break; } } @@ -779,19 +839,31 @@ export class QuestHelper * @param sessionID Session id * @param response Response to send back to client */ - protected findAndAddHideoutProductionIdToProfile(pmcData: IPmcData, craftUnlockReward: Reward, questDetails: IQuest, sessionID: string, response: IItemEventRouterResponse): void + protected findAndAddHideoutProductionIdToProfile( + pmcData: IPmcData, + craftUnlockReward: Reward, + questDetails: IQuest, + sessionID: string, + response: IItemEventRouterResponse, + ): void { // Get hideout crafts and find those that match by areatype/required level/end product tpl - hope for just one match const hideoutProductions = this.databaseServer.getTables().hideout.production; - const matchingProductions = hideoutProductions.filter(x => - x.areaType === Number.parseInt(craftUnlockReward.traderId) - && x.requirements.some(x => x.requiredLevel === craftUnlockReward.loyaltyLevel) - && x.endProduct === craftUnlockReward.items[0]._tpl); + const matchingProductions = hideoutProductions.filter((x) => + x.areaType === Number.parseInt(craftUnlockReward.traderId) && + x.requirements.some((x) => x.requiredLevel === craftUnlockReward.loyaltyLevel) && + x.endProduct === craftUnlockReward.items[0]._tpl + ); // More/less than 1 match, above filtering wasn't strict enough if (matchingProductions.length !== 1) { - this.logger.error(this.localisationService.getText("quest-unable_to_find_matching_hideout_production", {questName: questDetails.QuestName, matchCount: matchingProductions.length})); + this.logger.error( + this.localisationService.getText("quest-unable_to_find_matching_hideout_production", { + questName: questDetails.QuestName, + matchCount: matchingProductions.length, + }), + ); return; } @@ -810,7 +882,7 @@ export class QuestHelper protected getQuestMoneyRewardBonus(pmcData: IPmcData): number { // Check player has intel center - const moneyRewardBonuses = pmcData.Bonuses.filter(x => x.type === "QuestMoneyReward"); + const moneyRewardBonuses = pmcData.Bonuses.filter((x) => x.type === "QuestMoneyReward"); if (!moneyRewardBonuses) { return 0; @@ -823,7 +895,7 @@ export class QuestHelper const hideoutManagementSkill = this.profileHelper.getSkillFromProfile(pmcData, SkillTypes.HIDEOUT_MANAGEMENT); if (hideoutManagementSkill) { - moneyRewardBonus *= (1 + (hideoutManagementSkill.Progress / 10000)); // 5100 becomes 0.51, add 1 to it, 1.51, multiply the moneyreward bonus by it (e.g. 15 x 51) + moneyRewardBonus *= 1 + (hideoutManagementSkill.Progress / 10000); // 5100 becomes 0.51, add 1 to it, 1.51, multiply the moneyreward bonus by it (e.g. 15 x 51) } return moneyRewardBonus; @@ -835,19 +907,27 @@ export class QuestHelper * @param questIds Quests to search through for the findItem condition * @returns quest id with 'FindItem' condition id */ - public getFindItemConditionByQuestItem(itemTpl: string, questIds: string[], allQuests: IQuest[]): Record + public getFindItemConditionByQuestItem( + itemTpl: string, + questIds: string[], + allQuests: IQuest[], + ): Record { const result: Record = {}; for (const questId of questIds) { - const questInDb = allQuests.find(x => x._id === questId); + const questInDb = allQuests.find((x) => x._id === questId); if (!questInDb) { - this.logger.warning(`Unable to find quest: ${questId} in db, cannot get 'FindItem' condition, skipping`); + this.logger.warning( + `Unable to find quest: ${questId} in db, cannot get 'FindItem' condition, skipping`, + ); continue; } - const condition = questInDb.conditions.AvailableForFinish.find(c => c._parent === "FindItem" && c._props?.target?.includes(itemTpl)); + const condition = questInDb.conditions.AvailableForFinish.find((c) => + c._parent === "FindItem" && c._props?.target?.includes(itemTpl) + ); if (condition) { result[questId] = condition._props.id; @@ -872,7 +952,7 @@ export class QuestHelper { // Quest from db matches quests in profile, skip const questData = quests[questKey]; - if (pmcProfile.Quests.find(x => x.qid === questData._id)) + if (pmcProfile.Quests.find((x) => x.qid === questData._id)) { continue; } @@ -889,13 +969,13 @@ export class QuestHelper status: statuses[statuses.length - 1], statusTimers: statusesDict, completedConditions: [], - availableAfter: 0 + availableAfter: 0, }; - if (pmcProfile.Quests.some(x => x.qid === questKey)) + if (pmcProfile.Quests.some((x) => x.qid === questKey)) { // Update existing - const existingQuest = pmcProfile.Quests.find(x => x.qid === questKey); + const existingQuest = pmcProfile.Quests.find((x) => x.qid === questKey); existingQuest.status = questRecordToAdd.status; existingQuest.statusTimers = questRecordToAdd.statusTimers; } @@ -909,10 +989,10 @@ export class QuestHelper public findAndRemoveQuestFromArrayIfExists(questId: string, quests: IQuestStatus[]): void { - const pmcQuestToReplaceStatus = quests.find(x => x.qid === questId); + const pmcQuestToReplaceStatus = quests.find((x) => x.qid === questId); if (pmcQuestToReplaceStatus) { quests.splice(quests.indexOf(pmcQuestToReplaceStatus, 1)); } } -} \ No newline at end of file +} diff --git a/project/src/helpers/RagfairHelper.ts b/project/src/helpers/RagfairHelper.ts index 991bc61f..e8790996 100644 --- a/project/src/helpers/RagfairHelper.ts +++ b/project/src/helpers/RagfairHelper.ts @@ -31,17 +31,17 @@ export class RagfairHelper @inject("ItemHelper") protected itemHelper: ItemHelper, @inject("RagfairLinkedItemService") protected ragfairLinkedItemService: RagfairLinkedItemService, @inject("UtilityHelper") protected utilityHelper: UtilityHelper, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR); } /** - * Gets currency TAG from TPL - * @param {string} currency - * @returns string - */ + * Gets currency TAG from TPL + * @param {string} currency + * @returns string + */ public getCurrencyTag(currency: string): string { switch (currency) @@ -73,9 +73,9 @@ export class RagfairHelper if (info.linkedSearchId) { const data = this.ragfairLinkedItemService.getLinkedItems(info.linkedSearchId); - result = !data - ? [] - : [...data]; + result = !data ? + [] : + [...data]; } // Case: category @@ -185,7 +185,7 @@ export class RagfairHelper for (let item of items) { item = this.itemHelper.fixItemStackCount(item); - const isChild = items.find(it => it._id === item.parentId); + const isChild = items.find((it) => it._id === item.parentId); if (!isChild) { diff --git a/project/src/helpers/RagfairOfferHelper.ts b/project/src/helpers/RagfairOfferHelper.ts index 6543ad18..9de15133 100644 --- a/project/src/helpers/RagfairOfferHelper.ts +++ b/project/src/helpers/RagfairOfferHelper.ts @@ -60,7 +60,7 @@ export class RagfairOfferHelper @inject("LocaleService") protected localeService: LocaleService, @inject("LocalisationService") protected localisationService: LocalisationService, @inject("MailSendService") protected mailSendService: MailSendService, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR); @@ -75,9 +75,16 @@ export class RagfairOfferHelper * @param pmcProfile Player profile * @returns Offers the player should see */ - public getValidOffers(searchRequest: ISearchRequestData, itemsToAdd: string[], traderAssorts: Record, pmcProfile: IPmcData): IRagfairOffer[] + public getValidOffers( + searchRequest: ISearchRequestData, + itemsToAdd: string[], + traderAssorts: Record, + pmcProfile: IPmcData, + ): IRagfairOffer[] { - return this.ragfairOfferService.getOffers().filter(x => this.isDisplayableOffer(searchRequest, itemsToAdd, traderAssorts, x, pmcProfile)); + return this.ragfairOfferService.getOffers().filter((x) => + this.isDisplayableOffer(searchRequest, itemsToAdd, traderAssorts, x, pmcProfile) + ); } /** @@ -88,7 +95,12 @@ export class RagfairOfferHelper * @param pmcProfile Player profile * @returns IRagfairOffer array */ - public getOffersForBuild(searchRequest: ISearchRequestData, itemsToAdd: string[], traderAssorts: Record, pmcProfile: IPmcData): IRagfairOffer[] + public getOffersForBuild( + searchRequest: ISearchRequestData, + itemsToAdd: string[], + traderAssorts: Record, + pmcProfile: IPmcData, + ): IRagfairOffer[] { const offersMap = new Map(); const offers: IRagfairOffer[] = []; @@ -137,13 +149,13 @@ export class RagfairOfferHelper if (possibleOffers.length > 1) { const lockedOffers = this.getLoyaltyLockedOffers(possibleOffers, pmcProfile); - + // Exclude locked offers + above loyalty locked offers if at least 1 was found - const availableOffers = possibleOffers.filter(x => !(x.locked || lockedOffers.includes(x._id))); + const availableOffers = possibleOffers.filter((x) => !(x.locked || lockedOffers.includes(x._id))); if (availableOffers.length > 0) { possibleOffers = availableOffers; - } + } } const offer = this.ragfairSortHelper.sortOffers(possibleOffers, RagfairSort.PRICE, 0)[0]; @@ -174,7 +186,9 @@ export class RagfairOfferHelper */ public traderOfferItemQuestLocked(offer: IRagfairOffer, traderAssorts: Record): boolean { - return offer.items?.some(i => traderAssorts[offer.user.id].barter_scheme[i._id]?.some(bs1 => bs1?.some(bs2 => bs2.sptQuestLocked))); + return offer.items?.some((i) => + traderAssorts[offer.user.id].barter_scheme[i._id]?.some((bs1) => bs1?.some((bs2) => bs2.sptQuestLocked)) + ); } /** @@ -182,7 +196,7 @@ export class RagfairOfferHelper * @param offer Offer to check stock of * @returns true if out of stock */ - protected traderOutOfStock(offer: IRagfairOffer): boolean + protected traderOutOfStock(offer: IRagfairOffer): boolean { if (offer?.items?.length === 0) { @@ -200,17 +214,21 @@ export class RagfairOfferHelper protected traderBuyRestrictionReached(offer: IRagfairOffer): boolean { const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items; - const assortData = traderAssorts.find(x => x._id === offer.items[0]._id); + const assortData = traderAssorts.find((x) => x._id === offer.items[0]._id); // No trader assort data if (!assortData) { - this.logger.warning(`Unable to find trader: ${offer.user.nickname} assort for item: ${this.itemHelper.getItemName(offer.items[0]._tpl)} ${offer.items[0]._tpl}, cannot check if buy restriction reached`); + this.logger.warning( + `Unable to find trader: ${offer.user.nickname} assort for item: ${ + this.itemHelper.getItemName(offer.items[0]._tpl) + } ${offer.items[0]._tpl}, cannot check if buy restriction reached`, + ); return false; } // No restriction values - // Can't use !assortData.upd.BuyRestrictionX as value could be 0 + // Can't use !assortData.upd.BuyRestrictionX as value could be 0 if (assortData.upd.BuyRestrictionMax === undefined || assortData.upd.BuyRestrictionCurrent === undefined) { return false; @@ -279,7 +297,10 @@ export class RagfairOfferHelper boughtAmount = offer.sellResult[0].amount; } - this.increaseProfileRagfairRating(this.saveServer.getProfile(sessionID), offer.summaryCost / totalItemsCount * boughtAmount); + this.increaseProfileRagfairRating( + this.saveServer.getProfile(sessionID), + offer.summaryCost / totalItemsCount * boughtAmount, + ); this.completeOffer(sessionID, offer, boughtAmount); offer.sellResult.splice(0, 1); @@ -331,7 +352,7 @@ export class RagfairOfferHelper protected deleteOfferById(sessionID: string, offerId: string): void { const profileRagfairInfo = this.saveServer.getProfile(sessionID).characters.pmc.RagfairInfo; - const index = profileRagfairInfo.offers.findIndex(o => o._id === offerId); + const index = profileRagfairInfo.offers.findIndex((o) => o._id === offerId); profileRagfairInfo.offers.splice(index, 1); // Also delete from ragfair this.ragfairOfferService.removeOfferById(offerId); @@ -357,7 +378,7 @@ export class RagfairOfferHelper else { offer.items[0].upd.StackObjectsCount -= boughtAmount; - const rootItems = offer.items.filter(i => i.parentId === "hideout"); + const rootItems = offer.items.filter((i) => i.parentId === "hideout"); rootItems.splice(0, 1); let removeCount = boughtAmount; @@ -384,11 +405,12 @@ export class RagfairOfferHelper while (foundNewItems) { foundNewItems = false; - - // eslint-disable-next-line @typescript-eslint/no-unused-vars + for (const id of idsToRemove) { - const newIds = offer.items.filter(i => !idsToRemove.includes(i._id) && idsToRemove.includes(i.parentId)).map(i => i._id); + const newIds = offer.items.filter((i) => + !idsToRemove.includes(i._id) && idsToRemove.includes(i.parentId) + ).map((i) => i._id); if (newIds.length > 0) { foundNewItems = true; @@ -399,7 +421,7 @@ export class RagfairOfferHelper if (idsToRemove.length > 0) { - offer.items = offer.items.filter(i => !idsToRemove.includes(i._id)); + offer.items = offer.items.filter((i) => !idsToRemove.includes(i._id)); } } @@ -410,7 +432,7 @@ export class RagfairOfferHelper const requestedItem: Item = { _id: this.hashUtil.generate(), _tpl: requirement._tpl, - upd: { StackObjectsCount: requirement.count * boughtAmount } + upd: {StackObjectsCount: requirement.count * boughtAmount}, }; const stacks = this.itemHelper.splitStack(requestedItem); @@ -436,7 +458,7 @@ export class RagfairOfferHelper const ragfairDetails = { offerId: offer._id, count: offer.sellInOnePiece ? offerStackCount : boughtAmount, // pack-offers NEED to the full item count otherwise it only removes 1 from the pack, leaving phantom offer on client ui - handbookId: itemTpl + handbookId: itemTpl, }; this.mailSendService.sendDirectNpcMessageToPlayer( @@ -447,7 +469,8 @@ export class RagfairOfferHelper itemsToSend, this.timeUtil.getHoursAsSeconds(this.questConfig.redeemTime), null, - ragfairDetails); + ragfairDetails, + ); return this.eventOutputHolder.getOutput(sessionID); } @@ -465,14 +488,19 @@ export class RagfairOfferHelper const soldMessageLocaleGuid = globalLocales[RagfairOfferHelper.goodSoldTemplate]; if (!soldMessageLocaleGuid) { - this.logger.error(this.localisationService.getText("ragfair-unable_to_find_locale_by_key", RagfairOfferHelper.goodSoldTemplate)); + this.logger.error( + this.localisationService.getText( + "ragfair-unable_to_find_locale_by_key", + RagfairOfferHelper.goodSoldTemplate, + ), + ); } // Used to replace tokens in sold message sent to player const tplVars: ISystemData = { soldItem: globalLocales[`${itemTpl} Name`] || itemTpl, buyerNickname: this.ragfairServerHelper.getNickname(this.hashUtil.generate()), - itemCount: boughtAmount + itemCount: boughtAmount, }; const offerSoldMessageText = soldMessageLocaleGuid.replace(/{\w+}/g, (matched) => @@ -492,14 +520,23 @@ export class RagfairOfferHelper * @param pmcProfile Player profile * @returns True = should be shown to player */ - public isDisplayableOffer(searchRequest: ISearchRequestData, itemsToAdd: string[], traderAssorts: Record, offer: IRagfairOffer, pmcProfile: IPmcData): boolean + public isDisplayableOffer( + searchRequest: ISearchRequestData, + itemsToAdd: string[], + traderAssorts: Record, + offer: IRagfairOffer, + pmcProfile: IPmcData, + ): boolean { const item = offer.items[0]; const money = offer.requirements[0]._tpl; const isTraderOffer = offer.user.memberType === MemberCategory.TRADER; const isDefaultUserOffer = offer.user.memberType === MemberCategory.DEFAULT; - if (pmcProfile.Info.Level < this.databaseServer.getTables().globals.config.RagFair.minUserLevel && isDefaultUserOffer) + if ( + pmcProfile.Info.Level < this.databaseServer.getTables().globals.config.RagFair.minUserLevel && + isDefaultUserOffer + ) { // Skip item if player is < global unlock level (default is 15) and item is from a dynamically generated source return false; @@ -512,7 +549,7 @@ export class RagfairOfferHelper } // Performing a required search and offer doesn't have requirement for item - if (searchRequest.neededSearchId && !offer.requirements.some(x => x._tpl === searchRequest.neededSearchId)) + if (searchRequest.neededSearchId && !offer.requirements.some((x) => x._tpl === searchRequest.neededSearchId)) { return false; } @@ -559,7 +596,10 @@ export class RagfairOfferHelper return false; } - if (( item.upd.MedKit || item.upd.Repairable ) && !this.itemQualityInRange(item, searchRequest.conditionFrom, searchRequest.conditionTo)) + if ( + (item.upd.MedKit || item.upd.Repairable) && + !this.itemQualityInRange(item, searchRequest.conditionFrom, searchRequest.conditionTo) + ) { return false; } @@ -612,10 +652,12 @@ export class RagfairOfferHelper return false; } - if (!traderAssorts[offer.user.id].items.find((item) => - { - return item._id === offer.root; - })) + if ( + !traderAssorts[offer.user.id].items.find((item) => + { + return item._id === offer.root; + }) + ) { // skip (quest) locked items return false; @@ -649,4 +691,4 @@ export class RagfairOfferHelper return true; } -} \ No newline at end of file +} diff --git a/project/src/helpers/RagfairSellHelper.ts b/project/src/helpers/RagfairSellHelper.ts index 12d0ba55..bbe9777c 100644 --- a/project/src/helpers/RagfairSellHelper.ts +++ b/project/src/helpers/RagfairSellHelper.ts @@ -17,7 +17,7 @@ export class RagfairSellHelper @inject("WinstonLogger") protected logger: ILogger, @inject("RandomUtil") protected randomUtil: RandomUtil, @inject("TimeUtil") protected timeUtil: TimeUtil, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR); @@ -30,15 +30,20 @@ export class RagfairSellHelper * @param qualityMultiplier Quality multipler of item being sold * @returns percent value */ - public calculateSellChance(averageOfferPriceRub: number, playerListedPriceRub: number, qualityMultiplier: number): number + public calculateSellChance( + averageOfferPriceRub: number, + playerListedPriceRub: number, + qualityMultiplier: number, + ): number { const baseSellChancePercent = this.ragfairConfig.sell.chance.base * qualityMultiplier; const listedPriceAboveAverage = playerListedPriceRub > averageOfferPriceRub; // Get sell chance multiplier - const multiplier = (listedPriceAboveAverage) - ? this.ragfairConfig.sell.chance.overpriced // Player price is over average listing price - : this.getSellMultiplierWhenPlayerPriceIsBelowAverageListingPrice(averageOfferPriceRub, playerListedPriceRub); + const multiplier = listedPriceAboveAverage ? + this.ragfairConfig.sell.chance.overpriced // Player price is over average listing price + : + this.getSellMultiplierWhenPlayerPriceIsBelowAverageListingPrice(averageOfferPriceRub, playerListedPriceRub); return Math.round(baseSellChancePercent * (averageOfferPriceRub / playerListedPriceRub * multiplier)); } @@ -49,11 +54,14 @@ export class RagfairSellHelper * @param averageOfferPriceRub Price of average offer in roubles * @returns percent value */ - protected getSellMultiplierWhenPlayerPriceIsBelowAverageListingPrice(averageOfferPriceRub: number, playerListedPriceRub: number): number + protected getSellMultiplierWhenPlayerPriceIsBelowAverageListingPrice( + averageOfferPriceRub: number, + playerListedPriceRub: number, + ): number { - return (playerListedPriceRub < averageOfferPriceRub) - ? this.ragfairConfig.sell.chance.underpriced - : 1; + return (playerListedPriceRub < averageOfferPriceRub) ? + this.ragfairConfig.sell.chance.underpriced : + 1; } /** @@ -75,14 +83,16 @@ export class RagfairSellHelper let sellTime = startTime; let remainingCount = itemSellCount; const result: SellResult[] = []; - + // Value can sometimes be NaN for whatever reason, default to base chance if that happens if (Number.isNaN(sellChancePercent)) { - this.logger.warning(`Sell chance was not a number: ${sellChancePercent}, defaulting to ${this.ragfairConfig.sell.chance.base} %`); + this.logger.warning( + `Sell chance was not a number: ${sellChancePercent}, defaulting to ${this.ragfairConfig.sell.chance.base} %`, + ); sellChancePercent = this.ragfairConfig.sell.chance.base; } - + this.logger.debug(`Rolling to sell: ${itemSellCount} items (chance: ${sellChancePercent}%)`); // No point rolling for a sale on a 0% chance item, exit early @@ -90,18 +100,21 @@ export class RagfairSellHelper { return result; } - + while (remainingCount > 0 && sellTime < endTime) { const boughtAmount = this.randomUtil.getInt(1, remainingCount); if (this.randomUtil.getChance100(sellChancePercent)) { // Passed roll check, item will be sold - sellTime += Math.max(Math.round(chance / 100 * this.ragfairConfig.sell.time.max * 60), this.ragfairConfig.sell.time.min * 60); + sellTime += Math.max( + Math.round(chance / 100 * this.ragfairConfig.sell.time.max * 60), + this.ragfairConfig.sell.time.min * 60, + ); result.push({ sellTime: sellTime, - amount: boughtAmount + amount: boughtAmount, }); this.logger.debug(`Offer will sell at: ${new Date(sellTime * 1000).toLocaleTimeString("en-US")}`); @@ -116,4 +129,4 @@ export class RagfairSellHelper return result; } -} \ No newline at end of file +} diff --git a/project/src/helpers/RagfairServerHelper.ts b/project/src/helpers/RagfairServerHelper.ts index 9ff80555..06fc2646 100644 --- a/project/src/helpers/RagfairServerHelper.ts +++ b/project/src/helpers/RagfairServerHelper.ts @@ -48,7 +48,7 @@ export class RagfairServerHelper @inject("JsonUtil") protected jsonUtil: JsonUtil, @inject("MailSendService") protected mailSendService: MailSendService, @inject("ItemFilterService") protected itemFilterService: ItemFilterService, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR); @@ -57,7 +57,7 @@ export class RagfairServerHelper /** * Is item valid / on blacklist / quest item - * @param itemDetails + * @param itemDetails * @returns boolean */ public isItemValidRagfairItem(itemDetails: [boolean, ITemplateItem]): boolean @@ -95,7 +95,10 @@ export class RagfairServerHelper } // Don't include damaged ammo packs - if (this.ragfairConfig.dynamic.blacklist.damagedAmmoPacks && itemDetails[1]._parent === BaseClasses.AMMO_BOX && itemDetails[1]._name.includes("_damaged")) + if ( + this.ragfairConfig.dynamic.blacklist.damagedAmmoPacks && itemDetails[1]._parent === BaseClasses.AMMO_BOX && + itemDetails[1]._name.includes("_damaged") + ) { return false; } @@ -120,7 +123,7 @@ export class RagfairServerHelper /** * is supplied id a trader - * @param traderId + * @param traderId * @returns True if id was a trader */ public isTrader(traderId: string): boolean @@ -155,7 +158,7 @@ export class RagfairServerHelper MessageType.MESSAGE_WITH_ITEMS, RagfairServerHelper.goodsReturnedTemplate, returnedItems, - this.timeUtil.getHoursAsSeconds(this.questConfig.redeemTime) + this.timeUtil.getHoursAsSeconds(this.questConfig.redeemTime), ); } @@ -171,7 +174,10 @@ export class RagfairServerHelper } // Item Types to return one of - if (isWeaponPreset || this.itemHelper.isOfBaseclasses(itemDetails[1]._id, this.ragfairConfig.dynamic.showAsSingleStack)) + if ( + isWeaponPreset || + this.itemHelper.isOfBaseclasses(itemDetails[1]._id, this.ragfairConfig.dynamic.showAsSingleStack) + ) { return 1; } @@ -185,7 +191,9 @@ export class RagfairServerHelper return Math.round(this.randomUtil.getInt(config.nonStackableCount.min, config.nonStackableCount.max)); } - const stackPercent = Math.round(this.randomUtil.getInt(config.stackablePercent.min, config.stackablePercent.max)); + const stackPercent = Math.round( + this.randomUtil.getInt(config.stackablePercent.min, config.stackablePercent.max), + ); return Math.round((maxStackCount / 100) * stackPercent); } @@ -263,7 +271,9 @@ export class RagfairServerHelper { if (this.databaseServer.getTables().globals.ItemPresets[itemId]._items[0]._tpl === item._tpl) { - const presetItems = this.jsonUtil.clone(this.databaseServer.getTables().globals.ItemPresets[itemId]._items); + const presetItems = this.jsonUtil.clone( + this.databaseServer.getTables().globals.ItemPresets[itemId]._items, + ); presets.push(this.reparentPresets(item, presetItems)); } } @@ -274,7 +284,7 @@ export class RagfairServerHelper /** * Generate new unique ids for the children while preserving hierarchy * @param item base item - * @param preset + * @param preset * @returns Item array with new IDs */ public reparentPresets(item: Item, preset: Item[]): Item[] @@ -296,11 +306,11 @@ export class RagfairServerHelper idMappings[mod.parentId] = this.hashUtil.generate(); } - mod._id = idMappings[mod._id]; + mod._id = idMappings[mod._id]; if (mod.parentId !== undefined) { - mod.parentId = idMappings[mod.parentId]; + mod.parentId = idMappings[mod.parentId]; } } @@ -309,4 +319,4 @@ export class RagfairServerHelper return preset; } -} \ No newline at end of file +} diff --git a/project/src/helpers/RagfairSortHelper.ts b/project/src/helpers/RagfairSortHelper.ts index 2e41203b..22450fe8 100644 --- a/project/src/helpers/RagfairSortHelper.ts +++ b/project/src/helpers/RagfairSortHelper.ts @@ -10,15 +10,15 @@ export class RagfairSortHelper { constructor( @inject("DatabaseServer") protected databaseServer: DatabaseServer, - @inject("LocaleService") protected localeService: LocaleService + @inject("LocaleService") protected localeService: LocaleService, ) - { } + {} /** * Sort a list of ragfair offers by something (id/rating/offer name/price/expiry time) * @param offers Offers to sort * @param type How to sort it - * @param direction Ascending/descending + * @param direction Ascending/descending * @returns Sorted offers */ public sortOffers(offers: IRagfairOffer[], type: RagfairSort, direction = 0): IRagfairOffer[] @@ -75,16 +75,18 @@ export class RagfairSortHelper const nameA = locale[`${tplA} Name`] || tplA; const nameB = locale[`${tplB} Name`] || tplB; - return (nameA < nameB) - ? -1 - : (nameA > nameB) ? 1 : 0; + return (nameA < nameB) ? + -1 : + (nameA > nameB) ? + 1 : + 0; } /** * Order two offers by rouble price value * @param a Offer a * @param b Offer b - * @returns + * @returns */ protected sortOffersByPrice(a: IRagfairOffer, b: IRagfairOffer): number { @@ -95,4 +97,4 @@ export class RagfairSortHelper { return a.endTime - b.endTime; } -} \ No newline at end of file +} diff --git a/project/src/helpers/RepairHelper.ts b/project/src/helpers/RepairHelper.ts index 9b1a07bd..84b9fe5d 100644 --- a/project/src/helpers/RepairHelper.ts +++ b/project/src/helpers/RepairHelper.ts @@ -21,7 +21,7 @@ export class RepairHelper @inject("JsonUtil") protected jsonUtil: JsonUtil, @inject("RandomUtil") protected randomUtil: RandomUtil, @inject("DatabaseServer") protected databaseServer: DatabaseServer, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.repairConfig = this.configServer.getConfig(ConfigTypes.REPAIR); @@ -44,7 +44,7 @@ export class RepairHelper amountToRepair: number, useRepairKit: boolean, traderQualityMultipler: number, - applyMaxDurabilityDegradation = true + applyMaxDurabilityDegradation = true, ): void { this.logger.debug(`Adding ${amountToRepair} to ${itemToRepairDetails._name} using kit: ${useRepairKit}`); @@ -70,20 +70,30 @@ export class RepairHelper // Construct object to return itemToRepair.upd.Repairable = { Durability: newCurrentDurability, - MaxDurability: newCurrentMaxDurability + MaxDurability: newCurrentMaxDurability, }; // when modders set the repair coefficient to 0 it means that they dont want to lose durability on items // the code below generates a random degradation on the weapon durability if (applyMaxDurabilityDegradation) { - const randomisedWearAmount = (isArmor) - ? this.getRandomisedArmorRepairDegradationValue(itemToRepairDetails._props.ArmorMaterial, useRepairKit, itemCurrentMaxDurability, traderQualityMultipler) - : this.getRandomisedWeaponRepairDegradationValue(itemToRepairDetails._props, useRepairKit, itemCurrentMaxDurability, traderQualityMultipler); - + const randomisedWearAmount = isArmor ? + this.getRandomisedArmorRepairDegradationValue( + itemToRepairDetails._props.ArmorMaterial, + useRepairKit, + itemCurrentMaxDurability, + traderQualityMultipler, + ) : + this.getRandomisedWeaponRepairDegradationValue( + itemToRepairDetails._props, + useRepairKit, + itemCurrentMaxDurability, + traderQualityMultipler, + ); + // Apply wear to durability itemToRepair.upd.Repairable.MaxDurability -= randomisedWearAmount; - + // After adjusting max durability with degradation, ensure current dura isnt above max if (itemToRepair.upd.Repairable.Durability > itemToRepair.upd.Repairable.MaxDurability) { @@ -98,32 +108,42 @@ export class RepairHelper } } - protected getRandomisedArmorRepairDegradationValue(armorMaterial: string, isRepairKit: boolean, armorMax: number, traderQualityMultipler: number): number + protected getRandomisedArmorRepairDegradationValue( + armorMaterial: string, + isRepairKit: boolean, + armorMax: number, + traderQualityMultipler: number, + ): number { const armorMaterialSettings = this.databaseServer.getTables().globals.config.ArmorMaterials[armorMaterial]; - const minMultiplier = isRepairKit - ? armorMaterialSettings.MinRepairKitDegradation - : armorMaterialSettings.MinRepairDegradation; + const minMultiplier = isRepairKit ? + armorMaterialSettings.MinRepairKitDegradation : + armorMaterialSettings.MinRepairDegradation; - const maxMultiplier = isRepairKit - ? armorMaterialSettings.MaxRepairKitDegradation - : armorMaterialSettings.MaxRepairDegradation; + const maxMultiplier = isRepairKit ? + armorMaterialSettings.MaxRepairKitDegradation : + armorMaterialSettings.MaxRepairDegradation; const duraLossPercent = this.randomUtil.getFloat(minMultiplier, maxMultiplier); - const duraLossMultipliedByTraderMultiplier = (duraLossPercent * armorMax) * traderQualityMultipler; + const duraLossMultipliedByTraderMultiplier = (duraLossPercent * armorMax) * traderQualityMultipler; return Number(duraLossMultipliedByTraderMultiplier.toFixed(2)); } - protected getRandomisedWeaponRepairDegradationValue(itemProps: Props, isRepairKit: boolean, weaponMax: number, traderQualityMultipler: number): number + protected getRandomisedWeaponRepairDegradationValue( + itemProps: Props, + isRepairKit: boolean, + weaponMax: number, + traderQualityMultipler: number, + ): number { - const minRepairDeg = (isRepairKit) - ? itemProps.MinRepairKitDegradation - : itemProps.MinRepairDegradation; - let maxRepairDeg = (isRepairKit) - ? itemProps.MaxRepairKitDegradation - : itemProps.MaxRepairDegradation; + const minRepairDeg = isRepairKit ? + itemProps.MinRepairKitDegradation : + itemProps.MinRepairDegradation; + let maxRepairDeg = isRepairKit ? + itemProps.MaxRepairKitDegradation : + itemProps.MaxRepairDegradation; // WORKAROUND: Some items are always 0 when repairkit is true if (maxRepairDeg === 0) @@ -132,7 +152,7 @@ export class RepairHelper } const duraLossPercent = this.randomUtil.getFloat(minRepairDeg, maxRepairDeg); - const duraLossMultipliedByTraderMultiplier = (duraLossPercent * weaponMax) * traderQualityMultipler; + const duraLossMultipliedByTraderMultiplier = (duraLossPercent * weaponMax) * traderQualityMultipler; return Number(duraLossMultipliedByTraderMultiplier.toFixed(2)); } @@ -151,5 +171,4 @@ export class RepairHelper return parentNode._id === BaseClasses.WEAPON; } - -} \ No newline at end of file +} diff --git a/project/src/helpers/RepeatableQuestHelper.ts b/project/src/helpers/RepeatableQuestHelper.ts index dabf30cd..24182c84 100644 --- a/project/src/helpers/RepeatableQuestHelper.ts +++ b/project/src/helpers/RepeatableQuestHelper.ts @@ -15,7 +15,7 @@ export class RepeatableQuestHelper constructor( @inject("MathUtil") protected mathUtil: MathUtil, @inject("JsonUtil") protected jsonUtil: JsonUtil, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.questConfig = this.configServer.getConfig(ConfigTypes.QUEST); @@ -27,9 +27,14 @@ export class RepeatableQuestHelper * @param repeatableConfig Main repeatable config * @returns IEliminationConfig */ - public getEliminationConfigByPmcLevel(pmcLevel: number, repeatableConfig: IRepeatableQuestConfig): IEliminationConfig + public getEliminationConfigByPmcLevel( + pmcLevel: number, + repeatableConfig: IRepeatableQuestConfig, + ): IEliminationConfig { - return repeatableConfig.questConfig.Elimination.find(x => pmcLevel >= x.levelRange.min && pmcLevel <= x.levelRange.max); + return repeatableConfig.questConfig.Elimination.find((x) => + pmcLevel >= x.levelRange.min && pmcLevel <= x.levelRange.max + ); } public probabilityObjectArray(configArrayInput: ProbabilityObject[]): ProbabilityObjectArray @@ -38,8 +43,10 @@ export class RepeatableQuestHelper const probabilityArray = new ProbabilityObjectArray(this.mathUtil, this.jsonUtil); for (const configObject of configArray) { - probabilityArray.push(new ProbabilityObject(configObject.key, configObject.relativeProbability, configObject.data)); + probabilityArray.push( + new ProbabilityObject(configObject.key, configObject.relativeProbability, configObject.data), + ); } return probabilityArray; } -} \ No newline at end of file +} diff --git a/project/src/helpers/SecureContainerHelper.ts b/project/src/helpers/SecureContainerHelper.ts index bce992cb..a62f51b1 100644 --- a/project/src/helpers/SecureContainerHelper.ts +++ b/project/src/helpers/SecureContainerHelper.ts @@ -5,24 +5,23 @@ import { Item } from "@spt-aki/models/eft/common/tables/IItem"; export interface OwnerInventoryItems { - from: Item[] - to: Item[] - sameInventory: boolean, - isMail: boolean + from: Item[]; + to: Item[]; + sameInventory: boolean; + isMail: boolean; } @injectable() export class SecureContainerHelper { - constructor( - @inject("ItemHelper") protected itemHelper: ItemHelper + @inject("ItemHelper") protected itemHelper: ItemHelper, ) - { } + {} public getSecureContainerItems(items: Item[]): string[] { - const secureContainer = items.find(x => x.slotId === "SecuredContainer"); + const secureContainer = items.find((x) => x.slotId === "SecuredContainer"); // No container found, drop out if (!secureContainer) @@ -33,6 +32,6 @@ export class SecureContainerHelper const itemsInSecureContainer = this.itemHelper.findAndReturnChildrenByItems(items, secureContainer._id); // Return all items returned and exclude the secure container item itself - return itemsInSecureContainer.filter(x => x !== secureContainer._id); + return itemsInSecureContainer.filter((x) => x !== secureContainer._id); } } diff --git a/project/src/helpers/TradeHelper.ts b/project/src/helpers/TradeHelper.ts index e92f3b77..c4b0d3c1 100644 --- a/project/src/helpers/TradeHelper.ts +++ b/project/src/helpers/TradeHelper.ts @@ -34,7 +34,7 @@ export class TradeHelper @inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil, @inject("InventoryHelper") protected inventoryHelper: InventoryHelper, @inject("RagfairServer") protected ragfairServer: RagfairServer, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.traderConfig = this.configServer.getConfig(ConfigTypes.TRADER); @@ -47,9 +47,15 @@ export class TradeHelper * @param sessionID Session id * @param foundInRaid Should item be found in raid * @param upd optional item details used when buying from flea - * @returns + * @returns */ - public buyItem(pmcData: IPmcData, buyRequestData: IProcessBuyTradeRequestData, sessionID: string, foundInRaid: boolean, upd: Upd): IItemEventRouterResponse + public buyItem( + pmcData: IPmcData, + buyRequestData: IProcessBuyTradeRequestData, + sessionID: string, + foundInRaid: boolean, + upd: Upd, + ): IItemEventRouterResponse { let output = this.eventOutputHolder.getOutput(sessionID); @@ -58,10 +64,10 @@ export class TradeHelper { // eslint-disable-next-line @typescript-eslint/naming-convention item_id: buyRequestData.item_id, - count: buyRequestData.count - } + count: buyRequestData.count, + }, ], - tid: buyRequestData.tid + tid: buyRequestData.tid, }; const callback = () => @@ -71,13 +77,13 @@ export class TradeHelper if (isRagfair) { const allOffers = this.ragfairServer.getOffers(); - const offersWithItem = allOffers.find(x => x.items[0]._id === buyRequestData.item_id); + const offersWithItem = allOffers.find((x) => x.items[0]._id === buyRequestData.item_id); itemPurchased = offersWithItem.items[0]; } else { const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items; - itemPurchased = traderAssorts.find(x => x._id === buyRequestData.item_id); + itemPurchased = traderAssorts.find((x) => x._id === buyRequestData.item_id); } // Ensure purchase does not exceed trader item limit @@ -130,7 +136,12 @@ export class TradeHelper * @param sessionID Session id * @returns IItemEventRouterResponse */ - public sellItem(profileWithItemsToSell: IPmcData, profileToReceiveMoney: IPmcData, sellRequest: IProcessSellTradeRequestData, sessionID: string): IItemEventRouterResponse + public sellItem( + profileWithItemsToSell: IPmcData, + profileToReceiveMoney: IPmcData, + sellRequest: IProcessSellTradeRequestData, + sessionID: string, + ): IItemEventRouterResponse { let output = this.eventOutputHolder.getOutput(sessionID); @@ -140,7 +151,7 @@ export class TradeHelper const itemIdToFind = itemToBeRemoved.id.replace(/\s+/g, ""); // Strip out whitespace // Find item in player inventory, or show error to player if not found - const matchingItemInInventory = profileWithItemsToSell.Inventory.items.find(x => x._id === itemIdToFind); + const matchingItemInInventory = profileWithItemsToSell.Inventory.items.find((x) => x._id === itemIdToFind); if (!matchingItemInInventory) { const errorMessage = `Unable to sell item ${itemToBeRemoved.id}, cannot be found in player inventory`; @@ -179,7 +190,9 @@ export class TradeHelper { if ((assortBeingPurchased.upd.BuyRestrictionCurrent + count) > assortBeingPurchased.upd?.BuyRestrictionMax) { - throw new Error(`Unable to purchase ${count} items, this would exceed your purchase limit of ${assortBeingPurchased.upd.BuyRestrictionMax} from the trader this refresh`); + throw new Error( + `Unable to purchase ${count} items, this would exceed your purchase limit of ${assortBeingPurchased.upd.BuyRestrictionMax} from the trader this refresh`, + ); } } -} \ No newline at end of file +} diff --git a/project/src/helpers/TraderAssortHelper.ts b/project/src/helpers/TraderAssortHelper.ts index 15a39dc7..535d48e6 100644 --- a/project/src/helpers/TraderAssortHelper.ts +++ b/project/src/helpers/TraderAssortHelper.ts @@ -29,7 +29,7 @@ export class TraderAssortHelper protected mergedQuestAssorts: Record> = { started: {}, success: {}, - fail: {} + fail: {}, }; protected createdMergedQuestAssorts = false; @@ -46,10 +46,11 @@ export class TraderAssortHelper @inject("RagfairOfferGenerator") protected ragfairOfferGenerator: RagfairOfferGenerator, @inject("TraderAssortService") protected traderAssortService: TraderAssortService, @inject("LocalisationService") protected localisationService: LocalisationService, - @inject("TraderPurchasePersisterService") protected traderPurchasePersisterService: TraderPurchasePersisterService, + @inject("TraderPurchasePersisterService") protected traderPurchasePersisterService: + TraderPurchasePersisterService, @inject("TraderHelper") protected traderHelper: TraderHelper, @inject("FenceService") protected fenceService: FenceService, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.traderConfig = this.configServer.getConfig(ConfigTypes.TRADER); @@ -81,7 +82,7 @@ export class TraderAssortHelper // Strip assorts player should not see yet if (!flea) - { + { trader.assort = this.assortHelper.stripLockedLoyaltyAssort(pmcProfile, traderId, trader.assort); } @@ -89,21 +90,28 @@ export class TraderAssortHelper trader.assort.nextResupply = trader.base.nextResupply; // Adjust displayed assort counts based on values stored in profile - const assortPurchasesfromTrader = this.traderPurchasePersisterService.getProfileTraderPurchases(sessionId, traderId); + const assortPurchasesfromTrader = this.traderPurchasePersisterService.getProfileTraderPurchases( + sessionId, + traderId, + ); for (const assortId in assortPurchasesfromTrader) { // Find assort we want to update current buy count of - const assortToAdjust = trader.assort.items.find(x => x._id === assortId); + const assortToAdjust = trader.assort.items.find((x) => x._id === assortId); if (!assortToAdjust) { - this.logger.debug(`Cannot find trader: ${trader.base.nickname} assort: ${assortId} to adjust BuyRestrictionCurrent value, skipping`); + this.logger.debug( + `Cannot find trader: ${trader.base.nickname} assort: ${assortId} to adjust BuyRestrictionCurrent value, skipping`, + ); continue; } if (!assortToAdjust.upd) { - this.logger.debug(`Unable to adjust assort ${assortToAdjust._id} item: ${assortToAdjust._tpl} BuyRestrictionCurrent value, assort has an undefined upd object`); + this.logger.debug( + `Unable to adjust assort ${assortToAdjust._id} item: ${assortToAdjust._tpl} BuyRestrictionCurrent value, assort has an undefined upd object`, + ); continue; } @@ -117,7 +125,13 @@ export class TraderAssortHelper this.hydrateMergedQuestAssorts(); this.createdMergedQuestAssorts = true; } - trader.assort = this.assortHelper.stripLockedQuestAssort(pmcProfile, traderId, trader.assort, this.mergedQuestAssorts, flea); + trader.assort = this.assortHelper.stripLockedQuestAssort( + pmcProfile, + traderId, + trader.assort, + this.mergedQuestAssorts, + flea, + ); // Multiply price if multiplier is other than 1 if (this.traderConfig.traderPriceMultipler !== 1) @@ -234,7 +248,7 @@ export class TraderAssortHelper barter_scheme: {}, // eslint-disable-next-line @typescript-eslint/naming-convention loyal_level_items: {}, - nextResupply: null + nextResupply: null, }; } -} \ No newline at end of file +} diff --git a/project/src/helpers/TraderHelper.ts b/project/src/helpers/TraderHelper.ts index 2557b866..19056e3c 100644 --- a/project/src/helpers/TraderHelper.ts +++ b/project/src/helpers/TraderHelper.ts @@ -42,14 +42,14 @@ export class TraderHelper @inject("FenceService") protected fenceService: FenceService, @inject("TimeUtil") protected timeUtil: TimeUtil, @inject("RandomUtil") protected randomUtil: RandomUtil, - @inject("ConfigServer") protected configServer: ConfigServer + @inject("ConfigServer") protected configServer: ConfigServer, ) { this.traderConfig = this.configServer.getConfig(ConfigTypes.TRADER); } /** - * Get a trader base object, update profile to reflect players current standing in profile + * Get a trader base object, update profile to reflect players current standing in profile * when trader not found in profile * @param traderID Traders Id to get * @param sessionID Players id @@ -62,7 +62,7 @@ export class TraderHelper { this.logger.error(`No profile with sessionId: ${sessionID}`); } - + // Profile has traderInfo dict (profile beyond creation stage) but no requested trader in profile if (pmcData.TradersInfo && !(traderID in pmcData.TradersInfo)) { @@ -70,7 +70,7 @@ export class TraderHelper this.resetTrader(sessionID, traderID); this.lvlUp(traderID, pmcData); } - + const trader = this.databaseServer.getTables().traders?.[traderID]?.base; if (!trader) { @@ -87,9 +87,9 @@ export class TraderHelper */ public getTraderAssortsByTraderId(traderId: string): ITraderAssort { - return traderId === Traders.FENCE - ? this.fenceService.getRawFenceAssorts() - : this.databaseServer.getTables().traders[traderId].assort; + return traderId === Traders.FENCE ? + this.fenceService.getRawFenceAssorts() : + this.databaseServer.getTables().traders[traderId].assort; } /** @@ -109,7 +109,7 @@ export class TraderHelper } // Find specific assort in traders data - const purchasedAssort = traderAssorts.items.find(x => x._id === assortId); + const purchasedAssort = traderAssorts.items.find((x) => x._id === assortId); if (!purchasedAssort) { this.logger.debug(`No assort ${assortId} on trader: ${traderId} found`); @@ -130,15 +130,17 @@ export class TraderHelper { const account = this.saveServer.getProfile(sessionID); const pmcData = this.profileHelper.getPmcProfile(sessionID); - const rawProfileTemplate: ProfileTraderTemplate = this.databaseServer.getTables().templates.profiles[account.info.edition][pmcData.Info.Side.toLowerCase()].trader; + const rawProfileTemplate: ProfileTraderTemplate = + this.databaseServer.getTables().templates.profiles[account.info.edition][pmcData.Info.Side.toLowerCase()] + .trader; pmcData.TradersInfo[traderID] = { disabled: false, loyaltyLevel: rawProfileTemplate.initialLoyaltyLevel, salesSum: rawProfileTemplate.initialSalesSum, - standing: this.getStartingStanding(traderID, rawProfileTemplate), + standing: this.getStartingStanding(traderID, rawProfileTemplate), nextResupply: this.databaseServer.getTables().traders[traderID].base.nextResupply, - unlocked: this.databaseServer.getTables().traders[traderID].base.unlockedByDefault + unlocked: this.databaseServer.getTables().traders[traderID].base.unlockedByDefault, }; if (traderID === Traders.JAEGER) @@ -197,9 +199,9 @@ export class TraderHelper { const newStanding = currentStanding + standingToAdd; - return newStanding < 0 - ? 0 - : newStanding; + return newStanding < 0 ? + 0 : + newStanding; } /** @@ -224,10 +226,12 @@ export class TraderHelper { const loyalty = loyaltyLevels[level]; - if ((loyalty.minLevel <= pmcData.Info.Level - && loyalty.minSalesSum <= pmcData.TradersInfo[traderID].salesSum - && loyalty.minStanding <= pmcData.TradersInfo[traderID].standing) - && targetLevel < 4) + if ( + (loyalty.minLevel <= pmcData.Info.Level && + loyalty.minSalesSum <= pmcData.TradersInfo[traderID].salesSum && + loyalty.minStanding <= pmcData.TradersInfo[traderID].standing) && + targetLevel < 4 + ) { // level reached targetLevel++; @@ -257,15 +261,20 @@ export class TraderHelper */ public getTraderUpdateSeconds(traderId: string): number { - const traderDetails = this.traderConfig.updateTime.find(x => x.traderId === traderId); + const traderDetails = this.traderConfig.updateTime.find((x) => x.traderId === traderId); if (!traderDetails) { - this.logger.warning(this.localisationService.getText("trader-missing_trader_details_using_default_refresh_time", {traderId: traderId, updateTime: this.traderConfig.updateTimeDefault})); - this.traderConfig.updateTime.push( // create temporary entry to prevent logger spam + this.logger.warning( + this.localisationService.getText("trader-missing_trader_details_using_default_refresh_time", { + traderId: traderId, + updateTime: this.traderConfig.updateTimeDefault, + }), + ); + this.traderConfig.updateTime.push( // create temporary entry to prevent logger spam { traderId: traderId, - seconds: this.traderConfig.updateTimeDefault - } + seconds: this.traderConfig.updateTimeDefault, + }, ); } else @@ -298,7 +307,10 @@ export class TraderHelper * @param newPurchaseDetails New item assort id + count */ // eslint-disable-next-line @typescript-eslint/naming-convention - public addTraderPurchasesToPlayerProfile(sessionID: string, newPurchaseDetails: { items: { item_id: string; count: number; }[]; tid: string; }): void + public addTraderPurchasesToPlayerProfile( + sessionID: string, + newPurchaseDetails: {items: {item_id: string; count: number;}[]; tid: string;}, + ): void { const profile = this.profileHelper.getFullProfile(sessionID); const traderId = newPurchaseDetails.tid; @@ -320,10 +332,9 @@ export class TraderHelper const currentTime = this.timeUtil.getTimestamp(); if (!profile.traderPurchases[traderId][purchasedItem.item_id]) { - profile.traderPurchases[traderId][purchasedItem.item_id] = - { + profile.traderPurchases[traderId][purchasedItem.item_id] = { count: purchasedItem.count, - purchaseTimestamp: currentTime + purchaseTimestamp: currentTime, }; continue; @@ -369,15 +380,15 @@ export class TraderHelper } // Get all item assorts that have parentid of hideout (base item and not a mod of other item) - for (const item of traderAssorts.items.filter(x => x.parentId === "hideout")) + for (const item of traderAssorts.items.filter((x) => x.parentId === "hideout")) { // Get barter scheme (contains cost of item) const barterScheme = traderAssorts.barter_scheme[item._id][0][0]; // Convert into roubles - const roubleAmount = barterScheme._tpl === Money.ROUBLES - ? barterScheme.count - : this.handbookHelper.inRUB(barterScheme.count, barterScheme._tpl); + const roubleAmount = barterScheme._tpl === Money.ROUBLES ? + barterScheme.count : + this.handbookHelper.inRUB(barterScheme.count, barterScheme._tpl); // Existing price smaller in dict than current iteration, overwrite if (this.highestTraderPriceItems[item._tpl] ?? 0 < roubleAmount) @@ -409,7 +420,6 @@ export class TraderHelper return this.highestTraderBuyPriceItems[tpl]; } - // Find highest trader price for item for (const traderName in Traders) { @@ -423,7 +433,9 @@ export class TraderHelper const traderBuyBackPricePercent = relevantLoyaltyData.buy_price_coef; const itemHandbookPrice = this.handbookHelper.getTemplatePrice(tpl); - const priceTraderBuysItemAt = Math.round(this.randomUtil.getPercentOfValue(traderBuyBackPricePercent, itemHandbookPrice)); + const priceTraderBuysItemAt = Math.round( + this.randomUtil.getPercentOfValue(traderBuyBackPricePercent, itemHandbookPrice), + ); // Set new item to 1 rouble as default if (!this.highestTraderBuyPriceItems[tpl]) @@ -449,7 +461,7 @@ export class TraderHelper */ public getTraderById(traderId: string): Traders { - const keys = Object.keys(Traders).filter(x => Traders[x] === traderId); + const keys = Object.keys(Traders).filter((x) => Traders[x] === traderId); if (keys.length === 0) { @@ -462,16 +474,16 @@ export class TraderHelper } /** - * Validates that the provided traderEnumValue exists in the Traders enum. If the value is valid, it returns the - * same enum value, effectively serving as a trader ID; otherwise, it logs an error and returns an empty string. + * Validates that the provided traderEnumValue exists in the Traders enum. If the value is valid, it returns the + * same enum value, effectively serving as a trader ID; otherwise, it logs an error and returns an empty string. * This method provides a runtime check to prevent undefined behavior when using the enum as a dictionary key. - * + * * For example, instead of this: * `const traderId = Traders[Traders.PRAPOR];` - * + * * You can use safely use this: * `const traderId = this.traderHelper.getValidTraderIdByEnumValue(Traders.PRAPOR);` - * + * * @param traderEnumValue The trader enum value to validate * @returns The validated trader enum value as a string, or an empty string if invalid */ @@ -483,7 +495,7 @@ export class TraderHelper return ""; } - + return Traders[traderEnumValue]; } @@ -506,4 +518,4 @@ export class TraderHelper { return Object.values(Traders).some((x) => x === traderId); } -} \ No newline at end of file +} diff --git a/project/src/helpers/UtilityHelper.ts b/project/src/helpers/UtilityHelper.ts index 8093354f..6e10d619 100644 --- a/project/src/helpers/UtilityHelper.ts +++ b/project/src/helpers/UtilityHelper.ts @@ -5,6 +5,6 @@ export class UtilityHelper { public arrayIntersect(a: T[], b: T[]): T[] { - return a.filter(x => b.includes(x)); + return a.filter((x) => b.includes(x)); } -} \ No newline at end of file +} diff --git a/project/src/helpers/WeightedRandomHelper.ts b/project/src/helpers/WeightedRandomHelper.ts index 17d639d0..5b6178a4 100644 --- a/project/src/helpers/WeightedRandomHelper.ts +++ b/project/src/helpers/WeightedRandomHelper.ts @@ -9,7 +9,7 @@ export class WeightedRandomHelper * @param {tplId: weighting[]} itemArray * @returns tplId */ - public getWeightedInventoryItem(itemArray: { [tplId: string]: unknown; } | ArrayLike): string + public getWeightedInventoryItem(itemArray: {[tplId: string]: unknown;} | ArrayLike): string { const itemKeys = Object.keys(itemArray); const weights = Object.values(itemArray); @@ -18,7 +18,7 @@ export class WeightedRandomHelper return chosenItem.item; } - public getWeightedValue(itemArray: { [key: string]: unknown; } | ArrayLike): T + public getWeightedValue(itemArray: {[key: string]: unknown;} | ArrayLike): T { const itemKeys = Object.keys(itemArray); const weights = Object.values(itemArray); @@ -41,7 +41,7 @@ export class WeightedRandomHelper * @param {number[]} weights * @returns {{item: any, index: number}} */ - public weightedRandom(items: string | any[], weights: string | any[]): { item: any; index: number; } + public weightedRandom(items: string | any[], weights: string | any[]): {item: any; index: number;} { if (items.length !== weights.length) { @@ -79,9 +79,9 @@ export class WeightedRandomHelper { return { item: items[itemIndex], - index: itemIndex + index: itemIndex, }; } } } -} \ No newline at end of file +}