rename file
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user