rename file

This commit is contained in:
2024-06-09 14:50:21 +08:00
parent 138a16c289
commit 0e22d8dbce
376 changed files with 3 additions and 3 deletions
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 acidphantasm
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,13 @@
# Welcome to Harry Hideout by acidphantasm
This mod is designed and built to ease constructing and upgrading your hideout pre-flea market. You can continue to use it post-flea as Harry contains all items used in construction & upgrades.
## **Configuration options**
- itemPriceMultiplier
- useFleaPrices
- useBarters
Adjust itemPriceMultiplier to adjust item value for both flea & non-flea price.
If you disable useFleaPrices, the item price will revert to values in items.json
If you disable useBarters, the high end items will be available for Roubles
@@ -0,0 +1,7 @@
{
"itemPriceMultiplier": 1,
"useFleaPrices": true,
"useBarters": true,
"enableConsoleDebug": false
}
@@ -0,0 +1,458 @@
{
"nonBarterItems": [
{
"itemID": "569668774bdc2da2298b4568",
"price": 140
},
{
"itemID": "5696686a4bdc2da3298b456a",
"price": 130
},
{
"itemID": "57347b8b24597737dd42e192",
"price": 17000
},
{
"itemID": "590c2c9c86f774245b1f03f2",
"price": 8000
},
{
"itemID": "5c13cef886f774072e618e82",
"price": 6000
},
{
"itemID": "57347c93245977448d35f6e3",
"price": 35000
},
{
"itemID": "5c13cd2486f774072c757944",
"price": 8000
},
{
"itemID": "62a0a098de7ac8199358053b",
"price": 18000
},
{
"itemID": "5d1b3f2d86f774253763b735",
"price": 28000
},
{
"itemID": "5d1b3a5d86f774252167ba22",
"price": 26000
},
{
"itemID": "544fb25a4bdc2dfb738b4567",
"price": 2000
},
{
"itemID": "62a0a043cf4a99369e2624a5",
"price": 25000
},
{
"itemID": "57347c77245977448d35f6e2",
"price": 22000
},
{
"itemID": "57347c5b245977448d35f6e1",
"price": 29000
},
{
"itemID": "544fb5454bdc2df8738b456a",
"price": 19000
},
{
"itemID": "56742c284bdc2d98058b456d",
"price": 12000
},
{
"itemID": "590a3c0a86f774385a33c450",
"price": 13000
},
{
"itemID": "5d1b2fa286f77425227d1674",
"price": 87000
},
{
"itemID": "5733279d245977289b77ec24",
"price": 43000
},
{
"itemID": "5734779624597737e04bf329",
"price": 17000
},
{
"itemID": "61bf7b6302b3924be92fa8c3",
"price": 27000
},
{
"itemID": "5d1b317c86f7742523398392",
"price": 38000
},
{
"itemID": "59e35ef086f7741777737012",
"price": 16000
},
{
"itemID": "590c5bbd86f774785762df04",
"price": 11000
},
{
"itemID": "590c31c586f774245e3141b2",
"price": 24000
},
{
"itemID": "57347c1124597737fb1379e3",
"price": 21000
},
{
"itemID": "5e2af2bc86f7746d3f3c33fc",
"price": 12000
},
{
"itemID": "590a373286f774287540368b",
"price": 28000
},
{
"itemID": "5af04b6486f774195a3ebb49",
"price": 22000
},
{
"itemID": "60391b0fb847c71012789415",
"price": 20000
},
{
"itemID": "5d1b313086f77425227d1678",
"price": 20000
},
{
"itemID": "59e36c6f86f774176c10a2a7",
"price": 27000
},
{
"itemID": "62a09ee4cf4a99369e262453",
"price": 7000
},
{
"itemID": "5b4335ba86f7744d2837a264",
"price": 14000
},
{
"itemID": "5e831507ea0a7c419c2f9bd9",
"price": 59000
},
{
"itemID": "59e3606886f77417674759a5",
"price": 30000
},
{
"itemID": "619cc01e0a7c3a1a2731940c",
"price": 17000
},
{
"itemID": "5d1b392c86f77425243e98fe",
"price": 19000
},
{
"itemID": "5c06779c86f77426e00dd782",
"price": 13000
},
{
"itemID": "59e35cbb86f7741778269d83",
"price": 26000
},
{
"itemID": "59e35de086f7741778269d84",
"price": 44000
},
{
"itemID": "5e2af29386f7746d4159f077",
"price": 26000
},
{
"itemID": "61bf83814088ec1a363d7097",
"price": 24000
},
{
"itemID": "590c2e1186f77425357b6124",
"price": 44000
},
{
"itemID": "5d1c819a86f774771b0acd6c",
"price": 26000
},
{
"itemID": "62a0a0bb621468534a797ad5",
"price": 25000
},
{
"itemID": "62a0a124de7ac81993580542",
"price": 45000
},
{
"itemID": "574eb85c245977648157eec3",
"price": 24000
},
{
"itemID": "619cbfeb6b8a1b37a54eebfa",
"price": 61000
},
{
"itemID": "63a0b208f444d32d6f03ea1e",
"price": 145000
},
{
"itemID": "590a3b0486f7743954552bdb",
"price": 23000
},
{
"itemID": "590c311186f77424d1667482",
"price": 16000
},
{
"itemID": "59faf98186f774067b6be103",
"price": 17000
},
{
"itemID": "5d40419286f774318526545f",
"price": 18000
},
{
"itemID": "590c346786f77423e50ed342",
"price": 32000
},
{
"itemID": "590a3cd386f77436f20848cb",
"price": 24000
},
{
"itemID": "5d1b304286f774253763a528",
"price": 30000
},
{
"itemID": "5d1b2ffd86f77425243e8d17",
"price": 26000
},
{
"itemID": "590c392f86f77444754deb29",
"price": 38000
},
{
"itemID": "5734781f24597737e04bf32a",
"price": 24000
},
{
"itemID": "590a391c86f774385a33c404",
"price": 25000
},
{
"itemID": "5bc9b355d4351e6d1509862a",
"price": 24000
},
{
"itemID": "60391a8b3364dc22b04d0ce5",
"price": 45000
},
{
"itemID": "5734795124597738002c6176",
"price": 19000
},
{
"itemID": "5d1c774f86f7746d6620f8db",
"price": 14000
},
{
"itemID": "619cbf476b8a1b37a54eebf8",
"price": 19000
},
{
"itemID": "57347c2e24597744902c94a1",
"price": 60000
},
{
"itemID": "5d1b327086f7742525194449",
"price": 45000
},
{
"itemID": "5af0534a86f7743b6f354284",
"price": 89000
},
{
"itemID": "5e2af22086f7746d3f3c33fa",
"price": 12000
},
{
"itemID": "5c06782b86f77426df5407d2",
"price": 15000
},
{
"itemID": "590c639286f774151567fa95",
"price": 22000
},
{
"itemID": "5d0378d486f77420421a5ff4",
"price": 340000
},
{
"itemID": "590c595c86f7747884343ad7",
"price": 48000
},
{
"itemID": "5d0375ff86f774186372f685",
"price": 34000
},
{
"itemID": "5d03775b86f774203e7e0c4b",
"price": 100000
},
{
"itemID": "5af0484c86f7740f02001f7f",
"price": 12000
},
{
"itemID": "59e35abd86f7741778269d82",
"price": 25000
},
{
"itemID": "5e2af00086f7746d3f3c33f7",
"price": 13000
},
{
"itemID": "590c35a486f774273531c822",
"price": 35000
},
{
"itemID": "60391afc25aff57af81f7085",
"price": 74000
},
{
"itemID": "5e2aedd986f7746d404f3aa4",
"price": 180000
},
{
"itemID": "573478bc24597738002c6175",
"price": 19000
},
{
"itemID": "573474f924597738002c6174",
"price": 5000
},
{
"itemID": "590c645c86f77412b01304d9",
"price": 26000
},
{
"itemID": "590c651286f7741e566b6461",
"price": 38000
},
{
"itemID": "62a09e73af34e73a266d932a",
"price": 26000
},
{
"itemID": "590c621186f774138d11ea29",
"price": 19000
},
{
"itemID": "590a386e86f77429692b27ab",
"price": 13000
},
{
"itemID": "59e3639286f7741777737013",
"price": 105000
},
{
"itemID": "5d235a5986f77443f6329bc6",
"price": 50000
},
{
"itemID": "5734758f24597738025ee253",
"price": 28000
},
{
"itemID": "59faf7ca86f7740dbe19f6c2",
"price": 55000
},
{
"itemID": "5d1b376e86f774252519444e",
"price": 325000
},
{
"itemID": "5bc9bc53d4351e00367fbcee",
"price": 57000
},
{
"itemID": "57347cd0245977445a2d6ff1",
"price": 12000
},
{
"itemID": "5d1b39a386f774252339976f",
"price": 15000
},
{
"itemID": "5d1b32c186f774252167a530",
"price": 27000
},
{
"itemID": "619cbfccbedcde2f5b3f7bdd",
"price": 75000
},
{
"itemID": "5c052f6886f7746b1e3db148",
"price": 90000
},
{
"itemID": "62a0a16d0b9d3c46de5b6e97",
"price": 155000
},
{
"itemID": "61bf7c024770ee6f9c6b8b53",
"price": 65000
},
{
"itemID": "5c12613b86f7743bbe2c3f76",
"price": 375000
},
{
"itemID": "5c05300686f7746dce784e5d",
"price": 125000
}
],
"barterItems": [
{
"itemID": "5c0530ee86f774697952d952",
"price": 1290504,
"barterAmount": 3,
"barterItemID": "59faff1d86f7746c51718c9c"
},
{
"itemID": "6389c85357baa773a825b356",
"price": 4596724,
"barterAmount": 8,
"barterItemID": "59faff1d86f7746c51718c9c"
},
{
"itemID": "6389c7f115805221fb410466",
"price": 1932786,
"barterAmount": 4,
"barterItemID": "59faff1d86f7746c51718c9c"
},
{
"itemID": "5d03794386f77420415576f5",
"price": 217169,
"barterAmount": 1,
"barterItemID": "59faff1d86f7746c51718c9c"
},
{
"itemID": "5b4391a586f7745321235ab2",
"price": 37189,
"barterAmount": 3,
"barterItemID": "5991b51486f77447b112d44f"
},
{
"itemID": "5b7c710788a4506dec015957",
"price": 1081368,
"barterAmount": 2,
"barterItemID": "59faff1d86f7746c51718c9c"
}
]
}
@@ -0,0 +1,92 @@
{
"_id": "HarryHideout",
"working": true,
"availableInRaid": false,
"items_buy": {
"category": [
"5448eb774bdc2d0a728b4567"
],
"id_list": []
},
"items_buy_prohibited": {},
"customization_seller": false,
"name": "Harry",
"surname": "Hideout",
"nickname": "Hideout Harry",
"location": "I'm sellin', what are you buyin'?",
"avatar": "/files/trader/avatar/harry.jpg",
"balance_rub": 5000000,
"balance_dol": 0,
"balance_eur": 0,
"unlockedByDefault": true,
"discount": 0,
"discount_end": 0,
"buyer_up": true,
"currency": "RUB",
"nextResupply": 1615141448,
"repair": {
"availability": false,
"quality": "2",
"excluded_id_list": [],
"excluded_category": [],
"currency": "5449016a4bdc2d6f028b456f",
"currency_coefficient": 1,
"price_rate": 10
},
"insurance": {
"availability": false,
"min_payment": 0,
"min_return_hour": 0,
"max_return_hour": 0,
"max_storage_time": 99,
"excluded_category": []
},
"gridHeight": 150,
"loyaltyLevels": [{
"minLevel": 1,
"minSalesSum": 0,
"minStanding": 0,
"buy_price_coef": 38,
"repair_price_coef": 175,
"insurance_price_coef": 10,
"exchange_price_coef": 0,
"heal_price_coef": 0
}
],
"sell_category": [
"82e7fac0b7495d72d4083356",
"ac705d3440c1407645e33579",
"dc97aee367144dc03389405d",
"7ffcc96aa06c7e90940330c5",
"e8f46e3ad74b9d862121f9dc",
"5b47574386f77428ca22b33e",
"5b47574386f77428ca22b33f",
"5b5f78dc86f77409407a7f8e",
"5b47574386f77428ca22b346",
"5b47574386f77428ca22b340",
"5b47574386f77428ca22b344",
"5b47574386f77428ca22b342",
"5b47574386f77428ca22b341",
"5b47574386f77428ca22b345",
"5b47574386f77428ca22b343",
"5b5f71b386f774093f2ecf11",
"5b5f71c186f77409407a7ec0",
"5b5f71de86f774093f2ecf13",
"5b5f724186f77447ed5636ad",
"5b5f736886f774094242f193",
"5b5f73ec86f774093e6cb4fd",
"5b5f74cc86f77447ec5d770a",
"5b5f750686f774093e6cb503",
"5b5f751486f77447ec5d770c",
"5b5f752e86f774093e6cb505",
"5b5f754a86f774094242f19b",
"5b5f755f86f77447ec5d770e",
"5b5f757486f774093e6cb507",
"5b5f75b986f77447ec5d7710",
"5b5f75c686f774094242f19f",
"5b5f75e486f77447ec5d7712",
"5b5f760586f774093e6cb509",
"5b5f761f86f774094242f1a1",
"5b5f764186f77447ec5d7714"
]
}
@@ -0,0 +1,30 @@
{
"name": "HarryHideout",
"version": "1.0.3",
"main": "src/mod.js",
"license": "MIT",
"author": "acidphantasm",
"akiVersion": "~3.8",
"loadBefore": [],
"loadAfter": [],
"incompatibilities": [],
"contributors": [],
"scripts": {
"setup": "npm i",
"build": "node ./build.mjs",
"buildinfo": "node ./build.mjs --verbose"
},
"devDependencies": {
"@types/node": "20.11",
"@typescript-eslint/eslint-plugin": "7.2",
"@typescript-eslint/parser": "7.2",
"archiver": "^6.0",
"eslint": "8.57",
"fs-extra": "11.2",
"ignore": "^5.2",
"os": "^0.1",
"tsyringe": "4.8.0",
"typescript": "5.4",
"winston": "3.12"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

@@ -0,0 +1,126 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FluentAssortConstructor = void 0;
class FluentAssortConstructor {
itemsToSell = [];
barterScheme = {};
loyaltyLevel = {};
hashUtil;
logger;
constructor(hashutil, logger) {
this.hashUtil = hashutil;
this.logger = logger;
}
/**
* Start selling item with tpl
* @param itemTpl Tpl id of the item you want trader to sell
* @param itemId Optional - set your own Id, otherwise unique id will be generated
*/
createSingleAssortItem(itemTpl, itemId = undefined) {
// Create item ready for insertion into assort table
const newItemToAdd = {
_id: !itemId ? this.hashUtil.generate() : itemId,
_tpl: itemTpl,
parentId: "hideout", // Should always be "hideout"
slotId: "hideout", // Should always be "hideout"
upd: {
UnlimitedCount: false,
StackObjectsCount: 100
}
};
this.itemsToSell.push(newItemToAdd);
return this;
}
createComplexAssortItem(items) {
items[0].parentId = "hideout";
items[0].slotId = "hideout";
if (!items[0].upd) {
items[0].upd = {};
}
items[0].upd.UnlimitedCount = false;
items[0].upd.StackObjectsCount = 100;
this.itemsToSell.push(...items);
return this;
}
addStackCount(stackCount) {
this.itemsToSell[0].upd.StackObjectsCount = stackCount;
return this;
}
addUnlimitedStackCount() {
this.itemsToSell[0].upd.StackObjectsCount = 999999;
this.itemsToSell[0].upd.UnlimitedCount = true;
return this;
}
makeStackCountUnlimited() {
this.itemsToSell[0].upd.StackObjectsCount = 999999;
return this;
}
addBuyRestriction(maxBuyLimit) {
this.itemsToSell[0].upd.BuyRestrictionMax = maxBuyLimit;
this.itemsToSell[0].upd.BuyRestrictionCurrent = 0;
return this;
}
addLoyaltyLevel(level) {
this.loyaltyLevel[this.itemsToSell[0]._id] = level;
return this;
}
addMoneyCost(currencyType, amount) {
this.barterScheme[this.itemsToSell[0]._id] = [
[
{
count: amount,
_tpl: currencyType
}
]
];
return this;
}
addBarterCost(itemTpl, count) {
const sellableItemId = this.itemsToSell[0]._id;
// No data at all, create
if (Object.keys(this.barterScheme).length === 0) {
this.barterScheme[sellableItemId] = [[
{
count: count,
_tpl: itemTpl
}
]];
}
else {
// Item already exists, add to
const existingData = this.barterScheme[sellableItemId][0].find(x => x._tpl === itemTpl);
if (existingData) {
// itemtpl already a barter for item, add to count
existingData.count += count;
}
else {
// No barter for item, add it fresh
this.barterScheme[sellableItemId][0].push({
count: count,
_tpl: itemTpl
});
}
}
return this;
}
/**
* Reset objet ready for reuse
* @returns
*/
export(data) {
const itemBeingSoldId = this.itemsToSell[0]._id;
if (data.assort.items.find(x => x._id === itemBeingSoldId)) {
this.logger.error(`Unable to add complex item with item key ${this.itemsToSell[0]._id}, key already used`);
return;
}
data.assort.items.push(...this.itemsToSell);
data.assort.barter_scheme[itemBeingSoldId] = this.barterScheme[itemBeingSoldId];
data.assort.loyal_level_items[itemBeingSoldId] = this.loyaltyLevel[itemBeingSoldId];
this.itemsToSell = [];
this.barterScheme = {};
this.loyaltyLevel = {};
return this;
}
}
exports.FluentAssortConstructor = FluentAssortConstructor;
//# sourceMappingURL=fluentTraderAssortCreator.js.map
@@ -0,0 +1 @@
{"version":3,"file":"fluentTraderAssortCreator.js","sourceRoot":"","sources":["fluentTraderAssortCreator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,175 @@
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
import { IBarterScheme, ITrader } from "@spt-aki/models/eft/common/tables/ITrader";
import { Money } from "@spt-aki/models/enums/Money";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { HashUtil } from "@spt-aki/utils/HashUtil";
export class FluentAssortConstructor
{
protected itemsToSell: Item[] = [];
protected barterScheme: Record<string, IBarterScheme[][]> = {};
protected loyaltyLevel: Record<string, number> = {};
protected hashUtil: HashUtil;
protected logger: ILogger;
constructor(hashutil: HashUtil, logger: ILogger)
{
this.hashUtil = hashutil
this.logger = logger;
}
/**
* Start selling item with tpl
* @param itemTpl Tpl id of the item you want trader to sell
* @param itemId Optional - set your own Id, otherwise unique id will be generated
*/
public createSingleAssortItem(itemTpl: string, itemId = undefined): FluentAssortConstructor
{
// Create item ready for insertion into assort table
const newItemToAdd: Item = {
_id: !itemId ? this.hashUtil.generate(): itemId,
_tpl: itemTpl,
parentId: "hideout", // Should always be "hideout"
slotId: "hideout", // Should always be "hideout"
upd: {
UnlimitedCount: false,
StackObjectsCount: 100
}
};
this.itemsToSell.push(newItemToAdd);
return this;
}
public createComplexAssortItem(items: Item[]): FluentAssortConstructor
{
items[0].parentId = "hideout";
items[0].slotId = "hideout";
if (!items[0].upd)
{
items[0].upd = {}
}
items[0].upd.UnlimitedCount = false;
items[0].upd.StackObjectsCount = 100;
this.itemsToSell.push(...items);
return this;
}
public addStackCount(stackCount: number): FluentAssortConstructor
{
this.itemsToSell[0].upd.StackObjectsCount = stackCount;
return this;
}
public addUnlimitedStackCount(): FluentAssortConstructor
{
this.itemsToSell[0].upd.StackObjectsCount = 999999;
this.itemsToSell[0].upd.UnlimitedCount = true;
return this;
}
public makeStackCountUnlimited(): FluentAssortConstructor
{
this.itemsToSell[0].upd.StackObjectsCount = 999999;
return this;
}
public addBuyRestriction(maxBuyLimit: number): FluentAssortConstructor
{
this.itemsToSell[0].upd.BuyRestrictionMax = maxBuyLimit;
this.itemsToSell[0].upd.BuyRestrictionCurrent = 0;
return this;
}
public addLoyaltyLevel(level: number)
{
this.loyaltyLevel[this.itemsToSell[0]._id] = level;
return this;
}
public addMoneyCost(currencyType: Money, amount: number): FluentAssortConstructor
{
this.barterScheme[this.itemsToSell[0]._id] = [
[
{
count: amount,
_tpl: currencyType
}
]
];
return this;
}
public addBarterCost(itemTpl: string, count: number): FluentAssortConstructor
{
const sellableItemId = this.itemsToSell[0]._id;
// No data at all, create
if (Object.keys(this.barterScheme).length === 0)
{
this.barterScheme[sellableItemId] = [[
{
count: count,
_tpl: itemTpl
}
]];
}
else
{
// Item already exists, add to
const existingData = this.barterScheme[sellableItemId][0].find(x => x._tpl === itemTpl);
if (existingData)
{
// itemtpl already a barter for item, add to count
existingData.count+= count;
}
else
{
// No barter for item, add it fresh
this.barterScheme[sellableItemId][0].push({
count: count,
_tpl: itemTpl
})
}
}
return this;
}
/**
* Reset objet ready for reuse
* @returns
*/
public export(data: ITrader): FluentAssortConstructor
{
const itemBeingSoldId = this.itemsToSell[0]._id;
if (data.assort.items.find(x => x._id === itemBeingSoldId))
{
this.logger.error(`Unable to add complex item with item key ${this.itemsToSell[0]._id}, key already used`);
return;
}
data.assort.items.push(...this.itemsToSell);
data.assort.barter_scheme[itemBeingSoldId] = this.barterScheme[itemBeingSoldId];
data.assort.loyal_level_items[itemBeingSoldId] = this.loyaltyLevel[itemBeingSoldId];
this.itemsToSell = [];
this.barterScheme = {};
this.loyaltyLevel = {};
return this;
}
}
@@ -0,0 +1,161 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const ConfigTypes_1 = require("/snapshot/project/obj/models/enums/ConfigTypes");
const fs = __importStar(require("node:fs"));
const path = __importStar(require("node:path"));
// New trader settings
const baseJson = __importStar(require("../db/base.json"));
const traderHelpers_1 = require("./traderHelpers");
const fluentTraderAssortCreator_1 = require("./fluentTraderAssortCreator");
const Money_1 = require("/snapshot/project/obj/models/enums/Money");
const Traders_1 = require("/snapshot/project/obj/models/enums/Traders");
class HideoutHarry {
mod;
logger;
traderHelper;
fluentAssortCreator;
static config;
static itemsPath = path.resolve(__dirname, "../config/items.json");
static configPath = path.resolve(__dirname, "../config/config.json");
constructor() {
this.mod = "acidphantasm-harryhideout"; // Set name of mod so we can log it to console later
}
/**
* Some work needs to be done prior to SPT code being loaded, registering the profile image + setting trader update time inside the trader config json
* @param container Dependency container
*/
preAkiLoad(container) {
// Get a logger
this.logger = container.resolve("WinstonLogger");
// Get SPT code/data we need later
const preAkiModLoader = container.resolve("PreAkiModLoader");
const imageRouter = container.resolve("ImageRouter");
const hashUtil = container.resolve("HashUtil");
const configServer = container.resolve("ConfigServer");
const traderConfig = configServer.getConfig(ConfigTypes_1.ConfigTypes.TRADER);
const ragfairConfig = configServer.getConfig(ConfigTypes_1.ConfigTypes.RAGFAIR);
// Create helper class and use it to register our traders image/icon + set its stock refresh time
this.traderHelper = new traderHelpers_1.TraderHelper();
this.fluentAssortCreator = new fluentTraderAssortCreator_1.FluentAssortConstructor(hashUtil, this.logger);
this.traderHelper.registerProfileImage(baseJson, this.mod, preAkiModLoader, imageRouter, "harry.jpg");
this.traderHelper.setTraderUpdateTime(traderConfig, baseJson, 3600, 4000);
// Add trader to trader enum
Traders_1.Traders[baseJson._id] = baseJson._id;
// Add trader to flea market
ragfairConfig.traders[baseJson._id] = true;
}
/**
* Majority of trader-related work occurs after the aki database has been loaded but prior to SPT code being run
* @param container Dependency container
*/
postDBLoad(container) {
HideoutHarry.config = JSON.parse(fs.readFileSync(HideoutHarry.configPath, "utf-8"));
// Resolve SPT classes we'll use
const logger = container.resolve("WinstonLogger");
const databaseServer = container.resolve("DatabaseServer");
const configServer = container.resolve("ConfigServer");
const jsonUtil = container.resolve("JsonUtil");
const priceTable = databaseServer.getTables().templates.prices;
const handbookTable = databaseServer.getTables().templates.handbook;
// Get a reference to the database tables
const tables = databaseServer.getTables();
// Add new trader to the trader dictionary in DatabaseServer - has no assorts (items) yet
this.traderHelper.addTraderToDb(baseJson, tables, jsonUtil);
const start = performance.now();
const itemList = JSON.parse(fs.readFileSync(HideoutHarry.itemsPath, "utf-8"));
const nonBarterItems = itemList.nonBarterItems;
const barterItems = itemList.barterItems;
const lowFleaRange = 0.85;
// Non-Barter Items Iteration
for (const item in nonBarterItems) {
{
const itemID = nonBarterItems[item].itemID;
if (HideoutHarry.config.useFleaPrices) {
let price = (priceTable[itemID] * HideoutHarry.config.itemPriceMultiplier);
if (!price) {
price = (handbookTable.Items.find(x => x.Id === itemID)?.Price ?? 1) * HideoutHarry.config.itemPriceMultiplier;
}
this.fluentAssortCreator.createSingleAssortItem(itemID)
.addUnlimitedStackCount()
.addMoneyCost(Money_1.Money.ROUBLES, Math.round(price * lowFleaRange))
.addLoyaltyLevel(1)
.export(tables.traders[baseJson._id]);
if (HideoutHarry.config.enableConsoleDebug) {
logger.log("ItemID: " + itemID + " for price: " + Math.round(price), "cyan");
}
}
else {
const price = nonBarterItems[item].price;
this.fluentAssortCreator.createSingleAssortItem(itemID)
.addUnlimitedStackCount()
.addMoneyCost(Money_1.Money.ROUBLES, Math.round(price * lowFleaRange))
.addLoyaltyLevel(1)
.export(tables.traders[baseJson._id]);
if (HideoutHarry.config.enableConsoleDebug) {
logger.log("ItemID: " + itemID + " for price: " + Math.round(price), "cyan");
}
}
}
}
// Barter Items Iteration
for (const item in barterItems) {
{
const itemID = barterItems[item].itemID;
const barterItem = barterItems[item].barterItemID;
const barterAmount = barterItems[item].barterAmount;
if (HideoutHarry.config.useBarters) {
this.fluentAssortCreator.createSingleAssortItem(itemID)
.addUnlimitedStackCount()
.addBarterCost(barterItem, barterAmount)
.addLoyaltyLevel(1)
.export(tables.traders[baseJson._id]);
if (HideoutHarry.config.enableConsoleDebug) {
logger.log("ItemID: " + itemID + " for barter: " + barterAmount + " " + barterItem, "cyan");
}
}
else {
const price = barterItems[item].price;
this.fluentAssortCreator.createSingleAssortItem(itemID)
.addUnlimitedStackCount()
.addMoneyCost(Money_1.Money.ROUBLES, Math.round(price))
.addLoyaltyLevel(1)
.export(tables.traders[baseJson._id]);
if (HideoutHarry.config.enableConsoleDebug) {
logger.log("ItemID: " + itemID + " for price: " + Math.round(price), "cyan");
}
}
}
}
// Add trader to locale file, ensures trader text shows properly on screen
// WARNING: adds the same text to ALL locales (e.g. chinese/french/english)
this.traderHelper.addTraderToLocales(baseJson, tables, baseJson.name, "Hideout Harry", baseJson.nickname, baseJson.location, "I'm sellin', what are you buyin'?");
this.logger.debug(`[${this.mod}] loaded... `);
const timeTaken = performance.now() - start;
logger.log(`[${this.mod}] Assort generation took ${timeTaken.toFixed(3)}ms.`, "green");
}
}
module.exports = { mod: new HideoutHarry() };
//# sourceMappingURL=mod.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,184 @@
import { DependencyContainer } from "tsyringe";
// SPT types
import { IPreAkiLoadMod } from "@spt-aki/models/external/IPreAkiLoadMod";
import { IPostDBLoadMod } from "@spt-aki/models/external/IPostDBLoadMod";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
import { ImageRouter } from "@spt-aki/routers/ImageRouter";
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
import { ITraderConfig } from "@spt-aki/models/spt/config/ITraderConfig";
import { IRagfairConfig } from "@spt-aki/models/spt/config/IRagfairConfig";
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
import * as fs from "node:fs";
import * as path from "node:path";
// New trader settings
import * as baseJson from "../db/base.json";
import { TraderHelper } from "./traderHelpers";
import { FluentAssortConstructor as FluentAssortCreator } from "./fluentTraderAssortCreator";
import { Money } from "@spt-aki/models/enums/Money";
import { Traders } from "@spt-aki/models/enums/Traders";
import { HashUtil } from "@spt-aki/utils/HashUtil";
class HideoutHarry implements IPreAkiLoadMod, IPostDBLoadMod
{
private mod: string
private logger: ILogger
private traderHelper: TraderHelper
private fluentAssortCreator: FluentAssortCreator
private static config: Config;
private static itemsPath = path.resolve(__dirname, "../config/items.json");
private static configPath = path.resolve(__dirname, "../config/config.json");
constructor() {
this.mod = "acidphantasm-harryhideout"; // Set name of mod so we can log it to console later
}
/**
* Some work needs to be done prior to SPT code being loaded, registering the profile image + setting trader update time inside the trader config json
* @param container Dependency container
*/
public preAkiLoad(container: DependencyContainer): void
{
// Get a logger
this.logger = container.resolve<ILogger>("WinstonLogger");
// Get SPT code/data we need later
const preAkiModLoader: PreAkiModLoader = container.resolve<PreAkiModLoader>("PreAkiModLoader");
const imageRouter: ImageRouter = container.resolve<ImageRouter>("ImageRouter");
const hashUtil: HashUtil = container.resolve<HashUtil>("HashUtil");
const configServer = container.resolve<ConfigServer>("ConfigServer");
const traderConfig: ITraderConfig = configServer.getConfig<ITraderConfig>(ConfigTypes.TRADER);
const ragfairConfig = configServer.getConfig<IRagfairConfig>(ConfigTypes.RAGFAIR);
// Create helper class and use it to register our traders image/icon + set its stock refresh time
this.traderHelper = new TraderHelper();
this.fluentAssortCreator = new FluentAssortCreator(hashUtil, this.logger);
this.traderHelper.registerProfileImage(baseJson, this.mod, preAkiModLoader, imageRouter, "harry.jpg");
this.traderHelper.setTraderUpdateTime(traderConfig, baseJson, 3600, 4000);
// Add trader to trader enum
Traders[baseJson._id] = baseJson._id;
// Add trader to flea market
ragfairConfig.traders[baseJson._id] = true;
}
/**
* Majority of trader-related work occurs after the aki database has been loaded but prior to SPT code being run
* @param container Dependency container
*/
public postDBLoad(container: DependencyContainer): void
{
HideoutHarry.config = JSON.parse(fs.readFileSync(HideoutHarry.configPath, "utf-8"));
// Resolve SPT classes we'll use
const logger = container.resolve<ILogger>("WinstonLogger");
const databaseServer: DatabaseServer = container.resolve<DatabaseServer>("DatabaseServer");
const configServer: ConfigServer = container.resolve<ConfigServer>("ConfigServer");
const jsonUtil: JsonUtil = container.resolve<JsonUtil>("JsonUtil");
const priceTable = databaseServer.getTables().templates.prices;
const handbookTable = databaseServer.getTables().templates.handbook;
// Get a reference to the database tables
const tables = databaseServer.getTables();
// Add new trader to the trader dictionary in DatabaseServer - has no assorts (items) yet
this.traderHelper.addTraderToDb(baseJson, tables, jsonUtil);
const start = performance.now();
const itemList = JSON.parse(fs.readFileSync(HideoutHarry.itemsPath, "utf-8"));
const nonBarterItems = itemList.nonBarterItems;
const barterItems = itemList.barterItems;
const lowFleaRange = 0.85;
// Non-Barter Items Iteration
for (const item in nonBarterItems){
{
const itemID = nonBarterItems[item].itemID;
if (HideoutHarry.config.useFleaPrices)
{
let price = (priceTable[itemID] * HideoutHarry.config.itemPriceMultiplier);
if (!price)
{
price = (handbookTable.Items.find(x => x.Id === itemID)?.Price ?? 1) * HideoutHarry.config.itemPriceMultiplier;
}
this.fluentAssortCreator.createSingleAssortItem(itemID)
.addUnlimitedStackCount()
.addMoneyCost(Money.ROUBLES, Math.round(price * lowFleaRange))
.addLoyaltyLevel(1)
.export(tables.traders[baseJson._id])
if (HideoutHarry.config.enableConsoleDebug){
logger.log("ItemID: " + itemID + " for price: " + Math.round(price), "cyan");
}
}
else
{
const price = nonBarterItems[item].price
this.fluentAssortCreator.createSingleAssortItem(itemID)
.addUnlimitedStackCount()
.addMoneyCost(Money.ROUBLES, Math.round(price * lowFleaRange))
.addLoyaltyLevel(1)
.export(tables.traders[baseJson._id]);
if (HideoutHarry.config.enableConsoleDebug){
logger.log("ItemID: " + itemID + " for price: " + Math.round(price), "cyan");
}
}
}
}
// Barter Items Iteration
for (const item in barterItems){
{
const itemID = barterItems[item].itemID;
const barterItem = barterItems[item].barterItemID;
const barterAmount = barterItems[item].barterAmount;
if (HideoutHarry.config.useBarters)
{
this.fluentAssortCreator.createSingleAssortItem(itemID)
.addUnlimitedStackCount()
.addBarterCost(barterItem, barterAmount)
.addLoyaltyLevel(1)
.export(tables.traders[baseJson._id])
if (HideoutHarry.config.enableConsoleDebug){
logger.log("ItemID: " + itemID + " for barter: " + barterAmount + " "+ barterItem, "cyan");
}
}
else
{
const price = barterItems[item].price
this.fluentAssortCreator.createSingleAssortItem(itemID)
.addUnlimitedStackCount()
.addMoneyCost(Money.ROUBLES, Math.round(price))
.addLoyaltyLevel(1)
.export(tables.traders[baseJson._id]);
if (HideoutHarry.config.enableConsoleDebug){
logger.log("ItemID: " + itemID + " for price: " + Math.round(price), "cyan");
}
}
}
}
// Add trader to locale file, ensures trader text shows properly on screen
// WARNING: adds the same text to ALL locales (e.g. chinese/french/english)
this.traderHelper.addTraderToLocales(baseJson, tables, baseJson.name, "Hideout Harry", baseJson.nickname, baseJson.location, "I'm sellin', what are you buyin'?");
this.logger.debug(`[${this.mod}] loaded... `);
const timeTaken = performance.now() - start;
logger.log(`[${this.mod}] Assort generation took ${timeTaken.toFixed(3)}ms.`, "green");
}
}
interface Config
{
useBarters: boolean,
itemPriceMultiplier: number,
useFleaPrices: boolean,
enableConsoleDebug: boolean,
}
module.exports = { mod: new HideoutHarry() }
@@ -0,0 +1,94 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TraderHelper = void 0;
class TraderHelper {
/**
* Add profile picture to our trader
* @param baseJson json file for trader (db/base.json)
* @param preAkiModLoader mod loader class - used to get the mods file path
* @param imageRouter image router class - used to register the trader image path so we see their image on trader page
* @param traderImageName Filename of the trader icon to use
*/
registerProfileImage(baseJson, modName, preAkiModLoader, imageRouter, traderImageName) {
// Reference the mod "res" folder
const imageFilepath = `./${preAkiModLoader.getModPath(modName)}res`;
// Register a route to point to the profile picture - remember to remove the .jpg from it
imageRouter.addRoute(baseJson.avatar.replace(".jpg", ""), `${imageFilepath}/${traderImageName}`);
}
/**
* Add record to trader config to set the refresh time of trader in seconds (default is 60 minutes)
* @param traderConfig trader config to add our trader to
* @param baseJson json file for trader (db/base.json)
* @param refreshTimeSecondsMin How many seconds between trader stock refresh min time
* @param refreshTimeSecondsMax How many seconds between trader stock refresh max time
*/
setTraderUpdateTime(traderConfig, baseJson, refreshTimeSecondsMin, refreshTimeSecondsMax) {
// Add refresh time in seconds to config
const traderRefreshRecord = {
traderId: baseJson._id,
seconds: {
min: refreshTimeSecondsMin,
max: refreshTimeSecondsMax
}
};
traderConfig.updateTime.push(traderRefreshRecord);
}
/**
* Add our new trader to the database
* @param traderDetailsToAdd trader details
* @param tables database
* @param jsonUtil json utility class
*/
// rome-ignore lint/suspicious/noExplicitAny: traderDetailsToAdd comes from base.json, so no type
addTraderToDb(traderDetailsToAdd, tables, jsonUtil) {
// Add trader to trader table, key is the traders id
tables.traders[traderDetailsToAdd._id] = {
assort: this.createAssortTable(), // assorts are the 'offers' trader sells, can be a single item (e.g. carton of milk) or multiple items as a collection (e.g. a gun)
base: jsonUtil.deserialize(jsonUtil.serialize(traderDetailsToAdd)), // Deserialise/serialise creates a copy of the json and allows us to cast it as an ITraderBase
questassort: {
started: {},
success: {},
fail: {}
} // questassort is empty as trader has no assorts unlocked by quests
};
}
/**
* Create basic data for trader + add empty assorts table for trader
* @param tables SPT db
* @param jsonUtil SPT JSON utility class
* @returns ITraderAssort
*/
createAssortTable() {
// Create a blank assort object, ready to have items added
const assortTable = {
nextResupply: 0,
items: [],
barter_scheme: {},
loyal_level_items: {}
};
return assortTable;
}
/**
* Add traders name/location/description to the locale table
* @param baseJson json file for trader (db/base.json)
* @param tables database tables
* @param fullName Complete name of trader
* @param firstName First name of trader
* @param nickName Nickname of trader
* @param location Location of trader (e.g. "Here in the cat shop")
* @param description Description of trader
*/
addTraderToLocales(baseJson, tables, fullName, firstName, nickName, location, description) {
// For each language, add locale for the new trader
const locales = Object.values(tables.locales.global);
for (const locale of locales) {
locale[`${baseJson._id} FullName`] = fullName;
locale[`${baseJson._id} FirstName`] = firstName;
locale[`${baseJson._id} Nickname`] = nickName;
locale[`${baseJson._id} Location`] = location;
locale[`${baseJson._id} Description`] = description;
}
}
}
exports.TraderHelper = TraderHelper;
//# sourceMappingURL=traderHelpers.js.map
@@ -0,0 +1 @@
{"version":3,"file":"traderHelpers.js","sourceRoot":"","sources":["traderHelpers.ts"],"names":[],"mappings":";;;AAOA,MAAa,YAAY;IAErB;;;;;;OAMG;IACI,oBAAoB,CAAC,QAAa,EAAE,OAAe,EAAE,eAAgC,EAAE,WAAwB,EAAE,eAAuB;QAE3I,iCAAiC;QACjC,MAAM,aAAa,GAAG,KAAK,eAAe,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC;QAEpE,yFAAyF;QACzF,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,GAAG,aAAa,IAAI,eAAe,EAAE,CAAC,CAAC;IACrG,CAAC;IAED;;;;;;OAMG;IACI,mBAAmB,CAAC,YAA2B,EAAE,QAAa,EAAE,qBAA6B,EAAE,qBAA6B;QAE/H,wCAAwC;QACxC,MAAM,mBAAmB,GAAe;YACpC,QAAQ,EAAE,QAAQ,CAAC,GAAG;YACtB,OAAO,EAAE;gBACL,GAAG,EAAE,qBAAqB;gBAC1B,GAAG,EAAE,qBAAqB;aAC7B;SAAE,CAAC;QAER,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACtD,CAAC;IAED;;;;;OAKG;IACH,iGAAiG;IAC1F,aAAa,CAAC,kBAAuB,EAAE,MAAuB,EAAE,QAAkB;QAErF,oDAAoD;QACpD,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG;YACrC,MAAM,EAAE,IAAI,CAAC,iBAAiB,EAAE,EAAE,mIAAmI;YACrK,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAgB,EAAE,8FAA8F;YACjL,WAAW,EAAE;gBACT,OAAO,EAAE,EAAE;gBACX,OAAO,EAAE,EAAE;gBACX,IAAI,EAAE,EAAE;aACX,CAAC,mEAAmE;SACxE,CAAC;IACN,CAAC;IAED;;;;;OAKG;IACK,iBAAiB;QAErB,0DAA0D;QAC1D,MAAM,WAAW,GAAkB;YAC/B,YAAY,EAAE,CAAC;YACf,KAAK,EAAE,EAAE;YACT,aAAa,EAAE,EAAE;YACjB,iBAAiB,EAAE,EAAE;SACxB,CAAA;QAED,OAAO,WAAW,CAAC;IACvB,CAAC;IAED;;;;;;;;;OASG;IACI,kBAAkB,CAAC,QAAa,EAAE,MAAuB,EAAE,QAAgB,EAAE,SAAiB,EAAE,QAAgB,EAAE,QAAgB,EAAE,WAAmB;QAE1J,mDAAmD;QACnD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAA6B,CAAC;QACjF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC3B,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,WAAW,CAAC,GAAG,QAAQ,CAAC;YAC9C,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,YAAY,CAAC,GAAG,SAAS,CAAC;YAChD,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,WAAW,CAAC,GAAG,QAAQ,CAAC;YAC9C,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,WAAW,CAAC,GAAG,QAAQ,CAAC;YAC9C,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,cAAc,CAAC,GAAG,WAAW,CAAC;QACxD,CAAC;IACL,CAAC;CACJ;AApGD,oCAoGC"}
@@ -0,0 +1,108 @@
import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";
import { ITraderBase, ITraderAssort } from "@spt-aki/models/eft/common/tables/ITrader";
import { ITraderConfig, UpdateTime } from "@spt-aki/models/spt/config/ITraderConfig";
import { IDatabaseTables } from "@spt-aki/models/spt/server/IDatabaseTables";
import { ImageRouter } from "@spt-aki/routers/ImageRouter";
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
export class TraderHelper
{
/**
* Add profile picture to our trader
* @param baseJson json file for trader (db/base.json)
* @param preAkiModLoader mod loader class - used to get the mods file path
* @param imageRouter image router class - used to register the trader image path so we see their image on trader page
* @param traderImageName Filename of the trader icon to use
*/
public registerProfileImage(baseJson: any, modName: string, preAkiModLoader: PreAkiModLoader, imageRouter: ImageRouter, traderImageName: string): void
{
// Reference the mod "res" folder
const imageFilepath = `./${preAkiModLoader.getModPath(modName)}res`;
// Register a route to point to the profile picture - remember to remove the .jpg from it
imageRouter.addRoute(baseJson.avatar.replace(".jpg", ""), `${imageFilepath}/${traderImageName}`);
}
/**
* Add record to trader config to set the refresh time of trader in seconds (default is 60 minutes)
* @param traderConfig trader config to add our trader to
* @param baseJson json file for trader (db/base.json)
* @param refreshTimeSecondsMin How many seconds between trader stock refresh min time
* @param refreshTimeSecondsMax How many seconds between trader stock refresh max time
*/
public setTraderUpdateTime(traderConfig: ITraderConfig, baseJson: any, refreshTimeSecondsMin: number, refreshTimeSecondsMax: number): void
{
// Add refresh time in seconds to config
const traderRefreshRecord: UpdateTime = {
traderId: baseJson._id,
seconds: {
min: refreshTimeSecondsMin,
max: refreshTimeSecondsMax
} };
traderConfig.updateTime.push(traderRefreshRecord);
}
/**
* Add our new trader to the database
* @param traderDetailsToAdd trader details
* @param tables database
* @param jsonUtil json utility class
*/
// rome-ignore lint/suspicious/noExplicitAny: traderDetailsToAdd comes from base.json, so no type
public addTraderToDb(traderDetailsToAdd: any, tables: IDatabaseTables, jsonUtil: JsonUtil): void
{
// Add trader to trader table, key is the traders id
tables.traders[traderDetailsToAdd._id] = {
assort: this.createAssortTable(), // assorts are the 'offers' trader sells, can be a single item (e.g. carton of milk) or multiple items as a collection (e.g. a gun)
base: jsonUtil.deserialize(jsonUtil.serialize(traderDetailsToAdd)) as ITraderBase, // Deserialise/serialise creates a copy of the json and allows us to cast it as an ITraderBase
questassort: {
started: {},
success: {},
fail: {}
} // questassort is empty as trader has no assorts unlocked by quests
};
}
/**
* Create basic data for trader + add empty assorts table for trader
* @param tables SPT db
* @param jsonUtil SPT JSON utility class
* @returns ITraderAssort
*/
private createAssortTable(): ITraderAssort
{
// Create a blank assort object, ready to have items added
const assortTable: ITraderAssort = {
nextResupply: 0,
items: [],
barter_scheme: {},
loyal_level_items: {}
}
return assortTable;
}
/**
* Add traders name/location/description to the locale table
* @param baseJson json file for trader (db/base.json)
* @param tables database tables
* @param fullName Complete name of trader
* @param firstName First name of trader
* @param nickName Nickname of trader
* @param location Location of trader (e.g. "Here in the cat shop")
* @param description Description of trader
*/
public addTraderToLocales(baseJson: any, tables: IDatabaseTables, fullName: string, firstName: string, nickName: string, location: string, description: string)
{
// For each language, add locale for the new trader
const locales = Object.values(tables.locales.global) as Record<string, string>[];
for (const locale of locales) {
locale[`${baseJson._id} FullName`] = fullName;
locale[`${baseJson._id} FirstName`] = firstName;
locale[`${baseJson._id} Nickname`] = nickName;
locale[`${baseJson._id} Location`] = location;
locale[`${baseJson._id} Description`] = description;
}
}
}