This is just Jetbrains formatting and code syntax styling
This commit is contained in:
@@ -23,11 +23,10 @@ public class AchievementController(
|
||||
var stats = new Dictionary<string, int>();
|
||||
|
||||
foreach (var achievement in achievements)
|
||||
{
|
||||
if (achievement.Id != null) stats.Add(achievement.Id, 0);
|
||||
}
|
||||
if (achievement.Id != null)
|
||||
stats.Add(achievement.Id, 0);
|
||||
|
||||
return new()
|
||||
return new CompletedAchievementsResponse
|
||||
{
|
||||
Elements = stats
|
||||
};
|
||||
|
||||
@@ -52,10 +52,7 @@ public class BotController(
|
||||
.First(p => p.Name.ToLower() == (typeInLower == "assaultgroup" ? "assault" : typeInLower))
|
||||
.GetValue(_botConfig.PresetBatch);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
if (value != null) return value;
|
||||
|
||||
_logger.Warning(_localisationService.GetText("bot-bot_preset_count_value_missing", type));
|
||||
return 30;
|
||||
@@ -70,18 +67,12 @@ public class BotController(
|
||||
{
|
||||
var difficulty = diffLevel.ToLower();
|
||||
|
||||
if (!(raidConfig != null || ignoreRaidSettings))
|
||||
{
|
||||
_logger.Error(_localisationService.GetText("bot-missing_application_context", "RAID_CONFIGURATION"));
|
||||
}
|
||||
if (!(raidConfig != null || ignoreRaidSettings)) _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";
|
||||
if (botDifficultyDropDownValue != "asonline")
|
||||
{
|
||||
difficulty = _botDifficultyHelper.ConvertBotDifficultyDropdownToBotDifficulty(botDifficultyDropDownValue);
|
||||
}
|
||||
if (botDifficultyDropDownValue != "asonline") difficulty = _botDifficultyHelper.ConvertBotDifficultyDropdownToBotDifficulty(botDifficultyDropDownValue);
|
||||
|
||||
var botDb = _databaseService.GetBots();
|
||||
return _botDifficultyHelper.GetBotDifficultySettings(type, difficulty, botDb);
|
||||
@@ -96,10 +87,7 @@ public class BotController(
|
||||
var botTypes = Enum.GetValues<WildSpawnType>().Select(item => item.ToString()).ToList();
|
||||
foreach (var botType in botTypes)
|
||||
{
|
||||
if (botTypesDb is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (botTypesDb is null) continue;
|
||||
|
||||
// If bot is usec/bear, swap to different name
|
||||
var botTypeLower = _botHelper.IsBotPmc(botType)
|
||||
@@ -113,10 +101,7 @@ public class BotController(
|
||||
{
|
||||
// No bot of this type found, copy details from assault
|
||||
result[botTypeLower] = result["assault"];
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Unable to find bot: {botTypeLower} in db, copying 'assault'");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Unable to find bot: {botTypeLower} in db, copying 'assault'");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -131,10 +116,7 @@ public class BotController(
|
||||
foreach (var (difficultyName, _) in botDetails.BotDifficulty)
|
||||
{
|
||||
// Bot doesn't exist in result, add
|
||||
if (!result.ContainsKey(botNameKey))
|
||||
{
|
||||
result.TryAdd(botNameKey, new Dictionary<string, DifficultyCategories>());
|
||||
}
|
||||
if (!result.ContainsKey(botNameKey)) result.TryAdd(botNameKey, new Dictionary<string, DifficultyCategories>());
|
||||
|
||||
// Store all difficulty values in dict keyed by difficulty type e.g. easy/normal/impossible
|
||||
result[botNameKey].Add(difficultyName, GetBotDifficulty(botNameKey, difficultyName, null, true));
|
||||
@@ -147,7 +129,7 @@ public class BotController(
|
||||
public List<BotBase> Generate(string sessionId, GenerateBotsRequestData info)
|
||||
{
|
||||
var pmcProfile = _profileHelper.GetPmcProfile(sessionId);
|
||||
|
||||
|
||||
// Use this opportunity to create and cache bots for later retrieval
|
||||
var multipleBotTypesRequested = info.Conditions?.Count > 1;
|
||||
return multipleBotTypesRequested
|
||||
@@ -166,7 +148,6 @@ public class BotController(
|
||||
var tasks = new List<Task>();
|
||||
// Map conditions to promises for bot generation
|
||||
foreach (var condition in request.Conditions ?? [])
|
||||
{
|
||||
tasks.Add(
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
@@ -185,14 +166,10 @@ public class BotController(
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Task.WaitAll(tasks.ToArray());
|
||||
stopwatch.Stop();
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Took {stopwatch.ElapsedMilliseconds}ms to GenerateMultipleBotsAndCache");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Took {stopwatch.ElapsedMilliseconds}ms to GenerateMultipleBotsAndCache");
|
||||
|
||||
return [];
|
||||
}
|
||||
@@ -220,24 +197,17 @@ public class BotController(
|
||||
|
||||
if (botCacheCount >= botGenerationDetails.BotCountToGenerate)
|
||||
{
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Cache already has sufficient {cacheKey} bots: {botCacheCount}");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Cache already has sufficient {cacheKey} bots: {botCacheCount}");
|
||||
return;
|
||||
}
|
||||
|
||||
// We're below desired count, add bots to cache
|
||||
var botsToGenerate = botGenerationDetails.BotCountToGenerate - botCacheCount;
|
||||
var progressWriter = new ProgressWriter(botGenerationDetails.BotCountToGenerate.GetValueOrDefault(30));
|
||||
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Generating {botsToGenerate} bots for cacheKey: {cacheKey}");
|
||||
}
|
||||
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Generating {botsToGenerate} bots for cacheKey: {cacheKey}");
|
||||
|
||||
for (var i = 0; i < botsToGenerate; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var detailsClone = _cloner.Clone(botGenerationDetails);
|
||||
@@ -248,15 +218,12 @@ public class BotController(
|
||||
{
|
||||
_logger.Error($"Failed to generate bot: {botGenerationDetails.Role} #{i + 1}: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
_logger.Debug(
|
||||
$"Generated {botGenerationDetails.BotCountToGenerate} {botGenerationDetails.Role}" +
|
||||
$"({botGenerationDetails.EventRole ?? botGenerationDetails.Role ?? ""}) {botGenerationDetails.BotDifficulty}bots"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private List<BotBase> ReturnSingleBotFromCache(string sessionId, GenerateBotsRequestData request)
|
||||
@@ -271,7 +238,7 @@ public class BotController(
|
||||
{
|
||||
Role = requestedBot?.Role,
|
||||
Limit = 5,
|
||||
Difficulty = requestedBot?.Difficulty,
|
||||
Difficulty = requestedBot?.Difficulty
|
||||
};
|
||||
var botGenerationDetails = GetBotGenerationDetailsForWave(
|
||||
condition,
|
||||
@@ -321,13 +288,9 @@ public class BotController(
|
||||
{
|
||||
var bossConvertPercent = bossConvertMinMax.GetByJsonProp<MinMax>(requestedBot?.Role?.ToLower() ?? string.Empty);
|
||||
if (bossConvertPercent is not null)
|
||||
{
|
||||
// Roll a percentage check if we should convert scav to boss
|
||||
if (_randomUtil.GetChance100(_randomUtil.GetDouble(bossConvertPercent.Min!.Value, bossConvertPercent.Max!.Value)))
|
||||
{
|
||||
UpdateBotGenerationDetailsToRandomBoss(botGenerationDetails, bossesToConvertToWeights);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a compound key to store bots in cache against
|
||||
@@ -341,14 +304,12 @@ public class BotController(
|
||||
{
|
||||
// No bot in cache, generate new and store in cache
|
||||
GenerateSingleBotAndStoreInCache(botGenerationDetails, sessionId, cacheKey);
|
||||
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
_logger.Debug(
|
||||
$"Generated {botGenerationDetails.BotCountToGenerate} " +
|
||||
$"{botGenerationDetails.Role} ({botGenerationDetails.EventRole ?? ""}) {botGenerationDetails.BotDifficulty} bots"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var desiredBot = _botGenerationCacheService.GetBot(cacheKey);
|
||||
@@ -400,10 +361,7 @@ public class BotController(
|
||||
.GetLatestValue(ContextVariableType.RAID_CONFIGURATION)
|
||||
?.GetValue<GetRaidConfigurationRequestData>();
|
||||
|
||||
if (raidSettings is null)
|
||||
{
|
||||
_logger.Warning(_localisationService.GetText("bot-unable_to_load_raid_settings_from_appcontext"));
|
||||
}
|
||||
if (raidSettings is null) _logger.Warning(_localisationService.GetText("bot-unable_to_load_raid_settings_from_appcontext"));
|
||||
|
||||
return raidSettings;
|
||||
}
|
||||
@@ -432,9 +390,9 @@ public class BotController(
|
||||
BotRelativeLevelDeltaMin = _pmcConfig.BotRelativeLevelDeltaMin,
|
||||
BotCountToGenerate = botCountToGenerate,
|
||||
BotDifficulty = condition.Difficulty,
|
||||
LocationSpecificPmcLevelOverride = this.GetPmcLevelRangeForMap(raidSettings?.Location), // Min/max levels for PMCs to generate within
|
||||
LocationSpecificPmcLevelOverride = GetPmcLevelRangeForMap(raidSettings?.Location), // Min/max levels for PMCs to generate within
|
||||
IsPlayerScav = false,
|
||||
AllPmcsHaveSameNameAsPlayer = allPmcsHaveSameNameAsPlayer,
|
||||
AllPmcsHaveSameNameAsPlayer = allPmcsHaveSameNameAsPlayer
|
||||
};
|
||||
}
|
||||
|
||||
@@ -442,11 +400,9 @@ public class BotController(
|
||||
{
|
||||
var botCap = _botConfig.MaxBotCap.FirstOrDefault(x => x.Key.ToLower() == location.ToLower());
|
||||
if (location == "default")
|
||||
{
|
||||
_logger.Warning(
|
||||
_localisationService.GetText("bot-no_bot_cap_found_for_location", location.ToLower())
|
||||
);
|
||||
}
|
||||
|
||||
return botCap.Value;
|
||||
}
|
||||
@@ -457,7 +413,7 @@ public class BotController(
|
||||
{
|
||||
PmcType = _pmcConfig.PmcType,
|
||||
Assault = _botConfig.AssaultBrainType,
|
||||
PlayerScav = _botConfig.PlayerScavBrainType,
|
||||
PlayerScav = _botConfig.PlayerScavBrainType
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -465,11 +421,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; }
|
||||
}
|
||||
|
||||
@@ -36,9 +36,7 @@ public class BuildController(
|
||||
const string secureContainerSlotId = "SecuredContainer";
|
||||
var profile = _profileHelper.GetFullProfile(sessionID);
|
||||
if (profile is not null && profile.UserBuildData is null)
|
||||
{
|
||||
profile.UserBuildData = new UserBuilds { EquipmentBuilds = [], WeaponBuilds = [], MagazineBuilds = [] };
|
||||
}
|
||||
|
||||
// Ensure the secure container in the default presets match what the player has equipped
|
||||
var defaultEquipmentPresetsClone = _cloner.Clone(
|
||||
@@ -52,18 +50,13 @@ public class BuildController(
|
||||
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
|
||||
foreach (var defaultPreset in defaultEquipmentPresetsClone ?? [])
|
||||
{
|
||||
// Find presets secure container
|
||||
var secureContainer = defaultPreset.Items?.FirstOrDefault(item => item.SlotId == secureContainerSlotId);
|
||||
if (secureContainer is not null)
|
||||
{
|
||||
secureContainer.Template = playerSecureContainer.Template;
|
||||
}
|
||||
if (secureContainer is not null) secureContainer.Template = playerSecureContainer.Template;
|
||||
}
|
||||
}
|
||||
|
||||
// Clone player build data from profile and append the above defaults onto end
|
||||
var userBuildsClone = _cloner.Clone(profile?.UserBuildData);
|
||||
@@ -87,7 +80,7 @@ public class BuildController(
|
||||
body.Root = body.Items.FirstOrDefault().Id;
|
||||
|
||||
// Create new object ready to save into profile userbuilds.weaponBuilds
|
||||
WeaponBuild newBuild = new WeaponBuild { Id = body.Id, Name = body.Name, Root = body.Root, Items = body.Items };
|
||||
var newBuild = new WeaponBuild { Id = body.Id, Name = body.Name, Root = body.Root, Items = body.Items };
|
||||
|
||||
var profile = _profileHelper.GetFullProfile(sessionId);
|
||||
|
||||
@@ -124,13 +117,13 @@ public class BuildController(
|
||||
// Root ID and the base item ID need to match.
|
||||
request.Items = _itemHelper.ReplaceIDs(request.Items, pmcData);
|
||||
|
||||
EquipmentBuild newBuild = new EquipmentBuild
|
||||
var newBuild = new EquipmentBuild
|
||||
{
|
||||
Id = request.Id,
|
||||
Name = request.Name,
|
||||
BuildType = EquipmentBuildType.Custom,
|
||||
Root = request.Items[0].Id,
|
||||
Items = request.Items,
|
||||
Items = request.Items
|
||||
};
|
||||
|
||||
var existingBuild = existingSavedEquipmentBuilds.FirstOrDefault(
|
||||
@@ -167,14 +160,14 @@ public class BuildController(
|
||||
/// <param name="request"></param>
|
||||
public void CreateMagazineTemplate(string sessionId, SetMagazineRequest request)
|
||||
{
|
||||
MagazineBuild result = new MagazineBuild
|
||||
var result = new MagazineBuild
|
||||
{
|
||||
Id = request.Id,
|
||||
Name = request.Name,
|
||||
Caliber = request.Caliber,
|
||||
TopCount = request.TopCount,
|
||||
BottomCount = request.BottomCount,
|
||||
Items = request.Items,
|
||||
Items = request.Items
|
||||
};
|
||||
|
||||
var profile = _profileHelper.GetFullProfile(sessionId);
|
||||
|
||||
@@ -8,9 +8,8 @@ namespace Core.Controllers;
|
||||
[Injectable]
|
||||
public class ClientLogController(
|
||||
ISptLogger<ClientLogController> _logger
|
||||
)
|
||||
)
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Handle /singleplayer/log
|
||||
/// </summary>
|
||||
|
||||
@@ -55,10 +55,7 @@ public class CustomizationController(
|
||||
)
|
||||
.ToList();
|
||||
|
||||
if (matchingSuits == null)
|
||||
{
|
||||
throw new Exception(_localisationService.GetText("customisation-unable_to_get_trader_suits", traderId));
|
||||
}
|
||||
if (matchingSuits == null) throw new Exception(_localisationService.GetText("customisation-unable_to_get_trader_suits", traderId));
|
||||
|
||||
return matchingSuits;
|
||||
}
|
||||
@@ -104,7 +101,7 @@ public class CustomizationController(
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
// Charge player for buying item
|
||||
PayForClothingItems(sessionId, pmcData, buyClothingRequest.Items, output);
|
||||
|
||||
@@ -127,20 +124,14 @@ public class CustomizationController(
|
||||
{
|
||||
var suits = _saveServer.GetProfile(sessionId).Suits;
|
||||
|
||||
if (suits is null || suits.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (suits is null || suits.Count == 0) return false;
|
||||
return suits.Contains(suitId);
|
||||
}
|
||||
|
||||
private Suit? GetTraderClothingOffer(string sessionId, string? offerId)
|
||||
{
|
||||
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));
|
||||
}
|
||||
if (foundSuit is null) _logger.Error(_localisationService.GetText("customisation-unable_to_find_suit_with_id", offerId));
|
||||
|
||||
return foundSuit;
|
||||
}
|
||||
@@ -156,11 +147,8 @@ public class CustomizationController(
|
||||
List<PaymentItemForClothing>? itemsToPayForClothingWith,
|
||||
ItemEventRouterResponse output)
|
||||
{
|
||||
if (itemsToPayForClothingWith is null || itemsToPayForClothingWith.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (itemsToPayForClothingWith is null || itemsToPayForClothingWith.Count == 0) return;
|
||||
|
||||
foreach (var inventoryItemToProcess in itemsToPayForClothingWith)
|
||||
{
|
||||
var options = new ProcessBuyTradeRequestData
|
||||
@@ -189,9 +177,7 @@ public class CustomizationController(
|
||||
|
||||
foreach (var trader in traders)
|
||||
if (trader.Value.Base?.CustomizationSeller is not null && trader.Value.Base.CustomizationSeller.Value)
|
||||
{
|
||||
result.AddRange(GetTraderSuits(trader.Key, sessionId));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -220,10 +206,7 @@ public class CustomizationController(
|
||||
var customisationResultsClone = _cloner.Clone(_databaseService.GetTemplates().CustomisationStorage);
|
||||
|
||||
var profile = _profileHelper.GetFullProfile(sessionId);
|
||||
if (profile is null)
|
||||
{
|
||||
return customisationResultsClone!;
|
||||
}
|
||||
if (profile is null) return customisationResultsClone!;
|
||||
|
||||
customisationResultsClone!.AddRange(profile.CustomisationUnlocks ?? []);
|
||||
|
||||
@@ -240,7 +223,6 @@ public class CustomizationController(
|
||||
public ItemEventRouterResponse SetCustomisation(string sessionId, CustomizationSetRequest request, PmcData pmcData)
|
||||
{
|
||||
foreach (var customisation in request.Customizations)
|
||||
{
|
||||
switch (customisation.Type)
|
||||
{
|
||||
case "dogTag":
|
||||
@@ -253,7 +235,6 @@ public class CustomizationController(
|
||||
_logger.Error($"Unhandled customisation type: {customisation.Type}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _eventOutputHolder.GetOutput(sessionId);
|
||||
}
|
||||
@@ -285,9 +266,6 @@ public class CustomizationController(
|
||||
}
|
||||
|
||||
// Feet
|
||||
if (dbSuit.Parent == _lowerParentClothingId)
|
||||
{
|
||||
pmcData.Customization.Feet = dbSuit.Properties.Feet;
|
||||
}
|
||||
if (dbSuit.Parent == _lowerParentClothingId) pmcData.Customization.Feet = dbSuit.Properties.Feet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +37,7 @@ public class DialogueController(
|
||||
public void RegisterChatBot(IDialogueChatBot chatBot) // TODO: this is in with the helper types
|
||||
{
|
||||
if (_dialogueChatBots.Any(cb => cb.GetChatBot().Id == chatBot.GetChatBot().Id))
|
||||
{
|
||||
_logger.Error(_localisationService.GetText("dialog-chatbot_id_already_exists", chatBot.GetChatBot().Id));
|
||||
}
|
||||
|
||||
_dialogueChatBots.Add(chatBot);
|
||||
}
|
||||
@@ -51,10 +49,7 @@ public class DialogueController(
|
||||
public void Update()
|
||||
{
|
||||
var profiles = _saveServer.GetProfiles();
|
||||
foreach (var kvp in profiles)
|
||||
{
|
||||
RemoveExpiredItemsFromMessages(kvp.Key);
|
||||
}
|
||||
foreach (var kvp in profiles) RemoveExpiredItemsFromMessages(kvp.Key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -70,23 +65,19 @@ public class DialogueController(
|
||||
// Add any friends the user has after the chatbots
|
||||
var profile = _profileHelper.GetFullProfile(sessionId);
|
||||
if (profile?.FriendProfileIds is not null)
|
||||
{
|
||||
foreach (var friendId in profile.FriendProfileIds)
|
||||
{
|
||||
var friendProfile = _profileHelper.GetChatRoomMemberFromSessionId(friendId);
|
||||
if (friendProfile is not null)
|
||||
{
|
||||
friends.Add(
|
||||
new UserDialogInfo
|
||||
{
|
||||
Id = friendProfile.Id,
|
||||
Aid = friendProfile.Aid,
|
||||
Info = friendProfile.Info,
|
||||
Info = friendProfile.Info
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new GetFriendListDataResponse
|
||||
{
|
||||
@@ -105,10 +96,7 @@ public class DialogueController(
|
||||
foreach (var bot in _dialogueChatBots)
|
||||
{
|
||||
var botData = bot.GetChatBot();
|
||||
if (chatBotConfig.EnabledBots.ContainsKey(botData.Id!))
|
||||
{
|
||||
activeBots.Add(botData);
|
||||
}
|
||||
if (chatBotConfig.EnabledBots.ContainsKey(botData.Id!)) activeBots.Add(botData);
|
||||
}
|
||||
|
||||
return activeBots;
|
||||
@@ -124,10 +112,7 @@ public class DialogueController(
|
||||
public List<DialogueInfo> GenerateDialogueList(string sessionId)
|
||||
{
|
||||
var data = new List<DialogueInfo>();
|
||||
foreach (var dialogueId in _dialogueHelper.GetDialogsForProfile(sessionId))
|
||||
{
|
||||
data.Add(GetDialogueInfo(dialogueId.Key, sessionId));
|
||||
}
|
||||
foreach (var dialogueId in _dialogueHelper.GetDialogsForProfile(sessionId)) data.Add(GetDialogueInfo(dialogueId.Key, sessionId));
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -153,7 +138,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;
|
||||
@@ -177,7 +162,6 @@ public class DialogueController(
|
||||
if (messageType == MessageType.USER_MESSAGE &&
|
||||
dialog?.Users is not null &&
|
||||
dialog.Users.All(userDialog => userDialog.Id != profile.CharacterData?.PmcData?.SessionId))
|
||||
{
|
||||
dialog.Users.Add(
|
||||
new UserDialogInfo
|
||||
{
|
||||
@@ -189,11 +173,10 @@ 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
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return dialog?.Users!;
|
||||
}
|
||||
@@ -225,7 +208,7 @@ public class DialogueController(
|
||||
{
|
||||
Messages = dialogue.Messages,
|
||||
Profiles = GetProfilesForMail(fullProfile, dialogue.Users),
|
||||
HasMessagesWithRewards = MessagesHaveUncollectedRewards(dialogue.Messages!),
|
||||
HasMessagesWithRewards = MessagesHaveUncollectedRewards(dialogue.Messages!)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -249,22 +232,16 @@ public class DialogueController(
|
||||
Pinned = false,
|
||||
Messages = [],
|
||||
New = 0,
|
||||
Type = request.Type,
|
||||
Type = request.Type
|
||||
};
|
||||
|
||||
if (request.Type != MessageType.USER_MESSAGE)
|
||||
{
|
||||
return profile.DialogueRecords[request.DialogId!];
|
||||
}
|
||||
if (request.Type != MessageType.USER_MESSAGE) return profile.DialogueRecords[request.DialogId!];
|
||||
|
||||
var dialogue = profile.DialogueRecords[request.DialogId!];
|
||||
dialogue.Users = [];
|
||||
var chatBot = _dialogueChatBots.FirstOrDefault(cb => cb.GetChatBot().Id == request.DialogId);
|
||||
|
||||
if (chatBot is null)
|
||||
{
|
||||
return profile.DialogueRecords[request.DialogId!];
|
||||
}
|
||||
if (chatBot is null) return profile.DialogueRecords[request.DialogId!];
|
||||
|
||||
dialogue.Users ??= [];
|
||||
dialogue.Users.Add(chatBot.GetChatBot());
|
||||
@@ -282,17 +259,12 @@ public class DialogueController(
|
||||
{
|
||||
List<UserDialogInfo> result = [];
|
||||
if (userDialogs is null)
|
||||
{
|
||||
// Nothing to add
|
||||
return result;
|
||||
}
|
||||
|
||||
result.AddRange(userDialogs);
|
||||
|
||||
if (result.Any(userDialog => userDialog.Id == fullProfile.ProfileInfo?.ProfileId))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if (result.Any(userDialog => userDialog.Id == fullProfile.ProfileInfo?.ProfileId)) return result;
|
||||
|
||||
// Player doesn't exist, add them in before returning
|
||||
var pmcProfile = fullProfile.CharacterData?.PmcData;
|
||||
@@ -307,7 +279,7 @@ public class DialogueController(
|
||||
Side = pmcProfile?.Info?.Side,
|
||||
Level = pmcProfile?.Info?.Level,
|
||||
MemberCategory = pmcProfile?.Info?.MemberCategory,
|
||||
SelectedMemberCategory = pmcProfile?.Info?.SelectedMemberCategory,
|
||||
SelectedMemberCategory = pmcProfile?.Info?.SelectedMemberCategory
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -328,12 +300,8 @@ public class DialogueController(
|
||||
var newAttachmentCount = 0;
|
||||
var activeMessages = GetActiveMessagesFromDialog(sessionId, dialogueId);
|
||||
foreach (var message in activeMessages)
|
||||
{
|
||||
if (message.HasRewards.GetValueOrDefault(false) && !message.RewardCollected.GetValueOrDefault(false))
|
||||
{
|
||||
newAttachmentCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return newAttachmentCount;
|
||||
}
|
||||
@@ -382,7 +350,7 @@ public class DialogueController(
|
||||
new
|
||||
{
|
||||
sessionId,
|
||||
dialogueId,
|
||||
dialogueId
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -410,7 +378,7 @@ public class DialogueController(
|
||||
new
|
||||
{
|
||||
sessionId,
|
||||
dialogueId,
|
||||
dialogueId
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -437,7 +405,7 @@ public class DialogueController(
|
||||
"dialogue-unable_to_find_dialogs_in_profile",
|
||||
new
|
||||
{
|
||||
sessionId,
|
||||
sessionId
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -498,11 +466,13 @@ public class DialogueController(
|
||||
{
|
||||
_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>
|
||||
@@ -521,10 +491,7 @@ public class DialogueController(
|
||||
/// <param name="sessionId">Session id</param>
|
||||
private void RemoveExpiredItemsFromMessages(string sessionId)
|
||||
{
|
||||
foreach (var dialogueId in _dialogueHelper.GetDialogsForProfile(sessionId))
|
||||
{
|
||||
RemoveExpiredItemsFromMessage(sessionId, dialogueId.Key);
|
||||
}
|
||||
foreach (var dialogueId in _dialogueHelper.GetDialogsForProfile(sessionId)) RemoveExpiredItemsFromMessage(sessionId, dialogueId.Key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -535,18 +502,11 @@ public class DialogueController(
|
||||
private void RemoveExpiredItemsFromMessage(string sessionId, string dialogueId)
|
||||
{
|
||||
var dialogs = _dialogueHelper.GetDialogsForProfile(sessionId);
|
||||
if (!dialogs.TryGetValue(dialogueId, out var dialog))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!dialogs.TryGetValue(dialogueId, out var dialog)) return;
|
||||
|
||||
foreach (var message in dialog.Messages ?? [])
|
||||
{
|
||||
if (MessageHasExpired(message))
|
||||
{
|
||||
message.Items = new MessageItems();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -564,30 +524,25 @@ public class DialogueController(
|
||||
// To avoid needing to jump between profiles, auto-accept all friend requests
|
||||
var friendProfile = _profileHelper.GetFullProfile(request.To);
|
||||
if (friendProfile?.CharacterData?.PmcData is null)
|
||||
{
|
||||
return new FriendRequestSendResponse
|
||||
{
|
||||
Status = BackendErrorCodes.PlayerProfileNotFound,
|
||||
RequestId = "", // Unused in an error state
|
||||
RetryAfter = 600,
|
||||
RetryAfter = 600
|
||||
};
|
||||
}
|
||||
|
||||
// Only add the profile to the friends list if it doesn't already exist
|
||||
var profile = _saveServer.GetProfile(sessionID);
|
||||
if (!profile.FriendProfileIds.Contains(request.To))
|
||||
{
|
||||
profile.FriendProfileIds.Add(request.To);
|
||||
}
|
||||
if (!profile.FriendProfileIds.Contains(request.To)) profile.FriendProfileIds.Add(request.To);
|
||||
|
||||
// We need to delay this so that the friend request gets properly added to the clientside list before we accept it
|
||||
_ = new Timer(
|
||||
_ =>
|
||||
{
|
||||
WsFriendsListAccept notification = new WsFriendsListAccept
|
||||
var notification = new WsFriendsListAccept
|
||||
{
|
||||
EventType = NotificationEventType.friendListRequestAccept,
|
||||
Profile = _profileHelper.GetChatRoomMemberFromPmcProfile(friendProfile.CharacterData.PmcData),
|
||||
Profile = _profileHelper.GetChatRoomMemberFromPmcProfile(friendProfile.CharacterData.PmcData)
|
||||
};
|
||||
_notificationSendHelper.SendMessage(sessionID, notification);
|
||||
},
|
||||
@@ -608,9 +563,6 @@ public class DialogueController(
|
||||
{
|
||||
var profile = _saveServer.GetProfile(sessionID);
|
||||
var friendIndex = profile.FriendProfileIds.IndexOf(request.FriendId);
|
||||
if (friendIndex != -1)
|
||||
{
|
||||
profile.FriendProfileIds.RemoveAt(friendIndex);
|
||||
}
|
||||
if (friendIndex != -1) profile.FriendProfileIds.RemoveAt(friendIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,12 +44,12 @@ public class GameController(
|
||||
ICloner _cloner
|
||||
)
|
||||
{
|
||||
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
protected CoreConfig _coreConfig = _configServer.GetConfig<CoreConfig>();
|
||||
protected double _deviation = 0.0001;
|
||||
protected HideoutConfig _hideoutConfig = _configServer.GetConfig<HideoutConfig>();
|
||||
protected HttpConfig _httpConfig = _configServer.GetConfig<HttpConfig>();
|
||||
protected RagfairConfig _ragfairConfig = _configServer.GetConfig<RagfairConfig>();
|
||||
protected HideoutConfig _hideoutConfig = _configServer.GetConfig<HideoutConfig>();
|
||||
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
protected double _deviation = 0.0001;
|
||||
|
||||
/// <summary>
|
||||
/// Handle client/game/start
|
||||
@@ -82,40 +82,25 @@ public class GameController(
|
||||
_logger.Error($"{nameof(fullProfile)} is null on GameController.GameStart");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
fullProfile.SptData ??= new Spt { Version = "Replace_me" };
|
||||
fullProfile.SptData.Migrations ??= new Dictionary<string, long>();
|
||||
fullProfile.FriendProfileIds ??= [];
|
||||
|
||||
if (fullProfile.ProfileInfo?.IsWiped is not null && fullProfile.ProfileInfo.IsWiped.Value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (fullProfile.ProfileInfo?.IsWiped is not null && fullProfile.ProfileInfo.IsWiped.Value) 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>(), []);
|
||||
|
||||
if (fullProfile.DialogueRecords is not null)
|
||||
{
|
||||
_profileFixerService.CheckForAndFixDialogueAttachments(fullProfile);
|
||||
}
|
||||
if (fullProfile.DialogueRecords is not null) _profileFixerService.CheckForAndFixDialogueAttachments(fullProfile);
|
||||
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Started game with session {sessionId} {fullProfile.ProfileInfo?.Username}");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Started game with session {sessionId} {fullProfile.ProfileInfo?.Username}");
|
||||
|
||||
var pmcProfile = fullProfile.CharacterData.PmcData;
|
||||
|
||||
if (_coreConfig.Fixes.FixProfileBreakingInventoryItemIssues)
|
||||
{
|
||||
_profileFixerService.FixProfileBreakingInventoryItemIssues(pmcProfile);
|
||||
}
|
||||
if (_coreConfig.Fixes.FixProfileBreakingInventoryItemIssues) _profileFixerService.FixProfileBreakingInventoryItemIssues(pmcProfile);
|
||||
|
||||
if (pmcProfile.Health is not null)
|
||||
{
|
||||
UpdateProfileHealthValues(pmcProfile);
|
||||
}
|
||||
if (pmcProfile.Health is not null) UpdateProfileHealthValues(pmcProfile);
|
||||
|
||||
if (pmcProfile.Inventory is not null)
|
||||
{
|
||||
@@ -143,10 +128,7 @@ public class GameController(
|
||||
CheckForAndRemoveUndefinedDialogues(fullProfile);
|
||||
}
|
||||
|
||||
if (pmcProfile.Skills?.Common is not null)
|
||||
{
|
||||
WarnOnActiveBotReloadSkill(pmcProfile);
|
||||
}
|
||||
if (pmcProfile.Skills?.Common is not null) WarnOnActiveBotReloadSkill(pmcProfile);
|
||||
|
||||
_seasonalEventService.GivePlayerSeasonalGifts(sessionId);
|
||||
}
|
||||
@@ -160,8 +142,9 @@ public class GameController(
|
||||
{
|
||||
var profile = _profileHelper.GetPmcProfile(sessionId);
|
||||
var gameTime = profile?.Stats?.Eft?.OverallCounters?.Items?
|
||||
.FirstOrDefault(c => c.Key!.Contains("LifeTime")
|
||||
&& c.Key.Contains("Pmc"))?.Value ?? 0D;
|
||||
.FirstOrDefault(c => c.Key!.Contains("LifeTime") && c.Key.Contains("Pmc"))
|
||||
?.Value ??
|
||||
0D;
|
||||
|
||||
var config = new GameConfigResponse
|
||||
{
|
||||
@@ -173,7 +156,7 @@ public class GameController(
|
||||
Aid = profile?.Aid,
|
||||
Taxonomy = 6,
|
||||
ActiveProfileId = sessionId,
|
||||
Backend = new()
|
||||
Backend = new Backend
|
||||
{
|
||||
Lobby = _httpServerHelper.GetBackendUrl(),
|
||||
Trading = _httpServerHelper.GetBackendUrl(),
|
||||
@@ -185,7 +168,7 @@ public class GameController(
|
||||
UtcTime = _timeUtil.GetTimeStamp(),
|
||||
TotalInGame = gameTime,
|
||||
SessionMode = "pve",
|
||||
PurchasedGames = new()
|
||||
PurchasedGames = new PurchasedGames
|
||||
{
|
||||
IsEftPurchased = true,
|
||||
IsArenaPurchased = false
|
||||
@@ -205,7 +188,7 @@ public class GameController(
|
||||
string sessionId,
|
||||
GameModeRequestData requestData)
|
||||
{
|
||||
return new()
|
||||
return new GameModeResponse
|
||||
{
|
||||
GameMode = "pve",
|
||||
BackendUrl = _httpServerHelper.GetBackendUrl()
|
||||
@@ -291,7 +274,7 @@ public class GameController(
|
||||
/// <returns></returns>
|
||||
public SurveyResponseData GetSurvey(string sessionId)
|
||||
{
|
||||
return this._coreConfig.Survey;
|
||||
return _coreConfig.Survey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -301,10 +284,7 @@ public class GameController(
|
||||
private void WarnOnActiveBotReloadSkill(PmcData pmcProfile)
|
||||
{
|
||||
var botReloadSkill = _profileHelper.GetSkillFromProfile(pmcProfile, SkillTypes.BotReload);
|
||||
if (botReloadSkill?.Progress > 0)
|
||||
{
|
||||
_logger.Warning(_localisationService.GetText("server_start_player_active_botreload_skill"));
|
||||
}
|
||||
if (botReloadSkill?.Progress > 0) _logger.Warning(_localisationService.GetText("server_start_player_active_botreload_skill"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -323,40 +303,35 @@ public class GameController(
|
||||
// Base values
|
||||
double energyRegenPerHour = 60;
|
||||
double hydrationRegenPerHour = 60;
|
||||
double hpRegenPerHour = 456.6;
|
||||
var hpRegenPerHour = 456.6;
|
||||
|
||||
// Set new values, whatever is smallest
|
||||
energyRegenPerHour += pmcProfile.Bonuses!
|
||||
.Where(bonus => bonus.Type == BonusType.EnergyRegeneration)
|
||||
.Aggregate(0d, (sum, bonus) => sum + (bonus.Value!.Value));
|
||||
|
||||
.Aggregate(0d, (sum, bonus) => sum + bonus.Value!.Value);
|
||||
|
||||
hydrationRegenPerHour += pmcProfile.Bonuses!
|
||||
.Where(bonus => bonus.Type == BonusType.HydrationRegeneration)
|
||||
.Aggregate(0d, (sum, bonus) => sum + (bonus.Value!.Value));
|
||||
|
||||
.Aggregate(0d, (sum, bonus) => sum + bonus.Value!.Value);
|
||||
|
||||
hpRegenPerHour += pmcProfile.Bonuses!
|
||||
.Where(bonus => bonus.Type == BonusType.HealthRegeneration)
|
||||
.Aggregate(0d, (sum, bonus) => sum + (bonus.Value!.Value));
|
||||
.Aggregate(0d, (sum, bonus) => sum + bonus.Value!.Value);
|
||||
|
||||
// Player has energy deficit
|
||||
if (Math.Abs((pmcProfile.Health?.Energy?.Current - pmcProfile.Health?.Energy?.Maximum) ?? 1) <= _deviation)
|
||||
if (Math.Abs(pmcProfile.Health?.Energy?.Current - pmcProfile.Health?.Energy?.Maximum ?? 1) <= _deviation)
|
||||
{
|
||||
// Set new value, whatever is smallest
|
||||
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;
|
||||
}
|
||||
if (pmcProfile.Health.Energy.Current > pmcProfile.Health.Energy.Maximum) pmcProfile.Health.Energy.Current = pmcProfile.Health.Energy.Maximum;
|
||||
}
|
||||
|
||||
// Player has hydration deficit
|
||||
if (Math.Abs((pmcProfile.Health?.Hydration?.Current - pmcProfile.Health?.Hydration?.Maximum) ?? 1) <= _deviation)
|
||||
if (Math.Abs(pmcProfile.Health?.Hydration?.Current - pmcProfile.Health?.Hydration?.Maximum ?? 1) <= _deviation)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Check all body parts
|
||||
@@ -364,21 +339,12 @@ public class GameController(
|
||||
.Select(bodyPartKvP => bodyPartKvP.Value))
|
||||
{
|
||||
// Check part hp
|
||||
if (bodyPart.Health!.Current < bodyPart.Health.Maximum)
|
||||
{
|
||||
bodyPart.Health.Current += Math.Round(hpRegenPerHour * (diffSeconds!.Value / 3600));
|
||||
}
|
||||
if (bodyPart.Health!.Current < bodyPart.Health.Maximum) bodyPart.Health.Current += Math.Round(hpRegenPerHour * (diffSeconds!.Value / 3600));
|
||||
|
||||
if (bodyPart.Health.Current > bodyPart.Health.Maximum)
|
||||
{
|
||||
bodyPart.Health.Current = bodyPart.Health.Maximum;
|
||||
}
|
||||
if (bodyPart.Health.Current > bodyPart.Health.Maximum) bodyPart.Health.Current = bodyPart.Health.Maximum;
|
||||
|
||||
|
||||
if (bodyPart.Effects is null || bodyPart.Effects.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (bodyPart.Effects is null || bodyPart.Effects.Count == 0) continue;
|
||||
|
||||
// Look for effects
|
||||
foreach (var effectKvP in bodyPart.Effects)
|
||||
@@ -387,10 +353,7 @@ public class GameController(
|
||||
if (effectKvP.Value.Time < 1)
|
||||
{
|
||||
// More than 30 mins has passed
|
||||
if (diffSeconds > 1800)
|
||||
{
|
||||
bodyPart.Effects.Remove(effectKvP.Key);
|
||||
}
|
||||
if (diffSeconds > 1800) bodyPart.Effects.Remove(effectKvP.Key);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -398,10 +361,8 @@ 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
|
||||
effectKvP.Value.Time = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,16 +382,10 @@ public class GameController(
|
||||
var currentTimeStamp = _timeUtil.GetTimeStamp();
|
||||
|
||||
// One day post-profile creation
|
||||
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds)
|
||||
{
|
||||
_giftService.SendPraporStartingGift(pmcProfile.SessionId!, 1);
|
||||
}
|
||||
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds) _giftService.SendPraporStartingGift(pmcProfile.SessionId!, 1);
|
||||
|
||||
// Two day post-profile creation
|
||||
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds * 2)
|
||||
{
|
||||
_giftService.SendPraporStartingGift(pmcProfile.SessionId!, 2);
|
||||
}
|
||||
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds * 2) _giftService.SendPraporStartingGift(pmcProfile.SessionId!, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -438,7 +393,7 @@ public class GameController(
|
||||
* @param pmcProfile Player profile
|
||||
*/
|
||||
protected void SendMechanicGiftsToNewProfile(PmcData pmcProfile)
|
||||
{
|
||||
{
|
||||
_giftService.SendGiftWithSilentReceivedCheck("MechanicGiftDay1", pmcProfile.SessionId, 1);
|
||||
}
|
||||
|
||||
@@ -495,27 +450,16 @@ public class GameController(
|
||||
var bots = _databaseService.GetBots().Types;
|
||||
|
||||
// Official names can only be 15 chars in length
|
||||
if (playerName.Length > _botConfig.BotNameLengthLimit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (playerName.Length > _botConfig.BotNameLengthLimit) return;
|
||||
|
||||
// Skip if player name exists already
|
||||
if (bots!.TryGetValue("bear", out var bearBot))
|
||||
{
|
||||
if (bearBot is not null && bearBot.FirstNames!.Any(x => x == playerName))
|
||||
{
|
||||
bearBot.FirstNames!.Add(playerName);
|
||||
}
|
||||
}
|
||||
|
||||
if (bots.TryGetValue("bear", out var usecBot))
|
||||
{
|
||||
if (usecBot is not null && usecBot.FirstNames!.Any(x => x == playerName))
|
||||
{
|
||||
usecBot.FirstNames!.Add(playerName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,10 +469,7 @@ public class GameController(
|
||||
/// <param name="fullProfile">Profile to check for dialog in</param>
|
||||
private void CheckForAndRemoveUndefinedDialogues(SptProfile fullProfile)
|
||||
{
|
||||
if (fullProfile.DialogueRecords!.TryGetValue("undefined", out var _))
|
||||
{
|
||||
fullProfile.DialogueRecords.Remove("undefined");
|
||||
}
|
||||
if (fullProfile.DialogueRecords!.TryGetValue("undefined", out _)) fullProfile.DialogueRecords.Remove("undefined");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -540,7 +481,7 @@ 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()}");
|
||||
}
|
||||
|
||||
@@ -69,15 +69,12 @@ public class HealthController(
|
||||
}
|
||||
|
||||
// Resource in medkit is spent, delete it
|
||||
if (healingItemToUse.Upd.MedKit.HpResource <= 0)
|
||||
{
|
||||
_inventoryHelper.RemoveItem(pmcData, request.Item, sessionID, output);
|
||||
}
|
||||
if (healingItemToUse.Upd.MedKit.HpResource <= 0) _inventoryHelper.RemoveItem(pmcData, request.Item, sessionID, output);
|
||||
|
||||
var healingItemDbDetails = _itemHelper.GetItem(healingItemToUse.Template);
|
||||
|
||||
var healItemEffectDetails = healingItemDbDetails.Value.Properties.EffectsDamage;
|
||||
BodyPartHealth bodyPartToHeal = pmcData.Health.BodyParts.GetValueOrDefault(request.Part.ToString());
|
||||
var bodyPartToHeal = pmcData.Health.BodyParts.GetValueOrDefault(request.Part.ToString());
|
||||
if (bodyPartToHeal is null)
|
||||
{
|
||||
_logger.Warning($"Player: {sessionID} Tried to heal a non-existent body part: {request.Part}");
|
||||
@@ -98,10 +95,8 @@ public class HealthController(
|
||||
{
|
||||
// Check if healing item removes the effect on limb
|
||||
if (!healItemEffectDetails.TryGetValue(Enum.Parse<DamageEffectType>(effectKey), out var matchingEffectFromHealingItem))
|
||||
{
|
||||
// Healing item doesn't have matching effect, it doesn't remove the effect
|
||||
continue;
|
||||
}
|
||||
|
||||
// Adjust limb heal amount based on if its fixing an effect (request.count is TOTAL cost of hp resource on heal item, NOT amount to heal limb)
|
||||
amountToHealLimb -= (int)(matchingEffectFromHealingItem.Cost ?? 0);
|
||||
@@ -113,10 +108,7 @@ public class HealthController(
|
||||
bodyPartToHeal.Health.Current += amountToHealLimb;
|
||||
|
||||
// Ensure we've not healed beyond the limbs max hp
|
||||
if (bodyPartToHeal.Health.Current > bodyPartToHeal.Health.Maximum)
|
||||
{
|
||||
bodyPartToHeal.Health.Current = bodyPartToHeal.Health.Maximum;
|
||||
}
|
||||
if (bodyPartToHeal.Health.Current > bodyPartToHeal.Health.Maximum) bodyPartToHeal.Health.Current = bodyPartToHeal.Health.Maximum;
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -139,13 +131,11 @@ public class HealthController(
|
||||
|
||||
var itemToConsume = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == request.Item);
|
||||
if (itemToConsume is null)
|
||||
{
|
||||
// Item not found, very bad
|
||||
return _httpResponseUtil.AppendErrorToOutput(
|
||||
output,
|
||||
_localisationService.GetText("health-unable_to_find_item_to_consume", request.Item)
|
||||
);
|
||||
}
|
||||
|
||||
var consumedItemMaxResource = _itemHelper.GetItem(itemToConsume.Template).Value.Properties.MaxResource;
|
||||
if (consumedItemMaxResource > 1)
|
||||
@@ -154,22 +144,15 @@ public class HealthController(
|
||||
_itemHelper.AddUpdObjectToItem(itemToConsume);
|
||||
|
||||
if (itemToConsume.Upd.FoodDrink is null)
|
||||
{
|
||||
itemToConsume.Upd.FoodDrink = new UpdFoodDrink { HpPercent = consumedItemMaxResource - request.Count };
|
||||
}
|
||||
else
|
||||
{
|
||||
itemToConsume.Upd.FoodDrink.HpPercent -= request.Count;
|
||||
}
|
||||
|
||||
resourceLeft = itemToConsume.Upd.FoodDrink.HpPercent.Value;
|
||||
}
|
||||
|
||||
// Remove item from inventory if resource has dropped below threshold
|
||||
if (consumedItemMaxResource == 1 || resourceLeft < 1)
|
||||
{
|
||||
_inventoryHelper.RemoveItem(pmcData, request.Item, sessionID, output);
|
||||
}
|
||||
if (consumedItemMaxResource == 1 || resourceLeft < 1) _inventoryHelper.RemoveItem(pmcData, request.Item, sessionID, output);
|
||||
|
||||
// Check what effect eating item has and handle
|
||||
var foodItemDbDetails = _itemHelper.GetItem(itemToConsume.Template).Value;
|
||||
@@ -198,14 +181,10 @@ public class HealthController(
|
||||
OffraidEatRequestData request)
|
||||
{
|
||||
if (foodIsSingleUse)
|
||||
{
|
||||
// Apply whole value from passed in parameter
|
||||
bodyValue.Current += consumptionDetails.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
bodyValue.Current += request.Count;
|
||||
}
|
||||
|
||||
// Ensure current never goes over max
|
||||
if (bodyValue.Current > bodyValue.Maximum)
|
||||
@@ -216,10 +195,7 @@ public class HealthController(
|
||||
}
|
||||
|
||||
// Same as above but for the lower bound
|
||||
if (bodyValue.Current < 0)
|
||||
{
|
||||
bodyValue.Current = 0;
|
||||
}
|
||||
if (bodyValue.Current < 0) bodyValue.Current = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -248,10 +224,7 @@ public class HealthController(
|
||||
};
|
||||
|
||||
_paymentService.PayMoney(pmcData, payMoneyRequest, sessionID, output);
|
||||
if (output.Warnings.Count > 0)
|
||||
{
|
||||
return output;
|
||||
}
|
||||
if (output.Warnings.Count > 0) return output;
|
||||
|
||||
foreach (var bodyPartKvP in healthTreatmentRequest.Difference.BodyParts.GetAllPropsAsDict())
|
||||
{
|
||||
@@ -261,25 +234,17 @@ public class HealthController(
|
||||
|
||||
// Bodypart healing is chosen when part request hp is above 0
|
||||
if (partRequest.Health > 0)
|
||||
{
|
||||
// Heal bodypart
|
||||
profilePart.Health.Current = profilePart.Health.Maximum;
|
||||
}
|
||||
|
||||
// Check for effects to remove
|
||||
if (partRequest.Effects?.Count > 0)
|
||||
{
|
||||
// Found some, loop over them and remove from pmc profile
|
||||
foreach (var effect in partRequest.Effects)
|
||||
{
|
||||
pmcData.Health.BodyParts[bodyPartKvP.Key].Effects.Remove(effect);
|
||||
}
|
||||
foreach (var effect in partRequest.Effects) pmcData.Health.BodyParts[bodyPartKvP.Key].Effects.Remove(effect);
|
||||
|
||||
// Remove empty effect object
|
||||
if (pmcData.Health.BodyParts[bodyPartKvP.Key].Effects.Count == 0)
|
||||
{
|
||||
pmcData.Health.BodyParts[bodyPartKvP.Key].Effects = null;
|
||||
}
|
||||
if (pmcData.Health.BodyParts[bodyPartKvP.Key].Effects.Count == 0) pmcData.Health.BodyParts[bodyPartKvP.Key].Effects = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@ public class HideoutController(
|
||||
ConfigServer _configServer
|
||||
)
|
||||
{
|
||||
protected HideoutConfig _hideoutConfig = _configServer.GetConfig<HideoutConfig>();
|
||||
public const string NameTaskConditionCountersCraftingId = "673f5d6fdd6ed700c703afdc";
|
||||
|
||||
protected List<HideoutAreas> _hideoutAreas =
|
||||
@@ -54,9 +53,11 @@ public class HideoutController(
|
||||
HideoutAreas.AIR_FILTERING,
|
||||
HideoutAreas.WATER_COLLECTOR,
|
||||
HideoutAreas.GENERATOR,
|
||||
HideoutAreas.BITCOIN_FARM,
|
||||
HideoutAreas.BITCOIN_FARM
|
||||
];
|
||||
|
||||
protected HideoutConfig _hideoutConfig = _configServer.GetConfig<HideoutConfig>();
|
||||
|
||||
public void StartUpgrade(PmcData pmcData, HideoutUpgradeRequestData request, string sessionID, ItemEventRouterResponse output)
|
||||
{
|
||||
var items = request.Items.Select(
|
||||
@@ -87,13 +88,9 @@ public class HideoutController(
|
||||
item.inventoryItem.Upd.StackObjectsCount is not null &&
|
||||
item.inventoryItem.Upd.StackObjectsCount > item.requestedItem.Count
|
||||
)
|
||||
{
|
||||
item.inventoryItem.Upd.StackObjectsCount -= item.requestedItem.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
_inventoryHelper.RemoveItem(pmcData, item.inventoryItem.Id, sessionID, output);
|
||||
}
|
||||
}
|
||||
|
||||
// Construction time management
|
||||
@@ -122,10 +119,7 @@ public class HideoutController(
|
||||
var ctime = hideoutDataDb.Stages[(profileHideoutArea.Level + 1).ToString()].ConstructionTime;
|
||||
if (ctime > 0)
|
||||
{
|
||||
if (_profileHelper.IsDeveloperAccount(sessionID))
|
||||
{
|
||||
ctime = 40;
|
||||
}
|
||||
if (_profileHelper.IsDeveloperAccount(sessionID)) ctime = 40;
|
||||
|
||||
var timestamp = _timeUtil.GetTimeStamp();
|
||||
|
||||
@@ -168,16 +162,11 @@ public class HideoutController(
|
||||
var hideoutStage = hideoutData.Stages[profileHideoutArea.Level.ToString()];
|
||||
var bonuses = hideoutStage.Bonuses;
|
||||
if (bonuses?.Count > 0)
|
||||
{
|
||||
foreach (var bonus in bonuses)
|
||||
{
|
||||
_hideoutHelper.ApplyPlayerUpgradesBonuses(pmcData, bonus);
|
||||
}
|
||||
}
|
||||
|
||||
// Upgrade includes a container improvement/addition
|
||||
if (!string.IsNullOrEmpty(hideoutStage?.Container))
|
||||
{
|
||||
AddContainerImprovementToProfile(
|
||||
output,
|
||||
sessionID,
|
||||
@@ -186,22 +175,17 @@ public class HideoutController(
|
||||
hideoutData,
|
||||
hideoutStage
|
||||
);
|
||||
}
|
||||
|
||||
// Upgrading water collector / med station
|
||||
if (
|
||||
profileHideoutArea.Type == HideoutAreas.WATER_COLLECTOR ||
|
||||
profileHideoutArea.Type == HideoutAreas.MEDSTATION
|
||||
)
|
||||
{
|
||||
SetWallVisibleIfPrereqsMet(pmcData);
|
||||
}
|
||||
|
||||
// Cleanup temporary buffs/debuffs from wall if complete
|
||||
if (profileHideoutArea.Type == HideoutAreas.EMERGENCY_WALL && profileHideoutArea.Level == 6)
|
||||
{
|
||||
_hideoutHelper.RemoveHideoutWallBuffsAndDebuffs(hideoutData, pmcData);
|
||||
}
|
||||
|
||||
// Add Skill Points Per Area Upgrade
|
||||
_profileHelper.AddSkillPointsToPlayer(
|
||||
@@ -218,10 +202,7 @@ public class HideoutController(
|
||||
if (medStation?.Level >= 1 && waterCollector?.Level >= 1)
|
||||
{
|
||||
var wall = pmcData.Hideout.Areas.FirstOrDefault((area) => area.Type == HideoutAreas.EMERGENCY_WALL);
|
||||
if (wall?.Level == 0)
|
||||
{
|
||||
wall.Level = 3;
|
||||
}
|
||||
if (wall?.Level == 0) wall.Level = 3;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,27 +211,21 @@ public class HideoutController(
|
||||
{
|
||||
// Add key/value to `hideoutAreaStashes` dictionary - used to link hideout area to inventory stash by its id
|
||||
if (!pmcData.Inventory.HideoutAreaStashes.ContainsKey(dbHideoutArea.Type.ToString()))
|
||||
{
|
||||
pmcData.Inventory.HideoutAreaStashes[dbHideoutArea.Type.ToString()] = dbHideoutArea.Id;
|
||||
}
|
||||
|
||||
// Add/upgrade stash item in player inventory
|
||||
AddUpdateInventoryItemToProfile(sessionID, pmcData, dbHideoutArea, hideoutStage);
|
||||
|
||||
// Edge case, add/update `stand1/stand2/stand3` children
|
||||
if (dbHideoutArea.Type == HideoutAreas.EQUIPMENT_PRESETS_STAND)
|
||||
{
|
||||
// Can have multiple 'standx' children depending on upgrade level
|
||||
AddMissingPresetStandItemsToProfile(sessionID, hideoutStage, pmcData, dbHideoutArea, output);
|
||||
}
|
||||
|
||||
// Dont inform client when upgraded area is hall of fame or equipment stand, BSG doesn't inform client this specifc upgrade has occurred
|
||||
// will break client if sent
|
||||
List<HideoutAreas> check = [HideoutAreas.PLACE_OF_FAME];
|
||||
if (!check.Contains(dbHideoutArea.Type ?? HideoutAreas.NOTSET))
|
||||
{
|
||||
AddContainerUpgradeToClientOutput(sessionID, dbHideoutArea.Type, dbHideoutArea, hideoutStage, output);
|
||||
}
|
||||
|
||||
// Some hideout areas (Gun stand) have child areas linked to it
|
||||
var childDbArea = _databaseService
|
||||
@@ -260,9 +235,7 @@ public class HideoutController(
|
||||
{
|
||||
// Add key/value to `hideoutAreaStashes` dictionary - used to link hideout area to inventory stash by its id
|
||||
if (pmcData.Inventory.HideoutAreaStashes.GetValueOrDefault(childDbArea.Type.ToString()) is null)
|
||||
{
|
||||
pmcData.Inventory.HideoutAreaStashes[childDbArea.Type.ToString()] = childDbArea.Id;
|
||||
}
|
||||
|
||||
// Set child area level to same as parent area
|
||||
pmcData.Hideout.Areas.FirstOrDefault((hideoutArea) => hideoutArea.Type == childDbArea.Type).Level =
|
||||
@@ -297,15 +270,13 @@ public class HideoutController(
|
||||
ItemEventRouterResponse output)
|
||||
{
|
||||
if (output.ProfileChanges[sessionID].ChangedHideoutStashes is null)
|
||||
{
|
||||
output.ProfileChanges[sessionID].ChangedHideoutStashes = new Dictionary<string, HideoutStashItem>();
|
||||
}
|
||||
|
||||
// Inform client of changes
|
||||
output.ProfileChanges[sessionID].ChangedHideoutStashes[areaType.ToString()] = new HideoutStashItem
|
||||
{
|
||||
Id = hideoutDbData.Id,
|
||||
Template = hideoutStage.Container,
|
||||
Template = hideoutStage.Container
|
||||
};
|
||||
}
|
||||
|
||||
@@ -370,7 +341,7 @@ public class HideoutController(
|
||||
Id = item.inventoryItem.Id,
|
||||
Template = item.inventoryItem.Template,
|
||||
Upd = item.inventoryItem.Upd
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
_inventoryHelper.RemoveItem(pmcData, item.inventoryItem.Id, sessionID, output);
|
||||
@@ -445,15 +416,13 @@ public class HideoutController(
|
||||
ItemWithModsToAdd = [itemToReturn.ConvertToItem()],
|
||||
FoundInRaid = itemToReturn.Upd?.SpawnedInSession,
|
||||
Callback = null,
|
||||
UseSortingTable = false,
|
||||
UseSortingTable = false
|
||||
};
|
||||
|
||||
_inventoryHelper.AddItemToStash(sessionID, request, pmcData, output);
|
||||
if (output.Warnings?.Count > 0)
|
||||
{
|
||||
// Adding to stash failed, drop out - don't remove item from hideout area slot
|
||||
return output;
|
||||
}
|
||||
|
||||
// Remove items from slot, locationIndex remains
|
||||
var hideoutSlotIndex = hideoutArea.Slots.FindIndex((slot) => slot.LocationIndex == slotIndexToRemove);
|
||||
@@ -510,18 +479,12 @@ public class HideoutController(
|
||||
|
||||
// Handle tools not having a `count`, but always only requiring 1
|
||||
var requiredCount = requirement.Count ?? 1;
|
||||
if (requiredCount <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (requiredCount <= 0) continue;
|
||||
|
||||
_inventoryHelper.RemoveItemByCount(pmcData, itemToDelete.Id, requiredCount, sessionID, output);
|
||||
|
||||
// Tools don't have a count
|
||||
if (requirement.Type != "Tool")
|
||||
{
|
||||
requirement.Count -= (int)itemToDelete.Count;
|
||||
}
|
||||
if (requirement.Type != "Tool") requirement.Count -= (int)itemToDelete.Count;
|
||||
}
|
||||
|
||||
return output;
|
||||
@@ -546,13 +509,9 @@ public class HideoutController(
|
||||
}
|
||||
|
||||
if (inventoryItem.Upd?.StackObjectsCount is not null && inventoryItem.Upd.StackObjectsCount > requestedItem.Count)
|
||||
{
|
||||
inventoryItem.Upd.StackObjectsCount -= requestedItem.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
_inventoryHelper.RemoveItem(pmcData, requestedItem.Id, sessionID, output);
|
||||
}
|
||||
}
|
||||
|
||||
var recipe = _databaseService.GetHideout().Production?.ScavRecipes?.FirstOrDefault(r => r.Id == body.RecipeId);
|
||||
@@ -592,10 +551,7 @@ public class HideoutController(
|
||||
private double? GetScavCaseTime(PmcData pmcData, double? productionTime)
|
||||
{
|
||||
var fenceLevel = _fenceService.GetFenceInfo(pmcData);
|
||||
if (fenceLevel is null)
|
||||
{
|
||||
return productionTime;
|
||||
}
|
||||
if (fenceLevel is null) return productionTime;
|
||||
|
||||
return productionTime * fenceLevel.ScavCaseTimeModifier;
|
||||
}
|
||||
@@ -661,10 +617,7 @@ public class HideoutController(
|
||||
foreach (var production in productionDict)
|
||||
{
|
||||
// Skip undefined production objects
|
||||
if (production.Value is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (production.Value is null) continue;
|
||||
|
||||
// Production or ScavCase
|
||||
if (production.Value.RecipeId == request.RecipeId)
|
||||
@@ -723,11 +676,11 @@ public class HideoutController(
|
||||
if (rewardIsStackable ?? false)
|
||||
{
|
||||
// Create root item
|
||||
Item rewardToAdd = new Item
|
||||
var rewardToAdd = new Item
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Template = recipe.EndProduct,
|
||||
Upd = new Upd { StackObjectsCount = recipe.Count },
|
||||
Upd = new Upd { StackObjectsCount = recipe.Count }
|
||||
};
|
||||
|
||||
// Split item into separate items with acceptable stack sizes
|
||||
@@ -739,50 +692,39 @@ public class HideoutController(
|
||||
// Not stackable, may have to send send multiple of reward
|
||||
|
||||
// Add the first reward item to array when not a preset (first preset added above earlier)
|
||||
if (!rewardIsPreset)
|
||||
{
|
||||
itemAndChildrenToSendToPlayer.Add([new Item { Id = _hashUtil.Generate(), Template = recipe.EndProduct }]);
|
||||
}
|
||||
if (!rewardIsPreset) itemAndChildrenToSendToPlayer.Add([new Item { Id = _hashUtil.Generate(), Template = recipe.EndProduct }]);
|
||||
|
||||
// Add multiple of item if recipe requests it
|
||||
// Start index at one so we ignore first item in array
|
||||
var countOfItemsToReward = recipe.Count;
|
||||
for (var index = 1; index < countOfItemsToReward; index++)
|
||||
{
|
||||
List<Item> itemAndMods = _itemHelper.ReplaceIDs(_cloner.Clone(itemAndChildrenToSendToPlayer.FirstOrDefault()));
|
||||
var itemAndMods = _itemHelper.ReplaceIDs(_cloner.Clone(itemAndChildrenToSendToPlayer.FirstOrDefault()));
|
||||
itemAndChildrenToSendToPlayer.AddRange([itemAndMods]);
|
||||
}
|
||||
}
|
||||
|
||||
// Recipe has an `isEncoded` requirement for reward(s), Add `RecodableComponent` property
|
||||
if (recipe.IsEncoded ?? false)
|
||||
{
|
||||
foreach (var reward in itemAndChildrenToSendToPlayer)
|
||||
{
|
||||
_itemHelper.AddUpdObjectToItem(reward.FirstOrDefault());
|
||||
|
||||
reward.FirstOrDefault().Upd.RecodableComponent = new UpdRecodableComponent { IsEncoded = true };
|
||||
}
|
||||
}
|
||||
|
||||
// Build an array of the tools that need to be returned to the player
|
||||
List<List<Item>> toolsToSendToPlayer = [];
|
||||
var hideoutProduction = pmcData.Hideout.Production[prodId];
|
||||
if (hideoutProduction.SptRequiredTools?.Count > 0)
|
||||
{
|
||||
foreach (var tool in hideoutProduction.SptRequiredTools)
|
||||
{
|
||||
toolsToSendToPlayer.Add([tool]);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the recipe is the same as the last one - get bonus when crafting same thing multiple times
|
||||
var area = pmcData.Hideout.Areas.FirstOrDefault(area => area.Type == recipe.AreaType);
|
||||
if (area is not null && request.RecipeId != area.LastRecipe)
|
||||
{
|
||||
// 1 point per craft upon the end of production for alternating between 2 different crafting recipes in the same module
|
||||
craftingExpAmount += _hideoutConfig.ExpCraftAmount; // Default is 10
|
||||
}
|
||||
|
||||
// Update variable with time spent crafting item(s)
|
||||
// 1 point per 8 hours of crafting
|
||||
@@ -814,34 +756,28 @@ public class HideoutController(
|
||||
foreach (var toolItem in toolsToSendToPlayer)
|
||||
{
|
||||
// Note: FIR state will be based on the first item's SpawnedInSession property per item group
|
||||
AddItemsDirectRequest addToolsRequest = new AddItemsDirectRequest
|
||||
var addToolsRequest = new AddItemsDirectRequest
|
||||
{
|
||||
ItemsWithModsToAdd = [toolItem],
|
||||
FoundInRaid = toolItem[0].Upd?.SpawnedInSession ?? false,
|
||||
UseSortingTable = false,
|
||||
Callback = null,
|
||||
Callback = null
|
||||
};
|
||||
|
||||
_inventoryHelper.AddItemsToStash(sessionID, addToolsRequest, pmcData, output);
|
||||
if (output.Warnings?.Count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (output.Warnings?.Count > 0) return;
|
||||
}
|
||||
|
||||
// Add the crafting result to the stash, marked as FiR
|
||||
AddItemsDirectRequest addItemsRequest = new AddItemsDirectRequest
|
||||
var addItemsRequest = new AddItemsDirectRequest
|
||||
{
|
||||
ItemsWithModsToAdd = itemAndChildrenToSendToPlayer,
|
||||
FoundInRaid = true,
|
||||
UseSortingTable = false,
|
||||
Callback = null,
|
||||
Callback = null
|
||||
};
|
||||
_inventoryHelper.AddItemsToStash(sessionID, addItemsRequest, pmcData, output);
|
||||
if (output.Warnings?.Count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (output.Warnings?.Count > 0) return;
|
||||
|
||||
// - increment skill point for crafting
|
||||
// - delete the production in profile Hideout.Production
|
||||
@@ -861,10 +797,7 @@ public class HideoutController(
|
||||
_profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Crafting, craftingExpAmount);
|
||||
|
||||
var intellectAmountToGive = 0.5 * Math.Round((double)(craftingExpAmount / 15));
|
||||
if (intellectAmountToGive > 0)
|
||||
{
|
||||
_profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Intellect, intellectAmountToGive);
|
||||
}
|
||||
if (intellectAmountToGive > 0) _profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Intellect, intellectAmountToGive);
|
||||
}
|
||||
|
||||
area.LastRecipe = request.RecipeId;
|
||||
@@ -879,36 +812,29 @@ public class HideoutController(
|
||||
// Continious recipies need the craft time refreshed as it gets created once on initial craft and stays the same regardless of what
|
||||
// production.json is set to
|
||||
if (recipe.Continuous ?? false)
|
||||
{
|
||||
pmcData.Hideout.Production[prodId].ProductionTime = _hideoutHelper.GetAdjustedCraftTimeWithSkills(
|
||||
pmcData,
|
||||
recipe.Id,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
// Flag normal (non continious) crafts as complete
|
||||
if (!recipe.Continuous ?? false)
|
||||
{
|
||||
pmcData.Hideout.Production[prodId].InProgress = false;
|
||||
}
|
||||
if (!recipe.Continuous ?? false) pmcData.Hideout.Production[prodId].InProgress = false;
|
||||
}
|
||||
|
||||
private TaskConditionCounter GetHoursCraftingTaskConditionCounter(PmcData pmcData, HideoutProduction recipe)
|
||||
{
|
||||
if (!pmcData.TaskConditionCounters.TryGetValue(HideoutController.NameTaskConditionCountersCraftingId, out var _))
|
||||
{
|
||||
if (!pmcData.TaskConditionCounters.TryGetValue(NameTaskConditionCountersCraftingId, out _))
|
||||
// Doesn't exist, create
|
||||
pmcData.TaskConditionCounters[HideoutController.NameTaskConditionCountersCraftingId] = new TaskConditionCounter
|
||||
pmcData.TaskConditionCounters[NameTaskConditionCountersCraftingId] = new TaskConditionCounter
|
||||
{
|
||||
Id = recipe.Id,
|
||||
Type = HideoutController.NameTaskConditionCountersCraftingId,
|
||||
Type = NameTaskConditionCountersCraftingId,
|
||||
SourceId = "CounterCrafting",
|
||||
Value = 0,
|
||||
Value = 0
|
||||
};
|
||||
}
|
||||
|
||||
return pmcData.TaskConditionCounters[HideoutController.NameTaskConditionCountersCraftingId];
|
||||
return pmcData.TaskConditionCounters[NameTaskConditionCountersCraftingId];
|
||||
}
|
||||
|
||||
private void HandleScavCase(string sessionID, PmcData pmcData, HideoutTakeProductionRequestData request, ItemEventRouterResponse output)
|
||||
@@ -916,14 +842,12 @@ public class HideoutController(
|
||||
var ongoingProductions = pmcData.Hideout.Production;
|
||||
string? prodId = null;
|
||||
foreach (var production in ongoingProductions)
|
||||
{
|
||||
// Production or ScavCase
|
||||
if ((production.Value).RecipeId == request.RecipeId)
|
||||
if (production.Value.RecipeId == request.RecipeId)
|
||||
{
|
||||
prodId = production.Key; // Set to objects key
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prodId == null)
|
||||
{
|
||||
@@ -942,19 +866,16 @@ public class HideoutController(
|
||||
// Create rewards for scav case
|
||||
var scavCaseRewards = _scavCaseRewardGenerator.Generate(request.RecipeId);
|
||||
|
||||
AddItemsDirectRequest addItemsRequest = new AddItemsDirectRequest
|
||||
var addItemsRequest = new AddItemsDirectRequest
|
||||
{
|
||||
ItemsWithModsToAdd = scavCaseRewards,
|
||||
FoundInRaid = true,
|
||||
Callback = null,
|
||||
UseSortingTable = false,
|
||||
UseSortingTable = false
|
||||
};
|
||||
|
||||
_inventoryHelper.AddItemsToStash(sessionID, addItemsRequest, pmcData, output);
|
||||
if (output.Warnings?.Count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (output.Warnings?.Count > 0) return;
|
||||
|
||||
// Remove the old production from output object before its sent to client
|
||||
output.ProfileChanges[sessionID].Production.Remove(request.RecipeId);
|
||||
@@ -981,7 +902,6 @@ public class HideoutController(
|
||||
var qteDb = _databaseService.GetHideout().Qte;
|
||||
var relevantQte = qteDb.FirstOrDefault(qte => qte.Id == request.Id);
|
||||
foreach (var outcome in request.Results)
|
||||
{
|
||||
if (outcome)
|
||||
{
|
||||
// Success
|
||||
@@ -994,17 +914,10 @@ public class HideoutController(
|
||||
pmcData.Health.Energy.Current += relevantQte.Results[QteEffectType.singleFailEffect].Energy;
|
||||
pmcData.Health.Hydration.Current += relevantQte.Results[QteEffectType.singleFailEffect].Hydration;
|
||||
}
|
||||
}
|
||||
|
||||
if (pmcData.Health.Energy.Current < 1)
|
||||
{
|
||||
pmcData.Health.Energy.Current = 1;
|
||||
}
|
||||
if (pmcData.Health.Energy.Current < 1) pmcData.Health.Energy.Current = 1;
|
||||
|
||||
if (pmcData.Health.Hydration.Current < 1)
|
||||
{
|
||||
pmcData.Health.Hydration.Current = 1;
|
||||
}
|
||||
if (pmcData.Health.Hydration.Current < 1) pmcData.Health.Hydration.Current = 1;
|
||||
|
||||
HandleMusclePain(pmcData, relevantQte.Results[QteEffectType.finishEffect]);
|
||||
}
|
||||
@@ -1021,7 +934,7 @@ public class HideoutController(
|
||||
pmcData.Health.BodyParts["Chest"].Effects ??= new Dictionary<string, BodyPartEffectProperties>();
|
||||
pmcData.Health.BodyParts["Chest"].Effects["MildMusclePain"] = new BodyPartEffectProperties
|
||||
{
|
||||
Time = finishEffect.RewardEffects.FirstOrDefault().Time, // TODO - remove hard coded access, get value properly
|
||||
Time = finishEffect.RewardEffects.FirstOrDefault().Time // TODO - remove hard coded access, get value properly
|
||||
};
|
||||
|
||||
return;
|
||||
@@ -1034,7 +947,7 @@ public class HideoutController(
|
||||
|
||||
pmcData.Health.BodyParts["Chest"].Effects["SevereMusclePain"] = new BodyPartEffectProperties
|
||||
{
|
||||
Time = finishEffect.RewardEffects.FirstOrDefault().Time,
|
||||
Time = finishEffect.RewardEffects.FirstOrDefault().Time
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1086,13 +999,9 @@ public class HideoutController(
|
||||
item.inventoryItem.Upd.StackObjectsCount is not null &&
|
||||
item.inventoryItem.Upd.StackObjectsCount > item.requestedItem.Count
|
||||
)
|
||||
{
|
||||
item.inventoryItem.Upd.StackObjectsCount -= item.requestedItem.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
_inventoryHelper.RemoveItem(pmcData, item.inventoryItem.Id, sessionId, output);
|
||||
}
|
||||
}
|
||||
|
||||
var profileHideoutArea = pmcData.Hideout.Areas.FirstOrDefault(x => x.Type == request.AreaType);
|
||||
@@ -1115,17 +1024,14 @@ public class HideoutController(
|
||||
var improvements = hideoutDbData.Stages[profileHideoutArea.Level.ToString()].Improvements;
|
||||
var timestamp = _timeUtil.GetTimeStamp();
|
||||
|
||||
if (output.ProfileChanges[sessionId].Improvements is null)
|
||||
{
|
||||
output.ProfileChanges[sessionId].Improvements = new Dictionary<string, HideoutImprovement>();
|
||||
}
|
||||
if (output.ProfileChanges[sessionId].Improvements is null) output.ProfileChanges[sessionId].Improvements = new Dictionary<string, HideoutImprovement>();
|
||||
|
||||
foreach (var improvement in improvements)
|
||||
{
|
||||
var improvementDetails = new HideoutImprovement
|
||||
{
|
||||
Completed = false,
|
||||
ImproveCompleteTimestamp = (long)(timestamp + improvement.ImprovementTime),
|
||||
ImproveCompleteTimestamp = (long)(timestamp + improvement.ImprovementTime)
|
||||
};
|
||||
output.ProfileChanges[sessionId].Improvements[improvement.Id] = improvementDetails;
|
||||
|
||||
@@ -1232,7 +1138,7 @@ public class HideoutController(
|
||||
Id = standId,
|
||||
Template = ItemTpl.INVENTORY_DEFAULT,
|
||||
ParentId = equipmentPresetHideoutArea.Id,
|
||||
SlotId = mannequinSlot.Name,
|
||||
SlotId = mannequinSlot.Name
|
||||
};
|
||||
pmcData.Inventory.Items.Add(mannequinToAdd);
|
||||
|
||||
@@ -1245,7 +1151,7 @@ public class HideoutController(
|
||||
)
|
||||
.Template, // Same pocket tpl as players profile (unheard get bigger, matching pockets etc)
|
||||
ParentId = standId,
|
||||
SlotId = "Pockets",
|
||||
SlotId = "Pockets"
|
||||
};
|
||||
pmcData.Inventory.Items.Add(mannequinPocketItemToAdd);
|
||||
output.ProfileChanges[sessionId].Items.NewItems.Add(mannequinToAdd);
|
||||
@@ -1290,16 +1196,12 @@ public class HideoutController(
|
||||
public void Update()
|
||||
{
|
||||
foreach (var sessionID in _saveServer.GetProfiles())
|
||||
{
|
||||
if (sessionID.Value.CharacterData.PmcData.Hideout is not null &&
|
||||
_profileActivityService.ActiveWithinLastMinutes(
|
||||
sessionID.Key,
|
||||
_hideoutConfig.UpdateProfileHideoutWhenActiveWithinMinutes
|
||||
)
|
||||
)
|
||||
{
|
||||
_hideoutHelper.UpdatePlayerHideout(sessionID.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ public class InRaidController(
|
||||
ConfigServer _configServer
|
||||
)
|
||||
{
|
||||
protected InRaidConfig _inRaidConfig = _configServer.GetConfig<InRaidConfig>();
|
||||
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
protected InRaidConfig _inRaidConfig = _configServer.GetConfig<InRaidConfig>();
|
||||
|
||||
/// <summary>
|
||||
/// Save locationId to active profiles in-raid object AND app context
|
||||
@@ -43,9 +43,7 @@ public class InRaidController(
|
||||
// If equipment match overwrite existing data from update to date raid data for scavenger screen to work correctly.
|
||||
// otherwise Scav inventory will be overwritten and break scav regeneration, breaking profile.
|
||||
if (serverScavProfile.Inventory.Equipment == offRaidProfileData.Inventory.Equipment)
|
||||
{
|
||||
serverScavProfile.Inventory.Items = offRaidProfileData.Inventory.Items;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -86,12 +86,8 @@ public class InsuranceController(
|
||||
|
||||
var profileInsuranceDetails = _saveServer.GetProfile(sessionId).InsuranceList;
|
||||
if (profileInsuranceDetails.Count > 0)
|
||||
{
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
_logger.Debug($"Found {profileInsuranceDetails.Count} insurance packages in profile {sessionId}");
|
||||
}
|
||||
}
|
||||
|
||||
return profileInsuranceDetails.Where(insured => insuranceTime >= insured.ScheduledTime).ToList();
|
||||
}
|
||||
@@ -105,12 +101,10 @@ public class InsuranceController(
|
||||
*/
|
||||
protected void ProcessInsuredItems(List<Insurance> insuranceDetails, string sessionId)
|
||||
{
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
_logger.Debug(
|
||||
$"Processing {insuranceDetails.Count} insurance packages, which includes a total of: {CountAllInsuranceItems(insuranceDetails)} items, in profile: {sessionId}"
|
||||
);
|
||||
}
|
||||
|
||||
// Iterate over each of the insurance packages.
|
||||
foreach (var insured in insuranceDetails)
|
||||
@@ -170,10 +164,7 @@ public class InsuranceController(
|
||||
)
|
||||
.ToList();
|
||||
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Removed processed insurance package. Remaining packages: {profile.InsuranceList.Count}");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Removed processed insurance package. Remaining packages: {profile.InsuranceList.Count}");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,10 +189,7 @@ public class InsuranceController(
|
||||
);
|
||||
|
||||
// Process all items that are not attached, attachments; those are handled separately, by value.
|
||||
if (hasRegularItems)
|
||||
{
|
||||
ProcessRegularItems(insured, toDelete, parentAttachmentsMap);
|
||||
}
|
||||
if (hasRegularItems) ProcessRegularItems(insured, toDelete, parentAttachmentsMap);
|
||||
|
||||
// Process attached, attachments, by value, only if there are any.
|
||||
if (parentAttachmentsMap.Count > 0)
|
||||
@@ -215,12 +203,8 @@ public class InsuranceController(
|
||||
|
||||
// Log the number of items marked for deletion, if any
|
||||
if (!toDelete.Any())
|
||||
{
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
_logger.Debug($"Marked {toDelete.Count} items for deletion from insurance.");
|
||||
}
|
||||
}
|
||||
|
||||
return toDelete;
|
||||
}
|
||||
@@ -253,7 +237,7 @@ public class InsuranceController(
|
||||
{
|
||||
insuredItemId = insuredItem.Id,
|
||||
insuredItemTpl = insuredItem.Template,
|
||||
parentId = insuredItem.ParentId,
|
||||
parentId = insuredItem.ParentId
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -273,7 +257,7 @@ public class InsuranceController(
|
||||
new
|
||||
{
|
||||
insuredItemId = insuredItem.Id,
|
||||
insuredItemTpl = insuredItem.Template,
|
||||
insuredItemTpl = insuredItem.Template
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -293,7 +277,7 @@ public class InsuranceController(
|
||||
{
|
||||
insuredItemId = insuredItem.Id,
|
||||
insuredItemTpl = insuredItem.Template,
|
||||
parentId = insuredItem.ParentId,
|
||||
parentId = insuredItem.ParentId
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -304,10 +288,7 @@ public class InsuranceController(
|
||||
// Update (or add to) the main-parent to attachments map.
|
||||
if (mainParentToAttachmentsMap.ContainsKey(mainParent.Id))
|
||||
{
|
||||
if (mainParentToAttachmentsMap.TryGetValue(mainParent.Id, out var parent))
|
||||
{
|
||||
parent.Add(insuredItem);
|
||||
}
|
||||
if (mainParentToAttachmentsMap.TryGetValue(mainParent.Id, out var parent)) parent.Add(insuredItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -344,24 +325,14 @@ public class InsuranceController(
|
||||
// attachment on the main-parent. For example, if the attachment is a stock, we need to check to see if
|
||||
// it's moddable in the upper receiver (attachment/parent), which is attached to the gun (main-parent).
|
||||
if (attachment.ParentId is not null)
|
||||
{
|
||||
if (itemsMap.TryGetValue(attachment.ParentId, out var directParentItem))
|
||||
{
|
||||
attachmentParentItem = directParentItem;
|
||||
}
|
||||
}
|
||||
|
||||
if (_itemHelper.IsRaidModdable(attachment, attachmentParentItem) ?? false)
|
||||
{
|
||||
moddableAttachments.Add(attachment);
|
||||
}
|
||||
if (_itemHelper.IsRaidModdable(attachment, attachmentParentItem) ?? false) moddableAttachments.Add(attachment);
|
||||
}
|
||||
|
||||
// If any moddable attachments remain, add them to the updated map.
|
||||
if (moddableAttachments.Count > 0)
|
||||
{
|
||||
updatedMap.TryAdd(map.Key, moddableAttachments);
|
||||
}
|
||||
if (moddableAttachments.Count > 0) updatedMap.TryAdd(map.Key, moddableAttachments);
|
||||
}
|
||||
|
||||
return updatedMap;
|
||||
@@ -382,10 +353,7 @@ public class InsuranceController(
|
||||
foreach (var insuredItem in insured.Items)
|
||||
{
|
||||
// Skip if the item is an attachment. These are handled separately.
|
||||
if (_itemHelper.IsAttachmentAttached(insuredItem))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (_itemHelper.IsAttachmentAttached(insuredItem)) continue;
|
||||
|
||||
// Roll for item deletion
|
||||
var itemRoll = RollForDelete(insured.TraderId, insuredItem);
|
||||
@@ -401,10 +369,7 @@ public class InsuranceController(
|
||||
insured.Items,
|
||||
insuredItem.Id
|
||||
);
|
||||
foreach (var item in itemAndChildren)
|
||||
{
|
||||
toDelete.Add(item.Id);
|
||||
}
|
||||
foreach (var item in itemAndChildren) toDelete.Add(item.Id);
|
||||
|
||||
// Remove the parent (and its children) from the parentAttachmentsMap.
|
||||
parentAttachmentsMap.Remove(insuredItem.Id);
|
||||
@@ -433,18 +398,12 @@ public class InsuranceController(
|
||||
{
|
||||
// Skip processing if parentId is already marked for deletion, as all attachments for that parent will
|
||||
// already be marked for deletion as well.
|
||||
if (toDelete.Contains(parentObj.Key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (toDelete.Contains(parentObj.Key)) continue;
|
||||
|
||||
// Log the parent item's name.
|
||||
itemsMap.TryGetValue(parentObj.Key, out var parentItem);
|
||||
var parentName = _itemHelper.GetItemName(parentItem.Template);
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Processing attachments of parent {parentName}");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Processing attachments of parent {parentName}");
|
||||
|
||||
// Process the attachments for this individual parent item.
|
||||
ProcessAttachmentByParent(parentObj.Value, insuredTraderId, toDelete);
|
||||
@@ -473,25 +432,17 @@ public class InsuranceController(
|
||||
// Create prob array and add all attachments with rouble price as the weight
|
||||
var attachmentsProbabilityArray = new ProbabilityObjectArray<string, double?>(_mathUtil, _cloner);
|
||||
foreach (var attachmentTpl in weightedAttachmentByPrice)
|
||||
{
|
||||
attachmentsProbabilityArray.Add(
|
||||
new ProbabilityObject<string, double?>(attachmentTpl.Key, attachmentTpl.Value, null)
|
||||
);
|
||||
}
|
||||
|
||||
// Draw x attachments from weighted array to remove from parent, remove from pool after being picked
|
||||
var attachmentIdsToRemove = attachmentsProbabilityArray.Draw((int)countOfAttachmentsToRemove, false);
|
||||
foreach (var attachmentId in attachmentIdsToRemove)
|
||||
{
|
||||
toDelete.Add(attachmentId);
|
||||
}
|
||||
foreach (var attachmentId in attachmentIdsToRemove) toDelete.Add(attachmentId);
|
||||
|
||||
LogAttachmentsBeingRemoved(attachmentIdsToRemove, attachments, weightedAttachmentByPrice);
|
||||
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Number of attachments to be deleted: {attachmentIdsToRemove.Count}");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Number of attachments to be deleted: {attachmentIdsToRemove.Count}");
|
||||
}
|
||||
|
||||
private void LogAttachmentsBeingRemoved(List<string> attachmentIdsToRemove, List<Item> attachments, Dictionary<string, double> attachmentPrices)
|
||||
@@ -500,12 +451,10 @@ public class InsuranceController(
|
||||
foreach (var attachmentId in attachmentIdsToRemove)
|
||||
{
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug(
|
||||
$"Attachment {index} Id: {attachmentId} Tpl: {attachments.FirstOrDefault((x) => x.Id == attachmentId)?.Template} - " +
|
||||
$"Price: {attachmentPrices[attachmentId]}"
|
||||
);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@@ -518,10 +467,7 @@ public class InsuranceController(
|
||||
foreach (var attachment in attachments)
|
||||
{
|
||||
var price = _ragfairPriceService.GetDynamicItemPrice(attachment.Template, Money.ROUBLES);
|
||||
if (price is not null)
|
||||
{
|
||||
result[attachment.Id] = Math.Round(price ?? 0);
|
||||
}
|
||||
if (price is not null) result[attachment.Id] = Math.Round(price ?? 0);
|
||||
}
|
||||
|
||||
_weightedRandomHelper.ReduceWeightValues(result);
|
||||
@@ -533,10 +479,7 @@ public class InsuranceController(
|
||||
{
|
||||
var removeCount = 0;
|
||||
|
||||
if (_randomUtil.GetChance100(_insuranceConfig.ChanceNoAttachmentsTakenPercent))
|
||||
{
|
||||
return removeCount;
|
||||
}
|
||||
if (_randomUtil.GetChance100(_insuranceConfig.ChanceNoAttachmentsTakenPercent)) return removeCount;
|
||||
|
||||
// Get attachments count above or equal to price set in config
|
||||
return weightedAttachmentByPrice
|
||||
@@ -564,19 +507,13 @@ public class InsuranceController(
|
||||
|
||||
// Map is labs + insurance is disabled in base.json
|
||||
if (IsMapLabsAndInsuranceDisabled(insurance))
|
||||
{
|
||||
// Trader has labs-specific messages
|
||||
// Wipe out returnable items
|
||||
HandleLabsInsurance(traderDialogMessages, insurance);
|
||||
}
|
||||
else if (insurance.Items?.Count == 0)
|
||||
{
|
||||
// Not labs and no items to return
|
||||
if (traderDialogMessages.TryGetValue("insuranceFailed", out var insuranceFailedTemplates))
|
||||
{
|
||||
insurance.MessageTemplateId = _randomUtil.GetArrayValue(insuranceFailedTemplates);
|
||||
}
|
||||
}
|
||||
|
||||
// Send the insurance message
|
||||
_mailSendService.SendLocalisedNpcMessageToPlayer(
|
||||
@@ -592,9 +529,8 @@ public class InsuranceController(
|
||||
|
||||
private bool IsMapLabsAndInsuranceDisabled(Insurance insurance, string labsId = "laboratory")
|
||||
{
|
||||
return (insurance.SystemData?.Location?.ToLower() == labsId
|
||||
&& !(_databaseService.GetLocation(labsId)?.Base?.Insurance.GetValueOrDefault(false) ?? false)
|
||||
);
|
||||
return insurance.SystemData?.Location?.ToLower() == labsId &&
|
||||
!(_databaseService.GetLocation(labsId)?.Base?.Insurance.GetValueOrDefault(false) ?? false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -618,10 +554,7 @@ public class InsuranceController(
|
||||
private bool? RollForDelete(string traderId, Item? insuredItem = null)
|
||||
{
|
||||
var trader = _traderHelper.GetTraderById(traderId);
|
||||
if (trader is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (trader is null) return null;
|
||||
|
||||
const int maxRoll = 9999;
|
||||
const int conversionFactor = 100;
|
||||
@@ -633,10 +566,8 @@ public class InsuranceController(
|
||||
// Log the roll with as much detail as possible.
|
||||
var itemName = insuredItem is not null ? $"{_itemHelper.GetItemName(insuredItem.Template)}" : "";
|
||||
var status = roll ? "Delete" : "Keep";
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
_logger.Debug($"Rolling {itemName} with {trader} - Return {traderReturnChance}% - Roll: {returnChance} - Status: {status}");
|
||||
}
|
||||
|
||||
return roll;
|
||||
}
|
||||
@@ -661,7 +592,6 @@ public class InsuranceController(
|
||||
|
||||
// Get price of all items being insured, add to 'itemsToPay'
|
||||
foreach (var key in body.Items)
|
||||
{
|
||||
itemsToPay.Add(
|
||||
new IdWithCount
|
||||
{
|
||||
@@ -673,7 +603,6 @@ public class InsuranceController(
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var options = new ProcessBuyTradeRequestData
|
||||
{
|
||||
@@ -688,10 +617,7 @@ public class InsuranceController(
|
||||
|
||||
// pay for the item insurance
|
||||
_paymentService.PayMoney(pmcData, options, sessionId, output);
|
||||
if (output.Warnings?.Count > 0)
|
||||
{
|
||||
return output;
|
||||
}
|
||||
if (output.Warnings?.Count > 0) return output;
|
||||
|
||||
// add items to InsuredItems list once money has been paid
|
||||
pmcData.InsuredItems ??= [];
|
||||
@@ -699,10 +625,7 @@ public class InsuranceController(
|
||||
{
|
||||
pmcData.InsuredItems.Add(new InsuredItem { TId = body.TransactionId, ItemId = inventoryItemsHash[key].Id });
|
||||
// If Item is Helmet or Body Armour -> Handle insurance of soft inserts
|
||||
if (_itemHelper.ArmorItemHasRemovableOrSoftInsertSlots(inventoryItemsHash[key].Template))
|
||||
{
|
||||
InsureSoftInserts(inventoryItemsHash[key], pmcData, body);
|
||||
}
|
||||
if (_itemHelper.ArmorItemHasRemovableOrSoftInsertSlots(inventoryItemsHash[key].Template)) InsureSoftInserts(inventoryItemsHash[key], pmcData, body);
|
||||
}
|
||||
|
||||
_profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Charisma, itemsToInsureCount * 0.01);
|
||||
@@ -726,11 +649,8 @@ public class InsuranceController(
|
||||
|
||||
foreach (var softInsertSlot in softInsertSlots)
|
||||
{
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"SoftInsertSlots: {softInsertSlot.SlotId}");
|
||||
}
|
||||
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"SoftInsertSlots: {softInsertSlot.SlotId}");
|
||||
|
||||
pmcData.InsuredItems.Add(new InsuredItem { TId = body.TransactionId, ItemId = softInsertSlot.Id });
|
||||
}
|
||||
}
|
||||
@@ -761,10 +681,7 @@ public class InsuranceController(
|
||||
// Ensure hash has item in it
|
||||
if (!inventoryItemsHash.ContainsKey(itemId))
|
||||
{
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Item with id: {itemId} missing from player inventory, skipping");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Item with id: {itemId} missing from player inventory, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,9 +83,7 @@ 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") || originalLocationSlotId.StartsWith("dogtag")))
|
||||
{
|
||||
_hideoutHelper.ApplyPlaceOfFameDogtagBonus(pmcData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -155,7 +153,7 @@ public class InventoryController(
|
||||
_logger.Success($"Set trader {mailEvent.Entity}: Standing to: {mailEvent.Value}");
|
||||
break;
|
||||
case ProfileChangeEventType.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}");
|
||||
@@ -347,23 +345,16 @@ public class InventoryController(
|
||||
inventoryItem.ParentId = change.ParentId;
|
||||
inventoryItem.SlotId = change.SlotId;
|
||||
if (change.Location is not null)
|
||||
{
|
||||
inventoryItem.Location = change.Location;
|
||||
}
|
||||
else
|
||||
{
|
||||
inventoryItem.Location = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ItemEventRouterResponse ReadEncyclopedia(PmcData pmcData, InventoryReadEncyclopediaRequestData body,
|
||||
string sessionId)
|
||||
{
|
||||
foreach (var id in body.Ids)
|
||||
{
|
||||
pmcData.Encyclopedia[id] = true;
|
||||
}
|
||||
foreach (var id in body.Ids) pmcData.Encyclopedia[id] = true;
|
||||
|
||||
return _eventOutputHolder.GetOutput(sessionId);
|
||||
}
|
||||
@@ -373,7 +364,6 @@ public class InventoryController(
|
||||
{
|
||||
string? itemId = null;
|
||||
if (request.FromOwner is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
itemId = GetExaminedItemTpl(request, sessionId);
|
||||
@@ -382,25 +372,17 @@ public class InventoryController(
|
||||
{
|
||||
_logger.Error(_localisationService.GetText("inventory-examine_item_does_not_exist", request.Item));
|
||||
}
|
||||
}
|
||||
|
||||
if (itemId is null)
|
||||
{
|
||||
// item template
|
||||
if (_databaseService.GetItems().ContainsKey(request.Item))
|
||||
{
|
||||
itemId = request.Item;
|
||||
}
|
||||
}
|
||||
|
||||
if (itemId is null)
|
||||
{
|
||||
// Player inventory
|
||||
var target = pmcData.Inventory.Items.FirstOrDefault(item => item.Id == request.Item);
|
||||
if (target is not null)
|
||||
{
|
||||
itemId = target.Template;
|
||||
}
|
||||
if (target is not null) itemId = target.Template;
|
||||
}
|
||||
|
||||
if (itemId is not null)
|
||||
@@ -415,29 +397,22 @@ public class InventoryController(
|
||||
if (_presetHelper.IsPreset(request.Item)) return _presetHelper.GetBaseItemTpl(request.Item);
|
||||
|
||||
if (request.FromOwner.Id == Traders.FENCE)
|
||||
{
|
||||
// Get tpl from fence assorts
|
||||
return _fenceService.GetRawFenceAssorts().Items.FirstOrDefault(x => x.Id == request.Item)?.Template;
|
||||
}
|
||||
|
||||
if (request.FromOwner.Type == "Trader")
|
||||
{
|
||||
// Not fence
|
||||
// get tpl from trader assort
|
||||
return _databaseService
|
||||
.GetTrader(request.FromOwner.Id)
|
||||
.Assort.Items.FirstOrDefault(item => item.Id == request.Item)
|
||||
?.Template;
|
||||
}
|
||||
|
||||
if (request.FromOwner.Type == "RagFair")
|
||||
{
|
||||
// Try to get tplId from items.json first
|
||||
var item = _itemHelper.GetItem(request.Item);
|
||||
if (item.Key)
|
||||
{
|
||||
return item.Value.Id;
|
||||
}
|
||||
if (item.Key) return item.Value.Id;
|
||||
|
||||
// Try alternate way of getting offer if first approach fails
|
||||
var offer = _ragfairOfferService.GetOfferByOfferId(request.Item) ??
|
||||
@@ -445,20 +420,14 @@ public class InventoryController(
|
||||
|
||||
// Try find examine item inside offer items array
|
||||
var matchingItem = offer.Items.FirstOrDefault(offerItem => offerItem.Id == request.Item);
|
||||
if (matchingItem is not null)
|
||||
{
|
||||
return matchingItem.Template;
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
// get hideout item
|
||||
if (request.FromOwner.Type == "HideoutProduction")
|
||||
{
|
||||
return request.Item;
|
||||
}
|
||||
if (request.FromOwner.Type == "HideoutProduction") return request.Item;
|
||||
|
||||
if (request.FromOwner.Type == "Mail")
|
||||
{
|
||||
@@ -472,10 +441,7 @@ public class InventoryController(
|
||||
// get the Id given and get the Template ID from that
|
||||
var item = message.Items.Data.FirstOrDefault(item => item.Id == request.Item);
|
||||
|
||||
if (item is not null)
|
||||
{
|
||||
return item.Template;
|
||||
}
|
||||
if (item is not null) return item.Template;
|
||||
}
|
||||
|
||||
_logger.Error($"Unable to get item with id: {request.Item}");
|
||||
@@ -559,10 +525,7 @@ public class InventoryController(
|
||||
var playerData = pmcData;
|
||||
|
||||
// We may be folding data on scav profile, get that profile instead
|
||||
if (request.FromOwner?.Type == "Profile" && request.FromOwner.Id != playerData.Id)
|
||||
{
|
||||
playerData = _profileHelper.GetScavProfile(sessionId);
|
||||
}
|
||||
if (request.FromOwner?.Type == "Profile" && request.FromOwner.Id != playerData.Id) playerData = _profileHelper.GetScavProfile(sessionId);
|
||||
|
||||
var itemToFold = playerData.Inventory.Items.FirstOrDefault(item => item?.Id == request.Item);
|
||||
if (itemToFold is null)
|
||||
@@ -592,10 +555,7 @@ public class InventoryController(
|
||||
{
|
||||
// During post-raid scav transfer, the swap may be in the scav inventory
|
||||
var playerData = pmcData;
|
||||
if (request.FromOwner?.Type == "Profile" && request.FromOwner.Id != playerData.Id)
|
||||
{
|
||||
playerData = _profileHelper.GetScavProfile(sessionId);
|
||||
}
|
||||
if (request.FromOwner?.Type == "Profile" && request.FromOwner.Id != playerData.Id) playerData = _profileHelper.GetScavProfile(sessionId);
|
||||
|
||||
var itemOne = playerData.Inventory.Items.FirstOrDefault(x => x.Id == request.Item);
|
||||
if (itemOne is null)
|
||||
@@ -631,24 +591,16 @@ public class InventoryController(
|
||||
|
||||
// Request object has location data, add it in, otherwise remove existing location from object
|
||||
if (request.To.Location is not null)
|
||||
{
|
||||
itemOne.Location = request.To.Location;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemOne.Location = null;
|
||||
}
|
||||
|
||||
itemTwo.ParentId = request.To2.Id;
|
||||
itemTwo.SlotId = request.To2.Container;
|
||||
if (request.To2.Location is not null)
|
||||
{
|
||||
itemTwo.Location = request.To2.Location;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemTwo.Location = null;
|
||||
}
|
||||
|
||||
// Client already informed of inventory locations, nothing for us to do
|
||||
return _eventOutputHolder.GetOutput(sessionId);
|
||||
@@ -696,15 +648,11 @@ public class InventoryController(
|
||||
|
||||
var sourceStackCount = sourceItem.Upd.StackObjectsCount;
|
||||
if (sourceStackCount > request.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
|
||||
sourceItem.Upd.StackObjectsCount = sourceStackCount - 1;
|
||||
}
|
||||
|
||||
destinationItem.Upd ??= new Upd { StackObjectsCount = 1 };
|
||||
|
||||
@@ -743,27 +691,19 @@ public class InventoryController(
|
||||
}
|
||||
|
||||
if (destinationItem.Upd?.StackObjectsCount is null)
|
||||
{
|
||||
// No stackcount on destination, add one
|
||||
destinationItem.Upd = new Upd { StackObjectsCount = 1 };
|
||||
}
|
||||
|
||||
if (sourceItem.Upd is null)
|
||||
{
|
||||
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
|
||||
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))
|
||||
{
|
||||
destinationItem.Upd.SpawnedInSession = false;
|
||||
}
|
||||
|
||||
destinationItem.Upd.StackObjectsCount +=
|
||||
sourceItem.Upd.StackObjectsCount; // Add source stackcount to destination
|
||||
|
||||
@@ -45,7 +45,7 @@ public class LauncherController(
|
||||
BackendUrl = _httpServerHelper.GetBackendUrl(),
|
||||
Name = _coreConfig.ServerName,
|
||||
Editions = profiles,
|
||||
ProfileDescriptions = GetProfileDescriptions(),
|
||||
ProfileDescriptions = GetProfileDescriptions()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -83,10 +83,7 @@ public class LauncherController(
|
||||
foreach (var kvp in _saveServer.GetProfiles())
|
||||
{
|
||||
var account = _saveServer.GetProfile(kvp.Key).ProfileInfo;
|
||||
if (info?.Username == account?.Username)
|
||||
{
|
||||
return kvp.Key;
|
||||
}
|
||||
if (info?.Username == account?.Username) return kvp.Key;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -95,12 +92,8 @@ public class LauncherController(
|
||||
public string Register(RegisterData info)
|
||||
{
|
||||
foreach (var kvp in _saveServer.GetProfiles())
|
||||
{
|
||||
if (info.Username == _saveServer.GetProfile(kvp.Key).ProfileInfo?.Username)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
return CreateAccount(info);
|
||||
}
|
||||
@@ -117,7 +110,7 @@ public class LauncherController(
|
||||
Username = info.Username,
|
||||
Password = info.Password,
|
||||
IsWiped = true,
|
||||
Edition = info.Edition,
|
||||
Edition = info.Edition
|
||||
};
|
||||
_saveServer.CreateProfile(newProfileDetails);
|
||||
|
||||
@@ -146,10 +139,7 @@ public class LauncherController(
|
||||
{
|
||||
var sessionID = Login(info);
|
||||
|
||||
if (!string.IsNullOrEmpty(sessionID))
|
||||
{
|
||||
_saveServer.GetProfile(sessionID).ProfileInfo!.Username = info.Change;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(sessionID)) _saveServer.GetProfile(sessionID).ProfileInfo!.Username = info.Change;
|
||||
|
||||
return sessionID;
|
||||
}
|
||||
@@ -158,10 +148,7 @@ public class LauncherController(
|
||||
{
|
||||
var sessionID = Login(info);
|
||||
|
||||
if (!string.IsNullOrEmpty(sessionID))
|
||||
{
|
||||
_saveServer.GetProfile(sessionID).ProfileInfo!.Password = info.Change;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(sessionID)) _saveServer.GetProfile(sessionID).ProfileInfo!.Password = info.Change;
|
||||
|
||||
return sessionID;
|
||||
}
|
||||
@@ -173,10 +160,7 @@ public class LauncherController(
|
||||
*/
|
||||
public string? Wipe(RegisterData info)
|
||||
{
|
||||
if (!_coreConfig.AllowProfileWipe)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!_coreConfig.AllowProfileWipe) return null;
|
||||
|
||||
var sessionID = Login(info);
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ public class LauncherV2Controller(
|
||||
var casterPropertyValue = propertyValue as ProfileSides;
|
||||
result[templatesProperty.GetJsonName()] = _localisationService.GetText(casterPropertyValue?.DescriptionLocaleKey!);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -82,12 +82,8 @@ public class LauncherV2Controller(
|
||||
public bool Register(RegisterData info)
|
||||
{
|
||||
foreach (var session in _saveServer.GetProfiles())
|
||||
{
|
||||
if (info.Username == _saveServer.GetProfile(session.Key).ProfileInfo!.Username)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CreateAccount(info);
|
||||
return true;
|
||||
@@ -104,7 +100,7 @@ public class LauncherV2Controller(
|
||||
|
||||
if (sessionId is null)
|
||||
return false;
|
||||
|
||||
|
||||
_saveServer.GetProfile(sessionId).ProfileInfo!.Password = info.Password;
|
||||
return true;
|
||||
}
|
||||
@@ -117,7 +113,7 @@ public class LauncherV2Controller(
|
||||
public bool Remove(LoginRequestData info)
|
||||
{
|
||||
var sessionId = GetSessionId(info);
|
||||
|
||||
|
||||
return sessionId is not null && _saveServer.RemoveProfile(sessionId);
|
||||
}
|
||||
|
||||
@@ -169,22 +165,22 @@ public class LauncherV2Controller(
|
||||
IsWiped = true,
|
||||
Edition = info.Edition
|
||||
};
|
||||
|
||||
|
||||
_saveServer.CreateProfile(newProfileDetails);
|
||||
|
||||
|
||||
_saveServer.LoadProfile(profileId);
|
||||
_saveServer.SaveProfile(profileId);
|
||||
|
||||
|
||||
return profileId;
|
||||
}
|
||||
|
||||
|
||||
protected string GenerateProfileId()
|
||||
{
|
||||
var timestamp = _timeUtil.GetTimeStamp();
|
||||
|
||||
return FormatID(timestamp, timestamp * _randomUtil.GetInt(1, 1000000));
|
||||
}
|
||||
|
||||
|
||||
protected string FormatID(long timeStamp, long counter)
|
||||
{
|
||||
var timeStampStr = Convert.ToString(timeStamp, 16).PadLeft(8, '0');
|
||||
@@ -196,13 +192,8 @@ public class LauncherV2Controller(
|
||||
protected string? GetSessionId(LoginRequestData info)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ public class LocationController(
|
||||
ICloner _cloner
|
||||
)
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Handle client/locations
|
||||
/// Get all maps base location properties without loot data
|
||||
@@ -38,10 +37,7 @@ public class LocationController(
|
||||
var mapBase = kvp.Value.Base;
|
||||
if (mapBase == null)
|
||||
{
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Map: {kvp} has no base json file, skipping generation");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Map: {kvp} has no base json file, skipping generation");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -65,10 +61,7 @@ public class LocationController(
|
||||
/// <returns></returns>
|
||||
public GetAirdropLootResponse? GetAirDropLoot(GetAirdropLootRequest? request)
|
||||
{
|
||||
if (request?.ContainerId is not null)
|
||||
{
|
||||
return _airdropService.GenerateCustomAirdropLoot(request);
|
||||
}
|
||||
if (request?.ContainerId is not null) return _airdropService.GenerateCustomAirdropLoot(request);
|
||||
|
||||
return _airdropService.GenerateAirdropLoot();
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public class MatchController(
|
||||
/// <returns></returns>
|
||||
public ProfileStatusResponse JoinMatch(MatchGroupStartGameRequest info, string sessionId)
|
||||
{
|
||||
ProfileStatusResponse output = new ProfileStatusResponse
|
||||
var output = new ProfileStatusResponse
|
||||
{
|
||||
MaxPveCountExceeded = false,
|
||||
// get list of players joining into the match
|
||||
@@ -105,11 +105,9 @@ public class MatchController(
|
||||
|
||||
// Set pmcs to difficulty set in pre-raid screen if override in bot config isnt enabled
|
||||
if (!_pmcConfig.UseDifficultyOverride)
|
||||
{
|
||||
_pmcConfig.Difficulty = ConvertDifficultyDropdownIntoBotDifficulty(
|
||||
request.WavesSettings.BotDifficulty.ToString()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -120,10 +118,7 @@ public class MatchController(
|
||||
private string ConvertDifficultyDropdownIntoBotDifficulty(string botDifficulty)
|
||||
{
|
||||
// Edge case medium - must be altered
|
||||
if (botDifficulty.ToLower() == "medium")
|
||||
{
|
||||
return "normal";
|
||||
}
|
||||
if (botDifficulty.ToLower() == "medium") return "normal";
|
||||
|
||||
return botDifficulty;
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@ public class NoteController(
|
||||
NoteActionData body,
|
||||
string sessionId)
|
||||
{
|
||||
Note newNote = new Note { Time = body.Note.Time, Text = body.Note.Text };
|
||||
var newNote = new Note { Time = body.Note.Time, Text = body.Note.Text };
|
||||
pmcData.Notes.DataNotes.Add(newNote);
|
||||
|
||||
|
||||
return _eventOutputHolder.GetOutput(sessionId);
|
||||
}
|
||||
|
||||
@@ -41,10 +41,10 @@ public class NoteController(
|
||||
NoteActionData body,
|
||||
string sessionId)
|
||||
{
|
||||
Note noteToEdit = pmcData.Notes.DataNotes[body.Index!.Value];
|
||||
var noteToEdit = pmcData.Notes.DataNotes[body.Index!.Value];
|
||||
noteToEdit.Time = body.Note.Time;
|
||||
noteToEdit.Text = body.Note.Text;
|
||||
|
||||
|
||||
return _eventOutputHolder.GetOutput(sessionId);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Core.Controllers;
|
||||
public class NotifierController(
|
||||
HttpServerHelper _httpServerHelper,
|
||||
NotifierHelper _notifierHelper
|
||||
)
|
||||
)
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolve an array of session notifications.
|
||||
@@ -59,9 +59,9 @@ public class NotifierController(
|
||||
|
||||
// _notificationService.UpdateMessageOnQueue(sessionID, []);
|
||||
// resolve(messages);
|
||||
//};
|
||||
//};
|
||||
|
||||
// immediately check
|
||||
// immediately check
|
||||
// checkNotifications();
|
||||
//});
|
||||
}
|
||||
|
||||
@@ -55,25 +55,25 @@ public class PrestigeController(
|
||||
ObtainPrestigeRequestList request)
|
||||
{
|
||||
// Going to prestige 1
|
||||
|
||||
|
||||
// transfer
|
||||
// 5% of skills should be transfered over
|
||||
// 5% of mastering should be transfered over
|
||||
// earned achievements should be transfered over
|
||||
// profile stats should be transfered over
|
||||
// prestige progress should be transfered over
|
||||
|
||||
|
||||
// reset
|
||||
// trader standing
|
||||
// task progress
|
||||
// character level
|
||||
// stash
|
||||
// hideout progress
|
||||
|
||||
|
||||
// going to prestige 2
|
||||
// most likely the same, but wait for dump of new beginnings quest
|
||||
|
||||
|
||||
|
||||
|
||||
// Clone existing profile, create a new one
|
||||
var prePrestigeProfileClone = _cloner.Clone(_profileHelper.GetFullProfile(sessionId));
|
||||
var prePrestigePmc = prePrestigeProfileClone.CharacterData.PmcData;
|
||||
@@ -87,7 +87,7 @@ public class PrestigeController(
|
||||
(customisation) => customisation.Value.Name == prePrestigePmc.Info.Voice
|
||||
)
|
||||
.Value.Id,
|
||||
SptForcePrestigeLevel = prePrestigeProfileClone.CharacterData.PmcData.Info.PrestigeLevel.GetValueOrDefault(0) + 1, // Current + 1
|
||||
SptForcePrestigeLevel = prePrestigeProfileClone.CharacterData.PmcData.Info.PrestigeLevel.GetValueOrDefault(0) + 1 // Current + 1
|
||||
};
|
||||
|
||||
// Reset profile
|
||||
@@ -104,15 +104,11 @@ public class PrestigeController(
|
||||
skillToCopy.Progress = skillToCopy.Progress.Value * 0.05;
|
||||
var existingSkill = newProfile.CharacterData.PmcData.Skills.Common.FirstOrDefault((skill) => skill.Id == skillToCopy.Id);
|
||||
if (existingSkill is not null)
|
||||
{
|
||||
existingSkill.Progress = skillToCopy.Progress;
|
||||
}
|
||||
else
|
||||
{
|
||||
newProfile.CharacterData.PmcData.Skills.Common.Add(skillToCopy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Copy mastering to new profile
|
||||
var masteringSkillsToCopy = prePrestigePmc.Skills.Mastering;
|
||||
foreach (var skillToCopy in masteringSkillsToCopy)
|
||||
@@ -123,35 +119,29 @@ public class PrestigeController(
|
||||
(skill) => skill.Id == skillToCopy.Id
|
||||
);
|
||||
if (existingSkill is not null)
|
||||
{
|
||||
existingSkill.Progress = skillToCopy.Progress;
|
||||
}
|
||||
else
|
||||
{
|
||||
newProfile.CharacterData.PmcData.Skills.Mastering.Add(skillToCopy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add existing completed achievements and new one for prestige
|
||||
newProfile.CharacterData.PmcData.Achievements = prePrestigeProfileClone.CharacterData.PmcData.Achievements; // this *should* only contain completed ones
|
||||
|
||||
// Add "Prestigious" achievement
|
||||
if (!newProfile.CharacterData.PmcData.Achievements.ContainsKey("676091c0f457869a94017a23"))
|
||||
{
|
||||
newProfile.CharacterData.PmcData.Achievements.Add("676091c0f457869a94017a23", _timeUtil.GetTimeStamp());
|
||||
}
|
||||
// TODO: is there one for second prestige
|
||||
|
||||
// Add existing Stats to profile
|
||||
newProfile.CharacterData.PmcData.Stats = prePrestigePmc.Stats;
|
||||
|
||||
|
||||
// Assumes Prestige data is in descending order
|
||||
var indexOfPrestigeObtained = (int)Math.Min(createRequest.SptForcePrestigeLevel.Value - 1, 1); // Index starts at 0
|
||||
var currentPrestigeData = _databaseService.GetTemplates().Prestige.Elements[indexOfPrestigeObtained];
|
||||
var prestigeRewards = _databaseService.GetTemplates()
|
||||
.Prestige.Elements.Slice(0, indexOfPrestigeObtained + 1)
|
||||
.SelectMany((prestige) => prestige.Rewards);
|
||||
|
||||
|
||||
AddPrestigeRewardsToProfile(sessionId, newProfile, prestigeRewards);
|
||||
|
||||
// Flag profile as having achieved this prestige level
|
||||
@@ -159,7 +149,6 @@ public class PrestigeController(
|
||||
newProfile.CharacterData.PmcData.Info.PrestigeLevel++;
|
||||
|
||||
if (request is not null)
|
||||
{
|
||||
// Copy transferred items
|
||||
foreach (var transferRequest in request)
|
||||
{
|
||||
@@ -169,7 +158,7 @@ public class PrestigeController(
|
||||
ItemWithModsToAdd = [item],
|
||||
FoundInRaid = item.Upd?.SpawnedInSession,
|
||||
UseSortingTable = false,
|
||||
Callback = null,
|
||||
Callback = null
|
||||
};
|
||||
_inventoryHelper.AddItemToStash(
|
||||
sessionId,
|
||||
@@ -178,40 +167,39 @@ public class PrestigeController(
|
||||
_eventOutputHolder.GetOutput(sessionId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Force save of above changes to disk
|
||||
_saveServer.SaveProfile(sessionId);
|
||||
}
|
||||
|
||||
private void AddPrestigeRewardsToProfile(string sessionId, SptProfile newProfile, IEnumerable<Reward> rewards)
|
||||
{
|
||||
foreach (var reward in rewards) {
|
||||
switch (reward.Type) {
|
||||
case RewardType.CustomizationDirect: {
|
||||
foreach (var reward in rewards)
|
||||
switch (reward.Type)
|
||||
{
|
||||
case RewardType.CustomizationDirect:
|
||||
{
|
||||
_profileHelper.AddHideoutCustomisationUnlock(newProfile, reward, CustomisationSource.PRESTIGE);
|
||||
break;
|
||||
}
|
||||
case RewardType.Skill:
|
||||
if (Enum.TryParse(reward.Target, out SkillTypes result))
|
||||
{
|
||||
_profileHelper.AddSkillPointsToPlayer(
|
||||
newProfile.CharacterData.PmcData,
|
||||
result,
|
||||
((JsonElement)reward.Value).ToObject<double>()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error($"Unable to parse reward Target to Enum: {reward.Target}");
|
||||
}
|
||||
break;
|
||||
case RewardType.Item: {
|
||||
AddItemDirectRequest addItemRequest = new AddItemDirectRequest {
|
||||
case RewardType.Item:
|
||||
{
|
||||
var addItemRequest = new AddItemDirectRequest
|
||||
{
|
||||
ItemWithModsToAdd = reward.Items,
|
||||
FoundInRaid = reward.Items.FirstOrDefault()?.Upd?.SpawnedInSession,
|
||||
UseSortingTable = false,
|
||||
Callback = null,
|
||||
Callback = null
|
||||
};
|
||||
_inventoryHelper.AddItemToStash(
|
||||
sessionId,
|
||||
@@ -229,6 +217,5 @@ public class PrestigeController(
|
||||
_logger.Error($"Unhandled prestige reward type: {reward.Type}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,19 +51,15 @@ public class ProfileController(
|
||||
public MiniProfile GetMiniProfile(string sessionID)
|
||||
{
|
||||
var profile = _saveServer.GetProfile(sessionID);
|
||||
if (profile?.CharacterData == null)
|
||||
{
|
||||
throw new Exception($"Unable to find character data for id: {sessionID}. Profile may be corrupt");
|
||||
}
|
||||
if (profile?.CharacterData == null) throw new Exception($"Unable to find character data for id: {sessionID}. Profile may be corrupt");
|
||||
|
||||
var pmc = profile.CharacterData.PmcData;
|
||||
var maxLvl = _profileHelper.GetMaxLevel();
|
||||
|
||||
// Player hasn't completed profile creation process, send defaults
|
||||
var currlvl = pmc?.Info?.Level.GetValueOrDefault(1);
|
||||
var xpToNextLevel = _profileHelper.GetExperience(((currlvl ?? 1) + 1));
|
||||
var xpToNextLevel = _profileHelper.GetExperience((currlvl ?? 1) + 1);
|
||||
if (pmc?.Info?.Level == null)
|
||||
{
|
||||
return new MiniProfile
|
||||
{
|
||||
Username = profile.ProfileInfo?.Username ?? "",
|
||||
@@ -77,9 +73,8 @@ public class ProfileController(
|
||||
MaxLevel = maxLvl,
|
||||
Edition = profile.ProfileInfo?.Edition ?? "",
|
||||
ProfileId = profile.ProfileInfo?.ProfileId ?? "",
|
||||
SptData = _profileHelper.GetDefaultSptDataObject(),
|
||||
SptData = _profileHelper.GetDefaultSptDataObject()
|
||||
};
|
||||
}
|
||||
|
||||
return new MiniProfile
|
||||
{
|
||||
@@ -87,14 +82,14 @@ public class ProfileController(
|
||||
Nickname = pmc.Info.Nickname,
|
||||
HasPassword = profile.ProfileInfo.Password != "",
|
||||
Side = pmc.Info.Side,
|
||||
CurrentLevel = (int)(pmc.Info.Level),
|
||||
CurrentExperience = (pmc.Info.Experience ?? 0),
|
||||
CurrentLevel = (int)pmc.Info.Level,
|
||||
CurrentExperience = pmc.Info.Experience ?? 0,
|
||||
PreviousExperience = currlvl == 0 ? 0 : _profileHelper.GetExperience((int)currlvl),
|
||||
NextLevel = xpToNextLevel,
|
||||
MaxLevel = maxLvl,
|
||||
Edition = profile.ProfileInfo?.Edition ?? "",
|
||||
ProfileId = profile.ProfileInfo?.ProfileId ?? "",
|
||||
SptData = profile.SptData,
|
||||
SptData = profile.SptData
|
||||
};
|
||||
}
|
||||
|
||||
@@ -133,15 +128,9 @@ public class ProfileController(
|
||||
*/
|
||||
public string ValidateNickname(ValidateNicknameRequestData info, string sessionID)
|
||||
{
|
||||
if (info.Nickname.Length < 3)
|
||||
{
|
||||
return "tooshort";
|
||||
}
|
||||
if (info.Nickname.Length < 3) return "tooshort";
|
||||
|
||||
if (_profileHelper.IsNicknameTaken(info, sessionID))
|
||||
{
|
||||
return "taken";
|
||||
}
|
||||
if (_profileHelper.IsNicknameTaken(info, sessionID)) return "taken";
|
||||
|
||||
return "OK";
|
||||
}
|
||||
@@ -188,10 +177,7 @@ public class ProfileController(
|
||||
{
|
||||
var pmcProfile = profile?.CharacterData?.PmcData;
|
||||
|
||||
if (!pmcProfile?.Info?.LowerNickname?.Contains(info.Nickname.ToLower()) ?? false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!pmcProfile?.Info?.LowerNickname?.Contains(info.Nickname.ToLower()) ?? false) continue;
|
||||
|
||||
result.Add(_profileHelper.GetChatRoomMemberFromPmcProfile(pmcProfile));
|
||||
}
|
||||
@@ -210,8 +196,8 @@ public class ProfileController(
|
||||
MaxPveCountExceeded = false,
|
||||
Profiles =
|
||||
[
|
||||
new() { ProfileId = account.ScavengerId, ProfileToken = null, Status = "Free", Sid = "", Ip = "", Port = 0 },
|
||||
new() { ProfileId = account.ProfileId, ProfileToken = null, Status = "Free", Sid = "", Ip = "", Port = 0 },
|
||||
new ProfileStatusData { ProfileId = account.ScavengerId, ProfileToken = null, Status = "Free", Sid = "", Ip = "", Port = 0 },
|
||||
new ProfileStatusData { ProfileId = account.ProfileId, ProfileToken = null, Status = "Free", Sid = "", Ip = "", Port = 0 }
|
||||
]
|
||||
};
|
||||
|
||||
@@ -261,7 +247,7 @@ public class ProfileController(
|
||||
MemberCategory = profileToViewPmc.Info.MemberCategory as int?,
|
||||
BannedState = profileToViewPmc.Info.BannedState,
|
||||
BannedUntil = profileToViewPmc.Info.BannedUntil,
|
||||
RegistrationDate = profileToViewPmc.Info.RegistrationDate,
|
||||
RegistrationDate = profileToViewPmc.Info.RegistrationDate
|
||||
},
|
||||
Customization =
|
||||
{
|
||||
@@ -269,13 +255,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 =
|
||||
{
|
||||
Id = profileToViewPmc.Inventory.Equipment,
|
||||
Items = profileToViewPmc.Inventory.Items,
|
||||
Items = profileToViewPmc.Inventory.Items
|
||||
},
|
||||
Achievements = profileToViewPmc.Achievements,
|
||||
FavoriteItems = _profileHelper.GetOtherProfileFavorites(profileToViewPmc),
|
||||
@@ -284,15 +270,15 @@ public class ProfileController(
|
||||
Eft =
|
||||
{
|
||||
TotalInGameTime = profileToViewPmc.Stats.Eft.TotalInGameTime,
|
||||
OverAllCounters = profileToViewPmc.Stats.Eft.OverallCounters,
|
||||
},
|
||||
OverAllCounters = profileToViewPmc.Stats.Eft.OverallCounters
|
||||
}
|
||||
},
|
||||
ScavStats =
|
||||
{
|
||||
Eft =
|
||||
{
|
||||
TotalInGameTime = profileToViewScav.Stats.Eft.TotalInGameTime,
|
||||
OverAllCounters = profileToViewScav.Stats.Eft.OverallCounters,
|
||||
OverAllCounters = profileToViewScav.Stats.Eft.OverallCounters
|
||||
}
|
||||
},
|
||||
Hideout = profileToViewPmc.Hideout,
|
||||
@@ -308,20 +294,11 @@ public class ProfileController(
|
||||
public bool SetChosenProfileIcon(string sessionId, GetProfileSettingsRequest request)
|
||||
{
|
||||
var profileToUpdate = _profileHelper.GetPmcProfile(sessionId);
|
||||
if (profileToUpdate == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (profileToUpdate == null) return false;
|
||||
|
||||
if (request.MemberCategory != null)
|
||||
{
|
||||
profileToUpdate.Info.SelectedMemberCategory = request.MemberCategory as MemberCategory?;
|
||||
}
|
||||
if (request.MemberCategory != null) profileToUpdate.Info.SelectedMemberCategory = request.MemberCategory as MemberCategory?;
|
||||
|
||||
if (request.SquadInviteRestriction != null)
|
||||
{
|
||||
profileToUpdate.Info.SquadInviteRestriction = request.SquadInviteRestriction;
|
||||
}
|
||||
if (request.SquadInviteRestriction != null) profileToUpdate.Info.SquadInviteRestriction = request.SquadInviteRestriction;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -107,10 +107,7 @@ public class QuestController(
|
||||
acceptedQuest.QuestId,
|
||||
sessionID
|
||||
);
|
||||
if (newlyAccessibleQuests.Count > 0)
|
||||
{
|
||||
acceptQuestResponse.ProfileChanges[sessionID].Quests.AddRange(newlyAccessibleQuests);
|
||||
}
|
||||
if (newlyAccessibleQuests.Count > 0) acceptQuestResponse.ProfileChanges[sessionID].Quests.AddRange(newlyAccessibleQuests);
|
||||
|
||||
return acceptQuestResponse;
|
||||
}
|
||||
@@ -120,11 +117,9 @@ public class QuestController(
|
||||
foreach (var condition in questConditions)
|
||||
{
|
||||
if (pmcData.TaskConditionCounters.TryGetValue(condition.Id, out var counter))
|
||||
{
|
||||
_logger.Error(
|
||||
$"Unable to add new task condition counter: {condition.ConditionType} for qeust: {questId} to profile: {pmcData.SessionId} as it already exists:"
|
||||
);
|
||||
}
|
||||
|
||||
switch (condition.ConditionType)
|
||||
{
|
||||
@@ -134,7 +129,7 @@ public class QuestController(
|
||||
Id = condition.Id,
|
||||
SourceId = questId,
|
||||
Type = condition.ConditionType,
|
||||
Value = 0,
|
||||
Value = 0
|
||||
};
|
||||
break;
|
||||
}
|
||||
@@ -186,10 +181,7 @@ public class QuestController(
|
||||
var matchingQuest = repeatableQuest.ActiveQuests.FirstOrDefault(x => x.Id == acceptedQuest.QuestId);
|
||||
if (matchingQuest is not null)
|
||||
{
|
||||
if(_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Accepted repeatable quest {acceptedQuest.QuestId} from {repeatableQuest.Name}");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Accepted repeatable quest {acceptedQuest.QuestId} from {repeatableQuest.Name}");
|
||||
matchingQuest.SptRepatableGroupName = repeatableQuest.Name;
|
||||
|
||||
return matchingQuest;
|
||||
@@ -217,7 +209,6 @@ public class QuestController(
|
||||
// Decrement number of items handed in
|
||||
QuestCondition? handoverRequirements = null;
|
||||
foreach (var condition in quest.Conditions.AvailableForFinish)
|
||||
{
|
||||
if (condition.Id == handoverQuestRequest.ConditionId && handoverQuestTypes.Contains(condition.ConditionType))
|
||||
{
|
||||
handedInCount = int.Parse(condition.Value.ToString());
|
||||
@@ -249,19 +240,14 @@ public class QuestController(
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isItemHandoverQuest && handedInCount == 0)
|
||||
{
|
||||
return ShowRepeatableQuestInvalidConditionError(handoverQuestRequest, output);
|
||||
}
|
||||
if (isItemHandoverQuest && handedInCount == 0) return ShowRepeatableQuestInvalidConditionError(handoverQuestRequest, output);
|
||||
|
||||
var totalItemCountToRemove = 0d;
|
||||
foreach (var itemHandover in handoverQuestRequest.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 doesnt match what was requested
|
||||
return ShowQuestItemHandoverMatchError(
|
||||
handoverQuestRequest,
|
||||
@@ -269,7 +255,6 @@ public class QuestController(
|
||||
handoverRequirements,
|
||||
output
|
||||
);
|
||||
}
|
||||
|
||||
// Remove the right quantity of given items
|
||||
var itemCountToRemove = Math.Min(itemHandover.Count ?? 0, handedInCount - totalItemCountToRemove);
|
||||
@@ -284,10 +269,7 @@ public class QuestController(
|
||||
sessionID,
|
||||
output
|
||||
);
|
||||
if (totalItemCountToRemove == handedInCount)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (totalItemCountToRemove == handedInCount) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -306,13 +288,12 @@ public class QuestController(
|
||||
|
||||
// Important: loop backward when removing items from the array we're looping on
|
||||
while (index-- > 0)
|
||||
{
|
||||
if (toRemove.Contains(pmcData.Inventory.Items[index].Id))
|
||||
{
|
||||
var removedItem = _cloner.Clone(pmcData.Inventory.Items[index]);
|
||||
pmcData.Inventory.Items.RemoveAt(index);
|
||||
// Remove the item
|
||||
|
||||
// Remove the item
|
||||
// If the removed item has a numeric `location` property, re-calculate all the child
|
||||
// element `location` properties of the parent so they are sequential, while retaining order
|
||||
if (removedItem.Location.GetType() == typeof(int))
|
||||
@@ -324,15 +305,11 @@ 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 (int i = 0; i < childItems.Count; i++)
|
||||
{
|
||||
childItems[i].Location = i;
|
||||
}
|
||||
for (var i = 0; i < childItems.Count; i++) childItems[i].Location = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,7 +347,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 +369,7 @@ public class QuestController(
|
||||
Id = conditionId,
|
||||
SourceId = questId,
|
||||
Type = "HandoverItem",
|
||||
Value = counterValue,
|
||||
Value = counterValue
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -25,32 +25,32 @@ namespace Core.Controllers;
|
||||
[Injectable]
|
||||
public class RagfairController
|
||||
{
|
||||
private readonly ISptLogger<RagfairController> _logger;
|
||||
private readonly TimeUtil _timeUtil;
|
||||
private readonly JsonUtil _jsonUtil;
|
||||
private readonly HttpResponseUtil _httpResponseUtil;
|
||||
private readonly EventOutputHolder _eventOutputHolder;
|
||||
private readonly RagfairServer _ragfairServer;
|
||||
private readonly ItemHelper _itemHelper;
|
||||
private readonly InventoryHelper _inventoryHelper;
|
||||
private readonly RagfairSellHelper _ragfairSellHelper;
|
||||
private readonly HandbookHelper _handbookHelper;
|
||||
private readonly ProfileHelper _profileHelper;
|
||||
private readonly PaymentHelper _paymentHelper;
|
||||
private readonly RagfairHelper _ragfairHelper;
|
||||
private readonly RagfairSortHelper _ragfairSortHelper;
|
||||
private readonly RagfairOfferHelper _ragfairOfferHelper;
|
||||
private readonly TraderHelper _traderHelper;
|
||||
private readonly DatabaseService _databaseService;
|
||||
private readonly LocalisationService _localisationService;
|
||||
private readonly RagfairTaxService _ragfairTaxService;
|
||||
private readonly RagfairOfferService _ragfairOfferService;
|
||||
private readonly PaymentService _paymentService;
|
||||
private readonly RagfairPriceService _ragfairPriceService;
|
||||
private readonly RagfairOfferGenerator _ragfairOfferGenerator;
|
||||
private readonly ConfigServer _configServer;
|
||||
private readonly DatabaseService _databaseService;
|
||||
private readonly EventOutputHolder _eventOutputHolder;
|
||||
private readonly HandbookHelper _handbookHelper;
|
||||
private readonly HttpResponseUtil _httpResponseUtil;
|
||||
private readonly InventoryHelper _inventoryHelper;
|
||||
private readonly ItemHelper _itemHelper;
|
||||
private readonly JsonUtil _jsonUtil;
|
||||
private readonly LocalisationService _localisationService;
|
||||
private readonly ISptLogger<RagfairController> _logger;
|
||||
private readonly PaymentHelper _paymentHelper;
|
||||
private readonly PaymentService _paymentService;
|
||||
private readonly ProfileHelper _profileHelper;
|
||||
|
||||
private readonly RagfairConfig _ragfairConfig;
|
||||
private readonly RagfairHelper _ragfairHelper;
|
||||
private readonly RagfairOfferGenerator _ragfairOfferGenerator;
|
||||
private readonly RagfairOfferHelper _ragfairOfferHelper;
|
||||
private readonly RagfairOfferService _ragfairOfferService;
|
||||
private readonly RagfairPriceService _ragfairPriceService;
|
||||
private readonly RagfairSellHelper _ragfairSellHelper;
|
||||
private readonly RagfairServer _ragfairServer;
|
||||
private readonly RagfairSortHelper _ragfairSortHelper;
|
||||
private readonly RagfairTaxService _ragfairTaxService;
|
||||
private readonly TimeUtil _timeUtil;
|
||||
private readonly TraderHelper _traderHelper;
|
||||
|
||||
public RagfairController(
|
||||
ISptLogger<RagfairController> logger,
|
||||
@@ -119,9 +119,7 @@ public class RagfairController
|
||||
if (
|
||||
pmcProfile.RagfairInfo is not null && pmcProfile.Info.Level >= _databaseService.GetGlobals().Configuration.RagFair.MinUserLevel
|
||||
)
|
||||
{
|
||||
_ragfairOfferHelper.ProcessOffersOnProfile(sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,16 +140,14 @@ public class RagfairController
|
||||
{
|
||||
Offers = [],
|
||||
OffersCount = searchRequest.Limit,
|
||||
SelectedCategory = searchRequest.HandbookId,
|
||||
SelectedCategory = searchRequest.HandbookId
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
AddIndexValueToOffers(result.Offers);
|
||||
|
||||
@@ -167,10 +163,7 @@ public class RagfairController
|
||||
{
|
||||
// For the items, check the barter schemes. The method getDisplayableAssorts sets a flag sptQuestLocked
|
||||
// to true if the quest is not completed yet
|
||||
if (_ragfairOfferHelper.TraderOfferItemQuestLocked(traderOffer, traderAssorts))
|
||||
{
|
||||
traderOffer.Locked = true;
|
||||
}
|
||||
if (_ragfairOfferHelper.TraderOfferItemQuestLocked(traderOffer, traderAssorts)) traderOffer.Locked = true;
|
||||
|
||||
// Update offers BuyRestrictionCurrent/BuyRestrictionMax values
|
||||
SetTraderOfferPurchaseLimits(traderOffer, profile);
|
||||
@@ -208,7 +201,7 @@ public class RagfairController
|
||||
new
|
||||
{
|
||||
offerId = offer.Items.First().Id,
|
||||
traderId = offer.User.Id,
|
||||
traderId = offer.User.Id
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -263,10 +256,7 @@ public class RagfairController
|
||||
{
|
||||
var counter = 0;
|
||||
|
||||
foreach (var offer in offers)
|
||||
{
|
||||
offer.InternalId = ++counter;
|
||||
}
|
||||
foreach (var offer in offers) offer.InternalId = ++counter;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,10 +283,7 @@ public class RagfairController
|
||||
else
|
||||
{
|
||||
_logger.Error(_localisationService.GetText("ragfair-unable_to_get_categories"));
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug(_jsonUtil.Serialize(searchRequest));
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug(_jsonUtil.Serialize(searchRequest));
|
||||
return new Dictionary<string, int>();
|
||||
}
|
||||
|
||||
@@ -335,15 +322,9 @@ public class RagfairController
|
||||
PmcData pmcProfile)
|
||||
{
|
||||
// Searching for items in preset menu
|
||||
if (searchRequest.BuildCount > 0)
|
||||
{
|
||||
return _ragfairOfferHelper.GetOffersForBuild(searchRequest, itemsToAdd, traderAssorts, pmcProfile);
|
||||
}
|
||||
if (searchRequest.BuildCount > 0) return _ragfairOfferHelper.GetOffersForBuild(searchRequest, itemsToAdd, traderAssorts, pmcProfile);
|
||||
|
||||
if (searchRequest.NeededSearchId?.Length > 0)
|
||||
{
|
||||
return _ragfairOfferHelper.GetOffersThatRequireItem(searchRequest, pmcProfile);
|
||||
}
|
||||
if (searchRequest.NeededSearchId?.Length > 0) return _ragfairOfferHelper.GetOffersThatRequireItem(searchRequest, pmcProfile);
|
||||
|
||||
// Searching for general items
|
||||
return _ragfairOfferHelper.GetValidOffers(searchRequest, itemsToAdd, traderAssorts, pmcProfile);
|
||||
@@ -375,10 +356,7 @@ public class RagfairController
|
||||
// No offers listed, get price from live ragfair price list prices.json
|
||||
// No flea price, get handbook price
|
||||
var fleaPrices = _databaseService.GetPrices();
|
||||
if (!fleaPrices.TryGetValue(getPriceRequest.TemplateId, out var tplPrice))
|
||||
{
|
||||
tplPrice = _handbookHelper.GetTemplatePrice(getPriceRequest.TemplateId);
|
||||
}
|
||||
if (!fleaPrices.TryGetValue(getPriceRequest.TemplateId, out var tplPrice)) tplPrice = _handbookHelper.GetTemplatePrice(getPriceRequest.TemplateId);
|
||||
|
||||
return new GetItemPriceResult { Avg = tplPrice, Min = tplPrice, Max = tplPrice };
|
||||
}
|
||||
@@ -391,40 +369,26 @@ public class RagfairController
|
||||
foreach (var offer in offers)
|
||||
{
|
||||
// Exclude barter items, they tend to have outrageous equivalent prices
|
||||
if (offer.Requirements.Any(req => !_paymentHelper.IsMoneyTpl(req.Template)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (offer.Requirements.Any(req => !_paymentHelper.IsMoneyTpl(req.Template))) continue;
|
||||
|
||||
if (ignoreTraderOffers && _ragfairOfferHelper.OfferIsFromTrader(offer))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (ignoreTraderOffers && _ragfairOfferHelper.OfferIsFromTrader(offer)) continue;
|
||||
|
||||
// Figure out how many items the requirementsCost is applying to, and what the per-item price is
|
||||
var offerItemCount = offer.SellInOnePiece.GetValueOrDefault(false)
|
||||
? (offer.Items.First().Upd?.StackObjectsCount ?? 1)
|
||||
? offer.Items.First().Upd?.StackObjectsCount ?? 1
|
||||
: 1;
|
||||
var perItemPrice = offer.RequirementsCost / offerItemCount;
|
||||
|
||||
// Handle min/max calculations based on the per-item price
|
||||
if (perItemPrice < minMax.Min)
|
||||
{
|
||||
minMax.Min = perItemPrice;
|
||||
}
|
||||
else if (perItemPrice > minMax.Max)
|
||||
{
|
||||
minMax.Max = perItemPrice;
|
||||
}
|
||||
else if (perItemPrice > minMax.Max) minMax.Max = perItemPrice;
|
||||
|
||||
sum += perItemPrice.Value;
|
||||
totalOfferCount++;
|
||||
}
|
||||
|
||||
if (totalOfferCount == 0)
|
||||
{
|
||||
return -1d;
|
||||
}
|
||||
if (totalOfferCount == 0) return -1d;
|
||||
|
||||
return sum / totalOfferCount;
|
||||
}
|
||||
@@ -442,16 +406,11 @@ public class RagfairController
|
||||
var fullProfile = _profileHelper.GetFullProfile(sessionID);
|
||||
|
||||
var validationMessage = "";
|
||||
if (!IsValidPlayerOfferRequest(offerRequest, validationMessage))
|
||||
{
|
||||
return _httpResponseUtil.AppendErrorToOutput(output, validationMessage);
|
||||
}
|
||||
if (!IsValidPlayerOfferRequest(offerRequest, validationMessage)) return _httpResponseUtil.AppendErrorToOutput(output, validationMessage);
|
||||
|
||||
var typeOfOffer = GetOfferType(offerRequest);
|
||||
if (typeOfOffer == FleaOfferType.UNKNOWN)
|
||||
{
|
||||
return _httpResponseUtil.AppendErrorToOutput(output, $"Unknown offer type: {typeOfOffer}, cannot list item on flea");
|
||||
}
|
||||
|
||||
switch (typeOfOffer)
|
||||
{
|
||||
@@ -504,21 +463,12 @@ public class RagfairController
|
||||
|
||||
if (!sellInOncePiece)
|
||||
{
|
||||
if (offerRequest.Items.Count == 1)
|
||||
{
|
||||
return FleaOfferType.SINGLE;
|
||||
}
|
||||
if (offerRequest.Items.Count == 1) return FleaOfferType.SINGLE;
|
||||
|
||||
if (offerRequest.Items.Count > 1)
|
||||
{
|
||||
return FleaOfferType.MULTI;
|
||||
}
|
||||
if (offerRequest.Items.Count > 1) return FleaOfferType.MULTI;
|
||||
}
|
||||
|
||||
if (sellInOncePiece)
|
||||
{
|
||||
return FleaOfferType.PACK;
|
||||
}
|
||||
if (sellInOncePiece) return FleaOfferType.PACK;
|
||||
|
||||
return FleaOfferType.UNKNOWN;
|
||||
}
|
||||
@@ -542,14 +492,12 @@ public class RagfairController
|
||||
// Get first item and its children and use as template
|
||||
var firstListingAndChidren = _itemHelper.FindAndReturnChildrenAsItems(
|
||||
pmcData.Inventory.Items,
|
||||
offerRequest.Items[0]);
|
||||
offerRequest.Items[0]
|
||||
);
|
||||
|
||||
// Find items to be listed on flea (+ children) from player inventory
|
||||
var result = GetItemsToListOnFleaFromInventory(pmcData, offerRequest.Items);
|
||||
if (result.Items is null || !string.IsNullOrEmpty(result.ErrorMessage))
|
||||
{
|
||||
_httpResponseUtil.AppendErrorToOutput(output, result.ErrorMessage);
|
||||
}
|
||||
if (result.Items is null || !string.IsNullOrEmpty(result.ErrorMessage)) _httpResponseUtil.AppendErrorToOutput(output, result.ErrorMessage);
|
||||
|
||||
// Total count of items summed using their stack counts
|
||||
var stackCountTotal = _ragfairOfferHelper.GetTotalStackCountSize(result.Items);
|
||||
@@ -557,7 +505,7 @@ public class RagfairController
|
||||
// When listing identical items on flea, condense separate items into one stack with a merged stack count
|
||||
// e.g. 2 ammo items, stackObjectCount = 3 for each, will result in 1 stack of 6
|
||||
|
||||
firstListingAndChidren[0].Upd ??= new Upd{ };
|
||||
firstListingAndChidren[0].Upd ??= new Upd { };
|
||||
|
||||
firstListingAndChidren[0].Upd.StackObjectsCount = stackCountTotal;
|
||||
|
||||
@@ -568,14 +516,11 @@ public class RagfairController
|
||||
var newRootOfferItem = offer.Items[0];
|
||||
|
||||
// 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 });
|
||||
var averageOfferPrice = averages.Avg;
|
||||
|
||||
// Check for and apply item price modifer if it exists in config
|
||||
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(newRootOfferItem.Template, out var itemPriceModifer))
|
||||
{
|
||||
averageOfferPrice *= itemPriceModifer;
|
||||
}
|
||||
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(newRootOfferItem.Template, out var itemPriceModifer)) averageOfferPrice *= itemPriceModifer;
|
||||
|
||||
// Get average of item+children quality
|
||||
var qualityMultiplier = _itemHelper.GetItemQualityModifierForItems(offer.Items, true);
|
||||
@@ -590,7 +535,8 @@ public class RagfairController
|
||||
var sellChancePercent = _ragfairSellHelper.CalculateSellChance(
|
||||
averageOfferPrice.Value,
|
||||
playerListedPriceInRub,
|
||||
qualityMultiplier);
|
||||
qualityMultiplier
|
||||
);
|
||||
|
||||
// Create array of sell times for items listed
|
||||
offer.SellResults = _ragfairSellHelper.RollForSale(sellChancePercent, (int)stackCountTotal);
|
||||
@@ -605,11 +551,9 @@ public class RagfairController
|
||||
playerListedPriceInRub,
|
||||
(int)stackCountTotal,
|
||||
offerRequest,
|
||||
output);
|
||||
if (taxFeeChargeFailed)
|
||||
{
|
||||
return output;
|
||||
}
|
||||
output
|
||||
);
|
||||
if (taxFeeChargeFailed) return output;
|
||||
}
|
||||
|
||||
// Add offer to players profile + add to client response
|
||||
@@ -617,9 +561,7 @@ public class RagfairController
|
||||
output.ProfileChanges[sessionID].RagFairOffers.Add(offer);
|
||||
|
||||
// Remove items from inventory after creating offer
|
||||
foreach (var itemToRemove in offerRequest.Items) {
|
||||
_inventoryHelper.RemoveItem(pmcData, itemToRemove, sessionID, output);
|
||||
}
|
||||
foreach (var itemToRemove in offerRequest.Items) _inventoryHelper.RemoveItem(pmcData, itemToRemove, sessionID, output);
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -643,14 +585,12 @@ public class RagfairController
|
||||
// Get first item and its children and use as template
|
||||
var firstListingAndChidren = _itemHelper.FindAndReturnChildrenAsItems(
|
||||
pmcData.Inventory.Items,
|
||||
offerRequest.Items[0]);
|
||||
offerRequest.Items[0]
|
||||
);
|
||||
|
||||
// Find items to be listed on flea (+ children) from player inventory
|
||||
var result = GetItemsToListOnFleaFromInventory(pmcData, offerRequest.Items);
|
||||
if (result.Items is null || !string.IsNullOrEmpty(result.ErrorMessage))
|
||||
{
|
||||
_httpResponseUtil.AppendErrorToOutput(output, result.ErrorMessage);
|
||||
}
|
||||
if (result.Items is null || !string.IsNullOrEmpty(result.ErrorMessage)) _httpResponseUtil.AppendErrorToOutput(output, result.ErrorMessage);
|
||||
|
||||
// Total count of items summed using their stack counts
|
||||
var stackCountTotal = _ragfairOfferHelper.GetTotalStackCountSize(result.Items);
|
||||
@@ -668,14 +608,11 @@ public class RagfairController
|
||||
var newRootOfferItem = offer.Items[0];
|
||||
|
||||
// Single price for an item
|
||||
var averages = GetItemMinAvgMaxFleaPriceValues( new GetMarketPriceRequestData{ TemplateId = firstListingAndChidren[0].Template });
|
||||
var averages = GetItemMinAvgMaxFleaPriceValues(new GetMarketPriceRequestData { TemplateId = firstListingAndChidren[0].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 double itemPriceModifer))
|
||||
{
|
||||
singleItemPrice *= itemPriceModifer;
|
||||
}
|
||||
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(newRootOfferItem.Template, out var itemPriceModifer)) singleItemPrice *= itemPriceModifer;
|
||||
|
||||
// Get average of item+children quality
|
||||
var qualityMultiplier = _itemHelper.GetItemQualityModifierForItems(offer.Items, true);
|
||||
@@ -690,7 +627,8 @@ public class RagfairController
|
||||
var sellChancePercent = _ragfairSellHelper.CalculateSellChance(
|
||||
singleItemPrice.Value * stackCountTotal,
|
||||
playerListedPriceInRub,
|
||||
qualityMultiplier);
|
||||
qualityMultiplier
|
||||
);
|
||||
|
||||
// Create array of sell times for items listed + sell all at once as its a pack
|
||||
offer.SellResults = _ragfairSellHelper.RollForSale(sellChancePercent, (int)stackCountTotal, true);
|
||||
@@ -705,11 +643,9 @@ public class RagfairController
|
||||
playerListedPriceInRub,
|
||||
(int)stackCountTotal,
|
||||
offerRequest,
|
||||
output);
|
||||
if (taxFeeChargeFailed)
|
||||
{
|
||||
return output;
|
||||
}
|
||||
output
|
||||
);
|
||||
if (taxFeeChargeFailed) return output;
|
||||
}
|
||||
|
||||
// Add offer to players profile + add to client response
|
||||
@@ -717,9 +653,7 @@ public class RagfairController
|
||||
output.ProfileChanges[sessionID].RagFairOffers.Add(offer);
|
||||
|
||||
// Remove items from inventory after creating offer
|
||||
foreach (var itemToRemove in offerRequest.Items) {
|
||||
_inventoryHelper.RemoveItem(pmcData, itemToRemove, sessionID, output);
|
||||
}
|
||||
foreach (var itemToRemove in offerRequest.Items) _inventoryHelper.RemoveItem(pmcData, itemToRemove, sessionID, output);
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -741,10 +675,7 @@ public class RagfairController
|
||||
|
||||
// Find items to be listed on flea from player inventory
|
||||
var result = GetItemsToListOnFleaFromInventory(pmcData, offerRequest.Items);
|
||||
if (result.Items is null || !string.IsNullOrEmpty(result.ErrorMessage))
|
||||
{
|
||||
_httpResponseUtil.AppendErrorToOutput(output, result.ErrorMessage);
|
||||
}
|
||||
if (result.Items is null || !string.IsNullOrEmpty(result.ErrorMessage)) _httpResponseUtil.AppendErrorToOutput(output, result.ErrorMessage);
|
||||
|
||||
// Total count of items summed using their stack counts
|
||||
var stackCountTotal = _ragfairOfferHelper.GetTotalStackCountSize(result.Items);
|
||||
@@ -767,10 +698,8 @@ public class RagfairController
|
||||
var averageOfferPriceSingleItem = averages.Avg;
|
||||
|
||||
// Check for and apply item price modifer if it exists in config
|
||||
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(rootItem.Template, out double itemPriceModifer))
|
||||
{
|
||||
if (_ragfairConfig.Dynamic.ItemPriceMultiplier.TryGetValue(rootItem.Template, out var itemPriceModifer))
|
||||
averageOfferPriceSingleItem *= itemPriceModifer;
|
||||
}
|
||||
|
||||
// Multiply single item price by quality
|
||||
averageOfferPriceSingleItem *= qualityMultiplier;
|
||||
@@ -795,10 +724,7 @@ public class RagfairController
|
||||
offerRequest,
|
||||
output
|
||||
);
|
||||
if (taxFeeChargeFailed)
|
||||
{
|
||||
return output;
|
||||
}
|
||||
if (taxFeeChargeFailed) return output;
|
||||
}
|
||||
|
||||
// Add offer to players profile + add to client response
|
||||
@@ -806,10 +732,7 @@ public class RagfairController
|
||||
output.ProfileChanges[sessionID].RagFairOffers.Add(offer);
|
||||
|
||||
// Remove items from inventory after creating offer
|
||||
foreach (var itemToRemove in offerRequest.Items)
|
||||
{
|
||||
_inventoryHelper.RemoveItem(pmcData, itemToRemove, sessionID, output);
|
||||
}
|
||||
foreach (var itemToRemove in offerRequest.Items) _inventoryHelper.RemoveItem(pmcData, itemToRemove, sessionID, output);
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -846,10 +769,7 @@ public class RagfairController
|
||||
offerRequest.SellInOnePiece.GetValueOrDefault(false)
|
||||
);
|
||||
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Offer tax to charge: {tax}, pulled from client: {storedClientTaxValue.Count is not null}");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _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
|
||||
_ragfairTaxService.ClearStoredOfferTaxById(offerRequest.Items.First());
|
||||
@@ -892,7 +812,7 @@ public class RagfairController
|
||||
{
|
||||
Template = item.Template,
|
||||
Count = item.Count,
|
||||
OnlyFunctional = item.OnlyFunctional,
|
||||
OnlyFunctional = item.OnlyFunctional
|
||||
}
|
||||
);
|
||||
|
||||
@@ -919,13 +839,9 @@ public class RagfairController
|
||||
var requestedItemTpl = item.Template;
|
||||
|
||||
if (_paymentHelper.IsMoneyTpl(requestedItemTpl))
|
||||
{
|
||||
requirementsPriceInRub += _handbookHelper.InRUB(item.Count.Value, requestedItemTpl);
|
||||
}
|
||||
else
|
||||
{
|
||||
requirementsPriceInRub += _itemHelper.GetDynamicItemPrice(requestedItemTpl).Value * item.Count.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return requirementsPriceInRub;
|
||||
@@ -963,12 +879,6 @@ public class RagfairController
|
||||
return new GetItemsToListOnFleaFromInventoryResult { Items = itemsToReturn, ErrorMessage = errorMessage };
|
||||
}
|
||||
|
||||
public record GetItemsToListOnFleaFromInventoryResult
|
||||
{
|
||||
public List<List<Item>>? Items { get; set; }
|
||||
public string? ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
public ItemEventRouterResponse RemoveOffer(RemoveOfferRequestData removeRequest, string sessionId)
|
||||
{
|
||||
var output = _eventOutputHolder.GetOutput(sessionId);
|
||||
@@ -1050,10 +960,7 @@ public class RagfairController
|
||||
{
|
||||
var count = 1;
|
||||
var sellInOncePiece = playerOffer.SellInOnePiece.GetValueOrDefault(false);
|
||||
if (!sellInOncePiece)
|
||||
{
|
||||
count = (int)playerOffer.Items.Sum(offerItem => offerItem.Upd?.StackObjectsCount ?? 0);
|
||||
}
|
||||
if (!sellInOncePiece) count = (int)playerOffer.Items.Sum(offerItem => offerItem.Upd?.StackObjectsCount ?? 0);
|
||||
|
||||
var tax = _ragfairTaxService.CalculateTax(
|
||||
playerOffer.Items.First(),
|
||||
@@ -1066,12 +973,10 @@ public class RagfairController
|
||||
var request = CreateBuyTradeRequestObject(CurrencyType.RUB, tax);
|
||||
_paymentService.PayMoney(pmcData, request, sessionId, output);
|
||||
if (output.Warnings.Count > 0)
|
||||
{
|
||||
return _httpResponseUtil.AppendErrorToOutput(
|
||||
output,
|
||||
_localisationService.GetText("ragfair-unable_to_pay_commission_fee")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add extra time to offer
|
||||
@@ -1096,7 +1001,7 @@ public class RagfairController
|
||||
Type = "",
|
||||
ItemId = "",
|
||||
Count = 0,
|
||||
SchemeId = 0,
|
||||
SchemeId = 0
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1117,4 +1022,10 @@ public class RagfairController
|
||||
|
||||
return offerToReturn;
|
||||
}
|
||||
|
||||
public record GetItemsToListOnFleaFromInventoryResult
|
||||
{
|
||||
public List<List<Item>>? Items { get; set; }
|
||||
public string? ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Core.Controllers;
|
||||
public class RepairController(
|
||||
EventOutputHolder _eventOutputHolder,
|
||||
RepairService _repairService
|
||||
)
|
||||
)
|
||||
{
|
||||
/// <summary>
|
||||
/// Handle TraderRepair event
|
||||
@@ -29,7 +29,8 @@ public class RepairController(
|
||||
var output = _eventOutputHolder.GetOutput(sessionID);
|
||||
|
||||
// find the item to repair
|
||||
foreach (var repairItem in body.RepairItems) {
|
||||
foreach (var repairItem in body.RepairItems)
|
||||
{
|
||||
var repairDetails = _repairService.RepairItemByTrader(sessionID, pmcData, repairItem, body.TId);
|
||||
|
||||
_repairService.PayForRepair(
|
||||
@@ -38,12 +39,10 @@ public class RepairController(
|
||||
repairItem.Id,
|
||||
repairDetails.RepairCost.Value,
|
||||
body.TId,
|
||||
output);
|
||||
output
|
||||
);
|
||||
|
||||
if (output.Warnings?.Count > 0)
|
||||
{
|
||||
return output;
|
||||
}
|
||||
if (output.Warnings?.Count > 0) return output;
|
||||
|
||||
// Add repaired item to output object
|
||||
output.ProfileChanges[sessionID].Items.ChangedItems.Add(repairDetails.RepairedItem);
|
||||
|
||||
@@ -89,10 +89,7 @@ public class RepeatableQuestController(
|
||||
);
|
||||
|
||||
// If the configuration dictates to replace with the same quest type, adjust the available quest types
|
||||
if (repeatableConfig?.KeepDailyQuestTypeOnReplacement is not null)
|
||||
{
|
||||
repeatableConfig.Types = [questToReplace.Type.ToString()];
|
||||
}
|
||||
if (repeatableConfig?.KeepDailyQuestTypeOnReplacement is not null) repeatableConfig.Types = [questToReplace.Type.ToString()];
|
||||
|
||||
// Generate meta-data for what type/levelrange of quests can be generated for player
|
||||
var allowedQuestTypes = GenerateQuestPool(repeatableConfig, pmcData.Info.Level);
|
||||
@@ -117,11 +114,9 @@ public class RepeatableQuestController(
|
||||
repeatablesOfTypeInProfile.ActiveQuests.Add(newRepeatableQuest);
|
||||
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug(
|
||||
$"Removing: {repeatableConfig.Name} quest: {questToReplace.Id} from trader: {questToReplace.TraderId} as its been replaced"
|
||||
);
|
||||
}
|
||||
|
||||
RemoveQuestFromProfile(fullProfile, questToReplace.Id);
|
||||
|
||||
@@ -153,10 +148,7 @@ public class RepeatableQuestController(
|
||||
// Not free, Charge player + appy 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);
|
||||
if (output.Warnings.Count > 0)
|
||||
{
|
||||
return output;
|
||||
}
|
||||
if (output.Warnings.Count > 0) return output;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,16 +219,12 @@ public class RepeatableQuestController(
|
||||
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
|
||||
repeatablesOfTypeInProfile.ChangeRequirement.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Multiple active quests of this type (e.g. daily or weekly) are active, just remove the single replaced quest
|
||||
repeatablesOfTypeInProfile.ChangeRequirement.Remove(replacedQuestId);
|
||||
}
|
||||
}
|
||||
|
||||
private RepeatableQuest? AttemptToGenerateRepeatableQuest(string sessionId, PmcData pmcData,
|
||||
@@ -256,18 +244,13 @@ public class RepeatableQuestController(
|
||||
);
|
||||
|
||||
if (newRepeatableQuest is not null)
|
||||
{
|
||||
// Successfully generated a quest, exit loop
|
||||
break;
|
||||
}
|
||||
|
||||
attempts++;
|
||||
}
|
||||
|
||||
if (attempts > maxAttempts)
|
||||
{
|
||||
_logger.Error("We were stuck in repeatable quest generation. This should never happen. Please report");
|
||||
}
|
||||
if (attempts > maxAttempts) _logger.Error("We were stuck in repeatable quest generation. This should never happen. Please report");
|
||||
|
||||
return newRepeatableQuest;
|
||||
}
|
||||
@@ -279,12 +262,10 @@ public class RepeatableQuestController(
|
||||
|
||||
// Find quest we're replacing in scav profile quests array and remove it
|
||||
if (fullProfile.CharacterData.ScavData is not null)
|
||||
{
|
||||
_questHelper.FindAndRemoveQuestFromArrayIfExists(
|
||||
questToReplaceId,
|
||||
fullProfile.CharacterData.ScavData.Quests
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,10 +282,8 @@ public class RepeatableQuestController(
|
||||
var questToReplace =
|
||||
repeatablesInProfile.ActiveQuests.FirstOrDefault(repeatable => repeatable.Id == questId);
|
||||
if (questToReplace is null)
|
||||
{
|
||||
// Not found, skip to next repeatable sub-type
|
||||
continue;
|
||||
}
|
||||
|
||||
return new GetRepeatableByIdResult { Quest = questToReplace, RepeatableType = repeatablesInProfile };
|
||||
}
|
||||
@@ -328,20 +307,15 @@ public class RepeatableQuestController(
|
||||
|
||||
var canAccessRepeatables = CanProfileAccessRepeatableQuests(repeatableConfig, pmcData);
|
||||
if (!canAccessRepeatables)
|
||||
{
|
||||
// Don't send any repeatables, even existing ones
|
||||
continue;
|
||||
}
|
||||
|
||||
// Existing repeatables are still valid, add to return data and move to next sub-type
|
||||
if (currentTime < generatedRepeatables.EndTime - 1)
|
||||
{
|
||||
returnData.Add(generatedRepeatables);
|
||||
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"[Quest Check] {repeatableTypeLower} quests are still valid.");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"[Quest Check] {repeatableTypeLower} quests are still valid.");
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -351,10 +325,7 @@ public class RepeatableQuestController(
|
||||
// Set endtime to be now + new duration
|
||||
generatedRepeatables.EndTime = currentTime + repeatableConfig.ResetTime;
|
||||
generatedRepeatables.InactiveQuests = [];
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Generating new {repeatableTypeLower}");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Generating new {repeatableTypeLower}");
|
||||
|
||||
// Put old quests to inactive (this is required since only then the client makes them fail due to non-completion)
|
||||
// Also need to push them to the "inactiveQuests" list since we need to remove them from offraidData.profile.Quests
|
||||
@@ -391,10 +362,7 @@ public class RepeatableQuestController(
|
||||
}
|
||||
|
||||
// check if there are no more quest types available
|
||||
if (questTypePool.Types.Count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (questTypePool.Types.Count == 0) break;
|
||||
|
||||
quest.Side = repeatableConfig.Side;
|
||||
generatedRepeatables.ActiveQuests.Add(quest);
|
||||
@@ -473,18 +441,12 @@ public class RepeatableQuestController(
|
||||
private bool CanProfileAccessRepeatableQuests(RepeatableQuestConfig repeatableConfig, PmcData pmcData)
|
||||
{
|
||||
// PMC and daily quests not unlocked yet
|
||||
if (repeatableConfig.Side == "Pmc" && !PlayerHasDailyPmcQuestsUnlocked(pmcData, repeatableConfig))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (repeatableConfig.Side == "Pmc" && !PlayerHasDailyPmcQuestsUnlocked(pmcData, repeatableConfig)) return false;
|
||||
|
||||
// Scav and daily quests not unlocked yet
|
||||
if (repeatableConfig.Side == "Scav" && !PlayerHasDailyScavQuestsUnlocked(pmcData))
|
||||
{
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug("Daily scav quests still locked, Intel center not built");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug("Daily scav quests still locked, Intel center not built");
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -521,21 +483,16 @@ public class RepeatableQuestController(
|
||||
foreach (var activeQuest in generatedRepeatables.ActiveQuests)
|
||||
{
|
||||
var questStatusInProfile = pmcData.Quests.FirstOrDefault(quest => quest.QId == activeQuest.Id);
|
||||
if (questStatusInProfile is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (questStatusInProfile is null) continue;
|
||||
|
||||
// Keep finished quests in list so player can hand in
|
||||
if (questStatusInProfile.Status == QuestStatusEnum.AvailableForFinish)
|
||||
{
|
||||
questsToKeep.Add(activeQuest);
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug( // TODO: this shouldnt happen, doesnt on live
|
||||
$"Keeping repeatable quest: {activeQuest.Id} in activeQuests since it is available to hand in"
|
||||
);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -632,17 +589,10 @@ public class RepeatableQuestController(
|
||||
{
|
||||
var locationNames = new List<string>();
|
||||
foreach (var locationName in value)
|
||||
{
|
||||
if (IsPmcLevelAllowedOnLocation(locationName, pmcLevel))
|
||||
{
|
||||
locationNames.Add(locationName);
|
||||
}
|
||||
}
|
||||
|
||||
if (locationNames.Count > 0)
|
||||
{
|
||||
allowedLocation[location] = locationNames;
|
||||
}
|
||||
if (locationNames.Count > 0) allowedLocation[location] = locationNames;
|
||||
}
|
||||
|
||||
return allowedLocation;
|
||||
@@ -657,16 +607,10 @@ public class RepeatableQuestController(
|
||||
protected bool IsPmcLevelAllowedOnLocation(string location, int pmcLevel)
|
||||
{
|
||||
// All PMC levels are allowed for 'any' location requirement
|
||||
if (location == ELocationName.any.ToString())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (location == ELocationName.any.ToString()) return true;
|
||||
|
||||
var locationBase = _databaseService.GetLocation(location.ToLower())?.Base;
|
||||
if (locationBase is null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (locationBase is null) return true;
|
||||
|
||||
return pmcLevel <= locationBase.RequiredPlayerLevelMax && pmcLevel >= locationBase.RequiredPlayerLevelMin;
|
||||
}
|
||||
@@ -680,14 +624,10 @@ public class RepeatableQuestController(
|
||||
private int GetQuestCount(RepeatableQuestConfig repeatableConfig, PmcData pmcData)
|
||||
{
|
||||
var questCount = repeatableConfig.NumQuests.GetValueOrDefault(0);
|
||||
if (questCount == 0)
|
||||
{
|
||||
_logger.Warning($"Repeatable {repeatableConfig.Name} quests have a count of 0");
|
||||
}
|
||||
if (questCount == 0) _logger.Warning($"Repeatable {repeatableConfig.Name} quests have a count of 0");
|
||||
|
||||
// Add elite bonus to daily quests
|
||||
if (repeatableConfig.Name.ToLower() == "daily" && _profileHelper.HasEliteSkillLevel(SkillTypes.Charisma, pmcData))
|
||||
{
|
||||
// Elite charisma skill gives extra daily quest(s)
|
||||
questCount += _databaseService
|
||||
.GetGlobals()
|
||||
@@ -698,7 +638,6 @@ public class RepeatableQuestController(
|
||||
.EliteBonusSettings
|
||||
.RepeatableQuestExtraCount
|
||||
.GetValueOrDefault(0);
|
||||
}
|
||||
|
||||
return questCount;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public class TradeController(
|
||||
if (request.Type == "buy_from_trader")
|
||||
{
|
||||
var foundInRaid = _traderConfig.PurchasesAreFoundInRaid;
|
||||
ProcessBuyTradeRequestData buyData = (ProcessBuyTradeRequestData)request;
|
||||
var buyData = (ProcessBuyTradeRequestData)request;
|
||||
_tradeHelper.buyItem(pmcData, buyData, sessionID, foundInRaid, output);
|
||||
|
||||
return output;
|
||||
@@ -67,7 +67,7 @@ public class TradeController(
|
||||
// Selling
|
||||
if (request.Type == "sell_to_trader")
|
||||
{
|
||||
ProcessSellTradeRequestData sellData = (ProcessSellTradeRequestData)request;
|
||||
var sellData = (ProcessSellTradeRequestData)request;
|
||||
_tradeHelper.sellItem(pmcData, pmcData, sellData, sessionID, output);
|
||||
|
||||
return output;
|
||||
@@ -97,13 +97,11 @@ public class TradeController(
|
||||
{
|
||||
var fleaOffer = _ragfairServer.GetOffer(offer.Id);
|
||||
if (fleaOffer is null)
|
||||
{
|
||||
return _httpResponseUtil.AppendErrorToOutput(
|
||||
output,
|
||||
$"Offer with ID {offer.Id} not found",
|
||||
BackendErrorCodes.OfferNotFound
|
||||
);
|
||||
}
|
||||
|
||||
if (offer.Count == 0)
|
||||
{
|
||||
@@ -115,19 +113,12 @@ public class TradeController(
|
||||
}
|
||||
|
||||
if (_ragfairOfferHelper.OfferIsFromTrader(fleaOffer))
|
||||
{
|
||||
BuyTraderItemFromRagfair(sessionID, pmcData, fleaOffer, offer, output);
|
||||
}
|
||||
else
|
||||
{
|
||||
BuyPmcItemFromRagfair(sessionID, pmcData, fleaOffer, offer, output);
|
||||
}
|
||||
|
||||
// Exit loop early if problem found
|
||||
if (output.Warnings?.Count > 0)
|
||||
{
|
||||
return output;
|
||||
}
|
||||
if (output.Warnings?.Count > 0) return output;
|
||||
}
|
||||
|
||||
return output;
|
||||
@@ -152,17 +143,14 @@ public class TradeController(
|
||||
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";
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug(errorMessage);
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug(errorMessage);
|
||||
|
||||
_httpResponseUtil.AppendErrorToOutput(output, errorMessage, BackendErrorCodes.RagfairUnavailable);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessBuyTradeRequestData buyData = new ProcessBuyTradeRequestData
|
||||
var buyData = new ProcessBuyTradeRequestData
|
||||
{
|
||||
Action = "TradingConfirm",
|
||||
Type = "buy_from_ragfair",
|
||||
@@ -170,7 +158,7 @@ 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);
|
||||
@@ -191,7 +179,7 @@ public class TradeController(
|
||||
OfferRequest requestOffer,
|
||||
ItemEventRouterResponse output)
|
||||
{
|
||||
ProcessBuyTradeRequestData buyData = new ProcessBuyTradeRequestData
|
||||
var buyData = new ProcessBuyTradeRequestData
|
||||
{
|
||||
Action = "TradingConfirm",
|
||||
Type = "buy_from_ragfair",
|
||||
@@ -199,15 +187,12 @@ 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);
|
||||
if (output.Warnings?.Count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (output.Warnings?.Count > 0) return;
|
||||
|
||||
// resolve when a profile buy another profile's offer
|
||||
var offerOwnerId = fleaOffer.User?.Id;
|
||||
@@ -237,17 +222,12 @@ public class TradeController(
|
||||
string? offerOwnerId)
|
||||
{
|
||||
// No ownerid, not player offer
|
||||
if (offerOwnerId is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (offerOwnerId is null) return false;
|
||||
|
||||
var offerCreatorProfile = _profileHelper.GetPmcProfile(offerOwnerId);
|
||||
if (offerCreatorProfile is null || offerCreatorProfile.RagfairInfo.Offers?.Count == 0)
|
||||
{
|
||||
// No profile or no offers
|
||||
return false;
|
||||
}
|
||||
|
||||
// Does offer id exist in profile
|
||||
return offerCreatorProfile.RagfairInfo.Offers.Any(offer => offer.Id == offerId);
|
||||
@@ -296,17 +276,14 @@ public class TradeController(
|
||||
int roublesToSend,
|
||||
string trader)
|
||||
{
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug))
|
||||
{
|
||||
_logger.Debug($"Selling scav items to fence for {roublesToSend} roubles");
|
||||
}
|
||||
if (_logger.IsLogEnabled(LogLevel.Debug)) _logger.Debug($"Selling scav items to fence for {roublesToSend} roubles");
|
||||
|
||||
// Create single currency item with all currency on it
|
||||
Item rootCurrencyReward = new Item
|
||||
var rootCurrencyReward = new Item
|
||||
{
|
||||
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
|
||||
@@ -317,7 +294,7 @@ public class TradeController(
|
||||
sessionId,
|
||||
_traderHelper.GetTraderById(trader).ToString(),
|
||||
MessageType.MESSAGE_WITH_ITEMS,
|
||||
_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)
|
||||
);
|
||||
@@ -344,10 +321,8 @@ public class TradeController(
|
||||
{
|
||||
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
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get price of item multiplied by how many are in stack
|
||||
totalPrice += (int)((handbookPrices[itemToSell.Template] ?? 0) * (itemToSell.Upd?.StackObjectsCount ?? 1));
|
||||
|
||||
@@ -59,17 +59,13 @@ public class TraderController(
|
||||
|
||||
// Adjust price by traderPriceMultipler config property
|
||||
if (_traderConfig.TraderPriceMultipler != 1)
|
||||
{
|
||||
foreach (var kvp in trader.Value?.Assort?.BarterScheme)
|
||||
{
|
||||
var barterSchemeItem = kvp.Value[0][0];
|
||||
|
||||
if (barterSchemeItem != null && _paymentHelper.IsMoneyTpl(barterSchemeItem?.Template))
|
||||
{
|
||||
barterSchemeItem.Count += Math.Round((barterSchemeItem?.Count * _traderConfig?.TraderPriceMultipler) ?? 0D, 2);
|
||||
}
|
||||
barterSchemeItem.Count += Math.Round(barterSchemeItem?.Count * _traderConfig?.TraderPriceMultipler ?? 0D, 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Create dict of pristine trader assorts on server start
|
||||
if (_traderAssortService.GetPristineTraderAssort(trader.Key) == null)
|
||||
@@ -81,7 +77,8 @@ public class TraderController(
|
||||
_traderPurchasePersisterService.RemoveStalePurchasesFromProfiles(trader.Key);
|
||||
|
||||
// Set to next hour on clock or current time + 60 mins
|
||||
trader.Value.Base.NextResupply = traderResetStartsWithServer ? (int)_traderHelper.GetNextUpdateTimestamp(trader.Value.Base.Id) : (int)nextHourTimestamp;
|
||||
trader.Value.Base.NextResupply =
|
||||
traderResetStartsWithServer ? (int)_traderHelper.GetNextUpdateTimestamp(trader.Value.Base.Id) : (int)nextHourTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,10 +98,7 @@ public class TraderController(
|
||||
continue;
|
||||
case Traders.FENCE:
|
||||
{
|
||||
if (_fenceService.NeedsPartialRefresh())
|
||||
{
|
||||
_fenceService.GenerateFenceAssorts();
|
||||
}
|
||||
if (_fenceService.NeedsPartialRefresh()) _fenceService.GenerateFenceAssorts();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -135,10 +129,7 @@ public class TraderController(
|
||||
{
|
||||
traders.Add(_traderHelper.GetTrader(traderId, sessionId));
|
||||
|
||||
if (pmcData?.Info != null)
|
||||
{
|
||||
_traderHelper.LevelUp(traderId, pmcData);
|
||||
}
|
||||
if (pmcData?.Info != null) _traderHelper.LevelUp(traderId, pmcData);
|
||||
}
|
||||
|
||||
traders.Sort(SortByTraderId);
|
||||
@@ -186,7 +177,7 @@ public class TraderController(
|
||||
{
|
||||
var handbookPrices = _ragfairPriceService.GetAllStaticPrices();
|
||||
|
||||
return new()
|
||||
return new GetItemPricesResponse
|
||||
{
|
||||
SupplyNextTime = _traderHelper.GetNextUpdateTimestamp(traderId),
|
||||
Prices = handbookPrices,
|
||||
|
||||
@@ -23,10 +23,7 @@ public class WishlistController(
|
||||
AddToWishlistRequest request,
|
||||
string sessionId)
|
||||
{
|
||||
foreach (var item in request.Items)
|
||||
{
|
||||
pmcData.WishList.Dictionary.Add(item.Key, item.Value);
|
||||
}
|
||||
foreach (var item in request.Items) pmcData.WishList.Dictionary.Add(item.Key, item.Value);
|
||||
|
||||
return _eventOutputHolder.GetOutput(sessionId);
|
||||
}
|
||||
@@ -43,10 +40,7 @@ public class WishlistController(
|
||||
RemoveFromWishlistRequest request,
|
||||
string sessionId)
|
||||
{
|
||||
foreach (var itemId in request.Items)
|
||||
{
|
||||
pmcData.WishList.Dictionary.Remove(itemId);
|
||||
}
|
||||
foreach (var itemId in request.Items) pmcData.WishList.Dictionary.Remove(itemId);
|
||||
|
||||
return _eventOutputHolder.GetOutput(sessionId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user