mirror of
https://github.com/sp-tarkov/server.git
synced 2025-02-13 02:50:44 -05:00
ESLint Pass
This is the first pass of ESLint on the codebase. ESLint formatting is less strict when it comes to line-length and line-breaks then dprint/biome, so if you see formatting that you don't like... fix it! It shouldn't require a configuration change. - This should merge clean into master (when the time comes). - This will not merge clean into `3.9.0-DEV`, but the conflicts aren't that bad.
This commit is contained in:
parent
45bf159bb8
commit
50c7a26a58
@ -1,5 +1,4 @@
|
|||||||
import readline from "node:readline";
|
import readline from "node:readline";
|
||||||
|
|
||||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||||
import { AsyncQueue } from "@spt-aki/utils/AsyncQueue";
|
import { AsyncQueue } from "@spt-aki/utils/AsyncQueue";
|
||||||
import { WinstonMainLogger } from "@spt-aki/utils/logging/WinstonMainLogger";
|
import { WinstonMainLogger } from "@spt-aki/utils/logging/WinstonMainLogger";
|
||||||
@ -24,7 +23,7 @@ export class ErrorHandler
|
|||||||
this.logger.error(`\nStacktrace:\n${err.stack}`);
|
this.logger.error(`\nStacktrace:\n${err.stack}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.readLine.question("Press Enter to close the window", (_ans) => this.readLine.close());
|
this.readLine.question("Press Enter to close the window", _ans => this.readLine.close());
|
||||||
this.readLine.on("close", () => process.exit(1));
|
this.readLine.on("close", () => process.exit(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { container } from "tsyringe";
|
import { container } from "tsyringe";
|
||||||
|
|
||||||
import { ErrorHandler } from "@spt-aki/ErrorHandler";
|
|
||||||
import { Container } from "@spt-aki/di/Container";
|
import { Container } from "@spt-aki/di/Container";
|
||||||
|
import { ErrorHandler } from "@spt-aki/ErrorHandler";
|
||||||
import type { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";
|
import type { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";
|
||||||
import { App } from "@spt-aki/utils/App";
|
import { App } from "@spt-aki/utils/App";
|
||||||
import { Watermark } from "@spt-aki/utils/Watermark";
|
import { Watermark } from "@spt-aki/utils/Watermark";
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { inject, injectable } from "tsyringe";
|
||||||
import { AchievementController } from "@spt-aki/controllers/AchievementController";
|
import { AchievementController } from "@spt-aki/controllers/AchievementController";
|
||||||
import { ProfileController } from "@spt-aki/controllers/ProfileController";
|
import { ProfileController } from "@spt-aki/controllers/ProfileController";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
@ -6,7 +7,6 @@ import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyR
|
|||||||
import { ICompletedAchievementsResponse } from "@spt-aki/models/eft/profile/ICompletedAchievementsResponse";
|
import { ICompletedAchievementsResponse } from "@spt-aki/models/eft/profile/ICompletedAchievementsResponse";
|
||||||
import { IGetAchievementsResponse } from "@spt-aki/models/eft/profile/IGetAchievementsResponse";
|
import { IGetAchievementsResponse } from "@spt-aki/models/eft/profile/IGetAchievementsResponse";
|
||||||
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
|
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
|
||||||
import { inject, injectable } from "tsyringe";
|
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class AchievementCallbacks
|
export class AchievementCallbacks
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { BotController } from "@spt-aki/controllers/BotController";
|
import { BotController } from "@spt-aki/controllers/BotController";
|
||||||
import { IGenerateBotsRequestData } from "@spt-aki/models/eft/bot/IGenerateBotsRequestData";
|
import { IGenerateBotsRequestData } from "@spt-aki/models/eft/bot/IGenerateBotsRequestData";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { inject, injectable } from "tsyringe";
|
||||||
import { BuildController } from "@spt-aki/controllers/BuildController";
|
import { BuildController } from "@spt-aki/controllers/BuildController";
|
||||||
import { ISetMagazineRequest } from "@spt-aki/models/eft/builds/ISetMagazineRequest";
|
import { ISetMagazineRequest } from "@spt-aki/models/eft/builds/ISetMagazineRequest";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
@ -7,7 +8,6 @@ import { IPresetBuildActionRequestData } from "@spt-aki/models/eft/presetBuild/I
|
|||||||
import { IRemoveBuildRequestData } from "@spt-aki/models/eft/presetBuild/IRemoveBuildRequestData";
|
import { IRemoveBuildRequestData } from "@spt-aki/models/eft/presetBuild/IRemoveBuildRequestData";
|
||||||
import { IUserBuilds } from "@spt-aki/models/eft/profile/IAkiProfile";
|
import { IUserBuilds } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||||
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
|
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
|
||||||
import { inject, injectable } from "tsyringe";
|
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class BuildsCallbacks
|
export class BuildsCallbacks
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { BundleLoader } from "@spt-aki/loaders/BundleLoader";
|
import { BundleLoader } from "@spt-aki/loaders/BundleLoader";
|
||||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
import { IHttpConfig } from "@spt-aki/models/spt/config/IHttpConfig";
|
import { IHttpConfig } from "@spt-aki/models/spt/config/IHttpConfig";
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { inject, injectable } from "tsyringe";
|
||||||
import { ClientLogController } from "@spt-aki/controllers/ClientLogController";
|
import { ClientLogController } from "@spt-aki/controllers/ClientLogController";
|
||||||
import { ModLoadOrder } from "@spt-aki/loaders/ModLoadOrder";
|
import { ModLoadOrder } from "@spt-aki/loaders/ModLoadOrder";
|
||||||
import { INullResponseData } from "@spt-aki/models/eft/httpResponse/INullResponseData";
|
import { INullResponseData } from "@spt-aki/models/eft/httpResponse/INullResponseData";
|
||||||
@ -7,7 +8,6 @@ import { IClientLogRequest } from "@spt-aki/models/spt/logging/IClientLogRequest
|
|||||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||||
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
||||||
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
|
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
|
||||||
import { inject, injectable } from "tsyringe";
|
|
||||||
|
|
||||||
/** Handle client logging related events */
|
/** Handle client logging related events */
|
||||||
@injectable()
|
@injectable()
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { CustomizationController } from "@spt-aki/controllers/CustomizationController";
|
import { CustomizationController } from "@spt-aki/controllers/CustomizationController";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { HideoutController } from "@spt-aki/controllers/HideoutController";
|
import { HideoutController } from "@spt-aki/controllers/HideoutController";
|
||||||
import { RagfairController } from "@spt-aki/controllers/RagfairController";
|
import { RagfairController } from "@spt-aki/controllers/RagfairController";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { DialogueController } from "@spt-aki/controllers/DialogueController";
|
import { DialogueController } from "@spt-aki/controllers/DialogueController";
|
||||||
import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { GameController } from "@spt-aki/controllers/GameController";
|
import { GameController } from "@spt-aki/controllers/GameController";
|
||||||
import { OnLoad } from "@spt-aki/di/OnLoad";
|
import { OnLoad } from "@spt-aki/di/OnLoad";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { HandbookController } from "@spt-aki/controllers/HandbookController";
|
import { HandbookController } from "@spt-aki/controllers/HandbookController";
|
||||||
import { OnLoad } from "@spt-aki/di/OnLoad";
|
import { OnLoad } from "@spt-aki/di/OnLoad";
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { HealthController } from "@spt-aki/controllers/HealthController";
|
import { HealthController } from "@spt-aki/controllers/HealthController";
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { HideoutController } from "@spt-aki/controllers/HideoutController";
|
import { HideoutController } from "@spt-aki/controllers/HideoutController";
|
||||||
import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { OnLoad } from "@spt-aki/di/OnLoad";
|
import { OnLoad } from "@spt-aki/di/OnLoad";
|
||||||
import { HttpServer } from "@spt-aki/servers/HttpServer";
|
import { HttpServer } from "@spt-aki/servers/HttpServer";
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { InraidController } from "@spt-aki/controllers/InraidController";
|
import { InraidController } from "@spt-aki/controllers/InraidController";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
import { INullResponseData } from "@spt-aki/models/eft/httpResponse/INullResponseData";
|
import { INullResponseData } from "@spt-aki/models/eft/httpResponse/INullResponseData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { InsuranceController } from "@spt-aki/controllers/InsuranceController";
|
import { InsuranceController } from "@spt-aki/controllers/InsuranceController";
|
||||||
import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { InventoryController } from "@spt-aki/controllers/InventoryController";
|
import { InventoryController } from "@spt-aki/controllers/InventoryController";
|
||||||
import { QuestController } from "@spt-aki/controllers/QuestController";
|
import { QuestController } from "@spt-aki/controllers/QuestController";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData";
|
import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData";
|
||||||
import { Warning } from "@spt-aki/models/eft/itemEvent/IItemEventRouterBase";
|
import { Warning } from "@spt-aki/models/eft/itemEvent/IItemEventRouterBase";
|
||||||
import { IItemEventRouterRequest } from "@spt-aki/models/eft/itemEvent/IItemEventRouterRequest";
|
import { IItemEventRouterRequest } from "@spt-aki/models/eft/itemEvent/IItemEventRouterRequest";
|
||||||
@ -24,7 +23,7 @@ export class ItemEventCallbacks
|
|||||||
): IGetBodyResponseData<IItemEventRouterResponse>
|
): IGetBodyResponseData<IItemEventRouterResponse>
|
||||||
{
|
{
|
||||||
const eventResponse = this.itemEventRouter.handleEvents(info, sessionID);
|
const eventResponse = this.itemEventRouter.handleEvents(info, sessionID);
|
||||||
const result = (this.isCriticalError(eventResponse.warnings))
|
const result = this.isCriticalError(eventResponse.warnings)
|
||||||
? this.httpResponse.getBody(
|
? this.httpResponse.getBody(
|
||||||
eventResponse,
|
eventResponse,
|
||||||
this.getErrorCode(eventResponse.warnings),
|
this.getErrorCode(eventResponse.warnings),
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { LauncherController } from "@spt-aki/controllers/LauncherController";
|
import { LauncherController } from "@spt-aki/controllers/LauncherController";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
import { IChangeRequestData } from "@spt-aki/models/eft/launcher/IChangeRequestData";
|
import { IChangeRequestData } from "@spt-aki/models/eft/launcher/IChangeRequestData";
|
||||||
@ -29,13 +28,13 @@ export class LauncherCallbacks
|
|||||||
public login(url: string, info: ILoginRequestData, sessionID: string): string
|
public login(url: string, info: ILoginRequestData, sessionID: string): string
|
||||||
{
|
{
|
||||||
const output = this.launcherController.login(info);
|
const output = this.launcherController.login(info);
|
||||||
return (!output) ? "FAILED" : output;
|
return !output ? "FAILED" : output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public register(url: string, info: IRegisterData, sessionID: string): "FAILED" | "OK"
|
public register(url: string, info: IRegisterData, sessionID: string): "FAILED" | "OK"
|
||||||
{
|
{
|
||||||
const output = this.launcherController.register(info);
|
const output = this.launcherController.register(info);
|
||||||
return (!output) ? "FAILED" : "OK";
|
return !output ? "FAILED" : "OK";
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(url: string, info: ILoginRequestData, sessionID: string): string
|
public get(url: string, info: ILoginRequestData, sessionID: string): string
|
||||||
@ -47,19 +46,19 @@ export class LauncherCallbacks
|
|||||||
public changeUsername(url: string, info: IChangeRequestData, sessionID: string): "FAILED" | "OK"
|
public changeUsername(url: string, info: IChangeRequestData, sessionID: string): "FAILED" | "OK"
|
||||||
{
|
{
|
||||||
const output = this.launcherController.changeUsername(info);
|
const output = this.launcherController.changeUsername(info);
|
||||||
return (!output) ? "FAILED" : "OK";
|
return !output ? "FAILED" : "OK";
|
||||||
}
|
}
|
||||||
|
|
||||||
public changePassword(url: string, info: IChangeRequestData, sessionID: string): "FAILED" | "OK"
|
public changePassword(url: string, info: IChangeRequestData, sessionID: string): "FAILED" | "OK"
|
||||||
{
|
{
|
||||||
const output = this.launcherController.changePassword(info);
|
const output = this.launcherController.changePassword(info);
|
||||||
return (!output) ? "FAILED" : "OK";
|
return !output ? "FAILED" : "OK";
|
||||||
}
|
}
|
||||||
|
|
||||||
public wipe(url: string, info: IRegisterData, sessionID: string): "FAILED" | "OK"
|
public wipe(url: string, info: IRegisterData, sessionID: string): "FAILED" | "OK"
|
||||||
{
|
{
|
||||||
const output = this.launcherController.wipe(info);
|
const output = this.launcherController.wipe(info);
|
||||||
return (!output) ? "FAILED" : "OK";
|
return !output ? "FAILED" : "OK";
|
||||||
}
|
}
|
||||||
|
|
||||||
public getServerVersion(): string
|
public getServerVersion(): string
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { LocationController } from "@spt-aki/controllers/LocationController";
|
import { LocationController } from "@spt-aki/controllers/LocationController";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
import { ILocationBase } from "@spt-aki/models/eft/common/ILocationBase";
|
import { ILocationBase } from "@spt-aki/models/eft/common/ILocationBase";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { MatchController } from "@spt-aki/controllers/MatchController";
|
import { MatchController } from "@spt-aki/controllers/MatchController";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
@ -112,6 +111,7 @@ export class MatchCallbacks
|
|||||||
{
|
{
|
||||||
return this.httpResponse.getBody(true);
|
return this.httpResponse.getBody(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handle client/match/group/transfer */
|
/** Handle client/match/group/transfer */
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
public transferGroup(url: string, info: ITransferGroupRequest, sessionID: string): IGetBodyResponseData<boolean>
|
public transferGroup(url: string, info: ITransferGroupRequest, sessionID: string): IGetBodyResponseData<boolean>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { OnLoad } from "@spt-aki/di/OnLoad";
|
import { OnLoad } from "@spt-aki/di/OnLoad";
|
||||||
import { PostAkiModLoader } from "@spt-aki/loaders/PostAkiModLoader";
|
import { PostAkiModLoader } from "@spt-aki/loaders/PostAkiModLoader";
|
||||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { NoteController } from "@spt-aki/controllers/NoteController";
|
import { NoteController } from "@spt-aki/controllers/NoteController";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { NotifierController } from "@spt-aki/controllers/NotifierController";
|
import { NotifierController } from "@spt-aki/controllers/NotifierController";
|
||||||
import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper";
|
import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
@ -38,8 +37,8 @@ export class NotifierCallbacks
|
|||||||
* be sent to client as NEWLINE separated strings... yup.
|
* be sent to client as NEWLINE separated strings... yup.
|
||||||
*/
|
*/
|
||||||
this.notifierController.notifyAsync(tmpSessionID).then((messages: any) =>
|
this.notifierController.notifyAsync(tmpSessionID).then((messages: any) =>
|
||||||
messages.map((message: any) => this.jsonUtil.serialize(message)).join("\n")
|
messages.map((message: any) => this.jsonUtil.serialize(message)).join("\n"),
|
||||||
).then((text) => this.httpServerHelper.sendTextJson(resp, text));
|
).then(text => this.httpServerHelper.sendTextJson(resp, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handle push/notifier/get */
|
/** Handle push/notifier/get */
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { PresetController } from "@spt-aki/controllers/PresetController";
|
import { PresetController } from "@spt-aki/controllers/PresetController";
|
||||||
import { OnLoad } from "@spt-aki/di/OnLoad";
|
import { OnLoad } from "@spt-aki/di/OnLoad";
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ProfileController } from "@spt-aki/controllers/ProfileController";
|
import { ProfileController } from "@spt-aki/controllers/ProfileController";
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { QuestController } from "@spt-aki/controllers/QuestController";
|
import { QuestController } from "@spt-aki/controllers/QuestController";
|
||||||
import { RepeatableQuestController } from "@spt-aki/controllers/RepeatableQuestController";
|
import { RepeatableQuestController } from "@spt-aki/controllers/RepeatableQuestController";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { RagfairController } from "@spt-aki/controllers/RagfairController";
|
import { RagfairController } from "@spt-aki/controllers/RagfairController";
|
||||||
import { OnLoad } from "@spt-aki/di/OnLoad";
|
import { OnLoad } from "@spt-aki/di/OnLoad";
|
||||||
import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { RepairController } from "@spt-aki/controllers/RepairController";
|
import { RepairController } from "@spt-aki/controllers/RepairController";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { OnLoad } from "@spt-aki/di/OnLoad";
|
import { OnLoad } from "@spt-aki/di/OnLoad";
|
||||||
import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
||||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { TradeController } from "@spt-aki/controllers/TradeController";
|
import { TradeController } from "@spt-aki/controllers/TradeController";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { TraderController } from "@spt-aki/controllers/TraderController";
|
import { TraderController } from "@spt-aki/controllers/TraderController";
|
||||||
import { OnLoad } from "@spt-aki/di/OnLoad";
|
import { OnLoad } from "@spt-aki/di/OnLoad";
|
||||||
import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
import { OnUpdate } from "@spt-aki/di/OnUpdate";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { WeatherController } from "@spt-aki/controllers/WeatherController";
|
import { WeatherController } from "@spt-aki/controllers/WeatherController";
|
||||||
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt-aki/models/eft/common/IEmptyRequestData";
|
||||||
import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData";
|
import { IGetBodyResponseData } from "@spt-aki/models/eft/httpResponse/IGetBodyResponseData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { WishlistController } from "@spt-aki/controllers/WishlistController";
|
import { WishlistController } from "@spt-aki/controllers/WishlistController";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { injectable } from "tsyringe";
|
import { injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ContextVariable } from "@spt-aki/context/ContextVariable";
|
import { ContextVariable } from "@spt-aki/context/ContextVariable";
|
||||||
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
||||||
import { LinkedList } from "@spt-aki/utils/collections/lists/LinkedList";
|
import { LinkedList } from "@spt-aki/utils/collections/lists/LinkedList";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ICompletedAchievementsResponse } from "@spt-aki/models/eft/profile/ICompletedAchievementsResponse";
|
import { ICompletedAchievementsResponse } from "@spt-aki/models/eft/profile/ICompletedAchievementsResponse";
|
||||||
import { IGetAchievementsResponse } from "@spt-aki/models/eft/profile/IGetAchievementsResponse";
|
import { IGetAchievementsResponse } from "@spt-aki/models/eft/profile/IGetAchievementsResponse";
|
||||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
||||||
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
||||||
import { BotGenerator } from "@spt-aki/generators/BotGenerator";
|
import { BotGenerator } from "@spt-aki/generators/BotGenerator";
|
||||||
@ -61,7 +60,7 @@ export class BotController
|
|||||||
*/
|
*/
|
||||||
public getBotPresetGenerationLimit(type: string): number
|
public getBotPresetGenerationLimit(type: string): number
|
||||||
{
|
{
|
||||||
const value = this.botConfig.presetBatch[(type === "assaultGroup") ? "assault" : type];
|
const value = this.botConfig.presetBatch[type === "assaultGroup" ? "assault" : type];
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
{
|
{
|
||||||
@ -147,7 +146,7 @@ export class BotController
|
|||||||
const result = {};
|
const result = {};
|
||||||
|
|
||||||
const botDb = this.databaseServer.getTables().bots.types;
|
const botDb = this.databaseServer.getTables().bots.types;
|
||||||
const botTypes = Object.keys(WildSpawnTypeNumber).filter((v) => Number.isNaN(Number(v)));
|
const botTypes = Object.keys(WildSpawnTypeNumber).filter(v => Number.isNaN(Number(v)));
|
||||||
for (let botType of botTypes)
|
for (let botType of botTypes)
|
||||||
{
|
{
|
||||||
const enumType = botType.toLowerCase();
|
const enumType = botType.toLowerCase();
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
import { ISetMagazineRequest } from "@spt-aki/models/eft/builds/ISetMagazineRequest";
|
import { ISetMagazineRequest } from "@spt-aki/models/eft/builds/ISetMagazineRequest";
|
||||||
@ -43,11 +42,11 @@ export class BuildController
|
|||||||
const defaultEquipmentPresetsClone = this.jsonUtil.clone(
|
const defaultEquipmentPresetsClone = this.jsonUtil.clone(
|
||||||
this.databaseServer.getTables().templates.defaultEquipmentPresets,
|
this.databaseServer.getTables().templates.defaultEquipmentPresets,
|
||||||
);
|
);
|
||||||
const playerSecureContainer = profile.characters.pmc.Inventory.items?.find((x) =>
|
const playerSecureContainer = profile.characters.pmc.Inventory.items?.find(x =>
|
||||||
x.slotId === secureContainerSlotId
|
x.slotId === secureContainerSlotId,
|
||||||
);
|
);
|
||||||
const firstDefaultItemsSecureContainer = defaultEquipmentPresetsClone[0]?.Items?.find((x) =>
|
const firstDefaultItemsSecureContainer = defaultEquipmentPresetsClone[0]?.Items?.find(x =>
|
||||||
x.slotId === secureContainerSlotId
|
x.slotId === secureContainerSlotId,
|
||||||
);
|
);
|
||||||
if (playerSecureContainer && playerSecureContainer?._tpl !== firstDefaultItemsSecureContainer?._tpl)
|
if (playerSecureContainer && playerSecureContainer?._tpl !== firstDefaultItemsSecureContainer?._tpl)
|
||||||
{
|
{
|
||||||
@ -55,7 +54,7 @@ export class BuildController
|
|||||||
for (const defaultPreset of defaultEquipmentPresetsClone)
|
for (const defaultPreset of defaultEquipmentPresetsClone)
|
||||||
{
|
{
|
||||||
// Find presets secure container
|
// Find presets secure container
|
||||||
const secureContainer = defaultPreset.Items.find((item) => item.slotId === secureContainerSlotId);
|
const secureContainer = defaultPreset.Items.find(item => item.slotId === secureContainerSlotId);
|
||||||
if (secureContainer)
|
if (secureContainer)
|
||||||
{
|
{
|
||||||
secureContainer._tpl = playerSecureContainer._tpl;
|
secureContainer._tpl = playerSecureContainer._tpl;
|
||||||
@ -84,7 +83,7 @@ export class BuildController
|
|||||||
const newBuild: IWeaponBuild = { Id: body.Id, Name: body.Name, Root: body.Root, Items: body.Items };
|
const newBuild: IWeaponBuild = { Id: body.Id, Name: body.Name, Root: body.Root, Items: body.Items };
|
||||||
|
|
||||||
const savedWeaponBuilds = this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds;
|
const savedWeaponBuilds = this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds;
|
||||||
const existingBuild = savedWeaponBuilds.find((x) => x.Id === body.Id);
|
const existingBuild = savedWeaponBuilds.find(x => x.Id === body.Id);
|
||||||
if (existingBuild)
|
if (existingBuild)
|
||||||
{
|
{
|
||||||
// exists, replace
|
// exists, replace
|
||||||
@ -107,8 +106,8 @@ export class BuildController
|
|||||||
const buildType = "equipmentBuilds";
|
const buildType = "equipmentBuilds";
|
||||||
const pmcData = this.profileHelper.getPmcProfile(sessionID);
|
const pmcData = this.profileHelper.getPmcProfile(sessionID);
|
||||||
|
|
||||||
const existingSavedEquipmentBuilds: IEquipmentBuild[] =
|
const existingSavedEquipmentBuilds: IEquipmentBuild[] = this.saveServer.getProfile(sessionID)
|
||||||
this.saveServer.getProfile(sessionID).userbuilds[buildType];
|
.userbuilds[buildType];
|
||||||
|
|
||||||
// Replace duplicate ID's. The first item is the base item.
|
// Replace duplicate ID's. The first item is the base item.
|
||||||
// Root ID and the base item ID need to match.
|
// Root ID and the base item ID need to match.
|
||||||
@ -122,8 +121,8 @@ export class BuildController
|
|||||||
Items: request.Items,
|
Items: request.Items,
|
||||||
};
|
};
|
||||||
|
|
||||||
const existingBuild = existingSavedEquipmentBuilds.find((build) =>
|
const existingBuild = existingSavedEquipmentBuilds.find(build =>
|
||||||
build.Name === request.Name || build.Id === request.Id
|
build.Name === request.Name || build.Id === request.Id,
|
||||||
);
|
);
|
||||||
if (existingBuild)
|
if (existingBuild)
|
||||||
{
|
{
|
||||||
@ -141,7 +140,7 @@ export class BuildController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handle client/builds/delete*/
|
/** Handle client/builds/delete */
|
||||||
public removeBuild(sessionID: string, request: IRemoveBuildRequestData): void
|
public removeBuild(sessionID: string, request: IRemoveBuildRequestData): void
|
||||||
{
|
{
|
||||||
this.removePlayerBuild(request.id, sessionID);
|
this.removePlayerBuild(request.id, sessionID);
|
||||||
@ -155,7 +154,7 @@ export class BuildController
|
|||||||
const magazineBuilds = profile.userbuilds.magazineBuilds;
|
const magazineBuilds = profile.userbuilds.magazineBuilds;
|
||||||
|
|
||||||
// Check for id in weapon array first
|
// Check for id in weapon array first
|
||||||
const matchingWeaponBuild = weaponBuilds.find((weaponBuild) => weaponBuild.Id === idToRemove);
|
const matchingWeaponBuild = weaponBuilds.find(weaponBuild => weaponBuild.Id === idToRemove);
|
||||||
if (matchingWeaponBuild)
|
if (matchingWeaponBuild)
|
||||||
{
|
{
|
||||||
weaponBuilds.splice(weaponBuilds.indexOf(matchingWeaponBuild), 1);
|
weaponBuilds.splice(weaponBuilds.indexOf(matchingWeaponBuild), 1);
|
||||||
@ -164,7 +163,7 @@ export class BuildController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Id not found in weapons, try equipment
|
// Id not found in weapons, try equipment
|
||||||
const matchingEquipmentBuild = equipmentBuilds.find((equipmentBuild) => equipmentBuild.Id === idToRemove);
|
const matchingEquipmentBuild = equipmentBuilds.find(equipmentBuild => equipmentBuild.Id === idToRemove);
|
||||||
if (matchingEquipmentBuild)
|
if (matchingEquipmentBuild)
|
||||||
{
|
{
|
||||||
equipmentBuilds.splice(equipmentBuilds.indexOf(matchingEquipmentBuild), 1);
|
equipmentBuilds.splice(equipmentBuilds.indexOf(matchingEquipmentBuild), 1);
|
||||||
@ -173,7 +172,7 @@ export class BuildController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Id not found in weapons/equipment, try mags
|
// Id not found in weapons/equipment, try mags
|
||||||
const matchingMagazineBuild = magazineBuilds.find((magBuild) => magBuild.Id === idToRemove);
|
const matchingMagazineBuild = magazineBuilds.find(magBuild => magBuild.Id === idToRemove);
|
||||||
if (matchingMagazineBuild)
|
if (matchingMagazineBuild)
|
||||||
{
|
{
|
||||||
magazineBuilds.splice(magazineBuilds.indexOf(matchingMagazineBuild), 1);
|
magazineBuilds.splice(magazineBuilds.indexOf(matchingMagazineBuild), 1);
|
||||||
@ -208,7 +207,7 @@ export class BuildController
|
|||||||
profile.userbuilds.magazineBuilds = [];
|
profile.userbuilds.magazineBuilds = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingArrayId = profile.userbuilds.magazineBuilds.findIndex((item) => item.Name === request.Name);
|
const existingArrayId = profile.userbuilds.magazineBuilds.findIndex(item => item.Name === request.Name);
|
||||||
|
|
||||||
if (existingArrayId === -1)
|
if (existingArrayId === -1)
|
||||||
{
|
{
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
import { inject, injectable } from "tsyringe";
|
||||||
import { IClientLogRequest } from "@spt-aki/models/spt/logging/IClientLogRequest";
|
import { IClientLogRequest } from "@spt-aki/models/spt/logging/IClientLogRequest";
|
||||||
import { LogBackgroundColor } from "@spt-aki/models/spt/logging/LogBackgroundColor";
|
import { LogBackgroundColor } from "@spt-aki/models/spt/logging/LogBackgroundColor";
|
||||||
import { LogLevel } from "@spt-aki/models/spt/logging/LogLevel";
|
import { LogLevel } from "@spt-aki/models/spt/logging/LogLevel";
|
||||||
import { LogTextColor } from "@spt-aki/models/spt/logging/LogTextColor";
|
import { LogTextColor } from "@spt-aki/models/spt/logging/LogTextColor";
|
||||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||||
import { inject, injectable } from "tsyringe";
|
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class ClientLogController
|
export class ClientLogController
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
import { ISuit } from "@spt-aki/models/eft/common/tables/ITrader";
|
import { ISuit } from "@spt-aki/models/eft/common/tables/ITrader";
|
||||||
@ -43,10 +42,10 @@ export class CustomizationController
|
|||||||
const suits = this.databaseServer.getTables().traders[traderID].suits;
|
const suits = this.databaseServer.getTables().traders[traderID].suits;
|
||||||
|
|
||||||
// Get an inner join of clothing from templates.customization and Ragman's suits array
|
// Get an inner join of clothing from templates.customization and Ragman's suits array
|
||||||
const matchingSuits = suits.filter((x) => x.suiteId in templates);
|
const matchingSuits = suits.filter(x => x.suiteId in templates);
|
||||||
|
|
||||||
// Return all suits that have a side array containing the players side (usec/bear)
|
// Return all suits that have a side array containing the players side (usec/bear)
|
||||||
return matchingSuits.filter((x) => templates[x.suiteId]._props.Side.includes(pmcData.Info.Side));
|
return matchingSuits.filter(x => templates[x.suiteId]._props.Side.includes(pmcData.Info.Side));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -133,7 +132,7 @@ export class CustomizationController
|
|||||||
|
|
||||||
protected getTraderClothingOffer(sessionId: string, offerId: string): ISuit
|
protected getTraderClothingOffer(sessionId: string, offerId: string): ISuit
|
||||||
{
|
{
|
||||||
return this.getAllTraderSuits(sessionId).find((x) => x._id === offerId);
|
return this.getAllTraderSuits(sessionId).find(x => x._id === offerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -181,7 +180,7 @@ export class CustomizationController
|
|||||||
output: IItemEventRouterResponse,
|
output: IItemEventRouterResponse,
|
||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
const relatedItem = pmcData.Inventory.items.find((x) => x._id === clothingItem.id);
|
const relatedItem = pmcData.Inventory.items.find(x => x._id === clothingItem.id);
|
||||||
if (!relatedItem)
|
if (!relatedItem)
|
||||||
{
|
{
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectAll, injectable } from "tsyringe";
|
import { inject, injectAll, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot";
|
import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot";
|
||||||
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
|
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
|
||||||
import { IGetAllAttachmentsResponse } from "@spt-aki/models/eft/dialog/IGetAllAttachmentsResponse";
|
import { IGetAllAttachmentsResponse } from "@spt-aki/models/eft/dialog/IGetAllAttachmentsResponse";
|
||||||
@ -34,21 +33,21 @@ export class DialogueController
|
|||||||
// if give command is disabled or commando commands are disabled
|
// if give command is disabled or commando commands are disabled
|
||||||
if (!coreConfigs.features?.chatbotFeatures?.commandoEnabled)
|
if (!coreConfigs.features?.chatbotFeatures?.commandoEnabled)
|
||||||
{
|
{
|
||||||
const sptCommando = this.dialogueChatBots.find((c) =>
|
const sptCommando = this.dialogueChatBots.find(c =>
|
||||||
c.getChatBot()._id.toLocaleLowerCase() === "sptcommando"
|
c.getChatBot()._id.toLocaleLowerCase() === "sptcommando",
|
||||||
);
|
);
|
||||||
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptCommando), 1);
|
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptCommando), 1);
|
||||||
}
|
}
|
||||||
if (!coreConfigs.features?.chatbotFeatures?.sptFriendEnabled)
|
if (!coreConfigs.features?.chatbotFeatures?.sptFriendEnabled)
|
||||||
{
|
{
|
||||||
const sptFriend = this.dialogueChatBots.find((c) => c.getChatBot()._id.toLocaleLowerCase() === "sptFriend");
|
const sptFriend = this.dialogueChatBots.find(c => c.getChatBot()._id.toLocaleLowerCase() === "sptFriend");
|
||||||
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptFriend), 1);
|
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptFriend), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public registerChatBot(chatBot: IDialogueChatBot): void
|
public registerChatBot(chatBot: IDialogueChatBot): void
|
||||||
{
|
{
|
||||||
if (this.dialogueChatBots.some((cb) => cb.getChatBot()._id === chatBot.getChatBot()._id))
|
if (this.dialogueChatBots.some(cb => cb.getChatBot()._id === chatBot.getChatBot()._id))
|
||||||
{
|
{
|
||||||
throw new Error(`The chat bot ${chatBot.getChatBot()._id} being registered already exists!`);
|
throw new Error(`The chat bot ${chatBot.getChatBot()._id} being registered already exists!`);
|
||||||
}
|
}
|
||||||
@ -73,7 +72,7 @@ export class DialogueController
|
|||||||
public getFriendList(sessionID: string): IGetFriendListDataResponse
|
public getFriendList(sessionID: string): IGetFriendListDataResponse
|
||||||
{
|
{
|
||||||
// Force a fake friend called SPT into friend list
|
// Force a fake friend called SPT into friend list
|
||||||
return { Friends: this.dialogueChatBots.map((v) => v.getChatBot()), Ignore: [], InIgnoreList: [] };
|
return { Friends: this.dialogueChatBots.map(v => v.getChatBot()), Ignore: [], InIgnoreList: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,6 +116,7 @@ export class DialogueController
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the users involved in a dialog (player + other party)
|
* Get the users involved in a dialog (player + other party)
|
||||||
* @param dialog The dialog to check for users
|
* @param dialog The dialog to check for users
|
||||||
@ -131,7 +131,7 @@ export class DialogueController
|
|||||||
// User to user messages are special in that they need the player to exist in them, add if they don't
|
// User to user messages are special in that they need the player to exist in them, add if they don't
|
||||||
if (
|
if (
|
||||||
messageType === MessageType.USER_MESSAGE
|
messageType === MessageType.USER_MESSAGE
|
||||||
&& !dialog.Users?.find((userDialog) => userDialog._id === profile.characters.pmc.sessionId)
|
&& !dialog.Users?.find(userDialog => userDialog._id === profile.characters.pmc.sessionId)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!dialog.Users)
|
if (!dialog.Users)
|
||||||
@ -207,7 +207,7 @@ export class DialogueController
|
|||||||
if (request.type === MessageType.USER_MESSAGE)
|
if (request.type === MessageType.USER_MESSAGE)
|
||||||
{
|
{
|
||||||
profile.dialogues[request.dialogId].Users = [];
|
profile.dialogues[request.dialogId].Users = [];
|
||||||
const chatBot = this.dialogueChatBots.find((cb) => cb.getChatBot()._id === request.dialogId);
|
const chatBot = this.dialogueChatBots.find(cb => cb.getChatBot()._id === request.dialogId);
|
||||||
if (chatBot)
|
if (chatBot)
|
||||||
{
|
{
|
||||||
profile.dialogues[request.dialogId].Users.push(chatBot.getChatBot());
|
profile.dialogues[request.dialogId].Users.push(chatBot.getChatBot());
|
||||||
@ -217,6 +217,7 @@ export class DialogueController
|
|||||||
|
|
||||||
return profile.dialogues[request.dialogId];
|
return profile.dialogues[request.dialogId];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the users involved in a mail between two entities
|
* Get the users involved in a mail between two entities
|
||||||
* @param fullProfile Player profile
|
* @param fullProfile Player profile
|
||||||
@ -230,7 +231,7 @@ export class DialogueController
|
|||||||
{
|
{
|
||||||
result.push(...dialogUsers);
|
result.push(...dialogUsers);
|
||||||
|
|
||||||
if (!result.find((userDialog) => userDialog._id === fullProfile.info.id))
|
if (!result.find(userDialog => userDialog._id === fullProfile.info.id))
|
||||||
{
|
{
|
||||||
// Player doesnt exist, add them in before returning
|
// Player doesnt exist, add them in before returning
|
||||||
const pmcProfile = fullProfile.characters.pmc;
|
const pmcProfile = fullProfile.characters.pmc;
|
||||||
@ -278,7 +279,7 @@ export class DialogueController
|
|||||||
*/
|
*/
|
||||||
protected messagesHaveUncollectedRewards(messages: Message[]): boolean
|
protected messagesHaveUncollectedRewards(messages: Message[]): boolean
|
||||||
{
|
{
|
||||||
return messages.some((message) => message.items?.data?.length > 0);
|
return messages.some(message => message.items?.data?.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -375,7 +376,7 @@ export class DialogueController
|
|||||||
{
|
{
|
||||||
this.mailSendService.sendPlayerMessageToNpc(sessionId, request.dialogId, request.text);
|
this.mailSendService.sendPlayerMessageToNpc(sessionId, request.dialogId, request.text);
|
||||||
|
|
||||||
return this.dialogueChatBots.find((cb) => cb.getChatBot()._id === request.dialogId)?.handleMessage(
|
return this.dialogueChatBots.find(cb => cb.getChatBot()._id === request.dialogId)?.handleMessage(
|
||||||
sessionId,
|
sessionId,
|
||||||
request,
|
request,
|
||||||
) ?? request.dialogId;
|
) ?? request.dialogId;
|
||||||
@ -391,7 +392,7 @@ export class DialogueController
|
|||||||
{
|
{
|
||||||
const timeNow = this.timeUtil.getTimestamp();
|
const timeNow = this.timeUtil.getTimestamp();
|
||||||
const dialogs = this.dialogueHelper.getDialogsForProfile(sessionId);
|
const dialogs = this.dialogueHelper.getDialogsForProfile(sessionId);
|
||||||
return dialogs[dialogueId].messages.filter((message) => timeNow < (message.dt + message.maxStorageTime));
|
return dialogs[dialogueId].messages.filter(message => timeNow < message.dt + message.maxStorageTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -401,7 +402,7 @@ export class DialogueController
|
|||||||
*/
|
*/
|
||||||
protected getMessagesWithAttachments(messages: Message[]): Message[]
|
protected getMessagesWithAttachments(messages: Message[]): Message[]
|
||||||
{
|
{
|
||||||
return messages.filter((message) => message.items?.data?.length > 0);
|
return messages.filter(message => message.items?.data?.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -446,6 +447,6 @@ export class DialogueController
|
|||||||
*/
|
*/
|
||||||
protected messageHasExpired(message: Message): boolean
|
protected messageHasExpired(message: Message): boolean
|
||||||
{
|
{
|
||||||
return (this.timeUtil.getTimestamp()) > (message.dt + message.maxStorageTime);
|
return this.timeUtil.getTimestamp() > message.dt + message.maxStorageTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
||||||
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
||||||
import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper";
|
import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper";
|
||||||
@ -358,8 +357,8 @@ export class GameController
|
|||||||
for (const positionToAdd of positionsToAdd)
|
for (const positionToAdd of positionsToAdd)
|
||||||
{
|
{
|
||||||
// Exists already, add new items to existing positions pool
|
// Exists already, add new items to existing positions pool
|
||||||
const existingLootPosition = mapLooseLoot.spawnpoints.find((x) =>
|
const existingLootPosition = mapLooseLoot.spawnpoints.find(x =>
|
||||||
x.template.Id === positionToAdd.template.Id
|
x.template.Id === positionToAdd.template.Id,
|
||||||
);
|
);
|
||||||
if (existingLootPosition)
|
if (existingLootPosition)
|
||||||
{
|
{
|
||||||
@ -389,7 +388,7 @@ export class GameController
|
|||||||
const mapLootAdjustmentsDict = adjustments[mapId];
|
const mapLootAdjustmentsDict = adjustments[mapId];
|
||||||
for (const lootKey in mapLootAdjustmentsDict)
|
for (const lootKey in mapLootAdjustmentsDict)
|
||||||
{
|
{
|
||||||
const lootPostionToAdjust = mapLooseLootData.spawnpoints.find((x) => x.template.Id === lootKey);
|
const lootPostionToAdjust = mapLooseLootData.spawnpoints.find(x => x.template.Id === lootKey);
|
||||||
if (!lootPostionToAdjust)
|
if (!lootPostionToAdjust)
|
||||||
{
|
{
|
||||||
this.logger.warning(`Unable to adjust loot position: ${lootKey} on map: ${mapId}`);
|
this.logger.warning(`Unable to adjust loot position: ${lootKey} on map: ${mapId}`);
|
||||||
@ -422,7 +421,7 @@ export class GameController
|
|||||||
|
|
||||||
for (const botToLimit of this.locationConfig.botTypeLimits[mapId])
|
for (const botToLimit of this.locationConfig.botTypeLimits[mapId])
|
||||||
{
|
{
|
||||||
const index = map.base.MinMaxBots.findIndex((x) => x.WildSpawnType === botToLimit.type);
|
const index = map.base.MinMaxBots.findIndex(x => x.WildSpawnType === botToLimit.type);
|
||||||
if (index !== -1)
|
if (index !== -1)
|
||||||
{
|
{
|
||||||
// Existing bot type found in MinMaxBots array, edit
|
// Existing bot type found in MinMaxBots array, edit
|
||||||
@ -450,9 +449,9 @@ export class GameController
|
|||||||
public getGameConfig(sessionID: string): IGameConfigResponse
|
public getGameConfig(sessionID: string): IGameConfigResponse
|
||||||
{
|
{
|
||||||
const profile = this.profileHelper.getPmcProfile(sessionID);
|
const profile = this.profileHelper.getPmcProfile(sessionID);
|
||||||
const gameTime =
|
const gameTime
|
||||||
profile.Stats?.Eft.OverallCounters.Items?.find((counter) =>
|
= profile.Stats?.Eft.OverallCounters.Items?.find(counter =>
|
||||||
counter.Key.includes("LifeTime") && counter.Key.includes("Pmc")
|
counter.Key.includes("LifeTime") && counter.Key.includes("Pmc"),
|
||||||
)?.Value ?? 0;
|
)?.Value ?? 0;
|
||||||
|
|
||||||
const config: IGameConfigResponse = {
|
const config: IGameConfigResponse = {
|
||||||
@ -589,12 +588,12 @@ export class GameController
|
|||||||
let hpRegenPerHour = 456.6;
|
let hpRegenPerHour = 456.6;
|
||||||
|
|
||||||
// Set new values, whatever is smallest
|
// Set new values, whatever is smallest
|
||||||
energyRegenPerHour += pmcProfile.Bonuses.filter((bonus) => bonus.type === BonusType.ENERGY_REGENERATION)
|
energyRegenPerHour += pmcProfile.Bonuses.filter(bonus => bonus.type === BonusType.ENERGY_REGENERATION)
|
||||||
.reduce((sum, curr) => sum + curr.value, 0);
|
.reduce((sum, curr) => sum + curr.value, 0);
|
||||||
hydrationRegenPerHour += pmcProfile.Bonuses.filter((bonus) =>
|
hydrationRegenPerHour += pmcProfile.Bonuses.filter(bonus =>
|
||||||
bonus.type === BonusType.HYDRATION_REGENERATION
|
bonus.type === BonusType.HYDRATION_REGENERATION,
|
||||||
).reduce((sum, curr) => sum + curr.value, 0);
|
).reduce((sum, curr) => sum + curr.value, 0);
|
||||||
hpRegenPerHour += pmcProfile.Bonuses.filter((bonus) => bonus.type === BonusType.HEALTH_REGENERATION).reduce(
|
hpRegenPerHour += pmcProfile.Bonuses.filter(bonus => bonus.type === BonusType.HEALTH_REGENERATION).reduce(
|
||||||
(sum, curr) => sum + curr.value,
|
(sum, curr) => sum + curr.value,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
@ -691,7 +690,7 @@ export class GameController
|
|||||||
|
|
||||||
for (const wave of location.base.waves ?? [])
|
for (const wave of location.base.waves ?? [])
|
||||||
{
|
{
|
||||||
if ((wave.slots_max - wave.slots_min === 0))
|
if (wave.slots_max - wave.slots_min === 0)
|
||||||
{
|
{
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Fixed ${wave.WildSpawnType} Spawn: ${locationKey} wave: ${wave.number} of type: ${wave.WildSpawnType} in zone: ${wave.SpawnPoints} with Max Slots of ${wave.slots_max}`,
|
`Fixed ${wave.WildSpawnType} Spawn: ${locationKey} wave: ${wave.number} of type: ${wave.WildSpawnType} in zone: ${wave.SpawnPoints} with Max Slots of ${wave.slots_max}`,
|
||||||
@ -729,13 +728,13 @@ export class GameController
|
|||||||
const currentTimeStamp = this.timeUtil.getTimestamp();
|
const currentTimeStamp = this.timeUtil.getTimestamp();
|
||||||
|
|
||||||
// One day post-profile creation
|
// One day post-profile creation
|
||||||
if (currentTimeStamp > (timeStampProfileCreated + oneDaySeconds))
|
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds)
|
||||||
{
|
{
|
||||||
this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 1);
|
this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Two day post-profile creation
|
// Two day post-profile creation
|
||||||
if (currentTimeStamp > (timeStampProfileCreated + (oneDaySeconds * 2)))
|
if (currentTimeStamp > timeStampProfileCreated + oneDaySeconds * 2)
|
||||||
{
|
{
|
||||||
this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 2);
|
this.giftService.sendPraporStartingGift(pmcProfile.sessionId, 2);
|
||||||
}
|
}
|
||||||
@ -761,7 +760,7 @@ export class GameController
|
|||||||
// Wave has size that makes it candidate for splitting
|
// Wave has size that makes it candidate for splitting
|
||||||
if (
|
if (
|
||||||
wave.slots_max - wave.slots_min
|
wave.slots_max - wave.slots_min
|
||||||
>= this.locationConfig.splitWaveIntoSingleSpawnsSettings.waveSizeThreshold
|
>= this.locationConfig.splitWaveIntoSingleSpawnsSettings.waveSizeThreshold
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Get count of bots to be spawned in wave
|
// Get count of bots to be spawned in wave
|
||||||
@ -832,8 +831,8 @@ export class GameController
|
|||||||
{
|
{
|
||||||
const modDetails = activeMods[modKey];
|
const modDetails = activeMods[modKey];
|
||||||
if (
|
if (
|
||||||
fullProfile.aki.mods.some((x) =>
|
fullProfile.aki.mods.some(x =>
|
||||||
x.author === modDetails.author && x.name === modDetails.name && x.version === modDetails.version
|
x.author === modDetails.author && x.name === modDetails.name && x.version === modDetails.version,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -948,8 +947,8 @@ export class GameController
|
|||||||
protected adjustLabsRaiderSpawnRate(): void
|
protected adjustLabsRaiderSpawnRate(): void
|
||||||
{
|
{
|
||||||
const labsBase = this.databaseServer.getTables().locations.laboratory.base;
|
const labsBase = this.databaseServer.getTables().locations.laboratory.base;
|
||||||
const nonTriggerLabsBossSpawns = labsBase.BossLocationSpawn.filter((x) =>
|
const nonTriggerLabsBossSpawns = labsBase.BossLocationSpawn.filter(x =>
|
||||||
x.TriggerId === "" && x.TriggerName === ""
|
x.TriggerId === "" && x.TriggerName === "",
|
||||||
);
|
);
|
||||||
if (nonTriggerLabsBossSpawns)
|
if (nonTriggerLabsBossSpawns)
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
|
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
|
||||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { HealthHelper } from "@spt-aki/helpers/HealthHelper";
|
import { HealthHelper } from "@spt-aki/helpers/HealthHelper";
|
||||||
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
|
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
@ -66,7 +65,7 @@ export class HealthController
|
|||||||
const output = this.eventOutputHolder.getOutput(sessionID);
|
const output = this.eventOutputHolder.getOutput(sessionID);
|
||||||
|
|
||||||
// Update medkit used (hpresource)
|
// Update medkit used (hpresource)
|
||||||
const healingItemToUse = pmcData.Inventory.items.find((item) => item._id === request.item);
|
const healingItemToUse = pmcData.Inventory.items.find(item => item._id === request.item);
|
||||||
if (!healingItemToUse)
|
if (!healingItemToUse)
|
||||||
{
|
{
|
||||||
const errorMessage = this.localisationService.getText(
|
const errorMessage = this.localisationService.getText(
|
||||||
@ -114,7 +113,7 @@ export class HealthController
|
|||||||
const output = this.eventOutputHolder.getOutput(sessionID);
|
const output = this.eventOutputHolder.getOutput(sessionID);
|
||||||
let resourceLeft = 0;
|
let resourceLeft = 0;
|
||||||
|
|
||||||
const itemToConsume = pmcData.Inventory.items.find((x) => x._id === request.item);
|
const itemToConsume = pmcData.Inventory.items.find(x => x._id === request.item);
|
||||||
if (!itemToConsume)
|
if (!itemToConsume)
|
||||||
{
|
{
|
||||||
// Item not found, very bad
|
// Item not found, very bad
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ScavCaseRewardGenerator } from "@spt-aki/generators/ScavCaseRewardGenerator";
|
import { ScavCaseRewardGenerator } from "@spt-aki/generators/ScavCaseRewardGenerator";
|
||||||
import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper";
|
import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper";
|
||||||
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
|
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
|
||||||
@ -106,7 +105,7 @@ export class HideoutController
|
|||||||
{
|
{
|
||||||
const items = request.items.map((reqItem) =>
|
const items = request.items.map((reqItem) =>
|
||||||
{
|
{
|
||||||
const item = pmcData.Inventory.items.find((invItem) => invItem._id === reqItem.id);
|
const item = pmcData.Inventory.items.find(invItem => invItem._id === reqItem.id);
|
||||||
return { inventoryItem: item, requestedItem: reqItem };
|
return { inventoryItem: item, requestedItem: reqItem };
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -139,7 +138,7 @@ export class HideoutController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Construction time management
|
// Construction time management
|
||||||
const profileHideoutArea = pmcData.Hideout.Areas.find((area) => area.type === request.areaType);
|
const profileHideoutArea = pmcData.Hideout.Areas.find(area => area.type === request.areaType);
|
||||||
if (!profileHideoutArea)
|
if (!profileHideoutArea)
|
||||||
{
|
{
|
||||||
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
||||||
@ -148,8 +147,8 @@ export class HideoutController
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hideoutDataDb = this.databaseServer.getTables().hideout.areas.find((area) =>
|
const hideoutDataDb = this.databaseServer.getTables().hideout.areas.find(area =>
|
||||||
area.type === request.areaType
|
area.type === request.areaType,
|
||||||
);
|
);
|
||||||
if (!hideoutDataDb)
|
if (!hideoutDataDb)
|
||||||
{
|
{
|
||||||
@ -192,7 +191,7 @@ export class HideoutController
|
|||||||
{
|
{
|
||||||
const db = this.databaseServer.getTables();
|
const db = this.databaseServer.getTables();
|
||||||
|
|
||||||
const profileHideoutArea = pmcData.Hideout.Areas.find((area) => area.type === request.areaType);
|
const profileHideoutArea = pmcData.Hideout.Areas.find(area => area.type === request.areaType);
|
||||||
if (!profileHideoutArea)
|
if (!profileHideoutArea)
|
||||||
{
|
{
|
||||||
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
||||||
@ -206,7 +205,7 @@ export class HideoutController
|
|||||||
profileHideoutArea.completeTime = 0;
|
profileHideoutArea.completeTime = 0;
|
||||||
profileHideoutArea.constructing = false;
|
profileHideoutArea.constructing = false;
|
||||||
|
|
||||||
const hideoutData = db.hideout.areas.find((area) => area.type === profileHideoutArea.type);
|
const hideoutData = db.hideout.areas.find(area => area.type === profileHideoutArea.type);
|
||||||
if (!hideoutData)
|
if (!hideoutData)
|
||||||
{
|
{
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
@ -264,11 +263,11 @@ export class HideoutController
|
|||||||
*/
|
*/
|
||||||
protected checkAndUpgradeWall(pmcData: IPmcData): void
|
protected checkAndUpgradeWall(pmcData: IPmcData): void
|
||||||
{
|
{
|
||||||
const medStation = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.MEDSTATION);
|
const medStation = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.MEDSTATION);
|
||||||
const waterCollector = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.WATER_COLLECTOR);
|
const waterCollector = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.WATER_COLLECTOR);
|
||||||
if (medStation?.level >= 1 && waterCollector?.level >= 1)
|
if (medStation?.level >= 1 && waterCollector?.level >= 1)
|
||||||
{
|
{
|
||||||
const wall = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.EMERGENCY_WALL);
|
const wall = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.EMERGENCY_WALL);
|
||||||
if (wall?.level === 0)
|
if (wall?.level === 0)
|
||||||
{
|
{
|
||||||
wall.level = 3;
|
wall.level = 3;
|
||||||
@ -310,8 +309,8 @@ export class HideoutController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Some areas like gun stand have a child area linked to it, it needs to do the same as above
|
// Some areas like gun stand have a child area linked to it, it needs to do the same as above
|
||||||
const childDbArea = this.databaseServer.getTables().hideout.areas.find((x) =>
|
const childDbArea = this.databaseServer.getTables().hideout.areas.find(x =>
|
||||||
x.parentArea === dbHideoutArea._id
|
x.parentArea === dbHideoutArea._id,
|
||||||
);
|
);
|
||||||
if (childDbArea)
|
if (childDbArea)
|
||||||
{
|
{
|
||||||
@ -322,8 +321,8 @@ export class HideoutController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set child area level to same as parent area
|
// Set child area level to same as parent area
|
||||||
pmcData.Hideout.Areas.find((x) => x.type === childDbArea.type).level = pmcData.Hideout.Areas.find((x) =>
|
pmcData.Hideout.Areas.find(x => x.type === childDbArea.type).level = pmcData.Hideout.Areas.find(x =>
|
||||||
x.type === profileParentHideoutArea.type
|
x.type === profileParentHideoutArea.type,
|
||||||
).level;
|
).level;
|
||||||
|
|
||||||
// Add/upgrade stash item in player inventory
|
// Add/upgrade stash item in player inventory
|
||||||
@ -343,7 +342,7 @@ export class HideoutController
|
|||||||
*/
|
*/
|
||||||
protected addUpdateInventoryItemToProfile(pmcData: IPmcData, dbHideoutData: IHideoutArea, hideoutStage: Stage): void
|
protected addUpdateInventoryItemToProfile(pmcData: IPmcData, dbHideoutData: IHideoutArea, hideoutStage: Stage): void
|
||||||
{
|
{
|
||||||
const existingInventoryItem = pmcData.Inventory.items.find((x) => x._id === dbHideoutData._id);
|
const existingInventoryItem = pmcData.Inventory.items.find(x => x._id === dbHideoutData._id);
|
||||||
if (existingInventoryItem)
|
if (existingInventoryItem)
|
||||||
{
|
{
|
||||||
// Update existing items container tpl to point to new id (tpl)
|
// Update existing items container tpl to point to new id (tpl)
|
||||||
@ -400,11 +399,11 @@ export class HideoutController
|
|||||||
|
|
||||||
const itemsToAdd = Object.entries(addItemToHideoutRequest.items).map((kvp) =>
|
const itemsToAdd = Object.entries(addItemToHideoutRequest.items).map((kvp) =>
|
||||||
{
|
{
|
||||||
const item = pmcData.Inventory.items.find((invItem) => invItem._id === kvp[1].id);
|
const item = pmcData.Inventory.items.find(invItem => invItem._id === kvp[1].id);
|
||||||
return { inventoryItem: item, requestedItem: kvp[1], slot: kvp[0] };
|
return { inventoryItem: item, requestedItem: kvp[1], slot: kvp[0] };
|
||||||
});
|
});
|
||||||
|
|
||||||
const hideoutArea = pmcData.Hideout.Areas.find((area) => area.type === addItemToHideoutRequest.areaType);
|
const hideoutArea = pmcData.Hideout.Areas.find(area => area.type === addItemToHideoutRequest.areaType);
|
||||||
if (!hideoutArea)
|
if (!hideoutArea)
|
||||||
{
|
{
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
@ -431,7 +430,7 @@ export class HideoutController
|
|||||||
|
|
||||||
// Add item to area.slots
|
// Add item to area.slots
|
||||||
const destinationLocationIndex = Number(item.slot);
|
const destinationLocationIndex = Number(item.slot);
|
||||||
const hideoutSlotIndex = hideoutArea.slots.findIndex((x) => x.locationIndex === destinationLocationIndex);
|
const hideoutSlotIndex = hideoutArea.slots.findIndex(x => x.locationIndex === destinationLocationIndex);
|
||||||
hideoutArea.slots[hideoutSlotIndex].item = [{
|
hideoutArea.slots[hideoutSlotIndex].item = [{
|
||||||
_id: item.inventoryItem._id,
|
_id: item.inventoryItem._id,
|
||||||
_tpl: item.inventoryItem._tpl,
|
_tpl: item.inventoryItem._tpl,
|
||||||
@ -463,7 +462,7 @@ export class HideoutController
|
|||||||
{
|
{
|
||||||
const output = this.eventOutputHolder.getOutput(sessionID);
|
const output = this.eventOutputHolder.getOutput(sessionID);
|
||||||
|
|
||||||
const hideoutArea = pmcData.Hideout.Areas.find((area) => area.type === request.areaType);
|
const hideoutArea = pmcData.Hideout.Areas.find(area => area.type === request.areaType);
|
||||||
if (!hideoutArea)
|
if (!hideoutArea)
|
||||||
{
|
{
|
||||||
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
||||||
@ -520,7 +519,7 @@ export class HideoutController
|
|||||||
const slotIndexToRemove = removeResourceRequest.slots[0];
|
const slotIndexToRemove = removeResourceRequest.slots[0];
|
||||||
|
|
||||||
// Assume only one item in slot
|
// Assume only one item in slot
|
||||||
const itemToReturn = hideoutArea.slots.find((slot) => slot.locationIndex === slotIndexToRemove).item[0];
|
const itemToReturn = hideoutArea.slots.find(slot => slot.locationIndex === slotIndexToRemove).item[0];
|
||||||
|
|
||||||
const request: IAddItemDirectRequest = {
|
const request: IAddItemDirectRequest = {
|
||||||
itemWithModsToAdd: [itemToReturn],
|
itemWithModsToAdd: [itemToReturn],
|
||||||
@ -537,7 +536,7 @@ export class HideoutController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove items from slot, locationIndex remains
|
// Remove items from slot, locationIndex remains
|
||||||
const hideoutSlotIndex = hideoutArea.slots.findIndex((slot) => slot.locationIndex === slotIndexToRemove);
|
const hideoutSlotIndex = hideoutArea.slots.findIndex(slot => slot.locationIndex === slotIndexToRemove);
|
||||||
hideoutArea.slots[hideoutSlotIndex].item = undefined;
|
hideoutArea.slots[hideoutSlotIndex].item = undefined;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
@ -562,7 +561,7 @@ export class HideoutController
|
|||||||
// Force a production update (occur before area is toggled as it could be generator and doing it after generator enabled would cause incorrect calculaton of production progress)
|
// Force a production update (occur before area is toggled as it could be generator and doing it after generator enabled would cause incorrect calculaton of production progress)
|
||||||
this.hideoutHelper.updatePlayerHideout(sessionID);
|
this.hideoutHelper.updatePlayerHideout(sessionID);
|
||||||
|
|
||||||
const hideoutArea = pmcData.Hideout.Areas.find((area) => area.type === request.areaType);
|
const hideoutArea = pmcData.Hideout.Areas.find(area => area.type === request.areaType);
|
||||||
if (!hideoutArea)
|
if (!hideoutArea)
|
||||||
{
|
{
|
||||||
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
||||||
@ -592,20 +591,20 @@ export class HideoutController
|
|||||||
this.hideoutHelper.registerProduction(pmcData, body, sessionID);
|
this.hideoutHelper.registerProduction(pmcData, body, sessionID);
|
||||||
|
|
||||||
// Find the recipe of the production
|
// Find the recipe of the production
|
||||||
const recipe = this.databaseServer.getTables().hideout.production.find((p) => p._id === body.recipeId);
|
const recipe = this.databaseServer.getTables().hideout.production.find(p => p._id === body.recipeId);
|
||||||
|
|
||||||
// Find the actual amount of items we need to remove because body can send weird data
|
// Find the actual amount of items we need to remove because body can send weird data
|
||||||
const recipeRequirementsClone = this.jsonUtil.clone(
|
const recipeRequirementsClone = this.jsonUtil.clone(
|
||||||
recipe.requirements.filter((i) => i.type === "Item" || i.type === "Tool"),
|
recipe.requirements.filter(i => i.type === "Item" || i.type === "Tool"),
|
||||||
);
|
);
|
||||||
|
|
||||||
const output = this.eventOutputHolder.getOutput(sessionID);
|
const output = this.eventOutputHolder.getOutput(sessionID);
|
||||||
const itemsToDelete = body.items.concat(body.tools);
|
const itemsToDelete = body.items.concat(body.tools);
|
||||||
for (const itemToDelete of itemsToDelete)
|
for (const itemToDelete of itemsToDelete)
|
||||||
{
|
{
|
||||||
const itemToCheck = pmcData.Inventory.items.find((i) => i._id === itemToDelete.id);
|
const itemToCheck = pmcData.Inventory.items.find(i => i._id === itemToDelete.id);
|
||||||
const requirement = recipeRequirementsClone.find((requirement) =>
|
const requirement = recipeRequirementsClone.find(requirement =>
|
||||||
requirement.templateId === itemToCheck._tpl
|
requirement.templateId === itemToCheck._tpl,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle tools not having a `count`, but always only requiring 1
|
// Handle tools not having a `count`, but always only requiring 1
|
||||||
@ -645,7 +644,7 @@ export class HideoutController
|
|||||||
|
|
||||||
for (const requestedItem of body.items)
|
for (const requestedItem of body.items)
|
||||||
{
|
{
|
||||||
const inventoryItem = pmcData.Inventory.items.find((item) => item._id === requestedItem.id);
|
const inventoryItem = pmcData.Inventory.items.find(item => item._id === requestedItem.id);
|
||||||
if (!inventoryItem)
|
if (!inventoryItem)
|
||||||
{
|
{
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
@ -667,7 +666,7 @@ export class HideoutController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const recipe = this.databaseServer.getTables().hideout.scavcase.find((r) => r._id === body.recipeId);
|
const recipe = this.databaseServer.getTables().hideout.scavcase.find(r => r._id === body.recipeId);
|
||||||
if (!recipe)
|
if (!recipe)
|
||||||
{
|
{
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
@ -679,13 +678,12 @@ export class HideoutController
|
|||||||
// @Important: Here we need to be very exact:
|
// @Important: Here we need to be very exact:
|
||||||
// - normal recipe: Production time value is stored in attribute "productionTime" with small "p"
|
// - normal recipe: Production time value is stored in attribute "productionTime" with small "p"
|
||||||
// - scav case recipe: Production time value is stored in attribute "ProductionTime" with capital "P"
|
// - scav case recipe: Production time value is stored in attribute "ProductionTime" with capital "P"
|
||||||
const adjustedCraftTime = recipe.ProductionTime
|
const adjustedCraftTime = recipe.ProductionTime - this.hideoutHelper.getSkillProductionTimeReduction(
|
||||||
- this.hideoutHelper.getSkillProductionTimeReduction(
|
pmcData,
|
||||||
pmcData,
|
recipe.ProductionTime,
|
||||||
recipe.ProductionTime,
|
SkillTypes.CRAFTING,
|
||||||
SkillTypes.CRAFTING,
|
this.databaseServer.getTables().globals.config.SkillsSettings.Crafting.CraftTimeReductionPerLevel,
|
||||||
this.databaseServer.getTables().globals.config.SkillsSettings.Crafting.CraftTimeReductionPerLevel,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
const modifiedScavCaseTime = this.getScavCaseTime(pmcData, adjustedCraftTime);
|
const modifiedScavCaseTime = this.getScavCaseTime(pmcData, adjustedCraftTime);
|
||||||
|
|
||||||
@ -772,7 +770,7 @@ export class HideoutController
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
const recipe = hideoutDb.production.find((r) => r._id === request.recipeId);
|
const recipe = hideoutDb.production.find(r => r._id === request.recipeId);
|
||||||
if (recipe)
|
if (recipe)
|
||||||
{
|
{
|
||||||
this.handleRecipe(sessionID, recipe, pmcData, request, output);
|
this.handleRecipe(sessionID, recipe, pmcData, request, output);
|
||||||
@ -780,7 +778,7 @@ export class HideoutController
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
const scavCase = hideoutDb.scavcase.find((r) => r._id === request.recipeId);
|
const scavCase = hideoutDb.scavcase.find(r => r._id === request.recipeId);
|
||||||
if (scavCase)
|
if (scavCase)
|
||||||
{
|
{
|
||||||
this.handleScavCase(sessionID, pmcData, request, output);
|
this.handleScavCase(sessionID, pmcData, request, output);
|
||||||
@ -938,7 +936,7 @@ export class HideoutController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the recipe is the same as the last one - get bonus when crafting same thing multiple times
|
// Check if the recipe is the same as the last one - get bonus when crafting same thing multiple times
|
||||||
const area = pmcData.Hideout.Areas.find((area) => area.type === recipe.areaType);
|
const area = pmcData.Hideout.Areas.find(area => area.type === recipe.areaType);
|
||||||
if (area && request.recipeId !== area.lastRecipe)
|
if (area && request.recipeId !== area.lastRecipe)
|
||||||
{
|
{
|
||||||
// 1 point per craft upon the end of production for alternating between 2 different crafting recipes in the same module
|
// 1 point per craft upon the end of production for alternating between 2 different crafting recipes in the same module
|
||||||
@ -948,7 +946,7 @@ export class HideoutController
|
|||||||
// Update variable with time spent crafting item(s)
|
// Update variable with time spent crafting item(s)
|
||||||
// 1 point per 8 hours of crafting
|
// 1 point per 8 hours of crafting
|
||||||
hoursCrafting += recipe.productionTime;
|
hoursCrafting += recipe.productionTime;
|
||||||
if ((hoursCrafting / this.hideoutConfig.hoursForSkillCrafting) >= 1)
|
if (hoursCrafting / this.hideoutConfig.hoursForSkillCrafting >= 1)
|
||||||
{
|
{
|
||||||
// Spent enough time crafting to get a bonus xp multipler
|
// Spent enough time crafting to get a bonus xp multipler
|
||||||
const multiplierCrafting = Math.floor(hoursCrafting / this.hideoutConfig.hoursForSkillCrafting);
|
const multiplierCrafting = Math.floor(hoursCrafting / this.hideoutConfig.hoursForSkillCrafting);
|
||||||
@ -1016,7 +1014,7 @@ export class HideoutController
|
|||||||
{
|
{
|
||||||
this.profileHelper.addSkillPointsToPlayer(pmcData, SkillTypes.CRAFTING, craftingExpAmount);
|
this.profileHelper.addSkillPointsToPlayer(pmcData, SkillTypes.CRAFTING, craftingExpAmount);
|
||||||
|
|
||||||
const intellectAmountToGive = 0.5 * (Math.round(craftingExpAmount / 15));
|
const intellectAmountToGive = 0.5 * Math.round(craftingExpAmount / 15);
|
||||||
if (intellectAmountToGive > 0)
|
if (intellectAmountToGive > 0)
|
||||||
{
|
{
|
||||||
this.profileHelper.addSkillPointsToPlayer(pmcData, SkillTypes.INTELLECT, intellectAmountToGive);
|
this.profileHelper.addSkillPointsToPlayer(pmcData, SkillTypes.INTELLECT, intellectAmountToGive);
|
||||||
@ -1189,14 +1187,14 @@ export class HideoutController
|
|||||||
public recordShootingRangePoints(sessionId: string, pmcData: IPmcData, request: IRecordShootingRangePoints): void
|
public recordShootingRangePoints(sessionId: string, pmcData: IPmcData, request: IRecordShootingRangePoints): void
|
||||||
{
|
{
|
||||||
// Check if counter exists, add placeholder if it doesnt
|
// Check if counter exists, add placeholder if it doesnt
|
||||||
if (!pmcData.Stats.Eft.OverallCounters.Items.find((x) => x.Key.includes("ShootingRangePoints")))
|
if (!pmcData.Stats.Eft.OverallCounters.Items.find(x => x.Key.includes("ShootingRangePoints")))
|
||||||
{
|
{
|
||||||
pmcData.Stats.Eft.OverallCounters.Items.push({ Key: ["ShootingRangePoints"], Value: 0 });
|
pmcData.Stats.Eft.OverallCounters.Items.push({ Key: ["ShootingRangePoints"], Value: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find counter by key and update value
|
// Find counter by key and update value
|
||||||
const shootingRangeHighScore = pmcData.Stats.Eft.OverallCounters.Items.find((x) =>
|
const shootingRangeHighScore = pmcData.Stats.Eft.OverallCounters.Items.find(x =>
|
||||||
x.Key.includes("ShootingRangePoints")
|
x.Key.includes("ShootingRangePoints"),
|
||||||
);
|
);
|
||||||
shootingRangeHighScore.Value = request.points;
|
shootingRangeHighScore.Value = request.points;
|
||||||
}
|
}
|
||||||
@ -1218,7 +1216,7 @@ export class HideoutController
|
|||||||
// Create mapping of required item with corrisponding item from player inventory
|
// Create mapping of required item with corrisponding item from player inventory
|
||||||
const items = request.items.map((reqItem) =>
|
const items = request.items.map((reqItem) =>
|
||||||
{
|
{
|
||||||
const item = pmcData.Inventory.items.find((invItem) => invItem._id === reqItem.id);
|
const item = pmcData.Inventory.items.find(invItem => invItem._id === reqItem.id);
|
||||||
return { inventoryItem: item, requestedItem: reqItem };
|
return { inventoryItem: item, requestedItem: reqItem };
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1248,14 +1246,14 @@ export class HideoutController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const profileHideoutArea = pmcData.Hideout.Areas.find((x) => x.type === request.areaType);
|
const profileHideoutArea = pmcData.Hideout.Areas.find(x => x.type === request.areaType);
|
||||||
if (!profileHideoutArea)
|
if (!profileHideoutArea)
|
||||||
{
|
{
|
||||||
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
this.logger.error(this.localisationService.getText("hideout-unable_to_find_area", request.areaType));
|
||||||
return this.httpResponse.appendErrorToOutput(output);
|
return this.httpResponse.appendErrorToOutput(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hideoutDbData = this.databaseServer.getTables().hideout.areas.find((x) => x.type === request.areaType);
|
const hideoutDbData = this.databaseServer.getTables().hideout.areas.find(x => x.type === request.areaType);
|
||||||
if (!hideoutDbData)
|
if (!hideoutDbData)
|
||||||
{
|
{
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
||||||
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
||||||
import { PlayerScavGenerator } from "@spt-aki/generators/PlayerScavGenerator";
|
import { PlayerScavGenerator } from "@spt-aki/generators/PlayerScavGenerator";
|
||||||
@ -204,8 +203,8 @@ export class InraidController
|
|||||||
if (locationName === "lighthouse" && postRaidRequest.profile.Info.Side.toLowerCase() === "usec")
|
if (locationName === "lighthouse" && postRaidRequest.profile.Info.Side.toLowerCase() === "usec")
|
||||||
{
|
{
|
||||||
// Decrement counter if it exists, don't go below 0
|
// Decrement counter if it exists, don't go below 0
|
||||||
const remainingCounter = serverPmcProfile?.Stats.Eft.OverallCounters.Items.find((x) =>
|
const remainingCounter = serverPmcProfile?.Stats.Eft.OverallCounters.Items.find(x =>
|
||||||
x.Key.includes("UsecRaidRemainKills")
|
x.Key.includes("UsecRaidRemainKills"),
|
||||||
);
|
);
|
||||||
if (remainingCounter?.Value > 0)
|
if (remainingCounter?.Value > 0)
|
||||||
{
|
{
|
||||||
@ -229,9 +228,9 @@ export class InraidController
|
|||||||
// Not dead
|
// Not dead
|
||||||
|
|
||||||
// Check for cultist amulets in special slot (only slot it can fit)
|
// Check for cultist amulets in special slot (only slot it can fit)
|
||||||
const amuletOnPlayer = serverPmcProfile.Inventory.items.filter((item) =>
|
const amuletOnPlayer = serverPmcProfile.Inventory.items.filter(item =>
|
||||||
item.slotId?.startsWith("SpecialSlot")
|
item.slotId?.startsWith("SpecialSlot"),
|
||||||
).find((item) => item._tpl === "64d0b40fbe2eed70e254e2d4");
|
).find(item => item._tpl === "64d0b40fbe2eed70e254e2d4");
|
||||||
if (amuletOnPlayer)
|
if (amuletOnPlayer)
|
||||||
{
|
{
|
||||||
// No charges left, delete it
|
// No charges left, delete it
|
||||||
@ -250,8 +249,8 @@ export class InraidController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const victims = postRaidRequest.profile.Stats.Eft.Victims.filter((x) =>
|
const victims = postRaidRequest.profile.Stats.Eft.Victims.filter(x =>
|
||||||
["sptbear", "sptusec"].includes(x.Role.toLowerCase())
|
["sptbear", "sptusec"].includes(x.Role.toLowerCase()),
|
||||||
);
|
);
|
||||||
if (victims?.length > 0)
|
if (victims?.length > 0)
|
||||||
{
|
{
|
||||||
@ -283,9 +282,13 @@ export class InraidController
|
|||||||
// Find and remove the completed condition from profile if player died, otherwise quest is stuck in limbo
|
// Find and remove the completed condition from profile if player died, otherwise quest is stuck in limbo
|
||||||
// and quest items cannot be picked up again
|
// and quest items cannot be picked up again
|
||||||
const allQuests = this.questHelper.getQuestsFromDb();
|
const allQuests = this.questHelper.getQuestsFromDb();
|
||||||
const activeQuestIdsInProfile = pmcData.Quests.filter((profileQuest) =>
|
const activeQuestIdsInProfile = pmcData.Quests.filter(
|
||||||
![QuestStatus.AvailableForStart, QuestStatus.Success, QuestStatus.Expired].includes(profileQuest.status)
|
profileQuest => ![
|
||||||
).map((x) => x.qid);
|
QuestStatus.AvailableForStart,
|
||||||
|
QuestStatus.Success,
|
||||||
|
QuestStatus.Expired,
|
||||||
|
].includes(profileQuest.status),
|
||||||
|
).map(x => x.qid);
|
||||||
for (const questItem of postRaidSaveRequest.profile.Stats.Eft.CarriedQuestItems)
|
for (const questItem of postRaidSaveRequest.profile.Stats.Eft.CarriedQuestItems)
|
||||||
{
|
{
|
||||||
// Get quest/find condition for carried quest item
|
// Get quest/find condition for carried quest item
|
||||||
@ -399,7 +402,7 @@ export class InraidController
|
|||||||
*/
|
*/
|
||||||
protected mergePmcAndScavEncyclopedias(primary: IPmcData, secondary: IPmcData): void
|
protected mergePmcAndScavEncyclopedias(primary: IPmcData, secondary: IPmcData): void
|
||||||
{
|
{
|
||||||
function extend(target: { [key: string]: boolean; }, source: Record<string, boolean>)
|
function extend(target: { [key: string]: boolean }, source: Record<string, boolean>)
|
||||||
{
|
{
|
||||||
for (const key in source)
|
for (const key in source)
|
||||||
{
|
{
|
||||||
@ -469,7 +472,7 @@ export class InraidController
|
|||||||
|
|
||||||
for (const quest of scavProfile.Quests)
|
for (const quest of scavProfile.Quests)
|
||||||
{
|
{
|
||||||
const pmcQuest = pmcProfile.Quests.find((x) => x.qid === quest.qid);
|
const pmcQuest = pmcProfile.Quests.find(x => x.qid === quest.qid);
|
||||||
if (!pmcQuest)
|
if (!pmcQuest)
|
||||||
{
|
{
|
||||||
this.logger.warning(`No PMC quest found for ID: ${quest.qid}`);
|
this.logger.warning(`No PMC quest found for ID: ${quest.qid}`);
|
||||||
@ -504,7 +507,7 @@ export class InraidController
|
|||||||
for (const scavCounter of Object.values(scavProfile.TaskConditionCounters))
|
for (const scavCounter of Object.values(scavProfile.TaskConditionCounters))
|
||||||
{
|
{
|
||||||
// If this is an achievement that isn't for the scav, don't process it
|
// If this is an achievement that isn't for the scav, don't process it
|
||||||
const achievement = achievements.find((achievement) => achievement.id === scavCounter.sourceId);
|
const achievement = achievements.find(achievement => achievement.id === scavCounter.sourceId);
|
||||||
if (achievement && achievement.side !== "Savage")
|
if (achievement && achievement.side !== "Savage")
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -541,7 +544,7 @@ export class InraidController
|
|||||||
*/
|
*/
|
||||||
protected isPlayerDead(statusOnExit: PlayerRaidEndState): boolean
|
protected isPlayerDead(statusOnExit: PlayerRaidEndState): boolean
|
||||||
{
|
{
|
||||||
return (statusOnExit !== PlayerRaidEndState.SURVIVED && statusOnExit !== PlayerRaidEndState.RUNNER);
|
return statusOnExit !== PlayerRaidEndState.SURVIVED && statusOnExit !== PlayerRaidEndState.RUNNER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -686,8 +689,8 @@ export class InraidController
|
|||||||
|
|
||||||
// Remove any items that were returned by the item delivery, but also insured, from the player's insurance list
|
// Remove any items that were returned by the item delivery, but also insured, from the player's insurance list
|
||||||
// This is to stop items being duplicated by being returned from both the item delivery, and insurance
|
// This is to stop items being duplicated by being returned from both the item delivery, and insurance
|
||||||
const deliveredItemIds = items.map((x) => x._id);
|
const deliveredItemIds = items.map(x => x._id);
|
||||||
pmcData.InsuredItems = pmcData.InsuredItems.filter((x) => !deliveredItemIds.includes(x.itemId));
|
pmcData.InsuredItems = pmcData.InsuredItems.filter(x => !deliveredItemIds.includes(x.itemId));
|
||||||
|
|
||||||
// Send the items to the player
|
// Send the items to the player
|
||||||
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
|
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
@ -113,7 +112,7 @@ export class InsuranceController
|
|||||||
this.logger.debug(`Found ${profileInsuranceDetails.length} insurance packages in profile ${sessionID}`);
|
this.logger.debug(`Found ${profileInsuranceDetails.length} insurance packages in profile ${sessionID}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return profileInsuranceDetails.filter((insured) => insuranceTime >= insured.scheduledTime);
|
return profileInsuranceDetails.filter(insured => insuranceTime >= insured.scheduledTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -161,7 +160,7 @@ export class InsuranceController
|
|||||||
*/
|
*/
|
||||||
protected countAllInsuranceItems(insurance: Insurance[]): number
|
protected countAllInsuranceItems(insurance: Insurance[]): number
|
||||||
{
|
{
|
||||||
return this.mathUtil.arraySum(insurance.map((ins) => ins.items.length));
|
return this.mathUtil.arraySum(insurance.map(ins => ins.items.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -174,11 +173,11 @@ export class InsuranceController
|
|||||||
protected removeInsurancePackageFromProfile(sessionID: string, insPackage: Insurance): void
|
protected removeInsurancePackageFromProfile(sessionID: string, insPackage: Insurance): void
|
||||||
{
|
{
|
||||||
const profile = this.saveServer.getProfile(sessionID);
|
const profile = this.saveServer.getProfile(sessionID);
|
||||||
profile.insurance = profile.insurance.filter((insurance) =>
|
profile.insurance = profile.insurance.filter(insurance =>
|
||||||
insurance.traderId !== insPackage.traderId
|
insurance.traderId !== insPackage.traderId
|
||||||
|| insurance.systemData.date !== insPackage.systemData.date
|
|| insurance.systemData.date !== insPackage.systemData.date
|
||||||
|| insurance.systemData.time !== insPackage.systemData.time
|
|| insurance.systemData.time !== insPackage.systemData.time
|
||||||
|| insurance.systemData.location !== insPackage.systemData.location
|
|| insurance.systemData.location !== insPackage.systemData.location,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.logger.debug(`Removed processed insurance package. Remaining packages: ${profile.insurance.length}`);
|
this.logger.debug(`Removed processed insurance package. Remaining packages: ${profile.insurance.length}`);
|
||||||
@ -201,8 +200,8 @@ export class InsuranceController
|
|||||||
let parentAttachmentsMap = this.populateParentAttachmentsMap(rootItemParentID, insured, itemsMap);
|
let parentAttachmentsMap = this.populateParentAttachmentsMap(rootItemParentID, insured, itemsMap);
|
||||||
|
|
||||||
// Check to see if any regular items are present.
|
// Check to see if any regular items are present.
|
||||||
const hasRegularItems = Array.from(itemsMap.values()).some((item) =>
|
const hasRegularItems = Array.from(itemsMap.values()).some(item =>
|
||||||
!this.itemHelper.isAttachmentAttached(item)
|
!this.itemHelper.isAttachmentAttached(item),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Process all items that are not attached, attachments; those are handled separately, by value.
|
// Process all items that are not attached, attachments; those are handled separately, by value.
|
||||||
@ -250,7 +249,7 @@ export class InsuranceController
|
|||||||
for (const insuredItem of insured.items)
|
for (const insuredItem of insured.items)
|
||||||
{
|
{
|
||||||
// Use the parent ID from the item to get the parent item.
|
// Use the parent ID from the item to get the parent item.
|
||||||
const parentItem = insured.items.find((item) => item._id === insuredItem.parentId);
|
const parentItem = insured.items.find(item => item._id === insuredItem.parentId);
|
||||||
|
|
||||||
// The parent (not the hideout) could not be found. Skip and warn.
|
// The parent (not the hideout) could not be found. Skip and warn.
|
||||||
if (!parentItem && insuredItem.parentId !== rootItemParentID)
|
if (!parentItem && insuredItem.parentId !== rootItemParentID)
|
||||||
@ -490,7 +489,7 @@ export class InsuranceController
|
|||||||
{
|
{
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Attachment ${index} Id: ${attachmentId} Tpl: ${
|
`Attachment ${index} Id: ${attachmentId} Tpl: ${
|
||||||
attachments.find((x) => x._id === attachmentId)?._tpl
|
attachments.find(x => x._id === attachmentId)?._tpl
|
||||||
} - Price: ${attachmentPrices[attachmentId]}`,
|
} - Price: ${attachmentPrices[attachmentId]}`,
|
||||||
);
|
);
|
||||||
index++;
|
index++;
|
||||||
@ -557,7 +556,7 @@ export class InsuranceController
|
|||||||
*/
|
*/
|
||||||
protected removeItemsFromInsurance(insured: Insurance, toDelete: Set<string>): void
|
protected removeItemsFromInsurance(insured: Insurance, toDelete: Set<string>): void
|
||||||
{
|
{
|
||||||
insured.items = insured.items.filter((item) => !toDelete.has(item._id));
|
insured.items = insured.items.filter(item => !toDelete.has(item._id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -746,6 +745,6 @@ export class InsuranceController
|
|||||||
// Represents an insurance item that has had it's common locale-name and value added to it.
|
// Represents an insurance item that has had it's common locale-name and value added to it.
|
||||||
interface EnrichedItem extends Item
|
interface EnrichedItem extends Item
|
||||||
{
|
{
|
||||||
name: string;
|
name: string
|
||||||
dynamicPrice: number;
|
dynamicPrice: number
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { LootGenerator } from "@spt-aki/generators/LootGenerator";
|
import { LootGenerator } from "@spt-aki/generators/LootGenerator";
|
||||||
import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper";
|
import { HideoutHelper } from "@spt-aki/helpers/HideoutHelper";
|
||||||
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
|
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
|
||||||
@ -107,7 +106,7 @@ export class InventoryController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for item in inventory before allowing internal transfer
|
// Check for item in inventory before allowing internal transfer
|
||||||
const originalItemLocation = ownerInventoryItems.from.find((item) => item._id === moveRequest.item);
|
const originalItemLocation = ownerInventoryItems.from.find(item => item._id === moveRequest.item);
|
||||||
if (!originalItemLocation)
|
if (!originalItemLocation)
|
||||||
{
|
{
|
||||||
// Internal item move but item never existed, possible dupe glitch
|
// Internal item move but item never existed, possible dupe glitch
|
||||||
@ -169,7 +168,7 @@ export class InventoryController
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const profileToRemoveItemFrom = (!request.fromOwner || request.fromOwner.id === pmcData._id)
|
const profileToRemoveItemFrom = !request.fromOwner || request.fromOwner.id === pmcData._id
|
||||||
? pmcData
|
? pmcData
|
||||||
: this.profileHelper.getFullProfile(sessionID).characters.scav;
|
: this.profileHelper.getFullProfile(sessionID).characters.scav;
|
||||||
|
|
||||||
@ -198,12 +197,12 @@ export class InventoryController
|
|||||||
// Handle cartridge edge-case
|
// Handle cartridge edge-case
|
||||||
if (!request.container.location && request.container.container === "cartridges")
|
if (!request.container.location && request.container.container === "cartridges")
|
||||||
{
|
{
|
||||||
const matchingItems = inventoryItems.to.filter((x) => x.parentId === request.container.id);
|
const matchingItems = inventoryItems.to.filter(x => x.parentId === request.container.id);
|
||||||
request.container.location = matchingItems.length; // Wrong location for first cartridge
|
request.container.location = matchingItems.length; // Wrong location for first cartridge
|
||||||
}
|
}
|
||||||
|
|
||||||
// The item being merged has three possible sources: pmc, scav or mail, getOwnerInventoryItems() handles getting correct one
|
// The item being merged has three possible sources: pmc, scav or mail, getOwnerInventoryItems() handles getting correct one
|
||||||
const itemToSplit = inventoryItems.from.find((x) => x._id === request.splitItem);
|
const itemToSplit = inventoryItems.from.find(x => x._id === request.splitItem);
|
||||||
if (!itemToSplit)
|
if (!itemToSplit)
|
||||||
{
|
{
|
||||||
const errorMessage = `Unable to split stack as source item: ${request.splitItem} cannot be found`;
|
const errorMessage = `Unable to split stack as source item: ${request.splitItem} cannot be found`;
|
||||||
@ -259,7 +258,7 @@ export class InventoryController
|
|||||||
const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID);
|
const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID);
|
||||||
|
|
||||||
// Get source item (can be from player or trader or mail)
|
// Get source item (can be from player or trader or mail)
|
||||||
const sourceItem = inventoryItems.from.find((x) => x._id === body.item);
|
const sourceItem = inventoryItems.from.find(x => x._id === body.item);
|
||||||
if (!sourceItem)
|
if (!sourceItem)
|
||||||
{
|
{
|
||||||
const errorMessage = `Unable to merge stacks as source item: ${body.with} cannot be found`;
|
const errorMessage = `Unable to merge stacks as source item: ${body.with} cannot be found`;
|
||||||
@ -271,7 +270,7 @@ export class InventoryController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get item being merged into
|
// Get item being merged into
|
||||||
const destinationItem = inventoryItems.to.find((x) => x._id === body.with);
|
const destinationItem = inventoryItems.to.find(x => x._id === body.with);
|
||||||
if (!destinationItem)
|
if (!destinationItem)
|
||||||
{
|
{
|
||||||
const errorMessage = `Unable to merge stacks as destination item: ${body.with} cannot be found`;
|
const errorMessage = `Unable to merge stacks as destination item: ${body.with} cannot be found`;
|
||||||
@ -282,7 +281,7 @@ export class InventoryController
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(destinationItem.upd?.StackObjectsCount))
|
if (!destinationItem.upd?.StackObjectsCount)
|
||||||
{
|
{
|
||||||
// No stackcount on destination, add one
|
// No stackcount on destination, add one
|
||||||
destinationItem.upd = { StackObjectsCount: 1 };
|
destinationItem.upd = { StackObjectsCount: 1 };
|
||||||
@ -307,7 +306,7 @@ export class InventoryController
|
|||||||
destinationItem.upd.StackObjectsCount += sourceItem.upd.StackObjectsCount; // Add source stackcount to destination
|
destinationItem.upd.StackObjectsCount += sourceItem.upd.StackObjectsCount; // Add source stackcount to destination
|
||||||
output.profileChanges[sessionID].items.del.push({ _id: sourceItem._id }); // Inform client source item being deleted
|
output.profileChanges[sessionID].items.del.push({ _id: sourceItem._id }); // Inform client source item being deleted
|
||||||
|
|
||||||
const indexOfItemToRemove = inventoryItems.from.findIndex((x) => x._id === sourceItem._id);
|
const indexOfItemToRemove = inventoryItems.from.findIndex(x => x._id === sourceItem._id);
|
||||||
if (indexOfItemToRemove === -1)
|
if (indexOfItemToRemove === -1)
|
||||||
{
|
{
|
||||||
const errorMessage = `Unable to find item: ${sourceItem._id} to remove from sender inventory`;
|
const errorMessage = `Unable to find item: ${sourceItem._id} to remove from sender inventory`;
|
||||||
@ -340,8 +339,8 @@ export class InventoryController
|
|||||||
): IItemEventRouterResponse
|
): IItemEventRouterResponse
|
||||||
{
|
{
|
||||||
const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID);
|
const inventoryItems = this.inventoryHelper.getOwnerInventoryItems(body, sessionID);
|
||||||
const sourceItem = inventoryItems.from.find((item) => item._id === body.item);
|
const sourceItem = inventoryItems.from.find(item => item._id === body.item);
|
||||||
const destinationItem = inventoryItems.to.find((item) => item._id === body.with);
|
const destinationItem = inventoryItems.to.find(item => item._id === body.with);
|
||||||
|
|
||||||
if (sourceItem === null)
|
if (sourceItem === null)
|
||||||
{
|
{
|
||||||
@ -397,13 +396,13 @@ export class InventoryController
|
|||||||
*/
|
*/
|
||||||
public swapItem(pmcData: IPmcData, request: IInventorySwapRequestData, sessionID: string): IItemEventRouterResponse
|
public swapItem(pmcData: IPmcData, request: IInventorySwapRequestData, sessionID: string): IItemEventRouterResponse
|
||||||
{
|
{
|
||||||
const itemOne = pmcData.Inventory.items.find((x) => x._id === request.item);
|
const itemOne = pmcData.Inventory.items.find(x => x._id === request.item);
|
||||||
if (!itemOne)
|
if (!itemOne)
|
||||||
{
|
{
|
||||||
this.logger.error(`Unable to find item: ${request.item} to swap positions with: ${request.item2}`);
|
this.logger.error(`Unable to find item: ${request.item} to swap positions with: ${request.item2}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemTwo = pmcData.Inventory.items.find((x) => x._id === request.item2);
|
const itemTwo = pmcData.Inventory.items.find(x => x._id === request.item2);
|
||||||
if (!itemTwo)
|
if (!itemTwo)
|
||||||
{
|
{
|
||||||
this.logger.error(`Unable to find item: ${request.item2} to swap positions with: ${request.item}`);
|
this.logger.error(`Unable to find item: ${request.item2} to swap positions with: ${request.item}`);
|
||||||
@ -454,7 +453,7 @@ export class InventoryController
|
|||||||
playerData = this.profileHelper.getScavProfile(sessionID);
|
playerData = this.profileHelper.getScavProfile(sessionID);
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemToFold = playerData.Inventory.items.find((item) => item?._id === request.item);
|
const itemToFold = playerData.Inventory.items.find(item => item?._id === request.item);
|
||||||
if (!itemToFold)
|
if (!itemToFold)
|
||||||
{
|
{
|
||||||
// Item not found
|
// Item not found
|
||||||
@ -488,7 +487,7 @@ export class InventoryController
|
|||||||
playerData = this.profileHelper.getScavProfile(sessionID);
|
playerData = this.profileHelper.getScavProfile(sessionID);
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemToToggle = playerData.Inventory.items.find((x) => x._id === body.item);
|
const itemToToggle = playerData.Inventory.items.find(x => x._id === body.item);
|
||||||
if (itemToToggle)
|
if (itemToToggle)
|
||||||
{
|
{
|
||||||
this.itemHelper.addUpdObjectToItem(
|
this.itemHelper.addUpdObjectToItem(
|
||||||
@ -689,15 +688,15 @@ export class InventoryController
|
|||||||
if (request.fromOwner.id === Traders.FENCE)
|
if (request.fromOwner.id === Traders.FENCE)
|
||||||
{
|
{
|
||||||
// Get tpl from fence assorts
|
// Get tpl from fence assorts
|
||||||
return this.fenceService.getRawFenceAssorts().items.find((x) => x._id === request.item)._tpl;
|
return this.fenceService.getRawFenceAssorts().items.find(x => x._id === request.item)._tpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.fromOwner.type === "Trader")
|
if (request.fromOwner.type === "Trader")
|
||||||
{
|
{
|
||||||
// Not fence
|
// Not fence
|
||||||
// get tpl from trader assort
|
// get tpl from trader assort
|
||||||
return this.databaseServer.getTables().traders[request.fromOwner.id].assort.items.find((item) =>
|
return this.databaseServer.getTables().traders[request.fromOwner.id].assort.items.find(item =>
|
||||||
item._id === request.item
|
item._id === request.item,
|
||||||
)._tpl;
|
)._tpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -718,7 +717,7 @@ export class InventoryController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try find examine item inside offer items array
|
// Try find examine item inside offer items array
|
||||||
const matchingItem = offer.items.find((offerItem) => offerItem._id === request.item);
|
const matchingItem = offer.items.find(offerItem => offerItem._id === request.item);
|
||||||
if (matchingItem)
|
if (matchingItem)
|
||||||
{
|
{
|
||||||
return matchingItem._tpl;
|
return matchingItem._tpl;
|
||||||
@ -754,7 +753,7 @@ export class InventoryController
|
|||||||
{
|
{
|
||||||
for (const change of request.changedItems)
|
for (const change of request.changedItems)
|
||||||
{
|
{
|
||||||
const inventoryItem = pmcData.Inventory.items.find((x) => x._id === change._id);
|
const inventoryItem = pmcData.Inventory.items.find(x => x._id === change._id);
|
||||||
if (!inventoryItem)
|
if (!inventoryItem)
|
||||||
{
|
{
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
@ -793,7 +792,7 @@ export class InventoryController
|
|||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
// Get map from inventory
|
// Get map from inventory
|
||||||
const mapItem = pmcData.Inventory.items.find((i) => i._id === request.item);
|
const mapItem = pmcData.Inventory.items.find(i => i._id === request.item);
|
||||||
|
|
||||||
// add marker
|
// add marker
|
||||||
mapItem.upd.Map = mapItem.upd.Map || { Markers: [] };
|
mapItem.upd.Map = mapItem.upd.Map || { Markers: [] };
|
||||||
@ -819,7 +818,7 @@ export class InventoryController
|
|||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
// Get map from inventory
|
// Get map from inventory
|
||||||
const mapItem = pmcData.Inventory.items.find((i) => i._id === request.item);
|
const mapItem = pmcData.Inventory.items.find(i => i._id === request.item);
|
||||||
|
|
||||||
// remove marker
|
// remove marker
|
||||||
const markers = mapItem.upd.Map.Markers.filter((marker) =>
|
const markers = mapItem.upd.Map.Markers.filter((marker) =>
|
||||||
@ -847,10 +846,10 @@ export class InventoryController
|
|||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
// Get map from inventory
|
// Get map from inventory
|
||||||
const mapItem = pmcData.Inventory.items.find((i) => i._id === request.item);
|
const mapItem = pmcData.Inventory.items.find(i => i._id === request.item);
|
||||||
|
|
||||||
// edit marker
|
// edit marker
|
||||||
const indexOfExistingNote = mapItem.upd.Map.Markers.findIndex((m) => m.X === request.X && m.Y === request.Y);
|
const indexOfExistingNote = mapItem.upd.Map.Markers.findIndex(m => m.X === request.X && m.Y === request.Y);
|
||||||
request.mapMarker.Note = this.sanitiseMapMarkerText(request.mapMarker.Note);
|
request.mapMarker.Note = this.sanitiseMapMarkerText(request.mapMarker.Note);
|
||||||
mapItem.upd.Map.Markers[indexOfExistingNote] = request.mapMarker;
|
mapItem.upd.Map.Markers[indexOfExistingNote] = request.mapMarker;
|
||||||
|
|
||||||
@ -884,7 +883,7 @@ export class InventoryController
|
|||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
/** Container player opened in their inventory */
|
/** Container player opened in their inventory */
|
||||||
const openedItem = pmcData.Inventory.items.find((item) => item._id === body.item);
|
const openedItem = pmcData.Inventory.items.find(item => item._id === body.item);
|
||||||
const containerDetailsDb = this.itemHelper.getItem(openedItem._tpl);
|
const containerDetailsDb = this.itemHelper.getItem(openedItem._tpl);
|
||||||
const isSealedWeaponBox = containerDetailsDb[1]._name.includes("event_container_airdrop");
|
const isSealedWeaponBox = containerDetailsDb[1]._name.includes("event_container_airdrop");
|
||||||
|
|
||||||
@ -935,8 +934,8 @@ export class InventoryController
|
|||||||
// Hard coded to `SYSTEM` for now
|
// Hard coded to `SYSTEM` for now
|
||||||
// TODO: make this dynamic
|
// TODO: make this dynamic
|
||||||
const dialog = fullProfile.dialogues["59e7125688a45068a6249071"];
|
const dialog = fullProfile.dialogues["59e7125688a45068a6249071"];
|
||||||
const mail = dialog.messages.find((x) => x._id === event.MessageId);
|
const mail = dialog.messages.find(x => x._id === event.MessageId);
|
||||||
const mailEvent = mail.profileChangeEvents.find((x) => x._id === event.EventId);
|
const mailEvent = mail.profileChangeEvents.find(x => x._id === event.EventId);
|
||||||
|
|
||||||
switch (mailEvent.Type)
|
switch (mailEvent.Type)
|
||||||
{
|
{
|
||||||
@ -955,15 +954,15 @@ export class InventoryController
|
|||||||
break;
|
break;
|
||||||
case "SkillPoints":
|
case "SkillPoints":
|
||||||
{
|
{
|
||||||
const profileSkill = pmcData.Skills.Common.find((x) => x.Id === mailEvent.entity);
|
const profileSkill = pmcData.Skills.Common.find(x => x.Id === mailEvent.entity);
|
||||||
profileSkill.Progress = mailEvent.value;
|
profileSkill.Progress = mailEvent.value;
|
||||||
this.logger.success(`Set profile skill: ${mailEvent.entity} to: ${mailEvent.value}`);
|
this.logger.success(`Set profile skill: ${mailEvent.entity} to: ${mailEvent.value}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "ExamineAllItems":
|
case "ExamineAllItems":
|
||||||
{
|
{
|
||||||
const itemsToInspect = this.itemHelper.getItems().filter((x) => x._type !== "Node");
|
const itemsToInspect = this.itemHelper.getItems().filter(x => x._type !== "Node");
|
||||||
this.flagItemsAsInspectedAndRewardXp(itemsToInspect.map((x) => x._id), fullProfile);
|
this.flagItemsAsInspectedAndRewardXp(itemsToInspect.map(x => x._id), fullProfile);
|
||||||
this.logger.success(`Flagged ${itemsToInspect.length} items as examined`);
|
this.logger.success(`Flagged ${itemsToInspect.length} items as examined`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -988,7 +987,7 @@ export class InventoryController
|
|||||||
for (const itemId of request.items)
|
for (const itemId of request.items)
|
||||||
{
|
{
|
||||||
// If id already exists in array, we're removing it
|
// If id already exists in array, we're removing it
|
||||||
const indexOfItemAlreadyFavorited = pmcData.Inventory.favoriteItems.findIndex((x) => x === itemId);
|
const indexOfItemAlreadyFavorited = pmcData.Inventory.favoriteItems.findIndex(x => x === itemId);
|
||||||
if (indexOfItemAlreadyFavorited > -1)
|
if (indexOfItemAlreadyFavorited > -1)
|
||||||
{
|
{
|
||||||
pmcData.Inventory.favoriteItems.splice(indexOfItemAlreadyFavorited, 1);
|
pmcData.Inventory.favoriteItems.splice(indexOfItemAlreadyFavorited, 1);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper";
|
import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper";
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";
|
import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
||||||
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
||||||
import { LocationGenerator } from "@spt-aki/generators/LocationGenerator";
|
import { LocationGenerator } from "@spt-aki/generators/LocationGenerator";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
||||||
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
||||||
import { LootGenerator } from "@spt-aki/generators/LootGenerator";
|
import { LootGenerator } from "@spt-aki/generators/LootGenerator";
|
||||||
@ -191,7 +190,7 @@ export class MatchController
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (this.inRaidConfig.coopExtracts.includes(extractName.trim()));
|
return this.inRaidConfig.coopExtracts.includes(extractName.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected sendCoopTakenFenceMessage(sessionId: string): void
|
protected sendCoopTakenFenceMessage(sessionId: string): void
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
import { Note } from "@spt-aki/models/eft/common/tables/IBotBase";
|
import { Note } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper";
|
import { HttpServerHelper } from "@spt-aki/helpers/HttpServerHelper";
|
||||||
import { NotifierHelper } from "@spt-aki/helpers/NotifierHelper";
|
import { NotifierHelper } from "@spt-aki/helpers/NotifierHelper";
|
||||||
import { INotifierChannel } from "@spt-aki/models/eft/notifier/INotifier";
|
import { INotifierChannel } from "@spt-aki/models/eft/notifier/INotifier";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
||||||
import { IPreset } from "@spt-aki/models/eft/common/IGlobals";
|
import { IPreset } from "@spt-aki/models/eft/common/IGlobals";
|
||||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { PlayerScavGenerator } from "@spt-aki/generators/PlayerScavGenerator";
|
import { PlayerScavGenerator } from "@spt-aki/generators/PlayerScavGenerator";
|
||||||
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
|
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
@ -81,7 +80,7 @@ export class ProfileController
|
|||||||
const pmc = profile.characters.pmc;
|
const pmc = profile.characters.pmc;
|
||||||
|
|
||||||
// make sure character completed creation
|
// make sure character completed creation
|
||||||
if (!(pmc?.Info?.Level))
|
if (!pmc?.Info?.Level)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
username: profile.info.username,
|
username: profile.info.username,
|
||||||
@ -104,7 +103,7 @@ export class ProfileController
|
|||||||
side: pmc.Info.Side,
|
side: pmc.Info.Side,
|
||||||
currlvl: pmc.Info.Level,
|
currlvl: pmc.Info.Level,
|
||||||
currexp: pmc.Info.Experience ?? 0,
|
currexp: pmc.Info.Experience ?? 0,
|
||||||
prevexp: (currlvl === 0) ? 0 : this.profileHelper.getExperience(currlvl),
|
prevexp: currlvl === 0 ? 0 : this.profileHelper.getExperience(currlvl),
|
||||||
nextlvl: nextlvl,
|
nextlvl: nextlvl,
|
||||||
maxlvl: maxlvl,
|
maxlvl: maxlvl,
|
||||||
akiData: profile.aki,
|
akiData: profile.aki,
|
||||||
@ -130,8 +129,10 @@ export class ProfileController
|
|||||||
public createProfile(info: IProfileCreateRequestData, sessionID: string): string
|
public createProfile(info: IProfileCreateRequestData, sessionID: string): string
|
||||||
{
|
{
|
||||||
const account = this.saveServer.getProfile(sessionID).info;
|
const account = this.saveServer.getProfile(sessionID).info;
|
||||||
const profile: ITemplateSide =
|
const profile: ITemplateSide = this.databaseServer
|
||||||
this.databaseServer.getTables().templates.profiles[account.edition][info.side.toLowerCase()];
|
.getTables()
|
||||||
|
.templates
|
||||||
|
.profiles[account.edition][info.side.toLowerCase()];
|
||||||
const pmcData = profile.character;
|
const pmcData = profile.character;
|
||||||
|
|
||||||
// Delete existing profile
|
// Delete existing profile
|
||||||
@ -151,7 +152,7 @@ export class ProfileController
|
|||||||
pmcData.Customization.Head = info.headId;
|
pmcData.Customization.Head = info.headId;
|
||||||
pmcData.Health.UpdateTime = this.timeUtil.getTimestamp();
|
pmcData.Health.UpdateTime = this.timeUtil.getTimestamp();
|
||||||
pmcData.Quests = [];
|
pmcData.Quests = [];
|
||||||
pmcData.Hideout.Seed = this.timeUtil.getTimestamp() + (8 * 60 * 60 * 24 * 365); // 8 years in future why? who knows, we saw it in live
|
pmcData.Hideout.Seed = this.timeUtil.getTimestamp() + 8 * 60 * 60 * 24 * 365; // 8 years in future why? who knows, we saw it in live
|
||||||
pmcData.RepeatableQuests = [];
|
pmcData.RepeatableQuests = [];
|
||||||
pmcData.CarExtractCounts = {};
|
pmcData.CarExtractCounts = {};
|
||||||
pmcData.CoopExtractCounts = {};
|
pmcData.CoopExtractCounts = {};
|
||||||
@ -458,7 +459,7 @@ export class ProfileController
|
|||||||
skills: playerPmc.Skills,
|
skills: playerPmc.Skills,
|
||||||
equipment: {
|
equipment: {
|
||||||
// Default inventory tpl
|
// Default inventory tpl
|
||||||
Id: playerPmc.Inventory.items.find((x) => x._tpl === "55d7217a4bdc2d86028b456d")._id,
|
Id: playerPmc.Inventory.items.find(x => x._tpl === "55d7217a4bdc2d86028b456d")._id,
|
||||||
Items: playerPmc.Inventory.items,
|
Items: playerPmc.Inventory.items,
|
||||||
},
|
},
|
||||||
achievements: playerPmc.Achievements,
|
achievements: playerPmc.Achievements,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
|
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
@ -79,7 +78,7 @@ export class QuestController
|
|||||||
for (const quest of allQuests)
|
for (const quest of allQuests)
|
||||||
{
|
{
|
||||||
// Player already accepted the quest, show it regardless of status
|
// Player already accepted the quest, show it regardless of status
|
||||||
const questInProfile = profile.Quests.find((x) => x.qid === quest._id);
|
const questInProfile = profile.Quests.find(x => x.qid === quest._id);
|
||||||
if (questInProfile)
|
if (questInProfile)
|
||||||
{
|
{
|
||||||
quest.sptStatus = questInProfile.status;
|
quest.sptStatus = questInProfile.status;
|
||||||
@ -137,8 +136,8 @@ export class QuestController
|
|||||||
for (const conditionToFulfil of questRequirements)
|
for (const conditionToFulfil of questRequirements)
|
||||||
{
|
{
|
||||||
// If the previous quest isn't in the user profile, it hasn't been completed or started
|
// If the previous quest isn't in the user profile, it hasn't been completed or started
|
||||||
const prerequisiteQuest = profile.Quests.find((profileQuest) =>
|
const prerequisiteQuest = profile.Quests.find(profileQuest =>
|
||||||
conditionToFulfil.target.includes(profileQuest.qid)
|
conditionToFulfil.target.includes(profileQuest.qid),
|
||||||
);
|
);
|
||||||
if (!prerequisiteQuest)
|
if (!prerequisiteQuest)
|
||||||
{
|
{
|
||||||
@ -148,7 +147,7 @@ export class QuestController
|
|||||||
|
|
||||||
// Prereq does not have its status requirement fulfilled
|
// Prereq does not have its status requirement fulfilled
|
||||||
// Some bsg status ids are strings, MUST convert to number before doing includes check
|
// Some bsg status ids are strings, MUST convert to number before doing includes check
|
||||||
if (!conditionToFulfil.status.map((status) => Number(status)).includes(prerequisiteQuest.status))
|
if (!conditionToFulfil.status.map(status => Number(status)).includes(prerequisiteQuest.status))
|
||||||
{
|
{
|
||||||
haveCompletedPreviousQuest = false;
|
haveCompletedPreviousQuest = false;
|
||||||
break;
|
break;
|
||||||
@ -292,7 +291,7 @@ export class QuestController
|
|||||||
|
|
||||||
// Does quest exist in profile
|
// Does quest exist in profile
|
||||||
// Restarting a failed quest can mean quest exists in profile
|
// Restarting a failed quest can mean quest exists in profile
|
||||||
const existingQuestStatus = pmcData.Quests.find((x) => x.qid === acceptedQuest.qid);
|
const existingQuestStatus = pmcData.Quests.find(x => x.qid === acceptedQuest.qid);
|
||||||
if (existingQuestStatus)
|
if (existingQuestStatus)
|
||||||
{
|
{
|
||||||
// Update existing
|
// Update existing
|
||||||
@ -399,15 +398,15 @@ export class QuestController
|
|||||||
fullProfile.characters.scav.Quests.push(newRepeatableQuest);
|
fullProfile.characters.scav.Quests.push(newRepeatableQuest);
|
||||||
}
|
}
|
||||||
|
|
||||||
const repeatableSettings = pmcData.RepeatableQuests.find((x) =>
|
const repeatableSettings = pmcData.RepeatableQuests.find(x =>
|
||||||
x.name === repeatableQuestProfile.sptRepatableGroupName
|
x.name === repeatableQuestProfile.sptRepatableGroupName,
|
||||||
);
|
);
|
||||||
|
|
||||||
const change = {};
|
const change = {};
|
||||||
change[repeatableQuestProfile._id] = repeatableSettings.changeRequirement[repeatableQuestProfile._id];
|
change[repeatableQuestProfile._id] = repeatableSettings.changeRequirement[repeatableQuestProfile._id];
|
||||||
const responseData: IPmcDataRepeatableQuest = {
|
const responseData: IPmcDataRepeatableQuest = {
|
||||||
id: repeatableSettings.id ?? this.questConfig.repeatableQuests.find((x) =>
|
id: repeatableSettings.id ?? this.questConfig.repeatableQuests.find(x =>
|
||||||
x.name === repeatableQuestProfile.sptRepatableGroupName
|
x.name === repeatableQuestProfile.sptRepatableGroupName,
|
||||||
).id,
|
).id,
|
||||||
name: repeatableSettings.name,
|
name: repeatableSettings.name,
|
||||||
endTime: repeatableSettings.endTime,
|
endTime: repeatableSettings.endTime,
|
||||||
@ -435,7 +434,7 @@ export class QuestController
|
|||||||
{
|
{
|
||||||
for (const repeatableQuest of pmcData.RepeatableQuests)
|
for (const repeatableQuest of pmcData.RepeatableQuests)
|
||||||
{
|
{
|
||||||
const matchingQuest = repeatableQuest.activeQuests.find((x) => x._id === acceptedQuest.qid);
|
const matchingQuest = repeatableQuest.activeQuests.find(x => x._id === acceptedQuest.qid);
|
||||||
if (matchingQuest)
|
if (matchingQuest)
|
||||||
{
|
{
|
||||||
this.logger.debug(`Accepted repeatable quest ${acceptedQuest.qid} from ${repeatableQuest.name}`);
|
this.logger.debug(`Accepted repeatable quest ${acceptedQuest.qid} from ${repeatableQuest.name}`);
|
||||||
@ -504,8 +503,8 @@ export class QuestController
|
|||||||
// Check if it's a repeatable quest. If so, remove from Quests
|
// Check if it's a repeatable quest. If so, remove from Quests
|
||||||
for (const currentRepeatable of pmcData.RepeatableQuests)
|
for (const currentRepeatable of pmcData.RepeatableQuests)
|
||||||
{
|
{
|
||||||
const repeatableQuest = currentRepeatable.activeQuests.find((activeRepeatable) =>
|
const repeatableQuest = currentRepeatable.activeQuests.find(activeRepeatable =>
|
||||||
activeRepeatable._id === completedQuestId
|
activeRepeatable._id === completedQuestId,
|
||||||
);
|
);
|
||||||
if (repeatableQuest)
|
if (repeatableQuest)
|
||||||
{
|
{
|
||||||
@ -548,15 +547,15 @@ export class QuestController
|
|||||||
|
|
||||||
// Quest already failed in profile, skip
|
// Quest already failed in profile, skip
|
||||||
if (
|
if (
|
||||||
pmcProfile.Quests.some((profileQuest) =>
|
pmcProfile.Quests.some(profileQuest =>
|
||||||
profileQuest.qid === quest._id && profileQuest.status === QuestStatus.Fail
|
profileQuest.qid === quest._id && profileQuest.status === QuestStatus.Fail,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return quest.conditions.Fail.some((condition) => condition.target?.includes(completedQuestId));
|
return quest.conditions.Fail.some(condition => condition.target?.includes(completedQuestId));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,7 +567,7 @@ export class QuestController
|
|||||||
protected removeQuestFromScavProfile(sessionId: string, questIdToRemove: string): void
|
protected removeQuestFromScavProfile(sessionId: string, questIdToRemove: string): void
|
||||||
{
|
{
|
||||||
const fullProfile = this.profileHelper.getFullProfile(sessionId);
|
const fullProfile = this.profileHelper.getFullProfile(sessionId);
|
||||||
const repeatableInScavProfile = fullProfile.characters.scav.Quests?.find((x) => x.qid === questIdToRemove);
|
const repeatableInScavProfile = fullProfile.characters.scav.Quests?.find(x => x.qid === questIdToRemove);
|
||||||
if (!repeatableInScavProfile)
|
if (!repeatableInScavProfile)
|
||||||
{
|
{
|
||||||
this.logger.warning(
|
this.logger.warning(
|
||||||
@ -600,7 +599,7 @@ export class QuestController
|
|||||||
for (const quest of postQuestStatuses)
|
for (const quest of postQuestStatuses)
|
||||||
{
|
{
|
||||||
// Add quest if status differs or quest not found
|
// Add quest if status differs or quest not found
|
||||||
const preQuest = preQuestStatusus.find((x) => x.qid === quest.qid);
|
const preQuest = preQuestStatusus.find(x => x.qid === quest.qid);
|
||||||
if (!preQuest || preQuest.status !== quest.status)
|
if (!preQuest || preQuest.status !== quest.status)
|
||||||
{
|
{
|
||||||
result.push(quest);
|
result.push(quest);
|
||||||
@ -653,8 +652,8 @@ export class QuestController
|
|||||||
for (const quest of quests)
|
for (const quest of quests)
|
||||||
{
|
{
|
||||||
// If quest has prereq of completed quest + availableAfter value > 0 (quest has wait time)
|
// If quest has prereq of completed quest + availableAfter value > 0 (quest has wait time)
|
||||||
const nextQuestWaitCondition = quest.conditions.AvailableForStart.find((x) =>
|
const nextQuestWaitCondition = quest.conditions.AvailableForStart.find(x =>
|
||||||
x.target?.includes(completedQuestId) && x.availableAfter > 0
|
x.target?.includes(completedQuestId) && x.availableAfter > 0,
|
||||||
);
|
);
|
||||||
if (nextQuestWaitCondition)
|
if (nextQuestWaitCondition)
|
||||||
{
|
{
|
||||||
@ -662,7 +661,7 @@ export class QuestController
|
|||||||
const availableAfterTimestamp = this.timeUtil.getTimestamp() + nextQuestWaitCondition.availableAfter;
|
const availableAfterTimestamp = this.timeUtil.getTimestamp() + nextQuestWaitCondition.availableAfter;
|
||||||
|
|
||||||
// Update quest in profile with status of AvailableAfter
|
// Update quest in profile with status of AvailableAfter
|
||||||
const existingQuestInProfile = pmcData.Quests.find((x) => x.qid === quest._id);
|
const existingQuestInProfile = pmcData.Quests.find(x => x.qid === quest._id);
|
||||||
if (existingQuestInProfile)
|
if (existingQuestInProfile)
|
||||||
{
|
{
|
||||||
existingQuestInProfile.availableAfter = availableAfterTimestamp;
|
existingQuestInProfile.availableAfter = availableAfterTimestamp;
|
||||||
@ -679,7 +678,7 @@ export class QuestController
|
|||||||
status: QuestStatus.AvailableAfter,
|
status: QuestStatus.AvailableAfter,
|
||||||
statusTimers: {
|
statusTimers: {
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
"9": this.timeUtil.getTimestamp(),
|
9: this.timeUtil.getTimestamp(),
|
||||||
},
|
},
|
||||||
availableAfter: availableAfterTimestamp,
|
availableAfter: availableAfterTimestamp,
|
||||||
});
|
});
|
||||||
@ -705,12 +704,12 @@ export class QuestController
|
|||||||
for (const questToFail of questsToFail)
|
for (const questToFail of questsToFail)
|
||||||
{
|
{
|
||||||
// Skip failing a quest that has a fail status of something other than success
|
// Skip failing a quest that has a fail status of something other than success
|
||||||
if (questToFail.conditions.Fail?.some((x) => x.status?.some((status) => status !== QuestStatus.Success)))
|
if (questToFail.conditions.Fail?.some(x => x.status?.some(status => status !== QuestStatus.Success)))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isActiveQuestInPlayerProfile = pmcData.Quests.find((quest) => quest.qid === questToFail._id);
|
const isActiveQuestInPlayerProfile = pmcData.Quests.find(quest => quest.qid === questToFail._id);
|
||||||
if (isActiveQuestInPlayerProfile)
|
if (isActiveQuestInPlayerProfile)
|
||||||
{
|
{
|
||||||
if (isActiveQuestInPlayerProfile.status !== QuestStatus.Fail)
|
if (isActiveQuestInPlayerProfile.status !== QuestStatus.Fail)
|
||||||
@ -772,7 +771,7 @@ export class QuestController
|
|||||||
isItemHandoverQuest = condition.conditionType === handoverQuestTypes[0];
|
isItemHandoverQuest = condition.conditionType === handoverQuestTypes[0];
|
||||||
handoverRequirements = condition;
|
handoverRequirements = condition;
|
||||||
|
|
||||||
const profileCounter = (handoverQuestRequest.conditionId in pmcData.TaskConditionCounters)
|
const profileCounter = handoverQuestRequest.conditionId in pmcData.TaskConditionCounters
|
||||||
? pmcData.TaskConditionCounters[handoverQuestRequest.conditionId].value
|
? pmcData.TaskConditionCounters[handoverQuestRequest.conditionId].value
|
||||||
: 0;
|
: 0;
|
||||||
handedInCount -= profileCounter;
|
handedInCount -= profileCounter;
|
||||||
@ -806,7 +805,7 @@ export class QuestController
|
|||||||
let totalItemCountToRemove = 0;
|
let totalItemCountToRemove = 0;
|
||||||
for (const itemHandover of handoverQuestRequest.items)
|
for (const itemHandover of handoverQuestRequest.items)
|
||||||
{
|
{
|
||||||
const matchingItemInProfile = pmcData.Inventory.items.find((item) => item._id === itemHandover.id);
|
const matchingItemInProfile = pmcData.Inventory.items.find(item => item._id === itemHandover.id);
|
||||||
if (!(matchingItemInProfile && handoverRequirements.target.includes(matchingItemInProfile._tpl)))
|
if (!(matchingItemInProfile && handoverRequirements.target.includes(matchingItemInProfile._tpl)))
|
||||||
{
|
{
|
||||||
// Item handed in by player doesnt match what was requested
|
// Item handed in by player doesnt match what was requested
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { RagfairOfferGenerator } from "@spt-aki/generators/RagfairOfferGenerator";
|
import { RagfairOfferGenerator } from "@spt-aki/generators/RagfairOfferGenerator";
|
||||||
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
|
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
|
||||||
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
|
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
|
||||||
@ -160,7 +159,7 @@ export class RagfairController
|
|||||||
public getOfferById(sessionId: string, request: IGetRagfairOfferByIdRequest): IRagfairOffer
|
public getOfferById(sessionId: string, request: IGetRagfairOfferByIdRequest): IRagfairOffer
|
||||||
{
|
{
|
||||||
const offers = this.ragfairOfferService.getOffers();
|
const offers = this.ragfairOfferService.getOffers();
|
||||||
const offerToReturn = offers.find((x) => x.intId === request.id);
|
const offerToReturn = offers.find(x => x.intId === request.id);
|
||||||
|
|
||||||
return offerToReturn;
|
return offerToReturn;
|
||||||
}
|
}
|
||||||
@ -208,14 +207,18 @@ export class RagfairController
|
|||||||
): Record<string, number>
|
): Record<string, number>
|
||||||
{
|
{
|
||||||
// Linked/required search categories
|
// Linked/required search categories
|
||||||
const playerHasFleaUnlocked =
|
const playerHasFleaUnlocked = pmcProfile.Info.Level >= this.databaseServer
|
||||||
pmcProfile.Info.Level >= this.databaseServer.getTables().globals.config.RagFair.minUserLevel;
|
.getTables()
|
||||||
|
.globals
|
||||||
|
.config
|
||||||
|
.RagFair
|
||||||
|
.minUserLevel;
|
||||||
let offerPool = [];
|
let offerPool = [];
|
||||||
if (this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest))
|
if (this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest))
|
||||||
{
|
{
|
||||||
offerPool = offers;
|
offerPool = offers;
|
||||||
}
|
}
|
||||||
else if ((!(this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest))))
|
else if (!(this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest)))
|
||||||
{
|
{
|
||||||
// Get all categories
|
// Get all categories
|
||||||
offerPool = this.ragfairOfferService.getOffers();
|
offerPool = this.ragfairOfferService.getOffers();
|
||||||
@ -260,7 +263,7 @@ export class RagfairController
|
|||||||
|
|
||||||
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items;
|
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items;
|
||||||
const assortId = offer.items[0]._id;
|
const assortId = offer.items[0]._id;
|
||||||
const assortData = traderAssorts.find((x) => x._id === assortId);
|
const assortData = traderAssorts.find(x => x._id === assortId);
|
||||||
|
|
||||||
// Use value stored in profile, otherwise use value directly from in-memory trader assort data
|
// Use value stored in profile, otherwise use value directly from in-memory trader assort data
|
||||||
offer.buyRestrictionCurrent = fullProfile.traderPurchases[offer.user.id][assortId]
|
offer.buyRestrictionCurrent = fullProfile.traderPurchases[offer.user.id][assortId]
|
||||||
@ -279,7 +282,7 @@ export class RagfairController
|
|||||||
const firstItem = offer.items[0];
|
const firstItem = offer.items[0];
|
||||||
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items;
|
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(offer.user.id).items;
|
||||||
|
|
||||||
const assortPurchased = traderAssorts.find((x) => x._id === offer.items[0]._id);
|
const assortPurchased = traderAssorts.find(x => x._id === offer.items[0]._id);
|
||||||
if (!assortPurchased)
|
if (!assortPurchased)
|
||||||
{
|
{
|
||||||
this.logger.warning(
|
this.logger.warning(
|
||||||
@ -357,7 +360,7 @@ export class RagfairController
|
|||||||
const avg = offers.reduce((sum, offer) =>
|
const avg = offers.reduce((sum, offer) =>
|
||||||
{
|
{
|
||||||
// Exclude barter items, they tend to have outrageous equivalent prices
|
// Exclude barter items, they tend to have outrageous equivalent prices
|
||||||
if (offer.requirements.some((req) => !this.paymentHelper.isMoneyTpl(req._tpl)))
|
if (offer.requirements.some(req => !this.paymentHelper.isMoneyTpl(req._tpl)))
|
||||||
{
|
{
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
@ -456,15 +459,15 @@ export class RagfairController
|
|||||||
// Multiply single item price by stack count and quality
|
// Multiply single item price by stack count and quality
|
||||||
averageOfferPrice *= rootItem.upd.StackObjectsCount * qualityMultiplier;
|
averageOfferPrice *= rootItem.upd.StackObjectsCount * qualityMultiplier;
|
||||||
|
|
||||||
const itemStackCount = (offerRequest.sellInOnePiece) ? 1 : rootItem.upd.StackObjectsCount;
|
const itemStackCount = offerRequest.sellInOnePiece ? 1 : rootItem.upd.StackObjectsCount;
|
||||||
|
|
||||||
// Get averaged price of a single item being listed
|
// Get averaged price of a single item being listed
|
||||||
const averageSingleItemPrice = (offerRequest.sellInOnePiece)
|
const averageSingleItemPrice = offerRequest.sellInOnePiece
|
||||||
? averageOfferPrice / rootItem.upd.StackObjectsCount // Packs are a single offer made of many items
|
? averageOfferPrice / rootItem.upd.StackObjectsCount // Packs are a single offer made of many items
|
||||||
: averageOfferPrice / itemStackCount;
|
: averageOfferPrice / itemStackCount;
|
||||||
|
|
||||||
// Get averaged price of listing
|
// Get averaged price of listing
|
||||||
const averagePlayerListedPriceInRub = (offerRequest.sellInOnePiece)
|
const averagePlayerListedPriceInRub = offerRequest.sellInOnePiece
|
||||||
? playerListedPriceInRub / rootItem.upd.StackObjectsCount
|
? playerListedPriceInRub / rootItem.upd.StackObjectsCount
|
||||||
: playerListedPriceInRub;
|
: playerListedPriceInRub;
|
||||||
|
|
||||||
@ -540,7 +543,7 @@ export class RagfairController
|
|||||||
offerRequest.sellInOnePiece,
|
offerRequest.sellInOnePiece,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.logger.debug(`Offer tax to charge: ${tax}, pulled from client: ${(!!storedClientTaxValue)}`);
|
this.logger.debug(`Offer tax to charge: ${tax}, pulled from client: ${!!storedClientTaxValue}`);
|
||||||
|
|
||||||
// cleanup of cache now we've used the tax value from it
|
// cleanup of cache now we've used the tax value from it
|
||||||
this.ragfairTaxService.clearStoredOfferTaxById(offerRequest.items[0]);
|
this.ragfairTaxService.clearStoredOfferTaxById(offerRequest.items[0]);
|
||||||
@ -602,8 +605,8 @@ export class RagfairController
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
requirementsPriceInRub += this.ragfairPriceService.getDynamicPriceForItem(requestedItemTpl)
|
requirementsPriceInRub += this.ragfairPriceService
|
||||||
* item.count;
|
.getDynamicPriceForItem(requestedItemTpl) * item.count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,7 +622,7 @@ export class RagfairController
|
|||||||
protected getItemsToListOnFleaFromInventory(
|
protected getItemsToListOnFleaFromInventory(
|
||||||
pmcData: IPmcData,
|
pmcData: IPmcData,
|
||||||
itemIdsFromFleaOfferRequest: string[],
|
itemIdsFromFleaOfferRequest: string[],
|
||||||
): { items: Item[] | null; errorMessage: string | null; }
|
): { items: Item[] | null, errorMessage: string | null }
|
||||||
{
|
{
|
||||||
const itemsToReturn = [];
|
const itemsToReturn = [];
|
||||||
let errorMessage: string | null = null;
|
let errorMessage: string | null = null;
|
||||||
@ -627,7 +630,7 @@ export class RagfairController
|
|||||||
// Count how many items are being sold and multiply the requested amount accordingly
|
// Count how many items are being sold and multiply the requested amount accordingly
|
||||||
for (const itemId of itemIdsFromFleaOfferRequest)
|
for (const itemId of itemIdsFromFleaOfferRequest)
|
||||||
{
|
{
|
||||||
let item = pmcData.Inventory.items.find((i) => i._id === itemId);
|
let item = pmcData.Inventory.items.find(i => i._id === itemId);
|
||||||
if (!item)
|
if (!item)
|
||||||
{
|
{
|
||||||
errorMessage = this.localisationService.getText("ragfair-unable_to_find_item_in_inventory", {
|
errorMessage = this.localisationService.getText("ragfair-unable_to_find_item_in_inventory", {
|
||||||
@ -663,7 +666,7 @@ export class RagfairController
|
|||||||
const loyalLevel = 1;
|
const loyalLevel = 1;
|
||||||
const formattedItems: Item[] = items.map((item) =>
|
const formattedItems: Item[] = items.map((item) =>
|
||||||
{
|
{
|
||||||
const isChild = items.find((it) => it._id === item.parentId);
|
const isChild = items.find(it => it._id === item.parentId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_id: item._id,
|
_id: item._id,
|
||||||
@ -724,7 +727,7 @@ export class RagfairController
|
|||||||
pmcData.RagfairInfo.offers = [];
|
pmcData.RagfairInfo.offers = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const playerOfferIndex = playerProfileOffers.findIndex((offer) => offer._id === removeRequest.offerId);
|
const playerOfferIndex = playerProfileOffers.findIndex(offer => offer._id === removeRequest.offerId);
|
||||||
if (playerOfferIndex === -1)
|
if (playerOfferIndex === -1)
|
||||||
{
|
{
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
@ -761,7 +764,7 @@ export class RagfairController
|
|||||||
|
|
||||||
const pmcData = this.saveServer.getProfile(sessionId).characters.pmc;
|
const pmcData = this.saveServer.getProfile(sessionId).characters.pmc;
|
||||||
const playerOffers = pmcData.RagfairInfo.offers;
|
const playerOffers = pmcData.RagfairInfo.offers;
|
||||||
const playerOfferIndex = playerOffers.findIndex((offer) => offer._id === extendRequest.offerId);
|
const playerOfferIndex = playerOffers.findIndex(offer => offer._id === extendRequest.offerId);
|
||||||
const secondsToAdd = extendRequest.renewalTime * TimeUtil.ONE_HOUR_AS_SECONDS;
|
const secondsToAdd = extendRequest.renewalTime * TimeUtil.ONE_HOUR_AS_SECONDS;
|
||||||
|
|
||||||
if (playerOfferIndex === -1)
|
if (playerOfferIndex === -1)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
import { QuestHelper } from "@spt-aki/helpers/QuestHelper";
|
import { QuestHelper } from "@spt-aki/helpers/QuestHelper";
|
||||||
import { RepairHelper } from "@spt-aki/helpers/RepairHelper";
|
import { RepairHelper } from "@spt-aki/helpers/RepairHelper";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { RepeatableQuestGenerator } from "@spt-aki/generators/RepeatableQuestGenerator";
|
import { RepeatableQuestGenerator } from "@spt-aki/generators/RepeatableQuestGenerator";
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
import { QuestHelper } from "@spt-aki/helpers/QuestHelper";
|
import { QuestHelper } from "@spt-aki/helpers/QuestHelper";
|
||||||
@ -83,15 +82,15 @@ export class RepeatableQuestController
|
|||||||
* @param {string} _info Request from client
|
* @param {string} _info Request from client
|
||||||
* @param {string} sessionID Player's session id
|
* @param {string} sessionID Player's session id
|
||||||
*
|
*
|
||||||
* @returns {array} Array of "repeatableQuestObjects" as descibed above
|
* @returns {array} Array of "repeatableQuestObjects" as described above
|
||||||
*/
|
*/
|
||||||
public getClientRepeatableQuests(_info: IEmptyRequestData, sessionID: string): IPmcDataRepeatableQuest[]
|
public getClientRepeatableQuests(_info: IEmptyRequestData, sessionID: string): IPmcDataRepeatableQuest[]
|
||||||
{
|
{
|
||||||
const returnData: Array<IPmcDataRepeatableQuest> = [];
|
const returnData: Array<IPmcDataRepeatableQuest> = [];
|
||||||
const pmcData = this.profileHelper.getPmcProfile(sessionID);
|
const pmcData = this.profileHelper.getPmcProfile(sessionID);
|
||||||
const time = this.timeUtil.getTimestamp();
|
const time = this.timeUtil.getTimestamp();
|
||||||
const scavQuestUnlocked =
|
const scavQuestUnlocked
|
||||||
pmcData?.Hideout?.Areas?.find((hideoutArea) => hideoutArea.type === HideoutAreas.INTEL_CENTER)?.level >= 1;
|
= pmcData?.Hideout?.Areas?.find(hideoutArea => hideoutArea.type === HideoutAreas.INTEL_CENTER)?.level >= 1;
|
||||||
|
|
||||||
// Daily / weekly / Daily_Savage
|
// Daily / weekly / Daily_Savage
|
||||||
for (const repeatableConfig of this.questConfig.repeatableQuests)
|
for (const repeatableConfig of this.questConfig.repeatableQuests)
|
||||||
@ -119,7 +118,7 @@ export class RepeatableQuestController
|
|||||||
for (const activeQuest of currentRepeatableQuestType.activeQuests)
|
for (const activeQuest of currentRepeatableQuestType.activeQuests)
|
||||||
{
|
{
|
||||||
// Keep finished quests in list so player can hand in
|
// Keep finished quests in list so player can hand in
|
||||||
const quest = pmcData.Quests.find((quest) => quest.qid === activeQuest._id);
|
const quest = pmcData.Quests.find(quest => quest.qid === activeQuest._id);
|
||||||
if (quest)
|
if (quest)
|
||||||
{
|
{
|
||||||
if (quest.status === QuestStatus.AvailableForFinish)
|
if (quest.status === QuestStatus.AvailableForFinish)
|
||||||
@ -135,7 +134,7 @@ export class RepeatableQuestController
|
|||||||
this.profileFixerService.removeDanglingConditionCounters(pmcData);
|
this.profileFixerService.removeDanglingConditionCounters(pmcData);
|
||||||
|
|
||||||
// Remove expired quest from pmc.quest array
|
// Remove expired quest from pmc.quest array
|
||||||
pmcData.Quests = pmcData.Quests.filter((quest) => quest.qid !== activeQuest._id);
|
pmcData.Quests = pmcData.Quests.filter(quest => quest.qid !== activeQuest._id);
|
||||||
currentRepeatableQuestType.inactiveQuests.push(activeQuest);
|
currentRepeatableQuestType.inactiveQuests.push(activeQuest);
|
||||||
}
|
}
|
||||||
currentRepeatableQuestType.activeQuests = questsToKeep;
|
currentRepeatableQuestType.activeQuests = questsToKeep;
|
||||||
@ -217,9 +216,14 @@ export class RepeatableQuestController
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Elite charisma skill gives extra daily quest(s)
|
// Elite charisma skill gives extra daily quest(s)
|
||||||
return repeatableConfig.numQuests
|
return repeatableConfig.numQuests + this.databaseServer.getTables()
|
||||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.Charisma.BonusSettings
|
.globals
|
||||||
.EliteBonusSettings.RepeatableQuestExtraCount;
|
.config
|
||||||
|
.SkillsSettings
|
||||||
|
.Charisma
|
||||||
|
.BonusSettings
|
||||||
|
.EliteBonusSettings
|
||||||
|
.RepeatableQuestExtraCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
return repeatableConfig.numQuests;
|
return repeatableConfig.numQuests;
|
||||||
@ -237,7 +241,7 @@ export class RepeatableQuestController
|
|||||||
): IPmcDataRepeatableQuest
|
): IPmcDataRepeatableQuest
|
||||||
{
|
{
|
||||||
// Get from profile, add if missing
|
// Get from profile, add if missing
|
||||||
let repeatableQuestDetails = pmcData.RepeatableQuests.find((x) => x.name === repeatableConfig.name);
|
let repeatableQuestDetails = pmcData.RepeatableQuests.find(x => x.name === repeatableConfig.name);
|
||||||
if (!repeatableQuestDetails)
|
if (!repeatableQuestDetails)
|
||||||
{
|
{
|
||||||
repeatableQuestDetails = {
|
repeatableQuestDetails = {
|
||||||
@ -327,8 +331,8 @@ export class RepeatableQuestController
|
|||||||
const possibleLocations = Object.keys(locations);
|
const possibleLocations = Object.keys(locations);
|
||||||
|
|
||||||
// Set possible locations for elimination task, if target is savage, exclude labs from locations
|
// Set possible locations for elimination task, if target is savage, exclude labs from locations
|
||||||
questPool.pool.Elimination.targets[probabilityObject.key] = (probabilityObject.key === "Savage")
|
questPool.pool.Elimination.targets[probabilityObject.key] = probabilityObject.key === "Savage"
|
||||||
? { locations: possibleLocations.filter((x) => x !== "laboratory") }
|
? { locations: possibleLocations.filter(x => x !== "laboratory") }
|
||||||
: { locations: possibleLocations };
|
: { locations: possibleLocations };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,7 +400,7 @@ export class RepeatableQuestController
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (pmcLevel <= locationBase.RequiredPlayerLevelMax && pmcLevel >= locationBase.RequiredPlayerLevelMin);
|
return pmcLevel <= locationBase.RequiredPlayerLevelMax && pmcLevel >= locationBase.RequiredPlayerLevelMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public debugLogRepeatableQuestIds(pmcData: IPmcData): void
|
public debugLogRepeatableQuestIds(pmcData: IPmcData): void
|
||||||
@ -439,7 +443,7 @@ export class RepeatableQuestController
|
|||||||
for (const currentRepeatablePool of pmcData.RepeatableQuests)
|
for (const currentRepeatablePool of pmcData.RepeatableQuests)
|
||||||
{
|
{
|
||||||
// Check for existing quest in (daily/weekly/scav arrays)
|
// Check for existing quest in (daily/weekly/scav arrays)
|
||||||
const questToReplace = currentRepeatablePool.activeQuests.find((x) => x._id === changeRequest.qid);
|
const questToReplace = currentRepeatablePool.activeQuests.find(x => x._id === changeRequest.qid);
|
||||||
if (!questToReplace)
|
if (!questToReplace)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -449,8 +453,8 @@ export class RepeatableQuestController
|
|||||||
replacedQuestTraderId = questToReplace.traderId;
|
replacedQuestTraderId = questToReplace.traderId;
|
||||||
|
|
||||||
// Update active quests to exclude the quest we're replacing
|
// Update active quests to exclude the quest we're replacing
|
||||||
currentRepeatablePool.activeQuests = currentRepeatablePool.activeQuests.filter((x) =>
|
currentRepeatablePool.activeQuests = currentRepeatablePool.activeQuests.filter(x =>
|
||||||
x._id !== changeRequest.qid
|
x._id !== changeRequest.qid,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get cost to replace existing quest
|
// Get cost to replace existing quest
|
||||||
@ -458,8 +462,8 @@ export class RepeatableQuestController
|
|||||||
delete currentRepeatablePool.changeRequirement[changeRequest.qid];
|
delete currentRepeatablePool.changeRequirement[changeRequest.qid];
|
||||||
// TODO: somehow we need to reduce the questPool by the currently active quests (for all repeatables)
|
// TODO: somehow we need to reduce the questPool by the currently active quests (for all repeatables)
|
||||||
|
|
||||||
const repeatableConfig = this.questConfig.repeatableQuests.find((x) =>
|
const repeatableConfig = this.questConfig.repeatableQuests.find(x =>
|
||||||
x.name === currentRepeatablePool.name
|
x.name === currentRepeatablePool.name,
|
||||||
);
|
);
|
||||||
const questTypePool = this.generateQuestPool(repeatableConfig, pmcData.Info.Level);
|
const questTypePool = this.generateQuestPool(repeatableConfig, pmcData.Info.Level);
|
||||||
const newRepeatableQuest = this.attemptToGenerateRepeatableQuest(pmcData, questTypePool, repeatableConfig);
|
const newRepeatableQuest = this.attemptToGenerateRepeatableQuest(pmcData, questTypePool, repeatableConfig);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
import { TradeHelper } from "@spt-aki/helpers/TradeHelper";
|
import { TradeHelper } from "@spt-aki/helpers/TradeHelper";
|
||||||
@ -294,7 +293,7 @@ export class TradeController
|
|||||||
this.traderHelper.getTraderById(trader),
|
this.traderHelper.getTraderById(trader),
|
||||||
MessageType.MESSAGE_WITH_ITEMS,
|
MessageType.MESSAGE_WITH_ITEMS,
|
||||||
this.randomUtil.getArrayValue(this.databaseServer.getTables().traders[trader].dialogue.soldItems),
|
this.randomUtil.getArrayValue(this.databaseServer.getTables().traders[trader].dialogue.soldItems),
|
||||||
curencyReward.flatMap((x) => x),
|
curencyReward.flatMap(x => x),
|
||||||
this.timeUtil.getHoursAsSeconds(72),
|
this.timeUtil.getHoursAsSeconds(72),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -320,12 +319,12 @@ export class TradeController
|
|||||||
for (const itemToSell of itemWithChildren)
|
for (const itemToSell of itemWithChildren)
|
||||||
{
|
{
|
||||||
const itemDetails = this.itemHelper.getItem(itemToSell._tpl);
|
const itemDetails = this.itemHelper.getItem(itemToSell._tpl);
|
||||||
if (
|
if (!(itemDetails[0] && this.itemHelper.isOfBaseclasses(
|
||||||
!(itemDetails[0]
|
itemDetails[1]._id,
|
||||||
&& this.itemHelper.isOfBaseclasses(itemDetails[1]._id, traderDetails.items_buy.category))
|
traderDetails.items_buy.category,
|
||||||
)
|
)))
|
||||||
{
|
{
|
||||||
// Skip if tpl isnt item OR item doesn't fulfill match traders buy categories
|
// Skip if tpl isn't item OR item doesn't fulfil match traders buy categories
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { FenceBaseAssortGenerator } from "@spt-aki/generators/FenceBaseAssortGenerator";
|
import { FenceBaseAssortGenerator } from "@spt-aki/generators/FenceBaseAssortGenerator";
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
import { TraderAssortHelper } from "@spt-aki/helpers/TraderAssortHelper";
|
import { TraderAssortHelper } from "@spt-aki/helpers/TraderAssortHelper";
|
||||||
@ -30,8 +29,7 @@ export class TraderController
|
|||||||
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||||
@inject("TraderHelper") protected traderHelper: TraderHelper,
|
@inject("TraderHelper") protected traderHelper: TraderHelper,
|
||||||
@inject("TraderAssortService") protected traderAssortService: TraderAssortService,
|
@inject("TraderAssortService") protected traderAssortService: TraderAssortService,
|
||||||
@inject("TraderPurchasePersisterService") protected traderPurchasePersisterService:
|
@inject("TraderPurchasePersisterService") protected traderPurchasePersisterService: TraderPurchasePersisterService,
|
||||||
TraderPurchasePersisterService,
|
|
||||||
@inject("FenceService") protected fenceService: FenceService,
|
@inject("FenceService") protected fenceService: FenceService,
|
||||||
@inject("FenceBaseAssortGenerator") protected fenceBaseAssortGenerator: FenceBaseAssortGenerator,
|
@inject("FenceBaseAssortGenerator") protected fenceBaseAssortGenerator: FenceBaseAssortGenerator,
|
||||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { WeatherGenerator } from "@spt-aki/generators/WeatherGenerator";
|
import { WeatherGenerator } from "@spt-aki/generators/WeatherGenerator";
|
||||||
import { IWeatherData } from "@spt-aki/models/eft/weather/IWeatherData";
|
import { IWeatherData } from "@spt-aki/models/eft/weather/IWeatherData";
|
||||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||||
import { IWishlistActionData } from "@spt-aki/models/eft/wishlist/IWishlistActionData";
|
import { IWishlistActionData } from "@spt-aki/models/eft/wishlist/IWishlistActionData";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { DependencyContainer, Lifecycle } from "tsyringe";
|
import { DependencyContainer, Lifecycle } from "tsyringe";
|
||||||
|
|
||||||
import { AchievementCallbacks } from "@spt-aki/callbacks/AchievementCallbacks";
|
import { AchievementCallbacks } from "@spt-aki/callbacks/AchievementCallbacks";
|
||||||
import { BotCallbacks } from "@spt-aki/callbacks/BotCallbacks";
|
import { BotCallbacks } from "@spt-aki/callbacks/BotCallbacks";
|
||||||
import { BuildsCallbacks } from "@spt-aki/callbacks/BuildsCallbacks";
|
import { BuildsCallbacks } from "@spt-aki/callbacks/BuildsCallbacks";
|
||||||
@ -71,18 +70,18 @@ import { BotWeaponGenerator } from "@spt-aki/generators/BotWeaponGenerator";
|
|||||||
import { FenceBaseAssortGenerator } from "@spt-aki/generators/FenceBaseAssortGenerator";
|
import { FenceBaseAssortGenerator } from "@spt-aki/generators/FenceBaseAssortGenerator";
|
||||||
import { LocationGenerator } from "@spt-aki/generators/LocationGenerator";
|
import { LocationGenerator } from "@spt-aki/generators/LocationGenerator";
|
||||||
import { LootGenerator } from "@spt-aki/generators/LootGenerator";
|
import { LootGenerator } from "@spt-aki/generators/LootGenerator";
|
||||||
import { PMCLootGenerator } from "@spt-aki/generators/PMCLootGenerator";
|
|
||||||
import { PlayerScavGenerator } from "@spt-aki/generators/PlayerScavGenerator";
|
import { PlayerScavGenerator } from "@spt-aki/generators/PlayerScavGenerator";
|
||||||
|
import { PMCLootGenerator } from "@spt-aki/generators/PMCLootGenerator";
|
||||||
import { RagfairAssortGenerator } from "@spt-aki/generators/RagfairAssortGenerator";
|
import { RagfairAssortGenerator } from "@spt-aki/generators/RagfairAssortGenerator";
|
||||||
import { RagfairOfferGenerator } from "@spt-aki/generators/RagfairOfferGenerator";
|
import { RagfairOfferGenerator } from "@spt-aki/generators/RagfairOfferGenerator";
|
||||||
import { RepeatableQuestGenerator } from "@spt-aki/generators/RepeatableQuestGenerator";
|
import { RepeatableQuestGenerator } from "@spt-aki/generators/RepeatableQuestGenerator";
|
||||||
import { RepeatableQuestRewardGenerator } from "@spt-aki/generators/RepeatableQuestRewardGenerator";
|
import { RepeatableQuestRewardGenerator } from "@spt-aki/generators/RepeatableQuestRewardGenerator";
|
||||||
import { ScavCaseRewardGenerator } from "@spt-aki/generators/ScavCaseRewardGenerator";
|
import { ScavCaseRewardGenerator } from "@spt-aki/generators/ScavCaseRewardGenerator";
|
||||||
import { WeatherGenerator } from "@spt-aki/generators/WeatherGenerator";
|
|
||||||
import { BarrelInventoryMagGen } from "@spt-aki/generators/weapongen/implementations/BarrelInventoryMagGen";
|
import { BarrelInventoryMagGen } from "@spt-aki/generators/weapongen/implementations/BarrelInventoryMagGen";
|
||||||
import { ExternalInventoryMagGen } from "@spt-aki/generators/weapongen/implementations/ExternalInventoryMagGen";
|
import { ExternalInventoryMagGen } from "@spt-aki/generators/weapongen/implementations/ExternalInventoryMagGen";
|
||||||
import { InternalMagazineInventoryMagGen } from "@spt-aki/generators/weapongen/implementations/InternalMagazineInventoryMagGen";
|
import { InternalMagazineInventoryMagGen } from "@spt-aki/generators/weapongen/implementations/InternalMagazineInventoryMagGen";
|
||||||
import { UbglExternalMagGen } from "@spt-aki/generators/weapongen/implementations/UbglExternalMagGen";
|
import { UbglExternalMagGen } from "@spt-aki/generators/weapongen/implementations/UbglExternalMagGen";
|
||||||
|
import { WeatherGenerator } from "@spt-aki/generators/WeatherGenerator";
|
||||||
import { AssortHelper } from "@spt-aki/helpers/AssortHelper";
|
import { AssortHelper } from "@spt-aki/helpers/AssortHelper";
|
||||||
import { BotDifficultyHelper } from "@spt-aki/helpers/BotDifficultyHelper";
|
import { BotDifficultyHelper } from "@spt-aki/helpers/BotDifficultyHelper";
|
||||||
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
||||||
@ -133,10 +132,6 @@ import { PostAkiModLoader } from "@spt-aki/loaders/PostAkiModLoader";
|
|||||||
import { PostDBModLoader } from "@spt-aki/loaders/PostDBModLoader";
|
import { PostDBModLoader } from "@spt-aki/loaders/PostDBModLoader";
|
||||||
import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";
|
import { PreAkiModLoader } from "@spt-aki/loaders/PreAkiModLoader";
|
||||||
import { IAsyncQueue } from "@spt-aki/models/spt/utils/IAsyncQueue";
|
import { IAsyncQueue } from "@spt-aki/models/spt/utils/IAsyncQueue";
|
||||||
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
|
|
||||||
import { HttpRouter } from "@spt-aki/routers/HttpRouter";
|
|
||||||
import { ImageRouter } from "@spt-aki/routers/ImageRouter";
|
|
||||||
import { ItemEventRouter } from "@spt-aki/routers/ItemEventRouter";
|
|
||||||
import { BotDynamicRouter } from "@spt-aki/routers/dynamic/BotDynamicRouter";
|
import { BotDynamicRouter } from "@spt-aki/routers/dynamic/BotDynamicRouter";
|
||||||
import { BundleDynamicRouter } from "@spt-aki/routers/dynamic/BundleDynamicRouter";
|
import { BundleDynamicRouter } from "@spt-aki/routers/dynamic/BundleDynamicRouter";
|
||||||
import { CustomizationDynamicRouter } from "@spt-aki/routers/dynamic/CustomizationDynamicRouter";
|
import { CustomizationDynamicRouter } from "@spt-aki/routers/dynamic/CustomizationDynamicRouter";
|
||||||
@ -146,6 +141,9 @@ import { InraidDynamicRouter } from "@spt-aki/routers/dynamic/InraidDynamicRoute
|
|||||||
import { LocationDynamicRouter } from "@spt-aki/routers/dynamic/LocationDynamicRouter";
|
import { LocationDynamicRouter } from "@spt-aki/routers/dynamic/LocationDynamicRouter";
|
||||||
import { NotifierDynamicRouter } from "@spt-aki/routers/dynamic/NotifierDynamicRouter";
|
import { NotifierDynamicRouter } from "@spt-aki/routers/dynamic/NotifierDynamicRouter";
|
||||||
import { TraderDynamicRouter } from "@spt-aki/routers/dynamic/TraderDynamicRouter";
|
import { TraderDynamicRouter } from "@spt-aki/routers/dynamic/TraderDynamicRouter";
|
||||||
|
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
|
||||||
|
import { HttpRouter } from "@spt-aki/routers/HttpRouter";
|
||||||
|
import { ImageRouter } from "@spt-aki/routers/ImageRouter";
|
||||||
import { CustomizationItemEventRouter } from "@spt-aki/routers/item_events/CustomizationItemEventRouter";
|
import { CustomizationItemEventRouter } from "@spt-aki/routers/item_events/CustomizationItemEventRouter";
|
||||||
import { HealthItemEventRouter } from "@spt-aki/routers/item_events/HealthItemEventRouter";
|
import { HealthItemEventRouter } from "@spt-aki/routers/item_events/HealthItemEventRouter";
|
||||||
import { HideoutItemEventRouter } from "@spt-aki/routers/item_events/HideoutItemEventRouter";
|
import { HideoutItemEventRouter } from "@spt-aki/routers/item_events/HideoutItemEventRouter";
|
||||||
@ -157,6 +155,7 @@ import { RagfairItemEventRouter } from "@spt-aki/routers/item_events/RagfairItem
|
|||||||
import { RepairItemEventRouter } from "@spt-aki/routers/item_events/RepairItemEventRouter";
|
import { RepairItemEventRouter } from "@spt-aki/routers/item_events/RepairItemEventRouter";
|
||||||
import { TradeItemEventRouter } from "@spt-aki/routers/item_events/TradeItemEventRouter";
|
import { TradeItemEventRouter } from "@spt-aki/routers/item_events/TradeItemEventRouter";
|
||||||
import { WishlistItemEventRouter } from "@spt-aki/routers/item_events/WishlistItemEventRouter";
|
import { WishlistItemEventRouter } from "@spt-aki/routers/item_events/WishlistItemEventRouter";
|
||||||
|
import { ItemEventRouter } from "@spt-aki/routers/ItemEventRouter";
|
||||||
import { HealthSaveLoadRouter } from "@spt-aki/routers/save_load/HealthSaveLoadRouter";
|
import { HealthSaveLoadRouter } from "@spt-aki/routers/save_load/HealthSaveLoadRouter";
|
||||||
import { InraidSaveLoadRouter } from "@spt-aki/routers/save_load/InraidSaveLoadRouter";
|
import { InraidSaveLoadRouter } from "@spt-aki/routers/save_load/InraidSaveLoadRouter";
|
||||||
import { InsuranceSaveLoadRouter } from "@spt-aki/routers/save_load/InsuranceSaveLoadRouter";
|
import { InsuranceSaveLoadRouter } from "@spt-aki/routers/save_load/InsuranceSaveLoadRouter";
|
||||||
@ -188,16 +187,18 @@ import { TraderStaticRouter } from "@spt-aki/routers/static/TraderStaticRouter";
|
|||||||
import { WeatherStaticRouter } from "@spt-aki/routers/static/WeatherStaticRouter";
|
import { WeatherStaticRouter } from "@spt-aki/routers/static/WeatherStaticRouter";
|
||||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||||
|
import { AkiHttpListener } from "@spt-aki/servers/http/AkiHttpListener";
|
||||||
import { HttpServer } from "@spt-aki/servers/HttpServer";
|
import { HttpServer } from "@spt-aki/servers/HttpServer";
|
||||||
import { RagfairServer } from "@spt-aki/servers/RagfairServer";
|
import { RagfairServer } from "@spt-aki/servers/RagfairServer";
|
||||||
import { SaveServer } from "@spt-aki/servers/SaveServer";
|
import { SaveServer } from "@spt-aki/servers/SaveServer";
|
||||||
import { WebSocketServer } from "@spt-aki/servers/WebSocketServer";
|
import { WebSocketServer } from "@spt-aki/servers/WebSocketServer";
|
||||||
import { AkiHttpListener } from "@spt-aki/servers/http/AkiHttpListener";
|
|
||||||
import { BotEquipmentFilterService } from "@spt-aki/services/BotEquipmentFilterService";
|
import { BotEquipmentFilterService } from "@spt-aki/services/BotEquipmentFilterService";
|
||||||
import { BotEquipmentModPoolService } from "@spt-aki/services/BotEquipmentModPoolService";
|
import { BotEquipmentModPoolService } from "@spt-aki/services/BotEquipmentModPoolService";
|
||||||
import { BotGenerationCacheService } from "@spt-aki/services/BotGenerationCacheService";
|
import { BotGenerationCacheService } from "@spt-aki/services/BotGenerationCacheService";
|
||||||
import { BotLootCacheService } from "@spt-aki/services/BotLootCacheService";
|
import { BotLootCacheService } from "@spt-aki/services/BotLootCacheService";
|
||||||
import { BotWeaponModLimitService } from "@spt-aki/services/BotWeaponModLimitService";
|
import { BotWeaponModLimitService } from "@spt-aki/services/BotWeaponModLimitService";
|
||||||
|
import { BundleHashCacheService } from "@spt-aki/services/cache/BundleHashCacheService";
|
||||||
|
import { ModHashCacheService } from "@spt-aki/services/cache/ModHashCacheService";
|
||||||
import { CustomLocationWaveService } from "@spt-aki/services/CustomLocationWaveService";
|
import { CustomLocationWaveService } from "@spt-aki/services/CustomLocationWaveService";
|
||||||
import { FenceService } from "@spt-aki/services/FenceService";
|
import { FenceService } from "@spt-aki/services/FenceService";
|
||||||
import { GiftService } from "@spt-aki/services/GiftService";
|
import { GiftService } from "@spt-aki/services/GiftService";
|
||||||
@ -209,6 +210,13 @@ import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
|||||||
import { MailSendService } from "@spt-aki/services/MailSendService";
|
import { MailSendService } from "@spt-aki/services/MailSendService";
|
||||||
import { MatchBotDetailsCacheService } from "@spt-aki/services/MatchBotDetailsCacheService";
|
import { MatchBotDetailsCacheService } from "@spt-aki/services/MatchBotDetailsCacheService";
|
||||||
import { MatchLocationService } from "@spt-aki/services/MatchLocationService";
|
import { MatchLocationService } from "@spt-aki/services/MatchLocationService";
|
||||||
|
import { CustomItemService } from "@spt-aki/services/mod/CustomItemService";
|
||||||
|
import { DynamicRouterModService } from "@spt-aki/services/mod/dynamicRouter/DynamicRouterModService";
|
||||||
|
import { HttpListenerModService } from "@spt-aki/services/mod/httpListener/HttpListenerModService";
|
||||||
|
import { ImageRouteService } from "@spt-aki/services/mod/image/ImageRouteService";
|
||||||
|
import { OnLoadModService } from "@spt-aki/services/mod/onLoad/OnLoadModService";
|
||||||
|
import { OnUpdateModService } from "@spt-aki/services/mod/onUpdate/OnUpdateModService";
|
||||||
|
import { StaticRouterModService } from "@spt-aki/services/mod/staticRouter/StaticRouterModService";
|
||||||
import { ModCompilerService } from "@spt-aki/services/ModCompilerService";
|
import { ModCompilerService } from "@spt-aki/services/ModCompilerService";
|
||||||
import { NotificationService } from "@spt-aki/services/NotificationService";
|
import { NotificationService } from "@spt-aki/services/NotificationService";
|
||||||
import { OpenZoneService } from "@spt-aki/services/OpenZoneService";
|
import { OpenZoneService } from "@spt-aki/services/OpenZoneService";
|
||||||
@ -230,15 +238,6 @@ import { SeasonalEventService } from "@spt-aki/services/SeasonalEventService";
|
|||||||
import { TraderAssortService } from "@spt-aki/services/TraderAssortService";
|
import { TraderAssortService } from "@spt-aki/services/TraderAssortService";
|
||||||
import { TraderPurchasePersisterService } from "@spt-aki/services/TraderPurchasePersisterService";
|
import { TraderPurchasePersisterService } from "@spt-aki/services/TraderPurchasePersisterService";
|
||||||
import { TraderServicesService } from "@spt-aki/services/TraderServicesService";
|
import { TraderServicesService } from "@spt-aki/services/TraderServicesService";
|
||||||
import { BundleHashCacheService } from "@spt-aki/services/cache/BundleHashCacheService";
|
|
||||||
import { ModHashCacheService } from "@spt-aki/services/cache/ModHashCacheService";
|
|
||||||
import { CustomItemService } from "@spt-aki/services/mod/CustomItemService";
|
|
||||||
import { DynamicRouterModService } from "@spt-aki/services/mod/dynamicRouter/DynamicRouterModService";
|
|
||||||
import { HttpListenerModService } from "@spt-aki/services/mod/httpListener/HttpListenerModService";
|
|
||||||
import { ImageRouteService } from "@spt-aki/services/mod/image/ImageRouteService";
|
|
||||||
import { OnLoadModService } from "@spt-aki/services/mod/onLoad/OnLoadModService";
|
|
||||||
import { OnUpdateModService } from "@spt-aki/services/mod/onUpdate/OnUpdateModService";
|
|
||||||
import { StaticRouterModService } from "@spt-aki/services/mod/staticRouter/StaticRouterModService";
|
|
||||||
import { App } from "@spt-aki/utils/App";
|
import { App } from "@spt-aki/utils/App";
|
||||||
import { AsyncQueue } from "@spt-aki/utils/AsyncQueue";
|
import { AsyncQueue } from "@spt-aki/utils/AsyncQueue";
|
||||||
import { CompareUtil } from "@spt-aki/utils/CompareUtil";
|
import { CompareUtil } from "@spt-aki/utils/CompareUtil";
|
||||||
@ -249,14 +248,14 @@ import { HttpFileUtil } from "@spt-aki/utils/HttpFileUtil";
|
|||||||
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
|
import { HttpResponseUtil } from "@spt-aki/utils/HttpResponseUtil";
|
||||||
import { ImporterUtil } from "@spt-aki/utils/ImporterUtil";
|
import { ImporterUtil } from "@spt-aki/utils/ImporterUtil";
|
||||||
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||||
|
import { WinstonMainLogger } from "@spt-aki/utils/logging/WinstonMainLogger";
|
||||||
|
import { WinstonRequestLogger } from "@spt-aki/utils/logging/WinstonRequestLogger";
|
||||||
import { MathUtil } from "@spt-aki/utils/MathUtil";
|
import { MathUtil } from "@spt-aki/utils/MathUtil";
|
||||||
import { ObjectId } from "@spt-aki/utils/ObjectId";
|
import { ObjectId } from "@spt-aki/utils/ObjectId";
|
||||||
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
||||||
import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
||||||
import { VFS } from "@spt-aki/utils/VFS";
|
import { VFS } from "@spt-aki/utils/VFS";
|
||||||
import { Watermark, WatermarkLocale } from "@spt-aki/utils/Watermark";
|
import { Watermark, WatermarkLocale } from "@spt-aki/utils/Watermark";
|
||||||
import { WinstonMainLogger } from "@spt-aki/utils/logging/WinstonMainLogger";
|
|
||||||
import { WinstonRequestLogger } from "@spt-aki/utils/logging/WinstonRequestLogger";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the registration of classes to be used by the Dependency Injection code
|
* Handle the registration of classes to be used by the Dependency Injection code
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export interface OnLoad
|
export interface OnLoad
|
||||||
{
|
{
|
||||||
onLoad(): Promise<void>;
|
onLoad(): Promise<void>
|
||||||
getRoute(): string;
|
getRoute(): string
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export interface OnUpdate
|
export interface OnUpdate
|
||||||
{
|
{
|
||||||
onUpdate(timeSinceLastRun: number): Promise<boolean>;
|
onUpdate(timeSinceLastRun: number): Promise<boolean>
|
||||||
getRoute(): string;
|
getRoute(): string
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,9 @@ export class Router
|
|||||||
{
|
{
|
||||||
if (partialMatch)
|
if (partialMatch)
|
||||||
{
|
{
|
||||||
return this.getInternalHandledRoutes().filter((r) => r.dynamic).some((r) => url.includes(r.route));
|
return this.getInternalHandledRoutes().filter(r => r.dynamic).some(r => url.includes(r.route));
|
||||||
}
|
}
|
||||||
return this.getInternalHandledRoutes().filter((r) => !r.dynamic).some((r) => r.route === url);
|
return this.getInternalHandledRoutes().filter(r => !r.dynamic).some(r => r.route === url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,12 +44,12 @@ export class StaticRouter extends Router
|
|||||||
|
|
||||||
public handleStatic(url: string, info: any, sessionID: string, output: string): any
|
public handleStatic(url: string, info: any, sessionID: string, output: string): any
|
||||||
{
|
{
|
||||||
return this.routes.find((route) => route.url === url).action(url, info, sessionID, output);
|
return this.routes.find(route => route.url === url).action(url, info, sessionID, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override getHandledRoutes(): HandledRoute[]
|
public override getHandledRoutes(): HandledRoute[]
|
||||||
{
|
{
|
||||||
return this.routes.map((route) => new HandledRoute(route.url, false));
|
return this.routes.map(route => new HandledRoute(route.url, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,12 +62,12 @@ export class DynamicRouter extends Router
|
|||||||
|
|
||||||
public handleDynamic(url: string, info: any, sessionID: string, output: string): any
|
public handleDynamic(url: string, info: any, sessionID: string, output: string): any
|
||||||
{
|
{
|
||||||
return this.routes.find((r) => url.includes(r.url)).action(url, info, sessionID, output);
|
return this.routes.find(r => url.includes(r.url)).action(url, info, sessionID, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override getHandledRoutes(): HandledRoute[]
|
public override getHandledRoutes(): HandledRoute[]
|
||||||
{
|
{
|
||||||
return this.routes.map((route) => new HandledRoute(route.url, true));
|
return this.routes.map(route => new HandledRoute(route.url, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
||||||
import { BotHelper } from "@spt-aki/helpers/BotHelper";
|
import { BotHelper } from "@spt-aki/helpers/BotHelper";
|
||||||
import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper";
|
import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper";
|
||||||
@ -234,8 +233,8 @@ export class BotEquipmentModGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the front/back/side weights based on bots level
|
// Get the front/back/side weights based on bots level
|
||||||
const plateSlotWeights = settings.botEquipmentConfig?.armorPlateWeighting?.find((armorWeight) =>
|
const plateSlotWeights = settings.botEquipmentConfig?.armorPlateWeighting?.find(armorWeight =>
|
||||||
settings.botLevel >= armorWeight.levelRange.min && settings.botLevel <= armorWeight.levelRange.max
|
settings.botLevel >= armorWeight.levelRange.min && settings.botLevel <= armorWeight.levelRange.max,
|
||||||
);
|
);
|
||||||
if (!plateSlotWeights)
|
if (!plateSlotWeights)
|
||||||
{
|
{
|
||||||
@ -261,17 +260,17 @@ export class BotEquipmentModGenerator
|
|||||||
const chosenArmorPlateLevel = this.weightedRandomHelper.getWeightedValue<string>(plateWeights);
|
const chosenArmorPlateLevel = this.weightedRandomHelper.getWeightedValue<string>(plateWeights);
|
||||||
|
|
||||||
// Convert the array of ids into database items
|
// Convert the array of ids into database items
|
||||||
const platesFromDb = existingPlateTplPool.map((plateTpl) => this.itemHelper.getItem(plateTpl)[1]);
|
const platesFromDb = existingPlateTplPool.map(plateTpl => this.itemHelper.getItem(plateTpl)[1]);
|
||||||
|
|
||||||
// Filter plates to the chosen level based on its armorClass property
|
// Filter plates to the chosen level based on its armorClass property
|
||||||
const filteredPlates = platesFromDb.filter((item) => item._props.armorClass === chosenArmorPlateLevel);
|
const filteredPlates = platesFromDb.filter(item => item._props.armorClass === chosenArmorPlateLevel);
|
||||||
if (filteredPlates.length === 0)
|
if (filteredPlates.length === 0)
|
||||||
{
|
{
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Plate filter was too restrictive for armor: ${armorItem._id}, unable to find plates of level: ${chosenArmorPlateLevel}. Using mod items default plate`,
|
`Plate filter was too restrictive for armor: ${armorItem._id}, unable to find plates of level: ${chosenArmorPlateLevel}. Using mod items default plate`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const relatedItemDbModSlot = armorItem._props.Slots.find((slot) => slot._name.toLowerCase() === modSlot);
|
const relatedItemDbModSlot = armorItem._props.Slots.find(slot => slot._name.toLowerCase() === modSlot);
|
||||||
const defaultPlate = relatedItemDbModSlot._props.filters[0].Plate;
|
const defaultPlate = relatedItemDbModSlot._props.filters[0].Plate;
|
||||||
if (!defaultPlate)
|
if (!defaultPlate)
|
||||||
{
|
{
|
||||||
@ -281,8 +280,8 @@ export class BotEquipmentModGenerator
|
|||||||
const defaultPreset = this.presetHelper.getDefaultPreset(armorItem._id);
|
const defaultPreset = this.presetHelper.getDefaultPreset(armorItem._id);
|
||||||
if (defaultPreset)
|
if (defaultPreset)
|
||||||
{
|
{
|
||||||
const relatedPresetSlot = defaultPreset._items.find((item) =>
|
const relatedPresetSlot = defaultPreset._items.find(item =>
|
||||||
item.slotId?.toLowerCase() === modSlot
|
item.slotId?.toLowerCase() === modSlot,
|
||||||
);
|
);
|
||||||
if (relatedPresetSlot)
|
if (relatedPresetSlot)
|
||||||
{
|
{
|
||||||
@ -306,7 +305,7 @@ export class BotEquipmentModGenerator
|
|||||||
|
|
||||||
// Only return the items ids
|
// Only return the items ids
|
||||||
result.result = Result.SUCCESS;
|
result.result = Result.SUCCESS;
|
||||||
result.plateModTpls = filteredPlates.map((item) => item._id);
|
result.plateModTpls = filteredPlates.map(item => item._id);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -346,8 +345,8 @@ export class BotEquipmentModGenerator
|
|||||||
const compatibleModsPool = modPool[parentTemplate._id];
|
const compatibleModsPool = modPool[parentTemplate._id];
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!((parentTemplate._props.Slots.length || parentTemplate._props.Cartridges?.length)
|
!(parentTemplate._props.Slots.length || parentTemplate._props.Cartridges?.length
|
||||||
|| parentTemplate._props.Chambers?.length)
|
|| parentTemplate._props.Chambers?.length)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
@ -468,10 +467,10 @@ export class BotEquipmentModGenerator
|
|||||||
// Handguard mod can take a sub handguard mod + weapon has no UBGL (takes same slot)
|
// Handguard mod can take a sub handguard mod + weapon has no UBGL (takes same slot)
|
||||||
// Force spawn chance to be 100% to ensure it gets added
|
// Force spawn chance to be 100% to ensure it gets added
|
||||||
if (
|
if (
|
||||||
modSlot === "mod_handguard" && modToAddTemplate._props.Slots.find((slot) =>
|
modSlot === "mod_handguard" && modToAddTemplate._props.Slots.find(slot =>
|
||||||
slot._name === "mod_handguard"
|
slot._name === "mod_handguard",
|
||||||
)
|
)
|
||||||
&& !weapon.find((item) => item.slotId === "mod_launcher")
|
&& !weapon.find(item => item.slotId === "mod_launcher")
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Needed for handguards with lower
|
// Needed for handguards with lower
|
||||||
@ -481,9 +480,9 @@ export class BotEquipmentModGenerator
|
|||||||
// If stock mod can take a sub stock mod, force spawn chance to be 100% to ensure sub-stock gets added
|
// If stock mod can take a sub stock mod, force spawn chance to be 100% to ensure sub-stock gets added
|
||||||
// Or if mod_stock is configured to be forced on
|
// Or if mod_stock is configured to be forced on
|
||||||
if (
|
if (
|
||||||
modSlot === "mod_stock" && (modToAddTemplate._props.Slots.find((slot) =>
|
modSlot === "mod_stock" && modToAddTemplate._props.Slots.find(slot =>
|
||||||
slot._name.includes("mod_stock") || botEquipConfig.forceStock
|
slot._name.includes("mod_stock") || botEquipConfig.forceStock,
|
||||||
))
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Stock mod can take additional stocks, could be a locking device, force 100% chance
|
// Stock mod can take additional stocks, could be a locking device, force 100% chance
|
||||||
@ -700,11 +699,11 @@ export class BotEquipmentModGenerator
|
|||||||
case "patron_in_weapon":
|
case "patron_in_weapon":
|
||||||
case "patron_in_weapon_000":
|
case "patron_in_weapon_000":
|
||||||
case "patron_in_weapon_001":
|
case "patron_in_weapon_001":
|
||||||
return parentTemplate._props.Chambers.find((chamber) => chamber._name.includes(modSlotLower));
|
return parentTemplate._props.Chambers.find(chamber => chamber._name.includes(modSlotLower));
|
||||||
case "cartridges":
|
case "cartridges":
|
||||||
return parentTemplate._props.Cartridges.find((c) => c._name.toLowerCase() === modSlotLower);
|
return parentTemplate._props.Cartridges.find(c => c._name.toLowerCase() === modSlotLower);
|
||||||
default:
|
default:
|
||||||
return parentTemplate._props.Slots.find((s) => s._name.toLowerCase() === modSlotLower);
|
return parentTemplate._props.Slots.find(s => s._name.toLowerCase() === modSlotLower);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -762,7 +761,7 @@ export class BotEquipmentModGenerator
|
|||||||
): [boolean, ITemplateItem]
|
): [boolean, ITemplateItem]
|
||||||
{
|
{
|
||||||
/** Slot mod will fill */
|
/** Slot mod will fill */
|
||||||
const parentSlot = parentTemplate._props.Slots.find((i) => i._name === modSlot);
|
const parentSlot = parentTemplate._props.Slots.find(i => i._name === modSlot);
|
||||||
const weaponTemplate = this.itemHelper.getItem(weapon[0]._tpl)[1];
|
const weaponTemplate = this.itemHelper.getItem(weapon[0]._tpl)[1];
|
||||||
|
|
||||||
// It's ammo, use predefined ammo parameter
|
// It's ammo, use predefined ammo parameter
|
||||||
@ -950,8 +949,8 @@ export class BotEquipmentModGenerator
|
|||||||
if (modSpawnResult === ModSpawn.DEFAULT_MOD)
|
if (modSpawnResult === ModSpawn.DEFAULT_MOD)
|
||||||
{
|
{
|
||||||
const matchingPreset = this.getMatchingPreset(weaponTemplate, parentTemplate._id);
|
const matchingPreset = this.getMatchingPreset(weaponTemplate, parentTemplate._id);
|
||||||
const matchingMod = matchingPreset._items.find((item) =>
|
const matchingMod = matchingPreset._items.find(item =>
|
||||||
item?.slotId?.toLowerCase() === modSlot.toLowerCase()
|
item?.slotId?.toLowerCase() === modSlot.toLowerCase(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Only filter mods down to single default item if it already exists in existing itemModPool, OR the default item has no children
|
// Only filter mods down to single default item if it already exists in existing itemModPool, OR the default item has no children
|
||||||
@ -967,8 +966,8 @@ export class BotEquipmentModGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check the filter of the slot to ensure a chosen mod fits
|
// Check the filter of the slot to ensure a chosen mod fits
|
||||||
const parentSlotCompatibleItems = parentTemplate._props.Slots?.find((slot) =>
|
const parentSlotCompatibleItems = parentTemplate._props.Slots?.find(slot =>
|
||||||
slot._name.toLowerCase() === modSlot.toLowerCase()
|
slot._name.toLowerCase() === modSlot.toLowerCase(),
|
||||||
)._props.filters[0].Filter;
|
)._props.filters[0].Filter;
|
||||||
|
|
||||||
// Mod isnt in existing pool, only add if it has no children and matches parent filter
|
// Mod isnt in existing pool, only add if it has no children and matches parent filter
|
||||||
@ -1176,7 +1175,7 @@ export class BotEquipmentModGenerator
|
|||||||
botEquipBlacklist: EquipmentFilterDetails,
|
botEquipBlacklist: EquipmentFilterDetails,
|
||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
const desiredSlotObject = modTemplate._props.Slots.find((slot) => slot._name.includes(desiredSlotName));
|
const desiredSlotObject = modTemplate._props.Slots.find(slot => slot._name.includes(desiredSlotName));
|
||||||
if (desiredSlotObject)
|
if (desiredSlotObject)
|
||||||
{
|
{
|
||||||
const supportedSubMods = desiredSlotObject._props.filters[0].Filter;
|
const supportedSubMods = desiredSlotObject._props.filters[0].Filter;
|
||||||
@ -1262,7 +1261,7 @@ export class BotEquipmentModGenerator
|
|||||||
const blacklist = this.itemFilterService.getBlacklistedItems().concat(
|
const blacklist = this.itemFilterService.getBlacklistedItems().concat(
|
||||||
botEquipBlacklist.equipment[modSlot] || [],
|
botEquipBlacklist.equipment[modSlot] || [],
|
||||||
);
|
);
|
||||||
result = allowedMods.filter((tpl) => !blacklist.includes(tpl));
|
result = allowedMods.filter(tpl => !blacklist.includes(tpl));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1288,7 +1287,7 @@ export class BotEquipmentModGenerator
|
|||||||
weaponName: parentTemplate._name,
|
weaponName: parentTemplate._name,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const camoraSlots = parentTemplate._props.Slots.filter((slot) => slot._name.startsWith("camora"));
|
const camoraSlots = parentTemplate._props.Slots.filter(slot => slot._name.startsWith("camora"));
|
||||||
|
|
||||||
// Attempt to generate camora slots for item
|
// Attempt to generate camora slots for item
|
||||||
modPool[parentTemplate._id] = {};
|
modPool[parentTemplate._id] = {};
|
||||||
@ -1422,17 +1421,17 @@ export class BotEquipmentModGenerator
|
|||||||
{
|
{
|
||||||
// Check to see if mount has a scope slot (only include primary slot, ignore the rest like the backup sight slots)
|
// Check to see if mount has a scope slot (only include primary slot, ignore the rest like the backup sight slots)
|
||||||
// Should only find 1 as there's currently no items with a mod_scope AND a mod_scope_000
|
// Should only find 1 as there's currently no items with a mod_scope AND a mod_scope_000
|
||||||
const scopeSlot = itemDetails._props.Slots.filter((slot) =>
|
const scopeSlot = itemDetails._props.Slots.filter(slot =>
|
||||||
["mod_scope", "mod_scope_000"].includes(slot._name)
|
["mod_scope", "mod_scope_000"].includes(slot._name),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Mods scope slot found must allow ALL whitelisted scope types OR be a mount
|
// Mods scope slot found must allow ALL whitelisted scope types OR be a mount
|
||||||
if (
|
if (
|
||||||
scopeSlot?.every((slot) =>
|
scopeSlot?.every(slot =>
|
||||||
slot._props.filters[0].Filter.every((tpl) =>
|
slot._props.filters[0].Filter.every(tpl =>
|
||||||
this.itemHelper.isOfBaseclasses(tpl, whitelistedSightTypes)
|
this.itemHelper.isOfBaseclasses(tpl, whitelistedSightTypes)
|
||||||
|| this.itemHelper.isOfBaseclass(tpl, BaseClasses.MOUNT)
|
|| this.itemHelper.isOfBaseclass(tpl, BaseClasses.MOUNT),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { BotInventoryGenerator } from "@spt-aki/generators/BotInventoryGenerator";
|
import { BotInventoryGenerator } from "@spt-aki/generators/BotInventoryGenerator";
|
||||||
import { BotLevelGenerator } from "@spt-aki/generators/BotLevelGenerator";
|
import { BotLevelGenerator } from "@spt-aki/generators/BotLevelGenerator";
|
||||||
import { BotDifficultyHelper } from "@spt-aki/helpers/BotDifficultyHelper";
|
import { BotDifficultyHelper } from "@spt-aki/helpers/BotDifficultyHelper";
|
||||||
@ -111,7 +110,7 @@ export class BotGenerator
|
|||||||
|
|
||||||
// Get raw json data for bot (Cloned)
|
// Get raw json data for bot (Cloned)
|
||||||
const botJsonTemplateClone = this.jsonUtil.clone(
|
const botJsonTemplateClone = this.jsonUtil.clone(
|
||||||
this.botHelper.getBotTemplate((botGenerationDetails.isPmc) ? bot.Info.Side : botGenerationDetails.role),
|
this.botHelper.getBotTemplate(botGenerationDetails.isPmc ? bot.Info.Side : botGenerationDetails.role),
|
||||||
);
|
);
|
||||||
|
|
||||||
bot = this.generateBot(sessionId, bot, botJsonTemplateClone, botGenerationDetails);
|
bot = this.generateBot(sessionId, bot, botJsonTemplateClone, botGenerationDetails);
|
||||||
@ -446,7 +445,7 @@ export class BotGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
return skillToAdd;
|
return skillToAdd;
|
||||||
}).filter((x) => x !== null);
|
}).filter(x => x !== null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -546,7 +545,7 @@ export class BotGenerator
|
|||||||
Nickname: bot.Info.Nickname,
|
Nickname: bot.Info.Nickname,
|
||||||
Side: bot.Info.Side,
|
Side: bot.Info.Side,
|
||||||
Level: bot.Info.Level,
|
Level: bot.Info.Level,
|
||||||
Time: (new Date().toISOString()),
|
Time: new Date().toISOString(),
|
||||||
Status: "Killed by ",
|
Status: "Killed by ",
|
||||||
KillerAccountId: "Unknown",
|
KillerAccountId: "Unknown",
|
||||||
KillerProfileId: "Unknown",
|
KillerProfileId: "Unknown",
|
||||||
@ -557,7 +556,7 @@ export class BotGenerator
|
|||||||
|
|
||||||
const inventoryItem: Item = {
|
const inventoryItem: Item = {
|
||||||
_id: this.hashUtil.generate(),
|
_id: this.hashUtil.generate(),
|
||||||
_tpl: ((bot.Info.Side === "Usec") ? BaseClasses.DOG_TAG_USEC : BaseClasses.DOG_TAG_BEAR),
|
_tpl: bot.Info.Side === "Usec" ? BaseClasses.DOG_TAG_USEC : BaseClasses.DOG_TAG_BEAR,
|
||||||
parentId: bot.Inventory.equipment,
|
parentId: bot.Inventory.equipment,
|
||||||
slotId: "Dogtag",
|
slotId: "Dogtag",
|
||||||
location: undefined,
|
location: undefined,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { BotEquipmentModGenerator } from "@spt-aki/generators/BotEquipmentModGenerator";
|
import { BotEquipmentModGenerator } from "@spt-aki/generators/BotEquipmentModGenerator";
|
||||||
import { BotLootGenerator } from "@spt-aki/generators/BotLootGenerator";
|
import { BotLootGenerator } from "@spt-aki/generators/BotLootGenerator";
|
||||||
import { BotWeaponGenerator } from "@spt-aki/generators/BotWeaponGenerator";
|
import { BotWeaponGenerator } from "@spt-aki/generators/BotWeaponGenerator";
|
||||||
@ -308,12 +307,11 @@ export class BotInventoryGenerator
|
|||||||
*/
|
*/
|
||||||
protected generateEquipment(settings: IGenerateEquipmentProperties): boolean
|
protected generateEquipment(settings: IGenerateEquipmentProperties): boolean
|
||||||
{
|
{
|
||||||
const spawnChance =
|
const spawnChance = ([EquipmentSlots.POCKETS, EquipmentSlots.SECURED_CONTAINER] as string[])
|
||||||
([EquipmentSlots.POCKETS, EquipmentSlots.SECURED_CONTAINER] as string[]).includes(
|
.includes(settings.rootEquipmentSlot)
|
||||||
settings.rootEquipmentSlot,
|
? 100
|
||||||
)
|
: settings.spawnChances.equipment[settings.rootEquipmentSlot];
|
||||||
? 100
|
|
||||||
: settings.spawnChances.equipment[settings.rootEquipmentSlot];
|
|
||||||
if (typeof spawnChance === "undefined")
|
if (typeof spawnChance === "undefined")
|
||||||
{
|
{
|
||||||
this.logger.warning(
|
this.logger.warning(
|
||||||
@ -444,7 +442,7 @@ export class BotInventoryGenerator
|
|||||||
for (const modSlot of Object.keys(modPool ?? []))
|
for (const modSlot of Object.keys(modPool ?? []))
|
||||||
{
|
{
|
||||||
const blacklistedMods = equipmentBlacklist[0]?.equipment[modSlot] || [];
|
const blacklistedMods = equipmentBlacklist[0]?.equipment[modSlot] || [];
|
||||||
const filteredMods = modPool[modSlot].filter((x) => !blacklistedMods.includes(x));
|
const filteredMods = modPool[modSlot].filter(x => !blacklistedMods.includes(x));
|
||||||
|
|
||||||
if (filteredMods.length > 0)
|
if (filteredMods.length > 0)
|
||||||
{
|
{
|
||||||
@ -503,7 +501,7 @@ export class BotInventoryGenerator
|
|||||||
* @param equipmentChances Chances bot has certain equipment
|
* @param equipmentChances Chances bot has certain equipment
|
||||||
* @returns What slots bot should have weapons generated for
|
* @returns What slots bot should have weapons generated for
|
||||||
*/
|
*/
|
||||||
protected getDesiredWeaponsForBot(equipmentChances: Chances): { slot: EquipmentSlots; shouldSpawn: boolean; }[]
|
protected getDesiredWeaponsForBot(equipmentChances: Chances): { slot: EquipmentSlots, shouldSpawn: boolean }[]
|
||||||
{
|
{
|
||||||
const shouldSpawnPrimary = this.randomUtil.getChance100(equipmentChances.equipment.FirstPrimaryWeapon);
|
const shouldSpawnPrimary = this.randomUtil.getChance100(equipmentChances.equipment.FirstPrimaryWeapon);
|
||||||
return [{ slot: EquipmentSlots.FIRST_PRIMARY_WEAPON, shouldSpawn: shouldSpawnPrimary }, {
|
return [{ slot: EquipmentSlots.FIRST_PRIMARY_WEAPON, shouldSpawn: shouldSpawnPrimary }, {
|
||||||
@ -532,7 +530,7 @@ export class BotInventoryGenerator
|
|||||||
*/
|
*/
|
||||||
protected addWeaponAndMagazinesToInventory(
|
protected addWeaponAndMagazinesToInventory(
|
||||||
sessionId: string,
|
sessionId: string,
|
||||||
weaponSlot: { slot: EquipmentSlots; shouldSpawn: boolean; },
|
weaponSlot: { slot: EquipmentSlots, shouldSpawn: boolean },
|
||||||
templateInventory: Inventory,
|
templateInventory: Inventory,
|
||||||
botInventory: PmcInventory,
|
botInventory: PmcInventory,
|
||||||
equipmentChances: Chances,
|
equipmentChances: Chances,
|
||||||
@ -567,18 +565,18 @@ export class BotInventoryGenerator
|
|||||||
export interface IGenerateEquipmentProperties
|
export interface IGenerateEquipmentProperties
|
||||||
{
|
{
|
||||||
/** Root Slot being generated */
|
/** Root Slot being generated */
|
||||||
rootEquipmentSlot: string;
|
rootEquipmentSlot: string
|
||||||
/** Equipment pool for root slot being generated */
|
/** Equipment pool for root slot being generated */
|
||||||
rootEquipmentPool: Record<string, number>;
|
rootEquipmentPool: Record<string, number>
|
||||||
modPool: Mods;
|
modPool: Mods
|
||||||
/** Dictionary of mod items and their chance to spawn for this bot type */
|
/** Dictionary of mod items and their chance to spawn for this bot type */
|
||||||
spawnChances: Chances;
|
spawnChances: Chances
|
||||||
/** Role being generated for */
|
/** Role being generated for */
|
||||||
botRole: string;
|
botRole: string
|
||||||
/** Level of bot being generated */
|
/** Level of bot being generated */
|
||||||
botLevel: number;
|
botLevel: number
|
||||||
inventory: PmcInventory;
|
inventory: PmcInventory
|
||||||
botEquipmentConfig: EquipmentFilters;
|
botEquipmentConfig: EquipmentFilters
|
||||||
/** Settings from bot.json to adjust how item is generated */
|
/** Settings from bot.json to adjust how item is generated */
|
||||||
randomisationDetails: RandomisationDetails;
|
randomisationDetails: RandomisationDetails
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { MinMax } from "@spt-aki/models/common/MinMax";
|
import { MinMax } from "@spt-aki/models/common/MinMax";
|
||||||
import { IRandomisedBotLevelResult } from "@spt-aki/models/eft/bot/IRandomisedBotLevelResult";
|
import { IRandomisedBotLevelResult } from "@spt-aki/models/eft/bot/IRandomisedBotLevelResult";
|
||||||
import { IExpTable } from "@spt-aki/models/eft/common/IGlobals";
|
import { IExpTable } from "@spt-aki/models/eft/common/IGlobals";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { BotWeaponGenerator } from "@spt-aki/generators/BotWeaponGenerator";
|
import { BotWeaponGenerator } from "@spt-aki/generators/BotWeaponGenerator";
|
||||||
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
||||||
import { BotHelper } from "@spt-aki/helpers/BotHelper";
|
import { BotHelper } from "@spt-aki/helpers/BotHelper";
|
||||||
@ -292,7 +291,7 @@ export class BotLootGenerator
|
|||||||
// Secure
|
// Secure
|
||||||
|
|
||||||
// only add if not a pmc or is pmc and flag is true
|
// only add if not a pmc or is pmc and flag is true
|
||||||
if (!isPmc || (isPmc && this.pmcConfig.addSecureContainerLootFromBotConfig))
|
if (!isPmc || isPmc && this.pmcConfig.addSecureContainerLootFromBotConfig)
|
||||||
{
|
{
|
||||||
this.addLootFromPool(
|
this.addLootFromPool(
|
||||||
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.SECURE, botJsonTemplate),
|
this.botLootCacheService.getLootFromCache(botRole, isPmc, LootCacheType.SECURE, botJsonTemplate),
|
||||||
@ -317,12 +316,12 @@ export class BotLootGenerator
|
|||||||
{
|
{
|
||||||
const result = [EquipmentSlots.POCKETS];
|
const result = [EquipmentSlots.POCKETS];
|
||||||
|
|
||||||
if (botInventory.items.find((item) => item.slotId === EquipmentSlots.TACTICAL_VEST))
|
if (botInventory.items.find(item => item.slotId === EquipmentSlots.TACTICAL_VEST))
|
||||||
{
|
{
|
||||||
result.push(EquipmentSlots.TACTICAL_VEST);
|
result.push(EquipmentSlots.TACTICAL_VEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (botInventory.items.find((item) => item.slotId === EquipmentSlots.BACKPACK))
|
if (botInventory.items.find(item => item.slotId === EquipmentSlots.BACKPACK))
|
||||||
{
|
{
|
||||||
result.push(EquipmentSlots.BACKPACK);
|
result.push(EquipmentSlots.BACKPACK);
|
||||||
}
|
}
|
||||||
@ -476,7 +475,7 @@ export class BotLootGenerator
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
itemWithChildrenToAdd.push(...itemsToAdd.flatMap((moneyStack) => moneyStack));
|
itemWithChildrenToAdd.push(...itemsToAdd.flatMap(moneyStack => moneyStack));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectAll, injectable } from "tsyringe";
|
import { inject, injectAll, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { BotEquipmentModGenerator } from "@spt-aki/generators/BotEquipmentModGenerator";
|
import { BotEquipmentModGenerator } from "@spt-aki/generators/BotEquipmentModGenerator";
|
||||||
import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen";
|
import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen";
|
||||||
import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
|
import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
|
||||||
@ -200,7 +199,7 @@ export class BotWeaponGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fill existing magazines to full and sync ammo type
|
// Fill existing magazines to full and sync ammo type
|
||||||
for (const magazine of weaponWithModsArray.filter((item) => item.slotId === this.modMagazineSlotId))
|
for (const magazine of weaponWithModsArray.filter(item => item.slotId === this.modMagazineSlotId))
|
||||||
{
|
{
|
||||||
this.fillExistingMagazines(weaponWithModsArray, magazine, ammoTpl);
|
this.fillExistingMagazines(weaponWithModsArray, magazine, ammoTpl);
|
||||||
}
|
}
|
||||||
@ -212,12 +211,12 @@ export class BotWeaponGenerator
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Guns have variety of possible Chamber ids, patron_in_weapon/patron_in_weapon_000/patron_in_weapon_001
|
// Guns have variety of possible Chamber ids, patron_in_weapon/patron_in_weapon_000/patron_in_weapon_001
|
||||||
const chamberSlotNames = weaponItemTemplate._props.Chambers.map((x) => x._name);
|
const chamberSlotNames = weaponItemTemplate._props.Chambers.map(x => x._name);
|
||||||
this.addCartridgeToChamber(weaponWithModsArray, ammoTpl, chamberSlotNames);
|
this.addCartridgeToChamber(weaponWithModsArray, ammoTpl, chamberSlotNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill UBGL if found
|
// Fill UBGL if found
|
||||||
const ubglMod = weaponWithModsArray.find((x) => x.slotId === "mod_launcher");
|
const ubglMod = weaponWithModsArray.find(x => x.slotId === "mod_launcher");
|
||||||
let ubglAmmoTpl: string = undefined;
|
let ubglAmmoTpl: string = undefined;
|
||||||
if (ubglMod)
|
if (ubglMod)
|
||||||
{
|
{
|
||||||
@ -246,7 +245,7 @@ export class BotWeaponGenerator
|
|||||||
{
|
{
|
||||||
for (const slotId of chamberSlotIds)
|
for (const slotId of chamberSlotIds)
|
||||||
{
|
{
|
||||||
const existingItemWithSlot = weaponWithModsArray.find((x) => x.slotId === slotId);
|
const existingItemWithSlot = weaponWithModsArray.find(x => x.slotId === slotId);
|
||||||
if (!existingItemWithSlot)
|
if (!existingItemWithSlot)
|
||||||
{
|
{
|
||||||
// Not found, add new slot to weapon
|
// Not found, add new slot to weapon
|
||||||
@ -367,11 +366,11 @@ export class BotWeaponGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over required slots in db item, check mod exists for that slot
|
// Iterate over required slots in db item, check mod exists for that slot
|
||||||
for (const modSlotTemplate of modTemplate._props.Slots.filter((slot) => slot._required))
|
for (const modSlotTemplate of modTemplate._props.Slots.filter(slot => slot._required))
|
||||||
{
|
{
|
||||||
const slotName = modSlotTemplate._name;
|
const slotName = modSlotTemplate._name;
|
||||||
const weaponSlotItem = weaponItemArray.find((weaponItem) =>
|
const weaponSlotItem = weaponItemArray.find(weaponItem =>
|
||||||
weaponItem.parentId === mod._id && weaponItem.slotId === slotName
|
weaponItem.parentId === mod._id && weaponItem.slotId === slotName,
|
||||||
);
|
);
|
||||||
if (!weaponSlotItem)
|
if (!weaponSlotItem)
|
||||||
{
|
{
|
||||||
@ -442,7 +441,7 @@ export class BotWeaponGenerator
|
|||||||
ammoTemplate,
|
ammoTemplate,
|
||||||
inventory,
|
inventory,
|
||||||
);
|
);
|
||||||
this.inventoryMagGenComponents.find((v) => v.canHandleInventoryMagGen(inventoryMagGenModel)).process(
|
this.inventoryMagGenComponents.find(v => v.canHandleInventoryMagGen(inventoryMagGenModel)).process(
|
||||||
inventoryMagGenModel,
|
inventoryMagGenModel,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -468,13 +467,13 @@ export class BotWeaponGenerator
|
|||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
// Find ubgl mod item + get details of it from db
|
// Find ubgl mod item + get details of it from db
|
||||||
const ubglMod = weaponMods.find((x) => x.slotId === "mod_launcher");
|
const ubglMod = weaponMods.find(x => x.slotId === "mod_launcher");
|
||||||
const ubglDbTemplate = this.itemHelper.getItem(ubglMod._tpl)[1];
|
const ubglDbTemplate = this.itemHelper.getItem(ubglMod._tpl)[1];
|
||||||
|
|
||||||
// Define min/max of how many grenades bot will have
|
// Define min/max of how many grenades bot will have
|
||||||
const ubglMinMax: GenerationData = {
|
const ubglMinMax: GenerationData = {
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
weights: { "1": 1, "2": 1 },
|
weights: { 1: 1, 2: 1 },
|
||||||
whitelist: {},
|
whitelist: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -489,7 +488,7 @@ export class BotWeaponGenerator
|
|||||||
ubglAmmoDbTemplate,
|
ubglAmmoDbTemplate,
|
||||||
inventory,
|
inventory,
|
||||||
);
|
);
|
||||||
this.inventoryMagGenComponents.find((v) => v.canHandleInventoryMagGen(ubglAmmoGenModel)).process(
|
this.inventoryMagGenComponents.find(v => v.canHandleInventoryMagGen(ubglAmmoGenModel)).process(
|
||||||
ubglAmmoGenModel,
|
ubglAmmoGenModel,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -537,7 +536,7 @@ export class BotWeaponGenerator
|
|||||||
botRole: string,
|
botRole: string,
|
||||||
): string
|
): string
|
||||||
{
|
{
|
||||||
const magazine = weaponMods.find((m) => m.slotId === this.modMagazineSlotId);
|
const magazine = weaponMods.find(m => m.slotId === this.modMagazineSlotId);
|
||||||
if (!magazine)
|
if (!magazine)
|
||||||
{
|
{
|
||||||
// Edge case - magazineless chamber loaded weapons dont have magazines, e.g. mp18
|
// Edge case - magazineless chamber loaded weapons dont have magazines, e.g. mp18
|
||||||
@ -737,8 +736,8 @@ export class BotWeaponGenerator
|
|||||||
magazineTemplate: ITemplateItem,
|
magazineTemplate: ITemplateItem,
|
||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
const magazineCartridgeChildItem = weaponWithMods.find((m) =>
|
const magazineCartridgeChildItem = weaponWithMods.find(m =>
|
||||||
m.parentId === magazine._id && m.slotId === "cartridges"
|
m.parentId === magazine._id && m.slotId === "cartridges",
|
||||||
);
|
);
|
||||||
if (magazineCartridgeChildItem)
|
if (magazineCartridgeChildItem)
|
||||||
{
|
{
|
||||||
@ -767,7 +766,7 @@ export class BotWeaponGenerator
|
|||||||
// for CylinderMagazine we exchange the ammo in the "camoras".
|
// for CylinderMagazine we exchange the ammo in the "camoras".
|
||||||
// This might not be necessary since we already filled the camoras with a random whitelisted and compatible ammo type,
|
// This might not be necessary since we already filled the camoras with a random whitelisted and compatible ammo type,
|
||||||
// but I'm not sure whether this is also used elsewhere
|
// but I'm not sure whether this is also used elsewhere
|
||||||
const camoras = weaponMods.filter((x) => x.parentId === magazineId && x.slotId.startsWith("camora"));
|
const camoras = weaponMods.filter(x => x.parentId === magazineId && x.slotId.startsWith("camora"));
|
||||||
for (const camora of camoras)
|
for (const camora of camoras)
|
||||||
{
|
{
|
||||||
camora._tpl = ammoTpl;
|
camora._tpl = ammoTpl;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
|
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
||||||
@ -50,7 +49,7 @@ export class FenceBaseAssortGenerator
|
|||||||
const blockedSeasonalItems = this.seasonalEventService.getInactiveSeasonalEventItems();
|
const blockedSeasonalItems = this.seasonalEventService.getInactiveSeasonalEventItems();
|
||||||
const baseFenceAssort = this.databaseServer.getTables().traders[Traders.FENCE].assort;
|
const baseFenceAssort = this.databaseServer.getTables().traders[Traders.FENCE].assort;
|
||||||
|
|
||||||
for (const rootItemDb of this.itemHelper.getItems().filter((item) => this.isValidFenceItem(item)))
|
for (const rootItemDb of this.itemHelper.getItems().filter(item => this.isValidFenceItem(item)))
|
||||||
{
|
{
|
||||||
// Skip blacklisted items
|
// Skip blacklisted items
|
||||||
if (this.itemFilterService.isItemBlacklisted(rootItemDb._id))
|
if (this.itemFilterService.isItemBlacklisted(rootItemDb._id))
|
||||||
@ -144,7 +143,7 @@ export class FenceBaseAssortGenerator
|
|||||||
for (const defaultPreset of defaultPresets)
|
for (const defaultPreset of defaultPresets)
|
||||||
{
|
{
|
||||||
// Skip presets we've already added
|
// Skip presets we've already added
|
||||||
if (baseFenceAssort.items.some((item) => item.upd && item.upd.sptPresetId === defaultPreset._id))
|
if (baseFenceAssort.items.some(item => item.upd && item.upd.sptPresetId === defaultPreset._id))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -252,7 +251,7 @@ export class FenceBaseAssortGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for and add required soft inserts to armors
|
// Check for and add required soft inserts to armors
|
||||||
const requiredSlots = itemDbDetails._props.Slots.filter((slot) => slot._required);
|
const requiredSlots = itemDbDetails._props.Slots.filter(slot => slot._required);
|
||||||
const hasRequiredSlots = requiredSlots.length > 0;
|
const hasRequiredSlots = requiredSlots.length > 0;
|
||||||
if (hasRequiredSlots)
|
if (hasRequiredSlots)
|
||||||
{
|
{
|
||||||
@ -284,8 +283,8 @@ export class FenceBaseAssortGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for and add plate items
|
// Check for and add plate items
|
||||||
const plateSlots = itemDbDetails._props.Slots.filter((slot) =>
|
const plateSlots = itemDbDetails._props.Slots.filter(slot =>
|
||||||
this.itemHelper.isRemovablePlateSlot(slot._name)
|
this.itemHelper.isRemovablePlateSlot(slot._name),
|
||||||
);
|
);
|
||||||
if (plateSlots.length > 0)
|
if (plateSlots.length > 0)
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
export interface IFilterPlateModsForSlotByLevelResult
|
export interface IFilterPlateModsForSlotByLevelResult
|
||||||
{
|
{
|
||||||
result: Result;
|
result: Result
|
||||||
plateModTpls: string[];
|
plateModTpls: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Result
|
export enum Result
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ContainerHelper } from "@spt-aki/helpers/ContainerHelper";
|
import { ContainerHelper } from "@spt-aki/helpers/ContainerHelper";
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
||||||
@ -29,17 +28,17 @@ import { ProbabilityObject, ProbabilityObjectArray, RandomUtil } from "@spt-aki/
|
|||||||
|
|
||||||
export interface IContainerItem
|
export interface IContainerItem
|
||||||
{
|
{
|
||||||
items: Item[];
|
items: Item[]
|
||||||
width: number;
|
width: number
|
||||||
height: number;
|
height: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IContainerGroupCount
|
export interface IContainerGroupCount
|
||||||
{
|
{
|
||||||
/** Containers this group has + probabilty to spawn */
|
/** Containers this group has + probabilty to spawn */
|
||||||
containerIdsWithProbability: Record<string, number>;
|
containerIdsWithProbability: Record<string, number>
|
||||||
/** How many containers the map should spawn with this group id */
|
/** How many containers the map should spawn with this group id */
|
||||||
chosenCount: number;
|
chosenCount: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
@ -135,7 +134,7 @@ export class LocationGenerator
|
|||||||
// Randomisation is turned off globally or just turned off for this map
|
// Randomisation is turned off globally or just turned off for this map
|
||||||
if (
|
if (
|
||||||
!(this.locationConfig.containerRandomisationSettings.enabled
|
!(this.locationConfig.containerRandomisationSettings.enabled
|
||||||
&& this.locationConfig.containerRandomisationSettings.maps[locationId])
|
&& this.locationConfig.containerRandomisationSettings.maps[locationId])
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
@ -218,8 +217,8 @@ export class LocationGenerator
|
|||||||
for (const chosenContainerId of chosenContainerIds)
|
for (const chosenContainerId of chosenContainerIds)
|
||||||
{
|
{
|
||||||
// Look up container object from full list of containers on map
|
// Look up container object from full list of containers on map
|
||||||
const containerObject = staticRandomisableContainersOnMap.find((staticContainer) =>
|
const containerObject = staticRandomisableContainersOnMap.find(staticContainer =>
|
||||||
staticContainer.template.Id === chosenContainerId
|
staticContainer.template.Id === chosenContainerId,
|
||||||
);
|
);
|
||||||
if (!containerObject)
|
if (!containerObject)
|
||||||
{
|
{
|
||||||
@ -262,11 +261,11 @@ export class LocationGenerator
|
|||||||
*/
|
*/
|
||||||
protected getRandomisableContainersOnMap(staticContainers: IStaticContainerData[]): IStaticContainerData[]
|
protected getRandomisableContainersOnMap(staticContainers: IStaticContainerData[]): IStaticContainerData[]
|
||||||
{
|
{
|
||||||
return staticContainers.filter((staticContainer) =>
|
return staticContainers.filter(staticContainer =>
|
||||||
staticContainer.probability !== 1 && !staticContainer.template.IsAlwaysSpawn
|
staticContainer.probability !== 1 && !staticContainer.template.IsAlwaysSpawn
|
||||||
&& !this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes(
|
&& !this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes(
|
||||||
staticContainer.template.Items[0]._tpl,
|
staticContainer.template.Items[0]._tpl,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,11 +276,11 @@ export class LocationGenerator
|
|||||||
*/
|
*/
|
||||||
protected getGuaranteedContainers(staticContainersOnMap: IStaticContainerData[]): IStaticContainerData[]
|
protected getGuaranteedContainers(staticContainersOnMap: IStaticContainerData[]): IStaticContainerData[]
|
||||||
{
|
{
|
||||||
return staticContainersOnMap.filter((staticContainer) =>
|
return staticContainersOnMap.filter(staticContainer =>
|
||||||
staticContainer.probability === 1 || staticContainer.template.IsAlwaysSpawn
|
staticContainer.probability === 1 || staticContainer.template.IsAlwaysSpawn
|
||||||
|| this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes(
|
|| this.locationConfig.containerRandomisationSettings.containerTypesToNotRandomise.includes(
|
||||||
staticContainer.template.Items[0]._tpl,
|
staticContainer.template.Items[0]._tpl,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,11 +337,11 @@ export class LocationGenerator
|
|||||||
chosenCount: this.randomUtil.getInt(
|
chosenCount: this.randomUtil.getInt(
|
||||||
Math.round(
|
Math.round(
|
||||||
groupData.minContainers
|
groupData.minContainers
|
||||||
* this.locationConfig.containerRandomisationSettings.containerGroupMinSizeMultiplier,
|
* this.locationConfig.containerRandomisationSettings.containerGroupMinSizeMultiplier,
|
||||||
),
|
),
|
||||||
Math.round(
|
Math.round(
|
||||||
groupData.maxContainers
|
groupData.maxContainers
|
||||||
* this.locationConfig.containerRandomisationSettings.containerGroupMaxSizeMultiplier,
|
* this.locationConfig.containerRandomisationSettings.containerGroupMaxSizeMultiplier,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
@ -412,9 +411,9 @@ export class LocationGenerator
|
|||||||
const containerLootPool = this.getPossibleLootItemsForContainer(containerTpl, staticLootDist);
|
const containerLootPool = this.getPossibleLootItemsForContainer(containerTpl, staticLootDist);
|
||||||
|
|
||||||
// Some containers need to have items forced into it (quest keys etc)
|
// Some containers need to have items forced into it (quest keys etc)
|
||||||
const tplsForced = staticForced.filter((forcedStaticProp) =>
|
const tplsForced = staticForced.filter(forcedStaticProp =>
|
||||||
forcedStaticProp.containerId === containerClone.template.Id
|
forcedStaticProp.containerId === containerClone.template.Id,
|
||||||
).map((x) => x.itemTpl);
|
).map(x => x.itemTpl);
|
||||||
|
|
||||||
// Draw random loot
|
// Draw random loot
|
||||||
// Money spawn more than once in container
|
// Money spawn more than once in container
|
||||||
@ -427,7 +426,7 @@ export class LocationGenerator
|
|||||||
itemCountToAdd,
|
itemCountToAdd,
|
||||||
this.locationConfig.allowDuplicateItemsInStaticContainers,
|
this.locationConfig.allowDuplicateItemsInStaticContainers,
|
||||||
locklist,
|
locklist,
|
||||||
).filter((tpl) => !tplsForced.includes(tpl));
|
).filter(tpl => !tplsForced.includes(tpl));
|
||||||
|
|
||||||
// Add forced loot to chosen item pool
|
// Add forced loot to chosen item pool
|
||||||
const tplsToAddToContainer = tplsForced.concat(chosenTpls);
|
const tplsToAddToContainer = tplsForced.concat(chosenTpls);
|
||||||
@ -597,7 +596,7 @@ export class LocationGenerator
|
|||||||
|
|
||||||
// Build the list of forced loot from both `spawnpointsForced` and any point marked `IsAlwaysSpawn`
|
// Build the list of forced loot from both `spawnpointsForced` and any point marked `IsAlwaysSpawn`
|
||||||
dynamicForcedSpawnPoints.push(...dynamicLootDist.spawnpointsForced);
|
dynamicForcedSpawnPoints.push(...dynamicLootDist.spawnpointsForced);
|
||||||
dynamicForcedSpawnPoints.push(...dynamicLootDist.spawnpoints.filter((point) => point.template.IsAlwaysSpawn));
|
dynamicForcedSpawnPoints.push(...dynamicLootDist.spawnpoints.filter(point => point.template.IsAlwaysSpawn));
|
||||||
|
|
||||||
// Add forced loot
|
// Add forced loot
|
||||||
this.addForcedLoot(loot, dynamicForcedSpawnPoints, locationName);
|
this.addForcedLoot(loot, dynamicForcedSpawnPoints, locationName);
|
||||||
@ -607,10 +606,10 @@ export class LocationGenerator
|
|||||||
// Draw from random distribution
|
// Draw from random distribution
|
||||||
const desiredSpawnpointCount = Math.round(
|
const desiredSpawnpointCount = Math.round(
|
||||||
this.getLooseLootMultiplerForLocation(locationName)
|
this.getLooseLootMultiplerForLocation(locationName)
|
||||||
* this.randomUtil.getNormallyDistributedRandomNumber(
|
* this.randomUtil.getNormallyDistributedRandomNumber(
|
||||||
dynamicLootDist.spawnpointCount.mean,
|
dynamicLootDist.spawnpointCount.mean,
|
||||||
dynamicLootDist.spawnpointCount.std,
|
dynamicLootDist.spawnpointCount.std,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Positions not in forced but have 100% chance to spawn
|
// Positions not in forced but have 100% chance to spawn
|
||||||
@ -660,11 +659,11 @@ export class LocationGenerator
|
|||||||
|
|
||||||
// Filter out duplicate locationIds
|
// Filter out duplicate locationIds
|
||||||
chosenSpawnpoints = [
|
chosenSpawnpoints = [
|
||||||
...new Map(chosenSpawnpoints.map((spawnPoint) => [spawnPoint.locationId, spawnPoint])).values(),
|
...new Map(chosenSpawnpoints.map(spawnPoint => [spawnPoint.locationId, spawnPoint])).values(),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Do we have enough items in pool to fulfill requirement
|
// Do we have enough items in pool to fulfill requirement
|
||||||
const tooManySpawnPointsRequested = (desiredSpawnpointCount - chosenSpawnpoints.length) > 0;
|
const tooManySpawnPointsRequested = desiredSpawnpointCount - chosenSpawnpoints.length > 0;
|
||||||
if (tooManySpawnPointsRequested)
|
if (tooManySpawnPointsRequested)
|
||||||
{
|
{
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
@ -704,7 +703,7 @@ export class LocationGenerator
|
|||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
!seasonalEventActive && seasonalItemTplBlacklist.includes(
|
!seasonalEventActive && seasonalItemTplBlacklist.includes(
|
||||||
spawnPoint.template.Items.find((item) => item._id === itemDist.composedKey.key)._tpl,
|
spawnPoint.template.Items.find(item => item._id === itemDist.composedKey.key)._tpl,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -755,8 +754,8 @@ export class LocationGenerator
|
|||||||
for (const itemTpl of lootToForceSingleAmountOnMap)
|
for (const itemTpl of lootToForceSingleAmountOnMap)
|
||||||
{
|
{
|
||||||
// Get all spawn positions for item tpl in forced loot array
|
// Get all spawn positions for item tpl in forced loot array
|
||||||
const items = forcedSpawnPoints.filter((forcedSpawnPoint) =>
|
const items = forcedSpawnPoints.filter(forcedSpawnPoint =>
|
||||||
forcedSpawnPoint.template.Items[0]._tpl === itemTpl
|
forcedSpawnPoint.template.Items[0]._tpl === itemTpl,
|
||||||
);
|
);
|
||||||
if (!items || items.length === 0)
|
if (!items || items.length === 0)
|
||||||
{
|
{
|
||||||
@ -780,7 +779,7 @@ export class LocationGenerator
|
|||||||
// Choose 1 out of all found spawn positions for spawn id and add to loot array
|
// Choose 1 out of all found spawn positions for spawn id and add to loot array
|
||||||
for (const spawnPointLocationId of spawnpointArray.draw(1, false))
|
for (const spawnPointLocationId of spawnpointArray.draw(1, false))
|
||||||
{
|
{
|
||||||
const itemToAdd = items.find((item) => item.locationId === spawnPointLocationId);
|
const itemToAdd = items.find(item => item.locationId === spawnPointLocationId);
|
||||||
const lootItem = itemToAdd.template;
|
const lootItem = itemToAdd.template;
|
||||||
lootItem.Root = this.objectId.generate();
|
lootItem.Root = this.objectId.generate();
|
||||||
lootItem.Items[0]._id = lootItem.Root;
|
lootItem.Items[0]._id = lootItem.Root;
|
||||||
@ -816,8 +815,8 @@ export class LocationGenerator
|
|||||||
locationTemplateToAdd.Items[0]._id = locationTemplateToAdd.Root;
|
locationTemplateToAdd.Items[0]._id = locationTemplateToAdd.Root;
|
||||||
|
|
||||||
// Push forced location into array as long as it doesnt exist already
|
// Push forced location into array as long as it doesnt exist already
|
||||||
const existingLocation = lootLocationTemplates.find((spawnPoint) =>
|
const existingLocation = lootLocationTemplates.find(spawnPoint =>
|
||||||
spawnPoint.Id === locationTemplateToAdd.Id
|
spawnPoint.Id === locationTemplateToAdd.Id,
|
||||||
);
|
);
|
||||||
if (!existingLocation)
|
if (!existingLocation)
|
||||||
{
|
{
|
||||||
@ -845,7 +844,7 @@ export class LocationGenerator
|
|||||||
staticAmmoDist: Record<string, IStaticAmmoDetails[]>,
|
staticAmmoDist: Record<string, IStaticAmmoDetails[]>,
|
||||||
): IContainerItem
|
): IContainerItem
|
||||||
{
|
{
|
||||||
const chosenItem = spawnPoint.template.Items.find((item) => item._id === chosenComposedKey);
|
const chosenItem = spawnPoint.template.Items.find(item => item._id === chosenComposedKey);
|
||||||
const chosenTpl = chosenItem._tpl;
|
const chosenTpl = chosenItem._tpl;
|
||||||
const itemTemplate = this.itemHelper.getItem(chosenTpl)[1];
|
const itemTemplate = this.itemHelper.getItem(chosenTpl)[1];
|
||||||
|
|
||||||
@ -945,10 +944,10 @@ export class LocationGenerator
|
|||||||
{
|
{
|
||||||
if (this.itemHelper.isOfBaseclass(chosenTpl, BaseClasses.WEAPON))
|
if (this.itemHelper.isOfBaseclass(chosenTpl, BaseClasses.WEAPON))
|
||||||
{
|
{
|
||||||
return items.find((v) => v._tpl === chosenTpl && v.parentId === undefined);
|
return items.find(v => v._tpl === chosenTpl && v.parentId === undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
return items.find((item) => item._tpl === chosenTpl);
|
return items.find(item => item._tpl === chosenTpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: rewrite, BIG yikes
|
// TODO: rewrite, BIG yikes
|
||||||
@ -1052,7 +1051,7 @@ export class LocationGenerator
|
|||||||
// it can handle revolver ammo (it's not restructured to be used here yet.)
|
// it can handle revolver ammo (it's not restructured to be used here yet.)
|
||||||
// General: Make a WeaponController for Ragfair preset stuff and the generating weapons and ammo stuff from
|
// General: Make a WeaponController for Ragfair preset stuff and the generating weapons and ammo stuff from
|
||||||
// BotGenerator
|
// BotGenerator
|
||||||
const magazine = items.filter((item) => item.slotId === "mod_magazine")[0];
|
const magazine = items.filter(item => item.slotId === "mod_magazine")[0];
|
||||||
// some weapon presets come without magazine; only fill the mag if it exists
|
// some weapon presets come without magazine; only fill the mag if it exists
|
||||||
if (magazine)
|
if (magazine)
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
|
import { InventoryHelper } from "@spt-aki/helpers/InventoryHelper";
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
||||||
@ -21,7 +20,7 @@ import { HashUtil } from "@spt-aki/utils/HashUtil";
|
|||||||
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||||
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
||||||
|
|
||||||
type ItemLimit = { current: number; max: number; };
|
type ItemLimit = { current: number, max: number };
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class LootGenerator
|
export class LootGenerator
|
||||||
@ -74,8 +73,8 @@ export class LootGenerator
|
|||||||
if (desiredWeaponCrateCount > 0)
|
if (desiredWeaponCrateCount > 0)
|
||||||
{
|
{
|
||||||
// Get list of all sealed containers from db
|
// Get list of all sealed containers from db
|
||||||
const sealedWeaponContainerPool = Object.values(tables.templates.items).filter((x) =>
|
const sealedWeaponContainerPool = Object.values(tables.templates.items).filter(x =>
|
||||||
x._name.includes("event_container_airdrop")
|
x._name.includes("event_container_airdrop"),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (let index = 0; index < desiredWeaponCrateCount; index++)
|
for (let index = 0; index < desiredWeaponCrateCount; index++)
|
||||||
@ -92,11 +91,11 @@ export class LootGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get items from items.json that have a type of item + not in global blacklist + basetype is in whitelist
|
// Get items from items.json that have a type of item + not in global blacklist + basetype is in whitelist
|
||||||
const items = Object.entries(tables.templates.items).filter((x) =>
|
const items = Object.entries(tables.templates.items).filter(x =>
|
||||||
!itemBlacklist.has(x[1]._id)
|
!itemBlacklist.has(x[1]._id)
|
||||||
&& x[1]._type.toLowerCase() === "item"
|
&& x[1]._type.toLowerCase() === "item"
|
||||||
&& !x[1]._props.QuestItem
|
&& !x[1]._props.QuestItem
|
||||||
&& options.itemTypeWhitelist.includes(x[1]._parent)
|
&& options.itemTypeWhitelist.includes(x[1]._parent),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (items.length > 0)
|
if (items.length > 0)
|
||||||
@ -122,8 +121,8 @@ export class LootGenerator
|
|||||||
);
|
);
|
||||||
if (randomisedWeaponPresetCount > 0)
|
if (randomisedWeaponPresetCount > 0)
|
||||||
{
|
{
|
||||||
const weaponDefaultPresets = globalDefaultPresets.filter((preset) =>
|
const weaponDefaultPresets = globalDefaultPresets.filter(preset =>
|
||||||
this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON)
|
this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (weaponDefaultPresets.length > 0)
|
if (weaponDefaultPresets.length > 0)
|
||||||
@ -153,11 +152,11 @@ export class LootGenerator
|
|||||||
);
|
);
|
||||||
if (randomisedArmorPresetCount > 0)
|
if (randomisedArmorPresetCount > 0)
|
||||||
{
|
{
|
||||||
const armorDefaultPresets = globalDefaultPresets.filter((preset) =>
|
const armorDefaultPresets = globalDefaultPresets.filter(preset =>
|
||||||
this.itemHelper.armorItemCanHoldMods(preset._encyclopedia)
|
this.itemHelper.armorItemCanHoldMods(preset._encyclopedia),
|
||||||
);
|
);
|
||||||
const levelFilteredArmorPresets = armorDefaultPresets.filter((armor) =>
|
const levelFilteredArmorPresets = armorDefaultPresets.filter(armor =>
|
||||||
this.armorIsDesiredProtectionLevel(armor, options)
|
this.armorIsDesiredProtectionLevel(armor, options),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add some armors to rewards
|
// Add some armors to rewards
|
||||||
@ -192,21 +191,21 @@ export class LootGenerator
|
|||||||
*/
|
*/
|
||||||
protected armorIsDesiredProtectionLevel(armor: IPreset, options: LootRequest): boolean
|
protected armorIsDesiredProtectionLevel(armor: IPreset, options: LootRequest): boolean
|
||||||
{
|
{
|
||||||
const frontPlate = armor._items.find((mod) => mod?.slotId?.toLowerCase() === "front_plate");
|
const frontPlate = armor._items.find(mod => mod?.slotId?.toLowerCase() === "front_plate");
|
||||||
if (frontPlate)
|
if (frontPlate)
|
||||||
{
|
{
|
||||||
const plateDb = this.itemHelper.getItem(frontPlate._tpl);
|
const plateDb = this.itemHelper.getItem(frontPlate._tpl);
|
||||||
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
|
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
|
||||||
}
|
}
|
||||||
|
|
||||||
const helmetTop = armor._items.find((mod) => mod?.slotId?.toLowerCase() === "helmet_top");
|
const helmetTop = armor._items.find(mod => mod?.slotId?.toLowerCase() === "helmet_top");
|
||||||
if (helmetTop)
|
if (helmetTop)
|
||||||
{
|
{
|
||||||
const plateDb = this.itemHelper.getItem(helmetTop._tpl);
|
const plateDb = this.itemHelper.getItem(helmetTop._tpl);
|
||||||
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
|
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
|
||||||
}
|
}
|
||||||
|
|
||||||
const softArmorFront = armor._items.find((mod) => mod?.slotId?.toLowerCase() === "soft_armor_front");
|
const softArmorFront = armor._items.find(mod => mod?.slotId?.toLowerCase() === "soft_armor_front");
|
||||||
if (softArmorFront)
|
if (softArmorFront)
|
||||||
{
|
{
|
||||||
const plateDb = this.itemHelper.getItem(softArmorFront._tpl);
|
const plateDb = this.itemHelper.getItem(softArmorFront._tpl);
|
||||||
@ -242,7 +241,7 @@ export class LootGenerator
|
|||||||
*/
|
*/
|
||||||
protected findAndAddRandomItemToLoot(
|
protected findAndAddRandomItemToLoot(
|
||||||
items: [string, ITemplateItem][],
|
items: [string, ITemplateItem][],
|
||||||
itemTypeCounts: Record<string, { current: number; max: number; }>,
|
itemTypeCounts: Record<string, { current: number, max: number }>,
|
||||||
options: LootRequest,
|
options: LootRequest,
|
||||||
result: LootItem[],
|
result: LootItem[],
|
||||||
): boolean
|
): boolean
|
||||||
@ -317,7 +316,7 @@ export class LootGenerator
|
|||||||
*/
|
*/
|
||||||
protected findAndAddRandomPresetToLoot(
|
protected findAndAddRandomPresetToLoot(
|
||||||
presetPool: IPreset[],
|
presetPool: IPreset[],
|
||||||
itemTypeCounts: Record<string, { current: number; max: number; }>,
|
itemTypeCounts: Record<string, { current: number, max: number }>,
|
||||||
itemBlacklist: string[],
|
itemBlacklist: string[],
|
||||||
result: LootItem[],
|
result: LootItem[],
|
||||||
): boolean
|
): boolean
|
||||||
@ -408,7 +407,7 @@ export class LootGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get weapon preset - default or choose a random one from globals.json preset pool
|
// Get weapon preset - default or choose a random one from globals.json preset pool
|
||||||
let chosenWeaponPreset = (containerSettings.defaultPresetsOnly)
|
let chosenWeaponPreset = containerSettings.defaultPresetsOnly
|
||||||
? this.presetHelper.getDefaultPreset(chosenWeaponTpl)
|
? this.presetHelper.getDefaultPreset(chosenWeaponTpl)
|
||||||
: this.randomUtil.getArrayValue(this.presetHelper.getPresets(chosenWeaponTpl));
|
: this.randomUtil.getArrayValue(this.presetHelper.getPresets(chosenWeaponTpl));
|
||||||
|
|
||||||
@ -473,7 +472,7 @@ export class LootGenerator
|
|||||||
|
|
||||||
// Need to find boxes that matches weapons caliber
|
// Need to find boxes that matches weapons caliber
|
||||||
const weaponCaliber = weaponDetailsDb._props.ammoCaliber;
|
const weaponCaliber = weaponDetailsDb._props.ammoCaliber;
|
||||||
const ammoBoxesMatchingCaliber = ammoBoxesDetails.filter((x) => x._props.ammoCaliber === weaponCaliber);
|
const ammoBoxesMatchingCaliber = ammoBoxesDetails.filter(x => x._props.ammoCaliber === weaponCaliber);
|
||||||
if (ammoBoxesMatchingCaliber.length === 0)
|
if (ammoBoxesMatchingCaliber.length === 0)
|
||||||
{
|
{
|
||||||
this.logger.debug(`No ammo box with caliber ${weaponCaliber} found, skipping`);
|
this.logger.debug(`No ammo box with caliber ${weaponCaliber} found, skipping`);
|
||||||
@ -493,12 +492,12 @@ export class LootGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get all items of the desired type + not quest items + not globally blacklisted
|
// Get all items of the desired type + not quest items + not globally blacklisted
|
||||||
const rewardItemPool = Object.values(this.databaseServer.getTables().templates.items).filter((x) =>
|
const rewardItemPool = Object.values(this.databaseServer.getTables().templates.items).filter(x =>
|
||||||
x._parent === rewardTypeId
|
x._parent === rewardTypeId
|
||||||
&& x._type.toLowerCase() === "item"
|
&& x._type.toLowerCase() === "item"
|
||||||
&& !this.itemFilterService.isItemBlacklisted(x._id)
|
&& !this.itemFilterService.isItemBlacklisted(x._id)
|
||||||
&& (!(containerSettings.allowBossItems || this.itemFilterService.isBossItem(x._id)))
|
&& !(containerSettings.allowBossItems || this.itemFilterService.isBossItem(x._id))
|
||||||
&& !x._props.QuestItem
|
&& !x._props.QuestItem,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (rewardItemPool.length === 0)
|
if (rewardItemPool.length === 0)
|
||||||
@ -547,8 +546,8 @@ export class LootGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get items that fulfil reward type criteria from items that fit on gun
|
// Get items that fulfil reward type criteria from items that fit on gun
|
||||||
const relatedItems = linkedItemsToWeapon.filter((x) =>
|
const relatedItems = linkedItemsToWeapon.filter(x =>
|
||||||
x._parent === rewardTypeId && !this.itemFilterService.isItemBlacklisted(x._id)
|
x._parent === rewardTypeId && !this.itemFilterService.isItemBlacklisted(x._id),
|
||||||
);
|
);
|
||||||
if (!relatedItems || relatedItems.length === 0)
|
if (!relatedItems || relatedItems.length === 0)
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
|
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
|
||||||
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
||||||
@ -48,8 +47,8 @@ export class PMCLootGenerator
|
|||||||
if (Object.keys(this.pocketLootPool).length === 0)
|
if (Object.keys(this.pocketLootPool).length === 0)
|
||||||
{
|
{
|
||||||
const items = this.databaseServer.getTables().templates.items;
|
const items = this.databaseServer.getTables().templates.items;
|
||||||
const pmcPriceOverrides =
|
const pmcPriceOverrides
|
||||||
this.databaseServer.getTables().bots.types[botRole === "sptBear" ? "bear" : "usec"].inventory.items
|
= this.databaseServer.getTables().bots.types[botRole === "sptBear" ? "bear" : "usec"].inventory.items
|
||||||
.Pockets;
|
.Pockets;
|
||||||
|
|
||||||
const allowedItemTypes = this.pmcConfig.pocketLoot.whitelist;
|
const allowedItemTypes = this.pmcConfig.pocketLoot.whitelist;
|
||||||
@ -59,13 +58,13 @@ export class PMCLootGenerator
|
|||||||
// Blacklist inactive seasonal items
|
// Blacklist inactive seasonal items
|
||||||
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
|
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
|
||||||
|
|
||||||
const itemsToAdd = Object.values(items).filter((item) =>
|
const itemsToAdd = Object.values(items).filter(item =>
|
||||||
allowedItemTypes.includes(item._parent)
|
allowedItemTypes.includes(item._parent)
|
||||||
&& this.itemHelper.isValidItem(item._id)
|
&& this.itemHelper.isValidItem(item._id)
|
||||||
&& !pmcItemBlacklist.includes(item._id)
|
&& !pmcItemBlacklist.includes(item._id)
|
||||||
&& !itemBlacklist.includes(item._id)
|
&& !itemBlacklist.includes(item._id)
|
||||||
&& item._props.Width === 1
|
&& item._props.Width === 1
|
||||||
&& item._props.Height === 1
|
&& item._props.Height === 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const itemToAdd of itemsToAdd)
|
for (const itemToAdd of itemsToAdd)
|
||||||
@ -88,7 +87,7 @@ export class PMCLootGenerator
|
|||||||
{
|
{
|
||||||
// Invert price so cheapest has a larger weight
|
// Invert price so cheapest has a larger weight
|
||||||
// Times by highest price so most expensive item has weight of 1
|
// Times by highest price so most expensive item has weight of 1
|
||||||
this.pocketLootPool[key] = Math.round((1 / this.pocketLootPool[key]) * highestPrice);
|
this.pocketLootPool[key] = Math.round(1 / this.pocketLootPool[key] * highestPrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.weightedRandomHelper.reduceWeightValues(this.pocketLootPool);
|
this.weightedRandomHelper.reduceWeightValues(this.pocketLootPool);
|
||||||
@ -107,8 +106,8 @@ export class PMCLootGenerator
|
|||||||
if (Object.keys(this.vestLootPool).length === 0)
|
if (Object.keys(this.vestLootPool).length === 0)
|
||||||
{
|
{
|
||||||
const items = this.databaseServer.getTables().templates.items;
|
const items = this.databaseServer.getTables().templates.items;
|
||||||
const pmcPriceOverrides =
|
const pmcPriceOverrides
|
||||||
this.databaseServer.getTables().bots.types[botRole === "sptBear" ? "bear" : "usec"].inventory.items
|
= this.databaseServer.getTables().bots.types[botRole === "sptBear" ? "bear" : "usec"].inventory.items
|
||||||
.TacticalVest;
|
.TacticalVest;
|
||||||
|
|
||||||
const allowedItemTypes = this.pmcConfig.vestLoot.whitelist;
|
const allowedItemTypes = this.pmcConfig.vestLoot.whitelist;
|
||||||
@ -118,12 +117,12 @@ export class PMCLootGenerator
|
|||||||
// Blacklist seasonal items
|
// Blacklist seasonal items
|
||||||
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
|
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
|
||||||
|
|
||||||
const itemsToAdd = Object.values(items).filter((item) =>
|
const itemsToAdd = Object.values(items).filter(item =>
|
||||||
allowedItemTypes.includes(item._parent)
|
allowedItemTypes.includes(item._parent)
|
||||||
&& this.itemHelper.isValidItem(item._id)
|
&& this.itemHelper.isValidItem(item._id)
|
||||||
&& !pmcItemBlacklist.includes(item._id)
|
&& !pmcItemBlacklist.includes(item._id)
|
||||||
&& !itemBlacklist.includes(item._id)
|
&& !itemBlacklist.includes(item._id)
|
||||||
&& this.itemFitsInto2By2Slot(item)
|
&& this.itemFitsInto2By2Slot(item),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const itemToAdd of itemsToAdd)
|
for (const itemToAdd of itemsToAdd)
|
||||||
@ -146,7 +145,7 @@ export class PMCLootGenerator
|
|||||||
{
|
{
|
||||||
// Invert price so cheapest has a larger weight
|
// Invert price so cheapest has a larger weight
|
||||||
// Times by highest price so most expensive item has weight of 1
|
// Times by highest price so most expensive item has weight of 1
|
||||||
this.vestLootPool[key] = Math.round((1 / this.vestLootPool[key]) * highestPrice);
|
this.vestLootPool[key] = Math.round(1 / this.vestLootPool[key] * highestPrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.weightedRandomHelper.reduceWeightValues(this.vestLootPool);
|
this.weightedRandomHelper.reduceWeightValues(this.vestLootPool);
|
||||||
@ -176,8 +175,8 @@ export class PMCLootGenerator
|
|||||||
if (Object.keys(this.backpackLootPool).length === 0)
|
if (Object.keys(this.backpackLootPool).length === 0)
|
||||||
{
|
{
|
||||||
const items = this.databaseServer.getTables().templates.items;
|
const items = this.databaseServer.getTables().templates.items;
|
||||||
const pmcPriceOverrides =
|
const pmcPriceOverrides
|
||||||
this.databaseServer.getTables().bots.types[botRole === "sptBear" ? "bear" : "usec"].inventory.items
|
= this.databaseServer.getTables().bots.types[botRole === "sptBear" ? "bear" : "usec"].inventory.items
|
||||||
.Backpack;
|
.Backpack;
|
||||||
|
|
||||||
const allowedItemTypes = this.pmcConfig.backpackLoot.whitelist;
|
const allowedItemTypes = this.pmcConfig.backpackLoot.whitelist;
|
||||||
@ -187,11 +186,11 @@ export class PMCLootGenerator
|
|||||||
// Blacklist seasonal items
|
// Blacklist seasonal items
|
||||||
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
|
itemBlacklist.push(...this.seasonalEventService.getInactiveSeasonalEventItems());
|
||||||
|
|
||||||
const itemsToAdd = Object.values(items).filter((item) =>
|
const itemsToAdd = Object.values(items).filter(item =>
|
||||||
allowedItemTypes.includes(item._parent)
|
allowedItemTypes.includes(item._parent)
|
||||||
&& this.itemHelper.isValidItem(item._id)
|
&& this.itemHelper.isValidItem(item._id)
|
||||||
&& !pmcItemBlacklist.includes(item._id)
|
&& !pmcItemBlacklist.includes(item._id)
|
||||||
&& !itemBlacklist.includes(item._id)
|
&& !itemBlacklist.includes(item._id),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const itemToAdd of itemsToAdd)
|
for (const itemToAdd of itemsToAdd)
|
||||||
@ -214,7 +213,7 @@ export class PMCLootGenerator
|
|||||||
{
|
{
|
||||||
// Invert price so cheapest has a larger weight
|
// Invert price so cheapest has a larger weight
|
||||||
// Times by highest price so most expensive item has weight of 1
|
// Times by highest price so most expensive item has weight of 1
|
||||||
this.backpackLootPool[key] = Math.round((1 / this.backpackLootPool[key]) * highestPrice);
|
this.backpackLootPool[key] = Math.round(1 / this.backpackLootPool[key] * highestPrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.weightedRandomHelper.reduceWeightValues(this.backpackLootPool);
|
this.weightedRandomHelper.reduceWeightValues(this.backpackLootPool);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { BotGenerator } from "@spt-aki/generators/BotGenerator";
|
import { BotGenerator } from "@spt-aki/generators/BotGenerator";
|
||||||
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
||||||
import { BotHelper } from "@spt-aki/helpers/BotHelper";
|
import { BotHelper } from "@spt-aki/helpers/BotHelper";
|
||||||
@ -310,7 +309,7 @@ export class PlayerScavGenerator
|
|||||||
protected getScavLevel(scavProfile: IPmcData): number
|
protected getScavLevel(scavProfile: IPmcData): number
|
||||||
{
|
{
|
||||||
// Info can be null on initial account creation
|
// Info can be null on initial account creation
|
||||||
if (!(scavProfile.Info?.Level))
|
if (!scavProfile.Info?.Level)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -321,7 +320,7 @@ export class PlayerScavGenerator
|
|||||||
protected getScavExperience(scavProfile: IPmcData): number
|
protected getScavExperience(scavProfile: IPmcData): number
|
||||||
{
|
{
|
||||||
// Info can be null on initial account creation
|
// Info can be null on initial account creation
|
||||||
if (!(scavProfile.Info?.Experience))
|
if (!scavProfile.Info?.Experience)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -364,7 +363,7 @@ export class PlayerScavGenerator
|
|||||||
scavLockDuration = 10;
|
scavLockDuration = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
scavData.Info.SavageLockTime = (Date.now() / 1000) + scavLockDuration;
|
scavData.Info.SavageLockTime = Date.now() / 1000 + scavLockDuration;
|
||||||
|
|
||||||
return scavData;
|
return scavData;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
||||||
import { IPreset } from "@spt-aki/models/eft/common/IGlobals";
|
import { IPreset } from "@spt-aki/models/eft/common/IGlobals";
|
||||||
@ -75,7 +74,7 @@ export class RagfairAssortGenerator
|
|||||||
const results: Item[][] = [];
|
const results: Item[][] = [];
|
||||||
|
|
||||||
/** Get cloned items from db */
|
/** Get cloned items from db */
|
||||||
const dbItemsClone = this.itemHelper.getItems().filter((item) => item._type !== "Node");
|
const dbItemsClone = this.itemHelper.getItems().filter(item => item._type !== "Node");
|
||||||
|
|
||||||
/** Store processed preset tpls so we dont add them when procesing non-preset items */
|
/** Store processed preset tpls so we dont add them when procesing non-preset items */
|
||||||
const processedArmorItems: string[] = [];
|
const processedArmorItems: string[] = [];
|
||||||
@ -136,7 +135,7 @@ export class RagfairAssortGenerator
|
|||||||
*/
|
*/
|
||||||
protected getPresetsToAdd(): IPreset[]
|
protected getPresetsToAdd(): IPreset[]
|
||||||
{
|
{
|
||||||
return (this.ragfairConfig.dynamic.showDefaultPresetsOnly)
|
return this.ragfairConfig.dynamic.showDefaultPresetsOnly
|
||||||
? Object.values(this.presetHelper.getDefaultPresets())
|
? Object.values(this.presetHelper.getDefaultPresets())
|
||||||
: this.presetHelper.getAllPresets();
|
: this.presetHelper.getAllPresets();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { RagfairAssortGenerator } from "@spt-aki/generators/RagfairAssortGenerator";
|
import { RagfairAssortGenerator } from "@spt-aki/generators/RagfairAssortGenerator";
|
||||||
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
|
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
@ -37,7 +36,7 @@ import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
|||||||
export class RagfairOfferGenerator
|
export class RagfairOfferGenerator
|
||||||
{
|
{
|
||||||
protected ragfairConfig: IRagfairConfig;
|
protected ragfairConfig: IRagfairConfig;
|
||||||
protected allowedFleaPriceItemsForBarter: { tpl: string; price: number; }[];
|
protected allowedFleaPriceItemsForBarter: { tpl: string, price: number }[];
|
||||||
|
|
||||||
/** Internal counter to ensure each offer created has a unique value for its intId property */
|
/** Internal counter to ensure each offer created has a unique value for its intId property */
|
||||||
protected offerCounter = 0;
|
protected offerCounter = 0;
|
||||||
@ -136,7 +135,7 @@ export class RagfairOfferGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemCount = items.filter((x) => x.slotId === "hideout").length;
|
const itemCount = items.filter(x => x.slotId === "hideout").length;
|
||||||
const roublePrice = Math.round(this.convertOfferRequirementsIntoRoubles(offerRequirements));
|
const roublePrice = Math.round(this.convertOfferRequirementsIntoRoubles(offerRequirements));
|
||||||
|
|
||||||
const offer: IRagfairOffer = {
|
const offer: IRagfairOffer = {
|
||||||
@ -144,7 +143,7 @@ export class RagfairOfferGenerator
|
|||||||
intId: this.offerCounter,
|
intId: this.offerCounter,
|
||||||
user: {
|
user: {
|
||||||
id: this.getTraderId(userID),
|
id: this.getTraderId(userID),
|
||||||
memberType: (userID === "ragfair")
|
memberType: userID === "ragfair"
|
||||||
? MemberCategory.DEFAULT
|
? MemberCategory.DEFAULT
|
||||||
: this.ragfairServerHelper.getMemberType(userID),
|
: this.ragfairServerHelper.getMemberType(userID),
|
||||||
nickname: this.ragfairServerHelper.getNickname(userID),
|
nickname: this.ragfairServerHelper.getNickname(userID),
|
||||||
@ -297,8 +296,8 @@ export class RagfairOfferGenerator
|
|||||||
if (this.ragfairServerHelper.isPlayer(userID))
|
if (this.ragfairServerHelper.isPlayer(userID))
|
||||||
{
|
{
|
||||||
// Player offer = current time + offerDurationTimeInHour;
|
// Player offer = current time + offerDurationTimeInHour;
|
||||||
const offerDurationTimeHours =
|
const offerDurationTimeHours
|
||||||
this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour;
|
= this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour;
|
||||||
return this.timeUtil.getTimestamp() + Math.round(offerDurationTimeHours * TimeUtil.ONE_HOUR_AS_SECONDS);
|
return this.timeUtil.getTimestamp() + Math.round(offerDurationTimeHours * TimeUtil.ONE_HOUR_AS_SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,10 +310,10 @@ export class RagfairOfferGenerator
|
|||||||
// Generated fake-player offer
|
// Generated fake-player offer
|
||||||
return Math.round(
|
return Math.round(
|
||||||
time
|
time
|
||||||
+ this.randomUtil.getInt(
|
+ this.randomUtil.getInt(
|
||||||
this.ragfairConfig.dynamic.endTimeSeconds.min,
|
this.ragfairConfig.dynamic.endTimeSeconds.min,
|
||||||
this.ragfairConfig.dynamic.endTimeSeconds.max,
|
this.ragfairConfig.dynamic.endTimeSeconds.max,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,8 +410,8 @@ export class RagfairOfferGenerator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const plateSlots = presetWithChildren.filter((item) =>
|
const plateSlots = presetWithChildren.filter(item =>
|
||||||
this.itemHelper.getRemovablePlateSlotIds().includes(item.slotId?.toLowerCase())
|
this.itemHelper.getRemovablePlateSlotIds().includes(item.slotId?.toLowerCase()),
|
||||||
);
|
);
|
||||||
if (plateSlots.length === 0)
|
if (plateSlots.length === 0)
|
||||||
{
|
{
|
||||||
@ -461,12 +460,12 @@ export class RagfairOfferGenerator
|
|||||||
|
|
||||||
const isBarterOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.barter.chancePercent);
|
const isBarterOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.barter.chancePercent);
|
||||||
const isPackOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.pack.chancePercent)
|
const isPackOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.pack.chancePercent)
|
||||||
&& !isBarterOffer
|
&& !isBarterOffer
|
||||||
&& itemWithChildren.length === 1
|
&& itemWithChildren.length === 1
|
||||||
&& this.itemHelper.isOfBaseclasses(
|
&& this.itemHelper.isOfBaseclasses(
|
||||||
itemWithChildren[0]._tpl,
|
itemWithChildren[0]._tpl,
|
||||||
this.ragfairConfig.dynamic.pack.itemTypeWhitelist,
|
this.ragfairConfig.dynamic.pack.itemTypeWhitelist,
|
||||||
);
|
);
|
||||||
|
|
||||||
const randomUserId = this.hashUtil.generate();
|
const randomUserId = this.hashUtil.generate();
|
||||||
|
|
||||||
@ -478,8 +477,8 @@ export class RagfairOfferGenerator
|
|||||||
const shouldRemovePlates = this.randomUtil.getChance100(armorConfig.removeRemovablePlateChance);
|
const shouldRemovePlates = this.randomUtil.getChance100(armorConfig.removeRemovablePlateChance);
|
||||||
if (shouldRemovePlates && this.itemHelper.armorItemHasRemovablePlateSlots(itemWithChildren[0]._tpl))
|
if (shouldRemovePlates && this.itemHelper.armorItemHasRemovablePlateSlots(itemWithChildren[0]._tpl))
|
||||||
{
|
{
|
||||||
const offerItemPlatesToRemove = itemWithChildren.filter((item) =>
|
const offerItemPlatesToRemove = itemWithChildren.filter(item =>
|
||||||
armorConfig.plateSlotIdToRemovePool.includes(item.slotId?.toLowerCase())
|
armorConfig.plateSlotIdToRemovePool.includes(item.slotId?.toLowerCase()),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const plateItem of offerItemPlatesToRemove)
|
for (const plateItem of offerItemPlatesToRemove)
|
||||||
@ -684,8 +683,8 @@ export class RagfairOfferGenerator
|
|||||||
this.randomiseArmorDurabilityValues(itemWithMods, currentMultiplier, maxMultiplier);
|
this.randomiseArmorDurabilityValues(itemWithMods, currentMultiplier, maxMultiplier);
|
||||||
|
|
||||||
// Add hits to visor
|
// Add hits to visor
|
||||||
const visorMod = itemWithMods.find((item) =>
|
const visorMod = itemWithMods.find(item =>
|
||||||
item.parentId === BaseClasses.ARMORED_EQUIPMENT && item.slotId === "mod_equipment_000"
|
item.parentId === BaseClasses.ARMORED_EQUIPMENT && item.slotId === "mod_equipment_000",
|
||||||
);
|
);
|
||||||
if (this.randomUtil.getChance100(25) && visorMod)
|
if (this.randomUtil.getChance100(25) && visorMod)
|
||||||
{
|
{
|
||||||
@ -717,7 +716,7 @@ export class RagfairOfferGenerator
|
|||||||
{
|
{
|
||||||
// randomize key uses
|
// randomize key uses
|
||||||
rootItem.upd.Key.NumberOfUsages = Math.round(itemDetails._props.MaximumNumberOfUsage * (1 - maxMultiplier))
|
rootItem.upd.Key.NumberOfUsages = Math.round(itemDetails._props.MaximumNumberOfUsage * (1 - maxMultiplier))
|
||||||
|| 0;
|
|| 0;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -789,12 +788,12 @@ export class RagfairOfferGenerator
|
|||||||
for (const armorItem of armorWithMods)
|
for (const armorItem of armorWithMods)
|
||||||
{
|
{
|
||||||
const itemDbDetails = this.itemHelper.getItem(armorItem._tpl)[1];
|
const itemDbDetails = this.itemHelper.getItem(armorItem._tpl)[1];
|
||||||
if ((Number.parseInt(<string>itemDbDetails._props.armorClass)) > 1)
|
if (Number.parseInt(<string>itemDbDetails._props.armorClass) > 1)
|
||||||
{
|
{
|
||||||
this.itemHelper.addUpdObjectToItem(armorItem);
|
this.itemHelper.addUpdObjectToItem(armorItem);
|
||||||
|
|
||||||
const lowestMaxDurability = this.randomUtil.getFloat(maxMultiplier, 1)
|
const lowestMaxDurability = this.randomUtil.getFloat(maxMultiplier, 1)
|
||||||
* itemDbDetails._props.MaxDurability;
|
* itemDbDetails._props.MaxDurability;
|
||||||
const chosenMaxDurability = Math.round(
|
const chosenMaxDurability = Math.round(
|
||||||
this.randomUtil.getFloat(lowestMaxDurability, itemDbDetails._props.MaxDurability),
|
this.randomUtil.getFloat(lowestMaxDurability, itemDbDetails._props.MaxDurability),
|
||||||
);
|
);
|
||||||
@ -888,9 +887,9 @@ export class RagfairOfferGenerator
|
|||||||
const fleaPrices = this.getFleaPricesAsArray();
|
const fleaPrices = this.getFleaPricesAsArray();
|
||||||
|
|
||||||
// Filter possible barters to items that match the price range + not itself
|
// Filter possible barters to items that match the price range + not itself
|
||||||
const filtered = fleaPrices.filter((x) =>
|
const filtered = fleaPrices.filter(x =>
|
||||||
x.price >= desiredItemCost - offerCostVariance && x.price <= desiredItemCost + offerCostVariance
|
x.price >= desiredItemCost - offerCostVariance && x.price <= desiredItemCost + offerCostVariance
|
||||||
&& x.tpl !== offerItems[0]._tpl
|
&& x.tpl !== offerItems[0]._tpl,
|
||||||
);
|
);
|
||||||
|
|
||||||
// No items on flea have a matching price, fall back to currency
|
// No items on flea have a matching price, fall back to currency
|
||||||
@ -909,7 +908,7 @@ export class RagfairOfferGenerator
|
|||||||
* Get an array of flea prices + item tpl, cached in generator class inside `allowedFleaPriceItemsForBarter`
|
* Get an array of flea prices + item tpl, cached in generator class inside `allowedFleaPriceItemsForBarter`
|
||||||
* @returns array with tpl/price values
|
* @returns array with tpl/price values
|
||||||
*/
|
*/
|
||||||
protected getFleaPricesAsArray(): { tpl: string; price: number; }[]
|
protected getFleaPricesAsArray(): { tpl: string, price: number }[]
|
||||||
{
|
{
|
||||||
// Generate if needed
|
// Generate if needed
|
||||||
if (!this.allowedFleaPriceItemsForBarter)
|
if (!this.allowedFleaPriceItemsForBarter)
|
||||||
@ -918,10 +917,10 @@ export class RagfairOfferGenerator
|
|||||||
const fleaArray = Object.entries(fleaPrices).map(([tpl, price]) => ({ tpl: tpl, price: price }));
|
const fleaArray = Object.entries(fleaPrices).map(([tpl, price]) => ({ tpl: tpl, price: price }));
|
||||||
|
|
||||||
// Only get item prices for items that also exist in items.json
|
// Only get item prices for items that also exist in items.json
|
||||||
const filteredItems = fleaArray.filter((x) => this.itemHelper.getItem(x.tpl)[0]);
|
const filteredItems = fleaArray.filter(x => this.itemHelper.getItem(x.tpl)[0]);
|
||||||
|
|
||||||
this.allowedFleaPriceItemsForBarter = filteredItems.filter((x) =>
|
this.allowedFleaPriceItemsForBarter = filteredItems.filter(x =>
|
||||||
!this.itemHelper.isOfBaseclasses(x.tpl, this.ragfairConfig.dynamic.barter.itemTypeBlacklist)
|
!this.itemHelper.isOfBaseclasses(x.tpl, this.ragfairConfig.dynamic.barter.itemTypeBlacklist),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -943,7 +942,7 @@ export class RagfairOfferGenerator
|
|||||||
{
|
{
|
||||||
const currency = this.ragfairServerHelper.getDynamicOfferCurrency();
|
const currency = this.ragfairServerHelper.getDynamicOfferCurrency();
|
||||||
const price = this.ragfairPriceService.getDynamicOfferPriceForOffer(offerWithChildren, currency, isPackOffer)
|
const price = this.ragfairPriceService.getDynamicOfferPriceForOffer(offerWithChildren, currency, isPackOffer)
|
||||||
* multipler;
|
* multipler;
|
||||||
|
|
||||||
return [{ count: price, _tpl: currency }];
|
return [{ count: price, _tpl: currency }];
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { RepeatableQuestRewardGenerator } from "@spt-aki/generators/RepeatableQuestRewardGenerator";
|
import { RepeatableQuestRewardGenerator } from "@spt-aki/generators/RepeatableQuestRewardGenerator";
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { RepeatableQuestHelper } from "@spt-aki/helpers/RepeatableQuestHelper";
|
import { RepeatableQuestHelper } from "@spt-aki/helpers/RepeatableQuestHelper";
|
||||||
@ -42,7 +41,7 @@ export class RepeatableQuestGenerator
|
|||||||
@inject("ObjectId") protected objectId: ObjectId,
|
@inject("ObjectId") protected objectId: ObjectId,
|
||||||
@inject("RepeatableQuestHelper") protected repeatableQuestHelper: RepeatableQuestHelper,
|
@inject("RepeatableQuestHelper") protected repeatableQuestHelper: RepeatableQuestHelper,
|
||||||
@inject("RepeatableQuestRewardGenerator") protected repeatableQuestRewardGenerator:
|
@inject("RepeatableQuestRewardGenerator") protected repeatableQuestRewardGenerator:
|
||||||
RepeatableQuestRewardGenerator,
|
RepeatableQuestRewardGenerator,
|
||||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -68,11 +67,11 @@ export class RepeatableQuestGenerator
|
|||||||
const questType = this.randomUtil.drawRandomFromList<string>(questTypePool.types)[0];
|
const questType = this.randomUtil.drawRandomFromList<string>(questTypePool.types)[0];
|
||||||
|
|
||||||
// get traders from whitelist and filter by quest type availability
|
// get traders from whitelist and filter by quest type availability
|
||||||
let traders = repeatableConfig.traderWhitelist.filter((x) => x.questTypes.includes(questType)).map((x) =>
|
let traders = repeatableConfig.traderWhitelist.filter(x => x.questTypes.includes(questType)).map(x =>
|
||||||
x.traderId
|
x.traderId,
|
||||||
);
|
);
|
||||||
// filter out locked traders
|
// filter out locked traders
|
||||||
traders = traders.filter((x) => pmcTraderInfo[x].unlocked);
|
traders = traders.filter(x => pmcTraderInfo[x].unlocked);
|
||||||
const traderId = this.randomUtil.drawRandomFromList(traders)[0];
|
const traderId = this.randomUtil.drawRandomFromList(traders)[0];
|
||||||
|
|
||||||
switch (questType)
|
switch (questType)
|
||||||
@ -159,15 +158,15 @@ export class RepeatableQuestGenerator
|
|||||||
return Math.sqrt(Math.sqrt(target) + bodyPart + dist + weaponRequirement) * kill;
|
return Math.sqrt(Math.sqrt(target) + bodyPart + dist + weaponRequirement) * kill;
|
||||||
}
|
}
|
||||||
|
|
||||||
targetsConfig = targetsConfig.filter((x) =>
|
targetsConfig = targetsConfig.filter(x =>
|
||||||
Object.keys(questTypePool.pool.Elimination.targets).includes(x.key)
|
Object.keys(questTypePool.pool.Elimination.targets).includes(x.key),
|
||||||
);
|
);
|
||||||
if (targetsConfig.length === 0 || targetsConfig.every((x) => x.data.isBoss))
|
if (targetsConfig.length === 0 || targetsConfig.every(x => x.data.isBoss))
|
||||||
{
|
{
|
||||||
// There are no more targets left for elimination; delete it as a possible quest type
|
// There are no more targets left for elimination; delete it as a possible quest type
|
||||||
// also if only bosses are left we need to leave otherwise it's a guaranteed boss elimination
|
// also if only bosses are left we need to leave otherwise it's a guaranteed boss elimination
|
||||||
// -> then it would not be a quest with low probability anymore
|
// -> then it would not be a quest with low probability anymore
|
||||||
questTypePool.types = questTypePool.types.filter((t) => t !== "Elimination");
|
questTypePool.types = questTypePool.types.filter(t => t !== "Elimination");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,12 +188,12 @@ export class RepeatableQuestGenerator
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
locations = locations.filter((l) => l !== "any");
|
locations = locations.filter(l => l !== "any");
|
||||||
if (locations.length > 0)
|
if (locations.length > 0)
|
||||||
{
|
{
|
||||||
locationKey = this.randomUtil.drawRandomFromList<string>(locations)[0];
|
locationKey = this.randomUtil.drawRandomFromList<string>(locations)[0];
|
||||||
questTypePool.pool.Elimination.targets[targetKey].locations = locations.filter((l) =>
|
questTypePool.pool.Elimination.targets[targetKey].locations = locations.filter(l =>
|
||||||
l !== locationKey
|
l !== locationKey,
|
||||||
);
|
);
|
||||||
if (questTypePool.pool.Elimination.targets[targetKey].locations.length === 0)
|
if (questTypePool.pool.Elimination.targets[targetKey].locations.length === 0)
|
||||||
{
|
{
|
||||||
@ -239,18 +238,18 @@ export class RepeatableQuestGenerator
|
|||||||
if (targetsConfig.data(targetKey).isBoss)
|
if (targetsConfig.data(targetKey).isBoss)
|
||||||
{
|
{
|
||||||
// Get all boss spawn information
|
// Get all boss spawn information
|
||||||
const bossSpawns = Object.values(this.databaseServer.getTables().locations).filter((x) =>
|
const bossSpawns = Object.values(this.databaseServer.getTables().locations).filter(x =>
|
||||||
"base" in x && "Id" in x.base
|
"base" in x && "Id" in x.base,
|
||||||
).map((x) => ({ Id: x.base.Id, BossSpawn: x.base.BossLocationSpawn }));
|
).map(x => ({ Id: x.base.Id, BossSpawn: x.base.BossLocationSpawn }));
|
||||||
// filter for the current boss to spawn on map
|
// filter for the current boss to spawn on map
|
||||||
const thisBossSpawns = bossSpawns.map((x) => ({
|
const thisBossSpawns = bossSpawns.map(x => ({
|
||||||
Id: x.Id,
|
Id: x.Id,
|
||||||
BossSpawn: x.BossSpawn.filter((e) => e.BossName === targetKey),
|
BossSpawn: x.BossSpawn.filter(e => e.BossName === targetKey),
|
||||||
})).filter((x) => x.BossSpawn.length > 0);
|
})).filter(x => x.BossSpawn.length > 0);
|
||||||
// remove blacklisted locations
|
// remove blacklisted locations
|
||||||
const allowedSpawns = thisBossSpawns.filter((x) => !eliminationConfig.distLocationBlacklist.includes(x.Id));
|
const allowedSpawns = thisBossSpawns.filter(x => !eliminationConfig.distLocationBlacklist.includes(x.Id));
|
||||||
// if the boss spawns on nom-blacklisted locations and the current location is allowed we can generate a distance kill requirement
|
// if the boss spawns on nom-blacklisted locations and the current location is allowed we can generate a distance kill requirement
|
||||||
isDistanceRequirementAllowed = isDistanceRequirementAllowed && (allowedSpawns.length > 0);
|
isDistanceRequirementAllowed = isDistanceRequirementAllowed && allowedSpawns.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eliminationConfig.distProb > Math.random() && isDistanceRequirementAllowed)
|
if (eliminationConfig.distProb > Math.random() && isDistanceRequirementAllowed)
|
||||||
@ -258,7 +257,7 @@ export class RepeatableQuestGenerator
|
|||||||
// Random distance with lower values more likely; simple distribution for starters...
|
// Random distance with lower values more likely; simple distribution for starters...
|
||||||
distance = Math.floor(
|
distance = Math.floor(
|
||||||
Math.abs(Math.random() - Math.random()) * (1 + eliminationConfig.maxDist - eliminationConfig.minDist)
|
Math.abs(Math.random() - Math.random()) * (1 + eliminationConfig.maxDist - eliminationConfig.minDist)
|
||||||
+ eliminationConfig.minDist,
|
+ eliminationConfig.minDist,
|
||||||
);
|
);
|
||||||
distance = Math.ceil(distance / 5) * 5;
|
distance = Math.ceil(distance / 5) * 5;
|
||||||
distanceDifficulty = maxDistDifficulty * distance / eliminationConfig.maxDist;
|
distanceDifficulty = maxDistDifficulty * distance / eliminationConfig.maxDist;
|
||||||
@ -270,14 +269,14 @@ export class RepeatableQuestGenerator
|
|||||||
// Filter out close range weapons from far distance requirement
|
// Filter out close range weapons from far distance requirement
|
||||||
if (distance > 50)
|
if (distance > 50)
|
||||||
{
|
{
|
||||||
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter((category) =>
|
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter(category =>
|
||||||
["Shotgun", "Pistol"].includes(category.key)
|
["Shotgun", "Pistol"].includes(category.key),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (distance < 20)
|
else if (distance < 20)
|
||||||
{ // Filter out far range weapons from close distance requirement
|
{ // Filter out far range weapons from close distance requirement
|
||||||
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter((category) =>
|
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter(category =>
|
||||||
["MarksmanRifle", "DMR"].includes(category.key)
|
["MarksmanRifle", "DMR"].includes(category.key),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +309,7 @@ export class RepeatableQuestGenerator
|
|||||||
bodyPartDifficulty / maxBodyPartsDifficulty,
|
bodyPartDifficulty / maxBodyPartsDifficulty,
|
||||||
distanceDifficulty / maxDistDifficulty,
|
distanceDifficulty / maxDistDifficulty,
|
||||||
killDifficulty / maxKillDifficulty,
|
killDifficulty / maxKillDifficulty,
|
||||||
(allowedWeaponsCategory || allowedWeapon) ? 1 : 0,
|
allowedWeaponsCategory || allowedWeapon ? 1 : 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Aforementioned issue makes it a bit crazy since now all easier quests give significantly lower rewards than Completion / Exploration
|
// Aforementioned issue makes it a bit crazy since now all easier quests give significantly lower rewards than Completion / Exploration
|
||||||
@ -498,27 +497,27 @@ export class RepeatableQuestGenerator
|
|||||||
this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig) * this.randomUtil.getFloat(0.5, 1),
|
this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig) * this.randomUtil.getFloat(0.5, 1),
|
||||||
);
|
);
|
||||||
roublesBudget = Math.max(roublesBudget, 5000);
|
roublesBudget = Math.max(roublesBudget, 5000);
|
||||||
let itemSelection = possibleItemsToRetrievePool.filter((x) =>
|
let itemSelection = possibleItemsToRetrievePool.filter(x =>
|
||||||
this.itemHelper.getItemPrice(x[0]) < roublesBudget
|
this.itemHelper.getItemPrice(x[0]) < roublesBudget,
|
||||||
);
|
);
|
||||||
|
|
||||||
// We also have the option to use whitelist and/or blacklist which is defined in repeatableQuests.json as
|
// We also have the option to use whitelist and/or blacklist which is defined in repeatableQuests.json as
|
||||||
// [{"minPlayerLevel": 1, "itemIds": ["id1",...]}, {"minPlayerLevel": 15, "itemIds": ["id3",...]}]
|
// [{"minPlayerLevel": 1, "itemIds": ["id1",...]}, {"minPlayerLevel": 15, "itemIds": ["id3",...]}]
|
||||||
if (repeatableConfig.questConfig.Completion.useWhitelist)
|
if (repeatableConfig.questConfig.Completion.useWhitelist)
|
||||||
{
|
{
|
||||||
const itemWhitelist =
|
const itemWhitelist
|
||||||
this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsWhitelist;
|
= this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsWhitelist;
|
||||||
|
|
||||||
// Filter and concatenate the arrays according to current player level
|
// Filter and concatenate the arrays according to current player level
|
||||||
const itemIdsWhitelisted = itemWhitelist.filter((p) => p.minPlayerLevel <= pmcLevel).reduce(
|
const itemIdsWhitelisted = itemWhitelist.filter(p => p.minPlayerLevel <= pmcLevel).reduce(
|
||||||
(a, p) => a.concat(p.itemIds),
|
(a, p) => a.concat(p.itemIds),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
itemSelection = itemSelection.filter((x) =>
|
itemSelection = itemSelection.filter((x) =>
|
||||||
{
|
{
|
||||||
// Whitelist can contain item tpls and item base type ids
|
// Whitelist can contain item tpls and item base type ids
|
||||||
return (itemIdsWhitelisted.some((v) => this.itemHelper.isOfBaseclass(x[0], v))
|
return itemIdsWhitelisted.some(v => this.itemHelper.isOfBaseclass(x[0], v))
|
||||||
|| itemIdsWhitelisted.includes(x[0]));
|
|| itemIdsWhitelisted.includes(x[0]);
|
||||||
});
|
});
|
||||||
// check if items are missing
|
// check if items are missing
|
||||||
// const flatList = itemSelection.reduce((a, il) => a.concat(il[0]), []);
|
// const flatList = itemSelection.reduce((a, il) => a.concat(il[0]), []);
|
||||||
@ -527,19 +526,19 @@ export class RepeatableQuestGenerator
|
|||||||
|
|
||||||
if (repeatableConfig.questConfig.Completion.useBlacklist)
|
if (repeatableConfig.questConfig.Completion.useBlacklist)
|
||||||
{
|
{
|
||||||
const itemBlacklist =
|
const itemBlacklist
|
||||||
this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsBlacklist;
|
= this.databaseServer.getTables().templates.repeatableQuests.data.Completion.itemsBlacklist;
|
||||||
|
|
||||||
// we filter and concatenate the arrays according to current player level
|
// we filter and concatenate the arrays according to current player level
|
||||||
const itemIdsBlacklisted = itemBlacklist.filter((p) => p.minPlayerLevel <= pmcLevel).reduce(
|
const itemIdsBlacklisted = itemBlacklist.filter(p => p.minPlayerLevel <= pmcLevel).reduce(
|
||||||
(a, p) => a.concat(p.itemIds),
|
(a, p) => a.concat(p.itemIds),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
itemSelection = itemSelection.filter((x) =>
|
itemSelection = itemSelection.filter((x) =>
|
||||||
{
|
{
|
||||||
return itemIdsBlacklisted.every((v) => !this.itemHelper.isOfBaseclass(x[0], v))
|
return itemIdsBlacklisted.every(v => !this.itemHelper.isOfBaseclass(x[0], v))
|
||||||
|| !itemIdsBlacklisted.includes(x[0]);
|
|| !itemIdsBlacklisted.includes(x[0]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -602,7 +601,7 @@ export class RepeatableQuestGenerator
|
|||||||
if (roublesBudget > 0)
|
if (roublesBudget > 0)
|
||||||
{
|
{
|
||||||
// reduce the list possible items to fulfill the new budget constraint
|
// reduce the list possible items to fulfill the new budget constraint
|
||||||
itemSelection = itemSelection.filter((x) => this.itemHelper.getItemPrice(x[0]) < roublesBudget);
|
itemSelection = itemSelection.filter(x => this.itemHelper.getItemPrice(x[0]) < roublesBudget);
|
||||||
if (itemSelection.length === 0)
|
if (itemSelection.length === 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -687,13 +686,13 @@ export class RepeatableQuestGenerator
|
|||||||
): IRepeatableQuest
|
): IRepeatableQuest
|
||||||
{
|
{
|
||||||
const explorationConfig = repeatableConfig.questConfig.Exploration;
|
const explorationConfig = repeatableConfig.questConfig.Exploration;
|
||||||
const requiresSpecificExtract =
|
const requiresSpecificExtract
|
||||||
Math.random() < repeatableConfig.questConfig.Exploration.specificExits.probability;
|
= Math.random() < repeatableConfig.questConfig.Exploration.specificExits.probability;
|
||||||
|
|
||||||
if (Object.keys(questTypePool.pool.Exploration.locations).length === 0)
|
if (Object.keys(questTypePool.pool.Exploration.locations).length === 0)
|
||||||
{
|
{
|
||||||
// there are no more locations left for exploration; delete it as a possible quest type
|
// there are no more locations left for exploration; delete it as a possible quest type
|
||||||
questTypePool.types = questTypePool.types.filter((t) => t !== "Exploration");
|
questTypePool.types = questTypePool.types.filter(t => t !== "Exploration");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -738,15 +737,13 @@ export class RepeatableQuestGenerator
|
|||||||
const mapExits = this.getLocationExitsForSide(locationKey, repeatableConfig.side);
|
const mapExits = this.getLocationExitsForSide(locationKey, repeatableConfig.side);
|
||||||
|
|
||||||
// Only get exits that have a greater than 0% chance to spawn
|
// Only get exits that have a greater than 0% chance to spawn
|
||||||
const exitPool = mapExits.filter((exit) => exit.Chance > 0);
|
const exitPool = mapExits.filter(exit => exit.Chance > 0);
|
||||||
|
|
||||||
// Exclude exits with a requirement to leave (e.g. car extracts)
|
// Exclude exits with a requirement to leave (e.g. car extracts)
|
||||||
const possibleExits = exitPool.filter((
|
const possibleExits = exitPool.filter(exit => !("PassageRequirement" in exit)
|
||||||
exit,
|
|| repeatableConfig.questConfig.Exploration.specificExits.passageRequirementWhitelist.includes(
|
||||||
) => (!("PassageRequirement" in exit)
|
exit.PassageRequirement,
|
||||||
|| repeatableConfig.questConfig.Exploration.specificExits.passageRequirementWhitelist.includes(
|
),
|
||||||
exit.PassageRequirement,
|
|
||||||
))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (possibleExits.length === 0)
|
if (possibleExits.length === 0)
|
||||||
@ -791,7 +788,7 @@ export class RepeatableQuestGenerator
|
|||||||
const mapExtracts = this.databaseServer.getTables().locations[locationKey.toLocaleLowerCase()]
|
const mapExtracts = this.databaseServer.getTables().locations[locationKey.toLocaleLowerCase()]
|
||||||
.allExtracts as Exit[];
|
.allExtracts as Exit[];
|
||||||
|
|
||||||
return mapExtracts.filter((exit) => exit.Side === playerSide);
|
return mapExtracts.filter(exit => exit.Side === playerSide);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected generatePickupQuest(
|
protected generatePickupQuest(
|
||||||
@ -814,18 +811,18 @@ export class RepeatableQuestGenerator
|
|||||||
// const locationKey: string = this.randomUtil.drawRandomFromDict(questTypePool.pool.Pickup.locations)[0];
|
// const locationKey: string = this.randomUtil.drawRandomFromDict(questTypePool.pool.Pickup.locations)[0];
|
||||||
// const locationTarget = questTypePool.pool.Pickup.locations[locationKey];
|
// const locationTarget = questTypePool.pool.Pickup.locations[locationKey];
|
||||||
|
|
||||||
const findCondition = quest.conditions.AvailableForFinish.find((x) => x.conditionType === "FindItem");
|
const findCondition = quest.conditions.AvailableForFinish.find(x => x.conditionType === "FindItem");
|
||||||
findCondition.target = [itemTypeToFetchWithCount.itemType];
|
findCondition.target = [itemTypeToFetchWithCount.itemType];
|
||||||
findCondition.value = itemCountToFetch;
|
findCondition.value = itemCountToFetch;
|
||||||
|
|
||||||
const counterCreatorCondition = quest.conditions.AvailableForFinish.find((x) =>
|
const counterCreatorCondition = quest.conditions.AvailableForFinish.find(x =>
|
||||||
x.conditionType === "CounterCreator"
|
x.conditionType === "CounterCreator",
|
||||||
);
|
);
|
||||||
// const locationCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Location");
|
// const locationCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Location");
|
||||||
// (locationCondition._props as ILocationConditionProps).target = [...locationTarget];
|
// (locationCondition._props as ILocationConditionProps).target = [...locationTarget];
|
||||||
|
|
||||||
const equipmentCondition = counterCreatorCondition.counter.conditions.find((x) =>
|
const equipmentCondition = counterCreatorCondition.counter.conditions.find(x =>
|
||||||
x.conditionType === "Equipment"
|
x.conditionType === "Equipment",
|
||||||
);
|
);
|
||||||
equipmentCondition.equipmentInclusive = [[itemTypeToFetchWithCount.itemType]];
|
equipmentCondition.equipmentInclusive = [[itemTypeToFetchWithCount.itemType]];
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
|
import { HandbookHelper } from "@spt-aki/helpers/HandbookHelper";
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
||||||
@ -96,20 +95,20 @@ export class RepeatableQuestRewardGenerator
|
|||||||
// rewards are generated based on pmcLevel, difficulty and a random spread
|
// rewards are generated based on pmcLevel, difficulty and a random spread
|
||||||
const rewardXP = Math.floor(
|
const rewardXP = Math.floor(
|
||||||
effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, xpConfig)
|
effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, xpConfig)
|
||||||
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig),
|
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig),
|
||||||
);
|
);
|
||||||
const rewardRoubles = Math.floor(
|
const rewardRoubles = Math.floor(
|
||||||
effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig)
|
effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, roublesConfig)
|
||||||
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig),
|
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig),
|
||||||
);
|
);
|
||||||
const rewardNumItems = this.randomUtil.randInt(
|
const rewardNumItems = this.randomUtil.randInt(
|
||||||
1,
|
1,
|
||||||
Math.round(this.mathUtil.interp1(pmcLevel, levelsConfig, itemsConfig)) + 1,
|
Math.round(this.mathUtil.interp1(pmcLevel, levelsConfig, itemsConfig)) + 1,
|
||||||
);
|
);
|
||||||
const rewardReputation =
|
const rewardReputation
|
||||||
Math.round(
|
= Math.round(
|
||||||
100 * effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, reputationConfig)
|
100 * effectiveDifficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, reputationConfig)
|
||||||
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig),
|
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig),
|
||||||
) / 100;
|
) / 100;
|
||||||
const skillRewardChance = this.mathUtil.interp1(pmcLevel, levelsConfig, skillRewardChanceConfig);
|
const skillRewardChance = this.mathUtil.interp1(pmcLevel, levelsConfig, skillRewardChanceConfig);
|
||||||
const skillPointReward = this.mathUtil.interp1(pmcLevel, levelsConfig, skillPointRewardConfig);
|
const skillPointReward = this.mathUtil.interp1(pmcLevel, levelsConfig, skillPointRewardConfig);
|
||||||
@ -135,7 +134,7 @@ export class RepeatableQuestRewardGenerator
|
|||||||
this.addMoneyReward(traderId, rewards, rewardRoubles, rewardIndex);
|
this.addMoneyReward(traderId, rewards, rewardRoubles, rewardIndex);
|
||||||
rewardIndex++;
|
rewardIndex++;
|
||||||
|
|
||||||
const traderWhitelistDetails = repeatableConfig.traderWhitelist.find((x) => x.traderId === traderId);
|
const traderWhitelistDetails = repeatableConfig.traderWhitelist.find(x => x.traderId === traderId);
|
||||||
if (
|
if (
|
||||||
traderWhitelistDetails.rewardCanBeWeapon
|
traderWhitelistDetails.rewardCanBeWeapon
|
||||||
&& this.randomUtil.getChance100(traderWhitelistDetails.weaponRewardChancePercent)
|
&& this.randomUtil.getChance100(traderWhitelistDetails.weaponRewardChancePercent)
|
||||||
@ -151,7 +150,7 @@ export class RepeatableQuestRewardGenerator
|
|||||||
while (defaultPresetPool.hasValues())
|
while (defaultPresetPool.hasValues())
|
||||||
{
|
{
|
||||||
const randomPreset = defaultPresetPool.getRandomValue();
|
const randomPreset = defaultPresetPool.getRandomValue();
|
||||||
const tpls = randomPreset._items.map((item) => item._tpl);
|
const tpls = randomPreset._items.map(item => item._tpl);
|
||||||
const presetPrice = this.itemHelper.getItemAndChildrenPrice(tpls);
|
const presetPrice = this.itemHelper.getItemAndChildrenPrice(tpls);
|
||||||
if (presetPrice <= roublesBudget)
|
if (presetPrice <= roublesBudget)
|
||||||
{
|
{
|
||||||
@ -309,13 +308,13 @@ export class RepeatableQuestRewardGenerator
|
|||||||
protected canIncreaseRewardItemStackSize(item: ITemplateItem, maxRoublePriceToStack: number): boolean
|
protected canIncreaseRewardItemStackSize(item: ITemplateItem, maxRoublePriceToStack: number): boolean
|
||||||
{
|
{
|
||||||
return this.presetHelper.getDefaultPresetOrItemPrice(item._id) < maxRoublePriceToStack
|
return this.presetHelper.getDefaultPresetOrItemPrice(item._id) < maxRoublePriceToStack
|
||||||
&& !this.itemHelper.isOfBaseclasses(item._id, [
|
&& !this.itemHelper.isOfBaseclasses(item._id, [
|
||||||
BaseClasses.WEAPON,
|
BaseClasses.WEAPON,
|
||||||
BaseClasses.ARMORED_EQUIPMENT,
|
BaseClasses.ARMORED_EQUIPMENT,
|
||||||
BaseClasses.AMMO,
|
BaseClasses.AMMO,
|
||||||
])
|
])
|
||||||
&& !this.itemHelper.itemRequiresSoftInserts(item._id)
|
&& !this.itemHelper.itemRequiresSoftInserts(item._id)
|
||||||
&& this.randomUtil.getChance100(25);
|
&& this.randomUtil.getChance100(25);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected calculateAmmoStackSizeThatFitsBudget(
|
protected calculateAmmoStackSizeThatFitsBudget(
|
||||||
@ -355,7 +354,7 @@ export class RepeatableQuestRewardGenerator
|
|||||||
const rewardableItemPool = this.getRewardableItems(repeatableConfig, traderId);
|
const rewardableItemPool = this.getRewardableItems(repeatableConfig, traderId);
|
||||||
const minPrice = Math.min(25000, 0.5 * roublesBudget);
|
const minPrice = Math.min(25000, 0.5 * roublesBudget);
|
||||||
|
|
||||||
let rewardableItemPoolWithinBudget = rewardableItemPool.map((x) => x[1]);
|
let rewardableItemPoolWithinBudget = rewardableItemPool.map(x => x[1]);
|
||||||
rewardableItemPoolWithinBudget = this.filterRewardPoolWithinBudget(
|
rewardableItemPoolWithinBudget = this.filterRewardPoolWithinBudget(
|
||||||
rewardableItemPoolWithinBudget,
|
rewardableItemPoolWithinBudget,
|
||||||
roublesBudget,
|
roublesBudget,
|
||||||
@ -370,9 +369,9 @@ export class RepeatableQuestRewardGenerator
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
// In case we don't find any items in the price range
|
// In case we don't find any items in the price range
|
||||||
rewardableItemPoolWithinBudget = rewardableItemPool.filter((x) =>
|
rewardableItemPoolWithinBudget = rewardableItemPool.filter(x =>
|
||||||
this.itemHelper.getItemPrice(x[0]) < roublesBudget
|
this.itemHelper.getItemPrice(x[0]) < roublesBudget,
|
||||||
).map((x) => x[1]);
|
).map(x => x[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rewardableItemPoolWithinBudget;
|
return rewardableItemPoolWithinBudget;
|
||||||
@ -393,7 +392,7 @@ export class RepeatableQuestRewardGenerator
|
|||||||
|
|
||||||
if (preset)
|
if (preset)
|
||||||
{
|
{
|
||||||
const rootItem = preset.find((x) => x._tpl === tpl);
|
const rootItem = preset.find(x => x._tpl === tpl);
|
||||||
rewardItem.items = this.itemHelper.reparentItemAndChildren(rootItem, preset);
|
rewardItem.items = this.itemHelper.reparentItemAndChildren(rootItem, preset);
|
||||||
rewardItem.target = rootItem._id; // Target property and root items id must match
|
rewardItem.target = rootItem._id; // Target property and root items id must match
|
||||||
}
|
}
|
||||||
@ -436,8 +435,8 @@ export class RepeatableQuestRewardGenerator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const traderWhitelist = repeatableQuestConfig.traderWhitelist.find((trader) =>
|
const traderWhitelist = repeatableQuestConfig.traderWhitelist.find(trader =>
|
||||||
trader.traderId === traderId
|
trader.traderId === traderId,
|
||||||
);
|
);
|
||||||
return this.isValidRewardItem(tpl, repeatableQuestConfig, traderWhitelist?.rewardBaseWhitelist);
|
return this.isValidRewardItem(tpl, repeatableQuestConfig, traderWhitelist?.rewardBaseWhitelist);
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
||||||
import { Product } from "@spt-aki/models/eft/common/tables/IBotBase";
|
import { Product } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||||
@ -61,7 +60,7 @@ export class ScavCaseRewardGenerator
|
|||||||
this.cacheDbItems();
|
this.cacheDbItems();
|
||||||
|
|
||||||
// Get scavcase details from hideout/scavcase.json
|
// Get scavcase details from hideout/scavcase.json
|
||||||
const scavCaseDetails = this.databaseServer.getTables().hideout.scavcase.find((r) => r._id === recipeId);
|
const scavCaseDetails = this.databaseServer.getTables().hideout.scavcase.find(r => r._id === recipeId);
|
||||||
const rewardItemCounts = this.getScavCaseRewardCountsAndPrices(scavCaseDetails);
|
const rewardItemCounts = this.getScavCaseRewardCountsAndPrices(scavCaseDetails);
|
||||||
|
|
||||||
// Get items that fit the price criteria as set by the scavCase config
|
// Get items that fit the price criteria as set by the scavCase config
|
||||||
@ -122,7 +121,7 @@ export class ScavCaseRewardGenerator
|
|||||||
|
|
||||||
// Skip item if item id is on blacklist
|
// Skip item if item id is on blacklist
|
||||||
if (
|
if (
|
||||||
(item._type !== "Item")
|
item._type !== "Item"
|
||||||
|| this.scavCaseConfig.rewardItemBlacklist.includes(item._id)
|
|| this.scavCaseConfig.rewardItemBlacklist.includes(item._id)
|
||||||
|| this.itemFilterService.isItemBlacklisted(item._id)
|
|| this.itemFilterService.isItemBlacklisted(item._id)
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
||||||
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
||||||
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
|
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
|
||||||
@ -72,10 +71,10 @@ export class WeatherGenerator
|
|||||||
public getInRaidTime(): Date
|
public getInRaidTime(): Date
|
||||||
{
|
{
|
||||||
// tarkov time = (real time * 7 % 24 hr) + 3 hour
|
// tarkov time = (real time * 7 % 24 hr) + 3 hour
|
||||||
const russiaOffset = (this.timeUtil.getHoursAsSeconds(3)) * 1000;
|
const russiaOffset = this.timeUtil.getHoursAsSeconds(3) * 1000;
|
||||||
return new Date(
|
return new Date(
|
||||||
(russiaOffset + (new Date().getTime() * this.weatherConfig.acceleration))
|
(russiaOffset + new Date().getTime() * this.weatherConfig.acceleration)
|
||||||
% (this.timeUtil.getHoursAsSeconds(24) * 1000),
|
% (this.timeUtil.getHoursAsSeconds(24) * 1000),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +102,7 @@ export class WeatherGenerator
|
|||||||
wind_direction: this.getWeightedWindDirection(),
|
wind_direction: this.getWeightedWindDirection(),
|
||||||
wind_gustiness: this.getRandomFloat("windGustiness"),
|
wind_gustiness: this.getRandomFloat("windGustiness"),
|
||||||
rain: rain,
|
rain: rain,
|
||||||
rain_intensity: (rain > 1) ? this.getRandomFloat("rainIntensity") : 0,
|
rain_intensity: rain > 1 ? this.getRandomFloat("rainIntensity") : 0,
|
||||||
fog: this.getWeightedFog(),
|
fog: this.getWeightedFog(),
|
||||||
temp: this.getRandomFloat("temp"),
|
temp: this.getRandomFloat("temp"),
|
||||||
pressure: this.getRandomFloat("pressure"),
|
pressure: this.getRandomFloat("pressure"),
|
||||||
|
@ -2,7 +2,7 @@ import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
|
|||||||
|
|
||||||
export interface IInventoryMagGen
|
export interface IInventoryMagGen
|
||||||
{
|
{
|
||||||
getPriority(): number;
|
getPriority(): number
|
||||||
canHandleInventoryMagGen(inventoryMagGen: InventoryMagGen): boolean;
|
canHandleInventoryMagGen(inventoryMagGen: InventoryMagGen): boolean
|
||||||
process(inventoryMagGen: InventoryMagGen): void;
|
process(inventoryMagGen: InventoryMagGen): void
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen";
|
import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen";
|
||||||
import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
|
import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
|
||||||
import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper";
|
import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen";
|
import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen";
|
||||||
import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
|
import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
|
||||||
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
||||||
@ -154,15 +153,15 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
|||||||
): ITemplateItem
|
): ITemplateItem
|
||||||
{
|
{
|
||||||
// The mag Slot data for the weapon
|
// The mag Slot data for the weapon
|
||||||
const magSlot = this.itemHelper.getItem(weaponTpl)[1]._props.Slots.find((x) => x._name === "mod_magazine");
|
const magSlot = this.itemHelper.getItem(weaponTpl)[1]._props.Slots.find(x => x._name === "mod_magazine");
|
||||||
if (!magSlot)
|
if (!magSlot)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// All possible mags that fit into the weapon excluding blacklisted
|
// All possible mags that fit into the weapon excluding blacklisted
|
||||||
const magazinePool = magSlot._props.filters[0].Filter.filter((x) => !magazineBlacklist.includes(x)).map((x) =>
|
const magazinePool = magSlot._props.filters[0].Filter.filter(x => !magazineBlacklist.includes(x)).map(x =>
|
||||||
this.itemHelper.getItem(x)[1]
|
this.itemHelper.getItem(x)[1],
|
||||||
);
|
);
|
||||||
if (!magazinePool)
|
if (!magazinePool)
|
||||||
{
|
{
|
||||||
@ -170,7 +169,7 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Non-internal magazines that fit into the weapon
|
// Non-internal magazines that fit into the weapon
|
||||||
const externalMagazineOnlyPool = magazinePool.filter((x) => x._props.ReloadMagType !== "InternalMagazine");
|
const externalMagazineOnlyPool = magazinePool.filter(x => x._props.ReloadMagType !== "InternalMagazine");
|
||||||
if (!externalMagazineOnlyPool || externalMagazineOnlyPool?.length === 0)
|
if (!externalMagazineOnlyPool || externalMagazineOnlyPool?.length === 0)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen";
|
import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen";
|
||||||
import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
|
import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
|
||||||
import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper";
|
import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen";
|
import { IInventoryMagGen } from "@spt-aki/generators/weapongen/IInventoryMagGen";
|
||||||
import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
|
import { InventoryMagGen } from "@spt-aki/generators/weapongen/InventoryMagGen";
|
||||||
import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper";
|
import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { QuestHelper } from "@spt-aki/helpers/QuestHelper";
|
import { QuestHelper } from "@spt-aki/helpers/QuestHelper";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
@ -77,7 +76,7 @@ export class AssortHelper
|
|||||||
protected getQuestIdAndStatusThatShowAssort(
|
protected getQuestIdAndStatusThatShowAssort(
|
||||||
mergedQuestAssorts: Record<string, Record<string, string>>,
|
mergedQuestAssorts: Record<string, Record<string, string>>,
|
||||||
assortId: string,
|
assortId: string,
|
||||||
): { questId: string; status: QuestStatus[]; }
|
): { questId: string, status: QuestStatus[] }
|
||||||
{
|
{
|
||||||
if (assortId in mergedQuestAssorts.started)
|
if (assortId in mergedQuestAssorts.started)
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { BotHelper } from "@spt-aki/helpers/BotHelper";
|
import { BotHelper } from "@spt-aki/helpers/BotHelper";
|
||||||
import { Difficulty } from "@spt-aki/models/eft/common/tables/IBotType";
|
import { Difficulty } from "@spt-aki/models/eft/common/tables/IBotType";
|
||||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
import { ApplicationContext } from "@spt-aki/context/ApplicationContext";
|
||||||
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
import { ContextVariableType } from "@spt-aki/context/ContextVariableType";
|
||||||
import { ContainerHelper } from "@spt-aki/helpers/ContainerHelper";
|
import { ContainerHelper } from "@spt-aki/helpers/ContainerHelper";
|
||||||
@ -52,7 +51,7 @@ export class BotGeneratorHelper
|
|||||||
* @param botRole Used by weapons to randomize the durability values. Null for non-equipped items
|
* @param botRole Used by weapons to randomize the durability values. Null for non-equipped items
|
||||||
* @returns Item Upd object with extra properties
|
* @returns Item Upd object with extra properties
|
||||||
*/
|
*/
|
||||||
public generateExtraPropertiesForItem(itemTemplate: ITemplateItem, botRole?: string): { upd?: Upd; }
|
public generateExtraPropertiesForItem(itemTemplate: ITemplateItem, botRole?: string): { upd?: Upd }
|
||||||
{
|
{
|
||||||
// Get raid settings, if no raid, default to day
|
// Get raid settings, if no raid, default to day
|
||||||
const raidSettings = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue<
|
const raidSettings = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION)?.getValue<
|
||||||
@ -123,7 +122,7 @@ export class BotGeneratorHelper
|
|||||||
? this.getBotEquipmentSettingFromConfig(botRole, "lightIsActiveNightChancePercent", 50)
|
? this.getBotEquipmentSettingFromConfig(botRole, "lightIsActiveNightChancePercent", 50)
|
||||||
: this.getBotEquipmentSettingFromConfig(botRole, "lightIsActiveDayChancePercent", 25);
|
: this.getBotEquipmentSettingFromConfig(botRole, "lightIsActiveDayChancePercent", 25);
|
||||||
itemProperties.Light = {
|
itemProperties.Light = {
|
||||||
IsActive: (this.randomUtil.getChance100(lightLaserActiveChance)),
|
IsActive: this.randomUtil.getChance100(lightLaserActiveChance),
|
||||||
SelectedMode: 0,
|
SelectedMode: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -136,7 +135,7 @@ export class BotGeneratorHelper
|
|||||||
50,
|
50,
|
||||||
);
|
);
|
||||||
itemProperties.Light = {
|
itemProperties.Light = {
|
||||||
IsActive: (this.randomUtil.getChance100(lightLaserActiveChance)),
|
IsActive: this.randomUtil.getChance100(lightLaserActiveChance),
|
||||||
SelectedMode: 0,
|
SelectedMode: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -147,7 +146,7 @@ export class BotGeneratorHelper
|
|||||||
const nvgActiveChance = raidIsNight
|
const nvgActiveChance = raidIsNight
|
||||||
? this.getBotEquipmentSettingFromConfig(botRole, "nvgIsActiveChanceNightPercent", 90)
|
? this.getBotEquipmentSettingFromConfig(botRole, "nvgIsActiveChanceNightPercent", 90)
|
||||||
: this.getBotEquipmentSettingFromConfig(botRole, "nvgIsActiveChanceDayPercent", 15);
|
: this.getBotEquipmentSettingFromConfig(botRole, "nvgIsActiveChanceDayPercent", 15);
|
||||||
itemProperties.Togglable = { On: (this.randomUtil.getChance100(nvgActiveChance)) };
|
itemProperties.Togglable = { On: this.randomUtil.getChance100(nvgActiveChance) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Togglable face shield
|
// Togglable face shield
|
||||||
@ -159,7 +158,7 @@ export class BotGeneratorHelper
|
|||||||
"faceShieldIsActiveChancePercent",
|
"faceShieldIsActiveChancePercent",
|
||||||
75,
|
75,
|
||||||
);
|
);
|
||||||
itemProperties.Togglable = { On: (this.randomUtil.getChance100(faceShieldActiveChance)) };
|
itemProperties.Togglable = { On: this.randomUtil.getChance100(faceShieldActiveChance) };
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.keys(itemProperties).length ? { upd: itemProperties } : {};
|
return Object.keys(itemProperties).length ? { upd: itemProperties } : {};
|
||||||
@ -288,7 +287,7 @@ export class BotGeneratorHelper
|
|||||||
): IChooseRandomCompatibleModResult
|
): IChooseRandomCompatibleModResult
|
||||||
{
|
{
|
||||||
// TODO: Can probably be optimized to cache itemTemplates as items are added to inventory
|
// TODO: Can probably be optimized to cache itemTemplates as items are added to inventory
|
||||||
const equippedItemsDb = itemsEquipped.map((item) => this.databaseServer.getTables().templates.items[item._tpl]);
|
const equippedItemsDb = itemsEquipped.map(item => this.databaseServer.getTables().templates.items[item._tpl]);
|
||||||
const itemToEquipDb = this.itemHelper.getItem(tplToCheck);
|
const itemToEquipDb = this.itemHelper.getItem(tplToCheck);
|
||||||
const itemToEquip = itemToEquipDb[1];
|
const itemToEquip = itemToEquipDb[1];
|
||||||
|
|
||||||
@ -319,7 +318,7 @@ export class BotGeneratorHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if any of the current weapon mod templates have the incoming item defined as incompatible
|
// Check if any of the current weapon mod templates have the incoming item defined as incompatible
|
||||||
const blockingItem = equippedItemsDb.find((x) => x._props.ConflictingItems?.includes(tplToCheck));
|
const blockingItem = equippedItemsDb.find(x => x._props.ConflictingItems?.includes(tplToCheck));
|
||||||
if (blockingItem)
|
if (blockingItem)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
@ -332,7 +331,7 @@ export class BotGeneratorHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check inverse to above, if the incoming item has any existing mods in its conflicting items array
|
// Check inverse to above, if the incoming item has any existing mods in its conflicting items array
|
||||||
const blockingModItem = itemsEquipped.find((item) => itemToEquip._props.ConflictingItems?.includes(item._tpl));
|
const blockingModItem = itemsEquipped.find(item => itemToEquip._props.ConflictingItems?.includes(item._tpl));
|
||||||
if (blockingModItem)
|
if (blockingModItem)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
@ -366,7 +365,7 @@ export class BotGeneratorHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Can probably be optimized to cache itemTemplates as items are added to inventory
|
// TODO: Can probably be optimized to cache itemTemplates as items are added to inventory
|
||||||
const equippedItemsDb = itemsEquipped.map((i) => this.databaseServer.getTables().templates.items[i._tpl]);
|
const equippedItemsDb = itemsEquipped.map(i => this.databaseServer.getTables().templates.items[i._tpl]);
|
||||||
const itemToEquipDb = this.itemHelper.getItem(tplToCheck);
|
const itemToEquipDb = this.itemHelper.getItem(tplToCheck);
|
||||||
const itemToEquip = itemToEquipDb[1];
|
const itemToEquip = itemToEquipDb[1];
|
||||||
|
|
||||||
@ -396,7 +395,7 @@ export class BotGeneratorHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Does an equipped item have a property that blocks the desired item - check for prop "BlocksX" .e.g BlocksEarpiece / BlocksFaceCover
|
// Does an equipped item have a property that blocks the desired item - check for prop "BlocksX" .e.g BlocksEarpiece / BlocksFaceCover
|
||||||
let blockingItem = equippedItemsDb.find((x) => x._props[`Blocks${equipmentSlot}`]);
|
let blockingItem = equippedItemsDb.find(x => x._props[`Blocks${equipmentSlot}`]);
|
||||||
if (blockingItem)
|
if (blockingItem)
|
||||||
{
|
{
|
||||||
// this.logger.warning(`1 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._name} - ${equipmentSlot}`);
|
// this.logger.warning(`1 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._name} - ${equipmentSlot}`);
|
||||||
@ -410,7 +409,7 @@ export class BotGeneratorHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if any of the current inventory templates have the incoming item defined as incompatible
|
// Check if any of the current inventory templates have the incoming item defined as incompatible
|
||||||
blockingItem = equippedItemsDb.find((x) => x._props.ConflictingItems?.includes(tplToCheck));
|
blockingItem = equippedItemsDb.find(x => x._props.ConflictingItems?.includes(tplToCheck));
|
||||||
if (blockingItem)
|
if (blockingItem)
|
||||||
{
|
{
|
||||||
// this.logger.warning(`2 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._props.Name} - ${equipmentSlot}`);
|
// this.logger.warning(`2 incompatibility found between - ${itemToEquip[1]._name} and ${blockingItem._props.Name} - ${equipmentSlot}`);
|
||||||
@ -426,7 +425,7 @@ export class BotGeneratorHelper
|
|||||||
// Does item being checked get blocked/block existing item
|
// Does item being checked get blocked/block existing item
|
||||||
if (itemToEquip._props.BlocksHeadwear)
|
if (itemToEquip._props.BlocksHeadwear)
|
||||||
{
|
{
|
||||||
const existingHeadwear = itemsEquipped.find((x) => x.slotId === "Headwear");
|
const existingHeadwear = itemsEquipped.find(x => x.slotId === "Headwear");
|
||||||
if (existingHeadwear)
|
if (existingHeadwear)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
@ -442,7 +441,7 @@ export class BotGeneratorHelper
|
|||||||
// Does item being checked get blocked/block existing item
|
// Does item being checked get blocked/block existing item
|
||||||
if (itemToEquip._props.BlocksFaceCover)
|
if (itemToEquip._props.BlocksFaceCover)
|
||||||
{
|
{
|
||||||
const existingFaceCover = itemsEquipped.find((item) => item.slotId === "FaceCover");
|
const existingFaceCover = itemsEquipped.find(item => item.slotId === "FaceCover");
|
||||||
if (existingFaceCover)
|
if (existingFaceCover)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
@ -458,7 +457,7 @@ export class BotGeneratorHelper
|
|||||||
// Does item being checked get blocked/block existing item
|
// Does item being checked get blocked/block existing item
|
||||||
if (itemToEquip._props.BlocksEarpiece)
|
if (itemToEquip._props.BlocksEarpiece)
|
||||||
{
|
{
|
||||||
const existingEarpiece = itemsEquipped.find((item) => item.slotId === "Earpiece");
|
const existingEarpiece = itemsEquipped.find(item => item.slotId === "Earpiece");
|
||||||
if (existingEarpiece)
|
if (existingEarpiece)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
@ -474,7 +473,7 @@ export class BotGeneratorHelper
|
|||||||
// Does item being checked get blocked/block existing item
|
// Does item being checked get blocked/block existing item
|
||||||
if (itemToEquip._props.BlocksArmorVest)
|
if (itemToEquip._props.BlocksArmorVest)
|
||||||
{
|
{
|
||||||
const existingArmorVest = itemsEquipped.find((item) => item.slotId === "ArmorVest");
|
const existingArmorVest = itemsEquipped.find(item => item.slotId === "ArmorVest");
|
||||||
if (existingArmorVest)
|
if (existingArmorVest)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
@ -488,7 +487,7 @@ export class BotGeneratorHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the incoming item has any inventory items defined as incompatible
|
// Check if the incoming item has any inventory items defined as incompatible
|
||||||
const blockingInventoryItem = itemsEquipped.find((x) => itemToEquip._props.ConflictingItems?.includes(x._tpl));
|
const blockingInventoryItem = itemsEquipped.find(x => itemToEquip._props.ConflictingItems?.includes(x._tpl));
|
||||||
if (blockingInventoryItem)
|
if (blockingInventoryItem)
|
||||||
{
|
{
|
||||||
// this.logger.warning(`3 incompatibility found between - ${itemToEquip[1]._name} and ${blockingInventoryItem._tpl} - ${equipmentSlot}`)
|
// this.logger.warning(`3 incompatibility found between - ${itemToEquip[1]._name} and ${blockingInventoryItem._tpl} - ${equipmentSlot}`)
|
||||||
@ -510,9 +509,9 @@ export class BotGeneratorHelper
|
|||||||
*/
|
*/
|
||||||
public getBotEquipmentRole(botRole: string): string
|
public getBotEquipmentRole(botRole: string): string
|
||||||
{
|
{
|
||||||
return ([this.pmcConfig.usecType.toLowerCase(), this.pmcConfig.bearType.toLowerCase()].includes(
|
return [this.pmcConfig.usecType.toLowerCase(), this.pmcConfig.bearType.toLowerCase()].includes(
|
||||||
botRole.toLowerCase(),
|
botRole.toLowerCase(),
|
||||||
))
|
)
|
||||||
? "pmc"
|
? "pmc"
|
||||||
: botRole;
|
: botRole;
|
||||||
}
|
}
|
||||||
@ -544,7 +543,7 @@ export class BotGeneratorHelper
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Get container to put item into
|
// Get container to put item into
|
||||||
const container = inventory.items.find((item) => item.slotId === equipmentSlotId);
|
const container = inventory.items.find(item => item.slotId === equipmentSlotId);
|
||||||
if (!container)
|
if (!container)
|
||||||
{
|
{
|
||||||
missingContainerCount++;
|
missingContainerCount++;
|
||||||
@ -590,8 +589,8 @@ export class BotGeneratorHelper
|
|||||||
{
|
{
|
||||||
// Grid is empty, skip or item size is bigger than grid
|
// Grid is empty, skip or item size is bigger than grid
|
||||||
if (
|
if (
|
||||||
(slotGrid._props.cellsH === 0 || slotGrid._props.cellsV === 0)
|
slotGrid._props.cellsH === 0 || slotGrid._props.cellsV === 0
|
||||||
|| (itemSize[0] * itemSize[1] > slotGrid._props.cellsV * slotGrid._props.cellsH)
|
|| itemSize[0] * itemSize[1] > slotGrid._props.cellsV * slotGrid._props.cellsH
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -605,12 +604,12 @@ export class BotGeneratorHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get all root items in found container
|
// Get all root items in found container
|
||||||
const existingContainerItems = inventory.items.filter((item) =>
|
const existingContainerItems = inventory.items.filter(item =>
|
||||||
item.parentId === container._id && item.slotId === slotGrid._name
|
item.parentId === container._id && item.slotId === slotGrid._name,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get root items in container we can iterate over to find out what space is free
|
// Get root items in container we can iterate over to find out what space is free
|
||||||
const containerItemsToCheck = existingContainerItems.filter((x) => x.slotId === slotGrid._name);
|
const containerItemsToCheck = existingContainerItems.filter(x => x.slotId === slotGrid._name);
|
||||||
for (const item of containerItemsToCheck)
|
for (const item of containerItemsToCheck)
|
||||||
{
|
{
|
||||||
// Look for children on items, insert into array if found
|
// Look for children on items, insert into array if found
|
||||||
@ -636,7 +635,7 @@ export class BotGeneratorHelper
|
|||||||
// Open slot found, add item to inventory
|
// Open slot found, add item to inventory
|
||||||
if (findSlotResult.success)
|
if (findSlotResult.success)
|
||||||
{
|
{
|
||||||
const parentItem = itemWithChildren.find((i) => i._id === rootItemId);
|
const parentItem = itemWithChildren.find(i => i._id === rootItemId);
|
||||||
|
|
||||||
// Set items parent to container id
|
// Set items parent to container id
|
||||||
parentItem.parentId = container._id;
|
parentItem.parentId = container._id;
|
||||||
@ -666,7 +665,7 @@ export class BotGeneratorHelper
|
|||||||
if (containersIdFull)
|
if (containersIdFull)
|
||||||
{
|
{
|
||||||
// if the item was a one by one, we know it must be full. Or if the maps cant find a slot for a one by one
|
// if the item was a one by one, we know it must be full. Or if the maps cant find a slot for a one by one
|
||||||
if ((itemSize[0] === 1 && itemSize[1] === 1))
|
if (itemSize[0] === 1 && itemSize[1] === 1)
|
||||||
{
|
{
|
||||||
containersIdFull.add(equipmentSlotId);
|
containersIdFull.add(equipmentSlotId);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { MinMax } from "@spt-aki/models/common/MinMax";
|
import { MinMax } from "@spt-aki/models/common/MinMax";
|
||||||
import { Difficulty, IBotType } from "@spt-aki/models/eft/common/tables/IBotType";
|
import { Difficulty, IBotType } from "@spt-aki/models/eft/common/tables/IBotType";
|
||||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
@ -64,12 +63,12 @@ export class BotHelper
|
|||||||
*/
|
*/
|
||||||
public isBotPmc(botRole: string): boolean
|
public isBotPmc(botRole: string): boolean
|
||||||
{
|
{
|
||||||
return (["usec", "bear", "pmc", "sptbear", "sptusec"].includes(botRole?.toLowerCase()));
|
return ["usec", "bear", "pmc", "sptbear", "sptusec"].includes(botRole?.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
public isBotBoss(botRole: string): boolean
|
public isBotBoss(botRole: string): boolean
|
||||||
{
|
{
|
||||||
return this.botConfig.bosses.some((x) => x.toLowerCase() === botRole?.toLowerCase());
|
return this.botConfig.bosses.some(x => x.toLowerCase() === botRole?.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
public isBotFollower(botRole: string): boolean
|
public isBotFollower(botRole: string): boolean
|
||||||
@ -186,7 +185,7 @@ export class BotHelper
|
|||||||
public rollChanceToBePmc(role: string, botConvertMinMax: MinMax): boolean
|
public rollChanceToBePmc(role: string, botConvertMinMax: MinMax): boolean
|
||||||
{
|
{
|
||||||
return role.toLowerCase() in this.pmcConfig.convertIntoPmcChance
|
return role.toLowerCase() in this.pmcConfig.convertIntoPmcChance
|
||||||
&& this.randomUtil.getChance100(this.randomUtil.getInt(botConvertMinMax.min, botConvertMinMax.max));
|
&& this.randomUtil.getChance100(this.randomUtil.getInt(botConvertMinMax.min, botConvertMinMax.max));
|
||||||
}
|
}
|
||||||
|
|
||||||
public botRoleIsPmc(botRole: string): boolean
|
public botRoleIsPmc(botRole: string): boolean
|
||||||
@ -210,7 +209,7 @@ export class BotHelper
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return botEquipConfig.randomisation.find((x) => botLevel >= x.levelRange.min && botLevel <= x.levelRange.max);
|
return botEquipConfig.randomisation.find(x => botLevel >= x.levelRange.min && botLevel <= x.levelRange.max);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -219,7 +218,7 @@ export class BotHelper
|
|||||||
*/
|
*/
|
||||||
public getRandomizedPmcRole(): string
|
public getRandomizedPmcRole(): string
|
||||||
{
|
{
|
||||||
return (this.randomUtil.getChance100(this.pmcConfig.isUsec))
|
return this.randomUtil.getChance100(this.pmcConfig.isUsec)
|
||||||
? this.pmcConfig.usecType
|
? this.pmcConfig.usecType
|
||||||
: this.pmcConfig.bearType;
|
: this.pmcConfig.bearType;
|
||||||
}
|
}
|
||||||
@ -248,6 +247,6 @@ export class BotHelper
|
|||||||
*/
|
*/
|
||||||
protected getRandomizedPmcSide(): string
|
protected getRandomizedPmcSide(): string
|
||||||
{
|
{
|
||||||
return (this.randomUtil.getChance100(this.pmcConfig.isUsec)) ? "Usec" : "Bear";
|
return this.randomUtil.getChance100(this.pmcConfig.isUsec) ? "Usec" : "Bear";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
||||||
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
|
import { WeightedRandomHelper } from "@spt-aki/helpers/WeightedRandomHelper";
|
||||||
@ -46,7 +45,7 @@ export class BotWeaponGeneratorHelper
|
|||||||
{
|
{
|
||||||
const firstSlotAmmoTpl = magTemplate._props.Cartridges[0]._props.filters[0].Filter[0];
|
const firstSlotAmmoTpl = magTemplate._props.Cartridges[0]._props.filters[0].Filter[0];
|
||||||
const ammoMaxStackSize = this.itemHelper.getItem(firstSlotAmmoTpl)[1]?._props?.StackMaxSize ?? 1;
|
const ammoMaxStackSize = this.itemHelper.getItem(firstSlotAmmoTpl)[1]?._props?.StackMaxSize ?? 1;
|
||||||
chamberBulletCount = (ammoMaxStackSize === 1)
|
chamberBulletCount = ammoMaxStackSize === 1
|
||||||
? 1 // Rotating grenade launcher
|
? 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
|
: magTemplate._props.Slots.length; // Shotguns/revolvers. We count the number of camoras as the _max_count of the magazine is 0
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ export class ContainerHelper
|
|||||||
const limitX = containerX - minVolume;
|
const limitX = containerX - minVolume;
|
||||||
|
|
||||||
// Every x+y slot taken up in container, exit
|
// Every x+y slot taken up in container, exit
|
||||||
if (container2D.every((x) => x.every((y) => y === 1)))
|
if (container2D.every(x => x.every(y => y === 1)))
|
||||||
{
|
{
|
||||||
return new FindSlotResult(false);
|
return new FindSlotResult(false);
|
||||||
}
|
}
|
||||||
@ -44,7 +44,7 @@ export class ContainerHelper
|
|||||||
for (let y = 0; y < limitY; y++)
|
for (let y = 0; y < limitY; y++)
|
||||||
{
|
{
|
||||||
// Across
|
// Across
|
||||||
if (container2D[y].every((x) => x === 1))
|
if (container2D[y].every(x => x === 1))
|
||||||
{
|
{
|
||||||
// Every item in row is full, skip row
|
// Every item in row is full, skip row
|
||||||
continue;
|
continue;
|
||||||
|
@ -26,7 +26,7 @@ export abstract class AbstractDialogueChatBot implements IDialogueChatBot
|
|||||||
|
|
||||||
public registerChatCommand(chatCommand: IChatCommand | ICommandoCommand): void
|
public registerChatCommand(chatCommand: IChatCommand | ICommandoCommand): void
|
||||||
{
|
{
|
||||||
if (this.chatCommands.some((cc) => cc.getCommandPrefix() === chatCommand.getCommandPrefix()))
|
if (this.chatCommands.some(cc => cc.getCommandPrefix() === chatCommand.getCommandPrefix()))
|
||||||
{
|
{
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`The command "${chatCommand.getCommandPrefix()}" attempting to be registered already exists.`,
|
`The command "${chatCommand.getCommandPrefix()}" attempting to be registered already exists.`,
|
||||||
@ -49,7 +49,7 @@ export abstract class AbstractDialogueChatBot implements IDialogueChatBot
|
|||||||
|
|
||||||
const splitCommand = request.text.split(" ");
|
const splitCommand = request.text.split(" ");
|
||||||
|
|
||||||
const commandos = this.chatCommands.filter((c) => c.getCommandPrefix() === splitCommand[0]);
|
const commandos = this.chatCommands.filter(c => c.getCommandPrefix() === splitCommand[0]);
|
||||||
if (commandos[0]?.getCommands().has(splitCommand[1]))
|
if (commandos[0]?.getCommands().has(splitCommand[1]))
|
||||||
{
|
{
|
||||||
return commandos[0].handle(splitCommand[1], this.getChatBot(), sessionId, request);
|
return commandos[0].handle(splitCommand[1], this.getChatBot(), sessionId, request);
|
||||||
|
@ -8,8 +8,8 @@ import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile";
|
|||||||
export type ICommandoCommand = IChatCommand;
|
export type ICommandoCommand = IChatCommand;
|
||||||
export interface IChatCommand
|
export interface IChatCommand
|
||||||
{
|
{
|
||||||
getCommandPrefix(): string;
|
getCommandPrefix(): string
|
||||||
getCommandHelp(command: string): string;
|
getCommandHelp(command: string): string
|
||||||
getCommands(): Set<string>;
|
getCommands(): Set<string>
|
||||||
handle(command: string, commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string;
|
handle(command: string, commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { inject, injectAll, injectable } from "tsyringe";
|
||||||
import { IChatCommand } from "@spt-aki/helpers/Dialogue/Commando/IChatCommand";
|
import { IChatCommand } from "@spt-aki/helpers/Dialogue/Commando/IChatCommand";
|
||||||
import { ISptCommand } from "@spt-aki/helpers/Dialogue/Commando/SptCommands/ISptCommand";
|
import { ISptCommand } from "@spt-aki/helpers/Dialogue/Commando/SptCommands/ISptCommand";
|
||||||
import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest";
|
import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest";
|
||||||
@ -5,7 +6,6 @@ import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile";
|
|||||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
import { ICoreConfig } from "@spt-aki/models/spt/config/ICoreConfig";
|
import { ICoreConfig } from "@spt-aki/models/spt/config/ICoreConfig";
|
||||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||||
import { inject, injectAll, injectable } from "tsyringe";
|
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class SptCommandoCommands implements IChatCommand
|
export class SptCommandoCommands implements IChatCommand
|
||||||
@ -19,17 +19,17 @@ export class SptCommandoCommands implements IChatCommand
|
|||||||
// if give command is disabled or commando commands are disabled
|
// if give command is disabled or commando commands are disabled
|
||||||
if (
|
if (
|
||||||
!(coreConfigs.features?.chatbotFeatures?.commandoFeatures?.giveCommandEnabled
|
!(coreConfigs.features?.chatbotFeatures?.commandoFeatures?.giveCommandEnabled
|
||||||
&& coreConfigs.features?.chatbotFeatures?.commandoEnabled)
|
&& coreConfigs.features?.chatbotFeatures?.commandoEnabled)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const giveCommand = this.sptCommands.find((c) => c.getCommand().toLocaleLowerCase() === "give");
|
const giveCommand = this.sptCommands.find(c => c.getCommand().toLocaleLowerCase() === "give");
|
||||||
this.sptCommands.splice(this.sptCommands.indexOf(giveCommand), 1);
|
this.sptCommands.splice(this.sptCommands.indexOf(giveCommand), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public registerSptCommandoCommand(command: ISptCommand): void
|
public registerSptCommandoCommand(command: ISptCommand): void
|
||||||
{
|
{
|
||||||
if (this.sptCommands.some((c) => c.getCommand() === command.getCommand()))
|
if (this.sptCommands.some(c => c.getCommand() === command.getCommand()))
|
||||||
{
|
{
|
||||||
throw new Error(`The command "${command.getCommand()}" attempting to be registered already exists.`);
|
throw new Error(`The command "${command.getCommand()}" attempting to be registered already exists.`);
|
||||||
}
|
}
|
||||||
@ -38,7 +38,7 @@ export class SptCommandoCommands implements IChatCommand
|
|||||||
|
|
||||||
public getCommandHelp(command: string): string
|
public getCommandHelp(command: string): string
|
||||||
{
|
{
|
||||||
return this.sptCommands.find((c) => c.getCommand() === command)?.getCommandHelp();
|
return this.sptCommands.find(c => c.getCommand() === command)?.getCommandHelp();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCommandPrefix(): string
|
public getCommandPrefix(): string
|
||||||
@ -48,7 +48,7 @@ export class SptCommandoCommands implements IChatCommand
|
|||||||
|
|
||||||
public getCommands(): Set<string>
|
public getCommands(): Set<string>
|
||||||
{
|
{
|
||||||
return new Set(this.sptCommands.map((c) => c.getCommand()));
|
return new Set(this.sptCommands.map(c => c.getCommand()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public handle(
|
public handle(
|
||||||
@ -58,7 +58,7 @@ export class SptCommandoCommands implements IChatCommand
|
|||||||
request: ISendMessageRequest,
|
request: ISendMessageRequest,
|
||||||
): string
|
): string
|
||||||
{
|
{
|
||||||
return this.sptCommands.find((c) => c.getCommand() === command).performAction(
|
return this.sptCommands.find(c => c.getCommand() === command).performAction(
|
||||||
commandHandler,
|
commandHandler,
|
||||||
sessionId,
|
sessionId,
|
||||||
request,
|
request,
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user