Move RepeatableQuestRewardGenerator.cs and update some reward generation data

This commit is contained in:
Cj
2025-06-24 02:59:37 -04:00
parent 2646f90273
commit c6d5638057
3 changed files with 148 additions and 163 deletions
@@ -219,14 +219,14 @@
"numQuests": 3,
"minPlayerLevel": 5,
"rewardScaling": {
"levels": [1, 10, 20, 30, 40, 50, 60],
"levels": [5, 10, 20, 30, 40, 50, 60],
"experience": [1000, 2000, 8000, 13000, 19000, 24000, 30000],
"roubles": [11000, 20000, 32000, 45000, 58000, 70000, 82000],
"gpCoins": [2, 3, 6, 6, 8, 8, 10],
"items": [2, 4, 5, 5, 5, 5, 5],
"reputation": [0.01, 0.01, 0.02, 0.02, 0.03, 0.03, 0.03],
"rewardSpread": 0.5,
"skillRewardChance": [0, 0.01, 0.05, 0.1, 0.1, 0.15, 0.15],
"items": [2, 3, 4, 5, 5, 5, 5],
"reputation": [0.01, 0.02, 0.03, 0.03, 0.03, 0.03, 0.03],
"rewardSpread": 0.40,
"skillRewardChance": [0, 1, 5, 10, 10, 15, 15],
"skillPointReward": [10, 15, 20, 25, 30, 35, 40]
},
"locations": {
@@ -1031,14 +1031,14 @@
"numQuests": 1,
"minPlayerLevel": 15,
"rewardScaling": {
"levels": [1, 10, 20, 30, 40, 50, 60],
"experience": [5000, 15000, 27000, 80000, 210000, 260000, 350000],
"roubles": [20000, 50000, 175000, 350000, 540000, 710000, 880000],
"levels": [5, 10, 20, 30, 40, 50, 60],
"experience": [7500, 18000, 30000, 80000, 210000, 260000, 350000],
"roubles": [20000, 125000, 200000, 350000, 540000, 710000, 880000],
"gpCoins": [10, 10, 16, 16, 20, 30, 35],
"items": [4, 5, 5, 6, 6, 7, 7],
"reputation": [0.02, 0.03, 0.04, 0.04, 0.05, 0.05, 0.05],
"items": [3, 3, 4, 4, 5, 5, 5],
"reputation": [0.02, 0.03, 0.04, 0.04, 0.05, 0.06, 0.07],
"rewardSpread": 0.5,
"skillRewardChance": [0, 0.05, 0.1, 0.15, 0.2, 0.2, 0.2],
"skillRewardChance": [0, 5, 10, 15, 20, 20, 20],
"skillPointReward": [25, 35, 45, 50, 55, 60, 65]
},
"locations": {
@@ -13,26 +13,26 @@ using SPTarkov.Server.Core.Utils.Cloners;
using SPTarkov.Server.Core.Utils.Collections;
using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel;
namespace SPTarkov.Server.Core.Generators;
namespace SPTarkov.Server.Core.Generators.RepeatableQuestGeneration;
[Injectable]
public class RepeatableQuestRewardGenerator(
ISptLogger<RepeatableQuestRewardGenerator> _logger,
RandomUtil _randomUtil,
HashUtil _hashUtil,
MathUtil _mathUtil,
DatabaseService _databaseService,
ItemHelper _itemHelper,
PresetHelper _presetHelper,
HandbookHelper _handbookHelper,
LocalisationService _localisationService,
ItemFilterService _itemFilterService,
SeasonalEventService _seasonalEventService,
ConfigServer _configServer,
ICloner _cloner
ISptLogger<RepeatableQuestRewardGenerator> logger,
RandomUtil randomUtil,
HashUtil hashUtil,
MathUtil mathUtil,
DatabaseService databaseService,
ItemHelper itemHelper,
PresetHelper presetHelper,
HandbookHelper handbookHelper,
LocalisationService localisationService,
ItemFilterService itemFilterService,
SeasonalEventService seasonalEventService,
ConfigServer configServer,
ICloner cloner
)
{
protected QuestConfig _questConfig = _configServer.GetConfig<QuestConfig>();
protected QuestConfig QuestConfig = configServer.GetConfig<QuestConfig>();
/// <summary>
/// Generate the reward for a mission. A reward can consist of: <br />
@@ -94,7 +94,7 @@ public class RepeatableQuestRewardGenerator(
rewards.Success.Add(
new Reward
{
Id = _hashUtil.Generate(),
Id = hashUtil.Generate(),
Unknown = false,
GameMode = [],
AvailableInGameEditions = [],
@@ -108,13 +108,13 @@ public class RepeatableQuestRewardGenerator(
// Add money reward
rewards.Success.Add(
GetMoneyReward(traderId, rewardParams.RewardRoubles.Value, rewardIndex)
GetMoneyReward(traderId, rewardParams.RewardRoubles, rewardIndex)
);
rewardIndex++;
// Add GP coin reward
rewards.Success.Add(
GenerateItemReward(Money.GP, rewardParams.GpCoinRewardCount.Value, rewardIndex)
GenerateItemReward(Money.GP, rewardParams.GpCoinRewardCount, rewardIndex)
);
rewardIndex++;
@@ -125,17 +125,17 @@ public class RepeatableQuestRewardGenerator(
if (traderWhitelistDetails is null)
{
_logger.Error($"Cound not find trader id: {traderId} in whitelist");
logger.Error($"Cound not find trader id: {traderId} in whitelist");
return null;
}
if (
traderWhitelistDetails.RewardCanBeWeapon
&& _randomUtil.GetChance100(traderWhitelistDetails.WeaponRewardChancePercent)
&& randomUtil.GetChance100(traderWhitelistDetails.WeaponRewardChancePercent)
)
{
var chosenWeapon = GetRandomWeaponPresetWithinBudget(
itemRewardBudget.Value,
itemRewardBudget,
rewardIndex
);
if (chosenWeapon is not null)
@@ -158,16 +158,17 @@ public class RepeatableQuestRewardGenerator(
// 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)
);
if (filteredRewardItemPool.Count() > 0)
).ToList();
if (filteredRewardItemPool.Count != 0)
{
inBudgetRewardItemPool = filteredRewardItemPool.ToList();
}
}
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Generating: {repeatableConfig.Name} quest for: {traderId} with budget: {itemRewardBudget} totalling: {rewardParams.RewardNumItems} items"
);
}
@@ -176,8 +177,8 @@ public class RepeatableQuestRewardGenerator(
{
var itemsToReward = GetRewardableItemsFromPoolWithinBudget(
inBudgetRewardItemPool,
rewardParams.RewardNumItems.Value,
itemRewardBudget.Value,
rewardParams.RewardNumItems,
itemRewardBudget,
repeatableConfig
);
@@ -196,7 +197,7 @@ public class RepeatableQuestRewardGenerator(
{
Reward reward = new()
{
Id = _hashUtil.Generate(),
Id = hashUtil.Generate(),
Unknown = false,
GameMode = [],
AvailableInGameEditions = [],
@@ -208,21 +209,21 @@ public class RepeatableQuestRewardGenerator(
rewards.Success.Add(reward);
rewardIndex++;
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Adding: {rewardParams.RewardReputation} {traderId} trader reputation reward"
);
}
}
// Chance of adding skill reward
if (_randomUtil.GetChance100((double)rewardParams.SkillRewardChance * 100))
if (randomUtil.GetChance100(rewardParams.SkillRewardChance))
{
var targetSkill = _randomUtil.GetArrayValue(eliminationConfig.PossibleSkillRewards);
var targetSkill = randomUtil.GetArrayValue(eliminationConfig.PossibleSkillRewards);
Reward reward = new()
{
Id = _hashUtil.Generate(),
Id = hashUtil.Generate(),
Unknown = false,
GameMode = [],
AvailableInGameEditions = [],
@@ -233,9 +234,9 @@ public class RepeatableQuestRewardGenerator(
};
rewards.Success.Add(reward);
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Adding {rewardParams.SkillPointReward} skill points to {targetSkill}"
);
}
@@ -245,8 +246,8 @@ public class RepeatableQuestRewardGenerator(
}
protected QuestRewardValues GetQuestRewardValues(
RewardScaling? rewardScaling,
double? difficulty,
RewardScaling rewardScaling,
double effectiveDifficulty,
int pmcLevel
)
{
@@ -261,16 +262,10 @@ public class RepeatableQuestRewardGenerator(
var skillPointRewardConfig = rewardScaling.SkillPointReward;
var reputationConfig = rewardScaling.Reputation;
var effectiveDifficulty = difficulty is null ? 1 : difficulty;
if (difficulty is null)
{
_logger.Warning(_localisationService.GetText("repeatable-difficulty_was_nan"));
}
return new QuestRewardValues
{
SkillPointReward = _mathUtil.Interp1(pmcLevel, levelsConfig, skillPointRewardConfig),
SkillRewardChance = _mathUtil.Interp1(pmcLevel, levelsConfig, skillRewardChanceConfig),
SkillPointReward = mathUtil.Interp1(pmcLevel, levelsConfig, skillPointRewardConfig),
SkillRewardChance = mathUtil.Interp1(pmcLevel, levelsConfig, skillRewardChanceConfig),
RewardReputation = GetRewardRep(
effectiveDifficulty,
pmcLevel,
@@ -304,91 +299,81 @@ public class RepeatableQuestRewardGenerator(
}
protected double GetRewardXp(
double? effectiveDifficulty,
double effectiveDifficulty,
int pmcLevel,
List<double>? levelsConfig,
List<double>? xpConfig,
double? rewardSpreadConfig
List<double> levelsConfig,
List<double> xpConfig,
double rewardSpreadConfig
)
{
var interpolatedXp = mathUtil.Interp1(pmcLevel, levelsConfig, xpConfig);
var randomSpread = randomUtil.GetDouble(1 - rewardSpreadConfig, 1 + rewardSpreadConfig);
return Math.Floor(
effectiveDifficulty
* _mathUtil.Interp1(pmcLevel, levelsConfig, xpConfig)
* _randomUtil.GetDouble(
(double)(1 - rewardSpreadConfig),
(double)(1 + rewardSpreadConfig)
)
?? 0
effectiveDifficulty * interpolatedXp * randomSpread
);
}
protected double GetGpCoinRewardCount(
double? effectiveDifficulty,
double effectiveDifficulty,
int pmcLevel,
List<double>? levelsConfig,
List<double>? gpCoinConfig,
double? rewardSpreadConfig
List<double> levelsConfig,
List<double> gpCoinConfig,
double rewardSpreadConfig
)
{
var interpolatedGpCoins = mathUtil.Interp1(pmcLevel, levelsConfig, gpCoinConfig);
var randomSpread = randomUtil.GetDouble(1 - rewardSpreadConfig, 1 + rewardSpreadConfig);
return Math.Ceiling(
effectiveDifficulty
* _mathUtil.Interp1(pmcLevel, levelsConfig, gpCoinConfig)
* _randomUtil.GetDouble(
(double)(1 - rewardSpreadConfig),
(double)(1 + rewardSpreadConfig)
)
?? 0
effectiveDifficulty * interpolatedGpCoins * randomSpread
);
}
protected double GetRewardRep(
double? effectiveDifficulty,
double effectiveDifficulty,
int pmcLevel,
List<double>? levelsConfig,
List<double>? reputationConfig,
double? rewardSpreadConfig
List<double> levelsConfig,
List<double> reputationConfig,
double rewardSpreadConfig
)
{
return Math.Round(
100
* effectiveDifficulty
* _mathUtil.Interp1(pmcLevel, levelsConfig, reputationConfig)
* _randomUtil.GetDouble(
(double)(1 - rewardSpreadConfig),
(double)(1 + rewardSpreadConfig)
)
?? 0
) / 100;
var difficultyMod = 100 * effectiveDifficulty;
var interpolatedRep = mathUtil.Interp1(pmcLevel, levelsConfig, reputationConfig);
var randomSpread = randomUtil.GetDouble(1 - rewardSpreadConfig, 1 + rewardSpreadConfig);
var multiplier = difficultyMod * interpolatedRep * randomSpread;
return Math.Round(multiplier) / 100;
}
protected int GetRewardNumItems(
int pmcLevel,
List<double>? levelsConfig,
List<double>? itemsConfig
List<double> levelsConfig,
List<double> itemsConfig
)
{
return _randomUtil.RandInt(
var interpolatedNumItems = mathUtil.Interp1(pmcLevel, levelsConfig, itemsConfig);
return randomUtil.RandInt(
1,
(int)Math.Round(_mathUtil.Interp1(pmcLevel, levelsConfig, itemsConfig)) + 1
(int)Math.Round(interpolatedNumItems) + 1
);
}
protected double GetRewardRoubles(
double? effectiveDifficulty,
double effectiveDifficulty,
int pmcLevel,
List<double>? levelsConfig,
List<double>? roublesConfig,
double? rewardSpreadConfig
List<double> levelsConfig,
List<double> roublesConfig,
double rewardSpreadConfig
)
{
var interpolatedRoubles = mathUtil.Interp1(pmcLevel, levelsConfig, roublesConfig);
var randomSpread = randomUtil.GetDouble(1d - rewardSpreadConfig, 1d + rewardSpreadConfig);
return Math.Floor(
effectiveDifficulty
* _mathUtil.Interp1(pmcLevel, levelsConfig, roublesConfig)
* _randomUtil.GetDouble(
1d - rewardSpreadConfig.Value,
1d + rewardSpreadConfig.Value
)
?? 0
effectiveDifficulty * interpolatedRoubles * randomSpread
);
}
@@ -408,7 +393,7 @@ public class RepeatableQuestRewardGenerator(
)
{
var itemsToReturn = new Dictionary<TemplateItem, int>();
var exhausableItemPool = new ExhaustableArray<TemplateItem>(itemPool, _randomUtil, _cloner);
var exhaustibleItemPool = new ExhaustableArray<TemplateItem>(itemPool, randomUtil, cloner);
for (var i = 0; i < maxItemCount; i++)
{
@@ -416,14 +401,14 @@ public class RepeatableQuestRewardGenerator(
var rewardItemStackCount = 1;
// Get a random item
var chosenItemFromPool = exhausableItemPool.GetRandomValue();
if (!exhausableItemPool.HasValues())
var chosenItemFromPool = exhaustibleItemPool.GetRandomValue();
if (chosenItemFromPool is null || !exhaustibleItemPool.HasValues())
{
break;
}
// Handle edge case - ammo
if (_itemHelper.IsOfBaseclass(chosenItemFromPool.Id, BaseClasses.AMMO))
if (itemHelper.IsOfBaseclass(chosenItemFromPool.Id, BaseClasses.AMMO))
{
// Don't reward ammo that stacks to less than what's allowed in config
if (
@@ -435,7 +420,7 @@ public class RepeatableQuestRewardGenerator(
continue;
}
// Choose smallest value between budget, fitting size and stack max
// Choose the smallest value between budget, fitting size and stack max
rewardItemStackCount = CalculateAmmoStackSizeThatFitsBudget(
chosenItemFromPool,
itemRewardBudget,
@@ -452,11 +437,11 @@ public class RepeatableQuestRewardGenerator(
itemsToReturn.Add(chosenItemFromPool, rewardItemStackCount);
var itemCost = _presetHelper.GetDefaultPresetOrItemPrice(chosenItemFromPool.Id);
var itemCost = presetHelper.GetDefaultPresetOrItemPrice(chosenItemFromPool.Id);
var calculatedItemRewardBudget = itemRewardBudget - rewardItemStackCount * itemCost;
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Added item: {chosenItemFromPool.Id} with price: {rewardItemStackCount * itemCost}"
);
}
@@ -465,17 +450,17 @@ public class RepeatableQuestRewardGenerator(
if (calculatedItemRewardBudget > 0)
{
// Filter possible reward items to only items with a price below the remaining budget
exhausableItemPool = new ExhaustableArray<TemplateItem>(
exhaustibleItemPool = new ExhaustableArray<TemplateItem>(
FilterRewardPoolWithinBudget(itemPool, calculatedItemRewardBudget, 0),
_randomUtil,
_cloner
randomUtil,
cloner
);
if (!exhausableItemPool.HasValues())
if (!exhaustibleItemPool.HasValues())
{
if (_logger.IsLogEnabled(LogLevel.Debug))
if (logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug(
logger.Debug(
$"Reward pool empty with: {calculatedItemRewardBudget} roubles of budget remaining"
);
}
@@ -506,7 +491,7 @@ public class RepeatableQuestRewardGenerator(
// Calculate budget per reward item
var stackRoubleBudget = roublesBudget / rewardNumItems;
var singleCartridgePrice = _handbookHelper.GetTemplatePrice(itemSelected.Id);
var singleCartridgePrice = handbookHelper.GetTemplatePrice(itemSelected.Id);
// Get a stack size of ammo that fits rouble budget
var stackSizeThatFitsBudget = Math.Round(stackRoubleBudget / singleCartridgePrice);
@@ -525,14 +510,14 @@ public class RepeatableQuestRewardGenerator(
)
{
var isEligibleForStackSizeIncrease =
_presetHelper.GetDefaultPresetOrItemPrice(item.Id) < maxRoublePriceToStack
&& !_itemHelper.IsOfBaseclasses(
presetHelper.GetDefaultPresetOrItemPrice(item.Id) < maxRoublePriceToStack
&& !itemHelper.IsOfBaseclasses(
item.Id,
[BaseClasses.WEAPON, BaseClasses.ARMORED_EQUIPMENT, BaseClasses.AMMO]
)
&& !_itemHelper.ItemRequiresSoftInserts(item.Id);
&& !itemHelper.ItemRequiresSoftInserts(item.Id);
return isEligibleForStackSizeIncrease && _randomUtil.GetChance100(randomChanceToPass);
return isEligibleForStackSizeIncrease && randomUtil.GetChance100(randomChanceToPass);
}
/// <summary>
@@ -542,7 +527,7 @@ public class RepeatableQuestRewardGenerator(
/// <returns> Matching stack size for the passed in items price </returns>
protected int GetRandomisedRewardItemStackSizeByPrice(TemplateItem item)
{
var rewardItemPrice = _presetHelper.GetDefaultPresetOrItemPrice(item.Id);
var rewardItemPrice = presetHelper.GetDefaultPresetOrItemPrice(item.Id);
// Define price tiers and corresponding stack size options
var priceTiers = new List<Tuple<int, List<int>?>>
@@ -559,7 +544,7 @@ public class RepeatableQuestRewardGenerator(
return 4; // Default to 2 if no tier matches
}
return _randomUtil.GetArrayValue(tier.Item2);
return randomUtil.GetArrayValue(tier.Item2);
}
/// <summary>
@@ -587,8 +572,8 @@ public class RepeatableQuestRewardGenerator(
if (rewardableItemPoolWithinBudget.Count == 0)
{
_logger.Warning(
_localisationService.GetText(
logger.Warning(
localisationService.GetText(
"repeatable-no_reward_item_found_in_price_range",
new { minPrice, roublesBudget }
)
@@ -596,7 +581,7 @@ public class RepeatableQuestRewardGenerator(
// In case we don't find any items in the price range
rewardableItemPoolWithinBudget = rewardableItemPool
.Where(x => _itemHelper.GetItemPrice(x.Id) < roublesBudget)
.Where(x => itemHelper.GetItemPrice(x.Id) < roublesBudget)
.ToList();
}
@@ -619,7 +604,7 @@ public class RepeatableQuestRewardGenerator(
return rewardItems
.Where(item =>
{
var itemPrice = _presetHelper.GetDefaultPresetOrItemPrice(item.Id);
var itemPrice = presetHelper.GetDefaultPresetOrItemPrice(item.Id);
return itemPrice < roublesBudget && itemPrice > minPrice;
})
.ToList();
@@ -638,9 +623,9 @@ public class RepeatableQuestRewardGenerator(
{
// Add a random default preset weapon as reward
var defaultPresetPool = new ExhaustableArray<Preset>(
_presetHelper.GetDefaultWeaponPresets().Values.ToList(),
_randomUtil,
_cloner
presetHelper.GetDefaultWeaponPresets().Values.ToList(),
randomUtil,
cloner
);
while (defaultPresetPool.HasValues())
@@ -655,11 +640,11 @@ public class RepeatableQuestRewardGenerator(
var tpls = randomPreset.Items.Select(item => item.Template).ToList();
// Does preset items fit our budget
var presetPrice = _itemHelper.GetItemAndChildrenPrice(tpls);
var presetPrice = itemHelper.GetItemAndChildrenPrice(tpls);
if (presetPrice <= roublesBudget)
{
_logger.Debug($"Added weapon: {tpls[0]}with price: {presetPrice}");
var chosenPreset = _cloner.Clone(randomPreset);
logger.Debug($"Added weapon: {tpls[0]}with price: {presetPrice}");
var chosenPreset = cloner.Clone(randomPreset);
return new KeyValuePair<Reward, double>(
GeneratePresetReward(
@@ -693,10 +678,10 @@ public class RepeatableQuestRewardGenerator(
bool foundInRaid = true
)
{
var id = _hashUtil.Generate();
var id = hashUtil.Generate();
var questRewardItem = new Reward
{
Id = _hashUtil.Generate(),
Id = hashUtil.Generate(),
Unknown = false,
GameMode = [],
AvailableInGameEditions = [],
@@ -710,18 +695,18 @@ public class RepeatableQuestRewardGenerator(
};
// Get presets root item
var rootItem = preset.FirstOrDefault(item => item.Template == tpl);
var rootItem = preset?.FirstOrDefault(item => item.Template == tpl);
if (rootItem is null)
{
_logger.Warning($"Root item of preset: {tpl} not found");
logger.Warning($"Root item of preset: {tpl} not found");
}
if (rootItem.Upd is not null)
if (rootItem?.Upd is not null)
{
rootItem.Upd.SpawnedInSession = foundInRaid;
}
questRewardItem.Items = _itemHelper.ReparentItemAndChildren(rootItem, preset);
questRewardItem.Items = itemHelper.ReparentItemAndChildren(rootItem, preset);
questRewardItem.Target = rootItem.Id; // Target property and root items id must match
return questRewardItem;
@@ -742,10 +727,10 @@ public class RepeatableQuestRewardGenerator(
bool foundInRaid = true
)
{
var id = _hashUtil.Generate();
var id = hashUtil.Generate();
var questRewardItem = new Reward
{
Id = _hashUtil.Generate(),
Id = hashUtil.Generate(),
Unknown = false,
GameMode = [],
AvailableInGameEditions = [],
@@ -780,7 +765,7 @@ public class RepeatableQuestRewardGenerator(
// Convert reward amount to Euros if necessary
var rewardAmountToGivePlayer =
currency == Money.EUROS
? _handbookHelper.FromRUB(rewardRoubles, Money.EUROS)
? handbookHelper.FromRUB(rewardRoubles, Money.EUROS)
: rewardRoubles;
// Get chosen currency + amount and return
@@ -803,12 +788,12 @@ public class RepeatableQuestRewardGenerator(
)
{
// Get an array of seasonal items that should not be shown right now as seasonal event is not active
var seasonalItems = _seasonalEventService.GetInactiveSeasonalEventItems();
var seasonalItems = seasonalEventService.GetInactiveSeasonalEventItems();
// Check for specific base classes which don't make sense as reward item
// also check if the price is greater than 0; there are some items whose price can not be found
// those are not in the game yet (e.g. AGS grenade launcher)
return _databaseService
return databaseService
.GetItems()
.Values.Where(itemTemplate =>
{
@@ -854,36 +839,36 @@ public class RepeatableQuestRewardGenerator(
)
{
// Return early if not valid item to give as reward
if (!_itemHelper.IsValidItem(tpl))
if (!itemHelper.IsValidItem(tpl))
{
return false;
}
// Check item is not blacklisted
if (
_itemFilterService.IsItemBlacklisted(tpl)
|| _itemFilterService.IsItemRewardBlacklisted(tpl)
itemFilterService.IsItemBlacklisted(tpl)
|| itemFilterService.IsItemRewardBlacklisted(tpl)
|| itemTplBlacklist.Contains(tpl)
|| _itemFilterService.IsItemBlacklisted(tpl)
|| itemFilterService.IsItemBlacklisted(tpl)
)
{
return false;
}
// Item has blacklisted base types
if (_itemHelper.IsOfBaseclasses(tpl, itemTypeBlacklist))
if (itemHelper.IsOfBaseclasses(tpl, itemTypeBlacklist))
{
return false;
}
// Skip boss items
if (_itemFilterService.IsBossItem(tpl))
if (itemFilterService.IsBossItem(tpl))
{
return false;
}
// Trader has specific item base types they can give as rewards to player
if (itemBaseWhitelist is not null && !_itemHelper.IsOfBaseclasses(tpl, itemBaseWhitelist))
if (itemBaseWhitelist is not null && !itemHelper.IsOfBaseclasses(tpl, itemBaseWhitelist))
{
return false;
}
@@ -8,23 +8,23 @@ public record QuestRewardValues
public Dictionary<string, object> ExtensionData { get; set; }
[JsonPropertyName("skillPointReward")]
public double? SkillPointReward { get; set; }
public required double SkillPointReward { get; set; }
[JsonPropertyName("skillRewardChance")]
public double? SkillRewardChance { get; set; }
public required double SkillRewardChance { get; set; }
[JsonPropertyName("rewardReputation")]
public double? RewardReputation { get; set; }
public required double RewardReputation { get; set; }
[JsonPropertyName("rewardNumItems")]
public int? RewardNumItems { get; set; }
public required int RewardNumItems { get; set; }
[JsonPropertyName("rewardRoubles")]
public double? RewardRoubles { get; set; }
public required double RewardRoubles { get; set; }
[JsonPropertyName("gpCoinRewardCount")]
public double? GpCoinRewardCount { get; set; }
public required double GpCoinRewardCount { get; set; }
[JsonPropertyName("rewardXP")]
public double? RewardXP { get; set; }
public required double RewardXP { get; set; }
}