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:
parent
5def42416b
commit
cb169a18b9
@ -23,7 +23,7 @@ export class ErrorHandler
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import { inject, injectable } from "tsyringe";
|
||||
import { AchievementController } from "@spt-aki/controllers/AchievementController";
|
||||
import { ProfileController } from "@spt-aki/controllers/ProfileController";
|
||||
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 { ICompletedAchievementsResponse } from "@spt-aki/models/eft/profile/ICompletedAchievementsResponse";
|
||||
import { IGetAchievementsResponse } from "@spt-aki/models/eft/profile/IGetAchievementsResponse";
|
||||
|
@ -48,7 +48,11 @@ export class BotCallbacks
|
||||
* Handle singleplayer/settings/bot/difficulties
|
||||
* @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());
|
||||
}
|
||||
|
@ -46,7 +46,11 @@ export class CustomizationCallbacks
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
@ -88,7 +88,11 @@ export class DataCallbacks
|
||||
* Handle client/account/customization
|
||||
* @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);
|
||||
}
|
||||
|
@ -47,8 +47,7 @@ export class DialogueCallbacks implements OnUpdate
|
||||
@inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil,
|
||||
@inject("DialogueController") protected dialogueController: DialogueController,
|
||||
)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* Handle client/friend/list
|
||||
@ -276,11 +275,7 @@ export class DialogueCallbacks implements OnUpdate
|
||||
return this.httpResponse.emptyArrayResponse();
|
||||
}
|
||||
|
||||
public createGroupMail(
|
||||
url: string,
|
||||
info: ICreateGroupMailRequest,
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<any[]>
|
||||
public createGroupMail(url: string, info: ICreateGroupMailRequest, sessionID: string): IGetBodyResponseData<any[]>
|
||||
{
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
@ -294,11 +289,7 @@ export class DialogueCallbacks implements OnUpdate
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public addUserToMail(
|
||||
url: string,
|
||||
info: IAddUserGroupMailRequest,
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<any[]>
|
||||
public addUserToMail(url: string, info: IAddUserGroupMailRequest, sessionID: string): IGetBodyResponseData<any[]>
|
||||
{
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
@ -56,7 +56,11 @@ export class GameCallbacks implements OnLoad
|
||||
* Handle client/game/start
|
||||
* @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 startTimeStampMS = Date.parse(today);
|
||||
|
@ -102,7 +102,11 @@ export class InventoryCallbacks
|
||||
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);
|
||||
}
|
||||
|
@ -101,22 +101,14 @@ export class MatchCallbacks
|
||||
|
||||
/** Handle client/match/group/invite/decline */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public declineGroupInvite(
|
||||
url: string,
|
||||
info: IRequestIdRequest,
|
||||
sessionId: string,
|
||||
): IGetBodyResponseData<boolean>
|
||||
public declineGroupInvite(url: string, info: IRequestIdRequest, sessionId: string): IGetBodyResponseData<boolean>
|
||||
{
|
||||
return this.httpResponse.getBody(true);
|
||||
}
|
||||
|
||||
/** Handle client/match/group/invite/cancel */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public cancelGroupInvite(
|
||||
url: string,
|
||||
info: IRequestIdRequest,
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<boolean>
|
||||
public cancelGroupInvite(url: string, info: IRequestIdRequest, sessionID: string): IGetBodyResponseData<boolean>
|
||||
{
|
||||
return this.httpResponse.getBody(true);
|
||||
}
|
||||
@ -246,21 +238,13 @@ export class MatchCallbacks
|
||||
}
|
||||
|
||||
/** Handle client/match/group/raid/ready */
|
||||
public raidReady(
|
||||
url: string,
|
||||
info: IEmptyRequestData,
|
||||
sessionId: string,
|
||||
): IGetBodyResponseData<boolean>
|
||||
public raidReady(url: string, info: IEmptyRequestData, sessionId: string): IGetBodyResponseData<boolean>
|
||||
{
|
||||
return this.httpResponse.getBody(true);
|
||||
}
|
||||
|
||||
/** Handle client/match/group/raid/not-ready */
|
||||
public notRaidReady(
|
||||
url: string,
|
||||
info: IEmptyRequestData,
|
||||
sessionId: string,
|
||||
): IGetBodyResponseData<boolean>
|
||||
public notRaidReady(url: string, info: IEmptyRequestData, sessionId: string): IGetBodyResponseData<boolean>
|
||||
{
|
||||
return this.httpResponse.getBody(true);
|
||||
}
|
||||
|
@ -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
|
||||
* be sent to client as NEWLINE separated strings... yup.
|
||||
*/
|
||||
this.notifierController.notifyAsync(tmpSessionID).then((messages: any) =>
|
||||
messages.map((message: any) => this.jsonUtil.serialize(message)).join("\n"),
|
||||
).then(text => this.httpServerHelper.sendTextJson(resp, text));
|
||||
this.notifierController
|
||||
.notifyAsync(tmpSessionID)
|
||||
.then((messages: any) => messages.map((message: any) => this.jsonUtil.serialize(message)).join("\n"))
|
||||
.then((text) => this.httpServerHelper.sendTextJson(resp, text));
|
||||
}
|
||||
|
||||
/** Handle push/notifier/get */
|
||||
|
@ -17,7 +17,11 @@ export class WishlistCallbacks
|
||||
}
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { BotGenerator } from "@spt-aki/generators/BotGenerator";
|
||||
import { BotDifficultyHelper } from "@spt-aki/helpers/BotDifficultyHelper";
|
||||
import { BotHelper } from "@spt-aki/helpers/BotHelper";
|
||||
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 { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||
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 { ICloner } from "@spt-aki/utils/cloners/ICloner";
|
||||
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
||||
import { MinMax } from "@spt-aki/models/common/MinMax";
|
||||
|
||||
@injectable()
|
||||
export class BotController
|
||||
@ -94,9 +94,9 @@ export class BotController
|
||||
{
|
||||
let difficulty = diffLevel.toLowerCase();
|
||||
|
||||
const raidConfig = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue<
|
||||
IGetRaidConfigurationRequestData
|
||||
>();
|
||||
const raidConfig = this.applicationContext
|
||||
.getLatestValue(ContextVariableType.RAID_CONFIGURATION)
|
||||
?.getValue<IGetRaidConfigurationRequestData>();
|
||||
if (!(raidConfig || ignoreRaidSettings))
|
||||
{
|
||||
this.logger.error(
|
||||
@ -109,9 +109,8 @@ export class BotController
|
||||
const botDifficultyDropDownValue = raidConfig?.wavesSettings.botDifficulty.toLowerCase() ?? "asonline";
|
||||
if (botDifficultyDropDownValue !== "asonline")
|
||||
{
|
||||
difficulty = this.botDifficultyHelper.convertBotDifficultyDropdownToBotDifficulty(
|
||||
botDifficultyDropDownValue,
|
||||
);
|
||||
difficulty
|
||||
= this.botDifficultyHelper.convertBotDifficultyDropdownToBotDifficulty(botDifficultyDropDownValue);
|
||||
}
|
||||
|
||||
let difficultySettings: Difficulty;
|
||||
@ -147,7 +146,7 @@ export class BotController
|
||||
const result = {};
|
||||
|
||||
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)
|
||||
{
|
||||
const enumType = botType.toLowerCase();
|
||||
@ -228,12 +227,13 @@ export class BotController
|
||||
allPmcsHaveSameNameAsPlayer,
|
||||
pmcLevelRangeForMap,
|
||||
this.botConfig.presetBatch[condition.Role],
|
||||
false);
|
||||
false,
|
||||
);
|
||||
|
||||
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 [];
|
||||
}
|
||||
@ -254,8 +254,8 @@ export class BotController
|
||||
allPmcsHaveSameNameAsPlayer: boolean,
|
||||
pmcLevelRangeForMap: MinMax,
|
||||
botCountToGenerate: number,
|
||||
generateAsPmc: boolean): BotGenerationDetails
|
||||
|
||||
generateAsPmc: boolean,
|
||||
): BotGenerationDetails
|
||||
{
|
||||
return {
|
||||
isPmc: generateAsPmc,
|
||||
@ -357,14 +357,17 @@ export class BotController
|
||||
* @param request Bot generation request 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 requestedBot = request.conditions[0];
|
||||
|
||||
const raidSettings = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue<
|
||||
IGetRaidConfigurationRequestData
|
||||
>();
|
||||
const raidSettings = this.applicationContext
|
||||
.getLatestValue(ContextVariableType.RAID_CONFIGURATION)
|
||||
?.getValue<IGetRaidConfigurationRequestData>();
|
||||
const pmcLevelRangeForMap
|
||||
= this.pmcConfig.locationSpecificPmcLevelOverride[raidSettings.location.toLowerCase()];
|
||||
|
||||
@ -372,7 +375,7 @@ export class BotController
|
||||
const condition: Condition = {
|
||||
Role: requestedBot.Role,
|
||||
Limit: 5,
|
||||
Difficulty: requestedBot.Difficulty
|
||||
Difficulty: requestedBot.Difficulty,
|
||||
};
|
||||
const botGenerationDetails = this.getBotGenerationDetailsForWave(
|
||||
condition,
|
||||
@ -380,7 +383,8 @@ export class BotController
|
||||
false,
|
||||
pmcLevelRangeForMap,
|
||||
this.botConfig.presetBatch[requestedBot.Role],
|
||||
false);
|
||||
false,
|
||||
);
|
||||
|
||||
// Event bots need special actions to occur, set data up for them
|
||||
const isEventBot = requestedBot.Role.toLowerCase().includes("event");
|
||||
@ -475,9 +479,9 @@ export class BotController
|
||||
public getBotCap(): number
|
||||
{
|
||||
const defaultMapCapId = "default";
|
||||
const raidConfig = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION).getValue<
|
||||
IGetRaidConfigurationRequestData
|
||||
>();
|
||||
const raidConfig = this.applicationContext
|
||||
.getLatestValue(ContextVariableType.RAID_CONFIGURATION)
|
||||
.getValue<IGetRaidConfigurationRequestData>();
|
||||
|
||||
if (!raidConfig)
|
||||
{
|
||||
|
@ -42,11 +42,11 @@ export class BuildController
|
||||
const defaultEquipmentPresetsClone = this.cloner.clone(
|
||||
this.databaseServer.getTables().templates.defaultEquipmentPresets,
|
||||
);
|
||||
const playerSecureContainer = profile.characters.pmc.Inventory.items?.find(x =>
|
||||
x.slotId === secureContainerSlotId,
|
||||
const playerSecureContainer = profile.characters.pmc.Inventory.items?.find(
|
||||
(x) => x.slotId === secureContainerSlotId,
|
||||
);
|
||||
const firstDefaultItemsSecureContainer = defaultEquipmentPresetsClone[0]?.Items?.find(x =>
|
||||
x.slotId === secureContainerSlotId,
|
||||
const firstDefaultItemsSecureContainer = defaultEquipmentPresetsClone[0]?.Items?.find(
|
||||
(x) => x.slotId === secureContainerSlotId,
|
||||
);
|
||||
if (playerSecureContainer && playerSecureContainer?._tpl !== firstDefaultItemsSecureContainer?._tpl)
|
||||
{
|
||||
@ -54,7 +54,7 @@ export class BuildController
|
||||
for (const defaultPreset of defaultEquipmentPresetsClone)
|
||||
{
|
||||
// Find presets secure container
|
||||
const secureContainer = defaultPreset.Items.find(item => item.slotId === secureContainerSlotId);
|
||||
const secureContainer = defaultPreset.Items.find((item) => item.slotId === secureContainerSlotId);
|
||||
if (secureContainer)
|
||||
{
|
||||
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 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)
|
||||
{
|
||||
// exists, replace
|
||||
this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds.splice(
|
||||
savedWeaponBuilds.indexOf(existingBuild),
|
||||
1,
|
||||
newBuild,
|
||||
);
|
||||
this.saveServer
|
||||
.getProfile(sessionId)
|
||||
.userbuilds.weaponBuilds.splice(savedWeaponBuilds.indexOf(existingBuild), 1, newBuild);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -106,8 +104,8 @@ export class BuildController
|
||||
const buildType = "equipmentBuilds";
|
||||
const pmcData = this.profileHelper.getPmcProfile(sessionID);
|
||||
|
||||
const existingSavedEquipmentBuilds: IEquipmentBuild[] = this.saveServer.getProfile(sessionID)
|
||||
.userbuilds[buildType];
|
||||
const existingSavedEquipmentBuilds: IEquipmentBuild[]
|
||||
= this.saveServer.getProfile(sessionID).userbuilds[buildType];
|
||||
|
||||
// Replace duplicate ID's. The first item is the base item.
|
||||
// Root ID and the base item ID need to match.
|
||||
@ -121,17 +119,15 @@ export class BuildController
|
||||
Items: request.Items,
|
||||
};
|
||||
|
||||
const existingBuild = existingSavedEquipmentBuilds.find(build =>
|
||||
build.Name === request.Name || build.Id === request.Id,
|
||||
const existingBuild = existingSavedEquipmentBuilds.find(
|
||||
(build) => build.Name === request.Name || build.Id === request.Id,
|
||||
);
|
||||
if (existingBuild)
|
||||
{
|
||||
// Already exists, replace
|
||||
this.saveServer.getProfile(sessionID).userbuilds[buildType].splice(
|
||||
existingSavedEquipmentBuilds.indexOf(existingBuild),
|
||||
1,
|
||||
newBuild,
|
||||
);
|
||||
this.saveServer
|
||||
.getProfile(sessionID)
|
||||
.userbuilds[buildType].splice(existingSavedEquipmentBuilds.indexOf(existingBuild), 1, newBuild);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -154,7 +150,7 @@ export class BuildController
|
||||
const magazineBuilds = profile.userbuilds.magazineBuilds;
|
||||
|
||||
// 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)
|
||||
{
|
||||
weaponBuilds.splice(weaponBuilds.indexOf(matchingWeaponBuild), 1);
|
||||
@ -163,7 +159,7 @@ export class BuildController
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
equipmentBuilds.splice(equipmentBuilds.indexOf(matchingEquipmentBuild), 1);
|
||||
@ -172,7 +168,7 @@ export class BuildController
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
magazineBuilds.splice(magazineBuilds.indexOf(matchingMagazineBuild), 1);
|
||||
@ -207,7 +203,7 @@ export class BuildController
|
||||
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)
|
||||
{
|
||||
|
@ -42,10 +42,10 @@ export class CustomizationController
|
||||
const suits = this.databaseServer.getTables().traders[traderID].suits;
|
||||
|
||||
// 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 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
|
||||
{
|
||||
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,
|
||||
): 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)
|
||||
{
|
||||
this.logger.error(
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { inject, injectAll, injectable } from "tsyringe";
|
||||
import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot";
|
||||
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 { IGetFriendListDataResponse } from "@spt-aki/models/eft/dialog/IGetFriendListDataResponse";
|
||||
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 { MailSendService } from "@spt-aki/services/MailSendService";
|
||||
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()
|
||||
export class DialogueController
|
||||
@ -35,21 +35,21 @@ export class DialogueController
|
||||
// if give command is disabled or commando commands are disabled
|
||||
if (!coreConfigs.features?.chatbotFeatures?.commandoEnabled)
|
||||
{
|
||||
const sptCommando = this.dialogueChatBots.find(c =>
|
||||
c.getChatBot()._id.toLocaleLowerCase() === "sptcommando",
|
||||
const sptCommando = this.dialogueChatBots.find(
|
||||
(c) => c.getChatBot()._id.toLocaleLowerCase() === "sptcommando",
|
||||
);
|
||||
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptCommando), 1);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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!`);
|
||||
}
|
||||
@ -74,7 +74,7 @@ export class DialogueController
|
||||
public getFriendList(sessionID: string): IGetFriendListDataResponse
|
||||
{
|
||||
// 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
|
||||
if (
|
||||
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)
|
||||
@ -209,7 +209,7 @@ export class DialogueController
|
||||
if (request.type === MessageType.USER_MESSAGE)
|
||||
{
|
||||
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)
|
||||
{
|
||||
profile.dialogues[request.dialogId].Users.push(chatBot.getChatBot());
|
||||
@ -233,7 +233,7 @@ export class DialogueController
|
||||
{
|
||||
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
|
||||
const pmcProfile = fullProfile.characters.pmc;
|
||||
@ -281,7 +281,7 @@ export class DialogueController
|
||||
*/
|
||||
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);
|
||||
|
||||
return this.dialogueChatBots.find(cb => cb.getChatBot()._id === request.dialogId)?.handleMessage(
|
||||
sessionId,
|
||||
request,
|
||||
) ?? request.dialogId;
|
||||
return (
|
||||
this.dialogueChatBots
|
||||
.find((cb) => cb.getChatBot()._id === request.dialogId)
|
||||
?.handleMessage(sessionId, request) ?? request.dialogId
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -394,7 +395,7 @@ export class DialogueController
|
||||
{
|
||||
const timeNow = this.timeUtil.getTimestamp();
|
||||
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[]
|
||||
{
|
||||
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 */
|
||||
public sendFriendRequest(
|
||||
sessionID: string,
|
||||
request: IFriendRequestData
|
||||
|
||||
): IFriendRequestSendResponse
|
||||
public sendFriendRequest(sessionID: string, request: IFriendRequestData): IFriendRequestSendResponse
|
||||
{
|
||||
return { status: 0, requestId: "12345", retryAfter: 600 }
|
||||
return { status: 0, requestId: "12345", retryAfter: 600 };
|
||||
}
|
||||
}
|
||||
|
@ -359,8 +359,8 @@ export class GameController
|
||||
for (const positionToAdd of positionsToAdd)
|
||||
{
|
||||
// Exists already, add new items to existing positions pool
|
||||
const existingLootPosition = mapLooseLoot.spawnpoints.find(x =>
|
||||
x.template.Id === positionToAdd.template.Id,
|
||||
const existingLootPosition = mapLooseLoot.spawnpoints.find(
|
||||
(x) => x.template.Id === positionToAdd.template.Id,
|
||||
);
|
||||
if (existingLootPosition)
|
||||
{
|
||||
@ -390,7 +390,7 @@ export class GameController
|
||||
const mapLootAdjustmentsDict = adjustments[mapId];
|
||||
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)
|
||||
{
|
||||
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])
|
||||
{
|
||||
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)
|
||||
{
|
||||
// Existing bot type found in MinMaxBots array, edit
|
||||
@ -452,8 +452,8 @@ export class GameController
|
||||
{
|
||||
const profile = this.profileHelper.getPmcProfile(sessionID);
|
||||
const gameTime
|
||||
= profile.Stats?.Eft.OverallCounters.Items?.find(counter =>
|
||||
counter.Key.includes("LifeTime") && counter.Key.includes("Pmc"),
|
||||
= profile.Stats?.Eft.OverallCounters.Items?.find(
|
||||
(counter) => counter.Key.includes("LifeTime") && counter.Key.includes("Pmc"),
|
||||
)?.Value ?? 0;
|
||||
|
||||
const config: IGameConfigResponse = {
|
||||
@ -598,12 +598,13 @@ export class GameController
|
||||
let hpRegenPerHour = 456.6;
|
||||
|
||||
// Set new values, whatever is smallest
|
||||
energyRegenPerHour += pmcProfile.Bonuses.filter(bonus => bonus.type === BonusType.ENERGY_REGENERATION)
|
||||
.reduce((sum, curr) => sum + curr.value, 0);
|
||||
hydrationRegenPerHour += pmcProfile.Bonuses.filter(bonus =>
|
||||
bonus.type === BonusType.HYDRATION_REGENERATION,
|
||||
energyRegenPerHour += pmcProfile.Bonuses.filter(
|
||||
(bonus) => bonus.type === BonusType.ENERGY_REGENERATION,
|
||||
).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,
|
||||
0,
|
||||
);
|
||||
@ -738,13 +739,13 @@ export class GameController
|
||||
const currentTimeStamp = this.timeUtil.getTimestamp();
|
||||
|
||||
// One day post-profile creation
|
||||
if (currentTimeStamp > (timeStampProfileCreated + oneDaySeconds))
|
||||
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds)
|
||||
{
|
||||
this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 1);
|
||||
}
|
||||
|
||||
// Two day post-profile creation
|
||||
if (currentTimeStamp > (timeStampProfileCreated + oneDaySeconds * 2))
|
||||
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds * 2)
|
||||
{
|
||||
this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 2);
|
||||
}
|
||||
@ -841,8 +842,11 @@ export class GameController
|
||||
{
|
||||
const modDetails = activeMods[modKey];
|
||||
if (
|
||||
fullProfile.aki.mods.some(x =>
|
||||
x.author === modDetails.author && x.name === modDetails.name && x.version === modDetails.version,
|
||||
fullProfile.aki.mods.some(
|
||||
(x) =>
|
||||
x.author === modDetails.author
|
||||
&& x.name === modDetails.name
|
||||
&& x.version === modDetails.version,
|
||||
)
|
||||
)
|
||||
{
|
||||
@ -957,8 +961,8 @@ export class GameController
|
||||
protected adjustLabsRaiderSpawnRate(): void
|
||||
{
|
||||
const labsBase = this.databaseServer.getTables().locations.laboratory.base;
|
||||
const nonTriggerLabsBossSpawns = labsBase.BossLocationSpawn.filter(x =>
|
||||
x.TriggerId === "" && x.TriggerName === "",
|
||||
const nonTriggerLabsBossSpawns = labsBase.BossLocationSpawn.filter(
|
||||
(x) => x.TriggerId === "" && x.TriggerName === "",
|
||||
);
|
||||
if (nonTriggerLabsBossSpawns)
|
||||
{
|
||||
|
@ -60,12 +60,16 @@ export class HealthController
|
||||
* @param sessionID Player id
|
||||
* @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);
|
||||
|
||||
// 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)
|
||||
{
|
||||
const errorMessage = this.localisationService.getText(
|
||||
@ -113,7 +117,7 @@ export class HealthController
|
||||
const output = this.eventOutputHolder.getOutput(sessionID);
|
||||
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)
|
||||
{
|
||||
// Item not found, very bad
|
||||
|
@ -11,7 +11,6 @@ import {
|
||||
HideoutArea,
|
||||
ITaskConditionCounter,
|
||||
Product,
|
||||
Production,
|
||||
ScavCase,
|
||||
} from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||
@ -105,7 +104,7 @@ export class HideoutController
|
||||
{
|
||||
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 };
|
||||
});
|
||||
|
||||
@ -138,7 +137,7 @@ export class HideoutController
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
||||
@ -147,9 +146,9 @@ export class HideoutController
|
||||
return;
|
||||
}
|
||||
|
||||
const hideoutDataDb = this.databaseServer.getTables().hideout.areas.find(area =>
|
||||
area.type === request.areaType,
|
||||
);
|
||||
const hideoutDataDb = this.databaseServer
|
||||
.getTables()
|
||||
.hideout.areas.find((area) => area.type === request.areaType);
|
||||
if (!hideoutDataDb)
|
||||
{
|
||||
this.logger.error(
|
||||
@ -191,7 +190,7 @@ export class HideoutController
|
||||
{
|
||||
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)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
||||
@ -205,7 +204,7 @@ export class HideoutController
|
||||
profileHideoutArea.completeTime = 0;
|
||||
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)
|
||||
{
|
||||
this.logger.error(
|
||||
@ -263,11 +262,11 @@ export class HideoutController
|
||||
*/
|
||||
protected checkAndUpgradeWall(pmcData: IPmcData): void
|
||||
{
|
||||
const medStation = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.MEDSTATION);
|
||||
const waterCollector = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.WATER_COLLECTOR);
|
||||
const medStation = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.MEDSTATION);
|
||||
const waterCollector = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.WATER_COLLECTOR);
|
||||
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)
|
||||
{
|
||||
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
|
||||
const childDbArea = this.databaseServer.getTables().hideout.areas.find(x =>
|
||||
x.parentArea === dbHideoutArea._id,
|
||||
);
|
||||
const childDbArea = this.databaseServer
|
||||
.getTables()
|
||||
.hideout.areas.find((x) => x.parentArea === dbHideoutArea._id);
|
||||
if (childDbArea)
|
||||
{
|
||||
// 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
|
||||
pmcData.Hideout.Areas.find(x => x.type === childDbArea.type).level = pmcData.Hideout.Areas.find(x =>
|
||||
x.type === profileParentHideoutArea.type,
|
||||
pmcData.Hideout.Areas.find((x) => x.type === childDbArea.type).level = pmcData.Hideout.Areas.find(
|
||||
(x) => x.type === profileParentHideoutArea.type,
|
||||
).level;
|
||||
|
||||
// Add/upgrade stash item in player inventory
|
||||
@ -340,9 +339,13 @@ export class HideoutController
|
||||
* @param dbHideoutData Hideout area from db being upgraded
|
||||
* @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)
|
||||
{
|
||||
// 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 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] };
|
||||
});
|
||||
|
||||
const hideoutArea = pmcData.Hideout.Areas.find(area => area.type === addItemToHideoutRequest.areaType);
|
||||
const hideoutArea = pmcData.Hideout.Areas.find((area) => area.type === addItemToHideoutRequest.areaType);
|
||||
if (!hideoutArea)
|
||||
{
|
||||
this.logger.error(
|
||||
@ -430,12 +433,14 @@ export class HideoutController
|
||||
|
||||
// Add item to area.slots
|
||||
const destinationLocationIndex = Number(item.slot);
|
||||
const hideoutSlotIndex = hideoutArea.slots.findIndex(x => x.locationIndex === destinationLocationIndex);
|
||||
hideoutArea.slots[hideoutSlotIndex].item = [{
|
||||
_id: item.inventoryItem._id,
|
||||
_tpl: item.inventoryItem._tpl,
|
||||
upd: item.inventoryItem.upd,
|
||||
}];
|
||||
const hideoutSlotIndex = hideoutArea.slots.findIndex((x) => x.locationIndex === destinationLocationIndex);
|
||||
hideoutArea.slots[hideoutSlotIndex].item = [
|
||||
{
|
||||
_id: item.inventoryItem._id,
|
||||
_tpl: item.inventoryItem._tpl,
|
||||
upd: item.inventoryItem.upd,
|
||||
},
|
||||
];
|
||||
|
||||
this.inventoryHelper.removeItem(pmcData, item.inventoryItem._id, sessionID, output);
|
||||
}
|
||||
@ -462,7 +467,7 @@ export class HideoutController
|
||||
{
|
||||
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)
|
||||
{
|
||||
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];
|
||||
|
||||
// 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 = {
|
||||
itemWithModsToAdd: [itemToReturn],
|
||||
@ -536,7 +541,7 @@ export class HideoutController
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
// 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
|
||||
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 itemsToDelete = body.items.concat(body.tools);
|
||||
for (const itemToDelete of itemsToDelete)
|
||||
{
|
||||
const itemToCheck = pmcData.Inventory.items.find(i => i._id === itemToDelete.id);
|
||||
const requirement = recipeRequirementsClone.find(requirement =>
|
||||
requirement.templateId === itemToCheck._tpl,
|
||||
const itemToCheck = pmcData.Inventory.items.find((i) => i._id === itemToDelete.id);
|
||||
const requirement = recipeRequirementsClone.find(
|
||||
(requirement) => requirement.templateId === itemToCheck._tpl,
|
||||
);
|
||||
|
||||
// Handle tools not having a `count`, but always only requiring 1
|
||||
@ -644,7 +649,7 @@ export class HideoutController
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
this.logger.error(
|
||||
@ -678,12 +683,14 @@ export class HideoutController
|
||||
// @Important: Here we need to be very exact:
|
||||
// - 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"
|
||||
const adjustedCraftTime = recipe.ProductionTime - this.hideoutHelper.getSkillProductionTimeReduction(
|
||||
pmcData,
|
||||
recipe.ProductionTime,
|
||||
SkillTypes.CRAFTING,
|
||||
this.databaseServer.getTables().globals.config.SkillsSettings.Crafting.CraftTimeReductionPerLevel,
|
||||
);
|
||||
const adjustedCraftTime
|
||||
= recipe.ProductionTime
|
||||
- this.hideoutHelper.getSkillProductionTimeReduction(
|
||||
pmcData,
|
||||
recipe.ProductionTime,
|
||||
SkillTypes.CRAFTING,
|
||||
this.databaseServer.getTables().globals.config.SkillsSettings.Crafting.CraftTimeReductionPerLevel,
|
||||
);
|
||||
|
||||
const modifiedScavCaseTime = this.getScavCaseTime(pmcData, adjustedCraftTime);
|
||||
|
||||
@ -770,7 +777,7 @@ export class HideoutController
|
||||
return output;
|
||||
}
|
||||
|
||||
const recipe = hideoutDb.production.find(r => r._id === request.recipeId);
|
||||
const recipe = hideoutDb.production.find((r) => r._id === request.recipeId);
|
||||
if (recipe)
|
||||
{
|
||||
this.handleRecipe(sessionID, recipe, pmcData, request, output);
|
||||
@ -778,7 +785,7 @@ export class HideoutController
|
||||
return output;
|
||||
}
|
||||
|
||||
const scavCase = hideoutDb.scavcase.find(r => r._id === request.recipeId);
|
||||
const scavCase = hideoutDb.scavcase.find((r) => r._id === request.recipeId);
|
||||
if (scavCase)
|
||||
{
|
||||
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
|
||||
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)
|
||||
{
|
||||
// 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
|
||||
* @returns ITaskConditionCounter
|
||||
*/
|
||||
protected getHoursCraftingTaskConditionCounter(pmcData: IPmcData, recipe: IHideoutProduction): ITaskConditionCounter
|
||||
protected getHoursCraftingTaskConditionCounter(
|
||||
pmcData: IPmcData,
|
||||
recipe: IHideoutProduction,
|
||||
): ITaskConditionCounter
|
||||
{
|
||||
let counterHoursCrafting = pmcData.TaskConditionCounters[HideoutController.nameTaskConditionCountersCrafting];
|
||||
if (!counterHoursCrafting)
|
||||
@ -1078,7 +1088,8 @@ export class HideoutController
|
||||
for (const production of ongoingProductions)
|
||||
{
|
||||
if (this.hideoutHelper.isProductionType(production[1]))
|
||||
{ // Production or ScavCase
|
||||
{
|
||||
// Production or ScavCase
|
||||
if ((production[1] as ScavCase).RecipeId === request.recipeId)
|
||||
{
|
||||
prodId = production[0]; // Set to objects key
|
||||
@ -1187,13 +1198,13 @@ export class HideoutController
|
||||
public recordShootingRangePoints(sessionId: string, pmcData: IPmcData, request: IRecordShootingRangePoints): void
|
||||
{
|
||||
// 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 });
|
||||
}
|
||||
|
||||
// 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"),
|
||||
);
|
||||
shootingRangeHighScore.Value = request.points;
|
||||
@ -1216,7 +1227,7 @@ export class HideoutController
|
||||
// Create mapping of required item with corrisponding item from player inventory
|
||||
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 };
|
||||
});
|
||||
|
||||
@ -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)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
||||
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)
|
||||
{
|
||||
this.logger.error(
|
||||
|
@ -201,7 +201,7 @@ export class InraidController
|
||||
if (locationName === "lighthouse" && postRaidRequest.profile.Info.Side.toLowerCase() === "usec")
|
||||
{
|
||||
// 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"),
|
||||
);
|
||||
if (remainingCounter?.Value > 0)
|
||||
@ -226,9 +226,9 @@ export class InraidController
|
||||
// Not dead
|
||||
|
||||
// Check for cultist amulets in special slot (only slot it can fit)
|
||||
const amuletOnPlayer = serverPmcProfile.Inventory.items.filter(item =>
|
||||
item.slotId?.startsWith("SpecialSlot"),
|
||||
).find(item => item._tpl === "64d0b40fbe2eed70e254e2d4");
|
||||
const amuletOnPlayer = serverPmcProfile.Inventory.items
|
||||
.filter((item) => item.slotId?.startsWith("SpecialSlot"))
|
||||
.find((item) => item._tpl === "64d0b40fbe2eed70e254e2d4");
|
||||
if (amuletOnPlayer)
|
||||
{
|
||||
// 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()),
|
||||
);
|
||||
if (victims?.length > 0)
|
||||
@ -281,12 +281,11 @@ export class InraidController
|
||||
// and quest items cannot be picked up again
|
||||
const allQuests = this.questHelper.getQuestsFromDb();
|
||||
const activeQuestIdsInProfile = pmcData.Quests.filter(
|
||||
profileQuest => ![
|
||||
QuestStatus.AvailableForStart,
|
||||
QuestStatus.Success,
|
||||
QuestStatus.Expired,
|
||||
].includes(profileQuest.status),
|
||||
).map(x => x.qid);
|
||||
(profileQuest) =>
|
||||
![QuestStatus.AvailableForStart, QuestStatus.Success, QuestStatus.Expired].includes(
|
||||
profileQuest.status,
|
||||
),
|
||||
).map((x) => x.qid);
|
||||
for (const questItem of postRaidSaveRequest.profile.Stats.Eft.CarriedQuestItems)
|
||||
{
|
||||
// Get quest/find condition for carried quest item
|
||||
@ -470,7 +469,7 @@ export class InraidController
|
||||
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
// 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")
|
||||
{
|
||||
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
|
||||
// This is to stop items being duplicated by being returned from both the item delivery, and insurance
|
||||
const deliveredItemIds = items.map(x => x._id);
|
||||
pmcData.InsuredItems = pmcData.InsuredItems.filter(x => !deliveredItemIds.includes(x.itemId));
|
||||
const deliveredItemIds = items.map((x) => x._id);
|
||||
pmcData.InsuredItems = pmcData.InsuredItems.filter((x) => !deliveredItemIds.includes(x.itemId));
|
||||
|
||||
// Send the items to the player
|
||||
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
||||
|
@ -112,7 +112,7 @@ export class InsuranceController
|
||||
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
|
||||
{
|
||||
this.logger.debug(
|
||||
`Processing ${insuranceDetails.length} insurance packages, which includes a total of ${
|
||||
this.countAllInsuranceItems(insuranceDetails)
|
||||
} items, in profile ${sessionID}`,
|
||||
`Processing ${insuranceDetails.length} insurance packages, which includes a total of ${this.countAllInsuranceItems(
|
||||
insuranceDetails,
|
||||
)} items, in profile ${sessionID}`,
|
||||
);
|
||||
|
||||
// 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
|
||||
{
|
||||
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
|
||||
{
|
||||
const profile = this.saveServer.getProfile(sessionID);
|
||||
profile.insurance = profile.insurance.filter(insurance =>
|
||||
insurance.traderId !== insPackage.traderId
|
||||
|| insurance.systemData.date !== insPackage.systemData.date
|
||||
|| insurance.systemData.time !== insPackage.systemData.time
|
||||
|| insurance.systemData.location !== insPackage.systemData.location,
|
||||
profile.insurance = profile.insurance.filter(
|
||||
(insurance) =>
|
||||
insurance.traderId !== insPackage.traderId
|
||||
|| insurance.systemData.date !== insPackage.systemData.date
|
||||
|| insurance.systemData.time !== insPackage.systemData.time
|
||||
|| insurance.systemData.location !== insPackage.systemData.location,
|
||||
);
|
||||
|
||||
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);
|
||||
|
||||
// Check to see if any regular items are present.
|
||||
const hasRegularItems = Array.from(itemsMap.values()).some(item =>
|
||||
!this.itemHelper.isAttachmentAttached(item),
|
||||
const hasRegularItems = Array.from(itemsMap.values()).some(
|
||||
(item) => !this.itemHelper.isAttachmentAttached(item),
|
||||
);
|
||||
|
||||
// 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)
|
||||
{
|
||||
// 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.
|
||||
if (!parentItem && insuredItem.parentId !== rootItemParentID)
|
||||
@ -489,7 +490,7 @@ export class InsuranceController
|
||||
{
|
||||
this.logger.debug(
|
||||
`Attachment ${index} Id: ${attachmentId} Tpl: ${
|
||||
attachments.find(x => x._id === attachmentId)?._tpl
|
||||
attachments.find((x) => x._id === attachmentId)?._tpl
|
||||
} - Price: ${attachmentPrices[attachmentId]}`,
|
||||
);
|
||||
index++;
|
||||
@ -556,7 +557,7 @@ export class InsuranceController
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,7 +106,7 @@ export class InventoryController
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Internal item move but item never existed, possible dupe glitch
|
||||
@ -168,9 +168,10 @@ export class InventoryController
|
||||
return;
|
||||
}
|
||||
|
||||
const profileToRemoveItemFrom = (!request.fromOwner || request.fromOwner.id === pmcData._id)
|
||||
? pmcData
|
||||
: this.profileHelper.getFullProfile(sessionID).characters.scav;
|
||||
const profileToRemoveItemFrom
|
||||
= !request.fromOwner || request.fromOwner.id === pmcData._id
|
||||
? pmcData
|
||||
: this.profileHelper.getFullProfile(sessionID).characters.scav;
|
||||
|
||||
this.inventoryHelper.removeItem(profileToRemoveItemFrom, request.item, sessionID, output);
|
||||
}
|
||||
@ -197,12 +198,12 @@ export class InventoryController
|
||||
// Handle cartridge edge-case
|
||||
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
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
|
||||
// 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)
|
||||
{
|
||||
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
|
||||
const destinationItem = inventoryItems.to.find(x => x._id === body.with);
|
||||
const destinationItem = inventoryItems.to.find((x) => x._id === body.with);
|
||||
if (!destinationItem)
|
||||
{
|
||||
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
|
||||
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)
|
||||
{
|
||||
const errorMessage = `Unable to find item: ${sourceItem._id} to remove from sender inventory`;
|
||||
@ -339,8 +340,8 @@ export class InventoryController
|
||||
): IItemEventRouterResponse
|
||||
{
|
||||
const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID);
|
||||
const sourceItem = inventoryItems.from.find(item => item._id === body.item);
|
||||
const destinationItem = inventoryItems.to.find(item => item._id === body.with);
|
||||
const sourceItem = inventoryItems.from.find((item) => item._id === body.item);
|
||||
const destinationItem = inventoryItems.to.find((item) => item._id === body.with);
|
||||
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
*/
|
||||
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
|
||||
let playerData = pmcData;
|
||||
@ -453,7 +462,7 @@ export class InventoryController
|
||||
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)
|
||||
{
|
||||
// Item not found
|
||||
@ -476,7 +485,11 @@ export class InventoryController
|
||||
* @param sessionID Session id
|
||||
* @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
|
||||
let playerData = pmcData;
|
||||
@ -487,7 +500,7 @@ export class InventoryController
|
||||
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)
|
||||
{
|
||||
this.itemHelper.addUpdObjectToItem(
|
||||
@ -688,16 +701,16 @@ export class InventoryController
|
||||
if (request.fromOwner.id === Traders.FENCE)
|
||||
{
|
||||
// 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")
|
||||
{
|
||||
// Not fence
|
||||
// get tpl from trader assort
|
||||
return this.databaseServer.getTables().traders[request.fromOwner.id].assort.items.find(item =>
|
||||
item._id === request.item,
|
||||
)._tpl;
|
||||
return this.databaseServer
|
||||
.getTables()
|
||||
.traders[request.fromOwner.id].assort.items.find((item) => item._id === request.item)._tpl;
|
||||
}
|
||||
|
||||
if (request.fromOwner.type === "RagFair")
|
||||
@ -717,7 +730,7 @@ export class InventoryController
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
return matchingItem._tpl;
|
||||
@ -753,7 +766,7 @@ export class InventoryController
|
||||
{
|
||||
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)
|
||||
{
|
||||
this.logger.error(
|
||||
@ -792,7 +805,7 @@ export class InventoryController
|
||||
): void
|
||||
{
|
||||
// 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
|
||||
mapItem.upd.Map = mapItem.upd.Map || { Markers: [] };
|
||||
@ -818,7 +831,7 @@ export class InventoryController
|
||||
): void
|
||||
{
|
||||
// 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
|
||||
const markers = mapItem.upd.Map.Markers.filter((marker) =>
|
||||
@ -846,10 +859,10 @@ export class InventoryController
|
||||
): void
|
||||
{
|
||||
// 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
|
||||
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);
|
||||
mapItem.upd.Map.Markers[indexOfExistingNote] = request.mapMarker;
|
||||
|
||||
@ -883,7 +896,7 @@ export class InventoryController
|
||||
): void
|
||||
{
|
||||
/** 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 isSealedWeaponBox = containerDetailsDb[1]._name.includes("event_container_airdrop");
|
||||
|
||||
@ -934,8 +947,8 @@ export class InventoryController
|
||||
// Hard coded to `SYSTEM` for now
|
||||
// TODO: make this dynamic
|
||||
const dialog = fullProfile.dialogues["59e7125688a45068a6249071"];
|
||||
const mail = dialog.messages.find(x => x._id === event.MessageId);
|
||||
const mailEvent = mail.profileChangeEvents.find(x => x._id === event.EventId);
|
||||
const mail = dialog.messages.find((x) => x._id === event.MessageId);
|
||||
const mailEvent = mail.profileChangeEvents.find((x) => x._id === event.EventId);
|
||||
|
||||
switch (mailEvent.Type)
|
||||
{
|
||||
@ -954,15 +967,18 @@ export class InventoryController
|
||||
break;
|
||||
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;
|
||||
this.logger.success(`Set profile skill: ${mailEvent.entity} to: ${mailEvent.value}`);
|
||||
break;
|
||||
}
|
||||
case "ExamineAllItems":
|
||||
{
|
||||
const itemsToInspect = this.itemHelper.getItems().filter(x => x._type !== "Node");
|
||||
this.flagItemsAsInspectedAndRewardXp(itemsToInspect.map(x => x._id), fullProfile);
|
||||
const itemsToInspect = this.itemHelper.getItems().filter((x) => x._type !== "Node");
|
||||
this.flagItemsAsInspectedAndRewardXp(
|
||||
itemsToInspect.map((x) => x._id),
|
||||
fullProfile,
|
||||
);
|
||||
this.logger.success(`Flagged ${itemsToInspect.length} items as examined`);
|
||||
break;
|
||||
}
|
||||
@ -987,7 +1003,7 @@ export class InventoryController
|
||||
for (const itemId of request.items)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
pmcData.Inventory.favoriteItems.splice(indexOfItemAlreadyFavorited, 1);
|
||||
|
@ -92,9 +92,9 @@ export class LocationController
|
||||
|
||||
// Check for a loot multipler adjustment in app context and apply if one is found
|
||||
let locationConfigCopy: ILocationConfig;
|
||||
const raidAdjustments = this.applicationContext.getLatestValue(ContextVariableType.RAID_ADJUSTMENTS)?.getValue<
|
||||
IRaidChanges
|
||||
>();
|
||||
const raidAdjustments = this.applicationContext
|
||||
.getLatestValue(ContextVariableType.RAID_ADJUSTMENTS)
|
||||
?.getValue<IRaidChanges>();
|
||||
if (raidAdjustments)
|
||||
{
|
||||
locationConfigCopy = this.cloner.clone(this.locationConfig); // Clone values so they can be used to reset originals later
|
||||
|
@ -24,9 +24,7 @@ export class PresetController
|
||||
if (id !== preset._id)
|
||||
{
|
||||
this.logger.error(
|
||||
`Preset for template tpl: '${
|
||||
preset._items[0]._tpl
|
||||
} ${preset._name}' has invalid key: (${id} != ${preset._id}). Skipping`,
|
||||
`Preset for template tpl: '${preset._items[0]._tpl} ${preset._name}' has invalid key: (${id} != ${preset._id}). Skipping`,
|
||||
);
|
||||
|
||||
continue;
|
||||
|
@ -129,10 +129,8 @@ export class ProfileController
|
||||
public createProfile(info: IProfileCreateRequestData, sessionID: string): string
|
||||
{
|
||||
const account = this.saveServer.getProfile(sessionID).info;
|
||||
const profile: ITemplateSide = this.databaseServer
|
||||
.getTables()
|
||||
.templates
|
||||
.profiles[account.edition][info.side.toLowerCase()];
|
||||
const profile: ITemplateSide
|
||||
= this.databaseServer.getTables().templates.profiles[account.edition][info.side.toLowerCase()];
|
||||
const pmcData = profile.character;
|
||||
|
||||
// Delete existing profile
|
||||
@ -152,7 +150,7 @@ export class ProfileController
|
||||
pmcData.Customization.Head = info.headId;
|
||||
pmcData.Health.UpdateTime = this.timeUtil.getTimestamp();
|
||||
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.CarExtractCounts = {};
|
||||
pmcData.CoopExtractCounts = {};
|
||||
@ -398,16 +396,18 @@ export class ProfileController
|
||||
const profile = this.saveServer.getProfile(sessionID);
|
||||
|
||||
// return some of the current player info for now
|
||||
return [{
|
||||
_id: profile.characters.pmc._id,
|
||||
aid: profile.characters.pmc.aid,
|
||||
Info: {
|
||||
Nickname: info.nickname,
|
||||
Side: "Bear",
|
||||
Level: 1,
|
||||
MemberCategory: profile.characters.pmc.Info.MemberCategory,
|
||||
return [
|
||||
{
|
||||
_id: profile.characters.pmc._id,
|
||||
aid: profile.characters.pmc.aid,
|
||||
Info: {
|
||||
Nickname: info.nickname,
|
||||
Side: "Bear",
|
||||
Level: 1,
|
||||
MemberCategory: profile.characters.pmc.Info.MemberCategory,
|
||||
},
|
||||
},
|
||||
}];
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -418,14 +418,17 @@ export class ProfileController
|
||||
const account = this.saveServer.getProfile(sessionId).info;
|
||||
const response: GetProfileStatusResponseData = {
|
||||
maxPveCountExceeded: false,
|
||||
profiles: [{ profileid: account.scavId, profileToken: null, status: "Free", sid: "", ip: "", port: 0 }, {
|
||||
profileid: account.id,
|
||||
profileToken: null,
|
||||
status: "Free",
|
||||
sid: "",
|
||||
ip: "",
|
||||
port: 0,
|
||||
}],
|
||||
profiles: [
|
||||
{ profileid: account.scavId, profileToken: null, status: "Free", sid: "", ip: "", port: 0 },
|
||||
{
|
||||
profileid: account.id,
|
||||
profileToken: null,
|
||||
status: "Free",
|
||||
sid: "",
|
||||
ip: "",
|
||||
port: 0,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return response;
|
||||
@ -459,7 +462,7 @@ export class ProfileController
|
||||
skills: playerPmc.Skills,
|
||||
equipment: {
|
||||
// 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,
|
||||
},
|
||||
achievements: playerPmc.Achievements,
|
||||
|
@ -78,7 +78,7 @@ export class QuestController
|
||||
for (const quest of allQuests)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
quest.sptStatus = questInProfile.status;
|
||||
@ -123,7 +123,11 @@ export class QuestController
|
||||
);
|
||||
|
||||
// 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;
|
||||
questsToShowPlayer.push(quest);
|
||||
@ -136,7 +140,7 @@ export class QuestController
|
||||
for (const conditionToFulfil of questRequirements)
|
||||
{
|
||||
// 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),
|
||||
);
|
||||
if (!prerequisiteQuest)
|
||||
@ -147,7 +151,7 @@ export class QuestController
|
||||
|
||||
// Prereq does not have its status requirement fulfilled
|
||||
// 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;
|
||||
break;
|
||||
@ -291,7 +295,7 @@ export class QuestController
|
||||
|
||||
// Does quest exist 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)
|
||||
{
|
||||
// Update existing
|
||||
@ -398,16 +402,17 @@ export class QuestController
|
||||
fullProfile.characters.scav.Quests.push(newRepeatableQuest);
|
||||
}
|
||||
|
||||
const repeatableSettings = pmcData.RepeatableQuests.find(x =>
|
||||
x.name === repeatableQuestProfile.sptRepatableGroupName,
|
||||
const repeatableSettings = pmcData.RepeatableQuests.find(
|
||||
(x) => x.name === repeatableQuestProfile.sptRepatableGroupName,
|
||||
);
|
||||
|
||||
const change = {};
|
||||
change[repeatableQuestProfile._id] = repeatableSettings.changeRequirement[repeatableQuestProfile._id];
|
||||
const responseData: IPmcDataRepeatableQuest = {
|
||||
id: repeatableSettings.id ?? this.questConfig.repeatableQuests.find(x =>
|
||||
x.name === repeatableQuestProfile.sptRepatableGroupName,
|
||||
).id,
|
||||
id:
|
||||
repeatableSettings.id
|
||||
?? this.questConfig.repeatableQuests.find((x) => x.name === repeatableQuestProfile.sptRepatableGroupName)
|
||||
.id,
|
||||
name: repeatableSettings.name,
|
||||
endTime: repeatableSettings.endTime,
|
||||
changeRequirement: change,
|
||||
@ -430,11 +435,14 @@ export class QuestController
|
||||
* @param acceptedQuest Quest to search for
|
||||
* @returns IRepeatableQuest
|
||||
*/
|
||||
protected getRepeatableQuestFromProfile(pmcData: IPmcData, acceptedQuest: IAcceptQuestRequestData): IRepeatableQuest
|
||||
protected getRepeatableQuestFromProfile(
|
||||
pmcData: IPmcData,
|
||||
acceptedQuest: IAcceptQuestRequestData,
|
||||
): IRepeatableQuest
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
for (const currentRepeatable of pmcData.RepeatableQuests)
|
||||
{
|
||||
const repeatableQuest = currentRepeatable.activeQuests.find(activeRepeatable =>
|
||||
activeRepeatable._id === completedQuestId,
|
||||
const repeatableQuest = currentRepeatable.activeQuests.find(
|
||||
(activeRepeatable) => activeRepeatable._id === completedQuestId,
|
||||
);
|
||||
if (repeatableQuest)
|
||||
{
|
||||
@ -547,15 +555,15 @@ export class QuestController
|
||||
|
||||
// Quest already failed in profile, skip
|
||||
if (
|
||||
pmcProfile.Quests.some(profileQuest =>
|
||||
profileQuest.qid === quest._id && profileQuest.status === QuestStatus.Fail,
|
||||
pmcProfile.Quests.some(
|
||||
(profileQuest) => profileQuest.qid === quest._id && profileQuest.status === QuestStatus.Fail,
|
||||
)
|
||||
)
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
this.logger.warning(
|
||||
@ -599,7 +607,7 @@ export class QuestController
|
||||
for (const quest of postQuestStatuses)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
result.push(quest);
|
||||
@ -652,8 +660,8 @@ export class QuestController
|
||||
for (const quest of quests)
|
||||
{
|
||||
// If quest has prereq of completed quest + availableAfter value > 0 (quest has wait time)
|
||||
const nextQuestWaitCondition = quest.conditions.AvailableForStart.find(x =>
|
||||
x.target?.includes(completedQuestId) && x.availableAfter > 0,
|
||||
const nextQuestWaitCondition = quest.conditions.AvailableForStart.find(
|
||||
(x) => x.target?.includes(completedQuestId) && x.availableAfter > 0,
|
||||
);
|
||||
if (nextQuestWaitCondition)
|
||||
{
|
||||
@ -661,7 +669,7 @@ export class QuestController
|
||||
const availableAfterTimestamp = this.timeUtil.getTimestamp() + nextQuestWaitCondition.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)
|
||||
{
|
||||
existingQuestInProfile.availableAfter = availableAfterTimestamp;
|
||||
@ -704,12 +712,12 @@ export class QuestController
|
||||
for (const questToFail of questsToFail)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
const isActiveQuestInPlayerProfile = pmcData.Quests.find(quest => quest.qid === questToFail._id);
|
||||
const isActiveQuestInPlayerProfile = pmcData.Quests.find((quest) => quest.qid === questToFail._id);
|
||||
if (isActiveQuestInPlayerProfile)
|
||||
{
|
||||
if (isActiveQuestInPlayerProfile.status !== QuestStatus.Fail)
|
||||
@ -771,9 +779,10 @@ export class QuestController
|
||||
isItemHandoverQuest = condition.conditionType === handoverQuestTypes[0];
|
||||
handoverRequirements = condition;
|
||||
|
||||
const profileCounter = handoverQuestRequest.conditionId in pmcData.TaskConditionCounters
|
||||
? pmcData.TaskConditionCounters[handoverQuestRequest.conditionId].value
|
||||
: 0;
|
||||
const profileCounter
|
||||
= handoverQuestRequest.conditionId in pmcData.TaskConditionCounters
|
||||
? pmcData.TaskConditionCounters[handoverQuestRequest.conditionId].value
|
||||
: 0;
|
||||
handedInCount -= profileCounter;
|
||||
|
||||
if (handedInCount <= 0)
|
||||
@ -805,7 +814,7 @@ export class QuestController
|
||||
let totalItemCountToRemove = 0;
|
||||
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)))
|
||||
{
|
||||
// Item handed in by player doesnt match what was requested
|
||||
|
@ -27,7 +27,6 @@ import { ISearchRequestData } from "@spt-aki/models/eft/ragfair/ISearchRequestDa
|
||||
import { IProcessBuyTradeRequestData } from "@spt-aki/models/eft/trade/IProcessBuyTradeRequestData";
|
||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||
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 { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
|
||||
@ -159,7 +158,7 @@ export class RagfairController
|
||||
public getOfferById(sessionId: string, request: IGetRagfairOfferByIdRequest): IRagfairOffer
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -207,12 +206,8 @@ export class RagfairController
|
||||
): Record<string, number>
|
||||
{
|
||||
// Linked/required search categories
|
||||
const playerHasFleaUnlocked = pmcProfile.Info.Level >= this.databaseServer
|
||||
.getTables()
|
||||
.globals
|
||||
.config
|
||||
.RagFair
|
||||
.minUserLevel;
|
||||
const playerHasFleaUnlocked
|
||||
= pmcProfile.Info.Level >= this.databaseServer.getTables().globals.config.RagFair.minUserLevel;
|
||||
let offerPool = [];
|
||||
if (this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest))
|
||||
{
|
||||
@ -263,7 +258,7 @@ export class RagfairController
|
||||
|
||||
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items;
|
||||
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
|
||||
offer.buyRestrictionCurrent = fullProfile.traderPurchases[offer.user.id][assortId]
|
||||
@ -282,7 +277,7 @@ export class RagfairController
|
||||
const firstItem = offer.items[0];
|
||||
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)
|
||||
{
|
||||
this.logger.warning(
|
||||
@ -357,31 +352,34 @@ export class RagfairController
|
||||
|
||||
// Get the average offer price, excluding barter offers
|
||||
let avgOfferCount = 0;
|
||||
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)))
|
||||
const avg
|
||||
= offers.reduce((sum, offer) =>
|
||||
{
|
||||
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
|
||||
const offerItemCount = Math.max(offer.sellInOnePiece ? offer.items[0].upd?.StackObjectsCount ?? 1 : 1);
|
||||
const perItemPrice = offer.requirementsCost / offerItemCount;
|
||||
// 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 perItemPrice = offer.requirementsCost / offerItemCount;
|
||||
|
||||
// Handle min/max calculations based on the per-item price
|
||||
if (perItemPrice < min)
|
||||
{
|
||||
min = perItemPrice;
|
||||
}
|
||||
else if (perItemPrice > max)
|
||||
{
|
||||
max = perItemPrice;
|
||||
}
|
||||
// Handle min/max calculations based on the per-item price
|
||||
if (perItemPrice < min)
|
||||
{
|
||||
min = perItemPrice;
|
||||
}
|
||||
else if (perItemPrice > max)
|
||||
{
|
||||
max = perItemPrice;
|
||||
}
|
||||
|
||||
avgOfferCount++;
|
||||
return sum + perItemPrice;
|
||||
}, 0) / Math.max(avgOfferCount, 1);
|
||||
avgOfferCount++;
|
||||
return sum + perItemPrice;
|
||||
}, 0) / Math.max(avgOfferCount, 1);
|
||||
|
||||
// If no items were actually counted, min will still be MAX_VALUE, so set it to 0
|
||||
if (min === Number.MAX_VALUE)
|
||||
@ -428,8 +426,8 @@ export class RagfairController
|
||||
}
|
||||
|
||||
// Get an array of items from player inventory to list on flea
|
||||
const { items: itemsInInventoryToList, errorMessage: itemsInInventoryError } = this
|
||||
.getItemsToListOnFleaFromInventory(pmcData, offerRequest.items);
|
||||
const { items: itemsInInventoryToList, errorMessage: itemsInInventoryError }
|
||||
= this.getItemsToListOnFleaFromInventory(pmcData, offerRequest.items);
|
||||
if (!itemsInInventoryToList || itemsInInventoryError)
|
||||
{
|
||||
this.httpResponse.appendErrorToOutput(output, itemsInInventoryError);
|
||||
@ -605,8 +603,8 @@ export class RagfairController
|
||||
}
|
||||
else
|
||||
{
|
||||
requirementsPriceInRub += this.ragfairPriceService
|
||||
.getDynamicPriceForItem(requestedItemTpl) * item.count;
|
||||
requirementsPriceInRub
|
||||
+= 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
|
||||
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)
|
||||
{
|
||||
errorMessage = this.localisationService.getText("ragfair-unable_to_find_item_in_inventory", {
|
||||
@ -666,7 +664,7 @@ export class RagfairController
|
||||
const loyalLevel = 1;
|
||||
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 {
|
||||
_id: item._id,
|
||||
@ -727,7 +725,7 @@ export class RagfairController
|
||||
pmcData.RagfairInfo.offers = [];
|
||||
}
|
||||
|
||||
const playerOfferIndex = playerProfileOffers.findIndex(offer => offer._id === removeRequest.offerId);
|
||||
const playerOfferIndex = playerProfileOffers.findIndex((offer) => offer._id === removeRequest.offerId);
|
||||
if (playerOfferIndex === -1)
|
||||
{
|
||||
this.logger.error(
|
||||
@ -764,7 +762,7 @@ export class RagfairController
|
||||
|
||||
const pmcData = this.saveServer.getProfile(sessionId).characters.pmc;
|
||||
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;
|
||||
|
||||
if (playerOfferIndex === -1)
|
||||
|
@ -7,7 +7,6 @@ import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||
import { IRepairActionDataRequest } from "@spt-aki/models/eft/repair/IRepairActionDataRequest";
|
||||
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 { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
|
||||
@ -86,7 +85,11 @@ export class RepairController
|
||||
* @param pmcData player profile
|
||||
* @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);
|
||||
|
||||
|
@ -90,7 +90,7 @@ export class RepeatableQuestController
|
||||
const pmcData = this.profileHelper.getPmcProfile(sessionID);
|
||||
const time = this.timeUtil.getTimestamp();
|
||||
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
|
||||
for (const repeatableConfig of this.questConfig.repeatableQuests)
|
||||
@ -118,7 +118,7 @@ export class RepeatableQuestController
|
||||
for (const activeQuest of currentRepeatableQuestType.activeQuests)
|
||||
{
|
||||
// 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.status === QuestStatus.AvailableForFinish)
|
||||
@ -134,7 +134,7 @@ export class RepeatableQuestController
|
||||
this.profileFixerService.removeDanglingConditionCounters(pmcData);
|
||||
|
||||
// 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.activeQuests = questsToKeep;
|
||||
@ -216,14 +216,11 @@ export class RepeatableQuestController
|
||||
)
|
||||
{
|
||||
// Elite charisma skill gives extra daily quest(s)
|
||||
return repeatableConfig.numQuests + this.databaseServer.getTables()
|
||||
.globals
|
||||
.config
|
||||
.SkillsSettings
|
||||
.Charisma
|
||||
.BonusSettings
|
||||
.EliteBonusSettings
|
||||
.RepeatableQuestExtraCount;
|
||||
return (
|
||||
repeatableConfig.numQuests
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.Charisma.BonusSettings.EliteBonusSettings
|
||||
.RepeatableQuestExtraCount
|
||||
);
|
||||
}
|
||||
|
||||
return repeatableConfig.numQuests;
|
||||
@ -241,7 +238,7 @@ export class RepeatableQuestController
|
||||
): IPmcDataRepeatableQuest
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
repeatableQuestDetails = {
|
||||
@ -331,9 +328,10 @@ export class RepeatableQuestController
|
||||
const possibleLocations = Object.keys(locations);
|
||||
|
||||
// Set possible locations for elimination task, if target is savage, exclude labs from locations
|
||||
questPool.pool.Elimination.targets[probabilityObject.key] = probabilityObject.key === "Savage"
|
||||
? { locations: possibleLocations.filter(x => x !== "laboratory") }
|
||||
: { locations: possibleLocations };
|
||||
questPool.pool.Elimination.targets[probabilityObject.key]
|
||||
= probabilityObject.key === "Savage"
|
||||
? { locations: possibleLocations.filter((x) => x !== "laboratory") }
|
||||
: { locations: possibleLocations };
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,7 +441,7 @@ export class RepeatableQuestController
|
||||
for (const currentRepeatablePool of pmcData.RepeatableQuests)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
continue;
|
||||
@ -453,8 +451,8 @@ export class RepeatableQuestController
|
||||
replacedQuestTraderId = questToReplace.traderId;
|
||||
|
||||
// Update active quests to exclude the quest we're replacing
|
||||
currentRepeatablePool.activeQuests = currentRepeatablePool.activeQuests.filter(x =>
|
||||
x._id !== changeRequest.qid,
|
||||
currentRepeatablePool.activeQuests = currentRepeatablePool.activeQuests.filter(
|
||||
(x) => x._id !== changeRequest.qid,
|
||||
);
|
||||
|
||||
// Get cost to replace existing quest
|
||||
@ -462,8 +460,8 @@ export class RepeatableQuestController
|
||||
delete currentRepeatablePool.changeRequirement[changeRequest.qid];
|
||||
// TODO: somehow we need to reduce the questPool by the currently active quests (for all repeatables)
|
||||
|
||||
const repeatableConfig = this.questConfig.repeatableQuests.find(x =>
|
||||
x.name === currentRepeatablePool.name,
|
||||
const repeatableConfig = this.questConfig.repeatableQuests.find(
|
||||
(x) => x.name === currentRepeatablePool.name,
|
||||
);
|
||||
const questTypePool = this.generateQuestPool(repeatableConfig, pmcData.Info.Level);
|
||||
const newRepeatableQuest = this.attemptToGenerateRepeatableQuest(pmcData, questTypePool, repeatableConfig);
|
||||
|
@ -4,7 +4,7 @@ import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||
import { TradeHelper } from "@spt-aki/helpers/TradeHelper";
|
||||
import { TraderHelper } from "@spt-aki/helpers/TraderHelper";
|
||||
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 { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||
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
|
||||
if (this.playerLacksTraderLoyaltyLevelToBuyOffer(fleaOffer, pmcData))
|
||||
{
|
||||
const errorMessage = `Unable to buy item: ${
|
||||
fleaOffer.items[0]._tpl
|
||||
} from trader: ${fleaOffer.user.id} as loyalty level too low, skipping`;
|
||||
const errorMessage = `Unable to buy item: ${fleaOffer.items[0]._tpl} from trader: ${fleaOffer.user.id} as loyalty level too low, skipping`;
|
||||
this.logger.debug(errorMessage);
|
||||
|
||||
this.httpResponse.appendErrorToOutput(output, errorMessage, BackendErrorCodes.RAGFAIRUNAVAILABLE);
|
||||
@ -291,7 +289,7 @@ export class TradeController
|
||||
this.traderHelper.getTraderById(trader),
|
||||
MessageType.MESSAGE_WITH_ITEMS,
|
||||
this.randomUtil.getArrayValue(this.databaseServer.getTables().traders[trader].dialogue.soldItems),
|
||||
curencyReward.flatMap(x => x),
|
||||
curencyReward.flatMap((x) => x),
|
||||
this.timeUtil.getHoursAsSeconds(72),
|
||||
);
|
||||
}
|
||||
@ -317,10 +315,12 @@ export class TradeController
|
||||
for (const itemToSell of itemWithChildren)
|
||||
{
|
||||
const itemDetails = this.itemHelper.getItem(itemToSell._tpl);
|
||||
if (!(itemDetails[0] && this.itemHelper.isOfBaseclasses(
|
||||
itemDetails[1]._id,
|
||||
traderDetails.items_buy.category,
|
||||
)))
|
||||
if (
|
||||
!(
|
||||
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
|
||||
continue;
|
||||
|
@ -29,7 +29,8 @@ export class TraderController
|
||||
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||
@inject("TraderHelper") protected traderHelper: TraderHelper,
|
||||
@inject("TraderAssortService") protected traderAssortService: TraderAssortService,
|
||||
@inject("TraderPurchasePersisterService") protected traderPurchasePersisterService: TraderPurchasePersisterService,
|
||||
@inject("TraderPurchasePersisterService")
|
||||
protected traderPurchasePersisterService: TraderPurchasePersisterService,
|
||||
@inject("FenceService") protected fenceService: FenceService,
|
||||
@inject("FenceBaseAssortGenerator") protected fenceBaseAssortGenerator: FenceBaseAssortGenerator,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
|
@ -28,7 +28,11 @@ export class WishlistController
|
||||
}
|
||||
|
||||
/** 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++)
|
||||
{
|
||||
|
@ -791,9 +791,13 @@ export class Container
|
||||
depContainer.register<CustomizationController>("CustomizationController", {
|
||||
useClass: CustomizationController,
|
||||
});
|
||||
depContainer.register<DialogueController>("DialogueController", { useClass: DialogueController }, {
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
});
|
||||
depContainer.register<DialogueController>(
|
||||
"DialogueController",
|
||||
{ useClass: DialogueController },
|
||||
{
|
||||
lifecycle: Lifecycle.Singleton,
|
||||
},
|
||||
);
|
||||
depContainer.register<GameController>("GameController", { useClass: GameController });
|
||||
depContainer.register<HandbookController>("HandbookController", { useClass: HandbookController });
|
||||
depContainer.register<HealthController>("HealthController", { useClass: HealthController });
|
||||
|
@ -29,9 +29,13 @@ export class Router
|
||||
{
|
||||
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>
|
||||
{
|
||||
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[]
|
||||
{
|
||||
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>
|
||||
{
|
||||
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[]
|
||||
{
|
||||
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
|
||||
{
|
||||
constructor(public route: string, public dynamic: boolean)
|
||||
constructor(
|
||||
public route: string,
|
||||
public dynamic: boolean,
|
||||
)
|
||||
{}
|
||||
}
|
||||
|
||||
|
@ -233,8 +233,9 @@ export class BotEquipmentModGenerator
|
||||
}
|
||||
|
||||
// Get the front/back/side weights based on bots level
|
||||
const plateSlotWeights = settings.botEquipmentConfig?.armorPlateWeighting?.find(armorWeight =>
|
||||
settings.botLevel >= armorWeight.levelRange.min && settings.botLevel <= armorWeight.levelRange.max,
|
||||
const plateSlotWeights = settings.botEquipmentConfig?.armorPlateWeighting?.find(
|
||||
(armorWeight) =>
|
||||
settings.botLevel >= armorWeight.levelRange.min && settings.botLevel <= armorWeight.levelRange.max,
|
||||
);
|
||||
if (!plateSlotWeights)
|
||||
{
|
||||
@ -260,17 +261,17 @@ export class BotEquipmentModGenerator
|
||||
const chosenArmorPlateLevel = this.weightedRandomHelper.getWeightedValue<string>(plateWeights);
|
||||
|
||||
// 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
|
||||
const platesOfDesiredLevel = platesFromDb.filter(item => item._props.armorClass === chosenArmorPlateLevel);
|
||||
const platesOfDesiredLevel = platesFromDb.filter((item) => item._props.armorClass === chosenArmorPlateLevel);
|
||||
if (platesOfDesiredLevel.length === 0)
|
||||
{
|
||||
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`,
|
||||
);
|
||||
|
||||
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;
|
||||
if (!defaultPlate)
|
||||
{
|
||||
@ -280,8 +281,8 @@ export class BotEquipmentModGenerator
|
||||
const defaultPreset = this.presetHelper.getDefaultPreset(armorItem._id);
|
||||
if (defaultPreset)
|
||||
{
|
||||
const relatedPresetSlot = defaultPreset._items.find(item =>
|
||||
item.slotId?.toLowerCase() === modSlot,
|
||||
const relatedPresetSlot = defaultPreset._items.find(
|
||||
(item) => item.slotId?.toLowerCase() === modSlot,
|
||||
);
|
||||
if (relatedPresetSlot)
|
||||
{
|
||||
@ -305,7 +306,7 @@ export class BotEquipmentModGenerator
|
||||
|
||||
// Only return the items ids
|
||||
result.result = Result.SUCCESS;
|
||||
result.plateModTpls = platesOfDesiredLevel.map(item => item._id);
|
||||
result.plateModTpls = platesOfDesiredLevel.map((item) => item._id);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -345,8 +346,11 @@ export class BotEquipmentModGenerator
|
||||
const compatibleModsPool = modPool[parentTemplate._id];
|
||||
|
||||
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(
|
||||
@ -467,10 +471,9 @@ export class BotEquipmentModGenerator
|
||||
// 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
|
||||
if (
|
||||
modSlot === "mod_handguard" && modToAddTemplate._props.Slots.find(slot =>
|
||||
slot._name === "mod_handguard",
|
||||
)
|
||||
&& !weapon.find(item => item.slotId === "mod_launcher")
|
||||
modSlot === "mod_handguard"
|
||||
&& modToAddTemplate._props.Slots.find((slot) => slot._name === "mod_handguard")
|
||||
&& !weapon.find((item) => item.slotId === "mod_launcher")
|
||||
)
|
||||
{
|
||||
// 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
|
||||
// Or if mod_stock is configured to be forced on
|
||||
if (
|
||||
modSlot === "mod_stock" && modToAddTemplate._props.Slots.find(slot =>
|
||||
slot._name.includes("mod_stock") || botEquipConfig.forceStock,
|
||||
modSlot === "mod_stock"
|
||||
&& 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
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -565,15 +570,17 @@ export class BotEquipmentModGenerator
|
||||
*/
|
||||
protected modSlotCanHoldScope(modSlot: string, modsParentId: string): boolean
|
||||
{
|
||||
return [
|
||||
"mod_scope",
|
||||
"mod_mount",
|
||||
"mod_mount_000",
|
||||
"mod_scope_000",
|
||||
"mod_scope_001",
|
||||
"mod_scope_002",
|
||||
"mod_scope_003",
|
||||
].includes(modSlot.toLowerCase()) && modsParentId === BaseClasses.MOUNT;
|
||||
return (
|
||||
[
|
||||
"mod_scope",
|
||||
"mod_mount",
|
||||
"mod_mount_000",
|
||||
"mod_scope_000",
|
||||
"mod_scope_001",
|
||||
"mod_scope_002",
|
||||
"mod_scope_003",
|
||||
].includes(modSlot.toLowerCase()) && modsParentId === BaseClasses.MOUNT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -700,11 +707,11 @@ export class BotEquipmentModGenerator
|
||||
case "patron_in_weapon":
|
||||
case "patron_in_weapon_000":
|
||||
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":
|
||||
return parentTemplate._props.Cartridges.find(c => c._name.toLowerCase() === modSlotLower);
|
||||
return parentTemplate._props.Cartridges.find((c) => c._name.toLowerCase() === modSlotLower);
|
||||
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]
|
||||
{
|
||||
/** 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];
|
||||
|
||||
// It's ammo, use predefined ammo parameter
|
||||
@ -837,9 +844,7 @@ export class BotEquipmentModGenerator
|
||||
if (parentSlot._required)
|
||||
{
|
||||
this.logger.warning(
|
||||
`Required slot unable to be filled, ${modSlot} on ${parentTemplate._name} ${parentTemplate._id} for weapon: ${
|
||||
weapon[0]._tpl
|
||||
}`,
|
||||
`Required slot unable to be filled, ${modSlot} on ${parentTemplate._name} ${parentTemplate._id} for weapon: ${weapon[0]._tpl}`,
|
||||
);
|
||||
}
|
||||
|
||||
@ -950,8 +955,8 @@ export class BotEquipmentModGenerator
|
||||
if (modSpawnResult === ModSpawn.DEFAULT_MOD)
|
||||
{
|
||||
const matchingPreset = this.getMatchingPreset(weaponTemplate, parentTemplate._id);
|
||||
const matchingModFromPreset = matchingPreset?._items.find(item =>
|
||||
item?.slotId?.toLowerCase() === modSlot.toLowerCase(),
|
||||
const matchingModFromPreset = matchingPreset?._items.find(
|
||||
(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
|
||||
@ -968,8 +973,8 @@ export class BotEquipmentModGenerator
|
||||
|
||||
// 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
|
||||
const parentSlotCompatibleItems = parentTemplate._props.Slots?.find(slot =>
|
||||
slot._name.toLowerCase() === modSlot.toLowerCase(),
|
||||
const parentSlotCompatibleItems = parentTemplate._props.Slots?.find(
|
||||
(slot) => slot._name.toLowerCase() === modSlot.toLowerCase(),
|
||||
)._props.filters[0].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)
|
||||
{
|
||||
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
|
||||
@ -1178,7 +1185,7 @@ export class BotEquipmentModGenerator
|
||||
botEquipBlacklist: EquipmentFilterDetails,
|
||||
): 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)
|
||||
{
|
||||
const supportedSubMods = desiredSlotObject._props.filters[0].Filter;
|
||||
@ -1261,10 +1268,10 @@ export class BotEquipmentModGenerator
|
||||
let result: string[] = [];
|
||||
|
||||
// Get item blacklist and mod equipment blacklist as one array
|
||||
const blacklist = this.itemFilterService.getBlacklistedItems().concat(
|
||||
botEquipBlacklist.equipment[modSlot] || [],
|
||||
);
|
||||
result = allowedMods.filter(tpl => !blacklist.includes(tpl));
|
||||
const blacklist = this.itemFilterService
|
||||
.getBlacklistedItems()
|
||||
.concat(botEquipBlacklist.equipment[modSlot] || []);
|
||||
result = allowedMods.filter((tpl) => !blacklist.includes(tpl));
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1290,7 +1297,7 @@ export class BotEquipmentModGenerator
|
||||
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
|
||||
modPool[parentTemplate._id] = {};
|
||||
@ -1397,9 +1404,7 @@ export class BotEquipmentModGenerator
|
||||
if (!whitelistedSightTypes)
|
||||
{
|
||||
this.logger.debug(
|
||||
`Unable to find whitelist for weapon type: ${weaponDetails[1]._parent} ${
|
||||
weaponDetails[1]._name
|
||||
}, skipping sight filtering`,
|
||||
`Unable to find whitelist for weapon type: ${weaponDetails[1]._parent} ${weaponDetails[1]._name}, skipping sight filtering`,
|
||||
);
|
||||
|
||||
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)
|
||||
// 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),
|
||||
);
|
||||
|
||||
// Mods scope slot found must allow ALL whitelisted scope types OR be a mount
|
||||
if (
|
||||
scopeSlot?.every(slot =>
|
||||
slot._props.filters[0].Filter.every(tpl =>
|
||||
this.itemHelper.isOfBaseclasses(tpl, whitelistedSightTypes)
|
||||
|| this.itemHelper.isOfBaseclass(tpl, BaseClasses.MOUNT),
|
||||
scopeSlot?.every((slot) =>
|
||||
slot._props.filters[0].Filter.every(
|
||||
(tpl) =>
|
||||
this.itemHelper.isOfBaseclasses(tpl, whitelistedSightTypes)
|
||||
|| this.itemHelper.isOfBaseclass(tpl, BaseClasses.MOUNT),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
@ -232,7 +232,11 @@ export class BotGenerator
|
||||
* @param appearance Appearance settings to choose from
|
||||
* @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.Body = this.weightedRandomHelper.getWeightedValue<string>(appearance.body);
|
||||
@ -425,27 +429,29 @@ export class BotGenerator
|
||||
return [];
|
||||
}
|
||||
|
||||
return Object.keys(skills).map((skillKey): IBaseSkill =>
|
||||
{
|
||||
// Get skill from dict, skip if not found
|
||||
const skill = skills[skillKey];
|
||||
if (!skill)
|
||||
return Object.keys(skills)
|
||||
.map((skillKey): IBaseSkill =>
|
||||
{
|
||||
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
|
||||
const skillToAdd: IBaseSkill = { Id: skillKey, Progress: this.randomUtil.getInt(skill.min, skill.max) };
|
||||
// All skills have id and progress props
|
||||
const skillToAdd: IBaseSkill = { Id: skillKey, Progress: this.randomUtil.getInt(skill.min, skill.max) };
|
||||
|
||||
// Common skills have additional props
|
||||
if (isCommonSkills)
|
||||
{
|
||||
(skillToAdd as Common).PointsEarnedDuringSession = 0;
|
||||
(skillToAdd as Common).LastAccess = 0;
|
||||
}
|
||||
// Common skills have additional props
|
||||
if (isCommonSkills)
|
||||
{
|
||||
(skillToAdd as Common).PointsEarnedDuringSession = 0;
|
||||
(skillToAdd as Common).LastAccess = 0;
|
||||
}
|
||||
|
||||
return skillToAdd;
|
||||
}).filter(x => x !== null);
|
||||
return skillToAdd;
|
||||
})
|
||||
.filter((x) => x !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -307,8 +307,9 @@ export class BotInventoryGenerator
|
||||
*/
|
||||
protected generateEquipment(settings: IGenerateEquipmentProperties): boolean
|
||||
{
|
||||
const spawnChance = ([EquipmentSlots.POCKETS, EquipmentSlots.SECURED_CONTAINER] as string[])
|
||||
.includes(settings.rootEquipmentSlot)
|
||||
const spawnChance = ([EquipmentSlots.POCKETS, EquipmentSlots.SECURED_CONTAINER] as string[]).includes(
|
||||
settings.rootEquipmentSlot,
|
||||
)
|
||||
? 100
|
||||
: settings.spawnChances.equipment[settings.rootEquipmentSlot];
|
||||
|
||||
@ -442,7 +443,7 @@ export class BotInventoryGenerator
|
||||
for (const modSlot of Object.keys(modPool ?? []))
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -504,17 +505,21 @@ export class BotInventoryGenerator
|
||||
protected getDesiredWeaponsForBot(equipmentChances: Chances): { slot: EquipmentSlots, shouldSpawn: boolean }[]
|
||||
{
|
||||
const shouldSpawnPrimary = this.randomUtil.getChance100(equipmentChances.equipment.FirstPrimaryWeapon);
|
||||
return [{ slot: EquipmentSlots.FIRST_PRIMARY_WEAPON, shouldSpawn: shouldSpawnPrimary }, {
|
||||
slot: EquipmentSlots.SECOND_PRIMARY_WEAPON,
|
||||
shouldSpawn: shouldSpawnPrimary
|
||||
? this.randomUtil.getChance100(equipmentChances.equipment.SecondPrimaryWeapon)
|
||||
: false,
|
||||
}, {
|
||||
slot: EquipmentSlots.HOLSTER,
|
||||
shouldSpawn: shouldSpawnPrimary
|
||||
? this.randomUtil.getChance100(equipmentChances.equipment.Holster) // Primary weapon = roll for chance at pistol
|
||||
: true, // No primary = force pistol
|
||||
}];
|
||||
return [
|
||||
{ slot: EquipmentSlots.FIRST_PRIMARY_WEAPON, shouldSpawn: shouldSpawnPrimary },
|
||||
{
|
||||
slot: EquipmentSlots.SECOND_PRIMARY_WEAPON,
|
||||
shouldSpawn: shouldSpawnPrimary
|
||||
? this.randomUtil.getChance100(equipmentChances.equipment.SecondPrimaryWeapon)
|
||||
: false,
|
||||
},
|
||||
{
|
||||
slot: EquipmentSlots.HOLSTER,
|
||||
shouldSpawn: shouldSpawnPrimary
|
||||
? this.randomUtil.getChance100(equipmentChances.equipment.Holster) // Primary weapon = roll for chance at pistol
|
||||
: true, // No primary = force pistol
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,9 +65,10 @@ export class BotLevelGenerator
|
||||
maxLevel: number,
|
||||
): number
|
||||
{
|
||||
const maxPossibleLevel = botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride
|
||||
? 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
|
||||
const maxPossibleLevel
|
||||
= botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride
|
||||
? 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;
|
||||
if (level > maxPossibleLevel)
|
||||
@ -91,12 +92,13 @@ export class BotLevelGenerator
|
||||
maxlevel: number,
|
||||
): number
|
||||
{
|
||||
const minPossibleLevel = botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride
|
||||
? Math.min(
|
||||
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
|
||||
const minPossibleLevel
|
||||
= botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride
|
||||
? Math.min(
|
||||
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
|
||||
|
||||
let level = botGenerationDetails.playerLevel - botGenerationDetails.botRelativeLevelDeltaMin;
|
||||
if (level < minPossibleLevel)
|
||||
|
@ -85,7 +85,8 @@ export class BotLootGenerator
|
||||
// Limits on item types to be added as loot
|
||||
const itemCounts = botJsonTemplate.generation.items;
|
||||
|
||||
if(!itemCounts.backpackLoot.weights
|
||||
if (
|
||||
!itemCounts.backpackLoot.weights
|
||||
|| !itemCounts.pocketLoot.weights
|
||||
|| !itemCounts.vestLoot.weights
|
||||
|| !itemCounts.specialItems.weights
|
||||
@ -98,7 +99,9 @@ export class BotLootGenerator
|
||||
|| !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;
|
||||
}
|
||||
@ -334,12 +337,12 @@ export class BotLootGenerator
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (botInventory.items.find(item => item.slotId === EquipmentSlots.BACKPACK))
|
||||
if (botInventory.items.find((item) => item.slotId === EquipmentSlots.BACKPACK))
|
||||
{
|
||||
result.push(EquipmentSlots.BACKPACK);
|
||||
}
|
||||
@ -457,11 +460,13 @@ export class BotLootGenerator
|
||||
}
|
||||
|
||||
const newRootItemId = this.hashUtil.generate();
|
||||
const itemWithChildrenToAdd: Item[] = [{
|
||||
_id: newRootItemId,
|
||||
_tpl: itemToAddTemplate._id,
|
||||
...this.botGeneratorHelper.generateExtraPropertiesForItem(itemToAddTemplate, botRole),
|
||||
}];
|
||||
const itemWithChildrenToAdd: Item[] = [
|
||||
{
|
||||
_id: newRootItemId,
|
||||
_tpl: itemToAddTemplate._id,
|
||||
...this.botGeneratorHelper.generateExtraPropertiesForItem(itemToAddTemplate, botRole),
|
||||
},
|
||||
];
|
||||
|
||||
// Is Simple-Wallet / WZ wallet
|
||||
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)
|
||||
{
|
||||
this.logger.debug(
|
||||
`Failed to place item ${i} of ${totalItemCount} items into ${botRole} containers: ${
|
||||
equipmentSlots.join(",")
|
||||
}. Tried ${fitItemIntoContainerAttempts} times, reason: ${
|
||||
`Failed to place item ${i} of ${totalItemCount} items into ${botRole} containers: ${equipmentSlots.join(
|
||||
",",
|
||||
)}. Tried ${fitItemIntoContainerAttempts} times, reason: ${
|
||||
ItemAddedResult[itemAddedResult]
|
||||
}, skipping`,
|
||||
);
|
||||
@ -571,12 +576,14 @@ export class BotLootGenerator
|
||||
const chosenStackCount = Number(
|
||||
this.weightedRandomHelper.getWeightedValue<string>(this.botConfig.walletLoot.stackSizeWeight),
|
||||
);
|
||||
result.push([{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: this.weightedRandomHelper.getWeightedValue<string>(this.botConfig.walletLoot.currencyWeight),
|
||||
parentId: walletId,
|
||||
upd: { StackObjectsCount: chosenStackCount },
|
||||
}]);
|
||||
result.push([
|
||||
{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: this.weightedRandomHelper.getWeightedValue<string>(this.botConfig.walletLoot.currencyWeight),
|
||||
parentId: walletId,
|
||||
upd: { StackObjectsCount: chosenStackCount },
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -675,9 +682,7 @@ export class BotLootGenerator
|
||||
if (result !== ItemAddedResult.SUCCESS)
|
||||
{
|
||||
this.logger.debug(
|
||||
`Failed to add additional weapon ${generatedWeapon.weapon[0]._id} to bot backpack, reason: ${
|
||||
ItemAddedResult[result]
|
||||
}`,
|
||||
`Failed to add additional weapon ${generatedWeapon.weapon[0]._id} to bot backpack, reason: ${ItemAddedResult[result]}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -789,12 +794,13 @@ export class BotLootGenerator
|
||||
*/
|
||||
protected randomiseAmmoStackSize(isPmc: boolean, itemTemplate: ITemplateItem, ammoItem: Item): void
|
||||
{
|
||||
const randomSize = itemTemplate._props.StackMaxSize === 1
|
||||
? 1
|
||||
: this.randomUtil.getInt(
|
||||
itemTemplate._props.StackMinRandom,
|
||||
Math.min(itemTemplate._props.StackMaxRandom, 60),
|
||||
);
|
||||
const randomSize
|
||||
= itemTemplate._props.StackMaxSize === 1
|
||||
? 1
|
||||
: this.randomUtil.getInt(
|
||||
itemTemplate._props.StackMinRandom,
|
||||
Math.min(itemTemplate._props.StackMaxRandom, 60),
|
||||
);
|
||||
|
||||
this.itemHelper.addUpdObjectToItem(ammoItem);
|
||||
|
||||
|
@ -199,7 +199,7 @@ export class BotWeaponGenerator
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
@ -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
|
||||
const chamberSlotNames = weaponItemTemplate._props.Chambers.map(x => x._name);
|
||||
const chamberSlotNames = weaponItemTemplate._props.Chambers.map((x) => x._name);
|
||||
this.addCartridgeToChamber(weaponWithModsArray, ammoTpl, chamberSlotNames);
|
||||
}
|
||||
|
||||
// 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;
|
||||
if (ubglMod)
|
||||
{
|
||||
@ -245,7 +245,7 @@ export class BotWeaponGenerator
|
||||
{
|
||||
for (const slotId of chamberSlotIds)
|
||||
{
|
||||
const existingItemWithSlot = weaponWithModsArray.find(x => x.slotId === slotId);
|
||||
const existingItemWithSlot = weaponWithModsArray.find((x) => x.slotId === slotId);
|
||||
if (!existingItemWithSlot)
|
||||
{
|
||||
// Not found, add new slot to weapon
|
||||
@ -284,13 +284,15 @@ export class BotWeaponGenerator
|
||||
botRole: string,
|
||||
): Item[]
|
||||
{
|
||||
return [{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: weaponTpl,
|
||||
parentId: weaponParentId,
|
||||
slotId: equipmentSlot,
|
||||
...this.botGeneratorHelper.generateExtraPropertiesForItem(weaponItemTemplate, botRole),
|
||||
}];
|
||||
return [
|
||||
{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: weaponTpl,
|
||||
parentId: weaponParentId,
|
||||
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
|
||||
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 weaponSlotItem = weaponItemArray.find(weaponItem =>
|
||||
weaponItem.parentId === mod._id && weaponItem.slotId === slotName,
|
||||
const weaponSlotItem = weaponItemArray.find(
|
||||
(weaponItem) => weaponItem.parentId === mod._id && weaponItem.slotId === slotName,
|
||||
);
|
||||
if (!weaponSlotItem)
|
||||
{
|
||||
@ -441,9 +443,9 @@ export class BotWeaponGenerator
|
||||
ammoTemplate,
|
||||
inventory,
|
||||
);
|
||||
this.inventoryMagGenComponents.find(v => v.canHandleInventoryMagGen(inventoryMagGenModel)).process(
|
||||
inventoryMagGenModel,
|
||||
);
|
||||
this.inventoryMagGenComponents
|
||||
.find((v) => v.canHandleInventoryMagGen(inventoryMagGenModel))
|
||||
.process(inventoryMagGenModel);
|
||||
|
||||
// Add x stacks of bullets to SecuredContainer (bots use a magic mag packing skill to reload instantly)
|
||||
this.addAmmoToSecureContainer(
|
||||
@ -467,7 +469,7 @@ export class BotWeaponGenerator
|
||||
): void
|
||||
{
|
||||
// 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];
|
||||
|
||||
// Define min/max of how many grenades bot will have
|
||||
@ -488,9 +490,9 @@ export class BotWeaponGenerator
|
||||
ubglAmmoDbTemplate,
|
||||
inventory,
|
||||
);
|
||||
this.inventoryMagGenComponents.find(v => v.canHandleInventoryMagGen(ubglAmmoGenModel)).process(
|
||||
ubglAmmoGenModel,
|
||||
);
|
||||
this.inventoryMagGenComponents
|
||||
.find((v) => v.canHandleInventoryMagGen(ubglAmmoGenModel))
|
||||
.process(ubglAmmoGenModel);
|
||||
|
||||
// Store extra grenades in secure container
|
||||
this.addAmmoToSecureContainer(5, generatedWeaponResult.chosenUbglAmmoTpl, 20, inventory);
|
||||
@ -536,7 +538,7 @@ export class BotWeaponGenerator
|
||||
botRole: string,
|
||||
): string
|
||||
{
|
||||
const magazine = weaponMods.find(m => m.slotId === this.modMagazineSlotId);
|
||||
const magazine = weaponMods.find((m) => m.slotId === this.modMagazineSlotId);
|
||||
if (!magazine)
|
||||
{
|
||||
// Edge case - magazineless chamber loaded weapons dont have magazines, e.g. mp18
|
||||
@ -736,8 +738,8 @@ export class BotWeaponGenerator
|
||||
magazineTemplate: ITemplateItem,
|
||||
): void
|
||||
{
|
||||
const magazineCartridgeChildItem = weaponWithMods.find(m =>
|
||||
m.parentId === magazine._id && m.slotId === "cartridges",
|
||||
const magazineCartridgeChildItem = weaponWithMods.find(
|
||||
(m) => m.parentId === magazine._id && m.slotId === "cartridges",
|
||||
);
|
||||
if (magazineCartridgeChildItem)
|
||||
{
|
||||
@ -766,7 +768,7 @@ export class BotWeaponGenerator
|
||||
// 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,
|
||||
// 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)
|
||||
{
|
||||
camora._tpl = ammoTpl;
|
||||
|
@ -47,7 +47,7 @@ export class FenceBaseAssortGenerator
|
||||
const blockedSeasonalItems = this.seasonalEventService.getInactiveSeasonalEventItems();
|
||||
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
|
||||
if (this.itemFilterService.isItemBlacklisted(rootItemDb._id))
|
||||
@ -86,13 +86,15 @@ export class FenceBaseAssortGenerator
|
||||
}
|
||||
|
||||
// Create item object in array
|
||||
const itemWithChildrenToAdd: Item[] = [{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: rootItemDb._id,
|
||||
parentId: "hideout",
|
||||
slotId: "hideout",
|
||||
upd: { StackObjectsCount: 9999999 },
|
||||
}];
|
||||
const itemWithChildrenToAdd: Item[] = [
|
||||
{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: rootItemDb._id,
|
||||
parentId: "hideout",
|
||||
slotId: "hideout",
|
||||
upd: { StackObjectsCount: 9999999 },
|
||||
},
|
||||
];
|
||||
|
||||
// Ensure ammo is not above penetration limit value
|
||||
if (this.itemHelper.isOfBaseclasses(rootItemDb._id, [BaseClasses.AMMO_BOX, BaseClasses.AMMO]))
|
||||
@ -141,7 +143,7 @@ export class FenceBaseAssortGenerator
|
||||
for (const defaultPreset of defaultPresets)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
@ -249,7 +251,7 @@ export class FenceBaseAssortGenerator
|
||||
}
|
||||
|
||||
// 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;
|
||||
if (hasRequiredSlots)
|
||||
{
|
||||
@ -281,7 +283,7 @@ export class FenceBaseAssortGenerator
|
||||
}
|
||||
|
||||
// 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),
|
||||
);
|
||||
if (plateSlots.length > 0)
|
||||
|
@ -92,7 +92,7 @@ export class LocationGenerator
|
||||
}
|
||||
|
||||
// Add mounted weapons to output loot
|
||||
result.push(...staticWeaponsOnMapClone ?? []);
|
||||
result.push(...(staticWeaponsOnMapClone ?? []));
|
||||
|
||||
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
|
||||
if (
|
||||
!(this.locationConfig.containerRandomisationSettings.enabled
|
||||
&& this.locationConfig.containerRandomisationSettings.maps[locationId])
|
||||
!(
|
||||
this.locationConfig.containerRandomisationSettings.enabled
|
||||
&& this.locationConfig.containerRandomisationSettings.maps[locationId]
|
||||
)
|
||||
)
|
||||
{
|
||||
this.logger.debug(
|
||||
@ -221,15 +223,13 @@ export class LocationGenerator
|
||||
for (const chosenContainerId of chosenContainerIds)
|
||||
{
|
||||
// Look up container object from full list of containers on map
|
||||
const containerObject = staticRandomisableContainersOnMap.find(staticContainer =>
|
||||
staticContainer.template.Id === chosenContainerId,
|
||||
const containerObject = staticRandomisableContainersOnMap.find(
|
||||
(staticContainer) => staticContainer.template.Id === chosenContainerId,
|
||||
);
|
||||
if (!containerObject)
|
||||
{
|
||||
this.logger.debug(
|
||||
`Container: ${
|
||||
chosenContainerIds[chosenContainerId]
|
||||
} not found in staticRandomisableContainersOnMap, this is bad`,
|
||||
`Container: ${chosenContainerIds[chosenContainerId]} not found in staticRandomisableContainersOnMap, this is bad`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@ -265,11 +265,13 @@ export class LocationGenerator
|
||||
*/
|
||||
protected getRandomisableContainersOnMap(staticContainers: IStaticContainerData[]): IStaticContainerData[]
|
||||
{
|
||||
return staticContainers.filter(staticContainer =>
|
||||
staticContainer.probability !== 1 && !staticContainer.template.IsAlwaysSpawn
|
||||
&& !this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes(
|
||||
staticContainer.template.Items[0]._tpl,
|
||||
),
|
||||
return staticContainers.filter(
|
||||
(staticContainer) =>
|
||||
staticContainer.probability !== 1
|
||||
&& !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[]
|
||||
{
|
||||
return staticContainersOnMap.filter(staticContainer =>
|
||||
staticContainer.probability === 1 || staticContainer.template.IsAlwaysSpawn
|
||||
|| this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes(
|
||||
staticContainer.template.Items[0]._tpl,
|
||||
),
|
||||
return staticContainersOnMap.filter(
|
||||
(staticContainer) =>
|
||||
staticContainer.probability === 1
|
||||
|| 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);
|
||||
|
||||
// Some containers need to have items forced into it (quest keys etc)
|
||||
const tplsForced = staticForced.filter(forcedStaticProp =>
|
||||
forcedStaticProp.containerId === containerClone.template.Id,
|
||||
).map(x => x.itemTpl);
|
||||
const tplsForced = staticForced
|
||||
.filter((forcedStaticProp) => forcedStaticProp.containerId === containerClone.template.Id)
|
||||
.map((x) => x.itemTpl);
|
||||
|
||||
// Draw random loot
|
||||
// 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
|
||||
// Filter out items picked that're already in the above `tplsForced` array
|
||||
const chosenTpls = containerLootPool.draw(
|
||||
itemCountToAdd,
|
||||
this.locationConfig.allowDuplicateItemsInStaticContainers,
|
||||
locklist,
|
||||
).filter(tpl => !tplsForced.includes(tpl));
|
||||
const chosenTpls = containerLootPool
|
||||
.draw(itemCountToAdd, this.locationConfig.allowDuplicateItemsInStaticContainers, locklist)
|
||||
.filter((tpl) => !tplsForced.includes(tpl));
|
||||
|
||||
// Add forced loot to chosen item pool
|
||||
const tplsToAddToContainer = tplsForced.concat(chosenTpls);
|
||||
@ -495,7 +497,9 @@ export class LocationGenerator
|
||||
const width = containerTemplate._props.Grids[0]._props.cellsH;
|
||||
|
||||
// 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`
|
||||
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
|
||||
this.addForcedLoot(loot, dynamicForcedSpawnPoints, locationName);
|
||||
@ -663,7 +667,7 @@ export class LocationGenerator
|
||||
|
||||
// Filter out duplicate locationIds
|
||||
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
|
||||
@ -706,8 +710,9 @@ export class LocationGenerator
|
||||
for (const itemDist of spawnPoint.itemDistribution)
|
||||
{
|
||||
if (
|
||||
!seasonalEventActive && seasonalItemTplBlacklist.includes(
|
||||
spawnPoint.template.Items.find(item => item._id === itemDist.composedKey.key)._tpl,
|
||||
!seasonalEventActive
|
||||
&& 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)
|
||||
{
|
||||
// Get all spawn positions for item tpl in forced loot array
|
||||
const items = forcedSpawnPoints.filter(forcedSpawnPoint =>
|
||||
forcedSpawnPoint.template.Items[0]._tpl === itemTpl,
|
||||
const items = forcedSpawnPoints.filter(
|
||||
(forcedSpawnPoint) => forcedSpawnPoint.template.Items[0]._tpl === itemTpl,
|
||||
);
|
||||
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
|
||||
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;
|
||||
lootItem.Root = this.objectId.generate();
|
||||
lootItem.Items[0]._id = lootItem.Root;
|
||||
@ -819,8 +824,8 @@ export class LocationGenerator
|
||||
locationTemplateToAdd.Items[0]._id = locationTemplateToAdd.Root;
|
||||
|
||||
// Push forced location into array as long as it doesnt exist already
|
||||
const existingLocation = lootLocationTemplates.find(spawnPoint =>
|
||||
spawnPoint.Id === locationTemplateToAdd.Id,
|
||||
const existingLocation = lootLocationTemplates.find(
|
||||
(spawnPoint) => spawnPoint.Id === locationTemplateToAdd.Id,
|
||||
);
|
||||
if (!existingLocation)
|
||||
{
|
||||
@ -848,7 +853,7 @@ export class LocationGenerator
|
||||
staticAmmoDist: Record<string, IStaticAmmoDetails[]>,
|
||||
): 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 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
|
||||
if (this.itemHelper.isOfBaseclasses(chosenTpl, [BaseClasses.MONEY, BaseClasses.AMMO]))
|
||||
{
|
||||
const stackCount = itemTemplate._props.StackMaxSize === 1
|
||||
? 1
|
||||
: this.randomUtil.getInt(itemTemplate._props.StackMinRandom, itemTemplate._props.StackMaxRandom);
|
||||
const stackCount
|
||||
= itemTemplate._props.StackMaxSize === 1
|
||||
? 1
|
||||
: this.randomUtil.getInt(itemTemplate._props.StackMinRandom, itemTemplate._props.StackMaxRandom);
|
||||
|
||||
itemWithMods.push({
|
||||
_id: this.objectId.generate(),
|
||||
@ -948,10 +954,10 @@ export class LocationGenerator
|
||||
{
|
||||
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
|
||||
@ -979,9 +985,10 @@ export class LocationGenerator
|
||||
)
|
||||
{
|
||||
// Edge case - some ammos e.g. flares or M406 grenades shouldn't be stacked
|
||||
const stackCount = itemTemplate._props.StackMaxSize === 1
|
||||
? 1
|
||||
: this.randomUtil.getInt(itemTemplate._props.StackMinRandom, itemTemplate._props.StackMaxRandom);
|
||||
const stackCount
|
||||
= itemTemplate._props.StackMaxSize === 1
|
||||
? 1
|
||||
: this.randomUtil.getInt(itemTemplate._props.StackMinRandom, itemTemplate._props.StackMaxRandom);
|
||||
|
||||
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.)
|
||||
// General: Make a WeaponController for Ragfair preset stuff and the generating weapons and ammo stuff from
|
||||
// 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
|
||||
if (magazine)
|
||||
{
|
||||
|
@ -6,7 +6,6 @@ import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
|
||||
import { IPreset } from "@spt-aki/models/eft/common/IGlobals";
|
||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||
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 { ISealedAirdropContainerSettings, RewardDetails } from "@spt-aki/models/spt/config/IInventoryConfig";
|
||||
import { LootItem } from "@spt-aki/models/spt/services/LootItem";
|
||||
@ -71,7 +70,7 @@ export class LootGenerator
|
||||
if (desiredWeaponCrateCount > 0)
|
||||
{
|
||||
// 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"),
|
||||
);
|
||||
|
||||
@ -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
|
||||
const items = Object.entries(tables.templates.items).filter(x =>
|
||||
!itemBlacklist.has(x[1]._id)
|
||||
&& x[1]._type.toLowerCase() === "item"
|
||||
&& !x[1]._props.QuestItem
|
||||
&& options.itemTypeWhitelist.includes(x[1]._parent),
|
||||
const items = Object.entries(tables.templates.items).filter(
|
||||
(x) =>
|
||||
!itemBlacklist.has(x[1]._id)
|
||||
&& x[1]._type.toLowerCase() === "item"
|
||||
&& !x[1]._props.QuestItem
|
||||
&& options.itemTypeWhitelist.includes(x[1]._parent),
|
||||
);
|
||||
|
||||
if (items.length > 0)
|
||||
@ -119,7 +119,7 @@ export class LootGenerator
|
||||
);
|
||||
if (randomisedWeaponPresetCount > 0)
|
||||
{
|
||||
const weaponDefaultPresets = globalDefaultPresets.filter(preset =>
|
||||
const weaponDefaultPresets = globalDefaultPresets.filter((preset) =>
|
||||
this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON),
|
||||
);
|
||||
|
||||
@ -150,10 +150,10 @@ export class LootGenerator
|
||||
);
|
||||
if (randomisedArmorPresetCount > 0)
|
||||
{
|
||||
const armorDefaultPresets = globalDefaultPresets.filter(preset =>
|
||||
const armorDefaultPresets = globalDefaultPresets.filter((preset) =>
|
||||
this.itemHelper.armorItemCanHoldMods(preset._encyclopedia),
|
||||
);
|
||||
const levelFilteredArmorPresets = armorDefaultPresets.filter(armor =>
|
||||
const levelFilteredArmorPresets = armorDefaultPresets.filter((armor) =>
|
||||
this.armorIsDesiredProtectionLevel(armor, options),
|
||||
);
|
||||
|
||||
@ -189,21 +189,21 @@ export class LootGenerator
|
||||
*/
|
||||
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)
|
||||
{
|
||||
const plateDb = this.itemHelper.getItem(frontPlate._tpl);
|
||||
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)
|
||||
{
|
||||
const plateDb = this.itemHelper.getItem(helmetTop._tpl);
|
||||
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)
|
||||
{
|
||||
const plateDb = this.itemHelper.getItem(softArmorFront._tpl);
|
||||
@ -470,7 +470,7 @@ export class LootGenerator
|
||||
|
||||
// Need to find boxes that matches weapons caliber
|
||||
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)
|
||||
{
|
||||
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
|
||||
const rewardItemPool = Object.values(this.databaseServer.getTables().templates.items).filter(x =>
|
||||
x._parent === rewardTypeId
|
||||
&& x._type.toLowerCase() === "item"
|
||||
&& !this.itemFilterService.isItemBlacklisted(x._id)
|
||||
&& !(containerSettings.allowBossItems || this.itemFilterService.isBossItem(x._id))
|
||||
&& !x._props.QuestItem,
|
||||
const rewardItemPool = Object.values(this.databaseServer.getTables().templates.items).filter(
|
||||
(x) =>
|
||||
x._parent === rewardTypeId
|
||||
&& x._type.toLowerCase() === "item"
|
||||
&& !this.itemFilterService.isItemBlacklisted(x._id)
|
||||
&& !(containerSettings.allowBossItems || this.itemFilterService.isBossItem(x._id))
|
||||
&& !x._props.QuestItem,
|
||||
);
|
||||
|
||||
if (rewardItemPool.length === 0)
|
||||
@ -544,8 +545,8 @@ export class LootGenerator
|
||||
}
|
||||
|
||||
// Get items that fulfil reward type criteria from items that fit on gun
|
||||
const relatedItems = linkedItemsToWeapon.filter(x =>
|
||||
x._parent === rewardTypeId && !this.itemFilterService.isItemBlacklisted(x._id),
|
||||
const relatedItems = linkedItemsToWeapon.filter(
|
||||
(x) => x._parent === rewardTypeId && !this.itemFilterService.isItemBlacklisted(x._id),
|
||||
);
|
||||
if (!relatedItems || relatedItems.length === 0)
|
||||
{
|
||||
|
@ -58,13 +58,14 @@ export class PMCLootGenerator
|
||||
// Blacklist inactive seasonal items
|
||||
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
|
||||
|
||||
const itemsToAdd = Object.values(items).filter(item =>
|
||||
allowedItemTypes.includes(item._parent)
|
||||
&& this.itemHelper.isValidItem(item._id)
|
||||
&& !pmcItemBlacklist.includes(item._id)
|
||||
&& !itemBlacklist.includes(item._id)
|
||||
&& item._props.Width === 1
|
||||
&& item._props.Height === 1,
|
||||
const itemsToAdd = Object.values(items).filter(
|
||||
(item) =>
|
||||
allowedItemTypes.includes(item._parent)
|
||||
&& this.itemHelper.isValidItem(item._id)
|
||||
&& !pmcItemBlacklist.includes(item._id)
|
||||
&& !itemBlacklist.includes(item._id)
|
||||
&& item._props.Width === 1
|
||||
&& item._props.Height === 1,
|
||||
);
|
||||
|
||||
for (const itemToAdd of itemsToAdd)
|
||||
@ -87,7 +88,7 @@ export class PMCLootGenerator
|
||||
{
|
||||
// Invert price so cheapest has a larger weight
|
||||
// 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);
|
||||
@ -117,12 +118,13 @@ export class PMCLootGenerator
|
||||
// Blacklist seasonal items
|
||||
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
|
||||
|
||||
const itemsToAdd = Object.values(items).filter(item =>
|
||||
allowedItemTypes.includes(item._parent)
|
||||
&& this.itemHelper.isValidItem(item._id)
|
||||
&& !pmcItemBlacklist.includes(item._id)
|
||||
&& !itemBlacklist.includes(item._id)
|
||||
&& this.itemFitsInto2By2Slot(item),
|
||||
const itemsToAdd = Object.values(items).filter(
|
||||
(item) =>
|
||||
allowedItemTypes.includes(item._parent)
|
||||
&& this.itemHelper.isValidItem(item._id)
|
||||
&& !pmcItemBlacklist.includes(item._id)
|
||||
&& !itemBlacklist.includes(item._id)
|
||||
&& this.itemFitsInto2By2Slot(item),
|
||||
);
|
||||
|
||||
for (const itemToAdd of itemsToAdd)
|
||||
@ -145,7 +147,7 @@ export class PMCLootGenerator
|
||||
{
|
||||
// Invert price so cheapest has a larger weight
|
||||
// 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);
|
||||
@ -186,11 +188,12 @@ export class PMCLootGenerator
|
||||
// Blacklist seasonal items
|
||||
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
|
||||
|
||||
const itemsToAdd = Object.values(items).filter(item =>
|
||||
allowedItemTypes.includes(item._parent)
|
||||
&& this.itemHelper.isValidItem(item._id)
|
||||
&& !pmcItemBlacklist.includes(item._id)
|
||||
&& !itemBlacklist.includes(item._id),
|
||||
const itemsToAdd = Object.values(items).filter(
|
||||
(item) =>
|
||||
allowedItemTypes.includes(item._parent)
|
||||
&& this.itemHelper.isValidItem(item._id)
|
||||
&& !pmcItemBlacklist.includes(item._id)
|
||||
&& !itemBlacklist.includes(item._id),
|
||||
);
|
||||
|
||||
for (const itemToAdd of itemsToAdd)
|
||||
@ -213,7 +216,7 @@ export class PMCLootGenerator
|
||||
{
|
||||
// Invert price so cheapest has a larger weight
|
||||
// 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);
|
||||
|
@ -162,11 +162,13 @@ export class PlayerScavGenerator
|
||||
}
|
||||
|
||||
const itemTemplate = itemResult[1];
|
||||
const itemsToAdd: Item[] = [{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: itemTemplate._id,
|
||||
...this.botGeneratorHelper.generateExtraPropertiesForItem(itemTemplate),
|
||||
}];
|
||||
const itemsToAdd: Item[] = [
|
||||
{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: itemTemplate._id,
|
||||
...this.botGeneratorHelper.generateExtraPropertiesForItem(itemTemplate),
|
||||
},
|
||||
];
|
||||
|
||||
const result = this.botGeneratorHelper.addItemWithChildrenToEquipmentSlot(
|
||||
containersToAddTo,
|
||||
|
@ -72,7 +72,7 @@ export class RagfairAssortGenerator
|
||||
const results: Item[][] = [];
|
||||
|
||||
/** 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 */
|
||||
const processedArmorItems: string[] = [];
|
||||
@ -105,7 +105,8 @@ export class RagfairAssortGenerator
|
||||
|
||||
// Skip seasonal items when not in-season
|
||||
if (
|
||||
this.ragfairConfig.dynamic.removeSeasonalItemsWhenNotInEvent && !seasonalEventActive
|
||||
this.ragfairConfig.dynamic.removeSeasonalItemsWhenNotInEvent
|
||||
&& !seasonalEventActive
|
||||
&& seasonalItemTplBlacklist.includes(item._id)
|
||||
)
|
||||
{
|
||||
|
@ -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 offer: IRagfairOffer = {
|
||||
@ -143,9 +143,8 @@ export class RagfairOfferGenerator
|
||||
intId: this.offerCounter,
|
||||
user: {
|
||||
id: this.getTraderId(userID),
|
||||
memberType: userID === "ragfair"
|
||||
? MemberCategory.DEFAULT
|
||||
: this.ragfairServerHelper.getMemberType(userID),
|
||||
memberType:
|
||||
userID === "ragfair" ? MemberCategory.DEFAULT : this.ragfairServerHelper.getMemberType(userID),
|
||||
nickname: this.ragfairServerHelper.getNickname(userID),
|
||||
rating: this.getRating(userID),
|
||||
isRatingGrowing: this.getRatingGrowing(userID),
|
||||
@ -410,7 +409,7 @@ export class RagfairOfferGenerator
|
||||
return false;
|
||||
}
|
||||
|
||||
const plateSlots = presetWithChildren.filter(item =>
|
||||
const plateSlots = presetWithChildren.filter((item) =>
|
||||
this.itemHelper.getRemovablePlateSlotIds().includes(item.slotId?.toLowerCase()),
|
||||
);
|
||||
if (plateSlots.length === 0)
|
||||
@ -459,13 +458,14 @@ export class RagfairOfferGenerator
|
||||
);
|
||||
|
||||
const isBarterOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.barter.chancePercent);
|
||||
const isPackOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.pack.chancePercent)
|
||||
&& !isBarterOffer
|
||||
&& itemWithChildren.length === 1
|
||||
&& this.itemHelper.isOfBaseclasses(
|
||||
itemWithChildren[0]._tpl,
|
||||
this.ragfairConfig.dynamic.pack.itemTypeWhitelist,
|
||||
);
|
||||
const isPackOffer
|
||||
= this.randomUtil.getChance100(this.ragfairConfig.dynamic.pack.chancePercent)
|
||||
&& !isBarterOffer
|
||||
&& itemWithChildren.length === 1
|
||||
&& this.itemHelper.isOfBaseclasses(
|
||||
itemWithChildren[0]._tpl,
|
||||
this.ragfairConfig.dynamic.pack.itemTypeWhitelist,
|
||||
);
|
||||
|
||||
const randomUserId = this.hashUtil.generate();
|
||||
|
||||
@ -477,7 +477,7 @@ export class RagfairOfferGenerator
|
||||
const shouldRemovePlates = this.randomUtil.getChance100(armorConfig.removeRemovablePlateChance);
|
||||
if (shouldRemovePlates && this.itemHelper.armorItemHasRemovablePlateSlots(itemWithChildren[0]._tpl))
|
||||
{
|
||||
const offerItemPlatesToRemove = itemWithChildren.filter(item =>
|
||||
const offerItemPlatesToRemove = itemWithChildren.filter((item) =>
|
||||
armorConfig.plateSlotIdToRemovePool.includes(item.slotId?.toLowerCase()),
|
||||
);
|
||||
|
||||
@ -683,8 +683,8 @@ export class RagfairOfferGenerator
|
||||
this.randomiseArmorDurabilityValues(itemWithMods, currentMultiplier, maxMultiplier);
|
||||
|
||||
// Add hits to visor
|
||||
const visorMod = itemWithMods.find(item =>
|
||||
item.parentId === BaseClasses.ARMORED_EQUIPMENT && item.slotId === "mod_equipment_000",
|
||||
const visorMod = itemWithMods.find(
|
||||
(item) => item.parentId === BaseClasses.ARMORED_EQUIPMENT && item.slotId === "mod_equipment_000",
|
||||
);
|
||||
if (this.randomUtil.getChance100(25) && visorMod)
|
||||
{
|
||||
@ -715,8 +715,8 @@ export class RagfairOfferGenerator
|
||||
if (rootItem.upd.Key && itemDetails._props.MaximumNumberOfUsage > 1)
|
||||
{
|
||||
// randomize key uses
|
||||
rootItem.upd.Key.NumberOfUsages = Math.round(itemDetails._props.MaximumNumberOfUsage * (1 - maxMultiplier))
|
||||
|| 0;
|
||||
rootItem.upd.Key.NumberOfUsages
|
||||
= Math.round(itemDetails._props.MaximumNumberOfUsage * (1 - maxMultiplier)) || 0;
|
||||
|
||||
return;
|
||||
}
|
||||
@ -792,8 +792,8 @@ export class RagfairOfferGenerator
|
||||
{
|
||||
this.itemHelper.addUpdObjectToItem(armorItem);
|
||||
|
||||
const lowestMaxDurability = this.randomUtil.getFloat(maxMultiplier, 1)
|
||||
* itemDbDetails._props.MaxDurability;
|
||||
const lowestMaxDurability
|
||||
= this.randomUtil.getFloat(maxMultiplier, 1) * itemDbDetails._props.MaxDurability;
|
||||
const chosenMaxDurability = Math.round(
|
||||
this.randomUtil.getFloat(lowestMaxDurability, itemDbDetails._props.MaxDurability),
|
||||
);
|
||||
@ -882,14 +882,16 @@ export class RagfairOfferGenerator
|
||||
const desiredItemCost = Math.round(priceOfItemOffer / barterItemCount);
|
||||
|
||||
// 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();
|
||||
|
||||
// Filter possible barters to items that match the price range + not itself
|
||||
const filtered = fleaPrices.filter(x =>
|
||||
x.price >= desiredItemCost - offerCostVariance && x.price <= desiredItemCost + offerCostVariance
|
||||
&& x.tpl !== offerItems[0]._tpl,
|
||||
const filtered = fleaPrices.filter(
|
||||
(x) =>
|
||||
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
|
||||
@ -917,10 +919,10 @@ export class RagfairOfferGenerator
|
||||
const fleaArray = Object.entries(fleaPrices).map(([tpl, price]) => ({ tpl: tpl, price: price }));
|
||||
|
||||
// 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.itemHelper.isOfBaseclasses(x.tpl, this.ragfairConfig.dynamic.barter.itemTypeBlacklist),
|
||||
this.allowedFleaPriceItemsForBarter = filteredItems.filter(
|
||||
(x) => !this.itemHelper.isOfBaseclasses(x.tpl, this.ragfairConfig.dynamic.barter.itemTypeBlacklist),
|
||||
);
|
||||
}
|
||||
|
||||
@ -941,8 +943,8 @@ export class RagfairOfferGenerator
|
||||
): IBarterScheme[]
|
||||
{
|
||||
const currency = this.ragfairServerHelper.getDynamicOfferCurrency();
|
||||
const price = this.ragfairPriceService.getDynamicOfferPriceForOffer(offerWithChildren, currency, isPackOffer)
|
||||
* multipler;
|
||||
const price
|
||||
= this.ragfairPriceService.getDynamicOfferPriceForOffer(offerWithChildren, currency, isPackOffer) * multipler;
|
||||
|
||||
return [{ count: price, _tpl: currency }];
|
||||
}
|
||||
|
@ -39,8 +39,8 @@ export class RepeatableQuestGenerator
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("ObjectId") protected objectId: ObjectId,
|
||||
@inject("RepeatableQuestHelper") protected repeatableQuestHelper: RepeatableQuestHelper,
|
||||
@inject("RepeatableQuestRewardGenerator") protected repeatableQuestRewardGenerator:
|
||||
RepeatableQuestRewardGenerator,
|
||||
@inject("RepeatableQuestRewardGenerator")
|
||||
protected repeatableQuestRewardGenerator: RepeatableQuestRewardGenerator,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@inject("RecursiveCloner") protected cloner: ICloner,
|
||||
)
|
||||
@ -67,11 +67,11 @@ export class RepeatableQuestGenerator
|
||||
const questType = this.randomUtil.drawRandomFromList<string>(questTypePool.types)[0];
|
||||
|
||||
// get traders from whitelist and filter by quest type availability
|
||||
let traders = repeatableConfig.traderWhitelist.filter(x => x.questTypes.includes(questType)).map(x =>
|
||||
x.traderId,
|
||||
);
|
||||
let traders = repeatableConfig.traderWhitelist
|
||||
.filter((x) => x.questTypes.includes(questType))
|
||||
.map((x) => x.traderId);
|
||||
// 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];
|
||||
|
||||
switch (questType)
|
||||
@ -158,15 +158,15 @@ export class RepeatableQuestGenerator
|
||||
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),
|
||||
);
|
||||
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
|
||||
// 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
|
||||
questTypePool.types = questTypePool.types.filter(t => t !== "Elimination");
|
||||
questTypePool.types = questTypePool.types.filter((t) => t !== "Elimination");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -188,12 +188,12 @@ export class RepeatableQuestGenerator
|
||||
}
|
||||
else
|
||||
{
|
||||
locations = locations.filter(l => l !== "any");
|
||||
locations = locations.filter((l) => l !== "any");
|
||||
if (locations.length > 0)
|
||||
{
|
||||
locationKey = this.randomUtil.drawRandomFromList<string>(locations)[0];
|
||||
questTypePool.pool.Elimination.targets[targetKey].locations = locations.filter(l =>
|
||||
l !== locationKey,
|
||||
questTypePool.pool.Elimination.targets[targetKey].locations = locations.filter(
|
||||
(l) => l !== locationKey,
|
||||
);
|
||||
if (questTypePool.pool.Elimination.targets[targetKey].locations.length === 0)
|
||||
{
|
||||
@ -238,16 +238,18 @@ export class RepeatableQuestGenerator
|
||||
if (targetsConfig.data(targetKey).isBoss)
|
||||
{
|
||||
// Get all boss spawn information
|
||||
const bossSpawns = Object.values(this.databaseServer.getTables().locations).filter(x =>
|
||||
"base" in x && "Id" in x.base,
|
||||
).map(x => ({ Id: x.base.Id, BossSpawn: x.base.BossLocationSpawn }));
|
||||
const bossSpawns = Object.values(this.databaseServer.getTables().locations)
|
||||
.filter((x) => "base" in x && "Id" in x.base)
|
||||
.map((x) => ({ Id: x.base.Id, BossSpawn: x.base.BossLocationSpawn }));
|
||||
// filter for the current boss to spawn on map
|
||||
const thisBossSpawns = bossSpawns.map(x => ({
|
||||
Id: x.Id,
|
||||
BossSpawn: x.BossSpawn.filter(e => e.BossName === targetKey),
|
||||
})).filter(x => x.BossSpawn.length > 0);
|
||||
const thisBossSpawns = bossSpawns
|
||||
.map((x) => ({
|
||||
Id: x.Id,
|
||||
BossSpawn: x.BossSpawn.filter((e) => e.BossName === targetKey),
|
||||
}))
|
||||
.filter((x) => x.BossSpawn.length > 0);
|
||||
// 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
|
||||
isDistanceRequirementAllowed = isDistanceRequirementAllowed && allowedSpawns.length > 0;
|
||||
}
|
||||
@ -260,7 +262,7 @@ export class RepeatableQuestGenerator
|
||||
+ eliminationConfig.minDist,
|
||||
);
|
||||
distance = Math.ceil(distance / 5) * 5;
|
||||
distanceDifficulty = maxDistDifficulty * distance / eliminationConfig.maxDist;
|
||||
distanceDifficulty = (maxDistDifficulty * distance) / eliminationConfig.maxDist;
|
||||
}
|
||||
|
||||
let allowedWeaponsCategory: string = undefined;
|
||||
@ -269,13 +271,14 @@ export class RepeatableQuestGenerator
|
||||
// Filter out close range weapons from far distance requirement
|
||||
if (distance > 50)
|
||||
{
|
||||
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter(category =>
|
||||
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter((category) =>
|
||||
["Shotgun", "Pistol"].includes(category.key),
|
||||
);
|
||||
}
|
||||
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),
|
||||
);
|
||||
}
|
||||
@ -497,8 +500,8 @@ export class RepeatableQuestGenerator
|
||||
this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig) * this.randomUtil.getFloat(0.5, 1),
|
||||
);
|
||||
roublesBudget = Math.max(roublesBudget, 5000);
|
||||
let itemSelection = possibleItemsToRetrievePool.filter(x =>
|
||||
this.itemHelper.getItemPrice(x[0]) < roublesBudget,
|
||||
let itemSelection = possibleItemsToRetrievePool.filter(
|
||||
(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
|
||||
@ -509,15 +512,16 @@ export class RepeatableQuestGenerator
|
||||
= this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsWhitelist;
|
||||
|
||||
// Filter and concatenate the arrays according to current player level
|
||||
const itemIdsWhitelisted = itemWhitelist.filter(p => p.minPlayerLevel <= pmcLevel).reduce(
|
||||
(a, p) => a.concat(p.itemIds),
|
||||
[],
|
||||
);
|
||||
const itemIdsWhitelisted = itemWhitelist
|
||||
.filter((p) => p.minPlayerLevel <= pmcLevel)
|
||||
.reduce((a, p) => a.concat(p.itemIds), []);
|
||||
itemSelection = itemSelection.filter((x) =>
|
||||
{
|
||||
// Whitelist can contain item tpls and item base type ids
|
||||
return itemIdsWhitelisted.some(v => this.itemHelper.isOfBaseclass(x[0], v))
|
||||
|| itemIdsWhitelisted.includes(x[0]);
|
||||
return (
|
||||
itemIdsWhitelisted.some((v) => this.itemHelper.isOfBaseclass(x[0], v))
|
||||
|| itemIdsWhitelisted.includes(x[0])
|
||||
);
|
||||
});
|
||||
// check if items are missing
|
||||
// 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;
|
||||
|
||||
// we filter and concatenate the arrays according to current player level
|
||||
const itemIdsBlacklisted = itemBlacklist.filter(p => p.minPlayerLevel <= pmcLevel).reduce(
|
||||
(a, p) => a.concat(p.itemIds),
|
||||
[],
|
||||
);
|
||||
const itemIdsBlacklisted = itemBlacklist
|
||||
.filter((p) => p.minPlayerLevel <= pmcLevel)
|
||||
.reduce((a, p) => a.concat(p.itemIds), []);
|
||||
|
||||
itemSelection = itemSelection.filter((x) =>
|
||||
{
|
||||
return itemIdsBlacklisted.every(v => !this.itemHelper.isOfBaseclass(x[0], v))
|
||||
|| !itemIdsBlacklisted.includes(x[0]);
|
||||
return (
|
||||
itemIdsBlacklisted.every((v) => !this.itemHelper.isOfBaseclass(x[0], v))
|
||||
|| !itemIdsBlacklisted.includes(x[0])
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -601,7 +606,7 @@ export class RepeatableQuestGenerator
|
||||
if (roublesBudget > 0)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
break;
|
||||
@ -692,7 +697,7 @@ export class RepeatableQuestGenerator
|
||||
if (Object.keys(questTypePool.pool.Exploration.locations).length === 0)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -737,13 +742,15 @@ export class RepeatableQuestGenerator
|
||||
const mapExits = this.getLocationExitsForSide(locationKey, repeatableConfig.side);
|
||||
|
||||
// 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)
|
||||
const possibleExits = exitPool.filter(exit => !("PassageRequirement" in exit)
|
||||
|| repeatableConfig.questConfig.Exploration.specificExits.passageRequirementWhitelist.includes(
|
||||
exit.PassageRequirement,
|
||||
),
|
||||
const possibleExits = exitPool.filter(
|
||||
(exit) =>
|
||||
!("PassageRequirement" in exit)
|
||||
|| repeatableConfig.questConfig.Exploration.specificExits.passageRequirementWhitelist.includes(
|
||||
exit.PassageRequirement,
|
||||
),
|
||||
);
|
||||
|
||||
if (possibleExits.length === 0)
|
||||
@ -788,7 +795,7 @@ export class RepeatableQuestGenerator
|
||||
const mapExtracts = this.databaseServer.getTables().locations[locationKey.toLocaleLowerCase()]
|
||||
.allExtracts as Exit[];
|
||||
|
||||
return mapExtracts.filter(exit => exit.Side === playerSide);
|
||||
return mapExtracts.filter((exit) => exit.Side === playerSide);
|
||||
}
|
||||
|
||||
protected generatePickupQuest(
|
||||
@ -811,18 +818,18 @@ export class RepeatableQuestGenerator
|
||||
// const locationKey: string = this.randomUtil.drawRandomFromDict(questTypePool.pool.Pickup.locations)[0];
|
||||
// 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.value = itemCountToFetch;
|
||||
|
||||
const counterCreatorCondition = quest.conditions.AvailableForFinish.find(x =>
|
||||
x.conditionType === "CounterCreator",
|
||||
const counterCreatorCondition = quest.conditions.AvailableForFinish.find(
|
||||
(x) => x.conditionType === "CounterCreator",
|
||||
);
|
||||
// const locationCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Location");
|
||||
// (locationCondition._props as ILocationConditionProps).target = [...locationTarget];
|
||||
|
||||
const equipmentCondition = counterCreatorCondition.counter.conditions.find(x =>
|
||||
x.conditionType === "Equipment",
|
||||
const equipmentCondition = counterCreatorCondition.counter.conditions.find(
|
||||
(x) => x.conditionType === "Equipment",
|
||||
);
|
||||
equipmentCondition.equipmentInclusive = [[itemTypeToFetchWithCount.itemType]];
|
||||
|
||||
@ -887,46 +894,36 @@ export class RepeatableQuestGenerator
|
||||
// Get template id from config based on side and type of quest
|
||||
questClone.templateId = this.questConfig.questTemplateIds[side.toLowerCase()][type.toLowerCase()];
|
||||
|
||||
questClone.name = questClone.name.replace("{traderId}", traderId).replace(
|
||||
"{templateId}",
|
||||
questClone.templateId,
|
||||
);
|
||||
questClone.note = questClone.note.replace("{traderId}", traderId).replace(
|
||||
"{templateId}",
|
||||
questClone.templateId,
|
||||
);
|
||||
questClone.description = questClone.description.replace("{traderId}", traderId).replace(
|
||||
"{templateId}",
|
||||
questClone.templateId,
|
||||
);
|
||||
questClone.successMessageText = questClone.successMessageText.replace("{traderId}", traderId).replace(
|
||||
"{templateId}",
|
||||
questClone.templateId,
|
||||
);
|
||||
questClone.failMessageText = questClone.failMessageText.replace("{traderId}", traderId).replace(
|
||||
"{templateId}",
|
||||
questClone.templateId,
|
||||
);
|
||||
questClone.startedMessageText = questClone.startedMessageText.replace("{traderId}", traderId).replace(
|
||||
"{templateId}",
|
||||
questClone.templateId,
|
||||
);
|
||||
questClone.changeQuestMessageText = questClone.changeQuestMessageText.replace("{traderId}", traderId).replace(
|
||||
"{templateId}",
|
||||
questClone.templateId,
|
||||
);
|
||||
questClone.acceptPlayerMessage = questClone.acceptPlayerMessage.replace("{traderId}", traderId).replace(
|
||||
"{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,
|
||||
);
|
||||
questClone.name = questClone.name
|
||||
.replace("{traderId}", traderId)
|
||||
.replace("{templateId}", questClone.templateId);
|
||||
questClone.note = questClone.note
|
||||
.replace("{traderId}", traderId)
|
||||
.replace("{templateId}", questClone.templateId);
|
||||
questClone.description = questClone.description
|
||||
.replace("{traderId}", traderId)
|
||||
.replace("{templateId}", questClone.templateId);
|
||||
questClone.successMessageText = questClone.successMessageText
|
||||
.replace("{traderId}", traderId)
|
||||
.replace("{templateId}", questClone.templateId);
|
||||
questClone.failMessageText = questClone.failMessageText
|
||||
.replace("{traderId}", traderId)
|
||||
.replace("{templateId}", questClone.templateId);
|
||||
questClone.startedMessageText = questClone.startedMessageText
|
||||
.replace("{traderId}", traderId)
|
||||
.replace("{templateId}", questClone.templateId);
|
||||
questClone.changeQuestMessageText = questClone.changeQuestMessageText
|
||||
.replace("{traderId}", traderId)
|
||||
.replace("{templateId}", questClone.templateId);
|
||||
questClone.acceptPlayerMessage = questClone.acceptPlayerMessage
|
||||
.replace("{traderId}", traderId)
|
||||
.replace("{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;
|
||||
}
|
||||
|
@ -94,11 +94,13 @@ export class RepeatableQuestRewardGenerator
|
||||
|
||||
// rewards are generated based on pmcLevel, difficulty and a random spread
|
||||
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),
|
||||
);
|
||||
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),
|
||||
);
|
||||
const rewardNumItems = this.randomUtil.randInt(
|
||||
@ -107,7 +109,9 @@ export class RepeatableQuestRewardGenerator
|
||||
);
|
||||
const rewardReputation
|
||||
= 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),
|
||||
) / 100;
|
||||
const skillRewardChance = this.mathUtil.interp1(pmcLevel, levelsConfig, skillRewardChanceConfig);
|
||||
@ -134,7 +138,7 @@ export class RepeatableQuestRewardGenerator
|
||||
this.addMoneyReward(traderId, rewards, rewardRoubles, rewardIndex);
|
||||
rewardIndex++;
|
||||
|
||||
const traderWhitelistDetails = repeatableConfig.traderWhitelist.find(x => x.traderId === traderId);
|
||||
const traderWhitelistDetails = repeatableConfig.traderWhitelist.find((x) => x.traderId === traderId);
|
||||
if (
|
||||
traderWhitelistDetails.rewardCanBeWeapon
|
||||
&& this.randomUtil.getChance100(traderWhitelistDetails.weaponRewardChancePercent)
|
||||
@ -150,7 +154,7 @@ export class RepeatableQuestRewardGenerator
|
||||
while (defaultPresetPool.hasValues())
|
||||
{
|
||||
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);
|
||||
if (presetPrice <= roublesBudget)
|
||||
{
|
||||
@ -307,14 +311,16 @@ export class RepeatableQuestRewardGenerator
|
||||
*/
|
||||
protected canIncreaseRewardItemStackSize(item: ITemplateItem, maxRoublePriceToStack: number): boolean
|
||||
{
|
||||
return this.presetHelper.getDefaultPresetOrItemPrice(item._id) < maxRoublePriceToStack
|
||||
&& !this.itemHelper.isOfBaseclasses(item._id, [
|
||||
BaseClasses.WEAPON,
|
||||
BaseClasses.ARMORED_EQUIPMENT,
|
||||
BaseClasses.AMMO,
|
||||
])
|
||||
&& !this.itemHelper.itemRequiresSoftInserts(item._id)
|
||||
&& this.randomUtil.getChance100(25);
|
||||
return (
|
||||
this.presetHelper.getDefaultPresetOrItemPrice(item._id) < maxRoublePriceToStack
|
||||
&& !this.itemHelper.isOfBaseclasses(item._id, [
|
||||
BaseClasses.WEAPON,
|
||||
BaseClasses.ARMORED_EQUIPMENT,
|
||||
BaseClasses.AMMO,
|
||||
])
|
||||
&& !this.itemHelper.itemRequiresSoftInserts(item._id)
|
||||
&& this.randomUtil.getChance100(25)
|
||||
);
|
||||
}
|
||||
|
||||
protected calculateAmmoStackSizeThatFitsBudget(
|
||||
@ -354,7 +360,7 @@ export class RepeatableQuestRewardGenerator
|
||||
const rewardableItemPool = this.getRewardableItems(repeatableConfig, traderId);
|
||||
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,
|
||||
roublesBudget,
|
||||
@ -369,9 +375,9 @@ export class RepeatableQuestRewardGenerator
|
||||
}),
|
||||
);
|
||||
// In case we don't find any items in the price range
|
||||
rewardableItemPoolWithinBudget = rewardableItemPool.filter(x =>
|
||||
this.itemHelper.getItemPrice(x[0]) < roublesBudget,
|
||||
).map(x => x[1]);
|
||||
rewardableItemPoolWithinBudget = rewardableItemPool
|
||||
.filter((x) => this.itemHelper.getItemPrice(x[0]) < roublesBudget)
|
||||
.map((x) => x[1]);
|
||||
}
|
||||
|
||||
return rewardableItemPoolWithinBudget;
|
||||
@ -392,7 +398,7 @@ export class RepeatableQuestRewardGenerator
|
||||
|
||||
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.target = rootItem._id; // Target property and root items id must match
|
||||
}
|
||||
@ -435,8 +441,8 @@ export class RepeatableQuestRewardGenerator
|
||||
return false;
|
||||
}
|
||||
|
||||
const traderWhitelist = repeatableQuestConfig.traderWhitelist.find(trader =>
|
||||
trader.traderId === traderId,
|
||||
const traderWhitelist = repeatableQuestConfig.traderWhitelist.find(
|
||||
(trader) => trader.traderId === traderId,
|
||||
);
|
||||
return this.isValidRewardItem(tpl, repeatableQuestConfig, traderWhitelist?.rewardBaseWhitelist);
|
||||
},
|
||||
@ -502,7 +508,12 @@ export class RepeatableQuestRewardGenerator
|
||||
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
|
||||
if (traderId === Traders.PEACEKEEPER || traderId === Traders.FENCE)
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
||||
import { Product } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||
import { Item, Upd } 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 { IHideoutScavCase } from "@spt-aki/models/eft/hideout/IHideoutScavCase";
|
||||
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
|
||||
@ -58,7 +57,7 @@ export class ScavCaseRewardGenerator
|
||||
this.cacheDbItems();
|
||||
|
||||
// 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);
|
||||
|
||||
// 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++)
|
||||
{
|
||||
if (this.rewardShouldBeMoney() && !rewardWasMoney)
|
||||
{ // Only allow one reward to be money
|
||||
{
|
||||
// Only allow one reward to be money
|
||||
result.push(this.getRandomMoney());
|
||||
if (!this.scavCaseConfig.allowMultipleMoneyRewardsPerRarity)
|
||||
{
|
||||
@ -239,7 +239,8 @@ export class ScavCaseRewardGenerator
|
||||
}
|
||||
}
|
||||
else if (this.rewardShouldBeAmmo() && !rewardWasAmmo)
|
||||
{ // Only allow one reward to be ammo
|
||||
{
|
||||
// Only allow one reward to be ammo
|
||||
result.push(this.getRandomAmmo(rarity));
|
||||
if (!this.scavCaseConfig.allowMultipleAmmoRewardsPerRarity)
|
||||
{
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
||||
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
||||
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
|
||||
import { IWeather, IWeatherData } from "@spt-aki/models/eft/weather/IWeatherData";
|
||||
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 { IWeatherConfig } from "@spt-aki/models/spt/config/IWeatherConfig";
|
||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
@ -181,7 +179,8 @@ export class WeatherGenerator
|
||||
protected getRandomFloat(node: string): number
|
||||
{
|
||||
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),
|
||||
);
|
||||
}
|
||||
|
@ -85,8 +85,8 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
||||
}
|
||||
|
||||
/* We were unable to fit at least the minimum amount of magazines,
|
||||
* 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 */
|
||||
* 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 */
|
||||
|
||||
if (magazineTpl === defaultMagazineTpl)
|
||||
{
|
||||
@ -153,15 +153,15 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
||||
): ITemplateItem
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// All possible mags that fit into the weapon excluding blacklisted
|
||||
const magazinePool = magSlot._props.filters[0].Filter.filter(x => !magazineBlacklist.includes(x)).map(x =>
|
||||
this.itemHelper.getItem(x)[1],
|
||||
const magazinePool = magSlot._props.filters[0].Filter.filter((x) => !magazineBlacklist.includes(x)).map(
|
||||
(x) => this.itemHelper.getItem(x)[1],
|
||||
);
|
||||
if (!magazinePool)
|
||||
{
|
||||
@ -169,7 +169,7 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
return null;
|
||||
|
@ -92,9 +92,10 @@ export class BotDifficultyHelper
|
||||
*/
|
||||
protected getDifficultySettings(type: string, difficulty: string): Difficulty
|
||||
{
|
||||
let difficultySetting = this.pmcConfig.difficulty.toLowerCase() === "asonline"
|
||||
? difficulty
|
||||
: this.pmcConfig.difficulty.toLowerCase();
|
||||
let difficultySetting
|
||||
= this.pmcConfig.difficulty.toLowerCase() === "asonline"
|
||||
? difficulty
|
||||
: this.pmcConfig.difficulty.toLowerCase();
|
||||
|
||||
difficultySetting = this.convertBotDifficultyDropdownToBotDifficulty(difficultySetting);
|
||||
|
||||
|
@ -54,9 +54,9 @@ export class BotGeneratorHelper
|
||||
public generateExtraPropertiesForItem(itemTemplate: ITemplateItem, botRole?: string): { upd?: Upd }
|
||||
{
|
||||
// Get raid settings, if no raid, default to day
|
||||
const raidSettings = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue<
|
||||
IGetRaidConfigurationRequestData
|
||||
>();
|
||||
const raidSettings = this.applicationContext
|
||||
.getLatestValue(ContextVariableType.RAID_CONFIGURATION)
|
||||
?.getValue<IGetRaidConfigurationRequestData>();
|
||||
const raidIsNight = raidSettings?.timeVariant === "PAST";
|
||||
|
||||
const itemProperties: Upd = {};
|
||||
@ -64,11 +64,13 @@ export class BotGeneratorHelper
|
||||
if (itemTemplate._props.MaxDurability)
|
||||
{
|
||||
if (itemTemplate._props.weapClass)
|
||||
{ // Is weapon
|
||||
{
|
||||
// Is weapon
|
||||
itemProperties.Repairable = this.generateWeaponRepairableProperties(itemTemplate, botRole);
|
||||
}
|
||||
else if (itemTemplate._props.armorClass)
|
||||
{ // Is armor
|
||||
{
|
||||
// Is armor
|
||||
itemProperties.Repairable = this.generateArmorRepairableProperties(itemTemplate, botRole);
|
||||
}
|
||||
}
|
||||
@ -287,7 +289,7 @@ export class BotGeneratorHelper
|
||||
): IChooseRandomCompatibleModResult
|
||||
{
|
||||
// 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 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
|
||||
const blockingItem = equippedItemsDb.find(x => x._props.ConflictingItems?.includes(tplToCheck));
|
||||
const blockingItem = equippedItemsDb.find((x) => x._props.ConflictingItems?.includes(tplToCheck));
|
||||
if (blockingItem)
|
||||
{
|
||||
return {
|
||||
incompatible: true,
|
||||
found: false,
|
||||
reason:
|
||||
`Cannot add: ${tplToCheck} ${itemToEquip._name} to slot: ${modSlot}. Blocked by: ${blockingItem._id} ${blockingItem._name}`,
|
||||
reason: `Cannot add: ${tplToCheck} ${itemToEquip._name} to slot: ${modSlot}. Blocked by: ${blockingItem._id} ${blockingItem._name}`,
|
||||
slotBlocked: true,
|
||||
};
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
return {
|
||||
incompatible: true,
|
||||
found: false,
|
||||
reason:
|
||||
` Cannot add: ${tplToCheck} to slot: ${modSlot}. Would block existing item: ${blockingModItem._tpl} in slot: ${blockingModItem.slotId}`,
|
||||
reason: ` 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
|
||||
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 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
|
||||
let blockingItem = equippedItemsDb.find(x => x._props[`Blocks${equipmentSlot}`]);
|
||||
let blockingItem = equippedItemsDb.find((x) => x._props[`Blocks${equipmentSlot}`]);
|
||||
if (blockingItem)
|
||||
{
|
||||
// this.logger.warning(`1 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._name} - ${equipmentSlot}`);
|
||||
return {
|
||||
incompatible: true,
|
||||
found: false,
|
||||
reason:
|
||||
`${tplToCheck} ${itemToEquip._name} in slot: ${equipmentSlot} blocked by: ${blockingItem._id} ${blockingItem._name}`,
|
||||
reason: `${tplToCheck} ${itemToEquip._name} in slot: ${equipmentSlot} blocked by: ${blockingItem._id} ${blockingItem._name}`,
|
||||
slotBlocked: true,
|
||||
};
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// this.logger.warning(`2 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._props.Name} - ${equipmentSlot}`);
|
||||
return {
|
||||
incompatible: true,
|
||||
found: false,
|
||||
reason:
|
||||
`${tplToCheck} ${itemToEquip._name} in slot: ${equipmentSlot} blocked by: ${blockingItem._id} ${blockingItem._name}`,
|
||||
reason: `${tplToCheck} ${itemToEquip._name} in slot: ${equipmentSlot} blocked by: ${blockingItem._id} ${blockingItem._name}`,
|
||||
slotBlocked: true,
|
||||
};
|
||||
}
|
||||
@ -425,14 +423,13 @@ export class BotGeneratorHelper
|
||||
// Does item being checked get blocked/block existing item
|
||||
if (itemToEquip._props.BlocksHeadwear)
|
||||
{
|
||||
const existingHeadwear = itemsEquipped.find(x => x.slotId === "Headwear");
|
||||
const existingHeadwear = itemsEquipped.find((x) => x.slotId === "Headwear");
|
||||
if (existingHeadwear)
|
||||
{
|
||||
return {
|
||||
incompatible: true,
|
||||
found: false,
|
||||
reason:
|
||||
`${tplToCheck} ${itemToEquip._name} is blocked by: ${existingHeadwear._tpl} in slot: ${existingHeadwear.slotId}`,
|
||||
reason: `${tplToCheck} ${itemToEquip._name} is blocked by: ${existingHeadwear._tpl} in slot: ${existingHeadwear.slotId}`,
|
||||
slotBlocked: true,
|
||||
};
|
||||
}
|
||||
@ -441,14 +438,13 @@ export class BotGeneratorHelper
|
||||
// Does item being checked get blocked/block existing item
|
||||
if (itemToEquip._props.BlocksFaceCover)
|
||||
{
|
||||
const existingFaceCover = itemsEquipped.find(item => item.slotId === "FaceCover");
|
||||
const existingFaceCover = itemsEquipped.find((item) => item.slotId === "FaceCover");
|
||||
if (existingFaceCover)
|
||||
{
|
||||
return {
|
||||
incompatible: true,
|
||||
found: false,
|
||||
reason:
|
||||
`${tplToCheck} ${itemToEquip._name} is blocked by: ${existingFaceCover._tpl} in slot: ${existingFaceCover.slotId}`,
|
||||
reason: `${tplToCheck} ${itemToEquip._name} is blocked by: ${existingFaceCover._tpl} in slot: ${existingFaceCover.slotId}`,
|
||||
slotBlocked: true,
|
||||
};
|
||||
}
|
||||
@ -457,14 +453,13 @@ export class BotGeneratorHelper
|
||||
// Does item being checked get blocked/block existing item
|
||||
if (itemToEquip._props.BlocksEarpiece)
|
||||
{
|
||||
const existingEarpiece = itemsEquipped.find(item => item.slotId === "Earpiece");
|
||||
const existingEarpiece = itemsEquipped.find((item) => item.slotId === "Earpiece");
|
||||
if (existingEarpiece)
|
||||
{
|
||||
return {
|
||||
incompatible: true,
|
||||
found: false,
|
||||
reason:
|
||||
`${tplToCheck} ${itemToEquip._name} is blocked by: ${existingEarpiece._tpl} in slot: ${existingEarpiece.slotId}`,
|
||||
reason: `${tplToCheck} ${itemToEquip._name} is blocked by: ${existingEarpiece._tpl} in slot: ${existingEarpiece.slotId}`,
|
||||
slotBlocked: true,
|
||||
};
|
||||
}
|
||||
@ -473,29 +468,27 @@ export class BotGeneratorHelper
|
||||
// Does item being checked get blocked/block existing item
|
||||
if (itemToEquip._props.BlocksArmorVest)
|
||||
{
|
||||
const existingArmorVest = itemsEquipped.find(item => item.slotId === "ArmorVest");
|
||||
const existingArmorVest = itemsEquipped.find((item) => item.slotId === "ArmorVest");
|
||||
if (existingArmorVest)
|
||||
{
|
||||
return {
|
||||
incompatible: true,
|
||||
found: false,
|
||||
reason:
|
||||
`${tplToCheck} ${itemToEquip._name} is blocked by: ${existingArmorVest._tpl} in slot: ${existingArmorVest.slotId}`,
|
||||
reason: `${tplToCheck} ${itemToEquip._name} is blocked by: ${existingArmorVest._tpl} in slot: ${existingArmorVest.slotId}`,
|
||||
slotBlocked: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// this.logger.warning(`3 incompatibility found between - ${itemToEquip[1]._name} and ${blockingInventoryItem._tpl} - ${equipmentSlot}`)
|
||||
return {
|
||||
incompatible: true,
|
||||
found: false,
|
||||
reason:
|
||||
`${tplToCheck} blocks existing item ${blockingInventoryItem._tpl} in slot ${blockingInventoryItem.slotId}`,
|
||||
reason: `${tplToCheck} blocks existing item ${blockingInventoryItem._tpl} in slot ${blockingInventoryItem.slotId}`,
|
||||
};
|
||||
}
|
||||
|
||||
@ -543,7 +536,7 @@ export class BotGeneratorHelper
|
||||
continue;
|
||||
}
|
||||
// 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)
|
||||
{
|
||||
missingContainerCount++;
|
||||
@ -551,9 +544,9 @@ export class BotGeneratorHelper
|
||||
{
|
||||
// Bot doesnt have any containers we want to add item to
|
||||
this.logger.debug(
|
||||
`Unable to add item: ${itemWithChildren[0]._tpl} to bot as it lacks the following containers: ${
|
||||
equipmentSlots.join(",")
|
||||
}`,
|
||||
`Unable to add item: ${itemWithChildren[0]._tpl} to bot as it lacks the following containers: ${equipmentSlots.join(
|
||||
",",
|
||||
)}`,
|
||||
);
|
||||
|
||||
return ItemAddedResult.NO_CONTAINERS;
|
||||
@ -589,7 +582,8 @@ export class BotGeneratorHelper
|
||||
{
|
||||
// Grid is empty, skip or item size is bigger than grid
|
||||
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
|
||||
)
|
||||
{
|
||||
@ -604,12 +598,12 @@ export class BotGeneratorHelper
|
||||
}
|
||||
|
||||
// Get all root items in found container
|
||||
const existingContainerItems = inventory.items.filter(item =>
|
||||
item.parentId === container._id && item.slotId === slotGrid._name,
|
||||
const existingContainerItems = inventory.items.filter(
|
||||
(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
|
||||
const containerItemsToCheck = existingContainerItems.filter(x => x.slotId === slotGrid._name);
|
||||
const containerItemsToCheck = existingContainerItems.filter((x) => x.slotId === slotGrid._name);
|
||||
for (const item of containerItemsToCheck)
|
||||
{
|
||||
// Look for children on items, insert into array if found
|
||||
@ -635,7 +629,7 @@ export class BotGeneratorHelper
|
||||
// Open slot found, add item to inventory
|
||||
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
|
||||
parentItem.parentId = container._id;
|
||||
|
@ -66,7 +66,7 @@ export class BotHelper
|
||||
|
||||
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
|
||||
@ -182,8 +182,10 @@ export class BotHelper
|
||||
|
||||
public rollChanceToBePmc(role: string, botConvertMinMax: MinMax): boolean
|
||||
{
|
||||
return role.toLowerCase() in this.pmcConfig.convertIntoPmcChance
|
||||
&& this.randomUtil.getChance100(this.randomUtil.getInt(botConvertMinMax.min, botConvertMinMax.max));
|
||||
return (
|
||||
role.toLowerCase() in this.pmcConfig.convertIntoPmcChance
|
||||
&& this.randomUtil.getChance100(this.randomUtil.getInt(botConvertMinMax.min, botConvertMinMax.max))
|
||||
);
|
||||
}
|
||||
|
||||
public botRoleIsPmc(botRole: string): boolean
|
||||
@ -207,7 +209,7 @@ export class BotHelper
|
||||
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
|
||||
{
|
||||
return this.randomUtil.getChance100(this.pmcConfig.isUsec)
|
||||
? this.pmcConfig.usecType
|
||||
: this.pmcConfig.bearType;
|
||||
return this.randomUtil.getChance100(this.pmcConfig.isUsec) ? this.pmcConfig.usecType : this.pmcConfig.bearType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,9 +45,10 @@ export class BotWeaponGeneratorHelper
|
||||
{
|
||||
const firstSlotAmmoTpl = magTemplate._props.Cartridges[0]._props.filters[0].Filter[0];
|
||||
const ammoMaxStackSize = this.itemHelper.getItem(firstSlotAmmoTpl)[1]?._props?.StackMaxSize ?? 1;
|
||||
chamberBulletCount = ammoMaxStackSize === 1
|
||||
? 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
|
||||
chamberBulletCount
|
||||
= ammoMaxStackSize === 1
|
||||
? 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)
|
||||
{
|
||||
@ -60,7 +61,7 @@ export class BotWeaponGeneratorHelper
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ export class ContainerHelper
|
||||
const limitX = containerX - minVolume;
|
||||
|
||||
// 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);
|
||||
}
|
||||
@ -44,7 +44,7 @@ export class ContainerHelper
|
||||
for (let y = 0; y < limitY; y++)
|
||||
{
|
||||
// Across
|
||||
if (container2D[y].every(x => x === 1))
|
||||
if (container2D[y].every((x) => x === 1))
|
||||
{
|
||||
// Every item in row is full, skip row
|
||||
continue;
|
||||
|
@ -12,8 +12,7 @@ export abstract class AbstractDialogueChatBot implements IDialogueChatBot
|
||||
protected mailSendService: MailSendService,
|
||||
protected chatCommands: IChatCommand[] | ICommandoCommand[],
|
||||
)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @deprecated As of v3.7.6. Use registerChatCommand.
|
||||
@ -26,7 +25,7 @@ export abstract class AbstractDialogueChatBot implements IDialogueChatBot
|
||||
|
||||
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(
|
||||
`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 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]))
|
||||
{
|
||||
return commandos[0].handle(splitCommand[1], this.getChatBot(), sessionId, request);
|
||||
|
@ -18,18 +18,20 @@ export class SptCommandoCommands implements IChatCommand
|
||||
const coreConfigs = this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE);
|
||||
// if give command is disabled or commando commands are disabled
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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.`);
|
||||
}
|
||||
@ -38,7 +40,7 @@ export class SptCommandoCommands implements IChatCommand
|
||||
|
||||
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
|
||||
@ -48,7 +50,7 @@ export class SptCommandoCommands implements IChatCommand
|
||||
|
||||
public getCommands(): Set<string>
|
||||
{
|
||||
return new Set(this.sptCommands.map(c => c.getCommand()));
|
||||
return new Set(this.sptCommands.map((c) => c.getCommand()));
|
||||
}
|
||||
|
||||
public handle(
|
||||
@ -58,10 +60,8 @@ export class SptCommandoCommands implements IChatCommand
|
||||
request: ISendMessageRequest,
|
||||
): string
|
||||
{
|
||||
return this.sptCommands.find(c => c.getCommand() === command).performAction(
|
||||
commandHandler,
|
||||
sessionId,
|
||||
request,
|
||||
);
|
||||
return this.sptCommands
|
||||
.find((c) => c.getCommand() === command)
|
||||
.performAction(commandHandler, sessionId, request);
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,12 @@ export class GiveSptCommand implements ISptCommand
|
||||
private static commandRegex = /^spt give (((([a-z]{2,5}) )?"(.+)"|\w+) )?([0-9]+)$/;
|
||||
private static acceptableConfidence = 0.9;
|
||||
// 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>();
|
||||
|
||||
public constructor(
|
||||
@ -45,8 +50,7 @@ export class GiveSptCommand implements ISptCommand
|
||||
@inject("ItemFilterService") protected itemFilterService: ItemFilterService,
|
||||
@inject("RecursiveCloner") protected cloner: ICloner,
|
||||
)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
public getCommand(): string
|
||||
{
|
||||
@ -55,7 +59,7 @@ export class GiveSptCommand implements ISptCommand
|
||||
|
||||
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
|
||||
@ -65,7 +69,7 @@ export class GiveSptCommand implements ISptCommand
|
||||
this.mailSendService.sendUserMessageToPlayer(
|
||||
sessionId,
|
||||
commandHandler,
|
||||
"Invalid use of give command. Use \"help\" for more information.",
|
||||
'Invalid use of give command. Use "help" for more information.',
|
||||
);
|
||||
return request.dialogId;
|
||||
}
|
||||
@ -85,7 +89,7 @@ export class GiveSptCommand implements ISptCommand
|
||||
this.mailSendService.sendUserMessageToPlayer(
|
||||
sessionId,
|
||||
commandHandler,
|
||||
"Invalid use of give command. Use \"help\" for more information.",
|
||||
'Invalid use of give command. Use "help" for more information.',
|
||||
);
|
||||
return request.dialogId;
|
||||
}
|
||||
@ -95,7 +99,7 @@ export class GiveSptCommand implements ISptCommand
|
||||
this.mailSendService.sendUserMessageToPlayer(
|
||||
sessionId,
|
||||
commandHandler,
|
||||
"Invalid selection. Outside of bounds! Use \"help\" for more information.",
|
||||
'Invalid selection. Outside of bounds! Use "help" for more information.',
|
||||
);
|
||||
return request.dialogId;
|
||||
}
|
||||
@ -120,7 +124,7 @@ export class GiveSptCommand implements ISptCommand
|
||||
this.mailSendService.sendUserMessageToPlayer(
|
||||
sessionId,
|
||||
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;
|
||||
}
|
||||
@ -142,17 +146,19 @@ export class GiveSptCommand implements ISptCommand
|
||||
locale = "en";
|
||||
}
|
||||
|
||||
const localizedGlobal = this.databaseServer.getTables().locales.global[locale]
|
||||
?? this.databaseServer.getTables().locales.global.en;
|
||||
const localizedGlobal
|
||||
= this.databaseServer.getTables().locales.global[locale]
|
||||
?? this.databaseServer.getTables().locales.global.en;
|
||||
|
||||
const closestItemsMatchedByName = this.itemHelper.getItems()
|
||||
.filter(i => this.isItemAllowed(i))
|
||||
.map(i => localizedGlobal[`${i?._id} Name`]?.toLowerCase() ?? i._props.Name)
|
||||
.filter(i => i !== undefined && i !== "")
|
||||
.map(i => ({ match: stringSimilarity(
|
||||
item.toLocaleLowerCase(),
|
||||
i.toLocaleLowerCase(),
|
||||
), itemName: i }))
|
||||
const closestItemsMatchedByName = this.itemHelper
|
||||
.getItems()
|
||||
.filter((i) => this.isItemAllowed(i))
|
||||
.map((i) => localizedGlobal[`${i?._id} Name`]?.toLowerCase() ?? i._props.Name)
|
||||
.filter((i) => i !== undefined && i !== "")
|
||||
.map((i) => ({
|
||||
match: stringSimilarity(item.toLocaleLowerCase(), i.toLocaleLowerCase()),
|
||||
itemName: i,
|
||||
}))
|
||||
.sort((a1, a2) => a2.match - a1.match);
|
||||
|
||||
if (closestItemsMatchedByName[0].match >= GiveSptCommand.acceptableConfidence)
|
||||
@ -164,11 +170,16 @@ export class GiveSptCommand implements ISptCommand
|
||||
let i = 1;
|
||||
const slicedItems = closestItemsMatchedByName.slice(0, 10);
|
||||
// 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");
|
||||
this.savedCommand.set(
|
||||
sessionId,
|
||||
new SavedCommand(quantity, slicedItems.map(i => i.itemName), locale),
|
||||
new SavedCommand(
|
||||
quantity,
|
||||
slicedItems.map((i) => i.itemName),
|
||||
locale,
|
||||
),
|
||||
);
|
||||
this.mailSendService.sendUserMessageToPlayer(
|
||||
sessionId,
|
||||
@ -180,14 +191,15 @@ export class GiveSptCommand implements ISptCommand
|
||||
}
|
||||
}
|
||||
|
||||
const localizedGlobal = this.databaseServer.getTables().locales.global[locale]
|
||||
?? this.databaseServer.getTables().locales.global.en;
|
||||
const localizedGlobal
|
||||
= 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
|
||||
// item is just the tplId.
|
||||
const tplId = isItemName
|
||||
? this.itemHelper.getItems()
|
||||
.filter(i => this.isItemAllowed(i))
|
||||
.find(i => (localizedGlobal[`${i?._id} Name`]?.toLowerCase() ?? i._props.Name) === item)._id
|
||||
? this.itemHelper
|
||||
.getItems()
|
||||
.filter((i) => this.isItemAllowed(i))
|
||||
.find((i) => (localizedGlobal[`${i?._id} Name`]?.toLowerCase() ?? i._props.Name) === item)._id
|
||||
: item;
|
||||
|
||||
const checkedItem = this.itemHelper.getItem(tplId);
|
||||
@ -274,13 +286,15 @@ export class GiveSptCommand implements ISptCommand
|
||||
*/
|
||||
protected isItemAllowed(templateItem: ITemplateItem): boolean
|
||||
{
|
||||
return templateItem._type !== "Node"
|
||||
&& !this.itemHelper.isQuestItem(templateItem._id)
|
||||
&& !this.itemFilterService.isItemBlacklisted(templateItem._id)
|
||||
&& (templateItem._props?.Prefab?.path ?? "") !== ""
|
||||
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.HIDEOUT_AREA_CONTAINER)
|
||||
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.LOOT_CONTAINER)
|
||||
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.RANDOM_LOOT_CONTAINER)
|
||||
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.MOB_CONTAINER);
|
||||
return (
|
||||
templateItem._type !== "Node"
|
||||
&& !this.itemHelper.isQuestItem(templateItem._id)
|
||||
&& !this.itemFilterService.isItemBlacklisted(templateItem._id)
|
||||
&& (templateItem._props?.Prefab?.path ?? "") !== ""
|
||||
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.HIDEOUT_AREA_CONTAINER)
|
||||
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.LOOT_CONTAINER)
|
||||
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.RANDOM_LOOT_CONTAINER)
|
||||
&& !this.itemHelper.isOfBaseclass(templateItem._id, BaseClasses.MOB_CONTAINER)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
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,
|
||||
)
|
||||
{}
|
||||
}
|
||||
|
@ -37,8 +37,7 @@ export class ProfileSptCommand implements ISptCommand
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||
)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
public getCommand(): string
|
||||
{
|
||||
@ -57,7 +56,7 @@ export class ProfileSptCommand implements ISptCommand
|
||||
this.mailSendService.sendUserMessageToPlayer(
|
||||
sessionId,
|
||||
commandHandler,
|
||||
"Invalid use of trader command. Use \"help\" for more information.",
|
||||
'Invalid use of trader command. Use "help" for more information.',
|
||||
);
|
||||
return request.dialogId;
|
||||
}
|
||||
@ -77,7 +76,7 @@ export class ProfileSptCommand implements ISptCommand
|
||||
this.mailSendService.sendUserMessageToPlayer(
|
||||
sessionId,
|
||||
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;
|
||||
}
|
||||
@ -85,8 +84,8 @@ export class ProfileSptCommand implements ISptCommand
|
||||
break;
|
||||
case "skill":
|
||||
{
|
||||
const enumSkill = Object.values(SkillTypes).find(t =>
|
||||
t.toLocaleLowerCase() === skill.toLocaleLowerCase(),
|
||||
const enumSkill = Object.values(SkillTypes).find(
|
||||
(t) => t.toLocaleLowerCase() === skill.toLocaleLowerCase(),
|
||||
);
|
||||
|
||||
if (enumSkill === undefined)
|
||||
@ -94,7 +93,7 @@ export class ProfileSptCommand implements ISptCommand
|
||||
this.mailSendService.sendUserMessageToPlayer(
|
||||
sessionId,
|
||||
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;
|
||||
}
|
||||
@ -104,7 +103,7 @@ export class ProfileSptCommand implements ISptCommand
|
||||
this.mailSendService.sendUserMessageToPlayer(
|
||||
sessionId,
|
||||
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;
|
||||
}
|
||||
@ -123,13 +122,15 @@ export class ProfileSptCommand implements ISptCommand
|
||||
this.mailSendService.sendSystemMessageToPlayer(
|
||||
sessionId,
|
||||
"A single ruble is being attached, required by BSG logic.",
|
||||
[{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: "5449016a4bdc2d6f028b456f",
|
||||
upd: { StackObjectsCount: 1 },
|
||||
parentId: this.hashUtil.generate(),
|
||||
slotId: "main",
|
||||
}],
|
||||
[
|
||||
{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: "5449016a4bdc2d6f028b456f",
|
||||
upd: { StackObjectsCount: 1 },
|
||||
parentId: this.hashUtil.generate(),
|
||||
slotId: "main",
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
[event],
|
||||
);
|
||||
|
@ -33,8 +33,7 @@ export class TraderSptCommand implements ISptCommand
|
||||
@inject("LocaleService") protected localeService: LocaleService,
|
||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||
)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
public getCommand(): string
|
||||
{
|
||||
@ -53,7 +52,7 @@ export class TraderSptCommand implements ISptCommand
|
||||
this.mailSendService.sendUserMessageToPlayer(
|
||||
sessionId,
|
||||
commandHandler,
|
||||
"Invalid use of trader command. Use \"help\" for more information.",
|
||||
'Invalid use of trader command. Use "help" for more information.',
|
||||
);
|
||||
return request.dialogId;
|
||||
}
|
||||
@ -64,15 +63,15 @@ export class TraderSptCommand implements ISptCommand
|
||||
const command: string = result.groups.command;
|
||||
const quantity: number = +result.groups.quantity;
|
||||
|
||||
const dbTrader = Object.values(this.databaseServer.getTables().traders).find(t =>
|
||||
t.base.nickname.toLocaleLowerCase() === trader.toLocaleLowerCase(),
|
||||
const dbTrader = Object.values(this.databaseServer.getTables().traders).find(
|
||||
(t) => t.base.nickname.toLocaleLowerCase() === trader.toLocaleLowerCase(),
|
||||
);
|
||||
if (dbTrader === undefined)
|
||||
{
|
||||
this.mailSendService.sendUserMessageToPlayer(
|
||||
sessionId,
|
||||
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;
|
||||
}
|
||||
@ -97,13 +96,15 @@ export class TraderSptCommand implements ISptCommand
|
||||
this.mailSendService.sendSystemMessageToPlayer(
|
||||
sessionId,
|
||||
"A single ruble is being attached, required by BSG logic.",
|
||||
[{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: "5449016a4bdc2d6f028b456f",
|
||||
upd: { StackObjectsCount: 1 },
|
||||
parentId: this.hashUtil.generate(),
|
||||
slotId: "main",
|
||||
}],
|
||||
[
|
||||
{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: "5449016a4bdc2d6f028b456f",
|
||||
upd: { StackObjectsCount: 1 },
|
||||
parentId: this.hashUtil.generate(),
|
||||
slotId: "main",
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
[event],
|
||||
);
|
||||
|
@ -66,7 +66,7 @@ export class DialogueHelper
|
||||
const dialogueData = this.saveServer.getProfile(sessionID).dialogues;
|
||||
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)
|
||||
{
|
||||
continue;
|
||||
@ -87,7 +87,7 @@ export class DialogueHelper
|
||||
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)
|
||||
{
|
||||
message.rewardCollected = true;
|
||||
|
@ -172,7 +172,7 @@ export class DurabilityLimitsHelper
|
||||
const delta = this.randomUtil.getInt(minDelta, maxDelta);
|
||||
const result = Number((maxDurability - delta).toFixed(2));
|
||||
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
|
||||
@ -186,7 +186,7 @@ export class DurabilityLimitsHelper
|
||||
const delta = this.randomUtil.getInt(minDelta, maxDelta);
|
||||
const result = Number((maxDurability - delta).toFixed(2));
|
||||
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
|
||||
|
@ -56,9 +56,9 @@ export class HandbookHelper
|
||||
// Add handbook overrides found in items.json config into db
|
||||
for (const itemTpl in this.itemConfig.handbookPriceOverride)
|
||||
{
|
||||
let itemToUpdate = this.databaseServer.getTables().templates.handbook.Items.find(item =>
|
||||
item.Id === itemTpl,
|
||||
);
|
||||
let itemToUpdate = this.databaseServer
|
||||
.getTables()
|
||||
.templates.handbook.Items.find((item) => item.Id === itemTpl);
|
||||
if (!itemToUpdate)
|
||||
{
|
||||
this.databaseServer.getTables().templates.handbook.Items.push({
|
||||
@ -66,9 +66,9 @@ export class HandbookHelper
|
||||
ParentId: this.databaseServer.getTables().templates.items[itemTpl]._parent,
|
||||
Price: this.itemConfig.handbookPriceOverride[itemTpl],
|
||||
});
|
||||
itemToUpdate = this.databaseServer.getTables().templates.handbook.Items.find(item =>
|
||||
item.Id === itemTpl,
|
||||
);
|
||||
itemToUpdate = this.databaseServer
|
||||
.getTables()
|
||||
.templates.handbook.Items.find((item) => item.Id === itemTpl);
|
||||
}
|
||||
|
||||
itemToUpdate.Price = this.itemConfig.handbookPriceOverride[itemTpl];
|
||||
@ -118,7 +118,7 @@ export class HandbookHelper
|
||||
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)
|
||||
{
|
||||
const newValue = 0;
|
||||
@ -207,6 +207,6 @@ export class HandbookHelper
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,8 @@ export class HealthHelper
|
||||
const profile = this.saveServer.getProfile(sessionID);
|
||||
|
||||
if (!profile.vitality)
|
||||
{ // Occurs on newly created profiles
|
||||
{
|
||||
// Occurs on newly created profiles
|
||||
profile.vitality = { health: null, effects: null };
|
||||
}
|
||||
profile.vitality.health = {
|
||||
@ -99,13 +100,14 @@ export class HealthHelper
|
||||
profileEffects[bodyPart] = postRaidBodyParts[bodyPart].Effects;
|
||||
}
|
||||
if (request.IsAlive === true)
|
||||
{ // is player alive, not is limb alive
|
||||
{
|
||||
// is player alive, not is limb alive
|
||||
profileHealth[bodyPart] = postRaidBodyParts[bodyPart].Current;
|
||||
}
|
||||
else
|
||||
{
|
||||
profileHealth[bodyPart] = pmcData.Health.BodyParts[bodyPart].Health.Maximum
|
||||
* this.healthConfig.healthMultipliers.death;
|
||||
profileHealth[bodyPart]
|
||||
= pmcData.Health.BodyParts[bodyPart].Health.Maximum * this.healthConfig.healthMultipliers.death;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,9 +72,9 @@ export class HideoutHelper
|
||||
sessionID: string,
|
||||
): IItemEventRouterResponse
|
||||
{
|
||||
const recipe = this.databaseServer.getTables().hideout.production.find(production =>
|
||||
production._id === body.recipeId,
|
||||
);
|
||||
const recipe = this.databaseServer
|
||||
.getTables()
|
||||
.hideout.production.find((production) => production._id === body.recipeId);
|
||||
if (!recipe)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
this.itemHelper.addUpdObjectToItem(toolItem);
|
||||
@ -168,7 +168,7 @@ export class HideoutHelper
|
||||
case BonusType.STASH_SIZE:
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
this.logger.warning(
|
||||
@ -216,18 +216,20 @@ export class HideoutHelper
|
||||
* @param pmcData Player profile
|
||||
* @returns Properties
|
||||
*/
|
||||
protected getHideoutProperties(
|
||||
pmcData: IPmcData,
|
||||
): { btcFarmCGs: number, isGeneratorOn: boolean, waterCollectorHasFilter: boolean }
|
||||
protected getHideoutProperties(pmcData: IPmcData): {
|
||||
btcFarmCGs: number
|
||||
isGeneratorOn: boolean
|
||||
waterCollectorHasFilter: boolean
|
||||
}
|
||||
{
|
||||
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 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 hideoutProperties = {
|
||||
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(
|
||||
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)
|
||||
{
|
||||
// Has filter in at least one slot
|
||||
return waterCollector.slots.some(slot => slot.item);
|
||||
return waterCollector.slots.some((slot) => slot.item);
|
||||
}
|
||||
|
||||
// No Filter
|
||||
@ -308,7 +310,7 @@ export class HideoutHelper
|
||||
}
|
||||
|
||||
// Other recipes not covered by above
|
||||
const recipe = recipes.find(r => r._id === prodId);
|
||||
const recipe = recipes.find((r) => r._id === prodId);
|
||||
if (!recipe)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("hideout-missing_recipe_for_area", prodId));
|
||||
@ -364,9 +366,8 @@ export class HideoutHelper
|
||||
|
||||
// Increment progress by time passed
|
||||
const production = pmcData.Hideout.Production[prodId];
|
||||
production.Progress += production.needFuelForAllProductionTime && !hideoutProperties.isGeneratorOn
|
||||
? 0
|
||||
: timeElapsed; // Some items NEED power to craft (e.g. DSP)
|
||||
production.Progress
|
||||
+= production.needFuelForAllProductionTime && !hideoutProperties.isGeneratorOn ? 0 : 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))
|
||||
if (!recipe.continuous)
|
||||
@ -395,8 +396,10 @@ export class HideoutHelper
|
||||
*/
|
||||
protected updateScavCaseProductionTimer(pmcData: IPmcData, productionId: string): void
|
||||
{
|
||||
const timeElapsed = this.timeUtil.getTimestamp() - pmcData.Hideout.Production[productionId].StartTimestamp
|
||||
- pmcData.Hideout.Production[productionId].Progress;
|
||||
const timeElapsed
|
||||
= this.timeUtil.getTimestamp()
|
||||
- pmcData.Hideout.Production[productionId].StartTimestamp
|
||||
- pmcData.Hideout.Production[productionId].Progress;
|
||||
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
|
||||
// 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
|
||||
* this.getTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn);
|
||||
let fuelUsedSinceLastTick
|
||||
= 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
|
||||
const fuelConsumptionBonusMultipler
|
||||
@ -602,9 +606,9 @@ export class HideoutHelper
|
||||
{
|
||||
const globalSkillsDb = this.databaseServer.getTables().globals.config.SkillsSettings;
|
||||
|
||||
const recipe = this.databaseServer.getTables().hideout.production.find(production =>
|
||||
production._id === recipeId,
|
||||
);
|
||||
const recipe = this.databaseServer
|
||||
.getTables()
|
||||
.hideout.production.find((production) => production._id === recipeId);
|
||||
if (!recipe)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("hideout-missing_recipe_in_db", recipeId));
|
||||
@ -754,9 +758,10 @@ export class HideoutHelper
|
||||
baseFilterDrainRate: number,
|
||||
): number
|
||||
{
|
||||
const drainTimeSeconds = secondsSinceServerTick > totalProductionTime
|
||||
? totalProductionTime - productionProgress // More time passed than prod time, get total minus the current progress
|
||||
: secondsSinceServerTick;
|
||||
const drainTimeSeconds
|
||||
= secondsSinceServerTick > totalProductionTime
|
||||
? totalProductionTime - productionProgress // More time passed than prod time, get total minus the current progress
|
||||
: secondsSinceServerTick;
|
||||
|
||||
// Multiply base drain rate by time passed
|
||||
return baseFilterDrainRate * drainTimeSeconds;
|
||||
@ -786,9 +791,10 @@ export class HideoutHelper
|
||||
);
|
||||
|
||||
// Never let bonus become 0
|
||||
const reductionBonus = hideoutManagementConsumptionBonus + craftSkillTimeReductionMultipler === 0
|
||||
? 1
|
||||
: 1 - (hideoutManagementConsumptionBonus + craftSkillTimeReductionMultipler);
|
||||
const reductionBonus
|
||||
= hideoutManagementConsumptionBonus + craftSkillTimeReductionMultipler === 0
|
||||
? 1
|
||||
: 1 - (hideoutManagementConsumptionBonus + craftSkillTimeReductionMultipler);
|
||||
|
||||
return filterDrainRate * reductionBonus;
|
||||
}
|
||||
@ -800,7 +806,7 @@ export class HideoutHelper
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@ -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),
|
||||
300/17.64694/60/60 = 0.004722
|
||||
*/
|
||||
let filterDrainRate = this.databaseServer.getTables().hideout.settings.airFilterUnitFlowRate
|
||||
* this.getTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn);
|
||||
let filterDrainRate
|
||||
= this.databaseServer.getTables().hideout.settings.airFilterUnitFlowRate
|
||||
* this.getTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn);
|
||||
|
||||
// Hideout management resource consumption bonus:
|
||||
const hideoutManagementConsumptionBonus = 1.0 - this.getHideoutManagementConsumptionBonus(pmcData);
|
||||
@ -888,9 +895,9 @@ export class HideoutHelper
|
||||
protected updateBitcoinFarm(pmcData: IPmcData, btcFarmCGs: number, isGeneratorOn: boolean): Production
|
||||
{
|
||||
const btcProd = pmcData.Hideout.Production[HideoutHelper.bitcoinFarm];
|
||||
const bitcoinProdData = this.databaseServer.getTables().hideout.production.find(production =>
|
||||
production._id === HideoutHelper.bitcoinProductionId,
|
||||
);
|
||||
const bitcoinProdData = this.databaseServer
|
||||
.getTables()
|
||||
.hideout.production.find((production) => production._id === HideoutHelper.bitcoinProductionId);
|
||||
const coinSlotCount = this.getBTCSlots(pmcData);
|
||||
|
||||
// Full on bitcoins, halt progress
|
||||
@ -1024,9 +1031,9 @@ export class HideoutHelper
|
||||
*/
|
||||
protected getBTCSlots(pmcData: IPmcData): number
|
||||
{
|
||||
const bitcoinProductions = this.databaseServer.getTables().hideout.production.find(production =>
|
||||
production._id === HideoutHelper.bitcoinFarm,
|
||||
);
|
||||
const bitcoinProductions = this.databaseServer
|
||||
.getTables()
|
||||
.hideout.production.find((production) => production._id === HideoutHelper.bitcoinFarm);
|
||||
const productionSlots = bitcoinProductions?.productionLimitCount || 3; // Default to 3 if none found
|
||||
const hasManagementSkillSlots = this.profileHelper.hasEliteSkillLevel(SkillTypes.HIDEOUT_MANAGEMENT, pmcData);
|
||||
const managementSlotsCount = this.getEliteSkillAdditionalBitcoinSlotCount() || 2;
|
||||
@ -1063,9 +1070,12 @@ export class HideoutHelper
|
||||
let roundedLevel = Math.floor(hideoutManagementSkill.Progress / 100);
|
||||
roundedLevel = roundedLevel === 51 ? roundedLevel - 1 : roundedLevel;
|
||||
|
||||
return roundedLevel
|
||||
* this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement
|
||||
.ConsumptionReductionPerLevel / 100;
|
||||
return (
|
||||
(roundedLevel
|
||||
* this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement
|
||||
.ConsumptionReductionPerLevel)
|
||||
/ 100
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1089,7 +1099,7 @@ export class HideoutHelper
|
||||
let roundedLevel = Math.floor(profileSkill.Progress / 100);
|
||||
roundedLevel = roundedLevel === 51 ? roundedLevel - 1 : roundedLevel;
|
||||
|
||||
return roundedLevel * valuePerLevel / 100;
|
||||
return (roundedLevel * valuePerLevel) / 100;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1146,11 +1156,13 @@ export class HideoutHelper
|
||||
const itemsToAdd: Item[][] = [];
|
||||
for (let index = 0; index < craftedCoinCount; index++)
|
||||
{
|
||||
itemsToAdd.push([{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: HideoutHelper.bitcoinTpl,
|
||||
upd: { StackObjectsCount: 1 },
|
||||
}]);
|
||||
itemsToAdd.push([
|
||||
{
|
||||
_id: this.hashUtil.generate(),
|
||||
_tpl: HideoutHelper.bitcoinTpl,
|
||||
upd: { StackObjectsCount: 1 },
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
// Create request for what we want to add to stash
|
||||
@ -1187,9 +1199,9 @@ export class HideoutHelper
|
||||
*/
|
||||
public unlockHideoutWallInProfile(pmcProfile: IPmcData): void
|
||||
{
|
||||
const waterCollector = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WATER_COLLECTOR);
|
||||
const medStation = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.MEDSTATION);
|
||||
const wall = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.EMERGENCY_WALL);
|
||||
const waterCollector = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WATER_COLLECTOR);
|
||||
const medStation = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.MEDSTATION);
|
||||
const wall = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.EMERGENCY_WALL);
|
||||
|
||||
// No collector or med station, skip
|
||||
if (!(waterCollector && medStation))
|
||||
@ -1239,29 +1251,29 @@ export class HideoutHelper
|
||||
*/
|
||||
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
|
||||
const fameAreaDb = this.databaseServer.getTables().hideout.areas.find(area =>
|
||||
area.type === HideoutAreas.PLACE_OF_FAME,
|
||||
);
|
||||
const fameAreaDb = this.databaseServer
|
||||
.getTables()
|
||||
.hideout.areas.find((area) => area.type === HideoutAreas.PLACE_OF_FAME);
|
||||
|
||||
// Get SkillGroupLevelingBoost object
|
||||
const combatBoostBonusDb = fameAreaDb.stages[fameAreaProfile.level].bonuses.find(bonus =>
|
||||
bonus.type === "SkillGroupLevelingBoost",
|
||||
const combatBoostBonusDb = fameAreaDb.stages[fameAreaProfile.level].bonuses.find(
|
||||
(bonus) => bonus.type === "SkillGroupLevelingBoost",
|
||||
);
|
||||
|
||||
// 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
|
||||
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)
|
||||
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 bonus = this.getDogtagCombatSkillBonusPercent(pmcData, activeDogtags)
|
||||
* hideoutManagementSkillBonusPercent;
|
||||
const bonus
|
||||
= this.getDogtagCombatSkillBonusPercent(pmcData, activeDogtags) * hideoutManagementSkillBonusPercent;
|
||||
|
||||
// Update bonus value to above calcualted value
|
||||
combatBonusProfile.value = Number.parseFloat(bonus.toFixed(2));
|
||||
|
@ -4,7 +4,7 @@ import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||
import { PaymentHelper } from "@spt-aki/helpers/PaymentHelper";
|
||||
import { QuestHelper } from "@spt-aki/helpers/QuestHelper";
|
||||
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 { ISaveProgressRequestData } from "@spt-aki/models/eft/inRaid/ISaveProgressRequestData";
|
||||
import { IFailQuestRequestData } from "@spt-aki/models/eft/quests/IFailQuestRequestData";
|
||||
@ -67,7 +67,7 @@ export class InRaidHelper
|
||||
*/
|
||||
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);
|
||||
|
||||
@ -128,7 +128,10 @@ export class InRaidHelper
|
||||
}
|
||||
|
||||
/** 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)
|
||||
{
|
||||
@ -203,12 +206,12 @@ export class InRaidHelper
|
||||
): void
|
||||
{
|
||||
// Only copy active quests into scav profile // Progress will later to copied over to PMC profile
|
||||
const existingActiveQuestIds = scavData.Quests?.filter(
|
||||
x => x.status !== QuestStatus.AvailableForStart,
|
||||
).map(x => x.qid);
|
||||
const existingActiveQuestIds = scavData.Quests?.filter((x) => x.status !== QuestStatus.AvailableForStart).map(
|
||||
(x) => x.qid,
|
||||
);
|
||||
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);
|
||||
@ -240,10 +243,10 @@ export class InRaidHelper
|
||||
for (const postRaidQuest of postRaidProfile.Quests)
|
||||
{
|
||||
// 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
|
||||
const preRaidQuest = preRaidQuests?.find(preRaidQuest => preRaidQuest.qid === postRaidQuest.qid);
|
||||
const preRaidQuest = preRaidQuests?.find((preRaidQuest) => preRaidQuest.qid === postRaidQuest.qid);
|
||||
if (!preRaidQuest)
|
||||
{
|
||||
continue;
|
||||
@ -269,7 +272,8 @@ export class InRaidHelper
|
||||
|
||||
// Quest with time-gate has unlocked
|
||||
if (
|
||||
postRaidQuestStatus === "AvailableAfter" && postRaidQuest.availableAfter <= this.timeUtil.getTimestamp()
|
||||
postRaidQuestStatus === "AvailableAfter"
|
||||
&& postRaidQuest.availableAfter <= this.timeUtil.getTimestamp()
|
||||
)
|
||||
{
|
||||
// Flag as ready to start
|
||||
@ -298,8 +302,8 @@ export class InRaidHelper
|
||||
// Does failed quest have requirement to collect items from raid
|
||||
const questDbData = this.questHelper.getQuestFromDb(postRaidQuest.qid, pmcData);
|
||||
// AvailableForFinish
|
||||
const matchingAffFindConditions = questDbData.conditions.AvailableForFinish.filter(condition =>
|
||||
condition.conditionType === "FindItem",
|
||||
const matchingAffFindConditions = questDbData.conditions.AvailableForFinish.filter(
|
||||
(condition) => condition.conditionType === "FindItem",
|
||||
);
|
||||
const itemsToCollect: string[] = [];
|
||||
if (matchingAffFindConditions)
|
||||
@ -314,7 +318,7 @@ export class InRaidHelper
|
||||
// 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
|
||||
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
|
||||
@ -322,8 +326,8 @@ export class InRaidHelper
|
||||
for (const itemTpl of itemsToCollect)
|
||||
{
|
||||
// Look for sessioncounter and remove it
|
||||
const counterIndex = postRaidProfile.Stats.Eft.SessionCounters.Items.findIndex(x =>
|
||||
x.Key.includes(itemTpl) && x.Key.includes("LootItem"),
|
||||
const counterIndex = postRaidProfile.Stats.Eft.SessionCounters.Items.findIndex(
|
||||
(x) => x.Key.includes(itemTpl) && x.Key.includes("LootItem"),
|
||||
);
|
||||
if (counterIndex > -1)
|
||||
{
|
||||
@ -331,7 +335,7 @@ export class InRaidHelper
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
postRaidProfile.Inventory.items.splice(inventoryItemIndex, 1);
|
||||
@ -454,10 +458,15 @@ export class InRaidHelper
|
||||
const itemsToRemovePropertyFrom = postRaidProfile.Inventory.items.filter((x) =>
|
||||
{
|
||||
// Has upd object + upd.SpawnedInSession property + not a quest item
|
||||
return "upd" in x && "SpawnedInSession" in x.upd
|
||||
&& !dbItems[x._tpl]._props.QuestItem
|
||||
&& !(this.inRaidConfig.keepFiRSecureContainerOnDeath
|
||||
&& this.itemHelper.itemIsInsideContainer(x, "SecuredContainer", postRaidProfile.Inventory.items));
|
||||
return (
|
||||
"upd" in x
|
||||
&& "SpawnedInSession" in x.upd
|
||||
&& !dbItems[x._tpl]._props.QuestItem
|
||||
&& !(
|
||||
this.inRaidConfig.keepFiRSecureContainerOnDeath
|
||||
&& this.itemHelper.itemIsInsideContainer(x, "SecuredContainer", postRaidProfile.Inventory.items)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
for (const item of itemsToRemovePropertyFrom)
|
||||
@ -502,7 +511,7 @@ export class InRaidHelper
|
||||
public deleteInventory(pmcData: IPmcData, sessionId: string): void
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// Items inside containers are handled as part of function
|
||||
@ -555,13 +564,13 @@ export class InRaidHelper
|
||||
*/
|
||||
protected getBaseItemsInRigPocketAndBackpack(pmcData: IPmcData): Item[]
|
||||
{
|
||||
const rig = pmcData.Inventory.items.find(x => x.slotId === "TacticalVest");
|
||||
const pockets = pmcData.Inventory.items.find(x => x.slotId === "Pockets");
|
||||
const backpack = pmcData.Inventory.items.find(x => x.slotId === "Backpack");
|
||||
const rig = pmcData.Inventory.items.find((x) => x.slotId === "TacticalVest");
|
||||
const pockets = pmcData.Inventory.items.find((x) => x.slotId === "Pockets");
|
||||
const backpack = pmcData.Inventory.items.find((x) => x.slotId === "Backpack");
|
||||
|
||||
const baseItemsInRig = pmcData.Inventory.items.filter(x => x.parentId === rig?._id);
|
||||
const baseItemsInPockets = pmcData.Inventory.items.filter(x => x.parentId === pockets?._id);
|
||||
const baseItemsInBackpack = pmcData.Inventory.items.filter(x => x.parentId === backpack?._id);
|
||||
const baseItemsInRig = pmcData.Inventory.items.filter((x) => x.parentId === rig?._id);
|
||||
const baseItemsInPockets = pmcData.Inventory.items.filter((x) => x.parentId === pockets?._id);
|
||||
const baseItemsInBackpack = pmcData.Inventory.items.filter((x) => x.parentId === backpack?._id);
|
||||
|
||||
return [...baseItemsInRig, ...baseItemsInPockets, ...baseItemsInBackpack];
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ import { BackendErrorCodes } from "@spt-aki/models/enums/BackendErrorCodes";
|
||||
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
|
||||
import { BonusType } from "@spt-aki/models/enums/BonusType";
|
||||
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 { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||
@ -167,9 +166,8 @@ export class InventoryHelper
|
||||
catch (err)
|
||||
{
|
||||
// Callback failed
|
||||
const message = typeof err?.message === "string"
|
||||
? err.message
|
||||
: this.localisationService.getText("http-unknown_error");
|
||||
const message
|
||||
= typeof err?.message === "string" ? err.message : this.localisationService.getText("http-unknown_error");
|
||||
|
||||
this.httpResponse.appendErrorToOutput(output, message);
|
||||
|
||||
@ -520,13 +518,15 @@ export class InventoryHelper
|
||||
if (requestItem.count > itemDetails._props.StackMaxSize)
|
||||
{
|
||||
let remainingCountOfItemToAdd = requestItem.count;
|
||||
const calc = requestItem.count
|
||||
- Math.floor(requestItem.count / itemDetails._props.StackMaxSize)
|
||||
* itemDetails._props.StackMaxSize;
|
||||
const calc
|
||||
= requestItem.count
|
||||
- Math.floor(requestItem.count / itemDetails._props.StackMaxSize)
|
||||
* itemDetails._props.StackMaxSize;
|
||||
|
||||
maxStackCount = calc > 0
|
||||
? maxStackCount + Math.floor(remainingCountOfItemToAdd / itemDetails._props.StackMaxSize)
|
||||
: Math.floor(remainingCountOfItemToAdd / itemDetails._props.StackMaxSize);
|
||||
maxStackCount
|
||||
= calc > 0
|
||||
? maxStackCount + Math.floor(remainingCountOfItemToAdd / itemDetails._props.StackMaxSize)
|
||||
: Math.floor(remainingCountOfItemToAdd / itemDetails._props.StackMaxSize);
|
||||
|
||||
// Iterate until totalCountOfPurchasedItem is 0
|
||||
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".
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
insuredItems.splice(insuredIndex, 1);
|
||||
@ -636,7 +636,7 @@ export class InventoryHelper
|
||||
const dialogs = Object.values(fullProfile.dialogues);
|
||||
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)
|
||||
{
|
||||
// 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[][]
|
||||
{
|
||||
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 iH = tmpSize[1]; // y
|
||||
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"
|
||||
? iW
|
||||
: iH;
|
||||
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"
|
||||
? iH
|
||||
: iW;
|
||||
@ -1078,7 +1082,7 @@ export class InventoryHelper
|
||||
protected getPlayerStashSize(sessionID: string): Record<number, number>
|
||||
{
|
||||
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)
|
||||
const stashTPL = this.getStashType(sessionID);
|
||||
@ -1118,7 +1122,7 @@ export class InventoryHelper
|
||||
protected getStashType(sessionID: string): string
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
for (const itemId of idsToMove)
|
||||
{
|
||||
const itemToMove = fromItems.find(x => x._id === itemId);
|
||||
const itemToMove = fromItems.find((x) => x._id === itemId);
|
||||
if (!itemToMove)
|
||||
{
|
||||
this.logger.error(`Unable to find item to move: ${itemId}`);
|
||||
@ -1188,7 +1192,7 @@ export class InventoryHelper
|
||||
this.handleCartridges(inventoryItems, moveRequest);
|
||||
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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
|
||||
if (itemParent && !(itemParent.slotId?.startsWith("Pockets") || itemParent.slotId === "TacticalVest"))
|
||||
@ -1317,7 +1321,7 @@ export class InventoryHelper
|
||||
return true;
|
||||
}
|
||||
|
||||
container = pmcData.Inventory.items.find(item => item._id === container.parentId);
|
||||
container = pmcData.Inventory.items.find((item) => item._id === container.parentId);
|
||||
if (!container)
|
||||
{
|
||||
break;
|
||||
|
@ -68,7 +68,7 @@ export class ItemHelper
|
||||
}
|
||||
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)
|
||||
{
|
||||
return false;
|
||||
@ -98,7 +98,7 @@ export class ItemHelper
|
||||
|
||||
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]),
|
||||
);
|
||||
}
|
||||
@ -194,11 +194,13 @@ export class ItemHelper
|
||||
return false;
|
||||
}
|
||||
|
||||
return !itemDetails[1]._props.QuestItem
|
||||
&& itemDetails[1]._type === "Item"
|
||||
&& baseTypes.every(x => !this.isOfBaseclass(tpl, x))
|
||||
&& this.getItemPrice(tpl) > 0
|
||||
&& !this.itemFilterService.isItemBlacklisted(tpl);
|
||||
return (
|
||||
!itemDetails[1]._props.QuestItem
|
||||
&& itemDetails[1]._type === "Item"
|
||||
&& baseTypes.every((x) => !this.isOfBaseclass(tpl, x))
|
||||
&& this.getItemPrice(tpl) > 0
|
||||
&& !this.itemFilterService.isItemBlacklisted(tpl)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -261,7 +263,7 @@ export class ItemHelper
|
||||
const itemTemplate = this.getItem(itemTpl);
|
||||
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
|
||||
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;
|
||||
}
|
||||
@ -629,7 +631,7 @@ export class ItemHelper
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
@ -650,7 +652,7 @@ export class ItemHelper
|
||||
|
||||
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 = 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[]
|
||||
{
|
||||
// Find required items to take after buying (handles multiple items)
|
||||
const desiredBarterIds = typeof desiredBarterItemIds === "string"
|
||||
? [desiredBarterItemIds]
|
||||
: desiredBarterItemIds;
|
||||
const desiredBarterIds
|
||||
= typeof desiredBarterItemIds === "string" ? [desiredBarterItemIds] : desiredBarterItemIds;
|
||||
|
||||
const matchingItems: Item[] = [];
|
||||
for (const barterId of desiredBarterIds)
|
||||
@ -846,7 +847,7 @@ export class ItemHelper
|
||||
if (pmcData !== null)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
@ -1054,8 +1055,8 @@ export class ItemHelper
|
||||
let isRequiredSlot = false;
|
||||
if (parentTemplate[0] && parentTemplate[1]?._props?.Slots)
|
||||
{
|
||||
isRequiredSlot = parentTemplate[1]._props.Slots.some(slot =>
|
||||
slot._name === item.slotId && slot._required,
|
||||
isRequiredSlot = parentTemplate[1]._props.Slots.some(
|
||||
(slot) => slot._name === item.slotId && slot._required,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1100,11 +1101,13 @@ export class ItemHelper
|
||||
*/
|
||||
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)
|
||||
|| equipmentSlots.includes(item.slotId)
|
||||
|| !Number.isNaN(Number(item.slotId)));
|
||||
return !(
|
||||
["hideout", "main"].includes(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
|
||||
{
|
||||
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))
|
||||
{
|
||||
@ -1146,7 +1149,7 @@ export class ItemHelper
|
||||
*/
|
||||
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 height = rootTemplate._props.Height;
|
||||
|
||||
@ -1178,9 +1181,8 @@ export class ItemHelper
|
||||
sizeUp = sizeUp < itemTemplate._props.ExtraSizeUp ? itemTemplate._props.ExtraSizeUp : sizeUp;
|
||||
sizeDown = sizeDown < itemTemplate._props.ExtraSizeDown ? itemTemplate._props.ExtraSizeDown : sizeDown;
|
||||
sizeLeft = sizeLeft < itemTemplate._props.ExtraSizeLeft ? itemTemplate._props.ExtraSizeLeft : sizeLeft;
|
||||
sizeRight = sizeRight < itemTemplate._props.ExtraSizeRight
|
||||
? itemTemplate._props.ExtraSizeRight
|
||||
: sizeRight;
|
||||
sizeRight
|
||||
= sizeRight < itemTemplate._props.ExtraSizeRight ? itemTemplate._props.ExtraSizeRight : sizeRight;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1221,7 +1223,7 @@ export class ItemHelper
|
||||
const cartridgeMaxStackSize = cartridgeDetails[1]._props.StackMaxSize;
|
||||
|
||||
// Exit if ammo already exists in box
|
||||
if (ammoBox.find(item => item._tpl === cartridgeTpl))
|
||||
if (ammoBox.find((item) => item._tpl === cartridgeTpl))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1289,7 +1291,7 @@ export class ItemHelper
|
||||
public itemIsInsideContainer(item: Item, desiredContainerSlotId: string, items: Item[]): boolean
|
||||
{
|
||||
// Get items parent
|
||||
const parent = items.find(x => x._id === item.parentId);
|
||||
const parent = items.find((x) => x._id === item.parentId);
|
||||
if (!parent)
|
||||
{
|
||||
// No parent, end of line, not inside container
|
||||
@ -1394,9 +1396,8 @@ export class ItemHelper
|
||||
while (currentStoredCartridgeCount < desiredStackCount)
|
||||
{
|
||||
// Get stack size of cartridges
|
||||
let cartridgeCountToAdd = desiredStackCount <= cartridgeMaxStackSize
|
||||
? desiredStackCount
|
||||
: cartridgeMaxStackSize;
|
||||
let cartridgeCountToAdd
|
||||
= desiredStackCount <= cartridgeMaxStackSize ? desiredStackCount : cartridgeMaxStackSize;
|
||||
|
||||
// Ensure we don't go over the max stackcount size
|
||||
const remainingSpace = desiredStackCount - currentStoredCartridgeCount;
|
||||
@ -1437,9 +1438,9 @@ export class ItemHelper
|
||||
const ammoTpls = magTemplate._props.Cartridges[0]._props.filters[0].Filter;
|
||||
const calibers = [
|
||||
...new Set(
|
||||
ammoTpls.filter((x: string) => this.getItem(x)[0]).map((x: string) =>
|
||||
this.getItem(x)[1]._props.Caliber,
|
||||
),
|
||||
ammoTpls
|
||||
.filter((x: string) => this.getItem(x)[0])
|
||||
.map((x: string) => this.getItem(x)[1]._props.Caliber),
|
||||
),
|
||||
];
|
||||
return this.randomUtil.drawRandomFromList(calibers)[0];
|
||||
@ -1555,9 +1556,9 @@ export class ItemHelper
|
||||
|
||||
public getItemTplsOfBaseType(desiredBaseType: string): string[]
|
||||
{
|
||||
return Object.values(this.databaseServer.getTables().templates.items).filter(x =>
|
||||
x._parent === desiredBaseType,
|
||||
).map(x => x._id);
|
||||
return Object.values(this.databaseServer.getTables().templates.items)
|
||||
.filter((x) => x._parent === desiredBaseType)
|
||||
.map((x) => x._id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1771,7 +1772,7 @@ export class ItemHelper
|
||||
for (const item of items)
|
||||
{
|
||||
// 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
|
||||
// setting the parent ID to the PMCs inventory equipment ID, the slot ID to 'hideout', and remove the location.
|
||||
|
@ -86,9 +86,10 @@ export class NotificationSendHelper
|
||||
protected getDialog(sessionId: string, messageType: MessageType, senderDetails: IUserDialogInfo): Dialogue
|
||||
{
|
||||
// Use trader id if sender is trader, otherwise use nickname
|
||||
const key = senderDetails.Info.MemberCategory === MemberCategory.TRADER
|
||||
? senderDetails._id
|
||||
: senderDetails.Info.Nickname;
|
||||
const key
|
||||
= senderDetails.Info.MemberCategory === MemberCategory.TRADER
|
||||
? senderDetails._id
|
||||
: senderDetails.Info.Nickname;
|
||||
const dialogueData = this.saveServer.getProfile(sessionId).dialogues;
|
||||
const isNewDialogue = !(key in dialogueData);
|
||||
let dialogue: Dialogue = dialogueData[key];
|
||||
|
@ -21,8 +21,8 @@ export class PaymentHelper
|
||||
*/
|
||||
public isMoneyTpl(tpl: string): boolean
|
||||
{
|
||||
return [Money.DOLLARS, Money.EUROS, Money.ROUBLES, ...this.inventoryConfig.customMoneyTpls].some(element =>
|
||||
element === tpl,
|
||||
return [Money.DOLLARS, Money.EUROS, Money.ROUBLES, ...this.inventoryConfig.customMoneyTpls].some(
|
||||
(element) => element === tpl,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -44,11 +44,9 @@ export class PresetHelper
|
||||
{
|
||||
if (!this.defaultWeaponPresets)
|
||||
{
|
||||
this.defaultWeaponPresets = Object.values(
|
||||
this.databaseServer.getTables().globals.ItemPresets,
|
||||
)
|
||||
this.defaultWeaponPresets = Object.values(this.databaseServer.getTables().globals.ItemPresets)
|
||||
.filter(
|
||||
preset =>
|
||||
(preset) =>
|
||||
preset._encyclopedia !== undefined
|
||||
&& this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON),
|
||||
)
|
||||
@ -71,9 +69,12 @@ export class PresetHelper
|
||||
if (!this.defaultEquipmentPresets)
|
||||
{
|
||||
this.defaultEquipmentPresets = Object.values(this.databaseServer.getTables().globals.ItemPresets)
|
||||
.filter(preset => preset._encyclopedia !== undefined
|
||||
&& this.itemHelper.armorItemCanHoldMods(preset._encyclopedia),
|
||||
).reduce((acc, cur) =>
|
||||
.filter(
|
||||
(preset) =>
|
||||
preset._encyclopedia !== undefined
|
||||
&& this.itemHelper.armorItemCanHoldMods(preset._encyclopedia),
|
||||
)
|
||||
.reduce((acc, cur) =>
|
||||
{
|
||||
acc[cur._id] = cur;
|
||||
return acc;
|
||||
@ -186,7 +187,7 @@ export class PresetHelper
|
||||
const defaultPreset = this.getDefaultPreset(tpl);
|
||||
|
||||
// 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
|
||||
return this.itemHelper.getItemAndChildrenPrice(tpls);
|
||||
|
@ -52,7 +52,7 @@ export class ProfileHelper
|
||||
for (const questId in questConditionId)
|
||||
{
|
||||
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
|
||||
const index = profileQuest.completedConditions.indexOf(conditionId);
|
||||
@ -339,7 +339,7 @@ export class ProfileHelper
|
||||
public removeSecureContainer(profile: IPmcData): IPmcData
|
||||
{
|
||||
const items = profile.Inventory.items;
|
||||
const secureContainer = items.find(x => x.slotId === "SecuredContainer");
|
||||
const secureContainer = items.find((x) => x.slotId === "SecuredContainer");
|
||||
if (secureContainer)
|
||||
{
|
||||
// Find and remove container + children
|
||||
@ -349,7 +349,7 @@ export class ProfileHelper
|
||||
);
|
||||
|
||||
// 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;
|
||||
@ -393,7 +393,7 @@ export class ProfileHelper
|
||||
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
|
||||
{
|
||||
const stat = counters.find(x => x.Key.includes(keyToIncrement));
|
||||
const stat = counters.find((x) => x.Key.includes(keyToIncrement));
|
||||
if (stat)
|
||||
{
|
||||
stat.Value++;
|
||||
@ -424,7 +424,7 @@ export class ProfileHelper
|
||||
return false;
|
||||
}
|
||||
|
||||
const profileSkill = profileSkills.find(x => x.Id === skillType);
|
||||
const profileSkill = profileSkills.find((x) => x.Id === skillType);
|
||||
if (!profileSkill)
|
||||
{
|
||||
this.logger.warning(`Unable to check for elite skill ${skillType}, not found in profile`);
|
||||
@ -466,7 +466,7 @@ export class ProfileHelper
|
||||
return;
|
||||
}
|
||||
|
||||
const profileSkill = profileSkills.find(profileSkill => profileSkill.Id === skill);
|
||||
const profileSkill = profileSkills.find((profileSkill) => profileSkill.Id === skill);
|
||||
if (!profileSkill)
|
||||
{
|
||||
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
|
||||
{
|
||||
const skillToReturn = pmcData.Skills.Common.find(commonSkill => commonSkill.Id === skill);
|
||||
const skillToReturn = pmcData.Skills.Common.find((commonSkill) => commonSkill.Id === skill);
|
||||
if (!skillToReturn)
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
profile.Bonuses.push({
|
||||
|
@ -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 { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||
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 { IAcceptQuestRequestData } from "@spt-aki/models/eft/quests/IAcceptQuestRequestData";
|
||||
import { IFailQuestRequestData } from "@spt-aki/models/eft/quests/IFailQuestRequestData";
|
||||
@ -69,7 +68,7 @@ export class QuestHelper
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@ -150,7 +149,7 @@ export class QuestHelper
|
||||
}
|
||||
|
||||
// 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
|
||||
let remainingProgress = progressAmount / 10;
|
||||
@ -164,7 +163,7 @@ export class QuestHelper
|
||||
const currentLevelRemainingProgress = (currentLevel + 1) * 10 - startingLevelProgress;
|
||||
this.logger.debug(`currentLevelRemainingProgress: ${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}`);
|
||||
|
||||
// Add the progress amount adjusted by level
|
||||
@ -286,10 +285,13 @@ export class QuestHelper
|
||||
|
||||
// Is root item, fix stacks
|
||||
if (rewardItem._id === questReward.target)
|
||||
{ // Is base reward item
|
||||
{
|
||||
// Is base reward item
|
||||
if (
|
||||
rewardItem.parentId !== undefined && rewardItem.parentId === "hideout" // Has parentId of hideout
|
||||
&& rewardItem.upd !== undefined && rewardItem.upd.StackObjectsCount !== undefined // Has upd with stackobject count
|
||||
rewardItem.parentId !== undefined
|
||||
&& 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
|
||||
)
|
||||
{
|
||||
@ -353,7 +355,7 @@ export class QuestHelper
|
||||
questReward.items = presetAndMods;
|
||||
|
||||
// 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
|
||||
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
|
||||
const questRewards = quest.rewards[QuestStatus[status]].flatMap((reward: IQuestReward) =>
|
||||
(reward.type === "Item" ? this.processReward(reward) : []),
|
||||
reward.type === "Item" ? this.processReward(reward) : [],
|
||||
);
|
||||
|
||||
return questRewards;
|
||||
@ -404,7 +406,7 @@ export class QuestHelper
|
||||
): IQuestStatus
|
||||
{
|
||||
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)
|
||||
{
|
||||
// Quest exists, update its status
|
||||
@ -436,7 +438,7 @@ export class QuestHelper
|
||||
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")
|
||||
{
|
||||
// Quest should be put into 'pending' state
|
||||
@ -463,7 +465,7 @@ export class QuestHelper
|
||||
{
|
||||
// Get quest acceptance data from profile
|
||||
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
|
||||
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
|
||||
const acceptedQuestCondition = quest.conditions.AvailableForStart.find((x) =>
|
||||
{
|
||||
return x.conditionType === "Quest"
|
||||
&& x.target?.includes(startedQuestId)
|
||||
&& x.status?.includes(QuestStatus.Started);
|
||||
return (
|
||||
x.conditionType === "Quest"
|
||||
&& x.target?.includes(startedQuestId)
|
||||
&& x.status?.includes(QuestStatus.Started)
|
||||
);
|
||||
});
|
||||
|
||||
// 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
|
||||
return startedQuestInProfile
|
||||
&& [QuestStatus.Started, QuestStatus.AvailableForFinish].includes(startedQuestInProfile.status);
|
||||
return (
|
||||
startedQuestInProfile
|
||||
&& [QuestStatus.Started, QuestStatus.AvailableForFinish].includes(startedQuestInProfile.status)
|
||||
);
|
||||
});
|
||||
|
||||
return this.getQuestsWithOnlyLevelRequirementStartCondition(eligibleQuests);
|
||||
@ -551,15 +557,15 @@ export class QuestHelper
|
||||
public failedUnlocked(failedQuestId: string, sessionId: string): IQuest[]
|
||||
{
|
||||
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 acceptedQuestCondition = q.conditions.AvailableForStart.find((c) =>
|
||||
{
|
||||
return c.conditionType === "Quest"
|
||||
&& c.target.includes(failedQuestId)
|
||||
&& c.status[0] === QuestStatus.Fail;
|
||||
return (
|
||||
c.conditionType === "Quest" && c.target.includes(failedQuestId) && c.status[0] === QuestStatus.Fail
|
||||
);
|
||||
});
|
||||
|
||||
if (!acceptedQuestCondition)
|
||||
@ -595,7 +601,7 @@ export class QuestHelper
|
||||
if (this.paymentHelper.isMoneyTpl(reward.items[0]._tpl))
|
||||
{
|
||||
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,
|
||||
): void
|
||||
{
|
||||
const inventoryItemIndex = pmcData.Inventory.items.findIndex(item => item._id === itemId);
|
||||
const inventoryItemIndex = pmcData.Inventory.items.findIndex((item) => item._id === itemId);
|
||||
if (inventoryItemIndex < 0)
|
||||
{
|
||||
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
|
||||
{
|
||||
const updatedQuest = this.cloner.clone(quest);
|
||||
updatedQuest.conditions.AvailableForStart = updatedQuest.conditions.AvailableForStart.filter(q =>
|
||||
q.conditionType === "Level",
|
||||
updatedQuest.conditions.AvailableForStart = updatedQuest.conditions.AvailableForStart.filter(
|
||||
(q) => q.conditionType === "Level",
|
||||
);
|
||||
|
||||
return updatedQuest;
|
||||
@ -734,9 +740,9 @@ export class QuestHelper
|
||||
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
|
||||
const matchingRepeatableQuest = pmcData.RepeatableQuests.flatMap(repeatableType =>
|
||||
repeatableType.activeQuests,
|
||||
).find(activeQuest => activeQuest._id === failRequest.qid);
|
||||
const matchingRepeatableQuest = pmcData.RepeatableQuests.flatMap(
|
||||
(repeatableType) => repeatableType.activeQuests,
|
||||
).find((activeQuest) => activeQuest._id === failRequest.qid);
|
||||
|
||||
// Quest found and no repeatable found
|
||||
if (quest && !matchingRepeatableQuest)
|
||||
@ -783,7 +789,7 @@ export class QuestHelper
|
||||
// Check daily/weekly objects
|
||||
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)
|
||||
{
|
||||
break;
|
||||
@ -805,7 +811,9 @@ export class QuestHelper
|
||||
// blank or is a guid, use description instead
|
||||
const startedMessageText = this.getQuestLocaleIdFromDb(startedMessageTextId);
|
||||
if (
|
||||
!startedMessageText || startedMessageText.trim() === "" || startedMessageText.toLowerCase() === "test"
|
||||
!startedMessageText
|
||||
|| startedMessageText.trim() === ""
|
||||
|| startedMessageText.toLowerCase() === "test"
|
||||
|| startedMessageText.length === 24
|
||||
)
|
||||
{
|
||||
@ -835,7 +843,7 @@ export class QuestHelper
|
||||
public updateQuestState(pmcData: IPmcData, newQuestState: QuestStatus, questId: string): void
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
questToUpdate.status = newQuestState;
|
||||
@ -851,7 +859,7 @@ export class QuestHelper
|
||||
*/
|
||||
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)
|
||||
{
|
||||
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
|
||||
const hideoutProductions = this.databaseServer.getTables().hideout.production;
|
||||
const matchingProductions = hideoutProductions.filter(x =>
|
||||
x.areaType === Number.parseInt(craftUnlockReward.traderId)
|
||||
&& x.requirements.some(x => x.requiredLevel === craftUnlockReward.loyaltyLevel)
|
||||
&& x.endProduct === craftUnlockReward.items[0]._tpl,
|
||||
const matchingProductions = hideoutProductions.filter(
|
||||
(x) =>
|
||||
x.areaType === Number.parseInt(craftUnlockReward.traderId)
|
||||
&& 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
|
||||
@ -1027,7 +1036,7 @@ export class QuestHelper
|
||||
protected getQuestMoneyRewardBonus(pmcData: IPmcData): number
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
return 0;
|
||||
@ -1061,15 +1070,15 @@ export class QuestHelper
|
||||
const result: Record<string, string> = {};
|
||||
for (const questId of questIds)
|
||||
{
|
||||
const questInDb = allQuests.find(x => x._id === questId);
|
||||
const questInDb = allQuests.find((x) => x._id === questId);
|
||||
if (!questInDb)
|
||||
{
|
||||
this.logger.debug(`Unable to find quest: ${questId} in db, cannot get 'FindItem' condition, skipping`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const condition = questInDb.conditions.AvailableForFinish.find(c =>
|
||||
c.conditionType === "FindItem" && c?.target?.includes(itemTpl),
|
||||
const condition = questInDb.conditions.AvailableForFinish.find(
|
||||
(c) => c.conditionType === "FindItem" && c?.target?.includes(itemTpl),
|
||||
);
|
||||
if (condition)
|
||||
{
|
||||
@ -1095,7 +1104,7 @@ export class QuestHelper
|
||||
{
|
||||
// Quest from db matches quests in profile, skip
|
||||
const questData = quests[questIdKey];
|
||||
if (pmcProfile.Quests.find(x => x.qid === questData._id))
|
||||
if (pmcProfile.Quests.find((x) => x.qid === questData._id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -1115,10 +1124,10 @@ export class QuestHelper
|
||||
availableAfter: 0,
|
||||
};
|
||||
|
||||
if (pmcProfile.Quests.some(x => x.qid === questIdKey))
|
||||
if (pmcProfile.Quests.some((x) => x.qid === questIdKey))
|
||||
{
|
||||
// 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.statusTimers = questRecordToAdd.statusTimers;
|
||||
}
|
||||
@ -1132,7 +1141,7 @@ export class QuestHelper
|
||||
|
||||
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)
|
||||
{
|
||||
quests.splice(quests.indexOf(pmcQuestToReplaceStatus), 1);
|
||||
@ -1155,7 +1164,7 @@ export class QuestHelper
|
||||
return false;
|
||||
}
|
||||
|
||||
return quest.conditions.Fail.some(condition => condition.target?.includes(completedQuestId));
|
||||
return quest.conditions.Fail.some((condition) => condition.target?.includes(completedQuestId));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ export class RagfairHelper
|
||||
for (let item of items)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -14,7 +14,6 @@ import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEve
|
||||
import { IAkiProfile, ISystemData } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||
import { IRagfairOffer } from "@spt-aki/models/eft/ragfair/IRagfairOffer";
|
||||
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 { MemberCategory } from "@spt-aki/models/enums/MemberCategory";
|
||||
import { MessageType } from "@spt-aki/models/enums/MessageType";
|
||||
@ -185,7 +184,7 @@ export class RagfairOfferHelper
|
||||
const lockedOffers = this.getLoyaltyLockedOffers(possibleOffers, pmcData);
|
||||
|
||||
// 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)
|
||||
{
|
||||
possibleOffers = availableOffers;
|
||||
@ -220,8 +219,8 @@ export class RagfairOfferHelper
|
||||
*/
|
||||
public traderOfferItemQuestLocked(offer: IRagfairOffer, traderAssorts: Record<string, ITraderAssort>): boolean
|
||||
{
|
||||
return offer.items?.some(i =>
|
||||
traderAssorts[offer.user.id].barter_scheme[i._id]?.some(bs1 => bs1?.some(bs2 => bs2.sptQuestLocked)),
|
||||
return offer.items?.some((i) =>
|
||||
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
|
||||
{
|
||||
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
|
||||
if (!assortData)
|
||||
{
|
||||
this.logger.warning(
|
||||
`Unable to find trader: ${offer.user.nickname} assort for item: ${
|
||||
this.itemHelper.getItemName(offer.items[0]._tpl)
|
||||
} ${offer.items[0]._tpl}, cannot check if buy restriction reached`,
|
||||
`Unable to find trader: ${offer.user.nickname} assort for item: ${this.itemHelper.getItemName(
|
||||
offer.items[0]._tpl,
|
||||
)} ${offer.items[0]._tpl}, cannot check if buy restriction reached`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@ -333,7 +332,7 @@ export class RagfairOfferHelper
|
||||
|
||||
this.increaseProfileRagfairRating(
|
||||
this.saveServer.getProfile(sessionID),
|
||||
offer.summaryCost / totalItemsCount * boughtAmount,
|
||||
(offer.summaryCost / totalItemsCount) * boughtAmount,
|
||||
);
|
||||
|
||||
this.completeOffer(sessionID, offer, boughtAmount);
|
||||
@ -361,7 +360,7 @@ export class RagfairOfferHelper
|
||||
return;
|
||||
}
|
||||
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
|
||||
{
|
||||
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);
|
||||
|
||||
// Also delete from ragfair
|
||||
@ -416,7 +415,7 @@ export class RagfairOfferHelper
|
||||
else
|
||||
{
|
||||
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);
|
||||
|
||||
let removeCount = boughtAmount;
|
||||
@ -446,9 +445,9 @@ export class RagfairOfferHelper
|
||||
|
||||
for (const id of idsToRemove)
|
||||
{
|
||||
const newIds = offer.items.filter(i =>
|
||||
!idsToRemove.includes(i._id) && idsToRemove.includes(i.parentId),
|
||||
).map(i => i._id);
|
||||
const newIds = offer.items
|
||||
.filter((i) => !idsToRemove.includes(i._id) && idsToRemove.includes(i.parentId))
|
||||
.map((i) => i._id);
|
||||
if (newIds.length > 0)
|
||||
{
|
||||
foundNewItems = true;
|
||||
@ -459,7 +458,7 @@ export class RagfairOfferHelper
|
||||
|
||||
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))
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -724,7 +723,7 @@ export class RagfairOfferHelper
|
||||
// Performing a required search and offer doesn't have requirement for item
|
||||
if (
|
||||
searchRequest.neededSearchId
|
||||
&& !offer.requirements.some(requirement => requirement._tpl === searchRequest.neededSearchId)
|
||||
&& !offer.requirements.some((requirement) => requirement._tpl === searchRequest.neededSearchId)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
@ -782,7 +781,7 @@ export class RagfairOfferHelper
|
||||
|
||||
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;
|
||||
}
|
||||
@ -799,7 +798,11 @@ export class RagfairOfferHelper
|
||||
{
|
||||
// thanks typescript, undefined assertion is not returnable since it
|
||||
// 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
|
||||
? true
|
||||
: false;
|
||||
|
@ -43,7 +43,7 @@ export class RagfairSellHelper
|
||||
const baseSellChancePercent = sellConfig.base * qualityMultiplier;
|
||||
|
||||
// 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
|
||||
|
||||
// Adjust sell chance if below config value
|
||||
@ -72,10 +72,11 @@ export class RagfairSellHelper
|
||||
const startTime = this.timeUtil.getTimestamp();
|
||||
|
||||
// Get a time in future to stop simulating sell chances at
|
||||
const endTime = startTime
|
||||
+ this.timeUtil.getHoursAsSeconds(
|
||||
this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour,
|
||||
);
|
||||
const endTime
|
||||
= startTime
|
||||
+ this.timeUtil.getHoursAsSeconds(
|
||||
this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour,
|
||||
);
|
||||
|
||||
let sellTime = startTime;
|
||||
let remainingCount = itemSellCount;
|
||||
|
@ -106,7 +106,8 @@ export class RagfairServerHelper
|
||||
|
||||
// Don't include damaged ammo packs
|
||||
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")
|
||||
)
|
||||
{
|
||||
@ -217,7 +218,7 @@ export class RagfairServerHelper
|
||||
this.randomUtil.getInt(config.stackablePercent.min, config.stackablePercent.max),
|
||||
);
|
||||
|
||||
return Math.round(maxStackCount / 100 * stackPercent);
|
||||
return Math.round((maxStackCount / 100) * stackPercent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,8 +31,8 @@ export class RepeatableQuestHelper
|
||||
repeatableConfig: IRepeatableQuestConfig,
|
||||
): IEliminationConfig
|
||||
{
|
||||
return repeatableConfig.questConfig.Elimination.find(x =>
|
||||
pmcLevel >= x.levelRange.min && pmcLevel <= x.levelRange.max,
|
||||
return repeatableConfig.questConfig.Elimination.find(
|
||||
(x) => pmcLevel >= x.levelRange.min && pmcLevel <= x.levelRange.max,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ export class SecureContainerHelper
|
||||
*/
|
||||
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
|
||||
if (!secureContainer)
|
||||
@ -34,6 +34,6 @@ export class SecureContainerHelper
|
||||
const itemsInSecureContainer = this.itemHelper.findAndReturnChildrenByItems(items, secureContainer._id);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -43,8 +43,8 @@ export class TradeHelper
|
||||
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
|
||||
@inject("RagfairServer") protected ragfairServer: RagfairServer,
|
||||
@inject("TraderAssortHelper") protected traderAssortHelper: TraderAssortHelper,
|
||||
@inject("TraderPurchasePersisterService") protected traderPurchasePersisterService:
|
||||
TraderPurchasePersisterService,
|
||||
@inject("TraderPurchasePersisterService")
|
||||
protected traderPurchasePersisterService: TraderPurchasePersisterService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@inject("RecursiveCloner") protected cloner: ICloner,
|
||||
)
|
||||
@ -79,7 +79,7 @@ export class TradeHelper
|
||||
const allOffers = this.ragfairServer.getOffers();
|
||||
|
||||
// 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];
|
||||
|
||||
// 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
|
||||
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;
|
||||
}
|
||||
else if (buyRequestData.tid === Traders.FENCE)
|
||||
@ -114,7 +114,7 @@ export class TradeHelper
|
||||
{
|
||||
// Update assort/flea item values
|
||||
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
|
||||
itemPurchased.upd.StackObjectsCount -= buyCount;
|
||||
@ -123,7 +123,7 @@ export class TradeHelper
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
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
|
||||
const assortHasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased);
|
||||
@ -260,7 +260,7 @@ export class TradeHelper
|
||||
const itemIdToFind = itemToBeRemoved.id.replace(/\s+/g, ""); // Strip out whitespace
|
||||
|
||||
// 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)
|
||||
{
|
||||
const errorMessage = `Unable to sell item ${itemToBeRemoved.id}, cannot be found in player inventory`;
|
||||
|
@ -40,8 +40,8 @@ export class TraderAssortHelper
|
||||
@inject("RagfairOfferGenerator") protected ragfairOfferGenerator: RagfairOfferGenerator,
|
||||
@inject("TraderAssortService") protected traderAssortService: TraderAssortService,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("TraderPurchasePersisterService") protected traderPurchasePersisterService:
|
||||
TraderPurchasePersisterService,
|
||||
@inject("TraderPurchasePersisterService")
|
||||
protected traderPurchasePersisterService: TraderPurchasePersisterService,
|
||||
@inject("TraderHelper") protected traderHelper: TraderHelper,
|
||||
@inject("FenceService") protected fenceService: FenceService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@ -95,7 +95,7 @@ export class TraderAssortHelper
|
||||
for (const assortId in assortPurchasesfromTrader)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
this.logger.debug(
|
||||
@ -147,7 +147,7 @@ export class TraderAssortHelper
|
||||
protected resetBuyRestrictionCurrentValue(assortItems: Item[]): void
|
||||
{
|
||||
// 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
|
||||
if (!assort.upd.BuyRestrictionCurrent)
|
||||
|
@ -108,7 +108,7 @@ export class TraderHelper
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
this.logger.debug(`No assort ${assortId} on trader: ${traderId} found`);
|
||||
@ -239,7 +239,8 @@ export class TraderHelper
|
||||
if (
|
||||
loyalty.minLevel <= pmcData.Info.Level
|
||||
&& loyalty.minSalesSum <= pmcData.TradersInfo[traderID].salesSum
|
||||
&& loyalty.minStanding <= pmcData.TradersInfo[traderID].standing && targetLevel < 4
|
||||
&& loyalty.minStanding <= pmcData.TradersInfo[traderID].standing
|
||||
&& targetLevel < 4
|
||||
)
|
||||
{
|
||||
// level reached
|
||||
@ -270,7 +271,7 @@ export class TraderHelper
|
||||
*/
|
||||
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)
|
||||
{
|
||||
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,
|
||||
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)
|
||||
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)
|
||||
const barterScheme = traderAssorts.barter_scheme[item._id][0][0];
|
||||
|
||||
// Convert into roubles
|
||||
const roubleAmount = barterScheme._tpl === Money.ROUBLES
|
||||
? barterScheme.count
|
||||
: this.handbookHelper.inRUB(barterScheme.count, barterScheme._tpl);
|
||||
const roubleAmount
|
||||
= barterScheme._tpl === Money.ROUBLES
|
||||
? barterScheme.count
|
||||
: this.handbookHelper.inRUB(barterScheme.count, barterScheme._tpl);
|
||||
|
||||
// Existing price smaller in dict than current iteration, overwrite
|
||||
if (this.highestTraderPriceItems[item._tpl] ?? 0 < roubleAmount)
|
||||
@ -478,7 +481,7 @@ export class TraderHelper
|
||||
*/
|
||||
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)
|
||||
{
|
||||
@ -523,7 +526,7 @@ export class TraderHelper
|
||||
*/
|
||||
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
|
||||
{
|
||||
return Object.values(Traders).some(x => x === traderId);
|
||||
return Object.values(Traders).some((x) => x === traderId);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,6 @@ export class UtilityHelper
|
||||
{
|
||||
public arrayIntersect<T>(a: T[], b: T[]): T[]
|
||||
{
|
||||
return a.filter(x => b.includes(x));
|
||||
return a.filter((x) => b.includes(x));
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,9 @@ export class BundleLoader
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -69,11 +69,13 @@ export class ModTypeCheck
|
||||
*/
|
||||
public isPostV3Compatible(mod: any): boolean
|
||||
{
|
||||
return this.isPreAkiLoad(mod)
|
||||
|| this.isPostAkiLoad(mod)
|
||||
|| this.isPostDBAkiLoad(mod)
|
||||
|| this.isPreAkiLoadAsync(mod)
|
||||
|| this.isPostAkiLoadAsync(mod)
|
||||
|| this.isPostDBAkiLoadAsync(mod);
|
||||
return (
|
||||
this.isPreAkiLoad(mod)
|
||||
|| this.isPostAkiLoad(mod)
|
||||
|| this.isPostDBAkiLoad(mod)
|
||||
|| this.isPreAkiLoadAsync(mod)
|
||||
|| this.isPostAkiLoadAsync(mod)
|
||||
|| this.isPostDBAkiLoadAsync(mod)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -93,10 +93,10 @@ export class PreAkiModLoader implements IModLoader
|
||||
for (const modName in modsGroupedByName)
|
||||
{
|
||||
const modDatas = modsGroupedByName[modName];
|
||||
const modVersions = modDatas.map(x => x.version);
|
||||
const modVersions = modDatas.map((x) => x.version);
|
||||
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)
|
||||
{
|
||||
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 (
|
||||
modToValidate.dependencies && Object.keys(modToValidate.dependencies).length > 0
|
||||
modToValidate.dependencies
|
||||
&& Object.keys(modToValidate.dependencies).length > 0
|
||||
&& !this.vfs.exists(`${this.basepath}${modFolderName}/node_modules`)
|
||||
)
|
||||
{
|
||||
@ -267,7 +268,7 @@ export class PreAkiModLoader implements IModLoader
|
||||
for (const mod of modPackageData.values())
|
||||
{
|
||||
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 (grouppedMods.get(name).length > 1 && !this.skippedMods.has(name))
|
||||
@ -641,7 +642,7 @@ export class PreAkiModLoader implements IModLoader
|
||||
const modIsCalledSrc = modName.toLowerCase() === "src";
|
||||
const modIsCalledDb = modName.toLowerCase() === "db";
|
||||
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)
|
||||
{
|
||||
@ -691,7 +692,8 @@ export class PreAkiModLoader implements IModLoader
|
||||
if ("main" in config)
|
||||
{
|
||||
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));
|
||||
issue = true;
|
||||
}
|
||||
|
@ -1,3 +1,2 @@
|
||||
export interface IEmptyRequestData
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
@ -386,9 +386,9 @@ export interface Productive
|
||||
ProductionTime?: number
|
||||
GivenItemsInStart?: string[]
|
||||
Interrupted?: boolean
|
||||
Code?: string;
|
||||
Decoded?: boolean;
|
||||
AvailableForFinish?: boolean;
|
||||
Code?: string
|
||||
Decoded?: boolean
|
||||
AvailableForFinish?: boolean
|
||||
/** Used in hideout production.json */
|
||||
needFuelForAllProductionTime?: boolean
|
||||
/** Used when sending data to client */
|
||||
@ -459,8 +459,7 @@ export interface Notes
|
||||
}
|
||||
|
||||
export interface CarExtractCounts
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
export enum SurvivorClass
|
||||
{
|
||||
|
@ -1,14 +1,11 @@
|
||||
export interface IAcceptFriendRequestData extends IBaseFriendRequest
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
export interface ICancelFriendRequestData extends IBaseFriendRequest
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
export interface IDeclineFriendRequestData extends IBaseFriendRequest
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
export interface IBaseFriendRequest
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
export interface IAddUserGroupMailRequest
|
||||
{
|
||||
dialogId: string;
|
||||
uid: string;
|
||||
dialogId: string
|
||||
uid: string
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
export interface IChangeGroupMailOwnerRequest
|
||||
{
|
||||
dialogId: string;
|
||||
uid: string;
|
||||
dialogId: string
|
||||
uid: string
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
export interface ICreateGroupMailRequest
|
||||
{
|
||||
Name: string;
|
||||
Users: string[];
|
||||
Name: string
|
||||
Users: string[]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
export interface IRemoveUserGroupMailRequest
|
||||
{
|
||||
dialogId: string;
|
||||
uid: string;
|
||||
dialogId: string
|
||||
uid: string
|
||||
}
|
||||
|
@ -17,8 +17,7 @@ export interface IQteData
|
||||
area: HideoutAreas
|
||||
areaLevel: number
|
||||
quickTimeEvents: IQuickTimeEvent[]
|
||||
requirements:
|
||||
(
|
||||
requirements: (
|
||||
| IAreaRequirement
|
||||
| IItemRequirement
|
||||
| ITraderUnlockRequirement
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { IBaseInteractionRequestData } from "@spt-aki/models/eft/common/request/IBaseInteractionRequestData";
|
||||
|
||||
export interface IInventoryBaseActionRequestData extends IBaseInteractionRequestData
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
export interface To
|
||||
{
|
||||
|
@ -2,6 +2,4 @@ import { IWsNotificationEvent } from "@spt-aki/models/eft/ws/IWsNotificationEven
|
||||
import { IGroupCharacter } from "../match/IGroupCharacter";
|
||||
|
||||
export interface IWsGroupMatchInviteAccept extends IWsNotificationEvent, IGroupCharacter
|
||||
{
|
||||
|
||||
}
|
||||
{}
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { IWsNotificationEvent } from "@spt-aki/models/eft/ws/IWsNotificationEvent";
|
||||
|
||||
export interface IWsPing extends IWsNotificationEvent
|
||||
{
|
||||
|
||||
}
|
||||
{}
|
||||
|
@ -1,5 +1,5 @@
|
||||
export enum MemberCategory // player type
|
||||
{
|
||||
export enum MemberCategory
|
||||
{ // player type
|
||||
DEFAULT = 0,
|
||||
DEVELOPER = 1,
|
||||
UNIQUE_ID = 2,
|
||||
|
@ -10,5 +10,5 @@ export enum QuestRewardType
|
||||
TRADER_STANDING_RESET = "TraderStandingReset",
|
||||
TRADER_STANDING_RESTORE = "TraderStandingRestore",
|
||||
STASH_ROWS = "StashRows",
|
||||
ACHIEVEMENT = "Achievement"
|
||||
ACHIEVEMENT = "Achievement",
|
||||
}
|
||||
|
10
project/src/models/external/HttpFramework.ts
vendored
10
project/src/models/external/HttpFramework.ts
vendored
@ -12,7 +12,7 @@ export type HandleFn = (_: string, req: IncomingMessage, resp: ServerResponse) =
|
||||
*/
|
||||
export const Listen = (basePath: string) =>
|
||||
{
|
||||
return <T extends { new(...args: any[]): any }>(Base: T): T =>
|
||||
return <T extends { new (...args: any[]): any }>(Base: T): T =>
|
||||
{
|
||||
// Used for the base class to be able to use DI
|
||||
injectable()(Base);
|
||||
@ -61,8 +61,10 @@ export const Listen = (basePath: string) =>
|
||||
{
|
||||
const routesHandles = this.handlers[req.method];
|
||||
|
||||
return Object.keys(this.handlers).some(meth => meth === req.method)
|
||||
&& Object.keys(routesHandles).some(route => new RegExp(route).test(req.url));
|
||||
return (
|
||||
Object.keys(this.handlers).some((meth) => meth === req.method)
|
||||
&& Object.keys(routesHandles).some((route) => new RegExp(route).test(req.url))
|
||||
);
|
||||
};
|
||||
|
||||
// The actual handle method dispatches the request to the registered handlers
|
||||
@ -81,7 +83,7 @@ export const Listen = (basePath: string) =>
|
||||
routes.sort((routeA, routeB) => routeB.length - routeA.length);
|
||||
|
||||
// Filter to select valid routes but only use the first element since it's the most precise
|
||||
const validRoutes = routes.filter(handlerKey => new RegExp(handlerKey).test(route));
|
||||
const validRoutes = routes.filter((handlerKey) => new RegExp(handlerKey).test(route));
|
||||
if (validRoutes.length > 0)
|
||||
{
|
||||
routesHandles[validRoutes[0]](sessionID, req, resp);
|
||||
|
@ -5,7 +5,11 @@ export class ExhaustableArray<T> implements IExhaustableArray<T>
|
||||
{
|
||||
private pool: T[];
|
||||
|
||||
constructor(private itemPool: T[], private randomUtil: RandomUtil, private cloner: ICloner)
|
||||
constructor(
|
||||
private itemPool: T[],
|
||||
private randomUtil: RandomUtil,
|
||||
private cloner: ICloner,
|
||||
)
|
||||
{
|
||||
this.pool = this.cloner.clone(itemPool);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ export class HttpRouter
|
||||
}
|
||||
|
||||
// TODO: Temporary hack to change ItemEventRouter response sessionID binding to what client expects
|
||||
if (wrapper.output?.includes("\"profileChanges\":{"))
|
||||
if (wrapper.output?.includes('"profileChanges":{'))
|
||||
{
|
||||
wrapper.output = wrapper.output.replace(sessionID, sessionID);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ export class ItemEventRouter
|
||||
{
|
||||
const pmcData = this.profileHelper.getPmcProfile(sessionID);
|
||||
|
||||
const eventRouter = this.itemEventRouters.find(r => r.canHandle(body.Action));
|
||||
const eventRouter = this.itemEventRouters.find((r) => r.canHandle(body.Action));
|
||||
if (eventRouter)
|
||||
{
|
||||
this.logger.debug(`event: ${body.Action}`);
|
||||
|
@ -13,7 +13,8 @@ export class HealthSaveLoadRouter extends SaveLoadRouter
|
||||
public override handleLoad(profile: IAkiProfile): IAkiProfile
|
||||
{
|
||||
if (!profile.vitality)
|
||||
{ // Occurs on newly created profiles
|
||||
{
|
||||
// Occurs on newly created profiles
|
||||
profile.vitality = { health: null, effects: null };
|
||||
}
|
||||
profile.vitality.health = {
|
||||
|
@ -26,9 +26,10 @@ export class NotifySerializer extends Serializer
|
||||
* 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.
|
||||
*/
|
||||
this.notifierController.notifyAsync(tmpSessionID).then((messages: any) =>
|
||||
messages.map((message: any) => this.jsonUtil.serialize(message)).join("\n"),
|
||||
).then(text => this.httpServerHelper.sendTextJson(resp, text));
|
||||
this.notifierController
|
||||
.notifyAsync(tmpSessionID)
|
||||
.then((messages: any) => messages.map((message: any) => this.jsonUtil.serialize(message)).join("\n"))
|
||||
.then((text) => this.httpServerHelper.sendTextJson(resp, text));
|
||||
}
|
||||
|
||||
public override canHandle(route: string): boolean
|
||||
|
@ -160,7 +160,12 @@ export class MatchStaticRouter extends StaticRouter
|
||||
),
|
||||
new RouteAction(
|
||||
"/client/match/group/invite/decline",
|
||||
async (url: string, info: any, sessionID: string, output: string): Promise<IGetBodyResponseData<any>> =>
|
||||
async (
|
||||
url: string,
|
||||
info: any,
|
||||
sessionID: string,
|
||||
output: string,
|
||||
): Promise<IGetBodyResponseData<any>> =>
|
||||
{
|
||||
return this.matchCallbacks.declineGroupInvite(url, info, sessionID);
|
||||
},
|
||||
|
@ -60,14 +60,24 @@ export class ProfileStaticRouter extends StaticRouter
|
||||
),
|
||||
new RouteAction(
|
||||
"/client/game/profile/nickname/change",
|
||||
async (url: string, info: any, sessionID: string, output: string): Promise<IGetBodyResponseData<any>> =>
|
||||
async (
|
||||
url: string,
|
||||
info: any,
|
||||
sessionID: string,
|
||||
output: string,
|
||||
): Promise<IGetBodyResponseData<any>> =>
|
||||
{
|
||||
return this.profileCallbacks.changeNickname(url, info, sessionID);
|
||||
},
|
||||
),
|
||||
new RouteAction(
|
||||
"/client/game/profile/nickname/validate",
|
||||
async (url: string, info: any, sessionID: string, output: string): Promise<IGetBodyResponseData<any>> =>
|
||||
async (
|
||||
url: string,
|
||||
info: any,
|
||||
sessionID: string,
|
||||
output: string,
|
||||
): Promise<IGetBodyResponseData<any>> =>
|
||||
{
|
||||
return this.profileCallbacks.validateNickname(url, info, sessionID);
|
||||
},
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||
import { ICoreConfig } from "@spt-aki/models/spt/config/ICoreConfig";
|
||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||
import { VFS } from "@spt-aki/utils/VFS";
|
||||
|
@ -95,10 +95,12 @@ export class HttpServer
|
||||
}
|
||||
else
|
||||
{
|
||||
this.logger.info(this.localisationService.getText("client_request_ip", {
|
||||
ip: clientIp,
|
||||
url: req.url.replaceAll("/", "\\"), // Localisation service escapes `/` into hex code `/`
|
||||
}));
|
||||
this.logger.info(
|
||||
this.localisationService.getText("client_request_ip", {
|
||||
ip: clientIp,
|
||||
url: req.url.replaceAll("/", "\\"), // Localisation service escapes `/` into hex code `/`
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,9 +127,11 @@ export class HttpServer
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return remoteAddress.startsWith("127.0.0")
|
||||
|| remoteAddress.startsWith("192.168.")
|
||||
|| remoteAddress.startsWith("localhost");
|
||||
return (
|
||||
remoteAddress.startsWith("127.0.0")
|
||||
|| remoteAddress.startsWith("192.168.")
|
||||
|| remoteAddress.startsWith("localhost")
|
||||
);
|
||||
}
|
||||
|
||||
protected getCookies(req: IncomingMessage): Record<string, string>
|
||||
|
@ -79,7 +79,7 @@ export class RagfairServer
|
||||
*/
|
||||
public getUpdateableTraders(): string[]
|
||||
{
|
||||
return Object.keys(this.ragfairConfig.traders).filter(x => this.ragfairConfig.traders[x]);
|
||||
return Object.keys(this.ragfairConfig.traders).filter((x) => this.ragfairConfig.traders[x]);
|
||||
}
|
||||
|
||||
public getAllActiveCategories(
|
||||
@ -98,7 +98,7 @@ export class RagfairServer
|
||||
public hideOffer(offerId: string): void
|
||||
{
|
||||
const offers = this.ragfairOfferService.getOffers();
|
||||
const offer = offers.find(x => x._id === offerId);
|
||||
const offer = offers.find((x) => x._id === offerId);
|
||||
|
||||
if (!offer)
|
||||
{
|
||||
|
@ -21,8 +21,7 @@ export class AkiHttpListener implements IHttpListener
|
||||
@inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
public canHandle(_: string, req: IncomingMessage): boolean
|
||||
{
|
||||
@ -153,7 +152,7 @@ export class AkiHttpListener implements IHttpListener
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("unhandled_response", req.url));
|
||||
this.logger.info(info);
|
||||
output = <string><unknown> this.httpResponse.getBody(null, 404, `UNHANDLED RESPONSE: ${req.url}`);
|
||||
output = <string>(<unknown> this.httpResponse.getBody(null, 404, `UNHANDLED RESPONSE: ${req.url}`));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
@ -180,18 +179,28 @@ export class AkiHttpListener implements IHttpListener
|
||||
|
||||
class RequestData
|
||||
{
|
||||
constructor(public url: string, public headers: IncomingHttpHeaders, public data?: any)
|
||||
constructor(
|
||||
public url: string,
|
||||
public headers: IncomingHttpHeaders,
|
||||
public data?: any,
|
||||
)
|
||||
{}
|
||||
}
|
||||
|
||||
class Request
|
||||
{
|
||||
constructor(public type: string, public req: RequestData)
|
||||
constructor(
|
||||
public type: string,
|
||||
public req: RequestData,
|
||||
)
|
||||
{}
|
||||
}
|
||||
|
||||
class Response
|
||||
{
|
||||
constructor(public type: string, public response: any)
|
||||
constructor(
|
||||
public type: string,
|
||||
public response: any,
|
||||
)
|
||||
{}
|
||||
}
|
||||
|
@ -99,7 +99,10 @@ export class BotEquipmentFilterService
|
||||
* @param equipmentChanges Changes to apply
|
||||
* @param baseValues data to update
|
||||
*/
|
||||
protected adjustChances(equipmentChanges: Record<string, number>, baseValues: EquipmentChances | ModsChances): void
|
||||
protected adjustChances(
|
||||
equipmentChanges: Record<string, number>,
|
||||
baseValues: EquipmentChances | ModsChances,
|
||||
): void
|
||||
{
|
||||
if (!equipmentChanges)
|
||||
{
|
||||
@ -173,15 +176,16 @@ export class BotEquipmentFilterService
|
||||
|
||||
// No equipment blacklist found, skip
|
||||
if (
|
||||
!blacklistDetailsForBot || Object.keys(blacklistDetailsForBot).length === 0
|
||||
!blacklistDetailsForBot
|
||||
|| Object.keys(blacklistDetailsForBot).length === 0
|
||||
|| !blacklistDetailsForBot.blacklist
|
||||
)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return blacklistDetailsForBot.blacklist.find(x =>
|
||||
playerLevel >= x.levelRange.min && playerLevel <= x.levelRange.max,
|
||||
return blacklistDetailsForBot.blacklist.find(
|
||||
(x) => playerLevel >= x.levelRange.min && playerLevel <= x.levelRange.max,
|
||||
);
|
||||
}
|
||||
|
||||
@ -201,8 +205,8 @@ export class BotEquipmentFilterService
|
||||
return null;
|
||||
}
|
||||
|
||||
return botEquipmentConfig.whitelist.find(x =>
|
||||
playerLevel >= x.levelRange.min && playerLevel <= x.levelRange.max,
|
||||
return botEquipmentConfig.whitelist.find(
|
||||
(x) => playerLevel >= x.levelRange.min && playerLevel <= x.levelRange.max,
|
||||
);
|
||||
}
|
||||
|
||||
@ -218,15 +222,16 @@ export class BotEquipmentFilterService
|
||||
|
||||
// No config found, skip
|
||||
if (
|
||||
!botEquipmentConfig || Object.keys(botEquipmentConfig).length === 0
|
||||
!botEquipmentConfig
|
||||
|| Object.keys(botEquipmentConfig).length === 0
|
||||
|| !botEquipmentConfig.weightingAdjustmentsByBotLevel
|
||||
)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return botEquipmentConfig.weightingAdjustmentsByBotLevel.find(x =>
|
||||
botLevel >= x.levelRange.min && botLevel <= x.levelRange.max,
|
||||
return botEquipmentConfig.weightingAdjustmentsByBotLevel.find(
|
||||
(x) => botLevel >= x.levelRange.min && botLevel <= x.levelRange.max,
|
||||
);
|
||||
}
|
||||
|
||||
@ -236,21 +241,25 @@ export class BotEquipmentFilterService
|
||||
* @param playerlevel Level of bot
|
||||
* @returns Weighting adjustments for bot items
|
||||
*/
|
||||
protected getBotWeightingAdjustmentsByPlayerLevel(botRole: string, playerlevel: number): WeightingAdjustmentDetails
|
||||
protected getBotWeightingAdjustmentsByPlayerLevel(
|
||||
botRole: string,
|
||||
playerlevel: number,
|
||||
): WeightingAdjustmentDetails
|
||||
{
|
||||
const botEquipmentConfig = this.botEquipmentConfig[botRole];
|
||||
|
||||
// No config found, skip
|
||||
if (
|
||||
!botEquipmentConfig || Object.keys(botEquipmentConfig).length === 0
|
||||
!botEquipmentConfig
|
||||
|| Object.keys(botEquipmentConfig).length === 0
|
||||
|| !botEquipmentConfig.weightingAdjustmentsByPlayerLevel
|
||||
)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return botEquipmentConfig.weightingAdjustmentsByPlayerLevel.find(x =>
|
||||
playerlevel >= x.levelRange.min && playerlevel <= x.levelRange.max,
|
||||
return botEquipmentConfig.weightingAdjustmentsByPlayerLevel.find(
|
||||
(x) => playerlevel >= x.levelRange.min && playerlevel <= x.levelRange.max,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ export class BotEquipmentModPoolService
|
||||
}
|
||||
|
||||
// only add item to pool if it doesnt already exist
|
||||
if (!pool[item._id][slot._name].some(x => x === itemToAdd))
|
||||
if (!pool[item._id][slot._name].some((x) => x === itemToAdd))
|
||||
{
|
||||
pool[item._id][slot._name].push(itemToAdd);
|
||||
|
||||
@ -185,8 +185,8 @@ export class BotEquipmentModPoolService
|
||||
*/
|
||||
protected generateWeaponPool(): void
|
||||
{
|
||||
const weapons = Object.values(this.databaseServer.getTables().templates.items).filter(x =>
|
||||
x._type === "Item" && this.itemHelper.isOfBaseclass(x._id, BaseClasses.WEAPON),
|
||||
const weapons = Object.values(this.databaseServer.getTables().templates.items).filter(
|
||||
(x) => x._type === "Item" && this.itemHelper.isOfBaseclass(x._id, BaseClasses.WEAPON),
|
||||
);
|
||||
this.generatePool(weapons, "weapon");
|
||||
|
||||
@ -199,14 +199,15 @@ export class BotEquipmentModPoolService
|
||||
*/
|
||||
protected generateGearPool(): void
|
||||
{
|
||||
const gear = Object.values(this.databaseServer.getTables().templates.items).filter(x =>
|
||||
x._type === "Item"
|
||||
&& this.itemHelper.isOfBaseclasses(x._id, [
|
||||
BaseClasses.ARMORED_EQUIPMENT,
|
||||
BaseClasses.VEST,
|
||||
BaseClasses.ARMOR,
|
||||
BaseClasses.HEADWEAR,
|
||||
]),
|
||||
const gear = Object.values(this.databaseServer.getTables().templates.items).filter(
|
||||
(x) =>
|
||||
x._type === "Item"
|
||||
&& this.itemHelper.isOfBaseclasses(x._id, [
|
||||
BaseClasses.ARMORED_EQUIPMENT,
|
||||
BaseClasses.VEST,
|
||||
BaseClasses.ARMOR,
|
||||
BaseClasses.HEADWEAR,
|
||||
]),
|
||||
);
|
||||
this.generatePool(gear, "gear");
|
||||
|
||||
|
@ -79,7 +79,7 @@ export class BotGenerationCacheService
|
||||
*/
|
||||
public getUsedBot(profileId: string): IBotBase
|
||||
{
|
||||
return this.activeBotsInRaid.find(x => x._id === profileId);
|
||||
return this.activeBotsInRaid.find((x) => x._id === profileId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,7 +90,7 @@ export class BotWeaponModLimitService
|
||||
{
|
||||
// If weapon already has a longer ranged scope on it, allow ncstar to be spawned
|
||||
if (
|
||||
weapon.some(x =>
|
||||
weapon.some((x) =>
|
||||
this.itemHelper.isOfBaseclasses(x._tpl, [
|
||||
BaseClasses.ASSAULT_SCOPE,
|
||||
BaseClasses.OPTIC_SCOPE,
|
||||
@ -121,7 +121,7 @@ export class BotWeaponModLimitService
|
||||
// Mod is a mount that can hold only scopes and limit is reached (dont want to add empty mounts if limit is reached)
|
||||
if (
|
||||
this.itemHelper.isOfBaseclass(modTemplate._id, BaseClasses.MOUNT)
|
||||
&& modTemplate._props.Slots.some(x => x._name === "mod_scope")
|
||||
&& modTemplate._props.Slots.some((x) => x._name === "mod_scope")
|
||||
&& modTemplate._props.Slots.length === 1
|
||||
&& modLimits.scope.count >= modLimits.scopeMax
|
||||
)
|
||||
@ -144,7 +144,7 @@ export class BotWeaponModLimitService
|
||||
// Mod is a mount that can hold only flashlights ad limit is reached (dont want to add empty mounts if limit is reached)
|
||||
if (
|
||||
this.itemHelper.isOfBaseclass(modTemplate._id, BaseClasses.MOUNT)
|
||||
&& modTemplate._props.Slots.some(x => x._name === "mod_flashlight")
|
||||
&& modTemplate._props.Slots.some((x) => x._name === "mod_flashlight")
|
||||
&& modTemplate._props.Slots.length === 1
|
||||
&& modLimits.scope.count >= modLimits.scopeMax
|
||||
)
|
||||
|
@ -73,7 +73,7 @@ export class CustomLocationWaveService
|
||||
const location: ILocationBase = this.databaseServer.getTables().locations[mapKey].base;
|
||||
for (const bossWave of bossWavesToApply[mapKey])
|
||||
{
|
||||
if (location.BossLocationSpawn.find(x => x.sptId === bossWave.sptId))
|
||||
if (location.BossLocationSpawn.find((x) => x.sptId === bossWave.sptId))
|
||||
{
|
||||
// Already exists, skip
|
||||
continue;
|
||||
@ -90,7 +90,7 @@ export class CustomLocationWaveService
|
||||
const location: ILocationBase = this.databaseServer.getTables().locations[mapKey].base;
|
||||
for (const normalWave of normalWavesToApply[mapKey])
|
||||
{
|
||||
if (location.waves.find(x => x.sptId === normalWave.sptId))
|
||||
if (location.waves.find((x) => x.sptId === normalWave.sptId))
|
||||
{
|
||||
// Already exists, skip
|
||||
continue;
|
||||
|
@ -388,23 +388,28 @@ export class FenceService
|
||||
* @param newFenceAssorts Assorts to fold into existing fence assorts
|
||||
* @param existingFenceAssorts Current fence assorts new assorts will be added to
|
||||
*/
|
||||
protected updateFenceAssorts(newFenceAssorts: ICreateFenceAssortsResult, existingFenceAssorts: ITraderAssort): void
|
||||
protected updateFenceAssorts(
|
||||
newFenceAssorts: ICreateFenceAssortsResult,
|
||||
existingFenceAssorts: ITraderAssort,
|
||||
): void
|
||||
{
|
||||
for (const itemWithChildren of newFenceAssorts.sptItems)
|
||||
{
|
||||
// Find the root item
|
||||
const newRootItem = itemWithChildren.find(item => item.slotId === "hideout");
|
||||
const newRootItem = itemWithChildren.find((item) => item.slotId === "hideout");
|
||||
if (!newRootItem)
|
||||
{
|
||||
const firstItem = itemWithChildren.find(x => x);
|
||||
this.logger.error(`Unable to process fence assort as root item is missing, ${firstItem?._tpl}, skipping`);
|
||||
const firstItem = itemWithChildren.find((x) => x);
|
||||
this.logger.error(
|
||||
`Unable to process fence assort as root item is missing, ${firstItem?._tpl}, skipping`,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find a matching root item with same tpl in existing assort
|
||||
const existingRootItem = existingFenceAssorts.items.find(item =>
|
||||
item._tpl === newRootItem._tpl && item.slotId === "hideout",
|
||||
const existingRootItem = existingFenceAssorts.items.find(
|
||||
(item) => item._tpl === newRootItem._tpl && item.slotId === "hideout",
|
||||
);
|
||||
|
||||
// Check if same type of item exists + its on list of item types to always stack
|
||||
@ -453,8 +458,8 @@ export class FenceService
|
||||
*/
|
||||
protected incrementPartialRefreshTime(): void
|
||||
{
|
||||
this.nextPartialRefreshTimestamp = this.timeUtil.getTimestamp()
|
||||
+ this.traderConfig.fence.partialRefreshTimeSeconds;
|
||||
this.nextPartialRefreshTimestamp
|
||||
= this.timeUtil.getTimestamp() + this.traderConfig.fence.partialRefreshTimeSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -468,8 +473,8 @@ export class FenceService
|
||||
generationValues: IGenerationAssortValues,
|
||||
): IGenerationAssortValues
|
||||
{
|
||||
const allRootItems = assortItems.filter(item => item.slotId === "hideout");
|
||||
const rootPresetItems = allRootItems.filter(item => item?.upd?.sptPresetId);
|
||||
const allRootItems = assortItems.filter((item) => item.slotId === "hideout");
|
||||
const rootPresetItems = allRootItems.filter((item) => item?.upd?.sptPresetId);
|
||||
|
||||
// Get count of weapons
|
||||
const currentWeaponPresetCount = rootPresetItems.reduce((count, item) =>
|
||||
@ -507,7 +512,7 @@ export class FenceService
|
||||
{
|
||||
if (assort?.items?.length > 0)
|
||||
{
|
||||
const rootItems = assort.items.filter(item => item.slotId === "hideout");
|
||||
const rootItems = assort.items.filter((item) => item.slotId === "hideout");
|
||||
for (let index = 0; index < itemCountToReplace; index++)
|
||||
{
|
||||
this.removeRandomItemFromAssorts(assort, rootItems);
|
||||
@ -735,8 +740,8 @@ export class FenceService
|
||||
): void
|
||||
{
|
||||
const priceLimits = this.traderConfig.fence.itemCategoryRoublePriceLimit;
|
||||
const assortRootItems = baseFenceAssortClone.items.filter(item =>
|
||||
item.parentId === "hideout" && !item.upd?.sptPresetId,
|
||||
const assortRootItems = baseFenceAssortClone.items.filter(
|
||||
(item) => item.parentId === "hideout" && !item.upd?.sptPresetId,
|
||||
);
|
||||
|
||||
for (let i = 0; i < assortCount; i++)
|
||||
@ -806,7 +811,8 @@ export class FenceService
|
||||
const existingItemThatMatches = this.getMatchingItem(rootItemBeingAdded, itemDbDetails, assorts.sptItems);
|
||||
const shouldBeStacked = this.itemShouldBeForceStacked(existingItemThatMatches, itemDbDetails);
|
||||
if (shouldBeStacked && existingItemThatMatches)
|
||||
{ // Decrement loop counter so another items gets added
|
||||
{
|
||||
// Decrement loop counter so another items gets added
|
||||
i--;
|
||||
existingItemThatMatches.upd.StackObjectsCount++;
|
||||
|
||||
@ -843,12 +849,18 @@ export class FenceService
|
||||
* @param itemsWithChildren Items to search through
|
||||
* @returns Matching assort item
|
||||
*/
|
||||
protected getMatchingItem(rootItemBeingAdded: Item, itemDbDetails: ITemplateItem, itemsWithChildren: Item[][]): Item
|
||||
protected getMatchingItem(
|
||||
rootItemBeingAdded: Item,
|
||||
itemDbDetails: ITemplateItem,
|
||||
itemsWithChildren: Item[][],
|
||||
): Item
|
||||
{
|
||||
// Get matching root items
|
||||
const matchingItems = itemsWithChildren.filter(itemWithChildren =>
|
||||
itemWithChildren.find(item => item._tpl === rootItemBeingAdded._tpl && item.parentId === "hideout"),
|
||||
).flatMap(x => x);
|
||||
const matchingItems = itemsWithChildren
|
||||
.filter((itemWithChildren) =>
|
||||
itemWithChildren.find((item) => item._tpl === rootItemBeingAdded._tpl && item.parentId === "hideout"),
|
||||
)
|
||||
.flatMap((x) => x);
|
||||
if (matchingItems.length === 0)
|
||||
{
|
||||
// Nothing matches by tpl and is root item, exit early
|
||||
@ -998,8 +1010,8 @@ export class FenceService
|
||||
let weaponPresetsAddedCount = 0;
|
||||
if (desiredWeaponPresetsCount > 0)
|
||||
{
|
||||
const weaponPresetRootItems = baseFenceAssort.items.filter(item =>
|
||||
item.upd?.sptPresetId && this.itemHelper.isOfBaseclass(item._tpl, BaseClasses.WEAPON),
|
||||
const weaponPresetRootItems = baseFenceAssort.items.filter(
|
||||
(item) => item.upd?.sptPresetId && this.itemHelper.isOfBaseclass(item._tpl, BaseClasses.WEAPON),
|
||||
);
|
||||
while (weaponPresetsAddedCount < desiredWeaponPresetsCount)
|
||||
{
|
||||
@ -1021,8 +1033,9 @@ export class FenceService
|
||||
|
||||
// Check chosen item is below price cap
|
||||
const priceLimitRouble = this.traderConfig.fence.itemCategoryRoublePriceLimit[rootItemDb._parent];
|
||||
const itemPrice = this.handbookHelper.getTemplatePriceForItems(presetWithChildrenClone)
|
||||
* this.itemHelper.getItemQualityModifierForOfferItems(presetWithChildrenClone);
|
||||
const itemPrice
|
||||
= this.handbookHelper.getTemplatePriceForItems(presetWithChildrenClone)
|
||||
* this.itemHelper.getItemQualityModifierForOfferItems(presetWithChildrenClone);
|
||||
if (priceLimitRouble)
|
||||
{
|
||||
if (itemPrice > priceLimitRouble)
|
||||
@ -1043,10 +1056,14 @@ export class FenceService
|
||||
|
||||
// Set assort price
|
||||
// Must be careful to use correct id as the item has had its IDs regenerated
|
||||
assorts.barter_scheme[presetWithChildrenClone[0]._id] = [[{
|
||||
_tpl: "5449016a4bdc2d6f028b456f",
|
||||
count: Math.round(itemPrice),
|
||||
}]];
|
||||
assorts.barter_scheme[presetWithChildrenClone[0]._id] = [
|
||||
[
|
||||
{
|
||||
_tpl: "5449016a4bdc2d6f028b456f",
|
||||
count: Math.round(itemPrice),
|
||||
},
|
||||
],
|
||||
];
|
||||
assorts.loyal_level_items[presetWithChildrenClone[0]._id] = loyaltyLevel;
|
||||
|
||||
weaponPresetsAddedCount++;
|
||||
@ -1059,8 +1076,8 @@ export class FenceService
|
||||
return;
|
||||
}
|
||||
|
||||
const equipmentPresetRootItems = baseFenceAssort.items.filter(item =>
|
||||
item.upd?.sptPresetId && this.itemHelper.armorItemCanHoldMods(item._tpl),
|
||||
const equipmentPresetRootItems = baseFenceAssort.items.filter(
|
||||
(item) => item.upd?.sptPresetId && this.itemHelper.armorItemCanHoldMods(item._tpl),
|
||||
);
|
||||
while (equipmentPresetsAddedCount < desiredEquipmentPresetsCount)
|
||||
{
|
||||
@ -1081,8 +1098,9 @@ export class FenceService
|
||||
|
||||
// Check chosen item is below price cap
|
||||
const priceLimitRouble = this.traderConfig.fence.itemCategoryRoublePriceLimit[rootItemDb._parent];
|
||||
const itemPrice = this.handbookHelper.getTemplatePriceForItems(presetWithChildrenClone)
|
||||
* this.itemHelper.getItemQualityModifierForOfferItems(presetWithChildrenClone);
|
||||
const itemPrice
|
||||
= this.handbookHelper.getTemplatePriceForItems(presetWithChildrenClone)
|
||||
* this.itemHelper.getItemQualityModifierForOfferItems(presetWithChildrenClone);
|
||||
if (priceLimitRouble)
|
||||
{
|
||||
if (itemPrice > priceLimitRouble)
|
||||
@ -1103,10 +1121,14 @@ export class FenceService
|
||||
|
||||
// Set assort price
|
||||
// Must be careful to use correct id as the item has had its IDs regenerated
|
||||
assorts.barter_scheme[presetWithChildrenClone[0]._id] = [[{
|
||||
_tpl: "5449016a4bdc2d6f028b456f",
|
||||
count: Math.round(itemPrice),
|
||||
}]];
|
||||
assorts.barter_scheme[presetWithChildrenClone[0]._id] = [
|
||||
[
|
||||
{
|
||||
_tpl: "5449016a4bdc2d6f028b456f",
|
||||
count: Math.round(itemPrice),
|
||||
},
|
||||
],
|
||||
];
|
||||
assorts.loyal_level_items[presetWithChildrenClone[0]._id] = loyaltyLevel;
|
||||
|
||||
equipmentPresetsAddedCount++;
|
||||
@ -1128,7 +1150,7 @@ export class FenceService
|
||||
}
|
||||
|
||||
// Check for and adjust soft insert durability values
|
||||
const requiredSlots = itemDbDetails._props.Slots.filter(slot => slot._required);
|
||||
const requiredSlots = itemDbDetails._props.Slots.filter((slot) => slot._required);
|
||||
const hasRequiredSlots = requiredSlots.length > 0;
|
||||
if (hasRequiredSlots)
|
||||
{
|
||||
@ -1147,8 +1169,8 @@ export class FenceService
|
||||
}
|
||||
|
||||
// Find items mod to apply dura changes to
|
||||
const modItemToAdjust = armor.find(mod =>
|
||||
mod.slotId.toLowerCase() === requiredSlot._name.toLowerCase(),
|
||||
const modItemToAdjust = armor.find(
|
||||
(mod) => mod.slotId.toLowerCase() === requiredSlot._name.toLowerCase(),
|
||||
);
|
||||
|
||||
this.itemHelper.addUpdObjectToItem(modItemToAdjust);
|
||||
@ -1170,14 +1192,15 @@ export class FenceService
|
||||
&& modItemToAdjust.slotId === "mod_equipment_000"
|
||||
&& modItemToAdjust.upd.Repairable.Durability < modItemDbDetails._props.MaxDurability
|
||||
)
|
||||
{ // Is damaged
|
||||
{
|
||||
// Is damaged
|
||||
modItemToAdjust.upd.FaceShield = { Hits: this.randomUtil.getInt(1, 3) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for and adjust plate durability values
|
||||
const plateSlots = itemDbDetails._props.Slots.filter(slot =>
|
||||
const plateSlots = itemDbDetails._props.Slots.filter((slot) =>
|
||||
this.itemHelper.isRemovablePlateSlot(slot._name),
|
||||
);
|
||||
if (plateSlots.length > 0)
|
||||
@ -1203,7 +1226,7 @@ export class FenceService
|
||||
);
|
||||
|
||||
// Find items mod to apply dura changes to
|
||||
const modItemToAdjust = armor.find(mod => mod.slotId.toLowerCase() === plateSlot._name.toLowerCase());
|
||||
const modItemToAdjust = armor.find((mod) => mod.slotId.toLowerCase() === plateSlot._name.toLowerCase());
|
||||
this.itemHelper.addUpdObjectToItem(modItemToAdjust);
|
||||
|
||||
if (!modItemToAdjust.upd.Repairable)
|
||||
@ -1341,7 +1364,8 @@ export class FenceService
|
||||
if (
|
||||
(itemDetails._parent === BaseClasses.ARMORED_EQUIPMENT
|
||||
|| itemDetails._parent === BaseClasses.FACECOVER
|
||||
|| itemDetails._parent === BaseClasses.ARMOR_PLATE) && itemDetails._props.MaxDurability > 0
|
||||
|| itemDetails._parent === BaseClasses.ARMOR_PLATE)
|
||||
&& itemDetails._props.MaxDurability > 0
|
||||
)
|
||||
{
|
||||
const values = this.getRandomisedArmorDurabilityValues(
|
||||
@ -1357,12 +1381,12 @@ export class FenceService
|
||||
if (this.itemHelper.isOfBaseclass(itemDetails._id, BaseClasses.WEAPON))
|
||||
{
|
||||
const weaponDurabilityLimits = this.traderConfig.fence.weaponDurabilityPercentMinMax;
|
||||
const maxDuraMin = weaponDurabilityLimits.max.min / 100 * itemDetails._props.MaxDurability;
|
||||
const maxDuraMax = weaponDurabilityLimits.max.max / 100 * itemDetails._props.MaxDurability;
|
||||
const maxDuraMin = (weaponDurabilityLimits.max.min / 100) * itemDetails._props.MaxDurability;
|
||||
const maxDuraMax = (weaponDurabilityLimits.max.max / 100) * itemDetails._props.MaxDurability;
|
||||
const chosenMaxDurability = this.randomUtil.getInt(maxDuraMin, maxDuraMax);
|
||||
|
||||
const currentDuraMin = weaponDurabilityLimits.current.min / 100 * itemDetails._props.MaxDurability;
|
||||
const currentDuraMax = weaponDurabilityLimits.current.max / 100 * itemDetails._props.MaxDurability;
|
||||
const currentDuraMin = (weaponDurabilityLimits.current.min / 100) * itemDetails._props.MaxDurability;
|
||||
const currentDuraMax = (weaponDurabilityLimits.current.max / 100) * itemDetails._props.MaxDurability;
|
||||
const currentDurability = Math.min(
|
||||
this.randomUtil.getInt(currentDuraMin, currentDuraMax),
|
||||
chosenMaxDurability,
|
||||
@ -1414,12 +1438,12 @@ export class FenceService
|
||||
equipmentDurabilityLimits: IItemDurabilityCurrentMax,
|
||||
): Repairable
|
||||
{
|
||||
const maxDuraMin = equipmentDurabilityLimits.max.min / 100 * itemDetails._props.MaxDurability;
|
||||
const maxDuraMax = equipmentDurabilityLimits.max.max / 100 * itemDetails._props.MaxDurability;
|
||||
const maxDuraMin = (equipmentDurabilityLimits.max.min / 100) * itemDetails._props.MaxDurability;
|
||||
const maxDuraMax = (equipmentDurabilityLimits.max.max / 100) * itemDetails._props.MaxDurability;
|
||||
const chosenMaxDurability = this.randomUtil.getInt(maxDuraMin, maxDuraMax);
|
||||
|
||||
const currentDuraMin = equipmentDurabilityLimits.current.min / 100 * itemDetails._props.MaxDurability;
|
||||
const currentDuraMax = equipmentDurabilityLimits.current.max / 100 * itemDetails._props.MaxDurability;
|
||||
const currentDuraMin = (equipmentDurabilityLimits.current.min / 100) * itemDetails._props.MaxDurability;
|
||||
const currentDuraMax = (equipmentDurabilityLimits.current.max / 100) * itemDetails._props.MaxDurability;
|
||||
const chosenCurrentDurability = Math.min(
|
||||
this.randomUtil.getInt(currentDuraMin, currentDuraMax),
|
||||
chosenMaxDurability,
|
||||
@ -1462,7 +1486,7 @@ export class FenceService
|
||||
*/
|
||||
protected getFenceRefreshTime(): number
|
||||
{
|
||||
const fence = this.traderConfig.updateTime.find(x => x.traderId === Traders.FENCE).seconds;
|
||||
const fence = this.traderConfig.updateTime.find((x) => x.traderId === Traders.FENCE).seconds;
|
||||
|
||||
return this.randomUtil.getInt(fence.min, fence.max);
|
||||
}
|
||||
@ -1482,7 +1506,7 @@ export class FenceService
|
||||
return fenceSettings.Levels["0"];
|
||||
}
|
||||
|
||||
const fenceLevels = Object.keys(fenceSettings.Levels).map(value => Number.parseInt(value));
|
||||
const fenceLevels = Object.keys(fenceSettings.Levels).map((value) => Number.parseInt(value));
|
||||
const minLevel = Math.min(...fenceLevels);
|
||||
const maxLevel = Math.max(...fenceLevels);
|
||||
const pmcFenceLevel = Math.floor(pmcFenceInfo.standing);
|
||||
@ -1508,11 +1532,11 @@ export class FenceService
|
||||
public amendOrRemoveFenceOffer(assortId: string, buyCount: number): void
|
||||
{
|
||||
let isNormalAssort = true;
|
||||
let fenceAssortItem = this.fenceAssort.items.find(item => item._id === assortId);
|
||||
let fenceAssortItem = this.fenceAssort.items.find((item) => item._id === assortId);
|
||||
if (!fenceAssortItem)
|
||||
{
|
||||
// Not in main assorts, check secondary section
|
||||
fenceAssortItem = this.fenceDiscountAssort.items.find(item => item._id === assortId);
|
||||
fenceAssortItem = this.fenceDiscountAssort.items.find((item) => item._id === assortId);
|
||||
if (!fenceAssortItem)
|
||||
{
|
||||
this.logger.error(`Offer with id: ${assortId} not found`);
|
||||
@ -1540,12 +1564,12 @@ export class FenceService
|
||||
const itemWithChildrenToRemove = this.itemHelper.findAndReturnChildrenAsItems(assorts, assortId);
|
||||
for (const itemToRemove of itemWithChildrenToRemove)
|
||||
{
|
||||
let indexToRemove = assorts.findIndex(item => item._id === itemToRemove._id);
|
||||
let indexToRemove = assorts.findIndex((item) => item._id === itemToRemove._id);
|
||||
|
||||
// No offer found in main assort, check discount items
|
||||
if (indexToRemove === -1)
|
||||
{
|
||||
indexToRemove = this.fenceDiscountAssort.items.findIndex(item => item._id === itemToRemove._id);
|
||||
indexToRemove = this.fenceDiscountAssort.items.findIndex((item) => item._id === itemToRemove._id);
|
||||
this.fenceDiscountAssort.items.splice(indexToRemove, 1);
|
||||
|
||||
if (indexToRemove === -1)
|
||||
|
@ -120,7 +120,9 @@ export class InsuranceService
|
||||
MessageType.NPC_TRADER,
|
||||
this.randomUtil.getArrayValue(dialogueTemplates.insuranceStart),
|
||||
null,
|
||||
this.timeUtil.getHoursAsSeconds(this.databaseServer.getTables().globals.config.Insurance.MaxStorageTimeInHour),
|
||||
this.timeUtil.getHoursAsSeconds(
|
||||
this.databaseServer.getTables().globals.config.Insurance.MaxStorageTimeInHour,
|
||||
),
|
||||
systemData,
|
||||
);
|
||||
|
||||
@ -151,7 +153,7 @@ export class InsuranceService
|
||||
for (const insuredItem of this.getInsurance(sessionId)[traderId])
|
||||
{
|
||||
// Find insured items parent
|
||||
const insuredItemsParent = insuredItems.find(x => x._id === insuredItem.parentId);
|
||||
const insuredItemsParent = insuredItems.find((x) => x._id === insuredItem.parentId);
|
||||
if (!insuredItemsParent)
|
||||
{
|
||||
// Remove location + set slotId of insured items parent
|
||||
@ -179,9 +181,9 @@ export class InsuranceService
|
||||
return this.timeUtil.getTimestamp() + this.insuranceConfig.returnTimeOverrideSeconds;
|
||||
}
|
||||
|
||||
const insuranceReturnTimeBonus = pmcData.Bonuses.find(b => b.type === BonusType.INSURANCE_RETURN_TIME);
|
||||
const insuranceReturnTimeBonusPercent = 1.0
|
||||
- (insuranceReturnTimeBonus ? Math.abs(insuranceReturnTimeBonus.value) : 0) / 100;
|
||||
const insuranceReturnTimeBonus = pmcData.Bonuses.find((b) => b.type === BonusType.INSURANCE_RETURN_TIME);
|
||||
const insuranceReturnTimeBonusPercent
|
||||
= 1.0 - (insuranceReturnTimeBonus ? Math.abs(insuranceReturnTimeBonus.value) : 0) / 100;
|
||||
|
||||
const traderMinReturnAsSeconds = trader.insurance.min_return_hour * TimeUtil.ONE_HOUR_AS_SECONDS;
|
||||
const traderMaxReturnAsSeconds = trader.insurance.max_return_hour * TimeUtil.ONE_HOUR_AS_SECONDS;
|
||||
@ -256,7 +258,7 @@ export class InsuranceService
|
||||
itemToReturnToPlayer: this.getInsuredItemDetails(
|
||||
pmcData,
|
||||
preRaidItem,
|
||||
offraidData.insurance?.find(insuranceItem => insuranceItem.id === insuredItem.itemId),
|
||||
offraidData.insurance?.find((insuranceItem) => insuranceItem.id === insuredItem.itemId),
|
||||
),
|
||||
traderId: insuredItem.tid,
|
||||
sessionID: sessionID,
|
||||
@ -268,10 +270,13 @@ export class InsuranceService
|
||||
if (this.itemHelper.itemHasSlots(preRaidItem._tpl))
|
||||
{
|
||||
// Get IDs of all soft insert child items on armor from pre raid gear data
|
||||
const softInsertChildIds = preRaidGear.filter(item =>
|
||||
item.parentId === preRaidItem._id
|
||||
&& this.itemHelper.getSoftInsertSlotIds().includes(item.slotId.toLowerCase()),
|
||||
).map(x => x._id);
|
||||
const softInsertChildIds = preRaidGear
|
||||
.filter(
|
||||
(item) =>
|
||||
item.parentId === preRaidItem._id
|
||||
&& this.itemHelper.getSoftInsertSlotIds().includes(item.slotId.toLowerCase()),
|
||||
)
|
||||
.map((x) => x._id);
|
||||
|
||||
// Add all items found above to return data
|
||||
for (const softInsertChildModId of softInsertChildIds)
|
||||
@ -280,9 +285,9 @@ export class InsuranceService
|
||||
pmcData: pmcData,
|
||||
itemToReturnToPlayer: this.getInsuredItemDetails(
|
||||
pmcData,
|
||||
preRaidGear.find(item => item._id === softInsertChildModId),
|
||||
offraidData.insurance?.find(insuranceItem =>
|
||||
insuranceItem.id === softInsertChildModId,
|
||||
preRaidGear.find((item) => item._id === softInsertChildModId),
|
||||
offraidData.insurance?.find(
|
||||
(insuranceItem) => insuranceItem.id === softInsertChildModId,
|
||||
),
|
||||
),
|
||||
traderId: insuredItem.tid,
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
||||
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
|
||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
||||
@ -39,7 +38,7 @@ export class ItemBaseClassService
|
||||
return;
|
||||
}
|
||||
|
||||
const filteredDbItems = Object.values(this.items).filter(x => x._type === "Item");
|
||||
const filteredDbItems = Object.values(this.items).filter((x) => x._type === "Item");
|
||||
for (const item of filteredDbItems)
|
||||
{
|
||||
const itemIdToUpdate = item._id;
|
||||
@ -111,7 +110,7 @@ export class ItemBaseClassService
|
||||
}
|
||||
}
|
||||
|
||||
return this.itemBaseClassesCache[itemTpl].some(x => baseClasses.includes(x));
|
||||
return this.itemBaseClassesCache[itemTpl].some((x) => baseClasses.includes(x));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,6 @@
|
||||
import path from "node:path";
|
||||
import { I18n } from "i18n";
|
||||
import { inject, injectable } from "tsyringe";
|
||||
import { ILocaleConfig } from "@spt-aki/models/spt/config/ILocaleConfig";
|
||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||
import { LocaleService } from "@spt-aki/services/LocaleService";
|
||||
@ -66,7 +65,7 @@ export class LocalisationService
|
||||
*/
|
||||
public getRandomTextThatMatchesPartialKey(partialKey: string): string
|
||||
{
|
||||
const filteredKeys = Object.keys(this.databaseServer.getTables().locales.server.en).filter(x =>
|
||||
const filteredKeys = Object.keys(this.databaseServer.getTables().locales.server.en).filter((x) =>
|
||||
x.startsWith(partialKey),
|
||||
);
|
||||
const chosenKey = this.randomUtil.getArrayValue(filteredKeys);
|
||||
|
@ -365,9 +365,8 @@ export class MailSendService
|
||||
hasRewards: false, // The default dialog message has no rewards, can be added later via addRewardItemsToMessage()
|
||||
rewardCollected: false, // The default dialog message has no rewards, can be added later via addRewardItemsToMessage()
|
||||
systemData: messageDetails.systemData ? messageDetails.systemData : undefined, // Used by ragfair / localised messages that need "location" or "time"
|
||||
profileChangeEvents: messageDetails.profileChangeEvents?.length === 0
|
||||
? messageDetails.profileChangeEvents
|
||||
: undefined, // no one knows, its never been used in any dumps
|
||||
profileChangeEvents:
|
||||
messageDetails.profileChangeEvents?.length === 0 ? messageDetails.profileChangeEvents : undefined, // no one knows, its never been used in any dumps
|
||||
};
|
||||
|
||||
// Clean up empty system data
|
||||
@ -412,7 +411,10 @@ export class MailSendService
|
||||
* @param messageDetails
|
||||
* @returns Sanitised items
|
||||
*/
|
||||
protected processItemsBeforeAddingToMail(dialogType: MessageType, messageDetails: ISendMessageDetails): MessageItems
|
||||
protected processItemsBeforeAddingToMail(
|
||||
dialogType: MessageType,
|
||||
messageDetails: ISendMessageDetails,
|
||||
): MessageItems
|
||||
{
|
||||
const db = this.databaseServer.getTables().templates.items;
|
||||
|
||||
@ -512,7 +514,7 @@ export class MailSendService
|
||||
}
|
||||
|
||||
// Find first item with slotId that indicates its a 'base' item
|
||||
let item = items.find(x => ["hideout", "main"].includes(x.slotId));
|
||||
let item = items.find((x) => ["hideout", "main"].includes(x.slotId));
|
||||
if (item)
|
||||
{
|
||||
return item;
|
||||
@ -520,7 +522,7 @@ export class MailSendService
|
||||
|
||||
// Not a singlular item + no items have a hideout/main slotid
|
||||
// Look for first item without parent id
|
||||
item = items.find(x => !x.parentId);
|
||||
item = items.find((x) => !x.parentId);
|
||||
if (item)
|
||||
{
|
||||
return item;
|
||||
|
@ -58,7 +58,7 @@ export class PaymentService
|
||||
for (const index in request.scheme_items)
|
||||
{
|
||||
// Find the corresponding item in the player's inventory.
|
||||
const item = pmcData.Inventory.items.find(i => i._id === request.scheme_items[index].id);
|
||||
const item = pmcData.Inventory.items.find((i) => i._id === request.scheme_items[index].id);
|
||||
if (item !== undefined)
|
||||
{
|
||||
if (!this.paymentHelper.isMoneyTpl(item._tpl))
|
||||
@ -396,7 +396,7 @@ export class PaymentService
|
||||
*/
|
||||
protected isInStash(itemId: string, inventoryItems: Item[], playerStashId: string): boolean
|
||||
{
|
||||
const itemParent = inventoryItems.find(x => x._id === itemId);
|
||||
const itemParent = inventoryItems.find((x) => x._id === itemId);
|
||||
|
||||
if (itemParent)
|
||||
{
|
||||
|
@ -229,7 +229,7 @@ export class PmcChatResponseService
|
||||
const keyBase = isVictim ? "pmcresponse-victim_" : "pmcresponse-killer_";
|
||||
const keys = this.localisationService.getKeys();
|
||||
|
||||
return keys.filter(x => x.startsWith(`${keyBase}${keyType}`));
|
||||
return keys.filter((x) => x.startsWith(`${keyBase}${keyType}`));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -240,7 +240,7 @@ export class PmcChatResponseService
|
||||
{
|
||||
const keys = this.localisationService.getKeys();
|
||||
|
||||
return keys.filter(x => x.startsWith("pmcresponse-suffix"));
|
||||
return keys.filter((x) => x.startsWith("pmcresponse-suffix"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,10 +87,10 @@ export class ProfileFixerService
|
||||
this.reorderHideoutAreasWithResouceInputs(pmcProfile);
|
||||
|
||||
if (
|
||||
pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.GENERATOR).slots.length
|
||||
pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.GENERATOR).slots.length
|
||||
< 6
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.Generator.Slots
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.Generator
|
||||
.Slots
|
||||
)
|
||||
{
|
||||
this.logger.debug("Updating generator area slots to a size of 6 + hideout management skill");
|
||||
@ -104,7 +104,7 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
if (
|
||||
pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WATER_COLLECTOR).slots.length
|
||||
pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WATER_COLLECTOR).slots.length
|
||||
< 1
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.WaterCollector.Slots
|
||||
@ -121,7 +121,7 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
if (
|
||||
pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.AIR_FILTERING).slots.length
|
||||
pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.AIR_FILTERING).slots.length
|
||||
< 3
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.AirFilteringUnit.Slots
|
||||
@ -139,7 +139,7 @@ export class ProfileFixerService
|
||||
|
||||
// BTC Farm doesnt have extra slots for hideout management, but we still check for modded stuff!!
|
||||
if (
|
||||
pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.BITCOIN_FARM).slots.length
|
||||
pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.BITCOIN_FARM).slots.length
|
||||
< 50
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.BitcoinFarm.Slots
|
||||
@ -172,7 +172,7 @@ export class ProfileFixerService
|
||||
|
||||
protected addMissingGunStandContainerImprovements(pmcProfile: IPmcData): void
|
||||
{
|
||||
const weaponStandArea = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WEAPON_STAND);
|
||||
const weaponStandArea = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WEAPON_STAND);
|
||||
if (!weaponStandArea || weaponStandArea.level === 0)
|
||||
{
|
||||
// No stand in profile or its level 0, skip
|
||||
@ -180,8 +180,8 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
const db = this.databaseServer.getTables();
|
||||
const hideoutStandAreaDb = db.hideout.areas.find(x => x.type === HideoutAreas.WEAPON_STAND);
|
||||
const hideoutStandSecondaryAreaDb = db.hideout.areas.find(x => x.parentArea === hideoutStandAreaDb._id);
|
||||
const hideoutStandAreaDb = db.hideout.areas.find((x) => x.type === HideoutAreas.WEAPON_STAND);
|
||||
const hideoutStandSecondaryAreaDb = db.hideout.areas.find((x) => x.parentArea === hideoutStandAreaDb._id);
|
||||
const stageCurrentAt = hideoutStandAreaDb.stages[weaponStandArea.level];
|
||||
const hideoutStandStashId = pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.WEAPON_STAND];
|
||||
const hideoutSecondaryStashId = pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.WEAPON_STAND_SECONDARY];
|
||||
@ -195,7 +195,7 @@ export class ProfileFixerService
|
||||
= hideoutStandSecondaryAreaDb._id;
|
||||
|
||||
// Add stash item to profile
|
||||
const gunStandStashItem = pmcProfile.Inventory.items.find(x => x._id === hideoutStandAreaDb._id);
|
||||
const gunStandStashItem = pmcProfile.Inventory.items.find((x) => x._id === hideoutStandAreaDb._id);
|
||||
if (gunStandStashItem)
|
||||
{
|
||||
gunStandStashItem._tpl = stageCurrentAt.container;
|
||||
@ -212,8 +212,8 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
// Add secondary stash item to profile
|
||||
const gunStandStashSecondaryItem = pmcProfile.Inventory.items.find(x =>
|
||||
x._id === hideoutStandSecondaryAreaDb._id,
|
||||
const gunStandStashSecondaryItem = pmcProfile.Inventory.items.find(
|
||||
(x) => x._id === hideoutStandSecondaryAreaDb._id,
|
||||
);
|
||||
if (gunStandStashItem)
|
||||
{
|
||||
@ -236,12 +236,12 @@ export class ProfileFixerService
|
||||
return;
|
||||
}
|
||||
|
||||
let stashItem = pmcProfile.Inventory.items?.find(x => x._id === hideoutStandAreaDb._id);
|
||||
let stashItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandAreaDb._id);
|
||||
if (!stashItem)
|
||||
{
|
||||
// Stand inventory stash item doesnt exist, add it
|
||||
pmcProfile.Inventory.items.push({ _id: hideoutStandAreaDb._id, _tpl: stageCurrentAt.container });
|
||||
stashItem = pmcProfile.Inventory.items?.find(x => x._id === hideoutStandAreaDb._id);
|
||||
stashItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandAreaDb._id);
|
||||
}
|
||||
|
||||
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
||||
@ -254,12 +254,12 @@ export class ProfileFixerService
|
||||
stashItem._tpl = stageCurrentAt.container;
|
||||
}
|
||||
|
||||
let stashSecondaryItem = pmcProfile.Inventory.items?.find(x => x._id === hideoutStandSecondaryAreaDb._id);
|
||||
let stashSecondaryItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandSecondaryAreaDb._id);
|
||||
if (!stashSecondaryItem)
|
||||
{
|
||||
// Stand inventory stash item doesnt exist, add it
|
||||
pmcProfile.Inventory.items.push({ _id: hideoutStandSecondaryAreaDb._id, _tpl: stageCurrentAt.container });
|
||||
stashSecondaryItem = pmcProfile.Inventory.items?.find(x => x._id === hideoutStandSecondaryAreaDb._id);
|
||||
stashSecondaryItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandSecondaryAreaDb._id);
|
||||
}
|
||||
|
||||
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
||||
@ -275,7 +275,7 @@ export class ProfileFixerService
|
||||
|
||||
protected addMissingHallOfFameContainerImprovements(pmcProfile: IPmcData): void
|
||||
{
|
||||
const placeOfFameArea = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.PLACE_OF_FAME);
|
||||
const placeOfFameArea = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.PLACE_OF_FAME);
|
||||
if (!placeOfFameArea || placeOfFameArea.level === 0)
|
||||
{
|
||||
// No place of fame in profile or its level 0, skip
|
||||
@ -283,7 +283,7 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
const db = this.databaseServer.getTables();
|
||||
const placeOfFameAreaDb = db.hideout.areas.find(area => area.type === HideoutAreas.PLACE_OF_FAME);
|
||||
const placeOfFameAreaDb = db.hideout.areas.find((area) => area.type === HideoutAreas.PLACE_OF_FAME);
|
||||
if (!placeOfFameAreaDb)
|
||||
{
|
||||
return;
|
||||
@ -298,7 +298,7 @@ export class ProfileFixerService
|
||||
pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.PLACE_OF_FAME] = placeOfFameAreaDb._id;
|
||||
|
||||
// Add stash item to profile
|
||||
const placeOfFameStashItem = pmcProfile.Inventory.items.find(x => x._id === placeOfFameAreaDb._id);
|
||||
const placeOfFameStashItem = pmcProfile.Inventory.items.find((x) => x._id === placeOfFameAreaDb._id);
|
||||
if (placeOfFameStashItem)
|
||||
{
|
||||
placeOfFameStashItem._tpl = stageCurrentlyAt.container;
|
||||
@ -317,12 +317,12 @@ export class ProfileFixerService
|
||||
return;
|
||||
}
|
||||
|
||||
let stashItem = pmcProfile.Inventory.items?.find(x => x._id === placeOfFameAreaDb._id);
|
||||
let stashItem = pmcProfile.Inventory.items?.find((x) => x._id === placeOfFameAreaDb._id);
|
||||
if (!stashItem)
|
||||
{
|
||||
// Stand inventory stash item doesnt exist, add it
|
||||
pmcProfile.Inventory.items.push({ _id: placeOfFameAreaDb._id, _tpl: stageCurrentlyAt.container });
|
||||
stashItem = pmcProfile.Inventory.items?.find(x => x._id === placeOfFameAreaDb._id);
|
||||
stashItem = pmcProfile.Inventory.items?.find((x) => x._id === placeOfFameAreaDb._id);
|
||||
}
|
||||
|
||||
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
||||
@ -339,10 +339,10 @@ export class ProfileFixerService
|
||||
protected ensureGunStandLevelsMatch(pmcProfile: IPmcData): void
|
||||
{
|
||||
// only proceed if stand is level 1 or above
|
||||
const gunStandParent = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WEAPON_STAND);
|
||||
const gunStandParent = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WEAPON_STAND);
|
||||
if (gunStandParent && gunStandParent.level > 0)
|
||||
{
|
||||
const gunStandChild = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WEAPON_STAND_SECONDARY);
|
||||
const gunStandChild = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WEAPON_STAND_SECONDARY);
|
||||
if (gunStandChild && gunStandParent.level !== gunStandChild.level)
|
||||
{
|
||||
this.logger.success("Upgraded gun stand levels to match");
|
||||
@ -362,7 +362,7 @@ export class ProfileFixerService
|
||||
|
||||
protected addMissingHideoutWallAreas(pmcProfile: IPmcData): void
|
||||
{
|
||||
if (!pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WEAPON_STAND))
|
||||
if (!pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WEAPON_STAND))
|
||||
{
|
||||
pmcProfile.Hideout.Areas.push({
|
||||
type: 24,
|
||||
@ -376,7 +376,7 @@ export class ProfileFixerService
|
||||
});
|
||||
}
|
||||
|
||||
if (!pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.WEAPON_STAND_SECONDARY))
|
||||
if (!pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WEAPON_STAND_SECONDARY))
|
||||
{
|
||||
pmcProfile.Hideout.Areas.push({
|
||||
type: 25,
|
||||
@ -473,14 +473,14 @@ export class ProfileFixerService
|
||||
// Only check if profile has repeatable quests
|
||||
if (pmcProfile.RepeatableQuests && activeRepeatableQuests.length > 0)
|
||||
{
|
||||
const existsInActiveRepeatableQuests = activeRepeatableQuests.some(quest =>
|
||||
quest._id === taskConditionCounter.sourceId,
|
||||
const existsInActiveRepeatableQuests = activeRepeatableQuests.some(
|
||||
(quest) => quest._id === taskConditionCounter.sourceId,
|
||||
);
|
||||
const existsInQuests = pmcProfile.Quests.some(quest =>
|
||||
quest.qid === taskConditionCounter.sourceId,
|
||||
const existsInQuests = pmcProfile.Quests.some(
|
||||
(quest) => quest.qid === taskConditionCounter.sourceId,
|
||||
);
|
||||
const isAchievementTracker = achievements.some(quest =>
|
||||
quest.id === taskConditionCounter.sourceId,
|
||||
const isAchievementTracker = achievements.some(
|
||||
(quest) => quest.id === taskConditionCounter.sourceId,
|
||||
);
|
||||
|
||||
// If task conditions id is neither in activeQuests, quests or achievements - it's stale and should be cleaned up
|
||||
@ -565,12 +565,12 @@ export class ProfileFixerService
|
||||
continue;
|
||||
}
|
||||
|
||||
if (quest.status && Number.isNaN(Number.parseInt(<string><unknown>quest.status)))
|
||||
if (quest.status && Number.isNaN(Number.parseInt(<string>(<unknown>quest.status))))
|
||||
{
|
||||
fixes[quest.status] = (fixes[quest.status] ?? 0) + 1;
|
||||
|
||||
const newQuestStatus = QuestStatus[quest.status];
|
||||
quest.status = <QuestStatus><unknown>newQuestStatus;
|
||||
quest.status = <QuestStatus>(<unknown>newQuestStatus);
|
||||
}
|
||||
|
||||
for (const statusTimer in quest.statusTimers)
|
||||
@ -594,16 +594,18 @@ export class ProfileFixerService
|
||||
if (Object.keys(fixes).length > 0)
|
||||
{
|
||||
this.logger.debug(
|
||||
`Updated quests values: ${Object.entries(fixes).map(([k, v]) => `(${k}: ${v} times)`).join(", ")}`,
|
||||
`Updated quests values: ${Object.entries(fixes)
|
||||
.map(([k, v]) => `(${k}: ${v} times)`)
|
||||
.join(", ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (Object.keys(timerFixes).length > 0)
|
||||
{
|
||||
this.logger.debug(
|
||||
`Updated statusTimers values: ${
|
||||
Object.entries(timerFixes).map(([k, v]) => `(${k}: ${v} times)`).join(", ")
|
||||
}`,
|
||||
`Updated statusTimers values: ${Object.entries(timerFixes)
|
||||
.map(([k, v]) => `(${k}: ${v} times)`)
|
||||
.join(", ")}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -616,8 +618,12 @@ export class ProfileFixerService
|
||||
for (const currentRepeatable of pmcProfile.RepeatableQuests)
|
||||
{
|
||||
if (
|
||||
!(currentRepeatable.changeRequirement
|
||||
&& currentRepeatable.activeQuests.every(x => typeof x.changeCost !== "undefined" && typeof x.changeStandingCost !== "undefined"))
|
||||
!(
|
||||
currentRepeatable.changeRequirement
|
||||
&& currentRepeatable.activeQuests.every(
|
||||
(x) => typeof x.changeCost !== "undefined" && typeof x.changeStandingCost !== "undefined",
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
repeatablesCompatible = false;
|
||||
@ -642,10 +648,10 @@ export class ProfileFixerService
|
||||
*/
|
||||
protected addMissingWallImprovements(pmcProfile: IPmcData): void
|
||||
{
|
||||
const profileWallArea = pmcProfile.Hideout.Areas.find(x => x.type === HideoutAreas.EMERGENCY_WALL);
|
||||
const wallDb = this.databaseServer.getTables().hideout.areas.find(x =>
|
||||
x.type === HideoutAreas.EMERGENCY_WALL,
|
||||
);
|
||||
const profileWallArea = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.EMERGENCY_WALL);
|
||||
const wallDb = this.databaseServer
|
||||
.getTables()
|
||||
.hideout.areas.find((x) => x.type === HideoutAreas.EMERGENCY_WALL);
|
||||
|
||||
if (profileWallArea.level > 0)
|
||||
{
|
||||
@ -693,13 +699,13 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
// Only slots with location index
|
||||
area.slots = area.slots.filter(x => "locationIndex" in x);
|
||||
area.slots = area.slots.filter((x) => "locationIndex" in x);
|
||||
|
||||
// Only slots that:
|
||||
// Have an item property and it has at least one item in it
|
||||
// Or
|
||||
// Have no item property
|
||||
area.slots = area.slots.filter(x => ("item" in x && x.item?.length > 0) || !("item" in x));
|
||||
area.slots = area.slots.filter((x) => ("item" in x && x.item?.length > 0) || !("item" in x));
|
||||
}
|
||||
}
|
||||
|
||||
@ -718,7 +724,7 @@ export class ProfileFixerService
|
||||
|
||||
for (const areaId of areasToCheck)
|
||||
{
|
||||
const area = pmcProfile.Hideout.Areas.find(area => area.type === areaId);
|
||||
const area = pmcProfile.Hideout.Areas.find((area) => area.type === areaId);
|
||||
if (!area)
|
||||
{
|
||||
this.logger.debug(`unable to sort: ${area.type} (${areaId}) slots, no area found`);
|
||||
@ -749,7 +755,7 @@ export class ProfileFixerService
|
||||
pmcProfile: IPmcData,
|
||||
): void
|
||||
{
|
||||
const area = pmcProfile.Hideout.Areas.find(x => x.type === areaType);
|
||||
const area = pmcProfile.Hideout.Areas.find((x) => x.type === areaType);
|
||||
area.slots = this.addObjectsToArray(emptyItemCount, area.slots);
|
||||
}
|
||||
|
||||
@ -757,7 +763,7 @@ export class ProfileFixerService
|
||||
{
|
||||
for (let i = 0; i < count; i++)
|
||||
{
|
||||
if (!slots.find(x => x.locationIndex === i))
|
||||
if (!slots.find((x) => x.locationIndex === i))
|
||||
{
|
||||
slots.push({ locationIndex: i });
|
||||
}
|
||||
@ -795,7 +801,7 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
// Iterate over area levels, check for bonuses, add if needed
|
||||
const dbArea = dbHideoutAreas.find(x => x.type === areaType);
|
||||
const dbArea = dbHideoutAreas.find((x) => x.type === areaType);
|
||||
if (!dbArea)
|
||||
{
|
||||
continue;
|
||||
@ -840,22 +846,22 @@ export class ProfileFixerService
|
||||
// match by id first, used by "TextBonus" bonuses
|
||||
if (bonus.id)
|
||||
{
|
||||
return profileBonuses.find(x => x.id === bonus.id);
|
||||
return profileBonuses.find((x) => x.id === bonus.id);
|
||||
}
|
||||
|
||||
if (bonus.type === BonusType.STASH_SIZE)
|
||||
{
|
||||
return profileBonuses.find(x => x.type === bonus.type && x.templateId === bonus.templateId);
|
||||
return profileBonuses.find((x) => x.type === bonus.type && x.templateId === bonus.templateId);
|
||||
}
|
||||
|
||||
if (bonus.type === BonusType.ADDITIONAL_SLOTS)
|
||||
{
|
||||
return profileBonuses.find(x =>
|
||||
x.type === bonus.type && x.value === bonus.value && x.visible === bonus.visible,
|
||||
return profileBonuses.find(
|
||||
(x) => x.type === bonus.type && x.value === bonus.value && x.visible === bonus.visible,
|
||||
);
|
||||
}
|
||||
|
||||
return profileBonuses.find(x => x.type === bonus.type && x.value === bonus.value);
|
||||
return profileBonuses.find((x) => x.type === bonus.type && x.value === bonus.value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -870,7 +876,7 @@ export class ProfileFixerService
|
||||
|
||||
// Get items placed in root of stash
|
||||
// TODO: extend to other areas / sub items
|
||||
const inventoryItemsToCheck = pmcProfile.Inventory.items.filter(item =>
|
||||
const inventoryItemsToCheck = pmcProfile.Inventory.items.filter((item) =>
|
||||
["hideout", "main"].includes(item.slotId),
|
||||
);
|
||||
if (inventoryItemsToCheck)
|
||||
@ -952,7 +958,10 @@ export class ProfileFixerService
|
||||
|
||||
if (this.coreConfig.fixes.removeModItemsFromProfile)
|
||||
{
|
||||
dialog.messages.splice(dialog.messages.findIndex(x => x._id === message._id), 1);
|
||||
dialog.messages.splice(
|
||||
dialog.messages.findIndex((x) => x._id === message._id),
|
||||
1,
|
||||
);
|
||||
this.logger.warning(
|
||||
`Item: ${item._tpl} has resulted in the deletion of message: ${message._id} from dialog ${dialogId}`,
|
||||
);
|
||||
@ -991,7 +1000,7 @@ export class ProfileFixerService
|
||||
`Non-default quest: ${activeQuest._id} from trader: ${activeQuest.traderId} removed from RepeatableQuests list in profile`,
|
||||
);
|
||||
repeatable.activeQuests.splice(
|
||||
repeatable.activeQuests.findIndex(x => x._id === activeQuest._id),
|
||||
repeatable.activeQuests.findIndex((x) => x._id === activeQuest._id),
|
||||
1,
|
||||
);
|
||||
}
|
||||
@ -1016,7 +1025,7 @@ export class ProfileFixerService
|
||||
`Non-default quest: ${activeQuest._id} from trader: ${activeQuest.traderId} removed from RepeatableQuests list in profile`,
|
||||
);
|
||||
repeatable.activeQuests.splice(
|
||||
repeatable.activeQuests.findIndex(x => x._id === activeQuest._id),
|
||||
repeatable.activeQuests.findIndex((x) => x._id === activeQuest._id),
|
||||
1,
|
||||
);
|
||||
}
|
||||
@ -1081,7 +1090,10 @@ export class ProfileFixerService
|
||||
* @param itemsDb The items database to use for item lookup
|
||||
* @returns True if the build should be removed from the build list, false otherwise
|
||||
*/
|
||||
protected shouldRemoveMagazineBuild(magazineBuild: IMagazineBuild, itemsDb: Record<string, ITemplateItem>): boolean
|
||||
protected shouldRemoveMagazineBuild(
|
||||
magazineBuild: IMagazineBuild,
|
||||
itemsDb: Record<string, ITemplateItem>,
|
||||
): boolean
|
||||
{
|
||||
for (const item of magazineBuild.Items)
|
||||
{
|
||||
@ -1141,7 +1153,7 @@ export class ProfileFixerService
|
||||
if (itemAJson === itemBJson)
|
||||
{
|
||||
// Both items match, we can safely delete one
|
||||
const indexOfItemToRemove = pmcProfile.Inventory.items.findIndex(x => x._id === key);
|
||||
const indexOfItemToRemove = pmcProfile.Inventory.items.findIndex((x) => x._id === key);
|
||||
pmcProfile.Inventory.items.splice(indexOfItemToRemove, 1);
|
||||
this.logger.warning(`Deleted duplicate item: ${key}`);
|
||||
}
|
||||
@ -1149,10 +1161,10 @@ export class ProfileFixerService
|
||||
{
|
||||
// Items are different, replace ID with unique value
|
||||
// Only replace ID if items have no children, we dont want orphaned children
|
||||
const itemsHaveChildren = pmcProfile.Inventory.items.some(x => x.parentId === key);
|
||||
const itemsHaveChildren = pmcProfile.Inventory.items.some((x) => x.parentId === key);
|
||||
if (!itemsHaveChildren)
|
||||
{
|
||||
const itemToAdjustId = pmcProfile.Inventory.items.find(x => x._id === key);
|
||||
const itemToAdjustId = pmcProfile.Inventory.items.find((x) => x._id === key);
|
||||
itemToAdjustId._id = this.hashUtil.generate();
|
||||
this.logger.warning(`Replace duplicate item Id: ${key} with ${itemToAdjustId._id}`);
|
||||
}
|
||||
@ -1160,7 +1172,7 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
// Iterate over all inventory items
|
||||
for (const item of pmcProfile.Inventory.items.filter(x => x.slotId))
|
||||
for (const item of pmcProfile.Inventory.items.filter((x) => x.slotId))
|
||||
{
|
||||
if (!item.upd)
|
||||
{
|
||||
@ -1193,35 +1205,38 @@ export class ProfileFixerService
|
||||
if (!customizationDb[pmcProfile.Customization.Head])
|
||||
{
|
||||
const defaultHead = playerIsUsec
|
||||
? customizationDbArray.find(x => x._name === "DefaultUsecHead")
|
||||
: customizationDbArray.find(x => x._name === "DefaultBearHead");
|
||||
? customizationDbArray.find((x) => x._name === "DefaultUsecHead")
|
||||
: customizationDbArray.find((x) => x._name === "DefaultBearHead");
|
||||
pmcProfile.Customization.Head = defaultHead._id;
|
||||
}
|
||||
|
||||
// check Body
|
||||
if (!customizationDb[pmcProfile.Customization.Body])
|
||||
{
|
||||
const defaultBody = pmcProfile.Info.Side.toLowerCase() === "usec"
|
||||
? customizationDbArray.find(x => x._name === "DefaultUsecBody")
|
||||
: customizationDbArray.find(x => x._name === "DefaultBearBody");
|
||||
const defaultBody
|
||||
= pmcProfile.Info.Side.toLowerCase() === "usec"
|
||||
? customizationDbArray.find((x) => x._name === "DefaultUsecBody")
|
||||
: customizationDbArray.find((x) => x._name === "DefaultBearBody");
|
||||
pmcProfile.Customization.Body = defaultBody._id;
|
||||
}
|
||||
|
||||
// check Hands
|
||||
if (!customizationDb[pmcProfile.Customization.Hands])
|
||||
{
|
||||
const defaultHands = pmcProfile.Info.Side.toLowerCase() === "usec"
|
||||
? customizationDbArray.find(x => x._name === "DefaultUsecHands")
|
||||
: customizationDbArray.find(x => x._name === "DefaultBearHands");
|
||||
const defaultHands
|
||||
= pmcProfile.Info.Side.toLowerCase() === "usec"
|
||||
? customizationDbArray.find((x) => x._name === "DefaultUsecHands")
|
||||
: customizationDbArray.find((x) => x._name === "DefaultBearHands");
|
||||
pmcProfile.Customization.Hands = defaultHands._id;
|
||||
}
|
||||
|
||||
// check Hands
|
||||
if (!customizationDb[pmcProfile.Customization.Feet])
|
||||
{
|
||||
const defaultFeet = pmcProfile.Info.Side.toLowerCase() === "usec"
|
||||
? customizationDbArray.find(x => x._name === "DefaultUsecFeet")
|
||||
: customizationDbArray.find(x => x._name === "DefaultBearFeet");
|
||||
const defaultFeet
|
||||
= pmcProfile.Info.Side.toLowerCase() === "usec"
|
||||
? customizationDbArray.find((x) => x._name === "DefaultUsecFeet")
|
||||
: customizationDbArray.find((x) => x._name === "DefaultBearFeet");
|
||||
pmcProfile.Customization.Feet = defaultFeet._id;
|
||||
}
|
||||
}
|
||||
@ -1266,7 +1281,7 @@ export class ProfileFixerService
|
||||
// Get all areas from templates/profiles.json
|
||||
for (const area of profileTemplate.character.Hideout.Areas)
|
||||
{
|
||||
if (!pmcProfile.Hideout.Areas.find(x => x.type === area.type))
|
||||
if (!pmcProfile.Hideout.Areas.find((x) => x.type === area.type))
|
||||
{
|
||||
pmcProfile.Hideout.Areas.push(area);
|
||||
this.logger.debug(`Added missing hideout area ${area.type} to profile`);
|
||||
@ -1300,10 +1315,10 @@ export class ProfileFixerService
|
||||
// biome-ignore lint/suspicious/noGlobalIsNan: <value can be a valid string, Number.IsNaN() would ignore it>
|
||||
if (isNaN(fullProfile.characters.pmc.aid) || !fullProfile.info.aid)
|
||||
{
|
||||
fullProfile.characters.pmc.sessionId = <string><unknown>fullProfile.characters.pmc.aid;
|
||||
fullProfile.characters.pmc.sessionId = <string>(<unknown>fullProfile.characters.pmc.aid);
|
||||
fullProfile.characters.pmc.aid = this.hashUtil.generateAccountId();
|
||||
|
||||
fullProfile.characters.scav.sessionId = <string><unknown>fullProfile.characters.pmc.sessionId;
|
||||
fullProfile.characters.scav.sessionId = <string>(<unknown>fullProfile.characters.pmc.sessionId);
|
||||
fullProfile.characters.scav.aid = fullProfile.characters.pmc.aid;
|
||||
|
||||
fullProfile.info.aid = fullProfile.characters.pmc.aid;
|
||||
@ -1329,7 +1344,7 @@ export class ProfileFixerService
|
||||
// Clear stats object
|
||||
fullProfile.characters.pmc.Stats = { Eft: null };
|
||||
|
||||
fullProfile.characters.pmc.Stats.Eft = <any><unknown>statsCopy;
|
||||
fullProfile.characters.pmc.Stats.Eft = <any>(<unknown>statsCopy);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1355,8 +1370,8 @@ export class ProfileFixerService
|
||||
for (const stageIndex in area.stages)
|
||||
{
|
||||
const stageInfo = area.stages[stageIndex];
|
||||
const matchingBonus = stageInfo.bonuses.find(x =>
|
||||
x.templateId === bonus.templateId && x.type === bonus.type,
|
||||
const matchingBonus = stageInfo.bonuses.find(
|
||||
(x) => x.templateId === bonus.templateId && x.type === bonus.type,
|
||||
);
|
||||
if (matchingBonus)
|
||||
{
|
||||
@ -1425,7 +1440,7 @@ export class ProfileFixerService
|
||||
|
||||
for (let i = profileQuests.length - 1; i >= 0; i--)
|
||||
{
|
||||
if (!(quests[profileQuests[i].qid] || repeatableQuests.find(x => x._id === profileQuests[i].qid)))
|
||||
if (!(quests[profileQuests[i].qid] || repeatableQuests.find((x) => x._id === profileQuests[i].qid)))
|
||||
{
|
||||
profileQuests.splice(i, 1);
|
||||
this.logger.success("Successfully removed orphaned quest that doesnt exist in our quest data");
|
||||
|
@ -28,46 +28,48 @@ export class RagfairCategoriesService
|
||||
): Record<string, number>
|
||||
{
|
||||
// Get offers valid for search request, then reduce them down to just the counts
|
||||
return offers.filter((offer) =>
|
||||
{
|
||||
const isTraderOffer = offer.user.memberType === MemberCategory.TRADER;
|
||||
|
||||
// Not level 15 and offer is from player, skip
|
||||
if (!(fleaUnlocked || isTraderOffer))
|
||||
return offers
|
||||
.filter((offer) =>
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const isTraderOffer = offer.user.memberType === MemberCategory.TRADER;
|
||||
|
||||
// Remove items not for money when `removeBartering` is enabled
|
||||
if (
|
||||
searchRequestData.removeBartering
|
||||
&& (offer.requirements.length > 1 || !this.paymentHelper.isMoneyTpl(offer.requirements[0]._tpl))
|
||||
)
|
||||
// Not level 15 and offer is from player, skip
|
||||
if (!(fleaUnlocked || isTraderOffer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove items not for money when `removeBartering` is enabled
|
||||
if (
|
||||
searchRequestData.removeBartering
|
||||
&& (offer.requirements.length > 1 || !this.paymentHelper.isMoneyTpl(offer.requirements[0]._tpl))
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove when filter set to players only + offer is from trader
|
||||
if (searchRequestData.offerOwnerType === OfferOwnerType.PLAYEROWNERTYPE && isTraderOffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove when filter set to traders only + offer is not from trader
|
||||
if (searchRequestData.offerOwnerType === OfferOwnerType.TRADEROWNERTYPE && !isTraderOffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Passed checks, its a valid offer to process
|
||||
return true;
|
||||
})
|
||||
.reduce((acc, offer) =>
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const itemTpl = offer.items[0]._tpl;
|
||||
// Increment the category or add if doesnt exist
|
||||
acc[itemTpl] = (acc[itemTpl] || 0) + 1;
|
||||
|
||||
// Remove when filter set to players only + offer is from trader
|
||||
if (searchRequestData.offerOwnerType === OfferOwnerType.PLAYEROWNERTYPE && isTraderOffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove when filter set to traders only + offer is not from trader
|
||||
if (searchRequestData.offerOwnerType === OfferOwnerType.TRADEROWNERTYPE && !isTraderOffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Passed checks, its a valid offer to process
|
||||
return true;
|
||||
}).reduce((acc, offer) =>
|
||||
{
|
||||
const itemTpl = offer.items[0]._tpl;
|
||||
// Increment the category or add if doesnt exist
|
||||
acc[itemTpl] = (acc[itemTpl] || 0) + 1;
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ export class RagfairLinkedItemService
|
||||
applyLinkedItems: (items: string[]) => void,
|
||||
): void
|
||||
{
|
||||
const cylinderMod = cylinder._props.Slots.find(x => x._name === "mod_magazine");
|
||||
const cylinderMod = cylinder._props.Slots.find((x) => x._name === "mod_magazine");
|
||||
if (cylinderMod)
|
||||
{
|
||||
// Get the first cylinder filter tpl
|
||||
|
@ -2,7 +2,6 @@ import { inject, injectable } from "tsyringe";
|
||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||
import { RagfairServerHelper } from "@spt-aki/helpers/RagfairServerHelper";
|
||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||
import { IRagfairOffer } from "@spt-aki/models/eft/ragfair/IRagfairOffer";
|
||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||
import { IRagfairConfig } from "@spt-aki/models/spt/config/IRagfairConfig";
|
||||
@ -251,7 +250,7 @@ export class RagfairOfferService
|
||||
const pmcId = String(playerOffer.user.id);
|
||||
const profile = this.profileHelper.getProfileByPmcId(pmcId);
|
||||
|
||||
const offerinProfileIndex = profile.RagfairInfo.offers.findIndex(o => o._id === playerOffer._id);
|
||||
const offerinProfileIndex = profile.RagfairInfo.offers.findIndex((o) => o._id === playerOffer._id);
|
||||
if (offerinProfileIndex === -1)
|
||||
{
|
||||
this.logger.warning(
|
||||
|
@ -73,11 +73,9 @@ export class RagfairPriceService implements OnLoad
|
||||
*/
|
||||
public generateStaticPrices(): void
|
||||
{
|
||||
for (
|
||||
const item of Object.values(this.databaseServer.getTables().templates.items).filter(x =>
|
||||
x._type === "Item",
|
||||
)
|
||||
)
|
||||
for (const item of Object.values(this.databaseServer.getTables().templates.items).filter(
|
||||
(x) => x._type === "Item",
|
||||
))
|
||||
{
|
||||
this.prices.static[item._id] = Math.round(this.handbookHelper.getTemplatePrice(item._id));
|
||||
}
|
||||
@ -195,7 +193,7 @@ export class RagfairPriceService implements OnLoad
|
||||
*/
|
||||
protected getPriceDifference(a: number, b: number): number
|
||||
{
|
||||
return 100 * a / (a + b);
|
||||
return (100 * a) / (a + b);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -239,7 +237,10 @@ export class RagfairPriceService implements OnLoad
|
||||
price += this.getDynamicItemPrice(item._tpl, desiredCurrency, item, offerItems, isPackOffer);
|
||||
|
||||
// Check if the item is a weapon preset.
|
||||
if (item?.upd?.sptPresetId && this.presetHelper.isPresetBaseClass(item.upd.sptPresetId, BaseClasses.WEAPON))
|
||||
if (
|
||||
item?.upd?.sptPresetId
|
||||
&& this.presetHelper.isPresetBaseClass(item.upd.sptPresetId, BaseClasses.WEAPON)
|
||||
)
|
||||
{
|
||||
// This is a weapon preset, which has it's own price calculation that takes into account the mods in the
|
||||
// preset. Since we've already calculated the price for the preset entire preset in
|
||||
@ -365,7 +366,7 @@ export class RagfairPriceService implements OnLoad
|
||||
price: number,
|
||||
): number
|
||||
{
|
||||
const itemHandbookPrice = handbookPrices.find(handbookItem => handbookItem.Id === itemTpl);
|
||||
const itemHandbookPrice = handbookPrices.find((handbookItem) => handbookItem.Id === itemTpl);
|
||||
if (!itemHandbookPrice)
|
||||
{
|
||||
return price;
|
||||
@ -423,7 +424,8 @@ export class RagfairPriceService implements OnLoad
|
||||
|
||||
// Only adjust price if difference is > a percent AND item price passes threshold set in config
|
||||
if (
|
||||
priceDifferencePercent > this.ragfairConfig.dynamic.offerAdjustment.maxPriceDifferenceBelowHandbookPercent
|
||||
priceDifferencePercent
|
||||
> this.ragfairConfig.dynamic.offerAdjustment.maxPriceDifferenceBelowHandbookPercent
|
||||
&& itemPrice >= this.ragfairConfig.dynamic.offerAdjustment.priceThreshholdRub
|
||||
)
|
||||
{
|
||||
@ -467,8 +469,8 @@ export class RagfairPriceService implements OnLoad
|
||||
}
|
||||
|
||||
// Get mods on current gun not in default preset
|
||||
const newOrReplacedModsInPresetVsDefault = weaponWithChildren.filter(x =>
|
||||
!presetResult.preset._items.some(y => y._tpl === x._tpl),
|
||||
const newOrReplacedModsInPresetVsDefault = weaponWithChildren.filter(
|
||||
(x) => !presetResult.preset._items.some((y) => y._tpl === x._tpl),
|
||||
);
|
||||
|
||||
// Add up extra mods price
|
||||
@ -483,8 +485,8 @@ export class RagfairPriceService implements OnLoad
|
||||
if (newOrReplacedModsInPresetVsDefault.length >= 1)
|
||||
{
|
||||
// Add up cost of mods replaced
|
||||
const modsReplacedByNewMods = newOrReplacedModsInPresetVsDefault.filter(x =>
|
||||
presetResult.preset._items.some(y => y.slotId === x.slotId),
|
||||
const modsReplacedByNewMods = newOrReplacedModsInPresetVsDefault.filter((x) =>
|
||||
presetResult.preset._items.some((y) => y.slotId === x.slotId),
|
||||
);
|
||||
|
||||
// Add up replaced mods price
|
||||
@ -536,17 +538,13 @@ export class RagfairPriceService implements OnLoad
|
||||
if (nonDefaultPresets.length === 1)
|
||||
{
|
||||
this.logger.debug(
|
||||
`Item Id: ${weapon._tpl} has no default encyclopedia entry but only one preset (${
|
||||
nonDefaultPresets[0]._name
|
||||
}), choosing preset (${nonDefaultPresets[0]._name})`,
|
||||
`Item Id: ${weapon._tpl} has no default encyclopedia entry but only one preset (${nonDefaultPresets[0]._name}), choosing preset (${nonDefaultPresets[0]._name})`,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.logger.debug(
|
||||
`Item Id: ${weapon._tpl} has no default encyclopedia entry, choosing first preset (${
|
||||
nonDefaultPresets[0]._name
|
||||
}) of ${nonDefaultPresets.length}`,
|
||||
`Item Id: ${weapon._tpl} has no default encyclopedia entry, choosing first preset (${nonDefaultPresets[0]._name}) of ${nonDefaultPresets.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -70,8 +70,8 @@ export class RagfairTaxService
|
||||
const requirementsPrice = requirementsValue * (sellInOnePiece ? 1 : offerItemCount);
|
||||
|
||||
const itemTaxMult = this.databaseServer.getTables().globals.config.RagFair.communityItemTax / 100.0;
|
||||
const requirementTaxMult = this.databaseServer.getTables().globals.config.RagFair.communityRequirementTax
|
||||
/ 100.0;
|
||||
const requirementTaxMult
|
||||
= this.databaseServer.getTables().globals.config.RagFair.communityRequirementTax / 100.0;
|
||||
|
||||
let itemPriceMult = Math.log10(itemWorth / requirementsPrice);
|
||||
let requirementPriceMult = Math.log10(requirementsPrice / itemWorth);
|
||||
@ -88,11 +88,11 @@ export class RagfairTaxService
|
||||
itemPriceMult = 4 ** itemPriceMult;
|
||||
requirementPriceMult = 4 ** requirementPriceMult;
|
||||
|
||||
const hideoutFleaTaxDiscountBonus = pmcData.Bonuses.find(b => b.type === BonusType.RAGFAIR_COMMISSION);
|
||||
const hideoutFleaTaxDiscountBonus = pmcData.Bonuses.find((b) => b.type === BonusType.RAGFAIR_COMMISSION);
|
||||
const taxDiscountPercent = hideoutFleaTaxDiscountBonus ? Math.abs(hideoutFleaTaxDiscountBonus.value) : 0;
|
||||
|
||||
const tax = itemWorth * itemTaxMult * itemPriceMult
|
||||
+ requirementsPrice * requirementTaxMult * requirementPriceMult;
|
||||
const tax
|
||||
= itemWorth * itemTaxMult * itemPriceMult + requirementsPrice * requirementTaxMult * requirementPriceMult;
|
||||
const discountedTax = tax * (1.0 - taxDiscountPercent / 100.0);
|
||||
const itemComissionMult = itemTemplate._props.RagFairCommissionModifier
|
||||
? itemTemplate._props.RagFairCommissionModifier
|
||||
@ -123,7 +123,8 @@ export class RagfairTaxService
|
||||
|
||||
// In client, all item slots are traversed and any items contained within have their values added
|
||||
if (isRootItem)
|
||||
{ // Since we get a flat list of all child items, we only want to recurse from parent item
|
||||
{
|
||||
// Since we get a flat list of all child items, we only want to recurse from parent item
|
||||
const itemChildren = this.itemHelper.findAndReturnChildrenAsItems(pmcData.Inventory.items, item._id);
|
||||
if (itemChildren.length > 1)
|
||||
{
|
||||
@ -152,38 +153,40 @@ export class RagfairTaxService
|
||||
|
||||
if ("Key" in item.upd && itemTemplate._props.MaximumNumberOfUsage > 0)
|
||||
{
|
||||
worth = worth / itemTemplate._props.MaximumNumberOfUsage
|
||||
* (itemTemplate._props.MaximumNumberOfUsage - item.upd.Key.NumberOfUsages);
|
||||
worth
|
||||
= (worth / itemTemplate._props.MaximumNumberOfUsage)
|
||||
* (itemTemplate._props.MaximumNumberOfUsage - item.upd.Key.NumberOfUsages);
|
||||
}
|
||||
|
||||
if ("Resource" in item.upd && itemTemplate._props.MaxResource > 0)
|
||||
{
|
||||
worth = worth * 0.1 + worth * 0.9 / itemTemplate._props.MaxResource * item.upd.Resource.Value;
|
||||
worth = worth * 0.1 + ((worth * 0.9) / itemTemplate._props.MaxResource) * item.upd.Resource.Value;
|
||||
}
|
||||
|
||||
if ("SideEffect" in item.upd && itemTemplate._props.MaxResource > 0)
|
||||
{
|
||||
worth = worth * 0.1 + worth * 0.9 / itemTemplate._props.MaxResource * item.upd.SideEffect.Value;
|
||||
worth = worth * 0.1 + ((worth * 0.9) / itemTemplate._props.MaxResource) * item.upd.SideEffect.Value;
|
||||
}
|
||||
|
||||
if ("MedKit" in item.upd && itemTemplate._props.MaxHpResource > 0)
|
||||
{
|
||||
worth = worth / itemTemplate._props.MaxHpResource * item.upd.MedKit.HpResource;
|
||||
worth = (worth / itemTemplate._props.MaxHpResource) * item.upd.MedKit.HpResource;
|
||||
}
|
||||
|
||||
if ("FoodDrink" in item.upd && itemTemplate._props.MaxResource > 0)
|
||||
{
|
||||
worth = worth / itemTemplate._props.MaxResource * item.upd.FoodDrink.HpPercent;
|
||||
worth = (worth / itemTemplate._props.MaxResource) * item.upd.FoodDrink.HpPercent;
|
||||
}
|
||||
|
||||
if ("Repairable" in item.upd && <number > itemTemplate._props.armorClass > 0)
|
||||
{
|
||||
const num2 = 0.01 * 0.0 ** item.upd.Repairable.MaxDurability;
|
||||
worth = worth * (item.upd.Repairable.MaxDurability / itemTemplate._props.Durability - num2)
|
||||
- Math.floor(
|
||||
itemTemplate._props.RepairCost
|
||||
* (item.upd.Repairable.MaxDurability - item.upd.Repairable.Durability),
|
||||
);
|
||||
worth
|
||||
= worth * (item.upd.Repairable.MaxDurability / itemTemplate._props.Durability - num2)
|
||||
- Math.floor(
|
||||
itemTemplate._props.RepairCost
|
||||
* (item.upd.Repairable.MaxDurability - item.upd.Repairable.Durability),
|
||||
);
|
||||
}
|
||||
|
||||
return worth * itemCount;
|
||||
|
@ -80,7 +80,7 @@ export class RaidTimeAdjustmentService
|
||||
{
|
||||
// Remove waves that spawned before the player joined
|
||||
const originalWaveCount = mapBase.waves.length;
|
||||
mapBase.waves = mapBase.waves.filter(x => x.time_max > raidAdjustments.simulatedRaidStartSeconds);
|
||||
mapBase.waves = mapBase.waves.filter((x) => x.time_max > raidAdjustments.simulatedRaidStartSeconds);
|
||||
|
||||
// Adjust wave min/max times to match new simulated start
|
||||
for (const wave of mapBase.waves)
|
||||
|
@ -60,7 +60,7 @@ export class RepairService
|
||||
traderId: string,
|
||||
): RepairDetails
|
||||
{
|
||||
const itemToRepair = pmcData.Inventory.items.find(x => x._id === repairItemDetails._id);
|
||||
const itemToRepair = pmcData.Inventory.items.find((x) => x._id === repairItemDetails._id);
|
||||
if (itemToRepair === undefined)
|
||||
{
|
||||
throw new Error(`Item ${repairItemDetails._id} not found in profile inventory, unable to repair`);
|
||||
@ -121,10 +121,12 @@ export class RepairService
|
||||
): void
|
||||
{
|
||||
const options: IProcessBuyTradeRequestData = {
|
||||
scheme_items: [{
|
||||
id: "5449016a4bdc2d6f028b456f", // Rouble tpl
|
||||
count: Math.round(repairCost),
|
||||
}],
|
||||
scheme_items: [
|
||||
{
|
||||
id: "5449016a4bdc2d6f028b456f", // Rouble tpl
|
||||
count: Math.round(repairCost),
|
||||
},
|
||||
],
|
||||
tid: traderId,
|
||||
Action: "SptRepair",
|
||||
type: "",
|
||||
@ -184,8 +186,8 @@ export class RepairService
|
||||
|
||||
const isHeavyArmor = itemDetails[1]._props.ArmorType === "Heavy";
|
||||
const vestSkillToLevel = isHeavyArmor ? SkillTypes.HEAVY_VESTS : SkillTypes.LIGHT_VESTS;
|
||||
const pointsToAddToVestSkill = repairDetails.repairPoints
|
||||
* this.repairConfig.armorKitSkillPointGainPerRepairPointMultiplier;
|
||||
const pointsToAddToVestSkill
|
||||
= repairDetails.repairPoints * this.repairConfig.armorKitSkillPointGainPerRepairPointMultiplier;
|
||||
|
||||
this.logger.debug(`Added: ${pointsToAddToVestSkill} ${vestSkillToLevel} skill`);
|
||||
this.profileHelper.addSkillPointsToPlayer(pmcData, vestSkillToLevel, pointsToAddToVestSkill);
|
||||
@ -205,10 +207,12 @@ export class RepairService
|
||||
if (repairDetails.repairedByKit)
|
||||
{
|
||||
// Weapons/armor have different multipliers
|
||||
const intRepairMultiplier
|
||||
= this.itemHelper.isOfBaseclass(repairDetails.repairedItem._tpl, BaseClasses.WEAPON)
|
||||
? this.repairConfig.repairKitIntellectGainMultiplier.weapon
|
||||
: this.repairConfig.repairKitIntellectGainMultiplier.armor;
|
||||
const intRepairMultiplier = this.itemHelper.isOfBaseclass(
|
||||
repairDetails.repairedItem._tpl,
|
||||
BaseClasses.WEAPON,
|
||||
)
|
||||
? this.repairConfig.repairKitIntellectGainMultiplier.weapon
|
||||
: this.repairConfig.repairKitIntellectGainMultiplier.armor;
|
||||
|
||||
// Limit gain to a max value defined in config.maxIntellectGainPerRepair
|
||||
return Math.min(
|
||||
@ -302,7 +306,7 @@ export class RepairService
|
||||
// Find and use repair kit defined in body
|
||||
for (const repairKit of repairKits)
|
||||
{
|
||||
const repairKitInInventory = pmcData.Inventory.items.find(x => x._id === repairKit._id);
|
||||
const repairKitInInventory = pmcData.Inventory.items.find((x) => x._id === repairKit._id);
|
||||
const repairKitDetails = itemsDb[repairKitInInventory._tpl];
|
||||
const repairKitReductionAmount = repairKit.count;
|
||||
|
||||
@ -336,8 +340,8 @@ export class RepairService
|
||||
const globalRepairSettings = globals.config.RepairSettings;
|
||||
|
||||
const intellectRepairPointsPerLevel = globals.config.SkillsSettings.Intellect.RepairPointsCostReduction;
|
||||
const profileIntellectLevel = this.profileHelper.getSkillFromProfile(pmcData, SkillTypes.INTELLECT)?.Progress
|
||||
?? 0;
|
||||
const profileIntellectLevel
|
||||
= this.profileHelper.getSkillFromProfile(pmcData, SkillTypes.INTELLECT)?.Progress ?? 0;
|
||||
const intellectPointReduction = intellectRepairPointsPerLevel * Math.trunc(profileIntellectLevel / 100);
|
||||
|
||||
if (isArmor)
|
||||
@ -370,11 +374,11 @@ export class RepairService
|
||||
*/
|
||||
protected getBonusMultiplierValue(skillBonus: BonusType, pmcData: IPmcData): number
|
||||
{
|
||||
const bonusesMatched = pmcData?.Bonuses?.filter(b => b.type === skillBonus);
|
||||
const bonusesMatched = pmcData?.Bonuses?.filter((b) => b.type === skillBonus);
|
||||
let value = 1;
|
||||
if (bonusesMatched != null)
|
||||
{
|
||||
const sumedPercentage = bonusesMatched.map(b => b.value).reduce((v1, v2) => v1 + v2, 0);
|
||||
const sumedPercentage = bonusesMatched.map((b) => b.value).reduce((v1, v2) => v1 + v2, 0);
|
||||
value = 1 + sumedPercentage / 100;
|
||||
}
|
||||
|
||||
|
@ -342,7 +342,7 @@ export class SeasonalEventService
|
||||
}
|
||||
|
||||
// Get non-christmas items
|
||||
const nonChristmasTpls = Object.keys(containerItems).filter(tpl => !christmasItems.includes(tpl));
|
||||
const nonChristmasTpls = Object.keys(containerItems).filter((tpl) => !christmasItems.includes(tpl));
|
||||
const intermediaryDict = {};
|
||||
|
||||
for (const tpl of nonChristmasTpls)
|
||||
@ -368,7 +368,7 @@ export class SeasonalEventService
|
||||
switch (eventType.toLowerCase())
|
||||
{
|
||||
case SeasonalEventType.HALLOWEEN.toLowerCase():
|
||||
globalConfig.EventType = globalConfig.EventType.filter(x => x !== "None");
|
||||
globalConfig.EventType = globalConfig.EventType.filter((x) => x !== "None");
|
||||
globalConfig.EventType.push("Halloween");
|
||||
globalConfig.EventType.push("HalloweenIllumination");
|
||||
globalConfig.Health.ProfileHealthSettings.DefaultStimulatorBuff = "Buffs_Halloween";
|
||||
@ -380,7 +380,7 @@ export class SeasonalEventService
|
||||
this.adjustTraderIcons(eventType);
|
||||
break;
|
||||
case SeasonalEventType.CHRISTMAS.toLowerCase():
|
||||
globalConfig.EventType = globalConfig.EventType.filter(x => x !== "None");
|
||||
globalConfig.EventType = globalConfig.EventType.filter((x) => x !== "None");
|
||||
globalConfig.EventType.push("Christmas");
|
||||
this.addEventGearToBots(eventType);
|
||||
this.addGifterBotToMaps();
|
||||
@ -435,7 +435,7 @@ export class SeasonalEventService
|
||||
{
|
||||
const mapBosses: BossLocationSpawn[]
|
||||
= this.databaseServer.getTables().locations[mapKey].base.BossLocationSpawn;
|
||||
if (!mapBosses.find(x => x.BossName === boss.BossName))
|
||||
if (!mapBosses.find((x) => x.BossName === boss.BossName))
|
||||
{
|
||||
this.databaseServer.getTables().locations[mapKey].base.BossLocationSpawn.push(...bossesToAdd);
|
||||
}
|
||||
@ -474,9 +474,11 @@ export class SeasonalEventService
|
||||
break;
|
||||
}
|
||||
|
||||
this.databaseImporter.loadImages(`${this.databaseImporter.getSptDataPath()}images/`, ["traders"], [
|
||||
"/files/trader/avatar/",
|
||||
]);
|
||||
this.databaseImporter.loadImages(
|
||||
`${this.databaseImporter.getSptDataPath()}images/`,
|
||||
["traders"],
|
||||
["/files/trader/avatar/"],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -487,8 +489,9 @@ export class SeasonalEventService
|
||||
const gifterBot = this.databaseServer.getTables().bots.types.gifter;
|
||||
for (const difficulty in gifterBot.difficulty)
|
||||
{
|
||||
gifterBot.difficulty[difficulty].Patrol.ITEMS_TO_DROP = Object.keys(gifterBot.inventory.items.Backpack)
|
||||
.join(", ");
|
||||
gifterBot.difficulty[difficulty].Patrol.ITEMS_TO_DROP = Object.keys(
|
||||
gifterBot.inventory.items.Backpack,
|
||||
).join(", ");
|
||||
}
|
||||
}
|
||||
|
||||
@ -574,7 +577,7 @@ export class SeasonalEventService
|
||||
{
|
||||
const mapData: ILocation = maps[gifterMapSettings.map];
|
||||
// Dont add gifter to map twice
|
||||
if (mapData.base.BossLocationSpawn.some(boss => boss.BossName === "gifter"))
|
||||
if (mapData.base.BossLocationSpawn.some((boss) => boss.BossName === "gifter"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ export class TraderPurchasePersisterService
|
||||
|
||||
for (const purchaseKey in profile.traderPurchases[traderId])
|
||||
{
|
||||
const traderUpdateDetails = this.traderConfig.updateTime.find(x => x.traderId === traderId);
|
||||
const traderUpdateDetails = this.traderConfig.updateTime.find((x) => x.traderId === traderId);
|
||||
if (!traderUpdateDetails)
|
||||
{
|
||||
this.logger.error(
|
||||
@ -135,8 +135,9 @@ export class TraderPurchasePersisterService
|
||||
}
|
||||
|
||||
const purchaseDetails = profile.traderPurchases[traderId][purchaseKey];
|
||||
const resetTimeForItem = purchaseDetails.purchaseTimestamp
|
||||
+ this.randomUtil.getInt(traderUpdateDetails.seconds.min, traderUpdateDetails.seconds.max);
|
||||
const resetTimeForItem
|
||||
= purchaseDetails.purchaseTimestamp
|
||||
+ this.randomUtil.getInt(traderUpdateDetails.seconds.min, traderUpdateDetails.seconds.max);
|
||||
if (resetTimeForItem < this.timeUtil.getTimestamp())
|
||||
{
|
||||
// Item was purchased far enough in past a trader refresh would have occured, remove purchase record from profile
|
||||
|
@ -46,7 +46,7 @@ export class TraderServicesService
|
||||
{
|
||||
for (const questId of service.requirements.completedQuests)
|
||||
{
|
||||
const quest = pmcData.Quests.find(x => x.qid === questId);
|
||||
const quest = pmcData.Quests.find((x) => x.qid === questId);
|
||||
if (!quest || quest.status !== QuestStatus.Success)
|
||||
{
|
||||
servicesToDelete.push(service.serviceType);
|
||||
@ -57,7 +57,7 @@ export class TraderServicesService
|
||||
}
|
||||
|
||||
// Clear any unavailable services from the list
|
||||
traderServices = traderServices.filter(x => !servicesToDelete.includes(x.serviceType));
|
||||
traderServices = traderServices.filter((x) => !servicesToDelete.includes(x.serviceType));
|
||||
|
||||
return traderServices;
|
||||
}
|
||||
|
@ -2,7 +2,10 @@ import { DynamicRouter, RouteAction } from "@spt-aki/di/Router";
|
||||
|
||||
export class DynamicRouterMod extends DynamicRouter
|
||||
{
|
||||
public constructor(routes: RouteAction[], private topLevelRoute: string)
|
||||
public constructor(
|
||||
routes: RouteAction[],
|
||||
private topLevelRoute: string,
|
||||
)
|
||||
{
|
||||
super(routes);
|
||||
}
|
||||
|
@ -7,8 +7,7 @@ export class HttpListenerMod implements IHttpListener
|
||||
private canHandleOverride: (sessionId: string, req: IncomingMessage) => boolean,
|
||||
private handleOverride: (sessionId: string, req: IncomingMessage, resp: ServerResponse) => void,
|
||||
)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
public canHandle(sessionId: string, req: IncomingMessage): boolean
|
||||
{
|
||||
|
@ -2,7 +2,10 @@ import { OnLoad } from "@spt-aki/di/OnLoad";
|
||||
|
||||
export class OnLoadMod implements OnLoad
|
||||
{
|
||||
public constructor(private onLoadOverride: () => void, private getRouteOverride: () => string)
|
||||
public constructor(
|
||||
private onLoadOverride: () => void,
|
||||
private getRouteOverride: () => string,
|
||||
)
|
||||
{
|
||||
// super();
|
||||
}
|
||||
|
@ -6,8 +6,7 @@ export class OnUpdateMod implements OnUpdate
|
||||
private onUpdateOverride: (timeSinceLastRun: number) => boolean,
|
||||
private getRouteOverride: () => string,
|
||||
)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
public async onUpdate(timeSinceLastRun: number): Promise<boolean>
|
||||
{
|
||||
|
@ -7,7 +7,11 @@ export class OnUpdateModService
|
||||
constructor(protected container: DependencyContainer)
|
||||
{}
|
||||
|
||||
public registerOnUpdate(name: string, onUpdate: (timeSinceLastRun: number) => boolean, getRoute: () => string): void
|
||||
public registerOnUpdate(
|
||||
name: string,
|
||||
onUpdate: (timeSinceLastRun: number) => boolean,
|
||||
getRoute: () => string,
|
||||
): void
|
||||
{
|
||||
this.container.register(name, { useValue: new OnUpdateMod(onUpdate, getRoute) });
|
||||
this.container.registerType("OnUpdate", name);
|
||||
|
@ -2,7 +2,10 @@ import { RouteAction, StaticRouter } from "@spt-aki/di/Router";
|
||||
|
||||
export class StaticRouterMod extends StaticRouter
|
||||
{
|
||||
public constructor(routes: RouteAction[], private topLevelRoute: string)
|
||||
public constructor(
|
||||
routes: RouteAction[],
|
||||
private topLevelRoute: string,
|
||||
)
|
||||
{
|
||||
super(routes);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ export class CompareUtil
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return arr1.every(vOf1 => arr2.find(vOf2 => this.recursiveCompare(vOf1, vOf2)));
|
||||
return arr1.every((vOf1) => arr2.find((vOf2) => this.recursiveCompare(vOf1, vOf2)));
|
||||
}
|
||||
for (const propOf1 in v1)
|
||||
{
|
||||
|
@ -107,9 +107,8 @@ export class DatabaseImporter implements OnLoad
|
||||
(fileWithPath: string, data: string) => this.onReadValidate(fileWithPath, data),
|
||||
);
|
||||
|
||||
const validation = this.valid === VaildationResult.FAILED || this.valid === VaildationResult.NOT_FOUND
|
||||
? "."
|
||||
: "";
|
||||
const validation
|
||||
= this.valid === VaildationResult.FAILED || this.valid === VaildationResult.NOT_FOUND ? "." : "";
|
||||
this.logger.info(`${this.localisationService.getText("importing_database_finish")}${validation}`);
|
||||
this.databaseServer.setTables(dataToImport);
|
||||
}
|
||||
|
@ -7,14 +7,14 @@ import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper";
|
||||
export class HttpFileUtil
|
||||
{
|
||||
constructor(@inject("HttpServerHelper") protected httpServerHelper: HttpServerHelper)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
public sendFile(resp: ServerResponse, filePath: string): void
|
||||
{
|
||||
const pathSlic = filePath.split("/");
|
||||
const type = this.httpServerHelper.getMimeText(pathSlic[pathSlic.length - 1].split(".").at(-1))
|
||||
|| this.httpServerHelper.getMimeText("txt");
|
||||
const type
|
||||
= this.httpServerHelper.getMimeText(pathSlic[pathSlic.length - 1].split(".").at(-1))
|
||||
|| this.httpServerHelper.getMimeText("txt");
|
||||
const fileStream = fs.createReadStream(filePath);
|
||||
|
||||
fileStream.on("open", () =>
|
||||
|
@ -17,12 +17,12 @@ export class HttpResponseUtil
|
||||
|
||||
protected clearString(s: string): any
|
||||
{
|
||||
return s.replace(/[\b]/g, "").replace(/[\f]/g, "").replace(/[\n]/g, "")
|
||||
return s
|
||||
.replace(/[\b]/g, "")
|
||||
.replace(/[\f]/g, "")
|
||||
.replace(/[\n]/g, "")
|
||||
.replace(/[\r]/g, "")
|
||||
.replace(
|
||||
/[\t]/g,
|
||||
"",
|
||||
);
|
||||
.replace(/[\t]/g, "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,7 +8,10 @@ import { VFS } from "@spt-aki/utils/VFS";
|
||||
@injectable()
|
||||
export class ImporterUtil
|
||||
{
|
||||
constructor(@inject("VFS") protected vfs: VFS, @inject("JsonUtil") protected jsonUtil: JsonUtil)
|
||||
constructor(
|
||||
@inject("VFS") protected vfs: VFS,
|
||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||
)
|
||||
{}
|
||||
|
||||
/**
|
||||
@ -55,7 +58,7 @@ export class ImporterUtil
|
||||
|
||||
// set all loadRecursive to be executed asynchronously
|
||||
const resEntries = Object.entries(result);
|
||||
const resResolved = await Promise.all(resEntries.map(ent => ent[1]));
|
||||
const resResolved = await Promise.all(resEntries.map((ent) => ent[1]));
|
||||
for (let resIdx = 0; resIdx < resResolved.length; resIdx++)
|
||||
{
|
||||
resEntries[resIdx][1] = resResolved[resIdx];
|
||||
@ -70,9 +73,13 @@ export class ImporterUtil
|
||||
* @param filepath Path to folder with files
|
||||
* @returns
|
||||
*/
|
||||
public loadRecursive<T>(filepath: string, onReadCallback: (fileWithPath: string, data: string) => void = () =>
|
||||
{}, onObjectDeserialized: (fileWithPath: string, object: any) => void = () =>
|
||||
{}): T
|
||||
public loadRecursive<T>(
|
||||
filepath: string,
|
||||
onReadCallback: (fileWithPath: string, data: string) => void = () =>
|
||||
{},
|
||||
onObjectDeserialized: (fileWithPath: string, object: any) => void = () =>
|
||||
{},
|
||||
): T
|
||||
{
|
||||
const result = {} as T;
|
||||
|
||||
@ -123,14 +130,14 @@ export class ImporterUtil
|
||||
const files = this.vfs.getFiles(filepath);
|
||||
const directories = this.vfs.getDirs(filepath);
|
||||
|
||||
directoriesToRead.enqueueAll(directories.map(d => `${filepath}${d}`));
|
||||
filesToProcess.enqueueAll(files.map(f => new VisitNode(filepath, f)));
|
||||
directoriesToRead.enqueueAll(directories.map((d) => `${filepath}${d}`));
|
||||
filesToProcess.enqueueAll(files.map((f) => new VisitNode(filepath, f)));
|
||||
|
||||
while (directoriesToRead.length !== 0)
|
||||
{
|
||||
const directory = directoriesToRead.dequeue();
|
||||
filesToProcess.enqueueAll(this.vfs.getFiles(directory).map(f => new VisitNode(`${directory}/`, f)));
|
||||
directoriesToRead.enqueueAll(this.vfs.getDirs(directory).map(d => `${directory}/${d}`));
|
||||
filesToProcess.enqueueAll(this.vfs.getFiles(directory).map((f) => new VisitNode(`${directory}/`, f)));
|
||||
directoriesToRead.enqueueAll(this.vfs.getDirs(directory).map((d) => `${directory}/${d}`));
|
||||
}
|
||||
|
||||
while (filesToProcess.length !== 0)
|
||||
@ -140,21 +147,24 @@ export class ImporterUtil
|
||||
{
|
||||
const filePathAndName = `${fileNode.filePath}${fileNode.fileName}`;
|
||||
promises.push(
|
||||
this.vfs.readFileAsync(filePathAndName).then(async (fileData) =>
|
||||
{
|
||||
onReadCallback(filePathAndName, fileData);
|
||||
return this.jsonUtil.deserializeWithCacheCheckAsync<any>(fileData, filePathAndName);
|
||||
}).then(async (fileDeserialized) =>
|
||||
{
|
||||
onObjectDeserialized(filePathAndName, fileDeserialized);
|
||||
const strippedFilePath = this.vfs.stripExtension(filePathAndName).replace(filepath, "");
|
||||
this.placeObject(fileDeserialized, strippedFilePath, result, strippablePath);
|
||||
}),
|
||||
this.vfs
|
||||
.readFileAsync(filePathAndName)
|
||||
.then(async (fileData) =>
|
||||
{
|
||||
onReadCallback(filePathAndName, fileData);
|
||||
return this.jsonUtil.deserializeWithCacheCheckAsync<any>(fileData, filePathAndName);
|
||||
})
|
||||
.then(async (fileDeserialized) =>
|
||||
{
|
||||
onObjectDeserialized(filePathAndName, fileDeserialized);
|
||||
const strippedFilePath = this.vfs.stripExtension(filePathAndName).replace(filepath, "");
|
||||
this.placeObject(fileDeserialized, strippedFilePath, result, strippablePath);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(promises).catch(e => console.error(e));
|
||||
await Promise.all(promises).catch((e) => console.error(e));
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -186,6 +196,9 @@ export class ImporterUtil
|
||||
|
||||
class VisitNode
|
||||
{
|
||||
constructor(public filePath: string, public fileName: string)
|
||||
constructor(
|
||||
public filePath: string,
|
||||
public fileName: string,
|
||||
)
|
||||
{}
|
||||
}
|
||||
|
@ -178,7 +178,8 @@ export class JsonUtil
|
||||
{
|
||||
const { data, changed } = fixJson(jsonString);
|
||||
if (changed)
|
||||
{ // data invalid, return it
|
||||
{
|
||||
// data invalid, return it
|
||||
this.logger.error(`${filePath} - Detected faulty json, please fix your json file using VSCodium`);
|
||||
}
|
||||
else
|
||||
|
@ -39,7 +39,7 @@ export class MathUtil
|
||||
*/
|
||||
public arrayProd(values: number[], factor: number): number[]
|
||||
{
|
||||
return values.map(x => x * factor);
|
||||
return values.map((x) => x * factor);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,7 +49,7 @@ export class MathUtil
|
||||
*/
|
||||
public arrayAdd(values: number[], summand: number): number[]
|
||||
{
|
||||
return values.map(x => x + summand);
|
||||
return values.map((x) => x + summand);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,7 +101,7 @@ export class MathUtil
|
||||
{
|
||||
if (xp >= x[i] && xp <= x[i + 1])
|
||||
{
|
||||
return y[i] + (xp - x[i]) * (y[i + 1] - y[i]) / (x[i + 1] - x[i]);
|
||||
return y[i] + ((xp - x[i]) * (y[i + 1] - y[i])) / (x[i + 1] - x[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ export class ObjectId
|
||||
let hexString = "";
|
||||
for (let i = 0; i < byteArray.length; i++)
|
||||
{
|
||||
hexString += `0${(byteArray[i] & 0xFF).toString(16)}`.slice(-2);
|
||||
hexString += `0${(byteArray[i] & 0xff).toString(16)}`.slice(-2);
|
||||
}
|
||||
return hexString;
|
||||
}
|
||||
@ -42,16 +42,16 @@ export class ObjectId
|
||||
const objectIdBinary = Buffer.alloc(12);
|
||||
|
||||
objectIdBinary[3] = time & 0xff;
|
||||
objectIdBinary[2] = time >> 8 & 0xff;
|
||||
objectIdBinary[1] = time >> 16 & 0xff;
|
||||
objectIdBinary[0] = time >> 24 & 0xff;
|
||||
objectIdBinary[2] = (time >> 8) & 0xff;
|
||||
objectIdBinary[1] = (time >> 16) & 0xff;
|
||||
objectIdBinary[0] = (time >> 24) & 0xff;
|
||||
objectIdBinary[4] = this.randomBytes[0];
|
||||
objectIdBinary[5] = this.randomBytes[1];
|
||||
objectIdBinary[6] = this.randomBytes[2];
|
||||
objectIdBinary[7] = this.randomBytes[3];
|
||||
objectIdBinary[8] = this.randomBytes[4];
|
||||
objectIdBinary[9] = counter >> 16 & 0xff;
|
||||
objectIdBinary[10] = counter >> 8 & 0xff;
|
||||
objectIdBinary[9] = (counter >> 16) & 0xff;
|
||||
objectIdBinary[10] = (counter >> 8) & 0xff;
|
||||
objectIdBinary[11] = counter & 0xff;
|
||||
|
||||
return this.toHexString(objectIdBinary);
|
||||
|
@ -7,7 +7,10 @@ export class RagfairOfferHolder
|
||||
protected offersByTemplate: Map<string, Map<string, IRagfairOffer>>;
|
||||
protected offersByTrader: Map<string, Map<string, IRagfairOffer>>;
|
||||
|
||||
constructor(protected maxOffersPerTemplate: number, protected ragfairServerHelper: RagfairServerHelper)
|
||||
constructor(
|
||||
protected maxOffersPerTemplate: number,
|
||||
protected ragfairServerHelper: RagfairServerHelper,
|
||||
)
|
||||
{
|
||||
this.offersById = new Map();
|
||||
this.offersByTemplate = new Map();
|
||||
@ -122,7 +125,7 @@ export class RagfairOfferHolder
|
||||
*/
|
||||
public getStaleOffers(time: number): Array<IRagfairOffer>
|
||||
{
|
||||
return this.getOffers().filter(o => this.isStale(o, time));
|
||||
return this.getOffers().filter((o) => this.isStale(o, time));
|
||||
}
|
||||
|
||||
protected addOfferByTemplates(template: string, offer: IRagfairOffer): void
|
||||
|
@ -20,7 +20,11 @@ import { MathUtil } from "@spt-aki/utils/MathUtil";
|
||||
*/
|
||||
export class ProbabilityObjectArray<K, V = undefined> extends Array<ProbabilityObject<K, V>>
|
||||
{
|
||||
constructor(private mathUtil: MathUtil, private cloner: ICloner, ...items: ProbabilityObject<K, V>[])
|
||||
constructor(
|
||||
private mathUtil: MathUtil,
|
||||
private cloner: ICloner,
|
||||
...items: ProbabilityObject<K, V>[]
|
||||
)
|
||||
{
|
||||
super();
|
||||
this.push(...items);
|
||||
@ -69,7 +73,7 @@ export class ProbabilityObjectArray<K, V = undefined> extends Array<ProbabilityO
|
||||
*/
|
||||
drop(key: K): ProbabilityObjectArray<K, V>
|
||||
{
|
||||
return this.filter(r => r.key !== key);
|
||||
return this.filter((r) => r.key !== key);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,7 +83,7 @@ export class ProbabilityObjectArray<K, V = undefined> extends Array<ProbabilityO
|
||||
*/
|
||||
data(key: K): V
|
||||
{
|
||||
return this.filter(r => r.key === key)[0]?.data;
|
||||
return this.filter((r) => r.key === key)[0]?.data;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,7 +98,7 @@ export class ProbabilityObjectArray<K, V = undefined> extends Array<ProbabilityO
|
||||
*/
|
||||
probability(key: K): number
|
||||
{
|
||||
return this.filter(r => r.key === key)[0].relativeProbability;
|
||||
return this.filter((r) => r.key === key)[0].relativeProbability;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,7 +112,7 @@ export class ProbabilityObjectArray<K, V = undefined> extends Array<ProbabilityO
|
||||
*/
|
||||
maxProbability(): number
|
||||
{
|
||||
return Math.max(...this.map(x => x.relativeProbability));
|
||||
return Math.max(...this.map((x) => x.relativeProbability));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,7 +126,7 @@ export class ProbabilityObjectArray<K, V = undefined> extends Array<ProbabilityO
|
||||
*/
|
||||
minProbability(): number
|
||||
{
|
||||
return Math.min(...this.map(x => x.relativeProbability));
|
||||
return Math.min(...this.map((x) => x.relativeProbability));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,19 +144,22 @@ export class ProbabilityObjectArray<K, V = undefined> extends Array<ProbabilityO
|
||||
return [];
|
||||
}
|
||||
|
||||
const { probArray, keyArray } = this.reduce((acc, x) =>
|
||||
{
|
||||
acc.probArray.push(x.relativeProbability);
|
||||
acc.keyArray.push(x.key);
|
||||
return acc;
|
||||
}, { probArray: [], keyArray: [] });
|
||||
const { probArray, keyArray } = this.reduce(
|
||||
(acc, x) =>
|
||||
{
|
||||
acc.probArray.push(x.relativeProbability);
|
||||
acc.keyArray.push(x.key);
|
||||
return acc;
|
||||
},
|
||||
{ probArray: [], keyArray: [] },
|
||||
);
|
||||
let probCumsum = this.cumulativeProbability(probArray);
|
||||
|
||||
const drawnKeys = [];
|
||||
for (let i = 0; i < count; i++)
|
||||
{
|
||||
const rand = Math.random();
|
||||
const randomIndex = probCumsum.findIndex(x => x > rand);
|
||||
const randomIndex = probCumsum.findIndex((x) => x > rand);
|
||||
// We cannot put Math.random() directly in the findIndex because then it draws anew for each of its iteration
|
||||
if (replacement || locklist.includes(keyArray[randomIndex]))
|
||||
{
|
||||
@ -204,9 +211,11 @@ export class ProbabilityObject<K, V = undefined>
|
||||
@injectable()
|
||||
export class RandomUtil
|
||||
{
|
||||
constructor(@inject("RecursiveCloner") protected cloner: ICloner, @inject("WinstonLogger") protected logger: ILogger)
|
||||
{
|
||||
}
|
||||
constructor(
|
||||
@inject("RecursiveCloner") protected cloner: ICloner,
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
)
|
||||
{}
|
||||
|
||||
public getInt(min: number, max: number): number
|
||||
{
|
||||
@ -232,7 +241,7 @@ export class RandomUtil
|
||||
|
||||
public getPercentOfValue(percent: number, number: number, toFixed = 2): number
|
||||
{
|
||||
return Number.parseFloat((percent * number / 100).toFixed(toFixed));
|
||||
return Number.parseFloat(((percent * number) / 100).toFixed(toFixed));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -446,8 +455,7 @@ export class RandomUtil
|
||||
do
|
||||
{
|
||||
num = boundedGaussian(biasedMin, biasedMax, n);
|
||||
}
|
||||
while (num < min || num > max);
|
||||
} while (num < min || num > max);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
@ -112,8 +112,8 @@ export class TimeUtil
|
||||
public getTimestampOfNextHour(): number
|
||||
{
|
||||
const now = new Date();
|
||||
const millisecondsUntilNextHour = (60 - now.getMinutes()) * 60 * 1000 - now.getSeconds() * 1000
|
||||
- now.getMilliseconds();
|
||||
const millisecondsUntilNextHour
|
||||
= (60 - now.getMinutes()) * 60 * 1000 - now.getSeconds() * 1000 - now.getMilliseconds();
|
||||
return (now.getTime() + millisecondsUntilNextHour) / 1000;
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ export class VFS
|
||||
const files = this.getFiles(filepath);
|
||||
const dirs = this.getDirs(filepath);
|
||||
|
||||
if (!await this.existsAsync(target))
|
||||
if (!(await this.existsAsync(target)))
|
||||
{
|
||||
await this.createDirAsync(`${target}/`);
|
||||
}
|
||||
@ -194,7 +194,7 @@ export class VFS
|
||||
{
|
||||
const options = append ? { flag: "a" } : { flag: "w" };
|
||||
|
||||
if (!await this.exists(filepath))
|
||||
if (!(await this.exists(filepath)))
|
||||
{
|
||||
await this.createDir(filepath);
|
||||
await this.writeFilePromisify(filepath, "");
|
||||
@ -332,7 +332,7 @@ export class VFS
|
||||
|
||||
public async minifyAllJsonInDirRecursive(filepath: string): Promise<void>
|
||||
{
|
||||
const files = this.getFiles(filepath).filter(item => this.getFileExtension(item) === "json");
|
||||
const files = this.getFiles(filepath).filter((item) => this.getFileExtension(item) === "json");
|
||||
for (const file of files)
|
||||
{
|
||||
const filePathAndName = path.join(filepath, file);
|
||||
@ -349,7 +349,7 @@ export class VFS
|
||||
|
||||
public async minifyAllJsonInDirRecursiveAsync(filepath: string): Promise<void>
|
||||
{
|
||||
const files = this.getFiles(filepath).filter(item => this.getFileExtension(item) === "json");
|
||||
const files = this.getFiles(filepath).filter((item) => this.getFileExtension(item) === "json");
|
||||
for (const file of files)
|
||||
{
|
||||
const filePathAndName = path.join(filepath, file);
|
||||
|
@ -154,10 +154,11 @@ export class Watermark
|
||||
const result = [];
|
||||
|
||||
// Calculate size, add 10% for spacing to the right
|
||||
const longestLength = this.text.reduce((a, b) =>
|
||||
{
|
||||
return a.length > b.length ? a : b;
|
||||
}).length * 1.1;
|
||||
const longestLength
|
||||
= this.text.reduce((a, b) =>
|
||||
{
|
||||
return a.length > b.length ? a : b;
|
||||
}).length * 1.1;
|
||||
|
||||
// Create line of - to add top/bottom of watermark
|
||||
let line = "";
|
||||
|
@ -29,7 +29,7 @@ export class RecursiveCloner implements ICloner
|
||||
{
|
||||
// biome-ignore lint/suspicious/noExplicitAny: used for clone
|
||||
const objArr = obj as Array<any>;
|
||||
return objArr.map(v => this.clone(v)) as T;
|
||||
return objArr.map((v) => this.clone(v)) as T;
|
||||
}
|
||||
|
||||
const newObj = {};
|
||||
|
@ -1,5 +1,9 @@
|
||||
export class LinkedListNode<T>
|
||||
{
|
||||
constructor(public value: T, public prev?: LinkedListNode<T>, public next?: LinkedListNode<T>)
|
||||
constructor(
|
||||
public value: T,
|
||||
public prev?: LinkedListNode<T>,
|
||||
public next?: LinkedListNode<T>,
|
||||
)
|
||||
{}
|
||||
}
|
||||
|
@ -133,7 +133,11 @@ export abstract class AbstractWinstonLogger implements ILogger
|
||||
await this.asyncQueue.waitFor(command);
|
||||
}
|
||||
|
||||
public async log(data: string | Error | Record<string, unknown>, color: string, backgroundColor = ""): Promise<void>
|
||||
public async log(
|
||||
data: string | Error | Record<string, unknown>,
|
||||
color: string,
|
||||
backgroundColor = "",
|
||||
): Promise<void>
|
||||
{
|
||||
const textColor = `${color} ${backgroundColor}`.trimEnd();
|
||||
const tmpLogger = createLogger({
|
||||
|
Loading…
x
Reference in New Issue
Block a user