Null checks first pass (!353)
Co-authored-by: clodan <clodan@clodan.com> Reviewed-on: https://dev.sp-tarkov.com/SPT/Server/pulls/353
This commit is contained in:
parent
d330ab3715
commit
aee391ec1d
@ -36761,7 +36761,7 @@
|
||||
"lockedByDefaultOverride": [
|
||||
"579dc571d53a0658a154fbec"
|
||||
],
|
||||
"purchaseAlllClothingByDefaultForTrader":[
|
||||
"purchaseAllClothingByDefaultForTrader":[
|
||||
"5ac3b934156ae10c4430e83c"
|
||||
]
|
||||
},
|
||||
@ -37704,7 +37704,7 @@
|
||||
"lockedByDefaultOverride": [
|
||||
"579dc571d53a0658a154fbec"
|
||||
],
|
||||
"purchaseAlllClothingByDefaultForTrader":[
|
||||
"purchaseAllClothingByDefaultForTrader":[
|
||||
"5ac3b934156ae10c4430e83c"
|
||||
]
|
||||
},
|
||||
|
@ -36,7 +36,7 @@ export class DataCallbacks
|
||||
*/
|
||||
public getSettings(url: string, info: IEmptyRequestData, sessionID: string): IGetBodyResponseData<ISettingsBase>
|
||||
{
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().settings);
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().settings!);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -45,8 +45,8 @@ export class DataCallbacks
|
||||
*/
|
||||
public getGlobals(url: string, info: IEmptyRequestData, sessionID: string): IGetBodyResponseData<IGlobals>
|
||||
{
|
||||
this.databaseServer.getTables().globals.time = Date.now() / 1000;
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().globals);
|
||||
this.databaseServer.getTables().globals!.time = Date.now() / 1000;
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().globals!);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,7 +55,7 @@ export class DataCallbacks
|
||||
*/
|
||||
public getTemplateItems(url: string, info: IEmptyRequestData, sessionID: string): string
|
||||
{
|
||||
return this.httpResponse.getUnclearedBody(this.databaseServer.getTables().templates.items);
|
||||
return this.httpResponse.getUnclearedBody(this.databaseServer.getTables().templates!.items);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,7 +68,7 @@ export class DataCallbacks
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<IHandbookBase>
|
||||
{
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().templates.handbook);
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().templates!.handbook);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,7 +81,7 @@ export class DataCallbacks
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<Record<string, ICustomizationItem>>
|
||||
{
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().templates.customization);
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().templates!.customization);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,7 +94,7 @@ export class DataCallbacks
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<string[]>
|
||||
{
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().templates.character);
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().templates!.character);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,7 +107,7 @@ export class DataCallbacks
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<IHideoutSettingsBase>
|
||||
{
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().hideout.settings);
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().hideout!.settings);
|
||||
}
|
||||
|
||||
public getHideoutAreas(
|
||||
@ -116,7 +116,7 @@ export class DataCallbacks
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<IHideoutArea[]>
|
||||
{
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().hideout.areas);
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().hideout!.areas);
|
||||
}
|
||||
|
||||
public gethideoutProduction(
|
||||
@ -125,7 +125,7 @@ export class DataCallbacks
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<IHideoutProduction[]>
|
||||
{
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().hideout.production);
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().hideout!.production);
|
||||
}
|
||||
|
||||
public getHideoutScavcase(
|
||||
@ -134,7 +134,7 @@ export class DataCallbacks
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<IHideoutScavCase[]>
|
||||
{
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().hideout.scavcase);
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().hideout!.scavcase);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,7 +146,7 @@ export class DataCallbacks
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<Record<string, string>>
|
||||
{
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().locales.languages);
|
||||
return this.httpResponse.getBody(this.databaseServer.getTables().locales!.languages);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,13 +156,16 @@ export class DataCallbacks
|
||||
{
|
||||
const localeId = url.replace("/client/menu/locale/", "");
|
||||
const tables = this.databaseServer.getTables();
|
||||
let result = tables.locales.menu[localeId];
|
||||
let result = tables.locales?.menu[localeId];
|
||||
|
||||
if (result === undefined)
|
||||
{
|
||||
result = tables.locales.menu.en;
|
||||
result = tables.locales?.menu.en;
|
||||
}
|
||||
|
||||
if (result === undefined)
|
||||
throw new Error(`Unable to determine locale for request with '${localeId}'`);
|
||||
|
||||
return this.httpResponse.getBody(result);
|
||||
}
|
||||
|
||||
@ -173,11 +176,11 @@ export class DataCallbacks
|
||||
{
|
||||
const localeId = url.replace("/client/locale/", "");
|
||||
const tables = this.databaseServer.getTables();
|
||||
let result = tables.locales.global[localeId];
|
||||
let result = tables.locales?.global[localeId];
|
||||
|
||||
if (result === undefined)
|
||||
{
|
||||
result = tables.locales.global["en"];
|
||||
result = tables.locales?.global["en"];
|
||||
}
|
||||
|
||||
return this.httpResponse.getUnclearedBody(result);
|
||||
|
@ -95,7 +95,7 @@ export class DialogueCallbacks implements OnUpdate
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<DialogueInfo[]>
|
||||
{
|
||||
return this.httpResponse.getBody(this.dialogueController.generateDialogueList(sessionID), 0, null, false);
|
||||
return this.httpResponse.getBody(this.dialogueController.generateDialogueList(sessionID), 0, undefined, false);
|
||||
}
|
||||
|
||||
/** Handle client/mail/dialog/view */
|
||||
@ -105,7 +105,12 @@ export class DialogueCallbacks implements OnUpdate
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<IGetMailDialogViewResponseData>
|
||||
{
|
||||
return this.httpResponse.getBody(this.dialogueController.generateDialogueView(info, sessionID), 0, null, false);
|
||||
return this.httpResponse.getBody(
|
||||
this.dialogueController.generateDialogueView(info, sessionID),
|
||||
0,
|
||||
undefined,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
/** Handle client/mail/dialog/info */
|
||||
@ -154,7 +159,7 @@ export class DialogueCallbacks implements OnUpdate
|
||||
url: string,
|
||||
info: IGetAllAttachmentsRequestData,
|
||||
sessionID: string,
|
||||
): IGetBodyResponseData<IGetAllAttachmentsResponse>
|
||||
): IGetBodyResponseData<IGetAllAttachmentsResponse | undefined>
|
||||
{
|
||||
return this.httpResponse.getBody(this.dialogueController.getAllAttachments(info.dialogId, sessionID));
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ export class ItemEventCallbacks
|
||||
|
||||
for (const warning of warnings)
|
||||
{
|
||||
if (!nonCriticalErrorCodes.includes(+warning.code))
|
||||
if (!nonCriticalErrorCodes.includes(+(warning?.code ?? "0")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -94,6 +94,7 @@ export class MatchCallbacks
|
||||
): IGetBodyResponseData<IGroupCharacter[]>
|
||||
{
|
||||
const result = [];
|
||||
// eslint-disable-next-line strict-null-checks/all
|
||||
result.push({});
|
||||
|
||||
return this.httpResponse.getBody(result);
|
||||
@ -165,7 +166,7 @@ export class MatchCallbacks
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public getMetrics(url: string, info: any, sessionID: string): IGetBodyResponseData<string>
|
||||
{
|
||||
return this.httpResponse.getBody(this.jsonUtil.serialize(this.databaseServer.getTables().match.metrics));
|
||||
return this.httpResponse.getBody(this.jsonUtil.serialize(this.databaseServer.getTables().match!.metrics));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,27 +19,29 @@ export class ApplicationContext
|
||||
* const matchInfo = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION).getValue<IGetRaidConfigurationRequestData>();
|
||||
* ```
|
||||
*/
|
||||
public getLatestValue(type: ContextVariableType): ContextVariable
|
||||
public getLatestValue(type: ContextVariableType): ContextVariable | undefined
|
||||
{
|
||||
if (this.variables.has(type))
|
||||
{
|
||||
return this.variables.get(type)?.getTail();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public getValues(type: ContextVariableType): ContextVariable[]
|
||||
public getValues(type: ContextVariableType): ContextVariable[] | undefined
|
||||
{
|
||||
if (this.variables.has(type))
|
||||
{
|
||||
const res: ContextVariable[] = [];
|
||||
|
||||
for (const value of this.variables.get(type).values())
|
||||
for (const value of this.variables.get(type)!.values())
|
||||
{
|
||||
res.push(value);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public addValue(type: ContextVariableType, value: any): void
|
||||
@ -47,7 +49,7 @@ export class ApplicationContext
|
||||
let list: LinkedList<ContextVariable>;
|
||||
if (this.variables.has(type))
|
||||
{
|
||||
list = this.variables.get(type);
|
||||
list = this.variables.get(type)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ export class AchievementController
|
||||
*/
|
||||
public getAchievements(sessionID: string): IGetAchievementsResponse
|
||||
{
|
||||
return { elements: this.databaseServer.getTables().templates.achievements };
|
||||
return { elements: this.databaseServer.getTables().templates!.achievements };
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32,7 +32,7 @@ export class AchievementController
|
||||
*/
|
||||
public getAchievementStatistics(sessionId: string): ICompletedAchievementsResponse
|
||||
{
|
||||
const achievements = this.databaseServer.getTables().templates.achievements;
|
||||
const achievements = this.databaseServer.getTables().templates!.achievements;
|
||||
const stats = {};
|
||||
|
||||
for (const achievement of achievements)
|
||||
|
@ -80,7 +80,7 @@ export class BotController
|
||||
*/
|
||||
public getBotCoreDifficulty(): IBotCore
|
||||
{
|
||||
return this.databaseServer.getTables().bots.core;
|
||||
return this.databaseServer.getTables().bots!.core;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,7 +146,7 @@ export class BotController
|
||||
{
|
||||
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)));
|
||||
for (let botType of botTypes)
|
||||
{
|
||||
@ -212,8 +212,12 @@ export class BotController
|
||||
.getLatestValue(ContextVariableType.RAID_CONFIGURATION)
|
||||
?.getValue<IGetRaidConfigurationRequestData>();
|
||||
|
||||
if (raidSettings === undefined)
|
||||
{
|
||||
throw new Error("Raid settings could not be loaded from ApplicationContext");
|
||||
}
|
||||
const pmcLevelRangeForMap
|
||||
= this.pmcConfig.locationSpecificPmcLevelOverride[raidSettings?.location.toLowerCase()];
|
||||
= this.pmcConfig.locationSpecificPmcLevelOverride[raidSettings.location.toLowerCase()];
|
||||
|
||||
const allPmcsHaveSameNameAsPlayer = this.randomUtil.getChance100(
|
||||
this.pmcConfig.allPMCsHavePlayerNameWithRandomPrefixChance,
|
||||
@ -369,6 +373,11 @@ export class BotController
|
||||
const raidSettings = this.applicationContext
|
||||
.getLatestValue(ContextVariableType.RAID_CONFIGURATION)
|
||||
?.getValue<IGetRaidConfigurationRequestData>();
|
||||
|
||||
if (raidSettings === undefined)
|
||||
{
|
||||
throw new Error("Raid settings could not be loaded from ApplicationContext");
|
||||
}
|
||||
const pmcLevelRangeForMap
|
||||
= this.pmcConfig.locationSpecificPmcLevelOverride[raidSettings.location.toLowerCase()];
|
||||
|
||||
@ -482,7 +491,7 @@ export class BotController
|
||||
const defaultMapCapId = "default";
|
||||
const raidConfig = this.applicationContext
|
||||
.getLatestValue(ContextVariableType.RAID_CONFIGURATION)
|
||||
.getValue<IGetRaidConfigurationRequestData>();
|
||||
?.getValue<IGetRaidConfigurationRequestData>();
|
||||
|
||||
if (!raidConfig)
|
||||
{
|
||||
@ -497,7 +506,7 @@ export class BotController
|
||||
this.logger.warning(
|
||||
this.localisationService.getText(
|
||||
"bot-no_bot_cap_found_for_location",
|
||||
raidConfig.location.toLowerCase(),
|
||||
raidConfig?.location.toLowerCase(),
|
||||
),
|
||||
);
|
||||
botCap = this.botConfig.maxBotCap[defaultMapCapId];
|
||||
|
@ -42,7 +42,7 @@ export class BuildController
|
||||
|
||||
// Ensure the secure container in the default presets match what the player has equipped
|
||||
const defaultEquipmentPresetsClone = this.cloner.clone(
|
||||
this.databaseServer.getTables().templates.defaultEquipmentPresets,
|
||||
this.databaseServer.getTables().templates!.defaultEquipmentPresets,
|
||||
);
|
||||
const playerSecureContainer = profile.characters.pmc.Inventory.items?.find(
|
||||
(x) => x.slotId === secureContainerSlotId,
|
||||
|
@ -38,14 +38,17 @@ export class CustomizationController
|
||||
public getTraderSuits(traderID: string, sessionID: string): ISuit[]
|
||||
{
|
||||
const pmcData: IPmcData = this.profileHelper.getPmcProfile(sessionID);
|
||||
const templates = this.databaseServer.getTables().templates.customization;
|
||||
const suits = this.databaseServer.getTables().traders[traderID].suits;
|
||||
const templates = this.databaseServer.getTables().templates!.customization;
|
||||
const suits = this.databaseServer.getTables().traders![traderID].suits;
|
||||
|
||||
// Get an inner join of clothing from templates.customization and Ragman's suits array
|
||||
const matchingSuits = suits.filter((x) => x.suiteId in templates);
|
||||
const matchingSuits = suits?.filter((x) => x.suiteId in templates);
|
||||
|
||||
// Return all suits that have a side array containing the players side (usec/bear)
|
||||
return matchingSuits.filter((x) => templates[x.suiteId]._props.Side.includes(pmcData.Info.Side));
|
||||
const matchedSuits = matchingSuits?.filter((x) => templates[x.suiteId]._props.Side.includes(pmcData.Info.Side));
|
||||
if (matchingSuits === undefined)
|
||||
throw new Error(`Unable to get trader suits for trader ${traderID}`);
|
||||
return matchedSuits!;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,7 +64,7 @@ export class CustomizationController
|
||||
for (const suitId of wearClothingRequest.suites)
|
||||
{
|
||||
// Find desired clothing item in db
|
||||
const dbSuit = this.databaseServer.getTables().templates.customization[suitId];
|
||||
const dbSuit = this.databaseServer.getTables().templates!.customization[suitId];
|
||||
|
||||
// Legs
|
||||
if (dbSuit._parent === this.clothingIds.lowerParentId)
|
||||
@ -110,7 +113,7 @@ export class CustomizationController
|
||||
const suitId = traderOffer.suiteId;
|
||||
if (this.outfitAlreadyPurchased(suitId, sessionId))
|
||||
{
|
||||
const suitDetails = db.templates.customization[suitId];
|
||||
const suitDetails = db.templates!.customization[suitId];
|
||||
this.logger.error(
|
||||
this.localisationService.getText("customisation-item_already_purchased", {
|
||||
itemId: suitDetails._id,
|
||||
@ -132,7 +135,12 @@ export class CustomizationController
|
||||
|
||||
protected getTraderClothingOffer(sessionId: string, offerId: string): ISuit
|
||||
{
|
||||
return this.getAllTraderSuits(sessionId).find((x) => x._id === offerId);
|
||||
const foundSuit = this.getAllTraderSuits(sessionId).find((x) => x._id === offerId);
|
||||
if (foundSuit === undefined)
|
||||
{
|
||||
throw new Error(`Unable to find suit with offer id ${offerId}`);
|
||||
}
|
||||
return foundSuit;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,6 +207,11 @@ export class CustomizationController
|
||||
pmcData.Inventory.items.splice(pmcData.Inventory.items.indexOf(relatedItem), 1);
|
||||
}
|
||||
|
||||
if (!relatedItem.upd || !relatedItem.upd.StackObjectsCount)
|
||||
{
|
||||
throw new Error(`Suit with tpl id ${relatedItem._tpl} does not have upd or stack object count properties`);
|
||||
}
|
||||
|
||||
if (relatedItem.upd.StackObjectsCount > clothingItem.count)
|
||||
{
|
||||
relatedItem.upd.StackObjectsCount -= clothingItem.count;
|
||||
|
@ -37,14 +37,12 @@ export class DialogueController
|
||||
// if give command is disabled or commando commands are disabled
|
||||
if (!coreConfigs.features?.chatbotFeatures?.commandoEnabled)
|
||||
{
|
||||
const sptCommando = this.dialogueChatBots.find(
|
||||
(c) => c.getChatBot()._id.toLocaleLowerCase() === "sptcommando",
|
||||
);
|
||||
const sptCommando = this.dialogueChatBots.find((c) => c.getChatBot()._id.toLocaleLowerCase() === "sptcommando")!;
|
||||
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptCommando), 1);
|
||||
}
|
||||
if (!coreConfigs.features?.chatbotFeatures?.sptFriendEnabled)
|
||||
{
|
||||
const sptFriend = this.dialogueChatBots.find((c) => c.getChatBot()._id.toLocaleLowerCase() === "sptFriend");
|
||||
const sptFriend = this.dialogueChatBots.find((c) => c.getChatBot()._id.toLocaleLowerCase() === "sptFriend")!;
|
||||
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptFriend), 1);
|
||||
}
|
||||
}
|
||||
@ -128,7 +126,7 @@ export class DialogueController
|
||||
* @param sessionID Player id
|
||||
* @returns IUserDialogInfo array
|
||||
*/
|
||||
public getDialogueUsers(dialog: Dialogue, messageType: MessageType, sessionID: string): IUserDialogInfo[]
|
||||
public getDialogueUsers(dialog: Dialogue, messageType: MessageType, sessionID: string): IUserDialogInfo[] | undefined
|
||||
{
|
||||
const profile = this.saveServer.getProfile(sessionID);
|
||||
|
||||
@ -214,7 +212,11 @@ export class DialogueController
|
||||
const chatBot = this.dialogueChatBots.find((cb) => cb.getChatBot()._id === request.dialogId);
|
||||
if (chatBot)
|
||||
{
|
||||
profile.dialogues[request.dialogId].Users.push(chatBot.getChatBot());
|
||||
if (!profile.dialogues[request.dialogId].Users)
|
||||
{
|
||||
profile.dialogues[request.dialogId].Users = [];
|
||||
}
|
||||
profile.dialogues[request.dialogId].Users!.push(chatBot.getChatBot());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -228,7 +230,7 @@ export class DialogueController
|
||||
* @param dialogUsers The participants of the mail
|
||||
* @returns IUserDialogInfo array
|
||||
*/
|
||||
protected getProfilesForMail(fullProfile: ISptProfile, dialogUsers: IUserDialogInfo[]): IUserDialogInfo[]
|
||||
protected getProfilesForMail(fullProfile: ISptProfile, dialogUsers?: IUserDialogInfo[]): IUserDialogInfo[]
|
||||
{
|
||||
const result: IUserDialogInfo[] = [];
|
||||
if (dialogUsers)
|
||||
@ -283,7 +285,7 @@ export class DialogueController
|
||||
*/
|
||||
protected messagesHaveUncollectedRewards(messages: Message[]): boolean
|
||||
{
|
||||
return messages.some((message) => message.items?.data?.length > 0);
|
||||
return messages.some((message) => (message.items?.data?.length ?? 0) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -350,7 +352,7 @@ export class DialogueController
|
||||
* @param sessionId Session id
|
||||
* @returns IGetAllAttachmentsResponse
|
||||
*/
|
||||
public getAllAttachments(dialogueId: string, sessionId: string): IGetAllAttachmentsResponse
|
||||
public getAllAttachments(dialogueId: string, sessionId: string): IGetAllAttachmentsResponse | undefined
|
||||
{
|
||||
const dialogs = this.dialogueHelper.getDialogsForProfile(sessionId);
|
||||
const dialog = dialogs[dialogueId];
|
||||
@ -358,7 +360,7 @@ export class DialogueController
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("dialogue-unable_to_find_in_profile", { sessionId: sessionId, dialogueId: dialogueId }));
|
||||
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Removes corner 'new messages' tag
|
||||
@ -397,7 +399,7 @@ export class DialogueController
|
||||
{
|
||||
const timeNow = this.timeUtil.getTimestamp();
|
||||
const dialogs = this.dialogueHelper.getDialogsForProfile(sessionId);
|
||||
return dialogs[dialogueId].messages.filter((message) => timeNow < message.dt + message.maxStorageTime);
|
||||
return dialogs[dialogueId].messages.filter((message) => timeNow < message.dt + (message.maxStorageTime ?? 0));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -407,7 +409,7 @@ export class DialogueController
|
||||
*/
|
||||
protected getMessagesWithAttachments(messages: Message[]): Message[]
|
||||
{
|
||||
return messages.filter((message) => message.items?.data?.length > 0);
|
||||
return messages.filter((message) => (message.items?.data?.length ?? 0) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -452,7 +454,7 @@ export class DialogueController
|
||||
*/
|
||||
protected messageHasExpired(message: Message): boolean
|
||||
{
|
||||
return this.timeUtil.getTimestamp() > message.dt + message.maxStorageTime;
|
||||
return this.timeUtil.getTimestamp() > message.dt + (message.maxStorageTime ?? 0);
|
||||
}
|
||||
|
||||
/** Handle client/friend/request/send */
|
||||
|
@ -264,7 +264,7 @@ export class GameController
|
||||
return;
|
||||
}
|
||||
|
||||
for (const craft of this.databaseServer.getTables().hideout.production)
|
||||
for (const craft of this.databaseServer.getTables().hideout!.production)
|
||||
{
|
||||
// Only adjust crafts ABOVE the override
|
||||
if (craft.productionTime > craftTimeOverrideSeconds)
|
||||
@ -282,7 +282,7 @@ export class GameController
|
||||
return;
|
||||
}
|
||||
|
||||
for (const area of this.databaseServer.getTables().hideout.areas)
|
||||
for (const area of this.databaseServer.getTables().hideout!.areas)
|
||||
{
|
||||
for (const stageKey of Object.keys(area.stages))
|
||||
{
|
||||
@ -298,7 +298,7 @@ export class GameController
|
||||
|
||||
protected adjustLocationBotValues(): void
|
||||
{
|
||||
const mapsDb = this.databaseServer.getTables().locations;
|
||||
const mapsDb = this.databaseServer.getTables().locations!;
|
||||
|
||||
for (const locationKey in this.botConfig.maxBotCap)
|
||||
{
|
||||
@ -322,12 +322,12 @@ export class GameController
|
||||
{
|
||||
for (const traderKey in this.databaseServer.getTables().traders)
|
||||
{
|
||||
const trader = this.databaseServer.getTables().traders[traderKey];
|
||||
const trader = this.databaseServer.getTables().traders![traderKey];
|
||||
if (!trader?.base?.repair)
|
||||
{
|
||||
this.logger.warning(this.localisationService.getText("trader-missing_repair_property_using_default",
|
||||
{ traderId: trader.base._id, nickname: trader.base.nickname }));
|
||||
trader.base.repair = this.cloner.clone(this.databaseServer.getTables().traders.ragfair.base.repair);
|
||||
trader.base.repair = this.cloner.clone(this.databaseServer.getTables().traders!.ragfair.base.repair);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -337,9 +337,9 @@ export class GameController
|
||||
this.logger.warning(this.localisationService.getText("trader-missing_repair_quality_property_using_default",
|
||||
{ traderId: trader.base._id, nickname: trader.base.nickname }));
|
||||
trader.base.repair.quality = this.cloner.clone(
|
||||
this.databaseServer.getTables().traders.ragfair.base.repair.quality,
|
||||
this.databaseServer.getTables().traders!.ragfair.base.repair.quality,
|
||||
);
|
||||
trader.base.repair.quality = this.databaseServer.getTables().traders.ragfair.base.repair.quality;
|
||||
trader.base.repair.quality = this.databaseServer.getTables().traders!.ragfair.base.repair.quality;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -356,7 +356,7 @@ export class GameController
|
||||
continue;
|
||||
}
|
||||
|
||||
const mapLooseLoot: ILooseLoot = this.databaseServer.getTables().locations[mapId]?.looseLoot;
|
||||
const mapLooseLoot: ILooseLoot = this.databaseServer.getTables().locations![mapId]?.looseLoot;
|
||||
if (!mapLooseLoot)
|
||||
{
|
||||
this.logger.warning(this.localisationService.getText("location-map_has_no_loose_loot_data", mapId));
|
||||
@ -391,7 +391,7 @@ export class GameController
|
||||
const adjustments = this.lootConfig.looseLootSpawnPointAdjustments;
|
||||
for (const mapId in adjustments)
|
||||
{
|
||||
const mapLooseLootData: ILooseLoot = this.databaseServer.getTables().locations[mapId]?.looseLoot;
|
||||
const mapLooseLootData: ILooseLoot = this.databaseServer.getTables().locations![mapId]?.looseLoot;
|
||||
if (!mapLooseLootData)
|
||||
{
|
||||
this.logger.warning(this.localisationService.getText("location-map_has_no_loose_loot_data", mapId));
|
||||
@ -418,7 +418,7 @@ export class GameController
|
||||
/** Apply custom limits on bot types as defined in configs/location.json/botTypeLimits */
|
||||
protected adjustMapBotLimits(): void
|
||||
{
|
||||
const mapsDb = this.databaseServer.getTables().locations;
|
||||
const mapsDb = this.databaseServer.getTables().locations!;
|
||||
if (!this.locationConfig.botTypeLimits)
|
||||
{
|
||||
return;
|
||||
@ -470,7 +470,7 @@ export class GameController
|
||||
)?.Value ?? 0;
|
||||
|
||||
const config: IGameConfigResponse = {
|
||||
languages: this.databaseServer.getTables().locales.languages,
|
||||
languages: this.databaseServer.getTables().locales!.languages,
|
||||
ndaFree: false,
|
||||
reportAvailable: false,
|
||||
twitchEventMember: false,
|
||||
@ -552,7 +552,7 @@ export class GameController
|
||||
*/
|
||||
protected fixShotgunDispersions(): void
|
||||
{
|
||||
const itemDb = this.databaseServer.getTables().templates.items;
|
||||
const itemDb = this.databaseServer.getTables().templates!.items;
|
||||
|
||||
// Saiga 12ga
|
||||
// Toz 106
|
||||
@ -582,7 +582,7 @@ export class GameController
|
||||
|
||||
protected flagAllItemsInDbAsSellableOnFlea(): void
|
||||
{
|
||||
const dbItems = Object.values(this.databaseServer.getTables().templates.items);
|
||||
const dbItems = Object.values(this.databaseServer.getTables().templates!.items);
|
||||
for (const item of dbItems)
|
||||
{
|
||||
if (item._type === "Item" && !item._props?.CanSellOnRagfair)
|
||||
@ -613,12 +613,12 @@ export class GameController
|
||||
// Set new values, whatever is smallest
|
||||
energyRegenPerHour += pmcProfile.Bonuses.filter(
|
||||
(bonus) => bonus.type === BonusType.ENERGY_REGENERATION,
|
||||
).reduce((sum, curr) => sum + curr.value, 0);
|
||||
).reduce((sum, curr) => sum + (curr.value ?? 0), 0);
|
||||
hydrationRegenPerHour += pmcProfile.Bonuses.filter(
|
||||
(bonus) => bonus.type === BonusType.HYDRATION_REGENERATION,
|
||||
).reduce((sum, curr) => sum + curr.value, 0);
|
||||
).reduce((sum, curr) => sum + (curr.value ?? 0), 0);
|
||||
hpRegenPerHour += pmcProfile.Bonuses.filter((bonus) => bonus.type === BonusType.HEALTH_REGENERATION).reduce(
|
||||
(sum, curr) => sum + curr.value,
|
||||
(sum, curr) => sum + (curr.value ?? 0),
|
||||
0,
|
||||
);
|
||||
|
||||
@ -703,7 +703,7 @@ export class GameController
|
||||
}
|
||||
|
||||
// Loop over all of the locations waves and look for waves with identical min and max slots
|
||||
const location: ILocation = this.databaseServer.getTables().locations[locationKey];
|
||||
const location: ILocation = this.databaseServer.getTables().locations![locationKey];
|
||||
if (!location.base)
|
||||
{
|
||||
this.logger.warning(
|
||||
@ -730,7 +730,7 @@ export class GameController
|
||||
*/
|
||||
protected fixRoguesSpawningInstantlyOnLighthouse(): void
|
||||
{
|
||||
const lighthouse = this.databaseServer.getTables().locations.lighthouse.base;
|
||||
const lighthouse = this.databaseServer.getTables().locations!.lighthouse!.base;
|
||||
for (const wave of lighthouse.BossLocationSpawn)
|
||||
{
|
||||
// Find Rogues that spawn instantly
|
||||
@ -778,7 +778,7 @@ export class GameController
|
||||
}
|
||||
|
||||
// Iterate over all maps
|
||||
const location: ILocation = this.databaseServer.getTables().locations[locationKey];
|
||||
const location: ILocation = this.databaseServer.getTables().locations![locationKey];
|
||||
for (const wave of location.base.waves)
|
||||
{
|
||||
// Wave has size that makes it candidate for splitting
|
||||
@ -883,8 +883,8 @@ export class GameController
|
||||
protected validateQuestAssortUnlocksExist(): void
|
||||
{
|
||||
const db = this.databaseServer.getTables();
|
||||
const traders = db.traders;
|
||||
const quests = db.templates.quests;
|
||||
const traders = db.traders!;
|
||||
const quests = db.templates!.quests;
|
||||
for (const traderId of Object.values(Traders))
|
||||
{
|
||||
const traderData = traders[traderId];
|
||||
@ -896,9 +896,9 @@ export class GameController
|
||||
|
||||
// Merge started/success/fail quest assorts into one dictionary
|
||||
const mergedQuestAssorts = {
|
||||
...traderData.questassort.started,
|
||||
...traderData.questassort.success,
|
||||
...traderData.questassort.fail,
|
||||
...traderData.questassort?.started,
|
||||
...traderData.questassort?.success,
|
||||
...traderData.questassort?.fail,
|
||||
};
|
||||
|
||||
// Loop over all assorts for trader
|
||||
@ -929,7 +929,7 @@ export class GameController
|
||||
const playerName = pmcProfile.Info.Nickname;
|
||||
if (playerName)
|
||||
{
|
||||
const bots = this.databaseServer.getTables().bots.types;
|
||||
const bots = this.databaseServer.getTables().bots!.types;
|
||||
|
||||
if (bots.bear)
|
||||
{
|
||||
@ -962,9 +962,9 @@ export class GameController
|
||||
protected removePraporTestMessage(): void
|
||||
{
|
||||
// Iterate over all languages (e.g. "en", "fr")
|
||||
for (const localeKey in this.databaseServer.getTables().locales.global)
|
||||
for (const localeKey in this.databaseServer.getTables().locales!.global)
|
||||
{
|
||||
this.databaseServer.getTables().locales.global[localeKey]["61687e2c3e526901fa76baf9"] = "";
|
||||
this.databaseServer.getTables().locales!.global[localeKey]["61687e2c3e526901fa76baf9"] = "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -973,7 +973,7 @@ export class GameController
|
||||
*/
|
||||
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) => x.TriggerId === "" && x.TriggerName === "",
|
||||
);
|
||||
|
@ -7,6 +7,7 @@ import { BanType } from "@spt/models/eft/common/tables/IBotBase";
|
||||
import { Item } from "@spt/models/eft/common/tables/IItem";
|
||||
import { ProfileTraderTemplate } from "@spt/models/eft/common/tables/IProfileTemplate";
|
||||
import { ITraderAssort, ITraderBase, LoyaltyLevel } from "@spt/models/eft/common/tables/ITrader";
|
||||
import { ISptProfile } from "@spt/models/eft/profile/ISptProfile";
|
||||
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
||||
import { Money } from "@spt/models/enums/Money";
|
||||
import { Traders } from "@spt/models/enums/Traders";
|
||||
@ -15,7 +16,6 @@ import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt/servers/ConfigServer";
|
||||
import { DatabaseServer } from "@spt/servers/DatabaseServer";
|
||||
import { FenceService } from "@spt/services/FenceService";
|
||||
import { ISptProfile } from "@spt/models/eft/profile/ISptProfile";
|
||||
import { LocalisationService } from "@spt/services/LocalisationService";
|
||||
import { PlayerService } from "@spt/services/PlayerService";
|
||||
import { RandomUtil } from "@spt/utils/RandomUtil";
|
||||
@ -26,9 +26,9 @@ export class TraderHelper
|
||||
{
|
||||
protected traderConfig: ITraderConfig;
|
||||
/** Dictionary of item tpl and the highest trader sell rouble price */
|
||||
protected highestTraderPriceItems: Record<string, number> = null;
|
||||
protected highestTraderPriceItems?: Record<string, number> = undefined;
|
||||
/** Dictionary of item tpl and the highest trader buy back rouble price */
|
||||
protected highestTraderBuyPriceItems: Record<string, number> = null;
|
||||
protected highestTraderBuyPriceItems?: Record<string, number> = undefined;
|
||||
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@ -54,7 +54,7 @@ export class TraderHelper
|
||||
* @param sessionID Players id
|
||||
* @returns Trader base
|
||||
*/
|
||||
public getTrader(traderID: string, sessionID: string): ITraderBase
|
||||
public getTrader(traderID: string, sessionID: string): ITraderBase | undefined
|
||||
{
|
||||
const pmcData = this.profileHelper.getPmcProfile(sessionID);
|
||||
if (!pmcData)
|
||||
@ -88,7 +88,7 @@ export class TraderHelper
|
||||
{
|
||||
return traderId === Traders.FENCE
|
||||
? this.fenceService.getRawFenceAssorts()
|
||||
: this.databaseServer.getTables().traders[traderId].assort;
|
||||
: this.databaseServer.getTables().traders![traderId].assort!;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,14 +97,14 @@ export class TraderHelper
|
||||
* @param assortId Id of assort to find
|
||||
* @returns Item object
|
||||
*/
|
||||
public getTraderAssortItemByAssortId(traderId: string, assortId: string): Item
|
||||
public getTraderAssortItemByAssortId(traderId: string, assortId: string): Item | undefined
|
||||
{
|
||||
const traderAssorts = this.getTraderAssortsByTraderId(traderId);
|
||||
if (!traderAssorts)
|
||||
{
|
||||
this.logger.debug(`No assorts on trader: ${traderId} found`);
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Find specific assort in traders data
|
||||
@ -113,7 +113,7 @@ export class TraderHelper
|
||||
{
|
||||
this.logger.debug(`No assort ${assortId} on trader: ${traderId} found`);
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return purchasedAssort;
|
||||
@ -131,7 +131,7 @@ export class TraderHelper
|
||||
const fullProfile = this.profileHelper.getFullProfile(sessionID);
|
||||
const pmcData = fullProfile.characters.pmc;
|
||||
const rawProfileTemplate: ProfileTraderTemplate
|
||||
= db.templates.profiles[fullProfile.info.edition][pmcData.Info.Side.toLowerCase()]
|
||||
= db.templates!.profiles[fullProfile.info.edition][pmcData.Info.Side.toLowerCase()]
|
||||
.trader;
|
||||
|
||||
pmcData.TradersInfo[traderID] = {
|
||||
@ -139,8 +139,8 @@ export class TraderHelper
|
||||
loyaltyLevel: rawProfileTemplate.initialLoyaltyLevel[traderID] ?? 1,
|
||||
salesSum: rawProfileTemplate.initialSalesSum,
|
||||
standing: this.getStartingStanding(traderID, rawProfileTemplate),
|
||||
nextResupply: db.traders[traderID].base.nextResupply,
|
||||
unlocked: db.traders[traderID].base.unlockedByDefault,
|
||||
nextResupply: db.traders![traderID].base.nextResupply,
|
||||
unlocked: db.traders![traderID].base.unlockedByDefault,
|
||||
};
|
||||
|
||||
// Check if trader should be locked by default
|
||||
@ -149,19 +149,18 @@ export class TraderHelper
|
||||
pmcData.TradersInfo[traderID].unlocked = false;
|
||||
}
|
||||
|
||||
if (rawProfileTemplate.purchaseAlllClothingByDefaultForTrader?.includes(traderID))
|
||||
{
|
||||
//Get traders clothing
|
||||
const clothing = this.databaseServer.getTables().traders[traderID].suits;
|
||||
|
||||
// Force suit ids into profile
|
||||
this.addSuitsToProfile(fullProfile, clothing.map(x => x.suiteId));
|
||||
|
||||
}
|
||||
|
||||
if (rawProfileTemplate.fleaBlockedDays > 0)
|
||||
if (rawProfileTemplate.purchaseAllClothingByDefaultForTrader?.includes(traderID))
|
||||
{
|
||||
const newBanDateTime = this.timeUtil.getTimeStampFromNowDays(rawProfileTemplate.fleaBlockedDays);
|
||||
// Get traders clothing
|
||||
const clothing = this.databaseServer.getTables().traders![traderID].suits!;
|
||||
|
||||
// Force suit ids into profile
|
||||
this.addSuitsToProfile(fullProfile, clothing.map((x) => x.suiteId));
|
||||
}
|
||||
|
||||
if ((rawProfileTemplate.fleaBlockedDays ?? 0) > 0)
|
||||
{
|
||||
const newBanDateTime = this.timeUtil.getTimeStampFromNowDays(rawProfileTemplate.fleaBlockedDays!);
|
||||
const existingBan = pmcData.Info.Bans.find((ban) => ban.banType === BanType.RAGFAIR);
|
||||
if (existingBan)
|
||||
{
|
||||
@ -278,7 +277,7 @@ export class TraderHelper
|
||||
public validateTraderStandingsAndPlayerLevelForProfile(sessionId: string): void
|
||||
{
|
||||
const profile = this.profileHelper.getPmcProfile(sessionId);
|
||||
const traders = Object.keys(this.databaseServer.getTables().traders);
|
||||
const traders = Object.keys(this.databaseServer.getTables().traders!);
|
||||
for (const trader of traders)
|
||||
{
|
||||
this.lvlUp(trader, profile);
|
||||
@ -293,7 +292,7 @@ export class TraderHelper
|
||||
*/
|
||||
public lvlUp(traderID: string, pmcData: IPmcData): void
|
||||
{
|
||||
const loyaltyLevels = this.databaseServer.getTables().traders[traderID].base.loyaltyLevels;
|
||||
const loyaltyLevels = this.databaseServer.getTables().traders![traderID].base.loyaltyLevels;
|
||||
|
||||
// Level up player
|
||||
pmcData.Info.Level = this.playerService.calculateLevel(pmcData);
|
||||
@ -332,7 +331,7 @@ export class TraderHelper
|
||||
public getNextUpdateTimestamp(traderID: string): number
|
||||
{
|
||||
const time = this.timeUtil.getTimestamp();
|
||||
const updateSeconds = this.getTraderUpdateSeconds(traderID);
|
||||
const updateSeconds = this.getTraderUpdateSeconds(traderID) ?? 0;
|
||||
return time + updateSeconds;
|
||||
}
|
||||
|
||||
@ -341,7 +340,7 @@ export class TraderHelper
|
||||
* @param traderId Trader to look up
|
||||
* @returns Time in seconds
|
||||
*/
|
||||
public getTraderUpdateSeconds(traderId: string): number
|
||||
public getTraderUpdateSeconds(traderId: string): number | undefined
|
||||
{
|
||||
const traderDetails = this.traderConfig.updateTime.find((x) => x.traderId === traderId);
|
||||
if (!traderDetails || traderDetails.seconds.min === undefined || traderDetails.seconds.max === undefined)
|
||||
@ -360,6 +359,7 @@ export class TraderHelper
|
||||
seconds: { min: this.traderConfig.updateTimeDefault, max: this.traderConfig.updateTimeDefault },
|
||||
},
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -369,7 +369,7 @@ export class TraderHelper
|
||||
|
||||
public getLoyaltyLevel(traderID: string, pmcData: IPmcData): LoyaltyLevel
|
||||
{
|
||||
const trader = this.databaseServer.getTables().traders[traderID].base;
|
||||
const trader = this.databaseServer.getTables().traders![traderID].base;
|
||||
let loyaltyLevel = pmcData.TradersInfo[traderID].loyaltyLevel;
|
||||
|
||||
if (!loyaltyLevel || loyaltyLevel < 1)
|
||||
@ -426,14 +426,14 @@ export class TraderHelper
|
||||
|
||||
if (
|
||||
profile.traderPurchases[traderId][purchasedItem.itemId].count + purchasedItem.count
|
||||
> itemPurchased.upd.BuyRestrictionMax
|
||||
> itemPurchased.upd!.BuyRestrictionMax!
|
||||
)
|
||||
{
|
||||
throw new Error(
|
||||
this.localisationService.getText("trader-unable_to_purchase_item_limit_reached",
|
||||
{
|
||||
traderId: traderId,
|
||||
limit: itemPurchased.upd.BuyRestrictionMax,
|
||||
limit: itemPurchased.upd!.BuyRestrictionMax,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -470,7 +470,7 @@ export class TraderHelper
|
||||
}
|
||||
|
||||
// Get assorts for trader, skip trader if no assorts found
|
||||
const traderAssorts = this.databaseServer.getTables().traders[Traders[traderName]].assort;
|
||||
const traderAssorts = this.databaseServer.getTables().traders![Traders[traderName]].assort;
|
||||
if (!traderAssorts)
|
||||
{
|
||||
continue;
|
||||
@ -522,7 +522,7 @@ export class TraderHelper
|
||||
for (const traderName in Traders)
|
||||
{
|
||||
// Get trader and check buy category allows tpl
|
||||
const traderBase = this.databaseServer.getTables().traders[Traders[traderName]]?.base;
|
||||
const traderBase = this.databaseServer.getTables().traders![Traders[traderName]]?.base;
|
||||
if (traderBase && this.itemHelper.isOfBaseclasses(tpl, traderBase.items_buy.category))
|
||||
{
|
||||
// Get loyalty level details player has achieved with this trader
|
||||
@ -557,7 +557,7 @@ export class TraderHelper
|
||||
* @param traderId Traders id
|
||||
* @returns Traders key
|
||||
*/
|
||||
public getTraderById(traderId: string): Traders
|
||||
public getTraderById(traderId: string): Traders | undefined
|
||||
{
|
||||
const keys = Object.keys(Traders).filter((x) => Traders[x] === traderId);
|
||||
|
||||
@ -565,7 +565,7 @@ export class TraderHelper
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("trader-unable_to_find_trader_in_enum", traderId));
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return keys[0] as Traders;
|
||||
|
@ -202,7 +202,7 @@ export interface Mastering extends IBaseSkill
|
||||
|
||||
export interface Stats
|
||||
{
|
||||
Eft: IEftStats
|
||||
Eft?: IEftStats
|
||||
}
|
||||
|
||||
export interface IEftStats
|
||||
|
@ -45,5 +45,5 @@ export interface ProfileTraderTemplate
|
||||
/** What traders default to being locked on profile creation */
|
||||
lockedByDefaultOverride?: string[]
|
||||
/** What traders should have their clothing unlocked/purchased on creation */
|
||||
purchaseAlllClothingByDefaultForTrader?: string[]
|
||||
purchaseAllClothingByDefaultForTrader?: string[]
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
export interface IGetRaidTimeResponse
|
||||
{
|
||||
RaidTimeMinutes: number
|
||||
NewSurviveTimeSeconds: number
|
||||
NewSurviveTimeSeconds?: number
|
||||
OriginalSurvivalTimeSeconds: number
|
||||
ExitChanges: ExtractChange[]
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ export interface IAddItemsDirectRequest
|
||||
itemsWithModsToAdd: Item[][]
|
||||
foundInRaid: boolean
|
||||
/** Runs after EACH item with children is added */
|
||||
callback: (buyCount: number) => void
|
||||
callback?: (buyCount: number) => void
|
||||
/** Should sorting table be used when no space found in stash */
|
||||
useSortingTable: boolean
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ export interface IUserDialogInfo
|
||||
{
|
||||
_id: string
|
||||
aid: number
|
||||
Info: IUserDialogDetails
|
||||
Info?: IUserDialogDetails
|
||||
}
|
||||
|
||||
export interface IUserDialogDetails
|
||||
|
@ -110,7 +110,7 @@ export class GiftService
|
||||
{
|
||||
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
||||
playerId,
|
||||
giftData.trader,
|
||||
giftData.trader!,
|
||||
MessageType.MESSAGE_WITH_ITEMS,
|
||||
giftData.localeTextId,
|
||||
giftData.items,
|
||||
@ -121,7 +121,7 @@ export class GiftService
|
||||
{
|
||||
this.mailSendService.sendDirectNpcMessageToPlayer(
|
||||
playerId,
|
||||
giftData.trader,
|
||||
giftData.trader!,
|
||||
MessageType.MESSAGE_WITH_ITEMS,
|
||||
giftData.messageText,
|
||||
giftData.items,
|
||||
@ -135,11 +135,11 @@ export class GiftService
|
||||
// Trader / ragfair
|
||||
const details: ISendMessageDetails = {
|
||||
recipientId: playerId,
|
||||
sender: this.getMessageType(giftData),
|
||||
sender: this.getMessageType(giftData)!,
|
||||
senderDetails: {
|
||||
_id: this.getSenderId(giftData),
|
||||
_id: this.getSenderId(giftData)!,
|
||||
aid: 1234567, // TODO - pass proper aid value
|
||||
Info: null,
|
||||
Info: undefined,
|
||||
},
|
||||
messageText: giftData.messageText,
|
||||
items: giftData.items,
|
||||
@ -164,11 +164,11 @@ export class GiftService
|
||||
* @param giftData Gift to send player
|
||||
* @returns trader/user/system id
|
||||
*/
|
||||
protected getSenderId(giftData: Gift): string
|
||||
protected getSenderId(giftData: Gift): string | undefined
|
||||
{
|
||||
if (giftData.sender === GiftSenderType.TRADER)
|
||||
{
|
||||
return Traders[giftData.trader];
|
||||
return Traders[giftData.trader!];
|
||||
}
|
||||
|
||||
if (giftData.sender === GiftSenderType.USER)
|
||||
@ -182,7 +182,7 @@ export class GiftService
|
||||
* @param giftData Gift to send player
|
||||
* @returns MessageType enum value
|
||||
*/
|
||||
protected getMessageType(giftData: Gift): MessageType
|
||||
protected getMessageType(giftData: Gift): MessageType | undefined
|
||||
{
|
||||
switch (giftData.sender)
|
||||
{
|
||||
|
@ -109,28 +109,42 @@ export class InsuranceService
|
||||
for (const traderId in this.getInsurance(sessionID))
|
||||
{
|
||||
const traderBase = this.traderHelper.getTrader(traderId, sessionID);
|
||||
if (!traderBase)
|
||||
{
|
||||
throw new Error(`The trader id ${traderId} was not found!`);
|
||||
}
|
||||
let insuranceReturnTimestamp = this.getInsuranceReturnTimestamp(pmcData, traderBase);
|
||||
if (markOfTheUnheardOnPlayer)
|
||||
{
|
||||
insuranceReturnTimestamp *= this.databaseServer.getTables()
|
||||
.globals.config.Insurance.CoefOfHavingMarkOfUnknown;
|
||||
.globals!.config.Insurance.CoefOfHavingMarkOfUnknown;
|
||||
}
|
||||
const dialogueTemplates = this.databaseServer.getTables().traders![traderId].dialogue;
|
||||
|
||||
if (!dialogueTemplates)
|
||||
{
|
||||
throw new Error(`The trader id ${traderId} does not have dialogues for insurance`);
|
||||
}
|
||||
const dialogueTemplates = this.databaseServer.getTables().traders[traderId].dialogue;
|
||||
|
||||
const systemData = {
|
||||
date: this.timeUtil.getDateMailFormat(),
|
||||
time: this.timeUtil.getTimeMailFormat(),
|
||||
location: mapId,
|
||||
};
|
||||
const traderEnum = this.traderHelper.getTraderById(traderId);
|
||||
if (!traderEnum)
|
||||
{
|
||||
throw new Error(`The trader id ${traderId} is missing from Traders enum`);
|
||||
}
|
||||
// Send "i will go look for your stuff" message from trader to player
|
||||
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
||||
sessionID,
|
||||
this.traderHelper.getTraderById(traderId),
|
||||
traderEnum,
|
||||
MessageType.NPC_TRADER,
|
||||
this.randomUtil.getArrayValue(dialogueTemplates.insuranceStart),
|
||||
null,
|
||||
this.randomUtil.getArrayValue(dialogueTemplates?.insuranceStart),
|
||||
undefined,
|
||||
this.timeUtil.getHoursAsSeconds(
|
||||
this.databaseServer.getTables().globals.config.Insurance.MaxStorageTimeInHour,
|
||||
this.databaseServer.getTables().globals!.config.Insurance.MaxStorageTimeInHour,
|
||||
),
|
||||
systemData,
|
||||
);
|
||||
@ -192,7 +206,7 @@ export class InsuranceService
|
||||
|
||||
const insuranceReturnTimeBonus = pmcData.Bonuses.find((b) => b.type === BonusType.INSURANCE_RETURN_TIME);
|
||||
const insuranceReturnTimeBonusPercent
|
||||
= 1.0 - (insuranceReturnTimeBonus ? Math.abs(insuranceReturnTimeBonus.value) : 0) / 100;
|
||||
= 1.0 - (insuranceReturnTimeBonus ? Math.abs(insuranceReturnTimeBonus!.value ?? 0) : 0) / 100;
|
||||
|
||||
const traderMinReturnAsSeconds = trader.insurance.min_return_hour * TimeUtil.ONE_HOUR_AS_SECONDS;
|
||||
const traderMaxReturnAsSeconds = trader.insurance.max_return_hour * TimeUtil.ONE_HOUR_AS_SECONDS;
|
||||
@ -238,10 +252,10 @@ export class InsuranceService
|
||||
continue;
|
||||
}
|
||||
|
||||
const preRaidItem = preRaidGearMap.get(insuredItem.itemId);
|
||||
const preRaidItem = preRaidGearMap.get(insuredItem.itemId)!;
|
||||
|
||||
// Skip slots we should never return as they're never lost on death
|
||||
if (this.insuranceConfig.blacklistedEquipment.includes(preRaidItem.slotId))
|
||||
if (this.insuranceConfig.blacklistedEquipment.includes(preRaidItem.slotId!))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -261,7 +275,9 @@ export class InsuranceService
|
||||
|
||||
// Now that we have the equipment parent item, we can check to see if that item is located in an equipment
|
||||
// slot that is flagged as lost on death. If it is, then the itemShouldBeLostOnDeath.
|
||||
const itemShouldBeLostOnDeath = this.lostOnDeathConfig.equipment[equipmentParentItem?.slotId] ?? true;
|
||||
const itemShouldBeLostOnDeath = equipmentParentItem?.slotId
|
||||
? this.lostOnDeathConfig.equipment[equipmentParentItem?.slotId] ?? true
|
||||
: true;
|
||||
|
||||
// Was the item found in the player inventory post-raid?
|
||||
const itemOnPlayerPostRaid = offRaidGearMap.has(insuredItem.itemId);
|
||||
@ -270,12 +286,18 @@ export class InsuranceService
|
||||
// Catches both events: player died with item on + player survived but dropped item in raid
|
||||
if (!itemOnPlayerPostRaid || (playerDied && itemShouldBeLostOnDeath))
|
||||
{
|
||||
const inventoryInsuredItem = offraidData.insurance
|
||||
?.find((insuranceItem) => insuranceItem.id === insuredItem.itemId);
|
||||
if (!inventoryInsuredItem)
|
||||
{
|
||||
throw new Error(`Inventory insured item id ${insuredItem.itemId} was not found`);
|
||||
}
|
||||
equipmentPkg.push({
|
||||
pmcData: pmcData,
|
||||
itemToReturnToPlayer: this.getInsuredItemDetails(
|
||||
pmcData,
|
||||
preRaidItem,
|
||||
offraidData.insurance?.find((insuranceItem) => insuranceItem.id === insuredItem.itemId),
|
||||
inventoryInsuredItem,
|
||||
),
|
||||
traderId: insuredItem.tid,
|
||||
sessionID: sessionID,
|
||||
@ -291,21 +313,31 @@ export class InsuranceService
|
||||
.filter(
|
||||
(item) =>
|
||||
item.parentId === preRaidItem._id
|
||||
&& this.itemHelper.getSoftInsertSlotIds().includes(item.slotId.toLowerCase()),
|
||||
&& this.itemHelper.getSoftInsertSlotIds().includes(item.slotId!.toLowerCase()),
|
||||
)
|
||||
.map((x) => x._id);
|
||||
|
||||
// Add all items found above to return data
|
||||
for (const softInsertChildModId of softInsertChildIds)
|
||||
{
|
||||
const preRaidInventoryItem = preRaidGear.find((item) => item._id === softInsertChildModId);
|
||||
if (!preRaidInventoryItem)
|
||||
{
|
||||
throw new Error(`Preraid inventory item ${softInsertChildModId} was not found`);
|
||||
}
|
||||
const inventoryInsuredItem = offraidData.insurance?.find(
|
||||
(insuranceItem) => insuranceItem.id === softInsertChildModId,
|
||||
);
|
||||
if (!inventoryInsuredItem)
|
||||
{
|
||||
throw new Error(`Inventory insured item ${softInsertChildModId} was not found`);
|
||||
}
|
||||
equipmentPkg.push({
|
||||
pmcData: pmcData,
|
||||
itemToReturnToPlayer: this.getInsuredItemDetails(
|
||||
pmcData,
|
||||
preRaidGear.find((item) => item._id === softInsertChildModId),
|
||||
offraidData.insurance?.find(
|
||||
(insuranceItem) => insuranceItem.id === softInsertChildModId,
|
||||
),
|
||||
preRaidInventoryItem,
|
||||
inventoryInsuredItem,
|
||||
),
|
||||
traderId: insuredItem.tid,
|
||||
sessionID: sessionID,
|
||||
@ -381,7 +413,7 @@ export class InsuranceService
|
||||
}
|
||||
|
||||
// Remove found in raid status when upd exists + SpawnedInSession value exists
|
||||
if ("SpawnedInSession" in itemToReturnClone.upd)
|
||||
if ("SpawnedInSession" in itemToReturnClone.upd!)
|
||||
{
|
||||
itemToReturnClone.upd.SpawnedInSession = false;
|
||||
}
|
||||
@ -390,17 +422,17 @@ export class InsuranceService
|
||||
if (insuredItemFromClient?.durability)
|
||||
{
|
||||
// Item didnt have Repairable object pre-raid, add it
|
||||
if (!itemToReturnClone.upd.Repairable)
|
||||
if (!itemToReturnClone.upd?.Repairable)
|
||||
{
|
||||
itemToReturnClone.upd.Repairable = {
|
||||
itemToReturnClone.upd!.Repairable = {
|
||||
Durability: insuredItemFromClient.durability,
|
||||
MaxDurability: insuredItemFromClient.maxDurability,
|
||||
MaxDurability: insuredItemFromClient.maxDurability!,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
itemToReturnClone.upd.Repairable.Durability = insuredItemFromClient.durability;
|
||||
itemToReturnClone.upd.Repairable.MaxDurability = insuredItemFromClient.maxDurability;
|
||||
itemToReturnClone.upd.Repairable.MaxDurability = insuredItemFromClient.maxDurability!;
|
||||
}
|
||||
}
|
||||
|
||||
@ -408,9 +440,9 @@ export class InsuranceService
|
||||
if (insuredItemFromClient?.hits)
|
||||
{
|
||||
// Item didnt have faceshield object pre-raid, add it
|
||||
if (!itemToReturnClone.upd.FaceShield)
|
||||
if (!itemToReturnClone.upd?.FaceShield)
|
||||
{
|
||||
itemToReturnClone.upd.FaceShield = { Hits: insuredItemFromClient.hits };
|
||||
itemToReturnClone.upd!.FaceShield = { Hits: insuredItemFromClient.hits };
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -431,7 +463,7 @@ export class InsuranceService
|
||||
const pocketSlots = ["pocket1", "pocket2", "pocket3", "pocket4"];
|
||||
|
||||
// Some pockets can lose items with player death, some don't
|
||||
if (!("slotId" in itemToReturn) || pocketSlots.includes(itemToReturn.slotId))
|
||||
if (!("slotId" in itemToReturn) || pocketSlots.includes(itemToReturn.slotId!))
|
||||
{
|
||||
itemToReturn.slotId = "hideout";
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ export class ItemBaseClassService
|
||||
// Clear existing cache
|
||||
this.itemBaseClassesCache = {};
|
||||
|
||||
this.items = this.databaseServer.getTables().templates.items;
|
||||
this.items = this.databaseServer.getTables().templates!.items;
|
||||
if (!this.items)
|
||||
{
|
||||
this.logger.warning(this.localisationService.getText("baseclass-missing_db_no_cache"));
|
||||
|
@ -28,7 +28,7 @@ export class LocaleService
|
||||
*/
|
||||
public getLocaleDb(): Record<string, string>
|
||||
{
|
||||
const desiredLocale = this.databaseServer.getTables().locales.global[this.getDesiredGameLocale()];
|
||||
const desiredLocale = this.databaseServer.getTables().locales!.global[this.getDesiredGameLocale()];
|
||||
if (desiredLocale)
|
||||
{
|
||||
return desiredLocale;
|
||||
@ -38,7 +38,7 @@ export class LocaleService
|
||||
`Unable to find desired locale file using locale: ${this.getDesiredGameLocale()} from config/locale.json, falling back to 'en'`,
|
||||
);
|
||||
|
||||
return this.databaseServer.getTables().locales.global.en;
|
||||
return this.databaseServer.getTables().locales!.global.en;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,19 +135,19 @@ export class LocaleService
|
||||
}
|
||||
|
||||
const baseNameCode = platformLocale.baseName?.toLocaleLowerCase();
|
||||
if (baseNameCode && this.databaseServer.getTables().locales.global[baseNameCode])
|
||||
if (baseNameCode && this.databaseServer.getTables().locales!.global[baseNameCode])
|
||||
{
|
||||
return baseNameCode;
|
||||
}
|
||||
|
||||
const languageCode = platformLocale.language?.toLowerCase();
|
||||
if (languageCode && this.databaseServer.getTables().locales.global[languageCode])
|
||||
if (languageCode && this.databaseServer.getTables().locales!.global[languageCode])
|
||||
{
|
||||
return languageCode;
|
||||
}
|
||||
|
||||
const regionCode = platformLocale.region?.toLocaleLowerCase();
|
||||
if (regionCode && this.databaseServer.getTables().locales.global[regionCode])
|
||||
if (regionCode && this.databaseServer.getTables().locales!.global[regionCode])
|
||||
{
|
||||
return regionCode;
|
||||
}
|
||||
|
@ -44,9 +44,9 @@ export class LocalisationService
|
||||
* @param args optional arguments
|
||||
* @returns Localised string
|
||||
*/
|
||||
public getText(key: string, args = undefined): string
|
||||
public getText(key: string, args?: any): string
|
||||
{
|
||||
return this.i18n.__(key.toLowerCase(), args);
|
||||
return args ? this.i18n.__(key.toLowerCase(), args) : this.i18n.__(key.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,7 +55,7 @@ export class LocalisationService
|
||||
*/
|
||||
public getKeys(): string[]
|
||||
{
|
||||
return Object.keys(this.databaseServer.getTables().locales.server.en);
|
||||
return Object.keys(this.databaseServer.getTables().locales!.server.en);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,7 +65,7 @@ export class LocalisationService
|
||||
*/
|
||||
public getRandomTextThatMatchesPartialKey(partialKey: string): string
|
||||
{
|
||||
const filteredKeys = Object.keys(this.databaseServer.getTables().locales.server.en).filter((x) =>
|
||||
const filteredKeys = Object.keys(this.databaseServer.getTables().locales!.server.en).filter((x) =>
|
||||
x.startsWith(partialKey),
|
||||
);
|
||||
const chosenKey = this.randomUtil.getArrayValue(filteredKeys);
|
||||
|
@ -5,7 +5,7 @@ import { NotificationSendHelper } from "@spt/helpers/NotificationSendHelper";
|
||||
import { NotifierHelper } from "@spt/helpers/NotifierHelper";
|
||||
import { TraderHelper } from "@spt/helpers/TraderHelper";
|
||||
import { Item } from "@spt/models/eft/common/tables/IItem";
|
||||
import { Dialogue, IUserDialogInfo, Message, MessageItems } from "@spt/models/eft/profile/ISptProfile";
|
||||
import { Dialogue, ISystemData, IUserDialogInfo, Message, MessageContentRagfair, MessageItems } from "@spt/models/eft/profile/ISptProfile";
|
||||
import { BaseClasses } from "@spt/models/enums/BaseClasses";
|
||||
import { MessageType } from "@spt/models/enums/MessageType";
|
||||
import { Traders } from "@spt/models/enums/Traders";
|
||||
@ -52,9 +52,9 @@ export class MailSendService
|
||||
messageType: MessageType,
|
||||
message: string,
|
||||
items: Item[] = [],
|
||||
maxStorageTimeSeconds = null,
|
||||
systemData = null,
|
||||
ragfair = null,
|
||||
maxStorageTimeSeconds?: number,
|
||||
systemData?: ISystemData,
|
||||
ragfair?: MessageContentRagfair,
|
||||
): void
|
||||
{
|
||||
if (!trader)
|
||||
@ -112,9 +112,9 @@ export class MailSendService
|
||||
messageType: MessageType,
|
||||
messageLocaleId: string,
|
||||
items: Item[] = [],
|
||||
maxStorageTimeSeconds = null,
|
||||
systemData = null,
|
||||
ragfair = null,
|
||||
maxStorageTimeSeconds?: number,
|
||||
systemData?: ISystemData,
|
||||
ragfair?: MessageContentRagfair,
|
||||
): void
|
||||
{
|
||||
if (!trader)
|
||||
@ -242,7 +242,7 @@ export class MailSendService
|
||||
senderDetails: IUserDialogInfo,
|
||||
message: string,
|
||||
items: Item[] = [],
|
||||
maxStorageTimeSeconds = null,
|
||||
maxStorageTimeSeconds?: number,
|
||||
): void
|
||||
{
|
||||
const details: ISendMessageDetails = {
|
||||
@ -283,7 +283,7 @@ export class MailSendService
|
||||
const itemsToSendToPlayer = this.processItemsBeforeAddingToMail(senderDialog.type, messageDetails);
|
||||
|
||||
// If there's items to send to player, flag dialog as containing attachments
|
||||
if (itemsToSendToPlayer.data?.length > 0)
|
||||
if ((itemsToSendToPlayer.data?.length ?? 0) > 0)
|
||||
{
|
||||
senderDialog.attachmentsNew += 1;
|
||||
}
|
||||
@ -392,11 +392,11 @@ export class MailSendService
|
||||
*/
|
||||
protected addRewardItemsToMessage(
|
||||
message: Message,
|
||||
itemsToSendToPlayer: MessageItems,
|
||||
maxStorageTimeSeconds: number,
|
||||
itemsToSendToPlayer: MessageItems | undefined,
|
||||
maxStorageTimeSeconds: number | undefined,
|
||||
): void
|
||||
{
|
||||
if (itemsToSendToPlayer?.data?.length > 0)
|
||||
if ((itemsToSendToPlayer?.data?.length ?? 0) > 0)
|
||||
{
|
||||
message.items = itemsToSendToPlayer;
|
||||
message.hasRewards = true;
|
||||
@ -416,13 +416,13 @@ export class MailSendService
|
||||
messageDetails: ISendMessageDetails,
|
||||
): MessageItems
|
||||
{
|
||||
const db = this.databaseServer.getTables().templates.items;
|
||||
const db = this.databaseServer.getTables().templates!.items;
|
||||
|
||||
let itemsToSendToPlayer: MessageItems = {};
|
||||
if (messageDetails.items?.length > 0)
|
||||
if ((messageDetails.items?.length ?? 0) > 0)
|
||||
{
|
||||
// Find base item that should be the 'primary' + have its parent id be used as the dialogs 'stash' value
|
||||
const parentItem = this.getBaseItemFromRewards(messageDetails.items);
|
||||
const parentItem = this.getBaseItemFromRewards(messageDetails.items!);
|
||||
if (!parentItem)
|
||||
{
|
||||
this.localisationService.getText("mailsend-missing_parent", {
|
||||
@ -442,7 +442,7 @@ export class MailSendService
|
||||
itemsToSendToPlayer = { stash: parentItem.parentId, data: [] };
|
||||
|
||||
// Ensure Ids are unique and cont collide with items in player inventory later
|
||||
messageDetails.items = this.itemHelper.replaceIDs(messageDetails.items);
|
||||
messageDetails.items = this.itemHelper.replaceIDs(messageDetails.items!);
|
||||
|
||||
for (const reward of messageDetails.items)
|
||||
{
|
||||
@ -476,7 +476,7 @@ export class MailSendService
|
||||
this.itemHelper.addCartridgesToAmmoBox(boxAndCartridges, itemTemplate);
|
||||
|
||||
// Push box + cartridge children into array
|
||||
itemsToSendToPlayer.data.push(...boxAndCartridges);
|
||||
itemsToSendToPlayer.data!.push(...boxAndCartridges);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -486,12 +486,12 @@ export class MailSendService
|
||||
}
|
||||
|
||||
// Item is sanitised and ready to be pushed into holding array
|
||||
itemsToSendToPlayer.data.push(reward);
|
||||
itemsToSendToPlayer.data!.push(reward);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove empty data property if no rewards
|
||||
if (itemsToSendToPlayer.data.length === 0)
|
||||
if (itemsToSendToPlayer.data!.length === 0)
|
||||
{
|
||||
delete itemsToSendToPlayer.data;
|
||||
}
|
||||
@ -514,7 +514,7 @@ export class MailSendService
|
||||
}
|
||||
|
||||
// Find first item with slotId that indicates its a 'base' item
|
||||
let item = items.find((x) => ["hideout", "main"].includes(x.slotId));
|
||||
let item = items.find((x) => ["hideout", "main"].includes(x.slotId ?? ""));
|
||||
if (item)
|
||||
{
|
||||
return item;
|
||||
@ -542,7 +542,10 @@ export class MailSendService
|
||||
{
|
||||
const dialogsInProfile = this.dialogueHelper.getDialogsForProfile(messageDetails.recipientId);
|
||||
const senderId = this.getMessageSenderIdByType(messageDetails);
|
||||
|
||||
if (!senderId)
|
||||
{
|
||||
throw new Error(`Unable to find sender id for details ${messageDetails.sender}`);
|
||||
}
|
||||
// Does dialog exist
|
||||
let senderDialog = dialogsInProfile[senderId];
|
||||
if (!senderDialog)
|
||||
@ -568,7 +571,7 @@ export class MailSendService
|
||||
* @param messageDetails
|
||||
* @returns gets an id of the individual sending it
|
||||
*/
|
||||
protected getMessageSenderIdByType(messageDetails: ISendMessageDetails): string
|
||||
protected getMessageSenderIdByType(messageDetails: ISendMessageDetails): string | undefined
|
||||
{
|
||||
if (messageDetails.sender === MessageType.SYSTEM_MESSAGE)
|
||||
{
|
||||
@ -577,7 +580,9 @@ export class MailSendService
|
||||
|
||||
if (messageDetails.sender === MessageType.NPC_TRADER || messageDetails.dialogType === MessageType.NPC_TRADER)
|
||||
{
|
||||
return this.traderHelper.getValidTraderIdByEnumValue(messageDetails.trader);
|
||||
return messageDetails.trader
|
||||
? this.traderHelper.getValidTraderIdByEnumValue(messageDetails.trader)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
if (messageDetails.sender === MessageType.USER_MESSAGE)
|
||||
|
@ -32,7 +32,7 @@ export class ModCompilerService
|
||||
public async compileMod(modName: string, modPath: string, modTypeScriptFiles: string[]): Promise<void>
|
||||
{
|
||||
// Concatenate TS files into one string
|
||||
let tsFileContents: string;
|
||||
let tsFileContents = "";
|
||||
let fileExists = true; // does every js file exist (been compiled before)
|
||||
for (const file of modTypeScriptFiles)
|
||||
{
|
||||
|
@ -49,7 +49,7 @@ export class OpenZoneService
|
||||
*/
|
||||
public applyZoneChangesToAllMaps(): void
|
||||
{
|
||||
const dbLocations = this.databaseServer.getTables().locations;
|
||||
const dbLocations = this.databaseServer.getTables().locations!;
|
||||
for (const mapKey in this.locationConfig.openZones)
|
||||
{
|
||||
if (!dbLocations[mapKey])
|
||||
|
@ -182,7 +182,7 @@ export class PaymentService
|
||||
const trader = this.traderHelper.getTrader(request.tid, sessionID);
|
||||
const currency = this.paymentHelper.getCurrency(trader.currency);
|
||||
let calcAmount = this.handbookHelper.fromRUB(this.handbookHelper.inRUB(amountToSend, currency), currency);
|
||||
const currencyMaxStackSize = this.databaseServer.getTables().templates.items[currency]._props.StackMaxSize;
|
||||
const currencyMaxStackSize = this.databaseServer.getTables().templates!.items[currency]._props.StackMaxSize!;
|
||||
let skipSendingMoneyToStash = false;
|
||||
|
||||
for (const item of pmcData.Inventory.items)
|
||||
@ -200,18 +200,18 @@ export class PaymentService
|
||||
}
|
||||
|
||||
// Found currency item
|
||||
if (item.upd.StackObjectsCount < currencyMaxStackSize)
|
||||
if (item.upd!.StackObjectsCount! < currencyMaxStackSize)
|
||||
{
|
||||
if (item.upd.StackObjectsCount + calcAmount > currencyMaxStackSize)
|
||||
if (item.upd!.StackObjectsCount! + calcAmount > currencyMaxStackSize)
|
||||
{
|
||||
// calculate difference
|
||||
calcAmount -= currencyMaxStackSize - item.upd.StackObjectsCount;
|
||||
item.upd.StackObjectsCount = currencyMaxStackSize;
|
||||
calcAmount -= currencyMaxStackSize - item.upd!.StackObjectsCount!;
|
||||
item.upd!.StackObjectsCount! = currencyMaxStackSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
skipSendingMoneyToStash = true;
|
||||
item.upd.StackObjectsCount = item.upd.StackObjectsCount + calcAmount;
|
||||
item.upd!.StackObjectsCount! = item.upd!.StackObjectsCount! + calcAmount;
|
||||
}
|
||||
|
||||
// Inform client of change to items StackObjectsCount
|
||||
@ -239,7 +239,7 @@ export class PaymentService
|
||||
const addItemToStashRequest: IAddItemsDirectRequest = {
|
||||
itemsWithModsToAdd: rewards,
|
||||
foundInRaid: false,
|
||||
callback: null,
|
||||
callback: undefined,
|
||||
useSortingTable: true,
|
||||
};
|
||||
this.inventoryHelper.addItemsToStash(sessionID, addItemToStashRequest, pmcData, output);
|
||||
@ -274,7 +274,7 @@ export class PaymentService
|
||||
pmcData.Inventory.stash,
|
||||
);
|
||||
const amountAvailable = moneyItemsInInventory.reduce(
|
||||
(accumulator, item) => accumulator + item.upd.StackObjectsCount,
|
||||
(accumulator, item) => accumulator + item.upd!.StackObjectsCount!,
|
||||
0,
|
||||
);
|
||||
|
||||
@ -299,7 +299,7 @@ export class PaymentService
|
||||
let leftToPay = amountToPay;
|
||||
for (const profileMoneyItem of moneyItemsInInventory)
|
||||
{
|
||||
const itemAmount = profileMoneyItem.upd.StackObjectsCount;
|
||||
const itemAmount = profileMoneyItem.upd!.StackObjectsCount!;
|
||||
if (leftToPay >= itemAmount)
|
||||
{
|
||||
leftToPay -= itemAmount;
|
||||
@ -307,7 +307,7 @@ export class PaymentService
|
||||
}
|
||||
else
|
||||
{
|
||||
profileMoneyItem.upd.StackObjectsCount -= leftToPay;
|
||||
profileMoneyItem.upd!.StackObjectsCount! -= leftToPay;
|
||||
leftToPay = 0;
|
||||
output.profileChanges[sessionID].items.change.push(profileMoneyItem);
|
||||
}
|
||||
@ -394,7 +394,7 @@ export class PaymentService
|
||||
* @param playerStashId Players stash id
|
||||
* @returns true if its in inventory
|
||||
*/
|
||||
protected isInStash(itemId: string, inventoryItems: Item[], playerStashId: string): boolean
|
||||
protected isInStash(itemId: string | undefined, inventoryItems: Item[], playerStashId: string): boolean
|
||||
{
|
||||
const itemParent = inventoryItems.find((x) => x._id === itemId);
|
||||
|
||||
|
@ -25,7 +25,7 @@ export class PlayerService
|
||||
{
|
||||
let accExp = 0;
|
||||
|
||||
for (const [level, { exp }] of this.databaseServer.getTables().globals.config.exp.level.exp_table.entries())
|
||||
for (const [level, { exp }] of this.databaseServer.getTables().globals!.config.exp.level.exp_table.entries())
|
||||
{
|
||||
accExp += exp;
|
||||
|
||||
|
@ -51,12 +51,15 @@ export class PmcChatResponseService
|
||||
|
||||
const victimDetails = this.getVictimDetails(victim);
|
||||
const message = this.chooseMessage(true, pmcData);
|
||||
this.notificationSendHelper.sendMessageToPlayer(
|
||||
sessionId,
|
||||
victimDetails,
|
||||
message,
|
||||
MessageType.USER_MESSAGE,
|
||||
);
|
||||
if (message)
|
||||
{
|
||||
this.notificationSendHelper.sendMessageToPlayer(
|
||||
sessionId,
|
||||
victimDetails,
|
||||
message,
|
||||
MessageType.USER_MESSAGE,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,7 +123,7 @@ export class PmcChatResponseService
|
||||
* @param pmcData Player profile
|
||||
* @returns Message from PMC to player
|
||||
*/
|
||||
protected chooseMessage(isVictim: boolean, pmcData: IPmcData): string
|
||||
protected chooseMessage(isVictim: boolean, pmcData: IPmcData): string | undefined
|
||||
{
|
||||
// Positive/negative etc
|
||||
const responseType = this.chooseResponseType(isVictim);
|
||||
|
@ -86,27 +86,26 @@ export class ProfileFixerService
|
||||
|
||||
this.reorderHideoutAreasWithResouceInputs(pmcProfile);
|
||||
|
||||
if (
|
||||
pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.GENERATOR).slots.length
|
||||
< 6
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots.Generator
|
||||
.Slots
|
||||
if (pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.GENERATOR)!.slots.length
|
||||
< 6
|
||||
+ this.databaseServer.getTables().globals!.config.SkillsSettings.HideoutManagement.EliteSlots.Generator
|
||||
.Slots
|
||||
)
|
||||
{
|
||||
this.logger.debug("Updating generator area slots to a size of 6 + hideout management skill");
|
||||
this.addEmptyObjectsToHideoutAreaSlots(
|
||||
HideoutAreas.GENERATOR,
|
||||
6
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
+ this.databaseServer.getTables().globals!.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.Generator.Slots,
|
||||
pmcProfile,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WATER_COLLECTOR).slots.length
|
||||
pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.WATER_COLLECTOR)!.slots.length
|
||||
< 1
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
+ this.databaseServer.getTables().globals!.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.WaterCollector.Slots
|
||||
)
|
||||
{
|
||||
@ -114,16 +113,16 @@ export class ProfileFixerService
|
||||
this.addEmptyObjectsToHideoutAreaSlots(
|
||||
HideoutAreas.WATER_COLLECTOR,
|
||||
1
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
+ this.databaseServer.getTables().globals!.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.WaterCollector.Slots,
|
||||
pmcProfile,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.AIR_FILTERING).slots.length
|
||||
pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.AIR_FILTERING)!.slots.length
|
||||
< 3
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
+ this.databaseServer.getTables().globals!.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.AirFilteringUnit.Slots
|
||||
)
|
||||
{
|
||||
@ -131,7 +130,7 @@ export class ProfileFixerService
|
||||
this.addEmptyObjectsToHideoutAreaSlots(
|
||||
HideoutAreas.AIR_FILTERING,
|
||||
3
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
+ this.databaseServer.getTables().globals!.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.AirFilteringUnit.Slots,
|
||||
pmcProfile,
|
||||
);
|
||||
@ -139,9 +138,9 @@ export class ProfileFixerService
|
||||
|
||||
// BTC Farm doesnt have extra slots for hideout management, but we still check for modded stuff!!
|
||||
if (
|
||||
pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.BITCOIN_FARM).slots.length
|
||||
pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.BITCOIN_FARM)!.slots.length
|
||||
< 50
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
+ this.databaseServer.getTables().globals!.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.BitcoinFarm.Slots
|
||||
)
|
||||
{
|
||||
@ -149,7 +148,7 @@ export class ProfileFixerService
|
||||
this.addEmptyObjectsToHideoutAreaSlots(
|
||||
HideoutAreas.BITCOIN_FARM,
|
||||
50
|
||||
+ this.databaseServer.getTables().globals.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
+ this.databaseServer.getTables().globals!.config.SkillsSettings.HideoutManagement.EliteSlots
|
||||
.BitcoinFarm.Slots,
|
||||
pmcProfile,
|
||||
);
|
||||
@ -180,8 +179,8 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
const db = this.databaseServer.getTables();
|
||||
const hideoutStandAreaDb = db.hideout.areas.find((x) => x.type === HideoutAreas.WEAPON_STAND);
|
||||
const hideoutStandSecondaryAreaDb = db.hideout.areas.find((x) => x.parentArea === hideoutStandAreaDb._id);
|
||||
const hideoutStandAreaDb = db.hideout!.areas.find((x) => x.type === HideoutAreas.WEAPON_STAND)!;
|
||||
const hideoutStandSecondaryAreaDb = db.hideout!.areas.find((x) => x.parentArea === hideoutStandAreaDb._id)!;
|
||||
const stageCurrentAt = hideoutStandAreaDb.stages[weaponStandArea.level];
|
||||
const hideoutStandStashId = pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.WEAPON_STAND];
|
||||
const hideoutSecondaryStashId = pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.WEAPON_STAND_SECONDARY];
|
||||
@ -198,14 +197,14 @@ export class ProfileFixerService
|
||||
const gunStandStashItem = pmcProfile.Inventory.items.find((x) => x._id === hideoutStandAreaDb._id);
|
||||
if (gunStandStashItem)
|
||||
{
|
||||
gunStandStashItem._tpl = stageCurrentAt.container;
|
||||
gunStandStashItem._tpl = stageCurrentAt.container!;
|
||||
this.logger.debug(
|
||||
`Updated existing gun stand inventory stash: ${gunStandStashItem._id} tpl to ${stageCurrentAt.container}`,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
pmcProfile.Inventory.items.push({ _id: hideoutStandAreaDb._id, _tpl: stageCurrentAt.container });
|
||||
pmcProfile.Inventory.items.push({ _id: hideoutStandAreaDb._id, _tpl: stageCurrentAt.container! });
|
||||
this.logger.debug(
|
||||
`Added missing gun stand inventory stash: ${hideoutStandAreaDb._id} tpl to ${stageCurrentAt.container}`,
|
||||
);
|
||||
@ -214,10 +213,10 @@ export class ProfileFixerService
|
||||
// Add secondary stash item to profile
|
||||
const gunStandStashSecondaryItem = pmcProfile.Inventory.items.find(
|
||||
(x) => x._id === hideoutStandSecondaryAreaDb._id,
|
||||
);
|
||||
)!;
|
||||
if (gunStandStashItem)
|
||||
{
|
||||
gunStandStashSecondaryItem._tpl = stageCurrentAt.container;
|
||||
gunStandStashSecondaryItem._tpl = stageCurrentAt.container!;
|
||||
this.logger.debug(
|
||||
`Updated gun stand existing inventory secondary stash: ${gunStandStashSecondaryItem._id} tpl to ${stageCurrentAt.container}`,
|
||||
);
|
||||
@ -226,7 +225,7 @@ export class ProfileFixerService
|
||||
{
|
||||
pmcProfile.Inventory.items.push({
|
||||
_id: hideoutStandSecondaryAreaDb._id,
|
||||
_tpl: stageCurrentAt.container,
|
||||
_tpl: stageCurrentAt.container!,
|
||||
});
|
||||
this.logger.debug(
|
||||
`Added missing gun stand inventory secondary stash: ${hideoutStandSecondaryAreaDb._id} tpl to ${stageCurrentAt.container}`,
|
||||
@ -240,25 +239,25 @@ export class ProfileFixerService
|
||||
if (!stashItem)
|
||||
{
|
||||
// Stand inventory stash item doesnt exist, add it
|
||||
pmcProfile.Inventory.items.push({ _id: hideoutStandAreaDb._id, _tpl: stageCurrentAt.container });
|
||||
pmcProfile.Inventory.items.push({ _id: hideoutStandAreaDb._id, _tpl: stageCurrentAt.container! });
|
||||
stashItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandAreaDb._id);
|
||||
}
|
||||
|
||||
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
||||
if (hideoutStandStashId && stashItem._tpl !== stageCurrentAt.container)
|
||||
if (hideoutStandStashId && stashItem!._tpl !== stageCurrentAt.container)
|
||||
{
|
||||
this.logger.debug(
|
||||
`primary Stash tpl was: ${stashItem._tpl}, but should be ${stageCurrentAt.container}, updating`,
|
||||
`primary Stash tpl was: ${stashItem!._tpl}, but should be ${stageCurrentAt.container}, updating`,
|
||||
);
|
||||
// The id inside the profile does not match what the hideout db value is, out of sync, adjust
|
||||
stashItem._tpl = stageCurrentAt.container;
|
||||
stashItem!._tpl = stageCurrentAt.container!;
|
||||
}
|
||||
|
||||
let stashSecondaryItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandSecondaryAreaDb._id);
|
||||
if (!stashSecondaryItem)
|
||||
{
|
||||
// Stand inventory stash item doesnt exist, add it
|
||||
pmcProfile.Inventory.items.push({ _id: hideoutStandSecondaryAreaDb._id, _tpl: stageCurrentAt.container });
|
||||
pmcProfile.Inventory.items.push({ _id: hideoutStandSecondaryAreaDb._id, _tpl: stageCurrentAt.container! });
|
||||
stashSecondaryItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandSecondaryAreaDb._id);
|
||||
}
|
||||
|
||||
@ -266,10 +265,10 @@ export class ProfileFixerService
|
||||
if (hideoutSecondaryStashId && stashSecondaryItem?._tpl !== stageCurrentAt.container)
|
||||
{
|
||||
this.logger.debug(
|
||||
`Secondary stash tpl was: ${stashSecondaryItem._tpl}, but should be ${stageCurrentAt.container}, updating`,
|
||||
`Secondary stash tpl was: ${stashSecondaryItem?._tpl}, but should be ${stageCurrentAt.container}, updating`,
|
||||
);
|
||||
// The id inside the profile does not match what the hideout db value is, out of sync, adjust
|
||||
stashSecondaryItem._tpl = stageCurrentAt.container;
|
||||
stashSecondaryItem!._tpl = stageCurrentAt.container!;
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,7 +282,7 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
const db = this.databaseServer.getTables();
|
||||
const placeOfFameAreaDb = db.hideout.areas.find((area) => area.type === HideoutAreas.PLACE_OF_FAME);
|
||||
const placeOfFameAreaDb = db.hideout!.areas.find((area) => area.type === HideoutAreas.PLACE_OF_FAME);
|
||||
if (!placeOfFameAreaDb)
|
||||
{
|
||||
return;
|
||||
@ -301,14 +300,14 @@ export class ProfileFixerService
|
||||
const placeOfFameStashItem = pmcProfile.Inventory.items.find((x) => x._id === placeOfFameAreaDb._id);
|
||||
if (placeOfFameStashItem)
|
||||
{
|
||||
placeOfFameStashItem._tpl = stageCurrentlyAt.container;
|
||||
placeOfFameStashItem._tpl = stageCurrentlyAt.container!;
|
||||
this.logger.debug(
|
||||
`Updated existing place of fame inventory stash: ${placeOfFameStashItem._id} tpl to ${stageCurrentlyAt.container}`,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
pmcProfile.Inventory.items.push({ _id: placeOfFameAreaDb._id, _tpl: stageCurrentlyAt.container });
|
||||
pmcProfile.Inventory.items.push({ _id: placeOfFameAreaDb._id, _tpl: stageCurrentlyAt.container! });
|
||||
this.logger.debug(
|
||||
`Added missing place of fame inventory stash: ${placeOfFameAreaDb._id} tpl to ${stageCurrentlyAt.container}`,
|
||||
);
|
||||
@ -321,18 +320,18 @@ export class ProfileFixerService
|
||||
if (!stashItem)
|
||||
{
|
||||
// Stand inventory stash item doesnt exist, add it
|
||||
pmcProfile.Inventory.items.push({ _id: placeOfFameAreaDb._id, _tpl: stageCurrentlyAt.container });
|
||||
pmcProfile.Inventory.items.push({ _id: placeOfFameAreaDb._id, _tpl: stageCurrentlyAt.container! });
|
||||
stashItem = pmcProfile.Inventory.items?.find((x) => x._id === placeOfFameAreaDb._id);
|
||||
}
|
||||
|
||||
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
||||
if (placeOfFameStashId && stashItem._tpl !== stageCurrentlyAt.container)
|
||||
if (placeOfFameStashId && stashItem!._tpl !== stageCurrentlyAt.container)
|
||||
{
|
||||
this.logger.debug(
|
||||
`primary Stash tpl was: ${stashItem._tpl}, but should be ${stageCurrentlyAt.container}, updating`,
|
||||
`primary Stash tpl was: ${stashItem?._tpl}, but should be ${stageCurrentlyAt.container}, updating`,
|
||||
);
|
||||
// The id inside the profile does not match what the hideout db value is, out of sync, adjust
|
||||
stashItem._tpl = stageCurrentlyAt.container;
|
||||
stashItem!._tpl = stageCurrentlyAt.container!;
|
||||
}
|
||||
}
|
||||
|
||||
@ -465,7 +464,7 @@ export class ProfileFixerService
|
||||
{
|
||||
const taskConditionKeysToRemove: string[] = [];
|
||||
const activeRepeatableQuests = this.getActiveRepeatableQuests(pmcProfile.RepeatableQuests);
|
||||
const achievements = this.databaseServer.getTables().templates.achievements;
|
||||
const achievements = this.databaseServer.getTables().templates!.achievements;
|
||||
|
||||
// Loop over TaskConditionCounters objects and add once we want to remove to counterKeysToRemove
|
||||
for (const [key, taskConditionCounter] of Object.entries(pmcProfile.TaskConditionCounters))
|
||||
@ -501,7 +500,7 @@ export class ProfileFixerService
|
||||
|
||||
protected getActiveRepeatableQuests(repeatableQuests: IPmcDataRepeatableQuest[]): IRepeatableQuest[]
|
||||
{
|
||||
let activeQuests = [];
|
||||
let activeQuests: IRepeatableQuest[] = [];
|
||||
for (const repeatableQuest of repeatableQuests)
|
||||
{
|
||||
if (repeatableQuest.activeQuests.length > 0)
|
||||
@ -648,17 +647,17 @@ export class ProfileFixerService
|
||||
*/
|
||||
protected addMissingWallImprovements(pmcProfile: IPmcData): void
|
||||
{
|
||||
const profileWallArea = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.EMERGENCY_WALL);
|
||||
const profileWallArea = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.EMERGENCY_WALL)!;
|
||||
const wallDb = this.databaseServer
|
||||
.getTables()
|
||||
.hideout.areas.find((x) => x.type === HideoutAreas.EMERGENCY_WALL);
|
||||
.hideout!.areas.find((x) => x.type === HideoutAreas.EMERGENCY_WALL);
|
||||
|
||||
if (profileWallArea.level > 0)
|
||||
{
|
||||
for (let i = 0; i < profileWallArea.level; i++)
|
||||
{
|
||||
// Get wall stage from db
|
||||
const wallStageDb = wallDb.stages[i];
|
||||
const wallStageDb = wallDb!.stages[i];
|
||||
if (wallStageDb.improvements.length === 0)
|
||||
{
|
||||
// No improvements, skip
|
||||
@ -705,7 +704,7 @@ export class ProfileFixerService
|
||||
// Have an item property and it has at least one item in it
|
||||
// Or
|
||||
// Have no item property
|
||||
area.slots = area.slots.filter((x) => ("item" in x && x.item?.length > 0) || !("item" in x));
|
||||
area.slots = area.slots.filter((x) => ("item" in x && (x.item?.length ?? 0) > 0) || !("item" in x));
|
||||
}
|
||||
}
|
||||
|
||||
@ -727,7 +726,7 @@ export class ProfileFixerService
|
||||
const area = pmcProfile.Hideout.Areas.find((area) => area.type === areaId);
|
||||
if (!area)
|
||||
{
|
||||
this.logger.debug(`unable to sort: ${area.type} (${areaId}) slots, no area found`);
|
||||
this.logger.debug(`unable to sort: ${area!.type} (${areaId}) slots, no area found`);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -756,7 +755,7 @@ export class ProfileFixerService
|
||||
): void
|
||||
{
|
||||
const area = pmcProfile.Hideout.Areas.find((x) => x.type === areaType);
|
||||
area.slots = this.addObjectsToArray(emptyItemCount, area.slots);
|
||||
area!.slots = this.addObjectsToArray(emptyItemCount, area!.slots);
|
||||
}
|
||||
|
||||
protected addObjectsToArray(count: number, slots: HideoutSlot[]): HideoutSlot[]
|
||||
@ -780,7 +779,7 @@ export class ProfileFixerService
|
||||
{
|
||||
const profileHideoutAreas = pmcProfile.Hideout.Areas;
|
||||
const profileBonuses = pmcProfile.Bonuses;
|
||||
const dbHideoutAreas = this.databaseServer.getTables().hideout.areas;
|
||||
const dbHideoutAreas = this.databaseServer.getTables().hideout!.areas;
|
||||
|
||||
for (const area of profileHideoutAreas)
|
||||
{
|
||||
@ -841,7 +840,7 @@ export class ProfileFixerService
|
||||
* @param bonus bonus to find
|
||||
* @returns matching bonus
|
||||
*/
|
||||
protected getBonusFromProfile(profileBonuses: Bonus[], bonus: StageBonus): Bonus
|
||||
protected getBonusFromProfile(profileBonuses: Bonus[], bonus: StageBonus): Bonus | undefined
|
||||
{
|
||||
// match by id first, used by "TextBonus" bonuses
|
||||
if (bonus.id)
|
||||
@ -871,13 +870,13 @@ export class ProfileFixerService
|
||||
*/
|
||||
public checkForOrphanedModdedItems(sessionId: string, fullProfile: ISptProfile): void
|
||||
{
|
||||
const itemsDb = this.databaseServer.getTables().templates.items;
|
||||
const itemsDb = this.databaseServer.getTables().templates!.items;
|
||||
const pmcProfile = fullProfile.characters.pmc;
|
||||
|
||||
// Get items placed in root of stash
|
||||
// TODO: extend to other areas / sub items
|
||||
const inventoryItemsToCheck = pmcProfile.Inventory.items.filter((item) =>
|
||||
["hideout", "main"].includes(item.slotId),
|
||||
["hideout", "main"].includes(item.slotId ?? ""),
|
||||
);
|
||||
if (inventoryItemsToCheck)
|
||||
{
|
||||
@ -973,7 +972,7 @@ export class ProfileFixerService
|
||||
}
|
||||
}
|
||||
|
||||
const clothing = this.databaseServer.getTables().templates.customization;
|
||||
const clothing = this.databaseServer.getTables().templates!.customization;
|
||||
for (const [_, suitId] of Object.entries(fullProfile.suits))
|
||||
{
|
||||
if (!clothing[suitId])
|
||||
@ -1008,11 +1007,11 @@ export class ProfileFixerService
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const successReward of activeQuest.rewards.Success)
|
||||
for (const successReward of activeQuest.rewards.Success!)
|
||||
{
|
||||
if (successReward.type === "Item")
|
||||
{
|
||||
for (const rewardItem of successReward.items)
|
||||
for (const rewardItem of successReward.items!)
|
||||
{
|
||||
if (!itemsDb[rewardItem._tpl])
|
||||
{
|
||||
@ -1164,7 +1163,7 @@ export class ProfileFixerService
|
||||
const itemsHaveChildren = pmcProfile.Inventory.items.some((x) => x.parentId === key);
|
||||
if (!itemsHaveChildren)
|
||||
{
|
||||
const itemToAdjustId = pmcProfile.Inventory.items.find((x) => x._id === key);
|
||||
const itemToAdjustId = pmcProfile.Inventory.items.find((x) => x._id === key)!;
|
||||
itemToAdjustId._id = this.hashUtil.generate();
|
||||
this.logger.warning(`Replace duplicate item Id: ${key} with ${itemToAdjustId._id}`);
|
||||
}
|
||||
@ -1182,7 +1181,7 @@ export class ProfileFixerService
|
||||
|
||||
// Check items with a tag that contains non alphanumeric characters
|
||||
const regxp = /([/w"\\'])/g;
|
||||
if (regxp.test(item.upd.Tag?.Name))
|
||||
if (item.upd.Tag?.Name && regxp.test(item.upd.Tag?.Name))
|
||||
{
|
||||
this.logger.warning(`Fixed item: ${item._id}s Tag value, removed invalid characters`);
|
||||
item.upd.Tag.Name = item.upd.Tag.Name.replace(regxp, "");
|
||||
@ -1197,8 +1196,8 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
// Iterate over clothing
|
||||
const customizationDb = this.databaseServer.getTables().templates.customization;
|
||||
const customizationDbArray = Object.values(this.databaseServer.getTables().templates.customization);
|
||||
const customizationDb = this.databaseServer.getTables().templates!.customization;
|
||||
const customizationDbArray = Object.values(this.databaseServer.getTables().templates!.customization);
|
||||
const playerIsUsec = pmcProfile.Info.Side.toLowerCase() === "usec";
|
||||
|
||||
// Check Head
|
||||
@ -1207,7 +1206,7 @@ export class ProfileFixerService
|
||||
const defaultHead = playerIsUsec
|
||||
? customizationDbArray.find((x) => x._name === "DefaultUsecHead")
|
||||
: customizationDbArray.find((x) => x._name === "DefaultBearHead");
|
||||
pmcProfile.Customization.Head = defaultHead._id;
|
||||
pmcProfile.Customization.Head = defaultHead!._id;
|
||||
}
|
||||
|
||||
// check Body
|
||||
@ -1217,7 +1216,7 @@ export class ProfileFixerService
|
||||
= pmcProfile.Info.Side.toLowerCase() === "usec"
|
||||
? customizationDbArray.find((x) => x._name === "DefaultUsecBody")
|
||||
: customizationDbArray.find((x) => x._name === "DefaultBearBody");
|
||||
pmcProfile.Customization.Body = defaultBody._id;
|
||||
pmcProfile.Customization.Body = defaultBody!._id;
|
||||
}
|
||||
|
||||
// check Hands
|
||||
@ -1227,7 +1226,7 @@ export class ProfileFixerService
|
||||
= pmcProfile.Info.Side.toLowerCase() === "usec"
|
||||
? customizationDbArray.find((x) => x._name === "DefaultUsecHands")
|
||||
: customizationDbArray.find((x) => x._name === "DefaultBearHands");
|
||||
pmcProfile.Customization.Hands = defaultHands._id;
|
||||
pmcProfile.Customization.Hands = defaultHands!._id;
|
||||
}
|
||||
|
||||
// check Hands
|
||||
@ -1237,7 +1236,7 @@ export class ProfileFixerService
|
||||
= pmcProfile.Info.Side.toLowerCase() === "usec"
|
||||
? customizationDbArray.find((x) => x._name === "DefaultUsecFeet")
|
||||
: customizationDbArray.find((x) => x._name === "DefaultBearFeet");
|
||||
pmcProfile.Customization.Feet = defaultFeet._id;
|
||||
pmcProfile.Customization.Feet = defaultFeet!._id;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1266,7 +1265,7 @@ export class ProfileFixerService
|
||||
return;
|
||||
}
|
||||
|
||||
const profileTemplates = this.databaseServer.getTables().templates.profiles[fullProfile.info.edition];
|
||||
const profileTemplates = this.databaseServer.getTables().templates?.profiles[fullProfile.info.edition];
|
||||
if (!profileTemplates)
|
||||
{
|
||||
return;
|
||||
@ -1342,7 +1341,7 @@ export class ProfileFixerService
|
||||
const statsCopy = this.cloner.clone(fullProfile.characters.pmc.Stats);
|
||||
|
||||
// Clear stats object
|
||||
fullProfile.characters.pmc.Stats = { Eft: null };
|
||||
delete fullProfile.characters.pmc.Stats.Eft;
|
||||
|
||||
fullProfile.characters.pmc.Stats.Eft = <any>(<unknown>statsCopy);
|
||||
}
|
||||
@ -1364,7 +1363,7 @@ export class ProfileFixerService
|
||||
}
|
||||
|
||||
// Bonus lacks id, find matching hideout area / stage / bonus
|
||||
for (const area of this.databaseServer.getTables().hideout.areas)
|
||||
for (const area of this.databaseServer.getTables().hideout!.areas)
|
||||
{
|
||||
// TODO: skip if no stages
|
||||
for (const stageIndex in area.stages)
|
||||
@ -1429,7 +1428,7 @@ export class ProfileFixerService
|
||||
*/
|
||||
protected removeOrphanedQuests(pmcProfile: IPmcData): void
|
||||
{
|
||||
const quests = this.databaseServer.getTables().templates.quests;
|
||||
const quests = this.databaseServer.getTables().templates!.quests;
|
||||
const profileQuests = pmcProfile.Quests;
|
||||
|
||||
const repeatableQuests: IRepeatableQuest[] = [];
|
||||
|
@ -25,14 +25,14 @@ export class ProfileSnapshotService
|
||||
* @param sessionID key
|
||||
* @returns A player profile object
|
||||
*/
|
||||
public getProfileSnapshot(sessionID: string): ISptProfile
|
||||
public getProfileSnapshot(sessionID: string): ISptProfile | undefined
|
||||
{
|
||||
if (this.storedProfileSnapshots[sessionID])
|
||||
{
|
||||
return this.storedProfileSnapshots[sessionID];
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,7 +55,7 @@ export class RagfairLinkedItemService
|
||||
return linkedItems[id];
|
||||
};
|
||||
|
||||
for (const item of Object.values(this.databaseServer.getTables().templates.items))
|
||||
for (const item of Object.values(this.databaseServer.getTables().templates!.items))
|
||||
{
|
||||
const itemLinkedSet = getLinkedItems(item._id);
|
||||
|
||||
@ -94,7 +94,7 @@ export class RagfairLinkedItemService
|
||||
applyLinkedItems: (items: string[]) => void,
|
||||
): void
|
||||
{
|
||||
const cylinderMod = cylinder._props.Slots.find((x) => x._name === "mod_magazine");
|
||||
const cylinderMod = cylinder._props.Slots?.find((x) => x._name === "mod_magazine");
|
||||
if (cylinderMod)
|
||||
{
|
||||
// Get the first cylinder filter tpl
|
||||
@ -122,7 +122,7 @@ export class RagfairLinkedItemService
|
||||
return [];
|
||||
}
|
||||
|
||||
const filters = [];
|
||||
const filters: string[] = [];
|
||||
for (const sub of item._props[slot])
|
||||
{
|
||||
if (!("_props" in sub && "filters" in sub._props))
|
||||
|
@ -54,12 +54,12 @@ export class RagfairOfferService
|
||||
return this.ragfairOfferHandler.getOffers();
|
||||
}
|
||||
|
||||
public getOfferByOfferId(offerId: string): IRagfairOffer
|
||||
public getOfferByOfferId(offerId: string): IRagfairOffer | undefined
|
||||
{
|
||||
return this.ragfairOfferHandler.getOfferById(offerId);
|
||||
}
|
||||
|
||||
public getOffersOfType(templateId: string): IRagfairOffer[]
|
||||
public getOffersOfType(templateId: string): IRagfairOffer[] | undefined
|
||||
{
|
||||
return this.ragfairOfferHandler.getOffersByTemplate(templateId);
|
||||
}
|
||||
@ -145,10 +145,13 @@ export class RagfairOfferService
|
||||
public removeOfferStack(offerId: string, amount: number): void
|
||||
{
|
||||
const offer = this.ragfairOfferHandler.getOfferById(offerId);
|
||||
offer.items[0].upd.StackObjectsCount -= amount;
|
||||
if (offer.items[0].upd.StackObjectsCount <= 0)
|
||||
if (offer)
|
||||
{
|
||||
this.processStaleOffer(offer);
|
||||
offer.items[0].upd!.StackObjectsCount! -= amount;
|
||||
if (offer.items[0].upd!.StackObjectsCount! <= 0)
|
||||
{
|
||||
this.processStaleOffer(offer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +167,7 @@ export class RagfairOfferService
|
||||
*/
|
||||
public traderOffersNeedRefreshing(traderID: string): boolean
|
||||
{
|
||||
const trader = this.databaseServer.getTables().traders[traderID];
|
||||
const trader = this.databaseServer.getTables().traders![traderID];
|
||||
if (!trader || !trader.base)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("ragfair-trader_missing_base_file", traderID));
|
||||
@ -259,15 +262,15 @@ export class RagfairOfferService
|
||||
}
|
||||
|
||||
// Reduce player ragfair rep
|
||||
profile.RagfairInfo.rating -= this.databaseServer.getTables().globals.config.RagFair.ratingDecreaseCount;
|
||||
profile.RagfairInfo.rating -= this.databaseServer.getTables().globals!.config.RagFair.ratingDecreaseCount;
|
||||
profile.RagfairInfo.isRatingGrowing = false;
|
||||
|
||||
const firstOfferItem = playerOffer.items[0];
|
||||
if (firstOfferItem.upd.StackObjectsCount > firstOfferItem.upd.OriginalStackObjectsCount)
|
||||
if (firstOfferItem.upd!.StackObjectsCount! > firstOfferItem.upd!.OriginalStackObjectsCount!)
|
||||
{
|
||||
playerOffer.items[0].upd.StackObjectsCount = firstOfferItem.upd.OriginalStackObjectsCount;
|
||||
playerOffer.items[0].upd!.StackObjectsCount = firstOfferItem.upd!.OriginalStackObjectsCount;
|
||||
}
|
||||
delete playerOffer.items[0].upd.OriginalStackObjectsCount;
|
||||
delete playerOffer.items[0].upd!.OriginalStackObjectsCount;
|
||||
// Remove player offer from flea
|
||||
this.ragfairOfferHandler.removeOffer(playerOffer);
|
||||
|
||||
|
@ -64,7 +64,7 @@ export class RagfairPriceService implements OnLoad
|
||||
*/
|
||||
public refreshStaticPrices(): void
|
||||
{
|
||||
for (const item of Object.values(this.databaseServer.getTables().templates.items).filter(
|
||||
for (const item of Object.values(this.databaseServer.getTables().templates!.items).filter(
|
||||
(x) => x._type === "Item",
|
||||
))
|
||||
{
|
||||
@ -77,7 +77,7 @@ export class RagfairPriceService implements OnLoad
|
||||
*/
|
||||
public refreshDynamicPrices(): void
|
||||
{
|
||||
const pricesTable = this.databaseServer.getTables().templates.prices;
|
||||
const pricesTable = this.databaseServer.getTables().templates!.prices;
|
||||
this.prices.dynamic = { ...this.prices.dynamic, ...pricesTable };
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ export class RagfairPriceService implements OnLoad
|
||||
// If the price doesn't exist in the cache yet, try to find it
|
||||
if (!this.prices.dynamic[itemTpl])
|
||||
{
|
||||
this.prices.dynamic[itemTpl] = this.databaseServer.getTables().templates.prices[itemTpl];
|
||||
this.prices.dynamic[itemTpl] = this.databaseServer.getTables().templates!.prices[itemTpl];
|
||||
}
|
||||
|
||||
return this.prices.dynamic[itemTpl];
|
||||
@ -328,7 +328,7 @@ export class RagfairPriceService implements OnLoad
|
||||
if (unreasonableModifier.enabled)
|
||||
{
|
||||
price = this.adjustUnreasonablePrice(
|
||||
this.databaseServer.getTables().templates.handbook.Items,
|
||||
this.databaseServer.getTables().templates!.handbook.Items,
|
||||
unreasonableModifier,
|
||||
itemTemplateId,
|
||||
price,
|
||||
@ -338,7 +338,7 @@ export class RagfairPriceService implements OnLoad
|
||||
}
|
||||
|
||||
// Vary the price based on the type of offer.
|
||||
const range = this.getOfferTypeRangeValues(isPreset, isPackOffer);
|
||||
const range = this.getOfferTypeRangeValues(isPreset, isPackOffer ?? false);
|
||||
price = this.randomiseOfferPrice(price, range);
|
||||
|
||||
// Convert to different currency if required.
|
||||
|
@ -69,9 +69,9 @@ export class RagfairTaxService
|
||||
const itemWorth = this.calculateItemWorth(item, itemTemplate, offerItemCount, pmcData);
|
||||
const requirementsPrice = requirementsValue * (sellInOnePiece ? 1 : offerItemCount);
|
||||
|
||||
const itemTaxMult = this.databaseServer.getTables().globals.config.RagFair.communityItemTax / 100.0;
|
||||
const itemTaxMult = this.databaseServer.getTables().globals!.config.RagFair.communityItemTax / 100.0;
|
||||
const requirementTaxMult
|
||||
= this.databaseServer.getTables().globals.config.RagFair.communityRequirementTax / 100.0;
|
||||
= this.databaseServer.getTables().globals!.config.RagFair.communityRequirementTax / 100.0;
|
||||
|
||||
let itemPriceMult = Math.log10(itemWorth / requirementsPrice);
|
||||
let requirementPriceMult = Math.log10(requirementsPrice / itemWorth);
|
||||
@ -89,7 +89,7 @@ export class RagfairTaxService
|
||||
requirementPriceMult = 4 ** requirementPriceMult;
|
||||
|
||||
const hideoutFleaTaxDiscountBonus = pmcData.Bonuses.find((b) => b.type === BonusType.RAGFAIR_COMMISSION);
|
||||
const taxDiscountPercent = hideoutFleaTaxDiscountBonus ? Math.abs(hideoutFleaTaxDiscountBonus.value) : 0;
|
||||
const taxDiscountPercent = hideoutFleaTaxDiscountBonus ? Math.abs(hideoutFleaTaxDiscountBonus!.value ?? 0) : 0;
|
||||
|
||||
const tax
|
||||
= itemWorth * itemTaxMult * itemPriceMult + requirementsPrice * requirementTaxMult * requirementPriceMult;
|
||||
@ -98,10 +98,10 @@ export class RagfairTaxService
|
||||
? itemTemplate._props.RagFairCommissionModifier
|
||||
: 1;
|
||||
|
||||
if (item.upd.Buff)
|
||||
{
|
||||
// TODO: enhance tax calc with client implementation from GClass1932/CalculateTaxPrice()
|
||||
}
|
||||
// if (item.upd.Buff)
|
||||
// {
|
||||
// TODO: enhance tax calc with client implementation from GClass1932/CalculateTaxPrice()
|
||||
// }
|
||||
|
||||
const taxValue = Math.round(discountedTax * itemComissionMult);
|
||||
this.logger.debug(`Tax Calculated to be: ${taxValue}`);
|
||||
@ -138,7 +138,7 @@ export class RagfairTaxService
|
||||
worth += this.calculateItemWorth(
|
||||
child,
|
||||
this.itemHelper.getItem(child._tpl)[1],
|
||||
child.upd.StackObjectsCount,
|
||||
child.upd!.StackObjectsCount!,
|
||||
pmcData,
|
||||
false,
|
||||
);
|
||||
@ -146,46 +146,46 @@ export class RagfairTaxService
|
||||
}
|
||||
}
|
||||
|
||||
if ("Dogtag" in item.upd)
|
||||
if ("Dogtag" in item.upd!)
|
||||
{
|
||||
worth *= item.upd.Dogtag.Level;
|
||||
worth *= item.upd!.Dogtag!.Level;
|
||||
}
|
||||
|
||||
if ("Key" in item.upd && itemTemplate._props.MaximumNumberOfUsage > 0)
|
||||
if ("Key" in item.upd! && (itemTemplate._props.MaximumNumberOfUsage ?? 0) > 0)
|
||||
{
|
||||
worth
|
||||
= (worth / itemTemplate._props.MaximumNumberOfUsage)
|
||||
* (itemTemplate._props.MaximumNumberOfUsage - item.upd.Key.NumberOfUsages);
|
||||
= (worth / itemTemplate._props.MaximumNumberOfUsage!)
|
||||
* (itemTemplate._props.MaximumNumberOfUsage! - item.upd!.Key!.NumberOfUsages);
|
||||
}
|
||||
|
||||
if ("Resource" in item.upd && itemTemplate._props.MaxResource > 0)
|
||||
if ("Resource" in item.upd! && itemTemplate._props.MaxResource! > 0)
|
||||
{
|
||||
worth = worth * 0.1 + ((worth * 0.9) / itemTemplate._props.MaxResource) * item.upd.Resource.Value;
|
||||
worth = worth * 0.1 + ((worth * 0.9) / itemTemplate._props.MaxResource!) * item.upd.Resource!.Value;
|
||||
}
|
||||
|
||||
if ("SideEffect" in item.upd && itemTemplate._props.MaxResource > 0)
|
||||
if ("SideEffect" in item.upd! && itemTemplate._props.MaxResource! > 0)
|
||||
{
|
||||
worth = worth * 0.1 + ((worth * 0.9) / itemTemplate._props.MaxResource) * item.upd.SideEffect.Value;
|
||||
worth = worth * 0.1 + ((worth * 0.9) / itemTemplate._props.MaxResource!) * item.upd.SideEffect!.Value;
|
||||
}
|
||||
|
||||
if ("MedKit" in item.upd && itemTemplate._props.MaxHpResource > 0)
|
||||
if ("MedKit" in item.upd! && itemTemplate._props.MaxHpResource! > 0)
|
||||
{
|
||||
worth = (worth / itemTemplate._props.MaxHpResource) * item.upd.MedKit.HpResource;
|
||||
worth = (worth / itemTemplate._props.MaxHpResource!) * item.upd.MedKit!.HpResource;
|
||||
}
|
||||
|
||||
if ("FoodDrink" in item.upd && itemTemplate._props.MaxResource > 0)
|
||||
if ("FoodDrink" in item.upd! && itemTemplate._props.MaxResource! > 0)
|
||||
{
|
||||
worth = (worth / itemTemplate._props.MaxResource) * item.upd.FoodDrink.HpPercent;
|
||||
worth = (worth / itemTemplate._props.MaxResource!) * item.upd.FoodDrink!.HpPercent;
|
||||
}
|
||||
|
||||
if ("Repairable" in item.upd && <number > itemTemplate._props.armorClass > 0)
|
||||
if ("Repairable" in item.upd! && <number > itemTemplate._props.armorClass > 0)
|
||||
{
|
||||
const num2 = 0.01 * 0.0 ** item.upd.Repairable.MaxDurability;
|
||||
const num2 = 0.01 * 0.0 ** item.upd.Repairable!.MaxDurability;
|
||||
worth
|
||||
= worth * (item.upd.Repairable.MaxDurability / itemTemplate._props.Durability - num2)
|
||||
= worth * (item.upd.Repairable!.MaxDurability / itemTemplate._props.Durability! - num2)
|
||||
- Math.floor(
|
||||
itemTemplate._props.RepairCost
|
||||
* (item.upd.Repairable.MaxDurability - item.upd.Repairable.Durability),
|
||||
itemTemplate._props.RepairCost!
|
||||
* (item.upd.Repairable!.MaxDurability - item.upd.Repairable!.Durability),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -107,15 +107,15 @@ export class RaidTimeAdjustmentService
|
||||
{
|
||||
const db = this.databaseServer.getTables();
|
||||
|
||||
const mapBase: ILocationBase = db.locations[request.Location.toLowerCase()].base;
|
||||
const mapBase: ILocationBase = db.locations![request.Location.toLowerCase()].base;
|
||||
const baseEscapeTimeMinutes = mapBase.EscapeTimeLimit;
|
||||
|
||||
// Prep result object to return
|
||||
const result: IGetRaidTimeResponse = {
|
||||
RaidTimeMinutes: baseEscapeTimeMinutes,
|
||||
ExitChanges: [],
|
||||
NewSurviveTimeSeconds: null,
|
||||
OriginalSurvivalTimeSeconds: db.globals.config.exp.match_end.survived_seconds_requirement,
|
||||
NewSurviveTimeSeconds: undefined,
|
||||
OriginalSurvivalTimeSeconds: db.globals!.config.exp.match_end.survived_seconds_requirement,
|
||||
};
|
||||
|
||||
// Pmc raid, send default
|
||||
@ -203,9 +203,9 @@ export class RaidTimeAdjustmentService
|
||||
* @param newRaidTimeMinutes How long raid is in minutes
|
||||
* @returns List of exit changes to send to client
|
||||
*/
|
||||
protected getExitAdjustments(mapBase: ILocationBase, newRaidTimeMinutes: number): ExtractChange[]
|
||||
protected getExitAdjustments(mapBase: ILocationBase, newRaidTimeMinutes: number): ExtractChange[] | undefined
|
||||
{
|
||||
const result = [];
|
||||
const result: ExtractChange[] = [];
|
||||
// Adjust train exits only
|
||||
for (const exit of mapBase.exits)
|
||||
{
|
||||
@ -215,7 +215,12 @@ export class RaidTimeAdjustmentService
|
||||
}
|
||||
|
||||
// Prepare train adjustment object
|
||||
const exitChange: ExtractChange = { Name: exit.Name, MinTime: null, MaxTime: null, Chance: null };
|
||||
const exitChange: ExtractChange = {
|
||||
Name: exit.Name,
|
||||
MinTime: undefined,
|
||||
MaxTime: undefined,
|
||||
Chance: undefined,
|
||||
};
|
||||
|
||||
// At what minute we simulate the player joining the raid
|
||||
const simulatedRaidEntryTimeMinutes = mapBase.EscapeTimeLimit - newRaidTimeMinutes;
|
||||
@ -270,6 +275,6 @@ export class RaidTimeAdjustmentService
|
||||
result.push(exitChange);
|
||||
}
|
||||
|
||||
return result.length > 0 ? result : null;
|
||||
return result.length > 0 ? result : undefined;
|
||||
}
|
||||
}
|
||||
|
@ -61,17 +61,21 @@ export class RepairService
|
||||
): RepairDetails
|
||||
{
|
||||
const itemToRepair = pmcData.Inventory.items.find((x) => x._id === repairItemDetails._id);
|
||||
if (itemToRepair === undefined)
|
||||
if (!itemToRepair)
|
||||
{
|
||||
throw new Error(`Item ${repairItemDetails._id} not found in profile inventory, unable to repair`);
|
||||
}
|
||||
|
||||
const priceCoef = this.traderHelper.getLoyaltyLevel(traderId, pmcData).repair_price_coef;
|
||||
const traderRepairDetails = this.traderHelper.getTrader(traderId, sessionID).repair;
|
||||
const traderRepairDetails = this.traderHelper.getTrader(traderId, sessionID)?.repair;
|
||||
if (!traderRepairDetails)
|
||||
{
|
||||
throw new Error(`Trader details for ${traderId} was not found`);
|
||||
}
|
||||
const repairQualityMultiplier = Number(traderRepairDetails.quality);
|
||||
const repairRate = priceCoef <= 0 ? 1 : priceCoef / 100 + 1;
|
||||
|
||||
const itemToRepairDetails = this.databaseServer.getTables().templates.items[itemToRepair._tpl];
|
||||
const itemToRepairDetails = this.databaseServer.getTables().templates!.items[itemToRepair._tpl];
|
||||
const repairItemIsArmor = !!itemToRepairDetails._props.ArmorMaterial;
|
||||
|
||||
this.repairHelper.updateItemDurability(
|
||||
@ -85,7 +89,11 @@ export class RepairService
|
||||
);
|
||||
|
||||
// get repair price
|
||||
const itemRepairCost = this.databaseServer.getTables().templates.items[itemToRepair._tpl]._props.RepairCost;
|
||||
const itemRepairCost = this.databaseServer.getTables().templates!.items[itemToRepair._tpl]._props.RepairCost;
|
||||
if (!itemRepairCost)
|
||||
{
|
||||
throw new Error(`Item with tpl ${itemToRepair._tpl} has no repair cost`);
|
||||
}
|
||||
const repairCost = Math.round(
|
||||
itemRepairCost * repairItemDetails.count * repairRate * this.repairConfig.priceMultiplier,
|
||||
);
|
||||
@ -186,6 +194,10 @@ export class RepairService
|
||||
|
||||
const isHeavyArmor = itemDetails[1]._props.ArmorType === "Heavy";
|
||||
const vestSkillToLevel = isHeavyArmor ? SkillTypes.HEAVY_VESTS : SkillTypes.LIGHT_VESTS;
|
||||
if (!repairDetails.repairPoints)
|
||||
{
|
||||
throw new Error(`Repair for ${repairDetails.repairedItem._tpl} has no repair points`);
|
||||
}
|
||||
const pointsToAddToVestSkill
|
||||
= repairDetails.repairPoints * this.repairConfig.armorKitSkillPointGainPerRepairPointMultiplier;
|
||||
|
||||
@ -215,6 +227,10 @@ export class RepairService
|
||||
: this.repairConfig.repairKitIntellectGainMultiplier.armor;
|
||||
|
||||
// Limit gain to a max value defined in config.maxIntellectGainPerRepair
|
||||
if (!repairDetails.repairPoints)
|
||||
{
|
||||
throw new Error(`Repair for ${repairDetails.repairedItem._tpl} has no repair points`);
|
||||
}
|
||||
return Math.min(
|
||||
repairDetails.repairPoints * intRepairMultiplier,
|
||||
this.repairConfig.maxIntellectGainPerRepair.kit,
|
||||
@ -284,7 +300,7 @@ export class RepairService
|
||||
throw new Error(`Item ${itemToRepairId} not found, unable to repair`);
|
||||
}
|
||||
|
||||
const itemsDb = this.databaseServer.getTables().templates.items;
|
||||
const itemsDb = this.databaseServer.getTables().templates!.items;
|
||||
const itemToRepairDetails = itemsDb[itemToRepair._tpl];
|
||||
const repairItemIsArmor = !!itemToRepairDetails._props.ArmorMaterial;
|
||||
const repairAmount = repairKits[0].count / this.getKitDivisor(itemToRepairDetails, repairItemIsArmor, pmcData);
|
||||
@ -307,13 +323,17 @@ export class RepairService
|
||||
for (const repairKit of repairKits)
|
||||
{
|
||||
const repairKitInInventory = pmcData.Inventory.items.find((x) => x._id === repairKit._id);
|
||||
if (!repairKitInInventory)
|
||||
{
|
||||
throw new Error(`Repair kit with id ${repairKit._id} was not found in the inventory`);
|
||||
}
|
||||
const repairKitDetails = itemsDb[repairKitInInventory._tpl];
|
||||
const repairKitReductionAmount = repairKit.count;
|
||||
|
||||
this.addMaxResourceToKitIfMissing(repairKitDetails, repairKitInInventory);
|
||||
|
||||
// reduce usages on repairkit used
|
||||
repairKitInInventory.upd.RepairKit.Resource -= repairKitReductionAmount;
|
||||
repairKitInInventory.upd!.RepairKit!.Resource -= repairKitReductionAmount;
|
||||
|
||||
output.profileChanges[sessionId].items.change.push(repairKitInInventory);
|
||||
}
|
||||
@ -336,7 +356,7 @@ export class RepairService
|
||||
*/
|
||||
protected getKitDivisor(itemToRepairDetails: ITemplateItem, isArmor: boolean, pmcData: IPmcData): number
|
||||
{
|
||||
const globals = this.databaseServer.getTables().globals;
|
||||
const globals = this.databaseServer.getTables().globals!;
|
||||
const globalRepairSettings = globals.config.RepairSettings;
|
||||
|
||||
const intellectRepairPointsPerLevel = globals.config.SkillsSettings.Intellect.RepairPointsCostReduction;
|
||||
@ -376,10 +396,10 @@ export class RepairService
|
||||
{
|
||||
const bonusesMatched = pmcData?.Bonuses?.filter((b) => b.type === skillBonus);
|
||||
let value = 1;
|
||||
if (bonusesMatched != null)
|
||||
if (bonusesMatched)
|
||||
{
|
||||
const sumedPercentage = bonusesMatched.map((b) => b.value).reduce((v1, v2) => v1 + v2, 0);
|
||||
value = 1 + sumedPercentage / 100;
|
||||
const summedPercentage = bonusesMatched.map((b) => b.value ?? 0).reduce((v1, v2) => v1 + v2, 0);
|
||||
value = 1 + summedPercentage / 100;
|
||||
}
|
||||
|
||||
return value;
|
||||
@ -415,7 +435,7 @@ export class RepairService
|
||||
*/
|
||||
protected addMaxResourceToKitIfMissing(repairKitDetails: ITemplateItem, repairKitInInventory: Item): void
|
||||
{
|
||||
const maxRepairAmount = repairKitDetails._props.MaxRepairResource;
|
||||
const maxRepairAmount = repairKitDetails._props.MaxRepairResource!;
|
||||
if (!repairKitInInventory.upd)
|
||||
{
|
||||
this.logger.debug(`Repair kit: ${repairKitInInventory._id} in inventory lacks upd object, adding`);
|
||||
@ -478,13 +498,13 @@ export class RepairService
|
||||
const bonusThresholdPercents = itemConfig[bonusRarity][bonusType].activeDurabilityPercentMinMax;
|
||||
const bonusThresholdPercent = this.randomUtil.getInt(bonusThresholdPercents.min, bonusThresholdPercents.max);
|
||||
|
||||
item.upd.Buff = {
|
||||
item.upd!.Buff = {
|
||||
rarity: bonusRarity,
|
||||
buffType: bonusType,
|
||||
value: bonusValue,
|
||||
thresholdDurability: this.randomUtil.getPercentOfValue(
|
||||
bonusThresholdPercent,
|
||||
item.upd.Repairable.Durability,
|
||||
item.upd!.Repairable!.Durability,
|
||||
),
|
||||
};
|
||||
}
|
||||
@ -498,7 +518,7 @@ export class RepairService
|
||||
*/
|
||||
protected shouldBuffItem(repairDetails: RepairDetails, pmcData: IPmcData): boolean
|
||||
{
|
||||
const globals = this.databaseServer.getTables().globals;
|
||||
const globals = this.databaseServer.getTables().globals!;
|
||||
|
||||
const hasTemplate = this.itemHelper.getItem(repairDetails.repairedItem._tpl);
|
||||
if (!hasTemplate[0])
|
||||
@ -542,7 +562,11 @@ export class RepairService
|
||||
(this.profileHelper.getSkillFromProfile(pmcData, itemSkillType)?.Progress ?? 0) / 100,
|
||||
);
|
||||
|
||||
const durabilityToRestorePercent = repairDetails.repairPoints / template._props.MaxDurability;
|
||||
if (!repairDetails.repairPoints)
|
||||
{
|
||||
throw new Error(`Repair for ${repairDetails.repairedItem._tpl} has no repair points`);
|
||||
}
|
||||
const durabilityToRestorePercent = repairDetails.repairPoints / template._props.MaxDurability!;
|
||||
const durabilityMultiplier = this.getDurabilityMultiplier(
|
||||
receivedDurabilityMaxPercent,
|
||||
durabilityToRestorePercent,
|
||||
|
@ -27,8 +27,8 @@ export class SeasonalEventService
|
||||
protected httpConfig: IHttpConfig;
|
||||
protected weatherConfig: IWeatherConfig;
|
||||
|
||||
protected halloweenEventActive: boolean = undefined;
|
||||
protected christmasEventActive: boolean = undefined;
|
||||
protected halloweenEventActive?: boolean = undefined;
|
||||
protected christmasEventActive?: boolean = undefined;
|
||||
|
||||
/** All events active at this point in time */
|
||||
protected currentlyActiveEvents: SeasonalEventType[] = [];
|
||||
@ -128,7 +128,7 @@ export class SeasonalEventService
|
||||
*/
|
||||
public getInactiveSeasonalEventItems(): string[]
|
||||
{
|
||||
const items = [];
|
||||
const items: string[] = [];
|
||||
if (!this.christmasEventEnabled())
|
||||
{
|
||||
items.push(...this.christmasEventItems);
|
||||
@ -157,7 +157,7 @@ export class SeasonalEventService
|
||||
*/
|
||||
public christmasEventEnabled(): boolean
|
||||
{
|
||||
return this.christmasEventActive;
|
||||
return this.christmasEventActive ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -166,7 +166,7 @@ export class SeasonalEventService
|
||||
*/
|
||||
public halloweenEventEnabled(): boolean
|
||||
{
|
||||
return this.halloweenEventActive;
|
||||
return this.halloweenEventActive ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -222,7 +222,7 @@ export class SeasonalEventService
|
||||
{
|
||||
if (this.currentlyActiveEvents)
|
||||
{
|
||||
const globalConfig = this.databaseServer.getTables().globals.config;
|
||||
const globalConfig = this.databaseServer.getTables().globals!.config;
|
||||
for (const event of this.currentlyActiveEvents)
|
||||
{
|
||||
this.updateGlobalEvents(sessionId, globalConfig, event);
|
||||
@ -405,12 +405,12 @@ export class SeasonalEventService
|
||||
|
||||
protected adjustZryachiyMeleeChance(): void
|
||||
{
|
||||
this.databaseServer.getTables().bots.types.bosszryachiy.chances.equipment.Scabbard = 100;
|
||||
this.databaseServer.getTables().bots!.types.bosszryachiy.chances.equipment.Scabbard = 100;
|
||||
}
|
||||
|
||||
protected enableHalloweenSummonEvent(): void
|
||||
{
|
||||
this.databaseServer.getTables().globals.config.EventSettings.EventActive = true;
|
||||
this.databaseServer.getTables().globals!.config.EventSettings.EventActive = true;
|
||||
}
|
||||
|
||||
protected addEventBossesToMaps(eventType: SeasonalEventType): void
|
||||
@ -434,10 +434,10 @@ export class SeasonalEventService
|
||||
for (const boss of bossesToAdd)
|
||||
{
|
||||
const mapBosses: BossLocationSpawn[]
|
||||
= this.databaseServer.getTables().locations[mapKey].base.BossLocationSpawn;
|
||||
= this.databaseServer.getTables().locations![mapKey].base.BossLocationSpawn;
|
||||
if (!mapBosses.find((x) => x.BossName === boss.BossName))
|
||||
{
|
||||
this.databaseServer.getTables().locations[mapKey].base.BossLocationSpawn.push(...bossesToAdd);
|
||||
this.databaseServer.getTables().locations![mapKey].base.BossLocationSpawn.push(...bossesToAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -486,7 +486,7 @@ export class SeasonalEventService
|
||||
*/
|
||||
protected addLootItemsToGifterDropItemsList(): void
|
||||
{
|
||||
const gifterBot = this.databaseServer.getTables().bots.types.gifter;
|
||||
const gifterBot = this.databaseServer.getTables().bots!.types.gifter;
|
||||
for (const difficulty in gifterBot.difficulty)
|
||||
{
|
||||
gifterBot.difficulty[difficulty].Patrol.ITEMS_TO_DROP = Object.keys(
|
||||
@ -512,7 +512,7 @@ export class SeasonalEventService
|
||||
// Iterate over bots with changes to apply
|
||||
for (const bot in botGearChanges)
|
||||
{
|
||||
const botToUpdate = this.databaseServer.getTables().bots.types[bot.toLowerCase()];
|
||||
const botToUpdate = this.databaseServer.getTables().bots!.types[bot.toLowerCase()];
|
||||
if (!botToUpdate)
|
||||
{
|
||||
this.logger.warning(this.localisationService.getText("gameevent-bot_not_found", bot));
|
||||
@ -541,7 +541,7 @@ export class SeasonalEventService
|
||||
|
||||
protected addPumpkinsToScavBackpacks(): void
|
||||
{
|
||||
this.databaseServer.getTables().bots.types.assault.inventory.items.Backpack["634959225289190e5e773b3b"] = 400;
|
||||
this.databaseServer.getTables().bots!.types.assault.inventory.items.Backpack["634959225289190e5e773b3b"] = 400;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -572,7 +572,7 @@ export class SeasonalEventService
|
||||
protected addGifterBotToMaps(): void
|
||||
{
|
||||
const gifterSettings = this.seasonalEventConfig.gifterSettings;
|
||||
const maps = this.databaseServer.getTables().locations;
|
||||
const maps = this.databaseServer.getTables().locations!;
|
||||
for (const gifterMapSettings of gifterSettings)
|
||||
{
|
||||
const mapData: ILocation = maps[gifterMapSettings.map];
|
||||
|
@ -35,13 +35,13 @@ export class TraderPurchasePersisterService
|
||||
* @param traderId Trader to loop up purchases for
|
||||
* @returns Dict of assort id and count purchased
|
||||
*/
|
||||
public getProfileTraderPurchases(sessionId: string, traderId: string): Record<string, TraderPurchaseData>
|
||||
public getProfileTraderPurchases(sessionId: string, traderId: string): Record<string, TraderPurchaseData> | undefined
|
||||
{
|
||||
const profile = this.profileHelper.getFullProfile(sessionId);
|
||||
|
||||
if (!profile.traderPurchases)
|
||||
{
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return profile.traderPurchases[traderId];
|
||||
@ -54,19 +54,20 @@ export class TraderPurchasePersisterService
|
||||
* @param assortId Id of assort to get data for
|
||||
* @returns TraderPurchaseData
|
||||
*/
|
||||
public getProfileTraderPurchase(sessionId: string, traderId: string, assortId: string): TraderPurchaseData
|
||||
public getProfileTraderPurchase(sessionId: string, traderId: string, assortId: string):
|
||||
TraderPurchaseData | undefined
|
||||
{
|
||||
const profile = this.profileHelper.getFullProfile(sessionId);
|
||||
|
||||
if (!profile.traderPurchases)
|
||||
{
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const traderPurchases = profile.traderPurchases[traderId];
|
||||
if (!traderPurchases)
|
||||
{
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return traderPurchases[assortId];
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
|
||||
import { QuestStatus } from "@spt/models/enums/QuestStatus";
|
||||
import { TraderServiceType } from "@spt/models/enums/TraderServiceType";
|
||||
import { ITraderServiceModel } from "@spt/models/spt/services/ITraderServiceModel";
|
||||
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import { DatabaseServer } from "@spt/servers/DatabaseServer";
|
||||
@ -20,14 +21,14 @@ export class TraderServicesService
|
||||
public getTraderServices(sessionId: string, traderId: string): ITraderServiceModel[]
|
||||
{
|
||||
const pmcData = this.profileHelper.getPmcProfile(sessionId);
|
||||
let traderServices = this.cloner.clone(this.databaseServer.getTables().traders[traderId]?.services);
|
||||
let traderServices = this.cloner.clone(this.databaseServer.getTables().traders![traderId]?.services);
|
||||
if (!traderServices)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
// Filter out any service the user doesn't meet the conditions for
|
||||
const servicesToDelete = [];
|
||||
const servicesToDelete: TraderServiceType[] = [];
|
||||
for (const service of traderServices)
|
||||
{
|
||||
if (service.requirements?.standings)
|
||||
|
@ -27,6 +27,6 @@ export class AsyncQueue implements IAsyncQueue
|
||||
}
|
||||
|
||||
// When the command is ready, execute it
|
||||
return this.commandsQueue.shift().cmd();
|
||||
return this.commandsQueue.shift()!.cmd();
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ export class HttpFileUtil
|
||||
{
|
||||
const pathSlic = filePath.split("/");
|
||||
const type
|
||||
= this.httpServerHelper.getMimeText(pathSlic[pathSlic.length - 1].split(".").at(-1))
|
||||
= this.httpServerHelper.getMimeText(pathSlic[pathSlic.length - 1].split(".").at(-1) ?? "")
|
||||
|| this.httpServerHelper.getMimeText("txt");
|
||||
const fileStream = fs.createReadStream(filePath);
|
||||
|
||||
|
@ -42,14 +42,14 @@ export class HttpResponseUtil
|
||||
* @param errmsg
|
||||
* @returns
|
||||
*/
|
||||
public getBody<T>(data: T, err = 0, errmsg = null, sanitize = true): IGetBodyResponseData<T>
|
||||
public getBody<T>(data: T, err: number = 0, errmsg?: string, sanitize = true): IGetBodyResponseData<T>
|
||||
{
|
||||
return sanitize
|
||||
? this.clearString(this.getUnclearedBody(data, err, errmsg))
|
||||
: (this.getUnclearedBody(data, err, errmsg) as any);
|
||||
}
|
||||
|
||||
public getUnclearedBody(data: any, err = 0, errmsg = null): string
|
||||
public getUnclearedBody(data: any, err: number = 0, errmsg?: string): string
|
||||
{
|
||||
return this.jsonUtil.serialize({ err: err, errmsg: errmsg, data: data });
|
||||
}
|
||||
@ -61,7 +61,7 @@ export class HttpResponseUtil
|
||||
|
||||
public nullResponse(): INullResponseData
|
||||
{
|
||||
return this.clearString(this.getUnclearedBody(null, 0, null));
|
||||
return this.clearString(this.getUnclearedBody(null, 0, undefined));
|
||||
}
|
||||
|
||||
public emptyArrayResponse(): IGetBodyResponseData<any[]>
|
||||
|
@ -57,7 +57,7 @@ export class ImporterUtil
|
||||
}
|
||||
|
||||
// set all loadRecursive to be executed asynchronously
|
||||
const resEntries = Object.entries(result);
|
||||
const resEntries = Object.entries(result!);
|
||||
const resResolved = await Promise.all(resEntries.map((ent) => ent[1]));
|
||||
for (let resIdx = 0; resIdx < resResolved.length; resIdx++)
|
||||
{
|
||||
@ -136,6 +136,8 @@ export class ImporterUtil
|
||||
while (directoriesToRead.length !== 0)
|
||||
{
|
||||
const directory = directoriesToRead.dequeue();
|
||||
if (!directory)
|
||||
continue;
|
||||
filesToProcess.enqueueAll(this.vfs.getFiles(directory).map((f) => new VisitNode(`${directory}/`, f)));
|
||||
directoriesToRead.enqueueAll(this.vfs.getDirs(directory).map((d) => `${directory}/${d}`));
|
||||
}
|
||||
@ -143,6 +145,8 @@ export class ImporterUtil
|
||||
while (filesToProcess.length !== 0)
|
||||
{
|
||||
const fileNode = filesToProcess.dequeue();
|
||||
if (!fileNode)
|
||||
continue;
|
||||
if (this.vfs.getFileExtension(fileNode.fileName) === "json")
|
||||
{
|
||||
const filePathAndName = `${fileNode.filePath}${fileNode.fileName}`;
|
||||
|
@ -10,7 +10,7 @@ import { VFS } from "@spt/utils/VFS";
|
||||
@injectable()
|
||||
export class JsonUtil
|
||||
{
|
||||
protected fileHashes = null;
|
||||
protected fileHashes?: Map<string, string> = undefined;
|
||||
protected jsonCacheExists = false;
|
||||
protected jsonCachePath = "./user/cache/jsonCache.json";
|
||||
|
||||
@ -60,7 +60,7 @@ export class JsonUtil
|
||||
* @param options Stringify options or a replacer.
|
||||
* @returns The string converted from the JavaScript value
|
||||
*/
|
||||
public serializeJsonC(data: any, filename?: string | null, options?: IStringifyOptions | Reviver): string
|
||||
public serializeJsonC(data: any, filename?: string | null, options?: IStringifyOptions | Reviver): string | undefined
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -74,7 +74,7 @@ export class JsonUtil
|
||||
}
|
||||
}
|
||||
|
||||
public serializeJson5(data: any, filename?: string | null, prettify = false): string
|
||||
public serializeJson5(data: any, filename?: string | null, prettify = false): string | undefined
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -99,7 +99,7 @@ export class JsonUtil
|
||||
* @param filename Name of file being deserialized
|
||||
* @returns object
|
||||
*/
|
||||
public deserialize<T>(jsonString: string, filename = ""): T
|
||||
public deserialize<T>(jsonString: string, filename = ""): T | undefined
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -120,7 +120,7 @@ export class JsonUtil
|
||||
* @param options Parsing options
|
||||
* @returns object
|
||||
*/
|
||||
public deserializeJsonC<T>(jsonString: string, filename = "", options?: IParseOptions): T
|
||||
public deserializeJsonC<T>(jsonString: string, filename = "", options?: IParseOptions): T | undefined
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -134,7 +134,7 @@ export class JsonUtil
|
||||
}
|
||||
}
|
||||
|
||||
public deserializeJson5<T>(jsonString: string, filename = ""): T
|
||||
public deserializeJson5<T>(jsonString: string, filename = ""): T | undefined
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -148,7 +148,7 @@ export class JsonUtil
|
||||
}
|
||||
}
|
||||
|
||||
public async deserializeWithCacheCheckAsync<T>(jsonString: string, filePath: string): Promise<T>
|
||||
public async deserializeWithCacheCheckAsync<T>(jsonString: string, filePath: string): Promise<T | undefined>
|
||||
{
|
||||
return new Promise((resolve) =>
|
||||
{
|
||||
@ -162,7 +162,7 @@ export class JsonUtil
|
||||
* @param filePath Path to json file being processed
|
||||
* @returns Object
|
||||
*/
|
||||
public deserializeWithCacheCheck<T>(jsonString: string, filePath: string): T
|
||||
public deserializeWithCacheCheck<T>(jsonString: string, filePath: string): T | undefined
|
||||
{
|
||||
this.ensureJsonCacheExists(this.jsonCachePath);
|
||||
this.hydrateJsonCache(this.jsonCachePath);
|
||||
@ -170,6 +170,10 @@ export class JsonUtil
|
||||
// Generate hash of string
|
||||
const generatedHash = this.hashUtil.generateSha1ForData(jsonString);
|
||||
|
||||
if (!this.fileHashes)
|
||||
{
|
||||
throw new Error("Unable to deserialize with Cache, file hashes have not been hydrated yet");
|
||||
}
|
||||
// Get hash of file and check if missing or hash mismatch
|
||||
let savedHash = this.fileHashes[filePath];
|
||||
if (!savedHash || savedHash !== generatedHash)
|
||||
|
@ -22,7 +22,7 @@ export class MathUtil
|
||||
*/
|
||||
public arrayCumsum(values: number[]): number[]
|
||||
{
|
||||
const cumsumArray = [];
|
||||
const cumsumArray: number[] = [];
|
||||
let sum = 0;
|
||||
for (let i = 0; i < values.length; i++)
|
||||
{
|
||||
@ -85,7 +85,7 @@ export class MathUtil
|
||||
* @param {array} y support points in y (of same length as x)
|
||||
* @return {number} y(xp)
|
||||
*/
|
||||
public interp1(xp: number, x: number[], y: number[]): number
|
||||
public interp1(xp: number, x: number[], y: number[]): number | undefined
|
||||
{
|
||||
if (xp > x[x.length - 1])
|
||||
{
|
||||
@ -104,5 +104,6 @@ export class MathUtil
|
||||
return y[i] + ((xp - x[i]) * (y[i + 1] - y[i])) / (x[i + 1] - x[i]);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
@ -17,29 +17,29 @@ export class RagfairOfferHolder
|
||||
this.offersByTrader = new Map();
|
||||
}
|
||||
|
||||
public getOfferById(id: string): IRagfairOffer
|
||||
public getOfferById(id: string): IRagfairOffer | undefined
|
||||
{
|
||||
if (this.offersById.has(id))
|
||||
{
|
||||
return this.offersById.get(id);
|
||||
return this.offersById.get(id)!;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public getOffersByTemplate(templateId: string): Array<IRagfairOffer>
|
||||
public getOffersByTemplate(templateId: string): Array<IRagfairOffer> | undefined
|
||||
{
|
||||
if (this.offersByTemplate.has(templateId))
|
||||
{
|
||||
return [...this.offersByTemplate.get(templateId).values()];
|
||||
return [...this.offersByTemplate.get(templateId)!.values()];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public getOffersByTrader(traderId: string): Array<IRagfairOffer>
|
||||
public getOffersByTrader(traderId: string): Array<IRagfairOffer> | undefined
|
||||
{
|
||||
if (this.offersByTrader.has(traderId))
|
||||
{
|
||||
return [...this.offersByTrader.get(traderId).values()];
|
||||
return [...this.offersByTrader.get(traderId)!.values()];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@ -70,7 +70,7 @@ export class RagfairOfferHolder
|
||||
// for this template, just dont add in more
|
||||
if (
|
||||
!(this.ragfairServerHelper.isTrader(trader) || this.ragfairServerHelper.isPlayer(trader))
|
||||
&& this.getOffersByTemplate(itemTpl)?.length >= this.maxOffersPerTemplate
|
||||
&& (this.getOffersByTemplate(itemTpl)?.length ?? 0) >= this.maxOffersPerTemplate
|
||||
)
|
||||
{
|
||||
return;
|
||||
@ -89,17 +89,23 @@ export class RagfairOfferHolder
|
||||
if (this.offersById.has(offer._id))
|
||||
{
|
||||
this.offersById.delete(offer._id);
|
||||
const traderOffers = this.offersByTrader.get(offer.user.id);
|
||||
traderOffers.delete(offer._id);
|
||||
// This was causing a memory leak, we need to make sure that we remove
|
||||
// the user ID from the cached offers after they dont have anything else
|
||||
// on the flea placed. We regenerate the ID for the NPC users, making it
|
||||
// continously grow otherwise
|
||||
if (traderOffers.size === 0)
|
||||
if (this.offersByTrader.has(offer.user.id))
|
||||
{
|
||||
this.offersByTrader.delete(offer.user.id);
|
||||
this.offersByTrader.get(offer.user.id)!.delete(offer._id);
|
||||
// This was causing a memory leak, we need to make sure that we remove
|
||||
// the user ID from the cached offers after they dont have anything else
|
||||
// on the flea placed. We regenerate the ID for the NPC users, making it
|
||||
// continously grow otherwise
|
||||
if (this.offersByTrader.get(offer.user.id)!.size === 0)
|
||||
{
|
||||
this.offersByTrader.delete(offer.user.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.offersByTemplate.has(offer.items[0]._tpl))
|
||||
{
|
||||
this.offersByTemplate.get(offer.items[0]._tpl)!.delete(offer._id);
|
||||
}
|
||||
this.offersByTemplate.get(offer.items[0]._tpl).delete(offer._id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,7 +121,7 @@ export class RagfairOfferHolder
|
||||
{
|
||||
if (this.offersByTrader.has(traderId))
|
||||
{
|
||||
this.removeOffers([...this.offersByTrader.get(traderId).values()]);
|
||||
this.removeOffers([...this.offersByTrader.get(traderId)!.values()]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,7 +138,7 @@ export class RagfairOfferHolder
|
||||
{
|
||||
if (this.offersByTemplate.has(template))
|
||||
{
|
||||
this.offersByTemplate.get(template).set(offer._id, offer);
|
||||
this.offersByTemplate.get(template)!.set(offer._id, offer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -146,7 +152,7 @@ export class RagfairOfferHolder
|
||||
{
|
||||
if (this.offersByTrader.has(trader))
|
||||
{
|
||||
this.offersByTrader.get(trader).set(offer._id, offer);
|
||||
this.offersByTrader.get(trader)!.set(offer._id, offer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -158,6 +164,6 @@ export class RagfairOfferHolder
|
||||
|
||||
protected isStale(offer: IRagfairOffer, time: number): boolean
|
||||
{
|
||||
return offer.endTime < time || offer.items[0].upd.StackObjectsCount < 1;
|
||||
return offer.endTime < time || (offer.items[0].upd?.StackObjectsCount ?? 0) < 1;
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ export class ProbabilityObjectArray<K, V = undefined> extends Array<ProbabilityO
|
||||
* @param {string} key The key of the element whose data shall be retrieved
|
||||
* @returns {object} The data object
|
||||
*/
|
||||
data(key: K): V
|
||||
data(key: K): V | undefined
|
||||
{
|
||||
return this.filter((r) => r.key === key)[0]?.data;
|
||||
}
|
||||
@ -151,11 +151,11 @@ export class ProbabilityObjectArray<K, V = undefined> extends Array<ProbabilityO
|
||||
acc.keyArray.push(x.key);
|
||||
return acc;
|
||||
},
|
||||
{ probArray: [], keyArray: [] },
|
||||
{ probArray: new Array<number>(), keyArray: new Array<K>() },
|
||||
);
|
||||
let probCumsum = this.cumulativeProbability(probArray);
|
||||
|
||||
const drawnKeys = [];
|
||||
const drawnKeys: K[] = [];
|
||||
for (let i = 0; i < count; i++)
|
||||
{
|
||||
const rand = Math.random();
|
||||
@ -193,14 +193,14 @@ export class ProbabilityObject<K, V = undefined>
|
||||
{
|
||||
key: K;
|
||||
relativeProbability: number;
|
||||
data: V;
|
||||
data?: V;
|
||||
/**
|
||||
* Constructor for the ProbabilityObject
|
||||
* @param {string} key The key of the element
|
||||
* @param {number} relativeProbability The relative probability of this element
|
||||
* @param {any} data Optional data attached to the element
|
||||
*/
|
||||
constructor(key: K, relativeProbability: number, data: V = null)
|
||||
constructor(key: K, relativeProbability: number, data?: V)
|
||||
{
|
||||
this.key = key;
|
||||
this.relativeProbability = relativeProbability;
|
||||
@ -354,7 +354,7 @@ export class RandomUtil
|
||||
list = this.cloner.clone(originalList);
|
||||
}
|
||||
|
||||
const results = [];
|
||||
const results: T[] = [];
|
||||
for (let i = 0; i < count; i++)
|
||||
{
|
||||
const randomIndex = this.randInt(list.length);
|
||||
|
@ -14,7 +14,11 @@ export class VFS
|
||||
{
|
||||
accessFilePromisify: (path: fs.PathLike, mode?: number) => Promise<void>;
|
||||
copyFilePromisify: (src: fs.PathLike, dst: fs.PathLike, flags?: number) => Promise<void>;
|
||||
mkdirPromisify: (path: fs.PathLike, options: fs.MakeDirectoryOptions & { recursive: true }) => Promise<string>;
|
||||
mkdirPromisify: (
|
||||
path: fs.PathLike,
|
||||
options: fs.MakeDirectoryOptions & { recursive: true }
|
||||
) => Promise<string | undefined>;
|
||||
|
||||
readFilePromisify: (path: fs.PathLike) => Promise<Buffer>;
|
||||
writeFilePromisify: (path: fs.PathLike, data: string, options?: any) => Promise<void>;
|
||||
readdirPromisify: (
|
||||
@ -91,7 +95,7 @@ export class VFS
|
||||
await this.asyncQueue.waitFor(command);
|
||||
}
|
||||
|
||||
public copyDir(filepath: string, target: string, fileExtensions: string | string[] = undefined): void
|
||||
public copyDir(filepath: string, target: string, fileExtensions?: string | string[]): void
|
||||
{
|
||||
const files = this.getFiles(filepath);
|
||||
const dirs = this.getDirs(filepath);
|
||||
@ -109,7 +113,7 @@ export class VFS
|
||||
for (const file of files)
|
||||
{
|
||||
// copy all if fileExtension is not set, copy only those with fileExtension if set
|
||||
if (!fileExtensions || fileExtensions.includes(file.split(".").pop()))
|
||||
if (!fileExtensions || fileExtensions.includes(file.split(".").pop() ?? ""))
|
||||
{
|
||||
this.copyFile(path.join(filepath, file), path.join(target, file));
|
||||
}
|
||||
@ -134,7 +138,7 @@ export class VFS
|
||||
for (const file of files)
|
||||
{
|
||||
// copy all if fileExtension is not set, copy only those with fileExtension if set
|
||||
if (!fileExtensions || fileExtensions.includes(file.split(".").pop()))
|
||||
if (!fileExtensions || fileExtensions.includes(file.split(".").pop() ?? ""))
|
||||
{
|
||||
await this.copyAsync(path.join(filepath, file), path.join(target, file));
|
||||
}
|
||||
@ -279,7 +283,7 @@ export class VFS
|
||||
const files = this.getFiles(filepath);
|
||||
const dirs = this.getDirs(filepath);
|
||||
|
||||
const promises = [];
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
for (const dir of dirs)
|
||||
{
|
||||
@ -288,7 +292,7 @@ export class VFS
|
||||
|
||||
for (const file of files)
|
||||
{
|
||||
promises.push(this.removeFile(path.join(filepath, file)));
|
||||
promises.push(this.removeFileAsync(path.join(filepath, file)));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
@ -320,7 +324,7 @@ export class VFS
|
||||
unlockSync(filepath);
|
||||
}
|
||||
|
||||
public getFileExtension(filepath: string): string
|
||||
public getFileExtension(filepath: string): string | undefined
|
||||
{
|
||||
return filepath.split(".").pop();
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ export class Watermark
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("WatermarkLocale") protected watermarkLocale?: WatermarkLocale,
|
||||
@inject("WatermarkLocale") protected watermarkLocale: WatermarkLocale,
|
||||
)
|
||||
{
|
||||
this.sptConfig = this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE);
|
||||
@ -95,11 +95,14 @@ export class Watermark
|
||||
this.text = this.text.concat([...modding]);
|
||||
}
|
||||
|
||||
if (this.sptConfig.customWatermarkLocaleKeys?.length > 0)
|
||||
if (this.sptConfig.customWatermarkLocaleKeys)
|
||||
{
|
||||
for (const key of this.sptConfig.customWatermarkLocaleKeys)
|
||||
if (this.sptConfig.customWatermarkLocaleKeys.length > 0)
|
||||
{
|
||||
this.text.push(...["", this.localisationService.getText(key)]);
|
||||
for (const key of this.sptConfig.customWatermarkLocaleKeys)
|
||||
{
|
||||
this.text.push(...["", this.localisationService.getText(key)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,7 +162,7 @@ export class Watermark
|
||||
/** Draw the watermark */
|
||||
protected draw(): void
|
||||
{
|
||||
const result = [];
|
||||
const result: string[] = [];
|
||||
|
||||
// Calculate size, add 10% for spacing to the right
|
||||
const longestLength
|
||||
|
@ -66,15 +66,18 @@ export class LinkedList<T>
|
||||
let ref = this.head;
|
||||
for (let i = 0; i <= idx; ++i)
|
||||
{
|
||||
ref = ref.next;
|
||||
ref = ref?.next;
|
||||
}
|
||||
|
||||
const node = new LinkedListNode(value);
|
||||
this.length++;
|
||||
|
||||
node.next = ref;
|
||||
node.prev = ref.prev;
|
||||
ref.prev = node;
|
||||
node.prev = ref?.prev;
|
||||
if (ref)
|
||||
{
|
||||
ref.prev = node;
|
||||
}
|
||||
|
||||
if (node.prev)
|
||||
{
|
||||
@ -104,7 +107,7 @@ export class LinkedList<T>
|
||||
/**
|
||||
* Returns the first element's value.
|
||||
*/
|
||||
public getHead(): T
|
||||
public getHead(): T | undefined
|
||||
{
|
||||
return this.head?.value;
|
||||
}
|
||||
@ -112,7 +115,7 @@ export class LinkedList<T>
|
||||
/**
|
||||
* Finds the element from the list at the given index and returns it's value.
|
||||
*/
|
||||
public get(idx: number): T
|
||||
public get(idx: number): T | undefined
|
||||
{
|
||||
if (idx < 0 || idx >= this.length)
|
||||
{
|
||||
@ -141,7 +144,7 @@ export class LinkedList<T>
|
||||
/**
|
||||
* Returns the last element's value.
|
||||
*/
|
||||
public getTail(): T
|
||||
public getTail(): T | undefined
|
||||
{
|
||||
return this.tail?.value;
|
||||
}
|
||||
@ -149,7 +152,7 @@ export class LinkedList<T>
|
||||
/**
|
||||
* Finds and removes the first element from a list that has a value equal to the given value, returns it's value if it successfully removed it.
|
||||
*/
|
||||
public remove(value: T): T
|
||||
public remove(value: T): T | undefined
|
||||
{
|
||||
let ref = this.head;
|
||||
for (let i = 0; ref && i < this.length; ++i)
|
||||
@ -170,7 +173,7 @@ export class LinkedList<T>
|
||||
|
||||
if (this.length === 0)
|
||||
{
|
||||
const out = this.head.value;
|
||||
const out = this.head?.value;
|
||||
this.head = this.tail = undefined;
|
||||
return out;
|
||||
}
|
||||
@ -202,7 +205,7 @@ export class LinkedList<T>
|
||||
/**
|
||||
* Removes the first element from the list and returns it's value. If the list is empty, undefined is returned and the list is not modified.
|
||||
*/
|
||||
public shift(): T
|
||||
public shift(): T | undefined
|
||||
{
|
||||
if (!this.head)
|
||||
{
|
||||
@ -227,7 +230,7 @@ export class LinkedList<T>
|
||||
/**
|
||||
* Removes the element from the list at the given index and returns it's value.
|
||||
*/
|
||||
public removeAt(idx: number): T
|
||||
public removeAt(idx: number): T | undefined
|
||||
{
|
||||
if (idx < 0 || idx >= this.length)
|
||||
{
|
||||
@ -249,25 +252,25 @@ export class LinkedList<T>
|
||||
|
||||
for (let i = 0; i < idx; ++i)
|
||||
{
|
||||
ref = ref.next;
|
||||
ref = ref?.next;
|
||||
}
|
||||
|
||||
if (ref.prev)
|
||||
if (ref?.prev)
|
||||
{
|
||||
ref.prev.next = ref.next;
|
||||
}
|
||||
if (ref.next)
|
||||
if (ref?.next)
|
||||
{
|
||||
ref.next.prev = ref.prev;
|
||||
}
|
||||
|
||||
return ref.value;
|
||||
return ref?.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the last element from the list and returns it's value. If the list is empty, undefined is returned and the list is not modified.
|
||||
*/
|
||||
public pop(): T
|
||||
public pop(): T | undefined
|
||||
{
|
||||
if (!this.tail)
|
||||
{
|
||||
@ -292,13 +295,13 @@ export class LinkedList<T>
|
||||
/**
|
||||
* Returns an iterable of index, value pairs for every entry in the list.
|
||||
*/
|
||||
public *entries(): IterableIterator<[number, T]>
|
||||
public *entries(): IterableIterator<[number, T | undefined]>
|
||||
{
|
||||
let node = this.head;
|
||||
for (let i = 0; i < this.length; ++i)
|
||||
{
|
||||
yield [i, node.value];
|
||||
node = node.next;
|
||||
yield [i, node?.value];
|
||||
node = node?.next;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ export class Queue<T>
|
||||
/**
|
||||
* Removes the first element from the queue and returns it's value. If the queue is empty, undefined is returned and the queue is not modified.
|
||||
*/
|
||||
public dequeue(): T
|
||||
public dequeue(): T | undefined
|
||||
{
|
||||
return this.list.shift();
|
||||
}
|
||||
@ -44,7 +44,7 @@ export class Queue<T>
|
||||
/**
|
||||
* Returns the first element's value.
|
||||
*/
|
||||
public peek(): T
|
||||
public peek(): T | undefined
|
||||
{
|
||||
return this.list.getHead();
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ export abstract class AbstractWinstonLogger implements ILogger
|
||||
process.on("uncaughtException", (error) =>
|
||||
{
|
||||
this.error(`${error.name}: ${error.message}`);
|
||||
this.error(error.stack);
|
||||
this.error(error.stack ?? "No stack");
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -184,7 +184,7 @@ export abstract class AbstractWinstonLogger implements ILogger
|
||||
|
||||
public async success(data: string | Record<string, unknown>): Promise<void>
|
||||
{
|
||||
const command: ICommand = { uuid: crypto.randomUUID(), cmd: async () => await this.logger.succ(data) };
|
||||
const command: ICommand = { uuid: crypto.randomUUID(), cmd: async () => await this.logger.succ!(data) };
|
||||
await this.asyncQueue.waitFor(command);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "./tsconfig.base.json",
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"strictNullChecks": true,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user