From 9c2725e2fe263ef653c936defb71a5d6d9d9caa8 Mon Sep 17 00:00:00 2001 From: Dev Date: Tue, 28 Nov 2023 12:42:58 +0000 Subject: [PATCH] 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 --- project/assets/configs/location.json | 36 ++++++++++++++- project/src/context/ApplicationContext.ts | 8 ++++ project/src/context/ContextVariableType.ts | 3 +- project/src/controllers/GameController.ts | 16 +++++-- project/src/controllers/LocationController.ts | 44 ++++++++++++++++++- .../src/models/spt/config/ILocationConfig.ts | 9 +++- .../spt/location/ILootMultiplerChange.ts | 5 +++ 7 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 project/src/models/spt/location/ILootMultiplerChange.ts diff --git a/project/assets/configs/location.json b/project/assets/configs/location.json index d1653667..8167025e 100644 --- a/project/assets/configs/location.json +++ b/project/assets/configs/location.json @@ -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, diff --git a/project/src/context/ApplicationContext.ts b/project/src/context/ApplicationContext.ts index da9655a2..870be807 100644 --- a/project/src/context/ApplicationContext.ts +++ b/project/src/context/ApplicationContext.ts @@ -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); + } + } } diff --git a/project/src/context/ContextVariableType.ts b/project/src/context/ContextVariableType.ts index f69f3630..06fa7f00 100644 --- a/project/src/context/ContextVariableType.ts +++ b/project/src/context/ContextVariableType.ts @@ -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, } diff --git a/project/src/controllers/GameController.ts b/project/src/controllers/GameController.ts index 6fc82aef..420c73d8 100644 --- a/project/src/controllers/GameController.ts +++ b/project/src/controllers/GameController.ts @@ -598,12 +598,22 @@ export class GameController } // Get the weighted percent to reduce the raid time by - const chosenRaidReductionPercent = this.weightedRandomHelper.getWeightedValue( + const chosenRaidReductionPercent = Number.parseInt(this.weightedRandomHelper.getWeightedValue( 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; diff --git a/project/src/controllers/LocationController.ts b/project/src/controllers/LocationController.ts index 949cb52b..962dcaa0 100644 --- a/project/src/controllers/LocationController.ts +++ b/project/src/controllers/LocationController.ts @@ -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(); + 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 diff --git a/project/src/models/spt/config/ILocationConfig.ts b/project/src/models/spt/config/ILocationConfig.ts index c3f0c36c..c13fcae3 100644 --- a/project/src/models/spt/config/ILocationConfig.ts +++ b/project/src/models/spt/config/ILocationConfig.ts @@ -44,8 +44,13 @@ export interface ILocationConfig extends IBaseConfig export interface IScavRaidTimeLocationSettings { - reducedChancePercent: number - reductionPercentWeights: Record + /** 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; } export interface IContainerRandomistionSettings diff --git a/project/src/models/spt/location/ILootMultiplerChange.ts b/project/src/models/spt/location/ILootMultiplerChange.ts new file mode 100644 index 00000000..f1ce1dfc --- /dev/null +++ b/project/src/models/spt/location/ILootMultiplerChange.ts @@ -0,0 +1,5 @@ +export interface ILootMultiplerChange +{ + dynamicLootPercent: number + staticLootPercent: number +} \ No newline at end of file