Merge branch 'master' of https://dev.sp-tarkov.com/SPT-AKI/Server into 3.8.0
This commit is contained in:
commit
0a85f6f319
@ -1460,6 +1460,8 @@
|
|||||||
"minKills": 1,
|
"minKills": 1,
|
||||||
"maxBossKills": 1,
|
"maxBossKills": 1,
|
||||||
"minBossKills": 1,
|
"minBossKills": 1,
|
||||||
|
"maxPmcKills": 2,
|
||||||
|
"minPmcKills": 1,
|
||||||
"weaponRequirementProb": 0,
|
"weaponRequirementProb": 0,
|
||||||
"weaponCategoryRequirementProb": 0.3,
|
"weaponCategoryRequirementProb": 0.3,
|
||||||
"weaponCategoryRequirements": [{
|
"weaponCategoryRequirements": [{
|
||||||
@ -1573,6 +1575,8 @@
|
|||||||
"minKills": 3,
|
"minKills": 3,
|
||||||
"maxBossKills": 3,
|
"maxBossKills": 3,
|
||||||
"minBossKills": 1,
|
"minBossKills": 1,
|
||||||
|
"maxPmcKills": 5,
|
||||||
|
"minPmcKills": 2,
|
||||||
"weaponRequirementProb": 0,
|
"weaponRequirementProb": 0,
|
||||||
"weaponCategoryRequirementProb": 0.3,
|
"weaponCategoryRequirementProb": 0.3,
|
||||||
"weaponCategoryRequirements": [{
|
"weaponCategoryRequirements": [{
|
||||||
|
@ -11,6 +11,13 @@
|
|||||||
"kit": 0.6,
|
"kit": 0.6,
|
||||||
"trader": 0.6
|
"trader": 0.6
|
||||||
},
|
},
|
||||||
|
"weaponTreatment": {
|
||||||
|
"critSuccessChance": 0.10,
|
||||||
|
"critSuccessAmount": 4,
|
||||||
|
"critFailureChance": 0.10,
|
||||||
|
"critFailureAmount": 4,
|
||||||
|
"pointGainMultiplier": 0.6
|
||||||
|
},
|
||||||
"repairKit": {
|
"repairKit": {
|
||||||
"armor": {
|
"armor": {
|
||||||
"rarityWeight": {
|
"rarityWeight": {
|
||||||
|
@ -2073,7 +2073,6 @@
|
|||||||
"Оливье",
|
"Оливье",
|
||||||
"Подружка",
|
"Подружка",
|
||||||
"Шмыга",
|
"Шмыга",
|
||||||
"Шнур",
|
|
||||||
"Сырок",
|
"Сырок",
|
||||||
"Улётный",
|
"Улётный",
|
||||||
"Васёк",
|
"Васёк",
|
||||||
|
@ -28,7 +28,6 @@ export class BotController
|
|||||||
{
|
{
|
||||||
protected botConfig: IBotConfig;
|
protected botConfig: IBotConfig;
|
||||||
protected pmcConfig: IPmcConfig;
|
protected pmcConfig: IPmcConfig;
|
||||||
public static readonly pmcTypeLabel = "PMC";
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@inject("WinstonLogger") protected logger: ILogger,
|
@inject("WinstonLogger") protected logger: ILogger,
|
||||||
|
@ -244,11 +244,11 @@ export class RepeatableQuestGenerator
|
|||||||
{
|
{
|
||||||
// get all boss spawn information
|
// get all boss spawn information
|
||||||
const bossSpawns = Object.values(this.databaseServer.getTables().locations).filter(x => "base" in x && "Id" in x.base).map(
|
const bossSpawns = Object.values(this.databaseServer.getTables().locations).filter(x => "base" in x && "Id" in x.base).map(
|
||||||
(x) => ({ "Id": x.base.Id, "BossSpawn": x.base.BossLocationSpawn })
|
(x) => ({ Id: x.base.Id, BossSpawn: x.base.BossLocationSpawn })
|
||||||
);
|
);
|
||||||
// filter for the current boss to spawn on map
|
// filter for the current boss to spawn on map
|
||||||
const thisBossSpawns = bossSpawns.map(
|
const thisBossSpawns = bossSpawns.map(
|
||||||
(x) => ({ "Id": x.Id, "BossSpawn": x.BossSpawn.filter(e => e.BossName === targetKey) })
|
(x) => ({ Id: x.Id, BossSpawn: x.BossSpawn.filter(e => e.BossName === targetKey) })
|
||||||
).filter(x => x.BossSpawn.length > 0);
|
).filter(x => x.BossSpawn.length > 0);
|
||||||
// remove blacklisted locations
|
// remove blacklisted locations
|
||||||
const allowedSpawns = thisBossSpawns.filter(x => !eliminationConfig.distLocationBlacklist.includes(x.Id));
|
const allowedSpawns = thisBossSpawns.filter(x => !eliminationConfig.distLocationBlacklist.includes(x.Id));
|
||||||
@ -315,9 +315,11 @@ export class RepeatableQuestGenerator
|
|||||||
const availableForFinishCondition = quest.conditions.AvailableForFinish[0];
|
const availableForFinishCondition = quest.conditions.AvailableForFinish[0];
|
||||||
availableForFinishCondition._props.counter.id = this.objectId.generate();
|
availableForFinishCondition._props.counter.id = this.objectId.generate();
|
||||||
availableForFinishCondition._props.counter.conditions = [];
|
availableForFinishCondition._props.counter.conditions = [];
|
||||||
|
|
||||||
|
// Only add specific location condition if specific map selected
|
||||||
if (locationKey !== "any")
|
if (locationKey !== "any")
|
||||||
{
|
{
|
||||||
availableForFinishCondition._props.counter.conditions.push(this.generateEliminationLocation(locationsConfig[locationKey], allowedWeapon, allowedWeaponsCategory));
|
availableForFinishCondition._props.counter.conditions.push(this.generateEliminationLocation(locationsConfig[locationKey]));
|
||||||
}
|
}
|
||||||
availableForFinishCondition._props.counter.conditions.push(this.generateEliminationCondition(targetKey, bodyPartsToClient, distance, allowedWeapon, allowedWeaponsCategory));
|
availableForFinishCondition._props.counter.conditions.push(this.generateEliminationCondition(targetKey, bodyPartsToClient, distance, allowedWeapon, allowedWeaponsCategory));
|
||||||
availableForFinishCondition._props.value = desiredKillCount;
|
availableForFinishCondition._props.value = desiredKillCount;
|
||||||
@ -356,9 +358,9 @@ export class RepeatableQuestGenerator
|
|||||||
* This is a helper method for GenerateEliminationQuest to create a location condition.
|
* This is a helper method for GenerateEliminationQuest to create a location condition.
|
||||||
*
|
*
|
||||||
* @param {string} location the location on which to fulfill the elimination quest
|
* @param {string} location the location on which to fulfill the elimination quest
|
||||||
* @returns {object} object of "Elimination"-location-subcondition
|
* @returns {IEliminationCondition} object of "Elimination"-location-subcondition
|
||||||
*/
|
*/
|
||||||
protected generateEliminationLocation(location: string[], allowedWeapon: string, allowedWeaponCategory: string): IEliminationCondition
|
protected generateEliminationLocation(location: string[]): IEliminationCondition
|
||||||
{
|
{
|
||||||
const propsObject: IEliminationCondition = {
|
const propsObject: IEliminationCondition = {
|
||||||
_props: {
|
_props: {
|
||||||
@ -369,29 +371,19 @@ export class RepeatableQuestGenerator
|
|||||||
_parent: "Location"
|
_parent: "Location"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (allowedWeapon)
|
|
||||||
{
|
|
||||||
propsObject._props.weapon = [allowedWeapon];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allowedWeaponCategory)
|
|
||||||
{
|
|
||||||
propsObject._props.weaponCategories = [allowedWeaponCategory];
|
|
||||||
}
|
|
||||||
|
|
||||||
return propsObject;
|
return propsObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A repeatable quest, besides some more or less static components, exists of reward and condition (see assets/database/templates/repeatableQuests.json)
|
* Create kill condition for an elimination quest
|
||||||
* This is a helper method for GenerateEliminationQuest to create a kill condition.
|
* @param target Bot type target of elimination quest e.g. "AnyPmc", "Savage"
|
||||||
*
|
* @param targetedBodyParts Body parts player must hit
|
||||||
* @param {string} target array of target npcs e.g. "AnyPmc", "Savage"
|
* @param distance Distance from which to kill (currently only >= supported
|
||||||
* @param {array} bodyParts array of body parts with which to kill e.g. ["stomach", "thorax"]
|
* @param allowedWeapon What weapon must be used - undefined = any
|
||||||
* @param {number} distance distance from which to kill (currently only >= supported)
|
* @param allowedWeaponCategory What category of weapon must be used - undefined = any
|
||||||
* @returns {object} object of "Elimination"-kill-subcondition
|
* @returns IEliminationCondition object
|
||||||
*/
|
*/
|
||||||
protected generateEliminationCondition(target: string, bodyPart: string[], distance: number, allowedWeapon: string, allowedWeaponCategory: string): IEliminationCondition
|
protected generateEliminationCondition(target: string, targetedBodyParts: string[], distance: number, allowedWeapon: string, allowedWeaponCategory: string): IEliminationCondition
|
||||||
{
|
{
|
||||||
const killConditionProps: IKillConditionProps = {
|
const killConditionProps: IKillConditionProps = {
|
||||||
target: target,
|
target: target,
|
||||||
@ -406,9 +398,10 @@ export class RepeatableQuestGenerator
|
|||||||
killConditionProps.savageRole = [target];
|
killConditionProps.savageRole = [target];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bodyPart)
|
// Has specific body part hit condition
|
||||||
|
if (targetedBodyParts)
|
||||||
{
|
{
|
||||||
killConditionProps.bodyPart = bodyPart;
|
killConditionProps.bodyPart = targetedBodyParts;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dont allow distance + melee requirement
|
// Dont allow distance + melee requirement
|
||||||
@ -420,11 +413,13 @@ export class RepeatableQuestGenerator
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Has specific weapon requirement
|
||||||
if (allowedWeapon)
|
if (allowedWeapon)
|
||||||
{
|
{
|
||||||
killConditionProps.weapon = [allowedWeapon];
|
killConditionProps.weapon = [allowedWeapon];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Has specific weapon category requirement
|
||||||
if (allowedWeaponCategory?.length > 0)
|
if (allowedWeaponCategory?.length > 0)
|
||||||
{
|
{
|
||||||
killConditionProps.weaponCategories = [allowedWeaponCategory];
|
killConditionProps.weaponCategories = [allowedWeaponCategory];
|
||||||
@ -781,7 +776,7 @@ export class RepeatableQuestGenerator
|
|||||||
const rewardSpreadConfig = repeatableConfig.rewardScaling.rewardSpread;
|
const rewardSpreadConfig = repeatableConfig.rewardScaling.rewardSpread;
|
||||||
const reputationConfig = repeatableConfig.rewardScaling.reputation;
|
const reputationConfig = repeatableConfig.rewardScaling.reputation;
|
||||||
|
|
||||||
if (isNaN(difficulty))
|
if (Number.isNaN(difficulty))
|
||||||
{
|
{
|
||||||
difficulty = 1;
|
difficulty = 1;
|
||||||
this.logger.warning(this.localisationService.getText("repeatable-difficulty_was_nan"));
|
this.logger.warning(this.localisationService.getText("repeatable-difficulty_was_nan"));
|
||||||
|
@ -8,7 +8,7 @@ import { QuestConditionHelper } from "@spt-aki/helpers/QuestConditionHelper";
|
|||||||
import { RagfairServerHelper } from "@spt-aki/helpers/RagfairServerHelper";
|
import { RagfairServerHelper } from "@spt-aki/helpers/RagfairServerHelper";
|
||||||
import { TraderHelper } from "@spt-aki/helpers/TraderHelper";
|
import { TraderHelper } from "@spt-aki/helpers/TraderHelper";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
import { IQuestStatus } from "@spt-aki/models/eft/common/tables/IBotBase";
|
import { Common, IQuestStatus } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||||
import { AvailableForConditions, AvailableForProps, IQuest, Reward } from "@spt-aki/models/eft/common/tables/IQuest";
|
import { AvailableForConditions, AvailableForProps, IQuest, Reward } from "@spt-aki/models/eft/common/tables/IQuest";
|
||||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||||
@ -135,7 +135,7 @@ export class QuestHelper
|
|||||||
* @param skillName Name of skill to increase skill points of
|
* @param skillName Name of skill to increase skill points of
|
||||||
* @param progressAmount Amount of skill points to add to skill
|
* @param progressAmount Amount of skill points to add to skill
|
||||||
*/
|
*/
|
||||||
public rewardSkillPoints(sessionID: string, pmcData: IPmcData, skillName: string, progressAmount: number): void
|
public rewardSkillPoints(sessionID: string, pmcData: IPmcData, skillName: string, progressAmount: number, scaleToSkillLevel: boolean = false): void
|
||||||
{
|
{
|
||||||
const indexOfSkillToUpdate = pmcData.Skills.Common.findIndex(s => s.Id === skillName);
|
const indexOfSkillToUpdate = pmcData.Skills.Common.findIndex(s => s.Id === skillName);
|
||||||
if (indexOfSkillToUpdate === -1)
|
if (indexOfSkillToUpdate === -1)
|
||||||
@ -153,10 +153,66 @@ export class QuestHelper
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tarkov has special handling of skills under level 9 to scale them to the lower XP requirement
|
||||||
|
if (scaleToSkillLevel)
|
||||||
|
{
|
||||||
|
progressAmount = this.adjustSkillExpForLowLevels(profileSkill, progressAmount);
|
||||||
|
}
|
||||||
|
|
||||||
profileSkill.Progress += progressAmount;
|
profileSkill.Progress += progressAmount;
|
||||||
profileSkill.LastAccess = this.timeUtil.getTimestamp();
|
profileSkill.LastAccess = this.timeUtil.getTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjust skill experience for low skill levels, mimicing the official client
|
||||||
|
* @param profileSkill the skill experience is being added to
|
||||||
|
* @param progressAmount the amount of experience being added to the skill
|
||||||
|
* @returns the adjusted skill progress gain
|
||||||
|
*/
|
||||||
|
public adjustSkillExpForLowLevels(profileSkill: Common, progressAmount: number): number
|
||||||
|
{
|
||||||
|
let currentLevel = Math.floor(profileSkill.Progress / 100);
|
||||||
|
|
||||||
|
// Only run this if the current level is under 9
|
||||||
|
if (currentLevel >= 9)
|
||||||
|
{
|
||||||
|
return progressAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This calculates how much progress we have in the skill's starting level
|
||||||
|
let startingLevelProgress = (profileSkill.Progress % 100) * ((currentLevel + 1) / 10);
|
||||||
|
|
||||||
|
// The code below assumes a 1/10th progress skill amount
|
||||||
|
let remainingProgress = progressAmount / 10;
|
||||||
|
|
||||||
|
// We have to do this loop to handle edge cases where the provided XP bumps your level up
|
||||||
|
// See "CalculateExpOnFirstLevels" in client for original logic
|
||||||
|
let adjustedSkillProgress = 0;
|
||||||
|
while (remainingProgress > 0 && currentLevel < 9)
|
||||||
|
{
|
||||||
|
// Calculate how much progress to add, limiting it to the current level max progress
|
||||||
|
const currentLevelRemainingProgress = ((currentLevel + 1) * 10) - startingLevelProgress;
|
||||||
|
this.logger.debug(`currentLevelRemainingProgress: ${currentLevelRemainingProgress}`);
|
||||||
|
const progressToAdd = Math.min(remainingProgress, currentLevelRemainingProgress);
|
||||||
|
const adjustedProgressToAdd = (10 / (currentLevel + 1)) * progressToAdd;
|
||||||
|
this.logger.debug(`Progress To Add: ${progressToAdd} Adjusted for level: ${adjustedProgressToAdd}`);
|
||||||
|
|
||||||
|
// Add the progress amount adjusted by level
|
||||||
|
adjustedSkillProgress += adjustedProgressToAdd;
|
||||||
|
remainingProgress -= progressToAdd;
|
||||||
|
startingLevelProgress = 0;
|
||||||
|
currentLevel++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's any remaining progress, add it. This handles if you go from level 8 -> 9
|
||||||
|
if (remainingProgress > 0)
|
||||||
|
{
|
||||||
|
adjustedSkillProgress += remainingProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
return adjustedSkillProgress;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get quest name by quest id
|
* Get quest name by quest id
|
||||||
* @param questId id to get
|
* @param questId id to get
|
||||||
|
@ -12,6 +12,7 @@ export interface IRepairConfig extends IBaseConfig
|
|||||||
repairKitIntellectGainMultiplier: IIntellectGainValues
|
repairKitIntellectGainMultiplier: IIntellectGainValues
|
||||||
//** How much INT can be given to player per repair action */
|
//** How much INT can be given to player per repair action */
|
||||||
maxIntellectGainPerRepair: IMaxIntellectGainValues;
|
maxIntellectGainPerRepair: IMaxIntellectGainValues;
|
||||||
|
weaponTreatment: IWeaponTreatmentRepairValues;
|
||||||
repairKit: RepairKit
|
repairKit: RepairKit
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,6 +28,18 @@ export interface IMaxIntellectGainValues
|
|||||||
trader: number
|
trader: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IWeaponTreatmentRepairValues
|
||||||
|
{
|
||||||
|
/** The chance to gain more weapon maintenance skill */
|
||||||
|
critSuccessChance: number
|
||||||
|
critSuccessAmount: number
|
||||||
|
/** The chance to gain less weapon maintenance skill */
|
||||||
|
critFailureChance: number
|
||||||
|
critFailureAmount: number
|
||||||
|
/** The multiplier used for calculating weapon maintenance XP */
|
||||||
|
pointGainMultiplier: number
|
||||||
|
}
|
||||||
|
|
||||||
export interface RepairKit
|
export interface RepairKit
|
||||||
{
|
{
|
||||||
armor: BonusSettings
|
armor: BonusSettings
|
||||||
|
@ -147,10 +147,11 @@ export class RepairService
|
|||||||
repairDetails: RepairDetails,
|
repairDetails: RepairDetails,
|
||||||
pmcData: IPmcData): void
|
pmcData: IPmcData): void
|
||||||
{
|
{
|
||||||
if (this.itemHelper.isOfBaseclass(repairDetails.repairedItem._tpl, BaseClasses.WEAPON))
|
if (repairDetails.repairedByKit && this.itemHelper.isOfBaseclass(repairDetails.repairedItem._tpl, BaseClasses.WEAPON))
|
||||||
{
|
{
|
||||||
const progress = this.databaseServer.getTables().globals.config.SkillsSettings.WeaponTreatment.SkillPointsPerRepair;
|
const skillPoints = this.getWeaponRepairSkillPoints(repairDetails);
|
||||||
this.questHelper.rewardSkillPoints(sessionId, pmcData, "WeaponTreatment", progress);
|
|
||||||
|
this.questHelper.rewardSkillPoints(sessionId, pmcData, "WeaponTreatment", skillPoints, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle kit repairs of armor
|
// Handle kit repairs of armor
|
||||||
@ -167,7 +168,7 @@ export class RepairService
|
|||||||
|
|
||||||
const isHeavyArmor = itemDetails[1]._props.ArmorType === "Heavy";
|
const isHeavyArmor = itemDetails[1]._props.ArmorType === "Heavy";
|
||||||
const vestSkillToLevel = (isHeavyArmor) ? "HeavyVests" : "LightVests";
|
const vestSkillToLevel = (isHeavyArmor) ? "HeavyVests" : "LightVests";
|
||||||
const pointsToAddToVestSkill = repairDetails.repairAmount * this.repairConfig.armorKitSkillPointGainPerRepairPointMultiplier;
|
const pointsToAddToVestSkill = repairDetails.repairPoints * this.repairConfig.armorKitSkillPointGainPerRepairPointMultiplier;
|
||||||
|
|
||||||
this.questHelper.rewardSkillPoints(sessionId, pmcData, vestSkillToLevel, pointsToAddToVestSkill);
|
this.questHelper.rewardSkillPoints(sessionId, pmcData, vestSkillToLevel, pointsToAddToVestSkill);
|
||||||
}
|
}
|
||||||
@ -181,7 +182,7 @@ export class RepairService
|
|||||||
: this.repairConfig.repairKitIntellectGainMultiplier.armor;
|
: this.repairConfig.repairKitIntellectGainMultiplier.armor;
|
||||||
|
|
||||||
// limit gain to a max value defined in config.maxIntellectGainPerRepair
|
// limit gain to a max value defined in config.maxIntellectGainPerRepair
|
||||||
intellectGainedFromRepair = Math.min(repairDetails.repairAmount * intRepairMultiplier, this.repairConfig.maxIntellectGainPerRepair.kit);
|
intellectGainedFromRepair = Math.min(repairDetails.repairPoints * intRepairMultiplier, this.repairConfig.maxIntellectGainPerRepair.kit);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -192,6 +193,43 @@ export class RepairService
|
|||||||
this.questHelper.rewardSkillPoints(sessionId, pmcData, SkillTypes.INTELLECT, intellectGainedFromRepair);
|
this.questHelper.rewardSkillPoints(sessionId, pmcData, SkillTypes.INTELLECT, intellectGainedFromRepair);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an appromixation of the amount of skill points live would return for the given repairDetails
|
||||||
|
* @param repairDetails the repair details to calculate skill points for
|
||||||
|
* @returns the number of skill points to reward the user
|
||||||
|
*/
|
||||||
|
protected getWeaponRepairSkillPoints(
|
||||||
|
repairDetails: RepairDetails): number
|
||||||
|
{
|
||||||
|
// This formula and associated configs is calculated based on 30 repairs done on live
|
||||||
|
// The points always came out 2-aligned, which is why there's a divide/multiply by 2 with ceil calls
|
||||||
|
const gainMult = this.repairConfig.weaponTreatment.pointGainMultiplier;
|
||||||
|
|
||||||
|
// First we get a baseline based on our repair amount, and gain multiplier with a bit of rounding
|
||||||
|
const step1 = Math.ceil(repairDetails.repairAmount / 2) * gainMult;
|
||||||
|
|
||||||
|
// Then we have to get the next even number
|
||||||
|
const step2 = Math.ceil(step1 / 2) * 2;
|
||||||
|
|
||||||
|
// Then multiply by 2 again to hopefully get to what live would give us
|
||||||
|
let skillPoints = step2 * 2;
|
||||||
|
|
||||||
|
// You can both crit fail and succeed at the same time, for fun (Balances out to 0 with default settings)
|
||||||
|
// Add a random chance to crit-fail
|
||||||
|
if (Math.random() <= this.repairConfig.weaponTreatment.critFailureChance)
|
||||||
|
{
|
||||||
|
skillPoints -= this.repairConfig.weaponTreatment.critFailureAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a random chance to crit-succeed
|
||||||
|
if (Math.random() <= this.repairConfig.weaponTreatment.critSuccessChance)
|
||||||
|
{
|
||||||
|
skillPoints += this.repairConfig.weaponTreatment.critSuccessAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return skillPoints;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param sessionId Session id
|
* @param sessionId Session id
|
||||||
@ -218,12 +256,13 @@ export class RepairService
|
|||||||
const itemsDb = this.databaseServer.getTables().templates.items;
|
const itemsDb = this.databaseServer.getTables().templates.items;
|
||||||
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);
|
||||||
|
|
||||||
this.repairHelper.updateItemDurability(
|
this.repairHelper.updateItemDurability(
|
||||||
itemToRepair,
|
itemToRepair,
|
||||||
itemToRepairDetails,
|
itemToRepairDetails,
|
||||||
repairItemIsArmor,
|
repairItemIsArmor,
|
||||||
repairKits[0].count / this.getKitDivisor(itemToRepairDetails, repairItemIsArmor, pmcData),
|
repairAmount,
|
||||||
true,
|
true,
|
||||||
1,
|
1,
|
||||||
this.repairConfig.applyRandomizeDurabilityLoss);
|
this.repairConfig.applyRandomizeDurabilityLoss);
|
||||||
@ -244,9 +283,10 @@ export class RepairService
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
repairPoints: repairKits[0].count,
|
||||||
repairedItem: itemToRepair,
|
repairedItem: itemToRepair,
|
||||||
repairedItemIsArmor: repairItemIsArmor,
|
repairedItemIsArmor: repairItemIsArmor,
|
||||||
repairAmount: repairKits[0].count,
|
repairAmount: repairAmount,
|
||||||
repairedByKit: true
|
repairedByKit: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -414,7 +454,7 @@ export class RepairService
|
|||||||
|
|
||||||
const skillLevel = Math.trunc((pmcData?.Skills?.Common?.find(s => s.Id === itemSkillType)?.Progress ?? 0) / 100);
|
const skillLevel = Math.trunc((pmcData?.Skills?.Common?.find(s => s.Id === itemSkillType)?.Progress ?? 0) / 100);
|
||||||
|
|
||||||
const durabilityToRestorePercent = repairDetails.repairAmount / template._props.MaxDurability;
|
const durabilityToRestorePercent = repairDetails.repairPoints / template._props.MaxDurability;
|
||||||
const durabilityMultiplier = this.getDurabilityMultiplier(receivedDurabilityMaxPercent, durabilityToRestorePercent);
|
const durabilityMultiplier = this.getDurabilityMultiplier(receivedDurabilityMaxPercent, durabilityToRestorePercent);
|
||||||
|
|
||||||
const doBuff = commonBuffMinChanceValue + commonBuffChanceLevelBonus * skillLevel * durabilityMultiplier;
|
const doBuff = commonBuffMinChanceValue + commonBuffChanceLevelBonus * skillLevel * durabilityMultiplier;
|
||||||
@ -483,6 +523,7 @@ export class RepairService
|
|||||||
export class RepairDetails
|
export class RepairDetails
|
||||||
{
|
{
|
||||||
repairCost?: number;
|
repairCost?: number;
|
||||||
|
repairPoints?: number;
|
||||||
repairedItem: Item;
|
repairedItem: Item;
|
||||||
repairedItemIsArmor: boolean;
|
repairedItemIsArmor: boolean;
|
||||||
repairAmount: number;
|
repairAmount: number;
|
||||||
|
@ -3,7 +3,13 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"emitDeclarationOnly": true,
|
"emitDeclarationOnly": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"declarationDir": "./types"
|
"declarationDir": "./types",
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@spt-aki/*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"./types/**/*"
|
"./types/**/*"
|
||||||
|
Loading…
Reference in New Issue
Block a user