Fix daily reward budget not using preset prices for some items (!256)
- Switch item cost calculation to use a new helper that checks for a preset first, to more accurately keep track of the budget - Subtract weapon price from reward budget - Decrement reward counter for skipped ammo - Add a new helper for filtering the reward pool by budget, so it's consistent in the two places it's done - Add a metric boatload of debug output for daily generation Co-authored-by: DrakiaXYZ <565558+TheDgtl@users.noreply.github.com> Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/256 Co-authored-by: DrakiaXYZ <drakiaxyz@noreply.dev.sp-tarkov.com> Co-committed-by: DrakiaXYZ <drakiaxyz@noreply.dev.sp-tarkov.com>
This commit is contained in:
parent
561c5a7ffc
commit
15257ea263
@ -116,7 +116,10 @@ export class RepeatableQuestRewardGenerator
|
||||
|
||||
// Possible improvement -> draw trader-specific items e.g. with this.itemHelper.isOfBaseclass(val._id, ItemHelper.BASECLASS.FoodDrink)
|
||||
let roublesBudget = rewardRoubles;
|
||||
let rewardItemPool = this.chooseRewardItemsWithinBudget(repeatableConfig, roublesBudget, traderId);
|
||||
const rewardItemPool = this.chooseRewardItemsWithinBudget(repeatableConfig, roublesBudget, traderId);
|
||||
this.logger.debug(
|
||||
`Generating daily quest for ${traderId} with budget ${roublesBudget} for ${rewardNumItems} items`,
|
||||
);
|
||||
|
||||
const rewards: IQuestRewards = { Started: [], Success: [], Fail: [] };
|
||||
|
||||
@ -152,6 +155,8 @@ export class RepeatableQuestRewardGenerator
|
||||
const presetPrice = this.itemHelper.getItemAndChildrenPrice(tpls);
|
||||
if (presetPrice <= roublesBudget)
|
||||
{
|
||||
this.logger.debug(` Added weapon ${tpls[0]} with price ${presetPrice}`);
|
||||
roublesBudget -= presetPrice;
|
||||
chosenPreset = this.jsonUtil.clone(randomPreset);
|
||||
break;
|
||||
}
|
||||
@ -179,6 +184,7 @@ export class RepeatableQuestRewardGenerator
|
||||
// Don't reward ammo that stacks to less than what's defined in config
|
||||
if (itemSelected._props.StackMaxSize < repeatableConfig.rewardAmmoStackMinSize)
|
||||
{
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -199,18 +205,17 @@ export class RepeatableQuestRewardGenerator
|
||||
rewards.Success.push(this.generateRewardItem(itemSelected._id, rewardItemStackCount, rewardIndex));
|
||||
rewardIndex++;
|
||||
|
||||
const itemCost = this.itemHelper.getStaticItemPrice(itemSelected._id);
|
||||
const itemCost = this.presetHelper.getDefaultPresetOrItemPrice(itemSelected._id);
|
||||
roublesBudget -= rewardItemStackCount * itemCost;
|
||||
this.logger.debug(` Added item ${itemSelected._id} with price ${rewardItemStackCount * itemCost}`);
|
||||
|
||||
// If we still have budget narrow down possible items
|
||||
if (roublesBudget > 0)
|
||||
{
|
||||
// Filter possible reward items to only items with a price below the remaining budget
|
||||
rewardItemPool = rewardItemPool.filter((x) =>
|
||||
this.itemHelper.getStaticItemPrice(x._id) < roublesBudget
|
||||
);
|
||||
if (rewardItemPool.length === 0)
|
||||
if (!this.filterRewardPoolWithinBudget(rewardItemPool, roublesBudget, 0))
|
||||
{
|
||||
this.logger.debug(` Reward pool empty with ${roublesBudget} remaining`);
|
||||
break; // No reward items left, exit
|
||||
}
|
||||
}
|
||||
@ -232,23 +237,49 @@ export class RepeatableQuestRewardGenerator
|
||||
};
|
||||
rewards.Success.push(reward);
|
||||
rewardIndex++;
|
||||
|
||||
this.logger.debug(` Adding ${rewardReputation} trader reputation reward`);
|
||||
}
|
||||
|
||||
// Chance of adding skill reward
|
||||
if (this.randomUtil.getChance100(skillRewardChance * 100))
|
||||
{
|
||||
const targetSkill = this.randomUtil.getArrayValue(questConfig.possibleSkillRewards);
|
||||
const reward: IQuestReward = {
|
||||
target: this.randomUtil.getArrayValue(questConfig.possibleSkillRewards),
|
||||
target: targetSkill,
|
||||
value: skillPointReward,
|
||||
type: QuestRewardType.SKILL,
|
||||
index: rewardIndex,
|
||||
};
|
||||
rewards.Success.push(reward);
|
||||
|
||||
this.logger.debug(` Adding ${skillPointReward} skill points to ${targetSkill}`);
|
||||
}
|
||||
|
||||
return rewards;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rewardItems List of reward items to filter
|
||||
* @param roublesBudget The budget remaining for rewards
|
||||
* @param minPrice The minimum priced item to include
|
||||
* @returns True if any items remain in `rewardItems`, false otherwise
|
||||
*/
|
||||
protected filterRewardPoolWithinBudget(
|
||||
rewardItems: ITemplateItem[],
|
||||
roublesBudget: number,
|
||||
minPrice: number,
|
||||
): boolean
|
||||
{
|
||||
rewardItems.filter((item) =>
|
||||
{
|
||||
const itemPrice = this.presetHelper.getDefaultPresetOrItemPrice(item._id);
|
||||
return itemPrice < roublesBudget && itemPrice > minPrice;
|
||||
});
|
||||
|
||||
return (rewardItems.length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a randomised number a reward items stack size should be based on its handbook price
|
||||
* @param item Reward item to get stack size for
|
||||
@ -256,7 +287,7 @@ export class RepeatableQuestRewardGenerator
|
||||
*/
|
||||
protected getRandomisedRewardItemStackSizeByPrice(item: ITemplateItem): number
|
||||
{
|
||||
const rewardItemPrice = this.itemHelper.getStaticItemPrice(item._id);
|
||||
const rewardItemPrice = this.presetHelper.getDefaultPresetOrItemPrice(item._id);
|
||||
if (rewardItemPrice < 3000)
|
||||
{
|
||||
return this.randomUtil.getArrayValue([2, 3, 4]);
|
||||
@ -278,7 +309,7 @@ export class RepeatableQuestRewardGenerator
|
||||
*/
|
||||
protected canIncreaseRewardItemStackSize(item: ITemplateItem, maxRoublePriceToStack: number): boolean
|
||||
{
|
||||
return this.itemHelper.getStaticItemPrice(item._id) < maxRoublePriceToStack
|
||||
return this.presetHelper.getDefaultPresetOrItemPrice(item._id) < maxRoublePriceToStack
|
||||
&& !this.itemHelper.isOfBaseclasses(item._id, [
|
||||
BaseClasses.WEAPON,
|
||||
BaseClasses.ARMORED_EQUIPMENT,
|
||||
@ -324,21 +355,8 @@ export class RepeatableQuestRewardGenerator
|
||||
const rewardableItemPool = this.getRewardableItems(repeatableConfig, traderId);
|
||||
const minPrice = Math.min(25000, 0.5 * roublesBudget);
|
||||
|
||||
let rewardableItemPoolWithinBudget = rewardableItemPool.filter((item) =>
|
||||
{
|
||||
// Get default preset if it exists
|
||||
const defaultPreset = this.presetHelper.getDefaultPreset(item[0]);
|
||||
|
||||
// Bundle up tpls we want price for
|
||||
const tpls = defaultPreset ? defaultPreset._items.map((item) => item._tpl) : [item[0]];
|
||||
|
||||
// Get price of tpls
|
||||
const itemPrice = this.itemHelper.getItemAndChildrenPrice(tpls);
|
||||
|
||||
return itemPrice < roublesBudget && itemPrice > minPrice;
|
||||
}).map((x) => x[1]);
|
||||
|
||||
if (rewardableItemPoolWithinBudget.length === 0)
|
||||
let rewardableItemPoolWithinBudget = rewardableItemPool.map((x) => x[1]);
|
||||
if (!this.filterRewardPoolWithinBudget(rewardableItemPoolWithinBudget, roublesBudget, minPrice))
|
||||
{
|
||||
this.logger.warning(
|
||||
this.localisationService.getText("repeatable-no_reward_item_found_in_price_range", {
|
||||
|
@ -160,4 +160,21 @@ export class PresetHelper
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the price of the preset for the given item tpl, or for the tpl itself if no preset exists
|
||||
* @param tpl The item template to get the price of
|
||||
* @returns The price of the given item preset, or base item if no preset exists
|
||||
*/
|
||||
public getDefaultPresetOrItemPrice(tpl: string): number
|
||||
{
|
||||
// Get default preset if it exists
|
||||
const defaultPreset = this.getDefaultPreset(tpl);
|
||||
|
||||
// Bundle up tpls we want price for
|
||||
const tpls = defaultPreset ? defaultPreset._items.map((item) => item._tpl) : [tpl];
|
||||
|
||||
// Get price of tpls
|
||||
return this.itemHelper.getItemAndChildrenPrice(tpls);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user