questHelper done

This commit is contained in:
CWX
2025-01-22 11:15:14 +00:00
parent edb68d7f8b
commit e1ec67619d
2 changed files with 339 additions and 15 deletions
+310 -15
View File
@@ -11,6 +11,7 @@ using Core.Servers;
using Core.Services;
using Core.Utils;
using Core.Utils.Cloners;
using SptCommon.Extensions;
using Product = Core.Models.Eft.ItemEvent.Product;
namespace Core.Helpers;
@@ -38,6 +39,7 @@ public class QuestHelper(
)
{
protected QuestConfig _questConfig = _configServer.GetConfig<QuestConfig>();
protected List<QuestStatusEnum> _newlyQuestCheck = [QuestStatusEnum.Started, QuestStatusEnum.AvailableForFinish];
/// <summary>
/// Get status of a quest in player profile by its id
@@ -202,13 +204,66 @@ public class QuestHelper(
* @param newState State the new quest should be in when returned
* @param acceptedQuest Details of accepted quest from client
*/
public QuestStatus GetQuestReadyForProfile(
PmcData pmcData,
QuestStatusEnum newState,
AcceptQuestRequestData acceptedQuest
)
public QuestStatus GetQuestReadyForProfile(PmcData pmcData, QuestStatusEnum newState, AcceptQuestRequestData acceptedQuest)
{
throw new NotImplementedException();
var currentTimestamp = _timeUtil.GetTimeStamp();
var existingQuest = pmcData.Quests.FirstOrDefault(q => q.QId == acceptedQuest.QuestId);
if (existingQuest is not null)
{
// Quest exists, update its status
existingQuest.StartTime = currentTimestamp;
existingQuest.Status = newState;
existingQuest.StatusTimers[newState] = currentTimestamp;
existingQuest.CompletedConditions = [];
if (existingQuest.AvailableAfter is not null)
{
existingQuest.AvailableAfter = null;
}
return existingQuest;
}
// Quest doesn't exists, add it
QuestStatus newQuest = new QuestStatus
{
QId = acceptedQuest.QuestId,
StartTime = currentTimestamp,
Status = newState,
StatusTimers = new Dictionary<QuestStatusEnum, long>(),
};
// Check if quest has a prereq to be placed in a 'pending' state, otherwise set status timers value
var questDbData = GetQuestFromDb(acceptedQuest.QuestId, pmcData);
if (questDbData is null)
{
_logger.Error(
_localisationService.GetText(
"quest-unable_to_find_quest_in_db",
new
{
questId = acceptedQuest.QuestId,
questType = acceptedQuest.Type,
}
)
);
}
var waitTime = questDbData?.Conditions.AvailableForStart.FirstOrDefault(x => x.AvailableAfter > 0);
if (waitTime is not null && acceptedQuest.Type != "repeatable")
{
// Quest should be put into 'pending' state
newQuest.StartTime = 0;
newQuest.Status = QuestStatusEnum.AvailableAfter; // 9
newQuest.AvailableAfter = currentTimestamp + waitTime.AvailableAfter;
}
else
{
newQuest.StatusTimers[newState] = currentTimestamp;
newQuest.CompletedConditions = [];
}
return newQuest;
}
/**
@@ -219,7 +274,84 @@ public class QuestHelper(
*/
public List<Quest> GetNewlyAccessibleQuestsWhenStartingQuest(string startedQuestId, string sessionID)
{
throw new NotImplementedException();
// Get quest acceptance data from profile
PmcData profile = _profileHelper.GetPmcProfile(sessionID);
var startedQuestInProfile = profile.Quests.FirstOrDefault(profileQuest => profileQuest.QId == startedQuestId);
// Get quests that
var eligibleQuests = GetQuestsFromDb()
.Where(
quest =>
{
// Quest is accessible to player when the accepted quest passed into param is started
// e.g. Quest A passed in, quest B is looped over and has requirement of A to be started, include it
var acceptedQuestCondition = quest.Conditions.AvailableForStart.FirstOrDefault(
condition =>
{
return (
condition.ConditionType == "Quest" &&
(condition.Target?.List.Contains(startedQuestId) ?? false) &&
(condition.Status?.Contains(QuestStatusEnum.Started) ?? false)
);
}
);
// Not found, skip quest
if (acceptedQuestCondition is null)
{
return false;
}
// Skip locked event quests
if (!ShowEventQuestToPlayer(quest.Id))
{
return false;
}
// Skip quest if its flagged as for other side
if (QuestIsForOtherSide(profile.Info.Side, quest.Id))
{
return false;
}
if (QuestIsProfileBlacklisted(profile.Info.GameVersion, quest.Id))
{
return false;
}
if (!QuestIsProfileWhitelisted(profile.Info.GameVersion, quest.Id))
{
return false;
}
var standingRequirements = _questConditionHelper.GetStandingConditions(
quest.Conditions.AvailableForStart
);
foreach (var condition in standingRequirements)
{
if (!TraderStandingRequirementCheck(condition, profile))
{
return false;
}
}
var loyaltyRequirements = _questConditionHelper.GetLoyaltyConditions(
quest.Conditions.AvailableForStart
);
foreach (var condition in loyaltyRequirements)
{
if (!TraderLoyaltyLevelRequirementCheck(condition, profile))
{
return false;
}
}
// Include if quest found in profile and is started or ready to hand in
return ((startedQuestInProfile is not null) && _newlyQuestCheck.Contains((QuestStatusEnum)startedQuestInProfile.Status));
}
);
return GetQuestsWithOnlyLevelRequirementStartCondition(eligibleQuests.ToList());
}
/**
@@ -919,7 +1051,8 @@ public class QuestHelper(
? conditionToFulfil.Target.List
: (conditionToFulfil.Target.Item == null
? null
: [conditionToFulfil.Target.Item])) ?? [];
: [conditionToFulfil.Target.Item])) ??
[];
var prerequisiteQuest =
profile.Quests.FirstOrDefault(profileQuest => questIdsToFulfil.Contains(profileQuest.QId));
@@ -1000,7 +1133,24 @@ public class QuestHelper(
*/
protected List<Quest> UpdateQuestsForGameEdition(List<Quest> quests, string gameVersion)
{
throw new NotImplementedException();
_logger.Debug("[UpdateQuestsForGameEdition] If you are hitting this method, please confirm the return is compared to Node");
var modifiedQuests = _cloner.Clone(quests);
foreach (var quest in modifiedQuests)
{
// Remove any reward that doesn't pass the game edition check
var propsAsDict = quest.Rewards.GetAllPropsAsDict<List<Reward>>();
foreach (var rewardType in propsAsDict)
{
propsAsDict[rewardType.Key] = propsAsDict[rewardType.Key]
.Where(
reward =>
_rewardHelper.RewardIsForGameEdition(reward, gameVersion)
)
.ToList();
}
}
return modifiedQuests;
}
/**
@@ -1010,7 +1160,26 @@ public class QuestHelper(
*/
protected List<Quest> GetQuestsFromProfileFailedByCompletingQuest(string completedQuestId, PmcData pmcProfile)
{
throw new NotImplementedException();
var questsInDb = GetQuestsFromDb();
return questsInDb.Where(
quest =>
{
// No fail conditions, skip
if (quest.Conditions.Fail is null || quest.Conditions.Fail.Count == 0)
{
return false;
}
// Quest already failed in profile, skip
if (pmcProfile.Quests.Any(profileQuest => profileQuest.QId == quest.Id && profileQuest.Status == QuestStatusEnum.Fail))
{
return false;
}
return quest.Conditions.Fail.Any(condition => (condition.Target.List?.Contains(completedQuestId) ?? false));
}
)
.ToList();
}
/**
@@ -1028,7 +1197,50 @@ public class QuestHelper(
ItemEventRouterResponse output
)
{
throw new NotImplementedException();
foreach (var questToFail in questsToFail)
{
// Skip failing a quest that has a fail status of something other than success
if (questToFail.Conditions.Fail?.Any(x => x.Status?.Any(status => status != QuestStatusEnum.Success) ?? false) ?? false)
{
continue;
}
var isActiveQuestInPlayerProfile = pmcData.Quests.FirstOrDefault(quest => quest.QId == questToFail.Id);
if (isActiveQuestInPlayerProfile is not null)
{
if (isActiveQuestInPlayerProfile.Status != QuestStatusEnum.Fail)
{
FailQuestRequestData failBody = new FailQuestRequestData
{
Action = "QuestFail",
QuestId = questToFail.Id,
RemoveExcessItems = true,
};
FailQuest(pmcData, failBody, sessionID, output);
}
}
else
{
// Failing an entirely new quest that doesn't exist in profile
Dictionary<QuestStatusEnum, long> statusTimers = new Dictionary<QuestStatusEnum, long>();
if (!statusTimers.TryGetValue(QuestStatusEnum.Fail, out var _))
{
statusTimers.Add(QuestStatusEnum.Fail, 0);
}
statusTimers[QuestStatusEnum.Fail] = _timeUtil.GetTimeStamp();
QuestStatus questData = new QuestStatus
{
QId = questToFail.Id,
StartTime = _timeUtil.GetTimeStamp(),
StatusTimers = statusTimers,
Status = QuestStatusEnum.Fail,
}
;
pmcData.Quests.Add(questData);
}
}
}
/**
@@ -1045,7 +1257,16 @@ public class QuestHelper(
List<Item> questRewards
)
{
throw new NotImplementedException();
var quest = GetQuestFromDb(completedQuestId, pmcData);
_mailSendService.SendLocalisedNpcMessageToPlayer(
sessionID,
_traderHelper.GetTraderById(quest.TraderId).ToString(),
MessageType.QUEST_SUCCESS,
quest.SuccessMessageText,
questRewards,
_timeUtil.GetHoursAsSeconds((int)GetMailItemRedeemTimeHoursForProfile(pmcData))
);
}
/**
@@ -1056,7 +1277,46 @@ public class QuestHelper(
*/
protected void AddTimeLockedQuestsToProfile(PmcData pmcData, List<Quest> quests, string completedQuestId)
{
throw new NotImplementedException();
// Iterate over quests, look for quests with right criteria
foreach (var quest in quests)
{
// If quest has prereq of completed quest + availableAfter value > 0 (quest has wait time)
var nextQuestWaitCondition = quest.Conditions.AvailableForStart.FirstOrDefault(
x => (x.Target?.List.Contains(completedQuestId) ?? false) && x.AvailableAfter > 0
);
if (nextQuestWaitCondition is not null)
{
// Now + wait time
var availableAfterTimestamp = _timeUtil.GetTimeStamp() + nextQuestWaitCondition.AvailableAfter;
// Update quest in profile with status of AvailableAfter
var existingQuestInProfile = pmcData.Quests.FirstOrDefault(x => x.QId == quest.Id);
if (existingQuestInProfile is not null)
{
existingQuestInProfile.AvailableAfter = availableAfterTimestamp;
existingQuestInProfile.Status = QuestStatusEnum.AvailableAfter;
existingQuestInProfile.StartTime = 0;
existingQuestInProfile.StatusTimers = new Dictionary<QuestStatusEnum, long>();
continue;
}
pmcData.Quests.Add(
new QuestStatus
{
QId = quest.Id,
StartTime = 0,
Status = QuestStatusEnum.AvailableAfter,
StatusTimers = new Dictionary<QuestStatusEnum, long>
{
{ QuestStatusEnum.AvailableAfter, _timeUtil.GetTimeStamp() }
},
AvailableAfter = availableAfterTimestamp,
}
);
}
}
}
/**
@@ -1066,7 +1326,25 @@ public class QuestHelper(
*/
protected void RemoveQuestFromScavProfile(string sessionId, string questIdToRemove)
{
throw new NotImplementedException();
var fullProfile = _profileHelper.GetFullProfile(sessionId);
var repeatableInScavProfile = fullProfile.CharacterData.ScavData.Quests?.FirstOrDefault(x => x.QId == questIdToRemove);
if (repeatableInScavProfile is null)
{
_logger.Warning(
_localisationService.GetText(
"quest-unable_to_remove_scav_quest_from_profile",
new
{
scavQuestId = questIdToRemove,
profileId = sessionId
}
)
);
return;
}
fullProfile.CharacterData.ScavData.Quests.Remove(repeatableInScavProfile);
}
/**
@@ -1080,7 +1358,24 @@ public class QuestHelper(
List<QuestStatus> postQuestStatuses
)
{
throw new NotImplementedException();
List<QuestStatus> result = [];
foreach (var quest in postQuestStatuses)
{
// Add quest if status differs or quest not found
var preQuest = preQuestStatuses.FirstOrDefault(x => x.QId == quest.QId);
if (preQuest is null || preQuest.Status != quest.Status)
{
result.Add(quest);
}
}
if (result.Count == 0)
{
return null;
}
return result;
}
/**