pub mod admin; pub mod album; pub mod birthday; pub mod celeryman; pub mod color; pub mod emoji_race; pub mod fren_coin; pub mod joke; pub mod little_fren; pub mod motivate; pub mod shop; pub mod story; pub mod voices; use crate::api::web_server; use crate::discord::fren_coin::give_coin; use crate::discord::joke::random; use crate::discord::shop::restock_shop; use crate::models::birthday::BirthdayEntry; use crate::models::insult_compliment::{RandomResponseTemplate, ResponseType}; use crate::models::lil_fren::lil_fren_task; use crate::{help, hook, GlobalData}; use chrono::{Days, TimeZone, Timelike, Utc}; use rand::prelude::IteratorRandom; use rand::thread_rng; use serenity::async_trait; use serenity::client::Context; use serenity::framework::standard::{ help_commands, Args, CommandGroup, CommandResult, HelpOptions, }; use serenity::model::channel::{Message, ReactionType}; use serenity::model::gateway::Activity; use serenity::model::id::UserId; use serenity::model::prelude::{GuildId, OnlineStatus, Ready}; use serenity::prelude::{EventHandler, Mentionable}; use std::collections::HashSet; use std::time::Duration; pub struct Handler; static ERROR_MSG: &str = "OOPSIE WOOPSIE!! Uwu We made a fucky wucky!! A wittle fucko boingo! The admins at our headquarters are working VEWY HAWD to fix this!"; #[async_trait] impl EventHandler for Handler { async fn cache_ready(&self, ctx: Context, _guilds: Vec) { let ctx1 = ctx.clone(); tokio::spawn(async move { loop { lil_fren_task(&ctx1).await; } }); tokio::spawn(async move { let mut next_check = chrono_tz::America::Chicago .from_utc_datetime(&Utc::now().naive_utc()) .checked_sub_days(Days::new(1)) .unwrap(); loop { { println!("Restocking shop..."); restock_shop(&ctx).await.unwrap(); } { let now = chrono_tz::America::Chicago.from_utc_datetime(&Utc::now().naive_utc()); if now >= next_check { let data = ctx.data.read().await; let global_data = data.get::().unwrap(); let todays_birthdays = BirthdayEntry::todays_birthdays(&global_data.db, now.date_naive()) .unwrap(); for birth in todays_birthdays { if let Ok(user) = global_data .cfg .guild_id .member(&ctx.http, birth.discord_id) .await { global_data .cfg .announcement_channel .say(&ctx.http, format!("Happy birthday {}!", user.mention())) .await .unwrap(); let compliment = RandomResponseTemplate::get_random_response( &global_data.db, ResponseType::Compliment, user.display_name().as_str(), ) .unwrap() .unwrap(); global_data .cfg .announcement_channel .say(&ctx.http, compliment) .await .unwrap(); } } next_check = next_check .with_hour(7) .unwrap() .checked_add_days(Days::new(1)) .unwrap(); } } tokio::time::sleep(Duration::from_secs(60 * 60)).await; { { println!("Reloading config..."); let mut data = ctx.data.write().await; let global_data = data.get_mut::().unwrap(); global_data.reload().await.unwrap(); } } } }); } async fn message(&self, ctx: Context, new_message: Message) { if new_message.author.bot { return; } if new_message.guild_id.is_none() { return; } if new_message.content.eq_ignore_ascii_case("yes") || new_message.content.eq_ignore_ascii_case("mhmm") { let mut data = ctx.data.write().await; let global_data = data.get_mut::().unwrap(); if let Some(u) = global_data.bot_state.accepted_nsfw { if new_message.author.id == u { new_message.reply(&ctx.http, "||https://cdn.discordapp.com/attachments/614891432079130625/1041545254362423368/unknown.png||").await.unwrap(); global_data.bot_state.accepted_nsfw = None; } } } if new_message.content.to_lowercase().contains("good bot") { let recv_coin = give_coin(&ctx, new_message.author.id, 0.50, 25) .await .unwrap(); if recv_coin { let emojis = new_message.guild(&ctx.cache).unwrap().emojis; let emoji = { let mut rng = thread_rng(); emojis.iter().choose(&mut rng) }; if let Some(emoji) = emoji { new_message .react( &ctx.http, ReactionType::Custom { animated: emoji.1.animated, id: emoji.1.id, name: Some(emoji.1.name.clone()), }, ) .await .unwrap(); } } } if new_message.content.to_lowercase().contains("bad bot") { new_message.react(&ctx.http, '😭').await.unwrap(); } give_coin(&ctx, new_message.author.id, 0.05, 10) .await .unwrap(); } async fn ready(&self, ctx: Context, ready: Ready) { println!("Connected as {}", ready.user.name); ctx.set_presence( Some(Activity::listening("to your deepest secrets")), OnlineStatus::Online, ) .await; tokio::spawn(async move { web_server(ctx).await }); } } #[hook] pub async fn after( ctx: &Context, msg: &Message, command_name: &str, command_result: CommandResult, ) { match command_result { Ok(()) => { println!("Processed command '{}'", command_name); let data = ctx.data.read().await; let global_data = data.get::().unwrap(); global_data.db.db.flush_async().await.unwrap(); } Err(why) => { println!("Command '{}' returned error {:?}", command_name, why); msg.reply( &ctx.http, format!("{} (Error in command {})", ERROR_MSG, command_name), ) .await .unwrap(); } } } #[hook] pub async fn unrecognised_command_hook( ctx: &Context, msg: &Message, unrecognised_command_name: &str, ) { let contents_split: Vec<&str> = msg.content.split(' ').collect(); let tags = if contents_split.len() > 1 { contents_split[1..].to_vec() } else { Vec::new() }; let parsed_album = match album::parse_album(ctx, msg, unrecognised_command_name, tags).await { Ok(parsed) => parsed, Err(e) => { println!("Error processing album command: {}", e); true } }; if !parsed_album { match random(ctx, msg, unrecognised_command_name).await { Ok(_) => {} Err(e) => println!("Error processing random command: {}", e), } } give_coin(ctx, msg.author.id, 0.5, 10).await.unwrap(); } #[help] pub async fn my_help( context: &Context, msg: &Message, args: Args, help_options: &'static HelpOptions, groups: &[&'static CommandGroup], owners: HashSet, ) -> CommandResult { let _ = help_commands::with_embeds(context, msg, args, help_options, groups, owners).await; Ok(()) }