Moe majority of assort generation from FenceService
into FenceBaseAssortGenerator
Generate an items children and store in fence assort base Better handle presets Fix `removeRandomItemFromAssorts()` not removing all of an items mods from memory Correctly calculate an items price including its children
This commit is contained in:
parent
8b2fa7c8dd
commit
42b915990e
@ -2,6 +2,7 @@ import { inject, injectable } from "tsyringe";
|
||||
|
||||
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
|
||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
||||
import { IBarterScheme } from "@spt-aki/models/eft/common/tables/ITrader";
|
||||
@ -14,6 +15,8 @@ import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||
import { ItemFilterService } from "@spt-aki/services/ItemFilterService";
|
||||
import { SeasonalEventService } from "@spt-aki/services/SeasonalEventService";
|
||||
import { HashUtil } from "@spt-aki/utils/HashUtil";
|
||||
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||
|
||||
@injectable()
|
||||
export class FenceBaseAssortGenerator
|
||||
@ -22,9 +25,12 @@ export class FenceBaseAssortGenerator
|
||||
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("HandbookHelper") protected handbookHelper: HandbookHelper,
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
@inject("PresetHelper") protected presetHelper: PresetHelper,
|
||||
@inject("ItemFilterService") protected itemFilterService: ItemFilterService,
|
||||
@inject("SeasonalEventService") protected seasonalEventService: SeasonalEventService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@ -39,29 +45,27 @@ export class FenceBaseAssortGenerator
|
||||
public generateFenceBaseAssorts(): void
|
||||
{
|
||||
const blockedSeasonalItems = this.seasonalEventService.getInactiveSeasonalEventItems();
|
||||
|
||||
const baseFenceAssort = this.databaseServer.getTables().traders[Traders.FENCE].assort;
|
||||
|
||||
const dbItems = Object.values(this.databaseServer.getTables().templates.items);
|
||||
for (const item of dbItems.filter((x) => this.isValidFenceItem(x)))
|
||||
for (const rootItemDb of this.itemHelper.getItems().filter((item) => this.isValidFenceItem(item)))
|
||||
{
|
||||
// Skip blacklisted items
|
||||
if (this.itemFilterService.isItemBlacklisted(item._id))
|
||||
if (this.itemFilterService.isItemBlacklisted(rootItemDb._id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.itemHelper.isValidItem(item._id))
|
||||
// Invalid
|
||||
if (!this.itemHelper.isValidItem(rootItemDb._id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip items on fence ignore list
|
||||
// Item base type blacklisted
|
||||
if (this.traderConfig.fence.blacklist.length > 0)
|
||||
{
|
||||
if (
|
||||
this.traderConfig.fence.blacklist.includes(item._id)
|
||||
|| this.itemHelper.isOfBaseclasses(item._id, this.traderConfig.fence.blacklist)
|
||||
if (this.traderConfig.fence.blacklist.includes(rootItemDb._id)
|
||||
|| this.itemHelper.isOfBaseclasses(rootItemDb._id, this.traderConfig.fence.blacklist)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
@ -69,37 +73,200 @@ export class FenceBaseAssortGenerator
|
||||
}
|
||||
|
||||
// Skip seasonal event items when not in seasonal event
|
||||
if (this.traderConfig.fence.blacklistSeasonalItems && blockedSeasonalItems.includes(item._id))
|
||||
if (this.traderConfig.fence.blacklistSeasonalItems && blockedSeasonalItems.includes(rootItemDb._id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create barter scheme object
|
||||
// Create item object in array
|
||||
const itemWithChildrenToAdd: Item[] = [{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: rootItemDb._id,
|
||||
parentId: "hideout",
|
||||
slotId: "hideout",
|
||||
upd: { StackObjectsCount: 9999999, UnlimitedCount: true },
|
||||
}];
|
||||
|
||||
// Need to add mods to armors so they dont show as red in the trade screen
|
||||
let price = this.handbookHelper.getTemplatePrice(rootItemDb._id);
|
||||
if (this.itemHelper.itemRequiresSoftInserts(rootItemDb._id))
|
||||
{
|
||||
this.addChildrenToArmorModSlots(itemWithChildrenToAdd, rootItemDb);
|
||||
price = this.getHandbookItemPriceWithChildren(itemWithChildrenToAdd);
|
||||
}
|
||||
|
||||
// Ensure IDs are unique
|
||||
this.itemHelper.remapRootItemId(itemWithChildrenToAdd);
|
||||
if (itemWithChildrenToAdd.length > 1)
|
||||
{
|
||||
this.itemHelper.reparentItemAndChildren(itemWithChildrenToAdd[0], itemWithChildrenToAdd);
|
||||
}
|
||||
|
||||
// Create barter scheme (price)
|
||||
const barterSchemeToAdd: IBarterScheme = {
|
||||
count: Math.round(
|
||||
this.handbookHelper.getTemplatePrice(item._id) * this.traderConfig.fence.itemPriceMult,
|
||||
this.handbookHelper.getTemplatePrice(rootItemDb._id) * this.traderConfig.fence.itemPriceMult,
|
||||
),
|
||||
_tpl: Money.ROUBLES,
|
||||
};
|
||||
|
||||
// Add barter data to base
|
||||
baseFenceAssort.barter_scheme[item._id] = [[barterSchemeToAdd]];
|
||||
|
||||
// Create item object
|
||||
const itemToAdd: Item = {
|
||||
_id: item._id,
|
||||
_tpl: item._id,
|
||||
parentId: "hideout",
|
||||
slotId: "hideout",
|
||||
upd: { StackObjectsCount: 9999999, UnlimitedCount: true },
|
||||
};
|
||||
baseFenceAssort.barter_scheme[itemWithChildrenToAdd[0]._id] = [[barterSchemeToAdd]];
|
||||
|
||||
// Add item to base
|
||||
baseFenceAssort.items.push(itemToAdd);
|
||||
baseFenceAssort.items.push(...itemWithChildrenToAdd);
|
||||
|
||||
// Add loyalty data to base
|
||||
baseFenceAssort.loyal_level_items[item._id] = 1;
|
||||
baseFenceAssort.loyal_level_items[itemWithChildrenToAdd[0]._id] = 1;
|
||||
}
|
||||
|
||||
// Add all default presets to base fence assort
|
||||
const defaultPresets = Object.values(this.presetHelper.getDefaultPresets());
|
||||
for (const defaultPreset of defaultPresets)
|
||||
{
|
||||
// Skip presets we've already added
|
||||
if (baseFenceAssort.items.some((item) => item.upd && item.upd.sptPresetId === defaultPreset._id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Construct preset + mods
|
||||
const presetAndMods: Item[] = this.itemHelper.replaceIDs(
|
||||
null,
|
||||
this.jsonUtil.clone(defaultPreset._items),
|
||||
);
|
||||
|
||||
for (let i = 0; i < presetAndMods.length; i++)
|
||||
{
|
||||
const mod = presetAndMods[i];
|
||||
|
||||
// Build root Item info
|
||||
if (!("parentId" in mod))
|
||||
{
|
||||
mod._id = presetAndMods[0]._id;
|
||||
mod.parentId = "hideout";
|
||||
mod.slotId = "hideout";
|
||||
mod.upd = {
|
||||
UnlimitedCount: false,
|
||||
StackObjectsCount: 1,
|
||||
BuyRestrictionCurrent: 0,
|
||||
sptPresetId: defaultPreset._id, // Store preset id here so we can check it later to prevent preset dupes
|
||||
};
|
||||
|
||||
// Updated root item, exit loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const presetDbItem = this.itemHelper.getItem(presetAndMods[0]._tpl)[1];
|
||||
|
||||
// Add constructed preset to assorts
|
||||
baseFenceAssort.items.push(...presetAndMods);
|
||||
|
||||
// Calculate preset price
|
||||
let rub = 0;
|
||||
for (const it of presetAndMods)
|
||||
{
|
||||
rub += this.handbookHelper.getTemplatePrice(it._tpl);
|
||||
}
|
||||
|
||||
// Multiply weapon+mods rouble price by multipler in config
|
||||
baseFenceAssort.barter_scheme[presetAndMods[0]._id] = [[]];
|
||||
baseFenceAssort.barter_scheme[presetAndMods[0]._id][0][0] = { _tpl: Money.ROUBLES, count: Math.round(rub) };
|
||||
|
||||
baseFenceAssort.loyal_level_items[presetAndMods[0]._id] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add soft inserts + armor plates to an armor
|
||||
* @param armor Armor item array to add mods into
|
||||
* @param itemDbDetails Armor items db template
|
||||
*/
|
||||
protected addChildrenToArmorModSlots(armor: Item[], itemDbDetails: ITemplateItem): void
|
||||
{
|
||||
// Armor has no mods, make no additions
|
||||
const hasMods = itemDbDetails._props.Slots.length > 0;
|
||||
if (!hasMods)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for and add required soft inserts to armors
|
||||
const requiredSlots = itemDbDetails._props.Slots.filter(slot => slot._required);
|
||||
const hasRequiredSlots = requiredSlots.length > 0;
|
||||
if (hasRequiredSlots)
|
||||
{
|
||||
for (const requiredSlot of requiredSlots)
|
||||
{
|
||||
const modItemDbDetails = this.itemHelper.getItem(requiredSlot._props.filters[0].Plate)[1];
|
||||
const plateTpl = requiredSlot._props.filters[0].Plate; // `Plate` property appears to be the 'default' item for slot
|
||||
if (plateTpl === "")
|
||||
{
|
||||
// Some bsg plate properties are empty, skip mod
|
||||
continue;
|
||||
}
|
||||
|
||||
const mod: Item = {
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: plateTpl,
|
||||
parentId: armor[0]._id,
|
||||
slotId: requiredSlot._name,
|
||||
upd: {
|
||||
Repairable: {
|
||||
Durability: modItemDbDetails._props.MaxDurability,
|
||||
MaxDurability: modItemDbDetails._props.MaxDurability
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
armor.push(mod);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for and add plate items
|
||||
const plateSlots = itemDbDetails._props.Slots.filter(slot => this.itemHelper.isRemovablePlateSlot(slot._name));
|
||||
if (plateSlots.length > 0)
|
||||
{
|
||||
for (const plateSlot of plateSlots)
|
||||
{
|
||||
const plateTpl = plateSlot._props.filters[0].Plate
|
||||
if (!plateTpl)
|
||||
{
|
||||
// Bsg data lacks a default plate, skip adding mod
|
||||
continue;
|
||||
}
|
||||
const modItemDbDetails = this.itemHelper.getItem(plateTpl)[1];
|
||||
armor.push({
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: plateSlot._props.filters[0].Plate, // `Plate` property appears to be the 'default' item for slot
|
||||
parentId: armor[0]._id,
|
||||
slotId: plateSlot._name,
|
||||
upd: {
|
||||
Repairable: {
|
||||
Durability: modItemDbDetails._props.MaxDurability,
|
||||
MaxDurability: modItemDbDetails._props.MaxDurability
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate and return the price of an item and its child mods
|
||||
* @param itemWithChildren Item + mods to calcualte price of
|
||||
* @returns price
|
||||
*/
|
||||
protected getHandbookItemPriceWithChildren(itemWithChildren: Item[]): number
|
||||
{
|
||||
let price = 0;
|
||||
for (const item of itemWithChildren)
|
||||
{
|
||||
price += this.handbookHelper.getTemplatePrice(item._tpl);
|
||||
}
|
||||
|
||||
return price;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -507,7 +507,8 @@ export class ItemHelper
|
||||
|
||||
for (const itemFromAssort of assort)
|
||||
{
|
||||
if (itemFromAssort.parentId === itemIdToFind && !list.find((item) => itemFromAssort._id === item._id))
|
||||
if (itemFromAssort.parentId === itemIdToFind
|
||||
&& !list.find((item) => itemFromAssort._id === item._id))
|
||||
{
|
||||
list.push(itemFromAssort);
|
||||
list = list.concat(this.findAndReturnChildrenByAssort(itemFromAssort._id, assort));
|
||||
|
@ -114,7 +114,7 @@ export class FenceService
|
||||
|
||||
/**
|
||||
* Adjust all items contained inside an assort by a multiplier
|
||||
* @param assort Assort that contains items with prices to adjust
|
||||
* @param assort (clone)Assort that contains items with prices to adjust
|
||||
* @param itemMultipler multipler to use on items
|
||||
* @param presetMultiplier preset multipler to use on presets
|
||||
*/
|
||||
@ -325,12 +325,16 @@ export class FenceService
|
||||
itemToRemove = this.randomUtil.getArrayValue(assort.items);
|
||||
}
|
||||
|
||||
const indexOfItemToRemove = assort.items.findIndex((x) => x._id === itemToRemove._id);
|
||||
const indexOfItemToRemove = assort.items.findIndex((item) => item._id === itemToRemove._id);
|
||||
assort.items.splice(indexOfItemToRemove, 1);
|
||||
|
||||
// Clean up any mods if item removed was a weapon
|
||||
// TODO: also check for mods attached down the item chain
|
||||
assort.items = assort.items.filter((x) => x.parentId !== itemToRemove._id);
|
||||
const itemWithChildren = this.itemHelper.findAndReturnChildrenAsItems(assort.items, itemToRemove._id);
|
||||
for (const itemToDelete of itemWithChildren)
|
||||
{
|
||||
// Delete item from assort items array
|
||||
assort.items.splice(assort.items.indexOf(itemToDelete), 1);
|
||||
}
|
||||
|
||||
delete assort.barter_scheme[itemToRemove._id];
|
||||
delete assort.loyal_level_items[itemToRemove._id];
|
||||
@ -402,22 +406,50 @@ export class FenceService
|
||||
*/
|
||||
protected createAssorts(assortCount: number, assorts: ITraderAssort, loyaltyLevel: number): void
|
||||
{
|
||||
const fenceAssort = this.databaseServer.getTables().traders[Traders.FENCE].assort;
|
||||
const fenceAssortIds = Object.keys(fenceAssort.loyal_level_items);
|
||||
const baseFenceAssort = this.databaseServer.getTables().traders[Traders.FENCE].assort;
|
||||
const itemTypeCounts = this.initItemLimitCounter(this.traderConfig.fence.itemTypeLimits);
|
||||
|
||||
this.addItemAssorts(assortCount, fenceAssortIds, assorts, fenceAssort, itemTypeCounts, loyaltyLevel);
|
||||
this.addItemAssorts(assortCount, assorts, baseFenceAssort, itemTypeCounts, loyaltyLevel);
|
||||
|
||||
// Add presets
|
||||
const maxPresetCount = Math.round(assortCount * (this.traderConfig.fence.maxPresetsPercent / 100));
|
||||
const randomisedPresetCount = this.randomUtil.getInt(0, maxPresetCount);
|
||||
const defaultPresets = this.presetHelper.getDefaultPresets();
|
||||
this.addPresets(randomisedPresetCount, defaultPresets, assorts, loyaltyLevel);
|
||||
this.addPresetsToAssort(randomisedPresetCount, assorts, baseFenceAssort);
|
||||
}
|
||||
|
||||
protected addPresetsToAssort(desiredPresetCount: number, assorts: ITraderAssort, baseFenceAssort: ITraderAssort): void
|
||||
{
|
||||
let presetsAddedCount = 0;
|
||||
if (desiredPresetCount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const presetRootItems = baseFenceAssort.items.filter(item => item.upd?.sptPresetId);
|
||||
while (presetsAddedCount < desiredPresetCount)
|
||||
{
|
||||
const randomPresetRoot = this.randomUtil.getArrayValue(presetRootItems);
|
||||
const rootItemDb = this.itemHelper.getItem(randomPresetRoot._tpl)[1];
|
||||
const presetWithChildrenClone = this.jsonUtil.clone(this.itemHelper.findAndReturnChildrenAsItems(baseFenceAssort.items, randomPresetRoot._id));
|
||||
|
||||
this.removeRandomModsOfItem(presetWithChildrenClone);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
assorts.items.push(...presetWithChildrenClone);
|
||||
assorts.barter_scheme[randomPresetRoot._id] = baseFenceAssort.barter_scheme[randomPresetRoot._id];
|
||||
assorts.loyal_level_items[randomPresetRoot._id] = baseFenceAssort.loyal_level_items[randomPresetRoot._id];
|
||||
|
||||
presetsAddedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
protected addItemAssorts(
|
||||
assortCount: number,
|
||||
fenceAssortIds: string[],
|
||||
assorts: ITraderAssort,
|
||||
fenceAssort: ITraderAssort,
|
||||
itemTypeCounts: Record<string, { current: number; max: number; }>,
|
||||
@ -425,89 +457,83 @@ export class FenceService
|
||||
): void
|
||||
{
|
||||
const priceLimits = this.traderConfig.fence.itemCategoryRoublePriceLimit;
|
||||
const assortRootItems = fenceAssort.items.filter(x => x.parentId === "hideout");
|
||||
for (let i = 0; i < assortCount; i++)
|
||||
{
|
||||
const itemTpl = fenceAssortIds[this.randomUtil.getInt(0, fenceAssortIds.length - 1)];
|
||||
const chosenAssortRoot = this.randomUtil.getArrayValue(assortRootItems);
|
||||
if (!chosenAssortRoot)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("fence-unable_to_find_assort_by_id", chosenAssortRoot._id));
|
||||
|
||||
const price = this.handbookHelper.getTemplatePrice(itemTpl);
|
||||
const itemIsPreset = this.presetHelper.isPreset(itemTpl);
|
||||
continue;
|
||||
}
|
||||
const desiredAssortItemAndChildrenClone = this.jsonUtil.clone(this.itemHelper.findAndReturnChildrenAsItems(fenceAssort.items, chosenAssortRoot._id));
|
||||
|
||||
const itemDbDetails = this.itemHelper.getItem(chosenAssortRoot._tpl)[1];
|
||||
const itemLimitCount = itemTypeCounts[itemDbDetails._parent];
|
||||
if (itemLimitCount && itemLimitCount.current > itemLimitCount.max)
|
||||
{
|
||||
// Skip adding item as assort as limit reached, decrement i counter so we still get another item
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
const itemIsPreset = this.presetHelper.isPreset(chosenAssortRoot._id);
|
||||
|
||||
const price = fenceAssort.barter_scheme[chosenAssortRoot._id][0][0].count;
|
||||
if (price === 0 || (price === 1 && !itemIsPreset) || price === 100)
|
||||
{
|
||||
// Don't allow "special" items
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// It's a normal non-preset item
|
||||
if (!itemIsPreset)
|
||||
|
||||
if (price > priceLimits[itemDbDetails._parent])
|
||||
{
|
||||
const desiredAssort = fenceAssort.items[fenceAssort.items.findIndex((i) => i._id === itemTpl)];
|
||||
if (!desiredAssort)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("fence-unable_to_find_assort_by_id", itemTpl));
|
||||
}
|
||||
|
||||
const itemDbDetails = this.itemHelper.getItem(desiredAssort._tpl)[1];
|
||||
const itemLimitCount = itemTypeCounts[itemDbDetails._parent];
|
||||
|
||||
if (itemLimitCount && itemLimitCount.current > itemLimitCount.max)
|
||||
{
|
||||
// Skip adding item as assort as limit reached, decrement i counter so we still get another item
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (price > priceLimits[itemDbDetails._parent])
|
||||
{
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Increment count as item is being added
|
||||
if (itemLimitCount)
|
||||
{
|
||||
itemLimitCount.current++;
|
||||
}
|
||||
|
||||
const itemsToPush: Item[] = [];
|
||||
const rootItemToPush = this.jsonUtil.clone(desiredAssort);
|
||||
this.randomiseItemUpdProperties(itemDbDetails, rootItemToPush);
|
||||
itemsToPush.push(rootItemToPush);
|
||||
|
||||
rootItemToPush._id = this.hashUtil.generate();
|
||||
rootItemToPush.upd.StackObjectsCount = this.getSingleItemStackCount(itemDbDetails);
|
||||
rootItemToPush.upd.BuyRestrictionCurrent = 0;
|
||||
rootItemToPush.upd.UnlimitedCount = false;
|
||||
|
||||
// Need to add mods to armors so they dont show as red in the trade screen
|
||||
if (this.itemHelper.itemRequiresSoftInserts(rootItemToPush._tpl))
|
||||
{
|
||||
this.addModsToArmorModSlots(itemsToPush, itemDbDetails);
|
||||
}
|
||||
|
||||
assorts.items.push(...itemsToPush);
|
||||
assorts.barter_scheme[rootItemToPush._id] = fenceAssort.barter_scheme[itemTpl];
|
||||
assorts.loyal_level_items[rootItemToPush._id] = loyaltyLevel;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Increment count as item is being added
|
||||
if (itemLimitCount)
|
||||
{
|
||||
itemLimitCount.current++;
|
||||
}
|
||||
|
||||
const rootItemBeingAdded = desiredAssortItemAndChildrenClone[0];
|
||||
this.randomiseItemUpdProperties(itemDbDetails, rootItemBeingAdded);
|
||||
|
||||
rootItemBeingAdded.upd.StackObjectsCount = this.getSingleItemStackCount(itemDbDetails);
|
||||
rootItemBeingAdded.upd.BuyRestrictionCurrent = 0;
|
||||
rootItemBeingAdded.upd.UnlimitedCount = false;
|
||||
|
||||
// Need to add mods to armors so they dont show as red in the trade screen
|
||||
if (this.itemHelper.itemRequiresSoftInserts(rootItemBeingAdded._tpl))
|
||||
{
|
||||
this.randomiseArmorModDurability(desiredAssortItemAndChildrenClone, itemDbDetails);
|
||||
}
|
||||
|
||||
assorts.items.push(...desiredAssortItemAndChildrenClone);
|
||||
assorts.barter_scheme[rootItemBeingAdded._id] = fenceAssort.barter_scheme[chosenAssortRoot._id];
|
||||
assorts.loyal_level_items[rootItemBeingAdded._id] = loyaltyLevel;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add soft inserts + armor plates to an armor
|
||||
* Adjust plate / soft insert durability values
|
||||
* @param armor Armor item array to add mods into
|
||||
* @param itemDbDetails Armor items db template
|
||||
*/
|
||||
protected addModsToArmorModSlots(armor: Item[], itemDbDetails: ITemplateItem): void
|
||||
protected randomiseArmorModDurability(armor: Item[], itemDbDetails: ITemplateItem): void
|
||||
{
|
||||
// Armor has no mods, make no additions
|
||||
// Armor has no mods, make no changes
|
||||
const hasMods = itemDbDetails._props.Slots.length > 0;
|
||||
if (!hasMods)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for and add required soft inserts to armors
|
||||
// Check for and adjust soft insert durability values
|
||||
const requiredSlots = itemDbDetails._props.Slots.filter(slot => slot._required);
|
||||
const hasRequiredSlots = requiredSlots.length > 0;
|
||||
if (hasRequiredSlots)
|
||||
@ -515,7 +541,9 @@ export class FenceService
|
||||
for (const requiredSlot of requiredSlots)
|
||||
{
|
||||
const modItemDbDetails = this.itemHelper.getItem(requiredSlot._props.filters[0].Plate)[1];
|
||||
const durabilityValues = this.getRandomisedArmorDurabilityValues(modItemDbDetails, this.traderConfig.fence.armorMaxDurabilityPercentMinMax);
|
||||
const durabilityValues = this.getRandomisedArmorDurabilityValues(
|
||||
modItemDbDetails,
|
||||
this.traderConfig.fence.armorMaxDurabilityPercentMinMax);
|
||||
const plateTpl = requiredSlot._props.filters[0].Plate; // `Plate` property appears to be the 'default' item for slot
|
||||
if (plateTpl === "")
|
||||
{
|
||||
@ -523,34 +551,36 @@ export class FenceService
|
||||
continue;
|
||||
}
|
||||
|
||||
const mod: Item = {
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: plateTpl,
|
||||
parentId: armor[0]._id,
|
||||
slotId: requiredSlot._name,
|
||||
upd: {
|
||||
Repairable: {
|
||||
Durability: durabilityValues.Durability,
|
||||
MaxDurability: durabilityValues.MaxDurability
|
||||
}
|
||||
}
|
||||
};
|
||||
// Find items mod to apply dura changes to
|
||||
const modItemToAdjust = armor.find(mod => mod.slotId === requiredSlot._name);
|
||||
if (!modItemToAdjust.upd)
|
||||
{
|
||||
modItemToAdjust.upd = {}
|
||||
}
|
||||
|
||||
if (!modItemToAdjust.upd.Repairable)
|
||||
{
|
||||
modItemToAdjust.upd.Repairable = {
|
||||
Durability: modItemDbDetails._props.MaxDurability,
|
||||
MaxDurability: modItemDbDetails._props.MaxDurability
|
||||
};
|
||||
}
|
||||
modItemToAdjust.upd.Repairable.Durability = durabilityValues.Durability;
|
||||
modItemToAdjust.upd.Repairable.MaxDurability = durabilityValues.MaxDurability;
|
||||
|
||||
// 25% chance to add shots to visor when its below max durability
|
||||
if (this.randomUtil.getChance100(25)
|
||||
&& mod.parentId === BaseClasses.ARMORED_EQUIPMENT && mod.slotId === "mod_equipment_000"
|
||||
&& mod.upd.Repairable.Durability < modItemDbDetails._props.MaxDurability)
|
||||
&& modItemToAdjust.parentId === BaseClasses.ARMORED_EQUIPMENT && modItemToAdjust.slotId === "mod_equipment_000"
|
||||
&& modItemToAdjust.upd.Repairable.Durability < modItemDbDetails._props.MaxDurability) // Is damaged
|
||||
{
|
||||
mod.upd.FaceShield = {
|
||||
modItemToAdjust.upd.FaceShield = {
|
||||
Hits: this.randomUtil.getInt(1,3)
|
||||
}
|
||||
}
|
||||
|
||||
armor.push(mod);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for and add plate items
|
||||
// Check for and adjust plate durability values
|
||||
const plateSlots = itemDbDetails._props.Slots.filter(slot => this.itemHelper.isRemovablePlateSlot(slot._name));
|
||||
if (plateSlots.length > 0)
|
||||
{
|
||||
@ -569,19 +599,27 @@ export class FenceService
|
||||
continue;
|
||||
}
|
||||
const modItemDbDetails = this.itemHelper.getItem(plateTpl)[1];
|
||||
const durabilityValues = this.getRandomisedArmorDurabilityValues(modItemDbDetails, this.traderConfig.fence.armorMaxDurabilityPercentMinMax);
|
||||
armor.push({
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: plateSlot._props.filters[0].Plate, // `Plate` property appears to be the 'default' item for slot
|
||||
parentId: armor[0]._id,
|
||||
slotId: plateSlot._name,
|
||||
upd: {
|
||||
Repairable: {
|
||||
Durability: durabilityValues.Durability,
|
||||
MaxDurability: durabilityValues.MaxDurability
|
||||
}
|
||||
}
|
||||
});
|
||||
const durabilityValues = this.getRandomisedArmorDurabilityValues(
|
||||
modItemDbDetails,
|
||||
this.traderConfig.fence.armorMaxDurabilityPercentMinMax);
|
||||
|
||||
// Find items mod to apply dura changes to
|
||||
const modItemToAdjust = armor.find(mod => mod.slotId === plateSlot._name);
|
||||
if (!modItemToAdjust.upd)
|
||||
{
|
||||
modItemToAdjust.upd = {}
|
||||
}
|
||||
|
||||
if (!modItemToAdjust.upd.Repairable)
|
||||
{
|
||||
modItemToAdjust.upd.Repairable = {
|
||||
Durability: modItemDbDetails._props.MaxDurability,
|
||||
MaxDurability: modItemDbDetails._props.MaxDurability
|
||||
};
|
||||
}
|
||||
|
||||
modItemToAdjust.upd.Repairable.Durability = durabilityValues.Durability;
|
||||
modItemToAdjust.upd.Repairable.MaxDurability = durabilityValues.MaxDurability;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -776,10 +814,7 @@ export class FenceService
|
||||
|
||||
// Randomise armor durability
|
||||
if (
|
||||
(itemDetails._parent === BaseClasses.ARMOR
|
||||
|| itemDetails._parent === BaseClasses.HEADWEAR
|
||||
|| itemDetails._parent === BaseClasses.VEST
|
||||
|| itemDetails._parent === BaseClasses.ARMORED_EQUIPMENT
|
||||
(itemDetails._parent === BaseClasses.ARMORED_EQUIPMENT
|
||||
|| itemDetails._parent === BaseClasses.FACECOVER
|
||||
|| itemDetails._parent === BaseClasses.ARMOR_PLATE
|
||||
) && itemDetails._props.MaxDurability > 0
|
||||
|
Loading…
x
Reference in New Issue
Block a user