Merge branch 'master' of https://dev.sp-tarkov.com/SPT-AKI/Server into 3.8.0
# Conflicts: # project/src/controllers/HideoutController.ts
This commit is contained in:
commit
1db690afb3
@ -512,7 +512,53 @@
|
|||||||
"RandomTimeSpawn": false,
|
"RandomTimeSpawn": false,
|
||||||
"ChanceGroup": 0
|
"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": {
|
"normal": {
|
||||||
"factory4_day": [{
|
"factory4_day": [{
|
||||||
@ -795,190 +841,194 @@
|
|||||||
"allowDuplicateItemsInStaticContainers": true,
|
"allowDuplicateItemsInStaticContainers": true,
|
||||||
"looseLootBlacklist": {},
|
"looseLootBlacklist": {},
|
||||||
"scavRaidTimeSettings": {
|
"scavRaidTimeSettings": {
|
||||||
"bigmap": {
|
"settings": {
|
||||||
"reduceLootByPercent": true,
|
"trainArrivalDelayObservedSeconds": 90
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
"factory4_day": {
|
"maps": {
|
||||||
"reduceLootByPercent": true,
|
"bigmap": {
|
||||||
"minDynamicLootPercent": 50,
|
"reduceLootByPercent": true,
|
||||||
"minStaticLootPercent": 40,
|
"minDynamicLootPercent": 50,
|
||||||
"reducedChancePercent": 80,
|
"minStaticLootPercent": 40,
|
||||||
"reductionPercentWeights": {
|
"reducedChancePercent": 95,
|
||||||
"5": 2,
|
"reductionPercentWeights": {
|
||||||
"20": 3,
|
"20": 1,
|
||||||
"25": 3,
|
"25": 2,
|
||||||
"30": 5,
|
"30": 4,
|
||||||
"40": 5,
|
"35": 4,
|
||||||
"50": 5,
|
"40": 4,
|
||||||
"60": 2,
|
"45": 4,
|
||||||
"70": 2,
|
"50": 4,
|
||||||
"80": 2,
|
"60": 2,
|
||||||
"85": 1
|
"70": 2,
|
||||||
|
"80": 1
|
||||||
|
},
|
||||||
|
"adjustWaves": true
|
||||||
},
|
},
|
||||||
"adjustWaves": true
|
"factory4_day": {
|
||||||
},
|
"reduceLootByPercent": true,
|
||||||
"factory4_night": {
|
"minDynamicLootPercent": 50,
|
||||||
"reduceLootByPercent": true,
|
"minStaticLootPercent": 40,
|
||||||
"minDynamicLootPercent": 50,
|
"reducedChancePercent": 95,
|
||||||
"minStaticLootPercent": 40,
|
"reductionPercentWeights": {
|
||||||
"reducedChancePercent": 70,
|
"5": 2,
|
||||||
"reductionPercentWeights": {
|
"20": 3,
|
||||||
"20": 4,
|
"25": 3,
|
||||||
"30": 3,
|
"30": 5,
|
||||||
"40": 3,
|
"40": 5,
|
||||||
"60": 2,
|
"50": 5,
|
||||||
"70": 2,
|
"60": 2,
|
||||||
"80": 1
|
"70": 2,
|
||||||
|
"75": 2
|
||||||
|
},
|
||||||
|
"adjustWaves": true
|
||||||
},
|
},
|
||||||
"adjustWaves": true
|
"factory4_night": {
|
||||||
},
|
"reduceLootByPercent": true,
|
||||||
"interchange": {
|
"minDynamicLootPercent": 50,
|
||||||
"reduceLootByPercent": true,
|
"minStaticLootPercent": 40,
|
||||||
"minDynamicLootPercent": 50,
|
"reducedChancePercent": 75,
|
||||||
"minStaticLootPercent": 40,
|
"reductionPercentWeights": {
|
||||||
"reducedChancePercent": 70,
|
"20": 4,
|
||||||
"reductionPercentWeights": {
|
"30": 3,
|
||||||
"20": 5,
|
"40": 3,
|
||||||
"25": 5,
|
"60": 2,
|
||||||
"30": 5,
|
"70": 2,
|
||||||
"35": 5,
|
"75": 1
|
||||||
"40": 5,
|
},
|
||||||
"50": 5,
|
"adjustWaves": true
|
||||||
"60": 2,
|
|
||||||
"80": 1
|
|
||||||
},
|
},
|
||||||
"adjustWaves": true
|
"interchange": {
|
||||||
},
|
"reduceLootByPercent": true,
|
||||||
"rezervbase": {
|
"minDynamicLootPercent": 50,
|
||||||
"reduceLootByPercent": true,
|
"minStaticLootPercent": 40,
|
||||||
"minDynamicLootPercent": 50,
|
"reducedChancePercent": 95,
|
||||||
"minStaticLootPercent": 40,
|
"reductionPercentWeights": {
|
||||||
"reducedChancePercent": 70,
|
"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": 95,
|
||||||
|
|
||||||
"reductionPercentWeights": {
|
"reductionPercentWeights": {
|
||||||
"20": 3,
|
"20": 3,
|
||||||
"30": 3,
|
"30": 3,
|
||||||
"40": 4,
|
"40": 4,
|
||||||
"50": 4,
|
"50": 4,
|
||||||
"60": 2,
|
"60": 2,
|
||||||
"70": 1,
|
"70": 1,
|
||||||
"80": 1
|
"80": 1
|
||||||
|
},
|
||||||
|
"adjustWaves": true
|
||||||
},
|
},
|
||||||
"adjustWaves": true
|
"laboratory": {
|
||||||
},
|
"reduceLootByPercent": true,
|
||||||
"laboratory": {
|
"minDynamicLootPercent": 50,
|
||||||
"reduceLootByPercent": true,
|
"minStaticLootPercent": 40,
|
||||||
"minDynamicLootPercent": 50,
|
"reducedChancePercent": 95,
|
||||||
"minStaticLootPercent": 40,
|
"reductionPercentWeights": {
|
||||||
"reducedChancePercent": 70,
|
"20": 3,
|
||||||
"reductionPercentWeights": {
|
"30": 5,
|
||||||
"20": 3,
|
"40": 5,
|
||||||
"30": 5,
|
"50": 5,
|
||||||
"40": 5,
|
"60": 2,
|
||||||
"50": 5,
|
"80": 1
|
||||||
"60": 2,
|
},
|
||||||
"80": 1
|
"adjustWaves": true
|
||||||
},
|
},
|
||||||
"adjustWaves": true
|
"lighthouse": {
|
||||||
},
|
"reduceLootByPercent": true,
|
||||||
"lighthouse": {
|
"minDynamicLootPercent": 50,
|
||||||
"reduceLootByPercent": true,
|
"minStaticLootPercent": 40,
|
||||||
"minDynamicLootPercent": 50,
|
"reducedChancePercent": 95,
|
||||||
"minStaticLootPercent": 40,
|
"reductionPercentWeights": {
|
||||||
"reducedChancePercent": 60,
|
"20": 2,
|
||||||
"reductionPercentWeights": {
|
"25": 2,
|
||||||
"20": 2,
|
"30": 4,
|
||||||
"25": 2,
|
"40": 4,
|
||||||
"30": 4,
|
"50": 4,
|
||||||
"40": 4,
|
"60": 2,
|
||||||
"50": 4,
|
"80": 1
|
||||||
"60": 2,
|
},
|
||||||
"80": 1
|
"adjustWaves": true
|
||||||
},
|
},
|
||||||
"adjustWaves": true
|
"shoreline": {
|
||||||
},
|
"reduceLootByPercent": true,
|
||||||
"shoreline": {
|
"minDynamicLootPercent": 50,
|
||||||
"reduceLootByPercent": true,
|
"minStaticLootPercent": 40,
|
||||||
"minDynamicLootPercent": 50,
|
"reducedChancePercent": 95,
|
||||||
"minStaticLootPercent": 40,
|
"reductionPercentWeights": {
|
||||||
"reducedChancePercent": 60,
|
"20": 2,
|
||||||
"reductionPercentWeights": {
|
"25": 3,
|
||||||
"20": 2,
|
"30": 5,
|
||||||
"25": 3,
|
"35": 5,
|
||||||
"30": 5,
|
"40": 5,
|
||||||
"35": 5,
|
"50": 5,
|
||||||
"40": 5,
|
"60": 2,
|
||||||
"50": 5,
|
"70": 1,
|
||||||
"60": 2,
|
"80": 1
|
||||||
"70": 1,
|
},
|
||||||
"80": 1
|
"adjustWaves": true
|
||||||
},
|
},
|
||||||
"adjustWaves": true
|
"tarkovstreets": {
|
||||||
},
|
"reduceLootByPercent": true,
|
||||||
"tarkovstreets": {
|
"minDynamicLootPercent": 50,
|
||||||
"reduceLootByPercent": true,
|
"minStaticLootPercent": 40,
|
||||||
"minDynamicLootPercent": 50,
|
"reducedChancePercent": 95,
|
||||||
"minStaticLootPercent": 40,
|
"reductionPercentWeights": {
|
||||||
"reducedChancePercent": 70,
|
"20": 2,
|
||||||
"reductionPercentWeights": {
|
"30": 4,
|
||||||
"20": 2,
|
"40": 4,
|
||||||
"30": 4,
|
"50": 4,
|
||||||
"40": 4,
|
"60": 4,
|
||||||
"50": 4,
|
"70": 1,
|
||||||
"60": 4,
|
"80": 1
|
||||||
"70": 1,
|
},
|
||||||
"80": 1
|
"adjustWaves": true
|
||||||
},
|
},
|
||||||
"adjustWaves": true
|
"woods": {
|
||||||
},
|
"reduceLootByPercent": true,
|
||||||
"woods": {
|
"minDynamicLootPercent": 50,
|
||||||
"reduceLootByPercent": true,
|
"minStaticLootPercent": 40,
|
||||||
"minDynamicLootPercent": 50,
|
"reducedChancePercent": 95,
|
||||||
"minStaticLootPercent": 40,
|
"reductionPercentWeights": {
|
||||||
"reducedChancePercent": 60,
|
"20": 3,
|
||||||
"reductionPercentWeights": {
|
"30": 5,
|
||||||
"20": 3,
|
"40": 5,
|
||||||
"30": 5,
|
"50": 5,
|
||||||
"40": 5,
|
"60": 1,
|
||||||
"50": 5,
|
"70": 1,
|
||||||
"60": 1,
|
"80": 1
|
||||||
"70": 1,
|
},
|
||||||
"80": 1
|
"adjustWaves": true
|
||||||
},
|
},
|
||||||
"adjustWaves": true
|
"default": {
|
||||||
},
|
"reduceLootByPercent": true,
|
||||||
"default": {
|
"minDynamicLootPercent": 50,
|
||||||
"reduceLootByPercent": true,
|
"minStaticLootPercent": 50,
|
||||||
"minDynamicLootPercent": 50,
|
"reducedChancePercent": 95,
|
||||||
"minStaticLootPercent": 50,
|
"reductionPercentWeights": {
|
||||||
"reducedChancePercent": 50,
|
"10": 1,
|
||||||
"reductionPercentWeights": {
|
"20": 2,
|
||||||
"10": 1,
|
"30": 5,
|
||||||
"20": 2,
|
"40": 5,
|
||||||
"30": 5,
|
"50": 5,
|
||||||
"40": 5,
|
"60": 2,
|
||||||
"50": 5,
|
"70": 1,
|
||||||
"60": 2,
|
"80": 1
|
||||||
"70": 1,
|
},
|
||||||
"80": 1
|
"adjustWaves": true
|
||||||
},
|
}
|
||||||
"adjustWaves": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
{
|
{
|
||||||
|
"fail": {},
|
||||||
"started": {},
|
"started": {},
|
||||||
"success": {
|
"success": {
|
||||||
"6507ff21644a656aee0f758f": "596b455186f77457cb50eccb",
|
"6492e44bf4287b13040fcbae": "6179b5eabca27a099552e052",
|
||||||
"6507ff21644a656aee0f74b7": "5b4794cb86f774598100d5d4",
|
"6492e44bf4287b13040fccf6": "647710905320c660d91c15a5",
|
||||||
"6507ff20644a656aee0f744d": "5c0bbaa886f7746941031d82",
|
"64a8578f0e9876295f0f83ed": "649af47d717cb30e7e4b5e26",
|
||||||
"6507ff22644a656aee0f75d3": "5c0bbaa886f7746941031d82",
|
"64a8578f0e9876295f0f83ee": "649af47d717cb30e7e4b5e26",
|
||||||
"6507ff20644a656aee0f73e4": "596b36c586f77450d6045ad2",
|
"64a8578f0e9876295f0f83ef": "649af47d717cb30e7e4b5e26",
|
||||||
"6507ff22644a656aee0f76e1": "596b36c586f77450d6045ad2",
|
|
||||||
"6507ff20644a656aee0f743f": "5979eee086f774311955e614",
|
|
||||||
"6507ff22644a656aee0f75e5": "5b478ff486f7744d184ecbbf",
|
|
||||||
"6507ff21644a656aee0f75a8": "5a27d2af86f7744e1115b323",
|
|
||||||
"6507ff21644a656aee0f7481": "5c0bdb5286f774166e38eed4",
|
|
||||||
"6507ff20644a656aee0f744b": "5c1234c286f77406fa13baeb",
|
|
||||||
"6507ff20644a656aee0f7465": "596b43fb86f77457ca186186",
|
|
||||||
"6507ff20644a656aee0f7447": "5a27b87686f77460de0252a8",
|
|
||||||
"6507ff20644a656aee0f73d6": "5967725e86f774601a446662",
|
|
||||||
"652376e2f6c67195e4061382": "6179b5eabca27a099552e052",
|
|
||||||
"6507ff20644a656aee0f73bc": "6193850f60b34236ee0483de",
|
|
||||||
"6507ff20644a656aee0f738e": "6179b4f16e9dd54ac275e407",
|
"6507ff20644a656aee0f738e": "6179b4f16e9dd54ac275e407",
|
||||||
|
"6507ff20644a656aee0f73bc": "6193850f60b34236ee0483de",
|
||||||
"6507ff20644a656aee0f73d4": "6179b4f16e9dd54ac275e407",
|
"6507ff20644a656aee0f73d4": "6179b4f16e9dd54ac275e407",
|
||||||
|
"6507ff20644a656aee0f73d6": "5967725e86f774601a446662",
|
||||||
|
"6507ff20644a656aee0f73e4": "596b36c586f77450d6045ad2",
|
||||||
|
"6507ff20644a656aee0f743f": "5979eee086f774311955e614",
|
||||||
|
"6507ff20644a656aee0f7447": "5a27b87686f77460de0252a8",
|
||||||
|
"6507ff20644a656aee0f744b": "5c1234c286f77406fa13baeb",
|
||||||
|
"6507ff20644a656aee0f744d": "5c0bbaa886f7746941031d82",
|
||||||
|
"6507ff20644a656aee0f7465": "596b43fb86f77457ca186186",
|
||||||
|
"6507ff21644a656aee0f7481": "5c0bdb5286f774166e38eed4",
|
||||||
"6507ff21644a656aee0f7498": "6179b4f16e9dd54ac275e407",
|
"6507ff21644a656aee0f7498": "6179b4f16e9dd54ac275e407",
|
||||||
"6507ff21644a656aee0f74a6": "5ac242ab86f77412464f68b4",
|
"6507ff21644a656aee0f74a6": "5ac242ab86f77412464f68b4",
|
||||||
"6507ff21644a656aee0f757d": "639873003693c63d86328f25",
|
"6507ff21644a656aee0f74b7": "5b4794cb86f774598100d5d4",
|
||||||
"6507ff22644a656aee0f7624": "64f5e20652fc01298e2c61e3",
|
|
||||||
"6507ff21644a656aee0f751c": "64f6aafd67e11a7c6206e0d0",
|
"6507ff21644a656aee0f751c": "64f6aafd67e11a7c6206e0d0",
|
||||||
"64cac5c1d45ace5bc90c74a8": "649af47d717cb30e7e4b5e26",
|
"6507ff21644a656aee0f757d": "639873003693c63d86328f25",
|
||||||
"64cac5c1d45ace5bc90c74a9": "649af47d717cb30e7e4b5e26",
|
"6507ff21644a656aee0f758f": "596b455186f77457cb50eccb",
|
||||||
"64cac5c1d45ace5bc90c74aa": "649af47d717cb30e7e4b5e26",
|
"6507ff21644a656aee0f75a8": "5a27d2af86f7744e1115b323",
|
||||||
"64cac5c1d45ace5bc90c74ab": "647710905320c660d91c15a5"
|
"6507ff22644a656aee0f75d3": "5c0bbaa886f7746941031d82",
|
||||||
},
|
"6507ff22644a656aee0f75e5": "5b478ff486f7744d184ecbbf",
|
||||||
"fail": {}
|
"6507ff22644a656aee0f7624": "64f5e20652fc01298e2c61e3",
|
||||||
|
"6507ff22644a656aee0f76e1": "596b36c586f77450d6045ad2"
|
||||||
|
}
|
||||||
}
|
}
|
@ -320,6 +320,7 @@ export class HideoutController
|
|||||||
{
|
{
|
||||||
// Update existing items container tpl to point to new id (tpl)
|
// Update existing items container tpl to point to new id (tpl)
|
||||||
existingInventoryItem._tpl = hideoutStage.container;
|
existingInventoryItem._tpl = hideoutStage.container;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +358,7 @@ export class HideoutController
|
|||||||
* Handle HideoutPutItemsInAreaSlots
|
* Handle HideoutPutItemsInAreaSlots
|
||||||
* Create item in hideout slot item array, remove item from player inventory
|
* Create item in hideout slot item array, remove item from player inventory
|
||||||
* @param pmcData Profile data
|
* @param pmcData Profile data
|
||||||
* @param addItemToHideoutRequest request from client to place item in area slot
|
* @param addItemToHideoutRequest reqeust from client to place item in area slot
|
||||||
* @param sessionID Session id
|
* @param sessionID Session id
|
||||||
* @returns IItemEventRouterResponse object
|
* @returns IItemEventRouterResponse object
|
||||||
*/
|
*/
|
||||||
@ -490,7 +491,14 @@ export class HideoutController
|
|||||||
|
|
||||||
const itemToReturn = hideoutArea.slots.find((x) => x.locationIndex === slotIndexToRemove).item[0];
|
const itemToReturn = hideoutArea.slots.find((x) => x.locationIndex === slotIndexToRemove).item[0];
|
||||||
|
|
||||||
const newReq = { items: [{ item_id: itemToReturn._tpl, count: 1 }], tid: "ragfair" };
|
const newReq = {
|
||||||
|
items: [{
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
item_id: itemToReturn._tpl,
|
||||||
|
count: 1,
|
||||||
|
}],
|
||||||
|
tid: "ragfair",
|
||||||
|
};
|
||||||
|
|
||||||
output = this.inventoryHelper.addItem(
|
output = this.inventoryHelper.addItem(
|
||||||
pmcData,
|
pmcData,
|
||||||
@ -550,7 +558,7 @@ export class HideoutController
|
|||||||
* Handle HideoutSingleProductionStart event
|
* Handle HideoutSingleProductionStart event
|
||||||
* Start production for an item from hideout area
|
* Start production for an item from hideout area
|
||||||
* @param pmcData Player profile
|
* @param pmcData Player profile
|
||||||
* @param body Start production of single item request
|
* @param body Start prodution of single item request
|
||||||
* @param sessionID Session id
|
* @param sessionID Session id
|
||||||
* @returns IItemEventRouterResponse
|
* @returns IItemEventRouterResponse
|
||||||
*/
|
*/
|
||||||
@ -665,6 +673,7 @@ export class HideoutController
|
|||||||
{
|
{
|
||||||
return productionTime;
|
return productionTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
return productionTime * fenceLevel.ScavCaseTimeModifier;
|
return productionTime * fenceLevel.ScavCaseTimeModifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,7 +691,7 @@ export class HideoutController
|
|||||||
/**
|
/**
|
||||||
* Start production of continuously created item
|
* Start production of continuously created item
|
||||||
* @param pmcData Player profile
|
* @param pmcData Player profile
|
||||||
* @param request Continuous production request
|
* @param request Continious production request
|
||||||
* @param sessionID Session id
|
* @param sessionID Session id
|
||||||
* @returns IItemEventRouterResponse
|
* @returns IItemEventRouterResponse
|
||||||
*/
|
*/
|
||||||
@ -693,6 +702,7 @@ export class HideoutController
|
|||||||
): IItemEventRouterResponse
|
): IItemEventRouterResponse
|
||||||
{
|
{
|
||||||
this.registerProduction(pmcData, request, sessionID);
|
this.registerProduction(pmcData, request, sessionID);
|
||||||
|
|
||||||
return this.eventOutputHolder.getOutput(sessionID);
|
return this.eventOutputHolder.getOutput(sessionID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,7 +767,7 @@ export class HideoutController
|
|||||||
output: IItemEventRouterResponse,
|
output: IItemEventRouterResponse,
|
||||||
): IItemEventRouterResponse
|
): IItemEventRouterResponse
|
||||||
{
|
{
|
||||||
// Variables for management of skill
|
// Variables for managemnet of skill
|
||||||
let craftingExpAmount = 0;
|
let craftingExpAmount = 0;
|
||||||
|
|
||||||
// ? move the logic of BackendCounters in new method?
|
// ? move the logic of BackendCounters in new method?
|
||||||
@ -781,7 +791,14 @@ export class HideoutController
|
|||||||
id = this.presetHelper.getDefaultPreset(id)._id;
|
id = this.presetHelper.getDefaultPreset(id)._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newReq = { items: [{ item_id: id, count: recipe.count }], tid: "ragfair" };
|
const newReq = {
|
||||||
|
items: [{
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
item_id: id,
|
||||||
|
count: recipe.count,
|
||||||
|
}],
|
||||||
|
tid: "ragfair",
|
||||||
|
};
|
||||||
|
|
||||||
const entries = Object.entries(pmcData.Hideout.Production);
|
const entries = Object.entries(pmcData.Hideout.Production);
|
||||||
let prodId: string;
|
let prodId: string;
|
||||||
@ -901,7 +918,6 @@ export class HideoutController
|
|||||||
let prodId: string;
|
let prodId: string;
|
||||||
for (const production of ongoingProductions)
|
for (const production of ongoingProductions)
|
||||||
{
|
{
|
||||||
// Production or ScavCase
|
|
||||||
if (this.hideoutHelper.isProductionType(production[1]))
|
if (this.hideoutHelper.isProductionType(production[1]))
|
||||||
{ // Production or ScavCase
|
{ // Production or ScavCase
|
||||||
if ((production[1] as ScavCase).RecipeId === request.recipeId)
|
if ((production[1] as ScavCase).RecipeId === request.recipeId)
|
||||||
@ -927,34 +943,38 @@ export class HideoutController
|
|||||||
// Create rewards for scav case
|
// Create rewards for scav case
|
||||||
const scavCaseRewards = this.scavCaseRewardGenerator.generate(request.recipeId);
|
const scavCaseRewards = this.scavCaseRewardGenerator.generate(request.recipeId);
|
||||||
|
|
||||||
|
// Add scav case rewards to player profile
|
||||||
pmcData.Hideout.Production[prodId].Products = scavCaseRewards;
|
pmcData.Hideout.Production[prodId].Products = scavCaseRewards;
|
||||||
|
|
||||||
// Remove the old production from output object before its sent to client
|
// Remove the old production from output object before its sent to client
|
||||||
delete output.profileChanges[sessionID].production[request.recipeId];
|
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(
|
const itemsToAdd = pmcData.Hideout.Production[prodId].Products.map(
|
||||||
(x: { _tpl: string; upd?: { StackObjectsCount?: number; }; }) =>
|
(x: { _tpl: string; upd?: { StackObjectsCount?: number; }; }) =>
|
||||||
{
|
{
|
||||||
let id = x._tpl;
|
const itemTpl = this.presetHelper.hasPreset(x._tpl)
|
||||||
if (this.presetHelper.hasPreset(id))
|
? this.presetHelper.getDefaultPreset(x._tpl)._id
|
||||||
{
|
: x._tpl;
|
||||||
id = this.presetHelper.getDefaultPreset(id)._id;
|
|
||||||
}
|
// Count of items crafted
|
||||||
const numOfItems = !x.upd?.StackObjectsCount ? 1 : x.upd.StackObjectsCount;
|
const numOfItems = !x.upd?.StackObjectsCount ? 1 : x.upd.StackObjectsCount;
|
||||||
return { item_id: id, count: numOfItems };
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
return { item_id: itemTpl, count: numOfItems };
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const newReq = { items: itemsToAdd, tid: "ragfair" };
|
const newReq = { items: itemsToAdd, tid: "ragfair" };
|
||||||
|
|
||||||
const callback = () =>
|
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;
|
pmcData.Hideout.Production[prodId].sptIsComplete = true;
|
||||||
|
|
||||||
|
// Crafting complete, flag as such
|
||||||
pmcData.Hideout.Production[prodId].inProgress = false;
|
pmcData.Hideout.Production[prodId].inProgress = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add crafted item to player inventory
|
||||||
return this.inventoryHelper.addItem(pmcData, newReq, output, sessionID, callback, true);
|
return this.inventoryHelper.addItem(pmcData, newReq, output, sessionID, callback, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -976,10 +996,11 @@ export class HideoutController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get quick time event list for hideout
|
* Get quick time event list for hideout
|
||||||
* // TODO: Implement this
|
* // TODO - implement this
|
||||||
* @param sessionId Session id
|
* @param sessionId Session id
|
||||||
* @returns IQteData array
|
* @returns IQteData array
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
public getQteList(sessionId: string): IQteData[]
|
public getQteList(sessionId: string): IQteData[]
|
||||||
{
|
{
|
||||||
return this.databaseServer.getTables().hideout.qte;
|
return this.databaseServer.getTables().hideout.qte;
|
||||||
@ -992,6 +1013,7 @@ export class HideoutController
|
|||||||
* @param pmcData Profile to adjust
|
* @param pmcData Profile to adjust
|
||||||
* @param request QTE result object
|
* @param request QTE result object
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
public handleQTEEventOutcome(
|
public handleQTEEventOutcome(
|
||||||
sessionId: string,
|
sessionId: string,
|
||||||
pmcData: IPmcData,
|
pmcData: IPmcData,
|
||||||
@ -999,10 +1021,10 @@ export class HideoutController
|
|||||||
): IItemEventRouterResponse
|
): IItemEventRouterResponse
|
||||||
{
|
{
|
||||||
// {
|
// {
|
||||||
// Action: "HideoutQuickTimeEvent",
|
// "Action": "HideoutQuickTimeEvent",
|
||||||
// results: [true, false, true, true, true, true, true, true, true, false, false, false, false, false, false],
|
// "results": [true, false, true, true, true, true, true, true, true, false, false, false, false, false, false],
|
||||||
// id: "63b16feb5d012c402c01f6ef",
|
// "id": "63b16feb5d012c402c01f6ef",
|
||||||
// timestamp: 1672585349
|
// "timestamp": 1672585349
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Skill changes are done in
|
// Skill changes are done in
|
||||||
@ -1036,7 +1058,7 @@ export class HideoutController
|
|||||||
request: IRecordShootingRangePoints,
|
request: IRecordShootingRangePoints,
|
||||||
): IItemEventRouterResponse
|
): IItemEventRouterResponse
|
||||||
{
|
{
|
||||||
// Check if counter exists, add placeholder if it doesn't
|
// Check if counter exists, add placeholder if it doesnt
|
||||||
if (!pmcData.Stats.Eft.OverallCounters.Items.find((x) => x.Key.includes("ShootingRangePoints")))
|
if (!pmcData.Stats.Eft.OverallCounters.Items.find((x) => x.Key.includes("ShootingRangePoints")))
|
||||||
{
|
{
|
||||||
pmcData.Stats.Eft.OverallCounters.Items.push({ Key: ["ShootingRangePoints"], Value: 0 });
|
pmcData.Stats.Eft.OverallCounters.Items.push({ Key: ["ShootingRangePoints"], Value: 0 });
|
||||||
@ -1048,7 +1070,7 @@ export class HideoutController
|
|||||||
);
|
);
|
||||||
shootingRangeHighScore.Value = request.points;
|
shootingRangeHighScore.Value = request.points;
|
||||||
|
|
||||||
// Check against live, maybe a response isn't necessary
|
// Check against live, maybe a response isnt necessary
|
||||||
return this.eventOutputHolder.getOutput(sessionId);
|
return this.eventOutputHolder.getOutput(sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1066,7 +1088,7 @@ export class HideoutController
|
|||||||
{
|
{
|
||||||
const output = this.eventOutputHolder.getOutput(sessionId);
|
const output = this.eventOutputHolder.getOutput(sessionId);
|
||||||
|
|
||||||
// Create mapping of required item with corresponding item from player inventory
|
// Create mapping of required item with corrisponding item from player inventory
|
||||||
const items = request.items.map((reqItem) =>
|
const items = request.items.map((reqItem) =>
|
||||||
{
|
{
|
||||||
const item = pmcData.Inventory.items.find((invItem) => invItem._id === reqItem.id);
|
const item = pmcData.Inventory.items.find((invItem) => invItem._id === reqItem.id);
|
||||||
@ -1115,7 +1137,7 @@ export class HideoutController
|
|||||||
return this.httpResponse.appendErrorToOutput(output);
|
return this.httpResponse.appendErrorToOutput(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all improvements to output object
|
// Add all improvemets to output object
|
||||||
const improvements = hideoutDbData.stages[profileHideoutArea.level].improvements;
|
const improvements = hideoutDbData.stages[profileHideoutArea.level].improvements;
|
||||||
const timestamp = this.timeUtil.getTimestamp();
|
const timestamp = this.timeUtil.getTimestamp();
|
||||||
|
|
||||||
@ -1164,7 +1186,7 @@ export class HideoutController
|
|||||||
// Null out production data so client gets informed when response send back
|
// Null out production data so client gets informed when response send back
|
||||||
pmcData.Hideout.Production[request.recipeId] = null;
|
pmcData.Hideout.Production[request.recipeId] = null;
|
||||||
|
|
||||||
// TODO: handle timestamp somehow?
|
// TODO - handle timestamp somehow?
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
@ -107,17 +107,17 @@ export class InraidController
|
|||||||
*/
|
*/
|
||||||
protected savePmcProgress(sessionID: string, postRaidRequest: ISaveProgressRequestData): void
|
protected savePmcProgress(sessionID: string, postRaidRequest: ISaveProgressRequestData): void
|
||||||
{
|
{
|
||||||
const serveProfile = this.saveServer.getProfile(sessionID);
|
const serverProfile = this.saveServer.getProfile(sessionID);
|
||||||
const locationName = serveProfile.inraid.location.toLowerCase();
|
const locationName = serverProfile.inraid.location.toLowerCase();
|
||||||
|
|
||||||
const map: ILocationBase = this.databaseServer.getTables().locations[locationName].base;
|
const map: ILocationBase = this.databaseServer.getTables().locations[locationName].base;
|
||||||
const mapHasInsuranceEnabled = map.Insurance;
|
const mapHasInsuranceEnabled = map.Insurance;
|
||||||
|
|
||||||
let serverPmcProfile = serveProfile.characters.pmc;
|
let serverPmcProfile = serverProfile.characters.pmc;
|
||||||
const isDead = this.isPlayerDead(postRaidRequest.exit);
|
const isDead = this.isPlayerDead(postRaidRequest.exit);
|
||||||
const preRaidGear = this.inRaidHelper.getPlayerGear(serverPmcProfile.Inventory.items);
|
const preRaidGear = this.inRaidHelper.getPlayerGear(serverPmcProfile.Inventory.items);
|
||||||
|
|
||||||
serveProfile.inraid.character = "pmc";
|
serverProfile.inraid.character = "pmc";
|
||||||
|
|
||||||
this.inRaidHelper.updateProfileBaseStats(serverPmcProfile, postRaidRequest, sessionID);
|
this.inRaidHelper.updateProfileBaseStats(serverPmcProfile, postRaidRequest, sessionID);
|
||||||
this.inRaidHelper.updatePmcProfileDataPostRaid(serverPmcProfile, postRaidRequest, sessionID);
|
this.inRaidHelper.updatePmcProfileDataPostRaid(serverPmcProfile, postRaidRequest, sessionID);
|
||||||
@ -220,7 +220,7 @@ export class InraidController
|
|||||||
activeQuestIdsInProfile,
|
activeQuestIdsInProfile,
|
||||||
allQuests,
|
allQuests,
|
||||||
);
|
);
|
||||||
if (questAndFindItemConditionId)
|
if (Object.keys(questAndFindItemConditionId)?.length > 0)
|
||||||
{
|
{
|
||||||
this.profileHelper.removeCompletedQuestConditionFromProfile(pmcData, questAndFindItemConditionId);
|
this.profileHelper.removeCompletedQuestConditionFromProfile(pmcData, questAndFindItemConditionId);
|
||||||
}
|
}
|
||||||
|
@ -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
|
// Iterate over each grid in the container and look for a big enough space for the item to be placed in
|
||||||
let currentGridCount = 1;
|
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)
|
for (const slotGrid of containerTemplate[1]._props.Grids)
|
||||||
{
|
{
|
||||||
// Grid is empty, skip
|
// 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 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;
|
return ItemAddedResult.NO_SPACE;
|
||||||
}
|
}
|
||||||
|
@ -218,7 +218,7 @@ export class InRaidHelper
|
|||||||
public updatePmcProfileDataPostRaid(pmcData: IPmcData, saveProgressRequest: ISaveProgressRequestData, sessionId: string): void
|
public updatePmcProfileDataPostRaid(pmcData: IPmcData, saveProgressRequest: ISaveProgressRequestData, sessionId: string): void
|
||||||
{
|
{
|
||||||
// Process failed quests then copy everything
|
// 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;
|
pmcData.Quests = saveProgressRequest.profile.Quests;
|
||||||
|
|
||||||
// No need to do this for scav, old scav is deleted and new one generated
|
// 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 sessionId Player id
|
||||||
* @param pmcData Player profile
|
* @param pmcData Player profile
|
||||||
* @param preRaidQuests Quests prior to starting raid
|
* @param preRaidQuests Quests prior to starting raid
|
||||||
* @param postRaidQuests Quest after raid
|
* @param postRaidProfile Profile sent by client
|
||||||
*/
|
*/
|
||||||
protected processFailedQuests(
|
protected processFailedQuests(
|
||||||
sessionId: string,
|
sessionId: string,
|
||||||
pmcData: IPmcData,
|
pmcData: IPmcData,
|
||||||
preRaidQuests: IQuestStatus[],
|
preRaidQuests: IQuestStatus[],
|
||||||
postRaidQuests: IQuestStatus[],
|
postRaidProfile: IPostRaidPmcData,
|
||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
if (!preRaidQuests)
|
if (!preRaidQuests)
|
||||||
@ -270,24 +270,81 @@ export class InRaidHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Loop over all quests from post-raid profile
|
// 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);
|
const preRaidQuest = preRaidQuests?.find((x) => x.qid === postRaidQuest.qid);
|
||||||
if (preRaidQuest)
|
if (!preRaidQuest)
|
||||||
{
|
{
|
||||||
// Post-raid quest is failed but wasn't pre-raid
|
continue;
|
||||||
// postRaidQuest.status has a weird value, need to do some nasty casting to compare it
|
}
|
||||||
if (<string><unknown>postRaidQuest.status === "Fail" && preRaidQuest.status !== QuestStatus.Fail)
|
|
||||||
|
// 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 = <string><unknown>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
|
// Find all items the failed quest wanted
|
||||||
const failBody: IFailQuestRequestData = {
|
for (const condition of matchingAffFindConditions)
|
||||||
Action: "QuestComplete",
|
{
|
||||||
qid: postRaidQuest.qid,
|
itemsToCollect.push(...condition._props.target);
|
||||||
removeExcessItems: true,
|
}
|
||||||
};
|
|
||||||
this.questHelper.failQuest(pmcData, failBody, sessionId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -951,7 +951,7 @@ export class QuestHelper
|
|||||||
const questInDb = allQuests.find((x) => x._id === questId);
|
const questInDb = allQuests.find((x) => x._id === questId);
|
||||||
if (!questInDb)
|
if (!questInDb)
|
||||||
{
|
{
|
||||||
this.logger.warning(
|
this.logger.debug(
|
||||||
`Unable to find quest: ${questId} in db, cannot get 'FindItem' condition, skipping`,
|
`Unable to find quest: ${questId} in db, cannot get 'FindItem' condition, skipping`,
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -22,6 +22,7 @@ export class WeightedRandomHelper
|
|||||||
{
|
{
|
||||||
const itemKeys = Object.keys(itemArray);
|
const itemKeys = Object.keys(itemArray);
|
||||||
const weights = Object.values(itemArray);
|
const weights = Object.values(itemArray);
|
||||||
|
|
||||||
const chosenItem = this.weightedRandom(itemKeys, weights);
|
const chosenItem = this.weightedRandom(itemKeys, weights);
|
||||||
|
|
||||||
return chosenItem.item;
|
return chosenItem.item;
|
||||||
@ -41,18 +42,23 @@ export class WeightedRandomHelper
|
|||||||
* @param {number[]} weights
|
* @param {number[]} weights
|
||||||
* @returns {{item: any, index: number}}
|
* @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)
|
if (items.length !== weights.length)
|
||||||
{
|
{
|
||||||
throw new Error("Items and weight inputs must be of the same 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.
|
// Preparing the cumulative weights array.
|
||||||
// For example:
|
// For example:
|
||||||
// - weights = [1, 4, 3]
|
// - weights = [1, 4, 3]
|
||||||
|
@ -468,7 +468,7 @@ export interface IQuestStatus
|
|||||||
startTime: number;
|
startTime: number;
|
||||||
status: QuestStatus;
|
status: QuestStatus;
|
||||||
statusTimers?: Record<string, number>;
|
statusTimers?: Record<string, number>;
|
||||||
/** SPT specific property */
|
/** Property does not exist in live profile data, but is used by ProfileChanges.questsStatus when sent to client*/
|
||||||
completedConditions?: string[];
|
completedConditions?: string[];
|
||||||
availableAfter?: number;
|
availableAfter?: number;
|
||||||
}
|
}
|
||||||
@ -483,16 +483,6 @@ export interface TraderInfo
|
|||||||
disabled: boolean;
|
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
|
export interface RagfairInfo
|
||||||
{
|
{
|
||||||
rating: number;
|
rating: number;
|
||||||
|
@ -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 { Item, Upd } from "@spt-aki/models/eft/common/tables/IItem";
|
||||||
import { IQuest } from "@spt-aki/models/eft/common/tables/IQuest";
|
import { IQuest } from "@spt-aki/models/eft/common/tables/IQuest";
|
||||||
import { IPmcDataRepeatableQuest } from "@spt-aki/models/eft/common/tables/IRepeatableQuests";
|
import { IPmcDataRepeatableQuest } from "@spt-aki/models/eft/common/tables/IRepeatableQuests";
|
||||||
@ -80,6 +80,16 @@ export interface Improvement
|
|||||||
improveCompleteTimestamp: number;
|
improveCompleteTimestamp: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Related to TraderInfo */
|
||||||
|
export interface TraderData
|
||||||
|
{
|
||||||
|
salesSum: number;
|
||||||
|
standing: number;
|
||||||
|
loyalty: number;
|
||||||
|
unlocked: boolean;
|
||||||
|
disabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Product
|
export interface Product
|
||||||
{
|
{
|
||||||
_id: string;
|
_id: string;
|
||||||
|
@ -39,31 +39,7 @@ export interface ILocationConfig extends IBaseConfig
|
|||||||
/** Key: map, value: loose loot ids to ignore */
|
/** Key: map, value: loose loot ids to ignore */
|
||||||
looseLootBlacklist: Record<string, string[]>;
|
looseLootBlacklist: Record<string, string[]>;
|
||||||
/** Key: map, value: settings to control how long scav raids are*/
|
/** Key: map, value: settings to control how long scav raids are*/
|
||||||
scavRaidTimeSettings: Record<string, IScavRaidTimeLocationSettings>;
|
scavRaidTimeSettings: IScavRaidTimeSettings;
|
||||||
}
|
|
||||||
|
|
||||||
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<string, number>;
|
|
||||||
/** 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<string, boolean>;
|
|
||||||
/** Some container types don't work when randomised */
|
|
||||||
containerTypesToNotRandomise: string[];
|
|
||||||
containerGroupMinSizeMultiplier: number;
|
|
||||||
containerGroupMaxSizeMultiplier: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFixEmptyBotWavesSettings
|
export interface IFixEmptyBotWavesSettings
|
||||||
@ -117,3 +93,38 @@ export interface LootMultiplier
|
|||||||
terminal: number;
|
terminal: number;
|
||||||
town: number;
|
town: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IContainerRandomistionSettings
|
||||||
|
{
|
||||||
|
enabled: boolean;
|
||||||
|
/** What maps can use the container randomisation feature */
|
||||||
|
maps: Record<string, boolean>;
|
||||||
|
/** Some container types don't work when randomised */
|
||||||
|
containerTypesToNotRandomise: string[];
|
||||||
|
containerGroupMinSizeMultiplier: number;
|
||||||
|
containerGroupMaxSizeMultiplier: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IScavRaidTimeSettings
|
||||||
|
{
|
||||||
|
settings: IScavRaidTimeConfigSettings
|
||||||
|
maps: Record<string, IScavRaidTimeLocationSettings>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IScavRaidTimeConfigSettings
|
||||||
|
{
|
||||||
|
trainArrivalDelayObservedSeconds: 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<string, number>;
|
||||||
|
/** Should bot waves be removed / spawn times be adjusted */
|
||||||
|
adjustWaves: boolean;
|
||||||
|
}
|
||||||
|
@ -2,8 +2,8 @@ import { inject, injectable } from "tsyringe";
|
|||||||
|
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
import { IHideoutImprovement, Productive, TraderData, TraderInfo } from "@spt-aki/models/eft/common/tables/IBotBase";
|
import { IHideoutImprovement, Productive, TraderInfo } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||||
import { ProfileChange } from "@spt-aki/models/eft/itemEvent/IItemEventRouterBase";
|
import { ProfileChange, TraderData } from "@spt-aki/models/eft/itemEvent/IItemEventRouterBase";
|
||||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||||
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||||
import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
||||||
|
@ -171,11 +171,11 @@ export class RaidTimeAdjustmentService
|
|||||||
*/
|
*/
|
||||||
protected getMapSettings(location: string): IScavRaidTimeLocationSettings
|
protected getMapSettings(location: string): IScavRaidTimeLocationSettings
|
||||||
{
|
{
|
||||||
const mapSettings = this.locationConfig.scavRaidTimeSettings[location.toLowerCase()];
|
const mapSettings = this.locationConfig.scavRaidTimeSettings.maps[location.toLowerCase()];
|
||||||
if (!mapSettings)
|
if (!mapSettings)
|
||||||
{
|
{
|
||||||
this.logger.warning(`Unable to find scav raid time settings for map: ${location}, using defaults`);
|
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;
|
return mapSettings;
|
||||||
@ -206,27 +206,47 @@ export class RaidTimeAdjustmentService
|
|||||||
Chance: 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 = 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;
|
||||||
|
|
||||||
// If raid is after last moment train can leave, assume train has already left, disable extract
|
// If raid is after last moment train can leave, assume train has already left, disable extract
|
||||||
const latestPossibleDepartureMinutes = (exit.MaxTime + exit.Count) / 60;
|
const mostPossibleTimeRemainingAfterDeparture = mapBase.EscapeTimeLimit - earliestPossibleDepartureMinutes;
|
||||||
if (newRaidTimeMinutes < latestPossibleDepartureMinutes)
|
if (newRaidTimeMinutes < mostPossibleTimeRemainingAfterDeparture)
|
||||||
{
|
{
|
||||||
exitChange.Chance = 0;
|
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);
|
result.push(exitChange);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// What minute we simulate the player joining a raid at
|
// Reduce extract arrival times. Negative values seem to make extract turn red in game.
|
||||||
const simulatedRaidEntryTimeMinutes = mapBase.EscapeTimeLimit - newRaidTimeMinutes;
|
exitChange.MinTime = Math.max(exit.MinTime - reductionSeconds, 0);
|
||||||
|
exitChange.MaxTime = Math.max(exit.MaxTime - reductionSeconds, 0);
|
||||||
// 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;
|
|
||||||
|
|
||||||
this.logger.debug(`Train appears between: ${exitChange.MinTime} and ${exitChange.MaxTime} seconds raid time`);
|
this.logger.debug(`Train appears between: ${exitChange.MinTime} and ${exitChange.MaxTime} seconds raid time`);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user