Add system that adjusts the loot multipliers for a scav raid based on the percentage of the raid time remaining

Controlled per location

Most maps are capped at 40/50% min

Added multiple config proeprties to configure how system works
Added ability to remove all AppContext values by key

During `getRaidTime()` loot % modifier values are stored in app context,
Then, during `generate()` those values are retreived and applied if found
After loot generation values are reset to their original value
This commit is contained in:
Dev 2023-11-28 12:42:58 +00:00
parent f9cf3242c8
commit 9c2725e2fe
7 changed files with 112 additions and 9 deletions

View File

@ -796,6 +796,9 @@
"looseLootBlacklist": {},
"scavRaidTimeSettings": {
"bigmap": {
"reduceLootByPercent": true,
"minDynamicLootPercent": 50,
"minStaticLootPercent": 40,
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 12,
@ -806,7 +809,10 @@
}
},
"factory4_day": {
"reducedChancePercent": 60,
"reduceLootByPercent": true,
"minDynamicLootPercent": 50,
"minStaticLootPercent": 40,
"reducedChancePercent": 50,
"reductionPercentWeights": {
"20": 12,
"30": 7,
@ -816,6 +822,9 @@
}
},
"factory4_night": {
"reduceLootByPercent": true,
"minDynamicLootPercent": 50,
"minStaticLootPercent": 40,
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 12,
@ -826,6 +835,9 @@
}
},
"interchange": {
"reduceLootByPercent": true,
"minDynamicLootPercent": 50,
"minStaticLootPercent": 40,
"reducedChancePercent": 50,
"reductionPercentWeights": {
"20": 12,
@ -836,7 +848,11 @@
}
},
"rezervbase": {
"reduceLootByPercent": true,
"minDynamicLootPercent": 50,
"minStaticLootPercent": 40,
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 12,
"30": 7,
@ -846,6 +862,9 @@
}
},
"laboratory": {
"reduceLootByPercent": true,
"minDynamicLootPercent": 50,
"minStaticLootPercent": 40,
"reducedChancePercent": 30,
"reductionPercentWeights": {
"20": 12,
@ -856,6 +875,9 @@
}
},
"lighthouse": {
"reduceLootByPercent": true,
"minDynamicLootPercent": 50,
"minStaticLootPercent": 40,
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 12,
@ -866,6 +888,9 @@
}
},
"shoreline": {
"reduceLootByPercent": true,
"minDynamicLootPercent": 50,
"minStaticLootPercent": 40,
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 25,
@ -876,6 +901,9 @@
}
},
"tarkovstreets": {
"reduceLootByPercent": true,
"minDynamicLootPercent": 50,
"minStaticLootPercent": 40,
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 25,
@ -886,6 +914,9 @@
}
},
"woods": {
"reduceLootByPercent": true,
"minDynamicLootPercent": 50,
"minStaticLootPercent": 40,
"reducedChancePercent": 40,
"reductionPercentWeights": {
"20": 25,
@ -896,6 +927,9 @@
}
},
"default": {
"reduceLootByPercent": true,
"minDynamicLootPercent": 50,
"minStaticLootPercent": 50,
"reducedChancePercent": 25,
"reductionPercentWeights": {
"20": 12,

View File

@ -61,4 +61,12 @@ export class ApplicationContext
list.add(new ContextVariable(value, type));
this.variables.set(type, list);
}
public clearValues(type: ContextVariableType): void
{
this.variables.has(type)
{
this.variables.delete(type);
}
}
}

View File

@ -6,5 +6,6 @@ export enum ContextVariableType {
/** Timestamp when client first connected */
CLIENT_START_TIMESTAMP = 2,
/** When player is loading into map and loot is requested */
REGISTER_PLAYER_REQUEST = 3
REGISTER_PLAYER_REQUEST = 3,
LOOT_MULTIPLER_CHANGE = 4,
}

View File

@ -598,12 +598,22 @@ export class GameController
}
// Get the weighted percent to reduce the raid time by
const chosenRaidReductionPercent = this.weightedRandomHelper.getWeightedValue<string>(
const chosenRaidReductionPercent = Number.parseInt(this.weightedRandomHelper.getWeightedValue<string>(
mapSettings.reductionPercentWeights,
);
));
if (mapSettings.reduceLootByPercent)
{
// Store time reduction percent in app context so loot gen can pick it up later
this.applicationContext.addValue(ContextVariableType.LOOT_MULTIPLER_CHANGE,
{
dynamicLootPercent: Math.max(chosenRaidReductionPercent, mapSettings.minDynamicLootPercent),
staticLootPercent: Math.max(chosenRaidReductionPercent, mapSettings.minStaticLootPercent)
});
}
// How many minutes raid will be
const newRaidTimeMinutes = Math.floor(this.randomUtil.reduceValueByPercent(baseEscapeTimeMinutes, Number.parseInt(chosenRaidReductionPercent)));
const newRaidTimeMinutes = Math.floor(this.randomUtil.reduceValueByPercent(baseEscapeTimeMinutes, chosenRaidReductionPercent));
// Update result object with new time
result.RaidTimeMinutes = newRaidTimeMinutes;

View File

@ -1,5 +1,7 @@
import { inject, injectable } from "tsyringe";
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
import { LocationGenerator } from "@spt-aki/generators/LocationGenerator";
import { LootGenerator } from "@spt-aki/generators/LootGenerator";
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
@ -12,7 +14,8 @@ import { IGetLocationRequestData } from "@spt-aki/models/eft/location/IGetLocati
import { AirdropTypeEnum } from "@spt-aki/models/enums/AirdropType";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
import { IAirdropConfig } from "@spt-aki/models/spt/config/IAirdropConfig";
import { ILocationConfig } from "@spt-aki/models/spt/config/ILocationConfig";
import { ILocationConfig, LootMultiplier } from "@spt-aki/models/spt/config/ILocationConfig";
import { ILootMultiplerChange } from "@spt-aki/models/spt/location/ILootMultiplerChange";
import { ILocations } from "@spt-aki/models/spt/server/ILocations";
import { LootRequest } from "@spt-aki/models/spt/services/LootRequest";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
@ -42,6 +45,7 @@ export class LocationController
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
@inject("TimeUtil") protected timeUtil: TimeUtil,
@inject("ConfigServer") protected configServer: ConfigServer,
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
)
{
this.airdropConfig = this.configServer.getConfig(ConfigTypes.AIRDROP);
@ -83,10 +87,23 @@ export class LocationController
return output;
}
// Check for a loot multipler adjustment in app context and apply if one is found
let locationConfigCopy: ILocationConfig;
const lootMultiplierAdjustment = this.applicationContext.getLatestValue(ContextVariableType.LOOT_MULTIPLER_CHANGE)?.getValue<ILootMultiplerChange>();
if (lootMultiplierAdjustment)
{
this.logger.debug(`Adjusting dynamic loot multipliers to ${lootMultiplierAdjustment.dynamicLootPercent}% and static loot multipliers to ${lootMultiplierAdjustment.staticLootPercent}% of original`)
locationConfigCopy = this.jsonUtil.clone(this.locationConfig); // Clone values so they can be used to reset originals later
// Change loot multipler values before they're used below
this.adjustLootMultipliers(this.locationConfig.looseLootMultiplier, lootMultiplierAdjustment.dynamicLootPercent);
this.adjustLootMultipliers(this.locationConfig.staticLootMultiplier, lootMultiplierAdjustment.staticLootPercent);
}
const staticAmmoDist = this.jsonUtil.clone(db.loot.staticAmmo);
// Create containers and add loot to them
const staticLoot = this.locationGenerator.generateStaticContainers(location.base, staticAmmoDist);
const staticLoot = this.locationGenerator.generateStaticContainers(output, staticAmmoDist);
output.Loot.push(...staticLoot);
// Add dyanmic loot to output loot
@ -107,9 +124,32 @@ export class LocationController
);
this.logger.success(this.localisationService.getText("location-generated_success", name));
// Reset loot multipliers back to original values
if (lootMultiplierAdjustment)
{
this.logger.debug("Resetting loot multipliers back to their original values");
this.locationConfig.staticLootMultiplier = locationConfigCopy.staticLootMultiplier;
this.locationConfig.looseLootMultiplier = locationConfigCopy.looseLootMultiplier;
this.applicationContext.clearValues(ContextVariableType.LOOT_MULTIPLER_CHANGE);
}
return output;
}
/**
* Adjust the loot multiplier values passed in to be a % of their original value
* @param mapLootMultiplers Multiplers to adjust
* @param loosePercent Percent to change values to
*/
protected adjustLootMultipliers(mapLootMultiplers: LootMultiplier, loosePercent: number): void
{
for (const key in mapLootMultiplers)
{
mapLootMultiplers[key] = this.randomUtil.getPercentOfValue(mapLootMultiplers[key], loosePercent);
}
}
/**
* Handle client/locations
* Get all maps base location properties without loot data

View File

@ -44,8 +44,13 @@ export interface ILocationConfig extends IBaseConfig
export interface IScavRaidTimeLocationSettings
{
reducedChancePercent: number
reductionPercentWeights: Record<string, number>
/** Should loot be reduced by same percent length of raid is reduced by */
reduceLootByPercent: boolean;
minStaticLootPercent: number;
minDynamicLootPercent: number;
/** Chance raid time is reduced */
reducedChancePercent: number;
reductionPercentWeights: Record<string, number>;
}
export interface IContainerRandomistionSettings

View File

@ -0,0 +1,5 @@
export interface ILootMultiplerChange
{
dynamicLootPercent: number
staticLootPercent: number
}