pub mod uno; use std::sync::{Arc, Mutex as StdMutex}; use twitch_irc::message::PrivmsgMessage; use twitchbot_rs::{Bot, ClientQueue, Command, Context}; use crate::uno::{Uno, UnoPlayer, UnoState}; use crate::uno::UnoState::Ended; pub struct PingCommand; impl Command for PingCommand { type CommandPayLoad = Uno; fn execute(&self, pl_am: Arc>, ctx: Context) -> ClientQueue { let mut queue = ClientQueue::new(); let pl = pl_am.lock().unwrap(); queue.say(ctx.channel_login.to_owned(), format!("@{} Pong!", ctx.sender.name)); queue } } pub struct UnoCommand; impl Command for UnoCommand { type CommandPayLoad = Uno; fn execute(&self, pl_am: Arc>, ctx: PrivmsgMessage) -> ClientQueue { let mut queue = ClientQueue::new(); let mut pl = pl_am.lock().unwrap(); if pl.state == Ended { pl.reset(ctx.sender.name.clone()); queue.me(ctx.channel_login, format!("{} started a new uno game, type !join to join.", ctx.sender.name)); } else { queue.me(ctx.channel_login, "Another game going on rn".to_string()); } queue } } pub struct DrawCommand; impl Command for DrawCommand { type CommandPayLoad = Uno; fn execute(&self, pl_am: Arc>, ctx: PrivmsgMessage) -> ClientQueue { let mut queue = ClientQueue::new(); let args: Vec = ctx.message_text.split(' ').map(|s| s.to_string()).collect(); let mut pl = pl_am.lock().unwrap(); let idx = pl.active_player; if pl.players.get_mut(idx).unwrap().name == ctx.sender.name && args.len() > 1 { let amount = args .get(1) .unwrap() .parse::() .unwrap_or(0); for _ in 0..amount { let card = pl.draw(); pl.players.get_mut(idx).unwrap().hand.push(card); } queue.me(ctx.channel_login, format!("{} drew {} cards.", ctx.sender.name, amount)); } else { queue.me(ctx.channel_login, "Sender probably not active player.".to_string()) } queue } } pub struct PlaceCommand; impl Command for PlaceCommand { type CommandPayLoad = Uno; fn execute(&self, pl_am: Arc>, ctx: PrivmsgMessage) -> ClientQueue { let mut queue = ClientQueue::new(); let args: Vec = ctx.message_text.split(' ').map(|s| s.to_string()).collect(); let mut pl = pl_am.lock().unwrap(); let idx = pl.active_player; if pl.players.get_mut(idx).unwrap().name == ctx.sender.name && args.len() > 1 { let hand_idx = args .get(1) .unwrap() .parse::() .unwrap_or(0); if hand_idx < pl.players.get_mut(idx).unwrap().hand.len() { let card = pl.players.get_mut(idx).unwrap().take_card(hand_idx); if card.can_stack(&pl.top) { queue.me(ctx.channel_login, format!("{} placed {}", pl.players.get_mut(idx).unwrap().name, &card)); pl.place(card); } else { queue.me(ctx.channel_login, "Cant stack on that card.".to_string()) } } else { queue.me(ctx.channel_login, "Hand index out of range".to_string()); } } else { queue.me(ctx.channel_login, "Sender probably not active player.".to_string()) } queue } } pub struct JoinCommand; impl Command for JoinCommand { type CommandPayLoad = Uno; fn execute(&self, pl_am: Arc>, ctx: PrivmsgMessage) -> ClientQueue { let mut queue = ClientQueue::new(); let mut pl = pl_am.lock().unwrap(); if pl.state == UnoState::NotStarted { pl.players.push(UnoPlayer::new(ctx.sender.name.clone())); queue.me(ctx.channel_login, format!("{} Joined the game.", ctx.sender.name)); } queue } } pub struct StartCommand; impl Command for StartCommand { type CommandPayLoad = Uno; fn execute(&self, pl_am: Arc>, ctx: PrivmsgMessage) -> ClientQueue { let mut queue = ClientQueue::new(); let mut pl = pl_am.lock().unwrap(); if pl.admin == ctx.sender.name { pl.init(); queue.me(ctx.channel_login, "Game started!".to_string()); } queue } } pub struct EndCommand; impl Command for EndCommand { type CommandPayLoad = Uno; fn execute(&self, pl_am: Arc>, ctx: PrivmsgMessage) -> ClientQueue { let mut queue = ClientQueue::new(); let mut pl = pl_am.lock().unwrap(); if pl.admin == ctx.sender.name { pl.end(); queue.me(ctx.channel_login, "Game ended!".to_string()); } queue } } pub struct HandCommand; impl Command for HandCommand { type CommandPayLoad = Uno; fn execute(&self, pl_am: Arc>, ctx: PrivmsgMessage) -> ClientQueue { let mut queue = ClientQueue::new(); let args: Vec = ctx.message_text.split(' ').map(|s| s.to_string()).collect(); let mut pl = pl_am.lock().unwrap(); let mut index = usize::MAX; for (i, player) in pl.players.iter().enumerate() { if player.name == ctx.sender.name { index = i; } } let mut card_list = String::new(); for card in pl.players.get(index).unwrap().hand.iter().enumerate() { card_list.push_str(format!("{}: {}, ", card.0, card.1).as_str()); } let channel: String = if ctx.sender.name == "daph" { "daphbot".to_string() } else { ctx.sender.name }; queue.say(channel, card_list); queue } } pub struct TopCommand; impl Command for TopCommand { type CommandPayLoad = Uno; fn execute(&self, pl_am: Arc>, ctx: PrivmsgMessage) -> ClientQueue { let mut queue = ClientQueue::new(); let mut pl = pl_am.lock().unwrap(); queue.me(ctx.channel_login, format!("Top: {}", &pl.top)); queue } } #[tokio::test] async fn main() { let mut u = Uno::new("mzntori".to_string()); let login = std::env::var("LOGIN").unwrap(); let oauth = std::env::var("OAUTH").unwrap(); let mut bot = Bot::new( login.as_str(), oauth.as_str(), u, ); bot.add_command("!ping".to_owned(), Box::new(PingCommand {})).await; bot.add_command("!uno".to_owned(), Box::new(UnoCommand {})).await; bot.add_command("!join".to_owned(), Box::new(JoinCommand {})).await; bot.add_command("!draw".to_owned(), Box::new(DrawCommand {})).await; bot.add_command("!start".to_owned(), Box::new(StartCommand {})).await; bot.add_command("!end".to_owned(), Box::new(EndCommand {})).await; bot.add_command("!place".to_owned(), Box::new(PlaceCommand {})).await; bot.add_command("!hand".to_owned(), Box::new(HandCommand {})).await; bot.add_command("!top".to_owned(), Box::new(TopCommand {})).await; bot.run().await; }