diff --git a/src/cards.rs b/src/cards.rs index 22afcfe..9a054d8 100644 --- a/src/cards.rs +++ b/src/cards.rs @@ -86,6 +86,7 @@ macro_rules! coin { pub enum CardType { Action(fn(&mut Game)), Curse, + Reaction(fn(&mut Game)), Treasure(u32), Victory(u32), } diff --git a/src/main.rs b/src/main.rs index 6360892..c86714f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -165,7 +165,13 @@ impl Default for GameSetup { } } +#[derive(Clone)] +enum Effect { + OnCardPlayed(fn(&mut Game, &Card) -> bool), +} + pub struct Game { + effects: Vec, players: Vec, state: GameState, setup: GameSetup, @@ -179,6 +185,7 @@ pub struct Game { impl Game { fn new(player: Player) -> Self { Self { + effects: vec![], players: vec![player], state: GameState::Setup, setup: GameSetup::default(), @@ -227,7 +234,12 @@ impl Game { Card { name: "Moat".into(), cost: 2, - types: vec![CardType::Action(|game| draw!(game, 2))], + types: vec![ + CardType::Action(|game| { + draw!(game, 2); + }), + CardType::Reaction(|_| {}), + ], }, 10, ), @@ -249,6 +261,14 @@ impl Game { types: vec![CardType::Action(|game| { draw!(game, 1); action!(game, 1); + game.add_effect(Effect::OnCardPlayed(|game, card| { + if card.name.as_str() == "Silver" { + coin!(game, 1); + true + } else { + false + } + })); })], }, 10, @@ -257,7 +277,7 @@ impl Game { Card { name: "Workshop".into(), cost: 3, - types: vec![CardType::Action(|game| {})], + types: vec![CardType::Action(|_| {})], }, 10, ), @@ -273,7 +293,7 @@ impl Game { Card { name: "Remodel".into(), cost: 4, - types: vec![CardType::Action(|game| {})], + types: vec![CardType::Action(|_| {})], }, 10, ), @@ -304,7 +324,7 @@ impl Game { Card { name: "Mine".into(), cost: 5, - types: vec![CardType::Action(|game| {})], + types: vec![CardType::Action(|_| {})], }, 10, ), @@ -330,6 +350,8 @@ impl Game { self.active_player += 1; self.active_player %= self.players.len(); self.turn_state = TurnState::default(); + + self.effects.clear(); } // Check if the end game condition is reached and finish the game if so, @@ -368,7 +390,32 @@ impl Game { .push(self.players[player_number].hand.remove(index)); } - pub fn play_card(&mut self, player_number: usize, index: usize) { + pub fn can_play(&self, player_number: usize, index: usize) -> bool { + let card = self.players[player_number].hand.get(index).unwrap(); + + match card.action() { + Some(_) => { + if self.turn_state.actions > 0 { + return true; + } + } + None => (), + } + + match card.treasure() { + Some(_) => { + return true; + } + None => (), + } + + false + } + + pub fn play_card(&mut self, player_number: usize, index: usize) -> bool { + if !self.can_play(player_number, index) { + return false; + } let card = self.players[player_number].hand.remove(index); if let Some(coin) = card.treasure() { @@ -381,7 +428,22 @@ impl Game { effect(self); } + let mut effects = self.effects.clone(); + effects.retain(|effect| { + match effect { + Effect::OnCardPlayed(effect) => { + if effect(self, &card) { + return false; + } + } + } + + true + }); + self.effects = effects; + self.players[player_number].played_cards.push(card); + true } pub fn buy_card(&mut self, player_number: usize, index: usize) -> bool /*-> Result<(), &'static str>*/ @@ -409,6 +471,10 @@ impl Game { //Err("Not enough coin"); false } + + fn add_effect(&mut self, effect: Effect) { + self.effects.push(effect); + } } #[derive(Clone, Default)] @@ -683,14 +749,17 @@ async fn main() -> Result<(), std::io::Error> { let game = games.get_mut(&game_id).unwrap(); let card_name = game.players[player_number].hand[index].name.clone(); - game.play_card(player_number, index); - - notify_players( - &game, - format!("{} spielt {}", game.players[player_number].name, card_name), - ) - .await; - broadcast_state(&game).await; + if game.play_card(player_number, index) { + notify_players( + &game, + format!( + "{} spielt {}", + game.players[player_number].name, card_name + ), + ) + .await; + broadcast_state(&game).await; + } } ClientMessage::BuyCard { index } => {