Merge branch 'master' of https://dev.sp-tarkov.com/SPT-AKI/Server into 3.8.0
# Conflicts: # project/src/context/ApplicationContext.ts # project/src/context/ContextVariableType.ts # project/src/controllers/QuestController.ts # project/src/di/Container.ts # project/src/generators/weapongen/implementations/ExternalInventoryMagGen.ts
This commit is contained in:
commit
2148eaafe5
@ -1526,6 +1526,58 @@
|
||||
"pmcBot": 0
|
||||
}
|
||||
},
|
||||
"playerScavBrainType": {
|
||||
"factory4_day": {
|
||||
"bossKilla": 1,
|
||||
"assault": 1,
|
||||
"pmcBot": 1
|
||||
},
|
||||
"factory4_night": {
|
||||
"bossKilla": 1,
|
||||
"assault": 1,
|
||||
"pmcBot": 1
|
||||
},
|
||||
"bigmap": {
|
||||
"bossKilla": 1,
|
||||
"assault": 1,
|
||||
"pmcBot": 1
|
||||
},
|
||||
"laboratory": {
|
||||
"bossKilla": 1,
|
||||
"assault": 1,
|
||||
"pmcBot": 1
|
||||
},
|
||||
"woods": {
|
||||
"bossKilla": 1,
|
||||
"assault": 1,
|
||||
"pmcBot": 1
|
||||
},
|
||||
"interchange": {
|
||||
"bossKilla": 1,
|
||||
"assault": 1,
|
||||
"pmcBot": 1
|
||||
},
|
||||
"lighthouse": {
|
||||
"bossKilla": 1,
|
||||
"assault": 1,
|
||||
"pmcBot": 1
|
||||
},
|
||||
"rezervbase": {
|
||||
"bossKilla": 1,
|
||||
"assault": 1,
|
||||
"pmcBot": 1
|
||||
},
|
||||
"shoreline": {
|
||||
"bossKilla": 1,
|
||||
"assault": 1,
|
||||
"pmcBot": 1
|
||||
},
|
||||
"tarkovstreets": {
|
||||
"bossKilla": 1,
|
||||
"assault": 1,
|
||||
"pmcBot": 1
|
||||
}
|
||||
},
|
||||
"maxBotCap": {
|
||||
"factory4_day": 13,
|
||||
"factory4_night": 13,
|
||||
|
@ -7,9 +7,10 @@
|
||||
"sptFriendNickname": "SPT",
|
||||
"fixes": {
|
||||
"fixShotgunDispersion": true,
|
||||
"removeModItemsFromProfile": false
|
||||
"removeModItemsFromProfile": false,
|
||||
"fixProfileBreakingInventoryItemIssues": false
|
||||
},
|
||||
"features": {
|
||||
"autoInstallModDependencies": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -793,5 +793,192 @@
|
||||
"minFillStaticMagazinePercent": 50,
|
||||
"makeWishingTreeAlwaysGiveGift": true,
|
||||
"allowDuplicateItemsInStaticContainers": true,
|
||||
"looseLootBlacklist": {}
|
||||
"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
|
||||
},
|
||||
"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
|
||||
},
|
||||
"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
|
||||
},
|
||||
"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
|
||||
},
|
||||
"adjustWaves": true
|
||||
},
|
||||
"laboratory": {
|
||||
"reduceLootByPercent": true,
|
||||
"minDynamicLootPercent": 50,
|
||||
"minStaticLootPercent": 40,
|
||||
"reducedChancePercent": 70,
|
||||
"reductionPercentWeights": {
|
||||
"20": 3,
|
||||
"30": 5,
|
||||
"40": 5,
|
||||
"50": 5,
|
||||
"60": 2,
|
||||
"80": 1
|
||||
},
|
||||
"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
|
||||
},
|
||||
"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
|
||||
},
|
||||
"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
|
||||
},
|
||||
"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
|
||||
},
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +128,13 @@
|
||||
"startTimestamp": 1701388800000,
|
||||
"endTimestamp": 1703980800000,
|
||||
"yearly": true
|
||||
},
|
||||
"655e427b64d09b4122018228": {
|
||||
"name": "The punisher - Harvest",
|
||||
"season": "None",
|
||||
"startTimestamp": 1341615600000,
|
||||
"endTimestamp": "",
|
||||
"yearly": false
|
||||
}
|
||||
},
|
||||
"repeatableQuests": [{
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -84042,5 +84042,403 @@
|
||||
"templateId": "64f83bd983cfca080a362c82",
|
||||
"traderId": "5a7c2eca46aef81a7ca2145d",
|
||||
"type": "WeaponAssembly"
|
||||
},
|
||||
"655e427b64d09b4122018228": {
|
||||
"QuestName": "The Punisher - Harvest",
|
||||
"_id": "655e427b64d09b4122018228",
|
||||
"acceptPlayerMessage": "655e427b64d09b4122018228 acceptPlayerMessage",
|
||||
"canShowNotificationsInGame": true,
|
||||
"changeQuestMessageText": "655e427b64d09b4122018228 changeQuestMessageText",
|
||||
"completePlayerMessage": "655e427b64d09b4122018228 completePlayerMessage",
|
||||
"conditions": {
|
||||
"AvailableForFinish": [
|
||||
{
|
||||
"_parent": "CounterCreator",
|
||||
"_props": {
|
||||
"counter": {
|
||||
"conditions": [
|
||||
{
|
||||
"_parent": "Kills",
|
||||
"_props": {
|
||||
"compareMethod": ">=",
|
||||
"id": "655e484b52dc506c051b4409",
|
||||
"target": "AnyPmc",
|
||||
"value": "1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"id": "655e483da3ee7d4c56241e18"
|
||||
},
|
||||
"doNotResetIfCounterCompleted": false,
|
||||
"dynamicLocale": false,
|
||||
"id": "655e483da3ee7d4c56241e17",
|
||||
"index": 0,
|
||||
"oneSessionOnly": false,
|
||||
"parentId": "",
|
||||
"type": "Elimination",
|
||||
"value": "50",
|
||||
"visibilityConditions": []
|
||||
},
|
||||
"dynamicLocale": false
|
||||
},
|
||||
{
|
||||
"_parent": "HandoverItem",
|
||||
"_props": {
|
||||
"dogtagLevel": "25",
|
||||
"dynamicLocale": false,
|
||||
"id": "655e49e942913d55e050376b",
|
||||
"index": 1,
|
||||
"isEncoded": false,
|
||||
"maxDurability": 100,
|
||||
"minDurability": 0,
|
||||
"onlyFoundInRaid": true,
|
||||
"parentId": "",
|
||||
"target": [
|
||||
"59f32bb586f774757e1e8442",
|
||||
"59f32c3b86f77472a31742f0"
|
||||
],
|
||||
"value": "50",
|
||||
"visibilityConditions": []
|
||||
},
|
||||
"dynamicLocale": false
|
||||
}
|
||||
],
|
||||
"AvailableForStart": [],
|
||||
"Fail": []
|
||||
},
|
||||
"description": "655e427b64d09b4122018228 description",
|
||||
"failMessageText": "655e427b64d09b4122018228 failMessageText",
|
||||
"image": "/files/quest/icon/59ca2e4186f77445e4732b22.jpg",
|
||||
"instantComplete": false,
|
||||
"isKey": false,
|
||||
"location": "any",
|
||||
"name": "655e427b64d09b4122018228 name",
|
||||
"note": "655e427b64d09b4122018228 note",
|
||||
"questStatus": {},
|
||||
"restartable": false,
|
||||
"rewards": {
|
||||
"Fail": [],
|
||||
"Started": [
|
||||
{
|
||||
"findInRaid": true,
|
||||
"id": "655f3fd9b4f3e80ef35495e7",
|
||||
"index": 0,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63e6",
|
||||
"_tpl": "60a283193cb70855c43a381d",
|
||||
"upd": {
|
||||
"StackObjectsCount": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"target": "656629d07cac3c3b160e63e6",
|
||||
"type": "Item",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"findInRaid": true,
|
||||
"id": "655f3fedd5e086614d342776",
|
||||
"index": 1,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63e7",
|
||||
"_tpl": "5f60c74e3b85f6263c145586",
|
||||
"upd": {
|
||||
"StackObjectsCount": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"target": "656629d07cac3c3b160e63e7",
|
||||
"type": "Item",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"findInRaid": true,
|
||||
"id": "655f3ff8691eb93295472576",
|
||||
"index": 2,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63e8",
|
||||
"_tpl": "5f60c85b58eff926626a60f7",
|
||||
"upd": {
|
||||
"StackObjectsCount": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"target": "656629d07cac3c3b160e63e8",
|
||||
"type": "Item",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"findInRaid": true,
|
||||
"id": "655f41f5fdc15c010d329535",
|
||||
"index": 3,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63e9",
|
||||
"_tpl": "5bb2475ed4351e00853264e3",
|
||||
"upd": {
|
||||
"Repairable": {
|
||||
"Durability": 100,
|
||||
"MaxDurability": 100
|
||||
},
|
||||
"StackObjectsCount": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63ea",
|
||||
"_tpl": "59db3a1d86f77429e05b4e92",
|
||||
"parentId": "656629d07cac3c3b160e63e9",
|
||||
"slotId": "mod_pistol_grip"
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63eb",
|
||||
"_tpl": "5bb20d53d4351e4502010a69",
|
||||
"parentId": "656629d07cac3c3b160e63e9",
|
||||
"slotId": "mod_reciever"
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63ec",
|
||||
"_tpl": "5bb20dadd4351e00367faeff",
|
||||
"parentId": "656629d07cac3c3b160e63eb",
|
||||
"slotId": "mod_barrel"
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63ed",
|
||||
"_tpl": "5bb20dcad4351e3bac1212da",
|
||||
"parentId": "656629d07cac3c3b160e63ec",
|
||||
"slotId": "mod_gas_block"
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63ee",
|
||||
"_tpl": "5cff9e5ed7ad1a09407397d4",
|
||||
"parentId": "656629d07cac3c3b160e63ec",
|
||||
"slotId": "mod_muzzle"
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63ef",
|
||||
"_tpl": "5cff9e84d7ad1a049e54ed55",
|
||||
"parentId": "656629d07cac3c3b160e63ee",
|
||||
"slotId": "mod_muzzle"
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63f0",
|
||||
"_tpl": "5c6d11152e2216000f2003e7",
|
||||
"parentId": "656629d07cac3c3b160e63eb",
|
||||
"slotId": "mod_handguard"
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63f1",
|
||||
"_tpl": "57cffcd624597763133760c5",
|
||||
"parentId": "656629d07cac3c3b160e63f0",
|
||||
"slotId": "mod_foregrip"
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63f2",
|
||||
"_tpl": "5c18b9192e2216398b5a8104",
|
||||
"parentId": "656629d07cac3c3b160e63eb",
|
||||
"slotId": "mod_sight_rear"
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63f3",
|
||||
"_tpl": "5bb20e58d4351e00320205d7",
|
||||
"parentId": "656629d07cac3c3b160e63e9",
|
||||
"slotId": "mod_stock"
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63f4",
|
||||
"_tpl": "58d2946386f774496974c37e",
|
||||
"parentId": "656629d07cac3c3b160e63f3",
|
||||
"slotId": "mod_stock_000"
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63f5",
|
||||
"_tpl": "58d2912286f7744e27117493",
|
||||
"parentId": "656629d07cac3c3b160e63f4",
|
||||
"slotId": "mod_stock"
|
||||
},
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63f6",
|
||||
"_tpl": "5bb20dbcd4351e44f824c04e",
|
||||
"parentId": "656629d07cac3c3b160e63e9",
|
||||
"slotId": "mod_charge"
|
||||
}
|
||||
],
|
||||
"target": "656629d07cac3c3b160e63e9",
|
||||
"type": "Item",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"findInRaid": true,
|
||||
"id": "655f4214b4f3e80ef35495e8",
|
||||
"index": 4,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63f7",
|
||||
"_tpl": "5b44c8ea86f7742d1627baf1",
|
||||
"upd": {
|
||||
"StackObjectsCount": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"target": "656629d07cac3c3b160e63f7",
|
||||
"type": "Item",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"findInRaid": true,
|
||||
"id": "655f4226f0cdb65ed6328125",
|
||||
"index": 5,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63f8",
|
||||
"_tpl": "6034d2d697633951dc245ea6",
|
||||
"upd": {
|
||||
"StackObjectsCount": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"target": "656629d07cac3c3b160e63f8",
|
||||
"type": "Item",
|
||||
"value": "2"
|
||||
}
|
||||
],
|
||||
"Success": [
|
||||
{
|
||||
"findInRaid": true,
|
||||
"id": "655f3f8bb4f3e80ef35495e6",
|
||||
"index": 0,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63f9",
|
||||
"_tpl": "5c0a840b86f7742ffa4f2482",
|
||||
"upd": {
|
||||
"StackObjectsCount": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"target": "656629d07cac3c3b160e63f9",
|
||||
"type": "Item",
|
||||
"unknown": false,
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"findInRaid": true,
|
||||
"id": "655f3fb4fdc15c010d329516",
|
||||
"index": 1,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63fa",
|
||||
"_tpl": "5696686a4bdc2da3298b456a",
|
||||
"upd": {
|
||||
"StackObjectsCount": 15000
|
||||
}
|
||||
}
|
||||
],
|
||||
"target": "656629d07cac3c3b160e63fa",
|
||||
"type": "Item",
|
||||
"unknown": false,
|
||||
"value": "15000"
|
||||
},
|
||||
{
|
||||
"id": "655f3f6396fb284db70fa429",
|
||||
"index": 2,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63fb",
|
||||
"_tpl": "61962b617c6c7b169525f168"
|
||||
}
|
||||
],
|
||||
"loyaltyLevel": 1,
|
||||
"target": "656629d07cac3c3b160e63fb",
|
||||
"traderId": "5935c25fb3acc3127c3d8cd9",
|
||||
"type": "AssortmentUnlock",
|
||||
"unknown": true
|
||||
},
|
||||
{
|
||||
"id": "655f3f6bb4f3e80ef35495e5",
|
||||
"index": 3,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63fc",
|
||||
"_tpl": "601949593ae8f707c4608daa"
|
||||
}
|
||||
],
|
||||
"loyaltyLevel": 1,
|
||||
"target": "656629d07cac3c3b160e63fc",
|
||||
"traderId": "5935c25fb3acc3127c3d8cd9",
|
||||
"type": "AssortmentUnlock",
|
||||
"unknown": true
|
||||
},
|
||||
{
|
||||
"id": "655f3f6fd5e086614d342775",
|
||||
"index": 4,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63fd",
|
||||
"_tpl": "601aa3d2b2bcb34913271e6d"
|
||||
}
|
||||
],
|
||||
"loyaltyLevel": 1,
|
||||
"target": "656629d07cac3c3b160e63fd",
|
||||
"traderId": "5935c25fb3acc3127c3d8cd9",
|
||||
"type": "AssortmentUnlock",
|
||||
"unknown": true
|
||||
},
|
||||
{
|
||||
"id": "655f3f74691eb93295472575",
|
||||
"index": 5,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63fe",
|
||||
"_tpl": "5efb0c1bd79ff02a1f5e68d9"
|
||||
}
|
||||
],
|
||||
"loyaltyLevel": 1,
|
||||
"target": "656629d07cac3c3b160e63fe",
|
||||
"traderId": "5935c25fb3acc3127c3d8cd9",
|
||||
"type": "AssortmentUnlock",
|
||||
"unknown": true
|
||||
},
|
||||
{
|
||||
"id": "655f3f77fdc15c010d329515",
|
||||
"index": 6,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e63ff",
|
||||
"_tpl": "5efb0da7a29a85116f6ea05f"
|
||||
}
|
||||
],
|
||||
"loyaltyLevel": 1,
|
||||
"target": "656629d07cac3c3b160e63ff",
|
||||
"traderId": "5935c25fb3acc3127c3d8cd9",
|
||||
"type": "AssortmentUnlock",
|
||||
"unknown": true
|
||||
},
|
||||
{
|
||||
"id": "655f3f7c96fb284db70fa42a",
|
||||
"index": 7,
|
||||
"items": [
|
||||
{
|
||||
"_id": "656629d07cac3c3b160e6400",
|
||||
"_tpl": "5ba26835d4351e0035628ff5"
|
||||
}
|
||||
],
|
||||
"loyaltyLevel": 1,
|
||||
"target": "656629d07cac3c3b160e6400",
|
||||
"traderId": "5935c25fb3acc3127c3d8cd9",
|
||||
"type": "AssortmentUnlock",
|
||||
"unknown": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"secretQuest": false,
|
||||
"side": "Pmc",
|
||||
"startedMessageText": "655e427b64d09b4122018228 startedMessageText",
|
||||
"successMessageText": "655e427b64d09b4122018228 successMessageText",
|
||||
"templateId": "655e427b64d09b4122018228",
|
||||
"traderId": "5935c25fb3acc3127c3d8cd9",
|
||||
"type": "Elimination"
|
||||
}
|
||||
}
|
||||
|
@ -9122,7 +9122,7 @@
|
||||
"slotId": "hideout",
|
||||
"upd": {
|
||||
"BuyRestrictionMax": 10,
|
||||
"StackObjectsCount": 1500
|
||||
"StackObjectsCount": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -4717,7 +4717,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "652376e2f6c67195e4061382",
|
||||
"_id": "6492e44bf4287b13040fcbae",
|
||||
"_tpl": "5e85a9f4add9fe03027d9bf1",
|
||||
"parentId": "hideout",
|
||||
"slotId": "hideout",
|
||||
@ -4727,7 +4727,17 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "64cac5c1d45ace5bc90c74a8",
|
||||
"_id": "6492e44bf4287b13040fccf6",
|
||||
"_tpl": "5efb0da7a29a85116f6ea05f",
|
||||
"parentId": "hideout",
|
||||
"slotId": "hideout",
|
||||
"upd": {
|
||||
"StackObjectsCount": 20000,
|
||||
"BuyRestrictionMax": 150
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "64a8578f0e9876295f0f83ed",
|
||||
"_tpl": "5b2388675acfc4771e1be0be",
|
||||
"parentId": "hideout",
|
||||
"slotId": "hideout",
|
||||
@ -4737,7 +4747,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "64cac5c1d45ace5bc90c74a9",
|
||||
"_id": "64a8578f0e9876295f0f83ee",
|
||||
"_tpl": "618ba27d9008e4636a67f61d",
|
||||
"parentId": "hideout",
|
||||
"slotId": "hideout",
|
||||
@ -4747,7 +4757,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "64cac5c1d45ace5bc90c74aa",
|
||||
"_id": "64a8578f0e9876295f0f83ef",
|
||||
"_tpl": "5b3b99475acfc432ff4dcbee",
|
||||
"parentId": "hideout",
|
||||
"slotId": "hideout",
|
||||
@ -4755,16 +4765,6 @@
|
||||
"StackObjectsCount": 20,
|
||||
"BuyRestrictionMax": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "64cac5c1d45ace5bc90c74ab",
|
||||
"_tpl": "5efb0da7a29a85116f6ea05f",
|
||||
"parentId": "hideout",
|
||||
"slotId": "hideout",
|
||||
"upd": {
|
||||
"StackObjectsCount": 20000,
|
||||
"BuyRestrictionMax": 150
|
||||
}
|
||||
}
|
||||
],
|
||||
"barter_scheme": {
|
||||
@ -7413,7 +7413,7 @@
|
||||
}
|
||||
]
|
||||
],
|
||||
"652376e2f6c67195e4061382": [
|
||||
"6492e44bf4287b13040fcbae": [
|
||||
[
|
||||
{
|
||||
"count": 3381,
|
||||
@ -7421,7 +7421,15 @@
|
||||
}
|
||||
]
|
||||
],
|
||||
"64cac5c1d45ace5bc90c74a8": [
|
||||
"6492e44bf4287b13040fccf6": [
|
||||
[
|
||||
{
|
||||
"count": 700,
|
||||
"_tpl": "5449016a4bdc2d6f028b456f"
|
||||
}
|
||||
]
|
||||
],
|
||||
"64a8578f0e9876295f0f83ed": [
|
||||
[
|
||||
{
|
||||
"count": 45000,
|
||||
@ -7429,7 +7437,7 @@
|
||||
}
|
||||
]
|
||||
],
|
||||
"64cac5c1d45ace5bc90c74a9": [
|
||||
"64a8578f0e9876295f0f83ee": [
|
||||
[
|
||||
{
|
||||
"count": 115000,
|
||||
@ -7437,21 +7445,13 @@
|
||||
}
|
||||
]
|
||||
],
|
||||
"64cac5c1d45ace5bc90c74aa": [
|
||||
"64a8578f0e9876295f0f83ef": [
|
||||
[
|
||||
{
|
||||
"count": 80000,
|
||||
"_tpl": "5449016a4bdc2d6f028b456f"
|
||||
}
|
||||
]
|
||||
],
|
||||
"64cac5c1d45ace5bc90c74ab": [
|
||||
[
|
||||
{
|
||||
"count": 700,
|
||||
"_tpl": "5449016a4bdc2d6f028b456f"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"loyal_level_items": {
|
||||
@ -7781,10 +7781,10 @@
|
||||
"6507ff22644a656aee0f76dd": 3,
|
||||
"6507ff22644a656aee0f76df": 3,
|
||||
"6507ff22644a656aee0f76e1": 1,
|
||||
"652376e2f6c67195e4061382": 4,
|
||||
"64cac5c1d45ace5bc90c74a8": 1,
|
||||
"64cac5c1d45ace5bc90c74a9": 1,
|
||||
"64cac5c1d45ace5bc90c74aa": 1,
|
||||
"64cac5c1d45ace5bc90c74ab": 1
|
||||
"6492e44bf4287b13040fcbae": 4,
|
||||
"6492e44bf4287b13040fccf6": 1,
|
||||
"64a8578f0e9876295f0f83ed": 1,
|
||||
"64a8578f0e9876295f0f83ee": 1,
|
||||
"64a8578f0e9876295f0f83ef": 1
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,41 +1,47 @@
|
||||
{
|
||||
"fail": {},
|
||||
"started": {},
|
||||
"success": {
|
||||
"6492e44bf4287b13040fca51": "60e71ce009d7c801eb0c0ec6",
|
||||
"6507ff2a644a656aee0f7fbd": "5a27b7d686f77460d847e6a6",
|
||||
"6507ff2a644a656aee0f7fc6": "5a27bbf886f774333a418eeb",
|
||||
"6507ff2a644a656aee0f7fce": "5a27bb3d86f77411ea361a21",
|
||||
"6507ff2a644a656aee0f800a": "5edac020218d181e29451446",
|
||||
"6507ff2a644a656aee0f800e": "5c0d4e61d09282029f53920e",
|
||||
"6507ff2a644a656aee0f8029": "5a27b80086f774429a5d7e20",
|
||||
"6507ff2b644a656aee0f8089": "5a27ba9586f7741b543d8e85",
|
||||
"6507ff2b644a656aee0f809e": "5a03173786f77451cb427172",
|
||||
"6507ff2b644a656aee0f80df": "5a27b9de86f77464e5044585",
|
||||
"6507ff2b644a656aee0f80e3": "5b477f7686f7744d1b23c4d2",
|
||||
"6507ff2b644a656aee0f8107": "5a27bc6986f7741c7358402b",
|
||||
"6507ff2b644a656aee0f8159": "5a27b75b86f7742e97191958",
|
||||
"6507ff2b644a656aee0f816b": "6179aff8f57fb279792c60a1",
|
||||
"6507ff2b644a656aee0f8179": "5c0d4e61d09282029f53920e",
|
||||
"6507ff2b644a656aee0f817d": "5a27bc1586f7741f6d40fa2f",
|
||||
"6507ff2b644a656aee0f81d3": "5a27b75b86f7742e97191958",
|
||||
"6507ff2b644a656aee0f81f2": "5c0d4e61d09282029f53920e",
|
||||
"6507ff2b644a656aee0f8201": "5c0d0f1886f77457b8210226",
|
||||
"6507ff2b644a656aee0f8159": "5a27b75b86f7742e97191958",
|
||||
"6507ff2c644a656aee0f8231": "5a27b7a786f774579c3eb376",
|
||||
"6507ff2c644a656aee0f8260": "61958c366726521dd96828ec",
|
||||
"6507ff2a644a656aee0f7fbd": "5a27b7d686f77460d847e6a6",
|
||||
"6507ff2a644a656aee0f8029": "5a27b80086f774429a5d7e20",
|
||||
"6507ff2b644a656aee0f80df": "5a27b9de86f77464e5044585",
|
||||
"6507ff2b644a656aee0f8089": "5a27ba9586f7741b543d8e85",
|
||||
"6507ff2a644a656aee0f7fce": "5a27bb3d86f77411ea361a21",
|
||||
"6507ff2a644a656aee0f7fc6": "5a27bbf886f774333a418eeb",
|
||||
"6507ff2b644a656aee0f817d": "5a27bc1586f7741f6d40fa2f",
|
||||
"6507ff2c644a656aee0f8353": "5a27bc3686f7741c73584026",
|
||||
"6507ff2b644a656aee0f8107": "5a27bc6986f7741c7358402b",
|
||||
"6507ff2d644a656aee0f845f": "5a27bc6986f7741c7358402b",
|
||||
"6507ff2d644a656aee0f843e": "5a27bc8586f7741b543d8ea4",
|
||||
"6507ff2c644a656aee0f82b2": "5ac244c486f77413e12cf945",
|
||||
"6507ff2b644a656aee0f80e3": "5b477f7686f7744d1b23c4d2",
|
||||
"6507ff2d644a656aee0f835c": "5b47825886f77468074618d3",
|
||||
"6507ff2b644a656aee0f8201": "5c0d0f1886f77457b8210226",
|
||||
"6507ff2d644a656aee0f848d": "5c0d4c12d09282029f539173",
|
||||
"6507ff2b644a656aee0f81f2": "5c0d4e61d09282029f53920e",
|
||||
"6507ff2b644a656aee0f8179": "5c0d4e61d09282029f53920e",
|
||||
"6507ff2a644a656aee0f800e": "5c0d4e61d09282029f53920e",
|
||||
"6507ff2a644a656aee0f800a": "5edac020218d181e29451446",
|
||||
"6507ff2c644a656aee0f8287": "5edac020218d181e29451446",
|
||||
"6507ff2c644a656aee0f82a2": "5edac63b930f5454f51e128b",
|
||||
"6507ff2c644a656aee0f82b2": "5ac244c486f77413e12cf945",
|
||||
"6507ff2c644a656aee0f830d": "6179b4d1bca27a099552e04e",
|
||||
"6507ff2c644a656aee0f8335": "639872fe8871e1272b10ccf6",
|
||||
"6507ff2c644a656aee0f8353": "5a27bc3686f7741c73584026",
|
||||
"6507ff2d644a656aee0f835c": "5b47825886f77468074618d3",
|
||||
"6507ff2d644a656aee0f838c": "63a9b229813bba58a50c9ee5",
|
||||
"6507ff2d644a656aee0f83b1": "639135f286e646067c176a87",
|
||||
"6507ff2d644a656aee0f843e": "5a27bc8586f7741b543d8ea4",
|
||||
"6507ff2d644a656aee0f845f": "5a27bc6986f7741c7358402b",
|
||||
"6507ff2d644a656aee0f848d": "5c0d4c12d09282029f539173",
|
||||
"6507ff2d644a656aee0f8493": "5edac63b930f5454f51e128b",
|
||||
"6507ff2e644a656aee0f8562": "63a9b229813bba58a50c9ee5"
|
||||
}
|
||||
}
|
||||
"6492e44bf4287b13040fca51": "60e71ce009d7c801eb0c0ec6",
|
||||
"6507ff2b644a656aee0f816b": "6179aff8f57fb279792c60a1",
|
||||
"6507ff2c644a656aee0f830d": "6179b4d1bca27a099552e04e",
|
||||
"6507ff2c644a656aee0f8260": "61958c366726521dd96828ec",
|
||||
"6507ff2d644a656aee0f83b1": "639135f286e646067c176a87",
|
||||
"6507ff2c644a656aee0f8335": "639872fe8871e1272b10ccf6",
|
||||
"6507ff2e644a656aee0f8562": "63a9b229813bba58a50c9ee5",
|
||||
"6507ff2d644a656aee0f838c": "63a9b229813bba58a50c9ee5",
|
||||
"656629d07cac3c3b160e63fb": "655e427b64d09b4122018228",
|
||||
"656629d07cac3c3b160e63fc": "655e427b64d09b4122018228",
|
||||
"656629d07cac3c3b160e63fd": "655e427b64d09b4122018228",
|
||||
"656629d07cac3c3b160e63fe": "655e427b64d09b4122018228",
|
||||
"656629d07cac3c3b160e63ff": "655e427b64d09b4122018228",
|
||||
"656629d07cac3c3b160e6400": "655e427b64d09b4122018228"
|
||||
},
|
||||
"fail": {}
|
||||
}
|
@ -10,6 +10,7 @@ import { IGameEmptyCrcRequestData } from "@spt-aki/models/eft/game/IGameEmptyCrc
|
||||
import { IGameKeepAliveResponse } from "@spt-aki/models/eft/game/IGameKeepAliveResponse";
|
||||
import { IGameLogoutResponseData } from "@spt-aki/models/eft/game/IGameLogoutResponseData";
|
||||
import { IGameStartResponse } from "@spt-aki/models/eft/game/IGameStartResponse";
|
||||
import { IGetRaidTimeRequest } from "@spt-aki/models/eft/game/IGetRaidTimeRequest";
|
||||
import { IReportNicknameRequestData } from "@spt-aki/models/eft/game/IReportNicknameRequestData";
|
||||
import { IServerDetails } from "@spt-aki/models/eft/game/IServerDetails";
|
||||
import { IVersionValidateRequestData } from "@spt-aki/models/eft/game/IVersionValidateRequestData";
|
||||
@ -147,4 +148,14 @@ export class GameCallbacks implements OnLoad
|
||||
{
|
||||
return this.httpResponse.nullResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle singleplayer/settings/getRaidTime
|
||||
* @returns string
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public getRaidTime(url: string, request: IGetRaidTimeRequest, sessionID: string): any
|
||||
{
|
||||
return this.httpResponse.noBody(this.gameController.getRaidTime(sessionID, request));
|
||||
}
|
||||
}
|
||||
|
@ -11,16 +11,13 @@ export class ApplicationContext
|
||||
private static holderMaxSize = 10;
|
||||
|
||||
/**
|
||||
* @examples
|
||||
* Called like:
|
||||
*
|
||||
* const registerPlayerInfo = this.applicationContext.getLatestValue(ContextVariableType.REGISTER_PLAYER_REQUEST)
|
||||
* .getValue<IRegisterPlayerRequestData>();
|
||||
* const registerPlayerInfo = this.applicationContext.getLatestValue(ContextVariableType.REGISTER_PLAYER_REQUEST).getValue<IRegisterPlayerRequestData>();
|
||||
*
|
||||
* const activePlayerSessionId = this.applicationContext.getLatestValue(ContextVariableType.SESSION_ID)
|
||||
* .getValue<string>();
|
||||
* const activePlayerSessionId = this.applicationContext.getLatestValue(ContextVariableType.SESSION_ID).getValue<string>();
|
||||
*
|
||||
* const matchInfo = this.applicationContext.getLatestValue(ContextVariableType.MATCH_INFO)
|
||||
* .getValue<IStartOfflineRaidRequestData>();
|
||||
* const matchInfo = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION).getValue<IGetRaidConfigurationRequestData>();
|
||||
* @param type
|
||||
* @returns
|
||||
*/
|
||||
@ -30,6 +27,7 @@ export class ApplicationContext
|
||||
{
|
||||
return this.variables.get(type)?.getTail()?.getValue();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -39,6 +37,7 @@ export class ApplicationContext
|
||||
{
|
||||
return this.variables.get(type).toList();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -62,4 +61,12 @@ export class ApplicationContext
|
||||
list.add(new ContextVariable(value, type));
|
||||
this.variables.set(type, list);
|
||||
}
|
||||
|
||||
public clearValues(type: ContextVariableType): void
|
||||
{
|
||||
this.variables.has(type)
|
||||
{
|
||||
this.variables.delete(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
export enum ContextVariableType
|
||||
{
|
||||
SESSION_ID = 0, // Logged in users session id
|
||||
RAID_CONFIGURATION = 1, // Currently active raid information
|
||||
CLIENT_START_TIMESTAMP = 2, // Timestamp when client first connected
|
||||
REGISTER_PLAYER_REQUEST = 3, // When player is loading into map and loot is requested
|
||||
export enum ContextVariableType {
|
||||
/** Logged in users session id */
|
||||
SESSION_ID = 0,
|
||||
/** Currently acive raid information */
|
||||
RAID_CONFIGURATION = 1,
|
||||
/** Timestamp when client first connected */
|
||||
CLIENT_START_TIMESTAMP = 2,
|
||||
/** When player is loading into map and loot is requested */
|
||||
REGISTER_PLAYER_REQUEST = 3,
|
||||
RAID_ADJUSTMENTS = 4,
|
||||
}
|
||||
|
@ -290,6 +290,9 @@ export class BotController
|
||||
|
||||
public getAiBotBrainTypes(): any
|
||||
{
|
||||
return { pmc: this.pmcConfig.pmcType, assault: this.botConfig.assaultBrainType };
|
||||
return {
|
||||
pmc: this.pmcConfig.pmcType,
|
||||
assault: this.botConfig.assaultBrainType,
|
||||
playerScav: this.botConfig.playerScavBrainType};
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ import { ICheckVersionResponse } from "@spt-aki/models/eft/game/ICheckVersionRes
|
||||
import { ICurrentGroupResponse } from "@spt-aki/models/eft/game/ICurrentGroupResponse";
|
||||
import { IGameConfigResponse } from "@spt-aki/models/eft/game/IGameConfigResponse";
|
||||
import { IGameKeepAliveResponse } from "@spt-aki/models/eft/game/IGameKeepAliveResponse";
|
||||
import { IGetRaidTimeRequest } from "@spt-aki/models/eft/game/IGetRaidTimeRequest";
|
||||
import { IGetRaidTimeResponse } from "@spt-aki/models/eft/game/IGetRaidTimeResponse";
|
||||
import { IServerDetails } from "@spt-aki/models/eft/game/IServerDetails";
|
||||
import { IAkiProfile } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||
import { AccountTypes } from "@spt-aki/models/enums/AccountTypes";
|
||||
@ -36,7 +38,9 @@ import { ItemBaseClassService } from "@spt-aki/services/ItemBaseClassService";
|
||||
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
||||
import { OpenZoneService } from "@spt-aki/services/OpenZoneService";
|
||||
import { ProfileFixerService } from "@spt-aki/services/ProfileFixerService";
|
||||
import { RaidTimeAdjustmentService } from "@spt-aki/services/RaidTimeAdjustmentService";
|
||||
import { SeasonalEventService } from "@spt-aki/services/SeasonalEventService";
|
||||
import { HashUtil } from "@spt-aki/utils/HashUtil";
|
||||
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
||||
import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
||||
@ -56,6 +60,7 @@ export class GameController
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||
@inject("PreAkiModLoader") protected preAkiModLoader: PreAkiModLoader,
|
||||
@inject("HttpServerHelper") protected httpServerHelper: HttpServerHelper,
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||
@ -68,6 +73,7 @@ export class GameController
|
||||
@inject("SeasonalEventService") protected seasonalEventService: SeasonalEventService,
|
||||
@inject("ItemBaseClassService") protected itemBaseClassService: ItemBaseClassService,
|
||||
@inject("GiftService") protected giftService: GiftService,
|
||||
@inject("RaidTimeAdjustmentService") protected raidTimeAdjustmentService: RaidTimeAdjustmentService,
|
||||
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
@ -127,10 +133,21 @@ export class GameController
|
||||
if (sessionID)
|
||||
{
|
||||
const fullProfile = this.profileHelper.getFullProfile(sessionID);
|
||||
if (fullProfile.info.wipe)
|
||||
{
|
||||
// Don't bother doing any fixes, we're resetting profile
|
||||
return;
|
||||
}
|
||||
|
||||
const pmcProfile = fullProfile.characters.pmc;
|
||||
|
||||
this.logger.debug(`Started game with sessionId: ${sessionID} ${pmcProfile.Info?.Nickname}`);
|
||||
|
||||
if (this.coreConfig.fixes.fixProfileBreakingInventoryItemIssues)
|
||||
{
|
||||
this.fixProfileBreakingInventoryItemIssues(pmcProfile)
|
||||
}
|
||||
|
||||
if (pmcProfile.Health)
|
||||
{
|
||||
this.updateProfileHealthValues(pmcProfile);
|
||||
@ -230,6 +247,79 @@ export class GameController
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to fix common item issues that corrupt profiles
|
||||
* @param pmcProfile Profile to check items of
|
||||
*/
|
||||
protected fixProfileBreakingInventoryItemIssues(pmcProfile: IPmcData): void
|
||||
{
|
||||
// Create a mapping of all inventory items, keyed by _id value
|
||||
const itemMapping = pmcProfile.Inventory.items.reduce((acc, curr) =>
|
||||
{
|
||||
acc[curr._id] = acc[curr._id] || [];
|
||||
acc[curr._id].push(curr);
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
for (const key in itemMapping)
|
||||
{
|
||||
// Only one item for this id, not a dupe
|
||||
if (itemMapping[key].length === 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
this.logger.warning(`${itemMapping[key].length - 1} duplicate(s) found for item: ${key}`);
|
||||
const itemAJson = this.jsonUtil.serialize(itemMapping[key][0]);
|
||||
const itemBJson = this.jsonUtil.serialize(itemMapping[key][1]);
|
||||
if (itemAJson === itemBJson)
|
||||
{
|
||||
// Both items match, we can safely delete one
|
||||
const indexOfItemToRemove = pmcProfile.Inventory.items.findIndex(x => x._id === key);
|
||||
pmcProfile.Inventory.items.splice(indexOfItemToRemove, 1);
|
||||
this.logger.warning(`Deleted duplicate item: ${key}`);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Items are different, replace ID with unique value
|
||||
// Only replace ID if items have no children, we dont want orphaned children
|
||||
const itemsHaveChildren = pmcProfile.Inventory.items.some(x => x.parentId === key);
|
||||
if (!itemsHaveChildren)
|
||||
{
|
||||
const itemToAdjustId = pmcProfile.Inventory.items.find(x => x._id === key);
|
||||
itemToAdjustId._id = this.hashUtil.generate();
|
||||
this.logger.warning(`Replace duplicate item Id: ${key} with ${itemToAdjustId._id}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over all inventory items
|
||||
for (const item of pmcProfile.Inventory.items.filter(x => x.slotId))
|
||||
{
|
||||
if (!item.upd)
|
||||
{
|
||||
// Ignore items without a upd object
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check items with a tag that contains non alphanumeric characters
|
||||
const regxp = /([/w"\\'])/g;
|
||||
if (regxp.test(item.upd.Tag?.Name))
|
||||
{
|
||||
this.logger.warning(`Fixed item: ${item._id}s Tag value, removed invalid characters`);
|
||||
item.upd.Tag.Name = item.upd.Tag.Name.replace(regxp, '');
|
||||
}
|
||||
|
||||
// Check items with StackObjectsCount (null)
|
||||
if (item.upd.StackObjectsCount === null)
|
||||
{
|
||||
this.logger.warning(`Fixed item: ${item._id}s null StackObjectsCount value, now set to 1`);
|
||||
item.upd.StackObjectsCount = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Out of date/incorrectly made trader mods forget this data
|
||||
*/
|
||||
@ -464,6 +554,14 @@ export class GameController
|
||||
return { msg: "OK", utc_time: new Date().getTime() / 1000 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle singleplayer/settings/getRaidTime
|
||||
*/
|
||||
public getRaidTime(sessionId: string, request: IGetRaidTimeRequest): IGetRaidTimeResponse
|
||||
{
|
||||
return this.raidTimeAdjustmentService.getRaidAdjustments(sessionId, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* BSG have two values for shotgun dispersion, we make sure both have the same value
|
||||
*/
|
||||
|
@ -328,7 +328,7 @@ export class HideoutController
|
||||
}
|
||||
|
||||
/**
|
||||
* @param output Objet to send to client
|
||||
* @param output Object to send to client
|
||||
* @param sessionID Session/player id
|
||||
* @param areaType Hideout area that had stash added
|
||||
* @param hideoutDbData Hideout area that caused addition of stash
|
||||
@ -1118,13 +1118,14 @@ export class HideoutController
|
||||
// Add all improvements to output object
|
||||
const improvements = hideoutDbData.stages[profileHideoutArea.level].improvements;
|
||||
const timestamp = this.timeUtil.getTimestamp();
|
||||
|
||||
if (!output.profileChanges[sessionId].improvements)
|
||||
{
|
||||
output.profileChanges[sessionId].improvements = {};
|
||||
}
|
||||
|
||||
for (const improvement of improvements)
|
||||
{
|
||||
if (!output.profileChanges[sessionId].improvements)
|
||||
{
|
||||
output.profileChanges[sessionId].improvements = {};
|
||||
}
|
||||
|
||||
const improvementDetails = {
|
||||
completed: false,
|
||||
improveCompleteTimestamp: timestamp + improvement.improvementTime,
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
|
||||
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
||||
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
||||
import { LocationGenerator } from "@spt-aki/generators/LocationGenerator";
|
||||
import { LootGenerator } from "@spt-aki/generators/LootGenerator";
|
||||
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
|
||||
@ -13,12 +15,14 @@ import { AirdropTypeEnum } from "@spt-aki/models/enums/AirdropType";
|
||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||
import { IAirdropConfig } from "@spt-aki/models/spt/config/IAirdropConfig";
|
||||
import { ILocationConfig } from "@spt-aki/models/spt/config/ILocationConfig";
|
||||
import { IRaidChanges } from "@spt-aki/models/spt/location/IRaidChanges";
|
||||
import { ILocations } from "@spt-aki/models/spt/server/ILocations";
|
||||
import { LootRequest } from "@spt-aki/models/spt/services/LootRequest";
|
||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
||||
import { RaidTimeAdjustmentService } from "@spt-aki/services/RaidTimeAdjustmentService";
|
||||
import { HashUtil } from "@spt-aki/utils/HashUtil";
|
||||
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
||||
@ -38,10 +42,12 @@ export class LocationController
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("LocationGenerator") protected locationGenerator: LocationGenerator,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("RaidTimeAdjustmentService") protected raidTimeAdjustmentService: RaidTimeAdjustmentService,
|
||||
@inject("LootGenerator") protected lootGenerator: LootGenerator,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
|
||||
)
|
||||
{
|
||||
this.airdropConfig = this.configServer.getConfig(ConfigTypes.AIRDROP);
|
||||
@ -83,10 +89,19 @@ export class LocationController
|
||||
return output;
|
||||
}
|
||||
|
||||
// Check for a loot multipler adjustment in app context and apply if one is found
|
||||
let locationConfigCopy: ILocationConfig;
|
||||
const raidAdjustments = this.applicationContext.getLatestValue(ContextVariableType.RAID_ADJUSTMENTS)?.getValue<IRaidChanges>();
|
||||
if (raidAdjustments)
|
||||
{
|
||||
locationConfigCopy = this.jsonUtil.clone(this.locationConfig); // Clone values so they can be used to reset originals later
|
||||
this.raidTimeAdjustmentService.makeAdjustmentsToMap(raidAdjustments, output);
|
||||
}
|
||||
|
||||
const staticAmmoDist = this.jsonUtil.clone(db.loot.staticAmmo);
|
||||
|
||||
// Create containers and add loot to them
|
||||
const staticLoot = this.locationGenerator.generateStaticContainers(location.base, staticAmmoDist);
|
||||
const staticLoot = this.locationGenerator.generateStaticContainers(output, staticAmmoDist);
|
||||
output.Loot.push(...staticLoot);
|
||||
|
||||
// Add dynamic loot to output loot
|
||||
@ -107,6 +122,16 @@ export class LocationController
|
||||
);
|
||||
this.logger.success(this.localisationService.getText("location-generated_success", name));
|
||||
|
||||
// Reset loot multipliers back to original values
|
||||
if (raidAdjustments)
|
||||
{
|
||||
this.logger.debug("Resetting loot multipliers back to their original values");
|
||||
this.locationConfig.staticLootMultiplier = locationConfigCopy.staticLootMultiplier;
|
||||
this.locationConfig.looseLootMultiplier = locationConfigCopy.looseLootMultiplier;
|
||||
|
||||
this.applicationContext.clearValues(ContextVariableType.RAID_ADJUSTMENTS);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ export class QuestController
|
||||
break;
|
||||
}
|
||||
|
||||
// Prerequisite does not have its status requirement fulfilled
|
||||
// Prereq does not have its status requirement fulfilled
|
||||
if (!conditionToFulfil._props.status.includes(prerequisiteQuest.status))
|
||||
{
|
||||
haveCompletedPreviousQuest = false;
|
||||
@ -289,7 +289,7 @@ export class QuestController
|
||||
* @param pmcData Profile to update
|
||||
* @param acceptedQuest Quest accepted
|
||||
* @param sessionID Session id
|
||||
* @returns client response
|
||||
* @returns Client response
|
||||
*/
|
||||
public acceptQuest(
|
||||
pmcData: IPmcData,
|
||||
@ -298,31 +298,37 @@ export class QuestController
|
||||
): IItemEventRouterResponse
|
||||
{
|
||||
const acceptQuestResponse = this.eventOutputHolder.getOutput(sessionID);
|
||||
|
||||
const startedState = QuestStatus.Started;
|
||||
const newQuest = this.questHelper.getQuestReadyForProfile(pmcData, startedState, acceptedQuest);
|
||||
|
||||
|
||||
// Does quest exist in profile
|
||||
if (pmcData.Quests.find((x) => x.qid === acceptedQuest.qid))
|
||||
// Restarting a failed quest can mean quest exists in profile
|
||||
const existingQuestStatus = pmcData.Quests.find((x) => x.qid === acceptedQuest.qid)
|
||||
if (existingQuestStatus)
|
||||
{
|
||||
// Update existing
|
||||
this.questHelper.updateQuestState(pmcData, QuestStatus.Started, acceptedQuest.qid);
|
||||
this.questHelper.resetQuestState(pmcData, QuestStatus.Started, acceptedQuest.qid);
|
||||
|
||||
// Need to send client an empty list of completedConditions (Unsure if this does anything)
|
||||
acceptQuestResponse.profileChanges[sessionID].questsStatus.push(existingQuestStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add new quest to server profile
|
||||
const newQuest = this.questHelper.getQuestReadyForProfile(pmcData, QuestStatus.Started, acceptedQuest);
|
||||
pmcData.Quests.push(newQuest);
|
||||
}
|
||||
|
||||
// Create a dialog message for starting the quest.
|
||||
// Note that for starting quests, the correct locale field is "description", not "startedMessageText".
|
||||
const questFromDb = this.questHelper.getQuestFromDb(acceptedQuest.qid, pmcData);
|
||||
|
||||
// Get messageId of text to send to player as text message in game
|
||||
const messageId = this.questHelper.getMessageIdForQuestStart(
|
||||
questFromDb.startedMessageText,
|
||||
questFromDb.description,
|
||||
);
|
||||
const startedQuestRewards = this.questHelper.applyQuestReward(
|
||||
|
||||
// Apply non-item rewards to profile + return item rewards
|
||||
const startedQuestRewardItems = this.questHelper.applyQuestReward(
|
||||
pmcData,
|
||||
acceptedQuest.qid,
|
||||
QuestStatus.Started,
|
||||
@ -330,18 +336,20 @@ export class QuestController
|
||||
acceptQuestResponse,
|
||||
);
|
||||
|
||||
// Send started text + any starting reward items found above to player
|
||||
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
||||
sessionID,
|
||||
this.traderHelper.getTraderById(questFromDb.traderId),
|
||||
MessageType.QUEST_START,
|
||||
messageId,
|
||||
startedQuestRewards,
|
||||
startedQuestRewardItems,
|
||||
this.timeUtil.getHoursAsSeconds(this.questConfig.redeemTime),
|
||||
);
|
||||
|
||||
acceptQuestResponse.profileChanges[sessionID].quests = this.questHelper
|
||||
.getNewlyAccessibleQuestsWhenStartingQuest(acceptedQuest.qid, sessionID);
|
||||
|
||||
// Having accepted new quest, look for newly unlocked quests and inform client of them
|
||||
acceptQuestResponse.profileChanges[sessionID].quests.push(...this.questHelper
|
||||
.getNewlyAccessibleQuestsWhenStartingQuest(acceptedQuest.qid, sessionID));
|
||||
|
||||
return acceptQuestResponse;
|
||||
}
|
||||
|
||||
@ -362,10 +370,11 @@ export class QuestController
|
||||
{
|
||||
const acceptQuestResponse = this.eventOutputHolder.getOutput(sessionID);
|
||||
|
||||
const desiredQuestState = QuestStatus.Started;
|
||||
const newQuest = this.questHelper.getQuestReadyForProfile(pmcData, desiredQuestState, acceptedQuest);
|
||||
pmcData.Quests.push(newQuest);
|
||||
// Create and store quest status object inside player profile
|
||||
const newRepeatableQuest = this.questHelper.getQuestReadyForProfile(pmcData, QuestStatus.Started, acceptedQuest);
|
||||
pmcData.Quests.push(newRepeatableQuest);
|
||||
|
||||
// Look for the generated quest cache in profile.RepeatableQuests
|
||||
const repeatableQuestProfile = this.getRepeatableQuestFromProfile(pmcData, acceptedQuest);
|
||||
if (!repeatableQuestProfile)
|
||||
{
|
||||
@ -391,60 +400,13 @@ export class QuestController
|
||||
fullProfile.characters.scav.Quests = [];
|
||||
}
|
||||
|
||||
fullProfile.characters.scav.Quests.push(newQuest);
|
||||
fullProfile.characters.scav.Quests.push(newRepeatableQuest);
|
||||
}
|
||||
|
||||
const locale = this.localeService.getLocaleDb();
|
||||
const questStartedMessageKey = this.questHelper.getMessageIdForQuestStart(
|
||||
repeatableQuestProfile.startedMessageText,
|
||||
repeatableQuestProfile.description,
|
||||
);
|
||||
|
||||
// Can be started text or description text based on above function result
|
||||
let questStartedMessageText = locale[questStartedMessageKey];
|
||||
// TODO: Remove this whole if statement, possibly not required?
|
||||
if (!questStartedMessageText)
|
||||
{
|
||||
this.logger.debug(
|
||||
`Unable to accept quest ${acceptedQuest.qid}, cannot find the quest started message text with id ${questStartedMessageKey}. attempting to find it in en locale instead`,
|
||||
);
|
||||
|
||||
// For some reason non-en locales don't have repeatable quest ids, fall back to en and grab it if possible
|
||||
const enLocale = this.databaseServer.getTables().locales.global.en;
|
||||
questStartedMessageText = enLocale[repeatableQuestProfile.startedMessageText];
|
||||
|
||||
if (!questStartedMessageText)
|
||||
{
|
||||
this.logger.error(
|
||||
this.localisationService.getText("repeatable-unable_to_accept_quest_starting_message_not_found", {
|
||||
questId: acceptedQuest.qid,
|
||||
messageId: questStartedMessageKey,
|
||||
}),
|
||||
);
|
||||
|
||||
return this.httpResponseUtil.appendErrorToOutput(
|
||||
acceptQuestResponse,
|
||||
this.localisationService.getText("repeatable-unable_to_accept_quest_see_log"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const questRewards = this.questHelper.getQuestRewardItems(
|
||||
<IQuest><unknown>repeatableQuestProfile,
|
||||
desiredQuestState,
|
||||
);
|
||||
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
||||
sessionID,
|
||||
this.traderHelper.getTraderById(repeatableQuestProfile.traderId),
|
||||
MessageType.QUEST_START,
|
||||
questStartedMessageKey,
|
||||
questRewards,
|
||||
this.timeUtil.getHoursAsSeconds(this.questConfig.redeemTime),
|
||||
);
|
||||
|
||||
const repeatableSettings = pmcData.RepeatableQuests.find((x) =>
|
||||
x.name === repeatableQuestProfile.sptRepatableGroupName
|
||||
);
|
||||
|
||||
const change = {};
|
||||
change[repeatableQuestProfile._id] = repeatableSettings.changeRequirement[repeatableQuestProfile._id];
|
||||
const responseData: IPmcDataRepeatableQuest = {
|
||||
@ -457,7 +419,12 @@ export class QuestController
|
||||
activeQuests: [repeatableQuestProfile],
|
||||
inactiveQuests: [],
|
||||
};
|
||||
acceptQuestResponse.profileChanges[sessionID].repeatableQuests = [responseData];
|
||||
|
||||
if (!acceptQuestResponse.profileChanges[sessionID].repeatableQuests)
|
||||
{
|
||||
acceptQuestResponse.profileChanges[sessionID].repeatableQuests = []
|
||||
}
|
||||
acceptQuestResponse.profileChanges[sessionID].repeatableQuests.push(responseData);
|
||||
|
||||
return acceptQuestResponse;
|
||||
}
|
||||
@ -532,11 +499,11 @@ export class QuestController
|
||||
// Add diff of quests before completion vs after for client response
|
||||
const questDelta = this.questHelper.getDeltaQuests(beforeQuests, this.getClientQuests(sessionID));
|
||||
|
||||
// Check newly available + failed quests for time gates and add them to profile
|
||||
// Check newly available + failed quests for timegates and add them to profile
|
||||
this.addTimeLockedQuestsToProfile(pmcData, [...questDelta, ...questsToFail], body.qid);
|
||||
|
||||
// Inform client of quest changes
|
||||
completeQuestResponse.profileChanges[sessionID].quests = questDelta;
|
||||
completeQuestResponse.profileChanges[sessionID].quests.push(...questDelta);
|
||||
|
||||
// Check if it's a repeatable quest. If so, remove from Quests and repeatable.activeQuests list + move to repeatable.inactiveQuests
|
||||
for (const currentRepeatable of pmcData.RepeatableQuests)
|
||||
@ -593,12 +560,12 @@ export class QuestController
|
||||
|
||||
/**
|
||||
* Return quests that have different statuses
|
||||
* @param preQuestStatuses Quests before
|
||||
* @param preQuestStatusus Quests before
|
||||
* @param postQuestStatuses Quests after
|
||||
* @returns QuestStatusChange array
|
||||
*/
|
||||
protected getQuestsWithDifferentStatuses(
|
||||
preQuestStatuses: IQuestStatus[],
|
||||
preQuestStatusus: IQuestStatus[],
|
||||
postQuestStatuses: IQuestStatus[],
|
||||
): IQuestStatus[]
|
||||
{
|
||||
@ -607,7 +574,7 @@ export class QuestController
|
||||
for (const quest of postQuestStatuses)
|
||||
{
|
||||
// Add quest if status differs or quest not found
|
||||
const preQuest = preQuestStatuses.find((x) => x.qid === quest.qid);
|
||||
const preQuest = preQuestStatusus.find((x) => x.qid === quest.qid);
|
||||
if (!preQuest || preQuest.status !== quest.status)
|
||||
{
|
||||
result.push(quest);
|
||||
@ -659,7 +626,7 @@ export class QuestController
|
||||
// Iterate over quests, look for quests with right criteria
|
||||
for (const quest of quests)
|
||||
{
|
||||
// If quest has prerequisite of completed quest + availableAfter value > 0 (quest has wait time)
|
||||
// If quest has prereq of completed quest + availableAfter value > 0 (quest has wait time)
|
||||
const nextQuestWaitCondition = quest.conditions.AvailableForStart.find((x) =>
|
||||
x._props.target === completedQuestId && x._props.availableAfter > 0
|
||||
);
|
||||
@ -686,7 +653,8 @@ export class QuestController
|
||||
startTime: 0,
|
||||
status: QuestStatus.AvailableAfter,
|
||||
statusTimers: {
|
||||
"9": this.timeUtil.getTimestamp(), // eslint-disable-line @typescript-eslint/naming-convention
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
"9": this.timeUtil.getTimestamp(),
|
||||
},
|
||||
availableAfter: availableAfterTimestamp,
|
||||
});
|
||||
@ -832,7 +800,7 @@ export class QuestController
|
||||
const matchingItemInProfile = pmcData.Inventory.items.find((x) => x._id === itemHandover.id);
|
||||
if (!handoverRequirements._props.target.includes(matchingItemInProfile._tpl))
|
||||
{
|
||||
// Item handed in by player doesn't match what was requested
|
||||
// Item handed in by player doesnt match what was requested
|
||||
return this.showQuestItemHandoverMatchError(
|
||||
handoverQuestRequest,
|
||||
matchingItemInProfile,
|
||||
|
@ -117,21 +117,24 @@ export class RepeatableQuestController
|
||||
// for (let i = 0; i < currentRepeatable.activeQuests.length; i++)
|
||||
for (const activeQuest of currentRepeatableQuestType.activeQuests)
|
||||
{
|
||||
// check if the quest is ready to be completed, if so, don't remove it
|
||||
const quest = pmcData.Quests.filter((q) => q.qid === activeQuest._id);
|
||||
if (quest.length > 0)
|
||||
// Keep finished quests in list so player can hand in
|
||||
const quest = pmcData.Quests.find(quest => quest.qid === activeQuest._id);
|
||||
if (quest)
|
||||
{
|
||||
if (quest[0].status === QuestStatus.AvailableForFinish)
|
||||
if (quest.status === QuestStatus.AvailableForFinish)
|
||||
{
|
||||
questsToKeep.push(activeQuest);
|
||||
this.logger.debug(
|
||||
`Keeping repeatable quest ${activeQuest._id} in activeQuests since it is available to AvailableForFinish`,
|
||||
`Keeping repeatable quest ${activeQuest._id} in activeQuests since it is available to hand in`,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
this.profileFixerService.removeDanglingConditionCounters(pmcData);
|
||||
pmcData.Quests = pmcData.Quests.filter((q) => q.qid !== activeQuest._id);
|
||||
|
||||
// Remove expired quest from pmc.quest array
|
||||
pmcData.Quests = pmcData.Quests.filter(quest => quest.qid !== activeQuest._id);
|
||||
currentRepeatableQuestType.inactiveQuests.push(activeQuest);
|
||||
}
|
||||
currentRepeatableQuestType.activeQuests = questsToKeep;
|
||||
@ -455,7 +458,11 @@ export class RepeatableQuestController
|
||||
droppedQuestTrader.standing -= changeRequirement.changeStandingCost;
|
||||
|
||||
// Update client output with new repeatable
|
||||
output.profileChanges[sessionID].repeatableQuests = [repeatableToChange];
|
||||
if (!output.profileChanges[sessionID].repeatableQuests)
|
||||
{
|
||||
output.profileChanges[sessionID].repeatableQuests = [];
|
||||
}
|
||||
output.profileChanges[sessionID].repeatableQuests.push(repeatableToChange);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -124,6 +124,7 @@ import { PostAkiModLoader } from "@spt-aki/loaders/PostAkiModLoader";
|
||||
import { PostDBModLoader } from "@spt-aki/loaders/PostDBModLoader";
|
||||
import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";
|
||||
import { IAsyncQueue } from "@spt-aki/models/spt/utils/IAsyncQueue";
|
||||
import { IUUidGenerator } from "@spt-aki/models/spt/utils/IUuidGenerator";
|
||||
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
|
||||
import { HttpRouter } from "@spt-aki/routers/HttpRouter";
|
||||
import { ImageRouter } from "@spt-aki/routers/ImageRouter";
|
||||
@ -215,6 +216,7 @@ import { RagfairOfferService } from "@spt-aki/services/RagfairOfferService";
|
||||
import { RagfairPriceService } from "@spt-aki/services/RagfairPriceService";
|
||||
import { RagfairRequiredItemsService } from "@spt-aki/services/RagfairRequiredItemsService";
|
||||
import { RagfairTaxService } from "@spt-aki/services/RagfairTaxService";
|
||||
import { RaidTimeAdjustmentService } from "@spt-aki/services/RaidTimeAdjustmentService";
|
||||
import { RepairService } from "@spt-aki/services/RepairService";
|
||||
import { SeasonalEventService } from "@spt-aki/services/SeasonalEventService";
|
||||
import { TraderAssortService } from "@spt-aki/services/TraderAssortService";
|
||||
@ -239,6 +241,7 @@ import { MathUtil } from "@spt-aki/utils/MathUtil";
|
||||
import { ObjectId } from "@spt-aki/utils/ObjectId";
|
||||
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
||||
import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
||||
import { UUidGenerator } from "@spt-aki/utils/UUidGenerator";
|
||||
import { VFS } from "@spt-aki/utils/VFS";
|
||||
import { Watermark, WatermarkLocale } from "@spt-aki/utils/Watermark";
|
||||
import { WinstonMainLogger } from "@spt-aki/utils/logging/WinstonMainLogger";
|
||||
@ -255,442 +258,503 @@ export class Container
|
||||
childContainer.registerType("HttpListener", "AkiHttpListener");
|
||||
}
|
||||
|
||||
public static registerTypes(con: DependencyContainer): void
|
||||
public static registerTypes(depContainer: DependencyContainer): void
|
||||
{
|
||||
con.register("ApplicationContext", ApplicationContext, { lifecycle: Lifecycle.Singleton });
|
||||
Container.registerUtils(con);
|
||||
Container.registerRouters(con);
|
||||
Container.registerGenerators(con);
|
||||
Container.registerHelpers(con);
|
||||
Container.registerLoaders(con);
|
||||
Container.registerCallbacks(con);
|
||||
Container.registerServers(con);
|
||||
Container.registerServices(con);
|
||||
Container.registerControllers(con);
|
||||
depContainer.register("ApplicationContext", ApplicationContext, { lifecycle: Lifecycle.Singleton });
|
||||
Container.registerUtils(depContainer);
|
||||
|
||||
Container.registerRouters(depContainer);
|
||||
|
||||
Container.registerGenerators(depContainer);
|
||||
|
||||
Container.registerHelpers(depContainer);
|
||||
|
||||
Container.registerLoaders(depContainer);
|
||||
|
||||
Container.registerCallbacks(depContainer);
|
||||
|
||||
Container.registerServers(depContainer);
|
||||
|
||||
Container.registerServices(depContainer);
|
||||
|
||||
Container.registerControllers(depContainer);
|
||||
}
|
||||
|
||||
public static registerListTypes(con: DependencyContainer): void
|
||||
public static registerListTypes(depContainer: DependencyContainer): void
|
||||
{
|
||||
con.register("OnLoadModService", { useValue: new OnLoadModService(con) });
|
||||
con.register("HttpListenerModService", { useValue: new HttpListenerModService(con) });
|
||||
con.register("OnUpdateModService", { useValue: new OnUpdateModService(con) });
|
||||
con.register("DynamicRouterModService", { useValue: new DynamicRouterModService(con) });
|
||||
con.register("StaticRouterModService", { useValue: new StaticRouterModService(con) });
|
||||
depContainer.register("OnLoadModService", { useValue: new OnLoadModService(depContainer) });
|
||||
depContainer.register("HttpListenerModService", { useValue: new HttpListenerModService(depContainer) });
|
||||
depContainer.register("OnUpdateModService", { useValue: new OnUpdateModService(depContainer) });
|
||||
depContainer.register("DynamicRouterModService", { useValue: new DynamicRouterModService(depContainer) });
|
||||
depContainer.register("StaticRouterModService", { useValue: new StaticRouterModService(depContainer) });
|
||||
|
||||
con.registerType("OnLoad", "DatabaseImporter");
|
||||
con.registerType("OnLoad", "PostDBModLoader");
|
||||
con.registerType("OnLoad", "HandbookCallbacks");
|
||||
con.registerType("OnLoad", "HttpCallbacks");
|
||||
con.registerType("OnLoad", "PresetCallbacks");
|
||||
con.registerType("OnLoad", "SaveCallbacks");
|
||||
con.registerType("OnLoad", "TraderCallbacks"); // Must occur prior to RagfairCallbacks
|
||||
con.registerType("OnLoad", "RagfairPriceService");
|
||||
con.registerType("OnLoad", "RagfairCallbacks");
|
||||
con.registerType("OnLoad", "ModCallbacks");
|
||||
con.registerType("OnLoad", "GameCallbacks");
|
||||
con.registerType("OnUpdate", "DialogueCallbacks");
|
||||
con.registerType("OnUpdate", "HideoutCallbacks");
|
||||
con.registerType("OnUpdate", "TraderCallbacks");
|
||||
con.registerType("OnUpdate", "RagfairCallbacks");
|
||||
con.registerType("OnUpdate", "InsuranceCallbacks");
|
||||
con.registerType("OnUpdate", "SaveCallbacks");
|
||||
depContainer.registerType("OnLoad", "DatabaseImporter");
|
||||
depContainer.registerType("OnLoad", "PostDBModLoader");
|
||||
depContainer.registerType("OnLoad", "HandbookCallbacks");
|
||||
depContainer.registerType("OnLoad", "HttpCallbacks");
|
||||
depContainer.registerType("OnLoad", "PresetCallbacks");
|
||||
depContainer.registerType("OnLoad", "SaveCallbacks");
|
||||
depContainer.registerType("OnLoad", "TraderCallbacks"); // must occur prior to RagfairCallbacks
|
||||
depContainer.registerType("OnLoad", "RagfairPriceService");
|
||||
depContainer.registerType("OnLoad", "RagfairCallbacks");
|
||||
depContainer.registerType("OnLoad", "ModCallbacks");
|
||||
depContainer.registerType("OnLoad", "GameCallbacks");
|
||||
depContainer.registerType("OnUpdate", "DialogueCallbacks");
|
||||
depContainer.registerType("OnUpdate", "HideoutCallbacks");
|
||||
depContainer.registerType("OnUpdate", "TraderCallbacks");
|
||||
depContainer.registerType("OnUpdate", "RagfairCallbacks");
|
||||
depContainer.registerType("OnUpdate", "InsuranceCallbacks");
|
||||
depContainer.registerType("OnUpdate", "SaveCallbacks");
|
||||
|
||||
con.registerType("StaticRoutes", "BotStaticRouter");
|
||||
con.registerType("StaticRoutes", "ClientLogStaticRouter");
|
||||
con.registerType("StaticRoutes", "CustomizationStaticRouter");
|
||||
con.registerType("StaticRoutes", "DataStaticRouter");
|
||||
con.registerType("StaticRoutes", "DialogStaticRouter");
|
||||
con.registerType("StaticRoutes", "GameStaticRouter");
|
||||
con.registerType("StaticRoutes", "HealthStaticRouter");
|
||||
con.registerType("StaticRoutes", "InraidStaticRouter");
|
||||
con.registerType("StaticRoutes", "InsuranceStaticRouter");
|
||||
con.registerType("StaticRoutes", "ItemEventStaticRouter");
|
||||
con.registerType("StaticRoutes", "LauncherStaticRouter");
|
||||
con.registerType("StaticRoutes", "LocationStaticRouter");
|
||||
con.registerType("StaticRoutes", "WeatherStaticRouter");
|
||||
con.registerType("StaticRoutes", "MatchStaticRouter");
|
||||
con.registerType("StaticRoutes", "QuestStaticRouter");
|
||||
con.registerType("StaticRoutes", "RagfairStaticRouter");
|
||||
con.registerType("StaticRoutes", "PresetStaticRouter");
|
||||
con.registerType("StaticRoutes", "BundleStaticRouter");
|
||||
con.registerType("StaticRoutes", "NotifierStaticRouter");
|
||||
con.registerType("StaticRoutes", "ProfileStaticRouter");
|
||||
con.registerType("StaticRoutes", "TraderStaticRouter");
|
||||
con.registerType("DynamicRoutes", "BotDynamicRouter");
|
||||
con.registerType("DynamicRoutes", "BundleDynamicRouter");
|
||||
con.registerType("DynamicRoutes", "CustomizationDynamicRouter");
|
||||
con.registerType("DynamicRoutes", "DataDynamicRouter");
|
||||
con.registerType("DynamicRoutes", "HttpDynamicRouter");
|
||||
con.registerType("DynamicRoutes", "InraidDynamicRouter");
|
||||
con.registerType("DynamicRoutes", "LocationDynamicRouter");
|
||||
con.registerType("DynamicRoutes", "NotifierDynamicRouter");
|
||||
con.registerType("DynamicRoutes", "TraderDynamicRouter");
|
||||
depContainer.registerType("StaticRoutes", "BotStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "ClientLogStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "CustomizationStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "DataStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "DialogStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "GameStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "HealthStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "InraidStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "InsuranceStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "ItemEventStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "LauncherStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "LocationStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "WeatherStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "MatchStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "QuestStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "RagfairStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "PresetStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "BundleStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "NotifierStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "ProfileStaticRouter");
|
||||
depContainer.registerType("StaticRoutes", "TraderStaticRouter");
|
||||
depContainer.registerType("DynamicRoutes", "BotDynamicRouter");
|
||||
depContainer.registerType("DynamicRoutes", "BundleDynamicRouter");
|
||||
depContainer.registerType("DynamicRoutes", "CustomizationDynamicRouter");
|
||||
depContainer.registerType("DynamicRoutes", "DataDynamicRouter");
|
||||
depContainer.registerType("DynamicRoutes", "HttpDynamicRouter");
|
||||
depContainer.registerType("DynamicRoutes", "InraidDynamicRouter");
|
||||
depContainer.registerType("DynamicRoutes", "LocationDynamicRouter");
|
||||
depContainer.registerType("DynamicRoutes", "NotifierDynamicRouter");
|
||||
depContainer.registerType("DynamicRoutes", "TraderDynamicRouter");
|
||||
|
||||
con.registerType("IERouters", "CustomizationItemEventRouter");
|
||||
con.registerType("IERouters", "HealthItemEventRouter");
|
||||
con.registerType("IERouters", "HideoutItemEventRouter");
|
||||
con.registerType("IERouters", "InsuranceItemEventRouter");
|
||||
con.registerType("IERouters", "InventoryItemEventRouter");
|
||||
con.registerType("IERouters", "NoteItemEventRouter");
|
||||
con.registerType("IERouters", "PresetBuildItemEventRouter");
|
||||
con.registerType("IERouters", "QuestItemEventRouter");
|
||||
con.registerType("IERouters", "RagfairItemEventRouter");
|
||||
con.registerType("IERouters", "RepairItemEventRouter");
|
||||
con.registerType("IERouters", "TradeItemEventRouter");
|
||||
con.registerType("IERouters", "WishlistItemEventRouter");
|
||||
depContainer.registerType("IERouters", "CustomizationItemEventRouter");
|
||||
depContainer.registerType("IERouters", "HealthItemEventRouter");
|
||||
depContainer.registerType("IERouters", "HideoutItemEventRouter");
|
||||
depContainer.registerType("IERouters", "InsuranceItemEventRouter");
|
||||
depContainer.registerType("IERouters", "InventoryItemEventRouter");
|
||||
depContainer.registerType("IERouters", "NoteItemEventRouter");
|
||||
depContainer.registerType("IERouters", "PresetBuildItemEventRouter");
|
||||
depContainer.registerType("IERouters", "QuestItemEventRouter");
|
||||
depContainer.registerType("IERouters", "RagfairItemEventRouter");
|
||||
depContainer.registerType("IERouters", "RepairItemEventRouter");
|
||||
depContainer.registerType("IERouters", "TradeItemEventRouter");
|
||||
depContainer.registerType("IERouters", "WishlistItemEventRouter");
|
||||
|
||||
con.registerType("Serializer", "ImageSerializer");
|
||||
con.registerType("Serializer", "BundleSerializer");
|
||||
con.registerType("Serializer", "NotifySerializer");
|
||||
con.registerType("SaveLoadRouter", "HealthSaveLoadRouter");
|
||||
con.registerType("SaveLoadRouter", "InraidSaveLoadRouter");
|
||||
con.registerType("SaveLoadRouter", "InsuranceSaveLoadRouter");
|
||||
con.registerType("SaveLoadRouter", "ProfileSaveLoadRouter");
|
||||
depContainer.registerType("Serializer", "ImageSerializer");
|
||||
depContainer.registerType("Serializer", "BundleSerializer");
|
||||
depContainer.registerType("Serializer", "NotifySerializer");
|
||||
depContainer.registerType("SaveLoadRouter", "HealthSaveLoadRouter");
|
||||
depContainer.registerType("SaveLoadRouter", "InraidSaveLoadRouter");
|
||||
depContainer.registerType("SaveLoadRouter", "InsuranceSaveLoadRouter");
|
||||
depContainer.registerType("SaveLoadRouter", "ProfileSaveLoadRouter");
|
||||
}
|
||||
|
||||
private static registerUtils(con: DependencyContainer): void
|
||||
private static registerUtils(depContainer: DependencyContainer): void
|
||||
{
|
||||
// Utils
|
||||
con.register<App>("App", App, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<DatabaseImporter>("DatabaseImporter", DatabaseImporter, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<HashUtil>("HashUtil", HashUtil, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<ImporterUtil>("ImporterUtil", ImporterUtil, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<HttpResponseUtil>("HttpResponseUtil", HttpResponseUtil);
|
||||
con.register<EncodingUtil>("EncodingUtil", EncodingUtil, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<JsonUtil>("JsonUtil", JsonUtil);
|
||||
con.register<WinstonMainLogger>("WinstonLogger", WinstonMainLogger, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<WinstonRequestLogger>("RequestsLogger", WinstonRequestLogger, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<MathUtil>("MathUtil", MathUtil, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<ObjectId>("ObjectId", ObjectId);
|
||||
con.register<RandomUtil>("RandomUtil", RandomUtil, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<TimeUtil>("TimeUtil", TimeUtil, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<VFS>("VFS", VFS, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<WatermarkLocale>("WatermarkLocale", WatermarkLocale, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<Watermark>("Watermark", Watermark, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<IAsyncQueue>("AsyncQueue", AsyncQueue, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<HttpFileUtil>("HttpFileUtil", HttpFileUtil, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<ModLoadOrder>("ModLoadOrder", ModLoadOrder, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<ModTypeCheck>("ModTypeCheck", ModTypeCheck, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<App>("App", App, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<DatabaseImporter>("DatabaseImporter", DatabaseImporter, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<HashUtil>("HashUtil", HashUtil, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<ImporterUtil>("ImporterUtil", ImporterUtil, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<HttpResponseUtil>("HttpResponseUtil", HttpResponseUtil);
|
||||
depContainer.register<EncodingUtil>("EncodingUtil", EncodingUtil, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<JsonUtil>("JsonUtil", JsonUtil);
|
||||
depContainer.register<WinstonMainLogger>("WinstonLogger", WinstonMainLogger, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<WinstonRequestLogger>("RequestsLogger", WinstonRequestLogger, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<MathUtil>("MathUtil", MathUtil, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<ObjectId>("ObjectId", ObjectId);
|
||||
depContainer.register<RandomUtil>("RandomUtil", RandomUtil, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<TimeUtil>("TimeUtil", TimeUtil, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<VFS>("VFS", VFS, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<WatermarkLocale>("WatermarkLocale", WatermarkLocale, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<Watermark>("Watermark", Watermark, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<IAsyncQueue>("AsyncQueue", AsyncQueue, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<IUUidGenerator>("UUidGenerator", UUidGenerator, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<HttpFileUtil>("HttpFileUtil", HttpFileUtil, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<ModLoadOrder>("ModLoadOrder", ModLoadOrder, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<ModTypeCheck>("ModTypeCheck", ModTypeCheck, { lifecycle: Lifecycle.Singleton });
|
||||
}
|
||||
|
||||
private static registerRouters(con: DependencyContainer): void
|
||||
private static registerRouters(depContainer: DependencyContainer): void
|
||||
{
|
||||
// Routers
|
||||
con.register<HttpRouter>("HttpRouter", HttpRouter, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<ImageRouter>("ImageRouter", ImageRouter);
|
||||
con.register<EventOutputHolder>("EventOutputHolder", EventOutputHolder, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<ItemEventRouter>("ItemEventRouter", ItemEventRouter);
|
||||
depContainer.register<HttpRouter>("HttpRouter", HttpRouter, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<ImageRouter>("ImageRouter", ImageRouter);
|
||||
depContainer.register<EventOutputHolder>("EventOutputHolder", EventOutputHolder, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<ItemEventRouter>("ItemEventRouter", ItemEventRouter);
|
||||
|
||||
// Dynamic routes
|
||||
con.register<BotDynamicRouter>("BotDynamicRouter", { useClass: BotDynamicRouter });
|
||||
con.register<BundleDynamicRouter>("BundleDynamicRouter", { useClass: BundleDynamicRouter });
|
||||
con.register<CustomizationDynamicRouter>("CustomizationDynamicRouter", {
|
||||
depContainer.register<BotDynamicRouter>("BotDynamicRouter", { useClass: BotDynamicRouter });
|
||||
depContainer.register<BundleDynamicRouter>("BundleDynamicRouter", { useClass: BundleDynamicRouter });
|
||||
depContainer.register<CustomizationDynamicRouter>("CustomizationDynamicRouter", {
|
||||
useClass: CustomizationDynamicRouter,
|
||||
});
|
||||
con.register<DataDynamicRouter>("DataDynamicRouter", { useClass: DataDynamicRouter });
|
||||
con.register<HttpDynamicRouter>("HttpDynamicRouter", { useClass: HttpDynamicRouter });
|
||||
con.register<InraidDynamicRouter>("InraidDynamicRouter", { useClass: InraidDynamicRouter });
|
||||
con.register<LocationDynamicRouter>("LocationDynamicRouter", { useClass: LocationDynamicRouter });
|
||||
con.register<NotifierDynamicRouter>("NotifierDynamicRouter", { useClass: NotifierDynamicRouter });
|
||||
con.register<TraderDynamicRouter>("TraderDynamicRouter", { useClass: TraderDynamicRouter });
|
||||
depContainer.register<DataDynamicRouter>("DataDynamicRouter", { useClass: DataDynamicRouter });
|
||||
depContainer.register<HttpDynamicRouter>("HttpDynamicRouter", { useClass: HttpDynamicRouter });
|
||||
depContainer.register<InraidDynamicRouter>("InraidDynamicRouter", { useClass: InraidDynamicRouter });
|
||||
depContainer.register<LocationDynamicRouter>("LocationDynamicRouter", { useClass: LocationDynamicRouter });
|
||||
depContainer.register<NotifierDynamicRouter>("NotifierDynamicRouter", { useClass: NotifierDynamicRouter });
|
||||
depContainer.register<TraderDynamicRouter>("TraderDynamicRouter", { useClass: TraderDynamicRouter });
|
||||
|
||||
// Item event routes
|
||||
con.register<CustomizationItemEventRouter>("CustomizationItemEventRouter", {
|
||||
depContainer.register<CustomizationItemEventRouter>("CustomizationItemEventRouter", {
|
||||
useClass: CustomizationItemEventRouter,
|
||||
});
|
||||
con.register<HealthItemEventRouter>("HealthItemEventRouter", { useClass: HealthItemEventRouter });
|
||||
con.register<HideoutItemEventRouter>("HideoutItemEventRouter", { useClass: HideoutItemEventRouter });
|
||||
con.register<InsuranceItemEventRouter>("InsuranceItemEventRouter", { useClass: InsuranceItemEventRouter });
|
||||
con.register<InventoryItemEventRouter>("InventoryItemEventRouter", { useClass: InventoryItemEventRouter });
|
||||
con.register<NoteItemEventRouter>("NoteItemEventRouter", { useClass: NoteItemEventRouter });
|
||||
con.register<PresetBuildItemEventRouter>("PresetBuildItemEventRouter", {
|
||||
depContainer.register<HealthItemEventRouter>("HealthItemEventRouter", { useClass: HealthItemEventRouter });
|
||||
depContainer.register<HideoutItemEventRouter>("HideoutItemEventRouter", { useClass: HideoutItemEventRouter });
|
||||
depContainer.register<InsuranceItemEventRouter>("InsuranceItemEventRouter", {
|
||||
useClass: InsuranceItemEventRouter,
|
||||
});
|
||||
depContainer.register<InventoryItemEventRouter>("InventoryItemEventRouter", {
|
||||
useClass: InventoryItemEventRouter,
|
||||
});
|
||||
depContainer.register<NoteItemEventRouter>("NoteItemEventRouter", { useClass: NoteItemEventRouter });
|
||||
depContainer.register<PresetBuildItemEventRouter>("PresetBuildItemEventRouter", {
|
||||
useClass: PresetBuildItemEventRouter,
|
||||
});
|
||||
con.register<QuestItemEventRouter>("QuestItemEventRouter", { useClass: QuestItemEventRouter });
|
||||
con.register<RagfairItemEventRouter>("RagfairItemEventRouter", { useClass: RagfairItemEventRouter });
|
||||
con.register<RepairItemEventRouter>("RepairItemEventRouter", { useClass: RepairItemEventRouter });
|
||||
con.register<TradeItemEventRouter>("TradeItemEventRouter", { useClass: TradeItemEventRouter });
|
||||
con.register<WishlistItemEventRouter>("WishlistItemEventRouter", { useClass: WishlistItemEventRouter });
|
||||
depContainer.register<QuestItemEventRouter>("QuestItemEventRouter", { useClass: QuestItemEventRouter });
|
||||
depContainer.register<RagfairItemEventRouter>("RagfairItemEventRouter", { useClass: RagfairItemEventRouter });
|
||||
depContainer.register<RepairItemEventRouter>("RepairItemEventRouter", { useClass: RepairItemEventRouter });
|
||||
depContainer.register<TradeItemEventRouter>("TradeItemEventRouter", { useClass: TradeItemEventRouter });
|
||||
depContainer.register<WishlistItemEventRouter>("WishlistItemEventRouter", {
|
||||
useClass: WishlistItemEventRouter,
|
||||
});
|
||||
|
||||
// save load routes
|
||||
con.register<HealthSaveLoadRouter>("HealthSaveLoadRouter", { useClass: HealthSaveLoadRouter });
|
||||
con.register<InraidSaveLoadRouter>("InraidSaveLoadRouter", { useClass: InraidSaveLoadRouter });
|
||||
con.register<InsuranceSaveLoadRouter>("InsuranceSaveLoadRouter", { useClass: InsuranceSaveLoadRouter });
|
||||
con.register<ProfileSaveLoadRouter>("ProfileSaveLoadRouter", { useClass: ProfileSaveLoadRouter });
|
||||
depContainer.register<HealthSaveLoadRouter>("HealthSaveLoadRouter", { useClass: HealthSaveLoadRouter });
|
||||
depContainer.register<InraidSaveLoadRouter>("InraidSaveLoadRouter", { useClass: InraidSaveLoadRouter });
|
||||
depContainer.register<InsuranceSaveLoadRouter>("InsuranceSaveLoadRouter", {
|
||||
useClass: InsuranceSaveLoadRouter,
|
||||
});
|
||||
depContainer.register<ProfileSaveLoadRouter>("ProfileSaveLoadRouter", { useClass: ProfileSaveLoadRouter });
|
||||
|
||||
// Route serializers
|
||||
con.register<BundleSerializer>("BundleSerializer", { useClass: BundleSerializer });
|
||||
con.register<ImageSerializer>("ImageSerializer", { useClass: ImageSerializer });
|
||||
con.register<NotifySerializer>("NotifySerializer", { useClass: NotifySerializer });
|
||||
depContainer.register<BundleSerializer>("BundleSerializer", { useClass: BundleSerializer });
|
||||
depContainer.register<ImageSerializer>("ImageSerializer", { useClass: ImageSerializer });
|
||||
depContainer.register<NotifySerializer>("NotifySerializer", { useClass: NotifySerializer });
|
||||
|
||||
// Static routes
|
||||
con.register<BotStaticRouter>("BotStaticRouter", { useClass: BotStaticRouter });
|
||||
con.register<BundleStaticRouter>("BundleStaticRouter", { useClass: BundleStaticRouter });
|
||||
con.register<ClientLogStaticRouter>("ClientLogStaticRouter", { useClass: ClientLogStaticRouter });
|
||||
con.register<CustomizationStaticRouter>("CustomizationStaticRouter", { useClass: CustomizationStaticRouter });
|
||||
con.register<DataStaticRouter>("DataStaticRouter", { useClass: DataStaticRouter });
|
||||
con.register<DialogStaticRouter>("DialogStaticRouter", { useClass: DialogStaticRouter });
|
||||
con.register<GameStaticRouter>("GameStaticRouter", { useClass: GameStaticRouter });
|
||||
con.register<HealthStaticRouter>("HealthStaticRouter", { useClass: HealthStaticRouter });
|
||||
con.register<InraidStaticRouter>("InraidStaticRouter", { useClass: InraidStaticRouter });
|
||||
con.register<InsuranceStaticRouter>("InsuranceStaticRouter", { useClass: InsuranceStaticRouter });
|
||||
con.register<ItemEventStaticRouter>("ItemEventStaticRouter", { useClass: ItemEventStaticRouter });
|
||||
con.register<LauncherStaticRouter>("LauncherStaticRouter", { useClass: LauncherStaticRouter });
|
||||
con.register<LocationStaticRouter>("LocationStaticRouter", { useClass: LocationStaticRouter });
|
||||
con.register<MatchStaticRouter>("MatchStaticRouter", { useClass: MatchStaticRouter });
|
||||
con.register<NotifierStaticRouter>("NotifierStaticRouter", { useClass: NotifierStaticRouter });
|
||||
con.register<PresetStaticRouter>("PresetStaticRouter", { useClass: PresetStaticRouter });
|
||||
con.register<ProfileStaticRouter>("ProfileStaticRouter", { useClass: ProfileStaticRouter });
|
||||
con.register<QuestStaticRouter>("QuestStaticRouter", { useClass: QuestStaticRouter });
|
||||
con.register<RagfairStaticRouter>("RagfairStaticRouter", { useClass: RagfairStaticRouter });
|
||||
con.register<TraderStaticRouter>("TraderStaticRouter", { useClass: TraderStaticRouter });
|
||||
con.register<WeatherStaticRouter>("WeatherStaticRouter", { useClass: WeatherStaticRouter });
|
||||
depContainer.register<BotStaticRouter>("BotStaticRouter", { useClass: BotStaticRouter });
|
||||
depContainer.register<BundleStaticRouter>("BundleStaticRouter", { useClass: BundleStaticRouter });
|
||||
depContainer.register<ClientLogStaticRouter>("ClientLogStaticRouter", { useClass: ClientLogStaticRouter });
|
||||
depContainer.register<CustomizationStaticRouter>("CustomizationStaticRouter", {
|
||||
useClass: CustomizationStaticRouter,
|
||||
});
|
||||
depContainer.register<DataStaticRouter>("DataStaticRouter", { useClass: DataStaticRouter });
|
||||
depContainer.register<DialogStaticRouter>("DialogStaticRouter", { useClass: DialogStaticRouter });
|
||||
depContainer.register<GameStaticRouter>("GameStaticRouter", { useClass: GameStaticRouter });
|
||||
depContainer.register<HealthStaticRouter>("HealthStaticRouter", { useClass: HealthStaticRouter });
|
||||
depContainer.register<InraidStaticRouter>("InraidStaticRouter", { useClass: InraidStaticRouter });
|
||||
depContainer.register<InsuranceStaticRouter>("InsuranceStaticRouter", { useClass: InsuranceStaticRouter });
|
||||
depContainer.register<ItemEventStaticRouter>("ItemEventStaticRouter", { useClass: ItemEventStaticRouter });
|
||||
depContainer.register<LauncherStaticRouter>("LauncherStaticRouter", { useClass: LauncherStaticRouter });
|
||||
depContainer.register<LocationStaticRouter>("LocationStaticRouter", { useClass: LocationStaticRouter });
|
||||
depContainer.register<MatchStaticRouter>("MatchStaticRouter", { useClass: MatchStaticRouter });
|
||||
depContainer.register<NotifierStaticRouter>("NotifierStaticRouter", { useClass: NotifierStaticRouter });
|
||||
depContainer.register<PresetStaticRouter>("PresetStaticRouter", { useClass: PresetStaticRouter });
|
||||
depContainer.register<ProfileStaticRouter>("ProfileStaticRouter", { useClass: ProfileStaticRouter });
|
||||
depContainer.register<QuestStaticRouter>("QuestStaticRouter", { useClass: QuestStaticRouter });
|
||||
depContainer.register<RagfairStaticRouter>("RagfairStaticRouter", { useClass: RagfairStaticRouter });
|
||||
depContainer.register<TraderStaticRouter>("TraderStaticRouter", { useClass: TraderStaticRouter });
|
||||
depContainer.register<WeatherStaticRouter>("WeatherStaticRouter", { useClass: WeatherStaticRouter });
|
||||
}
|
||||
|
||||
private static registerGenerators(con: DependencyContainer): void
|
||||
private static registerGenerators(depContainer: DependencyContainer): void
|
||||
{
|
||||
// Generators
|
||||
con.register<BotGenerator>("BotGenerator", BotGenerator);
|
||||
con.register<BotWeaponGenerator>("BotWeaponGenerator", BotWeaponGenerator);
|
||||
con.register<BotLootGenerator>("BotLootGenerator", BotLootGenerator);
|
||||
con.register<BotInventoryGenerator>("BotInventoryGenerator", BotInventoryGenerator);
|
||||
con.register<LocationGenerator>("LocationGenerator", { useClass: LocationGenerator });
|
||||
con.register<PMCLootGenerator>("PMCLootGenerator", PMCLootGenerator, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<ScavCaseRewardGenerator>("ScavCaseRewardGenerator", ScavCaseRewardGenerator, {
|
||||
depContainer.register<BotGenerator>("BotGenerator", BotGenerator);
|
||||
depContainer.register<BotWeaponGenerator>("BotWeaponGenerator", BotWeaponGenerator);
|
||||
depContainer.register<BotLootGenerator>("BotLootGenerator", BotLootGenerator);
|
||||
depContainer.register<BotInventoryGenerator>("BotInventoryGenerator", BotInventoryGenerator);
|
||||
depContainer.register<LocationGenerator>("LocationGenerator", { useClass: LocationGenerator });
|
||||
depContainer.register<PMCLootGenerator>("PMCLootGenerator", PMCLootGenerator, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<RagfairAssortGenerator>("RagfairAssortGenerator", { useClass: RagfairAssortGenerator });
|
||||
con.register<RagfairOfferGenerator>("RagfairOfferGenerator", { useClass: RagfairOfferGenerator });
|
||||
con.register<WeatherGenerator>("WeatherGenerator", { useClass: WeatherGenerator });
|
||||
con.register<PlayerScavGenerator>("PlayerScavGenerator", { useClass: PlayerScavGenerator });
|
||||
con.register<LootGenerator>("LootGenerator", { useClass: LootGenerator });
|
||||
con.register<FenceBaseAssortGenerator>("FenceBaseAssortGenerator", { useClass: FenceBaseAssortGenerator });
|
||||
con.register<BotLevelGenerator>("BotLevelGenerator", { useClass: BotLevelGenerator });
|
||||
con.register<BotEquipmentModGenerator>("BotEquipmentModGenerator", { useClass: BotEquipmentModGenerator });
|
||||
con.register<RepeatableQuestGenerator>("RepeatableQuestGenerator", { useClass: RepeatableQuestGenerator });
|
||||
depContainer.register<ScavCaseRewardGenerator>("ScavCaseRewardGenerator", ScavCaseRewardGenerator, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<RagfairAssortGenerator>("RagfairAssortGenerator", { useClass: RagfairAssortGenerator });
|
||||
depContainer.register<RagfairOfferGenerator>("RagfairOfferGenerator", { useClass: RagfairOfferGenerator });
|
||||
depContainer.register<WeatherGenerator>("WeatherGenerator", { useClass: WeatherGenerator });
|
||||
depContainer.register<PlayerScavGenerator>("PlayerScavGenerator", { useClass: PlayerScavGenerator });
|
||||
depContainer.register<LootGenerator>("LootGenerator", { useClass: LootGenerator });
|
||||
depContainer.register<FenceBaseAssortGenerator>("FenceBaseAssortGenerator", {
|
||||
useClass: FenceBaseAssortGenerator,
|
||||
});
|
||||
depContainer.register<BotLevelGenerator>("BotLevelGenerator", { useClass: BotLevelGenerator });
|
||||
depContainer.register<BotEquipmentModGenerator>("BotEquipmentModGenerator", {
|
||||
useClass: BotEquipmentModGenerator,
|
||||
});
|
||||
depContainer.register<RepeatableQuestGenerator>("RepeatableQuestGenerator", {
|
||||
useClass: RepeatableQuestGenerator,
|
||||
});
|
||||
|
||||
con.register<BarrelInventoryMagGen>("BarrelInventoryMagGen", { useClass: BarrelInventoryMagGen });
|
||||
con.register<ExternalInventoryMagGen>("ExternalInventoryMagGen", { useClass: ExternalInventoryMagGen });
|
||||
con.register<InternalMagazineInventoryMagGen>("InternalMagazineInventoryMagGen", {
|
||||
depContainer.register<BarrelInventoryMagGen>("BarrelInventoryMagGen", { useClass: BarrelInventoryMagGen });
|
||||
depContainer.register<ExternalInventoryMagGen>("ExternalInventoryMagGen", {
|
||||
useClass: ExternalInventoryMagGen,
|
||||
});
|
||||
depContainer.register<InternalMagazineInventoryMagGen>("InternalMagazineInventoryMagGen", {
|
||||
useClass: InternalMagazineInventoryMagGen,
|
||||
});
|
||||
con.register<UbglExternalMagGen>("UbglExternalMagGen", { useClass: UbglExternalMagGen });
|
||||
depContainer.register<UbglExternalMagGen>("UbglExternalMagGen", { useClass: UbglExternalMagGen });
|
||||
|
||||
con.registerType("InventoryMagGen", "BarrelInventoryMagGen");
|
||||
con.registerType("InventoryMagGen", "ExternalInventoryMagGen");
|
||||
con.registerType("InventoryMagGen", "InternalMagazineInventoryMagGen");
|
||||
con.registerType("InventoryMagGen", "UbglExternalMagGen");
|
||||
depContainer.registerType("InventoryMagGen", "BarrelInventoryMagGen");
|
||||
depContainer.registerType("InventoryMagGen", "ExternalInventoryMagGen");
|
||||
depContainer.registerType("InventoryMagGen", "InternalMagazineInventoryMagGen");
|
||||
depContainer.registerType("InventoryMagGen", "UbglExternalMagGen");
|
||||
}
|
||||
|
||||
private static registerHelpers(con: DependencyContainer): void
|
||||
private static registerHelpers(depContainer: DependencyContainer): void
|
||||
{
|
||||
// Helpers
|
||||
con.register<AssortHelper>("AssortHelper", { useClass: AssortHelper });
|
||||
con.register<BotHelper>("BotHelper", { useClass: BotHelper });
|
||||
con.register<BotGeneratorHelper>("BotGeneratorHelper", { useClass: BotGeneratorHelper });
|
||||
con.register<ContainerHelper>("ContainerHelper", ContainerHelper);
|
||||
con.register<DialogueHelper>("DialogueHelper", { useClass: DialogueHelper });
|
||||
con.register<DurabilityLimitsHelper>("DurabilityLimitsHelper", { useClass: DurabilityLimitsHelper });
|
||||
con.register<GameEventHelper>("GameEventHelper", GameEventHelper);
|
||||
con.register<HandbookHelper>("HandbookHelper", HandbookHelper, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<HealthHelper>("HealthHelper", { useClass: HealthHelper });
|
||||
con.register<HideoutHelper>("HideoutHelper", { useClass: HideoutHelper });
|
||||
con.register<InRaidHelper>("InRaidHelper", { useClass: InRaidHelper });
|
||||
con.register<InventoryHelper>("InventoryHelper", { useClass: InventoryHelper });
|
||||
con.register<PaymentHelper>("PaymentHelper", PaymentHelper);
|
||||
con.register<ItemHelper>("ItemHelper", { useClass: ItemHelper });
|
||||
con.register<PresetHelper>("PresetHelper", PresetHelper, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<ProfileHelper>("ProfileHelper", { useClass: ProfileHelper });
|
||||
con.register<QuestHelper>("QuestHelper", { useClass: QuestHelper });
|
||||
con.register<QuestConditionHelper>("QuestConditionHelper", QuestConditionHelper);
|
||||
con.register<RagfairHelper>("RagfairHelper", { useClass: RagfairHelper });
|
||||
con.register<RagfairSortHelper>("RagfairSortHelper", { useClass: RagfairSortHelper });
|
||||
con.register<RagfairSellHelper>("RagfairSellHelper", { useClass: RagfairSellHelper });
|
||||
con.register<RagfairOfferHelper>("RagfairOfferHelper", { useClass: RagfairOfferHelper });
|
||||
con.register<RagfairServerHelper>("RagfairServerHelper", { useClass: RagfairServerHelper });
|
||||
con.register<RepairHelper>("RepairHelper", { useClass: RepairHelper });
|
||||
con.register<TraderHelper>("TraderHelper", TraderHelper);
|
||||
con.register<TraderAssortHelper>("TraderAssortHelper", TraderAssortHelper, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<TradeHelper>("TradeHelper", { useClass: TradeHelper });
|
||||
con.register<NotifierHelper>("NotifierHelper", { useClass: NotifierHelper });
|
||||
con.register<UtilityHelper>("UtilityHelper", UtilityHelper);
|
||||
con.register<WeightedRandomHelper>("WeightedRandomHelper", { useClass: WeightedRandomHelper });
|
||||
con.register<HttpServerHelper>("HttpServerHelper", { useClass: HttpServerHelper });
|
||||
con.register<NotificationSendHelper>("NotificationSendHelper", { useClass: NotificationSendHelper });
|
||||
con.register<SecureContainerHelper>("SecureContainerHelper", { useClass: SecureContainerHelper });
|
||||
con.register<ProbabilityHelper>("ProbabilityHelper", { useClass: ProbabilityHelper });
|
||||
con.register<BotWeaponGeneratorHelper>("BotWeaponGeneratorHelper", { useClass: BotWeaponGeneratorHelper });
|
||||
con.register<BotDifficultyHelper>("BotDifficultyHelper", { useClass: BotDifficultyHelper });
|
||||
con.register<RepeatableQuestHelper>("RepeatableQuestHelper", { useClass: RepeatableQuestHelper });
|
||||
depContainer.register<AssortHelper>("AssortHelper", { useClass: AssortHelper });
|
||||
depContainer.register<BotHelper>("BotHelper", { useClass: BotHelper });
|
||||
depContainer.register<BotGeneratorHelper>("BotGeneratorHelper", { useClass: BotGeneratorHelper });
|
||||
depContainer.register<ContainerHelper>("ContainerHelper", ContainerHelper);
|
||||
depContainer.register<DialogueHelper>("DialogueHelper", { useClass: DialogueHelper });
|
||||
depContainer.register<DurabilityLimitsHelper>("DurabilityLimitsHelper", { useClass: DurabilityLimitsHelper });
|
||||
depContainer.register<GameEventHelper>("GameEventHelper", GameEventHelper);
|
||||
depContainer.register<HandbookHelper>("HandbookHelper", HandbookHelper, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<HealthHelper>("HealthHelper", { useClass: HealthHelper });
|
||||
depContainer.register<HideoutHelper>("HideoutHelper", { useClass: HideoutHelper });
|
||||
depContainer.register<InRaidHelper>("InRaidHelper", { useClass: InRaidHelper });
|
||||
depContainer.register<InventoryHelper>("InventoryHelper", { useClass: InventoryHelper });
|
||||
depContainer.register<PaymentHelper>("PaymentHelper", PaymentHelper);
|
||||
depContainer.register<ItemHelper>("ItemHelper", { useClass: ItemHelper });
|
||||
depContainer.register<PresetHelper>("PresetHelper", PresetHelper, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<ProfileHelper>("ProfileHelper", { useClass: ProfileHelper });
|
||||
depContainer.register<QuestHelper>("QuestHelper", { useClass: QuestHelper });
|
||||
depContainer.register<QuestConditionHelper>("QuestConditionHelper", QuestConditionHelper);
|
||||
depContainer.register<RagfairHelper>("RagfairHelper", { useClass: RagfairHelper });
|
||||
depContainer.register<RagfairSortHelper>("RagfairSortHelper", { useClass: RagfairSortHelper });
|
||||
depContainer.register<RagfairSellHelper>("RagfairSellHelper", { useClass: RagfairSellHelper });
|
||||
depContainer.register<RagfairOfferHelper>("RagfairOfferHelper", { useClass: RagfairOfferHelper });
|
||||
depContainer.register<RagfairServerHelper>("RagfairServerHelper", { useClass: RagfairServerHelper });
|
||||
depContainer.register<RepairHelper>("RepairHelper", { useClass: RepairHelper });
|
||||
depContainer.register<TraderHelper>("TraderHelper", TraderHelper);
|
||||
depContainer.register<TraderAssortHelper>("TraderAssortHelper", TraderAssortHelper, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<TradeHelper>("TradeHelper", { useClass: TradeHelper });
|
||||
depContainer.register<NotifierHelper>("NotifierHelper", { useClass: NotifierHelper });
|
||||
depContainer.register<UtilityHelper>("UtilityHelper", UtilityHelper);
|
||||
depContainer.register<WeightedRandomHelper>("WeightedRandomHelper", { useClass: WeightedRandomHelper });
|
||||
depContainer.register<HttpServerHelper>("HttpServerHelper", { useClass: HttpServerHelper });
|
||||
depContainer.register<NotificationSendHelper>("NotificationSendHelper", { useClass: NotificationSendHelper });
|
||||
depContainer.register<SecureContainerHelper>("SecureContainerHelper", { useClass: SecureContainerHelper });
|
||||
depContainer.register<ProbabilityHelper>("ProbabilityHelper", { useClass: ProbabilityHelper });
|
||||
depContainer.register<BotWeaponGeneratorHelper>("BotWeaponGeneratorHelper", {
|
||||
useClass: BotWeaponGeneratorHelper,
|
||||
});
|
||||
depContainer.register<BotDifficultyHelper>("BotDifficultyHelper", { useClass: BotDifficultyHelper });
|
||||
depContainer.register<RepeatableQuestHelper>("RepeatableQuestHelper", { useClass: RepeatableQuestHelper });
|
||||
}
|
||||
|
||||
private static registerLoaders(con: DependencyContainer): void
|
||||
private static registerLoaders(depContainer: DependencyContainer): void
|
||||
{
|
||||
// Loaders
|
||||
con.register<BundleLoader>("BundleLoader", BundleLoader, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<PreAkiModLoader>("PreAkiModLoader", PreAkiModLoader, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<PostAkiModLoader>("PostAkiModLoader", PostAkiModLoader, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<BundleLoader>("BundleLoader", BundleLoader, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<PreAkiModLoader>("PreAkiModLoader", PreAkiModLoader, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<PostAkiModLoader>("PostAkiModLoader", PostAkiModLoader, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
}
|
||||
|
||||
private static registerCallbacks(con: DependencyContainer): void
|
||||
private static registerCallbacks(depContainer: DependencyContainer): void
|
||||
{
|
||||
// Callbacks
|
||||
con.register<BotCallbacks>("BotCallbacks", { useClass: BotCallbacks });
|
||||
con.register<BundleCallbacks>("BundleCallbacks", { useClass: BundleCallbacks });
|
||||
con.register<ClientLogCallbacks>("ClientLogCallbacks", { useClass: ClientLogCallbacks });
|
||||
con.register<CustomizationCallbacks>("CustomizationCallbacks", { useClass: CustomizationCallbacks });
|
||||
con.register<DataCallbacks>("DataCallbacks", { useClass: DataCallbacks });
|
||||
con.register<DialogueCallbacks>("DialogueCallbacks", { useClass: DialogueCallbacks });
|
||||
con.register<GameCallbacks>("GameCallbacks", { useClass: GameCallbacks });
|
||||
con.register<HandbookCallbacks>("HandbookCallbacks", { useClass: HandbookCallbacks });
|
||||
con.register<HealthCallbacks>("HealthCallbacks", { useClass: HealthCallbacks });
|
||||
con.register<HideoutCallbacks>("HideoutCallbacks", { useClass: HideoutCallbacks });
|
||||
con.register<HttpCallbacks>("HttpCallbacks", { useClass: HttpCallbacks });
|
||||
con.register<InraidCallbacks>("InraidCallbacks", { useClass: InraidCallbacks });
|
||||
con.register<InsuranceCallbacks>("InsuranceCallbacks", { useClass: InsuranceCallbacks });
|
||||
con.register<InventoryCallbacks>("InventoryCallbacks", { useClass: InventoryCallbacks });
|
||||
con.register<ItemEventCallbacks>("ItemEventCallbacks", { useClass: ItemEventCallbacks });
|
||||
con.register<LauncherCallbacks>("LauncherCallbacks", { useClass: LauncherCallbacks });
|
||||
con.register<LocationCallbacks>("LocationCallbacks", { useClass: LocationCallbacks });
|
||||
con.register<MatchCallbacks>("MatchCallbacks", { useClass: MatchCallbacks });
|
||||
con.register<ModCallbacks>("ModCallbacks", { useClass: ModCallbacks });
|
||||
con.register<PostDBModLoader>("PostDBModLoader", { useClass: PostDBModLoader });
|
||||
con.register<NoteCallbacks>("NoteCallbacks", { useClass: NoteCallbacks });
|
||||
con.register<NotifierCallbacks>("NotifierCallbacks", { useClass: NotifierCallbacks });
|
||||
con.register<PresetBuildCallbacks>("PresetBuildCallbacks", { useClass: PresetBuildCallbacks });
|
||||
con.register<PresetCallbacks>("PresetCallbacks", { useClass: PresetCallbacks });
|
||||
con.register<ProfileCallbacks>("ProfileCallbacks", { useClass: ProfileCallbacks });
|
||||
con.register<QuestCallbacks>("QuestCallbacks", { useClass: QuestCallbacks });
|
||||
con.register<RagfairCallbacks>("RagfairCallbacks", { useClass: RagfairCallbacks });
|
||||
con.register<RepairCallbacks>("RepairCallbacks", { useClass: RepairCallbacks });
|
||||
con.register<SaveCallbacks>("SaveCallbacks", { useClass: SaveCallbacks });
|
||||
con.register<TradeCallbacks>("TradeCallbacks", { useClass: TradeCallbacks });
|
||||
con.register<TraderCallbacks>("TraderCallbacks", { useClass: TraderCallbacks });
|
||||
con.register<WeatherCallbacks>("WeatherCallbacks", { useClass: WeatherCallbacks });
|
||||
con.register<WishlistCallbacks>("WishlistCallbacks", { useClass: WishlistCallbacks });
|
||||
depContainer.register<BotCallbacks>("BotCallbacks", { useClass: BotCallbacks });
|
||||
depContainer.register<BundleCallbacks>("BundleCallbacks", { useClass: BundleCallbacks });
|
||||
depContainer.register<ClientLogCallbacks>("ClientLogCallbacks", { useClass: ClientLogCallbacks });
|
||||
depContainer.register<CustomizationCallbacks>("CustomizationCallbacks", { useClass: CustomizationCallbacks });
|
||||
depContainer.register<DataCallbacks>("DataCallbacks", { useClass: DataCallbacks });
|
||||
depContainer.register<DialogueCallbacks>("DialogueCallbacks", { useClass: DialogueCallbacks });
|
||||
depContainer.register<GameCallbacks>("GameCallbacks", { useClass: GameCallbacks });
|
||||
depContainer.register<HandbookCallbacks>("HandbookCallbacks", { useClass: HandbookCallbacks });
|
||||
depContainer.register<HealthCallbacks>("HealthCallbacks", { useClass: HealthCallbacks });
|
||||
depContainer.register<HideoutCallbacks>("HideoutCallbacks", { useClass: HideoutCallbacks });
|
||||
depContainer.register<HttpCallbacks>("HttpCallbacks", { useClass: HttpCallbacks });
|
||||
depContainer.register<InraidCallbacks>("InraidCallbacks", { useClass: InraidCallbacks });
|
||||
depContainer.register<InsuranceCallbacks>("InsuranceCallbacks", { useClass: InsuranceCallbacks });
|
||||
depContainer.register<InventoryCallbacks>("InventoryCallbacks", { useClass: InventoryCallbacks });
|
||||
depContainer.register<ItemEventCallbacks>("ItemEventCallbacks", { useClass: ItemEventCallbacks });
|
||||
depContainer.register<LauncherCallbacks>("LauncherCallbacks", { useClass: LauncherCallbacks });
|
||||
depContainer.register<LocationCallbacks>("LocationCallbacks", { useClass: LocationCallbacks });
|
||||
depContainer.register<MatchCallbacks>("MatchCallbacks", { useClass: MatchCallbacks });
|
||||
depContainer.register<ModCallbacks>("ModCallbacks", { useClass: ModCallbacks });
|
||||
depContainer.register<PostDBModLoader>("PostDBModLoader", { useClass: PostDBModLoader });
|
||||
depContainer.register<NoteCallbacks>("NoteCallbacks", { useClass: NoteCallbacks });
|
||||
depContainer.register<NotifierCallbacks>("NotifierCallbacks", { useClass: NotifierCallbacks });
|
||||
depContainer.register<PresetBuildCallbacks>("PresetBuildCallbacks", { useClass: PresetBuildCallbacks });
|
||||
depContainer.register<PresetCallbacks>("PresetCallbacks", { useClass: PresetCallbacks });
|
||||
depContainer.register<ProfileCallbacks>("ProfileCallbacks", { useClass: ProfileCallbacks });
|
||||
depContainer.register<QuestCallbacks>("QuestCallbacks", { useClass: QuestCallbacks });
|
||||
depContainer.register<RagfairCallbacks>("RagfairCallbacks", { useClass: RagfairCallbacks });
|
||||
depContainer.register<RepairCallbacks>("RepairCallbacks", { useClass: RepairCallbacks });
|
||||
depContainer.register<SaveCallbacks>("SaveCallbacks", { useClass: SaveCallbacks });
|
||||
depContainer.register<TradeCallbacks>("TradeCallbacks", { useClass: TradeCallbacks });
|
||||
depContainer.register<TraderCallbacks>("TraderCallbacks", { useClass: TraderCallbacks });
|
||||
depContainer.register<WeatherCallbacks>("WeatherCallbacks", { useClass: WeatherCallbacks });
|
||||
depContainer.register<WishlistCallbacks>("WishlistCallbacks", { useClass: WishlistCallbacks });
|
||||
}
|
||||
|
||||
private static registerServices(con: DependencyContainer): void
|
||||
private static registerServices(depContainer: DependencyContainer): void
|
||||
{
|
||||
// Services
|
||||
con.register<ImageRouteService>("ImageRouteService", ImageRouteService, { lifecycle: Lifecycle.Singleton });
|
||||
|
||||
con.register<FenceService>("FenceService", FenceService, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<PlayerService>("PlayerService", { useClass: PlayerService });
|
||||
con.register<PaymentService>("PaymentService", { useClass: PaymentService });
|
||||
con.register<InsuranceService>("InsuranceService", InsuranceService, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<TraderAssortService>("TraderAssortService", TraderAssortService, {
|
||||
depContainer.register<ImageRouteService>("ImageRouteService", ImageRouteService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
|
||||
con.register<RagfairPriceService>("RagfairPriceService", RagfairPriceService, {
|
||||
depContainer.register<FenceService>("FenceService", FenceService, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<PlayerService>("PlayerService", { useClass: PlayerService });
|
||||
depContainer.register<PaymentService>("PaymentService", { useClass: PaymentService });
|
||||
depContainer.register<InsuranceService>("InsuranceService", InsuranceService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<RagfairCategoriesService>("RagfairCategoriesService", RagfairCategoriesService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<RagfairOfferService>("RagfairOfferService", RagfairOfferService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<RagfairLinkedItemService>("RagfairLinkedItemService", RagfairLinkedItemService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<RagfairRequiredItemsService>("RagfairRequiredItemsService", RagfairRequiredItemsService, {
|
||||
depContainer.register<TraderAssortService>("TraderAssortService", TraderAssortService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
|
||||
con.register<NotificationService>("NotificationService", NotificationService, {
|
||||
depContainer.register<RagfairPriceService>("RagfairPriceService", RagfairPriceService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<MatchLocationService>("MatchLocationService", MatchLocationService, {
|
||||
depContainer.register<RagfairCategoriesService>("RagfairCategoriesService", RagfairCategoriesService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<ModCompilerService>("ModCompilerService", ModCompilerService);
|
||||
con.register<HashCacheService>("HashCacheService", HashCacheService, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<LocaleService>("LocaleService", LocaleService, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<ProfileFixerService>("ProfileFixerService", ProfileFixerService);
|
||||
con.register<RepairService>("RepairService", RepairService);
|
||||
con.register<BotLootCacheService>("BotLootCacheService", BotLootCacheService, {
|
||||
depContainer.register<RagfairOfferService>("RagfairOfferService", RagfairOfferService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<CustomItemService>("CustomItemService", CustomItemService);
|
||||
con.register<BotEquipmentFilterService>("BotEquipmentFilterService", BotEquipmentFilterService);
|
||||
con.register<ProfileSnapshotService>("ProfileSnapshotService", ProfileSnapshotService, {
|
||||
depContainer.register<RagfairLinkedItemService>("RagfairLinkedItemService", RagfairLinkedItemService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<ItemFilterService>("ItemFilterService", ItemFilterService, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<BotGenerationCacheService>("BotGenerationCacheService", BotGenerationCacheService, {
|
||||
depContainer.register<RagfairRequiredItemsService>("RagfairRequiredItemsService", RagfairRequiredItemsService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<LocalisationService>("LocalisationService", LocalisationService, {
|
||||
|
||||
depContainer.register<NotificationService>("NotificationService", NotificationService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<CustomLocationWaveService>("CustomLocationWaveService", CustomLocationWaveService, {
|
||||
depContainer.register<MatchLocationService>("MatchLocationService", MatchLocationService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<OpenZoneService>("OpenZoneService", OpenZoneService, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<ItemBaseClassService>("ItemBaseClassService", ItemBaseClassService, {
|
||||
depContainer.register<ModCompilerService>("ModCompilerService", ModCompilerService);
|
||||
depContainer.register<HashCacheService>("HashCacheService", HashCacheService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<BotEquipmentModPoolService>("BotEquipmentModPoolService", BotEquipmentModPoolService, {
|
||||
depContainer.register<LocaleService>("LocaleService", LocaleService, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<ProfileFixerService>("ProfileFixerService", ProfileFixerService);
|
||||
depContainer.register<RepairService>("RepairService", RepairService);
|
||||
depContainer.register<BotLootCacheService>("BotLootCacheService", BotLootCacheService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<BotWeaponModLimitService>("BotWeaponModLimitService", BotWeaponModLimitService, {
|
||||
depContainer.register<CustomItemService>("CustomItemService", CustomItemService);
|
||||
depContainer.register<BotEquipmentFilterService>("BotEquipmentFilterService", BotEquipmentFilterService);
|
||||
depContainer.register<ProfileSnapshotService>("ProfileSnapshotService", ProfileSnapshotService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<SeasonalEventService>("SeasonalEventService", SeasonalEventService, {
|
||||
depContainer.register<ItemFilterService>("ItemFilterService", ItemFilterService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<MatchBotDetailsCacheService>("MatchBotDetailsCacheService", MatchBotDetailsCacheService, {
|
||||
depContainer.register<BotGenerationCacheService>("BotGenerationCacheService", BotGenerationCacheService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
con.register<RagfairTaxService>("RagfairTaxService", RagfairTaxService, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<TraderPurchasePersisterService>("TraderPurchasePersisterService", TraderPurchasePersisterService);
|
||||
con.register<PmcChatResponseService>("PmcChatResponseService", PmcChatResponseService);
|
||||
con.register<GiftService>("GiftService", GiftService);
|
||||
con.register<MailSendService>("MailSendService", MailSendService);
|
||||
depContainer.register<LocalisationService>("LocalisationService", LocalisationService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<CustomLocationWaveService>("CustomLocationWaveService", CustomLocationWaveService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<OpenZoneService>("OpenZoneService", OpenZoneService, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<ItemBaseClassService>("ItemBaseClassService", ItemBaseClassService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<BotEquipmentModPoolService>("BotEquipmentModPoolService", BotEquipmentModPoolService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<BotWeaponModLimitService>("BotWeaponModLimitService", BotWeaponModLimitService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<SeasonalEventService>("SeasonalEventService", SeasonalEventService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<MatchBotDetailsCacheService>("MatchBotDetailsCacheService", MatchBotDetailsCacheService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<RagfairTaxService>("RagfairTaxService", RagfairTaxService, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<TraderPurchasePersisterService>(
|
||||
"TraderPurchasePersisterService",
|
||||
TraderPurchasePersisterService,
|
||||
);
|
||||
depContainer.register<PmcChatResponseService>("PmcChatResponseService", PmcChatResponseService);
|
||||
depContainer.register<GiftService>("GiftService", GiftService);
|
||||
depContainer.register<MailSendService>("MailSendService", MailSendService);
|
||||
depContainer.register<RaidTimeAdjustmentService>("RaidTimeAdjustmentService", RaidTimeAdjustmentService);
|
||||
}
|
||||
|
||||
private static registerServers(con: DependencyContainer): void
|
||||
private static registerServers(depContainer: DependencyContainer): void
|
||||
{
|
||||
// Servers
|
||||
con.register<DatabaseServer>("DatabaseServer", DatabaseServer, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<HttpServer>("HttpServer", HttpServer, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<WebSocketServer>("WebSocketServer", WebSocketServer, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<RagfairServer>("RagfairServer", RagfairServer);
|
||||
con.register<SaveServer>("SaveServer", SaveServer, { lifecycle: Lifecycle.Singleton });
|
||||
con.register<ConfigServer>("ConfigServer", ConfigServer, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<DatabaseServer>("DatabaseServer", DatabaseServer, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<HttpServer>("HttpServer", HttpServer, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<WebSocketServer>("WebSocketServer", WebSocketServer, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<RagfairServer>("RagfairServer", RagfairServer);
|
||||
depContainer.register<SaveServer>("SaveServer", SaveServer, { lifecycle: Lifecycle.Singleton });
|
||||
depContainer.register<ConfigServer>("ConfigServer", ConfigServer, { lifecycle: Lifecycle.Singleton });
|
||||
}
|
||||
|
||||
private static registerControllers(con: DependencyContainer): void
|
||||
private static registerControllers(depContainer: DependencyContainer): void
|
||||
{
|
||||
// Controllers
|
||||
con.register<BotController>("BotController", { useClass: BotController });
|
||||
con.register<ClientLogController>("ClientLogController", { useClass: ClientLogController });
|
||||
con.register<CustomizationController>("CustomizationController", { useClass: CustomizationController });
|
||||
con.register<DialogueController>("DialogueController", { useClass: DialogueController });
|
||||
con.register<GameController>("GameController", { useClass: GameController });
|
||||
con.register<HandbookController>("HandbookController", { useClass: HandbookController });
|
||||
con.register<HealthController>("HealthController", { useClass: HealthController });
|
||||
con.register<HideoutController>("HideoutController", { useClass: HideoutController });
|
||||
con.register<InraidController>("InraidController", { useClass: InraidController });
|
||||
con.register<InsuranceController>("InsuranceController", { useClass: InsuranceController });
|
||||
con.register<InventoryController>("InventoryController", { useClass: InventoryController });
|
||||
con.register<LauncherController>("LauncherController", { useClass: LauncherController });
|
||||
con.register<LocationController>("LocationController", { useClass: LocationController });
|
||||
con.register<MatchController>("MatchController", MatchController);
|
||||
con.register<NoteController>("NoteController", { useClass: NoteController });
|
||||
con.register<NotifierController>("NotifierController", { useClass: NotifierController });
|
||||
con.register<PresetBuildController>("PresetBuildController", { useClass: PresetBuildController });
|
||||
con.register<PresetController>("PresetController", { useClass: PresetController });
|
||||
con.register<ProfileController>("ProfileController", { useClass: ProfileController });
|
||||
con.register<QuestController>("QuestController", { useClass: QuestController });
|
||||
con.register<RagfairController>("RagfairController", { useClass: RagfairController });
|
||||
con.register<RepairController>("RepairController", { useClass: RepairController });
|
||||
con.register<RepeatableQuestController>("RepeatableQuestController", { useClass: RepeatableQuestController });
|
||||
con.register<TradeController>("TradeController", { useClass: TradeController });
|
||||
con.register<TraderController>("TraderController", { useClass: TraderController });
|
||||
con.register<WeatherController>("WeatherController", { useClass: WeatherController });
|
||||
con.register<WishlistController>("WishlistController", WishlistController);
|
||||
depContainer.register<BotController>("BotController", { useClass: BotController });
|
||||
depContainer.register<ClientLogController>("ClientLogController", { useClass: ClientLogController });
|
||||
depContainer.register<CustomizationController>("CustomizationController", {
|
||||
useClass: CustomizationController,
|
||||
});
|
||||
depContainer.register<DialogueController>("DialogueController", { useClass: DialogueController });
|
||||
depContainer.register<GameController>("GameController", { useClass: GameController });
|
||||
depContainer.register<HandbookController>("HandbookController", { useClass: HandbookController });
|
||||
depContainer.register<HealthController>("HealthController", { useClass: HealthController });
|
||||
depContainer.register<HideoutController>("HideoutController", { useClass: HideoutController });
|
||||
depContainer.register<InraidController>("InraidController", { useClass: InraidController });
|
||||
depContainer.register<InsuranceController>("InsuranceController", { useClass: InsuranceController });
|
||||
depContainer.register<InventoryController>("InventoryController", { useClass: InventoryController });
|
||||
depContainer.register<LauncherController>("LauncherController", { useClass: LauncherController });
|
||||
depContainer.register<LocationController>("LocationController", { useClass: LocationController });
|
||||
depContainer.register<MatchController>("MatchController", MatchController);
|
||||
depContainer.register<NoteController>("NoteController", { useClass: NoteController });
|
||||
depContainer.register<NotifierController>("NotifierController", { useClass: NotifierController });
|
||||
depContainer.register<PresetBuildController>("PresetBuildController", { useClass: PresetBuildController });
|
||||
depContainer.register<PresetController>("PresetController", { useClass: PresetController });
|
||||
depContainer.register<ProfileController>("ProfileController", { useClass: ProfileController });
|
||||
depContainer.register<QuestController>("QuestController", { useClass: QuestController });
|
||||
depContainer.register<RagfairController>("RagfairController", { useClass: RagfairController });
|
||||
depContainer.register<RepairController>("RepairController", { useClass: RepairController });
|
||||
depContainer.register<RepeatableQuestController>("RepeatableQuestController", {
|
||||
useClass: RepeatableQuestController,
|
||||
});
|
||||
depContainer.register<TradeController>("TradeController", { useClass: TradeController });
|
||||
depContainer.register<TraderController>("TraderController", { useClass: TraderController });
|
||||
depContainer.register<WeatherController>("WeatherController", { useClass: WeatherController });
|
||||
depContainer.register<WishlistController>("WishlistController", WishlistController);
|
||||
}
|
||||
}
|
||||
|
@ -196,7 +196,6 @@ export class BotEquipmentModGenerator
|
||||
// Get pool of mods that fit weapon
|
||||
const compatibleModsPool = modPool[parentTemplate._id];
|
||||
|
||||
// biome-ignore lint/complexity/useSimplifiedLogicExpression: <explanation>
|
||||
if (
|
||||
!((parentTemplate._props.Slots.length || parentTemplate._props.Cartridges?.length)
|
||||
|| parentTemplate._props.Chambers?.length)
|
||||
|
@ -522,6 +522,7 @@ export class BotGenerator
|
||||
return;
|
||||
}
|
||||
|
||||
// more color = more op
|
||||
botInfo.GameVersion = this.weightedRandomHelper.getWeightedValue(this.pmcConfig.gameVersionWeight);
|
||||
botInfo.MemberCategory = Number.parseInt(
|
||||
this.weightedRandomHelper.getWeightedValue(this.pmcConfig.accountTypeWeight),
|
||||
|
@ -352,13 +352,21 @@ export class BotLootGenerator
|
||||
itemsToAdd,
|
||||
inventoryToAddItemsTo,
|
||||
);
|
||||
if (itemAddedResult === ItemAddedResult.NO_SPACE)
|
||||
if (itemAddedResult !== ItemAddedResult.SUCCESS)
|
||||
{
|
||||
|
||||
if (itemAddedResult === ItemAddedResult.NO_CONTAINERS)
|
||||
{
|
||||
// Bot has no container to put item in, exit
|
||||
this.logger.debug(`Unable to add ${totalItemCount} items to bot as it lacks a container to include them`);
|
||||
break;
|
||||
}
|
||||
|
||||
fitItemIntoContainerAttempts++;
|
||||
if (fitItemIntoContainerAttempts >= 4)
|
||||
{
|
||||
this.logger.debug(
|
||||
`Failed to place item ${i} of ${totalItemCount} item into ${botRole} container: ${equipmentSlots}, ${fitItemIntoContainerAttempts} times, skipping`,
|
||||
`Failed to place item ${i} of ${totalItemCount} items into ${botRole} containers: ${equipmentSlots.join(",")}. Tried ${fitItemIntoContainerAttempts} times, reason: ${ItemAddedResult[itemAddedResult]}, skipping`,
|
||||
);
|
||||
|
||||
break;
|
||||
@ -366,6 +374,7 @@ export class BotLootGenerator
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reset counter
|
||||
fitItemIntoContainerAttempts = 0;
|
||||
}
|
||||
|
||||
@ -426,13 +435,18 @@ export class BotLootGenerator
|
||||
isPmc,
|
||||
botLevel,
|
||||
);
|
||||
this.botWeaponGeneratorHelper.addItemWithChildrenToEquipmentSlot(
|
||||
const result = this.botWeaponGeneratorHelper.addItemWithChildrenToEquipmentSlot(
|
||||
[equipmentSlot],
|
||||
generatedWeapon.weapon[0]._id,
|
||||
generatedWeapon.weapon[0]._tpl,
|
||||
[...generatedWeapon.weapon],
|
||||
botInventory,
|
||||
);
|
||||
|
||||
if (result !== ItemAddedResult.SUCCESS)
|
||||
{
|
||||
this.logger.debug(`Failed to add additional weapon ${generatedWeapon.weapon[0]._id} to bot backpack, reason: ${ItemAddedResult[result]}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -205,14 +205,15 @@ export class BotWeaponGenerator
|
||||
this.fillExistingMagazines(weaponWithModsArray, magazine, ammoTpl);
|
||||
}
|
||||
|
||||
// Add cartridge to gun chamber if weapon has slot for it
|
||||
// Add cartridge(s) to gun chamber(s)
|
||||
if (
|
||||
weaponItemTemplate._props.Chambers?.length === 1
|
||||
&& weaponItemTemplate._props.Chambers[0]?._name === "patron_in_weapon"
|
||||
weaponItemTemplate._props.Chambers?.length > 0
|
||||
&& weaponItemTemplate._props.Chambers[0]?._props?.filters[0]?.Filter?.includes(ammoTpl)
|
||||
)
|
||||
{
|
||||
this.addCartridgeToChamber(weaponWithModsArray, ammoTpl, "patron_in_weapon");
|
||||
// Guns have variety of possible Chamber ids, patron_in_weapon/patron_in_weapon_000/patron_in_weapon_001
|
||||
const chamberSlotNames = weaponItemTemplate._props.Chambers.map(x => x._name);
|
||||
this.addCartridgeToChamber(weaponWithModsArray, ammoTpl, chamberSlotNames);
|
||||
}
|
||||
|
||||
// Fill UBGL if found
|
||||
@ -235,31 +236,34 @@ export class BotWeaponGenerator
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a cartridge into a weapon
|
||||
* Insert a cartridge(s) into a weapon
|
||||
* Handles all chambers - patron_in_weapon, patron_in_weapon_000 etc
|
||||
* @param weaponWithModsArray Weapon and mods
|
||||
* @param ammoTpl Cartridge to add to weapon
|
||||
* @param desiredSlotId name of slot, e.g. patron_in_weapon
|
||||
* @param chamberSlotIds name of slots to create or add ammo to
|
||||
*/
|
||||
protected addCartridgeToChamber(weaponWithModsArray: Item[], ammoTpl: string, desiredSlotId: string): void
|
||||
protected addCartridgeToChamber(weaponWithModsArray: Item[], ammoTpl: string, chamberSlotIds: string[]): void
|
||||
{
|
||||
// Check for slot first
|
||||
const existingItemWithSlot = weaponWithModsArray.find((x) => x.slotId === desiredSlotId);
|
||||
if (!existingItemWithSlot)
|
||||
for (const slotId of chamberSlotIds)
|
||||
{
|
||||
// Not found, add fresh
|
||||
weaponWithModsArray.push({
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: ammoTpl,
|
||||
parentId: weaponWithModsArray[0]._id,
|
||||
slotId: desiredSlotId,
|
||||
upd: { StackObjectsCount: 1 },
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Already exists, update values
|
||||
existingItemWithSlot.upd = { StackObjectsCount: 1 };
|
||||
existingItemWithSlot._tpl = ammoTpl;
|
||||
const existingItemWithSlot = weaponWithModsArray.find((x) => x.slotId === slotId);
|
||||
if (!existingItemWithSlot)
|
||||
{
|
||||
// Not found, add new slot to weapon
|
||||
weaponWithModsArray.push({
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: ammoTpl,
|
||||
parentId: weaponWithModsArray[0]._id,
|
||||
slotId: slotId,
|
||||
upd: { StackObjectsCount: 1 },
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Already exists, update values
|
||||
existingItemWithSlot._tpl = ammoTpl;
|
||||
existingItemWithSlot.upd = { StackObjectsCount: 1 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -612,7 +616,7 @@ export class BotWeaponGenerator
|
||||
{
|
||||
const possibleAmmo = this.weightedRandomHelper.getWeightedValue<string>(compatibleCartridges);
|
||||
|
||||
// Check compatibility
|
||||
// Weapon has chamber but does not support cartridge
|
||||
if (weaponTemplate._props.Chambers[0]
|
||||
&& !weaponTemplate._props.Chambers[0]._props.filters[0].Filter.includes(possibleAmmo)
|
||||
)
|
||||
|
@ -788,7 +788,7 @@ export class LocationGenerator
|
||||
}
|
||||
else if (this.itemHelper.isOfBaseclass(chosenTpl, BaseClasses.AMMO_BOX))
|
||||
{
|
||||
// Fill with cartrdiges
|
||||
// Fill with cartridges
|
||||
const ammoBoxTemplate = this.itemHelper.getItem(chosenTpl)[1];
|
||||
const ammoBoxItem: Item[] = [{ _id: this.objectId.generate(), _tpl: chosenTpl }];
|
||||
this.itemHelper.addCartridgesToAmmoBox(ammoBoxItem, ammoBoxTemplate);
|
||||
|
@ -12,6 +12,7 @@ import { IBotType } from "@spt-aki/models/eft/common/tables/IBotType";
|
||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||
import { AccountTypes } from "@spt-aki/models/enums/AccountTypes";
|
||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||
import { ItemAddedResult } from "@spt-aki/models/enums/ItemAddedResult";
|
||||
import { MemberCategory } from "@spt-aki/models/enums/MemberCategory";
|
||||
import { Traders } from "@spt-aki/models/enums/Traders";
|
||||
import { IPlayerScavConfig, KarmaLevel } from "@spt-aki/models/spt/config/IPlayerScavConfig";
|
||||
@ -125,13 +126,18 @@ export class PlayerScavGenerator
|
||||
_tpl: labsCard._id,
|
||||
...this.botGeneratorHelper.generateExtraPropertiesForItem(labsCard),
|
||||
}];
|
||||
this.botWeaponGeneratorHelper.addItemWithChildrenToEquipmentSlot(
|
||||
const result = this.botWeaponGeneratorHelper.addItemWithChildrenToEquipmentSlot(
|
||||
["TacticalVest", "Pockets", "Backpack"],
|
||||
itemsToAdd[0]._id,
|
||||
labsCard._id,
|
||||
itemsToAdd,
|
||||
scavData.Inventory,
|
||||
);
|
||||
|
||||
if (result !== ItemAddedResult.SUCCESS)
|
||||
{
|
||||
this.logger.debug(`Unable to add keycard to bot. Reason: ${ItemAddedResult[result]}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove secure container
|
||||
|
@ -4,10 +4,12 @@ import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen
|
||||
import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
|
||||
import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper";
|
||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
||||
import { EquipmentSlots } from "@spt-aki/models/enums/EquipmentSlots";
|
||||
import { ItemAddedResult } from "@spt-aki/models/enums/ItemAddedResult";
|
||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
||||
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
||||
|
||||
@injectable()
|
||||
export class ExternalInventoryMagGen implements IInventoryMagGen
|
||||
@ -17,6 +19,7 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("BotWeaponGeneratorHelper") protected botWeaponGeneratorHelper: BotWeaponGeneratorHelper,
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil
|
||||
)
|
||||
{}
|
||||
|
||||
@ -25,6 +28,7 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
||||
return 99;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
canHandleInventoryMagGen(inventoryMagGen: InventoryMagGen): boolean
|
||||
{
|
||||
return true; // Fallback, if code reaches here it means no other implementation can handle this type of magazine
|
||||
@ -32,8 +36,15 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
||||
|
||||
process(inventoryMagGen: InventoryMagGen): void
|
||||
{
|
||||
// Cout of attempts to fit a magazine into bot inventory
|
||||
let fitAttempts = 0;
|
||||
|
||||
// Magazine Db template
|
||||
let magTemplate = inventoryMagGen.getMagazineTemplate();
|
||||
let magazineTpl = magTemplate._id;
|
||||
const weapon = inventoryMagGen.getWeaponTemplate();
|
||||
const attemptedMagBlacklist: string[] = [];
|
||||
const defaultMagazineTpl = this.botWeaponGeneratorHelper.getWeaponsDefaultMagazineTpl(weapon);
|
||||
const randomizedMagazineCount = Number(
|
||||
this.botWeaponGeneratorHelper.getRandomizedMagazineCount(inventoryMagGen.getMagCount()),
|
||||
);
|
||||
@ -45,7 +56,7 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
||||
magTemplate,
|
||||
);
|
||||
|
||||
const ableToFitMagazinesIntoBotInventory = this.botWeaponGeneratorHelper.addItemWithChildrenToEquipmentSlot(
|
||||
const fitsIntoInventory = this.botWeaponGeneratorHelper.addItemWithChildrenToEquipmentSlot(
|
||||
[EquipmentSlots.TACTICAL_VEST, EquipmentSlots.POCKETS],
|
||||
magazineWithAmmo[0]._id,
|
||||
magazineTpl,
|
||||
@ -53,42 +64,104 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
||||
inventoryMagGen.getPmcInventory(),
|
||||
);
|
||||
|
||||
if (ableToFitMagazinesIntoBotInventory === ItemAddedResult.NO_SPACE && i < randomizedMagazineCount)
|
||||
if (fitsIntoInventory === ItemAddedResult.NO_CONTAINERS)
|
||||
{
|
||||
// We were unable to fit at least the minimum amount of magazines, so we fallback to default magazine
|
||||
// and try again. Temporary workaround to Killa spawning with no extras if he spawns with a drum mag.
|
||||
// TODO: Fix this properly
|
||||
if (
|
||||
magazineTpl
|
||||
=== this.botWeaponGeneratorHelper.getWeaponsDefaultMagazineTpl(
|
||||
inventoryMagGen.getWeaponTemplate(),
|
||||
)
|
||||
)
|
||||
// No containers to fit magazines, stop trying
|
||||
break;
|
||||
}
|
||||
// No space for magazine and we haven't reached desired magazine count
|
||||
else if (fitsIntoInventory === ItemAddedResult.NO_SPACE && i < randomizedMagazineCount)
|
||||
{
|
||||
// Prevent infinite loop by only allowing 5 attempts at fitting a magazine into inventory
|
||||
if (fitAttempts > 5)
|
||||
{
|
||||
this.logger.debug(`Failed ${fitAttempts} times to add magazine ${magazineTpl} to bot inventory, stopping`);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* We were unable to fit at least the minimum amount of magazines,
|
||||
* so we fallback to default magazine and try again.
|
||||
* Temporary workaround to Killa spawning with no extra mags if he spawns with a drum mag */
|
||||
|
||||
if (magazineTpl === defaultMagazineTpl)
|
||||
{
|
||||
// We were already on default - stop here to prevent infinite looping
|
||||
break;
|
||||
}
|
||||
|
||||
// Get default magazine tpl, reset loop counter by 1 and try again
|
||||
magazineTpl = this.botWeaponGeneratorHelper.getWeaponsDefaultMagazineTpl(
|
||||
inventoryMagGen.getWeaponTemplate(),
|
||||
);
|
||||
// Add failed magazine tpl to blacklist
|
||||
attemptedMagBlacklist.push(magazineTpl);
|
||||
|
||||
// Set chosen magazine tpl to the weapons default magazine tpl and try to fit into inventory next loop
|
||||
magazineTpl = defaultMagazineTpl;
|
||||
magTemplate = this.itemHelper.getItem(magazineTpl)[1];
|
||||
if (!magTemplate)
|
||||
{
|
||||
this.logger.error(
|
||||
this.localisationService.getText("bot-unable_to_find_default_magazine_item", magazineTpl),
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Edge case - some weapons (SKS) have an internal magazine as default, choose random non-internal magazine to add to bot instead
|
||||
if (magTemplate._props.ReloadMagType === "InternalMagazine")
|
||||
{
|
||||
break;
|
||||
const result = this.getRandomExternalMagazineForInternalMagazineGun(inventoryMagGen.getWeaponTemplate()._id, attemptedMagBlacklist);
|
||||
if (!result?._id)
|
||||
{
|
||||
this.logger.debug(`Unable to add additional magazine into bot inventory for weapon: ${weapon._name}, attempted: ${fitAttempts} times`);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
magazineTpl = result._id;
|
||||
magTemplate = result;
|
||||
fitAttempts++;
|
||||
}
|
||||
|
||||
// Reduce loop counter by 1 to ensure we get full cout of desired magazines
|
||||
i--;
|
||||
}
|
||||
|
||||
if (fitsIntoInventory === ItemAddedResult.SUCCESS)
|
||||
{
|
||||
// Reset fit counter now it succeeded
|
||||
fitAttempts = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random compatible external magazine for a weapon, excluses internal magazines from possible pool
|
||||
* @param weaponTpl Weapon to get mag for
|
||||
* @returns tpl of magazine
|
||||
*/
|
||||
protected getRandomExternalMagazineForInternalMagazineGun(weaponTpl: string, magazineBlacklist: string[]): ITemplateItem
|
||||
{
|
||||
// The mag Slot data for the weapon
|
||||
const magSlot = this.itemHelper.getItem(weaponTpl)[1]._props.Slots.find(x => x._name === "mod_magazine");
|
||||
if (!magSlot)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// All possible mags that fit into the weapon excluding blacklisted
|
||||
const magazinePool = magSlot._props.filters[0].Filter.filter(x => !magazineBlacklist.includes(x)).map((x) => this.itemHelper.getItem(x)[1]);
|
||||
if (!magazinePool)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Non-internal magazines that fit into the weapon
|
||||
const externalMagazineOnlyPool = magazinePool.filter(x => x._props.ReloadMagType !== "InternalMagazine");
|
||||
if (!externalMagazineOnlyPool || externalMagazineOnlyPool?.length === 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Randomly chosen external magazine
|
||||
return this.randomUtil.getArrayValue(externalMagazineOnlyPool);
|
||||
}
|
||||
}
|
||||
|
@ -46,12 +46,15 @@ export class BotWeaponGeneratorHelper
|
||||
let chamberBulletCount = 0;
|
||||
if (this.magazineIsCylinderRelated(parentItem._name))
|
||||
{
|
||||
// if we have a CylinderMagazine/SpringDrivenCylinder we count the number of camoras as the _max_count of the magazine is 0
|
||||
chamberBulletCount = magTemplate._props.Slots.length;
|
||||
const firstSlotAmmoTpl = magTemplate._props.Cartridges[0]._props.filters[0].Filter[0];
|
||||
const ammoMaxStackSize = this.itemHelper.getItem(firstSlotAmmoTpl)[1]?._props?.StackMaxSize ?? 1;
|
||||
chamberBulletCount = (ammoMaxStackSize === 1)
|
||||
? 1 // Rotating grenade launcher
|
||||
: magTemplate._props.Slots.length; // Shotguns/revolvers. We count the number of camoras as the _max_count of the magazine is 0
|
||||
}
|
||||
else if (parentItem._id === BaseClasses.UBGL)
|
||||
{
|
||||
// underbarrel launchers can only have 1 chambered grenade
|
||||
// Underbarrel launchers can only have 1 chambered grenade
|
||||
chamberBulletCount = 1;
|
||||
}
|
||||
else
|
||||
@ -74,7 +77,7 @@ export class BotWeaponGeneratorHelper
|
||||
// const range = magCounts.max - magCounts.min;
|
||||
// return this.randomUtil.getBiasedRandomNumber(magCounts.min, magCounts.max, Math.round(range * 0.75), 4);
|
||||
|
||||
return this.weightedRandomHelper.getWeightedValue(magCounts.weights);
|
||||
return Number.parseInt(this.weightedRandomHelper.getWeightedValue(magCounts.weights));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,9 +132,15 @@ export class BotWeaponGeneratorHelper
|
||||
ammoItem,
|
||||
], inventory);
|
||||
|
||||
if (result === ItemAddedResult.NO_SPACE)
|
||||
if (result !== ItemAddedResult.SUCCESS)
|
||||
{
|
||||
this.logger.debug(`Unable to add ammo: ${ammoItem._tpl} to bot equipment`);
|
||||
this.logger.debug(`Unable to add ammo: ${ammoItem._tpl} to bot inventory, ${ItemAddedResult[result]}`);
|
||||
|
||||
if (result === ItemAddedResult.NO_SPACE || result === ItemAddedResult.NO_CONTAINERS)
|
||||
{
|
||||
// If there's no space for 1 stack, there's no space for the others
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,18 +173,26 @@ export class BotWeaponGeneratorHelper
|
||||
inventory: Inventory,
|
||||
): ItemAddedResult
|
||||
{
|
||||
let missingContainerCount = 0;
|
||||
for (const slot of equipmentSlots)
|
||||
{
|
||||
// Get container to put item into
|
||||
const container = inventory.items.find((i) => i.slotId === slot);
|
||||
if (!container)
|
||||
{
|
||||
// Desired equipment container (e.g. backpack) not found
|
||||
this.logger.debug(
|
||||
`Unable to add item: ${
|
||||
itemWithChildren[0]._tpl
|
||||
} to: ${slot}, slot missing/bot generated without equipment`,
|
||||
);
|
||||
missingContainerCount++;
|
||||
if (missingContainerCount === equipmentSlots.length)
|
||||
{
|
||||
// Bot doesnt have any containers
|
||||
this.logger.debug(
|
||||
`Unable to add item: ${
|
||||
itemWithChildren[0]._tpl
|
||||
} to bot as it lacks the following containers: ${equipmentSlots.join(",")}`,
|
||||
);
|
||||
|
||||
return ItemAddedResult.NO_CONTAINERS
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -194,8 +211,12 @@ export class BotWeaponGeneratorHelper
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get x/y grid size of item
|
||||
const itemSize = this.inventoryHelper.getItemSize(parentTpl, parentId, itemWithChildren);
|
||||
|
||||
// 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;
|
||||
for (const slotGrid of containerTemplate[1]._props.Grids)
|
||||
{
|
||||
// Grid is empty, skip
|
||||
@ -210,13 +231,13 @@ export class BotWeaponGeneratorHelper
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get all base level items in backpack
|
||||
const containerItems = inventory.items.filter((i) =>
|
||||
// Get all root items in backpack
|
||||
const existingContainerItems = inventory.items.filter((i) =>
|
||||
i.parentId === container._id && i.slotId === slotGrid._name
|
||||
);
|
||||
|
||||
// Get a copy of base level items we can iterate over
|
||||
const containerItemsToCheck = containerItems.filter((x) => x.slotId === slotGrid._name);
|
||||
const containerItemsToCheck = existingContainerItems.filter((x) => x.slotId === slotGrid._name);
|
||||
for (const item of containerItemsToCheck)
|
||||
{
|
||||
// Look for children on items, insert into array if found
|
||||
@ -224,7 +245,7 @@ export class BotWeaponGeneratorHelper
|
||||
const itemWithChildren = this.itemHelper.findAndReturnChildrenAsItems(inventory.items, item._id);
|
||||
if (itemWithChildren.length > 1)
|
||||
{
|
||||
containerItems.splice(containerItems.indexOf(item), 1, ...itemWithChildren);
|
||||
existingContainerItems.splice(existingContainerItems.indexOf(item), 1, ...itemWithChildren);
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,9 +253,10 @@ export class BotWeaponGeneratorHelper
|
||||
const slotGridMap = this.inventoryHelper.getContainerMap(
|
||||
slotGrid._props.cellsH,
|
||||
slotGrid._props.cellsV,
|
||||
containerItems,
|
||||
existingContainerItems,
|
||||
container._id,
|
||||
);
|
||||
|
||||
// Try to fit item into grid
|
||||
const findSlotResult = this.containerHelper.findSlotForItem(slotGridMap, itemSize[0], itemSize[1]);
|
||||
|
||||
@ -257,11 +279,18 @@ export class BotWeaponGeneratorHelper
|
||||
return ItemAddedResult.SUCCESS;
|
||||
}
|
||||
|
||||
// If we've checked all grids in container and reached this point, there's no space for item
|
||||
if (slotGridCount >= currentGridCount)
|
||||
{
|
||||
return ItemAddedResult.NO_SPACE;
|
||||
}
|
||||
currentGridCount++;
|
||||
|
||||
// Start loop again in next grid of container
|
||||
}
|
||||
}
|
||||
|
||||
return ItemAddedResult.NO_SPACE;
|
||||
return ItemAddedResult.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -219,8 +219,13 @@ export class DialogueHelper
|
||||
}
|
||||
|
||||
// Check reward count when item being moved isn't in reward list
|
||||
// if count is 0, it means after this move the reward array will be empty and all rewards collected
|
||||
const rewardItemCount = message.items.data.filter((x) => x._id !== itemId);
|
||||
// If count is 0, it means after this move occurs the reward array will be empty and all rewards collected
|
||||
if (!message.items.data)
|
||||
{
|
||||
message.items.data = [];
|
||||
}
|
||||
|
||||
const rewardItemCount = message.items.data?.filter((item) => item._id !== itemId);
|
||||
if (rewardItemCount.length === 0)
|
||||
{
|
||||
message.rewardCollected = true;
|
||||
|
@ -240,8 +240,11 @@ export class InRaidHelper
|
||||
public updateScavProfileDataPostRaid(scavData: IPmcData, saveProgressRequest: ISaveProgressRequestData, sessionId: string): void
|
||||
{
|
||||
// Only copy active quests into scav profile // Progress will later to copied over to PMC profile
|
||||
const existingActiveQuestIds = scavData.Quests.filter(x => x.status !== QuestStatus.AvailableForStart).map(x => x.qid);
|
||||
scavData.Quests = saveProgressRequest.profile.Quests.filter(x => existingActiveQuestIds.includes(x.qid));
|
||||
const existingActiveQuestIds = scavData.Quests?.filter(x => x.status !== QuestStatus.AvailableForStart).map(x => x.qid);
|
||||
if (existingActiveQuestIds)
|
||||
{
|
||||
scavData.Quests = saveProgressRequest.profile.Quests.filter(x => existingActiveQuestIds.includes(x.qid));
|
||||
}
|
||||
|
||||
this.profileFixerService.checkForAndFixScavProfileIssues(scavData);
|
||||
}
|
||||
|
@ -1027,7 +1027,7 @@ class ItemHelper
|
||||
minSizePercent = 0.25,
|
||||
): void
|
||||
{
|
||||
// Get cartrdge properties and max allowed stack size
|
||||
// Get cartridge properties and max allowed stack size
|
||||
const cartridgeDetails = this.getItem(cartridgeTpl);
|
||||
const cartridgeMaxStackSize = cartridgeDetails[1]._props.StackMaxSize;
|
||||
|
||||
@ -1085,7 +1085,7 @@ class ItemHelper
|
||||
* Chose a randomly weighted cartridge that fits
|
||||
* @param caliber Desired caliber
|
||||
* @param staticAmmoDist Cartridges and thier weights
|
||||
* @returns Tpl of cartrdige
|
||||
* @returns Tpl of cartridge
|
||||
*/
|
||||
protected drawAmmoTpl(caliber: string, staticAmmoDist: Record<string, IStaticAmmoDetails[]>): string
|
||||
{
|
||||
|
@ -345,13 +345,14 @@ export class QuestHelper
|
||||
acceptedQuest: IAcceptQuestRequestData,
|
||||
): IQuestStatus
|
||||
{
|
||||
const currentTimestamp = this.timeUtil.getTimestamp();
|
||||
const existingQuest = pmcData.Quests.find((q) => q.qid === acceptedQuest.qid);
|
||||
if (existingQuest)
|
||||
{
|
||||
// Quest exists, update its status
|
||||
existingQuest.startTime = this.timeUtil.getTimestamp();
|
||||
existingQuest.startTime = currentTimestamp;
|
||||
existingQuest.status = newState;
|
||||
existingQuest.statusTimers[newState] = this.timeUtil.getTimestamp();
|
||||
existingQuest.statusTimers[newState] = currentTimestamp;
|
||||
existingQuest.completedConditions = [];
|
||||
|
||||
if (existingQuest.availableAfter)
|
||||
@ -365,7 +366,7 @@ export class QuestHelper
|
||||
// Quest doesn't exists, add it
|
||||
const newQuest: IQuestStatus = {
|
||||
qid: acceptedQuest.qid,
|
||||
startTime: this.timeUtil.getTimestamp(),
|
||||
startTime: currentTimestamp,
|
||||
status: newState,
|
||||
statusTimers: {},
|
||||
};
|
||||
@ -378,11 +379,11 @@ export class QuestHelper
|
||||
// Quest should be put into 'pending' state
|
||||
newQuest.startTime = 0;
|
||||
newQuest.status = QuestStatus.AvailableAfter; // 9
|
||||
newQuest.availableAfter = this.timeUtil.getTimestamp() + waitTime._props.availableAfter;
|
||||
newQuest.availableAfter = currentTimestamp + waitTime._props.availableAfter;
|
||||
}
|
||||
else
|
||||
{
|
||||
newQuest.statusTimers[newState.toString()] = this.timeUtil.getTimestamp();
|
||||
newQuest.statusTimers[newState.toString()] = currentTimestamp;
|
||||
newQuest.completedConditions = [];
|
||||
}
|
||||
|
||||
@ -733,6 +734,43 @@ export class QuestHelper
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a quests values back to its chosen state
|
||||
* @param pmcData Profile to update
|
||||
* @param newQuestState New state the quest should be in
|
||||
* @param questId Id of the quest to alter the status of
|
||||
*/
|
||||
public resetQuestState(pmcData: IPmcData, newQuestState: QuestStatus, questId: string): void
|
||||
{
|
||||
const questToUpdate = pmcData.Quests.find((quest) => quest.qid === questId);
|
||||
if (questToUpdate)
|
||||
{
|
||||
const currentTimestamp = this.timeUtil.getTimestamp();
|
||||
|
||||
questToUpdate.status = newQuestState;
|
||||
|
||||
// Only set start time when quest is being started
|
||||
if (newQuestState === QuestStatus.Started)
|
||||
{
|
||||
questToUpdate.startTime = currentTimestamp;
|
||||
}
|
||||
|
||||
questToUpdate.statusTimers[newQuestState] = currentTimestamp;
|
||||
|
||||
// Delete all status timers after applying new status
|
||||
for (const statusKey in questToUpdate.statusTimers)
|
||||
{
|
||||
if (Number.parseInt(statusKey) > newQuestState)
|
||||
{
|
||||
delete questToUpdate.statusTimers[statusKey];
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all completed conditions
|
||||
questToUpdate.completedConditions = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Give player quest rewards - Skills/exp/trader standing/items/assort unlocks - Returns reward items player earned
|
||||
* @param profileData Player profile (scav or pmc)
|
||||
|
5
project/src/models/eft/game/IGetRaidTimeRequest.ts
Normal file
5
project/src/models/eft/game/IGetRaidTimeRequest.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface IGetRaidTimeRequest
|
||||
{
|
||||
Side: string,
|
||||
Location: string
|
||||
}
|
15
project/src/models/eft/game/IGetRaidTimeResponse.ts
Normal file
15
project/src/models/eft/game/IGetRaidTimeResponse.ts
Normal file
@ -0,0 +1,15 @@
|
||||
export interface IGetRaidTimeResponse
|
||||
{
|
||||
RaidTimeMinutes: number
|
||||
NewSurviveTimeSeconds: number
|
||||
OriginalSurvivalTimeSeconds: number
|
||||
ExitChanges: ExtractChange[]
|
||||
}
|
||||
|
||||
export interface ExtractChange
|
||||
{
|
||||
Name: string
|
||||
MinTime?: number
|
||||
MaxTime?: number
|
||||
Chance?: number
|
||||
}
|
@ -55,6 +55,7 @@ export enum BaseClasses
|
||||
GRENADE_LAUNCHER = "5447bedf4bdc2d87278b4568",
|
||||
SPECIAL_WEAPON = "5447bee84bdc2dc3278b4569",
|
||||
SPEC_ITEM = "5447e0e74bdc2d3c308b4567",
|
||||
SPRING_DRIVEN_CYLINDER = "627a137bf21bc425b06ab944",
|
||||
KNIFE = "5447e1d04bdc2dff2f8b4567",
|
||||
AMMO = "5485a8684bdc2da71d8b4567",
|
||||
AMMO_BOX = "543be5cb4bdc2deb348b4568",
|
||||
|
@ -1,5 +1,6 @@
|
||||
export enum ItemAddedResult
|
||||
{
|
||||
export enum ItemAddedResult {
|
||||
UNKNOWN = -1,
|
||||
SUCCESS = 1,
|
||||
NO_SPACE = 2,
|
||||
NO_CONTAINERS = 3
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ export interface IBotConfig extends IBaseConfig
|
||||
showTypeInNickname: boolean;
|
||||
/** What ai brain should a normal scav use per map */
|
||||
assaultBrainType: Record<string, Record<string, number>>;
|
||||
/** What ai brain should a player scav use per map */
|
||||
playerScavBrainType: Record<string, Record<string, number>>;
|
||||
/** Max number of bots that can be spawned in a raid at any one time */
|
||||
maxBotCap: Record<string, number>;
|
||||
/** Chance scav has fake pscav name e.g. Scav name (player name) */
|
||||
|
@ -23,6 +23,8 @@ export interface IGameFixes
|
||||
fixShotgunDispersion: boolean;
|
||||
/** Remove items added by mods when the mod no longer exists - can fix dead profiles stuck at game load*/
|
||||
removeModItemsFromProfile: boolean;
|
||||
/** Fix issues that cause the game to not start due to inventory item issues */
|
||||
fixProfileBreakingInventoryItemIssues: boolean;
|
||||
}
|
||||
|
||||
export interface IServerFeatures
|
||||
|
@ -38,6 +38,21 @@ export interface ILocationConfig extends IBaseConfig
|
||||
allowDuplicateItemsInStaticContainers: boolean;
|
||||
/** Key: map, value: loose loot ids to ignore */
|
||||
looseLootBlacklist: Record<string, string[]>;
|
||||
/** Key: map, value: settings to control how long scav raids are*/
|
||||
scavRaidTimeSettings: Record<string, IScavRaidTimeLocationSettings>;
|
||||
}
|
||||
|
||||
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
|
||||
|
9
project/src/models/spt/location/IRaidChanges.ts
Normal file
9
project/src/models/spt/location/IRaidChanges.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export interface IRaidChanges
|
||||
{
|
||||
/** What percentage of dynamic loot should the map contain */
|
||||
dynamicLootPercent: number
|
||||
/** What percentage of static loot should the map contain */
|
||||
staticLootPercent: number
|
||||
/** How many seconds into the raid is the player simulated to spawn in at */
|
||||
simulatedRaidStartSeconds: number
|
||||
}
|
@ -64,6 +64,14 @@ export class GameStaticRouter extends StaticRouter
|
||||
return this.gameCallbacks.reportNickname(url, info, sessionID);
|
||||
},
|
||||
),
|
||||
new RouteAction(
|
||||
"/singleplayer/settings/getRaidTime",
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
(url: string, info: any, sessionID: string, output: string): any =>
|
||||
{
|
||||
return this.gameCallbacks.getRaidTime(url, info, sessionID);
|
||||
},
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -237,9 +237,21 @@ export class ProfileFixerService
|
||||
return;
|
||||
}
|
||||
|
||||
const stashItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandAreaDb._id);
|
||||
let stashItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandAreaDb._id);
|
||||
if (!stashItem)
|
||||
{
|
||||
// Stand inventory stash item doesnt exist, add it
|
||||
pmcProfile.Inventory.items.push(
|
||||
{
|
||||
_id: hideoutStandAreaDb._id,
|
||||
_tpl: stageCurrentAt.container
|
||||
}
|
||||
)
|
||||
stashItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandAreaDb._id)
|
||||
}
|
||||
|
||||
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
||||
if (hideoutStandStashId && stashItem?._tpl !== stageCurrentAt.container)
|
||||
if (hideoutStandStashId && stashItem._tpl !== stageCurrentAt.container)
|
||||
{
|
||||
this.logger.debug(
|
||||
`primary Stash tpl was: ${stashItem._tpl}, but should be ${stageCurrentAt.container}, updating`,
|
||||
@ -248,7 +260,19 @@ export class ProfileFixerService
|
||||
stashItem._tpl = stageCurrentAt.container;
|
||||
}
|
||||
|
||||
const stashSecondaryItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandSecondaryAreaDb._id);
|
||||
let stashSecondaryItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandSecondaryAreaDb._id);
|
||||
if (!stashSecondaryItem)
|
||||
{
|
||||
// Stand inventory stash item doesnt exist, add it
|
||||
pmcProfile.Inventory.items.push(
|
||||
{
|
||||
_id: hideoutStandSecondaryAreaDb._id,
|
||||
_tpl: stageCurrentAt.container
|
||||
}
|
||||
)
|
||||
stashSecondaryItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandSecondaryAreaDb._id)
|
||||
}
|
||||
|
||||
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
||||
if (hideoutSecondaryStashId && stashSecondaryItem?._tpl !== stageCurrentAt.container)
|
||||
{
|
||||
@ -1072,7 +1096,8 @@ export class ProfileFixerService
|
||||
public fixIncorrectAidValue(fullProfile: IAkiProfile): void
|
||||
{
|
||||
// Not a number, regenerate
|
||||
if (Number.isNaN(fullProfile.characters.pmc.aid))
|
||||
// biome-ignore lint/suspicious/noGlobalIsNan: <value can be a valid string, Number.IsNaN() would ignore it>
|
||||
if (isNaN(fullProfile.characters.pmc.aid) || !fullProfile.info.aid)
|
||||
{
|
||||
fullProfile.characters.pmc.sessionId = <string><unknown>fullProfile.characters.pmc.aid;
|
||||
fullProfile.characters.pmc.aid = this.hashUtil.generateAccountId();
|
||||
@ -1082,7 +1107,7 @@ export class ProfileFixerService
|
||||
|
||||
fullProfile.info.aid = fullProfile.characters.pmc.aid;
|
||||
|
||||
this.logger.debug(
|
||||
this.logger.info(
|
||||
`Migrated AccountId from: ${fullProfile.characters.pmc.sessionId} to: ${fullProfile.characters.pmc.aid}`,
|
||||
);
|
||||
}
|
||||
|
240
project/src/services/RaidTimeAdjustmentService.ts
Normal file
240
project/src/services/RaidTimeAdjustmentService.ts
Normal file
@ -0,0 +1,240 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
|
||||
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
||||
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
||||
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
|
||||
import { ILocationBase } from "@spt-aki/models/eft/common/ILocationBase";
|
||||
import { IGetRaidTimeRequest } from "@spt-aki/models/eft/game/IGetRaidTimeRequest";
|
||||
import { ExtractChange, IGetRaidTimeResponse } from "@spt-aki/models/eft/game/IGetRaidTimeResponse";
|
||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||
import { ILocationConfig, IScavRaidTimeLocationSettings, LootMultiplier } from "@spt-aki/models/spt/config/ILocationConfig";
|
||||
import { IRaidChanges } from "@spt-aki/models/spt/location/IRaidChanges";
|
||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
||||
|
||||
@injectable()
|
||||
export class RaidTimeAdjustmentService
|
||||
{
|
||||
protected locationConfig: ILocationConfig;
|
||||
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
|
||||
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
)
|
||||
{
|
||||
this.locationConfig = this.configServer.getConfig(ConfigTypes.LOCATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make alterations to the base map data passed in
|
||||
* Loot multipliers/waves/wave start times
|
||||
* @param raidAdjustments Changes to process on map
|
||||
* @param mapBase Map to adjust
|
||||
*/
|
||||
public makeAdjustmentsToMap(raidAdjustments: IRaidChanges, mapBase: ILocationBase): void
|
||||
{
|
||||
this.logger.debug(`Adjusting dynamic loot multipliers to ${raidAdjustments.dynamicLootPercent}% and static loot multipliers to ${raidAdjustments.staticLootPercent}% of original`);
|
||||
|
||||
// Change loot multipler values before they're used below
|
||||
this.adjustLootMultipliers(this.locationConfig.looseLootMultiplier, raidAdjustments.dynamicLootPercent);
|
||||
this.adjustLootMultipliers(this.locationConfig.staticLootMultiplier, raidAdjustments.staticLootPercent);
|
||||
|
||||
const mapSettings = this.getMapSettings(mapBase.Id);
|
||||
if (mapSettings.adjustWaves)
|
||||
{
|
||||
// Make alterations to bot spawn waves now player is simulated spawning later
|
||||
this.adjustWaves(mapBase, raidAdjustments)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the loot multiplier values passed in to be a % of their original value
|
||||
* @param mapLootMultiplers Multiplers to adjust
|
||||
* @param loosePercent Percent to change values to
|
||||
*/
|
||||
protected adjustLootMultipliers(mapLootMultiplers: LootMultiplier, loosePercent: number): void
|
||||
{
|
||||
for (const key in mapLootMultiplers)
|
||||
{
|
||||
mapLootMultiplers[key] = this.randomUtil.getPercentOfValue(mapLootMultiplers[key], loosePercent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust bot waves to act as if player spawned later
|
||||
* @param mapBase map to adjust
|
||||
* @param raidAdjustments Map adjustments
|
||||
*/
|
||||
protected adjustWaves(mapBase: ILocationBase, raidAdjustments: IRaidChanges): void
|
||||
{
|
||||
// Remove waves that spawned before the player joined
|
||||
const originalWaveCount = mapBase.waves.length;
|
||||
mapBase.waves = mapBase.waves.filter(x => x.time_max > raidAdjustments.simulatedRaidStartSeconds);
|
||||
|
||||
// Adjust wave min/max times to match new simulated start
|
||||
for (const wave of mapBase.waves)
|
||||
{
|
||||
// Dont let time fall below 0
|
||||
wave.time_min -= Math.max(raidAdjustments.simulatedRaidStartSeconds, 0);
|
||||
wave.time_max -= Math.max(raidAdjustments.simulatedRaidStartSeconds, 0);
|
||||
}
|
||||
|
||||
this.logger.debug(`Removed ${originalWaveCount - mapBase.waves.length} wave from map due to simulated raid start time of ${raidAdjustments.simulatedRaidStartSeconds / 60} minutes`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a randomised adjustment to the raid based on map data in location.json
|
||||
* @param sessionId Session id
|
||||
* @param request Raid adjustment request
|
||||
* @returns Response to send to client
|
||||
*/
|
||||
public getRaidAdjustments(sessionId: string, request: IGetRaidTimeRequest): IGetRaidTimeResponse
|
||||
{
|
||||
const db = this.databaseServer.getTables();
|
||||
|
||||
const mapBase: ILocationBase = db.locations[request.Location.toLowerCase()].base;
|
||||
const baseEscapeTimeMinutes = mapBase.EscapeTimeLimit;
|
||||
|
||||
// Prep result object to return
|
||||
const result: IGetRaidTimeResponse = {
|
||||
RaidTimeMinutes: baseEscapeTimeMinutes,
|
||||
ExitChanges: [],
|
||||
NewSurviveTimeSeconds: null,
|
||||
OriginalSurvivalTimeSeconds: db.globals.config.exp.match_end.survived_seconds_requirement
|
||||
}
|
||||
|
||||
// Pmc raid, send default
|
||||
if (request.Side.toLowerCase() === "pmc")
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// We're scav adjust values
|
||||
const mapSettings = this.getMapSettings(request.Location);
|
||||
|
||||
// Chance of reducing raid time for scav, not guaranteed
|
||||
if (!this.randomUtil.getChance100(mapSettings.reducedChancePercent))
|
||||
{
|
||||
// Send default
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get the weighted percent to reduce the raid time by
|
||||
const chosenRaidReductionPercent = Number.parseInt(this.weightedRandomHelper.getWeightedValue<string>(
|
||||
mapSettings.reductionPercentWeights,
|
||||
));
|
||||
|
||||
// How many minutes raid will last
|
||||
const newRaidTimeMinutes = Math.floor(this.randomUtil.reduceValueByPercent(baseEscapeTimeMinutes, chosenRaidReductionPercent));
|
||||
|
||||
// Time player spawns into the raid if it was online
|
||||
const simulatedRaidStartTimeMinutes = baseEscapeTimeMinutes - newRaidTimeMinutes;
|
||||
|
||||
if (mapSettings.reduceLootByPercent)
|
||||
{
|
||||
// Store time reduction percent in app context so loot gen can pick it up later
|
||||
this.applicationContext.addValue(ContextVariableType.RAID_ADJUSTMENTS,
|
||||
{
|
||||
dynamicLootPercent: Math.max(chosenRaidReductionPercent, mapSettings.minDynamicLootPercent),
|
||||
staticLootPercent: Math.max(chosenRaidReductionPercent, mapSettings.minStaticLootPercent),
|
||||
simulatedRaidStartSeconds: simulatedRaidStartTimeMinutes * 60
|
||||
});
|
||||
}
|
||||
|
||||
// Update result object with new time
|
||||
result.RaidTimeMinutes = newRaidTimeMinutes;
|
||||
|
||||
this.logger.debug(`Reduced: ${request.Location} raid time by: ${chosenRaidReductionPercent}% to ${newRaidTimeMinutes} minutes`)
|
||||
|
||||
// Calculate how long player needs to be in raid to get a `survived` extract status
|
||||
result.NewSurviveTimeSeconds = Math.max(result.OriginalSurvivalTimeSeconds - ((baseEscapeTimeMinutes - newRaidTimeMinutes) * 60), 0);
|
||||
|
||||
const exitAdjustments = this.getExitAdjustments(mapBase, newRaidTimeMinutes);
|
||||
if (exitAdjustments)
|
||||
{
|
||||
result.ExitChanges.push(...exitAdjustments);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raid start time settings for specific map
|
||||
* @param location Map Location e.g. bigmap
|
||||
* @returns IScavRaidTimeLocationSettings
|
||||
*/
|
||||
protected getMapSettings(location: string): IScavRaidTimeLocationSettings
|
||||
{
|
||||
const mapSettings = this.locationConfig.scavRaidTimeSettings[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 mapSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust exit times to handle scavs entering raids part-way through
|
||||
* @param mapBase Map base file player is on
|
||||
* @param newRaidTimeMinutes How long raid is in minutes
|
||||
* @returns List of exit changes to send to client
|
||||
*/
|
||||
protected getExitAdjustments(mapBase: ILocationBase, newRaidTimeMinutes: number): ExtractChange[]
|
||||
{
|
||||
const result = [];
|
||||
// Adjust train exits only
|
||||
for (const exit of mapBase.exits)
|
||||
{
|
||||
if (exit.PassageRequirement !== "Train")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Prepare train adjustment object
|
||||
const exitChange: ExtractChange = {
|
||||
Name: exit.Name,
|
||||
MinTime: null,
|
||||
MaxTime: null,
|
||||
Chance: null
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
exitChange.Chance = 0;
|
||||
|
||||
this.logger.debug(`Train Exit: ${exit.Name} disabled as new raid time ${newRaidTimeMinutes} minutes is below ${latestPossibleDepartureMinutes} 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;
|
||||
|
||||
this.logger.debug(`Train appears between: ${exitChange.MinTime} and ${exitChange.MaxTime} seconds raid time`);
|
||||
|
||||
result.push(exitChange);
|
||||
}
|
||||
|
||||
return result.length > 0
|
||||
? result
|
||||
: null ;
|
||||
}
|
||||
}
|
@ -34,6 +34,13 @@ export class HttpResponseUtil
|
||||
return this.clearString(this.jsonUtil.serialize(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Game client needs server responses in a particular format
|
||||
* @param data
|
||||
* @param err
|
||||
* @param errmsg
|
||||
* @returns
|
||||
*/
|
||||
public getBody<T>(data: T, err = 0, errmsg = null): IGetBodyResponseData<T>
|
||||
{
|
||||
return this.clearString(this.getUnclearedBody(data, err, errmsg));
|
||||
|
@ -231,6 +231,18 @@ export class RandomUtil
|
||||
return Number.parseFloat(((percent * number) / 100).toFixed(toFixed));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce a value by a percentage
|
||||
* @param number Value to reduce
|
||||
* @param percentage Percentage to reduce value by
|
||||
* @returns Reduced value
|
||||
*/
|
||||
public reduceValueByPercent(number: number, percentage: number): number
|
||||
{
|
||||
const reductionAmount = number * (percentage / 100);
|
||||
return number - reductionAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if number passes a check out of 100
|
||||
* @param chancePercent value check needs to be above
|
||||
|
Loading…
Reference in New Issue
Block a user