225 lines
6.4 KiB
Rust
225 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_line("Do $help to see all commands.")
|
|
.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()
|
|
}
|