use crate::config::GlobalData; use crate::error::Error; use j_db::database::Database; use j_db::model::JdbModel; use rand::distributions::{Distribution, Standard}; 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_frankenstein(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::alembic:"); msg.emoji(emoji); msg.push_line(":microscope::test_tube:"); 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_magic(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::tophat:"); msg.emoji(emoji); msg.push_line(":magic_wand::rabbit2:"); msg.push_line(":green_square::green_square::green_square::green_square::green_square:"); msg.build() } pub fn draw_resonance_cascade(emoji: &Emoji) -> String { let mut msg = MessageBuilder::new(); msg.push_line(":blue_square::blue_square::orange_square::blue_square::blue_square:"); msg.push_line(":yellow_circle::zap::black_large_square::zap::yellow_circle:"); msg.push_line(":blue_square::blue_square::zap::blue_square::blue_square:"); msg.push(":blue_square::gun:"); msg.emoji(emoji); msg.push_line(":gem::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_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_mining(emoji: &Emoji) -> String { let mut msg = MessageBuilder::new(); msg.push_line(":black_medium_square::black_medium_square::black_medium_square::black_medium_square::black_medium_square:"); msg.push_line(":black_medium_square::black_medium_square::black_medium_square::black_medium_square::black_medium_square:"); msg.push_line(":black_medium_square::black_medium_square::black_medium_square::black_medium_square::black_medium_square:"); msg.push(":black_medium_square::pick:"); msg.emoji(emoji); msg.push_line(":gem::black_medium_square:"); msg.push_line(":brown_square::brown_square::brown_square::brown_square::brown_square:"); msg.build() } pub fn draw_gone() -> 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::blue_square::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, Magic, AttemptingToCircumventDeath, AttemptingToNotCauseAResonanceCascade, Mining, PhasedIntoYourReality, } impl Distribution for Standard { fn sample(&self, rng: &mut R) -> LilFrenState { match rng.gen_range(0..10) { 0 => LilFrenState::Standing, 1 => LilFrenState::TaxFraud, 2 => LilFrenState::Sick, 3 => LilFrenState::Dancing, 4 => LilFrenState::Sleep, 5 => LilFrenState::Magic, 6 => LilFrenState::AttemptingToCircumventDeath, 7 => LilFrenState::AttemptingToNotCauseAResonanceCascade, 8 => LilFrenState::Mining, _ => LilFrenState::PhasedIntoYourReality, } } } #[derive(Debug, Clone, PartialOrd, PartialEq)] pub enum AliveState { Alive, DiedOfBoredom, DiedOfHunger, DiedOfThirst, } #[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.0..0.5), metabolism: thread_rng().gen_range(0.2..0.75), } } 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)? { if lil_fren.is_alive() != AliveState::Alive { return Ok(()); } let (hunger_diff, thirst_diff, entertainment_diff) = match lil_fren.state { LilFrenState::Standing => (-0.002, -0.002, -0.001), LilFrenState::TaxFraud => (-0.002, -0.002, 0.001), LilFrenState::Sick => (-0.005, -0.005, -0.001), LilFrenState::Dancing => (-0.005, -0.008, 0.01), LilFrenState::Sleep => (-0.001, -0.002, 0.00), LilFrenState::Magic => (-0.002, -0.002, 0.001), LilFrenState::AttemptingToCircumventDeath => (-0.002, -0.002, 0.001), LilFrenState::AttemptingToNotCauseAResonanceCascade => (-0.004, -0.004, 0.004), LilFrenState::Mining => (-0.006, -0.006, 0.001), LilFrenState::PhasedIntoYourReality => (0.0, 0.0, 0.0), }; lil_fren.hunger = (lil_fren.hunger + hunger_diff * self.metabolism).clamp(-1.0, 1.0); lil_fren.thirst = (lil_fren.thirst + thirst_diff * self.metabolism).clamp(-1.0, 1.0); lil_fren.thirst = (lil_fren.entertainment + entertainment_diff * self.smarts).clamp(-1.0, 1.0); 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), LilFrenState::Magic => draw_magic(emoji), LilFrenState::AttemptingToCircumventDeath => draw_frankenstein(emoji), LilFrenState::AttemptingToNotCauseAResonanceCascade => draw_resonance_cascade(emoji), LilFrenState::Mining => draw_mining(emoji), LilFrenState::PhasedIntoYourReality => draw_gone(), } } 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(); } }