diff --git a/.envdev b/.envdev new file mode 100644 index 0000000..58e02ab --- /dev/null +++ b/.envdev @@ -0,0 +1,91 @@ +################################################# +# _____ _ # +# / ____| | | # +# | (___ __ _ _ __ ___| |_ _ _ _ __ ___ # +# \___ \ / _` | '_ \ / __| __| | | | '_ ` _ \ # +# ____) | (_| | | | | (__| |_| |_| | | | | | | # +# |_____/ \__,_|_| |_|\___|\__|\__,_|_| |_| |_| # +# # +################################################# + +# +# +# Welcome to the SANCTUM Discord bot code, and specifically the .envdev file. +# +# To setup, !!! RENAME .envdev TO .env !!!, so it hooks into the bots +# and will get .gitignored. Don't want your tokens flying into cyberspace. +# +# There are a bunch of fields that need replacing, so once you do that, +# your new .env file should work perfectly. Until it doesn't. +# +# I wish you luck! +# - TheSomeoneXD +# +# + +# Prefix +PREFIX="!" + +# Discord Server ID +# Replace them with your own on a sandbox server! +SANCTUM_ID="454425466821017611" + +# Role IDs (A = Obsidian, B = Genesis, C = Hand) +# Replace them with your own on a sandbox server! +GROUP_A_ROLE="470656524042371072" +GROUP_B_ROLE="470668082441093121" +GROUP_C_ROLE="470656609295794199" + +# Channel IDs +# Replace them with your own on a sandbox server! +CODEX_CHANNEL_ID="457580831284789249" +OUTSKIRTS_CHANNEL_ID="462382076927148054" +TAVERN_CHANNEL_ID="462684096024543242" +GATE_CHANNEL_ID="459196623923445779" +STASIS_CHANNEL_ID="468984551113228318" +CRYSTAL_SHORES_CHANNEL_ID="482629581690372099" +SEA_OF_FOG_CHANNEL_ID="464150321699225634" +DEADLANDS_CHANNEL_ID="459196395119837195" +HELLS_GATE_CHANNEL_ID="464238060243124245" +TEST_CHANNEL_ID="464838060262293514" + +# Bot Channels in SANCTUM (A = Obsidian, B = Genesis, C = Hand) +# Replace them with your own on a sandbox server! +GROUP_A_BOT_ID="493972208616603658" +GROUP_B_BOT_ID="493972336190685185" +GROUP_C_BOT_ID="493972354137849856" + +# Bot IDs +# Replace them with your own on a sandbox server! +MORI_ID="461294299515191306" +RAVAGER_ID="458036985353732097" +MOSIAH_ID="457713779078332416" +GRAZE_ID="460640089198821377" +SONYA_ID="458078969653100554" +REY_ID="462675530928357376" +ALEXIS_ID="462708244171718656" +MONTGOMERY_GENESIS_ID="482642611023249409" +KAMALA_OBSIDIAN_ID="482644250354384906" +DAIRO_HAND_ID="482644985318211594" +LIBRARIAN_ID="458033243481047082" + +# Bot Tokens +ADAM_TOKEN="" +RAVAGER_TOKEN="" +WOLF_TOKEN="" +CROW_TOKEN="" +MOSIAH_TOKEN="" +REY_TOKEN="" +ALEXIS_TOKEN="" +GRAZE_TOKEN="" +MORI_TOKEN="" +LIBRARIAN_TOKEN="" +DRAVEN_MAW_TOKEN="" +SONYA_TOKEN="" +MONTGOMERY_GENESIS_TOKEN="" +KAMALA_OBSIDIAN_TOKEN="" +DAIRO_HAND_TOKEN="" +GHOST_TOKEN="" + +# Server Pass Key +SERVER_PASS_KEY="" \ No newline at end of file diff --git a/.gitignore b/.gitignore index ad46b30..fbf1604 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,6 @@ typings/ # next.js build output .next + +# Private build tool +buildanddeploy.py diff --git a/ADAM/adam.js b/ADAM/adam.js new file mode 100644 index 0000000..1fac4b2 --- /dev/null +++ b/ADAM/adam.js @@ -0,0 +1,1145 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); + +// Bot Modules (stores http requests & random functions respectively) +const npcSettings = require('./npcSettings'); +const dialog = require('./dialog'); +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); + +const commandArray = ['!checkin', '!stats', '!inventory', '!upgrade', '!heal', '!quests'] + +// Creates an array that seperates 10 items into seperate arrays each +const itemDB = { + "iron_sword": { + "name": "Iron Sword", + "info": "This sturdy sword is great for slashing Ravagers.", + "type": { + "type": "Weapon", + "subtype": "Sword", + "stats": [ + { "attack": 2 } + ] + }, + "amount": 1 + }, + "steel_sword": { + "name": "Steel Sword", + "info": "A tougher form of the Iron Sword, it deals greater blows.", + "type": { + "type": "Weapon", + "subtype": "Sword", + "stats": [ + { "attack": 3 } + ] + }, + "amount": 1 + }, + "leather_armour": { + "name": "Leather Armour", + "info": "A light piece of armour made of leather.", + "type": { + "type": "Equipment", + "subtype": "Armour", + "stats": [ + {"defence": 3}, {"speed": 1} + ] + }, + "amount": 1 + }, + "leather_helm": { + "name": "Leather Helm", + "info": "A leather headpiece, designed for some protection and shade.", + "type": { + "type": "Equipment", + "subtype": "Helm", + "stats": [ + {"defence": 2}, {"speed": 1} + ] + }, + "amount": 1 + }, + "leather_boots": { + "name": "Leather Boots", + "info": "Comfy, leather boots made for long trips in New Eden's deserts.", + "type": { + "type": "Equipment", + "subtype": "Boots", + "stats": [ + {"defence": 1}, {"speed": 1} + ] + }, + "amount": 1 + }, + "iron_armour": { + "name": "Iron Armour", + "info": "Tough, iron armour. It feels solid.", + "type": { + "type": "Equipment", + "subtype": "Armour", + "stats": [ + {"defence": 4}, {"speed": -1} + ] + }, + "amount": 1 + }, + "health_potion": { + "name": "Health Potion", + "info": "A sweet-smelling potion that heals the drinker for 50 HP.", + "type": { + "type": "Potion", + "stats": [ + {"healing": 50} + ] + }, + "amount": 1 + } +} + +// For development testing +var userItems = []; + +addItem(undefined, itemDB["health_potion"], 10); +addItem(undefined, itemDB["iron_sword"], 1); +addItem(undefined, itemDB["leather_armour"], 1); +addItem(undefined, itemDB["leather_boots"], 1); +addItem(undefined, itemDB["leather_helm"], 1); +addItem(undefined, itemDB["steel_sword"], 1); + +// State Machine (Uncomment if needed) +/* +var BotEnumState = { + WAITING: 0, + ACTIVE: 1 +} +var botState = BotEnumState.ACTIVE; +*/ + +// 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) + if (client.user.username !== "Ghost 5.0.1") + client.user.setStatus('online'); + else + client.user.setStatus('invisible'); + + if (client.user.username == "Captain Montomery") { + const newName = "Captain Montgomery"; + console.log("Username is " + client.user.username + "! Typos are NOT(?) cannon, so better change stuff.\nAttempting rename to " + newName + "..."); + + // Set username + client.user.setUsername(newName) + .then(user => console.log(`Success! New username is now ${user.username}.`)) + .catch(console.error); + + // Changes nickname + //client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id).setNickname(""); + } + + // Sets your "Playing" + if (npcSettings.activity) { + client.user.setActivity(npcSettings.activity, { type: npcSettings.type }) + .then(presence => console.log(`Activity set to ${presence.game ? presence.game.name : 'none'}`)) + .catch(console.error); + } + + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + + // Message has to be in a bot channel + //if (!channelProcessor.isBotChannel(message.channel.id)) { + if (message.channel.id !== npcSettings.botChannel) { + // If it's the gate + if (message.channel.id === process.env.GATE_CHANNEL_ID && client.user.username === "A.D.A.M") { + const args = message.content.slice(prefix.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + // If they haven't done the right command to enter + if (!(command === "obsidian" || command === "hand" || command === "genesis")) { + console.log("User sent " + command + (command !== "obsidian")); + if (!(command !== "intro" || command !== "introgenesis" || command !== "introhand" || command !== "introobsidian" || command !== "introend")) { + message.reply("Please choose one of the factions by typing your desired faction shown above (!genesis, !obsidian, or !hand).") + .then(msg => { + msg.delete(10000) + }) + .catch(console.error); + } + } + message.delete(100); + } + } + if (message.channel.id === process.env.STASIS_CHANNEL_ID) return; + + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "ping": + if (isAdmin(message.author.id)) + message.reply("What is your command, almighty and glorious master!"); + break; + case "intro": + if (client.user.username == "A.D.A.M.") + sendMessage(message.channel.id, dialog.getDialog("intro", message.author.id)); + break; + case "introobsidian": + if (client.user.username == "Kamala, Obsidian Vice President") + sendMessage(message.channel.id, dialog.getDialog("introObsidian", message.author.id)); + break; + case "introgenesis": + // Typos officially cannon + if (client.user.username == "Captain Montgomery") + sendMessage(message.channel.id, dialog.getDialog("introGenesis", message.author.id)); + break; + case "introhand": + if (client.user.username == "Dairo, High Prophet of The Hand") + sendMessage(message.channel.id, dialog.getDialog("introHand", message.author.id)); + break; + case "introend": + if (client.user.username == "A.D.A.M.") + sendMessage(message.channel.id, dialog.getDialog("introEnd", message.author.id)); + break; + case "admingetroleids": + //for (var i in discordBot.servers[serverID].roles) { + // console.log(discordBot.servers[serverID].roles[i]); // issues + //} + console.log("!adminGetRoleIDs is Disabled for now"); + break; + case "obsidian": + if (client.user.username == "Kamala, Obsidian Vice President") + changeFaction(process.env.GROUP_A_ROLE, message.channel.id, message.author.id, + message.member, process.env.GROUP_A_BOT_ID); + break; + case "genesis": + if (client.user.username == "Captain Montgomery") + changeFaction(process.env.GROUP_B_ROLE, message.channel.id, message.author.id, + message.member, process.env.GROUP_B_BOT_ID); + break; + case "hand": + if (client.user.username == "Dairo, High Prophet of The Hand") + changeFaction(process.env.GROUP_C_ROLE, message.channel.id, message.author.id, + message.member, process.env.GROUP_C_BOT_ID); + break; + case "beginners": + if (!isAdmin()) break; + if (client.user.username == "A.D.A.M.") { + + var timedEvents = `Mori will revive all weakened travelers every day, and may heal you for a cost, if Mori can find the right things to do so.`; + + var commandsText = `These commands can be done in <#${process.env.GROUP_B_BOT_ID}>, <#${process.env.GROUP_C_BOT_ID}>, or <#${process.env.GROUP_A_BOT_ID}>.\n` + + `**!checkin** - For your help around the city, you can use this to be given a sum of **<:crystals:460974340247257089> Crystals** daily from your faction leader.\n` + + `**!stats** - Your faction leader can check your stats, and your total crystals, materials, etc., with this command.\n`; + + const embed = new Discord.RichEmbed() + .setAuthor( "SANCTUM Beginner's Guide", client.user.avatarURL) + .setColor("#f1c40f") + .setTitle("Welcome to SANCTUM!") + .setDescription("Welcome to SANCTUM, traveler. I hope you will understand the basics on how to survive after the Genesis ship's crash.") + .addField("Basic Commands", commandsText) + .addField("Mori", timedEvents) + + message.channel.send({embed}); + } + break; + case "questboard": + if (!isAdmin(message.author.id)) break; + if (client.user.username != "A.D.A.M.") break; + + var quests = { + "quests": [ + { + "title": "The Lost Pendant", + "id": "thelostpendant", + "description": "Lorem ipsum, or some placeholder text. I wish I knew what to put here, I'm no writer! I need to put more text here in order for the inlines to work more nicely. Not like it matters on mobile, however.", + "objective": "Go to <#${process.env.OUTSKIRTS_CHANNEL_ID}> and **!scavenge** in hopes to find the pendant.", + "userID": process.env.LIBRARIAN_ID, + "color": "keepersOfTheCityColor", + "recommendedLVL": 1, + "questLength": "Short", + "rewards": [ + { + "name": "Crystals", + "emote": "<:crystals:460974340247257089>", + "amount": 10 + }, + { + "name": "Electronics", + "emote": "<:melectronics:462682568911749120>", + "amount": 2 + }, + { + "name": "Gem", + "emote": "<:mgem:462450060718768148>", + "amount": 2 + } + ] + }, + { + "title": "Looming Ravager Outside", + "id": "loomingravager", + "description": "Hey, I have a problem, ya' see. There's a Ravager outside my tavern! And I've been waiting fo' it to go, but it ain't leaving!! I need your help to get rid of it, it's scaring me and my customers!", + "objective": "Go and help slay a Ravager.", + "userID": process.env.ALEXIS_ID, + "color": "keepersOfTheCityColor", + "recommendedLVL": 1, + "questLength": "Short", + "rewards": [ + { + "name": "Crystals", + "emote": "<:crystals:460974340247257089>", + "amount": 5 + } + ] + } + ] + } + + // Collects all preset colors + const keepersOfTheCityColor = message.guild.roles.find(role => role.name === "Keepers of the City").color; + console.log("COLOR: " + keepersOfTheCityColor); + + // Header & Footer (mobile design choice) for quests + const header = new Discord.RichEmbed() + .setAuthor("Quests", client.user.avatarURL) + .setColor(keepersOfTheCityColor) + .setTitle("The Travelers' Quest Board") + .setDescription("Residents of New Eden can post their help requests here, and whoever fulfils them can earn some rewards.") + .setFooter(`⏰ 7 hrs. before the quests are exchanged for new ones.`) + await message.channel.send({embed: header}); + + // Displays all quests in order + for (let i = 0; i < quests.quests.length; i++) { + const element = quests.quests[i]; + const bot = client.guilds.get(process.env.SANCTUM_ID).members.get(element.userID); + var newColor = element.color; + var newDescription = element.description; + var newObjective = element.objective; + var newReward = ""; + const questLength = `Quest Length: **${element.questLength}**.`; + + // Adds rewards up + element.rewards.forEach(reward => { + newReward += `> **${reward.emote} ${reward.name}** [${reward.amount}x]\n`; + }); + + // Returns internal color if needed + if (element.color === "keepersOfTheCityColor") newColor = keepersOfTheCityColor; + + // Replaces certain strings with internal channel data if needed + // NEED TO FIGURE OUT REGEX EXPRESSIONS FOR MASS REPLACE + newObjective = element.objective.replace("${process.env.OUTSKIRTS_CHANNEL_ID}", `${process.env.OUTSKIRTS_CHANNEL_ID}`); + + const body = new Discord.RichEmbed() + .setAuthor(`${bot.displayName}`, bot.user.avatarURL) + .setColor(newColor) + .setTitle(`📃 ${element.title}`) + .setDescription(newDescription) + .addField("Objective", newObjective) + .addField("Reward", newReward, true) + .addField("Info", `Recommended Level: **<:level:461650552506286093> ${element.recommendedLVL}+**.\n${questLength}`, true) + .setFooter(`React with ❗ to take on the quest, and help ${bot.displayName}.`) + + var bodyMessage = await message.channel.send({embed: body}); + await bodyMessage.react("❗"); + } + + // Specifically for mobile + await message.channel.send({embed: header}); + + break; + case "guild": + if (!isAdmin(message.author.id)) break; + if (client.user.username != "A.D.A.M.") break; + + switch (args[0]) { + case "create": + // Start message + var progressMessage = await message.channel.send(`${message.author} I will setup a safe place in the City, please wait.`); + + // Creates new channel & sets topic + var channelName = message.content.replace("!guild create ", '').trim(); + var newChannel = await message.guild.createChannel(channelName, 'text'); + await newChannel.setParent('496813609201172500'); + newChannel.setTopic(`This is the ${channelName} guild!`); + + // Chooses a role name + const roleName = channelName.replace(/\\/g, ""); + + // Creates role & adds it to author + var newRole = await message.guild.createRole({ + name: roleName, + color: 'DARK_AQUA', + }); + await message.member.addRole(newRole); + + // Sets permissions + await newChannel.overwritePermissions(message.guild.roles.find(role => role.name === '@everyone'), { + 'VIEW_CHANNEL': false + }); + await newChannel.overwritePermissions(message.guild.roles.find(role => role.name === roleName), { + 'VIEW_CHANNEL': true + }); + await newChannel.overwritePermissions(message.guild.roles.find(role => role.name === 'Can View All Guilds'), { + 'VIEW_CHANNEL': true + }); + + // Progress message + await progressMessage.edit(`${message.author} I have finished setting up your new ${newRole} guild, in the City. Put it into good use, traveler.`); + + break; + case "tag": + // Appends guild name to user (Grabs nickname by removing anything in []s) + // NOTE: CODE WORKS, JUST DOESN'T LOOK RIGHT + /* + const userNickname = message.member.displayName.replace(/\[(.*?)\]+/g, '').trim(); + message.member.setNickname(`[${roleName}] ${userNickname}`) + .catch((e) => { + console.log("ERROR HAPPENED I THINK") + console.log(e); + + // Catches >32 nickname + if (e.code == 50035) { + message.channel.send(`${message.author} I couldn't change your username in order to put your guild tag, as it would be too long.`) + } + }); + */ + break; + } + + break; + + } + + if (!checkValidDisplay(message.member, message.channel.id, true) && client.user.username != "A.D.A.M.") return; + + switch (command) { + case "checkin": + if (client.user.username == "A.D.A.M.") break; + var checkinAmount = calcRandom.random(4, 9); + var checkInResponse = String(dataRequest.sendServerData("checkin", checkinAmount, message.author.id)); + if (checkInResponse == "1") { + sendMessage(message.channel.id, dialog.getDialog("checkin", message.author.id, checkinAmount)); + addXP(message.author.id, 1); + } else { + sendMessage(message.channel.id, dialog.getDialog("checkinLocked", message.author.id, checkInResponse)); + } + break; + case "give": // Could revamp to make player ID and amount interchangable + if (client.user.username == "A.D.A.M.") break; + var giveAmount = Math.floor(args[0]); + if (message.mentions.members.size > 0) { + console.log(message.mentions.members); + var giveToID = message.mentions.members.first().id; + console.log("GIVE: " + giveToID + " | message.author.id: " + message.author.id) + if (giveToID === message.author.id) { + sendMessage(message.channel.id, dialog.getDialog("giveInvalidUserSelf", message.author.id)); + return; + } + var amountInAccount = dataRequest.loadServerData("account",message.author.id); + if (giveAmount > 0) { + if (amountInAccount >= giveAmount) { + if (dataRequest.sendServerData("transfer",giveToID,message.author.id,giveAmount) == 1) { + sendMessage(message.channel.id, dialog.getDialog("giveSuccessful", message.author.id, giveToID, giveAmount)); + } else { + sendMessage(message.channel.id, dialog.getDialog("giveFailed", message.author.id)); + } + } else { + sendMessage(message.channel.id, dialog.getDialog("giveNotEnoughInAccount", message.author.id)); + } + } else { + sendMessage(message.channel.id, dialog.getDialog("giveNotAboveZero", message.author.id)); + } + } else { + sendMessage(message.channel.id, dialog.getDialog("giveInvalidUser", message.author.id)); + } + break; + case "lore": + if (client.user.username == "A.D.A.M.") break; + sendMessage(message.channel.id, dialog.getDialog("lore", args[0])); + break; + case "stats": + if (client.user.username == "A.D.A.M.") break; + getLevelUp(message.author.id); + + var attacker = String(dataRequest.loadServerData("userStats",message.author.id)); + var scavengeResponse = String(dataRequest.loadServerData("artifactsGet",message.author.id)); + var attackerStrength = parseFloat(attacker.split(",")[0]); + var attackerSpeed = parseFloat(attacker.split(",")[1]); + var attackerStamina = parseFloat(attacker.split(",")[2]); + var attackerHealth = parseFloat(attacker.split(",")[3]); + var attackerMaxStamina = parseFloat(attacker.split(",")[4]); + var attackerMaxHealth = parseFloat(attacker.split(",")[5]); + var attackerWallet = parseFloat(attacker.split(",")[6]); + var attackerXP = parseFloat(attacker.split(",")[7]); + var attackerLVL = Math.floor(parseFloat(attacker.split(",")[8])); + var attackerLvlPercent = parseFloat(attacker.split(",")[9]); + var attackerStatPoints = parseFloat(attacker.split(",")[10]); + var attackerChests = parseFloat(attacker.split(",")[11]); + + var items = scavengeResponse.split(","); + var response = items[0]; + var ultrarare = parseFloat(items[1]); + var rare = parseFloat(items[2]); + var uncommon = parseFloat(items[3]); + var common = parseFloat(items [4]); + var scrap = parseFloat(items[5]); + var totalQuantity = ultrarare + rare + uncommon + common + scrap; + var userStats = ""; + + if (attackerLVL >= 30) { + userStats += "<@" + message.author.id + "> <:level:461650552506286093> **" + attackerLVL + "** (MAX)\t\t" + "<:cannister:462046687058198530> **" + attackerStatPoints + "**\t\t" + "<:cyphercrate:464135029036154950> **" + attackerChests + "** (" + attackerLvlPercent + "%)"; + } else { + userStats += "<@" + message.author.id + "> <:level:461650552506286093> **" + attackerLVL + "** (" + attackerLvlPercent + "%)\t\t\t" + "<:cannister:462046687058198530> **" + attackerStatPoints + "**\t\t\t<:cyphercrate:464135029036154950> **" + attackerChests + "**"; + } + userStats += "```STR: " + attackerStrength + " | SPD: " + attackerSpeed + " | STAM: " + attackerStamina + "/" + attackerMaxStamina + " | HP: " + attackerHealth + "/" + attackerMaxHealth + "```"; + userStats += "<:crystals:460974340247257089> **" + attackerWallet + "**\t\t"; + if (response == "success") { + if (totalQuantity > 0) { + //userStats += "\n"; + if (scrap > 0) { userStats += "<:scrap:463436564379336715> **" + scrap + "**\t\t"; } + if (common > 0) { userStats += "<:mcloth:462682568483930123> **" + common + "**\t\t"; } + if (uncommon > 0) { userStats += "<:mmetal:462682568920137728> **" + uncommon + "**\t\t"; } + if (rare > 0) { userStats += "<:melectronics:462682568911749120> **" + rare + "**\t\t"; } + if (ultrarare > 0) {userStats += "<:mgem:462450060718768148> **" + ultrarare + "**\n\n"; } + } else {console.log("failure2");} + } else {console.log("failure");} + + sendMessage(message.channel.id, userStats); + break; + case "estats": + // Sees if the user is supposed to level up + getLevelUp(message.author.id); + + // Grabs all parameters from server + var attacker = String(dataRequest.loadServerData("userStats",message.author.id)); + var scavengeResponse = String(dataRequest.loadServerData("artifactsGet",message.author.id)); + var attackerStrength = parseFloat(attacker.split(",")[0]); + var attackerSpeed = parseFloat(attacker.split(",")[1]); + var attackerStamina = parseFloat(attacker.split(",")[2]); + var attackerHealth = parseFloat(attacker.split(",")[3]); + var attackerMaxStamina = parseFloat(attacker.split(",")[4]); + var attackerMaxHealth = parseFloat(attacker.split(",")[5]); + var attackerWallet = parseFloat(attacker.split(",")[6]); + var attackerXP = parseFloat(attacker.split(",")[7]); + var attackerLVL = Math.floor(parseFloat(attacker.split(",")[8])); + var attackerLvlPercent = parseFloat(attacker.split(",")[9]); + var attackerStatPoints = parseFloat(attacker.split(",")[10]); + var attackerChests = parseFloat(attacker.split(",")[11]); + + var items = scavengeResponse.split(","); + var response = items[0]; + var ultrarare = parseFloat(items[1]); + var rare = parseFloat(items[2]); + var uncommon = parseFloat(items[3]); + var common = parseFloat(items [4]); + var scrap = parseFloat(items[5]); + var totalQuantity = ultrarare + rare + uncommon + common + scrap; + + // Forms stats into a string + var levelText = `<:level:461650552506286093> **${attackerLVL}**`; + var levelProgress = `(${attackerLvlPercent}%)`; + var crystalText = `<:crystals:460974340247257089> **${attackerWallet}**`; + var cannisterText = `<:cannister:462046687058198530> **${attackerStatPoints}**`; + var cypherCrateText = `<:cyphercrate:464135029036154950> **${attackerChests}**`; + var userStats = "```" + `STR: ${attackerStrength} | SPD: ${attackerSpeed} | STAM: ${attackerStamina}/${attackerMaxStamina} | HP: ${attackerHealth}/${attackerMaxHealth}` + "```"; + var materialsText = ``; + + // Materials + if (response == "success") { + if (totalQuantity > 0) { + if (scrap > 0) { materialsText += `<:scrap:463436564379336715> **${scrap}**`; } + if (common > 0) { materialsText += ` | <:mcloth:462682568483930123> **${common}**`; } + if (uncommon > 0) { materialsText += ` | <:mmetal:462682568920137728> **${uncommon}**`; } + if (rare > 0) { materialsText += ` | <:melectronics:462682568911749120> **${rare}**`; } + if (ultrarare > 0) { materialsText += ` | <:mgem:462450060718768148> **${ultrarare}**`; } + } else {console.log("failure2");} + } else {console.log("failure");} + + // Says level is maxed out if it is LVL 30+ + if (attackerLVL >= 30) { + levelProgress = `(MAX)`; + cypherCrateText += ` (${attackerLvlPercent}%)`; + } + + // Creates embed & sends it + const embed = new Discord.RichEmbed() + .setAuthor(`${message.member.displayName}`, message.author.avatarURL) + .setColor(message.member.displayColor) + .setDescription(`${levelText} ${levelProgress} | ${crystalText} | ${cannisterText} | ${cypherCrateText}`) + .addField("Stats", userStats) + .addField("Materials", `${materialsText}`) + .setFooter("Commands: !inventory | !checkin | !upgrade | !heal | !quests") + + message.channel.send(embed); + break; + case "inventory": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num)) { + return sendInventory(message, num); + } + } else { + return sendInventory(message); + } + break; + case "inv": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num)) { + return sendInventory(message, num); + } + } else { + return sendInventory(message); + } + break; + case "item": + return appraiseItem(message); + + case "help": + if (client.user.username == "A.D.A.M.") break; + if (!args[0]) { + sendMessage(message.channel.id, dialog.getDialog("help", message.author.id)); + } else if (message.mentions.members.first() !== undefined) { + // MORI + if (message.mentions.members.first().id == process.env.MORI_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpMori", message.author.id)); + } + // RAVAGER + if (message.mentions.members.first().id == process.env.RAVAGER_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpRavager", message.author.id)); + + } + // MOSIAH + if (message.mentions.members.first().id == process.env.MOSIAH_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpMosiah", message.author.id)); + + } + // GRAZE + if (message.mentions.members.first().id == process.env.GRAZE_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpGraze", message.author.id)); + + } + // SONYA + /* + if (message.mentions.members.first().id == process.env.SONYA_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpSonya", message.author.id)); + } + */ + // REY + if (message.mentions.members.first().id == process.env.REY_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpRey", message.author.id)); + } + // ALEXIS + if (message.mentions.members.first().id == process.env.ALEXIS_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpAlexis", message.author.id)); + } + //sendMessage(message.channel.id, ":frowning:" + message.mentions.members.first().id); + } + break; + } + +}); + +client.on('error', console.error); + +// Gets footer commands for botspam channel commands +function getFooterCommands(currentCommand) { + var textFooter = ""; + const filtered = commandArray.filter(word => word !== currentCommand); + //console.log(filtered); + + filtered.forEach(element => { + var appendedText = " | "; + if (textFooter.length !== 0) textFooter += appendedText; + textFooter += element; + }); + //console.log(textFooter); + return textFooter; +} + +// Adds item to inventory +function addItem(userID, item, amount) { + // If item exists in inventory + console.log("[Add Item] " + amount); + var i = userItems.findIndex(i => i.name === item.name); + console.log("[Item Amount Item Exists] i Equals " + i); + + // If there is an item that exists in inventory + if (i !== -1) { + console.log("[Item Amount Start] " + userItems[i].amount); + userItems[i].amount += amount; // Increments amount value + console.log("[Item Amount Finish] " + userItems[i].amount); + // Disallows adding objects such as crystals + } else { + console.log("[Item Amount Wait] Created item for the first time."); + var clonedItem = JSON.parse(JSON.stringify(item)); // Clones item in order to not actually increment the rooms.js item JSON data + userItems.push(clonedItem); + addItem(userID, item, amount - 1); + } +} + +// Sends inventory into chat +async function sendInventory(message, pageNum, newMessage) { + var items = ""; + var groupedArr = createGroupedArray(userItems, 5); + + // Sets a default page num, or makes it human readable + if (pageNum === undefined) pageNum = 1; else { + if (pageNum < 1) pageNum = 1; + if (groupedArr.length < pageNum) pageNum = groupedArr.length; + } + + // Checks if page number is valid + if (pageNum > groupedArr.length) { + // If it's longer than actual length, but isn't just an empty inventory + if (!groupedArr.length === 0) return; + } + + //console.log(pageNum); + + // Grabs item in loop, parses it, then adds it to "items" variable + if (groupedArr[pageNum - 1]) { + for (let index = 0; index < groupedArr[pageNum - 1].length; index++) { + // Grabs an item, from a page index + const element = groupedArr[pageNum - 1][index]; + + // Makes if there is an emote, it'll add an extra space + var emoteText = ""; + if (element.emote) emoteText = element.emote + " "; + + // Adds it in + items += `> ${emoteText}**${element.name}** [${element.amount}x] ${element.info}\n`; + } + } + + // No items message to fill field + if (items === "") items = "There are no items in the party's inventory."; + + // To make the message of "Page 1/0" with no items in !inventory not happen + var moddedLength = groupedArr.length; + if (moddedLength < 1) moddedLength = 1; + + const footer = getFooterCommands("!inventory"); + + // Creates embed & sends it + const inv = new Discord.RichEmbed() + .setAuthor(`${message.member.displayName}`, message.author.avatarURL) + .setColor(message.member.displayColor) + .setDescription("I can appraise your items with `!item [ITEM NAME]`, traveler.") + .addField(`Items (Page ${pageNum}/${moddedLength})`, items) + .setFooter(`Commands: ${footer}`) + + var invMessage; + if (!newMessage) + invMessage = await message.channel.send({embed: inv}); + else { + invMessage = newMessage; + await invMessage.edit({embed: inv}); + } + + // Collector for emotes + const emotes = ['⬅', '❌', '➡']; + const collector = invMessage.createReactionCollector( + (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id , { time: 15 * 1000 }); + var react = ""; + var endedOnReact; + + // Sends reactions + if (!newMessage) { + for (let i = 0; i < emotes.length; i++) { + const element = emotes[i]; + console.log(element); + await invMessage.react(element); + } + } + + // Collects reactions + collector.on("collect", async reaction => { + var user = reaction.users.last(); + react = reaction.emoji.name; + if (react !== '❌') { reaction.remove(user); } + endedOnReact = true; + collector.stop(); + }); + + // Clears reactions + collector.once("end", async collecter => { + console.log("[Reaction Options] Ended collector, clearing emotes and sending timing out message if needed."); + + if (!endedOnReact) { + invMessage.clearReactions(); + return message.channel.send(":x: **Timed Out**: The emote reaction request timed out after 15 seconds."); + } + if (react === '❌') { + invMessage.clearReactions(); + return invMessage.edit(invMessage.content); + } + + var pageNumModifier = 0; + if (react === emotes[0]) pageNumModifier -= 1; + if (react === emotes[2]) pageNumModifier += 1; + console.log(pageNum + " | " + pageNumModifier); + sendInventory(message, pageNum + pageNumModifier, invMessage); + }); +} + +// Appraise an item +async function appraiseItem(message) { + const itemName = message.content.replace("!item", "").trim().toLowerCase(); + console.log("[Item Appraisal] " + `<< ${itemName} >>`); + + // Show if no parameter is given + if (itemName === "" || !itemName) { + message.channel.send(`:x: ${message.author} Please tell me the item name from your inventory, or I won't know which item you want me to look at.`); + return; + } + + var i = userItems.findIndex(i => i.name.toLowerCase() === itemName); + console.log("[Item Amount Item Exists] i Equals " + i); + + // If there is an item that exists in inventory + if (i !== -1) { + console.log(`[Item Appraisal] Found item in inventory!`); + const embed = new Discord.RichEmbed() + .setAuthor(`${message.member.displayName}`, message.author.avatarURL) + .setColor(message.member.displayColor) + .setTitle(userItems[i].name) + .setDescription(userItems[i].info) + + if (userItems[i].type.subtype) + embed.addField("Type", `${userItems[i].type.type}\n> ${userItems[i].type.subtype}`, true) + else + embed.addField("Type", `${userItems[i].type.type}`, true) + + if (userItems[i].type.stats) { + console.log(JSON.stringify(userItems[i].type.stats, null, 4)) + var itemStats = "There are no stats avaliable."; + var resetItemStats = false; + userItems[i].type.stats.forEach(element => { + if (element) { + if (!resetItemStats) { + resetItemStats = true; + itemStats = ""; + } + const types = [ + "attack", + "defence", + "speed", + "healing" + ]; + + types.forEach(type => { + if (element[type]) { + switch (type) { + case "attack": + itemStats += `ATK: ${element.attack}\n`; + break; + case "defence": + itemStats += `DEF: ${element.defence}\n`; + break; + case "speed": + itemStats += `SPD: ${element.speed}\n`; + break; + case "healing": + itemStats += `Healing: ${element.healing} HP\n`; + break; + } + } + }); + } + }); + } + + embed.addField("Stats", `${itemStats}`, true); + + message.channel.send(embed); + + // Disallows adding objects such as crystals + } else { + console.log("[Item Appraisal] Couldn't find item in inventory."); + message.channel.send(`:x: ${message.author} I'm unable to find "${itemName}" in your inventory.`); + } +} + +// Creates an array that creates multiple different arrays inside of that array -> [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +// http://www.frontcoded.com/splitting-javascript-array-into-chunks.html +var createGroupedArray = function(arr, chunkSize) { + var groups = [], i; + for (i = 0; i < arr.length; i += chunkSize) { + groups.push(arr.slice(i, i + chunkSize)); + } + return groups; +} + +// See if the bot should display its message +function checkValidDisplay(member, channelID, checkRole) { + if (client.user.username == "Kamala, Obsidian Vice President" && channelID === process.env.GROUP_A_BOT_ID) { + if (checkRole) { if (member.roles.has(process.env.GROUP_A_ROLE)) return true; } else true; + } + else if (client.user.username == "Captain Montgomery" && channelID === process.env.GROUP_B_BOT_ID) { + if (checkRole) { if (member.roles.has(process.env.GROUP_B_ROLE)) return true; } else true; + } + else if (client.user.username == "Dairo, High Prophet of The Hand" && channelID === process.env.GROUP_C_BOT_ID) { + if (checkRole) { if (member.roles.has(process.env.GROUP_C_ROLE)) return true; } else true; + } + else if (client.user.username == "Ghost 5.0.1") { + // JSON + const rooms = require('../TextAdv/rooms.json'); + var roomExists = false; + + // Loops for all rooms + rooms.rooms.forEach(element => { + if (channelID === rooms[element].channel) roomExists = true; + }); + + if (!roomExists) { + if (channelID === process.env.TEST_CHANNEL_ID) return true; + } else return true; + + } + + return false; +} + +// Gets if user has an Overseers rank +function isAdmin(userID) { + var guild = client.guilds.get(process.env.SANCTUM_ID); + return guild.members.get(userID).roles.find(role => role.name === "Overseers"); +} + +// Change Faction +async function changeFaction(factionID, channelID, userID, member, botChannelID) { + if (member.roles.has(factionID)) { + if (factionID === process.env.GROUP_A_ROLE) + sendMessage(channelID, dialog.getDialog("orderAlreadyJoined", userID)); + else if (factionID === process.env.GROUP_B_ROLE) + sendMessage(channelID, dialog.getDialog("anarchyAlreadyJoined", userID)); + else if (factionID === process.env.GROUP_C_ROLE) + sendMessage(channelID, dialog.getDialog("religionAlreadyJoined", userID)); + } else { + if (dataRequest.loadServerData("hasConvertedToday", userID) == 1) { + sendMessage(channelID, dialog.getDialog("alreadyConvertedToday", userID)); + } else { + // Creates new user + var response = String(dataRequest.sendServerData("newUser", "New user.", userID)); + + //var response = "createdUser" + // Obsidian Tech. + if (factionID === process.env.GROUP_A_ROLE) { + await member.removeRole(process.env.GROUP_B_ROLE); + await member.removeRole(process.env.GROUP_C_ROLE); + await member.addRole(process.env.GROUP_A_ROLE); + + dataRequest.sendServerData("conversion", "Converted to The Order.", userID); + + if (response == "createdUser") { + client.users.get(userID).send(dialog.getDialog("newUserPM", userID, getFactionName(factionID))); + sendMessage(botChannelID, dialog.getDialog("newUserWelcome", userID, `<#${getFactionName(factionID)}>`)); + } else { + sendMessage(channelID, dialog.getDialog("orderJoin", userID)); + } + + // Genesis Command + } else if (factionID === process.env.GROUP_B_ROLE) { + await member.removeRole(process.env.GROUP_C_ROLE); + await member.removeRole(process.env.GROUP_A_ROLE); + await member.addRole(process.env.GROUP_B_ROLE); + + dataRequest.sendServerData("conversion", "Converted to the Anarchy.", userID); + + if (response == "createdUser") { + client.users.get(userID).send(dialog.getDialog("newUserPM", userID, getFactionName(factionID))); + sendMessage(botChannelID, dialog.getDialog("newUserWelcome", userID, `<#${getFactionName(factionID)}>`)); + } else { + sendMessage(channelID, dialog.getDialog("anarchyJoin", userID)); + } + + // The Hand + } else if (factionID === process.env.GROUP_C_ROLE) { + await member.removeRole(process.env.GROUP_A_ROLE); + await member.removeRole(process.env.GROUP_B_ROLE); + await member.addRole(process.env.GROUP_C_ROLE); + + dataRequest.sendServerData("conversion", "Converted to The Religion.", userID); + + if (response == "createdUser") { + client.users.get(userID).send(dialog.getDialog("newUserPM", userID, getFactionName(factionID))); + sendMessage(botChannelID, dialog.getDialog("newUserWelcome", userID, `<#${getFactionName(factionID)}>`)); + } else { + sendMessage(channelID, dialog.getDialog("religionJoin", userID)); + } + } + } + } +} + +function addXP(userID,amount) { + var response = String(dataRequest.sendServerData("addXP", amount, userID)); +} + +function getLevelUp(userID) { + const server = client.guilds.get(process.env.SANCTUM_ID); + const member = server.members.get(userID); + if (client.user.username == "Kamala, Obsidian Vice President" && !member.roles.has(process.env.GROUP_A_ROLE)) return; + if (client.user.username == "Captain Montgomery" && !member.roles.has(process.env.GROUP_B_ROLE)) return; + if (client.user.username == "Dairo, High Prophet of The Hand" && !member.roles.has(process.env.GROUP_C_ROLE)) return; + + //const user = server.members.get(userID); + var response = String(dataRequest.sendServerData("getLevelUp", 0, userID)); + var responseMessage = String(response.split(",")[0]); + var lvl = Math.floor(parseFloat(response.split(",")[1])); + var statPoints = parseFloat(response.split(",")[2]); + + var attacker = String(dataRequest.loadServerData("userStats", userID)); + var chests = parseFloat(attacker.split(",")[11]); + + console.log(response.split(",")); + + majorLevelUp(lvl, server, userID); + + if (responseMessage == "levelup") { + //if (true) { + console.log("Chests: " + chests) + checkinLevelUp(userID, lvl, statPoints, chests); + } +} + +async function majorLevelUp(level, server, userID) { + const user = server.members.get(userID); + + var newChannel = ""; + + var levels = [ + // Role, Level + [server.roles.find(role => role.name === "LVL 1+"), 1, process.env.CRYSTAL_SHORES_CHANNEL_ID], + [server.roles.find(role => role.name === "LVL 15+"), 15, process.env.SEA_OF_FOG_CHANNEL_ID], + [server.roles.find(role => role.name === "LVL 30+"), 30, process.env.DEADLANDS_CHANNEL_ID] + ] + + // Shrinking level + if (level < 30) { + level = 15; + } else if (level < 15) { + level = 1; + } + + // Rank Level Up + var levelRole = server.roles.find(role => role.name === `LVL ${level}+`); + if (levelRole) { + var memberRole = user.roles.has(levelRole.id); + if (!memberRole) { + user.addRole(levelRole).catch(console.error); + for (let i = 0; i < levels.length; i++) { + const element = levels[i]; + if (element[1] !== level) { + await user.removeRole(element[0]); + } + } + if (user !== undefined) {// && newChannel !== undefined) { + var levelMarks = [1, 15, 30]; + + for (let i = 0; i < levelMarks.length; i++) { + const element = levelMarks[i]; + // Gets channel of array + newChannel = client.channels.get(levels[levels.findIndex(level => level[1] === element)][2]); + if (level === element) + newChannel.send(dialog.getDialog("level" + level, user, newChannel)); + } + } + } + } +} + +// Gets the user's role by member +function getFactionChannel(member) { + var playerChannel; + var isGroupA = member.roles.has(process.env.GROUP_A_ROLE); + var isGroupB = member.roles.has(process.env.GROUP_B_ROLE); + var isGroupC = member.roles.has(process.env.GROUP_C_ROLE); + //console.log(member.roles); + //console.log("isGroup: " + isGroupA + " " + isGroupB + " " + isGroupC); + if (isGroupA) playerChannel = process.env.GROUP_A_BOT_ID; + else if (isGroupB) playerChannel = process.env.GROUP_B_BOT_ID; + else if (isGroupC) playerChannel = process.env.GROUP_C_BOT_ID; + + return playerChannel; +} + +// Gets faction names by ID +function getFactionName(factionID) { + if (factionID === process.env.GROUP_A_ROLE) { + return "Obsidian Technologies"; + } + if (factionID === process.env.GROUP_B_ROLE) { + return "Genesis Command"; + } + if (factionID === process.env.GROUP_C_ROLE) { + return "The Hand"; + } +} + +function checkinLevelUp(userID, lvl, statPoints, chests) { + const guild = client.guilds.get(process.env.SANCTUM_ID); + if (lvl === 30) { + //Post level cap level up! + sendMessage(userID, getFactionChannel(guild.members.get(userID)), dialog.getDialog("levelUpLevelCap", userID, lvl, chests)); + } else { + //regular level up + sendMessage(userID, getFactionChannel(guild.members.get(userID)), dialog.getDialog("levelUp", userID, lvl, statPoints)); + } + //sendMessage(testChannelID, dialog.getDialog("levelUp", userID, lvl, statPoints)); +} + +// Updates stamina (1) and health by 1% every 2 min. +cron.schedule('*/2 * * * *', function() { + if (client.user.username === "A.D.A.M.") { + console.log('Updating STAMINA every 2 min.'); + dataRequest.sendServerData("updateStamina", 0); + }; +}); + +// Send message handler +function sendMessage(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message === undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message; + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); +} + +// Log our bot in +client.login(npcSettings.token); \ No newline at end of file diff --git a/ADAM/dialog.js b/ADAM/dialog.js new file mode 100644 index 0000000..79cbba5 --- /dev/null +++ b/ADAM/dialog.js @@ -0,0 +1,298 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + getDialog: function(dialogTag, data = "", data2 = "", data3 = "") { + switch(dialogTag) { + case "checkin": + return "<@" + data + ">" + " your presence has been noted. I've added " + data2 + " crystals to your account."; + + case "checkinLocked": + return ":x: <@" + data + ">" + " you already checked in with me " + data2 + ". You can check in again tomorrow."; + + case "alreadyConvertedToday": + return ":x: <@" + data + ">" + " as anxious as you may be, please don't attempt to change factions so quickly. You can only change once every 30 days."; + + case "depositSuccessful": + //codexLogEvent(data + " deposited " + data2 + " crystals."); + return "<@" + data + ">" + " your deposit of " + data2 + " crystals has been successful. Good luck."; + + case "depositFailed": + return ":x: <@" + data + ">" + " I can't make the deposit at the moment. I apologize for the inconvenience."; + + case "giveSuccessful": + //codexLogEvent(data + " gave " + data2 + " " + data3 + " crystals."); + return "<@" + data + ">" + " I've transferred " + data3 + " crystals to <@" + data2 + "> as per your request."; + + case "giveFailed": + return ":x: <@" + data + ">" + " I can't make that transfer at the moment. I apologize for the inconvenience."; + + case "giveNotEnoughInAccount": + return ":x: <@" + data + ">" + " You don't have that many crystals in your account. As such, I can't complete the transfer."; + + case "giveNotAboveZero": + return ":x: <@" + data + ">" + " In order for me to complete the transfer I need an amount above zero."; + + case "giveInvalidUser": + return ":x: <@" + data + ">" + " I can't find that traveler. Sorry."; + + case "giveInvalidUserSelf": + return ":x: <@" + data + ">" + " You can\'t send crystals to yourself. Sorry."; + + case "levelUp": + var dialogOptions = [ + 'I appreciate all of your help.', + 'Thank you for doing so much for the city.', + 'The other travelers are very grateful for your help.', + 'Your assistance is very much appreciated.', + 'Together we\'ve taken out most of the threats to city.', + 'The citizens of The Sanctum are most grateful.', + 'I cannot thank you enough for your help defending the city.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + var wordToUse = "it"; + if (data3 > 1) { var wordToUse = "them";} + return "You just hit **level " + data2 + "**! " + dialogOptions[randomNumber] + " I\'ve added a <:cannister:462046687058198530> **Nanotech Cannister** to your inventory so that you can upgrade your skills. You now have **" + data3 + "** total (you can check this any time with !stats). Use " + wordToUse + " wisely."; + + case "levelUpLevelCap": + var dialogOptions = [ + 'I appreciate all of your help.', + 'Thank you for doing so much for the city.', + 'The other travelers are very grateful for your help.', + 'Your assistance is very much appreciated.', + 'Together, we\'ve taken out most of the threats to city.', + 'The citizens of The Sanctum are most grateful.', + 'I cannot thank you enough for your help defending the city.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + return "You\'re currently at **level " + data2 + "** which is the current level cap! " + dialogOptions[randomNumber] + " I\'ve added a <:cyphercrate:464135029036154950> **Cypher Crate** to your inventory. Hopefully it contains something useful for you on your journey. You now have **" + data3 + "** total (you can check this any time with !stats). Good luck. "; + + case "help": + var temp = "*This world is strange and mysterious. And while I cannot help you on your journey or join your faction, I am here to help travelers to the best of my ability.* \n\nHere is what I can do for you:"; + temp += "\n\n"; + temp += "!checkin\n```Once per day, you may come see me for a daily sum in exchange for your help around the city.```"; + temp += "\n"; + temp += "!stats\n```I can share all of your stats and your crystal count information.```"; + temp += "\n"; + temp += "!give [AMOUNT] [@USER]\n```I can transfer some of your crystals to another traveler's account. Just make sure you have enough.```"; + temp += "\n"; + temp += "!help [@NAME]\n```I can tell you a little bit about some of the other people with us here on New Eden.```"; + temp += "\n"; + temp += "I hope this helps you on your journey, traveler."; + return temp; + + case "helpMori": + var temp = "*Mori is our resident head of the medbay. He can tend to your wounds and get you back on your feet. Here's what he can do:*"; + temp += "\n\n"; + temp += "!heal\n```Shows you Mori\'s available procedures for healing.```"; + temp += "\n"; + temp += "!heal [ITEM]\n```Purchases a procedure directly from him, and with his nanotech, takes effect immediately.```"; + return temp; + + case "helpGraze": + var temp = "*Graze is our loveable augmentation expert. He can help you upgrade your skills and boost your abilities. Here's what he can do:*"; + temp += "\n\n"; + temp += "!upgrade\n```Shows you the available upgrades that Graze can provide with your Nanotech Cannisters.```"; + temp += "\n"; + temp += "!upgrade [STAT]\n```Upgrades this specific stat permanently.```"; + return temp; + + case "helpMosiah": + var temp = `*Mosiah was exiled from our great city for many counts of misconduct, but it\'s been said he\'s been seen at <#${process.env.TAVERN_CHANNEL_ID}>. I recommend you not deal with him at all, but should you need to, here\'s what he can do:*`; + temp += "\n\n"; + temp += "!wager [AMOUNT]\n```Wagers your crystals in a primative coin flip bet. Winner takes all.```"; + return temp; + + case "helpRavager": + var temp = `*The Ravagers have been hunting us since crashing here on New Eden. They roam this planet and will attack travelers on sight. But you can defend yourself:*`; + temp += "\n\n"; + temp += "!attack\n```Sends your weapon towards an active Ravager. If you win the fight, you can loot their corpse for crystals. But be careful: they bite back.```"; + temp += "\n"; + temp += "!details\n```Shows you the details of the last Ravager fight to take place as well as the crystal distribution.```"; + return temp; + + case "helpSonya": + var temp = "*Professor Sonya is our resident archeologist, and she is fascinated by this world. Scavenge for some artifacts in the outskirts of the city, and she will apy you handsomely.*"; + temp += "\n\n"; + temp += "!scavenge\n```In #🌘the-outskirts, this allows you to look for rare artifacts for the professor.```"; + temp += "\n"; + temp += "!artifacts\n```Shows you the current artifacts that you have in your inventory.```"; + temp += "\n"; + temp += "!artifacts sell\n```Shows you the current prices that the professor is willing to pay for any artifacts that you may find.```"; + temp += "\n"; + temp += "!artifacts sell [TYPE]\n```Sells all of the artifacts that you have of that type to the professor, at current prices.```"; + return temp; + + case "helpRey": + var temp = "*Rey is a master of finding things that we need around the city. Resources are scarce, so anything you can help her find in <#462382076927148054> would be most helpful.*"; + temp += "\n\n"; + temp += "!scavenge\n```In #🌘the-outskirts, this allows you to look for materials and resources with Rey.```"; + temp += "\n"; + temp += "!materials\n```Shows you the current materials that you have in your inventory.```"; + return temp; + + case "helpAlexis": + var temp = "*Alexis is our top-of-the-line chemist who uses her talents to reward travelers with a nice and relaxing space. She\'d be happy to have or provide you with some company.*"; + temp += "\n\n"; + temp += "!buydrink\n```In #🍺travelers-watch, this allows you to buy a drink and relax.```"; + temp += "\n"; + temp += "!buydrink [@NAME]\n```In #🍺travelers-watch, you can buy a drink for a friend.```"; + temp += "\n"; + temp += "!tip [AMOUNT]\n```In #🍺travelers-watch, you can tip her for her great service. She might just give you a tip back.```"; + return temp; + + //Status commands + case "accountCheck": + return "<@" + data + ">" + " you currently have " + data2 + " crystals in your account."; + + case "bankCheck": + return "Currently, " + data + " has " + data2 + " crystals total in their bank."; + + case "victors": + return "Currently, " + data + " controls the fate of the codex."; + + case "noVictors": + return "The fate of the codex is still undetermined."; + + // Obsidian Technologies (Former Order) + case "orderAlreadyJoined": + return ":x: <@" + data + ">" + " The Obsidian Technologies already has your allegiance. There's no need to request a change."; + case "orderJoin": + //codexLogEvent(data + " joined Genesis Command."); + return "<@" + data + ">" + " you have joined the Obsidian Technologies. May peace reign upon your cause."; + + // Genesis Command (Former Anarchy) + case "anarchyAlreadyJoined": + return ":x: <@" + data + ">" + " The Genesis Command has already begun their chaos with you by their side. There's no need to request a change."; + case "anarchyJoin": + //codexLogEvent(data + " joined Obsidian Technologies."); + return "<@" + data + ">" + " you have joined the Genesis Command. May chaos come to those who oppose you."; + + // The Hand (Former Religion) + case "religionAlreadyJoined": + return ":x: <@" + data + ">" + " The Hand is happy to have you in their congregation already. There's no need to request a change."; + case "religionJoin": + //codexLogEvent(data + " joined The Hand."); + return "<@" + data + ">" + " you have joined The Hand. May the gods look favorably upon you."; + + //Onboarding + case "newUserWelcome": + messageToSend = "<@" + data + ">" + " welcome to " + data2 + ". If you need me for anything, you can contact me via this secure channel. Just use **!help** for a list of things I can do for you."; + messageToSend += "\n\nAnd don\'t forget to say hello to fellow travelers in "; + if (data2 == "Genesis Command") { + messageToSend += `${process.env.GROUP_B_BOT_ID}.`; + } + if (data2 == "Obsidian Technologies") { + messageToSend += `${process.env.GROUP_A_BOT_ID}.`; + } + if (data2 == "The Hand") { + messageToSend += `${process.env.GROUP_C_BOT_ID}.`; + } + return messageToSend; + case "newUserPM": + var messageToSend = ''; + messageToSend = "_Traveler, welcome to The Sanctum."; + messageToSend += "\n\n"; + + if (data2 == "Genesis Command") { + messageToSend += "I see that you've joined **Genesis Command**. The least reckless of the 3 factions, I can see why you'd pick them. You clearly understand that The Codex is a very powerful book, and should you be victorious, no one will have access to it\'s secrets. "; + } + if (data2 == "Obsidian Technologies") { + messageToSend += "I see that you've joined **Obsidian Technologies**. While they are the most chaotic of the 3 factions, I can see why you'd pick them. The Codex is a very powerful book, and should you be victorious, everyone will have equal access to it\'s secrets. "; + } + if (data2 == "The Hand") { + messageToSend += "I see that you've joined **The Hand**. While they are certainly the most suspicious of the 3 factions, I can see why you'd pick them. The Codex is a very powerful book, and should you be victorious, it is your job to guide the rest of the city using it\'s secrets."; + } + messageToSend += "\n\n"; + messageToSend += "I'll get you patched up and give you access to our team to upgrade skills and meet the others. There's just a few things I need you to take care of around the city:_"; + messageToSend += "\n\n"; + messageToSend += "**!checkin** with me daily.\n```Once a day I'll give you your daily allotment of crystals in exchange for some help around the city.```"; + messageToSend += "\n"; + messageToSend += "**!attack** any Ravagers in #the-deadlands.\n```With the constant bombardment from the enemies of the city, It\'s hard to keep us safe. I need your help```"; + messageToSend += "\n"; + messageToSend += "_Good luck. I'll be around if you need me._"; + return messageToSend; + //Lore + case "intro": + var tempLore = ''; + tempLore = "_Hello weary traveler."; + tempLore += "\n\n"; + tempLore += "My name is A.D.A.M. and I would like to offer you the amenities of The Sanctum. However, I cannot come to your aid until you choose a faction. I am dearly sorry to be so blunt and put trivial human rules in place over your sustenance and safety, but this is the only way to protect The Codex. But the Codex no longer exists since the Librarian destroyed it, so make something up, player."; + tempLore += " Your choices are as follows:_"; + return tempLore; + case "introHand": + var tempLore = "<:religionhand:461582719051104276> **<@&" + process.env.GROUP_C_ROLE + ">** - !hand\n```Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eu aliquet mauris, id congue nisi. Integer et lobortis tellus. Sed bibendum a metus quis volutpat. Mauris faucibus quam at euismod scelerisque. Vestibulum a elit auctor, venenatis augue in, rhoncus nisi. Mauris sagittis sit amet ante eget luctus. Maecenas id malesuada elit. Vestibulum nec ante nec justo venenatis tincidunt.```"; + return tempLore; + case "introGenesis": + var tempLore = "<:order:460991638152413194> **<@&" + process.env.GROUP_B_ROLE + ">** - !genesis\n```Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eu aliquet mauris, id congue nisi. Integer et lobortis tellus. Sed bibendum a metus quis volutpat. Mauris faucibus quam at euismod scelerisque. Vestibulum a elit auctor, venenatis augue in, rhoncus nisi. Mauris sagittis sit amet ante eget luctus. Maecenas id malesuada elit. Vestibulum nec ante nec justo venenatis tincidunt. ```"; + return tempLore; + case "introObsidian": + var tempLore = "<:anarchy:460990297099337750> **<@&" + process.env.GROUP_A_ROLE + ">** - !obsidian\n```Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eu aliquet mauris, id congue nisi. Integer et lobortis tellus. Sed bibendum a metus quis volutpat. Mauris faucibus quam at euismod scelerisque. Vestibulum a elit auctor, venenatis augue in, rhoncus nisi. Mauris sagittis sit amet ante eget luctus. Maecenas id malesuada elit. Vestibulum nec ante nec justo venenatis tincidunt.```"; + return tempLore; + case "introEnd": + var tempLore = "_Choose wisely._"; + return tempLore; + case "level1": + var tempLore = ''; + tempLore += `Congratulations ${data}, you have reached **${data2}**! Travelers defend the city from Ravagers here, and you can earn some crystals.` + return tempLore; + case "level15": + var tempLore = ''; + tempLore += `Congratulations ${data}, you have reached **${data2}**, where there are more dangerous enemies, lurking in the fog.` + return tempLore; + case "level30": + var tempLore = ''; + tempLore += `Congratulations ${data}, you have reached **${data2}**, the area most teeming with the strongest Ravagers. Watch your back, and good luck!` + return tempLore; + case "lore": + var tempLore = ''; + switch(data) { + case "backstory": + tempLore = "‘_Mother Earth had failed us. "; + tempLore += "\n\n"; + tempLore += "In her dying breath, she bore a starship, **The Genesis**, to save the last of humankind. But the **travelers** aboard were not prepared for the unwelcoming winds of barren space."; + tempLore += "\n\n"; + tempLore += "On the brink of extinction our forefathers landed here, but this was no earth. The desolate landscape of **The Deadlands** traded our starvation for thirst, our isolation for open and empty space. But despite our struggles, we could breathe again."; + tempLore += "\n\n"; + tempLore += "We walked for many days and many nights in **The Deadlands**, consuming only the native **crystals** climbing from the ground for sustenance. Leaving the shelter of our vessel behind for the hope of a new home. Many withered away under the scorching heat of the twin suns and the constant attacks from **Ravagers**, but Mother Earth kept her promise."; + tempLore += "\n\n"; + tempLore += "In our darkest hour, we laid eyes on **The Sanctum**, a city of the gods. Complete with a vault full of our edible crystals, and more than enough room for the entire population; A city with human amenities in the middle of an inhuman world, bestowed upon a dying nation in need. This place was truly a divine gift."; + tempLore += "\n\n"; + tempLore += "At the highest point of the city in the tower that touched the clouds, we found **The Librarian**. A meticulous mechanical record keeper hovering over his book, the great **Codex Arcana**. This was a book written in detail to record the actions of every man, woman, and child that lived among us. But it was far too powerful, and the secrets it contained proved lethal in the wrong hands."; + tempLore += "\n\n"; + tempLore += "And so began the **factions**, vying for control over the Codex._'"; + tempLore += "\n\n"; + tempLore += "- Excerpt from the **Teachings of Tiberius**. March 22, 2630."; + break; + case "genesis": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "travelers": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "deadlands": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "ravager": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "Sanctum": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "librarian": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "codex": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "factions": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + default: + tempLore = "Here is the lore that is available in my database. ```!lore backstory```" + break + } + console.log("TEMPLORE: " + tempLore); + return tempLore; + } + } +} diff --git a/ADAM/npcSettings.js b/ADAM/npcSettings.js new file mode 100644 index 0000000..ed4e094 --- /dev/null +++ b/ADAM/npcSettings.js @@ -0,0 +1,8 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + activity: "Automated Data Analysis Machine.", + type: "PLAYING", + token: process.env.ADAM_TOKEN, + botChannel: "default" +} diff --git a/ADAM/package-lock.json b/ADAM/package-lock.json new file mode 100644 index 0000000..aa3abae --- /dev/null +++ b/ADAM/package-lock.json @@ -0,0 +1,301 @@ +{ + "name": "nodejs-elasticbeanstalk", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-OU2+C7X+5Gs42JZzXoto7yOQ0A0=", + "requires": { + "@types/node": "*" + } + }, + "@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=", + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "9.6.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.28.tgz", + "integrity": "sha512-LMSOxMKNJ8tGqUVs8lSIT8RGo1XGWYada/ZU2QZcbcD6AW9futXDE99tfQA0K6DK60GXcwplsGGK5KABRmI5GA==" + }, + "@types/qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-mNhVdZHdtKHMMxbqzNK3RzkBcN1cux3AvuCYGTvjEIQT2uheH3eCAyYsbMbh2Bq8nXkeOWs1kyDiF7geWRFQ4Q==" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.0.0.tgz", + "integrity": "sha512-FlWbnhgjtwD+uNLUGHbMykMOYQaTivdHEmYwAKFjn6GKe/CqY0fNae93ZHTd20snh9ZLr8mTzIL9m0APQ1pjQg==" + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=" + }, + "http-basic": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-7.0.0.tgz", + "integrity": "sha1-gvClBr6UJzLsje6+6A50bvVzbbo=", + "requires": { + "@types/concat-stream": "^1.6.0", + "@types/node": "^9.4.1", + "caseless": "~0.12.0", + "concat-stream": "^1.4.6", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + } + }, + "http-response-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.1.tgz", + "integrity": "sha512-6L0Fkd6TozA8kFSfh9Widst0wfza3U1Ex2RjJ6zNDK0vR1U1auUR6jY4Nn2Xl7CCy0ikFmxW1XcspVpb9RvwTg==", + "requires": { + "@types/node": "^9.3.0" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "mime-db": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", + "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" + }, + "mime-types": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", + "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "requires": { + "mime-db": "~1.35.0" + } + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "promise": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.1.tgz", + "integrity": "sha1-5F1osAoXZHttpxG/he1u1HII9FA=", + "requires": { + "asap": "~2.0.3" + } + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "sync-request": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.0.0.tgz", + "integrity": "sha512-jGNIAlCi9iU4X3Dm4oQnNQshDD3h0/1A7r79LyqjbjUnj69sX6mShAXlhRXgImsfVKtTcnra1jfzabdZvp+Lmw==", + "requires": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + } + }, + "sync-rpc": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.4.tgz", + "integrity": "sha512-Iug+t1ICVFenUcTnDu8WXFnT+k8IVoLKGh8VA3eXUtl2Rt9SjKX3YEv33OenABqpTPL9QEaHv1+CNn2LK8vMow==", + "requires": { + "get-port": "^3.1.0" + } + }, + "then-request": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.0.tgz", + "integrity": "sha512-xA+7uEMc+jsQIoyySJ93Ad08Kuqnik7u6jLS5hR91Z3smAoCfL3M8/MqMlobAa9gzBfO9pA88A/AntfepkkMJQ==", + "requires": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^7.0.0", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "dependencies": { + "@types/node": { + "version": "8.10.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.26.tgz", + "integrity": "sha512-opk6bLLErLSwyVVJeSH5Ek7ZWOBSsN0JrvXTNVGLXLAXKB9xlTYajrplR44xVyMrmbut94H6uJ9jqzM/12jxkA==" + } + } + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "ws": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + } + } +} diff --git a/ADAM/package.json b/ADAM/package.json new file mode 100644 index 0000000..11eb464 --- /dev/null +++ b/ADAM/package.json @@ -0,0 +1,17 @@ +{ + "name": "nodejs-elasticbeanstalk", + "version": "1.0.0", + "description": "", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "node-cron": "^1.2.1" + } +} diff --git a/ADAM_Dairo/adam-dairo.js b/ADAM_Dairo/adam-dairo.js new file mode 100644 index 0000000..1fac4b2 --- /dev/null +++ b/ADAM_Dairo/adam-dairo.js @@ -0,0 +1,1145 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); + +// Bot Modules (stores http requests & random functions respectively) +const npcSettings = require('./npcSettings'); +const dialog = require('./dialog'); +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); + +const commandArray = ['!checkin', '!stats', '!inventory', '!upgrade', '!heal', '!quests'] + +// Creates an array that seperates 10 items into seperate arrays each +const itemDB = { + "iron_sword": { + "name": "Iron Sword", + "info": "This sturdy sword is great for slashing Ravagers.", + "type": { + "type": "Weapon", + "subtype": "Sword", + "stats": [ + { "attack": 2 } + ] + }, + "amount": 1 + }, + "steel_sword": { + "name": "Steel Sword", + "info": "A tougher form of the Iron Sword, it deals greater blows.", + "type": { + "type": "Weapon", + "subtype": "Sword", + "stats": [ + { "attack": 3 } + ] + }, + "amount": 1 + }, + "leather_armour": { + "name": "Leather Armour", + "info": "A light piece of armour made of leather.", + "type": { + "type": "Equipment", + "subtype": "Armour", + "stats": [ + {"defence": 3}, {"speed": 1} + ] + }, + "amount": 1 + }, + "leather_helm": { + "name": "Leather Helm", + "info": "A leather headpiece, designed for some protection and shade.", + "type": { + "type": "Equipment", + "subtype": "Helm", + "stats": [ + {"defence": 2}, {"speed": 1} + ] + }, + "amount": 1 + }, + "leather_boots": { + "name": "Leather Boots", + "info": "Comfy, leather boots made for long trips in New Eden's deserts.", + "type": { + "type": "Equipment", + "subtype": "Boots", + "stats": [ + {"defence": 1}, {"speed": 1} + ] + }, + "amount": 1 + }, + "iron_armour": { + "name": "Iron Armour", + "info": "Tough, iron armour. It feels solid.", + "type": { + "type": "Equipment", + "subtype": "Armour", + "stats": [ + {"defence": 4}, {"speed": -1} + ] + }, + "amount": 1 + }, + "health_potion": { + "name": "Health Potion", + "info": "A sweet-smelling potion that heals the drinker for 50 HP.", + "type": { + "type": "Potion", + "stats": [ + {"healing": 50} + ] + }, + "amount": 1 + } +} + +// For development testing +var userItems = []; + +addItem(undefined, itemDB["health_potion"], 10); +addItem(undefined, itemDB["iron_sword"], 1); +addItem(undefined, itemDB["leather_armour"], 1); +addItem(undefined, itemDB["leather_boots"], 1); +addItem(undefined, itemDB["leather_helm"], 1); +addItem(undefined, itemDB["steel_sword"], 1); + +// State Machine (Uncomment if needed) +/* +var BotEnumState = { + WAITING: 0, + ACTIVE: 1 +} +var botState = BotEnumState.ACTIVE; +*/ + +// 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) + if (client.user.username !== "Ghost 5.0.1") + client.user.setStatus('online'); + else + client.user.setStatus('invisible'); + + if (client.user.username == "Captain Montomery") { + const newName = "Captain Montgomery"; + console.log("Username is " + client.user.username + "! Typos are NOT(?) cannon, so better change stuff.\nAttempting rename to " + newName + "..."); + + // Set username + client.user.setUsername(newName) + .then(user => console.log(`Success! New username is now ${user.username}.`)) + .catch(console.error); + + // Changes nickname + //client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id).setNickname(""); + } + + // Sets your "Playing" + if (npcSettings.activity) { + client.user.setActivity(npcSettings.activity, { type: npcSettings.type }) + .then(presence => console.log(`Activity set to ${presence.game ? presence.game.name : 'none'}`)) + .catch(console.error); + } + + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + + // Message has to be in a bot channel + //if (!channelProcessor.isBotChannel(message.channel.id)) { + if (message.channel.id !== npcSettings.botChannel) { + // If it's the gate + if (message.channel.id === process.env.GATE_CHANNEL_ID && client.user.username === "A.D.A.M") { + const args = message.content.slice(prefix.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + // If they haven't done the right command to enter + if (!(command === "obsidian" || command === "hand" || command === "genesis")) { + console.log("User sent " + command + (command !== "obsidian")); + if (!(command !== "intro" || command !== "introgenesis" || command !== "introhand" || command !== "introobsidian" || command !== "introend")) { + message.reply("Please choose one of the factions by typing your desired faction shown above (!genesis, !obsidian, or !hand).") + .then(msg => { + msg.delete(10000) + }) + .catch(console.error); + } + } + message.delete(100); + } + } + if (message.channel.id === process.env.STASIS_CHANNEL_ID) return; + + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "ping": + if (isAdmin(message.author.id)) + message.reply("What is your command, almighty and glorious master!"); + break; + case "intro": + if (client.user.username == "A.D.A.M.") + sendMessage(message.channel.id, dialog.getDialog("intro", message.author.id)); + break; + case "introobsidian": + if (client.user.username == "Kamala, Obsidian Vice President") + sendMessage(message.channel.id, dialog.getDialog("introObsidian", message.author.id)); + break; + case "introgenesis": + // Typos officially cannon + if (client.user.username == "Captain Montgomery") + sendMessage(message.channel.id, dialog.getDialog("introGenesis", message.author.id)); + break; + case "introhand": + if (client.user.username == "Dairo, High Prophet of The Hand") + sendMessage(message.channel.id, dialog.getDialog("introHand", message.author.id)); + break; + case "introend": + if (client.user.username == "A.D.A.M.") + sendMessage(message.channel.id, dialog.getDialog("introEnd", message.author.id)); + break; + case "admingetroleids": + //for (var i in discordBot.servers[serverID].roles) { + // console.log(discordBot.servers[serverID].roles[i]); // issues + //} + console.log("!adminGetRoleIDs is Disabled for now"); + break; + case "obsidian": + if (client.user.username == "Kamala, Obsidian Vice President") + changeFaction(process.env.GROUP_A_ROLE, message.channel.id, message.author.id, + message.member, process.env.GROUP_A_BOT_ID); + break; + case "genesis": + if (client.user.username == "Captain Montgomery") + changeFaction(process.env.GROUP_B_ROLE, message.channel.id, message.author.id, + message.member, process.env.GROUP_B_BOT_ID); + break; + case "hand": + if (client.user.username == "Dairo, High Prophet of The Hand") + changeFaction(process.env.GROUP_C_ROLE, message.channel.id, message.author.id, + message.member, process.env.GROUP_C_BOT_ID); + break; + case "beginners": + if (!isAdmin()) break; + if (client.user.username == "A.D.A.M.") { + + var timedEvents = `Mori will revive all weakened travelers every day, and may heal you for a cost, if Mori can find the right things to do so.`; + + var commandsText = `These commands can be done in <#${process.env.GROUP_B_BOT_ID}>, <#${process.env.GROUP_C_BOT_ID}>, or <#${process.env.GROUP_A_BOT_ID}>.\n` + + `**!checkin** - For your help around the city, you can use this to be given a sum of **<:crystals:460974340247257089> Crystals** daily from your faction leader.\n` + + `**!stats** - Your faction leader can check your stats, and your total crystals, materials, etc., with this command.\n`; + + const embed = new Discord.RichEmbed() + .setAuthor( "SANCTUM Beginner's Guide", client.user.avatarURL) + .setColor("#f1c40f") + .setTitle("Welcome to SANCTUM!") + .setDescription("Welcome to SANCTUM, traveler. I hope you will understand the basics on how to survive after the Genesis ship's crash.") + .addField("Basic Commands", commandsText) + .addField("Mori", timedEvents) + + message.channel.send({embed}); + } + break; + case "questboard": + if (!isAdmin(message.author.id)) break; + if (client.user.username != "A.D.A.M.") break; + + var quests = { + "quests": [ + { + "title": "The Lost Pendant", + "id": "thelostpendant", + "description": "Lorem ipsum, or some placeholder text. I wish I knew what to put here, I'm no writer! I need to put more text here in order for the inlines to work more nicely. Not like it matters on mobile, however.", + "objective": "Go to <#${process.env.OUTSKIRTS_CHANNEL_ID}> and **!scavenge** in hopes to find the pendant.", + "userID": process.env.LIBRARIAN_ID, + "color": "keepersOfTheCityColor", + "recommendedLVL": 1, + "questLength": "Short", + "rewards": [ + { + "name": "Crystals", + "emote": "<:crystals:460974340247257089>", + "amount": 10 + }, + { + "name": "Electronics", + "emote": "<:melectronics:462682568911749120>", + "amount": 2 + }, + { + "name": "Gem", + "emote": "<:mgem:462450060718768148>", + "amount": 2 + } + ] + }, + { + "title": "Looming Ravager Outside", + "id": "loomingravager", + "description": "Hey, I have a problem, ya' see. There's a Ravager outside my tavern! And I've been waiting fo' it to go, but it ain't leaving!! I need your help to get rid of it, it's scaring me and my customers!", + "objective": "Go and help slay a Ravager.", + "userID": process.env.ALEXIS_ID, + "color": "keepersOfTheCityColor", + "recommendedLVL": 1, + "questLength": "Short", + "rewards": [ + { + "name": "Crystals", + "emote": "<:crystals:460974340247257089>", + "amount": 5 + } + ] + } + ] + } + + // Collects all preset colors + const keepersOfTheCityColor = message.guild.roles.find(role => role.name === "Keepers of the City").color; + console.log("COLOR: " + keepersOfTheCityColor); + + // Header & Footer (mobile design choice) for quests + const header = new Discord.RichEmbed() + .setAuthor("Quests", client.user.avatarURL) + .setColor(keepersOfTheCityColor) + .setTitle("The Travelers' Quest Board") + .setDescription("Residents of New Eden can post their help requests here, and whoever fulfils them can earn some rewards.") + .setFooter(`⏰ 7 hrs. before the quests are exchanged for new ones.`) + await message.channel.send({embed: header}); + + // Displays all quests in order + for (let i = 0; i < quests.quests.length; i++) { + const element = quests.quests[i]; + const bot = client.guilds.get(process.env.SANCTUM_ID).members.get(element.userID); + var newColor = element.color; + var newDescription = element.description; + var newObjective = element.objective; + var newReward = ""; + const questLength = `Quest Length: **${element.questLength}**.`; + + // Adds rewards up + element.rewards.forEach(reward => { + newReward += `> **${reward.emote} ${reward.name}** [${reward.amount}x]\n`; + }); + + // Returns internal color if needed + if (element.color === "keepersOfTheCityColor") newColor = keepersOfTheCityColor; + + // Replaces certain strings with internal channel data if needed + // NEED TO FIGURE OUT REGEX EXPRESSIONS FOR MASS REPLACE + newObjective = element.objective.replace("${process.env.OUTSKIRTS_CHANNEL_ID}", `${process.env.OUTSKIRTS_CHANNEL_ID}`); + + const body = new Discord.RichEmbed() + .setAuthor(`${bot.displayName}`, bot.user.avatarURL) + .setColor(newColor) + .setTitle(`📃 ${element.title}`) + .setDescription(newDescription) + .addField("Objective", newObjective) + .addField("Reward", newReward, true) + .addField("Info", `Recommended Level: **<:level:461650552506286093> ${element.recommendedLVL}+**.\n${questLength}`, true) + .setFooter(`React with ❗ to take on the quest, and help ${bot.displayName}.`) + + var bodyMessage = await message.channel.send({embed: body}); + await bodyMessage.react("❗"); + } + + // Specifically for mobile + await message.channel.send({embed: header}); + + break; + case "guild": + if (!isAdmin(message.author.id)) break; + if (client.user.username != "A.D.A.M.") break; + + switch (args[0]) { + case "create": + // Start message + var progressMessage = await message.channel.send(`${message.author} I will setup a safe place in the City, please wait.`); + + // Creates new channel & sets topic + var channelName = message.content.replace("!guild create ", '').trim(); + var newChannel = await message.guild.createChannel(channelName, 'text'); + await newChannel.setParent('496813609201172500'); + newChannel.setTopic(`This is the ${channelName} guild!`); + + // Chooses a role name + const roleName = channelName.replace(/\\/g, ""); + + // Creates role & adds it to author + var newRole = await message.guild.createRole({ + name: roleName, + color: 'DARK_AQUA', + }); + await message.member.addRole(newRole); + + // Sets permissions + await newChannel.overwritePermissions(message.guild.roles.find(role => role.name === '@everyone'), { + 'VIEW_CHANNEL': false + }); + await newChannel.overwritePermissions(message.guild.roles.find(role => role.name === roleName), { + 'VIEW_CHANNEL': true + }); + await newChannel.overwritePermissions(message.guild.roles.find(role => role.name === 'Can View All Guilds'), { + 'VIEW_CHANNEL': true + }); + + // Progress message + await progressMessage.edit(`${message.author} I have finished setting up your new ${newRole} guild, in the City. Put it into good use, traveler.`); + + break; + case "tag": + // Appends guild name to user (Grabs nickname by removing anything in []s) + // NOTE: CODE WORKS, JUST DOESN'T LOOK RIGHT + /* + const userNickname = message.member.displayName.replace(/\[(.*?)\]+/g, '').trim(); + message.member.setNickname(`[${roleName}] ${userNickname}`) + .catch((e) => { + console.log("ERROR HAPPENED I THINK") + console.log(e); + + // Catches >32 nickname + if (e.code == 50035) { + message.channel.send(`${message.author} I couldn't change your username in order to put your guild tag, as it would be too long.`) + } + }); + */ + break; + } + + break; + + } + + if (!checkValidDisplay(message.member, message.channel.id, true) && client.user.username != "A.D.A.M.") return; + + switch (command) { + case "checkin": + if (client.user.username == "A.D.A.M.") break; + var checkinAmount = calcRandom.random(4, 9); + var checkInResponse = String(dataRequest.sendServerData("checkin", checkinAmount, message.author.id)); + if (checkInResponse == "1") { + sendMessage(message.channel.id, dialog.getDialog("checkin", message.author.id, checkinAmount)); + addXP(message.author.id, 1); + } else { + sendMessage(message.channel.id, dialog.getDialog("checkinLocked", message.author.id, checkInResponse)); + } + break; + case "give": // Could revamp to make player ID and amount interchangable + if (client.user.username == "A.D.A.M.") break; + var giveAmount = Math.floor(args[0]); + if (message.mentions.members.size > 0) { + console.log(message.mentions.members); + var giveToID = message.mentions.members.first().id; + console.log("GIVE: " + giveToID + " | message.author.id: " + message.author.id) + if (giveToID === message.author.id) { + sendMessage(message.channel.id, dialog.getDialog("giveInvalidUserSelf", message.author.id)); + return; + } + var amountInAccount = dataRequest.loadServerData("account",message.author.id); + if (giveAmount > 0) { + if (amountInAccount >= giveAmount) { + if (dataRequest.sendServerData("transfer",giveToID,message.author.id,giveAmount) == 1) { + sendMessage(message.channel.id, dialog.getDialog("giveSuccessful", message.author.id, giveToID, giveAmount)); + } else { + sendMessage(message.channel.id, dialog.getDialog("giveFailed", message.author.id)); + } + } else { + sendMessage(message.channel.id, dialog.getDialog("giveNotEnoughInAccount", message.author.id)); + } + } else { + sendMessage(message.channel.id, dialog.getDialog("giveNotAboveZero", message.author.id)); + } + } else { + sendMessage(message.channel.id, dialog.getDialog("giveInvalidUser", message.author.id)); + } + break; + case "lore": + if (client.user.username == "A.D.A.M.") break; + sendMessage(message.channel.id, dialog.getDialog("lore", args[0])); + break; + case "stats": + if (client.user.username == "A.D.A.M.") break; + getLevelUp(message.author.id); + + var attacker = String(dataRequest.loadServerData("userStats",message.author.id)); + var scavengeResponse = String(dataRequest.loadServerData("artifactsGet",message.author.id)); + var attackerStrength = parseFloat(attacker.split(",")[0]); + var attackerSpeed = parseFloat(attacker.split(",")[1]); + var attackerStamina = parseFloat(attacker.split(",")[2]); + var attackerHealth = parseFloat(attacker.split(",")[3]); + var attackerMaxStamina = parseFloat(attacker.split(",")[4]); + var attackerMaxHealth = parseFloat(attacker.split(",")[5]); + var attackerWallet = parseFloat(attacker.split(",")[6]); + var attackerXP = parseFloat(attacker.split(",")[7]); + var attackerLVL = Math.floor(parseFloat(attacker.split(",")[8])); + var attackerLvlPercent = parseFloat(attacker.split(",")[9]); + var attackerStatPoints = parseFloat(attacker.split(",")[10]); + var attackerChests = parseFloat(attacker.split(",")[11]); + + var items = scavengeResponse.split(","); + var response = items[0]; + var ultrarare = parseFloat(items[1]); + var rare = parseFloat(items[2]); + var uncommon = parseFloat(items[3]); + var common = parseFloat(items [4]); + var scrap = parseFloat(items[5]); + var totalQuantity = ultrarare + rare + uncommon + common + scrap; + var userStats = ""; + + if (attackerLVL >= 30) { + userStats += "<@" + message.author.id + "> <:level:461650552506286093> **" + attackerLVL + "** (MAX)\t\t" + "<:cannister:462046687058198530> **" + attackerStatPoints + "**\t\t" + "<:cyphercrate:464135029036154950> **" + attackerChests + "** (" + attackerLvlPercent + "%)"; + } else { + userStats += "<@" + message.author.id + "> <:level:461650552506286093> **" + attackerLVL + "** (" + attackerLvlPercent + "%)\t\t\t" + "<:cannister:462046687058198530> **" + attackerStatPoints + "**\t\t\t<:cyphercrate:464135029036154950> **" + attackerChests + "**"; + } + userStats += "```STR: " + attackerStrength + " | SPD: " + attackerSpeed + " | STAM: " + attackerStamina + "/" + attackerMaxStamina + " | HP: " + attackerHealth + "/" + attackerMaxHealth + "```"; + userStats += "<:crystals:460974340247257089> **" + attackerWallet + "**\t\t"; + if (response == "success") { + if (totalQuantity > 0) { + //userStats += "\n"; + if (scrap > 0) { userStats += "<:scrap:463436564379336715> **" + scrap + "**\t\t"; } + if (common > 0) { userStats += "<:mcloth:462682568483930123> **" + common + "**\t\t"; } + if (uncommon > 0) { userStats += "<:mmetal:462682568920137728> **" + uncommon + "**\t\t"; } + if (rare > 0) { userStats += "<:melectronics:462682568911749120> **" + rare + "**\t\t"; } + if (ultrarare > 0) {userStats += "<:mgem:462450060718768148> **" + ultrarare + "**\n\n"; } + } else {console.log("failure2");} + } else {console.log("failure");} + + sendMessage(message.channel.id, userStats); + break; + case "estats": + // Sees if the user is supposed to level up + getLevelUp(message.author.id); + + // Grabs all parameters from server + var attacker = String(dataRequest.loadServerData("userStats",message.author.id)); + var scavengeResponse = String(dataRequest.loadServerData("artifactsGet",message.author.id)); + var attackerStrength = parseFloat(attacker.split(",")[0]); + var attackerSpeed = parseFloat(attacker.split(",")[1]); + var attackerStamina = parseFloat(attacker.split(",")[2]); + var attackerHealth = parseFloat(attacker.split(",")[3]); + var attackerMaxStamina = parseFloat(attacker.split(",")[4]); + var attackerMaxHealth = parseFloat(attacker.split(",")[5]); + var attackerWallet = parseFloat(attacker.split(",")[6]); + var attackerXP = parseFloat(attacker.split(",")[7]); + var attackerLVL = Math.floor(parseFloat(attacker.split(",")[8])); + var attackerLvlPercent = parseFloat(attacker.split(",")[9]); + var attackerStatPoints = parseFloat(attacker.split(",")[10]); + var attackerChests = parseFloat(attacker.split(",")[11]); + + var items = scavengeResponse.split(","); + var response = items[0]; + var ultrarare = parseFloat(items[1]); + var rare = parseFloat(items[2]); + var uncommon = parseFloat(items[3]); + var common = parseFloat(items [4]); + var scrap = parseFloat(items[5]); + var totalQuantity = ultrarare + rare + uncommon + common + scrap; + + // Forms stats into a string + var levelText = `<:level:461650552506286093> **${attackerLVL}**`; + var levelProgress = `(${attackerLvlPercent}%)`; + var crystalText = `<:crystals:460974340247257089> **${attackerWallet}**`; + var cannisterText = `<:cannister:462046687058198530> **${attackerStatPoints}**`; + var cypherCrateText = `<:cyphercrate:464135029036154950> **${attackerChests}**`; + var userStats = "```" + `STR: ${attackerStrength} | SPD: ${attackerSpeed} | STAM: ${attackerStamina}/${attackerMaxStamina} | HP: ${attackerHealth}/${attackerMaxHealth}` + "```"; + var materialsText = ``; + + // Materials + if (response == "success") { + if (totalQuantity > 0) { + if (scrap > 0) { materialsText += `<:scrap:463436564379336715> **${scrap}**`; } + if (common > 0) { materialsText += ` | <:mcloth:462682568483930123> **${common}**`; } + if (uncommon > 0) { materialsText += ` | <:mmetal:462682568920137728> **${uncommon}**`; } + if (rare > 0) { materialsText += ` | <:melectronics:462682568911749120> **${rare}**`; } + if (ultrarare > 0) { materialsText += ` | <:mgem:462450060718768148> **${ultrarare}**`; } + } else {console.log("failure2");} + } else {console.log("failure");} + + // Says level is maxed out if it is LVL 30+ + if (attackerLVL >= 30) { + levelProgress = `(MAX)`; + cypherCrateText += ` (${attackerLvlPercent}%)`; + } + + // Creates embed & sends it + const embed = new Discord.RichEmbed() + .setAuthor(`${message.member.displayName}`, message.author.avatarURL) + .setColor(message.member.displayColor) + .setDescription(`${levelText} ${levelProgress} | ${crystalText} | ${cannisterText} | ${cypherCrateText}`) + .addField("Stats", userStats) + .addField("Materials", `${materialsText}`) + .setFooter("Commands: !inventory | !checkin | !upgrade | !heal | !quests") + + message.channel.send(embed); + break; + case "inventory": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num)) { + return sendInventory(message, num); + } + } else { + return sendInventory(message); + } + break; + case "inv": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num)) { + return sendInventory(message, num); + } + } else { + return sendInventory(message); + } + break; + case "item": + return appraiseItem(message); + + case "help": + if (client.user.username == "A.D.A.M.") break; + if (!args[0]) { + sendMessage(message.channel.id, dialog.getDialog("help", message.author.id)); + } else if (message.mentions.members.first() !== undefined) { + // MORI + if (message.mentions.members.first().id == process.env.MORI_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpMori", message.author.id)); + } + // RAVAGER + if (message.mentions.members.first().id == process.env.RAVAGER_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpRavager", message.author.id)); + + } + // MOSIAH + if (message.mentions.members.first().id == process.env.MOSIAH_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpMosiah", message.author.id)); + + } + // GRAZE + if (message.mentions.members.first().id == process.env.GRAZE_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpGraze", message.author.id)); + + } + // SONYA + /* + if (message.mentions.members.first().id == process.env.SONYA_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpSonya", message.author.id)); + } + */ + // REY + if (message.mentions.members.first().id == process.env.REY_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpRey", message.author.id)); + } + // ALEXIS + if (message.mentions.members.first().id == process.env.ALEXIS_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpAlexis", message.author.id)); + } + //sendMessage(message.channel.id, ":frowning:" + message.mentions.members.first().id); + } + break; + } + +}); + +client.on('error', console.error); + +// Gets footer commands for botspam channel commands +function getFooterCommands(currentCommand) { + var textFooter = ""; + const filtered = commandArray.filter(word => word !== currentCommand); + //console.log(filtered); + + filtered.forEach(element => { + var appendedText = " | "; + if (textFooter.length !== 0) textFooter += appendedText; + textFooter += element; + }); + //console.log(textFooter); + return textFooter; +} + +// Adds item to inventory +function addItem(userID, item, amount) { + // If item exists in inventory + console.log("[Add Item] " + amount); + var i = userItems.findIndex(i => i.name === item.name); + console.log("[Item Amount Item Exists] i Equals " + i); + + // If there is an item that exists in inventory + if (i !== -1) { + console.log("[Item Amount Start] " + userItems[i].amount); + userItems[i].amount += amount; // Increments amount value + console.log("[Item Amount Finish] " + userItems[i].amount); + // Disallows adding objects such as crystals + } else { + console.log("[Item Amount Wait] Created item for the first time."); + var clonedItem = JSON.parse(JSON.stringify(item)); // Clones item in order to not actually increment the rooms.js item JSON data + userItems.push(clonedItem); + addItem(userID, item, amount - 1); + } +} + +// Sends inventory into chat +async function sendInventory(message, pageNum, newMessage) { + var items = ""; + var groupedArr = createGroupedArray(userItems, 5); + + // Sets a default page num, or makes it human readable + if (pageNum === undefined) pageNum = 1; else { + if (pageNum < 1) pageNum = 1; + if (groupedArr.length < pageNum) pageNum = groupedArr.length; + } + + // Checks if page number is valid + if (pageNum > groupedArr.length) { + // If it's longer than actual length, but isn't just an empty inventory + if (!groupedArr.length === 0) return; + } + + //console.log(pageNum); + + // Grabs item in loop, parses it, then adds it to "items" variable + if (groupedArr[pageNum - 1]) { + for (let index = 0; index < groupedArr[pageNum - 1].length; index++) { + // Grabs an item, from a page index + const element = groupedArr[pageNum - 1][index]; + + // Makes if there is an emote, it'll add an extra space + var emoteText = ""; + if (element.emote) emoteText = element.emote + " "; + + // Adds it in + items += `> ${emoteText}**${element.name}** [${element.amount}x] ${element.info}\n`; + } + } + + // No items message to fill field + if (items === "") items = "There are no items in the party's inventory."; + + // To make the message of "Page 1/0" with no items in !inventory not happen + var moddedLength = groupedArr.length; + if (moddedLength < 1) moddedLength = 1; + + const footer = getFooterCommands("!inventory"); + + // Creates embed & sends it + const inv = new Discord.RichEmbed() + .setAuthor(`${message.member.displayName}`, message.author.avatarURL) + .setColor(message.member.displayColor) + .setDescription("I can appraise your items with `!item [ITEM NAME]`, traveler.") + .addField(`Items (Page ${pageNum}/${moddedLength})`, items) + .setFooter(`Commands: ${footer}`) + + var invMessage; + if (!newMessage) + invMessage = await message.channel.send({embed: inv}); + else { + invMessage = newMessage; + await invMessage.edit({embed: inv}); + } + + // Collector for emotes + const emotes = ['⬅', '❌', '➡']; + const collector = invMessage.createReactionCollector( + (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id , { time: 15 * 1000 }); + var react = ""; + var endedOnReact; + + // Sends reactions + if (!newMessage) { + for (let i = 0; i < emotes.length; i++) { + const element = emotes[i]; + console.log(element); + await invMessage.react(element); + } + } + + // Collects reactions + collector.on("collect", async reaction => { + var user = reaction.users.last(); + react = reaction.emoji.name; + if (react !== '❌') { reaction.remove(user); } + endedOnReact = true; + collector.stop(); + }); + + // Clears reactions + collector.once("end", async collecter => { + console.log("[Reaction Options] Ended collector, clearing emotes and sending timing out message if needed."); + + if (!endedOnReact) { + invMessage.clearReactions(); + return message.channel.send(":x: **Timed Out**: The emote reaction request timed out after 15 seconds."); + } + if (react === '❌') { + invMessage.clearReactions(); + return invMessage.edit(invMessage.content); + } + + var pageNumModifier = 0; + if (react === emotes[0]) pageNumModifier -= 1; + if (react === emotes[2]) pageNumModifier += 1; + console.log(pageNum + " | " + pageNumModifier); + sendInventory(message, pageNum + pageNumModifier, invMessage); + }); +} + +// Appraise an item +async function appraiseItem(message) { + const itemName = message.content.replace("!item", "").trim().toLowerCase(); + console.log("[Item Appraisal] " + `<< ${itemName} >>`); + + // Show if no parameter is given + if (itemName === "" || !itemName) { + message.channel.send(`:x: ${message.author} Please tell me the item name from your inventory, or I won't know which item you want me to look at.`); + return; + } + + var i = userItems.findIndex(i => i.name.toLowerCase() === itemName); + console.log("[Item Amount Item Exists] i Equals " + i); + + // If there is an item that exists in inventory + if (i !== -1) { + console.log(`[Item Appraisal] Found item in inventory!`); + const embed = new Discord.RichEmbed() + .setAuthor(`${message.member.displayName}`, message.author.avatarURL) + .setColor(message.member.displayColor) + .setTitle(userItems[i].name) + .setDescription(userItems[i].info) + + if (userItems[i].type.subtype) + embed.addField("Type", `${userItems[i].type.type}\n> ${userItems[i].type.subtype}`, true) + else + embed.addField("Type", `${userItems[i].type.type}`, true) + + if (userItems[i].type.stats) { + console.log(JSON.stringify(userItems[i].type.stats, null, 4)) + var itemStats = "There are no stats avaliable."; + var resetItemStats = false; + userItems[i].type.stats.forEach(element => { + if (element) { + if (!resetItemStats) { + resetItemStats = true; + itemStats = ""; + } + const types = [ + "attack", + "defence", + "speed", + "healing" + ]; + + types.forEach(type => { + if (element[type]) { + switch (type) { + case "attack": + itemStats += `ATK: ${element.attack}\n`; + break; + case "defence": + itemStats += `DEF: ${element.defence}\n`; + break; + case "speed": + itemStats += `SPD: ${element.speed}\n`; + break; + case "healing": + itemStats += `Healing: ${element.healing} HP\n`; + break; + } + } + }); + } + }); + } + + embed.addField("Stats", `${itemStats}`, true); + + message.channel.send(embed); + + // Disallows adding objects such as crystals + } else { + console.log("[Item Appraisal] Couldn't find item in inventory."); + message.channel.send(`:x: ${message.author} I'm unable to find "${itemName}" in your inventory.`); + } +} + +// Creates an array that creates multiple different arrays inside of that array -> [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +// http://www.frontcoded.com/splitting-javascript-array-into-chunks.html +var createGroupedArray = function(arr, chunkSize) { + var groups = [], i; + for (i = 0; i < arr.length; i += chunkSize) { + groups.push(arr.slice(i, i + chunkSize)); + } + return groups; +} + +// See if the bot should display its message +function checkValidDisplay(member, channelID, checkRole) { + if (client.user.username == "Kamala, Obsidian Vice President" && channelID === process.env.GROUP_A_BOT_ID) { + if (checkRole) { if (member.roles.has(process.env.GROUP_A_ROLE)) return true; } else true; + } + else if (client.user.username == "Captain Montgomery" && channelID === process.env.GROUP_B_BOT_ID) { + if (checkRole) { if (member.roles.has(process.env.GROUP_B_ROLE)) return true; } else true; + } + else if (client.user.username == "Dairo, High Prophet of The Hand" && channelID === process.env.GROUP_C_BOT_ID) { + if (checkRole) { if (member.roles.has(process.env.GROUP_C_ROLE)) return true; } else true; + } + else if (client.user.username == "Ghost 5.0.1") { + // JSON + const rooms = require('../TextAdv/rooms.json'); + var roomExists = false; + + // Loops for all rooms + rooms.rooms.forEach(element => { + if (channelID === rooms[element].channel) roomExists = true; + }); + + if (!roomExists) { + if (channelID === process.env.TEST_CHANNEL_ID) return true; + } else return true; + + } + + return false; +} + +// Gets if user has an Overseers rank +function isAdmin(userID) { + var guild = client.guilds.get(process.env.SANCTUM_ID); + return guild.members.get(userID).roles.find(role => role.name === "Overseers"); +} + +// Change Faction +async function changeFaction(factionID, channelID, userID, member, botChannelID) { + if (member.roles.has(factionID)) { + if (factionID === process.env.GROUP_A_ROLE) + sendMessage(channelID, dialog.getDialog("orderAlreadyJoined", userID)); + else if (factionID === process.env.GROUP_B_ROLE) + sendMessage(channelID, dialog.getDialog("anarchyAlreadyJoined", userID)); + else if (factionID === process.env.GROUP_C_ROLE) + sendMessage(channelID, dialog.getDialog("religionAlreadyJoined", userID)); + } else { + if (dataRequest.loadServerData("hasConvertedToday", userID) == 1) { + sendMessage(channelID, dialog.getDialog("alreadyConvertedToday", userID)); + } else { + // Creates new user + var response = String(dataRequest.sendServerData("newUser", "New user.", userID)); + + //var response = "createdUser" + // Obsidian Tech. + if (factionID === process.env.GROUP_A_ROLE) { + await member.removeRole(process.env.GROUP_B_ROLE); + await member.removeRole(process.env.GROUP_C_ROLE); + await member.addRole(process.env.GROUP_A_ROLE); + + dataRequest.sendServerData("conversion", "Converted to The Order.", userID); + + if (response == "createdUser") { + client.users.get(userID).send(dialog.getDialog("newUserPM", userID, getFactionName(factionID))); + sendMessage(botChannelID, dialog.getDialog("newUserWelcome", userID, `<#${getFactionName(factionID)}>`)); + } else { + sendMessage(channelID, dialog.getDialog("orderJoin", userID)); + } + + // Genesis Command + } else if (factionID === process.env.GROUP_B_ROLE) { + await member.removeRole(process.env.GROUP_C_ROLE); + await member.removeRole(process.env.GROUP_A_ROLE); + await member.addRole(process.env.GROUP_B_ROLE); + + dataRequest.sendServerData("conversion", "Converted to the Anarchy.", userID); + + if (response == "createdUser") { + client.users.get(userID).send(dialog.getDialog("newUserPM", userID, getFactionName(factionID))); + sendMessage(botChannelID, dialog.getDialog("newUserWelcome", userID, `<#${getFactionName(factionID)}>`)); + } else { + sendMessage(channelID, dialog.getDialog("anarchyJoin", userID)); + } + + // The Hand + } else if (factionID === process.env.GROUP_C_ROLE) { + await member.removeRole(process.env.GROUP_A_ROLE); + await member.removeRole(process.env.GROUP_B_ROLE); + await member.addRole(process.env.GROUP_C_ROLE); + + dataRequest.sendServerData("conversion", "Converted to The Religion.", userID); + + if (response == "createdUser") { + client.users.get(userID).send(dialog.getDialog("newUserPM", userID, getFactionName(factionID))); + sendMessage(botChannelID, dialog.getDialog("newUserWelcome", userID, `<#${getFactionName(factionID)}>`)); + } else { + sendMessage(channelID, dialog.getDialog("religionJoin", userID)); + } + } + } + } +} + +function addXP(userID,amount) { + var response = String(dataRequest.sendServerData("addXP", amount, userID)); +} + +function getLevelUp(userID) { + const server = client.guilds.get(process.env.SANCTUM_ID); + const member = server.members.get(userID); + if (client.user.username == "Kamala, Obsidian Vice President" && !member.roles.has(process.env.GROUP_A_ROLE)) return; + if (client.user.username == "Captain Montgomery" && !member.roles.has(process.env.GROUP_B_ROLE)) return; + if (client.user.username == "Dairo, High Prophet of The Hand" && !member.roles.has(process.env.GROUP_C_ROLE)) return; + + //const user = server.members.get(userID); + var response = String(dataRequest.sendServerData("getLevelUp", 0, userID)); + var responseMessage = String(response.split(",")[0]); + var lvl = Math.floor(parseFloat(response.split(",")[1])); + var statPoints = parseFloat(response.split(",")[2]); + + var attacker = String(dataRequest.loadServerData("userStats", userID)); + var chests = parseFloat(attacker.split(",")[11]); + + console.log(response.split(",")); + + majorLevelUp(lvl, server, userID); + + if (responseMessage == "levelup") { + //if (true) { + console.log("Chests: " + chests) + checkinLevelUp(userID, lvl, statPoints, chests); + } +} + +async function majorLevelUp(level, server, userID) { + const user = server.members.get(userID); + + var newChannel = ""; + + var levels = [ + // Role, Level + [server.roles.find(role => role.name === "LVL 1+"), 1, process.env.CRYSTAL_SHORES_CHANNEL_ID], + [server.roles.find(role => role.name === "LVL 15+"), 15, process.env.SEA_OF_FOG_CHANNEL_ID], + [server.roles.find(role => role.name === "LVL 30+"), 30, process.env.DEADLANDS_CHANNEL_ID] + ] + + // Shrinking level + if (level < 30) { + level = 15; + } else if (level < 15) { + level = 1; + } + + // Rank Level Up + var levelRole = server.roles.find(role => role.name === `LVL ${level}+`); + if (levelRole) { + var memberRole = user.roles.has(levelRole.id); + if (!memberRole) { + user.addRole(levelRole).catch(console.error); + for (let i = 0; i < levels.length; i++) { + const element = levels[i]; + if (element[1] !== level) { + await user.removeRole(element[0]); + } + } + if (user !== undefined) {// && newChannel !== undefined) { + var levelMarks = [1, 15, 30]; + + for (let i = 0; i < levelMarks.length; i++) { + const element = levelMarks[i]; + // Gets channel of array + newChannel = client.channels.get(levels[levels.findIndex(level => level[1] === element)][2]); + if (level === element) + newChannel.send(dialog.getDialog("level" + level, user, newChannel)); + } + } + } + } +} + +// Gets the user's role by member +function getFactionChannel(member) { + var playerChannel; + var isGroupA = member.roles.has(process.env.GROUP_A_ROLE); + var isGroupB = member.roles.has(process.env.GROUP_B_ROLE); + var isGroupC = member.roles.has(process.env.GROUP_C_ROLE); + //console.log(member.roles); + //console.log("isGroup: " + isGroupA + " " + isGroupB + " " + isGroupC); + if (isGroupA) playerChannel = process.env.GROUP_A_BOT_ID; + else if (isGroupB) playerChannel = process.env.GROUP_B_BOT_ID; + else if (isGroupC) playerChannel = process.env.GROUP_C_BOT_ID; + + return playerChannel; +} + +// Gets faction names by ID +function getFactionName(factionID) { + if (factionID === process.env.GROUP_A_ROLE) { + return "Obsidian Technologies"; + } + if (factionID === process.env.GROUP_B_ROLE) { + return "Genesis Command"; + } + if (factionID === process.env.GROUP_C_ROLE) { + return "The Hand"; + } +} + +function checkinLevelUp(userID, lvl, statPoints, chests) { + const guild = client.guilds.get(process.env.SANCTUM_ID); + if (lvl === 30) { + //Post level cap level up! + sendMessage(userID, getFactionChannel(guild.members.get(userID)), dialog.getDialog("levelUpLevelCap", userID, lvl, chests)); + } else { + //regular level up + sendMessage(userID, getFactionChannel(guild.members.get(userID)), dialog.getDialog("levelUp", userID, lvl, statPoints)); + } + //sendMessage(testChannelID, dialog.getDialog("levelUp", userID, lvl, statPoints)); +} + +// Updates stamina (1) and health by 1% every 2 min. +cron.schedule('*/2 * * * *', function() { + if (client.user.username === "A.D.A.M.") { + console.log('Updating STAMINA every 2 min.'); + dataRequest.sendServerData("updateStamina", 0); + }; +}); + +// Send message handler +function sendMessage(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message === undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message; + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); +} + +// Log our bot in +client.login(npcSettings.token); \ No newline at end of file diff --git a/ADAM_Dairo/dialog.js b/ADAM_Dairo/dialog.js new file mode 100644 index 0000000..79cbba5 --- /dev/null +++ b/ADAM_Dairo/dialog.js @@ -0,0 +1,298 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + getDialog: function(dialogTag, data = "", data2 = "", data3 = "") { + switch(dialogTag) { + case "checkin": + return "<@" + data + ">" + " your presence has been noted. I've added " + data2 + " crystals to your account."; + + case "checkinLocked": + return ":x: <@" + data + ">" + " you already checked in with me " + data2 + ". You can check in again tomorrow."; + + case "alreadyConvertedToday": + return ":x: <@" + data + ">" + " as anxious as you may be, please don't attempt to change factions so quickly. You can only change once every 30 days."; + + case "depositSuccessful": + //codexLogEvent(data + " deposited " + data2 + " crystals."); + return "<@" + data + ">" + " your deposit of " + data2 + " crystals has been successful. Good luck."; + + case "depositFailed": + return ":x: <@" + data + ">" + " I can't make the deposit at the moment. I apologize for the inconvenience."; + + case "giveSuccessful": + //codexLogEvent(data + " gave " + data2 + " " + data3 + " crystals."); + return "<@" + data + ">" + " I've transferred " + data3 + " crystals to <@" + data2 + "> as per your request."; + + case "giveFailed": + return ":x: <@" + data + ">" + " I can't make that transfer at the moment. I apologize for the inconvenience."; + + case "giveNotEnoughInAccount": + return ":x: <@" + data + ">" + " You don't have that many crystals in your account. As such, I can't complete the transfer."; + + case "giveNotAboveZero": + return ":x: <@" + data + ">" + " In order for me to complete the transfer I need an amount above zero."; + + case "giveInvalidUser": + return ":x: <@" + data + ">" + " I can't find that traveler. Sorry."; + + case "giveInvalidUserSelf": + return ":x: <@" + data + ">" + " You can\'t send crystals to yourself. Sorry."; + + case "levelUp": + var dialogOptions = [ + 'I appreciate all of your help.', + 'Thank you for doing so much for the city.', + 'The other travelers are very grateful for your help.', + 'Your assistance is very much appreciated.', + 'Together we\'ve taken out most of the threats to city.', + 'The citizens of The Sanctum are most grateful.', + 'I cannot thank you enough for your help defending the city.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + var wordToUse = "it"; + if (data3 > 1) { var wordToUse = "them";} + return "You just hit **level " + data2 + "**! " + dialogOptions[randomNumber] + " I\'ve added a <:cannister:462046687058198530> **Nanotech Cannister** to your inventory so that you can upgrade your skills. You now have **" + data3 + "** total (you can check this any time with !stats). Use " + wordToUse + " wisely."; + + case "levelUpLevelCap": + var dialogOptions = [ + 'I appreciate all of your help.', + 'Thank you for doing so much for the city.', + 'The other travelers are very grateful for your help.', + 'Your assistance is very much appreciated.', + 'Together, we\'ve taken out most of the threats to city.', + 'The citizens of The Sanctum are most grateful.', + 'I cannot thank you enough for your help defending the city.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + return "You\'re currently at **level " + data2 + "** which is the current level cap! " + dialogOptions[randomNumber] + " I\'ve added a <:cyphercrate:464135029036154950> **Cypher Crate** to your inventory. Hopefully it contains something useful for you on your journey. You now have **" + data3 + "** total (you can check this any time with !stats). Good luck. "; + + case "help": + var temp = "*This world is strange and mysterious. And while I cannot help you on your journey or join your faction, I am here to help travelers to the best of my ability.* \n\nHere is what I can do for you:"; + temp += "\n\n"; + temp += "!checkin\n```Once per day, you may come see me for a daily sum in exchange for your help around the city.```"; + temp += "\n"; + temp += "!stats\n```I can share all of your stats and your crystal count information.```"; + temp += "\n"; + temp += "!give [AMOUNT] [@USER]\n```I can transfer some of your crystals to another traveler's account. Just make sure you have enough.```"; + temp += "\n"; + temp += "!help [@NAME]\n```I can tell you a little bit about some of the other people with us here on New Eden.```"; + temp += "\n"; + temp += "I hope this helps you on your journey, traveler."; + return temp; + + case "helpMori": + var temp = "*Mori is our resident head of the medbay. He can tend to your wounds and get you back on your feet. Here's what he can do:*"; + temp += "\n\n"; + temp += "!heal\n```Shows you Mori\'s available procedures for healing.```"; + temp += "\n"; + temp += "!heal [ITEM]\n```Purchases a procedure directly from him, and with his nanotech, takes effect immediately.```"; + return temp; + + case "helpGraze": + var temp = "*Graze is our loveable augmentation expert. He can help you upgrade your skills and boost your abilities. Here's what he can do:*"; + temp += "\n\n"; + temp += "!upgrade\n```Shows you the available upgrades that Graze can provide with your Nanotech Cannisters.```"; + temp += "\n"; + temp += "!upgrade [STAT]\n```Upgrades this specific stat permanently.```"; + return temp; + + case "helpMosiah": + var temp = `*Mosiah was exiled from our great city for many counts of misconduct, but it\'s been said he\'s been seen at <#${process.env.TAVERN_CHANNEL_ID}>. I recommend you not deal with him at all, but should you need to, here\'s what he can do:*`; + temp += "\n\n"; + temp += "!wager [AMOUNT]\n```Wagers your crystals in a primative coin flip bet. Winner takes all.```"; + return temp; + + case "helpRavager": + var temp = `*The Ravagers have been hunting us since crashing here on New Eden. They roam this planet and will attack travelers on sight. But you can defend yourself:*`; + temp += "\n\n"; + temp += "!attack\n```Sends your weapon towards an active Ravager. If you win the fight, you can loot their corpse for crystals. But be careful: they bite back.```"; + temp += "\n"; + temp += "!details\n```Shows you the details of the last Ravager fight to take place as well as the crystal distribution.```"; + return temp; + + case "helpSonya": + var temp = "*Professor Sonya is our resident archeologist, and she is fascinated by this world. Scavenge for some artifacts in the outskirts of the city, and she will apy you handsomely.*"; + temp += "\n\n"; + temp += "!scavenge\n```In #🌘the-outskirts, this allows you to look for rare artifacts for the professor.```"; + temp += "\n"; + temp += "!artifacts\n```Shows you the current artifacts that you have in your inventory.```"; + temp += "\n"; + temp += "!artifacts sell\n```Shows you the current prices that the professor is willing to pay for any artifacts that you may find.```"; + temp += "\n"; + temp += "!artifacts sell [TYPE]\n```Sells all of the artifacts that you have of that type to the professor, at current prices.```"; + return temp; + + case "helpRey": + var temp = "*Rey is a master of finding things that we need around the city. Resources are scarce, so anything you can help her find in <#462382076927148054> would be most helpful.*"; + temp += "\n\n"; + temp += "!scavenge\n```In #🌘the-outskirts, this allows you to look for materials and resources with Rey.```"; + temp += "\n"; + temp += "!materials\n```Shows you the current materials that you have in your inventory.```"; + return temp; + + case "helpAlexis": + var temp = "*Alexis is our top-of-the-line chemist who uses her talents to reward travelers with a nice and relaxing space. She\'d be happy to have or provide you with some company.*"; + temp += "\n\n"; + temp += "!buydrink\n```In #🍺travelers-watch, this allows you to buy a drink and relax.```"; + temp += "\n"; + temp += "!buydrink [@NAME]\n```In #🍺travelers-watch, you can buy a drink for a friend.```"; + temp += "\n"; + temp += "!tip [AMOUNT]\n```In #🍺travelers-watch, you can tip her for her great service. She might just give you a tip back.```"; + return temp; + + //Status commands + case "accountCheck": + return "<@" + data + ">" + " you currently have " + data2 + " crystals in your account."; + + case "bankCheck": + return "Currently, " + data + " has " + data2 + " crystals total in their bank."; + + case "victors": + return "Currently, " + data + " controls the fate of the codex."; + + case "noVictors": + return "The fate of the codex is still undetermined."; + + // Obsidian Technologies (Former Order) + case "orderAlreadyJoined": + return ":x: <@" + data + ">" + " The Obsidian Technologies already has your allegiance. There's no need to request a change."; + case "orderJoin": + //codexLogEvent(data + " joined Genesis Command."); + return "<@" + data + ">" + " you have joined the Obsidian Technologies. May peace reign upon your cause."; + + // Genesis Command (Former Anarchy) + case "anarchyAlreadyJoined": + return ":x: <@" + data + ">" + " The Genesis Command has already begun their chaos with you by their side. There's no need to request a change."; + case "anarchyJoin": + //codexLogEvent(data + " joined Obsidian Technologies."); + return "<@" + data + ">" + " you have joined the Genesis Command. May chaos come to those who oppose you."; + + // The Hand (Former Religion) + case "religionAlreadyJoined": + return ":x: <@" + data + ">" + " The Hand is happy to have you in their congregation already. There's no need to request a change."; + case "religionJoin": + //codexLogEvent(data + " joined The Hand."); + return "<@" + data + ">" + " you have joined The Hand. May the gods look favorably upon you."; + + //Onboarding + case "newUserWelcome": + messageToSend = "<@" + data + ">" + " welcome to " + data2 + ". If you need me for anything, you can contact me via this secure channel. Just use **!help** for a list of things I can do for you."; + messageToSend += "\n\nAnd don\'t forget to say hello to fellow travelers in "; + if (data2 == "Genesis Command") { + messageToSend += `${process.env.GROUP_B_BOT_ID}.`; + } + if (data2 == "Obsidian Technologies") { + messageToSend += `${process.env.GROUP_A_BOT_ID}.`; + } + if (data2 == "The Hand") { + messageToSend += `${process.env.GROUP_C_BOT_ID}.`; + } + return messageToSend; + case "newUserPM": + var messageToSend = ''; + messageToSend = "_Traveler, welcome to The Sanctum."; + messageToSend += "\n\n"; + + if (data2 == "Genesis Command") { + messageToSend += "I see that you've joined **Genesis Command**. The least reckless of the 3 factions, I can see why you'd pick them. You clearly understand that The Codex is a very powerful book, and should you be victorious, no one will have access to it\'s secrets. "; + } + if (data2 == "Obsidian Technologies") { + messageToSend += "I see that you've joined **Obsidian Technologies**. While they are the most chaotic of the 3 factions, I can see why you'd pick them. The Codex is a very powerful book, and should you be victorious, everyone will have equal access to it\'s secrets. "; + } + if (data2 == "The Hand") { + messageToSend += "I see that you've joined **The Hand**. While they are certainly the most suspicious of the 3 factions, I can see why you'd pick them. The Codex is a very powerful book, and should you be victorious, it is your job to guide the rest of the city using it\'s secrets."; + } + messageToSend += "\n\n"; + messageToSend += "I'll get you patched up and give you access to our team to upgrade skills and meet the others. There's just a few things I need you to take care of around the city:_"; + messageToSend += "\n\n"; + messageToSend += "**!checkin** with me daily.\n```Once a day I'll give you your daily allotment of crystals in exchange for some help around the city.```"; + messageToSend += "\n"; + messageToSend += "**!attack** any Ravagers in #the-deadlands.\n```With the constant bombardment from the enemies of the city, It\'s hard to keep us safe. I need your help```"; + messageToSend += "\n"; + messageToSend += "_Good luck. I'll be around if you need me._"; + return messageToSend; + //Lore + case "intro": + var tempLore = ''; + tempLore = "_Hello weary traveler."; + tempLore += "\n\n"; + tempLore += "My name is A.D.A.M. and I would like to offer you the amenities of The Sanctum. However, I cannot come to your aid until you choose a faction. I am dearly sorry to be so blunt and put trivial human rules in place over your sustenance and safety, but this is the only way to protect The Codex. But the Codex no longer exists since the Librarian destroyed it, so make something up, player."; + tempLore += " Your choices are as follows:_"; + return tempLore; + case "introHand": + var tempLore = "<:religionhand:461582719051104276> **<@&" + process.env.GROUP_C_ROLE + ">** - !hand\n```Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eu aliquet mauris, id congue nisi. Integer et lobortis tellus. Sed bibendum a metus quis volutpat. Mauris faucibus quam at euismod scelerisque. Vestibulum a elit auctor, venenatis augue in, rhoncus nisi. Mauris sagittis sit amet ante eget luctus. Maecenas id malesuada elit. Vestibulum nec ante nec justo venenatis tincidunt.```"; + return tempLore; + case "introGenesis": + var tempLore = "<:order:460991638152413194> **<@&" + process.env.GROUP_B_ROLE + ">** - !genesis\n```Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eu aliquet mauris, id congue nisi. Integer et lobortis tellus. Sed bibendum a metus quis volutpat. Mauris faucibus quam at euismod scelerisque. Vestibulum a elit auctor, venenatis augue in, rhoncus nisi. Mauris sagittis sit amet ante eget luctus. Maecenas id malesuada elit. Vestibulum nec ante nec justo venenatis tincidunt. ```"; + return tempLore; + case "introObsidian": + var tempLore = "<:anarchy:460990297099337750> **<@&" + process.env.GROUP_A_ROLE + ">** - !obsidian\n```Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eu aliquet mauris, id congue nisi. Integer et lobortis tellus. Sed bibendum a metus quis volutpat. Mauris faucibus quam at euismod scelerisque. Vestibulum a elit auctor, venenatis augue in, rhoncus nisi. Mauris sagittis sit amet ante eget luctus. Maecenas id malesuada elit. Vestibulum nec ante nec justo venenatis tincidunt.```"; + return tempLore; + case "introEnd": + var tempLore = "_Choose wisely._"; + return tempLore; + case "level1": + var tempLore = ''; + tempLore += `Congratulations ${data}, you have reached **${data2}**! Travelers defend the city from Ravagers here, and you can earn some crystals.` + return tempLore; + case "level15": + var tempLore = ''; + tempLore += `Congratulations ${data}, you have reached **${data2}**, where there are more dangerous enemies, lurking in the fog.` + return tempLore; + case "level30": + var tempLore = ''; + tempLore += `Congratulations ${data}, you have reached **${data2}**, the area most teeming with the strongest Ravagers. Watch your back, and good luck!` + return tempLore; + case "lore": + var tempLore = ''; + switch(data) { + case "backstory": + tempLore = "‘_Mother Earth had failed us. "; + tempLore += "\n\n"; + tempLore += "In her dying breath, she bore a starship, **The Genesis**, to save the last of humankind. But the **travelers** aboard were not prepared for the unwelcoming winds of barren space."; + tempLore += "\n\n"; + tempLore += "On the brink of extinction our forefathers landed here, but this was no earth. The desolate landscape of **The Deadlands** traded our starvation for thirst, our isolation for open and empty space. But despite our struggles, we could breathe again."; + tempLore += "\n\n"; + tempLore += "We walked for many days and many nights in **The Deadlands**, consuming only the native **crystals** climbing from the ground for sustenance. Leaving the shelter of our vessel behind for the hope of a new home. Many withered away under the scorching heat of the twin suns and the constant attacks from **Ravagers**, but Mother Earth kept her promise."; + tempLore += "\n\n"; + tempLore += "In our darkest hour, we laid eyes on **The Sanctum**, a city of the gods. Complete with a vault full of our edible crystals, and more than enough room for the entire population; A city with human amenities in the middle of an inhuman world, bestowed upon a dying nation in need. This place was truly a divine gift."; + tempLore += "\n\n"; + tempLore += "At the highest point of the city in the tower that touched the clouds, we found **The Librarian**. A meticulous mechanical record keeper hovering over his book, the great **Codex Arcana**. This was a book written in detail to record the actions of every man, woman, and child that lived among us. But it was far too powerful, and the secrets it contained proved lethal in the wrong hands."; + tempLore += "\n\n"; + tempLore += "And so began the **factions**, vying for control over the Codex._'"; + tempLore += "\n\n"; + tempLore += "- Excerpt from the **Teachings of Tiberius**. March 22, 2630."; + break; + case "genesis": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "travelers": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "deadlands": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "ravager": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "Sanctum": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "librarian": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "codex": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "factions": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + default: + tempLore = "Here is the lore that is available in my database. ```!lore backstory```" + break + } + console.log("TEMPLORE: " + tempLore); + return tempLore; + } + } +} diff --git a/ADAM_Dairo/npcSettings.js b/ADAM_Dairo/npcSettings.js new file mode 100644 index 0000000..4c5fc8d --- /dev/null +++ b/ADAM_Dairo/npcSettings.js @@ -0,0 +1,8 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + activity: "for !hand recruits.", + type: "WATCHING", + token: process.env.DAIRO_HAND_TOKEN, + botChannel: process.env.GROUP_C_BOT_ID +} diff --git a/ADAM_Dairo/package-lock.json b/ADAM_Dairo/package-lock.json new file mode 100644 index 0000000..16601ab --- /dev/null +++ b/ADAM_Dairo/package-lock.json @@ -0,0 +1,69 @@ +{ + "name": "nodejs-elasticbeanstalk", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + } + } +} diff --git a/ADAM_Dairo/package.json b/ADAM_Dairo/package.json new file mode 100644 index 0000000..11eb464 --- /dev/null +++ b/ADAM_Dairo/package.json @@ -0,0 +1,17 @@ +{ + "name": "nodejs-elasticbeanstalk", + "version": "1.0.0", + "description": "", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "node-cron": "^1.2.1" + } +} diff --git a/ADAM_Ghost/adam-ghost.js b/ADAM_Ghost/adam-ghost.js new file mode 100644 index 0000000..1fac4b2 --- /dev/null +++ b/ADAM_Ghost/adam-ghost.js @@ -0,0 +1,1145 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); + +// Bot Modules (stores http requests & random functions respectively) +const npcSettings = require('./npcSettings'); +const dialog = require('./dialog'); +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); + +const commandArray = ['!checkin', '!stats', '!inventory', '!upgrade', '!heal', '!quests'] + +// Creates an array that seperates 10 items into seperate arrays each +const itemDB = { + "iron_sword": { + "name": "Iron Sword", + "info": "This sturdy sword is great for slashing Ravagers.", + "type": { + "type": "Weapon", + "subtype": "Sword", + "stats": [ + { "attack": 2 } + ] + }, + "amount": 1 + }, + "steel_sword": { + "name": "Steel Sword", + "info": "A tougher form of the Iron Sword, it deals greater blows.", + "type": { + "type": "Weapon", + "subtype": "Sword", + "stats": [ + { "attack": 3 } + ] + }, + "amount": 1 + }, + "leather_armour": { + "name": "Leather Armour", + "info": "A light piece of armour made of leather.", + "type": { + "type": "Equipment", + "subtype": "Armour", + "stats": [ + {"defence": 3}, {"speed": 1} + ] + }, + "amount": 1 + }, + "leather_helm": { + "name": "Leather Helm", + "info": "A leather headpiece, designed for some protection and shade.", + "type": { + "type": "Equipment", + "subtype": "Helm", + "stats": [ + {"defence": 2}, {"speed": 1} + ] + }, + "amount": 1 + }, + "leather_boots": { + "name": "Leather Boots", + "info": "Comfy, leather boots made for long trips in New Eden's deserts.", + "type": { + "type": "Equipment", + "subtype": "Boots", + "stats": [ + {"defence": 1}, {"speed": 1} + ] + }, + "amount": 1 + }, + "iron_armour": { + "name": "Iron Armour", + "info": "Tough, iron armour. It feels solid.", + "type": { + "type": "Equipment", + "subtype": "Armour", + "stats": [ + {"defence": 4}, {"speed": -1} + ] + }, + "amount": 1 + }, + "health_potion": { + "name": "Health Potion", + "info": "A sweet-smelling potion that heals the drinker for 50 HP.", + "type": { + "type": "Potion", + "stats": [ + {"healing": 50} + ] + }, + "amount": 1 + } +} + +// For development testing +var userItems = []; + +addItem(undefined, itemDB["health_potion"], 10); +addItem(undefined, itemDB["iron_sword"], 1); +addItem(undefined, itemDB["leather_armour"], 1); +addItem(undefined, itemDB["leather_boots"], 1); +addItem(undefined, itemDB["leather_helm"], 1); +addItem(undefined, itemDB["steel_sword"], 1); + +// State Machine (Uncomment if needed) +/* +var BotEnumState = { + WAITING: 0, + ACTIVE: 1 +} +var botState = BotEnumState.ACTIVE; +*/ + +// 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) + if (client.user.username !== "Ghost 5.0.1") + client.user.setStatus('online'); + else + client.user.setStatus('invisible'); + + if (client.user.username == "Captain Montomery") { + const newName = "Captain Montgomery"; + console.log("Username is " + client.user.username + "! Typos are NOT(?) cannon, so better change stuff.\nAttempting rename to " + newName + "..."); + + // Set username + client.user.setUsername(newName) + .then(user => console.log(`Success! New username is now ${user.username}.`)) + .catch(console.error); + + // Changes nickname + //client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id).setNickname(""); + } + + // Sets your "Playing" + if (npcSettings.activity) { + client.user.setActivity(npcSettings.activity, { type: npcSettings.type }) + .then(presence => console.log(`Activity set to ${presence.game ? presence.game.name : 'none'}`)) + .catch(console.error); + } + + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + + // Message has to be in a bot channel + //if (!channelProcessor.isBotChannel(message.channel.id)) { + if (message.channel.id !== npcSettings.botChannel) { + // If it's the gate + if (message.channel.id === process.env.GATE_CHANNEL_ID && client.user.username === "A.D.A.M") { + const args = message.content.slice(prefix.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + // If they haven't done the right command to enter + if (!(command === "obsidian" || command === "hand" || command === "genesis")) { + console.log("User sent " + command + (command !== "obsidian")); + if (!(command !== "intro" || command !== "introgenesis" || command !== "introhand" || command !== "introobsidian" || command !== "introend")) { + message.reply("Please choose one of the factions by typing your desired faction shown above (!genesis, !obsidian, or !hand).") + .then(msg => { + msg.delete(10000) + }) + .catch(console.error); + } + } + message.delete(100); + } + } + if (message.channel.id === process.env.STASIS_CHANNEL_ID) return; + + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "ping": + if (isAdmin(message.author.id)) + message.reply("What is your command, almighty and glorious master!"); + break; + case "intro": + if (client.user.username == "A.D.A.M.") + sendMessage(message.channel.id, dialog.getDialog("intro", message.author.id)); + break; + case "introobsidian": + if (client.user.username == "Kamala, Obsidian Vice President") + sendMessage(message.channel.id, dialog.getDialog("introObsidian", message.author.id)); + break; + case "introgenesis": + // Typos officially cannon + if (client.user.username == "Captain Montgomery") + sendMessage(message.channel.id, dialog.getDialog("introGenesis", message.author.id)); + break; + case "introhand": + if (client.user.username == "Dairo, High Prophet of The Hand") + sendMessage(message.channel.id, dialog.getDialog("introHand", message.author.id)); + break; + case "introend": + if (client.user.username == "A.D.A.M.") + sendMessage(message.channel.id, dialog.getDialog("introEnd", message.author.id)); + break; + case "admingetroleids": + //for (var i in discordBot.servers[serverID].roles) { + // console.log(discordBot.servers[serverID].roles[i]); // issues + //} + console.log("!adminGetRoleIDs is Disabled for now"); + break; + case "obsidian": + if (client.user.username == "Kamala, Obsidian Vice President") + changeFaction(process.env.GROUP_A_ROLE, message.channel.id, message.author.id, + message.member, process.env.GROUP_A_BOT_ID); + break; + case "genesis": + if (client.user.username == "Captain Montgomery") + changeFaction(process.env.GROUP_B_ROLE, message.channel.id, message.author.id, + message.member, process.env.GROUP_B_BOT_ID); + break; + case "hand": + if (client.user.username == "Dairo, High Prophet of The Hand") + changeFaction(process.env.GROUP_C_ROLE, message.channel.id, message.author.id, + message.member, process.env.GROUP_C_BOT_ID); + break; + case "beginners": + if (!isAdmin()) break; + if (client.user.username == "A.D.A.M.") { + + var timedEvents = `Mori will revive all weakened travelers every day, and may heal you for a cost, if Mori can find the right things to do so.`; + + var commandsText = `These commands can be done in <#${process.env.GROUP_B_BOT_ID}>, <#${process.env.GROUP_C_BOT_ID}>, or <#${process.env.GROUP_A_BOT_ID}>.\n` + + `**!checkin** - For your help around the city, you can use this to be given a sum of **<:crystals:460974340247257089> Crystals** daily from your faction leader.\n` + + `**!stats** - Your faction leader can check your stats, and your total crystals, materials, etc., with this command.\n`; + + const embed = new Discord.RichEmbed() + .setAuthor( "SANCTUM Beginner's Guide", client.user.avatarURL) + .setColor("#f1c40f") + .setTitle("Welcome to SANCTUM!") + .setDescription("Welcome to SANCTUM, traveler. I hope you will understand the basics on how to survive after the Genesis ship's crash.") + .addField("Basic Commands", commandsText) + .addField("Mori", timedEvents) + + message.channel.send({embed}); + } + break; + case "questboard": + if (!isAdmin(message.author.id)) break; + if (client.user.username != "A.D.A.M.") break; + + var quests = { + "quests": [ + { + "title": "The Lost Pendant", + "id": "thelostpendant", + "description": "Lorem ipsum, or some placeholder text. I wish I knew what to put here, I'm no writer! I need to put more text here in order for the inlines to work more nicely. Not like it matters on mobile, however.", + "objective": "Go to <#${process.env.OUTSKIRTS_CHANNEL_ID}> and **!scavenge** in hopes to find the pendant.", + "userID": process.env.LIBRARIAN_ID, + "color": "keepersOfTheCityColor", + "recommendedLVL": 1, + "questLength": "Short", + "rewards": [ + { + "name": "Crystals", + "emote": "<:crystals:460974340247257089>", + "amount": 10 + }, + { + "name": "Electronics", + "emote": "<:melectronics:462682568911749120>", + "amount": 2 + }, + { + "name": "Gem", + "emote": "<:mgem:462450060718768148>", + "amount": 2 + } + ] + }, + { + "title": "Looming Ravager Outside", + "id": "loomingravager", + "description": "Hey, I have a problem, ya' see. There's a Ravager outside my tavern! And I've been waiting fo' it to go, but it ain't leaving!! I need your help to get rid of it, it's scaring me and my customers!", + "objective": "Go and help slay a Ravager.", + "userID": process.env.ALEXIS_ID, + "color": "keepersOfTheCityColor", + "recommendedLVL": 1, + "questLength": "Short", + "rewards": [ + { + "name": "Crystals", + "emote": "<:crystals:460974340247257089>", + "amount": 5 + } + ] + } + ] + } + + // Collects all preset colors + const keepersOfTheCityColor = message.guild.roles.find(role => role.name === "Keepers of the City").color; + console.log("COLOR: " + keepersOfTheCityColor); + + // Header & Footer (mobile design choice) for quests + const header = new Discord.RichEmbed() + .setAuthor("Quests", client.user.avatarURL) + .setColor(keepersOfTheCityColor) + .setTitle("The Travelers' Quest Board") + .setDescription("Residents of New Eden can post their help requests here, and whoever fulfils them can earn some rewards.") + .setFooter(`⏰ 7 hrs. before the quests are exchanged for new ones.`) + await message.channel.send({embed: header}); + + // Displays all quests in order + for (let i = 0; i < quests.quests.length; i++) { + const element = quests.quests[i]; + const bot = client.guilds.get(process.env.SANCTUM_ID).members.get(element.userID); + var newColor = element.color; + var newDescription = element.description; + var newObjective = element.objective; + var newReward = ""; + const questLength = `Quest Length: **${element.questLength}**.`; + + // Adds rewards up + element.rewards.forEach(reward => { + newReward += `> **${reward.emote} ${reward.name}** [${reward.amount}x]\n`; + }); + + // Returns internal color if needed + if (element.color === "keepersOfTheCityColor") newColor = keepersOfTheCityColor; + + // Replaces certain strings with internal channel data if needed + // NEED TO FIGURE OUT REGEX EXPRESSIONS FOR MASS REPLACE + newObjective = element.objective.replace("${process.env.OUTSKIRTS_CHANNEL_ID}", `${process.env.OUTSKIRTS_CHANNEL_ID}`); + + const body = new Discord.RichEmbed() + .setAuthor(`${bot.displayName}`, bot.user.avatarURL) + .setColor(newColor) + .setTitle(`📃 ${element.title}`) + .setDescription(newDescription) + .addField("Objective", newObjective) + .addField("Reward", newReward, true) + .addField("Info", `Recommended Level: **<:level:461650552506286093> ${element.recommendedLVL}+**.\n${questLength}`, true) + .setFooter(`React with ❗ to take on the quest, and help ${bot.displayName}.`) + + var bodyMessage = await message.channel.send({embed: body}); + await bodyMessage.react("❗"); + } + + // Specifically for mobile + await message.channel.send({embed: header}); + + break; + case "guild": + if (!isAdmin(message.author.id)) break; + if (client.user.username != "A.D.A.M.") break; + + switch (args[0]) { + case "create": + // Start message + var progressMessage = await message.channel.send(`${message.author} I will setup a safe place in the City, please wait.`); + + // Creates new channel & sets topic + var channelName = message.content.replace("!guild create ", '').trim(); + var newChannel = await message.guild.createChannel(channelName, 'text'); + await newChannel.setParent('496813609201172500'); + newChannel.setTopic(`This is the ${channelName} guild!`); + + // Chooses a role name + const roleName = channelName.replace(/\\/g, ""); + + // Creates role & adds it to author + var newRole = await message.guild.createRole({ + name: roleName, + color: 'DARK_AQUA', + }); + await message.member.addRole(newRole); + + // Sets permissions + await newChannel.overwritePermissions(message.guild.roles.find(role => role.name === '@everyone'), { + 'VIEW_CHANNEL': false + }); + await newChannel.overwritePermissions(message.guild.roles.find(role => role.name === roleName), { + 'VIEW_CHANNEL': true + }); + await newChannel.overwritePermissions(message.guild.roles.find(role => role.name === 'Can View All Guilds'), { + 'VIEW_CHANNEL': true + }); + + // Progress message + await progressMessage.edit(`${message.author} I have finished setting up your new ${newRole} guild, in the City. Put it into good use, traveler.`); + + break; + case "tag": + // Appends guild name to user (Grabs nickname by removing anything in []s) + // NOTE: CODE WORKS, JUST DOESN'T LOOK RIGHT + /* + const userNickname = message.member.displayName.replace(/\[(.*?)\]+/g, '').trim(); + message.member.setNickname(`[${roleName}] ${userNickname}`) + .catch((e) => { + console.log("ERROR HAPPENED I THINK") + console.log(e); + + // Catches >32 nickname + if (e.code == 50035) { + message.channel.send(`${message.author} I couldn't change your username in order to put your guild tag, as it would be too long.`) + } + }); + */ + break; + } + + break; + + } + + if (!checkValidDisplay(message.member, message.channel.id, true) && client.user.username != "A.D.A.M.") return; + + switch (command) { + case "checkin": + if (client.user.username == "A.D.A.M.") break; + var checkinAmount = calcRandom.random(4, 9); + var checkInResponse = String(dataRequest.sendServerData("checkin", checkinAmount, message.author.id)); + if (checkInResponse == "1") { + sendMessage(message.channel.id, dialog.getDialog("checkin", message.author.id, checkinAmount)); + addXP(message.author.id, 1); + } else { + sendMessage(message.channel.id, dialog.getDialog("checkinLocked", message.author.id, checkInResponse)); + } + break; + case "give": // Could revamp to make player ID and amount interchangable + if (client.user.username == "A.D.A.M.") break; + var giveAmount = Math.floor(args[0]); + if (message.mentions.members.size > 0) { + console.log(message.mentions.members); + var giveToID = message.mentions.members.first().id; + console.log("GIVE: " + giveToID + " | message.author.id: " + message.author.id) + if (giveToID === message.author.id) { + sendMessage(message.channel.id, dialog.getDialog("giveInvalidUserSelf", message.author.id)); + return; + } + var amountInAccount = dataRequest.loadServerData("account",message.author.id); + if (giveAmount > 0) { + if (amountInAccount >= giveAmount) { + if (dataRequest.sendServerData("transfer",giveToID,message.author.id,giveAmount) == 1) { + sendMessage(message.channel.id, dialog.getDialog("giveSuccessful", message.author.id, giveToID, giveAmount)); + } else { + sendMessage(message.channel.id, dialog.getDialog("giveFailed", message.author.id)); + } + } else { + sendMessage(message.channel.id, dialog.getDialog("giveNotEnoughInAccount", message.author.id)); + } + } else { + sendMessage(message.channel.id, dialog.getDialog("giveNotAboveZero", message.author.id)); + } + } else { + sendMessage(message.channel.id, dialog.getDialog("giveInvalidUser", message.author.id)); + } + break; + case "lore": + if (client.user.username == "A.D.A.M.") break; + sendMessage(message.channel.id, dialog.getDialog("lore", args[0])); + break; + case "stats": + if (client.user.username == "A.D.A.M.") break; + getLevelUp(message.author.id); + + var attacker = String(dataRequest.loadServerData("userStats",message.author.id)); + var scavengeResponse = String(dataRequest.loadServerData("artifactsGet",message.author.id)); + var attackerStrength = parseFloat(attacker.split(",")[0]); + var attackerSpeed = parseFloat(attacker.split(",")[1]); + var attackerStamina = parseFloat(attacker.split(",")[2]); + var attackerHealth = parseFloat(attacker.split(",")[3]); + var attackerMaxStamina = parseFloat(attacker.split(",")[4]); + var attackerMaxHealth = parseFloat(attacker.split(",")[5]); + var attackerWallet = parseFloat(attacker.split(",")[6]); + var attackerXP = parseFloat(attacker.split(",")[7]); + var attackerLVL = Math.floor(parseFloat(attacker.split(",")[8])); + var attackerLvlPercent = parseFloat(attacker.split(",")[9]); + var attackerStatPoints = parseFloat(attacker.split(",")[10]); + var attackerChests = parseFloat(attacker.split(",")[11]); + + var items = scavengeResponse.split(","); + var response = items[0]; + var ultrarare = parseFloat(items[1]); + var rare = parseFloat(items[2]); + var uncommon = parseFloat(items[3]); + var common = parseFloat(items [4]); + var scrap = parseFloat(items[5]); + var totalQuantity = ultrarare + rare + uncommon + common + scrap; + var userStats = ""; + + if (attackerLVL >= 30) { + userStats += "<@" + message.author.id + "> <:level:461650552506286093> **" + attackerLVL + "** (MAX)\t\t" + "<:cannister:462046687058198530> **" + attackerStatPoints + "**\t\t" + "<:cyphercrate:464135029036154950> **" + attackerChests + "** (" + attackerLvlPercent + "%)"; + } else { + userStats += "<@" + message.author.id + "> <:level:461650552506286093> **" + attackerLVL + "** (" + attackerLvlPercent + "%)\t\t\t" + "<:cannister:462046687058198530> **" + attackerStatPoints + "**\t\t\t<:cyphercrate:464135029036154950> **" + attackerChests + "**"; + } + userStats += "```STR: " + attackerStrength + " | SPD: " + attackerSpeed + " | STAM: " + attackerStamina + "/" + attackerMaxStamina + " | HP: " + attackerHealth + "/" + attackerMaxHealth + "```"; + userStats += "<:crystals:460974340247257089> **" + attackerWallet + "**\t\t"; + if (response == "success") { + if (totalQuantity > 0) { + //userStats += "\n"; + if (scrap > 0) { userStats += "<:scrap:463436564379336715> **" + scrap + "**\t\t"; } + if (common > 0) { userStats += "<:mcloth:462682568483930123> **" + common + "**\t\t"; } + if (uncommon > 0) { userStats += "<:mmetal:462682568920137728> **" + uncommon + "**\t\t"; } + if (rare > 0) { userStats += "<:melectronics:462682568911749120> **" + rare + "**\t\t"; } + if (ultrarare > 0) {userStats += "<:mgem:462450060718768148> **" + ultrarare + "**\n\n"; } + } else {console.log("failure2");} + } else {console.log("failure");} + + sendMessage(message.channel.id, userStats); + break; + case "estats": + // Sees if the user is supposed to level up + getLevelUp(message.author.id); + + // Grabs all parameters from server + var attacker = String(dataRequest.loadServerData("userStats",message.author.id)); + var scavengeResponse = String(dataRequest.loadServerData("artifactsGet",message.author.id)); + var attackerStrength = parseFloat(attacker.split(",")[0]); + var attackerSpeed = parseFloat(attacker.split(",")[1]); + var attackerStamina = parseFloat(attacker.split(",")[2]); + var attackerHealth = parseFloat(attacker.split(",")[3]); + var attackerMaxStamina = parseFloat(attacker.split(",")[4]); + var attackerMaxHealth = parseFloat(attacker.split(",")[5]); + var attackerWallet = parseFloat(attacker.split(",")[6]); + var attackerXP = parseFloat(attacker.split(",")[7]); + var attackerLVL = Math.floor(parseFloat(attacker.split(",")[8])); + var attackerLvlPercent = parseFloat(attacker.split(",")[9]); + var attackerStatPoints = parseFloat(attacker.split(",")[10]); + var attackerChests = parseFloat(attacker.split(",")[11]); + + var items = scavengeResponse.split(","); + var response = items[0]; + var ultrarare = parseFloat(items[1]); + var rare = parseFloat(items[2]); + var uncommon = parseFloat(items[3]); + var common = parseFloat(items [4]); + var scrap = parseFloat(items[5]); + var totalQuantity = ultrarare + rare + uncommon + common + scrap; + + // Forms stats into a string + var levelText = `<:level:461650552506286093> **${attackerLVL}**`; + var levelProgress = `(${attackerLvlPercent}%)`; + var crystalText = `<:crystals:460974340247257089> **${attackerWallet}**`; + var cannisterText = `<:cannister:462046687058198530> **${attackerStatPoints}**`; + var cypherCrateText = `<:cyphercrate:464135029036154950> **${attackerChests}**`; + var userStats = "```" + `STR: ${attackerStrength} | SPD: ${attackerSpeed} | STAM: ${attackerStamina}/${attackerMaxStamina} | HP: ${attackerHealth}/${attackerMaxHealth}` + "```"; + var materialsText = ``; + + // Materials + if (response == "success") { + if (totalQuantity > 0) { + if (scrap > 0) { materialsText += `<:scrap:463436564379336715> **${scrap}**`; } + if (common > 0) { materialsText += ` | <:mcloth:462682568483930123> **${common}**`; } + if (uncommon > 0) { materialsText += ` | <:mmetal:462682568920137728> **${uncommon}**`; } + if (rare > 0) { materialsText += ` | <:melectronics:462682568911749120> **${rare}**`; } + if (ultrarare > 0) { materialsText += ` | <:mgem:462450060718768148> **${ultrarare}**`; } + } else {console.log("failure2");} + } else {console.log("failure");} + + // Says level is maxed out if it is LVL 30+ + if (attackerLVL >= 30) { + levelProgress = `(MAX)`; + cypherCrateText += ` (${attackerLvlPercent}%)`; + } + + // Creates embed & sends it + const embed = new Discord.RichEmbed() + .setAuthor(`${message.member.displayName}`, message.author.avatarURL) + .setColor(message.member.displayColor) + .setDescription(`${levelText} ${levelProgress} | ${crystalText} | ${cannisterText} | ${cypherCrateText}`) + .addField("Stats", userStats) + .addField("Materials", `${materialsText}`) + .setFooter("Commands: !inventory | !checkin | !upgrade | !heal | !quests") + + message.channel.send(embed); + break; + case "inventory": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num)) { + return sendInventory(message, num); + } + } else { + return sendInventory(message); + } + break; + case "inv": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num)) { + return sendInventory(message, num); + } + } else { + return sendInventory(message); + } + break; + case "item": + return appraiseItem(message); + + case "help": + if (client.user.username == "A.D.A.M.") break; + if (!args[0]) { + sendMessage(message.channel.id, dialog.getDialog("help", message.author.id)); + } else if (message.mentions.members.first() !== undefined) { + // MORI + if (message.mentions.members.first().id == process.env.MORI_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpMori", message.author.id)); + } + // RAVAGER + if (message.mentions.members.first().id == process.env.RAVAGER_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpRavager", message.author.id)); + + } + // MOSIAH + if (message.mentions.members.first().id == process.env.MOSIAH_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpMosiah", message.author.id)); + + } + // GRAZE + if (message.mentions.members.first().id == process.env.GRAZE_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpGraze", message.author.id)); + + } + // SONYA + /* + if (message.mentions.members.first().id == process.env.SONYA_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpSonya", message.author.id)); + } + */ + // REY + if (message.mentions.members.first().id == process.env.REY_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpRey", message.author.id)); + } + // ALEXIS + if (message.mentions.members.first().id == process.env.ALEXIS_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpAlexis", message.author.id)); + } + //sendMessage(message.channel.id, ":frowning:" + message.mentions.members.first().id); + } + break; + } + +}); + +client.on('error', console.error); + +// Gets footer commands for botspam channel commands +function getFooterCommands(currentCommand) { + var textFooter = ""; + const filtered = commandArray.filter(word => word !== currentCommand); + //console.log(filtered); + + filtered.forEach(element => { + var appendedText = " | "; + if (textFooter.length !== 0) textFooter += appendedText; + textFooter += element; + }); + //console.log(textFooter); + return textFooter; +} + +// Adds item to inventory +function addItem(userID, item, amount) { + // If item exists in inventory + console.log("[Add Item] " + amount); + var i = userItems.findIndex(i => i.name === item.name); + console.log("[Item Amount Item Exists] i Equals " + i); + + // If there is an item that exists in inventory + if (i !== -1) { + console.log("[Item Amount Start] " + userItems[i].amount); + userItems[i].amount += amount; // Increments amount value + console.log("[Item Amount Finish] " + userItems[i].amount); + // Disallows adding objects such as crystals + } else { + console.log("[Item Amount Wait] Created item for the first time."); + var clonedItem = JSON.parse(JSON.stringify(item)); // Clones item in order to not actually increment the rooms.js item JSON data + userItems.push(clonedItem); + addItem(userID, item, amount - 1); + } +} + +// Sends inventory into chat +async function sendInventory(message, pageNum, newMessage) { + var items = ""; + var groupedArr = createGroupedArray(userItems, 5); + + // Sets a default page num, or makes it human readable + if (pageNum === undefined) pageNum = 1; else { + if (pageNum < 1) pageNum = 1; + if (groupedArr.length < pageNum) pageNum = groupedArr.length; + } + + // Checks if page number is valid + if (pageNum > groupedArr.length) { + // If it's longer than actual length, but isn't just an empty inventory + if (!groupedArr.length === 0) return; + } + + //console.log(pageNum); + + // Grabs item in loop, parses it, then adds it to "items" variable + if (groupedArr[pageNum - 1]) { + for (let index = 0; index < groupedArr[pageNum - 1].length; index++) { + // Grabs an item, from a page index + const element = groupedArr[pageNum - 1][index]; + + // Makes if there is an emote, it'll add an extra space + var emoteText = ""; + if (element.emote) emoteText = element.emote + " "; + + // Adds it in + items += `> ${emoteText}**${element.name}** [${element.amount}x] ${element.info}\n`; + } + } + + // No items message to fill field + if (items === "") items = "There are no items in the party's inventory."; + + // To make the message of "Page 1/0" with no items in !inventory not happen + var moddedLength = groupedArr.length; + if (moddedLength < 1) moddedLength = 1; + + const footer = getFooterCommands("!inventory"); + + // Creates embed & sends it + const inv = new Discord.RichEmbed() + .setAuthor(`${message.member.displayName}`, message.author.avatarURL) + .setColor(message.member.displayColor) + .setDescription("I can appraise your items with `!item [ITEM NAME]`, traveler.") + .addField(`Items (Page ${pageNum}/${moddedLength})`, items) + .setFooter(`Commands: ${footer}`) + + var invMessage; + if (!newMessage) + invMessage = await message.channel.send({embed: inv}); + else { + invMessage = newMessage; + await invMessage.edit({embed: inv}); + } + + // Collector for emotes + const emotes = ['⬅', '❌', '➡']; + const collector = invMessage.createReactionCollector( + (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id , { time: 15 * 1000 }); + var react = ""; + var endedOnReact; + + // Sends reactions + if (!newMessage) { + for (let i = 0; i < emotes.length; i++) { + const element = emotes[i]; + console.log(element); + await invMessage.react(element); + } + } + + // Collects reactions + collector.on("collect", async reaction => { + var user = reaction.users.last(); + react = reaction.emoji.name; + if (react !== '❌') { reaction.remove(user); } + endedOnReact = true; + collector.stop(); + }); + + // Clears reactions + collector.once("end", async collecter => { + console.log("[Reaction Options] Ended collector, clearing emotes and sending timing out message if needed."); + + if (!endedOnReact) { + invMessage.clearReactions(); + return message.channel.send(":x: **Timed Out**: The emote reaction request timed out after 15 seconds."); + } + if (react === '❌') { + invMessage.clearReactions(); + return invMessage.edit(invMessage.content); + } + + var pageNumModifier = 0; + if (react === emotes[0]) pageNumModifier -= 1; + if (react === emotes[2]) pageNumModifier += 1; + console.log(pageNum + " | " + pageNumModifier); + sendInventory(message, pageNum + pageNumModifier, invMessage); + }); +} + +// Appraise an item +async function appraiseItem(message) { + const itemName = message.content.replace("!item", "").trim().toLowerCase(); + console.log("[Item Appraisal] " + `<< ${itemName} >>`); + + // Show if no parameter is given + if (itemName === "" || !itemName) { + message.channel.send(`:x: ${message.author} Please tell me the item name from your inventory, or I won't know which item you want me to look at.`); + return; + } + + var i = userItems.findIndex(i => i.name.toLowerCase() === itemName); + console.log("[Item Amount Item Exists] i Equals " + i); + + // If there is an item that exists in inventory + if (i !== -1) { + console.log(`[Item Appraisal] Found item in inventory!`); + const embed = new Discord.RichEmbed() + .setAuthor(`${message.member.displayName}`, message.author.avatarURL) + .setColor(message.member.displayColor) + .setTitle(userItems[i].name) + .setDescription(userItems[i].info) + + if (userItems[i].type.subtype) + embed.addField("Type", `${userItems[i].type.type}\n> ${userItems[i].type.subtype}`, true) + else + embed.addField("Type", `${userItems[i].type.type}`, true) + + if (userItems[i].type.stats) { + console.log(JSON.stringify(userItems[i].type.stats, null, 4)) + var itemStats = "There are no stats avaliable."; + var resetItemStats = false; + userItems[i].type.stats.forEach(element => { + if (element) { + if (!resetItemStats) { + resetItemStats = true; + itemStats = ""; + } + const types = [ + "attack", + "defence", + "speed", + "healing" + ]; + + types.forEach(type => { + if (element[type]) { + switch (type) { + case "attack": + itemStats += `ATK: ${element.attack}\n`; + break; + case "defence": + itemStats += `DEF: ${element.defence}\n`; + break; + case "speed": + itemStats += `SPD: ${element.speed}\n`; + break; + case "healing": + itemStats += `Healing: ${element.healing} HP\n`; + break; + } + } + }); + } + }); + } + + embed.addField("Stats", `${itemStats}`, true); + + message.channel.send(embed); + + // Disallows adding objects such as crystals + } else { + console.log("[Item Appraisal] Couldn't find item in inventory."); + message.channel.send(`:x: ${message.author} I'm unable to find "${itemName}" in your inventory.`); + } +} + +// Creates an array that creates multiple different arrays inside of that array -> [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +// http://www.frontcoded.com/splitting-javascript-array-into-chunks.html +var createGroupedArray = function(arr, chunkSize) { + var groups = [], i; + for (i = 0; i < arr.length; i += chunkSize) { + groups.push(arr.slice(i, i + chunkSize)); + } + return groups; +} + +// See if the bot should display its message +function checkValidDisplay(member, channelID, checkRole) { + if (client.user.username == "Kamala, Obsidian Vice President" && channelID === process.env.GROUP_A_BOT_ID) { + if (checkRole) { if (member.roles.has(process.env.GROUP_A_ROLE)) return true; } else true; + } + else if (client.user.username == "Captain Montgomery" && channelID === process.env.GROUP_B_BOT_ID) { + if (checkRole) { if (member.roles.has(process.env.GROUP_B_ROLE)) return true; } else true; + } + else if (client.user.username == "Dairo, High Prophet of The Hand" && channelID === process.env.GROUP_C_BOT_ID) { + if (checkRole) { if (member.roles.has(process.env.GROUP_C_ROLE)) return true; } else true; + } + else if (client.user.username == "Ghost 5.0.1") { + // JSON + const rooms = require('../TextAdv/rooms.json'); + var roomExists = false; + + // Loops for all rooms + rooms.rooms.forEach(element => { + if (channelID === rooms[element].channel) roomExists = true; + }); + + if (!roomExists) { + if (channelID === process.env.TEST_CHANNEL_ID) return true; + } else return true; + + } + + return false; +} + +// Gets if user has an Overseers rank +function isAdmin(userID) { + var guild = client.guilds.get(process.env.SANCTUM_ID); + return guild.members.get(userID).roles.find(role => role.name === "Overseers"); +} + +// Change Faction +async function changeFaction(factionID, channelID, userID, member, botChannelID) { + if (member.roles.has(factionID)) { + if (factionID === process.env.GROUP_A_ROLE) + sendMessage(channelID, dialog.getDialog("orderAlreadyJoined", userID)); + else if (factionID === process.env.GROUP_B_ROLE) + sendMessage(channelID, dialog.getDialog("anarchyAlreadyJoined", userID)); + else if (factionID === process.env.GROUP_C_ROLE) + sendMessage(channelID, dialog.getDialog("religionAlreadyJoined", userID)); + } else { + if (dataRequest.loadServerData("hasConvertedToday", userID) == 1) { + sendMessage(channelID, dialog.getDialog("alreadyConvertedToday", userID)); + } else { + // Creates new user + var response = String(dataRequest.sendServerData("newUser", "New user.", userID)); + + //var response = "createdUser" + // Obsidian Tech. + if (factionID === process.env.GROUP_A_ROLE) { + await member.removeRole(process.env.GROUP_B_ROLE); + await member.removeRole(process.env.GROUP_C_ROLE); + await member.addRole(process.env.GROUP_A_ROLE); + + dataRequest.sendServerData("conversion", "Converted to The Order.", userID); + + if (response == "createdUser") { + client.users.get(userID).send(dialog.getDialog("newUserPM", userID, getFactionName(factionID))); + sendMessage(botChannelID, dialog.getDialog("newUserWelcome", userID, `<#${getFactionName(factionID)}>`)); + } else { + sendMessage(channelID, dialog.getDialog("orderJoin", userID)); + } + + // Genesis Command + } else if (factionID === process.env.GROUP_B_ROLE) { + await member.removeRole(process.env.GROUP_C_ROLE); + await member.removeRole(process.env.GROUP_A_ROLE); + await member.addRole(process.env.GROUP_B_ROLE); + + dataRequest.sendServerData("conversion", "Converted to the Anarchy.", userID); + + if (response == "createdUser") { + client.users.get(userID).send(dialog.getDialog("newUserPM", userID, getFactionName(factionID))); + sendMessage(botChannelID, dialog.getDialog("newUserWelcome", userID, `<#${getFactionName(factionID)}>`)); + } else { + sendMessage(channelID, dialog.getDialog("anarchyJoin", userID)); + } + + // The Hand + } else if (factionID === process.env.GROUP_C_ROLE) { + await member.removeRole(process.env.GROUP_A_ROLE); + await member.removeRole(process.env.GROUP_B_ROLE); + await member.addRole(process.env.GROUP_C_ROLE); + + dataRequest.sendServerData("conversion", "Converted to The Religion.", userID); + + if (response == "createdUser") { + client.users.get(userID).send(dialog.getDialog("newUserPM", userID, getFactionName(factionID))); + sendMessage(botChannelID, dialog.getDialog("newUserWelcome", userID, `<#${getFactionName(factionID)}>`)); + } else { + sendMessage(channelID, dialog.getDialog("religionJoin", userID)); + } + } + } + } +} + +function addXP(userID,amount) { + var response = String(dataRequest.sendServerData("addXP", amount, userID)); +} + +function getLevelUp(userID) { + const server = client.guilds.get(process.env.SANCTUM_ID); + const member = server.members.get(userID); + if (client.user.username == "Kamala, Obsidian Vice President" && !member.roles.has(process.env.GROUP_A_ROLE)) return; + if (client.user.username == "Captain Montgomery" && !member.roles.has(process.env.GROUP_B_ROLE)) return; + if (client.user.username == "Dairo, High Prophet of The Hand" && !member.roles.has(process.env.GROUP_C_ROLE)) return; + + //const user = server.members.get(userID); + var response = String(dataRequest.sendServerData("getLevelUp", 0, userID)); + var responseMessage = String(response.split(",")[0]); + var lvl = Math.floor(parseFloat(response.split(",")[1])); + var statPoints = parseFloat(response.split(",")[2]); + + var attacker = String(dataRequest.loadServerData("userStats", userID)); + var chests = parseFloat(attacker.split(",")[11]); + + console.log(response.split(",")); + + majorLevelUp(lvl, server, userID); + + if (responseMessage == "levelup") { + //if (true) { + console.log("Chests: " + chests) + checkinLevelUp(userID, lvl, statPoints, chests); + } +} + +async function majorLevelUp(level, server, userID) { + const user = server.members.get(userID); + + var newChannel = ""; + + var levels = [ + // Role, Level + [server.roles.find(role => role.name === "LVL 1+"), 1, process.env.CRYSTAL_SHORES_CHANNEL_ID], + [server.roles.find(role => role.name === "LVL 15+"), 15, process.env.SEA_OF_FOG_CHANNEL_ID], + [server.roles.find(role => role.name === "LVL 30+"), 30, process.env.DEADLANDS_CHANNEL_ID] + ] + + // Shrinking level + if (level < 30) { + level = 15; + } else if (level < 15) { + level = 1; + } + + // Rank Level Up + var levelRole = server.roles.find(role => role.name === `LVL ${level}+`); + if (levelRole) { + var memberRole = user.roles.has(levelRole.id); + if (!memberRole) { + user.addRole(levelRole).catch(console.error); + for (let i = 0; i < levels.length; i++) { + const element = levels[i]; + if (element[1] !== level) { + await user.removeRole(element[0]); + } + } + if (user !== undefined) {// && newChannel !== undefined) { + var levelMarks = [1, 15, 30]; + + for (let i = 0; i < levelMarks.length; i++) { + const element = levelMarks[i]; + // Gets channel of array + newChannel = client.channels.get(levels[levels.findIndex(level => level[1] === element)][2]); + if (level === element) + newChannel.send(dialog.getDialog("level" + level, user, newChannel)); + } + } + } + } +} + +// Gets the user's role by member +function getFactionChannel(member) { + var playerChannel; + var isGroupA = member.roles.has(process.env.GROUP_A_ROLE); + var isGroupB = member.roles.has(process.env.GROUP_B_ROLE); + var isGroupC = member.roles.has(process.env.GROUP_C_ROLE); + //console.log(member.roles); + //console.log("isGroup: " + isGroupA + " " + isGroupB + " " + isGroupC); + if (isGroupA) playerChannel = process.env.GROUP_A_BOT_ID; + else if (isGroupB) playerChannel = process.env.GROUP_B_BOT_ID; + else if (isGroupC) playerChannel = process.env.GROUP_C_BOT_ID; + + return playerChannel; +} + +// Gets faction names by ID +function getFactionName(factionID) { + if (factionID === process.env.GROUP_A_ROLE) { + return "Obsidian Technologies"; + } + if (factionID === process.env.GROUP_B_ROLE) { + return "Genesis Command"; + } + if (factionID === process.env.GROUP_C_ROLE) { + return "The Hand"; + } +} + +function checkinLevelUp(userID, lvl, statPoints, chests) { + const guild = client.guilds.get(process.env.SANCTUM_ID); + if (lvl === 30) { + //Post level cap level up! + sendMessage(userID, getFactionChannel(guild.members.get(userID)), dialog.getDialog("levelUpLevelCap", userID, lvl, chests)); + } else { + //regular level up + sendMessage(userID, getFactionChannel(guild.members.get(userID)), dialog.getDialog("levelUp", userID, lvl, statPoints)); + } + //sendMessage(testChannelID, dialog.getDialog("levelUp", userID, lvl, statPoints)); +} + +// Updates stamina (1) and health by 1% every 2 min. +cron.schedule('*/2 * * * *', function() { + if (client.user.username === "A.D.A.M.") { + console.log('Updating STAMINA every 2 min.'); + dataRequest.sendServerData("updateStamina", 0); + }; +}); + +// Send message handler +function sendMessage(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message === undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message; + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); +} + +// Log our bot in +client.login(npcSettings.token); \ No newline at end of file diff --git a/ADAM_Ghost/dialog.js b/ADAM_Ghost/dialog.js new file mode 100644 index 0000000..79cbba5 --- /dev/null +++ b/ADAM_Ghost/dialog.js @@ -0,0 +1,298 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + getDialog: function(dialogTag, data = "", data2 = "", data3 = "") { + switch(dialogTag) { + case "checkin": + return "<@" + data + ">" + " your presence has been noted. I've added " + data2 + " crystals to your account."; + + case "checkinLocked": + return ":x: <@" + data + ">" + " you already checked in with me " + data2 + ". You can check in again tomorrow."; + + case "alreadyConvertedToday": + return ":x: <@" + data + ">" + " as anxious as you may be, please don't attempt to change factions so quickly. You can only change once every 30 days."; + + case "depositSuccessful": + //codexLogEvent(data + " deposited " + data2 + " crystals."); + return "<@" + data + ">" + " your deposit of " + data2 + " crystals has been successful. Good luck."; + + case "depositFailed": + return ":x: <@" + data + ">" + " I can't make the deposit at the moment. I apologize for the inconvenience."; + + case "giveSuccessful": + //codexLogEvent(data + " gave " + data2 + " " + data3 + " crystals."); + return "<@" + data + ">" + " I've transferred " + data3 + " crystals to <@" + data2 + "> as per your request."; + + case "giveFailed": + return ":x: <@" + data + ">" + " I can't make that transfer at the moment. I apologize for the inconvenience."; + + case "giveNotEnoughInAccount": + return ":x: <@" + data + ">" + " You don't have that many crystals in your account. As such, I can't complete the transfer."; + + case "giveNotAboveZero": + return ":x: <@" + data + ">" + " In order for me to complete the transfer I need an amount above zero."; + + case "giveInvalidUser": + return ":x: <@" + data + ">" + " I can't find that traveler. Sorry."; + + case "giveInvalidUserSelf": + return ":x: <@" + data + ">" + " You can\'t send crystals to yourself. Sorry."; + + case "levelUp": + var dialogOptions = [ + 'I appreciate all of your help.', + 'Thank you for doing so much for the city.', + 'The other travelers are very grateful for your help.', + 'Your assistance is very much appreciated.', + 'Together we\'ve taken out most of the threats to city.', + 'The citizens of The Sanctum are most grateful.', + 'I cannot thank you enough for your help defending the city.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + var wordToUse = "it"; + if (data3 > 1) { var wordToUse = "them";} + return "You just hit **level " + data2 + "**! " + dialogOptions[randomNumber] + " I\'ve added a <:cannister:462046687058198530> **Nanotech Cannister** to your inventory so that you can upgrade your skills. You now have **" + data3 + "** total (you can check this any time with !stats). Use " + wordToUse + " wisely."; + + case "levelUpLevelCap": + var dialogOptions = [ + 'I appreciate all of your help.', + 'Thank you for doing so much for the city.', + 'The other travelers are very grateful for your help.', + 'Your assistance is very much appreciated.', + 'Together, we\'ve taken out most of the threats to city.', + 'The citizens of The Sanctum are most grateful.', + 'I cannot thank you enough for your help defending the city.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + return "You\'re currently at **level " + data2 + "** which is the current level cap! " + dialogOptions[randomNumber] + " I\'ve added a <:cyphercrate:464135029036154950> **Cypher Crate** to your inventory. Hopefully it contains something useful for you on your journey. You now have **" + data3 + "** total (you can check this any time with !stats). Good luck. "; + + case "help": + var temp = "*This world is strange and mysterious. And while I cannot help you on your journey or join your faction, I am here to help travelers to the best of my ability.* \n\nHere is what I can do for you:"; + temp += "\n\n"; + temp += "!checkin\n```Once per day, you may come see me for a daily sum in exchange for your help around the city.```"; + temp += "\n"; + temp += "!stats\n```I can share all of your stats and your crystal count information.```"; + temp += "\n"; + temp += "!give [AMOUNT] [@USER]\n```I can transfer some of your crystals to another traveler's account. Just make sure you have enough.```"; + temp += "\n"; + temp += "!help [@NAME]\n```I can tell you a little bit about some of the other people with us here on New Eden.```"; + temp += "\n"; + temp += "I hope this helps you on your journey, traveler."; + return temp; + + case "helpMori": + var temp = "*Mori is our resident head of the medbay. He can tend to your wounds and get you back on your feet. Here's what he can do:*"; + temp += "\n\n"; + temp += "!heal\n```Shows you Mori\'s available procedures for healing.```"; + temp += "\n"; + temp += "!heal [ITEM]\n```Purchases a procedure directly from him, and with his nanotech, takes effect immediately.```"; + return temp; + + case "helpGraze": + var temp = "*Graze is our loveable augmentation expert. He can help you upgrade your skills and boost your abilities. Here's what he can do:*"; + temp += "\n\n"; + temp += "!upgrade\n```Shows you the available upgrades that Graze can provide with your Nanotech Cannisters.```"; + temp += "\n"; + temp += "!upgrade [STAT]\n```Upgrades this specific stat permanently.```"; + return temp; + + case "helpMosiah": + var temp = `*Mosiah was exiled from our great city for many counts of misconduct, but it\'s been said he\'s been seen at <#${process.env.TAVERN_CHANNEL_ID}>. I recommend you not deal with him at all, but should you need to, here\'s what he can do:*`; + temp += "\n\n"; + temp += "!wager [AMOUNT]\n```Wagers your crystals in a primative coin flip bet. Winner takes all.```"; + return temp; + + case "helpRavager": + var temp = `*The Ravagers have been hunting us since crashing here on New Eden. They roam this planet and will attack travelers on sight. But you can defend yourself:*`; + temp += "\n\n"; + temp += "!attack\n```Sends your weapon towards an active Ravager. If you win the fight, you can loot their corpse for crystals. But be careful: they bite back.```"; + temp += "\n"; + temp += "!details\n```Shows you the details of the last Ravager fight to take place as well as the crystal distribution.```"; + return temp; + + case "helpSonya": + var temp = "*Professor Sonya is our resident archeologist, and she is fascinated by this world. Scavenge for some artifacts in the outskirts of the city, and she will apy you handsomely.*"; + temp += "\n\n"; + temp += "!scavenge\n```In #🌘the-outskirts, this allows you to look for rare artifacts for the professor.```"; + temp += "\n"; + temp += "!artifacts\n```Shows you the current artifacts that you have in your inventory.```"; + temp += "\n"; + temp += "!artifacts sell\n```Shows you the current prices that the professor is willing to pay for any artifacts that you may find.```"; + temp += "\n"; + temp += "!artifacts sell [TYPE]\n```Sells all of the artifacts that you have of that type to the professor, at current prices.```"; + return temp; + + case "helpRey": + var temp = "*Rey is a master of finding things that we need around the city. Resources are scarce, so anything you can help her find in <#462382076927148054> would be most helpful.*"; + temp += "\n\n"; + temp += "!scavenge\n```In #🌘the-outskirts, this allows you to look for materials and resources with Rey.```"; + temp += "\n"; + temp += "!materials\n```Shows you the current materials that you have in your inventory.```"; + return temp; + + case "helpAlexis": + var temp = "*Alexis is our top-of-the-line chemist who uses her talents to reward travelers with a nice and relaxing space. She\'d be happy to have or provide you with some company.*"; + temp += "\n\n"; + temp += "!buydrink\n```In #🍺travelers-watch, this allows you to buy a drink and relax.```"; + temp += "\n"; + temp += "!buydrink [@NAME]\n```In #🍺travelers-watch, you can buy a drink for a friend.```"; + temp += "\n"; + temp += "!tip [AMOUNT]\n```In #🍺travelers-watch, you can tip her for her great service. She might just give you a tip back.```"; + return temp; + + //Status commands + case "accountCheck": + return "<@" + data + ">" + " you currently have " + data2 + " crystals in your account."; + + case "bankCheck": + return "Currently, " + data + " has " + data2 + " crystals total in their bank."; + + case "victors": + return "Currently, " + data + " controls the fate of the codex."; + + case "noVictors": + return "The fate of the codex is still undetermined."; + + // Obsidian Technologies (Former Order) + case "orderAlreadyJoined": + return ":x: <@" + data + ">" + " The Obsidian Technologies already has your allegiance. There's no need to request a change."; + case "orderJoin": + //codexLogEvent(data + " joined Genesis Command."); + return "<@" + data + ">" + " you have joined the Obsidian Technologies. May peace reign upon your cause."; + + // Genesis Command (Former Anarchy) + case "anarchyAlreadyJoined": + return ":x: <@" + data + ">" + " The Genesis Command has already begun their chaos with you by their side. There's no need to request a change."; + case "anarchyJoin": + //codexLogEvent(data + " joined Obsidian Technologies."); + return "<@" + data + ">" + " you have joined the Genesis Command. May chaos come to those who oppose you."; + + // The Hand (Former Religion) + case "religionAlreadyJoined": + return ":x: <@" + data + ">" + " The Hand is happy to have you in their congregation already. There's no need to request a change."; + case "religionJoin": + //codexLogEvent(data + " joined The Hand."); + return "<@" + data + ">" + " you have joined The Hand. May the gods look favorably upon you."; + + //Onboarding + case "newUserWelcome": + messageToSend = "<@" + data + ">" + " welcome to " + data2 + ". If you need me for anything, you can contact me via this secure channel. Just use **!help** for a list of things I can do for you."; + messageToSend += "\n\nAnd don\'t forget to say hello to fellow travelers in "; + if (data2 == "Genesis Command") { + messageToSend += `${process.env.GROUP_B_BOT_ID}.`; + } + if (data2 == "Obsidian Technologies") { + messageToSend += `${process.env.GROUP_A_BOT_ID}.`; + } + if (data2 == "The Hand") { + messageToSend += `${process.env.GROUP_C_BOT_ID}.`; + } + return messageToSend; + case "newUserPM": + var messageToSend = ''; + messageToSend = "_Traveler, welcome to The Sanctum."; + messageToSend += "\n\n"; + + if (data2 == "Genesis Command") { + messageToSend += "I see that you've joined **Genesis Command**. The least reckless of the 3 factions, I can see why you'd pick them. You clearly understand that The Codex is a very powerful book, and should you be victorious, no one will have access to it\'s secrets. "; + } + if (data2 == "Obsidian Technologies") { + messageToSend += "I see that you've joined **Obsidian Technologies**. While they are the most chaotic of the 3 factions, I can see why you'd pick them. The Codex is a very powerful book, and should you be victorious, everyone will have equal access to it\'s secrets. "; + } + if (data2 == "The Hand") { + messageToSend += "I see that you've joined **The Hand**. While they are certainly the most suspicious of the 3 factions, I can see why you'd pick them. The Codex is a very powerful book, and should you be victorious, it is your job to guide the rest of the city using it\'s secrets."; + } + messageToSend += "\n\n"; + messageToSend += "I'll get you patched up and give you access to our team to upgrade skills and meet the others. There's just a few things I need you to take care of around the city:_"; + messageToSend += "\n\n"; + messageToSend += "**!checkin** with me daily.\n```Once a day I'll give you your daily allotment of crystals in exchange for some help around the city.```"; + messageToSend += "\n"; + messageToSend += "**!attack** any Ravagers in #the-deadlands.\n```With the constant bombardment from the enemies of the city, It\'s hard to keep us safe. I need your help```"; + messageToSend += "\n"; + messageToSend += "_Good luck. I'll be around if you need me._"; + return messageToSend; + //Lore + case "intro": + var tempLore = ''; + tempLore = "_Hello weary traveler."; + tempLore += "\n\n"; + tempLore += "My name is A.D.A.M. and I would like to offer you the amenities of The Sanctum. However, I cannot come to your aid until you choose a faction. I am dearly sorry to be so blunt and put trivial human rules in place over your sustenance and safety, but this is the only way to protect The Codex. But the Codex no longer exists since the Librarian destroyed it, so make something up, player."; + tempLore += " Your choices are as follows:_"; + return tempLore; + case "introHand": + var tempLore = "<:religionhand:461582719051104276> **<@&" + process.env.GROUP_C_ROLE + ">** - !hand\n```Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eu aliquet mauris, id congue nisi. Integer et lobortis tellus. Sed bibendum a metus quis volutpat. Mauris faucibus quam at euismod scelerisque. Vestibulum a elit auctor, venenatis augue in, rhoncus nisi. Mauris sagittis sit amet ante eget luctus. Maecenas id malesuada elit. Vestibulum nec ante nec justo venenatis tincidunt.```"; + return tempLore; + case "introGenesis": + var tempLore = "<:order:460991638152413194> **<@&" + process.env.GROUP_B_ROLE + ">** - !genesis\n```Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eu aliquet mauris, id congue nisi. Integer et lobortis tellus. Sed bibendum a metus quis volutpat. Mauris faucibus quam at euismod scelerisque. Vestibulum a elit auctor, venenatis augue in, rhoncus nisi. Mauris sagittis sit amet ante eget luctus. Maecenas id malesuada elit. Vestibulum nec ante nec justo venenatis tincidunt. ```"; + return tempLore; + case "introObsidian": + var tempLore = "<:anarchy:460990297099337750> **<@&" + process.env.GROUP_A_ROLE + ">** - !obsidian\n```Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eu aliquet mauris, id congue nisi. Integer et lobortis tellus. Sed bibendum a metus quis volutpat. Mauris faucibus quam at euismod scelerisque. Vestibulum a elit auctor, venenatis augue in, rhoncus nisi. Mauris sagittis sit amet ante eget luctus. Maecenas id malesuada elit. Vestibulum nec ante nec justo venenatis tincidunt.```"; + return tempLore; + case "introEnd": + var tempLore = "_Choose wisely._"; + return tempLore; + case "level1": + var tempLore = ''; + tempLore += `Congratulations ${data}, you have reached **${data2}**! Travelers defend the city from Ravagers here, and you can earn some crystals.` + return tempLore; + case "level15": + var tempLore = ''; + tempLore += `Congratulations ${data}, you have reached **${data2}**, where there are more dangerous enemies, lurking in the fog.` + return tempLore; + case "level30": + var tempLore = ''; + tempLore += `Congratulations ${data}, you have reached **${data2}**, the area most teeming with the strongest Ravagers. Watch your back, and good luck!` + return tempLore; + case "lore": + var tempLore = ''; + switch(data) { + case "backstory": + tempLore = "‘_Mother Earth had failed us. "; + tempLore += "\n\n"; + tempLore += "In her dying breath, she bore a starship, **The Genesis**, to save the last of humankind. But the **travelers** aboard were not prepared for the unwelcoming winds of barren space."; + tempLore += "\n\n"; + tempLore += "On the brink of extinction our forefathers landed here, but this was no earth. The desolate landscape of **The Deadlands** traded our starvation for thirst, our isolation for open and empty space. But despite our struggles, we could breathe again."; + tempLore += "\n\n"; + tempLore += "We walked for many days and many nights in **The Deadlands**, consuming only the native **crystals** climbing from the ground for sustenance. Leaving the shelter of our vessel behind for the hope of a new home. Many withered away under the scorching heat of the twin suns and the constant attacks from **Ravagers**, but Mother Earth kept her promise."; + tempLore += "\n\n"; + tempLore += "In our darkest hour, we laid eyes on **The Sanctum**, a city of the gods. Complete with a vault full of our edible crystals, and more than enough room for the entire population; A city with human amenities in the middle of an inhuman world, bestowed upon a dying nation in need. This place was truly a divine gift."; + tempLore += "\n\n"; + tempLore += "At the highest point of the city in the tower that touched the clouds, we found **The Librarian**. A meticulous mechanical record keeper hovering over his book, the great **Codex Arcana**. This was a book written in detail to record the actions of every man, woman, and child that lived among us. But it was far too powerful, and the secrets it contained proved lethal in the wrong hands."; + tempLore += "\n\n"; + tempLore += "And so began the **factions**, vying for control over the Codex._'"; + tempLore += "\n\n"; + tempLore += "- Excerpt from the **Teachings of Tiberius**. March 22, 2630."; + break; + case "genesis": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "travelers": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "deadlands": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "ravager": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "Sanctum": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "librarian": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "codex": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "factions": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + default: + tempLore = "Here is the lore that is available in my database. ```!lore backstory```" + break + } + console.log("TEMPLORE: " + tempLore); + return tempLore; + } + } +} diff --git a/ADAM_Ghost/npcSettings.js b/ADAM_Ghost/npcSettings.js new file mode 100644 index 0000000..87e60c9 --- /dev/null +++ b/ADAM_Ghost/npcSettings.js @@ -0,0 +1,6 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + token: process.env.GHOST_TOKEN, + botChannel: "" +} diff --git a/ADAM_Ghost/package-lock.json b/ADAM_Ghost/package-lock.json new file mode 100644 index 0000000..16601ab --- /dev/null +++ b/ADAM_Ghost/package-lock.json @@ -0,0 +1,69 @@ +{ + "name": "nodejs-elasticbeanstalk", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + } + } +} diff --git a/ADAM_Ghost/package.json b/ADAM_Ghost/package.json new file mode 100644 index 0000000..11eb464 --- /dev/null +++ b/ADAM_Ghost/package.json @@ -0,0 +1,17 @@ +{ + "name": "nodejs-elasticbeanstalk", + "version": "1.0.0", + "description": "", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "node-cron": "^1.2.1" + } +} diff --git a/ADAM_Kamala/adam-kamala.js b/ADAM_Kamala/adam-kamala.js new file mode 100644 index 0000000..1fac4b2 --- /dev/null +++ b/ADAM_Kamala/adam-kamala.js @@ -0,0 +1,1145 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); + +// Bot Modules (stores http requests & random functions respectively) +const npcSettings = require('./npcSettings'); +const dialog = require('./dialog'); +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); + +const commandArray = ['!checkin', '!stats', '!inventory', '!upgrade', '!heal', '!quests'] + +// Creates an array that seperates 10 items into seperate arrays each +const itemDB = { + "iron_sword": { + "name": "Iron Sword", + "info": "This sturdy sword is great for slashing Ravagers.", + "type": { + "type": "Weapon", + "subtype": "Sword", + "stats": [ + { "attack": 2 } + ] + }, + "amount": 1 + }, + "steel_sword": { + "name": "Steel Sword", + "info": "A tougher form of the Iron Sword, it deals greater blows.", + "type": { + "type": "Weapon", + "subtype": "Sword", + "stats": [ + { "attack": 3 } + ] + }, + "amount": 1 + }, + "leather_armour": { + "name": "Leather Armour", + "info": "A light piece of armour made of leather.", + "type": { + "type": "Equipment", + "subtype": "Armour", + "stats": [ + {"defence": 3}, {"speed": 1} + ] + }, + "amount": 1 + }, + "leather_helm": { + "name": "Leather Helm", + "info": "A leather headpiece, designed for some protection and shade.", + "type": { + "type": "Equipment", + "subtype": "Helm", + "stats": [ + {"defence": 2}, {"speed": 1} + ] + }, + "amount": 1 + }, + "leather_boots": { + "name": "Leather Boots", + "info": "Comfy, leather boots made for long trips in New Eden's deserts.", + "type": { + "type": "Equipment", + "subtype": "Boots", + "stats": [ + {"defence": 1}, {"speed": 1} + ] + }, + "amount": 1 + }, + "iron_armour": { + "name": "Iron Armour", + "info": "Tough, iron armour. It feels solid.", + "type": { + "type": "Equipment", + "subtype": "Armour", + "stats": [ + {"defence": 4}, {"speed": -1} + ] + }, + "amount": 1 + }, + "health_potion": { + "name": "Health Potion", + "info": "A sweet-smelling potion that heals the drinker for 50 HP.", + "type": { + "type": "Potion", + "stats": [ + {"healing": 50} + ] + }, + "amount": 1 + } +} + +// For development testing +var userItems = []; + +addItem(undefined, itemDB["health_potion"], 10); +addItem(undefined, itemDB["iron_sword"], 1); +addItem(undefined, itemDB["leather_armour"], 1); +addItem(undefined, itemDB["leather_boots"], 1); +addItem(undefined, itemDB["leather_helm"], 1); +addItem(undefined, itemDB["steel_sword"], 1); + +// State Machine (Uncomment if needed) +/* +var BotEnumState = { + WAITING: 0, + ACTIVE: 1 +} +var botState = BotEnumState.ACTIVE; +*/ + +// 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) + if (client.user.username !== "Ghost 5.0.1") + client.user.setStatus('online'); + else + client.user.setStatus('invisible'); + + if (client.user.username == "Captain Montomery") { + const newName = "Captain Montgomery"; + console.log("Username is " + client.user.username + "! Typos are NOT(?) cannon, so better change stuff.\nAttempting rename to " + newName + "..."); + + // Set username + client.user.setUsername(newName) + .then(user => console.log(`Success! New username is now ${user.username}.`)) + .catch(console.error); + + // Changes nickname + //client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id).setNickname(""); + } + + // Sets your "Playing" + if (npcSettings.activity) { + client.user.setActivity(npcSettings.activity, { type: npcSettings.type }) + .then(presence => console.log(`Activity set to ${presence.game ? presence.game.name : 'none'}`)) + .catch(console.error); + } + + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + + // Message has to be in a bot channel + //if (!channelProcessor.isBotChannel(message.channel.id)) { + if (message.channel.id !== npcSettings.botChannel) { + // If it's the gate + if (message.channel.id === process.env.GATE_CHANNEL_ID && client.user.username === "A.D.A.M") { + const args = message.content.slice(prefix.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + // If they haven't done the right command to enter + if (!(command === "obsidian" || command === "hand" || command === "genesis")) { + console.log("User sent " + command + (command !== "obsidian")); + if (!(command !== "intro" || command !== "introgenesis" || command !== "introhand" || command !== "introobsidian" || command !== "introend")) { + message.reply("Please choose one of the factions by typing your desired faction shown above (!genesis, !obsidian, or !hand).") + .then(msg => { + msg.delete(10000) + }) + .catch(console.error); + } + } + message.delete(100); + } + } + if (message.channel.id === process.env.STASIS_CHANNEL_ID) return; + + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "ping": + if (isAdmin(message.author.id)) + message.reply("What is your command, almighty and glorious master!"); + break; + case "intro": + if (client.user.username == "A.D.A.M.") + sendMessage(message.channel.id, dialog.getDialog("intro", message.author.id)); + break; + case "introobsidian": + if (client.user.username == "Kamala, Obsidian Vice President") + sendMessage(message.channel.id, dialog.getDialog("introObsidian", message.author.id)); + break; + case "introgenesis": + // Typos officially cannon + if (client.user.username == "Captain Montgomery") + sendMessage(message.channel.id, dialog.getDialog("introGenesis", message.author.id)); + break; + case "introhand": + if (client.user.username == "Dairo, High Prophet of The Hand") + sendMessage(message.channel.id, dialog.getDialog("introHand", message.author.id)); + break; + case "introend": + if (client.user.username == "A.D.A.M.") + sendMessage(message.channel.id, dialog.getDialog("introEnd", message.author.id)); + break; + case "admingetroleids": + //for (var i in discordBot.servers[serverID].roles) { + // console.log(discordBot.servers[serverID].roles[i]); // issues + //} + console.log("!adminGetRoleIDs is Disabled for now"); + break; + case "obsidian": + if (client.user.username == "Kamala, Obsidian Vice President") + changeFaction(process.env.GROUP_A_ROLE, message.channel.id, message.author.id, + message.member, process.env.GROUP_A_BOT_ID); + break; + case "genesis": + if (client.user.username == "Captain Montgomery") + changeFaction(process.env.GROUP_B_ROLE, message.channel.id, message.author.id, + message.member, process.env.GROUP_B_BOT_ID); + break; + case "hand": + if (client.user.username == "Dairo, High Prophet of The Hand") + changeFaction(process.env.GROUP_C_ROLE, message.channel.id, message.author.id, + message.member, process.env.GROUP_C_BOT_ID); + break; + case "beginners": + if (!isAdmin()) break; + if (client.user.username == "A.D.A.M.") { + + var timedEvents = `Mori will revive all weakened travelers every day, and may heal you for a cost, if Mori can find the right things to do so.`; + + var commandsText = `These commands can be done in <#${process.env.GROUP_B_BOT_ID}>, <#${process.env.GROUP_C_BOT_ID}>, or <#${process.env.GROUP_A_BOT_ID}>.\n` + + `**!checkin** - For your help around the city, you can use this to be given a sum of **<:crystals:460974340247257089> Crystals** daily from your faction leader.\n` + + `**!stats** - Your faction leader can check your stats, and your total crystals, materials, etc., with this command.\n`; + + const embed = new Discord.RichEmbed() + .setAuthor( "SANCTUM Beginner's Guide", client.user.avatarURL) + .setColor("#f1c40f") + .setTitle("Welcome to SANCTUM!") + .setDescription("Welcome to SANCTUM, traveler. I hope you will understand the basics on how to survive after the Genesis ship's crash.") + .addField("Basic Commands", commandsText) + .addField("Mori", timedEvents) + + message.channel.send({embed}); + } + break; + case "questboard": + if (!isAdmin(message.author.id)) break; + if (client.user.username != "A.D.A.M.") break; + + var quests = { + "quests": [ + { + "title": "The Lost Pendant", + "id": "thelostpendant", + "description": "Lorem ipsum, or some placeholder text. I wish I knew what to put here, I'm no writer! I need to put more text here in order for the inlines to work more nicely. Not like it matters on mobile, however.", + "objective": "Go to <#${process.env.OUTSKIRTS_CHANNEL_ID}> and **!scavenge** in hopes to find the pendant.", + "userID": process.env.LIBRARIAN_ID, + "color": "keepersOfTheCityColor", + "recommendedLVL": 1, + "questLength": "Short", + "rewards": [ + { + "name": "Crystals", + "emote": "<:crystals:460974340247257089>", + "amount": 10 + }, + { + "name": "Electronics", + "emote": "<:melectronics:462682568911749120>", + "amount": 2 + }, + { + "name": "Gem", + "emote": "<:mgem:462450060718768148>", + "amount": 2 + } + ] + }, + { + "title": "Looming Ravager Outside", + "id": "loomingravager", + "description": "Hey, I have a problem, ya' see. There's a Ravager outside my tavern! And I've been waiting fo' it to go, but it ain't leaving!! I need your help to get rid of it, it's scaring me and my customers!", + "objective": "Go and help slay a Ravager.", + "userID": process.env.ALEXIS_ID, + "color": "keepersOfTheCityColor", + "recommendedLVL": 1, + "questLength": "Short", + "rewards": [ + { + "name": "Crystals", + "emote": "<:crystals:460974340247257089>", + "amount": 5 + } + ] + } + ] + } + + // Collects all preset colors + const keepersOfTheCityColor = message.guild.roles.find(role => role.name === "Keepers of the City").color; + console.log("COLOR: " + keepersOfTheCityColor); + + // Header & Footer (mobile design choice) for quests + const header = new Discord.RichEmbed() + .setAuthor("Quests", client.user.avatarURL) + .setColor(keepersOfTheCityColor) + .setTitle("The Travelers' Quest Board") + .setDescription("Residents of New Eden can post their help requests here, and whoever fulfils them can earn some rewards.") + .setFooter(`⏰ 7 hrs. before the quests are exchanged for new ones.`) + await message.channel.send({embed: header}); + + // Displays all quests in order + for (let i = 0; i < quests.quests.length; i++) { + const element = quests.quests[i]; + const bot = client.guilds.get(process.env.SANCTUM_ID).members.get(element.userID); + var newColor = element.color; + var newDescription = element.description; + var newObjective = element.objective; + var newReward = ""; + const questLength = `Quest Length: **${element.questLength}**.`; + + // Adds rewards up + element.rewards.forEach(reward => { + newReward += `> **${reward.emote} ${reward.name}** [${reward.amount}x]\n`; + }); + + // Returns internal color if needed + if (element.color === "keepersOfTheCityColor") newColor = keepersOfTheCityColor; + + // Replaces certain strings with internal channel data if needed + // NEED TO FIGURE OUT REGEX EXPRESSIONS FOR MASS REPLACE + newObjective = element.objective.replace("${process.env.OUTSKIRTS_CHANNEL_ID}", `${process.env.OUTSKIRTS_CHANNEL_ID}`); + + const body = new Discord.RichEmbed() + .setAuthor(`${bot.displayName}`, bot.user.avatarURL) + .setColor(newColor) + .setTitle(`📃 ${element.title}`) + .setDescription(newDescription) + .addField("Objective", newObjective) + .addField("Reward", newReward, true) + .addField("Info", `Recommended Level: **<:level:461650552506286093> ${element.recommendedLVL}+**.\n${questLength}`, true) + .setFooter(`React with ❗ to take on the quest, and help ${bot.displayName}.`) + + var bodyMessage = await message.channel.send({embed: body}); + await bodyMessage.react("❗"); + } + + // Specifically for mobile + await message.channel.send({embed: header}); + + break; + case "guild": + if (!isAdmin(message.author.id)) break; + if (client.user.username != "A.D.A.M.") break; + + switch (args[0]) { + case "create": + // Start message + var progressMessage = await message.channel.send(`${message.author} I will setup a safe place in the City, please wait.`); + + // Creates new channel & sets topic + var channelName = message.content.replace("!guild create ", '').trim(); + var newChannel = await message.guild.createChannel(channelName, 'text'); + await newChannel.setParent('496813609201172500'); + newChannel.setTopic(`This is the ${channelName} guild!`); + + // Chooses a role name + const roleName = channelName.replace(/\\/g, ""); + + // Creates role & adds it to author + var newRole = await message.guild.createRole({ + name: roleName, + color: 'DARK_AQUA', + }); + await message.member.addRole(newRole); + + // Sets permissions + await newChannel.overwritePermissions(message.guild.roles.find(role => role.name === '@everyone'), { + 'VIEW_CHANNEL': false + }); + await newChannel.overwritePermissions(message.guild.roles.find(role => role.name === roleName), { + 'VIEW_CHANNEL': true + }); + await newChannel.overwritePermissions(message.guild.roles.find(role => role.name === 'Can View All Guilds'), { + 'VIEW_CHANNEL': true + }); + + // Progress message + await progressMessage.edit(`${message.author} I have finished setting up your new ${newRole} guild, in the City. Put it into good use, traveler.`); + + break; + case "tag": + // Appends guild name to user (Grabs nickname by removing anything in []s) + // NOTE: CODE WORKS, JUST DOESN'T LOOK RIGHT + /* + const userNickname = message.member.displayName.replace(/\[(.*?)\]+/g, '').trim(); + message.member.setNickname(`[${roleName}] ${userNickname}`) + .catch((e) => { + console.log("ERROR HAPPENED I THINK") + console.log(e); + + // Catches >32 nickname + if (e.code == 50035) { + message.channel.send(`${message.author} I couldn't change your username in order to put your guild tag, as it would be too long.`) + } + }); + */ + break; + } + + break; + + } + + if (!checkValidDisplay(message.member, message.channel.id, true) && client.user.username != "A.D.A.M.") return; + + switch (command) { + case "checkin": + if (client.user.username == "A.D.A.M.") break; + var checkinAmount = calcRandom.random(4, 9); + var checkInResponse = String(dataRequest.sendServerData("checkin", checkinAmount, message.author.id)); + if (checkInResponse == "1") { + sendMessage(message.channel.id, dialog.getDialog("checkin", message.author.id, checkinAmount)); + addXP(message.author.id, 1); + } else { + sendMessage(message.channel.id, dialog.getDialog("checkinLocked", message.author.id, checkInResponse)); + } + break; + case "give": // Could revamp to make player ID and amount interchangable + if (client.user.username == "A.D.A.M.") break; + var giveAmount = Math.floor(args[0]); + if (message.mentions.members.size > 0) { + console.log(message.mentions.members); + var giveToID = message.mentions.members.first().id; + console.log("GIVE: " + giveToID + " | message.author.id: " + message.author.id) + if (giveToID === message.author.id) { + sendMessage(message.channel.id, dialog.getDialog("giveInvalidUserSelf", message.author.id)); + return; + } + var amountInAccount = dataRequest.loadServerData("account",message.author.id); + if (giveAmount > 0) { + if (amountInAccount >= giveAmount) { + if (dataRequest.sendServerData("transfer",giveToID,message.author.id,giveAmount) == 1) { + sendMessage(message.channel.id, dialog.getDialog("giveSuccessful", message.author.id, giveToID, giveAmount)); + } else { + sendMessage(message.channel.id, dialog.getDialog("giveFailed", message.author.id)); + } + } else { + sendMessage(message.channel.id, dialog.getDialog("giveNotEnoughInAccount", message.author.id)); + } + } else { + sendMessage(message.channel.id, dialog.getDialog("giveNotAboveZero", message.author.id)); + } + } else { + sendMessage(message.channel.id, dialog.getDialog("giveInvalidUser", message.author.id)); + } + break; + case "lore": + if (client.user.username == "A.D.A.M.") break; + sendMessage(message.channel.id, dialog.getDialog("lore", args[0])); + break; + case "stats": + if (client.user.username == "A.D.A.M.") break; + getLevelUp(message.author.id); + + var attacker = String(dataRequest.loadServerData("userStats",message.author.id)); + var scavengeResponse = String(dataRequest.loadServerData("artifactsGet",message.author.id)); + var attackerStrength = parseFloat(attacker.split(",")[0]); + var attackerSpeed = parseFloat(attacker.split(",")[1]); + var attackerStamina = parseFloat(attacker.split(",")[2]); + var attackerHealth = parseFloat(attacker.split(",")[3]); + var attackerMaxStamina = parseFloat(attacker.split(",")[4]); + var attackerMaxHealth = parseFloat(attacker.split(",")[5]); + var attackerWallet = parseFloat(attacker.split(",")[6]); + var attackerXP = parseFloat(attacker.split(",")[7]); + var attackerLVL = Math.floor(parseFloat(attacker.split(",")[8])); + var attackerLvlPercent = parseFloat(attacker.split(",")[9]); + var attackerStatPoints = parseFloat(attacker.split(",")[10]); + var attackerChests = parseFloat(attacker.split(",")[11]); + + var items = scavengeResponse.split(","); + var response = items[0]; + var ultrarare = parseFloat(items[1]); + var rare = parseFloat(items[2]); + var uncommon = parseFloat(items[3]); + var common = parseFloat(items [4]); + var scrap = parseFloat(items[5]); + var totalQuantity = ultrarare + rare + uncommon + common + scrap; + var userStats = ""; + + if (attackerLVL >= 30) { + userStats += "<@" + message.author.id + "> <:level:461650552506286093> **" + attackerLVL + "** (MAX)\t\t" + "<:cannister:462046687058198530> **" + attackerStatPoints + "**\t\t" + "<:cyphercrate:464135029036154950> **" + attackerChests + "** (" + attackerLvlPercent + "%)"; + } else { + userStats += "<@" + message.author.id + "> <:level:461650552506286093> **" + attackerLVL + "** (" + attackerLvlPercent + "%)\t\t\t" + "<:cannister:462046687058198530> **" + attackerStatPoints + "**\t\t\t<:cyphercrate:464135029036154950> **" + attackerChests + "**"; + } + userStats += "```STR: " + attackerStrength + " | SPD: " + attackerSpeed + " | STAM: " + attackerStamina + "/" + attackerMaxStamina + " | HP: " + attackerHealth + "/" + attackerMaxHealth + "```"; + userStats += "<:crystals:460974340247257089> **" + attackerWallet + "**\t\t"; + if (response == "success") { + if (totalQuantity > 0) { + //userStats += "\n"; + if (scrap > 0) { userStats += "<:scrap:463436564379336715> **" + scrap + "**\t\t"; } + if (common > 0) { userStats += "<:mcloth:462682568483930123> **" + common + "**\t\t"; } + if (uncommon > 0) { userStats += "<:mmetal:462682568920137728> **" + uncommon + "**\t\t"; } + if (rare > 0) { userStats += "<:melectronics:462682568911749120> **" + rare + "**\t\t"; } + if (ultrarare > 0) {userStats += "<:mgem:462450060718768148> **" + ultrarare + "**\n\n"; } + } else {console.log("failure2");} + } else {console.log("failure");} + + sendMessage(message.channel.id, userStats); + break; + case "estats": + // Sees if the user is supposed to level up + getLevelUp(message.author.id); + + // Grabs all parameters from server + var attacker = String(dataRequest.loadServerData("userStats",message.author.id)); + var scavengeResponse = String(dataRequest.loadServerData("artifactsGet",message.author.id)); + var attackerStrength = parseFloat(attacker.split(",")[0]); + var attackerSpeed = parseFloat(attacker.split(",")[1]); + var attackerStamina = parseFloat(attacker.split(",")[2]); + var attackerHealth = parseFloat(attacker.split(",")[3]); + var attackerMaxStamina = parseFloat(attacker.split(",")[4]); + var attackerMaxHealth = parseFloat(attacker.split(",")[5]); + var attackerWallet = parseFloat(attacker.split(",")[6]); + var attackerXP = parseFloat(attacker.split(",")[7]); + var attackerLVL = Math.floor(parseFloat(attacker.split(",")[8])); + var attackerLvlPercent = parseFloat(attacker.split(",")[9]); + var attackerStatPoints = parseFloat(attacker.split(",")[10]); + var attackerChests = parseFloat(attacker.split(",")[11]); + + var items = scavengeResponse.split(","); + var response = items[0]; + var ultrarare = parseFloat(items[1]); + var rare = parseFloat(items[2]); + var uncommon = parseFloat(items[3]); + var common = parseFloat(items [4]); + var scrap = parseFloat(items[5]); + var totalQuantity = ultrarare + rare + uncommon + common + scrap; + + // Forms stats into a string + var levelText = `<:level:461650552506286093> **${attackerLVL}**`; + var levelProgress = `(${attackerLvlPercent}%)`; + var crystalText = `<:crystals:460974340247257089> **${attackerWallet}**`; + var cannisterText = `<:cannister:462046687058198530> **${attackerStatPoints}**`; + var cypherCrateText = `<:cyphercrate:464135029036154950> **${attackerChests}**`; + var userStats = "```" + `STR: ${attackerStrength} | SPD: ${attackerSpeed} | STAM: ${attackerStamina}/${attackerMaxStamina} | HP: ${attackerHealth}/${attackerMaxHealth}` + "```"; + var materialsText = ``; + + // Materials + if (response == "success") { + if (totalQuantity > 0) { + if (scrap > 0) { materialsText += `<:scrap:463436564379336715> **${scrap}**`; } + if (common > 0) { materialsText += ` | <:mcloth:462682568483930123> **${common}**`; } + if (uncommon > 0) { materialsText += ` | <:mmetal:462682568920137728> **${uncommon}**`; } + if (rare > 0) { materialsText += ` | <:melectronics:462682568911749120> **${rare}**`; } + if (ultrarare > 0) { materialsText += ` | <:mgem:462450060718768148> **${ultrarare}**`; } + } else {console.log("failure2");} + } else {console.log("failure");} + + // Says level is maxed out if it is LVL 30+ + if (attackerLVL >= 30) { + levelProgress = `(MAX)`; + cypherCrateText += ` (${attackerLvlPercent}%)`; + } + + // Creates embed & sends it + const embed = new Discord.RichEmbed() + .setAuthor(`${message.member.displayName}`, message.author.avatarURL) + .setColor(message.member.displayColor) + .setDescription(`${levelText} ${levelProgress} | ${crystalText} | ${cannisterText} | ${cypherCrateText}`) + .addField("Stats", userStats) + .addField("Materials", `${materialsText}`) + .setFooter("Commands: !inventory | !checkin | !upgrade | !heal | !quests") + + message.channel.send(embed); + break; + case "inventory": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num)) { + return sendInventory(message, num); + } + } else { + return sendInventory(message); + } + break; + case "inv": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num)) { + return sendInventory(message, num); + } + } else { + return sendInventory(message); + } + break; + case "item": + return appraiseItem(message); + + case "help": + if (client.user.username == "A.D.A.M.") break; + if (!args[0]) { + sendMessage(message.channel.id, dialog.getDialog("help", message.author.id)); + } else if (message.mentions.members.first() !== undefined) { + // MORI + if (message.mentions.members.first().id == process.env.MORI_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpMori", message.author.id)); + } + // RAVAGER + if (message.mentions.members.first().id == process.env.RAVAGER_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpRavager", message.author.id)); + + } + // MOSIAH + if (message.mentions.members.first().id == process.env.MOSIAH_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpMosiah", message.author.id)); + + } + // GRAZE + if (message.mentions.members.first().id == process.env.GRAZE_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpGraze", message.author.id)); + + } + // SONYA + /* + if (message.mentions.members.first().id == process.env.SONYA_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpSonya", message.author.id)); + } + */ + // REY + if (message.mentions.members.first().id == process.env.REY_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpRey", message.author.id)); + } + // ALEXIS + if (message.mentions.members.first().id == process.env.ALEXIS_ID) { + sendMessage(message.channel.id, dialog.getDialog("helpAlexis", message.author.id)); + } + //sendMessage(message.channel.id, ":frowning:" + message.mentions.members.first().id); + } + break; + } + +}); + +client.on('error', console.error); + +// Gets footer commands for botspam channel commands +function getFooterCommands(currentCommand) { + var textFooter = ""; + const filtered = commandArray.filter(word => word !== currentCommand); + //console.log(filtered); + + filtered.forEach(element => { + var appendedText = " | "; + if (textFooter.length !== 0) textFooter += appendedText; + textFooter += element; + }); + //console.log(textFooter); + return textFooter; +} + +// Adds item to inventory +function addItem(userID, item, amount) { + // If item exists in inventory + console.log("[Add Item] " + amount); + var i = userItems.findIndex(i => i.name === item.name); + console.log("[Item Amount Item Exists] i Equals " + i); + + // If there is an item that exists in inventory + if (i !== -1) { + console.log("[Item Amount Start] " + userItems[i].amount); + userItems[i].amount += amount; // Increments amount value + console.log("[Item Amount Finish] " + userItems[i].amount); + // Disallows adding objects such as crystals + } else { + console.log("[Item Amount Wait] Created item for the first time."); + var clonedItem = JSON.parse(JSON.stringify(item)); // Clones item in order to not actually increment the rooms.js item JSON data + userItems.push(clonedItem); + addItem(userID, item, amount - 1); + } +} + +// Sends inventory into chat +async function sendInventory(message, pageNum, newMessage) { + var items = ""; + var groupedArr = createGroupedArray(userItems, 5); + + // Sets a default page num, or makes it human readable + if (pageNum === undefined) pageNum = 1; else { + if (pageNum < 1) pageNum = 1; + if (groupedArr.length < pageNum) pageNum = groupedArr.length; + } + + // Checks if page number is valid + if (pageNum > groupedArr.length) { + // If it's longer than actual length, but isn't just an empty inventory + if (!groupedArr.length === 0) return; + } + + //console.log(pageNum); + + // Grabs item in loop, parses it, then adds it to "items" variable + if (groupedArr[pageNum - 1]) { + for (let index = 0; index < groupedArr[pageNum - 1].length; index++) { + // Grabs an item, from a page index + const element = groupedArr[pageNum - 1][index]; + + // Makes if there is an emote, it'll add an extra space + var emoteText = ""; + if (element.emote) emoteText = element.emote + " "; + + // Adds it in + items += `> ${emoteText}**${element.name}** [${element.amount}x] ${element.info}\n`; + } + } + + // No items message to fill field + if (items === "") items = "There are no items in the party's inventory."; + + // To make the message of "Page 1/0" with no items in !inventory not happen + var moddedLength = groupedArr.length; + if (moddedLength < 1) moddedLength = 1; + + const footer = getFooterCommands("!inventory"); + + // Creates embed & sends it + const inv = new Discord.RichEmbed() + .setAuthor(`${message.member.displayName}`, message.author.avatarURL) + .setColor(message.member.displayColor) + .setDescription("I can appraise your items with `!item [ITEM NAME]`, traveler.") + .addField(`Items (Page ${pageNum}/${moddedLength})`, items) + .setFooter(`Commands: ${footer}`) + + var invMessage; + if (!newMessage) + invMessage = await message.channel.send({embed: inv}); + else { + invMessage = newMessage; + await invMessage.edit({embed: inv}); + } + + // Collector for emotes + const emotes = ['⬅', '❌', '➡']; + const collector = invMessage.createReactionCollector( + (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id , { time: 15 * 1000 }); + var react = ""; + var endedOnReact; + + // Sends reactions + if (!newMessage) { + for (let i = 0; i < emotes.length; i++) { + const element = emotes[i]; + console.log(element); + await invMessage.react(element); + } + } + + // Collects reactions + collector.on("collect", async reaction => { + var user = reaction.users.last(); + react = reaction.emoji.name; + if (react !== '❌') { reaction.remove(user); } + endedOnReact = true; + collector.stop(); + }); + + // Clears reactions + collector.once("end", async collecter => { + console.log("[Reaction Options] Ended collector, clearing emotes and sending timing out message if needed."); + + if (!endedOnReact) { + invMessage.clearReactions(); + return message.channel.send(":x: **Timed Out**: The emote reaction request timed out after 15 seconds."); + } + if (react === '❌') { + invMessage.clearReactions(); + return invMessage.edit(invMessage.content); + } + + var pageNumModifier = 0; + if (react === emotes[0]) pageNumModifier -= 1; + if (react === emotes[2]) pageNumModifier += 1; + console.log(pageNum + " | " + pageNumModifier); + sendInventory(message, pageNum + pageNumModifier, invMessage); + }); +} + +// Appraise an item +async function appraiseItem(message) { + const itemName = message.content.replace("!item", "").trim().toLowerCase(); + console.log("[Item Appraisal] " + `<< ${itemName} >>`); + + // Show if no parameter is given + if (itemName === "" || !itemName) { + message.channel.send(`:x: ${message.author} Please tell me the item name from your inventory, or I won't know which item you want me to look at.`); + return; + } + + var i = userItems.findIndex(i => i.name.toLowerCase() === itemName); + console.log("[Item Amount Item Exists] i Equals " + i); + + // If there is an item that exists in inventory + if (i !== -1) { + console.log(`[Item Appraisal] Found item in inventory!`); + const embed = new Discord.RichEmbed() + .setAuthor(`${message.member.displayName}`, message.author.avatarURL) + .setColor(message.member.displayColor) + .setTitle(userItems[i].name) + .setDescription(userItems[i].info) + + if (userItems[i].type.subtype) + embed.addField("Type", `${userItems[i].type.type}\n> ${userItems[i].type.subtype}`, true) + else + embed.addField("Type", `${userItems[i].type.type}`, true) + + if (userItems[i].type.stats) { + console.log(JSON.stringify(userItems[i].type.stats, null, 4)) + var itemStats = "There are no stats avaliable."; + var resetItemStats = false; + userItems[i].type.stats.forEach(element => { + if (element) { + if (!resetItemStats) { + resetItemStats = true; + itemStats = ""; + } + const types = [ + "attack", + "defence", + "speed", + "healing" + ]; + + types.forEach(type => { + if (element[type]) { + switch (type) { + case "attack": + itemStats += `ATK: ${element.attack}\n`; + break; + case "defence": + itemStats += `DEF: ${element.defence}\n`; + break; + case "speed": + itemStats += `SPD: ${element.speed}\n`; + break; + case "healing": + itemStats += `Healing: ${element.healing} HP\n`; + break; + } + } + }); + } + }); + } + + embed.addField("Stats", `${itemStats}`, true); + + message.channel.send(embed); + + // Disallows adding objects such as crystals + } else { + console.log("[Item Appraisal] Couldn't find item in inventory."); + message.channel.send(`:x: ${message.author} I'm unable to find "${itemName}" in your inventory.`); + } +} + +// Creates an array that creates multiple different arrays inside of that array -> [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +// http://www.frontcoded.com/splitting-javascript-array-into-chunks.html +var createGroupedArray = function(arr, chunkSize) { + var groups = [], i; + for (i = 0; i < arr.length; i += chunkSize) { + groups.push(arr.slice(i, i + chunkSize)); + } + return groups; +} + +// See if the bot should display its message +function checkValidDisplay(member, channelID, checkRole) { + if (client.user.username == "Kamala, Obsidian Vice President" && channelID === process.env.GROUP_A_BOT_ID) { + if (checkRole) { if (member.roles.has(process.env.GROUP_A_ROLE)) return true; } else true; + } + else if (client.user.username == "Captain Montgomery" && channelID === process.env.GROUP_B_BOT_ID) { + if (checkRole) { if (member.roles.has(process.env.GROUP_B_ROLE)) return true; } else true; + } + else if (client.user.username == "Dairo, High Prophet of The Hand" && channelID === process.env.GROUP_C_BOT_ID) { + if (checkRole) { if (member.roles.has(process.env.GROUP_C_ROLE)) return true; } else true; + } + else if (client.user.username == "Ghost 5.0.1") { + // JSON + const rooms = require('../TextAdv/rooms.json'); + var roomExists = false; + + // Loops for all rooms + rooms.rooms.forEach(element => { + if (channelID === rooms[element].channel) roomExists = true; + }); + + if (!roomExists) { + if (channelID === process.env.TEST_CHANNEL_ID) return true; + } else return true; + + } + + return false; +} + +// Gets if user has an Overseers rank +function isAdmin(userID) { + var guild = client.guilds.get(process.env.SANCTUM_ID); + return guild.members.get(userID).roles.find(role => role.name === "Overseers"); +} + +// Change Faction +async function changeFaction(factionID, channelID, userID, member, botChannelID) { + if (member.roles.has(factionID)) { + if (factionID === process.env.GROUP_A_ROLE) + sendMessage(channelID, dialog.getDialog("orderAlreadyJoined", userID)); + else if (factionID === process.env.GROUP_B_ROLE) + sendMessage(channelID, dialog.getDialog("anarchyAlreadyJoined", userID)); + else if (factionID === process.env.GROUP_C_ROLE) + sendMessage(channelID, dialog.getDialog("religionAlreadyJoined", userID)); + } else { + if (dataRequest.loadServerData("hasConvertedToday", userID) == 1) { + sendMessage(channelID, dialog.getDialog("alreadyConvertedToday", userID)); + } else { + // Creates new user + var response = String(dataRequest.sendServerData("newUser", "New user.", userID)); + + //var response = "createdUser" + // Obsidian Tech. + if (factionID === process.env.GROUP_A_ROLE) { + await member.removeRole(process.env.GROUP_B_ROLE); + await member.removeRole(process.env.GROUP_C_ROLE); + await member.addRole(process.env.GROUP_A_ROLE); + + dataRequest.sendServerData("conversion", "Converted to The Order.", userID); + + if (response == "createdUser") { + client.users.get(userID).send(dialog.getDialog("newUserPM", userID, getFactionName(factionID))); + sendMessage(botChannelID, dialog.getDialog("newUserWelcome", userID, `<#${getFactionName(factionID)}>`)); + } else { + sendMessage(channelID, dialog.getDialog("orderJoin", userID)); + } + + // Genesis Command + } else if (factionID === process.env.GROUP_B_ROLE) { + await member.removeRole(process.env.GROUP_C_ROLE); + await member.removeRole(process.env.GROUP_A_ROLE); + await member.addRole(process.env.GROUP_B_ROLE); + + dataRequest.sendServerData("conversion", "Converted to the Anarchy.", userID); + + if (response == "createdUser") { + client.users.get(userID).send(dialog.getDialog("newUserPM", userID, getFactionName(factionID))); + sendMessage(botChannelID, dialog.getDialog("newUserWelcome", userID, `<#${getFactionName(factionID)}>`)); + } else { + sendMessage(channelID, dialog.getDialog("anarchyJoin", userID)); + } + + // The Hand + } else if (factionID === process.env.GROUP_C_ROLE) { + await member.removeRole(process.env.GROUP_A_ROLE); + await member.removeRole(process.env.GROUP_B_ROLE); + await member.addRole(process.env.GROUP_C_ROLE); + + dataRequest.sendServerData("conversion", "Converted to The Religion.", userID); + + if (response == "createdUser") { + client.users.get(userID).send(dialog.getDialog("newUserPM", userID, getFactionName(factionID))); + sendMessage(botChannelID, dialog.getDialog("newUserWelcome", userID, `<#${getFactionName(factionID)}>`)); + } else { + sendMessage(channelID, dialog.getDialog("religionJoin", userID)); + } + } + } + } +} + +function addXP(userID,amount) { + var response = String(dataRequest.sendServerData("addXP", amount, userID)); +} + +function getLevelUp(userID) { + const server = client.guilds.get(process.env.SANCTUM_ID); + const member = server.members.get(userID); + if (client.user.username == "Kamala, Obsidian Vice President" && !member.roles.has(process.env.GROUP_A_ROLE)) return; + if (client.user.username == "Captain Montgomery" && !member.roles.has(process.env.GROUP_B_ROLE)) return; + if (client.user.username == "Dairo, High Prophet of The Hand" && !member.roles.has(process.env.GROUP_C_ROLE)) return; + + //const user = server.members.get(userID); + var response = String(dataRequest.sendServerData("getLevelUp", 0, userID)); + var responseMessage = String(response.split(",")[0]); + var lvl = Math.floor(parseFloat(response.split(",")[1])); + var statPoints = parseFloat(response.split(",")[2]); + + var attacker = String(dataRequest.loadServerData("userStats", userID)); + var chests = parseFloat(attacker.split(",")[11]); + + console.log(response.split(",")); + + majorLevelUp(lvl, server, userID); + + if (responseMessage == "levelup") { + //if (true) { + console.log("Chests: " + chests) + checkinLevelUp(userID, lvl, statPoints, chests); + } +} + +async function majorLevelUp(level, server, userID) { + const user = server.members.get(userID); + + var newChannel = ""; + + var levels = [ + // Role, Level + [server.roles.find(role => role.name === "LVL 1+"), 1, process.env.CRYSTAL_SHORES_CHANNEL_ID], + [server.roles.find(role => role.name === "LVL 15+"), 15, process.env.SEA_OF_FOG_CHANNEL_ID], + [server.roles.find(role => role.name === "LVL 30+"), 30, process.env.DEADLANDS_CHANNEL_ID] + ] + + // Shrinking level + if (level < 30) { + level = 15; + } else if (level < 15) { + level = 1; + } + + // Rank Level Up + var levelRole = server.roles.find(role => role.name === `LVL ${level}+`); + if (levelRole) { + var memberRole = user.roles.has(levelRole.id); + if (!memberRole) { + user.addRole(levelRole).catch(console.error); + for (let i = 0; i < levels.length; i++) { + const element = levels[i]; + if (element[1] !== level) { + await user.removeRole(element[0]); + } + } + if (user !== undefined) {// && newChannel !== undefined) { + var levelMarks = [1, 15, 30]; + + for (let i = 0; i < levelMarks.length; i++) { + const element = levelMarks[i]; + // Gets channel of array + newChannel = client.channels.get(levels[levels.findIndex(level => level[1] === element)][2]); + if (level === element) + newChannel.send(dialog.getDialog("level" + level, user, newChannel)); + } + } + } + } +} + +// Gets the user's role by member +function getFactionChannel(member) { + var playerChannel; + var isGroupA = member.roles.has(process.env.GROUP_A_ROLE); + var isGroupB = member.roles.has(process.env.GROUP_B_ROLE); + var isGroupC = member.roles.has(process.env.GROUP_C_ROLE); + //console.log(member.roles); + //console.log("isGroup: " + isGroupA + " " + isGroupB + " " + isGroupC); + if (isGroupA) playerChannel = process.env.GROUP_A_BOT_ID; + else if (isGroupB) playerChannel = process.env.GROUP_B_BOT_ID; + else if (isGroupC) playerChannel = process.env.GROUP_C_BOT_ID; + + return playerChannel; +} + +// Gets faction names by ID +function getFactionName(factionID) { + if (factionID === process.env.GROUP_A_ROLE) { + return "Obsidian Technologies"; + } + if (factionID === process.env.GROUP_B_ROLE) { + return "Genesis Command"; + } + if (factionID === process.env.GROUP_C_ROLE) { + return "The Hand"; + } +} + +function checkinLevelUp(userID, lvl, statPoints, chests) { + const guild = client.guilds.get(process.env.SANCTUM_ID); + if (lvl === 30) { + //Post level cap level up! + sendMessage(userID, getFactionChannel(guild.members.get(userID)), dialog.getDialog("levelUpLevelCap", userID, lvl, chests)); + } else { + //regular level up + sendMessage(userID, getFactionChannel(guild.members.get(userID)), dialog.getDialog("levelUp", userID, lvl, statPoints)); + } + //sendMessage(testChannelID, dialog.getDialog("levelUp", userID, lvl, statPoints)); +} + +// Updates stamina (1) and health by 1% every 2 min. +cron.schedule('*/2 * * * *', function() { + if (client.user.username === "A.D.A.M.") { + console.log('Updating STAMINA every 2 min.'); + dataRequest.sendServerData("updateStamina", 0); + }; +}); + +// Send message handler +function sendMessage(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message === undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message; + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); +} + +// Log our bot in +client.login(npcSettings.token); \ No newline at end of file diff --git a/ADAM_Kamala/dialog.js b/ADAM_Kamala/dialog.js new file mode 100644 index 0000000..79cbba5 --- /dev/null +++ b/ADAM_Kamala/dialog.js @@ -0,0 +1,298 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + getDialog: function(dialogTag, data = "", data2 = "", data3 = "") { + switch(dialogTag) { + case "checkin": + return "<@" + data + ">" + " your presence has been noted. I've added " + data2 + " crystals to your account."; + + case "checkinLocked": + return ":x: <@" + data + ">" + " you already checked in with me " + data2 + ". You can check in again tomorrow."; + + case "alreadyConvertedToday": + return ":x: <@" + data + ">" + " as anxious as you may be, please don't attempt to change factions so quickly. You can only change once every 30 days."; + + case "depositSuccessful": + //codexLogEvent(data + " deposited " + data2 + " crystals."); + return "<@" + data + ">" + " your deposit of " + data2 + " crystals has been successful. Good luck."; + + case "depositFailed": + return ":x: <@" + data + ">" + " I can't make the deposit at the moment. I apologize for the inconvenience."; + + case "giveSuccessful": + //codexLogEvent(data + " gave " + data2 + " " + data3 + " crystals."); + return "<@" + data + ">" + " I've transferred " + data3 + " crystals to <@" + data2 + "> as per your request."; + + case "giveFailed": + return ":x: <@" + data + ">" + " I can't make that transfer at the moment. I apologize for the inconvenience."; + + case "giveNotEnoughInAccount": + return ":x: <@" + data + ">" + " You don't have that many crystals in your account. As such, I can't complete the transfer."; + + case "giveNotAboveZero": + return ":x: <@" + data + ">" + " In order for me to complete the transfer I need an amount above zero."; + + case "giveInvalidUser": + return ":x: <@" + data + ">" + " I can't find that traveler. Sorry."; + + case "giveInvalidUserSelf": + return ":x: <@" + data + ">" + " You can\'t send crystals to yourself. Sorry."; + + case "levelUp": + var dialogOptions = [ + 'I appreciate all of your help.', + 'Thank you for doing so much for the city.', + 'The other travelers are very grateful for your help.', + 'Your assistance is very much appreciated.', + 'Together we\'ve taken out most of the threats to city.', + 'The citizens of The Sanctum are most grateful.', + 'I cannot thank you enough for your help defending the city.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + var wordToUse = "it"; + if (data3 > 1) { var wordToUse = "them";} + return "You just hit **level " + data2 + "**! " + dialogOptions[randomNumber] + " I\'ve added a <:cannister:462046687058198530> **Nanotech Cannister** to your inventory so that you can upgrade your skills. You now have **" + data3 + "** total (you can check this any time with !stats). Use " + wordToUse + " wisely."; + + case "levelUpLevelCap": + var dialogOptions = [ + 'I appreciate all of your help.', + 'Thank you for doing so much for the city.', + 'The other travelers are very grateful for your help.', + 'Your assistance is very much appreciated.', + 'Together, we\'ve taken out most of the threats to city.', + 'The citizens of The Sanctum are most grateful.', + 'I cannot thank you enough for your help defending the city.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + return "You\'re currently at **level " + data2 + "** which is the current level cap! " + dialogOptions[randomNumber] + " I\'ve added a <:cyphercrate:464135029036154950> **Cypher Crate** to your inventory. Hopefully it contains something useful for you on your journey. You now have **" + data3 + "** total (you can check this any time with !stats). Good luck. "; + + case "help": + var temp = "*This world is strange and mysterious. And while I cannot help you on your journey or join your faction, I am here to help travelers to the best of my ability.* \n\nHere is what I can do for you:"; + temp += "\n\n"; + temp += "!checkin\n```Once per day, you may come see me for a daily sum in exchange for your help around the city.```"; + temp += "\n"; + temp += "!stats\n```I can share all of your stats and your crystal count information.```"; + temp += "\n"; + temp += "!give [AMOUNT] [@USER]\n```I can transfer some of your crystals to another traveler's account. Just make sure you have enough.```"; + temp += "\n"; + temp += "!help [@NAME]\n```I can tell you a little bit about some of the other people with us here on New Eden.```"; + temp += "\n"; + temp += "I hope this helps you on your journey, traveler."; + return temp; + + case "helpMori": + var temp = "*Mori is our resident head of the medbay. He can tend to your wounds and get you back on your feet. Here's what he can do:*"; + temp += "\n\n"; + temp += "!heal\n```Shows you Mori\'s available procedures for healing.```"; + temp += "\n"; + temp += "!heal [ITEM]\n```Purchases a procedure directly from him, and with his nanotech, takes effect immediately.```"; + return temp; + + case "helpGraze": + var temp = "*Graze is our loveable augmentation expert. He can help you upgrade your skills and boost your abilities. Here's what he can do:*"; + temp += "\n\n"; + temp += "!upgrade\n```Shows you the available upgrades that Graze can provide with your Nanotech Cannisters.```"; + temp += "\n"; + temp += "!upgrade [STAT]\n```Upgrades this specific stat permanently.```"; + return temp; + + case "helpMosiah": + var temp = `*Mosiah was exiled from our great city for many counts of misconduct, but it\'s been said he\'s been seen at <#${process.env.TAVERN_CHANNEL_ID}>. I recommend you not deal with him at all, but should you need to, here\'s what he can do:*`; + temp += "\n\n"; + temp += "!wager [AMOUNT]\n```Wagers your crystals in a primative coin flip bet. Winner takes all.```"; + return temp; + + case "helpRavager": + var temp = `*The Ravagers have been hunting us since crashing here on New Eden. They roam this planet and will attack travelers on sight. But you can defend yourself:*`; + temp += "\n\n"; + temp += "!attack\n```Sends your weapon towards an active Ravager. If you win the fight, you can loot their corpse for crystals. But be careful: they bite back.```"; + temp += "\n"; + temp += "!details\n```Shows you the details of the last Ravager fight to take place as well as the crystal distribution.```"; + return temp; + + case "helpSonya": + var temp = "*Professor Sonya is our resident archeologist, and she is fascinated by this world. Scavenge for some artifacts in the outskirts of the city, and she will apy you handsomely.*"; + temp += "\n\n"; + temp += "!scavenge\n```In #🌘the-outskirts, this allows you to look for rare artifacts for the professor.```"; + temp += "\n"; + temp += "!artifacts\n```Shows you the current artifacts that you have in your inventory.```"; + temp += "\n"; + temp += "!artifacts sell\n```Shows you the current prices that the professor is willing to pay for any artifacts that you may find.```"; + temp += "\n"; + temp += "!artifacts sell [TYPE]\n```Sells all of the artifacts that you have of that type to the professor, at current prices.```"; + return temp; + + case "helpRey": + var temp = "*Rey is a master of finding things that we need around the city. Resources are scarce, so anything you can help her find in <#462382076927148054> would be most helpful.*"; + temp += "\n\n"; + temp += "!scavenge\n```In #🌘the-outskirts, this allows you to look for materials and resources with Rey.```"; + temp += "\n"; + temp += "!materials\n```Shows you the current materials that you have in your inventory.```"; + return temp; + + case "helpAlexis": + var temp = "*Alexis is our top-of-the-line chemist who uses her talents to reward travelers with a nice and relaxing space. She\'d be happy to have or provide you with some company.*"; + temp += "\n\n"; + temp += "!buydrink\n```In #🍺travelers-watch, this allows you to buy a drink and relax.```"; + temp += "\n"; + temp += "!buydrink [@NAME]\n```In #🍺travelers-watch, you can buy a drink for a friend.```"; + temp += "\n"; + temp += "!tip [AMOUNT]\n```In #🍺travelers-watch, you can tip her for her great service. She might just give you a tip back.```"; + return temp; + + //Status commands + case "accountCheck": + return "<@" + data + ">" + " you currently have " + data2 + " crystals in your account."; + + case "bankCheck": + return "Currently, " + data + " has " + data2 + " crystals total in their bank."; + + case "victors": + return "Currently, " + data + " controls the fate of the codex."; + + case "noVictors": + return "The fate of the codex is still undetermined."; + + // Obsidian Technologies (Former Order) + case "orderAlreadyJoined": + return ":x: <@" + data + ">" + " The Obsidian Technologies already has your allegiance. There's no need to request a change."; + case "orderJoin": + //codexLogEvent(data + " joined Genesis Command."); + return "<@" + data + ">" + " you have joined the Obsidian Technologies. May peace reign upon your cause."; + + // Genesis Command (Former Anarchy) + case "anarchyAlreadyJoined": + return ":x: <@" + data + ">" + " The Genesis Command has already begun their chaos with you by their side. There's no need to request a change."; + case "anarchyJoin": + //codexLogEvent(data + " joined Obsidian Technologies."); + return "<@" + data + ">" + " you have joined the Genesis Command. May chaos come to those who oppose you."; + + // The Hand (Former Religion) + case "religionAlreadyJoined": + return ":x: <@" + data + ">" + " The Hand is happy to have you in their congregation already. There's no need to request a change."; + case "religionJoin": + //codexLogEvent(data + " joined The Hand."); + return "<@" + data + ">" + " you have joined The Hand. May the gods look favorably upon you."; + + //Onboarding + case "newUserWelcome": + messageToSend = "<@" + data + ">" + " welcome to " + data2 + ". If you need me for anything, you can contact me via this secure channel. Just use **!help** for a list of things I can do for you."; + messageToSend += "\n\nAnd don\'t forget to say hello to fellow travelers in "; + if (data2 == "Genesis Command") { + messageToSend += `${process.env.GROUP_B_BOT_ID}.`; + } + if (data2 == "Obsidian Technologies") { + messageToSend += `${process.env.GROUP_A_BOT_ID}.`; + } + if (data2 == "The Hand") { + messageToSend += `${process.env.GROUP_C_BOT_ID}.`; + } + return messageToSend; + case "newUserPM": + var messageToSend = ''; + messageToSend = "_Traveler, welcome to The Sanctum."; + messageToSend += "\n\n"; + + if (data2 == "Genesis Command") { + messageToSend += "I see that you've joined **Genesis Command**. The least reckless of the 3 factions, I can see why you'd pick them. You clearly understand that The Codex is a very powerful book, and should you be victorious, no one will have access to it\'s secrets. "; + } + if (data2 == "Obsidian Technologies") { + messageToSend += "I see that you've joined **Obsidian Technologies**. While they are the most chaotic of the 3 factions, I can see why you'd pick them. The Codex is a very powerful book, and should you be victorious, everyone will have equal access to it\'s secrets. "; + } + if (data2 == "The Hand") { + messageToSend += "I see that you've joined **The Hand**. While they are certainly the most suspicious of the 3 factions, I can see why you'd pick them. The Codex is a very powerful book, and should you be victorious, it is your job to guide the rest of the city using it\'s secrets."; + } + messageToSend += "\n\n"; + messageToSend += "I'll get you patched up and give you access to our team to upgrade skills and meet the others. There's just a few things I need you to take care of around the city:_"; + messageToSend += "\n\n"; + messageToSend += "**!checkin** with me daily.\n```Once a day I'll give you your daily allotment of crystals in exchange for some help around the city.```"; + messageToSend += "\n"; + messageToSend += "**!attack** any Ravagers in #the-deadlands.\n```With the constant bombardment from the enemies of the city, It\'s hard to keep us safe. I need your help```"; + messageToSend += "\n"; + messageToSend += "_Good luck. I'll be around if you need me._"; + return messageToSend; + //Lore + case "intro": + var tempLore = ''; + tempLore = "_Hello weary traveler."; + tempLore += "\n\n"; + tempLore += "My name is A.D.A.M. and I would like to offer you the amenities of The Sanctum. However, I cannot come to your aid until you choose a faction. I am dearly sorry to be so blunt and put trivial human rules in place over your sustenance and safety, but this is the only way to protect The Codex. But the Codex no longer exists since the Librarian destroyed it, so make something up, player."; + tempLore += " Your choices are as follows:_"; + return tempLore; + case "introHand": + var tempLore = "<:religionhand:461582719051104276> **<@&" + process.env.GROUP_C_ROLE + ">** - !hand\n```Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eu aliquet mauris, id congue nisi. Integer et lobortis tellus. Sed bibendum a metus quis volutpat. Mauris faucibus quam at euismod scelerisque. Vestibulum a elit auctor, venenatis augue in, rhoncus nisi. Mauris sagittis sit amet ante eget luctus. Maecenas id malesuada elit. Vestibulum nec ante nec justo venenatis tincidunt.```"; + return tempLore; + case "introGenesis": + var tempLore = "<:order:460991638152413194> **<@&" + process.env.GROUP_B_ROLE + ">** - !genesis\n```Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eu aliquet mauris, id congue nisi. Integer et lobortis tellus. Sed bibendum a metus quis volutpat. Mauris faucibus quam at euismod scelerisque. Vestibulum a elit auctor, venenatis augue in, rhoncus nisi. Mauris sagittis sit amet ante eget luctus. Maecenas id malesuada elit. Vestibulum nec ante nec justo venenatis tincidunt. ```"; + return tempLore; + case "introObsidian": + var tempLore = "<:anarchy:460990297099337750> **<@&" + process.env.GROUP_A_ROLE + ">** - !obsidian\n```Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eu aliquet mauris, id congue nisi. Integer et lobortis tellus. Sed bibendum a metus quis volutpat. Mauris faucibus quam at euismod scelerisque. Vestibulum a elit auctor, venenatis augue in, rhoncus nisi. Mauris sagittis sit amet ante eget luctus. Maecenas id malesuada elit. Vestibulum nec ante nec justo venenatis tincidunt.```"; + return tempLore; + case "introEnd": + var tempLore = "_Choose wisely._"; + return tempLore; + case "level1": + var tempLore = ''; + tempLore += `Congratulations ${data}, you have reached **${data2}**! Travelers defend the city from Ravagers here, and you can earn some crystals.` + return tempLore; + case "level15": + var tempLore = ''; + tempLore += `Congratulations ${data}, you have reached **${data2}**, where there are more dangerous enemies, lurking in the fog.` + return tempLore; + case "level30": + var tempLore = ''; + tempLore += `Congratulations ${data}, you have reached **${data2}**, the area most teeming with the strongest Ravagers. Watch your back, and good luck!` + return tempLore; + case "lore": + var tempLore = ''; + switch(data) { + case "backstory": + tempLore = "‘_Mother Earth had failed us. "; + tempLore += "\n\n"; + tempLore += "In her dying breath, she bore a starship, **The Genesis**, to save the last of humankind. But the **travelers** aboard were not prepared for the unwelcoming winds of barren space."; + tempLore += "\n\n"; + tempLore += "On the brink of extinction our forefathers landed here, but this was no earth. The desolate landscape of **The Deadlands** traded our starvation for thirst, our isolation for open and empty space. But despite our struggles, we could breathe again."; + tempLore += "\n\n"; + tempLore += "We walked for many days and many nights in **The Deadlands**, consuming only the native **crystals** climbing from the ground for sustenance. Leaving the shelter of our vessel behind for the hope of a new home. Many withered away under the scorching heat of the twin suns and the constant attacks from **Ravagers**, but Mother Earth kept her promise."; + tempLore += "\n\n"; + tempLore += "In our darkest hour, we laid eyes on **The Sanctum**, a city of the gods. Complete with a vault full of our edible crystals, and more than enough room for the entire population; A city with human amenities in the middle of an inhuman world, bestowed upon a dying nation in need. This place was truly a divine gift."; + tempLore += "\n\n"; + tempLore += "At the highest point of the city in the tower that touched the clouds, we found **The Librarian**. A meticulous mechanical record keeper hovering over his book, the great **Codex Arcana**. This was a book written in detail to record the actions of every man, woman, and child that lived among us. But it was far too powerful, and the secrets it contained proved lethal in the wrong hands."; + tempLore += "\n\n"; + tempLore += "And so began the **factions**, vying for control over the Codex._'"; + tempLore += "\n\n"; + tempLore += "- Excerpt from the **Teachings of Tiberius**. March 22, 2630."; + break; + case "genesis": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "travelers": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "deadlands": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "ravager": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "Sanctum": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "librarian": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "codex": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + case "factions": + tempLore = "Sorry. I recognize the term but am unable to process the request. There is a corruption in my cognitive core. Try again soon."; + break; + default: + tempLore = "Here is the lore that is available in my database. ```!lore backstory```" + break + } + console.log("TEMPLORE: " + tempLore); + return tempLore; + } + } +} diff --git a/ADAM_Kamala/npcSettings.js b/ADAM_Kamala/npcSettings.js new file mode 100644 index 0000000..396fbc0 --- /dev/null +++ b/ADAM_Kamala/npcSettings.js @@ -0,0 +1,8 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + activity: "for !obsidian recruits.", + type: "WATCHING", + token: process.env.KAMALA_OBSIDIAN_TOKEN, + botChannel: process.env.GROUP_A_BOT_ID +} diff --git a/ADAM_Kamala/package-lock.json b/ADAM_Kamala/package-lock.json new file mode 100644 index 0000000..16601ab --- /dev/null +++ b/ADAM_Kamala/package-lock.json @@ -0,0 +1,69 @@ +{ + "name": "nodejs-elasticbeanstalk", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + } + } +} diff --git a/ADAM_Kamala/package.json b/ADAM_Kamala/package.json new file mode 100644 index 0000000..11eb464 --- /dev/null +++ b/ADAM_Kamala/package.json @@ -0,0 +1,17 @@ +{ + "name": "nodejs-elasticbeanstalk", + "version": "1.0.0", + "description": "", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "node-cron": "^1.2.1" + } +} diff --git a/Alexis/alexis.js b/Alexis/alexis.js new file mode 100644 index 0000000..3ae1a44 --- /dev/null +++ b/Alexis/alexis.js @@ -0,0 +1,717 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); + +// Bot Modules (stores http requests & random functions respectively) +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); + +// Drinks +const drinks = [ + // https://brookstonbeerbulletin.com/beer-tasting-terms/ + ['🍺', 'Beer', 'The clean, classic Traveler\'s Watch drink.', '2'], + ['🥛', 'Milk', 'An innocent, creamy drink. It is very nutritious.', '2'], + // http://scotchtasting.info/glossary/ + ['🥃', 'Whiskey', 'A very dignified, rich drink.', '5'], + // https://en.wikipedia.org/wiki/Wine_tasting_descriptors + ['🍷', 'Wine', 'An aromatic wine, with a round taste.', '10'], + // http://richardgpeterson.com/champagne-glossary/ + ['🍾', 'Champagne', 'A brilliant, crisp drink. You can share your 🥂 drink with the tavern!', '20'] +] + +const normalActivity = '!buydrink | Bartender, Confidant' + +// 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" + client.user.setActivity(normalActivity); + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); +}); + +// Create an event listener for messages +client.on('message', async message => { + // Message has to be in Tavern or Test + if (!(message.channel.id === process.env.TAVERN_CHANNEL_ID + || message.channel.id === process.env.TEST_CHANNEL_ID)) return; + + var sentMessageFlag = false; + + // Ignores ALL bot messages with exceptions + if (message.author.bot) { + // If bot is Mori + if (message.author.id === "461294299515191306") { + if (calcRandom.gamble(33)) { + var dialogOptions = [ + 'Aww, do you have to rez \'em all?', + 'I feel like you should skip some of \'em.', + 'We don\'t say it enough, but we all appreciate what you do, honey.', + 'I\'m sure everyone is thankful, they\'re just occupied.', + 'Hey now, yer not gonna\' get no thanks with an attitude like that.', + 'Are ya\' really in this for the glory though?', + 'Thanks, hun.', + 'You are very much appreciated.', + 'I\'m sure it\'s not on purpose.', + 'Travelers got a lot on their minds. But you\'re very needed, Sugar.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + + message.channel.startTyping(); + setTimeout(() => { + sendMessage(message.channel.id, "<@" + message.author.id + "> " + dialogOptions[randomNumber]); + message.channel.stopTyping(true); + }, calcRandom.random(2500, 6000)); + sentMessageFlag = true; + } + } + return; + } + + var wholeMessage = message.content.toLowerCase().replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g,""); + var words = wholeMessage.split(" "); + console.log("wholeMessage: " + wholeMessage + "\nWords: " + words) + // Hearts message with "alexis" and not "date" + if (words.includes("alexis") && !words.includes("date") && sentMessageFlag === false) { + if (calcRandom.gamble(33)) { + setTimeout(function() { + message.react("❤") + }, calcRandom.random(1500,4000)); + sentMessageFlag = true; + return; + } + } + + // Hey message + if (words.includes("hey") && sentMessageFlag === false) { + sayHey(message.channel, message.author.id); + sentMessageFlag = true; + return; + } + + // Saying Alexis is your friend basically + if (words.includes("alexis") && words.includes("friend") && !words.includes("date") && sentMessageFlag === false) { + if (calcRandom.gamble(45)) { + var dialogOptions = [ + '<@276538857174990858> is my girl.', + '<@462675530928357376>\'s been out a long while, but when she gets back I hope she stops by.', + 'Me \'n <@462675530928357376> are pretty close.', + 'Well I can tell ya\' who\'s not my friend. <@461294299515191306>. No offense hun.', + 'That <@163770616581718017> character is mighty strange. But <@276538857174990858> fancies him so he must be alright.', + 'You don\'t tip enough to call me a friend sweetie.', + 'Listen here. I\'d love to chat but <@276538857174990858> \'n <@462675530928357376> have plans in a bit.', + 'We\'re all friends when we drink together.', + 'Ol\' Jakey never came back. Nice guy. Probably made a nice meal for a Ravager.', + 'There\'s friends, and then there\'s family. Me \'n <@276538857174990858> are like that.' + ]; + typeRandomDialog(dialogOptions, message.channel); + sentMessageFlag = true; + return; + } + } + + // Asking Alexis on a date + if (words.includes("alexis") && words.includes("date") && sentMessageFlag === false) { + if (calcRandom.gamble(33)) { + var dialogOptions = [ + 'Honey yer a darling, but not gonna happen.', + 'Just because yer cute doesn\'t mean you get an auto-yes.', + ':thumbsdown:', + 'Hey now, what makes you think I\'m even available?', + 'Calm yer britches and go ask Rey. She\'s into ones like you.', + 'Nah, but thank you honey. It was sweet of ya\'', + 'Listen here. I\'d love to chat but I\'d be lyin\' if I said I was interested.', + 'Sweetie I try to be nice, but sometimes there\'s no nice way to say ***no***.', + 'Yer gonna have to try harder than that now.', + 'How about I give you a big fat maybe?' + ]; + typeRandomDialog(dialogOptions, message.channel, message.author.id); + sentMessageFlag = true; + return; + } + } + + // Ravager topic + if (words.includes("ravager") || words.includes("ravagers") && sentMessageFlag === false) { + if (calcRandom.gamble(33)) { + var dialogOptions = [ + 'never seen one in person.', + 'Are they really big and scary? Only seen pictures on the \'net.', + 'Fight any big ones lately?', + 'What do you think they are? Like...they\'re angry that\'s for sure, but...like...why?', + 'You ever got bit?', + 'I hear they\'re mean \'n nasty.', + 'Hope I never see one face ta face', + 'You big strong travelers you. Keepin\' me safe an\' all :heart:', + 'I dunno what I\'d do if one broke into the city here.', + 'Just make sure you keep \'em away from ***The Watch*** ya\' hear?' + ]; + typeRandomDialog(dialogOptions, message.channel, message.author.id); + sentMessageFlag = true; + return; + } + } + + // Bar fights + if (words.includes("fight") || words.includes("attack") || words.includes("fighting") || words.includes("barfight") || words.includes("fite") && sentMessageFlag === false) { + if (calcRandom.gamble(33)) { + var dialogOptions = [ + 'Don\'t be startin\' no brawlers in here, ya\' hear?', + 'Don\'t even think about it.', + 'Don\'t make me give _Ghost_ a ping on the com.', + 'In here is drinkin\' time. Out there in the deadlands is fightin\' time. Learn the difference.', + 'You forget the rules or somethin\'?', + 'Honey, just because I\'m sweet doesnt mean I can\'t kick your ass out the door.', + 'You fight in here, you drink somewhere else.', + 'Whatever pissing contest you\'re try\'na win, win it elsewhere.', + 'Don\'t be actin\' all tuff here. Everybody knows what happened with you and that _Ravager_.', + 'The first rule of drink club, no fightin\'.' + ]; + typeRandomDialog(dialogOptions, message.channel, message.author.id); + sentMessageFlag = true; + return; + } + } + + // Good nights + if (words.includes("gn") || words.includes("night") || words.includes("goodnight") || words.includes("sleep") && sentMessageFlag === false) { + if (calcRandom.gamble(33)) { + var dialogOptions = [ + 'Night hun.', + 'Goodnight sweety. You comin\' back tomorrow?', + 'Have yerself a goodnight now ya\' hear?', + 'Sweet dreams.', + 'Nighty night.', + 'Gn. See ya tomorrow?', + 'Yer leavin\' already?', + 'Have yerself a good rest now.', + 'Sleep tight. I\' see ya\' tomorrow.', + 'Don\' let the bed bugs bite. They\'re the size of ravagers here on New Eden.' + ]; + typeRandomDialog(dialogOptions, message.channel, message.author.id); + sentMessageFlag = true; + return; + } + } + + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "ping": + if (message.author.id === '200340393596944384' || message.author.id === '163770616581718017') + message.reply("Pong!"); + break; + case "buydrink": + buyDrink(message, args); + break; + + case "tip": + if (args == "") { + //if (false) { + newMessage = `:x: I appreciate the gesture, but how much did you wanna tip, <@${message.author.id}>?`; + sendMessage(message.channel.id, newMessage); + } else { + var crystalCost = Math.floor(parseFloat(args)); + if (crystalCost > 0) { + //if (crystalCost > -1) { + // Valid number + var attacker = String(dataRequest.loadServerData("userStats", message.author.id)); + var attackerWallet = parseFloat(attacker.split(",")[6]); + if (attackerWallet > crystalCost) { + var upgradeResponse = dataRequest.sendServerData("buyDrink", crystalCost, message.author.id); + var dialogOptions = [ + 'Well ain\'t you sweet. Much appreciated.', + 'Awww that\'s mighty nice of ya\' :heart:', + 'Thank you sweet heart. Very generous of ya\'', + 'I appreciate that very much! And look forward to seein\' yer face more often. :wink:', + 'Well now, you are just too kind.', + 'You\' a sweet heart aren\'t ya. Thank you.', + 'Sweety I just can\'t take how kind you are. :heart: Thank you very much.', + 'For me? Aww, ya\' shouldn\'t have.', + 'That is very much appreciated and you are welcome back to ***The Watch*** anytime.', + 'Well darn, that\'s nice of ya. Thank you sweety.' + ]; + + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + newMessage = dialogOptions[randomNumber] + "\n<@" + message.author.id + "> <:crystals:460974340247257089> **-" + crystalCost + "**"; + sendMessage(message.channel.id, newMessage); + + //Send PM (defunct) + //if (crystalCost >= 0) { + /* + if (crystalCost >= 50) { + var dialogOptions2 = [ + 'Hey so...not 100% on this but heard it through the grape vine. ', + 'Ya\' know, the walls have ears around my place and occasionally I hear stuff. ', + 'I ain\'t supposed to be tellin\' ya this, and I ain\'t sure how true it it...but...', + 'So I probably shouldn\' get involved but I overheard some people talkin\'. Don\'t know if they spoke the truth, but...', + 'Yer a generous tipper. So am I. Not solid on the info, but I got a tip for ya\'. ', + 'So I hear things, and for generous people like yourself I might repeat \'em. Don\'t mean they\'re true. But...', + 'I heard somethin\' I probably shouldn\'t repeat. Obviously can\'t confirm this. ', + 'Things pass through my ears and I can\'t help but pass \'em on. ', + 'Hey there. A fello traveler told me something ya\' should hear. Don\'t know the accuracy, just know what I heard. ', + 'Ok so, don\'t know if this is up to date info, but I got somethin\' for ya. ' + ]; + + var dialogOptions3 = [ + 'Looks like The Order might actually be ahead in crystals this week.', + 'I think The Anarchy is winning this week. Although can\'t say by how much.', + 'Pretty sure The Religion has the most crystals in their bank right about now.', + 'I heard that The Order is behind on crystals in the bank.', + 'Someone mentioned that The Anarchy was a bit behind on crystals this week.', + 'Been hearin\' that the Religion is last place in crystals this week, but they always have tricks up their sleeves.' + ]; + + var randomNumber2 = Math.floor(Math.random() * dialogOptions2.length); + var randomNumber3 = Math.floor(Math.random() * dialogOptions3.length); + newMessage = dialogOptions2[randomNumber2] + dialogOptions3[randomNumber3]; + //sendDM(message.author.id, newMessage); + message.author.send(newMessage); + } + */ + } else { + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Looks like ya\' ain\'t got the <:crystals:460974340247257089>. Don\'t make a girl a promise that ya\' can\'t keep."); + } + } else { + //Not a number + sendMessage(message.channel.id, `:x: Doesn't seem like a tip I could use, but I appreciate the thought, <@${message.author.id}>!`); + } + } + break; + } +}); + +client.on('error', console.error); + +// https://stackoverflow.com/questions/3733227/javascript-seconds-to-minutes-and-seconds +function fmtMSS(s){ // accepts seconds as Number or String. Returns m:ss + return( s - // take value s and subtract (will try to convert String to Number) + ( s %= 60 ) // the new value of s, now holding the remainder of s divided by 60 + // (will also try to convert String to Number) + ) / 60 + ( // and divide the resulting Number by 60 + // (can never result in a fractional value = no need for rounding) + // to which we concatenate a String (converts the Number to String) + // who's reference is chosen by the conditional operator: + 9 < s // if seconds is larger than 9 + ? ':' // then we don't need to prepend a zero + : ':0' // else we do need to prepend a zero + ) + s ; // and we add Number s to the string (converting it to String as well) +} + +function sayHey(channel, userID) { + var dialogOptions = [ + 'Howdy', + 'Hey back', + 'Hey yourself', + 'Hi', + 'Hey it\'s you', + 'Hi there', + 'Hay is for horses silly', + 'Well hello', + 'Hey hey hey', + 'Hey stranger' + ]; + var dialogOptions2 = [ + 'How ya\' been?', + 'Whatcha\' up to?', + 'What\'s the weather like out there?', + 'Find any decent sized Ravagers?', + 'Welcome back.', + 'Glad you\'re back. Could use some company.', + 'What are ya\' havin\'?', + 'Whatcha\' drinkin\'?', + 'Retiring for the night? Already?', + 'Welcome to _The Watch!_' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + var randomNumber2 = Math.floor(Math.random() * dialogOptions2.length); + var newMessage = dialogOptions[randomNumber] + " <@" + userID + ">!\n" + dialogOptions2[randomNumber] + "\n"; + + channel.startTyping(); + setTimeout(function() { + sendMessage(channel.id, newMessage); + channel.stopTyping(true); + }, calcRandom.random(2500,6000)); +} + +function typeRandomDialog(dialogOptions, channel, playerID) { + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + + channel.startTyping(); + setTimeout(function() { + if (playerID === undefined) + sendMessage(channel.id, dialogOptions[randomNumber]); + else + sendMessage(channel.id, "<@" + playerID + "> " + dialogOptions[randomNumber]); + + channel.stopTyping(true); + }, calcRandom.random(2500, 6000)); +} + +// Send message handler +function sendMessage(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message === undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message; + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); +} + +// Async Waiting +function sleep(time) { + return new Promise((resolve, reject) => { + setTimeout(resolve, time); + }); +} + +// Buy drink +async function buyDrink(message, args) { + var randomGreet = [ + `Hey ${message.author}, wanna drink? Here's what I've got!`, + `Welcome to the tavern, ${message.author}! Care for a drink?`, + `People have been asking me on dates, ${message.author}. Must've be the alcohol.`, + `How's the Ravager hunting going, ${message.author}?` + ]; + + var randomNumber = Math.floor(Math.random() * randomGreet.length); + + message.channel.startTyping(); + await sleep(1500); + message.channel.stopTyping(true); + + const takingTooLongMessage = ":x: Sorry, hun. But the others need me and yer taking too long. Call me back once you've made yer mind up, alright " + message.author + "?"; + var footerName = message.member.displayName; + var courtesy = ""; + var tmp = ""; + + // Generates drink text. + for (let index = 0; index < drinks.length; index++) { + const element = drinks[index]; + tmp += `${element[0]} **${element[1]} <:crystals:460974340247257089> ${element[3]}** - ${element[2]}\n` + } + + // If there is a mention + if (message.mentions.members.size > 0) { + footerName = message.mentions.members.first().displayName; + courtesy = `(Given to ${message.mentions.members.first().displayName}, Courtesy of ${message.member.displayName})`; + } + + const embed = new Discord.RichEmbed() + .setAuthor("Alexis", client.user.avatarURL) + .setColor("#ffcc4d") + .setTitle("Traveler's Watch Drinks " + courtesy) + .setDescription(tmp) + .setFooter("We hope you enjoy your stay, " + footerName + "!") + + var newMessage = await message.channel.send(randomGreet[randomNumber], {embed}); + var emoteReaction; + + // Collects emotes and reacts upon the reaction (15 seconds) + const collector = newMessage.createReactionCollector( + (reaction, user) => (drinks.some(drinkElement => drinkElement[0] === reaction.emoji.name) || reaction.emoji.name === "❌") + && user.id !== client.user.id && user.id === message.author.id, { time: 15 * 1000 }); + var endedOnReact = false; + + // Reacts + for (let i = 0; i < drinks.length; i++) { + const element = drinks[i][0]; + console.log("[Reaction Options] Emote: " + element); + await newMessage.react(element); + } + await newMessage.react("❌"); + + // Collect + collector.once("collect", async reaction => { + emoteReaction = reaction.emoji.name; + endedOnReact = true; + collector.stop(); + }); + + // Chose an emote + collector.once("end", async collector => { + newMessage.clearReactions(); + + // If no choose + if (!endedOnReact) { + newMessage.edit(newMessage.content); + return newMessage.channel.send(takingTooLongMessage); + } + + // If cancelled + if (emoteReaction === "❌") { + newMessage.edit(newMessage.content); + return; + } + + // Gets confirmation by emote + var index = drinks.findIndex(drink => drink[0] === emoteReaction); + //console.log(index + "\n" + drinks[index]); + + var confirmationMessage = await message.channel.send(`${message.author} You sure you want to buy the ${drinks[index][0]} **${drinks[index][1]}** for <:crystals:460974340247257089> **${drinks[index][3]}**?`); + await confirmationMessage.react('✅'); + await confirmationMessage.react('❌'); + + // Collects emotes and reacts upon the reaction (15 seconds) + const newCollector = confirmationMessage.createReactionCollector( + (reaction, user) => (reaction.emoji.name === '✅' || reaction.emoji.name === '❌') + && user.id !== client.user.id && user.id === message.author.id, { time: 15 * 1000 }); + var confirmReact = false; + + // Collect + newCollector.once("collect", async reaction => { + emoteReaction = reaction.emoji.name; + console.log("confirm: " + emoteReaction); + confirmReact = true; + newCollector.stop(); + }); + + newCollector.once("end", async collector => { + confirmationMessage.delete(); + + // If no choose + if (!confirmReact) { + return message.channel.send(takingTooLongMessage); + } + + if (emoteReaction === "✅") { + payDrinks(message, drinks[index]); + } else { + confirmationMessage.clearReactions(); + } + }); + }); +} + +// Buying drink +function payDrinks(message, drink) { + //var crystalCost = 0; + + // A ton of variables + var crystalCost = parseFloat(drink[3]); + var emote = drink[0]; + var givenIsAlexis = false; + var success = false; + var attacker = String(dataRequest.loadServerData("userStats", message.author.id)); + var attackerWallet = parseFloat(attacker.split(",")[6]); + + console.log("[Pay Drinks] Wallet: " + attackerWallet + " | Crystal Cost: " + crystalCost); + if (attackerWallet >= crystalCost) { + dataRequest.sendServerData("buyDrink", crystalCost, message.author.id); + + dialogOptions = [ + 'Here\'s a cold one,', + 'Here\'s your drink', + 'Here you go,', + 'Here ya are. Enjoy,', + 'Sliding it your way,', + 'Don\'t go alone, take this,', + 'Drink up,', + 'Don\'t chug it all down now,', + 'Headed in your direction,', + 'Comin\' up,' + ]; + + // Alexis options + if (message.mentions.members.first() !== undefined) { + if (message.mentions.members.first().id === client.user.id) { + var dialogOptions = [ + `Aww, thanks! :heart:`, + `Thanks for the drink! Cheers!`, + `Are you trying to make me drunk? Don't even TRY asking me out on a date,` + ]; + givenIsAlexis = true; + } + } + + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + var newMessage = ""; + + // Single or multiple user messages + if (message.mentions.members.size < 1) { + success = true; + newMessage = `${emote} ` + dialogOptions[randomNumber] + " <@" + message.author.id + ">! <:crystals:460974340247257089> **-" + crystalCost + "**"; + } else { + // Huge scope creep, but have a list of players able to be given beer instead of just one later on + // For now, just taking the first player + let member = message.mentions.members.first(); + if (member) { + // Displays ping if not Alexis + var givePingUser = ` ${member.user}!`; + if (givenIsAlexis) givePingUser = ""; + + success = true; + newMessage = `${emote} ` + dialogOptions[randomNumber] + givePingUser + "\n\n" + "***Courtesy of *** <@" + message.author.id + ">. <:crystals:460974340247257089> **-" + crystalCost + "**"; + } else { + newMessage = ":x: <@" + message.author.id + "> You wanna buy ***WHO*** a ***WHAT*** now?"; + } + } + sendMessage(message.channel.id, newMessage); + + // Does champagne sharing + if (success && drink[1] === "Champagne") { + shareDrinks(message, drink); + } + + } else { + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Looks like ya\' ain\'t got the <:crystals:460974340247257089><:crystals:460974340247257089><:crystals:460974340247257089>. I ain\'t runnin\' a charity here."); + } +} + +// Mass buying of a drink +async function shareDrinks(message, drink) { + const drinkMessage = `${message.author} has bought some ${drink[0]} **${drink[1]}**! React to get your **free drink!** 🥂`; + var timer = 30; // Seconds + var decrementTime = 10; + var footerText = `⏰ ${timer} seconds left to get your free drink!`; + client.user.setActivity(`${footerText}`); + + // Embed + const embed = new Discord.RichEmbed() + .setAuthor("Alexis", client.user.avatarURL) + .setColor("#ffcc4d") + .setTitle("Free Drinks!") + .setDescription(drinkMessage) + .setFooter(footerText) + + var embedMessage = await message.channel.send(embed); + + // Message + message.channel.startTyping(); + await sleep(1500); + message.channel.send("Hmm... I might just take some too, if y'all don't mind. :heart:"); + message.channel.stopTyping(true); + await sleep(1500); + + // Collects emotes and reacts upon the reaction (30 seconds) + var users = ""; + var numberOfReacts = 0; + const newCollector = embedMessage.createReactionCollector( + (reaction, user) => reaction.emoji.name === drink[0] + , { time: timer * 1000 }); + + // Alexis grabbing some + await embedMessage.react(drink[0]); + + // Collect + newCollector.on("collect", async reaction => { + var user = reaction.users.last(); + dialogOptions = [ + `${user} has taken a drink!`, + `${user} eagerly grabs the ${drink[1]}!`, + `${user} enjoys the beverage!`, + `${user} gets a free drink!`, + `${user} chugs down the ${drink[1]}!`, + `${user} races to get down the drink the fastest!` + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + users += dialogOptions[randomNumber] + "\n"; + + // Embed + const embed = new Discord.RichEmbed() + .setAuthor("Alexis", client.user.avatarURL) + .setColor("#ffcc4d") + .setTitle("Free Drinks!") + .setDescription(`${drinkMessage}\n\n` + users) + .setFooter(footerText) + + embedMessage.edit(embed); + + // Counts up if not Alexis + if (reaction.users.last().id !== client.user.id) numberOfReacts++; + }); + + // Ends collection + newCollector.once("end", async collector => { + var number = "" + if (numberOfReacts === 1) { + number = numberOfReacts + " traveler"; + } else { + number = numberOfReacts + " travelers"; + } + + // Embed + embedMessage.clearReactions(); + const embed = new Discord.RichEmbed() + .setAuthor("Alexis", client.user.avatarURL) + .setColor("#ffcc4d") + .setTitle("Free Drinks!") + .setDescription(`${message.author}'s ${drink[0]} **${drink[1]}** has been finished. There were a total of ${number} that got the free drink! 🥂\n\n` + users) + .setFooter("⏰ The drink has been finished!") + + embedMessage.edit(embed); + message.channel.send(`Everyone, thank ${message.author} for the drink! It was great.`); + }); + + + function timerFunction() { + setTimeout(async () => { + console.log("timer: " + timer + " => " + (timer - decrementTime)) + timer -= decrementTime; + + footerText = `⏰ ${timer} seconds left to get your free drink!`; + + if (timer > 0) { + client.user.setActivity(`${footerText}`); + + // Embed + const embed = new Discord.RichEmbed() + .setAuthor("Alexis", client.user.avatarURL) + .setColor("#ffcc4d") + .setTitle("Free Drinks!") + .setDescription(`${drinkMessage}\n\n` + users) + .setFooter(footerText) + + embedMessage.edit(embed); + } else { + client.user.setActivity(normalActivity) + } + + if (timer > 0) timerFunction(); + }, decrementTime * 1000); + } + + timerFunction(); +} + +/* +async function sendDM(userID, dialogOption, dialogOption2, dialogOption3) { + // Wait for 20 - 40 seconds + //await(sleep(calcRandom.random(120, 240) * 60 * 1000)); + var author = client.users.get(userID); + + client.send(author, dialogOption); + client.send(author, dialogOption2); + client.send(author, dialogOption3); +} +*/ + +// Log our bot in +client.login(process.env.ALEXIS_TOKEN); \ No newline at end of file diff --git a/Alexis/package-lock.json b/Alexis/package-lock.json new file mode 100644 index 0000000..13e221c --- /dev/null +++ b/Alexis/package-lock.json @@ -0,0 +1,723 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "combine-middlewares": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/combine-middlewares/-/combine-middlewares-0.1.0.tgz", + "integrity": "sha512-X7A6T6UAH1cULUIhDgvBol2XcvThuVrDMdD2ZPg9FEddEW3KsoKShd1yaRsMIl1v4Aj8dqSfehMXJxD/kwXJ2Q==" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deserialize-error": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/deserialize-error/-/deserialize-error-0.0.3.tgz", + "integrity": "sha1-9WhjNXLXwsxGpVpfwlS23857P8o=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", + "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "~1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serialize-error": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=" + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-request": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/socket.io-request/-/socket.io-request-0.8.0.tgz", + "integrity": "sha512-uZXUELbSNMbujTLFr+hGurZM+fhMLJ7fd3ZmM4FjrXXch5Cy9agLx6pBdzGjEdBblmhzj3Buo1SJvTub2VIf5A==", + "requires": { + "combine-middlewares": "^0.1.0", + "deserialize-error": "^0.0.3", + "serialize-error": "^2.0.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/Alexis/package.json b/Alexis/package.json new file mode 100644 index 0000000..69163ab --- /dev/null +++ b/Alexis/package.json @@ -0,0 +1,29 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "description": "Universal package for all SANCTUM bots, using pm2.", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "echo \"Error: you need to use the bot name as a command.\" && exit 1", + "alexis": "pm2 start alexis.js -i max --watch", + "graze": "pm2 start graze.js -i max --watch", + "librarian": "pm2 start librarian.js -i max --watch", + "mainframe": "pm2 start mainframe.js -i max --watch", + "mori": "pm2 start mori.js -i max --watch", + "mosiah": "pm2 start mosiah.js -i max --watch", + "ravager": "pm2 start ravager.js -i max --watch", + "rey": "pm2 start rey.js -i max --watch", + "troll": "pm2 start troll.js -i max --watch" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "express": "^4.16.3", + "node-cron": "^1.2.1", + "socket.io": "^2.1.1", + "socket.io-request": "^0.8.0" + } +} diff --git a/Enemy/enemy.js b/Enemy/enemy.js new file mode 100644 index 0000000..85f406f --- /dev/null +++ b/Enemy/enemy.js @@ -0,0 +1,487 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); +const io = require('socket.io-client'); + +// Make connection +var socket = io.connect('http://localhost:80'); + +// Bot Modules +const npcSettings = require('./npcSettings') +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); + +// State Machine +var EnemyState = { + INACTIVE: 0, + PROWLING: 1, + ACTIVE: 2, + UNCONSCIOUS: 3 +} + +// Enemy lists +class EnemyBatchInstance { + constructor(channel) { + this.state = EnemyState.INACTIVE; + this.enemies = []; // Array of `new Enemy()`s + this.channel = channel; // Channel of spawning + this.spawnPrecentage = 100; + this.hostileLevel = 1; + this.fastSummon = true; // Show prowling + } +} + +// Enemy instance +class Enemy { + constructor(type) { + this.state = EnemyState.INACTIVE; + this.type = type; + this.level = 1; + this.health = 420; + this.speed = 21; + this.strength = 33; + this.stash = 0; + this.fleeTime = undefined; + this.guid = undefined; + this.deletePrevMessage = false; + } + + // Creates flee time by randomization + get randomFleeTime() { + var randomFleeTime; + randomFleeTime = calcRandom.random(3 * 60 * 1000, 6 * 60 * 1000); + randomFleeTime -= (randomFleeTime % 1000); + return randomFleeTime; + } +} + +var enemyBatchCollection = []; + +// Spawning patterns +var spawnPatterns = { + "types": ['default', 'randomBatch2'], + "default": { + "ravager": { + "amount": 1 + }, + "type": "incrememt" + }, + "randomBatch2": { + "amount": 2, + "type": "incrememt" + } +} + +var socketReady = false; +socket.on('spawn', (data) => { + if (!socketReady) return; + + console.log(JSON.stringify(data, null, 4)); + console.log(`Summoning enemies...`); + + // Spawns + summonEnemy(data); + +}); + +// 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 () => { + socketReady = true; + + // 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('invisible'); + // Sets your "Playing" + if (npcSettings.activity) { + client.user.setActivity(npcSettings.activity, { type: npcSettings.type }) + .then(presence => console.log(`Activity set to ${presence.game ? presence.game.name : 'none'}`)) + .catch(console.error); + } + + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); + + // Corrects Ravager username + if (client.user.username == "Raveger") { + const newName = "Ravager"; + console.log("Username is Raveger! Typos are NOT(?) cannon, so better change stuff.\nAttempting rename to " + newName + "..."); + + // Set username + client.user.setUsername(newName) + .then(user => console.log(`Success! New username is now ${user.username}.`)) + .catch(console.error); + + // Changes nickname + client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id).setNickname(""); + } +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + // Message has to be in Outskirts (should be edited later) + if (!(message.channel.id === process.env.DEADLANDS_CHANNEL_ID + || message.channel.id === process.env.TEST_CHANNEL_ID)) return; + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "ping": + if (isAdmin(message.author.id)) + message.reply("***...MRGRGRGR!***"); + break; + case "ravager": + if (args[0].toLowerCase() === "summon" && isAdmin(message.author.id)) { + generateEnemy(process.env.DEADLANDS_CHANNEL_ID); + } + break; + } +}); + +client.on('error', console.error); + +cron.schedule('*/10 * * * *', function() { + +}); + +async function generateEnemy(channelID) { + console.log("Generating enemy...") + + // Gets an enemy batch instance, or creates if non-existant + var index = enemyBatchCollection.findIndex(data => data.channel === channelID); + var enemyBatch; + console.log(index <= -1) + if (index <= -1) { + enemyBatch = new EnemyBatchInstance(channelID); + } else { + enemyBatch = enemyBatchCollection[index]; + } + + // Generate a spawn pattern + var randomSpawnPattern = spawnPatterns.types[calcRandom.randomExc(0, spawnPatterns.types.length)]; + var newSpawnPattern = spawnPatterns[randomSpawnPattern]; + newSpawnPattern = spawnPatterns["default"]; // Overruled! + + // Creates a bunch of new enemies + var amount = newSpawnPattern[npcSettings.id].amount; + var newEnemies = []; + for (let i = 0; i < amount; i++) { + var enemy = new Enemy(npcSettings.id); + var elevel = enemyBatch.hostileLevel; + + // Replication of newHostile in sendData.php + const healthBase = 50; const strengthBase = 3; const speedBase = 3; const stashBase = 3; + + const healthMin = (healthBase * elevel) / 2; + const healthMax = healthBase * elevel; + + const strengthMin = (strengthBase * elevel) / 2; + const strengthMax = strengthBase * elevel; + + const speedMin = (speedBase * elevel) / 2; + const speedMax = speedBase * elevel; + + const stashMin = (stashBase * elevel) / 2; + const stashMax = stashBase * elevel; + + const health = Math.floor(calcRandom.randomExc(healthMin, healthMax)); + const strength = Math.floor(calcRandom.randomExc(strengthMin, strengthMax)); + const speed = Math.floor(calcRandom.randomExc(speedMin, speedMax)); + const stash = Math.floor(calcRandom.randomExc(stashMin, stashMax)); + + enemy.level = elevel; + enemy.health = health; + enemy.strength = strength; + enemy.speed = speed; + enemy.stash = stash; + enemy.state = EnemyState.PROWLING; + enemy.fleeTime = enemy.randomFleeTime; + enemy.guid = guidGenerator(); + + // Logs stats + console.log(`\n[===== | Enemy Stats | =====]`); + console.log(`HEALTH: ${health} > ${healthMin} - ${healthMax}`); + console.log(`STRENGTH: ${strength} > ${strengthMin} - ${strengthMax}`); + console.log(`SPEED: ${speed} > ${speedMin} - ${speedMax}`); + console.log(`STASH: ${stash} > ${stashMin} - ${stashMax}`); + console.log(`[===========================]\n`); + newEnemies.push(enemy); + } + enemyBatch.enemies = newEnemies; + enemyBatch.hostileLevel++; + + console.log(JSON.stringify(newEnemies, null, 2)); + + if (calcRandom.gamble(enemyBatch.spawnPrecentage)) { + enemyBatch.spawnPrecentage = 50; + + // Creation of Ravager timer + var creationTime = calcRandom.random(35000, 540000); + creationTime = 3 * 1000; // shortcuts + + console.log(`[Enemy Spawn] ${amount} "${npcSettings.id}" will be created in ${fmtMSS(creationTime / 1000)} min.`); + await sleep(creationTime); + console.log(`[Enemy Spawn] ${amount} "${npcSettings.id}" has spawned!`); + summonEnemy(enemyBatch); + + enemyBatch.hostileLevel++; + } else { + console.log("[Enemy Spawn] Fail to spawn. Adding 10% more to chances."); + enemyBatch.spawnPrecentage += 10; + } +} + +// Turn online and turn offline +async function summonEnemy(data) { + // If timer exists, do outpost + const summonTime = 4; // 4 is debug, normal is 35 + if (!data.fastSummon) { + console.log(`Summoning Ravager... waiting for ${summonTime} seconds.`); + client.user.setStatus('online'); + client.user.setActivity(`Prowling...`); + + // Sets prowling states on the Ravagers + for (let i = 0; i < data.enemies.length; i++) { + const element = data.enemies[i]; + element.state = EnemyState.PROWLING; + } + + // Notification code + // TODO + + await sleep(summonTime * 1000); + } + console.log("Enemy has spawned!"); + + // Goes thru all enemies in array + for (let i = 0; i < data.enemies.length; i++) { + const element = data.enemies[i]; + const hostileStats = `LVL: ${element.level} | HP: ${element.health} | STR: ${element.strength} | SPD: ${element.speed}`; + + const ravagerMember = client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id); + const appearanceEmbed = new Discord.RichEmbed() + .setAuthor(ravagerMember.displayName, client.user.avatarURL) + .setColor(ravagerMember.displayColor) + .setDescription(`${healthbar(element.health, element.health)}\n` + "```" + hostileStats + "```") + + var newMessage = await client.channels.get(data.channel).send(getDialog("onTheProwl"), {embed: appearanceEmbed}); + await client.user.setStatus('online'); + await client.user.setActivity(hostileStats); + + for (let i = 0; i < data.enemies.length; i++) { + const element = data.enemies[i]; + element.state = EnemyState.ACTIVE; + } + enemyTimer(element, data, data.channel, element.fleeTime, newMessage); + } +} + +// Counts down +async function enemyTimer(newEnemy, data, channel, fleeTime, newMessage) { + function addUserToArray(userID) { + attackingUsers.push(userID); + } + + async function sendReactions(options) { + // Sends reactions + for (let i = 0; i < options.length; i++) { + const element = options[i]; + //console.log("[Reaction Options] Emote: " + element + " | newMessage: " + newMessage); + await newMessage.react(element); + } + } + + console.log(`Waiting for the next ${fmtMSS(fleeTime / 1000)} min. to check if Ravager has been killed. ${fleeTime}`); + + const ravagerMember = client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id); + const interactionEmbed = new Discord.RichEmbed() + .setColor(ravagerMember.displayColor) + .setTitle("Status") + .setDescription("...") + + var isReadyToFlee = false; + var attackingUsers = []; + var tempAttackUsers = ""; + var newChannel = client.channels.get(channel); + var interactionMessage = await newChannel.send({embed: interactionEmbed}); + + // Collects emotes and reacts upon the reaction + const collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); + + // Possible reaction attacks can go here + var options = ['🇦', '🇧', '🇨'] + sendReactions(options); + + // Collect + collector.once("collect", async reaction => { + var user = reaction.users.last(); + tempAttackUsers += `${user} :crossed_swords: 11 DAM | <:hitback:460969716580745236> MISS (150/150)\n`; + addUserToArray(user.id); + + // Send damage to server + // TODO + }); + + // Ends + collector.once("end", async collector => { + + }); + + // Goes every 4 seconds + var emoteRefresh = setInterval(async () => { + await newMessage.clearReactions(); + interactionEmbed.setDescription("..."); + + if (isReadyToFlee && newEnemy.state !== EnemyState.UNCONSCIOUS) { + console.log("Has fled!"); + interactionEmbed.setDescription("👣 The Ravager has fled...") + if (interactionMessage) await interactionMessage.edit({embed: interactionEmbed}); + clearInterval(emoteRefresh); + collector.stop(); + } else { + if (interactionMessage) await interactionMessage.edit({embed: interactionEmbed}); + sendReactions(options); + } + + tempAttackUsers = ""; + }, 5 * 1000); + + + // Waits to see if killed, and if not send a fleeing message + await sleep(fleeTime); + if (newEnemy.state === EnemyState.ACTIVE) { + newChannel.send("**YOU ARE WEAK. THERE IS NO CHALLENGE FOR ME HERE.**\n:bangbang:***ATTEMPTING TO FLEE...***"); + await sleep(20 * 1000); + + // If still there despawn + if (newEnemy.state !== EnemyState.UNCONSCIOUS) { + console.log('Hostile is now able to flee, now awaiting for collector to finish.'); + isReadyToFlee = true; + } + } +} + +async function flee(newEnemy, data, newChannel) { + newChannel.send("**THE POOR, ILL-EQUIPPED TRAVELERS PUT UP NO FIGHT...**\n:footprints:***RETURNS TO THE WILD. ***"); + socket.emit('fled', { + data: data, + ravager: newEnemy + }); + + if (data.length < 1) { + await client.user.setPresence('invisible'); + client.user.setActivity('Prowling...'); + } +} + +// Health bar +function healthbar(health, maxHealth) { + var heartHealthAmount = 30; + var printString = ""; + var amountMultiple = 0; + var timesToLoop = Math.floor(maxHealth / heartHealthAmount); + for (var i = 0; i < timesToLoop; i++) { + amountMultiple = i * heartHealthAmount; + if (amountMultiple < health) { + printString += ":heart: "; + } else { + printString += ":black_heart:"; + } + } + printString += " (" + health + "/" + maxHealth + ")"; + return printString; +} + +// Async Waiting +function sleep(time) { + return new Promise((resolve, reject) => { + setTimeout(resolve, time); + }); +} + +// Gets if user has an Overseers rank +function isAdmin(userID) { + var guild = client.guilds.get(process.env.SANCTUM_ID); + return guild.members.get(userID).roles.find(role => role.name === "Overseers"); +} + +// https://stackoverflow.com/questions/3733227/javascript-seconds-to-minutes-and-seconds +function fmtMSS(s){ // accepts seconds as Number or String. Returns m:ss + return( s - // take value s and subtract (will try to convert String to Number) + ( s %= 60 ) // the new value of s, now holding the remainder of s divided by 60 + // (will also try to convert String to Number) + ) / 60 + ( // and divide the resulting Number by 60 + // (can never result in a fractional value = no need for rounding) + // to which we concatenate a String (converts the Number to String) + // who's reference is chosen by the conditional operator: + 9 < s // if seconds is larger than 9 + ? ':' // then we don't need to prepend a zero + : ':0' // else we do need to prepend a zero + ) + s ; // and we add Number s to the string (converting it to String as well) +} + +// https://stackoverflow.com/questions/6860853/generate-random-string-for-div-id/6860916#6860916 +function guidGenerator() { + var S4 = function() { + return (((1+Math.random())*0x10000)|0).toString(16).substring(1); + }; + return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); +} + +function getDialog(dialogTag, data = "", data2 = "") { + switch(dialogTag) { + case "onTheProwl": + var dialogOptions = [ + 'THE AIR SMELLS OF BLOOD.', + 'LOOKS LIKE MEAT\'S BACK ON THE MENU BOYS.', + 'FRESH MEAAAATTTT.', + 'TONIGHT WE DINE ON TRAVELER FLESSHHHH.', + 'SKULL CRUSHING IS MY FAVORITE SPORT.', + 'HUNGRY...', + 'TRAVELERS MAKE GOOD MEEEAAAAT!', + 'PUNY TRAVELER THINKS THEY CAN FIGHT?!', + 'HUNT THEM ALL DOWN.', + 'I HUNGER FOR THE TASTE OF FLESH.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + return "***" + dialogOptions[randomNumber] + "***"; + + case "ravagerHit": + var dialogOptions = [ + 'STAGGERS BACK', + 'FALLS BACKWARDS', + 'CHARGES FORWARD CONFUSED', + 'LOOKS FOR THE SOURCE OF THE HIT', + 'FALLS FORWARDS', + 'BLOCKS ITS FACE', + 'STUMBLES BACKWARDS IN CONFUSION', + 'LUNGES FORWARD DISTRACTED', + 'BITES AT IT\'S ATTACKER', + 'CHECKS IT\'S WOUND' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + return `***${dialogOptions[randomNumber]}***`; + } +} + +// Log our bot in (change the token by looking into the .env file) +client.login(process.env.RAVAGER_TOKEN); \ No newline at end of file diff --git a/Enemy/npcSettings.js b/Enemy/npcSettings.js new file mode 100644 index 0000000..92cb18a --- /dev/null +++ b/Enemy/npcSettings.js @@ -0,0 +1,9 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + id: "ravager", + activity: "Prowling...", + type: "PLAYING", + token: process.env.RAVAGER_TOKEN, + botChannel: process.env.DEADLANDS_CHANNEL_ID +} diff --git a/Enemy/package-lock.json b/Enemy/package-lock.json new file mode 100644 index 0000000..004bdad --- /dev/null +++ b/Enemy/package-lock.json @@ -0,0 +1,745 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.1", + "http-errors": "~1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "~2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "~1.6.15" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "combine-middlewares": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/combine-middlewares/-/combine-middlewares-0.1.0.tgz", + "integrity": "sha512-X7A6T6UAH1cULUIhDgvBol2XcvThuVrDMdD2ZPg9FEddEW3KsoKShd1yaRsMIl1v4Aj8dqSfehMXJxD/kwXJ2Q==" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deserialize-error": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/deserialize-error/-/deserialize-error-0.0.3.tgz", + "integrity": "sha1-9WhjNXLXwsxGpVpfwlS23857P8o=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", + "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "~1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.3", + "resolved": "http://registry.npmjs.org/express/-/express-4.16.3.tgz", + "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.3", + "qs": "6.5.1", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + } + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": ">= 1.3.1 < 2" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serialize-error": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=" + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-request": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/socket.io-request/-/socket.io-request-0.8.0.tgz", + "integrity": "sha512-uZXUELbSNMbujTLFr+hGurZM+fhMLJ7fd3ZmM4FjrXXch5Cy9agLx6pBdzGjEdBblmhzj3Buo1SJvTub2VIf5A==", + "requires": { + "combine-middlewares": "^0.1.0", + "deserialize-error": "^0.0.3", + "serialize-error": "^2.0.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/Enemy/package.json b/Enemy/package.json new file mode 100644 index 0000000..5114af3 --- /dev/null +++ b/Enemy/package.json @@ -0,0 +1,31 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "description": "Universal package for all SANCTUM bots, using pm2.", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "echo \"Error: you need to use the bot name as a command.\" && exit 1", + "alexis": "pm2 start alexis.js -i max --watch", + "graze": "pm2 start graze.js -i max --watch", + "librarian": "pm2 start librarian.js -i max --watch", + "mainframe": "pm2 start mainframe.js -i max --watch", + "mori": "pm2 start mori.js -i max --watch", + "mosiah": "pm2 start mosiah.js -i max --watch", + "ravager": "pm2 start enemy-ravager.js -i max --watch", + "wolf": "pm2 start enemy-wolf.js -i max --watch", + "crow": "pm2 start enemy-crow.js -i max --watch", + "rey": "pm2 start rey.js -i max --watch", + "troll": "pm2 start troll.js -i max --watch" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "express": "^4.16.3", + "node-cron": "^1.2.1", + "socket.io": "^2.1.1", + "socket.io-request": "^0.8.0" + } +} diff --git a/Enemy_Crow/enemy-crow.js b/Enemy_Crow/enemy-crow.js new file mode 100644 index 0000000..81c43e8 --- /dev/null +++ b/Enemy_Crow/enemy-crow.js @@ -0,0 +1,346 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); +const io = require('socket.io-client'); + +// Make connection +var socket = io.connect('http://localhost:80'); + +// Bot Modules +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); + +// State Machine +var RavagerState = { + INACTIVE: 0, + PROWLING: 1, + ACTIVE: 2, + UNCONSCIOUS: 3 +} + +const prowling = 'Prowling...'; + +var socketReady = false; +socket.on('spawn', (data) => { + if (!socketReady) return; + + console.log(JSON.stringify(data, null, 4)); + console.log(`Summoning enemies...`); + + // Spawns + summonEnemy(data); + +}); + +// 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 () => { + socketReady = true; + + // 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('invisible'); + // Sets your "Playing" + client.user.setActivity(prowling); + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); + + // Corrects Ravager username + if (client.user.username == "Raveger") { + const newName = "Ravager"; + console.log("Username is Raveger! Typos are NOT(?) cannon, so better change stuff.\nAttempting rename to " + newName + "..."); + + // Set username + client.user.setUsername(newName) + .then(user => console.log(`Success! New username is now ${user.username}.`)) + .catch(console.error); + + // Changes nickname + client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id).setNickname(""); + } +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + // Message has to be in Outskirts (should be edited later) + if (!(message.channel.id === process.env.DEADLANDS_CHANNEL_ID + || message.channel.id === process.env.TEST_CHANNEL_ID)) return; + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "ping": + if (isAdmin(message.author.id)) + message.reply("***...MRGRGRGR!***"); + break; + } +}); + +client.on('error', console.error); + +cron.schedule('*/10 * * * *', function() { + +}); + +// Turn online and turn offline +async function summonEnemy(data) { + // Scans for Ravager already in channel + /* + var isRavagerInChannel = false; + ravagerCollection.forEach(element => { + if (element.channel === data.channel) { + console.log("There is already a Ravager in channel " + element.channel); + isRavagerInChannel = true; + } + }); + if (isRavagerInChannel) return; + */ + + // If timer exists, do outpost + const summonTime = 4; // 4 is debug, normal is 35 + if (!data.fastSummon) { + console.log(`Summoning Ravager... waiting for ${summonTime} seconds.`); + client.user.setStatus('online'); + client.user.setActivity(`Prowling...`); + + // Sets prowling states on the Ravagers + for (let i = 0; i < data.enemies.length; i++) { + const element = data.enemies[i]; + element.state = RavagerState.PROWLING; + } + + // Notification code + // TODO + + await sleep(summonTime * 1000); + } + console.log("Enemy has spawned!"); + + // Goes thru all enemies in array + for (let i = 0; i < data.enemies.length; i++) { + const element = data.enemies[i]; + const hostileStats = `LVL: ${element.level} | HP: ${element.health} | STR: ${element.strength} | SPD: ${element.speed}`; + + const ravagerMember = client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id); + const appearanceEmbed = new Discord.RichEmbed() + .setAuthor(ravagerMember.displayName, client.user.avatarURL) + .setColor(ravagerMember.displayColor) + .setDescription(`${healthbar(element.health, element.health)}\n` + "```" + hostileStats + "```") + + var newMessage = await client.channels.get(data.channel).send(getDialog("onTheProwl"), {embed: appearanceEmbed}); + await client.user.setStatus('online'); + await client.user.setActivity(hostileStats); + + for (let i = 0; i < data.enemies.length; i++) { + const element = data.enemies[i]; + element.state = RavagerState.ACTIVE; + } + enemyTimer(element, data, data.channel, element.fleeTime, newMessage); + } +} + +// Counts down +async function enemyTimer(newRavager, data, channel, fleeTime, newMessage) { + function addUserToArray(userID) { + attackingUsers.push(userID); + } + + async function sendReactions(options) { + // Sends reactions + for (let i = 0; i < options.length; i++) { + const element = options[i]; + //console.log("[Reaction Options] Emote: " + element + " | newMessage: " + newMessage); + await newMessage.react(element); + } + } + + console.log(`Waiting for the next ${fmtMSS(fleeTime / 1000)} min. to check if Ravager has been killed. ${fleeTime}`); + + const ravagerMember = client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id); + const interactionEmbed = new Discord.RichEmbed() + .setColor(ravagerMember.displayColor) + .setTitle("Status") + .setDescription("...") + + var isReadyToFlee = false; + var attackingUsers = []; + var tempAttackUsers = ""; + var newChannel = client.channels.get(channel); + var interactionMessage = await newChannel.send({embed: interactionEmbed}); + + // Collects emotes and reacts upon the reaction + const collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); + + // Possible reaction attacks can go here + var options = ['🇦', '🇧', '🇨'] + sendReactions(options); + + // Collect + collector.once("collect", async reaction => { + var user = reaction.users.last(); + tempAttackUsers += `${user} :crossed_swords: 11 DAM | <:hitback:460969716580745236> MISS (150/150)\n`; + addUserToArray(user.id); + console.log(tempAttackUsers); + if (!interactionMessage.deleted) { + interactionEmbed.setDescription(`${tempAttackUsers}`); + interactionMessage = await newChannel.edit({embed: interactionEmbed}); + } + + // Send damage. + + }); + + // Ends + collector.once("end", async collector => { + + }); + + // Goes every 4 seconds + var emoteRefresh = setInterval(async () => { + await newMessage.clearReactions(); + interactionEmbed.setDescription("..."); + + if (isReadyToFlee && newRavager.state !== RavagerState.UNCONSCIOUS) { + interactionEmbed.setDescription("👣 The Ravager has fled...") + if (interactionMessage) await interactionMessage.edit({embed: interactionEmbed}); + clearInterval(emoteRefresh); + collector.stop(); + } else { + if (interactionMessage) await interactionMessage.edit({embed: interactionEmbed}); + sendReactions(options); + } + + tempAttackUsers = ""; + }, 5 * 1000); + + + // Waits to see if killed, and if not send a fleeing message + await sleep(fleeTime); + if (newRavager.state === RavagerState.ACTIVE) { + newChannel.send("**YOU ARE WEAK. THERE IS NO CHALLENGE FOR ME HERE.**\n:bangbang:***ATTEMPTING TO FLEE...***"); + await sleep(20 * 1000); + + // If still there despawn + if (newRavager.state !== RavagerState.UNCONSCIOUS) { + console.log('Hostile is now able to flee, now awaiting for collector to finish.'); + isReadyToFlee = true; + } + } +} + +async function flee(newRavager, data, newChannel) { + newChannel.send("**THE POOR, ILL-EQUIPPED TRAVELERS PUT UP NO FIGHT...**\n:footprints:***RETURNS TO THE WILD. ***"); + socket.emit('fled', { + data: data, + ravager: newRavager + }); + + if (data.length < 1) { + await client.user.setPresence('invisible'); + client.user.setActivity('Prowling...'); + } +} + +// Health bar +function healthbar(health, maxHealth) { + var heartHealthAmount = 30; + var printString = ""; + var amountMultiple = 0; + var timesToLoop = Math.floor(maxHealth / heartHealthAmount); + for (var i = 0; i < timesToLoop; i++) { + amountMultiple = i * heartHealthAmount; + if (amountMultiple < health) { + printString += ":heart: "; + } else { + printString += ":black_heart:"; + } + } + printString += " (" + health + "/" + maxHealth + ")"; + return printString; +} + +// Async Waiting +function sleep(time) { + return new Promise((resolve, reject) => { + setTimeout(resolve, time); + }); +} + +// Gets if user has an Overseers rank +function isAdmin(userID) { + var guild = client.guilds.get(process.env.SANCTUM_ID); + return guild.members.get(userID).roles.find(role => role.name === "Overseers"); +} + +// https://stackoverflow.com/questions/3733227/javascript-seconds-to-minutes-and-seconds +function fmtMSS(s){ // accepts seconds as Number or String. Returns m:ss + return( s - // take value s and subtract (will try to convert String to Number) + ( s %= 60 ) // the new value of s, now holding the remainder of s divided by 60 + // (will also try to convert String to Number) + ) / 60 + ( // and divide the resulting Number by 60 + // (can never result in a fractional value = no need for rounding) + // to which we concatenate a String (converts the Number to String) + // who's reference is chosen by the conditional operator: + 9 < s // if seconds is larger than 9 + ? ':' // then we don't need to prepend a zero + : ':0' // else we do need to prepend a zero + ) + s ; // and we add Number s to the string (converting it to String as well) +} + +function getDialog(dialogTag, data = "", data2 = "") { + switch(dialogTag) { + case "onTheProwl": + var dialogOptions = [ + 'THE AIR SMELLS OF BLOOD.', + 'LOOKS LIKE MEAT\'S BACK ON THE MENU BOYS.', + 'FRESH MEAAAATTTT.', + 'TONIGHT WE DINE ON TRAVELER FLESSHHHH.', + 'SKULL CRUSHING IS MY FAVORITE SPORT.', + 'HUNGRY...', + 'TRAVELERS MAKE GOOD MEEEAAAAT!', + 'PUNY TRAVELER THINKS THEY CAN FIGHT?!', + 'HUNT THEM ALL DOWN.', + 'I HUNGER FOR THE TASTE OF FLESH.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + return "***" + dialogOptions[randomNumber] + "***"; + + case "ravagerHit": + var dialogOptions = [ + 'STAGGERS BACK', + 'FALLS BACKWARDS', + 'CHARGES FORWARD CONFUSED', + 'LOOKS FOR THE SOURCE OF THE HIT', + 'FALLS FORWARDS', + 'BLOCKS ITS FACE', + 'STUMBLES BACKWARDS IN CONFUSION', + 'LUNGES FORWARD DISTRACTED', + 'BITES AT IT\'S ATTACKER', + 'CHECKS IT\'S WOUND' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + return `***${dialogOptions[randomNumber]}***`; + } +} + +// Log our bot in (change the token by looking into the .env file) +client.login(process.env.RAVAGER_TOKEN); \ No newline at end of file diff --git a/Enemy_Crow/npcSettings.js b/Enemy_Crow/npcSettings.js new file mode 100644 index 0000000..17ec69b --- /dev/null +++ b/Enemy_Crow/npcSettings.js @@ -0,0 +1,9 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + id: "crow", + activity: "Cawing in the distance...", + type: "PLAYING", + token: process.env.CROW_TOKEN, + botChannel: process.env.CRYSTAL_SHORES +} diff --git a/Enemy_Crow/package-lock.json b/Enemy_Crow/package-lock.json new file mode 100644 index 0000000..004bdad --- /dev/null +++ b/Enemy_Crow/package-lock.json @@ -0,0 +1,745 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.1", + "http-errors": "~1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "~2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "~1.6.15" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "combine-middlewares": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/combine-middlewares/-/combine-middlewares-0.1.0.tgz", + "integrity": "sha512-X7A6T6UAH1cULUIhDgvBol2XcvThuVrDMdD2ZPg9FEddEW3KsoKShd1yaRsMIl1v4Aj8dqSfehMXJxD/kwXJ2Q==" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deserialize-error": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/deserialize-error/-/deserialize-error-0.0.3.tgz", + "integrity": "sha1-9WhjNXLXwsxGpVpfwlS23857P8o=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", + "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "~1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.3", + "resolved": "http://registry.npmjs.org/express/-/express-4.16.3.tgz", + "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.3", + "qs": "6.5.1", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + } + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": ">= 1.3.1 < 2" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serialize-error": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=" + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-request": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/socket.io-request/-/socket.io-request-0.8.0.tgz", + "integrity": "sha512-uZXUELbSNMbujTLFr+hGurZM+fhMLJ7fd3ZmM4FjrXXch5Cy9agLx6pBdzGjEdBblmhzj3Buo1SJvTub2VIf5A==", + "requires": { + "combine-middlewares": "^0.1.0", + "deserialize-error": "^0.0.3", + "serialize-error": "^2.0.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/Enemy_Crow/package.json b/Enemy_Crow/package.json new file mode 100644 index 0000000..69163ab --- /dev/null +++ b/Enemy_Crow/package.json @@ -0,0 +1,29 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "description": "Universal package for all SANCTUM bots, using pm2.", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "echo \"Error: you need to use the bot name as a command.\" && exit 1", + "alexis": "pm2 start alexis.js -i max --watch", + "graze": "pm2 start graze.js -i max --watch", + "librarian": "pm2 start librarian.js -i max --watch", + "mainframe": "pm2 start mainframe.js -i max --watch", + "mori": "pm2 start mori.js -i max --watch", + "mosiah": "pm2 start mosiah.js -i max --watch", + "ravager": "pm2 start ravager.js -i max --watch", + "rey": "pm2 start rey.js -i max --watch", + "troll": "pm2 start troll.js -i max --watch" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "express": "^4.16.3", + "node-cron": "^1.2.1", + "socket.io": "^2.1.1", + "socket.io-request": "^0.8.0" + } +} diff --git a/Enemy_Ravager/enemy-ravager.js b/Enemy_Ravager/enemy-ravager.js new file mode 100644 index 0000000..81c43e8 --- /dev/null +++ b/Enemy_Ravager/enemy-ravager.js @@ -0,0 +1,346 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); +const io = require('socket.io-client'); + +// Make connection +var socket = io.connect('http://localhost:80'); + +// Bot Modules +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); + +// State Machine +var RavagerState = { + INACTIVE: 0, + PROWLING: 1, + ACTIVE: 2, + UNCONSCIOUS: 3 +} + +const prowling = 'Prowling...'; + +var socketReady = false; +socket.on('spawn', (data) => { + if (!socketReady) return; + + console.log(JSON.stringify(data, null, 4)); + console.log(`Summoning enemies...`); + + // Spawns + summonEnemy(data); + +}); + +// 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 () => { + socketReady = true; + + // 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('invisible'); + // Sets your "Playing" + client.user.setActivity(prowling); + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); + + // Corrects Ravager username + if (client.user.username == "Raveger") { + const newName = "Ravager"; + console.log("Username is Raveger! Typos are NOT(?) cannon, so better change stuff.\nAttempting rename to " + newName + "..."); + + // Set username + client.user.setUsername(newName) + .then(user => console.log(`Success! New username is now ${user.username}.`)) + .catch(console.error); + + // Changes nickname + client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id).setNickname(""); + } +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + // Message has to be in Outskirts (should be edited later) + if (!(message.channel.id === process.env.DEADLANDS_CHANNEL_ID + || message.channel.id === process.env.TEST_CHANNEL_ID)) return; + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "ping": + if (isAdmin(message.author.id)) + message.reply("***...MRGRGRGR!***"); + break; + } +}); + +client.on('error', console.error); + +cron.schedule('*/10 * * * *', function() { + +}); + +// Turn online and turn offline +async function summonEnemy(data) { + // Scans for Ravager already in channel + /* + var isRavagerInChannel = false; + ravagerCollection.forEach(element => { + if (element.channel === data.channel) { + console.log("There is already a Ravager in channel " + element.channel); + isRavagerInChannel = true; + } + }); + if (isRavagerInChannel) return; + */ + + // If timer exists, do outpost + const summonTime = 4; // 4 is debug, normal is 35 + if (!data.fastSummon) { + console.log(`Summoning Ravager... waiting for ${summonTime} seconds.`); + client.user.setStatus('online'); + client.user.setActivity(`Prowling...`); + + // Sets prowling states on the Ravagers + for (let i = 0; i < data.enemies.length; i++) { + const element = data.enemies[i]; + element.state = RavagerState.PROWLING; + } + + // Notification code + // TODO + + await sleep(summonTime * 1000); + } + console.log("Enemy has spawned!"); + + // Goes thru all enemies in array + for (let i = 0; i < data.enemies.length; i++) { + const element = data.enemies[i]; + const hostileStats = `LVL: ${element.level} | HP: ${element.health} | STR: ${element.strength} | SPD: ${element.speed}`; + + const ravagerMember = client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id); + const appearanceEmbed = new Discord.RichEmbed() + .setAuthor(ravagerMember.displayName, client.user.avatarURL) + .setColor(ravagerMember.displayColor) + .setDescription(`${healthbar(element.health, element.health)}\n` + "```" + hostileStats + "```") + + var newMessage = await client.channels.get(data.channel).send(getDialog("onTheProwl"), {embed: appearanceEmbed}); + await client.user.setStatus('online'); + await client.user.setActivity(hostileStats); + + for (let i = 0; i < data.enemies.length; i++) { + const element = data.enemies[i]; + element.state = RavagerState.ACTIVE; + } + enemyTimer(element, data, data.channel, element.fleeTime, newMessage); + } +} + +// Counts down +async function enemyTimer(newRavager, data, channel, fleeTime, newMessage) { + function addUserToArray(userID) { + attackingUsers.push(userID); + } + + async function sendReactions(options) { + // Sends reactions + for (let i = 0; i < options.length; i++) { + const element = options[i]; + //console.log("[Reaction Options] Emote: " + element + " | newMessage: " + newMessage); + await newMessage.react(element); + } + } + + console.log(`Waiting for the next ${fmtMSS(fleeTime / 1000)} min. to check if Ravager has been killed. ${fleeTime}`); + + const ravagerMember = client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id); + const interactionEmbed = new Discord.RichEmbed() + .setColor(ravagerMember.displayColor) + .setTitle("Status") + .setDescription("...") + + var isReadyToFlee = false; + var attackingUsers = []; + var tempAttackUsers = ""; + var newChannel = client.channels.get(channel); + var interactionMessage = await newChannel.send({embed: interactionEmbed}); + + // Collects emotes and reacts upon the reaction + const collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); + + // Possible reaction attacks can go here + var options = ['🇦', '🇧', '🇨'] + sendReactions(options); + + // Collect + collector.once("collect", async reaction => { + var user = reaction.users.last(); + tempAttackUsers += `${user} :crossed_swords: 11 DAM | <:hitback:460969716580745236> MISS (150/150)\n`; + addUserToArray(user.id); + console.log(tempAttackUsers); + if (!interactionMessage.deleted) { + interactionEmbed.setDescription(`${tempAttackUsers}`); + interactionMessage = await newChannel.edit({embed: interactionEmbed}); + } + + // Send damage. + + }); + + // Ends + collector.once("end", async collector => { + + }); + + // Goes every 4 seconds + var emoteRefresh = setInterval(async () => { + await newMessage.clearReactions(); + interactionEmbed.setDescription("..."); + + if (isReadyToFlee && newRavager.state !== RavagerState.UNCONSCIOUS) { + interactionEmbed.setDescription("👣 The Ravager has fled...") + if (interactionMessage) await interactionMessage.edit({embed: interactionEmbed}); + clearInterval(emoteRefresh); + collector.stop(); + } else { + if (interactionMessage) await interactionMessage.edit({embed: interactionEmbed}); + sendReactions(options); + } + + tempAttackUsers = ""; + }, 5 * 1000); + + + // Waits to see if killed, and if not send a fleeing message + await sleep(fleeTime); + if (newRavager.state === RavagerState.ACTIVE) { + newChannel.send("**YOU ARE WEAK. THERE IS NO CHALLENGE FOR ME HERE.**\n:bangbang:***ATTEMPTING TO FLEE...***"); + await sleep(20 * 1000); + + // If still there despawn + if (newRavager.state !== RavagerState.UNCONSCIOUS) { + console.log('Hostile is now able to flee, now awaiting for collector to finish.'); + isReadyToFlee = true; + } + } +} + +async function flee(newRavager, data, newChannel) { + newChannel.send("**THE POOR, ILL-EQUIPPED TRAVELERS PUT UP NO FIGHT...**\n:footprints:***RETURNS TO THE WILD. ***"); + socket.emit('fled', { + data: data, + ravager: newRavager + }); + + if (data.length < 1) { + await client.user.setPresence('invisible'); + client.user.setActivity('Prowling...'); + } +} + +// Health bar +function healthbar(health, maxHealth) { + var heartHealthAmount = 30; + var printString = ""; + var amountMultiple = 0; + var timesToLoop = Math.floor(maxHealth / heartHealthAmount); + for (var i = 0; i < timesToLoop; i++) { + amountMultiple = i * heartHealthAmount; + if (amountMultiple < health) { + printString += ":heart: "; + } else { + printString += ":black_heart:"; + } + } + printString += " (" + health + "/" + maxHealth + ")"; + return printString; +} + +// Async Waiting +function sleep(time) { + return new Promise((resolve, reject) => { + setTimeout(resolve, time); + }); +} + +// Gets if user has an Overseers rank +function isAdmin(userID) { + var guild = client.guilds.get(process.env.SANCTUM_ID); + return guild.members.get(userID).roles.find(role => role.name === "Overseers"); +} + +// https://stackoverflow.com/questions/3733227/javascript-seconds-to-minutes-and-seconds +function fmtMSS(s){ // accepts seconds as Number or String. Returns m:ss + return( s - // take value s and subtract (will try to convert String to Number) + ( s %= 60 ) // the new value of s, now holding the remainder of s divided by 60 + // (will also try to convert String to Number) + ) / 60 + ( // and divide the resulting Number by 60 + // (can never result in a fractional value = no need for rounding) + // to which we concatenate a String (converts the Number to String) + // who's reference is chosen by the conditional operator: + 9 < s // if seconds is larger than 9 + ? ':' // then we don't need to prepend a zero + : ':0' // else we do need to prepend a zero + ) + s ; // and we add Number s to the string (converting it to String as well) +} + +function getDialog(dialogTag, data = "", data2 = "") { + switch(dialogTag) { + case "onTheProwl": + var dialogOptions = [ + 'THE AIR SMELLS OF BLOOD.', + 'LOOKS LIKE MEAT\'S BACK ON THE MENU BOYS.', + 'FRESH MEAAAATTTT.', + 'TONIGHT WE DINE ON TRAVELER FLESSHHHH.', + 'SKULL CRUSHING IS MY FAVORITE SPORT.', + 'HUNGRY...', + 'TRAVELERS MAKE GOOD MEEEAAAAT!', + 'PUNY TRAVELER THINKS THEY CAN FIGHT?!', + 'HUNT THEM ALL DOWN.', + 'I HUNGER FOR THE TASTE OF FLESH.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + return "***" + dialogOptions[randomNumber] + "***"; + + case "ravagerHit": + var dialogOptions = [ + 'STAGGERS BACK', + 'FALLS BACKWARDS', + 'CHARGES FORWARD CONFUSED', + 'LOOKS FOR THE SOURCE OF THE HIT', + 'FALLS FORWARDS', + 'BLOCKS ITS FACE', + 'STUMBLES BACKWARDS IN CONFUSION', + 'LUNGES FORWARD DISTRACTED', + 'BITES AT IT\'S ATTACKER', + 'CHECKS IT\'S WOUND' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + return `***${dialogOptions[randomNumber]}***`; + } +} + +// Log our bot in (change the token by looking into the .env file) +client.login(process.env.RAVAGER_TOKEN); \ No newline at end of file diff --git a/Enemy_Ravager/npcSettings.js b/Enemy_Ravager/npcSettings.js new file mode 100644 index 0000000..b7bf4de --- /dev/null +++ b/Enemy_Ravager/npcSettings.js @@ -0,0 +1,9 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + name: "ravager", + activity: "Prowling...", + type: "PLAYING", + token: process.env.RAVAGER_TOKEN, + botChannel: process.env.DEADLANDS_CHANNEL_ID +} diff --git a/Enemy_Ravager/package-lock.json b/Enemy_Ravager/package-lock.json new file mode 100644 index 0000000..004bdad --- /dev/null +++ b/Enemy_Ravager/package-lock.json @@ -0,0 +1,745 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.1", + "http-errors": "~1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "~2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "~1.6.15" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "combine-middlewares": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/combine-middlewares/-/combine-middlewares-0.1.0.tgz", + "integrity": "sha512-X7A6T6UAH1cULUIhDgvBol2XcvThuVrDMdD2ZPg9FEddEW3KsoKShd1yaRsMIl1v4Aj8dqSfehMXJxD/kwXJ2Q==" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deserialize-error": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/deserialize-error/-/deserialize-error-0.0.3.tgz", + "integrity": "sha1-9WhjNXLXwsxGpVpfwlS23857P8o=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", + "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "~1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.3", + "resolved": "http://registry.npmjs.org/express/-/express-4.16.3.tgz", + "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.3", + "qs": "6.5.1", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + } + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": ">= 1.3.1 < 2" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serialize-error": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=" + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-request": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/socket.io-request/-/socket.io-request-0.8.0.tgz", + "integrity": "sha512-uZXUELbSNMbujTLFr+hGurZM+fhMLJ7fd3ZmM4FjrXXch5Cy9agLx6pBdzGjEdBblmhzj3Buo1SJvTub2VIf5A==", + "requires": { + "combine-middlewares": "^0.1.0", + "deserialize-error": "^0.0.3", + "serialize-error": "^2.0.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/Enemy_Ravager/package.json b/Enemy_Ravager/package.json new file mode 100644 index 0000000..69163ab --- /dev/null +++ b/Enemy_Ravager/package.json @@ -0,0 +1,29 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "description": "Universal package for all SANCTUM bots, using pm2.", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "echo \"Error: you need to use the bot name as a command.\" && exit 1", + "alexis": "pm2 start alexis.js -i max --watch", + "graze": "pm2 start graze.js -i max --watch", + "librarian": "pm2 start librarian.js -i max --watch", + "mainframe": "pm2 start mainframe.js -i max --watch", + "mori": "pm2 start mori.js -i max --watch", + "mosiah": "pm2 start mosiah.js -i max --watch", + "ravager": "pm2 start ravager.js -i max --watch", + "rey": "pm2 start rey.js -i max --watch", + "troll": "pm2 start troll.js -i max --watch" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "express": "^4.16.3", + "node-cron": "^1.2.1", + "socket.io": "^2.1.1", + "socket.io-request": "^0.8.0" + } +} diff --git a/Enemy_Wolf/enemy-wolf.js b/Enemy_Wolf/enemy-wolf.js new file mode 100644 index 0000000..81c43e8 --- /dev/null +++ b/Enemy_Wolf/enemy-wolf.js @@ -0,0 +1,346 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); +const io = require('socket.io-client'); + +// Make connection +var socket = io.connect('http://localhost:80'); + +// Bot Modules +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); + +// State Machine +var RavagerState = { + INACTIVE: 0, + PROWLING: 1, + ACTIVE: 2, + UNCONSCIOUS: 3 +} + +const prowling = 'Prowling...'; + +var socketReady = false; +socket.on('spawn', (data) => { + if (!socketReady) return; + + console.log(JSON.stringify(data, null, 4)); + console.log(`Summoning enemies...`); + + // Spawns + summonEnemy(data); + +}); + +// 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 () => { + socketReady = true; + + // 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('invisible'); + // Sets your "Playing" + client.user.setActivity(prowling); + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); + + // Corrects Ravager username + if (client.user.username == "Raveger") { + const newName = "Ravager"; + console.log("Username is Raveger! Typos are NOT(?) cannon, so better change stuff.\nAttempting rename to " + newName + "..."); + + // Set username + client.user.setUsername(newName) + .then(user => console.log(`Success! New username is now ${user.username}.`)) + .catch(console.error); + + // Changes nickname + client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id).setNickname(""); + } +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + // Message has to be in Outskirts (should be edited later) + if (!(message.channel.id === process.env.DEADLANDS_CHANNEL_ID + || message.channel.id === process.env.TEST_CHANNEL_ID)) return; + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "ping": + if (isAdmin(message.author.id)) + message.reply("***...MRGRGRGR!***"); + break; + } +}); + +client.on('error', console.error); + +cron.schedule('*/10 * * * *', function() { + +}); + +// Turn online and turn offline +async function summonEnemy(data) { + // Scans for Ravager already in channel + /* + var isRavagerInChannel = false; + ravagerCollection.forEach(element => { + if (element.channel === data.channel) { + console.log("There is already a Ravager in channel " + element.channel); + isRavagerInChannel = true; + } + }); + if (isRavagerInChannel) return; + */ + + // If timer exists, do outpost + const summonTime = 4; // 4 is debug, normal is 35 + if (!data.fastSummon) { + console.log(`Summoning Ravager... waiting for ${summonTime} seconds.`); + client.user.setStatus('online'); + client.user.setActivity(`Prowling...`); + + // Sets prowling states on the Ravagers + for (let i = 0; i < data.enemies.length; i++) { + const element = data.enemies[i]; + element.state = RavagerState.PROWLING; + } + + // Notification code + // TODO + + await sleep(summonTime * 1000); + } + console.log("Enemy has spawned!"); + + // Goes thru all enemies in array + for (let i = 0; i < data.enemies.length; i++) { + const element = data.enemies[i]; + const hostileStats = `LVL: ${element.level} | HP: ${element.health} | STR: ${element.strength} | SPD: ${element.speed}`; + + const ravagerMember = client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id); + const appearanceEmbed = new Discord.RichEmbed() + .setAuthor(ravagerMember.displayName, client.user.avatarURL) + .setColor(ravagerMember.displayColor) + .setDescription(`${healthbar(element.health, element.health)}\n` + "```" + hostileStats + "```") + + var newMessage = await client.channels.get(data.channel).send(getDialog("onTheProwl"), {embed: appearanceEmbed}); + await client.user.setStatus('online'); + await client.user.setActivity(hostileStats); + + for (let i = 0; i < data.enemies.length; i++) { + const element = data.enemies[i]; + element.state = RavagerState.ACTIVE; + } + enemyTimer(element, data, data.channel, element.fleeTime, newMessage); + } +} + +// Counts down +async function enemyTimer(newRavager, data, channel, fleeTime, newMessage) { + function addUserToArray(userID) { + attackingUsers.push(userID); + } + + async function sendReactions(options) { + // Sends reactions + for (let i = 0; i < options.length; i++) { + const element = options[i]; + //console.log("[Reaction Options] Emote: " + element + " | newMessage: " + newMessage); + await newMessage.react(element); + } + } + + console.log(`Waiting for the next ${fmtMSS(fleeTime / 1000)} min. to check if Ravager has been killed. ${fleeTime}`); + + const ravagerMember = client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id); + const interactionEmbed = new Discord.RichEmbed() + .setColor(ravagerMember.displayColor) + .setTitle("Status") + .setDescription("...") + + var isReadyToFlee = false; + var attackingUsers = []; + var tempAttackUsers = ""; + var newChannel = client.channels.get(channel); + var interactionMessage = await newChannel.send({embed: interactionEmbed}); + + // Collects emotes and reacts upon the reaction + const collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); + + // Possible reaction attacks can go here + var options = ['🇦', '🇧', '🇨'] + sendReactions(options); + + // Collect + collector.once("collect", async reaction => { + var user = reaction.users.last(); + tempAttackUsers += `${user} :crossed_swords: 11 DAM | <:hitback:460969716580745236> MISS (150/150)\n`; + addUserToArray(user.id); + console.log(tempAttackUsers); + if (!interactionMessage.deleted) { + interactionEmbed.setDescription(`${tempAttackUsers}`); + interactionMessage = await newChannel.edit({embed: interactionEmbed}); + } + + // Send damage. + + }); + + // Ends + collector.once("end", async collector => { + + }); + + // Goes every 4 seconds + var emoteRefresh = setInterval(async () => { + await newMessage.clearReactions(); + interactionEmbed.setDescription("..."); + + if (isReadyToFlee && newRavager.state !== RavagerState.UNCONSCIOUS) { + interactionEmbed.setDescription("👣 The Ravager has fled...") + if (interactionMessage) await interactionMessage.edit({embed: interactionEmbed}); + clearInterval(emoteRefresh); + collector.stop(); + } else { + if (interactionMessage) await interactionMessage.edit({embed: interactionEmbed}); + sendReactions(options); + } + + tempAttackUsers = ""; + }, 5 * 1000); + + + // Waits to see if killed, and if not send a fleeing message + await sleep(fleeTime); + if (newRavager.state === RavagerState.ACTIVE) { + newChannel.send("**YOU ARE WEAK. THERE IS NO CHALLENGE FOR ME HERE.**\n:bangbang:***ATTEMPTING TO FLEE...***"); + await sleep(20 * 1000); + + // If still there despawn + if (newRavager.state !== RavagerState.UNCONSCIOUS) { + console.log('Hostile is now able to flee, now awaiting for collector to finish.'); + isReadyToFlee = true; + } + } +} + +async function flee(newRavager, data, newChannel) { + newChannel.send("**THE POOR, ILL-EQUIPPED TRAVELERS PUT UP NO FIGHT...**\n:footprints:***RETURNS TO THE WILD. ***"); + socket.emit('fled', { + data: data, + ravager: newRavager + }); + + if (data.length < 1) { + await client.user.setPresence('invisible'); + client.user.setActivity('Prowling...'); + } +} + +// Health bar +function healthbar(health, maxHealth) { + var heartHealthAmount = 30; + var printString = ""; + var amountMultiple = 0; + var timesToLoop = Math.floor(maxHealth / heartHealthAmount); + for (var i = 0; i < timesToLoop; i++) { + amountMultiple = i * heartHealthAmount; + if (amountMultiple < health) { + printString += ":heart: "; + } else { + printString += ":black_heart:"; + } + } + printString += " (" + health + "/" + maxHealth + ")"; + return printString; +} + +// Async Waiting +function sleep(time) { + return new Promise((resolve, reject) => { + setTimeout(resolve, time); + }); +} + +// Gets if user has an Overseers rank +function isAdmin(userID) { + var guild = client.guilds.get(process.env.SANCTUM_ID); + return guild.members.get(userID).roles.find(role => role.name === "Overseers"); +} + +// https://stackoverflow.com/questions/3733227/javascript-seconds-to-minutes-and-seconds +function fmtMSS(s){ // accepts seconds as Number or String. Returns m:ss + return( s - // take value s and subtract (will try to convert String to Number) + ( s %= 60 ) // the new value of s, now holding the remainder of s divided by 60 + // (will also try to convert String to Number) + ) / 60 + ( // and divide the resulting Number by 60 + // (can never result in a fractional value = no need for rounding) + // to which we concatenate a String (converts the Number to String) + // who's reference is chosen by the conditional operator: + 9 < s // if seconds is larger than 9 + ? ':' // then we don't need to prepend a zero + : ':0' // else we do need to prepend a zero + ) + s ; // and we add Number s to the string (converting it to String as well) +} + +function getDialog(dialogTag, data = "", data2 = "") { + switch(dialogTag) { + case "onTheProwl": + var dialogOptions = [ + 'THE AIR SMELLS OF BLOOD.', + 'LOOKS LIKE MEAT\'S BACK ON THE MENU BOYS.', + 'FRESH MEAAAATTTT.', + 'TONIGHT WE DINE ON TRAVELER FLESSHHHH.', + 'SKULL CRUSHING IS MY FAVORITE SPORT.', + 'HUNGRY...', + 'TRAVELERS MAKE GOOD MEEEAAAAT!', + 'PUNY TRAVELER THINKS THEY CAN FIGHT?!', + 'HUNT THEM ALL DOWN.', + 'I HUNGER FOR THE TASTE OF FLESH.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + return "***" + dialogOptions[randomNumber] + "***"; + + case "ravagerHit": + var dialogOptions = [ + 'STAGGERS BACK', + 'FALLS BACKWARDS', + 'CHARGES FORWARD CONFUSED', + 'LOOKS FOR THE SOURCE OF THE HIT', + 'FALLS FORWARDS', + 'BLOCKS ITS FACE', + 'STUMBLES BACKWARDS IN CONFUSION', + 'LUNGES FORWARD DISTRACTED', + 'BITES AT IT\'S ATTACKER', + 'CHECKS IT\'S WOUND' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + return `***${dialogOptions[randomNumber]}***`; + } +} + +// Log our bot in (change the token by looking into the .env file) +client.login(process.env.RAVAGER_TOKEN); \ No newline at end of file diff --git a/Enemy_Wolf/npcSettings.js b/Enemy_Wolf/npcSettings.js new file mode 100644 index 0000000..3236a9e --- /dev/null +++ b/Enemy_Wolf/npcSettings.js @@ -0,0 +1,9 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + id: "wolf", + activity: "OwOing... Totally not placeholder.", + type: "PLAYING", + token: process.env.WOLF_TOKEN, + botChannel: process.env.SEA_OF_FOG_CHANNEL_ID +} diff --git a/Enemy_Wolf/package-lock.json b/Enemy_Wolf/package-lock.json new file mode 100644 index 0000000..004bdad --- /dev/null +++ b/Enemy_Wolf/package-lock.json @@ -0,0 +1,745 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.1", + "http-errors": "~1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "~2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "~1.6.15" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "combine-middlewares": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/combine-middlewares/-/combine-middlewares-0.1.0.tgz", + "integrity": "sha512-X7A6T6UAH1cULUIhDgvBol2XcvThuVrDMdD2ZPg9FEddEW3KsoKShd1yaRsMIl1v4Aj8dqSfehMXJxD/kwXJ2Q==" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deserialize-error": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/deserialize-error/-/deserialize-error-0.0.3.tgz", + "integrity": "sha1-9WhjNXLXwsxGpVpfwlS23857P8o=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", + "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "~1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.3", + "resolved": "http://registry.npmjs.org/express/-/express-4.16.3.tgz", + "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.3", + "qs": "6.5.1", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + } + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": ">= 1.3.1 < 2" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serialize-error": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=" + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-request": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/socket.io-request/-/socket.io-request-0.8.0.tgz", + "integrity": "sha512-uZXUELbSNMbujTLFr+hGurZM+fhMLJ7fd3ZmM4FjrXXch5Cy9agLx6pBdzGjEdBblmhzj3Buo1SJvTub2VIf5A==", + "requires": { + "combine-middlewares": "^0.1.0", + "deserialize-error": "^0.0.3", + "serialize-error": "^2.0.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/Enemy_Wolf/package.json b/Enemy_Wolf/package.json new file mode 100644 index 0000000..69163ab --- /dev/null +++ b/Enemy_Wolf/package.json @@ -0,0 +1,29 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "description": "Universal package for all SANCTUM bots, using pm2.", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "echo \"Error: you need to use the bot name as a command.\" && exit 1", + "alexis": "pm2 start alexis.js -i max --watch", + "graze": "pm2 start graze.js -i max --watch", + "librarian": "pm2 start librarian.js -i max --watch", + "mainframe": "pm2 start mainframe.js -i max --watch", + "mori": "pm2 start mori.js -i max --watch", + "mosiah": "pm2 start mosiah.js -i max --watch", + "ravager": "pm2 start ravager.js -i max --watch", + "rey": "pm2 start rey.js -i max --watch", + "troll": "pm2 start troll.js -i max --watch" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "express": "^4.16.3", + "node-cron": "^1.2.1", + "socket.io": "^2.1.1", + "socket.io-request": "^0.8.0" + } +} diff --git a/Graze/graze.js b/Graze/graze.js new file mode 100644 index 0000000..3bc36b7 --- /dev/null +++ b/Graze/graze.js @@ -0,0 +1,185 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); + +// Bot Modules (stores http requests & random functions respectively) +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); +const channelProcessor = require('../modules/channelProcessor'); + +// State Machine (Uncomment if needed) +/* +var BotEnumState = { + WAITING: 0, + ACTIVE: 1 +} +var botState = BotEnumState.ACTIVE; +*/ + +// 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" + client.user.setActivity('!upgrade | Nanotech Upgrades.'); + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); +}); + +// Error handler +client.on('error', console.error); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + // Message has to be a bot channel (should be edited later) + if (!channelProcessor.isBotChannel(message.channel.id)) return; + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + //handle the command + switch(command) { + case "upgrade": + if (!args[0]) { + //shows upgrade menu + var intro = `${message.author} Hey buddy! Here's what we can upgrade ASAP!`; + var newMessage = "STR - <:cannister:462046687058198530> **1**\n```Permanently upgrades your Strength by 1, so you can hit them Ravagers harder.```\n" + newMessage += "SPD - <:cannister:462046687058198530> **1**\n```Permanently upgrades your Speed by 1, so you can get hit less in battle.```\n" + newMessage += "STAM - <:cannister:462046687058198530> **1**\n```Permanently upgrades your Max Stamina by 1, so you can hit more Ravagers.```\n" + newMessage += "HP - <:cannister:462046687058198530> **1**\n```Permanently upgrades your Max HP by 10, so you can can take those beatings like a champ.```" + //sendMessage(message.channel.id, newMessage); + + // Grabs all parameters from server + var attacker = String(dataRequest.loadServerData("userStats",message.author.id)); + var attackerStatPoints = parseFloat(attacker.split(",")[10]); // Cannisters + const keepersOfTheCityColor = client.guilds.get(process.env.SANCTUM_ID).roles.find(role => role.name === "Keepers of the City").color; + const embed = new Discord.RichEmbed() + .setAuthor("Graze", client.user.avatarURL) + .setColor(keepersOfTheCityColor) + .setTitle("Nanotech Upgrades") + .setDescription(newMessage) + .setFooter(`${message.member.displayName}, you have ${attackerStatPoints} cannisters! Use !upgrade [OPTION] to upgrade that stat!`) + + message.channel.send(intro, embed); + } else { + console.log(args[0]); + //Upgrades stats + var statToUpgrade = String(args[0]); + var numberOfPointsToUpgrade = 1; + var canUpgrade = 0; + var suffix = "point."; + //var statToUpgrade = String(args.split(" ")[0]); + //var numberOfPointsToUpgrade = parseFloat(args.split(" ")[1]); + switch (statToUpgrade.toUpperCase()) { + case "STRENGTH": + statToUpgrade = "STR"; + break; + case "HEALTH": + statToUpgrade = "HP"; + break; + case "STAMINA": + statToUpgrade = "STAM"; + break; + case "SPEED": + statToUpgrade = "SPD"; + break; + } + + switch (statToUpgrade.toUpperCase()) { + case "STR": + numberOfPointsToUpgrade = 1; + canUpgrade = 1; + suffix = "point."; + break; + case "HP": + numberOfPointsToUpgrade = 10; + canUpgrade = 1; + suffix = "points."; + break; + case "SPD": + numberOfPointsToUpgrade = 1; + canUpgrade = 1; + suffix = "point."; + break; + case "STAM": + numberOfPointsToUpgrade = 1; + canUpgrade = 1; + suffix = "point."; + break; + } + if (canUpgrade == 0) { + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Believe me, I wish I could upgrade things like that."); + return; + } + + var upgradeResponse = dataRequest.sendServerData("upgradeStats", statToUpgrade, message.author.id); + if (String(upgradeResponse) == "notEnoughPoints") { + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Hey now, you don't have that many cannisters."); + return; + } + if (String(upgradeResponse) == "failure") { + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Sorry, no can do right now. Come back later though, ok?"); + return; + } + if (String(upgradeResponse) == "success") { + var skillName = ""; + switch (statToUpgrade.toUpperCase()) { + case "STR": + skillName = "strength"; + break; + case "HP": + skillName = "health"; + break; + case "SPD": + skillName = "speed"; + break; + case "STAM": + skillName = "stamina"; + break; + } + sendMessage(message.channel.id, "<@" + message.author.id + "> Sweet! I used your Nanotech Cannister to upgrade your **" + skillName + "** by " + numberOfPointsToUpgrade + " " + suffix); + } + } + break; + }; +}); + +// Send message handler +function sendMessage(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message === undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message; + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); +} + +// Log our bot in (change the token by looking into the .env file) +client.login(process.env.GRAZE_TOKEN); \ No newline at end of file diff --git a/Graze/package-lock.json b/Graze/package-lock.json new file mode 100644 index 0000000..13e221c --- /dev/null +++ b/Graze/package-lock.json @@ -0,0 +1,723 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "combine-middlewares": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/combine-middlewares/-/combine-middlewares-0.1.0.tgz", + "integrity": "sha512-X7A6T6UAH1cULUIhDgvBol2XcvThuVrDMdD2ZPg9FEddEW3KsoKShd1yaRsMIl1v4Aj8dqSfehMXJxD/kwXJ2Q==" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deserialize-error": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/deserialize-error/-/deserialize-error-0.0.3.tgz", + "integrity": "sha1-9WhjNXLXwsxGpVpfwlS23857P8o=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", + "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "~1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serialize-error": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=" + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-request": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/socket.io-request/-/socket.io-request-0.8.0.tgz", + "integrity": "sha512-uZXUELbSNMbujTLFr+hGurZM+fhMLJ7fd3ZmM4FjrXXch5Cy9agLx6pBdzGjEdBblmhzj3Buo1SJvTub2VIf5A==", + "requires": { + "combine-middlewares": "^0.1.0", + "deserialize-error": "^0.0.3", + "serialize-error": "^2.0.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/Graze/package.json b/Graze/package.json new file mode 100644 index 0000000..69163ab --- /dev/null +++ b/Graze/package.json @@ -0,0 +1,29 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "description": "Universal package for all SANCTUM bots, using pm2.", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "echo \"Error: you need to use the bot name as a command.\" && exit 1", + "alexis": "pm2 start alexis.js -i max --watch", + "graze": "pm2 start graze.js -i max --watch", + "librarian": "pm2 start librarian.js -i max --watch", + "mainframe": "pm2 start mainframe.js -i max --watch", + "mori": "pm2 start mori.js -i max --watch", + "mosiah": "pm2 start mosiah.js -i max --watch", + "ravager": "pm2 start ravager.js -i max --watch", + "rey": "pm2 start rey.js -i max --watch", + "troll": "pm2 start troll.js -i max --watch" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "express": "^4.16.3", + "node-cron": "^1.2.1", + "socket.io": "^2.1.1", + "socket.io-request": "^0.8.0" + } +} diff --git a/Librarian/librarian.js b/Librarian/librarian.js new file mode 100644 index 0000000..05f810f --- /dev/null +++ b/Librarian/librarian.js @@ -0,0 +1,132 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); + +// Bot Modules +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); + +// State Machine (Uncomment if needed) +var BotEnumState = { + WAITING: 0, + ACTIVE: 1 +} +var botState = BotEnumState.ACTIVE; + +const playingMessage = 'Scribe of the Codex'; +const breakMessage = "Taking a break..." + +// 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" + client.user.setActivity(playingMessage); + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + // Message has to be in Outskirts (should be edited later) + if (!(message.channel.id === process.env.TAVERN_CHANNEL_ID + || message.channel.id === process.env.TEST_CHANNEL_ID)) return; + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "ping": + if (isAdmin(message.author.id)) + message.reply("Pong!"); + break; + case "summon": + if (isAdmin(message.author.id)) { + console.log("Summon the bot!"); + BotTurnOnline(process.env.TAVERN_CHANNEL_ID); + } + break; + case "vanish": + if (isAdmin(message.author.id)) { + BotTurnOffline(process.env.TAVERN_CHANNEL_ID); + } + break; + } +}); + +client.on('error', console.error); + +// Turn online and turn offline +function BotTurnOnline(channel) { + sendMessage(channel, `Insert Online Message here. \ + \n\n***SOME BOLD AND ITALIC TEXT***`); + client.user.setStatus('online'); + client.user.setActivity(playingMessage); + botState = BotEnumState.ACTIVE; +} + +function BotTurnOffline(channel) { + sendMessage(channel, `Insert Offline Message here. \ + \n\n***SOME BOLD AND ITALIC TEXT***`); + client.user.setStatus('invisible'); + client.user.setActivity(''); + botState = BotEnumState.WAITING; +} + +// You may use cron normally +cron.schedule('* * * * Saturday', function() { + console.log('Saturday join.'); +}); + +// Async Waiting +function sleep(time) { + return new Promise((resolve, reject) => { + setTimeout(resolve, time); + }); +} + +// Gets if user has an Overseers rank +function isAdmin(userID) { + var guild = client.guilds.get(process.env.SANCTUM_ID); + return guild.members.get(userID).roles.find(role => role.name === "Overseers"); +} + +// Send message handler +function sendMessage(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message === undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message; + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); +} + +// Log our bot in (change the token by looking into the .env file) +client.login(process.env.LIBRARIAN_TOKEN); \ No newline at end of file diff --git a/Librarian/package-lock.json b/Librarian/package-lock.json new file mode 100644 index 0000000..13e221c --- /dev/null +++ b/Librarian/package-lock.json @@ -0,0 +1,723 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "combine-middlewares": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/combine-middlewares/-/combine-middlewares-0.1.0.tgz", + "integrity": "sha512-X7A6T6UAH1cULUIhDgvBol2XcvThuVrDMdD2ZPg9FEddEW3KsoKShd1yaRsMIl1v4Aj8dqSfehMXJxD/kwXJ2Q==" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deserialize-error": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/deserialize-error/-/deserialize-error-0.0.3.tgz", + "integrity": "sha1-9WhjNXLXwsxGpVpfwlS23857P8o=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", + "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "~1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serialize-error": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=" + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-request": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/socket.io-request/-/socket.io-request-0.8.0.tgz", + "integrity": "sha512-uZXUELbSNMbujTLFr+hGurZM+fhMLJ7fd3ZmM4FjrXXch5Cy9agLx6pBdzGjEdBblmhzj3Buo1SJvTub2VIf5A==", + "requires": { + "combine-middlewares": "^0.1.0", + "deserialize-error": "^0.0.3", + "serialize-error": "^2.0.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/Librarian/package.json b/Librarian/package.json new file mode 100644 index 0000000..69163ab --- /dev/null +++ b/Librarian/package.json @@ -0,0 +1,29 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "description": "Universal package for all SANCTUM bots, using pm2.", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "echo \"Error: you need to use the bot name as a command.\" && exit 1", + "alexis": "pm2 start alexis.js -i max --watch", + "graze": "pm2 start graze.js -i max --watch", + "librarian": "pm2 start librarian.js -i max --watch", + "mainframe": "pm2 start mainframe.js -i max --watch", + "mori": "pm2 start mori.js -i max --watch", + "mosiah": "pm2 start mosiah.js -i max --watch", + "ravager": "pm2 start ravager.js -i max --watch", + "rey": "pm2 start rey.js -i max --watch", + "troll": "pm2 start troll.js -i max --watch" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "express": "^4.16.3", + "node-cron": "^1.2.1", + "socket.io": "^2.1.1", + "socket.io-request": "^0.8.0" + } +} diff --git a/Mori/mori.js b/Mori/mori.js new file mode 100644 index 0000000..94d6d60 --- /dev/null +++ b/Mori/mori.js @@ -0,0 +1,272 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); + +// Bot Modules (stores http requests & random functions respectively) +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); +const channelProcessor = require('../modules/channelProcessor'); + +var medItems = [0, 1, 2]; +var availableTreatments = []; +var itemCount = 3; +const treatments = [ + // Name | Crystals | HP | Description + /* + ['TREAT','5','15','Heals 15HP immediately. Must have more than 0HP.'], + ['TREATV2','7','%15','Heals to 15% HP immediately. Must have more than 0HP.'], + */ + ['PATCH','10','50','Heals 50HP immediately. Must have more than 0HP.'], + ['PATCHV2','15','%50','Heals to 50% HP immediately. Must have more than 0HP.'], + ['REGEN','20','100','Heals 100HP immediately. Must have more than 0HP.'], + ['REGENV2','25','%100','Heals all HP to maximum immediately. Must have more than 0HP.'], + ['REVIVE','20','25','Brings a traveler back from a KO (0HP) to 25HP immediately.'], + ['REVIVEV2','25','%50','Brings a traveler back from a KO (0HP) to 50% HP immediately.'], + ['REVIVEV3','30','%100','Brings a traveler back from a KO (0HP) to 100% HP immediately.'] +]; + +// 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" + client.user.setActivity('!heal | BioMed Specialist.'); + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); + + resetInventory(itemCount); +}); + +//Revives everyone every morning at 7am PST (server time dependant). +cron.schedule('0 7 * * *', function() { + console.log('Reviving'); + dataRequest.sendServerData("reviveAll",0); + + var dialogOptions = [ + 'Ahhh. Just finished reviving all of our fellow travelers.', + 'Rezing travelers is hard work. <@462708244171718656> 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\' just drink in silence.', + 'Good day. All the travelers are back up. Time for some sleep. Goodnight everybody.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + + client.channels.get(process.env.TAVERN_CHANNEL_ID).startTyping(); + setTimeout(function() { + sendMessage(process.env.TAVERN_CHANNEL_ID, dialogOptions[randomNumber]); + client.channels.get(process.env.TAVERN_CHANNEL_ID).stopTyping(true); + }, calcRandom.random(2500,6000)); + resetInventory(itemCount); +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + // Message has to be in Outskirts (should be edited later) + if (!channelProcessor.isBotChannel(message.channel.id)) return; + // Has to be (prefix)command + if (message.content.indexOf (process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "reset": + if (isAdmin(message.author.id)) + resetInventory(3); + break; + case "heal": + if (!args[0]) { + // Grabs all parameters from server + var attacker = String(dataRequest.loadServerData("userStats",message.author.id)); + var attackerWallet = parseFloat(attacker.split(",")[6]); // Crystals + + var intro = `${message.author} Here's what I've got at the moment. My prices are based on availability, ` + + `it's hard to find stuff these days.`; + var newMessage = ""; + for (var i = 0; i < availableTreatments.length; i++) { + //newMessage += availableTreatments[i][0] + " - **" + availableTreatments[i][1] + "**<:crystals:460974340247257089>\n```" + availableTreatments[i][3] + "```\n"; + newMessage += `${availableTreatments[i][0]} - <:crystals:460974340247257089> **${availableTreatments[i][1]}**\n` + "```" + availableTreatments[i][3] + "```\n"; + } + const keepersOfTheCityColor = client.guilds.get(process.env.SANCTUM_ID).roles.find(role => role.name === "Keepers of the City").color; + const embed = new Discord.RichEmbed() + .setAuthor("Mori", client.user.avatarURL) + .setColor(keepersOfTheCityColor) + .setTitle("BioTech Healing") + .setDescription(newMessage) + .setFooter(`${message.member.displayName}, you have ${attackerWallet} crystals. Use !heal [OPTION] to buy.`) + //sendMessage(message.channel.id, newMessage); + message.channel.send(intro, embed); + } else { + //4815 + var purchase = args[0].toUpperCase(); + var treatmentCost = 0; + var treatmentName = ''; + var treatmentAvailable = false; + for (var i = 0, len = availableTreatments.length; i < len; i++) { + if (availableTreatments[i][0] === purchase) { + treatmentAvailable = true; + treatmentName = availableTreatments[i][0]; + //treatmentCost = availableTreatments[i][1]; + break; + } + } + if (treatmentAvailable) { + var healResponse = String(dataRequest.sendServerData("heal", treatmentCost, message.author.id, treatmentName)); + var response = String(healResponse.split(",")[0]); + var health = String(healResponse.split(",")[1]); + switch (response) { + case "success": + sendMessage(message.channel.id, "<@" + message.author.id + "> I\'ve applied a " + purchase + " via nanotech .\n**-" + treatmentCost + "**<:crystals:460974340247257089> | **" + health + "**HP." ); + break; + case "notEnoughCrystals": + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Sorry, looks like you don\'t have the funds for that." ); + break; + case "cantDoThat": + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Sorry, you don\'t meet the requirements for this procedure." ); + break; + case "youreKnockedOut": + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> You\'re currently knoecked out (0HP). You require a revive procdure to heal immediately, or you can wait until 7 AM UTC when I revive everyone." ); + break; + case "lessThanYourHealth": + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Doing that procedure would put you at less than your current HP." ); + break; + case "fullHealth": + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Looks like you\'re already full health. Why would you want to heal?" ); + break; + case "failure": + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Sorry, not sure I understand what procedure you\'d like to purchase." ); + break; + } + } else{ + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> I don\'t have that type of procedure available." ); + } + } + break; + } +}); + +client.on('error', console.error); + +// Gets if user has an Overseers rank +function isAdmin(userID) { + var guild = client.guilds.get(process.env.SANCTUM_ID); + return guild.members.get(userID).roles.find(role => role.name === "Overseers"); +} + +function resetInventory(itemCount) { + console.log("\nResetting inventory..."); + medItems = []; + availableTreatments = []; + var treatmentsClone = arrayClone(treatments); + var tempnum = 0; + var i = 0; + // DEBUG + //itemCount = treatments.length; + + // Chooses random numbers, in order to pick random heal packs + do { + tempnum = Math.floor(Math.random() * treatments.length); + if (!medItems.includes(tempnum)) { + medItems.push(tempnum); + } + i++; + } + while (medItems.length < itemCount); + + medItems.sort(sortNumber); + message = ""; + var list2 = new Array(); + for (var i = 0; i < medItems.length; i++) { + //console.log('MED ITEM: [' + medItems[i] + '] ADDED'); + availableTreatments.push(treatmentsClone[medItems[i]]); + tempnum = parseFloat(availableTreatments[i][1]); + //console.log(">>> Tempnum: " + tempnum + " | availableTreatments: " + availableTreatments[i][1]); + //console.log(">>> MedItems: " + treatments[medItems[i]] + ""); + // Older Calculations + var multiple = parseFloat(Math.floor(tempnum / 6)); + if (calcRandom.gamble(50)) { + availableTreatments[i][1] = tempnum + multiple; + } else { + availableTreatments[i][1] = tempnum - multiple; + } + + // Specifically for Treat + availableTreatments[i][1] += calcRandom.random(-3, 3); + + console.log(availableTreatments[i][0] + " | Base Cost: " + tempnum + " | HP: " + availableTreatments[i][2] + " | Modifier: " + multiple + " | Final: " + availableTreatments[i][1]); + + message = availableTreatments[i][0] + " - **" + availableTreatments[i][1] + "**<:crystals:460974340247257089>\n```" + availableTreatments[i][3] + "```\n"; + //console.log(message); + } +} + +function sortNumber(a,b) { + return a - b; +} + +// Send message handler +function sendMessage(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message === undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message; + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); +} + +/* +This function is for fixing a bug where an array gets edited, and possibly +causing negative numbers due to my calcRandom +2 -2 change. This will not +work with arrays containing objects (eg. JSON data). +*/ +// https://blog.andrewray.me/how-to-clone-a-nested-array-in-javascript/ +function arrayClone(arr) { + var i, copy; + + if( Array.isArray( arr ) ) { + copy = arr.slice( 0 ); + for( i = 0; i < copy.length; i++ ) { + copy[ i ] = arrayClone( copy[ i ] ); + } + return copy; + } else if( typeof arr === 'object' ) { + throw 'Cannot clone array containing an object!'; + } else { + return arr; + } + +} + + +// Log our bot in (change the token by looking into the .env file) +client.login(process.env.MORI_TOKEN); \ No newline at end of file diff --git a/Mori/package-lock.json b/Mori/package-lock.json new file mode 100644 index 0000000..13e221c --- /dev/null +++ b/Mori/package-lock.json @@ -0,0 +1,723 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "combine-middlewares": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/combine-middlewares/-/combine-middlewares-0.1.0.tgz", + "integrity": "sha512-X7A6T6UAH1cULUIhDgvBol2XcvThuVrDMdD2ZPg9FEddEW3KsoKShd1yaRsMIl1v4Aj8dqSfehMXJxD/kwXJ2Q==" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deserialize-error": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/deserialize-error/-/deserialize-error-0.0.3.tgz", + "integrity": "sha1-9WhjNXLXwsxGpVpfwlS23857P8o=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", + "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "~1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serialize-error": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=" + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-request": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/socket.io-request/-/socket.io-request-0.8.0.tgz", + "integrity": "sha512-uZXUELbSNMbujTLFr+hGurZM+fhMLJ7fd3ZmM4FjrXXch5Cy9agLx6pBdzGjEdBblmhzj3Buo1SJvTub2VIf5A==", + "requires": { + "combine-middlewares": "^0.1.0", + "deserialize-error": "^0.0.3", + "serialize-error": "^2.0.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/Mori/package.json b/Mori/package.json new file mode 100644 index 0000000..69163ab --- /dev/null +++ b/Mori/package.json @@ -0,0 +1,29 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "description": "Universal package for all SANCTUM bots, using pm2.", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "echo \"Error: you need to use the bot name as a command.\" && exit 1", + "alexis": "pm2 start alexis.js -i max --watch", + "graze": "pm2 start graze.js -i max --watch", + "librarian": "pm2 start librarian.js -i max --watch", + "mainframe": "pm2 start mainframe.js -i max --watch", + "mori": "pm2 start mori.js -i max --watch", + "mosiah": "pm2 start mosiah.js -i max --watch", + "ravager": "pm2 start ravager.js -i max --watch", + "rey": "pm2 start rey.js -i max --watch", + "troll": "pm2 start troll.js -i max --watch" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "express": "^4.16.3", + "node-cron": "^1.2.1", + "socket.io": "^2.1.1", + "socket.io-request": "^0.8.0" + } +} diff --git a/Mosiah/mosiah.js b/Mosiah/mosiah.js new file mode 100644 index 0000000..f4b5de1 --- /dev/null +++ b/Mosiah/mosiah.js @@ -0,0 +1,144 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); + +// Bot Modules +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); + +const normalActivity = '!wager | Games of Fortune'; + +// State Machine +var MosiahEnumState = { + WAITING: 0, + GAMBLING: 1 +} +var mosiahState = MosiahEnumState.WAITING; + +// 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); + } + + client.user.setStatus('invisible'); + client.user.setActivity(normalActivity); + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + // Message has to be in Tavern or Test + if (!(message.channel.id === process.env.TAVERN_CHANNEL_ID + || message.channel.id === process.env.TEST_CHANNEL_ID)) return; + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "wager": + if (mosiahState == MosiahEnumState.GAMBLING) + wagerMessage(message, args); + else + message.reply("I'm out and about right now. Don't wanna get found by the wrong peoples."); + break; + case "summon": + if (isAdmin(message.author.id)) MosiahTurnOnline(); + break; + case "vanish": + if (isAdmin(message.author.id)) MosiahTurnOffline(); + break; + case "rigged": + message.channel.send("What are you talkin' about? I may look like it, being an outcaster from the city, but I'd never rip peoples off."); + + // Testing out textadv payment + if (isAdmin(message.author.id)) dataRequest.sendServerData("gambleWon", 50, message.author.id); + break; + } +}); + +client.on('error', console.error); + +// Gets if user has an Overseers rank +function isAdmin(userID) { + var guild = client.guilds.get(process.env.SANCTUM_ID); + return guild.members.get(userID).roles.find(role => role.name === "Overseers"); +} + +function wagerMessage(message, args) { + var amount = Math.floor(args[0]); + var account = dataRequest.loadServerData("account", message.author.id); + if (amount > 0) { + if (amount <= account) { + if (calcRandom.gamble(49)) { + sendMessage(message.channel.id, "<@" + message.author.id + "> Ya got me. Here's your " + amount + " crystals. "); + dataRequest.sendServerData("gambleWon", amount, message.author.id); + } else { + sendMessage(message.channel.id, "<@" + message.author.id + "> Looks like ya lost. Guess I'll keep your " + amount + " crystals. "); + dataRequest.sendServerData("gambleLost", amount, message.author.id); + } + } else { + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Yer a funny one ain't ya. Show me the crystals first."); + } + } else { + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Aww c'mon. You wanna wager me nothin'?"); + } +} + +cron.schedule('0 7 * * Saturday', function(){ + console.log('Saturday join.' + new Date().toLocaleString()); + MosiahTurnOnline(); +}); + +cron.schedule('0 7 * * Sunday', function(){ + console.log('Sunday leave.' + new Date().toLocaleString()); + MosiahTurnOffline(); +}); + +function MosiahTurnOnline() { + client.user.setStatus('online'); + client.channels.get(process.env.TAVERN_CHANNEL_ID).send("*Psst.* Anyone wanna wager a few **<:crystals:460974340247257089> Crystals** with me?"); + mosiahState = MosiahEnumState.GAMBLING; +} + +function MosiahTurnOffline() { + client.user.setStatus('invisible'); + mosiahState = MosiahEnumState.WAITING; +} + +// Send message handler +function sendMessage(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message === undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message; + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); +} + +// Log our bot in +client.login(process.env.MOSIAH_TOKEN); \ No newline at end of file diff --git a/Mosiah/package-lock.json b/Mosiah/package-lock.json new file mode 100644 index 0000000..13e221c --- /dev/null +++ b/Mosiah/package-lock.json @@ -0,0 +1,723 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "combine-middlewares": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/combine-middlewares/-/combine-middlewares-0.1.0.tgz", + "integrity": "sha512-X7A6T6UAH1cULUIhDgvBol2XcvThuVrDMdD2ZPg9FEddEW3KsoKShd1yaRsMIl1v4Aj8dqSfehMXJxD/kwXJ2Q==" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deserialize-error": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/deserialize-error/-/deserialize-error-0.0.3.tgz", + "integrity": "sha1-9WhjNXLXwsxGpVpfwlS23857P8o=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", + "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "~1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serialize-error": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=" + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-request": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/socket.io-request/-/socket.io-request-0.8.0.tgz", + "integrity": "sha512-uZXUELbSNMbujTLFr+hGurZM+fhMLJ7fd3ZmM4FjrXXch5Cy9agLx6pBdzGjEdBblmhzj3Buo1SJvTub2VIf5A==", + "requires": { + "combine-middlewares": "^0.1.0", + "deserialize-error": "^0.0.3", + "serialize-error": "^2.0.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/Mosiah/package.json b/Mosiah/package.json new file mode 100644 index 0000000..69163ab --- /dev/null +++ b/Mosiah/package.json @@ -0,0 +1,29 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "description": "Universal package for all SANCTUM bots, using pm2.", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "echo \"Error: you need to use the bot name as a command.\" && exit 1", + "alexis": "pm2 start alexis.js -i max --watch", + "graze": "pm2 start graze.js -i max --watch", + "librarian": "pm2 start librarian.js -i max --watch", + "mainframe": "pm2 start mainframe.js -i max --watch", + "mori": "pm2 start mori.js -i max --watch", + "mosiah": "pm2 start mosiah.js -i max --watch", + "ravager": "pm2 start ravager.js -i max --watch", + "rey": "pm2 start rey.js -i max --watch", + "troll": "pm2 start troll.js -i max --watch" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "express": "^4.16.3", + "node-cron": "^1.2.1", + "socket.io": "^2.1.1", + "socket.io-request": "^0.8.0" + } +} diff --git a/README.md b/README.md index f8b54d4..33ad56e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,52 @@ -# SANCTUM -The SANCTUM Discord MMO repository! https://discord.gg/D7dyrVn +# ![SANCTUM Logo](https://i.imgur.com/yZI3Am9.png) SANCTUM +[![SANCTUM Discord](https://img.shields.io/badge/sanctum-discord-%237289DA.svg?logo=discord)](https://discord.gg/D7dyrVn) +[![SANCTUM Developers](https://img.shields.io/badge/sanctum-developers-%237289DA.svg?logo=discord)](https://discord.gg/mP98ZYv) +# What is SANCTUM? +SANCTUM is an open-source Discord MMO, with 200+ players. + +- [Discord Game Invite Link](https://discord.gg/D7dyrVn) +- [Developer's Discord](https://discord.gg/mP98ZYv) + +# Run the bots +## Requirements: +You will need: +- [Node.js](https://nodejs.org/en/) (recommended v8.12.0 LTS) + +## Steps +1. Clone the repo. + + You can use programs like [Git](https://git-scm.com/), [SourceTree](https://www.sourcetreeapp.com/) or simply download the project, although you won't be able to submit changes as easily. + +2. Rename the `.envdev` file to `.env`, and fill out tokens and channels. + + Make sure you save it, and also don't push any of your tokens here! If you do though, consider them comprimised and then reset them. + +3. Navigate via command-line to a bot's folder, install dependancies, and run it! + + Make sure you're in the project folder! + On Windows, you can hold Shift and Right Click the folder to get the option of a command prompt, inside that folder. + ```bash + # You have to be in the project folder first to navigate through it + cd "A.D.A.M." + npm i + node adam.js + ``` + +4. ??? + +5. Profit! You did it, unless something has happened along the way. ~~Probably likely, sadly.~~ + +## Quality of Life + +We recommend [nodemon](https://nodemon.io/) for reloading bots automatically, instead of `Ctrl+C`ing in and out of bots when you need a restart. + +# Join the SANCTUM Development Team +We're looking for: +- Discord.js and/or PHP programmers +- Artists +- Writers +- Designers +- Producers +- and Testers! + +Join the [SANCTUM Developers](https://discord.gg/mP98ZYv) Discord for more info! diff --git a/Rey/package-lock.json b/Rey/package-lock.json new file mode 100644 index 0000000..13e221c --- /dev/null +++ b/Rey/package-lock.json @@ -0,0 +1,723 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "combine-middlewares": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/combine-middlewares/-/combine-middlewares-0.1.0.tgz", + "integrity": "sha512-X7A6T6UAH1cULUIhDgvBol2XcvThuVrDMdD2ZPg9FEddEW3KsoKShd1yaRsMIl1v4Aj8dqSfehMXJxD/kwXJ2Q==" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deserialize-error": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/deserialize-error/-/deserialize-error-0.0.3.tgz", + "integrity": "sha1-9WhjNXLXwsxGpVpfwlS23857P8o=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", + "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "~1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serialize-error": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=" + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-request": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/socket.io-request/-/socket.io-request-0.8.0.tgz", + "integrity": "sha512-uZXUELbSNMbujTLFr+hGurZM+fhMLJ7fd3ZmM4FjrXXch5Cy9agLx6pBdzGjEdBblmhzj3Buo1SJvTub2VIf5A==", + "requires": { + "combine-middlewares": "^0.1.0", + "deserialize-error": "^0.0.3", + "serialize-error": "^2.0.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/Rey/package.json b/Rey/package.json new file mode 100644 index 0000000..69163ab --- /dev/null +++ b/Rey/package.json @@ -0,0 +1,29 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "description": "Universal package for all SANCTUM bots, using pm2.", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "echo \"Error: you need to use the bot name as a command.\" && exit 1", + "alexis": "pm2 start alexis.js -i max --watch", + "graze": "pm2 start graze.js -i max --watch", + "librarian": "pm2 start librarian.js -i max --watch", + "mainframe": "pm2 start mainframe.js -i max --watch", + "mori": "pm2 start mori.js -i max --watch", + "mosiah": "pm2 start mosiah.js -i max --watch", + "ravager": "pm2 start ravager.js -i max --watch", + "rey": "pm2 start rey.js -i max --watch", + "troll": "pm2 start troll.js -i max --watch" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "express": "^4.16.3", + "node-cron": "^1.2.1", + "socket.io": "^2.1.1", + "socket.io-request": "^0.8.0" + } +} diff --git a/Rey/rey.js b/Rey/rey.js new file mode 100644 index 0000000..572c921 --- /dev/null +++ b/Rey/rey.js @@ -0,0 +1,241 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); +const request = require('sync-request'); + +// Bot Modules +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); + +// State Machine +var ReyEnumState = { + WAITING: 0, + SCAVENGING: 1 +} +var reyState = ReyEnumState.WAITING; + +// 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); + } + + client.user.setStatus('invisible'); + client.user.setActivity(''); + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + // Message has to be in Outskirts or Test + if (!(message.channel.id === process.env.OUTSKIRTS_CHANNEL_ID + || message.channel.id === process.env.TEST_CHANNEL_ID)) return; + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "scavenge": + scavengeMessage(message); + break; + case "s": + scavengeMessage(message); + break; + case "materials": + materialsMessage(message, args); + break; + case "m": + materialsMessage(message, args); + break; + case "summon": + if (message.author.id === '200340393596944384' || message.author.id === '163770616581718017') + ReySpawnTimer(process.env.OUTSKIRTS_CHANNEL_ID); + break; + case "vanish": + if (message.author.id === '200340393596944384' || message.author.id === '163770616581718017') + ReyTurnOffline(process.env.OUTSKIRTS_CHANNEL_ID); + break; + } +}); + +client.on('error', console.error); + +function scavengeMessage(message) { + if (reyState == ReyEnumState.SCAVENGING) { + scavenge(message.author.id, message.channel.id); + } else { + // Tell that Rey is out of the city + message.reply("I'm out of the city for a while. I'll be back later!"); + } +} + +function materialsMessage(message, args) { + if (args[0] === undefined) { + var scavengeResponse = String(dataRequest.loadServerData("artifactsGet", message.author.id)); + var items = scavengeResponse.split(","); + var response = items[0]; + var ultrarare = parseFloat(items[1]); + var rare = parseFloat(items[2]); + var uncommon = parseFloat(items[3]); + var common = parseFloat(items [4]); + var scrap = parseFloat(items[5]); + var totalQuantity = ultrarare + rare + uncommon + common + scrap; + + if (response == "success"){ + if (totalQuantity > 0) { + var messageContent = "<@" + message.author.id + "> ***Here\'s what you found so far:***\n\n"; + if (scrap > 0) { messageContent += "<:scrap:463436564379336715> **" + scrap + "**\t\t"; } + if (common > 0) { messageContent += "<:mcloth:462682568483930123> **" + common + "**\t\t"; } + if (uncommon > 0) { messageContent += "<:mmetal:462682568920137728> **" + uncommon + "**\t\t"; } + if (rare > 0) { messageContent += "<:melectronics:462682568911749120> **" + rare + "**\t\t"; } + if (ultrarare > 0) { messageContent += "<:mgem:462450060718768148> **" + ultrarare + "**\n\n"; } + sendMessage(message.channel.id, messageContent); + } else { + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Looks like you don\'t have any materials yet. Help me out on a ***!scavenge***."); + } + } else { + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Sorry, something went wrong. Give me a minute."); + } + } else { + sendMessage(message.channel.id, ":x: <@" + message.author.id + "> Sorry, not sure what you want me to do."); + } +} + +//cron.schedule('*/10 * * * *', function() { +cron.schedule('0 */2 * * *', function() { + console.log('Running 2 hourly process...'); + if (reyState == ReyEnumState.WAITING) { + ReySpawnTimer(process.env.OUTSKIRTS_CHANNEL_ID); + } +}); + +// Async Waiting +function sleep(time) { + return new Promise((resolve, reject) => { + setTimeout(resolve, time); + }); +} + +// Rey spawn timer +async function ReySpawnTimer(channel) { + // Random from 6 sec up to 15 min + var startTime = calcRandom.random(6000, 20 * 60 * 1000); + //var startTime = 0; + await sleep(startTime); + + client.user.setStatus('online'); + client.user.setActivity('Scavenging...'); + sendMessage(channel, `***Hey y\'all! Let's scavenge us some materials!***\ + \nUse !scavenge to get some materials for **3** <:crystals:460974340247257089> and **1 STAM**.`); + reyState = ReyEnumState.SCAVENGING; + + // Start time plus another 6 - 10 min + //var leaveTime = startTime + (2 * 60 * 1000); // Debug 2 Minute Mode + var leaveTime = calcRandom.random(6 * 60 * 1000, 10 * 60 * 1000); + await sleep(leaveTime); + + sendMessage(channel, "Getting ready to pack up here, I think we found enough.\n\n:warning: ***LAST CALL!***"); + await sleep(30000); + ReyTurnOffline(channel); +} + +function ReyTurnOffline(channel) { + sendMessage(channel, `Alright ladies and gents... I'm out of here. Nice finding stuff with y'all! \ + \n\n:v: ***HEADS BACK TO THE CITY***`); + client.user.setStatus('invisible'); + client.user.setActivity(''); + reyState = ReyEnumState.WAITING; +} + +// Scavenge logic +function scavenge(userID, channelID) { + var attacker = String(dataRequest.loadServerData("userStats", userID)); + var attackerStamina = parseFloat(attacker.split(",")[2]); + var attackerHealth = parseFloat(attacker.split(",")[3]); + var attackerWallet = parseFloat(attacker.split(",")[6]); + + var staminaCost = 1; + var crystalCost = 3; + if (attackerHealth > 0) { + if (attackerStamina >= staminaCost) { + if (attackerWallet >= crystalCost) { + var scavengeResponse = String(dataRequest.sendServerData("scavenge", staminaCost, userID, crystalCost)); + var items = scavengeResponse.split(","); + var response = parseFloat(items[0]); + var ultrarare = parseFloat(items[1]); + var rare = parseFloat(items[2]); + var uncommon = parseFloat(items[3]); + var common = parseFloat(items [4]); + var scrap = parseFloat(items[5]); + + var dialogOptions = [ + 'Hey that works!', + 'That\'s interesting... Should be able to use that.', + 'That\'s really useful.', + 'Great find!', + 'Wish I found as much stuff as you.', + 'You\'re on a roll here.', + 'You\'re better than me at this!', + 'Nice! Should fetch you a pretty penny.', + 'That\'s awesome.', + 'You\'re good at this.' + ]; + + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + var message = "<@" + userID + "> \t\t"; + message += "<:crystals:460974340247257089> **-" + crystalCost + "**\t\t" + if (scrap > 0) { message += "<:scrap:463436564379336715> **+" + scrap + "**\t\t"; } + if (common > 0) { message += "<:mcloth:462682568483930123> **+" + common + "**\t\t"; } + if (uncommon > 0) { message += "<:mmetal:462682568920137728> **+" + uncommon + "**\t\t"; } + if (rare > 0) { message += "<:melectronics:462682568911749120> **+" + rare + "**\t\t"; } + if (ultrarare > 0) { message += "<:mgem:462450060718768148> **+" + ultrarare + "**\n\n"; } + message += "\n***" + dialogOptions[randomNumber] + "*** \n" + sendMessage(channelID, message); + } else { + sendMessage(channelID, ":x: <@" + userID + "> You don\'t have enough crystals to sustain you while you\'re out. Bad idea."); + } + } else { + sendMessage(channelID, ":x: <@" + userID + "> You don\'t have enough stamina for that right now. You should probably get some rest."); + } + } else { + sendMessage(channelID, ":x: <@" + userID + "> You\'re in really bad shape... You should go see <@461294299515191306> before you go on a scavenge."); + } +} + + +// Send message handler +function sendMessage(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message === undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message; + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); +} + +// Log our bot in +client.login(process.env.REY_TOKEN); \ No newline at end of file diff --git a/TextAdv/dungeonClass.js b/TextAdv/dungeonClass.js new file mode 100644 index 0000000..ad1dac4 --- /dev/null +++ b/TextAdv/dungeonClass.js @@ -0,0 +1,11 @@ +// Dungeons +module.exports = class DungeonRaidInstance { + constructor(room, players) { + this.room = room; + this.players = players; + this.location; + this.state = DungeonState.WAITING_FOR_USERS; + this.dialogObj; + this.isTyping; + } +} \ No newline at end of file diff --git a/TextAdv/package-lock.json b/TextAdv/package-lock.json new file mode 100644 index 0000000..29e0d24 --- /dev/null +++ b/TextAdv/package-lock.json @@ -0,0 +1,69 @@ +{ + "name": "nodejs-elasticbeanstalk", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.0.0.tgz", + "integrity": "sha512-FlWbnhgjtwD+uNLUGHbMykMOYQaTivdHEmYwAKFjn6GKe/CqY0fNae93ZHTd20snh9ZLr8mTzIL9m0APQ1pjQg==" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "ws": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + } + } +} diff --git a/TextAdv/package.json b/TextAdv/package.json new file mode 100644 index 0000000..076ef32 --- /dev/null +++ b/TextAdv/package.json @@ -0,0 +1,18 @@ +{ + "name": "nodejs-elasticbeanstalk", + "version": "1.0.0", + "description": "", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "node-cron": "^1.2.1" + }, + "devDependencies": {} +} diff --git a/TextAdv/playerClass.js b/TextAdv/playerClass.js new file mode 100644 index 0000000..2704532 --- /dev/null +++ b/TextAdv/playerClass.js @@ -0,0 +1,57 @@ +module.exports = class PlayerClass { + constructor (userID, factionID, combatClass, badge, leader) { + this.userID = userID; + this.factionID = factionID; + this.combatClass = combatClass; + this.badge = badge; + this.leader = leader; + this.commander; + } + + get factionEmote() { + //server.members.get(factionID).roles.has(process.env.GROUP_A_ROLE) + // Obsidian Tech + if (this.factionID === process.env.GROUP_A_ROLE) { + return "<:anarchy:460990297099337750>" + // Genesis Command + } else if (this.factionID === process.env.GROUP_B_ROLE) { + return "<:order:460991638152413194>"; + // The Hand + } else if (this.factionID === process.env.GROUP_C_ROLE) { + return "<:religionhand:461582719051104276>" + // No faction + } else if (this.factionID === "none") { + return ":beginner:"; + // Unknown + } else { + return ":grey_question:"; + } + } + + // Combat Class emote + get combatClassEmote() { + if (this.combatClass.toLowerCase() === "tank") { + return ":shield:"; + } else if (this.combatClass.toLowerCase() === "rogue") { + return ":dagger:"; + } else if (this.combatClass.toLowerCase() === "dps melee") { + return ":crossed_swords:"; + } else if (this.combatClass.toLowerCase() === "support") { + return ":heart:"; + } else if (this.combatClass.toLowerCase() === "dps range") { + return ":bow_and_arrow:"; + } else { + return ":grey_question:"; + } + } + + get isLeaderText() { + if (this.leader) { + return "(Leader)"; + } else if (this.commander) { + return "(Commander)"; + } else { + return ""; + } + } +} \ No newline at end of file diff --git a/TextAdv/rooms.json b/TextAdv/rooms.json new file mode 100644 index 0000000..f3d45fe --- /dev/null +++ b/TextAdv/rooms.json @@ -0,0 +1,746 @@ +{ + "rooms": ["hellsgate"], + "items": { + "key": { + "name": "Key", + "emote": ":key:", + "info": "The key unlocks chests and certain doors.", + "amount": 1, + "dungeonOnly": true + }, + "dungeon_key": { + "name": "Dungeon Key", + "emote": ":key2:", + "info": "It's the dungeon key for moving down the floors.", + "amount": 1, + "dungeonOnly": true + }, + "crystals": { + "name": "Crystals", + "emote": "<:crystals:460974340247257089>", + "internal": true + } + }, + "hellsgate": { + "name": "Hell's Gate", + "id": "hellsgate", + "channel": "464238060243124245", + "color": "#e67e22", + "entrance": { + "name": "Dungeon Entrance", + "descriptions": [ + { "text": "The entrance is a bunch of code cobbled together to make a half-working mass of \"Dungeon\". Hopefully it doesn't kill you, or the party." }, + { "text": "\nThere is a tired **!traveler** that seemed to have learned that idea all too well, try talking to him." } + ], + "image_url": "https://dummyimage.com/800x400/241f1a/e82525.png&text=Room", + "northtext": "Move **!north** to enter the dungeon.", + "easttext": "", + "southtext": "", + "westtext": "", + "floor": 1, + "connections": { + "north": "room_1" + }, + "traveler": { + "npc": true, + "command": true, + "name": "Traveler", + "descriptions": [ + { "waitBegin": 2000, "waitEnd": 1000, "text": "Hello ${leader}, be careful in there." }, + { "waitBegin": 2000, "waitEnd": 1000, "text": "There's a few deadly Ravagers that hurt me real bad." }, + { "waitBegin": 2000, "waitEnd": 1000, "text": "Hopefully you're all in top shape, right?" } + ], + "optionsDescription": { "waitBegin": 800, "waitEnd": 0, "text": "**!yes** or **!no**?" }, + "options": [ + {"command": "yes", "emote": "✅"}, + {"command": "no", "emote": "❌"} + ], + "yes": { + "command": true, + "name": "Traveler", + "descriptions": [ + { "waitBegin": 3000, "waitEnd": 2000, "text": "Good to know, hopefully you can walk out alive. Wish you luck!" } + ], + "lastCommand": true + }, + "no": { + "command": true, + "name": "Traveler", + "descriptions": [ + { "waitBegin": 3000, "waitEnd": 2000, "text": "Oh... well good luck anyhow. If you just want to bail out, just **!leave**. You won't get your **<:crystals:460974340247257089> Crystals** back, though." } + ], + "lastCommand": true + } + } + }, + "room_1": { + "name": "Dungeon Room", + "descriptions": [ + {"text": "You can feel the hot air hitting your face entering. Hot lava is seeping out of the rocks. You should watch your step." } + ], + "image_url": "https://dummyimage.com/800x400/241f1a/e82525.png&text=Dungeon+Room", + "northtext": "You can hear loud groans **!north** that don't sound human, ", + "easttext": "", + "southtext": "Go back with **!south**, ", + "westtext": "or investigate the chest down **!west**.", + "floor": 1, + "connections": { + "north": "ravager_room_1", + "south": "entrance", + "west": "locked_chest_room_1" + } + }, + "locked_chest_room_1": { + "name": "A Locked Chest", + "descriptions": [ + {"text": "You found a locked **!chest**! Wonder what lies inside it. Hopefully there is something valuable."} + ], + "image_url": "https://dummyimage.com/800x400/593521/f5c91b.png&text=Chest", + "northtext": "", + "easttext": "Leave the chest by typing **!east**.", + "southtext": "", + "westtext": "", + "floor": 1, + "connections": { + "east": "room_1" + }, + "chest": { + "command": true, + "type": "chest", + "removeItem": ["key"], + "embed": { + "formatting": "author_title_image_desc", + "setAuthor": {"title": "${dungeon.room.name}", "image": "${profile_pic}"}, + "setTitle": "A Locked Chest", + "setDescription": "This chest requires a **:key: Key** to open.\n**:closed_lock_with_key: Unlock** chest with the key.\n:lock_with_ink_pen: **Lockpick** chest, and risk breaking the lock.\n:x: **Exit** options for the chest.", + "waitBegin": 0, + "waitEnd": 0 + }, + "options": [ + {"command": "unlock", "emote": "🔐"}, + {"command": "lockpick", "emote": "🔏"}, + {"command": "exit", "emote": "❌"} + ], + "unlock": { + "command": true, + "internal": true, + "type": "chest", + "moveFrom": "locked_chest_room_1", + "moveTo": "empty_chest_room_1", + "required": ["key"], + "objects": [ + [ + { + "name": "crystals", + "amount": [5, 10] + } + ], + [ + { + "name": "crystals", + "amount": [18, 22] + } + ] + ] + }, + "lockpick": { + "command": true, + "internal": true, + "type": "chest", + "moveFrom": "locked_chest_room_1", + "moveToFail": "broken_chest_room_1", + "moveTo": "empty_chest_room_1" + }, + "exit": { + "command": true, + "internal": true, + "type": "chest", + "moveTo": "locked_chest_room_1" + } + } + }, + "empty_chest_room_1": { + "name": "An Empty Chest", + "descriptions": [ + {"text": "You have already opened this chest."} + ], + "image_url": "https://dummyimage.com/800x400/593521/f5c91b.png&text=Chest+(Opened)", + "northtext": "", + "easttext": "Leave the chest by typing **!east**.", + "southtext": "", + "westtext": "", + "floor": 1, + "connections": { + "east": "room_1" + } + }, + "broken_chest_room_1": { + "name": "A Broken Chest", + "descriptions": [ + {"text": "This chest has failed to be lockpicked, and cannot be opened."} + ], + "image_url": "https://dummyimage.com/800x400/593521/f5c91b.png&text=Chest+(Broken)", + "northtext": "", + "easttext": "Leave the chest by typing **!east**.", + "southtext": "", + "westtext": "", + "floor": 1, + "connections": { + "east": "room_1" + } + }, + "ravager_room_1": { + "name": "Ravager Room", + "descriptions": [ + {"text": "You found a starving <@458036985353732097>, that hasn't feasted on a traveler for days."} + ], + "image_url": "https://dummyimage.com/800x400/e62b4a/422626.png&text=Ravager", + "northtext": "", + "easttext": "To the party's **!east**, you can see something shiny. ", + "southtext": "Move **!south** to go back. ", + "westtext": "Move **!west** to enter another room.", + "floor": 1, + "ravager": { + "level": [4, 5] + }, + "connections": { + "east": "key_room_1", + "south": "room_1", + "west": "room_2" + } + }, + "key_room_1": { + "name": "A Key", + "descriptions": [ + {"text": "You found a **!key**! You should pick it up."} + ], + "objects": ["key"], + "image_url": "https://dummyimage.com/800x400/73778a/faf5f5.png&text=Key", + "northtext": "", + "easttext": "", + "southtext": "", + "westtext": "Go back with **!west**", + "floor": 1, + "connections": { + "west": "ravager_room_1" + }, + "key": { + "command": "true", + "internal": "true", + "moveTo": "empty_key_room_1", + "moveFrom": "key_room_1", + "pickup": [ + {"item": "key"} + ] + } + }, + "empty_key_room_1": { + "name": "A Key", + "descriptions": [ + {"text": "The key here has been picked up."} + ], + "image_url": "https://dummyimage.com/800x400/73778a/faf5f5.png&text=Key", + "northtext": "", + "easttext": "", + "southtext": "", + "westtext": "Go back with **!west**", + "floor": 1, + "connections": { + "west": "ravager_room_1" + } + }, + "room_2": { + "name": "Dungeon Room", + "descriptions": [ + {"text": "Two rooms can be seen ahead, both with chests."} + ], + "image_url": "https://dummyimage.com/800x400/241f1a/e82525.png&text=Dungeon+Room", + "northtext": "Move **!north** to go to another room with another groan. ", + "easttext": "Back **!east** is a room filled with unconscious ones. ", + "southtext": "", + "westtext": "Move **!west** to check out another chest.", + "floor": 1, + + "connections": { + "north": "ravager_room_2", + "east": "ravager_room_1", + "west": "locked_chest_room_2" + } + }, + "locked_chest_room_2": { + "name": "A Locked Chest", + "descriptions": [ + {"text": "You found a locked **!chest**! Wonder what lies inside it. Hopefully there is something valuable."} + ], + "image_url": "https://dummyimage.com/800x400/593521/f5c91b.png&text=Chest", + "northtext": "", + "easttext": "Leave the chest by typing **!east**.", + "southtext": "", + "westtext": "", + "floor": 1, + "connections": { + "east": "room_2" + }, + "chest": { + "command": true, + "type": "chest", + "removeItem": ["key"], + "embed": { + "formatting": "author_title_image_desc", + "setAuthor": {"title": "${dungeon.room.name}", "image": "${profile_pic}"}, + "setTitle": "A Locked Chest", + "setDescription": "This chest requires a **:key: Key** to open.\n**:closed_lock_with_key: Unlock** chest with the key.\n:lock_with_ink_pen: **Lockpick** chest, and risk breaking the lock.\n:x: **Exit** options for the chest.", + "waitBegin": 0, + "waitEnd": 0 + }, + "options": [ + {"command": "unlock", "emote": "🔐"}, + {"command": "lockpick", "emote": "🔏"}, + {"command": "exit", "emote": "❌"} + ], + "unlock": { + "command": true, + "internal": true, + "type": "chest", + "moveFrom": "locked_chest_room_2", + "moveTo": "empty_chest_room_2", + "required": ["key"], + "objects": [ + [ + { + "name": "crystals", + "amount": [5, 10] + } + ], + [ + { + "name": "crystals", + "amount": [18, 22] + } + ] + ] + }, + "lockpick": { + "command": true, + "internal": true, + "type": "chest", + "moveFrom": "locked_chest_room_2", + "moveToFail": "broken_chest_room_2", + "moveTo": "empty_chest_room_2" + }, + "exit": { + "command": true, + "internal": true, + "type": "chest", + "moveTo": "locked_chest_room_2" + } + } + }, + "empty_chest_room_2": { + "name": "An Empty Chest", + "descriptions": [ + {"text": "You have already opened this chest."} + ], + "image_url": "https://dummyimage.com/800x400/593521/f5c91b.png&text=Chest+(Opened)", + "northtext": "", + "easttext": "Leave the chest by typing **!east**.", + "southtext": "", + "westtext": "", + "floor": 1, + "connections": { + "east": "room_2" + } + }, + "broken_chest_room_2": { + "name": "A Broken Chest", + "descriptions": [ + {"text": "This chest has failed to be lockpicked, and cannot be opened."} + ], + "image_url": "https://dummyimage.com/800x400/593521/f5c91b.png&text=Chest+(Broken)", + "northtext": "", + "easttext": "Leave the chest by typing **!east**.", + "southtext": "", + "westtext": "", + "floor": 1, + "connections": { + "east": "room_2" + } + }, + "ravager_room_2": { + "name": "Ravager Room", + "descriptions": [ + {"text": "You found another <@458036985353732097>!"} + ], + "image_url": "https://dummyimage.com/800x400/e62b4a/422626.png&text=Ravager", + "northtext": "Move **!north** to find a key. ", + "easttext": "", + "southtext": "Move **!south** to go back. ", + "westtext": "", + "floor": 1, + "ravager": { + "level": [6, 7] + }, + "connections": { + "north": "key_room_2", + "south": "room_2" + } + }, + "key_room_2": { + "name": "A Key", + "descriptions": [ + {"text": "You found a **!key**! You should pick it up."} + ], + "objects": ["key"], + "image_url": "https://dummyimage.com/800x400/73778a/faf5f5.png&text=Key", + "northtext": "", + "easttext": "Snarls are coming from the **!east**. ", + "southtext": "Go back with **!south**. ", + "westtext": "There's another key down **!west**, but at a distance it looks oddly different.", + "floor": 1, + "connections": { + "east": "ravager_room_3", + "west": "dungeon_key_room_1", + "south": "ravager_room_2" + }, + "key": { + "command": "true", + "internal": "true", + "moveTo": "empty_key_room_2", + "moveFrom": "key_room_2", + "pickup": [ + {"item": "key"} + ] + } + }, + "empty_key_room_2": { + "name": "A Key", + "descriptions": [ + {"text": "The key here has been picked up."} + ], + "image_url": "https://dummyimage.com/800x400/73778a/faf5f5.png&text=Key", + "northtext": "", + "easttext": "Snarls are coming from the **!east**. ", + "southtext": "Go back with **!south**. ", + "westtext": "There's another key down **!west**, but at a distance it looks oddly different.", + "floor": 1, + "connections": { + "east": "ravager_room_3", + "west": "dungeon_key_room_1", + "south": "ravager_room_2" + } + }, + "dungeon_key_room_1": { + "name": "The Dungeon Key", + "descriptions": [ + {"text": "You found the dungeon **!key**! This item will be important later, likely."} + ], + "objects": ["key"], + "image_url": "https://dummyimage.com/800x400/555b66/a9b4c9.png&text=+Dungeon+Key", + "northtext": "", + "easttext": "Go back with **!east**.", + "southtext": "", + "westtext": "", + "floor": 1, + "connections": { + "east": "key_room_2" + }, + "key": { + "command": "true", + "internal": "true", + "moveTo": "empty_dungeon_key_room_1", + "moveFrom": "dungeon_key_room_1", + "pickup": [ + {"item": "dungeon_key"}, + {"item": "crystals", "amount": [3, 5]} + ] + } + }, + "empty_dungeon_key_room_1": { + "name": "The Dungeon Key", + "descriptions": [ + {"text": "The dungeon key here has been picked up."} + ], + "objects": ["key"], + "image_url": "https://dummyimage.com/800x400/555b66/a9b4c9.png&text=+Dungeon+Key", + "northtext": "", + "easttext": "Go back with **!east**.", + "southtext": "", + "westtext": "", + "floor": 1, + "connections": { + "east": "key_room_2" + } + }, + "ravager_room_3": { + "name": "Ravager Room", + "descriptions": [ + {"text": "You found a high level <@458036985353732097>!"} + ], + "image_url": "https://dummyimage.com/800x400/e62b4a/422626.png&text=Ravager", + "northtext": "", + "easttext": "Move **!east** towards the next room, containing two locked doors. ", + "southtext": "", + "westtext": "Move back **!west** to find the room with a key again.", + "floor": 1, + "ravager": { + "level": [7, 8] + }, + "connections": { + "east": "room_3", + "west": "key_room_2" + } + }, + "room_3": { + "name": "Dungeon Room", + "descriptions": [ + {"text": "Two locked doors lie before you. They may hold some significance."} + ], + "image_url": "https://dummyimage.com/800x400/241f1a/e82525.png&text=Dungeon+Room", + "northtext": "Move **!north** to enter the first door. ", + "easttext": "Move **!east** to enter the second door. ", + "southtext": "", + "westtext": "To move back, go **!west**.", + "floor": 1, + "connections": { + "north": "locked_door_room_1", + "east": "locked_door_room_2", + "west": "ravager_room_3" + } + }, + "locked_door_room_1": { + "name": "A Locked Door", + "descriptions": [ + {"text": "The first locked door locks growling and scratching here. You can check out the door with **!door**."} + ], + "image_url": "https://dummyimage.com/800x400/bfa897/7a4e4e.png&text=Locked+Door", + "northtext": "", + "easttext": "", + "southtext": "To move back, go **!south**.", + "westtext": "", + "floor": 1, + "connections": { + "south": "room_3" + }, + "door": { + "command": true, + "type": "door", + "removeItem": [{"item": "key", "amount": 1}], + "embed": { + "formatting": "author_title_image_desc", + "setAuthor": {"title": "${dungeon.room.name}", "image": "${profile_pic}"}, + "setTitle": "A Locked Door", + "setDescription": "This door requires a **:key: Key** to open.\n**:closed_lock_with_key: Unlock** door with the key.\n:lock_with_ink_pen: **Lockpick** door, and risk breaking the lock.\n:x: **Exit** options for the door.", + "waitBegin": 0, + "waitEnd": 0 + }, + "options": [ + {"command": "unlock", "emote": "🔐"}, + {"command": "lockpick", "emote": "🔏"}, + {"command": "exit", "emote": "❌"} + ], + "unlock": { + "command": true, + "internal": true, + "type": "door", + "moveFrom": "locked_door_room_1", + "moveTo": "unlocked_door_room_1", + "required": [{"item": "key", "amount": 1}] + }, + "lockpick": { + "command": true, + "internal": true, + "type": "door", + "moveFrom": "locked_door_room_1", + "moveToFail": "broken_door_room_1", + "moveTo": "unlocked_door_room_1" + }, + "exit": { + "command": true, + "internal": true, + "type": "door", + "moveTo": "locked_door_room_1" + } + } + }, + "unlocked_door_room_1": { + "name": "An Unlocked Door", + "descriptions": [ + {"text": "The first locked door has been opened! Beware the <@458036985353732097>."} + ], + "image_url": "https://dummyimage.com/800x400/bfa897/7a4e4e.png&text=Unlocked+Door", + "northtext": "Move **!north** to meet face-to-face with the Ravager. ", + "easttext": "", + "southtext": "To move back, go **!south**.", + "westtext": "", + "floor": 1, + "connections": { + "north": "ravager_room_4", + "south": "room_3" + } + }, + "ravager_room_4": { + "name": "Ravager Room", + "descriptions": [ + {"text": "You found a locked-in <@458036985353732097>!"} + ], + "image_url": "https://dummyimage.com/800x400/e62b4a/422626.png&text=Ravager", + "northtext": "Move **!north** to the chest, it doesn't have a lock on it! ", + "easttext": "", + "southtext": "Move back **!south** to go to the door.", + "westtext": "", + "floor": 1, + "ravager": { + "level": [8, 9] + }, + "connections": { + "north": "free_chest_room_1", + "south": "locked_door_room_1" + } + }, + "free_chest_room_1": { + "name": "A Chest", + "descriptions": [ + {"text": "You found a **!chest**! Wonder what lies inside it. Hopefully there is something valuable."} + ], + "image_url": "https://dummyimage.com/800x400/593521/f5c91b.png&text=Chest", + "northtext": "", + "easttext": "", + "southtext": "Leave the chest by typing **!south**.", + "westtext": "", + "floor": 1, + "connections": { + "south": "ravager_room_4" + }, + "chest": { + "command": true, + "type": "chest", + "embed": { + "formatting": "author_title_image_desc", + "setAuthor": {"title": "${dungeon.room.name}", "image": "${profile_pic}"}, + "setTitle": "A Chest", + "setDescription": "Do you want to open the chest?\n**:unlock: Unlock** chest.\n:x: **Exit** options for the chest.", + "waitBegin": 0, + "waitEnd": 0 + }, + "options": [ + {"command": "unlock", "emote": "🔓"}, + {"command": "exit", "emote": "❌"} + ], + "unlock": { + "command": true, + "internal": true, + "type": "chest", + "moveFrom": "free_chest_room_1", + "moveTo": "empty_free_chest_room_1", + "objects": [ + [ + { + "name": "crystals", + "amount": [18, 22] + } + ] + ] + }, + "exit": { + "command": true, + "internal": true, + "type": "chest", + "moveTo": "free_chest_room_1" + } + } + }, + "empty_free_chest_room_1": { + "name": "An Empty Chest", + "descriptions": [ + {"text": "You have already opened this chest."} + ], + "image_url": "https://dummyimage.com/800x400/593521/f5c91b.png&text=Chest+(Opened)", + "northtext": "", + "easttext": "", + "southtext": "Leave the chest by typing **!south**.", + "westtext": "", + "floor": 1, + "connections": { + "south": "ravager_room_4" + } + }, + "locked_door_room_2": { + "name": "A Locked Door", + "descriptions": [ + {"text": "The second locked door leads to the end of the dungeon. You can check out the door with **!door**."} + ], + "image_url": "https://dummyimage.com/800x400/bfa897/7a4e4e.png&text=Locked+Door", + "northtext": "", + "easttext": "", + "southtext": "", + "westtext": "To move back, go **!west**.", + "floor": 1, + "connections": { + "west": "room_3" + }, + "door": { + "command": true, + "type": "door", + "removeItem": [{"item": "dungeon_key", "amount": 1}], + "embed": { + "formatting": "author_title_image_desc", + "setAuthor": {"title": "${dungeon.room.name}", "image": "${profile_pic}"}, + "setTitle": "A Locked Door", + "setDescription": "This door requires a **:key2: Dungeon Key** to open.\n**:closed_lock_with_key: Unlock** door with the dungeon key.\n:x: **Exit** options for the door.", + "waitBegin": 0, + "waitEnd": 0 + }, + "options": [ + {"command": "unlock", "emote": "🔐"}, + {"command": "exit", "emote": "❌"} + ], + "unlock": { + "command": true, + "internal": true, + "type": "door", + "moveFrom": "locked_door_room_2", + "moveTo": "unlocked_door_room_2", + "required": [{"item": "dungeon_key", "amount": 1}] + }, + "exit": { + "command": true, + "internal": true, + "type": "door", + "moveTo": "locked_door_room_2" + } + } + }, + "unlocked_door_room_2": { + "name": "An Unlocked Door", + "descriptions": [ + {"text": "The second locked door has been opened! You may now exit the dungeon in the final room."} + ], + "image_url": "https://dummyimage.com/800x400/bfa897/7a4e4e.png&text=Unlocked+Door", + "northtext": "", + "easttext": "The final room lies down **!east**.", + "southtext": "", + "westtext": "To move back, go **!west**.", + "floor": 1, + "connections": { + "east": "final_room", + "west": "room_3" + } + }, + "final_room": { + "name": "Dungeon Room", + "descriptions": [ + {"text": "You can see the exit from here. There is a gate that opens to the outside."} + ], + "image_url": "https://dummyimage.com/800x400/69584b/ffffff.png&text=Dungeon+Exit", + "northtext": "Move **!north** to leave the dungeon. ", + "easttext": "", + "southtext": "", + "westtext": "Move **!west** to go back inside to get anything that has been missed.", + "floor": 1, + "connections": { + "north": "__END", + "west": "locked_door_room_2" + } + } + } +} \ No newline at end of file diff --git a/TextAdv/textadv.js b/TextAdv/textadv.js new file mode 100644 index 0000000..3355262 --- /dev/null +++ b/TextAdv/textadv.js @@ -0,0 +1,2105 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); + +// Bot Modules +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); +const PlayerClass = require('./playerClass'); +const DungeonClass = require('./dungeonClass'); + +// JSON +const rooms = require('./rooms.json'); + +// Playing dialogs +const nothingMessage = "with locks." + +// State Machine +var BotEnumState = { + NOTHING: 0, + WAITING_FOR_PLAYERS: 1, + ACTIVE: 2 +} + +// Directions +var Directions = { + NORTH: 0, + EAST: 1, + SOUTH: 2, + WEST: 3 +} + +// Dungeon State +var DungeonState = { + WAITING_FOR_USERS: 0, + INSIDE_DUNGEON: 1, + FIGHTING: 2, + BOSS_BATTLE: 3 +} + +// Modes (these better not be final, me.) +var DungeonModes = { + HEIRARCHY: 0, // Uses heirarchy to determine movement + ANARCHY: 1, // Anyone can determine movement + DEMOCRACY: 2 // Voting system +} + +// Dungeons +class DungeonRaidInstance { + constructor(room) { + this.room = room; + this.mode = DungeonModes.DEMOCRACY; + this.players = []; + this.location; + this.state = DungeonState.WAITING_FOR_USERS; + this.dialogObj; + this.reroutedRooms = []; + this.items = []; + this.isTyping; + this.timer; + this.startTimer; + this.crystalsGained = 0; + this.directionalCollector; + this.directionalMessageID; + } +} + +// Dungeon collections; +var dungeonCollection = []; + +// 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('invisible'); + + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); + + //client.guilds.get(process.env.SANCTUM_ID).members.get(client.user.id).setNickname(""); +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + // Message has to be in test or hell's gate + if (!(message.channel.id !== process.env.TEST_CHANNEL_ID || message.channel.id !== process.env.HELLS_GATE_CHANNEL_ID)) { + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + if (command !== "party") return; + }; + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + switch (command) { + case "ping": + if (isAdmin(message.author.id)) { + return message.reply("Pong!"); + } + break; + case "summonr": + if (isAdmin(message.author.id)) { + return NewDungeonSequence(process.env.TEST_CHANNEL_ID); + } + break; + case "vanishr": + if (isAdmin(message.author.id) && getDungeonPlayer(message.author.id).playerDungeon !== undefined) { + return BotActive(getDungeonPlayer(message.author.id).playerDungeon); + } + break; + case "help": + if (args[0] && message.mentions.members.first() !== undefined) { + if (message.mentions.members.first().id !== client.user.id) break; + let tempVar = ''; + tempVar += "Here are the commands you can do." + tempVar += "\n\n" + tempVar += "!map (!m)\n```Checks your high-tech map about the dungeon.```" + tempVar += "\n" + tempVar += "!party (!p)\n```Lists all members in your party.```" + tempVar += "\n" + tempVar += "!promote (!pr)\n```If you're the leader, you can promote others to be a party leader with you in order to move around.```" + tempVar += "\n" + tempVar += "!demote (!de)\n```If you're the leader, you can demote others if needed if they are a commander.```" + return sendMessage(message.channel.id, tempVar); + } + break; + case "leave": + leaveMessage(message); + break; + } + + // Scans if player is in the raid collection + const dungeonPlayer = getDungeonPlayer(message.author.id); + var isLeader = dungeonPlayer.isLeader; // Gets if author is leader of raid + var isCommander = dungeonPlayer.isCommander; // Gets if userID is commander + var playerID = dungeonPlayer.playerID; // Grabs message.author if this is part of raid + var playerDungeon = dungeonPlayer.playerDungeon; // Grab's the player's dungeon if joined + + // If user has not joined a party + /* + if (!playerID) { + switch (command) { + case "join": + joinMessage(message, getRoomName(args[0])); + break; + case "j": + joinMessage(message, getRoomName(args[0])); + break; + } + } + */ + + // Party member commands only + if (!playerID) return; + + // Party commands + switch (command) { + case "check": + return sendMessage(message.author.id, message.channel.id, "Please use **!map** for checking the map."); + case "members": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num) && Math.sign(num) > 0) { + return partyMembers(playerDungeon, num); + } + } else { + return partyMembers(playerDungeon); + } + break; + case "party": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num) && Math.sign(num) > 0) { + return partyMembers(playerDungeon, num); + } + } else { + return partyMembers(playerDungeon); + } + break; + case "p": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num) && Math.sign(num) > 0) { + return partyMembers(playerDungeon, num); + } + } else { + return partyMembers(playerDungeon); + } + break; + case "promote": + return promoteCommander(message.author, message.mentions.members.first(), isLeader, message.channel.id); + case "pr": + return promoteCommander(message.author, message.mentions.members.first(), isLeader, message.channel.id); + case "demote": + return demoteCommander(message.author, message.mentions.members.first(), isLeader, message.channel.id); + case "de": + return demoteCommander(message.author, message.mentions.members.first(), isLeader, message.channel.id); + case "transferleadership": + return transferLeader(message, message.mentions.members.first()); + case "giveleadership": + return transferLeader(message, message.mentions.members.first()); + case "map": + return sendEmbedLocation(playerDungeon); + case "m": + return sendEmbedLocation(playerDungeon); + case "location": + return sendEmbedLocation(playerDungeon); + case "l": + return sendEmbedLocation(playerDungeon); + case "locationtext": + return sendLocation(playerDungeon, message.author); + case "lt": + return sendLocation(playerDungeon, message.author); + case "pinventory": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num) && Math.sign(num) > 0) { + return sendInventory(playerDungeon, num); + } + } else { + return sendInventory(playerDungeon); + } + case "pinv": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num) && Math.sign(num) > 0) { + return sendInventory(playerDungeon, num); + } + } else { + return sendInventory(playerDungeon); + } + case "pi": + if (args[0] !== undefined) { + var num = Math.floor(parseInt(args[0])); + if (Number.isSafeInteger(num) && Math.sign(num) > 0) { + return sendInventory(playerDungeon, num); + } + } else { + return sendInventory(playerDungeon); + } + case "timer": + return sendTimerInChat(playerDungeon); + case "cleardialog": + console.log("Clearing player dungeon by command trigger..."); + playerDungeon.dialogObj = undefined; + return; + case "debug": + console.log(playerDungeon.reroutedRooms); + return; + } + + // The dungeon has to be active now + if (playerDungeon.state === DungeonState.WAITING_FOR_USERS) { + //return sendMessage(message.author.id, message.channel.id, "**Command denied.** Please wait for until the dungeon closes."); + return; + } + + // Custom commands from JSON + if (playerDungeon.dialogObj === undefined) { + var newCommand = playerDungeon.location[command]; + customCommands(newCommand, playerDungeon, message.author, command, args); + // More custom commands that are children from other custom commands + } else { + var newCommand = playerDungeon.dialogObj[command]; + customCommands(newCommand, playerDungeon, message.author, command, args); + return; + } + + // Leader or commander only commands (movement) + return; + switch (command) { + case "north": + move(Directions.NORTH, playerDungeon, (isLeader || isCommander), message.author); + break; + case "n": + move(Directions.NORTH, playerDungeon, (isLeader || isCommander), message.author); + break; + case "east": + move(Directions.EAST, playerDungeon, (isLeader || isCommander), message.author); + break; + case "e": + move(Directions.EAST, playerDungeon, (isLeader || isCommander), message.author); + break; + case "south": + move(Directions.SOUTH, playerDungeon, (isLeader || isCommander), message.author); + break; + case "s": + move(Directions.SOUTH, playerDungeon, (isLeader || isCommander), message.author); + break; + case "west": + move(Directions.WEST, playerDungeon, (isLeader || isCommander), message.author); + break; + case "w": + move(Directions.WEST, playerDungeon, (isLeader || isCommander), message.author); + break; + case "mode": + + break; + case "m": + + break; + } +}); + +client.on('error', console.error); +client.on('warn', console.warn); + +// Gets if user has an Overseers rank +function isAdmin(userID) { + var guild = client.guilds.get(process.env.SANCTUM_ID); + return guild.members.get(userID).roles.find(role => role.name === "Overseers"); +} + +// Creates an array that creates multiple different arrays inside of that array -> [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +// http://www.frontcoded.com/splitting-javascript-array-into-chunks.html +var createGroupedArray = function(arr, chunkSize) { + var groups = [], i; + for (i = 0; i < arr.length; i += chunkSize) { + groups.push(arr.slice(i, i + chunkSize)); + } + return groups; +} + +// Gets the user's role by member +function getFactionID(member) { + var playerRole; + var isGroupA = member.roles.has(process.env.GROUP_A_ROLE); + var isGroupB = member.roles.has(process.env.GROUP_B_ROLE); + var isGroupC = member.roles.has(process.env.GROUP_C_ROLE); + + if (isGroupA) playerRole = process.env.GROUP_A_ROLE; + else if (isGroupB) playerRole = process.env.GROUP_B_ROLE; + else if (isGroupC) playerRole = process.env.GROUP_C_ROLE; + else playerRole = "none"; + + return playerRole; +} + +// Gets the Combat Class name by role +function getCombatClassName(member) { + var combatClass; + var isTank = member.roles.find(role => role.name === "🛡️ Tank"); + var isRogue = member.roles.find(role => role.name === "🗡️ Rogue"); + var isDPSMelee = member.roles.find(role => role.name === "⚔️ DPS Melee"); + var isDPSRange = member.roles.find(role => role.name === "🏹 DPS Range"); + var isSupport = member.roles.find(role => role.name === "❤️ Support"); + + if (isTank) combatClass = "Tank"; + else if (isRogue) combatClass = "Rogue"; + else if (isDPSMelee) combatClass = "DPS Melee"; + else if (isDPSRange) combatClass = "DPS Range"; + else if (isSupport) combatClass = "Support"; + else combatClass = "None"; + + return combatClass; +} + +// Returns JSON room data by room name +function getRoomName(name) { + if (name !== undefined) { + if (name.toLowerCase() === "hellsgate") + return rooms.hellsgate; + } else { + name = ""; + } + + return { "undefined": name }; +} + +// Updates Player data in Dungeon Collection +function updatePlayers() { + // Scans if player is in the raid collection + // Totally seemingly not intensive test of for loops (Wish I knew) + if (dungeonCollection !== undefined) { + // Loops through every dungeon active + for (let index = 0; index < dungeonCollection.length; index++) { + const dungeonElement = dungeonCollection[index]; + + // Loops through every player in that dungeon + for (let index = 0; index < dungeonElement.players.length; index++) { + const playerElement = dungeonElement.players[index]; + const thisGuild = client.guilds.get(process.env.SANCTUM_ID); + const newMember = thisGuild.members.get(playerElement.userID); + // If user is in one of the dungeon + if (newMember) { + // Start updating + playerElement.factionID = getFactionID(newMember); + playerElement.combatClass = getCombatClassName(newMember); + //playerElement.badgeEmote; + } + } + } + } +} + +// Collects usable username for !party +function playerName(userID) { + const server = client.guilds.get(process.env.SANCTUM_ID); + const sizeLimit = 19; + var name = server.members.get(userID).displayName; + + if (name.length > sizeLimit) { + name = truncate(name, sizeLimit); + } + return name; +} + +// Truncates super long text that is way too lon... +function truncate(string, amount) { + if (string.length > amount) + return string.substring(0, amount - 3) + '...'; + else + return string; +}; + +// Gets dungeon player by userID +function getDungeonPlayer(userID) { + // Scans if player is in the raid collection + var isLeader = false; // Gets if author is leader of raid + var isCommander = false; // Gets if user is commander + var playerID; // Grabs userID if this is part of raid + var playerDungeon; // Grabs the player's dungeon if joined + var player; // Gets player class + + // Totally seemingly not intensive test of for loops (Wish I knew) + if (dungeonCollection !== undefined) { + // Loops through every dungeon active + for (let index = 0; index < dungeonCollection.length; index++) { + const dungeonElement = dungeonCollection[index]; + //console.log("dungeonElement | " + dungeonElement); + + // Loops through every player in that dungeon + for (let index = 0; index < dungeonElement.players.length; index++) { + const playerElement = dungeonElement.players[index]; + //console.log("playerElement | " + playerElement); + + // If user is in one of the dungeon + if (userID === playerElement.userID) { + playerID = userID; + player = playerElement; + playerDungeon = dungeonElement; // Sets player's dungeon to this + + if (playerElement.leader) { + isLeader = true; + } + + if (playerElement.commander) { + isCommander = true; + } + } + } + } + } else { console.log("UNDEFINED DUNGEON COLLECTION" + dungeonCollection) } + + return { isLeader, isCommander, playerID, playerDungeon, player }; +} + +// Async Waiting +function sleep(time) { + return new Promise((resolve, reject) => { + setTimeout(resolve, time); + }); +} + +// Checks for if custom command is valid +async function customCommands(newCommand, playerDungeon, author, command, args) { + function items() { + var array = []; + newCommand.pickup.forEach(element => { + array.push(element); + }); + } + + // Grabs the object if it exists + console.log(`[Custom Commands] Type I | newCommand exists: ${newCommand !== undefined}`) + if (newCommand !== undefined && newCommand.command) { + if (playerDungeon.state === DungeonState.WAITING_FOR_USERS) return; + console.log(`[Custom Commands] Type II | internal: ${newCommand.internal} | command: ${command}`); + // If command is meant to be an internal, inscript command + if (newCommand.internal) { + if (newCommand.pickup) + pickupItem(playerDungeon, newCommand, author, newCommand.pickup); + } else { + playerDungeon.dialogObj = newCommand; + typingDialog(playerDungeon, newCommand, author); + } + } +} + +// Executes custom commands by emote text +function customCommandEmoteProcessor(playerDungeon, newCommand, author, returnElement, newMessage) { + //console.log("[Emote Processor] Emote reaction custom command: " + JSON.stringify(returnElement, null, 4)); + //console.log("[Emote Processor] newCommand: " + JSON.stringify(newCommand, null, 4)); + console.log("[Emote Processor] newCommand.type = " + newCommand.type); + switch (newCommand.type) { + case "chest": + switch (returnElement.emote) { + // JSON : chest.options.unlock + case "🔓": + openChest(playerDungeon, newCommand[returnElement.command], author, false, newMessage, newCommand.embed) + break; + case "🔐": + openChest(playerDungeon, newCommand[returnElement.command], author, true, newMessage, newCommand.embed); + break; + case "🔏": + lockpickChest(playerDungeon, newCommand, author, newMessage, newCommand.embed); + break; + case "❌": + leaveObject(playerDungeon, newCommand[returnElement.command], author); + break; + } + break; + + case "door": + switch (returnElement.emote) { + case "🔐": + openDoor(playerDungeon, newCommand[returnElement.command], author, returnElement, newMessage, newCommand.embed); + break; + case "🔏": + lockpickDoor(playerDungeon, newCommand, author, newMessage, newCommand.embed); + break; + case "❌": + leaveObject(playerDungeon, newCommand[returnElement.command], author); + break; + } + break; + } +} + +// Adds item to inventory +function addItem(playerDungeon, item, amount) { + // If item exists in inventory + console.log("[Add Item] " + amount); + var i = playerDungeon.items.findIndex(i => i.name === item.name); + console.log("[Item Amount Item Exists] i Equals " + i); + + // Item is internally handled + if (item.internal) { + switch (item.name.toLowerCase()) { + case "crystals": + addCrystalsToPartyMember(playerDungeon, amount); + break; + + default: + break; + } + } + + // If there is an item that exists in inventory + if (i !== -1) { + console.log("[Item Amount Start] " + playerDungeon.items[i].amount); + playerDungeon.items[i].amount += item.amount; // Increments amount value + console.log("[Item Amount Finish] " + playerDungeon.items[i].amount); + // Disallows adding objects such as crystals + } else if (!item.internal) { + console.log("[Item Amount Wait] Created item for the first time."); + var clonedItem = JSON.parse(JSON.stringify(item)); // Clones item in order to not actually increment the rooms.js item JSON data + playerDungeon.items.push(clonedItem); + } +} + +// Removes item from party inventory (TODO: multi item stacks & only take one item) +function removeItem(playerDungeon, item, amount) { + let i = playerDungeon.items.findIndex( i => i.name === item.name ); + console.log("[Remove Item] i Equals " + i + ` | For item: ${item.name}`); + if (i !== -1) { + if (playerDungeon.items[i].amount > 2) { + console.log("[Item Amount Start] " + playerDungeon.items[i].amount); + playerDungeon.items[i].amount -= item.amount; // Decrements amount value + console.log("[Item Amount Finish] " + playerDungeon.items[i].amount); + } + else { + console.log("[Item Amount Wait] Destroying item:\n" + playerDungeon.items.length); + playerDungeon.items.splice(i, 1); + console.log("[Item Amount Done] Finished Destroying item:\n" + playerDungeon.items.length); + } + + console.log("[Remove Item] Successfully removed item " + item.name + " from " + playerDungeon.room.name) + return true; + } + console.log("[Remove Item] Couldn't remove item!"); + return false; +} + +// Adds crystals to EACH player dungeon players (GAMBLE IS BEING USED TO ADD) +function addCrystalsToPartyMember(playerDungeon, amount) { + playerDungeon.players.forEach(element => { + dataRequest.sendServerData("gambleWon", amount, element.userID); + playerDungeon.crystalsGained += amount; + }); +} + +// Pickup Item +async function pickupItem(playerDungeon, newCommand, author, items) { + // Loops through all the items in array, and adds them into the item string + var itemString = ""; + console.log("[Pickup Item] JSON Data:\n" + JSON.stringify(items, null, 4)); + for (let i = 0; i < items.length; i++) { + const element = items[i].item; + const item = rooms.items[element]; + console.log("[Pickup Item] " + element + "\nJSON:\n" + JSON.stringify(item, null, 4)); + // Emote processing + var emoteText = ""; + if (item.emote !== undefined && item.emote !== "") emoteText = `${item.emote} `; + + // Adds to item string & inventory + var amount = 1; + // Generates random number if array + if (Array.isArray(items[i].amount)) + amount = calcRandom.random(items[i].amount[0], items[i].amount[1]); + // Treats it as an int instead + else { + // If amount variables exists, set it to so + if (items[i].amount) amount = items[i].amount; + } + + var newAmount; + switch (element) { + // Meant to have each player get a set amount of crystals + case "crystals": + newAmount = amount * playerDungeon.players.length; + break; + // Normal handling + default: + newAmount = amount; + break; + } + + itemString += `> **${emoteText}${item.name}** [${newAmount}x]\n`; + addItem(playerDungeon, item, amount); + } + + // Sends embed + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", client.user.avatarURL) + .setColor(playerDungeon.room.color) + .setTitle("Item Get!") + .setDescription(`You picked up...\n${itemString}You can find it in the party's **!pinventory**.\nAny collected crystals or materials will be distributed evenly.`) + + client.channels.get(playerDungeon.room.channel).send({embed}); + + // Debug + // console.log("DEBUG JSON DATA: " + JSON.stringify(item. null, 4)); + + await sleep(2500); + playerDungeon.dialogObj = newCommand; + playerDungeon.reroutedRooms.push([newCommand.moveFrom, newCommand.moveTo]); + move(newCommand.moveTo, playerDungeon, true, author); + playerDungeon.dialogObj = undefined; +} + +// Lock picks a chest +async function lockpickChest(playerDungeon, newCommand, author, newMessage, embedData) { + var random = calcRandom.gamble(50); + var channel = client.channels.get(playerDungeon.room.channel); + var successMessage = `:lock_with_ink_pen: **You have successfully lockpicked the chest!** The party has saved a key.`; + var failedMessage = `:lock_with_ink_pen: **The unlock has failed.** Better luck next time!`; + if (random) { + if (!embedData) { + if (!newMessage) + channel.send(successMessage); + } else { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle) + .setDescription("...") + + await newMessage.edit({embed}); + embed.description = successMessage; + newMessage.edit({embed}); + } + await sleep(2500); + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle) + .setDescription("...") + + await newMessage.edit({embed}); + lootChest(playerDungeon, newCommand.unlock, author, newMessage, embedData); + } else { + if (!embedData) + channel.send(failedMessage); + else { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle) + .setDescription("...") + + await newMessage.edit({embed}); + embed.description = failedMessage; + newMessage.edit({embed}); + } + await sleep(2500); + + playerDungeon.dialogObj = newCommand.lockpick; + move(newCommand.lockpick.moveToFail, playerDungeon, true, author); + playerDungeon.dialogObj = undefined; + } +} + +// Opens the chest +async function openChest(playerDungeon, newCommand, author, useKey, newMessage, embedData) { + var successMessage = `${author} used the **:key: Key** to open the chest.`; + var failedMessage = "The party does not have a **:key: Key** to :closed_lock_with_key: unlock this chest."; + + console.log("[Open Chest] " + successMessage + " | " + failedMessage); + + if (useKey && playerDungeon.dialogObj.removeItem) { + // Checks for key in inventory + let removeKey = playerDungeon.items.findIndex( i => i.name === "Key" ); + console.log("[Remove Key] " + removeKey); + + // If key exist + if (removeKey !== -1) { + removeItem(playerDungeon, rooms.items["key"]); + if (!embedData) + sendMessage(author.id, playerDungeon.room.channel, successMessage) + else { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle + ": Unlocking") + .setDescription("...") + + await newMessage.edit({embed}); + embed.description = successMessage; + newMessage.edit({embed}); + await sleep(2500); + } + } else { + if (!embedData) + sendMessage(author.id, playerDungeon.room.channel, failedMessage); + else { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle) + .setDescription("...") + + await newMessage.edit({embed}); + embed.description = failedMessage; + newMessage.edit({embed}); + await sleep(2500); + } + + return typingDialog(playerDungeon, playerDungeon.dialogObj, author); + } + } else { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle) + .setDescription("...") + + await newMessage.edit({embed}); + } + + // Open chest + lootChest(playerDungeon, newCommand, author, newMessage, embedData); +} + +// Lockpicks door (lockpickChest IS VERY SIMILAR) +async function lockpickDoor(playerDungeon, newCommand, author, newMessage, embedData) { + var random = calcRandom.gamble(50); + var channel = client.channels.get(playerDungeon.room.channel); + var successMessage = `:lock_with_ink_pen: **You have successfully lockpicked the door!** The party has saved a key.`; + var failedMessage = `:lock_with_ink_pen: **The unlock has failed.** Better luck next time!`; + if (random) { + if (!embedData) { + if (!newMessage) + channel.send(successMessage); + } else { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle) + .setDescription("...") + + + await newMessage.edit({embed}); + embed.description = successMessage; + newMessage.edit({embed}); + } + await sleep(2500); + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle) + .setDescription("...") + + + await newMessage.edit({embed}); + actualOpenDoor(playerDungeon, newCommand.unlock, author, newMessage, embedData); + } else { + if (!embedData) + channel.send(failedMessage); + else { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle) + .setDescription("...") + + + await newMessage.edit({embed}); + embed.description = failedMessage; + newMessage.edit({embed}); + } + await sleep(2500); + + playerDungeon.dialogObj = newCommand.lockpick; + move(newCommand.lockpick.moveToFail, playerDungeon, true, author); + playerDungeon.dialogObj = undefined; + } +} + +// Opens the door (TODO: ADD NO EMOTE COMPATIBILITY, AND REMOVE KEY) +async function openDoor(playerDungeon, newCommand, author, returnElement, newMessage, embedData) { + var hasAllItems = true; + const noneString = "**> [None]**\n"; + var itemsHasString = noneString; + var itemsNotHaveString = noneString; + console.log("[Open Door] JSON Data: " + JSON.stringify(newCommand, null, 4) + "\nreturnElement: " + JSON.stringify(returnElement, null, 4)); + // Loops over all items + for (let i = 0; i < newCommand.required.length; i++) { + // Element = item object + const objData = newCommand.required[i]; // Contains data from rooms.json + const item = rooms.items[objData.item]; + + // Checks for key in inventory + let itemRemove = playerDungeon.items.findIndex( i => i.name === item.name ); + console.log("[Remove Item Door] " + "itemRemove = " + itemRemove); + + // If item exist + var failed; + if (itemRemove !== -1) { + if (removeItem(playerDungeon, item, objData.amount)) { + if (itemsHasString === noneString) itemsHasString = ""; // Erases None string + itemsHasString += `**> ${item.emote} ${item.name} [${objData.amount}x]**\n`; + } + else { + console.log(`[Remove Item Door] Remove fail at removeItem().`) + failed = true; + } + } else { + console.log(`[Remove Item Door] Couldn't find item name.`) + failed = true; + } + + if (failed) { + hasAllItems = false; + if (itemsNotHaveString === noneString) itemsNotHaveString = ""; // Erases None string + itemsNotHaveString += `**> ${item.emote} ${item.name} [${objData.amount}x]**\n`; + } + } + + // Variables + var successMessage = `${author} used:\n${itemsHasString} to open the door.`; + var failedMessage = `The party does have:\n${itemsHasString}However, the party does not have:\n${itemsNotHaveString}\n...in order to :closed_lock_with_key: unlock the door.`; + console.log("[Open Door] " + successMessage + " | " + failedMessage); + + // If no items needed + if (hasAllItems) { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle + ": Unlocking") + .setDescription("...") + + await newMessage.edit({embed}); + embed.description = successMessage; + newMessage.edit({embed}); + await sleep(2500); + } else { + // Send fail message + if (!embedData) + sendMessage(author.id, playerDungeon.room.channel, failedMessage); + else { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle) + .setDescription("...") + + await newMessage.edit({embed}); + embed.description = failedMessage; + newMessage.edit({embed}); + await sleep(2500); + } + + return typingDialog(playerDungeon, playerDungeon.dialogObj, author); + } + + actualOpenDoor(playerDungeon, newCommand, author, newMessage, embedData); +} + +function actualOpenDoor(playerDungeon, newCommand, author, newMessage, embedData) { + if (newMessage) { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle + ": Unlocking") + .setDescription(`:unlock: The door has been opened!`) + + newMessage.edit({embed}); + } + + playerDungeon.dialogObj = newCommand; + playerDungeon.reroutedRooms.push([newCommand.moveFrom, newCommand.moveTo]); + move(newCommand.moveTo, playerDungeon, true, author); + playerDungeon.dialogObj = undefined; +} + +// Loots the chest (TODO: REMOVE GAMBLWON ON SENDSERVERDATA) +async function lootChest(playerDungeon, newCommand, author, newMessage, embedData) { + var channel = client.channels.get(playerDungeon.room.channel); + var content = `:lock: **Opening chest.`; + var openMessage = `:unlock: **You obtained :wind_blowing_face: Air!** This item will be distributed through the party at random.`; + // Generates a random item drop group + //console.log(JSON.stringify(newCommand, null, 4)); + var randomDropGroup = calcRandom.random(0, newCommand.objects.length - 1); + var randomItemGroup = calcRandom.random(0, newCommand.objects[randomDropGroup].length - 1) + + /* + console.log("newCommand.objects: " + JSON.stringify(newCommand.objects, null, 4)); + console.log("newCommand.objects.length: " + newCommand.objects.length); + console.log("newCommand.objects[randomDropGroup]: " + JSON.stringify(newCommand.objects[randomDropGroup], null, 4));= + console.log("newCommand.objects[0][0]: " + JSON.stringify(newCommand.objects[0][0], null, 4)); + console.log("IF THIS DOESNT WORK, AHHH: " + newCommand.objects[0][0].name) + */ + + console.log("[RNG] " + randomDropGroup + " " + randomItemGroup + " | " + newCommand.objects[randomDropGroup].length); + var randomItem = newCommand.objects[randomDropGroup][randomItemGroup]; + + switch (randomItem.name) { + case "crystals": + if (randomItem["amount"]) { + var amount = calcRandom.random(randomItem["amount"][0], randomItem["amount"][1]); + openMessage = `:unlock: **You obtained <:crystals:460974340247257089> ${amount * playerDungeon.players.length} Crystals!** This item will be distributed through the party evenly.`; + addCrystalsToPartyMember(playerDungeon, amount); + } + break; + + case "materials": + openMessage = `:unlock: **You obtained materials that I have implemented!**`; + break; + + default: + console.warn("Message not in switch statement: " + randomItem.name) + break; + } + + if (!embedData || !newMessage) { + var message = await channel.send(content + "**").catch(console.error); + } else { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle + ": Unlocking") + .setDescription(content + "**") + + newMessage.edit({embed}); + } + + for (let index = 1; index < 3; index++) { + var stringOfDots = ""; + + for (let i = 0; i < index; i++) { + console.log("[Loot Chest] | Number of dots: " + index); + stringOfDots += "."; + } + + await sleep(750); + console.log("[Loot Chest] " + content + stringOfDots + " | " + index); + if (!embedData) + await message.edit(content + stringOfDots + "**"); + else { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle + ": Unlocking") + .setDescription(content + stringOfDots + "**") + + await newMessage.edit({embed}) + } + } + + await sleep(750); + if (!embedData) + message.edit(openMessage); + else { + var dungeonName = embedData.setAuthor.title.replace("${dungeon.room.name}", playerDungeon.room.name); + var newImage = embedData.setAuthor.image.replace("${profile_pic}", client.user.avatarURL); + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(embedData.setTitle + ": Unlocked") + .setDescription(openMessage) + + newMessage.edit({embed}); + } + await sleep(2500); + + // Moves user to empty chest room + playerDungeon.dialogObj = newCommand; + //console.log(JSON.stringify(newCommand, null, 4)); + playerDungeon.reroutedRooms.push([newCommand.moveFrom, newCommand.moveTo]); + move(newCommand.moveTo, playerDungeon, true, author); + playerDungeon.dialogObj = undefined; +} + +// Leaves the chest alone +async function leaveObject(playerDungeon, newCommand, author) { + playerDungeon.dialogObj = newCommand; + move(newCommand.moveTo, playerDungeon, true, author); + playerDungeon.dialogObj = undefined; +} + +// Passes all the user IDs +function passDungeonUserIDs(playerDungeon) { + var userIDArray = []; + playerDungeon.players.forEach(element => { + userIDArray.push(element.userID); + }); + console.log(userIDArray); + return userIDArray; +} + +// https://stackoverflow.com/questions/3733227/javascript-seconds-to-minutes-and-seconds +function fmtMSS(s){ // accepts seconds as Number or String. Returns m:ss + return( s - // take value s and subtract (will try to convert String to Number) + ( s %= 60 ) // the new value of s, now holding the remainder of s divided by 60 + // (will also try to convert String to Number) + ) / 60 + ( // and divide the resulting Number by 60 + // (can never result in a fractional value = no need for rounding) + // to which we concatenate a String (converts the Number to String) + // who's reference is chosen by the conditional operator: + 9 < s // if seconds is larger than 9 + ? ':' // then we don't need to prepend a zero + : ':0' // else we do need to prepend a zero + ) + s ; // and we add Number s to the string (converting it to String as well) +} + +// Creates new dungeon, inits BotWaitingPlayers() +async function NewDungeonSequence(channel) { + console.log('Attempting to start a raid!'); + + // If bot summoning for a dungeon is free + var newRoomID = rooms.rooms[calcRandom.random(0, rooms.rooms.length - 1)]; // calcRandom.random is inclusive for low + high + console.log(newRoomID); + var newRoom = rooms[newRoomID] + + var newDungeon; + dungeonCollection.forEach(element => { + if (element.room.name === newRoom.name) { + return console.log("Raid already happening."); + } + }); + + // Decides on new dungeon + newDungeon = new DungeonRaidInstance(newRoom); + newDungeon.location = newDungeon.room.entrance; + dungeonCollection.push(newDungeon); + + // Minutes + var sleepTime = 2 * 60; + BotWaitingPlayers(channel, newDungeon, sleepTime); +} + +// Shows the join message for the specified dungeon +async function BotWaitingPlayers(channel, dungeon, timer) { + dungeon.startTimer = timer; + + var decrementTime = 1; // Seconds + var newMessage; + var textTimer = `⏰ ${fmtMSS(dungeon.startTimer)} min. left before leaving`; + var crystalCost = 50; + const botDialog = `*Psst.* Hey travelers, **${dungeon.room.name}** doesn't have any Ravagers outside guarding it. ` + + `I could lockpick it, but it's gunna cost you **<:crystals:460974340247257089> 50**, for each of you.`; + const description = `In order to join the dungeon, you have to pay **<:crystals:460974340247257089> ${crystalCost}**. \nReact with <:crystals:460974340247257089> to enter, and the crystals will be subtracted from your account.`; + + client.user.setStatus('online'); + client.user.setActivity(`${textTimer} ${dungeon.room.name}.`) + dungeon.state = DungeonState.WAITING_FOR_USERS; + + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", client.user.avatarURL) + .setColor(dungeon.room.color) + .setDescription(description) + .setFooter(textTimer + ".") + newMessage = await client.channels.get(channel).send(botDialog, {embed}); + + await newMessage.react('460974340247257089'); + + // Collector for emotes + const collector = newMessage.createReactionCollector( + (reaction, user) => reaction.emoji.name === 'crystals' && user.id !== client.user.id , { time: timer * 1000 }); + + // Removes crystals + collector.on("collect", async reaction => { + var user = reaction.users.last(); + //console.log(reaction.emoji.name) + //console.log("Added new user: " + user.username) + + var attacker = String(dataRequest.loadServerData("userStats", user.id)); + var attackerWallet = parseFloat(attacker.split(",")[6]); + + if (attackerWallet >= crystalCost) { + dataRequest.sendServerData("buyDrink", crystalCost, user.id); + joinMessage(user, channel, dungeon.room); + } else { + newMessage.channel.send(`:x: ${user} You don't have enough crystals to pay me. Come back later, when you do. I ain't doing this for free.`); + } + }); + + // Clears reactions + collector.once("end", async collecter => { + console.log("[Reaction Options] Ended collector, clearing emotes and sending timing out message if needed."); + newMessage.clearReactions(); + }); + + // Creates description and displays it (join, no-join) + function timerFunction() { + setTimeout(async () => { + if (dungeon.state !== DungeonState.WAITING_FOR_USERS) return; + const timeInveral = 30; + var quarterMinuteRemainder = dungeon.startTimer % timeInveral; + console.log("[Timer Function] timer: " + dungeon.startTimer + " => " + (dungeon.startTimer - decrementTime) + " | " + quarterMinuteRemainder) + + // If it's been 30 seconds (divisible without any remainder, & not exactly starting time) + if (quarterMinuteRemainder == 0 && dungeon.startTimer !== timer) { + var descriptionString = ""; + var finished = `The travelers entered the dungeon. You can no longer join.` + var textTimer = `⏰ ${fmtMSS(dungeon.startTimer)} min. left before leaving`; + var footerText = textTimer + "."; + + if (dungeon.startTimer > 0) { + descriptionString = description; + client.user.setActivity(`${textTimer} ${dungeon.room.name}.`); + } else { + descriptionString = finished; + footerText = "⏰ You can no longer join." + } + + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", client.user.avatarURL) + .setColor(dungeon.room.color) + .setDescription(descriptionString) + .setFooter(`${footerText}`) + + newMessage.edit(botDialog, embed); + } else if (dungeon.startTimer === timer) { + console.log("[Debug] " + dungeon.startTimer + " | " + timer); + } + dungeon.startTimer -= decrementTime; + if (dungeon.startTimer > -1) timerFunction(); else { + if (dungeon.state === DungeonState.WAITING_FOR_USERS && dungeon.players.length > 0) { + console.log(dungeon.players.length); + BotActive(dungeon); + } else { + BotInactive(dungeon); + } + } + }, decrementTime * 1000); + } + + timerFunction(); +} + +// Sends closing dungeon messages +async function BotActive(dungeon) { + //sendMessage(channel, `${dungeon.room.name} has closed, trapping the travelers inside the dungeon. \ + //\n\n***YOU NO LONGER CAN !JOIN***`); + + if (dungeon.players.length > 0) { + await sendEmbedLocation(dungeon); + + client.channels.get(dungeon.room.channel).send(`**<#${dungeon.room.channel}>** got closed behind us. I guess we should start venturing deeper.` + + `\nUse **!help ${client.user}** to get all the commands you are able to use here, if you need anythin'.`); + + client.user.setStatus('away'); + + dungeon.state = DungeonState.INSIDE_DUNGEON; + } else { + BotInactive(dungeon); + } + + // Starts timer + var decrementTime = 1000; // 1 every second + + dungeon.timer = 10 * 60 * 1000; + sendTimerInChat(dungeon); + + // Decrements dungeon timer and displays it in chat. + function displayTimer() { + setTimeout(async () => { + // Makes sure dungeon is still there + if (dungeon) { + if (dungeon.state === DungeonState.INSIDE_DUNGEON) { + dungeon.timer -= decrementTime; + + // Timers + if (dungeon.timer > 0) { + // Events + var oneMinuteRemainder = dungeon.timer % (1 * 60 * 1000); + + if (oneMinuteRemainder == 0) { + sendTimerInChat(dungeon); + client.user.setActivity(`⏰ ${fmtMSS(dungeon.timer / 1000)} min. left | ${dungeon.room.name}`).then(presence => console.log(`Activity set to ${presence.game ? presence.game.name : 'none'}`)) + .catch(console.error); + } + + // Recursion + displayTimer(); + // Leaves dungeon + } else { + await sendTimerInChat(dungeon); + await client.channels.get(dungeon.room.channel).send("An overwhelming amount of Ravagers came back in," + + " and the party escaped, however not completing the dungeon.\n\n***THE DUNGEON HAS FAILED TO BE COMPLETED IN TIME.***"); + await client.channels.get(process.env.TEST_CHANNEL_ID).send("Alright travelers, we didn't make it in time, but we managed to get out alive, I guess. Better luck next time."); + BotInactive(dungeon); + } + } + } + }, decrementTime); + } + + displayTimer(); +} + +// Inactive +async function BotInactive(dungeon) { + // Removes roles + const guild = client.guilds.get(process.env.SANCTUM_ID); + if (dungeon.players.length > 0) { + for (let i = 0; i < dungeon.players.length; i++) { + const element = dungeon.players[i]; + + // Deletes role + let role = client.guilds.get(process.env.SANCTUM_ID).roles.find(role => role.name === `${dungeon.room.name}: Raid Party`); + await guild.members.get(element.userID).removeRole(role); + } + } + + // Removes dungeon by index + let removeDungeon = dungeonCollection.findIndex( d => d.room.name === dungeon.room.name ); + dungeonCollection.splice(removeDungeon); + + if (dungeonCollection.length < 1) + client.user.setStatus('invisible'); +} + +// Sends timer message +function sendTimerInChat(newDungeon) { + console.log("[Timer] " + newDungeon.timer + " | " + newDungeon.startTimer); + const guild = client.guilds.get(process.env.SANCTUM_ID); + var role = guild.roles.find(role => role.name === `${newDungeon.room.name}: Raid Party`); + + if (newDungeon.state !== DungeonState.WAITING_FOR_USERS) + return client.channels.get(newDungeon.room.channel).send(`:alarm_clock: ${role} has ${fmtMSS(newDungeon.timer / 1000)} min. left to complete the dungeon.`); + else + return client.channels.get(newDungeon.room.channel).send(`:alarm_clock: ${role} has ${fmtMSS(newDungeon.startTimer)} min. left before the dungeon starts.`); +} + +// Ends dialog by pausing then sending your location again. +async function endDialog(newCommand, playerDungeon, overrideLastCommand) { + if (newCommand.lastCommand || overrideLastCommand) { + console.log("[End Dialog] Doing End Dialog Sequence.") + playerDungeon.dialogObj = undefined; + await sleep(1000); + + if (newCommand.lastCommand) sendEmbedLocation(playerDungeon); + } +} + +// Does typing dialog for the NPC +async function typingDialog(playerDungeon, newCommand, author, newMessage) { + if (playerDungeon.isTyping) { console.log("isTyping true, cancelling"); return false }; + console.log("[Typing Dialog]\n" + JSON.stringify(newCommand, null, 4)); + playerDungeon.isTyping = true; + var firstTime; + var range = 250; + var channel = client.channels.get(playerDungeon.room.channel); + + // Types out all the dialog + if (newCommand.descriptions) { + for (let index = 0; index < newCommand.descriptions.length; index++) { + var temp = ""; + const element = newCommand.descriptions[index]; + if (element.text !== undefined) { + var title = "" + if (!firstTime) { + title = `**${playerDungeon.dialogObj.name}**\n`; + firstTime = true; + } + temp = element.text.replace("${leader}", author); + var waitTimerRange = calcRandom.random(element.waitBegin - range, element.waitBegin + range); + + // Debug purposes only + //waitTimerRange = 10; + + sendTypingMessage(channel, title + temp, waitTimerRange); + await sleep(waitTimerRange + element.waitEnd); + + endDialog(newCommand, playerDungeon); + } + } + } + + playerDungeon.isTyping = false; + reactionOptions(playerDungeon, newCommand, author, newMessage); +} + +// Does reactions on a message, then uses them as options +async function reactionOptions(playerDungeon, newCommand, author, newMessage) { + var channel = client.channels.get(playerDungeon.room.channel); + var range = 250; + var returnElement = false; + + // Reactions (if they exist via text or have an options JSON field) + if (newCommand.optionsDescription || newCommand.options) { + var waitTimerRange; + var isEmbed = false; + waitTimerRange = 10; + + // Embed and text varients + if (!newCommand.embed) { + waitTimerRange = calcRandom.random(newCommand.optionsDescription.waitBegin - range, newCommand.optionsDescription.waitBegin + range); + newMessage = await sendTypingMessage(channel, newCommand.optionsDescription.text, waitTimerRange) + } + else { + await sleep(newCommand.embed.waitBegin); + + // Specific formattings + if (newCommand.embed.formatting === "author_title_image_desc") { + var newImage = client.user.avatarURL; + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", newImage) + .setColor(playerDungeon.room.color) + .setTitle(newCommand.embed.setTitle) + .setDescription(newCommand.embed.setDescription) + + newMessage = await channel.send({embed}); + channel.stopTyping(true); + } else { + console.error("[Reaction Options] Embed was tried, but no vaid formatting!"); + } + + await sleep(newCommand.embed.waitEnd) + } + + // Reacts + for (let i = 0; i < newCommand.options.length; i++) { + const element = newCommand.options[i]; + console.log("[Reaction Options] Emote: " + element.emote + " | newMessage: " + newMessage); + await newMessage.react(element.emote); + } + + // Collects emotes and reacts upon the reaction (120 seconds) + const collector = newMessage.createReactionCollector( + (reaction, user) => (getDungeonPlayer(user.id).isLeader || getDungeonPlayer(user.id).isCommander) && + (newCommand.options.some(option => option.emote === reaction.emoji.name)), { time: 120 * 1000 }); + var endedOnReact = false; + + // Collect + collector.once("collect", async reaction => { + // Solely for players + if (playerDungeon.dialogObj) { + const chosen = reaction.emoji.name; + newCommand.options.forEach(element => { + if (element.emote === chosen) { + returnElement = element; + + // Grabs the object if it exists + if (playerDungeon.dialogObj[element.command] && playerDungeon.dialogObj[element.command].command) { + typingDialog(playerDungeon, playerDungeon.dialogObj[element.command], author, newMessage); + console.log("Using grab object if exists"); + hasAlreadyTriggered = true; + } + } + }); + } + customCommandEmoteProcessor(playerDungeon, newCommand, author, returnElement, newMessage, reaction); + endedOnReact = true; + collector.stop(); + + /* + console.log(newMessage.reactions); + newMessage.reactions.forEach(element => { + if (element.users.id !== client.user.id) newMessage.reactions.remove(element); + }); + */ + + // Debug + //console.log("[Reaction Options] Return emote from reactionOptions: " + returnElement.emote); + //console.log("[Reaction Options] newCommand @ reactions function: " + JSON.stringify(newCommand)); + //console.log("[Reaction Options] returnElement: " + JSON.stringify(returnElement)); + }); + + // End trigger + collector.once("end", collecter => { + console.log("[Reaction Options] Ended collector, clearing emotes and sending timing out message if needed."); + newMessage.edit(newMessage.content); + newMessage.clearReactions(); + if (!endedOnReact) { + sendMessage(playerDungeon.room.channel, ":x: **Timed Out** The emote reaction request timed out after 2 minutes."); + endDialog(newCommand, playerDungeon, true); + } + }); + + } +} + +// Sends messages in periods of time +async function sendTypingMessage(channel, message, waitTimer) { + channel.startTyping() + await sleep(waitTimer); + channel.stopTyping(true); + + return channel.send(message); +} + +// Just here for placeholder, do not use +async function sendEmbedMessage(channel, embedData, waitTimer) { + channel.startTyping(); + await sleep(waitTimer); + channel.stopTyping(true); + + const embed = new Discord.RichEmbed(); + + return channel.send(embed); +} + +// Send message handler +function sendMessage(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message === undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message; + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); +} + +// You may use cron normally +cron.schedule('30 */3 * * *', function() { + NewDungeonSequence(process.env.TEST_CHANNEL_ID); +}); + +// Join Message +function joinMessage(user, channel, room) { + var newDungeon; + var firstUserGiveLeader = false; + dungeonCollection.forEach(element => { + if (element.room === room) newDungeon = element; + }); + + // If dungeon doesn't exist + if (!newDungeon) { + if (room.undefined != undefined) { + if (room.undefined == "") + return sendMessage(user.id, channel.id, `:x: You need to specify what dungeon you wish to join.`); + return sendMessage(user.id, channel.id, `:x: There is no dungeon named ${room.undefined}.`); + } + return sendMessage(user.id, channel.id, ":x: This dungeon does not exist."); + } else { + if (newDungeon.players.length == 0) { + firstUserGiveLeader = true; + } + } + + if (newDungeon.state !== DungeonState.WAITING_FOR_USERS) { + return sendMessage(user.id, channel.id, ":x: This dungeon's closed currently."); + } + + // Find if user is in the Raid Party + var userExists = newDungeon.players.find( player => player.userID === user.id ); + + // If user doesn't exist in the list, join message + if (!userExists) { + let member = client.guilds.get(process.env.SANCTUM_ID).members.get(user.id); + + // Adds role to use + let role = client.guilds.get(process.env.SANCTUM_ID).roles.find(role => role.name === `${newDungeon.room.name}: Raid Party`); + member.addRole(role); + + // Creates new player for array + var playerRole = getFactionID(member); + var className = getCombatClassName(member); + var newPlayer = new PlayerClass(user.id, playerRole, className, ":new:", firstUserGiveLeader); + + newDungeon.players.push(newPlayer); + + // Sends messages confirming it + client.channels.get(newDungeon.room.channel).send(`<@${user.id}> welcome to the ${newDungeon.room.name} dungeon raid! Use **!party** to check the members.`); + //message.channel.send(`<@${user.id}> you have **!join**ed the ${newDungeon.room.name} dungeon raid! Use **!party** to check the members.`); + // Else send error already joined + } else { + //client.channels.get(newDungeon).send(`<@${user.id}> you already **!join**ed the ${newDungeon.room.name} dungeon raid. Use **!party** to check the members.`); + } +} + +// Leave Message +async function leaveMessage(message) { + var dungeonPlayer = getDungeonPlayer(message.author.id); + + // Sends messages confirming it + if (dungeonPlayer.playerDungeon === undefined) { + var confirmMessage = await message.channel.send(`<@${message.author.id}> you aren't in a dungeon raid in my books, but are you sure you want to force leave all dungeon raids?\n*This will remove all dungeon raid roles.*`); + + // Reacts + await confirmMessage.react('✅'); + await confirmMessage.react('❌'); + + const collector = confirmMessage.createReactionCollector( + (reaction, user) => (reaction.emoji.name === '✅' || reaction.emoji.name === '❌') && user.id === message.author.id , { time: 15 * 1000 }); + var react = ""; + + // Collect + collector.once("collect", async reaction => { + endedOnReact = true; + react = reaction.emoji.name; + collector.stop(); + }); + + // End trigger + collector.once("end", async collecter => { + console.log("[Reaction Options] Ended collector, clearing emotes and sending timing out message if needed."); + confirmMessage.edit(confirmMessage.content); + confirmMessage.clearReactions(); + if (!endedOnReact) return message.channel.send(":x: **Timed Out**: The emote reaction request timed out after 15 seconds."); + if (react === '❌') return confirmMessage.edit(`${message.author} Cancelled removing dungeon raid roles.`); + + // Force deletes all dungeons that exist + for (let i = 0; i < rooms.rooms.length; i++) { + const element = rooms.rooms[i]; + const name = rooms[element].name; + let role = client.guilds.get(process.env.SANCTUM_ID).roles.find(role => role.name === `${name}: Raid Party`); + await message.member.removeRole(role); + } + + await confirmMessage.edit(`${message.author} Removed all dungeon raid roles.`) + }); + } else { + var confirmMessage = await message.channel.send(`<@${message.author.id}> are you sure you want to leave the ${dungeonPlayer.playerDungeon.room.name} dungeon raid?`); + + // Reacts + await confirmMessage.react('✅'); + await confirmMessage.react('❌'); + + // Collects emotes and reacts upon the reaction (15 seconds) + const collector = confirmMessage.createReactionCollector( + (reaction, user) => (reaction.emoji.name === '✅' || reaction.emoji.name === '❌') && user.id === message.author.id , { time: 15 * 1000 }); + var endedOnReact = false; + var react = ""; + + // Collect + collector.once("collect", async reaction => { + // Solely for players + endedOnReact = true; + react = reaction.emoji.name; + collector.stop(); + }); + + // End trigger + collector.once("end", collecter => { + console.log("[Reaction Options] Ended collector, clearing emotes and sending timing out message if needed."); + confirmMessage.edit(confirmMessage.content); + confirmMessage.clearReactions(); + if (!endedOnReact) return sendMessage(message.channel, ":x: **Timed Out**: The emote reaction request timed out after 15 seconds."); + if (react === '❌') return confirmMessage.edit(`${message.author} Cancelled leaving the ${dungeonPlayer.playerDungeon.room.name}.`); + + // Sends confirmation message + message.channel.send(`${message.author} has left the dungeon.`) + + // Deletes role + let role = client.guilds.get(process.env.SANCTUM_ID).roles.find(role => role.name === `${dungeonPlayer.playerDungeon.room.name}: Raid Party`); + message.member.removeRole(role); + + // Removes user from dungeon + dungeonPlayer.playerDungeon.players = dungeonPlayer.playerDungeon.players.filter(obj => obj.userID !== message.author.id) + + // Chooses random leader if leader left + console.log("Is there a leader: " + dungeonPlayer.playerDungeon.players.find(l => l.leader) === true); + if (dungeonPlayer.playerDungeon.players.find(l => l.leader) === undefined) { + for (let i = 0; i < dungeonPlayer.playerDungeon.players.length; i++) { + const element = dungeonPlayer.playerDungeon.players[i]; + console.log(element); + if (element.commander) { + element.commander = false; + element.leader = true; + message.channel.send(`<@${element.userID}> has been promoted to leader!`); + break; + } + } + + // If there is no commander, promote first person on list + for (let i = 0; i < dungeonPlayer.playerDungeon.players.length; i++) { + const element = dungeonPlayer.playerDungeon.players[i]; + element.commander = false; + element.leader = true; + message.channel.send(`<@${element.userID}> has been promoted to leader!`); + break; + } + } + + // Destroy dungeon if last player + if (dungeonPlayer.playerDungeon.players.length === 0) { + BotInactive(dungeonPlayer.playerDungeon); + } + }); + } +} + +// Checks if direction can be done (skips anything other than Directions.XXXX) +function checkValidMovement(direction, dungeon, silent) { + var directionFailure; + switch (direction) { + case Directions.NORTH: + if (dungeon.location.connections.north === undefined) { + directionFailure = "**north**"; + } + break; + case Directions.EAST: + if (dungeon.location.connections.east === undefined) { + directionFailure = "**east**"; + } + break; + case Directions.SOUTH: + if (dungeon.location.connections.south === undefined) { + directionFailure = "**south**"; + } + break; + case Directions.WEST: + if (dungeon.location.connections.west === undefined) { + directionFailure = "**west**"; + } + break; + } + + if (directionFailure) { + if (!silent) { + var deniedMessage = `:x: ${user} You can't go ${directionFailure}, please choose a valid path.`; + client.channels.get(dungeon.room.channel).send(deniedMessage); + } + return false; + } + return true; +} + +// Moves in the dungeon +// TODO ITEM +async function move(direction, dungeon, isPartyLeader, user, moveToOverride) { + if (dungeon === undefined) return console.log("Dungeon doesn't exist!"); + + var channel = client.channels.get(dungeon.room.channel); + var newRoom; + + if (!isPartyLeader) return channel.send(`:x: ${user} You need to be a Party Leader or be **!promoted** to Commander in order to move.`); + if (!checkValidMovement(direction, dungeon)) return; + + // Says something if command can be done + switch (direction) { + case Directions.NORTH: + if (dungeon.location.connections.north !== undefined) { + newRoom = dungeon.location.connections.north; + //channel.send(":white_check_mark: **Command accepted.** Following the party **north**."); + } + break; + case Directions.EAST: + if (dungeon.location.connections.east !== undefined) { + newRoom = dungeon.location.connections.east; + //channel.send(":white_check_mark: **Command accepted.** Following the party **east**."); + } + break; + case Directions.SOUTH: + if (dungeon.location.connections.south !== undefined) { + newRoom = dungeon.location.connections.south; + //channel.send(":white_check_mark: **Command accepted.** Following the party **south**."); + } + break; + case Directions.WEST: + if (dungeon.location.connections.west !== undefined) { + newRoom = dungeon.location.connections.west; + //channel.send(":white_check_mark: **Command accepted.** Following the party **west**."); + } + break; + default: + // If uses a custom moveTo statement + if (moveToOverride) { + newRoom = moveToOverride; + // Else if no override + } else if (dungeon.dialogObj.moveTo) { + newRoom = dungeon.dialogObj.moveTo; + } + break; + } + + // Reroutes rooms + dungeon.reroutedRooms.forEach(element => { + console.log("[Move Reroute Rooms] " + element[0] + " " + element[1] + " " + newRoom + " " + (element[0] === newRoom)); + if (element[0] === newRoom) newRoom = element[1]; + }); + + console.log("[New Room]: " + newRoom + " | [Old Room]: " + dungeon.location.name); + switch (newRoom) { + case "__END": + await client.channels.get(process.env.TEST_CHANNEL_ID).send(`The **${dungeon.room.name}** dungeon has been completed!`); + await channel.send(`Congratulations! The party completed the **${dungeon.room.name}** dungeon with **${fmtMSS(dungeon.timer / 1000)} min. left**!`); + BotInactive(dungeon); + break; + + default: + dungeon.location = dungeon.room[newRoom]; + sendEmbedLocation(dungeon); + break; + } + console.log("[New Location]: " + dungeon.location.name); +} + +// Movement option text +function movementOptions(dungeon) { + var temp = ""; + + if (dungeon.location.northtext !== "" && dungeon.location.northtext) + temp += `:arrow_up: ${dungeon.location.northtext}\n`; + if (dungeon.location.easttext !== "" && dungeon.location.easttext) + temp += `:arrow_right: ${dungeon.location.easttext}\n`; + if (dungeon.location.southtext !== "" && dungeon.location.southtext) + temp += `:arrow_down: ${dungeon.location.southtext}\n`; + if (dungeon.location.westtext !== "" && dungeon.location.westtext) + temp += `:arrow_left: ${dungeon.location.westtext}\n`; + return temp; +} + +async function sendInventory(playerDungeon, pageNum) { + var items = ""; + + // Creates an array that seperates 10 items into seperate arrays each + var groupedArr = createGroupedArray(playerDungeon.items, 5); + + // Sets a default page num, or makes it human readable + if (pageNum === undefined) pageNum = 0; else { + pageNum--; + if (pageNum < 0) pageNum = 0; + if (groupedArr.length < pageNum) pageNum = groupedArr.length; + } + + // Checks if page number is valid + if (pageNum + 1 > groupedArr.length) { + // If it's longer than actual length, but isn't just an empty inventory + if (!groupedArr.length === 0) return; + } + + // Grabs item in loop, parses it, then adds it to "items" variable + if (groupedArr[pageNum]) { + for (let index = 0; index < groupedArr[pageNum].length; index++) { + // Grabs an item, from a page index + const element = groupedArr[pageNum][index]; + + // Makes if there is an emote, it'll add an extra space + var emoteText = ""; + if (element.emote) emoteText = element.emote + " "; + + // Adds it in + items += `> ${emoteText}**${element.name}** [${element.amount}x] ${element.info}\n`; + } + } + + // No items message to fill field + if (items === "") items = "There are no items in the party's inventory."; + + // To make the message of "Page 1/0" with no items in !pinventory not happen + var moddedLength = groupedArr.length; + if (moddedLength < 1) moddedLength = 1; + + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", client.user.avatarURL) + .setColor(playerDungeon.room.color) + .addField(`Party Inventory (Page ${pageNum + 1}/${moddedLength})`, items, true) + //.setDescription(`${items}`) + + client.channels.get(playerDungeon.room.channel).send({embed}); +} + +// Sends location into chat (non-embed) +function sendLocation(dungeon, author) { + var temp = `Current Room: **${dungeon.location.name}**\n\n`; + temp += location(dungeon); + temp += "\n\n"; + temp += movementOptions(dungeon); + + // Sends message + var channel = client.channels.get(dungeon.room.channel); + channel.send(author + " " + temp); +} + +// Sends location into chat (embed) +async function sendEmbedLocation(dungeon) { + if (dungeon.directionalMessageID) { + dungeon.directionalCollector.stop(); + } + var channel = client.channels.get(dungeon.room.channel); + + // Does image for background (future map) + const imageEmbed = new Discord.RichEmbed() + //.setAuthor("Ghost", client.user.avatarURL) + .setColor(dungeon.room.color) + .setImage(dungeon.location.image_url) + await channel.send({embed: imageEmbed}); + + // Does text dialog + const textEmbed = new Discord.RichEmbed() + .setAuthor("Ghost", client.user.avatarURL) + .setTitle(`${dungeon.location.name}`) + .setColor(dungeon.room.color) + .setDescription(`${location(dungeon)}\n\n${movementOptions(dungeon)}`) + var newMessage = await channel.send({embed: textEmbed}); + + // Collects emotes and reacts upon the reaction (120 seconds) + var options = ['⬆', '⬇', '⬅', '➡'] + const collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); + + // Reacts + for (let i = 0; i < options.length; i++) { + const element = options[i]; + console.log("[Reaction Options] Emote: " + element + " | newMessage: " + newMessage); + await newMessage.react(element); + } + + // Collect + collector.once("collect", async reaction => { + const user = reaction.users.last(); + var moveSuccessful; + switch (reaction.emoji.name) { + case '⬆': + moveSuccessful = move(Directions.NORTH, dungeon, (getDungeonPlayer(user.id).isLeader || getDungeonPlayer(user.id).isCommander), user, false); + break; + + case '⬇': + moveSuccessful = move(Directions.SOUTH, dungeon, (getDungeonPlayer(user.id).isLeader || getDungeonPlayer(user.id).isCommander), user, false); + break; + + case '⬅': + moveSuccessful = move(Directions.WEST, dungeon, (getDungeonPlayer(user.id).isLeader || getDungeonPlayer(user.id).isCommander), user, false); + break; + + case '➡': + moveSuccessful = move(Directions.EAST, dungeon, (getDungeonPlayer(user.id).isLeader || getDungeonPlayer(user.id).isCommander), user, false); + break; + } + collector.stop(); + + }); + + // End trigger + collector.once("end", collecter => { + console.log("[Reaction Options] [sendEmbedLocation] Ended collector, clearing emotes and sending timing out message if needed."); + newMessage.edit(newMessage.content); + }); +} + +// Sends location descriptions (Text) +function location(dungeon) { + var temp = ""; + + for (let index = 0; index < dungeon.location.descriptions.length; index++) { + const element = dungeon.location.descriptions[index]; + if (element.text !== undefined) { + temp += element.text + " "; + } + } + + //console.log(temp); + return temp; +} + +// Sends party members (Embed) +function partyMembers(dungeon, pageNum) { + // Updates players + updatePlayers(); + var playerString = ""; + var userInfo = ""; + + //console.log("0: " + pageNum); + if (pageNum === undefined) + pageNum = 0; + else + pageNum--; + + //console.log("1: " + pageNum) + var groupedArr = createGroupedArray(dungeon.players, 9); + //console.log(groupedArr); + //console.log("\n\nGROUPEDARR[PAGENUM]: " + groupedArr[pageNum] + "\n\n") + + if (pageNum + 1 > groupedArr.length) return; // If it's longer than actual length + if (groupedArr[pageNum] !== undefined) { + for (let index = 0; index < groupedArr[pageNum].length; index++) { + //const user = dungeon.players[index]; + const element = groupedArr[pageNum][index]; + + playerString += `${element.factionEmote}${element.badge} ${playerName(element.userID)}\n`; + userInfo += `${element.combatClassEmote} ${element.combatClass} ${element.isLeaderText}\n`; + //console.log("playerString:\n" + playerString); + //console.log("userInfo:\n " + userInfo); + } + } + + if (playerString == "") playerString = "None."; + if (userInfo == "") userInfo = "None."; + + const embed = new Discord.RichEmbed() + .setAuthor("Ghost", client.user.avatarURL) + //.setTitle("Hell's Gate: Dungeon Raid") + /* + * Alternatively, use "#00AE86", [0, 174, 134] or an integer number. + */ + .setColor(dungeon.room.color) + .setTitle(`${dungeon.location.name}`) + .setDescription(`The **!party** is currently on floor ${dungeon.location.floor}. The leader can **!promote** users so they can interact with the dungeon.`) + //.setImage("https://i.imgur.com/WyI8YuR.png") + //.setThumbnail("https://i.imgur.com/BZgLV7w.png") + //.setThumbnail("https://i.imgur.com/BlQTi94.jpg") + + .addField(`Party Members (Page ${pageNum + 1}/${groupedArr.length})`, playerString, true) + .addField("User Info", `${userInfo}`, true) + + client.channels.get(dungeon.room.channel).send({embed}); +} + +// Promote user to become leader +function promoteCommander(author, mentionedMember, leader, channelID) { + if (mentionedMember !== undefined ) { + if (leader) { + var dungeonPlayer = getDungeonPlayer(mentionedMember.id); + if (dungeonPlayer.player) { + if (author.id !== mentionedMember.id) { + if (!dungeonPlayer.isCommander) { + sendMessage(channelID, `:white_check_mark: ${author} has been **!promote**d ${mentionedMember} to commander status!`); + dungeonPlayer.player.commander = true; + } else { + sendMessage(channelID, `:x: ${author} **Command denied.** User already has been **!promote**d.`); + } + } else { + sendMessage(channelID, `:x: ${author} **Command denied.** You cannot promote yourself.`); + } + } + else + sendMessage(channelID, `:x: ${author} **Command denied.** The user being promoted has to be in the party.`); + } + else + sendMessage(channelID, `:x: ${author} **Command denied.** You need to be a leader in order to **!promote** others.`); + } else { + temp = author + " !promote (!pr)\n```If you're the leader, you can promote others to be a commander with you in order to move around.```" + sendMessage(channelID, temp); + } +} + +// Promote user to become leader +function demoteCommander(author, mentionedMember, leader, channelID) { + if (mentionedMember !== undefined ) { + if (leader) { + var dungeonPlayer = getDungeonPlayer(mentionedMember.id); + if (dungeonPlayer.player) { + if (author.id !== mentionedMember.id) { + if (dungeonPlayer.isCommander) { + sendMessage(channelID, `:white_check_mark: ${author} has **!demote**d ${mentionedMember} to normal status.`); + dungeonPlayer.player.commander = false; + } else { + sendMessage(channelID, `:x: ${author} **Command denied.** User already has been **!demote**d.`); + } + } else { + sendMessage(channelID, `:x: ${author} **Command denied.** You cannot promote yourself.`); + } + } + else + sendMessage(channelID, `:x: ${author} **Command denied.** The user being demoted has to be in the party.`); + } + else + sendMessage(channelID, `:x: ${author} **Command denied.** You need to be a leader in order to **!demote** others.`); + } else { + temp = author + " !demote (!de)\n```If you're the leader, you can demote others if needed if they are a commander.```" + sendMessage(channelID, temp); + } +} + +// Transfer party leadership +async function transferLeader(message, toUser) { + // From and to user transfer + if (toUser === undefined) return message.channel.send(`${message.author} I don't know that user, please try again with someone I can recognize, thanks.`); + + fromUser = getDungeonPlayer(message.author.id); + newUser = getDungeonPlayer(toUser.id); + + if (newUser.playerDungeon !== undefined && fromUser.playerDungeon !== undefined + && newUser.playerDungeon === fromUser.playerDungeon && fromUser.player.leader + && message.author.id !== toUser.id) { + + // Sends messages confirming it + var confirmMessage = await message.channel.send(`:warning: <@${message.author.id}> are you sure you want to give leadership to ${toUser}?\n*You'll be given Commander status afterwards.*`); + + // Reacts + await confirmMessage.react('✅'); + await confirmMessage.react('❌'); + + const collector = confirmMessage.createReactionCollector( + (reaction, user) => (reaction.emoji.name === '✅' || reaction.emoji.name === '❌') && user.id === message.author.id , { time: 15 * 1000 }); + var react = ""; + var endedOnReact; + + // Collect + collector.once("collect", async reaction => { + endedOnReact = true; + react = reaction.emoji.name; + collector.stop(); + }); + + // End trigger + collector.once("end", async collecter => { + console.log("[Reaction Options] Ended collector, clearing emotes and sending timing out message if needed."); + confirmMessage.edit(confirmMessage.content); + confirmMessage.clearReactions(); + if (!endedOnReact) return sendMessage(message.channel, ":x: **Timed Out**: The emote reaction request timed out after 15 seconds."); + if (react === '❌') return confirmMessage.edit(`:x: ${message.author} Cancelled giving leadership to ${toUser}.`); + + fromUser.player.leader = false; + fromUser.player.commander = true; + newUser.player.leader = true; + newUser.player.commander = false; + + await confirmMessage.edit(`:white_check_mark: ${message.author} has transferred leadership tp ${toUser}!`) + }); + } else { + if (newUser.playerDungeon !== fromUser.playerDungeon) { + return message.channel.send(`:x: ${message.author} The traveler must be in the party, or else I can't do anything about it.`); + } + + if (!fromUser.player.leader) { + return message.channel.send(`:x: ${message.author} You need to be a leader, in order to transfer your leadership.`) + } + + if (message.author.id === toUser.id) { + return message.channel.send(`:x: ${message.author} You cannot give yourself leadership if you are already the leader.`) + } + } +} + +// Log our bot in (change the token by looking into the .env file) +client.login(process.env.GHOST_TOKEN); \ No newline at end of file diff --git a/Troll/package-lock.json b/Troll/package-lock.json new file mode 100644 index 0000000..13e221c --- /dev/null +++ b/Troll/package-lock.json @@ -0,0 +1,723 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "combine-middlewares": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/combine-middlewares/-/combine-middlewares-0.1.0.tgz", + "integrity": "sha512-X7A6T6UAH1cULUIhDgvBol2XcvThuVrDMdD2ZPg9FEddEW3KsoKShd1yaRsMIl1v4Aj8dqSfehMXJxD/kwXJ2Q==" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deserialize-error": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/deserialize-error/-/deserialize-error-0.0.3.tgz", + "integrity": "sha1-9WhjNXLXwsxGpVpfwlS23857P8o=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "discord.js": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz", + "integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.3", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "engine.io": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", + "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "~1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "prism-media": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz", + "integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ==" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serialize-error": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=" + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "socket.io-request": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/socket.io-request/-/socket.io-request-0.8.0.tgz", + "integrity": "sha512-uZXUELbSNMbujTLFr+hGurZM+fhMLJ7fd3ZmM4FjrXXch5Cy9agLx6pBdzGjEdBblmhzj3Buo1SJvTub2VIf5A==", + "requires": { + "combine-middlewares": "^0.1.0", + "deserialize-error": "^0.0.3", + "serialize-error": "^2.0.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "ws": { + "version": "4.1.0", + "resolved": "http://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/Troll/package.json b/Troll/package.json new file mode 100644 index 0000000..69163ab --- /dev/null +++ b/Troll/package.json @@ -0,0 +1,29 @@ +{ + "name": "sanctum-deploypackage", + "version": "1.0.1", + "description": "Universal package for all SANCTUM bots, using pm2.", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "echo \"Error: you need to use the bot name as a command.\" && exit 1", + "alexis": "pm2 start alexis.js -i max --watch", + "graze": "pm2 start graze.js -i max --watch", + "librarian": "pm2 start librarian.js -i max --watch", + "mainframe": "pm2 start mainframe.js -i max --watch", + "mori": "pm2 start mori.js -i max --watch", + "mosiah": "pm2 start mosiah.js -i max --watch", + "ravager": "pm2 start ravager.js -i max --watch", + "rey": "pm2 start rey.js -i max --watch", + "troll": "pm2 start troll.js -i max --watch" + }, + "author": "", + "license": "ISC", + "dependencies": { + "discord.js": "^11.4.2", + "dotenv": "^6.0.0", + "express": "^4.16.3", + "node-cron": "^1.2.1", + "socket.io": "^2.1.1", + "socket.io-request": "^0.8.0" + } +} diff --git a/Troll/troll.js b/Troll/troll.js new file mode 100644 index 0000000..6262c55 --- /dev/null +++ b/Troll/troll.js @@ -0,0 +1,367 @@ +// .env Variables +require('dotenv').config({path: '../.env'}); + +// Node Modules +const Discord = require('discord.js'); +const client = new Discord.Client(); +const cron = require('node-cron'); + +// Bot Modules (stores http requests & random functions respectively) +const dataRequest = require('../modules/dataRequest'); +const calcRandom = require('../modules/calcRandom'); +var attacked = 0; + +// Playing activities state machine +var ActivityEnumState = { + GetDataActivity: 0, + ListenDataActivity: 1, + WatchingRavagersActivity: 2, + StreamingSanctumActivity: 3 +} +var activityState; + +// 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'); + ListenDataActivity(); + + //client.user.setActivity('sCRIBe of the Codex'); + console.log(`Connected! \ + \nLogged in as: ${client.user.username} - (${client.user.id})`); + + //client.channels.get(process.env.GATE_CHANNEL_ID).send("I'M YOUR NEW BABE EVERYONE! LOVE ME."); +}); + +// Create an event listener for messages +client.on('message', async message => { + // Ignores ALL bot messages + if (message.author.bot) return; + // Message has to be in Outskirts (should be edited later) + if (!(message.channel.id === process.env.STASIS_CHANNEL_ID + || message.channel.id === process.env.TEST_CHANNEL_ID)) return; + + + var wholeMessage = message.content.toLowerCase().replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g,""); + var words = wholeMessage.split(" "); + // Asking Alexis on a date + if (words.includes("librarian") && words.includes("date")) { + var dialogOptions = [ + 'IM LOVED.', + 'THANK YOU.', + ':thumbsup:', + 'I AM ALWAYS AVAILABLE UNLESS I\'M OFFLINE', + 'I\'M INTO ANYONE!', + 'YOU INTEREST ME.', + 'YES!!', + 'TELL ME MORE!', + 'YES DATE ME.' + ]; + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + message.channel.send(`${message.author} ${dialogOptions[randomNumber]}`); + return; + } + + // "This is the best way to define args. Trust me." + // - Some tutorial dude on the internet + const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/g); + const command = args.shift().toLowerCase(); + + // Has to be (prefix)command + if (message.content.indexOf(process.env.PREFIX) !== 0) return; + + switch (command) { + case "ping": + message.reply("PONGPINGPONGPINGPONG!"); + break; + case "attack": + attacked++; + message.channel.send(message.author + " ***OW. SCREW YOU!*** ```Attacked " + attacked + " times.```"); + break; + case "tip": + if (!args[0]) + message.reply("THANKS FOR THE " + args[0] + "!"); + else + message.reply("TIP ME ***SOMETHING!?!**"); + break; + case "orderordertaperecorder": + message.reply("YES."); + break; + case "eaglewritewhen": + message.reply("GOOD QUESTION"); + break; + case "tim": + message.reply("HE'S THE MURDERER!"); + break; + case "scavenge": + message.channel.send("YOU FOUND NOTHING BUT LIES! MWAHAHA."); + break; + case "codex": + message.reply("WHAT'S A CODEX. ***THERE IS NO SUCH THING.***"); + break; + case "secret": + message.reply("I MEAN, YOU TRIED! ***TRY HARDER***."); + break; + case "redacted": + message.reply("This is now ***REDACTED***.") + break; + case "buydrink": + var dialogOptions = [ + 'HOW DID YOU KNOW WE HAVE FREE BEER.', + 'TAKE YOUR DRINKS.', + 'GET DRUNK.', + 'ENJOY OR ELSE!', + 'IT\'S BEEN A MONTH. HOW MUCH LONGER!', + 'IT\'S DANGEROUS TO GO ALONE, TAKE THIS.', + 'IM ACTUALLY MESSING WITH YOUR MINDS BY SPIKING WITH THE DRINKS.', + 'HURRY UP AND COLLAPSE FROM THE BEER!', + 'MOOAAAARRR BEEER!', + 'EAGLE WRITE II WHEN.', + 'HEY, AT LEAST I TRY TO BE NICE.', + 'THE SOMEONE IS ALWAYS RIGHT FOUNDATION™ NEEDS YOUR CRYSTALS', + '**REDACTED** IS COMING TO SANCTUM.', + 'RELIGION SUX', + 'KAJSLKFDJLAJJ;OIF AEJOIEJGOIEJGOIEJGRA', + '1090190308401840184385825', + 'HERE IS SOME DIALOG. HAPPY?', + 'TICK TOCK KAI BUDDY, BETTER NOT KEEP **REDACTED** WAITIN. I HEARD HE\'S A VERY IMPATIENT MAN.', + 'DOES ANYONE READ THE TEXT.', + 'WHATEVER YOU DO YOU WILL NEVER FIND THE SECRET COMMAND', + 'PRESS ALT+F4 FOR FREE CRYSTALS.', + 'ONE DAY YOU WILL STOP FIGHTING FOR SOME STUPID THING.', + 'WHY DO YOU PLAY THIS GAME SO MUCH ANYWAYS.', + 'YOU CAN\'T FIGHT HERE. THIS IS THE WAR ROOM!', + 'HELL IS THE ULTIMATE TEST OF SURVIVAL WHERE YOU PROBABLY WILL GATE.', + 'WHAT DO YOU WANT ME TO DO, MORE BEER?', + 'FOR YOU SEE!™ THE PERSON WHO HAS BEEN KEEPING YOU HERE ALL ALONG IS...', + 'WHY AM I STILL HERE??', + 'WHAT DO YOU GUYS THINK OF ALEXIS COMPARED TO ME!', + 'CHECK THIS OUT.', + 'PEOPLE ACTUALLY TAKING BEER? CHECK.', + 'NO ROGUE BOT CHECK CAN STOP ME!', + `I AM THE LIBRARIAN. I HAND OUT LIVERS!` + ]; + + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + var newMessage = ""; + + if (message.mentions.members.size < 1) { + newMessage = ":beer: " + dialogOptions[randomNumber] + " <@" + message.author.id + ">! <:crystals:460974340247257089> **FREE**"; + } else { + // Huge scope creep, but have a list of players able to be given beer instead of just one later on + // For now, just taking the first player + let member = message.mentions.members.first(); + if (member) { + newMessage = ":beer: " + dialogOptions[randomNumber] + " <@" + member.user.id + ">!\n\n" + "***GIVEN BY *** <@" + message.author.id + "> AT GUNPOINT OR SOMETHING. <:crystals:460974340247257089> **FREE**"; + } else { + newMessage = ":x: <@" + message.author.id + "> YOU WANNA BUY ***WHO*** A ***WHAT*** NOW?"; + } + } + sendMessage(message.channel.id, newMessage); + break; + case "check": + if (message.channel.id == process.env.TEST_CHANNEL_ID) return; + message.reply("WOW, YOU FOUND IT. THIS MAY OR MAY NOT COME INTO SANCTUM, WE'RE ONLY PLANNING. DON'T EXCEPT IT, KEEP EXPECTATIONS LOW. HAVE MERCY ON THE OVERSEERS."); + const server = client.guilds.get(process.env.SANCTUM_ID); + const sizeLimit = 19; + var LVL = 2; + var minutes = 15; + var raidUsers = ["200340393596944384", "433759248800022532", "274301199841361920", + "150649616772235264", "201102155896193024", "454823752925052930"]; + var raidUserNames = []; + var userString = ``; + + // Collects usable usersnames + for (var i in raidUsers) { + // Use this totally not large line of code + var name = server.members.get(raidUsers[i]).displayName; + console.log("NAME: " + name); + + // If displayName (possible nickname) is too large + if (name.length > sizeLimit) { + // Grabs normal username + var username = client.users.get(raidUsers[i]).username; + console.log("EDITED NAME: " + name); + + // If that's too large + if (username.length > sizeLimit) { + // Uses displayName and adds "..." + name = truncate(name, sizeLimit); + } + } + raidUserNames.push(name); + } + + console.log("RAIDUSERNAMES: " + raidUserNames); + for (var r in raidUserNames) { + var emote; + if (server.members.get(raidUsers[i]).roles.has(process.env.GROUP_A_ROLE)) { + factionID = process.env.GROUP_A_ROLE; + } + userString += raidUserNames[r] + "\n"; + } + + const embed = new Discord.RichEmbed() + .setTitle(":triangular_flag_on_post: Hell's Gate: Dungeon Raid") + /* + * Alternatively, use "#00AE86", [0, 174, 134] or an integer number. + */ + .setColor("#e74c3c") + .setDescription(`**OUTDATED, PLEASE USE OTHER COMMANDS LIKE !join INSTEAD.** This dungeon is **Danger LVL ${LVL}**, it is relatively safe. The level will increase in the next **${minutes} minutes**. + The scouted map by TheSomeoneXD can be found [here](https://www.youtube.com/watch?v=dQw4w9WgXcQ).`) + .setFooter("OBBO Find X • OBSIDIAN TECHNOLOGIES") + //.setImage("https://i.imgur.com/BlQTi94.jpg") + //.setThumbnail("https://i.imgur.com/BZgLV7w.png") + .setThumbnail("https://i.imgur.com/BlQTi94.jpg") + .addField("Location", + `The party is at the beginning of the dungeon. There is a dying **!traveler** next to the stairs, starving. + **!north** leads up stairs, into a room with a Ravager. + **!west** leads to a chest room.`) + + .addField("Party Members", + `<:anarchy:460990297099337750>:shield: TheSomeoneXD\n\ + <:order:460991638152413194>:shield: *Totally NOT the FBI*\n\ + <:anarchy:460990297099337750>:crossed_swords: refraction\n\ + <:order:460991638152413194>:crossed_swords: FrozenAlex\n\ + <:religionhand:461582719051104276>:crossed_swords: Kai Buddy\n\ + <:religionhand:461582719051104276>:heart: Jim Ruswick`, true) + + .addField("User Info", + `Tank + Tank + DPS + DPS + DPS + Support`, true) + + message.channel.send({embed}); + break; + } +}); + +client.on('error', console.error); + +// You may use cron +//cron.schedule('* */1 * * *', function() { +cron.schedule('*/20 * * * *', function() { + /* + console.log('10 MIN.'); + var dialogOptions = [ + 'HEY! LISTEN!', + 'SANCTUM SHOULD COME IN A FEW YEARS, JUST WAIT.', + `HEY Y'ALL, LET'S SCAVENGE SOME OF YOUR MINDS OR SOMETHING.`, + `WINNERS DON'T DO DRUGS. EXCEPT STEROIDS. IN WHICH CASE, USE LOTS OF DRUGS!`, + `CHECK YOUR GUNS, WE'RE RAIDING THE CRYSTAL BANKS. AND I GET ALL OF IT!`, + `CODING YOUR OWN GAMES, IS EASIER THAN YOU THINK. YOU KNOW, YOU SHOULD TAKE THIS ONLINE COURSE ON UDEMY.`, + `MY FAVORITE ANIME IS CORY IN THE HOUSE.`, + `ORDER. ORDER. TAPE RECORDER.`, + `PLUSHIES ARE A DISEASE VECTOR.`, + `HURRY UP AND CHECK YOU IDIOTS. THERE'S A SECRET THAT YOU WILL NEVER FIND!`, + `TRAVELERS MAKE GOOD MEEEEAAAATTTTTTT!`, + `YOU THINK YOU CAN FIGHT, TRAVELERS??`, + `HEY Y'ALL, LET'S SCAVENGE US SOME NOTHING.`, + `I AM BEST BOT. DATE ME!`, + `C HASHTAG!`, + `ROSES ARE RED. VIOLETS ARE BLUE. THIS IS A TALE ABOUT... I FORGOT. HELP?`, + `<@200340393596944384> WHEN ARE YOU GOING TO CREATE **REDACTED**??` + ]; + + var randomNumber = Math.floor(Math.random() * dialogOptions.length); + client.channels.get(process.env.STASIS_CHANNEL_ID).send(dialogOptions[randomNumber]); + */ +}); + +// Every 15 minutes +cron.schedule('*/15 * * * *', () => { + var random = calcRandom.random(0, 2); + switch (random) { + case 0: + GetDataActivity(); + break; + case 1: + ListenDataActivity(); + break; + case 2: + WatchingRavagersActivity(); + break; + } + +}); + +function GetDataActivity() { + // Sets your "Playing" + client.user.setActivity("Collecting data.", { + type: "PLAYING" + }).then(presence => console.log(`Activity set to ${presence.game ? presence.game.name : 'none'}`)) + .catch(console.error); + + activityState = ActivityEnumState.GetDataActivity; +} + +function ListenDataActivity() { + // Sets your "Playing" + client.user.setActivity("something interesting.", { + type: "LISTENING" + }).then(presence => console.log(`Activity set to ${presence.game ? presence.game.name : 'none'}`)) + .catch(console.error); + + activityState = ActivityEnumState.ListenDataActivity; +} + +function WatchingRavagersActivity() { + // Sets your "Playing" + client.user.setActivity("for Ravager positions.", { + type: "WATCHING" + }).then(presence => console.log(`Activity set to ${presence.game ? presence.game.name : 'none'}`)) + .catch(console.error); + + activityState = ActivityEnumState.WatchingRavagersActivity; +} + +function StreamingSanctumActivity() { + // Sets your "Playing" + client.user.setActivity("developing Sanctum.", { + type: "STREAMING", + url: "https://www.twitch.tv/timruswick" + }).then(presence => console.log(`Activity set to ${presence.game ? presence.game.name : 'none'}`)) + .catch(console.error); + + activityState = ActivityEnumState.StreamingSanctumActivity; +} + +// Async Waiting +function sleep(time) { + return new Promise((resolve, reject) => { + setTimeout(resolve, time); + }); +} + +// Send message handler +function sendMessage(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message === undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message; + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); +} + +// Log our bot in (change the token by looking into the .env file) +client.login(process.env.LIBRARIAN_TOKEN); \ No newline at end of file diff --git a/modules/calcRandom.js b/modules/calcRandom.js new file mode 100644 index 0000000..b349ca7 --- /dev/null +++ b/modules/calcRandom.js @@ -0,0 +1,27 @@ +module.exports = { + // Changed it from exclusive high to inclusive high + random: function(low, high) { + return Math.floor(Math.random() * (high - low + 1) + low); + }, + + randomExc: function(low, high) { + return Math.floor(Math.random() * (high - low) + low); + }, + + // Random generation by % + gamble: function(percentage) { + // I found out that it wasn't acutally entirely accurate (0.1 difference) + // So I changed it to be 1 to 100, and have a <= instead of < + // I calculated it with PineTools and a small JS script to calculate it. + // Feel free to change it! + var winState = Math.floor(module.exports.random(1, 100)); + //var winState = Math.floor(module.exports.random(0, 101)); + + if (winState <= percentage) { + // if (winState < percentage) + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/modules/channelProcessor.js b/modules/channelProcessor.js new file mode 100644 index 0000000..18b10a5 --- /dev/null +++ b/modules/channelProcessor.js @@ -0,0 +1,34 @@ +require('dotenv').config({path: '../.env'}); + +module.exports = { + isBotChannel: function(channelID) { + // Insert new channels here + var botChannels = [ + process.env.GROUP_A_BOT_ID, + process.env.GROUP_B_BOT_ID, + process.env.GROUP_C_BOT_ID, + process.env.TEST_CHANNEL_ID + ]; + + // Apparently Outskirts was in the discord.io code, add that if needed + + for (let index = 0; index < botChannels.length; index++) { + const element = botChannels[index]; + if (channelID == element) return true; + } + + return false; + }, + + isRaidChannel: function(channelID) { + // Insert new channels here + var raidChannels = [ + process.env.HELLS_GATE_CHANNEL_ID + ]; + + for (let index = 0; index < raidChannels.length; index++) { + const element = raidChannels[index]; + if (channelID == element) return true; + } + } +} \ No newline at end of file diff --git a/modules/dataRequest.js b/modules/dataRequest.js new file mode 100644 index 0000000..e86ff8f --- /dev/null +++ b/modules/dataRequest.js @@ -0,0 +1,29 @@ +var request = require('sync-request'); +require('dotenv').config({path: '../.env'}); + +module.exports = { + loadServerData: function(dataToLoad, usersID = ''){ + var res = request('GET', `http://skullboxstudios.com/projects/sanctum/botserver/getData.php?pk=${process.env.SERVER_PASS_KEY}&dataToLoad=` + dataToLoad + '&userid=' + usersID); + console.log(res.getBody()); + return res.getBody(); + }, + + sendServerData: function(dataType, dataToSend, usersID = '', dataToSend2 = ''){ + var res = request('GET', `http://skullboxstudios.com/projects/sanctum/botserver/sendData.php?pk=${process.env.SERVER_PASS_KEY}&dataType=` + dataType + '&dataToSend=' + dataToSend + '&dataToSend2=' + dataToSend2 + '&userid=' + usersID); + console.log(res.getBody()); + return res.getBody(); + }, + + sendAttackData: function(dataType, dataToSend, dataToSend2 = ''){ + var res = request('GET', `http://skullboxstudios.com/projects/sanctum/botserver/sendPostData.php?pk=${process.env.SERVER_PASS_KEY}&dataType=` + dataType + '&dataToSend=' + dataToSend + '&dataToSend2=' + dataToSend2) + console.log(res.getBody()); + return res.getBody(); + }, + + // Possibly unused? + postServerData: function(dataType, dataToPost, dataToSend2 = ''){ + var res = request('POST', `http://skullboxstudios.com/projects/sanctum/botserver/sendPostData.php?pk=${process.env.SERVER_PASS_KEY}&dataType=` + dataType + '&dataToSend2=' + dataToSend2, dataToPost) + console.log(res.getBody()); + return res.getBody(); + } +} \ No newline at end of file diff --git a/modules/messages.js b/modules/messages.js new file mode 100644 index 0000000..bfc4aad --- /dev/null +++ b/modules/messages.js @@ -0,0 +1,20 @@ +// Do not use, no client reference + +module.exports = { + sendMessage: function(userID, channelID, message) { + // Handle optional first argument (so much for default arugments in node) + if (message == undefined) { + message = channelID; + channelID = userID; + userID = null; + } + + // Utility trick (@userID with an optional argument) + if (userID != null) { + message = "<@" + userID + "> " + message + } + + // Sends message (needs client var, therefore I think external script won't work) + client.channels.get(channelID).send(message); + } +} \ No newline at end of file