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