734 lines
21 KiB
Rust
734 lines
21 KiB
Rust
use chrono::Duration;
|
|
use std::collections::HashSet;
|
|
|
|
use rand::prelude::SliceRandom;
|
|
use rand::thread_rng;
|
|
use serenity::framework::standard::macros::{command, group, help, hook};
|
|
use serenity::framework::standard::{
|
|
help_commands, Args, CommandGroup, CommandResult, HelpOptions,
|
|
};
|
|
use serenity::framework::StandardFramework;
|
|
use serenity::model::guild::Member;
|
|
use serenity::model::id::ChannelId;
|
|
use serenity::model::prelude::{Message, UserId};
|
|
use serenity::prelude::Context;
|
|
use serenity::utils::MessageBuilder;
|
|
|
|
use crate::discord::helper::{add_user_to_game, parse_duration_arg};
|
|
use crate::error::{Result, WoxlfError};
|
|
use crate::game::global_data::GlobalData;
|
|
use crate::game::message_router::{
|
|
dispatch_message, Median, MessageDest, MessageSource, WoxlfMessage,
|
|
};
|
|
use crate::game::player_data::PlayerData;
|
|
use crate::game::Phase;
|
|
use crate::messages::DiscordUser;
|
|
|
|
#[group]
|
|
#[commands(
|
|
start, say, end, broadcast, next_phase, kill, add_time, test_theme, whisper
|
|
)]
|
|
struct Host;
|
|
|
|
#[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::<GlobalData>().unwrap();
|
|
let guild = msg.guild(&ctx.cache).unwrap();
|
|
let mut global_data = global_data.lock().await;
|
|
|
|
let game_name = args.single::<String>()?;
|
|
let duration = parse_duration_arg(&mut args).await?;
|
|
|
|
global_data.start_game(&game_name, Phase::Night, duration.into())?;
|
|
|
|
let players: Result<Vec<&Member>> = args
|
|
.iter::<String>()
|
|
.flatten()
|
|
.map(|discord_id| {
|
|
let discord_id = match discord_id.parse::<u64>() {
|
|
Ok(discord_id) => discord_id,
|
|
Err(_) => {
|
|
return Err(WoxlfError::DiscordIdParseError(discord_id));
|
|
}
|
|
};
|
|
|
|
if let Some(discord_user) = guild.members.get(&UserId::from(discord_id)) {
|
|
Ok(discord_user)
|
|
} else {
|
|
Err(WoxlfError::DiscordIdParseError(discord_id.to_string()))
|
|
}
|
|
})
|
|
.collect();
|
|
|
|
let mut players = match players {
|
|
Ok(players) => players,
|
|
Err(e) => {
|
|
let err_msg = match e {
|
|
WoxlfError::DiscordIdParseError(e) => {
|
|
format!("Error parsing '{}' as a discord user id.", e)
|
|
}
|
|
_ => "Internal bot error".to_string(),
|
|
};
|
|
|
|
msg.reply(&ctx.http, err_msg).await?;
|
|
|
|
return Ok(());
|
|
}
|
|
};
|
|
|
|
players.shuffle(&mut thread_rng());
|
|
|
|
let mut first_names = global_data.game_cfg()?.first_name.clone();
|
|
let mut last_names = global_data.game_cfg()?.last_name.clone();
|
|
|
|
first_names.shuffle(&mut thread_rng());
|
|
last_names.shuffle(&mut thread_rng());
|
|
|
|
let mut profile_pics = global_data.get_profile_pic_album().await?;
|
|
|
|
profile_pics.shuffle(&mut thread_rng());
|
|
|
|
for player in players {
|
|
let first_name = first_names.pop();
|
|
let last_name = last_names.pop();
|
|
let profile_pic_url = profile_pics.pop();
|
|
add_user_to_game(
|
|
ctx,
|
|
&guild,
|
|
&mut global_data,
|
|
player,
|
|
first_name,
|
|
last_name,
|
|
profile_pic_url,
|
|
)
|
|
.await?;
|
|
}
|
|
|
|
for player_data in &global_data.game_state()?.player_data {
|
|
let channel = ChannelId::from(player_data.channel);
|
|
let discord_user = guild.member(&ctx.http, player_data.discord_id).await?;
|
|
|
|
let intro_message = global_data.templates()?.build_welcome_message(
|
|
&global_data,
|
|
&DiscordUser::from(&discord_user),
|
|
player_data,
|
|
)?;
|
|
|
|
let msg = channel
|
|
.send_message(&ctx.http, |m| m.content(intro_message))
|
|
.await?;
|
|
channel.pin(&ctx.http, msg.id).await?;
|
|
}
|
|
|
|
global_data.save_game_state().unwrap();
|
|
|
|
ctx.http
|
|
.edit_nickname(guild.id.0, Some(&global_data.game_cfg()?.bot_name))
|
|
.await?;
|
|
|
|
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::<GlobalData>().unwrap();
|
|
let guild = msg.guild(&ctx.cache).unwrap();
|
|
|
|
let mut global_data = global_data.lock().await;
|
|
|
|
for player_data in &global_data.game_state_mut()?.player_data {
|
|
let channel = guild
|
|
.channels
|
|
.get(&ChannelId::from(player_data.channel))
|
|
.unwrap();
|
|
|
|
channel.delete(&ctx.http).await?;
|
|
}
|
|
|
|
global_data.clear_game_state()?;
|
|
|
|
ctx.http.edit_nickname(guild.id.0, None).await?;
|
|
msg.reply(&ctx.http, "Game ended!").await.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::<GlobalData>().unwrap();
|
|
|
|
let global_data = global_data.lock().await;
|
|
|
|
let msg = WoxlfMessage::default()
|
|
.source(MessageSource::Host)
|
|
.dest(MessageDest::Broadcast)
|
|
.median(Median::Webhook)
|
|
.content(args.rest())
|
|
.clone();
|
|
|
|
dispatch_message(ctx, &global_data, msg).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::<GlobalData>().unwrap();
|
|
|
|
let global_data = global_data.lock().await;
|
|
|
|
let broadcast = global_data
|
|
.templates()?
|
|
.build_announcement(&global_data, args.rest())?;
|
|
|
|
let woxlf_msg = WoxlfMessage::default()
|
|
.source(MessageSource::Automated)
|
|
.dest(MessageDest::Broadcast)
|
|
.content(&broadcast)
|
|
.median(Median::Webhook)
|
|
.clone();
|
|
|
|
dispatch_message(ctx, &global_data, woxlf_msg).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[command]
|
|
#[only_in(guilds)]
|
|
#[allowed_roles("wolfx host")]
|
|
async fn next_phase(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
|
let mut data = ctx.data.write().await;
|
|
let global_data = data.get_mut::<GlobalData>().unwrap();
|
|
let guild = msg.guild(&ctx.cache).unwrap();
|
|
|
|
let mut global_data = global_data.lock().await;
|
|
|
|
let duration = parse_duration_arg(&mut args).await?;
|
|
|
|
global_data.game_state_mut()?.next_phase(duration.into());
|
|
|
|
let broadcast = MessageBuilder::new()
|
|
.push_line(args.rest())
|
|
.push_line("")
|
|
.push(global_data.templates()?.build_satus_message(&global_data)?)
|
|
.build();
|
|
|
|
let broadcast = global_data
|
|
.templates()?
|
|
.build_announcement(&global_data, &broadcast)?;
|
|
|
|
let woxlf_msg = WoxlfMessage::default()
|
|
.source(MessageSource::Automated)
|
|
.dest(MessageDest::Broadcast)
|
|
.median(Median::Webhook)
|
|
.content(&broadcast)
|
|
.clone();
|
|
|
|
dispatch_message(ctx, &global_data, woxlf_msg).await?;
|
|
|
|
if global_data.game_state_mut()?.current_phase == Phase::Day {
|
|
let vote_channel = guild
|
|
.channels
|
|
.get(&ChannelId::from(
|
|
global_data.cfg.discord_config.vote_channel,
|
|
))
|
|
.unwrap();
|
|
vote_channel
|
|
.id()
|
|
.send_message(&ctx.http, |m| {
|
|
m.content(format!(
|
|
"**{} {} Votes:**",
|
|
global_data.game_cfg().unwrap().vote_phase_name.clone(),
|
|
&global_data.game_state_mut().unwrap().phase_number
|
|
))
|
|
})
|
|
.await?;
|
|
}
|
|
|
|
msg.reply(
|
|
&ctx.http,
|
|
format!(
|
|
"Phase has been cycled to {}.",
|
|
&global_data.get_phase_name()?
|
|
),
|
|
)
|
|
.await?;
|
|
|
|
global_data.save_game_state()?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[command]
|
|
#[only_in(guilds)]
|
|
#[allowed_roles("wolfx host")]
|
|
async fn kill(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
|
let mut data = ctx.data.write().await;
|
|
let global_data = data.get_mut::<GlobalData>().unwrap();
|
|
|
|
let mut global_data = global_data.lock().await;
|
|
|
|
let target = args.rest().to_lowercase();
|
|
let player = global_data
|
|
.game_state_mut()?
|
|
.get_player_by_codename_mut(&target);
|
|
|
|
if let Some(player) = player {
|
|
player.alive = false;
|
|
msg.reply(&ctx.http, format!("{} has been killed.", player.codename))
|
|
.await?;
|
|
} else {
|
|
msg.reply(&ctx.http, "No player found with that codename.")
|
|
.await?;
|
|
}
|
|
|
|
global_data.save_game_state().unwrap();
|
|
Ok(())
|
|
}
|
|
|
|
#[command]
|
|
#[only_in(guilds)]
|
|
#[allowed_roles("wolfx host")]
|
|
async fn add_time(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
|
let mut data = ctx.data.write().await;
|
|
let global_data = data.get_mut::<GlobalData>().unwrap();
|
|
|
|
let mut global_data = global_data.lock().await;
|
|
|
|
let duration = parse_duration_arg(&mut args).await?;
|
|
|
|
global_data
|
|
.game_state_mut()?
|
|
.add_time_to_phase(duration.into());
|
|
|
|
let broadcast = MessageBuilder::new()
|
|
.push(
|
|
global_data
|
|
.templates()?
|
|
.build_phase_extend_message(&global_data)?,
|
|
)
|
|
.push_line("")
|
|
.push(global_data.templates()?.build_satus_message(&global_data)?)
|
|
.build();
|
|
|
|
let broadcast = global_data
|
|
.templates()?
|
|
.build_announcement(&global_data, &broadcast)?;
|
|
|
|
let woxlf_msg = WoxlfMessage::default()
|
|
.source(MessageSource::Automated)
|
|
.dest(MessageDest::Broadcast)
|
|
.median(Median::Webhook)
|
|
.content(&broadcast)
|
|
.clone();
|
|
|
|
dispatch_message(ctx, &global_data, woxlf_msg).await?;
|
|
|
|
msg.reply(&ctx.http, "Phase has been updated")
|
|
.await
|
|
.unwrap();
|
|
|
|
global_data.save_game_state().unwrap();
|
|
Ok(())
|
|
}
|
|
|
|
#[command]
|
|
#[only_in(guilds)]
|
|
#[allowed_roles("wolfx host")]
|
|
#[description = "Display all the messages from a theme"]
|
|
async fn test_theme(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
|
let mut data = ctx.data.write().await;
|
|
|
|
let global_data = data.get_mut::<GlobalData>().unwrap();
|
|
let global_data = global_data.lock().await;
|
|
|
|
let theme = args.parse::<String>()?;
|
|
|
|
let mut test_global_data = GlobalData::new(global_data.cfg.clone());
|
|
|
|
test_global_data.start_game(&theme, Phase::Day, Duration::hours(1))?;
|
|
|
|
let test_player_1 = PlayerData {
|
|
channel: 0,
|
|
discord_id: 0,
|
|
codename: "Test Player 1".to_string(),
|
|
vote_target: None,
|
|
profile_pic_url: "".to_string(),
|
|
channel_webhook_id: 0,
|
|
alive: true,
|
|
};
|
|
|
|
let player_1_discord = DiscordUser {
|
|
display_name: "Test Player Discord".to_string(),
|
|
mention: "@Test Player Discord".to_string(),
|
|
};
|
|
|
|
let test_player_2 = PlayerData {
|
|
channel: 0,
|
|
discord_id: 0,
|
|
codename: "Test Player 2".to_string(),
|
|
vote_target: None,
|
|
profile_pic_url: "".to_string(),
|
|
channel_webhook_id: 0,
|
|
alive: false,
|
|
};
|
|
|
|
let mut players = vec![test_player_1.clone(), test_player_2.clone()];
|
|
|
|
test_global_data
|
|
.game_state_mut()?
|
|
.player_data
|
|
.append(&mut players);
|
|
|
|
let codename_format = test_global_data.templates()?.build_name(
|
|
&test_global_data,
|
|
Some("FirstName".to_lowercase()),
|
|
Some("LastName".to_lowercase()),
|
|
)?;
|
|
|
|
let phase_extend_message = test_global_data
|
|
.templates()?
|
|
.build_phase_extend_message(&test_global_data)?;
|
|
|
|
let vote_message = test_global_data.templates()?.build_vote_message(
|
|
&test_global_data,
|
|
&test_player_1,
|
|
&test_player_2,
|
|
)?;
|
|
|
|
let status_message = test_global_data
|
|
.templates()?
|
|
.build_satus_message(&test_global_data)?;
|
|
|
|
let announcement_message = test_global_data
|
|
.templates()?
|
|
.build_announcement(&test_global_data, "Test announcement")?;
|
|
|
|
let welcome_message = test_global_data.templates()?.build_welcome_message(
|
|
&test_global_data,
|
|
&player_1_discord,
|
|
&test_player_1,
|
|
)?;
|
|
|
|
let tally_message = test_global_data
|
|
.templates()?
|
|
.build_vote_tally(&test_global_data)?;
|
|
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content("==Codename Format=="))
|
|
.await?;
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content(codename_format))
|
|
.await?;
|
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
|
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content("==Phase Extend Message=="))
|
|
.await?;
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content(phase_extend_message))
|
|
.await?;
|
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
|
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content("==Vote Message=="))
|
|
.await?;
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content(vote_message))
|
|
.await?;
|
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
|
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content("==Status Message=="))
|
|
.await?;
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content(status_message))
|
|
.await?;
|
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
|
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content("==Announcement Message=="))
|
|
.await?;
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content(announcement_message))
|
|
.await?;
|
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
|
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content("==Welcome Message=="))
|
|
.await?;
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content(welcome_message))
|
|
.await?;
|
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
|
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content("==Tally Message=="))
|
|
.await?;
|
|
msg.channel_id
|
|
.send_message(&ctx.http, |m| m.content(tally_message))
|
|
.await?;
|
|
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[group]
|
|
#[commands(vote, status, players)]
|
|
struct Player;
|
|
|
|
#[command]
|
|
#[only_in(guilds)]
|
|
#[description = "vote another subject for termination. $vote <code_name>"]
|
|
async fn vote(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
|
let mut data = ctx.data.write().await;
|
|
let global_data = data.get_mut::<GlobalData>().unwrap();
|
|
let guild = msg.guild(&ctx.cache).unwrap();
|
|
|
|
let mut global_data = global_data.lock().await;
|
|
|
|
if global_data.game_state_mut()?.current_phase != Phase::Day {
|
|
msg.reply(
|
|
&ctx.http,
|
|
format!(
|
|
"You can only vote during the {} phase.",
|
|
global_data.game_cfg()?.vote_phase_name
|
|
),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
return Ok(());
|
|
}
|
|
|
|
if global_data
|
|
.game_state_mut()?
|
|
.get_player_from_channel(msg.channel_id.0)
|
|
.is_some()
|
|
{
|
|
let target_player = global_data
|
|
.game_state_mut()?
|
|
.get_player_by_codename(args.rest());
|
|
|
|
if let Some(target_player) = target_player {
|
|
let vote_channel = guild
|
|
.channels
|
|
.get(&ChannelId::from(
|
|
global_data.cfg.discord_config.vote_channel,
|
|
))
|
|
.unwrap();
|
|
|
|
let player_data = global_data
|
|
.game_state_mut()?
|
|
.get_player_from_channel_mut(msg.channel_id.0)
|
|
.unwrap();
|
|
|
|
player_data.cast_vote(target_player.discord_id);
|
|
|
|
// borrow as immutable
|
|
let player_data = global_data
|
|
.game_state()?
|
|
.get_player_from_channel(msg.channel_id.0)
|
|
.unwrap();
|
|
|
|
let vote_msg = global_data.templates()?.build_vote_message(
|
|
&global_data,
|
|
player_data,
|
|
&target_player,
|
|
)?;
|
|
|
|
vote_channel
|
|
.id()
|
|
.send_message(&ctx.http, |m| m.content(vote_msg))
|
|
.await?;
|
|
} else {
|
|
msg.reply(&ctx.http, "Target not found!").await.unwrap();
|
|
}
|
|
} else {
|
|
msg.reply(
|
|
&ctx.http,
|
|
"This command needs to be run in a game channel, goober",
|
|
)
|
|
.await?;
|
|
}
|
|
|
|
global_data.save_game_state().unwrap();
|
|
Ok(())
|
|
}
|
|
|
|
#[command]
|
|
#[only_in(guilds)]
|
|
#[description = "Get the game status."]
|
|
async fn status(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
|
|
let mut data = ctx.data.write().await;
|
|
let global_data = data.get_mut::<GlobalData>().unwrap();
|
|
|
|
let mut global_data = global_data.lock().await;
|
|
|
|
let mut msg_builder = MessageBuilder::new();
|
|
|
|
msg_builder.push(
|
|
global_data
|
|
.templates()?
|
|
.build_satus_message(&global_data)
|
|
.unwrap(),
|
|
);
|
|
|
|
if global_data.game_state_mut()?.current_phase == Phase::Day {
|
|
msg_builder.push_line(
|
|
global_data
|
|
.templates()?
|
|
.build_vote_tally(&global_data)
|
|
.unwrap(),
|
|
);
|
|
}
|
|
|
|
msg.reply(&ctx.http, msg_builder.build()).await.unwrap();
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[command]
|
|
#[only_in(guilds)]
|
|
#[description = "Get the other players in the game."]
|
|
async fn players(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
|
|
let data = ctx.data.read().await;
|
|
let global_data = data.get::<GlobalData>().unwrap();
|
|
|
|
let global_data = global_data.lock().await;
|
|
|
|
let mut msg_builder = MessageBuilder::new();
|
|
|
|
msg_builder.push_line(&global_data.game_cfg()?.player_group_name);
|
|
|
|
for player in &global_data.game_state()?.player_data {
|
|
let alive_status = if !player.alive { " (Dead) " } else { "" };
|
|
|
|
msg_builder
|
|
.push("* ")
|
|
.push(&player.codename)
|
|
.push(alive_status);
|
|
|
|
if msg.channel_id.0 == global_data.cfg.discord_config.host_channel {
|
|
let guild = msg.guild(&ctx.cache).unwrap();
|
|
let member = guild.members.get(&UserId::from(player.discord_id)).unwrap();
|
|
msg_builder.push_line(format!(" ({})", member.display_name()));
|
|
} else {
|
|
msg_builder.push_line("");
|
|
}
|
|
}
|
|
|
|
msg.reply(&ctx.http, msg_builder.build()).await.unwrap();
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[command]
|
|
#[aliases("pm", "w")]
|
|
#[description = "Send a private message to another player."]
|
|
async fn whisper(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
|
if args.len() < 2 {
|
|
msg.reply(&ctx.http, "Need a recipient and message!")
|
|
.await?;
|
|
} else {
|
|
let data = ctx.data.read().await;
|
|
let global_data = data.get::<GlobalData>().unwrap();
|
|
let global_data = global_data.lock().await;
|
|
|
|
let target = args.single::<String>()?;
|
|
let pm = args.rest();
|
|
|
|
let src_player = match global_data
|
|
.game_state()?
|
|
.get_player_from_discord_id(msg.author.id.0)
|
|
{
|
|
None => {
|
|
msg.reply(&ctx.http, "You are not in the game!").await?;
|
|
return Ok(());
|
|
}
|
|
Some(player) => player,
|
|
};
|
|
|
|
if let Some(target_player) = global_data.game_state()?.get_player_by_codename(&target) {
|
|
if src_player.discord_id == target_player.discord_id {
|
|
msg.reply(&ctx.http, "You can't send messages to yourself!")
|
|
.await?;
|
|
return Ok(());
|
|
}
|
|
|
|
let woxlf_msg = WoxlfMessage::default()
|
|
.source(MessageSource::Player(Box::new(src_player.clone())))
|
|
.dest(MessageDest::Player(Box::new(target_player.clone())))
|
|
.median(Median::DirectMessage)
|
|
.content(pm)
|
|
.clone();
|
|
|
|
dispatch_message(ctx, &global_data, woxlf_msg).await?;
|
|
} else {
|
|
msg.reply(
|
|
&ctx.http,
|
|
format!("Could not find a player with codename {}.", target),
|
|
)
|
|
.await?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[help]
|
|
#[individual_command_tip = "If you want more information about a specific command, just pass the command as argument."]
|
|
#[command_not_found_text = "Could not find: `{}`."]
|
|
#[max_levenshtein_distance(3)]
|
|
#[indention_prefix = "+"]
|
|
#[lacking_role = "Strike"]
|
|
#[wrong_channel = "Strike"]
|
|
async fn help(
|
|
context: &Context,
|
|
msg: &Message,
|
|
args: Args,
|
|
help_options: &'static HelpOptions,
|
|
groups: &[&'static CommandGroup],
|
|
owners: HashSet<UserId>,
|
|
) -> CommandResult {
|
|
let _ = help_commands::with_embeds(context, msg, args, help_options, groups, owners).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[hook]
|
|
async fn handle_errors(
|
|
ctx: &Context,
|
|
msg: &Message,
|
|
command_name: &str,
|
|
command_result: CommandResult,
|
|
) {
|
|
match command_result {
|
|
Ok(()) => println!("Successfully processed command '{}'", command_name),
|
|
Err(err) => {
|
|
let reply_msg = format!("Command '{}' returned an error. {}", command_name, err,);
|
|
println!("{}", reply_msg);
|
|
msg.reply(&ctx.http, reply_msg).await.unwrap();
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn command_framework() -> StandardFramework {
|
|
StandardFramework::new()
|
|
.configure(|c| c.prefix('$'))
|
|
.group(&HOST_GROUP)
|
|
.group(&PLAYER_GROUP)
|
|
.help(&HELP)
|
|
.after(handle_errors)
|
|
}
|