wOxlf/src/discord/players.rs

225 lines
6.6 KiB
Rust

use crate::game::global_data::GlobalData;
use crate::game::message_router::{
dispatch_message, Median, MessageDest, MessageSource, WoxlfMessage,
};
use crate::game::Phase;
use serenity::client::Context;
use serenity::framework::standard::macros::{command, group};
use serenity::framework::standard::{Args, CommandResult};
use serenity::model::channel::Message;
use serenity::model::id::{ChannelId, UserId};
use serenity::utils::MessageBuilder;
#[group]
#[commands(vote, status, players, whisper)]
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(),
player.role,
player.role.seer_color()
));
} 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 {
let data = ctx.data.read().await;
let global_data = data.get::<GlobalData>().unwrap();
let mut global_data = global_data.lock().await;
if !global_data.game_cfg()?.whispers_allowed {
msg.reply(&ctx.http, "No private messages are allowed in this game")
.await?;
return Ok(());
}
if args.len() < 2 {
msg.reply(&ctx.http, "Need a recipient and message!")
.await?;
} else {
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, &mut global_data, woxlf_msg).await?;
} else {
msg.reply(
&ctx.http,
format!("Could not find a player with codename {}.", target),
)
.await?;
}
}
Ok(())
}