From 8b4a81fae7fe0edcb996e8268d552a233e84b6bc Mon Sep 17 00:00:00 2001
From: Cj <161484149+CJ-SPT@users.noreply.github.com>
Date: Sun, 10 Aug 2025 04:52:00 -0400
Subject: [PATCH] Make first 3 initial daily quests of differing type (#540)
* Make first 3 initial daily quests of differing type
* add comment
---
.../Controllers/RepeatableQuestController.cs | 143 ++++++++++++++----
.../Eft/Common/Tables/RepeatableQuests.cs | 4 +-
2 files changed, 119 insertions(+), 28 deletions(-)
diff --git a/Libraries/SPTarkov.Server.Core/Controllers/RepeatableQuestController.cs b/Libraries/SPTarkov.Server.Core/Controllers/RepeatableQuestController.cs
index 538b5f86..8dbbe4fb 100644
--- a/Libraries/SPTarkov.Server.Core/Controllers/RepeatableQuestController.cs
+++ b/Libraries/SPTarkov.Server.Core/Controllers/RepeatableQuestController.cs
@@ -368,16 +368,8 @@ public class RepeatableQuestController(
)
{
var questType = randomUtil.DrawRandomFromList(questTypePool.Types).First();
+ var traderId = DrawRandomTraderId(pmcTraderInfo, questType, repeatableConfig);
- // Get traders from whitelist and filter by quest type availability
- var traders = repeatableConfig
- .TraderWhitelist.Where(whitelist => whitelist.QuestTypes.Contains(questType))
- .Select(x => x.TraderId)
- // filter out locked traders
- .Where(mongoId => pmcTraderInfo[mongoId].Unlocked.GetValueOrDefault(false))
- .ToList();
-
- var traderId = randomUtil.DrawRandomFromList(traders).FirstOrDefault();
if (traderId.IsEmpty)
{
logger.Error(serverLocalisationService.GetText("repeatable-unable_to_find_trader_in_pool"));
@@ -400,6 +392,30 @@ public class RepeatableQuestController(
};
}
+ ///
+ /// Draws a random trader to assign a repeatable task to
+ ///
+ /// Trader info
+ /// Type of quest
+ /// Repeatable config
+ /// Randomly selected traderId
+ protected MongoId DrawRandomTraderId(
+ Dictionary traderInfos,
+ string questType,
+ RepeatableQuestConfig repeatableConfig
+ )
+ {
+ // Get traders from whitelist and filter by quest type availability
+ var traders = repeatableConfig
+ .TraderWhitelist.Where(whitelist => whitelist.QuestTypes.Contains(questType))
+ .Select(x => x.TraderId)
+ // filter out locked traders
+ .Where(mongoId => traderInfos[mongoId].Unlocked.GetValueOrDefault(false))
+ .ToList();
+
+ return randomUtil.DrawRandomFromList(traders).FirstOrDefault();
+ }
+
///
/// Remove the provided quest from pmc and scav character profiles
///
@@ -518,24 +534,57 @@ public class RepeatableQuestController(
// Add repeatable quests of this loops sub-type (daily/weekly)
for (var i = 0; i < GetQuestCount(repeatableConfig, fullProfile); i++)
{
- RepeatableQuest? quest = null;
- var lifeline = 0;
- while (quest?.Id == null && questTypePool.Types.Count > 0)
- {
- quest = PickAndGenerateRandomRepeatableQuest(
- sessionID,
- pmcData.Info.Level ?? 0,
- pmcData.TradersInfo,
- questTypePool,
- repeatableConfig
- );
- lifeline++;
- if (lifeline > 10)
- {
- logger.Error("We were stuck in repeatable quest generation. This should never happen. Please report");
+ RepeatableQuest? quest;
- break;
+ // The first 3 initial dailies generated need to be of separate types
+ if (repeatableConfig.Name == "Daily" && i < 3)
+ {
+ var questType = i switch
+ {
+ 0 => "Elimination",
+ 1 => "Completion",
+ 2 => "Exploration",
+ _ => null,
+ };
+
+ if (questType is null)
+ {
+ logger.Error("index `i` is out of range for valid quest types, this should never be hit, report it.");
+ continue;
}
+
+ var traderId = DrawRandomTraderId(pmcData.TradersInfo, questType, repeatableConfig);
+
+ quest = i switch
+ {
+ 0 => eliminationQuestGenerator.Generate(
+ sessionID,
+ pmcData.Info.Level ?? 0,
+ traderId,
+ questTypePool,
+ repeatableConfig
+ ),
+ 1 => completionQuestGenerator.Generate(
+ sessionID,
+ pmcData.Info.Level ?? 0,
+ traderId,
+ questTypePool,
+ repeatableConfig
+ ),
+ 2 => explorationQuestGenerator.Generate(
+ sessionID,
+ pmcData.Info.Level ?? 0,
+ traderId,
+ questTypePool,
+ repeatableConfig
+ ),
+ _ => null,
+ };
+ }
+ // Not part of the first 3 dailies generated or not a daily task, generate a random type of task
+ else
+ {
+ quest = TryGenerateRandomRepeatable(sessionID, pmcData, questTypePool, repeatableConfig);
}
// check if there are no more quest types available
@@ -555,7 +604,7 @@ public class RepeatableQuestController(
fullProfile.SptData.FreeRepeatableRefreshUsedCount[repeatableTypeLower] = 0;
// Create stupid redundant change requirements from quest data
- generatedRepeatables.ChangeRequirement = new Dictionary();
+ generatedRepeatables.ChangeRequirement = new Dictionary();
foreach (var quest in generatedRepeatables.ActiveQuests)
{
generatedRepeatables.ChangeRequirement.TryAdd(
@@ -589,6 +638,48 @@ public class RepeatableQuestController(
return returnData;
}
+ ///
+ /// Try to generate a repeatable task at random
+ ///
+ /// sessionId to generate for
+ /// Pmc profile to add the quest to
+ /// Pool of quests to pick from
+ /// Repeatable quest config
+ ///
+ protected RepeatableQuest? TryGenerateRandomRepeatable(
+ MongoId sessionId,
+ PmcData pmcData,
+ QuestTypePool questTypePool,
+ RepeatableQuestConfig repeatableConfig
+ )
+ {
+ RepeatableQuest? quest = null;
+ var lifeline = 0;
+
+ while (quest?.Id == null && questTypePool.Types.Count > 0)
+ {
+ quest = PickAndGenerateRandomRepeatableQuest(
+ sessionId,
+ pmcData.Info.Level ?? 0,
+ pmcData.TradersInfo,
+ questTypePool,
+ repeatableConfig
+ );
+
+ lifeline++;
+ if (lifeline <= 10)
+ {
+ continue;
+ }
+
+ logger.Error("We were stuck in repeatable quest generation. This should never happen. Please report");
+
+ break;
+ }
+
+ return quest;
+ }
+
///
/// Get repeatable quest data from profile from name (daily/weekly), creates base repeatable quest object if none exists
///
diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/RepeatableQuests.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/RepeatableQuests.cs
index aaf6eed9..bc0f63ec 100644
--- a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/RepeatableQuests.cs
+++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/RepeatableQuests.cs
@@ -87,7 +87,7 @@ public record PmcDataRepeatableQuest
public Dictionary? ExtensionData { get; set; }
[JsonPropertyName("id")]
- public string? Id { get; set; }
+ public MongoId? Id { get; set; }
[JsonPropertyName("name")]
public string? Name { get; set; }
@@ -109,7 +109,7 @@ public record PmcDataRepeatableQuest
///
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
[JsonPropertyName("changeRequirement")]
- public Dictionary? ChangeRequirement { get; set; }
+ public Dictionary? ChangeRequirement { get; set; }
[JsonPropertyName("freeChanges")]
public int? FreeChanges { get; set; }