Simp-O-Matic

Dumb Discord bot in TS.
git clone git://git.knutsen.co/Simp-O-Matic
Log | Files | Refs | README | LICENSE

commit edfd011abe7909d1934ed9f8ca66e4a146d21875
parent adb5cf043d36a9b805c08906d7bd48ecd2477f9b
Author: Danny <23189912+danyisill@users.noreply.github.com>
Date:   Mon,  8 Feb 2021 17:00:53 +0200

Add pharmaceutical capabilities.

Diffstat:
Mlib/commands/drug.ts | 41+++++++----------------------------------
Alib/drug-o-matic/LICENSE.MD | 24++++++++++++++++++++++++
Alib/drug-o-matic/Procfile | 2++
Alib/drug-o-matic/assets/breathe.gif | 0
Alib/drug-o-matic/assets/breathe2.gif | 0
Alib/drug-o-matic/assets/combochart.png | 0
Alib/drug-o-matic/assets/hrtguide.png | 0
Alib/drug-o-matic/assets/logo.png | 0
Alib/drug-o-matic/assets/mascot.png | 0
Alib/drug-o-matic/bot.js | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/command-system.js | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/commands/about.js | 17+++++++++++++++++
Alib/drug-o-matic/commands/analysis.js | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/commands/avatar.js | 20++++++++++++++++++++
Alib/drug-o-matic/commands/badtrip.js | 16++++++++++++++++
Alib/drug-o-matic/commands/bobross.js | 11+++++++++++
Alib/drug-o-matic/commands/breathe.js | 6++++++
Alib/drug-o-matic/commands/breathe2.js | 6++++++
Alib/drug-o-matic/commands/cocoa.js | 20++++++++++++++++++++
Alib/drug-o-matic/commands/combochart.js | 6++++++
Alib/drug-o-matic/commands/combos.js | 44++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/commands/dxmcalc.js | 34++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/commands/effectinfo.js | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/commands/effects.js | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/commands/help.js | 38++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/commands/hrt.js | 5+++++
Alib/drug-o-matic/commands/info.js | 443+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/commands/invitelink.js | 5+++++
Alib/drug-o-matic/commands/ketaminecalc.js | 48++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/commands/mascot.js | 5+++++
Alib/drug-o-matic/commands/psychtolerance.js | 35+++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/commands/randomtdc.js | 8++++++++
Alib/drug-o-matic/commands/role.js | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/commands/roles.js | 38++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/commands/sei.js | 8++++++++
Alib/drug-o-matic/commands/whois.js | 29+++++++++++++++++++++++++++++
Alib/drug-o-matic/helpers.js | 12++++++++++++
Alib/drug-o-matic/include/combos.js | 48++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/include/customs.json | 268+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/include/dxmcalc.js | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/include/effects.js | 36++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/include/ketaminecalc.js | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/include/quote.js | 27+++++++++++++++++++++++++++
Alib/drug-o-matic/include/roles.js | 24++++++++++++++++++++++++
Alib/drug-o-matic/include/sanitize-substance-name.js | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/package.json | 26++++++++++++++++++++++++++
Alib/drug-o-matic/pw-info-pw-e2e-test.js | 31+++++++++++++++++++++++++++++++
Alib/drug-o-matic/queries/effects.js | 11+++++++++++
Alib/drug-o-matic/queries/info.js | 44++++++++++++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/readme.md | 34++++++++++++++++++++++++++++++++++
Alib/drug-o-matic/test-command.js | 34++++++++++++++++++++++++++++++++++
51 files changed, 2179 insertions(+), 34 deletions(-)

diff --git a/lib/commands/drug.ts b/lib/commands/drug.ts @@ -1,36 +1,9 @@ -// This is Danny's, I don't endorse it. -const drugs = { - 'alcohol': [10000, 100000], - 'amphetamine': [10, 20, 40, 60], - 'caffeine': [100, 150, 200, 250], - 'cocaine': [10, 20, 40, 60], - 'datura': [10000], - 'ketamine': [50, 100, 300, 500], - 'mescaline': [50, 100, 200, 400, 800], - 'psilocin': [5, 10, 20, 40], - 'lysergic acid diethylamide': [0.01, 0.1, 0.2, 0.3], - 'cannabis': [20, 30, 60, 100, 150], - 'MDMA': [20, 40, 80, 150, 200], - 'nicotine': [0.3, 0.5, 1, 2, 3], - 'codeine': [30, 50, 100, 150, 200], - 'alprazolam': [1, 2, 4, 6, 8], - 'clonazepam': [2, 4, 8, 16], - 'phenazepam': [1, 2, 4, 6, 8], - 'fentanyl': [0.1, 0.5, 0.7], - 'heroin': [5, 10, 20, 30, 50], - 'dimethyltryptamine': [2, 10, 20, 40, 60], - 'nitrous oxide': [20000], - 'salvia divinorum': [20000], - 'baclofen': [25, 50, 100], - 'diphenhydramine': [25, 100, 200, 500, 700, 1000], - 'dextromethorphan': [100, 200, 400, 800, 1000], - 'kratom': [1000, 5000, 10000], - 'memantine': [30, 60, 120, 180] -}; - export default (home_scope: HomeScope) => { - const { message } = home_scope; - const drug = Object.keys(drugs)[Math.floor(25 * Math.random())]; - message.answer(`${drugs[drug][Math.floor(Math.random() - * drugs[drug].length)]}mg ${drug}`); + const { CLIENT, message, args } = home_scope; + try { + var cmd = require('../drug-o-matic/commands/' + args.shift())(); + cmd.run(CLIENT, message, args); + } catch(e) { + message.answer('Command not found') + } }; diff --git a/lib/drug-o-matic/LICENSE.MD b/lib/drug-o-matic/LICENSE.MD @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> diff --git a/lib/drug-o-matic/Procfile b/lib/drug-o-matic/Procfile @@ -0,0 +1 @@ +worker: forever --minUptime 1000 bot.js+ \ No newline at end of file diff --git a/lib/drug-o-matic/assets/breathe.gif b/lib/drug-o-matic/assets/breathe.gif Binary files differ. diff --git a/lib/drug-o-matic/assets/breathe2.gif b/lib/drug-o-matic/assets/breathe2.gif Binary files differ. diff --git a/lib/drug-o-matic/assets/combochart.png b/lib/drug-o-matic/assets/combochart.png Binary files differ. diff --git a/lib/drug-o-matic/assets/hrtguide.png b/lib/drug-o-matic/assets/hrtguide.png Binary files differ. diff --git a/lib/drug-o-matic/assets/logo.png b/lib/drug-o-matic/assets/logo.png Binary files differ. diff --git a/lib/drug-o-matic/assets/mascot.png b/lib/drug-o-matic/assets/mascot.png Binary files differ. diff --git a/lib/drug-o-matic/bot.js b/lib/drug-o-matic/bot.js @@ -0,0 +1,52 @@ +require('dotenv').config(); +const Discord = require('discord.js'); +const DiscordClient = new Discord.Client(); +const CommandSystem = require('./command-system.js')(); + +CommandSystem.load(() => { + console.log('Command system loaded.'); +}); + +DiscordClient.on('ready', () => { + console.log('DoseBot is online - beep boop'); + + // Update game message on launch + DiscordClient.user + .setActivity(`my part in reducing harm!`, { type: 'PLAYING' }) + .then(presence => console.log(`Activity set: ${JSON.stringify(presence.game)}`)) + .catch(console.error); + + // Print guild list + let guilds = DiscordClient.guilds.cache; + const userCount = guilds + .map(guild => guild.memberCount) + .reduce((x, y) => x + y, 0); + + console.log(`Currently serving ${userCount} users on ${guilds.length} guilds`); + for (let guildComponents of guilds) { + let guildId = guildComponents[0]; + let guild = guildComponents[1]; + console.log(`- ${guildId} - ${guild.name} (${guild.memberCount} members)`); + + if (guildId == "697833083201650689") { + console.log("leaving guild"); + guild.leave().then(g => console.log("Left the guild")).catch(console.error); + } + } +}); + +DiscordClient.on('guildCreate', guild => { + console.log(`New server joined - Name: ${guild.name} Members: ${guild.memberCount}`); +}); + +DiscordClient.on('message', message => { + const guild = message.guild || {}; + const channel = message.channel.name; + const author = `${message.author.id} ${message.author.username}#${message.author.discriminator}`; + + console.log(`[${guild.id} ${guild.name} #${channel}] <${author}> -- ${message.content}`); + + CommandSystem.execute(DiscordClient, message); +}); + +DiscordClient.login(process.env.DISCORD_API_TOKEN); diff --git a/lib/drug-o-matic/command-system.js b/lib/drug-o-matic/command-system.js @@ -0,0 +1,83 @@ +var fs = require('fs'); + +// Server-specific trigger overrides +// Limitations: +// - Triggers cannot contain spaces, because commands don't know how to replace +// triggers other than to split on the first space. Commands should be reworked +// to take a sanitized array of arguments. +function triggerForGuild(guild) { + if (null != (process.env.TRIGGER)) { + return process.env.TRIGGER; + } + if (null == guild) { + return "--"; + } + switch (guild.id) { + // case "253612214148136981": return "."; // Drugs Community + default: return "--"; + } +} + +module.exports = function CommandSystem() { + // Specify the DoseBot command prefix + + // Initialize an object to hold the list of commands + var commandTable = {}; + + return { + load: function(ready) { + fs.readdir('./commands', function(err, items) { + for (let i = 0; i < items.length; i++) { + try { + var commandName = items[i].replace(/.js$/, ''); + commandTable[commandName] = require(`./commands/${commandName}.js`); + } catch (err) { + console.error( + `Encountered error trying to require command: ${commandName}.js` + ); + console.error(err); + } + } + }); + }, + + execute: function(client, message) { + if (message.author.bot) { + // console.log("Message author is bot") + return; + } + + // undo some autocorrects to fix triggers + const content = message.content.replace(/^[—─]/, '--') + + const trigger = triggerForGuild(message.guild); + + if (!content.startsWith(trigger)) { + return; + } + + const args = content + .slice(trigger.length) + .trim() + .split(/ +/g); + const commandName = args.shift().toLowerCase(); + const commandFunction = commandTable[commandName]; + + console.log(`CMD: ${commandName} on server ${ + message.guild == null ? "<no guild>" : message.guild.name + }`) + if (commandFunction) { + try { + commandFunction.run(client, message, args); + } catch (err) { + console.error( + `Encountered error trying to execute command: ${commandName}` + ); + console.error(err); + } + } else { + // console.log(`Command does not exist: ${commandName}\n${commandTable}`) + } + } + }; +}; diff --git a/lib/drug-o-matic/commands/about.js b/lib/drug-o-matic/commands/about.js @@ -0,0 +1,17 @@ +// About message +const Discord = require('discord.js'); +const Helpers = require('../helpers.js'); + +exports.run = (client, message, args) => { + const embed = Helpers.TemplatedMessageEmbed() + .addField( + 'About DoseBot Redux', + `DoseBot Redux automatically sources dosage, duration, tolerance, and harm reduction information from [PsychonautWiki](http://www.psychonautwiki.org) and [Effect Index](https://effectindex.com). + + It was created with the goal of raising awareness of harm reduction best practices, as well as the Subjective Effect Index. For a complete list of commands type \'--help\'. + + For more information about DoseBot Redux, see [our page on Effect Index](https://effectindex.com/dosebot).` + ); + + message.channel.send({ embed }); +}; diff --git a/lib/drug-o-matic/commands/analysis.js b/lib/drug-o-matic/commands/analysis.js @@ -0,0 +1,71 @@ +// About message +const Discord = require('discord.js'); +const Helpers = require('../helpers.js') + +exports.run = (client, message, args) => { + var effectLines = message.content.split("\n"); + const firstLineArguments = effectLines.shift().split(/ +/); // actual command, plus first line arguments + firstLineArguments.shift(); // remove trigger + + let strength = 'moderate'; + let drug = 'psychedelic'; + if (firstLineArguments.length == 1) { + strength = firstLineArguments[0]; + } + else if (firstLineArguments.length == 2) { + strength = firstLineArguments[0]; + drug = firstLineArguments[1]; + } + + if (drug == 'disso' || drug == 'dissociative') { + drug = '[dissociative effects](https://effectindex.com/summaries/dissociatives/)'; + } else if (drug == 'del' || drug == 'deliriant') { + drug = '[deliriant effects](https://effectindex.com/summaries/deliriants/)'; + } else { + drug = '[psychedelic effects](https://effectindex.com/summaries/psychedelics/visual)'; + } + + const templateStart = `This is a replication of ${strength} ${drug}. The specific effect/s which are occurring within this replication seem to include:`; + const templateEnd = 'Please reply to this comment if you disagree with this replication analysis or would like to provide general feedback.'; + let additionalNotes = ''; + + // What do i need to make this work? + // Need to have the collector go until a finish message is sent + // All collected messages need to be split if there's a | + // First half needs to be formatted lowercase with hyphens for links + + // NEXT UP: search recent messages in #subreddit-moderation for posts by dosebot, with emoji reactions. + // OR be listening to all reactions and push ones that are to dosebot posts in that channel to a list? + // When would that list get reset? + // We want to listen on the messageReactionAdd event for making the post-index. + + /* collector.on('collect', m => { + // Stop condition + if (m.content.includes('done')) { + collector.stop(); + return; + } + effects.push(m.content); + });*/ + + let templateMiddle = ''; + for (const effectLine of effectLines) { + // Split message + const spl = effectLine.split('|'); + const effect = spl[0].trim(); + const notes = (spl[1] || '').trim(); + const link = effect.toLowerCase().replace(/ /g, '-'); + + // **Additional notes:** + + if (effect == 'notes') { + additionalNotes = `**Additional notes:**\n> ${notes}`; + } + else { + const line = `* [**${effect}**](https://effectindex.com/effects/${link}) ${notes}`; + templateMiddle += line + '\n'; + } + } + + message.channel.send('```' + templateStart + '\n\n' + templateMiddle + '\n' + templateEnd + '\n' + additionalNotes + '```'); +}; diff --git a/lib/drug-o-matic/commands/avatar.js b/lib/drug-o-matic/commands/avatar.js @@ -0,0 +1,20 @@ +const Discord = require('discord.js'); +const Helpers = require('../helpers.js'); + +// Avatar message +exports.run = (client, message, args) => { + let avatar = message.author.avatarURL({size: 2048}); + const mentionedUsers = []; + + if (message.mentions) { + message.mentions.users.forEach(function(user) { + avatar = user.avatarURL({size: 2048}); + }); + } + + const embed = Helpers.TemplatedMessageEmbed() + .setTitle('DoseBot Redux Avatar Service') + .setImage(avatar); + + message.channel.send({ embed }); +}; diff --git a/lib/drug-o-matic/commands/badtrip.js b/lib/drug-o-matic/commands/badtrip.js @@ -0,0 +1,16 @@ +const Discord = require("discord.js"); +const Helpers = require('../helpers.js'); + +//Badtrip command +exports.run = (client, message, args) => { + const embed = Helpers.TemplatedMessageEmbed() + .setImage( + "https://psychonautwiki.org/w/thumb.php,qf=You_do_not_need_to_understand.gif,awidth=419.pagespeed.ce._yCpj9CanE.gif" + ) + .addField( + "Assistance", + "Taken drugs or have questions about taking drugs? Concerned or have any questions? Visit the TripSit Chat: <https://chat.tripsit.me/>\n\nNeed a healthy dose of **good vibes**? Check out the PsychonautWiki Good Vibes page: <https://psychonautwiki.org/wiki/Good_vibes>\n\nThis Youtube channel is dedicated to sending positive vibes: <https://www.youtube.com/user/TheMeditativeMind>\n\n**Everything is going to be okay!** You are awesome, everyone here loves, cares, and supports you! **Take long, slow, deep breaths** and focus on each breath in and out!" + ); + + message.channel.send({ embed }).catch(console.error); +}; diff --git a/lib/drug-o-matic/commands/bobross.js b/lib/drug-o-matic/commands/bobross.js @@ -0,0 +1,11 @@ +exports.run = (client, message, args) => { + // If someone mentions a person at the end of the bobross command, + // make sure those people are mentioned with the response + const mentions = message.mentions.users.array() + .map(user => `<@${user.id}> `) + .reduce((x, y) => `${x}${y}`, ''); + + message.channel + .send(`${mentions}Enjoy a random episode of The Joy of Painting: <https://mityurl.com/y/cDIn/r>`) + .catch(console.error); +}; diff --git a/lib/drug-o-matic/commands/breathe.js b/lib/drug-o-matic/commands/breathe.js @@ -0,0 +1,6 @@ +const Discord = require('discord.js'); + +// Panic attack command +exports.run = (client, message, args) => { + message.channel.send({ files: ["./assets/breathe.gif"] }); +}; diff --git a/lib/drug-o-matic/commands/breathe2.js b/lib/drug-o-matic/commands/breathe2.js @@ -0,0 +1,6 @@ +const Discord = require('discord.js'); + +// Panic attack command +exports.run = (client, message, args) => { + message.channel.send({ files: ["./assets/breathe2.gif"] }); +}; diff --git a/lib/drug-o-matic/commands/cocoa.js b/lib/drug-o-matic/commands/cocoa.js @@ -0,0 +1,20 @@ +const Discord = require('discord.js'); + +// If you're reading this comment, you're looking for a bit more information +// than the command gives. Without going into too much detail, Cocoa and I had +// a falling out and haven't spoken since November of 2018. In November of 2019, +// we lost Cocoa. I'm not sure what happened. Cocoa and I were not friends when +// they died, but I respect their effort to learn JavaScript and create harm +// reduction resources, and DoseBot would not be here if it weren't for their +// effort. It's tragic that they left us before unleashing their full potential +// upon the world, which Cocoa was just beginning to unlock. +// +// To Cocoa's loved ones: I hope you can find comfort in these dark times. If I +// can be of any help, you know how to reach me. +// +// <3 +// Maethor + +exports.run = (client, message, args) => { + message.channel.send('Godspeed Cocoa. Right hand of the revolution, lightkeeper, botmaster, and defender of the northern realms, 1995 - 2019. :cry:'); +}; diff --git a/lib/drug-o-matic/commands/combochart.js b/lib/drug-o-matic/commands/combochart.js @@ -0,0 +1,6 @@ +//tripsit combo chart message +exports.run = (client, message, args) => { + message.channel + .send({ files: ["./assets/combochart.png"] }) + .catch(console.error); +}; diff --git a/lib/drug-o-matic/commands/combos.js b/lib/drug-o-matic/commands/combos.js @@ -0,0 +1,44 @@ +const Combos = require('../include/combos'); +const sanitizeSubstanceName = require('../include/sanitize-substance-name.js'); +const rp = require('request-promise'); + +exports.run = (client, message, args) => { + const drug = message.content + .toLowerCase() + .replace(/^[^\s]+ /, '', -1) // remove first word + .replace(/-/g, '', -1) + .split(' '); + + drug[0] = sanitizeSubstanceName(drug[0]); + + const tripSitAPIURL = `http://tripbot.tripsit.me/api/tripsit/getDrug?name=${ + drug[0] + }`; + + if (drug.length === 1) { + rp(tripSitAPIURL) + .then(function(response) { + // If we have an error send the error to the channel + if (response.err === true) { + message.channel.send( + `Error fetching combos from TripSit: ${response.data.msg}` + ); + return; + } else { + // Pluck what we need from the response + const { name, combos } = Combos.pluckQueryResponse(response); + // Generate the string for the message + const combosString = Combos.generateEmbedComboString(combos); + + // Send the message + message.channel.send(Combos.createComboMessage(combosString, name)); + } + }) + .catch(function(err) { + console.log(err); + message.channel.send( + `Error getting **${drug[0]}** combos from TripSit API` + ); + }); + } +}; diff --git a/lib/drug-o-matic/commands/dxmcalc.js b/lib/drug-o-matic/commands/dxmcalc.js @@ -0,0 +1,34 @@ +// Calc dxm plateau dosages. usage --dxmcalc [weight in pounds] +exports.run = (client, message, args) => { + const Discord = require('discord.js'); + const DXMCalc = require('../include/dxmcalc.js'); + const Helpers = require('../helpers.js'); + + // Message variables + const inputs = message.content.split(/ +/g); + + // parse weight from result + let weight = parseInt(inputs[1]); + let weightIsKilos = false; + + if (inputs[1].includes('kg')) { + weightIsKilos = true; + } + + if (!isNaN(weight)) { + const embed = Helpers.TemplatedMessageEmbed() + .setTitle('DXM Dosage Calculator') + .addField( + '[:scales:] Dosages', + DXMCalc.generateDosageField(weight, weightIsKilos) + ) + .addField('[:warning:] Warning', DXMCalc.generateWarningField()) + .addField('[:globe_with_meridians:] Links', DXMCalc.generateLinksField()); + + message.channel.send({ embed }); + } else { + message.channel.send( + '**Error:** No weight specified | Usage: --dxmcalc [weight]<optional: lb/kg>' + ); + } +}; diff --git a/lib/drug-o-matic/commands/effectinfo.js b/lib/drug-o-matic/commands/effectinfo.js @@ -0,0 +1,67 @@ +// About message +const Discord = require('discord.js'); +const rp = require('request-promise'); +const Helpers = require('../helpers.js'); + +exports.run = (client, message, args) => { + + var tokens = message.content.split(' '); + tokens.shift(); + const effect = tokens.join("-"); + + console.log(`effect: ${effect}`); + + // Declare the location of the API URL + let url = `https://www.effectindex.com/api/effects/${effect}`; + + rp(`${url}`) + .then(function(body) { + const effectInfo = JSON.parse(body); + console.log(effectInfo.effect.summary_raw); + + const embed = Helpers.TemplatedMessageEmbed() + .setImage(createReplicationField(effectInfo)) + .addField( + `**${createEffectFieldTitle(effectInfo)} summary**`, + createSummaryField(effectInfo) + ) + .addField('Links', createLinksField(effect, effectInfo)); + + message.channel.send({ embed }); + }) + .catch(function(err) { + console.error(err); + + message.channel.send(`Error: ${effect} is not found on Effect Index`); + }); + + function createSummaryField(effectJSON) { + return `${effectJSON.effect.summary_raw}`; + } + + function createEffectFieldTitle(effectJSON) { + return `${effectJSON.effect.name}`; + } + + // Builds the link field + function createLinksField(effect, effectJSON) { + const effectURL = `https://www.effectindex.com/effects/${effect}`; + + return `[${effectJSON.effect.name} on Effect Index](${effectURL})`; + } + + function createReplicationField(effectJSON) { + if (effectJSON.effect.social_media_image) { + console.log('we\'re in the right place'); + const replicationName = effectJSON.effect.social_media_image; + + const replicationURL = `https://www.effectindex.com${replicationName}`; + + return replicationURL; + } else { + console.log('we are in the wrong place'); + // Return a blank image if no replicaiton is for as MessageEmbed fields cant be empty + return 'https://i.imgur.com/3mENLpk.png'; + } + } +}; diff --git a/lib/drug-o-matic/commands/effects.js b/lib/drug-o-matic/commands/effects.js @@ -0,0 +1,80 @@ +// Modules +const Discord = require('discord.js'); +const sanitizeSubstanceName = require('../include/sanitize-substance-name.js'); +const Effects = require('../include/effects.js'); +const Helpers = require('../helpers.js'); + +const rp = require('request-promise'); + +const effectQuery = require('../queries/effects.js'); + +const fetchAndParseURL = async url => { + try { + const responseData = await rp(url); + + return JSON.parse(responseData); + } catch (err) { + console.error(err); + } + + return null; +} + +const fetchPWSubstanceData = async substanceName => { + const query = effectQuery.effect(substanceName); + + const encodedQuery = encodeURIComponent(query); + + return fetchAndParseURL( + `https://api.psychonautwiki.org/?query=${encodedQuery}` + ); +} + +exports.run = async (client, message, args) => { + const str = message.content; + // Removes all symbols and puts everything in lower case so bot finds the images easier + let substanceName = str + .toLowerCase() + .replace(/^[^\s]+ /, '', -1) // remove first word + .replace(/-/g, '', -1) + .replace(/ /g, '', -1); + + substanceName = sanitizeSubstanceName(substanceName); + + try { + const { data } = await fetchPWSubstanceData(substanceName); + + console.log(data); // SHOW ME WHAT YOU GOT + + if (data.substances.length == 0) { + message.channel + .send(`There are no substances matching \`${substanceName}\` on PsychonautWiki.`) + .catch(console.error); + return; + } + + if (data.substances.length > 1) { + message.channel + .send(`There are multiple substances matching \`${substanceName}\` on PsychonautWiki.`) + .catch(console.error); + return; + } + + const substance = data.substances[0]; + + const embed = Helpers.TemplatedMessageEmbed() + .setTitle(`${substance.name} effect information`) + .addField( + 'Effects (randomly selected)', + Effects.createEffectsList(substance) + ) + .addField( + 'More information', + Effects.createFullEffectListLink(substance) + ); + + message.channel.send({ embed }).catch(console.error); + } catch(err) { + console.error(err); + } +}; diff --git a/lib/drug-o-matic/commands/help.js b/lib/drug-o-matic/commands/help.js @@ -0,0 +1,38 @@ +const Discord = require('discord.js'); +const Helpers = require('../helpers.js'); + +//displays list of commands. in future should scan commands directory and display info for each programmatically/dynamically +exports.run = (client, message, args) => { + const embed = Helpers.TemplatedMessageEmbed() + .addField('Available commands', buildCommandList()); + + message.channel.send({ embed }); +}; + +function buildCommandList() { + var commands = [ + '--about', + "--avatar", + '--badtrip', + '--bobross', + "--breathe", + '--combochart', + '--combos [drug]', + '--dxmcalc [weight in lbs]', + '--effectinfo [effect]', + '--effects [substance]', + "--help (you are here)", + "--hrt", + '--info [substance]', + "--invitelink", + '--ketaminecalc [weight in lbs]', + '--psychtolerance [days]', + '--randomtdc', + '--role [rolename]', + "--roles", + '--sei', + '--whois [@user]' + ]; + + return commands.join('\n'); +} diff --git a/lib/drug-o-matic/commands/hrt.js b/lib/drug-o-matic/commands/hrt.js @@ -0,0 +1,5 @@ +exports.run = (client, message, args) => { + message.channel + .send({ files: ["./assets/hrtguide.png"] }) + .catch(console.error); +} diff --git a/lib/drug-o-matic/commands/info.js b/lib/drug-o-matic/commands/info.js @@ -0,0 +1,443 @@ +const sanitizeSubstanceName = require('../include/sanitize-substance-name.js'); +const Discord = require('discord.js'); +const customsJSON = require('../include/customs.json'); + +const infoQuery = require('../queries/info.js'); + +const rp = require('request-promise'); + +const Helpers = require('../helpers.js') + +const fetchAndParseURL = async url => { + try { + const responseData = await rp(url); + + return JSON.parse(responseData); + } catch (err) { + console.error(err); + } + + return null; +} + +const fetchPWSubstanceData = async substanceName => { + const query = infoQuery.info(substanceName); + + const encodedQuery = encodeURIComponent(query); + + return fetchAndParseURL( + `https://api.psychonautwiki.org/?query=${encodedQuery}` + ); +} + +exports.run = async (client, message, args) => { + // For keeping track of whether or not a substance is found in the custom sheets + var hasCustom; + + // Capture messages posted to a given channel and remove all symbols and put everything into lower case + var str = message.content; + var substanceName = parseSubstanceName(str); + + // Checks to see if drug is on the customs list + if (checkIfCustomSheet(substanceName)) { + console.log('Pulling from custom'); + hasCustom = true; + + // Find the location of the substance object in the JSON and set substance + let substance = locateCustomSheetLocation(substanceName); + + createPWChannelMessage(substance, message); + } else { + console.log('Pulling from PW'); + hasCustom = false; + } + + if (hasCustom == false) { + console.log(`Requesting info for ${substanceName}`); + // Loads GraphQL query as "query" variable + + try { + const { data } = await fetchPWSubstanceData(substanceName); + + // Logs API's returned object of requested substance + console.log("Substances response: " + JSON.stringify(data)); + + // Send a message to channel if there are zero or more than one substances returned by the API + // Not sure if the API in its current configuration can return more than one substance + if (data.substances.length === 0) { + console.log('Pulling from TS'); + + let tripSitURL = `http://tripbot.tripsit.me/api/tripsit/getDrug?name=${substanceName}`; + + const responseData = await fetchAndParseURL(tripSitURL); + + if (responseData.err === true) { + message.channel.send(`Error: No API data available for **${substanceName}**`); + } else { + let substance = responseData.data[0]; + + createTSChannelMessage(substance, message); + } + + return; + } else if (data.substances.length > 1) { + message.channel + .send(`There are multiple substances matching \`${substanceName}\` on PsychonautWiki.`) + .catch(console.error); + return; + } else { + // Set substance to the first returned substance from PW API + var substance = data.substances[0]; + createPWChannelMessage(substance, message); + } + } catch (err) { + console.log('Promise rejected/errored out'); + console.log(err); + } + + // Reset hasCustom + hasCustom = false; + } +}; + +// Functions +//// Create a MessageEmbed powered message utilizing the various field builder functions +function createPWChannelMessage(substance, message) { + const embed = Helpers.TemplatedMessageEmbed() + .setTitle(`**${capitalize(substance.name)} drug information**`) + .addField( + ':telescope: __Class__', + buildChemicalClassField(substance) + + '\n' + + buildPsychoactiveClassField(substance) + ) + .addField(':scales: __Dosages__', `${buildDosageField(substance)}\n`, true) + .addField( + ':clock2: __Duration__', + `${buildDurationField(substance)}\n`, + true + ) + .addField( + ':warning: __Addiction potential__', + buildAddictionPotentialField(substance), + true + ) + .addField( + ':chart_with_upwards_trend: __Tolerance__', + `${buildToleranceField(substance)}\n`, + true + ) + .addField(':globe_with_meridians: __Links__', buildLinksField(substance)); + + message.channel.send({ embed }); +} +// Custom sheet functions +//// Check if the requested substance is in the customs.json file +function checkIfCustomSheet(drug) { + console.log('drug: ' + drug); + if ( + drug == 'ayahuasca' || + drug == 'datura' || + drug == 'salvia' || + drug == 'lsa' + ) { + return true; + } else { + return false; + } +} + +//// Find the location of a given substance in the customs.json file +function locateCustomSheetLocation(drug) { + var locationsArray = []; + var loc; + + // Loop through the JSON file and add all of the names and locations to locationsArray + for (let i = 0; i < customsJSON.data.substances.length; i++) { + locationsArray.push({ + name: customsJSON.data.substances[i].name, + location: i + }); + } + + // Loop through the locationsArray to find the location of a given substance + for (let i = 0; i < locationsArray.length; i++) { + if (locationsArray[i].name == drug) { + loc = i; + } + } + + // Set substance equal to the correct substance in the JSON file + return customsJSON.data.substances[loc]; +} + +// Capitalization function +function capitalize(name) { + if (name === 'lsa') { + return name.toUpperCase(); + } else { + return name[0].toUpperCase() + name.slice(1); + } +} + +// Message builders +function buildToleranceField(substance) { + let tolerances = substance.tolerance; + let toleranceArr = []; + + if (tolerances) { + let createToleranceString = function(string, tolerance) { + return `**${capitalize(string)}**: ${tolerance}`; + }; + + let pushToleranceToArray = function(toleranceTier, tolerance) { + if (tolerance) { + toleranceArr.push(createToleranceString(toleranceTier, tolerance)); + } + }; + + // If substance does not have standard tolerances return the custom tolerance + if (substance.name == 'ayahuasca' || substance.name == 'salvia') { + return substance.tolerance.tolerance; + } else { + // return standard tolerances + pushToleranceToArray('full', tolerances.full); + pushToleranceToArray('half', tolerances.half); + pushToleranceToArray('baseline', tolerances.zero); + + return toleranceArr.join('\n'); + } + } else { + return 'No information'; + } +} + +function buildDosageField(substance) { + var messages = []; + + for (let i = 0; i < substance.roas.length; i++) { + let roa = substance.roas[i]; + let dose = roa.dose; + let name = capitalize(roa.name); + + // Convert dosage object into a string + let dosageObjectToString = function(dosageTier) { + // Set substance dose units + let unit = dose.units; + + // If there's a dose return dose + unit + if (dosageTier) { + if (typeof dosageTier === 'number') { + return `${dosageTier}${unit}`; + } + // If there's a dose range return dose range + unit + return `${dosageTier.min} - ${dosageTier.max}${unit}`; + } + }; + + // Function for creating dosage message string + let createMessageString = function(string, dosage) { + return `**${capitalize(string)}**: ${dosageObjectToString(dosage)}`; + }; + + // Function to push dosage message to array + let pushDosageToMessageArray = function(phaseString, phase) { + if (phase) { + messages.push(createMessageString(phaseString, phase)); + } + }; + + if (substance.name == 'ayahuasca' || substance.name == 'datura') { + // Ayahuasca hardcoded message (can really be used for any substance without standard dosage information) + messages.push(`*(${name})*`); + + // If nonstandard dose add dosage information to messages array + if (dose) { + messages.push(`${dose.dosage}`); + messages.push(''); + } else { + // This should really never happen + messages.push('No dosage information.'); + } + } else { + messages.push(`*(${name})*`); + + // Add all dosage information + // Uses double conditional to prevent massive no information walls + if (dose) { + pushDosageToMessageArray('threshold', dose.threshold); + pushDosageToMessageArray('light', dose.light); + pushDosageToMessageArray('common', dose.common); + pushDosageToMessageArray('strong', dose.strong); + pushDosageToMessageArray('heavy', dose.heavy); + messages.push(''); + } else { + // Or none if there is none + messages.push('No dosage information.'); + } + } + } + // Join the message array into a string + return messages.length > 0 ? messages.join("\n") : "No dosage info." +} + +function buildDurationField(substance) { + var messages = []; + + for (let i = 0; i < substance.roas.length; i++) { + let roa = substance.roas[i]; + let name = capitalize(roa.name); + + // Parses duration object and returns string + let durationObjectToString = function(phaseDuration) { + // If there's a duration range return it + units + if (phaseDuration) { + return `${phaseDuration.min} - ${phaseDuration.max} ${ + phaseDuration.units + }`; + } + return undefined; + }; + + // Function for creating message string + let createMessageString = function(string, phase) { + return `**${capitalize(string)}**: ${durationObjectToString(phase)}`; + }; + + // Function for pushing dosage message to array + let pushDurationToMessageArray = function(durationString, phase) { + if (phase) { + messages.push(createMessageString(durationString, phase)); + } + }; + + if (substance.name) { + // Duration + messages.push(`*(${name})*`); + + if (roa.duration) { + pushDurationToMessageArray('onset', roa.duration.onset); + pushDurationToMessageArray('comeup', roa.duration.comeup); + pushDurationToMessageArray('peak', roa.duration.peak); + pushDurationToMessageArray('offset', roa.duration.offset); + pushDurationToMessageArray('afterglow', roa.duration.afterglow); + pushDurationToMessageArray('total', roa.duration.total); + messages.push(' '); + } else { + messages.push('No duration information.'); + } + } else { + console.log('Not sure why this would ever happen'); + messages.push('An unknown error has occurred <@278301453620084736>'); + } + } + return messages.length > 0 ? messages.join("\n") : "No duration info." +} + +// Builds the chemical class field +function buildChemicalClassField(substance) { + if ((typeof substance.class != undefined) && + (substance.class !== null) && + (typeof substance.class.chemical != undefined) && + (substance.class.chemical != null)) + { + return `**Chemical**: ${substance.class.chemical[0]}`; + } else { + return 'No chemical class information.'; + } +} + +// Builds the psychoactive class field +function buildPsychoactiveClassField(substance) { + if ((typeof substance.class != undefined) && + (substance.class !== null) && + (typeof substance.class.psychoactive != undefined) && + (substance.class.psychoactive != null)) + { + return `**Psychoactive**: ${substance.class.psychoactive[0]}`; + } else { + return 'No psychoactive class information.'; + } +} + +// Builds the addiction potential field +function buildAddictionPotentialField(substance) { + if (substance.addictionPotential !== null) { + return `${capitalize(substance.addictionPotential)}\n`; + } else { + return 'No addiction potential information.'; + } +} + +// Builds the link field +function buildLinksField(substance) { + return `[PsychonautWiki](https://psychonautwiki.org/wiki/${ substance.name.replace(/ /g, '_',) }) - [Effect Index](https://www.effectindex.com) - [Drug combination chart](https://wiki.tripsit.me/images/3/3a/Combo_2.png)`; +} + +function createTSChannelMessage(substance, message) { + const embed = Helpers.TemplatedMessageEmbed() + .setTitle(`**${substance.pretty_name} drug information**`) + .addField( + ':scales: __Dosages__', + `${buildTSDosageField(substance)}\n`, + true + ) + .addField( + ':clock2: __Duration__', + `${buildTSDurationField(substance)}\n`, + true + ) + .addField(':globe_with_meridians: __Links__', buildTSLinksField(substance)); + + message.channel.send({ embed }).catch(console.error); +} + +// Capitalization function +function capitalize(name) { + if (name === 'lsa') { + return name.toUpperCase(); + } else { + return name[0].toUpperCase() + name.slice(1); + } +} + +// Build TS dosage field +function buildTSDosageField(substance) { + console.log(`in buildTSDosageField -- ${JSON.stringify(substance.formatted_dose)}`) + + if ((typeof substance.formatted_dose != undefined) && + (substance.formatted_dose != null)) + { + // try fancy formatting + let substanceName = Object.keys(substance.formatted_dose)[0]; + return Object.entries(substance.formatted_dose[substanceName]).map(([intensity, dosageRange]) => { + return `**${capitalize(intensity)}**: ${dosageRange}`; + }).join("\n"); + } + + return `${substance.properties.dose}`; +} + +// Build TS duration field +function buildTSDurationField(substance) { + return `${substance.properties.duration}`; +} + +// Build TS links field +function buildTSLinksField(substance) { + return `[PsychonautWiki](https://psychonautwiki.org/wiki/${ + substance.name + })\n[Effect Index](https://www.effectindex.com)\n[Drug combination chart](http://wiki.tripsit.me/images/3/3a/Combo_2.png)\n[TripSit](http://www.tripsit.me)\n\nInformation sourced from TripSit`; +} + +// Parses and sanitizes substance name +function parseSubstanceName(string) { + let unsanitizedDrugName = string + .toLowerCase() + .replace(/^[^\s]+ /, '', -1) // remove first word + .replace(/-/g, '', -1) + .replace(/ /g, '', -1); + + // Sanitizes input names to match PsychonautWiki API names + return sanitizeSubstanceName(unsanitizedDrugName); +} diff --git a/lib/drug-o-matic/commands/invitelink.js b/lib/drug-o-matic/commands/invitelink.js @@ -0,0 +1,5 @@ +exports.run = (client, message, args) => { + message.channel + .send('Want to invite Dosebot Redux to your server? Click this: https://discord.com/oauth2/authorize?client_id=799165497710084116&scope=bot&permissions=268815552') + .catch(console.error); +} diff --git a/lib/drug-o-matic/commands/ketaminecalc.js b/lib/drug-o-matic/commands/ketaminecalc.js @@ -0,0 +1,48 @@ +const Discord = require('discord.js'); +const KetamineCalc = require('../include/ketaminecalc'); +const Helpers = require('../helpers.js'); + +exports.run = (client, message, args) => { + // Message variables + var tokens = message.content.toLowerCase().split(" ") + tokens.shift() // remove trigger + var combined = tokens.join("") + + if (tokens.length < 1 || isNaN(parseInt(combined))) { + message.channel.send('**Error:** No weight specified | Usage: `--ketaminecalc [weight] [unit]`. Example: `--ketaminecalc 85 kg`.'); + return; + } + + // parse weight from result + let weight = parseInt(combined); + let weightIsKilos = (combined.includes('kg') || combined.includes('kilo')); + + const embed = Helpers.TemplatedMessageEmbed() + .setTitle('Ketamine Dosage Calculator') + .addField( + '[:scales:] Dosages', + `Dosages for: **${weight}${weightIsKilos ? 'kg' : 'lbs'}**` + ) + .addField( + 'Insufflated', + KetamineCalc.generateInsufflatedDosages(weight, weightIsKilos), + true + ) + .addField( + 'Intramuscular', + KetamineCalc.generateIntramuscularDosages(weight, weightIsKilos), + true + ) + .addField( + 'Oral', + KetamineCalc.generateOralDosage(weight, weightIsKilos), + true + ) + .addField( + 'Rectal', + KetamineCalc.generateRectalDosage(weight, weightIsKilos), + true + ); + + message.channel.send({ embed }); +}; diff --git a/lib/drug-o-matic/commands/mascot.js b/lib/drug-o-matic/commands/mascot.js @@ -0,0 +1,5 @@ +exports.run = (client, message, args) => { + message.channel + .send(`Hello <@${ message.author.id }>, I'm DoseBot Redux! Nice to meet you! ^_^`, { files: ["./assets/mascot.png"] }) + .catch(console.error); +}; diff --git a/lib/drug-o-matic/commands/psychtolerance.js b/lib/drug-o-matic/commands/psychtolerance.js @@ -0,0 +1,35 @@ +// Usage --tolerance [days since last trip]. calculates tolerance/extra dose needed to achieve normal effects +exports.run = (client, message, args) => { + var str = message.content; + var result = str.split(" "); + var x = parseFloat(result[result.length - 1]); + var y = Math.pow(x - 14, 4) / 150 + (20 - (x / 14) * 20) + 100; + + // If < 14 days perform calculations, if greater then return no tolerance + if (x <= 14) { + if (x < 3) { + // If days since last dose would give a very high calculated dose return a warning + message.channel + .send( + "Take approximately **" + + Math.ceil(y / 10) * 10 + + "%** of the drug to reach full effects.\nWarning: Negative effects may be amplified with a high dose of a psychedelic.\n\nhttp://i47.tinypic.com/2qvcw79.jpg" + ) + .catch(console.error); + } else { + message.channel + .send( + "Take approximately " + + Math.ceil(y / 10) * 10 + + "% of the drug to reach full effects.\n\nhttp://i47.tinypic.com/2qvcw79.jpg" + ) + .catch(console.error); + } + } else { + message.channel + .send( + "You should not have a tolerance, take 100% of desired dosage.\n\nhttp://i47.tinypic.com/2qvcw79.jpg" + ) + .catch(console.error); + } +}; diff --git a/lib/drug-o-matic/commands/randomtdc.js b/lib/drug-o-matic/commands/randomtdc.js @@ -0,0 +1,8 @@ +// Sends a random TDC video to the channel +exports.run = (client, message, args) => { + let response = `<@${ + message.author.id + }> - Enjoy a random episode of The Drug Classroom: <https://kek.gg/u/LP7h>`; + + message.channel.send(response).catch(console.error); +}; diff --git a/lib/drug-o-matic/commands/role.js b/lib/drug-o-matic/commands/role.js @@ -0,0 +1,110 @@ +const roles = require('../include/roles.js'); + +function assignNickname(guild, user, substance, dosage) { + if (!guild.me.hasPermission('MANAGE_NICKNAMES')) { + console.log("Not setting nickname, don't have permission"); + return new Promise((resolve) => resolve()); + } + + if (substance !== undefined && dosage !== undefined) { + return user.setNickname(`${user.displayName} | ${substance} ${dosage}`); + } else if (substance !== undefined) { + return user.setNickname(`${user.displayName} | ${substance}`); + } else { + return new Promise((resolve) => resolve()) + } +} + +function restoreNickname(guild, user) { + if (!guild.me.hasPermission('MANAGE_NICKNAMES')) { + console.log("Not setting nickname, don't have permission"); + return new Promise((resolve) => resolve()); + } + + if (user.displayName.includes('|')) { + let nickTokens = user.displayName.split('|'); + return message.member.setNickname(nickTokens[0]); + } else { + return new Promise((resolve) => resolve()); + } +} + +function assignRole(guild, user, roleToApply, substance, dosage, isPermanent) { + return user.roles.add(roleToApply).then(() => { + // Catching this error. There's a bug that causes Missing Permissions API + // errors even with the permissions being checked. + return assignNickname(guild, user, substance, dosage).catch(console.error); + }).then(() => { + if (!isPermanent) { + new Promise((resolve) => { + console.log("Unassigning role in 8 hours.") + setTimeout(resolve, 8 * 60 * 60 * 1000); + }).then(() => { + return unassignRole(user, roleToApply); + }).catch(console.error); + } + }) +} + +function unassignRole(guild, user, roleToApply) { + return user.roles.remove(roleToApply).then(() => { + // Catching this error. There's a bug that causes Missing Permissions API + // errors even with the permissions being checked. + return restoreNickname(guild, user).catch(console.error); + }); +} + +// Function for toggling a role +function toggleRole(channel, user, roleToSet, substance, dosage, isPermanent) { + if (user.roles.cache.find(role => role.name == roleToSet.name)) { + // User already has role -- unset + return unassignRole(channel.guild, user, roleToSet).then(() => { + return channel.send(`Removed **${roleToSet.name}** from <@${user.id}>`); + }); + } else { + // User does not have role -- set + return assignRole(channel.guild, user, roleToSet, substance, dosage, isPermanent).then(() => { + return channel.send(`Added **${roleToSet.name}** to <@${user.id}>`); + }); + } +} + +exports.run = (client, message, args) => { + var tokens = message.content.split(" "); + tokens.shift(); + let roleName = tokens[0].toLowerCase().replace(/[\W_]+/g,""); + + if (!(roles.temporaryRoles.includes(roleName) || roles.permanentRoles.includes(roleName))) { + console.log(`Not a valid role: roleName`) + return + } + + let substance; + let dosage; + if (tokens.length === 2) { + substance = tokens[1]; + dosage = undefined; + } else if (tokens.length === 3) { + substance = tokens[1]; + dosage = tokens[2]; + } else { + substance = undefined; + dosage = undefined; + } + + // Checks to see if the desiredRole is equal to any role object's name property + const roleToSet = message.guild.roles.cache.find(role => role.name.toLowerCase().replace(/[\W_]+/g,"") == roleName) + if (!roleToSet) { + message.channel.send('Error: That role does not does not exist on this server.').catch(console.error); + return; + } + + let member = message.member; + if (!member) { + message.channel.send("It appears you're not a member of this guild.").catch(console.error); + } + + // Now that we have the desired guild role snowflake we can check if its temporary or permanent + let isPermanent = roles.permanentRoles.includes(roleName) + toggleRole(message.channel, member, roleToSet, substance, dosage, isPermanent).catch(console.error); +}; diff --git a/lib/drug-o-matic/commands/roles.js b/lib/drug-o-matic/commands/roles.js @@ -0,0 +1,38 @@ +const Helpers = require('../helpers.js'); + +// Roles message +exports.run = (client, message, args) => { + const Discord = require('discord.js'); + const roles = require('../include/roles.js'); + + const guildRoles = message.guild.roles.cache; + + const availableTemporaryRoles = []; + const availablePermanentRoles = []; + + roles.temporaryRoles.forEach(roleName => { + if (guildRoles.find(role => role.name.toLowerCase() === roleName)) { + availableTemporaryRoles.push(roleName); + } + }); + + roles.permanentRoles.forEach(roleName => { + if (guildRoles.find(role => role.name.toLowerCase() === roleName)) { + availablePermanentRoles.push(roleName); + } + }); + + const embed = Helpers.TemplatedMessageEmbed() + .setTitle('DoseBot Redux Help') + .addField('Temporary roles', generateRoleField(availableTemporaryRoles)) + .addField('Permanent roles', generateRoleField(availablePermanentRoles)); + + message.channel.send({ embed }); + + function generateRoleField(array) { + if (array.length > 0) { + return array.join('\n'); + } + return 'No roles'; + } +}; diff --git a/lib/drug-o-matic/commands/sei.js b/lib/drug-o-matic/commands/sei.js @@ -0,0 +1,8 @@ +// SEI blurb +exports.run = (client, message, args) => { + message.channel + .send( + "The Subjective Effect Index - https://www.effectindex.com/effects \nFounded by <@!295422447887450114>" + ) + .catch(console.error); +}; diff --git a/lib/drug-o-matic/commands/whois.js b/lib/drug-o-matic/commands/whois.js @@ -0,0 +1,29 @@ +//displays list of commands. in future should scan commands directory and display info for each programmatically/dynamically +exports.run = (client, message, args) => { + const Discord = require('discord.js'); + const Helpers = require('../helpers.js') + + const mentionedUsers = []; + + if (message.mentions) { + message.mentions.users.forEach(user => { + mentionedUsers.push(user); + }); + } + + if (mentionedUsers.length > 0) { + mentionedUsers.forEach(user => { + const embed = Helpers.TemplatedMessageEmbed() + .addField('Name', user.username) + .addField('Status', user.presence.status) + .addField('Registered', user.createdAt) + .addField('Last seen', user.lastMessage.createdAt) + .addField('Discord ID', user.id); + + message.channel.send({ embed }); + }); + } else { + message.channel.send('Error: No mentioned users detected'); + } + +}; diff --git a/lib/drug-o-matic/helpers.js b/lib/drug-o-matic/helpers.js @@ -0,0 +1,12 @@ +const Discord = require('discord.js'); + +exports.TemplatedMessageEmbed = function () { + return new Discord.MessageEmbed() + .setTimestamp() + .attachFiles(["./assets/logo.png"]) + .setAuthor('DoseBot Redux', 'attachment://logo.png') + .setThumbnail('attachment://logo.png') + .setColor('747474') + .setURL("https://github.com/dosebotredux") + .setFooter('Please use drugs responsibly', 'attachment://logo.png') +} diff --git a/lib/drug-o-matic/include/combos.js b/lib/drug-o-matic/include/combos.js @@ -0,0 +1,48 @@ +const Discord = require('discord.js'); +const Helpers = require('../helpers.js'); + +// Function for creating combo message +function createComboMessage(combos, name) { + return Helpers.TemplatedMessageEmbed() + .setTitle(`**${name} combo information**`) + .addField('Combos', combos); +} + +// Function for extracting combo information from query response +function pluckQueryResponse(response) { + // Extract data + const queryResults = JSON.parse(response); + const name = queryResults.data[0].pretty_name; + const combos = queryResults.data[0].combos; + + // Return object with needed data + return { name, combos }; +} + +// Function for creating combo string for embed +function generateEmbedComboString(combosObject) { + const comboArr = []; + + // Loop through the combos object and push the formatted combo to the comboArr + for (const combo in combosObject) { + if (combosObject.hasOwnProperty(combo)) { + const element = combosObject[combo]; + const substanceCombo = `${capitalize(combo)}: ${element.status}`; + + comboArr.push(substanceCombo); + } + } + // Sort and return it + return comboArr.sort().join('\n'); +} + +// Function for capitalizing +function capitalize(name) { + return name.toUpperCase(); +} + +module.exports = { + createComboMessage, + pluckQueryResponse, + generateEmbedComboString +}; diff --git a/lib/drug-o-matic/include/customs.json b/lib/drug-o-matic/include/customs.json @@ -0,0 +1,268 @@ +{ + "data": { + "substances": [ + { + "name": "ayahuasca", + "tolerance": { + "tolerance": "Ayahuasca does not have a tolerance" + }, + "class": { + "chemical": ["Tryptamine"], + "psychoactive": ["Psychedelics"] + }, + "addictionPotential": "not habit-forming", + "roas": [ + { + "bioavailability": null, + "dose": { + "dosage": + "Varies drastically depending on the preparation method and plant materials." + }, + "duration": { + "afterglow": { + "max": 8, + "min": 1, + "units": "hours" + }, + "comeup": null, + "duration": null, + "offset": { + "max": 8, + "min": 1, + "units": "hours" + }, + "onset": { + "max": 60, + "min": 20, + "units": "minutes" + }, + "peak": { + "max": 2, + "min": 1, + "units": "hours" + }, + "total": { + "max": 10, + "min": 5, + "units": "hours" + } + }, + "name": "oral" + } + ] + }, + { + "name": "datura", + "tolerance": { + "full": "Reached with repeated use", + "half": "3-7 days", + "zero": "1-2 weeks" + }, + "class": { + "chemical": ["Tropane alkaloids"], + "psychoactive": ["Deliriant"] + }, + "addictionPotential": + "Mildly addictive with a high potential for adverse side effects such as psychosis", + "roas": [ + { + "bioavailability": null, + "dose": { + "dosage": + "Varies drastically depending on the preparation method and plant materials." + }, + "duration": { + "afterglow": { + "max": 24, + "min": 6, + "units": "hours" + }, + "comeup": { + "max": 120, + "min": 60, + "units": "minutes" + }, + "duration": null, + "offset": { + "max": 3, + "min": 2, + "units": "hours" + }, + "onset": { + "max": 120, + "min": 20, + "units": "minutes" + }, + "peak": { + "max": 12, + "min": 5, + "units": "hours" + }, + "total": { + "max": 18, + "min": 8, + "units": "hours" + } + }, + "name": "oral" + } + ] + }, + { + "name": "salvia", + "class": { + "chemical": ["Terpenoid"], + "psychoactive": ["Hallucinogen"] + }, + "addictionPotential": "not habit-forming", + "roas": [ + { + "bioavailability": null, + "dose": { + "common": 0.5, + "heavy": 1, + "light": 0.25, + "strong": { + "max": 1.0, + "min": 0.75 + }, + "units": "g" + }, + "duration": { + "afterglow": { + "max": 60, + "min": 15, + "units": "seconds" + }, + "comeup": null, + "duration": null, + "offset": null, + "onset": { + "max": 60, + "min": 15, + "units": "seconds" + }, + "peak": null, + "total": { + "max": 90, + "min": 15, + "units": "minutes" + } + }, + "name": "smoked" + }, + { + "bioavailability": null, + "dose": { + "common": 0.5, + "heavy": 1, + "light": 0.25, + "strong": { + "max": 1.0, + "min": 0.75 + }, + "units": "g" + }, + "duration": { + "afterglow": { + "max": 120, + "min": 30, + "units": "seconds" + }, + "comeup": null, + "duration": null, + "offset": null, + "onset": { + "max": 20, + "min": 10, + "units": "minutes" + }, + "peak": null, + "total": { + "max": 90, + "min": 30, + "units": "minutes" + } + }, + "name": "sublingual" + } + ], + "tolerance": { + "tolerance": "Salvia does not have a tolerance" + } + }, + { + "name": "lsa", + "addictionPotential": "not habit-forming", + "class": { + "chemical": ["Lysergamide"], + "psychoactive": ["Psychedelics"] + }, + "roas": [ + { + "bioavailability": null, + "dose": { + "common": { + "max": 250, + "min": 100 + }, + "heavy": 400, + "light": { + "max": 100, + "min": 50 + }, + "strong": { + "max": 400, + "min": 250 + }, + "threshold": { + "max": 50, + "min": 20 + }, + "units": " seeds" + }, + "duration": { + "afterglow": { + "max": 48, + "min": 4, + "units": "hours" + }, + "comeup": { + "max": 75, + "min": 30, + "units": "minutes" + }, + "duration": null, + "offset": { + "max": 2, + "min": 1, + "units": "hours" + }, + "onset": { + "max": 40, + "min": 15, + "units": "minutes" + }, + "peak": { + "max": 3.5, + "min": 2, + "units": "hours" + }, + "total": { + "max": 7, + "min": 4.5, + "units": "hours" + } + }, + "name": "oral" + } + ], + "tolerance": { + "full": "almost immediately after ingestion", + "half": "5-7 days", + "zero": "14 days" + } + } + ] + } +} diff --git a/lib/drug-o-matic/include/dxmcalc.js b/lib/drug-o-matic/include/dxmcalc.js @@ -0,0 +1,73 @@ +module.exports.generateDosageField = generateDosageField; +module.exports.generateWarningField = generateWarningField; +module.exports.generateLinksField = generateLinksField; + +// Function for calculating dosages +function calculateDosages(weight, isKilos) { + let weightInLbs; + + if (isKilos) { + weightInLbs = Math.floor(weight * 2.2); + } else { + weightInLbs = weight; + } + + // kaylee's formula for dxm weight calculation + const calculatedDoseModifier = 2 * getLog(125, weightInLbs) - 1; + + // Return a dosage object + return { + lightMin: Math.floor(100 * calculatedDoseModifier), + lightMaxCommonMin: Math.floor(200 * calculatedDoseModifier), + commonMaxStrongMin: Math.floor(400 * calculatedDoseModifier), + strongMaxHeavy: Math.floor(700 * calculatedDoseModifier) + }; +} + +// Function for getting log base 125 +function getLog(x, y) { + return Math.log(y) / Math.log(x); +} + +// Function for generating dosage field +function generateDosageField(weight, isKilos) { + const dosageObject = calculateDosages(weight, isKilos); + const dosageArray = []; + + if (isKilos) { + dosageArray.push(`Dosages for: **${weight}kg**\n`); + } else { + dosageArray.push(`Dosages for: **${weight}lbs**\n`); + } + + dosageArray.push( + `**First plateau**: ${dosageObject.lightMin}-${ + dosageObject.lightMaxCommonMin + }mg` + ); + dosageArray.push( + `**Second plateau**: ${dosageObject.lightMaxCommonMin}-${ + dosageObject.commonMaxStrongMin + }mg` + ); + dosageArray.push( + `**Third plateau**: ${dosageObject.commonMaxStrongMin}-${ + dosageObject.strongMaxHeavy + }mg` + ); + dosageArray.push(`**Fourth plateau**: ${dosageObject.strongMaxHeavy}+mg`); + + return dosageArray.join('\n'); +} + +// Function for generating warning field +function generateWarningField() { + return `These recommendations are an approximation and are on the lower end for harm reduction purposes, please take into account your own personal tolerance and start with lower dosages. Doses exceeding 1500mg are potentially fatal.`; +} + +// Function for generating links field +function generateLinksField() { + return `[PsychonautWiki](https://psychonautwiki.org/wiki/DXM) + [Tripsit](http://drugs.tripsit.me/dxm) + [Drug combination chart](https://wiki.tripsit.me/images/3/3a/Combo_2.png)`; +} diff --git a/lib/drug-o-matic/include/effects.js b/lib/drug-o-matic/include/effects.js @@ -0,0 +1,36 @@ +module.exports.createEffectsList = createEffectsList; +module.exports.createFullEffectListLink = createFullEffectListLink; + +function createEffectsList(substance) { + // const substance = data.substances[0]; + const effects = substance.effects; + const numberOfEffects = effects.length; + const randomNumberArray = []; + const namesUnderscoresRemovedArray = []; + + while (randomNumberArray.length < 10) { + randomNumberArray.push(Math.floor(Math.random() * numberOfEffects)); + } + + randomNumberArray.forEach(element => { + namesUnderscoresRemovedArray.push(effects[element].name.replace(/ /g, '_')); + }); + + var messages = []; + + // loops through effects and add their name to the message variable + for (let i = 0; i < randomNumberArray.length; i++) { + messages.push( + `-[${ + effects[randomNumberArray[i]].name + }](https://psychonautwiki.org/wiki/${namesUnderscoresRemovedArray[i]})` + ); + } + return messages.join('\n'); +} + +function createFullEffectListLink(substance) { + return `These effects were randomly selected from a larger list - [see all effects](https://psychonautwiki.org/wiki/${ + substance.name + }#Subjective_effects)`; +} diff --git a/lib/drug-o-matic/include/ketaminecalc.js b/lib/drug-o-matic/include/ketaminecalc.js @@ -0,0 +1,72 @@ +// Calculate weight in pounds +function calculateWeight(weight, isKilos) { + if (isKilos) { + return Math.floor(weight * 2.2); + } else { + return weight; + } +} + +// Calculate insufflated dosages +function generateInsufflatedDosages(weight, isKilos) { + const weightInLbs = calculateWeight(weight, isKilos); + const dosageArray = []; + + dosageArray.push(`**Threshold**: ${weightInLbs * 0.1}mg`); + dosageArray.push(`**Light**: ${weightInLbs * 0.15}mg`); + dosageArray.push(`**Common**: ${weightInLbs * 0.3}mg`); + dosageArray.push(`**Strong**: ${weightInLbs * 0.5}-${weightInLbs * 0.75}mg`); + dosageArray.push(`**K-hole**: ${weightInLbs}mg`); + + return dosageArray.join('\n'); +} + +// Calculate intramuscular dosages +function generateIntramuscularDosages(weight, isKilos) { + const weightInLbs = calculateWeight(weight, isKilos); + const dosageArray = []; + + dosageArray.push(`**Threshold**: ${weightInLbs * 0.1}mg`); + dosageArray.push(`**Light**: ${weightInLbs * 0.15}mg`); + dosageArray.push(`**Common**: ${weightInLbs * 0.2}mg`); + dosageArray.push(`**Strong**: ${weightInLbs * 0.5}mg`); + dosageArray.push(`**K-hole**: ${weightInLbs * 0.75}mg`); + dosageArray.push(`**Anesthetic**: ${weightInLbs}mg`); + + return dosageArray.join('\n'); +} + +// Calculate oral dosages +function generateOralDosage(weight, isKilos) { + const weightInLbs = calculateWeight(weight, isKilos); + const dosageArray = []; + + dosageArray.push(`**Threshold**: ${weightInLbs * 0.3}mg`); + dosageArray.push(`**Light**: ${weightInLbs * 0.6}mg`); + dosageArray.push(`**Common**: ${weightInLbs * 0.75}-${weightInLbs * 2}mg`); + dosageArray.push(`**Strong**: ${weightInLbs * 2}-${weightInLbs * 2.5}mg`); + dosageArray.push(`**K-hole**: ${weightInLbs * 3}-${weightInLbs * 4}mg`); + + return dosageArray.join('\n'); +} + +// Calculate rectal dosages +function generateRectalDosage(weight, isKilos) { + const weightInLbs = calculateWeight(weight, isKilos); + const dosageArray = []; + + dosageArray.push(`**Threshold**: ${weightInLbs * 0.3}mg`); + dosageArray.push(`**Light**: ${weightInLbs * 0.6}mg`); + dosageArray.push(`**Common**: ${weightInLbs * 0.75}-${weightInLbs * 2}mg`); + dosageArray.push(`**Strong**: ${weightInLbs * 2}-${weightInLbs * 2.5}mg`); + dosageArray.push(`**K-hole**: ${weightInLbs * 3}-${weightInLbs * 4}mg`); + + return dosageArray.join('\n'); +} + +module.exports = { + generateInsufflatedDosages, + generateIntramuscularDosages, + generateOralDosage, + generateRectalDosage +}; diff --git a/lib/drug-o-matic/include/quote.js b/lib/drug-o-matic/include/quote.js @@ -0,0 +1,27 @@ +module.exports.insertQuote = insertQuote; +// MongoDB stuff +const MongoClient = require('mongodb').MongoClient; +const url = `mongodb://${process.env.MONGO_DB_USER}:${ + process.env.MONGO_DB_PASS +}@ds121282.mlab.com:21282/dosebot_quotes`; +const dbName = 'dosebot_quotes'; + +// Function for inserting into database +function insertQuote(message, quote, author) { + MongoClient.connect( + url, + function(err, client) { + console.log('Connected to Mongo'); + const db = client.db(dbName); + const collection = db.collection('quotes'); + + collection.insertOne({ quote: quote, author: author }); + + client.close(); + + message.channel.send( + `Added quote - **Author:** ${author} **Quote:** ${quote}` + ); + } + ); +} diff --git a/lib/drug-o-matic/include/roles.js b/lib/drug-o-matic/include/roles.js @@ -0,0 +1,24 @@ +module.exports.temporaryRoles = [ + 'tripping', + 'stimmed', + 'barred', + 'nodding', + 'drunk', + 'dissod', + 'rolling', + 'stoned', + 'hungover', + 'delirious', + 'altered', + 'baked', + 'microdosing', + 'gabaergic' +]; + +module.exports.permanentRoles = [ + 'he/him', + 'she/her', + 'they/them', + 'any pronouns', + 'ask my pronouns' +]; diff --git a/lib/drug-o-matic/include/sanitize-substance-name.js b/lib/drug-o-matic/include/sanitize-substance-name.js @@ -0,0 +1,101 @@ +module.exports = function sanitizeSubstanceName(drug) { + if (drug === 'ket') return 'ketamine' + if (drug === "dck") return "deschloroketamine" + if (drug === "pce") return "Eticyclidine" + if (drug === "3meopce") return "3-meo-pce" + if (drug === "pcp") return "Phencyclidine" + if (drug === "mxp") return "Methoxphenidine" + if (drug === "14bdo") return "1,4-Butanediol" + if (drug === "quaalude") return "Methaqualone" + if (drug === "eph") return "Ethylphenidate" + if (drug === "ipph") return "Isopropylphenidate" + if (drug === "hdmp28") return "Methylnaphthidate" + if (drug === "khat") return "Cathinone" + if (drug === "4mmc") return "Mephedrone" + if (drug === "dxm") return "dextromethorphan" + if (drug === "dph") return "diphenhydramine" + if (drug === "ghb") return "GHB" + if (drug === "diclaz") return "Diclazepam" + + // Lysergamides: LSD, 1P-LSD, ETH-LAD, 1P-ETH-LAD, AL-LAD, ALD-52, LSA, LSD, + // LSM-775, LSZ, PARGY-LAD, PRO-LAD, + if (drug === "lsm775") return "LSM-775" + if (drug === "lsz") return "LSZ" + if (drug === "pargylad") return "PARGY-LAD" + if (drug === "prolad") return "PRO-LAD" + // if (drug === "lsa") { return "LSA" } + + // 2C-{x}: B, C, D, E, H, I, iP, P, TFM, T-2, T-4, T-7, T-21 + // if (drug === "2cip") { return "2C-iP" } // doesn't exist + // if (drug === "2ctfm") { return "2C-TFM" } // doesn't exist + // if (drug === "2ct4") { return "2C-T-4" } // doesn't exist + if (drug === "2ct21") return "2C-T-21" + + // DO{x}: M, ET, PR, iPR, BU, AM, F, C, B, I, EF, TFM, N + if (drug === "dom") return "DOM" + // if (drug === "doet") { return "DOET" } // doesn't exist + // if (drug === "dopr") { return "DOPR" } // doesn't exist + // if (drug === "doipr") { return "DOiPR" } // doesn't exist + // if (drug === "dobu") { return "DOBU" } // doesn't exist + // if (drug === "doam") { return "DOAM" } // doesn't exist + // if (drug === "dof") { return "DOF" } // doesn't exist + // if (drug === "doc") { return "DOC" } // BREAKS THE API + if (drug === "dob") return "DOB" + if (drug === "doi") return "DOI" + // if (drug === "doef") { return "DOEF" } // doesn't exist + // if (drug === "dotfm") { return "DOTFM" } // doesn't exist + // if (drug === "don") { return "DON" } // doesn't exist + + // 25{x}-NBOMe: B, C, D, I, N + // if (drug === "25d") { return "25dnbome"} // doesn't exist + if (drug === "25n") return "25nnbome" + + // Base tryptamines: DMT, DET, MET, EPT, MPT, DPT, EiPT, MiPT, DiPT, aMT + if (drug === "det") return "DET" + if (drug === "met") return "MET" + if (drug === "ept") return "EPT" + if (drug === "mpt") return "MPT" + // if (drug == "eipt") { return "EiPT" } // doesn't exist + if (drug === "mipt") return "MiPT" + if (drug === "dipt") return "DiPT" + if (drug === "amt") return "aMT" + + // 4-sub tryptamines: 4-AcO-DET (Ethacetin), 4-AcO-DMT (Psilacetin), + // 4-AcO-DPT (Psipracetin), 4-AcO-DiPT (Ipracetin), 4-AcO-EPT, + // 4-AcO-MET (Metacetin), 4-AcO-MPT, 4-AcO-MiPT (Mipracetin), + // 4-HO-DET (Ethocin), 4-HO-DMT (Psilocin), 4-HO-DPT (Psiprocin), + // 4-HO-DiPT (Iprocin), 4-HO-EPT, 4-HO-MET (Metocin), 4-HO-MPT, + // 4-HO-MiPT (Miprocin) + if (drug === "4acodet") return "4-AcO-DET" + // if (drug === "4acodpt") { return "4-AcO-DPT" } // doesn't exist + if (drug === "4acoept") return "4-AcO-EPT" + // if (drug === "4acompt") { return "4-AcO-MPT" } // doesn't exist + if (drug === "4acomipt") return "4-AcO-MiPT" + if (drug === "4hodet") return "4-HO-DET" + if (drug === "4hodmt") return "4-HO-DMT" + if (drug === "4hodpt") return "4-HO-DPT" + if (drug === "4hodipt") return "4-HO-DiPT" + if (drug === "4hoept") return "4-HO-EPT" + + if (drug === "ethacetin") return "4-AcO-DET" + // if (drug === "psipracetin") { return "4-AcO-DPT" } // doesn't exist + if (drug === "ipracetin") return "4-AcO-DET" + if (drug === "metacetin") return "4-AcO-MET" + if (drug === "mipracetin") return "4-AcO-MiPT" + if (drug === "psiprocin") return "4-HO-DPT" + + // 5-sub tryptamines: 5-HO-DMT / Bufotenin, 5-MeO-DALT, 5-MeO-DMT, + // 5-MeO-DiPT / Foxy, 5-MeO-MALT, 5-MeO-MiPT / Moxy, 5-MeO-aMT + if (drug === "5hodmt") return "5-HO-DMT"; + if (drug === "5meodipt") return "5-MeO-DiPT" + if (drug === "foxy") return "5-MeO-DiPT" + // if (drug === "5meomalt") { return "5-MeO-MALT" } // doesn't exist + if (drug === "5meomipt") return "5-MeO-MiPT" + if (drug === "moxy") return "5-MeO-MiPT" + // if (drug === "5meoamt") { return "5-MeO-aMT" } // doesn't exist + + // Other pharmaceuticals + if (drug === "sertraline") return "ssri"; + + return drug +} diff --git a/lib/drug-o-matic/package.json b/lib/drug-o-matic/package.json @@ -0,0 +1,26 @@ +{ + "name": "DoseBot-Redux", + "version": "0.0.1", + "description": "Dosage bot", + "main": "bot.js", + "repository": "https://github.com/wjlafrance/DosebotRedux.git", + "author": "wjlafrance", + "license": "Unlicense", + "dependencies": { + "bufferutil": "^4.0.0", + "forever": "^0.15.3", + "discord.js": "^12.4.1", + "dotenv": "^5.0.1", + "request": "^2.88.0", + "request-promise": "^4.2.4" + }, + "devDependencies": { + "eslint": "^4.19.1", + "eslint-config-airbnb-base": "^13.2.0", + "eslint-config-google": "^0.9.1", + "eslint-plugin-import": "^2.18.2" + }, + "scripts": { + "start": "node bot.js" + } +} diff --git a/lib/drug-o-matic/pw-info-pw-e2e-test.js b/lib/drug-o-matic/pw-info-pw-e2e-test.js @@ -0,0 +1,31 @@ +const info = require('./commands/info'); + +info.run(null, { + content: '4-aco-dmt', + guild: { + name: 'foo' + }, + channel: { + send: console.log + } +}) + +const effects = require('./commands/effects'); + +const p1 = function(...args) { + console.log(...args); + + return { + catch: () => {} + } +}; + +effects.run(null, { + content: '4-aco-dmt', + guild: { + name: 'foo' + }, + channel: { + send: p1 + } +}) diff --git a/lib/drug-o-matic/queries/effects.js b/lib/drug-o-matic/queries/effects.js @@ -0,0 +1,11 @@ +exports.effect = function(substance) { + return `{ + substances(query: "${substance}") { + name + + effects { + name url + } + } + }`; +}; diff --git a/lib/drug-o-matic/queries/info.js b/lib/drug-o-matic/queries/info.js @@ -0,0 +1,44 @@ +exports.info = function(substance) { + return `{ + substances(query: "${substance}") { + name + addictionPotential + class { + chemical + psychoactive + } + tolerance { + full + half + zero + } + # routes of administration + roas { + name + + dose { + units + threshold + heavy + common { min max } + light { min max } + strong { min max } + } + + duration { + afterglow { min max units } + comeup { min max units } + duration { min max units } + offset { min max units } + onset { min max units } + peak { min max units } + total { min max units } + } + + bioavailability { + min max + } + } + } + }`; +}; diff --git a/lib/drug-o-matic/readme.md b/lib/drug-o-matic/readme.md @@ -0,0 +1,34 @@ +# DoseBot + +**DoseBot** is a harm reduction Discord bot, used to provide users with a variety of useful harm reduction information from [PsychonautWiki](https://www.psychonautwiki.org) and effect information from [Effect Index](https://www.effectindex.com). + +**Harm reduction** is the set of practical strategies and ideas at reducing negative consequences associated with substance use. Harm reduction is also a movement for social justice built on a belief in, and respect for, the rights of people who use substances - [Harm Reduction Coalition](http://harmreduction.org/about-us/principles-of-harm-reduction/). + +The **drug abuse epidemic** that has been sweeping the the United States has cost 63,600 lives in 2016 alone [CDC](https://www.cdc.gov/nchs/products/databriefs/db294.htm), with a median age of 20. Every day DoseBot provides scientifically backed best practices to tens of thousands of users that helps save lives. + +## Features + +- Substance harm reduction information +- Combination safety information +- Role management system +- Effect information +- Tolerance calculators +- And more! Say `--help` for the full command list. + +## Contributors + +This project is maintained by members of the [dosebotredux organization](https://github.com/dosebotredux) on Github. + +## Usage + +1. Clone repo +2. `npm install` to download dependencies +3. `DISCORD_API_TOKEN=xxx node bot.js` to start bot + +## Invite DoseBot Redux to your server! + +Want DoseBot Redux on your server? Just click [this link](https://discord.com/oauth2/authorize?client_id=799165497710084116&scope=bot&permissions=268815552) and it shall appear! + +### In memoriam + +DoseBot Redux is maintained in memory of Cocoa, 1995 - 2019. Cocoa was the creator of the [original DoseBot](https://github.com/GabrielMorris/DoseBot). diff --git a/lib/drug-o-matic/test-command.js b/lib/drug-o-matic/test-command.js @@ -0,0 +1,34 @@ +const CommandSystem = require("./command-system.js"); + +const input = process.argv + .filter(function(x, idx) { + return idx >= 2; + }) + .join(" "); + +console.log(`Command input: ${input}`); + +const catchable = { + catch: function() {} +}; + +const client = {}; + +const message = { + content: input, + author: { + bot: false + }, + channel: { + send: function(x) { + console.log(`channel.send: ${x}`); + return catchable; + } + } +}; + +const commandSystem = CommandSystem(); + +commandSystem.load(function() { + commandSystem.execute(client, message); +});