diff --git a/Core/Controllers/ProfileController.cs b/Core/Controllers/ProfileController.cs index 8485f208..3bcf627d 100644 --- a/Core/Controllers/ProfileController.cs +++ b/Core/Controllers/ProfileController.cs @@ -1,5 +1,3 @@ -using System.Runtime.InteropServices.JavaScript; -using System.Text.Json; using Core.Annotations; using Core.Generators; using Core.Helpers; @@ -40,6 +38,7 @@ public class ProfileController protected TraderHelper _traderHelper; protected DialogueHelper _dialogueHelper; protected QuestHelper _questHelper; + private readonly QuestRewardHelper _questRewardHelper; protected ProfileHelper _profileHelper; public ProfileController( @@ -59,6 +58,7 @@ public class ProfileController TraderHelper traderHelper, DialogueHelper dialogueHelper, QuestHelper questHelper, + QuestRewardHelper questRewardHelper, ProfileHelper profileHelper ) { @@ -77,6 +77,7 @@ public class ProfileController _traderHelper = traderHelper; _dialogueHelper = dialogueHelper; _questHelper = questHelper; + _questRewardHelper = questRewardHelper; _profileHelper = profileHelper; } @@ -365,7 +366,7 @@ public class ProfileController questFromDb.StartedMessageText, questFromDb.Description ); - var itemRewards = _questHelper.ApplyQuestReward( + var itemRewards = _questRewardHelper.ApplyQuestReward( profileDetails.CharacterData.PmcData, quest.QId, QuestStatusEnum.Started, diff --git a/Core/Controllers/QuestController.cs b/Core/Controllers/QuestController.cs index 66982644..7d24f47e 100644 --- a/Core/Controllers/QuestController.cs +++ b/Core/Controllers/QuestController.cs @@ -4,18 +4,32 @@ using Core.Models.Eft.Common; using Core.Models.Eft.Common.Tables; using Core.Models.Eft.ItemEvent; using Core.Models.Eft.Quests; +using Core.Utils; +using ILogger = Core.Models.Utils.ILogger; namespace Core.Controllers; [Injectable] public class QuestController { + private readonly ILogger _logger; + private readonly TimeUtil _timeUtil; + private readonly HttpResponseUtil _httpResponseUtil; private readonly QuestHelper _questHelper; + private readonly QuestRewardHelper _questRewardHelper; public QuestController( - QuestHelper questHelper) + ILogger logger, + TimeUtil timeUtil, + HttpResponseUtil httpResponseUtil, + QuestHelper questHelper, + QuestRewardHelper questRewardHelper) { + _logger = logger; + _timeUtil = timeUtil; + _httpResponseUtil = httpResponseUtil; _questHelper = questHelper; + _questRewardHelper = questRewardHelper; } // TODO public ItemEventRouterResponse CompleteQuest(PmcData pmcData, CompleteQuestRequestData info, string sessionId) diff --git a/Core/Helpers/QuestHelper.cs b/Core/Helpers/QuestHelper.cs index e234181e..2e7b85e4 100644 --- a/Core/Helpers/QuestHelper.cs +++ b/Core/Helpers/QuestHelper.cs @@ -1,7 +1,6 @@ using Core.Annotations; using Core.Models.Eft.Common; using Core.Models.Eft.Common.Tables; -using Core.Models.Eft.Hideout; using Core.Models.Eft.ItemEvent; using Core.Models.Eft.Quests; using Core.Models.Enums; @@ -9,7 +8,9 @@ using Core.Models.Spt.Config; using Core.Servers; using Core.Services; using Core.Utils; +using Core.Utils.Cloners; using ILogger = Core.Models.Utils.ILogger; +using Product = Core.Models.Eft.ItemEvent.Product; namespace Core.Helpers; @@ -22,6 +23,8 @@ public class QuestHelper private readonly QuestConditionHelper _questConditionHelper; private readonly ProfileHelper _profileHelper; private readonly LocalisationService _localisationService; + private readonly LocaleService _localeService; + private readonly ICloner _cloner; private readonly QuestConfig _questConfig; public QuestHelper( @@ -31,7 +34,9 @@ public class QuestHelper QuestConditionHelper questConditionHelper, ProfileHelper profileHelper, LocalisationService localisationService, - ConfigServer configServer) + LocaleService localeService, + ConfigServer configServer, + ICloner Cloner) { _logger = logger; _timeUtil = timeUtil; @@ -39,6 +44,8 @@ public class QuestHelper _questConditionHelper = questConditionHelper; _profileHelper = profileHelper; _localisationService = localisationService; + _localeService = localeService; + _cloner = Cloner; _questConfig = configServer.GetConfig(ConfigTypes.QUEST); } @@ -49,9 +56,11 @@ public class QuestHelper /// Profile to search /// Quest id to look up /// QuestStatus enum - public QuestStatus GetQuestStatus(PmcData pmcData, string questId) + public QuestStatusEnum GetQuestStatus(PmcData pmcData, string questId) { - throw new System.NotImplementedException(); + var quest = pmcData.Quests?.FirstOrDefault((q) => q.QId == questId); + + return quest?.Status ?? QuestStatusEnum.Locked; } /// @@ -117,7 +126,8 @@ public class QuestHelper /// public string GetQuestNameFromLocale(string questId) { - throw new System.NotImplementedException(); + var questNameKey = $"{ questId} name"; + return _localeService.GetLocaleDb().GetValueOrDefault(questNameKey, "UNKNOWN"); } /// @@ -144,38 +154,26 @@ public class QuestHelper protected bool CompareAvailableForValues(int current, int required, string compareMethod) { - throw new NotImplementedException(); - } + switch (compareMethod) + { + case ">=": + return current >= required; + case ">": + return current > required; + case "<=": + return current <= required; + case "<": + return current < required; + case "!=": + return current != required; + case "==": + return current == required; - /** - * Take reward item from quest and set FiR status + fix stack sizes + fix mod Ids - * @param questReward Reward item to fix - * @returns Fixed rewards - */ - protected List ProcessReward(QuestReward questReward) - { - throw new NotImplementedException(); - } + default: + _logger.Error(_localisationService.GetText("quest-compare_operator_unhandled", compareMethod)); - /** - * Add missing mod items to a quest armor reward - * @param originalRewardRootItem Original armor reward item from QuestReward.items object - * @param questReward Armor reward from quest - */ - protected void GenerateArmorRewardChildSlots(Item originalRewardRootItem, QuestReward questReward) - { - throw new NotImplementedException(); - } - - /** - * Gets a flat list of reward items for the given quest at a specific state for the specified game version (e.g. Fail/Success) - * @param quest quest to get rewards for - * @param status Quest status that holds the items (Started, Success, Fail) - * @returns List of items with the correct maxStack - */ - public List GetQuestRewardItems(Quest quest, QuestStatus status, string gameVersion) - { - throw new NotImplementedException(); + return false; + } } /** @@ -258,7 +256,14 @@ public class QuestHelper */ protected bool QuestIsProfileWhitelisted(string gameVersion, string questId) { - throw new NotImplementedException(); + var questBlacklist = _questConfig.ProfileBlacklist.GetValueOrDefault(gameVersion); + if (questBlacklist is null) + { + // Not blacklisted + return false; + } + + return questBlacklist.Contains(questId); } /** @@ -272,18 +277,6 @@ public class QuestHelper throw new NotImplementedException(); } - /** - * Adjust quest money rewards by passed in multiplier - * @param quest Quest to multiple money rewards - * @param bonusPercent Percent to adjust money rewards by - * @param questStatus Status of quest to apply money boost to rewards of - * @returns Updated quest - */ - public Quest ApplyMoneyBoost(Quest quest, double bonusPercent, QuestStatus questStatus) - { - throw new NotImplementedException(); - } - /** * Sets the item stack to new value, or delete the item if value <= 0 * // TODO maybe merge this function and the one from customization @@ -314,7 +307,14 @@ public class QuestHelper string sessionId, Item item) { - throw new NotImplementedException(); + output.ProfileChanges[sessionId].Items.ChangedItems.Add( new Product{ + Id = item.Id, + Template = item.Template, + ParentId = item.ParentId, + SlotId = item.SlotId, + Location = (ItemLocation)item.Location, + Upd = new Upd { StackObjectsCount = item.Upd.StackObjectsCount }, + }); } /** @@ -324,7 +324,7 @@ public class QuestHelper */ protected List GetQuestsWithOnlyLevelRequirementStartCondition(List quests) { - throw new NotImplementedException(); + return quests.Select(GetQuestWithOnlyLevelRequirementStartCondition).ToList(); } /** @@ -334,7 +334,11 @@ public class QuestHelper */ public Quest GetQuestWithOnlyLevelRequirementStartCondition(Quest quest) { - throw new NotImplementedException(); + var updatedQuest = _cloner.Clone(quest); + updatedQuest.Conditions.AvailableForStart = updatedQuest.Conditions.AvailableForStart.Where( + (q) => q.ConditionType == "Level").ToList(); + + return updatedQuest; } /** @@ -367,7 +371,7 @@ public class QuestHelper * Get quest by id from database (repeatables are stored in profile, check there if questId not found) * @param questId Id of quest to find * @param pmcData Player profile - * @returns Quest object + * @returns IQuest object */ public Quest GetQuestFromDb(string questId, PmcData pmcData) { @@ -382,7 +386,19 @@ public class QuestHelper /// message id public string GetMessageIdForQuestStart(string startedMessageTextId, string questDescriptionId) { - throw new NotImplementedException(); + // Blank or is a guid, use description instead + var startedMessageText = GetQuestLocaleIdFromDb(startedMessageTextId); + if ( + startedMessageText is null || + startedMessageText.Trim() == "" || + startedMessageText.ToLower() == "test" || + startedMessageText.Length == 24 + ) + { + return questDescriptionId; + } + + return startedMessageTextId; } /// @@ -392,7 +408,8 @@ public class QuestHelper /// Locale Id from locale db public string GetQuestLocaleIdFromDb(string questMessageId) { - throw new NotImplementedException(); + var locale = _localeService.GetLocaleDb(); + return locale.GetValueOrDefault(questMessageId, null); } /// @@ -401,9 +418,15 @@ public class QuestHelper /// Profile to update /// New state the quest should be in /// Id of the quest to alter the status of - public void UpdateQuestState(PmcData pmcData, QuestStatus newQuestState, string questId) + public void UpdateQuestState(PmcData pmcData, QuestStatusEnum newQuestState, string questId) { - throw new NotImplementedException(); + // Find quest in profile, update status to desired status + var questToUpdate = pmcData.Quests.FirstOrDefault((quest) => quest.QId == questId); + if (questToUpdate is not null) + { + questToUpdate.Status = newQuestState; + questToUpdate.StatusTimers[newQuestState] = _timeUtil.GetTimeStamp(); + } } /// @@ -417,67 +440,6 @@ public class QuestHelper throw new NotImplementedException(); } - /// - /// Give player quest rewards - Skills/exp/trader standing/items/assort unlocks - Returns reward items player earned - /// - /// Player profile (scav or pmc) - /// questId of quest to get rewards for - /// State of the quest to get rewards for - /// Session id - /// Response to send back to client - /// Array of reward objects - public Item[] ApplyQuestReward(PmcData profileData, string questId, QuestStatusEnum state, string sessionId, ItemEventRouterResponse questResponse) - { - throw new NotImplementedException(); - } - - /// - /// Does the provided quest reward have a game version requirement to be given and does it match - /// - /// Reward to check - /// Version of game to check reward against - /// True if it has requirement, false if it doesnt pass check - protected bool QuestRewardIsForGameEdition(QuestReward reward, string gameVersion) - { - throw new NotImplementedException(); - } - - /// - /// WIP - Find hideout craft id and add to unlockedProductionRecipe array in player profile - /// also update client response recipeUnlocked array with craft id - /// - /// Player profile - /// Reward item from quest with craft unlock details - /// Quest with craft unlock reward - /// Session id - /// Response to send back to client - protected void FindAndAddHideoutProductionIdToProfile(PmcData pmcData, QuestReward craftUnlockReward, Quest questDetails, string sessionID, - ItemEventRouterResponse response) - { - throw new NotImplementedException(); - } - - /// - /// Find hideout craft for the specified quest reward - /// - /// Reward item from quest with craft unlock details - /// Quest with craft unlock reward - /// Hideout craft - public List GetRewardProductionMatch(QuestReward craftUnlockReward, Quest questDetails) - { - throw new NotImplementedException(); - } - - /// - /// Get players money reward bonus from profile - /// - /// player profile - /// bonus as a percent - protected double GetQuestMoneyRewardBonusMultiplier(PmcData pmcData) - { - throw new NotImplementedException(); - } - /** * Find quest with 'findItem' condition that needs the item tpl be handed in * @param itemTpl item tpl to look for @@ -543,7 +505,12 @@ public class QuestHelper public void FindAndRemoveQuestFromArrayIfExists(string questId, List quests) { - throw new NotImplementedException(); + var pmcQuestToReplaceStatus = quests.FirstOrDefault((quest) => quest.QId == questId); + if (pmcQuestToReplaceStatus is not null) + { + var index = quests.IndexOf(pmcQuestToReplaceStatus); + quests.RemoveAt(index); + } } /** diff --git a/Core/Helpers/QuestRewardHelper.cs b/Core/Helpers/QuestRewardHelper.cs new file mode 100644 index 00000000..ec8351f2 --- /dev/null +++ b/Core/Helpers/QuestRewardHelper.cs @@ -0,0 +1,175 @@ +using Core.Annotations; +using Core.Models.Eft.Common; +using Core.Models.Eft.Common.Tables; +using Core.Models.Eft.Hideout; +using Core.Models.Eft.ItemEvent; +using Core.Models.Enums; +using Core.Models.Spt.Config; +using Core.Servers; +using Core.Services; +using Core.Utils; +using ILogger = Core.Models.Utils.ILogger; + +namespace Core.Helpers; + +[Injectable] +public class QuestRewardHelper +{ + private readonly ILogger _logger; + private readonly HashUtil _hashUtil; + private readonly TimeUtil _timeUtil; + private readonly ItemHelper _itemHelper; + private readonly PaymentHelper _paymentHelper; + private readonly TraderHelper _traderHelper; + private readonly DatabaseService _databaseService; + private readonly QuestConditionHelper _questConditionHelper; + private readonly ProfileHelper _profileHelper; + private readonly PresetHelper _presetHelper; + private readonly LocalisationService _localisationService; + private readonly QuestConfig _questConfig; + + public QuestRewardHelper( + ILogger logger, + HashUtil hashUtil, + TimeUtil timeUtil, + ItemHelper itemHelper, + PaymentHelper paymentHelper, + TraderHelper traderHelper, + DatabaseService databaseService, + QuestConditionHelper questConditionHelper, + ProfileHelper profileHelper, + PresetHelper presetHelper, + LocalisationService localisationService, + ConfigServer configServer) + { + _logger = logger; + _hashUtil = hashUtil; + _timeUtil = timeUtil; + _itemHelper = itemHelper; + _paymentHelper = paymentHelper; + _traderHelper = traderHelper; + _databaseService = databaseService; + _questConditionHelper = questConditionHelper; + _profileHelper = profileHelper; + _presetHelper = presetHelper; + _localisationService = localisationService; + + _questConfig = configServer.GetConfig(ConfigTypes.QUEST); + } + + /** + * 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 + */ + public IEnumerable ApplyQuestReward(PmcData profileData, string questId, QuestStatusEnum state, string sessionId, ItemEventRouterResponse questResponse) + { + throw new System.NotImplementedException(); + } + + /** + * Does the provided quest reward have a game version requirement to be given and does it match + * @param reward Reward to check + * @param gameVersion Version of game to check reward against + * @returns True if it has requirement, false if it doesnt pass check + */ + public bool QuestRewardIsForGameEdition(RewardDetails reward, string gameVersion) + { + throw new System.NotImplementedException(); + } + + /** + * Get quest by id from database (repeatables are stored in profile, check there if questId not found) + * @param questId Id of quest to find + * @param pmcData Player profile + * @returns IQuest object + */ + protected Quest GetQuestFromDb(string questId, PmcData pmcData) + { + throw new NotImplementedException(); + } + + /// + /// Get players money reward bonus from profile + /// + /// player profile + /// bonus as a percent + protected double GetQuestMoneyRewardBonusMultiplier(PmcData pmcData) + { + throw new NotImplementedException(); + } + + /** + * Adjust quest money rewards by passed in multiplier + * @param quest Quest to multiple money rewards + * @param bonusPercent Percent to adjust money rewards by + * @param questStatus Status of quest to apply money boost to rewards of + * @returns Updated quest + */ + public Quest ApplyMoneyBoost(Quest quest, double bonusPercent, QuestStatus questStatus) + { + throw new NotImplementedException(); + } + + /// + /// WIP - Find hideout craft id and add to unlockedProductionRecipe array in player profile + /// also update client response recipeUnlocked array with craft id + /// + /// Player profile + /// Reward item from quest with craft unlock details + /// Quest with craft unlock reward + /// Session id + /// Response to send back to client + protected void FindAndAddHideoutProductionIdToProfile(PmcData pmcData, QuestReward craftUnlockReward, Quest questDetails, string sessionID, + ItemEventRouterResponse response) + { + throw new NotImplementedException(); + } + + /// + /// Find hideout craft for the specified quest reward + /// + /// Reward item from quest with craft unlock details + /// Quest with craft unlock reward + /// Hideout craft + public List GetRewardProductionMatch(QuestReward craftUnlockReward, Quest questDetails) + { + throw new NotImplementedException(); + } + + /** + * Gets a flat list of reward items for the given quest at a specific state for the specified game version (e.g. Fail/Success) + * @param quest quest to get rewards for + * @param status Quest status that holds the items (Started, Success, Fail) + * @returns List of items with the correct maxStack + */ + protected List GetQuestRewardItems(Quest quest, QuestStatus status, string gameVersion) + { + throw new NotImplementedException(); + } + + /** + * Take reward item from quest and set FiR status + fix stack sizes + fix mod Ids + * @param questReward Reward item to fix + * @returns Fixed rewards + */ + protected List ProcessReward(QuestReward questReward) + { + throw new NotImplementedException(); + } + + /** + * Add missing mod items to a quest armor reward + * @param originalRewardRootItem Original armor reward item from QuestReward.items object + * @param questReward Armor reward from quest + */ + protected void GenerateArmorRewardChildSlots(Item originalRewardRootItem, QuestReward questReward) + { + throw new NotImplementedException(); + } + +} diff --git a/Core/Models/Eft/Common/Tables/Item.cs b/Core/Models/Eft/Common/Tables/Item.cs index f4e885f5..d2eb2967 100644 --- a/Core/Models/Eft/Common/Tables/Item.cs +++ b/Core/Models/Eft/Common/Tables/Item.cs @@ -1,4 +1,4 @@ -using System.Text.Json.Serialization; +using System.Text.Json.Serialization; namespace Core.Models.Eft.Common.Tables; diff --git a/Core/Models/Eft/ItemEvent/ItemEventRouterBase.cs b/Core/Models/Eft/ItemEvent/ItemEventRouterBase.cs index b13de36e..6d81ffba 100644 --- a/Core/Models/Eft/ItemEvent/ItemEventRouterBase.cs +++ b/Core/Models/Eft/ItemEvent/ItemEventRouterBase.cs @@ -169,6 +169,9 @@ public class Product [JsonPropertyName("_id")] public string? Id { get; set; } + /// + /// _tpl + /// [JsonPropertyName("_tpl")] public string? Template { get; set; }