diff --git a/Libraries/SPTarkov.Server.Core/Generators/RepeatableQuestGeneration/RepeatableQuestRewardGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/RepeatableQuestGeneration/RepeatableQuestRewardGenerator.cs
index 9616c775..205598d8 100644
--- a/Libraries/SPTarkov.Server.Core/Generators/RepeatableQuestGeneration/RepeatableQuestRewardGenerator.cs
+++ b/Libraries/SPTarkov.Server.Core/Generators/RepeatableQuestGeneration/RepeatableQuestRewardGenerator.cs
@@ -58,7 +58,7 @@ public class RepeatableQuestRewardGenerator(
/// Base Quest config
/// Optional: list of tpls to NOT use when picking a reward
/// QuestRewards
- public QuestRewards? GenerateReward(
+ public Dictionary>? GenerateReward(
int pmcLevel,
double difficulty,
MongoId traderId,
@@ -78,11 +78,11 @@ public class RepeatableQuestRewardGenerator(
var itemRewardBudget = rewardParams.RewardRoubles;
// Possible improvement -> draw trader-specific items e.g. with _itemHelper.isOfBaseclass(val._id, ItemHelper.BASECLASS.FoodDrink)
- QuestRewards rewards = new()
+ var rewards = new Dictionary>
{
- Started = [],
- Success = [],
- Fail = [],
+ { "Success", [] },
+ { "Started", [] },
+ { "Fail", [] },
};
// Start reward index to keep track
@@ -91,29 +91,29 @@ public class RepeatableQuestRewardGenerator(
// Add xp reward
if (rewardParams.RewardXP > 0)
{
- rewards.Success.Add(
- new Reward
- {
- Id = new MongoId(),
- Unknown = false,
- GameMode = [],
- AvailableInGameEditions = [],
- Index = rewardIndex,
- Value = rewardParams.RewardXP,
- Type = RewardType.Experience,
- }
- );
+ rewards["Success"]
+ .Add(
+ new Reward
+ {
+ Id = new MongoId(),
+ Unknown = false,
+ GameMode = [],
+ AvailableInGameEditions = [],
+ Index = rewardIndex,
+ Value = rewardParams.RewardXP,
+ Type = RewardType.Experience,
+ }
+ );
rewardIndex++;
}
// Add money reward
- rewards.Success.Add(GetMoneyReward(traderId, rewardParams.RewardRoubles, rewardIndex));
+ rewards["Success"].Add(GetMoneyReward(traderId, rewardParams.RewardRoubles, rewardIndex));
rewardIndex++;
// Add GP coin reward
- rewards.Success.Add(
- GenerateItemReward(Money.GP, rewardParams.GpCoinRewardCount, rewardIndex)
- );
+ rewards["Success"]
+ .Add(GenerateItemReward(Money.GP, rewardParams.GpCoinRewardCount, rewardIndex));
rewardIndex++;
// Add preset weapon to reward if checks pass
@@ -135,7 +135,7 @@ public class RepeatableQuestRewardGenerator(
var chosenWeapon = GetRandomWeaponPresetWithinBudget(itemRewardBudget, rewardIndex);
if (chosenWeapon is not null)
{
- rewards.Success.Add(chosenWeapon.Value.Key);
+ rewards["Success"].Add(chosenWeapon.Value.Key);
// Subtract price of preset from item budget so we don't give player too much stuff
itemRewardBudget -= chosenWeapon.Value.Value;
@@ -180,9 +180,8 @@ public class RepeatableQuestRewardGenerator(
// Add item rewards
foreach (var itemReward in itemsToReward)
{
- rewards.Success.Add(
- GenerateItemReward(itemReward.Key.Id, itemReward.Value, rewardIndex)
- );
+ rewards["Success"]
+ .Add(GenerateItemReward(itemReward.Key.Id, itemReward.Value, rewardIndex));
rewardIndex++;
}
}
@@ -201,7 +200,7 @@ public class RepeatableQuestRewardGenerator(
Type = RewardType.TraderStanding,
Index = rewardIndex,
};
- rewards.Success.Add(reward);
+ rewards["Success"].Add(reward);
rewardIndex++;
if (logger.IsLogEnabled(LogLevel.Debug))
@@ -227,7 +226,7 @@ public class RepeatableQuestRewardGenerator(
Type = RewardType.Skill,
Index = rewardIndex,
};
- rewards.Success.Add(reward);
+ rewards["Success"].Add(reward);
if (logger.IsLogEnabled(LogLevel.Debug))
{
diff --git a/Libraries/SPTarkov.Server.Core/Helpers/QuestHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/QuestHelper.cs
index 9f15c748..483b5910 100644
--- a/Libraries/SPTarkov.Server.Core/Helpers/QuestHelper.cs
+++ b/Libraries/SPTarkov.Server.Core/Helpers/QuestHelper.cs
@@ -1,6 +1,5 @@
using System.Collections.Frozen;
using System.Globalization;
-using SPTarkov.Common.Extensions;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Models.Common;
@@ -1403,7 +1402,10 @@ public class QuestHelper(
}
}
- return UpdateQuestsForGameEdition(questsToShowPlayer, profile.Info.GameVersion);
+ return UpdateQuestsForGameEdition(
+ cloner.Clone(questsToShowPlayer),
+ profile.Info.GameVersion
+ );
}
///
@@ -1414,11 +1416,10 @@ public class QuestHelper(
/// Collection of Quest objects with the rewards filtered correctly for the game version
protected List UpdateQuestsForGameEdition(List quests, string gameVersion)
{
- var modifiedQuests = cloner.Clone(quests);
- foreach (var quest in modifiedQuests)
+ foreach (var quest in quests)
{
// Remove any reward that doesn't pass the game edition check
- var propsAsDict = quest.Rewards.GetAllPropsAsDict();
+ var propsAsDict = quest.Rewards;
foreach (var rewardType in propsAsDict)
{
if (rewardType.Value is null)
@@ -1426,13 +1427,13 @@ public class QuestHelper(
continue;
}
- propsAsDict[rewardType.Key] = ((List)propsAsDict[rewardType.Key])
+ propsAsDict[rewardType.Key] = propsAsDict[rewardType.Key]
.Where(reward => rewardHelper.RewardIsForGameEdition(reward, gameVersion))
.ToList();
}
}
- return modifiedQuests;
+ return quests;
}
///
diff --git a/Libraries/SPTarkov.Server.Core/Helpers/QuestRewardHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/QuestRewardHelper.cs
index d36bb492..29be0a2f 100644
--- a/Libraries/SPTarkov.Server.Core/Helpers/QuestRewardHelper.cs
+++ b/Libraries/SPTarkov.Server.Core/Helpers/QuestRewardHelper.cs
@@ -1,4 +1,3 @@
-using SPTarkov.Common.Extensions;
using SPTarkov.DI.Annotations;
using SPTarkov.Server.Core.Extensions;
using SPTarkov.Server.Core.Models.Common;
@@ -89,7 +88,7 @@ public class QuestRewardHelper(
}
// e.g. 'Success' or 'AvailableForFinish'
- var rewards = questDetails.Rewards.GetByJsonProp>(state.ToString());
+ var rewards = questDetails.Rewards[state.ToString()];
return rewardHelper.ApplyRewards(
rewards,
CustomisationSource.UNLOCKED_IN_GAME,
@@ -172,18 +171,20 @@ public class QuestRewardHelper(
public Quest ApplyMoneyBoost(Quest quest, double bonusPercent, QuestStatusEnum questStatus)
{
var clonedQuest = cloner.Clone(quest);
- if (clonedQuest?.Rewards?.Success == null)
+ if (clonedQuest?.Rewards?["Success"] == null)
{
return clonedQuest;
}
// Grab just the money rewards from quest reward pool
- var moneyRewards = clonedQuest.Rewards.Success.Where(reward =>
- reward.Type == RewardType.Item
- && reward.Items != null
- && reward.Items.Count > 0
- && paymentHelper.IsMoneyTpl(reward.Items.FirstOrDefault().Template)
- );
+ var moneyRewards = clonedQuest
+ .Rewards["Success"]
+ .Where(reward =>
+ reward.Type == RewardType.Item
+ && reward.Items != null
+ && reward.Items.Count > 0
+ && paymentHelper.IsMoneyTpl(reward.Items.FirstOrDefault().Template)
+ );
foreach (var moneyReward in moneyRewards)
{
diff --git a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/Quest.cs b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/Quest.cs
index 20b603e5..3d573534 100644
--- a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/Quest.cs
+++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/Quest.cs
@@ -85,7 +85,7 @@ public record Quest
public string? TemplateId { get; set; }
[JsonPropertyName("rewards")]
- public QuestRewards? Rewards { get; set; }
+ public Dictionary>? Rewards { get; set; }
///
/// Becomes 'AppearStatus' inside client
@@ -489,30 +489,3 @@ public record VisibilityCondition
[JsonPropertyName("conditionType")]
public required string ConditionType { get; set; }
}
-
-public record QuestRewards
-{
- [JsonExtensionData]
- public Dictionary? ExtensionData { get; set; }
-
- [JsonPropertyName("AvailableForStart")]
- public List? AvailableForStart { get; set; }
-
- [JsonPropertyName("AvailableForFinish")]
- public List? AvailableForFinish { get; set; }
-
- [JsonPropertyName("Started")]
- public List? Started { get; set; }
-
- [JsonPropertyName("Success")]
- public List? Success { get; set; }
-
- [JsonPropertyName("Fail")]
- public List? Fail { get; set; }
-
- [JsonPropertyName("FailRestartable")]
- public List? FailRestartable { get; set; }
-
- [JsonPropertyName("Expired")]
- public List? Expired { get; set; }
-}
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 2e06d406..aaf6eed9 100644
--- a/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/RepeatableQuests.cs
+++ b/Libraries/SPTarkov.Server.Core/Models/Eft/Common/Tables/RepeatableQuests.cs
@@ -240,7 +240,7 @@ public record SampleQuests
public bool? CanShowNotificationsInGame { get; set; }
[JsonPropertyName("rewards")]
- public QuestRewards? Rewards { get; set; }
+ public Dictionary>? Rewards { get; set; }
[JsonPropertyName("conditions")]
public QuestConditionTypes? Conditions { get; set; }
diff --git a/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs b/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs
index 3da3e142..19d07c72 100644
--- a/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs
+++ b/Libraries/SPTarkov.Server.Core/Services/ProfileFixerService.cs
@@ -362,9 +362,9 @@ public class ProfileFixerService(
// For started or successful quests, check for unlocks in the `Started` rewards
if (profileQuest.Status is QuestStatusEnum.Started or QuestStatusEnum.Success)
{
- var productionRewards = quest.Rewards.Started?.Where(reward =>
- reward.Type == RewardType.ProductionScheme
- );
+ var productionRewards = quest
+ .Rewards["Started"]
+ ?.Where(reward => reward.Type == RewardType.ProductionScheme);
if (productionRewards is not null)
{
@@ -378,9 +378,9 @@ public class ProfileFixerService(
// For successful quests, check for unlocks in the `Success` rewards
if (profileQuest.Status is QuestStatusEnum.Success)
{
- var productionRewards = quest.Rewards.Success?.Where(reward =>
- reward.Type == RewardType.ProductionScheme
- );
+ var productionRewards = quest
+ .Rewards["Success"]
+ ?.Where(reward => reward.Type == RewardType.ProductionScheme);
if (productionRewards is not null)
{
@@ -793,16 +793,16 @@ public class ProfileFixerService(
continue;
}
- if (activeQuest.Rewards?.Success is null)
+ if (activeQuest.Rewards?["Success"] is null)
{
continue;
}
// Get Item rewards only
foreach (
- var successReward in activeQuest.Rewards.Success.Where(reward =>
- reward.Type == RewardType.Item
- )
+ var successReward in activeQuest
+ .Rewards["Success"]
+ .Where(reward => reward.Type == RewardType.Item)
)
foreach (var item in successReward.Items)
{
diff --git a/Tools/HideoutCraftQuestIdGenerator/HideoutCraftQuestIdGenerator.cs b/Tools/HideoutCraftQuestIdGenerator/HideoutCraftQuestIdGenerator.cs
index e4fddedb..47b03994 100644
--- a/Tools/HideoutCraftQuestIdGenerator/HideoutCraftQuestIdGenerator.cs
+++ b/Tools/HideoutCraftQuestIdGenerator/HideoutCraftQuestIdGenerator.cs
@@ -231,19 +231,14 @@ public class HideoutCraftQuestIdGenerator(
return true;
}
- private HashSet CombineRewards(QuestRewards? questRewards)
+ ///
+ /// Merge all rewards together into one collection
+ ///
+ /// Rewards to merge
+ /// IEnumerable
+ protected IEnumerable CombineRewards(Dictionary>? questRewards)
{
- var result = new HashSet();
- questRewards.Started?.ForEach(x => result.Add(x));
- questRewards.Success?.ForEach(x => result.Add(x));
- questRewards.AvailableForFinish?.ForEach(x => result.Add(x));
- questRewards.Expired?.ForEach(x => result.Add(x));
- questRewards.AvailableForStart?.ForEach(x => result.Add(x));
- questRewards.Fail?.ForEach(x => result.Add(x));
- questRewards.FailRestartable?.ForEach(x => result.Add(x));
- questRewards.Started?.ForEach(x => result.Add(x));
-
- return result;
+ return questRewards?.SelectMany(rewardKvP => rewardKvP.Value) ?? [];
}
}