@@ -2,16 +2,20 @@ import { HideoutHelper } from "@spt/helpers/HideoutHelper";
2
2
import { InventoryHelper } from "@spt/helpers/InventoryHelper" ;
3
3
import { ItemHelper } from "@spt/helpers/ItemHelper" ;
4
4
import { ProfileHelper } from "@spt/helpers/ProfileHelper" ;
5
+ import { QuestHelper } from "@spt/helpers/QuestHelper" ;
5
6
import { TraderHelper } from "@spt/helpers/TraderHelper" ;
6
7
import { IPmcData } from "@spt/models/eft/common/IPmcData" ;
7
8
import { IBonus , IHideoutSlot } from "@spt/models/eft/common/tables/IBotBase" ;
9
+ import { IQuest , IQuestReward } from "@spt/models/eft/common/tables/IQuest" ;
8
10
import { IPmcDataRepeatableQuest , IRepeatableQuest } from "@spt/models/eft/common/tables/IRepeatableQuests" ;
9
11
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem" ;
10
12
import { IStageBonus } from "@spt/models/eft/hideout/IHideoutArea" ;
11
13
import { IEquipmentBuild , IMagazineBuild , ISptProfile , IWeaponBuild } from "@spt/models/eft/profile/ISptProfile" ;
12
14
import { BonusType } from "@spt/models/enums/BonusType" ;
13
15
import { ConfigTypes } from "@spt/models/enums/ConfigTypes" ;
14
16
import { HideoutAreas } from "@spt/models/enums/HideoutAreas" ;
17
+ import { QuestRewardType } from "@spt/models/enums/QuestRewardType" ;
18
+ import { QuestStatus } from "@spt/models/enums/QuestStatus" ;
15
19
import { ICoreConfig } from "@spt/models/spt/config/ICoreConfig" ;
16
20
import { IRagfairConfig } from "@spt/models/spt/config/IRagfairConfig" ;
17
21
import { ILogger } from "@spt/models/spt/utils/ILogger" ;
@@ -45,6 +49,7 @@ export class ProfileFixerService {
45
49
@inject ( "HashUtil" ) protected hashUtil : HashUtil ,
46
50
@inject ( "ConfigServer" ) protected configServer : ConfigServer ,
47
51
@inject ( "PrimaryCloner" ) protected cloner : ICloner ,
52
+ @inject ( "QuestHelper" ) protected questHelper : QuestHelper ,
48
53
) {
49
54
this . coreConfig = this . configServer . getConfig ( ConfigTypes . CORE ) ;
50
55
this . ragfairConfig = this . configServer . getConfig ( ConfigTypes . RAGFAIR ) ;
@@ -58,6 +63,7 @@ export class ProfileFixerService {
58
63
this . removeDanglingConditionCounters ( pmcProfile ) ;
59
64
this . removeDanglingTaskConditionCounters ( pmcProfile ) ;
60
65
this . removeOrphanedQuests ( pmcProfile ) ;
66
+ this . verifyQuestProductionUnlocks ( pmcProfile ) ;
61
67
62
68
if ( pmcProfile . Hideout ) {
63
69
this . addHideoutEliteSlots ( pmcProfile ) ;
@@ -264,6 +270,72 @@ export class ProfileFixerService {
264
270
}
265
271
}
266
272
273
+ /**
274
+ * Verify that all quest production unlocks have been applied to the PMC Profile
275
+ * @param pmcProfile The profile to validate quest productions for
276
+ */
277
+ protected verifyQuestProductionUnlocks ( pmcProfile : IPmcData ) : void {
278
+ const start = performance . now ( ) ;
279
+
280
+ const quests = this . databaseService . getQuests ( ) ;
281
+ const profileQuests = pmcProfile . Quests ;
282
+
283
+ for ( const profileQuest of profileQuests )
284
+ {
285
+ const quest = quests [ profileQuest . qid ] ;
286
+
287
+ // For started or successful quests, check for unlocks in the `Started` rewards
288
+ if ( profileQuest . status == QuestStatus . Started || profileQuest . status == QuestStatus . Success )
289
+ {
290
+ const productionRewards = quest . rewards . Started ?. filter ( reward => reward . type == QuestRewardType . PRODUCTIONS_SCHEME ) ;
291
+ productionRewards ?. forEach ( reward => this . verifyQuestProductionUnlock ( pmcProfile , reward , quest ) ) ;
292
+ }
293
+
294
+ // For successful quests, check for unlocks in the `Success` rewards
295
+ if ( profileQuest . status == QuestStatus . Success )
296
+ {
297
+ const productionRewards = quest . rewards . Success ?. filter ( reward => reward . type == QuestRewardType . PRODUCTIONS_SCHEME ) ;
298
+ productionRewards ?. forEach ( reward => this . verifyQuestProductionUnlock ( pmcProfile , reward , quest ) ) ;
299
+ }
300
+ }
301
+
302
+ const validateTime = performance . now ( ) - start
303
+ this . logger . debug ( `Quest Production Unlock validation took: ${ validateTime . toFixed ( 2 ) } ms` ) ;
304
+ }
305
+
306
+ /**
307
+ * Validate that the given profile has the given quest reward production scheme unlocked, and add it if not
308
+ * @param pmcProfile Profile to check
309
+ * @param productionUnlockReward The quest reward to validate
310
+ * @param questDetails The quest the reward belongs to
311
+ * @returns
312
+ */
313
+ protected verifyQuestProductionUnlock (
314
+ pmcProfile : IPmcData ,
315
+ productionUnlockReward : IQuestReward ,
316
+ questDetails : IQuest
317
+ ) : void {
318
+ const matchingProductions = this . questHelper . getRewardProductionMatch ( productionUnlockReward , questDetails ) ;
319
+ if ( matchingProductions . length !== 1 ) {
320
+ this . logger . error (
321
+ this . localisationService . getText ( "quest-unable_to_find_matching_hideout_production" , {
322
+ questName : questDetails . QuestName ,
323
+ matchCount : matchingProductions . length ,
324
+ } ) ,
325
+ ) ;
326
+
327
+ return ;
328
+ }
329
+
330
+ // Add above match to pmc profile
331
+ const matchingProductionId = matchingProductions [ 0 ] . _id ;
332
+ if ( ! pmcProfile . UnlockedInfo . unlockedProductionRecipe . includes ( matchingProductionId ) )
333
+ {
334
+ pmcProfile . UnlockedInfo . unlockedProductionRecipe . push ( matchingProductionId ) ;
335
+ this . logger . debug ( `Added production ${ matchingProductionId } to unlocked production recipes for ${ questDetails . QuestName } ` ) ;
336
+ }
337
+ }
338
+
267
339
/**
268
340
* If the profile has elite Hideout Managment skill, add the additional slots from globals
269
341
* NOTE: This seems redundant, but we will leave it here just incase.
0 commit comments