Merge branch 'master' of https://dev.sp-tarkov.com/SPT-AKI/Server into 3.8.0
This commit is contained in:
commit
123df5c595
@ -18,6 +18,7 @@ import { IServerDetails } from "@spt-aki/models/eft/game/IServerDetails";
|
|||||||
import { IAkiProfile } from "@spt-aki/models/eft/profile/IAkiProfile";
|
import { IAkiProfile } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||||
import { AccountTypes } from "@spt-aki/models/enums/AccountTypes";
|
import { AccountTypes } from "@spt-aki/models/enums/AccountTypes";
|
||||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
|
import { SkillTypes } from "@spt-aki/models/enums/SkillTypes";
|
||||||
import { Traders } from "@spt-aki/models/enums/Traders";
|
import { Traders } from "@spt-aki/models/enums/Traders";
|
||||||
import { ICoreConfig } from "@spt-aki/models/spt/config/ICoreConfig";
|
import { ICoreConfig } from "@spt-aki/models/spt/config/ICoreConfig";
|
||||||
import { IHttpConfig } from "@spt-aki/models/spt/config/IHttpConfig";
|
import { IHttpConfig } from "@spt-aki/models/spt/config/IHttpConfig";
|
||||||
@ -118,6 +119,8 @@ export class GameController
|
|||||||
|
|
||||||
this.adjustLooseLootSpawnProbabilities();
|
this.adjustLooseLootSpawnProbabilities();
|
||||||
|
|
||||||
|
this.checkTraderRepairValuesExist();
|
||||||
|
|
||||||
// repeatableQuests are stored by in profile.Quests due to the responses of the client (e.g. Quests in offraidData)
|
// repeatableQuests are stored by in profile.Quests due to the responses of the client (e.g. Quests in offraidData)
|
||||||
// Since we don't want to clutter the Quests list, we need to remove all completed (failed / successful) repeatable quests.
|
// Since we don't want to clutter the Quests list, we need to remove all completed (failed / successful) repeatable quests.
|
||||||
// We also have to remove the Counters from the repeatableQuests
|
// We also have to remove the Counters from the repeatableQuests
|
||||||
@ -227,6 +230,30 @@ export class GameController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Out of date/incorrectly made trader mods forget this data
|
||||||
|
*/
|
||||||
|
protected checkTraderRepairValuesExist(): void
|
||||||
|
{
|
||||||
|
for (const traderKey in this.databaseServer.getTables().traders)
|
||||||
|
{
|
||||||
|
const trader = this.databaseServer.getTables().traders[traderKey];
|
||||||
|
if (!trader?.base?.repair)
|
||||||
|
{
|
||||||
|
this.logger.warning(`Trader ${trader.base._id} ${trader.base.name} is missing a repair object, adding in default values`);
|
||||||
|
trader.base.repair = this.jsonUtil.clone(this.databaseServer.getTables().traders.ragfair.base.repair);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trader?.base?.repair?.quality)
|
||||||
|
{
|
||||||
|
this.logger.warning(`Trader ${trader.base._id} ${trader.base.name} is missing a repair quality value, adding in default value`);
|
||||||
|
trader.base.repair.quality = this.jsonUtil.clone(this.databaseServer.getTables().traders.ragfair.base.repair.quality);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected addCustomLooseLootPositions(): void
|
protected addCustomLooseLootPositions(): void
|
||||||
{
|
{
|
||||||
const looseLootPositionsToAdd = this.lootConfig.looseLoot;
|
const looseLootPositionsToAdd = this.lootConfig.looseLoot;
|
||||||
@ -472,7 +499,7 @@ export class GameController
|
|||||||
*/
|
*/
|
||||||
protected warnOnActiveBotReloadSkill(pmcProfile: IPmcData): void
|
protected warnOnActiveBotReloadSkill(pmcProfile: IPmcData): void
|
||||||
{
|
{
|
||||||
const botReloadSkill = pmcProfile.Skills.Common.find(x => x.Id === "BotReload");
|
const botReloadSkill = this.profileHelper.getSkillFromProfile(pmcProfile, SkillTypes.BOT_RELOAD);
|
||||||
if (botReloadSkill?.Progress > 0)
|
if (botReloadSkill?.Progress > 0)
|
||||||
{
|
{
|
||||||
this.logger.warning(this.localisationService.getText("server_start_player_active_botreload_skill"));
|
this.logger.warning(this.localisationService.getText("server_start_player_active_botreload_skill"));
|
||||||
|
@ -3,7 +3,7 @@ import { inject, injectable } from "tsyringe";
|
|||||||
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
|
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
import { Common, HideoutArea, IHideoutImprovement, Production, Productive } from "@spt-aki/models/eft/common/tables/IBotBase";
|
import { HideoutArea, IHideoutImprovement, Production, Productive } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||||
import { Upd } from "@spt-aki/models/eft/common/tables/IItem";
|
import { Upd } from "@spt-aki/models/eft/common/tables/IItem";
|
||||||
import { StageBonus } from "@spt-aki/models/eft/hideout/IHideoutArea";
|
import { StageBonus } from "@spt-aki/models/eft/hideout/IHideoutArea";
|
||||||
import { IHideoutContinuousProductionStartRequestData } from "@spt-aki/models/eft/hideout/IHideoutContinuousProductionStartRequestData";
|
import { IHideoutContinuousProductionStartRequestData } from "@spt-aki/models/eft/hideout/IHideoutContinuousProductionStartRequestData";
|
||||||
@ -800,16 +800,6 @@ export class HideoutHelper
|
|||||||
return productionSlots + (hasManagementSkillSlots ? managementSlotsCount : 0);
|
return productionSlots + (hasManagementSkillSlots ? managementSlotsCount : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Does profile have elite hideout management skill
|
|
||||||
* @param pmcData Profile to look at
|
|
||||||
* @returns True if profile has skill
|
|
||||||
*/
|
|
||||||
protected hasEliteHideoutManagementSkill(pmcData: IPmcData): boolean
|
|
||||||
{
|
|
||||||
return this.getHideoutManagementSkill(pmcData)?.Progress >= 5100; // level 51+
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a count of bitcoins player miner can hold
|
* Get a count of bitcoins player miner can hold
|
||||||
*/
|
*/
|
||||||
@ -818,16 +808,6 @@ export class HideoutHelper
|
|||||||
return this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.BitcoinFarm.Container;
|
return this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.BitcoinFarm.Container;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the hideout management skill from player profile
|
|
||||||
* @param pmcData Profile to look at
|
|
||||||
* @returns Hideout management skill object
|
|
||||||
*/
|
|
||||||
protected getHideoutManagementSkill(pmcData: IPmcData): Common
|
|
||||||
{
|
|
||||||
return pmcData.Skills.Common.find(x => x.Id === SkillTypes.HIDEOUT_MANAGEMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HideoutManagement skill gives a consumption bonus the higher the level
|
* HideoutManagement skill gives a consumption bonus the higher the level
|
||||||
* 0.5% per level per 1-51, (25.5% at max)
|
* 0.5% per level per 1-51, (25.5% at max)
|
||||||
@ -836,7 +816,7 @@ export class HideoutHelper
|
|||||||
*/
|
*/
|
||||||
protected getHideoutManagementConsumptionBonus(pmcData: IPmcData): number
|
protected getHideoutManagementConsumptionBonus(pmcData: IPmcData): number
|
||||||
{
|
{
|
||||||
const hideoutManagementSkill = this.getHideoutManagementSkill(pmcData);
|
const hideoutManagementSkill = this.profileHelper.getSkillFromProfile(pmcData, SkillTypes.HIDEOUT_MANAGEMENT);
|
||||||
if (!hideoutManagementSkill)
|
if (!hideoutManagementSkill)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2,7 +2,7 @@ import { inject, injectable } from "tsyringe";
|
|||||||
|
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
import { CounterKeyValue, Stats } from "@spt-aki/models/eft/common/tables/IBotBase";
|
import { Common, CounterKeyValue, Stats } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||||
import { IAkiProfile } from "@spt-aki/models/eft/profile/IAkiProfile";
|
import { IAkiProfile } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||||
import { IValidateNicknameRequestData } from "@spt-aki/models/eft/profile/IValidateNicknameRequestData";
|
import { IValidateNicknameRequestData } from "@spt-aki/models/eft/profile/IValidateNicknameRequestData";
|
||||||
import { SkillTypes } from "@spt-aki/models/enums/SkillTypes";
|
import { SkillTypes } from "@spt-aki/models/enums/SkillTypes";
|
||||||
@ -423,4 +423,16 @@ export class ProfileHelper
|
|||||||
profileSkill.Progress += pointsToAdd;
|
profileSkill.Progress += pointsToAdd;
|
||||||
profileSkill.LastAccess = this.timeUtil.getTimestamp();
|
profileSkill.LastAccess = this.timeUtil.getTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getSkillFromProfile(pmcData: IPmcData, skill: SkillTypes): Common
|
||||||
|
{
|
||||||
|
const skillToReturn = pmcData.Skills.Common.find(x => x.Id === skill);
|
||||||
|
if (!skillToReturn)
|
||||||
|
{
|
||||||
|
this.logger.warning(`Profile ${pmcData.sessionId} does not have a skill named: ${skill}`);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return skillToReturn;
|
||||||
|
}
|
||||||
}
|
}
|
@ -818,7 +818,7 @@ export class QuestHelper
|
|||||||
let moneyRewardBonus = moneyRewardBonuses.reduce((acc, cur) => acc + cur.value, 0);
|
let moneyRewardBonus = moneyRewardBonuses.reduce((acc, cur) => acc + cur.value, 0);
|
||||||
|
|
||||||
// Apply hideout management bonus to money reward (up to 51% bonus)
|
// Apply hideout management bonus to money reward (up to 51% bonus)
|
||||||
const hideoutManagementSkill = pmcData.Skills.Common.find(x => x.Id === 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)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
export enum SkillTypes
|
export enum SkillTypes
|
||||||
{
|
{
|
||||||
|
BOT_RELOAD = "BotReload",
|
||||||
|
BOT_SOUND = "BotSound",
|
||||||
HIDEOUT_MANAGEMENT = "HideoutManagement",
|
HIDEOUT_MANAGEMENT = "HideoutManagement",
|
||||||
CRAFTING = "Crafting",
|
CRAFTING = "Crafting",
|
||||||
METABOLISM = "Metabolism",
|
METABOLISM = "Metabolism",
|
||||||
@ -20,6 +22,7 @@ export enum SkillTypes
|
|||||||
ATTENTION = "Attention",
|
ATTENTION = "Attention",
|
||||||
CHARISMA = "Charisma",
|
CHARISMA = "Charisma",
|
||||||
MEMORY = "Memory",
|
MEMORY = "Memory",
|
||||||
|
MELEE = "Melee",
|
||||||
SURGERY = "Surgery",
|
SURGERY = "Surgery",
|
||||||
AIM_DRILLS = "AimDrills",
|
AIM_DRILLS = "AimDrills",
|
||||||
TROUBLESHOOTING = "TroubleShooting",
|
TROUBLESHOOTING = "TroubleShooting",
|
||||||
@ -32,6 +35,7 @@ export enum SkillTypes
|
|||||||
NIGHT_OPS = "NightOps",
|
NIGHT_OPS = "NightOps",
|
||||||
SILENT_OPS = "SilentOps",
|
SILENT_OPS = "SilentOps",
|
||||||
LOCKPICKING = "Lockpicking",
|
LOCKPICKING = "Lockpicking",
|
||||||
|
/** Also called Weapon Maintenance*/
|
||||||
WEAPON_TREATMENT = "WeaponTreatment",
|
WEAPON_TREATMENT = "WeaponTreatment",
|
||||||
MAG_DRILLS = "MagDrills",
|
MAG_DRILLS = "MagDrills",
|
||||||
FREE_TRADING = "Freetrading",
|
FREE_TRADING = "Freetrading",
|
||||||
|
@ -259,6 +259,7 @@ export class RepairService
|
|||||||
const itemToRepairDetails = itemsDb[itemToRepair._tpl];
|
const itemToRepairDetails = itemsDb[itemToRepair._tpl];
|
||||||
const repairItemIsArmor = (!!itemToRepairDetails._props.ArmorMaterial);
|
const repairItemIsArmor = (!!itemToRepairDetails._props.ArmorMaterial);
|
||||||
const repairAmount = repairKits[0].count / this.getKitDivisor(itemToRepairDetails, repairItemIsArmor, pmcData);
|
const repairAmount = repairKits[0].count / this.getKitDivisor(itemToRepairDetails, repairItemIsArmor, pmcData);
|
||||||
|
const shouldApplyDurabilityLoss = this.shouldRepairKitApplyDurabilityLoss(pmcData, this.repairConfig.applyRandomizeDurabilityLoss);
|
||||||
|
|
||||||
this.repairHelper.updateItemDurability(
|
this.repairHelper.updateItemDurability(
|
||||||
itemToRepair,
|
itemToRepair,
|
||||||
@ -267,7 +268,7 @@ export class RepairService
|
|||||||
repairAmount,
|
repairAmount,
|
||||||
true,
|
true,
|
||||||
1,
|
1,
|
||||||
this.repairConfig.applyRandomizeDurabilityLoss);
|
shouldApplyDurabilityLoss);
|
||||||
|
|
||||||
// Find and use repair kit defined in body
|
// Find and use repair kit defined in body
|
||||||
for (const repairKit of repairKits)
|
for (const repairKit of repairKits)
|
||||||
@ -306,7 +307,7 @@ export class RepairService
|
|||||||
const globalRepairSettings = globals.config.RepairSettings;
|
const globalRepairSettings = globals.config.RepairSettings;
|
||||||
|
|
||||||
const intellectRepairPointsPerLevel = globals.config.SkillsSettings.Intellect.RepairPointsCostReduction;
|
const intellectRepairPointsPerLevel = globals.config.SkillsSettings.Intellect.RepairPointsCostReduction;
|
||||||
const profileIntellectLevel = pmcData.Skills?.Common?.find(s => s.Id === SkillTypes.INTELLECT)?.Progress ?? 0;
|
const profileIntellectLevel = this.profileHelper.getSkillFromProfile(pmcData, SkillTypes.INTELLECT)?.Progress ?? 0;
|
||||||
const intellectPointReduction = intellectRepairPointsPerLevel * Math.trunc(profileIntellectLevel / 100);
|
const intellectPointReduction = intellectRepairPointsPerLevel * Math.trunc(profileIntellectLevel / 100);
|
||||||
|
|
||||||
if (isArmor)
|
if (isArmor)
|
||||||
@ -352,6 +353,29 @@ export class RepairService
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should a repair kit apply total durability loss on repair
|
||||||
|
* @param pmcData Player profile
|
||||||
|
* @param applyRandomizeDurabilityLoss Value from repair config
|
||||||
|
* @returns True if loss should be applied
|
||||||
|
*/
|
||||||
|
protected shouldRepairKitApplyDurabilityLoss(pmcData: IPmcData, applyRandomizeDurabilityLoss: boolean): boolean
|
||||||
|
{
|
||||||
|
let shouldApplyDurabilityLoss = applyRandomizeDurabilityLoss;
|
||||||
|
if (shouldApplyDurabilityLoss)
|
||||||
|
{
|
||||||
|
// Random loss not disabled via config, perform charisma check
|
||||||
|
const hasEliteCharisma = this.profileHelper.hasEliteSkillLevel(SkillTypes.CHARISMA, pmcData);
|
||||||
|
if (hasEliteCharisma)
|
||||||
|
{
|
||||||
|
// 50/50 chance of loss being ignored at elite level
|
||||||
|
shouldApplyDurabilityLoss = this.randomUtil.getChance100(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shouldApplyDurabilityLoss;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update repair kits Resource object if it doesn't exist
|
* Update repair kits Resource object if it doesn't exist
|
||||||
* @param repairKitDetails Repair kit details from db
|
* @param repairKitDetails Repair kit details from db
|
||||||
@ -448,13 +472,15 @@ export class RepairService
|
|||||||
|
|
||||||
const itemSkillType = this.getItemSkillType(template);
|
const itemSkillType = this.getItemSkillType(template);
|
||||||
if (!itemSkillType)
|
if (!itemSkillType)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const commonBuffMinChanceValue = globals.config.SkillsSettings[itemSkillType].BuffSettings.CommonBuffMinChanceValue;
|
const commonBuffMinChanceValue = globals.config.SkillsSettings[itemSkillType as string].BuffSettings.CommonBuffMinChanceValue;
|
||||||
const commonBuffChanceLevelBonus = globals.config.SkillsSettings[itemSkillType].BuffSettings.CommonBuffChanceLevelBonus;
|
const commonBuffChanceLevelBonus = globals.config.SkillsSettings[itemSkillType as string].BuffSettings.CommonBuffChanceLevelBonus;
|
||||||
const receivedDurabilityMaxPercent = globals.config.SkillsSettings[itemSkillType].BuffSettings.ReceivedDurabilityMaxPercent;
|
const receivedDurabilityMaxPercent = globals.config.SkillsSettings[itemSkillType as string].BuffSettings.ReceivedDurabilityMaxPercent;
|
||||||
|
|
||||||
const skillLevel = Math.trunc((pmcData?.Skills?.Common?.find(s => s.Id === itemSkillType)?.Progress ?? 0) / 100);
|
const skillLevel = Math.trunc((this.profileHelper.getSkillFromProfile(pmcData, itemSkillType)?.Progress ?? 0) / 100);
|
||||||
|
|
||||||
const durabilityToRestorePercent = repairDetails.repairPoints / template._props.MaxDurability;
|
const durabilityToRestorePercent = repairDetails.repairPoints / template._props.MaxDurability;
|
||||||
const durabilityMultiplier = this.getDurabilityMultiplier(receivedDurabilityMaxPercent, durabilityToRestorePercent);
|
const durabilityMultiplier = this.getDurabilityMultiplier(receivedDurabilityMaxPercent, durabilityToRestorePercent);
|
||||||
@ -474,26 +500,26 @@ export class RepairService
|
|||||||
* @param itemTemplate Item to check for skill
|
* @param itemTemplate Item to check for skill
|
||||||
* @returns Skill name
|
* @returns Skill name
|
||||||
*/
|
*/
|
||||||
protected getItemSkillType(itemTemplate: ITemplateItem): string
|
protected getItemSkillType(itemTemplate: ITemplateItem): SkillTypes
|
||||||
{
|
{
|
||||||
if (this.itemHelper.isOfBaseclass(itemTemplate._id, BaseClasses.ARMOR))
|
if (this.itemHelper.isOfBaseclass(itemTemplate._id, BaseClasses.ARMOR))
|
||||||
{
|
{
|
||||||
if (itemTemplate._props.ArmorType === "Light")
|
if (itemTemplate._props.ArmorType === "Light")
|
||||||
{
|
{
|
||||||
return "LightVests";
|
return SkillTypes.LIGHT_VESTS;
|
||||||
}
|
}
|
||||||
else if (itemTemplate._props.ArmorType === "Heavy")
|
else if (itemTemplate._props.ArmorType === "Heavy")
|
||||||
{
|
{
|
||||||
return "HeavyVests";
|
return SkillTypes.HEAVY_VESTS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (this.itemHelper.isOfBaseclass(itemTemplate._id, BaseClasses.WEAPON))
|
else if (this.itemHelper.isOfBaseclass(itemTemplate._id, BaseClasses.WEAPON))
|
||||||
{
|
{
|
||||||
return "WeaponTreatment";
|
return SkillTypes.WEAPON_TREATMENT;
|
||||||
}
|
}
|
||||||
else if (this.itemHelper.isOfBaseclass(itemTemplate._id, BaseClasses.KNIFE))
|
else if (this.itemHelper.isOfBaseclass(itemTemplate._id, BaseClasses.KNIFE))
|
||||||
{
|
{
|
||||||
return "Melee";
|
return SkillTypes.MELEE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
|
Loading…
Reference in New Issue
Block a user