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; }