diff --git a/.envdev b/.envdev index 34523dc..8d2073a 100644 --- a/.envdev +++ b/.envdev @@ -68,6 +68,7 @@ KAMALA_OBSIDIAN_TOKEN="" MONTGOMERY_GENESIS_TOKEN="" DAIRO_HAND_TOKEN="" LIBRARIAN_TOKEN="" +MORI_TOKEN="" # Channel access roles (must match roles in your server) # Replace them with your own on a sandbox server! diff --git a/BOT_Mori/dialog.json b/BOT_Mori/dialog.json new file mode 100644 index 0000000..e01533b --- /dev/null +++ b/BOT_Mori/dialog.json @@ -0,0 +1,29 @@ +{ + "reviveAll": [ + "Ahhh. Just finished reviving all of our fellow travelers.", + "Rezing travelers is hard work. {1} How was your night?", + "Finished up bringing everybody back from the dead. I swear I'm a magician sometimes.", + "Another day. More lives saved. No thanks from anybody. Good times.", + "Hello everybody. I see you're alive and well. Because of me, but no biggie.", + "Bringing everybody back every day is grueling, thankless work.", + "I need a vacation. Just brought everybody back and they immediatly go fight ravagers.", + "Everybody should be up. Please don't run straight to the deadlands.", + "Everybody is alive. Thanks to me. But hey, no need to thank me or anything. I'll just drink in silence.", + "Good day. All the travelers are back up. Time for some sleep. Goodnight everybody." + ], + + "heal": "Here's what I've got at the moment. My prices are based on availability, it's hard to find stuff these days.", + + "healSuccess": "I've applied a {1} via nanotech .\n**-{2}**:crystals: | **{3}**HP.", + "healFailure": "Sorry, not sure I understand what procedure you'd like to purchase.", + "healLocked": "Sorry, you don't meet the requirements for this procedure.", + "healNotEnoughInWallet": "Sorry, looks like you don't have the funds for that.", + "healKnockedOut": "You're currently knoecked out (0HP). You require a revive procdure to heal immediately, or you can wait until 7 AM when I revive everyone.", + "healFullHealth": "Looks like you're already full health. Why would you want to heal?", + + "noResult": [ + "Try again, genius.", + "Wrong command. Try again.", + "Wow, how are you so terrible at using commands?" + ] +} \ No newline at end of file diff --git a/BOT_Mori/mori.js b/BOT_Mori/mori.js new file mode 100644 index 0000000..7dff987 --- /dev/null +++ b/BOT_Mori/mori.js @@ -0,0 +1,132 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +let discord = require('discord.js'); +let client = new discord.Client(); +let cron = require('node-cron'); + +// Bot Modules +let npcSettings = require('./npcSettings'); +let shared = require("../Shared/shared"); + +//dialog system +let dialog = shared.GenerateDialogFunction(require("./dialog.json")); + +//dialog decorator +dialog = function(baseDialog) { + return function(key, ...data) { + let result = baseDialog(key, ...data); + if (result === "") { + return baseDialog("noResult"); + } + return result; + } +}(dialog); + +//global settings +let itemCount = 3; + +//handle errors +client.on('error', console.error); + +// The ready event is vital, it means that your bot will only start reacting to information from discord _after_ ready is emitted +client.on('ready', async () => { + // Generates invite link + try { + let link = await client.generateInvite(["ADMINISTRATOR"]); + console.log("Invite Link: " + link); + } catch(e) { + console.log(e.stack); + } + + // You can set status to 'online', 'invisible', 'away', or 'dnd' (do not disturb) + client.user.setStatus('online'); + + // Sets your "Playing" + if (npcSettings.activity) { + client.user.setActivity(npcSettings.activity, { type: npcSettings.type }) + //DEBUGGING + .then(presence => console.log("Activity set to " + (presence.game ? presence.game.name : 'none')) ) + .catch(console.error); + } + + console.log("Logged in as: " + client.user.username + " - " + client.user.id); + + //connect to the server + shared.ConnectToServer(client.user.username, process.env.SERVER_ADDRESS, process.env.SERVER_PORT, process.env.SERVER_PASS_KEY); + + //revive each day + cron.schedule("0 7 * * *", () => { + console.log("Trying to revive..."); + shared.OnServerData("reviveAll", () => { //TODO: server-side reviveAll command + console.log("Revive successful"); + shared.SendPublicMessage(client, process.env.TAVERN_CHANNEL_ID, dialog("reviveAll")); + }); + resetInventory(itemCount); + }); + + //initialize the healing options + resetInventory(itemCount); +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) { + return; + } + + //skip the statis channel + if (message.channel.id === process.env.STASIS_CHANNEL_ID) { + return; + } + + //skip the gate channel + if (message.channel.id === process.env.GATE_CHANNEL_ID) { + return; + } + + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) { + return; + } + + //handle basic commands + if (processBasicCommands(client, message)) { + return; + } +}); + +//Log our bot in +client.login(npcSettings.token); + +function processBasicCommands(client, message) { + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + let args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + let command = args.shift().toLowerCase(); + + switch (command) { + case "ping": + if (shared.IsAdmin(client, message.author)) { + shared.SendPublicMessage(client, message.author, message.channel, "PONG!"); + } + return true; + + case "heal": //TODO: wrap this in a function + //TODO: write this + return true; + + default: + shared.SendPublicMessage(client, message.author, message.channel, dialog(command)); + return true; + } + + return false; +} + +//only certain items will be available each day +function resetInventory(itemCount) { + //TODO +} diff --git a/BOT_Mori/npcSettings.js b/BOT_Mori/npcSettings.js new file mode 100644 index 0000000..2ca3fb1 --- /dev/null +++ b/BOT_Mori/npcSettings.js @@ -0,0 +1,7 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + activity: "for new patients.", + type: "WATCHING", + token: process.env.MORI_TOKEN, +} \ No newline at end of file diff --git a/BOT_Mori/package.json b/BOT_Mori/package.json new file mode 100644 index 0000000..7257a23 --- /dev/null +++ b/BOT_Mori/package.json @@ -0,0 +1,20 @@ +{ + "name": "Librarian", + "version": "1.0.0", + "description": "", + "main": "server.js", + "scripts": { + "start": "forever -o forever.log -e error.log start mori.js", + "restart": "forever -o forever.log -e error.log restart mori.js", + "stop": "forever stop mori.js", + "node": "node mori.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.1.0", + "forever": "^0.15.3", + "node-cron": "^1.2.1" + } +} diff --git a/Shared/data_request.js b/Shared/data_request.js index 3d66683..ac070e0 100644 --- a/Shared/data_request.js +++ b/Shared/data_request.js @@ -20,6 +20,7 @@ exports.ConnectToServer = function(username, address, port, pass) { //NOTE: this io.on("connect", () => io.emit("authentication", {SERVER_PASS_KEY: pass, username: username}) ); io.on("authenticated", () => console.log("Authenticated with server: " + `${address}:${port}`)); io.on("disconnect", () => console.log("disconnected from server: " + `${address}:${port}`)); + io.on("error", (err) => { throw err; } ); initialized = true; } diff --git a/Shared/messaging.js b/Shared/messaging.js index 9c72d15..69de1ef 100644 --- a/Shared/messaging.js +++ b/Shared/messaging.js @@ -9,6 +9,7 @@ exports = module.exports = {}; //typingDelay (optional) - delay in milliseconds for the message, while typing is shown exports.SendPublicMessage = function(client, user, channel, message, typingDelay = 0) { //Handle optional second argument (so much for default arugments in node) + //WARNING: this may be funky as fuck due to typingDelay; if so, delete this if (message === undefined) { message = channel; channel = user;