using SPTarkov.DI.Annotations; using SPTarkov.Server.Core.Extensions; using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Eft.Common.Tables; using SPTarkov.Server.Core.Models.Eft.Profile; using SPTarkov.Server.Core.Models.Enums; using SPTarkov.Server.Core.Models.Utils; using SPTarkov.Server.Core.Services; using SPTarkov.Server.Core.Utils; namespace SPTarkov.Server.Core.Helpers; [Injectable] public class PrestigeHelper( ISptLogger logger, TimeUtil timeUtil, DatabaseService databaseService, MailSendService mailSendService, ProfileHelper profileHelper, RewardHelper rewardHelper ) { public void ProcessPendingPrestige(SptProfile oldProfile, SptProfile newProfile, PendingPrestige prestige) { var prePrestigePmc = oldProfile.CharacterData?.PmcData; var sessionId = newProfile.ProfileInfo?.ProfileId; var prestigeLevels = databaseService.GetTemplates().Prestige?.Elements ?? []; var indexOfPrestigeObtained = Math.Clamp((prestige.PrestigeLevel ?? 1) - 1, 0, prestigeLevels.Count - 1); // Levels are 1 to 4, Index is 0 to 3 // Skill copy var skillProgressCopyAmount = (float)(1 - prestigeLevels[indexOfPrestigeObtained].TransferConfigs.SkillConfig.TransferMultiplier); var masteringProgressCopyAmount = (float)( 1 - prestigeLevels[indexOfPrestigeObtained].TransferConfigs.MasteringConfig.TransferMultiplier ); if (prePrestigePmc?.Skills?.Common is not null) { var commonSKillsToCopy = prePrestigePmc.Skills.Common; foreach (var skillToCopy in commonSKillsToCopy) { // Set progress for 5% of what it was, multiplied by prestige level skillToCopy.Progress *= skillProgressCopyAmount; var existingSkill = newProfile.CharacterData?.PmcData?.Skills?.Common.FirstOrDefault(skill => skill.Id == skillToCopy.Id); if (existingSkill is not null) { existingSkill.Progress = skillToCopy.Progress; } else { newProfile.CharacterData!.PmcData!.Skills!.Common = newProfile.CharacterData.PmcData.Skills.Common.Union([skillToCopy]); } } var masteringSkillsToCopy = prePrestigePmc.Skills.Mastering; foreach (var skillToCopy in masteringSkillsToCopy ?? []) { // Set progress 5% of what it was, multiplied by prestige level skillToCopy.Progress *= masteringProgressCopyAmount; var existingSkill = newProfile.CharacterData?.PmcData?.Skills?.Mastering?.FirstOrDefault(skill => skill.Id == skillToCopy.Id ); if (existingSkill is not null) { existingSkill.Progress = skillToCopy.Progress; } else { newProfile.CharacterData!.PmcData!.Skills!.Mastering = newProfile.CharacterData.PmcData.Skills.Mastering?.Union( [skillToCopy] ); } } } // Add "Prestigious" achievement var prestigiousAchievement = new MongoId("676091c0f457869a94017a23"); if (newProfile.CharacterData?.PmcData?.Achievements?.ContainsKey(prestigiousAchievement) is false) { rewardHelper.AddAchievementToProfile(newProfile, prestigiousAchievement); } // Assumes Prestige data is in descending order var currentPrestigeData = databaseService.GetTemplates().Prestige?.Elements[indexOfPrestigeObtained]; // Get all prestige rewards from prestige 1 up to desired prestige var prestigeRewards = prestigeLevels .Slice(0, indexOfPrestigeObtained + 1) // Index back to PrestigeLevel .SelectMany(prestigeInner => prestigeInner.Rewards); AddPrestigeRewardsToProfile(sessionId!.Value, newProfile, prestigeRewards); // Flag profile as having achieved this prestige level if (newProfile.CharacterData?.PmcData?.Prestige?.TryAdd(currentPrestigeData!.Id, timeUtil.GetTimeStamp()) is false) { logger.Error( $"Failed to add prestige element with id: {currentPrestigeData.Id} to new profile during processing of pending prestige." ); } var itemsToTransfer = new List(); // Copy transferred items foreach (var transferRequest in prestige.Items ?? []) { var item = prePrestigePmc?.Inventory?.Items?.FirstOrDefault(item => item.Id == transferRequest.Id); if (item is null) { logger.Error($"Unable to find item with id: {transferRequest.Id} in profile: {sessionId}, skipping"); continue; } itemsToTransfer.Add(item); } if (itemsToTransfer.Count > 0) { mailSendService.SendSystemMessageToPlayer( sessionId.Value, string.Empty, itemsToTransfer, timeUtil.GetHoursAsSeconds(8760) // Year ); } newProfile.CharacterData!.PmcData!.Info!.PrestigeLevel = prestige.PrestigeLevel; } private void AddPrestigeRewardsToProfile(MongoId sessionId, SptProfile newProfile, IEnumerable rewards) { var itemsToSend = new List(); foreach (var reward in rewards) { switch (reward.Type) { case RewardType.CustomizationDirect: { profileHelper.AddHideoutCustomisationUnlock(newProfile, reward, CustomisationSource.PRESTIGE); break; } case RewardType.Skill: if (Enum.TryParse(reward.Target, out SkillTypes result)) { profileHelper.AddSkillPointsToPlayer(newProfile.CharacterData!.PmcData!, result, reward.Value.GetValueOrDefault(0)); } else { logger.Error($"Unable to parse reward Target to Enum: {reward.Target}"); } break; case RewardType.Item: { itemsToSend.AddRange(reward.Items ?? []); break; } case RewardType.ExtraDailyQuest: { newProfile.AddExtraRepeatableQuest(new MongoId(reward.Target), (double)reward.Value!); break; } default: logger.Error($"Unhandled prestige reward type: {reward.Type} Id: {reward.Id}"); break; } } if (itemsToSend.Count > 0) { mailSendService.SendSystemMessageToPlayer(sessionId, string.Empty, itemsToSend, 31536000); } } }