diff --git a/project/src/controllers/InraidController.ts b/project/src/controllers/InraidController.ts index b2d70bdc..c7db8dc7 100644 --- a/project/src/controllers/InraidController.ts +++ b/project/src/controllers/InraidController.ts @@ -262,6 +262,13 @@ export class InraidController scavData = this.inRaidHelper.updateProfileBaseStats(scavData, postRaidRequest, sessionID); + // Completing scav quests create ConditionCounters, these values need to be transported to the PMC profile + if (this.profileHasConditionCounters(scavData)) + { + // Scav quest progress needs to be moved to pmc so player can see it in menu / hand them in + this.migrateScavQuestProgressToPmcProfile(scavData, pmcData); + } + // Check for exit status this.markOrRemoveFoundInRaidItems(postRaidRequest); @@ -271,6 +278,66 @@ export class InraidController this.handlePostRaidPlayerScavProcess(scavData, sessionID, postRaidRequest, pmcData, isDead); } + /** + * Does provided profile contain any condition counters + * @param profile Profile to check for condition counters + * @returns + */ + protected profileHasConditionCounters(profile: IPmcData): boolean + { + if (!profile.ConditionCounters.Counters) + { + return false; + } + + return profile.ConditionCounters.Counters.length > 0; + } + + protected migrateScavQuestProgressToPmcProfile(scavProfile: IPmcData, pmcProfile: IPmcData): void + { + for (const quest of scavProfile.Quests) + { + const pmcQuest = pmcProfile.Quests.find(x => x.qid === quest.qid); + if (!pmcQuest) + { + this.logger.warning(`No PMC quest found for ID: ${quest.qid}`); + continue; + } + + // Post-raid status is enum word e.g. `Started` but pmc quest status is number e.g. 2 + // Status values mismatch or statusTimers counts mismatch + if (quest.status !== QuestStatus[pmcQuest.status] || quest.statusTimers.length !== pmcQuest.statusTimers.length) + { + this.logger.warning(`Quest: ${quest.qid} found in PMC profile has different status/statustimer. Scav: ${quest.status} vs PMC: ${pmcQuest.status}`); + pmcQuest.status = QuestStatus[quest.status]; + pmcQuest.statusTimers = quest.statusTimers; + } + } + + // Loop over all scav counters and add into pmc profile + for (const scavCounter of scavProfile.ConditionCounters.Counters) + { + this.logger.warning(`Processing counter: ${scavCounter.id} value:${scavCounter.value} quest:${scavCounter.qid}`); + const counterInPmcProfile = pmcProfile.ConditionCounters.Counters.find(x => x.id === scavCounter.id); + if (!counterInPmcProfile) + { + // Doesn't exist yet, push it straight in + pmcProfile.ConditionCounters.Counters.push(scavCounter); + + continue; + } + + this.logger.warning(`Counter id: ${scavCounter.id} already exists in pmc profile! with value: ${counterInPmcProfile.value} for quest: ${counterInPmcProfile.qid}`); + this.logger.warning(`OVERWRITING with values: ${scavCounter.value} quest: ${scavCounter.qid}`); + + // Only adjust counter value if its changed + if (counterInPmcProfile.value !== scavCounter.value) + { + counterInPmcProfile.value = scavCounter.value; + } + } + } + /** * Is the player dead after a raid - dead is anything other than "survived" / "runner" * @param statusOnExit exit value from offraidData object diff --git a/project/src/controllers/QuestController.ts b/project/src/controllers/QuestController.ts index 90d580f6..f8d3461a 100644 --- a/project/src/controllers/QuestController.ts +++ b/project/src/controllers/QuestController.ts @@ -338,8 +338,8 @@ export class QuestController throw new Error(this.localisationService.getText("repeatable-unable_to_accept_quest_see_log")); } - // Scav quests need to be added to scav profile - if (repeatableQuestProfile.side === "Scav") + // Some scav quests need to be added to scav profile for them to show up in-raid + if (repeatableQuestProfile.side === "Scav" && ["PickUp", "Exploration", "Elimination"].includes(repeatableQuestProfile.type)) { const fullProfile = this.profileHelper.getFullProfile(sessionID); if (!fullProfile.characters.scav.Quests) @@ -460,6 +460,9 @@ export class QuestController { currentRepeatable.activeQuests = currentRepeatable.activeQuests.filter(x => x._id !== completedQuestId); currentRepeatable.inactiveQuests.push(repeatableQuest); + + // Need to remove redundant scav quest object as its no longer necessary, is tracked in pmc profile + this.removeQuestFromScavProfile(sessionID, repeatableQuest._id); } } @@ -476,6 +479,25 @@ export class QuestController return completeQuestResponse; } + /** + * Remove a quest entirely from a profile + * @param sessionId Player id + * @param questIdToRemove Qid of quest to remove + */ + protected removeQuestFromScavProfile(sessionId: string, questIdToRemove: string): void + { + const fullProfile = this.profileHelper.getFullProfile(sessionId); + const repeatableInScavProfile = fullProfile.characters.scav.Quests.find(x => x.qid === questIdToRemove); + if (!repeatableInScavProfile) + { + this.logger.warning(`Unable to remove quest: ${questIdToRemove} from profile as scav profile cannot be found`); + + return; + } + + fullProfile.characters.scav.Quests.splice(fullProfile.characters.scav.Quests.indexOf(repeatableInScavProfile), 1); + } + /** * Return quests that have different statuses * @param preQuestStatusus Quests before diff --git a/project/src/controllers/RepeatableQuestController.ts b/project/src/controllers/RepeatableQuestController.ts index 768dd7c9..b7f131a2 100644 --- a/project/src/controllers/RepeatableQuestController.ts +++ b/project/src/controllers/RepeatableQuestController.ts @@ -97,7 +97,8 @@ export class RepeatableQuestController const currentRepeatableType = this.getRepeatableQuestSubTypeFromProfile(repeatableConfig, pmcData); if (repeatableConfig.side === "Pmc" - && pmcData.Info.Level >= repeatableConfig.minPlayerLevel || repeatableConfig.side === "Scav" && scavQuestUnlocked) + && pmcData.Info.Level >= repeatableConfig.minPlayerLevel + || repeatableConfig.side === "Scav" && scavQuestUnlocked) { if (time > currentRepeatableType.endTime - 1) { diff --git a/project/src/helpers/InRaidHelper.ts b/project/src/helpers/InRaidHelper.ts index ce915873..ac3db33f 100644 --- a/project/src/helpers/InRaidHelper.ts +++ b/project/src/helpers/InRaidHelper.ts @@ -145,6 +145,7 @@ export class InRaidHelper for (const backendCounterKey in saveProgressRequest.profile.BackendCounters) { + // Skip counters with no id if (!saveProgressRequest.profile.BackendCounters[backendCounterKey].id) { continue; @@ -160,7 +161,7 @@ export class InRaidHelper if (matchingPreRaidCounter.value !== saveProgressRequest.profile.BackendCounters[backendCounterKey].value) { - this.logger.error(`Backendcounter: ${backendCounterKey} value is different post raid, old: ${matchingPreRaidCounter.value} new: saveProgressRequest.profile.BackendCounters[backendCounterKey].value`); + this.logger.error(`Backendcounter: ${backendCounterKey} value is different post raid, old: ${matchingPreRaidCounter.value} new: ${saveProgressRequest.profile.BackendCounters[backendCounterKey].value}`); } } @@ -174,7 +175,7 @@ export class InRaidHelper profileData.SurvivorClass = saveProgressRequest.profile.SurvivorClass; - // add experience points + // Add experience points profileData.Info.Experience += profileData.Stats.Eft.TotalSessionExperience; profileData.Stats.Eft.TotalSessionExperience = 0;