Added 911 command

This commit is contained in:
Joey Hines 2026-06-28 13:18:03 -06:00
parent bb6a961c22
commit 88440fb7af
Signed by: joeyahines
GPG Key ID: E99D8FB14855100E
3 changed files with 211 additions and 2 deletions

202
src/discord/emergency.rs Normal file
View File

@ -0,0 +1,202 @@
use crate::discord::Context;
use crate::discord::is_not_cancelled;
use crate::error::Error;
use crate::inventory::ItemType;
use crate::models::lil_fren::LilFren;
use crate::user::User;
use log::info;
use poise::serenity_prelude::{Mentionable, UserId, parse_user_mention};
use rand::distr::StandardUniform;
use rand::prelude::Distribution;
use rand::{Rng, RngExt};
use std::cmp::PartialEq;
use std::collections::HashSet;
use std::time::Duration;
#[derive(Debug, PartialEq, Eq)]
pub enum Outcomes {
EveryoneDies,
DogDies,
AllInvolvedDie,
CallerDies,
SuspectDies,
CopsWriteCallerATicket,
CopsWriteSuspectATicket,
CopsNeverShowUp,
}
impl Outcomes {
pub fn msg(&self, caller: &str, suspects: &[String]) -> String {
let suspect_str = suspects.join(",");
match self {
Outcomes::EveryoneDies => {
"ON YOUR KNEES, ON THE GROUND, THEY'RE ALL REACHING!!!! *gunshot noises* Thank god we did that ICE training, that could have been really bad.".to_string()
}
Outcomes::DogDies => {
"OH FUCK IS THAT A DOG IN A CLIPPERS JERSY, SHOOT IT *gunshot noises* (you might want to check lil buddy)".to_string()
}
Outcomes::AllInvolvedDie => {
"*gunshot noises* Hey... umm... this wasn't the active shooter call. We kinda just killed everyone... oh well".to_string()
}
Outcomes::CallerDies => {
format!("*gunshot noises* Damn {caller} was a bitch, glad they are shut up thanks to my trust government furnished killing machine; a gun!")
}
Outcomes::SuspectDies => {
format!("SUSPECT IS FLEEING THE SCENE. {suspect_str} is heading towards #uwu-cuite-zone. THINK OF THE KIDS. *gunshot noises*")
}
Outcomes::CopsWriteCallerATicket => {
format!("After a long invesigation, I have to give you {caller} a ticket. Really sorry, but I'm under my quota for your race group... I MEAN yeah please only water your grass on Tuesdays and Wednesdays")
}
Outcomes::CopsWriteSuspectATicket => {
format!("{suspect_str}, for disturbing the peace you are hereby CHARGED with TOMFOOLERY. With A HEFTY fine.")
}
Outcomes::CopsNeverShowUp => {
"".to_string()
}
}
}
}
impl Distribution<Outcomes> for StandardUniform {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Outcomes {
match rng.random_range(0..100) {
0 => Outcomes::EveryoneDies,
1 => Outcomes::DogDies,
2..=10 => Outcomes::AllInvolvedDie,
11..=30 => Outcomes::CallerDies,
31..=50 => Outcomes::SuspectDies,
51..=70 => Outcomes::CopsWriteCallerATicket,
71..=90 => Outcomes::CopsWriteSuspectATicket,
_ => Outcomes::CopsNeverShowUp,
}
}
}
#[poise::command(
prefix_command,
guild_only,
aliases("911"),
category = "emergency",
check = "is_not_cancelled",
user_cooldown = 3600
)]
pub async fn call_911(ctx: Context<'_>, #[rest] msg: String) -> Result<(), Error> {
ctx.reply("Thank you for reporting your emergency Fren PD is on the case!")
.await?;
let mut involved_parties = HashSet::new();
let role_regex = regex::Regex::new("<@.*>").unwrap();
for mention in role_regex.find_iter(&msg) {
if let Some(user_id) = parse_user_mention(mention.as_str()) {
involved_parties.insert(user_id);
}
}
let involved_parties: Vec<UserId> = involved_parties.iter().cloned().collect();
let outcome: Outcomes = rand::rng().random();
let response_time = match rand::random_range(0..100) {
0..=60 => rand::random_range(1..20),
61..=90 => rand::random_range(20..60 * 2),
_ => rand::random_range(60 * 2..60 * 48),
};
if outcome == Outcomes::CopsNeverShowUp {
info!("Nope, they never coming");
return Ok(());
}
info!("Sleeping for {response_time} minutes until the cops show up.");
tokio::time::sleep(Duration::from_mins(response_time)).await;
ctx.reply("🚨 FREN PD IS HERE! NO ONE MOVE! 🚨").await?;
let involved_party_names: Vec<String> = involved_parties
.iter()
.map(|m| m.mention().to_string())
.collect();
ctx.reply(outcome.msg(&ctx.author().mention().to_string(), &involved_party_names))
.await?;
match outcome {
Outcomes::EveryoneDies => {
let members: Vec<UserId> = ctx.guild().unwrap().members.keys().copied().collect();
for member in members {
User::use_item_on_user(
ctx,
member,
ctx.guild_id().unwrap(),
ItemType::KillGun,
&None,
)
.await?;
}
}
Outcomes::DogDies => {
let lil_buddy = LilFren::get_lil_fren(&ctx.data().db)?;
if let Some(mut lil_buddy) = lil_buddy {
lil_buddy.hunger = -500.0;
lil_buddy.thirst = -500.0;
ctx.data().db.insert(lil_buddy)?;
}
}
Outcomes::AllInvolvedDie => {
User::use_item_on_user(
ctx,
ctx.author().id,
ctx.guild_id().unwrap(),
ItemType::KillGun,
&None,
)
.await?;
for suspect in involved_parties {
User::use_item_on_user(
ctx,
suspect,
ctx.guild_id().unwrap(),
ItemType::KillGun,
&None,
)
.await?;
}
}
Outcomes::CallerDies => {
User::use_item_on_user(
ctx,
ctx.author().id,
ctx.guild_id().unwrap(),
ItemType::KillGun,
&None,
)
.await?;
}
Outcomes::SuspectDies => {
for suspect in involved_parties {
User::use_item_on_user(
ctx,
suspect,
ctx.guild_id().unwrap(),
ItemType::KillGun,
&None,
)
.await?;
}
}
Outcomes::CopsWriteCallerATicket => {
User::take_funds(&ctx.data().db, ctx.author().id, 1000)?;
}
Outcomes::CopsWriteSuspectATicket => {
for suspect in involved_parties {
User::take_funds(&ctx.data().db, suspect, 1000)?;
}
}
Outcomes::CopsNeverShowUp => {}
}
Ok(())
}

View File

@ -5,6 +5,7 @@ mod album;
mod birthday; mod birthday;
mod celeryman; mod celeryman;
mod color; mod color;
mod emergency;
mod emoji_race; mod emoji_race;
mod fren_coin; mod fren_coin;
mod image; mod image;
@ -383,6 +384,7 @@ pub async fn run_bot(global_data: GlobalData) {
celeryman::tayne(), celeryman::tayne(),
color::set_color(), color::set_color(),
color::remove_color(), color::remove_color(),
emergency::call_911(),
emoji_race::bet(), emoji_race::bet(),
emoji_race::race(), emoji_race::race(),
emoji_race::start_race(), emoji_race::start_race(),

View File

@ -9,12 +9,13 @@ use chrono::{Days, Duration, TimeDelta, TimeZone, Timelike, Utc};
use j_db::database::Database; use j_db::database::Database;
use j_db::model::JdbModel; use j_db::model::JdbModel;
use log::{error, info}; use log::{error, info};
use poise::serenity_prelude::ChannelId;
use poise::serenity_prelude::all::Mentionable; use poise::serenity_prelude::all::Mentionable;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::ops::Add; use std::ops::Add;
use std::sync::Arc; use std::sync::Arc;
#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
pub enum TaskType { pub enum TaskType {
RemoveRole { user_id: u64, role_id: u64 }, RemoveRole { user_id: u64, role_id: u64 },
CheckBirthdays, CheckBirthdays,
@ -22,6 +23,7 @@ pub enum TaskType {
RestockShop, RestockShop,
UpdateLilBuddy, UpdateLilBuddy,
UpdateGogurtRate, UpdateGogurtRate,
Say { msg: String, channel: ChannelId },
} }
impl TaskType { impl TaskType {
@ -80,7 +82,7 @@ impl Task {
db.insert::<Task>(Task { db.insert::<Task>(Task {
id: None, id: None,
task_type, task_type: task_type.clone(),
time, time,
})?; })?;
@ -207,6 +209,9 @@ impl Task {
GogurtReserves::get_next_market_update_time(&data.db)?, GogurtReserves::get_next_market_update_time(&data.db)?,
)?; )?;
} }
TaskType::Say { ref msg, channel } => {
channel.say(&ctx.http, msg).await?;
}
} }
let _ = data.db.remove::<Task>(task.id().unwrap()).is_ok(); let _ = data.db.remove::<Task>(task.id().unwrap()).is_ok();