Implement Mine

This commit is contained in:
Markus Wagner 2021-01-22 19:21:51 +01:00
parent 998d27764d
commit d18942feda
3 changed files with 129 additions and 8 deletions

View File

@ -82,10 +82,19 @@ macro_rules! coin {
}; };
} }
#[derive(Clone)] fn serialize_card_type<S>(_: &fn(&mut super::Game), serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str("ActionSer")
}
#[derive(Clone, Serialize)]
pub enum CardType { pub enum CardType {
#[serde(serialize_with = "serialize_card_type")]
Action(fn(&mut Game)), Action(fn(&mut Game)),
Curse, Curse,
#[serde(serialize_with = "serialize_card_type")]
Reaction(fn(&mut Game)), Reaction(fn(&mut Game)),
Treasure(u32), Treasure(u32),
Victory(u32), Victory(u32),

View File

@ -4,7 +4,7 @@ mod cards;
use async_std::{prelude::*, sync::RwLock}; use async_std::{prelude::*, sync::RwLock};
use cards::*; use cards::*;
use itertools::Itertools; use itertools::Itertools;
use rand::{seq::SliceRandom, Rng, thread_rng}; use rand::{seq::SliceRandom, thread_rng, Rng};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use tide::{Body, Redirect, Request, Response}; use tide::{Body, Redirect, Request, Response};
@ -192,6 +192,7 @@ enum ResolveReply {
enum ResolveRequest { enum ResolveRequest {
ChooseHandCardsToDiscard { ChooseHandCardsToDiscard {
player: ResolvingPlayer, player: ResolvingPlayer,
filter: CardFilter,
}, },
GainCard { GainCard {
player: ResolvingPlayer, player: ResolvingPlayer,
@ -214,6 +215,7 @@ enum Effect {
enum CardFilter { enum CardFilter {
Any, Any,
MaxCost(u32), MaxCost(u32),
Type(CardType),
} }
type ResolvingEffect = fn(&mut Game, &ResolveReply); type ResolvingEffect = fn(&mut Game, &ResolveReply);
@ -287,12 +289,14 @@ impl Game {
"Cellar".into(), "Cellar".into(),
ResolveRequest::ChooseHandCardsToDiscard { ResolveRequest::ChooseHandCardsToDiscard {
player: ResolvingPlayer::ActivePlayer, player: ResolvingPlayer::ActivePlayer,
filter: CardFilter::Any,
}, },
|game, message| { |game, message| {
if let ResolveReply::HandCardsChosen { choice } = message { if let ResolveReply::HandCardsChosen { choice } = message {
let mut discarded = 0; let mut discarded = 0;
for c in choice.iter().sorted_by(|a, b| b.cmp(a)) { 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; discarded += 1;
} }
@ -402,6 +406,7 @@ impl Game {
"Remodel".into(), "Remodel".into(),
ResolveRequest::ChooseHandCardsToDiscard { ResolveRequest::ChooseHandCardsToDiscard {
player: ResolvingPlayer::ActivePlayer, player: ResolvingPlayer::ActivePlayer,
filter: CardFilter::Any,
}, },
|game, message| { |game, message| {
if let ResolveReply::HandCardsChosen { choice } = message { if let ResolveReply::HandCardsChosen { choice } = message {
@ -503,7 +508,95 @@ impl Game {
Card { Card {
name: "Mine".into(), name: "Mine".into(),
cost: 5, 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, 10,
), ),
@ -515,6 +608,10 @@ impl Game {
} }
fn end_turn(&mut self) { fn end_turn(&mut self) {
if let Some(_) = self.resolving_effect {
return;
}
match self.players.get_mut(self.active_player) { match self.players.get_mut(self.active_player) {
None => {} None => {}
Some(p) => { Some(p) => {
@ -560,16 +657,24 @@ impl Game {
} }
} }
fn get_active_player(&mut self) -> &Player { fn get_active_player(&mut self) -> &mut Player {
return &self.players[self.active_player]; return &mut self.players[self.active_player];
} }
pub fn trash_hand(&mut self, player_number: usize, index: usize) { pub fn trash_hand(&mut self, player_number: usize, index: usize) {
if let Some(_) = self.resolving_effect {
return;
}
self.trash self.trash
.push(self.players[player_number].hand.remove(index)); .push(self.players[player_number].hand.remove(index));
} }
pub fn can_play(&self, player_number: usize, index: usize) -> bool { 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(); let card = self.players[player_number].hand.get(index).unwrap();
match card.action() { match card.action() {
@ -630,6 +735,10 @@ impl Game {
pub fn buy_card(&mut self, player_number: usize, index: usize) -> bool /*-> Result<(), &'static str>*/ 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 { if player_number != self.active_player {
return false; return false;
} }
@ -748,7 +857,7 @@ async fn broadcast_state(game: &Game) {
if let Some((card_name, request, _)) = &game.resolving_effect { if let Some((card_name, request, _)) = &game.resolving_effect {
match request { match request {
ResolveRequest::ChooseHandCardsToDiscard { ref player } => match player { ResolveRequest::ChooseHandCardsToDiscard { ref player, .. } => 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 {

View File

@ -443,7 +443,7 @@ img.card:hover {
} }
.dialog.hand { .dialog.hand {
top: 50%; top: 20%;
} }
.dialog img { .dialog img {
@ -482,6 +482,9 @@ img.card:hover {
} }
var toggle_supply_selection = function(index) { 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"); document.querySelectorAll(".supply-area .supply-pile")[index].classList.toggle("selected");
} }