From e793b0bc63cbba066a4fe94bccfcffa1d7d0d95c Mon Sep 17 00:00:00 2001 From: Dev Date: Sun, 16 Jun 2024 10:58:35 +0100 Subject: [PATCH] Fixed nullref error on repeatable refresh click event Fixed all profiles having access to free repeatable refreshes Fixed newly created profiles generating with 0 free refreshes regardless of game version --- .../controllers/RepeatableQuestController.ts | 57 +++++++++++++++---- project/src/helpers/ProfileHelper.ts | 6 ++ 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/project/src/controllers/RepeatableQuestController.ts b/project/src/controllers/RepeatableQuestController.ts index 69a2f723..4ed69e5b 100644 --- a/project/src/controllers/RepeatableQuestController.ts +++ b/project/src/controllers/RepeatableQuestController.ts @@ -10,6 +10,7 @@ import { IRepeatableQuest, } from "@spt/models/eft/common/tables/IRepeatableQuests"; import { IItemEventRouterResponse } from "@spt/models/eft/itemEvent/IItemEventRouterResponse"; +import { ISptProfile } from "@spt/models/eft/profile/ISptProfile"; import { IRepeatableQuestChangeRequest } from "@spt/models/eft/quests/IRepeatableQuestChangeRequest"; import { ConfigTypes } from "@spt/models/enums/ConfigTypes"; import { ELocationName } from "@spt/models/enums/ELocationName"; @@ -317,9 +318,11 @@ export class RepeatableQuestController ): IPmcDataRepeatableQuest { // Get from profile, add if missing - let repeatableQuestDetails = pmcData.RepeatableQuests.find((x) => x.name === repeatableConfig.name); - if (!repeatableQuestDetails) + let repeatableQuestDetails = pmcData.RepeatableQuests + .find((repeatable) => repeatable.name === repeatableConfig.name); + if (!repeatableQuestDetails) // Not in profile, generate { + const hasAccess = this.profileHelper.hasAccessToRepeatableFreeRefreshSystem(pmcData); repeatableQuestDetails = { id: repeatableConfig.id, name: repeatableConfig.name, @@ -327,8 +330,8 @@ export class RepeatableQuestController inactiveQuests: [], endTime: 0, changeRequirement: {}, - freeChanges: 0, - freeChangesAvailable: 0, + freeChanges: hasAccess ? repeatableConfig.freeChanges : 0, + freeChangesAvailable: hasAccess ? repeatableConfig.freeChangesAvailable : 0, }; // Add base object that holds repeatable data to profile @@ -589,13 +592,7 @@ export class RepeatableQuestController fullProfile.characters.scav?.Quests ?? [], ); - // Increment the count in profile now we've replaced a daily - const repeatableRefreshCounts = fullProfile.spt.freeRepeatableRefreshUsedCount; - repeatableRefreshCounts[repeatableTypeLower]++; - - // Set client return objects avail count to total minus how many used so far - repeatablesInProfile.freeChangesAvailable - = repeatablesInProfile.freeChanges - repeatableRefreshCounts[repeatableTypeLower]; + this.handleFreeRefreshUses(fullProfile, repeatablesInProfile, repeatableTypeLower); } // Not sure why we clone but we do @@ -676,4 +673,42 @@ export class RepeatableQuestController return newRepeatableQuest; } + + /** + * Some accounts have access to repeatable quest refreshes for free + * Track the usage of them inside players profile + * @param fullProfile Profile of player + * @param repeatableSubType Can be daily/weekly/scav repeatables + * @param repeatableTypeName Subtype of repeatables: daily / weekly / scav + */ + protected handleFreeRefreshUses( + fullProfile: ISptProfile, + repeatableSubType: IPmcDataRepeatableQuest, + repeatableTypeName: string): void + { + // Only certain game versions have access + const hasAccessToFreeRefreshSystem + = this.profileHelper.hasAccessToRepeatableFreeRefreshSystem(fullProfile.characters.pmc); + // Initialize/retrieve free refresh count for the desired subtype: daily/weekly + fullProfile.spt.freeRepeatableRefreshUsedCount ||= {}; + const repeatableRefreshCounts = fullProfile.spt.freeRepeatableRefreshUsedCount; + repeatableRefreshCounts[repeatableTypeName] ||= 0; // Set to 0 if undefined + + if (!hasAccessToFreeRefreshSystem) + { + // Reset the available count if the player does not have free refreshes. + repeatableSubType.freeChangesAvailable = 0; + + return; + } + + if (repeatableSubType.freeChangesAvailable > 0) + { + // Increment the used count if the player has free refreshes and available changes. + repeatableRefreshCounts[repeatableTypeName]++; + + // Update the available count. + repeatableSubType.freeChangesAvailable--; + } + } } diff --git a/project/src/helpers/ProfileHelper.ts b/project/src/helpers/ProfileHelper.ts index 7d0f7e8b..16dd9dd6 100644 --- a/project/src/helpers/ProfileHelper.ts +++ b/project/src/helpers/ProfileHelper.ts @@ -570,4 +570,10 @@ export class ProfileHelper { pmcProfile.Achievements[achievementId] = this.timeUtil.getTimestamp(); } + + public hasAccessToRepeatableFreeRefreshSystem(pmcProfile: IPmcData): boolean + { + return ["edge_of_darkness", "unheard_edition"] + .includes(pmcProfile.Info?.GameVersion); + } }