From b4b253ab863bd37c73b607cc4848087b845859bf Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 25 Oct 2019 16:22:03 +1100 Subject: [PATCH 01/21] youtube tutorial link --- client/assets/styles/styles.less | 2 +- client/src/components/play.jsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/client/assets/styles/styles.less b/client/assets/styles/styles.less index e8188302..86ea5d38 100644 --- a/client/assets/styles/styles.less +++ b/client/assets/styles/styles.less @@ -143,7 +143,7 @@ button, input { a { color: whitesmoke; - text-decoration: none; + // text-decoration: none; &:hover { color: whitesmoke; diff --git a/client/src/components/play.jsx b/client/src/components/play.jsx index 25906879..30246537 100644 --- a/client/src/components/play.jsx +++ b/client/src/components/play.jsx @@ -203,6 +203,7 @@ function Play(args) {
Join our Discord server to find opponents and talk to the devs.
Message @ntr or @mashy for some credits to get started.
+ Tutorial Playthrough on YouTube

From 0172e1dba350691be6b345b387c43ff771196805 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 25 Oct 2019 17:42:52 +1100 Subject: [PATCH 02/21] fix player css width --- client/assets/styles/game.less | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index f85ca3cf..65ad6b25 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -437,11 +437,12 @@ #targeting, .resolving-skill { width: calc(100% - 1em); } + + .player { + width: calc(100% - 1em); + bottom: 3em; + height: calc(50% - 3em); + } } - .player { - width: calc(100% - 1em); - bottom: 3em; - height: calc(50% - 3em); - } } From 76a6eb27102e4604f41d6d500a01dfcd4e09c039 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 25 Oct 2019 18:49:21 +1100 Subject: [PATCH 03/21] only init logrocket once authed --- client/src/app.jsx | 4 ---- client/src/events.jsx | 1 + server/src/account.rs | 4 ++-- server/src/rpc.rs | 3 ++- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/client/src/app.jsx b/client/src/app.jsx index cfc877b7..e56f3044 100644 --- a/client/src/app.jsx +++ b/client/src/app.jsx @@ -15,10 +15,6 @@ const registerEvents = require('./events'); const Mnml = require('./components/mnml'); -if (process.env.NODE_ENV !== 'development') { - LogRocket.init('yh0dy3/mnml'); -} - function stripeKey() { if (window.location.host === 'mnml.gg') return 'pk_live_fQGrL1uWww2ot8W1G7vTySAv004ygmnMXq'; return 'pk_test_Cb49tTqTXpzk7nEmlGzRrNJg00AU0aNZDj'; diff --git a/client/src/events.jsx b/client/src/events.jsx index 6f42c894..aaf0fdf8 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -127,6 +127,7 @@ function registerEvents(store) { function setAccount(account) { if (account) { + LogRocket.init('yh0dy3/mnml'); LogRocket.identify(account.id, account); } diff --git a/server/src/account.rs b/server/src/account.rs index 56921e2c..e42ca9e9 100644 --- a/server/src/account.rs +++ b/server/src/account.rs @@ -189,7 +189,7 @@ pub fn new_img(tx: &mut Transaction, id: Uuid) -> Result { } pub fn set_password(tx: &mut Transaction, id: Uuid, current: &String, password: &String) -> Result { - if password.len() < PASSWORD_MIN_LEN { + if password.len() < PASSWORD_MIN_LEN || password.len() > 100 { return Err(MnmlHttpError::PasswordUnacceptable); } @@ -328,7 +328,7 @@ pub fn create(name: &String, password: &String, tx: &mut Transaction) -> Result< let id = Uuid::new_v4(); let img = Uuid::new_v4(); - let rounds = 8; + let rounds = 12; let password = hash(&password, rounds)?; let mut rng = thread_rng(); diff --git a/server/src/rpc.rs b/server/src/rpc.rs index 3194c1d4..91c1068e 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -449,7 +449,8 @@ pub fn start(pool: PgPool, events_tx: CbSender, stripe: StripeClient) { out.send(Message::Binary(response)).unwrap(); } // we done - Err(_e) => { + Err(e) => { + info!("{:?}", e); break; }, }; From 87ea0eb81f79adcf5b15d01bc7fbe68a85203eae Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 25 Oct 2019 19:04:45 +1100 Subject: [PATCH 04/21] terms label --- client/assets/styles/menu.less | 5 +++++ client/src/components/welcome.register.jsx | 4 +++- server/src/rpc.rs | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/client/assets/styles/menu.less b/client/assets/styles/menu.less index 0fbb7f90..672e928e 100644 --- a/client/assets/styles/menu.less +++ b/client/assets/styles/menu.less @@ -90,6 +90,11 @@ .login { display: flex; flex-flow: column; + + .terms { + display: inline; + margin: 0 1em; + } } } diff --git a/client/src/components/welcome.register.jsx b/client/src/components/welcome.register.jsx index 99f8baed..5eb2b17d 100644 --- a/client/src/components/welcome.register.jsx +++ b/client/src/components/welcome.register.jsx @@ -79,9 +79,11 @@ function Register(args) {
-   Confirm agreement to terms of service   +
{pageEl()} diff --git a/client/src/socket.jsx b/client/src/socket.jsx index adad1a66..517ee04f 100644 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -1,6 +1,8 @@ const toast = require('izitoast'); const cbor = require('borc'); +const throttle = require('lodash/throttle'); + const SOCKET_URL = `${window.location.protocol === 'https:' ? 'wss://' : 'ws://'}${window.location.host}/api/ws`; @@ -363,7 +365,8 @@ function createSocket(events) { sendGameTarget, sendInstanceAbandon, - sendInstanceReady, + // some weird shit happening in face off + sendInstanceReady: throttle(sendInstanceReady, 500), sendInstancePractice, sendInstanceQueue, sendInstanceState, From 3183f56a4ad2fdeaf3501862f7f4d9d29f0e4d58 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 25 Oct 2019 21:54:46 +1100 Subject: [PATCH 06/21] relax password restrictions --- client/src/components/welcome.register.jsx | 2 +- .../mnml.gg.PRODUCTION.nginx.conf | 23 ------------------- server/src/account.rs | 4 ++-- server/src/rpc.rs | 2 +- 4 files changed, 4 insertions(+), 27 deletions(-) diff --git a/client/src/components/welcome.register.jsx b/client/src/components/welcome.register.jsx index 5eb2b17d..68b6fedb 100644 --- a/client/src/components/welcome.register.jsx +++ b/client/src/components/welcome.register.jsx @@ -58,7 +58,7 @@ function Register(args) { value={this.state.name} onInput={linkState(this, 'name')} /> - + https server { server_name mnml.gg; @@ -91,8 +73,3 @@ server { server_name minimal.gg; return 301 https://mnml.gg$request_uri; } - -server { - server_name minimalstudios.com.au; - return 301 https://minimalstudios.com.au$request_uri; -} diff --git a/server/src/account.rs b/server/src/account.rs index e42ca9e9..22224568 100644 --- a/server/src/account.rs +++ b/server/src/account.rs @@ -20,7 +20,7 @@ use img; use failure::Error; use failure::{err_msg, format_err}; -static PASSWORD_MIN_LEN: usize = 11; +static PASSWORD_MIN_LEN: usize = 3; #[derive(Debug,Clone,Serialize,Deserialize)] pub struct Account { @@ -318,7 +318,7 @@ pub fn set_subscribed(tx: &mut Transaction, id: Uuid, subscribed: bool) -> Resul } pub fn create(name: &String, password: &String, tx: &mut Transaction) -> Result { - if password.len() < PASSWORD_MIN_LEN { + if password.len() < PASSWORD_MIN_LEN || password.len() > 100 { return Err(MnmlHttpError::PasswordUnacceptable); } diff --git a/server/src/rpc.rs b/server/src/rpc.rs index f4019ad3..826590c9 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -449,7 +449,7 @@ pub fn start(pool: PgPool, events_tx: CbSender, stripe: StripeClient) { out.send(Message::Binary(response)).unwrap(); } // we done - Err(e) => { + Err(_e) => { // info!("{:?}", e); break; }, From 0a07e98794e72cd1e475df5c09e4ebaa0d9a9c24 Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 26 Oct 2019 00:06:42 +1100 Subject: [PATCH 07/21] update youtube link --- client/src/components/play.jsx | 2 +- client/src/components/welcome.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/components/play.jsx b/client/src/components/play.jsx index 30246537..40f5b657 100644 --- a/client/src/components/play.jsx +++ b/client/src/components/play.jsx @@ -203,7 +203,7 @@ function Play(args) {
Join our Discord server to find opponents and talk to the devs.
Message @ntr or @mashy for some credits to get started.
- Tutorial Playthrough on YouTube + Tutorial Playthrough on YouTube

diff --git a/client/src/components/welcome.jsx b/client/src/components/welcome.jsx index 077da507..558e5719 100644 --- a/client/src/components/welcome.jsx +++ b/client/src/components/welcome.jsx @@ -53,7 +53,7 @@ function Welcome() {

Welcome to mnml.

-

Turn-based 1v1 strategy game in an abstract setting.

+

MNML is a turn-based 1v1 strategy game in an abstract setting.

Build a unique team of 3 constructs from a range of skills and specialisations.
Outplay your opponent in multiple rounds by adapting to an always shifting meta.
@@ -62,7 +62,7 @@ function Welcome() {

Free to play, no pay to win. Register to start playing.

- Tutorial Playthrough on YouTube + Tutorial Playthrough on YouTube
{pageEl()} From 96efa2d07619bbabb97ef96c6487eca635d8f627 Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 26 Oct 2019 13:02:25 +1100 Subject: [PATCH 08/21] make intercept defensive --- server/src/skill.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/src/skill.rs b/server/src/skill.rs index 75a6094d..2e98af9b 100644 --- a/server/src/skill.rs +++ b/server/src/skill.rs @@ -1264,6 +1264,9 @@ impl Skill { Skill::Invert| Skill::InvertPlus | Skill::InvertPlusPlus | + Skill::Intercept| + Skill::InterceptPlus | + Skill::InterceptPlusPlus | Skill::Counter| Skill::CounterPlus | Skill::CounterPlusPlus | @@ -2083,7 +2086,7 @@ mod tests { let Resolution { source: _, target: _, event, stages: _ } = results.remove(0); match event { - Event::Damage { amount, skill: _, mitigation: _, colour: _} => assert_eq!(amount, 256.pct(Skill::SiphonTick.multiplier()) + Event::Damage { amount, skill: _, mitigation: _, colour: _} => assert_eq!(amount, 256.pct(Skill::SiphonTick.multiplier()) + 220.pct(Skill::SiphonTick.multiplier())), _ => panic!("not damage siphon"), }; From dbd06c2053f4851335f488d2f27eac65fb39dc42 Mon Sep 17 00:00:00 2001 From: Mashy Date: Sat, 26 Oct 2019 13:33:58 +1000 Subject: [PATCH 09/21] improved wiggle --- client/src/components/anims/wiggle.jsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/client/src/components/anims/wiggle.jsx b/client/src/components/anims/wiggle.jsx index a9615181..e071450b 100644 --- a/client/src/components/anims/wiggle.jsx +++ b/client/src/components/anims/wiggle.jsx @@ -6,17 +6,18 @@ function wiggle(id, idle) { const x = window.innerWidth * 0.01 * (Math.round(Math.random()) ? Math.random() : -Math.random()); const y = window.innerHeight * 0.01 * (Math.round(Math.random()) ? Math.random() : -Math.random()); + const originalX = parseFloat(idle.animations[0].currentValue); + const originalY = parseFloat(idle.animations[1].currentValue); // console.log(x, y); return anime({ targets: target, - rotate: 0, - translateX: [x, -x, 0], - translateY: [y, -y, 0], + translateX: [originalX + x, originalX - x, originalX], + translateY: [originalY + y, originalY - y, originalY], duration, easing: 'easeInOutSine', // direction: 'alternate', begin: idle.pause, - complete: idle.restart, + complete: idle.play, }); } From 1694a21b9f7592646fba63b0888a0d8d529577a8 Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 26 Oct 2019 15:56:14 +1100 Subject: [PATCH 10/21] handle blocked stripe --- client/src/app.jsx | 9 ++++++--- client/src/components/shop.jsx | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/client/src/app.jsx b/client/src/app.jsx index e56f3044..0d668980 100644 --- a/client/src/app.jsx +++ b/client/src/app.jsx @@ -36,9 +36,12 @@ events.setWs(ws); const App = () => ( - - - + {window.Stripe + ? + + + : + } ); diff --git a/client/src/components/shop.jsx b/client/src/components/shop.jsx index 08a79fad..283e78bc 100644 --- a/client/src/components/shop.jsx +++ b/client/src/components/shop.jsx @@ -48,9 +48,12 @@ function Shop(args) {

¤ {account.balance}

- - - + {window.stripe + ? + + + :
Please unblock Stripe to use the store
+ }
); From a633e3b297789cd8bc945b460d4b9c0cffa4efa9 Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 26 Oct 2019 16:06:52 +1100 Subject: [PATCH 11/21] sub rgb name and stripe fix --- client/assets/styles/colours.less | 20 +++++++++++++++++++- client/assets/styles/player.less | 5 +++++ client/src/components/account.box.jsx | 2 +- client/src/components/shop.jsx | 2 +- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/client/assets/styles/colours.less b/client/assets/styles/colours.less index 79088b7c..13da2d0e 100644 --- a/client/assets/styles/colours.less +++ b/client/assets/styles/colours.less @@ -150,4 +150,22 @@ button { &.green { border-color: @green; } -} \ No newline at end of file +} + +@keyframes rgb { + 0% { + color: @red; + } + 25% { + color: @white; + } + 50% { + color: @blue; + } + 75% { + color: @white; + } + 100% { + color: @green; + } +} diff --git a/client/assets/styles/player.less b/client/assets/styles/player.less index 616ba46f..bda41989 100644 --- a/client/assets/styles/player.less +++ b/client/assets/styles/player.less @@ -51,6 +51,11 @@ color: @yellow; font-weight: bold; } + + .name.subscriber { + animation: rgb 4s cubic-bezier(0.5, 0, 0.5, 1) 0s infinite alternate; + font-weight: bold; + } } .chat { diff --git a/client/src/components/account.box.jsx b/client/src/components/account.box.jsx index c6383c55..4097816d 100644 --- a/client/src/components/account.box.jsx +++ b/client/src/components/account.box.jsx @@ -105,7 +105,7 @@ function AccountBox(args) {
 
-
{account.name}
+
{account.name}
 
); diff --git a/client/src/components/shop.jsx b/client/src/components/shop.jsx index 283e78bc..7e23bc60 100644 --- a/client/src/components/shop.jsx +++ b/client/src/components/shop.jsx @@ -48,7 +48,7 @@ function Shop(args) {

¤ {account.balance}

- {window.stripe + {window.Stripe ? From d370709d90d129cc6848aa789e30ddd98893e2fa Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 26 Oct 2019 16:13:32 +1100 Subject: [PATCH 12/21] fix name class --- client/src/components/account.box.jsx | 4 +++- client/src/components/play.footer.jsx | 2 -- client/src/components/player.box.jsx | 10 +++++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/client/src/components/account.box.jsx b/client/src/components/account.box.jsx index 4097816d..0ff61b8f 100644 --- a/client/src/components/account.box.jsx +++ b/client/src/components/account.box.jsx @@ -101,11 +101,13 @@ function AccountBox(args) { // ); // } + const nameClass = `name ${account.subscribed ? 'subscriber' : ''}`; + return (
 
-
{account.name}
+
{account.name}
 
); diff --git a/client/src/components/play.footer.jsx b/client/src/components/play.footer.jsx index f8a8479a..1f059064 100644 --- a/client/src/components/play.footer.jsx +++ b/client/src/components/play.footer.jsx @@ -3,8 +3,6 @@ const { connect } = require('preact-redux'); const { errorToast, infoToast } = require('../utils'); -const AccountBox = require('./account.box'); - const addState = connect( function receiveState(state) { const { diff --git a/client/src/components/player.box.jsx b/client/src/components/player.box.jsx index 29ee6532..2790d69f 100644 --- a/client/src/components/player.box.jsx +++ b/client/src/components/player.box.jsx @@ -70,22 +70,26 @@ function Scoreboard(args) { const winner = player.score === 'Win'; if (!isPlayer) { + const nameClass = `name ${player.img ? 'subscriber' : ''}`; return (
{scoreText()}
-
{player.name}
+
{player.name}
{chat || '\u00A0'}
); } + const boxClass = `player-box bottom ${winner ? 'winner': player.ready ? 'ready' : ''}`; + const nameClass = `name ${player.img ? 'subscriber' : ''}`; + return ( -
+
{chat || '\u00A0'}
{scoreText()}
-
{player.name}
+
{player.name}
); From 03c7302019eb6c696f1b3f1ebf429e90e56bf01f Mon Sep 17 00:00:00 2001 From: ntr Date: Sat, 26 Oct 2019 16:14:46 +1100 Subject: [PATCH 13/21] remove sub rgb for now --- client/assets/styles/player.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/assets/styles/player.less b/client/assets/styles/player.less index bda41989..cadd02fe 100644 --- a/client/assets/styles/player.less +++ b/client/assets/styles/player.less @@ -53,8 +53,8 @@ } .name.subscriber { - animation: rgb 4s cubic-bezier(0.5, 0, 0.5, 1) 0s infinite alternate; - font-weight: bold; + // animation: rgb 4s cubic-bezier(0.5, 0, 0.5, 1) 0s infinite alternate; + // font-weight: bold; } } From 6f5d7338d074a76e0d274c6d3f0b4a862979dde5 Mon Sep 17 00:00:00 2001 From: Mashy Date: Sat, 26 Oct 2019 21:48:12 +1000 Subject: [PATCH 14/21] catch null idle case --- client/src/components/anims/wiggle.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/components/anims/wiggle.jsx b/client/src/components/anims/wiggle.jsx index e071450b..5886a47d 100644 --- a/client/src/components/anims/wiggle.jsx +++ b/client/src/components/anims/wiggle.jsx @@ -1,11 +1,12 @@ const anime = require('animejs').default; function wiggle(id, idle) { + if (!idle) return true; const duration = 300; const target = document.getElementById(id); const x = window.innerWidth * 0.01 * (Math.round(Math.random()) ? Math.random() : -Math.random()); const y = window.innerHeight * 0.01 * (Math.round(Math.random()) ? Math.random() : -Math.random()); - + const originalX = parseFloat(idle.animations[0].currentValue); const originalY = parseFloat(idle.animations[1].currentValue); // console.log(x, y); From d41ff0d4e8822f36b07517119ae6e7b923dd0aef Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 27 Oct 2019 12:01:04 +1100 Subject: [PATCH 15/21] don't generate source maps --- client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/package.json b/client/package.json index 6c6d56fe..790e7aed 100644 --- a/client/package.json +++ b/client/package.json @@ -6,7 +6,7 @@ "scripts": { "start": "parcel watch index.html --out-dir /var/lib/mnml/public/current", "anims": "parcel watch animations.html --no-hmr --out-dir /var/lib/mnml/public/current", - "build": "parcel build index.html", + "build": "parcel build index.html --no-source-maps", "scss": "node-sass --watch assets/scss -o assets/styles", "lint": "eslint --fix --ext .jsx src/", "test": "echo \"Error: no test specified\" && exit 1" From 4593a5f2033e539fe76504810aad7cea42a44f12 Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 27 Oct 2019 13:20:14 +1100 Subject: [PATCH 16/21] offer draws --- CHANGELOG.md | 18 +++++++ client/assets/styles/controls.less | 10 +++- client/src/components/game.ctrl.btns.jsx | 2 +- client/src/components/game.ctrl.btns.top.jsx | 23 +++++++-- client/src/components/game.footer.jsx | 4 +- client/src/socket.jsx | 6 +++ server/src/game.rs | 52 +++++++++++++++++--- server/src/instance.rs | 44 +++++------------ server/src/player.rs | 3 ++ server/src/rpc.rs | 6 ++- 10 files changed, 121 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 807de0fb..009c5d41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,24 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). + +## [1.6.5] - 2019-10-27 +# Added +- Offering of draws + - Neither player receives a point if they agree to a draw + - Bots automatically agree to draws + +## [1.6.5] - 2019-10-25 +# Fixed +- Stripe being blocked no longer causes unrecoverable error +- Automatic ready up is now throttled after abandons +- Player width styling + +# Changed +- Improved wiggle animation +- Intercept is now considered defensive by bots +- Password restrictions relaxed + ## [1.6.4] - 2019-10-24 ### Changed - Animations processing on client side reduced. diff --git a/client/assets/styles/controls.less b/client/assets/styles/controls.less index 2ff3ee04..54bcb375 100644 --- a/client/assets/styles/controls.less +++ b/client/assets/styles/controls.less @@ -144,7 +144,15 @@ aside { &:active, &.confirming { background: @red; color: black; - border: 2px solid black; + border: 2px solid @red; + } +} + +.draw:not([disabled]) { + &:active, &.confirming { + background: @gray-hover; + color: black; + border: 2px solid @gray-hover; } } diff --git a/client/src/components/game.ctrl.btns.jsx b/client/src/components/game.ctrl.btns.jsx index 671e9d62..3918b5ca 100644 --- a/client/src/components/game.ctrl.btns.jsx +++ b/client/src/components/game.ctrl.btns.jsx @@ -75,7 +75,7 @@ function GameCtrlBtns(args) { } = args; if (!game) return false; - const finished = game.phase === 'Finish'; + const finished = game.phase === 'Finished'; function quitClick() { getInstanceState(); diff --git a/client/src/components/game.ctrl.btns.top.jsx b/client/src/components/game.ctrl.btns.top.jsx index 4ab0d543..4b81670c 100644 --- a/client/src/components/game.ctrl.btns.top.jsx +++ b/client/src/components/game.ctrl.btns.top.jsx @@ -14,10 +14,15 @@ const addState = connect( return ws.sendInstanceAbandon(game.instance); } + function sendDraw() { + return ws.sendGameOfferDraw(game.id); + } + return { game, sendAbandon, + sendDraw, }; }, function receiveDispatch(dispatch) { @@ -37,10 +42,11 @@ function GameCtrlTopBtns(args) { leave, sendAbandon, + sendDraw, } = args; const finished = game && game.phase === 'Finished'; - const { abandonState } = this.state; + const { abandonState, drawState } = this.state; const abandonStateTrue = e => { e.stopPropagation(); @@ -48,16 +54,27 @@ function GameCtrlTopBtns(args) { setTimeout(() => this.setState({ abandonState: false }), 2000); }; + const drawStateTrue = e => { + e.stopPropagation(); + this.setState({ drawState: true }); + setTimeout(() => this.setState({ drawState: false }), 2000); + }; + const abandonClasses = `abandon ${abandonState ? 'confirming' : ''}`; const abandonText = abandonState ? 'Confirm' : 'Abandon'; const abandonAction = abandonState ? sendAbandon : abandonStateTrue; const abandonBtn = ; - const leaveBtn = ; + + const drawClasses = `draw ${drawState ? 'confirming' : ''}`; + const drawText = drawState ? 'Draw' : 'Offer'; + const drawAction = drawState ? sendDraw : drawStateTrue; + const drawBtn = ; return (
- {finished ? leaveBtn : abandonBtn} + {abandonBtn} + {drawBtn}
); } diff --git a/client/src/components/game.footer.jsx b/client/src/components/game.footer.jsx index 101318a4..4a1589b0 100644 --- a/client/src/components/game.footer.jsx +++ b/client/src/components/game.footer.jsx @@ -82,7 +82,7 @@ function GameFooter(props) { const now = Date.now(); const end = Date.parse(game.phase_end); const timerPct = ((now - zero) / (end - zero) * 100); - const displayPct = game.phase === 'Finish' || !game.phase_end + const displayPct = game.phase === 'Finished' || !game.phase_end ? 0 : Math.min(timerPct, 100); @@ -108,7 +108,7 @@ function GameFooter(props) { return (
{timer} - {game.phase === 'Finish' && quitBtn } + {game.phase === 'Finished' && quitBtn } {game.phase === 'Skill' && readyBtn }
); diff --git a/client/src/socket.jsx b/client/src/socket.jsx index 517ee04f..85d81154 100644 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -123,6 +123,11 @@ function createSocket(events) { events.setActiveSkill(null); } + function sendGameOfferDraw(gameId) { + send(['GameOfferDraw', { game_id: gameId }]); + events.setActiveSkill(null); + } + function sendGameTarget(gameId, constructId, skillId) { send(['GameTarget', { game_id: gameId, construct_id: constructId, skill_id: skillId }]); events.setActiveSkill(null); @@ -362,6 +367,7 @@ function createSocket(events) { sendGameReady, sendGameSkill, sendGameSkillClear, + sendGameOfferDraw, sendGameTarget, sendInstanceAbandon, diff --git a/server/src/game.rs b/server/src/game.rs index 0421ab65..12a175b4 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -27,7 +27,7 @@ pub enum Phase { Start, Skill, Resolve, - Finish, + Finished, } #[derive(Debug,Clone,Serialize,Deserialize)] @@ -325,6 +325,30 @@ impl Game { return Ok(self); } + fn offer_draw(mut self, player_id: Uuid) -> Result { + if self.phase != Phase::Skill { + return Err(err_msg("game not in skill phase")); + } + + { + let player = self.player_by_id(player_id)?; + player.draw_offered = true; + } + + // bots automatically accept draws + for player in self.players.iter_mut() { + if player.bot { + player.draw_offered = true; + } + } + + if self.players.iter().all(|p| p.draw_offered) { + return Ok(self.finish()); + } + + return Ok(self); + } + fn clear_skill(&mut self, player_id: Uuid) -> Result<&mut Game, Error> { self.player_by_id(player_id)?; if self.phase != Phase::Skill { @@ -564,15 +588,18 @@ impl Game { // } pub fn finished(&self) -> bool { - self.players.iter().any(|t| t.constructs.iter().all(|c| c.is_ko())) + self.phase == Phase::Finished || self.players.iter().any(|t| t.constructs.iter().all(|c| c.is_ko())) } pub fn winner(&self) -> Option<&Player> { - self.players.iter().find(|t| t.constructs.iter().any(|c| !c.is_ko())) + match self.players.iter().any(|t| t.constructs.iter().all(|c| c.is_ko())) { + true => self.players.iter().find(|t| t.constructs.iter().any(|c| !c.is_ko())), + false => None, + } } fn finish(mut self) -> Game { - self.phase = Phase::Finish; + self.phase = Phase::Finished; // self.log.push(format!("Game finished.")); // { @@ -594,7 +621,7 @@ impl Game { } pub fn upkeep(mut self) -> Game { - if self.phase == Phase::Finish { + if self.phase == Phase::Finished { return self; } @@ -903,6 +930,15 @@ pub fn game_skill(tx: &mut Transaction, account: &Account, game_id: Uuid, constr Ok(game) } +pub fn game_offer_draw(tx: &mut Transaction, account: &Account, game_id: Uuid) -> Result { + let game = game_get(tx, game_id)? + .offer_draw(account.id)?; + + game_update(tx, &game)?; + + Ok(game) +} + pub fn game_skill_clear(tx: &mut Transaction, account: &Account, game_id: Uuid) -> Result { let mut game = game_get(tx, game_id)?; @@ -1051,7 +1087,7 @@ mod tests { game = game.resolve_phase_start(); - assert!([Phase::Skill, Phase::Finish].contains(&game.phase)); + assert!([Phase::Skill, Phase::Finished].contains(&game.phase)); return; } @@ -1117,7 +1153,7 @@ mod tests { game = game.resolve_phase_start(); assert!(!game.player_by_id(y_player.id).unwrap().constructs[0].is_stunned()); - assert!(game.phase == Phase::Finish); + assert!(game.phase == Phase::Finished); } #[test] @@ -1423,7 +1459,7 @@ mod tests { assert!(game.skill_phase_finished()); game = game.resolve_phase_start(); - assert!([Phase::Skill, Phase::Finish].contains(&game.phase)); + assert!([Phase::Skill, Phase::Finished].contains(&game.phase)); // kill a construct game.player_by_id(i_player.id).unwrap().construct_by_id(i_construct.id).unwrap().green_life.reduce(u64::max_value()); diff --git a/server/src/instance.rs b/server/src/instance.rs index 8c92a821..eec93a0d 100644 --- a/server/src/instance.rs +++ b/server/src/instance.rs @@ -317,7 +317,13 @@ impl Instance { self.phase_start = Utc::now(); self.phase_end = self.time_control.vbox_phase_end(); + let bits = match self.rounds.len() > 0 { + true => 12 + 6 * self.rounds.len(), + false => 0, + }; + self.players.iter_mut().for_each(|p| { + p.vbox.balance_add(bits.into()); p.set_ready(false); p.vbox.fill(); }); @@ -412,38 +418,14 @@ impl Instance { } // if you don't win, you lose - // ties can happen if both players forfeit - // in this case we just finish the game and - // dock them 10k mmr - let winner_id = match game.winner() { - Some(w) => w.id, - None => return Ok(self.finish()), - }; - - let bits = 12 + 6 * self.rounds.len(); - - { - let loser = self.players.iter() - .find(|p| p.id != winner_id) - .map(|p| p.score) - .unwrap(); - + // ties can happen if both players agree to a draw + // or ticks fire and knock everybody out + if let Some(winner) = game.winner() { let winner = self.players.iter_mut() - .find(|p| p.id == winner_id) + .find(|p| p.id == winner.id) .unwrap(); - - winner.score = winner.score.add_win(&loser); - winner.vbox.balance_add(bits.into()); - } - - { - let loser = self.players.iter_mut() - .find(|p| p.id != winner_id) - .unwrap(); - - loser.score = loser.score.add_loss(); - loser.vbox.balance_add(bits.into()); - } + winner.score = winner.score.add_win(&Score::Zero); + }; if self.all_games_finished() { self.next_round(); @@ -799,7 +781,7 @@ pub fn instance_state(tx: &mut Transaction, instance_id: Uuid) -> Result Ok(RpcMessage::GameState(game_ready(&mut tx, account, id)?)), + RpcRequest::GameOfferDraw { game_id } => + Ok(RpcMessage::GameState(game_offer_draw(&mut tx, account, game_id)?)), + RpcRequest::InstancePractice {} => Ok(RpcMessage::InstanceState(instance_practice(&mut tx, account)?)), From 6b6726f3a6d76fd2c5db66707c10b9381a33269d Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 27 Oct 2019 13:20:58 +1100 Subject: [PATCH 17/21] v1.6.6 --- VERSION | 2 +- acp/package.json | 2 +- client/package.json | 2 +- ops/package.json | 2 +- server/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 49ebdd60..83d1a5eb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.6.5 \ No newline at end of file +1.6.6 \ No newline at end of file diff --git a/acp/package.json b/acp/package.json index 2591fabe..a1935bb7 100644 --- a/acp/package.json +++ b/acp/package.json @@ -1,6 +1,6 @@ { "name": "mnml-client", - "version": "1.6.5", + "version": "1.6.6", "description": "", "main": "index.js", "scripts": { diff --git a/client/package.json b/client/package.json index 790e7aed..b6b1c359 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "mnml-client", - "version": "1.6.5", + "version": "1.6.6", "description": "", "main": "index.js", "scripts": { diff --git a/ops/package.json b/ops/package.json index 40211410..ae05c7f0 100755 --- a/ops/package.json +++ b/ops/package.json @@ -1,6 +1,6 @@ { "name": "mnml-ops", - "version": "1.6.5", + "version": "1.6.6", "description": "", "main": "index.js", "scripts": { diff --git a/server/Cargo.toml b/server/Cargo.toml index 4df35fa1..c80430f6 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mnml" -version = "1.6.5" +version = "1.6.6" authors = ["ntr "] [dependencies] From 343731e7e894f25c317bdc7b7e1a51a2a4a61f4b Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 27 Oct 2019 14:12:38 +1100 Subject: [PATCH 18/21] draw fixes and client side showing --- client/src/components/game.ctrl.btns.top.jsx | 14 +++++++++++--- client/src/components/player.box.jsx | 9 +++++++-- server/src/instance.rs | 19 +------------------ 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/client/src/components/game.ctrl.btns.top.jsx b/client/src/components/game.ctrl.btns.top.jsx index 4b81670c..8e09718c 100644 --- a/client/src/components/game.ctrl.btns.top.jsx +++ b/client/src/components/game.ctrl.btns.top.jsx @@ -8,6 +8,7 @@ const addState = connect( const { ws, game, + account, } = state; function sendAbandon() { @@ -20,6 +21,7 @@ const addState = connect( return { game, + account, sendAbandon, sendDraw, @@ -39,6 +41,7 @@ const addState = connect( function GameCtrlTopBtns(args) { const { game, + account, leave, sendAbandon, @@ -48,6 +51,9 @@ function GameCtrlTopBtns(args) { const finished = game && game.phase === 'Finished'; const { abandonState, drawState } = this.state; + const player = game.players.find(p => p.id === account.id); + const drawOffered = player && player.draw_offered; + const abandonStateTrue = e => { e.stopPropagation(); this.setState({ abandonState: true }); @@ -66,10 +72,12 @@ function GameCtrlTopBtns(args) { const abandonBtn = ; - const drawClasses = `draw ${drawState ? 'confirming' : ''}`; - const drawText = drawState ? 'Draw' : 'Offer'; + const drawClasses = `draw ${drawState || drawOffered ? 'confirming' : ''}`; + const drawText = drawOffered + ? 'Offered' + : drawState ? 'Draw' : 'Offer'; const drawAction = drawState ? sendDraw : drawStateTrue; - const drawBtn = ; + const drawBtn = ; return (
diff --git a/client/src/components/player.box.jsx b/client/src/components/player.box.jsx index 2790d69f..9d55606e 100644 --- a/client/src/components/player.box.jsx +++ b/client/src/components/player.box.jsx @@ -68,6 +68,11 @@ function Scoreboard(args) { }; const winner = player.score === 'Win'; + const chatText = player.draw_offered + ? 'draw?' + : chat || '\u00A0'; + + console.log(chatText); if (!isPlayer) { const nameClass = `name ${player.img ? 'subscriber' : ''}`; @@ -77,7 +82,7 @@ function Scoreboard(args) {
{scoreText()}
{player.name}
-
{chat || '\u00A0'}
+
{chatText}
); } @@ -87,7 +92,7 @@ function Scoreboard(args) { return (
-
{chat || '\u00A0'}
+
{chatText}
{scoreText()}
{player.name}
diff --git a/server/src/instance.rs b/server/src/instance.rs index eec93a0d..07498300 100644 --- a/server/src/instance.rs +++ b/server/src/instance.rs @@ -335,24 +335,7 @@ impl Instance { } fn finish_condition(&mut self) -> bool { - // tennis - for player in self.players.iter() { - if player.score == Score::Win { - self.winner = Some(player.id); - return true; - } - } - // Game defaults to lose otherwise - if self.rounds.len() < 4 { - return false; - } - - // both players afk - if self.players.iter().all(|p| p.score == Score::Zero) { - return true; - } - - return false; + self.players.iter().any(|p| p.score == Score::Win) } pub fn finish(&mut self) -> &mut Instance { From d5764f0067d2f0b94485423cf9361f2d76323446 Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 27 Oct 2019 14:18:20 +1100 Subject: [PATCH 19/21] draw text change --- client/src/components/player.box.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/src/components/player.box.jsx b/client/src/components/player.box.jsx index 9d55606e..6cace8a4 100644 --- a/client/src/components/player.box.jsx +++ b/client/src/components/player.box.jsx @@ -68,11 +68,11 @@ function Scoreboard(args) { }; const winner = player.score === 'Win'; - const chatText = player.draw_offered - ? 'draw?' - : chat || '\u00A0'; - - console.log(chatText); + const chatText = chat + ? chat + : player.draw_offered + ? 'draw' + : '\u00A0'; if (!isPlayer) { const nameClass = `name ${player.img ? 'subscriber' : ''}`; From 45aad71939b2227e4e3a58a9457f1a825ff9b9cc Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 27 Oct 2019 14:57:27 +1100 Subject: [PATCH 20/21] changelog --- CHANGELOG.md | 1 - server/src/instance.rs | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 009c5d41..01b06b18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,6 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). - ## [1.6.5] - 2019-10-27 # Added - Offering of draws diff --git a/server/src/instance.rs b/server/src/instance.rs index 07498300..2e65b9d6 100644 --- a/server/src/instance.rs +++ b/server/src/instance.rs @@ -340,6 +340,13 @@ impl Instance { pub fn finish(&mut self) -> &mut Instance { self.phase = InstancePhase::Finished; + + for player in self.players.iter() { + if player.score == Score::Win { + self.winner = Some(player.id); + } + } + self } From c18a0f02708b3be2447bda0c2ee3bfe611d45ffd Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 27 Oct 2019 14:58:51 +1100 Subject: [PATCH 21/21] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01b06b18..9a6107c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## [1.6.5] - 2019-10-27 +## [1.6.6] - 2019-10-27 # Added - Offering of draws - Neither player receives a point if they agree to a draw