Updated serenity version and added new commands

+ Added task.rs to handle periodic tasks
This commit is contained in:
2024-01-15 16:53:17 -07:00
parent 8ec84ff946
commit 67ff69aca0
20 changed files with 1978 additions and 1038 deletions
+55 -9
View File
@@ -1,20 +1,31 @@
use crate::config::BotConfig;
use crate::inventory::ItemType;
use crate::models::api_key::Apikey;
use crate::models::lil_fren::{
draw_dancing, draw_frankenstein, draw_gone, draw_magic, draw_mining, draw_resonance_cascade,
draw_sick, draw_sleep, draw_standing, draw_tax_fraud, AliveState, LilFren,
};
use crate::user::User;
use crate::{command, group, GlobalData};
use json::JsonValue;
use serenity::all::{CreateAttachment, CreateMessage};
use serenity::client::Context;
use serenity::framework::standard::{Args, CommandResult};
use serenity::model::channel::{AttachmentType, Message};
use serenity::model::channel::Message;
use serenity::model::misc::EmojiIdentifier;
use serenity::model::prelude::UserId;
use std::borrow::Cow;
#[group]
#[commands(reload, dump_db, load_db, add_key, debug_buddy, draw_buddy_states)]
#[commands(
reload,
dump_db,
load_db,
add_key,
debug_buddy,
draw_buddy_states,
op_give
)]
pub struct ADMIN;
pub fn is_admin(user_id: &UserId, cfg: &BotConfig) -> bool {
@@ -53,13 +64,15 @@ async fn dump_db(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
.id
.create_dm_channel(&ctx.http)
.await?
.send_message(&ctx.http, |m| {
m.content("The current DB state")
.add_file(AttachmentType::Bytes {
data: Cow::from(output.as_bytes()),
filename: "db.json".to_string(),
})
})
.send_message(
&ctx.http,
CreateMessage::new()
.content("The current DB state")
.add_file(CreateAttachment::bytes(
Cow::from(output.as_bytes()),
"db.json".to_string(),
)),
)
.await?;
Ok(())
@@ -186,3 +199,36 @@ async fn draw_buddy_states(ctx: &Context, msg: &Message, args: Args) -> CommandR
Ok(())
}
#[command]
#[description("Hey can I get op? I'm from planet minecraft")]
async fn op_give(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let mut data = ctx.data.write().await;
let global_data = data.get_mut::<GlobalData>().unwrap();
if args.is_empty() {
msg.reply(&ctx.http, "You need to select an item to give")
.await?;
return Ok(());
}
let msg_content = args.rest().to_lowercase();
let item = match msg_content.parse::<ItemType>() {
Ok(i) => i,
Err(_) => {
msg.reply(&ctx.http, "I don't know what the heck that is tbh.")
.await?;
return Ok(());
}
};
User::give_item(&global_data.db, msg.author.id, item, 1, None)?;
msg.reply(
&ctx,
format!("[Console] Op has given {} 1 {}", msg.author.name, item),
)
.await?;
Ok(())
}
+10 -8
View File
@@ -44,13 +44,13 @@ pub async fn add_birthday(ctx: &Context, msg: &Message, args: Args) -> CommandRe
let data = ctx.data.read().await;
let global_data = data.get::<GlobalData>().unwrap();
BirthdayEntry::add_birthday(&global_data.db, msg.author.id.0, date)?;
BirthdayEntry::add_birthday(&global_data.db, msg.author.id.get(), date)?;
msg.reply(
&ctx.http,
format!(
"Thank you subject #{}, I am now {}% closer to making a full AI replica of you.",
msg.author.id.0,
msg.author.id.get(),
thread_rng().gen_range(0.0..100.0)
),
)
@@ -78,14 +78,16 @@ pub async fn list_birthdays(ctx: &Context, msg: &Message) -> CommandResult {
msg_builder.push_bold_line("All the birthdays I know:");
for birthday in birthdays {
let user = msg
.guild(&ctx.cache)
.unwrap()
.member(&ctx.http, UserId::from(birthday.discord_id))
.await?;
let guild = msg.guild(&ctx.cache).unwrap();
let member = guild
.members
.get(&UserId::from(birthday.discord_id))
.unwrap();
msg_builder.push_line(format!(
"* {} {}",
user.display_name(),
member.display_name(),
birthday.birthday.format("%m-%d-%Y")
));
}
+42 -50
View File
@@ -1,8 +1,9 @@
use crate::{command, group};
use serenity::builder::EditRole;
use serenity::client::Context;
use serenity::framework::standard::{Args, CommandResult};
use serenity::model::channel::Message;
use serenity::utils::Colour;
use serenity::model::Colour;
#[group]
#[commands(set_color, remove_color)]
@@ -16,13 +17,15 @@ pub struct Color;
#[min_args(1)]
#[max_args(3)]
#[only_in(guilds)]
async fn set_color(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
async fn set_color(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
let color = if args.len() == 3 {
Colour::from_rgb(
args.parse::<u8>()?,
args.parse::<u8>()?,
args.parse::<u8>()?,
)
let r = args.parse::<u8>()?;
args.advance();
let g = args.parse::<u8>()?;
args.advance();
let b = args.parse::<u8>()?;
args.advance();
Colour::from_rgb(r, g, b)
} else {
let color_str = args.rest();
@@ -36,42 +39,38 @@ async fn set_color(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
}
};
let guild = msg.guild(&ctx.cache).unwrap();
let (_, member) = guild
.members
.iter()
.find(|(id, _)| id == &&msg.author.id)
.unwrap();
let role = if let Some(role) = member
.roles(&ctx.cache)
.unwrap_or_default()
.iter()
.find(|r| r.name.contains("COwOlor"))
{
role.clone()
let role = if let Some(role) = msg.member.as_ref().unwrap().roles.iter().find(|r| {
ctx.cache
.role(msg.guild_id.unwrap(), **r)
.unwrap()
.name
.contains("COwOlor")
}) {
*role
} else {
guild
.create_role(&ctx.http, |r| {
r.name(&format!("{} COwOlor", member.user.name))
})
msg.guild_id
.unwrap()
.create_role(
&ctx.http,
EditRole::new().name(&format!("{} COwOlor", msg.author.name)),
)
.await?
.id
};
guild
.edit_role(&ctx.http, role.id, |r| {
r.position(255).hoist(false).colour(color.0 as u64)
})
msg.guild_id
.unwrap()
.edit_role(&ctx.http, role, EditRole::new().colour(color))
.await?;
let len = guild.roles.len() - 1;
guild
.edit_role_position(&ctx.http, role.id, len as u64)
msg.guild_id
.unwrap()
.member(&ctx.http, msg.author.id)
.await
.unwrap()
.add_role(&ctx.http, role)
.await?;
member.clone().add_role(&ctx.http, role).await?;
msg.reply(&ctx.http, "Color set!").await?;
Ok(())
@@ -82,21 +81,14 @@ async fn set_color(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
#[only_in(guilds)]
#[description("Remove your name color.")]
async fn remove_color(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
let guild = msg.guild(&ctx.cache).unwrap();
let (_, member) = guild
.members
.iter()
.find(|(id, _)| id == &&msg.author.id)
.unwrap();
if let Some(role) = member
.roles(&ctx.cache)
.unwrap_or_default()
.iter()
.find(|r| r.name.contains("COwOlor"))
{
role.clone().delete(&ctx.http).await?;
if let Some(role) = msg.member.as_ref().unwrap().roles.iter().find(|r| {
ctx.cache
.role(msg.guild_id.unwrap(), **r)
.unwrap()
.name
.contains("COwOlor")
}) {
msg.guild_id.unwrap().delete_role(&ctx.http, role).await?;
}
msg.reply(&ctx.http, "Color removed!").await?;
+22 -13
View File
@@ -4,6 +4,7 @@ use crate::user::{User, UserError};
use crate::{command, group};
use rand::seq::IteratorRandom;
use rand::{thread_rng, Rng};
use serenity::builder::EditMessage;
use serenity::client::Context;
use serenity::framework::standard::{Args, CommandResult};
use serenity::model::id::{EmojiId, UserId};
@@ -77,7 +78,7 @@ impl Eq for Racer {}
impl Racer {
pub fn new(emoji: Emoji) -> Self {
let genetic_stat = (emoji.id.0 & 0xff) as f32 / 255.0;
let genetic_stat = (emoji.id.get() & 0xff) as f32 / 255.0;
let random_stat = thread_rng().gen_range(0.0..0.5);
let speed = BASE_SPEED + (0.50 * genetic_stat) + (0.50 * random_stat);
@@ -169,19 +170,17 @@ async fn race(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
}
};
let guild = msg.guild(&ctx.cache).unwrap();
let guild = msg.guild_id.unwrap();
let channels = guild.channels(&ctx.http).await?;
let race_channel = channels.get(&msg.channel_id).unwrap();
let racers: Vec<_> = guild
.emojis
let emojis = guild.emojis(&ctx.http).await.unwrap();
let racers: Vec<_> = emojis
.iter()
.choose_multiple(&mut thread_rng(), NUMBER_OF_RACERS);
let mut racers: Vec<Racer> = racers
.iter()
.map(|(_, e)| Racer::new((*e).clone()))
.collect();
let mut racers: Vec<Racer> = racers.iter().map(|e| Racer::new((*e).clone())).collect();
let mut racers_msg = MessageBuilder::new();
racers_msg.push_bold_line("Welcome to the Emoji Races, the racers today are:");
@@ -193,18 +192,28 @@ async fn race(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
let mut bets: Vec<Bet> = Vec::new();
loop {
let msg = recv.recv().await.unwrap();
let race_msg = recv.recv().await.unwrap();
match msg {
match race_msg {
RaceMessage::StartRace => {
race_channel.say(&ctx, "And they're off!").await?;
break;
}
RaceMessage::Bet(bet) => {
let emoji = match msg.guild_id.unwrap().emoji(&ctx.http, bet.emoji).await {
Ok(emoji) => emoji,
Err(_) => {
race_channel
.say(&ctx, "That's a weird looking racer, pick a normal one!")
.await?;
continue;
}
};
if let Err(e) = add_bet(ctx, bet.clone(), &mut bets, &racers).await {
let msg = match e {
RaceError::RacerNotFound => {
format!("{} is not in this race!", bet.emoji.mention())
format!("{} is not in this race!", emoji)
}
RaceError::BetFundError(_) => {
"Only rich people can bet in this race, sorry".to_string()
@@ -225,7 +234,7 @@ async fn race(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
"{} has put {} on {}",
bet.author.mention(),
bet.amount,
bet.emoji.mention()
emoji,
),
)
.await?;
@@ -243,7 +252,7 @@ async fn race(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
}
race_msg
.edit(&ctx.http, |m| m.content(draw_race(&racers)))
.edit(&ctx.http, EditMessage::new().content(draw_race(&racers)))
.await?;
for racer in &racers {
+2 -12
View File
@@ -28,12 +28,7 @@ async fn balance(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
&ctx.http,
format!(
"{}'s current balance is {} fren coins!",
msg.guild(&ctx.cache)
.unwrap()
.member(&ctx.http, user)
.await
.unwrap()
.mention(),
user.mention(),
wallet.coin_count
),
)
@@ -80,16 +75,11 @@ async fn gift(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
.await?;
}
} else {
let target_user = msg
.guild(&ctx.cache)
.unwrap()
.member(&ctx.http, target)
.await?;
msg.reply(
&ctx.http,
format!(
"You have gifted {} {} fren coins!",
target_user.mention(),
target.mention(),
amount
),
)
+10 -7
View File
@@ -7,6 +7,7 @@ use rand::prelude::SliceRandom;
use rand::thread_rng;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serenity::builder::EditMessage;
use serenity::client::Context;
use serenity::constants::MESSAGE_CODE_LIMIT;
use serenity::framework::standard::{Args, CommandResult};
@@ -107,13 +108,14 @@ pub async fn random(ctx: &Context, msg: &Message, random_name: &str) -> CommandR
};
let guild_member = msg
.guild(&ctx.cache)
.guild_id
.unwrap()
.member(&ctx.http, msg.author.id)
.await?;
.await
.unwrap();
let reply = render_random(
&guild_member.display_name(),
guild_member.display_name(),
global_data,
response_template_str,
)?;
@@ -248,13 +250,14 @@ async fn bad_apple(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
if (idx % 10) == 0 {
bad_apple_msg
.edit(&ctx.http, |m| {
m.content(
.edit(
&ctx.http,
EditMessage::new().content(
MessageBuilder::default()
.push_codeblock_safe(frame, None)
.build(),
)
})
),
)
.await?;
}
}
+35 -78
View File
@@ -15,26 +15,24 @@ 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::models::task::Task;
use crate::{help, hook, GlobalData};
use chrono::{Days, TimeZone, Timelike, Utc};
use rand::prelude::IteratorRandom;
use rand::thread_rng;
use serenity::all::{ActivityData, Http, RoleId};
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 serenity::prelude::EventHandler;
use std::collections::HashSet;
use std::time::Duration;
use tokio::time::sleep;
pub struct Handler;
@@ -52,72 +50,10 @@ impl EventHandler for Handler {
});
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();
Task::create_reoccurring_tasks(&ctx).await.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::<GlobalData>().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::<GlobalData>().unwrap();
global_data.reload().await.unwrap();
}
}
Task::run_tasks(&ctx).await.unwrap();
sleep(Duration::from_secs(5)).await;
}
});
}
@@ -151,7 +87,12 @@ impl EventHandler for Handler {
.unwrap();
if recv_coin {
let emojis = new_message.guild(&ctx.cache).unwrap().emojis;
let emojis = &new_message
.guild_id
.unwrap()
.emojis(&ctx.http)
.await
.unwrap();
let emoji = {
let mut rng = thread_rng();
@@ -163,9 +104,9 @@ impl EventHandler for Handler {
.react(
&ctx.http,
ReactionType::Custom {
animated: emoji.1.animated,
id: emoji.1.id,
name: Some(emoji.1.name.clone()),
animated: emoji.animated,
id: emoji.id,
name: Some(emoji.name.clone()),
},
)
.await
@@ -187,10 +128,15 @@ impl EventHandler for Handler {
println!("Connected as {}", ready.user.name);
ctx.set_presence(
Some(Activity::listening("to your deepest secrets")),
Some(
ActivityData::streaming(
"Security Cameras inside your Home",
"https://www.youtube.com/watch?v=6n3pFFPSlW4",
)
.unwrap(),
),
OnlineStatus::Online,
)
.await;
);
tokio::spawn(async move { web_server(ctx).await });
}
@@ -268,3 +214,14 @@ pub async fn my_help(
let _ = help_commands::with_embeds(context, msg, args, help_options, groups, owners).await;
Ok(())
}
pub async fn get_role(http: &Http, guild_id: GuildId, role_name: &str) -> Option<RoleId> {
guild_id
.roles(http)
.await
.unwrap()
.iter()
.find(|(_, role)| role.name == role_name)
.map(|(role_id, _)| role_id)
.copied()
}
+11 -8
View File
@@ -1,9 +1,10 @@
use crate::models::motivation::{Motivation, MotivationConfig};
use crate::{command, group, GlobalData};
use magick_rust::{DrawingWand, MagickWand, PixelWand};
use serenity::builder::{CreateAttachment, CreateMessage};
use serenity::client::Context;
use serenity::framework::standard::{Args, CommandError, CommandResult};
use serenity::model::channel::{AttachmentType, Message};
use serenity::model::channel::Message;
use std::borrow::Cow;
#[group]
@@ -80,13 +81,15 @@ async fn motivation(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let image = create_motivation_image(motivation).await?;
msg.channel_id
.send_message(&ctx.http, |m| {
m.content("Today's motivation")
.add_file(AttachmentType::Bytes {
data: Cow::from(image),
filename: "motivate.png".to_string(),
})
})
.send_message(
&ctx.http,
CreateMessage::new()
.content("Today's motivation")
.add_file(CreateAttachment::bytes(
Cow::from(image),
"motivate.png".to_string(),
)),
)
.await?;
Ok(())
+152 -22
View File
@@ -1,21 +1,28 @@
use crate::discord::get_role;
use crate::discord::motivate::create_motivation_image;
use crate::error::Error;
use crate::inventory::{InventoryError, ItemData, ItemType, Operation};
use crate::models::motivation::MotivationConfig;
use crate::models::task::{Task, TaskType};
use crate::user::{User, UserError};
use crate::{command, group, GlobalData};
use rand::prelude::SliceRandom;
use rand::{thread_rng, Rng};
use serenity::all::{
parse_user_mention, CreateAttachment, CreateMessage, EditRole, GuildId, Member,
};
use serenity::client::Context;
use serenity::framework::standard::{Args, CommandError, CommandResult};
use serenity::model::channel::{AttachmentType, Message};
use serenity::model::channel::Message;
use serenity::model::Colour;
use serenity::prelude::Mentionable;
use serenity::utils::MessageBuilder;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
use tokio::io::AsyncWriteExt;
#[group]
#[commands(shop, buy, inventory, use_item, sell_item)]
#[commands(shop, buy, inventory, use_item, sell_item, item_help)]
pub struct Shop;
#[command]
@@ -24,7 +31,7 @@ async fn shop(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
let mut data = ctx.data.write().await;
let global_data = data.get_mut::<GlobalData>().unwrap();
let bot_user = User::get_user(&global_data.db, ctx.cache.current_user_id())?;
let bot_user = User::get_user(&global_data.db, ctx.cache.current_user().id)?;
if bot_user.inventory.inventory.is_empty() {
msg.reply(&ctx.http, "Sorry shop is closed until we get more wares.")
@@ -91,7 +98,7 @@ async fn buy(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let res = User::item_transaction(
&global_data.db,
ctx.cache.current_user_id(),
ctx.cache.current_user().id,
msg.author.id,
item,
Operation::Buy,
@@ -117,6 +124,58 @@ async fn buy(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
Ok(())
}
async fn blockable_item(
ctx: &Context,
global_data: &GlobalData,
guild_id: GuildId,
msg_content: &str,
role_name: &str,
weapon_name: &str,
block_item: ItemType,
) -> CommandResult<(bool, Member)> {
let split = msg_content.split(weapon_name);
let target = parse_user_mention(split.last().unwrap()).unwrap();
let target_member = match guild_id.member(&ctx.http, target).await {
Ok(member) => member,
Err(_) => return Err(CommandError::from("I have no clue who that is tbh")),
};
if target_member.user.id == ctx.cache.current_user().id {
return Err(CommandError::from("You can not harm me in a way that matters."));
}
if User::try_use_item(&global_data.db, target, block_item, true).is_ok() {
Ok((false, target_member))
} else {
let role = if let Some(role) = get_role(&ctx.http, guild_id, role_name).await {
role
} else {
guild_id
.create_role(
&ctx.http,
EditRole::new()
.name(role_name)
.colour(Colour::from_rgb(1, 1, 1)),
)
.await
.unwrap()
.id
};
target_member.add_role(&ctx.http, role).await?;
Task::add_task(
&global_data.db,
TaskType::RemoveRole {
role_id: role.get(),
user_id: target_member.user.id.get(),
},
chrono::Utc::now() + chrono::Duration::seconds(global_data.cfg.effect_role_duration),
)?;
Ok((true, target_member))
}
}
#[command]
#[only_in(guilds)]
#[aliases("use")]
@@ -131,7 +190,8 @@ async fn use_item(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
return Ok(());
}
let item = match args.rest().parse::<ItemType>() {
let msg_content = args.rest().to_lowercase();
let item = match msg_content.parse::<ItemType>() {
Ok(i) => i,
Err(_) => {
msg.reply(&ctx.http, "I don't know what the heck that is tbh.")
@@ -140,7 +200,7 @@ async fn use_item(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
}
};
let item_data = match User::try_use_item(&global_data.db, msg.author.id, item) {
let item_data = match User::try_use_item(&global_data.db, msg.author.id, item, false) {
Ok(i) => i,
Err(err) => {
if let Error::UserError(UserError::InventoryError(InventoryError::NotEnoughItems)) = err
@@ -185,7 +245,7 @@ async fn use_item(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
];
let fortune = good_fortunes.choose(&mut thread_rng()).unwrap();
msg.reply(&ctx.http, fortune).await?;
msg.reply(&ctx.http, fortune.to_string()).await?;
}
ItemType::Nft => {
if let Some(ItemData::Nft(path)) = item_data {
@@ -198,13 +258,16 @@ async fn use_item(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
}
};
msg.channel_id
.send_message(&ctx.http, |m| {
m.content("Your NFT my good friend:")
.add_file(AttachmentType::File {
file: &file,
filename: "nft.png".to_string(),
})
})
.send_message(
&ctx.http,
CreateMessage::new()
.content("Your NFT my good friend:")
.add_file(
CreateAttachment::file(&file, "nft.png".to_string())
.await
.unwrap(),
),
)
.await?;
} else {
msg.reply(
@@ -217,6 +280,46 @@ async fn use_item(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
ItemType::LicenseToBeHorny => {
msg.reply(&ctx.http, "https://media.discordapp.net/attachments/840015650286075945/1127022083919069184/Img_2022_10_21_05_08_12.jpg").await?;
}
ItemType::KillGun => {
let (outcome, target) = blockable_item(
ctx,
global_data,
msg.guild_id.unwrap(),
&msg_content,
"Dead",
"kill gun ",
ItemType::Helmet,
)
.await?;
if outcome {
msg.reply(&ctx.http, format!("You draw your trusty kill gun and shoot one kill bullet. It hits it mark between {}'s eyes, killing them instantly. They are now dead.", target.mention())).await?;
} else {
msg.reply(&ctx.http, format!("The kill bullet shoots at kill velocity toward {}! They smirk, and simply pull out their Helmet and put it on, the bullet bounces off and falls to the floor. The crowd gasps (like they do in my animes). \"No death today pal\"", target.mention())).await?;
}
}
ItemType::CancelRay => {
let (outcome, target) = blockable_item(
ctx,
global_data,
msg.guild_id.unwrap(),
&msg_content,
"Cancelled",
"cancel ray ",
ItemType::CancelInsurance,
)
.await?;
if outcome {
msg.reply(&ctx.http, format!("You shoot the cancel ray at {}. As the ray impacts them, you can here their phone buzz. They have been cancelled, you hear the liberal media in the distance.", target.mention())).await?;
} else {
msg.reply(&ctx.http, format!("The ray nearly hits {}, but they are surrounded in a a shimmering blue energy shield. \"The liberal media won't strike this time!\"", target.mention())).await?;
}
}
ItemType::Helmet => {
msg.reply(&ctx.http, "You're trusty helmet regards you helmetly")
.await?;
}
}
Ok(())
@@ -239,10 +342,12 @@ async fn sell_item(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
}
};
let bot_user = ctx.cache.current_user().id;
match User::item_transaction(
&global_data.db,
msg.author.id,
ctx.cache.current_user_id(),
bot_user,
item,
Operation::Sell,
) {
@@ -278,17 +383,33 @@ async fn sell_item(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
Ok(())
}
pub async fn restock_shop(ctx: &Context) -> Result<(), CommandError> {
let mut data = ctx.data.write().await;
let global_data = data.get_mut::<GlobalData>().unwrap();
#[command]
#[only_in(guilds)]
#[description("Get help with an item")]
async fn item_help(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let item = match args.rest().parse::<ItemType>() {
Ok(i) => i,
Err(_) => {
msg.reply(&ctx.http, "I don't know what the heck that is tbh.")
.await?;
return Ok(());
}
};
let mut bot_user = User::get_user(&global_data.db, ctx.cache.current_user_id())?;
msg.reply(&ctx.http, format!("**{}**: {}", item, item.description()))
.await?;
Ok(())
}
pub async fn restock_shop(ctx: &Context, global_data: &GlobalData) -> Result<(), CommandError> {
let mut bot_user = User::get_user(&global_data.db, ctx.cache.current_user().id)?;
bot_user.inventory.inventory.clear();
bot_user.inventory.give_item(
ItemType::TheConceptOfLove,
thread_rng().gen_range(0..5),
thread_rng().gen_range(0..=5),
None,
);
bot_user
@@ -296,14 +417,23 @@ pub async fn restock_shop(ctx: &Context) -> Result<(), CommandError> {
.give_item(ItemType::GoodFortune, thread_rng().gen_range(0..10), None);
bot_user.inventory.give_item(
ItemType::CancelInsurance,
thread_rng().gen_range(0..10),
thread_rng().gen_range(1..=3),
None,
);
bot_user.inventory.give_item(
ItemType::LicenseToBeHorny,
thread_rng().gen_range(0..25),
thread_rng().gen_range(0..=25),
None,
);
bot_user
.inventory
.give_item(ItemType::KillGun, thread_rng().gen_range(1..=3), None);
bot_user
.inventory
.give_item(ItemType::CancelRay, thread_rng().gen_range(1..=3), None);
bot_user
.inventory
.give_item(ItemType::Helmet, thread_rng().gen_range(1..=3), None);
loop {
let mut dir = tokio::fs::read_dir(&global_data.cfg.nft_path).await?;
+1 -9
View File
@@ -119,15 +119,7 @@ async fn story(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let mut story_globals: HashMap<String, String> = HashMap::new();
let msg_channel = msg.channel(&ctx.http).await?;
let guild = msg.guild(&ctx.cache).unwrap();
let msg_channel = guild
.channels(&ctx.http)
.await?
.get(&msg_channel.id())
.unwrap()
.clone();
let msg_channel = msg.channel(&ctx.http).await?.id();
for global in get_all_blanks(&story_contents) {
msg_channel
+32 -29
View File
@@ -1,7 +1,9 @@
use crate::{command, group, GlobalData};
use serenity::all::CreateAttachment;
use serenity::builder::CreateMessage;
use serenity::client::Context;
use serenity::framework::standard::{Args, CommandResult};
use serenity::model::channel::{AttachmentType, Message};
use serenity::model::channel::Message;
use serenity::model::id::UserId;
use serenity::model::prelude::GuildId;
use serenity::utils::MessageBuilder;
@@ -157,12 +159,16 @@ pub async fn speak(
}
}
let guild = guild_id.to_guild_cached(&ctx.cache).unwrap();
let channel_id = {
let guild = ctx.cache.guild(guild_id).unwrap();
let channel_id = guild
.voice_states
.get(&user_id)
.and_then(|voice_state| voice_state.channel_id);
let channel_id = guild
.voice_states
.get(&user_id)
.and_then(|voice_state| voice_state.channel_id);
channel_id
};
let connect_to = match channel_id {
Some(channel) => channel,
@@ -176,31 +182,30 @@ pub async fn speak(
.expect("Songbird not initialized")
.clone();
let (handler_lock, success_reader) = manager.join(guild_id, connect_to).await;
let handler_lock = manager.join(guild_id, connect_to).await;
let mut handler = handler_lock.lock().await;
if success_reader.is_ok() {
if let Ok(handler_lock) = handler_lock {
let mut handler = handler_lock.lock().await;
for word in sentence {
let word_path = dict.get(&word).unwrap();
let word_path = dict.get(&word).cloned().unwrap();
let src = input::File::new(word_path);
let audio_src = Compressed::new(src.into(), Bitrate::BitsPerSecond(128_000))
.await
.expect("Bad params on message load");
let audio_src = Compressed::new(
input::ffmpeg(word_path.to_str().unwrap())
.await
.expect("Bad audio link."),
Bitrate::BitsPerSecond(128_000),
)
.expect("Bad params on message load");
let _ = audio_src.raw.spawn_loader();
let duration = audio_src.metadata.duration.unwrap();
let voice = handler.play_source(audio_src.into());
let voice = handler.play_input(audio_src.into());
voice.set_volume(0.5).unwrap();
tokio::time::sleep(duration).await;
//tokio::time::sleep(duration).await;
}
handler.leave().await.unwrap();
}
handler.leave().await.unwrap();
Ok(())
}
@@ -208,8 +213,7 @@ pub async fn speak(
#[only_in(guilds)]
#[min_args(1)]
async fn say(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
let guild = msg.guild(&ctx.cache).unwrap();
let guild_id = guild.id;
let guild_id = msg.guild_id.unwrap();
let voice = args.parse::<String>()?;
args.advance();
@@ -262,12 +266,11 @@ async fn list_words(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let file_data = Cow::from(file_data);
msg.channel_id
.send_message(&ctx.http, |m| {
m.add_file(AttachmentType::Bytes {
data: file_data,
filename: "words.txt".to_string(),
})
})
.send_message(
&ctx.http,
CreateMessage::new()
.add_file(CreateAttachment::bytes(file_data, "words.txt".to_string())),
)
.await?;
}
};