diff --git a/commands/db/addons/snowflake.js b/commands/db/addons/snowflake.js new file mode 100644 index 0000000..9585469 --- /dev/null +++ b/commands/db/addons/snowflake.js @@ -0,0 +1,59 @@ +//THIS CODE WAS TAKEN FROM https://github.com/vegeta897/snow-stamp/blob/main/src/convert.js + +const DISCORD_EPOCH = 1420070400000 + +// Converts a snowflake ID string into a JS Date object using the provided epoch (in ms), or Discord's epoch if not provided +function convertSnowflakeToDate(snowflake, epoch = DISCORD_EPOCH) { + // Convert snowflake to BigInt to extract timestamp bits + // https://discord.com/developers/docs/reference#snowflakes + const milliseconds = BigInt(snowflake) >> 22n + return new Date(Number(milliseconds) + epoch); +} + +// Validates a snowflake ID string and returns a JS Date object if valid +function validateSnowflake(snowflake, epoch) { + if (!Number.isInteger(+snowflake)) { + throw new Error( + "That doesn't look like a snowflake. Snowflakes contain only numbers." + ) + } + + if (snowflake < 4194304) { + throw new Error( + "That doesn't look like a snowflake. Snowflakes are much larger numbers." + ) + } + + const timestamp = convertSnowflakeToDate(snowflake, epoch) + + if (Number.isNaN(timestamp.getTime())) { + throw new Error( + "That doesn't look like a snowflake. Snowflakes have fewer digits." + ) + } + + return timestamp +} + +module.exports = { convertSnowflakeToDate, validateSnowflake } + + + + +/* + +//TEST FUNCTION BY ION606 (for Discord ONLY) +async function TEST_FUNC(message) { + let mid = message.reference.messageId; + let msg = await message.channel.messages.fetch(mid); + let snowflake = require("./commands/db/addons/snowflake.js"); + let prev = snowflake.convertSnowflakeToDate(msg.id); + let now = snowflake.convertSnowflakeToDate(message.id); + let diff = now - prev; + var minutes = Math.floor((diff / 1000) / 60); + console.log(diff, minutes); + return { diff, minutes }; +} + + +*/ \ No newline at end of file diff --git a/commands/db/econ.js b/commands/db/econ.js index bb4aa5e..8f8081b 100644 --- a/commands/db/econ.js +++ b/commands/db/econ.js @@ -7,7 +7,8 @@ const { CLIENT_ODBC } = require('mysql/lib/protocol/constants/client'); const BASE = { PAY: 5, HP: 5, - MP: 10 + MP: 10, + XP: 5 } const STATE = { @@ -327,7 +328,7 @@ module.exports = { }, //Battle Updating stuff - addxp, checkAndUpdateBal, CreateNewCollection, econHelp, BASE, STATE + addxp, checkAndUpdateBal, CreateNewCollection, econHelp, addxp, BASE, STATE } diff --git a/commands/db/game.js b/commands/db/game.js index 3e3e98a..84a3092 100644 --- a/commands/db/game.js +++ b/commands/db/game.js @@ -1,7 +1,9 @@ const { MongoClient, ServerApiVersion } = require('mongodb'); let ecoimport = require("./econ.js"); let battle = require("./battle.js"); +let snowflake = require("./addons/snowflake.js"); const STATE = ecoimport.STATE; +const BASE = ecoimport.BASE; //Has a list of all games (used to change player state) const allGames = ['battle']; @@ -18,40 +20,117 @@ function Initialize(user_dbo, command, message, other_dbo = null) { let doc = docs[0]; if (allGames.indexOf(command) != -1) { if (other_dbo != null) { - user_dbo.updateOne(doc, { $set: { game: command, opponent: other_dbo.s.namespace.collection }}); + user_dbo.updateOne({ doc}, { $set: { game: command, opponent: other_dbo.s.namespace.collection }}); + other_dbo.updateOne({ game: null, opponent: null}, { $set: { game: command, opponent: user_dbo.s.namespace.collection }}); } else { user_dbo.updateOne(doc, { $set: { game: command }}); } + + } else { console.log(`ERROR! ${command} IS NOT A GAME!`); } + }); + + let mentioned = message.mentions.users.keys(); + let second = mentioned.next().value; + message.reply(`<@${mentioned.next().value}> and <@${second}> have started a game of ***${command.toUpperCase()}!***`); +} + + +//#region game lose/win +function loseGame(user_dbo, xp_collection) { + user_dbo.find({"game": {$exists: true}}).toArray(function(err, docs){ + const doc = docs[0]; + + //Update the player's xp + user_dbo.updateOne(doc, { $set: { game: null, opponent: null, state: STATE.IDLE, xp: ecoimport.addxp(message, dbo, Math.ceil((BASE.XP * doc.rank)/2),xp_collection) }}); + + //If remove some money (looting) [maybe implement a "friendly" game setting later with no looting] + let addbal = doc.rank * 2; + let diff = addbal; + if (doc.balance - addbal < 5) { addbal = addbal - doc.balance; } + if (doc.balance > 5) { + user_dbo.updateOne(doc, { $set: { balance: doc.balance - addbal}}); + } + user_dbo.updateOne(doc, { $set: { game: null, opponent: null, state: STATE.IDLE, xp: BASE.XP * doc.rank }}); + + return addbal; + }); +} + +function winGame(db, user_dbo, xp_collection) { + user_dbo.find({"game": {$exists: true}}).toArray(function(err, docs){ + const doc = docs[0]; + + //Update the player with xp + user_dbo.updateOne(doc, { $set: { game: null, opponent: null, state: STATE.IDLE, xp: doc.xp + (BASE.XP * doc.rank) }}); + + //Check for an opponent + if (doc.opponent != null) { + let other = db.collection(doc.opponent); + let amt_taken = loseGame(other, xp_collection); + user_dbo.updateOne(doc, { $set: { balance: doc.balance + amt_taken}}); } }); } +//#endregion -function resetPlayer(user_dbo) { + +function resetPlayer(db, user_dbo, message) { user_dbo.find({"game": {$exists: true}}).toArray(function(err, docs){ - let doc = docs[0]; + const doc = docs[0]; + + if (doc.game == null) { return message.reply("You're not even in a game and you're trying to quit! Sad..."); } user_dbo.updateOne(doc, { $set: { game: null, opponent: null, state: STATE.IDLE }}); + + let temp = `${message.author} has quit a game of ${doc.game}!`; + + if (doc.opponent != null) { + let other = db.collection(doc.opponent); + + } + message.reply(temp); }); } -function gameHelp() { - let l = ['']; +function acceptIsValid(other_discord, message, msg) { - return l.join(', '); + if (other_discord == undefined) { + message.reply("This is not a valid invite!"); + return false; + } + + //Make sure the bot was the one creating the invite + let check0 = msg.author.bot; + + //Author + let check1 = other_discord.id == message.author.id; + + //Time (within the last 5 min) + let prev = snowflake.convertSnowflakeToDate(msg.id); + let now = snowflake.convertSnowflakeToDate(message.id); + let diff = now - prev; + var minutes = Math.floor((diff/1000)/60); + let check2 = minutes <= 5; + + if (!check0) { message.reply("really?"); } + else if (!check1 && check2) { message.reply("_INVALID USER_"); } + else if (check1 && !check2) { message.reply("_THIS INVITE EXPIRED!_"); } + else if (!check1 && !check2) { message.reply("_THIS MESSAGE HAS AN INVALID USER AND HAS EXPIRED_")} + + return (check0 && check1 && check2); } //#endregion - module.exports ={ name: "game", description: "Play a game using Selmer Bot!", async execute(bot, message, args, command, Discord, mongouri, items, xp_collection) { - return message.reply("This command is currently in development!"); + if (!bot.inDebugMode) { return message.reply("This command is currently in development!"); } const id = message.author.id; const server = message.guild.id; @@ -81,7 +160,8 @@ module.exports ={ dbo.find({"game": {$exists: true}}).toArray(async function(err, docs){ if (err) { return console.log(error); } let doc = docs[0]; - let game = doc.game; + let game = null; + if (doc) { game = doc.game; } //#endregion if (command == 'accept') { @@ -94,24 +174,34 @@ module.exports ={ let mentioned = msg.mentions.users.keys(); const other_discord = mentioned.next().value; + if (!acceptIsValid(other_discord, message, msg)) { return; } + //Get the opponent const other = db.collection(other_discord); - Initialize(dbo, command, message); - battle.handle(dbo, other, bot, message, args, command, Discord, mongouri, items, xp_collection); + let startPos = msg.content.indexOf('"') + 1; + let newCommand = msg.content.substr(startPos, msg.content.lastIndexOf('"') - startPos); + + if (newCommand == 'battle') { + Initialize(dbo, newCommand, msg, other); + battle.handle(dbo, other, bot, message, args, 'initiate', Discord, mongouri, items, xp_collection); + } } else { - if (game == 'battle' || command == 'battle') { + if (command == 'quit') { + winGame(db, dbo, xp_collection); + } else if (game == 'battle' || command == 'battle') { //Handle sending the request and making sure the user exists here let other_discord = message.mentions.users.first(); if (other_discord == undefined) { return message.reply(`${args[1]} is not a valid user!`); } - message.channel.send(`<@${other_discord}>, <@${message.author.id}> has invited you to battle, to accept, please reply to this message with !accept`); + message.channel.send(`${other_discord}, <@${message.author.id}> has invited you to play "battle", to accept, please reply to this message with _!game accept_`); } //Catch statement (invalid command) else { - message.reply(`'!game ${command}' is not a command!`); + if (command == undefined) { message.reply("Please specify a game or use _!game help_"); } + else { message.reply(`'!game ${command}' is not a command!`); } } } @@ -119,5 +209,5 @@ module.exports ={ }); client.close(); - } + }, allGames } \ No newline at end of file diff --git a/commands/misc/help.js b/commands/misc/help.js index 0f7fb55..2dc4dfb 100644 --- a/commands/misc/help.js +++ b/commands/misc/help.js @@ -8,11 +8,13 @@ module.exports ={ temp += bot.commands.get('econ').econHelp(); temp += `\n\n(remember to use '${bot.prefix}' before the command!)`; return message.channel.send(temp); - } else if (args[0] == 'game') { + } + else if (args[0] == 'game') { let temp = "***Selmer Bot Commands (Games):***\n"; - temp += bot.commands.get('game').gameHelp(); + temp += bot.commands.get('game').allGames.join(", "); temp += `\n\n(remember to use '${bot.prefix}' before the command!)`; - return message.channel.send(temp); } + return message.channel.send(temp); + } let temp = "***Selmer Bot Commands:***\n"; @@ -22,9 +24,11 @@ module.exports ={ if (comm.name != 'verify') { if (comm.name == 'econ') { temp += `econ - use _!help econ_\n`; - } else if (comm.name == 'game') { + } + else if (comm.name == 'game') { temp += `game - use _!help game_\n`; - }else { + } + else { temp += `${comm.name.toLowerCase()} - _${comm.description}_\n`; } } diff --git a/commands/misc/scraper.js b/commands/misc/scraper.js index e5b4e26..9fb1cea 100644 --- a/commands/misc/scraper.js +++ b/commands/misc/scraper.js @@ -5,7 +5,7 @@ module.exports ={ description: ".....", async execute(message, args, Discord, Client, bot) { const axios = require('axios'); - const cheerio = require('cheerio') + const cheerio = require('cheerio'); const url = args[0]; axios(url) .then(async response => { @@ -17,9 +17,13 @@ module.exports ={ // console.log(lyrics); }) .catch(function(err) { - if (err.message.indexOf('The "url" argument must be of type string.') != -1) { + if (err.message.indexOf('The "url" argument must be of type string') != -1) { message.reply("The URL should be a string!"); + } else { + message.reply("Oops! There's been an error"); } + + console.log(err); }); } } diff --git a/main.js b/main.js index 23615a9..2bc49fe 100644 --- a/main.js +++ b/main.js @@ -9,13 +9,13 @@ const BASE_LVL_XP = 20; //Token area //Adding integration for development mode let token; -let inDebugMode = false; +let IDM = false; if (process.env.token != undefined) { //Use "setx NAME VALUE" in the local powershell terminal to set token = process.env.token; } else { token = require('./config.json').token; - inDebugMode = true; + IDM = true; } // const { token } = require('./config.json'); @@ -35,6 +35,7 @@ const bot = new Client({ const prefix = '!'; bot.prefix = new String; bot.prefix = prefix; +bot.inDebugMode = IDM; //MongoDB integration @@ -132,7 +133,7 @@ bot.on('ready', async () => { //Reaction map area - if (!inDebugMode) { + if (!bot.inDebugMode) { console.log('SLEEMER BOT ONLINE!!!!! OH MY GOD OH MY GOD!!!'); } else { console.log("Testing testing 1 2 5..."); @@ -141,6 +142,7 @@ bot.on('ready', async () => { bot.on('messageCreate', (message) => { + //COMMAND AREA //Check if the prefix exists if (!message.content.startsWith(prefix) || message.author.bot) return;