Rework fence service to handle armor/weapons separately,
made config work with a weapon/equipment min/max value Improve price filtering system to work with weapons/equipment
This commit is contained in:
parent
3653ab9f83
commit
d36593ca57
@ -49,12 +49,19 @@
|
|||||||
"discountOptions": {
|
"discountOptions": {
|
||||||
"assortSize": 50,
|
"assortSize": 50,
|
||||||
"itemPriceMult": 0.8,
|
"itemPriceMult": 0.8,
|
||||||
"presetPriceMult": 1.3
|
"presetPriceMult": 1.2
|
||||||
},
|
},
|
||||||
"partialRefreshTimeSeconds": 240,
|
"partialRefreshTimeSeconds": 240,
|
||||||
"partialRefreshChangePercent": 15,
|
"partialRefreshChangePercent": 15,
|
||||||
"assortSize": 140,
|
"assortSize": 150,
|
||||||
"maxPresetsPercent": 10,
|
"weaponPresetMinMax": {
|
||||||
|
"min": 8,
|
||||||
|
"max": 15
|
||||||
|
},
|
||||||
|
"equipmentPresetMinMax": {
|
||||||
|
"min": 8,
|
||||||
|
"max": 15
|
||||||
|
},
|
||||||
"itemPriceMult": 1.2,
|
"itemPriceMult": 1.2,
|
||||||
"presetPriceMult": 2.0,
|
"presetPriceMult": 2.0,
|
||||||
"regenerateAssortsOnRefresh": false,
|
"regenerateAssortsOnRefresh": false,
|
||||||
@ -66,7 +73,7 @@
|
|||||||
"555ef6e44bdc2de9068b457e": 5,
|
"555ef6e44bdc2de9068b457e": 5,
|
||||||
"5a341c4086f77401f2541505": 5,
|
"5a341c4086f77401f2541505": 5,
|
||||||
"55818ad54bdc2ddc698b4569": 5,
|
"55818ad54bdc2ddc698b4569": 5,
|
||||||
"5448e53e4bdc2d60728b4567": 5,
|
"5448e53e4bdc2d60728b4567": 6,
|
||||||
"55818ac54bdc2d5b648b456e": 5,
|
"55818ac54bdc2d5b648b456e": 5,
|
||||||
"55818af64bdc2d5b648b4570": 5,
|
"55818af64bdc2d5b648b4570": 5,
|
||||||
"55818a304bdc2db5418b457d": 4,
|
"55818a304bdc2db5418b457d": 4,
|
||||||
@ -97,7 +104,7 @@
|
|||||||
"min": 35,
|
"min": 35,
|
||||||
"max": 60
|
"max": 60
|
||||||
},
|
},
|
||||||
"chancePlateExistsInArmorPercent": 40,
|
"chancePlateExistsInArmorPercent": 50,
|
||||||
"armorMaxDurabilityPercentMinMax": {
|
"armorMaxDurabilityPercentMinMax": {
|
||||||
"min": 35,
|
"min": 35,
|
||||||
"max": 60
|
"max": 60
|
||||||
@ -119,17 +126,29 @@
|
|||||||
"57864a66245977548f04a81f": 71000,
|
"57864a66245977548f04a81f": 71000,
|
||||||
"5448e54d4bdc2dcc718b4568": 200000,
|
"5448e54d4bdc2dcc718b4568": 200000,
|
||||||
"5a2c3a9486f774688b05e574": 70000,
|
"5a2c3a9486f774688b05e574": 70000,
|
||||||
"5a341c4086f77401f2541505": 125000,
|
|
||||||
"5448f3a64bdc2d60728b456a": 70000,
|
"5448f3a64bdc2d60728b456a": 70000,
|
||||||
"5447b6194bdc2d67278b4567": 500000,
|
"5447b6194bdc2d67278b4567": 500000,
|
||||||
"550aa4cd4bdc2dd8348b456c": 70000,
|
"550aa4cd4bdc2dd8348b456c": 70000,
|
||||||
"57864ee62459775490116fc1": 95000,
|
"57864ee62459775490116fc1": 95000,
|
||||||
"5448bc234bdc2d3c308b4569": 29000,
|
"5448bc234bdc2d3c308b4569": 29000,
|
||||||
|
|
||||||
|
"5447b6094bdc2dc3278b4567": 35009,
|
||||||
|
"5447bedf4bdc2d87278b4568": 27008,
|
||||||
|
"5447bed64bdc2d97278b4568": 27007,
|
||||||
|
"5447b5e04bdc2d62278b4567": 33006,
|
||||||
|
"5447b5fc4bdc2d87278b4567": 42005,
|
||||||
|
"5447b5f14bdc2d61278b4567": 44004,
|
||||||
|
"5447b5cf4bdc2d65278b4567": 30003,
|
||||||
|
"5447b6254bdc2dc3278b4568": 28002,
|
||||||
|
"5447e1d04bdc2dff2f8b4567": 19001,
|
||||||
|
|
||||||
"55818ae44bdc2dde698b456c": 45000,
|
"55818ae44bdc2dde698b456c": 45000,
|
||||||
"55818add4bdc2d5b648b456f": 35000,
|
"55818add4bdc2d5b648b456f": 35000,
|
||||||
"590c745b86f7743cc433c5f2": 64000,
|
"590c745b86f7743cc433c5f2": 64000,
|
||||||
"57864bb7245977548b3b66c2": 90000,
|
"57864bb7245977548b3b66c2": 85000,
|
||||||
"5c99f98d86f7745c314214b3": 15000
|
|
||||||
|
"5448e5284bdc2dcb718b4567": 40001,
|
||||||
|
"5a341c4086f77401f2541505": 105000
|
||||||
},
|
},
|
||||||
"presetSlotsToRemoveChancePercent": {
|
"presetSlotsToRemoveChancePercent": {
|
||||||
"mod_scope": 70,
|
"mod_scope": 70,
|
||||||
@ -264,4 +283,4 @@
|
|||||||
},
|
},
|
||||||
"btrDeliveryExpireHours": 240
|
"btrDeliveryExpireHours": 240
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { Category } from "@spt-aki/models/eft/common/tables/IHandbookBase";
|
import { Category } from "@spt-aki/models/eft/common/tables/IHandbookBase";
|
||||||
|
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||||
import { Money } from "@spt-aki/models/enums/Money";
|
import { Money } from "@spt-aki/models/enums/Money";
|
||||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||||
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||||
@ -102,6 +103,17 @@ export class HandbookHelper
|
|||||||
return handbookItem.Price;
|
return handbookItem.Price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getTemplatePriceForItems(items: Item[]): number
|
||||||
|
{
|
||||||
|
let total = 0;
|
||||||
|
for (const item of items)
|
||||||
|
{
|
||||||
|
total += this.getTemplatePrice(item._tpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all items in template with the given parent category
|
* Get all items in template with the given parent category
|
||||||
* @param parentId
|
* @param parentId
|
||||||
|
@ -26,7 +26,8 @@ export interface FenceConfig
|
|||||||
partialRefreshTimeSeconds: number;
|
partialRefreshTimeSeconds: number;
|
||||||
partialRefreshChangePercent: number;
|
partialRefreshChangePercent: number;
|
||||||
assortSize: number;
|
assortSize: number;
|
||||||
maxPresetsPercent: number;
|
weaponPresetMinMax: MinMax;
|
||||||
|
equipmentPresetMinMax: MinMax;
|
||||||
itemPriceMult: number;
|
itemPriceMult: number;
|
||||||
presetPriceMult: number;
|
presetPriceMult: number;
|
||||||
armorMaxDurabilityPercentMinMax: MinMax;
|
armorMaxDurabilityPercentMinMax: MinMax;
|
||||||
|
@ -422,9 +422,15 @@ export class FenceService
|
|||||||
this.addItemAssorts(assortCount, assorts, baseFenceAssort, itemTypeCounts, loyaltyLevel);
|
this.addItemAssorts(assortCount, assorts, baseFenceAssort, itemTypeCounts, loyaltyLevel);
|
||||||
|
|
||||||
// Add presets
|
// Add presets
|
||||||
const maxPresetCount = Math.round(assortCount * (this.traderConfig.fence.maxPresetsPercent / 100));
|
const weaponPresetCount = this.randomUtil.getInt(
|
||||||
const randomisedPresetCount = this.randomUtil.getInt(0, maxPresetCount);
|
this.traderConfig.fence.weaponPresetMinMax.min,
|
||||||
this.addPresetsToAssort(randomisedPresetCount, assorts, baseFenceAssort, loyaltyLevel);
|
this.traderConfig.fence.weaponPresetMinMax.max,
|
||||||
|
);
|
||||||
|
const equipmentPresetCount = this.randomUtil.getInt(
|
||||||
|
this.traderConfig.fence.equipmentPresetMinMax.min,
|
||||||
|
this.traderConfig.fence.equipmentPresetMinMax.max,
|
||||||
|
);
|
||||||
|
this.addPresetsToAssort(weaponPresetCount, equipmentPresetCount, assorts, baseFenceAssort, loyaltyLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected addItemAssorts(
|
protected addItemAssorts(
|
||||||
@ -509,39 +515,37 @@ export class FenceService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Find presets in base fence assort and add desired number to 'assorts' parameter
|
* Find presets in base fence assort and add desired number to 'assorts' parameter
|
||||||
* @param desiredPresetCount
|
* @param desiredWeaponPresetsCount
|
||||||
* @param assorts
|
* @param assorts
|
||||||
* @param baseFenceAssort
|
* @param baseFenceAssort
|
||||||
* @param loyaltyLevel Which loyalty level is required to see/buy item
|
* @param loyaltyLevel Which loyalty level is required to see/buy item
|
||||||
*/
|
*/
|
||||||
protected addPresetsToAssort(
|
protected addPresetsToAssort(
|
||||||
desiredPresetCount: number,
|
desiredWeaponPresetsCount: number,
|
||||||
|
desiredEquipmentPresetsCount: number,
|
||||||
assorts: ITraderAssort,
|
assorts: ITraderAssort,
|
||||||
baseFenceAssort: ITraderAssort,
|
baseFenceAssort: ITraderAssort,
|
||||||
loyaltyLevel: number,
|
loyaltyLevel: number,
|
||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
let presetsAddedCount = 0;
|
let weaponPresetsAddedCount = 0;
|
||||||
if (desiredPresetCount <= 0)
|
if (desiredWeaponPresetsCount <= 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const presetRootItems = baseFenceAssort.items.filter((item) => item.upd?.sptPresetId);
|
const weaponPresetRootItems = baseFenceAssort.items.filter((item) =>
|
||||||
while (presetsAddedCount < desiredPresetCount)
|
item.upd?.sptPresetId && this.itemHelper.isOfBaseclass(item._tpl, BaseClasses.WEAPON)
|
||||||
|
);
|
||||||
|
while (weaponPresetsAddedCount < desiredWeaponPresetsCount)
|
||||||
{
|
{
|
||||||
const randomPresetRoot = this.randomUtil.getArrayValue(presetRootItems);
|
const randomPresetRoot = this.randomUtil.getArrayValue(weaponPresetRootItems);
|
||||||
const rootItemDb = this.itemHelper.getItem(randomPresetRoot._tpl)[1];
|
const rootItemDb = this.itemHelper.getItem(randomPresetRoot._tpl)[1];
|
||||||
|
|
||||||
const presetWithChildrenClone = this.jsonUtil.clone(
|
const presetWithChildrenClone = this.jsonUtil.clone(
|
||||||
this.itemHelper.findAndReturnChildrenAsItems(baseFenceAssort.items, randomPresetRoot._id),
|
this.itemHelper.findAndReturnChildrenAsItems(baseFenceAssort.items, randomPresetRoot._id),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Need to add mods to armors so they dont show as red in the trade screen
|
|
||||||
if (this.itemHelper.itemRequiresSoftInserts(randomPresetRoot._tpl))
|
|
||||||
{
|
|
||||||
this.randomiseArmorModDurability(presetWithChildrenClone, rootItemDb);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.itemHelper.isOfBaseclass(rootItemDb._id, BaseClasses.WEAPON))
|
if (this.itemHelper.isOfBaseclass(rootItemDb._id, BaseClasses.WEAPON))
|
||||||
{
|
{
|
||||||
this.randomiseItemUpdProperties(rootItemDb, presetWithChildrenClone[0]);
|
this.randomiseItemUpdProperties(rootItemDb, presetWithChildrenClone[0]);
|
||||||
@ -549,6 +553,26 @@ export class FenceService
|
|||||||
|
|
||||||
this.removeRandomModsOfItem(presetWithChildrenClone);
|
this.removeRandomModsOfItem(presetWithChildrenClone);
|
||||||
|
|
||||||
|
// Check chosen item is below price cap
|
||||||
|
const priceLimitRouble = this.traderConfig.fence.itemCategoryRoublePriceLimit[rootItemDb._parent];
|
||||||
|
if (priceLimitRouble)
|
||||||
|
{
|
||||||
|
if (this.handbookHelper.getTemplatePriceForItems(presetWithChildrenClone) > priceLimitRouble)
|
||||||
|
{
|
||||||
|
// Too expensive, try again
|
||||||
|
this.logger.warning(
|
||||||
|
`Blocked ${rootItemDb._name}, price: ${
|
||||||
|
this.handbookHelper.getTemplatePriceForItems(presetWithChildrenClone)
|
||||||
|
} limit: ${priceLimitRouble}`,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.logger.warning(`No limit ${rootItemDb._name} ${rootItemDb._parent}`);
|
||||||
|
}
|
||||||
|
|
||||||
// MUST randomise Ids as its possible to add the same base fence assort twice = duplicate IDs = dead client
|
// MUST randomise Ids as its possible to add the same base fence assort twice = duplicate IDs = dead client
|
||||||
this.itemHelper.reparentItemAndChildren(presetWithChildrenClone[0], presetWithChildrenClone);
|
this.itemHelper.reparentItemAndChildren(presetWithChildrenClone[0], presetWithChildrenClone);
|
||||||
this.itemHelper.remapRootItemId(presetWithChildrenClone);
|
this.itemHelper.remapRootItemId(presetWithChildrenClone);
|
||||||
@ -562,7 +586,69 @@ export class FenceService
|
|||||||
assorts.barter_scheme[presetWithChildrenClone[0]._id] = baseFenceAssort.barter_scheme[randomPresetRoot._id];
|
assorts.barter_scheme[presetWithChildrenClone[0]._id] = baseFenceAssort.barter_scheme[randomPresetRoot._id];
|
||||||
assorts.loyal_level_items[presetWithChildrenClone[0]._id] = loyaltyLevel;
|
assorts.loyal_level_items[presetWithChildrenClone[0]._id] = loyaltyLevel;
|
||||||
|
|
||||||
presetsAddedCount++;
|
weaponPresetsAddedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
let equipmentPresetsAddedCount = 0;
|
||||||
|
if (desiredEquipmentPresetsCount <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const equipmentPresetRootItems = baseFenceAssort.items.filter((item) =>
|
||||||
|
item.upd?.sptPresetId && this.itemHelper.armorItemCanHoldMods(item._tpl)
|
||||||
|
);
|
||||||
|
while (equipmentPresetsAddedCount < desiredEquipmentPresetsCount)
|
||||||
|
{
|
||||||
|
const randomPresetRoot = this.randomUtil.getArrayValue(equipmentPresetRootItems);
|
||||||
|
const rootItemDb = this.itemHelper.getItem(randomPresetRoot._tpl)[1];
|
||||||
|
|
||||||
|
const presetWithChildrenClone = this.jsonUtil.clone(
|
||||||
|
this.itemHelper.findAndReturnChildrenAsItems(baseFenceAssort.items, randomPresetRoot._id),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Need to add mods to armors so they dont show as red in the trade screen
|
||||||
|
if (this.itemHelper.itemRequiresSoftInserts(randomPresetRoot._tpl))
|
||||||
|
{
|
||||||
|
this.randomiseArmorModDurability(presetWithChildrenClone, rootItemDb);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeRandomModsOfItem(presetWithChildrenClone);
|
||||||
|
|
||||||
|
// Check chosen item is below price cap
|
||||||
|
const priceLimitRouble = this.traderConfig.fence.itemCategoryRoublePriceLimit[rootItemDb._parent];
|
||||||
|
if (priceLimitRouble)
|
||||||
|
{
|
||||||
|
if (this.handbookHelper.getTemplatePriceForItems(presetWithChildrenClone) > priceLimitRouble)
|
||||||
|
{
|
||||||
|
// Too expensive, try again
|
||||||
|
this.logger.warning(
|
||||||
|
`Blocked ${rootItemDb._name}, price: ${
|
||||||
|
this.handbookHelper.getTemplatePriceForItems(presetWithChildrenClone)
|
||||||
|
} limit: ${priceLimitRouble}`,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.logger.warning(`No limit ${rootItemDb._name} ${rootItemDb._parent}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MUST randomise Ids as its possible to add the same base fence assort twice = duplicate IDs = dead client
|
||||||
|
this.itemHelper.reparentItemAndChildren(presetWithChildrenClone[0], presetWithChildrenClone);
|
||||||
|
this.itemHelper.remapRootItemId(presetWithChildrenClone);
|
||||||
|
|
||||||
|
// Remapping IDs causes parentid to be altered
|
||||||
|
presetWithChildrenClone[0].parentId = "hideout";
|
||||||
|
|
||||||
|
assorts.items.push(...presetWithChildrenClone);
|
||||||
|
|
||||||
|
// Must be careful to use correct id as the item has had its IDs regenerated
|
||||||
|
assorts.barter_scheme[presetWithChildrenClone[0]._id] = baseFenceAssort.barter_scheme[randomPresetRoot._id];
|
||||||
|
assorts.loyal_level_items[presetWithChildrenClone[0]._id] = loyaltyLevel;
|
||||||
|
|
||||||
|
equipmentPresetsAddedCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user