Move card definition to new module
This commit is contained in:
		@@ -2,62 +2,6 @@ pub use super::Game;
 | 
				
			|||||||
use serde::{Serialize, Serializer};
 | 
					use serde::{Serialize, Serializer};
 | 
				
			||||||
use std::fmt;
 | 
					use std::fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn copper() -> Card {
 | 
					 | 
				
			||||||
    Card {
 | 
					 | 
				
			||||||
        name: "Copper".into(),
 | 
					 | 
				
			||||||
        cost: 0,
 | 
					 | 
				
			||||||
        types: vec![CardType::Treasure(1)],
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn silver() -> Card {
 | 
					 | 
				
			||||||
    Card {
 | 
					 | 
				
			||||||
        name: "Silver".into(),
 | 
					 | 
				
			||||||
        cost: 3,
 | 
					 | 
				
			||||||
        types: vec![CardType::Treasure(2)],
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn gold() -> Card {
 | 
					 | 
				
			||||||
    Card {
 | 
					 | 
				
			||||||
        name: "Gold".into(),
 | 
					 | 
				
			||||||
        cost: 6,
 | 
					 | 
				
			||||||
        types: vec![CardType::Treasure(3)],
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn estate() -> Card {
 | 
					 | 
				
			||||||
    Card {
 | 
					 | 
				
			||||||
        name: "Estate".into(),
 | 
					 | 
				
			||||||
        cost: 2,
 | 
					 | 
				
			||||||
        types: vec![CardType::Victory(1)],
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn duchy() -> Card {
 | 
					 | 
				
			||||||
    Card {
 | 
					 | 
				
			||||||
        name: "Duchy".into(),
 | 
					 | 
				
			||||||
        cost: 5,
 | 
					 | 
				
			||||||
        types: vec![CardType::Victory(3)],
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn province() -> Card {
 | 
					 | 
				
			||||||
    Card {
 | 
					 | 
				
			||||||
        name: "Province".into(),
 | 
					 | 
				
			||||||
        cost: 8,
 | 
					 | 
				
			||||||
        types: vec![CardType::Victory(6)],
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn curse() -> Card {
 | 
					 | 
				
			||||||
    Card {
 | 
					 | 
				
			||||||
        name: "Curse".into(),
 | 
					 | 
				
			||||||
        cost: 0,
 | 
					 | 
				
			||||||
        types: vec![CardType::Curse],
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
macro_rules! draw {
 | 
					macro_rules! draw {
 | 
				
			||||||
    ($g:ident, $e:expr) => {
 | 
					    ($g:ident, $e:expr) => {
 | 
				
			||||||
        $g.players[$g.active_player].draw($e)
 | 
					        $g.players[$g.active_player].draw($e)
 | 
				
			||||||
@@ -93,6 +37,7 @@ where
 | 
				
			|||||||
pub enum CardType {
 | 
					pub enum CardType {
 | 
				
			||||||
    #[serde(serialize_with = "serialize_card_type")]
 | 
					    #[serde(serialize_with = "serialize_card_type")]
 | 
				
			||||||
    Action(fn(&mut Game)),
 | 
					    Action(fn(&mut Game)),
 | 
				
			||||||
 | 
					    Attack,
 | 
				
			||||||
    Curse,
 | 
					    Curse,
 | 
				
			||||||
    #[serde(serialize_with = "serialize_card_type")]
 | 
					    #[serde(serialize_with = "serialize_card_type")]
 | 
				
			||||||
    Reaction(fn(&mut Game)),
 | 
					    Reaction(fn(&mut Game)),
 | 
				
			||||||
@@ -102,7 +47,7 @@ pub enum CardType {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone)]
 | 
				
			||||||
pub struct Card {
 | 
					pub struct Card {
 | 
				
			||||||
    pub name: String,
 | 
					    pub name: &'static str,
 | 
				
			||||||
    pub cost: u32,
 | 
					    pub cost: u32,
 | 
				
			||||||
    pub types: Vec<CardType>,
 | 
					    pub types: Vec<CardType>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										478
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										478
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -1,8 +1,9 @@
 | 
				
			|||||||
#[macro_use]
 | 
					#[macro_use]
 | 
				
			||||||
mod cards;
 | 
					mod card;
 | 
				
			||||||
 | 
					mod sets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use async_std::{prelude::*, sync::RwLock};
 | 
					use async_std::{prelude::*, sync::RwLock};
 | 
				
			||||||
use cards::*;
 | 
					use card::*;
 | 
				
			||||||
use itertools::Itertools;
 | 
					use itertools::Itertools;
 | 
				
			||||||
use rand::{seq::SliceRandom, thread_rng, Rng};
 | 
					use rand::{seq::SliceRandom, thread_rng, Rng};
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
@@ -157,16 +158,15 @@ impl Default for GameSetup {
 | 
				
			|||||||
    fn default() -> GameSetup {
 | 
					    fn default() -> GameSetup {
 | 
				
			||||||
        GameSetup {
 | 
					        GameSetup {
 | 
				
			||||||
            deck: vec![
 | 
					            deck: vec![
 | 
				
			||||||
                copper(),
 | 
					                sets::base::copper(),
 | 
				
			||||||
                copper(),
 | 
					                sets::base::copper(),
 | 
				
			||||||
                copper(),
 | 
					                sets::base::copper(),
 | 
				
			||||||
                copper(),
 | 
					                sets::base::copper(),
 | 
				
			||||||
                copper(),
 | 
					                sets::base::copper(),
 | 
				
			||||||
                copper(),
 | 
					                sets::base::copper(),
 | 
				
			||||||
                copper(),
 | 
					                sets::base::estate(),
 | 
				
			||||||
                estate(),
 | 
					                sets::base::estate(),
 | 
				
			||||||
                estate(),
 | 
					                sets::base::estate(),
 | 
				
			||||||
                estate(),
 | 
					 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -176,6 +176,7 @@ impl Default for GameSetup {
 | 
				
			|||||||
#[derive(Clone, Serialize)]
 | 
					#[derive(Clone, Serialize)]
 | 
				
			||||||
enum ResolvingPlayer {
 | 
					enum ResolvingPlayer {
 | 
				
			||||||
    ActivePlayer,
 | 
					    ActivePlayer,
 | 
				
			||||||
 | 
					    AllNonActivePlayers,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Deserialize)]
 | 
					#[derive(Deserialize)]
 | 
				
			||||||
@@ -190,14 +191,8 @@ enum ResolveReply {
 | 
				
			|||||||
#[derive(Clone, Serialize)]
 | 
					#[derive(Clone, Serialize)]
 | 
				
			||||||
#[serde(tag = "type")]
 | 
					#[serde(tag = "type")]
 | 
				
			||||||
enum ResolveRequest {
 | 
					enum ResolveRequest {
 | 
				
			||||||
    ChooseHandCardsToDiscard {
 | 
					    ChooseHandCardsToDiscard { filter: CardFilter },
 | 
				
			||||||
        player: ResolvingPlayer,
 | 
					    GainCard { filter: CardFilter },
 | 
				
			||||||
        filter: CardFilter,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    GainCard {
 | 
					 | 
				
			||||||
        player: ResolvingPlayer,
 | 
					 | 
				
			||||||
        filter: CardFilter,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone)]
 | 
				
			||||||
@@ -207,7 +202,18 @@ enum Effect {
 | 
				
			|||||||
    OnCardPlayed(fn(&mut Game, &Card) -> bool),
 | 
					    OnCardPlayed(fn(&mut Game, &Card) -> bool),
 | 
				
			||||||
    /// Effect that blocks further processing of the game state until
 | 
					    /// Effect that blocks further processing of the game state until
 | 
				
			||||||
    /// some user input is received that allows to fully resolve the effect
 | 
					    /// some user input is received that allows to fully resolve the effect
 | 
				
			||||||
    Resolving(String, ResolveRequest, ResolvingEffect),
 | 
					    Resolving {
 | 
				
			||||||
 | 
					        card: String,
 | 
				
			||||||
 | 
					        player: ResolvingPlayer,
 | 
				
			||||||
 | 
					        request: ResolveRequest,
 | 
				
			||||||
 | 
					        effect: ResolvingEffectHandler,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Default)]
 | 
				
			||||||
 | 
					struct EffectState {
 | 
				
			||||||
 | 
					    resolved: bool,
 | 
				
			||||||
 | 
					    players_responded: Vec<usize>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Serialize)]
 | 
					#[derive(Clone, Serialize)]
 | 
				
			||||||
@@ -218,7 +224,8 @@ enum CardFilter {
 | 
				
			|||||||
    Type(CardType),
 | 
					    Type(CardType),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ResolvingEffect = fn(&mut Game, &ResolveReply);
 | 
					type ResolvingEffectHandler =
 | 
				
			||||||
 | 
					    fn(&mut Game, &ResolveReply, usize, &ResolveRequest, &mut EffectState);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Game {
 | 
					pub struct Game {
 | 
				
			||||||
    effects: Vec<Effect>,
 | 
					    effects: Vec<Effect>,
 | 
				
			||||||
@@ -233,7 +240,13 @@ pub struct Game {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// Any effect from a card that requires further input from players
 | 
					    /// Any effect from a card that requires further input from players
 | 
				
			||||||
    /// and blocks the game until fully resolved.
 | 
					    /// and blocks the game until fully resolved.
 | 
				
			||||||
    resolving_effect: Option<(String, ResolveRequest, ResolvingEffect)>,
 | 
					    resolving_effect: Option<(
 | 
				
			||||||
 | 
					        String,
 | 
				
			||||||
 | 
					        ResolveRequest,
 | 
				
			||||||
 | 
					        ResolvingEffectHandler,
 | 
				
			||||||
 | 
					        ResolvingPlayer,
 | 
				
			||||||
 | 
					        EffectState,
 | 
				
			||||||
 | 
					    )>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Game {
 | 
					impl Game {
 | 
				
			||||||
@@ -272,334 +285,23 @@ impl Game {
 | 
				
			|||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                self.supply = vec![
 | 
					                self.supply = vec![
 | 
				
			||||||
                    (copper(), 60 - self.players.len() * 7),
 | 
					                    (sets::base::copper(), 60 - self.players.len() * 7),
 | 
				
			||||||
                    (silver(), 40),
 | 
					                    (sets::base::silver(), 40),
 | 
				
			||||||
                    (gold(), 30),
 | 
					                    (sets::base::gold(), 30),
 | 
				
			||||||
                    (estate(), victory_qty),
 | 
					                    (sets::base::estate(), victory_qty),
 | 
				
			||||||
                    (duchy(), victory_qty),
 | 
					                    (sets::base::duchy(), victory_qty),
 | 
				
			||||||
                    (province(), victory_qty),
 | 
					                    (sets::base::province(), victory_qty),
 | 
				
			||||||
                    (curse(), 10),
 | 
					                    (sets::base::curse(), 10),
 | 
				
			||||||
                    (
 | 
					                    (sets::base::cellar(), 10),
 | 
				
			||||||
                        Card {
 | 
					                    (sets::base::moat(), 10),
 | 
				
			||||||
                            name: "Cellar".into(),
 | 
					                    (sets::base::village(), 10),
 | 
				
			||||||
                            cost: 2,
 | 
					                    (sets::base::merchant(), 10),
 | 
				
			||||||
                            types: vec![CardType::Action(|game| {
 | 
					                    (sets::base::workshop(), 10),
 | 
				
			||||||
                                action!(game, 1);
 | 
					                    (sets::base::simthy(), 10),
 | 
				
			||||||
                                game.add_effect(Effect::Resolving(
 | 
					                    (sets::base::remodel(), 10),
 | 
				
			||||||
                                    "Cellar".into(),
 | 
					                    (sets::base::militia(), 10),
 | 
				
			||||||
                                    ResolveRequest::ChooseHandCardsToDiscard {
 | 
					                    (sets::base::market(), 10),
 | 
				
			||||||
                                        player: ResolvingPlayer::ActivePlayer,
 | 
					                    (sets::base::mine(), 10),
 | 
				
			||||||
                                        filter: CardFilter::Any,
 | 
					 | 
				
			||||||
                                    },
 | 
					 | 
				
			||||||
                                    |game, message| {
 | 
					 | 
				
			||||||
                                        if let ResolveReply::HandCardsChosen { choice } = message {
 | 
					 | 
				
			||||||
                                            let mut discarded = 0;
 | 
					 | 
				
			||||||
                                            for c in choice.iter().sorted_by(|a, b| b.cmp(a)) {
 | 
					 | 
				
			||||||
                                                game.get_active_player().discard(*c);
 | 
					 | 
				
			||||||
                                                //game.players[game.active_player].discard(*c);
 | 
					 | 
				
			||||||
                                                discarded += 1;
 | 
					 | 
				
			||||||
                                            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                            game.players[game.active_player].draw(discarded);
 | 
					 | 
				
			||||||
                                            game.resolving_effect = None;
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                    },
 | 
					 | 
				
			||||||
                                ));
 | 
					 | 
				
			||||||
                            })],
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        10,
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    (
 | 
					 | 
				
			||||||
                        Card {
 | 
					 | 
				
			||||||
                            name: "Moat".into(),
 | 
					 | 
				
			||||||
                            cost: 2,
 | 
					 | 
				
			||||||
                            types: vec![
 | 
					 | 
				
			||||||
                                CardType::Action(|game| {
 | 
					 | 
				
			||||||
                                    draw!(game, 2);
 | 
					 | 
				
			||||||
                                }),
 | 
					 | 
				
			||||||
                                CardType::Reaction(|_| {}),
 | 
					 | 
				
			||||||
                            ],
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        10,
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    (
 | 
					 | 
				
			||||||
                        Card {
 | 
					 | 
				
			||||||
                            name: "Village".into(),
 | 
					 | 
				
			||||||
                            cost: 3,
 | 
					 | 
				
			||||||
                            types: vec![CardType::Action(|game| {
 | 
					 | 
				
			||||||
                                draw!(game, 1);
 | 
					 | 
				
			||||||
                                action!(game, 2);
 | 
					 | 
				
			||||||
                            })],
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        10,
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    (
 | 
					 | 
				
			||||||
                        Card {
 | 
					 | 
				
			||||||
                            name: "Merchant".into(),
 | 
					 | 
				
			||||||
                            cost: 3,
 | 
					 | 
				
			||||||
                            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,
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    (
 | 
					 | 
				
			||||||
                        Card {
 | 
					 | 
				
			||||||
                            name: "Workshop".into(),
 | 
					 | 
				
			||||||
                            cost: 3,
 | 
					 | 
				
			||||||
                            types: vec![CardType::Action(|game| {
 | 
					 | 
				
			||||||
                                game.add_effect(Effect::Resolving(
 | 
					 | 
				
			||||||
                                    "Workshop".into(),
 | 
					 | 
				
			||||||
                                    ResolveRequest::GainCard {
 | 
					 | 
				
			||||||
                                        player: ResolvingPlayer::ActivePlayer,
 | 
					 | 
				
			||||||
                                        filter: CardFilter::MaxCost(4),
 | 
					 | 
				
			||||||
                                    },
 | 
					 | 
				
			||||||
                                    |game, message| {
 | 
					 | 
				
			||||||
                                        if let ResolveReply::SupplyCardChosen { choice } = message {
 | 
					 | 
				
			||||||
                                            if let Some((card, count)) = game.supply.get(*choice) {
 | 
					 | 
				
			||||||
                                                if *count < 1 {
 | 
					 | 
				
			||||||
                                                    return;
 | 
					 | 
				
			||||||
                                                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                                if card.cost > 4 {
 | 
					 | 
				
			||||||
                                                    return;
 | 
					 | 
				
			||||||
                                                }
 | 
					 | 
				
			||||||
                                            }
 | 
					 | 
				
			||||||
                                            game.supply.get_mut(*choice).unwrap().1 =
 | 
					 | 
				
			||||||
                                                game.supply.get(*choice).unwrap().1 - 1;
 | 
					 | 
				
			||||||
                                            let card = game.supply[*choice].0.clone();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                            game.players[game.active_player]
 | 
					 | 
				
			||||||
                                                .discard_pile
 | 
					 | 
				
			||||||
                                                .push(card.clone());
 | 
					 | 
				
			||||||
                                            game.resolving_effect = None;
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                    },
 | 
					 | 
				
			||||||
                                ));
 | 
					 | 
				
			||||||
                            })],
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        10,
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    (
 | 
					 | 
				
			||||||
                        Card {
 | 
					 | 
				
			||||||
                            name: "Smithy".into(),
 | 
					 | 
				
			||||||
                            cost: 4,
 | 
					 | 
				
			||||||
                            types: vec![CardType::Action(|game| draw!(game, 3))],
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        10,
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    (
 | 
					 | 
				
			||||||
                        Card {
 | 
					 | 
				
			||||||
                            name: "Remodel".into(),
 | 
					 | 
				
			||||||
                            cost: 4,
 | 
					 | 
				
			||||||
                            types: vec![CardType::Action(|game| {
 | 
					 | 
				
			||||||
                                game.add_effect(Effect::Resolving(
 | 
					 | 
				
			||||||
                                    "Remodel".into(),
 | 
					 | 
				
			||||||
                                    ResolveRequest::ChooseHandCardsToDiscard {
 | 
					 | 
				
			||||||
                                        player: ResolvingPlayer::ActivePlayer,
 | 
					 | 
				
			||||||
                                        filter: CardFilter::Any,
 | 
					 | 
				
			||||||
                                    },
 | 
					 | 
				
			||||||
                                    |game, message| {
 | 
					 | 
				
			||||||
                                        if let ResolveReply::HandCardsChosen { choice } = message {
 | 
					 | 
				
			||||||
                                            if choice.len() != 1 {
 | 
					 | 
				
			||||||
                                                return;
 | 
					 | 
				
			||||||
                                            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                            let card = game.players[game.active_player]
 | 
					 | 
				
			||||||
                                                .hand
 | 
					 | 
				
			||||||
                                                .remove(choice[0]);
 | 
					 | 
				
			||||||
                                            let cost = card.cost;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                            game.trash.push(card);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                            game.add_effect(Effect::Resolving(
 | 
					 | 
				
			||||||
                                                "Remodel".into(),
 | 
					 | 
				
			||||||
                                                ResolveRequest::GainCard {
 | 
					 | 
				
			||||||
                                                    player: ResolvingPlayer::ActivePlayer,
 | 
					 | 
				
			||||||
                                                    filter: CardFilter::MaxCost(cost + 2),
 | 
					 | 
				
			||||||
                                                },
 | 
					 | 
				
			||||||
                                                |game, message| {
 | 
					 | 
				
			||||||
                                                    if let ResolveReply::SupplyCardChosen {
 | 
					 | 
				
			||||||
                                                        choice,
 | 
					 | 
				
			||||||
                                                    } = message
 | 
					 | 
				
			||||||
                                                    {
 | 
					 | 
				
			||||||
                                                        if let Some((card, count)) =
 | 
					 | 
				
			||||||
                                                            game.supply.get(*choice)
 | 
					 | 
				
			||||||
                                                        {
 | 
					 | 
				
			||||||
                                                            if *count < 1 {
 | 
					 | 
				
			||||||
                                                                return;
 | 
					 | 
				
			||||||
                                                            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                                            if let Some((
 | 
					 | 
				
			||||||
                                                                _,
 | 
					 | 
				
			||||||
                                                                ResolveRequest::GainCard {
 | 
					 | 
				
			||||||
                                                                    filter:
 | 
					 | 
				
			||||||
                                                                        CardFilter::MaxCost(cost),
 | 
					 | 
				
			||||||
                                                                    ..
 | 
					 | 
				
			||||||
                                                                },
 | 
					 | 
				
			||||||
                                                                _,
 | 
					 | 
				
			||||||
                                                            )) = game.resolving_effect
 | 
					 | 
				
			||||||
                                                            {
 | 
					 | 
				
			||||||
                                                                if card.cost > cost {
 | 
					 | 
				
			||||||
                                                                    return;
 | 
					 | 
				
			||||||
                                                                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                                                game.supply
 | 
					 | 
				
			||||||
                                                                    .get_mut(*choice)
 | 
					 | 
				
			||||||
                                                                    .unwrap()
 | 
					 | 
				
			||||||
                                                                    .1 = game
 | 
					 | 
				
			||||||
                                                                    .supply
 | 
					 | 
				
			||||||
                                                                    .get(*choice)
 | 
					 | 
				
			||||||
                                                                    .unwrap()
 | 
					 | 
				
			||||||
                                                                    .1
 | 
					 | 
				
			||||||
                                                                    - 1;
 | 
					 | 
				
			||||||
                                                                let card =
 | 
					 | 
				
			||||||
                                                                    game.supply[*choice].0.clone();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                                                game.players[game.active_player]
 | 
					 | 
				
			||||||
                                                                    .discard_pile
 | 
					 | 
				
			||||||
                                                                    .push(card.clone());
 | 
					 | 
				
			||||||
                                                                game.resolving_effect = None;
 | 
					 | 
				
			||||||
                                                            }
 | 
					 | 
				
			||||||
                                                        }
 | 
					 | 
				
			||||||
                                                    }
 | 
					 | 
				
			||||||
                                                },
 | 
					 | 
				
			||||||
                                            ));
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                    },
 | 
					 | 
				
			||||||
                                ));
 | 
					 | 
				
			||||||
                            })],
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        10,
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    (
 | 
					 | 
				
			||||||
                        Card {
 | 
					 | 
				
			||||||
                            name: "Militia".into(),
 | 
					 | 
				
			||||||
                            cost: 4,
 | 
					 | 
				
			||||||
                            types: vec![CardType::Action(|game| {
 | 
					 | 
				
			||||||
                                coin!(game, 2);
 | 
					 | 
				
			||||||
                            })],
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        10,
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    (
 | 
					 | 
				
			||||||
                        Card {
 | 
					 | 
				
			||||||
                            name: "Market".into(),
 | 
					 | 
				
			||||||
                            cost: 5,
 | 
					 | 
				
			||||||
                            types: vec![CardType::Action(|game| {
 | 
					 | 
				
			||||||
                                draw!(game, 1);
 | 
					 | 
				
			||||||
                                action!(game, 1);
 | 
					 | 
				
			||||||
                                buy!(game, 1);
 | 
					 | 
				
			||||||
                                coin!(game, 1);
 | 
					 | 
				
			||||||
                            })],
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        10,
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    (
 | 
					 | 
				
			||||||
                        Card {
 | 
					 | 
				
			||||||
                            name: "Mine".into(),
 | 
					 | 
				
			||||||
                            cost: 5,
 | 
					 | 
				
			||||||
                            types: vec![CardType::Action(|game| {
 | 
					 | 
				
			||||||
                                game.add_effect(Effect::Resolving(
 | 
					 | 
				
			||||||
                                    "Mine".into(),
 | 
					 | 
				
			||||||
                                    ResolveRequest::ChooseHandCardsToDiscard {
 | 
					 | 
				
			||||||
                                        player: ResolvingPlayer::ActivePlayer,
 | 
					 | 
				
			||||||
                                        filter: CardFilter::Type(CardType::Treasure(0)),
 | 
					 | 
				
			||||||
                                    },
 | 
					 | 
				
			||||||
                                    |game, message| {
 | 
					 | 
				
			||||||
                                        if let ResolveReply::HandCardsChosen { choice } = message {
 | 
					 | 
				
			||||||
                                            if choice.len() != 1 {
 | 
					 | 
				
			||||||
                                                return;
 | 
					 | 
				
			||||||
                                            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                            if let Some(card) =
 | 
					 | 
				
			||||||
                                                game.get_active_player().hand.get(choice[0])
 | 
					 | 
				
			||||||
                                            {
 | 
					 | 
				
			||||||
                                                if let None = card.treasure() {
 | 
					 | 
				
			||||||
                                                    return;
 | 
					 | 
				
			||||||
                                                }
 | 
					 | 
				
			||||||
                                            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                            let card = game.players[game.active_player]
 | 
					 | 
				
			||||||
                                                .hand
 | 
					 | 
				
			||||||
                                                .remove(choice[0]);
 | 
					 | 
				
			||||||
                                            let cost = card.cost;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                            game.trash.push(card);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                            game.add_effect(Effect::Resolving(
 | 
					 | 
				
			||||||
                                                "Mine".into(),
 | 
					 | 
				
			||||||
                                                ResolveRequest::GainCard {
 | 
					 | 
				
			||||||
                                                    player: ResolvingPlayer::ActivePlayer,
 | 
					 | 
				
			||||||
                                                    filter: CardFilter::MaxCost(cost + 3),
 | 
					 | 
				
			||||||
                                                },
 | 
					 | 
				
			||||||
                                                |game, message| {
 | 
					 | 
				
			||||||
                                                    if let ResolveReply::SupplyCardChosen {
 | 
					 | 
				
			||||||
                                                        choice,
 | 
					 | 
				
			||||||
                                                    } = message
 | 
					 | 
				
			||||||
                                                    {
 | 
					 | 
				
			||||||
                                                        if let Some((card, count)) =
 | 
					 | 
				
			||||||
                                                            game.supply.get(*choice)
 | 
					 | 
				
			||||||
                                                        {
 | 
					 | 
				
			||||||
                                                            if *count < 1 {
 | 
					 | 
				
			||||||
                                                                return;
 | 
					 | 
				
			||||||
                                                            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                                            if let Some((
 | 
					 | 
				
			||||||
                                                                _,
 | 
					 | 
				
			||||||
                                                                ResolveRequest::GainCard {
 | 
					 | 
				
			||||||
                                                                    filter:
 | 
					 | 
				
			||||||
                                                                        CardFilter::MaxCost(cost),
 | 
					 | 
				
			||||||
                                                                    ..
 | 
					 | 
				
			||||||
                                                                },
 | 
					 | 
				
			||||||
                                                                _,
 | 
					 | 
				
			||||||
                                                            )) = game.resolving_effect
 | 
					 | 
				
			||||||
                                                            {
 | 
					 | 
				
			||||||
                                                                if card.cost > cost {
 | 
					 | 
				
			||||||
                                                                    return;
 | 
					 | 
				
			||||||
                                                                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                                                if let None = card.treasure() {
 | 
					 | 
				
			||||||
                                                                    return;
 | 
					 | 
				
			||||||
                                                                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                                                game.supply
 | 
					 | 
				
			||||||
                                                                    .get_mut(*choice)
 | 
					 | 
				
			||||||
                                                                    .unwrap()
 | 
					 | 
				
			||||||
                                                                    .1 = game
 | 
					 | 
				
			||||||
                                                                    .supply
 | 
					 | 
				
			||||||
                                                                    .get(*choice)
 | 
					 | 
				
			||||||
                                                                    .unwrap()
 | 
					 | 
				
			||||||
                                                                    .1
 | 
					 | 
				
			||||||
                                                                    - 1;
 | 
					 | 
				
			||||||
                                                                let card =
 | 
					 | 
				
			||||||
                                                                    game.supply[*choice].0.clone();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                                                game.players[game.active_player]
 | 
					 | 
				
			||||||
                                                                    .discard_pile
 | 
					 | 
				
			||||||
                                                                    .push(card.clone());
 | 
					 | 
				
			||||||
                                                                game.resolving_effect = None;
 | 
					 | 
				
			||||||
                                                            }
 | 
					 | 
				
			||||||
                                                        }
 | 
					 | 
				
			||||||
                                                    }
 | 
					 | 
				
			||||||
                                                },
 | 
					 | 
				
			||||||
                                            ));
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                    },
 | 
					 | 
				
			||||||
                                ));
 | 
					 | 
				
			||||||
                            })],
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        10,
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                ];
 | 
					                ];
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -722,7 +424,7 @@ impl Game {
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Effect::Resolving(_, _, _) => {}
 | 
					                Effect::Resolving { .. } => {}
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            true
 | 
					            true
 | 
				
			||||||
@@ -769,8 +471,14 @@ impl Game {
 | 
				
			|||||||
                self.effects.push(effect);
 | 
					                self.effects.push(effect);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Effect::Resolving(card_name, request, effect) => {
 | 
					            Effect::Resolving {
 | 
				
			||||||
                self.resolving_effect = Some((card_name, request, effect));
 | 
					                card,
 | 
				
			||||||
 | 
					                request,
 | 
				
			||||||
 | 
					                effect,
 | 
				
			||||||
 | 
					                player,
 | 
				
			||||||
 | 
					            } => {
 | 
				
			||||||
 | 
					                let state = EffectState::default();
 | 
				
			||||||
 | 
					                self.resolving_effect = Some((card, request, effect, player, state));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -804,8 +512,12 @@ async fn broadcast_state(game: &Game) {
 | 
				
			|||||||
                name: html_escape::encode_text(&p.name).into(),
 | 
					                name: html_escape::encode_text(&p.name).into(),
 | 
				
			||||||
                draw_pile_count: p.draw_pile.len(),
 | 
					                draw_pile_count: p.draw_pile.len(),
 | 
				
			||||||
                hand_count: p.hand.len(),
 | 
					                hand_count: p.hand.len(),
 | 
				
			||||||
                discard_pile: p.discard_pile.last().map(|c| c.name.clone()),
 | 
					                discard_pile: p.discard_pile.last().map(|c| c.name.clone().into()),
 | 
				
			||||||
                played_cards: p.played_cards.iter().map(|c| c.name.clone()).collect(),
 | 
					                played_cards: p
 | 
				
			||||||
 | 
					                    .played_cards
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .map(|c| c.name.clone().into())
 | 
				
			||||||
 | 
					                    .collect(),
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .collect(),
 | 
					            .collect(),
 | 
				
			||||||
        active_player: game.active_player,
 | 
					        active_player: game.active_player,
 | 
				
			||||||
@@ -855,9 +567,9 @@ async fn broadcast_state(game: &Game) {
 | 
				
			|||||||
        broadcast(&game, &sm).await;
 | 
					        broadcast(&game, &sm).await;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if let Some((card_name, request, _)) = &game.resolving_effect {
 | 
					    if let Some((card_name, request, _, ref player, _)) = &game.resolving_effect {
 | 
				
			||||||
        match request {
 | 
					        match request {
 | 
				
			||||||
            ResolveRequest::ChooseHandCardsToDiscard { ref player, .. } => match player {
 | 
					            ResolveRequest::ChooseHandCardsToDiscard { .. } => match player {
 | 
				
			||||||
                ResolvingPlayer::ActivePlayer => {
 | 
					                ResolvingPlayer::ActivePlayer => {
 | 
				
			||||||
                    let p = game.players.get(game.active_player).unwrap();
 | 
					                    let p = game.players.get(game.active_player).unwrap();
 | 
				
			||||||
                    let sm = ServerMessage::ResolveRequest {
 | 
					                    let sm = ServerMessage::ResolveRequest {
 | 
				
			||||||
@@ -866,9 +578,22 @@ async fn broadcast_state(game: &Game) {
 | 
				
			|||||||
                    };
 | 
					                    };
 | 
				
			||||||
                    send_msg(&game, &p, &sm).await;
 | 
					                    send_msg(&game, &p, &sm).await;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ResolvingPlayer::AllNonActivePlayers => {
 | 
				
			||||||
 | 
					                    for (id, player) in game.players.iter().enumerate() {
 | 
				
			||||||
 | 
					                        let sm = ServerMessage::ResolveRequest {
 | 
				
			||||||
 | 
					                            card: card_name.clone(),
 | 
				
			||||||
 | 
					                            request: request.clone(),
 | 
				
			||||||
 | 
					                        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if id != game.active_player {
 | 
				
			||||||
 | 
					                            send_msg(&game, &player, &sm).await;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ResolveRequest::GainCard { ref player, .. } => match player {
 | 
					            ResolveRequest::GainCard { .. } => match player {
 | 
				
			||||||
                ResolvingPlayer::ActivePlayer => {
 | 
					                ResolvingPlayer::ActivePlayer => {
 | 
				
			||||||
                    let p = game.players.get(game.active_player).unwrap();
 | 
					                    let p = game.players.get(game.active_player).unwrap();
 | 
				
			||||||
                    let sm = ServerMessage::ResolveRequest {
 | 
					                    let sm = ServerMessage::ResolveRequest {
 | 
				
			||||||
@@ -877,6 +602,8 @@ async fn broadcast_state(game: &Game) {
 | 
				
			|||||||
                    };
 | 
					                    };
 | 
				
			||||||
                    send_msg(&game, &p, &sm).await;
 | 
					                    send_msg(&game, &p, &sm).await;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                _ => unimplemented!("GainCard for non active players?!"),
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -1177,19 +904,42 @@ async fn main() -> Result<(), std::io::Error> {
 | 
				
			|||||||
                        let mut games = req.state().games.write().await;
 | 
					                        let mut games = req.state().games.write().await;
 | 
				
			||||||
                        let game = games.get_mut(&game_id).unwrap();
 | 
					                        let game = games.get_mut(&game_id).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if let Some((card, request, effect, player, mut state)) =
 | 
				
			||||||
 | 
					                            game.resolving_effect.take()
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            match player {
 | 
				
			||||||
 | 
					                                ResolvingPlayer::ActivePlayer => {
 | 
				
			||||||
                                    if player_number == game.active_player {
 | 
					                                    if player_number == game.active_player {
 | 
				
			||||||
                            match game.resolving_effect {
 | 
					                                        effect(
 | 
				
			||||||
                                Some((_, _, ref effect)) => {
 | 
					                                            game,
 | 
				
			||||||
                                    effect(game, &reply);
 | 
					                                            &reply,
 | 
				
			||||||
 | 
					                                            game.active_player,
 | 
				
			||||||
 | 
					                                            &request,
 | 
				
			||||||
 | 
					                                            &mut state,
 | 
				
			||||||
 | 
					                                        );
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                ResolvingPlayer::AllNonActivePlayers => {
 | 
				
			||||||
 | 
					                                    if player_number != game.active_player {
 | 
				
			||||||
 | 
					                                        effect(game, &reply, player_number, &request, &mut state);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            match state.resolved {
 | 
				
			||||||
 | 
					                                false => {
 | 
				
			||||||
 | 
					                                    game.resolving_effect =
 | 
				
			||||||
 | 
					                                        Some((card, request, effect, player, state));
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                true => {}
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                                None => {}
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        broadcast_state(&game).await;
 | 
					                        broadcast_state(&game).await;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let mut games = req.state().games.write().await;
 | 
					            let mut games = req.state().games.write().await;
 | 
				
			||||||
            let game = games.get_mut(&game_id).unwrap();
 | 
					            let game = games.get_mut(&game_id).unwrap();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										377
									
								
								src/sets/base.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										377
									
								
								src/sets/base.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,377 @@
 | 
				
			|||||||
 | 
					use crate::card::{Card, CardType};
 | 
				
			||||||
 | 
					use crate::{CardFilter, Effect, ResolveReply, ResolveRequest, ResolvingPlayer};
 | 
				
			||||||
 | 
					use itertools::Itertools;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn copper() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Copper",
 | 
				
			||||||
 | 
					        cost: 0,
 | 
				
			||||||
 | 
					        types: vec![CardType::Treasure(1)],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn silver() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Silver",
 | 
				
			||||||
 | 
					        cost: 3,
 | 
				
			||||||
 | 
					        types: vec![CardType::Treasure(2)],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn gold() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Gold",
 | 
				
			||||||
 | 
					        cost: 6,
 | 
				
			||||||
 | 
					        types: vec![CardType::Treasure(3)],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn estate() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Estate",
 | 
				
			||||||
 | 
					        cost: 2,
 | 
				
			||||||
 | 
					        types: vec![CardType::Victory(1)],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn duchy() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Duchy",
 | 
				
			||||||
 | 
					        cost: 5,
 | 
				
			||||||
 | 
					        types: vec![CardType::Victory(3)],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn province() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Province",
 | 
				
			||||||
 | 
					        cost: 8,
 | 
				
			||||||
 | 
					        types: vec![CardType::Victory(6)],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn curse() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Curse",
 | 
				
			||||||
 | 
					        cost: 0,
 | 
				
			||||||
 | 
					        types: vec![CardType::Curse],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn cellar() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Cellar",
 | 
				
			||||||
 | 
					        cost: 2,
 | 
				
			||||||
 | 
					        types: vec![CardType::Action(|game| {
 | 
				
			||||||
 | 
					            action!(game, 1);
 | 
				
			||||||
 | 
					            game.add_effect(Effect::Resolving {
 | 
				
			||||||
 | 
					                card: "Cellar".into(),
 | 
				
			||||||
 | 
					                request: ResolveRequest::ChooseHandCardsToDiscard {
 | 
				
			||||||
 | 
					                    filter: CardFilter::Any,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                player: ResolvingPlayer::ActivePlayer,
 | 
				
			||||||
 | 
					                effect: |game, message, _player, _request, state| {
 | 
				
			||||||
 | 
					                    if let ResolveReply::HandCardsChosen { choice } = message {
 | 
				
			||||||
 | 
					                        let mut discarded = 0;
 | 
				
			||||||
 | 
					                        for c in choice.iter().sorted_by(|a, b| b.cmp(a)) {
 | 
				
			||||||
 | 
					                            game.get_active_player().discard(*c);
 | 
				
			||||||
 | 
					                            discarded += 1;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        game.players[game.active_player].draw(discarded);
 | 
				
			||||||
 | 
					                        state.resolved = true;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        })],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn moat() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Moat",
 | 
				
			||||||
 | 
					        cost: 2,
 | 
				
			||||||
 | 
					        types: vec![
 | 
				
			||||||
 | 
					            CardType::Action(|game| {
 | 
				
			||||||
 | 
					                draw!(game, 2);
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            CardType::Reaction(|_| {}),
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn village() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Village",
 | 
				
			||||||
 | 
					        cost: 3,
 | 
				
			||||||
 | 
					        types: vec![CardType::Action(|game| {
 | 
				
			||||||
 | 
					            draw!(game, 1);
 | 
				
			||||||
 | 
					            action!(game, 2);
 | 
				
			||||||
 | 
					        })],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn merchant() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Merchant",
 | 
				
			||||||
 | 
					        cost: 3,
 | 
				
			||||||
 | 
					        types: vec![CardType::Action(|game| {
 | 
				
			||||||
 | 
					            draw!(game, 1);
 | 
				
			||||||
 | 
					            action!(game, 1);
 | 
				
			||||||
 | 
					            game.add_effect(Effect::OnCardPlayed(|game, card| {
 | 
				
			||||||
 | 
					                if card.name == "Silver" {
 | 
				
			||||||
 | 
					                    coin!(game, 1);
 | 
				
			||||||
 | 
					                    true
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    false
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					        })],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn workshop() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Workshop",
 | 
				
			||||||
 | 
					        cost: 3,
 | 
				
			||||||
 | 
					        types: vec![CardType::Action(|game| {
 | 
				
			||||||
 | 
					            game.add_effect(Effect::Resolving {
 | 
				
			||||||
 | 
					                card: "Workshop".into(),
 | 
				
			||||||
 | 
					                request: ResolveRequest::GainCard {
 | 
				
			||||||
 | 
					                    filter: CardFilter::MaxCost(4),
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                player: ResolvingPlayer::ActivePlayer,
 | 
				
			||||||
 | 
					                effect: |game, message, _player, _request, state| {
 | 
				
			||||||
 | 
					                    if let ResolveReply::SupplyCardChosen { choice } = message {
 | 
				
			||||||
 | 
					                        if let Some((card, count)) = game.supply.get(*choice) {
 | 
				
			||||||
 | 
					                            if *count < 1 {
 | 
				
			||||||
 | 
					                                return;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if card.cost > 4 {
 | 
				
			||||||
 | 
					                                return;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        game.supply.get_mut(*choice).unwrap().1 =
 | 
				
			||||||
 | 
					                            game.supply.get(*choice).unwrap().1 - 1;
 | 
				
			||||||
 | 
					                        let card = game.supply[*choice].0.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        game.players[game.active_player]
 | 
				
			||||||
 | 
					                            .discard_pile
 | 
				
			||||||
 | 
					                            .push(card.clone());
 | 
				
			||||||
 | 
					                        state.resolved = true;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        })],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn simthy() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Smithy",
 | 
				
			||||||
 | 
					        cost: 4,
 | 
				
			||||||
 | 
					        types: vec![CardType::Action(|game| draw!(game, 3))],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn remodel() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Remodel",
 | 
				
			||||||
 | 
					        cost: 4,
 | 
				
			||||||
 | 
					        types: vec![CardType::Action(|game| {
 | 
				
			||||||
 | 
					            game.add_effect(Effect::Resolving {
 | 
				
			||||||
 | 
					                card: "Remodel".into(),
 | 
				
			||||||
 | 
					                request: ResolveRequest::ChooseHandCardsToDiscard {
 | 
				
			||||||
 | 
					                    filter: CardFilter::Any,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                player: ResolvingPlayer::ActivePlayer,
 | 
				
			||||||
 | 
					                effect: |game, message, _player, _request, state| {
 | 
				
			||||||
 | 
					                    if let ResolveReply::HandCardsChosen { choice } = message {
 | 
				
			||||||
 | 
					                        if choice.len() != 1 {
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        let card = game.players[game.active_player].hand.remove(choice[0]);
 | 
				
			||||||
 | 
					                        let cost = card.cost;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        game.trash.push(card);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        state.resolved = true;
 | 
				
			||||||
 | 
					                        game.add_effect(Effect::Resolving {
 | 
				
			||||||
 | 
					                            card: "Remodel".into(),
 | 
				
			||||||
 | 
					                            request: ResolveRequest::GainCard {
 | 
				
			||||||
 | 
					                                filter: CardFilter::MaxCost(cost + 2),
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            player: ResolvingPlayer::ActivePlayer,
 | 
				
			||||||
 | 
					                            effect: |game, message, _player, request, state| {
 | 
				
			||||||
 | 
					                                if let ResolveReply::SupplyCardChosen { choice } = message {
 | 
				
			||||||
 | 
					                                    if let Some((card, count)) = game.supply.get(*choice) {
 | 
				
			||||||
 | 
					                                        if *count < 1 {
 | 
				
			||||||
 | 
					                                            return;
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        if let ResolveRequest::GainCard {
 | 
				
			||||||
 | 
					                                            filter: CardFilter::MaxCost(cost),
 | 
				
			||||||
 | 
					                                            ..
 | 
				
			||||||
 | 
					                                        } = request
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            if card.cost > *cost {
 | 
				
			||||||
 | 
					                                                return;
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            game.supply.get_mut(*choice).unwrap().1 =
 | 
				
			||||||
 | 
					                                                game.supply.get(*choice).unwrap().1 - 1;
 | 
				
			||||||
 | 
					                                            let card = game.supply[*choice].0.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            game.players[game.active_player]
 | 
				
			||||||
 | 
					                                                .discard_pile
 | 
				
			||||||
 | 
					                                                .push(card.clone());
 | 
				
			||||||
 | 
					                                            state.resolved = true;
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        })],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn militia() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Militia",
 | 
				
			||||||
 | 
					        cost: 4,
 | 
				
			||||||
 | 
					        types: vec![
 | 
				
			||||||
 | 
					            CardType::Attack,
 | 
				
			||||||
 | 
					            CardType::Action(|game| {
 | 
				
			||||||
 | 
					                coin!(game, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if game.players.len() == 1 {
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                game.add_effect(Effect::Resolving {
 | 
				
			||||||
 | 
					                    card: "Militia".into(),
 | 
				
			||||||
 | 
					                    request: ResolveRequest::ChooseHandCardsToDiscard {
 | 
				
			||||||
 | 
					                        filter: CardFilter::Any,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    player: ResolvingPlayer::AllNonActivePlayers,
 | 
				
			||||||
 | 
					                    effect: |game, message, player, _request, state| {
 | 
				
			||||||
 | 
					                        if let ResolveReply::HandCardsChosen { choice } = message {
 | 
				
			||||||
 | 
					                            if choice.len() == 0 {
 | 
				
			||||||
 | 
					                                if !game.players[player].hand.iter().any(|c| c.name == "Moat") {
 | 
				
			||||||
 | 
					                                    return;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            } else if game.players[player].hand.len() > 3
 | 
				
			||||||
 | 
					                                && choice.len() != game.players[player].hand.len() - 3
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                return;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            for c in choice.iter().sorted_by(|a, b| b.cmp(a)) {
 | 
				
			||||||
 | 
					                                game.players[player].discard(*c);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            state.players_responded.push(player);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if state.players_responded.len() == game.players.len() - 1 {
 | 
				
			||||||
 | 
					                                state.resolved = true;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn market() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Market",
 | 
				
			||||||
 | 
					        cost: 5,
 | 
				
			||||||
 | 
					        types: vec![CardType::Action(|game| {
 | 
				
			||||||
 | 
					            draw!(game, 1);
 | 
				
			||||||
 | 
					            action!(game, 1);
 | 
				
			||||||
 | 
					            buy!(game, 1);
 | 
				
			||||||
 | 
					            coin!(game, 1);
 | 
				
			||||||
 | 
					        })],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn mine() -> Card {
 | 
				
			||||||
 | 
					    Card {
 | 
				
			||||||
 | 
					        name: "Mine",
 | 
				
			||||||
 | 
					        cost: 5,
 | 
				
			||||||
 | 
					        types: vec![CardType::Action(|game| {
 | 
				
			||||||
 | 
					            game.add_effect(Effect::Resolving {
 | 
				
			||||||
 | 
					                card: "Mine".into(),
 | 
				
			||||||
 | 
					                request: ResolveRequest::ChooseHandCardsToDiscard {
 | 
				
			||||||
 | 
					                    filter: CardFilter::Type(CardType::Treasure(0)),
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                player: ResolvingPlayer::ActivePlayer,
 | 
				
			||||||
 | 
					                effect: |game, message, _player, _request, state| {
 | 
				
			||||||
 | 
					                    if let ResolveReply::HandCardsChosen { choice } = message {
 | 
				
			||||||
 | 
					                        if choice.len() != 1 {
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if let Some(card) = game.get_active_player().hand.get(choice[0]) {
 | 
				
			||||||
 | 
					                            if let None = card.treasure() {
 | 
				
			||||||
 | 
					                                return;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        let card = game.players[game.active_player].hand.remove(choice[0]);
 | 
				
			||||||
 | 
					                        let cost = card.cost;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        game.trash.push(card);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        state.resolved = true;
 | 
				
			||||||
 | 
					                        game.add_effect(Effect::Resolving {
 | 
				
			||||||
 | 
					                            card: "Mine".into(),
 | 
				
			||||||
 | 
					                            request: ResolveRequest::GainCard {
 | 
				
			||||||
 | 
					                                filter: CardFilter::MaxCost(cost + 3),
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            player: ResolvingPlayer::ActivePlayer,
 | 
				
			||||||
 | 
					                            effect: |game, message, _player, request, state| {
 | 
				
			||||||
 | 
					                                if let ResolveReply::SupplyCardChosen { choice } = message {
 | 
				
			||||||
 | 
					                                    if let Some((card, count)) = game.supply.get(*choice) {
 | 
				
			||||||
 | 
					                                        if *count < 1 {
 | 
				
			||||||
 | 
					                                            return;
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        if let ResolveRequest::GainCard {
 | 
				
			||||||
 | 
					                                            filter: CardFilter::MaxCost(cost),
 | 
				
			||||||
 | 
					                                            ..
 | 
				
			||||||
 | 
					                                        } = request
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            if card.cost > *cost {
 | 
				
			||||||
 | 
					                                                return;
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            if let None = card.treasure() {
 | 
				
			||||||
 | 
					                                                return;
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            game.supply.get_mut(*choice).unwrap().1 =
 | 
				
			||||||
 | 
					                                                game.supply.get(*choice).unwrap().1 - 1;
 | 
				
			||||||
 | 
					                                            let card = game.supply[*choice].0.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            game.players[game.active_player]
 | 
				
			||||||
 | 
					                                                .discard_pile
 | 
				
			||||||
 | 
					                                                .push(card.clone());
 | 
				
			||||||
 | 
					                                            state.resolved = true;
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        })],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/sets/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/sets/mod.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					pub mod base;
 | 
				
			||||||
		Reference in New Issue
	
	Block a user