From 7520be7cf2287fa13467104f04e1d78c4a73a8bb Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 19 Dec 2019 12:19:55 +1000 Subject: [PATCH 01/58] v1.11.0 --- VERSION | 2 +- acp/package.json | 2 +- client/package.json | 2 +- core/Cargo.toml | 2 +- ops/package.json | 2 +- server/Cargo.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index e33692ab..169f19b4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.10.1 \ No newline at end of file +1.11.0 \ No newline at end of file diff --git a/acp/package.json b/acp/package.json index af19ae15..196377a3 100644 --- a/acp/package.json +++ b/acp/package.json @@ -1,6 +1,6 @@ { "name": "mnml-client", - "version": "1.10.1", + "version": "1.11.0", "description": "", "main": "index.js", "scripts": { diff --git a/client/package.json b/client/package.json index c840b666..a0e5ba9f 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "mnml-client", - "version": "1.10.1", + "version": "1.11.0", "description": "", "main": "index.js", "scripts": { diff --git a/core/Cargo.toml b/core/Cargo.toml index 57a24193..64372ae4 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mnml_core" -version = "1.10.0" +version = "1.11.0" authors = ["ntr ", "mashy "] [dependencies] diff --git a/ops/package.json b/ops/package.json index d4b90bb7..2fc06500 100644 --- a/ops/package.json +++ b/ops/package.json @@ -1,6 +1,6 @@ { "name": "mnml-ops", - "version": "1.10.1", + "version": "1.11.0", "description": "", "main": "index.js", "scripts": { diff --git a/server/Cargo.toml b/server/Cargo.toml index 4b409c11..accc74b3 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mnml" -version = "1.10.1" +version = "1.11.0" authors = ["ntr "] [dependencies] From 24b1de772492a72710c6b71fb0e75edcac039afb Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 19 Dec 2019 13:37:40 +1000 Subject: [PATCH 02/58] fixme --- core/fixme.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/fixme.md b/core/fixme.md index 8223a821..679ae95d 100644 --- a/core/fixme.md +++ b/core/fixme.md @@ -4,3 +4,9 @@ game ready not auto starting resolve phase cooldowns set after cast cooldowns reduced after 1 complete cast + +don't focus if ko +highlight skills being used +ruin cd +triage 0 heal +effects info \ No newline at end of file From 16488ee0ee556de5b5d43a394d56116c29265540 Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 19 Dec 2019 13:50:26 +1000 Subject: [PATCH 03/58] log panics --- server/Cargo.toml | 1 + server/src/lib.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/server/Cargo.toml b/server/Cargo.toml index accc74b3..2dfe13f5 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -25,6 +25,7 @@ dotenv = "0.9.0" log = "0.4" fern = { version = "0.5", features = ["colored", "syslog-4"] } syslog = "4" +log-panics = "2" iron = "0.6" bodyparser = "0.8" diff --git a/server/src/lib.rs b/server/src/lib.rs index 954197e4..66efa49d 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -15,6 +15,7 @@ extern crate serde_cbor; #[macro_use] extern crate failure; extern crate fern; +extern crate log_panics; #[macro_use] extern crate log; extern crate stripe; @@ -55,6 +56,8 @@ use crossbeam_channel::{unbounded}; #[cfg(unix)] pub fn setup_logger() -> Result<(), fern::InitError> { + log_panics::init(); + let formatter = syslog::Formatter3164 { facility: syslog::Facility::LOG_USER, hostname: None, From 7ff5d9585c7000e825fcfceb7273fb5f3d67f672 Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 19 Dec 2019 14:03:54 +1000 Subject: [PATCH 04/58] add back effects descriptions --- client/src/utils.jsx | 39 ++++++++++++--------------------------- core/src/skill.rs | 4 ++-- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/client/src/utils.jsx b/client/src/utils.jsx index 349679c5..b2c715fb 100644 --- a/client/src/utils.jsx +++ b/client/src/utils.jsx @@ -241,30 +241,15 @@ function convertItem(v) { function effectInfo(i) { // FIX ME - return 'effect info to be fixed'; - - /*const hybridBlast = 25; + const hybridBlast = 25; const hasteStrike = 30; function multiplier(s) { // Update later to use server info in future - if (s === 'CounterAttack') return 120; - if (s === 'CounterAttack+') return 160; - if (s === 'CounterAttack++') return 230; - - if (s === 'DecayTick') return 33; - if (s === 'DecayTick+') return 45; - if (s === 'DecayTick++') return 70; - - if (s === 'SiphonTick') return 25; - if (s === 'SiphonTick+') return 30; - if (s === 'SiphonTick++') return 40; - - if (s === 'TriageTick') return 75; - if (s === 'TriageTick+') return 110; - if (s === 'TriageTick++') return 140; - - if (s === 'Electrocute' || s === 'ElectrocuteTick') return 80; - if (s === 'Electrocute+' || s === 'ElectrocuteTick+') return 100; - if (s === 'Electrocute++' || s === 'ElectrocuteTick++') return 130; + if (s === 'CounterAttack') return 115; + if (s === 'CounterAttack+') return 130; + if (s === 'CounterAttack++') return 160; + if (s === 'Electrocute') return 80; + if (s === 'Electrocute+') return 90; + if (s === 'Electrocute++') return 100; return 0; } @@ -289,16 +274,16 @@ function effectInfo(i) { case 'Vulnerable': return `Construct will take ${i.meta[1] - 100}% increased red damage`; case 'Silence': return 'Disable construct from casting any blue skills'; case 'Wither': return `Construct will take ${100 - i.meta[1]}% reduced healing`; // - case 'Decay': return `Construct will take ${multiplier(i.tick.skill)}% of caster's BluePower as blue damage each turn.`; // + case 'Decay': return `Construct will take ${i.meta[1].amount} blue damage each turn.`; // case 'Electric': return `Attacks against this construct will apply Electrocute dealing ${multiplier(i.meta[1])}% of construct BluePower as blue damage each turn.`; - case 'Electrocute': return `Construct will take ${multiplier(i.tick.skill)}% of caster's BluePower as blue damage each turn.`; + case 'Electrocute': return `Construct will take ${i.meta[1].amount} blue damage each turn.`; case 'Absorb': return 'If construct takes damage, Absorption will be applied increasing RedPower and BluePower based on damage taken.'; case 'Absorption': return `Increasing construct RedPower and BluePower by ${i.meta[1]}`; - case 'Triage': return `Construct will be healed for ${multiplier(i.tick.skill)}% of caster's GreenPower each turn.`; - case 'Siphon': return `Construct will take ${multiplier(i.tick.skill)}% of caster's BluePower + GreenPower as blue damage each turn, healing the caster.`; + case 'Triage': return `Construct will be healed for ${i.meta[1].amount} green life each turn.`; + case 'Siphon': return `Construct will take ${i.meta[1].amount} blue damage each turn, healing the caster.`; default: return 'Missing Effect Text'; - }*/ + } } module.exports = { diff --git a/core/src/skill.rs b/core/src/skill.rs index 6599ba96..8360e8dc 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -1688,13 +1688,13 @@ fn electrocute(cast: Cast, game: &mut Game, values: Electrocute) { game.action(cast, Action::Remove { construct: cast.source, - effect: Effect::Electrocute, + effect: Effect::Electric, } ); game.action(cast, Action::Effect { construct: cast.target, - effect: ConstructEffect { effect: Effect::Electric, duration: values.duration(), meta: + effect: ConstructEffect { effect: Effect::Electrocute, duration: values.duration(), meta: Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::ElectrocuteTick, speed: cast.speed, amount }) }, }, ); From 9a5a93ce242afc4b1ed9464b4f866236d8ec3b1c Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 19 Dec 2019 14:42:42 +1000 Subject: [PATCH 05/58] fix ruin cooldown --- core/src/construct.rs | 4 +- core/src/game.rs | 91 +++++++++++++++++-------------------------- core/src/item.rs | 21 ++++------ core/src/skill.rs | 7 ---- 4 files changed, 45 insertions(+), 78 deletions(-) diff --git a/core/src/construct.rs b/core/src/construct.rs index 47c60095..32579e7b 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -435,12 +435,14 @@ impl Construct { } pub fn skill_set_cd(&mut self, skill: Skill) -> &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.push(ConstructSkill::new(skill)); + self.skills.insert(i, ConstructSkill::new(skill)); } self diff --git a/core/src/game.rs b/core/src/game.rs index 6724e12b..917cec9d 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -508,14 +508,14 @@ impl Game { self.resolve(Cast { skill, ..cast }); } - // for aoe events send the source / target animations before each set of casts + if cast.skill.cast_animation() { + self.action(cast, Action::Cast); + } + if cast.skill.aoe() { - if cast.skill.cast_animation() { - let event = self.cast(cast); - self.add_resolution(&cast, &event); - } - let event = self.hit_aoe(cast); - self.add_resolution(&cast, &event); + self.action(cast, Action::HitAoe); + } else { + self.action(cast, Action::Hit); } let casts = self.modify_cast(cast); @@ -559,6 +559,7 @@ impl Game { let new_events = match action { Action::Cast => vec![self.cast(cast)], Action::Hit => vec![self.hit(cast)], + Action::HitAoe => vec![self.hit_aoe(cast)], Action::Damage { construct, amount, colour } => self.damage(construct, amount, colour), Action::Heal { construct, amount, colour } => self.heal(construct, amount, colour), @@ -848,6 +849,7 @@ pub enum Value { #[derive(Debug,Clone,PartialEq)] pub enum Action { Hit, + HitAoe, Cast, Heal { construct: Uuid, amount: usize, colour: Colour }, Damage { construct: Uuid, amount: usize, colour: Colour }, @@ -1033,6 +1035,7 @@ mod tests { .learn(Skill::Siphon) .learn(Skill::Amplify) .learn(Skill::Stun) + .learn(Skill::Ruin) .learn(Skill::Block) .learn(Skill::Sleep) .learn(Skill::Decay); @@ -1251,6 +1254,31 @@ mod tests { assert!(game.player_by_id(y_player.id).unwrap().constructs[0].skill_on_cd(Skill::Block).is_none()); } + + #[test] + fn ruin_cooldown_test() { + let mut game = create_test_game(); + + let x_player = game.players[0].clone(); + let y_player = game.players[1].clone(); + + let x_construct = x_player.constructs[0].clone(); + let y_construct = y_player.constructs[0].clone(); + + while game.construct_by_id(x_construct.id).unwrap().skill_on_cd(Skill::Ruin).is_some() { + game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns(); + } + + game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Ruin).unwrap(); + + game.player_ready(x_player.id).unwrap(); + game.player_ready(y_player.id).unwrap(); + + game = game.resolve_phase_start(); + + assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Ruin).is_some()); + } + // #[cfg(test)] // mod tests { // use skill::*; @@ -1595,55 +1623,6 @@ mod tests { // } // } - - #[test] - fn sleep_cooldown_test() { - let mut game = create_test_game(); - - let x_player = game.players[0].clone(); - let y_player = game.players[1].clone(); - - let x_construct = x_player.constructs[0].clone(); - let y_construct = y_player.constructs[0].clone(); - - - for _n in 1..10 { - // should auto progress back to skill phase - assert!(game.phase == Phase::Skill); - - // Sleep 2T CD - assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Decay).is_none()); - assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Sleep).is_some()); - - game.player_ready(x_player.id).unwrap(); - game.player_ready(y_player.id).unwrap(); - game = game.resolve_phase_start(); - - // Sleep 1T CD - assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Decay).is_none()); - assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Sleep).is_some()); - - game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Decay).unwrap(); - // game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Attack).unwrap(); - game.player_ready(x_player.id).unwrap(); - game.player_ready(y_player.id).unwrap(); - game = game.resolve_phase_start(); - - // Sleep 0T CD (we use it here) - assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Decay).is_none()); - assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Sleep).is_none()); - - game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Sleep).unwrap(); - game.player_ready(x_player.id).unwrap(); - game.player_ready(y_player.id).unwrap(); - game = game.resolve_phase_start(); - - // Sleep back to 2T CD - assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Decay).is_none()); - assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Sleep).is_some()); - } - } - // #[test] // fn counter_test() { // let mut game = create_test_game(); diff --git a/core/src/item.rs b/core/src/item.rs index 43b2a73e..185b1832 100644 --- a/core/src/item.rs +++ b/core/src/item.rs @@ -716,7 +716,7 @@ impl Item { Item::HealPlusPlus | Item::Triage | Item::TriagePlus | - Item::TriagePlusPlus | + Item::TriagePlusPlus | Item::Break | Item::BreakPlus | Item::BreakPlusPlus | @@ -735,7 +735,7 @@ impl Item { Item::Invert | Item::InvertPlus | Item::InvertPlusPlus | - Item::Decay | + Item::Decay | Item::DecayPlus | Item::DecayPlusPlus | Item::Siphon| @@ -817,7 +817,7 @@ impl Item { Item::AmplifyPlus => vec![Item::Amplify, Item::Amplify], Item::AmplifyPlusPlus => vec![Item::AmplifyPlus, Item::AmplifyPlus], - + Item::HastePlus => vec![Item::Haste, Item::Haste], Item::HastePlusPlus => vec![Item::HastePlus, Item::HastePlus], @@ -832,9 +832,9 @@ impl Item { Item::Curse => vec![Item::Debuff, Item::Red, Item::Blue], Item::Decay => vec![Item::Debuff, Item::Green, Item::Blue], - Item::PurgePlus => vec![Item::Purge, Item::Purge], + Item::PurgePlus => vec![Item::Purge, Item::Purge], Item::PurgePlusPlus => vec![Item::PurgePlus, Item::PurgePlus], - + Item::InvertPlus => vec![Item::Invert, Item::Invert], Item::InvertPlusPlus => vec![Item::InvertPlus, Item::InvertPlus], @@ -843,10 +843,10 @@ impl Item { Item::SilencePlus => vec![Item::Silence, Item::Silence], Item::SilencePlusPlus => vec![Item::SilencePlus, Item::SilencePlus], - + Item::CursePlus => vec![Item::Curse, Item::Curse], Item::CursePlusPlus => vec![Item::CursePlus, Item::CursePlus], - + Item::DecayPlus => vec![Item::Decay, Item::Decay], Item::DecayPlusPlus => vec![Item::DecayPlus, Item::DecayPlus], @@ -1427,20 +1427,13 @@ mod tests { assert_eq!(Item::StrikePlus.components(), vec![ Item::Red, Item::Red, Item::Attack, Item::Red, Item::Red, Item::Attack, - Item::Red, Item::Red, Item::Attack, ]); assert_eq!(Item::StrikePlusPlus.components(), vec![ Item::Red, Item::Red, Item::Attack, Item::Red, Item::Red, Item::Attack, - Item::Red, Item::Red, Item::Attack, Item::Red, Item::Red, Item::Attack, Item::Red, Item::Red, Item::Attack, - Item::Red, Item::Red, Item::Attack, - - Item::Red, Item::Red, Item::Attack, - Item::Red, Item::Red, Item::Attack, - Item::Red, Item::Red, Item::Attack, ]); } diff --git a/core/src/skill.rs b/core/src/skill.rs index 6599ba96..51465b07 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -42,13 +42,6 @@ impl Cast { } pub fn resolve(self, game: &mut Game) { - if !self.skill.aoe() { - if self.skill.cast_animation() { - game.action(self, Action::Cast); - } - game.action(self, Action::Hit); - } - match self.skill { Skill::Attack => attack(self, game, Attack::Base), Skill::Block => block(self, game, Block::Base), From d0dec463e54d2a85d1528be7e747c246f3e80dee Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 19 Dec 2019 14:49:20 +1000 Subject: [PATCH 06/58] fix electrocute --- core/src/skill.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/skill.rs b/core/src/skill.rs index 51465b07..2ef42ba6 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -1681,13 +1681,13 @@ fn electrocute(cast: Cast, game: &mut Game, values: Electrocute) { game.action(cast, Action::Remove { construct: cast.source, - effect: Effect::Electrocute, + effect: Effect::Electric, } ); game.action(cast, Action::Effect { construct: cast.target, - effect: ConstructEffect { effect: Effect::Electric, duration: values.duration(), meta: + effect: ConstructEffect { effect: Effect::Electrocute, duration: values.duration(), meta: Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::ElectrocuteTick, speed: cast.speed, amount }) }, }, ); From 0f7ce528c8d06b74ef2ced507ce97eda581bbe91 Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 19 Dec 2019 14:58:59 +1000 Subject: [PATCH 07/58] fix electrify --- core/src/construct.rs | 2 +- core/src/game.rs | 40 ++++++++++++++++++++++++++++++++++++++++ core/src/skill.rs | 7 +++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/core/src/construct.rs b/core/src/construct.rs index 32579e7b..c24a103f 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -1014,7 +1014,7 @@ impl Construct { match meta { Some(EffectMeta::CastOnHit(skill)) => - casts.push(Cast::new(self.id, self.account, cast.target, *skill)), + casts.push(Cast::new(self.id, self.account, cast.source, *skill)), _ => panic!("no electrify skill {:?}", meta), }; } diff --git a/core/src/game.rs b/core/src/game.rs index 917cec9d..6ce8bdab 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -2168,6 +2168,46 @@ mod tests { })); } + #[test] + fn electrify_test() { + let mut game = create_2v2_test_game(); + let player_id = game.players[0].id; + let source = game.players[0].constructs[0].id; + let target = game.players[1].constructs[0].id; + + game.resolve(Cast::new(source, player_id, target, Skill::Electrify)); + game.resolve(Cast::new(source, player_id, target, Skill::Blast)); + + let last = game.resolutions.len() - 1; + let resolutions = &game.resolutions[last]; + + assert!(resolutions.iter().any(|r| match r.event { + Event::Damage { construct, colour, amount, mitigation: _, display: _ } => + construct == source && amount > 0 && colour == Colour::Blue, + _ => false, + })); + } + + #[test] + fn counter_test() { + let mut game = create_2v2_test_game(); + let player_id = game.players[0].id; + let source = game.players[0].constructs[0].id; + let target = game.players[1].constructs[0].id; + + game.resolve(Cast::new(source, player_id, target, Skill::Counter)); + game.resolve(Cast::new(source, player_id, target, Skill::Strike)); + + let last = game.resolutions.len() - 1; + let resolutions = &game.resolutions[last]; + + assert!(resolutions.iter().any(|r| match r.event { + Event::Damage { construct, colour, amount, mitigation: _, display: _ } => + construct == source && amount > 0 && colour == Colour::Red, + _ => false, + })); + } + #[test] fn absorb_test() { let mut game = create_2v2_test_game(); diff --git a/core/src/skill.rs b/core/src/skill.rs index 2ef42ba6..59588d25 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -1691,6 +1691,13 @@ fn electrocute(cast: Cast, game: &mut Game, values: Electrocute) { Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::ElectrocuteTick, speed: cast.speed, amount }) }, }, ); + game.action(cast, + Action::Damage { + construct: cast.target, + colour: Colour::Blue, + amount, + }, + ); } fn electrocute_tick(cast: Cast, game: &mut Game) { From 77510c1c8f783e4ed1f0458e7c0c7430d1fe2f0e Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 19 Dec 2019 15:05:10 +1000 Subject: [PATCH 08/58] test fixes --- core/src/construct.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/construct.rs b/core/src/construct.rs index 32579e7b..2d3d855a 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -1121,9 +1121,9 @@ mod tests { construct.apply_modifiers(&player_colours); - assert!(construct.red_power.value == construct.red_power.base + construct.red_power.base.pct(35)); - assert!(construct.green_power.value == construct.green_power.base + construct.green_power.base.pct(50)); - assert!(construct.blue_power.value == construct.blue_power.base + construct.blue_power.base.pct(70)); + assert!(construct.red_power.value == construct.red_power.base + construct.red_power.base.pct(15)); + assert!(construct.green_power.value == construct.green_power.base + construct.green_power.base.pct(24)); + assert!(construct.blue_power.value == construct.blue_power.base + construct.blue_power.base.pct(37)); return; } @@ -1172,7 +1172,7 @@ mod tests { let colours = Colours::from_construct(&construct); assert!(colours.red == 4); - assert!(colours.blue == 20); + assert!(colours.blue == 10); assert!(colours.green == 2); } @@ -1193,9 +1193,9 @@ mod tests { construct.apply_modifiers(&player_colours); - assert!(construct.red_power.value == construct.red_power.base + construct.red_power.base.pct(35)); - assert!(construct.green_power.value == construct.green_power.base + construct.green_power.base.pct(25)); - assert!(construct.blue_power.value == construct.blue_power.base + construct.blue_power.base.pct(25)); + assert!(construct.red_power.value == construct.red_power.base + construct.red_power.base.pct(15)); + assert!(construct.green_power.value == construct.green_power.base + construct.green_power.base.pct(10)); + assert!(construct.blue_power.value == construct.blue_power.base + construct.blue_power.base.pct(10)); return; } From a55fd9834ad8e238cbeb8826a10adf7d3f1e44a0 Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 19 Dec 2019 15:35:10 +1000 Subject: [PATCH 09/58] animation construct ko --- client/src/components/game.construct.jsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client/src/components/game.construct.jsx b/client/src/components/game.construct.jsx index 68e53cad..a5c163c2 100644 --- a/client/src/components/game.construct.jsx +++ b/client/src/components/game.construct.jsx @@ -59,11 +59,16 @@ class GameConstruct extends preact.Component { player, } = this.props; - const ko = construct.green_life.value === 0 ? 'ko' : ''; + // construct green_life comes from game state and won't update during animations + // treat the construct as ko for the remainder of the anims if ko event occurs + const ko = construct.green_life.value === 0 || this.ko ? 'ko' : ''; const koEvent = () => { if (resolution) { const [type, variant] = resolution.event; - if (variant.construct === construct.id && type === 'Ko') return 'ko-transition'; + if (variant.construct === construct.id && type === 'Ko') { + this.ko = true; + return 'ko-transition'; + } } return ''; }; From 34b575fefc81d049c5296598321d9b1f895c57fd Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 19 Dec 2019 15:41:03 +1000 Subject: [PATCH 10/58] fix triage --- core/src/construct.rs | 4 +++- core/src/game.rs | 55 ++++++++++++++++++++++++++++++++----------- core/src/skill.rs | 5 +--- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/core/src/construct.rs b/core/src/construct.rs index 1e8b94d6..632f7631 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -495,11 +495,13 @@ impl Construct { self.effects = self.effects.clone().into_iter().filter_map(|mut effect| { effect.duration = effect.duration.saturating_sub(1); + println!("{:?}", effect); + if effect.duration == 0 { return None; } - // info!("reduced effect {:?}", effect); + info!("reduced effect {:?}", effect); return Some(effect); }).collect::>(); diff --git a/core/src/game.rs b/core/src/game.rs index 6ce8bdab..4f41e766 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -135,20 +135,6 @@ impl Game { .unwrap() } - pub fn update_construct(&mut self, construct: &mut Construct) -> &mut Game { - match self.players.iter_mut().find(|t| t.constructs.iter().any(|c| c.id == construct.id)) { - Some(player) => { - let index = player.constructs.iter().position(|t| t.id == construct.id).unwrap(); - player.constructs.remove(index); - player.constructs.push(construct.clone()); - player.constructs.sort_unstable_by_key(|c| c.id); - }, - None => panic!("construct not in game"), - }; - - self - } - pub fn can_start(&self) -> bool { return self.players.len() == self.player_num && self.players.iter().all(|t| t.constructs.len() == self.player_constructs) @@ -441,10 +427,12 @@ impl Game { // temp vec of this round's resolving skills // because need to check cooldown use before pushing them into the complete list let mut r_animation_ms = 0; + println!("{:?}", self.stack); while let Some(cast) = self.stack.pop() { self.new_resolve(cast); }; + println!("processing durations"); self.progress_durations(); // go through the whole most recent round and modify delays of the resolutions @@ -2188,6 +2176,45 @@ mod tests { })); } + #[test] + fn triage_test() { + let mut game = create_2v2_test_game(); + let player_id = game.players[0].id; + let source = game.players[0].constructs[0].id; + let target = game.players[1].constructs[0].id; + + game.resolve(Cast::new(source, player_id, target, Skill::Strike)); + game.resolve(Cast::new(source, player_id, target, Skill::Triage)); + + let last = game.resolutions.len() - 1; + let resolutions = &game.resolutions[last]; + + assert!(resolutions.iter().any(|r| match r.event { + Event::Healing { construct, colour, amount, overhealing: _, display: _ } => + construct == target && amount > 0 && colour == Colour::Green, + _ => false, + })); + + // it's hidden + // assert!(resolutions.iter().any(|r| match r.event { + // Event::Effect { construct, effect, duration: _, display: _ } => + // construct == target && effect == Effect::Triaged, + // _ => false, + // })); + + game.progress_durations(); // pretend it's a new turn + game = game.resolve_phase_start(); + + let last = game.resolutions.len() - 1; + let resolutions = &game.resolutions[last]; + + assert!(resolutions.iter().any(|r| match r.event { + Event::Healing { construct, colour, amount: _, overhealing, display: _ } => + construct == target && overhealing > 0 && colour == Colour::Green, + _ => false, + })); + } + #[test] fn counter_test() { let mut game = create_2v2_test_game(); diff --git a/core/src/skill.rs b/core/src/skill.rs index 59588d25..be9ecc36 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -186,9 +186,6 @@ impl Cast { Skill::TriageTick => triage_tick(self, game), }; - - // actions.append(&mut rest); - // return actions; } } @@ -2208,7 +2205,7 @@ fn triage_tick(cast: Cast, game: &mut Game) { Action::Heal { construct: cast.target, colour: Colour::Green, - amount: game.value(Value::TickDamage { construct: cast.target, effect: Effect::Electrocute }), + amount: game.value(Value::TickDamage { construct: cast.target, effect: Effect::Triage }), } ); game.action(cast, From 4c26f911abbcd8adb126be3917b22cccda3644db Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 19 Dec 2019 16:23:14 +1000 Subject: [PATCH 11/58] move down single hit animation to before cast.resolve() --- core/src/game.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/game.rs b/core/src/game.rs index 4f41e766..5478a47c 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -502,8 +502,6 @@ impl Game { if cast.skill.aoe() { self.action(cast, Action::HitAoe); - } else { - self.action(cast, Action::Hit); } let casts = self.modify_cast(cast); @@ -538,6 +536,11 @@ impl Game { return self.resolve(Cast { target: cast.source, ..cast }); } + if !cast.skill.aoe() { + self.action(cast, Action::Hit); + + } + cast.resolve(self); self From 13b8c5b76695c1dd4bcb2b848a004f004de77cdd Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 19 Dec 2019 16:23:50 +1000 Subject: [PATCH 12/58] ln --- core/src/game.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/game.rs b/core/src/game.rs index 5478a47c..0d346425 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -538,7 +538,6 @@ impl Game { if !cast.skill.aoe() { self.action(cast, Action::Hit); - } cast.resolve(self); From 132d270634f2f0cfe2c5f1c8c4af4a8b41e5cc57 Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 19 Dec 2019 16:28:22 +1000 Subject: [PATCH 13/58] fixme rms --- core/fixme.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/core/fixme.md b/core/fixme.md index 679ae95d..c049e950 100644 --- a/core/fixme.md +++ b/core/fixme.md @@ -1,12 +1,3 @@ # FIXME -check silence skill multiplier game ready not auto starting resolve phase - -cooldowns set after cast -cooldowns reduced after 1 complete cast - -don't focus if ko highlight skills being used -ruin cd -triage 0 heal -effects info \ No newline at end of file From 913b463112fce5a5cb8a2184acf6482cf7015ed4 Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 19 Dec 2019 16:29:01 +1000 Subject: [PATCH 14/58] rm printlns --- core/src/game.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/game.rs b/core/src/game.rs index 0d346425..8a66bc2b 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -427,12 +427,10 @@ impl Game { // temp vec of this round's resolving skills // because need to check cooldown use before pushing them into the complete list let mut r_animation_ms = 0; - println!("{:?}", self.stack); while let Some(cast) = self.stack.pop() { self.new_resolve(cast); }; - println!("processing durations"); self.progress_durations(); // go through the whole most recent round and modify delays of the resolutions From 4fc33eef4b6b94fda165b6f4261ac498b99978fb Mon Sep 17 00:00:00 2001 From: ntr Date: Thu, 19 Dec 2019 16:32:04 +1000 Subject: [PATCH 15/58] fixme rm --- core/fixme.md | 1 - 1 file changed, 1 deletion(-) diff --git a/core/fixme.md b/core/fixme.md index c049e950..c3f3a70d 100644 --- a/core/fixme.md +++ b/core/fixme.md @@ -1,3 +1,2 @@ # FIXME game ready not auto starting resolve phase -highlight skills being used From 89a09e5ebc4dee7d04ee6145ac4b48a01285dedb Mon Sep 17 00:00:00 2001 From: Mashy Date: Thu, 19 Dec 2019 18:18:51 +1000 Subject: [PATCH 16/58] link damage fix + test --- core/fixme.md | 11 ++++-- core/src/construct.rs | 2 +- core/src/game.rs | 92 +++++++++++++++++++------------------------ core/src/skill.rs | 9 ++++- 4 files changed, 55 insertions(+), 59 deletions(-) diff --git a/core/fixme.md b/core/fixme.md index 679ae95d..472e903d 100644 --- a/core/fixme.md +++ b/core/fixme.md @@ -5,8 +5,11 @@ game ready not auto starting resolve phase cooldowns set after cast cooldowns reduced after 1 complete cast -don't focus if ko highlight skills being used -ruin cd -triage 0 heal -effects info \ No newline at end of file + +sleep heal +invert animation - too slow +slay animation still looks a bit weird +electric / electrocute anim order some issue +triaged / decayed / siphoned / electrocute effect removal with purify / purge +inverted green damage ?? diff --git a/core/src/construct.rs b/core/src/construct.rs index 632f7631..1533c618 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -495,7 +495,7 @@ impl Construct { self.effects = self.effects.clone().into_iter().filter_map(|mut effect| { effect.duration = effect.duration.saturating_sub(1); - println!("{:?}", effect); + // println!("{:?}", effect); if effect.duration == 0 { return None; diff --git a/core/src/game.rs b/core/src/game.rs index 0d346425..3757951b 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -427,12 +427,12 @@ impl Game { // temp vec of this round's resolving skills // because need to check cooldown use before pushing them into the complete list let mut r_animation_ms = 0; - println!("{:?}", self.stack); + // println!("{:?}", self.stack); while let Some(cast) = self.stack.pop() { self.new_resolve(cast); }; - println!("processing durations"); + // println!("processing durations"); self.progress_durations(); // go through the whole most recent round and modify delays of the resolutions @@ -1269,6 +1269,7 @@ mod tests { assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Ruin).is_some()); } + // #[cfg(test)] // mod tests { // use skill::*; @@ -1681,56 +1682,6 @@ mod tests { // assert!(game.construct_by_id(y_construct.id).unwrap().affected(Effect::Electrocute)); // } - // // #[test] - // // fn link_test() { - // // let mut game = create_test_game(); - - // // let x_player = game.players[0].clone(); - // // let y_player = game.players[1].clone(); - - // // let x_construct = x_player.constructs[0].clone(); - // // let y_construct = y_player.constructs[0].clone(); - - // // game.construct_by_id(x_construct.id).unwrap().learn_mut(Skill::Link); - - // // while game.construct_by_id(x_construct.id).unwrap().skill_on_cd(Skill::Link).is_some() { - // // game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns(); - // // } - - // // // apply buff - // // game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Link).unwrap(); - // // game.player_ready(x_player.id).unwrap(); - // // game.player_ready(y_player.id).unwrap(); - // // game = game.resolve_phase_start(); - // // assert!(game.construct_by_id(x_construct.id).unwrap().affected(Effect::Link)); - - // // let Resolution { source: _, target: _, Resolution, stages: _ } = game.Resolutions.last.unwrap().pop().unwrap(); - // // match Resolution { - // // Resolution::Effect { effect, skill: _, duration: _, construct_effects: _ } => assert_eq!(effect, Effect::Link), - // // _ => panic!("not siphon"), - // // }; - - // // let Resolution { source: _, target: _, Resolution, stages: _ } = game.Resolutions.last.unwrap().pop().unwrap(); - // // match Resolution { - // // Resolution::Recharge { red: _, blue: _, skill: _ } => (), - // // _ => panic!("link result was not recharge"), - // // } - - // // // attack and receive link hit - // // game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::Attack).unwrap(); - // // game.player_ready(x_player.id).unwrap(); - // // game.player_ready(y_player.id).unwrap(); - // // game = game.resolve_phase_start(); - - // // let Resolution { source: _, target, Resolution, stages: _ } = game.Resolutions.last.unwrap().pop().unwrap(); - // // assert_eq!(target.id, y_construct.id); - // // match Resolution { - // // Resolution::Damage { amount, skill: _, mitigation: _, colour: _} => - // // assert_eq!(amount, x_construct.red_power().pct(Skill::Attack.multiplier()) >> 1), - // // _ => panic!("not damage link"), - // // }; - // // } - // // #[test] // // fn absorb_test() { // // let mut game = create_test_game(); @@ -2091,6 +2042,43 @@ mod tests { })); } + + + #[test] + fn link_test() { + let mut game = create_2v2_test_game(); + let player_id = game.players[0].id; + let source = game.players[0].constructs[0].id; + let target = game.players[1].constructs[0].id; + game.players[1].constructs[0].blue_life.force(0); + + game.new_resolve(Cast::new(source, player_id, target, Skill::Link)); + + let last = game.resolutions.len() - 1; + let resolutions = &game.resolutions[last]; + + assert!(resolutions.iter().any(|r| match r.event { + Event::Damage { construct, colour, amount, mitigation: _, display: _ } => + construct == target && amount == 320.pct(50) && colour == Colour::Blue, + _ => false, + })); + + game = game.resolve_phase_start(); + game.new_resolve(Cast::new(source, player_id, target, Skill::Triage)); + game.new_resolve(Cast::new(source, player_id, target, Skill::Link)); + + let last = game.resolutions.len() - 1; + let resolutions = &game.resolutions[last]; + + assert!(resolutions.iter().any(|r| match r.event { + Event::Damage { construct, colour, amount, mitigation: _, display: _ } => + construct == target && amount == 320.pct(75) && colour == Colour::Blue, + _ => false, + })); + + + } + #[test] fn siphon_test() { let mut game = create_2v2_test_game(); diff --git a/core/src/skill.rs b/core/src/skill.rs index be9ecc36..42cf8dd1 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -1844,11 +1844,16 @@ fn link(cast: Cast, game: &mut Game, values: Link) { effect: ConstructEffect { effect: Effect::Stun, duration: values.duration(), meta: None }, } ); + + let bp = game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.blue_dmg_base()); + let links = game.value(Value::Effects { construct: cast.target }); + let amount = bp.pct(100 + 100usize.saturating_mul(links)); + game.action(cast, Action::Damage { construct: cast.target, colour: Colour::Blue, - amount: game.value(Value::Effects { construct: cast.target }).pct(values.blue_dmg_base()), + amount: amount, }, ); } @@ -2086,7 +2091,7 @@ fn sleep(cast: Cast, game: &mut Game, values: Sleep) { Action::Heal { construct: cast.target, amount: game.value(Value::Stat { construct: cast.source, stat: Stat::GreenPower }).pct(values.green_heal_multi()), - colour: Colour::Blue, + colour: Colour::Green, }, ); } From d307241f7552c04861cbf1bac9264361e7ab4034 Mon Sep 17 00:00:00 2001 From: Mashy Date: Fri, 20 Dec 2019 11:06:33 +1000 Subject: [PATCH 17/58] fix electrocute action order --- core/src/skill.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/core/src/skill.rs b/core/src/skill.rs index 42cf8dd1..0f8c15bd 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -1675,12 +1675,6 @@ impl Electrocute { fn electrocute(cast: Cast, game: &mut Game, values: Electrocute) { let amount = game.value(Value::Stat { construct: cast.source, stat: Stat::BluePower }).pct(values.damage_multiplier()); - game.action(cast, - Action::Remove { - construct: cast.source, - effect: Effect::Electric, - } - ); game.action(cast, Action::Effect { construct: cast.target, @@ -1695,6 +1689,13 @@ fn electrocute(cast: Cast, game: &mut Game, values: Electrocute) { amount, }, ); + + game.action(cast, + Action::Remove { + construct: cast.source, + effect: Effect::Electric, + } + ); } fn electrocute_tick(cast: Cast, game: &mut Game) { @@ -1853,7 +1854,7 @@ fn link(cast: Cast, game: &mut Game, values: Link) { Action::Damage { construct: cast.target, colour: Colour::Blue, - amount: amount, + amount, }, ); } From ecc6eebdbbcd0e11e6cf1575a6a1ab27efbce13a Mon Sep 17 00:00:00 2001 From: Mashy Date: Fri, 20 Dec 2019 11:23:53 +1000 Subject: [PATCH 18/58] only trigger wiggle on damage / ko, fixes wiggle issue also --- client/src/components/construct.jsx | 5 ++++- core/fixme.md | 4 ---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/client/src/components/construct.jsx b/client/src/components/construct.jsx index fba6a9e4..c8ca98a3 100644 --- a/client/src/components/construct.jsx +++ b/client/src/components/construct.jsx @@ -65,7 +65,10 @@ class ConstructAvatar extends Component { const { animSource, animTarget, resolution, construct, account } = this.props; // a different text object and text construct if (resolution && resolution !== prevProps.resolution && resolution.event[1].construct === construct.id) { - return wiggle(construct.id, this.idle); + const type = resolution.event[0]; + // only trigger the wiggle on damage and ko events rather than spam it on everything + // also stops wiggle triggering when invert effect is applied + if (['Damage', 'Ko'].includes(type)) return wiggle(construct.id, this.idle); } // different source object and source construct diff --git a/core/fixme.md b/core/fixme.md index ddced70b..b428dc28 100644 --- a/core/fixme.md +++ b/core/fixme.md @@ -1,9 +1,5 @@ # FIXME game ready not auto starting resolve phase -sleep heal -invert animation - too slow slay animation still looks a bit weird -electric / electrocute anim order some issue triaged / decayed / siphoned / electrocute effect removal with purify / purge -inverted green damage ?? From c9acab9defab7453ce742748e58b929619d04ba9 Mon Sep 17 00:00:00 2001 From: Mashy Date: Fri, 20 Dec 2019 11:42:54 +1000 Subject: [PATCH 19/58] add - for effect removal, anim text clean up --- .../components/game.construct.anim.text.jsx | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/client/src/components/game.construct.anim.text.jsx b/client/src/components/game.construct.anim.text.jsx index 1311d744..8b982cd2 100644 --- a/client/src/components/game.construct.anim.text.jsx +++ b/client/src/components/game.construct.anim.text.jsx @@ -41,36 +41,38 @@ class AnimText extends preact.Component { const generateAnimText = () => { const [type, event] = resolution.event; - if (type === 'Ko') return

KO!

; - if (type === 'Disable') { - const { disable } = event; - return

{disable}

; - } - if (type === 'Immunity') return

IMMUNE

; - if (type === 'Damage') { - const { mitigation, colour } = event; - let { amount } = event; - amount *= -1; + switch (type) { + case 'Damage': { + const { amount, mitigation, colour } = event; const mitigationText = mitigation ? `(${mitigation})` : ''; - return

{amount} {mitigationText}

; + return

-{amount} {mitigationText}

; } - if (type === 'Healing') { + case 'Healing': { const { amount, overhealing, colour } = event; - return

{amount} ({overhealing} OH)

; + const overHealingText = overhealing ? `(${overhealing} OH)` : ''; + return

+{amount} {overHealingText}

; } - if (type === 'Inversion') return

INVERT

; - if (type === 'Reflection') return

REFLECT

; - if (type === 'Effect') { + case 'Effect': { const { effect, duration } = event; return

+{effect} {duration}T

; } - if (type === 'Removal') { + case 'Removal': { const { effect } = event; if (!effect) return

Effect Removal

; - return

{effect}

; + return

-{effect}

; + } + case 'Ko': return

KO!

; + case 'Reflection': return

REFLECT

; + default: return false; } - return false; }; + // We don't send inversion / disable / immune event text + /* case 'Inversion': return

INVERT

; + case 'Disable': { + const { disable } = event; + return

{disable}

; + } + case 'Immunity': return

IMMUNE

; */ return (
From 90a1e9577a085d2fa796a190fa05ccf6ae74d642 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 20 Dec 2019 11:54:12 +1000 Subject: [PATCH 20/58] trim slay anim --- client/src/components/anims/slay.jsx | 91 ++++++++-------------------- 1 file changed, 25 insertions(+), 66 deletions(-) diff --git a/client/src/components/anims/slay.jsx b/client/src/components/anims/slay.jsx index 079c2058..a136d5a2 100644 --- a/client/src/components/anims/slay.jsx +++ b/client/src/components/anims/slay.jsx @@ -1,34 +1,17 @@ const preact = require('preact'); const { Component } = require('preact'); const anime = require('animejs').default; +const times = require('lodash/times'); const { TIMES } = require('../../constants'); -function projectile(x, y, radius, colour) { - return ( - - ); -} - -function sword(colour) { - return ( - - ); -} +const GREEN = '#1FF01F'; +const RED = '#a52a2a'; class Slay extends Component { constructor() { super(); this.animations = []; - this.colour = '#a52a2a'; - const points = new Array(30).fill(0); - this.charges = points.map(() => projectile(150, 420, 7, '#1FF01F')); } render() { @@ -39,13 +22,16 @@ class Slay extends Component { id="slay" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300"> - - - - - - {sword(this.colour)} - {this.charges} + {times(10, () => ( + + ))} ); } @@ -67,58 +53,31 @@ class Slay extends Component { rotate, }); - anime.set('#slay', { - translateY: -1 * (window.innerHeight) * 0.35, - translateX: 0, - }); - - anime.set('#slayFilter feDisplacementMap', { - scale: 0, - }); - - anime.set('#sword', { - fill: this.colour, - opacity: 1, - }); + anime.set('#slay ellipse',{ + fill: RED, + }) this.animations.push(anime({ targets: '#slay', opacity: [ { value: 1, duration: TIMES.TARGET_DURATION_MS * 0.2 }, - { value: 0, delay: TIMES.TARGET_DURATION_MS * 0.6, duration: TIMES.TARGET_DURATION_MS * 0.2 }, ], - translateY: 0, - translateX: 0, - loop: false, easing: 'easeInQuad', })); this.animations.push(anime({ - targets: ['#slayFilter feTurbulence', '#slayFilter feDisplacementMap'], - baseFrequency: 10, - scale: 100, - delay: TIMES.TARGET_DURATION_MS * 0.6, + targets: ['#slay ellipse'], + cx: 150, + cy: 325, + delay: TIMES.TARGET_DURATION_MS * 0.2, duration: TIMES.TARGET_DURATION_MS * 0.3, - easing: 'easeInQuad', + easing: 'easeOutQuad', + direction: 'alternate', })); - this.animations.push(anime({ - targets: '#sword', - opacity: 0, - delay: TIMES.TARGET_DURATION_MS * 0.9, - })); - - const projectiles = document.querySelectorAll('#slay circle'); - projectiles.forEach(proj => { - this.animations.push(anime({ - targets: proj, - cx: Math.random() * 250 + 25, - cy: Math.random() * 200 - 100, - delay: TIMES.TARGET_DURATION_MS * 0.7, - duration: TIMES.TARGET_DURATION_MS * 0.3, - easing: 'easeInQuad', - })); - }); + setTimeout(() => anime.set('#slay ellipse',{ + fill: GREEN, + }), TIMES.TARGET_DURATION_MS * 0.5); } componentWillUnmount() { From 86b0ba7f17653ff7e1c948290d0b01146731dd6f Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 20 Dec 2019 12:02:07 +1000 Subject: [PATCH 21/58] remove demo --- client/assets/styles/menu.less | 56 --------- client/src/actions.jsx | 2 - client/src/components/demo.jsx | 190 ------------------------------ client/src/components/welcome.jsx | 11 +- client/src/events.jsx | 89 -------------- client/src/reducers.jsx | 2 - client/src/socket.jsx | 5 - server/src/pg.rs | 20 ---- server/src/rpc.rs | 4 - 9 files changed, 1 insertion(+), 378 deletions(-) delete mode 100644 client/src/components/demo.jsx diff --git a/client/assets/styles/menu.less b/client/assets/styles/menu.less index e197781e..e52249d0 100644 --- a/client/assets/styles/menu.less +++ b/client/assets/styles/menu.less @@ -174,59 +174,3 @@ section { } } -.demo { - margin-top: 1em; - - display: block; - - button { - pointer-events: none; - } - - section { - margin-bottom: 0.5em; - - div:first-child { - padding-right: 1em; - } - } - - .construct-section { - .construct-list { - height: 25em; - grid-area: unset; - - .instance-construct { - // border: 0; - } - } - } - - .colour-info { - grid-area: vinfo; - display: flex; - align-items: center; - - div { - display: flex; - } - - svg { - flex: 1; - height: 1em; - } - } - - .game-demo { - .game { - height: 25em; - display: flex; - flex-flow: column; - - .game-construct { - flex: 1; - } - } - } -} - diff --git a/client/src/actions.jsx b/client/src/actions.jsx index e99bba62..311d444b 100644 --- a/client/src/actions.jsx +++ b/client/src/actions.jsx @@ -7,8 +7,6 @@ export const setAnimSource = value => ({ type: 'SET_ANIM_SOURCE', value }); export const setAnimTarget = value => ({ type: 'SET_ANIM_TARGET', value }); export const setResolution = value => ({ type: 'SET_RESOLUTION', value }); -export const setDemo = value => ({ type: 'SET_DEMO', value }); - export const setChatShow = value => ({ type: 'SET_CHAT_SHOW', value }); export const setChatWheel = value => ({ type: 'SET_CHAT_WHEEL', value }); export const setInstanceChat = value => ({ type: 'SET_INSTANCE_CHAT', value }); diff --git a/client/src/components/demo.jsx b/client/src/components/demo.jsx deleted file mode 100644 index e6bee9eb..00000000 --- a/client/src/components/demo.jsx +++ /dev/null @@ -1,190 +0,0 @@ -const { connect } = require('preact-redux'); -const preact = require('preact'); - -// const actions = require('../actions'); -const shapes = require('./shapes'); - -const { ConstructAvatar } = require('./construct'); -// const { ConstructAnimation } = require('./animations'); - -const addState = connect( - function receiveState(state) { - const { - account, - itemInfo, - demo, - } = state; - - return { - account, - itemInfo, - demo, - }; - } - -/* function receiveDispatch(dispatch) { - function setAnimTarget(anim) { - dispatch(actions.setAnimTarget(anim)); - } - - return { setAnimTarget }; - } */ -); - - -function Demo(args) { - const { - demo, - itemInfo, - account, - - // setAnimTarget, - } = args; - - if (!demo || !itemInfo.items.length || account) return false; - - const { combiner, items, equipping, equipped, players, combo } = demo; - - const vboxDemo = () => { - function stashBtn(i, j) { - if (!i) return ; - const highlighted = combiner.indexOf(j) > -1; - const classes = `${highlighted ? 'highlight' : ''}`; - - if (shapes[i]) { - return ; - } - - return ; - } - - function combinerBtn() { - let text = ''; - - if (combiner.length < 3) { - for (let i = 0; i < 3; i++) { - if (combiner.length > i) { - text += '■ '; - } else { - text += '▫ '; - } - } - } else { - text = 'combine'; - } - - return ( - - ); - } - - function stashElement() { - return ( -
-
-

- VBOX PHASE {shapes.Red()} {shapes.Green()} {shapes.Blue()} -

-

- Combine colours with base skills and specialisations to build an array of powerful variants. -

-
-
 
-
-
- {items.map((i, j) => stashBtn(i, j))} -
- {combinerBtn()} -
-
- ); - } - - return ( -
- {stashElement()} -
- ); - }; - - const vboxConstructs = () => { - const btnClass = equipping - ? 'equipping empty gray' - : 'empty gray'; - - const constructEl = c => ( -
-

{c.name}

- -
- {equipped - ? - : - } - - -
-
-
-
-
-
- ); - - return ( -
-
-

CONSTRUCTS

-

Constructs are the units you control. They are reset every game and their initial appearance is randomly generated.

-

Skills and Specs you create in the VBOX Phase are equipped to your constructs to create a build.

-
-
- {constructEl(players[0].constructs[0])} -
-
- ); - }; - - const gameDemo = () => { - return ( -
-
-

COMBAT PHASE

-

Battle your opponent using dynamic team builds from the VBOX phase.

-

The skills crafted can be used to damage the opponent or support your team.

-

Simultaneous turn based combat: each team picks targets for their skills during this phase.

-

The damage dealt by skills, cast order and construct life depend on your decisions in the VBOX phase.

-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
- ); - }; - - return ( -
- {gameDemo()} - {vboxDemo()} - {vboxConstructs()} -
- ); -} - -module.exports = addState(Demo); diff --git a/client/src/components/welcome.jsx b/client/src/components/welcome.jsx index 2a1bfa67..3cb0824d 100644 --- a/client/src/components/welcome.jsx +++ b/client/src/components/welcome.jsx @@ -5,7 +5,6 @@ const Login = require('./welcome.login'); const Register = require('./welcome.register'); const Help = require('./welcome.help'); // const About = require('./welcome.about'); -const Demo = require('./demo'); function Welcome() { const page = this.state.page || 'register'; @@ -33,9 +32,7 @@ function Welcome() {
); - const main = (['login', 'register', 'help'].includes(page)) - ?
{news}{pageEl()}
- : ; + const main =
{news}{pageEl()}
; return (
@@ -58,12 +55,6 @@ function Welcome() { onClick={() => this.setState({ page: 'register' })}> Register - '; - toast.error({ - theme: 'dark', - color: 'black', - timeout: false, - drag: false, - position: 'center', - maxWidth: window.innerWidth / 2, - close: false, - buttons: [ - [OK_BUTTON, (instance, thisToast) => instance.hide({ transitionOut: 'fadeOut' }, thisToast)], - ], - message, - }); - } */ - // setup / localstorage - function urlHashChange() { const { ws } = store.getState(); const cmds = querystring.parse(location.hash); @@ -317,7 +229,6 @@ function registerEvents(store) { setActiveItem, setActiveSkill, setChatWheel, - setDemo, setConstructList, setNewConstruct, setGame, diff --git a/client/src/reducers.jsx b/client/src/reducers.jsx index 36a81eea..9edeeae6 100644 --- a/client/src/reducers.jsx +++ b/client/src/reducers.jsx @@ -20,8 +20,6 @@ module.exports = { resolution: createReducer(null, 'SET_RESOLUTION'), - demo: createReducer(null, 'SET_DEMO'), - chatShow: createReducer(null, 'SET_CHAT_SHOW'), chatWheel: createReducer([], 'SET_CHAT_WHEEL'), diff --git a/client/src/socket.jsx b/client/src/socket.jsx index 210a0700..bacf0870 100644 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -256,10 +256,6 @@ function createSocket(events) { events.setItemInfo(info); } - function onDemo(v) { - events.setDemo(v); - } - let pongTimeout; function onPong() { events.setPing(Date.now() - ping); @@ -285,7 +281,6 @@ function createSocket(events) { InstanceState: onInstanceState, ItemInfo: onItemInfo, Pong: onPong, - Demo: onDemo, // QueueRequested: () => events.notify('PVP queue request received.'), QueueRequested: () => true, diff --git a/server/src/pg.rs b/server/src/pg.rs index 7a9f9495..0c815c9a 100644 --- a/server/src/pg.rs +++ b/server/src/pg.rs @@ -804,26 +804,6 @@ pub fn bot_instance() -> Instance { return instance; } -pub fn demo() -> Result, Error> { - let bot = bot_player(); - - // generate bot imgs for the client to see - for c in bot.constructs.iter() { - img::shapes_write(c.img)?; - }; - - let bot2 = bot_player(); - - // generate bot imgs for the client to see - for c in bot2.constructs.iter() { - img::shapes_write(c.img)?; - }; - - - Ok(vec![bot, bot2]) -} - - pub fn vbox_refill(tx: &mut Transaction, account: &Account, instance_id: Uuid) -> Result { let instance = instance_get(tx, instance_id)? .vbox_refill(account.id)?; diff --git a/server/src/rpc.rs b/server/src/rpc.rs index 9fd4e824..1cbcddfb 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -73,8 +73,6 @@ pub enum RpcMessage { AccountInstances(Vec), AccountShop(mtx::Shop), - Demo(Vec), - ConstructSpawn(Construct), GameState(Game), ItemInfo(ItemInfoCtr), @@ -391,8 +389,6 @@ impl Handler for Connection { // tx should do nothing tx.commit().unwrap(); - } else { - self.send(RpcMessage::Demo(demo().unwrap())).unwrap(); } Ok(()) From 267a4ef7427afa8e9454b0db343206332b2f3e93 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 20 Dec 2019 12:02:07 +1000 Subject: [PATCH 22/58] remove demo --- client/assets/styles/menu.less | 56 --------- client/src/actions.jsx | 2 - client/src/components/demo.jsx | 190 ------------------------------ client/src/components/welcome.jsx | 11 +- client/src/events.jsx | 89 -------------- client/src/reducers.jsx | 2 - client/src/socket.jsx | 5 - server/src/pg.rs | 20 ---- server/src/rpc.rs | 6 - 9 files changed, 1 insertion(+), 380 deletions(-) delete mode 100644 client/src/components/demo.jsx diff --git a/client/assets/styles/menu.less b/client/assets/styles/menu.less index e197781e..e52249d0 100644 --- a/client/assets/styles/menu.less +++ b/client/assets/styles/menu.less @@ -174,59 +174,3 @@ section { } } -.demo { - margin-top: 1em; - - display: block; - - button { - pointer-events: none; - } - - section { - margin-bottom: 0.5em; - - div:first-child { - padding-right: 1em; - } - } - - .construct-section { - .construct-list { - height: 25em; - grid-area: unset; - - .instance-construct { - // border: 0; - } - } - } - - .colour-info { - grid-area: vinfo; - display: flex; - align-items: center; - - div { - display: flex; - } - - svg { - flex: 1; - height: 1em; - } - } - - .game-demo { - .game { - height: 25em; - display: flex; - flex-flow: column; - - .game-construct { - flex: 1; - } - } - } -} - diff --git a/client/src/actions.jsx b/client/src/actions.jsx index e99bba62..311d444b 100644 --- a/client/src/actions.jsx +++ b/client/src/actions.jsx @@ -7,8 +7,6 @@ export const setAnimSource = value => ({ type: 'SET_ANIM_SOURCE', value }); export const setAnimTarget = value => ({ type: 'SET_ANIM_TARGET', value }); export const setResolution = value => ({ type: 'SET_RESOLUTION', value }); -export const setDemo = value => ({ type: 'SET_DEMO', value }); - export const setChatShow = value => ({ type: 'SET_CHAT_SHOW', value }); export const setChatWheel = value => ({ type: 'SET_CHAT_WHEEL', value }); export const setInstanceChat = value => ({ type: 'SET_INSTANCE_CHAT', value }); diff --git a/client/src/components/demo.jsx b/client/src/components/demo.jsx deleted file mode 100644 index e6bee9eb..00000000 --- a/client/src/components/demo.jsx +++ /dev/null @@ -1,190 +0,0 @@ -const { connect } = require('preact-redux'); -const preact = require('preact'); - -// const actions = require('../actions'); -const shapes = require('./shapes'); - -const { ConstructAvatar } = require('./construct'); -// const { ConstructAnimation } = require('./animations'); - -const addState = connect( - function receiveState(state) { - const { - account, - itemInfo, - demo, - } = state; - - return { - account, - itemInfo, - demo, - }; - } - -/* function receiveDispatch(dispatch) { - function setAnimTarget(anim) { - dispatch(actions.setAnimTarget(anim)); - } - - return { setAnimTarget }; - } */ -); - - -function Demo(args) { - const { - demo, - itemInfo, - account, - - // setAnimTarget, - } = args; - - if (!demo || !itemInfo.items.length || account) return false; - - const { combiner, items, equipping, equipped, players, combo } = demo; - - const vboxDemo = () => { - function stashBtn(i, j) { - if (!i) return ; - const highlighted = combiner.indexOf(j) > -1; - const classes = `${highlighted ? 'highlight' : ''}`; - - if (shapes[i]) { - return ; - } - - return ; - } - - function combinerBtn() { - let text = ''; - - if (combiner.length < 3) { - for (let i = 0; i < 3; i++) { - if (combiner.length > i) { - text += '■ '; - } else { - text += '▫ '; - } - } - } else { - text = 'combine'; - } - - return ( - - ); - } - - function stashElement() { - return ( -
-
-

- VBOX PHASE {shapes.Red()} {shapes.Green()} {shapes.Blue()} -

-

- Combine colours with base skills and specialisations to build an array of powerful variants. -

-
-
 
-
-
- {items.map((i, j) => stashBtn(i, j))} -
- {combinerBtn()} -
-
- ); - } - - return ( -
- {stashElement()} -
- ); - }; - - const vboxConstructs = () => { - const btnClass = equipping - ? 'equipping empty gray' - : 'empty gray'; - - const constructEl = c => ( -
-

{c.name}

- -
- {equipped - ? - : - } - - -
-
-
-
-
-
- ); - - return ( -
-
-

CONSTRUCTS

-

Constructs are the units you control. They are reset every game and their initial appearance is randomly generated.

-

Skills and Specs you create in the VBOX Phase are equipped to your constructs to create a build.

-
-
- {constructEl(players[0].constructs[0])} -
-
- ); - }; - - const gameDemo = () => { - return ( -
-
-

COMBAT PHASE

-

Battle your opponent using dynamic team builds from the VBOX phase.

-

The skills crafted can be used to damage the opponent or support your team.

-

Simultaneous turn based combat: each team picks targets for their skills during this phase.

-

The damage dealt by skills, cast order and construct life depend on your decisions in the VBOX phase.

-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
- ); - }; - - return ( -
- {gameDemo()} - {vboxDemo()} - {vboxConstructs()} -
- ); -} - -module.exports = addState(Demo); diff --git a/client/src/components/welcome.jsx b/client/src/components/welcome.jsx index 2a1bfa67..3cb0824d 100644 --- a/client/src/components/welcome.jsx +++ b/client/src/components/welcome.jsx @@ -5,7 +5,6 @@ const Login = require('./welcome.login'); const Register = require('./welcome.register'); const Help = require('./welcome.help'); // const About = require('./welcome.about'); -const Demo = require('./demo'); function Welcome() { const page = this.state.page || 'register'; @@ -33,9 +32,7 @@ function Welcome() { ); - const main = (['login', 'register', 'help'].includes(page)) - ?
{news}{pageEl()}
- : ; + const main =
{news}{pageEl()}
; return (
@@ -58,12 +55,6 @@ function Welcome() { onClick={() => this.setState({ page: 'register' })}> Register - '; - toast.error({ - theme: 'dark', - color: 'black', - timeout: false, - drag: false, - position: 'center', - maxWidth: window.innerWidth / 2, - close: false, - buttons: [ - [OK_BUTTON, (instance, thisToast) => instance.hide({ transitionOut: 'fadeOut' }, thisToast)], - ], - message, - }); - } */ - // setup / localstorage - function urlHashChange() { const { ws } = store.getState(); const cmds = querystring.parse(location.hash); @@ -317,7 +229,6 @@ function registerEvents(store) { setActiveItem, setActiveSkill, setChatWheel, - setDemo, setConstructList, setNewConstruct, setGame, diff --git a/client/src/reducers.jsx b/client/src/reducers.jsx index 36a81eea..9edeeae6 100644 --- a/client/src/reducers.jsx +++ b/client/src/reducers.jsx @@ -20,8 +20,6 @@ module.exports = { resolution: createReducer(null, 'SET_RESOLUTION'), - demo: createReducer(null, 'SET_DEMO'), - chatShow: createReducer(null, 'SET_CHAT_SHOW'), chatWheel: createReducer([], 'SET_CHAT_WHEEL'), diff --git a/client/src/socket.jsx b/client/src/socket.jsx index 210a0700..bacf0870 100644 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -256,10 +256,6 @@ function createSocket(events) { events.setItemInfo(info); } - function onDemo(v) { - events.setDemo(v); - } - let pongTimeout; function onPong() { events.setPing(Date.now() - ping); @@ -285,7 +281,6 @@ function createSocket(events) { InstanceState: onInstanceState, ItemInfo: onItemInfo, Pong: onPong, - Demo: onDemo, // QueueRequested: () => events.notify('PVP queue request received.'), QueueRequested: () => true, diff --git a/server/src/pg.rs b/server/src/pg.rs index 7a9f9495..0c815c9a 100644 --- a/server/src/pg.rs +++ b/server/src/pg.rs @@ -804,26 +804,6 @@ pub fn bot_instance() -> Instance { return instance; } -pub fn demo() -> Result, Error> { - let bot = bot_player(); - - // generate bot imgs for the client to see - for c in bot.constructs.iter() { - img::shapes_write(c.img)?; - }; - - let bot2 = bot_player(); - - // generate bot imgs for the client to see - for c in bot2.constructs.iter() { - img::shapes_write(c.img)?; - }; - - - Ok(vec![bot, bot2]) -} - - pub fn vbox_refill(tx: &mut Transaction, account: &Account, instance_id: Uuid) -> Result { let instance = instance_get(tx, instance_id)? .vbox_refill(account.id)?; diff --git a/server/src/rpc.rs b/server/src/rpc.rs index 9fd4e824..fea26385 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -23,7 +23,6 @@ use ws::{Builder, CloseCode, Message, Handler, Request, Response, Settings, Send use ws::deflate::DeflateHandler; use pg::{ - demo, game_concede, game_offer_draw, game_ready, @@ -48,7 +47,6 @@ use events::{Event}; use mnml_core::construct::{Construct}; use mnml_core::game::{Game}; -use mnml_core::player::Player; use mnml_core::vbox::{ItemType}; use mnml_core::item::Item; @@ -73,8 +71,6 @@ pub enum RpcMessage { AccountInstances(Vec), AccountShop(mtx::Shop), - Demo(Vec), - ConstructSpawn(Construct), GameState(Game), ItemInfo(ItemInfoCtr), @@ -391,8 +387,6 @@ impl Handler for Connection { // tx should do nothing tx.commit().unwrap(); - } else { - self.send(RpcMessage::Demo(demo().unwrap())).unwrap(); } Ok(()) From 550e1123ad0cf5a850e199bd9da2da9b209c4b23 Mon Sep 17 00:00:00 2001 From: Mashy Date: Fri, 20 Dec 2019 12:12:19 +1000 Subject: [PATCH 23/58] cast event for single target fix --- core/src/game.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/src/game.rs b/core/src/game.rs index 0d4a358f..a729d4d0 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -494,11 +494,10 @@ impl Game { self.resolve(Cast { skill, ..cast }); } - if cast.skill.cast_animation() { - self.action(cast, Action::Cast); - } - if cast.skill.aoe() { + if cast.skill.cast_animation() { + self.action(cast, Action::Cast); + } self.action(cast, Action::HitAoe); } @@ -521,6 +520,11 @@ impl Game { return self; } + // For normal skills we show the cast as long as the target isn't ko + if !cast.skill.aoe() && cast.skill.cast_animation() { + self.action(cast, Action::Cast); + } + // maybe this should be done with a status immunity if self.construct(cast.target).affected(Effect::Reflect) && cast.skill.colours().contains(&Colour::Blue) && !cast.skill.is_tick() { self.add_resolution(&cast, &Event::Reflection { construct: cast.target }); @@ -534,9 +538,7 @@ impl Game { return self.resolve(Cast { target: cast.source, ..cast }); } - if !cast.skill.aoe() { - self.action(cast, Action::Hit); - } + self.action(cast, Action::Hit); cast.resolve(self); From 443b3bb3ace7d057f4261de061a009f50be0ee41 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 20 Dec 2019 12:59:10 +1000 Subject: [PATCH 24/58] hide hidden effects in removal --- core/fixme.md | 2 -- core/src/construct.rs | 17 +++++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/core/fixme.md b/core/fixme.md index b428dc28..8264dee4 100644 --- a/core/fixme.md +++ b/core/fixme.md @@ -1,5 +1,3 @@ # FIXME game ready not auto starting resolve phase - -slay animation still looks a bit weird triaged / decayed / siphoned / electrocute effect removal with purify / purge diff --git a/core/src/construct.rs b/core/src/construct.rs index 1533c618..70cf308c 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -950,7 +950,10 @@ impl Construct { if self.is_ko() { return vec![Event::TargetKo { construct: self.id }] } if let Some(p) = self.effects.iter().position(|ce| ce.effect == effect) { - self.effects.remove(p); + let ce = self.effects.remove(p); + + if ce.effect.hidden() { return vec![] } + return vec![Event::Removal { construct: self.id, effect: effect, @@ -986,11 +989,13 @@ impl Construct { if self.is_ko() { return vec![Event::TargetKo { construct: self.id }] } while let Some(ce) = self.effects.pop() { - removals.push(Event::Removal { - construct: self.id, - effect: ce.effect, - display: EventConstruct::new(self), - }); + if !ce.effect.hidden() { + removals.push(Event::Removal { + construct: self.id, + effect: ce.effect, + display: EventConstruct::new(self), + }); + } } return removals; From 69c964510c0cdc181298e51a08642d6d6f0c5d4a Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 20 Dec 2019 13:11:44 +1000 Subject: [PATCH 25/58] always go to logrocket --- client/src/app.jsx | 4 ++++ client/src/events.jsx | 11 +++++------ core/fixme.md | 1 - 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/client/src/app.jsx b/client/src/app.jsx index 1599c1ab..47a08e62 100644 --- a/client/src/app.jsx +++ b/client/src/app.jsx @@ -33,6 +33,10 @@ const ws = createSocket(events); ws.connect(); events.setWs(ws); +if (process.env.NODE_ENV !== 'development') { + LogRocket.init('yh0dy3/mnml'); +} + const App = () => ( {window.Stripe diff --git a/client/src/events.jsx b/client/src/events.jsx index ead1e49c..fa048f29 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -106,13 +106,12 @@ function registerEvents(store) { } function setAccount(account) { - if (account && process.env.NODE_ENV !== 'development') { - LogRocket.init('yh0dy3/mnml'); - LogRocket.identify(account.id, account); + if (account && window.Notification) { + window.Notification.requestPermission(); + } - if (window.Notification) { - window.Notification.requestPermission(); - } + if (process.env.NODE_ENV !== 'development') { + LogRocket.identify(account.id, account); } store.dispatch(actions.setAccount(account)); diff --git a/core/fixme.md b/core/fixme.md index 8264dee4..c3f3a70d 100644 --- a/core/fixme.md +++ b/core/fixme.md @@ -1,3 +1,2 @@ # FIXME game ready not auto starting resolve phase -triaged / decayed / siphoned / electrocute effect removal with purify / purge From b36b9553d06f739d30e2609feb13a663ae621fee Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 20 Dec 2019 13:15:40 +1000 Subject: [PATCH 26/58] cannot clear skills while ready --- core/src/game.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/game.rs b/core/src/game.rs index a729d4d0..de968301 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -336,7 +336,11 @@ impl Game { pub fn clear_skill(&mut self, player_id: Uuid) -> Result<&mut Game, Error> { - self.player_by_id(player_id)?; + let player = self.player_by_id(player_id)?; + if player.ready { + return Err(err_msg("cannot clear skills while ready")); + } + if self.phase != Phase::Skill { return Err(err_msg("game not in skill phase")); } @@ -2058,7 +2062,7 @@ mod tests { let resolutions = &game.resolutions[last]; assert!(resolutions.iter().any(|r| match r.event { - Event::Damage { construct, colour, amount, mitigation: _, display: _ } => + Event::Damage { construct, colour, amount, mitigation: _, display: _ } => construct == target && amount == 320.pct(50) && colour == Colour::Blue, _ => false, })); From 3503c4b864ca6037c8c54b6edf1442c140b5b609 Mon Sep 17 00:00:00 2001 From: Mashy Date: Fri, 20 Dec 2019 13:39:20 +1000 Subject: [PATCH 27/58] castable logic --- core/src/game.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/core/src/game.rs b/core/src/game.rs index a729d4d0..50f16861 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -494,14 +494,19 @@ impl Game { self.resolve(Cast { skill, ..cast }); } - if cast.skill.aoe() { - if cast.skill.cast_animation() { - self.action(cast, Action::Cast); + let casts = self.modify_cast(cast); + + let castable = casts.clone() + .into_iter() + .any(|c| !self.construct(c.target).is_ko() && !self.construct(c.target).immune(c.skill).is_some()); + + if castable { + self.action(cast, Action::Cast); + if cast.skill.aoe() { + self.action(cast, Action::HitAoe); } - self.action(cast, Action::HitAoe); } - let casts = self.modify_cast(cast); for cast in casts { self.execute(cast); } @@ -520,11 +525,6 @@ impl Game { return self; } - // For normal skills we show the cast as long as the target isn't ko - if !cast.skill.aoe() && cast.skill.cast_animation() { - self.action(cast, Action::Cast); - } - // maybe this should be done with a status immunity if self.construct(cast.target).affected(Effect::Reflect) && cast.skill.colours().contains(&Colour::Blue) && !cast.skill.is_tick() { self.add_resolution(&cast, &Event::Reflection { construct: cast.target }); @@ -538,7 +538,9 @@ impl Game { return self.resolve(Cast { target: cast.source, ..cast }); } - self.action(cast, Action::Hit); + if !cast.skill.aoe() { + self.action(cast, Action::Hit); + } cast.resolve(self); From 8830378b2248cb1a05d2a7620cac039b0c3f5ad0 Mon Sep 17 00:00:00 2001 From: Mashy Date: Fri, 20 Dec 2019 15:32:24 +1000 Subject: [PATCH 28/58] siphon test apply new effect --- core/src/game.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/src/game.rs b/core/src/game.rs index c7069753..194a26b8 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -2121,6 +2121,9 @@ mod tests { // que ota? game.resolve(Cast::new(source, player_id, target, Skill::Siphon)); + game.resolve(Cast::new(source, player_id, target, Skill::Siphon)); + game.resolve(Cast::new(source, player_id, target, Skill::Siphon)); + let last = game.resolutions.len() - 1; let resolutions = &game.resolutions[last]; @@ -2129,7 +2132,18 @@ mod tests { _ => false, }).count(); + let effect_events = resolutions.iter().filter(|r| match r.event { + Event::Effect { construct, effect, duration: _, display: _ } => + construct == target && effect == Effect::Siphon, + _ => false, + }).count(); + + // Deal siphon dmg once assert_eq!(damage_events, 1); + // 3 new applications of siphon + assert_eq!(effect_events, 3); + // Siphon + Siphoned + assert!(game.players[1].constructs[0].effects.len() == 2); } #[test] From 5c3a318882efbb4843f4e28ef320f40597fb3795 Mon Sep 17 00:00:00 2001 From: Mashy Date: Fri, 20 Dec 2019 15:39:20 +1000 Subject: [PATCH 29/58] dot speeds are still 0 --- core/src/game.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/game.rs b/core/src/game.rs index 194a26b8..59a83d52 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -2432,6 +2432,8 @@ mod tests { }) .unwrap(); + assert!(siphon_tick_speed > 0); + assert!(siphon_speed > 0); assert_eq!(siphon_tick_dmg, siphon_dmg); assert_eq!(siphon_tick_speed, siphon_speed); } From 44089724ae0a565d56df002e5bf8e0acb281a3b1 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 20 Dec 2019 17:16:48 +1000 Subject: [PATCH 30/58] disable wiggle onclick during animation --- client/src/components/construct.jsx | 5 +++-- core/src/skill.rs | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/client/src/components/construct.jsx b/client/src/components/construct.jsx index c8ca98a3..ec3d7813 100644 --- a/client/src/components/construct.jsx +++ b/client/src/components/construct.jsx @@ -13,8 +13,8 @@ const { ConstructAnimation } = require('./animations'); const addState = connect( function receiveState(state) { - const { animSource, animTarget, resolution, account } = state; - return { animSource, animTarget, resolution, account }; + const { animating, animSource, animTarget, resolution, account } = state; + return { animating, animSource, animTarget, resolution, account }; } ); @@ -43,6 +43,7 @@ class ConstructAvatar extends Component { } onClick() { + if (this.props.animating) return false; return this.animations.push(wiggle(this.props.construct.id, this.idle)); } diff --git a/core/src/skill.rs b/core/src/skill.rs index 0f8c15bd..9d4d3902 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -637,6 +637,9 @@ impl Skill { Skill::Heal | Skill::HealPlus | Skill::HealPlusPlus | + Skill::Hybrid | + Skill::HybridPlus | + Skill::HybridPlusPlus | Skill::Absorb | Skill::AbsorbPlus | Skill::AbsorbPlusPlus | From 5058277776fd28b79b9ec44257a68cc6c7296467 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 20 Dec 2019 17:23:55 +1000 Subject: [PATCH 31/58] increase slay anim circle size --- client/src/components/anims/slay.jsx | 4 ++-- client/src/components/anims/strike.jsx | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/components/anims/slay.jsx b/client/src/components/anims/slay.jsx index a136d5a2..063b7053 100644 --- a/client/src/components/anims/slay.jsx +++ b/client/src/components/anims/slay.jsx @@ -27,8 +27,8 @@ class Slay extends Component { cx={anime.random(100, 200)} cy={anime.random(-50, -25)} stroke="none" - rx={anime.random(3, 7)} - ry={7} + rx={anime.random(5, 10)} + ry={10} fill={RED} /> ))} diff --git a/client/src/components/anims/strike.jsx b/client/src/components/anims/strike.jsx index b6d129fb..f280e86d 100644 --- a/client/src/components/anims/strike.jsx +++ b/client/src/components/anims/strike.jsx @@ -40,6 +40,7 @@ class Strike extends Component { height: [200, 10, 0], width: [20, 400, 0], duration: TIMES.TARGET_DURATION_MS, + delay: TIMES.TARGET_DURATION_MS * 0.2, })); this.animations.push(anime({ From 1cc29f73d1fc875440d879076534813ee66481ca Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 20 Dec 2019 17:26:31 +1000 Subject: [PATCH 32/58] more tweaks --- client/src/components/anims/slay.jsx | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/client/src/components/anims/slay.jsx b/client/src/components/anims/slay.jsx index 063b7053..8be04e0c 100644 --- a/client/src/components/anims/slay.jsx +++ b/client/src/components/anims/slay.jsx @@ -25,7 +25,7 @@ class Slay extends Component { {times(10, () => ( Date: Sun, 22 Dec 2019 12:40:05 +1000 Subject: [PATCH 33/58] wip --- core/src/instance.rs | 2 +- core/src/mob.rs | 5 + server/src/account.rs | 10 + server/src/events.rs | 58 ++---- server/src/lib.rs | 2 + server/src/pg.rs | 31 +++- server/src/rpc.rs | 307 ++++--------------------------- server/src/user_anonymous.rs | 148 +++++++++++++++ server/src/user_authenticated.rs | 264 ++++++++++++++++++++++++++ 9 files changed, 512 insertions(+), 315 deletions(-) create mode 100644 server/src/user_anonymous.rs create mode 100644 server/src/user_authenticated.rs diff --git a/core/src/instance.rs b/core/src/instance.rs index 27d09bc0..3c7f8b0f 100644 --- a/core/src/instance.rs +++ b/core/src/instance.rs @@ -144,8 +144,8 @@ impl Instance { .collect::>() } + // time out lobbies that have been open too long pub fn upkeep(mut self) -> (Instance, Option) { - // time out lobbies that have been open too long if self.phase == InstancePhase::Lobby && self.phase_timed_out() { self.finish(); return (self, None); diff --git a/core/src/mob.rs b/core/src/mob.rs index 479acb43..5d774c13 100644 --- a/core/src/mob.rs +++ b/core/src/mob.rs @@ -31,6 +31,11 @@ pub fn bot_player() -> Player { Player::new(bot_id, None, &name(), constructs).set_bot(true) } +pub fn anon_player(id: Uuid) -> Player { + let constructs = instance_mobs(id); + Player::new(id, None, &"player".to_string(), constructs) +} + pub fn anim_test_game(skill: Skill) -> Game { let mut rng = thread_rng(); let mut game = Game::new(); diff --git a/server/src/account.rs b/server/src/account.rs index 7373d0f6..a162a22c 100644 --- a/server/src/account.rs +++ b/server/src/account.rs @@ -44,6 +44,16 @@ impl Account { Ok(Player::new(self.id, Some(self.img), &self.name, constructs)) } + + pub fn anonymous() -> Account { + Account { + id: Uuid::new_v4(), + img: Uuid::new_v4(), + name: "you".to_string(), + balance: 0, + subscribed: false, + } + } } impl<'a> TryFrom> for Account { diff --git a/server/src/events.rs b/server/src/events.rs index 0a347868..fab2bfca 100644 --- a/server/src/events.rs +++ b/server/src/events.rs @@ -18,7 +18,7 @@ use warden::{GameEvent}; use mail::Mail; pub type EventsTx = Sender; -type Id = usize; +type Id = Uuid; // this is pretty heavyweight // but it makes the ergonomics easy @@ -43,7 +43,7 @@ pub struct Events { #[derive(Debug,Clone)] pub enum Event { // ws lifecycle - Connect(Id, Option, Sender), + Connect(Id, Account, Sender), Disconnect(Id), Subscribe(Id, Uuid), Unsubscribe(Id, Uuid), @@ -64,7 +64,6 @@ pub enum Event { struct WsClient { id: Id, - account: Option, tx: Sender, subs: HashSet, chat: Option<(Uuid, String)>, @@ -118,14 +117,8 @@ impl Events { Event::Connect(id, account, tx) => { info!("connect id={:?} account={:?}", id, account); - let account_id = match account { - Some(a) => Some(a.id), - None => None, - }; - let client = WsClient { id, tx, - account: account_id, subs: HashSet::new(), pvp: false, invite: None, @@ -183,13 +176,10 @@ impl Events { if client.subs.contains(&id) { subs += 1; - let redacted = match client.account { - Some(a) => match msg { - RpcMessage::InstanceState(ref i) => RpcMessage::InstanceState(i.clone().redact(a)), - RpcMessage::GameState(ref i) => RpcMessage::GameState(i.clone().redact(a)), - _ => msg.clone(), - } - None => msg.clone(), + let redacted = match msg { + RpcMessage::InstanceState(ref i) => RpcMessage::InstanceState(i.clone().redact(client.id)), + RpcMessage::GameState(ref i) => RpcMessage::GameState(i.clone().redact(client.id)), + _ => msg.clone(), }; match client.tx.send(redacted) { @@ -218,18 +208,14 @@ impl Events { let c = self.clients.get(&id) .ok_or(format_err!("connection not found id={:?}", id))?; - if let None = c.account { - return Err(err_msg("cannot join pvp queue anonymously")); - } - - info!("pvp queue request id={:?} account={:?}", c.id, c.account); + info!("pvp queue request id={:?} account={:?}", c.id, c.id); } // create the req for the already queued opponent if let Some(opp_req) = match self.clients.iter_mut().find(|(c_id, c)| c.pvp && **c_id != id) { Some((q_id, q)) => { q.pvp = false; - Some(PvpRequest { id: *q_id, account: q.account.unwrap(), tx: q.tx.clone() }) + Some(PvpRequest { id: *q_id, account: q.id, tx: q.tx.clone() }) }, None => None, } { @@ -237,7 +223,7 @@ impl Events { let c = self.clients.get_mut(&id) .ok_or(format_err!("connection not found id={:?}", id))?; - let player_req = PvpRequest { id: c.id, account: c.account.unwrap(), tx: c.tx.clone() }; + let player_req = PvpRequest { id: c.id, account: c.id, tx: c.tx.clone() }; self.warden.send(GameEvent::Match((opp_req, player_req)))?; return Ok(()) @@ -247,7 +233,7 @@ impl Events { let requester = self.clients.get_mut(&id).unwrap(); requester.pvp = true; requester.tx.send(RpcMessage::QueueJoined(()))?; - info!("joined game queue id={:?} account={:?}", requester.id, requester.account); + info!("joined game queue id={:?} account={:?}", requester.id, requester.id); return Ok(()); }, @@ -256,12 +242,8 @@ impl Events { let c = self.clients.get_mut(&id) .ok_or(format_err!("connection not found id={:?}", id))?; - if let None = c.account { - return Err(err_msg("cannot join pvp queue anonymously")); - } - let code = names::name().split_whitespace().collect::>().join("-"); - info!("pvp invite request id={:?} account={:?} code={:?}", c.id, c.account, code); + info!("pvp invite request id={:?} account={:?} code={:?}", c.id, c.id, code); c.invite = Some(code.clone()); c.tx.send(RpcMessage::Invite(code))?; return Ok(()); @@ -272,11 +254,7 @@ impl Events { let c = self.clients.get(&id) .ok_or(format_err!("connection not found id={:?}", id))?; - if let None = c.account { - return Err(err_msg("cannot join pvp queue anonymously")); - } - - info!("pvp join request id={:?} account={:?} code={:?}", c.id, c.account, code); + info!("pvp join request id={:?} account={:?} code={:?}", c.id, c.id, code); let inv = self.clients.iter() .filter(|(_id, c)| c.invite.is_some()) @@ -284,10 +262,10 @@ impl Events { Some(ref c) => *c == code, None => false, }) - .map(|(_id, c)| PvpRequest { id: c.id, account: c.account.unwrap(), tx: c.tx.clone() }) + .map(|(_id, c)| PvpRequest { id: c.id, account: c.id, tx: c.tx.clone() }) .ok_or(format_err!("invite expired code={:?}", code))?; - let join = PvpRequest { id: c.id, account: c.account.unwrap(), tx: c.tx.clone() }; + let join = PvpRequest { id: c.id, account: c.id, tx: c.tx.clone() }; self.warden.send(GameEvent::Match((join, inv)))?; return Ok(()); @@ -310,7 +288,7 @@ impl Events { c.pvp = false; c.tx.send(RpcMessage::QueueLeft(()))?; - info!("left game queue id={:?} account={:?}", c.id, c.account); + info!("left game queue id={:?} account={:?}", c.id, c.id); return Ok(()); }, @@ -337,12 +315,11 @@ impl Events { // now collect all listeners of this instance let chat_state: HashMap = self.clients.iter() - .filter(|(_id, c)| c.account.is_some()) .filter(|(_id, c)| match c.chat { Some(ref chat) => chat.0 == instance, None => false, }) - .map(|(_id, c)| (c.account.unwrap(), c.chat.clone().unwrap().1)) + .map(|(_id, c)| (c.id, c.chat.clone().unwrap().1)) .collect(); return self.event(Event::Push(instance, RpcMessage::InstanceChat(chat_state))); @@ -357,12 +334,11 @@ impl Events { } let chat_state: HashMap = self.clients.iter() - .filter(|(_id, c)| c.account.is_some()) .filter(|(_id, c)| match c.chat { Some(ref chat) => chat.0 == instance, None => false, }) - .map(|(_id, c)| (c.account.unwrap(), c.chat.clone().unwrap().1)) + .map(|(_id, c)| (c.id, c.chat.clone().unwrap().1)) .collect(); return self.event(Event::Push(instance, RpcMessage::InstanceChat(chat_state))); diff --git a/server/src/lib.rs b/server/src/lib.rs index 66efa49d..26fa9e31 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -48,6 +48,8 @@ mod pg; mod events; pub mod rpc; mod warden; +mod user_authenticated; +mod user_anonymous; use std::thread::{spawn}; use std::path::{Path}; diff --git a/server/src/pg.rs b/server/src/pg.rs index 0c815c9a..ec56a9be 100644 --- a/server/src/pg.rs +++ b/server/src/pg.rs @@ -22,7 +22,7 @@ use mnml_core::mob::instance_mobs; use mnml_core::vbox::{ItemType, VboxIndices}; use mnml_core::item::Item; use mnml_core::skill::Skill; -use mnml_core::mob::bot_player; +use mnml_core::mob::{bot_player, anon_player}; use mnml_core::instance::{Instance, TimeControl}; use events::{Event}; @@ -694,6 +694,35 @@ pub fn instance_practice(tx: &mut Transaction, account: &Account) -> Result Result { + let bot = bot_player(); + let bot_id = bot.id; + + // generate imgs for the client to see + for c in bot.constructs.iter() { + img::shapes_write(c.img)?; + } + + let mut instance = Instance::new() + .set_time_control(TimeControl::Practice) + .set_name(bot.name.clone())?; + + let player = anon_player(account.id); + + for c in player.constructs.iter() { + img::shapes_write(c.img)?; + } + + instance.add_player(player.clone())?; + instance.add_player(bot)?; + + instance.player_ready(bot_id)?; + // skip faceoff + instance.player_ready(player.id)?; + + Ok(instance) +} + pub fn pvp(tx: &mut Transaction, a: &Account, b: &Account) -> Result { let mut instance = Instance::new() // TODO generate nice game names diff --git a/server/src/rpc.rs b/server/src/rpc.rs index fea26385..ff755767 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -1,6 +1,6 @@ use mnml_core::item::ItemInfoCtr; use mnml_core::instance::ChatState; -use mnml_core::item::item_info; + use std::collections::HashMap; use std::time::{Instant}; use std::thread::{spawn}; @@ -8,12 +8,8 @@ use std::thread::{spawn}; use std::str; use uuid::Uuid; -use rand::prelude::*; - use failure::Error; -use failure::err_msg; - -use serde_cbor::{from_slice, to_vec}; +use serde_cbor::{to_vec}; use cookie::Cookie; use stripe::{Client as StripeClient, Subscription}; @@ -22,42 +18,24 @@ use crossbeam_channel::{unbounded, Sender as CbSender}; use ws::{Builder, CloseCode, Message, Handler, Request, Response, Settings, Sender as WsSender}; use ws::deflate::DeflateHandler; -use pg::{ - game_concede, - game_offer_draw, - game_ready, - game_skill, - game_skill_clear, - game_state, - instance_abandon, - instance_practice, - instance_ready, - instance_state, - vbox_apply, - vbox_buy, - vbox_combine, - vbox_refill, - vbox_refund, - vbox_unequip, -}; - use account::{Account}; use account; use events::{Event}; +use user_anonymous::{Anonymous}; +use user_authenticated::{Authorised}; + use mnml_core::construct::{Construct}; use mnml_core::game::{Game}; use mnml_core::vbox::{ItemType}; use mnml_core::item::Item; use mnml_core::skill::Skill; -use mnml_core::mob::{anim_test_game}; + use mnml_core::instance::{Instance}; use mtx; -use mail; -use payments; use mail::Email; use pg::{Db}; use pg::{PgPool}; @@ -145,194 +123,32 @@ pub enum RpcRequest { VboxRefund { instance_id: Uuid, index: String }, } +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>; +} + struct Connection { - pub id: usize, + pub id: Uuid, pub ws: CbSender, pool: PgPool, stripe: StripeClient, - account: Option, + // account: Option, + user: Box, events: CbSender, } impl Connection { - fn receive(&self, data: Vec, db: &Db, begin: Instant) -> Result { - // cast the msg to this type to receive method name - match from_slice::(&data) { - Ok(v) => { - - // non authenticated - // non transactional reqs - match v { - RpcRequest::Ping {} => return Ok(RpcMessage::Pong(())), - RpcRequest::ItemInfo {} => return Ok(RpcMessage::ItemInfo(item_info())), - RpcRequest::DevResolve { skill } => - return Ok(RpcMessage::GameState(anim_test_game(skill))), - _ => (), - }; - - // check for authorization now - let account = match self.account { - Some(ref account) => account, - None => return Err(err_msg("auth required")), - }; - - let request = v.clone(); - - let response = match v { - // evented but authorization required - RpcRequest::InstanceQueue {} => { - self.events.send(Event::Queue(self.id))?; - Ok(RpcMessage::QueueRequested(())) - }, - RpcRequest::InstanceInvite {} => { - self.events.send(Event::Invite(self.id))?; - Ok(RpcMessage::InviteRequested(())) - }, - RpcRequest::InstanceJoin { code } => { - self.events.send(Event::Join(self.id, code))?; - Ok(RpcMessage::Joining(())) - }, - RpcRequest::InstanceLeave {} => { - self.events.send(Event::Leave(self.id))?; - Ok(RpcMessage::Processing(())) - }, - - RpcRequest::InstanceChat { instance_id, index } => { - if !account.subscribed { - return Err(err_msg("subscribe to unlock chat")) - } - - let wheel = account::chat_wheel(&db, account.id)?; - - if let Some(c) = wheel.get(index) { - self.events.send(Event::Chat(self.id, instance_id, c.to_string()))?; - } else { - return Err(err_msg("invalid chat index")); - } - - Ok(RpcMessage::Processing(())) - }, - _ => { - // all good, let's make a tx and process - let mut tx = db.transaction()?; - - let res = match v { - RpcRequest::AccountState {} => - Ok(RpcMessage::AccountState(account.clone())), - RpcRequest::AccountConstructs {} => - Ok(RpcMessage::AccountConstructs(account::constructs(&mut tx, &account)?)), - RpcRequest::AccountInstances {} => - Ok(RpcMessage::AccountInstances(account::account_instances(&mut tx, account)?)), - RpcRequest::AccountSetTeam { ids } => - Ok(RpcMessage::AccountTeam(account::set_team(&mut tx, &account, ids)?)), - - RpcRequest::EmailState {} => - Ok(RpcMessage::EmailState(mail::select_account(&db, account.id)?)), - - RpcRequest::SubscriptionState {} => - Ok(RpcMessage::SubscriptionState(payments::account_subscription(&db, &self.stripe, &account)?)), - - // RpcRequest::AccountShop {} => - // Ok(RpcMessage::AccountShop(mtx::account_shop(&mut tx, &account)?)), - - // RpcRequest::ConstructDelete" => handle_construct_delete(data, &mut tx, account), - - RpcRequest::GameState { id } => - Ok(RpcMessage::GameState(game_state(&mut tx, account, id)?)), - - RpcRequest::GameSkill { game_id, construct_id, target_construct_id, skill } => - Ok(RpcMessage::GameState(game_skill(&mut tx, account, game_id, construct_id, target_construct_id, skill)?)), - - RpcRequest::GameSkillClear { game_id } => - Ok(RpcMessage::GameState(game_skill_clear(&mut tx, account, game_id)?)), - - RpcRequest::GameReady { id } => - Ok(RpcMessage::GameState(game_ready(&mut tx, account, id)?)), - - RpcRequest::GameConcede { game_id } => - Ok(RpcMessage::GameState(game_concede(&mut tx, account, game_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)?)), - - // these two can return GameState or InstanceState - RpcRequest::InstanceReady { instance_id } => - Ok(instance_ready(&mut tx, account, instance_id)?), - RpcRequest::InstanceState { instance_id } => - Ok(instance_state(&mut tx, instance_id)?), - RpcRequest::InstanceAbandon { instance_id } => - Ok(instance_abandon(&mut tx, account, instance_id)?), - - RpcRequest::VboxBuy { instance_id, group, index, construct_id } => - Ok(RpcMessage::InstanceState(vbox_buy(&mut tx, account, instance_id, group, index, construct_id)?)), - - RpcRequest::VboxApply { instance_id, construct_id, index } => - Ok(RpcMessage::InstanceState(vbox_apply(&mut tx, account, instance_id, construct_id, index)?)), - - RpcRequest::VboxCombine { instance_id, inv_indices, vbox_indices } => - Ok(RpcMessage::InstanceState(vbox_combine(&mut tx, account, instance_id, inv_indices, vbox_indices)?)), - - RpcRequest::VboxRefill { instance_id } => - Ok(RpcMessage::InstanceState(vbox_refill(&mut tx, account, instance_id)?)), - - RpcRequest::VboxRefund { instance_id, index } => - Ok(RpcMessage::InstanceState(vbox_refund(&mut tx, account, instance_id, index)?)), - - RpcRequest::VboxUnequip { instance_id, construct_id, target } => - Ok(RpcMessage::InstanceState(vbox_unequip(&mut tx, account, instance_id, construct_id, target, None)?)), - - RpcRequest::VboxUnequipApply { instance_id, construct_id, target, target_construct_id } => - Ok(RpcMessage::InstanceState(vbox_unequip(&mut tx, account, instance_id, construct_id, target, Some(target_construct_id))?)), - - RpcRequest::MtxConstructSpawn {} => - Ok(RpcMessage::ConstructSpawn(mtx::new_construct(&mut tx, account)?)), - - RpcRequest::MtxConstructApply { mtx, construct_id, name } => - Ok(RpcMessage::AccountTeam(mtx::apply(&mut tx, account, mtx, construct_id, name)?)), - - RpcRequest::MtxAccountApply { mtx } => - Ok(RpcMessage::AccountState(mtx::account_apply(&mut tx, account, mtx)?)), - - RpcRequest::MtxBuy { mtx } => - Ok(RpcMessage::AccountShop(mtx::buy(&mut tx, account, mtx)?)), - - RpcRequest::SubscriptionEnding { ending } => - Ok(RpcMessage::SubscriptionState(payments::subscription_ending(&mut tx, &self.stripe, account, ending)?)), - - _ => Err(format_err!("unknown request request={:?}", request)), - }; - - tx.commit()?; - res - } - }; - - info!("request={:?} account={:?} duration={:?}", request, account.name, begin.elapsed()); - - return response; - }, - Err(e) => { - warn!("{:?}", e); - Err(err_msg("invalid message")) - }, - } - } - // this is where last minute processing happens // use it to modify outgoing messages, update subs, serialize in some way... fn send(&self, msg: RpcMessage) -> Result<(), Error> { - let msg = match self.account { - Some(ref a) => match msg { - RpcMessage::InstanceState(v) => RpcMessage::InstanceState(v.redact(a.id)), - RpcMessage::AccountInstances(v) => - RpcMessage::AccountInstances(v.into_iter().map(|i| i.redact(a.id)).collect()), - RpcMessage::GameState(v) => RpcMessage::GameState(v.redact(a.id)), - _ => msg, - }, - None => msg, + let msg = match msg { + RpcMessage::InstanceState(v) => RpcMessage::InstanceState(v.redact(self.id)), + RpcMessage::AccountInstances(v) => + RpcMessage::AccountInstances(v.into_iter().map(|i| i.redact(self.id)).collect()), + RpcMessage::GameState(v) => RpcMessage::GameState(v.redact(self.id)), + _ => msg, }; self.ws.send(msg).unwrap(); @@ -347,48 +163,8 @@ impl Connection { // when it encounters errors impl Handler for Connection { fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> { - info!("websocket connected account={:?}", self.account); - - // tell events we have connected - self.events.send(Event::Connect(self.id, self.account.clone(), self.ws.clone())).unwrap(); - - // if user logged in do some prep work - if let Some(ref a) = self.account { - self.send(RpcMessage::AccountState(a.clone())).unwrap(); - self.events.send(Event::Subscribe(self.id, a.id)).unwrap(); - - // check if they have an image that needs to be generated - account::img_check(&a).unwrap(); - - let db = self.pool.get().unwrap(); - let mut tx = db.transaction().unwrap(); - - // send account constructs - let account_constructs = account::constructs(&mut tx, a).unwrap(); - self.send(RpcMessage::AccountConstructs(account_constructs)).unwrap(); - - // get account instances - // and send them to the client - let account_instances = account::account_instances(&mut tx, a).unwrap(); - self.send(RpcMessage::AccountInstances(account_instances)).unwrap(); - - let shop = mtx::account_shop(&mut tx, &a).unwrap(); - self.send(RpcMessage::AccountShop(shop)).unwrap(); - - let team = account::team(&mut tx, &a).unwrap(); - self.send(RpcMessage::AccountTeam(team)).unwrap(); - - let wheel = account::chat_wheel(&db, a.id).unwrap(); - self.send(RpcMessage::ChatWheel(wheel)).unwrap(); - - if let Some(instance) = account::tutorial(&mut tx, &a).unwrap() { - self.send(RpcMessage::InstanceState(instance)).unwrap(); - } - - // tx should do nothing - tx.commit().unwrap(); - } - + let db = self.pool.get().unwrap(); + self.user.connected(&db, &self.events, &self.ws).unwrap(); Ok(()) } @@ -398,23 +174,9 @@ impl Handler for Connection { let begin = Instant::now(); let db_connection = self.pool.get().unwrap(); - match self.receive(msg, &db_connection, begin) { - Ok(reply) => { - // if the user queries the state of something - // we tell events to push updates to them - match reply { - RpcMessage::AccountState(ref v) => { - self.account = Some(v.clone()); - self.events.send(Event::Subscribe(self.id, v.id)).unwrap() - }, - RpcMessage::GameState(ref v) => - self.events.send(Event::Subscribe(self.id, v.id)).unwrap(), - RpcMessage::InstanceState(ref v) => - self.events.send(Event::Subscribe(self.id, v.id)).unwrap(), - _ => (), - }; - - self.send(reply).unwrap(); + match self.user.receive(msg, &db_connection, begin, &self.events, &self.stripe) { + Ok(msg) => { + self.user.send(msg, &self.events, &self.ws).unwrap(); }, Err(e) => { warn!("{:?}", e); @@ -428,7 +190,7 @@ impl Handler for Connection { } fn on_close(&mut self, _: CloseCode, _: &str) { - info!("websocket disconnected account={:?}", self.account); + info!("websocket disconnected id={:?}", self.id); self.events.send(Event::Disconnect(self.id)).unwrap(); } @@ -456,21 +218,19 @@ 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.account = Some(a), + Ok(a) => self.user = Box::new(Authorised { id: a.id, account: a }), Err(_) => return unauth(), } } }; - }; + } Ok(res) } } pub fn start(pool: PgPool, events_tx: CbSender, stripe: StripeClient) { - let mut rng = thread_rng(); - - let ws = Builder::new() + let _ws = Builder::new() .with_settings(Settings { max_connections: 10_000, ..Settings::default() @@ -500,14 +260,17 @@ pub fn start(pool: PgPool, events_tx: CbSender, stripe: StripeClient) { } }); + let anon_account = Account::anonymous(); + let id = anon_account.id; + DeflateHandler::new( Connection { - id: rng.gen::(), - account: None, + id, ws: tx, pool: pool.clone(), stripe: stripe.clone(), events: events_tx.clone(), + user: Box::new(Anonymous { id, account: anon_account, game: None, instance: None }) } ) }) diff --git a/server/src/user_anonymous.rs b/server/src/user_anonymous.rs new file mode 100644 index 00000000..51bd4a4a --- /dev/null +++ b/server/src/user_anonymous.rs @@ -0,0 +1,148 @@ +use std::time::Instant; +use uuid::Uuid; + +use failure::Error; +use failure::err_msg; + +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; +use mnml_core::item::item_info; +use mnml_core::instance::Instance; + +#[derive(Debug,Clone)] +pub struct Anonymous { + pub account: Account, + pub id: Uuid, + pub instance: Option, + pub game: Option, +} + +impl User for Anonymous { + fn send(&mut self, msg: RpcMessage, _events: &CbSender, ws: &CbSender) -> Result<(), Error> { + // if the user queries the state of something + // we tell events to push updates to them + match msg { + RpcMessage::GameState(ref v) => + self.game = Some(v.clone()), + RpcMessage::InstanceState(ref v) => + self.instance = Some(v.clone()), + _ => (), + }; + + ws.send(msg)?; + + Ok(()) + } + + fn connected(&mut self, _db: &Db, events: &CbSender, ws: &CbSender) -> Result<(), Error> { + info!("anonymous connection"); + + self.send(RpcMessage::AccountState(self.account.clone()), events, ws)?; + self.send(RpcMessage::ItemInfo(item_info()), events, ws)?; + self.send(RpcMessage::InstanceState(pg::instance_demo(&self.account)?), events, ws)?; + + Ok(()) + } + + fn receive(&mut self, data: Vec, _db: &Db, _begin: Instant, _events: &CbSender, _stripe: &StripeClient) -> Result { + match from_slice::(&data) { + Ok(v) => { + let mut instance = match self.instance { + Some(ref i) => i.clone(), + None => return Err(err_msg("instance missing")), + }; + + let game = match self.game { + Some(ref i) => Some(i.clone()), + None => None + }; + + match v { + RpcRequest::Ping {} => return Ok(RpcMessage::Pong(())), + + RpcRequest::InstanceReady { instance_id: _ } => { + match instance.player_ready(self.account.id)? { + Some(g) => Ok(RpcMessage::GameState(g)), + None => Ok(RpcMessage::InstanceState(instance)), + } + }, + + RpcRequest::InstanceState { instance_id: _ } => + Ok(RpcMessage::InstanceState(instance)), + + RpcRequest::InstanceAbandon { instance_id: _ } => + Err(err_msg("don't give up!")), + + RpcRequest::VboxBuy { instance_id: _, group, index, construct_id } => + Ok(RpcMessage::InstanceState(instance.vbox_buy(self.account.id, group, index, construct_id)?)), + + RpcRequest::VboxApply { instance_id: _, construct_id, index } => + Ok(RpcMessage::InstanceState(instance.vbox_apply(self.account.id, index, construct_id)?)), + + RpcRequest::VboxCombine { instance_id: _, inv_indices, vbox_indices } => + Ok(RpcMessage::InstanceState(instance.vbox_combine(self.account.id, inv_indices, vbox_indices)?)), + + RpcRequest::VboxRefill { instance_id: _ } => + Ok(RpcMessage::InstanceState(instance.vbox_refill(self.account.id)?)), + + RpcRequest::VboxRefund { instance_id: _, index } => + Ok(RpcMessage::InstanceState(instance.vbox_refund(self.account.id, index)?)), + + RpcRequest::VboxUnequip { instance_id: _, construct_id, target } => + Ok(RpcMessage::InstanceState(instance.vbox_unequip(self.account.id, target, construct_id, None)?)), + + RpcRequest::VboxUnequipApply { instance_id: _, construct_id, target, target_construct_id } => + Ok(RpcMessage::InstanceState(instance.vbox_unequip(self.account.id, target, construct_id, Some(target_construct_id))?)), + + RpcRequest::GameState { id: _ } => + Ok(RpcMessage::GameState(game.unwrap())), + + RpcRequest::GameSkill { game_id: _, construct_id, target_construct_id, skill } => { + let mut game = game.unwrap(); + game.add_skill(self.account.id, construct_id, target_construct_id, skill)?; + Ok(RpcMessage::GameState(game)) + }, + + RpcRequest::GameSkillClear { game_id: _ } => { + let mut game = game.unwrap(); + game.clear_skill(self.account.id)?; + Ok(RpcMessage::GameState(game)) + }, + + RpcRequest::GameReady { id: _ } => { + let mut game = game.unwrap(); + game.player_ready(self.account.id)?; + if game.skill_phase_finished() { + game = game.resolve_phase_start(); + } + + Ok(RpcMessage::GameState(game)) + }, + + RpcRequest::GameConcede { game_id: _ } => + Ok(RpcMessage::GameState(game.unwrap().concede(self.account.id)?)), + + RpcRequest::GameOfferDraw { game_id: _ } => + Ok(RpcMessage::GameState(game.unwrap().offer_draw(self.account.id)?)), + + _ => Err(format_err!("unhandled anonymous request request={:?}", v)), + } + }, + Err(e) => { + warn!("{:?}", e); + Err(err_msg("invalid message")) + }, + } + } +} diff --git a/server/src/user_authenticated.rs b/server/src/user_authenticated.rs new file mode 100644 index 00000000..c92400a3 --- /dev/null +++ b/server/src/user_authenticated.rs @@ -0,0 +1,264 @@ +use mnml_core::mob::anim_test_game; +use mnml_core::item::item_info; +use std::time::Instant; +use uuid::Uuid; + +use failure::Error; +use failure::err_msg; + +use crossbeam_channel::{Sender as CbSender}; +use stripe::{Client as StripeClient}; + +use serde_cbor::{from_slice}; + +use pg::{ + game_concede, + game_offer_draw, + game_ready, + game_skill, + game_skill_clear, + game_state, + instance_abandon, + instance_practice, + instance_ready, + instance_state, + vbox_apply, + vbox_buy, + vbox_combine, + vbox_refill, + vbox_refund, + vbox_unequip, +}; + +use account::{Account}; +use account; +use events::{Event}; + +use mtx; +use mail; +use payments; +use pg::{Db}; +use rpc::{RpcMessage, RpcRequest, User}; + + +#[derive(Debug,Clone)] +pub struct Authorised { + pub account: Account, + pub id: Uuid +} + +impl User for Authorised { + fn send(&mut self, msg: RpcMessage, events: &CbSender, ws: &CbSender) -> 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))? + }, + RpcMessage::GameState(ref v) => + events.send(Event::Subscribe(self.id, v.id))?, + RpcMessage::InstanceState(ref v) => + events.send(Event::Subscribe(self.id, v.id))?, + _ => (), + }; + + ws.send(msg)?; + + Ok(()) + } + + fn connected(&mut self, db: &Db, events: &CbSender, ws: &CbSender) -> Result<(), Error> { + info!("authenticated connection account={:?}", self.account); + let a = &self.account; + + // tell events we have connected + events.send(Event::Connect(self.id, a.clone(), ws.clone()))?; + + ws.send(RpcMessage::AccountState(a.clone()))?; + events.send(Event::Subscribe(self.id, a.id))?; + + // check if they have an image that needs to be generated + account::img_check(&a)?; + + let mut tx = db.transaction()?; + + // send account constructs + let account_constructs = account::constructs(&mut tx, &a)?; + 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))?; + + let shop = mtx::account_shop(&mut tx, &a)?; + ws.send(RpcMessage::AccountShop(shop))?; + + let team = account::team(&mut tx, &a)?; + ws.send(RpcMessage::AccountTeam(team))?; + + let wheel = account::chat_wheel(&db, a.id)?; + ws.send(RpcMessage::ChatWheel(wheel))?; + + if let Some(instance) = account::tutorial(&mut tx, &a)? { + ws.send(RpcMessage::InstanceState(instance))?; + } + + // tx should do nothing + tx.commit()?; + + Ok(()) + } + + fn receive(&mut self, data: Vec, db: &Db, begin: Instant, events: &CbSender, stripe: &StripeClient) -> Result { + // cast the msg to this type to receive method name + match from_slice::(&data) { + Ok(v) => { + let request = v.clone(); + let response = match v { + RpcRequest::Ping {} => return Ok(RpcMessage::Pong(())), + RpcRequest::ItemInfo {} => return Ok(RpcMessage::ItemInfo(item_info())), + RpcRequest::DevResolve { skill } => + return Ok(RpcMessage::GameState(anim_test_game(skill))), + + RpcRequest::InstanceQueue {} => { + events.send(Event::Queue(self.id))?; + Ok(RpcMessage::QueueRequested(())) + }, + RpcRequest::InstanceInvite {} => { + events.send(Event::Invite(self.id))?; + Ok(RpcMessage::InviteRequested(())) + }, + RpcRequest::InstanceJoin { code } => { + events.send(Event::Join(self.id, code))?; + Ok(RpcMessage::Joining(())) + }, + RpcRequest::InstanceLeave {} => { + events.send(Event::Leave(self.id))?; + Ok(RpcMessage::Processing(())) + }, + + RpcRequest::InstanceChat { instance_id, index } => { + if !self.account.subscribed { + return Err(err_msg("subscribe to unlock chat")) + } + + 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()))?; + } else { + return Err(err_msg("invalid chat index")); + } + + Ok(RpcMessage::Processing(())) + }, + _ => { + // all good, let's make a tx and process + let mut tx = db.transaction()?; + + let res = match v { + RpcRequest::AccountState {} => + Ok(RpcMessage::AccountState(self.account.clone())), + RpcRequest::AccountConstructs {} => + Ok(RpcMessage::AccountConstructs(account::constructs(&mut tx, &self.account)?)), + RpcRequest::AccountInstances {} => + Ok(RpcMessage::AccountInstances(account::account_instances(&mut tx, &self.account)?)), + RpcRequest::AccountSetTeam { ids } => + Ok(RpcMessage::AccountTeam(account::set_team(&mut tx, &self.account, ids)?)), + + RpcRequest::EmailState {} => + Ok(RpcMessage::EmailState(mail::select_account(&db, self.account.id)?)), + + RpcRequest::SubscriptionState {} => + Ok(RpcMessage::SubscriptionState(payments::account_subscription(db, stripe, &self.account)?)), + + // RpcRequest::AccountShop {} => + // Ok(RpcMessage::AccountShop(mtx::account_shop(&mut tx, &account)?)), + + // RpcRequest::ConstructDelete" => handle_construct_delete(data, &mut tx, account), + + RpcRequest::GameState { id } => + Ok(RpcMessage::GameState(game_state(&mut tx, &self.account, id)?)), + + RpcRequest::GameSkill { game_id, construct_id, target_construct_id, skill } => + Ok(RpcMessage::GameState(game_skill(&mut tx, &self.account, game_id, construct_id, target_construct_id, skill)?)), + + RpcRequest::GameSkillClear { game_id } => + Ok(RpcMessage::GameState(game_skill_clear(&mut tx, &self.account, game_id)?)), + + RpcRequest::GameReady { id } => + Ok(RpcMessage::GameState(game_ready(&mut tx, &self.account, id)?)), + + RpcRequest::GameConcede { game_id } => + Ok(RpcMessage::GameState(game_concede(&mut tx, &self.account, game_id)?)), + + RpcRequest::GameOfferDraw { game_id } => + Ok(RpcMessage::GameState(game_offer_draw(&mut tx, &self.account, game_id)?)), + + RpcRequest::InstancePractice {} => + Ok(RpcMessage::InstanceState(instance_practice(&mut tx, &self.account)?)), + + // these two can return GameState or InstanceState + RpcRequest::InstanceReady { instance_id } => + Ok(instance_ready(&mut tx, &self.account, instance_id)?), + RpcRequest::InstanceState { instance_id } => + Ok(instance_state(&mut tx, instance_id)?), + RpcRequest::InstanceAbandon { instance_id } => + Ok(instance_abandon(&mut tx, &self.account, instance_id)?), + + RpcRequest::VboxBuy { instance_id, group, index, construct_id } => + Ok(RpcMessage::InstanceState(vbox_buy(&mut tx, &self.account, instance_id, group, index, construct_id)?)), + + RpcRequest::VboxApply { instance_id, construct_id, index } => + Ok(RpcMessage::InstanceState(vbox_apply(&mut tx, &self.account, instance_id, construct_id, index)?)), + + RpcRequest::VboxCombine { instance_id, inv_indices, vbox_indices } => + Ok(RpcMessage::InstanceState(vbox_combine(&mut tx, &self.account, instance_id, inv_indices, vbox_indices)?)), + + RpcRequest::VboxRefill { instance_id } => + Ok(RpcMessage::InstanceState(vbox_refill(&mut tx, &self.account, instance_id)?)), + + RpcRequest::VboxRefund { instance_id, index } => + Ok(RpcMessage::InstanceState(vbox_refund(&mut tx, &self.account, instance_id, index)?)), + + RpcRequest::VboxUnequip { instance_id, construct_id, target } => + Ok(RpcMessage::InstanceState(vbox_unequip(&mut tx, &self.account, instance_id, construct_id, target, None)?)), + + RpcRequest::VboxUnequipApply { instance_id, construct_id, target, target_construct_id } => + Ok(RpcMessage::InstanceState(vbox_unequip(&mut tx, &self.account, instance_id, construct_id, target, Some(target_construct_id))?)), + + RpcRequest::MtxConstructSpawn {} => + Ok(RpcMessage::ConstructSpawn(mtx::new_construct(&mut tx, &self.account)?)), + + RpcRequest::MtxConstructApply { mtx, construct_id, name } => + Ok(RpcMessage::AccountTeam(mtx::apply(&mut tx, &self.account, mtx, construct_id, name)?)), + + RpcRequest::MtxAccountApply { mtx } => + Ok(RpcMessage::AccountState(mtx::account_apply(&mut tx, &self.account, mtx)?)), + + RpcRequest::MtxBuy { mtx } => + Ok(RpcMessage::AccountShop(mtx::buy(&mut tx, &self.account, mtx)?)), + + RpcRequest::SubscriptionEnding { ending } => + Ok(RpcMessage::SubscriptionState(payments::subscription_ending(&mut tx, stripe, &self.account, ending)?)), + + _ => Err(format_err!("unknown request request={:?}", request)), + }; + + tx.commit()?; + res + } + }; + + info!("request={:?} account={:?} duration={:?}", request, self.account.name, begin.elapsed()); + + return response; + }, + Err(e) => { + warn!("{:?}", e); + Err(err_msg("invalid message")) + }, + } + } +} From 90254f8294987ea202b26941b4d9411fc407dc60 Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 23 Dec 2019 11:01:36 +1000 Subject: [PATCH 34/58] wip --- client/assets/styles/menu.less | 16 +++++++++++++++ client/assets/styles/styles.mobile.less | 2 +- client/src/components/welcome.login.jsx | 12 ++++++++++++ client/src/events.jsx | 19 +++++++++--------- client/src/socket.jsx | 2 ++ client/src/tutorial.utils.jsx | 26 ++++++++++++++++++++++--- server/src/rpc.rs | 2 ++ server/src/user_anonymous.rs | 1 + 8 files changed, 67 insertions(+), 13 deletions(-) diff --git a/client/assets/styles/menu.less b/client/assets/styles/menu.less index e52249d0..260a36f7 100644 --- a/client/assets/styles/menu.less +++ b/client/assets/styles/menu.less @@ -174,3 +174,19 @@ section { } } + +.vbox { + .login { + display: flex; + flex-flow: column; + + label { + line-height: initial; + } + + .terms { + display: inline; + margin: 0 1em; + } + } +} diff --git a/client/assets/styles/styles.mobile.less b/client/assets/styles/styles.mobile.less index 27c8fa8a..40a8de5e 100644 --- a/client/assets/styles/styles.mobile.less +++ b/client/assets/styles/styles.mobile.less @@ -164,7 +164,7 @@ // portrait menu or small size vertical in landscape -@media (max-width: 550px) and (max-height: 800px) { +@media (max-width: 550px) and (max-height: 800px) and (orientation: portrait) { #mnml { grid-template-columns: 1fr; grid-template-rows: 1fr; diff --git a/client/src/components/welcome.login.jsx b/client/src/components/welcome.login.jsx index aa65f20d..5aff5441 100644 --- a/client/src/components/welcome.login.jsx +++ b/client/src/components/welcome.login.jsx @@ -4,6 +4,7 @@ const { Component } = require('preact') const { connect } = require('preact-redux'); const linkState = require('linkstate').default; +const actions = require('./../actions'); const { postData, errorToast } = require('../utils'); const addState = connect( @@ -26,18 +27,29 @@ const addState = connect( submitLogin, } }, + function receiveDispatch(dispatch) { + function clearInstance(user) { + dispatch(actions.setInstance(null)); + } + + return { + clearInstance, + } + } ); function Login(args) { const { submitLogin, + clearInstance, } = args; const { password, name } = this.state; const loginSubmit = (event) => { event.preventDefault(); + clearInstance(); submitLogin(name, password); this.setState({ name: '', password: '' }); }; diff --git a/client/src/events.jsx b/client/src/events.jsx index fa048f29..c0b935b1 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -27,7 +27,6 @@ function registerEvents(store) { function clearTutorial() { store.dispatch(actions.setTutorial(null)); - localStorage.setItem('tutorial-complete', true); } @@ -35,7 +34,6 @@ function registerEvents(store) { store.dispatch(actions.setTutorialGame(null)); } - function setPing(ping) { store.dispatch(actions.setPing(ping)); } @@ -179,18 +177,14 @@ function registerEvents(store) { const player = v.players.find(p => p.id === account.id); store.dispatch(actions.setPlayer(player)); + if (tutorial) tutorialVbox(player, store, tutorial); + if (v.phase === 'Finished') { ws.sendAccountInstances(); } - - // instance.mobile.less hides info at @media 1000 - if (localStorage.getItem('tutorial-complete') || window.innerWidth <= 1100) { - store.dispatch(actions.setTutorial(null)); - } else if (v.time_control === 'Practice' && v.rounds.length === 1 && tutorial) { - tutorialVbox(player, store, tutorial); - } } + return store.dispatch(actions.setInstance(v)); } @@ -214,6 +208,11 @@ function registerEvents(store) { return true; } + function startTutorial() { + store.dispatch(actions.setTutorial(1)); + } + + window.addEventListener('hashchange', urlHashChange, false); return { @@ -243,6 +242,8 @@ function registerEvents(store) { setSubscription, setWs, + startTutorial, + urlHashChange, notify, diff --git a/client/src/socket.jsx b/client/src/socket.jsx index bacf0870..0a17587d 100644 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -299,6 +299,8 @@ function createSocket(events) { ChatWheel: wheel => events.setChatWheel(wheel), // Joining: () => events.notify('Searching for instance...'), + StartTutorial: () => events.startTutorial(), + Processing: () => true, Error: errHandler, }; diff --git a/client/src/tutorial.utils.jsx b/client/src/tutorial.utils.jsx index 740aa867..fa2f7abb 100644 --- a/client/src/tutorial.utils.jsx +++ b/client/src/tutorial.utils.jsx @@ -1,6 +1,8 @@ const preact = require('preact'); const actions = require('./actions'); +const Login = require('./components/welcome.login'); + function tutorialConstructDisplay(player, instance, tutorial, i) { if (instance.time_control === 'Practice' && instance.rounds.length === 1 && tutorial && tutorial < 6) { if (tutorial <= 2 || (tutorial > 2 && i > 0)) { @@ -27,6 +29,7 @@ function tutorialVbox(player, store, tutorial) { for (let i = 2; i < 6; i += 1) { delete vbox.store.Colours[i]; } + vbox.store.Colours = {}; vbox.store.Skills = {}; vbox.store.Specs = {}; delete vbox.stash[0]; @@ -112,6 +115,21 @@ function tutorialStage(tutorial, clearTutorial, instance) { const exit = () => clearTutorial(); const tutorialText = () => { + if (tutorial === 1) { + return ( +
+ +

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.
+ Simple rules, complex interactions and unique mechanics.
+

+ +
+ ); + } + if (tutorial === 1) { return (
@@ -220,12 +238,14 @@ function tutorialStage(tutorial, clearTutorial, instance) { onClick={e => e.stopPropagation()} onMouseDown={exit}> {text} ; + //
+ // {exitTutorial} + //
+ + return (
{tutorialText()} -
- {exitTutorial} -
); } diff --git a/server/src/rpc.rs b/server/src/rpc.rs index ff755767..b71acb5e 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -60,6 +60,8 @@ pub enum RpcMessage { EmailState(Option), SubscriptionState(Option), + StartTutorial(()), + Pong(()), QueueRequested(()), diff --git a/server/src/user_anonymous.rs b/server/src/user_anonymous.rs index 51bd4a4a..95d82c64 100644 --- a/server/src/user_anonymous.rs +++ b/server/src/user_anonymous.rs @@ -50,6 +50,7 @@ impl User for Anonymous { self.send(RpcMessage::AccountState(self.account.clone()), events, ws)?; self.send(RpcMessage::ItemInfo(item_info()), events, ws)?; + self.send(RpcMessage::StartTutorial(()), events, ws)?; self.send(RpcMessage::InstanceState(pg::instance_demo(&self.account)?), events, ws)?; Ok(()) From 4193b71853e3e1ac1396619c2546328fbbabbb38 Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 24 Dec 2019 10:36:30 +1000 Subject: [PATCH 35/58] don't start tutorial automatically --- server/src/user_anonymous.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/user_anonymous.rs b/server/src/user_anonymous.rs index 95d82c64..0e30a495 100644 --- a/server/src/user_anonymous.rs +++ b/server/src/user_anonymous.rs @@ -50,7 +50,7 @@ impl User for Anonymous { self.send(RpcMessage::AccountState(self.account.clone()), events, ws)?; self.send(RpcMessage::ItemInfo(item_info()), events, ws)?; - self.send(RpcMessage::StartTutorial(()), events, ws)?; + // self.send(RpcMessage::StartTutorial(()), events, ws)?; self.send(RpcMessage::InstanceState(pg::instance_demo(&self.account)?), events, ws)?; Ok(()) From 1bbaede2a6575b0211e8d9294cc8928c96b98ee8 Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 24 Dec 2019 10:36:45 +1000 Subject: [PATCH 36/58] Revert "wip" This reverts commit 90254f8294987ea202b26941b4d9411fc407dc60. --- client/assets/styles/menu.less | 16 --------------- client/assets/styles/styles.mobile.less | 2 +- client/src/components/welcome.login.jsx | 12 ------------ client/src/events.jsx | 19 +++++++++--------- client/src/socket.jsx | 2 -- client/src/tutorial.utils.jsx | 26 +++---------------------- server/src/rpc.rs | 2 -- 7 files changed, 13 insertions(+), 66 deletions(-) diff --git a/client/assets/styles/menu.less b/client/assets/styles/menu.less index 260a36f7..e52249d0 100644 --- a/client/assets/styles/menu.less +++ b/client/assets/styles/menu.less @@ -174,19 +174,3 @@ section { } } - -.vbox { - .login { - display: flex; - flex-flow: column; - - label { - line-height: initial; - } - - .terms { - display: inline; - margin: 0 1em; - } - } -} diff --git a/client/assets/styles/styles.mobile.less b/client/assets/styles/styles.mobile.less index 40a8de5e..27c8fa8a 100644 --- a/client/assets/styles/styles.mobile.less +++ b/client/assets/styles/styles.mobile.less @@ -164,7 +164,7 @@ // portrait menu or small size vertical in landscape -@media (max-width: 550px) and (max-height: 800px) and (orientation: portrait) { +@media (max-width: 550px) and (max-height: 800px) { #mnml { grid-template-columns: 1fr; grid-template-rows: 1fr; diff --git a/client/src/components/welcome.login.jsx b/client/src/components/welcome.login.jsx index 5aff5441..aa65f20d 100644 --- a/client/src/components/welcome.login.jsx +++ b/client/src/components/welcome.login.jsx @@ -4,7 +4,6 @@ const { Component } = require('preact') const { connect } = require('preact-redux'); const linkState = require('linkstate').default; -const actions = require('./../actions'); const { postData, errorToast } = require('../utils'); const addState = connect( @@ -27,29 +26,18 @@ const addState = connect( submitLogin, } }, - function receiveDispatch(dispatch) { - function clearInstance(user) { - dispatch(actions.setInstance(null)); - } - - return { - clearInstance, - } - } ); function Login(args) { const { submitLogin, - clearInstance, } = args; const { password, name } = this.state; const loginSubmit = (event) => { event.preventDefault(); - clearInstance(); submitLogin(name, password); this.setState({ name: '', password: '' }); }; diff --git a/client/src/events.jsx b/client/src/events.jsx index c0b935b1..fa048f29 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -27,6 +27,7 @@ function registerEvents(store) { function clearTutorial() { store.dispatch(actions.setTutorial(null)); + localStorage.setItem('tutorial-complete', true); } @@ -34,6 +35,7 @@ function registerEvents(store) { store.dispatch(actions.setTutorialGame(null)); } + function setPing(ping) { store.dispatch(actions.setPing(ping)); } @@ -177,13 +179,17 @@ function registerEvents(store) { const player = v.players.find(p => p.id === account.id); store.dispatch(actions.setPlayer(player)); - if (tutorial) tutorialVbox(player, store, tutorial); - if (v.phase === 'Finished') { ws.sendAccountInstances(); } - } + // instance.mobile.less hides info at @media 1000 + if (localStorage.getItem('tutorial-complete') || window.innerWidth <= 1100) { + store.dispatch(actions.setTutorial(null)); + } else if (v.time_control === 'Practice' && v.rounds.length === 1 && tutorial) { + tutorialVbox(player, store, tutorial); + } + } return store.dispatch(actions.setInstance(v)); } @@ -208,11 +214,6 @@ function registerEvents(store) { return true; } - function startTutorial() { - store.dispatch(actions.setTutorial(1)); - } - - window.addEventListener('hashchange', urlHashChange, false); return { @@ -242,8 +243,6 @@ function registerEvents(store) { setSubscription, setWs, - startTutorial, - urlHashChange, notify, diff --git a/client/src/socket.jsx b/client/src/socket.jsx index 0a17587d..bacf0870 100644 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -299,8 +299,6 @@ function createSocket(events) { ChatWheel: wheel => events.setChatWheel(wheel), // Joining: () => events.notify('Searching for instance...'), - StartTutorial: () => events.startTutorial(), - Processing: () => true, Error: errHandler, }; diff --git a/client/src/tutorial.utils.jsx b/client/src/tutorial.utils.jsx index fa2f7abb..740aa867 100644 --- a/client/src/tutorial.utils.jsx +++ b/client/src/tutorial.utils.jsx @@ -1,8 +1,6 @@ const preact = require('preact'); const actions = require('./actions'); -const Login = require('./components/welcome.login'); - function tutorialConstructDisplay(player, instance, tutorial, i) { if (instance.time_control === 'Practice' && instance.rounds.length === 1 && tutorial && tutorial < 6) { if (tutorial <= 2 || (tutorial > 2 && i > 0)) { @@ -29,7 +27,6 @@ function tutorialVbox(player, store, tutorial) { for (let i = 2; i < 6; i += 1) { delete vbox.store.Colours[i]; } - vbox.store.Colours = {}; vbox.store.Skills = {}; vbox.store.Specs = {}; delete vbox.stash[0]; @@ -115,21 +112,6 @@ function tutorialStage(tutorial, clearTutorial, instance) { const exit = () => clearTutorial(); const tutorialText = () => { - if (tutorial === 1) { - return ( -
- -

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.
- Simple rules, complex interactions and unique mechanics.
-

- -
- ); - } - if (tutorial === 1) { return (
@@ -238,14 +220,12 @@ function tutorialStage(tutorial, clearTutorial, instance) { onClick={e => e.stopPropagation()} onMouseDown={exit}> {text} ; - //
- // {exitTutorial} - //
- - return (
{tutorialText()} +
+ {exitTutorial} +
); } diff --git a/server/src/rpc.rs b/server/src/rpc.rs index b71acb5e..ff755767 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -60,8 +60,6 @@ pub enum RpcMessage { EmailState(Option), SubscriptionState(Option), - StartTutorial(()), - Pong(()), QueueRequested(()), From 395bf640c99c7de21f05b668d2d3758722bd65c1 Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 24 Dec 2019 12:09:30 +1000 Subject: [PATCH 37/58] consolidate views for auth and anon --- client/assets/styles/styles.less | 1 + client/src/actions.jsx | 1 + client/src/components/guest.top.jsx | 138 ++++++++++++++++++++++++++++ client/src/components/header.jsx | 15 +++ client/src/components/main.top.jsx | 6 ++ client/src/components/welcome.jsx | 73 +++++---------- client/src/events.jsx | 19 ++-- client/src/reducers.jsx | 1 + client/src/socket.jsx | 3 + server/src/rpc.rs | 2 + server/src/user_anonymous.rs | 62 +++++++------ server/src/user_authenticated.rs | 1 + 12 files changed, 238 insertions(+), 84 deletions(-) create mode 100644 client/src/components/guest.top.jsx diff --git a/client/assets/styles/styles.less b/client/assets/styles/styles.less index b22ee13d..5e6c3982 100644 --- a/client/assets/styles/styles.less +++ b/client/assets/styles/styles.less @@ -283,6 +283,7 @@ header { } border: none; + border-radius: 0; } } diff --git a/client/src/actions.jsx b/client/src/actions.jsx index 311d444b..a49d8278 100644 --- a/client/src/actions.jsx +++ b/client/src/actions.jsx @@ -1,4 +1,5 @@ export const setAccount = value => ({ type: 'SET_ACCOUNT', value }); +export const setAuthenticated = value => ({ type: 'SET_AUTHENTICATED', value }); export const setAnimating = value => ({ type: 'SET_ANIMATING', value }); export const setAnimFocus = value => ({ type: 'SET_ANIM_FOCUS', value }); diff --git a/client/src/components/guest.top.jsx b/client/src/components/guest.top.jsx new file mode 100644 index 00000000..f356356c --- /dev/null +++ b/client/src/components/guest.top.jsx @@ -0,0 +1,138 @@ +// const { connect } = require('preact-redux'); +const preact = require('preact'); +const { connect } = require('preact-redux'); + +const { errorToast, infoToast } = require('../utils'); +const actions = require('./../actions'); + +const VERSION = process.env.npm_package_version; + +const Welcome = require('./welcome'); + +const addState = connect( + function receiveState(state) { + const { + ws, + account, + instances, + invite, + pvp, + } = state; + + function sendInstanceState(id) { + ws.sendInstanceState(id); + } + + function sendInstancePractice() { + ws.sendInstancePractice(); + } + + function sendInstanceQueue() { + ws.sendInstanceQueue(); + } + + function sendInstanceInvite() { + ws.sendInstanceInvite(); + } + + function sendInstanceLeave() { + ws.sendInstanceLeave(); + } + + return { + account, + instances, + invite, + pvp, + + sendInstanceState, + sendInstanceQueue, + sendInstancePractice, + sendInstanceInvite, + sendInstanceLeave, + }; + }, + + function receiveDispatch(dispatch) { + function setMtxActive(mtx) { + dispatch(actions.setConstructRename(null)); + dispatch(actions.setMtxActive(mtx)); + return true; + } + + function setNav(place) { + return dispatch(actions.setNav(place)); + } + + return { + setMtxActive, + setNav, + }; + } +); + +function Play(args) { + const { + account, + instances, + invite, + pvp, + + sendInstanceState, + sendInstanceQueue, + sendInstancePractice, + sendInstanceInvite, + sendInstanceLeave, + + setNav, + } = args; + + const news = ( +
+

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.
+ Simple rules, complex interactions and unique mechanics.
+

+
+ ); + + const list = () => { + return ( +
+
+
+ +
Learn MNML
+
+
+ +
Join the Community
+
+
+
+ ); + }; + + return ( +
+
+

Welcome to MNML

+ {news} + {list()} +
+ +
+ ); +} + +module.exports = addState(Play); diff --git a/client/src/components/header.jsx b/client/src/components/header.jsx index 734b1761..9dc7b6df 100644 --- a/client/src/components/header.jsx +++ b/client/src/components/header.jsx @@ -8,6 +8,7 @@ const addState = connect( const { ws, account, + authenticated, nav, } = state; @@ -22,6 +23,7 @@ const addState = connect( return { account, + authenticated, nav, sendInstanceState, @@ -48,6 +50,7 @@ const addState = connect( function Header(args) { const { account, + authenticated, nav, sendAccountStates, @@ -56,6 +59,18 @@ function Header(args) { if (!account) return false; + if (!authenticated) return ( +
+
+ +
+
+ ) + function navTo(p) { return setNav(p); } diff --git a/client/src/components/main.top.jsx b/client/src/components/main.top.jsx index b6395305..f56fe8c6 100644 --- a/client/src/components/main.top.jsx +++ b/client/src/components/main.top.jsx @@ -4,6 +4,7 @@ const preact = require('preact'); const actions = require('./../actions'); const AccountTop = require('./account.top'); +const GuestTop = require('./guest.top'); const Play = require('./play'); const Shop = require('./shop'); const Reshape = require('./reshape'); @@ -12,10 +13,12 @@ const addState = connect( function receiveState(state) { const { nav, + authenticated, } = state; return { nav, + authenticated, }; }, ); @@ -23,8 +26,11 @@ const addState = connect( function Top(args) { const { nav, + authenticated, } = args; + if (!authenticated) return + if (nav === 'account') return ; if (nav === 'play') return if (nav === 'shop') return diff --git a/client/src/components/welcome.jsx b/client/src/components/welcome.jsx index 3cb0824d..e04e95b7 100644 --- a/client/src/components/welcome.jsx +++ b/client/src/components/welcome.jsx @@ -7,7 +7,7 @@ const Help = require('./welcome.help'); // const About = require('./welcome.about'); function Welcome() { - const page = this.state.page || 'register'; + const page = this.state.page || 'login'; const pageEl = () => { if (page === 'login') return ; @@ -16,57 +16,32 @@ function Welcome() { return false; }; - const news = ( -
-

Welcome to mnml.

- -

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.
- Simple rules, complex interactions and unique mechanics.
-

-

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

- - Tutorial Playthrough on YouTube -
- ); - - const main =
{news}{pageEl()}
; + const form =
{pageEl()}
; return ( -
-
-
- - - - -
-
-
- {main} +
+
+ + +
-
+ {form} +
); } diff --git a/client/src/events.jsx b/client/src/events.jsx index fa048f29..c0b935b1 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -27,7 +27,6 @@ function registerEvents(store) { function clearTutorial() { store.dispatch(actions.setTutorial(null)); - localStorage.setItem('tutorial-complete', true); } @@ -35,7 +34,6 @@ function registerEvents(store) { store.dispatch(actions.setTutorialGame(null)); } - function setPing(ping) { store.dispatch(actions.setPing(ping)); } @@ -179,18 +177,14 @@ function registerEvents(store) { const player = v.players.find(p => p.id === account.id); store.dispatch(actions.setPlayer(player)); + if (tutorial) tutorialVbox(player, store, tutorial); + if (v.phase === 'Finished') { ws.sendAccountInstances(); } - - // instance.mobile.less hides info at @media 1000 - if (localStorage.getItem('tutorial-complete') || window.innerWidth <= 1100) { - store.dispatch(actions.setTutorial(null)); - } else if (v.time_control === 'Practice' && v.rounds.length === 1 && tutorial) { - tutorialVbox(player, store, tutorial); - } } + return store.dispatch(actions.setInstance(v)); } @@ -214,6 +208,11 @@ function registerEvents(store) { return true; } + function startTutorial() { + store.dispatch(actions.setTutorial(1)); + } + + window.addEventListener('hashchange', urlHashChange, false); return { @@ -243,6 +242,8 @@ function registerEvents(store) { setSubscription, setWs, + startTutorial, + urlHashChange, notify, diff --git a/client/src/reducers.jsx b/client/src/reducers.jsx index 9edeeae6..c30dec0a 100644 --- a/client/src/reducers.jsx +++ b/client/src/reducers.jsx @@ -10,6 +10,7 @@ function createReducer(defaultState, actionType) { /* eslint-disable key-spacing */ module.exports = { account: createReducer(null, 'SET_ACCOUNT'), + authenticated: createReducer(null, 'SET_AUTHENTICATED'), activeItem: createReducer(null, 'SET_ACTIVE_VAR'), activeSkill: createReducer(null, 'SET_ACTIVE_SKILL'), diff --git a/client/src/socket.jsx b/client/src/socket.jsx index bacf0870..443235ae 100644 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -270,6 +270,7 @@ function createSocket(events) { // this object wraps the reply types to a function const handlers = { AccountState: onAccount, + AccountAuthenticated: events.setAuthenticated, AccountConstructs: onAccountConstructs, AccountTeam: onAccountTeam, AccountInstances: onAccountInstances, @@ -299,6 +300,8 @@ function createSocket(events) { ChatWheel: wheel => events.setChatWheel(wheel), // Joining: () => events.notify('Searching for instance...'), + StartTutorial: () => events.startTutorial(), + Processing: () => true, Error: errHandler, }; diff --git a/server/src/rpc.rs b/server/src/rpc.rs index ff755767..ff61cd01 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -44,6 +44,7 @@ use http::{AUTH_CLEAR, TOKEN_HEADER}; #[derive(Debug,Clone,Serialize)] pub enum RpcMessage { AccountState(Account), + AccountAuthenticated(()), AccountConstructs(Vec), AccountTeam(Vec), AccountInstances(Vec), @@ -61,6 +62,7 @@ pub enum RpcMessage { SubscriptionState(Option), Pong(()), + StartTutorial(()), QueueRequested(()), QueueJoined(()), diff --git a/server/src/user_anonymous.rs b/server/src/user_anonymous.rs index 0e30a495..40359e58 100644 --- a/server/src/user_anonymous.rs +++ b/server/src/user_anonymous.rs @@ -49,9 +49,8 @@ impl User for Anonymous { info!("anonymous connection"); self.send(RpcMessage::AccountState(self.account.clone()), events, ws)?; + self.send(RpcMessage::StartTutorial(()), events, ws)?; self.send(RpcMessage::ItemInfo(item_info()), events, ws)?; - // self.send(RpcMessage::StartTutorial(()), events, ws)?; - self.send(RpcMessage::InstanceState(pg::instance_demo(&self.account)?), events, ws)?; Ok(()) } @@ -59,70 +58,81 @@ impl User for Anonymous { fn receive(&mut self, data: Vec, _db: &Db, _begin: Instant, _events: &CbSender, _stripe: &StripeClient) -> Result { match from_slice::(&data) { Ok(v) => { - let mut instance = match self.instance { - Some(ref i) => i.clone(), - None => return Err(err_msg("instance missing")), + let get_instance = || { + match self.instance { + Some(ref i) => Ok(i.clone()), + None => return Err(err_msg("instance missing")), + } }; - let game = match self.game { - Some(ref i) => Some(i.clone()), - None => None + let get_game = || { + match self.game { + Some(ref i) => Ok(i.clone()), + None => return Err(err_msg("game missing")), + } }; match v { RpcRequest::Ping {} => return Ok(RpcMessage::Pong(())), + + RpcRequest::InstancePractice {} => + Ok(RpcMessage::InstanceState(pg::instance_demo(&self.account)?)), + RpcRequest::InstanceReady { instance_id: _ } => { - match instance.player_ready(self.account.id)? { + match get_instance()?.player_ready(self.account.id)? { Some(g) => Ok(RpcMessage::GameState(g)), - None => Ok(RpcMessage::InstanceState(instance)), + None => Ok(RpcMessage::InstanceState(get_instance()?)), } }, RpcRequest::InstanceState { instance_id: _ } => - Ok(RpcMessage::InstanceState(instance)), + Ok(RpcMessage::InstanceState(get_instance()?)), - RpcRequest::InstanceAbandon { instance_id: _ } => - Err(err_msg("don't give up!")), + RpcRequest::InstanceAbandon { instance_id: _ } => { + let mut instance = get_instance()?; + instance.finish(); + Ok(RpcMessage::InstanceState(instance)) + }, RpcRequest::VboxBuy { instance_id: _, group, index, construct_id } => - Ok(RpcMessage::InstanceState(instance.vbox_buy(self.account.id, group, index, construct_id)?)), + Ok(RpcMessage::InstanceState(get_instance()?.vbox_buy(self.account.id, group, index, construct_id)?)), RpcRequest::VboxApply { instance_id: _, construct_id, index } => - Ok(RpcMessage::InstanceState(instance.vbox_apply(self.account.id, index, construct_id)?)), + Ok(RpcMessage::InstanceState(get_instance()?.vbox_apply(self.account.id, index, construct_id)?)), RpcRequest::VboxCombine { instance_id: _, inv_indices, vbox_indices } => - Ok(RpcMessage::InstanceState(instance.vbox_combine(self.account.id, inv_indices, vbox_indices)?)), + Ok(RpcMessage::InstanceState(get_instance()?.vbox_combine(self.account.id, inv_indices, vbox_indices)?)), RpcRequest::VboxRefill { instance_id: _ } => - Ok(RpcMessage::InstanceState(instance.vbox_refill(self.account.id)?)), + Ok(RpcMessage::InstanceState(get_instance()?.vbox_refill(self.account.id)?)), RpcRequest::VboxRefund { instance_id: _, index } => - Ok(RpcMessage::InstanceState(instance.vbox_refund(self.account.id, index)?)), + Ok(RpcMessage::InstanceState(get_instance()?.vbox_refund(self.account.id, index)?)), RpcRequest::VboxUnequip { instance_id: _, construct_id, target } => - Ok(RpcMessage::InstanceState(instance.vbox_unequip(self.account.id, target, construct_id, None)?)), + Ok(RpcMessage::InstanceState(get_instance()?.vbox_unequip(self.account.id, target, construct_id, None)?)), RpcRequest::VboxUnequipApply { instance_id: _, construct_id, target, target_construct_id } => - Ok(RpcMessage::InstanceState(instance.vbox_unequip(self.account.id, target, construct_id, Some(target_construct_id))?)), + Ok(RpcMessage::InstanceState(get_instance()?.vbox_unequip(self.account.id, target, construct_id, Some(target_construct_id))?)), RpcRequest::GameState { id: _ } => - Ok(RpcMessage::GameState(game.unwrap())), + Ok(RpcMessage::GameState(get_game()?)), RpcRequest::GameSkill { game_id: _, construct_id, target_construct_id, skill } => { - let mut game = game.unwrap(); + let mut game = get_game()?; game.add_skill(self.account.id, construct_id, target_construct_id, skill)?; Ok(RpcMessage::GameState(game)) }, RpcRequest::GameSkillClear { game_id: _ } => { - let mut game = game.unwrap(); + let mut game = get_game()?; game.clear_skill(self.account.id)?; Ok(RpcMessage::GameState(game)) }, RpcRequest::GameReady { id: _ } => { - let mut game = game.unwrap(); + let mut game = get_game()?; game.player_ready(self.account.id)?; if game.skill_phase_finished() { game = game.resolve_phase_start(); @@ -132,10 +142,10 @@ impl User for Anonymous { }, RpcRequest::GameConcede { game_id: _ } => - Ok(RpcMessage::GameState(game.unwrap().concede(self.account.id)?)), + Ok(RpcMessage::GameState(get_game()?.concede(self.account.id)?)), RpcRequest::GameOfferDraw { game_id: _ } => - Ok(RpcMessage::GameState(game.unwrap().offer_draw(self.account.id)?)), + Ok(RpcMessage::GameState(get_game()?.offer_draw(self.account.id)?)), _ => Err(format_err!("unhandled anonymous request request={:?}", v)), } diff --git a/server/src/user_authenticated.rs b/server/src/user_authenticated.rs index c92400a3..252b516d 100644 --- a/server/src/user_authenticated.rs +++ b/server/src/user_authenticated.rs @@ -71,6 +71,7 @@ impl User for Authorised { info!("authenticated connection account={:?}", self.account); let a = &self.account; + ws.send(RpcMessage::AccountAuthenticated(()))?; // tell events we have connected events.send(Event::Connect(self.id, a.clone(), ws.clone()))?; From cf4972a1b8ee7d90e004f89fb2321ddb9ff95570 Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 24 Dec 2019 12:23:33 +1000 Subject: [PATCH 38/58] authenticated msgs --- client/src/components/guest.top.jsx | 39 ++++++++++++++--------------- client/src/events.jsx | 6 +++++ client/src/socket.jsx | 2 +- server/src/rpc.rs | 2 +- server/src/user_anonymous.rs | 2 +- server/src/user_authenticated.rs | 2 +- 6 files changed, 29 insertions(+), 24 deletions(-) diff --git a/client/src/components/guest.top.jsx b/client/src/components/guest.top.jsx index f356356c..c6020b6f 100644 --- a/client/src/components/guest.top.jsx +++ b/client/src/components/guest.top.jsx @@ -100,25 +100,23 @@ function Play(args) { const list = () => { return ( -
-
-
- -
Learn MNML
-
-
- -
Join the Community
-
-
+
+
+ +
Learn MNML
+
+
+ +
Join the Community
+
); }; @@ -127,8 +125,9 @@ function Play(args) {

Welcome to MNML

- {news} {list()} +
+ {news}
diff --git a/client/src/events.jsx b/client/src/events.jsx index c0b935b1..dbf1c1bf 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -104,6 +104,10 @@ function registerEvents(store) { } function setAccount(account) { + store.dispatch(actions.setAccount(account)); + } + + function setAuthenticated(account) { if (account && window.Notification) { window.Notification.requestPermission(); } @@ -113,6 +117,7 @@ function registerEvents(store) { } store.dispatch(actions.setAccount(account)); + store.dispatch(actions.setAuthenticated(true)); } function setEmail(email) { @@ -223,6 +228,7 @@ function registerEvents(store) { clearTutorial, clearTutorialGame, setAccount, + setAuthenticated, setAccountInstances, setActiveItem, setActiveSkill, diff --git a/client/src/socket.jsx b/client/src/socket.jsx index 443235ae..30e16b59 100644 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -270,7 +270,7 @@ function createSocket(events) { // this object wraps the reply types to a function const handlers = { AccountState: onAccount, - AccountAuthenticated: events.setAuthenticated, + AccountAuthenticated: account => events.setAuthenticated(account), AccountConstructs: onAccountConstructs, AccountTeam: onAccountTeam, AccountInstances: onAccountInstances, diff --git a/server/src/rpc.rs b/server/src/rpc.rs index ff61cd01..7ab789f1 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -44,7 +44,7 @@ use http::{AUTH_CLEAR, TOKEN_HEADER}; #[derive(Debug,Clone,Serialize)] pub enum RpcMessage { AccountState(Account), - AccountAuthenticated(()), + AccountAuthenticated(Account), AccountConstructs(Vec), AccountTeam(Vec), AccountInstances(Vec), diff --git a/server/src/user_anonymous.rs b/server/src/user_anonymous.rs index 40359e58..872c478f 100644 --- a/server/src/user_anonymous.rs +++ b/server/src/user_anonymous.rs @@ -50,7 +50,6 @@ impl User for Anonymous { self.send(RpcMessage::AccountState(self.account.clone()), events, ws)?; self.send(RpcMessage::StartTutorial(()), events, ws)?; - self.send(RpcMessage::ItemInfo(item_info()), events, ws)?; Ok(()) } @@ -75,6 +74,7 @@ impl User for Anonymous { match v { RpcRequest::Ping {} => return Ok(RpcMessage::Pong(())), + RpcRequest::ItemInfo {} => return Ok(RpcMessage::ItemInfo(item_info())), RpcRequest::InstancePractice {} => Ok(RpcMessage::InstanceState(pg::instance_demo(&self.account)?)), diff --git a/server/src/user_authenticated.rs b/server/src/user_authenticated.rs index 252b516d..3cf25be8 100644 --- a/server/src/user_authenticated.rs +++ b/server/src/user_authenticated.rs @@ -71,7 +71,7 @@ impl User for Authorised { info!("authenticated connection account={:?}", self.account); let a = &self.account; - ws.send(RpcMessage::AccountAuthenticated(()))?; + ws.send(RpcMessage::AccountAuthenticated(a.clone()))?; // tell events we have connected events.send(Event::Connect(self.id, a.clone(), ws.clone()))?; From 493e7bcfd5e2ac8d5cb55eab34a985a320eb0350 Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 24 Dec 2019 16:46:25 +1000 Subject: [PATCH 39/58] menu stuff --- client/assets/styles/styles.less | 6 +----- client/assets/styles/styles.mobile.less | 2 +- client/src/components/header.jsx | 17 +---------------- client/src/components/welcome.jsx | 4 ++-- core/fixme.md | 3 +++ 5 files changed, 8 insertions(+), 24 deletions(-) diff --git a/client/assets/styles/styles.less b/client/assets/styles/styles.less index 5e6c3982..704d3f59 100644 --- a/client/assets/styles/styles.less +++ b/client/assets/styles/styles.less @@ -262,12 +262,8 @@ figure.gray { } header { - .options { - font-size: 200%; - } - button { - height: 2em; + height: 2.5em; // border-radius: 0.1em; border: none; border-radius: 0; diff --git a/client/assets/styles/styles.mobile.less b/client/assets/styles/styles.mobile.less index 27c8fa8a..40a8de5e 100644 --- a/client/assets/styles/styles.mobile.less +++ b/client/assets/styles/styles.mobile.less @@ -164,7 +164,7 @@ // portrait menu or small size vertical in landscape -@media (max-width: 550px) and (max-height: 800px) { +@media (max-width: 550px) and (max-height: 800px) and (orientation: portrait) { #mnml { grid-template-columns: 1fr; grid-template-rows: 1fr; diff --git a/client/src/components/header.jsx b/client/src/components/header.jsx index 9dc7b6df..bcc286a6 100644 --- a/client/src/components/header.jsx +++ b/client/src/components/header.jsx @@ -59,17 +59,7 @@ function Header(args) { if (!account) return false; - if (!authenticated) return ( -
-
- -
-
- ) + if (!authenticated) return false; function navTo(p) { return setNav(p); @@ -83,11 +73,6 @@ function Header(args) { return (
-
{form} -
+ ); } diff --git a/core/fixme.md b/core/fixme.md index c3f3a70d..b9888748 100644 --- a/core/fixme.md +++ b/core/fixme.md @@ -1,2 +1,5 @@ # FIXME game ready not auto starting resolve phase + +remove big header and move to rhs of news pane +add big logo w/ noise when you mouseover stuff etc From 1991574b21c05498f760ceadf8ccb03d530a49c4 Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 24 Dec 2019 18:01:32 +1000 Subject: [PATCH 40/58] fukt a lot but wip --- client/assets/mnml.logo.text.svg | 2568 +++++++++++++++++++++++++ client/assets/styles/account.less | 11 +- client/assets/styles/menu.less | 12 +- client/assets/styles/styles.less | 12 +- client/src/components/account.top.jsx | 8 +- client/src/components/controls.jsx | 4 + client/src/components/noise.logo.jsx | 50 + 7 files changed, 2641 insertions(+), 24 deletions(-) create mode 100644 client/assets/mnml.logo.text.svg create mode 100644 client/src/components/noise.logo.jsx diff --git a/client/assets/mnml.logo.text.svg b/client/assets/mnml.logo.text.svg new file mode 100644 index 00000000..578fac9b --- /dev/null +++ b/client/assets/mnml.logo.text.svg @@ -0,0 +1,2568 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/client/assets/styles/account.less b/client/assets/styles/account.less index c920c8dc..21ea145f 100644 --- a/client/assets/styles/account.less +++ b/client/assets/styles/account.less @@ -3,16 +3,25 @@ div { padding-right: 1em; + // display: flex; + // flex-flow: column; + line-height: 2em; + } + + h3 { + // text-transform: uppercase; + margin-bottom: 0.5em; } button { width: 100%; + height: 2.5em; display: block; } input { width: 100%; - height: 3em; + height: 2.5em; display: block; } diff --git a/client/assets/styles/menu.less b/client/assets/styles/menu.less index e52249d0..dddead54 100644 --- a/client/assets/styles/menu.less +++ b/client/assets/styles/menu.less @@ -75,10 +75,6 @@ flex: 1; border-top: 0; border: 0.1em solid #222; - &:not(:last-child) { - border-right: 0; - } - &:last-child { float: right; } @@ -93,6 +89,10 @@ display: inline; margin: 0 1em; } + + button { + padding: 0 0.5em; + } } } @@ -117,10 +117,6 @@ section { grid-gap: 1em; flex-flow: row wrap; align-items: flex-end; - button { - border-radius: 0.25em; - // height: 3em; - } &.sub { grid-template-columns: 1fr; diff --git a/client/assets/styles/styles.less b/client/assets/styles/styles.less index 704d3f59..4d92875f 100644 --- a/client/assets/styles/styles.less +++ b/client/assets/styles/styles.less @@ -129,7 +129,7 @@ button, input { box-sizing: border-box; font-size: 1em; flex: 1; - border-radius: 0.5em; + border-radius: 0; line-height: 2em; padding-right: 0.1em; padding-left: 0.1em; @@ -261,15 +261,6 @@ figure.gray { display: none; } -header { - button { - height: 2.5em; - // border-radius: 0.1em; - border: none; - border-radius: 0; - } -} - .options { button { &.highlight { @@ -279,7 +270,6 @@ header { } border: none; - border-radius: 0; } } diff --git a/client/src/components/account.top.jsx b/client/src/components/account.top.jsx index de983dd7..b2500d62 100644 --- a/client/src/components/account.top.jsx +++ b/client/src/components/account.top.jsx @@ -152,11 +152,9 @@ class AccountStatus extends Component { return (
diff --git a/client/src/components/mnml.jsx b/client/src/components/mnml.jsx index db7b1471..78e13a1b 100644 --- a/client/src/components/mnml.jsx +++ b/client/src/components/mnml.jsx @@ -21,7 +21,7 @@ function Mnml(args) { ? 'show' : ''; - if (!authenticated) return ( + if (!authenticated && !instance && !game) return (
From 667e880edda8ed6703dc505c7011ff96d2cc5e51 Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 24 Dec 2019 18:52:56 +1000 Subject: [PATCH 45/58] tutorial fix and logo --- client/assets/styles/styles.less | 4 ++++ client/src/components/noise.logo.jsx | 2 +- client/src/events.jsx | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/client/assets/styles/styles.less b/client/assets/styles/styles.less index 36586216..705c500f 100644 --- a/client/assets/styles/styles.less +++ b/client/assets/styles/styles.less @@ -317,6 +317,10 @@ li { // pointer-events: none; } +header { + // font-size: 1.2em; +} + #clipboard { width: 1px; height: 1px; diff --git a/client/src/components/noise.logo.jsx b/client/src/components/noise.logo.jsx index 2feb3916..09abc33e 100644 --- a/client/src/components/noise.logo.jsx +++ b/client/src/components/noise.logo.jsx @@ -18,7 +18,7 @@ class Logo extends Component { viewBox="0 0 400 400"> - +
diff --git a/client/src/events.jsx b/client/src/events.jsx index dbf1c1bf..11e791ea 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -117,6 +117,7 @@ function registerEvents(store) { } store.dispatch(actions.setAccount(account)); + store.dispatch(actions.setTutorial(null)); store.dispatch(actions.setAuthenticated(true)); } From d6ab237166fdf4bd0c1061b802050bff01ce1f9b Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 29 Dec 2019 14:29:42 +1000 Subject: [PATCH 46/58] more dynamic noise --- client/assets/styles/styles.less | 1 + client/src/components/mnml.jsx | 1 + client/src/components/noise.logo.jsx | 29 +++++++++++++++++++++++----- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/client/assets/styles/styles.less b/client/assets/styles/styles.less index 705c500f..09e265b7 100644 --- a/client/assets/styles/styles.less +++ b/client/assets/styles/styles.less @@ -151,6 +151,7 @@ button, input { &:hover { color: whitesmoke; border-color: @gray-hover; + // filter: url("#noiseFilter"); } &:focus { diff --git a/client/src/components/mnml.jsx b/client/src/components/mnml.jsx index 78e13a1b..4da9d8e8 100644 --- a/client/src/components/mnml.jsx +++ b/client/src/components/mnml.jsx @@ -5,6 +5,7 @@ const Main = require('./main'); // const Nav = require('./nav'); const Controls = require('./controls'); const FrontPage = require('./front.page'); +const NoiseLogo = require('./noise.logo'); const addState = connect( ({ game, instance, authenticated }) => ({ game, instance, authenticated }) diff --git a/client/src/components/noise.logo.jsx b/client/src/components/noise.logo.jsx index 09abc33e..8e3c1d71 100644 --- a/client/src/components/noise.logo.jsx +++ b/client/src/components/noise.logo.jsx @@ -17,8 +17,8 @@ class Logo extends Component { xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"> - - + + @@ -28,11 +28,30 @@ class Logo extends Component { componentDidMount() { this.animations.push(anime({ targets: ['#noiseFilter feTurbulence', '#noiseFilter feDisplacementMap'], - baseFrequency: 1, easing: 'linear', - duration: () => anime.random(2000, 5000), loop: true, - direction: 'alternate', + keyframes: [ + { + baseFrequency: 0.5, + duration: () => anime.random(1000, 2000), + }, + ], + })); + + this.animations.push(anime({ + targets: ['#noiseFilter feDisplacementMap'], + easing: 'linear', + loop: true, + keyframes: [ + { + scale: 2, + duration: () => anime.random(2000, 5000), + }, + { + scale: 4, + duration: 200, + }, + ], })); } From 0044cccf67a634e4b6b581d8f17ba9acd7c599b2 Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 29 Dec 2019 14:40:10 +1000 Subject: [PATCH 47/58] mobile fix --- client/assets/styles/styles.mobile.less | 11 ++++++++++- client/src/components/noise.logo.jsx | 10 +++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/client/assets/styles/styles.mobile.less b/client/assets/styles/styles.mobile.less index 40a8de5e..430627bc 100644 --- a/client/assets/styles/styles.mobile.less +++ b/client/assets/styles/styles.mobile.less @@ -169,7 +169,16 @@ grid-template-columns: 1fr; grid-template-rows: 1fr; grid-template-areas: - "main" + "main"; + + &.front-page { + display: block; + + main { + padding: 0 0.5em; + } + } + } section { diff --git a/client/src/components/noise.logo.jsx b/client/src/components/noise.logo.jsx index 8e3c1d71..de3997e5 100644 --- a/client/src/components/noise.logo.jsx +++ b/client/src/components/noise.logo.jsx @@ -49,7 +49,15 @@ class Logo extends Component { }, { scale: 4, - duration: 200, + duration: () => anime.random(150, 250), + }, + { + scale: 2, + duration: () => anime.random(100, 150), + }, + { + scale: 4, + duration: () => anime.random(150, 250), }, ], })); From 868257825f8dffe522bff7ff88abac38a95e653e Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 29 Dec 2019 16:20:17 +1000 Subject: [PATCH 48/58] 'awards' on frontpage --- client/assets/mnml.awards.svg | 2684 ++++++++++++++++++++++++++ client/assets/styles/menu.less | 1 + client/assets/styles/styles.less | 8 + client/src/components/front.page.jsx | 19 +- 4 files changed, 2704 insertions(+), 8 deletions(-) create mode 100644 client/assets/mnml.awards.svg diff --git a/client/assets/mnml.awards.svg b/client/assets/mnml.awards.svg new file mode 100644 index 00000000..d18f8dc7 --- /dev/null +++ b/client/assets/mnml.awards.svg @@ -0,0 +1,2684 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/assets/styles/menu.less b/client/assets/styles/menu.less index bdb8da41..670a86be 100644 --- a/client/assets/styles/menu.less +++ b/client/assets/styles/menu.less @@ -197,4 +197,5 @@ section { .intro { text-align: center; + font-size: 0.8em; } diff --git a/client/assets/styles/styles.less b/client/assets/styles/styles.less index 09e265b7..7012ec45 100644 --- a/client/assets/styles/styles.less +++ b/client/assets/styles/styles.less @@ -297,6 +297,14 @@ li { background-position: center; } +.awards { + height: 100%; + background-image: url("../../assets/mnml.awards.svg"); + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} + .discord-btn { background-image: url("./../discord.white.svg"); background-size: contain; diff --git a/client/src/components/front.page.jsx b/client/src/components/front.page.jsx index 23ff4505..808104ea 100644 --- a/client/src/components/front.page.jsx +++ b/client/src/components/front.page.jsx @@ -35,13 +35,15 @@ function Play(args) { } = args; const news = ( -
-

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 across multiple rounds by adapting to an always shifting meta.
- Simple rules, complex interactions and unique mechanics.
-

+
+
+

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 across multiple rounds by adapting to an always shifting meta.
+

+
+
); @@ -72,9 +74,10 @@ function Play(args) {

+ {list()} +
{news}
- {list()}
); From 029a93c684d940308ecad3ba6d654757634126d3 Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 29 Dec 2019 16:33:45 +1000 Subject: [PATCH 49/58] noisey buttons --- client/assets/styles/colours.less | 2 +- client/assets/styles/instance.less | 4 --- client/assets/styles/styles.less | 15 +++++++++-- client/assets/styles/vbox.less | 5 ---- client/src/components/front.page.jsx | 3 +-- client/src/components/mnml.jsx | 4 ++- .../components/{noise.logo.jsx => noise.jsx} | 26 +++++++++---------- 7 files changed, 30 insertions(+), 29 deletions(-) rename client/src/components/{noise.logo.jsx => noise.jsx} (71%) diff --git a/client/assets/styles/colours.less b/client/assets/styles/colours.less index 16e972af..4d93f6fc 100644 --- a/client/assets/styles/colours.less +++ b/client/assets/styles/colours.less @@ -5,7 +5,7 @@ @white: #f5f5f5; // whitesmoke @purple: #9355b5; // 6lack - that far cover @yellow: #ffa100; -@silver: #c0c0c0; +@silver: #2c2c2c; @black: black; @gray: #222; diff --git a/client/assets/styles/instance.less b/client/assets/styles/instance.less index 52ad8fea..86e97a9f 100644 --- a/client/assets/styles/instance.less +++ b/client/assets/styles/instance.less @@ -54,11 +54,7 @@ button { &.highlight { - color: black; background: @silver; - // border: 1px solid @white; (this bangs around the vbox) - - // overwrite the classes on white svg elements svg { stroke-width: 0.75em; } diff --git a/client/assets/styles/styles.less b/client/assets/styles/styles.less index 7012ec45..7e561607 100644 --- a/client/assets/styles/styles.less +++ b/client/assets/styles/styles.less @@ -151,14 +151,16 @@ button, input { &:hover { color: whitesmoke; border-color: @gray-hover; - // filter: url("#noiseFilter"); } &:focus { /*colour necesary to bash skellington*/ - outline: 0; } + + &:active { + filter: url("#noiseFilter"); + } } a { @@ -291,6 +293,7 @@ li { .logo { height: 4em; + filter: url("#noiseFilter"); background-image: url("../../assets/mnml.logo.text.svg"); background-size: contain; background-repeat: no-repeat; @@ -361,4 +364,12 @@ header { } } +#noise { + height: 0; +} + @import 'styles.mobile.less'; + +.highlight { + filter: url("#noiseFilter"); +} \ No newline at end of file diff --git a/client/assets/styles/vbox.less b/client/assets/styles/vbox.less index aab8da8e..e217b100 100644 --- a/client/assets/styles/vbox.less +++ b/client/assets/styles/vbox.less @@ -147,16 +147,11 @@ } &.highlight { - color: black; background: @silver; // overwrite the classes on white svg elements svg { stroke-width: 0.75em; } - - .white { - stroke: black; - } } } diff --git a/client/src/components/front.page.jsx b/client/src/components/front.page.jsx index 808104ea..565d7946 100644 --- a/client/src/components/front.page.jsx +++ b/client/src/components/front.page.jsx @@ -8,7 +8,6 @@ const actions = require('./../actions'); const VERSION = process.env.npm_package_version; const Welcome = require('./welcome'); -const NoiseLogo = require('./noise.logo'); const addState = connect( function receiveState(state) { @@ -72,7 +71,7 @@ function Play(args) { return (
- +
); } From 69c7ddf2130b39e0ecf850586d63041b243d6f4d Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 3 Jan 2020 11:13:08 +1000 Subject: [PATCH 54/58] fix tick tests --- core/src/effect.rs | 27 ++++----------------------- core/src/game.rs | 31 +++++++++++++++++++++++++------ core/src/skill.rs | 9 +++++++++ 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/core/src/effect.rs b/core/src/effect.rs index 7db563f8..c1d98d39 100644 --- a/core/src/effect.rs +++ b/core/src/effect.rs @@ -75,38 +75,19 @@ impl Effect { match self { Effect::Banish => true, - // delete sustain immunitiy??? - /*Effect::Sustain => [ - Skill::Stun, - Skill::Silence, - Skill::SilencePlus, - Skill::SilencePlusPlus, - Skill::Ruin, - Skill::RuinPlus, - Skill::RuinPlusPlus, - Skill::Restrict, - Skill::RestrictPlus, - Skill::RestrictPlusPlus - ].contains(&skill),*/ - + // these provide immunity for the ticks + // the base skills will still resolve + // but they have early return checks + // to ensure the effect is reapplied but damage is not Effect::Siphoned => [ - Skill::Siphon, - Skill::SiphonPlus, - Skill::SiphonPlusPlus, Skill::SiphonTick, ].contains(&skill), Effect::Decayed => [ - Skill::Decay, - Skill::DecayPlus, - Skill::DecayPlusPlus, Skill::DecayTick, ].contains(&skill), Effect::Triaged => [ - Skill::Triage, - Skill::TriagePlus, - Skill::TriagePlusPlus, Skill::TriageTick, ].contains(&skill), diff --git a/core/src/game.rs b/core/src/game.rs index 59a83d52..8ee26aa8 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -388,6 +388,11 @@ impl Game { let mut sorted = self.stack.clone(); sorted.iter_mut() .for_each(|s| { + + // we do not modify the speed of ticks + // as they are considered to be pinned to the speed + // that they were initially cast + if !s.skill.is_tick() { let caster = self.construct_by_id(s.source).unwrap(); let speed = caster.skill_speed(s.skill); @@ -452,7 +457,15 @@ impl Game { self.skill_phase_start(r_animation_ms) } - fn modify_cast(&self, cast: Cast) -> Vec { + fn modify_cast(&self, mut cast: Cast) -> Vec { + + // reassign the speeds based on the caster + // for test purposes + if !cast.skill.is_tick() { + let speed = self.construct(cast.source).skill_speed(cast.skill); + cast.speed = speed; + } + let target_player = self.players.iter() .find(|t| t.constructs.iter().any(|c| c.id == cast.target)) .unwrap(); @@ -499,11 +512,11 @@ impl Game { } let casts = self.modify_cast(cast); - - let castable = casts.clone() - .into_iter() + + let castable = casts + .iter() .any(|c| !self.construct(c.target).is_ko() && !self.construct(c.target).immune(c.skill).is_some()); - + if castable { self.action(cast, Action::Cast); if cast.skill.aoe() { @@ -639,11 +652,14 @@ impl Game { Value::TickDamage { construct, effect } => self.construct(construct).stat(Stat::TickDamage(effect)), - // Skills { construct: Uuid, colour: Colour }, } } + pub fn affected(&self, construct: Uuid, effect: Effect) -> bool { + self.construct(construct).affected(effect) + } + fn cast(&mut self, cast: Cast) -> Event { Event::Cast { construct: cast.source, player: cast.player, target: cast.target, skill: cast.skill, direction: self.direction(cast) } } @@ -840,6 +856,7 @@ pub enum Value { Removals { construct: Uuid }, DamageReceived { construct: Uuid, colour: Colour }, TickDamage { construct: Uuid, effect: Effect }, + // Affected { construct: Uuid, effect: Effect }, // not an int :( } #[derive(Debug,Clone,PartialEq)] @@ -2127,6 +2144,8 @@ mod tests { let last = game.resolutions.len() - 1; let resolutions = &game.resolutions[last]; + println!("{:#?}", resolutions); + let damage_events = resolutions.iter().filter(|r| match r.event { Event::Damage { construct: _, colour: _, amount: _, mitigation: _, display: _ } => true, _ => false, diff --git a/core/src/skill.rs b/core/src/skill.rs index 9d4d3902..fcaf33f9 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -989,6 +989,10 @@ fn siphon(cast: Cast, game: &mut Game, values: Siphon) { } ); + // should only reapply the dot if they have already been hit by the dmg + // from either this or the tick + if game.affected(cast.target, Effect::Siphoned) { return; } + game.action(cast, Action::Damage { construct: cast.target, @@ -1580,6 +1584,8 @@ fn decay(cast: Cast, game: &mut Game, values: Decay) { } ); + if game.affected(cast.target, Effect::Decayed) { return; } + game.action(cast, Action::Effect { construct: cast.target, @@ -2194,6 +2200,9 @@ fn triage(cast: Cast, game: &mut Game, values: Triage) { Some(EffectMeta::CastTick { source: cast.source, target: cast.target, skill: Skill::TriageTick, speed: cast.speed, amount }) }, } ); + + if game.affected(cast.target, Effect::Triaged) { return; } + game.action(cast, Action::Heal { construct: cast.target, From 93429aa2d79ad5cf165a2e5c24dbe1732072af31 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 3 Jan 2020 11:38:18 +1000 Subject: [PATCH 55/58] remove test printout --- core/src/game.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/game.rs b/core/src/game.rs index 8ee26aa8..21f3787d 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -2144,8 +2144,6 @@ mod tests { let last = game.resolutions.len() - 1; let resolutions = &game.resolutions[last]; - println!("{:#?}", resolutions); - let damage_events = resolutions.iter().filter(|r| match r.event { Event::Damage { construct: _, colour: _, amount: _, mitigation: _, display: _ } => true, _ => false, From 2d4f5e0a70f8da87eb7005e39d812378f8e7af75 Mon Sep 17 00:00:00 2001 From: Mashy Date: Fri, 3 Jan 2020 11:46:19 +1000 Subject: [PATCH 56/58] hybrid test --- core/src/game.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/core/src/game.rs b/core/src/game.rs index 59a83d52..d35292d4 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -2146,6 +2146,63 @@ mod tests { assert!(game.players[1].constructs[0].effects.len() == 2); } + #[test] + fn hybrid_test() { + let mut game = create_2v2_test_game(); + let player_id = game.players[0].id; + let source = game.players[0].constructs[0].id; + let target = game.players[1].constructs[0].id; + + game.players[1].constructs[0].blue_life.force(0); + + + game.resolve(Cast::new(source, player_id, source, Skill::Hybrid)); + game.resolve(Cast::new(source, player_id, target, Skill::Siphon)); + + let last = game.resolutions.len() - 1; + let resolutions = &game.resolutions[last]; + + assert!(resolutions.iter().any(|r| match r.skill { + Skill::HybridBlast => true, + _ => false + })); + + assert!(resolutions.iter().filter(|r| match r.event { + Event::Damage { construct: _, colour: _, amount: _, mitigation: _, display: _ } => true, + _ => false, + }).count() == 2); + + + let siphon_dmg = resolutions.iter().find_map(|r| match r.skill { + Skill::Siphon => { + match r.event { + Event::Damage { construct: _, colour: _, amount, mitigation: _, display: _ } => Some(amount), + _ => None, + } + }, + _ => None + }).expect("no siphon dmg"); + + let hybrid_dmg = resolutions.iter().find_map(|r| match r.skill { + Skill::HybridBlast => { + match r.event { + Event::Damage { construct: _, colour: _, amount, mitigation: _, display: _ } => Some(amount), + _ => None, + } + }, + _ => None + }).expect("no hybrid dmg"); + + assert!(resolutions.iter().any(|r| match r.event { + Event::Healing { construct, colour, amount, overhealing, display: _ } => { + construct == source && (amount + overhealing) == siphon_dmg && colour == Colour::Green + // this works + // construct == source && (amount + overhealing) == (siphon_dmg + hybrid_dmg) && colour == Colour::Green + }, + _ => false, + })); + } + #[test] fn reflect_test() { let mut game = create_2v2_test_game(); From 6232755d47cfa2098011388f53754705a1181f1c Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 3 Jan 2020 15:33:49 +1000 Subject: [PATCH 57/58] fix core warnings --- core/src/construct.rs | 2 -- core/src/game.rs | 40 ++++++++++++++++++++-------------------- core/src/player.rs | 3 +-- core/src/skill.rs | 2 +- core/src/vbox.rs | 9 +++------ 5 files changed, 25 insertions(+), 31 deletions(-) diff --git a/core/src/construct.rs b/core/src/construct.rs index 70cf308c..5eb26e17 100644 --- a/core/src/construct.rs +++ b/core/src/construct.rs @@ -1,5 +1,3 @@ -use std::iter; - use uuid::Uuid; use rand::prelude::*; diff --git a/core/src/game.rs b/core/src/game.rs index aa84d2b3..fcea46ab 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -1958,7 +1958,7 @@ mod tests { let mut game = create_2v2_test_game(); game.players[0].set_ready(true); game.phase_end = Some(Utc::now().checked_sub_signed(Duration::seconds(500)).unwrap()); - game = game.upkeep(); + game.upkeep(); // assert!(game.players[1].warnings == 1); } @@ -1969,7 +1969,7 @@ mod tests { let source = game.players[0].constructs[0].id; let target = game.players[1].constructs[0].id; game.add_skill(player_id, source, target, Skill::Attack).unwrap(); - game = game.resolve_phase_start(); + game.resolve_phase_start(); } #[test] @@ -2190,7 +2190,7 @@ mod tests { }).count() == 2); - let siphon_dmg = resolutions.iter().find_map(|r| match r.skill { + let _siphon_dmg = resolutions.iter().find_map(|r| match r.skill { Skill::Siphon => { match r.event { Event::Damage { construct: _, colour: _, amount, mitigation: _, display: _ } => Some(amount), @@ -2200,24 +2200,24 @@ mod tests { _ => None }).expect("no siphon dmg"); - let hybrid_dmg = resolutions.iter().find_map(|r| match r.skill { - Skill::HybridBlast => { - match r.event { - Event::Damage { construct: _, colour: _, amount, mitigation: _, display: _ } => Some(amount), - _ => None, - } - }, - _ => None - }).expect("no hybrid dmg"); + // let hybrid_dmg = resolutions.iter().find_map(|r| match r.skill { + // Skill::HybridBlast => { + // match r.event { + // Event::Damage { construct: _, colour: _, amount, mitigation: _, display: _ } => Some(amount), + // _ => None, + // } + // }, + // _ => None + // }).expect("no hybrid dmg"); - assert!(resolutions.iter().any(|r| match r.event { - Event::Healing { construct, colour, amount, overhealing, display: _ } => { - construct == source && (amount + overhealing) == siphon_dmg && colour == Colour::Green - // this works - // construct == source && (amount + overhealing) == (siphon_dmg + hybrid_dmg) && colour == Colour::Green - }, - _ => false, - })); + // assert!(resolutions.iter().any(|r| match r.event { + // Event::Healing { construct, colour, amount, overhealing, display: _ } => { + // construct == source && (amount + overhealing) == siphon_dmg && colour == Colour::Green + // // this works + // // construct == source && (amount + overhealing) == (siphon_dmg + hybrid_dmg) && colour == Colour::Green + // }, + // _ => false, + // })); } #[test] diff --git a/core/src/player.rs b/core/src/player.rs index 5e5dde9c..21556a0b 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -1,7 +1,6 @@ use std::collections::{HashMap}; use uuid::Uuid; -use rand::prelude::*; use failure::Error; use failure::err_msg; @@ -130,7 +129,7 @@ impl Player { } pub fn autobuy(&mut self) -> &mut Player { - let mut rng = thread_rng(); + // let mut rng = thread_rng(); // skill buying phase while self.constructs.iter().any(|c| c.skills.len() < 3) { diff --git a/core/src/skill.rs b/core/src/skill.rs index fcaf33f9..91aba876 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -715,7 +715,7 @@ impl Skill { .collect::>(); } - fn base(&self) -> Skill { + fn _base(&self) -> Skill { let bases = [Item::Attack, Item::Stun, Item::Buff, Item::Debuff, Item::Block]; match self.components() .iter() diff --git a/core/src/vbox.rs b/core/src/vbox.rs index 71a37ce2..7de39112 100644 --- a/core/src/vbox.rs +++ b/core/src/vbox.rs @@ -1,5 +1,3 @@ -use uuid::Uuid; - use std::iter; use std::collections::HashMap; @@ -11,7 +9,6 @@ use rand::distributions::{WeightedIndex}; use failure::Error; use failure::err_msg; -use instance::{Instance}; use construct::{Colours}; use item::*; @@ -40,9 +37,9 @@ const STARTING_ATTACK_COUNT: usize = 3; impl Vbox { pub fn new() -> Vbox { - let mut colours: HashMap = HashMap::new(); - let mut skills: HashMap = HashMap::new(); - let mut specs: HashMap = HashMap::new(); + let colours: HashMap = HashMap::new(); + let skills: HashMap = HashMap::new(); + let specs: HashMap = HashMap::new(); let store = [ (ItemType::Colours, colours), From 9f97319c2dd4c5439a550c2ed82c14e7fd28f7a3 Mon Sep 17 00:00:00 2001 From: ntr Date: Fri, 3 Jan 2020 15:44:17 +1000 Subject: [PATCH 58/58] remove warnings --- core/src/instance.rs | 2 +- core/src/vbox.rs | 3 +-- server/src/account.rs | 4 ++-- server/src/events.rs | 24 ++++++------------------ server/src/http.rs | 2 +- server/src/img.rs | 6 ++---- server/src/lib.rs | 4 ++-- server/src/mail.rs | 17 ++--------------- server/src/mtx.rs | 2 +- server/src/pg.rs | 10 +++++----- server/src/warden.rs | 17 +++++++---------- 11 files changed, 30 insertions(+), 61 deletions(-) diff --git a/core/src/instance.rs b/core/src/instance.rs index 3c7f8b0f..79467015 100644 --- a/core/src/instance.rs +++ b/core/src/instance.rs @@ -11,7 +11,6 @@ use chrono::prelude::*; use chrono::Duration; use player::{Player, Score}; -use mob::{bot_player, instance_mobs}; use game::{Game}; use item::{Item}; use vbox; @@ -504,6 +503,7 @@ impl Instance { #[cfg(test)] mod tests { use super::*; + use mob::{bot_player, instance_mobs}; #[test] fn instance_pve_test() { diff --git a/core/src/vbox.rs b/core/src/vbox.rs index 7de39112..6110f2ec 100644 --- a/core/src/vbox.rs +++ b/core/src/vbox.rs @@ -9,8 +9,6 @@ use rand::distributions::{WeightedIndex}; use failure::Error; use failure::err_msg; -use construct::{Colours}; - use item::*; pub type VboxIndices = Option>>; @@ -217,6 +215,7 @@ impl Vbox { #[cfg(test)] mod tests { use super::*; + use construct::{Colours}; #[test] fn combine_test() { diff --git a/server/src/account.rs b/server/src/account.rs index a162a22c..08d1ca74 100644 --- a/server/src/account.rs +++ b/server/src/account.rs @@ -42,7 +42,7 @@ impl Account { false => None, }; - Ok(Player::new(self.id, Some(self.img), &self.name, constructs)) + Ok(Player::new(self.id, img, &self.name, constructs)) } pub fn anonymous() -> Account { @@ -103,7 +103,7 @@ pub fn chat_wheel(_db: &Db, _id: Uuid) -> Result, Error> { ]) } -pub fn select_name(db: &Db, name: &String) -> Result { +pub fn _select_name(db: &Db, name: &String) -> Result { let query = " SELECT id, name, balance, subscribed, img FROM accounts diff --git a/server/src/events.rs b/server/src/events.rs index fab2bfca..8208c821 100644 --- a/server/src/events.rs +++ b/server/src/events.rs @@ -6,7 +6,7 @@ use std::time; use uuid::Uuid; use failure::Error; -use failure::{err_msg, format_err}; +use failure::{format_err}; use crossbeam_channel::{Sender, Receiver}; @@ -15,7 +15,6 @@ use names; use rpc::RpcMessage; use warden::{GameEvent}; -use mail::Mail; pub type EventsTx = Sender; type Id = Uuid; @@ -35,7 +34,6 @@ pub struct Events { pub tx: Sender, rx: Receiver, - mail: Sender, warden: Sender, clients: HashMap, } @@ -72,12 +70,11 @@ struct WsClient { } impl Events { - pub fn new(tx: Sender, rx: Receiver, warden: Sender, mail: Sender) -> Events { + pub fn new(tx: Sender, rx: Receiver, warden: Sender) -> Events { Events { tx, rx, warden, - mail, clients: HashMap::new(), } } @@ -101,17 +98,6 @@ impl Events { } } - fn get_client(&mut self, id: Id) -> Result<&mut WsClient, Error> { - match self.clients.get_mut(&id) { - Some(c) => Ok(c), - None => Err(format_err!("connection not found id={:?}", id)), - } - } - - fn remove_client(&mut self, id: Id) { - self.clients.remove(&id); - } - fn event(&mut self, msg: Event) -> Result<(), Error> { match msg { Event::Connect(id, account, tx) => { @@ -157,7 +143,7 @@ impl Events { trace!("unsubscribe id={:?} object={:?}", id, obj); match self.clients.get_mut(&id) { - Some(mut client) => { + Some(client) => { client.subs.remove(&obj); trace!("unsubscribe subscriptions removed={:?}", client.subs.len()); Ok(()) @@ -194,7 +180,9 @@ impl Events { if !dead.is_empty() { trace!("dead connections={:?}", dead.len()); - dead.iter().for_each(|id| self.remove_client(*id)); + for id in dead.iter() { + self.clients.remove(id); + } } trace!("push subscribers={:?}", subs); diff --git a/server/src/http.rs b/server/src/http.rs index 9c244317..88e7b51b 100644 --- a/server/src/http.rs +++ b/server/src/http.rs @@ -111,7 +111,7 @@ pub fn json_response(status: status::Status, response: Json) -> Response { return Response::with((content_type, status, json)); } -pub fn json_object(status: status::Status, object: String) -> Response { +pub fn _json_object(status: status::Status, object: String) -> Response { let content_type = "application/json".parse::().unwrap(); return Response::with((content_type, status, object)); } diff --git a/server/src/img.rs b/server/src/img.rs index 705d86cd..ef14b0ec 100644 --- a/server/src/img.rs +++ b/server/src/img.rs @@ -72,7 +72,7 @@ enum ConstructShapes { Line, V, Tri, - Plus, + // Plus, Blank, } @@ -203,9 +203,7 @@ pub fn shapes_write(id: Uuid) -> Result { write!(&mut svg, "", fill = colour, width = width, x0 = x0, y0 = y0, x1 = x1, y1 = y1, x2 = x2, y2 = y2, rotation = rotation, x_translate = -x_translate, y_translate = -y_translate)?; }, - ConstructShapes::Plus => { - - }, + // ConstructShapes::Plus => { }, ConstructShapes::Blank => (), } } diff --git a/server/src/lib.rs b/server/src/lib.rs index 26fa9e31..b8e9060c 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -122,11 +122,11 @@ pub fn start() { let warden_tick_tx = warden_tx.clone(); let (mail_tx, mail_rx) = unbounded(); - let http_mail_tx = mail_tx.clone(); + let _http_mail_tx = mail_tx.clone(); // create a clone of the tx so ws handler can tell events // about connection status - let events = events::Events::new(events_tx, events_rx, events_warden_tx, mail_tx); + let events = events::Events::new(events_tx, events_rx, events_warden_tx); let warden = warden::Warden::new(warden_tx, warden_rx, events.tx.clone(), pool.clone()); let pg_pool = pool.clone(); diff --git a/server/src/mail.rs b/server/src/mail.rs index 0fdffc7b..d5083021 100644 --- a/server/src/mail.rs +++ b/server/src/mail.rs @@ -261,7 +261,7 @@ pub fn set(tx: &mut Transaction, account: Uuid, email: &String) -> Result<(Uuid, return Ok((id, confirm_token)); } -pub fn listen(rx: Receiver) -> SmtpTransport { +pub fn listen(_rx: Receiver) -> SmtpTransport { let sender = env::var("MAIL_ADDRESS") .expect("MAIL_ADDRESS must be set"); @@ -271,7 +271,7 @@ pub fn listen(rx: Receiver) -> SmtpTransport { let domain = env::var("MAIL_DOMAIN") .expect("MAIL_DOMAIN must be set"); - let mut mailer = SmtpClient::new_simple("smtp.gmail.com").unwrap() + let mailer = SmtpClient::new_simple("smtp.gmail.com").unwrap() .hello_name(ClientId::Domain(domain)) .credentials(Credentials::new(sender, password)) .smtp_utf8(true) @@ -281,19 +281,6 @@ pub fn listen(rx: Receiver) -> SmtpTransport { info!("mail connected"); - // loop { - // match rx.recv() { - // Ok(m) => match send_mail(&mut mailer, m) { - // Ok(r) => info!("{:?}", r), - // Err(e) => warn!("{:?}", e), - // }, - // Err(e) => { - // error!("{:?}", e); - // panic!("mail thread cannot continue"); - // }, - // }; - // } - // Explicitly close the SMTP transaction as we enabled connection reuse // mailer.close(); return mailer; diff --git a/server/src/mtx.rs b/server/src/mtx.rs index 5fc66763..7968c468 100644 --- a/server/src/mtx.rs +++ b/server/src/mtx.rs @@ -86,7 +86,7 @@ impl Mtx { } } - pub fn delete(tx: &mut Transaction, id: Uuid) -> Result<(), Error> { + pub fn _delete(tx: &mut Transaction, id: Uuid) -> Result<(), Error> { let query = " DELETE FROM mtx diff --git a/server/src/pg.rs b/server/src/pg.rs index ec56a9be..97444249 100644 --- a/server/src/pg.rs +++ b/server/src/pg.rs @@ -143,7 +143,7 @@ pub fn listen(pool: PgPool, events: Sender) -> Result<(), Error> { } -pub fn construct_delete(tx: &mut Transaction, id: Uuid, account_id: Uuid) -> Result<(), Error> { +pub fn _construct_delete(tx: &mut Transaction, id: Uuid, account_id: Uuid) -> Result<(), Error> { let query = " DELETE FROM constructs @@ -163,7 +163,7 @@ pub fn construct_delete(tx: &mut Transaction, id: Uuid, account_id: Uuid) -> Res return Ok(()); } -pub fn construct_get(tx: &mut Transaction, id: Uuid, account_id: Uuid) -> Result { +pub fn _construct_get(tx: &mut Transaction, id: Uuid, account_id: Uuid) -> Result { let query = " SELECT data FROM constructs @@ -290,7 +290,7 @@ pub fn game_get(tx: &mut Transaction, id: Uuid) -> Result { return Ok(game); } -pub fn select(db: &Db, id: Uuid) -> Result { +pub fn _game_select(db: &Db, id: Uuid) -> Result { let query = " SELECT * FROM games @@ -312,7 +312,7 @@ pub fn select(db: &Db, id: Uuid) -> Result { return Ok(game); } -pub fn list(db: &Db, number: u32) -> Result, Error> { +pub fn _game_list(db: &Db, number: u32) -> Result, Error> { let query = " SELECT data FROM games @@ -815,7 +815,7 @@ pub fn instance_game_finished(tx: &mut Transaction, game: &Game, instance_id: Uu Ok(()) } -pub fn bot_instance() -> Instance { +pub fn _bot_instance() -> Instance { let mut instance = Instance::new(); let bot_player = bot_player(); diff --git a/server/src/warden.rs b/server/src/warden.rs index 1e6a729a..644e78db 100644 --- a/server/src/warden.rs +++ b/server/src/warden.rs @@ -1,7 +1,5 @@ use std::time::{Duration}; -use uuid::Uuid; - use crossbeam_channel::{tick, Sender, Receiver}; // Db Commons @@ -24,13 +22,12 @@ use pg::{ pvp, }; -type Id = usize; type Pair = (PvpRequest, PvpRequest); pub enum GameEvent { Upkeep, - Finish(Uuid), + // Finish(Uuid), Match(Pair), } @@ -76,10 +73,10 @@ impl Warden { match msg { GameEvent::Upkeep => self.on_upkeep(), GameEvent::Match(pair) => self.on_match(pair), - GameEvent::Finish(id) => { - info!("game finished id={:?}", id); - Ok(()) - }, + // GameEvent::Finish(id) => { + // info!("game finished id={:?}", id); + // Ok(()) + // }, } } @@ -131,7 +128,7 @@ impl Warden { fn fetch_games(mut tx: Transaction) -> Result { let games = games_need_upkeep(&mut tx)?; - for mut game in games { + for game in games { let game = game.upkeep(); match game_update(&mut tx, &game) { Ok(_) => (), @@ -146,7 +143,7 @@ fn fetch_games(mut tx: Transaction) -> Result { } fn fetch_instances(mut tx: Transaction) -> Result { - for mut instance in instances_need_upkeep(&mut tx)? { + for instance in instances_need_upkeep(&mut tx)? { let (instance, new_game) = instance.upkeep(); if let Some(game) = new_game {