Add crafting skill into water filter drain rate calculation

Added small optimisation to only process water filters if a water filter is installed
Added crafting skill bonus to water filter craft time calculation

Various variable/comment renames for clarity
This commit is contained in:
Dev 2024-03-30 11:32:14 +00:00
parent 50f580858d
commit a66b6644a1
3 changed files with 116 additions and 35 deletions

View File

@ -678,7 +678,13 @@ export class HideoutController
// - normal recipe: Production time value is stored in attribute "productionTime" with small "p"
// - scav case recipe: Production time value is stored in attribute "ProductionTime" with capital "P"
const adjustedCraftTime = recipe.ProductionTime
- this.hideoutHelper.getCraftingSkillProductionTimeReduction(pmcData, recipe.ProductionTime);
- this.hideoutHelper.getSkillProductionTimeReduction(
pmcData,
recipe.ProductionTime,
SkillTypes.CRAFTING,
this.databaseServer.getTables().globals.config.SkillsSettings.Crafting.CraftTimeReductionPerLevel,
);
const modifiedScavCaseTime = this.getScavCaseTime(pmcData, adjustedCraftTime);
pmcData.Hideout.Production[body.recipeId] = this.hideoutHelper.initProduction(

View File

@ -221,14 +221,14 @@ export class HideoutHelper
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((area) => area.type === HideoutAreas.BITCOIN_FARM);
const bitcoinCount = bitcoinFarm?.slots.filter((slot) => slot.item).length ?? 0; // Get slots with an item property
const hideoutProperties = {
btcFarmCGs: bitcoinCount,
isGeneratorOn: pmcData.Hideout.Areas.find((x) => x.type === HideoutAreas.GENERATOR)?.active ?? false,
isGeneratorOn: pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.GENERATOR)?.active ?? false,
waterCollectorHasFilter: this.doesWaterCollectorHaveFilter(
pmcData.Hideout.Areas.find((x) => x.type === HideoutAreas.WATER_COLLECTOR),
pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.WATER_COLLECTOR),
),
};
@ -237,10 +237,11 @@ export class HideoutHelper
protected doesWaterCollectorHaveFilter(waterCollector: HideoutArea): boolean
{
// Can put filters in from L3
if (waterCollector.level === 3)
{ // can put filters in from L3
{
// Has filter in at least one slot
return waterCollector.slots.some((x) => x.item);
return waterCollector.slots.some((slot) => slot.item);
}
// No Filter
@ -423,7 +424,7 @@ export class HideoutHelper
}
break;
case HideoutAreas.WATER_COLLECTOR:
this.updateWaterCollector(sessionID, pmcData, area, hideoutProperties.isGeneratorOn);
this.updateWaterCollector(sessionID, pmcData, area, hideoutProperties);
break;
case HideoutAreas.AIR_FILTERING:
@ -544,7 +545,7 @@ export class HideoutHelper
sessionId: string,
pmcData: IPmcData,
area: HideoutArea,
isGeneratorOn: boolean,
hideoutProperties: { btcFarmCGs: number; isGeneratorOn: boolean; waterCollectorHasFilter: boolean; },
): void
{
// Skip water collector when not level 3 (cant collect until 3)
@ -553,14 +554,23 @@ export class HideoutHelper
return;
}
if (!hideoutProperties.waterCollectorHasFilter)
{
return;
}
// Canister with purified water craft exists
const prod = pmcData.Hideout.Production[HideoutHelper.waterCollector];
if (prod && this.isProduction(prod))
const purifiedWaterCraft = pmcData.Hideout.Production[HideoutHelper.waterCollector];
if (purifiedWaterCraft && this.isProduction(purifiedWaterCraft))
{
// Update craft time to account for increases in players craft time skill
prod.ProductionTime = this.getAdjustedCraftTimeWithSkills(pmcData, prod.RecipeId);
purifiedWaterCraft.ProductionTime = this.getAdjustedCraftTimeWithSkills(
pmcData,
purifiedWaterCraft.RecipeId,
true,
);
this.updateWaterFilters(area, prod, isGeneratorOn, pmcData);
this.updateWaterFilters(area, purifiedWaterCraft, hideoutProperties.isGeneratorOn, pmcData);
}
else
{
@ -582,10 +592,17 @@ export class HideoutHelper
* Get craft time and make adjustments to account for dev profile + crafting skill level
* @param pmcData Player profile making craft
* @param recipeId Recipe being crafted
* @returns
* @param applyHideoutManagementBonus should the hideout mgmt bonus be appled to the calculation
* @returns Items craft time with bonuses subtracted
*/
protected getAdjustedCraftTimeWithSkills(pmcData: IPmcData, recipeId: string): number
protected getAdjustedCraftTimeWithSkills(
pmcData: IPmcData,
recipeId: string,
applyHideoutManagementBonus = false,
): number
{
const globalSkillsDb = this.databaseServer.getTables().globals.config.SkillsSettings;
const recipe = this.databaseServer.getTables().hideout.production.find((production) =>
production._id === recipeId
);
@ -596,9 +613,26 @@ export class HideoutHelper
return undefined;
}
let modifiedProductionTime = recipe.productionTime
- this.getCraftingSkillProductionTimeReduction(pmcData, recipe.productionTime);
// Seconds to deduct from crafts total time
let timeReductionSeconds = this.getSkillProductionTimeReduction(
pmcData,
recipe.productionTime,
SkillTypes.CRAFTING,
globalSkillsDb.Crafting.ProductionTimeReductionPerLevel,
);
// Some crafts take into account hideout management, e.g. fuel, water/air filters
if (applyHideoutManagementBonus)
{
timeReductionSeconds += this.getSkillProductionTimeReduction(
pmcData,
recipe.productionTime,
SkillTypes.HIDEOUT_MANAGEMENT,
globalSkillsDb.HideoutManagement.ConsumptionReductionPerLevel,
);
}
let modifiedProductionTime = recipe.productionTime - timeReductionSeconds;
if (modifiedProductionTime > 0 && this.profileHelper.isDeveloperAccount(pmcData._id))
{
modifiedProductionTime = 40;
@ -625,7 +659,7 @@ export class HideoutHelper
const productionTime = this.getTotalProductionTimeSeconds(HideoutHelper.waterCollector);
const secondsSinceServerTick = this.getTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn);
filterDrainRate = this.getAdjustWaterFilterDrainRate(
filterDrainRate = this.getTimeAdjustedWaterFilterDrainRate(
secondsSinceServerTick,
productionTime,
production.Progress,
@ -708,7 +742,7 @@ export class HideoutHelper
* @param baseFilterDrainRate Base drain rate
* @returns drain rate (adjusted)
*/
protected getAdjustWaterFilterDrainRate(
protected getTimeAdjustedWaterFilterDrainRate(
secondsSinceServerTick: number,
totalProductionTime: number,
productionProgress: number,
@ -716,10 +750,10 @@ export class HideoutHelper
): number
{
const drainTimeSeconds = 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;
// Multiply drain rate by calculated multiplier
// Multiply base drain rate by time passed
return baseFilterDrainRate * drainTimeSeconds;
}
@ -730,11 +764,28 @@ export class HideoutHelper
*/
protected getWaterFilterDrainRate(pmcData: IPmcData): number
{
const globalSkillsDb = this.databaseServer.getTables().globals.config.SkillsSettings;
// 100 resources last 8 hrs 20 min, 100/8.33/60/60 = 0.00333
const filterDrainRate = 0.00333;
const hideoutManagementConsumptionBonus = 1.0 - this.getHideoutManagementConsumptionBonus(pmcData);
return filterDrainRate * hideoutManagementConsumptionBonus;
const hideoutManagementConsumptionBonus = this.getSkillBonusMultipliedBySkillLevel(
pmcData,
SkillTypes.HIDEOUT_MANAGEMENT,
globalSkillsDb.HideoutManagement.ConsumptionReductionPerLevel,
);
const craftSkillTimeReductionMultipler = this.getSkillBonusMultipliedBySkillLevel(
pmcData,
SkillTypes.CRAFTING,
globalSkillsDb.Crafting.CraftTimeReductionPerLevel,
);
// Never let bonus become 0
const reductionBonus = hideoutManagementConsumptionBonus + craftSkillTimeReductionMultipler === 0
? 1
: 1 - (hideoutManagementConsumptionBonus + craftSkillTimeReductionMultipler);
return filterDrainRate * reductionBonus;
}
/**
@ -1013,22 +1064,46 @@ export class HideoutHelper
}
/**
* Adjust craft time based on crafting skill level found in player profile
* Get a multipler based on players skill level and value per level
* @param pmcData Player profile
* @param skill Player skill from profile
* @param valuePerLevel Value from globals.config.SkillsSettings - `PerLevel`
* @returns Multipler from 0 to 1
*/
protected getSkillBonusMultipliedBySkillLevel(pmcData: IPmcData, skill: SkillTypes, valuePerLevel: number): number
{
const profileSkill = this.profileHelper.getSkillFromProfile(pmcData, skill);
if (!profileSkill || profileSkill.Progress === 0)
{
return 0;
}
// If the level is 51 we need to round it at 50 so on elite you dont get 25.5%
// at level 1 you already get 0.5%, so it goes up until level 50. For some reason the wiki
// says that it caps at level 51 with 25% but as per dump data that is incorrect apparently
let roundedLevel = Math.floor(profileSkill.Progress / 100);
roundedLevel = (roundedLevel === 51) ? roundedLevel - 1 : roundedLevel;
return (roundedLevel * valuePerLevel) / 100;
}
/**
* @param pmcData Player profile
* @param productionTime Time to complete hideout craft in seconds
* @returns Adjusted craft time in seconds
* @param skill Skill bonus to get reduction from
* @param amountPerLevel Skill bonus amount to apply
* @returns Seconds to reduce craft time by
*/
public getCraftingSkillProductionTimeReduction(pmcData: IPmcData, productionTime: number): number
public getSkillProductionTimeReduction(
pmcData: IPmcData,
productionTime: number,
skill: SkillTypes,
amountPerLevel: number,
): number
{
const craftingSkill = pmcData.Skills.Common.find((skill) => skill.Id === SkillTypes.CRAFTING);
if (!craftingSkill)
{
return productionTime;
}
const roundedLevel = Math.floor(Math.min(HideoutHelper.maxSkillPoint, craftingSkill.Progress) / 100);
const percentageToDrop = roundedLevel * 0.75;
const skillTimeReductionMultipler = this.getSkillBonusMultipliedBySkillLevel(pmcData, skill, amountPerLevel);
return (productionTime * percentageToDrop) / 100;
return productionTime * skillTimeReductionMultipler;
}
public isProduction(productive: Productive): productive is Production

View File

@ -495,12 +495,12 @@ export class ProfileHelper
/**
* Get a speciic common skill from supplied profile
* @param pmcData Player profile
* @param skill Skill get get
* @param skill Skill to look up and return value from
* @returns Common skill object from desired profile
*/
public getSkillFromProfile(pmcData: IPmcData, skill: SkillTypes): Common
{
const skillToReturn = pmcData.Skills.Common.find((x) => x.Id === skill);
const skillToReturn = pmcData.Skills.Common.find((commonSkill) => commonSkill.Id === skill);
if (!skillToReturn)
{
this.logger.warning(`Profile ${pmcData.sessionId} does not have a skill named: ${skill}`);