use crate::config::GlobalData; use crate::error::Error; use j_db::database::Database; use j_db::model::JdbModel; use rand::distributions::Standard; use rand::prelude::Distribution; use rand::{thread_rng, Rng}; use serde::{Deserialize, Serialize}; use serenity::model::guild::Emoji; use serenity::model::id::{EmojiId, GuildId}; use serenity::prelude::Context; use serenity::utils::MessageBuilder; use std::time::Duration; pub fn draw_standing(emoji: &Emoji) -> String { let mut msg = MessageBuilder::new(); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push(":blue_square::blue_square:"); msg.emoji(emoji); msg.push_line(":blue_square::blue_square:"); msg.push_line(":green_square::green_square::green_square::green_square::green_square:"); msg.build() } pub fn draw_dancing(emoji: &Emoji) -> String { let mut msg = MessageBuilder::new(); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::blue_square::notes::blue_square:"); msg.push_line(":blue_square::notes::blue_square::notes::blue_square:"); msg.push(":blue_square::blue_square:"); msg.emoji(emoji); msg.push_line(":blue_square::blue_square:"); msg.push_line(":green_square::green_square::green_square::green_square::green_square:"); msg.build() } pub fn draw_tax_fraud(emoji: &Emoji) -> String { let mut msg = MessageBuilder::new(); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push(":blue_square::page_with_curl:"); msg.emoji(emoji); msg.push_line(":blue_square::blue_square:"); msg.push_line(":green_square::green_square::green_square::green_square::green_square:"); msg.build() } pub fn draw_sick(emoji: &Emoji) -> String { let mut msg = MessageBuilder::new(); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push(":blue_square::bucket:"); msg.emoji(emoji); msg.push_line(":roll_of_paper::blue_square:"); msg.push_line(":green_square::green_square::green_square::green_square::green_square:"); msg.build() } pub fn draw_sleep(emoji: &Emoji) -> String { let mut msg = MessageBuilder::new(); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push(":blue_square::blue_square:"); msg.emoji(emoji); msg.push_line(":blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::bed::blue_square::blue_square:"); msg.push_line(":green_square::green_square::green_square::green_square::green_square:"); msg.build() } pub fn draw_dead() -> String { let mut msg = MessageBuilder::new(); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::headstone::blue_square::blue_square:"); msg.push_line(":green_square::green_square::green_square::green_square::green_square:"); msg.build() } pub fn draw_feed(emoji: &Emoji, food: &str) -> String { let mut msg = MessageBuilder::new(); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push_line(":blue_square::blue_square::blue_square::blue_square::blue_square:"); msg.push(":blue_square::blue_square:"); msg.emoji(emoji); msg.push(food); msg.push_line(":blue_square:"); msg.push_line(":green_square::green_square::green_square::green_square::green_square:"); msg.build() } #[derive(Debug, Deserialize, Serialize, Clone, PartialOrd, PartialEq)] pub enum LilFrenState { Standing, TaxFraud, Sick, Dancing, Sleep, } #[derive(Debug, Clone, PartialOrd, PartialEq)] pub enum AliveState { Alive, DiedOfBoredom, DiedOfHunger, DiedOfThirst, } impl Distribution for Standard { fn sample(&self, rng: &mut R) -> LilFrenState { match rng.gen_range(0..100) { 0..=30 => LilFrenState::Standing, 31..=40 => LilFrenState::TaxFraud, 41..=50 => LilFrenState::Sick, 51..=70 => LilFrenState::Dancing, _ => LilFrenState::Sleep, } } } #[derive(Debug, Deserialize, Serialize, Clone)] pub struct LilFren { id: Option, pub emoji: EmojiId, pub hunger: f32, pub thirst: f32, pub entertainment: f32, pub state: LilFrenState, pub smarts: f32, pub metabolism: f32, } impl JdbModel for LilFren { fn id(&self) -> Option { self.id } fn set_id(&mut self, id: u64) { self.id = Some(id) } fn tree() -> String { "LilFren".to_string() } } impl LilFren { pub fn new(emoji: EmojiId) -> Self { Self { id: None, emoji, hunger: 1.0, thirst: 1.0, entertainment: 1.0, state: LilFrenState::Standing, smarts: thread_rng().gen_range(0.1..1.0), metabolism: thread_rng().gen_range(0.1..1.0), } } pub fn create_new_lil_fren(db: &Database, emoji: EmojiId) -> Result { let lil_fren: Option = Self::get_lil_fren(db)?; if let Some(lil_fren) = lil_fren { db.remove::(lil_fren.id().unwrap())?; } let lil_fren = db.insert(Self::new(emoji))?; Ok(lil_fren) } pub fn get_lil_fren(db: &Database) -> Result, Error> { Ok(db.filter(|_, _fren: &Self| true)?.next()) } pub fn update_fren(&mut self, db: &Database) -> Result<(), Error> { if let Some(mut lil_fren) = Self::get_lil_fren(db)? { let (hunger_diff, thirst_diff, entertainment_diff) = match lil_fren.state { LilFrenState::Standing => (-0.01, -0.02, -0.01), LilFrenState::TaxFraud => (-0.01, -0.02, 0.01), LilFrenState::Sick => (-0.1, -0.15, -0.01), LilFrenState::Dancing => (-0.05, -0.8, 0.05), LilFrenState::Sleep => (-0.005, -0.01, 0.00), }; lil_fren.hunger -= hunger_diff * self.metabolism; lil_fren.thirst -= thirst_diff * self.metabolism; lil_fren.entertainment -= entertainment_diff * self.smarts; if thread_rng().gen_bool(0.75) { println!("fren is now {:?}", self.state); lil_fren.state = thread_rng().gen(); } db.insert(lil_fren)?; } Ok(()) } pub fn is_alive(&self) -> AliveState { if self.thirst < 0.0 { AliveState::DiedOfThirst } else if self.entertainment < 0.0 { AliveState::DiedOfBoredom } else if self.hunger < 0.0 { AliveState::DiedOfHunger } else { AliveState::Alive } } fn draw_activity(&self, emoji: &Emoji) -> String { match self.state { LilFrenState::Standing => draw_standing(emoji), LilFrenState::TaxFraud => draw_tax_fraud(emoji), LilFrenState::Sick => draw_sick(emoji), LilFrenState::Dancing => draw_dancing(emoji), LilFrenState::Sleep => draw_sleep(emoji), } } pub async fn draw(&self, ctx: &Context, guild: &GuildId) -> String { let emoji = guild.emoji(&ctx.http, self.emoji).await.unwrap(); let alive_state = self.is_alive(); if let AliveState::Alive = alive_state { self.draw_activity(&emoji) } else { draw_dead() } } } pub async fn lil_fren_task(ctx: &Context) { tokio::time::sleep(Duration::from_secs(60)).await; let data = ctx.data.read().await; let global_data = data.get::().unwrap(); let fren = LilFren::get_lil_fren(&global_data.db).unwrap(); if let Some(mut fren) = fren { fren.update_fren(&global_data.db).unwrap(); } }