0
0
mirror of https://github.com/sp-tarkov/server.git synced 2025-02-13 09:10:43 -05:00

Project Code Format

Ran the `npm run format` command to bring the entire project in-line with the formatting rules.
This commit is contained in:
Refringe 2024-05-17 15:32:41 -04:00
parent 5def42416b
commit cb169a18b9
Signed by: Refringe
GPG Key ID: 7715B85B4A6306ED
158 changed files with 1999 additions and 1691 deletions

View File

@ -23,7 +23,7 @@ export class ErrorHandler
this.logger.error(`\nStacktrace:\n${err.stack}`); this.logger.error(`\nStacktrace:\n${err.stack}`);
} }
this.readLine.question("Press Enter to close the window", _ans => this.readLine.close()); this.readLine.question("Press Enter to close the window", (_ans) => this.readLine.close());
this.readLine.on("close", () => process.exit(1)); this.readLine.on("close", () => process.exit(1));
} }
} }

View File

@ -2,7 +2,6 @@ import { inject, injectable } from "tsyringe";
import { AchievementController } from "@spt-aki/controllers/AchievementController"; import { AchievementController } from "@spt-aki/controllers/AchievementController";
import { ProfileController } from "@spt-aki/controllers/ProfileController"; import { ProfileController } from "@spt-aki/controllers/ProfileController";
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData"; import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
import { IAchievement } from "@spt-aki/models/eft/common/tables/IAchievement";
import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData"; import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData";
import { ICompletedAchievementsResponse } from "@spt-aki/models/eft/profile/ICompletedAchievementsResponse"; import { ICompletedAchievementsResponse } from "@spt-aki/models/eft/profile/ICompletedAchievementsResponse";
import { IGetAchievementsResponse } from "@spt-aki/models/eft/profile/IGetAchievementsResponse"; import { IGetAchievementsResponse } from "@spt-aki/models/eft/profile/IGetAchievementsResponse";

View File

@ -48,7 +48,11 @@ export class BotCallbacks
* Handle singleplayer/settings/bot/difficulties * Handle singleplayer/settings/bot/difficulties
* @returns dictionary of every bot and its diffiulty settings * @returns dictionary of every bot and its diffiulty settings
*/ */
public getAllBotDifficulties(url: string, info: IEmptyRequestData, sessionID: string): Record<string, Difficulties> public getAllBotDifficulties(
url: string,
info: IEmptyRequestData,
sessionID: string,
): Record<string, Difficulties>
{ {
return this.httpResponse.noBody(this.botController.getAllBotDifficulties()); return this.httpResponse.noBody(this.botController.getAllBotDifficulties());
} }

View File

@ -46,7 +46,11 @@ export class CustomizationCallbacks
/** /**
* Handle CustomizationWear event * Handle CustomizationWear event
*/ */
public wearClothing(pmcData: IPmcData, body: IWearClothingRequestData, sessionID: string): IItemEventRouterResponse public wearClothing(
pmcData: IPmcData,
body: IWearClothingRequestData,
sessionID: string,
): IItemEventRouterResponse
{ {
return this.customizationController.wearClothing(pmcData, body, sessionID); return this.customizationController.wearClothing(pmcData, body, sessionID);
} }

View File

@ -88,7 +88,11 @@ export class DataCallbacks
* Handle client/account/customization * Handle client/account/customization
* @returns string[] * @returns string[]
*/ */
public getTemplateCharacter(url: string, info: IEmptyRequestData, sessionID: string): IGetBodyResponseData<string[]> public getTemplateCharacter(
url: string,
info: IEmptyRequestData,
sessionID: string,
): IGetBodyResponseData<string[]>
{ {
return this.httpResponse.getBody(this.databaseServer.getTables().templates.character); return this.httpResponse.getBody(this.databaseServer.getTables().templates.character);
} }

View File

@ -47,8 +47,7 @@ export class DialogueCallbacks implements OnUpdate
@inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil, @inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil,
@inject("DialogueController") protected dialogueController: DialogueController, @inject("DialogueController") protected dialogueController: DialogueController,
) )
{ {}
}
/** /**
* Handle client/friend/list * Handle client/friend/list
@ -276,11 +275,7 @@ export class DialogueCallbacks implements OnUpdate
return this.httpResponse.emptyArrayResponse(); return this.httpResponse.emptyArrayResponse();
} }
public createGroupMail( public createGroupMail(url: string, info: ICreateGroupMailRequest, sessionID: string): IGetBodyResponseData<any[]>
url: string,
info: ICreateGroupMailRequest,
sessionID: string,
): IGetBodyResponseData<any[]>
{ {
throw new Error("Method not implemented."); throw new Error("Method not implemented.");
} }
@ -294,11 +289,7 @@ export class DialogueCallbacks implements OnUpdate
throw new Error("Method not implemented."); throw new Error("Method not implemented.");
} }
public addUserToMail( public addUserToMail(url: string, info: IAddUserGroupMailRequest, sessionID: string): IGetBodyResponseData<any[]>
url: string,
info: IAddUserGroupMailRequest,
sessionID: string,
): IGetBodyResponseData<any[]>
{ {
throw new Error("Method not implemented."); throw new Error("Method not implemented.");
} }

View File

@ -56,7 +56,11 @@ export class GameCallbacks implements OnLoad
* Handle client/game/start * Handle client/game/start
* @returns IGameStartResponse * @returns IGameStartResponse
*/ */
public gameStart(url: string, info: IEmptyRequestData, sessionID: string): IGetBodyResponseData<IGameStartResponse> public gameStart(
url: string,
info: IEmptyRequestData,
sessionID: string,
): IGetBodyResponseData<IGameStartResponse>
{ {
const today = new Date().toUTCString(); const today = new Date().toUTCString();
const startTimeStampMS = Date.parse(today); const startTimeStampMS = Date.parse(today);

View File

@ -102,7 +102,11 @@ export class InventoryCallbacks
return this.inventoryController.foldItem(pmcData, body, sessionID); return this.inventoryController.foldItem(pmcData, body, sessionID);
} }
public toggleItem(pmcData: IPmcData, body: IInventoryToggleRequestData, sessionID: string): IItemEventRouterResponse public toggleItem(
pmcData: IPmcData,
body: IInventoryToggleRequestData,
sessionID: string,
): IItemEventRouterResponse
{ {
return this.inventoryController.toggleItem(pmcData, body, sessionID); return this.inventoryController.toggleItem(pmcData, body, sessionID);
} }

View File

@ -101,22 +101,14 @@ export class MatchCallbacks
/** Handle client/match/group/invite/decline */ /** Handle client/match/group/invite/decline */
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
public declineGroupInvite( public declineGroupInvite(url: string, info: IRequestIdRequest, sessionId: string): IGetBodyResponseData<boolean>
url: string,
info: IRequestIdRequest,
sessionId: string,
): IGetBodyResponseData<boolean>
{ {
return this.httpResponse.getBody(true); return this.httpResponse.getBody(true);
} }
/** Handle client/match/group/invite/cancel */ /** Handle client/match/group/invite/cancel */
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
public cancelGroupInvite( public cancelGroupInvite(url: string, info: IRequestIdRequest, sessionID: string): IGetBodyResponseData<boolean>
url: string,
info: IRequestIdRequest,
sessionID: string,
): IGetBodyResponseData<boolean>
{ {
return this.httpResponse.getBody(true); return this.httpResponse.getBody(true);
} }
@ -246,21 +238,13 @@ export class MatchCallbacks
} }
/** Handle client/match/group/raid/ready */ /** Handle client/match/group/raid/ready */
public raidReady( public raidReady(url: string, info: IEmptyRequestData, sessionId: string): IGetBodyResponseData<boolean>
url: string,
info: IEmptyRequestData,
sessionId: string,
): IGetBodyResponseData<boolean>
{ {
return this.httpResponse.getBody(true); return this.httpResponse.getBody(true);
} }
/** Handle client/match/group/raid/not-ready */ /** Handle client/match/group/raid/not-ready */
public notRaidReady( public notRaidReady(url: string, info: IEmptyRequestData, sessionId: string): IGetBodyResponseData<boolean>
url: string,
info: IEmptyRequestData,
sessionId: string,
): IGetBodyResponseData<boolean>
{ {
return this.httpResponse.getBody(true); return this.httpResponse.getBody(true);
} }

View File

@ -36,9 +36,10 @@ export class NotifierCallbacks
* Take our array of JSON message objects and cast them to JSON strings, so that they can then * Take our array of JSON message objects and cast them to JSON strings, so that they can then
* be sent to client as NEWLINE separated strings... yup. * be sent to client as NEWLINE separated strings... yup.
*/ */
this.notifierController.notifyAsync(tmpSessionID).then((messages: any) => this.notifierController
messages.map((message: any) => this.jsonUtil.serialize(message)).join("\n"), .notifyAsync(tmpSessionID)
).then(text => this.httpServerHelper.sendTextJson(resp, text)); .then((messages: any) => messages.map((message: any) => this.jsonUtil.serialize(message)).join("\n"))
.then((text) => this.httpServerHelper.sendTextJson(resp, text));
} }
/** Handle push/notifier/get */ /** Handle push/notifier/get */

View File

@ -17,7 +17,11 @@ export class WishlistCallbacks
} }
/** Handle RemoveFromWishList event */ /** Handle RemoveFromWishList event */
public removeFromWishlist(pmcData: IPmcData, body: IWishlistActionData, sessionID: string): IItemEventRouterResponse public removeFromWishlist(
pmcData: IPmcData,
body: IWishlistActionData,
sessionID: string,
): IItemEventRouterResponse
{ {
return this.wishlistController.removeFromWishList(pmcData, body, sessionID); return this.wishlistController.removeFromWishList(pmcData, body, sessionID);
} }

View File

@ -5,6 +5,7 @@ import { BotGenerator } from "@spt-aki/generators/BotGenerator";
import { BotDifficultyHelper } from "@spt-aki/helpers/BotDifficultyHelper"; import { BotDifficultyHelper } from "@spt-aki/helpers/BotDifficultyHelper";
import { BotHelper } from "@spt-aki/helpers/BotHelper"; import { BotHelper } from "@spt-aki/helpers/BotHelper";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper"; import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { MinMax } from "@spt-aki/models/common/MinMax";
import { Condition, IGenerateBotsRequestData } from "@spt-aki/models/eft/bot/IGenerateBotsRequestData"; import { Condition, IGenerateBotsRequestData } from "@spt-aki/models/eft/bot/IGenerateBotsRequestData";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { IBotBase } from "@spt-aki/models/eft/common/tables/IBotBase"; import { IBotBase } from "@spt-aki/models/eft/common/tables/IBotBase";
@ -25,7 +26,6 @@ import { MatchBotDetailsCacheService } from "@spt-aki/services/MatchBotDetailsCa
import { SeasonalEventService } from "@spt-aki/services/SeasonalEventService"; import { SeasonalEventService } from "@spt-aki/services/SeasonalEventService";
import { ICloner } from "@spt-aki/utils/cloners/ICloner"; import { ICloner } from "@spt-aki/utils/cloners/ICloner";
import { RandomUtil } from "@spt-aki/utils/RandomUtil"; import { RandomUtil } from "@spt-aki/utils/RandomUtil";
import { MinMax } from "@spt-aki/models/common/MinMax";
@injectable() @injectable()
export class BotController export class BotController
@ -94,9 +94,9 @@ export class BotController
{ {
let difficulty = diffLevel.toLowerCase(); let difficulty = diffLevel.toLowerCase();
const raidConfig = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue< const raidConfig = this.applicationContext
IGetRaidConfigurationRequestData .getLatestValue(ContextVariableType.RAID_CONFIGURATION)
>(); ?.getValue<IGetRaidConfigurationRequestData>();
if (!(raidConfig || ignoreRaidSettings)) if (!(raidConfig || ignoreRaidSettings))
{ {
this.logger.error( this.logger.error(
@ -109,9 +109,8 @@ export class BotController
const botDifficultyDropDownValue = raidConfig?.wavesSettings.botDifficulty.toLowerCase() ?? "asonline"; const botDifficultyDropDownValue = raidConfig?.wavesSettings.botDifficulty.toLowerCase() ?? "asonline";
if (botDifficultyDropDownValue !== "asonline") if (botDifficultyDropDownValue !== "asonline")
{ {
difficulty = this.botDifficultyHelper.convertBotDifficultyDropdownToBotDifficulty( difficulty
botDifficultyDropDownValue, = this.botDifficultyHelper.convertBotDifficultyDropdownToBotDifficulty(botDifficultyDropDownValue);
);
} }
let difficultySettings: Difficulty; let difficultySettings: Difficulty;
@ -147,7 +146,7 @@ export class BotController
const result = {}; const result = {};
const botDb = this.databaseServer.getTables().bots.types; const botDb = this.databaseServer.getTables().bots.types;
const botTypes = Object.keys(WildSpawnTypeNumber).filter(v => Number.isNaN(Number(v))); const botTypes = Object.keys(WildSpawnTypeNumber).filter((v) => Number.isNaN(Number(v)));
for (let botType of botTypes) for (let botType of botTypes)
{ {
const enumType = botType.toLowerCase(); const enumType = botType.toLowerCase();
@ -228,12 +227,13 @@ export class BotController
allPmcsHaveSameNameAsPlayer, allPmcsHaveSameNameAsPlayer,
pmcLevelRangeForMap, pmcLevelRangeForMap,
this.botConfig.presetBatch[condition.Role], this.botConfig.presetBatch[condition.Role],
false); false,
);
conditionPromises.push(this.generateWithBotDetails(condition, botGenerationDetails, sessionId)); conditionPromises.push(this.generateWithBotDetails(condition, botGenerationDetails, sessionId));
} }
await Promise.all(conditionPromises).then(p => Promise.all(p)); await Promise.all(conditionPromises).then((p) => Promise.all(p));
return []; return [];
} }
@ -254,8 +254,8 @@ export class BotController
allPmcsHaveSameNameAsPlayer: boolean, allPmcsHaveSameNameAsPlayer: boolean,
pmcLevelRangeForMap: MinMax, pmcLevelRangeForMap: MinMax,
botCountToGenerate: number, botCountToGenerate: number,
generateAsPmc: boolean): BotGenerationDetails generateAsPmc: boolean,
): BotGenerationDetails
{ {
return { return {
isPmc: generateAsPmc, isPmc: generateAsPmc,
@ -357,14 +357,17 @@ export class BotController
* @param request Bot generation request object * @param request Bot generation request object
* @returns Single IBotBase object * @returns Single IBotBase object
*/ */
protected async returnSingleBotFromCache(sessionId: string, request: IGenerateBotsRequestData): Promise<IBotBase[]> protected async returnSingleBotFromCache(
sessionId: string,
request: IGenerateBotsRequestData,
): Promise<IBotBase[]>
{ {
const pmcProfile = this.profileHelper.getPmcProfile(sessionId); const pmcProfile = this.profileHelper.getPmcProfile(sessionId);
const requestedBot = request.conditions[0]; const requestedBot = request.conditions[0];
const raidSettings = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue< const raidSettings = this.applicationContext
IGetRaidConfigurationRequestData .getLatestValue(ContextVariableType.RAID_CONFIGURATION)
>(); ?.getValue<IGetRaidConfigurationRequestData>();
const pmcLevelRangeForMap const pmcLevelRangeForMap
= this.pmcConfig.locationSpecificPmcLevelOverride[raidSettings.location.toLowerCase()]; = this.pmcConfig.locationSpecificPmcLevelOverride[raidSettings.location.toLowerCase()];
@ -372,7 +375,7 @@ export class BotController
const condition: Condition = { const condition: Condition = {
Role: requestedBot.Role, Role: requestedBot.Role,
Limit: 5, Limit: 5,
Difficulty: requestedBot.Difficulty Difficulty: requestedBot.Difficulty,
}; };
const botGenerationDetails = this.getBotGenerationDetailsForWave( const botGenerationDetails = this.getBotGenerationDetailsForWave(
condition, condition,
@ -380,7 +383,8 @@ export class BotController
false, false,
pmcLevelRangeForMap, pmcLevelRangeForMap,
this.botConfig.presetBatch[requestedBot.Role], this.botConfig.presetBatch[requestedBot.Role],
false); false,
);
// Event bots need special actions to occur, set data up for them // Event bots need special actions to occur, set data up for them
const isEventBot = requestedBot.Role.toLowerCase().includes("event"); const isEventBot = requestedBot.Role.toLowerCase().includes("event");
@ -475,9 +479,9 @@ export class BotController
public getBotCap(): number public getBotCap(): number
{ {
const defaultMapCapId = "default"; const defaultMapCapId = "default";
const raidConfig = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION).getValue< const raidConfig = this.applicationContext
IGetRaidConfigurationRequestData .getLatestValue(ContextVariableType.RAID_CONFIGURATION)
>(); .getValue<IGetRaidConfigurationRequestData>();
if (!raidConfig) if (!raidConfig)
{ {

View File

@ -42,11 +42,11 @@ export class BuildController
const defaultEquipmentPresetsClone = this.cloner.clone( const defaultEquipmentPresetsClone = this.cloner.clone(
this.databaseServer.getTables().templates.defaultEquipmentPresets, this.databaseServer.getTables().templates.defaultEquipmentPresets,
); );
const playerSecureContainer = profile.characters.pmc.Inventory.items?.find(x => const playerSecureContainer = profile.characters.pmc.Inventory.items?.find(
x.slotId === secureContainerSlotId, (x) => x.slotId === secureContainerSlotId,
); );
const firstDefaultItemsSecureContainer = defaultEquipmentPresetsClone[0]?.Items?.find(x => const firstDefaultItemsSecureContainer = defaultEquipmentPresetsClone[0]?.Items?.find(
x.slotId === secureContainerSlotId, (x) => x.slotId === secureContainerSlotId,
); );
if (playerSecureContainer && playerSecureContainer?._tpl !== firstDefaultItemsSecureContainer?._tpl) if (playerSecureContainer && playerSecureContainer?._tpl !== firstDefaultItemsSecureContainer?._tpl)
{ {
@ -54,7 +54,7 @@ export class BuildController
for (const defaultPreset of defaultEquipmentPresetsClone) for (const defaultPreset of defaultEquipmentPresetsClone)
{ {
// Find presets secure container // Find presets secure container
const secureContainer = defaultPreset.Items.find(item => item.slotId === secureContainerSlotId); const secureContainer = defaultPreset.Items.find((item) => item.slotId === secureContainerSlotId);
if (secureContainer) if (secureContainer)
{ {
secureContainer._tpl = playerSecureContainer._tpl; secureContainer._tpl = playerSecureContainer._tpl;
@ -83,15 +83,13 @@ export class BuildController
const newBuild: IWeaponBuild = { Id: body.Id, Name: body.Name, Root: body.Root, Items: body.Items }; const newBuild: IWeaponBuild = { Id: body.Id, Name: body.Name, Root: body.Root, Items: body.Items };
const savedWeaponBuilds = this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds; const savedWeaponBuilds = this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds;
const existingBuild = savedWeaponBuilds.find(x => x.Id === body.Id); const existingBuild = savedWeaponBuilds.find((x) => x.Id === body.Id);
if (existingBuild) if (existingBuild)
{ {
// exists, replace // exists, replace
this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds.splice( this.saveServer
savedWeaponBuilds.indexOf(existingBuild), .getProfile(sessionId)
1, .userbuilds.weaponBuilds.splice(savedWeaponBuilds.indexOf(existingBuild), 1, newBuild);
newBuild,
);
} }
else else
{ {
@ -106,8 +104,8 @@ export class BuildController
const buildType = "equipmentBuilds"; const buildType = "equipmentBuilds";
const pmcData = this.profileHelper.getPmcProfile(sessionID); const pmcData = this.profileHelper.getPmcProfile(sessionID);
const existingSavedEquipmentBuilds: IEquipmentBuild[] = this.saveServer.getProfile(sessionID) const existingSavedEquipmentBuilds: IEquipmentBuild[]
.userbuilds[buildType]; = this.saveServer.getProfile(sessionID).userbuilds[buildType];
// Replace duplicate ID's. The first item is the base item. // Replace duplicate ID's. The first item is the base item.
// Root ID and the base item ID need to match. // Root ID and the base item ID need to match.
@ -121,17 +119,15 @@ export class BuildController
Items: request.Items, Items: request.Items,
}; };
const existingBuild = existingSavedEquipmentBuilds.find(build => const existingBuild = existingSavedEquipmentBuilds.find(
build.Name === request.Name || build.Id === request.Id, (build) => build.Name === request.Name || build.Id === request.Id,
); );
if (existingBuild) if (existingBuild)
{ {
// Already exists, replace // Already exists, replace
this.saveServer.getProfile(sessionID).userbuilds[buildType].splice( this.saveServer
existingSavedEquipmentBuilds.indexOf(existingBuild), .getProfile(sessionID)
1, .userbuilds[buildType].splice(existingSavedEquipmentBuilds.indexOf(existingBuild), 1, newBuild);
newBuild,
);
} }
else else
{ {
@ -154,7 +150,7 @@ export class BuildController
const magazineBuilds = profile.userbuilds.magazineBuilds; const magazineBuilds = profile.userbuilds.magazineBuilds;
// Check for id in weapon array first // Check for id in weapon array first
const matchingWeaponBuild = weaponBuilds.find(weaponBuild => weaponBuild.Id === idToRemove); const matchingWeaponBuild = weaponBuilds.find((weaponBuild) => weaponBuild.Id === idToRemove);
if (matchingWeaponBuild) if (matchingWeaponBuild)
{ {
weaponBuilds.splice(weaponBuilds.indexOf(matchingWeaponBuild), 1); weaponBuilds.splice(weaponBuilds.indexOf(matchingWeaponBuild), 1);
@ -163,7 +159,7 @@ export class BuildController
} }
// Id not found in weapons, try equipment // Id not found in weapons, try equipment
const matchingEquipmentBuild = equipmentBuilds.find(equipmentBuild => equipmentBuild.Id === idToRemove); const matchingEquipmentBuild = equipmentBuilds.find((equipmentBuild) => equipmentBuild.Id === idToRemove);
if (matchingEquipmentBuild) if (matchingEquipmentBuild)
{ {
equipmentBuilds.splice(equipmentBuilds.indexOf(matchingEquipmentBuild), 1); equipmentBuilds.splice(equipmentBuilds.indexOf(matchingEquipmentBuild), 1);
@ -172,7 +168,7 @@ export class BuildController
} }
// Id not found in weapons/equipment, try mags // Id not found in weapons/equipment, try mags
const matchingMagazineBuild = magazineBuilds.find(magBuild => magBuild.Id === idToRemove); const matchingMagazineBuild = magazineBuilds.find((magBuild) => magBuild.Id === idToRemove);
if (matchingMagazineBuild) if (matchingMagazineBuild)
{ {
magazineBuilds.splice(magazineBuilds.indexOf(matchingMagazineBuild), 1); magazineBuilds.splice(magazineBuilds.indexOf(matchingMagazineBuild), 1);
@ -207,7 +203,7 @@ export class BuildController
profile.userbuilds.magazineBuilds = []; profile.userbuilds.magazineBuilds = [];
} }
const existingArrayId = profile.userbuilds.magazineBuilds.findIndex(item => item.Name === request.Name); const existingArrayId = profile.userbuilds.magazineBuilds.findIndex((item) => item.Name === request.Name);
if (existingArrayId === -1) if (existingArrayId === -1)
{ {

View File

@ -42,10 +42,10 @@ export class CustomizationController
const suits = this.databaseServer.getTables().traders[traderID].suits; const suits = this.databaseServer.getTables().traders[traderID].suits;
// Get an inner join of clothing from templates.customization and Ragman's suits array // Get an inner join of clothing from templates.customization and Ragman's suits array
const matchingSuits = suits.filter(x => x.suiteId in templates); const matchingSuits = suits.filter((x) => x.suiteId in templates);
// Return all suits that have a side array containing the players side (usec/bear) // Return all suits that have a side array containing the players side (usec/bear)
return matchingSuits.filter(x => templates[x.suiteId]._props.Side.includes(pmcData.Info.Side)); return matchingSuits.filter((x) => templates[x.suiteId]._props.Side.includes(pmcData.Info.Side));
} }
/** /**
@ -132,7 +132,7 @@ export class CustomizationController
protected getTraderClothingOffer(sessionId: string, offerId: string): ISuit protected getTraderClothingOffer(sessionId: string, offerId: string): ISuit
{ {
return this.getAllTraderSuits(sessionId).find(x => x._id === offerId); return this.getAllTraderSuits(sessionId).find((x) => x._id === offerId);
} }
/** /**
@ -180,7 +180,7 @@ export class CustomizationController
output: IItemEventRouterResponse, output: IItemEventRouterResponse,
): void ): void
{ {
const relatedItem = pmcData.Inventory.items.find(x => x._id === clothingItem.id); const relatedItem = pmcData.Inventory.items.find((x) => x._id === clothingItem.id);
if (!relatedItem) if (!relatedItem)
{ {
this.logger.error( this.logger.error(

View File

@ -1,6 +1,8 @@
import { inject, injectAll, injectable } from "tsyringe"; import { inject, injectAll, injectable } from "tsyringe";
import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot"; import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot";
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper"; import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
import { IFriendRequestData } from "@spt-aki/models/eft/dialog/IFriendRequestData";
import { IFriendRequestSendResponse } from "@spt-aki/models/eft/dialog/IFriendRequestSendResponse";
import { IGetAllAttachmentsResponse } from "@spt-aki/models/eft/dialog/IGetAllAttachmentsResponse"; import { IGetAllAttachmentsResponse } from "@spt-aki/models/eft/dialog/IGetAllAttachmentsResponse";
import { IGetFriendListDataResponse } from "@spt-aki/models/eft/dialog/IGetFriendListDataResponse"; import { IGetFriendListDataResponse } from "@spt-aki/models/eft/dialog/IGetFriendListDataResponse";
import { IGetMailDialogViewRequestData } from "@spt-aki/models/eft/dialog/IGetMailDialogViewRequestData"; import { IGetMailDialogViewRequestData } from "@spt-aki/models/eft/dialog/IGetMailDialogViewRequestData";
@ -15,8 +17,6 @@ import { ConfigServer } from "@spt-aki/servers/ConfigServer";
import { SaveServer } from "@spt-aki/servers/SaveServer"; import { SaveServer } from "@spt-aki/servers/SaveServer";
import { MailSendService } from "@spt-aki/services/MailSendService"; import { MailSendService } from "@spt-aki/services/MailSendService";
import { TimeUtil } from "@spt-aki/utils/TimeUtil"; import { TimeUtil } from "@spt-aki/utils/TimeUtil";
import { IFriendRequestData } from "@spt-aki/models/eft/dialog/IFriendRequestData";
import { IFriendRequestSendResponse } from "@spt-aki/models/eft/dialog/IFriendRequestSendResponse";
@injectable() @injectable()
export class DialogueController export class DialogueController
@ -35,21 +35,21 @@ export class DialogueController
// if give command is disabled or commando commands are disabled // if give command is disabled or commando commands are disabled
if (!coreConfigs.features?.chatbotFeatures?.commandoEnabled) if (!coreConfigs.features?.chatbotFeatures?.commandoEnabled)
{ {
const sptCommando = this.dialogueChatBots.find(c => const sptCommando = this.dialogueChatBots.find(
c.getChatBot()._id.toLocaleLowerCase() === "sptcommando", (c) => c.getChatBot()._id.toLocaleLowerCase() === "sptcommando",
); );
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptCommando), 1); this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptCommando), 1);
} }
if (!coreConfigs.features?.chatbotFeatures?.sptFriendEnabled) if (!coreConfigs.features?.chatbotFeatures?.sptFriendEnabled)
{ {
const sptFriend = this.dialogueChatBots.find(c => c.getChatBot()._id.toLocaleLowerCase() === "sptFriend"); const sptFriend = this.dialogueChatBots.find((c) => c.getChatBot()._id.toLocaleLowerCase() === "sptFriend");
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptFriend), 1); this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptFriend), 1);
} }
} }
public registerChatBot(chatBot: IDialogueChatBot): void public registerChatBot(chatBot: IDialogueChatBot): void
{ {
if (this.dialogueChatBots.some(cb => cb.getChatBot()._id === chatBot.getChatBot()._id)) if (this.dialogueChatBots.some((cb) => cb.getChatBot()._id === chatBot.getChatBot()._id))
{ {
throw new Error(`The chat bot ${chatBot.getChatBot()._id} being registered already exists!`); throw new Error(`The chat bot ${chatBot.getChatBot()._id} being registered already exists!`);
} }
@ -74,7 +74,7 @@ export class DialogueController
public getFriendList(sessionID: string): IGetFriendListDataResponse public getFriendList(sessionID: string): IGetFriendListDataResponse
{ {
// Force a fake friend called SPT into friend list // Force a fake friend called SPT into friend list
return { Friends: this.dialogueChatBots.map(v => v.getChatBot()), Ignore: [], InIgnoreList: [] }; return { Friends: this.dialogueChatBots.map((v) => v.getChatBot()), Ignore: [], InIgnoreList: [] };
} }
/** /**
@ -133,7 +133,7 @@ export class DialogueController
// User to user messages are special in that they need the player to exist in them, add if they don't // User to user messages are special in that they need the player to exist in them, add if they don't
if ( if (
messageType === MessageType.USER_MESSAGE messageType === MessageType.USER_MESSAGE
&& !dialog.Users?.find(userDialog => userDialog._id === profile.characters.pmc.sessionId) && !dialog.Users?.find((userDialog) => userDialog._id === profile.characters.pmc.sessionId)
) )
{ {
if (!dialog.Users) if (!dialog.Users)
@ -209,7 +209,7 @@ export class DialogueController
if (request.type === MessageType.USER_MESSAGE) if (request.type === MessageType.USER_MESSAGE)
{ {
profile.dialogues[request.dialogId].Users = []; profile.dialogues[request.dialogId].Users = [];
const chatBot = this.dialogueChatBots.find(cb => cb.getChatBot()._id === request.dialogId); const chatBot = this.dialogueChatBots.find((cb) => cb.getChatBot()._id === request.dialogId);
if (chatBot) if (chatBot)
{ {
profile.dialogues[request.dialogId].Users.push(chatBot.getChatBot()); profile.dialogues[request.dialogId].Users.push(chatBot.getChatBot());
@ -233,7 +233,7 @@ export class DialogueController
{ {
result.push(...dialogUsers); result.push(...dialogUsers);
if (!result.find(userDialog => userDialog._id === fullProfile.info.id)) if (!result.find((userDialog) => userDialog._id === fullProfile.info.id))
{ {
// Player doesnt exist, add them in before returning // Player doesnt exist, add them in before returning
const pmcProfile = fullProfile.characters.pmc; const pmcProfile = fullProfile.characters.pmc;
@ -281,7 +281,7 @@ export class DialogueController
*/ */
protected messagesHaveUncollectedRewards(messages: Message[]): boolean protected messagesHaveUncollectedRewards(messages: Message[]): boolean
{ {
return messages.some(message => message.items?.data?.length > 0); return messages.some((message) => message.items?.data?.length > 0);
} }
/** /**
@ -378,10 +378,11 @@ export class DialogueController
{ {
this.mailSendService.sendPlayerMessageToNpc(sessionId, request.dialogId, request.text); this.mailSendService.sendPlayerMessageToNpc(sessionId, request.dialogId, request.text);
return this.dialogueChatBots.find(cb => cb.getChatBot()._id === request.dialogId)?.handleMessage( return (
sessionId, this.dialogueChatBots
request, .find((cb) => cb.getChatBot()._id === request.dialogId)
) ?? request.dialogId; ?.handleMessage(sessionId, request) ?? request.dialogId
);
} }
/** /**
@ -394,7 +395,7 @@ export class DialogueController
{ {
const timeNow = this.timeUtil.getTimestamp(); const timeNow = this.timeUtil.getTimestamp();
const dialogs = this.dialogueHelper.getDialogsForProfile(sessionId); const dialogs = this.dialogueHelper.getDialogsForProfile(sessionId);
return dialogs[dialogueId].messages.filter(message => timeNow < message.dt + message.maxStorageTime); return dialogs[dialogueId].messages.filter((message) => timeNow < message.dt + message.maxStorageTime);
} }
/** /**
@ -404,7 +405,7 @@ export class DialogueController
*/ */
protected getMessagesWithAttachments(messages: Message[]): Message[] protected getMessagesWithAttachments(messages: Message[]): Message[]
{ {
return messages.filter(message => message.items?.data?.length > 0); return messages.filter((message) => message.items?.data?.length > 0);
} }
/** /**
@ -453,12 +454,8 @@ export class DialogueController
} }
/** Handle client/friend/request/send */ /** Handle client/friend/request/send */
public sendFriendRequest( public sendFriendRequest(sessionID: string, request: IFriendRequestData): IFriendRequestSendResponse
sessionID: string,
request: IFriendRequestData
): IFriendRequestSendResponse
{ {
return { status: 0, requestId: "12345", retryAfter: 600 } return { status: 0, requestId: "12345", retryAfter: 600 };
} }
} }

View File

@ -359,8 +359,8 @@ export class GameController
for (const positionToAdd of positionsToAdd) for (const positionToAdd of positionsToAdd)
{ {
// Exists already, add new items to existing positions pool // Exists already, add new items to existing positions pool
const existingLootPosition = mapLooseLoot.spawnpoints.find(x => const existingLootPosition = mapLooseLoot.spawnpoints.find(
x.template.Id === positionToAdd.template.Id, (x) => x.template.Id === positionToAdd.template.Id,
); );
if (existingLootPosition) if (existingLootPosition)
{ {
@ -390,7 +390,7 @@ export class GameController
const mapLootAdjustmentsDict = adjustments[mapId]; const mapLootAdjustmentsDict = adjustments[mapId];
for (const lootKey in mapLootAdjustmentsDict) for (const lootKey in mapLootAdjustmentsDict)
{ {
const lootPostionToAdjust = mapLooseLootData.spawnpoints.find(x => x.template.Id === lootKey); const lootPostionToAdjust = mapLooseLootData.spawnpoints.find((x) => x.template.Id === lootKey);
if (!lootPostionToAdjust) if (!lootPostionToAdjust)
{ {
this.logger.warning(`Unable to adjust loot position: ${lootKey} on map: ${mapId}`); this.logger.warning(`Unable to adjust loot position: ${lootKey} on map: ${mapId}`);
@ -423,7 +423,7 @@ export class GameController
for (const botToLimit of this.locationConfig.botTypeLimits[mapId]) for (const botToLimit of this.locationConfig.botTypeLimits[mapId])
{ {
const index = map.base.MinMaxBots.findIndex(x => x.WildSpawnType === botToLimit.type); const index = map.base.MinMaxBots.findIndex((x) => x.WildSpawnType === botToLimit.type);
if (index !== -1) if (index !== -1)
{ {
// Existing bot type found in MinMaxBots array, edit // Existing bot type found in MinMaxBots array, edit
@ -452,8 +452,8 @@ export class GameController
{ {
const profile = this.profileHelper.getPmcProfile(sessionID); const profile = this.profileHelper.getPmcProfile(sessionID);
const gameTime const gameTime
= profile.Stats?.Eft.OverallCounters.Items?.find(counter => = profile.Stats?.Eft.OverallCounters.Items?.find(
counter.Key.includes("LifeTime") && counter.Key.includes("Pmc"), (counter) => counter.Key.includes("LifeTime") && counter.Key.includes("Pmc"),
)?.Value ?? 0; )?.Value ?? 0;
const config: IGameConfigResponse = { const config: IGameConfigResponse = {
@ -598,12 +598,13 @@ export class GameController
let hpRegenPerHour = 456.6; let hpRegenPerHour = 456.6;
// Set new values, whatever is smallest // Set new values, whatever is smallest
energyRegenPerHour += pmcProfile.Bonuses.filter(bonus => bonus.type === BonusType.ENERGY_REGENERATION) energyRegenPerHour += pmcProfile.Bonuses.filter(
.reduce((sum, curr) => sum + curr.value, 0); (bonus) => bonus.type === BonusType.ENERGY_REGENERATION,
hydrationRegenPerHour += pmcProfile.Bonuses.filter(bonus =>
bonus.type === BonusType.HYDRATION_REGENERATION,
).reduce((sum, curr) => sum + curr.value, 0); ).reduce((sum, curr) => sum + curr.value, 0);
hpRegenPerHour += pmcProfile.Bonuses.filter(bonus => bonus.type === BonusType.HEALTH_REGENERATION).reduce( hydrationRegenPerHour += pmcProfile.Bonuses.filter(
(bonus) => bonus.type === BonusType.HYDRATION_REGENERATION,
).reduce((sum, curr) => sum + curr.value, 0);
hpRegenPerHour += pmcProfile.Bonuses.filter((bonus) => bonus.type === BonusType.HEALTH_REGENERATION).reduce(
(sum, curr) => sum + curr.value, (sum, curr) => sum + curr.value,
0, 0,
); );
@ -738,13 +739,13 @@ export class GameController
const currentTimeStamp = this.timeUtil.getTimestamp(); const currentTimeStamp = this.timeUtil.getTimestamp();
// One day post-profile creation // One day post-profile creation
if (currentTimeStamp > (timeStampProfileCreated + oneDaySeconds)) if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds)
{ {
this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 1); this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 1);
} }
// Two day post-profile creation // Two day post-profile creation
if (currentTimeStamp > (timeStampProfileCreated + oneDaySeconds * 2)) if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds * 2)
{ {
this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 2); this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 2);
} }
@ -841,8 +842,11 @@ export class GameController
{ {
const modDetails = activeMods[modKey]; const modDetails = activeMods[modKey];
if ( if (
fullProfile.aki.mods.some(x => fullProfile.aki.mods.some(
x.author === modDetails.author && x.name === modDetails.name && x.version === modDetails.version, (x) =>
x.author === modDetails.author
&& x.name === modDetails.name
&& x.version === modDetails.version,
) )
) )
{ {
@ -957,8 +961,8 @@ export class GameController
protected adjustLabsRaiderSpawnRate(): void protected adjustLabsRaiderSpawnRate(): void
{ {
const labsBase = this.databaseServer.getTables().locations.laboratory.base; const labsBase = this.databaseServer.getTables().locations.laboratory.base;
const nonTriggerLabsBossSpawns = labsBase.BossLocationSpawn.filter(x => const nonTriggerLabsBossSpawns = labsBase.BossLocationSpawn.filter(
x.TriggerId === "" && x.TriggerName === "", (x) => x.TriggerId === "" && x.TriggerName === "",
); );
if (nonTriggerLabsBossSpawns) if (nonTriggerLabsBossSpawns)
{ {

View File

@ -60,12 +60,16 @@ export class HealthController
* @param sessionID Player id * @param sessionID Player id
* @returns IItemEventRouterResponse * @returns IItemEventRouterResponse
*/ */
public offraidHeal(pmcData: IPmcData, request: IOffraidHealRequestData, sessionID: string): IItemEventRouterResponse public offraidHeal(
pmcData: IPmcData,
request: IOffraidHealRequestData,
sessionID: string,
): IItemEventRouterResponse
{ {
const output = this.eventOutputHolder.getOutput(sessionID); const output = this.eventOutputHolder.getOutput(sessionID);
// Update medkit used (hpresource) // Update medkit used (hpresource)
const healingItemToUse = pmcData.Inventory.items.find(item => item._id === request.item); const healingItemToUse = pmcData.Inventory.items.find((item) => item._id === request.item);
if (!healingItemToUse) if (!healingItemToUse)
{ {
const errorMessage = this.localisationService.getText( const errorMessage = this.localisationService.getText(
@ -113,7 +117,7 @@ export class HealthController
const output = this.eventOutputHolder.getOutput(sessionID); const output = this.eventOutputHolder.getOutput(sessionID);
let resourceLeft = 0; let resourceLeft = 0;
const itemToConsume = pmcData.Inventory.items.find(x => x._id === request.item); const itemToConsume = pmcData.Inventory.items.find((x) => x._id === request.item);
if (!itemToConsume) if (!itemToConsume)
{ {
// Item not found, very bad // Item not found, very bad

View File

@ -11,7 +11,6 @@ import {
HideoutArea, HideoutArea,
ITaskConditionCounter, ITaskConditionCounter,
Product, Product,
Production,
ScavCase, ScavCase,
} from "@spt-aki/models/eft/common/tables/IBotBase"; } from "@spt-aki/models/eft/common/tables/IBotBase";
import { Item } from "@spt-aki/models/eft/common/tables/IItem"; import { Item } from "@spt-aki/models/eft/common/tables/IItem";
@ -105,7 +104,7 @@ export class HideoutController
{ {
const items = request.items.map((reqItem) => const items = request.items.map((reqItem) =>
{ {
const item = pmcData.Inventory.items.find(invItem => invItem._id === reqItem.id); const item = pmcData.Inventory.items.find((invItem) => invItem._id === reqItem.id);
return { inventoryItem: item, requestedItem: reqItem }; return { inventoryItem: item, requestedItem: reqItem };
}); });
@ -138,7 +137,7 @@ export class HideoutController
} }
// Construction time management // Construction time management
const profileHideoutArea = pmcData.Hideout.Areas.find(area => area.type === request.areaType); const profileHideoutArea = pmcData.Hideout.Areas.find((area) => area.type === request.areaType);
if (!profileHideoutArea) if (!profileHideoutArea)
{ {
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType)); this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
@ -147,9 +146,9 @@ export class HideoutController
return; return;
} }
const hideoutDataDb = this.databaseServer.getTables().hideout.areas.find(area => const hideoutDataDb = this.databaseServer
area.type === request.areaType, .getTables()
); .hideout.areas.find((area) => area.type === request.areaType);
if (!hideoutDataDb) if (!hideoutDataDb)
{ {
this.logger.error( this.logger.error(
@ -191,7 +190,7 @@ export class HideoutController
{ {
const db = this.databaseServer.getTables(); const db = this.databaseServer.getTables();
const profileHideoutArea = pmcData.Hideout.Areas.find(area => area.type === request.areaType); const profileHideoutArea = pmcData.Hideout.Areas.find((area) => area.type === request.areaType);
if (!profileHideoutArea) if (!profileHideoutArea)
{ {
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType)); this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
@ -205,7 +204,7 @@ export class HideoutController
profileHideoutArea.completeTime = 0; profileHideoutArea.completeTime = 0;
profileHideoutArea.constructing = false; profileHideoutArea.constructing = false;
const hideoutData = db.hideout.areas.find(area => area.type === profileHideoutArea.type); const hideoutData = db.hideout.areas.find((area) => area.type === profileHideoutArea.type);
if (!hideoutData) if (!hideoutData)
{ {
this.logger.error( this.logger.error(
@ -263,11 +262,11 @@ export class HideoutController
*/ */
protected checkAndUpgradeWall(pmcData: IPmcData): void protected checkAndUpgradeWall(pmcData: IPmcData): void
{ {
const medStation = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.MEDSTATION); const medStation = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.MEDSTATION);
const waterCollector = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.WATER_COLLECTOR); const waterCollector = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.WATER_COLLECTOR);
if (medStation?.level >= 1 && waterCollector?.level >= 1) if (medStation?.level >= 1 && waterCollector?.level >= 1)
{ {
const wall = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.EMERGENCY_WALL); const wall = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.EMERGENCY_WALL);
if (wall?.level === 0) if (wall?.level === 0)
{ {
wall.level = 3; wall.level = 3;
@ -309,9 +308,9 @@ export class HideoutController
} }
// Some areas like gun stand have a child area linked to it, it needs to do the same as above // Some areas like gun stand have a child area linked to it, it needs to do the same as above
const childDbArea = this.databaseServer.getTables().hideout.areas.find(x => const childDbArea = this.databaseServer
x.parentArea === dbHideoutArea._id, .getTables()
); .hideout.areas.find((x) => x.parentArea === dbHideoutArea._id);
if (childDbArea) if (childDbArea)
{ {
// Add key/value to `hideoutAreaStashes` dictionary - used to link hideout area to inventory stash by its id // Add key/value to `hideoutAreaStashes` dictionary - used to link hideout area to inventory stash by its id
@ -321,8 +320,8 @@ export class HideoutController
} }
// Set child area level to same as parent area // Set child area level to same as parent area
pmcData.Hideout.Areas.find(x => x.type === childDbArea.type).level = pmcData.Hideout.Areas.find(x => pmcData.Hideout.Areas.find((x) => x.type === childDbArea.type).level = pmcData.Hideout.Areas.find(
x.type === profileParentHideoutArea.type, (x) => x.type === profileParentHideoutArea.type,
).level; ).level;
// Add/upgrade stash item in player inventory // Add/upgrade stash item in player inventory
@ -340,9 +339,13 @@ export class HideoutController
* @param dbHideoutData Hideout area from db being upgraded * @param dbHideoutData Hideout area from db being upgraded
* @param hideoutStage Stage area upgraded to * @param hideoutStage Stage area upgraded to
*/ */
protected addUpdateInventoryItemToProfile(pmcData: IPmcData, dbHideoutData: IHideoutArea, hideoutStage: Stage): void protected addUpdateInventoryItemToProfile(
pmcData: IPmcData,
dbHideoutData: IHideoutArea,
hideoutStage: Stage,
): void
{ {
const existingInventoryItem = pmcData.Inventory.items.find(x => x._id === dbHideoutData._id); const existingInventoryItem = pmcData.Inventory.items.find((x) => x._id === dbHideoutData._id);
if (existingInventoryItem) if (existingInventoryItem)
{ {
// Update existing items container tpl to point to new id (tpl) // Update existing items container tpl to point to new id (tpl)
@ -399,11 +402,11 @@ export class HideoutController
const itemsToAdd = Object.entries(addItemToHideoutRequest.items).map((kvp) => const itemsToAdd = Object.entries(addItemToHideoutRequest.items).map((kvp) =>
{ {
const item = pmcData.Inventory.items.find(invItem => invItem._id === kvp[1].id); const item = pmcData.Inventory.items.find((invItem) => invItem._id === kvp[1].id);
return { inventoryItem: item, requestedItem: kvp[1], slot: kvp[0] }; return { inventoryItem: item, requestedItem: kvp[1], slot: kvp[0] };
}); });
const hideoutArea = pmcData.Hideout.Areas.find(area => area.type === addItemToHideoutRequest.areaType); const hideoutArea = pmcData.Hideout.Areas.find((area) => area.type === addItemToHideoutRequest.areaType);
if (!hideoutArea) if (!hideoutArea)
{ {
this.logger.error( this.logger.error(
@ -430,12 +433,14 @@ export class HideoutController
// Add item to area.slots // Add item to area.slots
const destinationLocationIndex = Number(item.slot); const destinationLocationIndex = Number(item.slot);
const hideoutSlotIndex = hideoutArea.slots.findIndex(x => x.locationIndex === destinationLocationIndex); const hideoutSlotIndex = hideoutArea.slots.findIndex((x) => x.locationIndex === destinationLocationIndex);
hideoutArea.slots[hideoutSlotIndex].item = [{ hideoutArea.slots[hideoutSlotIndex].item = [
_id: item.inventoryItem._id, {
_tpl: item.inventoryItem._tpl, _id: item.inventoryItem._id,
upd: item.inventoryItem.upd, _tpl: item.inventoryItem._tpl,
}]; upd: item.inventoryItem.upd,
},
];
this.inventoryHelper.removeItem(pmcData, item.inventoryItem._id, sessionID, output); this.inventoryHelper.removeItem(pmcData, item.inventoryItem._id, sessionID, output);
} }
@ -462,7 +467,7 @@ export class HideoutController
{ {
const output = this.eventOutputHolder.getOutput(sessionID); const output = this.eventOutputHolder.getOutput(sessionID);
const hideoutArea = pmcData.Hideout.Areas.find(area => area.type === request.areaType); const hideoutArea = pmcData.Hideout.Areas.find((area) => area.type === request.areaType);
if (!hideoutArea) if (!hideoutArea)
{ {
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType)); this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
@ -519,7 +524,7 @@ export class HideoutController
const slotIndexToRemove = removeResourceRequest.slots[0]; const slotIndexToRemove = removeResourceRequest.slots[0];
// Assume only one item in slot // Assume only one item in slot
const itemToReturn = hideoutArea.slots.find(slot => slot.locationIndex === slotIndexToRemove).item[0]; const itemToReturn = hideoutArea.slots.find((slot) => slot.locationIndex === slotIndexToRemove).item[0];
const request: IAddItemDirectRequest = { const request: IAddItemDirectRequest = {
itemWithModsToAdd: [itemToReturn], itemWithModsToAdd: [itemToReturn],
@ -536,7 +541,7 @@ export class HideoutController
} }
// Remove items from slot, locationIndex remains // Remove items from slot, locationIndex remains
const hideoutSlotIndex = hideoutArea.slots.findIndex(slot => slot.locationIndex === slotIndexToRemove); const hideoutSlotIndex = hideoutArea.slots.findIndex((slot) => slot.locationIndex === slotIndexToRemove);
hideoutArea.slots[hideoutSlotIndex].item = undefined; hideoutArea.slots[hideoutSlotIndex].item = undefined;
return output; return output;
@ -561,7 +566,7 @@ export class HideoutController
// Force a production update (occur before area is toggled as it could be generator and doing it after generator enabled would cause incorrect calculaton of production progress) // Force a production update (occur before area is toggled as it could be generator and doing it after generator enabled would cause incorrect calculaton of production progress)
this.hideoutHelper.updatePlayerHideout(sessionID); this.hideoutHelper.updatePlayerHideout(sessionID);
const hideoutArea = pmcData.Hideout.Areas.find(area => area.type === request.areaType); const hideoutArea = pmcData.Hideout.Areas.find((area) => area.type === request.areaType);
if (!hideoutArea) if (!hideoutArea)
{ {
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType)); this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
@ -591,20 +596,20 @@ export class HideoutController
this.hideoutHelper.registerProduction(pmcData, body, sessionID); this.hideoutHelper.registerProduction(pmcData, body, sessionID);
// Find the recipe of the production // Find the recipe of the production
const recipe = this.databaseServer.getTables().hideout.production.find(p => p._id === body.recipeId); const recipe = this.databaseServer.getTables().hideout.production.find((p) => p._id === body.recipeId);
// Find the actual amount of items we need to remove because body can send weird data // Find the actual amount of items we need to remove because body can send weird data
const recipeRequirementsClone = this.cloner.clone( const recipeRequirementsClone = this.cloner.clone(
recipe.requirements.filter(i => i.type === "Item" || i.type === "Tool"), recipe.requirements.filter((i) => i.type === "Item" || i.type === "Tool"),
); );
const output = this.eventOutputHolder.getOutput(sessionID); const output = this.eventOutputHolder.getOutput(sessionID);
const itemsToDelete = body.items.concat(body.tools); const itemsToDelete = body.items.concat(body.tools);
for (const itemToDelete of itemsToDelete) for (const itemToDelete of itemsToDelete)
{ {
const itemToCheck = pmcData.Inventory.items.find(i => i._id === itemToDelete.id); const itemToCheck = pmcData.Inventory.items.find((i) => i._id === itemToDelete.id);
const requirement = recipeRequirementsClone.find(requirement => const requirement = recipeRequirementsClone.find(
requirement.templateId === itemToCheck._tpl, (requirement) => requirement.templateId === itemToCheck._tpl,
); );
// Handle tools not having a `count`, but always only requiring 1 // Handle tools not having a `count`, but always only requiring 1
@ -644,7 +649,7 @@ export class HideoutController
for (const requestedItem of body.items) for (const requestedItem of body.items)
{ {
const inventoryItem = pmcData.Inventory.items.find(item => item._id === requestedItem.id); const inventoryItem = pmcData.Inventory.items.find((item) => item._id === requestedItem.id);
if (!inventoryItem) if (!inventoryItem)
{ {
this.logger.error( this.logger.error(
@ -666,7 +671,7 @@ export class HideoutController
} }
} }
const recipe = this.databaseServer.getTables().hideout.scavcase.find(r => r._id === body.recipeId); const recipe = this.databaseServer.getTables().hideout.scavcase.find((r) => r._id === body.recipeId);
if (!recipe) if (!recipe)
{ {
this.logger.error( this.logger.error(
@ -678,12 +683,14 @@ export class HideoutController
// @Important: Here we need to be very exact: // @Important: Here we need to be very exact:
// - normal recipe: Production time value is stored in attribute "productionTime" with small "p" // - normal recipe: Production time value is stored in attribute "productionTime" with small "p"
// - scav case recipe: Production time value is stored in attribute "ProductionTime" with capital "P" // - scav case recipe: Production time value is stored in attribute "ProductionTime" with capital "P"
const adjustedCraftTime = recipe.ProductionTime - this.hideoutHelper.getSkillProductionTimeReduction( const adjustedCraftTime
pmcData, = recipe.ProductionTime
recipe.ProductionTime, - this.hideoutHelper.getSkillProductionTimeReduction(
SkillTypes.CRAFTING, pmcData,
this.databaseServer.getTables().globals.config.SkillsSettings.Crafting.CraftTimeReductionPerLevel, recipe.ProductionTime,
); SkillTypes.CRAFTING,
this.databaseServer.getTables().globals.config.SkillsSettings.Crafting.CraftTimeReductionPerLevel,
);
const modifiedScavCaseTime = this.getScavCaseTime(pmcData, adjustedCraftTime); const modifiedScavCaseTime = this.getScavCaseTime(pmcData, adjustedCraftTime);
@ -770,7 +777,7 @@ export class HideoutController
return output; return output;
} }
const recipe = hideoutDb.production.find(r => r._id === request.recipeId); const recipe = hideoutDb.production.find((r) => r._id === request.recipeId);
if (recipe) if (recipe)
{ {
this.handleRecipe(sessionID, recipe, pmcData, request, output); this.handleRecipe(sessionID, recipe, pmcData, request, output);
@ -778,7 +785,7 @@ export class HideoutController
return output; return output;
} }
const scavCase = hideoutDb.scavcase.find(r => r._id === request.recipeId); const scavCase = hideoutDb.scavcase.find((r) => r._id === request.recipeId);
if (scavCase) if (scavCase)
{ {
this.handleScavCase(sessionID, pmcData, request, output); this.handleScavCase(sessionID, pmcData, request, output);
@ -936,7 +943,7 @@ export class HideoutController
} }
// Check if the recipe is the same as the last one - get bonus when crafting same thing multiple times // Check if the recipe is the same as the last one - get bonus when crafting same thing multiple times
const area = pmcData.Hideout.Areas.find(area => area.type === recipe.areaType); const area = pmcData.Hideout.Areas.find((area) => area.type === recipe.areaType);
if (area && request.recipeId !== area.lastRecipe) if (area && request.recipeId !== area.lastRecipe)
{ {
// 1 point per craft upon the end of production for alternating between 2 different crafting recipes in the same module // 1 point per craft upon the end of production for alternating between 2 different crafting recipes in the same module
@ -1042,7 +1049,10 @@ export class HideoutController
* @param recipe Recipe being crafted * @param recipe Recipe being crafted
* @returns ITaskConditionCounter * @returns ITaskConditionCounter
*/ */
protected getHoursCraftingTaskConditionCounter(pmcData: IPmcData, recipe: IHideoutProduction): ITaskConditionCounter protected getHoursCraftingTaskConditionCounter(
pmcData: IPmcData,
recipe: IHideoutProduction,
): ITaskConditionCounter
{ {
let counterHoursCrafting = pmcData.TaskConditionCounters[HideoutController.nameTaskConditionCountersCrafting]; let counterHoursCrafting = pmcData.TaskConditionCounters[HideoutController.nameTaskConditionCountersCrafting];
if (!counterHoursCrafting) if (!counterHoursCrafting)
@ -1078,7 +1088,8 @@ export class HideoutController
for (const production of ongoingProductions) for (const production of ongoingProductions)
{ {
if (this.hideoutHelper.isProductionType(production[1])) if (this.hideoutHelper.isProductionType(production[1]))
{ // Production or ScavCase {
// Production or ScavCase
if ((production[1] as ScavCase).RecipeId === request.recipeId) if ((production[1] as ScavCase).RecipeId === request.recipeId)
{ {
prodId = production[0]; // Set to objects key prodId = production[0]; // Set to objects key
@ -1187,13 +1198,13 @@ export class HideoutController
public recordShootingRangePoints(sessionId: string, pmcData: IPmcData, request: IRecordShootingRangePoints): void public recordShootingRangePoints(sessionId: string, pmcData: IPmcData, request: IRecordShootingRangePoints): void
{ {
// Check if counter exists, add placeholder if it doesnt // Check if counter exists, add placeholder if it doesnt
if (!pmcData.Stats.Eft.OverallCounters.Items.find(x => x.Key.includes("ShootingRangePoints"))) if (!pmcData.Stats.Eft.OverallCounters.Items.find((x) => x.Key.includes("ShootingRangePoints")))
{ {
pmcData.Stats.Eft.OverallCounters.Items.push({ Key: ["ShootingRangePoints"], Value: 0 }); pmcData.Stats.Eft.OverallCounters.Items.push({ Key: ["ShootingRangePoints"], Value: 0 });
} }
// Find counter by key and update value // Find counter by key and update value
const shootingRangeHighScore = pmcData.Stats.Eft.OverallCounters.Items.find(x => const shootingRangeHighScore = pmcData.Stats.Eft.OverallCounters.Items.find((x) =>
x.Key.includes("ShootingRangePoints"), x.Key.includes("ShootingRangePoints"),
); );
shootingRangeHighScore.Value = request.points; shootingRangeHighScore.Value = request.points;
@ -1216,7 +1227,7 @@ export class HideoutController
// Create mapping of required item with corrisponding item from player inventory // Create mapping of required item with corrisponding item from player inventory
const items = request.items.map((reqItem) => const items = request.items.map((reqItem) =>
{ {
const item = pmcData.Inventory.items.find(invItem => invItem._id === reqItem.id); const item = pmcData.Inventory.items.find((invItem) => invItem._id === reqItem.id);
return { inventoryItem: item, requestedItem: reqItem }; return { inventoryItem: item, requestedItem: reqItem };
}); });
@ -1246,14 +1257,14 @@ export class HideoutController
} }
} }
const profileHideoutArea = pmcData.Hideout.Areas.find(x => x.type === request.areaType); const profileHideoutArea = pmcData.Hideout.Areas.find((x) => x.type === request.areaType);
if (!profileHideoutArea) if (!profileHideoutArea)
{ {
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType)); this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
return this.httpResponse.appendErrorToOutput(output); return this.httpResponse.appendErrorToOutput(output);
} }
const hideoutDbData = this.databaseServer.getTables().hideout.areas.find(x => x.type === request.areaType); const hideoutDbData = this.databaseServer.getTables().hideout.areas.find((x) => x.type === request.areaType);
if (!hideoutDbData) if (!hideoutDbData)
{ {
this.logger.error( this.logger.error(

View File

@ -201,7 +201,7 @@ export class InraidController
if (locationName === "lighthouse" && postRaidRequest.profile.Info.Side.toLowerCase() === "usec") if (locationName === "lighthouse" && postRaidRequest.profile.Info.Side.toLowerCase() === "usec")
{ {
// Decrement counter if it exists, don't go below 0 // Decrement counter if it exists, don't go below 0
const remainingCounter = serverPmcProfile?.Stats.Eft.OverallCounters.Items.find(x => const remainingCounter = serverPmcProfile?.Stats.Eft.OverallCounters.Items.find((x) =>
x.Key.includes("UsecRaidRemainKills"), x.Key.includes("UsecRaidRemainKills"),
); );
if (remainingCounter?.Value > 0) if (remainingCounter?.Value > 0)
@ -226,9 +226,9 @@ export class InraidController
// Not dead // Not dead
// Check for cultist amulets in special slot (only slot it can fit) // Check for cultist amulets in special slot (only slot it can fit)
const amuletOnPlayer = serverPmcProfile.Inventory.items.filter(item => const amuletOnPlayer = serverPmcProfile.Inventory.items
item.slotId?.startsWith("SpecialSlot"), .filter((item) => item.slotId?.startsWith("SpecialSlot"))
).find(item => item._tpl === "64d0b40fbe2eed70e254e2d4"); .find((item) => item._tpl === "64d0b40fbe2eed70e254e2d4");
if (amuletOnPlayer) if (amuletOnPlayer)
{ {
// No charges left, delete it // No charges left, delete it
@ -247,7 +247,7 @@ export class InraidController
} }
} }
const victims = postRaidRequest.profile.Stats.Eft.Victims.filter(x => const victims = postRaidRequest.profile.Stats.Eft.Victims.filter((x) =>
["sptbear", "sptusec"].includes(x.Role.toLowerCase()), ["sptbear", "sptusec"].includes(x.Role.toLowerCase()),
); );
if (victims?.length > 0) if (victims?.length > 0)
@ -281,12 +281,11 @@ export class InraidController
// and quest items cannot be picked up again // and quest items cannot be picked up again
const allQuests = this.questHelper.getQuestsFromDb(); const allQuests = this.questHelper.getQuestsFromDb();
const activeQuestIdsInProfile = pmcData.Quests.filter( const activeQuestIdsInProfile = pmcData.Quests.filter(
profileQuest => ![ (profileQuest) =>
QuestStatus.AvailableForStart, ![QuestStatus.AvailableForStart, QuestStatus.Success, QuestStatus.Expired].includes(
QuestStatus.Success, profileQuest.status,
QuestStatus.Expired, ),
].includes(profileQuest.status), ).map((x) => x.qid);
).map(x => x.qid);
for (const questItem of postRaidSaveRequest.profile.Stats.Eft.CarriedQuestItems) for (const questItem of postRaidSaveRequest.profile.Stats.Eft.CarriedQuestItems)
{ {
// Get quest/find condition for carried quest item // Get quest/find condition for carried quest item
@ -470,7 +469,7 @@ export class InraidController
for (const quest of scavProfile.Quests) for (const quest of scavProfile.Quests)
{ {
const pmcQuest = pmcProfile.Quests.find(x => x.qid === quest.qid); const pmcQuest = pmcProfile.Quests.find((x) => x.qid === quest.qid);
if (!pmcQuest) if (!pmcQuest)
{ {
this.logger.warning(`No PMC quest found for ID: ${quest.qid}`); this.logger.warning(`No PMC quest found for ID: ${quest.qid}`);
@ -505,7 +504,7 @@ export class InraidController
for (const scavCounter of Object.values(scavProfile.TaskConditionCounters)) for (const scavCounter of Object.values(scavProfile.TaskConditionCounters))
{ {
// If this is an achievement that isn't for the scav, don't process it // If this is an achievement that isn't for the scav, don't process it
const achievement = achievements.find(achievement => achievement.id === scavCounter.sourceId); const achievement = achievements.find((achievement) => achievement.id === scavCounter.sourceId);
if (achievement && achievement.side !== "Savage") if (achievement && achievement.side !== "Savage")
{ {
continue; continue;
@ -687,8 +686,8 @@ export class InraidController
// Remove any items that were returned by the item delivery, but also insured, from the player's insurance list // Remove any items that were returned by the item delivery, but also insured, from the player's insurance list
// This is to stop items being duplicated by being returned from both the item delivery, and insurance // This is to stop items being duplicated by being returned from both the item delivery, and insurance
const deliveredItemIds = items.map(x => x._id); const deliveredItemIds = items.map((x) => x._id);
pmcData.InsuredItems = pmcData.InsuredItems.filter(x => !deliveredItemIds.includes(x.itemId)); pmcData.InsuredItems = pmcData.InsuredItems.filter((x) => !deliveredItemIds.includes(x.itemId));
// Send the items to the player // Send the items to the player
this.mailSendService.sendLocalisedNpcMessageToPlayer( this.mailSendService.sendLocalisedNpcMessageToPlayer(

View File

@ -112,7 +112,7 @@ export class InsuranceController
this.logger.debug(`Found ${profileInsuranceDetails.length} insurance packages in profile ${sessionID}`); this.logger.debug(`Found ${profileInsuranceDetails.length} insurance packages in profile ${sessionID}`);
} }
return profileInsuranceDetails.filter(insured => insuranceTime >= insured.scheduledTime); return profileInsuranceDetails.filter((insured) => insuranceTime >= insured.scheduledTime);
} }
/** /**
@ -125,9 +125,9 @@ export class InsuranceController
protected processInsuredItems(insuranceDetails: Insurance[], sessionID: string): void protected processInsuredItems(insuranceDetails: Insurance[], sessionID: string): void
{ {
this.logger.debug( this.logger.debug(
`Processing ${insuranceDetails.length} insurance packages, which includes a total of ${ `Processing ${insuranceDetails.length} insurance packages, which includes a total of ${this.countAllInsuranceItems(
this.countAllInsuranceItems(insuranceDetails) insuranceDetails,
} items, in profile ${sessionID}`, )} items, in profile ${sessionID}`,
); );
// Fetch the root Item parentId property value that should be used for insurance packages. // Fetch the root Item parentId property value that should be used for insurance packages.
@ -160,7 +160,7 @@ export class InsuranceController
*/ */
protected countAllInsuranceItems(insurance: Insurance[]): number protected countAllInsuranceItems(insurance: Insurance[]): number
{ {
return this.mathUtil.arraySum(insurance.map(ins => ins.items.length)); return this.mathUtil.arraySum(insurance.map((ins) => ins.items.length));
} }
/** /**
@ -173,11 +173,12 @@ export class InsuranceController
protected removeInsurancePackageFromProfile(sessionID: string, insPackage: Insurance): void protected removeInsurancePackageFromProfile(sessionID: string, insPackage: Insurance): void
{ {
const profile = this.saveServer.getProfile(sessionID); const profile = this.saveServer.getProfile(sessionID);
profile.insurance = profile.insurance.filter(insurance => profile.insurance = profile.insurance.filter(
insurance.traderId !== insPackage.traderId (insurance) =>
|| insurance.systemData.date !== insPackage.systemData.date insurance.traderId !== insPackage.traderId
|| insurance.systemData.time !== insPackage.systemData.time || insurance.systemData.date !== insPackage.systemData.date
|| insurance.systemData.location !== insPackage.systemData.location, || insurance.systemData.time !== insPackage.systemData.time
|| insurance.systemData.location !== insPackage.systemData.location,
); );
this.logger.debug(`Removed processed insurance package. Remaining packages: ${profile.insurance.length}`); this.logger.debug(`Removed processed insurance package. Remaining packages: ${profile.insurance.length}`);
@ -200,8 +201,8 @@ export class InsuranceController
let parentAttachmentsMap = this.populateParentAttachmentsMap(rootItemParentID, insured, itemsMap); let parentAttachmentsMap = this.populateParentAttachmentsMap(rootItemParentID, insured, itemsMap);
// Check to see if any regular items are present. // Check to see if any regular items are present.
const hasRegularItems = Array.from(itemsMap.values()).some(item => const hasRegularItems = Array.from(itemsMap.values()).some(
!this.itemHelper.isAttachmentAttached(item), (item) => !this.itemHelper.isAttachmentAttached(item),
); );
// Process all items that are not attached, attachments; those are handled separately, by value. // Process all items that are not attached, attachments; those are handled separately, by value.
@ -249,7 +250,7 @@ export class InsuranceController
for (const insuredItem of insured.items) for (const insuredItem of insured.items)
{ {
// Use the parent ID from the item to get the parent item. // Use the parent ID from the item to get the parent item.
const parentItem = insured.items.find(item => item._id === insuredItem.parentId); const parentItem = insured.items.find((item) => item._id === insuredItem.parentId);
// The parent (not the hideout) could not be found. Skip and warn. // The parent (not the hideout) could not be found. Skip and warn.
if (!parentItem && insuredItem.parentId !== rootItemParentID) if (!parentItem && insuredItem.parentId !== rootItemParentID)
@ -489,7 +490,7 @@ export class InsuranceController
{ {
this.logger.debug( this.logger.debug(
`Attachment ${index} Id: ${attachmentId} Tpl: ${ `Attachment ${index} Id: ${attachmentId} Tpl: ${
attachments.find(x => x._id === attachmentId)?._tpl attachments.find((x) => x._id === attachmentId)?._tpl
} - Price: ${attachmentPrices[attachmentId]}`, } - Price: ${attachmentPrices[attachmentId]}`,
); );
index++; index++;
@ -556,7 +557,7 @@ export class InsuranceController
*/ */
protected removeItemsFromInsurance(insured: Insurance, toDelete: Set<string>): void protected removeItemsFromInsurance(insured: Insurance, toDelete: Set<string>): void
{ {
insured.items = insured.items.filter(item => !toDelete.has(item._id)); insured.items = insured.items.filter((item) => !toDelete.has(item._id));
} }
/** /**

View File

@ -106,7 +106,7 @@ export class InventoryController
} }
// Check for item in inventory before allowing internal transfer // Check for item in inventory before allowing internal transfer
const originalItemLocation = ownerInventoryItems.from.find(item => item._id === moveRequest.item); const originalItemLocation = ownerInventoryItems.from.find((item) => item._id === moveRequest.item);
if (!originalItemLocation) if (!originalItemLocation)
{ {
// Internal item move but item never existed, possible dupe glitch // Internal item move but item never existed, possible dupe glitch
@ -168,9 +168,10 @@ export class InventoryController
return; return;
} }
const profileToRemoveItemFrom = (!request.fromOwner || request.fromOwner.id === pmcData._id) const profileToRemoveItemFrom
? pmcData = !request.fromOwner || request.fromOwner.id === pmcData._id
: this.profileHelper.getFullProfile(sessionID).characters.scav; ? pmcData
: this.profileHelper.getFullProfile(sessionID).characters.scav;
this.inventoryHelper.removeItem(profileToRemoveItemFrom, request.item, sessionID, output); this.inventoryHelper.removeItem(profileToRemoveItemFrom, request.item, sessionID, output);
} }
@ -197,12 +198,12 @@ export class InventoryController
// Handle cartridge edge-case // Handle cartridge edge-case
if (!request.container.location && request.container.container === "cartridges") if (!request.container.location && request.container.container === "cartridges")
{ {
const matchingItems = inventoryItems.to.filter(x => x.parentId === request.container.id); const matchingItems = inventoryItems.to.filter((x) => x.parentId === request.container.id);
request.container.location = matchingItems.length; // Wrong location for first cartridge request.container.location = matchingItems.length; // Wrong location for first cartridge
} }
// The item being merged has three possible sources: pmc, scav or mail, getOwnerInventoryItems() handles getting correct one // The item being merged has three possible sources: pmc, scav or mail, getOwnerInventoryItems() handles getting correct one
const itemToSplit = inventoryItems.from.find(x => x._id === request.splitItem); const itemToSplit = inventoryItems.from.find((x) => x._id === request.splitItem);
if (!itemToSplit) if (!itemToSplit)
{ {
const errorMessage = `Unable to split stack as source item: ${request.splitItem} cannot be found`; const errorMessage = `Unable to split stack as source item: ${request.splitItem} cannot be found`;
@ -258,7 +259,7 @@ export class InventoryController
const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID); const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID);
// Get source item (can be from player or trader or mail) // Get source item (can be from player or trader or mail)
const sourceItem = inventoryItems.from.find(x => x._id === body.item); const sourceItem = inventoryItems.from.find((x) => x._id === body.item);
if (!sourceItem) if (!sourceItem)
{ {
const errorMessage = `Unable to merge stacks as source item: ${body.with} cannot be found`; const errorMessage = `Unable to merge stacks as source item: ${body.with} cannot be found`;
@ -270,7 +271,7 @@ export class InventoryController
} }
// Get item being merged into // Get item being merged into
const destinationItem = inventoryItems.to.find(x => x._id === body.with); const destinationItem = inventoryItems.to.find((x) => x._id === body.with);
if (!destinationItem) if (!destinationItem)
{ {
const errorMessage = `Unable to merge stacks as destination item: ${body.with} cannot be found`; const errorMessage = `Unable to merge stacks as destination item: ${body.with} cannot be found`;
@ -306,7 +307,7 @@ export class InventoryController
destinationItem.upd.StackObjectsCount += sourceItem.upd.StackObjectsCount; // Add source stackcount to destination destinationItem.upd.StackObjectsCount += sourceItem.upd.StackObjectsCount; // Add source stackcount to destination
output.profileChanges[sessionID].items.del.push({ _id: sourceItem._id }); // Inform client source item being deleted output.profileChanges[sessionID].items.del.push({ _id: sourceItem._id }); // Inform client source item being deleted
const indexOfItemToRemove = inventoryItems.from.findIndex(x => x._id === sourceItem._id); const indexOfItemToRemove = inventoryItems.from.findIndex((x) => x._id === sourceItem._id);
if (indexOfItemToRemove === -1) if (indexOfItemToRemove === -1)
{ {
const errorMessage = `Unable to find item: ${sourceItem._id} to remove from sender inventory`; const errorMessage = `Unable to find item: ${sourceItem._id} to remove from sender inventory`;
@ -339,8 +340,8 @@ export class InventoryController
): IItemEventRouterResponse ): IItemEventRouterResponse
{ {
const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID); const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID);
const sourceItem = inventoryItems.from.find(item => item._id === body.item); const sourceItem = inventoryItems.from.find((item) => item._id === body.item);
const destinationItem = inventoryItems.to.find(item => item._id === body.with); const destinationItem = inventoryItems.to.find((item) => item._id === body.with);
if (sourceItem === null) if (sourceItem === null)
{ {
@ -394,15 +395,19 @@ export class InventoryController
* its used for "reload" if you have weapon in hands and magazine is somewhere else in rig or backpack in equipment * its used for "reload" if you have weapon in hands and magazine is somewhere else in rig or backpack in equipment
* Also used to swap items using quick selection on character screen * Also used to swap items using quick selection on character screen
*/ */
public swapItem(pmcData: IPmcData, request: IInventorySwapRequestData, sessionID: string): IItemEventRouterResponse public swapItem(
pmcData: IPmcData,
request: IInventorySwapRequestData,
sessionID: string,
): IItemEventRouterResponse
{ {
const itemOne = pmcData.Inventory.items.find(x => x._id === request.item); const itemOne = pmcData.Inventory.items.find((x) => x._id === request.item);
if (!itemOne) if (!itemOne)
{ {
this.logger.error(`Unable to find item: ${request.item} to swap positions with: ${request.item2}`); this.logger.error(`Unable to find item: ${request.item} to swap positions with: ${request.item2}`);
} }
const itemTwo = pmcData.Inventory.items.find(x => x._id === request.item2); const itemTwo = pmcData.Inventory.items.find((x) => x._id === request.item2);
if (!itemTwo) if (!itemTwo)
{ {
this.logger.error(`Unable to find item: ${request.item2} to swap positions with: ${request.item}`); this.logger.error(`Unable to find item: ${request.item2} to swap positions with: ${request.item}`);
@ -442,7 +447,11 @@ export class InventoryController
/** /**
* Handles folding of Weapons * Handles folding of Weapons
*/ */
public foldItem(pmcData: IPmcData, request: IInventoryFoldRequestData, sessionID: string): IItemEventRouterResponse public foldItem(
pmcData: IPmcData,
request: IInventoryFoldRequestData,
sessionID: string,
): IItemEventRouterResponse
{ {
// May need to reassign to scav profile // May need to reassign to scav profile
let playerData = pmcData; let playerData = pmcData;
@ -453,7 +462,7 @@ export class InventoryController
playerData = this.profileHelper.getScavProfile(sessionID); playerData = this.profileHelper.getScavProfile(sessionID);
} }
const itemToFold = playerData.Inventory.items.find(item => item?._id === request.item); const itemToFold = playerData.Inventory.items.find((item) => item?._id === request.item);
if (!itemToFold) if (!itemToFold)
{ {
// Item not found // Item not found
@ -476,7 +485,11 @@ export class InventoryController
* @param sessionID Session id * @param sessionID Session id
* @returns IItemEventRouterResponse * @returns IItemEventRouterResponse
*/ */
public toggleItem(pmcData: IPmcData, body: IInventoryToggleRequestData, sessionID: string): IItemEventRouterResponse public toggleItem(
pmcData: IPmcData,
body: IInventoryToggleRequestData,
sessionID: string,
): IItemEventRouterResponse
{ {
// May need to reassign to scav profile // May need to reassign to scav profile
let playerData = pmcData; let playerData = pmcData;
@ -487,7 +500,7 @@ export class InventoryController
playerData = this.profileHelper.getScavProfile(sessionID); playerData = this.profileHelper.getScavProfile(sessionID);
} }
const itemToToggle = playerData.Inventory.items.find(x => x._id === body.item); const itemToToggle = playerData.Inventory.items.find((x) => x._id === body.item);
if (itemToToggle) if (itemToToggle)
{ {
this.itemHelper.addUpdObjectToItem( this.itemHelper.addUpdObjectToItem(
@ -688,16 +701,16 @@ export class InventoryController
if (request.fromOwner.id === Traders.FENCE) if (request.fromOwner.id === Traders.FENCE)
{ {
// Get tpl from fence assorts // Get tpl from fence assorts
return this.fenceService.getRawFenceAssorts().items.find(x => x._id === request.item)._tpl; return this.fenceService.getRawFenceAssorts().items.find((x) => x._id === request.item)._tpl;
} }
if (request.fromOwner.type === "Trader") if (request.fromOwner.type === "Trader")
{ {
// Not fence // Not fence
// get tpl from trader assort // get tpl from trader assort
return this.databaseServer.getTables().traders[request.fromOwner.id].assort.items.find(item => return this.databaseServer
item._id === request.item, .getTables()
)._tpl; .traders[request.fromOwner.id].assort.items.find((item) => item._id === request.item)._tpl;
} }
if (request.fromOwner.type === "RagFair") if (request.fromOwner.type === "RagFair")
@ -717,7 +730,7 @@ export class InventoryController
} }
// Try find examine item inside offer items array // Try find examine item inside offer items array
const matchingItem = offer.items.find(offerItem => offerItem._id === request.item); const matchingItem = offer.items.find((offerItem) => offerItem._id === request.item);
if (matchingItem) if (matchingItem)
{ {
return matchingItem._tpl; return matchingItem._tpl;
@ -753,7 +766,7 @@ export class InventoryController
{ {
for (const change of request.changedItems) for (const change of request.changedItems)
{ {
const inventoryItem = pmcData.Inventory.items.find(x => x._id === change._id); const inventoryItem = pmcData.Inventory.items.find((x) => x._id === change._id);
if (!inventoryItem) if (!inventoryItem)
{ {
this.logger.error( this.logger.error(
@ -792,7 +805,7 @@ export class InventoryController
): void ): void
{ {
// Get map from inventory // Get map from inventory
const mapItem = pmcData.Inventory.items.find(i => i._id === request.item); const mapItem = pmcData.Inventory.items.find((i) => i._id === request.item);
// add marker // add marker
mapItem.upd.Map = mapItem.upd.Map || { Markers: [] }; mapItem.upd.Map = mapItem.upd.Map || { Markers: [] };
@ -818,7 +831,7 @@ export class InventoryController
): void ): void
{ {
// Get map from inventory // Get map from inventory
const mapItem = pmcData.Inventory.items.find(i => i._id === request.item); const mapItem = pmcData.Inventory.items.find((i) => i._id === request.item);
// remove marker // remove marker
const markers = mapItem.upd.Map.Markers.filter((marker) => const markers = mapItem.upd.Map.Markers.filter((marker) =>
@ -846,10 +859,10 @@ export class InventoryController
): void ): void
{ {
// Get map from inventory // Get map from inventory
const mapItem = pmcData.Inventory.items.find(i => i._id === request.item); const mapItem = pmcData.Inventory.items.find((i) => i._id === request.item);
// edit marker // edit marker
const indexOfExistingNote = mapItem.upd.Map.Markers.findIndex(m => m.X === request.X && m.Y === request.Y); const indexOfExistingNote = mapItem.upd.Map.Markers.findIndex((m) => m.X === request.X && m.Y === request.Y);
request.mapMarker.Note = this.sanitiseMapMarkerText(request.mapMarker.Note); request.mapMarker.Note = this.sanitiseMapMarkerText(request.mapMarker.Note);
mapItem.upd.Map.Markers[indexOfExistingNote] = request.mapMarker; mapItem.upd.Map.Markers[indexOfExistingNote] = request.mapMarker;
@ -883,7 +896,7 @@ export class InventoryController
): void ): void
{ {
/** Container player opened in their inventory */ /** Container player opened in their inventory */
const openedItem = pmcData.Inventory.items.find(item => item._id === body.item); const openedItem = pmcData.Inventory.items.find((item) => item._id === body.item);
const containerDetailsDb = this.itemHelper.getItem(openedItem._tpl); const containerDetailsDb = this.itemHelper.getItem(openedItem._tpl);
const isSealedWeaponBox = containerDetailsDb[1]._name.includes("event_container_airdrop"); const isSealedWeaponBox = containerDetailsDb[1]._name.includes("event_container_airdrop");
@ -934,8 +947,8 @@ export class InventoryController
// Hard coded to `SYSTEM` for now // Hard coded to `SYSTEM` for now
// TODO: make this dynamic // TODO: make this dynamic
const dialog = fullProfile.dialogues["59e7125688a45068a6249071"]; const dialog = fullProfile.dialogues["59e7125688a45068a6249071"];
const mail = dialog.messages.find(x => x._id === event.MessageId); const mail = dialog.messages.find((x) => x._id === event.MessageId);
const mailEvent = mail.profileChangeEvents.find(x => x._id === event.EventId); const mailEvent = mail.profileChangeEvents.find((x) => x._id === event.EventId);
switch (mailEvent.Type) switch (mailEvent.Type)
{ {
@ -954,15 +967,18 @@ export class InventoryController
break; break;
case "SkillPoints": case "SkillPoints":
{ {
const profileSkill = pmcData.Skills.Common.find(x => x.Id === mailEvent.entity); const profileSkill = pmcData.Skills.Common.find((x) => x.Id === mailEvent.entity);
profileSkill.Progress = mailEvent.value; profileSkill.Progress = mailEvent.value;
this.logger.success(`Set profile skill: ${mailEvent.entity} to: ${mailEvent.value}`); this.logger.success(`Set profile skill: ${mailEvent.entity} to: ${mailEvent.value}`);
break; break;
} }
case "ExamineAllItems": case "ExamineAllItems":
{ {
const itemsToInspect = this.itemHelper.getItems().filter(x => x._type !== "Node"); const itemsToInspect = this.itemHelper.getItems().filter((x) => x._type !== "Node");
this.flagItemsAsInspectedAndRewardXp(itemsToInspect.map(x => x._id), fullProfile); this.flagItemsAsInspectedAndRewardXp(
itemsToInspect.map((x) => x._id),
fullProfile,
);
this.logger.success(`Flagged ${itemsToInspect.length} items as examined`); this.logger.success(`Flagged ${itemsToInspect.length} items as examined`);
break; break;
} }
@ -987,7 +1003,7 @@ export class InventoryController
for (const itemId of request.items) for (const itemId of request.items)
{ {
// If id already exists in array, we're removing it // If id already exists in array, we're removing it
const indexOfItemAlreadyFavorited = pmcData.Inventory.favoriteItems.findIndex(x => x === itemId); const indexOfItemAlreadyFavorited = pmcData.Inventory.favoriteItems.findIndex((x) => x === itemId);
if (indexOfItemAlreadyFavorited > -1) if (indexOfItemAlreadyFavorited > -1)
{ {
pmcData.Inventory.favoriteItems.splice(indexOfItemAlreadyFavorited, 1); pmcData.Inventory.favoriteItems.splice(indexOfItemAlreadyFavorited, 1);

View File

@ -92,9 +92,9 @@ export class LocationController
// Check for a loot multipler adjustment in app context and apply if one is found // Check for a loot multipler adjustment in app context and apply if one is found
let locationConfigCopy: ILocationConfig; let locationConfigCopy: ILocationConfig;
const raidAdjustments = this.applicationContext.getLatestValue(ContextVariableType.RAID_ADJUSTMENTS)?.getValue< const raidAdjustments = this.applicationContext
IRaidChanges .getLatestValue(ContextVariableType.RAID_ADJUSTMENTS)
>(); ?.getValue<IRaidChanges>();
if (raidAdjustments) if (raidAdjustments)
{ {
locationConfigCopy = this.cloner.clone(this.locationConfig); // Clone values so they can be used to reset originals later locationConfigCopy = this.cloner.clone(this.locationConfig); // Clone values so they can be used to reset originals later

View File

@ -24,9 +24,7 @@ export class PresetController
if (id !== preset._id) if (id !== preset._id)
{ {
this.logger.error( this.logger.error(
`Preset for template tpl: '${ `Preset for template tpl: '${preset._items[0]._tpl} ${preset._name}' has invalid key: (${id} != ${preset._id}). Skipping`,
preset._items[0]._tpl
} ${preset._name}' has invalid key: (${id} != ${preset._id}). Skipping`,
); );
continue; continue;

View File

@ -129,10 +129,8 @@ export class ProfileController
public createProfile(info: IProfileCreateRequestData, sessionID: string): string public createProfile(info: IProfileCreateRequestData, sessionID: string): string
{ {
const account = this.saveServer.getProfile(sessionID).info; const account = this.saveServer.getProfile(sessionID).info;
const profile: ITemplateSide = this.databaseServer const profile: ITemplateSide
.getTables() = this.databaseServer.getTables().templates.profiles[account.edition][info.side.toLowerCase()];
.templates
.profiles[account.edition][info.side.toLowerCase()];
const pmcData = profile.character; const pmcData = profile.character;
// Delete existing profile // Delete existing profile
@ -152,7 +150,7 @@ export class ProfileController
pmcData.Customization.Head = info.headId; pmcData.Customization.Head = info.headId;
pmcData.Health.UpdateTime = this.timeUtil.getTimestamp(); pmcData.Health.UpdateTime = this.timeUtil.getTimestamp();
pmcData.Quests = []; pmcData.Quests = [];
pmcData.Hideout.Seed = this.timeUtil.getTimestamp() + (8 * 60 * 60 * 24 * 365); // 8 years in future why? who knows, we saw it in live pmcData.Hideout.Seed = this.timeUtil.getTimestamp() + 8 * 60 * 60 * 24 * 365; // 8 years in future why? who knows, we saw it in live
pmcData.RepeatableQuests = []; pmcData.RepeatableQuests = [];
pmcData.CarExtractCounts = {}; pmcData.CarExtractCounts = {};
pmcData.CoopExtractCounts = {}; pmcData.CoopExtractCounts = {};
@ -398,16 +396,18 @@ export class ProfileController
const profile = this.saveServer.getProfile(sessionID); const profile = this.saveServer.getProfile(sessionID);
// return some of the current player info for now // return some of the current player info for now
return [{ return [
_id: profile.characters.pmc._id, {
aid: profile.characters.pmc.aid, _id: profile.characters.pmc._id,
Info: { aid: profile.characters.pmc.aid,
Nickname: info.nickname, Info: {
Side: "Bear", Nickname: info.nickname,
Level: 1, Side: "Bear",
MemberCategory: profile.characters.pmc.Info.MemberCategory, Level: 1,
MemberCategory: profile.characters.pmc.Info.MemberCategory,
},
}, },
}]; ];
} }
/** /**
@ -418,14 +418,17 @@ export class ProfileController
const account = this.saveServer.getProfile(sessionId).info; const account = this.saveServer.getProfile(sessionId).info;
const response: GetProfileStatusResponseData = { const response: GetProfileStatusResponseData = {
maxPveCountExceeded: false, maxPveCountExceeded: false,
profiles: [{ profileid: account.scavId, profileToken: null, status: "Free", sid: "", ip: "", port: 0 }, { profiles: [
profileid: account.id, { profileid: account.scavId, profileToken: null, status: "Free", sid: "", ip: "", port: 0 },
profileToken: null, {
status: "Free", profileid: account.id,
sid: "", profileToken: null,
ip: "", status: "Free",
port: 0, sid: "",
}], ip: "",
port: 0,
},
],
}; };
return response; return response;
@ -459,7 +462,7 @@ export class ProfileController
skills: playerPmc.Skills, skills: playerPmc.Skills,
equipment: { equipment: {
// Default inventory tpl // Default inventory tpl
Id: playerPmc.Inventory.items.find(x => x._tpl === "55d7217a4bdc2d86028b456d")._id, Id: playerPmc.Inventory.items.find((x) => x._tpl === "55d7217a4bdc2d86028b456d")._id,
Items: playerPmc.Inventory.items, Items: playerPmc.Inventory.items,
}, },
achievements: playerPmc.Achievements, achievements: playerPmc.Achievements,

View File

@ -78,7 +78,7 @@ export class QuestController
for (const quest of allQuests) for (const quest of allQuests)
{ {
// Player already accepted the quest, show it regardless of status // Player already accepted the quest, show it regardless of status
const questInProfile = profile.Quests.find(x => x.qid === quest._id); const questInProfile = profile.Quests.find((x) => x.qid === quest._id);
if (questInProfile) if (questInProfile)
{ {
quest.sptStatus = questInProfile.status; quest.sptStatus = questInProfile.status;
@ -123,7 +123,11 @@ export class QuestController
); );
// Quest has no conditions, standing or loyalty conditions, add to visible quest list // Quest has no conditions, standing or loyalty conditions, add to visible quest list
if (questRequirements.length === 0 && loyaltyRequirements.length === 0 && standingRequirements.length === 0) if (
questRequirements.length === 0
&& loyaltyRequirements.length === 0
&& standingRequirements.length === 0
)
{ {
quest.sptStatus = QuestStatus.AvailableForStart; quest.sptStatus = QuestStatus.AvailableForStart;
questsToShowPlayer.push(quest); questsToShowPlayer.push(quest);
@ -136,7 +140,7 @@ export class QuestController
for (const conditionToFulfil of questRequirements) for (const conditionToFulfil of questRequirements)
{ {
// If the previous quest isn't in the user profile, it hasn't been completed or started // If the previous quest isn't in the user profile, it hasn't been completed or started
const prerequisiteQuest = profile.Quests.find(profileQuest => const prerequisiteQuest = profile.Quests.find((profileQuest) =>
conditionToFulfil.target.includes(profileQuest.qid), conditionToFulfil.target.includes(profileQuest.qid),
); );
if (!prerequisiteQuest) if (!prerequisiteQuest)
@ -147,7 +151,7 @@ export class QuestController
// Prereq does not have its status requirement fulfilled // Prereq does not have its status requirement fulfilled
// Some bsg status ids are strings, MUST convert to number before doing includes check // Some bsg status ids are strings, MUST convert to number before doing includes check
if (!conditionToFulfil.status.map(status => Number(status)).includes(prerequisiteQuest.status)) if (!conditionToFulfil.status.map((status) => Number(status)).includes(prerequisiteQuest.status))
{ {
haveCompletedPreviousQuest = false; haveCompletedPreviousQuest = false;
break; break;
@ -291,7 +295,7 @@ export class QuestController
// Does quest exist in profile // Does quest exist in profile
// Restarting a failed quest can mean quest exists in profile // Restarting a failed quest can mean quest exists in profile
const existingQuestStatus = pmcData.Quests.find(x => x.qid === acceptedQuest.qid); const existingQuestStatus = pmcData.Quests.find((x) => x.qid === acceptedQuest.qid);
if (existingQuestStatus) if (existingQuestStatus)
{ {
// Update existing // Update existing
@ -398,16 +402,17 @@ export class QuestController
fullProfile.characters.scav.Quests.push(newRepeatableQuest); fullProfile.characters.scav.Quests.push(newRepeatableQuest);
} }
const repeatableSettings = pmcData.RepeatableQuests.find(x => const repeatableSettings = pmcData.RepeatableQuests.find(
x.name === repeatableQuestProfile.sptRepatableGroupName, (x) => x.name === repeatableQuestProfile.sptRepatableGroupName,
); );
const change = {}; const change = {};
change[repeatableQuestProfile._id] = repeatableSettings.changeRequirement[repeatableQuestProfile._id]; change[repeatableQuestProfile._id] = repeatableSettings.changeRequirement[repeatableQuestProfile._id];
const responseData: IPmcDataRepeatableQuest = { const responseData: IPmcDataRepeatableQuest = {
id: repeatableSettings.id ?? this.questConfig.repeatableQuests.find(x => id:
x.name === repeatableQuestProfile.sptRepatableGroupName, repeatableSettings.id
).id, ?? this.questConfig.repeatableQuests.find((x) => x.name === repeatableQuestProfile.sptRepatableGroupName)
.id,
name: repeatableSettings.name, name: repeatableSettings.name,
endTime: repeatableSettings.endTime, endTime: repeatableSettings.endTime,
changeRequirement: change, changeRequirement: change,
@ -430,11 +435,14 @@ export class QuestController
* @param acceptedQuest Quest to search for * @param acceptedQuest Quest to search for
* @returns IRepeatableQuest * @returns IRepeatableQuest
*/ */
protected getRepeatableQuestFromProfile(pmcData: IPmcData, acceptedQuest: IAcceptQuestRequestData): IRepeatableQuest protected getRepeatableQuestFromProfile(
pmcData: IPmcData,
acceptedQuest: IAcceptQuestRequestData,
): IRepeatableQuest
{ {
for (const repeatableQuest of pmcData.RepeatableQuests) for (const repeatableQuest of pmcData.RepeatableQuests)
{ {
const matchingQuest = repeatableQuest.activeQuests.find(x => x._id === acceptedQuest.qid); const matchingQuest = repeatableQuest.activeQuests.find((x) => x._id === acceptedQuest.qid);
if (matchingQuest) if (matchingQuest)
{ {
this.logger.debug(`Accepted repeatable quest ${acceptedQuest.qid} from ${repeatableQuest.name}`); this.logger.debug(`Accepted repeatable quest ${acceptedQuest.qid} from ${repeatableQuest.name}`);
@ -503,8 +511,8 @@ export class QuestController
// Check if it's a repeatable quest. If so, remove from Quests // Check if it's a repeatable quest. If so, remove from Quests
for (const currentRepeatable of pmcData.RepeatableQuests) for (const currentRepeatable of pmcData.RepeatableQuests)
{ {
const repeatableQuest = currentRepeatable.activeQuests.find(activeRepeatable => const repeatableQuest = currentRepeatable.activeQuests.find(
activeRepeatable._id === completedQuestId, (activeRepeatable) => activeRepeatable._id === completedQuestId,
); );
if (repeatableQuest) if (repeatableQuest)
{ {
@ -547,15 +555,15 @@ export class QuestController
// Quest already failed in profile, skip // Quest already failed in profile, skip
if ( if (
pmcProfile.Quests.some(profileQuest => pmcProfile.Quests.some(
profileQuest.qid === quest._id && profileQuest.status === QuestStatus.Fail, (profileQuest) => profileQuest.qid === quest._id && profileQuest.status === QuestStatus.Fail,
) )
) )
{ {
return false; return false;
} }
return quest.conditions.Fail.some(condition => condition.target?.includes(completedQuestId)); return quest.conditions.Fail.some((condition) => condition.target?.includes(completedQuestId));
}); });
} }
@ -567,7 +575,7 @@ export class QuestController
protected removeQuestFromScavProfile(sessionId: string, questIdToRemove: string): void protected removeQuestFromScavProfile(sessionId: string, questIdToRemove: string): void
{ {
const fullProfile = this.profileHelper.getFullProfile(sessionId); const fullProfile = this.profileHelper.getFullProfile(sessionId);
const repeatableInScavProfile = fullProfile.characters.scav.Quests?.find(x => x.qid === questIdToRemove); const repeatableInScavProfile = fullProfile.characters.scav.Quests?.find((x) => x.qid === questIdToRemove);
if (!repeatableInScavProfile) if (!repeatableInScavProfile)
{ {
this.logger.warning( this.logger.warning(
@ -599,7 +607,7 @@ export class QuestController
for (const quest of postQuestStatuses) for (const quest of postQuestStatuses)
{ {
// Add quest if status differs or quest not found // Add quest if status differs or quest not found
const preQuest = preQuestStatusus.find(x => x.qid === quest.qid); const preQuest = preQuestStatusus.find((x) => x.qid === quest.qid);
if (!preQuest || preQuest.status !== quest.status) if (!preQuest || preQuest.status !== quest.status)
{ {
result.push(quest); result.push(quest);
@ -652,8 +660,8 @@ export class QuestController
for (const quest of quests) for (const quest of quests)
{ {
// If quest has prereq of completed quest + availableAfter value > 0 (quest has wait time) // If quest has prereq of completed quest + availableAfter value > 0 (quest has wait time)
const nextQuestWaitCondition = quest.conditions.AvailableForStart.find(x => const nextQuestWaitCondition = quest.conditions.AvailableForStart.find(
x.target?.includes(completedQuestId) && x.availableAfter > 0, (x) => x.target?.includes(completedQuestId) && x.availableAfter > 0,
); );
if (nextQuestWaitCondition) if (nextQuestWaitCondition)
{ {
@ -661,7 +669,7 @@ export class QuestController
const availableAfterTimestamp = this.timeUtil.getTimestamp() + nextQuestWaitCondition.availableAfter; const availableAfterTimestamp = this.timeUtil.getTimestamp() + nextQuestWaitCondition.availableAfter;
// Update quest in profile with status of AvailableAfter // Update quest in profile with status of AvailableAfter
const existingQuestInProfile = pmcData.Quests.find(x => x.qid === quest._id); const existingQuestInProfile = pmcData.Quests.find((x) => x.qid === quest._id);
if (existingQuestInProfile) if (existingQuestInProfile)
{ {
existingQuestInProfile.availableAfter = availableAfterTimestamp; existingQuestInProfile.availableAfter = availableAfterTimestamp;
@ -704,12 +712,12 @@ export class QuestController
for (const questToFail of questsToFail) for (const questToFail of questsToFail)
{ {
// Skip failing a quest that has a fail status of something other than success // Skip failing a quest that has a fail status of something other than success
if (questToFail.conditions.Fail?.some(x => x.status?.some(status => status !== QuestStatus.Success))) if (questToFail.conditions.Fail?.some((x) => x.status?.some((status) => status !== QuestStatus.Success)))
{ {
continue; continue;
} }
const isActiveQuestInPlayerProfile = pmcData.Quests.find(quest => quest.qid === questToFail._id); const isActiveQuestInPlayerProfile = pmcData.Quests.find((quest) => quest.qid === questToFail._id);
if (isActiveQuestInPlayerProfile) if (isActiveQuestInPlayerProfile)
{ {
if (isActiveQuestInPlayerProfile.status !== QuestStatus.Fail) if (isActiveQuestInPlayerProfile.status !== QuestStatus.Fail)
@ -771,9 +779,10 @@ export class QuestController
isItemHandoverQuest = condition.conditionType === handoverQuestTypes[0]; isItemHandoverQuest = condition.conditionType === handoverQuestTypes[0];
handoverRequirements = condition; handoverRequirements = condition;
const profileCounter = handoverQuestRequest.conditionId in pmcData.TaskConditionCounters const profileCounter
? pmcData.TaskConditionCounters[handoverQuestRequest.conditionId].value = handoverQuestRequest.conditionId in pmcData.TaskConditionCounters
: 0; ? pmcData.TaskConditionCounters[handoverQuestRequest.conditionId].value
: 0;
handedInCount -= profileCounter; handedInCount -= profileCounter;
if (handedInCount <= 0) if (handedInCount <= 0)
@ -805,7 +814,7 @@ export class QuestController
let totalItemCountToRemove = 0; let totalItemCountToRemove = 0;
for (const itemHandover of handoverQuestRequest.items) for (const itemHandover of handoverQuestRequest.items)
{ {
const matchingItemInProfile = pmcData.Inventory.items.find(item => item._id === itemHandover.id); const matchingItemInProfile = pmcData.Inventory.items.find((item) => item._id === itemHandover.id);
if (!(matchingItemInProfile && handoverRequirements.target.includes(matchingItemInProfile._tpl))) if (!(matchingItemInProfile && handoverRequirements.target.includes(matchingItemInProfile._tpl)))
{ {
// Item handed in by player doesnt match what was requested // Item handed in by player doesnt match what was requested

View File

@ -27,7 +27,6 @@ import { ISearchRequestData } from "@spt-aki/models/eft/ragfair/ISearchRequestDa
import { IProcessBuyTradeRequestData } from "@spt-aki/models/eft/trade/IProcessBuyTradeRequestData"; import { IProcessBuyTradeRequestData } from "@spt-aki/models/eft/trade/IProcessBuyTradeRequestData";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
import { MemberCategory } from "@spt-aki/models/enums/MemberCategory"; import { MemberCategory } from "@spt-aki/models/enums/MemberCategory";
import { RagfairSort } from "@spt-aki/models/enums/RagfairSort";
import { IRagfairConfig } from "@spt-aki/models/spt/config/IRagfairConfig"; import { IRagfairConfig } from "@spt-aki/models/spt/config/IRagfairConfig";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder"; import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
@ -159,7 +158,7 @@ export class RagfairController
public getOfferById(sessionId: string, request: IGetRagfairOfferByIdRequest): IRagfairOffer public getOfferById(sessionId: string, request: IGetRagfairOfferByIdRequest): IRagfairOffer
{ {
const offers = this.ragfairOfferService.getOffers(); const offers = this.ragfairOfferService.getOffers();
const offerToReturn = offers.find(x => x.intId === request.id); const offerToReturn = offers.find((x) => x.intId === request.id);
return offerToReturn; return offerToReturn;
} }
@ -207,12 +206,8 @@ export class RagfairController
): Record<string, number> ): Record<string, number>
{ {
// Linked/required search categories // Linked/required search categories
const playerHasFleaUnlocked = pmcProfile.Info.Level >= this.databaseServer const playerHasFleaUnlocked
.getTables() = pmcProfile.Info.Level >= this.databaseServer.getTables().globals.config.RagFair.minUserLevel;
.globals
.config
.RagFair
.minUserLevel;
let offerPool = []; let offerPool = [];
if (this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest)) if (this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest))
{ {
@ -263,7 +258,7 @@ export class RagfairController
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items; const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items;
const assortId = offer.items[0]._id; const assortId = offer.items[0]._id;
const assortData = traderAssorts.find(x => x._id === assortId); const assortData = traderAssorts.find((x) => x._id === assortId);
// Use value stored in profile, otherwise use value directly from in-memory trader assort data // Use value stored in profile, otherwise use value directly from in-memory trader assort data
offer.buyRestrictionCurrent = fullProfile.traderPurchases[offer.user.id][assortId] offer.buyRestrictionCurrent = fullProfile.traderPurchases[offer.user.id][assortId]
@ -282,7 +277,7 @@ export class RagfairController
const firstItem = offer.items[0]; const firstItem = offer.items[0];
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items; const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items;
const assortPurchased = traderAssorts.find(x => x._id === offer.items[0]._id); const assortPurchased = traderAssorts.find((x) => x._id === offer.items[0]._id);
if (!assortPurchased) if (!assortPurchased)
{ {
this.logger.warning( this.logger.warning(
@ -357,31 +352,34 @@ export class RagfairController
// Get the average offer price, excluding barter offers // Get the average offer price, excluding barter offers
let avgOfferCount = 0; let avgOfferCount = 0;
const avg = offers.reduce((sum, offer) => const avg
{ = offers.reduce((sum, offer) =>
// Exclude barter items, they tend to have outrageous equivalent prices
if (offer.requirements.some(req => !this.paymentHelper.isMoneyTpl(req._tpl)))
{ {
return sum; // Exclude barter items, they tend to have outrageous equivalent prices
} if (offer.requirements.some((req) => !this.paymentHelper.isMoneyTpl(req._tpl)))
{
return sum;
}
// Figure out how many items the requirementsCost is applying to, and what the per-item price is // Figure out how many items the requirementsCost is applying to, and what the per-item price is
const offerItemCount = Math.max(offer.sellInOnePiece ? offer.items[0].upd?.StackObjectsCount ?? 1 : 1); const offerItemCount = Math.max(
const perItemPrice = offer.requirementsCost / offerItemCount; offer.sellInOnePiece ? offer.items[0].upd?.StackObjectsCount ?? 1 : 1,
);
const perItemPrice = offer.requirementsCost / offerItemCount;
// Handle min/max calculations based on the per-item price // Handle min/max calculations based on the per-item price
if (perItemPrice < min) if (perItemPrice < min)
{ {
min = perItemPrice; min = perItemPrice;
} }
else if (perItemPrice > max) else if (perItemPrice > max)
{ {
max = perItemPrice; max = perItemPrice;
} }
avgOfferCount++; avgOfferCount++;
return sum + perItemPrice; return sum + perItemPrice;
}, 0) / Math.max(avgOfferCount, 1); }, 0) / Math.max(avgOfferCount, 1);
// If no items were actually counted, min will still be MAX_VALUE, so set it to 0 // If no items were actually counted, min will still be MAX_VALUE, so set it to 0
if (min === Number.MAX_VALUE) if (min === Number.MAX_VALUE)
@ -428,8 +426,8 @@ export class RagfairController
} }
// Get an array of items from player inventory to list on flea // Get an array of items from player inventory to list on flea
const { items: itemsInInventoryToList, errorMessage: itemsInInventoryError } = this const { items: itemsInInventoryToList, errorMessage: itemsInInventoryError }
.getItemsToListOnFleaFromInventory(pmcData, offerRequest.items); = this.getItemsToListOnFleaFromInventory(pmcData, offerRequest.items);
if (!itemsInInventoryToList || itemsInInventoryError) if (!itemsInInventoryToList || itemsInInventoryError)
{ {
this.httpResponse.appendErrorToOutput(output, itemsInInventoryError); this.httpResponse.appendErrorToOutput(output, itemsInInventoryError);
@ -605,8 +603,8 @@ export class RagfairController
} }
else else
{ {
requirementsPriceInRub += this.ragfairPriceService requirementsPriceInRub
.getDynamicPriceForItem(requestedItemTpl) * item.count; += this.ragfairPriceService.getDynamicPriceForItem(requestedItemTpl) * item.count;
} }
} }
@ -630,7 +628,7 @@ export class RagfairController
// Count how many items are being sold and multiply the requested amount accordingly // Count how many items are being sold and multiply the requested amount accordingly
for (const itemId of itemIdsFromFleaOfferRequest) for (const itemId of itemIdsFromFleaOfferRequest)
{ {
let item = pmcData.Inventory.items.find(i => i._id === itemId); let item = pmcData.Inventory.items.find((i) => i._id === itemId);
if (!item) if (!item)
{ {
errorMessage = this.localisationService.getText("ragfair-unable_to_find_item_in_inventory", { errorMessage = this.localisationService.getText("ragfair-unable_to_find_item_in_inventory", {
@ -666,7 +664,7 @@ export class RagfairController
const loyalLevel = 1; const loyalLevel = 1;
const formattedItems: Item[] = items.map((item) => const formattedItems: Item[] = items.map((item) =>
{ {
const isChild = items.find(it => it._id === item.parentId); const isChild = items.find((it) => it._id === item.parentId);
return { return {
_id: item._id, _id: item._id,
@ -727,7 +725,7 @@ export class RagfairController
pmcData.RagfairInfo.offers = []; pmcData.RagfairInfo.offers = [];
} }
const playerOfferIndex = playerProfileOffers.findIndex(offer => offer._id === removeRequest.offerId); const playerOfferIndex = playerProfileOffers.findIndex((offer) => offer._id === removeRequest.offerId);
if (playerOfferIndex === -1) if (playerOfferIndex === -1)
{ {
this.logger.error( this.logger.error(
@ -764,7 +762,7 @@ export class RagfairController
const pmcData = this.saveServer.getProfile(sessionId).characters.pmc; const pmcData = this.saveServer.getProfile(sessionId).characters.pmc;
const playerOffers = pmcData.RagfairInfo.offers; const playerOffers = pmcData.RagfairInfo.offers;
const playerOfferIndex = playerOffers.findIndex(offer => offer._id === extendRequest.offerId); const playerOfferIndex = playerOffers.findIndex((offer) => offer._id === extendRequest.offerId);
const secondsToAdd = extendRequest.renewalTime * TimeUtil.ONE_HOUR_AS_SECONDS; const secondsToAdd = extendRequest.renewalTime * TimeUtil.ONE_HOUR_AS_SECONDS;
if (playerOfferIndex === -1) if (playerOfferIndex === -1)

View File

@ -7,7 +7,6 @@ import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse"; import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
import { IRepairActionDataRequest } from "@spt-aki/models/eft/repair/IRepairActionDataRequest"; import { IRepairActionDataRequest } from "@spt-aki/models/eft/repair/IRepairActionDataRequest";
import { ITraderRepairActionDataRequest } from "@spt-aki/models/eft/repair/ITraderRepairActionDataRequest"; import { ITraderRepairActionDataRequest } from "@spt-aki/models/eft/repair/ITraderRepairActionDataRequest";
import { SkillTypes } from "@spt-aki/models/enums/SkillTypes";
import { IRepairConfig } from "@spt-aki/models/spt/config/IRepairConfig"; import { IRepairConfig } from "@spt-aki/models/spt/config/IRepairConfig";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder"; import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
@ -86,7 +85,11 @@ export class RepairController
* @param pmcData player profile * @param pmcData player profile
* @returns item event router action * @returns item event router action
*/ */
public repairWithKit(sessionID: string, body: IRepairActionDataRequest, pmcData: IPmcData): IItemEventRouterResponse public repairWithKit(
sessionID: string,
body: IRepairActionDataRequest,
pmcData: IPmcData,
): IItemEventRouterResponse
{ {
const output = this.eventOutputHolder.getOutput(sessionID); const output = this.eventOutputHolder.getOutput(sessionID);

View File

@ -90,7 +90,7 @@ export class RepeatableQuestController
const pmcData = this.profileHelper.getPmcProfile(sessionID); const pmcData = this.profileHelper.getPmcProfile(sessionID);
const time = this.timeUtil.getTimestamp(); const time = this.timeUtil.getTimestamp();
const scavQuestUnlocked const scavQuestUnlocked
= pmcData?.Hideout?.Areas?.find(hideoutArea => hideoutArea.type === HideoutAreas.INTEL_CENTER)?.level >= 1; = pmcData?.Hideout?.Areas?.find((hideoutArea) => hideoutArea.type === HideoutAreas.INTEL_CENTER)?.level >= 1;
// Daily / weekly / Daily_Savage // Daily / weekly / Daily_Savage
for (const repeatableConfig of this.questConfig.repeatableQuests) for (const repeatableConfig of this.questConfig.repeatableQuests)
@ -118,7 +118,7 @@ export class RepeatableQuestController
for (const activeQuest of currentRepeatableQuestType.activeQuests) for (const activeQuest of currentRepeatableQuestType.activeQuests)
{ {
// Keep finished quests in list so player can hand in // Keep finished quests in list so player can hand in
const quest = pmcData.Quests.find(quest => quest.qid === activeQuest._id); const quest = pmcData.Quests.find((quest) => quest.qid === activeQuest._id);
if (quest) if (quest)
{ {
if (quest.status === QuestStatus.AvailableForFinish) if (quest.status === QuestStatus.AvailableForFinish)
@ -134,7 +134,7 @@ export class RepeatableQuestController
this.profileFixerService.removeDanglingConditionCounters(pmcData); this.profileFixerService.removeDanglingConditionCounters(pmcData);
// Remove expired quest from pmc.quest array // Remove expired quest from pmc.quest array
pmcData.Quests = pmcData.Quests.filter(quest => quest.qid !== activeQuest._id); pmcData.Quests = pmcData.Quests.filter((quest) => quest.qid !== activeQuest._id);
currentRepeatableQuestType.inactiveQuests.push(activeQuest); currentRepeatableQuestType.inactiveQuests.push(activeQuest);
} }
currentRepeatableQuestType.activeQuests = questsToKeep; currentRepeatableQuestType.activeQuests = questsToKeep;
@ -216,14 +216,11 @@ export class RepeatableQuestController
) )
{ {
// Elite charisma skill gives extra daily quest(s) // Elite charisma skill gives extra daily quest(s)
return repeatableConfig.numQuests + this.databaseServer.getTables() return (
.globals repeatableConfig.numQuests
.config + this.databaseServer.getTables().globals.config.SkillsSettings.Charisma.BonusSettings.EliteBonusSettings
.SkillsSettings .RepeatableQuestExtraCount
.Charisma );
.BonusSettings
.EliteBonusSettings
.RepeatableQuestExtraCount;
} }
return repeatableConfig.numQuests; return repeatableConfig.numQuests;
@ -241,7 +238,7 @@ export class RepeatableQuestController
): IPmcDataRepeatableQuest ): IPmcDataRepeatableQuest
{ {
// Get from profile, add if missing // Get from profile, add if missing
let repeatableQuestDetails = pmcData.RepeatableQuests.find(x => x.name === repeatableConfig.name); let repeatableQuestDetails = pmcData.RepeatableQuests.find((x) => x.name === repeatableConfig.name);
if (!repeatableQuestDetails) if (!repeatableQuestDetails)
{ {
repeatableQuestDetails = { repeatableQuestDetails = {
@ -331,9 +328,10 @@ export class RepeatableQuestController
const possibleLocations = Object.keys(locations); const possibleLocations = Object.keys(locations);
// Set possible locations for elimination task, if target is savage, exclude labs from locations // Set possible locations for elimination task, if target is savage, exclude labs from locations
questPool.pool.Elimination.targets[probabilityObject.key] = probabilityObject.key === "Savage" questPool.pool.Elimination.targets[probabilityObject.key]
? { locations: possibleLocations.filter(x => x !== "laboratory") } = probabilityObject.key === "Savage"
: { locations: possibleLocations }; ? { locations: possibleLocations.filter((x) => x !== "laboratory") }
: { locations: possibleLocations };
} }
} }
@ -443,7 +441,7 @@ export class RepeatableQuestController
for (const currentRepeatablePool of pmcData.RepeatableQuests) for (const currentRepeatablePool of pmcData.RepeatableQuests)
{ {
// Check for existing quest in (daily/weekly/scav arrays) // Check for existing quest in (daily/weekly/scav arrays)
const questToReplace = currentRepeatablePool.activeQuests.find(x => x._id === changeRequest.qid); const questToReplace = currentRepeatablePool.activeQuests.find((x) => x._id === changeRequest.qid);
if (!questToReplace) if (!questToReplace)
{ {
continue; continue;
@ -453,8 +451,8 @@ export class RepeatableQuestController
replacedQuestTraderId = questToReplace.traderId; replacedQuestTraderId = questToReplace.traderId;
// Update active quests to exclude the quest we're replacing // Update active quests to exclude the quest we're replacing
currentRepeatablePool.activeQuests = currentRepeatablePool.activeQuests.filter(x => currentRepeatablePool.activeQuests = currentRepeatablePool.activeQuests.filter(
x._id !== changeRequest.qid, (x) => x._id !== changeRequest.qid,
); );
// Get cost to replace existing quest // Get cost to replace existing quest
@ -462,8 +460,8 @@ export class RepeatableQuestController
delete currentRepeatablePool.changeRequirement[changeRequest.qid]; delete currentRepeatablePool.changeRequirement[changeRequest.qid];
// TODO: somehow we need to reduce the questPool by the currently active quests (for all repeatables) // TODO: somehow we need to reduce the questPool by the currently active quests (for all repeatables)
const repeatableConfig = this.questConfig.repeatableQuests.find(x => const repeatableConfig = this.questConfig.repeatableQuests.find(
x.name === currentRepeatablePool.name, (x) => x.name === currentRepeatablePool.name,
); );
const questTypePool = this.generateQuestPool(repeatableConfig, pmcData.Info.Level); const questTypePool = this.generateQuestPool(repeatableConfig, pmcData.Info.Level);
const newRepeatableQuest = this.attemptToGenerateRepeatableQuest(pmcData, questTypePool, repeatableConfig); const newRepeatableQuest = this.attemptToGenerateRepeatableQuest(pmcData, questTypePool, repeatableConfig);

View File

@ -4,7 +4,7 @@ import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { TradeHelper } from "@spt-aki/helpers/TradeHelper"; import { TradeHelper } from "@spt-aki/helpers/TradeHelper";
import { TraderHelper } from "@spt-aki/helpers/TraderHelper"; import { TraderHelper } from "@spt-aki/helpers/TraderHelper";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { Item, Upd } from "@spt-aki/models/eft/common/tables/IItem"; import { Item } from "@spt-aki/models/eft/common/tables/IItem";
import { ITraderBase } from "@spt-aki/models/eft/common/tables/ITrader"; import { ITraderBase } from "@spt-aki/models/eft/common/tables/ITrader";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse"; import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
import { IRagfairOffer } from "@spt-aki/models/eft/ragfair/IRagfairOffer"; import { IRagfairOffer } from "@spt-aki/models/eft/ragfair/IRagfairOffer";
@ -170,9 +170,7 @@ export class TradeController
// Skip buying items when player doesn't have needed loyalty // Skip buying items when player doesn't have needed loyalty
if (this.playerLacksTraderLoyaltyLevelToBuyOffer(fleaOffer, pmcData)) if (this.playerLacksTraderLoyaltyLevelToBuyOffer(fleaOffer, pmcData))
{ {
const errorMessage = `Unable to buy item: ${ const errorMessage = `Unable to buy item: ${fleaOffer.items[0]._tpl} from trader: ${fleaOffer.user.id} as loyalty level too low, skipping`;
fleaOffer.items[0]._tpl
} from trader: ${fleaOffer.user.id} as loyalty level too low, skipping`;
this.logger.debug(errorMessage); this.logger.debug(errorMessage);
this.httpResponse.appendErrorToOutput(output, errorMessage, BackendErrorCodes.RAGFAIRUNAVAILABLE); this.httpResponse.appendErrorToOutput(output, errorMessage, BackendErrorCodes.RAGFAIRUNAVAILABLE);
@ -291,7 +289,7 @@ export class TradeController
this.traderHelper.getTraderById(trader), this.traderHelper.getTraderById(trader),
MessageType.MESSAGE_WITH_ITEMS, MessageType.MESSAGE_WITH_ITEMS,
this.randomUtil.getArrayValue(this.databaseServer.getTables().traders[trader].dialogue.soldItems), this.randomUtil.getArrayValue(this.databaseServer.getTables().traders[trader].dialogue.soldItems),
curencyReward.flatMap(x => x), curencyReward.flatMap((x) => x),
this.timeUtil.getHoursAsSeconds(72), this.timeUtil.getHoursAsSeconds(72),
); );
} }
@ -317,10 +315,12 @@ export class TradeController
for (const itemToSell of itemWithChildren) for (const itemToSell of itemWithChildren)
{ {
const itemDetails = this.itemHelper.getItem(itemToSell._tpl); const itemDetails = this.itemHelper.getItem(itemToSell._tpl);
if (!(itemDetails[0] && this.itemHelper.isOfBaseclasses( if (
itemDetails[1]._id, !(
traderDetails.items_buy.category, itemDetails[0]
))) && this.itemHelper.isOfBaseclasses(itemDetails[1]._id, traderDetails.items_buy.category)
)
)
{ {
// Skip if tpl isn't item OR item doesn't fulfil match traders buy categories // Skip if tpl isn't item OR item doesn't fulfil match traders buy categories
continue; continue;

View File

@ -29,7 +29,8 @@ export class TraderController
@inject("ProfileHelper") protected profileHelper: ProfileHelper, @inject("ProfileHelper") protected profileHelper: ProfileHelper,
@inject("TraderHelper") protected traderHelper: TraderHelper, @inject("TraderHelper") protected traderHelper: TraderHelper,
@inject("TraderAssortService") protected traderAssortService: TraderAssortService, @inject("TraderAssortService") protected traderAssortService: TraderAssortService,
@inject("TraderPurchasePersisterService") protected traderPurchasePersisterService: TraderPurchasePersisterService, @inject("TraderPurchasePersisterService")
protected traderPurchasePersisterService: TraderPurchasePersisterService,
@inject("FenceService") protected fenceService: FenceService, @inject("FenceService") protected fenceService: FenceService,
@inject("FenceBaseAssortGenerator") protected fenceBaseAssortGenerator: FenceBaseAssortGenerator, @inject("FenceBaseAssortGenerator") protected fenceBaseAssortGenerator: FenceBaseAssortGenerator,
@inject("ConfigServer") protected configServer: ConfigServer, @inject("ConfigServer") protected configServer: ConfigServer,

View File

@ -28,7 +28,11 @@ export class WishlistController
} }
/** Handle RemoveFromWishList event */ /** Handle RemoveFromWishList event */
public removeFromWishList(pmcData: IPmcData, body: IWishlistActionData, sessionID: string): IItemEventRouterResponse public removeFromWishList(
pmcData: IPmcData,
body: IWishlistActionData,
sessionID: string,
): IItemEventRouterResponse
{ {
for (let i = 0; i < pmcData.WishList.length; i++) for (let i = 0; i < pmcData.WishList.length; i++)
{ {

View File

@ -791,9 +791,13 @@ export class Container
depContainer.register<CustomizationController>("CustomizationController", { depContainer.register<CustomizationController>("CustomizationController", {
useClass: CustomizationController, useClass: CustomizationController,
}); });
depContainer.register<DialogueController>("DialogueController", { useClass: DialogueController }, { depContainer.register<DialogueController>(
lifecycle: Lifecycle.Singleton, "DialogueController",
}); { useClass: DialogueController },
{
lifecycle: Lifecycle.Singleton,
},
);
depContainer.register<GameController>("GameController", { useClass: GameController }); depContainer.register<GameController>("GameController", { useClass: GameController });
depContainer.register<HandbookController>("HandbookController", { useClass: HandbookController }); depContainer.register<HandbookController>("HandbookController", { useClass: HandbookController });
depContainer.register<HealthController>("HealthController", { useClass: HealthController }); depContainer.register<HealthController>("HealthController", { useClass: HealthController });

View File

@ -29,9 +29,13 @@ export class Router
{ {
if (partialMatch) if (partialMatch)
{ {
return this.getInternalHandledRoutes().filter(r => r.dynamic).some(r => url.includes(r.route)); return this.getInternalHandledRoutes()
.filter((r) => r.dynamic)
.some((r) => url.includes(r.route));
} }
return this.getInternalHandledRoutes().filter(r => !r.dynamic).some(r => r.route === url); return this.getInternalHandledRoutes()
.filter((r) => !r.dynamic)
.some((r) => r.route === url);
} }
} }
@ -44,12 +48,12 @@ export class StaticRouter extends Router
public async handleStatic(url: string, info: any, sessionID: string, output: string): Promise<any> public async handleStatic(url: string, info: any, sessionID: string, output: string): Promise<any>
{ {
return this.routes.find(route => route.url === url).action(url, info, sessionID, output); return this.routes.find((route) => route.url === url).action(url, info, sessionID, output);
} }
public override getHandledRoutes(): HandledRoute[] public override getHandledRoutes(): HandledRoute[]
{ {
return this.routes.map(route => new HandledRoute(route.url, false)); return this.routes.map((route) => new HandledRoute(route.url, false));
} }
} }
@ -62,12 +66,12 @@ export class DynamicRouter extends Router
public async handleDynamic(url: string, info: any, sessionID: string, output: string): Promise<any> public async handleDynamic(url: string, info: any, sessionID: string, output: string): Promise<any>
{ {
return this.routes.find(r => url.includes(r.url)).action(url, info, sessionID, output); return this.routes.find((r) => url.includes(r.url)).action(url, info, sessionID, output);
} }
public override getHandledRoutes(): HandledRoute[] public override getHandledRoutes(): HandledRoute[]
{ {
return this.routes.map(route => new HandledRoute(route.url, true)); return this.routes.map((route) => new HandledRoute(route.url, true));
} }
} }
@ -97,7 +101,10 @@ export class SaveLoadRouter extends Router
export class HandledRoute export class HandledRoute
{ {
constructor(public route: string, public dynamic: boolean) constructor(
public route: string,
public dynamic: boolean,
)
{} {}
} }

View File

@ -233,8 +233,9 @@ export class BotEquipmentModGenerator
} }
// Get the front/back/side weights based on bots level // Get the front/back/side weights based on bots level
const plateSlotWeights = settings.botEquipmentConfig?.armorPlateWeighting?.find(armorWeight => const plateSlotWeights = settings.botEquipmentConfig?.armorPlateWeighting?.find(
settings.botLevel >= armorWeight.levelRange.min && settings.botLevel <= armorWeight.levelRange.max, (armorWeight) =>
settings.botLevel >= armorWeight.levelRange.min && settings.botLevel <= armorWeight.levelRange.max,
); );
if (!plateSlotWeights) if (!plateSlotWeights)
{ {
@ -260,17 +261,17 @@ export class BotEquipmentModGenerator
const chosenArmorPlateLevel = this.weightedRandomHelper.getWeightedValue<string>(plateWeights); const chosenArmorPlateLevel = this.weightedRandomHelper.getWeightedValue<string>(plateWeights);
// Convert the array of ids into database items // Convert the array of ids into database items
const platesFromDb = existingPlateTplPool.map(plateTpl => this.itemHelper.getItem(plateTpl)[1]); const platesFromDb = existingPlateTplPool.map((plateTpl) => this.itemHelper.getItem(plateTpl)[1]);
// Filter plates to the chosen level based on its armorClass property // Filter plates to the chosen level based on its armorClass property
const platesOfDesiredLevel = platesFromDb.filter(item => item._props.armorClass === chosenArmorPlateLevel); const platesOfDesiredLevel = platesFromDb.filter((item) => item._props.armorClass === chosenArmorPlateLevel);
if (platesOfDesiredLevel.length === 0) if (platesOfDesiredLevel.length === 0)
{ {
this.logger.debug( this.logger.debug(
`Plate filter was too restrictive for armor: ${armorItem._name} ${armorItem._id}, unable to find plates of level: ${chosenArmorPlateLevel}. Using mod items default plate`, `Plate filter was too restrictive for armor: ${armorItem._name} ${armorItem._id}, unable to find plates of level: ${chosenArmorPlateLevel}. Using mod items default plate`,
); );
const relatedItemDbModSlot = armorItem._props.Slots.find(slot => slot._name.toLowerCase() === modSlot); const relatedItemDbModSlot = armorItem._props.Slots.find((slot) => slot._name.toLowerCase() === modSlot);
const defaultPlate = relatedItemDbModSlot._props.filters[0].Plate; const defaultPlate = relatedItemDbModSlot._props.filters[0].Plate;
if (!defaultPlate) if (!defaultPlate)
{ {
@ -280,8 +281,8 @@ export class BotEquipmentModGenerator
const defaultPreset = this.presetHelper.getDefaultPreset(armorItem._id); const defaultPreset = this.presetHelper.getDefaultPreset(armorItem._id);
if (defaultPreset) if (defaultPreset)
{ {
const relatedPresetSlot = defaultPreset._items.find(item => const relatedPresetSlot = defaultPreset._items.find(
item.slotId?.toLowerCase() === modSlot, (item) => item.slotId?.toLowerCase() === modSlot,
); );
if (relatedPresetSlot) if (relatedPresetSlot)
{ {
@ -305,7 +306,7 @@ export class BotEquipmentModGenerator
// Only return the items ids // Only return the items ids
result.result = Result.SUCCESS; result.result = Result.SUCCESS;
result.plateModTpls = platesOfDesiredLevel.map(item => item._id); result.plateModTpls = platesOfDesiredLevel.map((item) => item._id);
return result; return result;
} }
@ -345,8 +346,11 @@ export class BotEquipmentModGenerator
const compatibleModsPool = modPool[parentTemplate._id]; const compatibleModsPool = modPool[parentTemplate._id];
if ( if (
!(parentTemplate._props.Slots.length || parentTemplate._props.Cartridges?.length !(
|| parentTemplate._props.Chambers?.length) parentTemplate._props.Slots.length
|| parentTemplate._props.Cartridges?.length
|| parentTemplate._props.Chambers?.length
)
) )
{ {
this.logger.error( this.logger.error(
@ -467,10 +471,9 @@ export class BotEquipmentModGenerator
// Handguard mod can take a sub handguard mod + weapon has no UBGL (takes same slot) // Handguard mod can take a sub handguard mod + weapon has no UBGL (takes same slot)
// Force spawn chance to be 100% to ensure it gets added // Force spawn chance to be 100% to ensure it gets added
if ( if (
modSlot === "mod_handguard" && modToAddTemplate._props.Slots.find(slot => modSlot === "mod_handguard"
slot._name === "mod_handguard", && modToAddTemplate._props.Slots.find((slot) => slot._name === "mod_handguard")
) && !weapon.find((item) => item.slotId === "mod_launcher")
&& !weapon.find(item => item.slotId === "mod_launcher")
) )
{ {
// Needed for handguards with lower // Needed for handguards with lower
@ -480,8 +483,9 @@ export class BotEquipmentModGenerator
// If stock mod can take a sub stock mod, force spawn chance to be 100% to ensure sub-stock gets added // If stock mod can take a sub stock mod, force spawn chance to be 100% to ensure sub-stock gets added
// Or if mod_stock is configured to be forced on // Or if mod_stock is configured to be forced on
if ( if (
modSlot === "mod_stock" && modToAddTemplate._props.Slots.find(slot => modSlot === "mod_stock"
slot._name.includes("mod_stock") || botEquipConfig.forceStock, && modToAddTemplate._props.Slots.find(
(slot) => slot._name.includes("mod_stock") || botEquipConfig.forceStock,
) )
) )
{ {
@ -549,8 +553,9 @@ export class BotEquipmentModGenerator
protected modIsFrontOrRearSight(modSlot: string, tpl: string): boolean protected modIsFrontOrRearSight(modSlot: string, tpl: string): boolean
{ {
// Gas block /w front sight is special case, deem it a 'front sight' too // Gas block /w front sight is special case, deem it a 'front sight' too
if (modSlot === "mod_gas_block" && tpl === "5ae30e795acfc408fb139a0b") // M4A1 front sight with gas block if (modSlot === "mod_gas_block" && tpl === "5ae30e795acfc408fb139a0b")
{ {
// M4A1 front sight with gas block
return true; return true;
} }
@ -565,15 +570,17 @@ export class BotEquipmentModGenerator
*/ */
protected modSlotCanHoldScope(modSlot: string, modsParentId: string): boolean protected modSlotCanHoldScope(modSlot: string, modsParentId: string): boolean
{ {
return [ return (
"mod_scope", [
"mod_mount", "mod_scope",
"mod_mount_000", "mod_mount",
"mod_scope_000", "mod_mount_000",
"mod_scope_001", "mod_scope_000",
"mod_scope_002", "mod_scope_001",
"mod_scope_003", "mod_scope_002",
].includes(modSlot.toLowerCase()) && modsParentId === BaseClasses.MOUNT; "mod_scope_003",
].includes(modSlot.toLowerCase()) && modsParentId === BaseClasses.MOUNT
);
} }
/** /**
@ -700,11 +707,11 @@ export class BotEquipmentModGenerator
case "patron_in_weapon": case "patron_in_weapon":
case "patron_in_weapon_000": case "patron_in_weapon_000":
case "patron_in_weapon_001": case "patron_in_weapon_001":
return parentTemplate._props.Chambers.find(chamber => chamber._name.includes(modSlotLower)); return parentTemplate._props.Chambers.find((chamber) => chamber._name.includes(modSlotLower));
case "cartridges": case "cartridges":
return parentTemplate._props.Cartridges.find(c => c._name.toLowerCase() === modSlotLower); return parentTemplate._props.Cartridges.find((c) => c._name.toLowerCase() === modSlotLower);
default: default:
return parentTemplate._props.Slots.find(s => s._name.toLowerCase() === modSlotLower); return parentTemplate._props.Slots.find((s) => s._name.toLowerCase() === modSlotLower);
} }
} }
@ -762,7 +769,7 @@ export class BotEquipmentModGenerator
): [boolean, ITemplateItem] ): [boolean, ITemplateItem]
{ {
/** Slot mod will fill */ /** Slot mod will fill */
const parentSlot = parentTemplate._props.Slots.find(i => i._name === modSlot); const parentSlot = parentTemplate._props.Slots.find((i) => i._name === modSlot);
const weaponTemplate = this.itemHelper.getItem(weapon[0]._tpl)[1]; const weaponTemplate = this.itemHelper.getItem(weapon[0]._tpl)[1];
// It's ammo, use predefined ammo parameter // It's ammo, use predefined ammo parameter
@ -837,9 +844,7 @@ export class BotEquipmentModGenerator
if (parentSlot._required) if (parentSlot._required)
{ {
this.logger.warning( this.logger.warning(
`Required slot unable to be filled, ${modSlot} on ${parentTemplate._name} ${parentTemplate._id} for weapon: ${ `Required slot unable to be filled, ${modSlot} on ${parentTemplate._name} ${parentTemplate._id} for weapon: ${weapon[0]._tpl}`,
weapon[0]._tpl
}`,
); );
} }
@ -950,8 +955,8 @@ export class BotEquipmentModGenerator
if (modSpawnResult === ModSpawn.DEFAULT_MOD) if (modSpawnResult === ModSpawn.DEFAULT_MOD)
{ {
const matchingPreset = this.getMatchingPreset(weaponTemplate, parentTemplate._id); const matchingPreset = this.getMatchingPreset(weaponTemplate, parentTemplate._id);
const matchingModFromPreset = matchingPreset?._items.find(item => const matchingModFromPreset = matchingPreset?._items.find(
item?.slotId?.toLowerCase() === modSlot.toLowerCase(), (item) => item?.slotId?.toLowerCase() === modSlot.toLowerCase(),
); );
// Only filter mods down to single default item if it already exists in existing itemModPool, OR the default item has no children // Only filter mods down to single default item if it already exists in existing itemModPool, OR the default item has no children
@ -968,8 +973,8 @@ export class BotEquipmentModGenerator
// Get an array of items that are allowed in slot from parent item // Get an array of items that are allowed in slot from parent item
// Check the filter of the slot to ensure a chosen mod fits // Check the filter of the slot to ensure a chosen mod fits
const parentSlotCompatibleItems = parentTemplate._props.Slots?.find(slot => const parentSlotCompatibleItems = parentTemplate._props.Slots?.find(
slot._name.toLowerCase() === modSlot.toLowerCase(), (slot) => slot._name.toLowerCase() === modSlot.toLowerCase(),
)._props.filters[0].Filter; )._props.filters[0].Filter;
// Mod isnt in existing pool, only add if it has no children and matches parent filter // Mod isnt in existing pool, only add if it has no children and matches parent filter
@ -985,7 +990,9 @@ export class BotEquipmentModGenerator
if (itemModPool[modSlot]?.length > 1) if (itemModPool[modSlot]?.length > 1)
{ {
this.logger.debug(`No default: ${modSlot} mod found on template: ${weaponTemplate._name} and multiple items found in existing pool`); this.logger.debug(
`No default: ${modSlot} mod found on template: ${weaponTemplate._name} and multiple items found in existing pool`,
);
} }
// Couldnt find default in globals, use existing mod pool data // Couldnt find default in globals, use existing mod pool data
@ -1178,7 +1185,7 @@ export class BotEquipmentModGenerator
botEquipBlacklist: EquipmentFilterDetails, botEquipBlacklist: EquipmentFilterDetails,
): void ): void
{ {
const desiredSlotObject = modTemplate._props.Slots.find(slot => slot._name.includes(desiredSlotName)); const desiredSlotObject = modTemplate._props.Slots.find((slot) => slot._name.includes(desiredSlotName));
if (desiredSlotObject) if (desiredSlotObject)
{ {
const supportedSubMods = desiredSlotObject._props.filters[0].Filter; const supportedSubMods = desiredSlotObject._props.filters[0].Filter;
@ -1261,10 +1268,10 @@ export class BotEquipmentModGenerator
let result: string[] = []; let result: string[] = [];
// Get item blacklist and mod equipment blacklist as one array // Get item blacklist and mod equipment blacklist as one array
const blacklist = this.itemFilterService.getBlacklistedItems().concat( const blacklist = this.itemFilterService
botEquipBlacklist.equipment[modSlot] || [], .getBlacklistedItems()
); .concat(botEquipBlacklist.equipment[modSlot] || []);
result = allowedMods.filter(tpl => !blacklist.includes(tpl)); result = allowedMods.filter((tpl) => !blacklist.includes(tpl));
return result; return result;
} }
@ -1290,7 +1297,7 @@ export class BotEquipmentModGenerator
weaponName: parentTemplate._name, weaponName: parentTemplate._name,
}), }),
); );
const camoraSlots = parentTemplate._props.Slots.filter(slot => slot._name.startsWith("camora")); const camoraSlots = parentTemplate._props.Slots.filter((slot) => slot._name.startsWith("camora"));
// Attempt to generate camora slots for item // Attempt to generate camora slots for item
modPool[parentTemplate._id] = {}; modPool[parentTemplate._id] = {};
@ -1397,9 +1404,7 @@ export class BotEquipmentModGenerator
if (!whitelistedSightTypes) if (!whitelistedSightTypes)
{ {
this.logger.debug( this.logger.debug(
`Unable to find whitelist for weapon type: ${weaponDetails[1]._parent} ${ `Unable to find whitelist for weapon type: ${weaponDetails[1]._parent} ${weaponDetails[1]._name}, skipping sight filtering`,
weaponDetails[1]._name
}, skipping sight filtering`,
); );
return scopes; return scopes;
@ -1424,16 +1429,17 @@ export class BotEquipmentModGenerator
{ {
// Check to see if mount has a scope slot (only include primary slot, ignore the rest like the backup sight slots) // Check to see if mount has a scope slot (only include primary slot, ignore the rest like the backup sight slots)
// Should only find 1 as there's currently no items with a mod_scope AND a mod_scope_000 // Should only find 1 as there's currently no items with a mod_scope AND a mod_scope_000
const scopeSlot = itemDetails._props.Slots.filter(slot => const scopeSlot = itemDetails._props.Slots.filter((slot) =>
["mod_scope", "mod_scope_000"].includes(slot._name), ["mod_scope", "mod_scope_000"].includes(slot._name),
); );
// Mods scope slot found must allow ALL whitelisted scope types OR be a mount // Mods scope slot found must allow ALL whitelisted scope types OR be a mount
if ( if (
scopeSlot?.every(slot => scopeSlot?.every((slot) =>
slot._props.filters[0].Filter.every(tpl => slot._props.filters[0].Filter.every(
this.itemHelper.isOfBaseclasses(tpl, whitelistedSightTypes) (tpl) =>
|| this.itemHelper.isOfBaseclass(tpl, BaseClasses.MOUNT), this.itemHelper.isOfBaseclasses(tpl, whitelistedSightTypes)
|| this.itemHelper.isOfBaseclass(tpl, BaseClasses.MOUNT),
), ),
) )
) )

View File

@ -232,7 +232,11 @@ export class BotGenerator
* @param appearance Appearance settings to choose from * @param appearance Appearance settings to choose from
* @param botGenerationDetails Generation details * @param botGenerationDetails Generation details
*/ */
protected setBotAppearance(bot: IBotBase, appearance: Appearance, botGenerationDetails: BotGenerationDetails): void protected setBotAppearance(
bot: IBotBase,
appearance: Appearance,
botGenerationDetails: BotGenerationDetails,
): void
{ {
bot.Customization.Head = this.weightedRandomHelper.getWeightedValue<string>(appearance.head); bot.Customization.Head = this.weightedRandomHelper.getWeightedValue<string>(appearance.head);
bot.Customization.Body = this.weightedRandomHelper.getWeightedValue<string>(appearance.body); bot.Customization.Body = this.weightedRandomHelper.getWeightedValue<string>(appearance.body);
@ -425,27 +429,29 @@ export class BotGenerator
return []; return [];
} }
return Object.keys(skills).map((skillKey): IBaseSkill => return Object.keys(skills)
{ .map((skillKey): IBaseSkill =>
// Get skill from dict, skip if not found
const skill = skills[skillKey];
if (!skill)
{ {
return null; // Get skill from dict, skip if not found
} const skill = skills[skillKey];
if (!skill)
{
return null;
}
// All skills have id and progress props // All skills have id and progress props
const skillToAdd: IBaseSkill = { Id: skillKey, Progress: this.randomUtil.getInt(skill.min, skill.max) }; const skillToAdd: IBaseSkill = { Id: skillKey, Progress: this.randomUtil.getInt(skill.min, skill.max) };
// Common skills have additional props // Common skills have additional props
if (isCommonSkills) if (isCommonSkills)
{ {
(skillToAdd as Common).PointsEarnedDuringSession = 0; (skillToAdd as Common).PointsEarnedDuringSession = 0;
(skillToAdd as Common).LastAccess = 0; (skillToAdd as Common).LastAccess = 0;
} }
return skillToAdd; return skillToAdd;
}).filter(x => x !== null); })
.filter((x) => x !== null);
} }
/** /**

View File

@ -307,8 +307,9 @@ export class BotInventoryGenerator
*/ */
protected generateEquipment(settings: IGenerateEquipmentProperties): boolean protected generateEquipment(settings: IGenerateEquipmentProperties): boolean
{ {
const spawnChance = ([EquipmentSlots.POCKETS, EquipmentSlots.SECURED_CONTAINER] as string[]) const spawnChance = ([EquipmentSlots.POCKETS, EquipmentSlots.SECURED_CONTAINER] as string[]).includes(
.includes(settings.rootEquipmentSlot) settings.rootEquipmentSlot,
)
? 100 ? 100
: settings.spawnChances.equipment[settings.rootEquipmentSlot]; : settings.spawnChances.equipment[settings.rootEquipmentSlot];
@ -442,7 +443,7 @@ export class BotInventoryGenerator
for (const modSlot of Object.keys(modPool ?? [])) for (const modSlot of Object.keys(modPool ?? []))
{ {
const blacklistedMods = equipmentBlacklist[0]?.equipment[modSlot] || []; const blacklistedMods = equipmentBlacklist[0]?.equipment[modSlot] || [];
const filteredMods = modPool[modSlot].filter(x => !blacklistedMods.includes(x)); const filteredMods = modPool[modSlot].filter((x) => !blacklistedMods.includes(x));
if (filteredMods.length > 0) if (filteredMods.length > 0)
{ {
@ -504,17 +505,21 @@ export class BotInventoryGenerator
protected getDesiredWeaponsForBot(equipmentChances: Chances): { slot: EquipmentSlots, shouldSpawn: boolean }[] protected getDesiredWeaponsForBot(equipmentChances: Chances): { slot: EquipmentSlots, shouldSpawn: boolean }[]
{ {
const shouldSpawnPrimary = this.randomUtil.getChance100(equipmentChances.equipment.FirstPrimaryWeapon); const shouldSpawnPrimary = this.randomUtil.getChance100(equipmentChances.equipment.FirstPrimaryWeapon);
return [{ slot: EquipmentSlots.FIRST_PRIMARY_WEAPON, shouldSpawn: shouldSpawnPrimary }, { return [
slot: EquipmentSlots.SECOND_PRIMARY_WEAPON, { slot: EquipmentSlots.FIRST_PRIMARY_WEAPON, shouldSpawn: shouldSpawnPrimary },
shouldSpawn: shouldSpawnPrimary {
? this.randomUtil.getChance100(equipmentChances.equipment.SecondPrimaryWeapon) slot: EquipmentSlots.SECOND_PRIMARY_WEAPON,
: false, shouldSpawn: shouldSpawnPrimary
}, { ? this.randomUtil.getChance100(equipmentChances.equipment.SecondPrimaryWeapon)
slot: EquipmentSlots.HOLSTER, : false,
shouldSpawn: shouldSpawnPrimary },
? this.randomUtil.getChance100(equipmentChances.equipment.Holster) // Primary weapon = roll for chance at pistol {
: true, // No primary = force pistol slot: EquipmentSlots.HOLSTER,
}]; shouldSpawn: shouldSpawnPrimary
? this.randomUtil.getChance100(equipmentChances.equipment.Holster) // Primary weapon = roll for chance at pistol
: true, // No primary = force pistol
},
];
} }
/** /**

View File

@ -65,9 +65,10 @@ export class BotLevelGenerator
maxLevel: number, maxLevel: number,
): number ): number
{ {
const maxPossibleLevel = botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride const maxPossibleLevel
? Math.min(botGenerationDetails.locationSpecificPmcLevelOverride.max, maxLevel) // Was a PMC and they have a level override = botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride
: Math.min(levelDetails.max, maxLevel); // Not pmc with override or non-pmc ? Math.min(botGenerationDetails.locationSpecificPmcLevelOverride.max, maxLevel) // Was a PMC and they have a level override
: Math.min(levelDetails.max, maxLevel); // Not pmc with override or non-pmc
let level = botGenerationDetails.playerLevel + botGenerationDetails.botRelativeLevelDeltaMax; let level = botGenerationDetails.playerLevel + botGenerationDetails.botRelativeLevelDeltaMax;
if (level > maxPossibleLevel) if (level > maxPossibleLevel)
@ -91,12 +92,13 @@ export class BotLevelGenerator
maxlevel: number, maxlevel: number,
): number ): number
{ {
const minPossibleLevel = botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride const minPossibleLevel
? Math.min( = botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride
Math.max(levelDetails.min, botGenerationDetails.locationSpecificPmcLevelOverride.min), // Biggest between json min and the botgen min ? Math.min(
maxlevel, // Fallback if value above is crazy (default is 79) Math.max(levelDetails.min, botGenerationDetails.locationSpecificPmcLevelOverride.min), // Biggest between json min and the botgen min
) maxlevel, // Fallback if value above is crazy (default is 79)
: Math.min(levelDetails.min, maxlevel); // Not pmc with override or non-pmc )
: Math.min(levelDetails.min, maxlevel); // Not pmc with override or non-pmc
let level = botGenerationDetails.playerLevel - botGenerationDetails.botRelativeLevelDeltaMin; let level = botGenerationDetails.playerLevel - botGenerationDetails.botRelativeLevelDeltaMin;
if (level < minPossibleLevel) if (level < minPossibleLevel)

View File

@ -85,7 +85,8 @@ export class BotLootGenerator
// Limits on item types to be added as loot // Limits on item types to be added as loot
const itemCounts = botJsonTemplate.generation.items; const itemCounts = botJsonTemplate.generation.items;
if(!itemCounts.backpackLoot.weights if (
!itemCounts.backpackLoot.weights
|| !itemCounts.pocketLoot.weights || !itemCounts.pocketLoot.weights
|| !itemCounts.vestLoot.weights || !itemCounts.vestLoot.weights
|| !itemCounts.specialItems.weights || !itemCounts.specialItems.weights
@ -98,7 +99,9 @@ export class BotLootGenerator
|| !itemCounts.grenades.weights || !itemCounts.grenades.weights
) )
{ {
this.logger.warning(`Unable to generate bot loot for ${botRole} as bot.generation.items lacks data, skipping`); this.logger.warning(
`Unable to generate bot loot for ${botRole} as bot.generation.items lacks data, skipping`,
);
return; return;
} }
@ -334,12 +337,12 @@ export class BotLootGenerator
{ {
const result = [EquipmentSlots.POCKETS]; const result = [EquipmentSlots.POCKETS];
if (botInventory.items.find(item => item.slotId === EquipmentSlots.TACTICAL_VEST)) if (botInventory.items.find((item) => item.slotId === EquipmentSlots.TACTICAL_VEST))
{ {
result.push(EquipmentSlots.TACTICAL_VEST); result.push(EquipmentSlots.TACTICAL_VEST);
} }
if (botInventory.items.find(item => item.slotId === EquipmentSlots.BACKPACK)) if (botInventory.items.find((item) => item.slotId === EquipmentSlots.BACKPACK))
{ {
result.push(EquipmentSlots.BACKPACK); result.push(EquipmentSlots.BACKPACK);
} }
@ -457,11 +460,13 @@ export class BotLootGenerator
} }
const newRootItemId = this.hashUtil.generate(); const newRootItemId = this.hashUtil.generate();
const itemWithChildrenToAdd: Item[] = [{ const itemWithChildrenToAdd: Item[] = [
_id: newRootItemId, {
_tpl: itemToAddTemplate._id, _id: newRootItemId,
...this.botGeneratorHelper.generateExtraPropertiesForItem(itemToAddTemplate, botRole), _tpl: itemToAddTemplate._id,
}]; ...this.botGeneratorHelper.generateExtraPropertiesForItem(itemToAddTemplate, botRole),
},
];
// Is Simple-Wallet / WZ wallet // Is Simple-Wallet / WZ wallet
if (this.botConfig.walletLoot.walletTplPool.includes(weightedItemTpl)) if (this.botConfig.walletLoot.walletTplPool.includes(weightedItemTpl))
@ -493,7 +498,7 @@ export class BotLootGenerator
); );
} }
itemWithChildrenToAdd.push(...itemsToAdd.flatMap(moneyStack => moneyStack)); itemWithChildrenToAdd.push(...itemsToAdd.flatMap((moneyStack) => moneyStack));
} }
} }
} }
@ -526,9 +531,9 @@ export class BotLootGenerator
if (fitItemIntoContainerAttempts >= 4) if (fitItemIntoContainerAttempts >= 4)
{ {
this.logger.debug( this.logger.debug(
`Failed to place item ${i} of ${totalItemCount} items into ${botRole} containers: ${ `Failed to place item ${i} of ${totalItemCount} items into ${botRole} containers: ${equipmentSlots.join(
equipmentSlots.join(",") ",",
}. Tried ${fitItemIntoContainerAttempts} times, reason: ${ )}. Tried ${fitItemIntoContainerAttempts} times, reason: ${
ItemAddedResult[itemAddedResult] ItemAddedResult[itemAddedResult]
}, skipping`, }, skipping`,
); );
@ -571,12 +576,14 @@ export class BotLootGenerator
const chosenStackCount = Number( const chosenStackCount = Number(
this.weightedRandomHelper.getWeightedValue<string>(this.botConfig.walletLoot.stackSizeWeight), this.weightedRandomHelper.getWeightedValue<string>(this.botConfig.walletLoot.stackSizeWeight),
); );
result.push([{ result.push([
_id: this.hashUtil.generate(), {
_tpl: this.weightedRandomHelper.getWeightedValue<string>(this.botConfig.walletLoot.currencyWeight), _id: this.hashUtil.generate(),
parentId: walletId, _tpl: this.weightedRandomHelper.getWeightedValue<string>(this.botConfig.walletLoot.currencyWeight),
upd: { StackObjectsCount: chosenStackCount }, parentId: walletId,
}]); upd: { StackObjectsCount: chosenStackCount },
},
]);
} }
return result; return result;
@ -675,9 +682,7 @@ export class BotLootGenerator
if (result !== ItemAddedResult.SUCCESS) if (result !== ItemAddedResult.SUCCESS)
{ {
this.logger.debug( this.logger.debug(
`Failed to add additional weapon ${generatedWeapon.weapon[0]._id} to bot backpack, reason: ${ `Failed to add additional weapon ${generatedWeapon.weapon[0]._id} to bot backpack, reason: ${ItemAddedResult[result]}`,
ItemAddedResult[result]
}`,
); );
} }
} }
@ -789,12 +794,13 @@ export class BotLootGenerator
*/ */
protected randomiseAmmoStackSize(isPmc: boolean, itemTemplate: ITemplateItem, ammoItem: Item): void protected randomiseAmmoStackSize(isPmc: boolean, itemTemplate: ITemplateItem, ammoItem: Item): void
{ {
const randomSize = itemTemplate._props.StackMaxSize === 1 const randomSize
? 1 = itemTemplate._props.StackMaxSize === 1
: this.randomUtil.getInt( ? 1
itemTemplate._props.StackMinRandom, : this.randomUtil.getInt(
Math.min(itemTemplate._props.StackMaxRandom, 60), itemTemplate._props.StackMinRandom,
); Math.min(itemTemplate._props.StackMaxRandom, 60),
);
this.itemHelper.addUpdObjectToItem(ammoItem); this.itemHelper.addUpdObjectToItem(ammoItem);

View File

@ -199,7 +199,7 @@ export class BotWeaponGenerator
} }
// Fill existing magazines to full and sync ammo type // Fill existing magazines to full and sync ammo type
for (const magazine of weaponWithModsArray.filter(item => item.slotId === this.modMagazineSlotId)) for (const magazine of weaponWithModsArray.filter((item) => item.slotId === this.modMagazineSlotId))
{ {
this.fillExistingMagazines(weaponWithModsArray, magazine, ammoTpl); this.fillExistingMagazines(weaponWithModsArray, magazine, ammoTpl);
} }
@ -211,12 +211,12 @@ export class BotWeaponGenerator
) )
{ {
// Guns have variety of possible Chamber ids, patron_in_weapon/patron_in_weapon_000/patron_in_weapon_001 // Guns have variety of possible Chamber ids, patron_in_weapon/patron_in_weapon_000/patron_in_weapon_001
const chamberSlotNames = weaponItemTemplate._props.Chambers.map(x => x._name); const chamberSlotNames = weaponItemTemplate._props.Chambers.map((x) => x._name);
this.addCartridgeToChamber(weaponWithModsArray, ammoTpl, chamberSlotNames); this.addCartridgeToChamber(weaponWithModsArray, ammoTpl, chamberSlotNames);
} }
// Fill UBGL if found // Fill UBGL if found
const ubglMod = weaponWithModsArray.find(x => x.slotId === "mod_launcher"); const ubglMod = weaponWithModsArray.find((x) => x.slotId === "mod_launcher");
let ubglAmmoTpl: string = undefined; let ubglAmmoTpl: string = undefined;
if (ubglMod) if (ubglMod)
{ {
@ -245,7 +245,7 @@ export class BotWeaponGenerator
{ {
for (const slotId of chamberSlotIds) for (const slotId of chamberSlotIds)
{ {
const existingItemWithSlot = weaponWithModsArray.find(x => x.slotId === slotId); const existingItemWithSlot = weaponWithModsArray.find((x) => x.slotId === slotId);
if (!existingItemWithSlot) if (!existingItemWithSlot)
{ {
// Not found, add new slot to weapon // Not found, add new slot to weapon
@ -284,13 +284,15 @@ export class BotWeaponGenerator
botRole: string, botRole: string,
): Item[] ): Item[]
{ {
return [{ return [
_id: this.hashUtil.generate(), {
_tpl: weaponTpl, _id: this.hashUtil.generate(),
parentId: weaponParentId, _tpl: weaponTpl,
slotId: equipmentSlot, parentId: weaponParentId,
...this.botGeneratorHelper.generateExtraPropertiesForItem(weaponItemTemplate, botRole), slotId: equipmentSlot,
}]; ...this.botGeneratorHelper.generateExtraPropertiesForItem(weaponItemTemplate, botRole),
},
];
} }
/** /**
@ -366,11 +368,11 @@ export class BotWeaponGenerator
} }
// Iterate over required slots in db item, check mod exists for that slot // Iterate over required slots in db item, check mod exists for that slot
for (const modSlotTemplate of modTemplate._props.Slots.filter(slot => slot._required)) for (const modSlotTemplate of modTemplate._props.Slots.filter((slot) => slot._required))
{ {
const slotName = modSlotTemplate._name; const slotName = modSlotTemplate._name;
const weaponSlotItem = weaponItemArray.find(weaponItem => const weaponSlotItem = weaponItemArray.find(
weaponItem.parentId === mod._id && weaponItem.slotId === slotName, (weaponItem) => weaponItem.parentId === mod._id && weaponItem.slotId === slotName,
); );
if (!weaponSlotItem) if (!weaponSlotItem)
{ {
@ -441,9 +443,9 @@ export class BotWeaponGenerator
ammoTemplate, ammoTemplate,
inventory, inventory,
); );
this.inventoryMagGenComponents.find(v => v.canHandleInventoryMagGen(inventoryMagGenModel)).process( this.inventoryMagGenComponents
inventoryMagGenModel, .find((v) => v.canHandleInventoryMagGen(inventoryMagGenModel))
); .process(inventoryMagGenModel);
// Add x stacks of bullets to SecuredContainer (bots use a magic mag packing skill to reload instantly) // Add x stacks of bullets to SecuredContainer (bots use a magic mag packing skill to reload instantly)
this.addAmmoToSecureContainer( this.addAmmoToSecureContainer(
@ -467,7 +469,7 @@ export class BotWeaponGenerator
): void ): void
{ {
// Find ubgl mod item + get details of it from db // Find ubgl mod item + get details of it from db
const ubglMod = weaponMods.find(x => x.slotId === "mod_launcher"); const ubglMod = weaponMods.find((x) => x.slotId === "mod_launcher");
const ubglDbTemplate = this.itemHelper.getItem(ubglMod._tpl)[1]; const ubglDbTemplate = this.itemHelper.getItem(ubglMod._tpl)[1];
// Define min/max of how many grenades bot will have // Define min/max of how many grenades bot will have
@ -488,9 +490,9 @@ export class BotWeaponGenerator
ubglAmmoDbTemplate, ubglAmmoDbTemplate,
inventory, inventory,
); );
this.inventoryMagGenComponents.find(v => v.canHandleInventoryMagGen(ubglAmmoGenModel)).process( this.inventoryMagGenComponents
ubglAmmoGenModel, .find((v) => v.canHandleInventoryMagGen(ubglAmmoGenModel))
); .process(ubglAmmoGenModel);
// Store extra grenades in secure container // Store extra grenades in secure container
this.addAmmoToSecureContainer(5, generatedWeaponResult.chosenUbglAmmoTpl, 20, inventory); this.addAmmoToSecureContainer(5, generatedWeaponResult.chosenUbglAmmoTpl, 20, inventory);
@ -536,7 +538,7 @@ export class BotWeaponGenerator
botRole: string, botRole: string,
): string ): string
{ {
const magazine = weaponMods.find(m => m.slotId === this.modMagazineSlotId); const magazine = weaponMods.find((m) => m.slotId === this.modMagazineSlotId);
if (!magazine) if (!magazine)
{ {
// Edge case - magazineless chamber loaded weapons dont have magazines, e.g. mp18 // Edge case - magazineless chamber loaded weapons dont have magazines, e.g. mp18
@ -736,8 +738,8 @@ export class BotWeaponGenerator
magazineTemplate: ITemplateItem, magazineTemplate: ITemplateItem,
): void ): void
{ {
const magazineCartridgeChildItem = weaponWithMods.find(m => const magazineCartridgeChildItem = weaponWithMods.find(
m.parentId === magazine._id && m.slotId === "cartridges", (m) => m.parentId === magazine._id && m.slotId === "cartridges",
); );
if (magazineCartridgeChildItem) if (magazineCartridgeChildItem)
{ {
@ -766,7 +768,7 @@ export class BotWeaponGenerator
// for CylinderMagazine we exchange the ammo in the "camoras". // for CylinderMagazine we exchange the ammo in the "camoras".
// This might not be necessary since we already filled the camoras with a random whitelisted and compatible ammo type, // This might not be necessary since we already filled the camoras with a random whitelisted and compatible ammo type,
// but I'm not sure whether this is also used elsewhere // but I'm not sure whether this is also used elsewhere
const camoras = weaponMods.filter(x => x.parentId === magazineId && x.slotId.startsWith("camora")); const camoras = weaponMods.filter((x) => x.parentId === magazineId && x.slotId.startsWith("camora"));
for (const camora of camoras) for (const camora of camoras)
{ {
camora._tpl = ammoTpl; camora._tpl = ammoTpl;

View File

@ -47,7 +47,7 @@ export class FenceBaseAssortGenerator
const blockedSeasonalItems = this.seasonalEventService.getInactiveSeasonalEventItems(); const blockedSeasonalItems = this.seasonalEventService.getInactiveSeasonalEventItems();
const baseFenceAssort = this.databaseServer.getTables().traders[Traders.FENCE].assort; const baseFenceAssort = this.databaseServer.getTables().traders[Traders.FENCE].assort;
for (const rootItemDb of this.itemHelper.getItems().filter(item => this.isValidFenceItem(item))) for (const rootItemDb of this.itemHelper.getItems().filter((item) => this.isValidFenceItem(item)))
{ {
// Skip blacklisted items // Skip blacklisted items
if (this.itemFilterService.isItemBlacklisted(rootItemDb._id)) if (this.itemFilterService.isItemBlacklisted(rootItemDb._id))
@ -86,13 +86,15 @@ export class FenceBaseAssortGenerator
} }
// Create item object in array // Create item object in array
const itemWithChildrenToAdd: Item[] = [{ const itemWithChildrenToAdd: Item[] = [
_id: this.hashUtil.generate(), {
_tpl: rootItemDb._id, _id: this.hashUtil.generate(),
parentId: "hideout", _tpl: rootItemDb._id,
slotId: "hideout", parentId: "hideout",
upd: { StackObjectsCount: 9999999 }, slotId: "hideout",
}]; upd: { StackObjectsCount: 9999999 },
},
];
// Ensure ammo is not above penetration limit value // Ensure ammo is not above penetration limit value
if (this.itemHelper.isOfBaseclasses(rootItemDb._id, [BaseClasses.AMMO_BOX, BaseClasses.AMMO])) if (this.itemHelper.isOfBaseclasses(rootItemDb._id, [BaseClasses.AMMO_BOX, BaseClasses.AMMO]))
@ -141,7 +143,7 @@ export class FenceBaseAssortGenerator
for (const defaultPreset of defaultPresets) for (const defaultPreset of defaultPresets)
{ {
// Skip presets we've already added // Skip presets we've already added
if (baseFenceAssort.items.some(item => item.upd && item.upd.sptPresetId === defaultPreset._id)) if (baseFenceAssort.items.some((item) => item.upd && item.upd.sptPresetId === defaultPreset._id))
{ {
continue; continue;
} }
@ -249,7 +251,7 @@ export class FenceBaseAssortGenerator
} }
// Check for and add required soft inserts to armors // Check for and add required soft inserts to armors
const requiredSlots = itemDbDetails._props.Slots.filter(slot => slot._required); const requiredSlots = itemDbDetails._props.Slots.filter((slot) => slot._required);
const hasRequiredSlots = requiredSlots.length > 0; const hasRequiredSlots = requiredSlots.length > 0;
if (hasRequiredSlots) if (hasRequiredSlots)
{ {
@ -281,7 +283,7 @@ export class FenceBaseAssortGenerator
} }
// Check for and add plate items // Check for and add plate items
const plateSlots = itemDbDetails._props.Slots.filter(slot => const plateSlots = itemDbDetails._props.Slots.filter((slot) =>
this.itemHelper.isRemovablePlateSlot(slot._name), this.itemHelper.isRemovablePlateSlot(slot._name),
); );
if (plateSlots.length > 0) if (plateSlots.length > 0)

View File

@ -92,7 +92,7 @@ export class LocationGenerator
} }
// Add mounted weapons to output loot // Add mounted weapons to output loot
result.push(...staticWeaponsOnMapClone ?? []); result.push(...(staticWeaponsOnMapClone ?? []));
const allStaticContainersOnMapClone = this.cloner.clone(mapData.staticContainers.staticContainers); const allStaticContainersOnMapClone = this.cloner.clone(mapData.staticContainers.staticContainers);
@ -137,8 +137,10 @@ export class LocationGenerator
// Randomisation is turned off globally or just turned off for this map // Randomisation is turned off globally or just turned off for this map
if ( if (
!(this.locationConfig.containerRandomisationSettings.enabled !(
&& this.locationConfig.containerRandomisationSettings.maps[locationId]) this.locationConfig.containerRandomisationSettings.enabled
&& this.locationConfig.containerRandomisationSettings.maps[locationId]
)
) )
{ {
this.logger.debug( this.logger.debug(
@ -221,15 +223,13 @@ export class LocationGenerator
for (const chosenContainerId of chosenContainerIds) for (const chosenContainerId of chosenContainerIds)
{ {
// Look up container object from full list of containers on map // Look up container object from full list of containers on map
const containerObject = staticRandomisableContainersOnMap.find(staticContainer => const containerObject = staticRandomisableContainersOnMap.find(
staticContainer.template.Id === chosenContainerId, (staticContainer) => staticContainer.template.Id === chosenContainerId,
); );
if (!containerObject) if (!containerObject)
{ {
this.logger.debug( this.logger.debug(
`Container: ${ `Container: ${chosenContainerIds[chosenContainerId]} not found in staticRandomisableContainersOnMap, this is bad`,
chosenContainerIds[chosenContainerId]
} not found in staticRandomisableContainersOnMap, this is bad`,
); );
continue; continue;
} }
@ -265,11 +265,13 @@ export class LocationGenerator
*/ */
protected getRandomisableContainersOnMap(staticContainers: IStaticContainerData[]): IStaticContainerData[] protected getRandomisableContainersOnMap(staticContainers: IStaticContainerData[]): IStaticContainerData[]
{ {
return staticContainers.filter(staticContainer => return staticContainers.filter(
staticContainer.probability !== 1 && !staticContainer.template.IsAlwaysSpawn (staticContainer) =>
&& !this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes( staticContainer.probability !== 1
staticContainer.template.Items[0]._tpl, && !staticContainer.template.IsAlwaysSpawn
), && !this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes(
staticContainer.template.Items[0]._tpl,
),
); );
} }
@ -280,11 +282,13 @@ export class LocationGenerator
*/ */
protected getGuaranteedContainers(staticContainersOnMap: IStaticContainerData[]): IStaticContainerData[] protected getGuaranteedContainers(staticContainersOnMap: IStaticContainerData[]): IStaticContainerData[]
{ {
return staticContainersOnMap.filter(staticContainer => return staticContainersOnMap.filter(
staticContainer.probability === 1 || staticContainer.template.IsAlwaysSpawn (staticContainer) =>
|| this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes( staticContainer.probability === 1
staticContainer.template.Items[0]._tpl, || staticContainer.template.IsAlwaysSpawn
), || this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes(
staticContainer.template.Items[0]._tpl,
),
); );
} }
@ -415,9 +419,9 @@ export class LocationGenerator
const containerLootPool = this.getPossibleLootItemsForContainer(containerTpl, staticLootDist); const containerLootPool = this.getPossibleLootItemsForContainer(containerTpl, staticLootDist);
// Some containers need to have items forced into it (quest keys etc) // Some containers need to have items forced into it (quest keys etc)
const tplsForced = staticForced.filter(forcedStaticProp => const tplsForced = staticForced
forcedStaticProp.containerId === containerClone.template.Id, .filter((forcedStaticProp) => forcedStaticProp.containerId === containerClone.template.Id)
).map(x => x.itemTpl); .map((x) => x.itemTpl);
// Draw random loot // Draw random loot
// Money spawn more than once in container // Money spawn more than once in container
@ -426,11 +430,9 @@ export class LocationGenerator
// Choose items to add to container, factor in weighting + lock money down // Choose items to add to container, factor in weighting + lock money down
// Filter out items picked that're already in the above `tplsForced` array // Filter out items picked that're already in the above `tplsForced` array
const chosenTpls = containerLootPool.draw( const chosenTpls = containerLootPool
itemCountToAdd, .draw(itemCountToAdd, this.locationConfig.allowDuplicateItemsInStaticContainers, locklist)
this.locationConfig.allowDuplicateItemsInStaticContainers, .filter((tpl) => !tplsForced.includes(tpl));
locklist,
).filter(tpl => !tplsForced.includes(tpl));
// Add forced loot to chosen item pool // Add forced loot to chosen item pool
const tplsToAddToContainer = tplsForced.concat(chosenTpls); const tplsToAddToContainer = tplsForced.concat(chosenTpls);
@ -495,7 +497,9 @@ export class LocationGenerator
const width = containerTemplate._props.Grids[0]._props.cellsH; const width = containerTemplate._props.Grids[0]._props.cellsH;
// Calcualte 2d array and return // Calcualte 2d array and return
return Array(height).fill(0).map(() => Array(width).fill(0)); return Array(height)
.fill(0)
.map(() => Array(width).fill(0));
} }
/** /**
@ -600,7 +604,7 @@ export class LocationGenerator
// Build the list of forced loot from both `spawnpointsForced` and any point marked `IsAlwaysSpawn` // Build the list of forced loot from both `spawnpointsForced` and any point marked `IsAlwaysSpawn`
dynamicForcedSpawnPoints.push(...dynamicLootDist.spawnpointsForced); dynamicForcedSpawnPoints.push(...dynamicLootDist.spawnpointsForced);
dynamicForcedSpawnPoints.push(...dynamicLootDist.spawnpoints.filter(point => point.template.IsAlwaysSpawn)); dynamicForcedSpawnPoints.push(...dynamicLootDist.spawnpoints.filter((point) => point.template.IsAlwaysSpawn));
// Add forced loot // Add forced loot
this.addForcedLoot(loot, dynamicForcedSpawnPoints, locationName); this.addForcedLoot(loot, dynamicForcedSpawnPoints, locationName);
@ -663,7 +667,7 @@ export class LocationGenerator
// Filter out duplicate locationIds // Filter out duplicate locationIds
chosenSpawnpoints = [ chosenSpawnpoints = [
...new Map(chosenSpawnpoints.map(spawnPoint => [spawnPoint.locationId, spawnPoint])).values(), ...new Map(chosenSpawnpoints.map((spawnPoint) => [spawnPoint.locationId, spawnPoint])).values(),
]; ];
// Do we have enough items in pool to fulfill requirement // Do we have enough items in pool to fulfill requirement
@ -706,8 +710,9 @@ export class LocationGenerator
for (const itemDist of spawnPoint.itemDistribution) for (const itemDist of spawnPoint.itemDistribution)
{ {
if ( if (
!seasonalEventActive && seasonalItemTplBlacklist.includes( !seasonalEventActive
spawnPoint.template.Items.find(item => item._id === itemDist.composedKey.key)._tpl, && seasonalItemTplBlacklist.includes(
spawnPoint.template.Items.find((item) => item._id === itemDist.composedKey.key)._tpl,
) )
) )
{ {
@ -758,8 +763,8 @@ export class LocationGenerator
for (const itemTpl of lootToForceSingleAmountOnMap) for (const itemTpl of lootToForceSingleAmountOnMap)
{ {
// Get all spawn positions for item tpl in forced loot array // Get all spawn positions for item tpl in forced loot array
const items = forcedSpawnPoints.filter(forcedSpawnPoint => const items = forcedSpawnPoints.filter(
forcedSpawnPoint.template.Items[0]._tpl === itemTpl, (forcedSpawnPoint) => forcedSpawnPoint.template.Items[0]._tpl === itemTpl,
); );
if (!items || items.length === 0) if (!items || items.length === 0)
{ {
@ -783,7 +788,7 @@ export class LocationGenerator
// Choose 1 out of all found spawn positions for spawn id and add to loot array // Choose 1 out of all found spawn positions for spawn id and add to loot array
for (const spawnPointLocationId of spawnpointArray.draw(1, false)) for (const spawnPointLocationId of spawnpointArray.draw(1, false))
{ {
const itemToAdd = items.find(item => item.locationId === spawnPointLocationId); const itemToAdd = items.find((item) => item.locationId === spawnPointLocationId);
const lootItem = itemToAdd.template; const lootItem = itemToAdd.template;
lootItem.Root = this.objectId.generate(); lootItem.Root = this.objectId.generate();
lootItem.Items[0]._id = lootItem.Root; lootItem.Items[0]._id = lootItem.Root;
@ -819,8 +824,8 @@ export class LocationGenerator
locationTemplateToAdd.Items[0]._id = locationTemplateToAdd.Root; locationTemplateToAdd.Items[0]._id = locationTemplateToAdd.Root;
// Push forced location into array as long as it doesnt exist already // Push forced location into array as long as it doesnt exist already
const existingLocation = lootLocationTemplates.find(spawnPoint => const existingLocation = lootLocationTemplates.find(
spawnPoint.Id === locationTemplateToAdd.Id, (spawnPoint) => spawnPoint.Id === locationTemplateToAdd.Id,
); );
if (!existingLocation) if (!existingLocation)
{ {
@ -848,7 +853,7 @@ export class LocationGenerator
staticAmmoDist: Record<string, IStaticAmmoDetails[]>, staticAmmoDist: Record<string, IStaticAmmoDetails[]>,
): IContainerItem ): IContainerItem
{ {
const chosenItem = spawnPoint.template.Items.find(item => item._id === chosenComposedKey); const chosenItem = spawnPoint.template.Items.find((item) => item._id === chosenComposedKey);
const chosenTpl = chosenItem._tpl; const chosenTpl = chosenItem._tpl;
const itemTemplate = this.itemHelper.getItem(chosenTpl)[1]; const itemTemplate = this.itemHelper.getItem(chosenTpl)[1];
@ -858,9 +863,10 @@ export class LocationGenerator
// Money/Ammo - don't rely on items in spawnPoint.template.Items so we can randomise it ourselves // Money/Ammo - don't rely on items in spawnPoint.template.Items so we can randomise it ourselves
if (this.itemHelper.isOfBaseclasses(chosenTpl, [BaseClasses.MONEY, BaseClasses.AMMO])) if (this.itemHelper.isOfBaseclasses(chosenTpl, [BaseClasses.MONEY, BaseClasses.AMMO]))
{ {
const stackCount = itemTemplate._props.StackMaxSize === 1 const stackCount
? 1 = itemTemplate._props.StackMaxSize === 1
: this.randomUtil.getInt(itemTemplate._props.StackMinRandom, itemTemplate._props.StackMaxRandom); ? 1
: this.randomUtil.getInt(itemTemplate._props.StackMinRandom, itemTemplate._props.StackMaxRandom);
itemWithMods.push({ itemWithMods.push({
_id: this.objectId.generate(), _id: this.objectId.generate(),
@ -948,10 +954,10 @@ export class LocationGenerator
{ {
if (this.itemHelper.isOfBaseclass(chosenTpl, BaseClasses.WEAPON)) if (this.itemHelper.isOfBaseclass(chosenTpl, BaseClasses.WEAPON))
{ {
return items.find(v => v._tpl === chosenTpl && v.parentId === undefined); return items.find((v) => v._tpl === chosenTpl && v.parentId === undefined);
} }
return items.find(item => item._tpl === chosenTpl); return items.find((item) => item._tpl === chosenTpl);
} }
// TODO: rewrite, BIG yikes // TODO: rewrite, BIG yikes
@ -979,9 +985,10 @@ export class LocationGenerator
) )
{ {
// Edge case - some ammos e.g. flares or M406 grenades shouldn't be stacked // Edge case - some ammos e.g. flares or M406 grenades shouldn't be stacked
const stackCount = itemTemplate._props.StackMaxSize === 1 const stackCount
? 1 = itemTemplate._props.StackMaxSize === 1
: this.randomUtil.getInt(itemTemplate._props.StackMinRandom, itemTemplate._props.StackMaxRandom); ? 1
: this.randomUtil.getInt(itemTemplate._props.StackMinRandom, itemTemplate._props.StackMaxRandom);
rootItem.upd = { StackObjectsCount: stackCount }; rootItem.upd = { StackObjectsCount: stackCount };
} }
@ -1055,7 +1062,7 @@ export class LocationGenerator
// it can handle revolver ammo (it's not restructured to be used here yet.) // it can handle revolver ammo (it's not restructured to be used here yet.)
// General: Make a WeaponController for Ragfair preset stuff and the generating weapons and ammo stuff from // General: Make a WeaponController for Ragfair preset stuff and the generating weapons and ammo stuff from
// BotGenerator // BotGenerator
const magazine = items.filter(item => item.slotId === "mod_magazine")[0]; const magazine = items.filter((item) => item.slotId === "mod_magazine")[0];
// some weapon presets come without magazine; only fill the mag if it exists // some weapon presets come without magazine; only fill the mag if it exists
if (magazine) if (magazine)
{ {

View File

@ -6,7 +6,6 @@ import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
import { IPreset } from "@spt-aki/models/eft/common/IGlobals"; import { IPreset } from "@spt-aki/models/eft/common/IGlobals";
import { Item } from "@spt-aki/models/eft/common/tables/IItem"; import { Item } from "@spt-aki/models/eft/common/tables/IItem";
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem"; import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
import { AddItem } from "@spt-aki/models/eft/inventory/IAddItemRequestData";
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses"; import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
import { ISealedAirdropContainerSettings, RewardDetails } from "@spt-aki/models/spt/config/IInventoryConfig"; import { ISealedAirdropContainerSettings, RewardDetails } from "@spt-aki/models/spt/config/IInventoryConfig";
import { LootItem } from "@spt-aki/models/spt/services/LootItem"; import { LootItem } from "@spt-aki/models/spt/services/LootItem";
@ -71,7 +70,7 @@ export class LootGenerator
if (desiredWeaponCrateCount > 0) if (desiredWeaponCrateCount > 0)
{ {
// Get list of all sealed containers from db // Get list of all sealed containers from db
const sealedWeaponContainerPool = Object.values(tables.templates.items).filter(x => const sealedWeaponContainerPool = Object.values(tables.templates.items).filter((x) =>
x._name.includes("event_container_airdrop"), x._name.includes("event_container_airdrop"),
); );
@ -89,11 +88,12 @@ export class LootGenerator
} }
// Get items from items.json that have a type of item + not in global blacklist + basetype is in whitelist // Get items from items.json that have a type of item + not in global blacklist + basetype is in whitelist
const items = Object.entries(tables.templates.items).filter(x => const items = Object.entries(tables.templates.items).filter(
!itemBlacklist.has(x[1]._id) (x) =>
&& x[1]._type.toLowerCase() === "item" !itemBlacklist.has(x[1]._id)
&& !x[1]._props.QuestItem && x[1]._type.toLowerCase() === "item"
&& options.itemTypeWhitelist.includes(x[1]._parent), && !x[1]._props.QuestItem
&& options.itemTypeWhitelist.includes(x[1]._parent),
); );
if (items.length > 0) if (items.length > 0)
@ -119,7 +119,7 @@ export class LootGenerator
); );
if (randomisedWeaponPresetCount > 0) if (randomisedWeaponPresetCount > 0)
{ {
const weaponDefaultPresets = globalDefaultPresets.filter(preset => const weaponDefaultPresets = globalDefaultPresets.filter((preset) =>
this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON), this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON),
); );
@ -150,10 +150,10 @@ export class LootGenerator
); );
if (randomisedArmorPresetCount > 0) if (randomisedArmorPresetCount > 0)
{ {
const armorDefaultPresets = globalDefaultPresets.filter(preset => const armorDefaultPresets = globalDefaultPresets.filter((preset) =>
this.itemHelper.armorItemCanHoldMods(preset._encyclopedia), this.itemHelper.armorItemCanHoldMods(preset._encyclopedia),
); );
const levelFilteredArmorPresets = armorDefaultPresets.filter(armor => const levelFilteredArmorPresets = armorDefaultPresets.filter((armor) =>
this.armorIsDesiredProtectionLevel(armor, options), this.armorIsDesiredProtectionLevel(armor, options),
); );
@ -189,21 +189,21 @@ export class LootGenerator
*/ */
protected armorIsDesiredProtectionLevel(armor: IPreset, options: LootRequest): boolean protected armorIsDesiredProtectionLevel(armor: IPreset, options: LootRequest): boolean
{ {
const frontPlate = armor._items.find(mod => mod?.slotId?.toLowerCase() === "front_plate"); const frontPlate = armor._items.find((mod) => mod?.slotId?.toLowerCase() === "front_plate");
if (frontPlate) if (frontPlate)
{ {
const plateDb = this.itemHelper.getItem(frontPlate._tpl); const plateDb = this.itemHelper.getItem(frontPlate._tpl);
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any)); return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
} }
const helmetTop = armor._items.find(mod => mod?.slotId?.toLowerCase() === "helmet_top"); const helmetTop = armor._items.find((mod) => mod?.slotId?.toLowerCase() === "helmet_top");
if (helmetTop) if (helmetTop)
{ {
const plateDb = this.itemHelper.getItem(helmetTop._tpl); const plateDb = this.itemHelper.getItem(helmetTop._tpl);
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any)); return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
} }
const softArmorFront = armor._items.find(mod => mod?.slotId?.toLowerCase() === "soft_armor_front"); const softArmorFront = armor._items.find((mod) => mod?.slotId?.toLowerCase() === "soft_armor_front");
if (softArmorFront) if (softArmorFront)
{ {
const plateDb = this.itemHelper.getItem(softArmorFront._tpl); const plateDb = this.itemHelper.getItem(softArmorFront._tpl);
@ -470,7 +470,7 @@ export class LootGenerator
// Need to find boxes that matches weapons caliber // Need to find boxes that matches weapons caliber
const weaponCaliber = weaponDetailsDb._props.ammoCaliber; const weaponCaliber = weaponDetailsDb._props.ammoCaliber;
const ammoBoxesMatchingCaliber = ammoBoxesDetails.filter(x => x._props.ammoCaliber === weaponCaliber); const ammoBoxesMatchingCaliber = ammoBoxesDetails.filter((x) => x._props.ammoCaliber === weaponCaliber);
if (ammoBoxesMatchingCaliber.length === 0) if (ammoBoxesMatchingCaliber.length === 0)
{ {
this.logger.debug(`No ammo box with caliber ${weaponCaliber} found, skipping`); this.logger.debug(`No ammo box with caliber ${weaponCaliber} found, skipping`);
@ -490,12 +490,13 @@ export class LootGenerator
} }
// Get all items of the desired type + not quest items + not globally blacklisted // Get all items of the desired type + not quest items + not globally blacklisted
const rewardItemPool = Object.values(this.databaseServer.getTables().templates.items).filter(x => const rewardItemPool = Object.values(this.databaseServer.getTables().templates.items).filter(
x._parent === rewardTypeId (x) =>
&& x._type.toLowerCase() === "item" x._parent === rewardTypeId
&& !this.itemFilterService.isItemBlacklisted(x._id) && x._type.toLowerCase() === "item"
&& !(containerSettings.allowBossItems || this.itemFilterService.isBossItem(x._id)) && !this.itemFilterService.isItemBlacklisted(x._id)
&& !x._props.QuestItem, && !(containerSettings.allowBossItems || this.itemFilterService.isBossItem(x._id))
&& !x._props.QuestItem,
); );
if (rewardItemPool.length === 0) if (rewardItemPool.length === 0)
@ -544,8 +545,8 @@ export class LootGenerator
} }
// Get items that fulfil reward type criteria from items that fit on gun // Get items that fulfil reward type criteria from items that fit on gun
const relatedItems = linkedItemsToWeapon.filter(x => const relatedItems = linkedItemsToWeapon.filter(
x._parent === rewardTypeId && !this.itemFilterService.isItemBlacklisted(x._id), (x) => x._parent === rewardTypeId && !this.itemFilterService.isItemBlacklisted(x._id),
); );
if (!relatedItems || relatedItems.length === 0) if (!relatedItems || relatedItems.length === 0)
{ {

View File

@ -58,13 +58,14 @@ export class PMCLootGenerator
// Blacklist inactive seasonal items // Blacklist inactive seasonal items
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems()); itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
const itemsToAdd = Object.values(items).filter(item => const itemsToAdd = Object.values(items).filter(
allowedItemTypes.includes(item._parent) (item) =>
&& this.itemHelper.isValidItem(item._id) allowedItemTypes.includes(item._parent)
&& !pmcItemBlacklist.includes(item._id) && this.itemHelper.isValidItem(item._id)
&& !itemBlacklist.includes(item._id) && !pmcItemBlacklist.includes(item._id)
&& item._props.Width === 1 && !itemBlacklist.includes(item._id)
&& item._props.Height === 1, && item._props.Width === 1
&& item._props.Height === 1,
); );
for (const itemToAdd of itemsToAdd) for (const itemToAdd of itemsToAdd)
@ -87,7 +88,7 @@ export class PMCLootGenerator
{ {
// Invert price so cheapest has a larger weight // Invert price so cheapest has a larger weight
// Times by highest price so most expensive item has weight of 1 // Times by highest price so most expensive item has weight of 1
this.pocketLootPool[key] = Math.round(1 / this.pocketLootPool[key] * highestPrice); this.pocketLootPool[key] = Math.round((1 / this.pocketLootPool[key]) * highestPrice);
} }
this.weightedRandomHelper.reduceWeightValues(this.pocketLootPool); this.weightedRandomHelper.reduceWeightValues(this.pocketLootPool);
@ -117,12 +118,13 @@ export class PMCLootGenerator
// Blacklist seasonal items // Blacklist seasonal items
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems()); itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
const itemsToAdd = Object.values(items).filter(item => const itemsToAdd = Object.values(items).filter(
allowedItemTypes.includes(item._parent) (item) =>
&& this.itemHelper.isValidItem(item._id) allowedItemTypes.includes(item._parent)
&& !pmcItemBlacklist.includes(item._id) && this.itemHelper.isValidItem(item._id)
&& !itemBlacklist.includes(item._id) && !pmcItemBlacklist.includes(item._id)
&& this.itemFitsInto2By2Slot(item), && !itemBlacklist.includes(item._id)
&& this.itemFitsInto2By2Slot(item),
); );
for (const itemToAdd of itemsToAdd) for (const itemToAdd of itemsToAdd)
@ -145,7 +147,7 @@ export class PMCLootGenerator
{ {
// Invert price so cheapest has a larger weight // Invert price so cheapest has a larger weight
// Times by highest price so most expensive item has weight of 1 // Times by highest price so most expensive item has weight of 1
this.vestLootPool[key] = Math.round(1 / this.vestLootPool[key] * highestPrice); this.vestLootPool[key] = Math.round((1 / this.vestLootPool[key]) * highestPrice);
} }
this.weightedRandomHelper.reduceWeightValues(this.vestLootPool); this.weightedRandomHelper.reduceWeightValues(this.vestLootPool);
@ -186,11 +188,12 @@ export class PMCLootGenerator
// Blacklist seasonal items // Blacklist seasonal items
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems()); itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
const itemsToAdd = Object.values(items).filter(item => const itemsToAdd = Object.values(items).filter(
allowedItemTypes.includes(item._parent) (item) =>
&& this.itemHelper.isValidItem(item._id) allowedItemTypes.includes(item._parent)
&& !pmcItemBlacklist.includes(item._id) && this.itemHelper.isValidItem(item._id)
&& !itemBlacklist.includes(item._id), && !pmcItemBlacklist.includes(item._id)
&& !itemBlacklist.includes(item._id),
); );
for (const itemToAdd of itemsToAdd) for (const itemToAdd of itemsToAdd)
@ -213,7 +216,7 @@ export class PMCLootGenerator
{ {
// Invert price so cheapest has a larger weight // Invert price so cheapest has a larger weight
// Times by highest price so most expensive item has weight of 1 // Times by highest price so most expensive item has weight of 1
this.backpackLootPool[key] = Math.round(1 / this.backpackLootPool[key] * highestPrice); this.backpackLootPool[key] = Math.round((1 / this.backpackLootPool[key]) * highestPrice);
} }
this.weightedRandomHelper.reduceWeightValues(this.backpackLootPool); this.weightedRandomHelper.reduceWeightValues(this.backpackLootPool);

View File

@ -162,11 +162,13 @@ export class PlayerScavGenerator
} }
const itemTemplate = itemResult[1]; const itemTemplate = itemResult[1];
const itemsToAdd: Item[] = [{ const itemsToAdd: Item[] = [
_id: this.hashUtil.generate(), {
_tpl: itemTemplate._id, _id: this.hashUtil.generate(),
...this.botGeneratorHelper.generateExtraPropertiesForItem(itemTemplate), _tpl: itemTemplate._id,
}]; ...this.botGeneratorHelper.generateExtraPropertiesForItem(itemTemplate),
},
];
const result = this.botGeneratorHelper.addItemWithChildrenToEquipmentSlot( const result = this.botGeneratorHelper.addItemWithChildrenToEquipmentSlot(
containersToAddTo, containersToAddTo,

View File

@ -72,7 +72,7 @@ export class RagfairAssortGenerator
const results: Item[][] = []; const results: Item[][] = [];
/** Get cloned items from db */ /** Get cloned items from db */
const dbItemsClone = this.itemHelper.getItems().filter(item => item._type !== "Node"); const dbItemsClone = this.itemHelper.getItems().filter((item) => item._type !== "Node");
/** Store processed preset tpls so we dont add them when procesing non-preset items */ /** Store processed preset tpls so we dont add them when procesing non-preset items */
const processedArmorItems: string[] = []; const processedArmorItems: string[] = [];
@ -105,7 +105,8 @@ export class RagfairAssortGenerator
// Skip seasonal items when not in-season // Skip seasonal items when not in-season
if ( if (
this.ragfairConfig.dynamic.removeSeasonalItemsWhenNotInEvent && !seasonalEventActive this.ragfairConfig.dynamic.removeSeasonalItemsWhenNotInEvent
&& !seasonalEventActive
&& seasonalItemTplBlacklist.includes(item._id) && seasonalItemTplBlacklist.includes(item._id)
) )
{ {

View File

@ -135,7 +135,7 @@ export class RagfairOfferGenerator
} }
} }
const itemCount = items.filter(x => x.slotId === "hideout").length; const itemCount = items.filter((x) => x.slotId === "hideout").length;
const roublePrice = Math.round(this.convertOfferRequirementsIntoRoubles(offerRequirements)); const roublePrice = Math.round(this.convertOfferRequirementsIntoRoubles(offerRequirements));
const offer: IRagfairOffer = { const offer: IRagfairOffer = {
@ -143,9 +143,8 @@ export class RagfairOfferGenerator
intId: this.offerCounter, intId: this.offerCounter,
user: { user: {
id: this.getTraderId(userID), id: this.getTraderId(userID),
memberType: userID === "ragfair" memberType:
? MemberCategory.DEFAULT userID === "ragfair" ? MemberCategory.DEFAULT : this.ragfairServerHelper.getMemberType(userID),
: this.ragfairServerHelper.getMemberType(userID),
nickname: this.ragfairServerHelper.getNickname(userID), nickname: this.ragfairServerHelper.getNickname(userID),
rating: this.getRating(userID), rating: this.getRating(userID),
isRatingGrowing: this.getRatingGrowing(userID), isRatingGrowing: this.getRatingGrowing(userID),
@ -410,7 +409,7 @@ export class RagfairOfferGenerator
return false; return false;
} }
const plateSlots = presetWithChildren.filter(item => const plateSlots = presetWithChildren.filter((item) =>
this.itemHelper.getRemovablePlateSlotIds().includes(item.slotId?.toLowerCase()), this.itemHelper.getRemovablePlateSlotIds().includes(item.slotId?.toLowerCase()),
); );
if (plateSlots.length === 0) if (plateSlots.length === 0)
@ -459,13 +458,14 @@ export class RagfairOfferGenerator
); );
const isBarterOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.barter.chancePercent); const isBarterOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.barter.chancePercent);
const isPackOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.pack.chancePercent) const isPackOffer
&& !isBarterOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.pack.chancePercent)
&& itemWithChildren.length === 1 && !isBarterOffer
&& this.itemHelper.isOfBaseclasses( && itemWithChildren.length === 1
itemWithChildren[0]._tpl, && this.itemHelper.isOfBaseclasses(
this.ragfairConfig.dynamic.pack.itemTypeWhitelist, itemWithChildren[0]._tpl,
); this.ragfairConfig.dynamic.pack.itemTypeWhitelist,
);
const randomUserId = this.hashUtil.generate(); const randomUserId = this.hashUtil.generate();
@ -477,7 +477,7 @@ export class RagfairOfferGenerator
const shouldRemovePlates = this.randomUtil.getChance100(armorConfig.removeRemovablePlateChance); const shouldRemovePlates = this.randomUtil.getChance100(armorConfig.removeRemovablePlateChance);
if (shouldRemovePlates && this.itemHelper.armorItemHasRemovablePlateSlots(itemWithChildren[0]._tpl)) if (shouldRemovePlates && this.itemHelper.armorItemHasRemovablePlateSlots(itemWithChildren[0]._tpl))
{ {
const offerItemPlatesToRemove = itemWithChildren.filter(item => const offerItemPlatesToRemove = itemWithChildren.filter((item) =>
armorConfig.plateSlotIdToRemovePool.includes(item.slotId?.toLowerCase()), armorConfig.plateSlotIdToRemovePool.includes(item.slotId?.toLowerCase()),
); );
@ -683,8 +683,8 @@ export class RagfairOfferGenerator
this.randomiseArmorDurabilityValues(itemWithMods, currentMultiplier, maxMultiplier); this.randomiseArmorDurabilityValues(itemWithMods, currentMultiplier, maxMultiplier);
// Add hits to visor // Add hits to visor
const visorMod = itemWithMods.find(item => const visorMod = itemWithMods.find(
item.parentId === BaseClasses.ARMORED_EQUIPMENT && item.slotId === "mod_equipment_000", (item) => item.parentId === BaseClasses.ARMORED_EQUIPMENT && item.slotId === "mod_equipment_000",
); );
if (this.randomUtil.getChance100(25) && visorMod) if (this.randomUtil.getChance100(25) && visorMod)
{ {
@ -715,8 +715,8 @@ export class RagfairOfferGenerator
if (rootItem.upd.Key && itemDetails._props.MaximumNumberOfUsage > 1) if (rootItem.upd.Key && itemDetails._props.MaximumNumberOfUsage > 1)
{ {
// randomize key uses // randomize key uses
rootItem.upd.Key.NumberOfUsages = Math.round(itemDetails._props.MaximumNumberOfUsage * (1 - maxMultiplier)) rootItem.upd.Key.NumberOfUsages
|| 0; = Math.round(itemDetails._props.MaximumNumberOfUsage * (1 - maxMultiplier)) || 0;
return; return;
} }
@ -792,8 +792,8 @@ export class RagfairOfferGenerator
{ {
this.itemHelper.addUpdObjectToItem(armorItem); this.itemHelper.addUpdObjectToItem(armorItem);
const lowestMaxDurability = this.randomUtil.getFloat(maxMultiplier, 1) const lowestMaxDurability
* itemDbDetails._props.MaxDurability; = this.randomUtil.getFloat(maxMultiplier, 1) * itemDbDetails._props.MaxDurability;
const chosenMaxDurability = Math.round( const chosenMaxDurability = Math.round(
this.randomUtil.getFloat(lowestMaxDurability, itemDbDetails._props.MaxDurability), this.randomUtil.getFloat(lowestMaxDurability, itemDbDetails._props.MaxDurability),
); );
@ -882,14 +882,16 @@ export class RagfairOfferGenerator
const desiredItemCost = Math.round(priceOfItemOffer / barterItemCount); const desiredItemCost = Math.round(priceOfItemOffer / barterItemCount);
// amount to go above/below when looking for an item (Wiggle cost of item a little) // amount to go above/below when looking for an item (Wiggle cost of item a little)
const offerCostVariance = desiredItemCost * this.ragfairConfig.dynamic.barter.priceRangeVariancePercent / 100; const offerCostVariance = (desiredItemCost * this.ragfairConfig.dynamic.barter.priceRangeVariancePercent) / 100;
const fleaPrices = this.getFleaPricesAsArray(); const fleaPrices = this.getFleaPricesAsArray();
// Filter possible barters to items that match the price range + not itself // Filter possible barters to items that match the price range + not itself
const filtered = fleaPrices.filter(x => const filtered = fleaPrices.filter(
x.price >= desiredItemCost - offerCostVariance && x.price <= desiredItemCost + offerCostVariance (x) =>
&& x.tpl !== offerItems[0]._tpl, x.price >= desiredItemCost - offerCostVariance
&& x.price <= desiredItemCost + offerCostVariance
&& x.tpl !== offerItems[0]._tpl,
); );
// No items on flea have a matching price, fall back to currency // No items on flea have a matching price, fall back to currency
@ -917,10 +919,10 @@ export class RagfairOfferGenerator
const fleaArray = Object.entries(fleaPrices).map(([tpl, price]) => ({ tpl: tpl, price: price })); const fleaArray = Object.entries(fleaPrices).map(([tpl, price]) => ({ tpl: tpl, price: price }));
// Only get item prices for items that also exist in items.json // Only get item prices for items that also exist in items.json
const filteredItems = fleaArray.filter(x => this.itemHelper.getItem(x.tpl)[0]); const filteredItems = fleaArray.filter((x) => this.itemHelper.getItem(x.tpl)[0]);
this.allowedFleaPriceItemsForBarter = filteredItems.filter(x => this.allowedFleaPriceItemsForBarter = filteredItems.filter(
!this.itemHelper.isOfBaseclasses(x.tpl, this.ragfairConfig.dynamic.barter.itemTypeBlacklist), (x) => !this.itemHelper.isOfBaseclasses(x.tpl, this.ragfairConfig.dynamic.barter.itemTypeBlacklist),
); );
} }
@ -941,8 +943,8 @@ export class RagfairOfferGenerator
): IBarterScheme[] ): IBarterScheme[]
{ {
const currency = this.ragfairServerHelper.getDynamicOfferCurrency(); const currency = this.ragfairServerHelper.getDynamicOfferCurrency();
const price = this.ragfairPriceService.getDynamicOfferPriceForOffer(offerWithChildren, currency, isPackOffer) const price
* multipler; = this.ragfairPriceService.getDynamicOfferPriceForOffer(offerWithChildren, currency, isPackOffer) * multipler;
return [{ count: price, _tpl: currency }]; return [{ count: price, _tpl: currency }];
} }

View File

@ -39,8 +39,8 @@ export class RepeatableQuestGenerator
@inject("LocalisationService") protected localisationService: LocalisationService, @inject("LocalisationService") protected localisationService: LocalisationService,
@inject("ObjectId") protected objectId: ObjectId, @inject("ObjectId") protected objectId: ObjectId,
@inject("RepeatableQuestHelper") protected repeatableQuestHelper: RepeatableQuestHelper, @inject("RepeatableQuestHelper") protected repeatableQuestHelper: RepeatableQuestHelper,
@inject("RepeatableQuestRewardGenerator") protected repeatableQuestRewardGenerator: @inject("RepeatableQuestRewardGenerator")
RepeatableQuestRewardGenerator, protected repeatableQuestRewardGenerator: RepeatableQuestRewardGenerator,
@inject("ConfigServer") protected configServer: ConfigServer, @inject("ConfigServer") protected configServer: ConfigServer,
@inject("RecursiveCloner") protected cloner: ICloner, @inject("RecursiveCloner") protected cloner: ICloner,
) )
@ -67,11 +67,11 @@ export class RepeatableQuestGenerator
const questType = this.randomUtil.drawRandomFromList<string>(questTypePool.types)[0]; const questType = this.randomUtil.drawRandomFromList<string>(questTypePool.types)[0];
// get traders from whitelist and filter by quest type availability // get traders from whitelist and filter by quest type availability
let traders = repeatableConfig.traderWhitelist.filter(x => x.questTypes.includes(questType)).map(x => let traders = repeatableConfig.traderWhitelist
x.traderId, .filter((x) => x.questTypes.includes(questType))
); .map((x) => x.traderId);
// filter out locked traders // filter out locked traders
traders = traders.filter(x => pmcTraderInfo[x].unlocked); traders = traders.filter((x) => pmcTraderInfo[x].unlocked);
const traderId = this.randomUtil.drawRandomFromList(traders)[0]; const traderId = this.randomUtil.drawRandomFromList(traders)[0];
switch (questType) switch (questType)
@ -158,15 +158,15 @@ export class RepeatableQuestGenerator
return Math.sqrt(Math.sqrt(target) + bodyPart + dist + weaponRequirement) * kill; return Math.sqrt(Math.sqrt(target) + bodyPart + dist + weaponRequirement) * kill;
} }
targetsConfig = targetsConfig.filter(x => targetsConfig = targetsConfig.filter((x) =>
Object.keys(questTypePool.pool.Elimination.targets).includes(x.key), Object.keys(questTypePool.pool.Elimination.targets).includes(x.key),
); );
if (targetsConfig.length === 0 || targetsConfig.every(x => x.data.isBoss)) if (targetsConfig.length === 0 || targetsConfig.every((x) => x.data.isBoss))
{ {
// There are no more targets left for elimination; delete it as a possible quest type // There are no more targets left for elimination; delete it as a possible quest type
// also if only bosses are left we need to leave otherwise it's a guaranteed boss elimination // also if only bosses are left we need to leave otherwise it's a guaranteed boss elimination
// -> then it would not be a quest with low probability anymore // -> then it would not be a quest with low probability anymore
questTypePool.types = questTypePool.types.filter(t => t !== "Elimination"); questTypePool.types = questTypePool.types.filter((t) => t !== "Elimination");
return null; return null;
} }
@ -188,12 +188,12 @@ export class RepeatableQuestGenerator
} }
else else
{ {
locations = locations.filter(l => l !== "any"); locations = locations.filter((l) => l !== "any");
if (locations.length > 0) if (locations.length > 0)
{ {
locationKey = this.randomUtil.drawRandomFromList<string>(locations)[0]; locationKey = this.randomUtil.drawRandomFromList<string>(locations)[0];
questTypePool.pool.Elimination.targets[targetKey].locations = locations.filter(l => questTypePool.pool.Elimination.targets[targetKey].locations = locations.filter(
l !== locationKey, (l) => l !== locationKey,
); );
if (questTypePool.pool.Elimination.targets[targetKey].locations.length === 0) if (questTypePool.pool.Elimination.targets[targetKey].locations.length === 0)
{ {
@ -238,16 +238,18 @@ export class RepeatableQuestGenerator
if (targetsConfig.data(targetKey).isBoss) if (targetsConfig.data(targetKey).isBoss)
{ {
// Get all boss spawn information // Get all boss spawn information
const bossSpawns = Object.values(this.databaseServer.getTables().locations).filter(x => const bossSpawns = Object.values(this.databaseServer.getTables().locations)
"base" in x && "Id" in x.base, .filter((x) => "base" in x && "Id" in x.base)
).map(x => ({ Id: x.base.Id, BossSpawn: x.base.BossLocationSpawn })); .map((x) => ({ Id: x.base.Id, BossSpawn: x.base.BossLocationSpawn }));
// filter for the current boss to spawn on map // filter for the current boss to spawn on map
const thisBossSpawns = bossSpawns.map(x => ({ const thisBossSpawns = bossSpawns
Id: x.Id, .map((x) => ({
BossSpawn: x.BossSpawn.filter(e => e.BossName === targetKey), Id: x.Id,
})).filter(x => x.BossSpawn.length > 0); BossSpawn: x.BossSpawn.filter((e) => e.BossName === targetKey),
}))
.filter((x) => x.BossSpawn.length > 0);
// remove blacklisted locations // remove blacklisted locations
const allowedSpawns = thisBossSpawns.filter(x => !eliminationConfig.distLocationBlacklist.includes(x.Id)); const allowedSpawns = thisBossSpawns.filter((x) => !eliminationConfig.distLocationBlacklist.includes(x.Id));
// if the boss spawns on nom-blacklisted locations and the current location is allowed we can generate a distance kill requirement // if the boss spawns on nom-blacklisted locations and the current location is allowed we can generate a distance kill requirement
isDistanceRequirementAllowed = isDistanceRequirementAllowed && allowedSpawns.length > 0; isDistanceRequirementAllowed = isDistanceRequirementAllowed && allowedSpawns.length > 0;
} }
@ -260,7 +262,7 @@ export class RepeatableQuestGenerator
+ eliminationConfig.minDist, + eliminationConfig.minDist,
); );
distance = Math.ceil(distance / 5) * 5; distance = Math.ceil(distance / 5) * 5;
distanceDifficulty = maxDistDifficulty * distance / eliminationConfig.maxDist; distanceDifficulty = (maxDistDifficulty * distance) / eliminationConfig.maxDist;
} }
let allowedWeaponsCategory: string = undefined; let allowedWeaponsCategory: string = undefined;
@ -269,13 +271,14 @@ export class RepeatableQuestGenerator
// Filter out close range weapons from far distance requirement // Filter out close range weapons from far distance requirement
if (distance > 50) if (distance > 50)
{ {
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter(category => weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter((category) =>
["Shotgun", "Pistol"].includes(category.key), ["Shotgun", "Pistol"].includes(category.key),
); );
} }
else if (distance < 20) else if (distance < 20)
{ // Filter out far range weapons from close distance requirement {
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter(category => // Filter out far range weapons from close distance requirement
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter((category) =>
["MarksmanRifle", "DMR"].includes(category.key), ["MarksmanRifle", "DMR"].includes(category.key),
); );
} }
@ -497,8 +500,8 @@ export class RepeatableQuestGenerator
this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig) * this.randomUtil.getFloat(0.5, 1), this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig) * this.randomUtil.getFloat(0.5, 1),
); );
roublesBudget = Math.max(roublesBudget, 5000); roublesBudget = Math.max(roublesBudget, 5000);
let itemSelection = possibleItemsToRetrievePool.filter(x => let itemSelection = possibleItemsToRetrievePool.filter(
this.itemHelper.getItemPrice(x[0]) < roublesBudget, (x) => this.itemHelper.getItemPrice(x[0]) < roublesBudget,
); );
// We also have the option to use whitelist and/or blacklist which is defined in repeatableQuests.json as // We also have the option to use whitelist and/or blacklist which is defined in repeatableQuests.json as
@ -509,15 +512,16 @@ export class RepeatableQuestGenerator
= this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsWhitelist; = this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsWhitelist;
// Filter and concatenate the arrays according to current player level // Filter and concatenate the arrays according to current player level
const itemIdsWhitelisted = itemWhitelist.filter(p => p.minPlayerLevel <= pmcLevel).reduce( const itemIdsWhitelisted = itemWhitelist
(a, p) => a.concat(p.itemIds), .filter((p) => p.minPlayerLevel <= pmcLevel)
[], .reduce((a, p) => a.concat(p.itemIds), []);
);
itemSelection = itemSelection.filter((x) => itemSelection = itemSelection.filter((x) =>
{ {
// Whitelist can contain item tpls and item base type ids // Whitelist can contain item tpls and item base type ids
return itemIdsWhitelisted.some(v => this.itemHelper.isOfBaseclass(x[0], v)) return (
|| itemIdsWhitelisted.includes(x[0]); itemIdsWhitelisted.some((v) => this.itemHelper.isOfBaseclass(x[0], v))
|| itemIdsWhitelisted.includes(x[0])
);
}); });
// check if items are missing // check if items are missing
// const flatList = itemSelection.reduce((a, il) => a.concat(il[0]), []); // const flatList = itemSelection.reduce((a, il) => a.concat(il[0]), []);
@ -530,15 +534,16 @@ export class RepeatableQuestGenerator
= this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsBlacklist; = this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsBlacklist;
// we filter and concatenate the arrays according to current player level // we filter and concatenate the arrays according to current player level
const itemIdsBlacklisted = itemBlacklist.filter(p => p.minPlayerLevel <= pmcLevel).reduce( const itemIdsBlacklisted = itemBlacklist
(a, p) => a.concat(p.itemIds), .filter((p) => p.minPlayerLevel <= pmcLevel)
[], .reduce((a, p) => a.concat(p.itemIds), []);
);
itemSelection = itemSelection.filter((x) => itemSelection = itemSelection.filter((x) =>
{ {
return itemIdsBlacklisted.every(v => !this.itemHelper.isOfBaseclass(x[0], v)) return (
|| !itemIdsBlacklisted.includes(x[0]); itemIdsBlacklisted.every((v) => !this.itemHelper.isOfBaseclass(x[0], v))
|| !itemIdsBlacklisted.includes(x[0])
);
}); });
} }
@ -601,7 +606,7 @@ export class RepeatableQuestGenerator
if (roublesBudget > 0) if (roublesBudget > 0)
{ {
// reduce the list possible items to fulfill the new budget constraint // reduce the list possible items to fulfill the new budget constraint
itemSelection = itemSelection.filter(x => this.itemHelper.getItemPrice(x[0]) < roublesBudget); itemSelection = itemSelection.filter((x) => this.itemHelper.getItemPrice(x[0]) < roublesBudget);
if (itemSelection.length === 0) if (itemSelection.length === 0)
{ {
break; break;
@ -692,7 +697,7 @@ export class RepeatableQuestGenerator
if (Object.keys(questTypePool.pool.Exploration.locations).length === 0) if (Object.keys(questTypePool.pool.Exploration.locations).length === 0)
{ {
// there are no more locations left for exploration; delete it as a possible quest type // there are no more locations left for exploration; delete it as a possible quest type
questTypePool.types = questTypePool.types.filter(t => t !== "Exploration"); questTypePool.types = questTypePool.types.filter((t) => t !== "Exploration");
return null; return null;
} }
@ -737,13 +742,15 @@ export class RepeatableQuestGenerator
const mapExits = this.getLocationExitsForSide(locationKey, repeatableConfig.side); const mapExits = this.getLocationExitsForSide(locationKey, repeatableConfig.side);
// Only get exits that have a greater than 0% chance to spawn // Only get exits that have a greater than 0% chance to spawn
const exitPool = mapExits.filter(exit => exit.Chance > 0); const exitPool = mapExits.filter((exit) => exit.Chance > 0);
// Exclude exits with a requirement to leave (e.g. car extracts) // Exclude exits with a requirement to leave (e.g. car extracts)
const possibleExits = exitPool.filter(exit => !("PassageRequirement" in exit) const possibleExits = exitPool.filter(
|| repeatableConfig.questConfig.Exploration.specificExits.passageRequirementWhitelist.includes( (exit) =>
exit.PassageRequirement, !("PassageRequirement" in exit)
), || repeatableConfig.questConfig.Exploration.specificExits.passageRequirementWhitelist.includes(
exit.PassageRequirement,
),
); );
if (possibleExits.length === 0) if (possibleExits.length === 0)
@ -788,7 +795,7 @@ export class RepeatableQuestGenerator
const mapExtracts = this.databaseServer.getTables().locations[locationKey.toLocaleLowerCase()] const mapExtracts = this.databaseServer.getTables().locations[locationKey.toLocaleLowerCase()]
.allExtracts as Exit[]; .allExtracts as Exit[];
return mapExtracts.filter(exit => exit.Side === playerSide); return mapExtracts.filter((exit) => exit.Side === playerSide);
} }
protected generatePickupQuest( protected generatePickupQuest(
@ -811,18 +818,18 @@ export class RepeatableQuestGenerator
// const locationKey: string = this.randomUtil.drawRandomFromDict(questTypePool.pool.Pickup.locations)[0]; // const locationKey: string = this.randomUtil.drawRandomFromDict(questTypePool.pool.Pickup.locations)[0];
// const locationTarget = questTypePool.pool.Pickup.locations[locationKey]; // const locationTarget = questTypePool.pool.Pickup.locations[locationKey];
const findCondition = quest.conditions.AvailableForFinish.find(x => x.conditionType === "FindItem"); const findCondition = quest.conditions.AvailableForFinish.find((x) => x.conditionType === "FindItem");
findCondition.target = [itemTypeToFetchWithCount.itemType]; findCondition.target = [itemTypeToFetchWithCount.itemType];
findCondition.value = itemCountToFetch; findCondition.value = itemCountToFetch;
const counterCreatorCondition = quest.conditions.AvailableForFinish.find(x => const counterCreatorCondition = quest.conditions.AvailableForFinish.find(
x.conditionType === "CounterCreator", (x) => x.conditionType === "CounterCreator",
); );
// const locationCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Location"); // const locationCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Location");
// (locationCondition._props as ILocationConditionProps).target = [...locationTarget]; // (locationCondition._props as ILocationConditionProps).target = [...locationTarget];
const equipmentCondition = counterCreatorCondition.counter.conditions.find(x => const equipmentCondition = counterCreatorCondition.counter.conditions.find(
x.conditionType === "Equipment", (x) => x.conditionType === "Equipment",
); );
equipmentCondition.equipmentInclusive = [[itemTypeToFetchWithCount.itemType]]; equipmentCondition.equipmentInclusive = [[itemTypeToFetchWithCount.itemType]];
@ -887,46 +894,36 @@ export class RepeatableQuestGenerator
// Get template id from config based on side and type of quest // Get template id from config based on side and type of quest
questClone.templateId = this.questConfig.questTemplateIds[side.toLowerCase()][type.toLowerCase()]; questClone.templateId = this.questConfig.questTemplateIds[side.toLowerCase()][type.toLowerCase()];
questClone.name = questClone.name.replace("{traderId}", traderId).replace( questClone.name = questClone.name
"{templateId}", .replace("{traderId}", traderId)
questClone.templateId, .replace("{templateId}", questClone.templateId);
); questClone.note = questClone.note
questClone.note = questClone.note.replace("{traderId}", traderId).replace( .replace("{traderId}", traderId)
"{templateId}", .replace("{templateId}", questClone.templateId);
questClone.templateId, questClone.description = questClone.description
); .replace("{traderId}", traderId)
questClone.description = questClone.description.replace("{traderId}", traderId).replace( .replace("{templateId}", questClone.templateId);
"{templateId}", questClone.successMessageText = questClone.successMessageText
questClone.templateId, .replace("{traderId}", traderId)
); .replace("{templateId}", questClone.templateId);
questClone.successMessageText = questClone.successMessageText.replace("{traderId}", traderId).replace( questClone.failMessageText = questClone.failMessageText
"{templateId}", .replace("{traderId}", traderId)
questClone.templateId, .replace("{templateId}", questClone.templateId);
); questClone.startedMessageText = questClone.startedMessageText
questClone.failMessageText = questClone.failMessageText.replace("{traderId}", traderId).replace( .replace("{traderId}", traderId)
"{templateId}", .replace("{templateId}", questClone.templateId);
questClone.templateId, questClone.changeQuestMessageText = questClone.changeQuestMessageText
); .replace("{traderId}", traderId)
questClone.startedMessageText = questClone.startedMessageText.replace("{traderId}", traderId).replace( .replace("{templateId}", questClone.templateId);
"{templateId}", questClone.acceptPlayerMessage = questClone.acceptPlayerMessage
questClone.templateId, .replace("{traderId}", traderId)
); .replace("{templateId}", questClone.templateId);
questClone.changeQuestMessageText = questClone.changeQuestMessageText.replace("{traderId}", traderId).replace( questClone.declinePlayerMessage = questClone.declinePlayerMessage
"{templateId}", .replace("{traderId}", traderId)
questClone.templateId, .replace("{templateId}", questClone.templateId);
); questClone.completePlayerMessage = questClone.completePlayerMessage
questClone.acceptPlayerMessage = questClone.acceptPlayerMessage.replace("{traderId}", traderId).replace( .replace("{traderId}", traderId)
"{templateId}", .replace("{templateId}", questClone.templateId);
questClone.templateId,
);
questClone.declinePlayerMessage = questClone.declinePlayerMessage.replace("{traderId}", traderId).replace(
"{templateId}",
questClone.templateId,
);
questClone.completePlayerMessage = questClone.completePlayerMessage.replace("{traderId}", traderId).replace(
"{templateId}",
questClone.templateId,
);
return questClone; return questClone;
} }

View File

@ -94,11 +94,13 @@ export class RepeatableQuestRewardGenerator
// rewards are generated based on pmcLevel, difficulty and a random spread // rewards are generated based on pmcLevel, difficulty and a random spread
const rewardXP = Math.floor( const rewardXP = Math.floor(
effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, xpConfig) effectiveDifficulty
* this.mathUtil.interp1(pmcLevel, levelsConfig, xpConfig)
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig), * this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig),
); );
const rewardRoubles = Math.floor( const rewardRoubles = Math.floor(
effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig) effectiveDifficulty
* this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig)
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig), * this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig),
); );
const rewardNumItems = this.randomUtil.randInt( const rewardNumItems = this.randomUtil.randInt(
@ -107,7 +109,9 @@ export class RepeatableQuestRewardGenerator
); );
const rewardReputation const rewardReputation
= Math.round( = Math.round(
100 * effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, reputationConfig) 100
* effectiveDifficulty
* this.mathUtil.interp1(pmcLevel, levelsConfig, reputationConfig)
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig), * this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig),
) / 100; ) / 100;
const skillRewardChance = this.mathUtil.interp1(pmcLevel, levelsConfig, skillRewardChanceConfig); const skillRewardChance = this.mathUtil.interp1(pmcLevel, levelsConfig, skillRewardChanceConfig);
@ -134,7 +138,7 @@ export class RepeatableQuestRewardGenerator
this.addMoneyReward(traderId, rewards, rewardRoubles, rewardIndex); this.addMoneyReward(traderId, rewards, rewardRoubles, rewardIndex);
rewardIndex++; rewardIndex++;
const traderWhitelistDetails = repeatableConfig.traderWhitelist.find(x => x.traderId === traderId); const traderWhitelistDetails = repeatableConfig.traderWhitelist.find((x) => x.traderId === traderId);
if ( if (
traderWhitelistDetails.rewardCanBeWeapon traderWhitelistDetails.rewardCanBeWeapon
&& this.randomUtil.getChance100(traderWhitelistDetails.weaponRewardChancePercent) && this.randomUtil.getChance100(traderWhitelistDetails.weaponRewardChancePercent)
@ -150,7 +154,7 @@ export class RepeatableQuestRewardGenerator
while (defaultPresetPool.hasValues()) while (defaultPresetPool.hasValues())
{ {
const randomPreset = defaultPresetPool.getRandomValue(); const randomPreset = defaultPresetPool.getRandomValue();
const tpls = randomPreset._items.map(item => item._tpl); const tpls = randomPreset._items.map((item) => item._tpl);
const presetPrice = this.itemHelper.getItemAndChildrenPrice(tpls); const presetPrice = this.itemHelper.getItemAndChildrenPrice(tpls);
if (presetPrice <= roublesBudget) if (presetPrice <= roublesBudget)
{ {
@ -307,14 +311,16 @@ export class RepeatableQuestRewardGenerator
*/ */
protected canIncreaseRewardItemStackSize(item: ITemplateItem, maxRoublePriceToStack: number): boolean protected canIncreaseRewardItemStackSize(item: ITemplateItem, maxRoublePriceToStack: number): boolean
{ {
return this.presetHelper.getDefaultPresetOrItemPrice(item._id) < maxRoublePriceToStack return (
&& !this.itemHelper.isOfBaseclasses(item._id, [ this.presetHelper.getDefaultPresetOrItemPrice(item._id) < maxRoublePriceToStack
BaseClasses.WEAPON, && !this.itemHelper.isOfBaseclasses(item._id, [
BaseClasses.ARMORED_EQUIPMENT, BaseClasses.WEAPON,
BaseClasses.AMMO, BaseClasses.ARMORED_EQUIPMENT,
]) BaseClasses.AMMO,
&& !this.itemHelper.itemRequiresSoftInserts(item._id) ])
&& this.randomUtil.getChance100(25); && !this.itemHelper.itemRequiresSoftInserts(item._id)
&& this.randomUtil.getChance100(25)
);
} }
protected calculateAmmoStackSizeThatFitsBudget( protected calculateAmmoStackSizeThatFitsBudget(
@ -354,7 +360,7 @@ export class RepeatableQuestRewardGenerator
const rewardableItemPool = this.getRewardableItems(repeatableConfig, traderId); const rewardableItemPool = this.getRewardableItems(repeatableConfig, traderId);
const minPrice = Math.min(25000, 0.5 * roublesBudget); const minPrice = Math.min(25000, 0.5 * roublesBudget);
let rewardableItemPoolWithinBudget = rewardableItemPool.map(x => x[1]); let rewardableItemPoolWithinBudget = rewardableItemPool.map((x) => x[1]);
rewardableItemPoolWithinBudget = this.filterRewardPoolWithinBudget( rewardableItemPoolWithinBudget = this.filterRewardPoolWithinBudget(
rewardableItemPoolWithinBudget, rewardableItemPoolWithinBudget,
roublesBudget, roublesBudget,
@ -369,9 +375,9 @@ export class RepeatableQuestRewardGenerator
}), }),
); );
// In case we don't find any items in the price range // In case we don't find any items in the price range
rewardableItemPoolWithinBudget = rewardableItemPool.filter(x => rewardableItemPoolWithinBudget = rewardableItemPool
this.itemHelper.getItemPrice(x[0]) < roublesBudget, .filter((x) => this.itemHelper.getItemPrice(x[0]) < roublesBudget)
).map(x => x[1]); .map((x) => x[1]);
} }
return rewardableItemPoolWithinBudget; return rewardableItemPoolWithinBudget;
@ -392,7 +398,7 @@ export class RepeatableQuestRewardGenerator
if (preset) if (preset)
{ {
const rootItem = preset.find(x => x._tpl === tpl); const rootItem = preset.find((x) => x._tpl === tpl);
rewardItem.items = this.itemHelper.reparentItemAndChildren(rootItem, preset); rewardItem.items = this.itemHelper.reparentItemAndChildren(rootItem, preset);
rewardItem.target = rootItem._id; // Target property and root items id must match rewardItem.target = rootItem._id; // Target property and root items id must match
} }
@ -435,8 +441,8 @@ export class RepeatableQuestRewardGenerator
return false; return false;
} }
const traderWhitelist = repeatableQuestConfig.traderWhitelist.find(trader => const traderWhitelist = repeatableQuestConfig.traderWhitelist.find(
trader.traderId === traderId, (trader) => trader.traderId === traderId,
); );
return this.isValidRewardItem(tpl, repeatableQuestConfig, traderWhitelist?.rewardBaseWhitelist); return this.isValidRewardItem(tpl, repeatableQuestConfig, traderWhitelist?.rewardBaseWhitelist);
}, },
@ -502,7 +508,12 @@ export class RepeatableQuestRewardGenerator
return true; return true;
} }
protected addMoneyReward(traderId: string, rewards: IQuestRewards, rewardRoubles: number, rewardIndex: number): void protected addMoneyReward(
traderId: string,
rewards: IQuestRewards,
rewardRoubles: number,
rewardIndex: number,
): void
{ {
// PK and Fence use euros // PK and Fence use euros
if (traderId === Traders.PEACEKEEPER || traderId === Traders.FENCE) if (traderId === Traders.PEACEKEEPER || traderId === Traders.FENCE)

View File

@ -1,8 +1,7 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { PresetHelper } from "@spt-aki/helpers/PresetHelper"; import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
import { Product } from "@spt-aki/models/eft/common/tables/IBotBase"; import { Item } from "@spt-aki/models/eft/common/tables/IItem";
import { Item, Upd } from "@spt-aki/models/eft/common/tables/IItem";
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem"; import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
import { IHideoutScavCase } from "@spt-aki/models/eft/hideout/IHideoutScavCase"; import { IHideoutScavCase } from "@spt-aki/models/eft/hideout/IHideoutScavCase";
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses"; import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
@ -58,7 +57,7 @@ export class ScavCaseRewardGenerator
this.cacheDbItems(); this.cacheDbItems();
// Get scavcase details from hideout/scavcase.json // Get scavcase details from hideout/scavcase.json
const scavCaseDetails = this.databaseServer.getTables().hideout.scavcase.find(r => r._id === recipeId); const scavCaseDetails = this.databaseServer.getTables().hideout.scavcase.find((r) => r._id === recipeId);
const rewardItemCounts = this.getScavCaseRewardCountsAndPrices(scavCaseDetails); const rewardItemCounts = this.getScavCaseRewardCountsAndPrices(scavCaseDetails);
// Get items that fit the price criteria as set by the scavCase config // Get items that fit the price criteria as set by the scavCase config
@ -231,7 +230,8 @@ export class ScavCaseRewardGenerator
for (let i = 0; i < randomCount; i++) for (let i = 0; i < randomCount; i++)
{ {
if (this.rewardShouldBeMoney() && !rewardWasMoney) if (this.rewardShouldBeMoney() && !rewardWasMoney)
{ // Only allow one reward to be money {
// Only allow one reward to be money
result.push(this.getRandomMoney()); result.push(this.getRandomMoney());
if (!this.scavCaseConfig.allowMultipleMoneyRewardsPerRarity) if (!this.scavCaseConfig.allowMultipleMoneyRewardsPerRarity)
{ {
@ -239,7 +239,8 @@ export class ScavCaseRewardGenerator
} }
} }
else if (this.rewardShouldBeAmmo() && !rewardWasAmmo) else if (this.rewardShouldBeAmmo() && !rewardWasAmmo)
{ // Only allow one reward to be ammo {
// Only allow one reward to be ammo
result.push(this.getRandomAmmo(rarity)); result.push(this.getRandomAmmo(rarity));
if (!this.scavCaseConfig.allowMultipleAmmoRewardsPerRarity) if (!this.scavCaseConfig.allowMultipleAmmoRewardsPerRarity)
{ {

View File

@ -1,10 +1,8 @@
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
import { ApplicationContext } from "@spt-aki/context/ApplicationContext"; import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper"; import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
import { IWeather, IWeatherData } from "@spt-aki/models/eft/weather/IWeatherData"; import { IWeather, IWeatherData } from "@spt-aki/models/eft/weather/IWeatherData";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
import { Season } from "@spt-aki/models/enums/Season";
import { WindDirection } from "@spt-aki/models/enums/WindDirection"; import { WindDirection } from "@spt-aki/models/enums/WindDirection";
import { IWeatherConfig } from "@spt-aki/models/spt/config/IWeatherConfig"; import { IWeatherConfig } from "@spt-aki/models/spt/config/IWeatherConfig";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
@ -181,7 +179,8 @@ export class WeatherGenerator
protected getRandomFloat(node: string): number protected getRandomFloat(node: string): number
{ {
return Number.parseFloat( return Number.parseFloat(
this.randomUtil.getFloat(this.weatherConfig.weather[node].min, this.weatherConfig.weather[node].max) this.randomUtil
.getFloat(this.weatherConfig.weather[node].min, this.weatherConfig.weather[node].max)
.toPrecision(3), .toPrecision(3),
); );
} }

View File

@ -85,8 +85,8 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
} }
/* We were unable to fit at least the minimum amount of magazines, /* We were unable to fit at least the minimum amount of magazines,
* so we fallback to default magazine and try again. * so we fallback to default magazine and try again.
* Temporary workaround to Killa spawning with no extra mags if he spawns with a drum mag */ * Temporary workaround to Killa spawning with no extra mags if he spawns with a drum mag */
if (magazineTpl === defaultMagazineTpl) if (magazineTpl === defaultMagazineTpl)
{ {
@ -153,15 +153,15 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
): ITemplateItem ): ITemplateItem
{ {
// The mag Slot data for the weapon // The mag Slot data for the weapon
const magSlot = this.itemHelper.getItem(weaponTpl)[1]._props.Slots.find(x => x._name === "mod_magazine"); const magSlot = this.itemHelper.getItem(weaponTpl)[1]._props.Slots.find((x) => x._name === "mod_magazine");
if (!magSlot) if (!magSlot)
{ {
return null; return null;
} }
// All possible mags that fit into the weapon excluding blacklisted // All possible mags that fit into the weapon excluding blacklisted
const magazinePool = magSlot._props.filters[0].Filter.filter(x => !magazineBlacklist.includes(x)).map(x => const magazinePool = magSlot._props.filters[0].Filter.filter((x) => !magazineBlacklist.includes(x)).map(
this.itemHelper.getItem(x)[1], (x) => this.itemHelper.getItem(x)[1],
); );
if (!magazinePool) if (!magazinePool)
{ {
@ -169,7 +169,7 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
} }
// Non-internal magazines that fit into the weapon // Non-internal magazines that fit into the weapon
const externalMagazineOnlyPool = magazinePool.filter(x => x._props.ReloadMagType !== "InternalMagazine"); const externalMagazineOnlyPool = magazinePool.filter((x) => x._props.ReloadMagType !== "InternalMagazine");
if (!externalMagazineOnlyPool || externalMagazineOnlyPool?.length === 0) if (!externalMagazineOnlyPool || externalMagazineOnlyPool?.length === 0)
{ {
return null; return null;

View File

@ -92,9 +92,10 @@ export class BotDifficultyHelper
*/ */
protected getDifficultySettings(type: string, difficulty: string): Difficulty protected getDifficultySettings(type: string, difficulty: string): Difficulty
{ {
let difficultySetting = this.pmcConfig.difficulty.toLowerCase() === "asonline" let difficultySetting
? difficulty = this.pmcConfig.difficulty.toLowerCase() === "asonline"
: this.pmcConfig.difficulty.toLowerCase(); ? difficulty
: this.pmcConfig.difficulty.toLowerCase();
difficultySetting = this.convertBotDifficultyDropdownToBotDifficulty(difficultySetting); difficultySetting = this.convertBotDifficultyDropdownToBotDifficulty(difficultySetting);

View File

@ -54,9 +54,9 @@ export class BotGeneratorHelper
public generateExtraPropertiesForItem(itemTemplate: ITemplateItem, botRole?: string): { upd?: Upd } public generateExtraPropertiesForItem(itemTemplate: ITemplateItem, botRole?: string): { upd?: Upd }
{ {
// Get raid settings, if no raid, default to day // Get raid settings, if no raid, default to day
const raidSettings = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue< const raidSettings = this.applicationContext
IGetRaidConfigurationRequestData .getLatestValue(ContextVariableType.RAID_CONFIGURATION)
>(); ?.getValue<IGetRaidConfigurationRequestData>();
const raidIsNight = raidSettings?.timeVariant === "PAST"; const raidIsNight = raidSettings?.timeVariant === "PAST";
const itemProperties: Upd = {}; const itemProperties: Upd = {};
@ -64,11 +64,13 @@ export class BotGeneratorHelper
if (itemTemplate._props.MaxDurability) if (itemTemplate._props.MaxDurability)
{ {
if (itemTemplate._props.weapClass) if (itemTemplate._props.weapClass)
{ // Is weapon {
// Is weapon
itemProperties.Repairable = this.generateWeaponRepairableProperties(itemTemplate, botRole); itemProperties.Repairable = this.generateWeaponRepairableProperties(itemTemplate, botRole);
} }
else if (itemTemplate._props.armorClass) else if (itemTemplate._props.armorClass)
{ // Is armor {
// Is armor
itemProperties.Repairable = this.generateArmorRepairableProperties(itemTemplate, botRole); itemProperties.Repairable = this.generateArmorRepairableProperties(itemTemplate, botRole);
} }
} }
@ -287,7 +289,7 @@ export class BotGeneratorHelper
): IChooseRandomCompatibleModResult ): IChooseRandomCompatibleModResult
{ {
// TODO: Can probably be optimized to cache itemTemplates as items are added to inventory // TODO: Can probably be optimized to cache itemTemplates as items are added to inventory
const equippedItemsDb = itemsEquipped.map(item => this.databaseServer.getTables().templates.items[item._tpl]); const equippedItemsDb = itemsEquipped.map((item) => this.databaseServer.getTables().templates.items[item._tpl]);
const itemToEquipDb = this.itemHelper.getItem(tplToCheck); const itemToEquipDb = this.itemHelper.getItem(tplToCheck);
const itemToEquip = itemToEquipDb[1]; const itemToEquip = itemToEquipDb[1];
@ -318,27 +320,25 @@ export class BotGeneratorHelper
} }
// Check if any of the current weapon mod templates have the incoming item defined as incompatible // Check if any of the current weapon mod templates have the incoming item defined as incompatible
const blockingItem = equippedItemsDb.find(x => x._props.ConflictingItems?.includes(tplToCheck)); const blockingItem = equippedItemsDb.find((x) => x._props.ConflictingItems?.includes(tplToCheck));
if (blockingItem) if (blockingItem)
{ {
return { return {
incompatible: true, incompatible: true,
found: false, found: false,
reason: reason: `Cannot add: ${tplToCheck} ${itemToEquip._name} to slot: ${modSlot}. Blocked by: ${blockingItem._id} ${blockingItem._name}`,
`Cannot add: ${tplToCheck} ${itemToEquip._name} to slot: ${modSlot}. Blocked by: ${blockingItem._id} ${blockingItem._name}`,
slotBlocked: true, slotBlocked: true,
}; };
} }
// Check inverse to above, if the incoming item has any existing mods in its conflicting items array // Check inverse to above, if the incoming item has any existing mods in its conflicting items array
const blockingModItem = itemsEquipped.find(item => itemToEquip._props.ConflictingItems?.includes(item._tpl)); const blockingModItem = itemsEquipped.find((item) => itemToEquip._props.ConflictingItems?.includes(item._tpl));
if (blockingModItem) if (blockingModItem)
{ {
return { return {
incompatible: true, incompatible: true,
found: false, found: false,
reason: reason: ` Cannot add: ${tplToCheck} to slot: ${modSlot}. Would block existing item: ${blockingModItem._tpl} in slot: ${blockingModItem.slotId}`,
` Cannot add: ${tplToCheck} to slot: ${modSlot}. Would block existing item: ${blockingModItem._tpl} in slot: ${blockingModItem.slotId}`,
}; };
} }
@ -365,7 +365,7 @@ export class BotGeneratorHelper
} }
// TODO: Can probably be optimized to cache itemTemplates as items are added to inventory // TODO: Can probably be optimized to cache itemTemplates as items are added to inventory
const equippedItemsDb = itemsEquipped.map(i => this.databaseServer.getTables().templates.items[i._tpl]); const equippedItemsDb = itemsEquipped.map((i) => this.databaseServer.getTables().templates.items[i._tpl]);
const itemToEquipDb = this.itemHelper.getItem(tplToCheck); const itemToEquipDb = this.itemHelper.getItem(tplToCheck);
const itemToEquip = itemToEquipDb[1]; const itemToEquip = itemToEquipDb[1];
@ -395,29 +395,27 @@ export class BotGeneratorHelper
} }
// Does an equipped item have a property that blocks the desired item - check for prop "BlocksX" .e.g BlocksEarpiece / BlocksFaceCover // Does an equipped item have a property that blocks the desired item - check for prop "BlocksX" .e.g BlocksEarpiece / BlocksFaceCover
let blockingItem = equippedItemsDb.find(x => x._props[`Blocks${equipmentSlot}`]); let blockingItem = equippedItemsDb.find((x) => x._props[`Blocks${equipmentSlot}`]);
if (blockingItem) if (blockingItem)
{ {
// this.logger.warning(`1 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._name} - ${equipmentSlot}`); // this.logger.warning(`1 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._name} - ${equipmentSlot}`);
return { return {
incompatible: true, incompatible: true,
found: false, found: false,
reason: reason: `${tplToCheck} ${itemToEquip._name} in slot: ${equipmentSlot} blocked by: ${blockingItem._id} ${blockingItem._name}`,
`${tplToCheck} ${itemToEquip._name} in slot: ${equipmentSlot} blocked by: ${blockingItem._id} ${blockingItem._name}`,
slotBlocked: true, slotBlocked: true,
}; };
} }
// Check if any of the current inventory templates have the incoming item defined as incompatible // Check if any of the current inventory templates have the incoming item defined as incompatible
blockingItem = equippedItemsDb.find(x => x._props.ConflictingItems?.includes(tplToCheck)); blockingItem = equippedItemsDb.find((x) => x._props.ConflictingItems?.includes(tplToCheck));
if (blockingItem) if (blockingItem)
{ {
// this.logger.warning(`2 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._props.Name} - ${equipmentSlot}`); // this.logger.warning(`2 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._props.Name} - ${equipmentSlot}`);
return { return {
incompatible: true, incompatible: true,
found: false, found: false,
reason: reason: `${tplToCheck} ${itemToEquip._name} in slot: ${equipmentSlot} blocked by: ${blockingItem._id} ${blockingItem._name}`,
`${tplToCheck} ${itemToEquip._name} in slot: ${equipmentSlot} blocked by: ${blockingItem._id} ${blockingItem._name}`,
slotBlocked: true, slotBlocked: true,
}; };
} }
@ -425,14 +423,13 @@ export class BotGeneratorHelper
// Does item being checked get blocked/block existing item // Does item being checked get blocked/block existing item
if (itemToEquip._props.BlocksHeadwear) if (itemToEquip._props.BlocksHeadwear)
{ {
const existingHeadwear = itemsEquipped.find(x => x.slotId === "Headwear"); const existingHeadwear = itemsEquipped.find((x) => x.slotId === "Headwear");
if (existingHeadwear) if (existingHeadwear)
{ {
return { return {
incompatible: true, incompatible: true,
found: false, found: false,
reason: reason: `${tplToCheck} ${itemToEquip._name} is blocked by: ${existingHeadwear._tpl} in slot: ${existingHeadwear.slotId}`,
`${tplToCheck} ${itemToEquip._name} is blocked by: ${existingHeadwear._tpl} in slot: ${existingHeadwear.slotId}`,
slotBlocked: true, slotBlocked: true,
}; };
} }
@ -441,14 +438,13 @@ export class BotGeneratorHelper
// Does item being checked get blocked/block existing item // Does item being checked get blocked/block existing item
if (itemToEquip._props.BlocksFaceCover) if (itemToEquip._props.BlocksFaceCover)
{ {
const existingFaceCover = itemsEquipped.find(item => item.slotId === "FaceCover"); const existingFaceCover = itemsEquipped.find((item) => item.slotId === "FaceCover");
if (existingFaceCover) if (existingFaceCover)
{ {
return { return {
incompatible: true, incompatible: true,
found: false, found: false,
reason: reason: `${tplToCheck} ${itemToEquip._name} is blocked by: ${existingFaceCover._tpl} in slot: ${existingFaceCover.slotId}`,
`${tplToCheck} ${itemToEquip._name} is blocked by: ${existingFaceCover._tpl} in slot: ${existingFaceCover.slotId}`,
slotBlocked: true, slotBlocked: true,
}; };
} }
@ -457,14 +453,13 @@ export class BotGeneratorHelper
// Does item being checked get blocked/block existing item // Does item being checked get blocked/block existing item
if (itemToEquip._props.BlocksEarpiece) if (itemToEquip._props.BlocksEarpiece)
{ {
const existingEarpiece = itemsEquipped.find(item => item.slotId === "Earpiece"); const existingEarpiece = itemsEquipped.find((item) => item.slotId === "Earpiece");
if (existingEarpiece) if (existingEarpiece)
{ {
return { return {
incompatible: true, incompatible: true,
found: false, found: false,
reason: reason: `${tplToCheck} ${itemToEquip._name} is blocked by: ${existingEarpiece._tpl} in slot: ${existingEarpiece.slotId}`,
`${tplToCheck} ${itemToEquip._name} is blocked by: ${existingEarpiece._tpl} in slot: ${existingEarpiece.slotId}`,
slotBlocked: true, slotBlocked: true,
}; };
} }
@ -473,29 +468,27 @@ export class BotGeneratorHelper
// Does item being checked get blocked/block existing item // Does item being checked get blocked/block existing item
if (itemToEquip._props.BlocksArmorVest) if (itemToEquip._props.BlocksArmorVest)
{ {
const existingArmorVest = itemsEquipped.find(item => item.slotId === "ArmorVest"); const existingArmorVest = itemsEquipped.find((item) => item.slotId === "ArmorVest");
if (existingArmorVest) if (existingArmorVest)
{ {
return { return {
incompatible: true, incompatible: true,
found: false, found: false,
reason: reason: `${tplToCheck} ${itemToEquip._name} is blocked by: ${existingArmorVest._tpl} in slot: ${existingArmorVest.slotId}`,
`${tplToCheck} ${itemToEquip._name} is blocked by: ${existingArmorVest._tpl} in slot: ${existingArmorVest.slotId}`,
slotBlocked: true, slotBlocked: true,
}; };
} }
} }
// Check if the incoming item has any inventory items defined as incompatible // Check if the incoming item has any inventory items defined as incompatible
const blockingInventoryItem = itemsEquipped.find(x => itemToEquip._props.ConflictingItems?.includes(x._tpl)); const blockingInventoryItem = itemsEquipped.find((x) => itemToEquip._props.ConflictingItems?.includes(x._tpl));
if (blockingInventoryItem) if (blockingInventoryItem)
{ {
// this.logger.warning(`3 incompatibility found between - ${itemToEquip[1]._name} and ${blockingInventoryItem._tpl} - ${equipmentSlot}`) // this.logger.warning(`3 incompatibility found between - ${itemToEquip[1]._name} and ${blockingInventoryItem._tpl} - ${equipmentSlot}`)
return { return {
incompatible: true, incompatible: true,
found: false, found: false,
reason: reason: `${tplToCheck} blocks existing item ${blockingInventoryItem._tpl} in slot ${blockingInventoryItem.slotId}`,
`${tplToCheck} blocks existing item ${blockingInventoryItem._tpl} in slot ${blockingInventoryItem.slotId}`,
}; };
} }
@ -543,7 +536,7 @@ export class BotGeneratorHelper
continue; continue;
} }
// Get container to put item into // Get container to put item into
const container = inventory.items.find(item => item.slotId === equipmentSlotId); const container = inventory.items.find((item) => item.slotId === equipmentSlotId);
if (!container) if (!container)
{ {
missingContainerCount++; missingContainerCount++;
@ -551,9 +544,9 @@ export class BotGeneratorHelper
{ {
// Bot doesnt have any containers we want to add item to // Bot doesnt have any containers we want to add item to
this.logger.debug( this.logger.debug(
`Unable to add item: ${itemWithChildren[0]._tpl} to bot as it lacks the following containers: ${ `Unable to add item: ${itemWithChildren[0]._tpl} to bot as it lacks the following containers: ${equipmentSlots.join(
equipmentSlots.join(",") ",",
}`, )}`,
); );
return ItemAddedResult.NO_CONTAINERS; return ItemAddedResult.NO_CONTAINERS;
@ -589,7 +582,8 @@ export class BotGeneratorHelper
{ {
// Grid is empty, skip or item size is bigger than grid // Grid is empty, skip or item size is bigger than grid
if ( if (
slotGrid._props.cellsH === 0 || slotGrid._props.cellsV === 0 slotGrid._props.cellsH === 0
|| slotGrid._props.cellsV === 0
|| itemSize[0] * itemSize[1] > slotGrid._props.cellsV * slotGrid._props.cellsH || itemSize[0] * itemSize[1] > slotGrid._props.cellsV * slotGrid._props.cellsH
) )
{ {
@ -604,12 +598,12 @@ export class BotGeneratorHelper
} }
// Get all root items in found container // Get all root items in found container
const existingContainerItems = inventory.items.filter(item => const existingContainerItems = inventory.items.filter(
item.parentId === container._id && item.slotId === slotGrid._name, (item) => item.parentId === container._id && item.slotId === slotGrid._name,
); );
// Get root items in container we can iterate over to find out what space is free // Get root items in container we can iterate over to find out what space is free
const containerItemsToCheck = existingContainerItems.filter(x => x.slotId === slotGrid._name); const containerItemsToCheck = existingContainerItems.filter((x) => x.slotId === slotGrid._name);
for (const item of containerItemsToCheck) for (const item of containerItemsToCheck)
{ {
// Look for children on items, insert into array if found // Look for children on items, insert into array if found
@ -635,7 +629,7 @@ export class BotGeneratorHelper
// Open slot found, add item to inventory // Open slot found, add item to inventory
if (findSlotResult.success) if (findSlotResult.success)
{ {
const parentItem = itemWithChildren.find(i => i._id === rootItemId); const parentItem = itemWithChildren.find((i) => i._id === rootItemId);
// Set items parent to container id // Set items parent to container id
parentItem.parentId = container._id; parentItem.parentId = container._id;

View File

@ -66,7 +66,7 @@ export class BotHelper
public isBotBoss(botRole: string): boolean public isBotBoss(botRole: string): boolean
{ {
return this.botConfig.bosses.some(x => x.toLowerCase() === botRole?.toLowerCase()); return this.botConfig.bosses.some((x) => x.toLowerCase() === botRole?.toLowerCase());
} }
public isBotFollower(botRole: string): boolean public isBotFollower(botRole: string): boolean
@ -182,8 +182,10 @@ export class BotHelper
public rollChanceToBePmc(role: string, botConvertMinMax: MinMax): boolean public rollChanceToBePmc(role: string, botConvertMinMax: MinMax): boolean
{ {
return role.toLowerCase() in this.pmcConfig.convertIntoPmcChance return (
&& this.randomUtil.getChance100(this.randomUtil.getInt(botConvertMinMax.min, botConvertMinMax.max)); role.toLowerCase() in this.pmcConfig.convertIntoPmcChance
&& this.randomUtil.getChance100(this.randomUtil.getInt(botConvertMinMax.min, botConvertMinMax.max))
);
} }
public botRoleIsPmc(botRole: string): boolean public botRoleIsPmc(botRole: string): boolean
@ -207,7 +209,7 @@ export class BotHelper
return null; return null;
} }
return botEquipConfig.randomisation.find(x => botLevel >= x.levelRange.min && botLevel <= x.levelRange.max); return botEquipConfig.randomisation.find((x) => botLevel >= x.levelRange.min && botLevel <= x.levelRange.max);
} }
/** /**
@ -216,9 +218,7 @@ export class BotHelper
*/ */
public getRandomizedPmcRole(): string public getRandomizedPmcRole(): string
{ {
return this.randomUtil.getChance100(this.pmcConfig.isUsec) return this.randomUtil.getChance100(this.pmcConfig.isUsec) ? this.pmcConfig.usecType : this.pmcConfig.bearType;
? this.pmcConfig.usecType
: this.pmcConfig.bearType;
} }
/** /**

View File

@ -45,9 +45,10 @@ export class BotWeaponGeneratorHelper
{ {
const firstSlotAmmoTpl = magTemplate._props.Cartridges[0]._props.filters[0].Filter[0]; const firstSlotAmmoTpl = magTemplate._props.Cartridges[0]._props.filters[0].Filter[0];
const ammoMaxStackSize = this.itemHelper.getItem(firstSlotAmmoTpl)[1]?._props?.StackMaxSize ?? 1; const ammoMaxStackSize = this.itemHelper.getItem(firstSlotAmmoTpl)[1]?._props?.StackMaxSize ?? 1;
chamberBulletCount = ammoMaxStackSize === 1 chamberBulletCount
? 1 // Rotating grenade launcher = ammoMaxStackSize === 1
: magTemplate._props.Slots.length; // Shotguns/revolvers. We count the number of camoras as the _max_count of the magazine is 0 ? 1 // Rotating grenade launcher
: magTemplate._props.Slots.length; // Shotguns/revolvers. We count the number of camoras as the _max_count of the magazine is 0
} }
else if (parentItem._id === BaseClasses.UBGL) else if (parentItem._id === BaseClasses.UBGL)
{ {
@ -60,7 +61,7 @@ export class BotWeaponGeneratorHelper
} }
/* Get the amount of bullets that would fit in the internal magazine /* Get the amount of bullets that would fit in the internal magazine
* and multiply by how many magazines were supposed to be created */ * and multiply by how many magazines were supposed to be created */
return chamberBulletCount * randomizedMagazineCount; return chamberBulletCount * randomizedMagazineCount;
} }

View File

@ -35,7 +35,7 @@ export class ContainerHelper
const limitX = containerX - minVolume; const limitX = containerX - minVolume;
// Every x+y slot taken up in container, exit // Every x+y slot taken up in container, exit
if (container2D.every(x => x.every(y => y === 1))) if (container2D.every((x) => x.every((y) => y === 1)))
{ {
return new FindSlotResult(false); return new FindSlotResult(false);
} }
@ -44,7 +44,7 @@ export class ContainerHelper
for (let y = 0; y < limitY; y++) for (let y = 0; y < limitY; y++)
{ {
// Across // Across
if (container2D[y].every(x => x === 1)) if (container2D[y].every((x) => x === 1))
{ {
// Every item in row is full, skip row // Every item in row is full, skip row
continue; continue;

View File

@ -12,8 +12,7 @@ export abstract class AbstractDialogueChatBot implements IDialogueChatBot
protected mailSendService: MailSendService, protected mailSendService: MailSendService,
protected chatCommands: IChatCommand[] | ICommandoCommand[], protected chatCommands: IChatCommand[] | ICommandoCommand[],
) )
{ {}
}
/** /**
* @deprecated As of v3.7.6. Use registerChatCommand. * @deprecated As of v3.7.6. Use registerChatCommand.
@ -26,7 +25,7 @@ export abstract class AbstractDialogueChatBot implements IDialogueChatBot
public registerChatCommand(chatCommand: IChatCommand | ICommandoCommand): void public registerChatCommand(chatCommand: IChatCommand | ICommandoCommand): void
{ {
if (this.chatCommands.some(cc => cc.getCommandPrefix() === chatCommand.getCommandPrefix())) if (this.chatCommands.some((cc) => cc.getCommandPrefix() === chatCommand.getCommandPrefix()))
{ {
throw new Error( throw new Error(
`The command "${chatCommand.getCommandPrefix()}" attempting to be registered already exists.`, `The command "${chatCommand.getCommandPrefix()}" attempting to be registered already exists.`,
@ -49,7 +48,7 @@ export abstract class AbstractDialogueChatBot implements IDialogueChatBot
const splitCommand = request.text.split(" "); const splitCommand = request.text.split(" ");
const commandos = this.chatCommands.filter(c => c.getCommandPrefix() === splitCommand[0]); const commandos = this.chatCommands.filter((c) => c.getCommandPrefix() === splitCommand[0]);
if (commandos[0]?.getCommands().has(splitCommand[1])) if (commandos[0]?.getCommands().has(splitCommand[1]))
{ {
return commandos[0].handle(splitCommand[1], this.getChatBot(), sessionId, request); return commandos[0].handle(splitCommand[1], this.getChatBot(), sessionId, request);

View File

@ -18,18 +18,20 @@ export class SptCommandoCommands implements IChatCommand
const coreConfigs = this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE); const coreConfigs = this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE);
// if give command is disabled or commando commands are disabled // if give command is disabled or commando commands are disabled
if ( if (
!(coreConfigs.features?.chatbotFeatures?.commandoFeatures?.giveCommandEnabled !(
&& coreConfigs.features?.chatbotFeatures?.commandoEnabled) coreConfigs.features?.chatbotFeatures?.commandoFeatures?.giveCommandEnabled
&& coreConfigs.features?.chatbotFeatures?.commandoEnabled
)
) )
{ {
const giveCommand = this.sptCommands.find(c => c.getCommand().toLocaleLowerCase() === "give"); const giveCommand = this.sptCommands.find((c) => c.getCommand().toLocaleLowerCase() === "give");
this.sptCommands.splice(this.sptCommands.indexOf(giveCommand), 1); this.sptCommands.splice(this.sptCommands.indexOf(giveCommand), 1);
} }
} }
public registerSptCommandoCommand(command: ISptCommand): void public registerSptCommandoCommand(command: ISptCommand): void
{ {
if (this.sptCommands.some(c => c.getCommand() === command.getCommand())) if (this.sptCommands.some((c) => c.getCommand() === command.getCommand()))
{ {
throw new Error(`The command "${command.getCommand()}" attempting to be registered already exists.`); throw new Error(`The command "${command.getCommand()}" attempting to be registered already exists.`);
} }
@ -38,7 +40,7 @@ export class SptCommandoCommands implements IChatCommand
public getCommandHelp(command: string): string public getCommandHelp(command: string): string
{ {
return this.sptCommands.find(c => c.getCommand() === command)?.getCommandHelp(); return this.sptCommands.find((c) => c.getCommand() === command)?.getCommandHelp();
} }
public getCommandPrefix(): string public getCommandPrefix(): string
@ -48,7 +50,7 @@ export class SptCommandoCommands implements IChatCommand
public getCommands(): Set<string> public getCommands(): Set<string>
{ {
return new Set(this.sptCommands.map(c => c.getCommand())); return new Set(this.sptCommands.map((c) => c.getCommand()));
} }
public handle( public handle(
@ -58,10 +60,8 @@ export class SptCommandoCommands implements IChatCommand
request: ISendMessageRequest, request: ISendMessageRequest,
): string ): string
{ {
return this.sptCommands.find(c => c.getCommand() === command).performAction( return this.sptCommands
commandHandler, .find((c) => c.getCommand() === command)
sessionId, .performAction(commandHandler, sessionId, request);
request,
);
} }
} }

View File

@ -31,7 +31,12 @@ export class GiveSptCommand implements ISptCommand
private static commandRegex = /^spt give (((([a-z]{2,5}) )?"(.+)"|\w+) )?([0-9]+)$/; private static commandRegex = /^spt give (((([a-z]{2,5}) )?"(.+)"|\w+) )?([0-9]+)$/;
private static acceptableConfidence = 0.9; private static acceptableConfidence = 0.9;
// exception for flares // exception for flares
private static excludedPresetItems = new Set<string>(["62178c4d4ecf221597654e3d", "6217726288ed9f0845317459", "624c0b3340357b5f566e8766"]); private static excludedPresetItems = new Set<string>([
"62178c4d4ecf221597654e3d",
"6217726288ed9f0845317459",
"624c0b3340357b5f566e8766",
]);
protected savedCommand: Map<string, SavedCommand> = new Map<string, SavedCommand>(); protected savedCommand: Map<string, SavedCommand> = new Map<string, SavedCommand>();
public constructor( public constructor(
@ -45,8 +50,7 @@ export class GiveSptCommand implements ISptCommand
@inject("ItemFilterService") protected itemFilterService: ItemFilterService, @inject("ItemFilterService") protected itemFilterService: ItemFilterService,
@inject("RecursiveCloner") protected cloner: ICloner, @inject("RecursiveCloner") protected cloner: ICloner,
) )
{ {}
}
public getCommand(): string public getCommand(): string
{ {
@ -55,7 +59,7 @@ export class GiveSptCommand implements ISptCommand
public getCommandHelp(): string public getCommandHelp(): string
{ {
return "spt give\n========\nSends items to the player through the message system.\n\n\tspt give [template ID] [quantity]\n\t\tEx: spt give 544fb25a4bdc2dfb738b4567 2\n\n\tspt give [\"item name\"] [quantity]\n\t\tEx: spt give \"pack of sugar\" 10\n\n\tspt give [locale] [\"item name\"] [quantity]\n\t\tEx: spt give fr \"figurine de chat\" 3"; return 'spt give\n========\nSends items to the player through the message system.\n\n\tspt give [template ID] [quantity]\n\t\tEx: spt give 544fb25a4bdc2dfb738b4567 2\n\n\tspt give ["item name"] [quantity]\n\t\tEx: spt give "pack of sugar" 10\n\n\tspt give [locale] ["item name"] [quantity]\n\t\tEx: spt give fr "figurine de chat" 3';
} }
public performAction(commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string public performAction(commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string
@ -65,7 +69,7 @@ export class GiveSptCommand implements ISptCommand
this.mailSendService.sendUserMessageToPlayer( this.mailSendService.sendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of give command. Use \"help\" for more information.", 'Invalid use of give command. Use "help" for more information.',
); );
return request.dialogId; return request.dialogId;
} }
@ -85,7 +89,7 @@ export class GiveSptCommand implements ISptCommand
this.mailSendService.sendUserMessageToPlayer( this.mailSendService.sendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of give command. Use \"help\" for more information.", 'Invalid use of give command. Use "help" for more information.',
); );
return request.dialogId; return request.dialogId;
} }
@ -95,7 +99,7 @@ export class GiveSptCommand implements ISptCommand
this.mailSendService.sendUserMessageToPlayer( this.mailSendService.sendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid selection. Outside of bounds! Use \"help\" for more information.", 'Invalid selection. Outside of bounds! Use "help" for more information.',
); );
return request.dialogId; return request.dialogId;
} }
@ -120,7 +124,7 @@ export class GiveSptCommand implements ISptCommand
this.mailSendService.sendUserMessageToPlayer( this.mailSendService.sendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid quantity! Must be 1 or higher. Use \"help\" for more information.", 'Invalid quantity! Must be 1 or higher. Use "help" for more information.',
); );
return request.dialogId; return request.dialogId;
} }
@ -142,17 +146,19 @@ export class GiveSptCommand implements ISptCommand
locale = "en"; locale = "en";
} }
const localizedGlobal = this.databaseServer.getTables().locales.global[locale] const localizedGlobal
?? this.databaseServer.getTables().locales.global.en; = this.databaseServer.getTables().locales.global[locale]
?? this.databaseServer.getTables().locales.global.en;
const closestItemsMatchedByName = this.itemHelper.getItems() const closestItemsMatchedByName = this.itemHelper
.filter(i => this.isItemAllowed(i)) .getItems()
.map(i => localizedGlobal[`${i?._id} Name`]?.toLowerCase() ?? i._props.Name) .filter((i) => this.isItemAllowed(i))
.filter(i => i !== undefined && i !== "") .map((i) => localizedGlobal[`${i?._id} Name`]?.toLowerCase() ?? i._props.Name)
.map(i => ({ match: stringSimilarity( .filter((i) => i !== undefined && i !== "")
item.toLocaleLowerCase(), .map((i) => ({
i.toLocaleLowerCase(), match: stringSimilarity(item.toLocaleLowerCase(), i.toLocaleLowerCase()),
), itemName: i })) itemName: i,
}))
.sort((a1, a2) => a2.match - a1.match); .sort((a1, a2) => a2.match - a1.match);
if (closestItemsMatchedByName[0].match >= GiveSptCommand.acceptableConfidence) if (closestItemsMatchedByName[0].match >= GiveSptCommand.acceptableConfidence)
@ -164,11 +170,16 @@ export class GiveSptCommand implements ISptCommand
let i = 1; let i = 1;
const slicedItems = closestItemsMatchedByName.slice(0, 10); const slicedItems = closestItemsMatchedByName.slice(0, 10);
// max 10 item names and map them // max 10 item names and map them
const itemList = slicedItems.map(match => `${i++}. ${match.itemName} (conf: ${(match.match * 100).toFixed(2)})`) const itemList = slicedItems
.map((match) => `${i++}. ${match.itemName} (conf: ${(match.match * 100).toFixed(2)})`)
.join("\n"); .join("\n");
this.savedCommand.set( this.savedCommand.set(
sessionId, sessionId,
new SavedCommand(quantity, slicedItems.map(i => i.itemName), locale), new SavedCommand(
quantity,
slicedItems.map((i) => i.itemName),
locale,
),
); );
this.mailSendService.sendUserMessageToPlayer( this.mailSendService.sendUserMessageToPlayer(
sessionId, sessionId,
@ -180,14 +191,15 @@ export class GiveSptCommand implements ISptCommand
} }
} }
const localizedGlobal = this.databaseServer.getTables().locales.global[locale] const localizedGlobal
?? this.databaseServer.getTables().locales.global.en; = this.databaseServer.getTables().locales.global[locale] ?? this.databaseServer.getTables().locales.global.en;
// If item is an item name, we need to search using that item name and the locale which one we want otherwise // If item is an item name, we need to search using that item name and the locale which one we want otherwise
// item is just the tplId. // item is just the tplId.
const tplId = isItemName const tplId = isItemName
? this.itemHelper.getItems() ? this.itemHelper
.filter(i => this.isItemAllowed(i)) .getItems()
.find(i => (localizedGlobal[`${i?._id} Name`]?.toLowerCase() ?? i._props.Name) === item)._id .filter((i) => this.isItemAllowed(i))
.find((i) => (localizedGlobal[`${i?._id} Name`]?.toLowerCase() ?? i._props.Name) === item)._id
: item; : item;
const checkedItem = this.itemHelper.getItem(tplId); const checkedItem = this.itemHelper.getItem(tplId);
@ -274,13 +286,15 @@ export class GiveSptCommand implements ISptCommand
*/ */
protected isItemAllowed(templateItem: ITemplateItem): boolean protected isItemAllowed(templateItem: ITemplateItem): boolean
{ {
return templateItem._type !== "Node" return (
&& !this.itemHelper.isQuestItem(templateItem._id) templateItem._type !== "Node"
&& !this.itemFilterService.isItemBlacklisted(templateItem._id) && !this.itemHelper.isQuestItem(templateItem._id)
&& (templateItem._props?.Prefab?.path ?? "") !== "" && !this.itemFilterService.isItemBlacklisted(templateItem._id)
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.HIDEOUT_AREA_CONTAINER) && (templateItem._props?.Prefab?.path ?? "") !== ""
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.LOOT_CONTAINER) && !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.HIDEOUT_AREA_CONTAINER)
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.RANDOM_LOOT_CONTAINER) && !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.LOOT_CONTAINER)
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.MOB_CONTAINER); && !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.RANDOM_LOOT_CONTAINER)
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.MOB_CONTAINER)
);
} }
} }

View File

@ -1,6 +1,9 @@
export class SavedCommand export class SavedCommand
{ {
public constructor(public quantity: number, public potentialItemNames: string[], public locale: string) public constructor(
{ public quantity: number,
} public potentialItemNames: string[],
public locale: string,
)
{}
} }

View File

@ -37,8 +37,7 @@ export class ProfileSptCommand implements ISptCommand
@inject("DatabaseServer") protected databaseServer: DatabaseServer, @inject("DatabaseServer") protected databaseServer: DatabaseServer,
@inject("ProfileHelper") protected profileHelper: ProfileHelper, @inject("ProfileHelper") protected profileHelper: ProfileHelper,
) )
{ {}
}
public getCommand(): string public getCommand(): string
{ {
@ -57,7 +56,7 @@ export class ProfileSptCommand implements ISptCommand
this.mailSendService.sendUserMessageToPlayer( this.mailSendService.sendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of trader command. Use \"help\" for more information.", 'Invalid use of trader command. Use "help" for more information.',
); );
return request.dialogId; return request.dialogId;
} }
@ -77,7 +76,7 @@ export class ProfileSptCommand implements ISptCommand
this.mailSendService.sendUserMessageToPlayer( this.mailSendService.sendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of profile command, the level was outside bounds: 1 to 70. Use \"help\" for more information.", 'Invalid use of profile command, the level was outside bounds: 1 to 70. Use "help" for more information.',
); );
return request.dialogId; return request.dialogId;
} }
@ -85,8 +84,8 @@ export class ProfileSptCommand implements ISptCommand
break; break;
case "skill": case "skill":
{ {
const enumSkill = Object.values(SkillTypes).find(t => const enumSkill = Object.values(SkillTypes).find(
t.toLocaleLowerCase() === skill.toLocaleLowerCase(), (t) => t.toLocaleLowerCase() === skill.toLocaleLowerCase(),
); );
if (enumSkill === undefined) if (enumSkill === undefined)
@ -94,7 +93,7 @@ export class ProfileSptCommand implements ISptCommand
this.mailSendService.sendUserMessageToPlayer( this.mailSendService.sendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of profile command, the skill was not found. Use \"help\" for more information.", 'Invalid use of profile command, the skill was not found. Use "help" for more information.',
); );
return request.dialogId; return request.dialogId;
} }
@ -104,7 +103,7 @@ export class ProfileSptCommand implements ISptCommand
this.mailSendService.sendUserMessageToPlayer( this.mailSendService.sendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of profile command, the skill level was outside bounds: 1 to 51. Use \"help\" for more information.", 'Invalid use of profile command, the skill level was outside bounds: 1 to 51. Use "help" for more information.',
); );
return request.dialogId; return request.dialogId;
} }
@ -123,13 +122,15 @@ export class ProfileSptCommand implements ISptCommand
this.mailSendService.sendSystemMessageToPlayer( this.mailSendService.sendSystemMessageToPlayer(
sessionId, sessionId,
"A single ruble is being attached, required by BSG logic.", "A single ruble is being attached, required by BSG logic.",
[{ [
_id: this.hashUtil.generate(), {
_tpl: "5449016a4bdc2d6f028b456f", _id: this.hashUtil.generate(),
upd: { StackObjectsCount: 1 }, _tpl: "5449016a4bdc2d6f028b456f",
parentId: this.hashUtil.generate(), upd: { StackObjectsCount: 1 },
slotId: "main", parentId: this.hashUtil.generate(),
}], slotId: "main",
},
],
undefined, undefined,
[event], [event],
); );

View File

@ -33,8 +33,7 @@ export class TraderSptCommand implements ISptCommand
@inject("LocaleService") protected localeService: LocaleService, @inject("LocaleService") protected localeService: LocaleService,
@inject("DatabaseServer") protected databaseServer: DatabaseServer, @inject("DatabaseServer") protected databaseServer: DatabaseServer,
) )
{ {}
}
public getCommand(): string public getCommand(): string
{ {
@ -53,7 +52,7 @@ export class TraderSptCommand implements ISptCommand
this.mailSendService.sendUserMessageToPlayer( this.mailSendService.sendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of trader command. Use \"help\" for more information.", 'Invalid use of trader command. Use "help" for more information.',
); );
return request.dialogId; return request.dialogId;
} }
@ -64,15 +63,15 @@ export class TraderSptCommand implements ISptCommand
const command: string = result.groups.command; const command: string = result.groups.command;
const quantity: number = +result.groups.quantity; const quantity: number = +result.groups.quantity;
const dbTrader = Object.values(this.databaseServer.getTables().traders).find(t => const dbTrader = Object.values(this.databaseServer.getTables().traders).find(
t.base.nickname.toLocaleLowerCase() === trader.toLocaleLowerCase(), (t) => t.base.nickname.toLocaleLowerCase() === trader.toLocaleLowerCase(),
); );
if (dbTrader === undefined) if (dbTrader === undefined)
{ {
this.mailSendService.sendUserMessageToPlayer( this.mailSendService.sendUserMessageToPlayer(
sessionId, sessionId,
commandHandler, commandHandler,
"Invalid use of trader command, the trader was not found. Use \"help\" for more information.", 'Invalid use of trader command, the trader was not found. Use "help" for more information.',
); );
return request.dialogId; return request.dialogId;
} }
@ -97,13 +96,15 @@ export class TraderSptCommand implements ISptCommand
this.mailSendService.sendSystemMessageToPlayer( this.mailSendService.sendSystemMessageToPlayer(
sessionId, sessionId,
"A single ruble is being attached, required by BSG logic.", "A single ruble is being attached, required by BSG logic.",
[{ [
_id: this.hashUtil.generate(), {
_tpl: "5449016a4bdc2d6f028b456f", _id: this.hashUtil.generate(),
upd: { StackObjectsCount: 1 }, _tpl: "5449016a4bdc2d6f028b456f",
parentId: this.hashUtil.generate(), upd: { StackObjectsCount: 1 },
slotId: "main", parentId: this.hashUtil.generate(),
}], slotId: "main",
},
],
undefined, undefined,
[event], [event],
); );

View File

@ -66,7 +66,7 @@ export class DialogueHelper
const dialogueData = this.saveServer.getProfile(sessionID).dialogues; const dialogueData = this.saveServer.getProfile(sessionID).dialogues;
for (const dialogueId in dialogueData) for (const dialogueId in dialogueData)
{ {
const message = dialogueData[dialogueId].messages.find(x => x._id === messageID); const message = dialogueData[dialogueId].messages.find((x) => x._id === messageID);
if (!message) if (!message)
{ {
continue; continue;
@ -87,7 +87,7 @@ export class DialogueHelper
message.items.data = []; message.items.data = [];
} }
const rewardItemCount = message.items.data?.filter(item => item._id !== itemId); const rewardItemCount = message.items.data?.filter((item) => item._id !== itemId);
if (rewardItemCount.length === 0) if (rewardItemCount.length === 0)
{ {
message.rewardCollected = true; message.rewardCollected = true;

View File

@ -172,7 +172,7 @@ export class DurabilityLimitsHelper
const delta = this.randomUtil.getInt(minDelta, maxDelta); const delta = this.randomUtil.getInt(minDelta, maxDelta);
const result = Number((maxDurability - delta).toFixed(2)); const result = Number((maxDurability - delta).toFixed(2));
const durabilityValueMinLimit = Math.round( const durabilityValueMinLimit = Math.round(
this.getMinWeaponLimitPercentFromConfig(botRole) / 100 * maxDurability, (this.getMinWeaponLimitPercentFromConfig(botRole) / 100) * maxDurability,
); );
// Dont let weapon dura go below the percent defined in config // Dont let weapon dura go below the percent defined in config
@ -186,7 +186,7 @@ export class DurabilityLimitsHelper
const delta = this.randomUtil.getInt(minDelta, maxDelta); const delta = this.randomUtil.getInt(minDelta, maxDelta);
const result = Number((maxDurability - delta).toFixed(2)); const result = Number((maxDurability - delta).toFixed(2));
const durabilityValueMinLimit = Math.round( const durabilityValueMinLimit = Math.round(
this.getMinArmorLimitPercentFromConfig(botRole) / 100 * maxDurability, (this.getMinArmorLimitPercentFromConfig(botRole) / 100) * maxDurability,
); );
// Dont let armor dura go below the percent defined in config // Dont let armor dura go below the percent defined in config

View File

@ -56,9 +56,9 @@ export class HandbookHelper
// Add handbook overrides found in items.json config into db // Add handbook overrides found in items.json config into db
for (const itemTpl in this.itemConfig.handbookPriceOverride) for (const itemTpl in this.itemConfig.handbookPriceOverride)
{ {
let itemToUpdate = this.databaseServer.getTables().templates.handbook.Items.find(item => let itemToUpdate = this.databaseServer
item.Id === itemTpl, .getTables()
); .templates.handbook.Items.find((item) => item.Id === itemTpl);
if (!itemToUpdate) if (!itemToUpdate)
{ {
this.databaseServer.getTables().templates.handbook.Items.push({ this.databaseServer.getTables().templates.handbook.Items.push({
@ -66,9 +66,9 @@ export class HandbookHelper
ParentId: this.databaseServer.getTables().templates.items[itemTpl]._parent, ParentId: this.databaseServer.getTables().templates.items[itemTpl]._parent,
Price: this.itemConfig.handbookPriceOverride[itemTpl], Price: this.itemConfig.handbookPriceOverride[itemTpl],
}); });
itemToUpdate = this.databaseServer.getTables().templates.handbook.Items.find(item => itemToUpdate = this.databaseServer
item.Id === itemTpl, .getTables()
); .templates.handbook.Items.find((item) => item.Id === itemTpl);
} }
itemToUpdate.Price = this.itemConfig.handbookPriceOverride[itemTpl]; itemToUpdate.Price = this.itemConfig.handbookPriceOverride[itemTpl];
@ -118,7 +118,7 @@ export class HandbookHelper
return this.handbookPriceCache.items.byId.get(tpl); return this.handbookPriceCache.items.byId.get(tpl);
} }
const handbookItem = this.databaseServer.getTables().templates.handbook.Items.find(x => x.Id === tpl); const handbookItem = this.databaseServer.getTables().templates.handbook.Items.find((x) => x.Id === tpl);
if (!handbookItem) if (!handbookItem)
{ {
const newValue = 0; const newValue = 0;
@ -207,6 +207,6 @@ export class HandbookHelper
public getCategoryById(handbookId: string): Category public getCategoryById(handbookId: string): Category
{ {
return this.databaseServer.getTables().templates.handbook.Categories.find(x => x.Id === handbookId); return this.databaseServer.getTables().templates.handbook.Categories.find((x) => x.Id === handbookId);
} }
} }

View File

@ -36,7 +36,8 @@ export class HealthHelper
const profile = this.saveServer.getProfile(sessionID); const profile = this.saveServer.getProfile(sessionID);
if (!profile.vitality) if (!profile.vitality)
{ // Occurs on newly created profiles {
// Occurs on newly created profiles
profile.vitality = { health: null, effects: null }; profile.vitality = { health: null, effects: null };
} }
profile.vitality.health = { profile.vitality.health = {
@ -99,13 +100,14 @@ export class HealthHelper
profileEffects[bodyPart] = postRaidBodyParts[bodyPart].Effects; profileEffects[bodyPart] = postRaidBodyParts[bodyPart].Effects;
} }
if (request.IsAlive === true) if (request.IsAlive === true)
{ // is player alive, not is limb alive {
// is player alive, not is limb alive
profileHealth[bodyPart] = postRaidBodyParts[bodyPart].Current; profileHealth[bodyPart] = postRaidBodyParts[bodyPart].Current;
} }
else else
{ {
profileHealth[bodyPart] = pmcData.Health.BodyParts[bodyPart].Health.Maximum profileHealth[bodyPart]
* this.healthConfig.healthMultipliers.death; = pmcData.Health.BodyParts[bodyPart].Health.Maximum * this.healthConfig.healthMultipliers.death;
} }
} }

View File

@ -72,9 +72,9 @@ export class HideoutHelper
sessionID: string, sessionID: string,
): IItemEventRouterResponse ): IItemEventRouterResponse
{ {
const recipe = this.databaseServer.getTables().hideout.production.find(production => const recipe = this.databaseServer
production._id === body.recipeId, .getTables()
); .hideout.production.find((production) => production._id === body.recipeId);
if (!recipe) if (!recipe)
{ {
this.logger.error(this.localisationService.getText("hideout-missing_recipe_in_db", body.recipeId)); this.logger.error(this.localisationService.getText("hideout-missing_recipe_in_db", body.recipeId));
@ -106,7 +106,7 @@ export class HideoutHelper
for (const tool of bodyAsSingle.tools) for (const tool of bodyAsSingle.tools)
{ {
const toolItem = this.cloner.clone(pmcData.Inventory.items.find(x => x._id === tool.id)); const toolItem = this.cloner.clone(pmcData.Inventory.items.find((x) => x._id === tool.id));
// Make sure we only return as many as we took // Make sure we only return as many as we took
this.itemHelper.addUpdObjectToItem(toolItem); this.itemHelper.addUpdObjectToItem(toolItem);
@ -168,7 +168,7 @@ export class HideoutHelper
case BonusType.STASH_SIZE: case BonusType.STASH_SIZE:
{ {
// Find stash item and adjust tpl to new tpl from bonus // Find stash item and adjust tpl to new tpl from bonus
const stashItem = pmcData.Inventory.items.find(x => x._id === pmcData.Inventory.stash); const stashItem = pmcData.Inventory.items.find((x) => x._id === pmcData.Inventory.stash);
if (!stashItem) if (!stashItem)
{ {
this.logger.warning( this.logger.warning(
@ -216,18 +216,20 @@ export class HideoutHelper
* @param pmcData Player profile * @param pmcData Player profile
* @returns Properties * @returns Properties
*/ */
protected getHideoutProperties( protected getHideoutProperties(pmcData: IPmcData): {
pmcData: IPmcData, btcFarmCGs: number
): { btcFarmCGs: number, isGeneratorOn: boolean, waterCollectorHasFilter: boolean } isGeneratorOn: boolean
waterCollectorHasFilter: boolean
}
{ {
const bitcoinFarm = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.BITCOIN_FARM); const bitcoinFarm = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.BITCOIN_FARM);
const bitcoinCount = bitcoinFarm?.slots.filter(slot => slot.item).length ?? 0; // Get slots with an item property const bitcoinCount = bitcoinFarm?.slots.filter((slot) => slot.item).length ?? 0; // Get slots with an item property
const hideoutProperties = { const hideoutProperties = {
btcFarmCGs: bitcoinCount, btcFarmCGs: bitcoinCount,
isGeneratorOn: pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.GENERATOR)?.active ?? false, isGeneratorOn: pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.GENERATOR)?.active ?? false,
waterCollectorHasFilter: this.doesWaterCollectorHaveFilter( waterCollectorHasFilter: this.doesWaterCollectorHaveFilter(
pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.WATER_COLLECTOR), pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.WATER_COLLECTOR),
), ),
}; };
@ -240,7 +242,7 @@ export class HideoutHelper
if (waterCollector.level === 3) if (waterCollector.level === 3)
{ {
// Has filter in at least one slot // Has filter in at least one slot
return waterCollector.slots.some(slot => slot.item); return waterCollector.slots.some((slot) => slot.item);
} }
// No Filter // No Filter
@ -308,7 +310,7 @@ export class HideoutHelper
} }
// Other recipes not covered by above // Other recipes not covered by above
const recipe = recipes.find(r => r._id === prodId); const recipe = recipes.find((r) => r._id === prodId);
if (!recipe) if (!recipe)
{ {
this.logger.error(this.localisationService.getText("hideout-missing_recipe_for_area", prodId)); this.logger.error(this.localisationService.getText("hideout-missing_recipe_for_area", prodId));
@ -364,9 +366,8 @@ export class HideoutHelper
// Increment progress by time passed // Increment progress by time passed
const production = pmcData.Hideout.Production[prodId]; const production = pmcData.Hideout.Production[prodId];
production.Progress += production.needFuelForAllProductionTime && !hideoutProperties.isGeneratorOn production.Progress
? 0 += production.needFuelForAllProductionTime && !hideoutProperties.isGeneratorOn ? 0 : timeElapsed; // Some items NEED power to craft (e.g. DSP)
: timeElapsed; // Some items NEED power to craft (e.g. DSP)
// Limit progress to total production time if progress is over (dont run for continious crafts)) // Limit progress to total production time if progress is over (dont run for continious crafts))
if (!recipe.continuous) if (!recipe.continuous)
@ -395,8 +396,10 @@ export class HideoutHelper
*/ */
protected updateScavCaseProductionTimer(pmcData: IPmcData, productionId: string): void protected updateScavCaseProductionTimer(pmcData: IPmcData, productionId: string): void
{ {
const timeElapsed = this.timeUtil.getTimestamp() - pmcData.Hideout.Production[productionId].StartTimestamp const timeElapsed
- pmcData.Hideout.Production[productionId].Progress; = this.timeUtil.getTimestamp()
- pmcData.Hideout.Production[productionId].StartTimestamp
- pmcData.Hideout.Production[productionId].Progress;
pmcData.Hideout.Production[productionId].Progress += timeElapsed; pmcData.Hideout.Production[productionId].Progress += timeElapsed;
} }
@ -446,10 +449,11 @@ export class HideoutHelper
{ {
// 1 resource last 14 min 27 sec, 1/14.45/60 = 0.00115 // 1 resource last 14 min 27 sec, 1/14.45/60 = 0.00115
// 10-10-2021 From wiki, 1 resource last 12 minutes 38 seconds, 1/12.63333/60 = 0.00131 // 10-10-2021 From wiki, 1 resource last 12 minutes 38 seconds, 1/12.63333/60 = 0.00131
let fuelUsedSinceLastTick = this.databaseServer.getTables().hideout.settings.generatorFuelFlowRate let fuelUsedSinceLastTick
* this.getTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn); = this.databaseServer.getTables().hideout.settings.generatorFuelFlowRate
* this.getTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn);
const profileFuelConsumptionBonus = pmcData.Bonuses.find(bonus => bonus.type === BonusType.FUEL_CONSUMPTION); const profileFuelConsumptionBonus = pmcData.Bonuses.find((bonus) => bonus.type === BonusType.FUEL_CONSUMPTION);
// 0 to 1 // 0 to 1
const fuelConsumptionBonusMultipler const fuelConsumptionBonusMultipler
@ -602,9 +606,9 @@ export class HideoutHelper
{ {
const globalSkillsDb = this.databaseServer.getTables().globals.config.SkillsSettings; const globalSkillsDb = this.databaseServer.getTables().globals.config.SkillsSettings;
const recipe = this.databaseServer.getTables().hideout.production.find(production => const recipe = this.databaseServer
production._id === recipeId, .getTables()
); .hideout.production.find((production) => production._id === recipeId);
if (!recipe) if (!recipe)
{ {
this.logger.error(this.localisationService.getText("hideout-missing_recipe_in_db", recipeId)); this.logger.error(this.localisationService.getText("hideout-missing_recipe_in_db", recipeId));
@ -754,9 +758,10 @@ export class HideoutHelper
baseFilterDrainRate: number, baseFilterDrainRate: number,
): number ): number
{ {
const drainTimeSeconds = secondsSinceServerTick > totalProductionTime const drainTimeSeconds
? totalProductionTime - productionProgress // More time passed than prod time, get total minus the current progress = secondsSinceServerTick > totalProductionTime
: secondsSinceServerTick; ? totalProductionTime - productionProgress // More time passed than prod time, get total minus the current progress
: secondsSinceServerTick;
// Multiply base drain rate by time passed // Multiply base drain rate by time passed
return baseFilterDrainRate * drainTimeSeconds; return baseFilterDrainRate * drainTimeSeconds;
@ -786,9 +791,10 @@ export class HideoutHelper
); );
// Never let bonus become 0 // Never let bonus become 0
const reductionBonus = hideoutManagementConsumptionBonus + craftSkillTimeReductionMultipler === 0 const reductionBonus
? 1 = hideoutManagementConsumptionBonus + craftSkillTimeReductionMultipler === 0
: 1 - (hideoutManagementConsumptionBonus + craftSkillTimeReductionMultipler); ? 1
: 1 - (hideoutManagementConsumptionBonus + craftSkillTimeReductionMultipler);
return filterDrainRate * reductionBonus; return filterDrainRate * reductionBonus;
} }
@ -800,7 +806,7 @@ export class HideoutHelper
*/ */
protected getTotalProductionTimeSeconds(prodId: string): number protected getTotalProductionTimeSeconds(prodId: string): number
{ {
const recipe = this.databaseServer.getTables().hideout.production.find(prod => prod._id === prodId); const recipe = this.databaseServer.getTables().hideout.production.find((prod) => prod._id === prodId);
return recipe.productionTime || 0; return recipe.productionTime || 0;
} }
@ -833,8 +839,9 @@ export class HideoutHelper
Lasts for 17 hours 38 minutes and 49 seconds (23 hours 31 minutes and 45 seconds with elite hideout management skill), Lasts for 17 hours 38 minutes and 49 seconds (23 hours 31 minutes and 45 seconds with elite hideout management skill),
300/17.64694/60/60 = 0.004722 300/17.64694/60/60 = 0.004722
*/ */
let filterDrainRate = this.databaseServer.getTables().hideout.settings.airFilterUnitFlowRate let filterDrainRate
* this.getTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn); = this.databaseServer.getTables().hideout.settings.airFilterUnitFlowRate
* this.getTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn);
// Hideout management resource consumption bonus: // Hideout management resource consumption bonus:
const hideoutManagementConsumptionBonus = 1.0 - this.getHideoutManagementConsumptionBonus(pmcData); const hideoutManagementConsumptionBonus = 1.0 - this.getHideoutManagementConsumptionBonus(pmcData);
@ -888,9 +895,9 @@ export class HideoutHelper
protected updateBitcoinFarm(pmcData: IPmcData, btcFarmCGs: number, isGeneratorOn: boolean): Production protected updateBitcoinFarm(pmcData: IPmcData, btcFarmCGs: number, isGeneratorOn: boolean): Production
{ {
const btcProd = pmcData.Hideout.Production[HideoutHelper.bitcoinFarm]; const btcProd = pmcData.Hideout.Production[HideoutHelper.bitcoinFarm];
const bitcoinProdData = this.databaseServer.getTables().hideout.production.find(production => const bitcoinProdData = this.databaseServer
production._id === HideoutHelper.bitcoinProductionId, .getTables()
); .hideout.production.find((production) => production._id === HideoutHelper.bitcoinProductionId);
const coinSlotCount = this.getBTCSlots(pmcData); const coinSlotCount = this.getBTCSlots(pmcData);
// Full on bitcoins, halt progress // Full on bitcoins, halt progress
@ -1024,9 +1031,9 @@ export class HideoutHelper
*/ */
protected getBTCSlots(pmcData: IPmcData): number protected getBTCSlots(pmcData: IPmcData): number
{ {
const bitcoinProductions = this.databaseServer.getTables().hideout.production.find(production => const bitcoinProductions = this.databaseServer
production._id === HideoutHelper.bitcoinFarm, .getTables()
); .hideout.production.find((production) => production._id === HideoutHelper.bitcoinFarm);
const productionSlots = bitcoinProductions?.productionLimitCount || 3; // Default to 3 if none found const productionSlots = bitcoinProductions?.productionLimitCount || 3; // Default to 3 if none found
const hasManagementSkillSlots = this.profileHelper.hasEliteSkillLevel(SkillTypes.HIDEOUT_MANAGEMENT, pmcData); const hasManagementSkillSlots = this.profileHelper.hasEliteSkillLevel(SkillTypes.HIDEOUT_MANAGEMENT, pmcData);
const managementSlotsCount = this.getEliteSkillAdditionalBitcoinSlotCount() || 2; const managementSlotsCount = this.getEliteSkillAdditionalBitcoinSlotCount() || 2;
@ -1063,9 +1070,12 @@ export class HideoutHelper
let roundedLevel = Math.floor(hideoutManagementSkill.Progress / 100); let roundedLevel = Math.floor(hideoutManagementSkill.Progress / 100);
roundedLevel = roundedLevel === 51 ? roundedLevel - 1 : roundedLevel; roundedLevel = roundedLevel === 51 ? roundedLevel - 1 : roundedLevel;
return roundedLevel return (
* this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement (roundedLevel
.ConsumptionReductionPerLevel / 100; * this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement
.ConsumptionReductionPerLevel)
/ 100
);
} }
/** /**
@ -1089,7 +1099,7 @@ export class HideoutHelper
let roundedLevel = Math.floor(profileSkill.Progress / 100); let roundedLevel = Math.floor(profileSkill.Progress / 100);
roundedLevel = roundedLevel === 51 ? roundedLevel - 1 : roundedLevel; roundedLevel = roundedLevel === 51 ? roundedLevel - 1 : roundedLevel;
return roundedLevel * valuePerLevel / 100; return (roundedLevel * valuePerLevel) / 100;
} }
/** /**
@ -1146,11 +1156,13 @@ export class HideoutHelper
const itemsToAdd: Item[][] = []; const itemsToAdd: Item[][] = [];
for (let index = 0; index < craftedCoinCount; index++) for (let index = 0; index < craftedCoinCount; index++)
{ {
itemsToAdd.push([{ itemsToAdd.push([
_id: this.hashUtil.generate(), {
_tpl: HideoutHelper.bitcoinTpl, _id: this.hashUtil.generate(),
upd: { StackObjectsCount: 1 }, _tpl: HideoutHelper.bitcoinTpl,
}]); upd: { StackObjectsCount: 1 },
},
]);
} }
// Create request for what we want to add to stash // Create request for what we want to add to stash
@ -1187,9 +1199,9 @@ export class HideoutHelper
*/ */
public unlockHideoutWallInProfile(pmcProfile: IPmcData): void public unlockHideoutWallInProfile(pmcProfile: IPmcData): void
{ {
const waterCollector = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WATER_COLLECTOR); const waterCollector = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WATER_COLLECTOR);
const medStation = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.MEDSTATION); const medStation = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.MEDSTATION);
const wall = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.EMERGENCY_WALL); const wall = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.EMERGENCY_WALL);
// No collector or med station, skip // No collector or med station, skip
if (!(waterCollector && medStation)) if (!(waterCollector && medStation))
@ -1239,29 +1251,29 @@ export class HideoutHelper
*/ */
public applyPlaceOfFameDogtagBonus(pmcData: IPmcData): void public applyPlaceOfFameDogtagBonus(pmcData: IPmcData): void
{ {
const fameAreaProfile = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.PLACE_OF_FAME); const fameAreaProfile = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.PLACE_OF_FAME);
// Get hideout area 16 bonus array // Get hideout area 16 bonus array
const fameAreaDb = this.databaseServer.getTables().hideout.areas.find(area => const fameAreaDb = this.databaseServer
area.type === HideoutAreas.PLACE_OF_FAME, .getTables()
); .hideout.areas.find((area) => area.type === HideoutAreas.PLACE_OF_FAME);
// Get SkillGroupLevelingBoost object // Get SkillGroupLevelingBoost object
const combatBoostBonusDb = fameAreaDb.stages[fameAreaProfile.level].bonuses.find(bonus => const combatBoostBonusDb = fameAreaDb.stages[fameAreaProfile.level].bonuses.find(
bonus.type === "SkillGroupLevelingBoost", (bonus) => bonus.type === "SkillGroupLevelingBoost",
); );
// Get SkillGroupLevelingBoost object in profile // Get SkillGroupLevelingBoost object in profile
const combatBonusProfile = pmcData.Bonuses.find(bonus => bonus.id === combatBoostBonusDb.id); const combatBonusProfile = pmcData.Bonuses.find((bonus) => bonus.id === combatBoostBonusDb.id);
// Get all slotted dogtag items // Get all slotted dogtag items
const activeDogtags = pmcData.Inventory.items.filter(item => item?.slotId?.startsWith("dogtag")); const activeDogtags = pmcData.Inventory.items.filter((item) => item?.slotId?.startsWith("dogtag"));
// Calculate bonus percent (apply hideoutManagement bonus) // Calculate bonus percent (apply hideoutManagement bonus)
const hideoutManagementSkill = this.profileHelper.getSkillFromProfile(pmcData, SkillTypes.HIDEOUT_MANAGEMENT); const hideoutManagementSkill = this.profileHelper.getSkillFromProfile(pmcData, SkillTypes.HIDEOUT_MANAGEMENT);
const hideoutManagementSkillBonusPercent = 1 + hideoutManagementSkill.Progress / 10000; // 5100 becomes 0.51, add 1 to it, 1.51 const hideoutManagementSkillBonusPercent = 1 + hideoutManagementSkill.Progress / 10000; // 5100 becomes 0.51, add 1 to it, 1.51
const bonus = this.getDogtagCombatSkillBonusPercent(pmcData, activeDogtags) const bonus
* hideoutManagementSkillBonusPercent; = this.getDogtagCombatSkillBonusPercent(pmcData, activeDogtags) * hideoutManagementSkillBonusPercent;
// Update bonus value to above calcualted value // Update bonus value to above calcualted value
combatBonusProfile.value = Number.parseFloat(bonus.toFixed(2)); combatBonusProfile.value = Number.parseFloat(bonus.toFixed(2));

View File

@ -4,7 +4,7 @@ import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
import { PaymentHelper } from "@spt-aki/helpers/PaymentHelper"; import { PaymentHelper } from "@spt-aki/helpers/PaymentHelper";
import { QuestHelper } from "@spt-aki/helpers/QuestHelper"; import { QuestHelper } from "@spt-aki/helpers/QuestHelper";
import { IPmcData, IPostRaidPmcData } from "@spt-aki/models/eft/common/IPmcData"; import { IPmcData, IPostRaidPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { IQuestStatus, TraderInfo, Victim } from "@spt-aki/models/eft/common/tables/IBotBase"; import { IQuestStatus, TraderInfo } from "@spt-aki/models/eft/common/tables/IBotBase";
import { Item } from "@spt-aki/models/eft/common/tables/IItem"; import { Item } from "@spt-aki/models/eft/common/tables/IItem";
import { ISaveProgressRequestData } from "@spt-aki/models/eft/inRaid/ISaveProgressRequestData"; import { ISaveProgressRequestData } from "@spt-aki/models/eft/inRaid/ISaveProgressRequestData";
import { IFailQuestRequestData } from "@spt-aki/models/eft/quests/IFailQuestRequestData"; import { IFailQuestRequestData } from "@spt-aki/models/eft/quests/IFailQuestRequestData";
@ -67,7 +67,7 @@ export class InRaidHelper
*/ */
public addUpdToMoneyFromRaid(items: Item[]): void public addUpdToMoneyFromRaid(items: Item[]): void
{ {
for (const moneyItem of items.filter(item => this.paymentHelper.isMoneyTpl(item._tpl))) for (const moneyItem of items.filter((item) => this.paymentHelper.isMoneyTpl(item._tpl)))
{ {
this.itemHelper.addUpdObjectToItem(moneyItem); this.itemHelper.addUpdObjectToItem(moneyItem);
@ -128,7 +128,10 @@ export class InRaidHelper
} }
/** Check counters are correct in profile */ /** Check counters are correct in profile */
protected validateTaskConditionCounters(saveProgressRequest: ISaveProgressRequestData, profileData: IPmcData): void protected validateTaskConditionCounters(
saveProgressRequest: ISaveProgressRequestData,
profileData: IPmcData,
): void
{ {
for (const backendCounterKey in saveProgressRequest.profile.TaskConditionCounters) for (const backendCounterKey in saveProgressRequest.profile.TaskConditionCounters)
{ {
@ -203,12 +206,12 @@ export class InRaidHelper
): void ): void
{ {
// Only copy active quests into scav profile // Progress will later to copied over to PMC profile // Only copy active quests into scav profile // Progress will later to copied over to PMC profile
const existingActiveQuestIds = scavData.Quests?.filter( const existingActiveQuestIds = scavData.Quests?.filter((x) => x.status !== QuestStatus.AvailableForStart).map(
x => x.status !== QuestStatus.AvailableForStart, (x) => x.qid,
).map(x => x.qid); );
if (existingActiveQuestIds) if (existingActiveQuestIds)
{ {
scavData.Quests = saveProgressRequest.profile.Quests.filter(x => existingActiveQuestIds.includes(x.qid)); scavData.Quests = saveProgressRequest.profile.Quests.filter((x) => existingActiveQuestIds.includes(x.qid));
} }
this.profileFixerService.checkForAndFixScavProfileIssues(scavData); this.profileFixerService.checkForAndFixScavProfileIssues(scavData);
@ -240,10 +243,10 @@ export class InRaidHelper
for (const postRaidQuest of postRaidProfile.Quests) for (const postRaidQuest of postRaidProfile.Quests)
{ {
// postRaidQuest.status has a weird value, need to do some nasty casting to compare it // postRaidQuest.status has a weird value, need to do some nasty casting to compare it
const postRaidQuestStatus = <string><unknown>postRaidQuest.status; const postRaidQuestStatus = <string>(<unknown>postRaidQuest.status);
// Find matching pre-raid quest, skip if we can't // Find matching pre-raid quest, skip if we can't
const preRaidQuest = preRaidQuests?.find(preRaidQuest => preRaidQuest.qid === postRaidQuest.qid); const preRaidQuest = preRaidQuests?.find((preRaidQuest) => preRaidQuest.qid === postRaidQuest.qid);
if (!preRaidQuest) if (!preRaidQuest)
{ {
continue; continue;
@ -269,7 +272,8 @@ export class InRaidHelper
// Quest with time-gate has unlocked // Quest with time-gate has unlocked
if ( if (
postRaidQuestStatus === "AvailableAfter" && postRaidQuest.availableAfter <= this.timeUtil.getTimestamp() postRaidQuestStatus === "AvailableAfter"
&& postRaidQuest.availableAfter <= this.timeUtil.getTimestamp()
) )
{ {
// Flag as ready to start // Flag as ready to start
@ -298,8 +302,8 @@ export class InRaidHelper
// Does failed quest have requirement to collect items from raid // Does failed quest have requirement to collect items from raid
const questDbData = this.questHelper.getQuestFromDb(postRaidQuest.qid, pmcData); const questDbData = this.questHelper.getQuestFromDb(postRaidQuest.qid, pmcData);
// AvailableForFinish // AvailableForFinish
const matchingAffFindConditions = questDbData.conditions.AvailableForFinish.filter(condition => const matchingAffFindConditions = questDbData.conditions.AvailableForFinish.filter(
condition.conditionType === "FindItem", (condition) => condition.conditionType === "FindItem",
); );
const itemsToCollect: string[] = []; const itemsToCollect: string[] = [];
if (matchingAffFindConditions) if (matchingAffFindConditions)
@ -314,7 +318,7 @@ export class InRaidHelper
// Remove quest items from profile as quest has failed and may still be alive // Remove quest items from profile as quest has failed and may still be alive
// Required as restarting the quest from main menu does not remove value from CarriedQuestItems array // Required as restarting the quest from main menu does not remove value from CarriedQuestItems array
postRaidProfile.Stats.Eft.CarriedQuestItems = postRaidProfile.Stats.Eft.CarriedQuestItems.filter( postRaidProfile.Stats.Eft.CarriedQuestItems = postRaidProfile.Stats.Eft.CarriedQuestItems.filter(
carriedQuestItem => !itemsToCollect.includes(carriedQuestItem), (carriedQuestItem) => !itemsToCollect.includes(carriedQuestItem),
); );
// Remove quest item from profile now quest is failed // Remove quest item from profile now quest is failed
@ -322,8 +326,8 @@ export class InRaidHelper
for (const itemTpl of itemsToCollect) for (const itemTpl of itemsToCollect)
{ {
// Look for sessioncounter and remove it // Look for sessioncounter and remove it
const counterIndex = postRaidProfile.Stats.Eft.SessionCounters.Items.findIndex(x => const counterIndex = postRaidProfile.Stats.Eft.SessionCounters.Items.findIndex(
x.Key.includes(itemTpl) && x.Key.includes("LootItem"), (x) => x.Key.includes(itemTpl) && x.Key.includes("LootItem"),
); );
if (counterIndex > -1) if (counterIndex > -1)
{ {
@ -331,7 +335,7 @@ export class InRaidHelper
} }
// Look for quest item and remove it // Look for quest item and remove it
const inventoryItemIndex = postRaidProfile.Inventory.items.findIndex(x => x._tpl === itemTpl); const inventoryItemIndex = postRaidProfile.Inventory.items.findIndex((x) => x._tpl === itemTpl);
if (inventoryItemIndex > -1) if (inventoryItemIndex > -1)
{ {
postRaidProfile.Inventory.items.splice(inventoryItemIndex, 1); postRaidProfile.Inventory.items.splice(inventoryItemIndex, 1);
@ -454,10 +458,15 @@ export class InRaidHelper
const itemsToRemovePropertyFrom = postRaidProfile.Inventory.items.filter((x) => const itemsToRemovePropertyFrom = postRaidProfile.Inventory.items.filter((x) =>
{ {
// Has upd object + upd.SpawnedInSession property + not a quest item // Has upd object + upd.SpawnedInSession property + not a quest item
return "upd" in x && "SpawnedInSession" in x.upd return (
&& !dbItems[x._tpl]._props.QuestItem "upd" in x
&& !(this.inRaidConfig.keepFiRSecureContainerOnDeath && "SpawnedInSession" in x.upd
&& this.itemHelper.itemIsInsideContainer(x, "SecuredContainer", postRaidProfile.Inventory.items)); && !dbItems[x._tpl]._props.QuestItem
&& !(
this.inRaidConfig.keepFiRSecureContainerOnDeath
&& this.itemHelper.itemIsInsideContainer(x, "SecuredContainer", postRaidProfile.Inventory.items)
)
);
}); });
for (const item of itemsToRemovePropertyFrom) for (const item of itemsToRemovePropertyFrom)
@ -502,7 +511,7 @@ export class InRaidHelper
public deleteInventory(pmcData: IPmcData, sessionId: string): void public deleteInventory(pmcData: IPmcData, sessionId: string): void
{ {
// Get inventory item ids to remove from players profile // Get inventory item ids to remove from players profile
const itemIdsToDeleteFromProfile = this.getInventoryItemsLostOnDeath(pmcData).map(item => item._id); const itemIdsToDeleteFromProfile = this.getInventoryItemsLostOnDeath(pmcData).map((item) => item._id);
for (const itemIdToDelete of itemIdsToDeleteFromProfile) for (const itemIdToDelete of itemIdsToDeleteFromProfile)
{ {
// Items inside containers are handled as part of function // Items inside containers are handled as part of function
@ -555,13 +564,13 @@ export class InRaidHelper
*/ */
protected getBaseItemsInRigPocketAndBackpack(pmcData: IPmcData): Item[] protected getBaseItemsInRigPocketAndBackpack(pmcData: IPmcData): Item[]
{ {
const rig = pmcData.Inventory.items.find(x => x.slotId === "TacticalVest"); const rig = pmcData.Inventory.items.find((x) => x.slotId === "TacticalVest");
const pockets = pmcData.Inventory.items.find(x => x.slotId === "Pockets"); const pockets = pmcData.Inventory.items.find((x) => x.slotId === "Pockets");
const backpack = pmcData.Inventory.items.find(x => x.slotId === "Backpack"); const backpack = pmcData.Inventory.items.find((x) => x.slotId === "Backpack");
const baseItemsInRig = pmcData.Inventory.items.filter(x => x.parentId === rig?._id); const baseItemsInRig = pmcData.Inventory.items.filter((x) => x.parentId === rig?._id);
const baseItemsInPockets = pmcData.Inventory.items.filter(x => x.parentId === pockets?._id); const baseItemsInPockets = pmcData.Inventory.items.filter((x) => x.parentId === pockets?._id);
const baseItemsInBackpack = pmcData.Inventory.items.filter(x => x.parentId === backpack?._id); const baseItemsInBackpack = pmcData.Inventory.items.filter((x) => x.parentId === backpack?._id);
return [...baseItemsInRig, ...baseItemsInPockets, ...baseItemsInBackpack]; return [...baseItemsInRig, ...baseItemsInPockets, ...baseItemsInBackpack];
} }

View File

@ -23,7 +23,6 @@ import { BackendErrorCodes } from "@spt-aki/models/enums/BackendErrorCodes";
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses"; import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
import { BonusType } from "@spt-aki/models/enums/BonusType"; import { BonusType } from "@spt-aki/models/enums/BonusType";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
import { Traders } from "@spt-aki/models/enums/Traders";
import { IInventoryConfig, RewardDetails } from "@spt-aki/models/spt/config/IInventoryConfig"; import { IInventoryConfig, RewardDetails } from "@spt-aki/models/spt/config/IInventoryConfig";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { ConfigServer } from "@spt-aki/servers/ConfigServer"; import { ConfigServer } from "@spt-aki/servers/ConfigServer";
@ -167,9 +166,8 @@ export class InventoryHelper
catch (err) catch (err)
{ {
// Callback failed // Callback failed
const message = typeof err?.message === "string" const message
? err.message = typeof err?.message === "string" ? err.message : this.localisationService.getText("http-unknown_error");
: this.localisationService.getText("http-unknown_error");
this.httpResponse.appendErrorToOutput(output, message); this.httpResponse.appendErrorToOutput(output, message);
@ -520,13 +518,15 @@ export class InventoryHelper
if (requestItem.count > itemDetails._props.StackMaxSize) if (requestItem.count > itemDetails._props.StackMaxSize)
{ {
let remainingCountOfItemToAdd = requestItem.count; let remainingCountOfItemToAdd = requestItem.count;
const calc = requestItem.count const calc
- Math.floor(requestItem.count / itemDetails._props.StackMaxSize) = requestItem.count
* itemDetails._props.StackMaxSize; - Math.floor(requestItem.count / itemDetails._props.StackMaxSize)
* itemDetails._props.StackMaxSize;
maxStackCount = calc > 0 maxStackCount
? maxStackCount + Math.floor(remainingCountOfItemToAdd / itemDetails._props.StackMaxSize) = calc > 0
: Math.floor(remainingCountOfItemToAdd / itemDetails._props.StackMaxSize); ? maxStackCount + Math.floor(remainingCountOfItemToAdd / itemDetails._props.StackMaxSize)
: Math.floor(remainingCountOfItemToAdd / itemDetails._props.StackMaxSize);
// Iterate until totalCountOfPurchasedItem is 0 // Iterate until totalCountOfPurchasedItem is 0
for (let i = 0; i < maxStackCount; i++) for (let i = 0; i < maxStackCount; i++)
@ -597,7 +597,7 @@ export class InventoryHelper
{ {
// We expect that each inventory item and each insured item has unique "_id", respective "itemId". // We expect that each inventory item and each insured item has unique "_id", respective "itemId".
// Therefore we want to use a NON-Greedy function and escape the iteration as soon as we find requested item. // Therefore we want to use a NON-Greedy function and escape the iteration as soon as we find requested item.
const inventoryIndex = inventoryItems.findIndex(item => item._id === childId); const inventoryIndex = inventoryItems.findIndex((item) => item._id === childId);
if (inventoryIndex > -1) if (inventoryIndex > -1)
{ {
inventoryItems.splice(inventoryIndex, 1); inventoryItems.splice(inventoryIndex, 1);
@ -610,7 +610,7 @@ export class InventoryHelper
); );
} }
const insuredIndex = insuredItems.findIndex(item => item.itemId === childId); const insuredIndex = insuredItems.findIndex((item) => item.itemId === childId);
if (insuredIndex > -1) if (insuredIndex > -1)
{ {
insuredItems.splice(insuredIndex, 1); insuredItems.splice(insuredIndex, 1);
@ -636,7 +636,7 @@ export class InventoryHelper
const dialogs = Object.values(fullProfile.dialogues); const dialogs = Object.values(fullProfile.dialogues);
for (const dialog of dialogs) for (const dialog of dialogs)
{ {
const messageWithReward = dialog.messages.find(x => x._id === removeRequest.fromOwner.id); const messageWithReward = dialog.messages.find((x) => x._id === removeRequest.fromOwner.id);
if (messageWithReward) if (messageWithReward)
{ {
// Find item + any possible children and remove them from mails items array // Find item + any possible children and remove them from mails items array
@ -876,7 +876,9 @@ export class InventoryHelper
*/ */
protected getBlankContainerMap(containerH: number, containerY: number): number[][] protected getBlankContainerMap(containerH: number, containerY: number): number[][]
{ {
return Array(containerY).fill(0).map(() => Array(containerH).fill(0)); return Array(containerY)
.fill(0)
.map(() => Array(containerH).fill(0));
} }
/** /**
@ -909,12 +911,14 @@ export class InventoryHelper
const iW = tmpSize[0]; // x const iW = tmpSize[0]; // x
const iH = tmpSize[1]; // y const iH = tmpSize[1]; // y
const fH const fH
= (item.location as Location).r === 1 || (item.location as Location).r === "Vertical" = (item.location as Location).r === 1
|| (item.location as Location).r === "Vertical"
|| (item.location as Location).rotation === "Vertical" || (item.location as Location).rotation === "Vertical"
? iW ? iW
: iH; : iH;
const fW const fW
= (item.location as Location).r === 1 || (item.location as Location).r === "Vertical" = (item.location as Location).r === 1
|| (item.location as Location).r === "Vertical"
|| (item.location as Location).rotation === "Vertical" || (item.location as Location).rotation === "Vertical"
? iH ? iH
: iW; : iW;
@ -1078,7 +1082,7 @@ export class InventoryHelper
protected getPlayerStashSize(sessionID: string): Record<number, number> protected getPlayerStashSize(sessionID: string): Record<number, number>
{ {
const profile = this.profileHelper.getPmcProfile(sessionID); const profile = this.profileHelper.getPmcProfile(sessionID);
const stashRowBonus = profile.Bonuses.find(bonus => bonus.type === BonusType.STASH_ROWS); const stashRowBonus = profile.Bonuses.find((bonus) => bonus.type === BonusType.STASH_ROWS);
// this sets automatically a stash size from items.json (its not added anywhere yet cause we still use base stash) // this sets automatically a stash size from items.json (its not added anywhere yet cause we still use base stash)
const stashTPL = this.getStashType(sessionID); const stashTPL = this.getStashType(sessionID);
@ -1118,7 +1122,7 @@ export class InventoryHelper
protected getStashType(sessionID: string): string protected getStashType(sessionID: string): string
{ {
const pmcData = this.profileHelper.getPmcProfile(sessionID); const pmcData = this.profileHelper.getPmcProfile(sessionID);
const stashObj = pmcData.Inventory.items.find(item => item._id === pmcData.Inventory.stash); const stashObj = pmcData.Inventory.items.find((item) => item._id === pmcData.Inventory.stash);
if (!stashObj) if (!stashObj)
{ {
this.logger.error(this.localisationService.getText("inventory-unable_to_find_stash")); this.logger.error(this.localisationService.getText("inventory-unable_to_find_stash"));
@ -1140,7 +1144,7 @@ export class InventoryHelper
const idsToMove = this.itemHelper.findAndReturnChildrenByItems(fromItems, body.item); const idsToMove = this.itemHelper.findAndReturnChildrenByItems(fromItems, body.item);
for (const itemId of idsToMove) for (const itemId of idsToMove)
{ {
const itemToMove = fromItems.find(x => x._id === itemId); const itemToMove = fromItems.find((x) => x._id === itemId);
if (!itemToMove) if (!itemToMove)
{ {
this.logger.error(`Unable to find item to move: ${itemId}`); this.logger.error(`Unable to find item to move: ${itemId}`);
@ -1188,7 +1192,7 @@ export class InventoryHelper
this.handleCartridges(inventoryItems, moveRequest); this.handleCartridges(inventoryItems, moveRequest);
// Find item we want to 'move' // Find item we want to 'move'
const matchingInventoryItem = inventoryItems.find(x => x._id === moveRequest.item); const matchingInventoryItem = inventoryItems.find((x) => x._id === moveRequest.item);
if (!matchingInventoryItem) if (!matchingInventoryItem)
{ {
const errorMesage = `Unable to move item: ${moveRequest.item}, cannot find in inventory`; const errorMesage = `Unable to move item: ${moveRequest.item}, cannot find in inventory`;
@ -1248,7 +1252,7 @@ export class InventoryHelper
if (pmcData.Inventory.fastPanel[itemKey] === itemBeingMoved._id) if (pmcData.Inventory.fastPanel[itemKey] === itemBeingMoved._id)
{ {
// Get moved items parent // Get moved items parent
const itemParent = pmcData.Inventory.items.find(x => x._id === itemBeingMoved.parentId); const itemParent = pmcData.Inventory.items.find((x) => x._id === itemBeingMoved.parentId);
// Empty out id if item is moved to a container other than pocket/rig // Empty out id if item is moved to a container other than pocket/rig
if (itemParent && !(itemParent.slotId?.startsWith("Pockets") || itemParent.slotId === "TacticalVest")) if (itemParent && !(itemParent.slotId?.startsWith("Pockets") || itemParent.slotId === "TacticalVest"))
@ -1317,7 +1321,7 @@ export class InventoryHelper
return true; return true;
} }
container = pmcData.Inventory.items.find(item => item._id === container.parentId); container = pmcData.Inventory.items.find((item) => item._id === container.parentId);
if (!container) if (!container)
{ {
break; break;

View File

@ -68,7 +68,7 @@ export class ItemHelper
} }
for (const itemOf1 of item1) for (const itemOf1 of item1)
{ {
const itemOf2 = item2.find(i2 => i2._tpl === itemOf1._tpl); const itemOf2 = item2.find((i2) => i2._tpl === itemOf1._tpl);
if (itemOf2 === undefined) if (itemOf2 === undefined)
{ {
return false; return false;
@ -98,7 +98,7 @@ export class ItemHelper
if (compareUpdProperties) if (compareUpdProperties)
{ {
return Array.from(compareUpdProperties.values()).every(p => return Array.from(compareUpdProperties.values()).every((p) =>
this.compareUtil.recursiveCompare(item1.upd?.[p], item2.upd?.[p]), this.compareUtil.recursiveCompare(item1.upd?.[p], item2.upd?.[p]),
); );
} }
@ -194,11 +194,13 @@ export class ItemHelper
return false; return false;
} }
return !itemDetails[1]._props.QuestItem return (
&& itemDetails[1]._type === "Item" !itemDetails[1]._props.QuestItem
&& baseTypes.every(x => !this.isOfBaseclass(tpl, x)) && itemDetails[1]._type === "Item"
&& this.getItemPrice(tpl) > 0 && baseTypes.every((x) => !this.isOfBaseclass(tpl, x))
&& !this.itemFilterService.isItemBlacklisted(tpl); && this.getItemPrice(tpl) > 0
&& !this.itemFilterService.isItemBlacklisted(tpl)
);
} }
/** /**
@ -261,7 +263,7 @@ export class ItemHelper
const itemTemplate = this.getItem(itemTpl); const itemTemplate = this.getItem(itemTpl);
const plateSlotIds = this.getRemovablePlateSlotIds(); const plateSlotIds = this.getRemovablePlateSlotIds();
return itemTemplate[1]._props.Slots.some(slot => plateSlotIds.includes(slot._name.toLowerCase())); return itemTemplate[1]._props.Slots.some((slot) => plateSlotIds.includes(slot._name.toLowerCase()));
} }
/** /**
@ -292,7 +294,7 @@ export class ItemHelper
// Check if item has slots that match soft insert name ids // Check if item has slots that match soft insert name ids
const softInsertIds = this.getSoftInsertSlotIds(); const softInsertIds = this.getSoftInsertSlotIds();
if (itemDbDetails[1]._props.Slots.find(slot => softInsertIds.includes(slot._name.toLowerCase()))) if (itemDbDetails[1]._props.Slots.find((slot) => softInsertIds.includes(slot._name.toLowerCase())))
{ {
return true; return true;
} }
@ -629,7 +631,7 @@ export class ItemHelper
} }
// Items parentid matches root item AND returned items doesnt contain current child // Items parentid matches root item AND returned items doesnt contain current child
if (childItem.parentId === baseItemId && !list.find(item => childItem._id === item._id)) if (childItem.parentId === baseItemId && !list.find((item) => childItem._id === item._id))
{ {
list.push(...this.findAndReturnChildrenAsItems(items, childItem._id)); list.push(...this.findAndReturnChildrenAsItems(items, childItem._id));
} }
@ -650,7 +652,7 @@ export class ItemHelper
for (const itemFromAssort of assort) for (const itemFromAssort of assort)
{ {
if (itemFromAssort.parentId === itemIdToFind && !list.find(item => itemFromAssort._id === item._id)) if (itemFromAssort.parentId === itemIdToFind && !list.find((item) => itemFromAssort._id === item._id))
{ {
list.push(itemFromAssort); list.push(itemFromAssort);
list = list.concat(this.findAndReturnChildrenByAssort(itemFromAssort._id, assort)); list = list.concat(this.findAndReturnChildrenByAssort(itemFromAssort._id, assort));
@ -798,9 +800,8 @@ export class ItemHelper
public findBarterItems(by: "tpl" | "id", itemsToSearch: Item[], desiredBarterItemIds: string | string[]): Item[] public findBarterItems(by: "tpl" | "id", itemsToSearch: Item[], desiredBarterItemIds: string | string[]): Item[]
{ {
// Find required items to take after buying (handles multiple items) // Find required items to take after buying (handles multiple items)
const desiredBarterIds = typeof desiredBarterItemIds === "string" const desiredBarterIds
? [desiredBarterItemIds] = typeof desiredBarterItemIds === "string" ? [desiredBarterItemIds] : desiredBarterItemIds;
: desiredBarterItemIds;
const matchingItems: Item[] = []; const matchingItems: Item[] = [];
for (const barterId of desiredBarterIds) for (const barterId of desiredBarterIds)
@ -846,7 +847,7 @@ export class ItemHelper
if (pmcData !== null) if (pmcData !== null)
{ {
// Insured items should not be renamed. Only works for PMCs. // Insured items should not be renamed. Only works for PMCs.
if (insuredItems?.find(insuredItem => insuredItem.itemId === item._id)) if (insuredItems?.find((insuredItem) => insuredItem.itemId === item._id))
{ {
continue; continue;
} }
@ -1054,8 +1055,8 @@ export class ItemHelper
let isRequiredSlot = false; let isRequiredSlot = false;
if (parentTemplate[0] && parentTemplate[1]?._props?.Slots) if (parentTemplate[0] && parentTemplate[1]?._props?.Slots)
{ {
isRequiredSlot = parentTemplate[1]._props.Slots.some(slot => isRequiredSlot = parentTemplate[1]._props.Slots.some(
slot._name === item.slotId && slot._required, (slot) => slot._name === item.slotId && slot._required,
); );
} }
@ -1100,11 +1101,13 @@ export class ItemHelper
*/ */
public isAttachmentAttached(item: Item): boolean public isAttachmentAttached(item: Item): boolean
{ {
const equipmentSlots = Object.values(EquipmentSlots).map(value => value as string); const equipmentSlots = Object.values(EquipmentSlots).map((value) => value as string);
return !(["hideout", "main"].includes(item.slotId) return !(
|| equipmentSlots.includes(item.slotId) ["hideout", "main"].includes(item.slotId)
|| !Number.isNaN(Number(item.slotId))); || equipmentSlots.includes(item.slotId)
|| !Number.isNaN(Number(item.slotId))
);
} }
/** /**
@ -1125,7 +1128,7 @@ export class ItemHelper
public getEquipmentParent(itemId: string, itemsMap: Map<string, Item>): Item | null public getEquipmentParent(itemId: string, itemsMap: Map<string, Item>): Item | null
{ {
let currentItem = itemsMap.get(itemId); let currentItem = itemsMap.get(itemId);
const equipmentSlots = Object.values(EquipmentSlots).map(value => value as string); const equipmentSlots = Object.values(EquipmentSlots).map((value) => value as string);
while (currentItem && !equipmentSlots.includes(currentItem.slotId)) while (currentItem && !equipmentSlots.includes(currentItem.slotId))
{ {
@ -1146,7 +1149,7 @@ export class ItemHelper
*/ */
public getItemSize(items: Item[], rootItemId: string): ItemHelper.ItemSize public getItemSize(items: Item[], rootItemId: string): ItemHelper.ItemSize
{ {
const rootTemplate = this.getItem(items.filter(x => x._id === rootItemId)[0]._tpl)[1]; const rootTemplate = this.getItem(items.filter((x) => x._id === rootItemId)[0]._tpl)[1];
const width = rootTemplate._props.Width; const width = rootTemplate._props.Width;
const height = rootTemplate._props.Height; const height = rootTemplate._props.Height;
@ -1178,9 +1181,8 @@ export class ItemHelper
sizeUp = sizeUp < itemTemplate._props.ExtraSizeUp ? itemTemplate._props.ExtraSizeUp : sizeUp; sizeUp = sizeUp < itemTemplate._props.ExtraSizeUp ? itemTemplate._props.ExtraSizeUp : sizeUp;
sizeDown = sizeDown < itemTemplate._props.ExtraSizeDown ? itemTemplate._props.ExtraSizeDown : sizeDown; sizeDown = sizeDown < itemTemplate._props.ExtraSizeDown ? itemTemplate._props.ExtraSizeDown : sizeDown;
sizeLeft = sizeLeft < itemTemplate._props.ExtraSizeLeft ? itemTemplate._props.ExtraSizeLeft : sizeLeft; sizeLeft = sizeLeft < itemTemplate._props.ExtraSizeLeft ? itemTemplate._props.ExtraSizeLeft : sizeLeft;
sizeRight = sizeRight < itemTemplate._props.ExtraSizeRight sizeRight
? itemTemplate._props.ExtraSizeRight = sizeRight < itemTemplate._props.ExtraSizeRight ? itemTemplate._props.ExtraSizeRight : sizeRight;
: sizeRight;
} }
} }
@ -1221,7 +1223,7 @@ export class ItemHelper
const cartridgeMaxStackSize = cartridgeDetails[1]._props.StackMaxSize; const cartridgeMaxStackSize = cartridgeDetails[1]._props.StackMaxSize;
// Exit if ammo already exists in box // Exit if ammo already exists in box
if (ammoBox.find(item => item._tpl === cartridgeTpl)) if (ammoBox.find((item) => item._tpl === cartridgeTpl))
{ {
return; return;
} }
@ -1289,7 +1291,7 @@ export class ItemHelper
public itemIsInsideContainer(item: Item, desiredContainerSlotId: string, items: Item[]): boolean public itemIsInsideContainer(item: Item, desiredContainerSlotId: string, items: Item[]): boolean
{ {
// Get items parent // Get items parent
const parent = items.find(x => x._id === item.parentId); const parent = items.find((x) => x._id === item.parentId);
if (!parent) if (!parent)
{ {
// No parent, end of line, not inside container // No parent, end of line, not inside container
@ -1394,9 +1396,8 @@ export class ItemHelper
while (currentStoredCartridgeCount < desiredStackCount) while (currentStoredCartridgeCount < desiredStackCount)
{ {
// Get stack size of cartridges // Get stack size of cartridges
let cartridgeCountToAdd = desiredStackCount <= cartridgeMaxStackSize let cartridgeCountToAdd
? desiredStackCount = desiredStackCount <= cartridgeMaxStackSize ? desiredStackCount : cartridgeMaxStackSize;
: cartridgeMaxStackSize;
// Ensure we don't go over the max stackcount size // Ensure we don't go over the max stackcount size
const remainingSpace = desiredStackCount - currentStoredCartridgeCount; const remainingSpace = desiredStackCount - currentStoredCartridgeCount;
@ -1437,9 +1438,9 @@ export class ItemHelper
const ammoTpls = magTemplate._props.Cartridges[0]._props.filters[0].Filter; const ammoTpls = magTemplate._props.Cartridges[0]._props.filters[0].Filter;
const calibers = [ const calibers = [
...new Set( ...new Set(
ammoTpls.filter((x: string) => this.getItem(x)[0]).map((x: string) => ammoTpls
this.getItem(x)[1]._props.Caliber, .filter((x: string) => this.getItem(x)[0])
), .map((x: string) => this.getItem(x)[1]._props.Caliber),
), ),
]; ];
return this.randomUtil.drawRandomFromList(calibers)[0]; return this.randomUtil.drawRandomFromList(calibers)[0];
@ -1555,9 +1556,9 @@ export class ItemHelper
public getItemTplsOfBaseType(desiredBaseType: string): string[] public getItemTplsOfBaseType(desiredBaseType: string): string[]
{ {
return Object.values(this.databaseServer.getTables().templates.items).filter(x => return Object.values(this.databaseServer.getTables().templates.items)
x._parent === desiredBaseType, .filter((x) => x._parent === desiredBaseType)
).map(x => x._id); .map((x) => x._id);
} }
/** /**
@ -1771,7 +1772,7 @@ export class ItemHelper
for (const item of items) for (const item of items)
{ {
// Check if the item's parent exists. // Check if the item's parent exists.
const parentExists = items.some(parentItem => parentItem._id === item.parentId); const parentExists = items.some((parentItem) => parentItem._id === item.parentId);
// If the parent does not exist and the item is not already a 'hideout' item, adopt the orphaned item by // If the parent does not exist and the item is not already a 'hideout' item, adopt the orphaned item by
// setting the parent ID to the PMCs inventory equipment ID, the slot ID to 'hideout', and remove the location. // setting the parent ID to the PMCs inventory equipment ID, the slot ID to 'hideout', and remove the location.

View File

@ -86,9 +86,10 @@ export class NotificationSendHelper
protected getDialog(sessionId: string, messageType: MessageType, senderDetails: IUserDialogInfo): Dialogue protected getDialog(sessionId: string, messageType: MessageType, senderDetails: IUserDialogInfo): Dialogue
{ {
// Use trader id if sender is trader, otherwise use nickname // Use trader id if sender is trader, otherwise use nickname
const key = senderDetails.Info.MemberCategory === MemberCategory.TRADER const key
? senderDetails._id = senderDetails.Info.MemberCategory === MemberCategory.TRADER
: senderDetails.Info.Nickname; ? senderDetails._id
: senderDetails.Info.Nickname;
const dialogueData = this.saveServer.getProfile(sessionId).dialogues; const dialogueData = this.saveServer.getProfile(sessionId).dialogues;
const isNewDialogue = !(key in dialogueData); const isNewDialogue = !(key in dialogueData);
let dialogue: Dialogue = dialogueData[key]; let dialogue: Dialogue = dialogueData[key];

View File

@ -21,8 +21,8 @@ export class PaymentHelper
*/ */
public isMoneyTpl(tpl: string): boolean public isMoneyTpl(tpl: string): boolean
{ {
return [Money.DOLLARS, Money.EUROS, Money.ROUBLES, ...this.inventoryConfig.customMoneyTpls].some(element => return [Money.DOLLARS, Money.EUROS, Money.ROUBLES, ...this.inventoryConfig.customMoneyTpls].some(
element === tpl, (element) => element === tpl,
); );
} }

View File

@ -44,11 +44,9 @@ export class PresetHelper
{ {
if (!this.defaultWeaponPresets) if (!this.defaultWeaponPresets)
{ {
this.defaultWeaponPresets = Object.values( this.defaultWeaponPresets = Object.values(this.databaseServer.getTables().globals.ItemPresets)
this.databaseServer.getTables().globals.ItemPresets,
)
.filter( .filter(
preset => (preset) =>
preset._encyclopedia !== undefined preset._encyclopedia !== undefined
&& this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON), && this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON),
) )
@ -71,9 +69,12 @@ export class PresetHelper
if (!this.defaultEquipmentPresets) if (!this.defaultEquipmentPresets)
{ {
this.defaultEquipmentPresets = Object.values(this.databaseServer.getTables().globals.ItemPresets) this.defaultEquipmentPresets = Object.values(this.databaseServer.getTables().globals.ItemPresets)
.filter(preset => preset._encyclopedia !== undefined .filter(
&& this.itemHelper.armorItemCanHoldMods(preset._encyclopedia), (preset) =>
).reduce((acc, cur) => preset._encyclopedia !== undefined
&& this.itemHelper.armorItemCanHoldMods(preset._encyclopedia),
)
.reduce((acc, cur) =>
{ {
acc[cur._id] = cur; acc[cur._id] = cur;
return acc; return acc;
@ -186,7 +187,7 @@ export class PresetHelper
const defaultPreset = this.getDefaultPreset(tpl); const defaultPreset = this.getDefaultPreset(tpl);
// Bundle up tpls we want price for // Bundle up tpls we want price for
const tpls = defaultPreset ? defaultPreset._items.map(item => item._tpl) : [tpl]; const tpls = defaultPreset ? defaultPreset._items.map((item) => item._tpl) : [tpl];
// Get price of tpls // Get price of tpls
return this.itemHelper.getItemAndChildrenPrice(tpls); return this.itemHelper.getItemAndChildrenPrice(tpls);

View File

@ -52,7 +52,7 @@ export class ProfileHelper
for (const questId in questConditionId) for (const questId in questConditionId)
{ {
const conditionId = questConditionId[questId]; const conditionId = questConditionId[questId];
const profileQuest = pmcData.Quests.find(x => x.qid === questId); const profileQuest = pmcData.Quests.find((x) => x.qid === questId);
// Find index of condition in array // Find index of condition in array
const index = profileQuest.completedConditions.indexOf(conditionId); const index = profileQuest.completedConditions.indexOf(conditionId);
@ -339,7 +339,7 @@ export class ProfileHelper
public removeSecureContainer(profile: IPmcData): IPmcData public removeSecureContainer(profile: IPmcData): IPmcData
{ {
const items = profile.Inventory.items; const items = profile.Inventory.items;
const secureContainer = items.find(x => x.slotId === "SecuredContainer"); const secureContainer = items.find((x) => x.slotId === "SecuredContainer");
if (secureContainer) if (secureContainer)
{ {
// Find and remove container + children // Find and remove container + children
@ -349,7 +349,7 @@ export class ProfileHelper
); );
// Remove child items + secure container // Remove child items + secure container
profile.Inventory.items = items.filter(x => !childItemsInSecureContainer.includes(x._id)); profile.Inventory.items = items.filter((x) => !childItemsInSecureContainer.includes(x._id));
} }
return profile; return profile;
@ -393,7 +393,7 @@ export class ProfileHelper
return false; return false;
} }
return !!profile.aki.receivedGifts.find(x => x.giftId === giftId); return !!profile.aki.receivedGifts.find((x) => x.giftId === giftId);
} }
/** /**
@ -403,7 +403,7 @@ export class ProfileHelper
*/ */
public incrementStatCounter(counters: CounterKeyValue[], keyToIncrement: string): void public incrementStatCounter(counters: CounterKeyValue[], keyToIncrement: string): void
{ {
const stat = counters.find(x => x.Key.includes(keyToIncrement)); const stat = counters.find((x) => x.Key.includes(keyToIncrement));
if (stat) if (stat)
{ {
stat.Value++; stat.Value++;
@ -424,7 +424,7 @@ export class ProfileHelper
return false; return false;
} }
const profileSkill = profileSkills.find(x => x.Id === skillType); const profileSkill = profileSkills.find((x) => x.Id === skillType);
if (!profileSkill) if (!profileSkill)
{ {
this.logger.warning(`Unable to check for elite skill ${skillType}, not found in profile`); this.logger.warning(`Unable to check for elite skill ${skillType}, not found in profile`);
@ -466,7 +466,7 @@ export class ProfileHelper
return; return;
} }
const profileSkill = profileSkills.find(profileSkill => profileSkill.Id === skill); const profileSkill = profileSkills.find((profileSkill) => profileSkill.Id === skill);
if (!profileSkill) if (!profileSkill)
{ {
this.logger.error(this.localisationService.getText("quest-no_skill_found", skill)); this.logger.error(this.localisationService.getText("quest-no_skill_found", skill));
@ -499,7 +499,7 @@ export class ProfileHelper
*/ */
public getSkillFromProfile(pmcData: IPmcData, skill: SkillTypes): Common public getSkillFromProfile(pmcData: IPmcData, skill: SkillTypes): Common
{ {
const skillToReturn = pmcData.Skills.Common.find(commonSkill => commonSkill.Id === skill); const skillToReturn = pmcData.Skills.Common.find((commonSkill) => commonSkill.Id === skill);
if (!skillToReturn) if (!skillToReturn)
{ {
this.logger.warning(`Profile ${pmcData.sessionId} does not have a skill named: ${skill}`); this.logger.warning(`Profile ${pmcData.sessionId} does not have a skill named: ${skill}`);
@ -527,7 +527,7 @@ export class ProfileHelper
public addStashRowsBonusToProfile(sessionId: string, rowsToAdd: number): void public addStashRowsBonusToProfile(sessionId: string, rowsToAdd: number): void
{ {
const profile = this.getPmcProfile(sessionId); const profile = this.getPmcProfile(sessionId);
const existingBonus = profile.Bonuses.find(bonus => bonus.type === BonusType.STASH_ROWS); const existingBonus = profile.Bonuses.find((bonus) => bonus.type === BonusType.STASH_ROWS);
if (!existingBonus) if (!existingBonus)
{ {
profile.Bonuses.push({ profile.Bonuses.push({

View File

@ -11,7 +11,6 @@ import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { Common, IQuestStatus } from "@spt-aki/models/eft/common/tables/IBotBase"; import { Common, IQuestStatus } from "@spt-aki/models/eft/common/tables/IBotBase";
import { Item } from "@spt-aki/models/eft/common/tables/IItem"; import { Item } from "@spt-aki/models/eft/common/tables/IItem";
import { IQuest, IQuestCondition, IQuestReward } from "@spt-aki/models/eft/common/tables/IQuest"; import { IQuest, IQuestCondition, IQuestReward } from "@spt-aki/models/eft/common/tables/IQuest";
import { IRepeatableQuest } from "@spt-aki/models/eft/common/tables/IRepeatableQuests";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse"; import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
import { IAcceptQuestRequestData } from "@spt-aki/models/eft/quests/IAcceptQuestRequestData"; import { IAcceptQuestRequestData } from "@spt-aki/models/eft/quests/IAcceptQuestRequestData";
import { IFailQuestRequestData } from "@spt-aki/models/eft/quests/IFailQuestRequestData"; import { IFailQuestRequestData } from "@spt-aki/models/eft/quests/IFailQuestRequestData";
@ -69,7 +68,7 @@ export class QuestHelper
*/ */
public getQuestStatus(pmcData: IPmcData, questId: string): QuestStatus public getQuestStatus(pmcData: IPmcData, questId: string): QuestStatus
{ {
const quest = pmcData.Quests?.find(q => q.qid === questId); const quest = pmcData.Quests?.find((q) => q.qid === questId);
return quest ? quest.status : QuestStatus.Locked; return quest ? quest.status : QuestStatus.Locked;
} }
@ -150,7 +149,7 @@ export class QuestHelper
} }
// This calculates how much progress we have in the skill's starting level // This calculates how much progress we have in the skill's starting level
let startingLevelProgress = profileSkill.Progress % 100 * ((currentLevel + 1) / 10); let startingLevelProgress = (profileSkill.Progress % 100) * ((currentLevel + 1) / 10);
// The code below assumes a 1/10th progress skill amount // The code below assumes a 1/10th progress skill amount
let remainingProgress = progressAmount / 10; let remainingProgress = progressAmount / 10;
@ -164,7 +163,7 @@ export class QuestHelper
const currentLevelRemainingProgress = (currentLevel + 1) * 10 - startingLevelProgress; const currentLevelRemainingProgress = (currentLevel + 1) * 10 - startingLevelProgress;
this.logger.debug(`currentLevelRemainingProgress: ${currentLevelRemainingProgress}`); this.logger.debug(`currentLevelRemainingProgress: ${currentLevelRemainingProgress}`);
const progressToAdd = Math.min(remainingProgress, currentLevelRemainingProgress); const progressToAdd = Math.min(remainingProgress, currentLevelRemainingProgress);
const adjustedProgressToAdd = 10 / (currentLevel + 1) * progressToAdd; const adjustedProgressToAdd = (10 / (currentLevel + 1)) * progressToAdd;
this.logger.debug(`Progress To Add: ${progressToAdd} Adjusted for level: ${adjustedProgressToAdd}`); this.logger.debug(`Progress To Add: ${progressToAdd} Adjusted for level: ${adjustedProgressToAdd}`);
// Add the progress amount adjusted by level // Add the progress amount adjusted by level
@ -286,10 +285,13 @@ export class QuestHelper
// Is root item, fix stacks // Is root item, fix stacks
if (rewardItem._id === questReward.target) if (rewardItem._id === questReward.target)
{ // Is base reward item {
// Is base reward item
if ( if (
rewardItem.parentId !== undefined && rewardItem.parentId === "hideout" // Has parentId of hideout rewardItem.parentId !== undefined
&& rewardItem.upd !== undefined && rewardItem.upd.StackObjectsCount !== undefined // Has upd with stackobject count && rewardItem.parentId === "hideout" // Has parentId of hideout
&& rewardItem.upd !== undefined
&& rewardItem.upd.StackObjectsCount !== undefined // Has upd with stackobject count
&& rewardItem.upd.StackObjectsCount > 1 // More than 1 item in stack && rewardItem.upd.StackObjectsCount > 1 // More than 1 item in stack
) )
{ {
@ -353,7 +355,7 @@ export class QuestHelper
questReward.items = presetAndMods; questReward.items = presetAndMods;
// Find root item and set its stack count // Find root item and set its stack count
const rootItem = questReward.items.find(item => item._id === newRootId); const rootItem = questReward.items.find((item) => item._id === newRootId);
// Remap target id to the new presets root id // Remap target id to the new presets root id
questReward.target = rootItem._id; questReward.target = rootItem._id;
@ -385,7 +387,7 @@ export class QuestHelper
{ {
// Iterate over all rewards with the desired status, flatten out items that have a type of Item // Iterate over all rewards with the desired status, flatten out items that have a type of Item
const questRewards = quest.rewards[QuestStatus[status]].flatMap((reward: IQuestReward) => const questRewards = quest.rewards[QuestStatus[status]].flatMap((reward: IQuestReward) =>
(reward.type === "Item" ? this.processReward(reward) : []), reward.type === "Item" ? this.processReward(reward) : [],
); );
return questRewards; return questRewards;
@ -404,7 +406,7 @@ export class QuestHelper
): IQuestStatus ): IQuestStatus
{ {
const currentTimestamp = this.timeUtil.getTimestamp(); const currentTimestamp = this.timeUtil.getTimestamp();
const existingQuest = pmcData.Quests.find(q => q.qid === acceptedQuest.qid); const existingQuest = pmcData.Quests.find((q) => q.qid === acceptedQuest.qid);
if (existingQuest) if (existingQuest)
{ {
// Quest exists, update its status // Quest exists, update its status
@ -436,7 +438,7 @@ export class QuestHelper
this.logger.error(`Quest: ${acceptedQuest.qid} of type: ${acceptedQuest.type} not found`); this.logger.error(`Quest: ${acceptedQuest.qid} of type: ${acceptedQuest.type} not found`);
} }
const waitTime = questDbData?.conditions.AvailableForStart.find(x => x.availableAfter > 0); const waitTime = questDbData?.conditions.AvailableForStart.find((x) => x.availableAfter > 0);
if (waitTime && acceptedQuest.type !== "repeatable") if (waitTime && acceptedQuest.type !== "repeatable")
{ {
// Quest should be put into 'pending' state // Quest should be put into 'pending' state
@ -463,7 +465,7 @@ export class QuestHelper
{ {
// Get quest acceptance data from profile // Get quest acceptance data from profile
const profile: IPmcData = this.profileHelper.getPmcProfile(sessionID); const profile: IPmcData = this.profileHelper.getPmcProfile(sessionID);
const startedQuestInProfile = profile.Quests.find(profileQuest => profileQuest.qid === startedQuestId); const startedQuestInProfile = profile.Quests.find((profileQuest) => profileQuest.qid === startedQuestId);
// Get quests that // Get quests that
const eligibleQuests = this.getQuestsFromDb().filter((quest) => const eligibleQuests = this.getQuestsFromDb().filter((quest) =>
@ -472,9 +474,11 @@ export class QuestHelper
// e.g. Quest A passed in, quest B is looped over and has requirement of A to be started, include it // e.g. Quest A passed in, quest B is looped over and has requirement of A to be started, include it
const acceptedQuestCondition = quest.conditions.AvailableForStart.find((x) => const acceptedQuestCondition = quest.conditions.AvailableForStart.find((x) =>
{ {
return x.conditionType === "Quest" return (
&& x.target?.includes(startedQuestId) x.conditionType === "Quest"
&& x.status?.includes(QuestStatus.Started); && x.target?.includes(startedQuestId)
&& x.status?.includes(QuestStatus.Started)
);
}); });
// Not found, skip quest // Not found, skip quest
@ -512,8 +516,10 @@ export class QuestHelper
} }
// Include if quest found in profile and is started or ready to hand in // Include if quest found in profile and is started or ready to hand in
return startedQuestInProfile return (
&& [QuestStatus.Started, QuestStatus.AvailableForFinish].includes(startedQuestInProfile.status); startedQuestInProfile
&& [QuestStatus.Started, QuestStatus.AvailableForFinish].includes(startedQuestInProfile.status)
);
}); });
return this.getQuestsWithOnlyLevelRequirementStartCondition(eligibleQuests); return this.getQuestsWithOnlyLevelRequirementStartCondition(eligibleQuests);
@ -551,15 +557,15 @@ export class QuestHelper
public failedUnlocked(failedQuestId: string, sessionId: string): IQuest[] public failedUnlocked(failedQuestId: string, sessionId: string): IQuest[]
{ {
const profile = this.profileHelper.getPmcProfile(sessionId); const profile = this.profileHelper.getPmcProfile(sessionId);
const profileQuest = profile.Quests.find(x => x.qid === failedQuestId); const profileQuest = profile.Quests.find((x) => x.qid === failedQuestId);
const quests = this.getQuestsFromDb().filter((q) => const quests = this.getQuestsFromDb().filter((q) =>
{ {
const acceptedQuestCondition = q.conditions.AvailableForStart.find((c) => const acceptedQuestCondition = q.conditions.AvailableForStart.find((c) =>
{ {
return c.conditionType === "Quest" return (
&& c.target.includes(failedQuestId) c.conditionType === "Quest" && c.target.includes(failedQuestId) && c.status[0] === QuestStatus.Fail
&& c.status[0] === QuestStatus.Fail; );
}); });
if (!acceptedQuestCondition) if (!acceptedQuestCondition)
@ -595,7 +601,7 @@ export class QuestHelper
if (this.paymentHelper.isMoneyTpl(reward.items[0]._tpl)) if (this.paymentHelper.isMoneyTpl(reward.items[0]._tpl))
{ {
reward.items[0].upd.StackObjectsCount += Math.round( reward.items[0].upd.StackObjectsCount += Math.round(
reward.items[0].upd.StackObjectsCount * multiplier / 100, (reward.items[0].upd.StackObjectsCount * multiplier) / 100,
); );
} }
} }
@ -621,7 +627,7 @@ export class QuestHelper
output: IItemEventRouterResponse, output: IItemEventRouterResponse,
): void ): void
{ {
const inventoryItemIndex = pmcData.Inventory.items.findIndex(item => item._id === itemId); const inventoryItemIndex = pmcData.Inventory.items.findIndex((item) => item._id === itemId);
if (inventoryItemIndex < 0) if (inventoryItemIndex < 0)
{ {
this.logger.error(this.localisationService.getText("quest-item_not_found_in_inventory", itemId)); this.logger.error(this.localisationService.getText("quest-item_not_found_in_inventory", itemId));
@ -692,8 +698,8 @@ export class QuestHelper
public getQuestWithOnlyLevelRequirementStartCondition(quest: IQuest): IQuest public getQuestWithOnlyLevelRequirementStartCondition(quest: IQuest): IQuest
{ {
const updatedQuest = this.cloner.clone(quest); const updatedQuest = this.cloner.clone(quest);
updatedQuest.conditions.AvailableForStart = updatedQuest.conditions.AvailableForStart.filter(q => updatedQuest.conditions.AvailableForStart = updatedQuest.conditions.AvailableForStart.filter(
q.conditionType === "Level", (q) => q.conditionType === "Level",
); );
return updatedQuest; return updatedQuest;
@ -734,9 +740,9 @@ export class QuestHelper
const quest = this.getQuestFromDb(failRequest.qid, pmcData); const quest = this.getQuestFromDb(failRequest.qid, pmcData);
// Merge all daily/weekly/scav daily quests into one array and look for the matching quest by id // Merge all daily/weekly/scav daily quests into one array and look for the matching quest by id
const matchingRepeatableQuest = pmcData.RepeatableQuests.flatMap(repeatableType => const matchingRepeatableQuest = pmcData.RepeatableQuests.flatMap(
repeatableType.activeQuests, (repeatableType) => repeatableType.activeQuests,
).find(activeQuest => activeQuest._id === failRequest.qid); ).find((activeQuest) => activeQuest._id === failRequest.qid);
// Quest found and no repeatable found // Quest found and no repeatable found
if (quest && !matchingRepeatableQuest) if (quest && !matchingRepeatableQuest)
@ -783,7 +789,7 @@ export class QuestHelper
// Check daily/weekly objects // Check daily/weekly objects
for (const repeatableType of pmcData.RepeatableQuests) for (const repeatableType of pmcData.RepeatableQuests)
{ {
quest = <IQuest><unknown>repeatableType.activeQuests.find(x => x._id === questId); quest = <IQuest>(<unknown>repeatableType.activeQuests.find((x) => x._id === questId));
if (quest) if (quest)
{ {
break; break;
@ -805,7 +811,9 @@ export class QuestHelper
// blank or is a guid, use description instead // blank or is a guid, use description instead
const startedMessageText = this.getQuestLocaleIdFromDb(startedMessageTextId); const startedMessageText = this.getQuestLocaleIdFromDb(startedMessageTextId);
if ( if (
!startedMessageText || startedMessageText.trim() === "" || startedMessageText.toLowerCase() === "test" !startedMessageText
|| startedMessageText.trim() === ""
|| startedMessageText.toLowerCase() === "test"
|| startedMessageText.length === 24 || startedMessageText.length === 24
) )
{ {
@ -835,7 +843,7 @@ export class QuestHelper
public updateQuestState(pmcData: IPmcData, newQuestState: QuestStatus, questId: string): void public updateQuestState(pmcData: IPmcData, newQuestState: QuestStatus, questId: string): void
{ {
// Find quest in profile, update status to desired status // Find quest in profile, update status to desired status
const questToUpdate = pmcData.Quests.find(quest => quest.qid === questId); const questToUpdate = pmcData.Quests.find((quest) => quest.qid === questId);
if (questToUpdate) if (questToUpdate)
{ {
questToUpdate.status = newQuestState; questToUpdate.status = newQuestState;
@ -851,7 +859,7 @@ export class QuestHelper
*/ */
public resetQuestState(pmcData: IPmcData, newQuestState: QuestStatus, questId: string): void public resetQuestState(pmcData: IPmcData, newQuestState: QuestStatus, questId: string): void
{ {
const questToUpdate = pmcData.Quests.find(quest => quest.qid === questId); const questToUpdate = pmcData.Quests.find((quest) => quest.qid === questId);
if (questToUpdate) if (questToUpdate)
{ {
const currentTimestamp = this.timeUtil.getTimestamp(); const currentTimestamp = this.timeUtil.getTimestamp();
@ -994,10 +1002,11 @@ export class QuestHelper
{ {
// Get hideout crafts and find those that match by areatype/required level/end product tpl - hope for just one match // Get hideout crafts and find those that match by areatype/required level/end product tpl - hope for just one match
const hideoutProductions = this.databaseServer.getTables().hideout.production; const hideoutProductions = this.databaseServer.getTables().hideout.production;
const matchingProductions = hideoutProductions.filter(x => const matchingProductions = hideoutProductions.filter(
x.areaType === Number.parseInt(craftUnlockReward.traderId) (x) =>
&& x.requirements.some(x => x.requiredLevel === craftUnlockReward.loyaltyLevel) x.areaType === Number.parseInt(craftUnlockReward.traderId)
&& x.endProduct === craftUnlockReward.items[0]._tpl, && x.requirements.some((x) => x.requiredLevel === craftUnlockReward.loyaltyLevel)
&& x.endProduct === craftUnlockReward.items[0]._tpl,
); );
// More/less than 1 match, above filtering wasn't strict enough // More/less than 1 match, above filtering wasn't strict enough
@ -1027,7 +1036,7 @@ export class QuestHelper
protected getQuestMoneyRewardBonus(pmcData: IPmcData): number protected getQuestMoneyRewardBonus(pmcData: IPmcData): number
{ {
// Check player has intel center // Check player has intel center
const moneyRewardBonuses = pmcData.Bonuses.filter(x => x.type === "QuestMoneyReward"); const moneyRewardBonuses = pmcData.Bonuses.filter((x) => x.type === "QuestMoneyReward");
if (!moneyRewardBonuses) if (!moneyRewardBonuses)
{ {
return 0; return 0;
@ -1061,15 +1070,15 @@ export class QuestHelper
const result: Record<string, string> = {}; const result: Record<string, string> = {};
for (const questId of questIds) for (const questId of questIds)
{ {
const questInDb = allQuests.find(x => x._id === questId); const questInDb = allQuests.find((x) => x._id === questId);
if (!questInDb) if (!questInDb)
{ {
this.logger.debug(`Unable to find quest: ${questId} in db, cannot get 'FindItem' condition, skipping`); this.logger.debug(`Unable to find quest: ${questId} in db, cannot get 'FindItem' condition, skipping`);
continue; continue;
} }
const condition = questInDb.conditions.AvailableForFinish.find(c => const condition = questInDb.conditions.AvailableForFinish.find(
c.conditionType === "FindItem" && c?.target?.includes(itemTpl), (c) => c.conditionType === "FindItem" && c?.target?.includes(itemTpl),
); );
if (condition) if (condition)
{ {
@ -1095,7 +1104,7 @@ export class QuestHelper
{ {
// Quest from db matches quests in profile, skip // Quest from db matches quests in profile, skip
const questData = quests[questIdKey]; const questData = quests[questIdKey];
if (pmcProfile.Quests.find(x => x.qid === questData._id)) if (pmcProfile.Quests.find((x) => x.qid === questData._id))
{ {
continue; continue;
} }
@ -1115,10 +1124,10 @@ export class QuestHelper
availableAfter: 0, availableAfter: 0,
}; };
if (pmcProfile.Quests.some(x => x.qid === questIdKey)) if (pmcProfile.Quests.some((x) => x.qid === questIdKey))
{ {
// Update existing // Update existing
const existingQuest = pmcProfile.Quests.find(x => x.qid === questIdKey); const existingQuest = pmcProfile.Quests.find((x) => x.qid === questIdKey);
existingQuest.status = questRecordToAdd.status; existingQuest.status = questRecordToAdd.status;
existingQuest.statusTimers = questRecordToAdd.statusTimers; existingQuest.statusTimers = questRecordToAdd.statusTimers;
} }
@ -1132,7 +1141,7 @@ export class QuestHelper
public findAndRemoveQuestFromArrayIfExists(questId: string, quests: IQuestStatus[]): void public findAndRemoveQuestFromArrayIfExists(questId: string, quests: IQuestStatus[]): void
{ {
const pmcQuestToReplaceStatus = quests.find(quest => quest.qid === questId); const pmcQuestToReplaceStatus = quests.find((quest) => quest.qid === questId);
if (pmcQuestToReplaceStatus) if (pmcQuestToReplaceStatus)
{ {
quests.splice(quests.indexOf(pmcQuestToReplaceStatus), 1); quests.splice(quests.indexOf(pmcQuestToReplaceStatus), 1);
@ -1155,7 +1164,7 @@ export class QuestHelper
return false; return false;
} }
return quest.conditions.Fail.some(condition => condition.target?.includes(completedQuestId)); return quest.conditions.Fail.some((condition) => condition.target?.includes(completedQuestId));
}); });
} }
} }

View File

@ -156,7 +156,7 @@ export class RagfairHelper
for (let item of items) for (let item of items)
{ {
item = this.itemHelper.fixItemStackCount(item); item = this.itemHelper.fixItemStackCount(item);
const isChild = items.find(it => it._id === item.parentId); const isChild = items.find((it) => it._id === item.parentId);
if (!isChild) if (!isChild)
{ {

View File

@ -14,7 +14,6 @@ import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEve
import { IAkiProfile, ISystemData } from "@spt-aki/models/eft/profile/IAkiProfile"; import { IAkiProfile, ISystemData } from "@spt-aki/models/eft/profile/IAkiProfile";
import { IRagfairOffer } from "@spt-aki/models/eft/ragfair/IRagfairOffer"; import { IRagfairOffer } from "@spt-aki/models/eft/ragfair/IRagfairOffer";
import { ISearchRequestData, OfferOwnerType } from "@spt-aki/models/eft/ragfair/ISearchRequestData"; import { ISearchRequestData, OfferOwnerType } from "@spt-aki/models/eft/ragfair/ISearchRequestData";
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
import { MemberCategory } from "@spt-aki/models/enums/MemberCategory"; import { MemberCategory } from "@spt-aki/models/enums/MemberCategory";
import { MessageType } from "@spt-aki/models/enums/MessageType"; import { MessageType } from "@spt-aki/models/enums/MessageType";
@ -185,7 +184,7 @@ export class RagfairOfferHelper
const lockedOffers = this.getLoyaltyLockedOffers(possibleOffers, pmcData); const lockedOffers = this.getLoyaltyLockedOffers(possibleOffers, pmcData);
// Exclude locked offers + above loyalty locked offers if at least 1 was found // Exclude locked offers + above loyalty locked offers if at least 1 was found
const availableOffers = possibleOffers.filter(x => !(x.locked || lockedOffers.includes(x._id))); const availableOffers = possibleOffers.filter((x) => !(x.locked || lockedOffers.includes(x._id)));
if (availableOffers.length > 0) if (availableOffers.length > 0)
{ {
possibleOffers = availableOffers; possibleOffers = availableOffers;
@ -220,8 +219,8 @@ export class RagfairOfferHelper
*/ */
public traderOfferItemQuestLocked(offer: IRagfairOffer, traderAssorts: Record<string, ITraderAssort>): boolean public traderOfferItemQuestLocked(offer: IRagfairOffer, traderAssorts: Record<string, ITraderAssort>): boolean
{ {
return offer.items?.some(i => return offer.items?.some((i) =>
traderAssorts[offer.user.id].barter_scheme[i._id]?.some(bs1 => bs1?.some(bs2 => bs2.sptQuestLocked)), traderAssorts[offer.user.id].barter_scheme[i._id]?.some((bs1) => bs1?.some((bs2) => bs2.sptQuestLocked)),
); );
} }
@ -248,15 +247,15 @@ export class RagfairOfferHelper
protected traderBuyRestrictionReached(offer: IRagfairOffer): boolean protected traderBuyRestrictionReached(offer: IRagfairOffer): boolean
{ {
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items; const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items;
const assortData = traderAssorts.find(x => x._id === offer.items[0]._id); const assortData = traderAssorts.find((x) => x._id === offer.items[0]._id);
// No trader assort data // No trader assort data
if (!assortData) if (!assortData)
{ {
this.logger.warning( this.logger.warning(
`Unable to find trader: ${offer.user.nickname} assort for item: ${ `Unable to find trader: ${offer.user.nickname} assort for item: ${this.itemHelper.getItemName(
this.itemHelper.getItemName(offer.items[0]._tpl) offer.items[0]._tpl,
} ${offer.items[0]._tpl}, cannot check if buy restriction reached`, )} ${offer.items[0]._tpl}, cannot check if buy restriction reached`,
); );
return false; return false;
} }
@ -333,7 +332,7 @@ export class RagfairOfferHelper
this.increaseProfileRagfairRating( this.increaseProfileRagfairRating(
this.saveServer.getProfile(sessionID), this.saveServer.getProfile(sessionID),
offer.summaryCost / totalItemsCount * boughtAmount, (offer.summaryCost / totalItemsCount) * boughtAmount,
); );
this.completeOffer(sessionID, offer, boughtAmount); this.completeOffer(sessionID, offer, boughtAmount);
@ -361,7 +360,7 @@ export class RagfairOfferHelper
return; return;
} }
profile.characters.pmc.RagfairInfo.rating profile.characters.pmc.RagfairInfo.rating
+= ragfairConfig.ratingIncreaseCount / ragfairConfig.ratingSumForIncrease * amountToIncrementBy; += (ragfairConfig.ratingIncreaseCount / ragfairConfig.ratingSumForIncrease) * amountToIncrementBy;
} }
/** /**
@ -389,7 +388,7 @@ export class RagfairOfferHelper
protected deleteOfferById(sessionID: string, offerId: string): void protected deleteOfferById(sessionID: string, offerId: string): void
{ {
const profileRagfairInfo = this.saveServer.getProfile(sessionID).characters.pmc.RagfairInfo; const profileRagfairInfo = this.saveServer.getProfile(sessionID).characters.pmc.RagfairInfo;
const index = profileRagfairInfo.offers.findIndex(o => o._id === offerId); const index = profileRagfairInfo.offers.findIndex((o) => o._id === offerId);
profileRagfairInfo.offers.splice(index, 1); profileRagfairInfo.offers.splice(index, 1);
// Also delete from ragfair // Also delete from ragfair
@ -416,7 +415,7 @@ export class RagfairOfferHelper
else else
{ {
offer.items[0].upd.StackObjectsCount -= boughtAmount; offer.items[0].upd.StackObjectsCount -= boughtAmount;
const rootItems = offer.items.filter(i => i.parentId === "hideout"); const rootItems = offer.items.filter((i) => i.parentId === "hideout");
rootItems.splice(0, 1); rootItems.splice(0, 1);
let removeCount = boughtAmount; let removeCount = boughtAmount;
@ -446,9 +445,9 @@ export class RagfairOfferHelper
for (const id of idsToRemove) for (const id of idsToRemove)
{ {
const newIds = offer.items.filter(i => const newIds = offer.items
!idsToRemove.includes(i._id) && idsToRemove.includes(i.parentId), .filter((i) => !idsToRemove.includes(i._id) && idsToRemove.includes(i.parentId))
).map(i => i._id); .map((i) => i._id);
if (newIds.length > 0) if (newIds.length > 0)
{ {
foundNewItems = true; foundNewItems = true;
@ -459,7 +458,7 @@ export class RagfairOfferHelper
if (idsToRemove.length > 0) if (idsToRemove.length > 0)
{ {
offer.items = offer.items.filter(i => !idsToRemove.includes(i._id)); offer.items = offer.items.filter((i) => !idsToRemove.includes(i._id));
} }
} }
@ -684,7 +683,7 @@ export class RagfairOfferHelper
if (this.itemHelper.armorItemCanHoldMods(offerRootItem._tpl)) if (this.itemHelper.armorItemCanHoldMods(offerRootItem._tpl))
{ {
const offerRootTemplate = this.itemHelper.getItem(offerRootItem._tpl)[1]; const offerRootTemplate = this.itemHelper.getItem(offerRootItem._tpl)[1];
const requiredPlateCount = offerRootTemplate._props.Slots?.filter(item => item._required)?.length; const requiredPlateCount = offerRootTemplate._props.Slots?.filter((item) => item._required)?.length;
return offer.items.length > requiredPlateCount; return offer.items.length > requiredPlateCount;
} }
@ -724,7 +723,7 @@ export class RagfairOfferHelper
// Performing a required search and offer doesn't have requirement for item // Performing a required search and offer doesn't have requirement for item
if ( if (
searchRequest.neededSearchId searchRequest.neededSearchId
&& !offer.requirements.some(requirement => requirement._tpl === searchRequest.neededSearchId) && !offer.requirements.some((requirement) => requirement._tpl === searchRequest.neededSearchId)
) )
{ {
return false; return false;
@ -782,7 +781,7 @@ export class RagfairOfferHelper
public isDisplayableOfferThatNeedsItem(searchRequest: ISearchRequestData, offer: IRagfairOffer): boolean public isDisplayableOfferThatNeedsItem(searchRequest: ISearchRequestData, offer: IRagfairOffer): boolean
{ {
if (offer.requirements.some(requirement => requirement._tpl === searchRequest.neededSearchId)) if (offer.requirements.some((requirement) => requirement._tpl === searchRequest.neededSearchId))
{ {
return true; return true;
} }
@ -799,7 +798,11 @@ export class RagfairOfferHelper
{ {
// thanks typescript, undefined assertion is not returnable since it // thanks typescript, undefined assertion is not returnable since it
// tries to return a multitype object // tries to return a multitype object
return item.upd.MedKit || item.upd.Repairable || item.upd.Resource || item.upd.FoodDrink || item.upd.Key return item.upd.MedKit
|| item.upd.Repairable
|| item.upd.Resource
|| item.upd.FoodDrink
|| item.upd.Key
|| item.upd.RepairKit || item.upd.RepairKit
? true ? true
: false; : false;

View File

@ -43,7 +43,7 @@ export class RagfairSellHelper
const baseSellChancePercent = sellConfig.base * qualityMultiplier; const baseSellChancePercent = sellConfig.base * qualityMultiplier;
// Modfier gets applied twice to either penalize or incentivize over/under pricing (Probably a cleaner way to do this) // Modfier gets applied twice to either penalize or incentivize over/under pricing (Probably a cleaner way to do this)
const sellModifier = averageOfferPriceRub / playerListedPriceRub * sellConfig.sellMultiplier; const sellModifier = (averageOfferPriceRub / playerListedPriceRub) * sellConfig.sellMultiplier;
let sellChance = Math.round(baseSellChancePercent * sellModifier * sellModifier ** 3 + 10); // Power of 3 let sellChance = Math.round(baseSellChancePercent * sellModifier * sellModifier ** 3 + 10); // Power of 3
// Adjust sell chance if below config value // Adjust sell chance if below config value
@ -72,10 +72,11 @@ export class RagfairSellHelper
const startTime = this.timeUtil.getTimestamp(); const startTime = this.timeUtil.getTimestamp();
// Get a time in future to stop simulating sell chances at // Get a time in future to stop simulating sell chances at
const endTime = startTime const endTime
+ this.timeUtil.getHoursAsSeconds( = startTime
this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour, + this.timeUtil.getHoursAsSeconds(
); this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour,
);
let sellTime = startTime; let sellTime = startTime;
let remainingCount = itemSellCount; let remainingCount = itemSellCount;

View File

@ -106,7 +106,8 @@ export class RagfairServerHelper
// Don't include damaged ammo packs // Don't include damaged ammo packs
if ( if (
this.ragfairConfig.dynamic.blacklist.damagedAmmoPacks && itemDetails[1]._parent === BaseClasses.AMMO_BOX this.ragfairConfig.dynamic.blacklist.damagedAmmoPacks
&& itemDetails[1]._parent === BaseClasses.AMMO_BOX
&& itemDetails[1]._name.includes("_damaged") && itemDetails[1]._name.includes("_damaged")
) )
{ {
@ -217,7 +218,7 @@ export class RagfairServerHelper
this.randomUtil.getInt(config.stackablePercent.min, config.stackablePercent.max), this.randomUtil.getInt(config.stackablePercent.min, config.stackablePercent.max),
); );
return Math.round(maxStackCount / 100 * stackPercent); return Math.round((maxStackCount / 100) * stackPercent);
} }
/** /**

View File

@ -31,8 +31,8 @@ export class RepeatableQuestHelper
repeatableConfig: IRepeatableQuestConfig, repeatableConfig: IRepeatableQuestConfig,
): IEliminationConfig ): IEliminationConfig
{ {
return repeatableConfig.questConfig.Elimination.find(x => return repeatableConfig.questConfig.Elimination.find(
pmcLevel >= x.levelRange.min && pmcLevel <= x.levelRange.max, (x) => pmcLevel >= x.levelRange.min && pmcLevel <= x.levelRange.max,
); );
} }

View File

@ -23,7 +23,7 @@ export class SecureContainerHelper
*/ */
public getSecureContainerItems(items: Item[]): string[] public getSecureContainerItems(items: Item[]): string[]
{ {
const secureContainer = items.find(x => x.slotId === "SecuredContainer"); const secureContainer = items.find((x) => x.slotId === "SecuredContainer");
// No container found, drop out // No container found, drop out
if (!secureContainer) if (!secureContainer)
@ -34,6 +34,6 @@ export class SecureContainerHelper
const itemsInSecureContainer = this.itemHelper.findAndReturnChildrenByItems(items, secureContainer._id); const itemsInSecureContainer = this.itemHelper.findAndReturnChildrenByItems(items, secureContainer._id);
// Return all items returned and exclude the secure container item itself // Return all items returned and exclude the secure container item itself
return itemsInSecureContainer.filter(x => x !== secureContainer._id); return itemsInSecureContainer.filter((x) => x !== secureContainer._id);
} }
} }

View File

@ -43,8 +43,8 @@ export class TradeHelper
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper, @inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
@inject("RagfairServer") protected ragfairServer: RagfairServer, @inject("RagfairServer") protected ragfairServer: RagfairServer,
@inject("TraderAssortHelper") protected traderAssortHelper: TraderAssortHelper, @inject("TraderAssortHelper") protected traderAssortHelper: TraderAssortHelper,
@inject("TraderPurchasePersisterService") protected traderPurchasePersisterService: @inject("TraderPurchasePersisterService")
TraderPurchasePersisterService, protected traderPurchasePersisterService: TraderPurchasePersisterService,
@inject("ConfigServer") protected configServer: ConfigServer, @inject("ConfigServer") protected configServer: ConfigServer,
@inject("RecursiveCloner") protected cloner: ICloner, @inject("RecursiveCloner") protected cloner: ICloner,
) )
@ -79,7 +79,7 @@ export class TradeHelper
const allOffers = this.ragfairServer.getOffers(); const allOffers = this.ragfairServer.getOffers();
// We store ragfair offerid in buyRequestData.item_id // We store ragfair offerid in buyRequestData.item_id
const offerWithItem = allOffers.find(x => x._id === buyRequestData.item_id); const offerWithItem = allOffers.find((x) => x._id === buyRequestData.item_id);
const itemPurchased = offerWithItem.items[0]; const itemPurchased = offerWithItem.items[0];
// Ensure purchase does not exceed trader item limit // Ensure purchase does not exceed trader item limit
@ -105,7 +105,7 @@ export class TradeHelper
// Get raw offer from ragfair, clone to prevent altering offer itself // Get raw offer from ragfair, clone to prevent altering offer itself
const allOffers = this.ragfairServer.getOffers(); const allOffers = this.ragfairServer.getOffers();
const offerWithItemCloned = this.cloner.clone(allOffers.find(x => x._id === buyRequestData.item_id)); const offerWithItemCloned = this.cloner.clone(allOffers.find((x) => x._id === buyRequestData.item_id));
offerItems = offerWithItemCloned.items; offerItems = offerWithItemCloned.items;
} }
else if (buyRequestData.tid === Traders.FENCE) else if (buyRequestData.tid === Traders.FENCE)
@ -114,7 +114,7 @@ export class TradeHelper
{ {
// Update assort/flea item values // Update assort/flea item values
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items; const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items;
const itemPurchased = traderAssorts.find(assort => assort._id === buyRequestData.item_id); const itemPurchased = traderAssorts.find((assort) => assort._id === buyRequestData.item_id);
// Decrement trader item count // Decrement trader item count
itemPurchased.upd.StackObjectsCount -= buyCount; itemPurchased.upd.StackObjectsCount -= buyCount;
@ -123,7 +123,7 @@ export class TradeHelper
}; };
const fenceItems = this.fenceService.getRawFenceAssorts().items; const fenceItems = this.fenceService.getRawFenceAssorts().items;
const rootItemIndex = fenceItems.findIndex(item => item._id === buyRequestData.item_id); const rootItemIndex = fenceItems.findIndex((item) => item._id === buyRequestData.item_id);
if (rootItemIndex === -1) if (rootItemIndex === -1)
{ {
this.logger.debug(`Tried to buy item ${buyRequestData.item_id} from fence that no longer exists`); this.logger.debug(`Tried to buy item ${buyRequestData.item_id} from fence that no longer exists`);
@ -142,7 +142,7 @@ export class TradeHelper
{ {
// Update assort/flea item values // Update assort/flea item values
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items; const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items;
const itemPurchased = traderAssorts.find(x => x._id === buyRequestData.item_id); const itemPurchased = traderAssorts.find((x) => x._id === buyRequestData.item_id);
// Ensure purchase does not exceed trader item limit // Ensure purchase does not exceed trader item limit
const assortHasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased); const assortHasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased);
@ -260,7 +260,7 @@ export class TradeHelper
const itemIdToFind = itemToBeRemoved.id.replace(/\s+/g, ""); // Strip out whitespace const itemIdToFind = itemToBeRemoved.id.replace(/\s+/g, ""); // Strip out whitespace
// Find item in player inventory, or show error to player if not found // Find item in player inventory, or show error to player if not found
const matchingItemInInventory = profileWithItemsToSell.Inventory.items.find(x => x._id === itemIdToFind); const matchingItemInInventory = profileWithItemsToSell.Inventory.items.find((x) => x._id === itemIdToFind);
if (!matchingItemInInventory) if (!matchingItemInInventory)
{ {
const errorMessage = `Unable to sell item ${itemToBeRemoved.id}, cannot be found in player inventory`; const errorMessage = `Unable to sell item ${itemToBeRemoved.id}, cannot be found in player inventory`;

View File

@ -40,8 +40,8 @@ export class TraderAssortHelper
@inject("RagfairOfferGenerator") protected ragfairOfferGenerator: RagfairOfferGenerator, @inject("RagfairOfferGenerator") protected ragfairOfferGenerator: RagfairOfferGenerator,
@inject("TraderAssortService") protected traderAssortService: TraderAssortService, @inject("TraderAssortService") protected traderAssortService: TraderAssortService,
@inject("LocalisationService") protected localisationService: LocalisationService, @inject("LocalisationService") protected localisationService: LocalisationService,
@inject("TraderPurchasePersisterService") protected traderPurchasePersisterService: @inject("TraderPurchasePersisterService")
TraderPurchasePersisterService, protected traderPurchasePersisterService: TraderPurchasePersisterService,
@inject("TraderHelper") protected traderHelper: TraderHelper, @inject("TraderHelper") protected traderHelper: TraderHelper,
@inject("FenceService") protected fenceService: FenceService, @inject("FenceService") protected fenceService: FenceService,
@inject("ConfigServer") protected configServer: ConfigServer, @inject("ConfigServer") protected configServer: ConfigServer,
@ -95,7 +95,7 @@ export class TraderAssortHelper
for (const assortId in assortPurchasesfromTrader) for (const assortId in assortPurchasesfromTrader)
{ {
// Find assort we want to update current buy count of // Find assort we want to update current buy count of
const assortToAdjust = traderClone.assort.items.find(x => x._id === assortId); const assortToAdjust = traderClone.assort.items.find((x) => x._id === assortId);
if (!assortToAdjust) if (!assortToAdjust)
{ {
this.logger.debug( this.logger.debug(
@ -147,7 +147,7 @@ export class TraderAssortHelper
protected resetBuyRestrictionCurrentValue(assortItems: Item[]): void protected resetBuyRestrictionCurrentValue(assortItems: Item[]): void
{ {
// iterate over root items // iterate over root items
for (const assort of assortItems.filter(item => item.slotId === "hideout")) for (const assort of assortItems.filter((item) => item.slotId === "hideout"))
{ {
// no value to adjust // no value to adjust
if (!assort.upd.BuyRestrictionCurrent) if (!assort.upd.BuyRestrictionCurrent)

View File

@ -108,7 +108,7 @@ export class TraderHelper
} }
// Find specific assort in traders data // Find specific assort in traders data
const purchasedAssort = traderAssorts.items.find(item => item._id === assortId); const purchasedAssort = traderAssorts.items.find((item) => item._id === assortId);
if (!purchasedAssort) if (!purchasedAssort)
{ {
this.logger.debug(`No assort ${assortId} on trader: ${traderId} found`); this.logger.debug(`No assort ${assortId} on trader: ${traderId} found`);
@ -239,7 +239,8 @@ export class TraderHelper
if ( if (
loyalty.minLevel <= pmcData.Info.Level loyalty.minLevel <= pmcData.Info.Level
&& loyalty.minSalesSum <= pmcData.TradersInfo[traderID].salesSum && loyalty.minSalesSum <= pmcData.TradersInfo[traderID].salesSum
&& loyalty.minStanding <= pmcData.TradersInfo[traderID].standing && targetLevel < 4 && loyalty.minStanding <= pmcData.TradersInfo[traderID].standing
&& targetLevel < 4
) )
{ {
// level reached // level reached
@ -270,7 +271,7 @@ export class TraderHelper
*/ */
public getTraderUpdateSeconds(traderId: string): number public getTraderUpdateSeconds(traderId: string): number
{ {
const traderDetails = this.traderConfig.updateTime.find(x => x.traderId === traderId); const traderDetails = this.traderConfig.updateTime.find((x) => x.traderId === traderId);
if (!traderDetails || traderDetails.seconds.min === undefined || traderDetails.seconds.max === undefined) if (!traderDetails || traderDetails.seconds.min === undefined || traderDetails.seconds.max === undefined)
{ {
this.logger.warning( this.logger.warning(
@ -280,7 +281,8 @@ export class TraderHelper
}), }),
); );
this.traderConfig.updateTime.push( // create temporary entry to prevent logger spam this.traderConfig.updateTime.push(
// create temporary entry to prevent logger spam
{ {
traderId: traderId, traderId: traderId,
seconds: { min: this.traderConfig.updateTimeDefault, max: this.traderConfig.updateTimeDefault }, seconds: { min: this.traderConfig.updateTimeDefault, max: this.traderConfig.updateTimeDefault },
@ -397,15 +399,16 @@ export class TraderHelper
} }
// Get all item assorts that have parentid of hideout (base item and not a mod of other item) // Get all item assorts that have parentid of hideout (base item and not a mod of other item)
for (const item of traderAssorts.items.filter(x => x.parentId === "hideout")) for (const item of traderAssorts.items.filter((x) => x.parentId === "hideout"))
{ {
// Get barter scheme (contains cost of item) // Get barter scheme (contains cost of item)
const barterScheme = traderAssorts.barter_scheme[item._id][0][0]; const barterScheme = traderAssorts.barter_scheme[item._id][0][0];
// Convert into roubles // Convert into roubles
const roubleAmount = barterScheme._tpl === Money.ROUBLES const roubleAmount
? barterScheme.count = barterScheme._tpl === Money.ROUBLES
: this.handbookHelper.inRUB(barterScheme.count, barterScheme._tpl); ? barterScheme.count
: this.handbookHelper.inRUB(barterScheme.count, barterScheme._tpl);
// Existing price smaller in dict than current iteration, overwrite // Existing price smaller in dict than current iteration, overwrite
if (this.highestTraderPriceItems[item._tpl] ?? 0 < roubleAmount) if (this.highestTraderPriceItems[item._tpl] ?? 0 < roubleAmount)
@ -478,7 +481,7 @@ export class TraderHelper
*/ */
public getTraderById(traderId: string): Traders public getTraderById(traderId: string): Traders
{ {
const keys = Object.keys(Traders).filter(x => Traders[x] === traderId); const keys = Object.keys(Traders).filter((x) => Traders[x] === traderId);
if (keys.length === 0) if (keys.length === 0)
{ {
@ -523,7 +526,7 @@ export class TraderHelper
*/ */
public traderEnumHasKey(key: string): boolean public traderEnumHasKey(key: string): boolean
{ {
return Object.keys(Traders).some(x => x === key); return Object.keys(Traders).some((x) => x === key);
} }
/** /**
@ -533,6 +536,6 @@ export class TraderHelper
*/ */
public traderEnumHasValue(traderId: string): boolean public traderEnumHasValue(traderId: string): boolean
{ {
return Object.values(Traders).some(x => x === traderId); return Object.values(Traders).some((x) => x === traderId);
} }
} }

View File

@ -5,6 +5,6 @@ export class UtilityHelper
{ {
public arrayIntersect<T>(a: T[], b: T[]): T[] public arrayIntersect<T>(a: T[], b: T[]): T[]
{ {
return a.filter(x => b.includes(x)); return a.filter((x) => b.includes(x));
} }
} }

View File

@ -58,7 +58,9 @@ export class BundleLoader
public addBundles(modpath: string): void public addBundles(modpath: string): void
{ {
const bundleManifestArr = this.jsonUtil.deserialize<BundleManifest>(this.vfs.readFile(`${modpath}bundles.json`)).manifest; const bundleManifestArr = this.jsonUtil.deserialize<BundleManifest>(
this.vfs.readFile(`${modpath}bundles.json`),
).manifest;
for (const bundleManifest of bundleManifestArr) for (const bundleManifest of bundleManifestArr)
{ {

View File

@ -69,11 +69,13 @@ export class ModTypeCheck
*/ */
public isPostV3Compatible(mod: any): boolean public isPostV3Compatible(mod: any): boolean
{ {
return this.isPreAkiLoad(mod) return (
|| this.isPostAkiLoad(mod) this.isPreAkiLoad(mod)
|| this.isPostDBAkiLoad(mod) || this.isPostAkiLoad(mod)
|| this.isPreAkiLoadAsync(mod) || this.isPostDBAkiLoad(mod)
|| this.isPostAkiLoadAsync(mod) || this.isPreAkiLoadAsync(mod)
|| this.isPostDBAkiLoadAsync(mod); || this.isPostAkiLoadAsync(mod)
|| this.isPostDBAkiLoadAsync(mod)
);
} }
} }

View File

@ -93,10 +93,10 @@ export class PreAkiModLoader implements IModLoader
for (const modName in modsGroupedByName) for (const modName in modsGroupedByName)
{ {
const modDatas = modsGroupedByName[modName]; const modDatas = modsGroupedByName[modName];
const modVersions = modDatas.map(x => x.version); const modVersions = modDatas.map((x) => x.version);
const highestVersion = maxSatisfying(modVersions, "*"); const highestVersion = maxSatisfying(modVersions, "*");
const chosenVersion = modDatas.find(x => x.name === modName && x.version === highestVersion); const chosenVersion = modDatas.find((x) => x.name === modName && x.version === highestVersion);
if (!chosenVersion) if (!chosenVersion)
{ {
continue; continue;
@ -174,7 +174,8 @@ export class PreAkiModLoader implements IModLoader
// if the mod has library dependencies check if these dependencies are bundled in the server, if not install them // if the mod has library dependencies check if these dependencies are bundled in the server, if not install them
if ( if (
modToValidate.dependencies && Object.keys(modToValidate.dependencies).length > 0 modToValidate.dependencies
&& Object.keys(modToValidate.dependencies).length > 0
&& !this.vfs.exists(`${this.basepath}${modFolderName}/node_modules`) && !this.vfs.exists(`${this.basepath}${modFolderName}/node_modules`)
) )
{ {
@ -267,7 +268,7 @@ export class PreAkiModLoader implements IModLoader
for (const mod of modPackageData.values()) for (const mod of modPackageData.values())
{ {
const name = `${mod.author}-${mod.name}`; const name = `${mod.author}-${mod.name}`;
grouppedMods.set(name, [...grouppedMods.get(name) ?? [], mod]); grouppedMods.set(name, [...(grouppedMods.get(name) ?? []), mod]);
// if there's more than one entry for a given mod it means there's at least 2 mods with the same author and name trying to load. // if there's more than one entry for a given mod it means there's at least 2 mods with the same author and name trying to load.
if (grouppedMods.get(name).length > 1 && !this.skippedMods.has(name)) if (grouppedMods.get(name).length > 1 && !this.skippedMods.has(name))
@ -641,7 +642,7 @@ export class PreAkiModLoader implements IModLoader
const modIsCalledSrc = modName.toLowerCase() === "src"; const modIsCalledSrc = modName.toLowerCase() === "src";
const modIsCalledDb = modName.toLowerCase() === "db"; const modIsCalledDb = modName.toLowerCase() === "db";
const hasBepinExFolderStructure = this.vfs.exists(`${modPath}/plugins`); const hasBepinExFolderStructure = this.vfs.exists(`${modPath}/plugins`);
const containsDll = this.vfs.getFiles(`${modPath}`).find(x => x.includes(".dll")); const containsDll = this.vfs.getFiles(`${modPath}`).find((x) => x.includes(".dll"));
if (modIsCalledSrc || modIsCalledDb || modIsCalledUser) if (modIsCalledSrc || modIsCalledDb || modIsCalledUser)
{ {
@ -691,7 +692,8 @@ export class PreAkiModLoader implements IModLoader
if ("main" in config) if ("main" in config)
{ {
if (config.main.split(".").pop() !== "js") if (config.main.split(".").pop() !== "js")
{ // expects js file as entry {
// expects js file as entry
this.logger.error(this.localisationService.getText("modloader-main_property_not_js", modName)); this.logger.error(this.localisationService.getText("modloader-main_property_not_js", modName));
issue = true; issue = true;
} }

View File

@ -1,3 +1,2 @@
export interface IEmptyRequestData export interface IEmptyRequestData
{ {}
}

View File

@ -386,9 +386,9 @@ export interface Productive
ProductionTime?: number ProductionTime?: number
GivenItemsInStart?: string[] GivenItemsInStart?: string[]
Interrupted?: boolean Interrupted?: boolean
Code?: string; Code?: string
Decoded?: boolean; Decoded?: boolean
AvailableForFinish?: boolean; AvailableForFinish?: boolean
/** Used in hideout production.json */ /** Used in hideout production.json */
needFuelForAllProductionTime?: boolean needFuelForAllProductionTime?: boolean
/** Used when sending data to client */ /** Used when sending data to client */
@ -459,8 +459,7 @@ export interface Notes
} }
export interface CarExtractCounts export interface CarExtractCounts
{ {}
}
export enum SurvivorClass export enum SurvivorClass
{ {

View File

@ -1,14 +1,11 @@
export interface IAcceptFriendRequestData extends IBaseFriendRequest export interface IAcceptFriendRequestData extends IBaseFriendRequest
{ {}
}
export interface ICancelFriendRequestData extends IBaseFriendRequest export interface ICancelFriendRequestData extends IBaseFriendRequest
{ {}
}
export interface IDeclineFriendRequestData extends IBaseFriendRequest export interface IDeclineFriendRequestData extends IBaseFriendRequest
{ {}
}
export interface IBaseFriendRequest export interface IBaseFriendRequest
{ {

View File

@ -1,5 +1,5 @@
export interface IAddUserGroupMailRequest export interface IAddUserGroupMailRequest
{ {
dialogId: string; dialogId: string
uid: string; uid: string
} }

View File

@ -1,5 +1,5 @@
export interface IChangeGroupMailOwnerRequest export interface IChangeGroupMailOwnerRequest
{ {
dialogId: string; dialogId: string
uid: string; uid: string
} }

View File

@ -1,5 +1,5 @@
export interface ICreateGroupMailRequest export interface ICreateGroupMailRequest
{ {
Name: string; Name: string
Users: string[]; Users: string[]
} }

View File

@ -1,5 +1,5 @@
export interface IRemoveUserGroupMailRequest export interface IRemoveUserGroupMailRequest
{ {
dialogId: string; dialogId: string
uid: string; uid: string
} }

View File

@ -17,8 +17,7 @@ export interface IQteData
area: HideoutAreas area: HideoutAreas
areaLevel: number areaLevel: number
quickTimeEvents: IQuickTimeEvent[] quickTimeEvents: IQuickTimeEvent[]
requirements: requirements: (
(
| IAreaRequirement | IAreaRequirement
| IItemRequirement | IItemRequirement
| ITraderUnlockRequirement | ITraderUnlockRequirement

View File

@ -1,8 +1,7 @@
import { IBaseInteractionRequestData } from "@spt-aki/models/eft/common/request/IBaseInteractionRequestData"; import { IBaseInteractionRequestData } from "@spt-aki/models/eft/common/request/IBaseInteractionRequestData";
export interface IInventoryBaseActionRequestData extends IBaseInteractionRequestData export interface IInventoryBaseActionRequestData extends IBaseInteractionRequestData
{ {}
}
export interface To export interface To
{ {

View File

@ -2,6 +2,4 @@ import { IWsNotificationEvent } from "@spt-aki/models/eft/ws/IWsNotificationEven
import { IGroupCharacter } from "../match/IGroupCharacter"; import { IGroupCharacter } from "../match/IGroupCharacter";
export interface IWsGroupMatchInviteAccept extends IWsNotificationEvent, IGroupCharacter export interface IWsGroupMatchInviteAccept extends IWsNotificationEvent, IGroupCharacter
{ {}
}

View File

@ -1,6 +1,4 @@
import { IWsNotificationEvent } from "@spt-aki/models/eft/ws/IWsNotificationEvent"; import { IWsNotificationEvent } from "@spt-aki/models/eft/ws/IWsNotificationEvent";
export interface IWsPing extends IWsNotificationEvent export interface IWsPing extends IWsNotificationEvent
{ {}
}

View File

@ -1,5 +1,5 @@
export enum MemberCategory // player type export enum MemberCategory
{ { // player type
DEFAULT = 0, DEFAULT = 0,
DEVELOPER = 1, DEVELOPER = 1,
UNIQUE_ID = 2, UNIQUE_ID = 2,

Some files were not shown because too many files have changed in this diff Show More