Format Style Fixes

This commit is contained in:
sp-tarkov-bot
2025-07-28 19:39:29 +00:00
parent 51430d55c9
commit b14b74bf24
357 changed files with 7345 additions and 24604 deletions
@@ -60,25 +60,15 @@ public class CompletionQuestGenerator(
if (quest is null)
{
logger.Error(
"Quest template null when attempting to create completion operational task."
);
logger.Error("Quest template null when attempting to create completion operational task.");
return null;
}
// Filter the items.json items to items the player must retrieve to complete quest: shouldn't be a quest item or "non-existent"
var itemsToRetrievePool = GetItemsToRetrievePool(
completionConfig,
repeatableConfig.RewardBlacklist
);
var itemsToRetrievePool = GetItemsToRetrievePool(completionConfig, repeatableConfig.RewardBlacklist);
// Filter items within our budget
var (hashSet, budget) = GetItemsWithinBudget(
pmcLevel,
levelsConfig,
roublesConfig,
itemsToRetrievePool
);
var (hashSet, budget) = GetItemsWithinBudget(pmcLevel, levelsConfig, roublesConfig, itemsToRetrievePool);
itemsToRetrievePool = hashSet;
// We also have the option to use whitelist and/or blacklist which is defined in repeatableQuests.json as
@@ -96,22 +86,12 @@ public class CompletionQuestGenerator(
// Filtering too harsh
if (itemsToRetrievePool.Count == 0)
{
logger.Error(
localisationService.GetText(
"repeatable-completion_quest_whitelist_too_small_or_blacklist_too_restrictive"
)
);
logger.Error(localisationService.GetText("repeatable-completion_quest_whitelist_too_small_or_blacklist_too_restrictive"));
return null;
}
var selectedItems = GenerateAvailableForFinish(
quest,
completionConfig,
repeatableConfig,
itemsToRetrievePool.ToList(),
budget
);
var selectedItems = GenerateAvailableForFinish(quest, completionConfig, repeatableConfig, itemsToRetrievePool.ToList(), budget);
quest.Rewards = repeatableQuestRewardGenerator.GenerateReward(
pmcLevel,
@@ -131,10 +111,7 @@ public class CompletionQuestGenerator(
/// <param name="completionConfig">Completion quest type config</param>
/// <param name="itemTplBlacklist">Item tpls to not add to pool</param>
/// <returns>Set of item tpls</returns>
protected HashSet<MongoId> GetItemsToRetrievePool(
Completion completionConfig,
HashSet<MongoId> itemTplBlacklist
)
protected HashSet<MongoId> GetItemsToRetrievePool(Completion completionConfig, HashSet<MongoId> itemTplBlacklist)
{
// Get seasonal items that should not be added to pool as seasonal event is not active
var seasonalItems = seasonalEventService.GetInactiveSeasonalEventItems();
@@ -184,19 +161,12 @@ public class CompletionQuestGenerator(
{
// Be fair, don't value the items be more expensive than the reward
var multiplier = randomUtil.GetDouble(0.5, 1);
var roublesBudget = Math.Floor(
mathUtil.Interp1(pmcLevel, levelsConfig, roublesConfig) * multiplier
);
var roublesBudget = Math.Floor(mathUtil.Interp1(pmcLevel, levelsConfig, roublesConfig) * multiplier);
// Make sure there is always a 5000 rouble budget available for selection
roublesBudget = Math.Max(roublesBudget, 5000d);
return (
itemsToRetrievePool
.Where(itemTpl => itemHelper.GetItemPrice(itemTpl) < roublesBudget)
.ToHashSet(),
roublesBudget
);
return (itemsToRetrievePool.Where(itemTpl => itemHelper.GetItemPrice(itemTpl) < roublesBudget).ToHashSet(), roublesBudget);
}
/// <summary>
@@ -205,14 +175,9 @@ public class CompletionQuestGenerator(
/// <param name="itemSelection">Item selection to filter</param>
/// <param name="pmcLevel">Level of pmc</param>
/// <returns>Filtered selection, or original if null or empty</returns>
protected HashSet<MongoId> GetWhitelistedItemSelection(
HashSet<MongoId> itemSelection,
int pmcLevel
)
protected HashSet<MongoId> GetWhitelistedItemSelection(HashSet<MongoId> itemSelection, int pmcLevel)
{
var itemWhitelist = databaseService
.GetTemplates()
.RepeatableQuests?.Data?.Completion?.ItemsWhitelist;
var itemWhitelist = databaseService.GetTemplates().RepeatableQuests?.Data?.Completion?.ItemsWhitelist;
// Whitelist doesn't exist or is empty, return original
if (itemWhitelist is null || itemWhitelist.Count == 0)
@@ -221,17 +186,13 @@ public class CompletionQuestGenerator(
}
// Filter and concatenate items according to current player level
var itemIdsWhitelisted = itemWhitelist
.Where(p => p.MinPlayerLevel <= pmcLevel)
.SelectMany(x => x.ItemIds)
.ToHashSet(); //.Aggregate((a, p) => a.Concat(p.ItemIds), []);
var itemIdsWhitelisted = itemWhitelist.Where(p => p.MinPlayerLevel <= pmcLevel).SelectMany(x => x.ItemIds).ToHashSet(); //.Aggregate((a, p) => a.Concat(p.ItemIds), []);
var filteredSelection = itemSelection
.Where(x =>
{
// Whitelist can contain item tpls and item base type ids
return itemIdsWhitelisted.Any(v => itemHelper.IsOfBaseclass(x, v))
|| itemIdsWhitelisted.Contains(x);
return itemIdsWhitelisted.Any(v => itemHelper.IsOfBaseclass(x, v)) || itemIdsWhitelisted.Contains(x);
})
.ToHashSet();
@@ -248,14 +209,9 @@ public class CompletionQuestGenerator(
/// <param name="itemSelection">Item selection to filter</param>
/// <param name="pmcLevel">Level of pmc</param>
/// <returns>Filtered selection, or original if null or empty</returns>
protected HashSet<MongoId> GetBlacklistedItemSelection(
HashSet<MongoId> itemSelection,
int pmcLevel
)
protected HashSet<MongoId> GetBlacklistedItemSelection(HashSet<MongoId> itemSelection, int pmcLevel)
{
var itemBlacklist = databaseService
.GetTemplates()
.RepeatableQuests?.Data?.Completion?.ItemsBlacklist;
var itemBlacklist = databaseService.GetTemplates().RepeatableQuests?.Data?.Completion?.ItemsBlacklist;
// Blacklist doesn't exist or is empty, return original
if (itemBlacklist is null || itemBlacklist.Count == 0)
@@ -272,8 +228,7 @@ public class CompletionQuestGenerator(
var filteredSelection = itemSelection
.Where(x =>
{
return itemIdsBlacklisted.All(v => !itemHelper.IsOfBaseclass(x, v))
|| !itemIdsBlacklisted.Contains(x);
return itemIdsBlacklisted.All(v => !itemHelper.IsOfBaseclass(x, v)) || !itemIdsBlacklisted.Contains(x);
})
.ToHashSet();
@@ -323,10 +278,7 @@ public class CompletionQuestGenerator(
if (!found)
{
logger.Error(
localisationService.GetText(
"repeatable-no_reward_item_found_in_price_range",
new { minPrice = 0, roublesBudget }
)
localisationService.GetText("repeatable-no_reward_item_found_in_price_range", new { minPrice = 0, roublesBudget })
);
return chosenRequirementItemsTpls;
@@ -356,17 +308,13 @@ public class CompletionQuestGenerator(
// Push a CompletionCondition with the item and the amount of the item into quest
chosenRequirementItemsTpls.Add(tplChosen);
quest.Conditions.AvailableForFinish.Add(
GenerateCondition(tplChosen, value, repeatableConfig.QuestConfig.Completion)
);
quest.Conditions.AvailableForFinish.Add(GenerateCondition(tplChosen, value, repeatableConfig.QuestConfig.Completion));
// Is there budget left for more items
if (roublesBudget > 0)
{
// Reduce item pool to fit budget
itemSelection = itemSelection
.Where(tpl => itemHelper.GetItemPrice(tpl) < roublesBudget)
.ToList();
itemSelection = itemSelection.Where(tpl => itemHelper.GetItemPrice(tpl) < roublesBudget).ToList();
if (itemSelection.Count == 0)
{
@@ -393,22 +341,12 @@ public class CompletionQuestGenerator(
/// <param name="value">Amount of items of this specific type to request</param>
/// <param name="completionConfig">Completion config from quest.json</param>
/// <returns>object of "Completion"-condition</returns>
protected QuestCondition GenerateCondition(
MongoId itemTpl,
double value,
Completion completionConfig
)
protected QuestCondition GenerateCondition(MongoId itemTpl, double value, Completion completionConfig)
{
var onlyFoundInRaid = completionConfig.RequiredItemsAreFiR;
var minDurability = itemHelper.IsOfBaseclasses(
itemTpl,
[BaseClasses.WEAPON, BaseClasses.ARMOR]
)
var minDurability = itemHelper.IsOfBaseclasses(itemTpl, [BaseClasses.WEAPON, BaseClasses.ARMOR])
? randomUtil.GetArrayValue(
[
completionConfig.RequiredItemMinDurabilityMinMax.Min,
completionConfig.RequiredItemMinDurabilityMinMax.Max,
]
[completionConfig.RequiredItemMinDurabilityMinMax.Min, completionConfig.RequiredItemMinDurabilityMinMax.Max]
)
: 0;
@@ -35,14 +35,13 @@ public class EliminationQuestGenerator(
/// <summary>
/// Body parts to present to the client as opposed to the body part information in quest data.
/// </summary>
private static readonly FrozenDictionary<string, List<string>> _bodyPartsToClient =
new Dictionary<string, List<string>>
{
{ BodyParts.Arms, [BodyParts.LeftArm, BodyParts.RightArm] },
{ BodyParts.Legs, [BodyParts.LeftLeg, BodyParts.RightLeg] },
{ BodyParts.Head, [BodyParts.Head] },
{ BodyParts.Chest, [BodyParts.Chest, BodyParts.Stomach] },
}.ToFrozenDictionary();
private static readonly FrozenDictionary<string, List<string>> _bodyPartsToClient = new Dictionary<string, List<string>>
{
{ BodyParts.Arms, [BodyParts.LeftArm, BodyParts.RightArm] },
{ BodyParts.Legs, [BodyParts.LeftLeg, BodyParts.RightLeg] },
{ BodyParts.Head, [BodyParts.Head] },
{ BodyParts.Chest, [BodyParts.Chest, BodyParts.Stomach] },
}.ToFrozenDictionary();
/// <summary>
/// MaxDistDifficulty is defined by 2, this could be a tuning parameter if we don't like the reward generation
@@ -83,9 +82,7 @@ public class EliminationQuestGenerator(
var generationData = GetGenerationData(repeatableConfig, pmcLevel);
if (generationData is null)
{
logger.Error(
localisationService.GetText("repeatable-eliminationQuestGenerationData-is-null")
);
logger.Error(localisationService.GetText("repeatable-eliminationQuestGenerationData-is-null"));
return null;
}
@@ -114,18 +111,13 @@ public class EliminationQuestGenerator(
// Target on bodyPart max. difficulty is that of the least probable element
var maxTargetDifficulty = 1 / generationData.TargetsConfig.MinProbability();
var maxBodyPartsDifficulty =
generationData.EliminationConfig.MinKills
/ generationData.BodyPartsConfig.MinProbability();
var maxBodyPartsDifficulty = generationData.EliminationConfig.MinKills / generationData.BodyPartsConfig.MinProbability();
var maxKillDifficulty = generationData.EliminationConfig.MaxKills;
var targetPool = questTypePool.Pool.Elimination;
// Get a random bot type to eliminate
var (botTypeToEliminate, targetsConfig) = GetBotTypeToEliminate(
generationData,
questTypePool
);
var (botTypeToEliminate, targetsConfig) = GetBotTypeToEliminate(generationData, questTypePool);
if (botTypeToEliminate is null || targetsConfig is null)
{
logger.Warning(localisationService.GetText("repeatable-no-bot-types-remain"));
@@ -143,30 +135,18 @@ public class EliminationQuestGenerator(
// Try and get a target location pool for this bot type
if (!targetPool.Targets.TryGetValue(botTypeToEliminate, out var targetLocationPool))
{
logger.Error(
localisationService.GetText("repeatable-unable-get-target-pool", botTypeToEliminate)
);
logger.Error(localisationService.GetText("repeatable-unable-get-target-pool", botTypeToEliminate));
return null;
}
// Try and get a location key for this quest
if (
!TryGetLocationKey(
generationData,
targetPool,
botTypeToEliminate,
targetLocationPool.Locations,
out var locationKey
) || locationKey is null
!TryGetLocationKey(generationData, targetPool, botTypeToEliminate, targetLocationPool.Locations, out var locationKey)
|| locationKey is null
)
{
logger.Error(
localisationService.GetText(
"repeatable-unable-get-location-key",
botTypeToEliminate
)
);
logger.Error(localisationService.GetText("repeatable-unable-get-location-key", botTypeToEliminate));
return null;
}
@@ -174,9 +154,7 @@ public class EliminationQuestGenerator(
// Generate a body part, make sure we ref the body part difficulty so it can be adjusted
var bodyPartsToClient = new List<string>();
var bodyPartDifficulty = 0d;
var generateBodyParts = randomUtil.GetChance100(
generationData.EliminationConfig.BodyPartChance
);
var generateBodyParts = randomUtil.GetChance100(generationData.EliminationConfig.BodyPartChance);
if (generateBodyParts)
{
// draw the target body part and calculate the difficulty factor
@@ -184,12 +162,7 @@ public class EliminationQuestGenerator(
}
// Draw a distance condition
var isDistanceRequirementAllowed = IsDistanceRequirementAllowed(
generationData,
botTypeToEliminate,
locationKey,
targetsConfig
);
var isDistanceRequirementAllowed = IsDistanceRequirementAllowed(generationData, botTypeToEliminate, locationKey, targetsConfig);
int? distance = null;
var distanceDifficulty = 0;
@@ -204,9 +177,7 @@ public class EliminationQuestGenerator(
string? allowedWeaponsCategory = null;
var generateWeaponCategoryRequirement = randomUtil.GetChance100(
generationData.EliminationConfig.WeaponCategoryRequirementChance
);
var generateWeaponCategoryRequirement = randomUtil.GetChance100(generationData.EliminationConfig.WeaponCategoryRequirementChance);
// Generate a weapon category requirement
if (generateWeaponCategoryRequirement)
@@ -217,9 +188,7 @@ public class EliminationQuestGenerator(
// Only allow a specific weapon requirement if a weapon category was not chosen
MongoId? allowedWeapon = null;
var generateWeaponRequirement = randomUtil.GetChance100(
generationData.EliminationConfig.WeaponRequirementChance
);
var generateWeaponRequirement = randomUtil.GetChance100(generationData.EliminationConfig.WeaponRequirementChance);
// Generate a weapon requirement
if (!generateWeaponCategoryRequirement && generateWeaponRequirement)
@@ -228,11 +197,7 @@ public class EliminationQuestGenerator(
}
// Draw how many npm kills are required
var desiredKillCount = GetEliminationKillCount(
botTypeToEliminate,
targetsConfig,
generationData.EliminationConfig
);
var desiredKillCount = GetEliminationKillCount(botTypeToEliminate, targetsConfig, generationData.EliminationConfig);
var killDifficulty = desiredKillCount;
@@ -261,12 +226,7 @@ public class EliminationQuestGenerator(
if (quest is null)
{
logger.Error(
localisationService.GetText(
"repeatable-quest_generation_failed_no_template",
"elimination"
)
);
logger.Error(localisationService.GetText("repeatable-quest_generation_failed_no_template", "elimination"));
return null;
}
@@ -285,19 +245,11 @@ public class EliminationQuestGenerator(
if (locationKey != "any")
{
var locationId = Enum.Parse<ELocationName>(locationKey);
availableForFinishCondition.Counter.Conditions.Add(
GenerateEliminationLocation(generationData.LocationsConfig[locationId])
);
availableForFinishCondition.Counter.Conditions.Add(GenerateEliminationLocation(generationData.LocationsConfig[locationId]));
}
availableForFinishCondition.Counter.Conditions.Add(
GenerateEliminationCondition(
botTypeToEliminate,
bodyPartsToClient,
distance,
allowedWeapon,
allowedWeaponsCategory
)
GenerateEliminationCondition(botTypeToEliminate, bodyPartsToClient, distance, allowedWeapon, allowedWeaponsCategory)
);
availableForFinishCondition.Value = desiredKillCount;
availableForFinishCondition.Id = new MongoId();
@@ -316,15 +268,9 @@ public class EliminationQuestGenerator(
return quest;
}
protected EliminationQuestGenerationData? GetGenerationData(
RepeatableQuestConfig repeatableConfig,
int pmcLevel
)
protected EliminationQuestGenerationData? GetGenerationData(RepeatableQuestConfig repeatableConfig, int pmcLevel)
{
var eliminationConfig = repeatableQuestHelper.GetEliminationConfigByPmcLevel(
pmcLevel,
repeatableConfig
);
var eliminationConfig = repeatableQuestHelper.GetEliminationConfigByPmcLevel(pmcLevel, repeatableConfig);
if (eliminationConfig is null)
{
@@ -334,22 +280,13 @@ public class EliminationQuestGenerator(
var locationsConfig = repeatableConfig.Locations;
var targetsConfig = new ProbabilityObjectArray<string, BossInfo>(
cloner,
eliminationConfig.Targets
);
var bodyPartsConfig = new ProbabilityObjectArray<string, List<string>>(
cloner,
eliminationConfig.BodyParts
);
var targetsConfig = new ProbabilityObjectArray<string, BossInfo>(cloner, eliminationConfig.Targets);
var bodyPartsConfig = new ProbabilityObjectArray<string, List<string>>(cloner, eliminationConfig.BodyParts);
var weaponCategoryRequirementConfig = new ProbabilityObjectArray<string, List<MongoId>>(
cloner,
eliminationConfig.WeaponCategoryRequirements
);
var weaponRequirementConfig = new ProbabilityObjectArray<string, List<MongoId>>(
cloner,
eliminationConfig.WeaponRequirements
);
var weaponRequirementConfig = new ProbabilityObjectArray<string, List<MongoId>>(cloner, eliminationConfig.WeaponRequirements);
return new EliminationQuestGenerationData(
eliminationConfig,
@@ -374,9 +311,7 @@ public class EliminationQuestGenerator(
{
var targetPool = questTypePool.Pool.Elimination;
var targetsConfig = generationData.TargetsConfig.Filter(x =>
targetPool.Targets.ContainsKey(x.Key)
);
var targetsConfig = generationData.TargetsConfig.Filter(x => targetPool.Targets.ContainsKey(x.Key));
if (targetsConfig.Count != 0 && !targetsConfig.All(x => x.Data?.IsBoss ?? false))
{
@@ -407,9 +342,7 @@ public class EliminationQuestGenerator(
out string? locationKey
)
{
var useSpecificLocation = randomUtil.GetChance100(
generationData.EliminationConfig.SpecificLocationChance
);
var useSpecificLocation = randomUtil.GetChance100(generationData.EliminationConfig.SpecificLocationChance);
switch (useSpecificLocation)
{
@@ -432,11 +365,7 @@ public class EliminationQuestGenerator(
if (locations.Count == 0)
{
// Never should reach this if everything works out
logger.Error(
localisationService.GetText(
"quest-repeatable_elimination_generation_failed_please_report"
)
);
logger.Error(localisationService.GetText("quest-repeatable_elimination_generation_failed_please_report"));
locationKey = null;
return false;
@@ -459,9 +388,7 @@ public class EliminationQuestGenerator(
var tmpKey = locationKey;
// Filter locations bot can be killed on to just those not chosen by key
possibleLocationPool.Locations = possibleLocationPool
.Locations?.Where(location => location != tmpKey)
.ToList();
possibleLocationPool.Locations = possibleLocationPool.Locations?.Where(location => location != tmpKey).ToList();
// None left after filtering
if (possibleLocationPool.Locations?.Count is null or 0)
@@ -480,10 +407,7 @@ public class EliminationQuestGenerator(
/// <param name="generationData">Generation data</param>
/// <param name="bodyPartDifficulty">BodyPartDifficulty to modify based on selection</param>
/// <returns>List of selected body parts</returns>
protected List<string> GenerateBodyParts(
EliminationQuestGenerationData generationData,
ref double bodyPartDifficulty
)
protected List<string> GenerateBodyParts(EliminationQuestGenerationData generationData, ref double bodyPartDifficulty)
{
// if we add a bodyPart condition, we draw randomly one or two parts
// each bodyPart of the BODYPARTS ProbabilityObjectArray includes the string(s)
@@ -533,9 +457,7 @@ public class EliminationQuestGenerator(
)
{
// This location is can be chosen for a distance requirement
var whitelisted = !generationData.EliminationConfig.DistLocationBlacklist.Contains(
locationKey
);
var whitelisted = !generationData.EliminationConfig.DistLocationBlacklist.Contains(locationKey);
// We're not whitelisted, exit early to avoid doing a roll for no reason
if (!whitelisted)
@@ -544,9 +466,7 @@ public class EliminationQuestGenerator(
}
// Are we allowed a distance condition by chance?
var isAllowedByChance = randomUtil.GetChance100(
generationData.EliminationConfig.DistanceProbability
);
var isAllowedByChance = randomUtil.GetChance100(generationData.EliminationConfig.DistanceProbability);
// Not allowed by chance, return early.
// We now just assume we rolled this condition and don't take it into account anymore.
@@ -567,25 +487,15 @@ public class EliminationQuestGenerator(
.GetDictionary()
.Select(x => x.Value)
.Where(location => location.Base?.Id != null)
.Select(location => new
{
location.Base.Id,
BossSpawn = location.Base.BossLocationSpawn,
});
.Select(location => new { location.Base.Id, BossSpawn = location.Base.BossLocationSpawn });
// filter for the current boss to spawn on map
var thisBossSpawns = bossSpawns
.Select(x => new
{
x.Id,
BossSpawn = x.BossSpawn.Where(e => e.BossName == botTypeToEliminate),
})
.Select(x => new { x.Id, BossSpawn = x.BossSpawn.Where(e => e.BossName == botTypeToEliminate) })
.Where(x => x.BossSpawn.Any());
// remove blacklisted locations
var allowedSpawns = thisBossSpawns.Where(x =>
!generationData.EliminationConfig.DistLocationBlacklist.Contains(x.Id)
);
var allowedSpawns = thisBossSpawns.Where(x => !generationData.EliminationConfig.DistLocationBlacklist.Contains(x.Id));
// if the boss spawns on non-blacklisted locations and the current location is allowed,
// we can generate a distance kill requirement
@@ -603,19 +513,13 @@ public class EliminationQuestGenerator(
var distance = (int)
Math.Floor(
Math.Abs(randomUtil.Random.NextDouble() - randomUtil.Random.NextDouble())
* (
1
+ generationData.EliminationConfig.MaxDistance
- generationData.EliminationConfig.MinDistance
)
* (1 + generationData.EliminationConfig.MaxDistance - generationData.EliminationConfig.MinDistance)
+ generationData.EliminationConfig.MinDistance
);
distance = (int)Math.Ceiling((decimal)(distance / 5d)) * 5;
var distanceDifficulty = (int)(
MaxDistDifficulty * distance / generationData.EliminationConfig.MaxDistance
);
var distanceDifficulty = (int)(MaxDistDifficulty * distance / generationData.EliminationConfig.MaxDistance);
return (distance, distanceDifficulty);
}
@@ -626,10 +530,7 @@ public class EliminationQuestGenerator(
/// <param name="generationData">Generation data</param>
/// <param name="distance">Distance to generate it for, pass null if not required</param>
/// <returns>Weapon requirement category selected</returns>
protected string? GenerateWeaponCategoryRequirement(
EliminationQuestGenerationData generationData,
int? distance
)
protected string? GenerateWeaponCategoryRequirement(EliminationQuestGenerationData generationData, int? distance)
{
switch (distance)
{
@@ -639,9 +540,7 @@ public class EliminationQuestGenerator(
HashSet<string> weaponTypeBlacklist = ["Shotgun", "Pistol"];
// Filter out close range weapons from long distance requirement
generationData.WeaponCategoryRequirementConfig.RemoveAll(category =>
weaponTypeBlacklist.Contains(category.Key)
);
generationData.WeaponCategoryRequirementConfig.RemoveAll(category => weaponTypeBlacklist.Contains(category.Key));
break;
}
// Filter out long range weapons from close distance requirement
@@ -650,9 +549,7 @@ public class EliminationQuestGenerator(
HashSet<string> weaponTypeBlacklist = ["MarksmanRifle", "DMR"];
// Filter out far range weapons from close distance requirement
generationData.WeaponCategoryRequirementConfig.RemoveAll(category =>
weaponTypeBlacklist.Contains(category.Key)
);
generationData.WeaponCategoryRequirementConfig.RemoveAll(category => weaponTypeBlacklist.Contains(category.Key));
break;
}
}
@@ -669,20 +566,14 @@ public class EliminationQuestGenerator(
/// </summary>
/// <param name="generationData">Generation data</param>
/// <returns>Weapon to use</returns>
protected MongoId GenerateSpecificWeaponRequirement(
EliminationQuestGenerationData generationData
)
protected MongoId GenerateSpecificWeaponRequirement(EliminationQuestGenerationData generationData)
{
var weaponRequirement = generationData.WeaponRequirementConfig.Draw(1, false);
var specificAllowedWeaponCategory = generationData.WeaponRequirementConfig.Data(
weaponRequirement[0]
);
var specificAllowedWeaponCategory = generationData.WeaponRequirementConfig.Data(weaponRequirement[0]);
if (specificAllowedWeaponCategory?[0] is null)
{
logger.Error(
localisationService.GetText("repeatable-elimination-specific-weapon-null")
);
logger.Error(localisationService.GetText("repeatable-elimination-specific-weapon-null"));
return MongoId.Empty();
}
@@ -706,30 +597,18 @@ public class EliminationQuestGenerator(
{
if (targetsConfig.Data(targetKey)?.IsBoss ?? false)
{
return randomUtil.RandInt(
eliminationConfig.MinBossKills,
eliminationConfig.MaxBossKills + 1
);
return randomUtil.RandInt(eliminationConfig.MinBossKills, eliminationConfig.MaxBossKills + 1);
}
if (targetsConfig.Data(targetKey)?.IsPmc ?? false)
{
return randomUtil.RandInt(
eliminationConfig.MinPmcKills,
eliminationConfig.MaxPmcKills + 1
);
return randomUtil.RandInt(eliminationConfig.MinPmcKills, eliminationConfig.MaxPmcKills + 1);
}
return randomUtil.RandInt(eliminationConfig.MinKills, eliminationConfig.MaxKills + 1);
}
protected double DifficultyWeighing(
double target,
double bodyPart,
int dist,
int kill,
int weaponRequirement
)
protected double DifficultyWeighing(double target, double bodyPart, int dist, int kill, int weaponRequirement)
{
return Math.Sqrt(Math.Sqrt(target) + bodyPart + dist + weaponRequirement) * kill;
}
@@ -796,11 +675,7 @@ public class EliminationQuestGenerator(
// Don't allow distance + melee requirement
if (distance is not null && allowedWeaponCategory != "5b5f7a0886f77409407a7f96")
{
killConditionProps.Distance = new CounterConditionDistance
{
CompareMethod = ">=",
Value = distance.Value,
};
killConditionProps.Distance = new CounterConditionDistance { CompareMethod = ">=", Value = distance.Value };
}
// Has specific weapon requirement
@@ -54,20 +54,9 @@ public class ExplorationQuestGenerator(
var explorationConfig = repeatableConfig.QuestConfig.Exploration;
// Try and get a location to generate for
if (
!TryGetLocationInfo(
repeatableConfig,
explorationConfig,
questTypePool,
out var locationInfo
) || locationInfo is null
)
if (!TryGetLocationInfo(repeatableConfig, explorationConfig, questTypePool, out var locationInfo) || locationInfo is null)
{
logger.Warning(
localisationService.GetText(
"repeatable-no_location_found_for_exploration_quest_generation"
)
);
logger.Warning(localisationService.GetText("repeatable-no_location_found_for_exploration_quest_generation"));
return null;
}
@@ -82,12 +71,7 @@ public class ExplorationQuestGenerator(
if (quest is null)
{
logger.Error(
localisationService.GetText(
"repeatable-quest_generation_failed_no_template",
"exploration"
)
);
logger.Error(localisationService.GetText("repeatable-quest_generation_failed_no_template", "exploration"));
return null;
}
@@ -95,45 +79,24 @@ public class ExplorationQuestGenerator(
if (!TryGenerateAvailableForFinish(quest, locationInfo))
{
logger.Error(
localisationService.GetText(
"repeatable-available_for_finish_condition_failed_to_generate",
locationInfo.LocationName
)
localisationService.GetText("repeatable-available_for_finish_condition_failed_to_generate", locationInfo.LocationName)
);
return null;
}
// If we require a specific extract requirement, generate it
if (
locationInfo.RequiresSpecificExtract
&& !TryGenerateSpecificExtractRequirement(quest, repeatableConfig, locationInfo)
)
if (locationInfo.RequiresSpecificExtract && !TryGenerateSpecificExtractRequirement(quest, repeatableConfig, locationInfo))
{
logger.Error(
localisationService.GetText(
"repeatable-specific_extract_condition_failed_to_generate",
locationInfo.LocationName
)
localisationService.GetText("repeatable-specific_extract_condition_failed_to_generate", locationInfo.LocationName)
);
return null;
}
// Difficulty for exploration goes from 1 extract to maxExtracts
// Difficulty for reward goes from 0.2...1 -> map
var difficulty = mathUtil.MapToRange(
locationInfo.NumOfExtractsRequired,
1,
explorationConfig.MaximumExtracts,
0.2,
1
);
quest.Rewards = repeatableQuestRewardGenerator.GenerateReward(
pmcLevel,
difficulty,
traderId,
repeatableConfig,
explorationConfig
);
var difficulty = mathUtil.MapToRange(locationInfo.NumOfExtractsRequired, 1, explorationConfig.MaximumExtracts, 0.2, 1);
quest.Rewards = repeatableQuestRewardGenerator.GenerateReward(pmcLevel, difficulty, traderId, repeatableConfig, explorationConfig);
return quest;
}
@@ -168,18 +131,11 @@ public class ExplorationQuestGenerator(
// Make the location info object
var locationTarget = pool.Pool!.Exploration!.Locations![locationKey];
var requiresSpecificExtract = randomUtil.GetChance100(
repeatableConfig.QuestConfig.Exploration.SpecificExits.Chance
);
var requiresSpecificExtract = randomUtil.GetChance100(repeatableConfig.QuestConfig.Exploration.SpecificExits.Chance);
var numExtracts = GetNumberOfExits(explorationConfig, requiresSpecificExtract);
locationInfo = new LocationInfo(
locationKey,
locationTarget.ToList(),
requiresSpecificExtract,
numExtracts
);
locationInfo = new LocationInfo(locationKey, locationTarget.ToList(), requiresSpecificExtract, numExtracts);
// Remove the location from the available pool
pool.Pool.Exploration.Locations.Remove(locationKey);
@@ -196,9 +152,7 @@ public class ExplorationQuestGenerator(
protected int GetNumberOfExits(Exploration config, bool requiresSpecificExtract)
{
// Different max extract count when specific extract needed
var exitTimesMax = requiresSpecificExtract
? config.MaximumExtractsWithSpecificExit
: config.MaximumExtracts + 1;
var exitTimesMax = requiresSpecificExtract ? config.MaximumExtractsWithSpecificExit : config.MaximumExtracts + 1;
return randomUtil.RandInt(1, exitTimesMax);
}
@@ -209,10 +163,7 @@ public class ExplorationQuestGenerator(
/// <param name="locationKey">Map id (e.g. factory4_day)</param>
/// <param name="playerGroup">Pmc/Scav</param>
/// <returns>List of Exit objects</returns>
protected IEnumerable<Exit>? GetLocationExitsForSide(
string locationKey,
PlayerGroup playerGroup
)
protected IEnumerable<Exit>? GetLocationExitsForSide(string locationKey, PlayerGroup playerGroup)
{
var mapExtracts = databaseService.GetLocation(locationKey.ToLowerInvariant())?.AllExtracts;
@@ -235,18 +186,11 @@ public class ExplorationQuestGenerator(
}
// Lookup the location
var location = repeatableQuestHelper.GetQuestLocationByMapId(
locationInfo.LocationName.ToString()
);
var location = repeatableQuestHelper.GetQuestLocationByMapId(locationInfo.LocationName.ToString());
if (location is null)
{
logger.Error(
localisationService.GetText(
"repeatable-unable_to_find_location_id_for_location_name",
locationInfo.LocationName
)
);
logger.Error(localisationService.GetText("repeatable-unable_to_find_location_id_for_location_name", locationInfo.LocationName));
return false;
}
@@ -267,11 +211,7 @@ public class ExplorationQuestGenerator(
};
quest.Conditions.AvailableForFinish![0].Counter!.Id = new MongoId();
quest.Conditions.AvailableForFinish![0].Counter!.Conditions =
[
exitStatusCondition,
locationCondition,
];
quest.Conditions.AvailableForFinish![0].Counter!.Conditions = [exitStatusCondition, locationCondition];
quest.Conditions.AvailableForFinish[0].Value = locationInfo.NumOfExtractsRequired;
quest.Conditions.AvailableForFinish[0].Id = new MongoId();
@@ -294,19 +234,11 @@ public class ExplorationQuestGenerator(
)
{
// Fetch extracts for the requested side
var mapExits = GetLocationExitsForSide(
locationInfo.LocationName.ToString(),
repeatableConfig.Side
);
var mapExits = GetLocationExitsForSide(locationInfo.LocationName.ToString(), repeatableConfig.Side);
if (mapExits is null)
{
logger.Error(
localisationService.GetText(
"repeatable-unable_to_find_exits_for_location",
locationInfo.LocationName
)
);
logger.Error(localisationService.GetText("repeatable-unable_to_find_exits_for_location", locationInfo.LocationName));
return false;
}
@@ -315,19 +247,12 @@ public class ExplorationQuestGenerator(
// Exclude exits with a requirement to leave (e.g. car extracts)
var possibleExits = exitPool.Where(exit =>
repeatableConfig.QuestConfig.Exploration.SpecificExits.PassageRequirementWhitelist.Contains(
"PassageRequirement"
)
repeatableConfig.QuestConfig.Exploration.SpecificExits.PassageRequirementWhitelist.Contains("PassageRequirement")
);
if (!possibleExits.Any())
{
logger.Error(
localisationService.GetText(
"repeatable-unable_choose_exit_pool_empty",
locationInfo.LocationName
)
);
logger.Error(localisationService.GetText("repeatable-unable_choose_exit_pool_empty", locationInfo.LocationName));
return false;
}
@@ -42,9 +42,7 @@ public class PickupQuestGenerator(
sessionId
);
var itemTypeToFetchWithCount = randomUtil.GetArrayValue(
pickupConfig.ItemTypeToFetchWithMaxCount
);
var itemTypeToFetchWithCount = randomUtil.GetArrayValue(pickupConfig.ItemTypeToFetchWithMaxCount);
var itemCountToFetch = randomUtil.RandInt(
itemTypeToFetchWithCount.MinimumPickupCount.Value,
@@ -54,34 +52,22 @@ public class PickupQuestGenerator(
// var locationKey: string = this.randomUtil.drawRandomFromDict(questTypePool.pool.Pickup.locations)[0];
// var locationTarget = questTypePool.pool.Pickup.locations[locationKey];
var findCondition = quest.Conditions.AvailableForFinish.FirstOrDefault(x =>
x.ConditionType == "FindItem"
);
var findCondition = quest.Conditions.AvailableForFinish.FirstOrDefault(x => x.ConditionType == "FindItem");
findCondition.Target = new ListOrT<string>([itemTypeToFetchWithCount.ItemType], null);
findCondition.Value = itemCountToFetch;
var counterCreatorCondition = quest.Conditions.AvailableForFinish.FirstOrDefault(x =>
x.ConditionType == "CounterCreator"
);
var counterCreatorCondition = quest.Conditions.AvailableForFinish.FirstOrDefault(x => x.ConditionType == "CounterCreator");
// var locationCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Location");
// (locationCondition._props as ILocationConditionProps).target = [...locationTarget];
var equipmentCondition = counterCreatorCondition.Counter.Conditions.FirstOrDefault(x =>
x.ConditionType == "Equipment"
);
var equipmentCondition = counterCreatorCondition.Counter.Conditions.FirstOrDefault(x => x.ConditionType == "Equipment");
equipmentCondition.EquipmentInclusive =
[
[itemTypeToFetchWithCount.ItemType],
];
// Add rewards
quest.Rewards = repeatableQuestRewardGenerator.GenerateReward(
pmcLevel,
1,
traderId,
repeatableConfig,
pickupConfig
);
quest.Rewards = repeatableQuestRewardGenerator.GenerateReward(pmcLevel, 1, traderId, repeatableConfig, pickupConfig);
return quest;
}
@@ -68,11 +68,7 @@ public class RepeatableQuestRewardGenerator(
)
{
// Get vars to configure rewards with
var rewardParams = GetQuestRewardValues(
repeatableConfig.RewardScaling,
difficulty,
pmcLevel
);
var rewardParams = GetQuestRewardValues(repeatableConfig.RewardScaling, difficulty, pmcLevel);
// Get budget to spend on item rewards (copy of raw roubles given)
var itemRewardBudget = rewardParams.RewardRoubles;
@@ -112,13 +108,12 @@ public class RepeatableQuestRewardGenerator(
rewardIndex++;
// Add GP coin reward
rewards["Success"]
.Add(GenerateItemReward(Money.GP, rewardParams.GpCoinRewardCount, rewardIndex));
rewards["Success"].Add(GenerateItemReward(Money.GP, rewardParams.GpCoinRewardCount, rewardIndex));
rewardIndex++;
// Add preset weapon to reward if checks pass
var traderWhitelistDetails = repeatableConfig.TraderWhitelist.FirstOrDefault(
traderWhitelist => traderWhitelist.TraderId == traderId
var traderWhitelistDetails = repeatableConfig.TraderWhitelist.FirstOrDefault(traderWhitelist =>
traderWhitelist.TraderId == traderId
);
if (traderWhitelistDetails is null)
@@ -127,10 +122,7 @@ public class RepeatableQuestRewardGenerator(
return null;
}
if (
traderWhitelistDetails.RewardCanBeWeapon
&& randomUtil.GetChance100(traderWhitelistDetails.WeaponRewardChancePercent)
)
if (traderWhitelistDetails.RewardCanBeWeapon && randomUtil.GetChance100(traderWhitelistDetails.WeaponRewardChancePercent))
{
var chosenWeapon = GetRandomWeaponPresetWithinBudget(itemRewardBudget, rewardIndex);
if (chosenWeapon is not null)
@@ -143,17 +135,11 @@ public class RepeatableQuestRewardGenerator(
}
}
var inBudgetRewardItemPool = ChooseRewardItemsWithinBudget(
repeatableConfig,
itemRewardBudget,
traderId
);
var inBudgetRewardItemPool = ChooseRewardItemsWithinBudget(repeatableConfig, itemRewardBudget, traderId);
if (rewardTplBlacklist is not null)
{
// Filter reward pool of items from blacklist, only use if there's at least 1 item remaining
var filteredRewardItemPool = inBudgetRewardItemPool
.Where(item => !rewardTplBlacklist.Contains(item.Id))
.ToList();
var filteredRewardItemPool = inBudgetRewardItemPool.Where(item => !rewardTplBlacklist.Contains(item.Id)).ToList();
if (filteredRewardItemPool.Count != 0)
{
@@ -180,8 +166,7 @@ public class RepeatableQuestRewardGenerator(
// Add item rewards
foreach (var itemReward in itemsToReward)
{
rewards["Success"]
.Add(GenerateItemReward(itemReward.Key.Id, itemReward.Value, rewardIndex));
rewards["Success"].Add(GenerateItemReward(itemReward.Key.Id, itemReward.Value, rewardIndex));
rewardIndex++;
}
}
@@ -205,9 +190,7 @@ public class RepeatableQuestRewardGenerator(
if (logger.IsLogEnabled(LogLevel.Debug))
{
logger.Debug(
$"Adding: {rewardParams.RewardReputation} {traderId.ToString()} trader reputation reward"
);
logger.Debug($"Adding: {rewardParams.RewardReputation} {traderId.ToString()} trader reputation reward");
}
}
@@ -230,20 +213,14 @@ public class RepeatableQuestRewardGenerator(
if (logger.IsLogEnabled(LogLevel.Debug))
{
logger.Debug(
$"Adding {rewardParams.SkillPointReward} skill points to {targetSkill}"
);
logger.Debug($"Adding {rewardParams.SkillPointReward} skill points to {targetSkill}");
}
}
return rewards;
}
protected QuestRewardValues GetQuestRewardValues(
RewardScaling rewardScaling,
double effectiveDifficulty,
int pmcLevel
)
protected QuestRewardValues GetQuestRewardValues(RewardScaling rewardScaling, double effectiveDifficulty, int pmcLevel)
{
// difficulty could go from 0.2 ... -> for lowest difficulty receive 0.2*nominal reward
var levelsConfig = rewardScaling.Levels;
@@ -260,35 +237,11 @@ public class RepeatableQuestRewardGenerator(
{
SkillPointReward = mathUtil.Interp1(pmcLevel, levelsConfig, skillPointRewardConfig),
SkillRewardChance = mathUtil.Interp1(pmcLevel, levelsConfig, skillRewardChanceConfig),
RewardReputation = GetRewardRep(
effectiveDifficulty,
pmcLevel,
levelsConfig,
reputationConfig,
rewardSpreadConfig
),
RewardReputation = GetRewardRep(effectiveDifficulty, pmcLevel, levelsConfig, reputationConfig, rewardSpreadConfig),
RewardNumItems = GetRewardNumItems(pmcLevel, levelsConfig, itemsConfig),
RewardRoubles = GetRewardRoubles(
effectiveDifficulty,
pmcLevel,
levelsConfig,
roublesConfig,
rewardSpreadConfig
),
GpCoinRewardCount = GetGpCoinRewardCount(
effectiveDifficulty,
pmcLevel,
levelsConfig,
gpCoinConfig,
rewardSpreadConfig
),
RewardXP = GetRewardXp(
effectiveDifficulty,
pmcLevel,
levelsConfig,
xpConfig,
rewardSpreadConfig
),
RewardRoubles = GetRewardRoubles(effectiveDifficulty, pmcLevel, levelsConfig, roublesConfig, rewardSpreadConfig),
GpCoinRewardCount = GetGpCoinRewardCount(effectiveDifficulty, pmcLevel, levelsConfig, gpCoinConfig, rewardSpreadConfig),
RewardXP = GetRewardXp(effectiveDifficulty, pmcLevel, levelsConfig, xpConfig, rewardSpreadConfig),
};
}
@@ -336,11 +289,7 @@ public class RepeatableQuestRewardGenerator(
return Math.Round(multiplier) / 100;
}
protected int GetRewardNumItems(
int pmcLevel,
List<double> levelsConfig,
List<double> itemsConfig
)
protected int GetRewardNumItems(int pmcLevel, List<double> levelsConfig, List<double> itemsConfig)
{
var interpolatedNumItems = mathUtil.Interp1(pmcLevel, levelsConfig, itemsConfig);
@@ -395,21 +344,14 @@ public class RepeatableQuestRewardGenerator(
if (itemHelper.IsOfBaseclass(chosenItemFromPool.Id, BaseClasses.AMMO))
{
// Don't reward ammo that stacks to less than what's allowed in config
if (
chosenItemFromPool.Properties.StackMaxSize
< repeatableConfig.RewardAmmoStackMinSize
)
if (chosenItemFromPool.Properties.StackMaxSize < repeatableConfig.RewardAmmoStackMinSize)
{
i--;
continue;
}
// Choose the smallest value between budget, fitting size and stack max
rewardItemStackCount = CalculateAmmoStackSizeThatFitsBudget(
chosenItemFromPool,
itemRewardBudget,
maxItemCount
);
rewardItemStackCount = CalculateAmmoStackSizeThatFitsBudget(chosenItemFromPool, itemRewardBudget, maxItemCount);
}
// 25% chance to double, triple or quadruple reward stack
@@ -425,9 +367,7 @@ public class RepeatableQuestRewardGenerator(
var calculatedItemRewardBudget = itemRewardBudget - rewardItemStackCount * itemCost;
if (logger.IsLogEnabled(LogLevel.Debug))
{
logger.Debug(
$"Added item: {chosenItemFromPool.Id} with price: {rewardItemStackCount * itemCost}"
);
logger.Debug($"Added item: {chosenItemFromPool.Id} with price: {rewardItemStackCount * itemCost}");
}
// If we still have budget narrow down possible items
@@ -444,9 +384,7 @@ public class RepeatableQuestRewardGenerator(
{
if (logger.IsLogEnabled(LogLevel.Debug))
{
logger.Debug(
$"Reward pool empty with: {calculatedItemRewardBudget} roubles of budget remaining"
);
logger.Debug($"Reward pool empty with: {calculatedItemRewardBudget} roubles of budget remaining");
}
}
}
@@ -466,11 +404,7 @@ public class RepeatableQuestRewardGenerator(
/// <param name="roublesBudget"> Rouble budget </param>
/// <param name="rewardNumItems"> Count of rewarded items </param>
/// <returns> Count that fits budget (min 1) </returns>
protected int CalculateAmmoStackSizeThatFitsBudget(
TemplateItem itemSelected,
double roublesBudget,
int rewardNumItems
)
protected int CalculateAmmoStackSizeThatFitsBudget(TemplateItem itemSelected, double roublesBudget, int rewardNumItems)
{
// Calculate budget per reward item
var stackRoubleBudget = roublesBudget / rewardNumItems;
@@ -487,18 +421,11 @@ public class RepeatableQuestRewardGenerator(
return (int)Math.Clamp(stackSizeThatFitsBudget, 1, stackMaxCount);
}
protected bool CanIncreaseRewardItemStackSize(
TemplateItem item,
int maxRoublePriceToStack,
int randomChanceToPass = 100
)
protected bool CanIncreaseRewardItemStackSize(TemplateItem item, int maxRoublePriceToStack, int randomChanceToPass = 100)
{
var isEligibleForStackSizeIncrease =
presetHelper.GetDefaultPresetOrItemPrice(item.Id) < maxRoublePriceToStack
&& !itemHelper.IsOfBaseclasses(
item.Id,
[BaseClasses.WEAPON, BaseClasses.ARMORED_EQUIPMENT, BaseClasses.AMMO]
)
&& !itemHelper.IsOfBaseclasses(item.Id, [BaseClasses.WEAPON, BaseClasses.ARMORED_EQUIPMENT, BaseClasses.AMMO])
&& !itemHelper.ItemRequiresSoftInserts(item.Id);
return isEligibleForStackSizeIncrease && randomUtil.GetChance100(randomChanceToPass);
@@ -548,25 +475,14 @@ public class RepeatableQuestRewardGenerator(
var rewardableItemPool = GetRewardableItems(repeatableConfig, traderId);
var minPrice = Math.Min(25000, 0.5 * roublesBudget.Value);
var rewardableItemPoolWithinBudget = FilterRewardPoolWithinBudget(
rewardableItemPool,
roublesBudget.Value,
minPrice
);
var rewardableItemPoolWithinBudget = FilterRewardPoolWithinBudget(rewardableItemPool, roublesBudget.Value, minPrice);
if (rewardableItemPoolWithinBudget.Count == 0)
{
logger.Warning(
localisationService.GetText(
"repeatable-no_reward_item_found_in_price_range",
new { minPrice, roublesBudget }
)
);
logger.Warning(localisationService.GetText("repeatable-no_reward_item_found_in_price_range", new { minPrice, roublesBudget }));
// In case we don't find any items in the price range
rewardableItemPoolWithinBudget = rewardableItemPool
.Where(x => itemHelper.GetItemPrice(x.Id) < roublesBudget)
.ToList();
rewardableItemPoolWithinBudget = rewardableItemPool.Where(x => itemHelper.GetItemPrice(x.Id) < roublesBudget).ToList();
}
return rewardableItemPoolWithinBudget;
@@ -579,11 +495,7 @@ public class RepeatableQuestRewardGenerator(
/// <param name="roublesBudget"> The budget remaining for rewards </param>
/// <param name="minPrice"> The minimum priced item to include </param>
/// <returns> List of Items </returns>
protected List<TemplateItem> FilterRewardPoolWithinBudget(
List<TemplateItem> rewardItems,
double roublesBudget,
double minPrice
)
protected List<TemplateItem> FilterRewardPoolWithinBudget(List<TemplateItem> rewardItems, double roublesBudget, double minPrice)
{
return rewardItems
.Where(item =>
@@ -600,17 +512,10 @@ public class RepeatableQuestRewardGenerator(
/// <param name="roublesBudget"> Budget in roubles </param>
/// <param name="rewardIndex"> Index of the reward </param>
/// <returns> Dictionary of the reward and it's price, can return null. </returns>
protected KeyValuePair<Reward, double>? GetRandomWeaponPresetWithinBudget(
double roublesBudget,
int rewardIndex
)
protected KeyValuePair<Reward, double>? GetRandomWeaponPresetWithinBudget(double roublesBudget, int rewardIndex)
{
// Add a random default preset weapon as reward
var defaultPresetPool = new ExhaustableArray<Preset>(
presetHelper.GetDefaultWeaponPresets().Values.ToList(),
randomUtil,
cloner
);
var defaultPresetPool = new ExhaustableArray<Preset>(presetHelper.GetDefaultWeaponPresets().Values.ToList(), randomUtil, cloner);
while (defaultPresetPool.HasValues())
{
@@ -631,12 +536,7 @@ public class RepeatableQuestRewardGenerator(
var chosenPreset = cloner.Clone(randomPreset);
return new KeyValuePair<Reward, double>(
GeneratePresetReward(
chosenPreset.Encyclopedia.Value,
1,
rewardIndex,
chosenPreset.Items
),
GeneratePresetReward(chosenPreset.Encyclopedia.Value, 1, rewardIndex, chosenPreset.Items),
presetPrice
);
}
@@ -654,13 +554,7 @@ public class RepeatableQuestRewardGenerator(
/// <param name="preset"> Optional list of preset items </param>
/// <param name="foundInRaid"> If generated Item is found in raid, default True </param>
/// <returns> Object of "Reward"-item-type </returns>
protected Reward GeneratePresetReward(
MongoId tpl,
int count,
int index,
List<Item>? preset,
bool foundInRaid = true
)
protected Reward GeneratePresetReward(MongoId tpl, int count, int index, List<Item>? preset, bool foundInRaid = true)
{
var id = new MongoId();
var questRewardItem = new Reward
@@ -704,12 +598,7 @@ public class RepeatableQuestRewardGenerator(
/// <param name="index"> All rewards will be appended to a list, for unknown reasons the client wants the index</param>
/// <param name="foundInRaid"> If generated Item is found in raid, default True </param>
/// <returns> Object of "Reward"-item-type </returns>
protected Reward GenerateItemReward(
MongoId tpl,
double count,
int index,
bool foundInRaid = true
)
protected Reward GenerateItemReward(MongoId tpl, double count, int index, bool foundInRaid = true)
{
var id = new MongoId();
var questRewardItem = new Reward
@@ -742,16 +631,10 @@ public class RepeatableQuestRewardGenerator(
{
// Determine currency based on trader
// PK and Fence use Euros, everyone else is Roubles
var currency =
traderId == Traders.PEACEKEEPER || traderId == Traders.FENCE
? Money.EUROS
: Money.ROUBLES;
var currency = traderId == Traders.PEACEKEEPER || traderId == Traders.FENCE ? Money.EUROS : Money.ROUBLES;
// Convert reward amount to Euros if necessary
var rewardAmountToGivePlayer =
currency == Money.EUROS
? handbookHelper.FromRUB(rewardRoubles, Money.EUROS)
: rewardRoubles;
var rewardAmountToGivePlayer = currency == Money.EUROS ? handbookHelper.FromRUB(rewardRoubles, Money.EUROS) : rewardRoubles;
// Get chosen currency + amount and return
return GenerateItemReward(currency, rewardAmountToGivePlayer, rewardIndex, false);
@@ -767,10 +650,7 @@ public class RepeatableQuestRewardGenerator(
/// <param name="repeatableQuestConfig"> Config </param>
/// <param name="traderId"> ID of trader who will give reward to player </param>
/// <returns> List of rewardable items [[_tpl, itemTemplate],...] </returns>
public List<TemplateItem> GetRewardableItems(
RepeatableQuestConfig repeatableQuestConfig,
MongoId traderId
)
public List<TemplateItem> GetRewardableItems(RepeatableQuestConfig repeatableQuestConfig, MongoId traderId)
{
// Get an array of seasonal items that should not be shown right now as seasonal event is not active
var seasonalItems = seasonalEventService.GetInactiveSeasonalEventItems();
@@ -793,9 +673,7 @@ public class RepeatableQuestRewardGenerator(
return false;
}
var traderWhitelist = repeatableQuestConfig.TraderWhitelist.FirstOrDefault(trader =>
trader.TraderId == traderId
);
var traderWhitelist = repeatableQuestConfig.TraderWhitelist.FirstOrDefault(trader => trader.TraderId == traderId);
return IsValidRewardItem(
itemTemplate.Id,