From 3d01fe621137b4ac7f25d4efc378eca511a04816 Mon Sep 17 00:00:00 2001 From: Dev Date: Thu, 30 Nov 2023 10:30:13 +0000 Subject: [PATCH 01/14] Move `TraderData` object into `ItemEventRouterBase` where it will cause less confusion --- project/src/models/eft/common/tables/IBotBase.ts | 12 +----------- .../src/models/eft/itemEvent/IItemEventRouterBase.ts | 12 +++++++++++- project/src/routers/EventOutputHolder.ts | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/project/src/models/eft/common/tables/IBotBase.ts b/project/src/models/eft/common/tables/IBotBase.ts index fba422cb..28f1be35 100644 --- a/project/src/models/eft/common/tables/IBotBase.ts +++ b/project/src/models/eft/common/tables/IBotBase.ts @@ -464,7 +464,7 @@ export interface IQuestStatus startTime: number; status: QuestStatus; statusTimers?: Record; - /** SPT specific property */ + /** Property does not exist in live profile data, but is used by ProfileChanges.questsStatus when sent to client*/ completedConditions?: string[]; availableAfter?: number; } @@ -479,16 +479,6 @@ export interface TraderInfo disabled: boolean; } -/** This object is sent to the client as part of traderRelations */ -export interface TraderData -{ - salesSum: number; - standing: number; - loyalty: number; - unlocked: boolean; - disabled: boolean; -} - export interface RagfairInfo { rating: number; diff --git a/project/src/models/eft/itemEvent/IItemEventRouterBase.ts b/project/src/models/eft/itemEvent/IItemEventRouterBase.ts index d3ceeea1..86ebf3a9 100644 --- a/project/src/models/eft/itemEvent/IItemEventRouterBase.ts +++ b/project/src/models/eft/itemEvent/IItemEventRouterBase.ts @@ -1,4 +1,4 @@ -import { Health, IQuestStatus, Productive, Skills, TraderData } from "@spt-aki/models/eft/common/tables/IBotBase"; +import { Health, IQuestStatus, Productive, Skills } from "@spt-aki/models/eft/common/tables/IBotBase"; import { Item, Upd } from "@spt-aki/models/eft/common/tables/IItem"; import { IQuest } from "@spt-aki/models/eft/common/tables/IQuest"; import { IPmcDataRepeatableQuest } from "@spt-aki/models/eft/common/tables/IRepeatableQuests"; @@ -80,6 +80,16 @@ export interface Improvement improveCompleteTimestamp: number; } +/** Related to TraderInfo */ +export interface TraderData +{ + salesSum: number; + standing: number; + loyalty: number; + unlocked: boolean; + disabled: boolean; +} + export interface Product { _id: string; diff --git a/project/src/routers/EventOutputHolder.ts b/project/src/routers/EventOutputHolder.ts index 27a9beed..21a3d56b 100644 --- a/project/src/routers/EventOutputHolder.ts +++ b/project/src/routers/EventOutputHolder.ts @@ -2,8 +2,8 @@ import { inject, injectable } from "tsyringe"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; -import { IHideoutImprovement, Productive, TraderData, TraderInfo } from "@spt-aki/models/eft/common/tables/IBotBase"; -import { ProfileChange } from "@spt-aki/models/eft/itemEvent/IItemEventRouterBase"; +import { IHideoutImprovement, Productive, TraderInfo } from "@spt-aki/models/eft/common/tables/IBotBase"; +import { ProfileChange, TraderData } from "@spt-aki/models/eft/itemEvent/IItemEventRouterBase"; import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse"; import { JsonUtil } from "@spt-aki/utils/JsonUtil"; import { TimeUtil } from "@spt-aki/utils/TimeUtil"; From 8ddad763be991f106a30b69f555ba07d5077d722 Mon Sep 17 00:00:00 2001 From: Dev Date: Thu, 30 Nov 2023 13:44:43 +0000 Subject: [PATCH 02/14] Cleanup of `handleScavCase()` --- project/src/controllers/HideoutController.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/project/src/controllers/HideoutController.ts b/project/src/controllers/HideoutController.ts index 9be4c369..cfb5af65 100644 --- a/project/src/controllers/HideoutController.ts +++ b/project/src/controllers/HideoutController.ts @@ -943,35 +943,38 @@ export class HideoutController // Create rewards for scav case const scavCaseRewards = this.scavCaseRewardGenerator.generate(request.recipeId); + // Add scav case rewards to player profile pmcData.Hideout.Production[prodId].Products = scavCaseRewards; // Remove the old production from output object before its sent to client delete output.profileChanges[sessionID].production[request.recipeId]; + // Get array of item created + count of them after completing hideout craft const itemsToAdd = pmcData.Hideout.Production[prodId].Products.map( (x: { _tpl: string; upd?: { StackObjectsCount?: number; }; }) => { - let id = x._tpl; - if (this.presetHelper.hasPreset(id)) - { - id = this.presetHelper.getDefaultPreset(id)._id; - } + const itemTpl = this.presetHelper.hasPreset(x._tpl) + ? this.presetHelper.getDefaultPreset(x._tpl)._id + : x._tpl; + + // Count of items crafted const numOfItems = !x.upd?.StackObjectsCount ? 1 : x.upd.StackObjectsCount; // eslint-disable-next-line @typescript-eslint/naming-convention - return { item_id: id, count: numOfItems }; + return { item_id: itemTpl, count: numOfItems }; }, ); const newReq = { items: itemsToAdd, tid: "ragfair" }; - const callback = () => { - // Flag as complete - will be cleaned up later by update() process + // Flag as complete - will be cleaned up later by hideoutController.update() pmcData.Hideout.Production[prodId].sptIsComplete = true; + // Crafting complete, flag as such pmcData.Hideout.Production[prodId].inProgress = false; }; + // Add crafted item to player inventory return this.inventoryHelper.addItem(pmcData, newReq, output, sessionID, callback, true); } From 7bf5f822eedd8e36810777952ae89b93f79ce51f Mon Sep 17 00:00:00 2001 From: Dev Date: Thu, 30 Nov 2023 15:22:10 +0000 Subject: [PATCH 03/14] Add 15% chance bear/usec spawn on reserve raid start --- project/assets/configs/location.json | 48 +++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/project/assets/configs/location.json b/project/assets/configs/location.json index 8d08f25d..8c13f9e0 100644 --- a/project/assets/configs/location.json +++ b/project/assets/configs/location.json @@ -512,7 +512,53 @@ "RandomTimeSpawn": false, "ChanceGroup": 0 } - ] + ], + "rezervbase": [ + { + "sptId": "sptBearReserveNormalSpawn", + "BossName": "sptBear", + "BossChance": 15, + "BossZone": "ZoneBarrack,ZonePTOR1,ZonePTOR2,ZoneSubCommand,ZoneSubStorage,ZoneRailStrorage", + "BossPlayer": false, + "BossDifficult": "normal", + "BossEscortType": "sptBear", + "BossEscortDifficult": "normal", + "BossEscortAmount": "1", + "Time": -1, + "Supports": [{ + "BossEscortType": "sptBear", + "BossEscortDifficult": [ + "normal" + ], + "BossEscortAmount": "1" + } + ], + "RandomTimeSpawn": false, + "ChanceGroup": 0 + }, + { + "sptId": "sptUsecReserveNormalSpawn", + "BossName": "sptUsec", + "BossChance": 15, + "BossZone": "ZoneBarrack,ZonePTOR1,ZonePTOR2,ZoneSubCommand,ZoneSubStorage,ZoneRailStrorage", + "BossPlayer": false, + "BossDifficult": "normal", + "BossEscortType": "sptUsec", + "BossEscortDifficult": "normal", + "BossEscortAmount": "1", + "Time": -1, + "Supports": [{ + "BossEscortType": "sptUsec", + "BossEscortDifficult": [ + "normal" + ], + "BossEscortAmount": "1" + } + ], + "RandomTimeSpawn": false, + "ChanceGroup": 0 + } + ] }, "normal": { "factory4_day": [{ From 1994832281a3484bc580f407ccb76c7a82f2b875 Mon Sep 17 00:00:00 2001 From: DanW Date: Fri, 1 Dec 2023 08:37:52 +0000 Subject: [PATCH 04/14] Improved check for disabling train extracts in Scav raids (!170) Made the following changes for determining if train extracts should be disabled in Scav raids: * When determining at what time the train will leave, include the extraction time and the delay between the train extract activating and it becoming available to board * Fixed the variable used for determining if the extract should be disabled * Ensure `MinTime` and `MaxTime` for extracts are never negative Also, trains are hard, and my brain hurts. Co-authored-by: dwesterwick Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/170 Co-authored-by: DanW Co-committed-by: DanW --- .../src/services/RaidTimeAdjustmentService.ts | 48 +++++++++++++------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/project/src/services/RaidTimeAdjustmentService.ts b/project/src/services/RaidTimeAdjustmentService.ts index 0fd2d27a..a62b2384 100644 --- a/project/src/services/RaidTimeAdjustmentService.ts +++ b/project/src/services/RaidTimeAdjustmentService.ts @@ -205,28 +205,48 @@ export class RaidTimeAdjustmentService MaxTime: null, Chance: null } + + // At what minute we simulate the player joining the raid + const simulatedRaidEntryTimeMinutes = mapBase.EscapeTimeLimit - newRaidTimeMinutes; + // How many seconds have elapsed in the raid when the player joins + const reductionSeconds = simulatedRaidEntryTimeMinutes * 60; + + // Delay between the train extract activating and it becoming available to board + // + // Test method for determining this value: + // 1) Set MinTime, MaxTime, and Count for the train extract all to 120 + // 2) Load into Reserve or Lighthouse as a PMC (both have the same result) + // 3) Board the train when it arrives + // 4) Check the raid time on the Raid Ended Screen (it should always be the same) + // + // trainArrivalDelaySeconds = [raid time on raid-ended screen] - MaxTime - Count - ExfiltrationTime + // Example: Raid Time = 5:33 = 333 seconds + // trainArrivalDelaySeconds = 333 - 120 - 120 - 5 = 88 + // + // I added 2 seconds just to be safe... + // + const trainArrivalDelaySeconds = 90; + + // Determine the earliest possible time in the raid when the train would leave + const earliestPossibleDepartureMinutes = (exit.MinTime + exit.Count + exit.ExfiltrationTime + trainArrivalDelaySeconds) / 60; + // If raid is after last moment train can leave, assume train has already left, disable extract - const latestPossibleDepartureMinutes = (exit.MaxTime + exit.Count) / 60; - if (newRaidTimeMinutes < latestPossibleDepartureMinutes) + const mostPossibleTimeRemainingAfterDeparture = mapBase.EscapeTimeLimit - earliestPossibleDepartureMinutes; + if (newRaidTimeMinutes < mostPossibleTimeRemainingAfterDeparture) { exitChange.Chance = 0; - this.logger.debug(`Train Exit: ${exit.Name} disabled as new raid time ${newRaidTimeMinutes} minutes is below ${latestPossibleDepartureMinutes} minutes`); - + this.logger.debug(`Train Exit: ${exit.Name} disabled as new raid time ${newRaidTimeMinutes} minutes is below ${mostPossibleTimeRemainingAfterDeparture} minutes`); + result.push(exitChange); continue; } - - // What minute we simulate the player joining a raid at - const simulatedRaidEntryTimeMinutes = mapBase.EscapeTimeLimit - newRaidTimeMinutes; - - // How many seconds to reduce extract arrival times by, negative values seem to make extract turn red in game - const reductionSeconds = simulatedRaidEntryTimeMinutes * 60; - - exitChange.MinTime = exit.MinTime - reductionSeconds; - exitChange.MaxTime = exit.MaxTime - reductionSeconds; + + // Reduce extract arrival times. Negative values seem to make extract turn red in game. + exitChange.MinTime = Math.max(exit.MinTime - reductionSeconds, 0); + exitChange.MaxTime = Math.max(exit.MaxTime - reductionSeconds, 0); this.logger.debug(`Train appears between: ${exitChange.MinTime} and ${exitChange.MaxTime} seconds raid time`); @@ -237,4 +257,4 @@ export class RaidTimeAdjustmentService ? result : null ; } -} \ No newline at end of file +} From 2a3839f6de0c018e9c9a229c1a39df25ebdcfe6a Mon Sep 17 00:00:00 2001 From: Dev Date: Fri, 1 Dec 2023 09:03:14 +0000 Subject: [PATCH 05/14] Move `trainArrivalDelaySeconds` value into config --- project/assets/configs/location.json | 351 +++++++++--------- .../src/models/spt/config/ILocationConfig.ts | 61 +-- .../src/services/RaidTimeAdjustmentService.ts | 6 +- 3 files changed, 217 insertions(+), 201 deletions(-) diff --git a/project/assets/configs/location.json b/project/assets/configs/location.json index 8c13f9e0..049a211f 100644 --- a/project/assets/configs/location.json +++ b/project/assets/configs/location.json @@ -841,190 +841,195 @@ "allowDuplicateItemsInStaticContainers": true, "looseLootBlacklist": {}, "scavRaidTimeSettings": { - "bigmap": { - "reduceLootByPercent": true, - "minDynamicLootPercent": 50, - "minStaticLootPercent": 40, - "reducedChancePercent": 70, - "reductionPercentWeights": { - "20": 1, - "25": 2, - "30": 4, - "35": 4, - "40": 4, - "45": 4, - "50": 4, - "60": 2, - "70": 2, - "80": 1 - }, - "adjustWaves": true + "settings": { + "trainArrivalDelaySeconds": 90 }, - "factory4_day": { - "reduceLootByPercent": true, - "minDynamicLootPercent": 50, - "minStaticLootPercent": 40, - "reducedChancePercent": 80, - "reductionPercentWeights": { - "5": 2, - "20": 3, - "25": 3, - "30": 5, - "40": 5, - "50": 5, - "60": 2, - "70": 2, - "80": 2, - "85": 1 + "maps": { + "bigmap": { + "reduceLootByPercent": true, + "minDynamicLootPercent": 50, + "minStaticLootPercent": 40, + "reducedChancePercent": 70, + "reductionPercentWeights": { + "20": 1, + "25": 2, + "30": 4, + "35": 4, + "40": 4, + "45": 4, + "50": 4, + "60": 2, + "70": 2, + "80": 1 + }, + "adjustWaves": true }, - "adjustWaves": true - }, - "factory4_night": { - "reduceLootByPercent": true, - "minDynamicLootPercent": 50, - "minStaticLootPercent": 40, - "reducedChancePercent": 70, - "reductionPercentWeights": { - "20": 4, - "30": 3, - "40": 3, - "60": 2, - "70": 2, - "80": 1 + "factory4_day": { + "reduceLootByPercent": true, + "minDynamicLootPercent": 50, + "minStaticLootPercent": 40, + "reducedChancePercent": 80, + "reductionPercentWeights": { + "5": 2, + "20": 3, + "25": 3, + "30": 5, + "40": 5, + "50": 5, + "60": 2, + "70": 2, + "80": 2, + "85": 1 + }, + "adjustWaves": true }, - "adjustWaves": true - }, - "interchange": { - "reduceLootByPercent": true, - "minDynamicLootPercent": 50, - "minStaticLootPercent": 40, - "reducedChancePercent": 70, - "reductionPercentWeights": { - "20": 5, - "25": 5, - "30": 5, - "35": 5, - "40": 5, - "50": 5, - "60": 2, - "80": 1 + "factory4_night": { + "reduceLootByPercent": true, + "minDynamicLootPercent": 50, + "minStaticLootPercent": 40, + "reducedChancePercent": 70, + "reductionPercentWeights": { + "20": 4, + "30": 3, + "40": 3, + "60": 2, + "70": 2, + "80": 1 + }, + "adjustWaves": true }, - "adjustWaves": true - }, - "rezervbase": { - "reduceLootByPercent": true, - "minDynamicLootPercent": 50, - "minStaticLootPercent": 40, - "reducedChancePercent": 70, + "interchange": { + "reduceLootByPercent": true, + "minDynamicLootPercent": 50, + "minStaticLootPercent": 40, + "reducedChancePercent": 70, + "reductionPercentWeights": { + "20": 5, + "25": 5, + "30": 5, + "35": 5, + "40": 5, + "50": 5, + "60": 2, + "80": 1 + }, + "adjustWaves": true + }, + "rezervbase": { + "reduceLootByPercent": true, + "minDynamicLootPercent": 50, + "minStaticLootPercent": 40, + "reducedChancePercent": 70, - "reductionPercentWeights": { - "20": 3, - "30": 3, - "40": 4, - "50": 4, - "60": 2, - "70": 1, - "80": 1 + "reductionPercentWeights": { + "20": 3, + "30": 3, + "40": 4, + "50": 4, + "60": 2, + "70": 1, + "80": 1 + }, + "adjustWaves": true }, - "adjustWaves": true - }, - "laboratory": { - "reduceLootByPercent": true, - "minDynamicLootPercent": 50, - "minStaticLootPercent": 40, - "reducedChancePercent": 70, - "reductionPercentWeights": { - "20": 3, - "30": 5, - "40": 5, - "50": 5, - "60": 2, - "80": 1 + "laboratory": { + "reduceLootByPercent": true, + "minDynamicLootPercent": 50, + "minStaticLootPercent": 40, + "reducedChancePercent": 70, + "reductionPercentWeights": { + "20": 3, + "30": 5, + "40": 5, + "50": 5, + "60": 2, + "80": 1 + }, + "adjustWaves": true }, - "adjustWaves": true - }, - "lighthouse": { - "reduceLootByPercent": true, - "minDynamicLootPercent": 50, - "minStaticLootPercent": 40, - "reducedChancePercent": 60, - "reductionPercentWeights": { - "20": 2, - "25": 2, - "30": 4, - "40": 4, - "50": 4, - "60": 2, - "80": 1 + "lighthouse": { + "reduceLootByPercent": true, + "minDynamicLootPercent": 50, + "minStaticLootPercent": 40, + "reducedChancePercent": 60, + "reductionPercentWeights": { + "20": 2, + "25": 2, + "30": 4, + "40": 4, + "50": 4, + "60": 2, + "80": 1 + }, + "adjustWaves": true }, - "adjustWaves": true - }, - "shoreline": { - "reduceLootByPercent": true, - "minDynamicLootPercent": 50, - "minStaticLootPercent": 40, - "reducedChancePercent": 60, - "reductionPercentWeights": { - "20": 2, - "25": 3, - "30": 5, - "35": 5, - "40": 5, - "50": 5, - "60": 2, - "70": 1, - "80": 1 + "shoreline": { + "reduceLootByPercent": true, + "minDynamicLootPercent": 50, + "minStaticLootPercent": 40, + "reducedChancePercent": 60, + "reductionPercentWeights": { + "20": 2, + "25": 3, + "30": 5, + "35": 5, + "40": 5, + "50": 5, + "60": 2, + "70": 1, + "80": 1 + }, + "adjustWaves": true }, - "adjustWaves": true - }, - "tarkovstreets": { - "reduceLootByPercent": true, - "minDynamicLootPercent": 50, - "minStaticLootPercent": 40, - "reducedChancePercent": 70, - "reductionPercentWeights": { - "20": 2, - "30": 4, - "40": 4, - "50": 4, - "60": 4, - "70": 1, - "80": 1 + "tarkovstreets": { + "reduceLootByPercent": true, + "minDynamicLootPercent": 50, + "minStaticLootPercent": 40, + "reducedChancePercent": 70, + "reductionPercentWeights": { + "20": 2, + "30": 4, + "40": 4, + "50": 4, + "60": 4, + "70": 1, + "80": 1 + }, + "adjustWaves": true }, - "adjustWaves": true - }, - "woods": { - "reduceLootByPercent": true, - "minDynamicLootPercent": 50, - "minStaticLootPercent": 40, - "reducedChancePercent": 60, - "reductionPercentWeights": { - "20": 3, - "30": 5, - "40": 5, - "50": 5, - "60": 1, - "70": 1, - "80": 1 + "woods": { + "reduceLootByPercent": true, + "minDynamicLootPercent": 50, + "minStaticLootPercent": 40, + "reducedChancePercent": 60, + "reductionPercentWeights": { + "20": 3, + "30": 5, + "40": 5, + "50": 5, + "60": 1, + "70": 1, + "80": 1 + }, + "adjustWaves": true }, - "adjustWaves": true - }, - "default": { - "reduceLootByPercent": true, - "minDynamicLootPercent": 50, - "minStaticLootPercent": 50, - "reducedChancePercent": 50, - "reductionPercentWeights": { - "10": 1, - "20": 2, - "30": 5, - "40": 5, - "50": 5, - "60": 2, - "70": 1, - "80": 1 - }, - "adjustWaves": true + "default": { + "reduceLootByPercent": true, + "minDynamicLootPercent": 50, + "minStaticLootPercent": 50, + "reducedChancePercent": 50, + "reductionPercentWeights": { + "10": 1, + "20": 2, + "30": 5, + "40": 5, + "50": 5, + "60": 2, + "70": 1, + "80": 1 + }, + "adjustWaves": true + } } } } diff --git a/project/src/models/spt/config/ILocationConfig.ts b/project/src/models/spt/config/ILocationConfig.ts index 172f390e..292388f4 100644 --- a/project/src/models/spt/config/ILocationConfig.ts +++ b/project/src/models/spt/config/ILocationConfig.ts @@ -39,31 +39,7 @@ export interface ILocationConfig extends IBaseConfig /** Key: map, value: loose loot ids to ignore */ looseLootBlacklist: Record; /** Key: map, value: settings to control how long scav raids are*/ - scavRaidTimeSettings: Record; -} - -export interface IScavRaidTimeLocationSettings -{ - /** 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; - /** Should bot waves be removed / spawn times be adjusted */ - adjustWaves: boolean; -} - -export interface IContainerRandomistionSettings -{ - enabled: boolean; - /** What maps can use the container randomisation feature */ - maps: Record; - /** Some container types don't work when randomised */ - containerTypesToNotRandomise: string[]; - containerGroupMinSizeMultiplier: number; - containerGroupMaxSizeMultiplier: number; + scavRaidTimeSettings: IScavRaidTimeSettings; } export interface IFixEmptyBotWavesSettings @@ -119,3 +95,38 @@ export interface LootMultiplier terminal: number; town: number; } + +export interface IContainerRandomistionSettings +{ + enabled: boolean; + /** What maps can use the container randomisation feature */ + maps: Record; + /** Some container types don't work when randomised */ + containerTypesToNotRandomise: string[]; + containerGroupMinSizeMultiplier: number; + containerGroupMaxSizeMultiplier: number; +} + +export interface IScavRaidTimeSettings +{ + settings: IScavRaidTimeConfigSettings + maps: Record +} + +export interface IScavRaidTimeConfigSettings +{ + trainArrivalDelaySeconds: number +} + +export interface IScavRaidTimeLocationSettings +{ + /** 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; + /** Should bot waves be removed / spawn times be adjusted */ + adjustWaves: boolean; +} diff --git a/project/src/services/RaidTimeAdjustmentService.ts b/project/src/services/RaidTimeAdjustmentService.ts index a62b2384..a5b7fc68 100644 --- a/project/src/services/RaidTimeAdjustmentService.ts +++ b/project/src/services/RaidTimeAdjustmentService.ts @@ -171,11 +171,11 @@ export class RaidTimeAdjustmentService */ protected getMapSettings(location: string): IScavRaidTimeLocationSettings { - const mapSettings = this.locationConfig.scavRaidTimeSettings[location.toLowerCase()]; + const mapSettings = this.locationConfig.scavRaidTimeSettings.maps[location.toLowerCase()]; if (!mapSettings) { this.logger.warning(`Unable to find scav raid time settings for map: ${location}, using defaults`); - return this.locationConfig.scavRaidTimeSettings.default; + return this.locationConfig.scavRaidTimeSettings.maps.default; } return mapSettings; @@ -226,7 +226,7 @@ export class RaidTimeAdjustmentService // // I added 2 seconds just to be safe... // - const trainArrivalDelaySeconds = 90; + const trainArrivalDelaySeconds = this.locationConfig.scavRaidTimeSettings.settings.trainArrivalDelaySeconds; // Determine the earliest possible time in the raid when the train would leave const earliestPossibleDepartureMinutes = (exit.MinTime + exit.Count + exit.ExfiltrationTime + trainArrivalDelaySeconds) / 60; From e1790ff7a5913e2008484b356394d961ebae5765 Mon Sep 17 00:00:00 2001 From: Dev Date: Fri, 1 Dec 2023 14:15:11 +0000 Subject: [PATCH 06/14] Prevent `getWeightedValue()` function from null error if items and weights do not match --- project/src/helpers/WeightedRandomHelper.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/project/src/helpers/WeightedRandomHelper.ts b/project/src/helpers/WeightedRandomHelper.ts index 7b5f8169..64ae26a7 100644 --- a/project/src/helpers/WeightedRandomHelper.ts +++ b/project/src/helpers/WeightedRandomHelper.ts @@ -22,6 +22,12 @@ export class WeightedRandomHelper { const itemKeys = Object.keys(itemArray); const weights = Object.values(itemArray); + + if (itemKeys.length !== weights.length) + { + return null; + } + const chosenItem = this.weightedRandom(itemKeys, weights); return chosenItem.item; From 52b91cae8770e51bfb65433c57a9d209610ea3c9 Mon Sep 17 00:00:00 2001 From: Dev Date: Fri, 1 Dec 2023 16:45:31 +0000 Subject: [PATCH 07/14] Remove useless length check --- project/src/helpers/WeightedRandomHelper.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/project/src/helpers/WeightedRandomHelper.ts b/project/src/helpers/WeightedRandomHelper.ts index 64ae26a7..da9dcf3e 100644 --- a/project/src/helpers/WeightedRandomHelper.ts +++ b/project/src/helpers/WeightedRandomHelper.ts @@ -23,11 +23,6 @@ export class WeightedRandomHelper const itemKeys = Object.keys(itemArray); const weights = Object.values(itemArray); - if (itemKeys.length !== weights.length) - { - return null; - } - const chosenItem = this.weightedRandom(itemKeys, weights); return chosenItem.item; From 19f6bbaed4c1d640e3e613002570bfb355639e88 Mon Sep 17 00:00:00 2001 From: Dev Date: Fri, 1 Dec 2023 17:22:24 +0000 Subject: [PATCH 08/14] improve `weightedRandom()` handling of bad data input update allowed param types, should only be arrays --- project/src/helpers/WeightedRandomHelper.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/project/src/helpers/WeightedRandomHelper.ts b/project/src/helpers/WeightedRandomHelper.ts index da9dcf3e..4c3ba03c 100644 --- a/project/src/helpers/WeightedRandomHelper.ts +++ b/project/src/helpers/WeightedRandomHelper.ts @@ -42,18 +42,23 @@ export class WeightedRandomHelper * @param {number[]} weights * @returns {{item: any, index: number}} */ - public weightedRandom(items: string | any[], weights: string | any[]): { item: any; index: number; } + public weightedRandom(items: any[], weights: any[]): { item: any; index: number; } { + if (!items || items.length === 0) + { + throw new Error("Items must not be empty"); + } + + if (!weights || weights.length === 0) + { + throw new Error("Item weights must not be empty"); + } + if (items.length !== weights.length) { throw new Error("Items and weight inputs must be of the same length"); } - if (!items.length) - { - throw new Error("Items must not be empty"); - } - // Preparing the cumulative weights array. // For example: // - weights = [1, 4, 3] From 12cb176a4293fc22b8c5c97dcc919e4e3b4f48c8 Mon Sep 17 00:00:00 2001 From: Dev Date: Sat, 2 Dec 2023 00:10:25 +0000 Subject: [PATCH 09/14] Potential fix for failed/repeatable quests keeping their subtask completed status --- project/src/controllers/InraidController.ts | 10 +-- project/src/helpers/InRaidHelper.ts | 89 +++++++++++++++++---- project/src/helpers/QuestHelper.ts | 2 +- 3 files changed, 79 insertions(+), 22 deletions(-) diff --git a/project/src/controllers/InraidController.ts b/project/src/controllers/InraidController.ts index 4dc71241..1ce0f99c 100644 --- a/project/src/controllers/InraidController.ts +++ b/project/src/controllers/InraidController.ts @@ -107,17 +107,17 @@ export class InraidController */ protected savePmcProgress(sessionID: string, postRaidRequest: ISaveProgressRequestData): void { - const serveProfile = this.saveServer.getProfile(sessionID); - const locationName = serveProfile.inraid.location.toLowerCase(); + const serverProfile = this.saveServer.getProfile(sessionID); + const locationName = serverProfile.inraid.location.toLowerCase(); const map: ILocationBase = this.databaseServer.getTables().locations[locationName].base; const mapHasInsuranceEnabled = map.Insurance; - let serverPmcProfile = serveProfile.characters.pmc; + let serverPmcProfile = serverProfile.characters.pmc; const isDead = this.isPlayerDead(postRaidRequest.exit); const preRaidGear = this.inRaidHelper.getPlayerGear(serverPmcProfile.Inventory.items); - serveProfile.inraid.character = "pmc"; + serverProfile.inraid.character = "pmc"; this.inRaidHelper.updateProfileBaseStats(serverPmcProfile, postRaidRequest, sessionID); this.inRaidHelper.updatePmcProfileDataPostRaid(serverPmcProfile, postRaidRequest, sessionID); @@ -219,7 +219,7 @@ export class InraidController activeQuestIdsInProfile, allQuests, ); - if (questAndFindItemConditionId) + if (Object.keys(questAndFindItemConditionId)?.length > 0) { this.profileHelper.removeCompletedQuestConditionFromProfile(pmcData, questAndFindItemConditionId); } diff --git a/project/src/helpers/InRaidHelper.ts b/project/src/helpers/InRaidHelper.ts index ec79edb3..c779e42e 100644 --- a/project/src/helpers/InRaidHelper.ts +++ b/project/src/helpers/InRaidHelper.ts @@ -218,7 +218,7 @@ export class InRaidHelper public updatePmcProfileDataPostRaid(pmcData: IPmcData, saveProgressRequest: ISaveProgressRequestData, sessionId: string): void { // Process failed quests then copy everything - this.processFailedQuests(sessionId, pmcData, pmcData.Quests, saveProgressRequest.profile.Quests); + this.processFailedQuests(sessionId, pmcData, pmcData.Quests, saveProgressRequest.profile); pmcData.Quests = saveProgressRequest.profile.Quests; // No need to do this for scav, old scav is deleted and new one generated @@ -254,13 +254,13 @@ export class InRaidHelper * @param sessionId Player id * @param pmcData Player profile * @param preRaidQuests Quests prior to starting raid - * @param postRaidQuests Quest after raid + * @param postRaidProfile Profile sent by client */ protected processFailedQuests( sessionId: string, pmcData: IPmcData, preRaidQuests: IQuestStatus[], - postRaidQuests: IQuestStatus[], + postRaidProfile: IPostRaidPmcData, ): void { if (!preRaidQuests) @@ -270,24 +270,81 @@ export class InRaidHelper } // Loop over all quests from post-raid profile - for (const postRaidQuest of postRaidQuests) + for (const postRaidQuest of postRaidProfile.Quests) { - // Find matching pre-raid quest + // Find matching pre-raid quest + not already failed const preRaidQuest = preRaidQuests?.find((x) => x.qid === postRaidQuest.qid); - if (preRaidQuest) + if (!preRaidQuest) { - // Post-raid quest is failed but wasn't pre-raid - // postRaidQuest.status has a weird value, need to do some nasty casting to compare it - if (postRaidQuest.status === "Fail" && preRaidQuest.status !== QuestStatus.Fail) + continue; + } + + // Already failed before raid, skip + if (preRaidQuest.status === QuestStatus.Fail) + { + continue; + } + + if (preRaidQuest.status === QuestStatus.Success) + { + continue; + } + + // Quest failed inside raid, need to handle + // postRaidQuest.status has a weird value, need to do some nasty casting to compare it + const postRaidQuestStatus = postRaidQuest.status; + if (postRaidQuestStatus === "Fail") + { + // Send failed message + const failBody: IFailQuestRequestData = { + Action: "QuestComplete", + qid: postRaidQuest.qid, + removeExcessItems: true, + }; + this.questHelper.failQuest(pmcData, failBody, sessionId); + } + // Restartable quests need special actions + else if (postRaidQuestStatus === "FailRestartable") + { + // Does failed quest have requirement to collect items from raid + const questDbData = this.questHelper.getQuestFromDb(postRaidQuest.qid, pmcData); + // AvailableForFinish + const matchingAffFindConditions = questDbData.conditions.AvailableForFinish.filter(x => x._parent === "FindItem"); + const itemsToCollect: string[] = []; + if (matchingAffFindConditions) { - // Send failed message - const failBody: IFailQuestRequestData = { - Action: "QuestComplete", - qid: postRaidQuest.qid, - removeExcessItems: true, - }; - this.questHelper.failQuest(pmcData, failBody, sessionId); + // Find all items the failed quest wanted + for (const condition of matchingAffFindConditions) + { + itemsToCollect.push(...condition._props.target); + } } + + // Remove quest items from profile as quest has failed and may still be alive + // Required as restarting the quest from main menu does not remove value from CarriedQuestItems array + postRaidProfile.Stats.Eft.CarriedQuestItems = postRaidProfile.Stats.Eft.CarriedQuestItems.filter(x => !itemsToCollect.includes(x)) + + // Remove quest item from profile now quest is failed + // updateProfileBaseStats() has already passed by ref EFT.Stats, all changes applied to postRaid profile also apply to server profile + for (const itemTpl of itemsToCollect) + { + // Look for sessioncounter and remove it + const counterIndex = postRaidProfile.Stats.Eft.SessionCounters.Items.findIndex(x => x.Key.includes(itemTpl) && x.Key.includes("LootItem")); + if (counterIndex > -1) + { + postRaidProfile.Stats.Eft.SessionCounters.Items.splice(counterIndex, 1); + } + + // Look for quest item and remove it + const inventoryItemIndex = postRaidProfile.Inventory.items.findIndex(x => x._tpl === itemTpl); + if (inventoryItemIndex > -1) + { + postRaidProfile.Inventory.items.splice(inventoryItemIndex, 1); + } + } + + // Clear out any completed conditions + postRaidQuest.completedConditions = []; } } } diff --git a/project/src/helpers/QuestHelper.ts b/project/src/helpers/QuestHelper.ts index ffaafc40..b3e2a0b9 100644 --- a/project/src/helpers/QuestHelper.ts +++ b/project/src/helpers/QuestHelper.ts @@ -951,7 +951,7 @@ export class QuestHelper const questInDb = allQuests.find((x) => x._id === questId); if (!questInDb) { - this.logger.warning( + this.logger.debug( `Unable to find quest: ${questId} in db, cannot get 'FindItem' condition, skipping`, ); continue; From f5e51366030049cc45db70e9e4e7ec70d5d297f0 Mon Sep 17 00:00:00 2001 From: Dev Date: Sat, 2 Dec 2023 19:25:46 +0000 Subject: [PATCH 10/14] Fix big that casued bots to spawn with only 1 magazine at most --- project/src/helpers/BotWeaponGeneratorHelper.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/src/helpers/BotWeaponGeneratorHelper.ts b/project/src/helpers/BotWeaponGeneratorHelper.ts index 011a5a05..29a0586e 100644 --- a/project/src/helpers/BotWeaponGeneratorHelper.ts +++ b/project/src/helpers/BotWeaponGeneratorHelper.ts @@ -216,7 +216,7 @@ export class BotWeaponGeneratorHelper // Iterate over each grid in the container and look for a big enough space for the item to be placed in let currentGridCount = 1; - const slotGridCount = containerTemplate[1]._props.Grids.length; + const totalSlotGridCount = containerTemplate[1]._props.Grids.length; for (const slotGrid of containerTemplate[1]._props.Grids) { // Grid is empty, skip @@ -280,7 +280,7 @@ export class BotWeaponGeneratorHelper } // If we've checked all grids in container and reached this point, there's no space for item - if (slotGridCount >= currentGridCount) + if (currentGridCount >= totalSlotGridCount) { return ItemAddedResult.NO_SPACE; } From 1fdd1967e986bb883e3bdb1a235a7bb08a3a35ce Mon Sep 17 00:00:00 2001 From: DanW Date: Sat, 2 Dec 2023 19:41:27 +0000 Subject: [PATCH 11/14] Change name of trainArrivalDelaySeconds to clarify its meaning (!171) Changed the name of the new `trainArrivalDelaySeconds` setting to `trainArrivalDelayObservedSeconds` so it's more obvious that it doesn't actually control the train arrival time. `trainArrivalDelayObservedSeconds` is my first choice for naming this setting, and `trainArrivalDelayThatYouDefinitelyShouldNotChangeSoDoNotEvenThinkAboutItSeconds` is my second choice. Co-authored-by: dwesterwick Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/171 Co-authored-by: DanW Co-committed-by: DanW --- project/assets/configs/location.json | 2 +- project/src/models/spt/config/ILocationConfig.ts | 2 +- project/src/services/RaidTimeAdjustmentService.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/project/assets/configs/location.json b/project/assets/configs/location.json index 049a211f..8f672c80 100644 --- a/project/assets/configs/location.json +++ b/project/assets/configs/location.json @@ -842,7 +842,7 @@ "looseLootBlacklist": {}, "scavRaidTimeSettings": { "settings": { - "trainArrivalDelaySeconds": 90 + "trainArrivalDelayObservedSeconds": 90 }, "maps": { "bigmap": { diff --git a/project/src/models/spt/config/ILocationConfig.ts b/project/src/models/spt/config/ILocationConfig.ts index 292388f4..e59469d0 100644 --- a/project/src/models/spt/config/ILocationConfig.ts +++ b/project/src/models/spt/config/ILocationConfig.ts @@ -115,7 +115,7 @@ export interface IScavRaidTimeSettings export interface IScavRaidTimeConfigSettings { - trainArrivalDelaySeconds: number + trainArrivalDelayObservedSeconds: number } export interface IScavRaidTimeLocationSettings diff --git a/project/src/services/RaidTimeAdjustmentService.ts b/project/src/services/RaidTimeAdjustmentService.ts index a5b7fc68..fbcad8b2 100644 --- a/project/src/services/RaidTimeAdjustmentService.ts +++ b/project/src/services/RaidTimeAdjustmentService.ts @@ -226,7 +226,7 @@ export class RaidTimeAdjustmentService // // I added 2 seconds just to be safe... // - const trainArrivalDelaySeconds = this.locationConfig.scavRaidTimeSettings.settings.trainArrivalDelaySeconds; + const trainArrivalDelaySeconds = this.locationConfig.scavRaidTimeSettings.settings.trainArrivalDelayObservedSeconds; // Determine the earliest possible time in the raid when the train would leave const earliestPossibleDepartureMinutes = (exit.MinTime + exit.Count + exit.ExfiltrationTime + trainArrivalDelaySeconds) / 60; From b834cd0547f181811f60361ed9d27a05e4a1757d Mon Sep 17 00:00:00 2001 From: Dev Date: Sat, 2 Dec 2023 23:01:18 +0000 Subject: [PATCH 12/14] increase chance scav raid time is reduced --- project/assets/configs/location.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/project/assets/configs/location.json b/project/assets/configs/location.json index 8f672c80..11149e98 100644 --- a/project/assets/configs/location.json +++ b/project/assets/configs/location.json @@ -849,7 +849,7 @@ "reduceLootByPercent": true, "minDynamicLootPercent": 50, "minStaticLootPercent": 40, - "reducedChancePercent": 70, + "reducedChancePercent": 95, "reductionPercentWeights": { "20": 1, "25": 2, @@ -868,7 +868,7 @@ "reduceLootByPercent": true, "minDynamicLootPercent": 50, "minStaticLootPercent": 40, - "reducedChancePercent": 80, + "reducedChancePercent": 95, "reductionPercentWeights": { "5": 2, "20": 3, @@ -887,7 +887,7 @@ "reduceLootByPercent": true, "minDynamicLootPercent": 50, "minStaticLootPercent": 40, - "reducedChancePercent": 70, + "reducedChancePercent": 75, "reductionPercentWeights": { "20": 4, "30": 3, @@ -902,7 +902,7 @@ "reduceLootByPercent": true, "minDynamicLootPercent": 50, "minStaticLootPercent": 40, - "reducedChancePercent": 70, + "reducedChancePercent": 95, "reductionPercentWeights": { "20": 5, "25": 5, @@ -919,7 +919,7 @@ "reduceLootByPercent": true, "minDynamicLootPercent": 50, "minStaticLootPercent": 40, - "reducedChancePercent": 70, + "reducedChancePercent": 95, "reductionPercentWeights": { "20": 3, @@ -936,7 +936,7 @@ "reduceLootByPercent": true, "minDynamicLootPercent": 50, "minStaticLootPercent": 40, - "reducedChancePercent": 70, + "reducedChancePercent": 95, "reductionPercentWeights": { "20": 3, "30": 5, @@ -951,7 +951,7 @@ "reduceLootByPercent": true, "minDynamicLootPercent": 50, "minStaticLootPercent": 40, - "reducedChancePercent": 60, + "reducedChancePercent": 95, "reductionPercentWeights": { "20": 2, "25": 2, @@ -967,7 +967,7 @@ "reduceLootByPercent": true, "minDynamicLootPercent": 50, "minStaticLootPercent": 40, - "reducedChancePercent": 60, + "reducedChancePercent": 95, "reductionPercentWeights": { "20": 2, "25": 3, @@ -985,7 +985,7 @@ "reduceLootByPercent": true, "minDynamicLootPercent": 50, "minStaticLootPercent": 40, - "reducedChancePercent": 70, + "reducedChancePercent": 95, "reductionPercentWeights": { "20": 2, "30": 4, @@ -1001,7 +1001,7 @@ "reduceLootByPercent": true, "minDynamicLootPercent": 50, "minStaticLootPercent": 40, - "reducedChancePercent": 60, + "reducedChancePercent": 95, "reductionPercentWeights": { "20": 3, "30": 5, @@ -1017,7 +1017,7 @@ "reduceLootByPercent": true, "minDynamicLootPercent": 50, "minStaticLootPercent": 50, - "reducedChancePercent": 50, + "reducedChancePercent": 95, "reductionPercentWeights": { "10": 1, "20": 2, From 044f4f9eb3daa2a88b8976ef5eb5e0021b01866e Mon Sep 17 00:00:00 2001 From: Dev Date: Sun, 3 Dec 2023 10:01:55 +0000 Subject: [PATCH 13/14] Update Skiers questassort data --- .../58330581ace78e27b8b10cee/questassort.json | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/project/assets/database/traders/58330581ace78e27b8b10cee/questassort.json b/project/assets/database/traders/58330581ace78e27b8b10cee/questassort.json index bdddcb79..65ac3860 100644 --- a/project/assets/database/traders/58330581ace78e27b8b10cee/questassort.json +++ b/project/assets/database/traders/58330581ace78e27b8b10cee/questassort.json @@ -1,33 +1,33 @@ { + "fail": {}, "started": {}, "success": { - "6507ff21644a656aee0f758f": "596b455186f77457cb50eccb", - "6507ff21644a656aee0f74b7": "5b4794cb86f774598100d5d4", - "6507ff20644a656aee0f744d": "5c0bbaa886f7746941031d82", - "6507ff22644a656aee0f75d3": "5c0bbaa886f7746941031d82", - "6507ff20644a656aee0f73e4": "596b36c586f77450d6045ad2", - "6507ff22644a656aee0f76e1": "596b36c586f77450d6045ad2", - "6507ff20644a656aee0f743f": "5979eee086f774311955e614", - "6507ff22644a656aee0f75e5": "5b478ff486f7744d184ecbbf", - "6507ff21644a656aee0f75a8": "5a27d2af86f7744e1115b323", - "6507ff21644a656aee0f7481": "5c0bdb5286f774166e38eed4", - "6507ff20644a656aee0f744b": "5c1234c286f77406fa13baeb", - "6507ff20644a656aee0f7465": "596b43fb86f77457ca186186", - "6507ff20644a656aee0f7447": "5a27b87686f77460de0252a8", - "6507ff20644a656aee0f73d6": "5967725e86f774601a446662", - "652376e2f6c67195e4061382": "6179b5eabca27a099552e052", - "6507ff20644a656aee0f73bc": "6193850f60b34236ee0483de", + "6492e44bf4287b13040fcbae": "6179b5eabca27a099552e052", + "6492e44bf4287b13040fccf6": "647710905320c660d91c15a5", + "64a8578f0e9876295f0f83ed": "649af47d717cb30e7e4b5e26", + "64a8578f0e9876295f0f83ee": "649af47d717cb30e7e4b5e26", + "64a8578f0e9876295f0f83ef": "649af47d717cb30e7e4b5e26", "6507ff20644a656aee0f738e": "6179b4f16e9dd54ac275e407", + "6507ff20644a656aee0f73bc": "6193850f60b34236ee0483de", "6507ff20644a656aee0f73d4": "6179b4f16e9dd54ac275e407", + "6507ff20644a656aee0f73d6": "5967725e86f774601a446662", + "6507ff20644a656aee0f73e4": "596b36c586f77450d6045ad2", + "6507ff20644a656aee0f743f": "5979eee086f774311955e614", + "6507ff20644a656aee0f7447": "5a27b87686f77460de0252a8", + "6507ff20644a656aee0f744b": "5c1234c286f77406fa13baeb", + "6507ff20644a656aee0f744d": "5c0bbaa886f7746941031d82", + "6507ff20644a656aee0f7465": "596b43fb86f77457ca186186", + "6507ff21644a656aee0f7481": "5c0bdb5286f774166e38eed4", "6507ff21644a656aee0f7498": "6179b4f16e9dd54ac275e407", "6507ff21644a656aee0f74a6": "5ac242ab86f77412464f68b4", - "6507ff21644a656aee0f757d": "639873003693c63d86328f25", - "6507ff22644a656aee0f7624": "64f5e20652fc01298e2c61e3", + "6507ff21644a656aee0f74b7": "5b4794cb86f774598100d5d4", "6507ff21644a656aee0f751c": "64f6aafd67e11a7c6206e0d0", - "64cac5c1d45ace5bc90c74a8": "649af47d717cb30e7e4b5e26", - "64cac5c1d45ace5bc90c74a9": "649af47d717cb30e7e4b5e26", - "64cac5c1d45ace5bc90c74aa": "649af47d717cb30e7e4b5e26", - "64cac5c1d45ace5bc90c74ab": "647710905320c660d91c15a5" - }, - "fail": {} -} \ No newline at end of file + "6507ff21644a656aee0f757d": "639873003693c63d86328f25", + "6507ff21644a656aee0f758f": "596b455186f77457cb50eccb", + "6507ff21644a656aee0f75a8": "5a27d2af86f7744e1115b323", + "6507ff22644a656aee0f75d3": "5c0bbaa886f7746941031d82", + "6507ff22644a656aee0f75e5": "5b478ff486f7744d184ecbbf", + "6507ff22644a656aee0f7624": "64f5e20652fc01298e2c61e3", + "6507ff22644a656aee0f76e1": "596b36c586f77450d6045ad2" + } +} From fc8b49b31335e394e3f5ba2f6cfbd43df05ff77c Mon Sep 17 00:00:00 2001 From: DanW Date: Sun, 3 Dec 2023 10:03:19 +0000 Subject: [PATCH 14/14] Increase minimum Scav time for Factory (!172) Based on tester feedback, ensure at least 5 minutes is remaining for Factory Scav raids. If we have evidence that people can regularly spawn into Factory on live EFT with 3-4 min remaining, then maybe we should just adjust the weights instead. Co-authored-by: dwesterwick Co-authored-by: chomp Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/172 Co-authored-by: DanW Co-committed-by: DanW --- project/assets/configs/location.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/project/assets/configs/location.json b/project/assets/configs/location.json index 11149e98..6bd02326 100644 --- a/project/assets/configs/location.json +++ b/project/assets/configs/location.json @@ -878,8 +878,7 @@ "50": 5, "60": 2, "70": 2, - "80": 2, - "85": 1 + "75": 2 }, "adjustWaves": true }, @@ -894,7 +893,7 @@ "40": 3, "60": 2, "70": 2, - "80": 1 + "75": 1 }, "adjustWaves": true },