From 17a80d0e7ea082fca098557012465b8bc370e4f3 Mon Sep 17 00:00:00 2001 From: Mashy Date: Wed, 8 Jan 2020 15:43:11 +1000 Subject: [PATCH 01/14] wlog --- WORKLOG.md | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/WORKLOG.md b/WORKLOG.md index 3ab85ef3..4fb85ec6 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -3,32 +3,24 @@ _ntr_ * can't reset password without knowing password =\ -* change cooldowns to delay & recharge - - delay is cooldown before skill can first be used - - recharge is cooldown after using skill - - every x speed reduces delay of skills +* quick play updates + * game phase real fast 1 shot ko enemies + * redirect to register after 1 round finishes + * hide abandon / draw / offer + * audio * animation effects * vbox combine / buy / equip etc * background music -* effects rework - -Siphon = -[ - DamageBlue(50%), - Apply( - Siphon(2T) - - Siphoning(2T) - ), -] - -Hexagon Set -- Pick Colour -- Random Walk -- Draw hex -- Increase intensity for each visit _mashy_ +* change cooldowns to delay & recharge + - delay is cooldown before skill can first be used + - recharge is cooldown after using skill + - every x speed reduces delay of skills +* combat text + - last 3-4 text events (damage / heal / disable etc) + * rebalance * speed specs * life specs @@ -111,6 +103,11 @@ _tba_ * treats * client animation bpm * background colour changes depending on time of day +Hexagon Set +- Pick Colour +- Random Walk +- Draw hex +- Increase intensity for each visit # Mechanics * 10d chaos maths, not rock paper scissors From 549b9cdf65e36d5b928ff9dfe57513200618a721 Mon Sep 17 00:00:00 2001 From: ntr Date: Wed, 8 Jan 2020 17:17:05 +1000 Subject: [PATCH 02/14] ez mode tutorial and updates to the auth and anon user structs --- client/assets/styles/menu.less | 6 ++ client/src/components/front.page.jsx | 14 ++++ client/src/components/game.ctrl.btns.jsx | 7 +- client/src/components/game.ctrl.btns.top.jsx | 14 +++- .../src/components/instance.ctrl.top.btns.jsx | 12 ++- client/src/components/welcome.jsx | 24 +++++- client/src/events.jsx | 5 ++ client/src/socket.jsx | 1 + server/src/pg.rs | 11 ++- server/src/rpc.rs | 28 +++---- server/src/user_anonymous.rs | 34 ++++++--- server/src/user_authenticated.rs | 75 ++++++++++++------- 12 files changed, 168 insertions(+), 63 deletions(-) diff --git a/client/assets/styles/menu.less b/client/assets/styles/menu.less index 670a86be..ff035799 100644 --- a/client/assets/styles/menu.less +++ b/client/assets/styles/menu.less @@ -100,6 +100,12 @@ section { } } +.block-text { + letter-spacing: 0.25em; + text-transform: uppercase; + text-align: center; +} + .list { margin-bottom: 2em; diff --git a/client/src/components/front.page.jsx b/client/src/components/front.page.jsx index 32cf3e16..defc62e1 100644 --- a/client/src/components/front.page.jsx +++ b/client/src/components/front.page.jsx @@ -14,6 +14,7 @@ const addState = connect( const { ws, account, + tutorial, } = state; function sendInstancePractice() { @@ -21,6 +22,7 @@ const addState = connect( } return { + promptRegister: tutorial === 99, // see events account, sendInstancePractice, }; @@ -30,6 +32,7 @@ const addState = connect( function Play(args) { const { account, + promptRegister, sendInstancePractice, } = args; @@ -47,6 +50,17 @@ function Play(args) { ); const list = () => { + + if (promptRegister) { + return ( +
+

You just won your first round of MNML.

+

Register below to play a real Bo5 against other players, play a practice round, customise your team & more...

+

glhf

+
+ ) + } + return (
diff --git a/client/src/components/game.ctrl.btns.jsx b/client/src/components/game.ctrl.btns.jsx index 557e0915..9b898345 100644 --- a/client/src/components/game.ctrl.btns.jsx +++ b/client/src/components/game.ctrl.btns.jsx @@ -9,6 +9,7 @@ const addState = connect( ws, game, account, + authenticated, chatShow, animating, } = state; @@ -33,6 +34,7 @@ const addState = connect( return { game, account, + authenticated, chatShow, sendAbandon, sendGameSkillClear, @@ -65,6 +67,7 @@ function GameCtrlBtns(args) { animating, account, chatShow, + authenticated, getInstanceState, sendGameSkillClear, @@ -77,7 +80,9 @@ function GameCtrlBtns(args) { const finished = game.phase === 'Finished'; function quitClick() { - getInstanceState(); + if (authenticated) { + getInstanceState(); + } quit(); } diff --git a/client/src/components/game.ctrl.btns.top.jsx b/client/src/components/game.ctrl.btns.top.jsx index 3128d40d..f5e67fa2 100644 --- a/client/src/components/game.ctrl.btns.top.jsx +++ b/client/src/components/game.ctrl.btns.top.jsx @@ -9,6 +9,7 @@ const addState = connect( ws, game, animating, + authenticated, account, } = state; @@ -27,6 +28,7 @@ const addState = connect( return { game, account, + authenticated, sendAbandon, sendDraw, @@ -50,6 +52,7 @@ function GameCtrlTopBtns(args) { const { game, account, + authenticated, leave, sendAbandon, @@ -82,6 +85,11 @@ function GameCtrlTopBtns(args) { setTimeout(() => this.setState({ concedeState: false }), 2000); }; + const authBtn = btn => { + if (authenticated) return btn; + return + } + const abandonClasses = `abandon ${abandonState ? 'confirming' : ''}`; const abandonText = abandonState ? 'Confirm' : 'Abandon'; const abandonAction = abandonState ? sendAbandon : abandonStateTrue; @@ -102,9 +110,9 @@ function GameCtrlTopBtns(args) { return (
- {abandonBtn} - {concedeBtn} - {drawBtn} + {authBtn(abandonBtn)} + {authBtn(concedeBtn)} + {authBtn(drawBtn)}
); } diff --git a/client/src/components/instance.ctrl.top.btns.jsx b/client/src/components/instance.ctrl.top.btns.jsx index 7fc4f018..319298d7 100644 --- a/client/src/components/instance.ctrl.top.btns.jsx +++ b/client/src/components/instance.ctrl.top.btns.jsx @@ -7,6 +7,7 @@ const addState = connect( function receiveState(state) { const { ws, + authenticated, instance, tutorial, } = state; @@ -17,6 +18,7 @@ const addState = connect( return { instance, + authenticated, tutorial, sendAbandon, }; @@ -39,6 +41,7 @@ const addState = connect( function InstanceTopBtns(args) { const { instance, + authenticated, leave, sendAbandon, @@ -61,9 +64,16 @@ function InstanceTopBtns(args) { const abandonBtn = ; const leaveBtn = ; + const finalBtn = () => { + // disable for tutorial mode + if (!authenticated) return ; + if (finished) return leaveBtn; + return abandonBtn; + } + return (
- {finished ? leaveBtn : abandonBtn} + {finalBtn()}
); } diff --git a/client/src/components/welcome.jsx b/client/src/components/welcome.jsx index 8270cdb2..d32c5997 100644 --- a/client/src/components/welcome.jsx +++ b/client/src/components/welcome.jsx @@ -1,13 +1,31 @@ // eslint-disable-next-line const preact = require('preact'); +const { connect } = require('preact-redux'); const Login = require('./welcome.login'); const Register = require('./welcome.register'); const Help = require('./welcome.help'); // const About = require('./welcome.about'); -function Welcome() { - const page = this.state.page || 'login'; +const addState = connect( + function receiveState(state) { + const { + tutorial, + } = state; + + return { + promptRegister: tutorial === 99, // see events + }; + }, +); + +function Welcome(args) { + + const { + promptRegister, + } = args; + + const page = this.state.page || promptRegister && 'register' || 'login'; const pageEl = () => { if (page === 'login') return ; @@ -45,4 +63,4 @@ function Welcome() { ); } -module.exports = Welcome; +module.exports = addState(Welcome); diff --git a/client/src/events.jsx b/client/src/events.jsx index 11e791ea..a0e6a307 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -218,6 +218,10 @@ function registerEvents(store) { store.dispatch(actions.setTutorial(1)); } + function promptRegister() { + store.dispatch(actions.setTutorial(99)); + store.dispatch(actions.setInstance(null)); + } window.addEventListener('hashchange', urlHashChange, false); @@ -250,6 +254,7 @@ function registerEvents(store) { setWs, startTutorial, + promptRegister, urlHashChange, diff --git a/client/src/socket.jsx b/client/src/socket.jsx index 30e16b59..a7e2916c 100644 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -301,6 +301,7 @@ function createSocket(events) { // Joining: () => events.notify('Searching for instance...'), StartTutorial: () => events.startTutorial(), + PromptRegister: () => events.promptRegister(), Processing: () => true, Error: errHandler, diff --git a/server/src/pg.rs b/server/src/pg.rs index 97444249..995c727b 100644 --- a/server/src/pg.rs +++ b/server/src/pg.rs @@ -695,11 +695,17 @@ pub fn instance_practice(tx: &mut Transaction, account: &Account) -> Result Result { - let bot = bot_player(); + let mut bot = bot_player(); let bot_id = bot.id; // generate imgs for the client to see - for c in bot.constructs.iter() { + for c in bot.constructs.iter_mut() { + + // smash these nubs + c.green_life.force(64); + c.red_life.force(0); + c.blue_life.force(0); + img::shapes_write(c.img)?; } @@ -709,6 +715,7 @@ pub fn instance_demo(account: &Account) -> Result { let player = anon_player(account.id); + // smash these noobs for c in player.constructs.iter() { img::shapes_write(c.img)?; } diff --git a/server/src/rpc.rs b/server/src/rpc.rs index 7ab789f1..9ffe3bdc 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -2,7 +2,6 @@ use mnml_core::item::ItemInfoCtr; use mnml_core::instance::ChatState; use std::collections::HashMap; -use std::time::{Instant}; use std::thread::{spawn}; use std::str; @@ -23,7 +22,7 @@ use account; use events::{Event}; use user_anonymous::{Anonymous}; -use user_authenticated::{Authorised}; +use user_authenticated::{Authenticated}; use mnml_core::construct::{Construct}; use mnml_core::game::{Game}; @@ -37,7 +36,7 @@ use mnml_core::instance::{Instance}; use mtx; use mail::Email; -use pg::{Db}; + use pg::{PgPool}; use http::{AUTH_CLEAR, TOKEN_HEADER}; @@ -63,6 +62,7 @@ pub enum RpcMessage { Pong(()), StartTutorial(()), + PromptRegister(()), QueueRequested(()), QueueJoined(()), @@ -126,9 +126,9 @@ pub enum RpcRequest { } pub trait User { - fn receive(&mut self, data: Vec, db: &Db, begin: Instant, events: &CbSender, stripe: &StripeClient) -> Result; - fn connected(&mut self, db: &Db, events: &CbSender, ws: &CbSender) -> Result<(), Error>; - fn send(&mut self, msg: RpcMessage, events: &CbSender, ws: &CbSender) -> Result<(), Error>; + fn receive(&mut self, data: Vec, stripe: &StripeClient) -> Result; + fn connected(&mut self) -> Result<(), Error>; + fn send(&mut self, msg: RpcMessage) -> Result<(), Error>; } struct Connection { @@ -165,20 +165,16 @@ impl Connection { // when it encounters errors impl Handler for Connection { fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> { - let db = self.pool.get().unwrap(); - self.user.connected(&db, &self.events, &self.ws).unwrap(); + self.user.connected().unwrap(); Ok(()) } fn on_message(&mut self, msg: Message) -> ws::Result<()> { match msg { Message::Binary(msg) => { - let begin = Instant::now(); - let db_connection = self.pool.get().unwrap(); - - match self.user.receive(msg, &db_connection, begin, &self.events, &self.stripe) { + match self.user.receive(msg, &self.stripe) { Ok(msg) => { - self.user.send(msg, &self.events, &self.ws).unwrap(); + self.user.send(msg).unwrap(); }, Err(e) => { warn!("{:?}", e); @@ -220,7 +216,7 @@ impl Handler for Connection { if cookie.name() == TOKEN_HEADER { let db = self.pool.get().unwrap(); match account::from_token(&db, &cookie.value().to_string()) { - Ok(a) => self.user = Box::new(Authorised { id: a.id, account: a }), + Ok(a) => self.user = Box::new(Authenticated::new(a, self.ws.clone(), self.events.clone(), self.pool.clone())), Err(_) => return unauth(), } } @@ -268,11 +264,11 @@ pub fn start(pool: PgPool, events_tx: CbSender, stripe: StripeClient) { DeflateHandler::new( Connection { id, - ws: tx, + ws: tx.clone(), pool: pool.clone(), stripe: stripe.clone(), events: events_tx.clone(), - user: Box::new(Anonymous { id, account: anon_account, game: None, instance: None }) + user: Box::new(Anonymous::new(anon_account, tx)) } ) }) diff --git a/server/src/user_anonymous.rs b/server/src/user_anonymous.rs index a24d9911..213d22a5 100644 --- a/server/src/user_anonymous.rs +++ b/server/src/user_anonymous.rs @@ -1,4 +1,3 @@ -use std::time::Instant; use uuid::Uuid; use failure::Error; @@ -9,11 +8,8 @@ use crossbeam_channel::{Sender as CbSender}; use serde_cbor::{from_slice}; use stripe::{Client as StripeClient}; - use account::{Account}; -use pg::{Db}; use pg; -use events::{Event}; use rpc::{RpcMessage, RpcRequest, User}; use mnml_core::game::Game; @@ -26,10 +22,24 @@ pub struct Anonymous { pub id: Uuid, pub instance: Option, pub game: Option, + + ws: CbSender, +} + +impl Anonymous { + pub fn new(account: Account, ws: CbSender) -> Anonymous { + Anonymous { + id: account.id, + account, + ws, + instance: None, + game: None, + } + } } impl User for Anonymous { - fn send(&mut self, msg: RpcMessage, _events: &CbSender, ws: &CbSender) -> Result<(), Error> { + fn send(&mut self, msg: RpcMessage) -> Result<(), Error> { // if the user queries the state of something // we tell events to push updates to them match msg { @@ -40,21 +50,21 @@ impl User for Anonymous { _ => (), }; - ws.send(msg)?; + self.ws.send(msg)?; Ok(()) } - fn connected(&mut self, _db: &Db, events: &CbSender, ws: &CbSender) -> Result<(), Error> { + fn connected(&mut self) -> Result<(), Error> { info!("anonymous connection"); - self.send(RpcMessage::AccountState(self.account.clone()), events, ws)?; - self.send(RpcMessage::StartTutorial(()), events, ws)?; + self.ws.send(RpcMessage::AccountState(self.account.clone()))?; + self.ws.send(RpcMessage::StartTutorial(()))?; Ok(()) } - fn receive(&mut self, data: Vec, _db: &Db, _begin: Instant, _events: &CbSender, _stripe: &StripeClient) -> Result { + fn receive(&mut self, data: Vec, _stripe: &StripeClient) -> Result { match from_slice::(&data) { Ok(v) => { let get_instance = || { @@ -139,6 +149,10 @@ impl User for Anonymous { game = game.resolve_phase_start(); } + if game.finished() { + self.ws.send(RpcMessage::PromptRegister(()))?; + } + Ok(RpcMessage::GameState(game)) }, diff --git a/server/src/user_authenticated.rs b/server/src/user_authenticated.rs index 3cf25be8..23d0c69d 100644 --- a/server/src/user_authenticated.rs +++ b/server/src/user_authenticated.rs @@ -37,72 +37,90 @@ use events::{Event}; use mtx; use mail; use payments; -use pg::{Db}; +use pg::{PgPool}; use rpc::{RpcMessage, RpcRequest, User}; #[derive(Debug,Clone)] -pub struct Authorised { +pub struct Authenticated { pub account: Account, - pub id: Uuid + pub id: Uuid, + + events: CbSender, + ws: CbSender, + pool: PgPool, } -impl User for Authorised { - fn send(&mut self, msg: RpcMessage, events: &CbSender, ws: &CbSender) -> Result<(), Error> { +impl Authenticated { + pub fn new(account: Account, ws: CbSender, events: CbSender, pool: PgPool) -> Authenticated { + Authenticated { + id: account.id, + account, + ws, + events, + pool, + } + } +} + + +impl User for Authenticated { + fn send(&mut self, msg: RpcMessage) -> Result<(), Error> { // if the user queries the state of something // we tell events to push updates to them match msg { RpcMessage::AccountState(ref v) => { - events.send(Event::Subscribe(self.id, v.id))? + self.events.send(Event::Subscribe(self.id, v.id))? }, RpcMessage::GameState(ref v) => - events.send(Event::Subscribe(self.id, v.id))?, + self.events.send(Event::Subscribe(self.id, v.id))?, RpcMessage::InstanceState(ref v) => - events.send(Event::Subscribe(self.id, v.id))?, + self.events.send(Event::Subscribe(self.id, v.id))?, _ => (), }; - ws.send(msg)?; + self.ws.send(msg)?; Ok(()) } - fn connected(&mut self, db: &Db, events: &CbSender, ws: &CbSender) -> Result<(), Error> { + fn connected(&mut self) -> Result<(), Error> { info!("authenticated connection account={:?}", self.account); let a = &self.account; - ws.send(RpcMessage::AccountAuthenticated(a.clone()))?; + self.ws.send(RpcMessage::AccountAuthenticated(a.clone()))?; // tell events we have connected - events.send(Event::Connect(self.id, a.clone(), ws.clone()))?; + self.events.send(Event::Connect(self.id, a.clone(), self.ws.clone()))?; - ws.send(RpcMessage::AccountState(a.clone()))?; - events.send(Event::Subscribe(self.id, a.id))?; + self.ws.send(RpcMessage::AccountState(a.clone()))?; + self.events.send(Event::Subscribe(self.id, a.id))?; // check if they have an image that needs to be generated account::img_check(&a)?; + let db = self.pool.get()?; let mut tx = db.transaction()?; // send account constructs let account_constructs = account::constructs(&mut tx, &a)?; - ws.send(RpcMessage::AccountConstructs(account_constructs))?; + self.ws.send(RpcMessage::AccountConstructs(account_constructs))?; // get account instances // and send them to the client let account_instances = account::account_instances(&mut tx, &a)?; - ws.send(RpcMessage::AccountInstances(account_instances))?; + self.ws.send(RpcMessage::AccountInstances(account_instances))?; let shop = mtx::account_shop(&mut tx, &a)?; - ws.send(RpcMessage::AccountShop(shop))?; + self.ws.send(RpcMessage::AccountShop(shop))?; let team = account::team(&mut tx, &a)?; - ws.send(RpcMessage::AccountTeam(team))?; + self.ws.send(RpcMessage::AccountTeam(team))?; let wheel = account::chat_wheel(&db, a.id)?; - ws.send(RpcMessage::ChatWheel(wheel))?; + self.ws.send(RpcMessage::ChatWheel(wheel))?; if let Some(instance) = account::tutorial(&mut tx, &a)? { - ws.send(RpcMessage::InstanceState(instance))?; + self.ws.send(RpcMessage::InstanceState(instance))?; } // tx should do nothing @@ -111,8 +129,11 @@ impl User for Authorised { Ok(()) } - fn receive(&mut self, data: Vec, db: &Db, begin: Instant, events: &CbSender, stripe: &StripeClient) -> Result { + fn receive(&mut self, data: Vec, stripe: &StripeClient) -> Result { // cast the msg to this type to receive method name + let begin = Instant::now(); + let db = self.pool.get()?; + match from_slice::(&data) { Ok(v) => { let request = v.clone(); @@ -123,19 +144,19 @@ impl User for Authorised { return Ok(RpcMessage::GameState(anim_test_game(skill))), RpcRequest::InstanceQueue {} => { - events.send(Event::Queue(self.id))?; + self.events.send(Event::Queue(self.id))?; Ok(RpcMessage::QueueRequested(())) }, RpcRequest::InstanceInvite {} => { - events.send(Event::Invite(self.id))?; + self.events.send(Event::Invite(self.id))?; Ok(RpcMessage::InviteRequested(())) }, RpcRequest::InstanceJoin { code } => { - events.send(Event::Join(self.id, code))?; + self.events.send(Event::Join(self.id, code))?; Ok(RpcMessage::Joining(())) }, RpcRequest::InstanceLeave {} => { - events.send(Event::Leave(self.id))?; + self.events.send(Event::Leave(self.id))?; Ok(RpcMessage::Processing(())) }, @@ -147,7 +168,7 @@ impl User for Authorised { let wheel = account::chat_wheel(&db, self.account.id)?; if let Some(c) = wheel.get(index) { - events.send(Event::Chat(self.id, instance_id, c.to_string()))?; + self.events.send(Event::Chat(self.id, instance_id, c.to_string()))?; } else { return Err(err_msg("invalid chat index")); } @@ -172,7 +193,7 @@ impl User for Authorised { Ok(RpcMessage::EmailState(mail::select_account(&db, self.account.id)?)), RpcRequest::SubscriptionState {} => - Ok(RpcMessage::SubscriptionState(payments::account_subscription(db, stripe, &self.account)?)), + Ok(RpcMessage::SubscriptionState(payments::account_subscription(&db, stripe, &self.account)?)), // RpcRequest::AccountShop {} => // Ok(RpcMessage::AccountShop(mtx::account_shop(&mut tx, &account)?)), From bc68362c78af0f3477861c3acaddbe00d645d14d Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 9 Jan 2020 11:59:15 +1000 Subject: [PATCH 03/14] rm youtube link --- client/src/components/play.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/components/play.jsx b/client/src/components/play.jsx index 2c97b77f..e731ad5c 100644 --- a/client/src/components/play.jsx +++ b/client/src/components/play.jsx @@ -232,7 +232,6 @@ 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 41921ad926d4c1ab06359f727b220448d6b62533 Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 9 Jan 2020 12:04:13 +1000 Subject: [PATCH 04/14] speed initial cooldown reduction wip --- core/src/construct.rs | 34 +++++++++++++++++++++++++---- core/src/game.rs | 50 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/core/src/construct.rs b/core/src/construct.rs index 3a11d06d..c9c4cd4d 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -56,6 +56,10 @@ impl ConstructSkill { disabled: false, } } + + pub fn set_cooldown(&mut self, cd: Cooldown) -> () { + self.cd = cd; + } } #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] @@ -432,15 +436,37 @@ impl Construct { self.skills.iter().find(|s| s.skill == skill && s.cd.is_some()) } - pub fn skill_set_cd(&mut self, skill: Skill) -> &mut Construct { + pub fn set_construct_delays(&mut self) -> () { + // for every multiple of speed threshold delays are reduced by 1 at start of game + let speed_threshold = 250; + let delay_reduction = self.speed.value.wrapping_div(speed_threshold); + + self.skills + .iter_mut() + .for_each(|s| match s.skill.base_cd() { + Some(cd) => { + let reduced_delay = cd.saturating_sub(delay_reduction); + match reduced_delay { + 0 => s.set_cooldown(None), + _ => s.set_cooldown(Some(reduced_delay)) + } + }, + None => s.set_cooldown(None) + }); + } + + pub fn skill_set_cd(&mut self, skill: Skill, cd: Cooldown) -> &mut Construct { // println!("{:?} {:?} skill cooldown set", self.name, skill); // tests force resolve some skills // which cause the game to attempt to put them on cd // even though the construct doesn't know the skill - if let Some(i) = self.skills.iter().position(|s| s.skill == skill) { - self.skills.remove(i); - self.skills.insert(i, ConstructSkill::new(skill)); + // if let Some(i) = self.skills.iter().position(|s| s.skill == skill) { + // self.skills.remove(i); + // self.skills.insert(i, ConstructSkill::new(skill)); + //} + if let Some(sk) = self.skills.iter_mut().find(|s| s.skill == skill) { + sk.set_cooldown(cd); } self diff --git a/core/src/game.rs b/core/src/game.rs index fbb8f187..cb2037e8 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -11,6 +11,7 @@ use failure::err_msg; use construct::{Construct, ConstructEffect, Stat, EffectMeta}; use skill::{Skill, Cast}; +use spec::{Spec}; use effect::{Effect}; use player::{Player}; @@ -140,12 +141,19 @@ impl Game { && self.players.iter().all(|t| t.constructs.len() == self.player_constructs) } - pub fn start(self) -> Game { + pub fn start(mut self) -> Game { // both forfeit ddue to no skills if self.finished() { return self.finish(); } + self.players + .iter_mut() + .for_each(|p| p.constructs + .iter_mut() + .for_each(|c| c.set_construct_delays()) + ); + self.skill_phase_start(0) } @@ -593,7 +601,7 @@ impl Game { Event::Damage { construct, colour: _, amount: _, mitigation: _, display: _ } => self.construct_by_id(construct).unwrap().damage_trigger_casts(&cast, &event), Event::Cast { construct, skill, player: _, target: _, direction: _ } => { - self.construct_by_id(construct).unwrap().skill_set_cd(skill); + self.construct_by_id(construct).unwrap().skill_set_cd(skill, skill.base_cd()); vec![] } Event::Ko { construct } => @@ -1163,6 +1171,44 @@ mod tests { return; } + #[test] + fn delay_test() { + let mut x = Construct::new() + .named(&"pronounced \"creeep\"".to_string()) + .learn(Skill::Ruin); + + let mut y = Construct::new() + .named(&"lemongrass tea".to_string()) + .learn(Skill::Ruin); + + // Ruin has 2 turn cd + // 250 speed = 1 cd delay reduction + x.speed.force(499); + y.speed.force(700); + + let mut game = Game::new(); + game.set_player_num(2).set_player_constructs(1); + + let x_player_id = Uuid::new_v4(); + x.account = x_player_id; + let x_player = Player::new(x_player_id, None, &"ntr".to_string(), vec![x]); + + let y_player_id = Uuid::new_v4(); + y.account = y_player_id; + let y_player = Player::new(y_player_id, None, &"mash".to_string(), vec![y]); + + game + .player_add(x_player).unwrap() + .player_add(y_player).unwrap(); + + game = game.start(); + + assert!(game.players[0].constructs[0].skill_on_cd(Skill::Ruin).is_some()); + assert!(game.players[1].constructs[0].skill_on_cd(Skill::Ruin).is_none()); + } + + + #[test] fn stun_test() { let mut game = create_test_game(); From 1bc871c66e08a1fc7357079dddcc02680e403886 Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 9 Jan 2020 12:11:11 +1000 Subject: [PATCH 05/14] set cd --- core/src/construct.rs | 4 ++-- core/src/game.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/construct.rs b/core/src/construct.rs index c9c4cd4d..2a59ba25 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -455,7 +455,7 @@ impl Construct { }); } - pub fn skill_set_cd(&mut self, skill: Skill, cd: Cooldown) -> &mut Construct { + pub fn skill_set_cd(&mut self, skill: Skill) -> &mut Construct { // println!("{:?} {:?} skill cooldown set", self.name, skill); // tests force resolve some skills @@ -466,7 +466,7 @@ impl Construct { // self.skills.insert(i, ConstructSkill::new(skill)); //} if let Some(sk) = self.skills.iter_mut().find(|s| s.skill == skill) { - sk.set_cooldown(cd); + sk.set_cooldown(skill.base_cd()); } self diff --git a/core/src/game.rs b/core/src/game.rs index cb2037e8..d45e8d7b 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -601,7 +601,7 @@ impl Game { Event::Damage { construct, colour: _, amount: _, mitigation: _, display: _ } => self.construct_by_id(construct).unwrap().damage_trigger_casts(&cast, &event), Event::Cast { construct, skill, player: _, target: _, direction: _ } => { - self.construct_by_id(construct).unwrap().skill_set_cd(skill, skill.base_cd()); + self.construct_by_id(construct).unwrap().skill_set_cd(skill); vec![] } Event::Ko { construct } => From 9c5b7d0c897ad6f8ec899d16f2c9411bf872329c Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 9 Jan 2020 12:24:22 +1000 Subject: [PATCH 06/14] cleanup --- core/src/construct.rs | 11 ++++------- core/src/game.rs | 1 - 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/core/src/construct.rs b/core/src/construct.rs index 2a59ba25..e7fcf993 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -444,14 +444,11 @@ impl Construct { self.skills .iter_mut() .for_each(|s| match s.skill.base_cd() { - Some(cd) => { - let reduced_delay = cd.saturating_sub(delay_reduction); - match reduced_delay { - 0 => s.set_cooldown(None), - _ => s.set_cooldown(Some(reduced_delay)) - } + Some(cd) => match cd.saturating_sub(delay_reduction) { + 0 => s.set_cooldown(None), + _ => s.set_cooldown(Some(cd.saturating_sub(delay_reduction))) }, - None => s.set_cooldown(None) + None => () }); } diff --git a/core/src/game.rs b/core/src/game.rs index d45e8d7b..f7c0f8b1 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -11,7 +11,6 @@ use failure::err_msg; use construct::{Construct, ConstructEffect, Stat, EffectMeta}; use skill::{Skill, Cast}; -use spec::{Spec}; use effect::{Effect}; use player::{Player}; From 5b45d9b5e460de3cf9542f86975fb9ba47495713 Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 9 Jan 2020 14:23:40 +1000 Subject: [PATCH 07/14] add skill delays --- core/src/construct.rs | 8 +-- core/src/game.rs | 2 +- core/src/skill.rs | 149 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 5 deletions(-) diff --git a/core/src/construct.rs b/core/src/construct.rs index e7fcf993..2c45b7be 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -52,7 +52,7 @@ impl ConstructSkill { pub fn new(skill: Skill) -> ConstructSkill { ConstructSkill { skill, - cd: skill.base_cd(), + cd: skill.delay(), disabled: false, } } @@ -443,12 +443,12 @@ impl Construct { self.skills .iter_mut() - .for_each(|s| match s.skill.base_cd() { + .for_each(|s| match s.skill.delay() { Some(cd) => match cd.saturating_sub(delay_reduction) { 0 => s.set_cooldown(None), _ => s.set_cooldown(Some(cd.saturating_sub(delay_reduction))) }, - None => () + None => s.set_cooldown(None) }); } @@ -1241,7 +1241,7 @@ mod tests { i += 1; } - assert_eq!(i, Skill::Sleep.base_cd().unwrap()); + assert_eq!(i, Skill::Sleep.delay().unwrap()); } } diff --git a/core/src/game.rs b/core/src/game.rs index f7c0f8b1..42e14f8b 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -1285,7 +1285,7 @@ mod tests { // should auto progress back to skill phase assert!(game.phase == Phase::Skill); - assert!(game.player_by_id(y_player.id).unwrap().constructs[0].skill_on_cd(Skill::Stun).is_some()); + assert!(game.player_by_id(y_player.id).unwrap().constructs[0].skill_on_cd(Skill::Stun).is_none()); assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Block).is_none()); game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Attack).unwrap(); diff --git a/core/src/skill.rs b/core/src/skill.rs index 653719f2..257e2412 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -522,6 +522,155 @@ impl Skill { Skill::SustainPlus | Skill::SustainPlusPlus => Some(1), + + + Skill::Electrify | + Skill::ElectrifyPlus | + Skill::ElectrifyPlusPlus => None, + + Skill::Absorb | + Skill::AbsorbPlus | + Skill::AbsorbPlusPlus => Some(1), + + //----------- + // Never cast directly + //--------- + // Trigger + Skill::HybridBlast | + Skill::HasteStrike | + Skill::CounterAttack| + Skill::CounterAttackPlus | + Skill::CounterAttackPlusPlus | // counter + Skill::Electrocute| + Skill::ElectrocutePlus | + Skill::ElectrocutePlusPlus | + Skill::Absorption| + Skill::AbsorptionPlus | + Skill::AbsorptionPlusPlus | + // Ticks + Skill::ElectrocuteTick| + Skill::DecayTick| + Skill::SiphonTick| + Skill::TriageTick => None, + } + } + + pub fn delay(&self) -> Cooldown { + match self { + Skill::Attack => None, + Skill::Block => None, // reduce damage + Skill::Buff => None, + Skill::Debuff => None, + Skill::Stun => Some(1), + + Skill::Strike=> None, + Skill::StrikePlus => None, + Skill::StrikePlusPlus => None, + + Skill::Counter| + Skill::CounterPlus | + Skill::CounterPlusPlus => None, // avoid all damage + + Skill::Restrict | + Skill::RestrictPlus | + Skill::RestrictPlusPlus => Some(1), + + Skill::Bash | + Skill::BashPlus | + Skill::BashPlusPlus => Some(1), + + Skill::Heal=> None, + Skill::HealPlus => None, + Skill::HealPlusPlus => None, + + Skill::Triage=> None, // hot + Skill::TriagePlus => None, // hot + Skill::TriagePlusPlus => None, // hot + + Skill::Break | // no damage stun, adds vulnerable + Skill::BreakPlus | + Skill::BreakPlusPlus => Some(1), + + Skill::Blast | + Skill::BlastPlus | + Skill::BlastPlusPlus => None, + + Skill::Chaos | + Skill::ChaosPlus | + Skill::ChaosPlusPlus => None, + + Skill::Amplify | + Skill::AmplifyPlus | + Skill::AmplifyPlusPlus => Some(1), + + Skill::Hybrid | + Skill::HybridPlus | + Skill::HybridPlusPlus => Some(1), + + Skill::Invert | + Skill::InvertPlus | + Skill::InvertPlusPlus => Some(2), + + Skill::Decay => None, // dot + Skill::DecayPlus => None, + Skill::DecayPlusPlus => None, + + Skill::Siphon| + Skill::SiphonPlus | + Skill::SiphonPlusPlus => None, + + Skill::Curse | + Skill::CursePlus | + Skill::CursePlusPlus => Some(1), + + Skill::Link | + Skill::LinkPlus | + Skill::LinkPlusPlus => Some(1), + + Skill::Silence | + Skill::SilencePlus | + Skill::SilencePlusPlus => Some(1), + + Skill::Purify | + Skill::PurifyPlus | + Skill::PurifyPlusPlus => None, + + Skill::Purge | + Skill::PurgePlus | + Skill::PurgePlusPlus => Some(1), + + Skill::Banish | + Skill::BanishPlus | + Skill::BanishPlusPlus => Some(1), + + Skill::Haste | + Skill::HastePlus | + Skill::HastePlusPlus => Some(1), + + Skill::Reflect | + Skill::ReflectPlus | + Skill::ReflectPlusPlus => None, + + Skill::Recharge | + Skill::RechargePlus | + Skill::RechargePlusPlus => None, + + Skill::Ruin | + Skill::RuinPlus | + Skill::RuinPlusPlus => Some(2), + + Skill::Slay=> None, + Skill::SlayPlus => None, + Skill::SlayPlusPlus => None, + + Skill::Sleep | + Skill::SleepPlus | + Skill::SleepPlusPlus => Some(1), + + Skill::Sustain | + Skill::SustainPlus | + Skill::SustainPlusPlus => Some(1), + Skill::Intercept => Some(1), Skill::InterceptPlus => Some(1), Skill::InterceptPlusPlus => Some(1), From 45b38a73e595e60170b42425ab0186dd69ed0944 Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 9 Jan 2020 14:26:40 +1000 Subject: [PATCH 08/14] woops --- core/src/skill.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/skill.rs b/core/src/skill.rs index 257e2412..12045329 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -522,7 +522,9 @@ impl Skill { Skill::SustainPlus | Skill::SustainPlusPlus => Some(1), - + Skill::Intercept => Some(2), + Skill::InterceptPlus => Some(2), + Skill::InterceptPlusPlus => Some(2), Skill::Electrify | Skill::ElectrifyPlus | From e9f92aa1b88d99e40959939a018f462a0bc54992 Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 9 Jan 2020 14:50:37 +1000 Subject: [PATCH 09/14] wl --- WORKLOG.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/WORKLOG.md b/WORKLOG.md index 4fb85ec6..fc60a200 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -3,10 +3,6 @@ _ntr_ * can't reset password without knowing password =\ -* quick play updates - * game phase real fast 1 shot ko enemies - * redirect to register after 1 round finishes - * hide abandon / draw / offer * audio * animation effects From cb14b1c50f78a16caf76e1d98c395080017ae089 Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 9 Jan 2020 15:34:15 +1000 Subject: [PATCH 10/14] add delay info to client --- client/src/components/vbox.utils.jsx | 2 +- core/src/item.rs | 5 +++++ core/src/skill.rs | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/client/src/components/vbox.utils.jsx b/client/src/components/vbox.utils.jsx index 4a4a90d1..9fcaca5c 100644 --- a/client/src/components/vbox.utils.jsx +++ b/client/src/components/vbox.utils.jsx @@ -96,7 +96,7 @@ function genItemInfo(item, itemInfo, player) { itemSourceInfo = reactStringReplace(itemSourceInfo, itemRegEx, match => shapes[match]()); } - const cooldown = isSkill && fullInfo.cooldown ?
{fullInfo.cooldown} Turn delay
: null; + const cooldown = isSkill && fullInfo.cooldown ?
{fullInfo.delay} turn delay, {fullInfo.cooldown} turn cooldown
: null; const speed = isSkill ?
Speed {shapes.SpeedStat()} multiplier {fullInfo.speed * 4}%
diff --git a/core/src/item.rs b/core/src/item.rs index 185b1832..9b13f568 100644 --- a/core/src/item.rs +++ b/core/src/item.rs @@ -1362,6 +1362,7 @@ pub struct ItemInfo { pub values: Option, pub skill: bool, pub speed: Option, + pub delay: Cooldown, pub cooldown: Cooldown, pub description: String, } @@ -1406,6 +1407,10 @@ pub fn item_info() -> ItemInfoCtr { Some(s) => s.base_cd(), None => None }, + delay: match v.into_skill() { + Some(s) => s.delay(), + None => None + }, }) .collect::>(); diff --git a/core/src/skill.rs b/core/src/skill.rs index 12045329..f26729a5 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -571,7 +571,7 @@ impl Skill { Skill::Counter| Skill::CounterPlus | - Skill::CounterPlusPlus => None, // avoid all damage + Skill::CounterPlusPlus => None, Skill::Restrict | Skill::RestrictPlus | From d4b5efcae6e17bec21c5751d8eab123dd884a669 Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 9 Jan 2020 15:39:32 +1000 Subject: [PATCH 11/14] speed description --- WORKLOG.md | 4 ---- client/src/constants.jsx | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/WORKLOG.md b/WORKLOG.md index fc60a200..5f20d1d1 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -10,10 +10,6 @@ _ntr_ * background music _mashy_ -* change cooldowns to delay & recharge - - delay is cooldown before skill can first be used - - recharge is cooldown after using skill - - every x speed reduces delay of skills * combat text - last 3-4 text events (damage / heal / disable etc) diff --git a/client/src/constants.jsx b/client/src/constants.jsx index c6b6dfaf..39b38535 100644 --- a/client/src/constants.jsx +++ b/client/src/constants.jsx @@ -71,7 +71,7 @@ module.exports = { }, speedStat: { item: 'SPEED', - description: 'Speed determines the order in which skills resolve.\nCombine SPEED specs to increase speed.', + description: 'Speed determines the order in which skills resolve.\nThe initial delay of skills is reduced by 1 turn for every 250 speed.\nCombine SPEED specs to increase speed.', }, }, }; From 4f6c3decd6c5b650ee7b995ba146a1071ea0be7e Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 9 Jan 2020 15:44:54 +1000 Subject: [PATCH 12/14] v1.12.0 --- VERSION | 2 +- acp/package.json | 2 +- client/package.json | 2 +- core/Cargo.toml | 2 +- ops/package.json | 2 +- server/Cargo.toml | 2 +- studios/package.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/VERSION b/VERSION index 0c9cb695..32bd932f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.11.2 \ No newline at end of file +1.12.0 \ No newline at end of file diff --git a/acp/package.json b/acp/package.json index e3c2b7f2..0e92cddc 100644 --- a/acp/package.json +++ b/acp/package.json @@ -1,6 +1,6 @@ { "name": "mnml-client", - "version": "1.11.2", + "version": "1.12.0", "description": "", "main": "index.js", "scripts": { diff --git a/client/package.json b/client/package.json index 94c36086..f3b08026 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "mnml-client", - "version": "1.11.2", + "version": "1.12.0", "description": "", "main": "index.js", "scripts": { diff --git a/core/Cargo.toml b/core/Cargo.toml index f128fda1..4edb5c25 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mnml_core" -version = "1.11.2" +version = "1.12.0" authors = ["ntr ", "mashy "] [dependencies] diff --git a/ops/package.json b/ops/package.json index 9a1ed953..3b993c63 100644 --- a/ops/package.json +++ b/ops/package.json @@ -1,6 +1,6 @@ { "name": "mnml-ops", - "version": "1.11.2", + "version": "1.12.0", "description": "", "main": "index.js", "scripts": { diff --git a/server/Cargo.toml b/server/Cargo.toml index 16ced6b7..9f7e199a 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mnml" -version = "1.11.2" +version = "1.12.0" authors = ["ntr "] [dependencies] diff --git a/studios/package.json b/studios/package.json index d7abb0fd..4d90c4c3 100644 --- a/studios/package.json +++ b/studios/package.json @@ -1,6 +1,6 @@ { "name": "mnml-studios", - "version": "1.11.2", + "version": "1.12.0", "description": "", "main": "index.js", "scripts": { From 15bc05b3d47d9cc941433a78146c92dec9e0c104 Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 9 Jan 2020 16:33:19 +1000 Subject: [PATCH 13/14] remove current password requirement so you can change pw after recovery --- client/src/components/account.top.jsx | 22 ++++------- server/src/account.rs | 54 +++++++++++++-------------- server/src/http.rs | 4 +- server/src/mail.rs | 8 ++-- 4 files changed, 40 insertions(+), 48 deletions(-) diff --git a/client/src/components/account.top.jsx b/client/src/components/account.top.jsx index b2500d62..eb4acec0 100644 --- a/client/src/components/account.top.jsx +++ b/client/src/components/account.top.jsx @@ -19,8 +19,8 @@ const addState = connect( } = state; - function sendSetPassword(current, password) { - postData('/account/password', { current, password }) + function sendSetPassword(password) { + postData('/account/password', { password }) .then(res => res.json()) .then(data => { if (data.error) return errorToast(data.error); @@ -74,7 +74,7 @@ class AccountStatus extends Component { super(props); this.state = { - passwordState: { current: '', password: '', confirm: ''}, + passwordState: { password: '', confirm: ''}, emailState: null, unsubState: false, }; @@ -105,8 +105,8 @@ class AccountStatus extends Component { passwordState.password === passwordState.confirm; const setPasswordDisabled = () => { - const { current, password, confirm } = passwordState; - return !(passwordsEqual() && password && current && confirm); + const { password, confirm } = passwordState; + return !(passwordsEqual() && password && confirm); } const tlClick = e => { @@ -173,15 +173,7 @@ class AccountStatus extends Component {

Password

- - +
diff --git a/server/src/account.rs b/server/src/account.rs index 08d1ca74..f180cf70 100644 --- a/server/src/account.rs +++ b/server/src/account.rs @@ -213,42 +213,42 @@ pub fn new_img(tx: &mut Transaction, id: Uuid) -> Result { Account::try_from(row) } -pub fn set_password(tx: &mut Transaction, id: Uuid, current: &String, password: &String) -> Result { +pub fn set_password(tx: &mut Transaction, id: Uuid, password: &String) -> Result { if password.len() < PASSWORD_MIN_LEN || password.len() > 100 { return Err(MnmlHttpError::PasswordUnacceptable); } - let query = " - SELECT id, password - FROM accounts - WHERE id = $1 - "; + // let query = " + // SELECT id, password + // FROM accounts + // WHERE id = $1 + // "; - let result = tx - .query(query, &[&id])?; + // let result = tx + // .query(query, &[&id])?; - let row = match result.iter().next() { - Some(row) => row, - None => { - let mut rng = thread_rng(); - let garbage: String = iter::repeat(()) - .map(|()| rng.sample(Alphanumeric)) - .take(64) - .collect(); + // let row = match result.iter().next() { + // Some(row) => row, + // None => { + // let mut rng = thread_rng(); + // let garbage: String = iter::repeat(()) + // .map(|()| rng.sample(Alphanumeric)) + // .take(64) + // .collect(); - // verify garbage to prevent timing attacks - verify(garbage.clone(), &garbage).ok(); - return Err(MnmlHttpError::AccountNotFound); - }, - }; + // // verify garbage to prevent timing attacks + // verify(garbage.clone(), &garbage).ok(); + // return Err(MnmlHttpError::AccountNotFound); + // }, + // }; - let id: Uuid = row.get(0); - let db_pw: String = row.get(1); + // let id: Uuid = row.get(0); + // let db_pw: String = row.get(1); - // return bad request to prevent being logged out - if !verify(current, &db_pw)? { - return Err(MnmlHttpError::BadRequest); - } + // // return bad request to prevent being logged out + // if !verify(current, &db_pw)? { + // return Err(MnmlHttpError::BadRequest); + // } let password = hash(&password, PASSWORD_ROUNDS)?; diff --git a/server/src/http.rs b/server/src/http.rs index 88e7b51b..34b3b994 100644 --- a/server/src/http.rs +++ b/server/src/http.rs @@ -369,7 +369,7 @@ fn recover(req: &mut Request) -> IronResult { #[derive(Debug,Clone,Deserialize)] struct SetPassword { - current: String, + // current: String, password: String, } @@ -385,7 +385,7 @@ fn set_password(req: &mut Request) -> IronResult { let db = state.pool.get().or(Err(MnmlHttpError::DbError))?; let mut tx = db.transaction().or(Err(MnmlHttpError::DbError))?; - let token = account::set_password(&mut tx, a.id, ¶ms.current, ¶ms.password)?; + let token = account::set_password(&mut tx, a.id, ¶ms.password)?; tx.commit().or(Err(MnmlHttpError::ServerError))?; diff --git a/server/src/mail.rs b/server/src/mail.rs index d5083021..8f3b351f 100644 --- a/server/src/mail.rs +++ b/server/src/mail.rs @@ -42,10 +42,10 @@ pub enum Mail { fn recover(email: &String, name: &String, token: &String) -> SendableEmail { let body = format!("{:}, the link below will recover your account. -please change your password immediately in the account page. -this link will expire in 48 hours or once used. +please change your password immediately in the account page +as this link will expire in 48 hours or once used. -http://mnml.gg/api/account/recover?recover_token={:} +https://mnml.gg/api/account/recover?recover_token={:} glhf --mnml", name, token); @@ -63,7 +63,7 @@ glhf fn confirm(email: &String, name: &String, token: &String) -> SendableEmail { let confirm_body = format!("{:}, please click the link below to confirm your email -http://mnml.gg/api/account/email/confirm?confirm_token={:} +https://mnml.gg/api/account/email/confirm?confirm_token={:} glhf --mnml", name, token); From 5871f3129bd5cde9dfd497f64869c5c275b8ac9b Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 10 Jan 2020 12:21:37 +1000 Subject: [PATCH 14/14] fix tutorial construct order bug --- core/src/game.rs | 3 +-- core/src/player.rs | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/game.rs b/core/src/game.rs index 42e14f8b..5364013b 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -104,7 +104,6 @@ impl Game { // let player_description = player.constructs.iter().map(|c| c.name.clone()).collect::>().join(", "); // self.log.push(format!("{:} has joined the game. [{:}]", player.name, player_description)); - player.constructs.sort_unstable_by_key(|c| c.id); self.players.push(player); Ok(self) @@ -1201,7 +1200,7 @@ mod tests { .player_add(y_player).unwrap(); game = game.start(); - + assert!(game.players[0].constructs[0].skill_on_cd(Skill::Ruin).is_some()); assert!(game.players[1].constructs[0].skill_on_cd(Skill::Ruin).is_none()); } diff --git a/core/src/player.rs b/core/src/player.rs index 21556a0b..0b686a60 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -65,7 +65,9 @@ pub struct Player { } impl Player { - pub fn new(account: Uuid, img: Option, name: &String, constructs: Vec) -> Player { + pub fn new(account: Uuid, img: Option, name: &String, mut constructs: Vec) -> Player { + constructs.sort_unstable_by_key(|c| c.id); + Player { id: account, img,