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