From d18942fedaa5027bebc69ff6a65f99e595c1d983 Mon Sep 17 00:00:00 2001 From: Markus Wagner Date: Fri, 22 Jan 2021 19:21:51 +0100 Subject: [PATCH] Implement Mine --- src/cards.rs | 11 ++++- src/main.rs | 121 ++++++++++++++++++++++++++++++++++++++++++++--- static/game.html | 5 +- 3 files changed, 129 insertions(+), 8 deletions(-) diff --git a/src/cards.rs b/src/cards.rs index 9a054d8..f14ee0c 100644 --- a/src/cards.rs +++ b/src/cards.rs @@ -82,10 +82,19 @@ macro_rules! coin { }; } -#[derive(Clone)] +fn serialize_card_type(_: &fn(&mut super::Game), serializer: S) -> Result +where + S: Serializer, +{ + serializer.serialize_str("ActionSer") +} + +#[derive(Clone, Serialize)] pub enum CardType { + #[serde(serialize_with = "serialize_card_type")] Action(fn(&mut Game)), Curse, + #[serde(serialize_with = "serialize_card_type")] Reaction(fn(&mut Game)), Treasure(u32), Victory(u32), diff --git a/src/main.rs b/src/main.rs index a2ffe50..8c01438 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ mod cards; use async_std::{prelude::*, sync::RwLock}; use cards::*; use itertools::Itertools; -use rand::{seq::SliceRandom, Rng, thread_rng}; +use rand::{seq::SliceRandom, thread_rng, Rng}; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, sync::Arc}; use tide::{Body, Redirect, Request, Response}; @@ -192,6 +192,7 @@ enum ResolveReply { enum ResolveRequest { ChooseHandCardsToDiscard { player: ResolvingPlayer, + filter: CardFilter, }, GainCard { player: ResolvingPlayer, @@ -214,6 +215,7 @@ enum Effect { enum CardFilter { Any, MaxCost(u32), + Type(CardType), } type ResolvingEffect = fn(&mut Game, &ResolveReply); @@ -287,12 +289,14 @@ impl Game { "Cellar".into(), ResolveRequest::ChooseHandCardsToDiscard { player: ResolvingPlayer::ActivePlayer, + 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.players[game.active_player].discard(*c); + game.get_active_player().discard(*c); + //game.players[game.active_player].discard(*c); discarded += 1; } @@ -402,6 +406,7 @@ impl Game { "Remodel".into(), ResolveRequest::ChooseHandCardsToDiscard { player: ResolvingPlayer::ActivePlayer, + filter: CardFilter::Any, }, |game, message| { if let ResolveReply::HandCardsChosen { choice } = message { @@ -503,7 +508,95 @@ impl Game { Card { name: "Mine".into(), cost: 5, - types: vec![CardType::Action(|_| {})], + 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, ), @@ -515,6 +608,10 @@ impl Game { } fn end_turn(&mut self) { + if let Some(_) = self.resolving_effect { + return; + } + match self.players.get_mut(self.active_player) { None => {} Some(p) => { @@ -560,16 +657,24 @@ impl Game { } } - fn get_active_player(&mut self) -> &Player { - return &self.players[self.active_player]; + fn get_active_player(&mut self) -> &mut Player { + return &mut self.players[self.active_player]; } pub fn trash_hand(&mut self, player_number: usize, index: usize) { + if let Some(_) = self.resolving_effect { + return; + } + self.trash .push(self.players[player_number].hand.remove(index)); } pub fn can_play(&self, player_number: usize, index: usize) -> bool { + if let Some(_) = self.resolving_effect { + return false; + } + let card = self.players[player_number].hand.get(index).unwrap(); match card.action() { @@ -630,6 +735,10 @@ impl Game { pub fn buy_card(&mut self, player_number: usize, index: usize) -> bool /*-> Result<(), &'static str>*/ { + if let Some(_) = self.resolving_effect { + return false; + } + if player_number != self.active_player { return false; } @@ -748,7 +857,7 @@ async fn broadcast_state(game: &Game) { if let Some((card_name, request, _)) = &game.resolving_effect { match request { - ResolveRequest::ChooseHandCardsToDiscard { ref player } => match player { + ResolveRequest::ChooseHandCardsToDiscard { ref player, .. } => match player { ResolvingPlayer::ActivePlayer => { let p = game.players.get(game.active_player).unwrap(); let sm = ServerMessage::ResolveRequest { diff --git a/static/game.html b/static/game.html index 498c0c6..22a6cd1 100644 --- a/static/game.html +++ b/static/game.html @@ -443,7 +443,7 @@ img.card:hover { } .dialog.hand { - top: 50%; + top: 20%; } .dialog img { @@ -482,6 +482,9 @@ img.card:hover { } var toggle_supply_selection = function(index) { + document.querySelectorAll(".supply-area .supply-pile").forEach((c) => { + c.classList.remove("selected"); + }); document.querySelectorAll(".supply-area .supply-pile")[index].classList.toggle("selected"); }