Feature: Add code to handle sealed weapon containers when opened in menu
Add handbook price for sealed containers (default of 100rub)
This commit is contained in:
parent
332dc140a6
commit
0c31719013
@ -19,5 +19,141 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sealedAirdropContainer": {
|
||||||
|
"weaponRewardWeight": {
|
||||||
|
"5447a9cd4bdc2dbd208b4567": 1,
|
||||||
|
"5bb2475ed4351e00853264e3": 1,
|
||||||
|
"5bd70322209c4d00d7167b8f": 1,
|
||||||
|
"5ac66d2e5acfc43b321d4b53": 1,
|
||||||
|
"5ac66d725acfc43b321d4b60": 1,
|
||||||
|
"5ac66d9b5acfc4001633997a": 1,
|
||||||
|
"62e7c4fba689e8c9c50dfc38": 1,
|
||||||
|
"63171672192e68c5460cebc5": 1,
|
||||||
|
"5c488a752e221602b412af63": 1,
|
||||||
|
"5dcbd56fdbd3d91b3e5468d5": 1,
|
||||||
|
"623063e994fc3f7b302a9696": 1,
|
||||||
|
"5fbcc1d9016cce60e8341ab3": 1,
|
||||||
|
"606587252535c57a13424cfd": 1,
|
||||||
|
"5b0bbe4e5acfc40dc528a72d": 1,
|
||||||
|
"6184055050224f204c1da540": 1,
|
||||||
|
"6183afd850224f204c1da514": 1,
|
||||||
|
"5beed0f50db834001c062b12": 1,
|
||||||
|
"5cc82d76e24e8d00134b4b83": 1,
|
||||||
|
"5fc3e272f8b6a877a729eac5": 1,
|
||||||
|
"5fb6548dd1409e5ca04b54f9": 1,
|
||||||
|
"5aafa857e5b5b00018480968": 1,
|
||||||
|
"5bfea6e90db834001b7347f3": 1,
|
||||||
|
"5cadfbf7ae92152ac412eeef": 1,
|
||||||
|
"628a60ae6b1d481ff772e9c8": 1,
|
||||||
|
"628b5638ad252a16da6dd245": 1,
|
||||||
|
"5d43021ca4b9362eab4b5e25": 1,
|
||||||
|
"58948c8e86f77409493f7266": 1,
|
||||||
|
"62e14904c2699c0ec93adc47": 1,
|
||||||
|
"5c46fbd72e2216398b5a8c9c": 1,
|
||||||
|
"5df8ce05b11454561e39243b": 1,
|
||||||
|
"5df24cf80dee1b22f862e9bc": 1
|
||||||
|
},
|
||||||
|
"defaultPresetsOnly": true,
|
||||||
|
"weaponModRewardLimits": {
|
||||||
|
"5448bc234bdc2d3c308b4569": {
|
||||||
|
"type": "magazine",
|
||||||
|
"min": 2,
|
||||||
|
"max": 4
|
||||||
|
},
|
||||||
|
"55818b164bdc2ddc698b456c": {
|
||||||
|
"type": "laserLight",
|
||||||
|
"min": 1,
|
||||||
|
"max": 2
|
||||||
|
},
|
||||||
|
"55818ad54bdc2ddc698b4569": {
|
||||||
|
"type": "collimator",
|
||||||
|
"min": 0,
|
||||||
|
"max": 2
|
||||||
|
},
|
||||||
|
"55818acf4bdc2dde698b456b": {
|
||||||
|
"type": "compactCollimator",
|
||||||
|
"min": 0,
|
||||||
|
"max": 2
|
||||||
|
},
|
||||||
|
"55818b224bdc2dde698b456f": {
|
||||||
|
"type": "mount",
|
||||||
|
"min": 0,
|
||||||
|
"max": 2
|
||||||
|
},
|
||||||
|
"555ef6e44bdc2de9068b457e": {
|
||||||
|
"type": "barrel",
|
||||||
|
"min": 1,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"55818add4bdc2d5b648b456f": {
|
||||||
|
"type": "assaultScope",
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"55818ae44bdc2dde698b456c": {
|
||||||
|
"type": "opticScope",
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"55818af64bdc2d5b648b4570": {
|
||||||
|
"type": "foregrip",
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"550aa4cd4bdc2dd8348b456c": {
|
||||||
|
"type": "silencer",
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"55818b084bdc2d5b648b4571": {
|
||||||
|
"type": "flashlight",
|
||||||
|
"min": 0,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"55818a104bdc2db9688b4569": {
|
||||||
|
"type": "handguard",
|
||||||
|
"min": 0,
|
||||||
|
"max": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rewardTypeLimits": {
|
||||||
|
"5448e8d04bdc2ddf718b4569": {
|
||||||
|
"type": "food",
|
||||||
|
"min": 2,
|
||||||
|
"max": 8
|
||||||
|
},
|
||||||
|
"5448f3a64bdc2d60728b456a": {
|
||||||
|
"type": "stim",
|
||||||
|
"min": 2,
|
||||||
|
"max": 5
|
||||||
|
},
|
||||||
|
"543be5cb4bdc2deb348b4568": {
|
||||||
|
"type": "ammobox",
|
||||||
|
"min": 2,
|
||||||
|
"max": 5
|
||||||
|
},
|
||||||
|
"5448f3ac4bdc2dce718b4569": {
|
||||||
|
"type": "medical",
|
||||||
|
"min": 2,
|
||||||
|
"max": 7
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ammoBoxWhitelist": [
|
||||||
|
"648983d6b5a2df1c815a04ec",
|
||||||
|
"6489848173c462723909a14b",
|
||||||
|
"648984b8d5b4df6140000a1a",
|
||||||
|
"648984e3f09d032aa9399d53",
|
||||||
|
"6489851fc827d4637f01791b",
|
||||||
|
"6489854673c462723909a14e",
|
||||||
|
"648985c074a806211e4fb682",
|
||||||
|
"6489875745f9ca4ba51c4808",
|
||||||
|
"648987d673c462723909a151",
|
||||||
|
"648986bbc827d4637f01791e",
|
||||||
|
"64898583d5b4df6140000a1d",
|
||||||
|
"64898602f09d032aa9399d56",
|
||||||
|
"6489870774a806211e4fb685",
|
||||||
|
"6489879db5a2df1c815a04ef"
|
||||||
|
]
|
||||||
|
}
|
||||||
"customMoneyTpls": []
|
"customMoneyTpls": []
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
|
import { LootGenerator } from "../generators/LootGenerator";
|
||||||
import { InventoryHelper } from "../helpers/InventoryHelper";
|
import { InventoryHelper } from "../helpers/InventoryHelper";
|
||||||
|
import { ItemHelper } from "../helpers/ItemHelper";
|
||||||
import { PaymentHelper } from "../helpers/PaymentHelper";
|
import { PaymentHelper } from "../helpers/PaymentHelper";
|
||||||
import { PresetHelper } from "../helpers/PresetHelper";
|
import { PresetHelper } from "../helpers/PresetHelper";
|
||||||
import { ProfileHelper } from "../helpers/ProfileHelper";
|
import { ProfileHelper } from "../helpers/ProfileHelper";
|
||||||
import { WeightedRandomHelper } from "../helpers/WeightedRandomHelper";
|
|
||||||
import { IPmcData } from "../models/eft/common/IPmcData";
|
import { IPmcData } from "../models/eft/common/IPmcData";
|
||||||
import { Item } from "../models/eft/common/tables/IItem";
|
import { Item } from "../models/eft/common/tables/IItem";
|
||||||
import { IAddItemRequestData } from "../models/eft/inventory/IAddItemRequestData";
|
import { IAddItemRequestData } from "../models/eft/inventory/IAddItemRequestData";
|
||||||
@ -38,7 +39,9 @@ import {
|
|||||||
IOpenRandomLootContainerRequestData
|
IOpenRandomLootContainerRequestData
|
||||||
} from "../models/eft/inventory/IOpenRandomLootContainerRequestData";
|
} from "../models/eft/inventory/IOpenRandomLootContainerRequestData";
|
||||||
import { IItemEventRouterResponse } from "../models/eft/itemEvent/IItemEventRouterResponse";
|
import { IItemEventRouterResponse } from "../models/eft/itemEvent/IItemEventRouterResponse";
|
||||||
|
import { BackendErrorCodes } from "../models/enums/BackendErrorCodes";
|
||||||
import { Traders } from "../models/enums/Traders";
|
import { Traders } from "../models/enums/Traders";
|
||||||
|
import { RewardDetails } from "../models/spt/config/IInventoryConfig";
|
||||||
import { ILogger } from "../models/spt/utils/ILogger";
|
import { ILogger } from "../models/spt/utils/ILogger";
|
||||||
import { EventOutputHolder } from "../routers/EventOutputHolder";
|
import { EventOutputHolder } from "../routers/EventOutputHolder";
|
||||||
import { DatabaseServer } from "../servers/DatabaseServer";
|
import { DatabaseServer } from "../servers/DatabaseServer";
|
||||||
@ -57,6 +60,7 @@ export class InventoryController
|
|||||||
@inject("WinstonLogger") protected logger: ILogger,
|
@inject("WinstonLogger") protected logger: ILogger,
|
||||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||||
|
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||||
@inject("FenceService") protected fenceService: FenceService,
|
@inject("FenceService") protected fenceService: FenceService,
|
||||||
@ -64,9 +68,9 @@ export class InventoryController
|
|||||||
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
|
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
|
||||||
@inject("RagfairOfferService") protected ragfairOfferService: RagfairOfferService,
|
@inject("RagfairOfferService") protected ragfairOfferService: RagfairOfferService,
|
||||||
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||||
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
|
|
||||||
@inject("PaymentHelper") protected paymentHelper: PaymentHelper,
|
@inject("PaymentHelper") protected paymentHelper: PaymentHelper,
|
||||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
|
@inject("LootGenerator") protected lootGenerator: LootGenerator,
|
||||||
@inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder,
|
@inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder,
|
||||||
@inject("HttpResponseUtil") protected httpResponseUtil: HttpResponseUtil
|
@inject("HttpResponseUtil") protected httpResponseUtil: HttpResponseUtil
|
||||||
)
|
)
|
||||||
@ -97,7 +101,7 @@ export class InventoryController
|
|||||||
// Dont move items from trader to profile, this can happen when editing a traders preset weapons
|
// Dont move items from trader to profile, this can happen when editing a traders preset weapons
|
||||||
if (moveRequest.fromOwner?.type === "Trader" && !items.isMail)
|
if (moveRequest.fromOwner?.type === "Trader" && !items.isMail)
|
||||||
{
|
{
|
||||||
return this.httpResponseUtil.appendErrorToOutput(output, this.localisationService.getText("inventory-edit_trader_item"), 228);
|
return this.httpResponseUtil.appendErrorToOutput(output, this.localisationService.getText("inventory-edit_trader_item"), <BackendErrorCodes>228);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.inventoryHelper.moveItemInternal(pmcData, items.from, moveRequest);
|
this.inventoryHelper.moveItemInternal(pmcData, items.from, moveRequest);
|
||||||
@ -760,29 +764,28 @@ export class InventoryController
|
|||||||
public openRandomLootContainer(pmcData: IPmcData, body: IOpenRandomLootContainerRequestData, sessionID: string): IItemEventRouterResponse
|
public openRandomLootContainer(pmcData: IPmcData, body: IOpenRandomLootContainerRequestData, sessionID: string): IItemEventRouterResponse
|
||||||
{
|
{
|
||||||
const openedItem = pmcData.Inventory.items.find(x => x._id === body.item);
|
const openedItem = pmcData.Inventory.items.find(x => x._id === body.item);
|
||||||
const rewardContainerDetails = this.inventoryHelper.getRandomLootContainerRewardDetails(openedItem._tpl);
|
const containerDetails = this.itemHelper.getItem(openedItem._tpl);
|
||||||
|
const isSealedWeaponBox = containerDetails[1]._name.includes("event_container_airdrop");
|
||||||
|
|
||||||
const newItemRequest: IAddItemRequestData = {
|
const newItemRequest: IAddItemRequestData = {
|
||||||
tid: "RandomLootContainer",
|
tid: "RandomLootContainer",
|
||||||
items: []
|
items: []
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get random items and add to newItemRequest
|
let rewardContainerDetails: RewardDetails = {
|
||||||
for (let index = 0; index < rewardContainerDetails.rewardCount; index++)
|
rewardCount: 0,
|
||||||
|
foundInRaid: true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isSealedWeaponBox)
|
||||||
{
|
{
|
||||||
// Pick random reward from pool, add to request object
|
newItemRequest.items.push(...this.lootGenerator.getSealedWeaponCaseLoot());
|
||||||
const chosenRewardItemTpl = this.weightedRandomHelper.getWeightedInventoryItem(rewardContainerDetails.rewardTplPool);
|
}
|
||||||
const existingItemInRequest = newItemRequest.items.find(x => x.item_id === chosenRewardItemTpl);
|
else
|
||||||
if (existingItemInRequest)
|
{
|
||||||
{
|
// Get summary of loot from config
|
||||||
// Exists in request already, increment count
|
rewardContainerDetails = this.inventoryHelper.getRandomLootContainerRewardDetails(openedItem._tpl);
|
||||||
existingItemInRequest.count++;
|
newItemRequest.items.push(...this.lootGenerator.getRandomLootContainerLoot(rewardContainerDetails));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
||||||
newItemRequest.items.push({item_id: chosenRewardItemTpl, count: 1});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const output = this.eventOutputHolder.getOutput(sessionID);
|
const output = this.eventOutputHolder.getOutput(sessionID);
|
||||||
|
@ -1,15 +1,21 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
|
import { InventoryHelper } from "../helpers/InventoryHelper";
|
||||||
import { ItemHelper } from "../helpers/ItemHelper";
|
import { ItemHelper } from "../helpers/ItemHelper";
|
||||||
|
import { PresetHelper } from "../helpers/PresetHelper";
|
||||||
|
import { WeightedRandomHelper } from "../helpers/WeightedRandomHelper";
|
||||||
import { Preset } from "../models/eft/common/IGlobals";
|
import { Preset } from "../models/eft/common/IGlobals";
|
||||||
import { ITemplateItem } from "../models/eft/common/tables/ITemplateItem";
|
import { ITemplateItem } from "../models/eft/common/tables/ITemplateItem";
|
||||||
|
import { AddItem } from "../models/eft/inventory/IAddItemRequestData";
|
||||||
import { BaseClasses } from "../models/enums/BaseClasses";
|
import { BaseClasses } from "../models/enums/BaseClasses";
|
||||||
|
import { ISealedAirdropContainerSettings, RewardDetails } from "../models/spt/config/IInventoryConfig";
|
||||||
import { LootItem } from "../models/spt/services/LootItem";
|
import { LootItem } from "../models/spt/services/LootItem";
|
||||||
import { LootRequest } from "../models/spt/services/LootRequest";
|
import { LootRequest } from "../models/spt/services/LootRequest";
|
||||||
import { ILogger } from "../models/spt/utils/ILogger";
|
import { ILogger } from "../models/spt/utils/ILogger";
|
||||||
import { DatabaseServer } from "../servers/DatabaseServer";
|
import { DatabaseServer } from "../servers/DatabaseServer";
|
||||||
import { ItemFilterService } from "../services/ItemFilterService";
|
import { ItemFilterService } from "../services/ItemFilterService";
|
||||||
import { LocalisationService } from "../services/LocalisationService";
|
import { LocalisationService } from "../services/LocalisationService";
|
||||||
|
import { RagfairLinkedItemService } from "../services/RagfairLinkedItemService";
|
||||||
import { HashUtil } from "../utils/HashUtil";
|
import { HashUtil } from "../utils/HashUtil";
|
||||||
import { RandomUtil } from "../utils/RandomUtil";
|
import { RandomUtil } from "../utils/RandomUtil";
|
||||||
|
|
||||||
@ -27,7 +33,11 @@ export class LootGenerator
|
|||||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||||
|
@inject("PresetHelper") protected presetHelper: PresetHelper,
|
||||||
|
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
|
||||||
|
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper,
|
||||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
|
@inject("RagfairLinkedItemService") protected ragfairLinkedItemService: RagfairLinkedItemService,
|
||||||
@inject("ItemFilterService") protected itemFilterService: ItemFilterService
|
@inject("ItemFilterService") protected itemFilterService: ItemFilterService
|
||||||
)
|
)
|
||||||
{}
|
{}
|
||||||
@ -228,4 +238,204 @@ export class LootGenerator
|
|||||||
// item added okay
|
// item added okay
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sealed weapon containers have a weapon + associated mods inside them + assortment of other things (food/meds)
|
||||||
|
* @returns Array of items to add to player inventory
|
||||||
|
*/
|
||||||
|
public getSealedWeaponCaseLoot(): AddItem[]
|
||||||
|
{
|
||||||
|
const itemsToReturn: AddItem[] = [];
|
||||||
|
const containerSettings = this.inventoryHelper.getInventoryConfig().sealedAirdropContainer;
|
||||||
|
|
||||||
|
// choose a weapon to give to the player (weighted)
|
||||||
|
const chosenWeaponTpl = this.weightedRandomHelper.getWeightedInventoryItem(containerSettings.weaponRewardWeight);
|
||||||
|
const weaponDetailsDb = this.itemHelper.getItem(chosenWeaponTpl);
|
||||||
|
if (!weaponDetailsDb[0])
|
||||||
|
{
|
||||||
|
this.logger.warning(`Non-item was picked as reward ${chosenWeaponTpl}, unable to continue`);
|
||||||
|
|
||||||
|
return itemsToReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get weapon preset - default or choose a random one from all possible
|
||||||
|
const chosenWeaponPreset = containerSettings.defaultPresetsOnly
|
||||||
|
? this.presetHelper.getDefaultPreset(chosenWeaponTpl)
|
||||||
|
: this.randomUtil.getArrayValue(this.presetHelper.getPresets(chosenWeaponTpl));
|
||||||
|
|
||||||
|
// Add preset to return object
|
||||||
|
itemsToReturn.push({
|
||||||
|
count: 1,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
item_id: chosenWeaponPreset._id,
|
||||||
|
isPreset: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get items related to chosen weapon
|
||||||
|
const linkedItemsToWeapon = this.ragfairLinkedItemService.getLinkedDbItems(chosenWeaponTpl);
|
||||||
|
itemsToReturn.push(...this.getSealedContainerWeaponModRewards(containerSettings, linkedItemsToWeapon, chosenWeaponPreset));
|
||||||
|
|
||||||
|
// Handle non-weapon mod reward types
|
||||||
|
itemsToReturn.push(...this.getSealedContainerNonWeaponModRewards(containerSettings, weaponDetailsDb[1]));
|
||||||
|
|
||||||
|
return itemsToReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get non-weapon mod rewards for a sealed container
|
||||||
|
* @param containerSettings Sealed weapon container settings
|
||||||
|
* @param weaponDetailsDb Details for the weapon to reward player
|
||||||
|
* @returns AddItem array
|
||||||
|
*/
|
||||||
|
protected getSealedContainerNonWeaponModRewards(containerSettings: ISealedAirdropContainerSettings, weaponDetailsDb: ITemplateItem): AddItem[]
|
||||||
|
{
|
||||||
|
const rewards: AddItem[] = [];
|
||||||
|
|
||||||
|
for (const rewardTypeId in containerSettings.rewardTypeLimits)
|
||||||
|
{
|
||||||
|
const settings = containerSettings.rewardTypeLimits[rewardTypeId];
|
||||||
|
const rewardCount = this.randomUtil.getInt(settings.min, settings.max);
|
||||||
|
|
||||||
|
if (rewardCount === 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edge case - ammo boxes
|
||||||
|
if (rewardTypeId === BaseClasses.AMMO_BOX)
|
||||||
|
{
|
||||||
|
// Get ammoboxes from db
|
||||||
|
const ammoBoxesDetails = containerSettings.ammoBoxWhitelist.map(x =>
|
||||||
|
{
|
||||||
|
const itemDetails = this.itemHelper.getItem(x);
|
||||||
|
return itemDetails[1];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Need to find boxes that matches weapons caliber
|
||||||
|
const weaponCaliber = weaponDetailsDb._props.ammoCaliber;
|
||||||
|
const ammoBoxesMatchingCaliber = ammoBoxesDetails.filter(x => x._props.ammoCaliber === weaponCaliber);
|
||||||
|
if (ammoBoxesMatchingCaliber.length === 0)
|
||||||
|
{
|
||||||
|
this.logger.debug(`No ammo box with caliber ${weaponCaliber} found, skipping`);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to add ammo to box, inventoryHelper.addItem() will handle it
|
||||||
|
const chosenAmmoBox = this.randomUtil.getArrayValue(ammoBoxesMatchingCaliber);
|
||||||
|
rewards.push({
|
||||||
|
count: rewardCount,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
item_id: chosenAmmoBox._id,
|
||||||
|
isPreset: false
|
||||||
|
});
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all items of the desired type + not quest items + not globally blacklisted
|
||||||
|
const possibleRewardItems = Object.values(this.databaseServer.getTables().templates.items)
|
||||||
|
.filter(x => x._parent === rewardTypeId
|
||||||
|
&& x._type.toLowerCase() === "item"
|
||||||
|
&& !this.itemFilterService.isItemBlacklisted(x._id)
|
||||||
|
&& !x._props.QuestItem);
|
||||||
|
|
||||||
|
if (possibleRewardItems.length === 0)
|
||||||
|
{
|
||||||
|
this.logger.debug(`No items with base type of ${rewardTypeId} found, skipping`);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let index = 0; index < rewardCount; index++)
|
||||||
|
{
|
||||||
|
// choose a random item from pool
|
||||||
|
const chosenRewardItem = this.randomUtil.getArrayValue(possibleRewardItems);
|
||||||
|
this.addOrIncrementItemToArray(chosenRewardItem._id, rewards);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rewards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over the container weaponModRewardLimits settings and create an array of weapon mods to reward player
|
||||||
|
* @param containerSettings Sealed weapon container settings
|
||||||
|
* @param linkedItemsToWeapon All items that can be attached/inserted into weapon
|
||||||
|
* @param chosenWeaponPreset The weapon preset given to player as reward
|
||||||
|
* @returns AddItem array
|
||||||
|
*/
|
||||||
|
protected getSealedContainerWeaponModRewards(containerSettings: ISealedAirdropContainerSettings, linkedItemsToWeapon: ITemplateItem[], chosenWeaponPreset: Preset): AddItem[]
|
||||||
|
{
|
||||||
|
const modRewards: AddItem[] = [];
|
||||||
|
for (const rewardTypeId in containerSettings.weaponModRewardLimits)
|
||||||
|
{
|
||||||
|
const settings = containerSettings.weaponModRewardLimits[rewardTypeId];
|
||||||
|
const rewardCount = this.randomUtil.getInt(settings.min, settings.max);
|
||||||
|
|
||||||
|
// Nothing to add, skip reward type
|
||||||
|
if (rewardCount === 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get items that fulfil reward type criteral from items that fit on gun
|
||||||
|
const relatedItems = linkedItemsToWeapon.filter(x => x._parent === rewardTypeId);
|
||||||
|
if (!relatedItems || relatedItems.length === 0)
|
||||||
|
{
|
||||||
|
this.logger.debug(`no items found to fulfil reward type ${rewardTypeId} for weapon: ${chosenWeaponPreset._name}, skipping`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a random item of the desired type and add as reward
|
||||||
|
for (let index = 0; index < rewardCount; index++)
|
||||||
|
{
|
||||||
|
const chosenItem = this.randomUtil.drawRandomFromList(relatedItems);
|
||||||
|
this.addOrIncrementItemToArray(chosenItem[0]._id, modRewards);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return modRewards;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle event-related loot containers - currently just the halloween jack-o-lanterns that give food rewards
|
||||||
|
* @param rewardContainerDetails
|
||||||
|
* @returns AddItem array
|
||||||
|
*/
|
||||||
|
public getRandomLootContainerLoot(rewardContainerDetails: RewardDetails): AddItem[]
|
||||||
|
{
|
||||||
|
const itemsToReturn: AddItem[] = [];
|
||||||
|
|
||||||
|
// Get random items and add to newItemRequest
|
||||||
|
for (let index = 0; index < rewardContainerDetails.rewardCount; index++)
|
||||||
|
{
|
||||||
|
// Pick random reward from pool, add to request object
|
||||||
|
const chosenRewardItemTpl = this.weightedRandomHelper.getWeightedInventoryItem(rewardContainerDetails.rewardTplPool);
|
||||||
|
this.addOrIncrementItemToArray(chosenRewardItemTpl, itemsToReturn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemsToReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A bug in inventoryHelper.addItem() means you cannot add the same item to the array twice with a count of 1, it causes duplication
|
||||||
|
* Default adds 1, or increments count
|
||||||
|
* @param itemTplToAdd items tpl we want to add to array
|
||||||
|
* @param resultsArray Array to add item tpl to
|
||||||
|
*/
|
||||||
|
protected addOrIncrementItemToArray(itemTplToAdd: string, resultsArray: AddItem[]): void
|
||||||
|
{
|
||||||
|
const existingItemIndex = resultsArray.findIndex(x => x.item_id === itemTplToAdd);
|
||||||
|
if (existingItemIndex > -1)
|
||||||
|
{
|
||||||
|
// Exists in array already, increment count
|
||||||
|
resultsArray[existingItemIndex].count++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
resultsArray.push({item_id: itemTplToAdd, count: 1, isPreset: false});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -467,7 +467,7 @@ export class RagfairOfferGenerator
|
|||||||
if ("Repairable" in item.upd)
|
if ("Repairable" in item.upd)
|
||||||
{
|
{
|
||||||
// Randomise non-0 class armor
|
// Randomise non-0 class armor
|
||||||
if (itemDetails._props.armorClass && itemDetails._props.armorClass >= 1)
|
if (itemDetails._props.armorClass && <number>itemDetails._props.armorClass >= 1)
|
||||||
{
|
{
|
||||||
this.randomiseDurabilityValues(item, multiplier);
|
this.randomiseDurabilityValues(item, multiplier);
|
||||||
}
|
}
|
||||||
|
@ -333,6 +333,7 @@ export class InventoryHelper
|
|||||||
...itemLocation,
|
...itemLocation,
|
||||||
upd: upd
|
upd: upd
|
||||||
});
|
});
|
||||||
|
this.logger.debug(`Added ${itemLib[tmpKey]._tpl} with id: ${idForItemToAdd} to inventory`);
|
||||||
}
|
}
|
||||||
|
|
||||||
toDo.push([itemLib[tmpKey]._id, idForItemToAdd]);
|
toDo.push([itemLib[tmpKey]._id, idForItemToAdd]);
|
||||||
@ -958,6 +959,11 @@ export class InventoryHelper
|
|||||||
{
|
{
|
||||||
return this.inventoryConfig.randomLootContainers[itemTpl];
|
return this.inventoryConfig.randomLootContainers[itemTpl];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getInventoryConfig(): IInventoryConfig
|
||||||
|
{
|
||||||
|
return this.inventoryConfig;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace InventoryHelper
|
namespace InventoryHelper
|
||||||
|
@ -76,7 +76,7 @@ export class RagfairHelper
|
|||||||
const data = this.ragfairLinkedItemService.getLinkedItems(info.linkedSearchId);
|
const data = this.ragfairLinkedItemService.getLinkedItems(info.linkedSearchId);
|
||||||
result = !data
|
result = !data
|
||||||
? []
|
? []
|
||||||
: Array.from(data);
|
: [...data];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case: category
|
// Case: category
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { MinMax } from "../../../models/common/MinMax";
|
||||||
import { IBaseConfig } from "./IBaseConfig";
|
import { IBaseConfig } from "./IBaseConfig";
|
||||||
|
|
||||||
export interface IInventoryConfig extends IBaseConfig
|
export interface IInventoryConfig extends IBaseConfig
|
||||||
@ -5,6 +6,7 @@ export interface IInventoryConfig extends IBaseConfig
|
|||||||
kind: "aki-inventory"
|
kind: "aki-inventory"
|
||||||
newItemsMarkedFound: boolean
|
newItemsMarkedFound: boolean
|
||||||
randomLootContainers: Record<string, RewardDetails>
|
randomLootContainers: Record<string, RewardDetails>
|
||||||
|
sealedAirdropContainer: ISealedAirdropContainerSettings
|
||||||
/** Contains item tpls that the server should consider money and treat the same as roubles/euros/dollars */
|
/** Contains item tpls that the server should consider money and treat the same as roubles/euros/dollars */
|
||||||
customMoneyTpls: string[]
|
customMoneyTpls: string[]
|
||||||
}
|
}
|
||||||
@ -13,5 +15,15 @@ export interface RewardDetails
|
|||||||
{
|
{
|
||||||
rewardCount: number
|
rewardCount: number
|
||||||
foundInRaid: boolean
|
foundInRaid: boolean
|
||||||
rewardTplPool: Record<string, number>
|
rewardTplPool?: Record<string, number>
|
||||||
|
rewardTypePool?: Record<string, number>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISealedAirdropContainerSettings
|
||||||
|
{
|
||||||
|
weaponRewardWeight: Record<string, number>
|
||||||
|
defaultPresetsOnly: boolean
|
||||||
|
weaponModRewardLimits: Record<string, MinMax>
|
||||||
|
rewardTypeLimits: Record<string, MinMax>
|
||||||
|
ammoBoxWhitelist: string[]
|
||||||
}
|
}
|
@ -8,7 +8,7 @@ import { DatabaseServer } from "../servers/DatabaseServer";
|
|||||||
@injectable()
|
@injectable()
|
||||||
export class RagfairLinkedItemService
|
export class RagfairLinkedItemService
|
||||||
{
|
{
|
||||||
protected linkedItemsCache: Record<string, Iterable<string>> = {};
|
protected linkedItemsCache: Record<string, Set<string>> = {};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||||
@ -16,7 +16,7 @@ export class RagfairLinkedItemService
|
|||||||
)
|
)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public getLinkedItems(linkedSearchId: string): Iterable<string>
|
public getLinkedItems(linkedSearchId: string): Set<string>
|
||||||
{
|
{
|
||||||
if (Object.keys(this.linkedItemsCache).length === 0)
|
if (Object.keys(this.linkedItemsCache).length === 0)
|
||||||
{
|
{
|
||||||
@ -26,6 +26,21 @@ export class RagfairLinkedItemService
|
|||||||
return this.linkedItemsCache[linkedSearchId];
|
return this.linkedItemsCache[linkedSearchId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use ragfair linked item service to get an array of items that can fit on or in designated itemtpl
|
||||||
|
* @param itemTpl Item to get sub-items for
|
||||||
|
* @returns ITemplateItem array
|
||||||
|
*/
|
||||||
|
public getLinkedDbItems(itemTpl: string): ITemplateItem[]
|
||||||
|
{
|
||||||
|
const linkedItemsToWeaponTpls = this.getLinkedItems(itemTpl);
|
||||||
|
return [...linkedItemsToWeaponTpls].map(x =>
|
||||||
|
{
|
||||||
|
const itemDetails = this.itemHelper.getItem(x);
|
||||||
|
return itemDetails[1];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Dictionary of every item and the items associated with it
|
* Create Dictionary of every item and the items associated with it
|
||||||
*/
|
*/
|
||||||
@ -91,7 +106,12 @@ export class RagfairLinkedItemService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scans a given slot type for filters and returns them as a Set */
|
/**
|
||||||
|
* Scans a given slot type for filters and returns them as a Set
|
||||||
|
* @param item
|
||||||
|
* @param slot
|
||||||
|
* @returns array of ids
|
||||||
|
*/
|
||||||
protected getFilters(item: ITemplateItem, slot: string): string[]
|
protected getFilters(item: ITemplateItem, slot: string): string[]
|
||||||
{
|
{
|
||||||
if (!(slot in item._props && item._props[slot].length))
|
if (!(slot in item._props && item._props[slot].length))
|
||||||
|
@ -51,6 +51,8 @@ export class RagfairPriceService implements OnLoad
|
|||||||
*/
|
*/
|
||||||
public async onLoad(): Promise<void>
|
public async onLoad(): Promise<void>
|
||||||
{
|
{
|
||||||
|
this.addMissingHandbookPrices();
|
||||||
|
|
||||||
if (!this.generatedStaticPrices)
|
if (!this.generatedStaticPrices)
|
||||||
{
|
{
|
||||||
this.generateStaticPrices();
|
this.generateStaticPrices();
|
||||||
@ -64,6 +66,24 @@ export class RagfairPriceService implements OnLoad
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add placeholder values for the new sealed weapon containers
|
||||||
|
*/
|
||||||
|
protected addMissingHandbookPrices(): void
|
||||||
|
{
|
||||||
|
const db = this.databaseServer.getTables();
|
||||||
|
const sealedWeaponContainers = Object.values(db.templates.items).filter(x => x._name.includes("event_container_airdrop"));
|
||||||
|
|
||||||
|
for (const container of sealedWeaponContainers)
|
||||||
|
{
|
||||||
|
// doesnt have a handbook value
|
||||||
|
if (db.templates.handbook.Items.findIndex(x => x.Id === container._id) === -1)
|
||||||
|
{
|
||||||
|
db.templates.handbook.Items.push({Id: container._id, ParentId: container._parent, Price: 100});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public getRoute(): string
|
public getRoute(): string
|
||||||
{
|
{
|
||||||
return "RagfairPriceService";
|
return "RagfairPriceService";
|
||||||
|
@ -300,7 +300,7 @@ export class RandomUtil
|
|||||||
* Drawing can be with or without replacement
|
* Drawing can be with or without replacement
|
||||||
* @param {array} list The array we want to draw randomly from
|
* @param {array} list The array we want to draw randomly from
|
||||||
* @param {integer} count The number of times we want to draw
|
* @param {integer} count The number of times we want to draw
|
||||||
* @param {boolean} replacement Draw with or without replacement from the input array
|
* @param {boolean} replacement Draw with or without replacement from the input array(defult true)
|
||||||
* @return {array} Array consisting of N random elements
|
* @return {array} Array consisting of N random elements
|
||||||
*/
|
*/
|
||||||
public drawRandomFromList<T>(list: Array<T>, count = 1, replacement = true): Array<T>
|
public drawRandomFromList<T>(list: Array<T>, count = 1, replacement = true): Array<T>
|
||||||
|
Loading…
Reference in New Issue
Block a user