use crate::data::{BotConfig, GlobalData, MessageSource, PlayerData}; use crate::helper::{clear_game_state, save_game_state, send_msg_to_player_channels}; use rand::Rng; use serenity::framework::standard::macros::{command, group}; use serenity::framework::standard::{Args, CommandResult}; use serenity::framework::StandardFramework; use serenity::model::channel::{PermissionOverwrite, PermissionOverwriteType}; use serenity::model::guild::{Guild, Member}; use serenity::model::id::ChannelId; use serenity::model::prelude::{Message, UserId}; use serenity::model::Permissions; use serenity::prelude::Context; use serenity::utils::MessageBuilder; #[group] #[commands(start, say, end, broadcast)] struct Host; fn generate_codename(config: &BotConfig) -> String { let mut rng = rand::thread_rng(); let occupation = &config.occupation[rng.gen_range(0..config.occupation.len())]; let adj = &config.adjective[rng.gen_range(0..config.adjective.len())]; format!("{} {}", adj, occupation) } async fn add_user_to_game( ctx: &Context, guild: &Guild, global_data: &mut GlobalData, discord_user: &Member, ) -> CommandResult { let mut codename = generate_codename(&global_data.cfg); while global_data.game_state.codename_exists(&codename) { codename = generate_codename(&global_data.cfg); } let channel = guild .create_channel(&ctx.http, |c| { c.category(&ChannelId::from(global_data.cfg.category)) .name(format!("{}'s Channel", discord_user.display_name())) }) .await?; let allow = Permissions::SEND_MESSAGES | Permissions::READ_MESSAGE_HISTORY | Permissions::READ_MESSAGE_HISTORY; let overwrite = PermissionOverwrite { allow, deny: Default::default(), kind: PermissionOverwriteType::Member(discord_user.user.id), }; channel.create_permission(&ctx.http, &overwrite).await?; let msg = channel.send_message(&ctx.http, |m| { m.content(MessageBuilder::new() .push("Welcome ") .mention(discord_user) .push_line(" to your WOxlf Terminal. You may use this terminal to communicate to other subjects.") .push_line("You will also use this terminal for choosing one of your fellow subjects for termination.") .push_line("Happy testing :)") .push_line("") .push("SUBJECT CODENAME: ") .push_line(&codename) ) }).await?; channel.pin(&ctx.http, msg.id).await?; let player_data = PlayerData { channel: channel.id.0, discord_id: discord_user.user.id.0, codename, }; global_data.game_state.player_data.push(player_data); Ok(()) } #[command] #[only_in(guilds)] #[allowed_roles("wolfx host")] async fn start(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult { msg.channel_id.say(&ctx.http, "Starting game").await?; let mut data = ctx.data.write().await; let global_data = data.get_mut::().unwrap(); let guild = msg.guild(&ctx.cache).await.unwrap(); let mut global_data = global_data.lock().await; clear_game_state(&mut global_data).unwrap(); for player in args.iter::().flatten() { if let Some(discord_user) = guild.members.get(&UserId::from(player)) { add_user_to_game(ctx, &guild, &mut global_data, discord_user).await?; } else { msg.reply( &ctx.http, format!("User {} is invalid or not in this server!", player), ) .await?; break; } } save_game_state(&global_data).unwrap(); Ok(()) } #[command] #[only_in(guilds)] #[allowed_roles("wolfx host")] async fn end(ctx: &Context, msg: &Message, mut _args: Args) -> CommandResult { let mut data = ctx.data.write().await; let global_data = data.get_mut::().unwrap(); let guild = msg.guild(&ctx.cache).await.unwrap(); let mut global_data = global_data.lock().await; for player_data in &global_data.game_state.player_data { let channel = guild .channels .get(&ChannelId::from(player_data.channel)) .unwrap(); channel.delete(&ctx.http).await?; } clear_game_state(&mut global_data).unwrap(); Ok(()) } #[command] #[only_in(guilds)] #[allowed_roles("wolfx host")] async fn say(ctx: &Context, msg: &Message, args: Args) -> CommandResult { let data = ctx.data.read().await; let global_data = data.get::().unwrap(); let guild = msg.guild(&ctx.cache).await.unwrap(); let global_data = global_data.lock().await; let msg = format!("**wOxlf **> {}", args.rest()); send_msg_to_player_channels(ctx, &guild, &global_data, MessageSource::Host, &msg, false).await; Ok(()) } #[command] #[only_in(guilds)] #[allowed_roles("wolfx host")] async fn broadcast(ctx: &Context, msg: &Message, args: Args) -> CommandResult { let data = ctx.data.read().await; let global_data = data.get::().unwrap(); let guild = msg.guild(&ctx.cache).await.unwrap(); let global_data = global_data.lock().await; let msg = MessageBuilder::new() .push_bold_line("\\*\\*IMPORTANT wOxlf SYSTEM MESSAGE\\*\\*") .push_line("") .push_line(args.rest()) .push_line("") .push_bold_line("\\*\\*END OF SYSTEM MESSAGE\\*\\*") .build(); send_msg_to_player_channels(ctx, &guild, &global_data, MessageSource::Host, &msg, true).await; Ok(()) } pub fn command_framework() -> StandardFramework { StandardFramework::new() .configure(|c| c.prefix("!")) .group(&HOST_GROUP) }