diff --git a/TypeScript/13AddTrader/db/base.json b/TypeScript/13AddTrader/db/base.json index 6e10865..cff5ccd 100644 --- a/TypeScript/13AddTrader/db/base.json +++ b/TypeScript/13AddTrader/db/base.json @@ -13,7 +13,7 @@ "customization_seller": false, "name": "Cat", "surname": " ", - "nickname": "Cat", + "nickname": "Maxwell", "location": "Here is the cat shop", "avatar": "/files/trader/avatar/cat.jpg", "balance_rub": 5000000, diff --git a/TypeScript/13AddTrader/src/mod.ts b/TypeScript/13AddTrader/src/mod.ts index 2702695..7c973d5 100644 --- a/TypeScript/13AddTrader/src/mod.ts +++ b/TypeScript/13AddTrader/src/mod.ts @@ -9,19 +9,18 @@ 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 { ITraderAssort, ITraderBase } from "@spt-aki/models/eft/common/tables/ITrader"; -import { ITraderConfig, UpdateTime } from "@spt-aki/models/spt/config/ITraderConfig"; +import { ITraderConfig } from "@spt-aki/models/spt/config/ITraderConfig"; import { JsonUtil } from "@spt-aki/utils/JsonUtil"; -import { Item } from "@spt-aki/models/eft/common/tables/IItem"; -import { IDatabaseTables } from "@spt-aki/models/spt/server/IDatabaseTables"; -import { Money } from "@spt-aki/models/enums/Money"; // New trader settings import * as baseJson from "../db/base.json"; +import { TraderHelper } from "./traderHelpers"; -class SampleTrader implements IPreAkiLoadMod, IPostDBLoadMod { - mod: string - logger: ILogger +class SampleTrader implements IPreAkiLoadMod, IPostDBLoadMod +{ + private mod: string + private logger: ILogger + private traderHeper: TraderHelper constructor() { this.mod = "13AddTrader"; // Set name of mod so we can log it to console later @@ -31,19 +30,23 @@ class SampleTrader implements IPreAkiLoadMod, IPostDBLoadMod { * 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 { + public preAkiLoad(container: DependencyContainer): void + { + // Get a logger this.logger = container.resolve<ILogger>("WinstonLogger"); this.logger.debug(`[${this.mod}] preAki Loading... `); + // Get SPT code/data we need later const preAkiModLoader: PreAkiModLoader = container.resolve<PreAkiModLoader>("PreAkiModLoader"); const imageRouter: ImageRouter = container.resolve<ImageRouter>("ImageRouter"); const configServer = container.resolve<ConfigServer>("ConfigServer"); const traderConfig: ITraderConfig = configServer.getConfig<ITraderConfig>(ConfigTypes.TRADER); - - this.registerProfileImage(preAkiModLoader, imageRouter); - - this.setupTraderUpdateTime(traderConfig); - + + // Create helper class and use it to register our traders image/icon + set its stock refresh time + this.traderHeper = new TraderHelper(); + this.traderHeper.registerProfileImage(baseJson, this.mod, preAkiModLoader, imageRouter, "cat.jpg"); + this.traderHeper.setTraderUpdateTime(traderConfig, baseJson, 3600); + this.logger.debug(`[${this.mod}] preAki Loaded`); } @@ -51,210 +54,33 @@ class SampleTrader implements IPreAkiLoadMod, IPostDBLoadMod { * 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 { + public postDBLoad(container: DependencyContainer): void + { this.logger.debug(`[${this.mod}] postDb Loading... `); // Resolve SPT classes we'll use const databaseServer: DatabaseServer = container.resolve<DatabaseServer>("DatabaseServer"); const configServer: ConfigServer = container.resolve<ConfigServer>("ConfigServer"); - const traderConfig: ITraderConfig = configServer.getConfig(ConfigTypes.TRADER); const jsonUtil: JsonUtil = container.resolve<JsonUtil>("JsonUtil"); // Get a reference to the database tables const tables = databaseServer.getTables(); - // Add new trader to the trader dictionary in DatabaseServer - this.addTraderToDb(baseJson, tables, jsonUtil); + // Add new trader to the trader dictionary in DatabaseServer - has no assorts (items) yet + this.traderHeper.addTraderToDb(baseJson, tables, jsonUtil); - this.addTraderToLocales(tables, baseJson.name, "Cat", baseJson.nickname, baseJson.location, "This is the cat shop"); + // Add some singular items to trader (items without sub-items e.g. milk/bandage) + this.traderHeper.addSingleItemsToTrader(tables, baseJson._id); + + // Add more complex items to trader (items with sub-items, e.g. guns) + this.traderHeper.addComplexItemsToTrader(tables, baseJson._id, jsonUtil); + + // 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.traderHeper.addTraderToLocales(baseJson, tables, baseJson.name, "Cat", baseJson.nickname, baseJson.location, "This is the cat shop"); this.logger.debug(`[${this.mod}] postDb Loaded`); } - - /** - * Add profile picture to our trader - * @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 - */ - private registerProfileImage(preAkiModLoader: PreAkiModLoader, imageRouter: ImageRouter): void - { - // Reference the mod "res" folder - const imageFilepath = `./${preAkiModLoader.getModPath(this.mod)}res`; - - // Register a route to point to the profile picture - imageRouter.addRoute(baseJson.avatar.replace(".jpg", ""), `${imageFilepath}/cat.jpg`); - } - - /** - * 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 - */ - private setupTraderUpdateTime(traderConfig: ITraderConfig): void - { - // Add refresh time in seconds to config - const traderRefreshRecord: UpdateTime = { traderId: baseJson._id, seconds: 3600 } - 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 -private 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(tables, jsonUtil), // 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, - questassort: { - started: {}, - success: {}, - fail: {} - } // Empty object as trader has no assorts unlocked by quests - }; - } - - /** - * Create assorts for trader and add milk and a gun to it - * @returns ITraderAssort - */ - private createAssortTable(tables: IDatabaseTables, jsonUtil: JsonUtil): ITraderAssort - { - // Create a blank assort object, ready to have items added - const assortTable: ITraderAssort = { - nextResupply: 0, - items: [], - barter_scheme: {}, - loyal_level_items: {} - } - - const MILK_ID = "575146b724597720a27126d5"; // Can find item ids in `database\templates\items.json` - // View function documentation for what all the parameters are - this.addSingleItemToAssort(assortTable, MILK_ID, true, 9999999, 1, Money.ROUBLES, 1); - - // Get the mp133 preset and add to the traders assort (Could make your own Items[] array, doesnt have to be presets) - const mp133GunPreset = tables.globals.ItemPresets["584148f2245977598f1ad387"]._items; - this.addCollectionToAssort(jsonUtil, assortTable, mp133GunPreset, false, 5, 1, Money.ROUBLES, 500); - - return assortTable; - } - - /** - * Add item to assortTable + barter scheme + loyalty level objects - * @param assortTable trader assorts to add item to - * @param itemTpl Items tpl to add to traders assort - * @param unlimitedCount Can an unlimited number of this item be purchased from trader - * @param stackCount Total size of item stack trader sells - * @param loyaltyLevel Loyalty level item can be purchased at - * @param currencyType What currency does item sell for - * @param currencyValue Amount of currency item can be purchased for - */ - private addSingleItemToAssort(assortTable: ITraderAssort, itemTpl: string, unlimitedCount: boolean, stackCount: number, loyaltyLevel: number, currencyType: Money, currencyValue: number) - { - // Define item in the table - const newItem: Item = { - _id: itemTpl, - _tpl: itemTpl, - parentId: "hideout", - slotId: "hideout", - upd: { - UnlimitedCount: unlimitedCount, - StackObjectsCount: stackCount - } - }; - assortTable.items.push(newItem); - - // Barter scheme holds the cost of the item + the currency needed (doesnt need to be currency, can be any item, this is how barter traders are made) - assortTable.barter_scheme[itemTpl] = [ - [ - { - count: currencyValue, - _tpl: currencyType - } - ] - ]; - - // Set loyalty level needed to unlock item - assortTable.loyal_level_items[itemTpl] = loyaltyLevel; - } - - /** - * Add a complex item to trader assort (item with child items) - * @param assortTable trader assorts to add items to - * @param jsonUtil JSON utility class - * @param items Items array to add to assort - * @param unlimitedCount Can an unlimited number of this item be purchased from trader - * @param stackCount Total size of item stack trader sells - * @param loyaltyLevel Loyalty level item can be purchased at - * @param currencyType What currency does item sell for - * @param currencyValue Amount of currency item can be purchased for - */ - private addCollectionToAssort(jsonUtil: JsonUtil, assortTable: ITraderAssort, items: Item[], unlimitedCount: boolean, stackCount: number, loyaltyLevel: number, currencyType: Money, currencyValue: number): void - { - // Deserialize and serialize to ensure we dont alter the original data - const collectionToAdd: Item[] = jsonUtil.deserialize(jsonUtil.serialize(items)); - - // Update item base with values needed to make item sellable by trader - collectionToAdd[0].upd = { - UnlimitedCount: unlimitedCount, - StackObjectsCount: stackCount - } - collectionToAdd[0].parentId = "hideout"; - collectionToAdd[0].slotId = "hideout"; - - // Push all the items into the traders assort table - assortTable.items.push(...collectionToAdd); - - // Barter scheme holds the cost of the item + the currency needed (doesnt need to be currency, can be any item, this is how barter traders are made) - assortTable.barter_scheme[collectionToAdd[0]._id] = [ - [ - { - count: currencyValue, - _tpl: currencyType - } - ] - ]; - - // Set loyalty level needed to unlock item - assortTable.loyal_level_items[collectionToAdd[0]._id] = loyaltyLevel; - } - - /** - * Add traders name/location/description to the locale table - * @param tables database tables - * @param fullName fullname of trader - * @param firstName first name of trader - * @param nickName nickname of trader - * @param location location of trader - * @param description description of trader - */ - private addTraderToLocales(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; - } - } - - private addItemToLocales(tables: IDatabaseTables, itemTpl: string, name: string, shortName: 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[`${itemTpl} Name`] = name; - locale[`${itemTpl} ShortName`] = shortName; - locale[`${itemTpl} Description`] = Description; - } - } } module.exports = { mod: new SampleTrader() } \ No newline at end of file diff --git a/TypeScript/13AddTrader/src/traderHelpers.ts b/TypeScript/13AddTrader/src/traderHelpers.ts new file mode 100644 index 0000000..b65e3c1 --- /dev/null +++ b/TypeScript/13AddTrader/src/traderHelpers.ts @@ -0,0 +1,326 @@ +import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader"; +import { Item } from "@spt-aki/models/eft/common/tables/IItem"; +import { ITraderBase, ITraderAssort } from "@spt-aki/models/eft/common/tables/ITrader"; +import { Money } from "@spt-aki/models/enums/Money"; +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 refreshTimeSeconds How many sections between trader stock refresh + */ + public setTraderUpdateTime(traderConfig: ITraderConfig, baseJson: any, refreshTimeSeconds: number): void + { + // Add refresh time in seconds to config + const traderRefreshRecord: UpdateTime = { + traderId: baseJson._id, + seconds: refreshTimeSeconds }; + + 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 basic items to trader + * @param tables SPT db + * @param traderId Traders id (basejson/_id value) + */ + public addSingleItemsToTrader(tables: IDatabaseTables, traderId: string) + { + // Get the table that can hold our new items + const traderAssortTable = tables.traders[traderId].assort + + // Add milk, unlimited stock for 1 rouble with no buy restrictions + const MILK_ID = "575146b724597720a27126d5"; // Can find item ids in `database\templates\items.json` or with https://db.sp-tarkov.com/search + this.addSingleItemToAssort(traderAssortTable, MILK_ID, true, 9999999, 1, Money.ROUBLES, 1, false, 0); + + // Add salewa with 50 stock for 500 dollars + buy restriction of 2 per refresh + const SALEWA_ID = "544fb45d4bdc2dee738b4568"; + this.addSingleItemToAssort(traderAssortTable, SALEWA_ID, false, 50, 1, Money.DOLLARS, 500, true, 2); + } + + /** + * Add items with sub items to trader + * @param tables SPT db + * @param traderId Traders id (basejson/_id value) + * @param jsonUtil SPT JSON utility class + */ + public addComplexItemsToTrader(tables: IDatabaseTables, traderId: string, jsonUtil: JsonUtil) + { + // Get the table that can hold our new items + const traderAssortTable = tables.traders[traderId].assort + + // Get the mp133 preset and add to the traders assort (Could make your own Items[] array, doesn't have to be from presets) + const mp133GunPreset = tables.globals.ItemPresets["584148f2245977598f1ad387"]._items; + this.addItemWithSubItemsToAssort(jsonUtil, traderAssortTable, mp133GunPreset, false, 5, 1, Money.ROUBLES, 500, false, 0); + + // Create a pistol with some mods + add to trader + const customGlock17 = this.createGlock(); + this.addItemWithSubItemsToAssort(jsonUtil, traderAssortTable, customGlock17, true, 69, 1, Money.EUROS, 5, true, 2); + } + + /** + * Create a weapon from scratch, ready to be added to trader + * @returns Item[] + */ + private createGlock(): Item[] + { + // Create an array ready to hold weapon + all mods + const glock: Item[] = []; + + // Add the base first + glock.push({ // Add the base weapon first + _id: "glockBase", // Ids dont matter, as long as they are unique (can use hashUtil.generate() if you dont want to type every id by hand) + _tpl: "5a7ae0c351dfba0017554310" // This is the weapons tpl, found on: https://db.sp-tarkov.com/search + }); + + // Add barrel + glock.push({ + _id: "glockbarrel", + _tpl: "5a6b60158dc32e000a31138b", + parentId: "glockBase", // This is a sub item, you need to define its parent its attached to / inserted into + slotId: "mod_barrel" // Required for mods, you need to define what 'role' they have + }); + + // Add reciever + glock.push({ + _id: "glockReciever", + _tpl:"5a9685b1a2750c0032157104", + parentId: "glockBase", + slotId: "mod_reciever" + }); + + // Add compensator + glock.push({ + _id: "glockCompensator", + _tpl:"5a7b32a2e899ef00135e345a", + parentId: "glockReciever", // The parent of this mod is the reciever NOT weapon, be careful to get the correct parent + slotId: "mod_muzzle" + }); + + // Add Pistol grip + glock.push({ + _id: "glockPistolGrip", + _tpl:"5a7b4960e899ef197b331a2d", + parentId: "glockBase", + slotId: "mod_pistol_grip" + }); + + // Add front sight + glock.push({ + _id: "glockRearSight", + _tpl: "5a6f5d528dc32e00094b97d9", + parentId: "glockReciever", + slotId: "mod_sight_rear" + }); + + // Add rear sight + glock.push({ + _id: "glockFrontSight", + _tpl: "5a6f58f68dc32e000a311390", + parentId: "glockReciever", + slotId: "mod_sight_front" + }); + + // Add magazine + glock.push({ + _id: "glockMagazine", + _tpl: "630769c4962d0247b029dc60", + parentId: "glockBase", + slotId: "mod_magazine" + }); + + return glock; + } + + /** + * Add item to assortTable + barter scheme + loyalty level objects + * @param assortTable Trader assorts to add item to + * @param itemTpl Items tpl to add to traders assort + * @param unlimitedCount Can an unlimited number of this item be purchased from trader + * @param stackCount Total size of item stack trader sells + * @param loyaltyLevel Loyalty level item can be purchased at + * @param currencyType What currency does item sell for + * @param currencyValue Amount of currency item can be purchased for + * @param hasBuyRestriction Does the item have a max purchase amount + * @param buyRestrictionMax How many times can item be purchased per trader refresh + */ + private addSingleItemToAssort(assortTable: ITraderAssort, itemTpl: string, unlimitedCount: boolean, stackCount: number, loyaltyLevel: number, currencyType: Money, currencyValue: number, hasBuyRestriction: boolean, buyRestrictionMax: number) + { + // Create item ready for insertion into assort table + const newItemToAdd: Item = { + _id: itemTpl, + _tpl: itemTpl, + parentId: "hideout", // Should always be "hideout" + slotId: "hideout", // Should always be "hideout" + upd: { + UnlimitedCount: unlimitedCount, + StackObjectsCount: stackCount + } + }; + + // Items can have a buy restriction per trader refresh cycle, optional + if(hasBuyRestriction) + { + newItemToAdd.upd.BuyRestrictionMax = buyRestrictionMax; + newItemToAdd.upd.BuyRestrictionCurrent = 0; + } + + assortTable.items.push(newItemToAdd); + + // Barter scheme holds the cost of the item + the currency needed (doesnt need to be currency, can be any item, this is how barter traders are made) + assortTable.barter_scheme[itemTpl] = [ + [ + { + count: currencyValue, + _tpl: currencyType + } + ] + ]; + + // Set loyalty level needed to unlock item + assortTable.loyal_level_items[itemTpl] = loyaltyLevel; + } + + /** + * Add a complex item to trader assort (item with child items) + * @param assortTable trader assorts to add items to + * @param jsonUtil JSON utility class + * @param items Items array to add to assort + * @param unlimitedCount Can an unlimited number of this item be purchased from trader + * @param stackCount Total size of item stack trader sells + * @param loyaltyLevel Loyalty level item can be purchased at + * @param currencyType What currency does item sell for + * @param currencyValue Amount of currency item can be purchased for + * @param hasBuyRestriction Does the item have a max purchase amount + * @param buyRestrictionMax How many times can item be purchased per trader refresh + */ + private addItemWithSubItemsToAssort(jsonUtil: JsonUtil, assortTable: ITraderAssort, items: Item[], unlimitedCount: boolean, stackCount: number, loyaltyLevel: number, currencyType: Money, currencyValue: number, hasBuyRestriction: boolean, buyRestrictionMax: number): void + { + // Deserialize and serialize to ensure we dont alter the original data (clone it) + const collectionToAdd: Item[] = jsonUtil.deserialize(jsonUtil.serialize(items)); + + // Create upd object if its missing + if (!collectionToAdd[0].upd) + { + collectionToAdd[0].upd = {}; + } + + // Update item base with values needed to make item sellable by trader + collectionToAdd[0].upd = { + UnlimitedCount: unlimitedCount, + StackObjectsCount: stackCount + } + + // Items can have a buy restriction per trader refresh cycle, optional + if(hasBuyRestriction) + { + collectionToAdd[0].upd.BuyRestrictionMax = buyRestrictionMax; + collectionToAdd[0].upd.BuyRestrictionCurrent = 0; + } + + // First item should always have both properties set to 'hideout' + collectionToAdd[0].parentId = "hideout"; + collectionToAdd[0].slotId = "hideout"; + + // Push all the items into the traders assort table + assortTable.items.push(...collectionToAdd); + + // Barter scheme holds the cost of the item + the currency needed (doesnt need to be currency, can be any item, this is how barter traders are made) + assortTable.barter_scheme[collectionToAdd[0]._id] = [ + [ + { + count: currencyValue, + _tpl: currencyType + } + ] + ]; + + // Set loyalty level needed to unlock item + assortTable.loyal_level_items[collectionToAdd[0]._id] = loyaltyLevel; + } + + /** + * 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; + } + } +} \ No newline at end of file diff --git a/TypeScript/6ReferenceAnotherClass/src/mod.ts b/TypeScript/6ReferenceAnotherClass/src/mod.ts index cddc4dd..b114e0a 100644 --- a/TypeScript/6ReferenceAnotherClass/src/mod.ts +++ b/TypeScript/6ReferenceAnotherClass/src/mod.ts @@ -2,7 +2,7 @@ import { DependencyContainer } from "tsyringe"; import { IPostAkiLoadMod } from "@spt-aki/models/external/IPostAkiLoadMod"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; -import {MoreCode } from "./MoreCode"; +import { MoreCode } from "./MoreCode"; class Mod implements IPostAkiLoadMod {