Attempt to resolve issue where failed quests that are restarted retain their previous completed statuses until client restart

New function to purge completed condtions + remove status timers beyond what a newly started quest would have + add updated quest status object to `questsStatus` property on profile changes response object
This commit is contained in:
Dev 2023-11-29 23:36:31 +00:00
parent bfee07d5fe
commit a941a22305
2 changed files with 45 additions and 8 deletions

View File

@ -289,7 +289,7 @@ export class QuestController
* @param pmcData Profile to update * @param pmcData Profile to update
* @param acceptedQuest Quest accepted * @param acceptedQuest Quest accepted
* @param sessionID Session id * @param sessionID Session id
* @returns client response * @returns Client response
*/ */
public acceptQuest( public acceptQuest(
pmcData: IPmcData, pmcData: IPmcData,
@ -299,29 +299,31 @@ export class QuestController
{ {
const acceptQuestResponse = this.eventOutputHolder.getOutput(sessionID); const acceptQuestResponse = this.eventOutputHolder.getOutput(sessionID);
const startedState = QuestStatus.Started;
const newQuest = this.questHelper.getQuestReadyForProfile(pmcData, startedState, acceptedQuest);
// Does quest exist in profile // Does quest exist in profile
if (pmcData.Quests.find((x) => x.qid === acceptedQuest.qid)) // Restarting a quest can mean quest exists in profile
const existingQuestStatus = pmcData.Quests.find((x) => x.qid === acceptedQuest.qid)
if (existingQuestStatus)
{ {
// Update existing // Update existing
this.questHelper.updateQuestState(pmcData, QuestStatus.Started, acceptedQuest.qid); this.questHelper.resetQuestState(pmcData, QuestStatus.Started, acceptedQuest.qid);
} }
else else
{ {
// Add new quest to server profile // Add new quest to server profile
const newQuest = this.questHelper.getQuestReadyForProfile(pmcData, QuestStatus.Started, acceptedQuest);
pmcData.Quests.push(newQuest); pmcData.Quests.push(newQuest);
} }
// Create a dialog message for starting the quest. // Create a dialog message for starting the quest.
// Note that for starting quests, the correct locale field is "description", not "startedMessageText". // Note that for starting quests, the correct locale field is "description", not "startedMessageText".
const questFromDb = this.questHelper.getQuestFromDb(acceptedQuest.qid, pmcData); const questFromDb = this.questHelper.getQuestFromDb(acceptedQuest.qid, pmcData);
// Get messageId of text to send to player as text message in game // Get messageId of text to send to player as text message in game
const messageId = this.questHelper.getMessageIdForQuestStart( const messageId = this.questHelper.getMessageIdForQuestStart(
questFromDb.startedMessageText, questFromDb.startedMessageText,
questFromDb.description, questFromDb.description,
); );
const startedQuestRewards = this.questHelper.applyQuestReward( const startedQuestRewards = this.questHelper.applyQuestReward(
pmcData, pmcData,
acceptedQuest.qid, acceptedQuest.qid,
@ -342,6 +344,13 @@ export class QuestController
acceptQuestResponse.profileChanges[sessionID].quests = this.questHelper acceptQuestResponse.profileChanges[sessionID].quests = this.questHelper
.getNewlyAccessibleQuestsWhenStartingQuest(acceptedQuest.qid, sessionID); .getNewlyAccessibleQuestsWhenStartingQuest(acceptedQuest.qid, sessionID);
// Quest already existed, probably a fail/restart
// Need to send client an empty list of completedConditions
if (existingQuestStatus)
{
acceptQuestResponse.profileChanges[sessionID].questsStatus = [ existingQuestStatus ];
}
return acceptQuestResponse; return acceptQuestResponse;
} }

View File

@ -733,6 +733,34 @@ 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)
{
questToUpdate.status = newQuestState;
questToUpdate.statusTimers[newQuestState] = this.timeUtil.getTimestamp();
// Delete all status timers after the 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 * Give player quest rewards - Skills/exp/trader standing/items/assort unlocks - Returns reward items player earned
* @param profileData Player profile (scav or pmc) * @param profileData Player profile (scav or pmc)