Moved in-game reward check even further up chain into ApplyQuestReward()

Replaced magic strings with string consts inside `IngameTraders` collection

Various comment improvements
This commit is contained in:
Chomp
2025-05-21 10:42:13 +01:00
parent e41002dc01
commit c9e28e05bb
3 changed files with 56 additions and 58 deletions
@@ -33,37 +33,61 @@ public class QuestRewardHelper(
{
protected QuestConfig _questConfig = _configServer.GetConfig<QuestConfig>();
/**
* Give player quest rewards - Skills/exp/trader standing/items/assort unlocks - Returns reward items player earned
* @param profileData Player profile (scav or pmc)
* @param questId questId of quest to get rewards for
* @param state State of the quest to get rewards for
* @param sessionId Session id
* @param questResponse Response to send back to client
* @returns Array of reward objects
*/
/// <summary>
/// Value for in game reward traders to not duplicate quest rewards.
/// Value can be modified by modders by overriding this value with new traders.
/// Ensure to add Lightkeeper's ID (638f541a29ffd1183d187f57) and BTR Driver's ID (656f0f98d80a697f855d34b1)
/// </summary>
protected string[] InGameTraders =
[
Traders.LIGHTHOUSEKEEPER,
Traders.BTR
];
/// <summary>
/// Give player quest rewards - Skills/exp/trader standing/items/assort unlocks - Returns reward items player earned
/// SKIP quests completed in-game
/// </summary>
/// <param name="profileData">Player profile (scav or pmc)</param>
/// <param name="questId">questId of quest to get rewards for</param>
/// <param name="state">State of the quest to get rewards for</param>
/// <param name="sessionId">Session id</param>
/// <param name="questResponse">Response to send back to client</param>
/// <returns>Array of reward items player was given</returns>
public IEnumerable<Item> ApplyQuestReward(PmcData profileData, string questId, QuestStatusEnum state, string sessionId,
ItemEventRouterResponse questResponse)
{
// Repeatable quest base data is always in PMCProfile, `profileData` may be scav profile
// TODO: consider moving repeatable quest data to profile-agnostic location
// TODO: Move repeatable quest data to profile-agnostic location
var fullProfile = _profileHelper.GetFullProfile(sessionId);
var pmcProfile = fullProfile.CharacterData.PmcData;
if (pmcProfile is null)
{
_logger.Error($"Unable to get pmc profile for: {sessionId}, no rewards given");
return Enumerable.Empty<Item>();
return [];
}
var questDetails = GetQuestFromDb(questId, pmcProfile);
if (questDetails is null)
{
_logger.Warning(_localisationService.GetText("quest-unable_to_find_quest_in_db_no_quest_rewards", questId));
return Enumerable.Empty<Item>();
return [];
}
if (IsInGameTrader(questDetails))
{
// Assuming in-game traders give ALL rewards
_logger.Debug(
$"Skipping quest rewards for quest: {questDetails.Id}, trader: {questDetails.TraderId} in InGameRewardTrader list"
);
return [];
}
var questMoneyRewardBonusMultiplier = GetQuestMoneyRewardBonusMultiplier(pmcProfile);
if (questMoneyRewardBonusMultiplier > 0) // money = money + (money * intelCenterBonus / 100)
if (questMoneyRewardBonusMultiplier > 0) // money = money + (money * IntelCenterBonus / 100)
{
questDetails = ApplyMoneyBoost(questDetails, questMoneyRewardBonusMultiplier, state);
}
@@ -76,11 +100,20 @@ public class QuestRewardHelper(
fullProfile,
profileData,
questId,
questResponse,
questDetails
questResponse
);
}
/// <summary>
/// Determines if quest rewards are given in raid by the trader instead of through messaging system.
/// </summary>
/// <param name="quest">The quest to check.</param>
/// <returns>True if the quest's trader is in the in-game reward trader list; otherwise, false.</returns>
protected bool IsInGameTrader(Quest quest)
{
return InGameTraders.Contains(quest.TraderId);
}
/// <summary>
/// Get quest by id from database (repeatable quests are stored in profile, check there if questId not found)
/// </summary>
@@ -37,7 +37,6 @@ public class RewardHelper(
/// <param name="profileData">The profile data (could be the scav profile).</param>
/// <param name="rewardSourceId">The quest or achievement ID, used for finding production unlocks.</param>
/// <param name="questResponse">Response to quest completion when a production is unlocked.</param>
/// <param name="quest">The quest that the reward is for.</param>
/// <returns>List of items that is the reward.</returns>
public List<Item> ApplyRewards(
List<Reward> rewards,
@@ -45,29 +44,20 @@ public class RewardHelper(
SptProfile fullProfile,
PmcData profileData,
string rewardSourceId,
ItemEventRouterResponse? questResponse = null,
Quest? quest = null
ItemEventRouterResponse? questResponse = null
)
{
var sessionId = fullProfile?.ProfileInfo?.ProfileId;
var pmcProfile = fullProfile?.CharacterData.PmcData;
var pmcProfile = fullProfile?.CharacterData?.PmcData;
if (pmcProfile is null)
{
_logger.Error($"Unable to get pmc profile for: {sessionId}, no rewards given");
_logger.Error($"Unable to get PMC profile for: {sessionId}, no rewards given");
return [];
}
var gameVersion = pmcProfile.Info.GameVersion;
var isInGameRewardTrader = quest != null && IsInGameRewardTrader(quest);
if (isInGameRewardTrader)
{
_logger.Debug(
$"Skipping quest rewards for quest {quest.Id} as it is in the InGameRewardrTader list"
);
return [];
}
foreach (var reward in rewards)
{
// Handle reward availability for different game versions, notAvailableInGameEditions currently not used
@@ -142,30 +132,7 @@ public class RewardHelper(
}
}
return GetRewardItems(rewards, gameVersion, quest);
}
/// <summary>
/// Value for in game reward traders to not duplicate quest rewards.
/// Value can be modified by modders by overriding this value with new traders.
/// Ensure to add Lightkeeper's ID (638f541a29ffd1183d187f57) and BTR Driver's ID (656f0f98d80a697f855d34b1)
/// </summary>
protected string[] noRewardTraders =
[
// LightKeeper
"638f541a29ffd1183d187f57",
// BTR Driver
"656f0f98d80a697f855d34b1",
];
/// <summary>
/// Determines if quest rewards are given in raid by the trader instead of through messaging system.
/// </summary>
/// <param name="quest">The quest to check.</param>
/// <returns>True if the quest's trader is in the in-game reward trader list; otherwise, false.</returns>
protected bool IsInGameRewardTrader(Quest quest)
{
return noRewardTraders.Contains(quest.TraderId);
return GetRewardItems(rewards, gameVersion);
}
/// <summary>
@@ -285,12 +252,10 @@ public class RewardHelper(
/// </summary>
/// <param name="rewards">Array of rewards to get the items from.</param>
/// <param name="gameVersion">The game version of the profile.</param>
/// <param name="quest">The quest (optional).</param>
/// <returns>Array of items with the correct maxStack.</returns>
protected List<Item> GetRewardItems(
List<Reward> rewards,
string gameVersion,
Quest? quest = null
string gameVersion
)
{
// Iterate over all rewards with the desired status, flatten out items that have a type of Item
@@ -310,7 +275,7 @@ public class RewardHelper(
/// <returns>Fixed rewards.</returns>
protected List<Item> ProcessReward(Reward reward)
{
/** item with mods to return */
// item with mods to return
List<Item> rewardItems = [];
List<Item> targets = [];
List<Item> mods = [];
@@ -135,7 +135,7 @@ public class CreateProfileService(
var achievementsDb = _databaseService.GetTemplates().Achievements;
var achievementRewardItemsToSend = new List<Item>();
foreach (var (achievementId, achievement) in profileDetails.CharacterData.PmcData.Achievements)
foreach (var (achievementId, _) in profileDetails.CharacterData.PmcData.Achievements)
{
var rewards = achievementsDb.FirstOrDefault(achievementDb => achievementDb.Id == achievementId)?.Rewards;