wOxlf/src/commands.rs

421 lines
11 KiB
Rust

use serenity::framework::standard::macros::{command, group};
use serenity::framework::standard::{Args, CommandResult};
use serenity::framework::StandardFramework;
use serenity::model::id::ChannelId;
use serenity::model::prelude::{Message, UserId};
use serenity::prelude::Context;
use serenity::utils::MessageBuilder;
use crate::data::{GlobalData, MessageSource, Phase};
use crate::helper;
use crate::helper::{
build_system_message, clear_game_state, get_phase_end_timestamp, print_game_status,
save_game_state, send_msg_to_player_channels,
};
#[group]
#[commands(start, say, end, broadcast, next_phase, terminate, add_time)]
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).await.unwrap();
let mut global_data = global_data.lock().await;
clear_game_state(&mut global_data).unwrap();
let duration = match args.single::<u64>() {
Ok(d) => d,
Err(_) => {
msg.reply(&ctx.http, "Error parsing phase duration!")
.await
.unwrap();
return Ok(());
}
};
global_data.game_state.phase_end_time = get_phase_end_timestamp(duration);
for player in args.iter::<u64>().flatten() {
if let Some(discord_user) = guild.members.get(&UserId::from(player)) {
helper::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::<GlobalData>().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();
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 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, None, 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::<GlobalData>().unwrap();
let guild = msg.guild(&ctx.cache).await.unwrap();
let global_data = global_data.lock().await;
let msg = build_system_message(args.rest());
send_msg_to_player_channels(ctx, &guild, &global_data, MessageSource::Host, &msg, None,true).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).await.unwrap();
let mut global_data = global_data.lock().await;
let duration = match args.single::<u64>() {
Ok(d) => d,
Err(_) => {
msg.reply(&ctx.http, "Error parsing phase duration!")
.await
.unwrap();
return Ok(());
}
};
global_data.game_state.next_phase();
global_data.game_state.phase_end_time = get_phase_end_timestamp(duration);
let broadcast = MessageBuilder::new()
.push_line(args.rest())
.push_line("")
.push(print_game_status(&global_data.game_state))
.build();
let broadcast = build_system_message(&broadcast);
send_msg_to_player_channels(
ctx,
&guild,
&global_data,
MessageSource::Host,
&broadcast,
None,
true,
)
.await;
if global_data.game_state.current_phase == Phase::Day {
let vote_channel = guild
.channels
.get(&ChannelId::from(global_data.cfg.vote_channel))
.unwrap();
vote_channel
.send_message(&ctx.http, |m| {
m.content(format!(
"**DAY {} VOTES:**",
global_data.game_state.phase_number
))
})
.await
.unwrap();
}
msg.reply(
&ctx.http,
format!(
"Phase has been cycled to {}.",
&global_data.game_state.current_phase
),
)
.await
.unwrap();
save_game_state(&global_data).unwrap();
Ok(())
}
#[command]
#[only_in(guilds)]
#[allowed_roles("wolfx host")]
async fn terminate(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).await.unwrap();
let mut global_data = global_data.lock().await;
let target = args.rest().to_lowercase();
let index = global_data
.game_state
.player_data
.iter()
.position(|p| p.codename.to_lowercase() == target);
if let Some(index) = index {
let player = global_data.game_state.player_data.remove(index);
let player_channel = guild
.channels
.get(&ChannelId::from(player.channel))
.unwrap();
player_channel.delete(&ctx.http).await.unwrap();
msg.reply(
&ctx.http,
format!("{} has been terminated.", player.codename),
)
.await
.unwrap();
} else {
msg.reply(&ctx.http, "No subject found with that codename.")
.await
.unwrap();
}
save_game_state(&global_data).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 guild = msg.guild(&ctx.cache).await.unwrap();
let mut global_data = global_data.lock().await;
global_data.game_state.next_phase();
let duration = match args.single::<u64>() {
Ok(d) => d,
Err(_) => {
msg.reply(&ctx.http, "Error parsing phase duration!")
.await
.unwrap();
return Ok(());
}
};
global_data.game_state.add_time_to_phase(duration);
let broadcast = MessageBuilder::new()
.push_line("EXPERIMENT PHASE HAS BEEN EXTENDED!!!")
.push_line("")
.push(print_game_status(&global_data.game_state))
.build();
let broadcast = build_system_message(&broadcast);
send_msg_to_player_channels(
ctx,
&guild,
&global_data,
MessageSource::Host,
&broadcast,
None,
true,
)
.await;
msg.reply(&ctx.http, "Phase has been updated")
.await
.unwrap();
save_game_state(&global_data).unwrap();
Ok(())
}
#[group]
#[commands(vote, status, players)]
struct Player;
#[command]
#[only_in(guilds)]
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).await.unwrap();
let mut global_data = global_data.lock().await;
if global_data.game_state.current_phase != Phase::Day {
msg.reply(
&ctx.http,
"You can only select subject for termination during the day!",
)
.await
.unwrap();
return Ok(());
}
if global_data
.game_state
.get_player_from_channel(msg.channel_id.0)
.is_some()
{
let target_player = global_data.game_state.get_player_by_codename(args.rest());
if let Some(target_player) = target_player {
let vote_channel = guild
.channels
.get(&ChannelId::from(global_data.cfg.vote_channel))
.unwrap();
let player_data = global_data
.game_state
.get_player_from_channel_mut(msg.channel_id.0)
.unwrap();
player_data.vote_target = Some(target_player.channel);
vote_channel
.send_message(&ctx.http, |m| {
m.content(format!(
"{} has selected {} for termination",
&player_data.codename, target_player.codename
))
})
.await
.unwrap();
} else {
msg.reply(&ctx.http, "Subject not found!").await.unwrap();
}
} else {
msg.reply(
&ctx.http,
"This command needs to be run in a game channel, goober",
)
.await
.unwrap();
}
save_game_state(&global_data).unwrap();
Ok(())
}
#[command]
#[only_in(guilds)]
async fn status(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(print_game_status(&global_data.game_state));
if global_data.game_state.current_phase == Phase::Day {
msg_builder.push_line("");
let vote_tallies = global_data.game_state.get_vote_tallies();
if vote_tallies.is_empty() {
msg_builder.push_line("NO TERMINATION VOTES HAVE BEEN CAST");
} else {
msg_builder.push_line("TERMINATION VOTE TALLIES:");
for (player, tally) in global_data.game_state.get_vote_tallies() {
msg_builder.push_line(format!("{}: {}", player, tally));
}
}
}
msg.reply(&ctx.http, msg_builder.build()).await.unwrap();
Ok(())
}
#[command]
#[only_in(guilds)]
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("Test Subjects:");
for player in &global_data.game_state.player_data {
msg_builder
.push("* ")
.push_line(&player.codename);
}
msg.reply(&ctx.http, msg_builder.build()).await.unwrap();
Ok(())
}
pub fn command_framework() -> StandardFramework {
StandardFramework::new()
.configure(|c| c.prefix("!"))
.group(&HOST_GROUP)
.group(&PLAYER_GROUP)
}