diff --git a/commands/insult.js b/commands/insult.js new file mode 100644 index 0000000..a75a06b --- /dev/null +++ b/commands/insult.js @@ -0,0 +1,474 @@ +module.exports = { + name: 'insult', + alias: ['insult'], + helptext: 'Fresh insults directed at whoever you want', + helphide: false, + permissions: ['READ_MESSAGES'], + category: 'general', + command: (client, msg) => { + if (msg.mentions.members.array().length > 0) + msg.channel.send(msg.mentions.members.first() + ', ' + getInsult()); + else + msg.reply(getInsult()); + } +} + +const importedBuckets = { + insults: [ + { weight: 100, value: "Get [disease] and [die][you_blank]." }, + { weight: 500, value: "I hope [bad_thing_happens_to_you][you_blank]." }, + { weight: 100, value: "your [relative] (p)[hate] you[you_blank]." }, + { weight: 100, value: "[you_smell] like [animal_excrement]." }, + { weight: 100, value: "[you_are] (s)[noun]." }, + { weight: 100, value: "[you_are] (s)[adj] [noun]." }, + { weight: 100, value: "[you_are] (s)[noun], (s)[adj] [noun]." }, + { weight: 100, value: "[you_are] (s)[noun] and your [relative] is (s)[noun]." }, + { weight: 200, value: "[noun]." }, + { weight: 50, value: "a thousand (p)[sex_anatomy] upon [your_face]." }, + { weight: 100, value: "you are (s)[walking] [anatomy]." }, + { weight: 100, value: "[your_or_your_relatives] [body_part_or_parts_are_ugly]." }, + { weight: 100, value: "you [walk] like (s)[animal][you_blank]." }, + { weight: 50, value: "I [hate] your [animal]-[body_part_or_body_parts]." }, + { weight: 100, value: "my, what [ugly_body_part_or_parts] you have!" }, + { weight: 50, value: "on [certain_day] you [doing_something_embarrassing][maybe_while_your_relative_watches]." }, + { weight: 50, value: "between you and r{(s)[adj] [noun]}, I'd rather be r{(s)[adj] [noun]}." }, + { weight: 100, value: "your [hygiene] is [atrocious][you_blank]." }, + { weight: 100, value: "your [body_parts] are [ugly], your [body_part] is [ugly], and you smell like (s)[smelly_noun]." }, + { weight: 50, value: "you're like (s)[noun], but [dumber]." }, + ], + your_or_your_relatives: [ + { weight: 200, value: "your" }, + { weight: 100, value: "your [relative]'s" } + ], + body_part_or_parts_are_ugly: [ + "[body_part] is [ugly]", + "[body_parts] are [ugly]" + ], + bad_thing_happens_to_you: [ + "it smells like (s)[smelly_noun] on your [nice_day]", + "[you_get] [disease]", + "[you_get] [hiccups]", + "your child grows up (s)[adj] [noun]", + "[you_get] [raped] by a [pack] of (p)[animal]", + "you fall [off_a_cliff] and die", + "[you_get] [crucified]", + "[you_get] [hanged]", + "your car gets towed", + "you walk in on your [relative] masturbating", + "your [relative] catches you masturbating", + "you have an unplanned child", + "someone steals your car", + "you get a nose bleed", + "no one remembers your birthday", + "you miss a mortgage payment and lose your home", + "[you_get] [slapped]", + "you spontaneously combust", + "your [relative] has an affair with your [relative]", + "[you_get] stabbed with (s)[dirty] [knife]", + "your [relative] marries a [racist]", + "you lose your job", + "you marry the wrong person", + "you fall into a ditch", + "you miss the bus", + "you get gum stuck in your hair", + "you drop your phone", + "you shit your pants", + "you miss an important phone call", + "you get a parking ticket", + "you get [hiccups]", + "(s)[fly] [flies_in_your_eye]", + "you stub your toe", + "you lose your keys", + "your leg falls asleep", + "you get locked out of your house", + "you get your identity stolen", + "you get passed on a promotion", + "you fall down in public", + "you step in [animal] [feces]", + "you never find true love", + "you get caught watching [animal] porn", + "you get arrested for fraud" + ], + animal_excrement: [ + "[animal] [excrement]", + "fresh [animal] [excrement]", + "a piece of [animal] [feces]", + "a fresh piece of [animal] [feces]" + ], + racist: ["racist", "nazi"], + knife: ["knife", "knife", "pitchfork", "fork", "syringe", "stick"], + dirty: ["dirty", "rusty", "AIDS-infected"], + crucified: ["crucified", "crucified upside-down"], + hanged: ["hanged", "hanged for (v)[fuck] (p)[animal]"], + slapped: ["slapped", "bitch-slapped", "slapped silly", "spat on"], + off_a_cliff: ["off a cliff", "down a well", "off a mountain"], + you_blank: ["", ", you [noun]", ", you [adj] [noun]"], + you_get: ["your [relative] gets", "you get"], + you_smell: ["you smell", "your [relative] smells", "your breath smells"], + you_are: ["you are", "your [relative] is"], + you_have: ["you have", "your [relative] has"], + your: ["your", "your [relative]'s"], + your_face: ["you", "your face", "your family", "you and your family"], + relative: [ + "brother", + "child", + "sister", + "dad", + "mom", + "grandpa", + "grandma", + "dog", + "cat", + "boyfriend", + "girlfriend" + ], + disease: ["AIDS", "cholera", "ebola", "smallpox", "leprosy"], + hiccups: [ + "hiccups", + "jock-itch", + "sunburn", + "athlete's foot", + "bad breath", + "frizzy hair", + "a paper cut", + "pink eye", + "the runs", + "food poisoning" + ], + adj: [ + "[compound_adj]", + "[single_word_adj]", + "[single_word_adj], [compound_adj]" + ], + compound_adj: [ + "[penis]-sucking", + "[fluid]-(v)[guzzle]", + "[feces]-(v)[eat]", + "[excrement]-stained", + "[animal]-(v)[fuck]", + "[disease]-ridden", + "[animal]-infested" + ], + single_word_adj: [ + "bloody", + "brain-dead", + "degenerate", + "depraved", + "despicable", + "disgusting", + "drooling", + "fat", + "festering", + "filthy", + "half-witted", + "insignificant", + "insecure", + "meat-headed", + "miserable", + "pathetic", + "puerile", + "rancid", + "repulsive", + "ridiculous", + "slack-jawed", + "ugly", + "vulgar", + "worthless" + ], + noun: [ + "[anatomy]", + "[fluid_container]", + "[smelly_noun]-[food]", + "[sex_anatomy]-face", + "[smelly_noun]-breath", + "piece of [feces]", + "piece of [animal] [feces]", + "son of (s)[animal]", + "[buffoon]", + "[fluid]-(n)[guzzle]", + "[feces]-(n)[eat]", + "[animal]-(n)[fuck]", + "[fruit]-[sex_anatomy]", + "[excrement]-stain", + "[sex_anatomy]-monster", + "miscreant", + "troglodyte", + "paper cut", + "canker sore", + "dildo", + "slut", + "[racist]" + ], + fluid_container: ["[fluid]-[container]", "[container] of [fluid]"], + container: ["bag", "sack", "bucket", "bowl"], + buffoon: ["buffoon", "moron", "nincompoop", "idiot", "loser", "dummy"], + anatomy: [ + "[penis]", + "[pubic_hair]", + "[anus]", + "canker", + "pustule", + "wart", + "ovary", + "tit", + "testicle" + ], + smelly_noun: ["[penis]", "[anus]", "[feces]", "fart", "armpit"], + sex_anatomy: ["[penis]", "[anus]"], + anus: ["anus", "ass", "rectum", "butt"], + penis: ["cock", "dick", "penis", "dong"], + animal: [ + "alligator", + "ape", + "baboon", + "camel", + "chicken", + "chimpanzee", + "chihuahua", + "cow", + "crocodile", + "dog", + "donkey", + "elephant", + "fish", + "goat", + "hippo", + "horse", + "hyena", + "llama", + "monkey", + "pig", + "rat", + "skunk", + "warthog" + ], + fuck: ["fist", "fuck", "hump", "molest", "slap", "violate"], + excrement: ["[feces]", "[semen]", "[urine]", "[vomit]", "douche"], + fluid: ["[semen]", "[urine]", "[vomit]", "douche", "diarrhea"], + feces: ["poop", "shit", "turd"], + feces_verb: ["poop", "shit"], + eat: ["eat", "lick", "sniff"], + semen: ["cum", "jizz"], + guzzle: ["chug", "drink", "guzzle"], + urine: ["piss", "urine"], + vomit: ["puke", "vomit"], + pubic_hair: ["pube", "pubic hair"], + raped: ["eaten", "humped", "violated", "captured", "imprisoned", "enslaved"], + pack: ["group", "family", "pack", "swarm"], + fruit: ["banana", "lemon", "mango", "kiwi", "cheese"], + food: ["burger", "sandwich", "cake", "biscuit"], + small_object: ["[fruit]", "[small_animal]"], + small_animal: ["rat", "gerbil", "hamster", "kitten", "insect", "maggot"], + nice_day: ["wedding day", "anniversary", "birthday"], + walking: ["walking", "talking"], + die: [ + "die", + "fall down a set of stairs", + "run into a wall", + "walk into oncoming traffic" + ], + fly: ["mosquito", "gnat", "bee"], + flies_in_your_eye: [ + "lands on your eye", + "lands in your ear", + "flies up your butt", + "flies in your mouth" + ], + ugly: [ + "atrocious", + "sub-par", + "vomit-inducing", + "disgusting", + "deformed", + "malformed", + "ugly", + "gross", + "nauseating", + "weird" + ], + body_part: ["face", "nose", "head", "beard", "skin", "hair", "forehead"], + countable_body_part: ["face", "nose", "head", "beard", "forehead"], + body_parts: ["ears", "eyes", "arms", "legs", "teeth", "lips"], + body_part_or_body_parts: ["[body_part]", "[body_parts]"], + ugly_body_part_or_parts: [ + "[ugly] [body_parts]", + "(s)[ugly] [countable_body_part]" + ], + walk: ["walk", "smell", "look", "sound", "laugh"], + hate: ["hate", "loathe", "despise", "detest"], + doing_something_embarrassing: [ + "[feces_verb] on (p)[animal]", + "expose yourself to children", + "sniff (s)[smelly_noun]", + "bathe in [fluid]", + "drink [animal] [urine]", + "eat [animal] [feces]", + "masturbate to [animal] porn" + ], + maybe_while_your_relative_watches: ["", " while your [relative] [watches]"], + watches: ["watches", "films it"], + certain_day: [ + "Mondays", + "Tuesdays", + "Wednesdays", + "Thursdays", + "Fridays", + "Saturdays", + "Sundays", + "Christmas", + "New Years", + "New Years Eve", + "Halloween", + "Valentine's Day", + "Martin Luther King Day", + "President's Day", + "Memorial Day", + "Labour Day" + ], + hygiene: ["personal hygiene", "oral hygiene", "hygiene"], + atrocious: [ + "terrible", + "horrendous", + "atrocious", + "sub-par", + "not good", + "disgusting" + ], + dumber: [ + "dumber", + "stupider", + "more annoying", + "smellier", + "fatter", + "grosser", + "worse" + ] +}; + +const isVowel = letter => + ["a", "e", "i", "o", "u"].includes(letter.toLowerCase()); + +const addIndefiniteArticle = str => { + if (str.match(/^(use|urin)/)) { + return "a " + str; + } + + if (isVowel(str[0])) { + return "an " + str; + } + + return "a " + str; +}; + +const capitalize = str => str[0].toUpperCase() + str.slice(1); + +const pluralize = str => { + if (str.slice(-1) === "s") { + return str + "es"; + } + if (str.slice(-2) === "sh") { + return str + "es"; + } + return str + "s"; +}; + +const nounify = str => { + if (str.slice(-3) === "ate") { + return str.slice(0, str.length - 1) + "or"; + } + + if (isVowel(str.slice(-1))) { + return str + "r"; + } + + if (isVowel(str[str.length - 2]) && isVowel(str[str.length - 3])) { + return str + "er"; + } + + if (isVowel(str[str.length - 2])) { + return str + str.slice(-1) + "er"; + } + + return str + "er"; +}; + +const ingify = str => { + if (isVowel(str.slice(-1))) { + return str.slice(0, str.length - 1) + "ing"; + } + + if (isVowel(str[str.length - 2]) && isVowel(str[str.length - 3])) { + return str + "ing"; + } + + if (isVowel(str[str.length - 2])) { + return str + str.slice(-1) + "ing"; + } + + return str + "ing"; +}; + + +const randomElement = arr => { + if (arr[0] && arr[0].weight) { + const totalWeight = arr.reduce((acc, curr) => acc + curr.weight, 0); + const rand = Math.random() * totalWeight; + let count = 0, index = 0; + + do { + count += arr[index].weight; + index++; + } while (count < rand); + + return arr[index - 1].value; + } else { + const index = Math.floor(Math.random() * arr.length); + return arr[index]; + } +}; + +const replacePatternWithModifier = buckets => (_, modifier, bucketName) => { + const phrase = select(bucketName, buckets); + + switch (modifier) { + case "s": + return addIndefiniteArticle(phrase); + case "c": + return capitalize(phrase); + case "p": + return pluralize(phrase); + case "n": + return nounify(phrase); + case "v": + return ingify(phrase); + default: + return phrase; + } +}; + +const replaceSimplePattern = buckets => (_, bucketName) => + select(bucketName, buckets); + +function parse(str, buckets) { + let output = str; + const repeatingMatch = str.match(/r{(.*?)}/); + + if (repeatingMatch) { + const phrase = parse(repeatingMatch[1], buckets); + + output = output.replace(/r{.*?}/g, phrase); + } + + return output + .replace(/\((.)\)\[(.*?)]/g, replacePatternWithModifier(buckets)) + .replace(/\[(.*?)]/g, replaceSimplePattern(buckets)); +} + +function select(bucketName, buckets) { + const phrase = randomElement(buckets[bucketName]); + + return parse(phrase, buckets); +} + +const getInsult = (buckets = importedBuckets) => + capitalize(select("insults", buckets));