Formatting for services.
This commit is contained in:
parent
ca9ab9bcc8
commit
8576929404
@ -3,16 +3,20 @@ import { inject, injectable } from "tsyringe";
|
||||
import { BotHelper } from "@spt-aki/helpers/BotHelper";
|
||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||
import {
|
||||
EquipmentChances, Generation,
|
||||
EquipmentChances,
|
||||
Generation,
|
||||
GenerationData,
|
||||
IBotType,
|
||||
ModsChances
|
||||
ModsChances,
|
||||
} from "@spt-aki/models/eft/common/tables/IBotType";
|
||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||
import { BotGenerationDetails } from "@spt-aki/models/spt/bots/BotGenerationDetails";
|
||||
import {
|
||||
AdjustmentDetails, EquipmentFilterDetails, EquipmentFilters, IBotConfig,
|
||||
WeightingAdjustmentDetails
|
||||
AdjustmentDetails,
|
||||
EquipmentFilterDetails,
|
||||
EquipmentFilters,
|
||||
IBotConfig,
|
||||
WeightingAdjustmentDetails,
|
||||
} from "@spt-aki/models/spt/config/IBotConfig";
|
||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||
@ -27,7 +31,7 @@ export class BotEquipmentFilterService
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("BotHelper") protected botHelper: BotHelper,
|
||||
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.botConfig = this.configServer.getConfig(ConfigTypes.BOT);
|
||||
@ -41,27 +45,35 @@ export class BotEquipmentFilterService
|
||||
* @param botLevel Level of the bot
|
||||
* @param botGenerationDetails details on how to generate a bot
|
||||
*/
|
||||
public filterBotEquipment(sessionId: string, baseBotNode: IBotType, botLevel: number, botGenerationDetails: BotGenerationDetails): void
|
||||
public filterBotEquipment(
|
||||
sessionId: string,
|
||||
baseBotNode: IBotType,
|
||||
botLevel: number,
|
||||
botGenerationDetails: BotGenerationDetails,
|
||||
): void
|
||||
{
|
||||
const pmcProfile = this.profileHelper.getPmcProfile(sessionId);
|
||||
|
||||
const botRole = (botGenerationDetails.isPmc)
|
||||
? "pmc"
|
||||
: botGenerationDetails.role;
|
||||
const botRole = (botGenerationDetails.isPmc) ?
|
||||
"pmc" :
|
||||
botGenerationDetails.role;
|
||||
const botEquipmentBlacklist = this.getBotEquipmentBlacklist(botRole, botLevel);
|
||||
const botEquipmentWhitelist = this.getBotEquipmentWhitelist(botRole, botLevel);
|
||||
const botWeightingAdjustments = this.getBotWeightingAdjustments(botRole, botLevel);
|
||||
const botWeightingAdjustmentsByPlayerLevel = this.getBotWeightingAdjustmentsByPlayerLevel(botRole, pmcProfile.Info.Level);
|
||||
const botWeightingAdjustmentsByPlayerLevel = this.getBotWeightingAdjustmentsByPlayerLevel(
|
||||
botRole,
|
||||
pmcProfile.Info.Level,
|
||||
);
|
||||
|
||||
const botEquipConfig = this.botConfig.equipment[botRole];
|
||||
const randomisationDetails = this.botHelper.getBotRandomizationDetails(botLevel, botEquipConfig);
|
||||
|
||||
|
||||
if (botEquipmentBlacklist || botEquipmentWhitelist)
|
||||
{
|
||||
this.filterEquipment(baseBotNode, botEquipmentBlacklist, botEquipmentWhitelist);
|
||||
this.filterCartridges(baseBotNode, botEquipmentBlacklist, botEquipmentWhitelist);
|
||||
}
|
||||
|
||||
|
||||
if (botWeightingAdjustments)
|
||||
{
|
||||
this.adjustWeighting(botWeightingAdjustments?.equipment, baseBotNode.inventory.equipment);
|
||||
@ -107,7 +119,10 @@ export class BotEquipmentFilterService
|
||||
* @param generationChanges Changes to apply
|
||||
* @param baseBotGeneration dictionary to update
|
||||
*/
|
||||
protected adjustGenerationChances(generationChanges: Record<string, GenerationData>, baseBotGeneration: Generation): void
|
||||
protected adjustGenerationChances(
|
||||
generationChanges: Record<string, GenerationData>,
|
||||
baseBotGeneration: Generation,
|
||||
): void
|
||||
{
|
||||
if (!generationChanges)
|
||||
{
|
||||
@ -159,12 +174,17 @@ export class BotEquipmentFilterService
|
||||
const blacklistDetailsForBot = this.botEquipmentConfig[botRole];
|
||||
|
||||
// No equipment blacklist found, skip
|
||||
if (!blacklistDetailsForBot || Object.keys(blacklistDetailsForBot).length === 0 || !blacklistDetailsForBot.blacklist)
|
||||
if (
|
||||
!blacklistDetailsForBot || Object.keys(blacklistDetailsForBot).length === 0 ||
|
||||
!blacklistDetailsForBot.blacklist
|
||||
)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return blacklistDetailsForBot.blacklist.find(x => playerLevel >= x.levelRange.min && playerLevel <= x.levelRange.max);
|
||||
return blacklistDetailsForBot.blacklist.find((x) =>
|
||||
playerLevel >= x.levelRange.min && playerLevel <= x.levelRange.max
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,7 +203,9 @@ export class BotEquipmentFilterService
|
||||
return null;
|
||||
}
|
||||
|
||||
return botEquipmentConfig.whitelist.find(x => playerLevel >= x.levelRange.min && playerLevel <= x.levelRange.max);
|
||||
return botEquipmentConfig.whitelist.find((x) =>
|
||||
playerLevel >= x.levelRange.min && playerLevel <= x.levelRange.max
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -197,12 +219,17 @@ export class BotEquipmentFilterService
|
||||
const botEquipmentConfig = this.botEquipmentConfig[botRole];
|
||||
|
||||
// No config found, skip
|
||||
if (!botEquipmentConfig || Object.keys(botEquipmentConfig).length === 0 || !botEquipmentConfig.weightingAdjustmentsByBotLevel)
|
||||
if (
|
||||
!botEquipmentConfig || Object.keys(botEquipmentConfig).length === 0 ||
|
||||
!botEquipmentConfig.weightingAdjustmentsByBotLevel
|
||||
)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return botEquipmentConfig.weightingAdjustmentsByBotLevel.find(x => botLevel >= x.levelRange.min && botLevel <= x.levelRange.max);
|
||||
return botEquipmentConfig.weightingAdjustmentsByBotLevel.find((x) =>
|
||||
botLevel >= x.levelRange.min && botLevel <= x.levelRange.max
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -216,12 +243,17 @@ export class BotEquipmentFilterService
|
||||
const botEquipmentConfig = this.botEquipmentConfig[botRole];
|
||||
|
||||
// No config found, skip
|
||||
if (!botEquipmentConfig || Object.keys(botEquipmentConfig).length === 0 || !botEquipmentConfig.weightingAdjustmentsByPlayerLevel)
|
||||
if (
|
||||
!botEquipmentConfig || Object.keys(botEquipmentConfig).length === 0 ||
|
||||
!botEquipmentConfig.weightingAdjustmentsByPlayerLevel
|
||||
)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return botEquipmentConfig.weightingAdjustmentsByPlayerLevel.find(x => playerlevel >= x.levelRange.min && playerlevel <= x.levelRange.max);
|
||||
return botEquipmentConfig.weightingAdjustmentsByPlayerLevel.find((x) =>
|
||||
playerlevel >= x.levelRange.min && playerlevel <= x.levelRange.max
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -231,7 +263,11 @@ export class BotEquipmentFilterService
|
||||
* @param blacklist equipment blacklist
|
||||
* @returns Filtered bot file
|
||||
*/
|
||||
protected filterEquipment(baseBotNode: IBotType, blacklist: EquipmentFilterDetails, whitelist: EquipmentFilterDetails): void
|
||||
protected filterEquipment(
|
||||
baseBotNode: IBotType,
|
||||
blacklist: EquipmentFilterDetails,
|
||||
whitelist: EquipmentFilterDetails,
|
||||
): void
|
||||
{
|
||||
if (whitelist)
|
||||
{
|
||||
@ -247,7 +283,9 @@ export class BotEquipmentFilterService
|
||||
}
|
||||
|
||||
// Filter equipment slot items to just items in whitelist
|
||||
baseBotNode.inventory.equipment[equipmentSlotKey] = Object.keys(botEquipment).filter((tpl) => whitelistEquipmentForSlot.includes(tpl)).reduce( (res, key) => (res[key] = botEquipment[key], res), {} );
|
||||
baseBotNode.inventory.equipment[equipmentSlotKey] = Object.keys(botEquipment).filter((tpl) =>
|
||||
whitelistEquipmentForSlot.includes(tpl)
|
||||
).reduce((res, key) => (res[key] = botEquipment[key], res), {});
|
||||
}
|
||||
|
||||
return;
|
||||
@ -267,7 +305,9 @@ export class BotEquipmentFilterService
|
||||
}
|
||||
|
||||
// Filter equipment slot items to just items not in blacklist
|
||||
baseBotNode.inventory.equipment[equipmentSlotKey] = Object.keys(botEquipment).filter((tpl) => !equipmentSlotBlacklist.includes(tpl)).reduce( (res, key) => (res[key] = botEquipment[key], res), {} );
|
||||
baseBotNode.inventory.equipment[equipmentSlotKey] = Object.keys(botEquipment).filter((tpl) =>
|
||||
!equipmentSlotBlacklist.includes(tpl)
|
||||
).reduce((res, key) => (res[key] = botEquipment[key], res), {});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -280,7 +320,11 @@ export class BotEquipmentFilterService
|
||||
* @param whitelist equipment on this list should be used exclusively
|
||||
* @returns Filtered bot file
|
||||
*/
|
||||
protected filterCartridges(baseBotNode: IBotType, blacklist: EquipmentFilterDetails, whitelist: EquipmentFilterDetails): void
|
||||
protected filterCartridges(
|
||||
baseBotNode: IBotType,
|
||||
blacklist: EquipmentFilterDetails,
|
||||
whitelist: EquipmentFilterDetails,
|
||||
): void
|
||||
{
|
||||
if (whitelist)
|
||||
{
|
||||
@ -296,7 +340,9 @@ export class BotEquipmentFilterService
|
||||
}
|
||||
|
||||
// Filter caliber slot items to just items in whitelist
|
||||
baseBotNode.inventory.Ammo[ammoCaliberKey] = Object.keys(botAmmo).filter((tpl) => whitelist.cartridge[ammoCaliberKey].includes(tpl)).reduce( (res, key) => (res[key] = botAmmo[key], res), {} );
|
||||
baseBotNode.inventory.Ammo[ammoCaliberKey] = Object.keys(botAmmo).filter((tpl) =>
|
||||
whitelist.cartridge[ammoCaliberKey].includes(tpl)
|
||||
).reduce((res, key) => (res[key] = botAmmo[key], res), {});
|
||||
}
|
||||
|
||||
return;
|
||||
@ -316,7 +362,9 @@ export class BotEquipmentFilterService
|
||||
}
|
||||
|
||||
// Filter cartridge slot items to just items not in blacklist
|
||||
baseBotNode.inventory.Ammo[ammoCaliberKey] = Object.keys(botAmmo).filter((tpl) => !cartridgeCaliberBlacklist.includes(tpl)).reduce( (res, key) => (res[key] = botAmmo[key], res), {} );
|
||||
baseBotNode.inventory.Ammo[ammoCaliberKey] = Object.keys(botAmmo).filter((tpl) =>
|
||||
!cartridgeCaliberBlacklist.includes(tpl)
|
||||
).reduce((res, key) => (res[key] = botAmmo[key], res), {});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -326,7 +374,11 @@ export class BotEquipmentFilterService
|
||||
* @param weightingAdjustments Weighting change to apply to bot
|
||||
* @param botItemPool Bot item dictionary to adjust
|
||||
*/
|
||||
protected adjustWeighting(weightingAdjustments: AdjustmentDetails, botItemPool: Record<string, any>, showEditWarnings = true): void
|
||||
protected adjustWeighting(
|
||||
weightingAdjustments: AdjustmentDetails,
|
||||
botItemPool: Record<string, any>,
|
||||
showEditWarnings = true,
|
||||
): void
|
||||
{
|
||||
if (!weightingAdjustments)
|
||||
{
|
||||
@ -361,12 +413,13 @@ export class BotEquipmentFilterService
|
||||
{
|
||||
if (showEditWarnings)
|
||||
{
|
||||
this.logger.warning(`Tried to edit a non-existent item for slot: ${poolAdjustmentKey} ${itemToEditKey}`);
|
||||
this.logger.warning(
|
||||
`Tried to edit a non-existent item for slot: ${poolAdjustmentKey} ${itemToEditKey}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export class BotEquipmentModPoolService
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.botConfig = this.configServer.getConfig(ConfigTypes.BOT);
|
||||
@ -48,12 +48,17 @@ export class BotEquipmentModPoolService
|
||||
}
|
||||
|
||||
// Get weapon or gear pool
|
||||
const pool = (poolType === "weapon" ? this.weaponModPool : this.gearModPool);
|
||||
const pool = poolType === "weapon" ? this.weaponModPool : this.gearModPool;
|
||||
for (const item of items)
|
||||
{
|
||||
if (!item._props)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("bot-item_missing_props_property", {itemTpl: item._id, name: item._name}));
|
||||
this.logger.error(
|
||||
this.localisationService.getText("bot-item_missing_props_property", {
|
||||
itemTpl: item._id,
|
||||
name: item._name,
|
||||
}),
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
@ -85,9 +90,9 @@ export class BotEquipmentModPoolService
|
||||
{
|
||||
pool[item._id][slot._name] = [];
|
||||
}
|
||||
|
||||
|
||||
// only add item to pool if it doesnt already exist
|
||||
if (!pool[item._id][slot._name].some(x => x === itemToAdd))
|
||||
if (!pool[item._id][slot._name].some((x) => x === itemToAdd))
|
||||
{
|
||||
pool[item._id][slot._name].push(itemToAdd);
|
||||
|
||||
@ -99,7 +104,7 @@ export class BotEquipmentModPoolService
|
||||
// Recursive call
|
||||
this.generatePool([subItemDetails], poolType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -181,7 +186,9 @@ export class BotEquipmentModPoolService
|
||||
*/
|
||||
protected generateWeaponPool(): void
|
||||
{
|
||||
const weapons = Object.values(this.databaseServer.getTables().templates.items).filter(x => x._type === "Item" && this.itemHelper.isOfBaseclass(x._id, BaseClasses.WEAPON));
|
||||
const weapons = Object.values(this.databaseServer.getTables().templates.items).filter((x) =>
|
||||
x._type === "Item" && this.itemHelper.isOfBaseclass(x._id, BaseClasses.WEAPON)
|
||||
);
|
||||
this.generatePool(weapons, "weapon");
|
||||
|
||||
// Flag pool as being complete
|
||||
@ -193,10 +200,12 @@ export class BotEquipmentModPoolService
|
||||
*/
|
||||
protected generateGearPool(): void
|
||||
{
|
||||
const gear = Object.values(this.databaseServer.getTables().templates.items).filter(x => x._type === "Item" && this.itemHelper.isOfBaseclass(x._id, BaseClasses.ARMOREDEQUIPMENT));
|
||||
const gear = Object.values(this.databaseServer.getTables().templates.items).filter((x) =>
|
||||
x._type === "Item" && this.itemHelper.isOfBaseclass(x._id, BaseClasses.ARMOREDEQUIPMENT)
|
||||
);
|
||||
this.generatePool(gear, "gear");
|
||||
|
||||
// Flag pool as being complete
|
||||
this.armorPoolGenerated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,22 +11,22 @@ import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
||||
export class BotGenerationCacheService
|
||||
{
|
||||
protected storedBots: Map<string, IBotBase[]> = new Map();
|
||||
|
||||
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("BotHelper") protected botHelper: BotHelper
|
||||
@inject("BotHelper") protected botHelper: BotHelper,
|
||||
)
|
||||
{ }
|
||||
|
||||
{}
|
||||
|
||||
/**
|
||||
* Store array of bots in cache, shuffle results before storage
|
||||
* @param botsToStore Bots we want to store in the cache
|
||||
*/
|
||||
public storeBots(key: string, botsToStore: IBotBase[]): void
|
||||
{
|
||||
{
|
||||
for (const bot of botsToStore)
|
||||
{
|
||||
if (this.storedBots.has(key))
|
||||
@ -63,7 +63,7 @@ export class BotGenerationCacheService
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove all cached bot profiles from memory
|
||||
*/
|
||||
@ -71,7 +71,7 @@ export class BotGenerationCacheService
|
||||
{
|
||||
this.storedBots = new Map();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does cache have a bot with requested key
|
||||
* @returns false if empty
|
||||
@ -80,4 +80,4 @@ export class BotGenerationCacheService
|
||||
{
|
||||
return this.storedBots.has(key) && this.storedBots.get(key).length > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ export class BotLootCacheService
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("PMCLootGenerator") protected pmcLootGenerator: PMCLootGenerator,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("RagfairPriceService") protected ragfairPriceService: RagfairPriceService
|
||||
@inject("RagfairPriceService") protected ragfairPriceService: RagfairPriceService,
|
||||
)
|
||||
{
|
||||
this.clearCache();
|
||||
@ -46,7 +46,12 @@ export class BotLootCacheService
|
||||
* @param botJsonTemplate Base json db file for the bot having its loot generated
|
||||
* @returns ITemplateItem array
|
||||
*/
|
||||
public getLootFromCache(botRole: string, isPmc: boolean, lootType: LootCacheType, botJsonTemplate: IBotType): ITemplateItem[]
|
||||
public getLootFromCache(
|
||||
botRole: string,
|
||||
isPmc: boolean,
|
||||
lootType: LootCacheType,
|
||||
botJsonTemplate: IBotType,
|
||||
): ITemplateItem[]
|
||||
{
|
||||
if (!this.botRoleExistsInCache(botRole))
|
||||
{
|
||||
@ -75,7 +80,13 @@ export class BotLootCacheService
|
||||
case LootCacheType.STIM_ITEMS:
|
||||
return this.lootCache[botRole].stimItems;
|
||||
default:
|
||||
this.logger.error(this.localisationService.getText("bot-loot_type_not_found", {lootType: lootType, botRole: botRole, isPmc: isPmc}));
|
||||
this.logger.error(
|
||||
this.localisationService.getText("bot-loot_type_not_found", {
|
||||
lootType: lootType,
|
||||
botRole: botRole,
|
||||
isPmc: isPmc,
|
||||
}),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -138,7 +149,7 @@ export class BotLootCacheService
|
||||
itemsToAdd = pool.map((lootTpl: string) => items[lootTpl]);
|
||||
this.addUniqueItemsToPool(backpackLootTemplates, itemsToAdd);
|
||||
}
|
||||
|
||||
|
||||
// Add items to combined pool if any exist
|
||||
if (Object.keys(itemsToAdd).length > 0)
|
||||
{
|
||||
@ -154,61 +165,67 @@ export class BotLootCacheService
|
||||
this.sortPoolByRagfairPrice(combinedPoolTemplates);
|
||||
|
||||
// use whitelist if array has values, otherwise process above sorted pools
|
||||
const specialLootItems = (botJsonTemplate.generation.items.specialItems.whitelist?.length > 0)
|
||||
? botJsonTemplate.generation.items.specialItems.whitelist.map(x => this.itemHelper.getItem(x)[1])
|
||||
: specialLootTemplates.filter(template =>
|
||||
!(this.isBulletOrGrenade(template._props)
|
||||
|| this.isMagazine(template._props)));
|
||||
const specialLootItems = (botJsonTemplate.generation.items.specialItems.whitelist?.length > 0) ?
|
||||
botJsonTemplate.generation.items.specialItems.whitelist.map((x) => this.itemHelper.getItem(x)[1]) :
|
||||
specialLootTemplates.filter((template) =>
|
||||
!(this.isBulletOrGrenade(template._props) ||
|
||||
this.isMagazine(template._props))
|
||||
);
|
||||
|
||||
const healingItems = (botJsonTemplate.generation.items.healing.whitelist?.length > 0)
|
||||
? botJsonTemplate.generation.items.healing.whitelist.map(x => this.itemHelper.getItem(x)[1])
|
||||
: combinedPoolTemplates.filter(template =>
|
||||
this.isMedicalItem(template._props)
|
||||
&& template._parent !== BaseClasses.STIMULATOR
|
||||
&& template._parent !== BaseClasses.DRUGS);
|
||||
const healingItems = (botJsonTemplate.generation.items.healing.whitelist?.length > 0) ?
|
||||
botJsonTemplate.generation.items.healing.whitelist.map((x) => this.itemHelper.getItem(x)[1]) :
|
||||
combinedPoolTemplates.filter((template) =>
|
||||
this.isMedicalItem(template._props) &&
|
||||
template._parent !== BaseClasses.STIMULATOR &&
|
||||
template._parent !== BaseClasses.DRUGS
|
||||
);
|
||||
|
||||
const drugItems = (botJsonTemplate.generation.items.drugs.whitelist?.length > 0)
|
||||
? botJsonTemplate.generation.items.drugs.whitelist.map(x => this.itemHelper.getItem(x)[1])
|
||||
: combinedPoolTemplates.filter(template =>
|
||||
this.isMedicalItem(template._props)
|
||||
&& template._parent === BaseClasses.DRUGS);
|
||||
const drugItems = (botJsonTemplate.generation.items.drugs.whitelist?.length > 0) ?
|
||||
botJsonTemplate.generation.items.drugs.whitelist.map((x) => this.itemHelper.getItem(x)[1]) :
|
||||
combinedPoolTemplates.filter((template) =>
|
||||
this.isMedicalItem(template._props) &&
|
||||
template._parent === BaseClasses.DRUGS
|
||||
);
|
||||
|
||||
const stimItems = (botJsonTemplate.generation.items.stims.whitelist?.length > 0)
|
||||
? botJsonTemplate.generation.items.stims.whitelist.map(x => this.itemHelper.getItem(x)[1])
|
||||
: combinedPoolTemplates.filter(template =>
|
||||
this.isMedicalItem(template._props)
|
||||
&& template._parent === BaseClasses.STIMULATOR);
|
||||
const stimItems = (botJsonTemplate.generation.items.stims.whitelist?.length > 0) ?
|
||||
botJsonTemplate.generation.items.stims.whitelist.map((x) => this.itemHelper.getItem(x)[1]) :
|
||||
combinedPoolTemplates.filter((template) =>
|
||||
this.isMedicalItem(template._props) &&
|
||||
template._parent === BaseClasses.STIMULATOR
|
||||
);
|
||||
|
||||
const grenadeItems = (botJsonTemplate.generation.items.grenades.whitelist?.length > 0)
|
||||
? botJsonTemplate.generation.items.grenades.whitelist.map(x => this.itemHelper.getItem(x)[1])
|
||||
: combinedPoolTemplates.filter(template =>
|
||||
this.isGrenade(template._props));
|
||||
const grenadeItems = (botJsonTemplate.generation.items.grenades.whitelist?.length > 0) ?
|
||||
botJsonTemplate.generation.items.grenades.whitelist.map((x) => this.itemHelper.getItem(x)[1]) :
|
||||
combinedPoolTemplates.filter((template) => this.isGrenade(template._props));
|
||||
|
||||
// Get loot items (excluding magazines, bullets, grenades and healing items)
|
||||
const backpackLootItems = backpackLootTemplates.filter(template =>
|
||||
const backpackLootItems = backpackLootTemplates.filter((template) =>
|
||||
// biome-ignore lint/complexity/useSimplifiedLogicExpression: <explanation>
|
||||
!this.isBulletOrGrenade(template._props)
|
||||
&& !this.isMagazine(template._props)
|
||||
//&& !this.isMedicalItem(template._props) // Disabled for now as followSanitar has a lot of med items as loot
|
||||
&& !this.isGrenade(template._props));
|
||||
!this.isBulletOrGrenade(template._props) &&
|
||||
!this.isMagazine(template._props) &&
|
||||
// && !this.isMedicalItem(template._props) // Disabled for now as followSanitar has a lot of med items as loot
|
||||
!this.isGrenade(template._props)
|
||||
);
|
||||
|
||||
// Get pocket loot
|
||||
const pocketLootItems = pocketLootTemplates.filter(template =>
|
||||
const pocketLootItems = pocketLootTemplates.filter((template) =>
|
||||
// biome-ignore lint/complexity/useSimplifiedLogicExpression: <explanation>
|
||||
!this.isBulletOrGrenade(template._props)
|
||||
&& !this.isMagazine(template._props)
|
||||
&& !this.isMedicalItem(template._props)
|
||||
&& !this.isGrenade(template._props)
|
||||
&& ("Height" in template._props)
|
||||
&& ("Width" in template._props));
|
||||
!this.isBulletOrGrenade(template._props) &&
|
||||
!this.isMagazine(template._props) &&
|
||||
!this.isMedicalItem(template._props) &&
|
||||
!this.isGrenade(template._props) &&
|
||||
("Height" in template._props) &&
|
||||
("Width" in template._props)
|
||||
);
|
||||
|
||||
// Get vest loot items
|
||||
const vestLootItems = vestLootTemplates.filter(template =>
|
||||
const vestLootItems = vestLootTemplates.filter((template) =>
|
||||
// biome-ignore lint/complexity/useSimplifiedLogicExpression: <explanation>
|
||||
!this.isBulletOrGrenade(template._props)
|
||||
&& !this.isMagazine(template._props)
|
||||
&& !this.isMedicalItem(template._props)
|
||||
&& !this.isGrenade(template._props));
|
||||
!this.isBulletOrGrenade(template._props) &&
|
||||
!this.isMagazine(template._props) &&
|
||||
!this.isMedicalItem(template._props) &&
|
||||
!this.isGrenade(template._props)
|
||||
);
|
||||
|
||||
this.lootCache[botRole].healingItems = healingItems;
|
||||
this.lootCache[botRole].drugItems = drugItems;
|
||||
@ -227,7 +244,12 @@ export class BotLootCacheService
|
||||
*/
|
||||
protected sortPoolByRagfairPrice(poolToSort: ITemplateItem[]): void
|
||||
{
|
||||
poolToSort.sort((a, b) => this.compareByValue(this.ragfairPriceService.getFleaPriceForItem(a._id), this.ragfairPriceService.getFleaPriceForItem(b._id)));
|
||||
poolToSort.sort((a, b) =>
|
||||
this.compareByValue(
|
||||
this.ragfairPriceService.getFleaPriceForItem(a._id),
|
||||
this.ragfairPriceService.getFleaPriceForItem(b._id),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -246,15 +268,15 @@ export class BotLootCacheService
|
||||
const mergedItemPools = [...combinedItemPool, ...itemsToAdd];
|
||||
|
||||
// Save only unique array values
|
||||
const uniqueResults = [... new Set([].concat(...mergedItemPools))];
|
||||
const uniqueResults = [...new Set([].concat(...mergedItemPools))];
|
||||
combinedItemPool.splice(0, combinedItemPool.length);
|
||||
combinedItemPool.push(...uniqueResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ammo/grenades have this property
|
||||
* @param props
|
||||
* @returns
|
||||
* @param props
|
||||
* @returns
|
||||
*/
|
||||
protected isBulletOrGrenade(props: Props): boolean
|
||||
{
|
||||
@ -263,8 +285,8 @@ export class BotLootCacheService
|
||||
|
||||
/**
|
||||
* Internal and external magazine have this property
|
||||
* @param props
|
||||
* @returns
|
||||
* @param props
|
||||
* @returns
|
||||
*/
|
||||
protected isMagazine(props: Props): boolean
|
||||
{
|
||||
@ -273,8 +295,8 @@ export class BotLootCacheService
|
||||
|
||||
/**
|
||||
* Medical use items (e.g. morphine/lip balm/grizzly)
|
||||
* @param props
|
||||
* @returns
|
||||
* @param props
|
||||
* @returns
|
||||
*/
|
||||
protected isMedicalItem(props: Props): boolean
|
||||
{
|
||||
@ -283,8 +305,8 @@ export class BotLootCacheService
|
||||
|
||||
/**
|
||||
* Grenades have this property (e.g. smoke/frag/flash grenades)
|
||||
* @param props
|
||||
* @returns
|
||||
* @param props
|
||||
* @returns
|
||||
*/
|
||||
protected isGrenade(props: Props): boolean
|
||||
{
|
||||
@ -317,7 +339,7 @@ export class BotLootCacheService
|
||||
grenadeItems: [],
|
||||
drugItems: [],
|
||||
healingItems: [],
|
||||
stimItems: []
|
||||
stimItems: [],
|
||||
};
|
||||
}
|
||||
|
||||
@ -326,9 +348,9 @@ export class BotLootCacheService
|
||||
* -1 when a < b
|
||||
* 0 when a === b
|
||||
* 1 when a > b
|
||||
* @param itemAPrice
|
||||
* @param itemBPrice
|
||||
* @returns
|
||||
* @param itemAPrice
|
||||
* @param itemBPrice
|
||||
* @returns
|
||||
*/
|
||||
protected compareByValue(itemAPrice: number, itemBPrice: number): number
|
||||
{
|
||||
@ -355,5 +377,4 @@ export class BotLootCacheService
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ export class BotWeaponModLimitService
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
)
|
||||
{
|
||||
this.botConfig = this.configServer.getConfig(ConfigTypes.BOT);
|
||||
@ -48,10 +48,20 @@ export class BotWeaponModLimitService
|
||||
return {
|
||||
scope: {count: 0},
|
||||
scopeMax: this.botConfig.equipment[botRole]?.weaponModLimits?.scopeLimit,
|
||||
scopeBaseTypes: [BaseClasses.OPTIC_SCOPE, BaseClasses.ASSAULT_SCOPE, BaseClasses.COLLIMATOR, BaseClasses.COMPACT_COLLIMATOR, BaseClasses.SPECIAL_SCOPE],
|
||||
scopeBaseTypes: [
|
||||
BaseClasses.OPTIC_SCOPE,
|
||||
BaseClasses.ASSAULT_SCOPE,
|
||||
BaseClasses.COLLIMATOR,
|
||||
BaseClasses.COMPACT_COLLIMATOR,
|
||||
BaseClasses.SPECIAL_SCOPE,
|
||||
],
|
||||
flashlightLaser: {count: 0},
|
||||
flashlightLaserMax: this.botConfig.equipment[botRole]?.weaponModLimits?.lightLaserLimit,
|
||||
flashlgihtLaserBaseTypes: [BaseClasses.TACTICAL_COMBO, BaseClasses.FLASHLIGHT, BaseClasses.PORTABLE_RANGE_FINDER]
|
||||
flashlgihtLaserBaseTypes: [
|
||||
BaseClasses.TACTICAL_COMBO,
|
||||
BaseClasses.FLASHLIGHT,
|
||||
BaseClasses.PORTABLE_RANGE_FINDER,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@ -67,14 +77,28 @@ export class BotWeaponModLimitService
|
||||
* @param modsParent The parent of the mod to be checked
|
||||
* @returns true if over item limit
|
||||
*/
|
||||
public weaponModHasReachedLimit(botRole: string, modTemplate: ITemplateItem, modLimits: BotModLimits, modsParent: ITemplateItem, weapon: Item[]): boolean
|
||||
public weaponModHasReachedLimit(
|
||||
botRole: string,
|
||||
modTemplate: ITemplateItem,
|
||||
modLimits: BotModLimits,
|
||||
modsParent: ITemplateItem,
|
||||
weapon: Item[],
|
||||
): boolean
|
||||
{
|
||||
// If mod or mods parent is the NcSTAR MPR45 Backup mount, allow it as it looks cool
|
||||
const ncSTARTpl = "5649a2464bdc2d91118b45a8";
|
||||
if (modsParent._id === ncSTARTpl || modTemplate._id === ncSTARTpl)
|
||||
{
|
||||
// If weapon already has a longer ranged scope on it, allow ncstar to be spawned
|
||||
if (weapon.some(x => this.itemHelper.isOfBaseclasses(x._tpl, [BaseClasses.ASSAULT_SCOPE, BaseClasses.OPTIC_SCOPE, BaseClasses.SPECIAL_SCOPE])))
|
||||
if (
|
||||
weapon.some((x) =>
|
||||
this.itemHelper.isOfBaseclasses(x._tpl, [
|
||||
BaseClasses.ASSAULT_SCOPE,
|
||||
BaseClasses.OPTIC_SCOPE,
|
||||
BaseClasses.SPECIAL_SCOPE,
|
||||
])
|
||||
)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -96,10 +120,12 @@ export class BotWeaponModLimitService
|
||||
}
|
||||
|
||||
// Mod is a mount that can hold only scopes and limit is reached (dont want to add empty mounts if limit is reached)
|
||||
if (this.itemHelper.isOfBaseclass(modTemplate._id, BaseClasses.MOUNT)
|
||||
&& modTemplate._props.Slots.some(x => x._name === "mod_scope")
|
||||
&& modTemplate._props.Slots.length === 1
|
||||
&& modLimits.scope.count >= modLimits.scopeMax)
|
||||
if (
|
||||
this.itemHelper.isOfBaseclass(modTemplate._id, BaseClasses.MOUNT) &&
|
||||
modTemplate._props.Slots.some((x) => x._name === "mod_scope") &&
|
||||
modTemplate._props.Slots.length === 1 &&
|
||||
modLimits.scope.count >= modLimits.scopeMax
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -108,14 +134,21 @@ export class BotWeaponModLimitService
|
||||
const modIsLightOrLaser = this.itemHelper.isOfBaseclasses(modTemplate._id, modLimits.flashlgihtLaserBaseTypes);
|
||||
if (modIsLightOrLaser)
|
||||
{
|
||||
return this.weaponModLimitReached(modTemplate._id, modLimits.flashlightLaser, modLimits.flashlightLaserMax, botRole);
|
||||
return this.weaponModLimitReached(
|
||||
modTemplate._id,
|
||||
modLimits.flashlightLaser,
|
||||
modLimits.flashlightLaserMax,
|
||||
botRole,
|
||||
);
|
||||
}
|
||||
|
||||
// Mod is a mount that can hold only flashlights ad limit is reached (dont want to add empty mounts if limit is reached)
|
||||
if (this.itemHelper.isOfBaseclass(modTemplate._id, BaseClasses.MOUNT)
|
||||
&& modTemplate._props.Slots.some(x => x._name === "mod_flashlight")
|
||||
&& modTemplate._props.Slots.length === 1
|
||||
&& modLimits.scope.count >= modLimits.scopeMax)
|
||||
if (
|
||||
this.itemHelper.isOfBaseclass(modTemplate._id, BaseClasses.MOUNT) &&
|
||||
modTemplate._props.Slots.some((x) => x._name === "mod_flashlight") &&
|
||||
modTemplate._props.Slots.length === 1 &&
|
||||
modLimits.scope.count >= modLimits.scopeMax
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -131,8 +164,12 @@ export class BotWeaponModLimitService
|
||||
* @param botRole role of bot we're checking weapon of
|
||||
* @returns true if limit reached
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
protected weaponModLimitReached(modTpl: string, currentCount: { count: number; }, maxLimit: number, botRole: string): boolean
|
||||
protected weaponModLimitReached(
|
||||
modTpl: string,
|
||||
currentCount: {count: number;},
|
||||
maxLimit: number,
|
||||
botRole: string,
|
||||
): boolean
|
||||
{
|
||||
// No value or 0
|
||||
if (!maxLimit)
|
||||
@ -143,7 +180,7 @@ export class BotWeaponModLimitService
|
||||
// Has mod limit for bot type been reached
|
||||
if (currentCount.count >= maxLimit)
|
||||
{
|
||||
//this.logger.debug(`[${botRole}] scope limit reached! tried to add ${modTpl} but scope count is ${currentCount.count}`);
|
||||
// this.logger.debug(`[${botRole}] scope limit reached! tried to add ${modTpl} but scope count is ${currentCount.count}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -152,4 +189,4 @@ export class BotWeaponModLimitService
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ export class CustomLocationWaveService
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.locationConfig = this.configServer.getConfig(ConfigTypes.LOCATION);
|
||||
@ -76,13 +76,15 @@ export class CustomLocationWaveService
|
||||
const location: ILocationBase = this.databaseServer.getTables().locations[mapKey].base;
|
||||
for (const bossWave of bossWavesToApply[mapKey])
|
||||
{
|
||||
if (location.BossLocationSpawn.find(x => x.sptId === bossWave.sptId))
|
||||
if (location.BossLocationSpawn.find((x) => x.sptId === bossWave.sptId))
|
||||
{
|
||||
// Already exists, skip
|
||||
continue;
|
||||
}
|
||||
location.BossLocationSpawn.push(bossWave);
|
||||
this.logger.debug(`Added custom boss wave to ${mapKey} of type ${bossWave.BossName}, time: ${bossWave.Time}, chance: ${bossWave.BossChance}, zone: ${bossWave.BossZone}`);
|
||||
this.logger.debug(
|
||||
`Added custom boss wave to ${mapKey} of type ${bossWave.BossName}, time: ${bossWave.Time}, chance: ${bossWave.BossChance}, zone: ${bossWave.BossZone}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +93,7 @@ export class CustomLocationWaveService
|
||||
const location: ILocationBase = this.databaseServer.getTables().locations[mapKey].base;
|
||||
for (const normalWave of normalWavesToApply[mapKey])
|
||||
{
|
||||
if (location.waves.find(x => x.sptId === normalWave.sptId))
|
||||
if (location.waves.find((x) => x.sptId === normalWave.sptId))
|
||||
{
|
||||
// Already exists, skip
|
||||
continue;
|
||||
@ -102,4 +104,4 @@ export class CustomLocationWaveService
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ export class FenceService
|
||||
@inject("PresetHelper") protected presetHelper: PresetHelper,
|
||||
@inject("ItemFilterService") protected itemFilterService: ItemFilterService,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.traderConfig = this.configServer.getConfig(ConfigTypes.TRADER);
|
||||
@ -88,13 +88,21 @@ export class FenceService
|
||||
|
||||
// Clone assorts so we can adjust prices before sending to client
|
||||
const assort = this.jsonUtil.clone(this.fenceAssort);
|
||||
this.adjustAssortItemPrices(assort, this.getFenceInfo(pmcProfile).PriceModifier, this.traderConfig.fence.presetPriceMult);
|
||||
this.adjustAssortItemPrices(
|
||||
assort,
|
||||
this.getFenceInfo(pmcProfile).PriceModifier,
|
||||
this.traderConfig.fence.presetPriceMult,
|
||||
);
|
||||
|
||||
// merge normal fence assorts + discount assorts if player standing is large enough
|
||||
if (pmcProfile.TradersInfo[Traders.FENCE].standing >= 6)
|
||||
{
|
||||
const discountAssort = this.jsonUtil.clone(this.fenceDiscountAssort);
|
||||
this.adjustAssortItemPrices(discountAssort, this.traderConfig.fence.discountOptions.itemPriceMult, this.traderConfig.fence.discountOptions.presetPriceMult);
|
||||
this.adjustAssortItemPrices(
|
||||
discountAssort,
|
||||
this.traderConfig.fence.discountOptions.itemPriceMult,
|
||||
this.traderConfig.fence.discountOptions.presetPriceMult,
|
||||
);
|
||||
const mergedAssorts = this.mergeAssorts(assort, discountAssort);
|
||||
|
||||
return mergedAssorts;
|
||||
@ -129,7 +137,7 @@ export class FenceService
|
||||
* @param secondAssort assort #2
|
||||
* @returns merged assort
|
||||
*/
|
||||
protected mergeAssorts(firstAssort: ITraderAssort,secondAssort: ITraderAssort): ITraderAssort
|
||||
protected mergeAssorts(firstAssort: ITraderAssort, secondAssort: ITraderAssort): ITraderAssort
|
||||
{
|
||||
for (const itemId in secondAssort.barter_scheme)
|
||||
{
|
||||
@ -156,14 +164,19 @@ export class FenceService
|
||||
* @param modifier value to multiply item price by
|
||||
* @param presetModifier value to multiply preset price by
|
||||
*/
|
||||
protected adjustItemPriceByModifier(item: Item, assort: ITraderAssort, modifier: number, presetModifier: number): void
|
||||
protected adjustItemPriceByModifier(
|
||||
item: Item,
|
||||
assort: ITraderAssort,
|
||||
modifier: number,
|
||||
presetModifier: number,
|
||||
): void
|
||||
{
|
||||
// Is preset
|
||||
if (item.upd.sptPresetId)
|
||||
{
|
||||
if (assort.barter_scheme[item._id])
|
||||
{
|
||||
assort.barter_scheme[item._id][0][0].count *= (modifier + presetModifier);
|
||||
assort.barter_scheme[item._id][0][0].count *= modifier + presetModifier;
|
||||
}
|
||||
}
|
||||
else if (assort.barter_scheme[item._id])
|
||||
@ -200,7 +213,9 @@ export class FenceService
|
||||
public performPartialRefresh(): void
|
||||
{
|
||||
let itemCountToReplace = this.getCountOfItemsToReplace(this.traderConfig.fence.assortSize);
|
||||
const discountItemCountToReplace = this.getCountOfItemsToReplace(this.traderConfig.fence.discountOptions.assortSize);
|
||||
const discountItemCountToReplace = this.getCountOfItemsToReplace(
|
||||
this.traderConfig.fence.discountOptions.assortSize,
|
||||
);
|
||||
|
||||
// Iterate x times to remove items (only remove if assort has items)
|
||||
if (this.fenceAssort?.items?.length > 0)
|
||||
@ -220,7 +235,6 @@ export class FenceService
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
itemCountToReplace = this.getCountOfItemsToGenerate(itemCountToReplace);
|
||||
|
||||
const newItems = this.createBaseTraderAssortItem();
|
||||
@ -253,7 +267,8 @@ export class FenceService
|
||||
// Add loyalty items to fence discount assorts loyalty object
|
||||
for (const loyaltyItemKey in newDiscountItems.loyal_level_items)
|
||||
{
|
||||
this.fenceDiscountAssort.loyal_level_items[loyaltyItemKey] = newDiscountItems.loyal_level_items[loyaltyItemKey];
|
||||
this.fenceDiscountAssort.loyal_level_items[loyaltyItemKey] =
|
||||
newDiscountItems.loyal_level_items[loyaltyItemKey];
|
||||
}
|
||||
|
||||
this.incrementPartialRefreshTime();
|
||||
@ -264,7 +279,8 @@ export class FenceService
|
||||
*/
|
||||
protected incrementPartialRefreshTime(): void
|
||||
{
|
||||
this.nextMiniRefreshTimestamp = this.timeUtil.getTimestamp() + this.traderConfig.fence.partialRefreshTimeSeconds;
|
||||
this.nextMiniRefreshTimestamp = this.timeUtil.getTimestamp() +
|
||||
this.traderConfig.fence.partialRefreshTimeSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -278,14 +294,14 @@ export class FenceService
|
||||
const desiredTotalCount = this.traderConfig.fence.assortSize;
|
||||
const actualTotalCount = this.fenceAssort.items.reduce((count, item) =>
|
||||
{
|
||||
return item.slotId === "hideout"
|
||||
? count + 1
|
||||
: count;
|
||||
return item.slotId === "hideout" ?
|
||||
count + 1 :
|
||||
count;
|
||||
}, 0);
|
||||
|
||||
return actualTotalCount < desiredTotalCount
|
||||
? (desiredTotalCount - actualTotalCount) + existingItemCountToReplace
|
||||
: existingItemCountToReplace;
|
||||
return actualTotalCount < desiredTotalCount ?
|
||||
(desiredTotalCount - actualTotalCount) + existingItemCountToReplace :
|
||||
existingItemCountToReplace;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -295,9 +311,11 @@ export class FenceService
|
||||
protected removeRandomItemFromAssorts(assort: ITraderAssort): void
|
||||
{
|
||||
// Only remove if assort has items
|
||||
if (!assort.items.some(x => x.slotId === "hideout"))
|
||||
if (!assort.items.some((x) => x.slotId === "hideout"))
|
||||
{
|
||||
this.logger.warning("Unable to remove random assort from trader as they have no assorts with a slotid of `hideout`");
|
||||
this.logger.warning(
|
||||
"Unable to remove random assort from trader as they have no assorts with a slotid of `hideout`",
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -308,12 +326,12 @@ export class FenceService
|
||||
itemToRemove = this.randomUtil.getArrayValue(assort.items);
|
||||
}
|
||||
|
||||
const indexOfItemToRemove = assort.items.findIndex(x => x._id === itemToRemove._id);
|
||||
const indexOfItemToRemove = assort.items.findIndex((x) => x._id === itemToRemove._id);
|
||||
assort.items.splice(indexOfItemToRemove, 1);
|
||||
|
||||
// Clean up any mods if item removed was a weapon
|
||||
// TODO: also check for mods attached down the item chain
|
||||
assort.items = assort.items.filter(x => x.parentId !== itemToRemove._id);
|
||||
assort.items = assort.items.filter((x) => x.parentId !== itemToRemove._id);
|
||||
|
||||
delete assort.barter_scheme[itemToRemove._id];
|
||||
delete assort.loyal_level_items[itemToRemove._id];
|
||||
@ -376,7 +394,7 @@ export class FenceService
|
||||
barter_scheme: {},
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
loyal_level_items: {},
|
||||
nextResupply: this.getNextFenceUpdateTimestamp()
|
||||
nextResupply: this.getNextFenceUpdateTimestamp(),
|
||||
};
|
||||
}
|
||||
|
||||
@ -400,7 +418,14 @@ export class FenceService
|
||||
this.addPresets(randomisedPresetCount, defaultWeaponPresets, assorts, loyaltyLevel);
|
||||
}
|
||||
|
||||
protected addItemAssorts(assortCount: number, fenceAssortIds: string[], assorts: ITraderAssort, fenceAssort: ITraderAssort, itemTypeCounts: Record<string, { current: number; max: number; }>, loyaltyLevel: number): void
|
||||
protected addItemAssorts(
|
||||
assortCount: number,
|
||||
fenceAssortIds: string[],
|
||||
assorts: ITraderAssort,
|
||||
fenceAssort: ITraderAssort,
|
||||
itemTypeCounts: Record<string, {current: number; max: number;}>,
|
||||
loyaltyLevel: number,
|
||||
): void
|
||||
{
|
||||
const priceLimits = this.traderConfig.fence.itemCategoryRoublePriceLimit;
|
||||
for (let i = 0; i < assortCount; i++)
|
||||
@ -420,7 +445,7 @@ export class FenceService
|
||||
// It's a normal non-preset item
|
||||
if (!itemIsPreset)
|
||||
{
|
||||
const desiredAssort = fenceAssort.items[fenceAssort.items.findIndex(i => i._id === itemTpl)];
|
||||
const desiredAssort = fenceAssort.items[fenceAssort.items.findIndex((i) => i._id === itemTpl)];
|
||||
if (!desiredAssort)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("fence-unable_to_find_assort_by_id", itemTpl));
|
||||
@ -481,11 +506,11 @@ export class FenceService
|
||||
if (this.itemHelper.isOfBaseclass(itemDbDetails._id, BaseClasses.AMMO))
|
||||
{
|
||||
// No override, use stack max size from item db
|
||||
return itemDbDetails._props.StackMaxSize === 1
|
||||
? 1
|
||||
: this.randomUtil.getInt(itemDbDetails._props.StackMinRandom, itemDbDetails._props.StackMaxRandom);
|
||||
return itemDbDetails._props.StackMaxSize === 1 ?
|
||||
1 :
|
||||
this.randomUtil.getInt(itemDbDetails._props.StackMinRandom, itemDbDetails._props.StackMaxRandom);
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -496,7 +521,12 @@ export class FenceService
|
||||
* @param assorts object to add presets to
|
||||
* @param loyaltyLevel loyalty level to requre item at
|
||||
*/
|
||||
protected addPresets(desiredPresetCount: number, defaultWeaponPresets: Record<string, IPreset>, assorts: ITraderAssort, loyaltyLevel: number): void
|
||||
protected addPresets(
|
||||
desiredPresetCount: number,
|
||||
defaultWeaponPresets: Record<string, IPreset>,
|
||||
assorts: ITraderAssort,
|
||||
loyaltyLevel: number,
|
||||
): void
|
||||
{
|
||||
let presetCount = 0;
|
||||
const presetKeys = Object.keys(defaultWeaponPresets);
|
||||
@ -512,19 +542,22 @@ export class FenceService
|
||||
}
|
||||
|
||||
// Skip presets we've already added
|
||||
if (assorts.items.some(i => i.upd && i.upd.sptPresetId === preset._id))
|
||||
if (assorts.items.some((i) => i.upd && i.upd.sptPresetId === preset._id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Construct weapon + mods
|
||||
const weaponAndMods: Item[] = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(defaultWeaponPresets[preset._id]._items));
|
||||
const weaponAndMods: Item[] = this.itemHelper.replaceIDs(
|
||||
null,
|
||||
this.jsonUtil.clone(defaultWeaponPresets[preset._id]._items),
|
||||
);
|
||||
this.removeRandomPartsOfWeapon(weaponAndMods);
|
||||
for (let i = 0; i < weaponAndMods.length; i++)
|
||||
{
|
||||
const mod = weaponAndMods[i];
|
||||
|
||||
//build root Item info
|
||||
// build root Item info
|
||||
if (!("parentId" in mod))
|
||||
{
|
||||
mod._id = weaponAndMods[0]._id;
|
||||
@ -534,7 +567,7 @@ export class FenceService
|
||||
UnlimitedCount: false,
|
||||
StackObjectsCount: 1,
|
||||
BuyRestrictionCurrent: 0,
|
||||
sptPresetId: preset._id // Store preset id here so we can check it later to prevent preset dupes
|
||||
sptPresetId: preset._id, // Store preset id here so we can check it later to prevent preset dupes
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -556,7 +589,7 @@ export class FenceService
|
||||
assorts.barter_scheme[weaponAndMods[0]._id] = [[]];
|
||||
assorts.barter_scheme[weaponAndMods[0]._id][0][0] = {
|
||||
_tpl: Money.ROUBLES,
|
||||
count: Math.round(rub)
|
||||
count: Math.round(rub),
|
||||
};
|
||||
|
||||
assorts.loyal_level_items[weaponAndMods[0]._id] = loyaltyLevel;
|
||||
@ -624,9 +657,9 @@ export class FenceService
|
||||
|
||||
// Roll from 0 to 9999, then divide it by 100: 9999 = 99.99%
|
||||
const randomChance = this.randomUtil.getInt(0, 9999) / 100;
|
||||
|
||||
return randomChance > removalChance
|
||||
&& !itemsBeingDeleted.includes(weaponMod._id);
|
||||
|
||||
return randomChance > removalChance &&
|
||||
!itemsBeingDeleted.includes(weaponMod._id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -638,7 +671,9 @@ export class FenceService
|
||||
{
|
||||
if (!itemDetails._props)
|
||||
{
|
||||
this.logger.error(`Item ${itemDetails._name} lacks a _props field, unable to randomise item: ${itemToAdjust._id}`);
|
||||
this.logger.error(
|
||||
`Item ${itemDetails._name} lacks a _props field, unable to randomise item: ${itemToAdjust._id}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -647,28 +682,30 @@ export class FenceService
|
||||
if ("MaxHpResource" in itemDetails._props && itemDetails._props.MaxHpResource > 0)
|
||||
{
|
||||
itemToAdjust.upd.MedKit = {
|
||||
HpResource: this.randomUtil.getInt(1, itemDetails._props.MaxHpResource)
|
||||
HpResource: this.randomUtil.getInt(1, itemDetails._props.MaxHpResource),
|
||||
};
|
||||
}
|
||||
|
||||
// Randomise armor durability
|
||||
if ((itemDetails._parent === BaseClasses.ARMOR
|
||||
|| itemDetails._parent === BaseClasses.HEADWEAR
|
||||
|| itemDetails._parent === BaseClasses.VEST
|
||||
|| itemDetails._parent === BaseClasses.ARMOREDEQUIPMENT
|
||||
|| itemDetails._parent === BaseClasses.FACECOVER)
|
||||
&& itemDetails._props.MaxDurability > 0)
|
||||
if (
|
||||
(itemDetails._parent === BaseClasses.ARMOR ||
|
||||
itemDetails._parent === BaseClasses.HEADWEAR ||
|
||||
itemDetails._parent === BaseClasses.VEST ||
|
||||
itemDetails._parent === BaseClasses.ARMOREDEQUIPMENT ||
|
||||
itemDetails._parent === BaseClasses.FACECOVER) &&
|
||||
itemDetails._props.MaxDurability > 0
|
||||
)
|
||||
{
|
||||
const armorMaxDurabilityLimits = this.traderConfig.fence.armorMaxDurabilityPercentMinMax;
|
||||
const duraMin = (armorMaxDurabilityLimits.min / 100 * itemDetails._props.MaxDurability);
|
||||
const duraMax = (armorMaxDurabilityLimits.max / 100 * itemDetails._props.MaxDurability);
|
||||
const duraMin = armorMaxDurabilityLimits.min / 100 * itemDetails._props.MaxDurability;
|
||||
const duraMax = armorMaxDurabilityLimits.max / 100 * itemDetails._props.MaxDurability;
|
||||
|
||||
const maxDurability = this.randomUtil.getInt(duraMin, duraMax);
|
||||
const durability = this.randomUtil.getInt(1, maxDurability);
|
||||
|
||||
itemToAdjust.upd.Repairable = {
|
||||
Durability: durability,
|
||||
MaxDurability: maxDurability
|
||||
MaxDurability: maxDurability,
|
||||
};
|
||||
|
||||
return;
|
||||
@ -678,15 +715,15 @@ export class FenceService
|
||||
if (this.itemHelper.isOfBaseclass(itemDetails._id, BaseClasses.WEAPON))
|
||||
{
|
||||
const presetMaxDurabilityLimits = this.traderConfig.fence.presetMaxDurabilityPercentMinMax;
|
||||
const duraMin = (presetMaxDurabilityLimits.min / 100 * itemDetails._props.MaxDurability);
|
||||
const duraMax = (presetMaxDurabilityLimits.max / 100 * itemDetails._props.MaxDurability);
|
||||
const duraMin = presetMaxDurabilityLimits.min / 100 * itemDetails._props.MaxDurability;
|
||||
const duraMax = presetMaxDurabilityLimits.max / 100 * itemDetails._props.MaxDurability;
|
||||
|
||||
const maxDurability = this.randomUtil.getInt(duraMin, duraMax);
|
||||
const durability = this.randomUtil.getInt(1, maxDurability);
|
||||
|
||||
itemToAdjust.upd.Repairable = {
|
||||
Durability: durability,
|
||||
MaxDurability: maxDurability
|
||||
MaxDurability: maxDurability,
|
||||
};
|
||||
|
||||
return;
|
||||
@ -695,17 +732,20 @@ export class FenceService
|
||||
if (this.itemHelper.isOfBaseclass(itemDetails._id, BaseClasses.REPAIR_KITS))
|
||||
{
|
||||
itemToAdjust.upd.RepairKit = {
|
||||
Resource: this.randomUtil.getInt(1, itemDetails._props.MaxRepairResource)
|
||||
Resource: this.randomUtil.getInt(1, itemDetails._props.MaxRepairResource),
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Mechanical key + has limited uses
|
||||
if (this.itemHelper.isOfBaseclass(itemDetails._id, BaseClasses.KEY_MECHANICAL) && itemDetails._props.MaximumNumberOfUsage > 1)
|
||||
if (
|
||||
this.itemHelper.isOfBaseclass(itemDetails._id, BaseClasses.KEY_MECHANICAL) &&
|
||||
itemDetails._props.MaximumNumberOfUsage > 1
|
||||
)
|
||||
{
|
||||
itemToAdjust.upd.Key = {
|
||||
NumberOfUsages: this.randomUtil.getInt(0, itemDetails._props.MaximumNumberOfUsage - 1)
|
||||
NumberOfUsages: this.randomUtil.getInt(0, itemDetails._props.MaximumNumberOfUsage - 1),
|
||||
};
|
||||
|
||||
return;
|
||||
@ -718,8 +758,8 @@ export class FenceService
|
||||
const resourceCurrent = this.randomUtil.getInt(1, itemDetails._props.MaxResource);
|
||||
|
||||
itemToAdjust.upd.Resource = {
|
||||
Value : resourceMax - resourceCurrent,
|
||||
UnitsConsumed: resourceCurrent
|
||||
Value: resourceMax - resourceCurrent,
|
||||
UnitsConsumed: resourceCurrent,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -729,15 +769,15 @@ export class FenceService
|
||||
* @param limits limits as defined in config
|
||||
* @returns record, key: item tplId, value: current/max item count allowed
|
||||
*/
|
||||
protected initItemLimitCounter(limits: Record<string, number>): Record<string, {current: number, max: number}>
|
||||
protected initItemLimitCounter(limits: Record<string, number>): Record<string, {current: number; max: number;}>
|
||||
{
|
||||
const itemTypeCounts: Record<string, {current: number, max: number}> = {};
|
||||
const itemTypeCounts: Record<string, {current: number; max: number;}> = {};
|
||||
|
||||
for (const x in limits)
|
||||
{
|
||||
itemTypeCounts[x] = {
|
||||
current: 0,
|
||||
max: limits[x]
|
||||
max: limits[x],
|
||||
};
|
||||
}
|
||||
|
||||
@ -760,7 +800,7 @@ export class FenceService
|
||||
*/
|
||||
protected getFenceRefreshTime(): number
|
||||
{
|
||||
return this.traderConfig.updateTime.find(x => x.traderId === Traders.FENCE).seconds;
|
||||
return this.traderConfig.updateTime.find((x) => x.traderId === Traders.FENCE).seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -802,12 +842,12 @@ export class FenceService
|
||||
*/
|
||||
public removeFenceOffer(assortIdToRemove: string): void
|
||||
{
|
||||
let relatedAssortIndex = this.fenceAssort.items.findIndex(i => i._id === assortIdToRemove);
|
||||
let relatedAssortIndex = this.fenceAssort.items.findIndex((i) => i._id === assortIdToRemove);
|
||||
|
||||
// No offer found in main assort, check discount items
|
||||
if (relatedAssortIndex === -1)
|
||||
{
|
||||
relatedAssortIndex = this.fenceDiscountAssort.items.findIndex(i => i._id === assortIdToRemove);
|
||||
relatedAssortIndex = this.fenceDiscountAssort.items.findIndex((i) => i._id === assortIdToRemove);
|
||||
this.fenceDiscountAssort.items.splice(relatedAssortIndex, 1);
|
||||
|
||||
return;
|
||||
@ -816,4 +856,4 @@ export class FenceService
|
||||
// Remove offer from assort
|
||||
this.fenceAssort.items.splice(relatedAssortIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ export class GiftService
|
||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
||||
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.giftConfig = this.configServer.getConfig(ConfigTypes.GIFTS);
|
||||
@ -77,7 +77,8 @@ export class GiftService
|
||||
playerId,
|
||||
giftData.localeTextId,
|
||||
giftData.items,
|
||||
this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours));
|
||||
this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours),
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -85,10 +86,9 @@ export class GiftService
|
||||
playerId,
|
||||
giftData.messageText,
|
||||
giftData.items,
|
||||
this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours));
|
||||
this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// Handle user messages
|
||||
else if (giftData.sender === GiftSenderType.USER)
|
||||
@ -98,7 +98,8 @@ export class GiftService
|
||||
giftData.senderDetails,
|
||||
giftData.messageText,
|
||||
giftData.items,
|
||||
this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours));
|
||||
this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours),
|
||||
);
|
||||
}
|
||||
else if (giftData.sender === GiftSenderType.TRADER)
|
||||
{
|
||||
@ -110,7 +111,8 @@ export class GiftService
|
||||
MessageType.MESSAGE_WITH_ITEMS,
|
||||
giftData.localeTextId,
|
||||
giftData.items,
|
||||
this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours));
|
||||
this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours),
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -120,8 +122,9 @@ export class GiftService
|
||||
MessageType.MESSAGE_WITH_ITEMS,
|
||||
giftData.messageText,
|
||||
giftData.items,
|
||||
this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours));
|
||||
}
|
||||
this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours),
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -130,10 +133,10 @@ export class GiftService
|
||||
const details: ISendMessageDetails = {
|
||||
recipientId: playerId,
|
||||
sender: this.getMessageType(giftData),
|
||||
senderDetails: { _id: this.getSenderId(giftData), info: null},
|
||||
senderDetails: {_id: this.getSenderId(giftData), info: null},
|
||||
messageText: giftData.messageText,
|
||||
items: giftData.items,
|
||||
itemsMaxStorageLifetimeSeconds: this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours)
|
||||
itemsMaxStorageLifetimeSeconds: this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours),
|
||||
};
|
||||
|
||||
if (giftData.trader)
|
||||
@ -142,7 +145,7 @@ export class GiftService
|
||||
}
|
||||
|
||||
this.mailSendService.sendMessageToPlayer(details);
|
||||
}
|
||||
}
|
||||
|
||||
this.profileHelper.addGiftReceivedFlagToProfile(playerId, giftId);
|
||||
|
||||
@ -195,7 +198,7 @@ export class GiftService
|
||||
*/
|
||||
public sendPraporStartingGift(sessionId: string, day: number): void
|
||||
{
|
||||
switch (day)
|
||||
switch (day)
|
||||
{
|
||||
case 1:
|
||||
if (this.profileHelper.playerHasRecievedGift(sessionId, "PraporGiftDay1"))
|
||||
@ -210,6 +213,5 @@ export class GiftService
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,17 +16,17 @@ export class HashCacheService
|
||||
@inject("VFS") protected vfs: VFS,
|
||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||
@inject("WinstonLogger") protected logger: ILogger
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
)
|
||||
{
|
||||
{
|
||||
if (!this.vfs.exists(this.modCachePath))
|
||||
{
|
||||
this.vfs.writeFile(this.modCachePath, "{}");
|
||||
}
|
||||
|
||||
// get mod hash file
|
||||
if (!this.modHashes) // empty
|
||||
{
|
||||
if (!this.modHashes)
|
||||
{ // empty
|
||||
this.modHashes = this.jsonUtil.deserialize(this.vfs.readFile(`${this.modCachePath}`));
|
||||
}
|
||||
}
|
||||
@ -44,7 +44,7 @@ export class HashCacheService
|
||||
/**
|
||||
* Does the generated hash match the stored hash
|
||||
* @param modName name of mod
|
||||
* @param modContent
|
||||
* @param modContent
|
||||
* @returns True if they match
|
||||
*/
|
||||
public modContentMatchesStoredHash(modName: string, modContent: string): boolean
|
||||
@ -77,4 +77,4 @@ export class HashCacheService
|
||||
|
||||
this.logger.debug(`Mod ${modName} hash stored in ${this.modCachePath}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ export class InsuranceService
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("LocaleService") protected localeService: LocaleService,
|
||||
@inject("MailSendService") protected mailSendService: MailSendService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.insuranceConfig = this.configServer.getConfig(ConfigTypes.INSURANCE);
|
||||
@ -103,13 +103,17 @@ export class InsuranceService
|
||||
const dialogueTemplates = this.databaseServer.getTables().traders[traderId].dialogue;
|
||||
|
||||
// Construct "i will go look for your stuff" message
|
||||
const messageContent = this.dialogueHelper.createMessageContext(this.randomUtil.getArrayValue(dialogueTemplates.insuranceStart), MessageType.NPC_TRADER, traderBase.insurance.max_storage_time);
|
||||
const messageContent = this.dialogueHelper.createMessageContext(
|
||||
this.randomUtil.getArrayValue(dialogueTemplates.insuranceStart),
|
||||
MessageType.NPC_TRADER,
|
||||
traderBase.insurance.max_storage_time,
|
||||
);
|
||||
messageContent.text = ""; // Live insurance returns have an empty string for the text property
|
||||
messageContent.profileChangeEvents = [];
|
||||
messageContent.systemData = {
|
||||
date: this.timeUtil.getDateMailFormat(),
|
||||
time: this.timeUtil.getTimeMailFormat(),
|
||||
location: mapId
|
||||
location: mapId,
|
||||
};
|
||||
|
||||
// MUST occur after systemData is hydrated
|
||||
@ -128,7 +132,7 @@ export class InsuranceService
|
||||
scheduledTime: insuranceReturnTimestamp,
|
||||
traderId: traderId,
|
||||
messageContent: messageContent,
|
||||
items: this.getInsurance(sessionID)[traderId]
|
||||
items: this.getInsurance(sessionID)[traderId],
|
||||
});
|
||||
}
|
||||
|
||||
@ -143,9 +147,9 @@ export class InsuranceService
|
||||
public sendLostInsuranceMessage(sessionId: string, locationName = ""): void
|
||||
{
|
||||
const dialogueTemplates = this.databaseServer.getTables().traders[Traders.PRAPOR].dialogue; // todo: get trader id instead of hard coded prapor
|
||||
const randomResponseId = locationName?.toLowerCase() === "laboratory"
|
||||
? this.randomUtil.getArrayValue(dialogueTemplates["insuranceFailedLabs"])
|
||||
: this.randomUtil.getArrayValue(dialogueTemplates["insuranceFailed"]);
|
||||
const randomResponseId = locationName?.toLowerCase() === "laboratory" ?
|
||||
this.randomUtil.getArrayValue(dialogueTemplates["insuranceFailedLabs"]) :
|
||||
this.randomUtil.getArrayValue(dialogueTemplates["insuranceFailed"]);
|
||||
|
||||
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
||||
sessionId,
|
||||
@ -154,7 +158,8 @@ export class InsuranceService
|
||||
randomResponseId,
|
||||
[],
|
||||
null,
|
||||
{location: locationName});
|
||||
{location: locationName},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -168,7 +173,7 @@ export class InsuranceService
|
||||
for (const insuredItem of this.getInsurance(sessionId)[traderId])
|
||||
{
|
||||
// Find insured items parent
|
||||
const insuredItemsParent = insuredItems.find(x => x._id === insuredItem.parentId);
|
||||
const insuredItemsParent = insuredItems.find((x) => x._id === insuredItem.parentId);
|
||||
if (!insuredItemsParent)
|
||||
{
|
||||
// Remove location + set slotId of insured items parent
|
||||
@ -190,14 +195,16 @@ export class InsuranceService
|
||||
// If override inconfig is non-zero, use that instead of trader values
|
||||
if (this.insuranceConfig.returnTimeOverrideSeconds > 0)
|
||||
{
|
||||
this.logger.debug(`Insurance override used: returning in ${this.insuranceConfig.returnTimeOverrideSeconds} seconds`);
|
||||
this.logger.debug(
|
||||
`Insurance override used: returning in ${this.insuranceConfig.returnTimeOverrideSeconds} seconds`,
|
||||
);
|
||||
return this.timeUtil.getTimestamp() + this.insuranceConfig.returnTimeOverrideSeconds;
|
||||
}
|
||||
|
||||
const insuranceReturnTimeBonus = pmcData.Bonuses.find(b => b.type === "InsuranceReturnTime");
|
||||
const insuranceReturnTimeBonusPercent = 1.0 - (insuranceReturnTimeBonus
|
||||
? Math.abs(insuranceReturnTimeBonus.value)
|
||||
: 0) / 100;
|
||||
const insuranceReturnTimeBonus = pmcData.Bonuses.find((b) => b.type === "InsuranceReturnTime");
|
||||
const insuranceReturnTimeBonusPercent = 1.0 - (insuranceReturnTimeBonus ?
|
||||
Math.abs(insuranceReturnTimeBonus.value) :
|
||||
0) / 100;
|
||||
|
||||
const traderMinReturnAsSeconds = trader.insurance.min_return_hour * TimeUtil.oneHourAsSeconds;
|
||||
const traderMaxReturnAsSeconds = trader.insurance.max_return_hour * TimeUtil.oneHourAsSeconds;
|
||||
@ -215,7 +222,13 @@ export class InsuranceService
|
||||
* @param sessionID Session id
|
||||
* @param playerDied did the player die in raid
|
||||
*/
|
||||
public storeLostGear(pmcData: IPmcData, offraidData: ISaveProgressRequestData, preRaidGear: Item[], sessionID: string, playerDied: boolean): void
|
||||
public storeLostGear(
|
||||
pmcData: IPmcData,
|
||||
offraidData: ISaveProgressRequestData,
|
||||
preRaidGear: Item[],
|
||||
sessionID: string,
|
||||
playerDied: boolean,
|
||||
): void
|
||||
{
|
||||
const preRaidGearHash = this.createItemHashTable(preRaidGear);
|
||||
const offRaidGearHash = this.createItemHashTable(offraidData.profile.Inventory.items);
|
||||
@ -242,9 +255,13 @@ export class InsuranceService
|
||||
{
|
||||
equipmentToSendToPlayer.push({
|
||||
pmcData: pmcData,
|
||||
itemToReturnToPlayer: this.getInsuredItemDetails(pmcData, preRaidItem, offraidData.insurance?.find(x => x.id === insuredItem.itemId)),
|
||||
itemToReturnToPlayer: this.getInsuredItemDetails(
|
||||
pmcData,
|
||||
preRaidItem,
|
||||
offraidData.insurance?.find((x) => x.id === insuredItem.itemId),
|
||||
),
|
||||
traderId: insuredItem.tid,
|
||||
sessionID: sessionID
|
||||
sessionID: sessionID,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -264,7 +281,11 @@ export class InsuranceService
|
||||
* @param insuredItemFromClient Item data when player left raid (durability values)
|
||||
* @returns Item object
|
||||
*/
|
||||
protected getInsuredItemDetails(pmcData: IPmcData, preRaidItem: Item, insuredItemFromClient: IInsuredItemsData): Item
|
||||
protected getInsuredItemDetails(
|
||||
pmcData: IPmcData,
|
||||
preRaidItem: Item,
|
||||
insuredItemFromClient: IInsuredItemsData,
|
||||
): Item
|
||||
{
|
||||
// Get baseline item to return, clone pre raid item
|
||||
const itemToReturn: Item = this.jsonUtil.clone(preRaidItem);
|
||||
@ -298,7 +319,7 @@ export class InsuranceService
|
||||
{
|
||||
itemToReturn.upd.Repairable = {
|
||||
Durability: insuredItemFromClient.durability,
|
||||
MaxDurability: insuredItemFromClient.maxDurability
|
||||
MaxDurability: insuredItemFromClient.maxDurability,
|
||||
};
|
||||
}
|
||||
else
|
||||
@ -306,7 +327,6 @@ export class InsuranceService
|
||||
itemToReturn.upd.Repairable.Durability = insuredItemFromClient.durability;
|
||||
itemToReturn.upd.Repairable.MaxDurability = insuredItemFromClient.maxDurability;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Client item has FaceShield values, Ensure values persist into server data
|
||||
@ -316,14 +336,13 @@ export class InsuranceService
|
||||
if (!itemToReturn.upd.FaceShield)
|
||||
{
|
||||
itemToReturn.upd.FaceShield = {
|
||||
Hits: insuredItemFromClient.hits
|
||||
Hits: insuredItemFromClient.hits,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
itemToReturn.upd.FaceShield.Hits = insuredItemFromClient.hits;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return itemToReturn;
|
||||
@ -340,17 +359,17 @@ export class InsuranceService
|
||||
"pocket1",
|
||||
"pocket2",
|
||||
"pocket3",
|
||||
"pocket4"
|
||||
"pocket4",
|
||||
];
|
||||
|
||||
// Some pockets can lose items with player death, some don't
|
||||
if (!("slotId" in itemToReturn) || pocketSlots.includes(itemToReturn.slotId))
|
||||
if (!("slotId" in itemToReturn) || pocketSlots.includes(itemToReturn.slotId))
|
||||
{
|
||||
itemToReturn.slotId = "hideout";
|
||||
}
|
||||
|
||||
// Mark root-level items for later processing
|
||||
if (itemToReturn.parentId === playerBaseInventoryEquipmentId)
|
||||
if (itemToReturn.parentId === playerBaseInventoryEquipmentId)
|
||||
{
|
||||
itemToReturn.slotId = "hideout";
|
||||
}
|
||||
@ -379,7 +398,9 @@ export class InsuranceService
|
||||
* @param itemToReturnToPlayer item to store
|
||||
* @param traderId Id of trader item was insured with
|
||||
*/
|
||||
protected addGearToSend(gear: { sessionID: string; pmcData: IPmcData; itemToReturnToPlayer: Item; traderId: string}): void
|
||||
protected addGearToSend(
|
||||
gear: {sessionID: string; pmcData: IPmcData; itemToReturnToPlayer: Item; traderId: string;},
|
||||
): void
|
||||
{
|
||||
const sessionId = gear.sessionID;
|
||||
const pmcData = gear.pmcData;
|
||||
@ -436,7 +457,6 @@ export class InsuranceService
|
||||
*/
|
||||
public addInsuranceItemToArray(sessionId: string, traderId: string, itemToAdd: Item): void
|
||||
{
|
||||
|
||||
this.insured[sessionId][traderId].push(itemToAdd);
|
||||
}
|
||||
|
||||
@ -453,7 +473,9 @@ export class InsuranceService
|
||||
if (!insuranceMultiplier)
|
||||
{
|
||||
insuranceMultiplier = 0.3;
|
||||
this.logger.warning(this.localisationService.getText("insurance-missing_insurance_price_multiplier", traderId));
|
||||
this.logger.warning(
|
||||
this.localisationService.getText("insurance-missing_insurance_price_multiplier", traderId),
|
||||
);
|
||||
}
|
||||
|
||||
// Multiply item handbook price by multiplier in config to get the new insurance price
|
||||
@ -462,9 +484,9 @@ export class InsuranceService
|
||||
|
||||
if (coef > 0)
|
||||
{
|
||||
pricePremium *= (1 - this.traderHelper.getLoyaltyLevel(traderId, pmcData).insurance_price_coef / 100);
|
||||
pricePremium *= 1 - this.traderHelper.getLoyaltyLevel(traderId, pmcData).insurance_price_coef / 100;
|
||||
}
|
||||
|
||||
return Math.round(pricePremium);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ export class ItemBaseClassService
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
)
|
||||
{}
|
||||
|
||||
@ -39,7 +39,7 @@ export class ItemBaseClassService
|
||||
return;
|
||||
}
|
||||
|
||||
const filteredDbItems = Object.values(allDbItems).filter(x => x._type === "Item");
|
||||
const filteredDbItems = Object.values(allDbItems).filter((x) => x._type === "Item");
|
||||
for (const item of filteredDbItems)
|
||||
{
|
||||
const itemIdToUpdate = item._id;
|
||||
@ -111,7 +111,7 @@ export class ItemBaseClassService
|
||||
}
|
||||
}
|
||||
|
||||
return this.itemBaseClassesCache[itemTpl].some(x => baseClasses.includes(x));
|
||||
return this.itemBaseClassesCache[itemTpl].some((x) => baseClasses.includes(x));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,4 +133,4 @@ export class ItemBaseClassService
|
||||
|
||||
return this.itemBaseClassesCache[itemTpl];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,16 +6,16 @@ import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||
|
||||
/** Centralise the handling of blacklisting items, uses blacklist found in config/item.json, stores items that should not be used by players / broken items */
|
||||
/** Centralise the handling of blacklisting items, uses blacklist found in config/item.json, stores items that should not be used by players / broken items */
|
||||
@injectable()
|
||||
export class ItemFilterService
|
||||
{
|
||||
protected itemConfig: IItemConfig ;
|
||||
protected itemConfig: IItemConfig;
|
||||
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.itemConfig = this.configServer.getConfig(ConfigTypes.ITEM);
|
||||
@ -58,4 +58,4 @@ export class ItemFilterService
|
||||
{
|
||||
return this.itemConfig.bossItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ export class LocaleService
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.localeConfig = this.configServer.getConfig(ConfigTypes.LOCALE);
|
||||
@ -35,7 +35,9 @@ export class LocaleService
|
||||
return desiredLocale;
|
||||
}
|
||||
|
||||
this.logger.warning(`Unable to find desired locale file using locale ${this.getDesiredGameLocale()} from config/locale.json, falling back to 'en'`);
|
||||
this.logger.warning(
|
||||
`Unable to find desired locale file using locale ${this.getDesiredGameLocale()} from config/locale.json, falling back to 'en'`,
|
||||
);
|
||||
|
||||
return this.databaseServer.getTables().locales.global["en"];
|
||||
}
|
||||
@ -95,10 +97,12 @@ export class LocaleService
|
||||
|
||||
if (!this.localeConfig.serverSupportedLocales.includes(platformLocale.language))
|
||||
{
|
||||
this.logger.warning(`Unsupported system langauge found ${platformLocale.baseName}, falling back to english`);
|
||||
this.logger.warning(
|
||||
`Unsupported system langauge found ${platformLocale.baseName}, falling back to english`,
|
||||
);
|
||||
return "en";
|
||||
}
|
||||
|
||||
return platformLocale.language;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,17 +21,22 @@ export class LocalisationService
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("LocaleService") protected localeService: LocaleService
|
||||
@inject("LocaleService") protected localeService: LocaleService,
|
||||
)
|
||||
{
|
||||
const localeFileDirectory = path.join(process.cwd(), globalThis.G_RELEASE_CONFIGURATION ? "Aki_Data/Server/database/locales/server" : "./assets/database/locales/server");
|
||||
const localeFileDirectory = path.join(
|
||||
process.cwd(),
|
||||
globalThis.G_RELEASE_CONFIGURATION ?
|
||||
"Aki_Data/Server/database/locales/server" :
|
||||
"./assets/database/locales/server",
|
||||
);
|
||||
this.i18n = new I18n(
|
||||
{
|
||||
locales: this.localeService.getServerSupportedLocales(),
|
||||
defaultLocale: "en",
|
||||
directory: localeFileDirectory,
|
||||
retryInDefaultLocale: true
|
||||
}
|
||||
retryInDefaultLocale: true,
|
||||
},
|
||||
);
|
||||
|
||||
this.i18n.setLocale(this.localeService.getDesiredServerLocale());
|
||||
@ -64,9 +69,11 @@ export class LocalisationService
|
||||
*/
|
||||
public getRandomTextThatMatchesPartialKey(partialKey: string): string
|
||||
{
|
||||
const filteredKeys = Object.keys(this.databaseServer.getTables().locales.server["en"]).filter(x => x.startsWith(partialKey));
|
||||
const filteredKeys = Object.keys(this.databaseServer.getTables().locales.server["en"]).filter((x) =>
|
||||
x.startsWith(partialKey)
|
||||
);
|
||||
const chosenKey = this.randomUtil.getArrayValue(filteredKeys);
|
||||
|
||||
return this.getText(chosenKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +33,9 @@ export class MailSendService
|
||||
@inject("NotificationSendHelper") protected notificationSendHelper: NotificationSendHelper,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
@inject("TraderHelper") protected traderHelper: TraderHelper
|
||||
@inject("TraderHelper") protected traderHelper: TraderHelper,
|
||||
)
|
||||
{ }
|
||||
{}
|
||||
|
||||
/**
|
||||
* Send a message from an NPC (e.g. prapor) to the player with or without items using direct message text, do not look up any locale
|
||||
@ -46,11 +46,25 @@ export class MailSendService
|
||||
* @param items Optional items to send to player
|
||||
* @param maxStorageTimeSeconds Optional time to collect items before they expire
|
||||
*/
|
||||
public sendDirectNpcMessageToPlayer(sessionId: string, trader: Traders, messageType: MessageType, message: string, items: Item[] = [], maxStorageTimeSeconds = null, systemData = null, ragfair = null): void
|
||||
public sendDirectNpcMessageToPlayer(
|
||||
sessionId: string,
|
||||
trader: Traders,
|
||||
messageType: MessageType,
|
||||
message: string,
|
||||
items: Item[] = [],
|
||||
maxStorageTimeSeconds = null,
|
||||
systemData = null,
|
||||
ragfair = null,
|
||||
): void
|
||||
{
|
||||
if (!trader)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("mailsend-missing_trader", {messageType: messageType, sessionId: sessionId}));
|
||||
this.logger.error(
|
||||
this.localisationService.getText("mailsend-missing_trader", {
|
||||
messageType: messageType,
|
||||
sessionId: sessionId,
|
||||
}),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -60,7 +74,7 @@ export class MailSendService
|
||||
sender: messageType,
|
||||
dialogType: MessageType.NPC_TRADER,
|
||||
trader: trader,
|
||||
messageText: message
|
||||
messageText: message,
|
||||
};
|
||||
|
||||
// Add items to message
|
||||
@ -92,11 +106,25 @@ export class MailSendService
|
||||
* @param items Optional items to send to player
|
||||
* @param maxStorageTimeSeconds Optional time to collect items before they expire
|
||||
*/
|
||||
public sendLocalisedNpcMessageToPlayer(sessionId: string, trader: Traders, messageType: MessageType, messageLocaleId: string, items: Item[] = [], maxStorageTimeSeconds = null, systemData = null, ragfair = null): void
|
||||
public sendLocalisedNpcMessageToPlayer(
|
||||
sessionId: string,
|
||||
trader: Traders,
|
||||
messageType: MessageType,
|
||||
messageLocaleId: string,
|
||||
items: Item[] = [],
|
||||
maxStorageTimeSeconds = null,
|
||||
systemData = null,
|
||||
ragfair = null,
|
||||
): void
|
||||
{
|
||||
if (!trader)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("mailsend-missing_trader", {messageType: messageType, sessionId: sessionId}));
|
||||
this.logger.error(
|
||||
this.localisationService.getText("mailsend-missing_trader", {
|
||||
messageType: messageType,
|
||||
sessionId: sessionId,
|
||||
}),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -106,7 +134,7 @@ export class MailSendService
|
||||
sender: messageType,
|
||||
dialogType: MessageType.NPC_TRADER,
|
||||
trader: trader,
|
||||
templateId: messageLocaleId
|
||||
templateId: messageLocaleId,
|
||||
};
|
||||
|
||||
// Add items to message
|
||||
@ -136,12 +164,17 @@ export class MailSendService
|
||||
* @param items Optional items to send to player
|
||||
* @param maxStorageTimeSeconds Optional time to collect items before they expire
|
||||
*/
|
||||
public sendSystemMessageToPlayer(sessionId: string, message: string, items: Item[] = [], maxStorageTimeSeconds = null): void
|
||||
public sendSystemMessageToPlayer(
|
||||
sessionId: string,
|
||||
message: string,
|
||||
items: Item[] = [],
|
||||
maxStorageTimeSeconds = null,
|
||||
): void
|
||||
{
|
||||
const details: ISendMessageDetails = {
|
||||
recipientId: sessionId,
|
||||
sender: MessageType.SYSTEM_MESSAGE,
|
||||
messageText: message
|
||||
messageText: message,
|
||||
};
|
||||
|
||||
// Add items to message
|
||||
@ -161,12 +194,17 @@ export class MailSendService
|
||||
* @param items Optional items to send to player
|
||||
* @param maxStorageTimeSeconds Optional time to collect items before they expire
|
||||
*/
|
||||
public sendLocalisedSystemMessageToPlayer(sessionId: string, messageLocaleId: string, items: Item[] = [], maxStorageTimeSeconds = null): void
|
||||
public sendLocalisedSystemMessageToPlayer(
|
||||
sessionId: string,
|
||||
messageLocaleId: string,
|
||||
items: Item[] = [],
|
||||
maxStorageTimeSeconds = null,
|
||||
): void
|
||||
{
|
||||
const details: ISendMessageDetails = {
|
||||
recipientId: sessionId,
|
||||
sender: MessageType.SYSTEM_MESSAGE,
|
||||
templateId: messageLocaleId
|
||||
templateId: messageLocaleId,
|
||||
};
|
||||
|
||||
// Add items to message
|
||||
@ -187,13 +225,19 @@ export class MailSendService
|
||||
* @param items Optional items to send to player
|
||||
* @param maxStorageTimeSeconds Optional time to collect items before they expire
|
||||
*/
|
||||
public sendUserMessageToPlayer(sessionId: string, senderDetails: IUserDialogInfo, message: string, items: Item[] = [], maxStorageTimeSeconds = null): void
|
||||
public sendUserMessageToPlayer(
|
||||
sessionId: string,
|
||||
senderDetails: IUserDialogInfo,
|
||||
message: string,
|
||||
items: Item[] = [],
|
||||
maxStorageTimeSeconds = null,
|
||||
): void
|
||||
{
|
||||
const details: ISendMessageDetails = {
|
||||
recipientId: sessionId,
|
||||
sender: MessageType.USER_MESSAGE,
|
||||
senderDetails: senderDetails,
|
||||
messageText: message
|
||||
messageText: message,
|
||||
};
|
||||
|
||||
// Add items to message
|
||||
@ -222,7 +266,7 @@ export class MailSendService
|
||||
// Craft message
|
||||
const message = this.createDialogMessage(senderDialog._id, messageDetails);
|
||||
|
||||
// Create items array
|
||||
// Create items array
|
||||
// Generate item stash if we have rewards.
|
||||
const itemsToSendToPlayer = this.processItemsBeforeAddingToMail(senderDialog.type, messageDetails);
|
||||
|
||||
@ -240,9 +284,15 @@ export class MailSendService
|
||||
|
||||
// TODO: clean up old code here
|
||||
// Offer Sold notifications are now separate from the main notification
|
||||
if ([MessageType.NPC_TRADER, MessageType.FLEAMARKET_MESSAGE].includes(senderDialog.type) && messageDetails.ragfairDetails)
|
||||
if (
|
||||
[MessageType.NPC_TRADER, MessageType.FLEAMARKET_MESSAGE].includes(senderDialog.type) &&
|
||||
messageDetails.ragfairDetails
|
||||
)
|
||||
{
|
||||
const offerSoldMessage = this.notifierHelper.createRagfairOfferSoldNotification(message, messageDetails.ragfairDetails);
|
||||
const offerSoldMessage = this.notifierHelper.createRagfairOfferSoldNotification(
|
||||
message,
|
||||
messageDetails.ragfairDetails,
|
||||
);
|
||||
this.notificationSendHelper.sendMessage(messageDetails.recipientId, offerSoldMessage);
|
||||
message.type = MessageType.MESSAGE_WITH_ITEMS; // Should prevent getting the same notification popup twice
|
||||
}
|
||||
@ -276,7 +326,7 @@ export class MailSendService
|
||||
uid: playerProfile.characters.pmc._id,
|
||||
type: MessageType.USER_MESSAGE,
|
||||
rewardCollected: false,
|
||||
text: message
|
||||
text: message,
|
||||
});
|
||||
}
|
||||
|
||||
@ -298,7 +348,9 @@ export class MailSendService
|
||||
hasRewards: false, // The default dialog message has no rewards, can be added later via addRewardItemsToMessage()
|
||||
rewardCollected: false, // The default dialog message has no rewards, can be added later via addRewardItemsToMessage()
|
||||
systemData: messageDetails.systemData ? messageDetails.systemData : undefined, // Used by ragfair / localised messages that need "location" or "time"
|
||||
profileChangeEvents: (messageDetails.profileChangeEvents?.length === 0) ? messageDetails.profileChangeEvents : undefined // no one knows, its never been used in any dumps
|
||||
profileChangeEvents: (messageDetails.profileChangeEvents?.length === 0) ?
|
||||
messageDetails.profileChangeEvents :
|
||||
undefined, // no one knows, its never been used in any dumps
|
||||
};
|
||||
|
||||
// Clean up empty system data
|
||||
@ -322,7 +374,11 @@ export class MailSendService
|
||||
* @param itemsToSendToPlayer Items to add to message
|
||||
* @param maxStorageTimeSeconds total time items are stored in mail before being deleted
|
||||
*/
|
||||
protected addRewardItemsToMessage(message: Message, itemsToSendToPlayer: MessageItems, maxStorageTimeSeconds: number): void
|
||||
protected addRewardItemsToMessage(
|
||||
message: Message,
|
||||
itemsToSendToPlayer: MessageItems,
|
||||
maxStorageTimeSeconds: number,
|
||||
): void
|
||||
{
|
||||
if (itemsToSendToPlayer?.data?.length > 0)
|
||||
{
|
||||
@ -335,8 +391,8 @@ export class MailSendService
|
||||
|
||||
/**
|
||||
* perform various sanitising actions on the items before they're considered ready for insertion into message
|
||||
* @param dialogType The type of the dialog that will hold the reward items being processed
|
||||
* @param messageDetails
|
||||
* @param dialogType The type of the dialog that will hold the reward items being processed
|
||||
* @param messageDetails
|
||||
* @returns Sanitised items
|
||||
*/
|
||||
protected processItemsBeforeAddingToMail(dialogType: MessageType, messageDetails: ISendMessageDetails): MessageItems
|
||||
@ -350,7 +406,10 @@ export class MailSendService
|
||||
const parentItem = this.getBaseItemFromRewards(messageDetails.items);
|
||||
if (!parentItem)
|
||||
{
|
||||
this.localisationService.getText("mailsend-missing_parent", {traderId: messageDetails.trader, sender: messageDetails.sender});
|
||||
this.localisationService.getText("mailsend-missing_parent", {
|
||||
traderId: messageDetails.trader,
|
||||
sender: messageDetails.sender,
|
||||
});
|
||||
|
||||
return itemsToSendToPlayer;
|
||||
}
|
||||
@ -363,9 +422,9 @@ export class MailSendService
|
||||
|
||||
itemsToSendToPlayer = {
|
||||
stash: parentItem.parentId,
|
||||
data: []
|
||||
data: [],
|
||||
};
|
||||
|
||||
|
||||
// Ensure Ids are unique and cont collide with items in player inventory later
|
||||
messageDetails.items = this.itemHelper.replaceIDs(null, messageDetails.items);
|
||||
|
||||
@ -376,7 +435,12 @@ export class MailSendService
|
||||
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: dialogType}));
|
||||
this.logger.error(
|
||||
this.localisationService.getText("dialog-missing_item_template", {
|
||||
tpl: reward._tpl,
|
||||
type: dialogType,
|
||||
}),
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
@ -427,7 +491,7 @@ export class MailSendService
|
||||
}
|
||||
|
||||
// Find first item with slotId that indicates its a 'base' item
|
||||
let item = items.find(x => ["hideout", "main"].includes(x.slotId));
|
||||
let item = items.find((x) => ["hideout", "main"].includes(x.slotId));
|
||||
if (item)
|
||||
{
|
||||
return item;
|
||||
@ -435,7 +499,7 @@ export class MailSendService
|
||||
|
||||
// Not a singlular item + no items have a hideout/main slotid
|
||||
// Look for first item without parent id
|
||||
item = items.find(x => !x.parentId);
|
||||
item = items.find((x) => !x.parentId);
|
||||
if (item)
|
||||
{
|
||||
return item;
|
||||
@ -467,7 +531,7 @@ export class MailSendService
|
||||
messages: [],
|
||||
pinned: false,
|
||||
new: 0,
|
||||
attachmentsNew: 0
|
||||
attachmentsNew: 0,
|
||||
};
|
||||
|
||||
senderDialog = dialogsInProfile[senderId];
|
||||
@ -478,7 +542,7 @@ export class MailSendService
|
||||
|
||||
/**
|
||||
* Get the appropriate sender id by the sender enum type
|
||||
* @param messageDetails
|
||||
* @param messageDetails
|
||||
* @returns gets an id of the individual sending it
|
||||
*/
|
||||
protected getMessageSenderIdByType(messageDetails: ISendMessageDetails): string
|
||||
@ -510,5 +574,4 @@ export class MailSendService
|
||||
|
||||
this.logger.warning(`Unable to handle message of type: ${messageDetails.sender}`);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ export class MatchBotDetailsCacheService
|
||||
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
)
|
||||
{}
|
||||
|
||||
@ -48,5 +48,4 @@ export class MatchBotDetailsCacheService
|
||||
|
||||
return botInCache;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,9 @@ export class MatchLocationService
|
||||
protected locations = {};
|
||||
|
||||
constructor(
|
||||
@inject("TimeUtil") protected timeUtil: TimeUtil
|
||||
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
||||
)
|
||||
{ }
|
||||
{}
|
||||
|
||||
public createGroup(sessionID: string, info: ICreateGroupRequestData): any
|
||||
{
|
||||
@ -33,10 +33,10 @@ export class MatchLocationService
|
||||
region: "EUR",
|
||||
ip: "127.0.0.1",
|
||||
savageId: `scav${sessionID}`,
|
||||
accessKeyId: ""
|
||||
}
|
||||
accessKeyId: "",
|
||||
},
|
||||
],
|
||||
customDataCenter: []
|
||||
customDataCenter: [],
|
||||
};
|
||||
|
||||
return this.locations[info.location].groups[groupID];
|
||||
@ -56,4 +56,4 @@ export class MatchLocationService
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ export class ModCompilerService
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("HashCacheService") protected hashCacheService: HashCacheService,
|
||||
@inject("VFS") protected vfs: VFS
|
||||
@inject("VFS") protected vfs: VFS,
|
||||
)
|
||||
{
|
||||
const packageJsonPath: string = path.join(__dirname, "../../package.json");
|
||||
@ -27,8 +27,8 @@ export class ModCompilerService
|
||||
* Convert a mods TS into JS
|
||||
* @param modName Name of mod
|
||||
* @param modPath Dir path to mod
|
||||
* @param modTypeScriptFiles
|
||||
* @returns
|
||||
* @param modTypeScriptFiles
|
||||
* @returns
|
||||
*/
|
||||
public async compileMod(modName: string, modPath: string, modTypeScriptFiles: string[]): Promise<void>
|
||||
{
|
||||
@ -38,7 +38,7 @@ export class ModCompilerService
|
||||
for (const file of modTypeScriptFiles)
|
||||
{
|
||||
const fileContent = this.vfs.readFile(file);
|
||||
tsFileContents+= fileContent;
|
||||
tsFileContents += fileContent;
|
||||
|
||||
// Does equivalent .js file exist
|
||||
if (!this.vfs.exists(file.replace(".ts", ".js")))
|
||||
@ -61,22 +61,21 @@ export class ModCompilerService
|
||||
this.hashCacheService.storeModContent(modName, tsFileContents);
|
||||
}
|
||||
|
||||
return this.compile(modTypeScriptFiles,
|
||||
{
|
||||
noEmitOnError: true,
|
||||
noImplicitAny: false,
|
||||
target: ts.ScriptTarget.ES2022,
|
||||
module: ts.ModuleKind.CommonJS,
|
||||
moduleResolution: ts.ModuleResolutionKind.Node10,
|
||||
sourceMap: true,
|
||||
resolveJsonModule: true,
|
||||
allowJs: true,
|
||||
esModuleInterop: true,
|
||||
downlevelIteration: true,
|
||||
experimentalDecorators: true,
|
||||
emitDecoratorMetadata: true,
|
||||
rootDir: modPath
|
||||
});
|
||||
return this.compile(modTypeScriptFiles, {
|
||||
noEmitOnError: true,
|
||||
noImplicitAny: false,
|
||||
target: ts.ScriptTarget.ES2022,
|
||||
module: ts.ModuleKind.CommonJS,
|
||||
moduleResolution: ts.ModuleResolutionKind.Node10,
|
||||
sourceMap: true,
|
||||
resolveJsonModule: true,
|
||||
allowJs: true,
|
||||
esModuleInterop: true,
|
||||
downlevelIteration: true,
|
||||
experimentalDecorators: true,
|
||||
emitDecoratorMetadata: true,
|
||||
rootDir: modPath,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,7 +86,7 @@ export class ModCompilerService
|
||||
protected async compile(fileNames: string[], options: ts.CompilerOptions): Promise<void>
|
||||
{
|
||||
// C:/snapshot/project || /snapshot/project
|
||||
const baseDir: string = __dirname.replace(/\\/g,"/").split("/").slice(0, 3).join("/");
|
||||
const baseDir: string = __dirname.replace(/\\/g, "/").split("/").slice(0, 3).join("/");
|
||||
|
||||
for (const filePath of fileNames)
|
||||
{
|
||||
@ -100,25 +99,28 @@ export class ModCompilerService
|
||||
if (globalThis.G_RELEASE_CONFIGURATION)
|
||||
{
|
||||
replacedText = text.replace(/(@spt-aki)/g, `${baseDir}/obj`);
|
||||
for (const dependency of this.serverDependencies)
|
||||
for (const dependency of this.serverDependencies)
|
||||
{
|
||||
replacedText = replacedText.replace(`"${dependency}"`, `"${baseDir}/node_modules/${dependency}"`);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
replacedText = text.replace(/(@spt-aki)/g, path.join(__dirname, "..").replace(/\\/g,"/"));
|
||||
replacedText = text.replace(/(@spt-aki)/g, path.join(__dirname, "..").replace(/\\/g, "/"));
|
||||
}
|
||||
|
||||
const output = ts.transpileModule(replacedText, { compilerOptions: options });
|
||||
const output = ts.transpileModule(replacedText, {compilerOptions: options});
|
||||
|
||||
if (output.sourceMapText)
|
||||
{
|
||||
output.outputText = output.outputText.replace("//# sourceMappingURL=module.js.map", `//# sourceMappingURL=${parsedDestPath.base}.map`);
|
||||
output.outputText = output.outputText.replace(
|
||||
"//# sourceMappingURL=module.js.map",
|
||||
`//# sourceMappingURL=${parsedDestPath.base}.map`,
|
||||
);
|
||||
|
||||
const sourceMap = JSON.parse(output.sourceMapText);
|
||||
sourceMap.file = parsedDestPath.base;
|
||||
sourceMap.sources = [ parsedPath.base ];
|
||||
sourceMap.sources = [parsedPath.base];
|
||||
|
||||
fs.writeFileSync(`${destPath}.map`, JSON.stringify(sourceMap));
|
||||
}
|
||||
@ -133,21 +135,21 @@ export class ModCompilerService
|
||||
|
||||
/**
|
||||
* Do the files at the provided paths exist
|
||||
* @param fileNames
|
||||
* @returns
|
||||
* @param fileNames
|
||||
* @returns
|
||||
*/
|
||||
protected areFilesReady(fileNames: string[]): boolean
|
||||
{
|
||||
return fileNames.filter(x => !this.vfs.exists(x.replace(".ts", ".js"))).length === 0;
|
||||
return fileNames.filter((x) => !this.vfs.exists(x.replace(".ts", ".js"))).length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait the provided number of milliseconds
|
||||
* @param ms Milliseconds
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
protected delay(ms: number): Promise<unknown>
|
||||
{
|
||||
return new Promise( resolve => setTimeout(resolve, ms) );
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,4 +61,4 @@ export class NotificationService
|
||||
|
||||
return this.messageQueue[sessionID];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ export class OpenZoneService
|
||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.locationConfig = this.configServer.getConfig(ConfigTypes.LOCATION);
|
||||
@ -54,7 +54,7 @@ export class OpenZoneService
|
||||
{
|
||||
const dbLocations = this.databaseServer.getTables().locations;
|
||||
for (const mapKey in this.locationConfig.openZones)
|
||||
{
|
||||
{
|
||||
if (!dbLocations[mapKey])
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("openzone-unable_to_find_map", mapKey));
|
||||
@ -76,4 +76,4 @@ export class OpenZoneService
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,9 +28,9 @@ export class PaymentService
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("PaymentHelper") protected paymentHelper: PaymentHelper
|
||||
@inject("PaymentHelper") protected paymentHelper: PaymentHelper,
|
||||
)
|
||||
{ }
|
||||
{}
|
||||
|
||||
/**
|
||||
* Take money and insert items into return to server request
|
||||
@ -39,12 +39,17 @@ export class PaymentService
|
||||
* @param {string} sessionID
|
||||
* @returns IItemEventRouterResponse
|
||||
*/
|
||||
public payMoney(pmcData: IPmcData, request: IProcessBuyTradeRequestData, sessionID: string, output: IItemEventRouterResponse): IItemEventRouterResponse
|
||||
public payMoney(
|
||||
pmcData: IPmcData,
|
||||
request: IProcessBuyTradeRequestData,
|
||||
sessionID: string,
|
||||
output: IItemEventRouterResponse,
|
||||
): IItemEventRouterResponse
|
||||
{
|
||||
const trader = this.traderHelper.getTrader(request.tid, sessionID);
|
||||
|
||||
// Track the amounts of each type of currency involved in the trade.
|
||||
const currencyAmounts: { [key: string]: number } = {};
|
||||
const currencyAmounts: {[key: string]: number;} = {};
|
||||
|
||||
// Delete barter items and track currencies if the action is "TradingConfirm".
|
||||
if (request.Action === "TradingConfirm")
|
||||
@ -52,7 +57,7 @@ export class PaymentService
|
||||
for (const index in request.scheme_items)
|
||||
{
|
||||
// Find the corresponding item in the player's inventory.
|
||||
const item = pmcData.Inventory.items.find(i => i._id === request.scheme_items[index].id);
|
||||
const item = pmcData.Inventory.items.find((i) => i._id === request.scheme_items[index].id);
|
||||
if (item !== undefined)
|
||||
{
|
||||
if (!this.paymentHelper.isMoneyTpl(item._tpl))
|
||||
@ -64,7 +69,8 @@ export class PaymentService
|
||||
else
|
||||
{
|
||||
// If the item is money, add its count to the currencyAmounts object.
|
||||
currencyAmounts[item._tpl] = (currencyAmounts[item._tpl] || 0) + request.scheme_items[index].count;
|
||||
currencyAmounts[item._tpl] = (currencyAmounts[item._tpl] || 0) +
|
||||
request.scheme_items[index].count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -90,7 +96,10 @@ export class PaymentService
|
||||
}
|
||||
|
||||
// Convert the amount to the trader's currency and update the sales sum.
|
||||
const costOfPurchaseInCurrency = this.handbookHelper.fromRUB(this.handbookHelper.inRUB(currencyAmount, currencyTpl), this.paymentHelper.getCurrency(trader.currency));
|
||||
const costOfPurchaseInCurrency = this.handbookHelper.fromRUB(
|
||||
this.handbookHelper.inRUB(currencyAmount, currencyTpl),
|
||||
this.paymentHelper.getCurrency(trader.currency),
|
||||
);
|
||||
pmcData.TradersInfo[request.tid].salesSum += costOfPurchaseInCurrency;
|
||||
}
|
||||
}
|
||||
@ -101,7 +110,10 @@ export class PaymentService
|
||||
this.logger.debug(this.localisationService.getText("payment-zero_price_no_payment"));
|
||||
|
||||
// Convert the handbook price to the trader's currency and update the sales sum.
|
||||
const costOfPurchaseInCurrency = this.handbookHelper.fromRUB(this.getTraderItemHandbookPriceRouble(request.item_id, request.tid), this.paymentHelper.getCurrency(trader.currency));
|
||||
const costOfPurchaseInCurrency = this.handbookHelper.fromRUB(
|
||||
this.getTraderItemHandbookPriceRouble(request.item_id, request.tid),
|
||||
this.paymentHelper.getCurrency(trader.currency),
|
||||
);
|
||||
pmcData.TradersInfo[request.tid].salesSum += costOfPurchaseInCurrency;
|
||||
}
|
||||
|
||||
@ -128,8 +140,10 @@ export class PaymentService
|
||||
const assortItemPriceRouble = this.handbookHelper.getTemplatePrice(purchasedAssortItem._tpl);
|
||||
if (!assortItemPriceRouble)
|
||||
{
|
||||
this.logger.debug(`No item price found for ${purchasedAssortItem._tpl} on trader: ${traderId} in assort: ${traderAssortId}`);
|
||||
|
||||
this.logger.debug(
|
||||
`No item price found for ${purchasedAssortItem._tpl} on trader: ${traderId} in assort: ${traderAssortId}`,
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -145,7 +159,13 @@ export class PaymentService
|
||||
* @param {string} sessionID
|
||||
* @returns IItemEventRouterResponse
|
||||
*/
|
||||
public getMoney(pmcData: IPmcData, amount: number, body: IProcessSellTradeRequestData, output: IItemEventRouterResponse, sessionID: string): IItemEventRouterResponse
|
||||
public getMoney(
|
||||
pmcData: IPmcData,
|
||||
amount: number,
|
||||
body: IProcessSellTradeRequestData,
|
||||
output: IItemEventRouterResponse,
|
||||
sessionID: string,
|
||||
): IItemEventRouterResponse
|
||||
{
|
||||
const trader = this.traderHelper.getTrader(body.tid, sessionID);
|
||||
const currency = this.paymentHelper.getCurrency(trader.currency);
|
||||
@ -169,7 +189,6 @@ export class PaymentService
|
||||
|
||||
if (item.upd.StackObjectsCount < maxStackSize)
|
||||
{
|
||||
|
||||
if (item.upd.StackObjectsCount + calcAmount > maxStackSize)
|
||||
{
|
||||
// calculate difference
|
||||
@ -197,9 +216,9 @@ export class PaymentService
|
||||
items: [{
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
item_id: currency,
|
||||
count: calcAmount
|
||||
count: calcAmount,
|
||||
}],
|
||||
tid: body.tid
|
||||
tid: body.tid,
|
||||
};
|
||||
|
||||
output = this.inventoryHelper.addItem(pmcData, request, output, sessionID, null, false, null, true);
|
||||
@ -215,22 +234,22 @@ export class PaymentService
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively checks if the given item is
|
||||
* inside the stash, that is it has the stash as
|
||||
* ancestor with slotId=hideout
|
||||
*/
|
||||
* Recursively checks if the given item is
|
||||
* inside the stash, that is it has the stash as
|
||||
* ancestor with slotId=hideout
|
||||
*/
|
||||
protected isItemInStash(pmcData: IPmcData, item: Item): boolean
|
||||
{
|
||||
let container = item;
|
||||
|
||||
|
||||
while ("parentId" in container)
|
||||
{
|
||||
if (container.parentId === pmcData.Inventory.stash && container.slotId === "hideout")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
container = pmcData.Inventory.items.find(i => i._id === container.parentId);
|
||||
|
||||
container = pmcData.Inventory.items.find((i) => i._id === container.parentId);
|
||||
if (!container)
|
||||
{
|
||||
break;
|
||||
@ -248,16 +267,38 @@ export class PaymentService
|
||||
* @param output output object to send to client
|
||||
* @returns IItemEventRouterResponse
|
||||
*/
|
||||
public addPaymentToOutput(pmcData: IPmcData, currencyTpl: string, amountToPay: number, sessionID: string, output: IItemEventRouterResponse): IItemEventRouterResponse
|
||||
public addPaymentToOutput(
|
||||
pmcData: IPmcData,
|
||||
currencyTpl: string,
|
||||
amountToPay: number,
|
||||
sessionID: string,
|
||||
output: IItemEventRouterResponse,
|
||||
): IItemEventRouterResponse
|
||||
{
|
||||
const moneyItemsInInventory = this.getSortedMoneyItemsInInventory(pmcData, currencyTpl, pmcData.Inventory.stash);
|
||||
const amountAvailable = moneyItemsInInventory.reduce((accumulator, item) => accumulator + item.upd.StackObjectsCount, 0);
|
||||
const moneyItemsInInventory = this.getSortedMoneyItemsInInventory(
|
||||
pmcData,
|
||||
currencyTpl,
|
||||
pmcData.Inventory.stash,
|
||||
);
|
||||
const amountAvailable = moneyItemsInInventory.reduce(
|
||||
(accumulator, item) => accumulator + item.upd.StackObjectsCount,
|
||||
0,
|
||||
);
|
||||
|
||||
// If no money in inventory or amount is not enough we return false
|
||||
if (moneyItemsInInventory.length <= 0 || amountAvailable < amountToPay)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("payment-not_enough_money_to_complete_transation", {amountToPay: amountToPay, amountAvailable: amountAvailable}));
|
||||
output = this.httpResponse.appendErrorToOutput(output, this.localisationService.getText("payment-not_enough_money_to_complete_transation_short"), BackendErrorCodes.UNKNOWN_TRADING_ERROR);
|
||||
this.logger.error(
|
||||
this.localisationService.getText("payment-not_enough_money_to_complete_transation", {
|
||||
amountToPay: amountToPay,
|
||||
amountAvailable: amountAvailable,
|
||||
}),
|
||||
);
|
||||
output = this.httpResponse.appendErrorToOutput(
|
||||
output,
|
||||
this.localisationService.getText("payment-not_enough_money_to_complete_transation_short"),
|
||||
BackendErrorCodes.UNKNOWN_TRADING_ERROR,
|
||||
);
|
||||
|
||||
return output;
|
||||
}
|
||||
@ -289,8 +330,8 @@ export class PaymentService
|
||||
|
||||
/**
|
||||
* Get all money stacks in inventory and prioritse items in stash
|
||||
* @param pmcData
|
||||
* @param currencyTpl
|
||||
* @param pmcData
|
||||
* @param currencyTpl
|
||||
* @param playerStashId Players stash id
|
||||
* @returns Sorting money items
|
||||
*/
|
||||
@ -360,7 +401,7 @@ export class PaymentService
|
||||
*/
|
||||
protected isInStash(itemId: string, inventoryItems: Item[], playerStashId: string): boolean
|
||||
{
|
||||
const itemParent = inventoryItems.find(x => x._id === itemId);
|
||||
const itemParent = inventoryItems.find((x) => x._id === itemId);
|
||||
|
||||
if (itemParent)
|
||||
{
|
||||
|
@ -9,14 +9,13 @@ import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
||||
@injectable()
|
||||
export class PlayerService
|
||||
{
|
||||
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
)
|
||||
{ }
|
||||
{}
|
||||
|
||||
/**
|
||||
* Get level of player
|
||||
@ -27,7 +26,7 @@ export class PlayerService
|
||||
{
|
||||
let accExp = 0;
|
||||
|
||||
for (const [level, { exp }] of this.databaseServer.getTables().globals.config.exp.level.exp_table.entries())
|
||||
for (const [level, {exp}] of this.databaseServer.getTables().globals.config.exp.level.exp_table.entries())
|
||||
{
|
||||
accExp += exp;
|
||||
|
||||
|
@ -27,7 +27,7 @@ export class PmcChatResponseService
|
||||
@inject("MatchBotDetailsCacheService") protected matchBotDetailsCacheService: MatchBotDetailsCacheService,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.pmcResponsesConfig = this.configServer.getConfig(ConfigTypes.PMC_CHAT_RESPONSE);
|
||||
@ -50,18 +50,21 @@ export class PmcChatResponseService
|
||||
|
||||
const victimDetails = this.getVictimDetails(victim);
|
||||
const message = this.chooseMessage(true, pmcData);
|
||||
this.notificationSendHelper.sendMessageToPlayer(sessionId, victimDetails, message, MessageType.USER_MESSAGE);
|
||||
}
|
||||
this.notificationSendHelper.sendMessageToPlayer(
|
||||
sessionId,
|
||||
victimDetails,
|
||||
message,
|
||||
MessageType.USER_MESSAGE,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Not fully implemented yet, needs method of acquiring killers details after raid
|
||||
* @param sessionId Session id
|
||||
* @param pmcData Players profile
|
||||
* @param killer The bot who killed the player
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public sendKillerResponse(sessionId: string, pmcData: IPmcData, killer: Aggressor): void
|
||||
{
|
||||
if (!killer)
|
||||
@ -75,7 +78,10 @@ export class PmcChatResponseService
|
||||
}
|
||||
|
||||
// find bot by name in cache
|
||||
const killerDetailsInCache = this.matchBotDetailsCacheService.getBotByNameAndSide(killer.Name.trim(), killer.Side);
|
||||
const killerDetailsInCache = this.matchBotDetailsCacheService.getBotByNameAndSide(
|
||||
killer.Name.trim(),
|
||||
killer.Side,
|
||||
);
|
||||
if (!killerDetailsInCache)
|
||||
{
|
||||
return;
|
||||
@ -93,8 +99,8 @@ export class PmcChatResponseService
|
||||
Nickname: killerDetailsInCache.Info.Nickname,
|
||||
Side: killerDetailsInCache.Info.Side,
|
||||
Level: killerDetailsInCache.Info.Level,
|
||||
MemberCategory: killerDetailsInCache.Info.MemberCategory
|
||||
}
|
||||
MemberCategory: killerDetailsInCache.Info.MemberCategory,
|
||||
},
|
||||
};
|
||||
|
||||
const message = this.chooseMessage(false, pmcData);
|
||||
@ -127,14 +133,20 @@ export class PmcChatResponseService
|
||||
}
|
||||
|
||||
// Choose random response from above list and request it from localisation service
|
||||
let responseText = this.localisationService.getText(this.randomUtil.getArrayValue(possibleResponseLocaleKeys), {playerName: pmcData.Info.Nickname, playerLevel: pmcData.Info.Level, playerSide: pmcData.Info.Side});
|
||||
let responseText = this.localisationService.getText(this.randomUtil.getArrayValue(possibleResponseLocaleKeys), {
|
||||
playerName: pmcData.Info.Nickname,
|
||||
playerLevel: pmcData.Info.Level,
|
||||
playerSide: pmcData.Info.Side,
|
||||
});
|
||||
|
||||
if (this.appendSuffixToMessageEnd(isVictim))
|
||||
{
|
||||
const suffixText = this.localisationService.getText(this.randomUtil.getArrayValue(this.getResponseSuffixLocaleKeys()));
|
||||
const suffixText = this.localisationService.getText(
|
||||
this.randomUtil.getArrayValue(this.getResponseSuffixLocaleKeys()),
|
||||
);
|
||||
responseText += ` ${suffixText}`;
|
||||
}
|
||||
|
||||
|
||||
if (this.stripCapitalistion(isVictim))
|
||||
{
|
||||
responseText = responseText.toLowerCase();
|
||||
@ -155,9 +167,9 @@ export class PmcChatResponseService
|
||||
*/
|
||||
protected stripCapitalistion(isVictim: boolean): boolean
|
||||
{
|
||||
const chance = isVictim
|
||||
? this.pmcResponsesConfig.victim.stripCapitalisationChancePercent
|
||||
: this.pmcResponsesConfig.killer.stripCapitalisationChancePercent;
|
||||
const chance = isVictim ?
|
||||
this.pmcResponsesConfig.victim.stripCapitalisationChancePercent :
|
||||
this.pmcResponsesConfig.killer.stripCapitalisationChancePercent;
|
||||
|
||||
return this.randomUtil.getChance100(chance);
|
||||
}
|
||||
@ -169,9 +181,9 @@ export class PmcChatResponseService
|
||||
*/
|
||||
protected allCaps(isVictim: boolean): boolean
|
||||
{
|
||||
const chance = isVictim
|
||||
? this.pmcResponsesConfig.victim.allCapsChancePercent
|
||||
: this.pmcResponsesConfig.killer.allCapsChancePercent;
|
||||
const chance = isVictim ?
|
||||
this.pmcResponsesConfig.victim.allCapsChancePercent :
|
||||
this.pmcResponsesConfig.killer.allCapsChancePercent;
|
||||
|
||||
return this.randomUtil.getChance100(chance);
|
||||
}
|
||||
@ -183,13 +195,13 @@ export class PmcChatResponseService
|
||||
*/
|
||||
appendSuffixToMessageEnd(isVictim: boolean): boolean
|
||||
{
|
||||
const chance = isVictim
|
||||
? this.pmcResponsesConfig.victim.appendBroToMessageEndChancePercent
|
||||
: this.pmcResponsesConfig.killer.appendBroToMessageEndChancePercent;
|
||||
const chance = isVictim ?
|
||||
this.pmcResponsesConfig.victim.appendBroToMessageEndChancePercent :
|
||||
this.pmcResponsesConfig.killer.appendBroToMessageEndChancePercent;
|
||||
|
||||
return this.randomUtil.getChance100(chance);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Choose a type of response based on the weightings in pmc response config
|
||||
* @param isVictim Was responder killed by player
|
||||
@ -197,9 +209,9 @@ export class PmcChatResponseService
|
||||
*/
|
||||
protected chooseResponseType(isVictim = true): string
|
||||
{
|
||||
const responseWeights = isVictim
|
||||
? this.pmcResponsesConfig.victim.responseTypeWeights
|
||||
: this.pmcResponsesConfig.killer.responseTypeWeights;
|
||||
const responseWeights = isVictim ?
|
||||
this.pmcResponsesConfig.victim.responseTypeWeights :
|
||||
this.pmcResponsesConfig.killer.responseTypeWeights;
|
||||
|
||||
return this.weightedRandomHelper.getWeightedValue<string>(responseWeights);
|
||||
}
|
||||
@ -208,14 +220,14 @@ export class PmcChatResponseService
|
||||
* Get locale keys related to the type of response to send (victim/killer)
|
||||
* @param keyType Positive/negative
|
||||
* @param isVictim Was responder killed by player
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
protected getResponseLocaleKeys(keyType: string, isVictim = true): string[]
|
||||
{
|
||||
const keyBase = isVictim ? "pmcresponse-victim_" : "pmcresponse-killer_";
|
||||
const keys = this.localisationService.getKeys();
|
||||
|
||||
return keys.filter(x => x.startsWith(`${keyBase}${keyType}`));
|
||||
return keys.filter((x) => x.startsWith(`${keyBase}${keyType}`));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,7 +238,7 @@ export class PmcChatResponseService
|
||||
{
|
||||
const keys = this.localisationService.getKeys();
|
||||
|
||||
return keys.filter(x => x.startsWith("pmcresponse-suffix"));
|
||||
return keys.filter((x) => x.startsWith("pmcresponse-suffix"));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -248,7 +260,25 @@ export class PmcChatResponseService
|
||||
*/
|
||||
protected getVictimDetails(pmcVictim: Victim): IUserDialogInfo
|
||||
{
|
||||
const categories = [MemberCategory.UNIQUE_ID, MemberCategory.DEFAULT, MemberCategory.DEFAULT, MemberCategory.DEFAULT, MemberCategory.DEFAULT, MemberCategory.DEFAULT, MemberCategory.DEFAULT, MemberCategory.SHERPA, MemberCategory.DEVELOPER];
|
||||
return {_id: pmcVictim.Name, info:{Nickname: pmcVictim.Name, Level: pmcVictim.Level, Side: pmcVictim.Side, MemberCategory: this.randomUtil.getArrayValue(categories)}};
|
||||
const categories = [
|
||||
MemberCategory.UNIQUE_ID,
|
||||
MemberCategory.DEFAULT,
|
||||
MemberCategory.DEFAULT,
|
||||
MemberCategory.DEFAULT,
|
||||
MemberCategory.DEFAULT,
|
||||
MemberCategory.DEFAULT,
|
||||
MemberCategory.DEFAULT,
|
||||
MemberCategory.SHERPA,
|
||||
MemberCategory.DEVELOPER,
|
||||
];
|
||||
return {
|
||||
_id: pmcVictim.Name,
|
||||
info: {
|
||||
Nickname: pmcVictim.Name,
|
||||
Level: pmcVictim.Level,
|
||||
Side: pmcVictim.Side,
|
||||
MemberCategory: this.randomUtil.getArrayValue(categories),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ export class ProfileFixerService
|
||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.coreConfig = this.configServer.getConfig(ConfigTypes.CORE);
|
||||
@ -81,30 +81,74 @@ export class ProfileFixerService
|
||||
|
||||
this.reorderHideoutAreasWithResouceInputs(pmcProfile);
|
||||
|
||||
if (pmcProfile.Hideout.Areas[HideoutAreas.GENERATOR].slots.length <
|
||||
(6 + this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.Generator.Slots))
|
||||
if (
|
||||
pmcProfile.Hideout.Areas[HideoutAreas.GENERATOR].slots.length <
|
||||
(6 +
|
||||
this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.Generator.Slots)
|
||||
)
|
||||
{
|
||||
this.logger.debug("Updating generator area slots to a size of 6 + hideout management skill");
|
||||
this.addEmptyObjectsToHideoutAreaSlots(HideoutAreas.GENERATOR, (6 + this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.Generator.Slots), pmcProfile);
|
||||
this.addEmptyObjectsToHideoutAreaSlots(
|
||||
HideoutAreas.GENERATOR,
|
||||
6 +
|
||||
this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.Generator
|
||||
.Slots,
|
||||
pmcProfile,
|
||||
);
|
||||
}
|
||||
|
||||
if (pmcProfile.Hideout.Areas[HideoutAreas.WATER_COLLECTOR].slots.length < (1 + this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.WaterCollector.Slots))
|
||||
if (
|
||||
pmcProfile.Hideout.Areas[HideoutAreas.WATER_COLLECTOR].slots.length <
|
||||
(1 +
|
||||
this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.WaterCollector.Slots)
|
||||
)
|
||||
{
|
||||
this.logger.debug("Updating water collector area slots to a size of 1 + hideout management skill");
|
||||
this.addEmptyObjectsToHideoutAreaSlots(HideoutAreas.WATER_COLLECTOR, (1 + this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.WaterCollector.Slots), pmcProfile);
|
||||
this.addEmptyObjectsToHideoutAreaSlots(
|
||||
HideoutAreas.WATER_COLLECTOR,
|
||||
1 +
|
||||
this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.WaterCollector.Slots,
|
||||
pmcProfile,
|
||||
);
|
||||
}
|
||||
|
||||
if (pmcProfile.Hideout.Areas[HideoutAreas.AIR_FILTERING].slots.length < (3 + this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.AirFilteringUnit.Slots))
|
||||
if (
|
||||
pmcProfile.Hideout.Areas[HideoutAreas.AIR_FILTERING].slots.length <
|
||||
(3 +
|
||||
this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.AirFilteringUnit.Slots)
|
||||
)
|
||||
{
|
||||
this.logger.debug("Updating air filter area slots to a size of 3 + hideout management skill");
|
||||
this.addEmptyObjectsToHideoutAreaSlots(HideoutAreas.AIR_FILTERING, (3 + this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.AirFilteringUnit.Slots), pmcProfile);
|
||||
this.addEmptyObjectsToHideoutAreaSlots(
|
||||
HideoutAreas.AIR_FILTERING,
|
||||
3 +
|
||||
this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.AirFilteringUnit.Slots,
|
||||
pmcProfile,
|
||||
);
|
||||
}
|
||||
|
||||
// BTC Farm doesnt have extra slots for hideout management, but we still check for modded stuff!!
|
||||
if (pmcProfile.Hideout.Areas[HideoutAreas.BITCOIN_FARM].slots.length < (50 + this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.BitcoinFarm.Slots))
|
||||
if (
|
||||
pmcProfile.Hideout.Areas[HideoutAreas.BITCOIN_FARM].slots.length <
|
||||
(50 +
|
||||
this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.BitcoinFarm.Slots)
|
||||
)
|
||||
{
|
||||
this.logger.debug("Updating bitcoin farm area slots to a size of 50 + hideout management skill");
|
||||
this.addEmptyObjectsToHideoutAreaSlots(HideoutAreas.BITCOIN_FARM, (50 + this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.BitcoinFarm.Slots), pmcProfile);
|
||||
this.addEmptyObjectsToHideoutAreaSlots(
|
||||
HideoutAreas.BITCOIN_FARM,
|
||||
50 +
|
||||
this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.BitcoinFarm.Slots,
|
||||
pmcProfile,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,7 +164,7 @@ export class ProfileFixerService
|
||||
|
||||
protected addMissingGunStandContainerImprovements(pmcProfile: IPmcData): void
|
||||
{
|
||||
const weaponStandArea = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WEAPON_STAND);
|
||||
const weaponStandArea = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WEAPON_STAND);
|
||||
if (!weaponStandArea || weaponStandArea.level === 0)
|
||||
{
|
||||
// No stand in profile or its level 0, skip
|
||||
@ -128,8 +172,8 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
const db = this.databaseServer.getTables();
|
||||
const hideoutStandAreaDb = db.hideout.areas.find(x => x.type === HideoutAreas.WEAPON_STAND);
|
||||
const hideoutStandSecondaryAreaDb = db.hideout.areas.find(x => x.parentArea === hideoutStandAreaDb._id);
|
||||
const hideoutStandAreaDb = db.hideout.areas.find((x) => x.type === HideoutAreas.WEAPON_STAND);
|
||||
const hideoutStandSecondaryAreaDb = db.hideout.areas.find((x) => x.parentArea === hideoutStandAreaDb._id);
|
||||
const stageCurrentAt = hideoutStandAreaDb.stages[weaponStandArea.level];
|
||||
const hideoutStandStashId = pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.WEAPON_STAND];
|
||||
const hideoutSecondaryStashId = pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.WEAPON_STAND_SECONDARY];
|
||||
@ -139,51 +183,66 @@ export class ProfileFixerService
|
||||
{
|
||||
// Value is missing, add it
|
||||
pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.WEAPON_STAND] = hideoutStandAreaDb._id;
|
||||
pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.WEAPON_STAND_SECONDARY] = hideoutStandSecondaryAreaDb._id;
|
||||
pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.WEAPON_STAND_SECONDARY] =
|
||||
hideoutStandSecondaryAreaDb._id;
|
||||
|
||||
// Add stash item to profile
|
||||
const gunStandStashItem = pmcProfile.Inventory.items.find(x => x._id === hideoutStandAreaDb._id);
|
||||
const gunStandStashItem = pmcProfile.Inventory.items.find((x) => x._id === hideoutStandAreaDb._id);
|
||||
if (gunStandStashItem)
|
||||
{
|
||||
gunStandStashItem._tpl = stageCurrentAt.container;
|
||||
this.logger.debug(`Updated existing gun stand inventory stash: ${gunStandStashItem._id} tpl to ${stageCurrentAt.container}`);
|
||||
this.logger.debug(
|
||||
`Updated existing gun stand inventory stash: ${gunStandStashItem._id} tpl to ${stageCurrentAt.container}`,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
pmcProfile.Inventory.items.push({ _id: hideoutStandAreaDb._id, _tpl: stageCurrentAt.container });
|
||||
this.logger.debug(`Added missing gun stand inventory stash: ${hideoutStandAreaDb._id} tpl to ${stageCurrentAt.container}`);
|
||||
pmcProfile.Inventory.items.push({_id: hideoutStandAreaDb._id, _tpl: stageCurrentAt.container});
|
||||
this.logger.debug(
|
||||
`Added missing gun stand inventory stash: ${hideoutStandAreaDb._id} tpl to ${stageCurrentAt.container}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Add secondary stash item to profile
|
||||
const gunStandStashSecondaryItem = pmcProfile.Inventory.items.find(x => x._id === hideoutStandSecondaryAreaDb._id);
|
||||
const gunStandStashSecondaryItem = pmcProfile.Inventory.items.find((x) =>
|
||||
x._id === hideoutStandSecondaryAreaDb._id
|
||||
);
|
||||
if (gunStandStashItem)
|
||||
{
|
||||
gunStandStashSecondaryItem._tpl = stageCurrentAt.container;
|
||||
this.logger.debug(`Updated gun stand existing inventory secondary stash: ${gunStandStashSecondaryItem._id} tpl to ${stageCurrentAt.container}`);
|
||||
this.logger.debug(
|
||||
`Updated gun stand existing inventory secondary stash: ${gunStandStashSecondaryItem._id} tpl to ${stageCurrentAt.container}`,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
pmcProfile.Inventory.items.push({ _id: hideoutStandSecondaryAreaDb._id, _tpl: stageCurrentAt.container });
|
||||
this.logger.debug(`Added missing gun stand inventory secondary stash: ${hideoutStandSecondaryAreaDb._id} tpl to ${stageCurrentAt.container}`);
|
||||
pmcProfile.Inventory.items.push({_id: hideoutStandSecondaryAreaDb._id, _tpl: stageCurrentAt.container});
|
||||
this.logger.debug(
|
||||
`Added missing gun stand inventory secondary stash: ${hideoutStandSecondaryAreaDb._id} tpl to ${stageCurrentAt.container}`,
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const stashItem = pmcProfile.Inventory.items?.find(x => x._id === hideoutStandAreaDb._id);
|
||||
const stashItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandAreaDb._id);
|
||||
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
||||
if (hideoutStandStashId && stashItem?._tpl !== stageCurrentAt.container)
|
||||
{
|
||||
this.logger.debug(`primary Stash tpl was: ${stashItem._tpl}, but should be ${stageCurrentAt.container}, updating`);
|
||||
this.logger.debug(
|
||||
`primary Stash tpl was: ${stashItem._tpl}, but should be ${stageCurrentAt.container}, updating`,
|
||||
);
|
||||
// The id inside the profile does not match what the hideout db value is, out of sync, adjust
|
||||
stashItem._tpl = stageCurrentAt.container;
|
||||
}
|
||||
|
||||
const stashSecondaryItem = pmcProfile.Inventory.items?.find(x => x._id === hideoutStandSecondaryAreaDb._id);
|
||||
const stashSecondaryItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandSecondaryAreaDb._id);
|
||||
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
||||
if (hideoutSecondaryStashId && stashSecondaryItem?._tpl !== stageCurrentAt.container)
|
||||
{
|
||||
this.logger.debug(`Secondary stash tpl was: ${stashSecondaryItem._tpl}, but should be ${stageCurrentAt.container}, updating`);
|
||||
this.logger.debug(
|
||||
`Secondary stash tpl was: ${stashSecondaryItem._tpl}, but should be ${stageCurrentAt.container}, updating`,
|
||||
);
|
||||
// The id inside the profile does not match what the hideout db value is, out of sync, adjust
|
||||
stashSecondaryItem._tpl = stageCurrentAt.container;
|
||||
}
|
||||
@ -192,10 +251,10 @@ export class ProfileFixerService
|
||||
protected ensureGunStandLevelsMatch(pmcProfile: IPmcData): void
|
||||
{
|
||||
// only proceed if stand is level 1 or above
|
||||
const gunStandParent = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WEAPON_STAND);
|
||||
const gunStandParent = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WEAPON_STAND);
|
||||
if (gunStandParent && gunStandParent.level > 0)
|
||||
{
|
||||
const gunStandChild = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WEAPON_STAND_SECONDARY);
|
||||
const gunStandChild = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WEAPON_STAND_SECONDARY);
|
||||
if (gunStandChild && gunStandParent.level !== gunStandChild.level)
|
||||
{
|
||||
this.logger.success("Upgraded gun stand levels to match");
|
||||
@ -203,7 +262,7 @@ export class ProfileFixerService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected addHideoutAreaStashes(pmcProfile: IPmcData): void
|
||||
{
|
||||
if (!pmcProfile?.Inventory?.hideoutAreaStashes)
|
||||
@ -215,7 +274,7 @@ export class ProfileFixerService
|
||||
|
||||
protected addMissingHideoutWallAreas(pmcProfile: IPmcData): void
|
||||
{
|
||||
if (!pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WEAPON_STAND))
|
||||
if (!pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WEAPON_STAND))
|
||||
{
|
||||
pmcProfile.Hideout.Areas.push(
|
||||
{
|
||||
@ -226,12 +285,12 @@ export class ProfileFixerService
|
||||
completeTime: 0,
|
||||
constructing: false,
|
||||
slots: [],
|
||||
lastRecipe: ""
|
||||
}
|
||||
lastRecipe: "",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (!pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WEAPON_STAND_SECONDARY))
|
||||
if (!pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WEAPON_STAND_SECONDARY))
|
||||
{
|
||||
pmcProfile.Hideout.Areas.push(
|
||||
{
|
||||
@ -242,8 +301,8 @@ export class ProfileFixerService
|
||||
completeTime: 0,
|
||||
constructing: false,
|
||||
slots: [],
|
||||
lastRecipe: ""
|
||||
}
|
||||
lastRecipe: "",
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -269,7 +328,7 @@ export class ProfileFixerService
|
||||
continue;
|
||||
}
|
||||
|
||||
const itemHandbookPrice = handbookPrices.find(x => x.Id === itemTpl);
|
||||
const itemHandbookPrice = handbookPrices.find((x) => x.Id === itemTpl);
|
||||
if (!itemHandbookPrice)
|
||||
{
|
||||
continue;
|
||||
@ -279,7 +338,7 @@ export class ProfileFixerService
|
||||
{
|
||||
if (fleaPrices[itemTpl] <= 1)
|
||||
{
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Price is over limit, adjust
|
||||
@ -291,7 +350,7 @@ export class ProfileFixerService
|
||||
|
||||
/**
|
||||
* Add tag to profile to indicate when it was made
|
||||
* @param fullProfile
|
||||
* @param fullProfile
|
||||
*/
|
||||
public addMissingAkiVersionTagToProfile(fullProfile: IAkiProfile): void
|
||||
{
|
||||
@ -300,7 +359,7 @@ export class ProfileFixerService
|
||||
this.logger.debug("Adding aki object to profile");
|
||||
fullProfile.aki = {
|
||||
version: this.watermark.getVersionTag(),
|
||||
receivedGifts: []
|
||||
receivedGifts: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -314,7 +373,7 @@ export class ProfileFixerService
|
||||
{
|
||||
if (pmcProfile.ConditionCounters)
|
||||
{
|
||||
pmcProfile.ConditionCounters.Counters = pmcProfile.ConditionCounters.Counters.filter(c => c.qid !== null);
|
||||
pmcProfile.ConditionCounters.Counters = pmcProfile.ConditionCounters.Counters.filter((c) => c.qid !== null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,7 +384,7 @@ export class ProfileFixerService
|
||||
return;
|
||||
}
|
||||
|
||||
// only add if other traders exist, means this is pre-patch 13 profile
|
||||
// only add if other traders exist, means this is pre-patch 13 profile
|
||||
if (!pmcProfile.TradersInfo[Traders.LIGHTHOUSEKEEPER] && Object.keys(pmcProfile.TradersInfo).length > 0)
|
||||
{
|
||||
this.logger.warning("Added missing Lighthouse keeper trader to pmc profile");
|
||||
@ -335,7 +394,7 @@ export class ProfileFixerService
|
||||
salesSum: 0,
|
||||
standing: 0.2,
|
||||
loyaltyLevel: 1,
|
||||
nextResupply: this.timeUtil.getTimestamp() + 3600 // now + 1 hour
|
||||
nextResupply: this.timeUtil.getTimestamp() + 3600, // now + 1 hour
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -346,7 +405,7 @@ export class ProfileFixerService
|
||||
{
|
||||
this.logger.debug("Adding UnlockedInfo object to profile");
|
||||
pmcProfile.UnlockedInfo = {
|
||||
unlockedProductionRecipe: []
|
||||
unlockedProductionRecipe: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -361,9 +420,9 @@ export class ProfileFixerService
|
||||
{
|
||||
if (pmcProfile.RepeatableQuests && activeQuests.length > 0)
|
||||
{
|
||||
const existsInActiveRepeatableQuests = activeQuests.some(x => x._id === backendCounter.qid);
|
||||
const existsInQuests = pmcProfile.Quests.some(q => q.qid === backendCounter.qid);
|
||||
|
||||
const existsInActiveRepeatableQuests = activeQuests.some((x) => x._id === backendCounter.qid);
|
||||
const existsInQuests = pmcProfile.Quests.some((q) => q.qid === backendCounter.qid);
|
||||
|
||||
// if BackendCounter's quest is neither in activeQuests nor Quests it's stale
|
||||
if (!existsInActiveRepeatableQuests && !existsInQuests)
|
||||
{
|
||||
@ -375,7 +434,7 @@ export class ProfileFixerService
|
||||
for (const counterKeyToRemove of counterKeysToRemove)
|
||||
{
|
||||
this.logger.debug(`Removed ${counterKeyToRemove} backend count object`);
|
||||
delete pmcProfile.BackendCounters[counterKeyToRemove];
|
||||
delete pmcProfile.BackendCounters[counterKeyToRemove];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -400,7 +459,7 @@ export class ProfileFixerService
|
||||
for (const traderId in pmcProfile.TradersInfo)
|
||||
{
|
||||
const trader = pmcProfile.TradersInfo[traderId];
|
||||
if (trader && trader.salesSum === null)
|
||||
if (trader && trader.salesSum === null)
|
||||
{
|
||||
this.logger.warning(`trader ${traderId} has a null salesSum value, resetting to 0`);
|
||||
trader.salesSum = 0;
|
||||
@ -430,7 +489,7 @@ export class ProfileFixerService
|
||||
return;
|
||||
}
|
||||
|
||||
const fixes = new Map<any, number>();
|
||||
const fixes = new Map<any, number>();
|
||||
const questsToDelete: IQuestStatus[] = [];
|
||||
const fullProfile = this.profileHelper.getFullProfile(pmcProfile.sessionId);
|
||||
const isDevProfile = fullProfile?.info.edition.toLowerCase() === "spt developer";
|
||||
@ -448,9 +507,13 @@ export class ProfileFixerService
|
||||
if (quest.status && !Number(quest.status))
|
||||
{
|
||||
if (fixes.has(quest.status))
|
||||
{
|
||||
fixes.set(quest.status, fixes.get(quest.status) + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fixes.set(quest.status, 1);
|
||||
}
|
||||
|
||||
const newQuestStatus = QuestStatus[quest.status];
|
||||
quest.status = <QuestStatus><unknown>newQuestStatus;
|
||||
@ -461,7 +524,7 @@ export class ProfileFixerService
|
||||
{
|
||||
const newKey = QuestStatus[statusTimer];
|
||||
quest.statusTimers[newKey] = quest.statusTimers[statusTimer];
|
||||
delete quest.statusTimers[statusTimer];
|
||||
delete quest.statusTimers[statusTimer];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -473,7 +536,13 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
if (fixes.size > 0)
|
||||
this.logger.debug(`Updated quests values: ${Array.from(fixes.entries()).map(([k, v]) => `(${k}: ${v} times)`).join(", ")}`);
|
||||
{
|
||||
this.logger.debug(
|
||||
`Updated quests values: ${
|
||||
Array.from(fixes.entries()).map(([k, v]) => `(${k}: ${v} times)`).join(", ")
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected addMissingRepeatableQuestsProperty(pmcProfile: IPmcData): void
|
||||
@ -485,7 +554,9 @@ export class ProfileFixerService
|
||||
{
|
||||
if (
|
||||
!(currentRepeatable.changeRequirement &&
|
||||
currentRepeatable.activeQuests.every(x => (typeof x.changeCost !== "undefined" && typeof x.changeStandingCost !== "undefined")))
|
||||
currentRepeatable.activeQuests.every(
|
||||
(x) => (typeof x.changeCost !== "undefined" && typeof x.changeStandingCost !== "undefined"),
|
||||
))
|
||||
)
|
||||
{
|
||||
repeatablesCompatible = false;
|
||||
@ -507,7 +578,9 @@ export class ProfileFixerService
|
||||
protected addMissingWallImprovements(pmcProfile: IPmcData): void
|
||||
{
|
||||
const profileWallArea = pmcProfile.Hideout.Areas[HideoutAreas.EMERGENCY_WALL];
|
||||
const wallDb = this.databaseServer.getTables().hideout.areas.find(x => x.type === HideoutAreas.EMERGENCY_WALL);
|
||||
const wallDb = this.databaseServer.getTables().hideout.areas.find((x) =>
|
||||
x.type === HideoutAreas.EMERGENCY_WALL
|
||||
);
|
||||
|
||||
if (profileWallArea.level > 0)
|
||||
{
|
||||
@ -531,7 +604,7 @@ export class ProfileFixerService
|
||||
|
||||
pmcProfile.Hideout.Improvement[improvement.id] = {
|
||||
completed: true,
|
||||
improveCompleteTimestamp: this.timeUtil.getTimestamp() + i // add some variability
|
||||
improveCompleteTimestamp: this.timeUtil.getTimestamp() + i, // add some variability
|
||||
};
|
||||
|
||||
this.logger.debug(`Added wall improvement ${improvement.id} to profile`);
|
||||
@ -555,13 +628,13 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
// Only slots with location index
|
||||
area.slots = area.slots.filter(x => "locationIndex" in x);
|
||||
area.slots = area.slots.filter((x) => "locationIndex" in x);
|
||||
|
||||
// Only slots that:
|
||||
// Have an item property and it has at least one item in it
|
||||
// Or
|
||||
// Have no item property
|
||||
area.slots = area.slots.filter(x => "item" in x && x.item?.length > 0 || !("item" in x));
|
||||
area.slots = area.slots.filter((x) => "item" in x && x.item?.length > 0 || !("item" in x));
|
||||
}
|
||||
}
|
||||
|
||||
@ -571,7 +644,12 @@ export class ProfileFixerService
|
||||
*/
|
||||
protected reorderHideoutAreasWithResouceInputs(pmcProfile: IPmcData): void
|
||||
{
|
||||
const areasToCheck = [HideoutAreas.AIR_FILTERING, HideoutAreas.GENERATOR, HideoutAreas.BITCOIN_FARM, HideoutAreas.WATER_COLLECTOR];
|
||||
const areasToCheck = [
|
||||
HideoutAreas.AIR_FILTERING,
|
||||
HideoutAreas.GENERATOR,
|
||||
HideoutAreas.BITCOIN_FARM,
|
||||
HideoutAreas.WATER_COLLECTOR,
|
||||
];
|
||||
|
||||
for (const areaId of areasToCheck)
|
||||
{
|
||||
@ -583,13 +661,13 @@ export class ProfileFixerService
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!area.slots || area.slots.length === 0)
|
||||
if (!area.slots || area.slots.length === 0)
|
||||
{
|
||||
this.logger.debug(`unable to sort ${areaId} slots, no slots found`);
|
||||
continue;
|
||||
}
|
||||
|
||||
area.slots = area.slots.sort( (a, b) =>
|
||||
area.slots = area.slots.sort((a, b) =>
|
||||
{
|
||||
return a.locationIndex > b.locationIndex ? 1 : -1;
|
||||
});
|
||||
@ -601,10 +679,13 @@ export class ProfileFixerService
|
||||
* @param areaType area to check
|
||||
* @param pmcProfile profile to update
|
||||
*/
|
||||
protected addEmptyObjectsToHideoutAreaSlots(areaType: HideoutAreas, emptyItemCount: number, pmcProfile: IPmcData): void
|
||||
protected addEmptyObjectsToHideoutAreaSlots(
|
||||
areaType: HideoutAreas,
|
||||
emptyItemCount: number,
|
||||
pmcProfile: IPmcData,
|
||||
): void
|
||||
{
|
||||
|
||||
const area = pmcProfile.Hideout.Areas.find(x => x.type === areaType);
|
||||
const area = pmcProfile.Hideout.Areas.find((x) => x.type === areaType);
|
||||
area.slots = this.addObjectsToArray(emptyItemCount, area.slots);
|
||||
}
|
||||
|
||||
@ -612,23 +693,22 @@ export class ProfileFixerService
|
||||
{
|
||||
for (let i = 0; i < count; i++)
|
||||
{
|
||||
if (!slots.find(x => x.locationIndex === i))
|
||||
if (!slots.find((x) => x.locationIndex === i))
|
||||
{
|
||||
slots.push({locationIndex: i});
|
||||
}
|
||||
}
|
||||
|
||||
return slots;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* In 18876 bsg changed the pockets tplid to be one that has 3 additional special slots
|
||||
* @param pmcProfile
|
||||
* @param pmcProfile
|
||||
*/
|
||||
protected updateProfilePocketsToNewId(pmcProfile: IPmcData): void
|
||||
{
|
||||
const pocketItem = pmcProfile.Inventory?.items?.find(x => x.slotId === "Pockets");
|
||||
const pocketItem = pmcProfile.Inventory?.items?.find((x) => x.slotId === "Pockets");
|
||||
if (pocketItem)
|
||||
{
|
||||
if (pocketItem._tpl === "557ffd194bdc2d28148b457f")
|
||||
@ -668,7 +748,7 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
// Iterate over area levels, check for bonuses, add if needed
|
||||
const dbArea = dbHideoutAreas.find(x => x.type === areaType);
|
||||
const dbArea = dbHideoutAreas.find((x) => x.type === areaType);
|
||||
if (!dbArea)
|
||||
{
|
||||
continue;
|
||||
@ -691,16 +771,19 @@ export class ProfileFixerService
|
||||
if (!profileBonus)
|
||||
{
|
||||
// no bonus, add to profile
|
||||
this.logger.debug(`Profile has level ${level} area ${HideoutAreas[area.type]} but no bonus found, adding ${bonus.type}`);
|
||||
this.logger.debug(
|
||||
`Profile has level ${level} area ${
|
||||
HideoutAreas[area.type]
|
||||
} but no bonus found, adding ${bonus.type}`,
|
||||
);
|
||||
this.hideoutHelper.applyPlayerUpgradesBonuses(pmcProfile, bonus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param profileBonuses bonuses from profile
|
||||
* @param bonus bonus to find
|
||||
* @returns matching bonus
|
||||
@ -710,27 +793,33 @@ export class ProfileFixerService
|
||||
// match by id first, used by "TextBonus" bonuses
|
||||
if (bonus.id)
|
||||
{
|
||||
return profileBonuses.find(x => x.id === bonus.id);
|
||||
return profileBonuses.find((x) => x.id === bonus.id);
|
||||
}
|
||||
|
||||
if (bonus.type.toLowerCase() === "stashsize")
|
||||
{
|
||||
return profileBonuses.find(
|
||||
x => x.type === bonus.type
|
||||
&& x.templateId === bonus.templateId);
|
||||
(x) =>
|
||||
x.type === bonus.type &&
|
||||
x.templateId === bonus.templateId,
|
||||
);
|
||||
}
|
||||
|
||||
if (bonus.type.toLowerCase() === "additionalslots")
|
||||
{
|
||||
return profileBonuses.find(
|
||||
x => x.type === bonus.type
|
||||
&& x.value === bonus.value
|
||||
&& x.visible === bonus.visible);
|
||||
(x) =>
|
||||
x.type === bonus.type &&
|
||||
x.value === bonus.value &&
|
||||
x.visible === bonus.visible,
|
||||
);
|
||||
}
|
||||
|
||||
return profileBonuses.find(
|
||||
x => x.type === bonus.type
|
||||
&& x.value === bonus.value);
|
||||
(x) =>
|
||||
x.type === bonus.type &&
|
||||
x.value === bonus.value,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -745,7 +834,7 @@ export class ProfileFixerService
|
||||
|
||||
// Get items placed in root of stash
|
||||
// TODO: extend to other areas / sub items
|
||||
const inventoryItemsToCheck = pmcProfile.Inventory.items.filter(x => ["hideout", "main"].includes(x.slotId));
|
||||
const inventoryItemsToCheck = pmcProfile.Inventory.items.filter((x) => ["hideout", "main"].includes(x.slotId));
|
||||
if (!inventoryItemsToCheck)
|
||||
{
|
||||
return;
|
||||
@ -760,7 +849,9 @@ export class ProfileFixerService
|
||||
|
||||
if (this.coreConfig.fixes.removeModItemsFromProfile)
|
||||
{
|
||||
this.logger.success(`Deleting item from inventory and insurance with id: ${item._id} tpl: ${item._tpl}`);
|
||||
this.logger.success(
|
||||
`Deleting item from inventory and insurance with id: ${item._id} tpl: ${item._tpl}`,
|
||||
);
|
||||
|
||||
// Also deletes from insured array
|
||||
this.inventoryHelper.removeItem(pmcProfile, item._id, sessionId);
|
||||
@ -781,7 +872,9 @@ export class ProfileFixerService
|
||||
if (this.coreConfig.fixes.removeModItemsFromProfile)
|
||||
{
|
||||
delete fullProfile.userbuilds.weaponBuilds[buildId];
|
||||
this.logger.warning(`Item: ${item._tpl} has resulted in the deletion of weapon build: ${buildId}`);
|
||||
this.logger.warning(
|
||||
`Item: ${item._tpl} has resulted in the deletion of weapon build: ${buildId}`,
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -824,8 +917,10 @@ export class ProfileFixerService
|
||||
|
||||
if (this.coreConfig.fixes.removeModItemsFromProfile)
|
||||
{
|
||||
dialog.messages.splice(dialog.messages.findIndex(x => x._id === message._id), 1);
|
||||
this.logger.warning(`Item: ${item._tpl} has resulted in the deletion of message: ${message._id} from dialog ${dialogId}`);
|
||||
dialog.messages.splice(dialog.messages.findIndex((x) => x._id === message._id), 1);
|
||||
this.logger.warning(
|
||||
`Item: ${item._tpl} has resulted in the deletion of message: ${message._id} from dialog ${dialogId}`,
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -857,8 +952,13 @@ export class ProfileFixerService
|
||||
this.logger.error(this.localisationService.getText("fixer-mod_item_found", activeQuest.traderId));
|
||||
if (this.coreConfig.fixes.removeModItemsFromProfile)
|
||||
{
|
||||
this.logger.warning(`Non-default quest: ${activeQuest._id} from trader: ${activeQuest.traderId} removed from RepeatableQuests list in profile`);
|
||||
repeatable.activeQuests.splice(repeatable.activeQuests.findIndex(x => x._id === activeQuest._id), 1);
|
||||
this.logger.warning(
|
||||
`Non-default quest: ${activeQuest._id} from trader: ${activeQuest.traderId} removed from RepeatableQuests list in profile`,
|
||||
);
|
||||
repeatable.activeQuests.splice(
|
||||
repeatable.activeQuests.findIndex((x) => x._id === activeQuest._id),
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
continue;
|
||||
@ -872,11 +972,18 @@ export class ProfileFixerService
|
||||
{
|
||||
if (!itemsDb[rewardItem._tpl])
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("fixer-mod_item_found", rewardItem._tpl));
|
||||
this.logger.error(
|
||||
this.localisationService.getText("fixer-mod_item_found", rewardItem._tpl),
|
||||
);
|
||||
if (this.coreConfig.fixes.removeModItemsFromProfile)
|
||||
{
|
||||
this.logger.warning(`Non-default quest: ${activeQuest._id} from trader: ${activeQuest.traderId} removed from RepeatableQuests list in profile`);
|
||||
repeatable.activeQuests.splice(repeatable.activeQuests.findIndex(x => x._id === activeQuest._id), 1);
|
||||
this.logger.warning(
|
||||
`Non-default quest: ${activeQuest._id} from trader: ${activeQuest.traderId} removed from RepeatableQuests list in profile`,
|
||||
);
|
||||
repeatable.activeQuests.splice(
|
||||
repeatable.activeQuests.findIndex((x) => x._id === activeQuest._id),
|
||||
1,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -898,7 +1005,7 @@ export class ProfileFixerService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add `Improvements` object to hideout if missing - added in eft 13.0.21469
|
||||
* @param pmcProfile profile to update
|
||||
@ -939,7 +1046,7 @@ export class ProfileFixerService
|
||||
// Get all areas from templates/profiles.json
|
||||
for (const area of profileTemplate.character.Hideout.Areas)
|
||||
{
|
||||
if (!pmcProfile.Hideout.Areas.find(x => x.type === area.type))
|
||||
if (!pmcProfile.Hideout.Areas.find((x) => x.type === area.type))
|
||||
{
|
||||
pmcProfile.Hideout.Areas.push(area);
|
||||
this.logger.debug(`Added missing hideout area ${area.type} to profile`);
|
||||
@ -957,7 +1064,7 @@ export class ProfileFixerService
|
||||
{
|
||||
if (prodKey.startsWith("ScavCase"))
|
||||
{
|
||||
delete pmcProfile.Hideout.Production[prodKey];
|
||||
delete pmcProfile.Hideout.Production[prodKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -980,7 +1087,9 @@ export class ProfileFixerService
|
||||
|
||||
fullProfile.info.aid = fullProfile.characters.pmc.aid;
|
||||
|
||||
this.logger.debug(`Migrated AccountId from: ${fullProfile.characters.pmc.sessionId} to: ${fullProfile.characters.pmc.aid}`);
|
||||
this.logger.debug(
|
||||
`Migrated AccountId from: ${fullProfile.characters.pmc.sessionId} to: ${fullProfile.characters.pmc.aid}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1020,12 +1129,14 @@ export class ProfileFixerService
|
||||
|
||||
// Bonus lacks id, find matching hideout area / stage / bonus
|
||||
for (const area of this.databaseServer.getTables().hideout.areas)
|
||||
{
|
||||
{
|
||||
// TODO: skip if no stages
|
||||
for (const stageIndex in area.stages)
|
||||
{
|
||||
const stageInfo = area.stages[stageIndex];
|
||||
const matchingBonus = stageInfo.bonuses.find(x => x.templateId === bonus.templateId && x.type === bonus.type);
|
||||
const matchingBonus = stageInfo.bonuses.find((x) =>
|
||||
x.templateId === bonus.templateId && x.type === bonus.type
|
||||
);
|
||||
if (matchingBonus)
|
||||
{
|
||||
// Add id to bonus, flag bonus as found and exit stage loop
|
||||
@ -1060,4 +1171,4 @@ export class ProfileFixerService
|
||||
this.logger.success("Successfully migrated hideout Improvements data to new location, deleted old data");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,10 @@ export class ProfileSnapshotService
|
||||
protected storedProfileSnapshots: Record<string, IAkiProfile> = {};
|
||||
|
||||
constructor(
|
||||
@inject("JsonUtil") protected jsonUtil: JsonUtil
|
||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||
)
|
||||
{}
|
||||
|
||||
|
||||
/**
|
||||
* Store a profile into an in-memory object
|
||||
* @param sessionID session id - acts as the key
|
||||
@ -61,4 +61,4 @@ export class ProfileSnapshotService
|
||||
{
|
||||
delete this.storedProfileSnapshots[sessionID];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,15 +9,15 @@ export class RagfairCategoriesService
|
||||
protected categories: Record<string, number> = {};
|
||||
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
)
|
||||
{ }
|
||||
{}
|
||||
|
||||
/**
|
||||
* Get all flea categories and their count of offers
|
||||
* @returns item categories and count
|
||||
*/
|
||||
public getAllCategories(): Record<string, number>
|
||||
public getAllCategories(): Record<string, number>
|
||||
{
|
||||
return this.categories;
|
||||
}
|
||||
@ -26,7 +26,7 @@ export class RagfairCategoriesService
|
||||
* With the supplied items, get custom categories
|
||||
* @returns a custom list of categories
|
||||
*/
|
||||
public getBespokeCategories(offers: IRagfairOffer[]): Record<string, number>
|
||||
public getBespokeCategories(offers: IRagfairOffer[]): Record<string, number>
|
||||
{
|
||||
return this.processOffersIntoCategories(offers);
|
||||
}
|
||||
@ -36,7 +36,7 @@ export class RagfairCategoriesService
|
||||
* @param offers ragfair offers
|
||||
* @returns categories and count
|
||||
*/
|
||||
protected processOffersIntoCategories(offers: IRagfairOffer[]): Record<string, number>
|
||||
protected processOffersIntoCategories(offers: IRagfairOffer[]): Record<string, number>
|
||||
{
|
||||
const result = {};
|
||||
for (const offer of offers)
|
||||
@ -53,14 +53,14 @@ export class RagfairCategoriesService
|
||||
* @param categories Categories to update
|
||||
* @param increment (Optional) Should item be incremented or decremented
|
||||
*/
|
||||
protected addOrIncrementCategory(offer: IRagfairOffer, categories: Record<string, number>, increment = true ): void
|
||||
protected addOrIncrementCategory(offer: IRagfairOffer, categories: Record<string, number>, increment = true): void
|
||||
{
|
||||
const itemId = offer.items[0]._tpl;
|
||||
if (increment)
|
||||
{
|
||||
categories[itemId] = categories[itemId]
|
||||
? categories[itemId] + 1
|
||||
: 1;
|
||||
categories[itemId] = categories[itemId] ?
|
||||
categories[itemId] + 1 :
|
||||
1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -80,7 +80,7 @@ export class RagfairCategoriesService
|
||||
|
||||
/**
|
||||
* Increase category count by 1
|
||||
* @param offer
|
||||
* @param offer
|
||||
*/
|
||||
public incrementCategory(offer: IRagfairOffer): void
|
||||
{
|
||||
@ -90,11 +90,11 @@ export class RagfairCategoriesService
|
||||
|
||||
/**
|
||||
* Reduce category count by 1
|
||||
* @param offer
|
||||
* @param offer
|
||||
*/
|
||||
public decrementCategory(offer: IRagfairOffer): void
|
||||
{
|
||||
this.addOrIncrementCategory(offer, this.categories, false);
|
||||
this.categories[offer.items[0]._tpl]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,9 @@ export class RagfairLinkedItemService
|
||||
|
||||
constructor(
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
)
|
||||
{ }
|
||||
{}
|
||||
|
||||
public getLinkedItems(linkedSearchId: string): Set<string>
|
||||
{
|
||||
@ -34,7 +34,7 @@ export class RagfairLinkedItemService
|
||||
public getLinkedDbItems(itemTpl: string): ITemplateItem[]
|
||||
{
|
||||
const linkedItemsToWeaponTpls = this.getLinkedItems(itemTpl);
|
||||
return [...linkedItemsToWeaponTpls].map(x =>
|
||||
return [...linkedItemsToWeaponTpls].map((x) =>
|
||||
{
|
||||
const itemDetails = this.itemHelper.getItem(x);
|
||||
return itemDetails[1];
|
||||
@ -88,11 +88,14 @@ export class RagfairLinkedItemService
|
||||
/**
|
||||
* Add ammo to revolvers linked item dictionary
|
||||
* @param cylinder Revolvers cylinder
|
||||
* @param applyLinkedItems
|
||||
* @param applyLinkedItems
|
||||
*/
|
||||
protected addRevolverCylinderAmmoToLinkedItems(cylinder: ITemplateItem, applyLinkedItems: (items: string[]) => void): void
|
||||
protected addRevolverCylinderAmmoToLinkedItems(
|
||||
cylinder: ITemplateItem,
|
||||
applyLinkedItems: (items: string[]) => void,
|
||||
): void
|
||||
{
|
||||
const cylinderMod = cylinder._props.Slots.find(x => x._name === "mod_magazine");
|
||||
const cylinderMod = cylinder._props.Slots.find((x) => x._name === "mod_magazine");
|
||||
if (cylinderMod)
|
||||
{
|
||||
// Get the first cylinder filter tpl
|
||||
@ -108,8 +111,8 @@ export class RagfairLinkedItemService
|
||||
|
||||
/**
|
||||
* Scans a given slot type for filters and returns them as a Set
|
||||
* @param item
|
||||
* @param slot
|
||||
* @param item
|
||||
* @param slot
|
||||
* @returns array of ids
|
||||
*/
|
||||
protected getFilters(item: ITemplateItem, slot: string): string[]
|
||||
@ -140,4 +143,4 @@ export class RagfairLinkedItemService
|
||||
|
||||
return filters;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ export class RagfairOfferService
|
||||
@inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder,
|
||||
@inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR);
|
||||
@ -113,12 +113,14 @@ export class RagfairOfferService
|
||||
* Remove an offer from ragfair by offer id
|
||||
* @param offerId Offer id to remove
|
||||
*/
|
||||
public removeOfferById(offerId: string): void
|
||||
public removeOfferById(offerId: string): void
|
||||
{
|
||||
const offer = this.ragfairOfferHandler.getOfferById(offerId);
|
||||
if (!offer)
|
||||
{
|
||||
this.logger.warning(this.localisationService.getText("ragfair-unable_to_remove_offer_doesnt_exist", offerId));
|
||||
this.logger.warning(
|
||||
this.localisationService.getText("ragfair-unable_to_remove_offer_doesnt_exist", offerId),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -171,13 +173,13 @@ export class RagfairOfferService
|
||||
for (const sessionID in this.saveServer.getProfiles())
|
||||
{
|
||||
const pmcData = this.saveServer.getProfile(sessionID).characters.pmc;
|
||||
|
||||
|
||||
if (pmcData.RagfairInfo === undefined || pmcData.RagfairInfo.offers === undefined)
|
||||
{
|
||||
// Profile is wiped
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
this.ragfairOfferHandler.addOffers(pmcData.RagfairInfo.offers);
|
||||
}
|
||||
this.playerOffersLoaded = true;
|
||||
@ -235,7 +237,7 @@ export class RagfairOfferService
|
||||
const pmcID = String(offer.user.id);
|
||||
const profile = this.profileHelper.getProfileByPmcId(pmcID);
|
||||
const sessionID = profile.sessionId;
|
||||
const offerIndex = profile.RagfairInfo.offers.findIndex(o => o._id === offer._id);
|
||||
const offerIndex = profile.RagfairInfo.offers.findIndex((o) => o._id === offer._id);
|
||||
|
||||
profile.RagfairInfo.rating -= this.ragfairConfig.sell.reputation.loss;
|
||||
profile.RagfairInfo.isRatingGrowing = false;
|
||||
@ -243,7 +245,10 @@ export class RagfairOfferService
|
||||
if (offerIndex === -1)
|
||||
{
|
||||
this.logger.warning(this.localisationService.getText("ragfair-unable_to_find_offer_to_remove", offer._id));
|
||||
return this.httpResponse.appendErrorToOutput(this.eventOutputHolder.getOutput(sessionID), this.localisationService.getText("ragfair-offer_not_found_in_profile_short"));
|
||||
return this.httpResponse.appendErrorToOutput(
|
||||
this.eventOutputHolder.getOutput(sessionID),
|
||||
this.localisationService.getText("ragfair-offer_not_found_in_profile_short"),
|
||||
);
|
||||
}
|
||||
|
||||
if (offer.items[0].upd.StackObjectsCount > offer.items[0].upd.OriginalStackObjectsCount)
|
||||
|
@ -31,7 +31,7 @@ export class RagfairPriceService implements OnLoad
|
||||
|
||||
protected prices: IRagfairServerPrices = {
|
||||
static: {},
|
||||
dynamic: {}
|
||||
dynamic: {},
|
||||
};
|
||||
|
||||
constructor(
|
||||
@ -43,7 +43,7 @@ export class RagfairPriceService implements OnLoad
|
||||
@inject("TraderHelper") protected traderHelper: TraderHelper,
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR);
|
||||
@ -52,7 +52,7 @@ export class RagfairPriceService implements OnLoad
|
||||
/**
|
||||
* Generate static (handbook) and dynamic (prices.json) flea prices, store inside class as dictionaries
|
||||
*/
|
||||
public async onLoad(): Promise<void>
|
||||
public async onLoad(): Promise<void>
|
||||
{
|
||||
if (!this.generatedStaticPrices)
|
||||
{
|
||||
@ -67,7 +67,7 @@ export class RagfairPriceService implements OnLoad
|
||||
}
|
||||
}
|
||||
|
||||
public getRoute(): string
|
||||
public getRoute(): string
|
||||
{
|
||||
return "RagfairPriceService";
|
||||
}
|
||||
@ -77,7 +77,11 @@ export class RagfairPriceService implements OnLoad
|
||||
*/
|
||||
public generateStaticPrices(): void
|
||||
{
|
||||
for (const item of Object.values(this.databaseServer.getTables().templates.items).filter(x => x._type === "Item"))
|
||||
for (
|
||||
const item of Object.values(this.databaseServer.getTables().templates.items).filter((x) =>
|
||||
x._type === "Item"
|
||||
)
|
||||
)
|
||||
{
|
||||
this.prices.static[item._id] = Math.round(this.handbookHelper.getTemplatePrice(item._id));
|
||||
}
|
||||
@ -103,7 +107,9 @@ export class RagfairPriceService implements OnLoad
|
||||
let itemPrice = this.getDynamicPriceForItem(tplId) || this.getStaticPriceForItem(tplId);
|
||||
if (!itemPrice)
|
||||
{
|
||||
this.logger.warning(this.localisationService.getText("ragfair-unable_to_find_item_price_for_item_in_flea_handbook", tplId));
|
||||
this.logger.warning(
|
||||
this.localisationService.getText("ragfair-unable_to_find_item_price_for_item_in_flea_handbook", tplId),
|
||||
);
|
||||
}
|
||||
|
||||
// If no price in dynamic/static, set to 1
|
||||
@ -150,7 +156,7 @@ export class RagfairPriceService implements OnLoad
|
||||
public getAllFleaPrices(): Record<string, number>
|
||||
{
|
||||
// assign static values first, then overwrite them with dynamic, any values not stored in dynamic data will be covered by static data
|
||||
return { ...this.prices.static, ...this.prices.dynamic };
|
||||
return {...this.prices.static, ...this.prices.dynamic};
|
||||
}
|
||||
|
||||
public getAllStaticPrices(): Record<string, number>
|
||||
@ -171,7 +177,7 @@ export class RagfairPriceService implements OnLoad
|
||||
|
||||
/**
|
||||
* Get the rouble price for an assorts barter scheme
|
||||
* @param barterScheme
|
||||
* @param barterScheme
|
||||
* @returns Rouble price
|
||||
*/
|
||||
public getBarterPrice(barterScheme: IBarterScheme[]): number
|
||||
@ -180,7 +186,7 @@ export class RagfairPriceService implements OnLoad
|
||||
|
||||
for (const item of barterScheme)
|
||||
{
|
||||
price += (this.prices.static[item._tpl] * item.count);
|
||||
price += this.prices.static[item._tpl] * item.count;
|
||||
}
|
||||
|
||||
return Math.round(price);
|
||||
@ -219,7 +225,7 @@ export class RagfairPriceService implements OnLoad
|
||||
itemPrice = traderPrice;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check if item type is weapon preset, handle differently
|
||||
const itemDetails = this.itemHelper.getItem(item._tpl);
|
||||
if (this.presetHelper.isPreset(item._id) && itemDetails[1]._props.weapFireType)
|
||||
@ -248,7 +254,7 @@ export class RagfairPriceService implements OnLoad
|
||||
|
||||
const rangeValues = this.getOfferTypeRangeValues(isPreset, isPackOffer);
|
||||
price = this.randomiseOfferPrice(price, rangeValues);
|
||||
|
||||
|
||||
if (price < 1)
|
||||
{
|
||||
price = 1;
|
||||
@ -291,12 +297,17 @@ export class RagfairPriceService implements OnLoad
|
||||
const priceDifferencePercent = this.getPriceDifference(itemHandbookPrice, itemPrice);
|
||||
|
||||
// Only adjust price if difference is > a percent AND item price passes threshhold set in config
|
||||
if (priceDifferencePercent > this.ragfairConfig.dynamic.offerAdjustment.maxPriceDifferenceBelowHandbookPercent
|
||||
&& itemPrice >= this.ragfairConfig.dynamic.offerAdjustment.priceThreshholdRub)
|
||||
if (
|
||||
priceDifferencePercent >
|
||||
this.ragfairConfig.dynamic.offerAdjustment.maxPriceDifferenceBelowHandbookPercent &&
|
||||
itemPrice >= this.ragfairConfig.dynamic.offerAdjustment.priceThreshholdRub
|
||||
)
|
||||
{
|
||||
//const itemDetails = this.itemHelper.getItem(itemTpl);
|
||||
//this.logger.debug(`item below handbook price ${itemDetails[1]._name} handbook: ${itemHandbookPrice} flea: ${itemPrice} ${priceDifferencePercent}%`);
|
||||
itemPrice = Math.round(itemHandbookPrice * this.ragfairConfig.dynamic.offerAdjustment.handbookPriceMultipier);
|
||||
// const itemDetails = this.itemHelper.getItem(itemTpl);
|
||||
// this.logger.debug(`item below handbook price ${itemDetails[1]._name} handbook: ${itemHandbookPrice} flea: ${itemPrice} ${priceDifferencePercent}%`);
|
||||
itemPrice = Math.round(
|
||||
itemHandbookPrice * this.ragfairConfig.dynamic.offerAdjustment.handbookPriceMultipier,
|
||||
);
|
||||
}
|
||||
|
||||
return itemPrice;
|
||||
@ -344,7 +355,9 @@ export class RagfairPriceService implements OnLoad
|
||||
}
|
||||
|
||||
// Get mods on current gun not in default preset
|
||||
const newOrReplacedModsInPresetVsDefault = items.filter(x => !presetResult.preset._items.some(y => y._tpl === x._tpl));
|
||||
const newOrReplacedModsInPresetVsDefault = items.filter((x) =>
|
||||
!presetResult.preset._items.some((y) => y._tpl === x._tpl)
|
||||
);
|
||||
|
||||
// Add up extra mods price
|
||||
let extraModsPrice = 0;
|
||||
@ -358,7 +371,9 @@ export class RagfairPriceService implements OnLoad
|
||||
if (newOrReplacedModsInPresetVsDefault.length >= 1)
|
||||
{
|
||||
// Add up cost of mods replaced
|
||||
const modsReplacedByNewMods = newOrReplacedModsInPresetVsDefault.filter(x => presetResult.preset._items.some(y => y.slotId === x.slotId));
|
||||
const modsReplacedByNewMods = newOrReplacedModsInPresetVsDefault.filter((x) =>
|
||||
presetResult.preset._items.some((y) => y.slotId === x.slotId)
|
||||
);
|
||||
|
||||
// Add up replaced mods price
|
||||
let replacedModsPrice = 0;
|
||||
@ -398,29 +413,37 @@ export class RagfairPriceService implements OnLoad
|
||||
* @param presets weapon presets to choose from
|
||||
* @returns Default preset object
|
||||
*/
|
||||
protected getWeaponPreset(presets: IPreset[], weapon: Item): {isDefault: boolean, preset: IPreset}
|
||||
protected getWeaponPreset(presets: IPreset[], weapon: Item): {isDefault: boolean; preset: IPreset;}
|
||||
{
|
||||
const defaultPreset = presets.find(x => x._encyclopedia);
|
||||
const defaultPreset = presets.find((x) => x._encyclopedia);
|
||||
if (defaultPreset)
|
||||
{
|
||||
return {
|
||||
isDefault: true,
|
||||
preset: defaultPreset
|
||||
preset: defaultPreset,
|
||||
};
|
||||
}
|
||||
|
||||
if (presets.length === 1)
|
||||
{
|
||||
this.logger.debug(`Item Id: ${weapon._tpl} has no default encyclopedia entry but only one preset (${presets[0]._name}), choosing preset (${presets[0]._name})`);
|
||||
this.logger.debug(
|
||||
`Item Id: ${weapon._tpl} has no default encyclopedia entry but only one preset (${
|
||||
presets[0]._name
|
||||
}), choosing preset (${presets[0]._name})`,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.logger.debug(`Item Id: ${weapon._tpl} has no default encyclopedia entry, choosing first preset (${presets[0]._name}) of ${presets.length}`);
|
||||
this.logger.debug(
|
||||
`Item Id: ${weapon._tpl} has no default encyclopedia entry, choosing first preset (${
|
||||
presets[0]._name
|
||||
}) of ${presets.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
isDefault: false,
|
||||
preset: presets[0]
|
||||
preset: presets[0],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,9 @@ export class RagfairRequiredItemsService
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("PaymentHelper") protected paymentHelper: PaymentHelper,
|
||||
@inject("RagfairOfferService") protected ragfairOfferService: RagfairOfferService
|
||||
@inject("RagfairOfferService") protected ragfairOfferService: RagfairOfferService,
|
||||
)
|
||||
{ }
|
||||
{}
|
||||
|
||||
public getRequiredItemsById(searchId: string): any
|
||||
{
|
||||
@ -50,5 +50,4 @@ export class RagfairRequiredItemsService
|
||||
|
||||
this.requiredItemsCache = requiredItems;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,9 @@ export class RagfairTaxService
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("RagfairPriceService") protected ragfairPriceService: RagfairPriceService,
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
)
|
||||
{ }
|
||||
{}
|
||||
|
||||
public storeClientOfferTaxValue(sessionId: string, offer: IStorePlayerOfferTaxAmountRequestData): void
|
||||
{
|
||||
@ -39,7 +39,13 @@ export class RagfairTaxService
|
||||
|
||||
// This method, along with calculateItemWorth, is trying to mirror the client-side code found in the method "CalculateTaxPrice".
|
||||
// It's structured to resemble the client-side code as closely as possible - avoid making any big structure changes if it's not necessary.
|
||||
public calculateTax(item: Item, pmcData: IPmcData, requirementsValue: number, offerItemCount: number, sellInOnePiece: boolean): number
|
||||
public calculateTax(
|
||||
item: Item,
|
||||
pmcData: IPmcData,
|
||||
requirementsValue: number,
|
||||
offerItemCount: number,
|
||||
sellInOnePiece: boolean,
|
||||
): number
|
||||
{
|
||||
if (!requirementsValue)
|
||||
{
|
||||
@ -56,7 +62,8 @@ export class RagfairTaxService
|
||||
const requirementsPrice = requirementsValue * (sellInOnePiece ? 1 : offerItemCount);
|
||||
|
||||
const itemTaxMult = this.databaseServer.getTables().globals.config.RagFair.communityItemTax / 100.0;
|
||||
const requirementTaxMult = this.databaseServer.getTables().globals.config.RagFair.communityRequirementTax / 100.0;
|
||||
const requirementTaxMult = this.databaseServer.getTables().globals.config.RagFair.communityRequirementTax /
|
||||
100.0;
|
||||
|
||||
let itemPriceMult = Math.log10(itemWorth / requirementsPrice);
|
||||
let requirementPriceMult = Math.log10(requirementsPrice / itemWorth);
|
||||
@ -73,12 +80,15 @@ export class RagfairTaxService
|
||||
itemPriceMult = 4 ** itemPriceMult;
|
||||
requirementPriceMult = 4 ** requirementPriceMult;
|
||||
|
||||
const hideoutFleaTaxDiscountBonus = pmcData.Bonuses.find(b => b.type === "RagfairCommission");
|
||||
const hideoutFleaTaxDiscountBonus = pmcData.Bonuses.find((b) => b.type === "RagfairCommission");
|
||||
const taxDiscountPercent = hideoutFleaTaxDiscountBonus ? Math.abs(hideoutFleaTaxDiscountBonus.value) : 0;
|
||||
|
||||
const tax = itemWorth * itemTaxMult * itemPriceMult + requirementsPrice * requirementTaxMult * requirementPriceMult;
|
||||
const tax = itemWorth * itemTaxMult * itemPriceMult +
|
||||
requirementsPrice * requirementTaxMult * requirementPriceMult;
|
||||
const discountedTax = tax * (1.0 - taxDiscountPercent / 100.0);
|
||||
const itemComissionMult = itemTemplate._props.RagFairCommissionModifier ? itemTemplate._props.RagFairCommissionModifier : 1;
|
||||
const itemComissionMult = itemTemplate._props.RagFairCommissionModifier ?
|
||||
itemTemplate._props.RagFairCommissionModifier :
|
||||
1;
|
||||
|
||||
if (item.upd.Buff)
|
||||
{
|
||||
@ -93,13 +103,19 @@ export class RagfairTaxService
|
||||
|
||||
// This method is trying to replicate the item worth calculation method found in the client code.
|
||||
// Any inefficiencies or style issues are intentional and should not be fixed, to preserve the client-side code mirroring.
|
||||
protected calculateItemWorth(item: Item, itemTemplate: ITemplateItem, itemCount: number, pmcData: IPmcData, isRootItem = true): number
|
||||
protected calculateItemWorth(
|
||||
item: Item,
|
||||
itemTemplate: ITemplateItem,
|
||||
itemCount: number,
|
||||
pmcData: IPmcData,
|
||||
isRootItem = true,
|
||||
): number
|
||||
{
|
||||
let worth = this.ragfairPriceService.getFleaPriceForItem(item._tpl);
|
||||
|
||||
// In client, all item slots are traversed and any items contained within have their values added
|
||||
if (isRootItem) // Since we get a flat list of all child items, we only want to recurse from parent item
|
||||
{
|
||||
if (isRootItem)
|
||||
{ // Since we get a flat list of all child items, we only want to recurse from parent item
|
||||
const itemChildren = this.itemHelper.findAndReturnChildrenAsItems(pmcData.Inventory.items, item._id);
|
||||
if (itemChildren.length > 1)
|
||||
{
|
||||
@ -110,7 +126,13 @@ export class RagfairTaxService
|
||||
continue;
|
||||
}
|
||||
|
||||
worth += this.calculateItemWorth(child, this.itemHelper.getItem(child._tpl)[1], child.upd.StackObjectsCount, pmcData, false);
|
||||
worth += this.calculateItemWorth(
|
||||
child,
|
||||
this.itemHelper.getItem(child._tpl)[1],
|
||||
child.upd.StackObjectsCount,
|
||||
pmcData,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -122,7 +144,8 @@ export class RagfairTaxService
|
||||
|
||||
if ("Key" in item.upd && itemTemplate._props.MaximumNumberOfUsage > 0)
|
||||
{
|
||||
worth = worth / itemTemplate._props.MaximumNumberOfUsage * (itemTemplate._props.MaximumNumberOfUsage - item.upd.Key.NumberOfUsages);
|
||||
worth = worth / itemTemplate._props.MaximumNumberOfUsage *
|
||||
(itemTemplate._props.MaximumNumberOfUsage - item.upd.Key.NumberOfUsages);
|
||||
}
|
||||
|
||||
if ("Resource" in item.upd && itemTemplate._props.MaxResource > 0)
|
||||
@ -148,9 +171,13 @@ export class RagfairTaxService
|
||||
if ("Repairable" in item.upd && <number>itemTemplate._props.armorClass > 0)
|
||||
{
|
||||
const num2 = 0.01 * (0.0 ** item.upd.Repairable.MaxDurability);
|
||||
worth = worth * ((item.upd.Repairable.MaxDurability / itemTemplate._props.Durability) - num2) - Math.floor(itemTemplate._props.RepairCost * (item.upd.Repairable.MaxDurability - item.upd.Repairable.Durability));
|
||||
worth = worth * ((item.upd.Repairable.MaxDurability / itemTemplate._props.Durability) - num2) -
|
||||
Math.floor(
|
||||
itemTemplate._props.RepairCost *
|
||||
(item.upd.Repairable.MaxDurability - item.upd.Repairable.Durability),
|
||||
);
|
||||
}
|
||||
|
||||
return worth * itemCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ export class RepairService
|
||||
@inject("PaymentService") protected paymentService: PaymentService,
|
||||
@inject("RepairHelper") protected repairHelper: RepairHelper,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.repairConfig = this.configServer.getConfig(ConfigTypes.REPAIR);
|
||||
@ -53,9 +53,14 @@ export class RepairService
|
||||
* @param traderId Trader being used to repair item
|
||||
* @returns RepairDetails object
|
||||
*/
|
||||
public repairItemByTrader(sessionID: string, pmcData: IPmcData, repairItemDetails: RepairItem, traderId: string): RepairDetails
|
||||
public repairItemByTrader(
|
||||
sessionID: string,
|
||||
pmcData: IPmcData,
|
||||
repairItemDetails: RepairItem,
|
||||
traderId: string,
|
||||
): RepairDetails
|
||||
{
|
||||
const itemToRepair = pmcData.Inventory.items.find(x => x._id === repairItemDetails._id);
|
||||
const itemToRepair = pmcData.Inventory.items.find((x) => x._id === repairItemDetails._id);
|
||||
if (itemToRepair === undefined)
|
||||
{
|
||||
throw new Error(`Item ${repairItemDetails._id} not found in profile inventory, unable to repair`);
|
||||
@ -64,12 +69,12 @@ export class RepairService
|
||||
const priceCoef = this.traderHelper.getLoyaltyLevel(traderId, pmcData).repair_price_coef;
|
||||
const traderRepairDetails = this.traderHelper.getTrader(traderId, sessionID).repair;
|
||||
const repairQualityMultiplier = traderRepairDetails.quality;
|
||||
const repairRate = (priceCoef <= 0)
|
||||
? 1
|
||||
: (priceCoef / 100 + 1);
|
||||
const repairRate = (priceCoef <= 0) ?
|
||||
1 :
|
||||
(priceCoef / 100 + 1);
|
||||
|
||||
const itemToRepairDetails = this.databaseServer.getTables().templates.items[itemToRepair._tpl];
|
||||
const repairItemIsArmor = (!!itemToRepairDetails._props.ArmorMaterial);
|
||||
const repairItemIsArmor = !!itemToRepairDetails._props.ArmorMaterial;
|
||||
|
||||
this.repairHelper.updateItemDurability(
|
||||
itemToRepair,
|
||||
@ -78,12 +83,14 @@ export class RepairService
|
||||
repairItemDetails.count,
|
||||
false,
|
||||
repairQualityMultiplier,
|
||||
repairQualityMultiplier !== 0 && this.repairConfig.applyRandomizeDurabilityLoss
|
||||
repairQualityMultiplier !== 0 && this.repairConfig.applyRandomizeDurabilityLoss,
|
||||
);
|
||||
|
||||
// get repair price
|
||||
const itemRepairCost = this.databaseServer.getTables().templates.items[itemToRepair._tpl]._props.RepairCost;
|
||||
const repairCost = Math.round((itemRepairCost * repairItemDetails.count * repairRate) * this.repairConfig.priceMultiplier);
|
||||
const repairCost = Math.round(
|
||||
(itemRepairCost * repairItemDetails.count * repairRate) * this.repairConfig.priceMultiplier,
|
||||
);
|
||||
|
||||
this.logger.debug(`item base repair cost: ${itemRepairCost}`, true);
|
||||
this.logger.debug(`price multipler: ${this.repairConfig.priceMultiplier}`, true);
|
||||
@ -94,18 +101,17 @@ export class RepairService
|
||||
repairedItem: itemToRepair,
|
||||
repairedItemIsArmor: repairItemIsArmor,
|
||||
repairAmount: repairItemDetails.count,
|
||||
repairedByKit: false
|
||||
repairedByKit: false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sessionID Session id
|
||||
* @param pmcData profile to take money from
|
||||
* @param repairedItemId Repaired item id
|
||||
* @param repairCost Cost to repair item in roubles
|
||||
* @param traderId Id of the trader who repaired the item / who is paid
|
||||
* @param output
|
||||
* @param output
|
||||
*/
|
||||
public payForRepair(
|
||||
sessionID: string,
|
||||
@ -113,15 +119,16 @@ export class RepairService
|
||||
repairedItemId: string,
|
||||
repairCost: number,
|
||||
traderId: string,
|
||||
output: IItemEventRouterResponse): void
|
||||
output: IItemEventRouterResponse,
|
||||
): void
|
||||
{
|
||||
const options: IProcessBuyTradeRequestData = {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
scheme_items: [
|
||||
{
|
||||
id: repairedItemId,
|
||||
count: Math.round(repairCost)
|
||||
}
|
||||
count: Math.round(repairCost),
|
||||
},
|
||||
],
|
||||
tid: traderId,
|
||||
Action: "",
|
||||
@ -130,7 +137,7 @@ export class RepairService
|
||||
item_id: "",
|
||||
count: 0,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
scheme_id: 0
|
||||
scheme_id: 0,
|
||||
};
|
||||
|
||||
this.paymentService.payMoney(pmcData, options, sessionID, output);
|
||||
@ -145,9 +152,13 @@ export class RepairService
|
||||
public addRepairSkillPoints(
|
||||
sessionId: string,
|
||||
repairDetails: RepairDetails,
|
||||
pmcData: IPmcData): void
|
||||
pmcData: IPmcData,
|
||||
): void
|
||||
{
|
||||
if (repairDetails.repairedByKit && this.itemHelper.isOfBaseclass(repairDetails.repairedItem._tpl, BaseClasses.WEAPON))
|
||||
if (
|
||||
repairDetails.repairedByKit &&
|
||||
this.itemHelper.isOfBaseclass(repairDetails.repairedItem._tpl, BaseClasses.WEAPON)
|
||||
)
|
||||
{
|
||||
const skillPoints = this.getWeaponRepairSkillPoints(repairDetails);
|
||||
|
||||
@ -155,22 +166,31 @@ export class RepairService
|
||||
}
|
||||
|
||||
// Handle kit repairs of armor
|
||||
if (repairDetails.repairedByKit && this.itemHelper.isOfBaseclasses(repairDetails.repairedItem._tpl, [BaseClasses.ARMOR, BaseClasses.VEST]))
|
||||
if (
|
||||
repairDetails.repairedByKit &&
|
||||
this.itemHelper.isOfBaseclasses(repairDetails.repairedItem._tpl, [BaseClasses.ARMOR, BaseClasses.VEST])
|
||||
)
|
||||
{
|
||||
const itemDetails = this.itemHelper.getItem(repairDetails.repairedItem._tpl);
|
||||
if (!itemDetails[0])
|
||||
{
|
||||
// No item found
|
||||
this.logger.error(this.localisationService.getText("repair-unable_to_find_item_in_db", repairDetails.repairedItem._tpl));
|
||||
this.logger.error(
|
||||
this.localisationService.getText(
|
||||
"repair-unable_to_find_item_in_db",
|
||||
repairDetails.repairedItem._tpl,
|
||||
),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const isHeavyArmor = itemDetails[1]._props.ArmorType === "Heavy";
|
||||
const vestSkillToLevel = (isHeavyArmor)
|
||||
? SkillTypes.HEAVY_VESTS
|
||||
: SkillTypes.LIGHT_VESTS;
|
||||
const pointsToAddToVestSkill = repairDetails.repairPoints * this.repairConfig.armorKitSkillPointGainPerRepairPointMultiplier;
|
||||
const vestSkillToLevel = isHeavyArmor ?
|
||||
SkillTypes.HEAVY_VESTS :
|
||||
SkillTypes.LIGHT_VESTS;
|
||||
const pointsToAddToVestSkill = repairDetails.repairPoints *
|
||||
this.repairConfig.armorKitSkillPointGainPerRepairPointMultiplier;
|
||||
|
||||
this.profileHelper.addSkillPointsToPlayer(pmcData, vestSkillToLevel, pointsToAddToVestSkill);
|
||||
}
|
||||
@ -179,17 +199,24 @@ export class RepairService
|
||||
let intellectGainedFromRepair: number;
|
||||
if (repairDetails.repairedByKit)
|
||||
{
|
||||
const intRepairMultiplier = (this.itemHelper.isOfBaseclass(repairDetails.repairedItem._tpl, BaseClasses.WEAPON))
|
||||
? this.repairConfig.repairKitIntellectGainMultiplier.weapon
|
||||
: this.repairConfig.repairKitIntellectGainMultiplier.armor;
|
||||
const intRepairMultiplier =
|
||||
(this.itemHelper.isOfBaseclass(repairDetails.repairedItem._tpl, BaseClasses.WEAPON)) ?
|
||||
this.repairConfig.repairKitIntellectGainMultiplier.weapon :
|
||||
this.repairConfig.repairKitIntellectGainMultiplier.armor;
|
||||
|
||||
// limit gain to a max value defined in config.maxIntellectGainPerRepair
|
||||
intellectGainedFromRepair = Math.min(repairDetails.repairPoints * intRepairMultiplier, this.repairConfig.maxIntellectGainPerRepair.kit);
|
||||
intellectGainedFromRepair = Math.min(
|
||||
repairDetails.repairPoints * intRepairMultiplier,
|
||||
this.repairConfig.maxIntellectGainPerRepair.kit,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Trader repair - Not as accurate as kit, needs data from live
|
||||
intellectGainedFromRepair = Math.min(repairDetails.repairAmount / 10, this.repairConfig.maxIntellectGainPerRepair.trader);
|
||||
intellectGainedFromRepair = Math.min(
|
||||
repairDetails.repairAmount / 10,
|
||||
this.repairConfig.maxIntellectGainPerRepair.trader,
|
||||
);
|
||||
}
|
||||
|
||||
this.profileHelper.addSkillPointsToPlayer(pmcData, SkillTypes.INTELLECT, intellectGainedFromRepair);
|
||||
@ -201,7 +228,8 @@ export class RepairService
|
||||
* @returns the number of skill points to reward the user
|
||||
*/
|
||||
protected getWeaponRepairSkillPoints(
|
||||
repairDetails: RepairDetails): number
|
||||
repairDetails: RepairDetails,
|
||||
): number
|
||||
{
|
||||
// This formula and associated configs is calculated based on 30 repairs done on live
|
||||
// The points always came out 2-aligned, which is why there's a divide/multiply by 2 with ceil calls
|
||||
@ -228,12 +256,11 @@ export class RepairService
|
||||
{
|
||||
skillPoints += this.repairConfig.weaponTreatment.critSuccessAmount;
|
||||
}
|
||||
|
||||
|
||||
return skillPoints;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sessionId Session id
|
||||
* @param pmcData Profile to update repaired item in
|
||||
* @param repairKits Array of Repair kits to use
|
||||
@ -246,10 +273,11 @@ export class RepairService
|
||||
pmcData: IPmcData,
|
||||
repairKits: RepairKitsInfo[],
|
||||
itemToRepairId: string,
|
||||
output: IItemEventRouterResponse): RepairDetails
|
||||
output: IItemEventRouterResponse,
|
||||
): RepairDetails
|
||||
{
|
||||
// Find item to repair in inventory
|
||||
const itemToRepair = pmcData.Inventory.items.find((x: { _id: string; }) => x._id === itemToRepairId);
|
||||
const itemToRepair = pmcData.Inventory.items.find((x: {_id: string;}) => x._id === itemToRepairId);
|
||||
if (itemToRepair === undefined)
|
||||
{
|
||||
throw new Error(`Item ${itemToRepairId} not found, unable to repair`);
|
||||
@ -257,9 +285,12 @@ export class RepairService
|
||||
|
||||
const itemsDb = this.databaseServer.getTables().templates.items;
|
||||
const itemToRepairDetails = itemsDb[itemToRepair._tpl];
|
||||
const repairItemIsArmor = (!!itemToRepairDetails._props.ArmorMaterial);
|
||||
const repairItemIsArmor = !!itemToRepairDetails._props.ArmorMaterial;
|
||||
const repairAmount = repairKits[0].count / this.getKitDivisor(itemToRepairDetails, repairItemIsArmor, pmcData);
|
||||
const shouldApplyDurabilityLoss = this.shouldRepairKitApplyDurabilityLoss(pmcData, this.repairConfig.applyRandomizeDurabilityLoss);
|
||||
const shouldApplyDurabilityLoss = this.shouldRepairKitApplyDurabilityLoss(
|
||||
pmcData,
|
||||
this.repairConfig.applyRandomizeDurabilityLoss,
|
||||
);
|
||||
|
||||
this.repairHelper.updateItemDurability(
|
||||
itemToRepair,
|
||||
@ -268,12 +299,13 @@ export class RepairService
|
||||
repairAmount,
|
||||
true,
|
||||
1,
|
||||
shouldApplyDurabilityLoss);
|
||||
shouldApplyDurabilityLoss,
|
||||
);
|
||||
|
||||
// Find and use repair kit defined in body
|
||||
for (const repairKit of repairKits)
|
||||
{
|
||||
const repairKitInInventory = pmcData.Inventory.items.find(x => x._id === repairKit._id);
|
||||
const repairKitInInventory = pmcData.Inventory.items.find((x) => x._id === repairKit._id);
|
||||
const repairKitDetails = itemsDb[repairKitInInventory._tpl];
|
||||
const repairKitReductionAmount = repairKit.count;
|
||||
|
||||
@ -290,7 +322,7 @@ export class RepairService
|
||||
repairedItem: itemToRepair,
|
||||
repairedItemIsArmor: repairItemIsArmor,
|
||||
repairAmount: repairAmount,
|
||||
repairedByKit: true
|
||||
repairedByKit: true,
|
||||
};
|
||||
}
|
||||
|
||||
@ -301,33 +333,34 @@ export class RepairService
|
||||
* @param pmcData Player profile
|
||||
* @returns Number to divide kit points by
|
||||
*/
|
||||
protected getKitDivisor(itemToRepairDetails: ITemplateItem, isArmor: boolean, pmcData: IPmcData): number
|
||||
protected getKitDivisor(itemToRepairDetails: ITemplateItem, isArmor: boolean, pmcData: IPmcData): number
|
||||
{
|
||||
const globals = this.databaseServer.getTables().globals;
|
||||
const globalRepairSettings = globals.config.RepairSettings;
|
||||
|
||||
const intellectRepairPointsPerLevel = globals.config.SkillsSettings.Intellect.RepairPointsCostReduction;
|
||||
const profileIntellectLevel = this.profileHelper.getSkillFromProfile(pmcData, SkillTypes.INTELLECT)?.Progress ?? 0;
|
||||
const profileIntellectLevel = this.profileHelper.getSkillFromProfile(pmcData, SkillTypes.INTELLECT)?.Progress ??
|
||||
0;
|
||||
const intellectPointReduction = intellectRepairPointsPerLevel * Math.trunc(profileIntellectLevel / 100);
|
||||
|
||||
if (isArmor)
|
||||
{
|
||||
const durabilityPointCostArmor = globalRepairSettings.durabilityPointCostArmor;
|
||||
const repairArmorBonus = this.getBonusMultiplierValue("RepairArmorBonus", pmcData);
|
||||
const armorBonus = (1.0 - (repairArmorBonus - 1.0) - intellectPointReduction);
|
||||
const armorBonus = 1.0 - (repairArmorBonus - 1.0) - intellectPointReduction;
|
||||
const materialType = itemToRepairDetails._props.ArmorMaterial ?? "";
|
||||
const armorMaterial = globals.config.ArmorMaterials[materialType] as IArmorType;
|
||||
const destructability = (1 + armorMaterial.Destructibility);
|
||||
const destructability = 1 + armorMaterial.Destructibility;
|
||||
const armorClass = parseInt(`${itemToRepairDetails._props.armorClass}`);
|
||||
const armorClassDivisor = globals.config.RepairSettings.armorClassDivisor;
|
||||
const armorClassMultiplier = (1.0 + armorClass / armorClassDivisor);
|
||||
const armorClassMultiplier = 1.0 + armorClass / armorClassDivisor;
|
||||
|
||||
return durabilityPointCostArmor * armorBonus * destructability * armorClassMultiplier;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
const repairWeaponBonus = this.getBonusMultiplierValue("RepairWeaponBonus", pmcData) - 1;
|
||||
const repairPointMultiplier = (1.0 - repairWeaponBonus - intellectPointReduction);
|
||||
const repairPointMultiplier = 1.0 - repairWeaponBonus - intellectPointReduction;
|
||||
const durabilityPointCostGuns = globals.config.RepairSettings.durabilityPointCostGuns;
|
||||
|
||||
return durabilityPointCostGuns * repairPointMultiplier;
|
||||
@ -342,11 +375,11 @@ export class RepairService
|
||||
*/
|
||||
protected getBonusMultiplierValue(skillBonusName: string, pmcData: IPmcData): number
|
||||
{
|
||||
const bonusesMatched = pmcData?.Bonuses?.filter(b => b.type === skillBonusName);
|
||||
const bonusesMatched = pmcData?.Bonuses?.filter((b) => b.type === skillBonusName);
|
||||
let value = 1;
|
||||
if (bonusesMatched != null)
|
||||
{
|
||||
const sumedPercentage = bonusesMatched.map(b => b.value).reduce((v1,v2) => v1 + v2, 0);
|
||||
const sumedPercentage = bonusesMatched.map((b) => b.value).reduce((v1, v2) => v1 + v2, 0);
|
||||
value = 1 + sumedPercentage / 100;
|
||||
}
|
||||
|
||||
@ -389,14 +422,14 @@ export class RepairService
|
||||
this.logger.debug(`Repair kit: ${repairKitInInventory._id} in inventory lacks upd object, adding`);
|
||||
repairKitInInventory.upd = {
|
||||
RepairKit: {
|
||||
Resource: maxRepairAmount
|
||||
}
|
||||
Resource: maxRepairAmount,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (!repairKitInInventory.upd.RepairKit?.Resource)
|
||||
{
|
||||
repairKitInInventory.upd.RepairKit = {
|
||||
Resource: maxRepairAmount
|
||||
Resource: maxRepairAmount,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -432,7 +465,7 @@ export class RepairService
|
||||
|
||||
/**
|
||||
* Add random buff to item
|
||||
* @param itemConfig weapon/armor config
|
||||
* @param itemConfig weapon/armor config
|
||||
* @param repairDetails Details for item to repair
|
||||
*/
|
||||
public addBuff(itemConfig: BonusSettings, item: Item): void
|
||||
@ -450,7 +483,10 @@ export class RepairService
|
||||
rarity: bonusRarity,
|
||||
buffType: bonusType,
|
||||
value: bonusValue,
|
||||
thresholdDurability: this.randomUtil.getPercentOfValue(bonusThresholdPercent, item.upd.Repairable.Durability)
|
||||
thresholdDurability: this.randomUtil.getPercentOfValue(
|
||||
bonusThresholdPercent,
|
||||
item.upd.Repairable.Durability,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@ -467,7 +503,9 @@ export class RepairService
|
||||
|
||||
const hasTemplate = this.itemHelper.getItem(repairDetails.repairedItem._tpl);
|
||||
if (!hasTemplate[0])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const template = hasTemplate[1];
|
||||
|
||||
const itemSkillType = this.getItemSkillType(template);
|
||||
@ -476,14 +514,22 @@ export class RepairService
|
||||
return false;
|
||||
}
|
||||
|
||||
const commonBuffMinChanceValue = globals.config.SkillsSettings[itemSkillType as string].BuffSettings.CommonBuffMinChanceValue;
|
||||
const commonBuffChanceLevelBonus = globals.config.SkillsSettings[itemSkillType as string].BuffSettings.CommonBuffChanceLevelBonus;
|
||||
const receivedDurabilityMaxPercent = globals.config.SkillsSettings[itemSkillType as string].BuffSettings.ReceivedDurabilityMaxPercent;
|
||||
const commonBuffMinChanceValue =
|
||||
globals.config.SkillsSettings[itemSkillType as string].BuffSettings.CommonBuffMinChanceValue;
|
||||
const commonBuffChanceLevelBonus =
|
||||
globals.config.SkillsSettings[itemSkillType as string].BuffSettings.CommonBuffChanceLevelBonus;
|
||||
const receivedDurabilityMaxPercent =
|
||||
globals.config.SkillsSettings[itemSkillType as string].BuffSettings.ReceivedDurabilityMaxPercent;
|
||||
|
||||
const skillLevel = Math.trunc((this.profileHelper.getSkillFromProfile(pmcData, itemSkillType)?.Progress ?? 0) / 100);
|
||||
const skillLevel = Math.trunc(
|
||||
(this.profileHelper.getSkillFromProfile(pmcData, itemSkillType)?.Progress ?? 0) / 100,
|
||||
);
|
||||
|
||||
const durabilityToRestorePercent = repairDetails.repairPoints / template._props.MaxDurability;
|
||||
const durabilityMultiplier = this.getDurabilityMultiplier(receivedDurabilityMaxPercent, durabilityToRestorePercent);
|
||||
const durabilityMultiplier = this.getDurabilityMultiplier(
|
||||
receivedDurabilityMaxPercent,
|
||||
durabilityToRestorePercent,
|
||||
);
|
||||
|
||||
const doBuff = commonBuffMinChanceValue + commonBuffChanceLevelBonus * skillLevel * durabilityMultiplier;
|
||||
|
||||
@ -494,13 +540,13 @@ export class RepairService
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Based on item, what underlying skill does this item use for buff settings
|
||||
* @param itemTemplate Item to check for skill
|
||||
* @returns Skill name
|
||||
*/
|
||||
protected getItemSkillType(itemTemplate: ITemplateItem): SkillTypes
|
||||
protected getItemSkillType(itemTemplate: ITemplateItem): SkillTypes
|
||||
{
|
||||
if (this.itemHelper.isOfBaseclass(itemTemplate._id, BaseClasses.ARMOR))
|
||||
{
|
||||
@ -533,7 +579,7 @@ export class RepairService
|
||||
*/
|
||||
protected getDurabilityMultiplier(receiveDurabilityMaxPercent: number, receiveDurabilityPercent: number): number
|
||||
{
|
||||
receiveDurabilityMaxPercent = ((receiveDurabilityMaxPercent > 0) ? receiveDurabilityMaxPercent : 0.01);
|
||||
receiveDurabilityMaxPercent = (receiveDurabilityMaxPercent > 0) ? receiveDurabilityMaxPercent : 0.01;
|
||||
const num = receiveDurabilityPercent / receiveDurabilityMaxPercent;
|
||||
if (num > 1)
|
||||
{
|
||||
@ -556,4 +602,4 @@ export class RepairDetails
|
||||
repairedItemIsArmor: boolean;
|
||||
repairAmount: number;
|
||||
repairedByKit: boolean;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ export class SeasonalEventService
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("BotHelper") protected botHelper: BotHelper,
|
||||
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.seasonalEventConfig = this.configServer.getConfig(ConfigTypes.SEASONAL_EVENT);
|
||||
@ -54,7 +54,7 @@ export class SeasonalEventService
|
||||
"5df8a77486f77412672a1e3f", // Violet bauble
|
||||
"5df8a72c86f77412640e2e83", // Silver bauble
|
||||
"5a43943586f77416ad2f06e2", // Ded moroz hat
|
||||
"5a43957686f7742a2c2f11b0" // Santa hat
|
||||
"5a43957686f7742a2c2f11b0", // Santa hat
|
||||
];
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ export class SeasonalEventService
|
||||
"6176a40f0b8c0312ac75a3d3", // Ghoul mask
|
||||
"62a5c2c98ec41a51b34739c0", // Hockey player mask "Captain"
|
||||
"62a5c333ec21e50cad3b5dc6", // Hockey player mask "Brawler"
|
||||
"62a5c41e8ec41a51b34739c3" // Hockey player mask "Quiet"
|
||||
"62a5c41e8ec41a51b34739c3", // Hockey player mask "Quiet"
|
||||
];
|
||||
}
|
||||
|
||||
@ -106,7 +106,7 @@ export class SeasonalEventService
|
||||
/**
|
||||
* Check if item id exists in christmas or halloween event arrays
|
||||
* @param itemTpl item tpl to check for
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
public itemIsSeasonalRelated(itemTpl: string): boolean
|
||||
{
|
||||
@ -236,11 +236,13 @@ export class SeasonalEventService
|
||||
const eventEndDate = new Date(currentDate.getFullYear(), event.endMonth - 1, event.endDay);
|
||||
|
||||
// Current date is between start/end dates
|
||||
if (currentDate >= eventStartDate
|
||||
&& currentDate <= eventEndDate)
|
||||
if (
|
||||
currentDate >= eventStartDate &&
|
||||
currentDate <= eventEndDate
|
||||
)
|
||||
{
|
||||
this.christmasEventActive = (SeasonalEventType[event.type] === SeasonalEventType.CHRISTMAS);
|
||||
this.halloweenEventActive = (SeasonalEventType[event.type] === SeasonalEventType.HALLOWEEN);
|
||||
this.christmasEventActive = SeasonalEventType[event.type] === SeasonalEventType.CHRISTMAS;
|
||||
this.halloweenEventActive = SeasonalEventType[event.type] === SeasonalEventType.HALLOWEEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -261,12 +263,18 @@ export class SeasonalEventService
|
||||
{
|
||||
if (!botInventory.equipment[equipmentSlotKey])
|
||||
{
|
||||
this.logger.warning(this.localisationService.getText("seasonal-missing_equipment_slot_on_bot", {equipmentSlot: equipmentSlotKey, botRole: botRole}));
|
||||
this.logger.warning(
|
||||
this.localisationService.getText("seasonal-missing_equipment_slot_on_bot", {
|
||||
equipmentSlot: equipmentSlotKey,
|
||||
botRole: botRole,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const equipment: Record<string, number> = botInventory.equipment[equipmentSlotKey];
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
botInventory.equipment[equipmentSlotKey] = Object.fromEntries(Object.entries(equipment).filter(([index]) => !christmasItems.includes(index)));
|
||||
botInventory.equipment[equipmentSlotKey] = Object.fromEntries(
|
||||
Object.entries(equipment).filter(([index]) => !christmasItems.includes(index)),
|
||||
);
|
||||
}
|
||||
|
||||
// Remove christmas related loot from loot containers
|
||||
@ -274,10 +282,17 @@ export class SeasonalEventService
|
||||
{
|
||||
if (!botInventory.items[lootContainerKey])
|
||||
{
|
||||
this.logger.warning(this.localisationService.getText("seasonal-missing_loot_container_slot_on_bot", {lootContainer: lootContainerKey, botRole: botRole}));
|
||||
this.logger.warning(
|
||||
this.localisationService.getText("seasonal-missing_loot_container_slot_on_bot", {
|
||||
lootContainer: lootContainerKey,
|
||||
botRole: botRole,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
botInventory.items[lootContainerKey] = botInventory.items[lootContainerKey].filter((x: string) => !christmasItems.includes(x));
|
||||
botInventory.items[lootContainerKey] = botInventory.items[lootContainerKey].filter((x: string) =>
|
||||
!christmasItems.includes(x)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,7 +307,7 @@ export class SeasonalEventService
|
||||
switch (eventType.toLowerCase())
|
||||
{
|
||||
case SeasonalEventType.HALLOWEEN.toLowerCase():
|
||||
globalConfig.EventType = globalConfig.EventType.filter(x => x !== "None");
|
||||
globalConfig.EventType = globalConfig.EventType.filter((x) => x !== "None");
|
||||
globalConfig.EventType.push("Halloween");
|
||||
globalConfig.EventType.push("HalloweenIllumination");
|
||||
globalConfig.Health.ProfileHealthSettings.DefaultStimulatorBuff = "Buffs_Halloween";
|
||||
@ -304,7 +319,7 @@ export class SeasonalEventService
|
||||
this.adjustTraderIcons(eventType);
|
||||
break;
|
||||
case SeasonalEventType.CHRISTMAS.toLowerCase():
|
||||
globalConfig.EventType = globalConfig.EventType.filter(x => x !== "None");
|
||||
globalConfig.EventType = globalConfig.EventType.filter((x) => x !== "None");
|
||||
globalConfig.EventType.push("Christmas");
|
||||
this.addEventGearToBots(eventType);
|
||||
this.addGifterBotToMaps();
|
||||
@ -352,10 +367,10 @@ export class SeasonalEventService
|
||||
}
|
||||
for (const boss of bossesToAdd)
|
||||
{
|
||||
const mapBosses: BossLocationSpawn[] = this.databaseServer.getTables().locations[mapKey].base.BossLocationSpawn;
|
||||
if (!mapBosses.find(x => x.BossName === boss.BossName))
|
||||
const mapBosses: BossLocationSpawn[] =
|
||||
this.databaseServer.getTables().locations[mapKey].base.BossLocationSpawn;
|
||||
if (!mapBosses.find((x) => x.BossName === boss.BossName))
|
||||
{
|
||||
|
||||
this.databaseServer.getTables().locations[mapKey].base.BossLocationSpawn.push(...bossesToAdd);
|
||||
}
|
||||
}
|
||||
@ -371,21 +386,31 @@ export class SeasonalEventService
|
||||
switch (eventType.toLowerCase())
|
||||
{
|
||||
case SeasonalEventType.HALLOWEEN.toLowerCase():
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/5a7c2ebb86f7746e324a06ab.png"] = "./assets/images/traders/halloween/5a7c2ebb86f7746e324a06ab.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/5ac3b86a86f77461491d1ad8.png"] = "./assets/images/traders/halloween/5ac3b86a86f77461491d1ad8.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/5c06531a86f7746319710e1b.png"] = "./assets/images/traders/halloween/5c06531a86f7746319710e1b.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/59b91ca086f77469a81232e4.png"] = "./assets/images/traders/halloween/59b91ca086f77469a81232e4.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/59b91cab86f77469aa5343ca.png"] = "./assets/images/traders/halloween/59b91cab86f77469aa5343ca.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/59b91cb486f77469a81232e5.png"] = "./assets/images/traders/halloween/59b91cb486f77469a81232e5.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/59b91cbd86f77469aa5343cb.png"] = "./assets/images/traders/halloween/59b91cbd86f77469aa5343cb.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/579dc571d53a0658a154fbec.png"] = "./assets/images/traders/halloween/579dc571d53a0658a154fbec.png";
|
||||
break;
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/5a7c2ebb86f7746e324a06ab.png"] =
|
||||
"./assets/images/traders/halloween/5a7c2ebb86f7746e324a06ab.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/5ac3b86a86f77461491d1ad8.png"] =
|
||||
"./assets/images/traders/halloween/5ac3b86a86f77461491d1ad8.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/5c06531a86f7746319710e1b.png"] =
|
||||
"./assets/images/traders/halloween/5c06531a86f7746319710e1b.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/59b91ca086f77469a81232e4.png"] =
|
||||
"./assets/images/traders/halloween/59b91ca086f77469a81232e4.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/59b91cab86f77469aa5343ca.png"] =
|
||||
"./assets/images/traders/halloween/59b91cab86f77469aa5343ca.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/59b91cb486f77469a81232e5.png"] =
|
||||
"./assets/images/traders/halloween/59b91cb486f77469a81232e5.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/59b91cbd86f77469aa5343cb.png"] =
|
||||
"./assets/images/traders/halloween/59b91cbd86f77469aa5343cb.png";
|
||||
this.httpConfig.serverImagePathOverride["./assets/images/traders/579dc571d53a0658a154fbec.png"] =
|
||||
"./assets/images/traders/halloween/579dc571d53a0658a154fbec.png";
|
||||
break;
|
||||
case SeasonalEventType.CHRISTMAS.toLowerCase():
|
||||
// TODO: find christmas trader icons
|
||||
break;
|
||||
}
|
||||
|
||||
this.databaseImporter.loadImages(`${this.databaseImporter.getSptDataPath()}images/`, ["traders"], ["/files/trader/avatar/"]);
|
||||
this.databaseImporter.loadImages(`${this.databaseImporter.getSptDataPath()}images/`, ["traders"], [
|
||||
"/files/trader/avatar/",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -413,7 +438,7 @@ export class SeasonalEventService
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Iterate over bots with changes to apply
|
||||
for (const bot in botGearChanges)
|
||||
{
|
||||
@ -429,7 +454,10 @@ export class SeasonalEventService
|
||||
for (const equipmentSlot in gearAmendments)
|
||||
{
|
||||
// Adjust slots spawn chance to be at least 75%
|
||||
botToUpdate.chances.equipment[equipmentSlot] = Math.max(botToUpdate.chances.equipment[equipmentSlot], 75);
|
||||
botToUpdate.chances.equipment[equipmentSlot] = Math.max(
|
||||
botToUpdate.chances.equipment[equipmentSlot],
|
||||
75,
|
||||
);
|
||||
|
||||
// Grab gear to add and loop over it
|
||||
const itemsToAdd = gearAmendments[equipmentSlot];
|
||||
@ -496,7 +524,7 @@ export class SeasonalEventService
|
||||
TriggerId: "",
|
||||
TriggerName: "",
|
||||
Delay: 0,
|
||||
RandomTimeSpawn: false
|
||||
RandomTimeSpawn: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -512,7 +540,6 @@ export class SeasonalEventService
|
||||
{
|
||||
this.giftService.sendGiftToPlayer(playerId, giftkey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -524,4 +551,4 @@ export class SeasonalEventService
|
||||
{
|
||||
return this.seasonalEventConfig.eventBotMapping[eventBotRole];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ITraderAssort } from "@spt-aki/models/eft/common/tables/ITrader";
|
||||
|
||||
export class TraderAssortService
|
||||
export class TraderAssortService
|
||||
{
|
||||
protected pristineTraderAssorts: Record<string, ITraderAssort> = {};
|
||||
|
||||
@ -18,4 +18,4 @@ export class TraderAssortService
|
||||
{
|
||||
this.pristineTraderAssorts[traderId] = assort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ export class TraderPurchasePersisterService
|
||||
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
||||
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.traderConfig = this.configServer.getConfig(ConfigTypes.TRADER);
|
||||
@ -95,23 +95,30 @@ export class TraderPurchasePersisterService
|
||||
|
||||
for (const purchaseKey in profile.traderPurchases[traderId])
|
||||
{
|
||||
const traderUpdateDetails = this.traderConfig.updateTime.find(x => x.traderId === traderId);
|
||||
const traderUpdateDetails = this.traderConfig.updateTime.find((x) => x.traderId === traderId);
|
||||
if (!traderUpdateDetails)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("trader-unable_to_delete_stale_purchases", {profileId: profile.info.id, traderId: traderId}));
|
||||
this.logger.error(
|
||||
this.localisationService.getText("trader-unable_to_delete_stale_purchases", {
|
||||
profileId: profile.info.id,
|
||||
traderId: traderId,
|
||||
}),
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const purchaseDetails = profile.traderPurchases[traderId][purchaseKey];
|
||||
const resetTimeForItem = purchaseDetails.purchaseTimestamp + traderUpdateDetails.seconds;
|
||||
if ((resetTimeForItem) < this.timeUtil.getTimestamp())
|
||||
if (resetTimeForItem < this.timeUtil.getTimestamp())
|
||||
{
|
||||
// Item was purchased far enough in past a trader refresh would have occured, remove purchase record from profile
|
||||
this.logger.debug(`Removed trader: ${traderId} purchase: ${purchaseKey} from profile: ${profile.info.id}`);
|
||||
this.logger.debug(
|
||||
`Removed trader: ${traderId} purchase: ${purchaseKey} from profile: ${profile.info.id}`,
|
||||
);
|
||||
delete profile.traderPurchases[traderId][purchaseKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
|
||||
import { ITemplateItem, Props } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
||||
import { CreateItemResult, LocaleDetails, NewItemDetails, NewItemFromCloneDetails } from "@spt-aki/models/spt/mod/NewItemDetails";
|
||||
import {
|
||||
CreateItemResult,
|
||||
LocaleDetails,
|
||||
NewItemDetails,
|
||||
NewItemFromCloneDetails,
|
||||
} from "@spt-aki/models/spt/mod/NewItemDetails";
|
||||
import { IDatabaseTables } from "@spt-aki/models/spt/server/IDatabaseTables";
|
||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||
@ -17,7 +22,7 @@ export class CustomItemService
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
)
|
||||
{
|
||||
this.tables = this.databaseServer.getTables();
|
||||
@ -115,9 +120,9 @@ export class CustomItemService
|
||||
*/
|
||||
protected getOrGenerateIdForItem(newId: string): string
|
||||
{
|
||||
return (newId === "")
|
||||
? this.hashUtil.generate()
|
||||
: newId;
|
||||
return (newId === "") ?
|
||||
this.hashUtil.generate() :
|
||||
newId;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,8 +161,8 @@ export class CustomItemService
|
||||
{
|
||||
Id: newItemId,
|
||||
ParentId: parentId,
|
||||
Price: priceRoubles
|
||||
}
|
||||
Price: priceRoubles,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -167,7 +172,7 @@ export class CustomItemService
|
||||
* e.g.
|
||||
* en[0]
|
||||
* fr[1]
|
||||
*
|
||||
*
|
||||
* No jp provided, so english will be used as a substitute
|
||||
* @param localeDetails key is language, value are the new locale details
|
||||
* @param newItemId id of the item being created
|
||||
@ -200,4 +205,4 @@ export class CustomItemService
|
||||
{
|
||||
this.tables.templates.prices[newItemId] = fleaPriceRoubles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,14 @@ export class DynamicRouterMod extends DynamicRouter
|
||||
{
|
||||
public constructor(
|
||||
routes: RouteAction[],
|
||||
private topLevelRoute: string
|
||||
)
|
||||
private topLevelRoute: string,
|
||||
)
|
||||
{
|
||||
super(routes);
|
||||
}
|
||||
|
||||
public override getTopLevelRoute(): string
|
||||
public override getTopLevelRoute(): string
|
||||
{
|
||||
return this.topLevelRoute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,17 +4,17 @@ import { RouteAction } from "@spt-aki/di/Router";
|
||||
import { DynamicRouterMod } from "@spt-aki/services/mod/dynamicRouter/DynamicRouterMod";
|
||||
|
||||
@injectable()
|
||||
export class DynamicRouterModService
|
||||
export class DynamicRouterModService
|
||||
{
|
||||
constructor(private container: DependencyContainer)
|
||||
constructor(private container: DependencyContainer)
|
||||
{}
|
||||
public registerDynamicRouter(
|
||||
name: string,
|
||||
routes: RouteAction[],
|
||||
topLevelRoute: string
|
||||
): void
|
||||
topLevelRoute: string,
|
||||
): void
|
||||
{
|
||||
this.container.register(name, {useValue: new DynamicRouterMod(routes, topLevelRoute)});
|
||||
this.container.registerType("DynamicRoutes", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,18 +6,18 @@ export class HttpListenerMod implements IHttpListener
|
||||
{
|
||||
public constructor(
|
||||
private canHandleOverride: (sessionId: string, req: IncomingMessage) => boolean,
|
||||
private handleOverride: (sessionId: string, req: IncomingMessage, resp: ServerResponse) => void
|
||||
)
|
||||
private handleOverride: (sessionId: string, req: IncomingMessage, resp: ServerResponse) => void,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public canHandle(sessionId: string, req: IncomingMessage): boolean
|
||||
public canHandle(sessionId: string, req: IncomingMessage): boolean
|
||||
{
|
||||
return this.canHandleOverride(sessionId, req);
|
||||
}
|
||||
|
||||
public handle(sessionId: string, req: IncomingMessage, resp: ServerResponse): void
|
||||
public handle(sessionId: string, req: IncomingMessage, resp: ServerResponse): void
|
||||
{
|
||||
this.handleOverride(sessionId, req, resp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,18 +5,20 @@ import { IHttpListener } from "@spt-aki/servers/http/IHttpListener";
|
||||
import { HttpListenerMod } from "@spt-aki/services/mod/httpListener/HttpListenerMod";
|
||||
|
||||
@injectable()
|
||||
export class HttpListenerModService
|
||||
export class HttpListenerModService
|
||||
{
|
||||
constructor(protected container: DependencyContainer)
|
||||
constructor(protected container: DependencyContainer)
|
||||
{}
|
||||
|
||||
|
||||
public registerHttpListener(
|
||||
name: string,
|
||||
canHandleOverride: (sessionId: string, req: IncomingMessage) => boolean,
|
||||
handleOverride: (sessionId: string, req: IncomingMessage, resp: ServerResponse) => void
|
||||
): void
|
||||
handleOverride: (sessionId: string, req: IncomingMessage, resp: ServerResponse) => void,
|
||||
): void
|
||||
{
|
||||
this.container.register<IHttpListener>(name, {useValue: new HttpListenerMod(canHandleOverride, handleOverride)});
|
||||
this.container.register<IHttpListener>(name, {
|
||||
useValue: new HttpListenerMod(canHandleOverride, handleOverride),
|
||||
});
|
||||
this.container.registerType("HttpListener", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,4 +16,4 @@ export class ImageRouteService
|
||||
{
|
||||
return (this.routes[urlKey] !== undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,10 @@ export class OnLoadMod implements OnLoad
|
||||
{
|
||||
public constructor(
|
||||
private onLoadOverride: () => void,
|
||||
private getRouteOverride: () => string
|
||||
)
|
||||
private getRouteOverride: () => string,
|
||||
)
|
||||
{
|
||||
//super();
|
||||
// super();
|
||||
}
|
||||
|
||||
public async onLoad(): Promise<void>
|
||||
@ -15,8 +15,8 @@ export class OnLoadMod implements OnLoad
|
||||
return this.onLoadOverride();
|
||||
}
|
||||
|
||||
public getRoute(): string
|
||||
public getRoute(): string
|
||||
{
|
||||
return this.getRouteOverride();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,18 +3,18 @@ import { DependencyContainer, injectable } from "tsyringe";
|
||||
import { OnLoadMod } from "@spt-aki/services/mod/onLoad/OnLoadMod";
|
||||
|
||||
@injectable()
|
||||
export class OnLoadModService
|
||||
export class OnLoadModService
|
||||
{
|
||||
constructor(protected container: DependencyContainer)
|
||||
constructor(protected container: DependencyContainer)
|
||||
{}
|
||||
|
||||
|
||||
public registerOnLoad(
|
||||
name: string,
|
||||
onLoad: () => void,
|
||||
getRoute: () => string
|
||||
): void
|
||||
getRoute: () => string,
|
||||
): void
|
||||
{
|
||||
this.container.register(name, {useValue: new OnLoadMod(onLoad, getRoute)});
|
||||
this.container.registerType("OnLoad", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
||||
export class OnUpdateMod implements OnUpdate
|
||||
{
|
||||
public constructor(
|
||||
private onUpdateOverride: ( timeSinceLastRun: number ) => boolean,
|
||||
private getRouteOverride: () => string
|
||||
)
|
||||
private onUpdateOverride: (timeSinceLastRun: number) => boolean,
|
||||
private getRouteOverride: () => string,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
@ -14,8 +14,8 @@ export class OnUpdateMod implements OnUpdate
|
||||
return this.onUpdateOverride(timeSinceLastRun);
|
||||
}
|
||||
|
||||
public getRoute(): string
|
||||
public getRoute(): string
|
||||
{
|
||||
return this.getRouteOverride();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,18 +3,18 @@ import { DependencyContainer, injectable } from "tsyringe";
|
||||
import { OnUpdateMod } from "@spt-aki/services/mod/onUpdate/OnUpdateMod";
|
||||
|
||||
@injectable()
|
||||
export class OnUpdateModService
|
||||
export class OnUpdateModService
|
||||
{
|
||||
constructor(protected container: DependencyContainer)
|
||||
constructor(protected container: DependencyContainer)
|
||||
{}
|
||||
|
||||
|
||||
public registerOnUpdate(
|
||||
name: string,
|
||||
onUpdate: (timeSinceLastRun: number) => boolean,
|
||||
getRoute: () => string
|
||||
): void
|
||||
getRoute: () => string,
|
||||
): void
|
||||
{
|
||||
this.container.register(name, {useValue: new OnUpdateMod(onUpdate, getRoute)});
|
||||
this.container.registerType("OnUpdate", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,14 @@ export class StaticRouterMod extends StaticRouter
|
||||
{
|
||||
public constructor(
|
||||
routes: RouteAction[],
|
||||
private topLevelRoute: string
|
||||
)
|
||||
private topLevelRoute: string,
|
||||
)
|
||||
{
|
||||
super(routes);
|
||||
}
|
||||
|
||||
public override getTopLevelRoute(): string
|
||||
public override getTopLevelRoute(): string
|
||||
{
|
||||
return this.topLevelRoute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,17 +4,17 @@ import { RouteAction } from "@spt-aki/di/Router";
|
||||
import { StaticRouterMod } from "@spt-aki/services/mod/staticRouter/StaticRouterMod";
|
||||
|
||||
@injectable()
|
||||
export class StaticRouterModService
|
||||
export class StaticRouterModService
|
||||
{
|
||||
constructor(protected container: DependencyContainer)
|
||||
constructor(protected container: DependencyContainer)
|
||||
{}
|
||||
public registerStaticRouter(
|
||||
name: string,
|
||||
routes: RouteAction[],
|
||||
topLevelRoute: string
|
||||
): void
|
||||
topLevelRoute: string,
|
||||
): void
|
||||
{
|
||||
this.container.register(name, {useValue: new StaticRouterMod(routes, topLevelRoute)});
|
||||
this.container.registerType("StaticRoutes", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user