UNPKG

d-bot

Version:

A quirky Discord bot made for single, small, private servers

256 lines (244 loc) 9.95 kB
// Riddle me this var util = require(__base+'core/util.js'); var discord = require(__base+'core/discord.js'); var storage = require(__base+'core/storage.js'); var FuzzySet = require('fuzzyset.js'); const CHANNEL = '430194045835542528'; const MONITOR_CHANNEL = '209177876975583232'; const { answerMods, chatRules } = require('./helpers/riddle-mods'); let waiting = false; const INIT_DATA = { attempts: 0, stage: -1, stageBeginTime: 0, furthestStage: -1, lastClueTime: 0, clueShownTimes: 0, nonAnswerMessages: 0, lastAnswerer: null, answerMod: false, chatRule: false, chatRuleData: {}, chatRuleViolations: 0, usedAnswerMods: [], usedChatRules: [], lastChatRuleTime: 0 }; const riddleData = storage.json('riddle', INIT_DATA, '\t'); function showClue() { riddleData.set('lastClueTime', Date.now()); riddleData.trans('clueShownTimes', t => t + 1); let stageNumber = riddleData.get('stage'); let message = STAGES[stageNumber].promptText; let answerMod = riddleData.get('answerMod'); if(answerMod) message = answerMods.get(answerMod).transform(message); let end = stageNumber === STAGES.length - 1; discord.uploadFile({ to: CHANNEL, message: (end ? ':tada: ' : ':small_orange_diamond: ') + message, file: storage.getStoragePath((end ? 'end' : stageNumber) + '.jpg') }); } function chooseMod(mods, usedKey, stage) { let mod, usedMods = riddleData.get(usedKey)[stage] || []; do mod = util.pickInArray([...mods.keys()]); while(usedMods.includes(mod)); riddleData.trans(usedKey, u => { if(!u[stage]) u[stage] = []; u[stage].push(mod); // console.log('used mods count', u[stage].length, 'all mods count', mods.size); if(u[stage].length === mods.size) u[stage] = [mod]; // All mods used, round robin resets return u; }); return mod; } function nextStage() { waiting = false; riddleData.trans('stage', s => s + 1); let answerMod = false; let stage = riddleData.get('stage'); riddleData.trans('furthestStage', f => Math.max(f, stage)); if(stage < STAGES.length && stage < riddleData.get('furthestStage') && Math.random() < 0.3) { answerMod = chooseMod(answerMods, 'usedAnswerMods', stage); } riddleData.set('answerMod', answerMod); riddleData.set('clueShownTimes', 0); riddleData.set('nonAnswerMessages', 0); riddleData.set('stageBeginTime', Date.now()); showClue(); } function reset() { riddleData.trans('attempts', a => { a++; discord.sendMessage(CHANNEL, `:repeat: **ATTEMPT ${a + 1}**`); return a; }); riddleData.set('stage', -1); setTimeout(nextStage, 5 * 1000); } module.exports = { listen: async function(data) { if(data.channel === MONITOR_CHANNEL) { if(data.message === 'init riddle') { return riddleData.setData(JSON.parse(JSON.stringify(INIT_DATA))); } if(data.message === 'start riddle') { discord.sendMessage(CHANNEL, '@everyone'); return nextStage(); } if(data.message === 'show clue') return showClue(); } if(data.userID === '86913608335773696' || data.channel !== CHANNEL || waiting || riddleData.get('stage') < 0) return; let stage = STAGES[riddleData.get('stage')]; let answer = stage.answer; let answerMod = riddleData.get('answerMod'); if(answerMod) answer = answerMods.get(answerMod).transform(answer); let messageScore = FuzzySet([answer]).get(data.message); messageScore = messageScore ? messageScore[0][0] : 0; // discord.sendMessage(MONITOR_CHANNEL, `Message "${data.message}" is ${messageScore*100}% close to "${answer}"`); if(messageScore >= 0.9 && (!answerMod || answerMods.get(answerMod).validGuess(answer, data.message))) { data.reply(':white_check_mark: **Correct!**'); riddleData.set('lastAnswerer', data.userID); return nextStage(); } else { let chatRule = riddleData.get('chatRule'); let chatRuleData = chatRule && riddleData.get('chatRuleData'); let chatRuleViolated = chatRule && chatRules.get(chatRule).violates(data, chatRuleData); riddleData.save(); if(chatRuleViolated) { data.reply( `:warning: ***CHAT RULE VIOLATION!*** — \`${chatRules.get(chatRule).message(chatRuleData)}\``); riddleData.trans('lastChatRuleTime', t => t - 2 * 60 * 1000); riddleData.trans('chatRuleViolations', v => v + 1); waiting = true; return setTimeout(reset, 3 * 1000); } } riddleData.trans('nonAnswerMessages', m => { m++; let stageTime = Date.now() - riddleData.get('stageBeginTime'); //console.log(m, stageTime > 3 * 60 * 1000); if((util.randomInt(m) > 4 || stageTime > 3 * 60 * 1000) && riddleData.get('stage') > 0) { let attempt = riddleData.get('attempts'); let attemptMessage = attemptMessages[attempt % attemptMessages.length]; data.reply(attemptMessage); waiting = true; setTimeout(reset, 3 * 1000); } else if(m % 12 === 11) { showClue(); } return m; }); }, tick() { if(waiting || riddleData.get('stage') < 0 || !discord.bot.connected) return; let timeSinceLastChatRule = Date.now() - riddleData.get('lastChatRuleTime'); if(riddleData.get('attempts') > 0 && (riddleData.get('chatRuleViolations') >= 3 || timeSinceLastChatRule > 10 * 60 * 1000)) { let chatRule = chooseMod(chatRules, 'usedChatRules', 0); riddleData.set('chatRule', chatRule); riddleData.set('chatRuleData', {}); if(chatRules.get(chatRule).init) chatRules.get(chatRule).init(riddleData.get('chatRuleData')); riddleData.save(); riddleData.set('lastChatRuleTime', Date.now() - util.randomInt(5) * 60 * 1000); riddleData.set('chatRuleViolations', 0); discord.sendMessage(CHANNEL, `:notepad_spiral: **New Chat Rule:** \`${chatRules.get(chatRule).message(riddleData.get('chatRuleData'))}\``); } }, commands: {} }; const STAGES = [ { // 0 promptText: 'Good morning, and welcome to the', answer: 'Black Mesa transit system' }, { // 1 promptText: 'The Barney says:', answer: `Morning Mr. Freeman, looks like you're running late` }, { // 2 promptText: 'Whose locker?', answer: 'Laidlaw' }, { // 3 promptText: `I'm seeing predictable`, answer: 'phase arrays' }, { // 4 promptText: 'Title card:', answer: 'OFFICE COMPLEX' }, { // 5 promptText: 'morgs: why does black mesa have a ..', answer: 'meat? processing plant?' }, { // 6 promptText: 'The dangling scientist says:', answer: `I... I can't hold on much longer` }, { // 7 promptText: 'For \\_\\_\\_ sake \\_\\_\\_ the \\_\\_\\_ door, \\_\\_\\_ coming \\_\\_\\_ us, \\_\\_\\_ our \\_\\_\\_ way \\_\\_\\_!', answer: `god's open silo they're for it's only out` }, { // 8 promptText: `What's _this_ button do?`, answer: 'TEST FIRE' }, { // 9 promptText: `How many W presses does it take to go full speed on a train?`, answer: 'four' }, { // 10 promptText: `They said it was hauled from the Challenger Deep`, answer: 'ichthyosaur' }, { // 11 promptText: `Who was being careless with the Gauss gun?`, answer: 'Barney' }, { // 12 promptText: `What does the suit lady say when you reach full battery?`, answer: 'Power level is one hundred percent' }, { // 13 promptText: `What comes out of this pod when you break it?`, answer: 'snarks' }, { // 14 promptText: `Who kept jumping into this portal too early because they couldn't hear the scientist?`, answer: 'Viper' }, { // 15 promptText: `Do the Xen healing pools make the best sound ever?`, answer: 'yes' }, { // 16 promptText: `The G-Man is \\_\\_\\_ by the nasty piece of work you managed over there`, answer: 'impressed' }, { // end promptText: 'You finally solved my riddle...', answer: 'L1VXsQjml4wFT8YYXKXgJLTtcPAprsULL1Df5TUPmCOVIfXTNOOnyiCjxlZzDAJ1gYjj4c7bAyRlxE9hxRDZHUFni2piWlDzVTpT5C' } ]; const attemptMessages = [ `:confused: Hmm. I'm resetting your progress. Try again.`, `:pensive: Start over. You'll get it this time.`, ':rolling_eyes: Really? Come on. Starting over.', ':disappointed: You guys are better than this. Do it again.', ':expressionless: Have you even played Half-Life?', `:neutral_face: This really isn't that hard.`, ':thinking: Some of you went to college, right?', ':sweat: This is a disgrace.', ':grimacing: What is the matter with you?', ':poop: Try again, morons.', ':unamused: Come the fuck on.', ':confounded: Try using your brains.', `:veg: I'm starting to feel sorry for you.`, ':no_mouth: You all must feel pretty stupid.', ':nerd: Try thinking for a change.', `:flushed: You should be ashamed.`, `:head_bandage: This is painful to watch.`, ':cry: Are you just hitting random keys?', ':cobra: *GOD DAMNIT!*' ];