diff --git a/VERSION b/VERSION index d5e98f72..e21e727f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.2 \ No newline at end of file +1.4.0 \ No newline at end of file diff --git a/acp/package.json b/acp/package.json index fb96a8c8..cc8e63ce 100644 --- a/acp/package.json +++ b/acp/package.json @@ -1,6 +1,6 @@ { "name": "mnml-client", - "version": "1.3.2", + "version": "1.4.0", "description": "", "main": "index.js", "scripts": { diff --git a/client/assets/styles/player.less b/client/assets/styles/player.less new file mode 100644 index 00000000..3dd302b9 --- /dev/null +++ b/client/assets/styles/player.less @@ -0,0 +1,37 @@ +@import 'colours.less'; + +.player-box { + display: grid; + + grid-template-areas: + "score" + "img" + "ctrl"; + + &.top { + grid-template-areas: + "ctrl" + "img" + "score"; + + .img { + display: flex; + flex-flow: column; + justify-content: flex-end; + } + } + + grid-template-rows: min-content 1fr min-content; + + .score { + grid-area: score; + } + + .img { + grid-area: img; + } + + .ctrl { + grid-area: ctrl; + } +} diff --git a/client/index.js b/client/index.js index 8c76e1ff..d25854c0 100644 --- a/client/index.js +++ b/client/index.js @@ -7,6 +7,7 @@ require('./assets/styles/controls.less'); require('./assets/styles/instance.less'); require('./assets/styles/vbox.less'); require('./assets/styles/game.less'); +require('./assets/styles/player.less'); require('./assets/styles/styles.mobile.css'); require('./assets/styles/instance.mobile.css'); diff --git a/client/package.json b/client/package.json index 00f15a25..cd637efa 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "mnml-client", - "version": "1.3.2", + "version": "1.4.0", "description": "", "main": "index.js", "scripts": { diff --git a/client/src/components/game.ctrl.jsx b/client/src/components/game.ctrl.jsx index 4bf517d6..9fd5b07a 100644 --- a/client/src/components/game.ctrl.jsx +++ b/client/src/components/game.ctrl.jsx @@ -3,8 +3,7 @@ const { connect } = require('preact-redux'); const actions = require('../actions'); -// dunno if this is a good idea -// bashing together instance and game to save having two panels +const PlayerBox = require('./player.box'); const addState = connect( function receiveState(state) { @@ -44,35 +43,6 @@ const addState = connect( } ); -function scoreboard(game, player, isOpponent) { - const text = game.phase === 'Finished' - ? player.wins > game.rounds / 2 && 'Winner' - : ''; - - const classes =`scoreboard ${player.ready ? 'ready' : ''}`; - - const body = isOpponent - ? ( - - {player.name} - {player.wins} / {player.losses} - {player.ready ? 'ready' : ''} - - ) : ( - - {player.ready ? 'ready' : ''} - {player.wins} / {player.losses} - {player.name} - - ); - - return ( - - {body} -
- ); -} - function Controls(args) { const { account, @@ -126,9 +96,9 @@ function Controls(args) { ); diff --git a/client/src/components/instance.ctrl.jsx b/client/src/components/instance.ctrl.jsx index a431f1d4..47324fa9 100644 --- a/client/src/components/instance.ctrl.jsx +++ b/client/src/components/instance.ctrl.jsx @@ -1,6 +1,10 @@ const preact = require('preact'); const { connect } = require('preact-redux'); +const actions = require('../actions'); + +const PlayerBox = require('./player.box'); + const addState = connect( function receiveState(state) { const { @@ -23,42 +27,23 @@ const addState = connect( animating, }; }, + function receiveDispatch(dispatch) { + function leave() { + dispatch(actions.setNav('play')); + dispatch(actions.setGame(null)); + dispatch(actions.setInstance(null)); + } + + return { leave }; + } ); -function scoreboard(instance, player, isOpponent) { - const text = instance.phase === 'Finished' - ? player.wins > instance.rounds / 2 && 'Winner' - : ''; - - const classes =`scoreboard ${player.ready ? 'ready' : ''}`; - - const body = isOpponent - ? ( - - {player.name} - {player.wins} / {player.losses} - {player.ready ? 'ready' : ''} - - ) : ( - - {player.ready ? 'ready' : ''} - {player.wins} / {player.losses} - {player.name} - - ); - - return ( - - {body} -
- ); -} - function Controls(args) { const { account, instance, sendReady, + leave, } = args; if (!instance) return false; @@ -96,9 +81,9 @@ function Controls(args) { ); diff --git a/client/src/components/player.box.jsx b/client/src/components/player.box.jsx new file mode 100644 index 00000000..4b626171 --- /dev/null +++ b/client/src/components/player.box.jsx @@ -0,0 +1,47 @@ +const preact = require('preact'); + +function Scoreboard(args) { + const { + isPlayer, + ready, + player, + + leave, + } = args; + + let scoreText = () => { + if (player.score === 'Zero') return '▫▫▫▫'; + if (player.score === 'One') return '■▫▫▫'; + if (player.score === 'Two') return '■■▫▫'; + if (player.score === 'Three') return '■■■▫'; + if (player.score === 'Adv') return '■■■+'; + if (player.score === 'Win') return '■■■■'; + return ''; + }; + + if (!isPlayer) { + return ( +
+
 
+
{scoreText()}
+
+
{player.name}
+
+
+ ); + } + + return ( +
+
{scoreText()}
+
+
{player.name}
+
+
+ {leave ? : null} +
+
+ ); +} + +module.exports = Scoreboard; diff --git a/ops/package.json b/ops/package.json index 7dc1156a..5286926e 100755 --- a/ops/package.json +++ b/ops/package.json @@ -1,6 +1,6 @@ { "name": "mnml-ops", - "version": "1.3.2", + "version": "1.4.0", "description": "", "main": "index.js", "scripts": { diff --git a/server/Cargo.toml b/server/Cargo.toml index c3c48ed2..ded86d14 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mnml" -version = "1.3.2" +version = "1.4.0" authors = ["ntr "] [dependencies] diff --git a/server/src/instance.rs b/server/src/instance.rs index 6feeb8f1..3061cb10 100644 --- a/server/src/instance.rs +++ b/server/src/instance.rs @@ -14,7 +14,7 @@ use chrono::Duration; use account::Account; use account; use events::{EventsTx, Event}; -use player::{Player, player_create}; +use player::{Player, Score, player_create}; use construct::{Construct, construct_get}; use mob::{bot_player, instance_mobs}; use game::{Game, Phase, game_get, game_write}; @@ -318,14 +318,14 @@ impl Instance { // tennis for player in self.players.iter() { - if player.wins >= 4 && player.wins >= player.losses + 2 { + if player.score == Score::Win { self.winner = Some(player.id); return true; } } // both players afk - if self.players.iter().all(|p| p.wins == 0) { + if self.players.iter().all(|p| p.score == Score::Zero) { return true; } @@ -403,12 +403,25 @@ impl Instance { None => return Ok(self.finish()), }; - for player in game.players.iter() { - let mut player = self.account_player(player.id)?; - match player.id == winner_id { - true => player.add_win(), - false => player.add_loss(), - }; + { + let loser = self.players.iter() + .find(|p| p.id != winner_id) + .map(|p| p.score) + .unwrap(); + + let winner = self.players.iter_mut() + .find(|p| p.id == winner_id) + .unwrap(); + + winner.score = winner.score.add_win(&loser); + } + + { + let loser = self.players.iter_mut() + .find(|p| p.id != winner_id) + .unwrap(); + + loser.score = loser.score.add_loss(); } if self.all_games_finished() { diff --git a/server/src/player.rs b/server/src/player.rs index 0c123143..8c42743d 100644 --- a/server/src/player.rs +++ b/server/src/player.rs @@ -14,6 +14,43 @@ use effect::{Effect}; const DISCARD_COST: u16 = 2; +#[derive(Debug,Copy,Clone,Serialize,Deserialize,Eq,PartialEq)] +pub enum Score { + Zero, + One, + Two, + Three, + Adv, + + Win, + Lose, +} + +impl Score { + pub fn add_win(self, opp: &Score) -> Score { + match self { + Score::Zero => Score::One, + Score::One => Score::Two, + Score::Two => Score::Three, + Score::Three => match opp { + Score::Adv => Score::Three, + Score::Three => Score::Adv, + _ => Score::Win, + } + Score::Adv => Score::Win, + _ => panic!("faulty score increment {:?}", self), + } + } + + pub fn add_loss(self) -> Score { + match self { + Score::Adv => Score::Three, + _ => self, + } + } + +} + #[derive(Debug,Clone,Serialize,Deserialize)] pub struct Player { pub id: Uuid, @@ -23,8 +60,7 @@ pub struct Player { pub bot: bool, pub ready: bool, pub warnings: u8, - pub wins: u8, - pub losses: u8, + pub score: Score, } impl Player { @@ -33,12 +69,11 @@ impl Player { id: account, name: name.clone(), vbox: Vbox::new(), - wins: 0, - losses: 0, constructs, bot: false, ready: false, warnings: 0, + score: Score::Zero, } } @@ -64,21 +99,6 @@ impl Player { self } - pub fn add_win(&mut self) -> &mut Player { - self.wins += 1; - let win_bonus = 12 + 6 * (self.wins + self.losses); - self.vbox.balance_add(win_bonus.into()); - self - } - - pub fn add_loss(&mut self) -> &mut Player { - self.losses += 1; - let loss_bonus = 12 + 6 * (self.wins + self.losses); - self.vbox.balance_add(loss_bonus.into()); - self - } - - pub fn construct_get(&mut self, id: Uuid) -> Result<&mut Construct, Error> { self.constructs.iter_mut().find(|c| c.id == id).ok_or(err_msg("construct not found")) } @@ -336,4 +356,32 @@ mod tests { assert!(player.constructs.iter().all(|c| c.skills.len() >= 1)); } + + #[test] + fn player_score_test() { + let player_account = Uuid::new_v4(); + let constructs = instance_mobs(player_account); + let mut player = Player::new(player_account, &"test".to_string(), constructs).set_bot(true); + + player.score = player.score.add_win(&Score::Zero); + player.score = player.score.add_win(&Score::Zero); + player.score = player.score.add_win(&Score::Zero); + assert_eq!(player.score, Score::Three); // 40 / 0 + + player.score = player.score.add_loss(); // adv -> deuce + assert_eq!(player.score, Score::Three); + + player.score = player.score.add_loss(); // adv -> deuce + assert_eq!(player.score, Score::Three); + + player.score = player.score.add_win(&Score::Adv); // opp adv -> stays deuce + assert_eq!(player.score, Score::Three); + + player.score = player.score.add_win(&Score::Three); + assert_eq!(player.score, Score::Adv); + + player.score = player.score.add_win(&Score::Three); + assert_eq!(player.score, Score::Win); + } + } \ No newline at end of file diff --git a/server/src/skill.rs b/server/src/skill.rs index c587a465..d71ac47e 100644 --- a/server/src/skill.rs +++ b/server/src/skill.rs @@ -2113,8 +2113,8 @@ mod tests { .learn(Skill::HealPlus); purge(&mut x, &mut y, vec![], Skill::Purge); - // 2 turns at lvl 1 - assert!(y.effects.iter().any(|e| e.effect == Effect::Purge && e.duration == 2)); + // current turn + 2 turns at lvl 1 + assert!(y.effects.iter().any(|e| e.effect == Effect::Purge && e.duration == 3)); assert!(y.disabled(Skill::Heal).is_some()); } }