├── helpers ├── result.js ├── sleep.js ├── getRandomItem.js ├── random.js ├── getMemberByReply.js ├── getMemberByMention.js ├── locale.js ├── recursiveReader.js ├── templateMessages.js └── roleplayMessages.js ├── colors.json ├── config.json.example ├── invites.json ├── tokens.json.example ├── api ├── somerandomapiml.js ├── routerBuilder.js ├── shirogg.js ├── nekoslife.js ├── nekosfun.js ├── purrbotsite.js └── nekosbest.js ├── package.json ├── botlistapi ├── BotsForDiscordPoster.js ├── ListcordPoster.js ├── BoticordPoster.js ├── DiscordBotListPoster.js ├── BotsServerDiscordPoster.js ├── FateslistPoster.js └── BasePoster.js ├── events ├── statsPoster.js ├── guildChecker.js ├── pingListener.js ├── ownerCommandsHandler.js └── commandsHandler.js ├── commands ├── emotes │ ├── like.js │ ├── bored.js │ ├── shrug.js │ ├── think.js │ ├── pout.js │ ├── wink.js │ ├── sleep.js │ ├── laugh.js │ ├── dance.js │ ├── happy.js │ ├── cry.js │ ├── smug.js │ └── blush.js ├── actions │ ├── wave.js │ ├── stare.js │ ├── cringe.js │ ├── highfive.js │ ├── bite.js │ ├── lick.js │ ├── feed.js │ ├── kiss.js │ ├── poke.js │ ├── slap.js │ ├── tickle.js │ ├── pat.js │ └── hug.js ├── misc │ ├── invite.js │ ├── ping.js │ ├── vote.js │ ├── donate.js │ └── help.js ├── nsfwActions │ ├── spank.js │ ├── fuck.js │ ├── kuni.js │ ├── cum.js │ ├── anal.js │ └── blowjob.js ├── fun │ ├── random.js │ ├── try.js │ └── dice.js └── serverCommands │ ├── prefix.js │ └── locale.js ├── .github └── FUNDING.yml ├── LICENSE ├── README.md ├── .gitignore ├── ownerCommands ├── eval.js └── blacklist.js ├── index.js ├── bot.js └── locales ├── en-US.json └── ru-RU.json /helpers/result.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /colors.json: -------------------------------------------------------------------------------- 1 | { 2 | "embedInvisible": "#2f3136", 3 | "botOfficial": "#e03260" 4 | } 5 | -------------------------------------------------------------------------------- /config.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "prefix": "./", 3 | "token": "YOUR BOT TOKEN", 4 | "owners": ["YOUR DISCORD ID"], 5 | "beta": true 6 | } 7 | -------------------------------------------------------------------------------- /invites.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": "https://discord.gg/Hr6Z9nNE2d", 3 | "bot": "https://discord.com/oauth2/authorize?client_id=793544441863471134&permissions=321608&scope=bot" 4 | } 5 | -------------------------------------------------------------------------------- /tokens.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "discordbotlist": "", 3 | "fateslist": "", 4 | "listcord": "", 5 | "botsServerDiscord": "", 6 | "botsfordiscord": "", 7 | "boticord": "" 8 | } 9 | -------------------------------------------------------------------------------- /helpers/sleep.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sleep 3 | * @param {number} ms Time to sleep in milliseconds 4 | */ 5 | const sleep = (ms) => new Promise((resolve) => setTimeout(() => resolve(), ms)); 6 | 7 | module.exports = sleep; 8 | -------------------------------------------------------------------------------- /helpers/getRandomItem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @template T 3 | * @param {T[]} array 4 | * @returns {T} 5 | */ 6 | const getRandomItem = (array) => 7 | array[Math.floor(Math.random() * array.length)]; 8 | 9 | module.exports = getRandomItem; 10 | -------------------------------------------------------------------------------- /helpers/random.js: -------------------------------------------------------------------------------- 1 | const random = (min, max) => Math.floor(Math.random() * (max + 1 - min) + min); 2 | const randomFloat = (min, max) => Math.random() * (max + 1 - min) + min; 3 | 4 | module.exports = { 5 | random, 6 | randomFloat, 7 | }; 8 | -------------------------------------------------------------------------------- /api/somerandomapiml.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios").default; 2 | const apiBase = axios.create({ 3 | baseURL: "https://some-random-api.ml/animu/", 4 | transformResponse: [(data) => JSON.parse(data).link], 5 | }); 6 | const buildRouter = require("./routerBuilder"); 7 | 8 | const routes = { 9 | hug: "hug", 10 | pat: "pat", 11 | wink: "wink", 12 | }; 13 | 14 | module.exports = buildRouter(apiBase, routes); 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "roleplay-bot", 3 | "description": "Roleplay bot for Discord", 4 | "version": "1.0.0", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "license": "MIT", 10 | "dependencies": { 11 | "axios": "^0.21.1", 12 | "bufferutil": "^4.0.2", 13 | "discord.js": "^13.1.0", 14 | "enmap": "^5.8.4", 15 | "utf-8-validate": "^5.0.3" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /botlistapi/BotsForDiscordPoster.js: -------------------------------------------------------------------------------- 1 | const BasePoster = require("./BasePoster"); 2 | 3 | class BotsForDiscordPoster extends BasePoster { 4 | post({ guilds }) { 5 | const headers = { 6 | Authorization: this.token, 7 | }; 8 | 9 | const body = { 10 | server_count: guilds, 11 | }; 12 | 13 | super.post(body, headers, `https://botsfordiscord.com/api/bot/${this.id}`); 14 | } 15 | } 16 | 17 | module.exports = BotsForDiscordPoster; 18 | -------------------------------------------------------------------------------- /helpers/getMemberByReply.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {import("discord.js").Message} reply 3 | * @returns {Promise} 4 | */ 5 | const getMemberByReply = async (reply) => { 6 | try { 7 | const original = await reply.channel.messages.fetch( 8 | reply.reference.messageId 9 | ); 10 | return original.member; 11 | } catch { 12 | return undefined; 13 | } 14 | }; 15 | 16 | module.exports = getMemberByReply; 17 | -------------------------------------------------------------------------------- /botlistapi/ListcordPoster.js: -------------------------------------------------------------------------------- 1 | const BasePoster = require("./BasePoster"); 2 | 3 | class ListcordPoster extends BasePoster { 4 | post({ guilds, users, shards, shard }) { 5 | const headers = { 6 | Authorization: this.token, 7 | }; 8 | 9 | const body = { 10 | server_count: guilds, 11 | }; 12 | 13 | super.post(body, headers, `https://listcord.gg/api/bot/${this.id}/stats`); 14 | } 15 | } 16 | 17 | module.exports = ListcordPoster; 18 | -------------------------------------------------------------------------------- /botlistapi/BoticordPoster.js: -------------------------------------------------------------------------------- 1 | const BasePoster = require("./BasePoster"); 2 | 3 | class BoticordPoster extends BasePoster { 4 | post({ guilds, users, shards }) { 5 | const headers = { 6 | Authorization: this.token, 7 | }; 8 | 9 | const body = { 10 | servers: guilds, 11 | shards, 12 | users, 13 | }; 14 | 15 | super.post(body, headers, "https://boticord.top/api/stats"); 16 | } 17 | } 18 | 19 | module.exports = BoticordPoster; 20 | -------------------------------------------------------------------------------- /helpers/getMemberByMention.js: -------------------------------------------------------------------------------- 1 | const mentionRegex = /<@!?(\d*?)>/; 2 | 3 | /** 4 | * @param {import("discord.js").Guild} guild 5 | * @param {string} mention 6 | * @returns {Promise} 7 | */ 8 | const getMemberByMention = async (guild, mention) => { 9 | try { 10 | const memberId = mention.match(mentionRegex)[1]; 11 | return await guild.members.fetch(memberId || mention); 12 | } catch { 13 | return undefined; 14 | } 15 | }; 16 | 17 | module.exports = getMemberByMention; 18 | -------------------------------------------------------------------------------- /botlistapi/DiscordBotListPoster.js: -------------------------------------------------------------------------------- 1 | const BasePoster = require("./BasePoster"); 2 | 3 | class DiscordBotListPoster extends BasePoster { 4 | post({ guilds, users, shards, shard }) { 5 | const headers = { 6 | Authorization: this.token, 7 | }; 8 | 9 | const body = { 10 | guilds, 11 | users, 12 | }; 13 | 14 | super.post( 15 | body, 16 | headers, 17 | `https://discordbotlist.com/api/v1/bots/${this.id}/stats` 18 | ); 19 | } 20 | } 21 | 22 | module.exports = DiscordBotListPoster; 23 | -------------------------------------------------------------------------------- /api/routerBuilder.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @template T 3 | * @param {import("axios").AxiosInstance} apiBase 4 | * @param {T} routes 5 | * @param {string} suffix 6 | * @returns {{[K in keyof T]: () => Promise}} 7 | */ 8 | const buildRouter = (apiBase, routes, suffix = "/") => { 9 | const newRoutes = {}; 10 | for (const key of Object.keys(routes)) { 11 | newRoutes[key] = () => 12 | apiBase.get(`${routes[key]}${suffix}`).then((res) => res.data); 13 | } 14 | 15 | return newRoutes; 16 | }; 17 | 18 | module.exports = buildRouter; 19 | -------------------------------------------------------------------------------- /botlistapi/BotsServerDiscordPoster.js: -------------------------------------------------------------------------------- 1 | const BasePoster = require("./BasePoster"); 2 | 3 | class DiscordBotListPoster extends BasePoster { 4 | post({ guilds, shards }) { 5 | const headers = { 6 | Authorization: `SDC ${this.token}`, 7 | }; 8 | 9 | const body = { 10 | servers: guilds, 11 | shards, 12 | }; 13 | 14 | super.post( 15 | body, 16 | headers, 17 | `https://api.server-discord.com/v2/bots/${this.id}/stats` 18 | ); 19 | } 20 | } 21 | 22 | module.exports = DiscordBotListPoster; 23 | -------------------------------------------------------------------------------- /events/statsPoster.js: -------------------------------------------------------------------------------- 1 | async function guildChange(guild) { 2 | guild.client.shard.send({ 3 | type: "guildsUpdate", 4 | data: { 5 | clientId: guild.client.user.id, 6 | }, 7 | }); 8 | } 9 | 10 | function load(client) { 11 | client.on("guildCreate", guildChange); 12 | client.on("guildDelete", guildChange); 13 | } 14 | 15 | function unload(client) { 16 | client.off("guildCreate", guildChange); 17 | client.off("guildDelete", guildChange); 18 | } 19 | 20 | module.exports = { 21 | name: "statsPoster", 22 | load, 23 | unload, 24 | }; 25 | -------------------------------------------------------------------------------- /commands/emotes/like.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const nekosbest = require("../../api/nekosbest"); 4 | 5 | const providers = [nekosbest.thumbsup]; 6 | 7 | async function like(msg, args, locale) { 8 | await sendEmotion({ 9 | msg, 10 | locale, 11 | providers, 12 | emote: "like", 13 | }); 14 | } 15 | 16 | module.exports = { 17 | name: "like", 18 | execute: like, 19 | alias: [], 20 | cooldown: 2, 21 | argsRequired: 0, 22 | module: "Emotes", 23 | isPrivate: false, 24 | nsfw: false, 25 | }; 26 | -------------------------------------------------------------------------------- /botlistapi/FateslistPoster.js: -------------------------------------------------------------------------------- 1 | const BasePoster = require("./BasePoster"); 2 | 3 | class FateslistPoster extends BasePoster { 4 | post({ guilds, users, shards, shard }) { 5 | const headers = { 6 | Authorization: this.token, 7 | }; 8 | 9 | const body = { 10 | guild_count: guilds, 11 | shard_count: shards, 12 | user_count: users, 13 | }; 14 | 15 | super.post( 16 | body, 17 | headers, 18 | `https://fateslist.xyz/api/v2/bots/${this.id}/stats` 19 | ); 20 | } 21 | } 22 | 23 | module.exports = FateslistPoster; 24 | -------------------------------------------------------------------------------- /commands/emotes/bored.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const nekosbest = require("../../api/nekosbest"); 4 | 5 | const providers = [nekosbest.bored]; 6 | 7 | async function bored(msg, args, locale) { 8 | await sendEmotion({ 9 | msg, 10 | locale, 11 | providers, 12 | emote: "bored", 13 | }); 14 | } 15 | 16 | module.exports = { 17 | name: "bored", 18 | execute: bored, 19 | alias: [], 20 | cooldown: 2, 21 | argsRequired: 0, 22 | module: "Emotes", 23 | isPrivate: false, 24 | nsfw: false, 25 | }; 26 | -------------------------------------------------------------------------------- /commands/emotes/shrug.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const nekosbest = require("../../api/nekosbest"); 4 | 5 | const providers = [nekosbest.shrug]; 6 | 7 | async function shrug(msg, args, locale) { 8 | await sendEmotion({ 9 | msg, 10 | locale, 11 | providers, 12 | emote: "shrug", 13 | }); 14 | } 15 | 16 | module.exports = { 17 | name: "shrug", 18 | execute: shrug, 19 | alias: [], 20 | cooldown: 2, 21 | argsRequired: 0, 22 | module: "Emotes", 23 | isPrivate: false, 24 | nsfw: false, 25 | }; 26 | -------------------------------------------------------------------------------- /commands/emotes/think.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const nekosbest = require("../../api/nekosbest"); 4 | 5 | const providers = [nekosbest.think]; 6 | 7 | async function think(msg, args, locale) { 8 | await sendEmotion({ 9 | msg, 10 | locale, 11 | providers, 12 | emote: "think", 13 | }); 14 | } 15 | 16 | module.exports = { 17 | name: "think", 18 | execute: think, 19 | alias: [], 20 | cooldown: 2, 21 | argsRequired: 0, 22 | module: "Emotes", 23 | isPrivate: false, 24 | nsfw: false, 25 | }; 26 | -------------------------------------------------------------------------------- /helpers/locale.js: -------------------------------------------------------------------------------- 1 | const translate = (templatePath, locale = "ru-RU", data = {}) => { 2 | const localeTemplates = require(`../locales/${locale}.json`); 3 | let template; 4 | const keys = templatePath.split("."); 5 | for (const key of keys) { 6 | template = template?.[key] || localeTemplates[key]; 7 | } 8 | 9 | if (typeof template !== "string") { 10 | return template; 11 | } 12 | 13 | return template.replace(/{([\w\d_]*?)}/gm, (match, key) => 14 | data.hasOwnProperty(key) ? data[key] : match 15 | ); 16 | }; 17 | 18 | module.exports = translate; 19 | -------------------------------------------------------------------------------- /api/shirogg.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios").default; 2 | const apiBase = axios.create({ 3 | baseURL: "https://api.dbot.dev/images/", 4 | transformResponse: [(data) => JSON.parse(data).url], 5 | }); 6 | const buildRouter = require("./routerBuilder"); 7 | 8 | const routes = { 9 | blush: "blush", 10 | cry: "cry", 11 | hug: "hug", 12 | kiss: "kiss", 13 | lick: "lick", 14 | nom: "nom", 15 | pat: "pat", 16 | poke: "poke", 17 | pout: "pout", 18 | punch: "punch", 19 | slap: "slap", 20 | sleep: "sleep", 21 | smug: "smug", 22 | tickle: "tickle", 23 | }; 24 | 25 | module.exports = buildRouter(apiBase, routes); 26 | -------------------------------------------------------------------------------- /commands/emotes/pout.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const shirogg = require("../../api/shirogg"); 4 | const nekosbest = require("../../api/nekosbest"); 5 | 6 | const providers = [shirogg.pout, nekosbest.pout]; 7 | 8 | async function pout(msg, args, locale) { 9 | await sendEmotion({ 10 | msg, 11 | locale, 12 | providers, 13 | emote: "pout", 14 | }); 15 | } 16 | 17 | module.exports = { 18 | name: "pout", 19 | execute: pout, 20 | alias: [], 21 | cooldown: 2, 22 | argsRequired: 0, 23 | module: "Emotes", 24 | isPrivate: false, 25 | nsfw: false, 26 | }; 27 | -------------------------------------------------------------------------------- /commands/emotes/wink.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const sra = require("../../api/somerandomapiml"); 4 | const nekosbest = require("../../api/nekosbest"); 5 | 6 | const providers = [sra.wink, nekosbest.wink]; 7 | 8 | async function wink(msg, args, locale) { 9 | await sendEmotion({ 10 | msg, 11 | locale, 12 | providers, 13 | emote: "wink", 14 | }); 15 | } 16 | 17 | module.exports = { 18 | name: "wink", 19 | execute: wink, 20 | alias: [], 21 | cooldown: 2, 22 | argsRequired: 0, 23 | module: "Emotes", 24 | isPrivate: false, 25 | nsfw: false, 26 | }; 27 | -------------------------------------------------------------------------------- /commands/emotes/sleep.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const shirogg = require("../../api/shirogg"); 4 | const nekosbest = require("../../api/nekosbest"); 5 | 6 | const providers = [shirogg.sleep, nekosbest.sleep]; 7 | 8 | async function sleep(msg, args, locale) { 9 | await sendEmotion({ 10 | msg, 11 | locale, 12 | providers, 13 | emote: "sleep", 14 | }); 15 | } 16 | 17 | module.exports = { 18 | name: "sleep", 19 | execute: sleep, 20 | alias: [], 21 | cooldown: 2, 22 | argsRequired: 0, 23 | module: "Emotes", 24 | isPrivate: false, 25 | nsfw: false, 26 | }; 27 | -------------------------------------------------------------------------------- /commands/emotes/laugh.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const nekosbest = require("../../api/nekosbest"); 4 | const nekosfun = require("../../api/nekosfun"); 5 | 6 | const providers = [nekosbest.laugh, nekosfun.laugh]; 7 | 8 | async function laugh(msg, args, locale) { 9 | await sendEmotion({ 10 | msg, 11 | locale, 12 | providers, 13 | emote: "laugh", 14 | }); 15 | } 16 | 17 | module.exports = { 18 | name: "laugh", 19 | execute: laugh, 20 | alias: [], 21 | cooldown: 2, 22 | argsRequired: 0, 23 | module: "Emotes", 24 | isPrivate: false, 25 | nsfw: false, 26 | }; 27 | -------------------------------------------------------------------------------- /commands/emotes/dance.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const nekosbest = require("../../api/nekosbest"); 5 | 6 | const providers = [purrbotsite.dance, nekosbest.dance]; 7 | 8 | async function dance(msg, args, locale) { 9 | await sendEmotion({ 10 | msg, 11 | locale, 12 | providers, 13 | emote: "dance", 14 | }); 15 | } 16 | 17 | module.exports = { 18 | name: "dance", 19 | execute: dance, 20 | alias: [], 21 | cooldown: 2, 22 | argsRequired: 0, 23 | module: "Emotes", 24 | isPrivate: false, 25 | nsfw: false, 26 | }; 27 | -------------------------------------------------------------------------------- /commands/emotes/happy.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const nekosbest = require("../../api/nekosbest"); 5 | 6 | const providers = [purrbotsite.smile, nekosbest.happy]; 7 | 8 | async function happy(msg, args, locale) { 9 | await sendEmotion({ 10 | msg, 11 | locale, 12 | providers, 13 | emote: "happy", 14 | }); 15 | } 16 | 17 | module.exports = { 18 | name: "happy", 19 | execute: happy, 20 | alias: [], 21 | cooldown: 2, 22 | argsRequired: 0, 23 | module: "Emotes", 24 | isPrivate: false, 25 | nsfw: false, 26 | }; 27 | -------------------------------------------------------------------------------- /commands/actions/wave.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const nekosbest = require("../../api/nekosbest"); 4 | 5 | const providers = [nekosbest.wave]; 6 | 7 | async function wave(msg, args, locale) { 8 | await sendAction({ 9 | msg, 10 | args, 11 | locale, 12 | providers, 13 | nsfw: false, 14 | meSelfEmbed: true, 15 | userSelfEmbed: true, 16 | action: "wave", 17 | }); 18 | } 19 | 20 | module.exports = { 21 | name: "wave", 22 | execute: wave, 23 | alias: [], 24 | cooldown: 2, 25 | argsRequired: 0, 26 | module: "Actions", 27 | isPrivate: false, 28 | nsfw: false, 29 | }; 30 | -------------------------------------------------------------------------------- /commands/actions/stare.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const nekosbest = require("../../api/nekosbest"); 4 | 5 | const providers = [nekosbest.stare]; 6 | 7 | async function stare(msg, args, locale) { 8 | await sendAction({ 9 | msg, 10 | args, 11 | locale, 12 | providers, 13 | nsfw: false, 14 | meSelfEmbed: true, 15 | userSelfEmbed: true, 16 | action: "stare", 17 | }); 18 | } 19 | 20 | module.exports = { 21 | name: "stare", 22 | execute: stare, 23 | alias: [], 24 | cooldown: 2, 25 | argsRequired: 0, 26 | module: "Actions", 27 | isPrivate: false, 28 | nsfw: false, 29 | }; 30 | -------------------------------------------------------------------------------- /commands/actions/cringe.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const nekosbest = require("../../api/nekosbest"); 4 | 5 | const providers = [nekosbest.facepalm]; 6 | 7 | async function cringe(msg, args, locale) { 8 | await sendAction({ 9 | msg, 10 | args, 11 | locale, 12 | providers, 13 | nsfw: false, 14 | meSelfEmbed: true, 15 | userSelfEmbed: true, 16 | action: "cringe", 17 | }); 18 | } 19 | 20 | module.exports = { 21 | name: "cringe", 22 | execute: cringe, 23 | alias: [], 24 | cooldown: 2, 25 | argsRequired: 0, 26 | module: "Actions", 27 | isPrivate: false, 28 | nsfw: false, 29 | }; 30 | -------------------------------------------------------------------------------- /commands/actions/highfive.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const nekosbest = require("../../api/nekosbest"); 4 | 5 | const providers = [nekosbest.highfive]; 6 | 7 | async function highfive(msg, args, locale) { 8 | await sendAction({ 9 | msg, 10 | args, 11 | locale, 12 | providers, 13 | nsfw: false, 14 | meSelfEmbed: true, 15 | userSelfEmbed: true, 16 | action: "highfive", 17 | }); 18 | } 19 | 20 | module.exports = { 21 | name: "highfive", 22 | execute: highfive, 23 | alias: [], 24 | cooldown: 2, 25 | argsRequired: 0, 26 | module: "Actions", 27 | isPrivate: false, 28 | nsfw: false, 29 | }; 30 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: dmax_programmer 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://boosty.to/dmax'] 13 | -------------------------------------------------------------------------------- /api/nekoslife.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios").default; 2 | const apiBase = axios.create({ 3 | baseURL: "https://nekos.life/api/v2/img/", 4 | transformResponse: [(data) => JSON.parse(data).url], 5 | }); 6 | const buildRouter = require("./routerBuilder"); 7 | 8 | const routes = { 9 | cuddle: "cuddle", 10 | feed: "feed", 11 | hug: "hug", 12 | kiss: "kiss", 13 | pat: "pat", 14 | poke: "poke", 15 | tickle: "tickle", 16 | slap: "slap", 17 | smug: "smug", 18 | 19 | anal: "anal", 20 | bj: "bj", 21 | blowjob: "blowjob", 22 | classic: "classic", 23 | cum: "cum", 24 | kuni: "kuni", 25 | spank: "spank", 26 | }; 27 | 28 | module.exports = buildRouter(apiBase, routes, ""); 29 | -------------------------------------------------------------------------------- /commands/emotes/cry.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const shirogg = require("../../api/shirogg"); 5 | const nekosbest = require("../../api/nekosbest"); 6 | 7 | const providers = [shirogg.cry, purrbotsite.cry, nekosbest.cry]; 8 | 9 | async function cry(msg, args, locale) { 10 | await sendEmotion({ 11 | msg, 12 | locale, 13 | providers, 14 | emote: "cry", 15 | }); 16 | } 17 | 18 | module.exports = { 19 | name: "cry", 20 | execute: cry, 21 | alias: [], 22 | cooldown: 2, 23 | argsRequired: 0, 24 | module: "Emotes", 25 | isPrivate: false, 26 | nsfw: false, 27 | }; 28 | -------------------------------------------------------------------------------- /commands/emotes/smug.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const nekosbest = require("../../api/nekosbest"); 4 | const nekosfun = require("../../api/nekosfun"); 5 | const shirogg = require("../../api/shirogg"); 6 | 7 | const providers = [nekosbest.smug, nekosfun.smug, shirogg.smug]; 8 | 9 | async function smug(msg, args, locale) { 10 | await sendEmotion({ 11 | msg, 12 | locale, 13 | providers, 14 | emote: "smug", 15 | }); 16 | } 17 | 18 | module.exports = { 19 | name: "smug", 20 | execute: smug, 21 | alias: [], 22 | cooldown: 2, 23 | argsRequired: 0, 24 | module: "Emotes", 25 | isPrivate: false, 26 | nsfw: false, 27 | }; 28 | -------------------------------------------------------------------------------- /commands/emotes/blush.js: -------------------------------------------------------------------------------- 1 | const { sendEmotion } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const shirogg = require("../../api/shirogg"); 5 | const nekosbest = require("../../api/nekosbest"); 6 | 7 | const providers = [shirogg.blush, purrbotsite.blush, nekosbest.blush]; 8 | 9 | async function blush(msg, args, locale) { 10 | await sendEmotion({ 11 | msg, 12 | locale, 13 | providers, 14 | emote: "blush", 15 | }); 16 | } 17 | 18 | module.exports = { 19 | name: "blush", 20 | execute: blush, 21 | alias: [], 22 | cooldown: 2, 23 | argsRequired: 0, 24 | module: "Emotes", 25 | isPrivate: false, 26 | nsfw: false, 27 | }; 28 | -------------------------------------------------------------------------------- /events/guildChecker.js: -------------------------------------------------------------------------------- 1 | async function guildChange(guild) { 2 | if (guild.memberCount === 2) { 3 | await guild.channels.cache 4 | .find( 5 | (channel) => 6 | channel.isText() && 7 | channel.permissionsFor(guild.me).has("SEND_MESSAGES") 8 | ) 9 | ?.send( 10 | "Hello, if you want to test me, join my support server! https://discord.gg/Hr6Z9nNE2d" 11 | ); 12 | guild.leave(); 13 | } 14 | } 15 | 16 | function load(client) { 17 | client.on("guildCreate", guildChange); 18 | } 19 | 20 | function unload(client) { 21 | client.off("guildCreate", guildChange); 22 | } 23 | 24 | module.exports = { 25 | name: "guildChecker", 26 | load, 27 | unload, 28 | }; 29 | -------------------------------------------------------------------------------- /commands/actions/bite.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const nekosbest = require("../../api/nekosbest"); 5 | 6 | const providers = [purrbotsite.bite, nekosbest.bite]; 7 | 8 | async function bite(msg, args, locale) { 9 | await sendAction({ 10 | msg, 11 | args, 12 | locale, 13 | providers, 14 | nsfw: false, 15 | meSelfEmbed: true, 16 | userSelfEmbed: true, 17 | action: "bite", 18 | }); 19 | } 20 | 21 | module.exports = { 22 | name: "bite", 23 | execute: bite, 24 | alias: [], 25 | cooldown: 2, 26 | argsRequired: 0, 27 | module: "Actions", 28 | isPrivate: false, 29 | nsfw: false, 30 | }; 31 | -------------------------------------------------------------------------------- /commands/misc/invite.js: -------------------------------------------------------------------------------- 1 | const translate = require("../../helpers/locale"); 2 | 3 | const { bot: botInvite, server: serverInvite } = require("../../invites.json"); 4 | const { embedInvisible } = require("../../colors.json"); 5 | 6 | async function invite(msg, args, locale) { 7 | await msg.channel.send({ 8 | embeds: [ 9 | { 10 | description: translate("invite.links", locale, { 11 | serverInvite, 12 | botInvite, 13 | }), 14 | color: embedInvisible, 15 | }, 16 | ], 17 | }); 18 | } 19 | 20 | module.exports = { 21 | name: "invite", 22 | execute: invite, 23 | alias: [], 24 | cooldown: 1, 25 | argsRequired: 0, 26 | module: "Misc", 27 | isPrivate: false, 28 | }; 29 | -------------------------------------------------------------------------------- /commands/nsfwActions/spank.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const nekosfun = require("../../api/nekosfun"); 4 | const nekoslife = require("../../api/nekoslife"); 5 | 6 | const providers = [nekosfun.spank, nekoslife.spank]; 7 | 8 | async function spank(msg, args, locale) { 9 | await sendAction({ 10 | msg, 11 | args, 12 | locale, 13 | providers, 14 | nsfw: true, 15 | meSelfEmbed: false, 16 | userSelfEmbed: false, 17 | action: "spank", 18 | }); 19 | } 20 | 21 | module.exports = { 22 | name: "spank", 23 | execute: spank, 24 | alias: [], 25 | cooldown: 2, 26 | argsRequired: 0, 27 | module: "Actions NSFW", 28 | isPrivate: false, 29 | nsfw: true, 30 | }; 31 | -------------------------------------------------------------------------------- /commands/misc/ping.js: -------------------------------------------------------------------------------- 1 | const translate = require("../../helpers/locale"); 2 | 3 | async function ping(msg, args, locale) { 4 | const loopbackMessage = await msg.channel.send( 5 | translate("ping.pinging", locale) 6 | ); 7 | 8 | await loopbackMessage.edit({ 9 | embeds: [ 10 | { 11 | description: translate("ping.pong", locale, { 12 | ws: msg.client.ws.ping, 13 | loopback: loopbackMessage.createdTimestamp - msg.createdTimestamp, 14 | }), 15 | color: 0x00ff00, 16 | }, 17 | ], 18 | }); 19 | } 20 | 21 | module.exports = { 22 | name: "ping", 23 | execute: ping, 24 | alias: [], 25 | cooldown: 5, 26 | argsRequired: 0, 27 | module: "Misc", 28 | isPrivate: false, 29 | }; 30 | -------------------------------------------------------------------------------- /commands/misc/vote.js: -------------------------------------------------------------------------------- 1 | const translate = require("../../helpers/locale"); 2 | 3 | async function vote(msg, args, locale) { 4 | await msg.channel.send({ 5 | content: translate("vote.request", locale), 6 | components: [ 7 | { 8 | type: "ACTION_ROW", 9 | components: [ 10 | { 11 | type: "BUTTON", 12 | label: translate("vote.discord-ly", locale), 13 | style: 5, 14 | url: "https://discord.ly/shiro-chan", 15 | }, 16 | ], 17 | }, 18 | ], 19 | }); 20 | } 21 | 22 | module.exports = { 23 | name: "vote", 24 | execute: vote, 25 | alias: [], 26 | cooldown: 2, 27 | argsRequired: 0, 28 | module: "Misc", 29 | isPrivate: false, 30 | }; 31 | -------------------------------------------------------------------------------- /commands/nsfwActions/fuck.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const nekoslife = require("../../api/nekoslife"); 5 | 6 | const providers = [purrbotsite.fuck, nekoslife.classic]; 7 | 8 | async function fuck(msg, args, locale) { 9 | await sendAction({ 10 | msg, 11 | args, 12 | locale, 13 | providers, 14 | nsfw: true, 15 | meSelfEmbed: false, 16 | userSelfEmbed: false, 17 | action: "fuck", 18 | }); 19 | } 20 | 21 | module.exports = { 22 | name: "fuck", 23 | execute: fuck, 24 | alias: [], 25 | cooldown: 2, 26 | argsRequired: 0, 27 | module: "Actions NSFW", 28 | isPrivate: false, 29 | nsfw: true, 30 | }; 31 | -------------------------------------------------------------------------------- /commands/nsfwActions/kuni.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const nekoslife = require("../../api/nekoslife"); 5 | 6 | const providers = [purrbotsite.pussylick, nekoslife.kuni]; 7 | 8 | async function kuni(msg, args, locale) { 9 | await sendAction({ 10 | msg, 11 | args, 12 | locale, 13 | providers, 14 | nsfw: true, 15 | meSelfEmbed: false, 16 | userSelfEmbed: false, 17 | action: "kuni", 18 | }); 19 | } 20 | 21 | module.exports = { 22 | name: "kuni", 23 | execute: kuni, 24 | alias: [], 25 | cooldown: 2, 26 | argsRequired: 0, 27 | module: "Actions NSFW", 28 | isPrivate: false, 29 | nsfw: true, 30 | }; 31 | -------------------------------------------------------------------------------- /helpers/recursiveReader.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | const path = require("path"); 3 | 4 | const recursiveRead = async (dir) => { 5 | let results = []; 6 | const list = await fs.readdir(dir); 7 | let pending = list.length; 8 | if (!pending) return results; 9 | 10 | for (const fileName of list) { 11 | const file = path.resolve(dir, fileName); 12 | const stat = await fs.stat(file); 13 | if (stat && stat.isDirectory()) { 14 | await recursiveRead(file).then((res) => { 15 | results = results.concat(res); 16 | }); 17 | if (!--pending) return results; 18 | } else { 19 | results.push(file); 20 | if (!--pending) return results; 21 | } 22 | } 23 | }; 24 | 25 | module.exports = recursiveRead; 26 | -------------------------------------------------------------------------------- /commands/actions/lick.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const shirogg = require("../../api/shirogg"); 5 | const nekosfun = require("../../api/nekosfun"); 6 | 7 | const providers = [purrbotsite.lick, shirogg.lick, nekosfun.lick]; 8 | 9 | async function lick(msg, args, locale) { 10 | await sendAction({ 11 | msg, 12 | args, 13 | locale, 14 | providers, 15 | nsfw: false, 16 | meSelfEmbed: true, 17 | userSelfEmbed: true, 18 | action: "lick", 19 | }); 20 | } 21 | 22 | module.exports = { 23 | name: "lick", 24 | execute: lick, 25 | alias: [], 26 | cooldown: 2, 27 | argsRequired: 0, 28 | module: "Actions", 29 | isPrivate: false, 30 | nsfw: false, 31 | }; 32 | -------------------------------------------------------------------------------- /commands/nsfwActions/cum.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const nekoslife = require("../../api/nekoslife"); 5 | const nekosfun = require("../../api/nekosfun"); 6 | 7 | const providers = [purrbotsite.cum, nekoslife.cum, nekosfun.cum]; 8 | 9 | async function cum(msg, args, locale) { 10 | await sendAction({ 11 | msg, 12 | args, 13 | locale, 14 | providers, 15 | nsfw: true, 16 | meSelfEmbed: false, 17 | userSelfEmbed: false, 18 | action: "cum", 19 | }); 20 | } 21 | 22 | module.exports = { 23 | name: "cum", 24 | execute: cum, 25 | alias: [], 26 | cooldown: 2, 27 | argsRequired: 0, 28 | module: "Actions NSFW", 29 | isPrivate: false, 30 | nsfw: true, 31 | }; 32 | -------------------------------------------------------------------------------- /api/nekosfun.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios").default; 2 | const apiBase = axios.create({ 3 | baseURL: "http://api.nekos.fun:8080/api/", 4 | transformResponse: [ 5 | (data) => { 6 | const url = JSON.parse(data).image; 7 | return url.endsWith(".gif") ? url : ""; 8 | }, 9 | ], 10 | }); 11 | const buildRouter = require("./routerBuilder"); 12 | 13 | const routes = { 14 | cry: "cry", 15 | cuddle: "cuddle", 16 | feed: "feed", 17 | hug: "hug", 18 | kiss: "kiss", 19 | laugh: "laugh", 20 | lick: "lick", 21 | pat: "pat", 22 | poke: "poke", 23 | slap: "slap", 24 | smug: "smug", 25 | tickle: "tickle", 26 | 27 | anal: "anal", 28 | cum: "cum", 29 | bj: "bj", 30 | blowjob: "blowjob", 31 | spank: "spank", 32 | }; 33 | 34 | module.exports = buildRouter(apiBase, routes); 35 | -------------------------------------------------------------------------------- /commands/nsfwActions/anal.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const nekoslife = require("../../api/nekoslife"); 5 | const nekosfun = require("../../api/nekosfun"); 6 | 7 | const providers = [purrbotsite.anal, nekoslife.anal, nekosfun.anal]; 8 | 9 | async function anal(msg, args, locale) { 10 | await sendAction({ 11 | msg, 12 | args, 13 | locale, 14 | providers, 15 | nsfw: true, 16 | meSelfEmbed: false, 17 | userSelfEmbed: false, 18 | action: "anal", 19 | }); 20 | } 21 | 22 | module.exports = { 23 | name: "anal", 24 | execute: anal, 25 | alias: [], 26 | cooldown: 2, 27 | argsRequired: 0, 28 | module: "Actions NSFW", 29 | isPrivate: false, 30 | nsfw: true, 31 | }; 32 | -------------------------------------------------------------------------------- /api/purrbotsite.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios").default; 2 | const apiBase = axios.create({ 3 | baseURL: "https://purrbot.site/api/img/", 4 | transformResponse: [(data) => JSON.parse(data).link], 5 | }); 6 | const buildRouter = require("./routerBuilder"); 7 | 8 | const routes = { 9 | bite: "sfw/bite", 10 | blush: "sfw/blush", 11 | cry: "sfw/cry", 12 | cuddle: "sfw/cuddle", 13 | dance: "sfw/dance", 14 | feed: "sfw/feed", 15 | hug: "sfw/hug", 16 | kiss: "sfw/kiss", 17 | lick: "sfw/lick", 18 | pat: "sfw/pat", 19 | poke: "sfw/poke", 20 | slap: "sfw/slap", 21 | smile: "sfw/smile", 22 | tickle: "sfw/tickle", 23 | 24 | anal: "nsfw/anal", 25 | blowjob: "nsfw/blowjob", 26 | cum: "nsfw/cum", 27 | fuck: "nsfw/fuck", 28 | pussylick: "nsfw/pussylick", 29 | }; 30 | 31 | module.exports = buildRouter(apiBase, routes, "/gif"); 32 | -------------------------------------------------------------------------------- /commands/actions/feed.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const nekosbest = require("../../api/nekosbest"); 4 | const nekoslife = require("../../api/nekoslife"); 5 | const nekosfun = require("../../api/nekosfun"); 6 | const purrbot = require("../../api/purrbotsite"); 7 | 8 | const providers = [nekosbest.feed, nekoslife.feed, nekosfun.feed, purrbot.feed]; 9 | 10 | async function feed(msg, args, locale) { 11 | await sendAction({ 12 | msg, 13 | args, 14 | locale, 15 | providers, 16 | nsfw: false, 17 | meSelfEmbed: true, 18 | userSelfEmbed: true, 19 | action: "feed", 20 | }); 21 | } 22 | 23 | module.exports = { 24 | name: "feed", 25 | execute: feed, 26 | alias: [], 27 | cooldown: 2, 28 | argsRequired: 0, 29 | module: "Actions", 30 | isPrivate: false, 31 | nsfw: false, 32 | }; 33 | -------------------------------------------------------------------------------- /botlistapi/BasePoster.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require("axios"); 2 | 3 | class BasePoster { 4 | constructor(options) { 5 | this.token = options.token; 6 | this.id = options.id; 7 | this.availableQueries = Infinity; 8 | 9 | if (options.ratelimit && options.availableQueries) { 10 | this.availableQueries = options.availableQueries; 11 | setInterval( 12 | () => (this.availableQueries = options.availableQueries), 13 | options.ratelimit 14 | ); 15 | } 16 | } 17 | 18 | async post(body, headers, url) { 19 | if (!this.availableQueries > 0) return; 20 | 21 | try { 22 | await axios.post(url, body, { headers }); 23 | this.availableQueries -= 1; 24 | } catch (e) { 25 | console.error(`Failed to post to "${url}"`, e.response?.data); 26 | } 27 | } 28 | } 29 | 30 | module.exports = BasePoster; 31 | -------------------------------------------------------------------------------- /commands/fun/random.js: -------------------------------------------------------------------------------- 1 | const { random } = require("../../helpers/random"); 2 | const { invalidUsage } = require("../../helpers/templateMessages"); 3 | const translate = require("../../helpers/locale"); 4 | 5 | async function randomExecute(msg, args, locale) { 6 | const min = parseInt(args[0]); 7 | const max = parseInt(args[1]); 8 | if (isNaN(min) || isNaN(max)) { 9 | await invalidUsage(msg.channel, this.name, locale); 10 | return; 11 | } 12 | 13 | await msg.reply({ 14 | content: translate("random.result", locale, { 15 | number: random(min, max), 16 | }), 17 | allowedMentions: { 18 | repliedUser: false, 19 | }, 20 | }); 21 | } 22 | 23 | module.exports = { 24 | name: "random", 25 | execute: randomExecute, 26 | alias: [], 27 | cooldown: 1, 28 | argsRequired: 0, 29 | module: "Fun", 30 | isPrivate: false, 31 | subCommands: [], 32 | }; 33 | -------------------------------------------------------------------------------- /commands/nsfwActions/blowjob.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const nekoslife = require("../../api/nekoslife"); 5 | const nekosfun = require("../../api/nekosfun"); 6 | 7 | const providers = [ 8 | purrbotsite.blowjob, 9 | nekoslife.bj, 10 | nekosfun.bj, 11 | nekoslife.blowjob, 12 | nekosfun.blowjob, 13 | ]; 14 | 15 | async function blowjob(msg, args, locale) { 16 | await sendAction({ 17 | msg, 18 | args, 19 | locale, 20 | providers, 21 | nsfw: true, 22 | meSelfEmbed: false, 23 | userSelfEmbed: false, 24 | action: "blowjob", 25 | }); 26 | } 27 | 28 | module.exports = { 29 | name: "blowjob", 30 | execute: blowjob, 31 | alias: ["bj"], 32 | cooldown: 2, 33 | argsRequired: 0, 34 | module: "Actions NSFW", 35 | isPrivate: false, 36 | nsfw: true, 37 | }; 38 | -------------------------------------------------------------------------------- /commands/misc/donate.js: -------------------------------------------------------------------------------- 1 | const translate = require("../../helpers/locale"); 2 | 3 | async function donate(msg, args, locale) { 4 | await msg.channel.send({ 5 | content: `**${translate("donate.support", locale)}**`, 6 | components: [ 7 | { 8 | type: "ACTION_ROW", 9 | components: [ 10 | { 11 | type: "BUTTON", 12 | label: "Patreon", 13 | style: 5, 14 | url: "https://www.patreon.com/dmax_programmer", 15 | }, 16 | { 17 | type: "BUTTON", 18 | label: "Boosty", 19 | style: 5, 20 | url: "https://boosty.to/dmax", 21 | }, 22 | ], 23 | }, 24 | ], 25 | }); 26 | } 27 | 28 | module.exports = { 29 | name: "donate", 30 | execute: donate, 31 | alias: [], 32 | cooldown: 0, 33 | argsRequired: 0, 34 | module: "Misc", 35 | isPrivate: false, 36 | }; 37 | -------------------------------------------------------------------------------- /api/nekosbest.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios").default; 2 | const apiBase = axios.create({ 3 | baseURL: "https://nekos.best/api/v2/", 4 | transformResponse: [(data) => JSON.parse(data).results[0].url], 5 | }); 6 | const buildRouter = require("./routerBuilder"); 7 | 8 | const routes = { 9 | bite: "bite", 10 | blush: "blush", 11 | bored: "bored", 12 | cry: "cry", 13 | cuddle: "cuddle", 14 | dance: "dance", 15 | facepalm: "facepalm", 16 | feed: "feed", 17 | happy: "happy", 18 | highfive: "highfive", 19 | hug: "hug", 20 | kiss: "kiss", 21 | laugh: "laugh", 22 | pat: "pat", 23 | poke: "poke", 24 | pout: "pout", 25 | shrug: "shrug", 26 | slap: "slap", 27 | sleep: "sleep", 28 | smile: "smile", 29 | smug: "smug", 30 | stare: "stare", 31 | think: "think", 32 | thumbsup: "thumbsup", 33 | tickle: "tickle", 34 | wave: "wave", 35 | wink: "wink", 36 | }; 37 | 38 | module.exports = buildRouter(apiBase, routes, ""); 39 | -------------------------------------------------------------------------------- /commands/actions/kiss.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const shirogg = require("../../api/shirogg"); 5 | const nekoslife = require("../../api/nekoslife"); 6 | const nekosbest = require("../../api/nekosbest"); 7 | const nekosfun = require("../../api/nekosfun"); 8 | 9 | const providers = [ 10 | purrbotsite.kiss, 11 | shirogg.kiss, 12 | nekoslife.kiss, 13 | nekosbest.kiss, 14 | nekosfun.kiss, 15 | ]; 16 | 17 | async function kiss(msg, args, locale) { 18 | await sendAction({ 19 | msg, 20 | args, 21 | locale, 22 | providers, 23 | nsfw: false, 24 | meSelfEmbed: true, 25 | userSelfEmbed: false, 26 | action: "kiss", 27 | }); 28 | } 29 | 30 | module.exports = { 31 | name: "kiss", 32 | execute: kiss, 33 | alias: [], 34 | cooldown: 2, 35 | argsRequired: 0, 36 | module: "Actions", 37 | isPrivate: false, 38 | nsfw: false, 39 | }; 40 | -------------------------------------------------------------------------------- /commands/actions/poke.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const shirogg = require("../../api/shirogg"); 5 | const nekoslife = require("../../api/nekoslife"); 6 | const nekosbest = require("../../api/nekosbest"); 7 | const nekosfun = require("../../api/nekosfun"); 8 | 9 | const providers = [ 10 | purrbotsite.poke, 11 | shirogg.poke, 12 | nekoslife.poke, 13 | nekosbest.poke, 14 | nekosfun.poke, 15 | ]; 16 | 17 | async function poke(msg, args, locale) { 18 | await sendAction({ 19 | msg, 20 | args, 21 | locale, 22 | providers, 23 | nsfw: false, 24 | meSelfEmbed: true, 25 | userSelfEmbed: true, 26 | action: "poke", 27 | }); 28 | } 29 | 30 | module.exports = { 31 | name: "poke", 32 | execute: poke, 33 | alias: [], 34 | cooldown: 2, 35 | argsRequired: 0, 36 | module: "Actions", 37 | isPrivate: false, 38 | nsfw: false, 39 | }; 40 | -------------------------------------------------------------------------------- /commands/actions/slap.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const shirogg = require("../../api/shirogg"); 5 | const nekoslife = require("../../api/nekoslife"); 6 | const nekosbest = require("../../api/nekosbest"); 7 | const nekosfun = require("../../api/nekosfun"); 8 | 9 | const providers = [ 10 | purrbotsite.slap, 11 | shirogg.slap, 12 | nekoslife.slap, 13 | nekosbest.slap, 14 | nekosfun.slap, 15 | ]; 16 | 17 | async function slap(msg, args, locale) { 18 | await sendAction({ 19 | msg, 20 | args, 21 | locale, 22 | providers, 23 | nsfw: false, 24 | meSelfEmbed: true, 25 | userSelfEmbed: true, 26 | action: "slap", 27 | }); 28 | } 29 | 30 | module.exports = { 31 | name: "slap", 32 | execute: slap, 33 | alias: [], 34 | cooldown: 2, 35 | argsRequired: 0, 36 | module: "Actions", 37 | isPrivate: false, 38 | nsfw: false, 39 | }; 40 | -------------------------------------------------------------------------------- /commands/actions/tickle.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const shirogg = require("../../api/shirogg"); 5 | const nekoslife = require("../../api/nekoslife"); 6 | const nekosbest = require("../../api/nekosbest"); 7 | const nekosfun = require("../../api/nekosfun"); 8 | 9 | const providers = [ 10 | purrbotsite.tickle, 11 | shirogg.tickle, 12 | nekoslife.tickle, 13 | nekosbest.tickle, 14 | nekosfun.tickle, 15 | ]; 16 | 17 | async function tickle(msg, args, locale) { 18 | await sendAction({ 19 | msg, 20 | args, 21 | locale, 22 | providers, 23 | nsfw: false, 24 | meSelfEmbed: true, 25 | userSelfEmbed: true, 26 | action: "tickle", 27 | }); 28 | } 29 | 30 | module.exports = { 31 | name: "tickle", 32 | execute: tickle, 33 | alias: [], 34 | cooldown: 2, 35 | argsRequired: 0, 36 | module: "Actions", 37 | isPrivate: false, 38 | nsfw: false, 39 | }; 40 | -------------------------------------------------------------------------------- /commands/actions/pat.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const shirogg = require("../../api/shirogg"); 5 | const nekoslife = require("../../api/nekoslife"); 6 | const nekosbest = require("../../api/nekosbest"); 7 | const nekosfun = require("../../api/nekosfun"); 8 | const sra = require("../../api/somerandomapiml"); 9 | 10 | const providers = [ 11 | purrbotsite.pat, 12 | shirogg.pat, 13 | nekoslife.pat, 14 | nekosbest.pat, 15 | nekosfun.pat, 16 | sra.pat, 17 | ]; 18 | 19 | async function pat(msg, args, locale) { 20 | await sendAction({ 21 | msg, 22 | args, 23 | locale, 24 | providers, 25 | nsfw: false, 26 | meSelfEmbed: true, 27 | userSelfEmbed: true, 28 | action: "pat", 29 | }); 30 | } 31 | 32 | module.exports = { 33 | name: "pat", 34 | execute: pat, 35 | alias: [], 36 | cooldown: 2, 37 | argsRequired: 0, 38 | module: "Actions", 39 | isPrivate: false, 40 | nsfw: false, 41 | }; 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 DMax 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /commands/actions/hug.js: -------------------------------------------------------------------------------- 1 | const { sendAction } = require("../../helpers/roleplayMessages"); 2 | 3 | const purrbotsite = require("../../api/purrbotsite"); 4 | const shirogg = require("../../api/shirogg"); 5 | const nekoslife = require("../../api/nekoslife"); 6 | const nekosbest = require("../../api/nekosbest"); 7 | const nekosfun = require("../../api/nekosfun"); 8 | const sra = require("../../api/somerandomapiml"); 9 | 10 | const providers = [ 11 | purrbotsite.hug, 12 | purrbotsite.cuddle, 13 | shirogg.hug, 14 | nekoslife.hug, 15 | nekoslife.cuddle, 16 | nekosbest.hug, 17 | nekosbest.cuddle, 18 | nekosfun.hug, 19 | nekosfun.cuddle, 20 | sra.hug, 21 | ]; 22 | 23 | async function hug(msg, args, locale) { 24 | await sendAction({ 25 | msg, 26 | args, 27 | locale, 28 | providers, 29 | nsfw: false, 30 | meSelfEmbed: true, 31 | userSelfEmbed: true, 32 | action: "hug", 33 | }); 34 | } 35 | 36 | module.exports = { 37 | name: "hug", 38 | execute: hug, 39 | alias: ["cuddle"], 40 | cooldown: 2, 41 | argsRequired: 0, 42 | module: "Actions", 43 | isPrivate: false, 44 | nsfw: false, 45 | }; 46 | -------------------------------------------------------------------------------- /events/pingListener.js: -------------------------------------------------------------------------------- 1 | const translate = require("../helpers/locale"); 2 | const { server: serverInvite } = require("../invites.json"); 3 | 4 | let mentions = []; 5 | 6 | async function messageHandler(msg) { 7 | if (!msg.guild?.available || msg.author.bot || msg.webhookID) return; 8 | const { 9 | client: { 10 | config: { prefix }, 11 | server, 12 | }, 13 | } = msg; 14 | 15 | const { locale, prefix: serverPrefix } = server.ensure(msg.guild.id, { 16 | locale: "en-US", 17 | prefix, 18 | }); 19 | 20 | if (!mentions.length) { 21 | mentions.push(`<@${msg.client.user.id}>`, `<@!${msg.client.user.id}>`); 22 | } 23 | 24 | if (!mentions.includes(msg.content)) return; 25 | 26 | msg.channel.send( 27 | translate("hello", locale, { 28 | prefix: serverPrefix, 29 | me: msg.guild.me, 30 | serverInvite, 31 | }) 32 | ); 33 | } 34 | 35 | function load(client) { 36 | client.on("messageCreate", messageHandler); 37 | } 38 | 39 | function unload(client) { 40 | client.off("messageCreate", messageHandler); 41 | } 42 | 43 | module.exports = { 44 | name: "pingListener", 45 | load, 46 | unload, 47 | }; 48 | -------------------------------------------------------------------------------- /commands/serverCommands/prefix.js: -------------------------------------------------------------------------------- 1 | const { error, success } = require("../../helpers/templateMessages"); 2 | const translate = require("../../helpers/locale"); 3 | 4 | async function prefix(msg, args, locale) { 5 | const newPrefix = args.join(" "); 6 | 7 | if (!newPrefix) { 8 | await msg.channel.send( 9 | translate("prefix.current", locale, { 10 | prefix: msg.client.server.get(msg.guild.id, "prefix"), 11 | }) 12 | ); 13 | return; 14 | } 15 | 16 | if (!msg.member.permissions.has(["MANAGE_GUILD"])) { 17 | await error(msg.channel, translate("permsError", locale), locale); 18 | return; 19 | } 20 | 21 | if (newPrefix.length > 5) { 22 | await error(msg.channel, translate("prefix.tooLong", locale), locale); 23 | return; 24 | } 25 | 26 | msg.client.server.set(msg.guild.id, newPrefix, "prefix"); 27 | await success( 28 | msg.channel, 29 | translate("prefix.change", locale, { 30 | prefix: newPrefix, 31 | }), 32 | locale 33 | ); 34 | } 35 | 36 | module.exports = { 37 | name: "prefix", 38 | execute: prefix, 39 | alias: [], 40 | cooldown: 2, 41 | argsRequired: 0, 42 | module: "Server", 43 | isPrivate: false, 44 | }; 45 | -------------------------------------------------------------------------------- /helpers/templateMessages.js: -------------------------------------------------------------------------------- 1 | const { prefix } = require("../config.json"); 2 | const translate = require("./locale"); 3 | 4 | const error = (channel, content, locale) => 5 | channel.send({ 6 | embeds: [ 7 | { 8 | author: { 9 | name: translate("error", locale), 10 | }, 11 | description: content, 12 | color: 0xd24a43, 13 | }, 14 | ], 15 | }); 16 | 17 | const invalidUsage = async (channel, commandName, locale) => 18 | channel.send({ 19 | embeds: [ 20 | { 21 | author: { 22 | name: translate("invalidUsage", locale), 23 | }, 24 | description: translate(`${commandName}.usage`, locale) 25 | .map((usage) => prefix + commandName + " " + usage) 26 | .join("\n"), 27 | color: 0xd24a43, 28 | }, 29 | ], 30 | }); 31 | 32 | const success = (channel, content, locale) => 33 | channel.send({ 34 | embeds: [ 35 | { 36 | author: { 37 | name: translate("success", locale), 38 | }, 39 | description: content, 40 | color: 0x99c45a, 41 | }, 42 | ], 43 | }); 44 | 45 | module.exports = { 46 | error, 47 | success, 48 | invalidUsage, 49 | }; 50 | -------------------------------------------------------------------------------- /commands/fun/try.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require("discord.js"); 2 | const { invalidUsage } = require("../../helpers/templateMessages"); 3 | 4 | const sleep = require("../../helpers/sleep"); 5 | const translate = require("../../helpers/locale"); 6 | const { random, randomFloat } = require("../../helpers/random"); 7 | 8 | const { embedInvisible } = require("../../colors.json"); 9 | 10 | async function tryCommand(msg, args, locale) { 11 | if (!args.length) { 12 | await invalidUsage(msg.channel, this.name, locale); 13 | return; 14 | } 15 | 16 | const action = args.join(" "); 17 | const tryEmbed = new MessageEmbed({ 18 | description: translate("try.action", locale, { 19 | caller: msg.member, 20 | action, 21 | }), 22 | color: embedInvisible, 23 | }); 24 | 25 | const tryMessage = await msg.reply({ 26 | embeds: [tryEmbed], 27 | allowedMentions: { 28 | repliedUser: false, 29 | }, 30 | }); 31 | 32 | await sleep(randomFloat(0.5, 1.5) * 1000); 33 | const success = random(0, 100) >= 50 ? true : false; 34 | 35 | if (success) { 36 | tryEmbed 37 | .setAuthor({ 38 | name: translate("try.success", locale), 39 | }) 40 | .setColor("DARK_GREEN"); 41 | } else { 42 | tryEmbed 43 | .setAuthor({ 44 | name: translate("try.failure", locale), 45 | }) 46 | .setColor("DARK_RED"); 47 | } 48 | 49 | await tryMessage.edit({ 50 | embeds: [tryEmbed], 51 | }); 52 | } 53 | 54 | module.exports = { 55 | name: "try", 56 | execute: tryCommand, 57 | alias: [], 58 | cooldown: 2, 59 | argsRequired: 1, 60 | module: "Fun", 61 | isPrivate: false, 62 | nsfw: false, 63 | }; 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shiro Chan 2 | 3 | This is a roleplay bot for discord. It is created for roleplay servers, that needs some gifs to make RP easier; "turn off" your imagination for a second. 4 | 5 | ## THIS REPOSITORY IS ARCHIVED, BOT IS OFFLINE (forever). MAYBE IN FUTURE I WILL MAKE SUCH BOT WITH C# 6 | This code is not bad and can be easily extended. *Fork it* if you want 7 | 8 | ## Useful links 9 | 10 | [Invite bot](https://discord.com/oauth2/authorize?client_id=793544441863471134&permissions=321608&scope=bot%20applications.commands) | [Join support server](https://discord.gg/Hr6Z9nNE2d) 11 | 12 | ## Features 13 | 14 | This bot has next features: 15 | 16 | - Multilanguage 17 | - Customizable prefix 18 | - Many roleplay commands 19 | 20 | Hope that bot will have more needing features. 21 | 22 | ## Commands 23 | 24 | You can check them with with `./help` 25 | 26 | ![Help menu command](https://dmax.discowd.com/r/kpml1gdbe9a.png) 27 | 28 | ## Multilanguage 29 | 30 | Current supported languages: 31 | 32 | ![Supported languages](https://dmax.discowd.com/r/kpml1oep49a.png) 33 | 34 | You can become a bot translator by contributing this repository. 35 | 36 | ## More info 37 | 38 | If you have any ideas or you want to contribute this bot, join my [support server](https://discord.gg/Hr6Z9nNE2d). Also you can become my patron [here](https://patreon.com/dmax_programmer). 39 | 40 | ## How can I contribute? 41 | 42 | You can contribute project to add some cool features to the bot or create a translation for new language. 43 | 44 | All you need to do this is just: 45 | 46 | 1. Fork the repository 47 | 2. Clone your fork: `git clone https://github.com/your-username/roleplay-bot.git` 48 | 3. Create your feature branch: `git checkout -b my-new-feature` 49 | 4. Commit your changes: `git commit -am 'uwu new feature'` 50 | 5. Push to the branch: `git push origin my-new-feature` 51 | 6. Submit a pull request 52 | -------------------------------------------------------------------------------- /events/ownerCommandsHandler.js: -------------------------------------------------------------------------------- 1 | const getSubCommand = (command, [commandName, ...args]) => { 2 | if (!command.subCommands?.length) 3 | return { 4 | command, 5 | args: [commandName, ...args], 6 | }; 7 | const commandNamelowerCase = commandName.toLowerCase(); 8 | const subCommand = command.subCommands.find( 9 | (command) => 10 | command.name === commandNamelowerCase || 11 | command.alias?.includes(commandNamelowerCase) 12 | ); 13 | if (!subCommand) 14 | return { 15 | command, 16 | args: [commandName, ...args], 17 | }; 18 | return { 19 | ...getSubCommand(subCommand, args), 20 | }; 21 | }; 22 | 23 | async function messageHandler(msg) { 24 | if (!msg.guild?.available || msg.author.bot) return; 25 | const { 26 | client: { 27 | config: { prefix, owners }, 28 | ownerCommands, 29 | }, 30 | } = msg; 31 | 32 | if (!owners.includes(msg.author.id)) return; 33 | if (!msg.content.startsWith(prefix) || msg.webhookID) return; 34 | 35 | let args = msg.content.slice(prefix.length).split(/ +/); 36 | const cmd = args.shift().toLowerCase(); 37 | 38 | let command = 39 | ownerCommands.get(cmd) || 40 | ownerCommands.find((command) => command.alias?.includes(cmd)); 41 | 42 | if (!command) return; 43 | 44 | if (args.length) { 45 | const subCommand = getSubCommand(command, args); 46 | command = subCommand.command; 47 | args = subCommand.args; 48 | } 49 | 50 | try { 51 | const executed = command.execute(msg, args); 52 | if (executed instanceof Promise) await executed; 53 | } catch (e) { 54 | console.error(e); 55 | msg.channel.send("Something went wrong"); 56 | } 57 | } 58 | 59 | function load(client) { 60 | client.on("messageCreate", messageHandler); 61 | } 62 | 63 | function unload(client) { 64 | client.off("messageCreate", messageHandler); 65 | } 66 | 67 | module.exports = { 68 | name: "commandsHandler", 69 | load, 70 | unload, 71 | }; 72 | -------------------------------------------------------------------------------- /commands/serverCommands/locale.js: -------------------------------------------------------------------------------- 1 | const { error, success } = require("../../helpers/templateMessages"); 2 | const translate = require("../../helpers/locale"); 3 | 4 | const { botOfficial } = require("../../colors.json"); 5 | 6 | const locales = { 7 | "en-US": "🇺🇸 American English", 8 | "ru-RU": "🇷🇺 Russian", 9 | }; 10 | 11 | async function showLocales(msg, args, locale) { 12 | await msg.channel.send({ 13 | embeds: [ 14 | { 15 | fields: [ 16 | { 17 | name: translate("locale.id", locale), 18 | value: Object.keys(locales).join("\n"), 19 | inline: true, 20 | }, 21 | { 22 | name: translate("locale.name", locale), 23 | value: Object.values(locales).join("\n"), 24 | inline: true, 25 | }, 26 | ], 27 | color: botOfficial, 28 | }, 29 | ], 30 | }); 31 | } 32 | 33 | async function localeExecute(msg, args, locale) { 34 | if (!args.length) { 35 | await msg.channel.send( 36 | translate("locale.current", locale, { 37 | locale: locales[locale], 38 | }) 39 | ); 40 | return; 41 | } 42 | 43 | if (!msg.member.permissions.has(["MANAGE_GUILD"])) { 44 | await error(msg.channel, translate("permsError", locale), locale); 45 | return; 46 | } 47 | 48 | const [newLocale] = args; 49 | if (!Object.keys(locales).includes(newLocale)) { 50 | await error(msg.channel, translate("locale.unknown", locale), locale); 51 | return; 52 | } 53 | 54 | msg.client.server.set(msg.guild.id, newLocale, "locale"); 55 | await success( 56 | msg.channel, 57 | translate("locale.change", newLocale, { 58 | locale: locales[newLocale], 59 | }), 60 | newLocale 61 | ); 62 | } 63 | 64 | module.exports = { 65 | name: "locale", 66 | execute: localeExecute, 67 | alias: [], 68 | cooldown: 2, 69 | argsRequired: 0, 70 | module: "Server", 71 | isPrivate: false, 72 | subCommands: [ 73 | { 74 | name: "show", 75 | execute: showLocales, 76 | alais: [], 77 | cooldown: 2, 78 | isPrivate: false, 79 | }, 80 | ], 81 | }; 82 | -------------------------------------------------------------------------------- /commands/fun/dice.js: -------------------------------------------------------------------------------- 1 | const sleep = require("../../helpers/sleep"); 2 | const { error } = require("../../helpers/templateMessages"); 3 | const { random, randomFloat } = require("../../helpers/random"); 4 | const translate = require("../../helpers/locale"); 5 | 6 | const randomDice = ""; 7 | const numToDice = [ 8 | "<:dice_1:812756441118408714>", 9 | "<:dice_2:812756441219596338>", 10 | "<:dice_3:812756441160745010>", 11 | "<:dice_4:812756441147637761>", 12 | "<:dice_5:812756441089572866>", 13 | "<:dice_6:812756441366659153>", 14 | ]; 15 | 16 | const minTime = 0.25; 17 | const maxTime = 1.5; 18 | 19 | async function dice(msg, args, locale) { 20 | const rollsCount = parseInt(args[0]); 21 | 22 | if (!rollsCount) { 23 | const rolling = await msg.reply({ 24 | content: randomDice, 25 | allowedMentions: { 26 | repliedUser: false, 27 | }, 28 | }); 29 | 30 | await sleep(randomFloat(minTime, maxTime) * 1000); 31 | await rolling.edit(numToDice[random(0, 5)]); 32 | 33 | return; 34 | } 35 | 36 | if (rollsCount >= 10) { 37 | await error(msg.channel, translate("dice.maxDicesError", locale), locale); 38 | return; 39 | } 40 | 41 | let allDices = [...Array(rollsCount)].map(() => randomDice); 42 | const rolling = await msg.reply({ 43 | content: allDices.join(""), 44 | allowedMentions: { 45 | repliedUser: false, 46 | }, 47 | }); 48 | 49 | for (const id of allDices.keys()) { 50 | await sleep(randomFloat(minTime, maxTime) * 1000); 51 | allDices[id] = random(0, 5); 52 | 53 | await rolling.edit( 54 | allDices.map((v) => numToDice[v] || randomDice).join("") 55 | ); 56 | } 57 | 58 | await msg.reply({ 59 | content: translate("dice.rolled", locale, { 60 | user: msg.member, 61 | sum: allDices.reduce((v, a) => v + a, rollsCount), 62 | }), 63 | allowedMentions: { 64 | parse: [], 65 | repliedUser: false, 66 | }, 67 | }); 68 | } 69 | 70 | module.exports = { 71 | name: "dice", 72 | execute: dice, 73 | alias: [], 74 | cooldown: 2, 75 | argsRequired: 0, 76 | module: "Fun", 77 | isPrivate: false, 78 | subCommands: [], 79 | }; 80 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # Config and token files 107 | config.json 108 | tokens.json 109 | 110 | # Lock files 111 | yarn.lock 112 | package-lock.json 113 | 114 | # Direcotry with SQLite 115 | db/ -------------------------------------------------------------------------------- /ownerCommands/eval.js: -------------------------------------------------------------------------------- 1 | const util = require("util"); 2 | 3 | const maxSymbols = 2039; 4 | const green = 0x00ff00; 5 | const red = 0xff0000; 6 | 7 | async function evalExecute(msg, args) { 8 | const code = args.join(" ").replace(/```(js)?/gim, ""); 9 | if (!code) return; 10 | 11 | const { client } = msg; 12 | const start = Date.now(); 13 | try { 14 | let evaled = eval(code); 15 | if (evaled instanceof Promise) evaled = await evaled; 16 | if (typeof evaled !== "string") evaled = util.inspect(evaled, { depth: 0 }); 17 | if (evaled.includes(msg.client.token)) return; 18 | 19 | const hasFiels = evaled.length > maxSymbols; 20 | const files = hasFiels 21 | ? [ 22 | { 23 | name: "result.txt", 24 | attachment: Buffer.from(evaled, "utf-8"), 25 | }, 26 | ] 27 | : []; 28 | 29 | msg.channel.send({ 30 | embeds: [ 31 | { 32 | title: "✅ Successfully evaluated", 33 | description: hasFiels ? "" : `\`\`\`xl\n${evaled}\`\`\``, 34 | footer: { 35 | text: `Took ${Date.now() - start} ms to eval`, 36 | }, 37 | color: green, 38 | }, 39 | ], 40 | files, 41 | }); 42 | } catch (e) { 43 | if (!e) { 44 | msg.channel.send({ 45 | embeds: [ 46 | { 47 | title: "❌ Something went wrong", 48 | footer: { 49 | text: `Took ${Date.now() - start} ms to eval`, 50 | }, 51 | color: red, 52 | }, 53 | ], 54 | }); 55 | return; 56 | } 57 | const errorResult = e.stack; 58 | if (errorResult.includes(msg.client.token)) return; 59 | 60 | const hasFiels = errorResult > maxSymbols; 61 | const files = hasFiels 62 | ? [ 63 | { 64 | name: "error.txt", 65 | attachment: Buffer.from(errorResult, "utf-8"), 66 | }, 67 | ] 68 | : []; 69 | 70 | msg.channel.send({ 71 | embeds: [ 72 | { 73 | title: "❌ Something went wrong", 74 | description: hasFiels ? "" : `\`\`\`xl\n${errorResult}\`\`\``, 75 | footer: { 76 | text: `Took ${Date.now() - start} ms to eval`, 77 | }, 78 | color: red, 79 | }, 80 | ], 81 | files, 82 | }); 83 | } 84 | } 85 | 86 | module.exports = { 87 | name: "eval", 88 | execute: evalExecute, 89 | alias: [], 90 | subCommands: [], 91 | }; 92 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { ShardingManager } = require("discord.js"); 2 | const { token, beta } = require("./config.json"); 3 | const manager = new ShardingManager("./bot.js", { 4 | token, 5 | }); 6 | 7 | let ready = false; 8 | 9 | //#region Stats posters 10 | const DBLPoster = require("./botlistapi/DiscordBotListPoster"); 11 | const BotsServerDiscordPoster = require("./botlistapi/BotsServerDiscordPoster"); 12 | const FateslistPoster = require("./botlistapi/FateslistPoster"); 13 | const ListcordPoster = require("./botlistapi/ListcordPoster"); 14 | const BotsForDiscordPoster = require("./botlistapi/BotsForDiscordPoster"); 15 | const BoticordPoster = require("./botlistapi/BoticordPoster"); 16 | const tokens = require("./tokens.json"); 17 | 18 | const posters = []; 19 | const initPosters = (clientId) => { 20 | if (!posters.length) { 21 | posters.push( 22 | new DBLPoster({ 23 | id: clientId, 24 | token: tokens.discordbotlist, 25 | }), 26 | new BotsServerDiscordPoster({ 27 | id: clientId, 28 | token: tokens.botsServerDiscord, 29 | availableQueries: 1, 30 | ratelimit: 2000, 31 | }) 32 | /* 33 | new FateslistPoster({ 34 | id: clientId, 35 | token: tokens.fateslist, 36 | }), 37 | new ListcordPoster({ 38 | id: clientId, 39 | token: tokens.listcord, 40 | availableQueries: 1, 41 | ratelimit: 120000, 42 | }), 43 | new BotsForDiscordPoster({ 44 | id: clientId, 45 | token: tokens.botsfordiscord, 46 | }), 47 | new BoticordPoster({ 48 | id: clientId, 49 | token: tokens.boticord, 50 | }) 51 | */ 52 | ); 53 | } 54 | }; 55 | //#endregion Stats posters 56 | 57 | const postStats = async (clientId, shardId) => { 58 | if (beta || !ready) return; 59 | 60 | const guilds = await manager 61 | .fetchClientValues("guilds.cache.size") 62 | .then((vals) => vals.reduce((acc, guilds) => acc + guilds, 0)); 63 | const users = await manager 64 | .broadcastEval( 65 | "this.guilds.cache.reduce((acc, guild) => acc + guild.memberCount, 0)" 66 | ) 67 | .then((results) => results?.reduce((prev, val) => prev + val, 0)); 68 | 69 | const shards = manager.shards.size; 70 | 71 | if (!posters.length) initPosters(clientId); 72 | 73 | posters.map((poster) => 74 | poster.post({ 75 | guilds, 76 | users, 77 | shards, 78 | shard: shardId, 79 | }) 80 | ); 81 | }; 82 | 83 | manager.on("shardCreate", (shard) => { 84 | console.log(`Spawning shard #${shard.id}`); 85 | shard.on("message", async (message) => { 86 | if (message.type === "guildsUpdate") { 87 | await postStats(message.data.clientId, shard.id); 88 | } else if (message.type === "updateLocales") { 89 | await manager.broadcastEval("this.updateLocales()"); 90 | } 91 | }); 92 | }); 93 | 94 | manager.spawn("auto", 1000).then(async (shards) => { 95 | ready = true; 96 | console.log(`\nSpawned ${shards.size} shards`); 97 | }); 98 | -------------------------------------------------------------------------------- /commands/misc/help.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require("discord.js"); 2 | const { error } = require("../../helpers/templateMessages"); 3 | const translate = require("../../helpers/locale"); 4 | 5 | const { botOfficial } = require("../../colors.json"); 6 | 7 | async function help(msg, args, locale) { 8 | const prefix = msg.client.server.get(msg.guild.id, "prefix"); 9 | let helpEmbed = new MessageEmbed({ 10 | title: translate("help.title", locale), 11 | color: botOfficial, 12 | }); 13 | 14 | if (args.length) { 15 | const name = args.join(" ").toLowerCase(); 16 | 17 | const command = 18 | msg.client.commands.get(name) || 19 | msg.client.commands.find((cmd) => cmd.alias.includes(name)); 20 | 21 | if (!command || command.isPrivate) { 22 | await error( 23 | msg.channel, 24 | translate("help.command.notExist", locale, { 25 | command: name, 26 | }), 27 | locale 28 | ); 29 | return; 30 | } 31 | 32 | if (!msg.channel.nsfw && command.nsfw) { 33 | await error( 34 | msg.channel, 35 | translate("help.command.nsfwError", locale), 36 | locale 37 | ); 38 | return; 39 | } 40 | 41 | helpEmbed 42 | .addField( 43 | translate("help.command.description", locale), 44 | translate(`${command.name}.description`, locale) 45 | ) 46 | .addField( 47 | translate("help.command.usage", locale), 48 | translate(`${command.name}.usage`, locale) 49 | .map((usage) => prefix + name + " " + usage) 50 | .join("\n"), 51 | true 52 | ) 53 | .addField( 54 | translate("help.command.alias", locale), 55 | command.alias.length 56 | ? command.alias.map((alias) => `\`${alias}\``).join(" ") 57 | : translate("help.command.noAlias", locale), 58 | true 59 | ) 60 | .addField( 61 | translate("help.command.examples", locale), 62 | translate(`${command.name}.examples`, locale) 63 | .map((example) => prefix + name + " " + example) 64 | .join("\n") 65 | ) 66 | .setFooter({ 67 | text: translate("help.argsInfo", locale), 68 | }); 69 | } else { 70 | const fields = []; 71 | const modules = new Set(msg.client.commands.map((c) => c.module)); 72 | 73 | for (const module of modules) { 74 | const commands = msg.client.commands 75 | .filter((cmd) => cmd.module === module && !cmd.isPrivate) 76 | .map((command) => 77 | command.nsfw 78 | ? `||\`${prefix}${command.name}\`||` 79 | : `\`${prefix}${command.name}\`` 80 | ) 81 | .join(" "); 82 | 83 | if (commands) { 84 | fields.push({ 85 | name: module, 86 | value: commands, 87 | }); 88 | } 89 | } 90 | 91 | helpEmbed 92 | .addFields(fields.sort((a, b) => a.name.localeCompare(b.name))) 93 | .setFooter({ 94 | text: translate("help.moreInfo", locale, { 95 | prefix, 96 | }), 97 | }); 98 | } 99 | 100 | await msg.channel.send({ 101 | embeds: [helpEmbed], 102 | }); 103 | } 104 | 105 | module.exports = { 106 | name: "help", 107 | execute: help, 108 | alias: ["h"], 109 | cooldown: 0, 110 | argsRequired: 0, 111 | module: "Misc", 112 | isPrivate: false, 113 | }; 114 | -------------------------------------------------------------------------------- /events/commandsHandler.js: -------------------------------------------------------------------------------- 1 | const { Collection } = require("discord.js"); 2 | const translate = require("../helpers/locale"); 3 | 4 | const mentions = []; 5 | const cooldown = new Map(); 6 | 7 | const getSubCommand = (command, [commandName, ...args], id) => { 8 | if (!command.subCommands?.length) 9 | return { 10 | command, 11 | args: [commandName, ...args], 12 | id, 13 | }; 14 | const commandNamelowerCase = commandName.toLowerCase(); 15 | const subCommand = command.subCommands.find( 16 | (command) => 17 | command.name === commandNamelowerCase || 18 | command.alias?.includes(commandNamelowerCase) 19 | ); 20 | if (!subCommand) 21 | return { 22 | command, 23 | args: [commandName, ...args], 24 | id: id + "." + command.name, 25 | }; 26 | return { 27 | ...getSubCommand(subCommand, args, id + "." + command.name), 28 | }; 29 | }; 30 | 31 | async function messageHandler(msg) { 32 | if (!msg.guild?.available || msg.author.bot) return; 33 | const { 34 | client: { 35 | config: { prefix }, 36 | commands, 37 | server, 38 | guildBlacklist, 39 | userBlacklist, 40 | }, 41 | } = msg; 42 | 43 | if (guildBlacklist.has(msg.guild.id) || userBlacklist.has(msg.author.id)) 44 | return; 45 | 46 | if (!mentions.length) { 47 | mentions.push(`<@${msg.guild.me.id}> `, `<@!${msg.guild.me.id}> `); 48 | } 49 | const serverConfig = server.ensure(msg.guild.id, { 50 | locale: "en-US", 51 | prefix, 52 | }); 53 | 54 | const currentPrefix = mentions.reduce( 55 | (a, v) => (msg.content.startsWith(v) ? v : a), 56 | serverConfig.prefix 57 | ); 58 | if (!msg.content.startsWith(currentPrefix) || msg.webhookID) return; 59 | 60 | let args = msg.content.slice(currentPrefix.length).split(/ +/); 61 | const cmd = args.shift().toLowerCase(); 62 | 63 | let command = 64 | commands.get(cmd) || 65 | commands.find((command) => command.alias?.includes(cmd)); 66 | 67 | if (!command) return; 68 | 69 | let id = command.name; 70 | if (args.length) { 71 | const subCommand = getSubCommand(command, args, id); 72 | command = subCommand.command; 73 | args = subCommand.args; 74 | id = subCommand.id; 75 | } 76 | 77 | if (!cooldown.has(id)) { 78 | cooldown.set(id, new Collection()); 79 | } 80 | 81 | const timestamps = cooldown.get(id); 82 | if (timestamps.has(msg.author.id)) { 83 | const timeLeft = (timestamps.get(msg.author.id) - Date.now()) / 1000; 84 | msg.channel.send( 85 | translate("cooldown", serverConfig.locale, { 86 | timeLeft: timeLeft.toFixed(1), 87 | }) 88 | ); 89 | return; 90 | } 91 | 92 | timestamps.set(msg.author.id, Date.now() + command.cooldown * 1e3); 93 | 94 | setTimeout(() => { 95 | timestamps.delete(msg.author.id); 96 | }, command.cooldown * 1e3); 97 | 98 | try { 99 | const executed = command.execute(msg, args, serverConfig.locale); 100 | if (executed instanceof Promise) await executed; 101 | } catch (e) { 102 | console.error(e); 103 | msg.channel.send("Something went wrong"); 104 | } 105 | } 106 | 107 | function load(client) { 108 | client.on("messageCreate", messageHandler); 109 | } 110 | 111 | function unload(client) { 112 | client.off("messageCreate", messageHandler); 113 | } 114 | 115 | module.exports = { 116 | name: "commandsHandler", 117 | load, 118 | unload, 119 | }; 120 | -------------------------------------------------------------------------------- /helpers/roleplayMessages.js: -------------------------------------------------------------------------------- 1 | const { embedInvisible } = require("../colors.json"); 2 | 3 | const translate = require("./locale"); 4 | const getRandomItem = require("./getRandomItem"); 5 | const { MessageEmbed } = require("discord.js"); 6 | const getMemberByReply = require("./getMemberByReply"); 7 | const getMemberByMention = require("./getMemberByMention"); 8 | 9 | /** 10 | * @typedef {Object} EmotionInfo 11 | * @property {import("discord.js").Message} msg 12 | * @property {string} emote 13 | * @property {string} locale 14 | * @property {Array<() => Promise>} providers 15 | */ 16 | 17 | /** 18 | * @param {EmotionInfo} emoteInfo 19 | * @returns {Promise} 20 | */ 21 | const sendEmotion = async (emoteInfo) => { 22 | const { emote, msg, locale, providers } = emoteInfo; 23 | const provider = getRandomItem(providers); 24 | 25 | let imageUrl; 26 | try { 27 | imageUrl = await provider(); 28 | } catch { 29 | sendEmotion(msg, args, locale); 30 | return; 31 | } 32 | 33 | if (!imageUrl) { 34 | sendEmotion(msg, args, locale); 35 | return; 36 | } 37 | 38 | const emotionEmbed = new MessageEmbed() 39 | .setColor(embedInvisible) 40 | .setImage(imageUrl) 41 | .setDescription( 42 | translate(`${emote}.action`, locale, { 43 | caller: msg.member, 44 | }) 45 | ); 46 | 47 | await msg.channel.send({ 48 | embeds: [emotionEmbed], 49 | }); 50 | }; 51 | 52 | /** 53 | * @typedef {Object} ActionInfo 54 | * @property {string} action 55 | * @property {import("discord.js").Message} msg 56 | * @property {bool} nsfw 57 | * @property {string} locale 58 | * @property {string[]} args 59 | * @property {Array<() => Promise>} providers 60 | * @property {bool} userSelfEmbed 61 | * @property {bool} meSelfEmbed 62 | */ 63 | 64 | /** 65 | * @param {ActionInfo} actionInfo 66 | * @returns {Promise} 67 | */ 68 | const sendAction = async (actionInfo) => { 69 | const { action, msg, locale, args, providers } = actionInfo; 70 | const provider = getRandomItem(providers); 71 | 72 | if (actionInfo.nsfw && !msg.channel.nsfw) { 73 | await msg.channel.send(translate("nsfwError", locale)); 74 | return; 75 | } 76 | 77 | const pinged = msg.reference?.messageId 78 | ? await getMemberByReply(msg) 79 | : await getMemberByMention(msg.guild, args[0]); 80 | 81 | if (!pinged) { 82 | await msg.channel.send(translate("specifyUser", locale)); 83 | return; 84 | } 85 | 86 | let imageUrl; 87 | try { 88 | imageUrl = await provider(); 89 | } catch { 90 | sendAction(actionInfo); 91 | return; 92 | } 93 | 94 | if (!imageUrl) { 95 | sendAction(actionInfo); 96 | return; 97 | } 98 | 99 | const actionEmbed = new MessageEmbed() 100 | .setColor(embedInvisible) 101 | .setImage(imageUrl); 102 | 103 | if (pinged === msg.member) { 104 | await msg.channel.send({ 105 | content: translate(`${action}.alone`, locale), 106 | embeds: actionInfo.userSelfEmbed 107 | ? [ 108 | actionEmbed.setDescription( 109 | translate(`${action}.action`, locale, { 110 | attacker: msg.guild.me, 111 | victim: msg.member, 112 | }) 113 | ), 114 | ] 115 | : [], 116 | }); 117 | } else if (pinged === msg.guild.me) { 118 | await msg.channel.send({ 119 | content: translate(`${action}.me`, locale), 120 | embeds: actionInfo.meSelfEmbed 121 | ? [ 122 | actionEmbed.setDescription( 123 | translate(`${action}.action`, locale, { 124 | attacker: msg.member, 125 | victim: pinged, 126 | }) 127 | ), 128 | ] 129 | : [], 130 | }); 131 | } else { 132 | await msg.channel.send({ 133 | embeds: [ 134 | actionEmbed.setDescription( 135 | translate(`${action}.action`, locale, { 136 | attacker: msg.member, 137 | victim: pinged, 138 | }) 139 | ), 140 | ], 141 | }); 142 | } 143 | }; 144 | 145 | module.exports = { 146 | sendEmotion, 147 | sendAction, 148 | }; 149 | -------------------------------------------------------------------------------- /bot.js: -------------------------------------------------------------------------------- 1 | const { Client, Collection } = require("discord.js"); 2 | const Enmap = require("enmap"); 3 | const recursiveRead = require("./helpers/recursiveReader"); 4 | 5 | const client = new Client({ 6 | intents: ["GUILDS", "GUILD_MESSAGES"], 7 | }); 8 | client.events = new Collection(); 9 | client.commands = new Collection(); 10 | client.ownerCommands = new Collection(); 11 | 12 | client.server = new Enmap({ 13 | name: "serverSettings", 14 | dataDir: "./db", 15 | }); 16 | client.guildBlacklist = new Enmap({ 17 | name: "guildBlacklist", 18 | dataDir: "./db", 19 | }); 20 | client.userBlacklist = new Enmap({ 21 | name: "guildBlacklist", 22 | dataDir: "./db", 23 | }); 24 | client.config = require("./config.json"); 25 | const { token } = client.config; 26 | 27 | client.on("ready", () => { 28 | console.log(`Logged in as ${client.user.tag}`); 29 | client.user.setActivity({ 30 | name: `@${client.user.username}`, 31 | type: "LISTENING", 32 | }); 33 | }); 34 | 35 | client.requestLocales = () => { 36 | client.shard.send({ type: "updateLocales" }); 37 | }; 38 | 39 | client.updateLocales = async () => { 40 | const locales = await recursiveRead("./locales").then((files) => 41 | files.filter((file) => file.endsWith(".json")) 42 | ); 43 | 44 | for (const file of locales) { 45 | delete require.cache[require.resolve(file)]; 46 | require(file); 47 | } 48 | }; 49 | 50 | client.registerCommands = async () => { 51 | let error = ""; 52 | try { 53 | const commands = await recursiveRead("./commands"); 54 | for (const file of commands) { 55 | try { 56 | delete require.cache[require.resolve(file)]; 57 | const module = require(file); 58 | if (!module.name) { 59 | continue; 60 | } 61 | 62 | if (Array.isArray(module)) { 63 | for (const command of module) { 64 | client.commands.set(command.name, command); 65 | } 66 | } else { 67 | client.commands.set(module.name, module); 68 | } 69 | } catch (e) { 70 | error += `Error in ${file}\n${e.stack}\n\n`; 71 | } 72 | } 73 | 74 | return error || "Successfully registered all commands"; 75 | } catch (err) { 76 | return ( 77 | err.stack || 78 | "Something went wrong, please check commands for forbidden code" 79 | ); 80 | } 81 | }; 82 | 83 | client.registerOwnerCommands = async () => { 84 | let error = ""; 85 | try { 86 | const commands = await recursiveRead("./ownerCommands"); 87 | for (const file of commands) { 88 | try { 89 | delete require.cache[require.resolve(file)]; 90 | const module = require(file); 91 | if (!module.name) { 92 | continue; 93 | } 94 | 95 | if (Array.isArray(module)) { 96 | for (const command of module) { 97 | client.ownerCommands.set(command.name, command); 98 | } 99 | } else { 100 | client.ownerCommands.set(module.name, module); 101 | } 102 | } catch (e) { 103 | error += `Error in ${file}\n${e.stack}\n\n`; 104 | } 105 | } 106 | 107 | return error || "Successfully registered all owner commands"; 108 | } catch (err) { 109 | return ( 110 | err.stack || 111 | "Something went wrong, please check commands for forbidden code" 112 | ); 113 | } 114 | }; 115 | 116 | client.registerEvents = async () => { 117 | let error = ""; 118 | try { 119 | const files = await recursiveRead("./events"); 120 | 121 | for (const [, event] of client.events) { 122 | event.unload(client); 123 | } 124 | client.events.clear(); 125 | 126 | for (const event of files) { 127 | delete require.cache[require.resolve(event)]; 128 | try { 129 | const module = require(event); 130 | 131 | client.events.set(module.name, module); 132 | module.load(client); 133 | } catch (e) { 134 | error += `Error in ${event}\n${e.stack}\n\n`; 135 | } 136 | } 137 | return error || "Successfully registered all events"; 138 | } catch (err) { 139 | return ( 140 | err.stack || 141 | "Something went wrong, please check events for forbidden code" 142 | ); 143 | } 144 | }; 145 | 146 | (async () => { 147 | console.log(await client.registerCommands()); 148 | console.log(await client.registerOwnerCommands()); 149 | console.log(await client.registerEvents()); 150 | client.login(token); 151 | })(); 152 | -------------------------------------------------------------------------------- /ownerCommands/blacklist.js: -------------------------------------------------------------------------------- 1 | async function addUser(msg, [id, ...reason]) { 2 | if (!id || !reason.length) { 3 | await msg.channel.send("./bl u add [id] [reason]"); 4 | return; 5 | } 6 | 7 | try { 8 | const user = await msg.client.users.fetch(id); 9 | 10 | if (msg.client.userBlacklist.has(id)) { 11 | await msg.channel.send(`\`${user.tag}\` is already in the blacklisted`); 12 | return; 13 | } 14 | 15 | msg.client.userBlacklist.set(id, { 16 | timestamp: Date.now(), 17 | reason: reason.join(" "), 18 | }); 19 | 20 | await msg.channel.send( 21 | `\`${user.tag}\` (${id}) was added to the blacklist` 22 | ); 23 | } catch { 24 | await msg.channel.send(`Invalid ID: ${id}`); 25 | return; 26 | } 27 | } 28 | 29 | async function removeUser(msg, [id]) { 30 | if (!id) { 31 | await msg.channel.send("./bl u remove [id]"); 32 | return; 33 | } 34 | 35 | try { 36 | const user = await msg.client.users.fetch(id); 37 | 38 | if (!msg.client.userBlacklist.has(id)) { 39 | await msg.channel.send(`\`${user.tag}\` was not in the blacklist`); 40 | return; 41 | } 42 | 43 | msg.client.userBlacklist.delete(id); 44 | 45 | await msg.channel.send( 46 | `\`${user.tag}\` (${id}) was removed from the blacklist` 47 | ); 48 | } catch { 49 | await msg.channel.send(`Invalid user ID: ${id}`); 50 | return; 51 | } 52 | } 53 | 54 | async function showUser(msg, [id]) { 55 | if (!id) { 56 | msg.channel.send("./bl u show [id]"); 57 | return; 58 | } 59 | 60 | try { 61 | const user = await msg.client.users.fetch(id); 62 | const blockedUser = msg.client.userBlacklist.get(id); 63 | if (!blockedUser) { 64 | await msg.channel.send(`\`${user.tag}\` (${id}) is not blackisted`); 65 | return; 66 | } 67 | 68 | await msg.channel.send({ 69 | embeds: [ 70 | { 71 | author: { 72 | name: user.tag, 73 | icon_url: user.avatarURL(), 74 | }, 75 | timestamp: blockedUser.timestamp, 76 | description: blockedUser.reason, 77 | }, 78 | ], 79 | }); 80 | } catch { 81 | await msg.channel.send(`Invalid ID: ${id}`); 82 | return; 83 | } 84 | } 85 | 86 | async function addGuild(msg, [id, ...reason]) { 87 | if (!id || !reason.length) { 88 | await msg.channel.send("./bl g add [id] [reason]"); 89 | return; 90 | } 91 | 92 | try { 93 | const guild = await msg.client.guilds.fetch(id); 94 | 95 | if (msg.client.guildBlacklist.has(id)) { 96 | msg.channel.send(`\`${id}\` is already in the blacklist`); 97 | return; 98 | } 99 | 100 | msg.client.guildBlacklist.set(id, { 101 | name: guild.name, 102 | timestamp: Date.now(), 103 | reason: reason.join(" "), 104 | }); 105 | 106 | await msg.channel.send( 107 | `\`${guild.name}\` (${id}) was added to the blacklist` 108 | ); 109 | } catch { 110 | const blockedGuild = msg.client.guildBlacklist.get(id); 111 | if (!!blockedGuild) { 112 | await msg.channel.send( 113 | `\`${blockedGuild.name}\` (${id}) is already in the blacklisted` 114 | ); 115 | return; 116 | } 117 | 118 | await msg.channel.send(`Invalid guild ID: ${id}`); 119 | return; 120 | } 121 | } 122 | 123 | async function removeGuild(msg, [id]) { 124 | if (!id) { 125 | await msg.channel.send("./bl g remove [id]"); 126 | return; 127 | } 128 | 129 | const blockedGuild = msg.client.guildBlacklist.get(id); 130 | 131 | if (!blockedGuild) { 132 | await msg.channel.send(`\`${blockedGuild.name}\` was not in the blacklist`); 133 | return; 134 | } 135 | 136 | msg.client.guildBlacklist.delete(id); 137 | 138 | await msg.channel.send( 139 | `\`${blockedGuild.name}\` (${id}) was removed from the blacklist` 140 | ); 141 | } 142 | 143 | async function showGuild(msg, [id]) { 144 | if (!id) { 145 | msg.channel.send("./bl g show [id]"); 146 | return; 147 | } 148 | 149 | const blockedGuild = msg.client.guildBlacklist.get(id); 150 | if (!blockedGuild) { 151 | await msg.channel.send( 152 | `\`${blockedGuild.name}\` (${id}) is not blackisted` 153 | ); 154 | return; 155 | } 156 | 157 | await msg.channel.send({ 158 | embeds: [ 159 | { 160 | author: { 161 | name: blockedGuild.name, 162 | }, 163 | timestamp: blockedGuild.timestamp, 164 | description: blockedGuild.reason, 165 | }, 166 | ], 167 | }); 168 | } 169 | 170 | module.exports = { 171 | name: "blacklist", 172 | alias: ["bl"], 173 | subCommands: [ 174 | { 175 | name: "user", 176 | alias: ["u"], 177 | isPrivate: false, 178 | subCommands: [ 179 | { 180 | name: "add", 181 | execute: addUser, 182 | alias: [], 183 | }, 184 | { 185 | name: "remove", 186 | execute: removeUser, 187 | alias: [], 188 | }, 189 | { 190 | name: "show", 191 | execute: showUser, 192 | alias: [], 193 | }, 194 | ], 195 | }, 196 | { 197 | name: "guild", 198 | alias: ["server", "g"], 199 | isPrivate: false, 200 | subCommands: [ 201 | { 202 | name: "add", 203 | execute: addGuild, 204 | alias: [], 205 | }, 206 | { 207 | name: "remove", 208 | execute: removeGuild, 209 | alias: [], 210 | }, 211 | { 212 | name: "show", 213 | execute: showGuild, 214 | alias: [], 215 | }, 216 | ], 217 | }, 218 | ], 219 | }; 220 | -------------------------------------------------------------------------------- /locales/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "bite": { 3 | "action": "{attacker} bites {victim}", 4 | "alone": "You wanna bite yourself? I won't let you do this. Lemme bite you instead", 5 | "me": "Aww... it hurts :<", 6 | 7 | "description": "Allows you to bite someone", 8 | "usage": ["(@user)"], 9 | "examples": ["@DMax"] 10 | }, 11 | "cringe": { 12 | "action": "{attacker} cringes on {victim}", 13 | "alone": "oh *cringe*", 14 | "me": "Hey, I am not cringe! :<", 15 | 16 | "description": "Allows you to cringe on someone", 17 | "usage": ["(@user)"], 18 | "examples": ["@DMax"] 19 | }, 20 | "feed": { 21 | "action": "{attacker} feeds {victim}", 22 | "alone": "You are going to feed yourself? I think I can help you with that 😏", 23 | "me": "*om-nom...*", 24 | 25 | "description": "Allows you to feed someone", 26 | "usage": ["(@user)"], 27 | "examples": ["@DMax"] 28 | }, 29 | "highfive": { 30 | "action": "{attacker} highives {victim}", 31 | "alone": "let's highive together :>", 32 | "me": "COol", 33 | 34 | "description": "Allows you to highive someone", 35 | "usage": ["(@user)"], 36 | "examples": ["@DMax"] 37 | }, 38 | "hug": { 39 | "action": "{attacker} hugs {victim}", 40 | "alone": "I can't look at this without sadness... lemme give you a hug", 41 | "me": "Oh yeah... gimmie this hug, I want it....", 42 | 43 | "description": "Allows you to hug someone", 44 | "usage": ["(@user)"], 45 | "examples": ["@DMax"] 46 | }, 47 | "kiss": { 48 | "action": "{attacker} kisses {victim}", 49 | "alone": "You are so lonely.... you can't kiss somebody else... 😭", 50 | "me": "What just happend? 😳", 51 | 52 | "description": "Allows you to kiss someone", 53 | "usage": ["(@user)"], 54 | "examples": ["@DMax"] 55 | }, 56 | "lick": { 57 | "action": "{attacker} licks {victim}", 58 | "alone": "", 59 | "me": "Did you just licked me? 😳", 60 | 61 | "description": "Allows you to lick someone", 62 | "usage": ["(@user)"], 63 | "examples": ["@DMax"] 64 | }, 65 | "pat": { 66 | "action": "{attacker} pats {victim}", 67 | "alone": "Oh, lemme pat you :>", 68 | "me": "*sounds of happy fox*", 69 | 70 | "description": "Allows you to pat someone", 71 | "usage": ["(@user)"], 72 | "examples": ["@DMax"] 73 | }, 74 | "poke": { 75 | "action": "{attacker} pokes {victim}", 76 | "alone": "", 77 | "me": "*disgruntled stare*", 78 | 79 | "description": "Allows you to poke someone", 80 | "usage": ["(@user)"], 81 | "examples": ["@DMax"] 82 | }, 83 | "slap": { 84 | "action": "{attacker} slaps {victim}", 85 | "alone": "NO! I won't let you slap yourself!", 86 | "me": "why did you slap me? *cry*", 87 | 88 | "description": "Allows you to slap someone", 89 | "usage": ["(@user)"], 90 | "examples": ["@DMax"] 91 | }, 92 | "stare": { 93 | "action": "{attacker} stares at {victim}", 94 | "alone": "", 95 | "me": "*stares at you*", 96 | 97 | "description": "Allows you to stare at someone", 98 | "usage": ["(@user)"], 99 | "examples": ["@DMax"] 100 | }, 101 | "tickle": { 102 | "action": "{attacker} tickles {victim}", 103 | "alone": "I see, someone wants a tickles :>", 104 | "me": "ahahaha, ticklish, ahaha ", 105 | 106 | "description": "Allows you to tickle someone", 107 | "usage": ["(@user)"], 108 | "examples": ["@DMax"] 109 | }, 110 | "wave": { 111 | "action": "{attacker} waves to {victim}", 112 | "alone": "hey, I'm here", 113 | "me": "Hiii *Uwu*", 114 | 115 | "description": "Allows you to wave to someone", 116 | "usage": ["(@user)"], 117 | "examples": ["@DMax"] 118 | }, 119 | 120 | "anal": { 121 | "action": "{attacker} has anal sex with {victim}", 122 | "alone": "How'd you do that?", 123 | "me": "NO! NO! AND NO AGAIN! *angry fox sounds*", 124 | 125 | "description": "Allows you to have anal sex with someone", 126 | "usage": ["(@user)"], 127 | "examples": ["@DMax"] 128 | }, 129 | "blowjob": { 130 | "action": "{attacker} gives {victim} a blowjob", 131 | "alone": "To do this, you need to remove a couple of edges at least)", 132 | "me": "Hey! I'm actually a girl :< *angry fox sounds*", 133 | 134 | "description": "Allows you to give blowjob someone", 135 | "usage": ["(@user)"], 136 | "examples": ["@DMax"] 137 | }, 138 | "cum": { 139 | "action": "{attacker} cums inside {victim}", 140 | "alone": "How'd you going to cum iside yourself?", 141 | "me": "*an awkward silence* 😳", 142 | 143 | "description": "Allows you to cum inside someone", 144 | "usage": ["(@user)"], 145 | "examples": ["@DMax"] 146 | }, 147 | "fuck": { 148 | "action": "{attacker} fucks {victim}", 149 | "alone": "Fuck yourself? What?", 150 | "me": "Of course I am already an adult, but no *sounds of fox embarrassment*", 151 | 152 | "description": "Allows you to fuck someone", 153 | "usage": ["(@user)"], 154 | "examples": ["@DMax"] 155 | }, 156 | "kuni": { 157 | "action": "{attacker} makes kuni {victim}", 158 | "alone": "I can't imagine that", 159 | "me": "I am of course love kuni, but not from you, thx", 160 | 161 | "description": "Allows you to make kuni someone", 162 | "usage": ["(@user)"], 163 | "examples": ["@DMax"] 164 | }, 165 | "spank": { 166 | "action": "{attacker} spanks {victim}", 167 | "alone": "I don't wanna watch this", 168 | "me": "no no no, I don't like that", 169 | 170 | "description": "Allows you to spank someone", 171 | "usage": ["(@user)"], 172 | "examples": ["@DMax"] 173 | }, 174 | 175 | "blush": { 176 | "action": "{caller} is blushing", 177 | 178 | "description": "Allows you to blush", 179 | "usage": [""], 180 | "examples": [""] 181 | }, 182 | "bored": { 183 | "action": "{caller} is bored", 184 | 185 | "description": "Allows you to be bored", 186 | "usage": [""], 187 | "examples": [""] 188 | }, 189 | "cry": { 190 | "action": "{caller} is crying", 191 | 192 | "description": "Allows you to cry", 193 | "usage": [""], 194 | "examples": [""] 195 | }, 196 | "dance": { 197 | "action": "{caller} is dancing", 198 | 199 | "description": "Allows you to dance", 200 | "usage": [""], 201 | "examples": [""] 202 | }, 203 | "happy": { 204 | "action": "{caller} is happy", 205 | 206 | "description": "Allows you to be happy", 207 | "usage": [""], 208 | "examples": [""] 209 | }, 210 | "laugh": { 211 | "action": "{caller} is laughing", 212 | 213 | "description": "Allows you to laugh", 214 | "usage": [""], 215 | "examples": [""] 216 | }, 217 | "like": { 218 | "action": "{caller} shows like", 219 | 220 | "description": "Allows you to like", 221 | "usage": [""], 222 | "examples": [""] 223 | }, 224 | "pout": { 225 | "action": "{caller} is sulking", 226 | 227 | "description": "Allows you to pout", 228 | "usage": [""], 229 | "examples": [""] 230 | }, 231 | "shrug": { 232 | "action": "{caller} shrugs", 233 | 234 | "description": "Allows you to shrug", 235 | "usage": [""], 236 | "examples": [""] 237 | }, 238 | "sleep": { 239 | "action": "{caller} is sleeping", 240 | 241 | "description": "Allows you to sleep", 242 | "usage": [""], 243 | "examples": [""] 244 | }, 245 | "smug": { 246 | "action": "{caller} looks smug", 247 | 248 | "description": "Allows you to look smug", 249 | "usage": [""], 250 | "examples": [""] 251 | }, 252 | "think": { 253 | "action": "{caller} is thinking", 254 | 255 | "description": "Allows you to think", 256 | "usage": [""], 257 | "examples": [""] 258 | }, 259 | "wink": { 260 | "action": "{caller} is winking", 261 | 262 | "description": "Allows you to wink", 263 | "usage": [""], 264 | "examples": [""] 265 | }, 266 | 267 | "try": { 268 | "action": "*{caller} trying {action}*", 269 | "success": "Success", 270 | "failure": "Failure", 271 | 272 | "description": "Allows you to try do the action", 273 | "usage": ["[action]"], 274 | "examples": ["take a coin from the floor"] 275 | }, 276 | "dice": { 277 | "rolled": "{user} rolled: {sum}", 278 | "maxDicesError": "The maximum number of dice at a time shouldn't be more than 9", 279 | 280 | "description": "Allows you to roll the dice", 281 | "usage": ["(dices count)"], 282 | "examples": ["", "2"] 283 | }, 284 | "random": { 285 | "result": "Your random number is `{number}`", 286 | 287 | "description": "Gives you a random number in a given range", 288 | "usage": ["[min] [max]"], 289 | "examples": ["0 100"] 290 | }, 291 | 292 | "help": { 293 | "title": "Help", 294 | "moreInfo": "📌 More info: {prefix}help (command name)", 295 | "argsInfo": "📌 Argument: [] - required, () - optional", 296 | "command": { 297 | "description": "Description", 298 | "usage": "Usage", 299 | "alias": "Alias", 300 | "noAlias": "No alias", 301 | "examples": "Examples", 302 | 303 | "nsfwError": "I can't send help about this command is SFW channel", 304 | "notExist": "Command `{command}` doesn't exist" 305 | }, 306 | 307 | "description": "Shows all bot commands or info about the specified", 308 | "usage": ["(command name)"], 309 | "examples": ["", "pet"] 310 | }, 311 | "ping": { 312 | "pinging": "Pinging...", 313 | "pong": "🏓: {ws} ms\n\n⏱️: {loopback} ms", 314 | 315 | "description": "Shows bot ping", 316 | "usage": [""], 317 | "examples": [""] 318 | }, 319 | "invite": { 320 | "links": "**[Bot Invite]({botInvite})**\n**[Support Server]({serverInvite})**", 321 | 322 | "description": "Gives links to the bot and server invite", 323 | "usage": [""], 324 | "examples": [""] 325 | }, 326 | "donate": { 327 | "support": "Suppowt my ownew pwease ;-;.. he will appweciate this", 328 | 329 | "description": "Gives links to donate to the bot", 330 | "usage": [""], 331 | "examples": [""] 332 | }, 333 | "vote": { 334 | "request": "Vote for me pwease <3", 335 | "discord-ly": "here <3", 336 | 337 | "description": "Gives links to vote the bot", 338 | "usage": [""], 339 | "examples": [""] 340 | }, 341 | 342 | "prefix": { 343 | "current": "My current prefix here is **`{prefix}`**", 344 | "change": "Prefix was successfully changed to **`{prefix}`**", 345 | "tooLong": "Prefix can't be longer than 5 characters", 346 | 347 | "description": "Allows you to change or view the current prefix", 348 | "usage": ["(new prefix)"], 349 | "examples": ["", "r!"] 350 | }, 351 | "locale": { 352 | "current": "Current language on server — **{locale}**", 353 | "change": "Language was successfully changed to **{locale}**", 354 | "unknown": "Unknown language", 355 | 356 | "id": "ID", 357 | "name": "Name", 358 | 359 | "description": "Allows you to change or view the current language", 360 | "usage": ["show", "(new language)"], 361 | "examples": ["", "ru-RU", "show"] 362 | }, 363 | 364 | "nsfwError": "I can't send this in SFW channel", 365 | "specifyUser": "Specify a user, please", 366 | "permsError": "You haven't enough permissions to use this command", 367 | "cooldown": "Wait `{timeLeft} seconds` before using the command again", 368 | 369 | "error": "Error", 370 | "success": "Success", 371 | "invalidUsage": "Invalid Usage", 372 | 373 | "hello": "Hello! I am {me}, roleplay bot.\n\n`-` You can see all my commands by using `{prefix}help`\n`-` My prefix here is **`{prefix}`**\nIt can be changed by using `{prefix}prefix new_prefix`\n`-` More info and help in my support server: <{serverInvite}>" 374 | } 375 | -------------------------------------------------------------------------------- /locales/ru-RU.json: -------------------------------------------------------------------------------- 1 | { 2 | "bite": { 3 | "action": "{attacker} кусает {victim}", 4 | "alone": "Хочешь укусить себя? Не позволю! Позволь мне укусить тебя вместо", 5 | "me": "Ауч... больно :<", 6 | 7 | "description": "Позволяет вам укусить кого-либо", 8 | "usage": ["(@пользователь)"], 9 | "examples": ["@DMax"] 10 | }, 11 | "cringe": { 12 | "action": "{attacker} кринжует с {victim}", 13 | "alone": "оу *кринге*", 14 | "me": "эээ, я не кринж! :<", 15 | 16 | "description": "Позволяет вам словить кринж с кого-либо", 17 | "usage": ["(@пользователь)"], 18 | "examples": ["@DMax"] 19 | }, 20 | "feed": { 21 | "action": "{attacker} кормит {victim}", 22 | "alone": "Хочешь покормить себя себя? Не дам этому случиться! Лучше позволь мне покормить тебя вместо", 23 | "me": "*ам-ням...*", 24 | 25 | "description": "Позволяет вам покормить кого-либо", 26 | "usage": ["(@пользователь)"], 27 | "examples": ["@DMax"] 28 | }, 29 | "highfive": { 30 | "action": "{attacker} даёт пять {victim}", 31 | "alone": "давай пять!", 32 | "me": "клаСс", 33 | 34 | "description": "Позволяет вам дать пять кому-либо", 35 | "usage": ["(@пользователь)"], 36 | "examples": ["@DMax"] 37 | }, 38 | "hug": { 39 | "action": "{attacker} обнимает {victim}", 40 | "alone": "Я не могу на это смотреть без грусти... позволь мне тебя обнять", 41 | "me": "О да... дай мне эти обнимашки, я жажду их....", 42 | 43 | "description": "Позволяет вам обнять кого-либо", 44 | "usage": ["(@пользователь)"], 45 | "examples": ["@DMax"] 46 | }, 47 | "kiss": { 48 | "action": "{attacker} целует {victim}", 49 | "alone": "Ты такой одинокий... тебе некого поцеловать... 😭", 50 | "me": "Что это было? 😳", 51 | 52 | "description": "Позволяет вам поцеловать кого-либо", 53 | "usage": ["(@пользователь)"], 54 | "examples": ["@DMax"] 55 | }, 56 | "lick": { 57 | "action": "{attacker} облизывает {victim}", 58 | "alone": "", 59 | "me": "Ты только что лизнул(а) меня? 😳", 60 | 61 | "description": "Позволяет вам облизать кого-либо", 62 | "usage": ["(@пользователь)"], 63 | "examples": ["@DMax"] 64 | }, 65 | "pat": { 66 | "action": "{attacker} гладит {victim}", 67 | "alone": "Ох, можно тебя погладить?", 68 | "me": "*звуки счастливой лисы*", 69 | 70 | "description": "Позволяет вам погладить кого-либо", 71 | "usage": ["(@пользователь)"], 72 | "examples": ["@DMax"] 73 | }, 74 | "poke": { 75 | "action": "{attacker} тыкает в {victim}", 76 | "alone": "", 77 | "me": "*недовольный взнляд*", 78 | 79 | "description": "Позволяет вам тыкнуть в кого-либо", 80 | "usage": ["(@пользователь)"], 81 | "examples": ["@DMax"] 82 | }, 83 | "slap": { 84 | "action": "{attacker} даёт пощечину {victim}", 85 | "alone": "НЕТ! Я тебе не позволю дать себе пощечину", 86 | "me": "почему ты дал(а) мне пощечину? *плачет*", 87 | 88 | "description": "Позволяет вам дать пощёчину кому-либо", 89 | "usage": ["(@пользователь)"], 90 | "examples": ["@DMax"] 91 | }, 92 | "stare": { 93 | "action": "{attacker} зыркает за {victim}", 94 | "alone": "*почему ты смотршь на меня..?*", 95 | "me": "*зырк*", 96 | 97 | "description": "Позволяет вам позыркать на кого-либо", 98 | "usage": ["(@пользователь)"], 99 | "examples": ["@DMax"] 100 | }, 101 | "tickle": { 102 | "action": "{attacker} щекочет {victim}", 103 | "alone": "Я смотрю кто-то жаждет щекотки :>", 104 | "me": "ахахах, щекотно, ахахаха ", 105 | 106 | "description": "Позволяет вам защекотать кого-либо", 107 | "usage": ["(@пользователь)"], 108 | "examples": ["@DMax"] 109 | }, 110 | "wave": { 111 | "action": "{attacker} машет {victim}", 112 | "alone": "хэй, я здеся", 113 | "me": "Кукусики *Uwu*", 114 | 115 | "description": "Позволяет вам помахать кому-либо", 116 | "usage": ["(@пользователь)"], 117 | "examples": ["@DMax"] 118 | }, 119 | 120 | "anal": { 121 | "action": "{attacker} занимается анальным сексом с {victim}", 122 | "alone": "Как ты это собираешься сделать?", 123 | "me": "Нет! Нет! И ещё раз нет! *звуки злой лисы*", 124 | 125 | "description": "Позволяет вам заняться анальным сексом с кем-либо", 126 | "usage": ["(@пользователь)"], 127 | "examples": ["@DMax"] 128 | }, 129 | "blowjob": { 130 | "action": "{attacker} делает минет {victim}", 131 | "alone": "Чтобы сделать это, сначала удали пару рёбер)", 132 | "me": "Эй! Я девушка вообще-то :< *звуки злой лисы*", 133 | 134 | "description": "Позволяет вам сделать минет кому-либо", 135 | "usage": ["(@пользователь)"], 136 | "examples": ["@DMax"] 137 | }, 138 | "cum": { 139 | "action": "{attacker} кончает в {victim}", 140 | "alone": "Как ты собираешься кончить внутрь себя?", 141 | "me": "*неловкое молчание* 😳", 142 | 143 | "description": "Позволяет вам кончить в кого-либо", 144 | "usage": ["(@пользователь)"], 145 | "examples": ["@DMax"] 146 | }, 147 | "fuck": { 148 | "action": "{attacker} занимается сексом с {victim}", 149 | "alone": "Трахнуть себя? Что?", 150 | "me": "Я, конечно, уже взрослая, но нет *звуки смущённой лисы*", 151 | 152 | "description": "Позволяет вам заняться сексом с кем-либо", 153 | "usage": ["(@пользователь)"], 154 | "examples": ["@DMax"] 155 | }, 156 | "kuni": { 157 | "action": "{attacker} делает куни {victim}", 158 | "alone": "Я даже не могу себе это представить...", 159 | "me": "Я, конечно, люблю куни, но не от тебя, спасибо", 160 | 161 | "description": "Позволяет вам сделать куни кому-либо", 162 | "usage": ["(@пользователь)"], 163 | "examples": ["@DMax"] 164 | }, 165 | "spank": { 166 | "action": "{attacker} шлёпает {victim}", 167 | "alone": "Я не хочу на это смотреть", 168 | "me": "не не не, я не люблю такие вещи", 169 | 170 | "description": "Позволяет вам шлёпнуть кого-либо", 171 | "usage": ["(@пользователь)"], 172 | "examples": ["@DMax"] 173 | }, 174 | 175 | "blush": { 176 | "action": "{caller} смущается", 177 | 178 | "description": "Позволяет вам смутиться", 179 | "usage": [""], 180 | "examples": [""] 181 | }, 182 | "bored": { 183 | "action": "{caller} скучает", 184 | 185 | "description": "Позволяет вам заскучать", 186 | "usage": [""], 187 | "examples": [""] 188 | }, 189 | "cry": { 190 | "action": "{caller} плачет", 191 | 192 | "description": "Позволяет вам поплакать", 193 | "usage": [""], 194 | "examples": [""] 195 | }, 196 | "dance": { 197 | "action": "{caller} танцует", 198 | 199 | "description": "Позволяет вам потанцевать", 200 | "usage": [""], 201 | "examples": [""] 202 | }, 203 | "happy": { 204 | "action": "{caller} чувствует прилив счастья", 205 | 206 | "description": "Позволяет вам почувствовать прилив счастья", 207 | "usage": [""], 208 | "examples": [""] 209 | }, 210 | "laugh": { 211 | "action": "{caller} смеётся", 212 | 213 | "description": "Позволяет вам засмеяться", 214 | "usage": [""], 215 | "examples": [""] 216 | }, 217 | "like": { 218 | "action": "{caller} лайкает", 219 | 220 | "description": "Позволяет вам лайкать", 221 | "usage": [""], 222 | "examples": [""] 223 | }, 224 | "pout": { 225 | "action": "{caller} дуется", 226 | 227 | "description": "Позволяет вам надуться", 228 | "usage": [""], 229 | "examples": [""] 230 | }, 231 | "shrug": { 232 | "action": "{caller} пожимает плечами", 233 | 234 | "description": "Позволяет вам пожать плечами", 235 | "usage": [""], 236 | "examples": [""] 237 | }, 238 | "sleep": { 239 | "action": "{caller} спит", 240 | 241 | "description": "Позволяет вам поспать", 242 | "usage": [""], 243 | "examples": [""] 244 | }, 245 | "smug": { 246 | "action": "{caller} выглядит самодовольно", 247 | 248 | "description": "Позволяет вам выглядеть самодовольно", 249 | "usage": [""], 250 | "examples": [""] 251 | }, 252 | "think": { 253 | "action": "{caller} думает", 254 | 255 | "description": "Позволяет вам думать", 256 | "usage": [""], 257 | "examples": [""] 258 | }, 259 | "wink": { 260 | "action": "{caller} подмигивает", 261 | 262 | "description": "Позволяет вам подмигнуть", 263 | "usage": [""], 264 | "examples": [""] 265 | }, 266 | 267 | "try": { 268 | "action": "*{caller} пытается {action}*", 269 | "success": "Успешно", 270 | "failure": "Неудачно", 271 | 272 | "description": "Позволяет вам попробавать выполнить действие", 273 | "usage": ["[действие]"], 274 | "examples": ["взять монетку с пола"] 275 | }, 276 | "dice": { 277 | "rolled": "{user} выкинул(а): {sum}", 278 | "maxDicesError": "Максимальное кол-во кубиков за раз не должно быть больше 9", 279 | 280 | "description": "Позволяет вам бросить кубик", 281 | "usage": ["(кол-во кубиков)"], 282 | "examples": ["", "2"] 283 | }, 284 | "random": { 285 | "result": "Ваше случайное число это `{number}`", 286 | 287 | "description": "Выдаёт вам случайное число в заданном диапазоне", 288 | "usage": ["[мин] [макс]"], 289 | "examples": ["0 100"] 290 | }, 291 | 292 | "help": { 293 | "title": "Помощь", 294 | "moreInfo": "📌 Больше информации: {prefix}help (название команды)", 295 | "argsInfo": "📌 Аргумент: [] - обязательный, () - опциональный", 296 | "command": { 297 | "description": "Описание", 298 | "usage": "Использование", 299 | "alias": "Псевдонимы", 300 | "noAlias": "Нет псевдонимов", 301 | "examples": "Примеры использования", 302 | 303 | "nsfwError": "Я не могу отправить помощь по этой команде в SFW канале", 304 | "notExist": "Команда `{command}` не существует" 305 | }, 306 | 307 | "description": "Показывает все команды или информацию о выбранной", 308 | "usage": ["(название команды)"], 309 | "examples": ["", "pet"] 310 | }, 311 | "ping": { 312 | "pinging": "Пингуем...", 313 | "pong": " 🏓: {ws} мс\n\n⏱️: {loopback} мс", 314 | 315 | "description": "Показывает пинг бота", 316 | "usage": [""], 317 | "examples": [""] 318 | }, 319 | "invite": { 320 | "links": "**[Инвайт бота]({botInvite})**\n**[Сервер поддержки]({serverInvite})**", 321 | 322 | "description": "Даёт приглашения для бота и на сервер поддержки", 323 | "usage": [""], 324 | "examples": [""] 325 | }, 326 | "donate": { 327 | "support": "Пожалуйста, поддержи моего создателя ;-;... это сделает его счастливым <3", 328 | 329 | "description": "Дает ссылки для пожертвования на бота", 330 | "usage": [""], 331 | "examples": [""] 332 | }, 333 | "vote": { 334 | "request": "проголосуй за меня позязя <3", 335 | "discord-ly": "вот сайтик!", 336 | 337 | "description": "Даёт ссылки чтобы проголосовать за бота", 338 | "usage": [""], 339 | "examples": [""] 340 | }, 341 | 342 | "prefix": { 343 | "current": "Мой текущий префикс это **`{prefix}`**", 344 | "change": "Префикс был успешно изменён на **`{prefix}`**", 345 | "tooLong": "Префикс не может быть длиннее 5 символов", 346 | 347 | "description": "Позволяет изменить или просмотреть текущий префикс", 348 | "usage": ["(новый префикс))"], 349 | "examples": ["", "r!"] 350 | }, 351 | "locale": { 352 | "current": "Текущий язык на сервере — **{locale}**", 353 | "change": "Язык был успешно изменён на **{locale}**", 354 | "unknown": "Неизвестный язык", 355 | 356 | "id": "Идентификатор", 357 | "name": "Название", 358 | 359 | "description": "Позволяет изменить или просмотреть текущий язык", 360 | "usage": ["show", "(новый язык)"], 361 | "examples": ["", "en-US", "show"] 362 | }, 363 | 364 | "nsfwError": "Я не могу отправлять это в SFW канале", 365 | "specifyUser": "Укажите пользователя", 366 | "permsError": "У вас недостаточно прав на выполнение этой команды", 367 | "cooldown": "Подождите `{timeLeft} сек` перед повторным использованием команды", 368 | 369 | "error": "Ошибка", 370 | "success": "Успех", 371 | "invalidUsage": "Неверное использование", 372 | 373 | "hello": "Привет! Я {me}, бот для ролевых игр.\n\n`-` Ты можешь просмотреть список моих команд, используя `{prefix}help`\n`-` Мой префикс на сервере — **`{prefix}`**\nОн может быть изменён при помощи `{prefix}prefix новый_префикс`\n`-` Больше информации и поддержки на моём сервере: <{serverInvite}>" 374 | } 375 | --------------------------------------------------------------------------------