diff --git a/server/src/cryp.rs b/server/src/cryp.rs index 67ed6939..c58d5276 100644 --- a/server/src/cryp.rs +++ b/server/src/cryp.rs @@ -278,6 +278,11 @@ impl Cryp { self.green_life.value == 0 } + pub fn force_ko(&mut self) -> &mut Cryp { + self.green_life.value = 0; + self + } + pub fn immune(&self, skill: Skill) -> Option { // also checked in resolve stage so shouldn't happen really if self.is_ko() { diff --git a/server/src/game.rs b/server/src/game.rs index 91027c04..d1b88f8f 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -22,7 +22,6 @@ use instance::{instance_game_finished, global_game_finished}; pub enum Phase { Start, Skill, - Target, Resolve, Finish, } @@ -568,19 +567,29 @@ impl Game { } fn phase_timed_out(&self) -> bool { - Utc::now().signed_duration_since(self.phase_start).num_seconds() > 30 + Utc::now().signed_duration_since(self.phase_start).num_seconds() > 60 } pub fn upkeep(mut self) -> Game { - // give players a ready status - // on time out if not enough skills selected - // add a warning - // on 3 warnings forfeit - - if self.phase == Phase::Skill && self.phase_timed_out() { - self = self.resolve_phase_start(); + if self.phase != Phase::Skill { + panic!("{:?} game not in skill phase during upkeep", self); } + if !self.phase_timed_out() { + return self; + } + + for player in self.players.iter_mut() { + if !player.ready { + player.set_ready(true); + player.add_warning(); + if player.warnings >= 3 { + player.forfeit(); + } + } + } + + self = self.resolve_phase_start(); self } } @@ -998,12 +1007,12 @@ mod tests { let i_player_id = Uuid::new_v4(); i.account = i_player_id; j.account = i_player_id; - let mut i_player = Player::new(i_player_id, &"ntr".to_string(), vec![i, j]); + let i_player = Player::new(i_player_id, &"ntr".to_string(), vec![i, j]); let x_player_id = Uuid::new_v4(); x.account = x_player_id; y.account = x_player_id; - let mut x_player = Player::new(x_player_id, &"mashy".to_string(), vec![x, y]); + let x_player = Player::new(x_player_id, &"mashy".to_string(), vec![x, y]); game .player_add(i_player).unwrap() @@ -1027,6 +1036,9 @@ mod tests { game.add_skill(x_player.id, x_cryp.id, Some(y_cryp.id), Skill::Attack).unwrap(); game.add_skill(y_player.id, y_cryp.id, Some(x_cryp.id), Skill::Attack).unwrap(); + game.player_ready(x_player.id).unwrap(); + game.player_ready(y_player.id).unwrap(); + assert!(game.skill_phase_finished()); game = game.resolve_phase_start(); @@ -1049,6 +1061,9 @@ mod tests { let _x_stun_id = game.add_skill(x_player.id, x_cryp.id, Some(y_cryp.id), Skill::TestStun).unwrap(); game.add_skill(y_player.id, y_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap(); + game.player_ready(x_player.id).unwrap(); + game.player_ready(y_player.id).unwrap(); + assert!(game.skill_phase_finished()); game = game.resolve_phase_start(); @@ -1079,6 +1094,9 @@ mod tests { let _x_stun_id = game.add_skill(x_player.id, x_cryp.id, Some(y_cryp.id), Skill::TestStun).unwrap(); game.add_skill(y_player.id, y_cryp.id, Some(x_cryp.id), Skill::Attack).unwrap(); + game.player_ready(x_player.id).unwrap(); + game.player_ready(y_player.id).unwrap(); + assert!(game.skill_phase_finished()); game = game.resolve_phase_start(); @@ -1291,8 +1309,9 @@ mod tests { #[test] fn upkeep_test() { let mut game = create_2v2_test_game(); - game.phase_start = Utc::now().checked_sub_signed(Duration::seconds(31)).unwrap(); - - println!("{:?}", game.upkeep()); + game.players[0].set_ready(true); + game.phase_start = Utc::now().checked_sub_signed(Duration::seconds(61)).unwrap(); + game = game.upkeep(); + assert!(game.players[1].warnings == 1); } } diff --git a/server/src/instance.rs b/server/src/instance.rs index bd2e8df3..e483c886 100644 --- a/server/src/instance.rs +++ b/server/src/instance.rs @@ -230,11 +230,16 @@ impl Instance { .ok_or(err_msg("could not find matchup in current round"))? .finished = true; - let winner = game.winner().ok_or(err_msg("game not finished"))?; + // if you don't win, you lose + // ties can happen if both players forfeit + let winner_id = match game.winner() { + Some(w) => w.id, + None => Uuid::nil(), + }; for player in game.players.iter() { let mut player = self.account_player(player.id)?; - match player.id == winner.id { + match player.id == winner_id { true => player.add_win(), false => player.add_loss(), }; @@ -663,7 +668,7 @@ pub fn instance_ready(params: InstanceReadyParams, tx: &mut Transaction, account } pub fn instance_state(params: InstanceStateParams, tx: &mut Transaction, account: &Account) -> Result { - let mut instance = instance_get(tx, params.instance_id)?; + let instance = instance_get(tx, params.instance_id)?; if let Some(game_id) = instance.current_game(account.id) { let game = game_get(tx, game_id)?; diff --git a/server/src/player.rs b/server/src/player.rs index 92ac849a..0cc2ec83 100644 --- a/server/src/player.rs +++ b/server/src/player.rs @@ -32,6 +32,7 @@ pub struct Player { pub cryps: Vec, pub bot: bool, pub ready: bool, + pub warnings: u8, } impl Player { @@ -44,6 +45,7 @@ impl Player { cryps, bot: false, ready: false, + warnings: 0, } } @@ -57,6 +59,18 @@ impl Player { self } + pub fn add_warning(&mut self) -> &mut Player { + self.warnings += 1; + self + } + + pub fn forfeit(&mut self) -> &mut Player { + for cryp in self.cryps.iter_mut() { + cryp.force_ko(); + } + self + } + pub fn add_win(&mut self) -> &mut Player { self.score.wins += 1; self.set_ready(false);