wOxlf/src/helper.rs

223 lines
6.4 KiB
Rust

use std::fs::File;
use std::io::prelude::*;
use rand::Rng;
use serenity::framework::standard::CommandResult;
use serenity::model::channel::{PermissionOverwrite, PermissionOverwriteType};
use serenity::model::guild::Member;
use serenity::model::id::UserId;
use serenity::model::prelude::ChannelId;
use serenity::model::prelude::Guild;
use serenity::model::Permissions;
use serenity::prelude::Context;
use serenity::utils::MessageBuilder;
use crate::data::{BotConfig, GameState, GlobalData, MessageSource, PlayerData};
use std::time::UNIX_EPOCH;
use serenity::http::AttachmentType;
pub async fn send_msg_to_player_channels(
ctx: &Context,
guild: &Guild,
global_data: &GlobalData,
msg_source: MessageSource,
msg: &str,
attachment: Option<Vec<AttachmentType<'_>>>,
pin: bool,
) {
for player_data in &global_data.game_state.player_data {
if let MessageSource::Player(channel_id) = msg_source {
if channel_id == player_data.channel {
continue;
}
}
let channel = guild
.channels
.get(&ChannelId::from(player_data.channel))
.unwrap();
let msg = channel
.send_message(&ctx.http, |m| {
m.content(&msg);
if let Some(attachment) = attachment.clone() {
m.add_files(attachment);
}
m
})
.await
.unwrap();
if pin {
// pin system messages
msg.pin(&ctx.http).await.unwrap();
}
}
let host_channel = guild
.channels
.get(&ChannelId::from(global_data.cfg.host_channel))
.unwrap();
let source = match msg_source {
MessageSource::Player(channel_id) => {
let discord_id = global_data
.game_state
.get_player_from_channel(channel_id)
.unwrap()
.discord_id;
let name = guild
.members
.get(&UserId::from(discord_id))
.unwrap()
.display_name();
name.to_string()
}
MessageSource::Host => "Host".to_string(),
MessageSource::Automated => "Automated".to_string(),
};
host_channel
.send_message(&ctx.http, |m| {
m.content(format!("({}): {}", source, msg));
if let Some(attachment) = attachment {
m.add_files(attachment);
}
m
}
)
.await
.unwrap();
}
pub fn save_game_state(global_data: &GlobalData) -> std::io::Result<()> {
let s = toml::to_string_pretty(&global_data.game_state).unwrap();
let mut file = File::create(global_data.cfg.get_game_state_path())?;
file.write_all(s.as_bytes())
}
pub fn get_game_state(global_data: &mut GlobalData) -> std::io::Result<()> {
let mut file = File::open(global_data.cfg.get_game_state_path())?;
let mut data = String::new();
file.read_to_string(&mut data)?;
global_data.game_state = toml::from_str(&data).unwrap();
Ok(())
}
pub fn clear_game_state(global_data: &mut GlobalData) -> std::io::Result<()> {
global_data.game_state.clear();
let state_path = global_data.cfg.get_game_state_path();
if state_path.exists() {
std::fs::remove_file(global_data.cfg.get_game_state_path())?;
}
Ok(())
}
pub 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)
}
pub 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_MESSAGES;
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)
.push(print_game_status(&global_data.game_state))
)
}).await?;
channel.pin(&ctx.http, msg.id).await?;
let player_data = PlayerData {
channel: channel.id.0,
discord_id: discord_user.user.id.0,
vote_target: None,
codename,
};
global_data.game_state.player_data.push(player_data);
Ok(())
}
pub fn build_system_message(msg: &str) -> String {
MessageBuilder::new()
.push_bold_line("\\*\\*IMPORTANT wOxlf SYSTEM MESSAGE\\*\\*")
.push_line("")
.push_line(msg)
.push_line("")
.push_bold_line("\\*\\*END OF SYSTEM MESSAGE\\*\\*")
.build()
}
pub fn print_game_status(game_state: &GameState) -> String {
MessageBuilder::new()
.push_line(format!(
"CURRENT EXPERIMENT PHASE: {} {}",
game_state.current_phase, game_state.phase_number
))
.push_line(format!(
"PHASE END TIME: {}",
game_state.get_phase_end_time()
))
.push_line(format!("PHASE ENDING {}", game_state.get_phase_countdown()))
.build()
}
pub fn get_phase_end_timestamp(hours: u64) -> u64 {
let end_time = std::time::SystemTime::now() + std::time::Duration::from_secs(hours * 60 * 60);
end_time.duration_since(UNIX_EPOCH).unwrap().as_secs()
}