#![allow(clippy::unreadable_literal)] use owoify::OwOifiable; use rand::Rng; use serenity::{ client::Client, framework::standard::{ macros::{check, command, group}, Args, CheckResult, CommandOptions, CommandResult, DispatchError, Reason, StandardFramework, }, model::{channel::Message, gateway::Ready, id::UserId, user::OnlineStatus}, prelude::*, }; use std::{env, process}; struct Handler; impl EventHandler for Handler { fn ready(&self, ctx: Context, ready: Ready) { if let Some(shard) = ready.shard { println!( "INFO: {} is connected on shard {}/{}!\nuwu", ready.user.name, shard[0], shard[1] ); use serenity::model::gateway::Activity; let activity = Activity::listening("catgirls nyaaing"); let status = OnlineStatus::Online; ctx.set_presence(Some(activity), status); } } } #[group] #[commands( init, ping, halt, list_srv, host, ship, headpat, uwu, gayculator, waffle, sausage, help, embed, what, owo, info )] struct General; fn main() { let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("Invalid token"), Handler) .expect("Error creating client"); client.with_framework( StandardFramework::new() .configure(|c| { c.with_whitespace(true) .owners(vec![UserId(254310746450690048)].into_iter().collect()) .prefixes(vec!["owo ", "OwO "]) .no_dm_prefix(true) .case_insensitivity(true) .by_space(false) }) .on_dispatch_error(|ctx, msg, error| { if let DispatchError::CheckFailed("Owner", Reason::Unknown) = error { let _ = msg.channel_id.say(&ctx.http, "nyo"); } else if let DispatchError::Ratelimited(seconds) = error { let _ = msg .channel_id .say(&ctx.http, &format!("Try again in {} seconds.", seconds)); } }) .group(&GENERAL_GROUP), ); if let Err(e) = client.start() { println!("An error occurred while running the client: {:?}", e); } } #[check] #[name = "Owner"] fn owner_check(_: &mut Context, msg: &Message, _: &mut Args, _: &CommandOptions) -> CheckResult { if msg.author.id == 254310746450690048 { CheckResult::Success } else { CheckResult::Failure(Reason::Unknown) } } #[check] #[name = "Server"] fn server_check(_: &mut Context, msg: &Message, _: &mut Args, _: &CommandOptions) -> CheckResult { (msg.guild_id == Some(serenity::model::id::GuildId(255386835964919810))).into() } #[command] fn init(ctx: &mut Context, message: &Message) -> CommandResult { let num = rand::thread_rng().gen_range(0, 2); match num { 0 => { let _ = message .channel_id .say(&ctx.http, "The Discordinator9000 is gonna hug ny'all!"); } 1 => { let _ = message.channel_id.say(&ctx.http, "Nyaa~!"); } _ => { let _ = message.channel_id.say(&ctx.http, "Oopsie woopsie! UwU"); } } Ok(()) } #[command] fn ping(ctx: &mut Context, message: &Message) -> CommandResult { let _ = message.reply(&ctx, "Pong!"); Ok(()) } #[command] #[checks(Owner)] fn halt(ctx: &mut Context) -> CommandResult { ctx.set_presence(None, OnlineStatus::Offline); use std::{thread, time}; let one_s = time::Duration::new(2, 0); thread::sleep(one_s); process::exit(0); } #[command] #[checks(Owner)] fn list_srv(ctx: &mut Context, message: &Message) -> CommandResult { let mut list = String::new(); let cache = ctx.cache.read(); for (index, guild_lock) in cache.guilds.values().enumerate() { let guild = guild_lock.read(); list.push_str(&format!("{}: {}\n", index, guild.name)); } let _ = message .channel_id .say(&ctx.http, list.replace("@", "@\u{200B}")); Ok(()) } #[command] #[checks(Owner)] fn host(ctx: &mut Context, message: &Message) -> CommandResult { let _ = message.channel_id.say( &ctx.http, format!( "Debug\nOS: {:?}\nHost: {:?}", sys_info::os_type().unwrap(), sys_info::hostname().unwrap() ), ); Ok(()) } #[command] #[checks(Owner)] fn embed(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { use serde::Deserialize; use serenity::utils::Colour; #[derive(Deserialize)] struct EmbedProperties { author: Option<(String, String)>, colour: String, description: Option, fields: Option>, footer: Option<(String, String)>, image: Option, timestamp: Option, title: Option, url: Option, } let input_embed: EmbedProperties = toml::from_str(args.rest().trim()).unwrap_or(EmbedProperties { author: None, colour: 000000.to_string(), description: None, fields: None, footer: None, image: None, timestamp: None, title: None, url: None, }); let _ = message.channel_id.send_message(&ctx.http, |m| { m.embed(|e| { // Set embed author unless empty if input_embed.author != None { let auth = input_embed.author.unwrap(); e.author(|a| { //assuming first array element is name and second is icon url a.name(auth.0); a.icon_url(auth.1); a }); } e.color(Colour::new( u32::from_str_radix(&input_embed.colour, 16) .ok() .unwrap_or(0x000000), )); // Set embed description unless empty if input_embed.description != None { e.description(input_embed.description.unwrap()); } // Set embed fields unless empty if input_embed.fields != None { e.fields(input_embed.fields.unwrap()); } // Set embed footer unless empty if input_embed.footer != None { let foot = input_embed.footer.unwrap(); e.footer(|f| { //assuming first array element is name and second is icon url f.text(foot.0); f.icon_url(foot.1); f }); } if input_embed.image != None { e.image(input_embed.image.unwrap()); } if input_embed.timestamp != None { e.timestamp(input_embed.timestamp.unwrap()); } if input_embed.title != None { e.title(input_embed.title.unwrap()); } if input_embed.url != None { e.url(input_embed.url.unwrap()); } e }); m }); Ok(()) } #[command] fn ship(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { use rand::{rngs::StdRng, SeedableRng}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; // Calculates hash of a type that implements Hash fn calculate_hash(t: &T) -> u64 { let mut s = DefaultHasher::new(); t.hash(&mut s); s.finish() } // Get input names let names: String = args.rest().trim().to_string(); // Calculate compatibility based on hash let compat: u64 = StdRng::seed_from_u64(calculate_hash(&names)).gen_range(0, 100); // Initialize a bar to display compatibility percentage let mut compbar = String::new(); let mut num = 0; while num < compat / 10 { compbar.push('▬'); num += 1; } compbar.push_str(":purple_heart:"); num = 0; while num < (10 - compat / 10) { compbar.push('▬'); num += 1; } // Convert names to a Vec let names = names .split_whitespace() .map(|x| x.to_owned()) .collect::>(); let shipname: Result = match names.len() { 0 => Err(()), 1 => Ok(names[0].clone()), _ => { let mut first_halves = String::new(); for name in &names[0..names.len() - 1] { first_halves.push_str(&name[0..name.len() / 2]); } let first_halves = first_halves.as_str(); let last_half = &names[names.len() - 1][(names.len() / 2) + 1..]; Ok(format!("{}{}", first_halves, last_half)) } }; let _ = message.channel_id.send_message(&ctx.http, |m| { m.embed(|e| { e.title(format!("Original names: {}", args.rest().trim())) .description(format!( "Ship name:\n**{}**\nCompatibility: **{}%**\n{}", shipname.unwrap_or_else(|_| "Invalid input!".to_string()), compat, compbar )) .color(0xffd1dc) }) }); Ok(()) } #[command] fn headpat(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { message .channel_id .send_message(&ctx.http, |m| { m.embed(|e| { e.title(format!("Sending headpats to **{}**...", args.rest().trim())) .image("https://i.pinimg.com/originals/83/1a/90/831a903eab6d827dcfd298b9e3196e30.jpg") .description("[Source](https://www.pinterest.com/pin/377809856242075277/)") }) }) .expect("Failed to send message!"); Ok(()) } #[command] fn uwu(ctx: &mut Context, message: &Message) -> CommandResult { let num = rand::thread_rng().gen_range(0, 4); match num { 0 => { let _ = message.channel_id.send_message(&ctx.http, |m| m .embed(|e| e .image("https://i.redditmedia.com/qDD9W7NJqTAk31y061TuRW9R8qOcCuEmmCWyOsUEavE.png?fit=crop&crop=faces%2Centropy&arh=2&w=640&s=ebdd3f1970b4fe70ccd24a1958e7fc32") )); } 1 => { let _ = message.channel_id.send_message(&ctx.http, |m| m .embed(|e| e .image("https://www.shitpostbot.com/img/sourceimages/smash-that-mfuckn-uwu-button-57b5aa1de9fe4.jpeg") )); } 2 => { let _ = message.channel_id.send_message(&ctx.http, |m| { m.embed(|e| { e .image("https://www.shitpostbot.com/img/sourceimages/fallout-nv-owo-57e586ae15322.jpeg") }) }); } 3 => { let _ = message.channel_id.send_message(&ctx.http, |m| m .embed(|e| e .image("https://i.redditmedia.com/-JaK9YW7mPz2S2xBJmXvW4fZ58uGMa4l6GIgYt3dqZg.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=640&s=ebab29a577346b4d18ec914538b69bb4") )); } _ => { let _ = message.channel_id.say(&ctx.http, "UwU"); } } Ok(()) } #[command] fn gayculator(ctx: &mut Context, message: &Message, mut args: Args) -> CommandResult { //the amiter check if message.author.id != 191948420141809665 { let number_32: i32 = args.single::().unwrap_or(1); let result = if number_32 % 2 == 0 { "much straight" } else { "large gay" }; let _ = message.channel_id.send_message(&ctx.http, |m| { m.embed(|e| { e.title("Gayness level:") .description(result) .color(0xffd1dc) }) }); } Ok(()) } #[command] fn waffle(ctx: &mut Context, message: &Message) -> CommandResult { let _ = message.channel_id.say(&ctx.http, "h"); Ok(()) } #[command] fn sausage(ctx: &mut Context, message: &Message) -> CommandResult { let _ = message.channel_id.send_message(&ctx.http, |m| { m.embed(|e| { e .title("Dongle!") .image("https://cdn.discordapp.com/attachments/379673147764506624/431546724637736971/image.png") }) }); Ok(()) } /* #[command] #[checks(Server)] fn ad(ctx: &mut Context, message: &Message) -> CommandResult { let _ = message.channel_id.send_message(&ctx.http, |m| m .embed(|e| e .title(":b:ottom text") ***REMOVED*** .thumbnail("https://i.imgur.com/8MU0gqD.png") .color(0x00f3ff)) ); Ok(()) } */ #[command] fn help(ctx: &mut Context, message: &Message) -> CommandResult { let _ = message.channel_id.send_message(&ctx.http, |m| { m.embed(|e| { e.title("Availble commands:") .description("All commands are case-insensitive") .fields(vec![ ("owo init", "Introduce me", false), ("owo ping", "Pong", false), ("owo waffle", "stroopwafel owo", false), ("owo sausage", "sosig", false), ("owo help", "Help the fellow humanz!", false), ("owo info", "Show information about me!", false), /*( "owo compare_bot ``bot's name``", "Compare me to other robots!", false, ), */ ( "owo what's this ``word``", "Find a definition of word", false, ), ("owo ship ``[names]``", "*shipping intensifies*", false), ("owo headpat ``name``", "Headpat someone", false), ("owo owo ``text``", "owoify input text", false), ("\u{200B}", "**Admin commands:**", false), ("owo halt", "kill me", false), ("owo list_srv", "list my servers", false), ( "owo embed ``[args]``", "Create an embed from a Toml object", false, ), ("owo host", "Display host info", false), ]) .color(0xffd1dc) }) }); Ok(()) } #[command] fn info(ctx: &mut Context, message: &Message) -> CommandResult { let num = ctx.cache.read().guilds.len(); let _ = message.channel_id.send_message(&ctx.http, |m| m .embed(|e| e .title("Discordinator9000's info:") .description("h") .field("Author:", "#9000 / Agatha", false) .field("Server count:", num , false) .field("Invite:", "[Invite link](https://discordapp.com/api/oauth2/authorize?client_id=470350233419907129&permissions=2048&scope=bot)", false ) .footer(|f| f .text("Written in Rust using Serenity, OwOify and a few other libraries")) .color(0xee657) )); Ok(()) } /* #[command] #[aliases("compare")] fn compare_bot(ctx: &mut Context, message: &Message, mut args: Args) -> CommandResult { //the amiter check if message.author.id != 191948420141809665 { let text: String = args .single::() .unwrap_or_else(|_| "Null".to_string()); if text.to_lowercase().contains("nib") { let _ = message.channel_id.say(&ctx.http, "I am superior to NibBot"); } else if text.to_lowercase().contains("amit") { let _ = message.channel_id.say(&ctx.http, "Amiter is big dumb"); } else if text.to_lowercase().contains("discordinator") { let _ = message.channel_id.say(&ctx.http, "Option<(!, ())>"); } else { let _ = message .channel_id .say(&ctx.http, format!("Me and {} are friends!", text)); } } Ok(()) } */ #[command] #[aliases("what's this")] fn what(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { let text: String = args.rest().trim().to_string(); let defs = &urbandict::get_definitions(&text); match defs { Err(_e) => { let _ = message.channel_id.say(&ctx.http, "Invalid query >w<"); } Ok(v) => { if !v.is_empty() { let def = &v[0]; let _ = message.channel_id.send_message(&ctx.http, |m| { m.embed(|e| { e.title(format!("Author: {}", def.author)).field( "Definition: ", def.definition.replace(|c| c == '[' || c == ']', ""), false, ) }) }); } else { println!("No resuwults"); } } } Ok(()) } #[command] fn owo(ctx: &mut Context, message: &Message, args: Args) -> CommandResult { let input: String = args.rest().trim().to_string(); let _ = message.channel_id.say(&ctx.http, input.owoify()); Ok(()) }