.NET Format Style Fixes
This commit is contained in:
@@ -23,10 +23,7 @@ public class AchievementController(
|
||||
/// <returns></returns>
|
||||
public virtual GetAchievementsResponse GetAchievements(string sessionID)
|
||||
{
|
||||
return new GetAchievementsResponse
|
||||
{
|
||||
Elements = databaseService.GetAchievements()
|
||||
};
|
||||
return new GetAchievementsResponse { Elements = databaseService.GetAchievements() };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -37,12 +34,21 @@ public class AchievementController(
|
||||
public virtual CompletedAchievementsResponse GetAchievementStatics(string sessionId)
|
||||
{
|
||||
var stats = new Dictionary<string, int>();
|
||||
var profiles = profileHelper.GetProfiles()
|
||||
.Where(kvp => !coreConfig.Features.AchievementProfileIdBlacklist.Contains(kvp.Value.ProfileInfo.ProfileId))
|
||||
var profiles = profileHelper
|
||||
.GetProfiles()
|
||||
.Where(kvp =>
|
||||
!coreConfig.Features.AchievementProfileIdBlacklist.Contains(
|
||||
kvp.Value.ProfileInfo.ProfileId
|
||||
)
|
||||
)
|
||||
.ToDictionary();
|
||||
|
||||
var achievements = databaseService.GetAchievements();
|
||||
foreach (var achievementId in achievements.Select(achievement => achievement.Id).Where(achievementId => !string.IsNullOrEmpty(achievementId)))
|
||||
foreach (
|
||||
var achievementId in achievements
|
||||
.Select(achievement => achievement.Id)
|
||||
.Where(achievementId => !string.IsNullOrEmpty(achievementId))
|
||||
)
|
||||
{
|
||||
var profilesHaveAchievement = 0;
|
||||
foreach (var (profileId, profile) in profiles)
|
||||
@@ -63,15 +69,13 @@ public class AchievementController(
|
||||
var percentage = 0;
|
||||
if (profiles.Count > 0)
|
||||
{
|
||||
percentage = (int)Math.Round((double)profilesHaveAchievement / profiles.Count * 100);
|
||||
percentage = (int)
|
||||
Math.Round((double)profilesHaveAchievement / profiles.Count * 100);
|
||||
}
|
||||
|
||||
stats.Add(achievementId, percentage);
|
||||
}
|
||||
|
||||
return new CompletedAchievementsResponse
|
||||
{
|
||||
Elements = stats
|
||||
};
|
||||
return new CompletedAchievementsResponse { Elements = stats };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text.Json.Serialization;
|
||||
using SPTarkov.Server.Core.Constants;
|
||||
using SPTarkov.DI.Annotations;
|
||||
using SPTarkov.Server.Core.Constants;
|
||||
using SPTarkov.Server.Core.Generators;
|
||||
using SPTarkov.Server.Core.Helpers;
|
||||
using SPTarkov.Server.Core.Models.Common;
|
||||
@@ -50,7 +50,9 @@ public class BotController(
|
||||
{
|
||||
if (!_botConfig.PresetBatch.TryGetValue(type, out var limit))
|
||||
{
|
||||
_logger.Warning(_localisationService.GetText("bot-bot_preset_count_value_missing", type));
|
||||
_logger.Warning(
|
||||
_localisationService.GetText("bot-bot_preset_count_value_missing", type)
|
||||
);
|
||||
|
||||
return 10;
|
||||
}
|
||||
@@ -78,23 +80,38 @@ public class BotController(
|
||||
/// <param name="raidConfig">OPTIONAL - applicationContext Data stored at start of raid</param>
|
||||
/// <param name="ignoreRaidSettings">OPTIONAL - should raid settings chosen pre-raid be ignored</param>
|
||||
/// <returns>Difficulty object</returns>
|
||||
public DifficultyCategories GetBotDifficulty(string sessionId, string type, string diffLevel, bool ignoreRaidSettings = false)
|
||||
public DifficultyCategories GetBotDifficulty(
|
||||
string sessionId,
|
||||
string type,
|
||||
string diffLevel,
|
||||
bool ignoreRaidSettings = false
|
||||
)
|
||||
{
|
||||
var difficulty = diffLevel.ToLower();
|
||||
|
||||
var raidConfig = _profileActivityService.GetProfileActivityRaidData(sessionId)?.RaidConfiguration;
|
||||
var raidConfig = _profileActivityService
|
||||
.GetProfileActivityRaidData(sessionId)
|
||||
?.RaidConfiguration;
|
||||
|
||||
if (!(raidConfig != null || ignoreRaidSettings))
|
||||
{
|
||||
_logger.Error(_localisationService.GetText("bot-missing_application_context", "RAID_CONFIGURATION"));
|
||||
_logger.Error(
|
||||
_localisationService.GetText(
|
||||
"bot-missing_application_context",
|
||||
"RAID_CONFIGURATION"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Check value chosen in pre-raid difficulty dropdown
|
||||
// If value is not 'asonline', change requested difficulty to be what was chosen in dropdown
|
||||
var botDifficultyDropDownValue = raidConfig?.WavesSettings?.BotDifficulty?.ToString().ToLower() ?? "asonline";
|
||||
var botDifficultyDropDownValue =
|
||||
raidConfig?.WavesSettings?.BotDifficulty?.ToString().ToLower() ?? "asonline";
|
||||
if (botDifficultyDropDownValue != "asonline")
|
||||
{
|
||||
difficulty = _botDifficultyHelper.ConvertBotDifficultyDropdownToBotDifficulty(botDifficultyDropDownValue);
|
||||
difficulty = _botDifficultyHelper.ConvertBotDifficultyDropdownToBotDifficulty(
|
||||
botDifficultyDropDownValue
|
||||
);
|
||||
}
|
||||
|
||||
var botDb = _databaseService.GetBots();
|
||||
@@ -130,7 +147,9 @@ public class BotController(
|
||||
result[botTypeLower] = result[Roles.Assault];
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Unable to find bot: {botTypeLower} in db, copying '{Roles.Assault}'");
|
||||
_logger.Debug(
|
||||
$"Unable to find bot: {botTypeLower} in db, copying '{Roles.Assault}'"
|
||||
);
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -139,7 +158,9 @@ public class BotController(
|
||||
if (botDetails?.BotDifficulty is null)
|
||||
{
|
||||
// Bot has no difficulty values, skip
|
||||
_logger.Warning($"Unable to find bot: {botTypeLower} difficulty values in db, skipping");
|
||||
_logger.Warning(
|
||||
$"Unable to find bot: {botTypeLower} difficulty values in db, skipping"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -153,7 +174,11 @@ public class BotController(
|
||||
}
|
||||
|
||||
// Store all difficulty values in dict keyed by difficulty type e.g. easy/normal/impossible
|
||||
result[botNameKey].Add(difficultyName, GetBotDifficulty(string.Empty, botNameKey, difficultyName, true));
|
||||
result[botNameKey]
|
||||
.Add(
|
||||
difficultyName,
|
||||
GetBotDifficulty(string.Empty, botNameKey, difficultyName, true)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +205,11 @@ public class BotController(
|
||||
/// <param name="pmcProfile">Player generating bots</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns>List of generated bots</returns>
|
||||
protected List<BotBase> GenerateBotWaves(GenerateBotsRequestData request, PmcData? pmcProfile, string sessionId)
|
||||
protected List<BotBase> GenerateBotWaves(
|
||||
GenerateBotsRequestData request,
|
||||
PmcData? pmcProfile,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var generatedBotList = new List<BotBase>();
|
||||
var raidSettings = GetMostRecentRaidSettings(sessionId);
|
||||
@@ -191,23 +220,36 @@ public class BotController(
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
// Map conditions to promises for bot generation
|
||||
|
||||
Task.WaitAll((request.Conditions ?? [])
|
||||
.Select(condition => Task.Factory.StartNew(() =>
|
||||
{
|
||||
var botWaveGenerationDetails = GetBotGenerationDetailsForWave(
|
||||
condition,
|
||||
pmcProfile,
|
||||
allPmcsHaveSameNameAsPlayer,
|
||||
raidSettings);
|
||||
Task.WaitAll(
|
||||
(request.Conditions ?? [])
|
||||
.Select(condition =>
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
var botWaveGenerationDetails = GetBotGenerationDetailsForWave(
|
||||
condition,
|
||||
pmcProfile,
|
||||
allPmcsHaveSameNameAsPlayer,
|
||||
raidSettings
|
||||
);
|
||||
|
||||
GenerateBotWave(condition, botWaveGenerationDetails, generatedBotList, sessionId);
|
||||
})).ToArray());
|
||||
GenerateBotWave(
|
||||
condition,
|
||||
botWaveGenerationDetails,
|
||||
generatedBotList,
|
||||
sessionId
|
||||
);
|
||||
})
|
||||
)
|
||||
.ToArray()
|
||||
);
|
||||
|
||||
stopwatch.Stop();
|
||||
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Took {stopwatch.ElapsedMilliseconds}ms to GenerateMultipleBotsAndCache()");
|
||||
_logger.Debug(
|
||||
$"Took {stopwatch.ElapsedMilliseconds}ms to GenerateMultipleBotsAndCache()"
|
||||
);
|
||||
}
|
||||
|
||||
return generatedBotList;
|
||||
@@ -225,9 +267,13 @@ public class BotController(
|
||||
GenerateCondition generateRequest,
|
||||
BotGenerationDetails botGenerationDetails,
|
||||
List<BotBase> botList,
|
||||
string sessionId)
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var isEventBot = generateRequest.Role?.Contains("event", StringComparison.OrdinalIgnoreCase);
|
||||
var isEventBot = generateRequest.Role?.Contains(
|
||||
"event",
|
||||
StringComparison.OrdinalIgnoreCase
|
||||
);
|
||||
if (isEventBot.GetValueOrDefault(false))
|
||||
{
|
||||
// Add eventRole data + reassign role property to be base type
|
||||
@@ -241,45 +287,55 @@ public class BotController(
|
||||
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Generating wave of: {botGenerationDetails.BotCountToGenerate} bots of type: {role} {botGenerationDetails.BotDifficulty}");
|
||||
_logger.Debug(
|
||||
$"Generating wave of: {botGenerationDetails.BotCountToGenerate} bots of type: {role} {botGenerationDetails.BotDifficulty}"
|
||||
);
|
||||
}
|
||||
|
||||
Parallel.For(0, botGenerationDetails.BotCountToGenerate.Value, (i) =>
|
||||
{
|
||||
BotBase bot = null;
|
||||
|
||||
try
|
||||
Parallel.For(
|
||||
0,
|
||||
botGenerationDetails.BotCountToGenerate.Value,
|
||||
(i) =>
|
||||
{
|
||||
bot = _botGenerator.PrepareAndGenerateBot(sessionId, _cloner.Clone(botGenerationDetails));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(
|
||||
$"Failed to generate bot: {botGenerationDetails.Role} #{i + 1}: {e.Message} {e.StackTrace}");
|
||||
return;
|
||||
}
|
||||
BotBase bot = null;
|
||||
|
||||
// The client expects the Side for PMCs to be `Savage`
|
||||
// We do this here so it's after we cache the bot in the match details lookup, as when you die, they will have the right side
|
||||
if (bot.Info.Side is Sides.Bear or Sides.Usec)
|
||||
{
|
||||
bot.Info.Side = Sides.Savage;
|
||||
}
|
||||
try
|
||||
{
|
||||
bot = _botGenerator.PrepareAndGenerateBot(
|
||||
sessionId,
|
||||
_cloner.Clone(botGenerationDetails)
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(
|
||||
$"Failed to generate bot: {botGenerationDetails.Role} #{i + 1}: {e.Message} {e.StackTrace}"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_botListLock)
|
||||
{
|
||||
botList.Add(bot);
|
||||
}
|
||||
// The client expects the Side for PMCs to be `Savage`
|
||||
// We do this here so it's after we cache the bot in the match details lookup, as when you die, they will have the right side
|
||||
if (bot.Info.Side is Sides.Bear or Sides.Usec)
|
||||
{
|
||||
bot.Info.Side = Sides.Savage;
|
||||
}
|
||||
|
||||
// Store bot details in cache so post-raid PMC messages can use data
|
||||
_matchBotDetailsCacheService.CacheBot(bot);
|
||||
});
|
||||
lock (_botListLock)
|
||||
{
|
||||
botList.Add(bot);
|
||||
}
|
||||
|
||||
// Store bot details in cache so post-raid PMC messages can use data
|
||||
_matchBotDetailsCacheService.CacheBot(bot);
|
||||
}
|
||||
);
|
||||
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug(
|
||||
$"Generated: {botGenerationDetails.BotCountToGenerate} {botGenerationDetails.Role}" +
|
||||
$"({botGenerationDetails.EventRole ?? botGenerationDetails.Role ?? ""}) {botGenerationDetails.BotDifficulty} bots"
|
||||
$"Generated: {botGenerationDetails.BotCountToGenerate} {botGenerationDetails.Role}"
|
||||
+ $"({botGenerationDetails.EventRole ?? botGenerationDetails.Role ?? ""}) {botGenerationDetails.BotDifficulty} bots"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -290,11 +346,15 @@ public class BotController(
|
||||
/// <returns>GetRaidConfigurationRequestData if it exists</returns>
|
||||
protected GetRaidConfigurationRequestData? GetMostRecentRaidSettings(string sessionId)
|
||||
{
|
||||
var raidConfiguration = _profileActivityService.GetProfileActivityRaidData(sessionId)?.RaidConfiguration;
|
||||
var raidConfiguration = _profileActivityService
|
||||
.GetProfileActivityRaidData(sessionId)
|
||||
?.RaidConfiguration;
|
||||
|
||||
if (raidConfiguration is null)
|
||||
{
|
||||
_logger.Warning(_localisationService.GetText("bot-unable_to_load_raid_settings_from_appcontext"));
|
||||
_logger.Warning(
|
||||
_localisationService.GetText("bot-unable_to_load_raid_settings_from_appcontext")
|
||||
);
|
||||
}
|
||||
|
||||
return raidConfiguration;
|
||||
@@ -307,7 +367,10 @@ public class BotController(
|
||||
/// <returns>MinMax values</returns>
|
||||
protected MinMax<int> GetPmcLevelRangeForMap(string? location)
|
||||
{
|
||||
return _pmcConfig.LocationSpecificPmcLevelOverride!.GetValueOrDefault(location?.ToLower() ?? "", null);
|
||||
return _pmcConfig.LocationSpecificPmcLevelOverride!.GetValueOrDefault(
|
||||
location?.ToLower() ?? "",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -322,24 +385,30 @@ public class BotController(
|
||||
GenerateCondition condition,
|
||||
PmcData? pmcProfile,
|
||||
bool allPmcsHaveSameNameAsPlayer,
|
||||
GetRaidConfigurationRequestData? raidSettings)
|
||||
GetRaidConfigurationRequestData? raidSettings
|
||||
)
|
||||
{
|
||||
var generateAsPmc = _botHelper.IsBotPmc(condition.Role);
|
||||
|
||||
return new BotGenerationDetails
|
||||
{
|
||||
IsPmc = generateAsPmc,
|
||||
Side = generateAsPmc ? _botHelper.GetPmcSideByRole(condition.Role ?? string.Empty) : "Savage",
|
||||
Side = generateAsPmc
|
||||
? _botHelper.GetPmcSideByRole(condition.Role ?? string.Empty)
|
||||
: "Savage",
|
||||
Role = condition.Role,
|
||||
PlayerLevel = pmcProfile?.Info?.Level ?? 1,
|
||||
PlayerName = pmcProfile?.Info?.Nickname,
|
||||
BotRelativeLevelDeltaMax = _pmcConfig.BotRelativeLevelDeltaMax,
|
||||
BotRelativeLevelDeltaMin = _pmcConfig.BotRelativeLevelDeltaMin,
|
||||
BotCountToGenerate = Math.Max(GetBotPresetGenerationLimit(condition.Role), condition.Limit), // Choose largest between value passed in from request vs what's in bot.config
|
||||
BotCountToGenerate = Math.Max(
|
||||
GetBotPresetGenerationLimit(condition.Role),
|
||||
condition.Limit
|
||||
), // Choose largest between value passed in from request vs what's in bot.config
|
||||
BotDifficulty = condition.Difficulty,
|
||||
LocationSpecificPmcLevelOverride = GetPmcLevelRangeForMap(raidSettings?.Location), // Min/max levels for PMCs to generate within
|
||||
IsPlayerScav = false,
|
||||
AllPmcsHaveSameNameAsPlayer = allPmcsHaveSameNameAsPlayer
|
||||
AllPmcsHaveSameNameAsPlayer = allPmcsHaveSameNameAsPlayer,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -359,7 +428,10 @@ public class BotController(
|
||||
if (location == "default")
|
||||
{
|
||||
_logger.Warning(
|
||||
_localisationService.GetText("bot-no_bot_cap_found_for_location", location.ToLower())
|
||||
_localisationService.GetText(
|
||||
"bot-no_bot_cap_found_for_location",
|
||||
location.ToLower()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -376,7 +448,7 @@ public class BotController(
|
||||
{
|
||||
PmcType = _pmcConfig.PmcType,
|
||||
Assault = _botConfig.AssaultBrainType,
|
||||
PlayerScav = _botConfig.PlayerScavBrainType
|
||||
PlayerScav = _botConfig.PlayerScavBrainType,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -384,23 +456,11 @@ public class BotController(
|
||||
public record AiBotBrainTypes
|
||||
{
|
||||
[JsonPropertyName("pmc")]
|
||||
public Dictionary<string, Dictionary<string, Dictionary<string, double>>> PmcType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Dictionary<string, Dictionary<string, Dictionary<string, double>>> PmcType { get; set; }
|
||||
|
||||
[JsonPropertyName("assault")]
|
||||
public Dictionary<string, Dictionary<string, int>> Assault
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Dictionary<string, Dictionary<string, int>> Assault { get; set; }
|
||||
|
||||
[JsonPropertyName("playerScav")]
|
||||
public Dictionary<string, Dictionary<string, int>> PlayerScav
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Dictionary<string, Dictionary<string, int>> PlayerScav { get; set; }
|
||||
}
|
||||
|
||||
@@ -42,30 +42,37 @@ public class BuildController(
|
||||
{
|
||||
EquipmentBuilds = [],
|
||||
WeaponBuilds = [],
|
||||
MagazineBuilds = []
|
||||
MagazineBuilds = [],
|
||||
};
|
||||
}
|
||||
|
||||
// Ensure the secure container in the default presets match what the player has equipped
|
||||
var defaultEquipmentPresetsClone = _cloner.Clone(_databaseService.GetTemplates().DefaultEquipmentPresets)
|
||||
var defaultEquipmentPresetsClone = _cloner
|
||||
.Clone(_databaseService.GetTemplates().DefaultEquipmentPresets)
|
||||
.ToList();
|
||||
|
||||
// Get players secure container
|
||||
var playerSecureContainer = profile?.CharacterData?.PmcData?.Inventory?.Items?.FirstOrDefault(x => x.SlotId == secureContainerSlotId
|
||||
);
|
||||
var playerSecureContainer =
|
||||
profile?.CharacterData?.PmcData?.Inventory?.Items?.FirstOrDefault(x =>
|
||||
x.SlotId == secureContainerSlotId
|
||||
);
|
||||
|
||||
var firstDefaultItemsSecureContainer = defaultEquipmentPresetsClone?
|
||||
.FirstOrDefault()
|
||||
?.Items?
|
||||
.FirstOrDefault(x => x.SlotId == secureContainerSlotId);
|
||||
var firstDefaultItemsSecureContainer = defaultEquipmentPresetsClone
|
||||
?.FirstOrDefault()
|
||||
?.Items?.FirstOrDefault(x => x.SlotId == secureContainerSlotId);
|
||||
|
||||
if (playerSecureContainer is not null && playerSecureContainer.Template != firstDefaultItemsSecureContainer?.Template)
|
||||
// Default equipment presets' secure container tpl doesn't match players secure container tpl
|
||||
if (
|
||||
playerSecureContainer is not null
|
||||
&& playerSecureContainer.Template != firstDefaultItemsSecureContainer?.Template
|
||||
)
|
||||
// Default equipment presets' secure container tpl doesn't match players secure container tpl
|
||||
{
|
||||
foreach (var defaultPreset in defaultEquipmentPresetsClone)
|
||||
{
|
||||
// Find presets secure container
|
||||
var secureContainer = defaultPreset.Items?.FirstOrDefault(item => item.SlotId == secureContainerSlotId);
|
||||
var secureContainer = defaultPreset.Items?.FirstOrDefault(item =>
|
||||
item.SlotId == secureContainerSlotId
|
||||
);
|
||||
if (secureContainer is not null)
|
||||
{
|
||||
secureContainer.Template = playerSecureContainer.Template;
|
||||
@@ -102,7 +109,7 @@ public class BuildController(
|
||||
Id = body.Id,
|
||||
Name = body.Name,
|
||||
Root = body.Root,
|
||||
Items = body.Items
|
||||
Items = body.Items,
|
||||
};
|
||||
|
||||
var profile = _profileHelper.GetFullProfile(sessionId);
|
||||
@@ -132,8 +139,9 @@ public class BuildController(
|
||||
var profile = _profileHelper.GetFullProfile(sessionID);
|
||||
var pmcData = profile.CharacterData.PmcData;
|
||||
|
||||
var existingSavedEquipmentBuilds =
|
||||
_saveServer.GetProfile(sessionID).UserBuildData.EquipmentBuilds;
|
||||
var existingSavedEquipmentBuilds = _saveServer
|
||||
.GetProfile(sessionID)
|
||||
.UserBuildData.EquipmentBuilds;
|
||||
|
||||
// Replace duplicate ID's. The first item is the base item.
|
||||
// Root ID and the base item ID need to match.
|
||||
@@ -145,10 +153,11 @@ public class BuildController(
|
||||
Name = request.Name,
|
||||
BuildType = EquipmentBuildType.Custom,
|
||||
Root = request.Items[0].Id,
|
||||
Items = request.Items
|
||||
Items = request.Items,
|
||||
};
|
||||
|
||||
var existingBuild = existingSavedEquipmentBuilds?.FirstOrDefault(build => build.Name == request.Name || build.Id == request.Id
|
||||
var existingBuild = existingSavedEquipmentBuilds?.FirstOrDefault(build =>
|
||||
build.Name == request.Name || build.Id == request.Id
|
||||
);
|
||||
if (existingBuild is not null)
|
||||
{
|
||||
@@ -190,7 +199,7 @@ public class BuildController(
|
||||
Caliber = request.Caliber,
|
||||
TopCount = request.TopCount,
|
||||
BottomCount = request.BottomCount,
|
||||
Items = request.Items
|
||||
Items = request.Items,
|
||||
};
|
||||
|
||||
var profile = _profileHelper.GetFullProfile(sessionId);
|
||||
@@ -198,7 +207,9 @@ public class BuildController(
|
||||
profile.UserBuildData.MagazineBuilds ??= [];
|
||||
|
||||
// Check if template with desired name already exists and remove it
|
||||
var magazineBuildToRemove = profile.UserBuildData.MagazineBuilds.FirstOrDefault(item => item.Name == request.Name);
|
||||
var magazineBuildToRemove = profile.UserBuildData.MagazineBuilds.FirstOrDefault(item =>
|
||||
item.Name == request.Name
|
||||
);
|
||||
if (magazineBuildToRemove is not null)
|
||||
{
|
||||
profile.UserBuildData.MagazineBuilds.Remove(magazineBuildToRemove);
|
||||
@@ -222,7 +233,9 @@ public class BuildController(
|
||||
var magazineBuilds = profile.UserBuildData.MagazineBuilds;
|
||||
|
||||
// Check for id in weapon array first
|
||||
var matchingWeaponBuild = weaponBuilds.FirstOrDefault(weaponBuild => weaponBuild.Id == idToRemove);
|
||||
var matchingWeaponBuild = weaponBuilds.FirstOrDefault(weaponBuild =>
|
||||
weaponBuild.Id == idToRemove
|
||||
);
|
||||
if (matchingWeaponBuild is not null)
|
||||
{
|
||||
weaponBuilds.Remove(matchingWeaponBuild);
|
||||
@@ -231,7 +244,9 @@ public class BuildController(
|
||||
}
|
||||
|
||||
// Id not found in weapons, try equipment
|
||||
var matchingEquipmentBuild = equipmentBuilds.FirstOrDefault(equipmentBuild => equipmentBuild.Id == idToRemove);
|
||||
var matchingEquipmentBuild = equipmentBuilds.FirstOrDefault(equipmentBuild =>
|
||||
equipmentBuild.Id == idToRemove
|
||||
);
|
||||
if (matchingEquipmentBuild is not null)
|
||||
{
|
||||
equipmentBuilds.Remove(matchingEquipmentBuild);
|
||||
@@ -240,7 +255,9 @@ public class BuildController(
|
||||
}
|
||||
|
||||
// Id not found in weapons/equipment, try mags
|
||||
var matchingMagazineBuild = magazineBuilds.FirstOrDefault(magBuild => magBuild.Id == idToRemove);
|
||||
var matchingMagazineBuild = magazineBuilds.FirstOrDefault(magBuild =>
|
||||
magBuild.Id == idToRemove
|
||||
);
|
||||
if (matchingMagazineBuild is not null)
|
||||
{
|
||||
magazineBuilds.Remove(matchingMagazineBuild);
|
||||
|
||||
@@ -7,9 +7,7 @@ using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
|
||||
namespace SPTarkov.Server.Core.Controllers;
|
||||
|
||||
[Injectable]
|
||||
public class ClientLogController(
|
||||
ISptLogger<ClientLogController> _logger
|
||||
)
|
||||
public class ClientLogController(ISptLogger<ClientLogController> _logger)
|
||||
{
|
||||
/// <summary>
|
||||
/// Handle /singleplayer/log
|
||||
|
||||
@@ -44,16 +44,18 @@ public class CustomizationController(
|
||||
var suits = _databaseService.GetTrader(traderId).Suits;
|
||||
|
||||
var matchingSuits = suits?.Where(s => clothing.ContainsKey(s.SuiteId!)).ToList();
|
||||
matchingSuits = matchingSuits?.Where(s => clothing[s.SuiteId ?? string.Empty]
|
||||
?.Properties?.Side?
|
||||
.Contains(pmcData?.Info?.Side ?? string.Empty) ??
|
||||
false
|
||||
matchingSuits = matchingSuits
|
||||
?.Where(s =>
|
||||
clothing[s.SuiteId ?? string.Empty]
|
||||
?.Properties?.Side?.Contains(pmcData?.Info?.Side ?? string.Empty) ?? false
|
||||
)
|
||||
.ToList();
|
||||
|
||||
if (matchingSuits == null)
|
||||
{
|
||||
throw new Exception(_localisationService.GetText("customisation-unable_to_get_trader_suits", traderId));
|
||||
throw new Exception(
|
||||
_localisationService.GetText("customisation-unable_to_get_trader_suits", traderId)
|
||||
);
|
||||
}
|
||||
|
||||
return matchingSuits;
|
||||
@@ -70,7 +72,8 @@ public class CustomizationController(
|
||||
public ItemEventRouterResponse BuyCustomisation(
|
||||
PmcData pmcData,
|
||||
BuyClothingRequestData buyClothingRequest,
|
||||
string sessionId)
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionId);
|
||||
|
||||
@@ -78,7 +81,10 @@ public class CustomizationController(
|
||||
if (traderOffer is null)
|
||||
{
|
||||
_logger.Error(
|
||||
_localisationService.GetText("customisation-unable_to_find_suit_by_id", buyClothingRequest.Offer)
|
||||
_localisationService.GetText(
|
||||
"customisation-unable_to_find_suit_by_id",
|
||||
buyClothingRequest.Offer
|
||||
)
|
||||
);
|
||||
return output;
|
||||
}
|
||||
@@ -90,11 +96,7 @@ public class CustomizationController(
|
||||
_logger.Error(
|
||||
_localisationService.GetText(
|
||||
"customisation-item_already_purchased",
|
||||
new
|
||||
{
|
||||
itemId = suitDetails?.Id,
|
||||
itemName = suitDetails?.Name
|
||||
}
|
||||
new { itemId = suitDetails?.Id, itemName = suitDetails?.Name }
|
||||
)
|
||||
);
|
||||
|
||||
@@ -111,7 +113,7 @@ public class CustomizationController(
|
||||
{
|
||||
Id = suitId,
|
||||
Source = CustomisationSource.UNLOCKED_IN_GAME,
|
||||
Type = CustomisationType.SUITE
|
||||
Type = CustomisationType.SUITE,
|
||||
};
|
||||
|
||||
profile.CustomisationUnlocks.Add(rewardToStore);
|
||||
@@ -130,7 +132,9 @@ public class CustomizationController(
|
||||
var fullProfile = _profileHelper.GetFullProfile(sessionId);
|
||||
|
||||
// Check if clothing can be found by id
|
||||
return fullProfile.CustomisationUnlocks.Exists(customisation => Equals(customisation.Id, suitId));
|
||||
return fullProfile.CustomisationUnlocks.Exists(customisation =>
|
||||
Equals(customisation.Id, suitId)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -144,7 +148,9 @@ public class CustomizationController(
|
||||
var foundSuit = GetAllTraderSuits(sessionId).FirstOrDefault(s => s.Id == offerId);
|
||||
if (foundSuit is null)
|
||||
{
|
||||
_logger.Error(_localisationService.GetText("customisation-unable_to_find_suit_with_id", offerId));
|
||||
_logger.Error(
|
||||
_localisationService.GetText("customisation-unable_to_find_suit_with_id", offerId)
|
||||
);
|
||||
}
|
||||
|
||||
return foundSuit;
|
||||
@@ -157,9 +163,12 @@ public class CustomizationController(
|
||||
/// <param name="pmcData">Player profile</param>
|
||||
/// <param name="itemsToPayForClothingWith">Clothing purchased</param>
|
||||
/// <param name="output">Client response</param>
|
||||
protected void PayForClothingItems(string sessionId, PmcData pmcData,
|
||||
protected void PayForClothingItems(
|
||||
string sessionId,
|
||||
PmcData pmcData,
|
||||
List<PaymentItemForClothing>? itemsToPayForClothingWith,
|
||||
ItemEventRouterResponse output)
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
if (itemsToPayForClothingWith is null || itemsToPayForClothingWith.Count == 0)
|
||||
{
|
||||
@@ -175,15 +184,15 @@ public class CustomizationController(
|
||||
new IdWithCount
|
||||
{
|
||||
Count = inventoryItemToProcess.Count.Value,
|
||||
Id = inventoryItemToProcess.Id
|
||||
}
|
||||
Id = inventoryItemToProcess.Id,
|
||||
},
|
||||
],
|
||||
TransactionId = Traders.RAGMAN,
|
||||
Action = "BuyCustomization",
|
||||
Type = "",
|
||||
ItemId = "",
|
||||
Count = 0,
|
||||
SchemeId = 0
|
||||
SchemeId = 0,
|
||||
};
|
||||
|
||||
_paymentService.PayMoney(pmcData, options, sessionId, output);
|
||||
@@ -202,7 +211,10 @@ public class CustomizationController(
|
||||
|
||||
foreach (var trader in traders)
|
||||
{
|
||||
if (trader.Value.Base?.CustomizationSeller is not null && trader.Value.Base.CustomizationSeller.Value)
|
||||
if (
|
||||
trader.Value.Base?.CustomizationSeller is not null
|
||||
&& trader.Value.Base.CustomizationSeller.Value
|
||||
)
|
||||
{
|
||||
result.AddRange(GetTraderSuits(trader.Key, sessionId));
|
||||
}
|
||||
@@ -226,10 +238,11 @@ public class CustomizationController(
|
||||
/// </summary>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns></returns>
|
||||
public List<CustomisationStorage> GetCustomisationStorage(
|
||||
string sessionId)
|
||||
public List<CustomisationStorage> GetCustomisationStorage(string sessionId)
|
||||
{
|
||||
var customisationResultsClone = _cloner.Clone(_databaseService.GetTemplates().CustomisationStorage);
|
||||
var customisationResultsClone = _cloner.Clone(
|
||||
_databaseService.GetTemplates().CustomisationStorage
|
||||
);
|
||||
|
||||
var profile = _profileHelper.GetFullProfile(sessionId);
|
||||
if (profile is null)
|
||||
@@ -249,7 +262,11 @@ public class CustomizationController(
|
||||
/// <param name="request"></param>
|
||||
/// <param name="pmcData">Players PMC profile</param>
|
||||
/// <returns></returns>
|
||||
public ItemEventRouterResponse SetCustomisation(string sessionId, CustomizationSetRequest request, PmcData pmcData)
|
||||
public ItemEventRouterResponse SetCustomisation(
|
||||
string sessionId,
|
||||
CustomizationSetRequest request,
|
||||
PmcData pmcData
|
||||
)
|
||||
{
|
||||
foreach (var customisation in request.Customizations)
|
||||
{
|
||||
|
||||
@@ -37,13 +37,17 @@ public class DialogueController(
|
||||
{
|
||||
if (_dialogueChatBots.Any(cb => cb.GetChatBot().Id == chatBot.GetChatBot().Id))
|
||||
{
|
||||
_logger.Error(_localisationService.GetText("dialog-chatbot_id_already_exists", chatBot.GetChatBot().Id));
|
||||
_logger.Error(
|
||||
_localisationService.GetText(
|
||||
"dialog-chatbot_id_already_exists",
|
||||
chatBot.GetChatBot().Id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
_dialogueChatBots.Add(chatBot);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handle onUpdate spt event
|
||||
/// </summary>
|
||||
@@ -80,7 +84,7 @@ public class DialogueController(
|
||||
{
|
||||
Id = friendProfile.Id,
|
||||
Aid = friendProfile.Aid,
|
||||
Info = friendProfile.Info
|
||||
Info = friendProfile.Info,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -91,7 +95,7 @@ public class DialogueController(
|
||||
{
|
||||
Friends = friends,
|
||||
Ignore = [],
|
||||
InIgnoreList = []
|
||||
InIgnoreList = [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -144,9 +148,7 @@ public class DialogueController(
|
||||
/// <param name="dialogueId">Dialog id</param>
|
||||
/// <param name="sessionId">Session Id</param>
|
||||
/// <returns>DialogueInfo</returns>
|
||||
public virtual DialogueInfo? GetDialogueInfo(
|
||||
string? dialogueId,
|
||||
string sessionId)
|
||||
public virtual DialogueInfo? GetDialogueInfo(string? dialogueId, string sessionId)
|
||||
{
|
||||
var dialogs = _dialogueHelper.GetDialogsForProfile(sessionId);
|
||||
var dialogue = dialogs!.GetValueOrDefault(dialogueId);
|
||||
@@ -164,7 +166,7 @@ public class DialogueController(
|
||||
New = dialogue?.New,
|
||||
AttachmentsNew = dialogue?.AttachmentsNew,
|
||||
Pinned = dialogue?.Pinned,
|
||||
Users = GetDialogueUsers(dialogue, dialogue?.Type, sessionId)
|
||||
Users = GetDialogueUsers(dialogue, dialogue?.Type, sessionId),
|
||||
};
|
||||
|
||||
return result;
|
||||
@@ -180,14 +182,19 @@ public class DialogueController(
|
||||
public virtual List<UserDialogInfo> GetDialogueUsers(
|
||||
Dialogue? dialog,
|
||||
MessageType? messageType,
|
||||
string sessionId)
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var profile = _saveServer.GetProfile(sessionId);
|
||||
|
||||
// User to user messages are special in that they need the player to exist in them, add if they don't
|
||||
if (messageType == MessageType.UserMessage &&
|
||||
dialog?.Users is not null &&
|
||||
dialog.Users.All(userDialog => userDialog.Id != profile.CharacterData?.PmcData?.SessionId))
|
||||
if (
|
||||
messageType == MessageType.UserMessage
|
||||
&& dialog?.Users is not null
|
||||
&& dialog.Users.All(userDialog =>
|
||||
userDialog.Id != profile.CharacterData?.PmcData?.SessionId
|
||||
)
|
||||
)
|
||||
{
|
||||
dialog.Users.Add(
|
||||
new UserDialogInfo
|
||||
@@ -200,8 +207,12 @@ public class DialogueController(
|
||||
Nickname = profile.CharacterData?.PmcData?.Info?.Nickname,
|
||||
Side = profile.CharacterData?.PmcData?.Info?.Side,
|
||||
MemberCategory = profile.CharacterData?.PmcData?.Info?.MemberCategory,
|
||||
SelectedMemberCategory = profile.CharacterData?.PmcData?.Info?.SelectedMemberCategory
|
||||
}
|
||||
SelectedMemberCategory = profile
|
||||
.CharacterData
|
||||
?.PmcData
|
||||
?.Info
|
||||
?.SelectedMemberCategory,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -220,7 +231,8 @@ public class DialogueController(
|
||||
/// <returns>GetMailDialogViewResponseData object</returns>
|
||||
public virtual GetMailDialogViewResponseData GenerateDialogueView(
|
||||
GetMailDialogViewRequestData request,
|
||||
string sessionId)
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var dialogueId = request.DialogId;
|
||||
var fullProfile = _saveServer.GetProfile(sessionId);
|
||||
@@ -232,7 +244,7 @@ public class DialogueController(
|
||||
{
|
||||
Messages = [],
|
||||
Profiles = [],
|
||||
HasMessagesWithRewards = false
|
||||
HasMessagesWithRewards = false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -246,7 +258,7 @@ public class DialogueController(
|
||||
{
|
||||
Messages = dialogue.Messages,
|
||||
Profiles = GetProfilesForMail(fullProfile, dialogue.Users),
|
||||
HasMessagesWithRewards = MessagesHaveUncollectedRewards(dialogue.Messages!)
|
||||
HasMessagesWithRewards = MessagesHaveUncollectedRewards(dialogue.Messages!),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -258,11 +270,16 @@ public class DialogueController(
|
||||
/// <returns>Dialogue</returns>
|
||||
protected Dialogue GetDialogByIdFromProfile(
|
||||
SptProfile profile,
|
||||
GetMailDialogViewRequestData request)
|
||||
GetMailDialogViewRequestData request
|
||||
)
|
||||
{
|
||||
if (profile.DialogueRecords is null || profile.DialogueRecords.ContainsKey(request.DialogId!))
|
||||
if (
|
||||
profile.DialogueRecords is null
|
||||
|| profile.DialogueRecords.ContainsKey(request.DialogId!)
|
||||
)
|
||||
{
|
||||
return profile.DialogueRecords?[request.DialogId!] ?? throw new NullReferenceException();
|
||||
return profile.DialogueRecords?[request.DialogId!]
|
||||
?? throw new NullReferenceException();
|
||||
}
|
||||
|
||||
profile.DialogueRecords[request.DialogId!] = new Dialogue
|
||||
@@ -272,7 +289,7 @@ public class DialogueController(
|
||||
Pinned = false,
|
||||
Messages = [],
|
||||
New = 0,
|
||||
Type = request.Type
|
||||
Type = request.Type,
|
||||
};
|
||||
|
||||
if (request.Type != MessageType.UserMessage)
|
||||
@@ -282,7 +299,9 @@ public class DialogueController(
|
||||
|
||||
var dialogue = profile.DialogueRecords[request.DialogId!];
|
||||
dialogue.Users = [];
|
||||
var chatBot = _dialogueChatBots.FirstOrDefault(cb => cb.GetChatBot().Id == request.DialogId);
|
||||
var chatBot = _dialogueChatBots.FirstOrDefault(cb =>
|
||||
cb.GetChatBot().Id == request.DialogId
|
||||
);
|
||||
|
||||
if (chatBot is null)
|
||||
{
|
||||
@@ -301,11 +320,14 @@ public class DialogueController(
|
||||
/// <param name="fullProfile">Player profile</param>
|
||||
/// <param name="userDialogs">The participants of the mail</param>
|
||||
/// <returns>UserDialogInfo list</returns>
|
||||
protected List<UserDialogInfo> GetProfilesForMail(SptProfile fullProfile, List<UserDialogInfo>? userDialogs)
|
||||
protected List<UserDialogInfo> GetProfilesForMail(
|
||||
SptProfile fullProfile,
|
||||
List<UserDialogInfo>? userDialogs
|
||||
)
|
||||
{
|
||||
List<UserDialogInfo> result = [];
|
||||
if (userDialogs is null)
|
||||
// Nothing to add
|
||||
// Nothing to add
|
||||
{
|
||||
return result;
|
||||
}
|
||||
@@ -330,8 +352,8 @@ public class DialogueController(
|
||||
Side = pmcProfile?.Info?.Side,
|
||||
Level = pmcProfile?.Info?.Level,
|
||||
MemberCategory = pmcProfile?.Info?.MemberCategory,
|
||||
SelectedMemberCategory = pmcProfile?.Info?.SelectedMemberCategory
|
||||
}
|
||||
SelectedMemberCategory = pmcProfile?.Info?.SelectedMemberCategory,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -344,15 +366,16 @@ public class DialogueController(
|
||||
/// <param name="sessionId">Session id</param>
|
||||
/// <param name="dialogueId">Dialog id</param>
|
||||
/// <returns>Count of messages with attachments</returns>
|
||||
protected int GetUnreadMessagesWithAttachmentsCount(
|
||||
string sessionId,
|
||||
string dialogueId)
|
||||
protected int GetUnreadMessagesWithAttachmentsCount(string sessionId, string dialogueId)
|
||||
{
|
||||
var newAttachmentCount = 0;
|
||||
var activeMessages = GetActiveMessagesFromDialog(sessionId, dialogueId);
|
||||
foreach (var message in activeMessages)
|
||||
{
|
||||
if (message.HasRewards.GetValueOrDefault(false) && !message.RewardCollected.GetValueOrDefault(false))
|
||||
if (
|
||||
message.HasRewards.GetValueOrDefault(false)
|
||||
&& !message.RewardCollected.GetValueOrDefault(false)
|
||||
)
|
||||
{
|
||||
newAttachmentCount++;
|
||||
}
|
||||
@@ -372,11 +395,13 @@ public class DialogueController(
|
||||
var timeNow = _timeUtil.GetTimeStamp();
|
||||
var dialogs = _dialogueHelper.GetDialogsForProfile(sessionId);
|
||||
|
||||
return dialogs[dialogueId].Messages?.Where(message =>
|
||||
{
|
||||
var checkTime = message.DateTime + (message.MaxStorageTime ?? 0);
|
||||
return timeNow < checkTime;
|
||||
}).ToList() ?? [];
|
||||
return dialogs[dialogueId]
|
||||
.Messages?.Where(message =>
|
||||
{
|
||||
var checkTime = message.DateTime + (message.MaxStorageTime ?? 0);
|
||||
return timeNow < checkTime;
|
||||
})
|
||||
.ToList() ?? [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -395,9 +420,7 @@ public class DialogueController(
|
||||
/// </summary>
|
||||
/// <param name="dialogueId">id of the dialog to remove</param>
|
||||
/// <param name="sessionId">Player id</param>
|
||||
public virtual void RemoveDialogue(
|
||||
string? dialogueId,
|
||||
string sessionId)
|
||||
public virtual void RemoveDialogue(string? dialogueId, string sessionId)
|
||||
{
|
||||
var profile = _saveServer.GetProfile(sessionId);
|
||||
if (!profile.DialogueRecords.ContainsKey(dialogueId))
|
||||
@@ -405,11 +428,7 @@ public class DialogueController(
|
||||
_logger.Error(
|
||||
_localisationService.GetText(
|
||||
"dialogue-unable_to_find_in_profile",
|
||||
new
|
||||
{
|
||||
sessionId,
|
||||
dialogueId
|
||||
}
|
||||
new { sessionId, dialogueId }
|
||||
)
|
||||
);
|
||||
|
||||
@@ -433,11 +452,7 @@ public class DialogueController(
|
||||
_logger.Error(
|
||||
_localisationService.GetText(
|
||||
"dialogue-unable_to_find_in_profile",
|
||||
new
|
||||
{
|
||||
sessionId,
|
||||
dialogueId
|
||||
}
|
||||
new { sessionId, dialogueId }
|
||||
)
|
||||
);
|
||||
|
||||
@@ -461,10 +476,7 @@ public class DialogueController(
|
||||
_logger.Error(
|
||||
_localisationService.GetText(
|
||||
"dialogue-unable_to_find_dialogs_in_profile",
|
||||
new
|
||||
{
|
||||
sessionId
|
||||
}
|
||||
new { sessionId }
|
||||
)
|
||||
);
|
||||
|
||||
@@ -491,9 +503,7 @@ public class DialogueController(
|
||||
var dialog = dialogs.TryGetValue(dialogueId, out var dialogInfo);
|
||||
if (!dialog)
|
||||
{
|
||||
_logger.Error(
|
||||
_localisationService.GetText("dialogue-unable_to_find_in_profile")
|
||||
);
|
||||
_logger.Error(_localisationService.GetText("dialogue-unable_to_find_in_profile"));
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -508,7 +518,7 @@ public class DialogueController(
|
||||
{
|
||||
Messages = messagesWithAttachments,
|
||||
Profiles = [],
|
||||
HasMessagesWithRewards = MessagesHaveUncollectedRewards(messagesWithAttachments)
|
||||
HasMessagesWithRewards = MessagesHaveUncollectedRewards(messagesWithAttachments),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -518,18 +528,15 @@ public class DialogueController(
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public virtual string SendMessage(
|
||||
string sessionId,
|
||||
SendMessageRequest request)
|
||||
public virtual string SendMessage(string sessionId, SendMessageRequest request)
|
||||
{
|
||||
_mailSendService.SendPlayerMessageToNpc(sessionId, request.DialogId!, request.Text!);
|
||||
|
||||
return (_dialogueChatBots.FirstOrDefault(cb =>
|
||||
cb.GetChatBot().Id == request.DialogId
|
||||
)
|
||||
?.HandleMessage(sessionId, request) ??
|
||||
request.DialogId) ??
|
||||
string.Empty;
|
||||
return (
|
||||
_dialogueChatBots
|
||||
.FirstOrDefault(cb => cb.GetChatBot().Id == request.DialogId)
|
||||
?.HandleMessage(sessionId, request) ?? request.DialogId
|
||||
) ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -592,7 +599,10 @@ public class DialogueController(
|
||||
/// <param name="sessionID">Session/player id</param>
|
||||
/// <param name="request">Sent friend request</param>
|
||||
/// <returns></returns>
|
||||
public virtual FriendRequestSendResponse SendFriendRequest(string sessionID, FriendRequestData request)
|
||||
public virtual FriendRequestSendResponse SendFriendRequest(
|
||||
string sessionID,
|
||||
FriendRequestData request
|
||||
)
|
||||
{
|
||||
// To avoid needing to jump between profiles, auto-accept all friend requests
|
||||
var friendProfile = _profileHelper.GetFullProfile(request.To);
|
||||
@@ -602,7 +612,7 @@ public class DialogueController(
|
||||
{
|
||||
Status = BackendErrorCodes.PlayerProfileNotFound,
|
||||
RequestId = "", // Unused in an error state
|
||||
RetryAfter = 600
|
||||
RetryAfter = 600,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -620,7 +630,9 @@ public class DialogueController(
|
||||
var notification = new WsFriendsListAccept
|
||||
{
|
||||
EventType = NotificationEventType.friendListRequestAccept,
|
||||
Profile = _profileHelper.GetChatRoomMemberFromPmcProfile(friendProfile.CharacterData.PmcData)
|
||||
Profile = _profileHelper.GetChatRoomMemberFromPmcProfile(
|
||||
friendProfile.CharacterData.PmcData
|
||||
),
|
||||
};
|
||||
_notificationSendHelper.SendMessage(sessionID, notification);
|
||||
},
|
||||
@@ -633,7 +645,7 @@ public class DialogueController(
|
||||
{
|
||||
Status = BackendErrorCodes.None,
|
||||
RequestId = friendProfile.ProfileInfo.Aid.ToString(),
|
||||
RetryAfter = 600
|
||||
RetryAfter = 600,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -662,7 +674,9 @@ public class DialogueController(
|
||||
var profile = _saveServer.GetProfile(sessionId);
|
||||
if (!profile.DialogueRecords.TryGetValue(request.DialogId, out var dialogToClear))
|
||||
{
|
||||
_logger.Warning($"unable to clear messages from dialog: {request.DialogId} as it cannot be found in profile: {sessionId}");
|
||||
_logger.Warning(
|
||||
$"unable to clear messages from dialog: {request.DialogId} as it cannot be found in profile: {sessionId}"
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ using SPTarkov.Server.Core.Utils.Cloners;
|
||||
using SPTarkov.Server.Core.Utils.Json;
|
||||
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
|
||||
|
||||
|
||||
namespace SPTarkov.Server.Core.Controllers;
|
||||
|
||||
[Injectable]
|
||||
@@ -81,7 +80,7 @@ public class GameController(
|
||||
fullProfile.SptData ??= new Spt
|
||||
{
|
||||
//TODO: complete
|
||||
Version = "Replace_me"
|
||||
Version = "Replace_me",
|
||||
};
|
||||
fullProfile.SptData.Migrations ??= new Dictionary<string, long>();
|
||||
fullProfile.FriendProfileIds ??= [];
|
||||
@@ -91,8 +90,14 @@ public class GameController(
|
||||
return;
|
||||
}
|
||||
|
||||
fullProfile.CharacterData!.PmcData!.WishList ??= new DictionaryOrList<string, int>(new Dictionary<string, int>(), []);
|
||||
fullProfile.CharacterData.ScavData!.WishList ??= new DictionaryOrList<string, int>(new Dictionary<string, int>(), []);
|
||||
fullProfile.CharacterData!.PmcData!.WishList ??= new DictionaryOrList<string, int>(
|
||||
new Dictionary<string, int>(),
|
||||
[]
|
||||
);
|
||||
fullProfile.CharacterData.ScavData!.WishList ??= new DictionaryOrList<string, int>(
|
||||
new Dictionary<string, int>(),
|
||||
[]
|
||||
);
|
||||
|
||||
if (fullProfile.DialogueRecords is not null)
|
||||
{
|
||||
@@ -101,7 +106,9 @@ public class GameController(
|
||||
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Started game with session {sessionId} {fullProfile.ProfileInfo?.Username}");
|
||||
_logger.Debug(
|
||||
$"Started game with session {sessionId} {fullProfile.ProfileInfo?.Username}"
|
||||
);
|
||||
}
|
||||
|
||||
var pmcProfile = fullProfile.CharacterData.PmcData;
|
||||
@@ -133,7 +140,12 @@ public class GameController(
|
||||
_hideoutHelper.UnlockHideoutWallInProfile(pmcProfile);
|
||||
|
||||
// Handle if player has been inactive for a long time, catch up on hideout update before the user goes to his hideout
|
||||
if (!_profileActivityService.ActiveWithinLastMinutes(sessionId, _hideoutConfig.UpdateProfileHideoutWhenActiveWithinMinutes))
|
||||
if (
|
||||
!_profileActivityService.ActiveWithinLastMinutes(
|
||||
sessionId,
|
||||
_hideoutConfig.UpdateProfileHideoutWhenActiveWithinMinutes
|
||||
)
|
||||
)
|
||||
{
|
||||
_hideoutHelper.UpdatePlayerHideout(sessionId);
|
||||
}
|
||||
@@ -167,10 +179,12 @@ public class GameController(
|
||||
public GameConfigResponse GetGameConfig(string sessionId)
|
||||
{
|
||||
var profile = _profileHelper.GetPmcProfile(sessionId);
|
||||
var gameTime = profile?.Stats?.Eft?.OverallCounters?.Items?
|
||||
.FirstOrDefault(c => c.Key!.Contains("LifeTime") && c.Key.Contains("Pmc"))
|
||||
?.Value ??
|
||||
0D;
|
||||
var gameTime =
|
||||
profile
|
||||
?.Stats?.Eft?.OverallCounters?.Items?.FirstOrDefault(c =>
|
||||
c.Key!.Contains("LifeTime") && c.Key.Contains("Pmc")
|
||||
)
|
||||
?.Value ?? 0D;
|
||||
|
||||
var config = new GameConfigResponse
|
||||
{
|
||||
@@ -188,18 +202,14 @@ public class GameController(
|
||||
Trading = _httpServerHelper.GetBackendUrl(),
|
||||
Messaging = _httpServerHelper.GetBackendUrl(),
|
||||
Main = _httpServerHelper.GetBackendUrl(),
|
||||
RagFair = _httpServerHelper.GetBackendUrl()
|
||||
RagFair = _httpServerHelper.GetBackendUrl(),
|
||||
},
|
||||
UseProtobuf = false,
|
||||
UtcTime = _timeUtil.GetTimeStamp(),
|
||||
TotalInGame = gameTime,
|
||||
SessionMode = "pve",
|
||||
PurchasedGames = new PurchasedGames
|
||||
{
|
||||
IsEftPurchased = true,
|
||||
IsArenaPurchased = false
|
||||
},
|
||||
IsGameSynced = true
|
||||
PurchasedGames = new PurchasedGames { IsEftPurchased = true, IsArenaPurchased = false },
|
||||
IsGameSynced = true,
|
||||
};
|
||||
|
||||
return config;
|
||||
@@ -211,14 +221,12 @@ public class GameController(
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="requestData"></param>
|
||||
/// <returns></returns>
|
||||
public GameModeResponse GetGameMode(
|
||||
string sessionId,
|
||||
GameModeRequestData requestData)
|
||||
public GameModeResponse GetGameMode(string sessionId, GameModeRequestData requestData)
|
||||
{
|
||||
return new GameModeResponse
|
||||
{
|
||||
GameMode = "pve",
|
||||
BackendUrl = _httpServerHelper.GetBackendUrl()
|
||||
BackendUrl = _httpServerHelper.GetBackendUrl(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -229,14 +237,7 @@ public class GameController(
|
||||
/// <returns></returns>
|
||||
public List<ServerDetails> GetServer(string sessionId)
|
||||
{
|
||||
return
|
||||
[
|
||||
new ServerDetails
|
||||
{
|
||||
Ip = _httpConfig.BackendIp,
|
||||
Port = _httpConfig.BackendPort
|
||||
}
|
||||
];
|
||||
return [new ServerDetails { Ip = _httpConfig.BackendIp, Port = _httpConfig.BackendPort }];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -246,13 +247,9 @@ public class GameController(
|
||||
/// <returns></returns>
|
||||
public CurrentGroupResponse GetCurrentGroup(string sessionId)
|
||||
{
|
||||
return new CurrentGroupResponse
|
||||
{
|
||||
Squad = []
|
||||
};
|
||||
return new CurrentGroupResponse { Squad = [] };
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handle client/checkVersion
|
||||
/// </summary>
|
||||
@@ -263,7 +260,7 @@ public class GameController(
|
||||
return new CheckVersionResponse
|
||||
{
|
||||
IsValid = true,
|
||||
LatestVersion = _coreConfig.CompatibleTarkovVersion
|
||||
LatestVersion = _coreConfig.CompatibleTarkovVersion,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -275,11 +272,7 @@ public class GameController(
|
||||
public GameKeepAliveResponse GetKeepAlive(string sessionId)
|
||||
{
|
||||
_profileActivityService.SetActivityTimestamp(sessionId);
|
||||
return new GameKeepAliveResponse
|
||||
{
|
||||
Message = "OK",
|
||||
UtcTime = _timeUtil.GetTimeStamp()
|
||||
};
|
||||
return new GameKeepAliveResponse { Message = "OK", UtcTime = _timeUtil.GetTimeStamp() };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -311,7 +304,9 @@ public class GameController(
|
||||
var botReloadSkill = _profileHelper.GetSkillFromProfile(pmcProfile, SkillTypes.BotReload);
|
||||
if (botReloadSkill?.Progress > 0)
|
||||
{
|
||||
_logger.Warning(_localisationService.GetText("server_start_player_active_botreload_skill"));
|
||||
_logger.Warning(
|
||||
_localisationService.GetText("server_start_player_active_botreload_skill")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,23 +332,25 @@ public class GameController(
|
||||
var hpRegenPerHour = 456.6;
|
||||
|
||||
// Set new values, whatever is smallest
|
||||
energyRegenPerHour += pmcProfile.Bonuses!
|
||||
.Where(bonus => bonus.Type == BonusType.EnergyRegeneration)
|
||||
energyRegenPerHour += pmcProfile
|
||||
.Bonuses!.Where(bonus => bonus.Type == BonusType.EnergyRegeneration)
|
||||
.Aggregate(0d, (sum, bonus) => sum + bonus.Value!.Value);
|
||||
|
||||
hydrationRegenPerHour += pmcProfile.Bonuses!
|
||||
.Where(bonus => bonus.Type == BonusType.HydrationRegeneration)
|
||||
hydrationRegenPerHour += pmcProfile
|
||||
.Bonuses!.Where(bonus => bonus.Type == BonusType.HydrationRegeneration)
|
||||
.Aggregate(0d, (sum, bonus) => sum + bonus.Value!.Value);
|
||||
|
||||
hpRegenPerHour += pmcProfile.Bonuses!
|
||||
.Where(bonus => bonus.Type == BonusType.HealthRegeneration)
|
||||
hpRegenPerHour += pmcProfile
|
||||
.Bonuses!.Where(bonus => bonus.Type == BonusType.HealthRegeneration)
|
||||
.Aggregate(0d, (sum, bonus) => sum + bonus.Value!.Value);
|
||||
|
||||
// Player has energy deficit
|
||||
if (pmcProfile.Health?.Energy?.Current - pmcProfile.Health?.Energy?.Maximum <= _deviation)
|
||||
{
|
||||
// Set new value, whatever is smallest
|
||||
pmcProfile.Health!.Energy!.Current += Math.Round(energyRegenPerHour * (diffSeconds!.Value / 3600));
|
||||
pmcProfile.Health!.Energy!.Current += Math.Round(
|
||||
energyRegenPerHour * (diffSeconds!.Value / 3600)
|
||||
);
|
||||
if (pmcProfile.Health.Energy.Current > pmcProfile.Health.Energy.Maximum)
|
||||
{
|
||||
pmcProfile.Health.Energy.Current = pmcProfile.Health.Energy.Maximum;
|
||||
@@ -361,9 +358,14 @@ public class GameController(
|
||||
}
|
||||
|
||||
// Player has hydration deficit
|
||||
if (pmcProfile.Health?.Hydration?.Current - pmcProfile.Health?.Hydration?.Maximum <= _deviation)
|
||||
if (
|
||||
pmcProfile.Health?.Hydration?.Current - pmcProfile.Health?.Hydration?.Maximum
|
||||
<= _deviation
|
||||
)
|
||||
{
|
||||
pmcProfile.Health!.Hydration!.Current += Math.Round(hydrationRegenPerHour * (diffSeconds!.Value / 3600));
|
||||
pmcProfile.Health!.Hydration!.Current += Math.Round(
|
||||
hydrationRegenPerHour * (diffSeconds!.Value / 3600)
|
||||
);
|
||||
if (pmcProfile.Health.Hydration.Current > pmcProfile.Health.Hydration.Maximum)
|
||||
{
|
||||
pmcProfile.Health.Hydration.Current = pmcProfile.Health.Hydration.Maximum;
|
||||
@@ -383,10 +385,15 @@ public class GameController(
|
||||
/// <param name="pmcProfile">Player</param>
|
||||
/// <param name="hpRegenPerHour"></param>
|
||||
/// <param name="diffSeconds"></param>
|
||||
protected void DecreaseBodyPartEffectTimes(PmcData pmcProfile, double hpRegenPerHour, double diffSeconds)
|
||||
protected void DecreaseBodyPartEffectTimes(
|
||||
PmcData pmcProfile,
|
||||
double hpRegenPerHour,
|
||||
double diffSeconds
|
||||
)
|
||||
{
|
||||
foreach (var bodyPart in pmcProfile.Health!.BodyParts!
|
||||
.Select(bodyPartKvP => bodyPartKvP.Value))
|
||||
foreach (
|
||||
var bodyPart in pmcProfile.Health!.BodyParts!.Select(bodyPartKvP => bodyPartKvP.Value)
|
||||
)
|
||||
{
|
||||
// Check part hp
|
||||
if (bodyPart.Health!.Current < bodyPart.Health.Maximum)
|
||||
@@ -399,7 +406,6 @@ public class GameController(
|
||||
bodyPart.Health.Current = bodyPart.Health.Maximum;
|
||||
}
|
||||
|
||||
|
||||
if (bodyPart.Effects is null || bodyPart.Effects.Count == 0)
|
||||
{
|
||||
continue;
|
||||
@@ -423,7 +429,7 @@ public class GameController(
|
||||
// Decrement effect time value by difference between current time and time health was last updated
|
||||
effectKvP.Value.Time -= diffSeconds;
|
||||
if (effectKvP.Value.Time < 1)
|
||||
// Effect time was sub 1, set floor it can be
|
||||
// Effect time was sub 1, set floor it can be
|
||||
{
|
||||
effectKvP.Value.Time = 1;
|
||||
}
|
||||
@@ -475,7 +481,9 @@ public class GameController(
|
||||
{
|
||||
if (
|
||||
fullProfile.SptData.Mods.Any(m =>
|
||||
m.Author == mod.ModMetadata.Author && m.Version == mod.ModMetadata.Version && m.Name == mod.ModMetadata.Name
|
||||
m.Author == mod.ModMetadata.Author
|
||||
&& m.Version == mod.ModMetadata.Version
|
||||
&& m.Name == mod.ModMetadata.Name
|
||||
)
|
||||
)
|
||||
{
|
||||
@@ -490,7 +498,7 @@ public class GameController(
|
||||
Version = mod.ModMetadata.Version,
|
||||
Name = mod.ModMetadata.Name,
|
||||
Url = mod.ModMetadata.Url,
|
||||
DateAdded = _timeUtil.GetTimeStamp()
|
||||
DateAdded = _timeUtil.GetTimeStamp(),
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -552,7 +560,9 @@ public class GameController(
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Profile made with: {fullProfile.SptData?.Version}");
|
||||
_logger.Debug($"Server version: {ProgramStatics.SPT_VERSION() ?? _coreConfig.SptVersion} {ProgramStatics.COMMIT()}");
|
||||
_logger.Debug(
|
||||
$"Server version: {ProgramStatics.SPT_VERSION() ?? _coreConfig.SptVersion} {ProgramStatics.COMMIT()}"
|
||||
);
|
||||
_logger.Debug($"Debug enabled: {ProgramStatics.DEBUG()}");
|
||||
_logger.Debug($"Mods enabled: {ProgramStatics.MODS()}");
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@ public class HealthController(
|
||||
LocalisationService _localisationService,
|
||||
HttpResponseUtil _httpResponseUtil,
|
||||
HealthHelper _healthHelper,
|
||||
ICloner _cloner)
|
||||
ICloner _cloner
|
||||
)
|
||||
{
|
||||
/// <summary>
|
||||
/// When healing in menu
|
||||
@@ -37,15 +38,21 @@ public class HealthController(
|
||||
public ItemEventRouterResponse OffRaidHeal(
|
||||
PmcData pmcData,
|
||||
OffraidHealRequestData request,
|
||||
string sessionID)
|
||||
string sessionID
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionID);
|
||||
|
||||
// Update medkit used (hpresource)
|
||||
var healingItemToUse = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == request.Item);
|
||||
var healingItemToUse = pmcData.Inventory.Items.FirstOrDefault(item =>
|
||||
item.Id == request.Item
|
||||
);
|
||||
if (healingItemToUse is null)
|
||||
{
|
||||
var errorMessage = _localisationService.GetText("health-healing_item_not_found", request.Item);
|
||||
var errorMessage = _localisationService.GetText(
|
||||
"health-healing_item_not_found",
|
||||
request.Item
|
||||
);
|
||||
_logger.Error(errorMessage);
|
||||
|
||||
return _httpResponseUtil.AppendErrorToOutput(output, errorMessage);
|
||||
@@ -61,11 +68,10 @@ public class HealthController(
|
||||
else
|
||||
{
|
||||
// Get max healing from db
|
||||
var maxHp = _itemHelper.GetItem(healingItemToUse.Template).Value.Properties.MaxHpResource;
|
||||
healingItemToUse.Upd.MedKit = new UpdMedKit
|
||||
{
|
||||
HpResource = maxHp - request.Count
|
||||
}; // Subtract amout used from max
|
||||
var maxHp = _itemHelper
|
||||
.GetItem(healingItemToUse.Template)
|
||||
.Value.Properties.MaxHpResource;
|
||||
healingItemToUse.Upd.MedKit = new UpdMedKit { HpResource = maxHp - request.Count }; // Subtract amout used from max
|
||||
// request.count appears to take into account healing effects removed, e.g. bleeds
|
||||
// Salewa heals limb for 20 and fixes light bleed = (20+45 = 65)
|
||||
}
|
||||
@@ -82,7 +88,9 @@ public class HealthController(
|
||||
var bodyPartToHeal = pmcData.Health.BodyParts.GetValueOrDefault(request.Part);
|
||||
if (bodyPartToHeal is null)
|
||||
{
|
||||
_logger.Warning($"Player: {sessionID} Tried to heal a non-existent body part: {request.Part}");
|
||||
_logger.Warning(
|
||||
$"Player: {sessionID} Tried to heal a non-existent body part: {request.Part}"
|
||||
);
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -99,20 +107,25 @@ public class HealthController(
|
||||
{
|
||||
// Check enum has effectType
|
||||
if (!Enum.TryParse<DamageEffectType>(effectKvP.Key, out var effect))
|
||||
// Enum doesnt contain this key
|
||||
// Enum doesnt contain this key
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if healing item removes the effect on limb
|
||||
if (!healItemEffectDetails.TryGetValue(effect, out var matchingEffectFromHealingItem))
|
||||
// Healing item doesn't have matching effect, it doesn't remove the effect
|
||||
if (
|
||||
!healItemEffectDetails.TryGetValue(
|
||||
effect,
|
||||
out var matchingEffectFromHealingItem
|
||||
)
|
||||
)
|
||||
// Healing item doesn't have matching effect, it doesn't remove the effect
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Adjust limb heal amount based on if it's fixing an effect (request.count is TOTAL cost of hp resource on heal item, NOT amount to heal limb)
|
||||
amountToHealLimb -= (int) (matchingEffectFromHealingItem.Cost ?? 0);
|
||||
amountToHealLimb -= (int)(matchingEffectFromHealingItem.Cost ?? 0);
|
||||
bodyPartToHeal.Effects.Remove(effectKvP.Key);
|
||||
}
|
||||
}
|
||||
@@ -140,14 +153,15 @@ public class HealthController(
|
||||
public ItemEventRouterResponse OffRaidEat(
|
||||
PmcData pmcData,
|
||||
OffraidEatRequestData request,
|
||||
string sessionID)
|
||||
string sessionID
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionID);
|
||||
var resourceLeft = 0d;
|
||||
|
||||
var itemToConsume = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == request.Item);
|
||||
if (itemToConsume is null)
|
||||
// Item not found, very bad
|
||||
// Item not found, very bad
|
||||
{
|
||||
return _httpResponseUtil.AppendErrorToOutput(
|
||||
output,
|
||||
@@ -155,7 +169,9 @@ public class HealthController(
|
||||
);
|
||||
}
|
||||
|
||||
var consumedItemMaxResource = _itemHelper.GetItem(itemToConsume.Template).Value.Properties.MaxResource;
|
||||
var consumedItemMaxResource = _itemHelper
|
||||
.GetItem(itemToConsume.Template)
|
||||
.Value.Properties.MaxResource;
|
||||
if (consumedItemMaxResource > 1)
|
||||
{
|
||||
// Ensure item has a upd object
|
||||
@@ -165,7 +181,7 @@ public class HealthController(
|
||||
{
|
||||
itemToConsume.Upd.FoodDrink = new UpdFoodDrink
|
||||
{
|
||||
HpPercent = consumedItemMaxResource - request.Count
|
||||
HpPercent = consumedItemMaxResource - request.Count,
|
||||
};
|
||||
}
|
||||
else
|
||||
@@ -192,14 +208,21 @@ public class HealthController(
|
||||
switch (key)
|
||||
{
|
||||
case HealthFactor.Hydration:
|
||||
ApplyEdibleEffect(pmcData.Health.Hydration, effectProps, foodIsSingleUse, request);
|
||||
ApplyEdibleEffect(
|
||||
pmcData.Health.Hydration,
|
||||
effectProps,
|
||||
foodIsSingleUse,
|
||||
request
|
||||
);
|
||||
break;
|
||||
case HealthFactor.Energy:
|
||||
ApplyEdibleEffect(pmcData.Health.Energy, effectProps, foodIsSingleUse, request);
|
||||
break;
|
||||
|
||||
default:
|
||||
_logger.Warning($"Unhandled effect after consuming: {itemToConsume.Template}, {key}");
|
||||
_logger.Warning(
|
||||
$"Unhandled effect after consuming: {itemToConsume.Template}, {key}"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -214,11 +237,15 @@ public class HealthController(
|
||||
/// <param name="consumptionDetails">Properties of consumed item</param>
|
||||
/// <param name="foodIsSingleUse">Single use item</param>
|
||||
/// <param name="request">Client request</param>
|
||||
protected void ApplyEdibleEffect(CurrentMinMax bodyValue, EffectsHealthProps consumptionDetails, bool foodIsSingleUse,
|
||||
OffraidEatRequestData request)
|
||||
protected void ApplyEdibleEffect(
|
||||
CurrentMinMax bodyValue,
|
||||
EffectsHealthProps consumptionDetails,
|
||||
bool foodIsSingleUse,
|
||||
OffraidEatRequestData request
|
||||
)
|
||||
{
|
||||
if (foodIsSingleUse)
|
||||
// Apply whole value from passed in parameter
|
||||
// Apply whole value from passed in parameter
|
||||
{
|
||||
bodyValue.Current += consumptionDetails.Value;
|
||||
}
|
||||
@@ -253,7 +280,8 @@ public class HealthController(
|
||||
public ItemEventRouterResponse HealthTreatment(
|
||||
PmcData pmcData,
|
||||
HealthTreatmentRequestData healthTreatmentRequest,
|
||||
string sessionID)
|
||||
string sessionID
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionID);
|
||||
var payMoneyRequest = new ProcessBuyTradeRequestData
|
||||
@@ -264,7 +292,7 @@ public class HealthController(
|
||||
Type = "",
|
||||
ItemId = "",
|
||||
Count = 0,
|
||||
SchemeId = 0
|
||||
SchemeId = 0,
|
||||
};
|
||||
|
||||
_paymentService.PayMoney(pmcData, payMoneyRequest, sessionID, output);
|
||||
@@ -276,12 +304,12 @@ public class HealthController(
|
||||
foreach (var bodyPartKvP in healthTreatmentRequest.Difference.BodyParts.GetAllPropsAsDict())
|
||||
{
|
||||
// Get body part from request + from pmc profile
|
||||
var partRequest = (BodyPartEffects) bodyPartKvP.Value;
|
||||
var partRequest = (BodyPartEffects)bodyPartKvP.Value;
|
||||
var profilePart = pmcData.Health.BodyParts[bodyPartKvP.Key];
|
||||
|
||||
// Bodypart healing is chosen when part request hp is above 0
|
||||
if (partRequest.Health > 0)
|
||||
// Heal bodypart
|
||||
// Heal bodypart
|
||||
{
|
||||
profilePart.Health.Current = profilePart.Health.Maximum;
|
||||
}
|
||||
@@ -315,10 +343,7 @@ public class HealthController(
|
||||
/// <param name="pmcData">Player profile</param>
|
||||
/// <param name="request">Request data</param>
|
||||
/// <param name="sessionId">session id</param>
|
||||
public void ApplyWorkoutChanges(
|
||||
PmcData? pmcData,
|
||||
WorkoutData request,
|
||||
string sessionId)
|
||||
public void ApplyWorkoutChanges(PmcData? pmcData, WorkoutData request, string sessionId)
|
||||
{
|
||||
pmcData.Skills.Common = request.Skills.Common;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,7 @@ public class InRaidController(
|
||||
/// <param name="info">Register player request</param>
|
||||
public void AddPlayer(string sessionId, RegisterPlayerRequestData info)
|
||||
{
|
||||
// _applicationContext.AddValue(ContextVariableType.REGISTER_PLAYER_REQUEST, info);
|
||||
// _applicationContext.AddValue(ContextVariableType.REGISTER_PLAYER_REQUEST, info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -91,11 +91,15 @@ public class InsuranceController(
|
||||
{
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Found {profileInsuranceDetails.Count} insurance packages in profile {sessionId}");
|
||||
_logger.Debug(
|
||||
$"Found {profileInsuranceDetails.Count} insurance packages in profile {sessionId}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return profileInsuranceDetails.Where(insured => insuranceTime >= insured.ScheduledTime).ToList();
|
||||
return profileInsuranceDetails
|
||||
.Where(insured => insuranceTime >= insured.ScheduledTime)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -159,17 +163,20 @@ public class InsuranceController(
|
||||
protected void RemoveInsurancePackageFromProfile(string sessionId, Insurance insPackage)
|
||||
{
|
||||
var profile = _saveServer.GetProfile(sessionId);
|
||||
profile.InsuranceList = profile.InsuranceList.Where(insurance =>
|
||||
insurance.TraderId != insPackage.TraderId ||
|
||||
insurance.SystemData?.Date != insPackage.SystemData?.Date ||
|
||||
insurance.SystemData?.Time != insPackage.SystemData?.Time ||
|
||||
insurance.SystemData?.Location != insPackage.SystemData?.Location
|
||||
profile.InsuranceList = profile
|
||||
.InsuranceList.Where(insurance =>
|
||||
insurance.TraderId != insPackage.TraderId
|
||||
|| insurance.SystemData?.Date != insPackage.SystemData?.Date
|
||||
|| insurance.SystemData?.Time != insPackage.SystemData?.Time
|
||||
|| insurance.SystemData?.Location != insPackage.SystemData?.Location
|
||||
)
|
||||
.ToList();
|
||||
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Removed processed insurance package. Remaining packages: {profile.InsuranceList.Count}");
|
||||
_logger.Debug(
|
||||
$"Removed processed insurance package. Remaining packages: {profile.InsuranceList.Count}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,11 +193,14 @@ public class InsuranceController(
|
||||
// Populate a Map object of items for quick lookup by their ID and use it to populate a Map of main-parent items
|
||||
// and each of their attachments. For example, a gun mapped to each of its attachments.
|
||||
var itemsMap = _itemHelper.GenerateItemsMap(insured.Items);
|
||||
var parentAttachmentsMap = PopulateParentAttachmentsMap(rootItemParentId, insured, itemsMap);
|
||||
var parentAttachmentsMap = PopulateParentAttachmentsMap(
|
||||
rootItemParentId,
|
||||
insured,
|
||||
itemsMap
|
||||
);
|
||||
|
||||
// Check to see if any regular items are present.
|
||||
var hasRegularItems = itemsMap.Values.Any(item => !_itemHelper.IsAttachmentAttached(item)
|
||||
);
|
||||
var hasRegularItems = itemsMap.Values.Any(item => !_itemHelper.IsAttachmentAttached(item));
|
||||
|
||||
// Process all items that are not attached, attachments; those are handled separately, by value.
|
||||
if (hasRegularItems)
|
||||
@@ -229,7 +239,11 @@ public class InsuranceController(
|
||||
/// <param name="insured">The insurance object containing the items to evaluate</param>
|
||||
/// <param name="itemsMap">A Dictionary for quick item look-up by item ID</param>
|
||||
/// <returns>A dictionary containing parent item IDs to arrays of their attachment items</returns>
|
||||
protected Dictionary<string, List<Item>> PopulateParentAttachmentsMap(string rootItemParentID, Insurance insured, Dictionary<string, Item> itemsMap)
|
||||
protected Dictionary<string, List<Item>> PopulateParentAttachmentsMap(
|
||||
string rootItemParentID,
|
||||
Insurance insured,
|
||||
Dictionary<string, Item> itemsMap
|
||||
)
|
||||
{
|
||||
var mainParentToAttachmentsMap = new Dictionary<string, List<Item>>();
|
||||
foreach (var insuredItem in insured.Items)
|
||||
@@ -247,7 +261,7 @@ public class InsuranceController(
|
||||
{
|
||||
insuredItemId = insuredItem.Id,
|
||||
insuredItemTpl = insuredItem.Template,
|
||||
parentId = insuredItem.ParentId
|
||||
parentId = insuredItem.ParentId,
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -270,7 +284,7 @@ public class InsuranceController(
|
||||
new
|
||||
{
|
||||
insuredItemId = insuredItem.Id,
|
||||
insuredItemTpl = insuredItem.Template
|
||||
insuredItemTpl = insuredItem.Template,
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -290,7 +304,7 @@ public class InsuranceController(
|
||||
{
|
||||
insuredItemId = insuredItem.Id,
|
||||
insuredItemTpl = insuredItem.Template,
|
||||
parentId = insuredItem.ParentId
|
||||
parentId = insuredItem.ParentId,
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -322,8 +336,10 @@ public class InsuranceController(
|
||||
/// <param name="parentAttachmentsMap">Dictionary containing parent item IDs to arrays of their attachment items</param>
|
||||
/// <param name="itemsMap">Hashset containing parent item IDs to arrays of their attachment items which are not moddable in-raid</param>
|
||||
/// <returns></returns>
|
||||
protected Dictionary<string, List<Item>> RemoveNonModdableAttachments(Dictionary<string, List<Item>> parentAttachmentsMap,
|
||||
Dictionary<string, Item> itemsMap)
|
||||
protected Dictionary<string, List<Item>> RemoveNonModdableAttachments(
|
||||
Dictionary<string, List<Item>> parentAttachmentsMap,
|
||||
Dictionary<string, Item> itemsMap
|
||||
)
|
||||
{
|
||||
var updatedMap = new Dictionary<string, List<Item>>();
|
||||
|
||||
@@ -371,7 +387,11 @@ public class InsuranceController(
|
||||
/// <param name="insured">Insurance object containing the items to evaluate</param>
|
||||
/// <param name="toDelete">Hashset to keep track of items marked for deletion</param>
|
||||
/// <param name="parentAttachmentsMap">Dictionary containing parent item IDs to arrays of their attachment items</param>
|
||||
protected void ProcessRegularItems(Insurance insured, HashSet<string> toDelete, Dictionary<string, List<Item>> parentAttachmentsMap)
|
||||
protected void ProcessRegularItems(
|
||||
Insurance insured,
|
||||
HashSet<string> toDelete,
|
||||
Dictionary<string, List<Item>> parentAttachmentsMap
|
||||
)
|
||||
{
|
||||
foreach (var insuredItem in insured.Items)
|
||||
{
|
||||
@@ -419,8 +439,12 @@ public class InsuranceController(
|
||||
/// <param name="itemsMap">Dictionary for quick item look-up by item ID</param>
|
||||
/// <param name="insuredTraderId">Trader ID from the Insurance object</param>
|
||||
/// <param name="toDelete">Tracked attachment ids to be removed</param>
|
||||
protected void ProcessAttachments(Dictionary<string, List<Item>> mainParentToAttachmentsMap, Dictionary<string, Item> itemsMap, string? insuredTraderId,
|
||||
HashSet<string> toDelete)
|
||||
protected void ProcessAttachments(
|
||||
Dictionary<string, List<Item>> mainParentToAttachmentsMap,
|
||||
Dictionary<string, Item> itemsMap,
|
||||
string? insuredTraderId,
|
||||
HashSet<string> toDelete
|
||||
)
|
||||
{
|
||||
foreach (var parentObj in mainParentToAttachmentsMap)
|
||||
{
|
||||
@@ -444,7 +468,6 @@ public class InsuranceController(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Takes an array of attachment items that belong to the same main-parent item, sorts them in descending order by
|
||||
/// their maximum price. For each attachment, a roll is made to determine if a deletion should be made. Once the
|
||||
@@ -454,16 +477,26 @@ public class InsuranceController(
|
||||
/// <param name="attachments">Array of attachment items to sort, filter, and roll</param>
|
||||
/// <param name="traderId">ID of the trader to that has ensured these items</param>
|
||||
/// <param name="toDelete">array that accumulates the IDs of the items to be deleted</param>
|
||||
protected void ProcessAttachmentByParent(List<Item> attachments, string? traderId, HashSet<string> toDelete)
|
||||
protected void ProcessAttachmentByParent(
|
||||
List<Item> attachments,
|
||||
string? traderId,
|
||||
HashSet<string> toDelete
|
||||
)
|
||||
{
|
||||
// Create dict of item ids + their flea/handbook price (highest is chosen)
|
||||
var weightedAttachmentByPrice = WeightAttachmentsByPrice(attachments);
|
||||
|
||||
// Get how many attachments we want to pull off parent
|
||||
var countOfAttachmentsToRemove = GetAttachmentCountToRemove(weightedAttachmentByPrice, traderId);
|
||||
var countOfAttachmentsToRemove = GetAttachmentCountToRemove(
|
||||
weightedAttachmentByPrice,
|
||||
traderId
|
||||
);
|
||||
|
||||
// Create prob array and add all attachments with rouble price as the weight
|
||||
var attachmentsProbabilityArray = new ProbabilityObjectArray<string, double?>(_mathUtil, _cloner);
|
||||
var attachmentsProbabilityArray = new ProbabilityObjectArray<string, double?>(
|
||||
_mathUtil,
|
||||
_cloner
|
||||
);
|
||||
foreach (var attachmentTpl in weightedAttachmentByPrice)
|
||||
{
|
||||
attachmentsProbabilityArray.Add(
|
||||
@@ -472,7 +505,10 @@ public class InsuranceController(
|
||||
}
|
||||
|
||||
// Draw x attachments from weighted array to remove from parent, remove from pool after being picked
|
||||
var attachmentIdsToRemove = attachmentsProbabilityArray.Draw((int) countOfAttachmentsToRemove, false);
|
||||
var attachmentIdsToRemove = attachmentsProbabilityArray.Draw(
|
||||
(int)countOfAttachmentsToRemove,
|
||||
false
|
||||
);
|
||||
foreach (var attachmentId in attachmentIdsToRemove)
|
||||
{
|
||||
toDelete.Add(attachmentId);
|
||||
@@ -492,7 +528,11 @@ public class InsuranceController(
|
||||
/// <param name="attachmentIdsToRemove"></param>
|
||||
/// <param name="attachments"></param>
|
||||
/// <param name="attachmentPrices"></param>
|
||||
protected void LogAttachmentsBeingRemoved(List<string> attachmentIdsToRemove, List<Item> attachments, Dictionary<string, double> attachmentPrices)
|
||||
protected void LogAttachmentsBeingRemoved(
|
||||
List<string> attachmentIdsToRemove,
|
||||
List<Item> attachments,
|
||||
Dictionary<string, double> attachmentPrices
|
||||
)
|
||||
{
|
||||
var index = 1;
|
||||
foreach (var attachmentId in attachmentIdsToRemove)
|
||||
@@ -500,8 +540,8 @@ public class InsuranceController(
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug(
|
||||
$"Attachment {index} Id: {attachmentId} Tpl: {attachments.FirstOrDefault(x => x.Id == attachmentId)?.Template} - " +
|
||||
$"Price: {attachmentPrices[attachmentId]}"
|
||||
$"Attachment {index} Id: {attachmentId} Tpl: {attachments.FirstOrDefault(x => x.Id == attachmentId)?.Template} - "
|
||||
+ $"Price: {attachmentPrices[attachmentId]}"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -521,7 +561,10 @@ public class InsuranceController(
|
||||
// Get a dictionary of item tpls + their rouble price
|
||||
foreach (var attachment in attachments)
|
||||
{
|
||||
var price = _ragfairPriceService.GetDynamicItemPrice(attachment.Template, Money.ROUBLES);
|
||||
var price = _ragfairPriceService.GetDynamicItemPrice(
|
||||
attachment.Template,
|
||||
Money.ROUBLES
|
||||
);
|
||||
if (price is not null)
|
||||
{
|
||||
result[attachment.Id] = Math.Round(price ?? 0);
|
||||
@@ -539,7 +582,10 @@ public class InsuranceController(
|
||||
/// <param name="weightedAttachmentByPrice">Dict of item Tpls and their rouble price</param>
|
||||
/// <param name="traderId">Trader the attachment is insured against</param>
|
||||
/// <returns>Attachment count to remove</returns>
|
||||
protected double GetAttachmentCountToRemove(Dictionary<string, double> weightedAttachmentByPrice, string? traderId)
|
||||
protected double GetAttachmentCountToRemove(
|
||||
Dictionary<string, double> weightedAttachmentByPrice,
|
||||
string? traderId
|
||||
)
|
||||
{
|
||||
const int removeCount = 0;
|
||||
|
||||
@@ -550,7 +596,9 @@ public class InsuranceController(
|
||||
|
||||
// Get attachments count above or equal to price set in config
|
||||
return weightedAttachmentByPrice
|
||||
.Where(attachment => attachment.Value >= _insuranceConfig.MinAttachmentRoublePriceToBeTaken)
|
||||
.Where(attachment =>
|
||||
attachment.Value >= _insuranceConfig.MinAttachmentRoublePriceToBeTaken
|
||||
)
|
||||
.Count(_ => RollForDelete(traderId) ?? false);
|
||||
}
|
||||
|
||||
@@ -577,8 +625,8 @@ public class InsuranceController(
|
||||
|
||||
// Map is labs + insurance is disabled in base.json
|
||||
if (IsMapLabsAndInsuranceDisabled(insurance))
|
||||
// Trader has labs-specific messages
|
||||
// Wipe out returnable items
|
||||
// Trader has labs-specific messages
|
||||
// Wipe out returnable items
|
||||
{
|
||||
HandleLabsInsurance(traderDialogMessages, insurance);
|
||||
}
|
||||
@@ -587,9 +635,14 @@ public class InsuranceController(
|
||||
HandleLabyrinthInsurance(traderDialogMessages, insurance);
|
||||
}
|
||||
else if (insurance.Items?.Count == 0)
|
||||
// Not labs and no items to return
|
||||
// Not labs and no items to return
|
||||
{
|
||||
if (traderDialogMessages.TryGetValue("insuranceFailed", out var insuranceFailedTemplates))
|
||||
if (
|
||||
traderDialogMessages.TryGetValue(
|
||||
"insuranceFailed",
|
||||
out var insuranceFailedTemplates
|
||||
)
|
||||
)
|
||||
{
|
||||
insurance.MessageTemplateId = _randomUtil.GetArrayValue(insuranceFailedTemplates);
|
||||
}
|
||||
@@ -615,8 +668,15 @@ public class InsuranceController(
|
||||
/// <returns></returns>
|
||||
protected bool IsMapLabsAndInsuranceDisabled(Insurance insurance, string labsId = "laboratory")
|
||||
{
|
||||
return string.Equals(insurance.SystemData?.Location, labsId, StringComparison.OrdinalIgnoreCase) &&
|
||||
!(_databaseService.GetLocation(labsId)?.Base?.Insurance.GetValueOrDefault(false) ?? false);
|
||||
return string.Equals(
|
||||
insurance.SystemData?.Location,
|
||||
labsId,
|
||||
StringComparison.OrdinalIgnoreCase
|
||||
)
|
||||
&& !(
|
||||
_databaseService.GetLocation(labsId)?.Base?.Insurance.GetValueOrDefault(false)
|
||||
?? false
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -625,10 +685,20 @@ public class InsuranceController(
|
||||
/// <param name="insurance">The insured items to process</param>
|
||||
/// <param name="labsId">OPTIONAL - id of labs location</param>
|
||||
/// <returns></returns>
|
||||
protected bool IsMapLabyrinthAndInsuranceDisabled(Insurance insurance, string labyrinthId = "labyrinth")
|
||||
protected bool IsMapLabyrinthAndInsuranceDisabled(
|
||||
Insurance insurance,
|
||||
string labyrinthId = "labyrinth"
|
||||
)
|
||||
{
|
||||
return string.Equals(insurance.SystemData?.Location, labyrinthId, StringComparison.OrdinalIgnoreCase) &&
|
||||
!(_databaseService.GetLocation(labyrinthId)?.Base?.Insurance.GetValueOrDefault(false) ?? false);
|
||||
return string.Equals(
|
||||
insurance.SystemData?.Location,
|
||||
labyrinthId,
|
||||
StringComparison.OrdinalIgnoreCase
|
||||
)
|
||||
&& !(
|
||||
_databaseService.GetLocation(labyrinthId)?.Base?.Insurance.GetValueOrDefault(false)
|
||||
?? false
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -636,7 +706,10 @@ public class InsuranceController(
|
||||
/// </summary>
|
||||
/// <param name="traderDialogMessages"></param>
|
||||
/// <param name="insurance"></param>
|
||||
protected void HandleLabsInsurance(Dictionary<string, List<string>?>? traderDialogMessages, Insurance insurance)
|
||||
protected void HandleLabsInsurance(
|
||||
Dictionary<string, List<string>?>? traderDialogMessages,
|
||||
Insurance insurance
|
||||
)
|
||||
{
|
||||
// Use labs specific messages if available, otherwise use default
|
||||
var responseMesageIds =
|
||||
@@ -655,10 +728,13 @@ public class InsuranceController(
|
||||
/// </summary>
|
||||
/// <param name="traderDialogMessages"></param>
|
||||
/// <param name="insurance"></param>
|
||||
protected void HandleLabyrinthInsurance(Dictionary<string, List<string>?>? traderDialogMessages, Insurance insurance)
|
||||
protected void HandleLabyrinthInsurance(
|
||||
Dictionary<string, List<string>?>? traderDialogMessages,
|
||||
Insurance insurance
|
||||
)
|
||||
{
|
||||
// Use labs specific messages if available, otherwise use default
|
||||
var responseMessageIds =
|
||||
var responseMessageIds =
|
||||
traderDialogMessages["insuranceFailedLabyrinth"]?.Count > 0
|
||||
? traderDialogMessages["insuranceFailedLabyrinth"]
|
||||
: traderDialogMessages["insuranceFailed"];
|
||||
@@ -669,7 +745,6 @@ public class InsuranceController(
|
||||
insurance.Items = [];
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Roll for chance of item being 'lost'
|
||||
/// </summary>
|
||||
@@ -692,11 +767,15 @@ public class InsuranceController(
|
||||
var roll = returnChance >= traderReturnChance;
|
||||
|
||||
// Log the roll with as much detail as possible.
|
||||
var itemName = insuredItem is not null ? $"{_itemHelper.GetItemName(insuredItem.Template)}" : "";
|
||||
var itemName = insuredItem is not null
|
||||
? $"{_itemHelper.GetItemName(insuredItem.Template)}"
|
||||
: "";
|
||||
var status = roll ? "Delete" : "Keep";
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Rolling {itemName} with {trader} - Return {traderReturnChance}% - Roll: {returnChance} - Status: {status}");
|
||||
_logger.Debug(
|
||||
$"Rolling {itemName} with {trader} - Return {traderReturnChance}% - Roll: {returnChance} - Status: {status}"
|
||||
);
|
||||
}
|
||||
|
||||
return roll;
|
||||
@@ -709,7 +788,11 @@ public class InsuranceController(
|
||||
/// <param name="request">Insurance request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns>ItemEventRouterResponse object to send to client</returns>
|
||||
public ItemEventRouterResponse Insure(PmcData pmcData, InsureRequestData request, string sessionId)
|
||||
public ItemEventRouterResponse Insure(
|
||||
PmcData pmcData,
|
||||
InsureRequestData request,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionId);
|
||||
var itemsToInsureCount = request.Items.Count;
|
||||
@@ -729,7 +812,7 @@ public class InsuranceController(
|
||||
pmcData,
|
||||
inventoryItemsHash[key],
|
||||
request.TransactionId
|
||||
)
|
||||
),
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -742,7 +825,7 @@ public class InsuranceController(
|
||||
Type = "",
|
||||
ItemId = "",
|
||||
Count = 0,
|
||||
SchemeId = 0
|
||||
SchemeId = 0,
|
||||
};
|
||||
|
||||
// pay for the item insurance
|
||||
@@ -757,20 +840,22 @@ public class InsuranceController(
|
||||
foreach (var key in request.Items)
|
||||
{
|
||||
pmcData.InsuredItems.Add(
|
||||
new InsuredItem
|
||||
{
|
||||
TId = request.TransactionId,
|
||||
ItemId = inventoryItemsHash[key].Id
|
||||
}
|
||||
new InsuredItem { TId = request.TransactionId, ItemId = inventoryItemsHash[key].Id }
|
||||
);
|
||||
// If Item is Helmet or Body Armour -> Handle insurance of soft inserts
|
||||
if (_itemHelper.ArmorItemHasRemovableOrSoftInsertSlots(inventoryItemsHash[key].Template))
|
||||
if (
|
||||
_itemHelper.ArmorItemHasRemovableOrSoftInsertSlots(inventoryItemsHash[key].Template)
|
||||
)
|
||||
{
|
||||
InsureSoftInserts(inventoryItemsHash[key], pmcData, request);
|
||||
}
|
||||
}
|
||||
|
||||
_profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Charisma, itemsToInsureCount * 0.01);
|
||||
_profileHelper.AddSkillPointsToPlayer(
|
||||
pmcData,
|
||||
SkillTypes.Charisma,
|
||||
itemsToInsureCount * 0.01
|
||||
);
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -781,9 +866,15 @@ public class InsuranceController(
|
||||
/// <param name="itemWithSoftInserts">Armor item to be insured</param>
|
||||
/// <param name="pmcData">Players PMC profile</param>
|
||||
/// <param name="request">Insurance request data</param>
|
||||
public void InsureSoftInserts(Item itemWithSoftInserts, PmcData pmcData, InsureRequestData request)
|
||||
public void InsureSoftInserts(
|
||||
Item itemWithSoftInserts,
|
||||
PmcData pmcData,
|
||||
InsureRequestData request
|
||||
)
|
||||
{
|
||||
var softInsertSlots = pmcData.Inventory.Items.Where(item => item.ParentId == itemWithSoftInserts.Id && _itemHelper.IsSoftInsertId(item.SlotId.ToLower())
|
||||
var softInsertSlots = pmcData.Inventory.Items.Where(item =>
|
||||
item.ParentId == itemWithSoftInserts.Id
|
||||
&& _itemHelper.IsSoftInsertId(item.SlotId.ToLower())
|
||||
);
|
||||
|
||||
foreach (var softInsertSlot in softInsertSlots)
|
||||
@@ -794,11 +885,7 @@ public class InsuranceController(
|
||||
}
|
||||
|
||||
pmcData.InsuredItems.Add(
|
||||
new InsuredItem
|
||||
{
|
||||
TId = request.TransactionId,
|
||||
ItemId = softInsertSlot.Id
|
||||
}
|
||||
new InsuredItem { TId = request.TransactionId, ItemId = softInsertSlot.Id }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -830,7 +917,9 @@ public class InsuranceController(
|
||||
{
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Item with id: {itemId} missing from player inventory, skipping");
|
||||
_logger.Debug(
|
||||
$"Item with id: {itemId} missing from player inventory, skipping"
|
||||
);
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -838,7 +927,11 @@ public class InsuranceController(
|
||||
|
||||
items.TryAdd(
|
||||
inventoryItemsHash[itemId].Template,
|
||||
_insuranceService.GetRoublePriceToInsureItemWithTrader(pmcData, inventoryItemsHash[itemId], trader)
|
||||
_insuranceService.GetRoublePriceToInsureItemWithTrader(
|
||||
pmcData,
|
||||
inventoryItemsHash[itemId],
|
||||
trader
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,8 +48,12 @@ public class InventoryController(
|
||||
/// <param name="moveRequest">Move request data</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void MoveItem(PmcData pmcData, InventoryMoveRequestData moveRequest, string sessionId,
|
||||
ItemEventRouterResponse output)
|
||||
public void MoveItem(
|
||||
PmcData pmcData,
|
||||
InventoryMoveRequestData moveRequest,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
if (output.Warnings?.Count > 0)
|
||||
{
|
||||
@@ -57,18 +61,27 @@ public class InventoryController(
|
||||
}
|
||||
|
||||
// Changes made to result apply to character inventory
|
||||
var ownerInventoryItems = _inventoryHelper.GetOwnerInventoryItems(moveRequest, moveRequest.Item, sessionId);
|
||||
var ownerInventoryItems = _inventoryHelper.GetOwnerInventoryItems(
|
||||
moveRequest,
|
||||
moveRequest.Item,
|
||||
sessionId
|
||||
);
|
||||
if (ownerInventoryItems.SameInventory.GetValueOrDefault(false))
|
||||
{
|
||||
// Don't move items from trader to profile, this can happen when editing a traders preset weapons
|
||||
if (moveRequest.FromOwner?.Type == "Trader" && !ownerInventoryItems.IsMail.GetValueOrDefault(false))
|
||||
if (
|
||||
moveRequest.FromOwner?.Type == "Trader"
|
||||
&& !ownerInventoryItems.IsMail.GetValueOrDefault(false)
|
||||
)
|
||||
{
|
||||
AppendTraderExploitErrorResponse(output);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for item in inventory before allowing internal transfer
|
||||
var originalItemLocation = ownerInventoryItems.From?.FirstOrDefault(item => item.Id == moveRequest.Item);
|
||||
var originalItemLocation = ownerInventoryItems.From?.FirstOrDefault(item =>
|
||||
item.Id == moveRequest.Item
|
||||
);
|
||||
if (originalItemLocation is null)
|
||||
{
|
||||
// Internal item move but item never existed, possible dupe glitch
|
||||
@@ -91,9 +104,19 @@ public class InventoryController(
|
||||
}
|
||||
|
||||
// Item is moving into or out of place of fame dog tag slot
|
||||
if (moveRequest.To?.Container != null &&
|
||||
(moveRequest.To.Container.StartsWith("dogtag", StringComparison.OrdinalIgnoreCase) ||
|
||||
originalLocationSlotId.StartsWith("dogtag", StringComparison.OrdinalIgnoreCase)))
|
||||
if (
|
||||
moveRequest.To?.Container != null
|
||||
&& (
|
||||
moveRequest.To.Container.StartsWith(
|
||||
"dogtag",
|
||||
StringComparison.OrdinalIgnoreCase
|
||||
)
|
||||
|| originalLocationSlotId.StartsWith(
|
||||
"dogtag",
|
||||
StringComparison.OrdinalIgnoreCase
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
_hideoutHelper.ApplyPlaceOfFameDogtagBonus(pmcData);
|
||||
}
|
||||
@@ -117,7 +140,7 @@ public class InventoryController(
|
||||
_httpResponseUtil.AppendErrorToOutput(
|
||||
output,
|
||||
_localisationService.GetText("inventory-edit_trader_item"),
|
||||
(BackendErrorCodes) 228
|
||||
(BackendErrorCodes)228
|
||||
);
|
||||
}
|
||||
|
||||
@@ -129,13 +152,21 @@ public class InventoryController(
|
||||
/// <param name="request">Pin/Lock request data</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void PinOrLock(PmcData pmcData, PinOrLockItemRequest request, string sessionId,
|
||||
ItemEventRouterResponse output)
|
||||
public void PinOrLock(
|
||||
PmcData pmcData,
|
||||
PinOrLockItemRequest request,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
var itemToAdjust = pmcData.Inventory!.Items!.FirstOrDefault(item => item.Id == request.Item);
|
||||
var itemToAdjust = pmcData.Inventory!.Items!.FirstOrDefault(item =>
|
||||
item.Id == request.Item
|
||||
);
|
||||
if (itemToAdjust is null)
|
||||
{
|
||||
_logger.Error($"Unable find item: {request.Item} to: {request.State} on player {sessionId}to: ");
|
||||
_logger.Error(
|
||||
$"Unable find item: {request.Item} to: {request.State} on player {sessionId}to: "
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -165,7 +196,11 @@ public class InventoryController(
|
||||
/// <param name="pmcData">Players PMC profile</param>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
public void RedeemProfileReward(PmcData pmcData, RedeemProfileRequestData request, string sessionId)
|
||||
public void RedeemProfileReward(
|
||||
PmcData pmcData,
|
||||
RedeemProfileRequestData request,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var fullProfile = _profileHelper.GetFullProfile(sessionId);
|
||||
foreach (var rewardEvent in request.Events)
|
||||
@@ -173,49 +208,58 @@ public class InventoryController(
|
||||
// Hard coded to `SYSTEM` for now
|
||||
// TODO: make this dynamic
|
||||
var dialog = fullProfile.DialogueRecords["59e7125688a45068a6249071"];
|
||||
var mail = dialog.Messages.FirstOrDefault(message => message.Id == rewardEvent.MessageId);
|
||||
var mailEvent =
|
||||
mail.ProfileChangeEvents.FirstOrDefault(changeEvent => changeEvent.Id == rewardEvent.EventId);
|
||||
|
||||
var mail = dialog.Messages.FirstOrDefault(message =>
|
||||
message.Id == rewardEvent.MessageId
|
||||
);
|
||||
var mailEvent = mail.ProfileChangeEvents.FirstOrDefault(changeEvent =>
|
||||
changeEvent.Id == rewardEvent.EventId
|
||||
);
|
||||
|
||||
switch (mailEvent.Type)
|
||||
{
|
||||
case "TraderSalesSum":
|
||||
pmcData.TradersInfo[mailEvent.Entity].SalesSum = mailEvent.Value;
|
||||
_traderHelper.LevelUp(mailEvent.Entity, pmcData);
|
||||
_logger.Success($"Set trader {mailEvent.Entity}: Sales Sum to: {mailEvent.Value}");
|
||||
_logger.Success(
|
||||
$"Set trader {mailEvent.Entity}: Sales Sum to: {mailEvent.Value}"
|
||||
);
|
||||
break;
|
||||
case "TraderStanding":
|
||||
pmcData.TradersInfo[mailEvent.Entity].Standing = mailEvent.Value;
|
||||
_traderHelper.LevelUp(mailEvent.Entity, pmcData);
|
||||
_logger.Success($"Set trader {mailEvent.Entity}: Standing to: {mailEvent.Value}");
|
||||
_logger.Success(
|
||||
$"Set trader {mailEvent.Entity}: Standing to: {mailEvent.Value}"
|
||||
);
|
||||
break;
|
||||
case "ProfileLevel":
|
||||
pmcData.Info.Experience = (int) mailEvent.Value.Value;
|
||||
pmcData.Info.Experience = (int)mailEvent.Value.Value;
|
||||
// Will calculate level below
|
||||
_traderHelper.ValidateTraderStandingsAndPlayerLevelForProfile(sessionId);
|
||||
_logger.Success($"Set profile xp to: {mailEvent.Value}");
|
||||
break;
|
||||
case "SkillPoints":
|
||||
{
|
||||
var profileSkill = pmcData.Skills.Common.FirstOrDefault(x =>
|
||||
x.Id == Enum.Parse<SkillTypes>(mailEvent.Entity)
|
||||
);
|
||||
if (profileSkill is null)
|
||||
{
|
||||
var profileSkill = pmcData.Skills.Common.FirstOrDefault(x => x.Id == Enum.Parse<SkillTypes>(mailEvent.Entity));
|
||||
if (profileSkill is null)
|
||||
{
|
||||
_logger.Warning($"Unable to find skill with name: {mailEvent.Entity}");
|
||||
continue;
|
||||
}
|
||||
|
||||
profileSkill.Progress = mailEvent.Value;
|
||||
_logger.Success($"Set profile skill: {mailEvent.Entity} to: {mailEvent.Value}");
|
||||
break;
|
||||
_logger.Warning($"Unable to find skill with name: {mailEvent.Entity}");
|
||||
continue;
|
||||
}
|
||||
|
||||
profileSkill.Progress = mailEvent.Value;
|
||||
_logger.Success($"Set profile skill: {mailEvent.Entity} to: {mailEvent.Value}");
|
||||
break;
|
||||
}
|
||||
case "ExamineAllItems":
|
||||
{
|
||||
var itemsToInspect = _itemHelper.GetItems().Where(x => x.Type != "Node");
|
||||
FlagItemsAsInspectedAndRewardXp(itemsToInspect.Select(x => x.Id), fullProfile);
|
||||
_logger.Success($"Flagged {itemsToInspect.Count()} items as examined");
|
||||
{
|
||||
var itemsToInspect = _itemHelper.GetItems().Where(x => x.Type != "Node");
|
||||
FlagItemsAsInspectedAndRewardXp(itemsToInspect.Select(x => x.Id), fullProfile);
|
||||
_logger.Success($"Flagged {itemsToInspect.Count()} items as examined");
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "UnlockTrader":
|
||||
pmcData.TradersInfo[mailEvent.Entity].Unlocked = true;
|
||||
_logger.Success($"Trader {mailEvent.Entity} Unlocked");
|
||||
@@ -228,19 +272,21 @@ public class InventoryController(
|
||||
|
||||
break;
|
||||
case "HideoutAreaLevel":
|
||||
{
|
||||
var areaName = mailEvent.Entity;
|
||||
var newValue = mailEvent.Value;
|
||||
var hideoutAreaType = Enum.Parse<HideoutAreas>(areaName ?? "NotSet");
|
||||
|
||||
var desiredArea = pmcData.Hideout.Areas.FirstOrDefault(area =>
|
||||
area.Type == hideoutAreaType
|
||||
);
|
||||
if (desiredArea is not null)
|
||||
{
|
||||
var areaName = mailEvent.Entity;
|
||||
var newValue = mailEvent.Value;
|
||||
var hideoutAreaType = Enum.Parse<HideoutAreas>(areaName ?? "NotSet");
|
||||
|
||||
var desiredArea = pmcData.Hideout.Areas.FirstOrDefault(area => area.Type == hideoutAreaType);
|
||||
if (desiredArea is not null)
|
||||
{
|
||||
desiredArea.Level = (int?) newValue;
|
||||
}
|
||||
|
||||
break;
|
||||
desiredArea.Level = (int?)newValue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
_logger.Warning($"Unhandled profile reward event: {mailEvent.Type}");
|
||||
|
||||
@@ -254,7 +300,10 @@ public class InventoryController(
|
||||
/// </summary>
|
||||
/// <param name="itemTpls">Inspected item tpls</param>
|
||||
/// <param name="fullProfile">Profile to add xp to</param>
|
||||
protected void FlagItemsAsInspectedAndRewardXp(IEnumerable<string> itemTpls, SptProfile fullProfile)
|
||||
protected void FlagItemsAsInspectedAndRewardXp(
|
||||
IEnumerable<string> itemTpls,
|
||||
SptProfile fullProfile
|
||||
)
|
||||
{
|
||||
foreach (var itemTpl in itemTpls)
|
||||
{
|
||||
@@ -262,16 +311,23 @@ public class InventoryController(
|
||||
if (!item.Key)
|
||||
{
|
||||
_logger.Warning(
|
||||
_localisationService.GetText("inventory-unable_to_inspect_item_not_in_db", itemTpl)
|
||||
_localisationService.GetText(
|
||||
"inventory-unable_to_inspect_item_not_in_db",
|
||||
itemTpl
|
||||
)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
fullProfile.CharacterData.PmcData.Info.Experience += item.Value.Properties.ExamineExperience;
|
||||
fullProfile.CharacterData.PmcData.Info.Experience += item.Value
|
||||
.Properties
|
||||
.ExamineExperience;
|
||||
fullProfile.CharacterData.PmcData.Encyclopedia[itemTpl] = false;
|
||||
|
||||
fullProfile.CharacterData.ScavData.Info.Experience += item.Value.Properties.ExamineExperience;
|
||||
fullProfile.CharacterData.ScavData.Info.Experience += item.Value
|
||||
.Properties
|
||||
.ExamineExperience;
|
||||
fullProfile.CharacterData.ScavData.Encyclopedia[itemTpl] = false;
|
||||
}
|
||||
|
||||
@@ -291,8 +347,12 @@ public class InventoryController(
|
||||
/// <param name="request"></param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void OpenRandomLootContainer(PmcData pmcData, OpenRandomLootContainerRequestData request, string sessionId,
|
||||
ItemEventRouterResponse output)
|
||||
public void OpenRandomLootContainer(
|
||||
PmcData pmcData,
|
||||
OpenRandomLootContainerRequestData request,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
// Container player opened in their inventory
|
||||
var openedItem = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == request.Item);
|
||||
@@ -305,7 +365,7 @@ public class InventoryController(
|
||||
{
|
||||
ItemTpl.RANDOMLOOTCONTAINER_ARENA_WEAPONCRATE_VIOLET_OPEN,
|
||||
ItemTpl.RANDOMLOOTCONTAINER_ARENA_WEAPONCRATE_BLUE_OPEN,
|
||||
ItemTpl.RANDOMLOOTCONTAINER_ARENA_WEAPONCRATE_GREEN_OPEN
|
||||
ItemTpl.RANDOMLOOTCONTAINER_ARENA_WEAPONCRATE_GREEN_OPEN,
|
||||
};
|
||||
// Temp fix for unlocked weapon crate hideout craft
|
||||
if (isSealedWeaponBox || unlockedWeaponCrates.Contains(containerDetailsDb.Value.Id))
|
||||
@@ -320,10 +380,14 @@ public class InventoryController(
|
||||
}
|
||||
else
|
||||
{
|
||||
var rewardContainerDetails = _inventoryHelper.GetRandomLootContainerRewardDetails(openedItem.Template);
|
||||
var rewardContainerDetails = _inventoryHelper.GetRandomLootContainerRewardDetails(
|
||||
openedItem.Template
|
||||
);
|
||||
if (rewardContainerDetails?.RewardCount == null)
|
||||
{
|
||||
_logger.Error($"Unable to add loot to container: {openedItem.Template}, no rewards found");
|
||||
_logger.Error(
|
||||
$"Unable to add loot to container: {openedItem.Template}, no rewards found"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -344,7 +408,7 @@ public class InventoryController(
|
||||
ItemsWithModsToAdd = rewards,
|
||||
FoundInRaid = foundInRaid,
|
||||
Callback = null,
|
||||
UseSortingTable = true
|
||||
UseSortingTable = true,
|
||||
};
|
||||
_inventoryHelper.AddItemsToStash(sessionId, addItemsRequest, pmcData, output);
|
||||
if (output.Warnings?.Count > 0)
|
||||
@@ -364,8 +428,12 @@ public class InventoryController(
|
||||
/// <param name="request">Edit marker request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void EditMapMarker(PmcData pmcData, InventoryEditMarkerRequestData request, string sessionId,
|
||||
ItemEventRouterResponse output)
|
||||
public void EditMapMarker(
|
||||
PmcData pmcData,
|
||||
InventoryEditMarkerRequestData request,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
var mapItem = _mapMarkerService.EditMarkerOnMap(pmcData, request);
|
||||
|
||||
@@ -380,8 +448,12 @@ public class InventoryController(
|
||||
/// <param name="request">Delete marker request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void DeleteMapMarker(PmcData pmcData, InventoryDeleteMarkerRequestData request, string sessionId,
|
||||
ItemEventRouterResponse output)
|
||||
public void DeleteMapMarker(
|
||||
PmcData pmcData,
|
||||
InventoryDeleteMarkerRequestData request,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
var mapItem = _mapMarkerService.DeleteMarkerFromMap(pmcData, request);
|
||||
|
||||
@@ -389,8 +461,12 @@ public class InventoryController(
|
||||
output.ProfileChanges[sessionId].Items.ChangedItems.Add(mapItem);
|
||||
}
|
||||
|
||||
public void CreateMapMarker(PmcData pmcData, InventoryCreateMarkerRequestData request, string sessionId,
|
||||
ItemEventRouterResponse output)
|
||||
public void CreateMapMarker(
|
||||
PmcData pmcData,
|
||||
InventoryCreateMarkerRequestData request,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
var adjustedMapItem = _mapMarkerService.CreateMarkerOnMap(pmcData, request);
|
||||
|
||||
@@ -405,16 +481,25 @@ public class InventoryController(
|
||||
/// <param name="request">Add marker request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void SortInventory(PmcData pmcData, InventorySortRequestData request, string sessionId,
|
||||
ItemEventRouterResponse output)
|
||||
public void SortInventory(
|
||||
PmcData pmcData,
|
||||
InventorySortRequestData request,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
foreach (var change in request.ChangedItems)
|
||||
{
|
||||
var inventoryItem = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == change.Id);
|
||||
var inventoryItem = pmcData.Inventory.Items.FirstOrDefault(item =>
|
||||
item.Id == change.Id
|
||||
);
|
||||
if (inventoryItem is null)
|
||||
{
|
||||
_logger.Error(
|
||||
_localisationService.GetText("inventory-unable_to_sort_inventory_restart_game", change.Id)
|
||||
_localisationService.GetText(
|
||||
"inventory-unable_to_sort_inventory_restart_game",
|
||||
change.Id
|
||||
)
|
||||
);
|
||||
|
||||
continue;
|
||||
@@ -440,8 +525,11 @@ public class InventoryController(
|
||||
/// <param name="request"></param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns></returns>
|
||||
public ItemEventRouterResponse ReadEncyclopedia(PmcData pmcData, InventoryReadEncyclopediaRequestData request,
|
||||
string sessionId)
|
||||
public ItemEventRouterResponse ReadEncyclopedia(
|
||||
PmcData pmcData,
|
||||
InventoryReadEncyclopediaRequestData request,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
foreach (var id in request.Ids)
|
||||
{
|
||||
@@ -458,8 +546,12 @@ public class InventoryController(
|
||||
/// <param name="request">Examine item request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void ExamineItem(PmcData pmcData, InventoryExamineRequestData request, string sessionId,
|
||||
ItemEventRouterResponse output)
|
||||
public void ExamineItem(
|
||||
PmcData pmcData,
|
||||
InventoryExamineRequestData request,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
string? itemId = null;
|
||||
if (request.FromOwner is not null)
|
||||
@@ -470,12 +562,17 @@ public class InventoryController(
|
||||
}
|
||||
catch
|
||||
{
|
||||
_logger.Error(_localisationService.GetText("inventory-examine_item_does_not_exist", request.Item));
|
||||
_logger.Error(
|
||||
_localisationService.GetText(
|
||||
"inventory-examine_item_does_not_exist",
|
||||
request.Item
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (itemId is null)
|
||||
// item template
|
||||
// item template
|
||||
{
|
||||
if (_databaseService.GetItems().ContainsKey(request.Item))
|
||||
{
|
||||
@@ -514,14 +611,17 @@ public class InventoryController(
|
||||
}
|
||||
|
||||
if (request.FromOwner.Id == Traders.FENCE)
|
||||
// Get tpl from fence assorts
|
||||
// Get tpl from fence assorts
|
||||
{
|
||||
return _fenceService.GetRawFenceAssorts().Items.FirstOrDefault(x => x.Id == request.Item)?.Template;
|
||||
return _fenceService
|
||||
.GetRawFenceAssorts()
|
||||
.Items.FirstOrDefault(x => x.Id == request.Item)
|
||||
?.Template;
|
||||
}
|
||||
|
||||
if (request.FromOwner.Type == "Trader")
|
||||
// Not fence
|
||||
// get tpl from trader assort
|
||||
// Not fence
|
||||
// get tpl from trader assort
|
||||
{
|
||||
return _databaseService
|
||||
.GetTrader(request.FromOwner.Id)
|
||||
@@ -539,18 +639,23 @@ public class InventoryController(
|
||||
}
|
||||
|
||||
// Try alternate way of getting offer if first approach fails
|
||||
var offer = _ragfairOfferService.GetOfferByOfferId(request.Item) ??
|
||||
_ragfairOfferService.GetOfferByOfferId(request.FromOwner.Id);
|
||||
var offer =
|
||||
_ragfairOfferService.GetOfferByOfferId(request.Item)
|
||||
?? _ragfairOfferService.GetOfferByOfferId(request.FromOwner.Id);
|
||||
|
||||
// Try find examine item inside offer items array
|
||||
var matchingItem = offer.Items.FirstOrDefault(offerItem => offerItem.Id == request.Item);
|
||||
var matchingItem = offer.Items.FirstOrDefault(offerItem =>
|
||||
offerItem.Id == request.Item
|
||||
);
|
||||
if (matchingItem is not null)
|
||||
{
|
||||
return matchingItem.Template;
|
||||
}
|
||||
|
||||
// Unable to find item in database or ragfair
|
||||
_logger.Warning(_localisationService.GetText("inventory-unable_to_find_item", request.Item));
|
||||
_logger.Warning(
|
||||
_localisationService.GetText("inventory-unable_to_find_item", request.Item)
|
||||
);
|
||||
}
|
||||
|
||||
// get hideout item
|
||||
@@ -565,7 +670,9 @@ public class InventoryController(
|
||||
// all mail the player has
|
||||
var mail = _profileHelper.GetFullProfile(sessionId).DialogueRecords;
|
||||
// per trader/person mail
|
||||
var dialogue = mail.FirstOrDefault(x => x.Value.Messages.Any(m => m.Id == request.FromOwner.Id));
|
||||
var dialogue = mail.FirstOrDefault(x =>
|
||||
x.Value.Messages.Any(m => m.Id == request.FromOwner.Id)
|
||||
);
|
||||
// check each message from that trader/person for messages that match the ID we got
|
||||
var message = dialogue.Value.Messages.FirstOrDefault(m => m.Id == request.FromOwner.Id);
|
||||
// get the Id given and get the Template ID from that
|
||||
@@ -590,8 +697,12 @@ public class InventoryController(
|
||||
/// <param name="request"></param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void UnBindItem(PmcData pmcData, InventoryBindRequestData request, string sessionId,
|
||||
ItemEventRouterResponse output)
|
||||
public void UnBindItem(
|
||||
PmcData pmcData,
|
||||
InventoryBindRequestData request,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
// Remove kvp from requested fast panel index
|
||||
|
||||
@@ -607,8 +718,12 @@ public class InventoryController(
|
||||
/// <param name="bindRequest"></param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void BindItem(PmcData pmcData, InventoryBindRequestData bindRequest, string sessionId,
|
||||
ItemEventRouterResponse output)
|
||||
public void BindItem(
|
||||
PmcData pmcData,
|
||||
InventoryBindRequestData bindRequest,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
// Remove link
|
||||
if (pmcData.Inventory.FastPanel.ContainsKey(bindRequest.Index))
|
||||
@@ -627,7 +742,11 @@ public class InventoryController(
|
||||
/// <param name="request"></param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
public ItemEventRouterResponse TagItem(PmcData pmcData, InventoryTagRequestData request, string sessionId)
|
||||
public ItemEventRouterResponse TagItem(
|
||||
PmcData pmcData,
|
||||
InventoryTagRequestData request,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var itemToTag = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == request.Item);
|
||||
if (itemToTag is null)
|
||||
@@ -636,20 +755,13 @@ public class InventoryController(
|
||||
$"Unable to tag item: {request.Item} as it cannot be found in player {sessionId} inventory"
|
||||
);
|
||||
|
||||
return new ItemEventRouterResponse
|
||||
{
|
||||
Warnings = []
|
||||
};
|
||||
return new ItemEventRouterResponse { Warnings = [] };
|
||||
}
|
||||
|
||||
// Null guard
|
||||
itemToTag.Upd ??= new Upd();
|
||||
|
||||
itemToTag.Upd.Tag = new UpdTag
|
||||
{
|
||||
Color = request.TagColor,
|
||||
Name = request.TagName
|
||||
};
|
||||
itemToTag.Upd.Tag = new UpdTag { Color = request.TagColor, Name = request.TagName };
|
||||
|
||||
return _eventOutputHolder.GetOutput(sessionId);
|
||||
}
|
||||
@@ -661,7 +773,11 @@ public class InventoryController(
|
||||
/// <param name="request">Toggle request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
public ItemEventRouterResponse ToggleItem(PmcData pmcData, InventoryToggleRequestData request, string sessionId)
|
||||
public ItemEventRouterResponse ToggleItem(
|
||||
PmcData pmcData,
|
||||
InventoryToggleRequestData request,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
// May need to reassign to scav profile
|
||||
var playerData = pmcData;
|
||||
@@ -677,23 +793,22 @@ public class InventoryController(
|
||||
{
|
||||
_itemHelper.AddUpdObjectToItem(
|
||||
itemToToggle,
|
||||
_localisationService.GetText("inventory-item_to_toggle_missing_upd", itemToToggle.Id)
|
||||
_localisationService.GetText(
|
||||
"inventory-item_to_toggle_missing_upd",
|
||||
itemToToggle.Id
|
||||
)
|
||||
);
|
||||
|
||||
itemToToggle.Upd.Togglable = new UpdTogglable
|
||||
{
|
||||
On = request.Value
|
||||
};
|
||||
itemToToggle.Upd.Togglable = new UpdTogglable { On = request.Value };
|
||||
|
||||
return _eventOutputHolder.GetOutput(sessionId);
|
||||
}
|
||||
|
||||
_logger.Warning(_localisationService.GetText("inventory-unable_to_toggle_item_not_found", request.Item));
|
||||
_logger.Warning(
|
||||
_localisationService.GetText("inventory-unable_to_toggle_item_not_found", request.Item)
|
||||
);
|
||||
|
||||
return new ItemEventRouterResponse
|
||||
{
|
||||
Warnings = []
|
||||
};
|
||||
return new ItemEventRouterResponse { Warnings = [] };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -703,7 +818,11 @@ public class InventoryController(
|
||||
/// <param name="request">Fold item request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
public ItemEventRouterResponse FoldItem(PmcData pmcData, InventoryFoldRequestData request, string sessionId)
|
||||
public ItemEventRouterResponse FoldItem(
|
||||
PmcData pmcData,
|
||||
InventoryFoldRequestData request,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
// May need to reassign to scav profile
|
||||
var playerData = pmcData;
|
||||
@@ -714,27 +833,26 @@ public class InventoryController(
|
||||
playerData = _profileHelper.GetScavProfile(sessionId);
|
||||
}
|
||||
|
||||
var itemToFold = playerData.Inventory.Items.FirstOrDefault(item => item?.Id == request.Item);
|
||||
var itemToFold = playerData.Inventory.Items.FirstOrDefault(item =>
|
||||
item?.Id == request.Item
|
||||
);
|
||||
if (itemToFold is null)
|
||||
{
|
||||
// Item not found
|
||||
_logger.Warning(
|
||||
_localisationService.GetText("inventory-unable_to_fold_item_not_found_in_inventory", request.Item)
|
||||
_localisationService.GetText(
|
||||
"inventory-unable_to_fold_item_not_found_in_inventory",
|
||||
request.Item
|
||||
)
|
||||
);
|
||||
|
||||
return new ItemEventRouterResponse
|
||||
{
|
||||
Warnings = []
|
||||
};
|
||||
return new ItemEventRouterResponse { Warnings = [] };
|
||||
}
|
||||
|
||||
// Item may not have upd object
|
||||
_itemHelper.AddUpdObjectToItem(itemToFold);
|
||||
|
||||
itemToFold.Upd.Foldable = new UpdFoldable
|
||||
{
|
||||
Folded = request.Value
|
||||
};
|
||||
itemToFold.Upd.Foldable = new UpdFoldable { Folded = request.Value };
|
||||
|
||||
return _eventOutputHolder.GetOutput(sessionId);
|
||||
}
|
||||
@@ -748,7 +866,11 @@ public class InventoryController(
|
||||
/// <param name="request">Swap item request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
public ItemEventRouterResponse SwapItem(PmcData pmcData, InventorySwapRequestData request, string sessionId)
|
||||
public ItemEventRouterResponse SwapItem(
|
||||
PmcData pmcData,
|
||||
InventorySwapRequestData request,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
// During post-raid scav transfer, the swap may be in the scav inventory
|
||||
var playerData = pmcData;
|
||||
@@ -763,11 +885,7 @@ public class InventoryController(
|
||||
_logger.Error(
|
||||
_localisationService.GetText(
|
||||
"inventory-unable_to_find_item_to_swap",
|
||||
new
|
||||
{
|
||||
item1Id = request.Item,
|
||||
item2Id = request.Item2
|
||||
}
|
||||
new { item1Id = request.Item, item2Id = request.Item2 }
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -778,11 +896,7 @@ public class InventoryController(
|
||||
_logger.Error(
|
||||
_localisationService.GetText(
|
||||
"inventory-unable_to_find_item_to_swap",
|
||||
new
|
||||
{
|
||||
item1Id = request.Item2,
|
||||
item2Id = request.Item
|
||||
}
|
||||
new { item1Id = request.Item2, item2Id = request.Item }
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -827,11 +941,19 @@ public class InventoryController(
|
||||
/// <param name="request">Transfer item request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void TransferItem(PmcData pmcData, InventoryTransferRequestData request, string sessionId,
|
||||
ItemEventRouterResponse output)
|
||||
public void TransferItem(
|
||||
PmcData pmcData,
|
||||
InventoryTransferRequestData request,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
// TODO - check GetOwnerInventoryItems() call still works
|
||||
var inventoryItems = _inventoryHelper.GetOwnerInventoryItems(request, request.Item, sessionId);
|
||||
var inventoryItems = _inventoryHelper.GetOwnerInventoryItems(
|
||||
request,
|
||||
request.Item,
|
||||
sessionId
|
||||
);
|
||||
var sourceItem = inventoryItems.From.FirstOrDefault(item => item.Id == request.Item);
|
||||
var destinationItem = inventoryItems.To.FirstOrDefault(item => item.Id == request.With);
|
||||
|
||||
@@ -855,27 +977,21 @@ public class InventoryController(
|
||||
return;
|
||||
}
|
||||
|
||||
sourceItem.Upd ??= new Upd
|
||||
{
|
||||
StackObjectsCount = 1
|
||||
};
|
||||
sourceItem.Upd ??= new Upd { StackObjectsCount = 1 };
|
||||
|
||||
var sourceStackCount = sourceItem.Upd.StackObjectsCount;
|
||||
if (sourceStackCount > request.Count)
|
||||
// Source items stack count greater than new desired count
|
||||
// Source items stack count greater than new desired count
|
||||
{
|
||||
sourceItem.Upd.StackObjectsCount = sourceStackCount - request.Count;
|
||||
}
|
||||
else
|
||||
// Moving a full stack onto a smaller stack
|
||||
// Moving a full stack onto a smaller stack
|
||||
{
|
||||
sourceItem.Upd.StackObjectsCount = sourceStackCount - 1;
|
||||
}
|
||||
|
||||
destinationItem.Upd ??= new Upd
|
||||
{
|
||||
StackObjectsCount = 1
|
||||
};
|
||||
destinationItem.Upd ??= new Upd { StackObjectsCount = 1 };
|
||||
|
||||
var destinationStackCount = destinationItem.Upd.StackObjectsCount;
|
||||
destinationItem.Upd.StackObjectsCount = destinationStackCount + request.Count;
|
||||
@@ -889,17 +1005,26 @@ public class InventoryController(
|
||||
/// <param name="request">Merge stacks request</param>
|
||||
/// <param name="sessionID">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void MergeItem(PmcData pmcData, InventoryMergeRequestData request, string sessionID,
|
||||
ItemEventRouterResponse output)
|
||||
public void MergeItem(
|
||||
PmcData pmcData,
|
||||
InventoryMergeRequestData request,
|
||||
string sessionID,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
// Changes made to result apply to character inventory
|
||||
var inventoryItems = _inventoryHelper.GetOwnerInventoryItems(request, request.Item, sessionID);
|
||||
var inventoryItems = _inventoryHelper.GetOwnerInventoryItems(
|
||||
request,
|
||||
request.Item,
|
||||
sessionID
|
||||
);
|
||||
|
||||
// Get source item (can be from player or trader or mail)
|
||||
var sourceItem = inventoryItems.From.FirstOrDefault(x => x.Id == request.Item);
|
||||
if (sourceItem is null)
|
||||
{
|
||||
var errorMessage = $"Unable to merge stacks as source item: {request.With} cannot be found";
|
||||
var errorMessage =
|
||||
$"Unable to merge stacks as source item: {request.With} cannot be found";
|
||||
_logger.Error(errorMessage);
|
||||
|
||||
_httpResponseUtil.AppendErrorToOutput(output, errorMessage);
|
||||
@@ -911,7 +1036,8 @@ public class InventoryController(
|
||||
var destinationItem = inventoryItems.To.FirstOrDefault(x => x.Id == request.With);
|
||||
if (destinationItem is null)
|
||||
{
|
||||
var errorMessage = $"Unable to merge stacks as destination item: {request.With} cannot be found";
|
||||
var errorMessage =
|
||||
$"Unable to merge stacks as destination item: {request.With} cannot be found";
|
||||
_logger.Error(errorMessage);
|
||||
|
||||
_httpResponseUtil.AppendErrorToOutput(output, errorMessage);
|
||||
@@ -920,48 +1046,38 @@ public class InventoryController(
|
||||
}
|
||||
|
||||
if (destinationItem.Upd?.StackObjectsCount is null)
|
||||
// No stackcount on destination, add one
|
||||
// No stackcount on destination, add one
|
||||
{
|
||||
destinationItem.Upd = new Upd
|
||||
{
|
||||
StackObjectsCount = 1
|
||||
};
|
||||
destinationItem.Upd = new Upd { StackObjectsCount = 1 };
|
||||
}
|
||||
|
||||
if (sourceItem.Upd is null)
|
||||
{
|
||||
sourceItem.Upd = new Upd
|
||||
{
|
||||
StackObjectsCount = 1
|
||||
};
|
||||
sourceItem.Upd = new Upd { StackObjectsCount = 1 };
|
||||
}
|
||||
else if (sourceItem.Upd.StackObjectsCount is null)
|
||||
// Items pulled out of raid can have no stack count if the stack should be 1
|
||||
// Items pulled out of raid can have no stack count if the stack should be 1
|
||||
{
|
||||
sourceItem.Upd.StackObjectsCount = 1;
|
||||
}
|
||||
|
||||
// Remove FiR status from destination stack when source stack has no FiR but destination does
|
||||
if (!sourceItem.Upd.SpawnedInSession.GetValueOrDefault(false) &&
|
||||
destinationItem.Upd.SpawnedInSession.GetValueOrDefault(false))
|
||||
if (
|
||||
!sourceItem.Upd.SpawnedInSession.GetValueOrDefault(false)
|
||||
&& destinationItem.Upd.SpawnedInSession.GetValueOrDefault(false)
|
||||
)
|
||||
{
|
||||
destinationItem.Upd.SpawnedInSession = false;
|
||||
}
|
||||
|
||||
destinationItem.Upd.StackObjectsCount +=
|
||||
sourceItem.Upd.StackObjectsCount; // Add source stackcount to destination
|
||||
output.ProfileChanges[sessionID]
|
||||
.Items.DeletedItems.Add(
|
||||
new Item
|
||||
{
|
||||
Id = sourceItem.Id
|
||||
}
|
||||
); // Inform client source item being deleted
|
||||
destinationItem.Upd.StackObjectsCount += sourceItem.Upd.StackObjectsCount; // Add source stackcount to destination
|
||||
output.ProfileChanges[sessionID].Items.DeletedItems.Add(new Item { Id = sourceItem.Id }); // Inform client source item being deleted
|
||||
|
||||
var indexOfItemToRemove = inventoryItems.From.FindIndex(x => x.Id == sourceItem.Id);
|
||||
if (indexOfItemToRemove == -1)
|
||||
{
|
||||
var errorMessage = $"Unable to find item: {sourceItem.Id} to remove from sender inventory";
|
||||
var errorMessage =
|
||||
$"Unable to find item: {sourceItem.Id} to remove from sender inventory";
|
||||
_logger.Error(errorMessage);
|
||||
|
||||
_httpResponseUtil.AppendErrorToOutput(output, errorMessage);
|
||||
@@ -979,11 +1095,19 @@ public class InventoryController(
|
||||
/// <param name="request">Split stack request</param>
|
||||
/// <param name="sessionID">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void SplitItem(PmcData pmcData, InventorySplitRequestData request, string sessionID,
|
||||
ItemEventRouterResponse output)
|
||||
public void SplitItem(
|
||||
PmcData pmcData,
|
||||
InventorySplitRequestData request,
|
||||
string sessionID,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
// Changes made to result apply to character inventory
|
||||
var inventoryItems = _inventoryHelper.GetOwnerInventoryItems(request, request.NewItem, sessionID);
|
||||
var inventoryItems = _inventoryHelper.GetOwnerInventoryItems(
|
||||
request,
|
||||
request.NewItem,
|
||||
sessionID
|
||||
);
|
||||
|
||||
// Handle cartridge edge-case
|
||||
if (request.Container.Location is null && request.Container.ContainerName == "cartridges")
|
||||
@@ -996,7 +1120,8 @@ public class InventoryController(
|
||||
var itemToSplit = inventoryItems.From.FirstOrDefault(x => x.Id == request.SplitItem);
|
||||
if (itemToSplit is null)
|
||||
{
|
||||
var errorMessage = $"Unable to split stack as source item: {request.SplitItem} cannot be found";
|
||||
var errorMessage =
|
||||
$"Unable to split stack as source item: {request.SplitItem} cannot be found";
|
||||
_logger.Error(errorMessage);
|
||||
|
||||
_httpResponseUtil.AppendErrorToOutput(output, errorMessage);
|
||||
@@ -1012,13 +1137,14 @@ public class InventoryController(
|
||||
itemToSplit.Upd.StackObjectsCount -= request.Count;
|
||||
|
||||
// Inform client of change
|
||||
output.ProfileChanges[sessionID]
|
||||
output
|
||||
.ProfileChanges[sessionID]
|
||||
.Items.NewItems.Add(
|
||||
new Item
|
||||
{
|
||||
Id = request.NewItem,
|
||||
Template = itemToSplit.Template,
|
||||
Upd = updatedUpd
|
||||
Upd = updatedUpd,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1031,7 +1157,7 @@ public class InventoryController(
|
||||
ParentId = request.Container.Id,
|
||||
SlotId = request.Container.ContainerName,
|
||||
Location = request.Container.Location,
|
||||
Upd = updatedUpd
|
||||
Upd = updatedUpd,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1044,8 +1170,12 @@ public class InventoryController(
|
||||
/// <param name="request">Discard item request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="output">Client response</param>
|
||||
public void DiscardItem(PmcData pmcData, InventoryRemoveRequestData request, string sessionId,
|
||||
ItemEventRouterResponse output)
|
||||
public void DiscardItem(
|
||||
PmcData pmcData,
|
||||
InventoryRemoveRequestData request,
|
||||
string sessionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
if (request.FromOwner?.Type == "Mail")
|
||||
{
|
||||
@@ -1054,9 +1184,10 @@ public class InventoryController(
|
||||
return;
|
||||
}
|
||||
|
||||
var profileToRemoveItemFrom = request.FromOwner is null || request.FromOwner?.Id == pmcData.Id
|
||||
? pmcData
|
||||
: _profileHelper.GetFullProfile(sessionId).CharacterData.ScavData;
|
||||
var profileToRemoveItemFrom =
|
||||
request.FromOwner is null || request.FromOwner?.Id == pmcData.Id
|
||||
? pmcData
|
||||
: _profileHelper.GetFullProfile(sessionId).CharacterData.ScavData;
|
||||
|
||||
_inventoryHelper.RemoveItem(profileToRemoveItemFrom, request.Item, sessionId, output);
|
||||
}
|
||||
|
||||
@@ -37,8 +37,11 @@ public class LauncherController(
|
||||
public ConnectResponse Connect()
|
||||
{
|
||||
// Get all possible profile types + filter out any that are blacklisted
|
||||
var profileTemplates = _databaseService.GetProfileTemplates()
|
||||
.Where(profile => !_coreConfig.Features.CreateNewProfileTypesBlacklist.Contains(profile.Key))
|
||||
var profileTemplates = _databaseService
|
||||
.GetProfileTemplates()
|
||||
.Where(profile =>
|
||||
!_coreConfig.Features.CreateNewProfileTypesBlacklist.Contains(profile.Key)
|
||||
)
|
||||
.ToDictionary();
|
||||
|
||||
return new ConnectResponse
|
||||
@@ -46,7 +49,7 @@ public class LauncherController(
|
||||
BackendUrl = _httpServerHelper.GetBackendUrl(),
|
||||
Name = _coreConfig.ServerName,
|
||||
Editions = profileTemplates.Select(x => x.Key).ToList(),
|
||||
ProfileDescriptions = GetProfileDescriptions(profileTemplates)
|
||||
ProfileDescriptions = GetProfileDescriptions(profileTemplates),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -55,7 +58,9 @@ public class LauncherController(
|
||||
/// </summary>
|
||||
/// <param name="profileTemplates">Profiles to get descriptions of</param>
|
||||
/// <returns>Dictionary of profile types with related descriptive text</returns>
|
||||
protected Dictionary<string, string> GetProfileDescriptions(Dictionary<string, ProfileSides> profileTemplates)
|
||||
protected Dictionary<string, string> GetProfileDescriptions(
|
||||
Dictionary<string, ProfileSides> profileTemplates
|
||||
)
|
||||
{
|
||||
var result = new Dictionary<string, string>();
|
||||
foreach (var (profileKey, profile) in profileTemplates)
|
||||
@@ -72,7 +77,11 @@ public class LauncherController(
|
||||
/// <returns></returns>
|
||||
public Info? Find(string? sessionId)
|
||||
{
|
||||
return sessionId is not null && _saveServer.GetProfiles().TryGetValue(sessionId, out var profile) ? profile.ProfileInfo : null;
|
||||
return
|
||||
sessionId is not null
|
||||
&& _saveServer.GetProfiles().TryGetValue(sessionId, out var profile)
|
||||
? profile.ProfileInfo
|
||||
: null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -126,7 +135,7 @@ public class LauncherController(
|
||||
Username = info.Username,
|
||||
Password = info.Password,
|
||||
IsWiped = true,
|
||||
Edition = info.Edition
|
||||
Edition = info.Edition,
|
||||
};
|
||||
_saveServer.CreateProfile(newProfileDetails);
|
||||
|
||||
@@ -229,7 +238,10 @@ public class LauncherController(
|
||||
/// <returns>Dictionary of mod name and mod details</returns>
|
||||
public Dictionary<string, AbstractModMetadata> GetLoadedServerMods()
|
||||
{
|
||||
return _loadedMods.ToDictionary(sptMod => sptMod.ModMetadata?.Name ?? "UNKNOWN MOD", sptMod => sptMod.ModMetadata);
|
||||
return _loadedMods.ToDictionary(
|
||||
sptMod => sptMod.ModMetadata?.Name ?? "UNKNOWN MOD",
|
||||
sptMod => sptMod.ModMetadata
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -48,7 +48,10 @@ public class LauncherV2Controller(
|
||||
|
||||
foreach (var profileKvP in dbProfiles)
|
||||
{
|
||||
result.TryAdd(profileKvP.Key, _localisationService.GetText(profileKvP.Value.DescriptionLocaleKey));
|
||||
result.TryAdd(
|
||||
profileKvP.Key,
|
||||
_localisationService.GetText(profileKvP.Value.DescriptionLocaleKey)
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -174,7 +177,7 @@ public class LauncherV2Controller(
|
||||
Username = info.Username,
|
||||
Password = info.Password,
|
||||
IsWiped = true,
|
||||
Edition = info.Edition
|
||||
Edition = info.Edition,
|
||||
};
|
||||
|
||||
_saveServer.CreateProfile(newProfileDetails);
|
||||
@@ -204,7 +207,10 @@ public class LauncherV2Controller(
|
||||
{
|
||||
foreach (var profile in _saveServer.GetProfiles())
|
||||
{
|
||||
if (info.Username == profile.Value.ProfileInfo!.Username && info.Password == profile.Value.ProfileInfo.Password)
|
||||
if (
|
||||
info.Username == profile.Value.ProfileInfo!.Username
|
||||
&& info.Password == profile.Value.ProfileInfo.Password
|
||||
)
|
||||
{
|
||||
return profile.Key;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ using SPTarkov.Server.Core.Services;
|
||||
using SPTarkov.Server.Core.Utils.Cloners;
|
||||
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
|
||||
|
||||
|
||||
namespace SPTarkov.Server.Core.Controllers;
|
||||
|
||||
[Injectable]
|
||||
@@ -54,7 +53,7 @@ public class LocationController(
|
||||
return new LocationsGenerateAllResponse
|
||||
{
|
||||
Locations = locationResult,
|
||||
Paths = locationsFromDb.Base!.Paths
|
||||
Paths = locationsFromDb.Base!.Paths,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -70,9 +70,9 @@ public class MatchController(
|
||||
RaidMode = "Online",
|
||||
Mode = "deathmatch",
|
||||
ShortId = null,
|
||||
AdditionalInfo = null
|
||||
}
|
||||
]
|
||||
AdditionalInfo = null,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return output;
|
||||
@@ -85,11 +85,7 @@ public class MatchController(
|
||||
/// <returns>MatchGroupStatusResponse</returns>
|
||||
public MatchGroupStatusResponse GetGroupStatus(MatchGroupStatusRequest request)
|
||||
{
|
||||
return new MatchGroupStatusResponse
|
||||
{
|
||||
Players = [],
|
||||
MaxPveCountExceeded = false
|
||||
};
|
||||
return new MatchGroupStatusResponse { Players = [], MaxPveCountExceeded = false };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -138,7 +134,10 @@ public class MatchController(
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="request">Start raid request</param>
|
||||
/// <returns>StartLocalRaidResponseData</returns>
|
||||
public StartLocalRaidResponseData StartLocalRaid(string sessionId, StartLocalRaidRequestData request)
|
||||
public StartLocalRaidResponseData StartLocalRaid(
|
||||
string sessionId,
|
||||
StartLocalRaidRequestData request
|
||||
)
|
||||
{
|
||||
return _locationLifecycleService.StartLocalRaid(sessionId, request);
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@ using SPTarkov.Server.Core.Routers;
|
||||
namespace SPTarkov.Server.Core.Controllers;
|
||||
|
||||
[Injectable]
|
||||
public class NoteController(
|
||||
EventOutputHolder _eventOutputHolder
|
||||
)
|
||||
public class NoteController(EventOutputHolder _eventOutputHolder)
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
@@ -20,13 +18,10 @@ public class NoteController(
|
||||
public ItemEventRouterResponse AddNote(
|
||||
PmcData pmcData,
|
||||
NoteActionRequest request,
|
||||
string sessionId)
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var newNote = new Note
|
||||
{
|
||||
Time = request.Note.Time,
|
||||
Text = request.Note.Text
|
||||
};
|
||||
var newNote = new Note { Time = request.Note.Time, Text = request.Note.Text };
|
||||
pmcData.Notes.DataNotes.Add(newNote);
|
||||
|
||||
return _eventOutputHolder.GetOutput(sessionId);
|
||||
@@ -41,7 +36,8 @@ public class NoteController(
|
||||
public ItemEventRouterResponse EditNote(
|
||||
PmcData pmcData,
|
||||
NoteActionRequest request,
|
||||
string sessionId)
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var noteToEdit = pmcData.Notes.DataNotes[request.Index!.Value];
|
||||
noteToEdit.Time = request.Note.Time;
|
||||
@@ -59,7 +55,8 @@ public class NoteController(
|
||||
public ItemEventRouterResponse DeleteNote(
|
||||
PmcData pmcData,
|
||||
NoteActionRequest request,
|
||||
string sessionId)
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
pmcData.Notes?.DataNotes?.RemoveAt(request.Index!.Value);
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ public class NotifierController(
|
||||
ChannelId = sessionId,
|
||||
Url = "",
|
||||
NotifierServer = GetServer(sessionId),
|
||||
WebSocket = _notifierHelper.GetWebSocketServer(sessionId)
|
||||
WebSocket = _notifierHelper.GetWebSocketServer(sessionId),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -33,10 +33,7 @@ public class PresetController(
|
||||
|
||||
// Get root items tpl
|
||||
var tpl = preset.Items.FirstOrDefault()?.Template;
|
||||
result.TryAdd(tpl, new PresetCacheDetails
|
||||
{
|
||||
PresetIds = []
|
||||
});
|
||||
result.TryAdd(tpl, new PresetCacheDetails { PresetIds = [] });
|
||||
|
||||
result.TryGetValue(tpl, out var details);
|
||||
details.PresetIds.Add(presetId);
|
||||
|
||||
@@ -23,8 +23,7 @@ public class PrestigeController(
|
||||
/// </summary>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns>Prestige</returns>
|
||||
public Prestige GetPrestige(
|
||||
string sessionId)
|
||||
public Prestige GetPrestige(string sessionId)
|
||||
{
|
||||
return _databaseService.GetTemplates().Prestige;
|
||||
}
|
||||
@@ -59,9 +58,7 @@ public class PrestigeController(
|
||||
/// </list>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task ObtainPrestige(
|
||||
string sessionId,
|
||||
ObtainPrestigeRequestList request)
|
||||
public async Task ObtainPrestige(string sessionId, ObtainPrestigeRequestList request)
|
||||
{
|
||||
var profile = _profileHelper.GetFullProfile(sessionId);
|
||||
if (profile is not null)
|
||||
@@ -69,7 +66,7 @@ public class PrestigeController(
|
||||
var pendingPrestige = new PendingPrestige
|
||||
{
|
||||
PrestigeLevel = profile.CharacterData.PmcData.Info.PrestigeLevel + 1,
|
||||
Items = request
|
||||
Items = request,
|
||||
};
|
||||
|
||||
profile.SptData.PendingPrestige = pendingPrestige;
|
||||
|
||||
@@ -57,7 +57,9 @@ public class ProfileController(
|
||||
var profile = _saveServer.GetProfile(sessionId);
|
||||
if (profile?.CharacterData == null)
|
||||
{
|
||||
throw new Exception($"Unable to find character data for id: {sessionId}. Profile may be corrupt");
|
||||
throw new Exception(
|
||||
$"Unable to find character data for id: {sessionId}. Profile may be corrupt"
|
||||
);
|
||||
}
|
||||
|
||||
var pmc = profile.CharacterData.PmcData;
|
||||
@@ -81,7 +83,7 @@ public class ProfileController(
|
||||
MaxLevel = maxLvl,
|
||||
Edition = profile.ProfileInfo?.Edition ?? "",
|
||||
ProfileId = profile.ProfileInfo?.ProfileId ?? "",
|
||||
SptData = _profileHelper.GetDefaultSptDataObject()
|
||||
SptData = _profileHelper.GetDefaultSptDataObject(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -93,12 +95,13 @@ public class ProfileController(
|
||||
Side = pmc.Info.Side,
|
||||
CurrentLevel = pmc.Info.Level,
|
||||
CurrentExperience = pmc.Info.Experience ?? 0,
|
||||
PreviousExperience = currentLevel == 0 ? 0 : _profileHelper.GetExperience(currentLevel.Value),
|
||||
PreviousExperience =
|
||||
currentLevel == 0 ? 0 : _profileHelper.GetExperience(currentLevel.Value),
|
||||
NextLevel = xpToNextLevel,
|
||||
MaxLevel = maxLvl,
|
||||
Edition = profile.ProfileInfo?.Edition ?? "",
|
||||
ProfileId = profile.ProfileInfo?.ProfileId ?? "",
|
||||
SptData = profile.SptData
|
||||
SptData = profile.SptData,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -118,7 +121,10 @@ public class ProfileController(
|
||||
/// <param name="request">Create profile request</param>
|
||||
/// <param name="sessionId">Player id</param>
|
||||
/// <returns>Player id</returns>
|
||||
public virtual async ValueTask<string> CreateProfile(ProfileCreateRequestData request, string sessionId)
|
||||
public virtual async ValueTask<string> CreateProfile(
|
||||
ProfileCreateRequestData request,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
return await _createProfileService.CreateProfile(sessionId, request);
|
||||
}
|
||||
@@ -140,7 +146,10 @@ public class ProfileController(
|
||||
/// <param name="request">Validate nickname request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns></returns>
|
||||
public virtual NicknameValidationResult ValidateNickname(ValidateNicknameRequestData request, string sessionId)
|
||||
public virtual NicknameValidationResult ValidateNickname(
|
||||
ValidateNicknameRequestData request,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
if (request.Nickname?.Length < 3)
|
||||
{
|
||||
@@ -162,13 +171,13 @@ public class ProfileController(
|
||||
/// <param name="request">Change nickname request</param>
|
||||
/// <param name="sessionId">Player id</param>
|
||||
/// <returns></returns>
|
||||
public virtual NicknameValidationResult ChangeNickname(ProfileChangeNicknameRequestData request, string sessionId)
|
||||
public virtual NicknameValidationResult ChangeNickname(
|
||||
ProfileChangeNicknameRequestData request,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var output = ValidateNickname(
|
||||
new ValidateNicknameRequestData
|
||||
{
|
||||
Nickname = request.Nickname
|
||||
},
|
||||
new ValidateNicknameRequestData { Nickname = request.Nickname },
|
||||
sessionId
|
||||
);
|
||||
|
||||
@@ -200,7 +209,10 @@ public class ProfileController(
|
||||
/// <param name="request">Search profiles request</param>
|
||||
/// <param name="sessionID">Player id</param>
|
||||
/// <returns>Found profiles</returns>
|
||||
public virtual List<SearchFriendResponse> SearchProfiles(SearchProfilesRequestData request, string sessionID)
|
||||
public virtual List<SearchFriendResponse> SearchProfiles(
|
||||
SearchProfilesRequestData request,
|
||||
string sessionID
|
||||
)
|
||||
{
|
||||
var result = new List<SearchFriendResponse>();
|
||||
|
||||
@@ -241,7 +253,7 @@ public class ProfileController(
|
||||
Status = "Free",
|
||||
Sid = "",
|
||||
Ip = "",
|
||||
Port = 0
|
||||
Port = 0,
|
||||
},
|
||||
new ProfileStatusData
|
||||
{
|
||||
@@ -250,9 +262,9 @@ public class ProfileController(
|
||||
Status = "Free",
|
||||
Sid = "",
|
||||
Ip = "",
|
||||
Port = 0
|
||||
}
|
||||
]
|
||||
Port = 0,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return response;
|
||||
@@ -264,13 +276,21 @@ public class ProfileController(
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <param name="request">Get other profile request</param>
|
||||
/// <returns>GetOtherProfileResponse</returns>
|
||||
public virtual GetOtherProfileResponse GetOtherProfile(string sessionId, GetOtherProfileRequest request)
|
||||
public virtual GetOtherProfileResponse GetOtherProfile(
|
||||
string sessionId,
|
||||
GetOtherProfileRequest request
|
||||
)
|
||||
{
|
||||
// Find the profile by the account ID, fall back to the current player if we can't find the account
|
||||
var profileToView = _profileHelper.GetFullProfileByAccountId(request.AccountId);
|
||||
if (profileToView?.CharacterData?.PmcData is null || profileToView.CharacterData.ScavData is null)
|
||||
if (
|
||||
profileToView?.CharacterData?.PmcData is null
|
||||
|| profileToView.CharacterData.ScavData is null
|
||||
)
|
||||
{
|
||||
_logger.Warning($"Unable to get profile: {request.AccountId} to show, falling back to own profile");
|
||||
_logger.Warning(
|
||||
$"Unable to get profile: {request.AccountId} to show, falling back to own profile"
|
||||
);
|
||||
profileToView = _profileHelper.GetFullProfile(sessionId);
|
||||
}
|
||||
|
||||
@@ -283,12 +303,17 @@ public class ProfileController(
|
||||
hideoutKeys.Add(profileToViewPmc.Inventory.HideoutCustomizationStashId);
|
||||
|
||||
// Find hideout items e.g. posters
|
||||
var hideoutRootItems = profileToViewPmc.Inventory.Items.Where(x => hideoutKeys.Contains(x.Id));
|
||||
var hideoutRootItems = profileToViewPmc.Inventory.Items.Where(x =>
|
||||
hideoutKeys.Contains(x.Id)
|
||||
);
|
||||
var itemsToReturn = new List<Item>();
|
||||
foreach (var rootItems in hideoutRootItems)
|
||||
{
|
||||
// Check each root items for children and add
|
||||
var itemWithChildren = _itemHelper.FindAndReturnChildrenAsItems(profileToViewPmc.Inventory.Items, rootItems.Id);
|
||||
var itemWithChildren = _itemHelper.FindAndReturnChildrenAsItems(
|
||||
profileToViewPmc.Inventory.Items,
|
||||
rootItems.Id
|
||||
);
|
||||
itemsToReturn.AddRange(itemWithChildren);
|
||||
}
|
||||
|
||||
@@ -301,10 +326,12 @@ public class ProfileController(
|
||||
Nickname = profileToViewPmc.Info.Nickname,
|
||||
Side = profileToViewPmc.Info.Side,
|
||||
Experience = profileToViewPmc.Info.Experience,
|
||||
MemberCategory = (int)(profileToViewPmc.Info.MemberCategory ?? MemberCategory.Default),
|
||||
MemberCategory = (int)(
|
||||
profileToViewPmc.Info.MemberCategory ?? MemberCategory.Default
|
||||
),
|
||||
BannedState = profileToViewPmc.Info.BannedState,
|
||||
BannedUntil = profileToViewPmc.Info.BannedUntil,
|
||||
RegistrationDate = profileToViewPmc.Info.RegistrationDate
|
||||
RegistrationDate = profileToViewPmc.Info.RegistrationDate,
|
||||
},
|
||||
Customization = new OtherProfileCustomization
|
||||
{
|
||||
@@ -312,13 +339,13 @@ public class ProfileController(
|
||||
Body = profileToViewPmc.Customization.Body,
|
||||
Feet = profileToViewPmc.Customization.Feet,
|
||||
Hands = profileToViewPmc.Customization.Hands,
|
||||
Dogtag = profileToViewPmc.Customization.DogTag
|
||||
Dogtag = profileToViewPmc.Customization.DogTag,
|
||||
},
|
||||
Skills = profileToViewPmc.Skills,
|
||||
Equipment = new OtherProfileEquipment
|
||||
{
|
||||
Id = profileToViewPmc.Inventory.Equipment,
|
||||
Items = profileToViewPmc.Inventory.Items
|
||||
Items = profileToViewPmc.Inventory.Items,
|
||||
},
|
||||
Achievements = profileToViewPmc.Achievements,
|
||||
FavoriteItems = _profileHelper.GetOtherProfileFavorites(profileToViewPmc),
|
||||
@@ -327,21 +354,21 @@ public class ProfileController(
|
||||
Eft = new OtherProfileSubStats
|
||||
{
|
||||
TotalInGameTime = profileToViewPmc.Stats.Eft.TotalInGameTime,
|
||||
OverAllCounters = profileToViewPmc.Stats.Eft.OverallCounters
|
||||
}
|
||||
OverAllCounters = profileToViewPmc.Stats.Eft.OverallCounters,
|
||||
},
|
||||
},
|
||||
ScavStats = new OtherProfileStats
|
||||
{
|
||||
Eft = new OtherProfileSubStats
|
||||
{
|
||||
TotalInGameTime = profileToViewScav.Stats.Eft.TotalInGameTime,
|
||||
OverAllCounters = profileToViewScav.Stats.Eft.OverallCounters
|
||||
}
|
||||
OverAllCounters = profileToViewScav.Stats.Eft.OverallCounters,
|
||||
},
|
||||
},
|
||||
Hideout = profileToViewPmc.Hideout,
|
||||
CustomizationStash = profileToViewPmc.Inventory.HideoutCustomizationStashId,
|
||||
HideoutAreaStashes = profileToViewPmc.Inventory.HideoutAreaStashes,
|
||||
Items = itemsToReturn
|
||||
Items = itemsToReturn,
|
||||
};
|
||||
|
||||
return profile;
|
||||
|
||||
@@ -14,7 +14,6 @@ using SPTarkov.Server.Core.Utils;
|
||||
using SPTarkov.Server.Core.Utils.Cloners;
|
||||
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
|
||||
|
||||
|
||||
namespace SPTarkov.Server.Core.Controllers;
|
||||
|
||||
[Injectable]
|
||||
@@ -63,13 +62,19 @@ public class QuestController(
|
||||
/// <param name="acceptedQuest">Quest accepted</param>
|
||||
/// <param name="sessionID">Session/Player id</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
public ItemEventRouterResponse AcceptQuest(PmcData pmcData, AcceptQuestRequestData acceptedQuest, string sessionID)
|
||||
public ItemEventRouterResponse AcceptQuest(
|
||||
PmcData pmcData,
|
||||
AcceptQuestRequestData acceptedQuest,
|
||||
string sessionID
|
||||
)
|
||||
{
|
||||
var acceptQuestResponse = _eventOutputHolder.GetOutput(sessionID);
|
||||
|
||||
// Does quest exist in profile
|
||||
// Restarting a failed quest can mean quest exists in profile
|
||||
var existingQuestStatus = pmcData.Quests.FirstOrDefault(x => x.QId == acceptedQuest.QuestId);
|
||||
var existingQuestStatus = pmcData.Quests.FirstOrDefault(x =>
|
||||
x.QId == acceptedQuest.QuestId
|
||||
);
|
||||
if (existingQuestStatus is not null)
|
||||
{
|
||||
// Update existing
|
||||
@@ -81,7 +86,11 @@ public class QuestController(
|
||||
else
|
||||
{
|
||||
// Add new quest to server profile
|
||||
var newQuest = _questHelper.GetQuestReadyForProfile(pmcData, QuestStatusEnum.Started, acceptedQuest);
|
||||
var newQuest = _questHelper.GetQuestReadyForProfile(
|
||||
pmcData,
|
||||
QuestStatusEnum.Started,
|
||||
acceptedQuest
|
||||
);
|
||||
pmcData.Quests.Add(newQuest);
|
||||
}
|
||||
|
||||
@@ -94,10 +103,10 @@ public class QuestController(
|
||||
AddTaskConditionCountersToProfile(
|
||||
questFromDb.Conditions.AvailableForFinish,
|
||||
pmcData,
|
||||
acceptedQuest.QuestId);
|
||||
acceptedQuest.QuestId
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Get messageId of text to send to player as text message in game
|
||||
var messageId = _questHelper.GetMessageIdForQuestStart(
|
||||
questFromDb.StartedMessageText,
|
||||
@@ -120,7 +129,9 @@ public class QuestController(
|
||||
MessageType.QuestStart,
|
||||
messageId,
|
||||
startedQuestRewardItems.ToList(),
|
||||
_timeUtil.GetHoursAsSeconds((int) _questHelper.GetMailItemRedeemTimeHoursForProfile(pmcData))
|
||||
_timeUtil.GetHoursAsSeconds(
|
||||
(int)_questHelper.GetMailItemRedeemTimeHoursForProfile(pmcData)
|
||||
)
|
||||
);
|
||||
|
||||
// Having accepted new quest, look for newly unlocked quests and inform client of them
|
||||
@@ -142,7 +153,11 @@ public class QuestController(
|
||||
/// <param name="questConditions">Conditions to iterate over and possibly add to profile</param>
|
||||
/// <param name="pmcData">Players PMC profile</param>
|
||||
/// <param name="questId">Quest where conditions originated</param>
|
||||
protected void AddTaskConditionCountersToProfile(List<QuestCondition> questConditions, PmcData pmcData, string questId)
|
||||
protected void AddTaskConditionCountersToProfile(
|
||||
List<QuestCondition> questConditions,
|
||||
PmcData pmcData,
|
||||
string questId
|
||||
)
|
||||
{
|
||||
foreach (var condition in questConditions)
|
||||
{
|
||||
@@ -161,7 +176,7 @@ public class QuestController(
|
||||
Id = condition.Id,
|
||||
SourceId = questId,
|
||||
Type = condition.ConditionType,
|
||||
Value = 0
|
||||
Value = 0,
|
||||
};
|
||||
break;
|
||||
}
|
||||
@@ -178,7 +193,11 @@ public class QuestController(
|
||||
/// <param name="request">Complete quest request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
public ItemEventRouterResponse CompleteQuest(PmcData pmcData, CompleteQuestRequestData request, string sessionId)
|
||||
public ItemEventRouterResponse CompleteQuest(
|
||||
PmcData pmcData,
|
||||
CompleteQuestRequestData request,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
return _questHelper.CompleteQuest(pmcData, request, sessionId);
|
||||
}
|
||||
@@ -191,7 +210,11 @@ public class QuestController(
|
||||
/// <param name="request">Handover request</param>
|
||||
/// <param name="sessionID">Session/Player id</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
public ItemEventRouterResponse HandoverQuest(PmcData pmcData, HandoverQuestRequestData request, string sessionID)
|
||||
public ItemEventRouterResponse HandoverQuest(
|
||||
PmcData pmcData,
|
||||
HandoverQuestRequestData request,
|
||||
string sessionID
|
||||
)
|
||||
{
|
||||
var quest = _questHelper.GetQuestFromDb(request.QuestId, pmcData);
|
||||
List<string> handoverQuestTypes = ["HandoverItem", "WeaponAssembly"];
|
||||
@@ -202,7 +225,11 @@ public class QuestController(
|
||||
|
||||
// Decrement number of items handed in
|
||||
QuestCondition? handoverRequirements = null;
|
||||
foreach (var condition in quest.Conditions.AvailableForFinish.Where(condition => condition.Id == request.ConditionId))
|
||||
foreach (
|
||||
var condition in quest.Conditions.AvailableForFinish.Where(condition =>
|
||||
condition.Id == request.ConditionId
|
||||
)
|
||||
)
|
||||
{
|
||||
// Not a handover quest type, skip
|
||||
if (!handoverQuestTypes.Contains(condition.ConditionType))
|
||||
@@ -216,7 +243,7 @@ public class QuestController(
|
||||
|
||||
if (pmcData.TaskConditionCounters.TryGetValue("ConditionId", out var counter))
|
||||
{
|
||||
handedInCount -= (int) (counter.Value ?? 0);
|
||||
handedInCount -= (int)(counter.Value ?? 0);
|
||||
|
||||
if (handedInCount <= 0)
|
||||
{
|
||||
@@ -228,7 +255,7 @@ public class QuestController(
|
||||
questId = request.QuestId,
|
||||
conditionId = request.ConditionId,
|
||||
profileCounter = counter.Value,
|
||||
value = handedInCount
|
||||
value = handedInCount,
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -242,15 +269,26 @@ public class QuestController(
|
||||
|
||||
if (isItemHandoverQuest && handedInCount == 0)
|
||||
{
|
||||
return ShowRepeatableQuestInvalidConditionError(request.QuestId, request.ConditionId, output);
|
||||
return ShowRepeatableQuestInvalidConditionError(
|
||||
request.QuestId,
|
||||
request.ConditionId,
|
||||
output
|
||||
);
|
||||
}
|
||||
|
||||
var totalItemCountToRemove = 0d;
|
||||
foreach (var itemHandover in request.Items)
|
||||
{
|
||||
var matchingItemInProfile = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == itemHandover.Id);
|
||||
if (!(matchingItemInProfile is not null && handoverRequirements.Target.List.Contains(matchingItemInProfile.Template)))
|
||||
// Item handed in by player doesn't match what was requested
|
||||
var matchingItemInProfile = pmcData.Inventory.Items.FirstOrDefault(item =>
|
||||
item.Id == itemHandover.Id
|
||||
);
|
||||
if (
|
||||
!(
|
||||
matchingItemInProfile is not null
|
||||
&& handoverRequirements.Target.List.Contains(matchingItemInProfile.Template)
|
||||
)
|
||||
)
|
||||
// Item handed in by player doesn't match what was requested
|
||||
{
|
||||
return ShowQuestItemHandoverMatchError(
|
||||
request,
|
||||
@@ -261,7 +299,10 @@ public class QuestController(
|
||||
}
|
||||
|
||||
// Remove the right quantity of given items
|
||||
var itemCountToRemove = Math.Min(itemHandover.Count ?? 0, handedInCount - totalItemCountToRemove);
|
||||
var itemCountToRemove = Math.Min(
|
||||
itemHandover.Count ?? 0,
|
||||
handedInCount - totalItemCountToRemove
|
||||
);
|
||||
totalItemCountToRemove += itemCountToRemove;
|
||||
if (itemHandover.Count - itemCountToRemove > 0)
|
||||
{
|
||||
@@ -269,7 +310,7 @@ public class QuestController(
|
||||
_questHelper.ChangeItemStack(
|
||||
pmcData,
|
||||
itemHandover.Id,
|
||||
(int) (itemHandover.Count - itemCountToRemove),
|
||||
(int)(itemHandover.Count - itemCountToRemove),
|
||||
sessionID,
|
||||
output
|
||||
);
|
||||
@@ -283,17 +324,16 @@ public class QuestController(
|
||||
else
|
||||
{
|
||||
// Remove item with children
|
||||
var toRemove = _itemHelper.FindAndReturnChildrenByItems(pmcData.Inventory.Items, itemHandover.Id);
|
||||
var toRemove = _itemHelper.FindAndReturnChildrenByItems(
|
||||
pmcData.Inventory.Items,
|
||||
itemHandover.Id
|
||||
);
|
||||
var index = pmcData.Inventory.Items.Count;
|
||||
|
||||
// Important: don't tell the client to remove the attachments, it will handle it
|
||||
output.ProfileChanges[sessionID]
|
||||
.Items.DeletedItems.Add(
|
||||
new Item
|
||||
{
|
||||
Id = itemHandover.Id
|
||||
}
|
||||
);
|
||||
output
|
||||
.ProfileChanges[sessionID]
|
||||
.Items.DeletedItems.Add(new Item { Id = itemHandover.Id });
|
||||
|
||||
// Important: loop backward when removing items from the array we're looping on
|
||||
while (index-- > 0)
|
||||
@@ -315,7 +355,7 @@ public class QuestController(
|
||||
childItems.RemoveAt(0); // Remove the parent
|
||||
|
||||
// Sort by the current `location` and update
|
||||
childItems.Sort((a, b) => (int) a.Location > (int) b.Location ? 1 : -1);
|
||||
childItems.Sort((a, b) => (int)a.Location > (int)b.Location ? 1 : -1);
|
||||
|
||||
for (var i = 0; i < childItems.Count; i++)
|
||||
{
|
||||
@@ -344,15 +384,15 @@ public class QuestController(
|
||||
/// <param name="conditionId">Relevant condition id that failed</param>
|
||||
/// <param name="output">Client response</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
protected ItemEventRouterResponse ShowRepeatableQuestInvalidConditionError(string questId, string conditionId, ItemEventRouterResponse output)
|
||||
protected ItemEventRouterResponse ShowRepeatableQuestInvalidConditionError(
|
||||
string questId,
|
||||
string conditionId,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
var errorMessage = _localisationService.GetText(
|
||||
"repeatable-quest_handover_failed_condition_invalid",
|
||||
new
|
||||
{
|
||||
questId,
|
||||
conditionId
|
||||
}
|
||||
new { questId, conditionId }
|
||||
);
|
||||
_logger.Error(errorMessage);
|
||||
|
||||
@@ -367,8 +407,12 @@ public class QuestController(
|
||||
/// <param name="handoverRequirements">Quest handover requirements</param>
|
||||
/// <param name="output">Response to send to user</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
protected ItemEventRouterResponse ShowQuestItemHandoverMatchError(HandoverQuestRequestData handoverQuestRequest, Item? itemHandedOver,
|
||||
QuestCondition? handoverRequirements, ItemEventRouterResponse output)
|
||||
protected ItemEventRouterResponse ShowQuestItemHandoverMatchError(
|
||||
HandoverQuestRequestData handoverQuestRequest,
|
||||
Item? itemHandedOver,
|
||||
QuestCondition? handoverRequirements,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
var errorMessage = _localisationService.GetText(
|
||||
"quest-handover_wrong_item",
|
||||
@@ -376,7 +420,7 @@ public class QuestController(
|
||||
{
|
||||
questId = handoverQuestRequest.QuestId,
|
||||
handedInTpl = itemHandedOver?.Template ?? "UNKNOWN",
|
||||
requiredTpl = handoverRequirements.Target.List.FirstOrDefault()
|
||||
requiredTpl = handoverRequirements.Target.List.FirstOrDefault(),
|
||||
}
|
||||
);
|
||||
_logger.Error(errorMessage);
|
||||
@@ -392,7 +436,12 @@ public class QuestController(
|
||||
/// <param name="conditionId">Backend counter id to update</param>
|
||||
/// <param name="questId">Quest id counter is associated with</param>
|
||||
/// <param name="counterValue">Value to increment the backend counter with</param>
|
||||
protected void UpdateProfileTaskConditionCounterValue(PmcData pmcData, string conditionId, string questId, double counterValue)
|
||||
protected void UpdateProfileTaskConditionCounterValue(
|
||||
PmcData pmcData,
|
||||
string conditionId,
|
||||
string questId,
|
||||
double counterValue
|
||||
)
|
||||
{
|
||||
if (pmcData.TaskConditionCounters.GetValueOrDefault(conditionId) != null)
|
||||
{
|
||||
@@ -401,13 +450,16 @@ public class QuestController(
|
||||
return;
|
||||
}
|
||||
|
||||
pmcData.TaskConditionCounters.Add(conditionId, new TaskConditionCounter
|
||||
{
|
||||
Id = conditionId,
|
||||
SourceId = questId,
|
||||
Type = "HandoverItem",
|
||||
Value = counterValue
|
||||
});
|
||||
pmcData.TaskConditionCounters.Add(
|
||||
conditionId,
|
||||
new TaskConditionCounter
|
||||
{
|
||||
Id = conditionId,
|
||||
SourceId = questId,
|
||||
Type = "HandoverItem",
|
||||
Value = counterValue,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -418,7 +470,12 @@ public class QuestController(
|
||||
/// <param name="sessionID">Session/Player id</param>
|
||||
/// <param name="output"></param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
public ItemEventRouterResponse FailQuest(PmcData pmcData, FailQuestRequestData request, string sessionID, ItemEventRouterResponse output)
|
||||
public ItemEventRouterResponse FailQuest(
|
||||
PmcData pmcData,
|
||||
FailQuestRequestData request,
|
||||
string sessionID,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
_questHelper.FailQuest(pmcData, request, sessionID, output);
|
||||
|
||||
|
||||
@@ -114,8 +114,9 @@ public class RagfairController
|
||||
// Check profile is capable of creating offers
|
||||
var pmcProfile = profile.CharacterData.PmcData;
|
||||
if (
|
||||
pmcProfile.RagfairInfo is not null &&
|
||||
pmcProfile.Info.Level >= _databaseService.GetGlobals().Configuration.RagFair.MinUserLevel
|
||||
pmcProfile.RagfairInfo is not null
|
||||
&& pmcProfile.Info.Level
|
||||
>= _databaseService.GetGlobals().Configuration.RagFair.MinUserLevel
|
||||
)
|
||||
{
|
||||
_ragfairOfferHelper.ProcessOffersOnProfile(sessionId);
|
||||
@@ -139,19 +140,28 @@ public class RagfairController
|
||||
{
|
||||
Offers = [],
|
||||
OffersCount = searchRequest.Limit,
|
||||
SelectedCategory = searchRequest.HandbookId
|
||||
SelectedCategory = searchRequest.HandbookId,
|
||||
};
|
||||
|
||||
// Get all offers ready for sorting/filtering below
|
||||
result.Offers = GetOffersForSearchType(searchRequest, itemsToAdd, traderAssorts, profile.CharacterData.PmcData);
|
||||
result.Offers = GetOffersForSearchType(
|
||||
searchRequest,
|
||||
itemsToAdd,
|
||||
traderAssorts,
|
||||
profile.CharacterData.PmcData
|
||||
);
|
||||
|
||||
// Client requested a category refresh
|
||||
if (searchRequest.UpdateOfferCount.GetValueOrDefault(false))
|
||||
{
|
||||
result.Categories = GetSpecificCategories(profile.CharacterData.PmcData, searchRequest, result.Offers);
|
||||
result.Categories = GetSpecificCategories(
|
||||
profile.CharacterData.PmcData,
|
||||
searchRequest,
|
||||
result.Offers
|
||||
);
|
||||
}
|
||||
|
||||
// Adjust index value of offers found to start at 0
|
||||
// Adjust index value of offers found to start at 0
|
||||
AddIndexValueToOffers(result.Offers);
|
||||
|
||||
// Sort offers
|
||||
@@ -171,7 +181,11 @@ public class RagfairController
|
||||
}
|
||||
|
||||
// Update trader offers' values, Lock quest-linked offers + adjust offer buy limits
|
||||
foreach (var traderOffer in result.Offers.Where(offer => _ragfairOfferHelper.OfferIsFromTrader(offer)))
|
||||
foreach (
|
||||
var traderOffer in result.Offers.Where(offer =>
|
||||
_ragfairOfferHelper.OfferIsFromTrader(offer)
|
||||
)
|
||||
)
|
||||
{
|
||||
// For the items, check the barter schemes. The method getDisplayableAssorts sets a flag sptQuestLocked
|
||||
// to true if the quest is not completed yet
|
||||
@@ -239,11 +253,7 @@ public class RagfairController
|
||||
_logger.Warning(
|
||||
_localisationService.GetText(
|
||||
"ragfair-unable_to_adjust_stack_count_assort_not_found",
|
||||
new
|
||||
{
|
||||
offerId = offer.Items.First().Id,
|
||||
traderId = offer.User.Id
|
||||
}
|
||||
new { offerId = offer.Items.First().Id, traderId = offer.User.Id }
|
||||
)
|
||||
);
|
||||
|
||||
@@ -288,7 +298,7 @@ public class RagfairController
|
||||
// Get specific assort purchase data and set current purchase buy value
|
||||
traderPurchases.TryGetValue(assortId, out var assortTraderPurchaseData);
|
||||
|
||||
offer.BuyRestrictionCurrent = (int?) assortTraderPurchaseData?.PurchaseCount ?? 0;
|
||||
offer.BuyRestrictionCurrent = (int?)assortTraderPurchaseData?.PurchaseCount ?? 0;
|
||||
offer.BuyRestrictionMax = offerRootItem.Upd.BuyRestrictionMax;
|
||||
}
|
||||
|
||||
@@ -313,12 +323,16 @@ public class RagfairController
|
||||
/// <param name="searchRequest">Client search request data</param>
|
||||
/// <param name="offers">Ragfair offers to get categories for</param>
|
||||
/// <returns>Record with templates + counts</returns>
|
||||
protected Dictionary<string, int> GetSpecificCategories(PmcData pmcProfile, SearchRequestData searchRequest,
|
||||
List<RagfairOffer> offers)
|
||||
protected Dictionary<string, int> GetSpecificCategories(
|
||||
PmcData pmcProfile,
|
||||
SearchRequestData searchRequest,
|
||||
List<RagfairOffer> offers
|
||||
)
|
||||
{
|
||||
// Linked/required search categories
|
||||
var playerHasFleaUnlocked =
|
||||
pmcProfile.Info.Level >= _databaseService.GetGlobals().Configuration.RagFair.MinUserLevel;
|
||||
pmcProfile.Info.Level
|
||||
>= _databaseService.GetGlobals().Configuration.RagFair.MinUserLevel;
|
||||
List<RagfairOffer> offerPool = [];
|
||||
if (IsLinkedSearch(searchRequest) || IsRequiredSearch(searchRequest))
|
||||
{
|
||||
@@ -340,7 +354,11 @@ public class RagfairController
|
||||
return new Dictionary<string, int>();
|
||||
}
|
||||
|
||||
return _ragfairServer.GetAllActiveCategories(playerHasFleaUnlocked, searchRequest, offerPool);
|
||||
return _ragfairServer.GetAllActiveCategories(
|
||||
playerHasFleaUnlocked,
|
||||
searchRequest,
|
||||
offerPool
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -371,14 +389,22 @@ public class RagfairController
|
||||
/// <param name="traderAssorts">Trader assorts</param>
|
||||
/// <param name="pmcProfile"></param>
|
||||
/// <returns>Array of offers</returns>
|
||||
protected List<RagfairOffer> GetOffersForSearchType(SearchRequestData searchRequest, List<string> itemsToAdd,
|
||||
protected List<RagfairOffer> GetOffersForSearchType(
|
||||
SearchRequestData searchRequest,
|
||||
List<string> itemsToAdd,
|
||||
Dictionary<string, TraderAssort> traderAssorts,
|
||||
PmcData pmcProfile)
|
||||
PmcData pmcProfile
|
||||
)
|
||||
{
|
||||
// Searching for items in preset menu
|
||||
if (searchRequest.BuildCount > 0)
|
||||
{
|
||||
return _ragfairOfferHelper.GetOffersForBuild(searchRequest, itemsToAdd, traderAssorts, pmcProfile);
|
||||
return _ragfairOfferHelper.GetOffersForBuild(
|
||||
searchRequest,
|
||||
itemsToAdd,
|
||||
traderAssorts,
|
||||
pmcProfile
|
||||
);
|
||||
}
|
||||
|
||||
if (searchRequest.NeededSearchId?.Length > 0)
|
||||
@@ -387,7 +413,12 @@ public class RagfairController
|
||||
}
|
||||
|
||||
// Searching for general items
|
||||
return _ragfairOfferHelper.GetValidOffers(searchRequest, itemsToAdd, traderAssorts, pmcProfile);
|
||||
return _ragfairOfferHelper.GetValidOffers(
|
||||
searchRequest,
|
||||
itemsToAdd,
|
||||
traderAssorts,
|
||||
pmcProfile
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -396,8 +427,10 @@ public class RagfairController
|
||||
/// <param name="getPriceRequest">Client request object</param>
|
||||
/// <param name="ignoreTraderOffers">OPTIONAL - Should trader offers be ignored in the calculation</param>
|
||||
/// <returns>min/avg/max values for an item based on flea offers available</returns>
|
||||
public GetItemPriceResult GetItemMinAvgMaxFleaPriceValues(GetMarketPriceRequestData getPriceRequest,
|
||||
bool ignoreTraderOffers = true)
|
||||
public GetItemPriceResult GetItemMinAvgMaxFleaPriceValues(
|
||||
GetMarketPriceRequestData getPriceRequest,
|
||||
bool ignoreTraderOffers = true
|
||||
)
|
||||
{
|
||||
// Get all items of tpl
|
||||
var offers = _ragfairOfferService.GetOffersOfType(getPriceRequest.TemplateId);
|
||||
@@ -415,7 +448,7 @@ public class RagfairController
|
||||
{
|
||||
Avg = Math.Round(average),
|
||||
Min = minMax.Min,
|
||||
Max = minMax.Max
|
||||
Max = minMax.Max,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -431,11 +464,15 @@ public class RagfairController
|
||||
{
|
||||
Avg = tplPrice,
|
||||
Min = tplPrice,
|
||||
Max = tplPrice
|
||||
Max = tplPrice,
|
||||
};
|
||||
}
|
||||
|
||||
protected double GetAveragePriceFromOffers(List<RagfairOffer> offers, MinMax<double> minMax, bool ignoreTraderOffers)
|
||||
protected double GetAveragePriceFromOffers(
|
||||
List<RagfairOffer> offers,
|
||||
MinMax<double> minMax,
|
||||
bool ignoreTraderOffers
|
||||
)
|
||||
{
|
||||
var sum = 0d;
|
||||
var totalOfferCount = 0;
|
||||
@@ -488,14 +525,21 @@ public class RagfairController
|
||||
/// <param name="offerRequest">Flea list creation offer</param>
|
||||
/// <param name="sessionID">Session/Player id</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
public ItemEventRouterResponse AddPlayerOffer(PmcData pmcData, AddOfferRequestData offerRequest, string sessionID)
|
||||
public ItemEventRouterResponse AddPlayerOffer(
|
||||
PmcData pmcData,
|
||||
AddOfferRequestData offerRequest,
|
||||
string sessionID
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionID);
|
||||
var fullProfile = _profileHelper.GetFullProfile(sessionID);
|
||||
|
||||
if (!IsValidPlayerOfferRequest(offerRequest))
|
||||
{
|
||||
return _httpResponseUtil.AppendErrorToOutput(output, "Unable to add offer, check server for error");
|
||||
return _httpResponseUtil.AppendErrorToOutput(
|
||||
output,
|
||||
"Unable to add offer, check server for error"
|
||||
);
|
||||
}
|
||||
|
||||
var typeOfOffer = GetOfferType(offerRequest);
|
||||
@@ -540,7 +584,9 @@ public class RagfairController
|
||||
|
||||
if (offerRequest.Requirements is null)
|
||||
{
|
||||
_logger.Error(_localisationService.GetText("ragfair-unable_to_place_offer_with_no_requirements"));
|
||||
_logger.Error(
|
||||
_localisationService.GetText("ragfair-unable_to_place_offer_with_no_requirements")
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -588,8 +634,12 @@ public class RagfairController
|
||||
/// <param name="fullProfile">Full profile of player</param>
|
||||
/// <param name="output">output Response to send to client</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
protected ItemEventRouterResponse CreateMultiOffer(string sessionID, AddOfferRequestData offerRequest,
|
||||
SptProfile fullProfile, ItemEventRouterResponse output)
|
||||
protected ItemEventRouterResponse CreateMultiOffer(
|
||||
string sessionID,
|
||||
AddOfferRequestData offerRequest,
|
||||
SptProfile fullProfile,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
var pmcData = fullProfile.CharacterData.PmcData;
|
||||
// var itemsToListCount = offerRequest.Items.Count; // Wasn't used to commented out for now // Does not count stack size, only items
|
||||
@@ -625,17 +675,18 @@ public class RagfairController
|
||||
var rootOfferItem = offer.Items.First(x => x.Id == firstOfferItemId);
|
||||
|
||||
// Average offer price for single item (or whole weapon)
|
||||
var averages =
|
||||
GetItemMinAvgMaxFleaPriceValues(
|
||||
new GetMarketPriceRequestData
|
||||
{
|
||||
TemplateId = offer.Items[0].Template
|
||||
}
|
||||
);
|
||||
var averages = GetItemMinAvgMaxFleaPriceValues(
|
||||
new GetMarketPriceRequestData { TemplateId = offer.Items[0].Template }
|
||||
);
|
||||
|
||||
// Check for and apply item price modifer if it exists in config
|
||||
var averageOfferPrice = averages.Avg;
|
||||
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(rootOfferItem.Template, out var itemPriceModifer))
|
||||
if (
|
||||
_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(
|
||||
rootOfferItem.Template,
|
||||
out var itemPriceModifer
|
||||
)
|
||||
)
|
||||
{
|
||||
averageOfferPrice *= itemPriceModifer;
|
||||
}
|
||||
@@ -657,7 +708,7 @@ public class RagfairController
|
||||
);
|
||||
|
||||
// Create array of sell times for items listed
|
||||
offer.SellResults = _ragfairSellHelper.RollForSale(sellChancePercent, (int) stackCountTotal);
|
||||
offer.SellResults = _ragfairSellHelper.RollForSale(sellChancePercent, (int)stackCountTotal);
|
||||
|
||||
// Subtract flea market fee from stash
|
||||
if (_ragfairConfig.Sell.Fees)
|
||||
@@ -667,7 +718,7 @@ public class RagfairController
|
||||
rootOfferItem,
|
||||
pmcData,
|
||||
playerListedPriceInRub,
|
||||
(int) stackCountTotal,
|
||||
(int)stackCountTotal,
|
||||
offerRequest,
|
||||
output
|
||||
);
|
||||
@@ -700,8 +751,12 @@ public class RagfairController
|
||||
/// <param name="fullProfile">Full profile of player</param>
|
||||
/// <param name="output">Response to send to client</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
protected ItemEventRouterResponse CreatePackOffer(string sessionID, AddOfferRequestData offerRequest,
|
||||
SptProfile fullProfile, ItemEventRouterResponse output)
|
||||
protected ItemEventRouterResponse CreatePackOffer(
|
||||
string sessionID,
|
||||
AddOfferRequestData offerRequest,
|
||||
SptProfile fullProfile,
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
var pmcData = fullProfile.CharacterData.PmcData;
|
||||
// var itemsToListCount = offerRequest.Items.Count; // TODO: Wasn't used so commented out for now // Does not count stack size, only items
|
||||
@@ -730,22 +785,29 @@ public class RagfairController
|
||||
firstListingRootItem.Upd.StackObjectsCount = stackCountTotal;
|
||||
|
||||
// Create flea object
|
||||
var offer = CreatePlayerOffer(sessionID, offerRequest.Requirements, firstListingAndChildren, true);
|
||||
var offer = CreatePlayerOffer(
|
||||
sessionID,
|
||||
offerRequest.Requirements,
|
||||
firstListingAndChildren,
|
||||
true
|
||||
);
|
||||
|
||||
// This is the item that will be listed on flea, has merged stackObjectCount
|
||||
var newRootOfferItem = offer.Items[0]; // TODO: add logic like single/multi offers to find root item
|
||||
|
||||
// Single price for an item
|
||||
var averages = GetItemMinAvgMaxFleaPriceValues(
|
||||
new GetMarketPriceRequestData
|
||||
{
|
||||
TemplateId = firstListingRootItem.Template
|
||||
}
|
||||
new GetMarketPriceRequestData { TemplateId = firstListingRootItem.Template }
|
||||
);
|
||||
var singleItemPrice = averages.Avg;
|
||||
|
||||
// Check for and apply item price modifer if it exists in config
|
||||
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(newRootOfferItem.Template, out var itemPriceModifer))
|
||||
if (
|
||||
_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(
|
||||
newRootOfferItem.Template,
|
||||
out var itemPriceModifer
|
||||
)
|
||||
)
|
||||
{
|
||||
singleItemPrice *= itemPriceModifer;
|
||||
}
|
||||
@@ -767,7 +829,11 @@ public class RagfairController
|
||||
);
|
||||
|
||||
// Create array of sell times for items listed + sell all at once as it's a pack
|
||||
offer.SellResults = _ragfairSellHelper.RollForSale(sellChancePercent, (int) stackCountTotal, true);
|
||||
offer.SellResults = _ragfairSellHelper.RollForSale(
|
||||
sellChancePercent,
|
||||
(int)stackCountTotal,
|
||||
true
|
||||
);
|
||||
|
||||
// Subtract flea market fee from stash
|
||||
if (_ragfairConfig.Sell.Fees)
|
||||
@@ -777,7 +843,7 @@ public class RagfairController
|
||||
newRootOfferItem,
|
||||
pmcData,
|
||||
playerListedPriceInRub,
|
||||
(int) stackCountTotal,
|
||||
(int)stackCountTotal,
|
||||
offerRequest,
|
||||
output
|
||||
);
|
||||
@@ -809,22 +875,30 @@ public class RagfairController
|
||||
/// <param name="fullProfile">Full profile of player</param>
|
||||
/// <param name="output">Response to send to client</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
protected ItemEventRouterResponse CreateSingleOffer(string sessionID, AddOfferRequestData offerRequest,
|
||||
protected ItemEventRouterResponse CreateSingleOffer(
|
||||
string sessionID,
|
||||
AddOfferRequestData offerRequest,
|
||||
SptProfile fullProfile,
|
||||
ItemEventRouterResponse output)
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
var pmcData = fullProfile.CharacterData.PmcData;
|
||||
// var itemsToListCount = offerRequest.Items.Count; // Wasn't used so commented out for now // Does not count stack size, only items
|
||||
|
||||
// Find items to be listed on flea from player inventory
|
||||
var inventoryItemsToSell = GetItemsToListOnFleaFromInventory(pmcData, offerRequest.Items);
|
||||
if (inventoryItemsToSell.Items is null || !string.IsNullOrEmpty(inventoryItemsToSell.ErrorMessage))
|
||||
if (
|
||||
inventoryItemsToSell.Items is null
|
||||
|| !string.IsNullOrEmpty(inventoryItemsToSell.ErrorMessage)
|
||||
)
|
||||
{
|
||||
_httpResponseUtil.AppendErrorToOutput(output, inventoryItemsToSell.ErrorMessage);
|
||||
}
|
||||
|
||||
// Total count of items summed using their stack counts
|
||||
var stackCountTotal = _ragfairOfferHelper.GetTotalStackCountSize(inventoryItemsToSell.Items);
|
||||
var stackCountTotal = _ragfairOfferHelper.GetTotalStackCountSize(
|
||||
inventoryItemsToSell.Items
|
||||
);
|
||||
|
||||
// Checks are done, create offer
|
||||
var playerListedPriceInRub = CalculateRequirementsPriceInRub(offerRequest.Requirements);
|
||||
@@ -841,17 +915,18 @@ public class RagfairController
|
||||
var qualityMultiplier = _itemHelper.GetItemQualityModifierForItems(offer.Items, true);
|
||||
|
||||
// Average offer price for single item (or whole weapon)
|
||||
var averages =
|
||||
GetItemMinAvgMaxFleaPriceValues(
|
||||
new GetMarketPriceRequestData
|
||||
{
|
||||
TemplateId = offerRootItem.Template
|
||||
}
|
||||
);
|
||||
var averages = GetItemMinAvgMaxFleaPriceValues(
|
||||
new GetMarketPriceRequestData { TemplateId = offerRootItem.Template }
|
||||
);
|
||||
var averageOfferPriceSingleItem = averages.Avg;
|
||||
|
||||
// Check for and apply item price modifer if it exists in config
|
||||
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(offerRootItem.Template, out var itemPriceModifer))
|
||||
if (
|
||||
_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(
|
||||
offerRootItem.Template,
|
||||
out var itemPriceModifer
|
||||
)
|
||||
)
|
||||
{
|
||||
averageOfferPriceSingleItem *= itemPriceModifer;
|
||||
}
|
||||
@@ -865,7 +940,7 @@ public class RagfairController
|
||||
playerListedPriceInRub,
|
||||
qualityMultiplier
|
||||
);
|
||||
offer.SellResults = _ragfairSellHelper.RollForSale(sellChancePercent, (int) stackCountTotal);
|
||||
offer.SellResults = _ragfairSellHelper.RollForSale(sellChancePercent, (int)stackCountTotal);
|
||||
|
||||
// Subtract flea market fee from stash
|
||||
if (_ragfairConfig.Sell.Fees)
|
||||
@@ -875,7 +950,7 @@ public class RagfairController
|
||||
offerRootItem,
|
||||
pmcData,
|
||||
playerListedPriceInRub,
|
||||
(int) stackCountTotal,
|
||||
(int)stackCountTotal,
|
||||
offerRequest,
|
||||
output
|
||||
);
|
||||
@@ -916,10 +991,13 @@ public class RagfairController
|
||||
double requirementsPriceInRub,
|
||||
int itemStackCount,
|
||||
AddOfferRequestData offerRequest,
|
||||
ItemEventRouterResponse output)
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
// Get tax from cache hydrated earlier by client, if that's missing fall back to server calculation (inaccurate)
|
||||
var storedClientTaxValue = _ragfairTaxService.GetStoredClientOfferTaxValueById(offerRequest.Items[0]);
|
||||
var storedClientTaxValue = _ragfairTaxService.GetStoredClientOfferTaxValueById(
|
||||
offerRequest.Items[0]
|
||||
);
|
||||
var tax = storedClientTaxValue is not null
|
||||
? storedClientTaxValue.Fee
|
||||
: _ragfairTaxService.CalculateTax(
|
||||
@@ -932,7 +1010,9 @@ public class RagfairController
|
||||
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Offer tax to charge: {tax}, pulled from client: {storedClientTaxValue.Count is not null}");
|
||||
_logger.Debug(
|
||||
$"Offer tax to charge: {tax}, pulled from client: {storedClientTaxValue.Count is not null}"
|
||||
);
|
||||
}
|
||||
|
||||
// cleanup of cache now we've used the tax value from it
|
||||
@@ -960,32 +1040,34 @@ public class RagfairController
|
||||
/// <param name="items">Item(s) to list on flea (with children)</param>
|
||||
/// <param name="sellInOnePiece">Is this a pack offer</param>
|
||||
/// <returns>RagfairOffer</returns>
|
||||
protected RagfairOffer CreatePlayerOffer(string sessionId, List<Requirement> requirements, List<Item> items,
|
||||
bool sellInOnePiece)
|
||||
protected RagfairOffer CreatePlayerOffer(
|
||||
string sessionId,
|
||||
List<Requirement> requirements,
|
||||
List<Item> items,
|
||||
bool sellInOnePiece
|
||||
)
|
||||
{
|
||||
const int loyalLevel = 1;
|
||||
var formattedItems = items.Select(item =>
|
||||
{
|
||||
var isChild = items.Any(subItem => subItem.Id == item.ParentId);
|
||||
{
|
||||
var isChild = items.Any(subItem => subItem.Id == item.ParentId);
|
||||
|
||||
return new Item
|
||||
{
|
||||
Id = item.Id,
|
||||
Template = item.Template,
|
||||
ParentId = isChild ? item.ParentId : "hideout",
|
||||
SlotId = isChild ? item.SlotId : "hideout",
|
||||
Upd = item.Upd
|
||||
};
|
||||
}
|
||||
);
|
||||
return new Item
|
||||
{
|
||||
Id = item.Id,
|
||||
Template = item.Template,
|
||||
ParentId = isChild ? item.ParentId : "hideout",
|
||||
SlotId = isChild ? item.SlotId : "hideout",
|
||||
Upd = item.Upd,
|
||||
};
|
||||
});
|
||||
|
||||
var formattedRequirements = requirements.Select(item => new BarterScheme
|
||||
{
|
||||
Template = item.Template,
|
||||
Count = item.Count,
|
||||
OnlyFunctional = item.OnlyFunctional
|
||||
}
|
||||
);
|
||||
{
|
||||
Template = item.Template,
|
||||
Count = item.Count,
|
||||
OnlyFunctional = item.OnlyFunctional,
|
||||
});
|
||||
|
||||
return _ragfairOfferGenerator.CreateAndAddFleaOffer(
|
||||
sessionId,
|
||||
@@ -993,7 +1075,7 @@ public class RagfairController
|
||||
formattedItems.ToList(),
|
||||
formattedRequirements.ToList(),
|
||||
loyalLevel,
|
||||
(int?) items.FirstOrDefault()?.Upd?.StackObjectsCount ?? 1,
|
||||
(int?)items.FirstOrDefault()?.Upd?.StackObjectsCount ?? 1,
|
||||
sellInOnePiece
|
||||
);
|
||||
}
|
||||
@@ -1006,17 +1088,21 @@ public class RagfairController
|
||||
protected double CalculateRequirementsPriceInRub(List<Requirement> requirements)
|
||||
{
|
||||
return requirements.Sum(requirement =>
|
||||
{
|
||||
if (
|
||||
string.IsNullOrEmpty(requirement.Template)
|
||||
|| !requirement.Count.HasValue
|
||||
|| requirement.Count == 0
|
||||
)
|
||||
{
|
||||
if (string.IsNullOrEmpty(requirement.Template) || !requirement.Count.HasValue || requirement.Count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _paymentHelper.IsMoneyTpl(requirement.Template)
|
||||
? _handbookHelper.InRUB(requirement.Count.Value, requirement.Template)
|
||||
: _itemHelper.GetDynamicItemPrice(requirement.Template).Value * requirement.Count.Value;
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
|
||||
return _paymentHelper.IsMoneyTpl(requirement.Template)
|
||||
? _handbookHelper.InRUB(requirement.Count.Value, requirement.Template)
|
||||
: _itemHelper.GetDynamicItemPrice(requirement.Template).Value
|
||||
* requirement.Count.Value;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1025,8 +1111,10 @@ public class RagfairController
|
||||
/// <param name="pmcData">Players PMC profile</param>
|
||||
/// <param name="itemIdsFromFleaOfferRequest">Request</param>
|
||||
/// <returns>GetItemsToListOnFleaFromInventoryResult</returns>
|
||||
protected GetItemsToListOnFleaFromInventoryResult GetItemsToListOnFleaFromInventory(PmcData pmcData,
|
||||
List<string> itemIdsFromFleaOfferRequest)
|
||||
protected GetItemsToListOnFleaFromInventoryResult GetItemsToListOnFleaFromInventory(
|
||||
PmcData pmcData,
|
||||
List<string> itemIdsFromFleaOfferRequest
|
||||
)
|
||||
{
|
||||
List<List<Item>> itemsToReturn = [];
|
||||
var errorMessage = string.Empty;
|
||||
@@ -1039,40 +1127,38 @@ public class RagfairController
|
||||
{
|
||||
errorMessage = _localisationService.GetText(
|
||||
"ragfair-unable_to_find_item_in_inventory",
|
||||
new
|
||||
{
|
||||
id = itemId
|
||||
}
|
||||
new { id = itemId }
|
||||
);
|
||||
_logger.Error(errorMessage);
|
||||
|
||||
return new GetItemsToListOnFleaFromInventoryResult
|
||||
{
|
||||
Items = itemsToReturn,
|
||||
ErrorMessage = errorMessage
|
||||
ErrorMessage = errorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
_itemHelper.FixItemStackCount(rootItem);
|
||||
|
||||
itemsToReturn.Add(_itemHelper.FindAndReturnChildrenAsItems(pmcData.Inventory.Items, itemId));
|
||||
itemsToReturn.Add(
|
||||
_itemHelper.FindAndReturnChildrenAsItems(pmcData.Inventory.Items, itemId)
|
||||
);
|
||||
}
|
||||
|
||||
if (itemsToReturn?.Count == 0)
|
||||
{
|
||||
errorMessage = _localisationService.GetText("ragfair-unable_to_find_requested_items_in_inventory");
|
||||
errorMessage = _localisationService.GetText(
|
||||
"ragfair-unable_to_find_requested_items_in_inventory"
|
||||
);
|
||||
_logger.Error(errorMessage);
|
||||
|
||||
return new GetItemsToListOnFleaFromInventoryResult
|
||||
{
|
||||
ErrorMessage = errorMessage
|
||||
};
|
||||
return new GetItemsToListOnFleaFromInventoryResult { ErrorMessage = errorMessage };
|
||||
}
|
||||
|
||||
return new GetItemsToListOnFleaFromInventoryResult
|
||||
{
|
||||
Items = itemsToReturn,
|
||||
ErrorMessage = errorMessage
|
||||
ErrorMessage = errorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1094,11 +1180,7 @@ public class RagfairController
|
||||
_logger.Warning(
|
||||
_localisationService.GetText(
|
||||
"ragfair-unable_to_remove_offer_not_found_in_profile",
|
||||
new
|
||||
{
|
||||
profileId = sessionId,
|
||||
offerId
|
||||
}
|
||||
new { profileId = sessionId, offerId }
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1109,13 +1191,7 @@ public class RagfairController
|
||||
if (playerOffer is null)
|
||||
{
|
||||
_logger.Error(
|
||||
_localisationService.GetText(
|
||||
"ragfair-offer_not_found_in_profile",
|
||||
new
|
||||
{
|
||||
offerId
|
||||
}
|
||||
)
|
||||
_localisationService.GetText("ragfair-offer_not_found_in_profile", new { offerId })
|
||||
);
|
||||
|
||||
return _httpResponseUtil.AppendErrorToOutput(
|
||||
@@ -1130,10 +1206,12 @@ public class RagfairController
|
||||
{
|
||||
// `expireSeconds` Default is 71 seconds
|
||||
var newEndTime = _ragfairConfig.Sell.ExpireSeconds + _timeUtil.GetTimeStamp();
|
||||
playerOffer.EndTime = (long?) Math.Round((double) newEndTime);
|
||||
playerOffer.EndTime = (long?)Math.Round((double)newEndTime);
|
||||
}
|
||||
|
||||
_logger.Debug($"Flagged player offer: {offerId} for expiry in: {TimeSpan.FromTicks(playerOffer.EndTime.Value).ToString()}");
|
||||
_logger.Debug(
|
||||
$"Flagged player offer: {offerId} for expiry in: {TimeSpan.FromTicks(playerOffer.EndTime.Value).ToString()}"
|
||||
);
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -1144,7 +1222,10 @@ public class RagfairController
|
||||
/// <param name="extendRequest">Extend time request</param>
|
||||
/// <param name="sessionId">Session/Player id</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
public ItemEventRouterResponse ExtendOffer(ExtendOfferRequestData extendRequest, string sessionId)
|
||||
public ItemEventRouterResponse ExtendOffer(
|
||||
ExtendOfferRequestData extendRequest,
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionId);
|
||||
|
||||
@@ -1158,10 +1239,7 @@ public class RagfairController
|
||||
_logger.Warning(
|
||||
_localisationService.GetText(
|
||||
"ragfair-offer_not_found_in_profile",
|
||||
new
|
||||
{
|
||||
offerId = extendRequest.OfferId
|
||||
}
|
||||
new { offerId = extendRequest.OfferId }
|
||||
)
|
||||
);
|
||||
return _httpResponseUtil.AppendErrorToOutput(
|
||||
@@ -1179,7 +1257,8 @@ public class RagfairController
|
||||
var sellInOncePiece = playerOffer.SellInOnePiece.GetValueOrDefault(false);
|
||||
if (!sellInOncePiece)
|
||||
{
|
||||
count = (int) playerOffer.Items.Sum(offerItem => offerItem.Upd?.StackObjectsCount ?? 0);
|
||||
count = (int)
|
||||
playerOffer.Items.Sum(offerItem => offerItem.Upd?.StackObjectsCount ?? 0);
|
||||
}
|
||||
|
||||
var tax = _ragfairTaxService.CalculateTax(
|
||||
@@ -1202,7 +1281,7 @@ public class RagfairController
|
||||
}
|
||||
|
||||
// Add extra time to offer
|
||||
playerOffers[playerOfferIndex].EndTime += (long?) Math.Round((decimal) secondsToAdd);
|
||||
playerOffers[playerOfferIndex].EndTime += (long?)Math.Round((decimal)secondsToAdd);
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -1213,7 +1292,10 @@ public class RagfairController
|
||||
/// <param name="currency">What currency: RUB, EURO, USD</param>
|
||||
/// <param name="value">Amount of currency</param>
|
||||
/// <returns>ProcessBuyTradeRequestData</returns>
|
||||
protected ProcessBuyTradeRequestData CreateBuyTradeRequestObject(CurrencyType currency, double value)
|
||||
protected ProcessBuyTradeRequestData CreateBuyTradeRequestObject(
|
||||
CurrencyType currency,
|
||||
double value
|
||||
)
|
||||
{
|
||||
return new ProcessBuyTradeRequestData
|
||||
{
|
||||
@@ -1224,13 +1306,13 @@ public class RagfairController
|
||||
new IdWithCount
|
||||
{
|
||||
Id = _paymentHelper.GetCurrency(currency),
|
||||
Count = Math.Round(value)
|
||||
}
|
||||
Count = Math.Round(value),
|
||||
},
|
||||
],
|
||||
Type = "",
|
||||
ItemId = "",
|
||||
Count = 0,
|
||||
SchemeId = 0
|
||||
SchemeId = 0,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1258,16 +1340,8 @@ public class RagfairController
|
||||
|
||||
public record GetItemsToListOnFleaFromInventoryResult
|
||||
{
|
||||
public List<List<Item>>? Items
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public List<List<Item>>? Items { get; set; }
|
||||
|
||||
public string? ErrorMessage
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string? ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@ using SPTarkov.Server.Core.Services;
|
||||
namespace SPTarkov.Server.Core.Controllers;
|
||||
|
||||
[Injectable]
|
||||
public class RepairController(
|
||||
EventOutputHolder _eventOutputHolder,
|
||||
RepairService _repairService
|
||||
)
|
||||
public class RepairController(EventOutputHolder _eventOutputHolder, RepairService _repairService)
|
||||
{
|
||||
/// <summary>
|
||||
/// Handle TraderRepair event
|
||||
@@ -24,14 +21,20 @@ public class RepairController(
|
||||
public ItemEventRouterResponse TraderRepair(
|
||||
string sessionID,
|
||||
TraderRepairActionDataRequest body,
|
||||
PmcData pmcData)
|
||||
PmcData pmcData
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionID);
|
||||
|
||||
// find the item to repair
|
||||
foreach (var repairItem in body.RepairItems)
|
||||
{
|
||||
var repairDetails = _repairService.RepairItemByTrader(sessionID, pmcData, repairItem, body.TId);
|
||||
var repairDetails = _repairService.RepairItemByTrader(
|
||||
sessionID,
|
||||
pmcData,
|
||||
repairItem,
|
||||
body.TId
|
||||
);
|
||||
|
||||
_repairService.PayForRepair(
|
||||
sessionID,
|
||||
@@ -68,7 +71,8 @@ public class RepairController(
|
||||
public ItemEventRouterResponse RepairWithKit(
|
||||
string sessionId,
|
||||
RepairActionDataRequest body,
|
||||
PmcData pmcData)
|
||||
PmcData pmcData
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionId);
|
||||
|
||||
|
||||
@@ -53,7 +53,11 @@ public class RepeatableQuestController(
|
||||
/// <param name="acceptedQuest">Repeatable quest accepted</param>
|
||||
/// <param name="sessionID">Session/Player id</param>
|
||||
/// <returns>ItemEventRouterResponse</returns>
|
||||
public ItemEventRouterResponse AcceptRepeatableQuest(PmcData pmcData, AcceptQuestRequestData acceptedQuest, string sessionID)
|
||||
public ItemEventRouterResponse AcceptRepeatableQuest(
|
||||
PmcData pmcData,
|
||||
AcceptQuestRequestData acceptedQuest,
|
||||
string sessionID
|
||||
)
|
||||
{
|
||||
// Create and store quest status object inside player profile
|
||||
var newRepeatableQuest = _questHelper.GetQuestReadyForProfile(
|
||||
@@ -74,11 +78,16 @@ public class RepeatableQuestController(
|
||||
)
|
||||
);
|
||||
|
||||
throw new Exception(_localisationService.GetText("repeatable-unable_to_accept_quest_see_log"));
|
||||
throw new Exception(
|
||||
_localisationService.GetText("repeatable-unable_to_accept_quest_see_log")
|
||||
);
|
||||
}
|
||||
|
||||
// Some scav quests need to be added to scav profile for them to show up in-raid
|
||||
if (repeatableQuestProfile.Side == "Scav" && _questTypes.Contains(repeatableQuestProfile.Type.ToString()))
|
||||
if (
|
||||
repeatableQuestProfile.Side == "Scav"
|
||||
&& _questTypes.Contains(repeatableQuestProfile.Type.ToString())
|
||||
)
|
||||
{
|
||||
var fullProfile = _profileHelper.GetFullProfile(sessionID);
|
||||
|
||||
@@ -98,8 +107,11 @@ public class RepeatableQuestController(
|
||||
/// <param name="changeRequest">Change quest request</param>
|
||||
/// <param name="sessionID">Session/Player id</param>
|
||||
/// <returns></returns>
|
||||
public ItemEventRouterResponse ChangeRepeatableQuest(PmcData pmcData, RepeatableQuestChangeRequest changeRequest,
|
||||
string sessionID)
|
||||
public ItemEventRouterResponse ChangeRepeatableQuest(
|
||||
PmcData pmcData,
|
||||
RepeatableQuestChangeRequest changeRequest,
|
||||
string sessionID
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionID);
|
||||
|
||||
@@ -112,7 +124,9 @@ public class RepeatableQuestController(
|
||||
if (repeatables.RepeatableType is null || repeatables.Quest is null)
|
||||
{
|
||||
// Unable to find quest being replaced
|
||||
var message = _localisationService.GetText("quest-unable_to_find_repeatable_to_replace");
|
||||
var message = _localisationService.GetText(
|
||||
"quest-unable_to_find_repeatable_to_replace"
|
||||
);
|
||||
_logger.Error(message);
|
||||
|
||||
return _httpResponseUtil.AppendErrorToOutput(output, message);
|
||||
@@ -125,8 +139,8 @@ public class RepeatableQuestController(
|
||||
var replacedQuestTraderId = questToReplace.TraderId;
|
||||
|
||||
// Update active quests to exclude the quest we're replacing
|
||||
repeatablesOfTypeInProfile.ActiveQuests = repeatablesOfTypeInProfile.ActiveQuests.Where(quest => quest.Id != changeRequest.QuestId
|
||||
)
|
||||
repeatablesOfTypeInProfile.ActiveQuests = repeatablesOfTypeInProfile
|
||||
.ActiveQuests.Where(quest => quest.Id != changeRequest.QuestId)
|
||||
.ToList();
|
||||
|
||||
// Save for later cost calculations
|
||||
@@ -138,7 +152,8 @@ public class RepeatableQuestController(
|
||||
repeatablesOfTypeInProfile.ChangeRequirement.Remove(changeRequest.QuestId);
|
||||
|
||||
// Get config for this repeatable subtype (daily/weekly/scav)
|
||||
var repeatableConfig = _questConfig.RepeatableQuests.FirstOrDefault(config => config.Name == repeatablesOfTypeInProfile.Name
|
||||
var repeatableConfig = _questConfig.RepeatableQuests.FirstOrDefault(config =>
|
||||
config.Name == repeatablesOfTypeInProfile.Name
|
||||
);
|
||||
|
||||
// If the configuration dictates to replace with the same quest type, adjust the available quest types
|
||||
@@ -148,7 +163,10 @@ public class RepeatableQuestController(
|
||||
}
|
||||
|
||||
// Generate meta-data for what type/level range of quests can be generated for player
|
||||
var allowedQuestTypes = GenerateQuestPool(repeatableConfig, pmcData.Info.Level.GetValueOrDefault(1));
|
||||
var allowedQuestTypes = GenerateQuestPool(
|
||||
repeatableConfig,
|
||||
pmcData.Info.Level.GetValueOrDefault(1)
|
||||
);
|
||||
var newRepeatableQuest = AttemptToGenerateRepeatableQuest(
|
||||
sessionID,
|
||||
pmcData,
|
||||
@@ -186,7 +204,7 @@ public class RepeatableQuestController(
|
||||
repeatablesOfTypeInProfile.ChangeRequirement[newRepeatableQuest.Id] = new ChangeRequirement
|
||||
{
|
||||
ChangeCost = newRepeatableQuest.ChangeCost,
|
||||
ChangeStandingCost = _randomUtil.GetArrayValue(repeatableConfig.StandingChangeCost)
|
||||
ChangeStandingCost = _randomUtil.GetArrayValue(repeatableConfig.StandingChangeCost),
|
||||
};
|
||||
|
||||
// Check if we should charge player for replacing quest
|
||||
@@ -201,12 +219,22 @@ public class RepeatableQuestController(
|
||||
var traderOfReplacedQuest = pmcData.TradersInfo[replacedQuestTraderId];
|
||||
traderOfReplacedQuest.Standing -= previousChangeRequirement.ChangeStandingCost;
|
||||
|
||||
var charismaBonus = _profileHelper.GetSkillFromProfile(pmcData, SkillTypes.Charisma)?.Progress ?? 0;
|
||||
var charismaBonus =
|
||||
_profileHelper.GetSkillFromProfile(pmcData, SkillTypes.Charisma)?.Progress ?? 0;
|
||||
foreach (var cost in previousChangeRequirement.ChangeCost)
|
||||
{
|
||||
// Not free, Charge player + apply charisma bonus to cost of replacement
|
||||
cost.Count = (int) Math.Truncate(cost.Count.Value * (1 - Math.Truncate(charismaBonus / 100) * 0.001));
|
||||
_paymentService.AddPaymentToOutput(pmcData, cost.TemplateId, cost.Count.Value, sessionID, output);
|
||||
cost.Count = (int)
|
||||
Math.Truncate(
|
||||
cost.Count.Value * (1 - Math.Truncate(charismaBonus / 100) * 0.001)
|
||||
);
|
||||
_paymentService.AddPaymentToOutput(
|
||||
pmcData,
|
||||
cost.TemplateId,
|
||||
cost.Count.Value,
|
||||
sessionID,
|
||||
output
|
||||
);
|
||||
if (output.Warnings.Count > 0)
|
||||
{
|
||||
return output;
|
||||
@@ -265,8 +293,11 @@ public class RepeatableQuestController(
|
||||
/// <param name="repeatableSubType">Can be daily / weekly / scav repeatable</param>
|
||||
/// <param name="repeatableTypeName">Subtype of repeatable quest: daily / weekly / scav</param>
|
||||
/// <returns>Is the repeatable being replaced for free</returns>
|
||||
protected bool UseFreeRefreshIfAvailable(SptProfile? fullProfile, PmcDataRepeatableQuest repeatableSubType,
|
||||
string repeatableTypeName)
|
||||
protected bool UseFreeRefreshIfAvailable(
|
||||
SptProfile? fullProfile,
|
||||
PmcDataRepeatableQuest repeatableSubType,
|
||||
string repeatableTypeName
|
||||
)
|
||||
{
|
||||
// No free refreshes, exit early
|
||||
if (repeatableSubType.FreeChangesAvailable <= 0)
|
||||
@@ -305,12 +336,14 @@ public class RepeatableQuestController(
|
||||
/// </summary>
|
||||
/// <param name="repeatablesOfTypeInProfile">repeatables that have the replaced and new quest</param>
|
||||
/// <param name="replacedQuestId">Id of the replaced quest</param>
|
||||
protected void CleanUpRepeatableChangeRequirements(PmcDataRepeatableQuest repeatablesOfTypeInProfile,
|
||||
string replacedQuestId)
|
||||
protected void CleanUpRepeatableChangeRequirements(
|
||||
PmcDataRepeatableQuest repeatablesOfTypeInProfile,
|
||||
string replacedQuestId
|
||||
)
|
||||
{
|
||||
if (repeatablesOfTypeInProfile.ActiveQuests.Count == 1)
|
||||
// Only one repeatable quest being replaced (e.g. scav_daily), remove everything ready for new quest requirement to be added
|
||||
// Will assist in cleanup of existing profiles data
|
||||
// Only one repeatable quest being replaced (e.g. scav_daily), remove everything ready for new quest requirement to be added
|
||||
// Will assist in cleanup of existing profiles data
|
||||
{
|
||||
repeatablesOfTypeInProfile.ChangeRequirement.Clear();
|
||||
|
||||
@@ -329,8 +362,12 @@ public class RepeatableQuestController(
|
||||
/// <param name="questTypePool">What type/level range of quests can be generated for player</param>
|
||||
/// <param name="repeatableConfig">Config for the quest type to generate</param>
|
||||
/// <returns></returns>
|
||||
protected RepeatableQuest? AttemptToGenerateRepeatableQuest(string sessionId, PmcData pmcData,
|
||||
QuestTypePool questTypePool, RepeatableQuestConfig repeatableConfig)
|
||||
protected RepeatableQuest? AttemptToGenerateRepeatableQuest(
|
||||
string sessionId,
|
||||
PmcData pmcData,
|
||||
QuestTypePool questTypePool,
|
||||
RepeatableQuestConfig repeatableConfig
|
||||
)
|
||||
{
|
||||
const int maxAttempts = 10;
|
||||
RepeatableQuest? newRepeatableQuest = null;
|
||||
@@ -346,7 +383,7 @@ public class RepeatableQuestController(
|
||||
);
|
||||
|
||||
if (newRepeatableQuest is not null)
|
||||
// Successfully generated a quest, exit loop
|
||||
// Successfully generated a quest, exit loop
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -356,7 +393,12 @@ public class RepeatableQuestController(
|
||||
|
||||
if (attempts > maxAttempts)
|
||||
{
|
||||
_logger.Error(_localisationService.GetText("quest-repeatable_generation_failed_please_report", attempts));
|
||||
_logger.Error(
|
||||
_localisationService.GetText(
|
||||
"quest-repeatable_generation_failed_please_report",
|
||||
attempts
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return newRepeatableQuest;
|
||||
@@ -370,7 +412,10 @@ public class RepeatableQuestController(
|
||||
protected void RemoveQuestFromProfile(SptProfile fullProfile, string questToReplaceId)
|
||||
{
|
||||
// Find quest we're replacing in pmc profile quests array and remove it
|
||||
_questHelper.FindAndRemoveQuestFromArrayIfExists(questToReplaceId, fullProfile.CharacterData.PmcData.Quests);
|
||||
_questHelper.FindAndRemoveQuestFromArrayIfExists(
|
||||
questToReplaceId,
|
||||
fullProfile.CharacterData.PmcData.Quests
|
||||
);
|
||||
|
||||
// Look for and remove quest we're replacing in scav profile too
|
||||
if (fullProfile.CharacterData.ScavData is not null)
|
||||
@@ -393,10 +438,11 @@ public class RepeatableQuestController(
|
||||
foreach (var repeatablesInProfile in pmcData.RepeatableQuests)
|
||||
{
|
||||
// Check for existing quest in (daily/weekly/scav arrays)
|
||||
var questToReplace =
|
||||
repeatablesInProfile.ActiveQuests?.FirstOrDefault(repeatable => repeatable.Id == questId);
|
||||
var questToReplace = repeatablesInProfile.ActiveQuests?.FirstOrDefault(repeatable =>
|
||||
repeatable.Id == questId
|
||||
);
|
||||
if (questToReplace is null)
|
||||
// Not found, skip to next repeatable subtype
|
||||
// Not found, skip to next repeatable subtype
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -404,7 +450,7 @@ public class RepeatableQuestController(
|
||||
return new GetRepeatableByIdResult
|
||||
{
|
||||
Quest = questToReplace,
|
||||
RepeatableType = repeatablesInProfile
|
||||
RepeatableType = repeatablesInProfile,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -443,12 +489,15 @@ public class RepeatableQuestController(
|
||||
foreach (var repeatableConfig in _questConfig.RepeatableQuests)
|
||||
{
|
||||
// Get daily/weekly data from profile, add empty object if missing
|
||||
var generatedRepeatables = GetRepeatableQuestSubTypeFromProfile(repeatableConfig, pmcData);
|
||||
var generatedRepeatables = GetRepeatableQuestSubTypeFromProfile(
|
||||
repeatableConfig,
|
||||
pmcData
|
||||
);
|
||||
var repeatableTypeLower = repeatableConfig.Name.ToLower();
|
||||
|
||||
var canAccessRepeatables = CanProfileAccessRepeatableQuests(repeatableConfig, pmcData);
|
||||
if (!canAccessRepeatables)
|
||||
// Don't send any repeatables, even existing ones
|
||||
// Don't send any repeatables, even existing ones
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -483,7 +532,10 @@ public class RepeatableQuestController(
|
||||
ProcessExpiredQuests(generatedRepeatables, pmcData);
|
||||
|
||||
// Create dynamic quest pool to avoid generating duplicates
|
||||
var questTypePool = GenerateQuestPool(repeatableConfig, pmcData.Info.Level.GetValueOrDefault(1));
|
||||
var questTypePool = GenerateQuestPool(
|
||||
repeatableConfig,
|
||||
pmcData.Info.Level.GetValueOrDefault(1)
|
||||
);
|
||||
|
||||
// Add repeatable quests of this loops sub-type (daily/weekly)
|
||||
for (var i = 0; i < GetQuestCount(repeatableConfig, fullProfile); i++)
|
||||
@@ -535,7 +587,9 @@ public class RepeatableQuestController(
|
||||
new ChangeRequirement
|
||||
{
|
||||
ChangeCost = quest.ChangeCost,
|
||||
ChangeStandingCost = _randomUtil.GetArrayValue(repeatableConfig.StandingChangeCost) // Randomise standing loss to replace
|
||||
ChangeStandingCost = _randomUtil.GetArrayValue(
|
||||
repeatableConfig.StandingChangeCost
|
||||
), // Randomise standing loss to replace
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -553,7 +607,7 @@ public class RepeatableQuestController(
|
||||
InactiveQuests = generatedRepeatables.InactiveQuests,
|
||||
ChangeRequirement = generatedRepeatables.ChangeRequirement,
|
||||
FreeChanges = generatedRepeatables.FreeChanges,
|
||||
FreeChangesAvailable = generatedRepeatables.FreeChangesAvailable
|
||||
FreeChangesAvailable = generatedRepeatables.FreeChangesAvailable,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -567,11 +621,14 @@ public class RepeatableQuestController(
|
||||
/// <param name="repeatableConfig">daily/weekly config</param>
|
||||
/// <param name="pmcData">Players PMC profile</param>
|
||||
/// <returns>PmcDataRepeatableQuest</returns>
|
||||
protected PmcDataRepeatableQuest GetRepeatableQuestSubTypeFromProfile(RepeatableQuestConfig repeatableConfig,
|
||||
PmcData pmcData)
|
||||
protected PmcDataRepeatableQuest GetRepeatableQuestSubTypeFromProfile(
|
||||
RepeatableQuestConfig repeatableConfig,
|
||||
PmcData pmcData
|
||||
)
|
||||
{
|
||||
// Get from profile, add if missing
|
||||
var repeatableQuestDetails = pmcData.RepeatableQuests.FirstOrDefault(repeatable => repeatable.Name == repeatableConfig.Name
|
||||
var repeatableQuestDetails = pmcData.RepeatableQuests.FirstOrDefault(repeatable =>
|
||||
repeatable.Name == repeatableConfig.Name
|
||||
);
|
||||
var hasAccess = _profileHelper.HasAccessToRepeatableFreeRefreshSystem(pmcData);
|
||||
|
||||
@@ -586,7 +643,7 @@ public class RepeatableQuestController(
|
||||
InactiveQuests = [],
|
||||
EndTime = 0,
|
||||
FreeChanges = hasAccess ? repeatableConfig.FreeChanges : 0,
|
||||
FreeChangesAvailable = hasAccess ? repeatableConfig.FreeChangesAvailable : 0
|
||||
FreeChangesAvailable = hasAccess ? repeatableConfig.FreeChangesAvailable : 0,
|
||||
};
|
||||
|
||||
// Add base object that holds repeatable data to profile
|
||||
@@ -610,10 +667,16 @@ public class RepeatableQuestController(
|
||||
/// <param name="repeatableConfig">Repeatable quest config</param>
|
||||
/// <param name="pmcData">Players PMC profile</param>
|
||||
/// <returns>True if profile has access to repeatables</returns>
|
||||
protected bool CanProfileAccessRepeatableQuests(RepeatableQuestConfig repeatableConfig, PmcData pmcData)
|
||||
protected bool CanProfileAccessRepeatableQuests(
|
||||
RepeatableQuestConfig repeatableConfig,
|
||||
PmcData pmcData
|
||||
)
|
||||
{
|
||||
// PMC and daily quests not unlocked yet
|
||||
if (repeatableConfig.Side == "Pmc" && !PlayerHasDailyPmcQuestsUnlocked(pmcData, repeatableConfig))
|
||||
if (
|
||||
repeatableConfig.Side == "Pmc"
|
||||
&& !PlayerHasDailyPmcQuestsUnlocked(pmcData, repeatableConfig)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -638,7 +701,10 @@ public class RepeatableQuestController(
|
||||
/// <param name="pmcData">Players PMC profile</param>
|
||||
/// <param name="repeatableConfig">Config of daily type to check</param>
|
||||
/// <returns>True if unlocked</returns>
|
||||
protected static bool PlayerHasDailyPmcQuestsUnlocked(PmcData pmcData, RepeatableQuestConfig repeatableConfig)
|
||||
protected static bool PlayerHasDailyPmcQuestsUnlocked(
|
||||
PmcData pmcData,
|
||||
RepeatableQuestConfig repeatableConfig
|
||||
)
|
||||
{
|
||||
return pmcData.Info.Level >= repeatableConfig.MinPlayerLevel;
|
||||
}
|
||||
@@ -650,9 +716,11 @@ public class RepeatableQuestController(
|
||||
/// <returns>True if unlocked</returns>
|
||||
protected bool PlayerHasDailyScavQuestsUnlocked(PmcData pmcData)
|
||||
{
|
||||
return pmcData?.Hideout?.Areas?.FirstOrDefault(hideoutArea => hideoutArea.Type == HideoutAreas.IntelligenceCenter)
|
||||
?.Level >=
|
||||
1;
|
||||
return pmcData
|
||||
?.Hideout?.Areas?.FirstOrDefault(hideoutArea =>
|
||||
hideoutArea.Type == HideoutAreas.IntelligenceCenter
|
||||
)
|
||||
?.Level >= 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -660,12 +728,17 @@ public class RepeatableQuestController(
|
||||
/// </summary>
|
||||
/// <param name="generatedRepeatables">Repeatables to process (daily/weekly)</param>
|
||||
/// <param name="pmcData">Players PMC profile</param>
|
||||
protected void ProcessExpiredQuests(PmcDataRepeatableQuest generatedRepeatables, PmcData pmcData)
|
||||
protected void ProcessExpiredQuests(
|
||||
PmcDataRepeatableQuest generatedRepeatables,
|
||||
PmcData pmcData
|
||||
)
|
||||
{
|
||||
var questsToKeep = new List<RepeatableQuest>();
|
||||
foreach (var activeQuest in generatedRepeatables.ActiveQuests)
|
||||
{
|
||||
var questStatusInProfile = pmcData.Quests.FirstOrDefault(quest => quest.QId == activeQuest.Id);
|
||||
var questStatusInProfile = pmcData.Quests.FirstOrDefault(quest =>
|
||||
quest.QId == activeQuest.Id
|
||||
);
|
||||
if (questStatusInProfile is null)
|
||||
{
|
||||
continue;
|
||||
@@ -723,8 +796,15 @@ public class RepeatableQuestController(
|
||||
// Add "any" to pickup quest pool
|
||||
questPool.Pool.Pickup.Locations[ELocationName.any] = ["any"];
|
||||
|
||||
var eliminationConfig = _repeatableQuestHelper.GetEliminationConfigByPmcLevel(pmcLevel, repeatableConfig);
|
||||
var targetsConfig = new ProbabilityObjectArray<string, BossInfo>(_mathUtil, _cloner, eliminationConfig.Targets);
|
||||
var eliminationConfig = _repeatableQuestHelper.GetEliminationConfigByPmcLevel(
|
||||
pmcLevel,
|
||||
repeatableConfig
|
||||
);
|
||||
var targetsConfig = new ProbabilityObjectArray<string, BossInfo>(
|
||||
_mathUtil,
|
||||
_cloner,
|
||||
eliminationConfig.Targets
|
||||
);
|
||||
|
||||
// Populate Elimination quest targets and their locations
|
||||
foreach (var target in targetsConfig)
|
||||
@@ -734,10 +814,7 @@ public class RepeatableQuestController(
|
||||
{
|
||||
questPool.Pool.Elimination.Targets.Add(
|
||||
target.Key,
|
||||
new TargetLocation
|
||||
{
|
||||
Locations = ["any"]
|
||||
}
|
||||
new TargetLocation { Locations = ["any"] }
|
||||
);
|
||||
|
||||
continue;
|
||||
@@ -747,16 +824,16 @@ public class RepeatableQuestController(
|
||||
var possibleLocations = repeatableConfig.Locations.Keys;
|
||||
var allowedLocations =
|
||||
target.Key == "Savage"
|
||||
? possibleLocations.Where(location => location != ELocationName.laboratory
|
||||
) // Exclude labs for Savage targets.
|
||||
? possibleLocations.Where(location => location != ELocationName.laboratory) // Exclude labs for Savage targets.
|
||||
: possibleLocations;
|
||||
|
||||
questPool.Pool.Elimination.Targets.Add(
|
||||
target.Key,
|
||||
new TargetLocation
|
||||
{
|
||||
Locations = allowedLocations.Select(x => x.ToString()).ToList()
|
||||
});
|
||||
Locations = allowedLocations.Select(x => x.ToString()).ToList(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return questPool;
|
||||
@@ -776,17 +853,17 @@ public class RepeatableQuestController(
|
||||
{
|
||||
Exploration = new ExplorationPool
|
||||
{
|
||||
Locations = new Dictionary<ELocationName, List<string>>()
|
||||
Locations = new Dictionary<ELocationName, List<string>>(),
|
||||
},
|
||||
Elimination = new EliminationPool
|
||||
{
|
||||
Targets = new Dictionary<string, TargetLocation>()
|
||||
Targets = new Dictionary<string, TargetLocation>(),
|
||||
},
|
||||
Pickup = new ExplorationPool
|
||||
{
|
||||
Locations = new Dictionary<ELocationName, List<string>>()
|
||||
}
|
||||
}
|
||||
Locations = new Dictionary<ELocationName, List<string>>(),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -805,23 +882,25 @@ public class RepeatableQuestController(
|
||||
}
|
||||
|
||||
// Add elite bonus to daily quests
|
||||
if (string.Equals(repeatableConfig.Name, "daily", StringComparison.OrdinalIgnoreCase) &&
|
||||
_profileHelper.HasEliteSkillLevel(SkillTypes.Charisma, fullProfile.CharacterData.PmcData))
|
||||
// Elite charisma skill gives extra daily quest(s)
|
||||
if (
|
||||
string.Equals(repeatableConfig.Name, "daily", StringComparison.OrdinalIgnoreCase)
|
||||
&& _profileHelper.HasEliteSkillLevel(
|
||||
SkillTypes.Charisma,
|
||||
fullProfile.CharacterData.PmcData
|
||||
)
|
||||
)
|
||||
// Elite charisma skill gives extra daily quest(s)
|
||||
{
|
||||
questCount += _databaseService
|
||||
.GetGlobals()
|
||||
.Configuration
|
||||
.SkillsSettings
|
||||
.Charisma
|
||||
.BonusSettings
|
||||
.EliteBonusSettings
|
||||
.RepeatableQuestExtraCount
|
||||
.GetValueOrDefault(0);
|
||||
.Configuration.SkillsSettings.Charisma.BonusSettings.EliteBonusSettings.RepeatableQuestExtraCount.GetValueOrDefault(
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// Add any extra repeatable quests the profile has unlocked
|
||||
questCount += (int) fullProfile.SptData.ExtraRepeatableQuests.GetValueOrDefault(repeatableConfig.Id, 0);
|
||||
questCount += (int)
|
||||
fullProfile.SptData.ExtraRepeatableQuests.GetValueOrDefault(repeatableConfig.Id, 0);
|
||||
|
||||
return questCount;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,8 @@ public class TradeController(
|
||||
public ItemEventRouterResponse ConfirmTrading(
|
||||
PmcData pmcData,
|
||||
ProcessBaseTradeRequestData request,
|
||||
string sessionID)
|
||||
string sessionID
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionID);
|
||||
|
||||
@@ -58,7 +59,7 @@ public class TradeController(
|
||||
if (request.Type == "buy_from_trader")
|
||||
{
|
||||
var foundInRaid = _traderConfig.PurchasesAreFoundInRaid;
|
||||
var buyData = (ProcessBuyTradeRequestData) request;
|
||||
var buyData = (ProcessBuyTradeRequestData)request;
|
||||
_tradeHelper.BuyItem(pmcData, buyData, sessionID, foundInRaid, output);
|
||||
|
||||
return output;
|
||||
@@ -67,7 +68,7 @@ public class TradeController(
|
||||
// Selling
|
||||
if (request.Type == "sell_to_trader")
|
||||
{
|
||||
var sellData = (ProcessSellTradeRequestData) request;
|
||||
var sellData = (ProcessSellTradeRequestData)request;
|
||||
_tradeHelper.SellItem(pmcData, pmcData, sellData, sessionID, output);
|
||||
|
||||
return output;
|
||||
@@ -76,7 +77,11 @@ public class TradeController(
|
||||
var errorMessage = $"Unhandled trade event: {request.Type}";
|
||||
_logger.Error(errorMessage);
|
||||
|
||||
return _httpResponseUtil.AppendErrorToOutput(output, errorMessage, BackendErrorCodes.RagfairUnavailable);
|
||||
return _httpResponseUtil.AppendErrorToOutput(
|
||||
output,
|
||||
errorMessage,
|
||||
BackendErrorCodes.RagfairUnavailable
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -89,7 +94,8 @@ public class TradeController(
|
||||
public ItemEventRouterResponse ConfirmRagfairTrading(
|
||||
PmcData pmcData,
|
||||
ProcessRagfairTradeRequestData request,
|
||||
string sessionID)
|
||||
string sessionID
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionID);
|
||||
|
||||
@@ -111,7 +117,11 @@ public class TradeController(
|
||||
"ragfair-unable_to_purchase_0_count_item",
|
||||
_itemHelper.GetItem(fleaOffer.Items[0].Template).Value.Name
|
||||
);
|
||||
return _httpResponseUtil.AppendErrorToOutput(output, errorMessage, BackendErrorCodes.OfferOutOfStock);
|
||||
return _httpResponseUtil.AppendErrorToOutput(
|
||||
output,
|
||||
errorMessage,
|
||||
BackendErrorCodes.OfferOutOfStock
|
||||
);
|
||||
}
|
||||
|
||||
if (_ragfairOfferHelper.OfferIsFromTrader(fleaOffer))
|
||||
@@ -146,18 +156,24 @@ public class TradeController(
|
||||
PmcData pmcData,
|
||||
RagfairOffer fleaOffer,
|
||||
OfferRequest requestOffer,
|
||||
ItemEventRouterResponse output)
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
// Skip buying items when player doesn't have needed loyalty
|
||||
if (PlayerLacksTraderLoyaltyLevelToBuyOffer(fleaOffer, pmcData))
|
||||
{
|
||||
var errorMessage = $"Unable to buy item: {fleaOffer.Items[0].Template} from trader: {fleaOffer.User.Id} as loyalty level too low, skipping";
|
||||
var errorMessage =
|
||||
$"Unable to buy item: {fleaOffer.Items[0].Template} from trader: {fleaOffer.User.Id} as loyalty level too low, skipping";
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug(errorMessage);
|
||||
}
|
||||
|
||||
_httpResponseUtil.AppendErrorToOutput(output, errorMessage, BackendErrorCodes.RagfairUnavailable);
|
||||
_httpResponseUtil.AppendErrorToOutput(
|
||||
output,
|
||||
errorMessage,
|
||||
BackendErrorCodes.RagfairUnavailable
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -171,9 +187,15 @@ public class TradeController(
|
||||
ItemId = fleaOffer.Root,
|
||||
Count = requestOffer.Count,
|
||||
SchemeId = 0,
|
||||
SchemeItems = requestOffer.Items
|
||||
SchemeItems = requestOffer.Items,
|
||||
};
|
||||
_tradeHelper.BuyItem(pmcData, buyData, sessionId, _traderConfig.PurchasesAreFoundInRaid, output);
|
||||
_tradeHelper.BuyItem(
|
||||
pmcData,
|
||||
buyData,
|
||||
sessionId,
|
||||
_traderConfig.PurchasesAreFoundInRaid,
|
||||
output
|
||||
);
|
||||
|
||||
// Remove/lower offer quantity of item purchased from trader flea offer
|
||||
_ragfairServer.ReduceOfferQuantity(fleaOffer.Id, requestOffer.Count ?? 0);
|
||||
@@ -192,7 +214,8 @@ public class TradeController(
|
||||
PmcData pmcData,
|
||||
RagfairOffer fleaOffer,
|
||||
OfferRequest requestOffer,
|
||||
ItemEventRouterResponse output)
|
||||
ItemEventRouterResponse output
|
||||
)
|
||||
{
|
||||
var buyData = new ProcessBuyTradeRequestData
|
||||
{
|
||||
@@ -202,11 +225,17 @@ public class TradeController(
|
||||
ItemId = fleaOffer.Id, // Store ragfair offerId in buyRequestData.item_id
|
||||
Count = requestOffer.Count,
|
||||
SchemeId = 0,
|
||||
SchemeItems = requestOffer.Items
|
||||
SchemeItems = requestOffer.Items,
|
||||
};
|
||||
|
||||
// buyItem() must occur prior to removing the offer stack, otherwise item inside offer doesn't exist for confirmTrading() to use
|
||||
_tradeHelper.BuyItem(pmcData, buyData, sessionId, _ragfairConfig.Dynamic.PurchasesAreFoundInRaid, output);
|
||||
_tradeHelper.BuyItem(
|
||||
pmcData,
|
||||
buyData,
|
||||
sessionId,
|
||||
_ragfairConfig.Dynamic.PurchasesAreFoundInRaid,
|
||||
output
|
||||
);
|
||||
if (output.Warnings?.Count > 0)
|
||||
{
|
||||
return;
|
||||
@@ -234,9 +263,7 @@ public class TradeController(
|
||||
/// <param name="offerId">id of the offer</param>
|
||||
/// <param name="offerOwnerId">Owner id</param>
|
||||
/// <returns>true if offer was made by a player</returns>
|
||||
protected bool IsPlayerOffer(
|
||||
string offerId,
|
||||
string? offerOwnerId)
|
||||
protected bool IsPlayerOffer(string offerId, string? offerOwnerId)
|
||||
{
|
||||
// No ownerId, not player offer
|
||||
if (offerOwnerId is null)
|
||||
@@ -246,7 +273,7 @@ public class TradeController(
|
||||
|
||||
var offerCreatorProfile = _profileHelper.GetPmcProfile(offerOwnerId);
|
||||
if (offerCreatorProfile is null || offerCreatorProfile.RagfairInfo.Offers?.Count == 0)
|
||||
// No profile or no offers
|
||||
// No profile or no offers
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -261,9 +288,7 @@ public class TradeController(
|
||||
/// <param name="fleaOffer">Flea offer being bought</param>
|
||||
/// <param name="pmcData">Player profile</param>
|
||||
/// <returns>True if player can buy offer</returns>
|
||||
protected bool PlayerLacksTraderLoyaltyLevelToBuyOffer(
|
||||
RagfairOffer fleaOffer,
|
||||
PmcData pmcData)
|
||||
protected bool PlayerLacksTraderLoyaltyLevelToBuyOffer(RagfairOffer fleaOffer, PmcData pmcData)
|
||||
{
|
||||
return fleaOffer.LoyaltyLevel > pmcData.TradersInfo[fleaOffer.User.Id].LoyaltyLevel;
|
||||
}
|
||||
@@ -278,11 +303,12 @@ public class TradeController(
|
||||
public ItemEventRouterResponse SellScavItemsToFence(
|
||||
PmcData pmcData,
|
||||
SellScavItemsToFenceRequestData request,
|
||||
string sessionId)
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionId);
|
||||
|
||||
MailMoneyToPlayer(sessionId, (int) request.TotalValue, Traders.FENCE);
|
||||
MailMoneyToPlayer(sessionId, (int)request.TotalValue, Traders.FENCE);
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -293,10 +319,7 @@ public class TradeController(
|
||||
/// <param name="sessionId">Session id</param>
|
||||
/// <param name="roublesToSend">amount of roubles to send</param>
|
||||
/// <param name="trader">Trader to sell items to</param>
|
||||
protected void MailMoneyToPlayer(
|
||||
string sessionId,
|
||||
int roublesToSend,
|
||||
string trader)
|
||||
protected void MailMoneyToPlayer(string sessionId, int roublesToSend, string trader)
|
||||
{
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
@@ -308,10 +331,7 @@ public class TradeController(
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Template = Money.ROUBLES,
|
||||
Upd = new Upd
|
||||
{
|
||||
StackObjectsCount = roublesToSend
|
||||
}
|
||||
Upd = new Upd { StackObjectsCount = roublesToSend },
|
||||
};
|
||||
|
||||
// Ensure money is properly split to follow its max stack size limit
|
||||
@@ -322,7 +342,11 @@ public class TradeController(
|
||||
sessionId,
|
||||
trader,
|
||||
MessageType.MessageWithItems,
|
||||
_randomUtil.GetArrayValue(_databaseService.GetTrader(trader).Dialogue.TryGetValue("soldItems", out var items) ? items : new List<string>()),
|
||||
_randomUtil.GetArrayValue(
|
||||
_databaseService.GetTrader(trader).Dialogue.TryGetValue("soldItems", out var items)
|
||||
? items
|
||||
: new List<string>()
|
||||
),
|
||||
curencyReward.SelectMany(x => x).ToList(),
|
||||
_timeUtil.GetHoursAsSeconds(72)
|
||||
);
|
||||
@@ -340,7 +364,8 @@ public class TradeController(
|
||||
string parentItemId,
|
||||
List<Item> items,
|
||||
Dictionary<string, int?> handbookPrices,
|
||||
TraderBase traderDetails)
|
||||
TraderBase traderDetails
|
||||
)
|
||||
{
|
||||
var itemWithChildren = _itemHelper.FindAndReturnChildrenAsItems(items, parentItemId);
|
||||
|
||||
@@ -348,14 +373,25 @@ public class TradeController(
|
||||
foreach (var itemToSell in itemWithChildren)
|
||||
{
|
||||
var itemDetails = _itemHelper.GetItem(itemToSell.Template);
|
||||
if (!(itemDetails.Key && _itemHelper.IsOfBaseclasses(itemDetails.Value.Id, traderDetails.ItemsBuy.Category)))
|
||||
// Skip if tpl isn't item OR item doesn't fulfil match traders buy categories
|
||||
if (
|
||||
!(
|
||||
itemDetails.Key
|
||||
&& _itemHelper.IsOfBaseclasses(
|
||||
itemDetails.Value.Id,
|
||||
traderDetails.ItemsBuy.Category
|
||||
)
|
||||
)
|
||||
)
|
||||
// Skip if tpl isn't item OR item doesn't fulfil match traders buy categories
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get price of item multiplied by how many are in stack
|
||||
totalPrice += (int) ((handbookPrices[itemToSell.Template] ?? 0) * (itemToSell.Upd?.StackObjectsCount ?? 1));
|
||||
totalPrice += (int)(
|
||||
(handbookPrices[itemToSell.Template] ?? 0)
|
||||
* (itemToSell.Upd?.StackObjectsCount ?? 1)
|
||||
);
|
||||
}
|
||||
|
||||
return totalPrice;
|
||||
|
||||
@@ -67,8 +67,9 @@ public class TraderController(
|
||||
_traderPurchasePersisterService.RemoveStalePurchasesFromProfiles(traderId);
|
||||
|
||||
// Set to next hour on clock or current time + 60 minutes
|
||||
trader.Base.NextResupply =
|
||||
traderResetStartsWithServer ? (int) _traderHelper.GetNextUpdateTimestamp(trader.Base.Id) : (int) nextHourTimestamp;
|
||||
trader.Base.NextResupply = traderResetStartsWithServer
|
||||
? (int)_traderHelper.GetNextUpdateTimestamp(trader.Base.Id)
|
||||
: (int)nextHourTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,10 +86,7 @@ public class TraderController(
|
||||
var barterSchemeItem = kvp.Value?.FirstOrDefault()?.FirstOrDefault();
|
||||
if (barterSchemeItem != null && _paymentHelper.IsMoneyTpl(barterSchemeItem.Template))
|
||||
{
|
||||
barterSchemeItem.Count += Math.Round(
|
||||
barterSchemeItem?.Count * multiplier ?? 0D,
|
||||
2
|
||||
);
|
||||
barterSchemeItem.Count += Math.Round(barterSchemeItem?.Count * multiplier ?? 0D, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,14 +106,14 @@ public class TraderController(
|
||||
case Traders.LIGHTHOUSEKEEPER:
|
||||
continue;
|
||||
case Traders.FENCE:
|
||||
{
|
||||
if (_fenceService.NeedsPartialRefresh())
|
||||
{
|
||||
if (_fenceService.NeedsPartialRefresh())
|
||||
{
|
||||
_fenceService.GenerateFenceAssorts();
|
||||
}
|
||||
|
||||
continue;
|
||||
_fenceService.GenerateFenceAssorts();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Trader needs to be refreshed
|
||||
@@ -203,8 +201,8 @@ public class TraderController(
|
||||
{
|
||||
{ "5449016a4bdc2d6f028b456f", handbookPrices[Money.ROUBLES] },
|
||||
{ "569668774bdc2da2298b4568", handbookPrices[Money.EUROS] },
|
||||
{ "5696686a4bdc2da3298b456a", handbookPrices[Money.DOLLARS] }
|
||||
}
|
||||
{ "5696686a4bdc2da3298b456a", handbookPrices[Money.DOLLARS] },
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ public class WeatherController(
|
||||
{
|
||||
protected WeatherConfig _weatherConfig = _configServer.GetConfig<WeatherConfig>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handle client/weather
|
||||
/// </summary>
|
||||
@@ -36,7 +35,7 @@ public class WeatherController(
|
||||
Time = "",
|
||||
Date = "",
|
||||
Weather = null,
|
||||
Season = Season.AUTUMN
|
||||
Season = Season.AUTUMN,
|
||||
};
|
||||
|
||||
_weatherGenerator.CalculateGameTime(result);
|
||||
@@ -55,7 +54,7 @@ public class WeatherController(
|
||||
var result = new GetLocalWeatherResponseData
|
||||
{
|
||||
Season = _seasonalEventService.GetActiveWeatherSeason(),
|
||||
Weather = []
|
||||
Weather = [],
|
||||
};
|
||||
|
||||
result.Weather.AddRange(_raidWeatherService.GetUpcomingWeather());
|
||||
|
||||
@@ -7,9 +7,7 @@ using SPTarkov.Server.Core.Routers;
|
||||
namespace SPTarkov.Server.Core.Controllers;
|
||||
|
||||
[Injectable]
|
||||
public class WishlistController(
|
||||
EventOutputHolder _eventOutputHolder
|
||||
)
|
||||
public class WishlistController(EventOutputHolder _eventOutputHolder)
|
||||
{
|
||||
/// <summary>
|
||||
/// Handle AddToWishList
|
||||
@@ -21,7 +19,8 @@ public class WishlistController(
|
||||
public ItemEventRouterResponse AddToWishList(
|
||||
PmcData pmcData,
|
||||
AddToWishlistRequest request,
|
||||
string sessionId)
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
foreach (var item in request.Items)
|
||||
{
|
||||
@@ -41,7 +40,8 @@ public class WishlistController(
|
||||
public ItemEventRouterResponse RemoveFromWishList(
|
||||
PmcData pmcData,
|
||||
RemoveFromWishlistRequest request,
|
||||
string sessionId)
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
foreach (var itemId in request.Items)
|
||||
{
|
||||
@@ -61,7 +61,8 @@ public class WishlistController(
|
||||
public ItemEventRouterResponse ChangeWishListItemCategory(
|
||||
PmcData pmcData,
|
||||
ChangeWishlistItemCategoryRequest request,
|
||||
string sessionId)
|
||||
string sessionId
|
||||
)
|
||||
{
|
||||
pmcData.WishList.Dictionary[request.Item] = request.Category.Value;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user