From fa602b0635a2bf7ad8a0894c736a0b878fd5941f Mon Sep 17 00:00:00 2001 From: Jonni Liljamo Date: Tue, 23 May 2023 14:48:25 +0300 Subject: [PATCH] feat(client): something something something --- client/src/api/game/mod.rs | 14 ++++ client/src/game_status/mod.rs | 4 ++ client/src/game_status/parser.rs | 74 +++++++++++++++++----- client/src/plugins/game/card/mod.rs | 1 + client/src/plugins/game/ui/state_button.rs | 17 +---- client/src/util/mod.rs | 17 +++++ 6 files changed, 97 insertions(+), 30 deletions(-) diff --git a/client/src/api/game/mod.rs b/client/src/api/game/mod.rs index de75d45..e5a488f 100644 --- a/client/src/api/game/mod.rs +++ b/client/src/api/game/mod.rs @@ -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, + }, } #[derive(Deserialize, Serialize, Clone, PartialEq)] diff --git a/client/src/game_status/mod.rs b/client/src/game_status/mod.rs index 3badf6c..b311543 100644 --- a/client/src/game_status/mod.rs +++ b/client/src/game_status/mod.rs @@ -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, pub actions: Vec, + /// trash after play? + pub to_be_trashed: bool, } /// a supply pile holds an amount of some card diff --git a/client/src/game_status/parser.rs b/client/src/game_status/parser.rs index c8be15d..2e766f6 100644 --- a/client/src/game_status/parser.rs +++ b/client/src/game_status/parser.rs @@ -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, - 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, + 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 { 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::().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::().unwrap()).usize(0..deck_len)).unwrap().to_be_trashed = true; + } + } + } #[allow(unreachable_patterns)] _ => todo!(), } diff --git a/client/src/plugins/game/card/mod.rs b/client/src/plugins/game/card/mod.rs index a47feaa..c1817c0 100644 --- a/client/src/plugins/game/card/mod.rs +++ b/client/src/plugins/game/card/mod.rs @@ -56,6 +56,7 @@ impl Default for VisualCard { long_details: vec![], cost: 0, actions: vec![], + to_be_trashed: false, }, } } diff --git a/client/src/plugins/game/ui/state_button.rs b/client/src/plugins/game/ui/state_button.rs index 0ff77f4..7b3cee0 100644 --- a/client/src/plugins/game/ui/state_button.rs +++ b/client/src/plugins/game/ui/state_button.rs @@ -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, ), diff --git a/client/src/util/mod.rs b/client/src/util/mod.rs index d151761..6215980 100644 --- a/client/src/util/mod.rs +++ b/client/src/util/mod.rs @@ -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() +} -- 2.44.1