M client/src/api/game/mod.rs => client/src/api/game/mod.rs +14 -0
@@ 70,6 70,20 @@ pub enum Command {
amount: usize,
sides: usize,
},
+ GivePlays {
+ amount: usize,
+ },
+ GiveBuys {
+ amount: usize,
+ },
+ GiveVP {
+ amount: usize,
+ },
+ /// mark a card in the targets deck to be trashed on play.
+ /// if index in None, a random card will be chosen
+ MarkCardInDeckToBeTrashed {
+ index: Option<usize>,
+ },
}
#[derive(Deserialize, Serialize, Clone, PartialEq)]
M client/src/game_status/mod.rs => client/src/game_status/mod.rs +4 -0
@@ 17,6 17,8 @@ mod parser;
#[derive(Deserialize, Serialize, Clone, PartialEq)]
pub struct CardAction {
pub command: Command,
+ /// if false, targets the next player
+ pub target_self: bool,
}
#[derive(Deserialize, Serialize, Clone, PartialEq)]
@@ 30,6 32,8 @@ pub struct Card {
/// if set, use this?
//vp_cost: Option<u32>,
pub actions: Vec<CardAction>,
+ /// trash after play?
+ pub to_be_trashed: bool,
}
/// a supply pile holds an amount of some card
M client/src/game_status/parser.rs => client/src/game_status/parser.rs +58 -16
@@ 19,14 19,11 @@ use crate::{
use super::{GameStatus, PlayerState, PlayerStatus};
/// funny unsafe wrapper
-fn get_invoker_target<'a, K, V>(
- players: &'a mut HashMap<K, V>,
- invoker: &K,
- target: &K,
-) -> (&'a mut V, &'a mut V)
-where
- K: Eq + std::hash::Hash,
-{
+fn get_invoker_target_next<'a>(
+ players: &'a mut HashMap<String, PlayerStatus>,
+ invoker: &String,
+ target: &String,
+) -> (&'a mut PlayerStatus, &'a mut PlayerStatus, String) {
unsafe {
// NOTE: soo... I don't really know the consequences of possibly
// having two mutable references to the same value, but I guess
@@ 36,9 33,22 @@ where
// if the wanted values were the same.
// e.g. returning (V, None), if the keys were the same.
- let invoker_ref = players.get_mut(invoker).unwrap() as *mut _;
- let target_ref = players.get_mut(target).unwrap() as *mut _;
- (&mut *invoker_ref, &mut *target_ref)
+ let invoker_ref: *mut PlayerStatus = players.get_mut(invoker).unwrap() as *mut _;
+ let target_ref: *mut PlayerStatus = players.get_mut(target).unwrap() as *mut _;
+
+ let next_turn_n: usize = if ((*invoker_ref).turn_n + 1) > (players.len() - 1)
+ {
+ 0
+ } else {
+ (*invoker_ref).turn_n + 1
+ };
+
+ let next_player = players
+ .iter()
+ .find(|np| np.1.turn_n == next_turn_n)
+ .unwrap();
+
+ (&mut *invoker_ref, &mut *target_ref, next_player.0.clone())
}
}
@@ 86,6 96,9 @@ pub fn parse(game: &Game) -> Result<GameStatus, ()> {
parse_action(&action, game, &mut game_status);
}
+ // TODO: check for end conditions, declare one player as winner.
+ // update game state in API to ended, set ended date (in API).
+
Ok(game_status)
}
@@ 100,8 113,8 @@ fn parse_action(action: &Action, game: &Game, game_status: &mut GameStatus) {
// invoker: the one who invoked the action
// target: the one who the action affects, may also be the invoker, e.g. draw
- let (invoker, target) =
- get_invoker_target(&mut game_status.players, &action.invoker, &action.target);
+ let (invoker, target, next_player_uuid) =
+ get_invoker_target_next(&mut game_status.players, &action.invoker, &action.target);
let Some(action_pos) = game_status.actions.iter().position(|a| *a == action.clone()) else {
panic!("Action was not found in game_status.actions!");
@@ 148,13 161,22 @@ fn parse_action(action: &Action, game: &Game, game_status: &mut GameStatus) {
target.plays -= 1;
let card = target.hand.remove(*index);
- target.discard.push(card.clone());
+ if card.to_be_trashed {
+ // marked for trash, let it fall into oblivion
+ } else {
+ // discard normally
+ target.discard.push(card.clone());
+ }
for card_action in &card.actions {
let action = &Action::new(
&game.id,
&action.invoker,
- &action.target,
+ if card_action.target_self {
+ &action.invoker
+ } else {
+ &next_player_uuid
+ },
&card_action.command,
current_seed!(action),
);
@@ 218,7 240,7 @@ fn parse_action(action: &Action, game: &Game, game_status: &mut GameStatus) {
&game.id,
&action.target,
&action.target,
- &Command::Draw { amount: 4 },
+ &Command::Draw { amount: 2 },
current_seed!(action),
);
game_status
@@ 236,6 258,26 @@ fn parse_action(action: &Action, game: &Game, game_status: &mut GameStatus) {
Rng::with_seed(action.seed.parse::<u64>().unwrap()).usize(1..=*sides);
}
}
+ Command::GivePlays { amount } => {
+ target.plays += amount;
+ }
+ Command::GiveBuys { amount } => {
+ target.buys += amount;
+ }
+ Command::GiveVP { amount } => {
+ target.vp += amount;
+ }
+ Command::MarkCardInDeckToBeTrashed { index } => {
+ match index {
+ Some(index) => {
+ target.deck.get_mut(*index).unwrap().to_be_trashed = true;
+ }
+ None => {
+ let deck_len = target.deck.len();
+ target.deck.get_mut(Rng::with_seed(action.seed.parse::<u64>().unwrap()).usize(0..deck_len)).unwrap().to_be_trashed = true;
+ }
+ }
+ }
#[allow(unreachable_patterns)]
_ => todo!(),
}
M client/src/plugins/game/card/mod.rs => client/src/plugins/game/card/mod.rs +1 -0
@@ 56,6 56,7 @@ impl Default for VisualCard {
long_details: vec![],
cost: 0,
actions: vec![],
+ to_be_trashed: false,
},
}
}
M client/src/plugins/game/ui/state_button.rs => client/src/plugins/game/ui/state_button.rs +3 -14
@@ 12,7 12,7 @@ use crate::{
api::game::{Action, Command},
game_status::PlayerState,
plugins::{GameActionCreateCallEvent, GameData},
- AppState, Global,
+ AppState, Global, util::get_next_player,
};
pub struct StateButtonPlugin;
@@ 162,24 162,13 @@ fn interact_state_button(
});
}
PlayerState::BuyPhase => {
- let next_turn_n: usize = if (player.turn_n + 1) > (status.players.len() - 1)
- {
- 0
- } else {
- player.turn_n + 1
- };
-
- let next_player = status
- .players
- .iter()
- .find(|np| np.1.turn_n == next_turn_n)
- .unwrap();
+ let next_player = get_next_player(player, &status);
gac_ev_w.send(GameActionCreateCallEvent {
action: Action::new(
&game.id,
&user.id,
- next_player.0,
+ &next_player.0,
&Command::EndTurn {},
None,
),
M client/src/util/mod.rs => client/src/util/mod.rs +17 -0
@@ 10,3 10,20 @@ pub mod egui;
mod action_to_log;
pub use action_to_log::action_to_log;
+
+use crate::game_status::{GameStatus, PlayerStatus};
+
+pub fn get_next_player<'a>(player: &'a PlayerStatus, game_status: &'a GameStatus) -> (&'a String, &'a PlayerStatus) {
+ let next_turn_n: usize = if (player.turn_n + 1) > (game_status.players.len() - 1)
+ {
+ 0
+ } else {
+ player.turn_n + 1
+ };
+
+ game_status
+ .players
+ .iter()
+ .find(|np| np.1.turn_n == next_turn_n)
+ .unwrap()
+}