From d4d4d56bf6b0acc5243d9d0cedcfb872445321ff Mon Sep 17 00:00:00 2001 From: TheSomeoneXD <31833556+TheSomeoneXD@users.noreply.github.com> Date: Sat, 13 Oct 2018 01:40:27 -0500 Subject: [PATCH] Added package.json for modules to wor, and !inventory Pg. 0 bugfix --- ADAM/adam.js | 6 +- ADAM_CptMon/adam-cptmon.js | 6 +- ADAM_Dairo/adam-dairo.js | 6 +- ADAM_Ghost/adam-ghost.js | 6 +- ADAM_Kamala/adam-kamala.js | 6 +- Enemy/enemy.js | 180 +++++++++++----- Enemy_Crow/enemy-crow.js | 363 ++++++++++++++++++++++++++------- Enemy_Ravager/enemy-ravager.js | 363 ++++++++++++++++++++++++++------- Enemy_Wolf/enemy-wolf.js | 363 ++++++++++++++++++++++++++------- README.md | 10 +- package-lock.json | 293 ++++++++++++++++++++++++++ package.json | 17 ++ 12 files changed, 1351 insertions(+), 268 deletions(-) create mode 100644 package-lock.json create mode 100644 package.json diff --git a/ADAM/adam.js b/ADAM/adam.js index 1fac4b2..abd2d52 100644 --- a/ADAM/adam.js +++ b/ADAM/adam.js @@ -743,6 +743,8 @@ async function sendInventory(message, pageNum, newMessage) { // To make the message of "Page 1/0" with no items in !inventory not happen var moddedLength = groupedArr.length; if (moddedLength < 1) moddedLength = 1; + var moddedPageNum = pageNum; + if (moddedPageNum < 1) moddedPageNum = 1; const footer = getFooterCommands("!inventory"); @@ -751,7 +753,7 @@ async function sendInventory(message, pageNum, newMessage) { .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) + .addField(`Items (Page ${moddedPageNum}/${moddedLength})`, items) .setFooter(`Commands: ${footer}`) var invMessage; @@ -765,7 +767,7 @@ async function sendInventory(message, pageNum, newMessage) { // Collector for emotes const emotes = ['⬅', '❌', '➡']; const collector = invMessage.createReactionCollector( - (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id , { time: 15 * 1000 }); + (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id & message.author.id === user.id, { time: 15 * 1000 }); var react = ""; var endedOnReact; diff --git a/ADAM_CptMon/adam-cptmon.js b/ADAM_CptMon/adam-cptmon.js index 1fac4b2..abd2d52 100644 --- a/ADAM_CptMon/adam-cptmon.js +++ b/ADAM_CptMon/adam-cptmon.js @@ -743,6 +743,8 @@ async function sendInventory(message, pageNum, newMessage) { // To make the message of "Page 1/0" with no items in !inventory not happen var moddedLength = groupedArr.length; if (moddedLength < 1) moddedLength = 1; + var moddedPageNum = pageNum; + if (moddedPageNum < 1) moddedPageNum = 1; const footer = getFooterCommands("!inventory"); @@ -751,7 +753,7 @@ async function sendInventory(message, pageNum, newMessage) { .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) + .addField(`Items (Page ${moddedPageNum}/${moddedLength})`, items) .setFooter(`Commands: ${footer}`) var invMessage; @@ -765,7 +767,7 @@ async function sendInventory(message, pageNum, newMessage) { // Collector for emotes const emotes = ['⬅', '❌', '➡']; const collector = invMessage.createReactionCollector( - (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id , { time: 15 * 1000 }); + (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id & message.author.id === user.id, { time: 15 * 1000 }); var react = ""; var endedOnReact; diff --git a/ADAM_Dairo/adam-dairo.js b/ADAM_Dairo/adam-dairo.js index 1fac4b2..abd2d52 100644 --- a/ADAM_Dairo/adam-dairo.js +++ b/ADAM_Dairo/adam-dairo.js @@ -743,6 +743,8 @@ async function sendInventory(message, pageNum, newMessage) { // To make the message of "Page 1/0" with no items in !inventory not happen var moddedLength = groupedArr.length; if (moddedLength < 1) moddedLength = 1; + var moddedPageNum = pageNum; + if (moddedPageNum < 1) moddedPageNum = 1; const footer = getFooterCommands("!inventory"); @@ -751,7 +753,7 @@ async function sendInventory(message, pageNum, newMessage) { .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) + .addField(`Items (Page ${moddedPageNum}/${moddedLength})`, items) .setFooter(`Commands: ${footer}`) var invMessage; @@ -765,7 +767,7 @@ async function sendInventory(message, pageNum, newMessage) { // Collector for emotes const emotes = ['⬅', '❌', '➡']; const collector = invMessage.createReactionCollector( - (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id , { time: 15 * 1000 }); + (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id & message.author.id === user.id, { time: 15 * 1000 }); var react = ""; var endedOnReact; diff --git a/ADAM_Ghost/adam-ghost.js b/ADAM_Ghost/adam-ghost.js index 1fac4b2..abd2d52 100644 --- a/ADAM_Ghost/adam-ghost.js +++ b/ADAM_Ghost/adam-ghost.js @@ -743,6 +743,8 @@ async function sendInventory(message, pageNum, newMessage) { // To make the message of "Page 1/0" with no items in !inventory not happen var moddedLength = groupedArr.length; if (moddedLength < 1) moddedLength = 1; + var moddedPageNum = pageNum; + if (moddedPageNum < 1) moddedPageNum = 1; const footer = getFooterCommands("!inventory"); @@ -751,7 +753,7 @@ async function sendInventory(message, pageNum, newMessage) { .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) + .addField(`Items (Page ${moddedPageNum}/${moddedLength})`, items) .setFooter(`Commands: ${footer}`) var invMessage; @@ -765,7 +767,7 @@ async function sendInventory(message, pageNum, newMessage) { // Collector for emotes const emotes = ['⬅', '❌', '➡']; const collector = invMessage.createReactionCollector( - (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id , { time: 15 * 1000 }); + (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id & message.author.id === user.id, { time: 15 * 1000 }); var react = ""; var endedOnReact; diff --git a/ADAM_Kamala/adam-kamala.js b/ADAM_Kamala/adam-kamala.js index 1fac4b2..abd2d52 100644 --- a/ADAM_Kamala/adam-kamala.js +++ b/ADAM_Kamala/adam-kamala.js @@ -743,6 +743,8 @@ async function sendInventory(message, pageNum, newMessage) { // To make the message of "Page 1/0" with no items in !inventory not happen var moddedLength = groupedArr.length; if (moddedLength < 1) moddedLength = 1; + var moddedPageNum = pageNum; + if (moddedPageNum < 1) moddedPageNum = 1; const footer = getFooterCommands("!inventory"); @@ -751,7 +753,7 @@ async function sendInventory(message, pageNum, newMessage) { .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) + .addField(`Items (Page ${moddedPageNum}/${moddedLength})`, items) .setFooter(`Commands: ${footer}`) var invMessage; @@ -765,7 +767,7 @@ async function sendInventory(message, pageNum, newMessage) { // Collector for emotes const emotes = ['⬅', '❌', '➡']; const collector = invMessage.createReactionCollector( - (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id , { time: 15 * 1000 }); + (reaction, user) => emotes.includes(reaction.emoji.name) && user.id !== client.user.id & message.author.id === user.id, { time: 15 * 1000 }); var react = ""; var endedOnReact; diff --git a/Enemy/enemy.js b/Enemy/enemy.js index 85f406f..bf3ee8e 100644 --- a/Enemy/enemy.js +++ b/Enemy/enemy.js @@ -31,7 +31,7 @@ class EnemyBatchInstance { this.channel = channel; // Channel of spawning this.spawnPrecentage = 100; this.hostileLevel = 1; - this.fastSummon = true; // Show prowling + this.fastSummon = false; // Show prowling } } @@ -148,7 +148,7 @@ client.on('message', async message => { if (isAdmin(message.author.id)) message.reply("***...MRGRGRGR!***"); break; - case "ravager": + case npcSettings.id: if (args[0].toLowerCase() === "summon" && isAdmin(message.author.id)) { generateEnemy(process.env.DEADLANDS_CHANNEL_ID); } @@ -317,69 +317,151 @@ async function enemyTimer(newEnemy, data, channel, fleeTime, newMessage) { .setTitle("Status") .setDescription("...") + const sendMessageMinimum = true; 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); + var options = ['💥', '🇦', '🇧', '🇨'] - // Send damage to server - // TODO - }); - - // Ends - collector.once("end", async collector => { + // System for no message sending except the minimum + if (sendMessageMinimum) { + // Collects emotes and reacts upon the reaction + const collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); - }); + sendReactions(options); + + // Collect + collector.on("collect", async reaction => { + var user = reaction.users.last(); - // Goes every 4 seconds - var emoteRefresh = setInterval(async () => { - await newMessage.clearReactions(); - interactionEmbed.setDescription("..."); + // Just in case, I managed to bug out Ravager to display its own name. + if (user.id === client.user.id) { + console.log("Well then. It bypassed the collector filter, we're stopping the Ravager from attacking itself. Would be interesting though!"); + return; + } - 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); + // Send damage to server + // TODO + + tempAttackUsers += `${user} :crossed_swords: 11 DAM | <:hitback:460969716580745236> MISS (150/150)\n`; + addUserToArray(user.id); + console.log("Collecting a user! " + user.username) + }); + + // Ends + collector.once("end", async collector => { + console.log("Ended collector.") + flee(newEnemy, data, client.channels.get(channel)); + }); + + // Goes every 4 seconds + var emoteRefresh = setInterval(async () => { + await newMessage.clearReactions(); + + 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 { + console.log("Sending refreshed embed... |" + tempAttackUsers + "|") + if (tempAttackUsers === "") tempAttackUsers = "..."; + interactionEmbed.setDescription(tempAttackUsers); + 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; + } } - - 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); + } else { + // Collects emotes and reacts upon the reaction + var collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); - // 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; + sendReactions(options); + + // Collect + collector.on("collect", async reaction => { + var user = reaction.users.last(); + + // Just in case, I managed to bug out Ravager to display its own name. + if (user.id === client.user.id) { + console.log("Well then. It bypassed the collector filter, we're stopping the Ravager from attacking itself. Would be interesting though!"); + return; + } + + // Send damage to server + // TODO + + tempAttackUsers += `${user} :crossed_swords: 11 DAM | <:hitback:460969716580745236> MISS (150/150)\n`; + addUserToArray(user.id); + console.log("Collecting a user! " + user.username) + }); + + // Ends + collector.once("end", async collector => { + console.log("Ended collector.") + flee(newEnemy, data, client.channels.get(channel)); + }); + + // Goes every 4 seconds + var emoteRefresh = setInterval(async () => { + await newMessage.clearReactions(); + + 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 { + console.log("Sending refreshed embed... |" + tempAttackUsers + "|") + if (tempAttackUsers === "") tempAttackUsers = "..."; + interactionEmbed.setDescription(tempAttackUsers); + 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; + } } } } +// Does flee sequence 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', { @@ -391,6 +473,8 @@ async function flee(newEnemy, data, newChannel) { await client.user.setPresence('invisible'); client.user.setActivity('Prowling...'); } + + console.log(data); } // Health bar diff --git a/Enemy_Crow/enemy-crow.js b/Enemy_Crow/enemy-crow.js index 81c43e8..bf3ee8e 100644 --- a/Enemy_Crow/enemy-crow.js +++ b/Enemy_Crow/enemy-crow.js @@ -11,18 +11,70 @@ const io = require('socket.io-client'); 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 RavagerState = { +var EnemyState = { INACTIVE: 0, PROWLING: 1, ACTIVE: 2, UNCONSCIOUS: 3 } -const prowling = 'Prowling...'; +// 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 = false; // 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) => { @@ -52,10 +104,15 @@ client.on('ready', async () => { // You can set status to 'online', 'invisible', 'away', or 'dnd' (do not disturb) client.user.setStatus('invisible'); // Sets your "Playing" - client.user.setActivity(prowling); + 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"; @@ -91,6 +148,11 @@ client.on('message', async message => { if (isAdmin(message.author.id)) message.reply("***...MRGRGRGR!***"); break; + case npcSettings.id: + if (args[0].toLowerCase() === "summon" && isAdmin(message.author.id)) { + generateEnemy(process.env.DEADLANDS_CHANNEL_ID); + } + break; } }); @@ -100,20 +162,95 @@ 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) { - // 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) { @@ -124,7 +261,7 @@ async function summonEnemy(data) { // Sets prowling states on the Ravagers for (let i = 0; i < data.enemies.length; i++) { const element = data.enemies[i]; - element.state = RavagerState.PROWLING; + element.state = EnemyState.PROWLING; } // Notification code @@ -151,14 +288,14 @@ async function summonEnemy(data) { for (let i = 0; i < data.enemies.length; i++) { const element = data.enemies[i]; - element.state = RavagerState.ACTIVE; + element.state = EnemyState.ACTIVE; } enemyTimer(element, data, data.channel, element.fleeTime, newMessage); } } // Counts down -async function enemyTimer(newRavager, data, channel, fleeTime, newMessage) { +async function enemyTimer(newEnemy, data, channel, fleeTime, newMessage) { function addUserToArray(userID) { attackingUsers.push(userID); } @@ -180,84 +317,164 @@ async function enemyTimer(newRavager, data, channel, fleeTime, newMessage) { .setTitle("Status") .setDescription("...") + const sendMessageMinimum = true; 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}); + var options = ['💥', '🇦', '🇧', '🇨'] + + // System for no message sending except the minimum + if (sendMessageMinimum) { + // Collects emotes and reacts upon the reaction + const collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); + + sendReactions(options); + + // Collect + collector.on("collect", async reaction => { + var user = reaction.users.last(); + + // Just in case, I managed to bug out Ravager to display its own name. + if (user.id === client.user.id) { + console.log("Well then. It bypassed the collector filter, we're stopping the Ravager from attacking itself. Would be interesting though!"); + return; + } + + // Send damage to server + // TODO + + tempAttackUsers += `${user} :crossed_swords: 11 DAM | <:hitback:460969716580745236> MISS (150/150)\n`; + addUserToArray(user.id); + console.log("Collecting a user! " + user.username) + }); + + // Ends + collector.once("end", async collector => { + console.log("Ended collector.") + flee(newEnemy, data, client.channels.get(channel)); + }); + + // Goes every 4 seconds + var emoteRefresh = setInterval(async () => { + await newMessage.clearReactions(); + + 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 { + console.log("Sending refreshed embed... |" + tempAttackUsers + "|") + if (tempAttackUsers === "") tempAttackUsers = "..."; + interactionEmbed.setDescription(tempAttackUsers); + 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; + } } - - // Send damage. + } else { + // Collects emotes and reacts upon the reaction + var collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); - }); - - // Ends - collector.once("end", async collector => { + sendReactions(options); - }); + // Collect + collector.on("collect", async reaction => { + var user = reaction.users.last(); - // Goes every 4 seconds - var emoteRefresh = setInterval(async () => { - await newMessage.clearReactions(); - interactionEmbed.setDescription("..."); + // Just in case, I managed to bug out Ravager to display its own name. + if (user.id === client.user.id) { + console.log("Well then. It bypassed the collector filter, we're stopping the Ravager from attacking itself. Would be interesting though!"); + return; + } - 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); - } + // Send damage to server + // TODO - tempAttackUsers = ""; - }, 5 * 1000); - + tempAttackUsers += `${user} :crossed_swords: 11 DAM | <:hitback:460969716580745236> MISS (150/150)\n`; + addUserToArray(user.id); + console.log("Collecting a user! " + user.username) + }); - // 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); + // Ends + collector.once("end", async collector => { + console.log("Ended collector.") + flee(newEnemy, data, client.channels.get(channel)); + }); + + // Goes every 4 seconds + var emoteRefresh = setInterval(async () => { + await newMessage.clearReactions(); + + 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 { + console.log("Sending refreshed embed... |" + tempAttackUsers + "|") + if (tempAttackUsers === "") tempAttackUsers = "..."; + interactionEmbed.setDescription(tempAttackUsers); + if (interactionMessage) await interactionMessage.edit({embed: interactionEmbed}); + sendReactions(options); + } + + tempAttackUsers = ""; + }, 5 * 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; + + // 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(newRavager, data, newChannel) { +// Does flee sequence +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: newRavager + ravager: newEnemy }); if (data.length < 1) { await client.user.setPresence('invisible'); client.user.setActivity('Prowling...'); } + + console.log(data); } // Health bar @@ -306,6 +523,14 @@ function fmtMSS(s){ // accepts seconds as Number or String. Returns m:ss ) + 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": diff --git a/Enemy_Ravager/enemy-ravager.js b/Enemy_Ravager/enemy-ravager.js index 81c43e8..bf3ee8e 100644 --- a/Enemy_Ravager/enemy-ravager.js +++ b/Enemy_Ravager/enemy-ravager.js @@ -11,18 +11,70 @@ const io = require('socket.io-client'); 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 RavagerState = { +var EnemyState = { INACTIVE: 0, PROWLING: 1, ACTIVE: 2, UNCONSCIOUS: 3 } -const prowling = 'Prowling...'; +// 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 = false; // 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) => { @@ -52,10 +104,15 @@ client.on('ready', async () => { // You can set status to 'online', 'invisible', 'away', or 'dnd' (do not disturb) client.user.setStatus('invisible'); // Sets your "Playing" - client.user.setActivity(prowling); + 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"; @@ -91,6 +148,11 @@ client.on('message', async message => { if (isAdmin(message.author.id)) message.reply("***...MRGRGRGR!***"); break; + case npcSettings.id: + if (args[0].toLowerCase() === "summon" && isAdmin(message.author.id)) { + generateEnemy(process.env.DEADLANDS_CHANNEL_ID); + } + break; } }); @@ -100,20 +162,95 @@ 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) { - // 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) { @@ -124,7 +261,7 @@ async function summonEnemy(data) { // Sets prowling states on the Ravagers for (let i = 0; i < data.enemies.length; i++) { const element = data.enemies[i]; - element.state = RavagerState.PROWLING; + element.state = EnemyState.PROWLING; } // Notification code @@ -151,14 +288,14 @@ async function summonEnemy(data) { for (let i = 0; i < data.enemies.length; i++) { const element = data.enemies[i]; - element.state = RavagerState.ACTIVE; + element.state = EnemyState.ACTIVE; } enemyTimer(element, data, data.channel, element.fleeTime, newMessage); } } // Counts down -async function enemyTimer(newRavager, data, channel, fleeTime, newMessage) { +async function enemyTimer(newEnemy, data, channel, fleeTime, newMessage) { function addUserToArray(userID) { attackingUsers.push(userID); } @@ -180,84 +317,164 @@ async function enemyTimer(newRavager, data, channel, fleeTime, newMessage) { .setTitle("Status") .setDescription("...") + const sendMessageMinimum = true; 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}); + var options = ['💥', '🇦', '🇧', '🇨'] + + // System for no message sending except the minimum + if (sendMessageMinimum) { + // Collects emotes and reacts upon the reaction + const collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); + + sendReactions(options); + + // Collect + collector.on("collect", async reaction => { + var user = reaction.users.last(); + + // Just in case, I managed to bug out Ravager to display its own name. + if (user.id === client.user.id) { + console.log("Well then. It bypassed the collector filter, we're stopping the Ravager from attacking itself. Would be interesting though!"); + return; + } + + // Send damage to server + // TODO + + tempAttackUsers += `${user} :crossed_swords: 11 DAM | <:hitback:460969716580745236> MISS (150/150)\n`; + addUserToArray(user.id); + console.log("Collecting a user! " + user.username) + }); + + // Ends + collector.once("end", async collector => { + console.log("Ended collector.") + flee(newEnemy, data, client.channels.get(channel)); + }); + + // Goes every 4 seconds + var emoteRefresh = setInterval(async () => { + await newMessage.clearReactions(); + + 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 { + console.log("Sending refreshed embed... |" + tempAttackUsers + "|") + if (tempAttackUsers === "") tempAttackUsers = "..."; + interactionEmbed.setDescription(tempAttackUsers); + 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; + } } - - // Send damage. + } else { + // Collects emotes and reacts upon the reaction + var collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); - }); - - // Ends - collector.once("end", async collector => { + sendReactions(options); - }); + // Collect + collector.on("collect", async reaction => { + var user = reaction.users.last(); - // Goes every 4 seconds - var emoteRefresh = setInterval(async () => { - await newMessage.clearReactions(); - interactionEmbed.setDescription("..."); + // Just in case, I managed to bug out Ravager to display its own name. + if (user.id === client.user.id) { + console.log("Well then. It bypassed the collector filter, we're stopping the Ravager from attacking itself. Would be interesting though!"); + return; + } - 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); - } + // Send damage to server + // TODO - tempAttackUsers = ""; - }, 5 * 1000); - + tempAttackUsers += `${user} :crossed_swords: 11 DAM | <:hitback:460969716580745236> MISS (150/150)\n`; + addUserToArray(user.id); + console.log("Collecting a user! " + user.username) + }); - // 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); + // Ends + collector.once("end", async collector => { + console.log("Ended collector.") + flee(newEnemy, data, client.channels.get(channel)); + }); + + // Goes every 4 seconds + var emoteRefresh = setInterval(async () => { + await newMessage.clearReactions(); + + 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 { + console.log("Sending refreshed embed... |" + tempAttackUsers + "|") + if (tempAttackUsers === "") tempAttackUsers = "..."; + interactionEmbed.setDescription(tempAttackUsers); + if (interactionMessage) await interactionMessage.edit({embed: interactionEmbed}); + sendReactions(options); + } + + tempAttackUsers = ""; + }, 5 * 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; + + // 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(newRavager, data, newChannel) { +// Does flee sequence +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: newRavager + ravager: newEnemy }); if (data.length < 1) { await client.user.setPresence('invisible'); client.user.setActivity('Prowling...'); } + + console.log(data); } // Health bar @@ -306,6 +523,14 @@ function fmtMSS(s){ // accepts seconds as Number or String. Returns m:ss ) + 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": diff --git a/Enemy_Wolf/enemy-wolf.js b/Enemy_Wolf/enemy-wolf.js index 81c43e8..bf3ee8e 100644 --- a/Enemy_Wolf/enemy-wolf.js +++ b/Enemy_Wolf/enemy-wolf.js @@ -11,18 +11,70 @@ const io = require('socket.io-client'); 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 RavagerState = { +var EnemyState = { INACTIVE: 0, PROWLING: 1, ACTIVE: 2, UNCONSCIOUS: 3 } -const prowling = 'Prowling...'; +// 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 = false; // 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) => { @@ -52,10 +104,15 @@ client.on('ready', async () => { // You can set status to 'online', 'invisible', 'away', or 'dnd' (do not disturb) client.user.setStatus('invisible'); // Sets your "Playing" - client.user.setActivity(prowling); + 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"; @@ -91,6 +148,11 @@ client.on('message', async message => { if (isAdmin(message.author.id)) message.reply("***...MRGRGRGR!***"); break; + case npcSettings.id: + if (args[0].toLowerCase() === "summon" && isAdmin(message.author.id)) { + generateEnemy(process.env.DEADLANDS_CHANNEL_ID); + } + break; } }); @@ -100,20 +162,95 @@ 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) { - // 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) { @@ -124,7 +261,7 @@ async function summonEnemy(data) { // Sets prowling states on the Ravagers for (let i = 0; i < data.enemies.length; i++) { const element = data.enemies[i]; - element.state = RavagerState.PROWLING; + element.state = EnemyState.PROWLING; } // Notification code @@ -151,14 +288,14 @@ async function summonEnemy(data) { for (let i = 0; i < data.enemies.length; i++) { const element = data.enemies[i]; - element.state = RavagerState.ACTIVE; + element.state = EnemyState.ACTIVE; } enemyTimer(element, data, data.channel, element.fleeTime, newMessage); } } // Counts down -async function enemyTimer(newRavager, data, channel, fleeTime, newMessage) { +async function enemyTimer(newEnemy, data, channel, fleeTime, newMessage) { function addUserToArray(userID) { attackingUsers.push(userID); } @@ -180,84 +317,164 @@ async function enemyTimer(newRavager, data, channel, fleeTime, newMessage) { .setTitle("Status") .setDescription("...") + const sendMessageMinimum = true; 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}); + var options = ['💥', '🇦', '🇧', '🇨'] + + // System for no message sending except the minimum + if (sendMessageMinimum) { + // Collects emotes and reacts upon the reaction + const collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); + + sendReactions(options); + + // Collect + collector.on("collect", async reaction => { + var user = reaction.users.last(); + + // Just in case, I managed to bug out Ravager to display its own name. + if (user.id === client.user.id) { + console.log("Well then. It bypassed the collector filter, we're stopping the Ravager from attacking itself. Would be interesting though!"); + return; + } + + // Send damage to server + // TODO + + tempAttackUsers += `${user} :crossed_swords: 11 DAM | <:hitback:460969716580745236> MISS (150/150)\n`; + addUserToArray(user.id); + console.log("Collecting a user! " + user.username) + }); + + // Ends + collector.once("end", async collector => { + console.log("Ended collector.") + flee(newEnemy, data, client.channels.get(channel)); + }); + + // Goes every 4 seconds + var emoteRefresh = setInterval(async () => { + await newMessage.clearReactions(); + + 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 { + console.log("Sending refreshed embed... |" + tempAttackUsers + "|") + if (tempAttackUsers === "") tempAttackUsers = "..."; + interactionEmbed.setDescription(tempAttackUsers); + 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; + } } - - // Send damage. + } else { + // Collects emotes and reacts upon the reaction + var collector = newMessage.createReactionCollector( + (reaction, user) => options.includes(reaction.emoji.name) && user.id !== client.user.id); - }); - - // Ends - collector.once("end", async collector => { + sendReactions(options); - }); + // Collect + collector.on("collect", async reaction => { + var user = reaction.users.last(); - // Goes every 4 seconds - var emoteRefresh = setInterval(async () => { - await newMessage.clearReactions(); - interactionEmbed.setDescription("..."); + // Just in case, I managed to bug out Ravager to display its own name. + if (user.id === client.user.id) { + console.log("Well then. It bypassed the collector filter, we're stopping the Ravager from attacking itself. Would be interesting though!"); + return; + } - 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); - } + // Send damage to server + // TODO - tempAttackUsers = ""; - }, 5 * 1000); - + tempAttackUsers += `${user} :crossed_swords: 11 DAM | <:hitback:460969716580745236> MISS (150/150)\n`; + addUserToArray(user.id); + console.log("Collecting a user! " + user.username) + }); - // 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); + // Ends + collector.once("end", async collector => { + console.log("Ended collector.") + flee(newEnemy, data, client.channels.get(channel)); + }); + + // Goes every 4 seconds + var emoteRefresh = setInterval(async () => { + await newMessage.clearReactions(); + + 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 { + console.log("Sending refreshed embed... |" + tempAttackUsers + "|") + if (tempAttackUsers === "") tempAttackUsers = "..."; + interactionEmbed.setDescription(tempAttackUsers); + if (interactionMessage) await interactionMessage.edit({embed: interactionEmbed}); + sendReactions(options); + } + + tempAttackUsers = ""; + }, 5 * 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; + + // 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(newRavager, data, newChannel) { +// Does flee sequence +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: newRavager + ravager: newEnemy }); if (data.length < 1) { await client.user.setPresence('invisible'); client.user.setActivity('Prowling...'); } + + console.log(data); } // Health bar @@ -306,6 +523,14 @@ function fmtMSS(s){ // accepts seconds as Number or String. Returns m:ss ) + 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": diff --git a/README.md b/README.md index 8104312..6b5c827 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ 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 +# Run the Bots ## Requirements: You will need: - [Node.js](https://nodejs.org/en/) (recommended v8.12.0 LTS) @@ -26,7 +26,11 @@ You will need: 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 + # If you already haven't, clone the repo + git clone https://github.com/TimRuswick/SANCTUM + cd "SANCTUM" + + # Choose a bot cd "A.D.A.M." npm i node adam.js @@ -34,7 +38,7 @@ You will need: 4. ??? -5. Profit! You did it, unless something has happened along the way. ~~Probably likely, sadly.~~ +5. Profit! You did it, unless something has happened along the way. ~~Developer luck says yes.~~ ## Quality of Life diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3b4d5c0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,293 @@ +{ + "name": "Sanctuary", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/concat-stream": { + "version": "1.6.0", + "resolved": "http://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": "http://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=", + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "9.6.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.35.tgz", + "integrity": "sha512-h5zvHS8wXHGa+Gcqs9K8vqCgOtqjr0+NqG/DDJmQIX1wpR9HivAfgV8bjcD3mGM4bPfQw5Aneb2Pn8355L83jA==" + }, + "@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=" + }, + "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=" + }, + "cjopus": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/cjopus/-/cjopus-0.0.4.tgz", + "integrity": "sha1-RvPPyWuD99eERt6LTP2ZS1iJqaA=" + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "http://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.io": { + "version": "github:woor/discord.io#4333acbc6f15542971f7503f4c1b1a07976a6615", + "from": "github:woor/discord.io#gateway_v6", + "requires": { + "cjopus": "^0.0.4", + "tweetnacl": "^0.14.0", + "ws": "^1.1.0" + } + }, + "dotenv": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-/veDn2ztgRlB7gKmE3i9f6CmDIyXAy6d5nBq+whO9SLX+Zs1sXEgFLPi+aSuWqUuusMfbi84fT8j34fs1HaYUw==" + }, + "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=" + }, + "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" + } + }, + "node-cron": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-1.2.1.tgz", + "integrity": "sha1-jJC8XccjpWKJsHhmVatKHEy2A2g=" + }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" + }, + "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=" + }, + "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.2", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz", + "integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==", + "requires": { + "asap": "~2.0.6" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://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==" + }, + "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.36", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.36.tgz", + "integrity": "sha512-SL6KhfM7PTqiFmbCW3eVNwVBZ+88Mrzbuvn9olPsfv43mbiWaFY+nRcz/TGGku0/lc2FepdMbImdMY1JrQ+zbw==" + } + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "ws": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", + "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", + "requires": { + "options": ">=0.0.5", + "ultron": "1.0.x" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..989b4df --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "Sanctuary", + "version": "1.0.0", + "description": "A text-based massively multiplayer game about the survival of the fittest.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Tim", + "license": "ISC", + "dependencies": { + "discord.io": "github:woor/discord.io#gateway_v6", + "dotenv": "^6.0.0", + "node-cron": "^1.2.1", + "sync-request": "^6.0.0" + } +}