use std::{borrow::Cow, fmt::Display}; use serde::Deserialize; use yoke::Yokeable; use super::player::Position; /// A card in a players deck which can apply an effect /// to the game or advance a solution #[derive(Default, Deserialize, Yokeable)] #[serde(default)] pub struct ActionCard<'a> { /// How much influence the card will cost to play influence: i32, /// The effects the card will have on the game once it's played effects: Vec, /// The image on the card image: Cow<'a, str>, /// A description of what the card does description: Cow<'a, str>, /// The name of the card name: Cow<'a, str>, /// The position that this card can exclusively be used by position: Option, /// The maximum number of times this card can be drawn draw_limit: u32, } impl<'a> Display for ActionCard<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for effect in &self.effects { write!(f, "{} ", effect)?; } if self.draw_limit > 0 { write!( f, "This card can only ever be drawn {} times.", self.draw_limit )?; } Ok(()) } } /// A card which must be solved by someone on the politburo #[derive(Default, Deserialize)] #[serde(default)] pub struct SituationCard<'a> { /// Points associated with the card points: i32, /// Solving this card benefits the player in this position benefactor: Vec, /// The image on the card image: Cow<'a, str>, /// The name of the card name: Cow<'a, str>, /// A description of the situation the card entails description: Cow<'a, str>, } #[derive(Deserialize)] pub enum CardType { /// A card which can be used by anyone General, /// A card which can only be used by the given /// poisition Position(Position), } #[derive(Deserialize, Default)] pub enum Effect { PublicOpinion { /// How much public opinion changes magnitude: i32, /// If the affector of this card is chosen by it's player position_choosable: bool, }, SolutionTrack { magnitude: i32, yours: bool, }, DrawCard { number: i32, position_specific: bool, }, OpposingCards { number: i32, position: Option, }, InfluenceGain { magnitude: i32, }, #[default] Custom, } impl Display for Effect { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Effect::PublicOpinion { magnitude, position_choosable, } => { if *magnitude < 0 { write!(f, "Decrease ")?; } else { write!(f, "Increase ")?; } if *position_choosable { write!(f, "the public opinion of a player you chose ")?; } else { write!(f, "your public opinion ")?; } write!(f, "by {}.", magnitude.abs())?; if *position_choosable { write!( f, " This player is chosen after it is determined that this card passes." ) } else { Ok(()) } } Effect::SolutionTrack { magnitude, yours } => { write!(f, "Move ")?; if *magnitude < 0 { write!(f, "down ")?; } else { write!(f, "up ")?; } if *yours { write!(f, "your solution track ")?; } else { write!(f, "a solution track of your choice ")?; } write!(f, "by {}.", magnitude.abs()) } Effect::DrawCard { number, position_specific, } => { if *number < 0 { write!(f, "Discard ")?; } else { write!(f, "Draw ")?; } write!(f, "{} ", number.abs())?; if *position_specific { write!(f, "position specific ")?; } if number.abs() <= 1 { write!(f, "card.") } else { write!(f, "cards.") } } Effect::InfluenceGain { magnitude } => { if *magnitude < 0 { write!(f, "Decrease ")?; } else { write!(f, "Increase ")?; } write!(f, "your influence gain by {}.", magnitude.abs()) } Effect::OpposingCards { number, position } => { if let Some(pos) = position { write!(f, "The {} ", pos)?; } else { write!(f, "A player of your choice ")?; } write!(f, "must ")?; if *number < 0 { write!(f, "discard ")?; } else { write!(f, "draw ")?; } write!(f, "{} cards.", number.abs()) } Effect::Custom => Ok(()), } } }