Merge branch 'master' of https://dev.sp-tarkov.com/SPT-AKI/Server into 3.8.0
# Conflicts: # project/assets/configs/core.json # project/src/controllers/DialogueController.ts
This commit is contained in:
commit
db70e8e4bc
@ -11,6 +11,7 @@
|
|||||||
"plugin:@typescript-eslint/eslint-recommended"
|
"plugin:@typescript-eslint/eslint-recommended"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"brace-style": ["error", "allman"],
|
||||||
"@typescript-eslint/no-namespace": "off",
|
"@typescript-eslint/no-namespace": "off",
|
||||||
"@typescript-eslint/no-empty-interface": "off",
|
"@typescript-eslint/no-empty-interface": "off",
|
||||||
"@typescript-eslint/no-explicit-any": "off", // We use a bunch of these.
|
"@typescript-eslint/no-explicit-any": "off", // We use a bunch of these.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"akiVersion": "3.8.0",
|
"akiVersion": "3.7.6",
|
||||||
"projectName": "SPT-AKI",
|
"projectName": "SPT-AKI",
|
||||||
"compatibleTarkovVersion": "0.13.9.27050",
|
"compatibleTarkovVersion": "0.13.5.26535",
|
||||||
"serverName": "SPT Server",
|
"serverName": "SPT Server",
|
||||||
"profileSaveIntervalSeconds": 15,
|
"profileSaveIntervalSeconds": 15,
|
||||||
"sptFriendNickname": "SPT",
|
"sptFriendNickname": "SPT",
|
||||||
@ -11,6 +11,14 @@
|
|||||||
"fixProfileBreakingInventoryItemIssues": false
|
"fixProfileBreakingInventoryItemIssues": false
|
||||||
},
|
},
|
||||||
"features": {
|
"features": {
|
||||||
"autoInstallModDependencies": false
|
"autoInstallModDependencies": false,
|
||||||
|
"compressProfile": false,
|
||||||
|
"chatbotFeatures": {
|
||||||
|
"sptFriendEnabled": true,
|
||||||
|
"commandoEnabled": true,
|
||||||
|
"commandoFeatures": {
|
||||||
|
"giveCommandEnabled": false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1552,8 +1552,7 @@
|
|||||||
"types": [
|
"types": [
|
||||||
"Exploration",
|
"Exploration",
|
||||||
"Elimination",
|
"Elimination",
|
||||||
"Completion",
|
"Completion"
|
||||||
"Pickup"
|
|
||||||
],
|
],
|
||||||
"resetTime": 86400,
|
"resetTime": 86400,
|
||||||
"numQuests": 1,
|
"numQuests": 1,
|
||||||
|
@ -90,7 +90,7 @@ export class DialogueCallbacks implements OnUpdate
|
|||||||
sessionID: string,
|
sessionID: string,
|
||||||
): IGetBodyResponseData<DialogueInfo[]>
|
): IGetBodyResponseData<DialogueInfo[]>
|
||||||
{
|
{
|
||||||
return this.httpResponse.getBody(this.dialogueController.generateDialogueList(sessionID));
|
return this.httpResponse.getBody(this.dialogueController.generateDialogueList(sessionID), 0, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handle client/mail/dialog/view */
|
/** Handle client/mail/dialog/view */
|
||||||
@ -100,7 +100,7 @@ export class DialogueCallbacks implements OnUpdate
|
|||||||
sessionID: string,
|
sessionID: string,
|
||||||
): IGetBodyResponseData<IGetMailDialogViewResponseData>
|
): IGetBodyResponseData<IGetMailDialogViewResponseData>
|
||||||
{
|
{
|
||||||
return this.httpResponse.getBody(this.dialogueController.generateDialogueView(info, sessionID));
|
return this.httpResponse.getBody(this.dialogueController.generateDialogueView(info, sessionID), 0, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handle client/mail/dialog/info */
|
/** Handle client/mail/dialog/info */
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectAll, injectable } from "tsyringe";
|
||||||
|
|
||||||
|
import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot";
|
||||||
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
|
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
|
||||||
import { IGetAllAttachmentsResponse } from "@spt-aki/models/eft/dialog/IGetAllAttachmentsResponse";
|
import { IGetAllAttachmentsResponse } from "@spt-aki/models/eft/dialog/IGetAllAttachmentsResponse";
|
||||||
import { IGetFriendListDataResponse } from "@spt-aki/models/eft/dialog/IGetFriendListDataResponse";
|
import { IGetFriendListDataResponse } from "@spt-aki/models/eft/dialog/IGetFriendListDataResponse";
|
||||||
import { IGetMailDialogViewRequestData } from "@spt-aki/models/eft/dialog/IGetMailDialogViewRequestData";
|
import { IGetMailDialogViewRequestData } from "@spt-aki/models/eft/dialog/IGetMailDialogViewRequestData";
|
||||||
@ -9,38 +9,50 @@ import { IGetMailDialogViewResponseData } from "@spt-aki/models/eft/dialog/IGetM
|
|||||||
import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest";
|
import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest";
|
||||||
import { Dialogue, DialogueInfo, IAkiProfile, IUserDialogInfo, Message } from "@spt-aki/models/eft/profile/IAkiProfile";
|
import { Dialogue, DialogueInfo, IAkiProfile, IUserDialogInfo, Message } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
import { GiftSentResult } from "@spt-aki/models/enums/GiftSentResult";
|
|
||||||
import { MemberCategory } from "@spt-aki/models/enums/MemberCategory";
|
|
||||||
import { MessageType } from "@spt-aki/models/enums/MessageType";
|
import { MessageType } from "@spt-aki/models/enums/MessageType";
|
||||||
import { ICoreConfig } from "@spt-aki/models/spt/config/ICoreConfig";
|
import { ICoreConfig } from "@spt-aki/models/spt/config/ICoreConfig";
|
||||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||||
import { SaveServer } from "@spt-aki/servers/SaveServer";
|
import { SaveServer } from "@spt-aki/servers/SaveServer";
|
||||||
import { GiftService } from "@spt-aki/services/GiftService";
|
|
||||||
import { MailSendService } from "@spt-aki/services/MailSendService";
|
import { MailSendService } from "@spt-aki/services/MailSendService";
|
||||||
import { HashUtil } from "@spt-aki/utils/HashUtil";
|
|
||||||
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
|
||||||
import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
import { TimeUtil } from "@spt-aki/utils/TimeUtil";
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class DialogueController
|
export class DialogueController
|
||||||
{
|
{
|
||||||
protected coreConfig: ICoreConfig;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@inject("WinstonLogger") protected logger: ILogger,
|
@inject("WinstonLogger") protected logger: ILogger,
|
||||||
@inject("SaveServer") protected saveServer: SaveServer,
|
@inject("SaveServer") protected saveServer: SaveServer,
|
||||||
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
||||||
@inject("DialogueHelper") protected dialogueHelper: DialogueHelper,
|
@inject("DialogueHelper") protected dialogueHelper: DialogueHelper,
|
||||||
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
|
||||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
|
||||||
@inject("MailSendService") protected mailSendService: MailSendService,
|
@inject("MailSendService") protected mailSendService: MailSendService,
|
||||||
@inject("GiftService") protected giftService: GiftService,
|
|
||||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
|
||||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
|
@injectAll("DialogueChatBot") protected dialogueChatBots: IDialogueChatBot[],
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.coreConfig = this.configServer.getConfig(ConfigTypes.CORE);
|
const coreConfigs = this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE);
|
||||||
|
// 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"
|
||||||
|
);
|
||||||
|
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptCommando), 1);
|
||||||
|
}
|
||||||
|
if (!coreConfigs.features?.chatbotFeatures?.sptFriendEnabled)
|
||||||
|
{
|
||||||
|
const sptFriend = this.dialogueChatBots.find((c) => c.getChatBot()._id.toLocaleLowerCase() === "sptFriend");
|
||||||
|
this.dialogueChatBots.splice(this.dialogueChatBots.indexOf(sptFriend), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerChatBot(chatBot: IDialogueChatBot): void
|
||||||
|
{
|
||||||
|
if (this.dialogueChatBots.some((cb) => cb.getChatBot()._id === chatBot.getChatBot()._id))
|
||||||
|
{
|
||||||
|
throw new Error(`The chat bot ${chatBot.getChatBot()._id} being registered already exists!`);
|
||||||
|
}
|
||||||
|
this.dialogueChatBots.push(chatBot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handle onUpdate spt event */
|
/** Handle onUpdate spt event */
|
||||||
@ -57,10 +69,11 @@ export class DialogueController
|
|||||||
* Handle client/friend/list
|
* Handle client/friend/list
|
||||||
* @returns IGetFriendListDataResponse
|
* @returns IGetFriendListDataResponse
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
public getFriendList(sessionID: string): IGetFriendListDataResponse
|
public getFriendList(sessionID: string): IGetFriendListDataResponse
|
||||||
{
|
{
|
||||||
// Force a fake friend called SPT into friend list
|
// Force a fake friend called SPT into friend list
|
||||||
return { Friends: [this.getSptFriendData()], Ignore: [], InIgnoreList: [] };
|
return { Friends: this.dialogueChatBots.map((v) => v.getChatBot()), Ignore: [], InIgnoreList: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,7 +130,8 @@ export class DialogueController
|
|||||||
|
|
||||||
// User to user messages are special in that they need the player to exist in them, add if they don't
|
// User to user messages are special in that they need the player to exist in them, add if they don't
|
||||||
if (
|
if (
|
||||||
messageType === MessageType.USER_MESSAGE && !dialog.Users?.find((x) => x._id === profile.characters.pmc._id)
|
messageType === MessageType.USER_MESSAGE
|
||||||
|
&& !dialog.Users?.find((x) => x._id === profile.characters.pmc.sessionId)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!dialog.Users)
|
if (!dialog.Users)
|
||||||
@ -126,7 +140,7 @@ export class DialogueController
|
|||||||
}
|
}
|
||||||
|
|
||||||
dialog.Users.push({
|
dialog.Users.push({
|
||||||
_id: profile.characters.pmc._id,
|
_id: profile.characters.pmc.sessionId,
|
||||||
info: {
|
info: {
|
||||||
Level: profile.characters.pmc.Info.Level,
|
Level: profile.characters.pmc.Info.Level,
|
||||||
Nickname: profile.characters.pmc.Info.Nickname,
|
Nickname: profile.characters.pmc.Info.Nickname,
|
||||||
@ -141,7 +155,7 @@ export class DialogueController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle client/mail/dialog/view
|
* Handle client/mail/dialog/view
|
||||||
* Handle player clicking 'messenger' and seeing all the messages they've received
|
* Handle player clicking 'messenger' and seeing all the messages they've recieved
|
||||||
* Set the content of the dialogue on the details panel, showing all the messages
|
* Set the content of the dialogue on the details panel, showing all the messages
|
||||||
* for the specified dialogue.
|
* for the specified dialogue.
|
||||||
* @param request Get dialog request
|
* @param request Get dialog request
|
||||||
@ -173,7 +187,7 @@ export class DialogueController
|
|||||||
/**
|
/**
|
||||||
* Get dialog from player profile, create if doesn't exist
|
* Get dialog from player profile, create if doesn't exist
|
||||||
* @param profile Player profile
|
* @param profile Player profile
|
||||||
* @param request get dialog request (params used when dialog doesn't exist in profile)
|
* @param request get dialog request (params used when dialog doesnt exist in profile)
|
||||||
* @returns Dialogue
|
* @returns Dialogue
|
||||||
*/
|
*/
|
||||||
protected getDialogByIdFromProfile(profile: IAkiProfile, request: IGetMailDialogViewRequestData): Dialogue
|
protected getDialogByIdFromProfile(profile: IAkiProfile, request: IGetMailDialogViewRequestData): Dialogue
|
||||||
@ -192,7 +206,11 @@ export class DialogueController
|
|||||||
if (request.type === MessageType.USER_MESSAGE)
|
if (request.type === MessageType.USER_MESSAGE)
|
||||||
{
|
{
|
||||||
profile.dialogues[request.dialogId].Users = [];
|
profile.dialogues[request.dialogId].Users = [];
|
||||||
profile.dialogues[request.dialogId].Users.push(this.getSptFriendData(request.dialogId));
|
const chatBot = this.dialogueChatBots.find((cb) => cb.getChatBot()._id === request.dialogId);
|
||||||
|
if (chatBot)
|
||||||
|
{
|
||||||
|
profile.dialogues[request.dialogId].Users.push(chatBot.getChatBot());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +229,7 @@ export class DialogueController
|
|||||||
{
|
{
|
||||||
result.push(...dialogUsers);
|
result.push(...dialogUsers);
|
||||||
|
|
||||||
// Player doesn't exist, add them in before returning
|
// Player doesnt exist, add them in before returning
|
||||||
if (!result.find((x) => x._id === fullProfile.info.id))
|
if (!result.find((x) => x._id === fullProfile.info.id))
|
||||||
{
|
{
|
||||||
const pmcProfile = fullProfile.characters.pmc;
|
const pmcProfile = fullProfile.characters.pmc;
|
||||||
@ -274,6 +292,7 @@ export class DialogueController
|
|||||||
if (!dialog)
|
if (!dialog)
|
||||||
{
|
{
|
||||||
this.logger.error(`No dialog in profile: ${sessionId} found with id: ${dialogueId}`);
|
this.logger.error(`No dialog in profile: ${sessionId} found with id: ${dialogueId}`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,6 +306,7 @@ export class DialogueController
|
|||||||
if (!dialog)
|
if (!dialog)
|
||||||
{
|
{
|
||||||
this.logger.error(`No dialog in profile: ${sessionId} found with id: ${dialogueId}`);
|
this.logger.error(`No dialog in profile: ${sessionId} found with id: ${dialogueId}`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,6 +325,7 @@ export class DialogueController
|
|||||||
if (!dialogs)
|
if (!dialogs)
|
||||||
{
|
{
|
||||||
this.logger.error(`No dialog object in profile: ${sessionId}`);
|
this.logger.error(`No dialog object in profile: ${sessionId}`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,6 +350,7 @@ export class DialogueController
|
|||||||
if (!dialog)
|
if (!dialog)
|
||||||
{
|
{
|
||||||
this.logger.error(`No dialog in profile: ${sessionId} found with id: ${dialogueId}`);
|
this.logger.error(`No dialog in profile: ${sessionId} found with id: ${dialogueId}`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,132 +368,15 @@ export class DialogueController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** client/mail/msg/send */
|
/** client/mail/msg/send */
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
public sendMessage(sessionId: string, request: ISendMessageRequest): string
|
public sendMessage(sessionId: string, request: ISendMessageRequest): string
|
||||||
{
|
{
|
||||||
this.mailSendService.sendPlayerMessageToNpc(sessionId, request.dialogId, request.text);
|
this.mailSendService.sendPlayerMessageToNpc(sessionId, request.dialogId, request.text);
|
||||||
|
|
||||||
// Handle when player types a keyword to sptFriend user
|
return this.dialogueChatBots.find((cb) => cb.getChatBot()._id === request.dialogId)?.handleMessage(
|
||||||
if (request.dialogId.includes("sptFriend"))
|
sessionId,
|
||||||
{
|
request,
|
||||||
this.handleChatWithSPTFriend(sessionId, request);
|
) ?? request.dialogId;
|
||||||
}
|
|
||||||
|
|
||||||
return request.dialogId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send responses back to player when they communicate with SPT friend on friends list
|
|
||||||
* @param sessionId Session Id
|
|
||||||
* @param request send message request
|
|
||||||
*/
|
|
||||||
protected handleChatWithSPTFriend(sessionId: string, request: ISendMessageRequest): void
|
|
||||||
{
|
|
||||||
const sender = this.profileHelper.getPmcProfile(sessionId);
|
|
||||||
const sptFriendUser = this.getSptFriendData();
|
|
||||||
const giftSent = this.giftService.sendGiftToPlayer(sessionId, request.text);
|
|
||||||
|
|
||||||
if (giftSent === GiftSentResult.SUCCESS)
|
|
||||||
{
|
|
||||||
this.mailSendService.sendUserMessageToPlayer(
|
|
||||||
sessionId,
|
|
||||||
sptFriendUser,
|
|
||||||
this.randomUtil.getArrayValue([
|
|
||||||
"Hey! you got the right code!",
|
|
||||||
"A secret code, how exciting!",
|
|
||||||
"You found a gift code!",
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (giftSent === GiftSentResult.FAILED_GIFT_ALREADY_RECEIVED)
|
|
||||||
{
|
|
||||||
this.mailSendService.sendUserMessageToPlayer(
|
|
||||||
sessionId,
|
|
||||||
sptFriendUser,
|
|
||||||
this.randomUtil.getArrayValue(["Looks like you already used that code", "You already have that!!"]),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.text.toLowerCase().includes("love you"))
|
|
||||||
{
|
|
||||||
this.mailSendService.sendUserMessageToPlayer(
|
|
||||||
sessionId,
|
|
||||||
sptFriendUser,
|
|
||||||
this.randomUtil.getArrayValue([
|
|
||||||
"That's quite forward but i love you too in a purely chatbot-human way",
|
|
||||||
"I love you too buddy :3!",
|
|
||||||
"uwu",
|
|
||||||
`love you too ${sender?.Info?.Nickname}`,
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.text.toLowerCase() === "spt")
|
|
||||||
{
|
|
||||||
this.mailSendService.sendUserMessageToPlayer(
|
|
||||||
sessionId,
|
|
||||||
sptFriendUser,
|
|
||||||
this.randomUtil.getArrayValue(["Its me!!", "spt? i've heard of that project"]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (["hello", "hi", "sup", "yo", "hey"].includes(request.text.toLowerCase()))
|
|
||||||
{
|
|
||||||
this.mailSendService.sendUserMessageToPlayer(
|
|
||||||
sessionId,
|
|
||||||
sptFriendUser,
|
|
||||||
this.randomUtil.getArrayValue([
|
|
||||||
"Howdy",
|
|
||||||
"Hi",
|
|
||||||
"Greetings",
|
|
||||||
"Hello",
|
|
||||||
"Bonjour",
|
|
||||||
"Yo",
|
|
||||||
"Sup",
|
|
||||||
"Heyyyyy",
|
|
||||||
"Hey there",
|
|
||||||
`Hello ${sender?.Info?.Nickname}`,
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.text.toLowerCase() === "nikita")
|
|
||||||
{
|
|
||||||
this.mailSendService.sendUserMessageToPlayer(
|
|
||||||
sessionId,
|
|
||||||
sptFriendUser,
|
|
||||||
this.randomUtil.getArrayValue([
|
|
||||||
"I know that guy!",
|
|
||||||
"Cool guy, he made EFT!",
|
|
||||||
"Legend",
|
|
||||||
"Remember when he said webel-webel-webel-webel, classic nikita moment",
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.text.toLowerCase() === "are you a bot")
|
|
||||||
{
|
|
||||||
this.mailSendService.sendUserMessageToPlayer(
|
|
||||||
sessionId,
|
|
||||||
sptFriendUser,
|
|
||||||
this.randomUtil.getArrayValue(["beep boop", "**sad boop**", "probably", "sometimes", "yeah lol"]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getSptFriendData(friendId = "sptFriend"): IUserDialogInfo
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
_id: friendId,
|
|
||||||
info: {
|
|
||||||
Level: 1,
|
|
||||||
MemberCategory: MemberCategory.DEVELOPER,
|
|
||||||
Nickname: this.coreConfig.sptFriendNickname,
|
|
||||||
Side: "Usec",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -424,6 +424,7 @@ export class GameController
|
|||||||
public getGameConfig(sessionID: string): IGameConfigResponse
|
public getGameConfig(sessionID: string): IGameConfigResponse
|
||||||
{
|
{
|
||||||
const profile = this.profileHelper.getPmcProfile(sessionID);
|
const profile = this.profileHelper.getPmcProfile(sessionID);
|
||||||
|
const gameTime = profile.Stats?.Eft.OverallCounters.Items?.find(counter => counter.Key.includes("LifeTime") && counter.Key.includes("Pmc"))?.Value ?? 0;
|
||||||
|
|
||||||
const config: IGameConfigResponse = {
|
const config: IGameConfigResponse = {
|
||||||
languages: this.databaseServer.getTables().locales.languages,
|
languages: this.databaseServer.getTables().locales.languages,
|
||||||
@ -443,7 +444,7 @@ export class GameController
|
|||||||
},
|
},
|
||||||
useProtobuf: false,
|
useProtobuf: false,
|
||||||
utc_time: new Date().getTime() / 1000,
|
utc_time: new Date().getTime() / 1000,
|
||||||
totalInGame: profile.Stats?.Eft?.TotalInGameTime ?? 0,
|
totalInGame: gameTime,
|
||||||
};
|
};
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
@ -104,6 +104,15 @@ export class QuestController
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Player can use trader mods then remove them, leaving quests behind
|
||||||
|
const trader = profile.TradersInfo[quest.traderId];
|
||||||
|
if (!trader)
|
||||||
|
{
|
||||||
|
this.logger.debug(`Unable to show quest: ${quest.QuestName} as its for a trader: ${quest.traderId} that no longer exists.`);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const questRequirements = this.questConditionHelper.getQuestConditions(quest.conditions.AvailableForStart);
|
const questRequirements = this.questConditionHelper.getQuestConditions(quest.conditions.AvailableForStart);
|
||||||
const loyaltyRequirements = this.questConditionHelper.getLoyaltyConditions(
|
const loyaltyRequirements = this.questConditionHelper.getLoyaltyConditions(
|
||||||
quest.conditions.AvailableForStart,
|
quest.conditions.AvailableForStart,
|
||||||
|
@ -86,6 +86,10 @@ import { BotGeneratorHelper } from "@spt-aki/helpers/BotGeneratorHelper";
|
|||||||
import { BotHelper } from "@spt-aki/helpers/BotHelper";
|
import { BotHelper } from "@spt-aki/helpers/BotHelper";
|
||||||
import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper";
|
import { BotWeaponGeneratorHelper } from "@spt-aki/helpers/BotWeaponGeneratorHelper";
|
||||||
import { ContainerHelper } from "@spt-aki/helpers/ContainerHelper";
|
import { ContainerHelper } from "@spt-aki/helpers/ContainerHelper";
|
||||||
|
import { SptCommandoCommands } from "@spt-aki/helpers/Dialogue/Commando/SptCommandoCommands";
|
||||||
|
import { GiveSptCommand } from "@spt-aki/helpers/Dialogue/Commando/SptCommands/GiveSptCommand";
|
||||||
|
import { CommandoDialogueChatBot } from "@spt-aki/helpers/Dialogue/CommandoDialogueChatBot";
|
||||||
|
import { SptDialogueChatBot } from "@spt-aki/helpers/Dialogue/SptDialogueChatBot";
|
||||||
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
|
import { DialogueHelper } from "@spt-aki/helpers/DialogueHelper";
|
||||||
import { DurabilityLimitsHelper } from "@spt-aki/helpers/DurabilityLimitsHelper";
|
import { DurabilityLimitsHelper } from "@spt-aki/helpers/DurabilityLimitsHelper";
|
||||||
import { GameEventHelper } from "@spt-aki/helpers/GameEventHelper";
|
import { GameEventHelper } from "@spt-aki/helpers/GameEventHelper";
|
||||||
@ -355,6 +359,16 @@ export class Container
|
|||||||
depContainer.registerType("SaveLoadRouter", "InraidSaveLoadRouter");
|
depContainer.registerType("SaveLoadRouter", "InraidSaveLoadRouter");
|
||||||
depContainer.registerType("SaveLoadRouter", "InsuranceSaveLoadRouter");
|
depContainer.registerType("SaveLoadRouter", "InsuranceSaveLoadRouter");
|
||||||
depContainer.registerType("SaveLoadRouter", "ProfileSaveLoadRouter");
|
depContainer.registerType("SaveLoadRouter", "ProfileSaveLoadRouter");
|
||||||
|
|
||||||
|
// Chat Bots
|
||||||
|
depContainer.registerType("DialogueChatBot", "SptDialogueChatBot");
|
||||||
|
depContainer.registerType("DialogueChatBot", "CommandoDialogueChatBot");
|
||||||
|
|
||||||
|
// Commando Commands
|
||||||
|
depContainer.registerType("CommandoCommand", "SptCommandoCommands");
|
||||||
|
|
||||||
|
// SptCommando Commands
|
||||||
|
depContainer.registerType("SptCommand", "GiveSptCommand");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static registerUtils(depContainer: DependencyContainer): void
|
private static registerUtils(depContainer: DependencyContainer): void
|
||||||
@ -563,6 +577,18 @@ export class Container
|
|||||||
});
|
});
|
||||||
depContainer.register<BotDifficultyHelper>("BotDifficultyHelper", { useClass: BotDifficultyHelper });
|
depContainer.register<BotDifficultyHelper>("BotDifficultyHelper", { useClass: BotDifficultyHelper });
|
||||||
depContainer.register<RepeatableQuestHelper>("RepeatableQuestHelper", { useClass: RepeatableQuestHelper });
|
depContainer.register<RepeatableQuestHelper>("RepeatableQuestHelper", { useClass: RepeatableQuestHelper });
|
||||||
|
|
||||||
|
// ChatBots
|
||||||
|
depContainer.register<SptDialogueChatBot>("SptDialogueChatBot", SptDialogueChatBot);
|
||||||
|
depContainer.register<CommandoDialogueChatBot>("CommandoDialogueChatBot", CommandoDialogueChatBot, {
|
||||||
|
lifecycle: Lifecycle.Singleton,
|
||||||
|
});
|
||||||
|
// SptCommando
|
||||||
|
depContainer.register<SptCommandoCommands>("SptCommandoCommands", SptCommandoCommands, {
|
||||||
|
lifecycle: Lifecycle.Singleton,
|
||||||
|
});
|
||||||
|
// SptCommands
|
||||||
|
depContainer.register<GiveSptCommand>("GiveSptCommand", GiveSptCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static registerLoaders(depContainer: DependencyContainer): void
|
private static registerLoaders(depContainer: DependencyContainer): void
|
||||||
@ -727,7 +753,9 @@ export class Container
|
|||||||
depContainer.register<CustomizationController>("CustomizationController", {
|
depContainer.register<CustomizationController>("CustomizationController", {
|
||||||
useClass: CustomizationController,
|
useClass: CustomizationController,
|
||||||
});
|
});
|
||||||
depContainer.register<DialogueController>("DialogueController", { useClass: DialogueController });
|
depContainer.register<DialogueController>("DialogueController", { useClass: DialogueController }, {
|
||||||
|
lifecycle: Lifecycle.Singleton,
|
||||||
|
});
|
||||||
depContainer.register<GameController>("GameController", { useClass: GameController });
|
depContainer.register<GameController>("GameController", { useClass: GameController });
|
||||||
depContainer.register<HandbookController>("HandbookController", { useClass: HandbookController });
|
depContainer.register<HandbookController>("HandbookController", { useClass: HandbookController });
|
||||||
depContainer.register<HealthController>("HealthController", { useClass: HealthController });
|
depContainer.register<HealthController>("HealthController", { useClass: HealthController });
|
||||||
|
10
project/src/helpers/Dialogue/Commando/ICommandoCommand.ts
Normal file
10
project/src/helpers/Dialogue/Commando/ICommandoCommand.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest";
|
||||||
|
import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||||
|
|
||||||
|
export interface ICommandoCommand
|
||||||
|
{
|
||||||
|
getCommandPrefix(): string;
|
||||||
|
getCommandHelp(command: string): string;
|
||||||
|
getCommands(): Set<string>;
|
||||||
|
handle(command: string, commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string;
|
||||||
|
}
|
67
project/src/helpers/Dialogue/Commando/SptCommandoCommands.ts
Normal file
67
project/src/helpers/Dialogue/Commando/SptCommandoCommands.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { ICommandoCommand } from "@spt-aki/helpers/Dialogue/Commando/ICommandoCommand";
|
||||||
|
import { ISptCommand } from "@spt-aki/helpers/Dialogue/Commando/SptCommands/ISptCommand";
|
||||||
|
import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest";
|
||||||
|
import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||||
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
|
import { ICoreConfig } from "@spt-aki/models/spt/config/ICoreConfig";
|
||||||
|
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||||
|
import { inject, injectAll, injectable } from "tsyringe";
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class SptCommandoCommands implements ICommandoCommand
|
||||||
|
{
|
||||||
|
constructor(
|
||||||
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
|
@injectAll("SptCommand") protected sptCommands: ISptCommand[],
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const coreConfigs = this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE);
|
||||||
|
// if give command is disabled or commando commands are disabled
|
||||||
|
if (
|
||||||
|
!(coreConfigs.features?.chatbotFeatures?.commandoFeatures?.giveCommandEnabled
|
||||||
|
&& coreConfigs.features?.chatbotFeatures?.commandoEnabled)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const giveCommand = this.sptCommands.find((c) => c.getCommand().toLocaleLowerCase() === "give");
|
||||||
|
this.sptCommands.splice(this.sptCommands.indexOf(giveCommand), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerSptCommandoCommand(command: ISptCommand): void
|
||||||
|
{
|
||||||
|
if (this.sptCommands.some((c) => c.getCommand() === command.getCommand()))
|
||||||
|
{
|
||||||
|
throw new Error(`The command ${command.getCommand()} being registered for SPT Commands already exists!`);
|
||||||
|
}
|
||||||
|
this.sptCommands.push(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCommandHelp(command: string): string
|
||||||
|
{
|
||||||
|
return this.sptCommands.find((c) => c.getCommand() === command)?.getCommandHelp();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCommandPrefix(): string
|
||||||
|
{
|
||||||
|
return "spt";
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCommands(): Set<string>
|
||||||
|
{
|
||||||
|
return new Set(this.sptCommands.map((c) => c.getCommand()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public handle(
|
||||||
|
command: string,
|
||||||
|
commandHandler: IUserDialogInfo,
|
||||||
|
sessionId: string,
|
||||||
|
request: ISendMessageRequest,
|
||||||
|
): string
|
||||||
|
{
|
||||||
|
return this.sptCommands.find((c) => c.getCommand() === command).performAction(
|
||||||
|
commandHandler,
|
||||||
|
sessionId,
|
||||||
|
request,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,138 @@
|
|||||||
|
import { ISptCommand } from "@spt-aki/helpers/Dialogue/Commando/SptCommands/ISptCommand";
|
||||||
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
|
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
||||||
|
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||||
|
import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest";
|
||||||
|
import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||||
|
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
|
||||||
|
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||||
|
import { MailSendService } from "@spt-aki/services/MailSendService";
|
||||||
|
import { HashUtil } from "@spt-aki/utils/HashUtil";
|
||||||
|
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||||
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class GiveSptCommand implements ISptCommand
|
||||||
|
{
|
||||||
|
public constructor(
|
||||||
|
@inject("WinstonLogger") protected logger: ILogger,
|
||||||
|
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||||
|
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||||
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||||
|
@inject("PresetHelper") protected presetHelper: PresetHelper,
|
||||||
|
@inject("MailSendService") protected mailSendService: MailSendService,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCommand(): string
|
||||||
|
{
|
||||||
|
return "give";
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCommandHelp(): string
|
||||||
|
{
|
||||||
|
return "Usage: spt give tplId quantity";
|
||||||
|
}
|
||||||
|
|
||||||
|
public performAction(commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string
|
||||||
|
{
|
||||||
|
const giveCommand = request.text.split(" ");
|
||||||
|
if (giveCommand[1] !== "give")
|
||||||
|
{
|
||||||
|
this.logger.error("Invalid action received for give command!");
|
||||||
|
return request.dialogId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!giveCommand[2])
|
||||||
|
{
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
commandHandler,
|
||||||
|
"Invalid use of give command! Template ID is missing. Use \"Help\" for more info",
|
||||||
|
);
|
||||||
|
return request.dialogId;
|
||||||
|
}
|
||||||
|
const tplId = giveCommand[2];
|
||||||
|
|
||||||
|
if (!giveCommand[3])
|
||||||
|
{
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
commandHandler,
|
||||||
|
"Invalid use of give command! Quantity is missing. Use \"Help\" for more info",
|
||||||
|
);
|
||||||
|
return request.dialogId;
|
||||||
|
}
|
||||||
|
const quantity = giveCommand[3];
|
||||||
|
|
||||||
|
if (Number.isNaN(+quantity))
|
||||||
|
{
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
commandHandler,
|
||||||
|
"Invalid use of give command! Quantity is not a valid integer. Use \"Help\" for more info",
|
||||||
|
);
|
||||||
|
return request.dialogId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkedItem = this.itemHelper.getItem(tplId);
|
||||||
|
if (!checkedItem[0])
|
||||||
|
{
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
commandHandler,
|
||||||
|
"Invalid template ID requested for give command. The item doesn't exist in the DB.",
|
||||||
|
);
|
||||||
|
return request.dialogId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemsToSend: Item[] = [];
|
||||||
|
if (this.itemHelper.isOfBaseclass(checkedItem[1]._id, BaseClasses.WEAPON))
|
||||||
|
{
|
||||||
|
const preset = this.presetHelper.getDefaultPreset(checkedItem[1]._id);
|
||||||
|
if (!preset)
|
||||||
|
{
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
commandHandler,
|
||||||
|
"Invalid weapon template ID requested. There are no default presets for this weapon.",
|
||||||
|
);
|
||||||
|
return request.dialogId;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < +quantity; i++)
|
||||||
|
{
|
||||||
|
// Make sure IDs are unique before adding to array - prevent collisions
|
||||||
|
const presetToSend = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(preset._items));
|
||||||
|
itemsToSend.push(... presetToSend);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (this.itemHelper.isOfBaseclass(checkedItem[1]._id, BaseClasses.AMMO_BOX))
|
||||||
|
{
|
||||||
|
for (let i = 0; i < +quantity; i++)
|
||||||
|
{
|
||||||
|
const ammoBoxArray: Item[] = [];
|
||||||
|
ammoBoxArray.push({ _id: this.hashUtil.generate(), _tpl: checkedItem[1]._id });
|
||||||
|
this.itemHelper.addCartridgesToAmmoBox(ammoBoxArray, checkedItem[1]);
|
||||||
|
itemsToSend.push(...ammoBoxArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const item: Item = {
|
||||||
|
_id: this.hashUtil.generate(),
|
||||||
|
_tpl: checkedItem[1]._id,
|
||||||
|
upd: {
|
||||||
|
StackObjectsCount: +quantity,
|
||||||
|
SpawnedInSession: true
|
||||||
|
},
|
||||||
|
};
|
||||||
|
itemsToSend.push(...this.itemHelper.splitStack(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mailSendService.sendSystemMessageToPlayer(sessionId, "Give command!", itemsToSend);
|
||||||
|
return request.dialogId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest";
|
||||||
|
import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||||
|
|
||||||
|
export interface ISptCommand
|
||||||
|
{
|
||||||
|
getCommand(): string;
|
||||||
|
getCommandHelp(): string;
|
||||||
|
performAction(commandHandler: IUserDialogInfo, sessionId: string, request: ISendMessageRequest): string;
|
||||||
|
}
|
74
project/src/helpers/Dialogue/CommandoDialogueChatBot.ts
Normal file
74
project/src/helpers/Dialogue/CommandoDialogueChatBot.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { inject, injectAll, injectable } from "tsyringe";
|
||||||
|
|
||||||
|
import { ICommandoCommand } from "@spt-aki/helpers/Dialogue/Commando/ICommandoCommand";
|
||||||
|
import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot";
|
||||||
|
import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest";
|
||||||
|
import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||||
|
import { MemberCategory } from "@spt-aki/models/enums/MemberCategory";
|
||||||
|
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||||
|
import { MailSendService } from "@spt-aki/services/MailSendService";
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class CommandoDialogueChatBot implements IDialogueChatBot
|
||||||
|
{
|
||||||
|
public constructor(
|
||||||
|
@inject("WinstonLogger") protected logger: ILogger,
|
||||||
|
@inject("MailSendService") protected mailSendService: MailSendService,
|
||||||
|
@injectAll("CommandoCommand") protected commandoCommands: ICommandoCommand[],
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerCommandoCommand(commandoCommand: ICommandoCommand): void
|
||||||
|
{
|
||||||
|
if (this.commandoCommands.some((cc) => cc.getCommandPrefix() === commandoCommand.getCommandPrefix()))
|
||||||
|
{
|
||||||
|
throw new Error(
|
||||||
|
`The commando command ${commandoCommand.getCommandPrefix()} being registered already exists!`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.commandoCommands.push(commandoCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getChatBot(): IUserDialogInfo
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
_id: "sptCommando",
|
||||||
|
info: { Level: 1, MemberCategory: MemberCategory.DEVELOPER, Nickname: "Commando", Side: "Usec" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public handleMessage(sessionId: string, request: ISendMessageRequest): string
|
||||||
|
{
|
||||||
|
if ((request.text ?? "").length === 0)
|
||||||
|
{
|
||||||
|
this.logger.error("Commando command came in as empty text! Invalid data!");
|
||||||
|
return request.dialogId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const splitCommand = request.text.split(" ");
|
||||||
|
|
||||||
|
const commandos = this.commandoCommands.filter((c) => c.getCommandPrefix() === splitCommand[0]);
|
||||||
|
if (commandos[0]?.getCommands().has(splitCommand[1]))
|
||||||
|
{
|
||||||
|
return commandos[0].handle(splitCommand[1], this.getChatBot(), sessionId, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (splitCommand[0].toLowerCase() === "help")
|
||||||
|
{
|
||||||
|
const helpMessage = this.commandoCommands.map((c) =>
|
||||||
|
`Help for ${c.getCommandPrefix()}:\n${
|
||||||
|
Array.from(c.getCommands()).map((command) => c.getCommandHelp(command)).join("\n")
|
||||||
|
}`
|
||||||
|
).join("\n");
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(sessionId, this.getChatBot(), helpMessage);
|
||||||
|
return request.dialogId;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
this.getChatBot(),
|
||||||
|
`Im sorry soldier, I dont recognize the command you are trying to use! Type "help" to see available commands.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
8
project/src/helpers/Dialogue/IDialogueChatBot.ts
Normal file
8
project/src/helpers/Dialogue/IDialogueChatBot.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest";
|
||||||
|
import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||||
|
|
||||||
|
export interface IDialogueChatBot
|
||||||
|
{
|
||||||
|
getChatBot(): IUserDialogInfo;
|
||||||
|
handleMessage(sessionId: string, request: ISendMessageRequest): string;
|
||||||
|
}
|
151
project/src/helpers/Dialogue/SptDialogueChatBot.ts
Normal file
151
project/src/helpers/Dialogue/SptDialogueChatBot.ts
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
|
import { IDialogueChatBot } from "@spt-aki/helpers/Dialogue/IDialogueChatBot";
|
||||||
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
|
import { ISendMessageRequest } from "@spt-aki/models/eft/dialog/ISendMessageRequest";
|
||||||
|
import { IUserDialogInfo } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||||
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
|
import { GiftSentResult } from "@spt-aki/models/enums/GiftSentResult";
|
||||||
|
import { MemberCategory } from "@spt-aki/models/enums/MemberCategory";
|
||||||
|
import { ICoreConfig } from "@spt-aki/models/spt/config/ICoreConfig";
|
||||||
|
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||||
|
import { GiftService } from "@spt-aki/services/GiftService";
|
||||||
|
import { MailSendService } from "@spt-aki/services/MailSendService";
|
||||||
|
import { RandomUtil } from "@spt-aki/utils/RandomUtil";
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class SptDialogueChatBot implements IDialogueChatBot
|
||||||
|
{
|
||||||
|
protected coreConfig: ICoreConfig;
|
||||||
|
public constructor(
|
||||||
|
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||||
|
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||||
|
@inject("MailSendService") protected mailSendService: MailSendService,
|
||||||
|
@inject("GiftService") protected giftService: GiftService,
|
||||||
|
@inject("ConfigServer") protected configServer: ConfigServer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this.coreConfig = this.configServer.getConfig(ConfigTypes.CORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getChatBot(): IUserDialogInfo
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
_id: "sptFriend",
|
||||||
|
info: {
|
||||||
|
Level: 1,
|
||||||
|
MemberCategory: MemberCategory.DEVELOPER,
|
||||||
|
Nickname: this.coreConfig.sptFriendNickname,
|
||||||
|
Side: "Usec",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send responses back to player when they communicate with SPT friend on friends list
|
||||||
|
* @param sessionId Session Id
|
||||||
|
* @param request send message request
|
||||||
|
*/
|
||||||
|
public handleMessage(sessionId: string, request: ISendMessageRequest): string
|
||||||
|
{
|
||||||
|
const sender = this.profileHelper.getPmcProfile(sessionId);
|
||||||
|
|
||||||
|
const sptFriendUser = this.getChatBot();
|
||||||
|
|
||||||
|
const giftSent = this.giftService.sendGiftToPlayer(sessionId, request.text);
|
||||||
|
|
||||||
|
if (giftSent === GiftSentResult.SUCCESS)
|
||||||
|
{
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
sptFriendUser,
|
||||||
|
this.randomUtil.getArrayValue([
|
||||||
|
"Hey! you got the right code!",
|
||||||
|
"A secret code, how exciting!",
|
||||||
|
"You found a gift code!",
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (giftSent === GiftSentResult.FAILED_GIFT_ALREADY_RECEIVED)
|
||||||
|
{
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
sptFriendUser,
|
||||||
|
this.randomUtil.getArrayValue(["Looks like you already used that code", "You already have that!!"])
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.text.toLowerCase().includes("love you"))
|
||||||
|
{
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
sptFriendUser,
|
||||||
|
this.randomUtil.getArrayValue([
|
||||||
|
"That's quite forward but i love you too in a purely chatbot-human way",
|
||||||
|
"I love you too buddy :3!",
|
||||||
|
"uwu",
|
||||||
|
`love you too ${sender?.Info?.Nickname}`,
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.text.toLowerCase() === "spt")
|
||||||
|
{
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
sptFriendUser,
|
||||||
|
this.randomUtil.getArrayValue(["Its me!!", "spt? i've heard of that project"])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (["hello", "hi", "sup", "yo", "hey"].includes(request.text.toLowerCase()))
|
||||||
|
{
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
sptFriendUser,
|
||||||
|
this.randomUtil.getArrayValue([
|
||||||
|
"Howdy",
|
||||||
|
"Hi",
|
||||||
|
"Greetings",
|
||||||
|
"Hello",
|
||||||
|
"bonjor",
|
||||||
|
"Yo",
|
||||||
|
"Sup",
|
||||||
|
"Heyyyyy",
|
||||||
|
"Hey there",
|
||||||
|
`Hello ${sender?.Info?.Nickname}`,
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.text.toLowerCase() === "nikita")
|
||||||
|
{
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
sptFriendUser,
|
||||||
|
this.randomUtil.getArrayValue([
|
||||||
|
"I know that guy!",
|
||||||
|
"Cool guy, he made EFT!",
|
||||||
|
"Legend",
|
||||||
|
"Remember when he said webel-webel-webel-webel, classic nikita moment",
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.text.toLowerCase() === "are you a bot")
|
||||||
|
{
|
||||||
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
|
sessionId,
|
||||||
|
sptFriendUser,
|
||||||
|
this.randomUtil.getArrayValue(["beep boop", "**sad boop**", "probably", "sometimes", "yeah lol"])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return request.dialogId;
|
||||||
|
}
|
||||||
|
}
|
@ -31,4 +31,18 @@ export interface IServerFeatures
|
|||||||
{
|
{
|
||||||
/* Controls whether or not the server attempts to download mod dependencies not included in the server's executable */
|
/* Controls whether or not the server attempts to download mod dependencies not included in the server's executable */
|
||||||
autoInstallModDependencies: boolean;
|
autoInstallModDependencies: boolean;
|
||||||
|
compressProfile: boolean;
|
||||||
|
chatbotFeatures: IChatbotFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IChatbotFeatures
|
||||||
|
{
|
||||||
|
sptFriendEnabled: boolean;
|
||||||
|
commandoEnabled: boolean;
|
||||||
|
commandoFeatures: ICommandoFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICommandoFeatures
|
||||||
|
{
|
||||||
|
giveCommandEnabled: boolean;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@ import { LocalisationService } from "@spt-aki/services/LocalisationService";
|
|||||||
import { HashUtil } from "@spt-aki/utils/HashUtil";
|
import { HashUtil } from "@spt-aki/utils/HashUtil";
|
||||||
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
import { JsonUtil } from "@spt-aki/utils/JsonUtil";
|
||||||
import { VFS } from "@spt-aki/utils/VFS";
|
import { VFS } from "@spt-aki/utils/VFS";
|
||||||
|
import { ConfigServer } from "./ConfigServer";
|
||||||
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
|
import { ICoreConfig } from "@spt-aki/models/spt/config/ICoreConfig";
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class SaveServer
|
export class SaveServer
|
||||||
@ -24,6 +27,7 @@ export class SaveServer
|
|||||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
@inject("WinstonLogger") protected logger: ILogger,
|
@inject("WinstonLogger") protected logger: ILogger,
|
||||||
|
@inject("ConfigServer") protected configServer: ConfigServer
|
||||||
)
|
)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -166,7 +170,9 @@ export class SaveServer
|
|||||||
if (this.vfs.exists(filePath))
|
if (this.vfs.exists(filePath))
|
||||||
{
|
{
|
||||||
// File found, store in profiles[]
|
// File found, store in profiles[]
|
||||||
|
const start = performance.now();
|
||||||
this.profiles[sessionID] = this.jsonUtil.deserialize(this.vfs.readFile(filePath), filename);
|
this.profiles[sessionID] = this.jsonUtil.deserialize(this.vfs.readFile(filePath), filename);
|
||||||
|
this.logger.debug(`Profile ${sessionID} took ${performance.now() - start}ms to load.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run callbacks
|
// Run callbacks
|
||||||
@ -200,7 +206,8 @@ export class SaveServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const jsonProfile = this.jsonUtil.serialize(this.profiles[sessionID], true);
|
const start = performance.now();
|
||||||
|
const jsonProfile = this.jsonUtil.serialize(this.profiles[sessionID], !this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE).features.compressProfile);
|
||||||
const fmd5 = this.hashUtil.generateMd5ForData(jsonProfile);
|
const fmd5 = this.hashUtil.generateMd5ForData(jsonProfile);
|
||||||
if (typeof (this.saveMd5[sessionID]) !== "string" || this.saveMd5[sessionID] !== fmd5)
|
if (typeof (this.saveMd5[sessionID]) !== "string" || this.saveMd5[sessionID] !== fmd5)
|
||||||
{
|
{
|
||||||
@ -209,6 +216,7 @@ export class SaveServer
|
|||||||
this.vfs.writeFile(filePath, jsonProfile);
|
this.vfs.writeFile(filePath, jsonProfile);
|
||||||
this.logger.debug(this.localisationService.getText("profile_saved", sessionID), true);
|
this.logger.debug(this.localisationService.getText("profile_saved", sessionID), true);
|
||||||
}
|
}
|
||||||
|
this.logger.debug(`Profile ${sessionID} took ${performance.now() - start}ms to save.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,7 +36,7 @@ export class LocaleService
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.logger.warning(
|
this.logger.warning(
|
||||||
`Unable to find desired locale file using locale ${this.getDesiredGameLocale()} from config/locale.json, falling back to 'en'`,
|
`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;
|
||||||
@ -103,6 +103,12 @@ export class LocaleService
|
|||||||
return "en";
|
return "en";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BSG map Czech to CZ for some reason
|
||||||
|
if (platformLocale.language === "cs")
|
||||||
|
{
|
||||||
|
return "cz";
|
||||||
|
}
|
||||||
|
|
||||||
return platformLocale.language;
|
return platformLocale.language;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
|
|
||||||
|
import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
||||||
import { ITemplateItem, Props } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
import { ITemplateItem, Props } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
||||||
import {
|
import {
|
||||||
CreateItemResult,
|
CreateItemResult,
|
||||||
@ -23,6 +24,7 @@ export class CustomItemService
|
|||||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||||
|
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.tables = this.databaseServer.getTables();
|
this.tables = this.databaseServer.getTables();
|
||||||
@ -197,4 +199,41 @@ export class CustomItemService
|
|||||||
{
|
{
|
||||||
this.tables.templates.prices[newItemId] = fleaPriceRoubles;
|
this.tables.templates.prices[newItemId] = fleaPriceRoubles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a custom weapon to PMCs loadout
|
||||||
|
* @param weaponTpl Custom weapon tpl to add to PMCs
|
||||||
|
* @param weaponWeight The weighting for the weapon to be picked vs other weapons
|
||||||
|
* @param weaponSlot The slot the weapon should be added to (e.g. FirstPrimaryWeapon/SecondPrimaryWeapon/Holster)
|
||||||
|
*/
|
||||||
|
public addCustomWeaponToPMCs(weaponTpl: string, weaponWeight: number, weaponSlot: string): void
|
||||||
|
{
|
||||||
|
const weapon = this.itemHelper.getItem(weaponTpl);
|
||||||
|
if (!weapon[0])
|
||||||
|
{
|
||||||
|
this.logger.warning(`Unable to add custom weapon ${weaponTpl} to PMCs as it cannot be found in the Item db`);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const baseWeaponModObject = {};
|
||||||
|
|
||||||
|
// Get all slots weapon has and create a dictionary of them with possible mods that slot into each
|
||||||
|
const weaponSltos = weapon[1]._props.Slots;
|
||||||
|
for (const slot of weaponSltos)
|
||||||
|
{
|
||||||
|
baseWeaponModObject[slot._name] = slot._props.filters[0].Filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get PMCs
|
||||||
|
const usec = this.databaseServer.getTables().bots.types.usec;
|
||||||
|
const bear = this.databaseServer.getTables().bots.types.bear;
|
||||||
|
|
||||||
|
// Add weapon base+mods into bear/usec data
|
||||||
|
usec.inventory.mods[weaponTpl] = baseWeaponModObject;
|
||||||
|
bear.inventory.mods[weaponTpl] = baseWeaponModObject;
|
||||||
|
|
||||||
|
// Add weapon to array of allowed weapons + weighting to be picked
|
||||||
|
usec.inventory.equipment[weaponSlot][weaponTpl] = weaponWeight;
|
||||||
|
bear.inventory.equipment[weaponSlot][weaponTpl] = weaponWeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,14 +36,16 @@ export class HttpResponseUtil
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Game client needs server responses in a particular format
|
* Game client needs server responses in a particular format
|
||||||
* @param data
|
* @param data
|
||||||
* @param err
|
* @param err
|
||||||
* @param errmsg
|
* @param errmsg
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public getBody<T>(data: T, err = 0, errmsg = null): IGetBodyResponseData<T>
|
public getBody<T>(data: T, err = 0, errmsg = null, sanitize = true): IGetBodyResponseData<T>
|
||||||
{
|
{
|
||||||
return this.clearString(this.getUnclearedBody(data, err, errmsg));
|
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 = 0, errmsg = null): string
|
||||||
|
Loading…
Reference in New Issue
Block a user