diff --git a/client/src/animations.socket.jsx b/client/src/animations.socket.jsx index b81e752b..71f35de2 100644 --- a/client/src/animations.socket.jsx +++ b/client/src/animations.socket.jsx @@ -4,9 +4,7 @@ const toast = require('izitoast'); const eachSeries = require('async/eachSeries'); const actions = require('./actions'); -const { TIMES } = require('./constants'); -const animations = require('./animations.utils'); -const { removeTier } = require('./utils'); +const { setAnimations, clearAnimations } = require('./animations.utils'); const SOCKET_URL = process.env.NODE_ENV === 'production' ? 'wss://mnml.gg/api/ws' : 'ws://localhost/api/ws'; @@ -20,73 +18,32 @@ function createSocket(store) { ws.send(cbor.encode(msg)); } - function sendDevResolve(a, b, skill) { - send(['DevResolve', { a, b, skill }]); + function sendDevResolve(skill) { + send(['DevResolve', { skill }]); } - function onDevResolutions(newRes) { - const { game, account, animating } = store.getState(); - - if (animating) return false; + function setGame(game) { + store.dispatch(actions.setGame(game)); store.dispatch(actions.setAnimating(true)); + store.dispatch(actions.setGameSkillInfo(null)); // stop fetching the game state til animations are done - + const newRes = game.resolutions[game.resolutions.length - 1]; return eachSeries(newRes, (r, cb) => { - if (!r.event) return cb(); - const timeout = animations.getTime(r.stages); - const anims = animations.getObjects(r, game, account); - const text = animations.getText(r); - store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r, game))); - if (anims.animSkill) store.dispatch(actions.setAnimSkill(anims.animSkill)); - - if (r.stages.includes('START_SKILL') && anims.animSource) { - store.dispatch(actions.setAnimSource(anims.animSource)); - } - - if (r.stages.includes('END_SKILL') && anims.animTarget) { - store.dispatch(actions.setAnimTarget(anims.animTarget)); - if (animations.isCbAnim(anims.animSkill)) store.dispatch(actions.setAnimCb(cb)); - } - - if (r.stages.includes('POST_SKILL') && text) { - // timeout to prevent text classes from being added too soon - if (timeout === TIMES.POST_SKILL_DURATION_MS) { - store.dispatch(actions.setResolution(text)); - } else { - setTimeout( - () => store.dispatch(actions.setResolution(text)), - timeout - TIMES.POST_SKILL_DURATION_MS - ); - } - } - - return setTimeout(() => { - store.dispatch(actions.setAnimSkill(null)); - store.dispatch(actions.setAnimSource(null)); - store.dispatch(actions.setAnimTarget(null)); - store.dispatch(actions.setResolution(null)); - store.dispatch(actions.setAnimFocus([])); - if (r.stages.includes('END_SKILL') && animations.isCbAnim(anims.animSkill)) return true; - return cb(); - }, timeout); + // if (r.delay === 0) return cb(); // TargetKo etc + setAnimations(r, store); + return setTimeout(cb, r.delay); }, err => { if (err) return console.error(err); - // clear animation state - store.dispatch(actions.setAnimSkill(null)); - store.dispatch(actions.setAnimSource(null)); - store.dispatch(actions.setAnimTarget(null)); - store.dispatch(actions.setResolution(null)); - store.dispatch(actions.setAnimating(false)); - store.dispatch(actions.setGameEffectInfo(null)); - + clearAnimations(store); // set the game state so resolutions don't fire twice store.dispatch(actions.setGame(game)); + // ws.sendGameState(game.id); return true; }); } const handlers = { - DevResolutions: onDevResolutions, + GameState: setGame, }; // decodes the cbor and diff --git a/client/src/animations.test.jsx b/client/src/animations.test.jsx index e230a58b..e78ccce1 100644 --- a/client/src/animations.test.jsx +++ b/client/src/animations.test.jsx @@ -5,18 +5,7 @@ const { createStore, combineReducers } = require('redux'); const reducers = require('./reducers'); const actions = require('./actions'); const createSocket = require('./animations.socket'); - -// const TrippyTriangle = require('./components/svgs/trippy.triangle'); -// const Amplify = require('./components/svgs/amplify'); -// const Hex = require('./components/svgs/hex'); const Game = require('./components/game'); -const testGameBuilder = require('./test.game'); - -const testGame = testGameBuilder('8552e0bf-340d-4fc8-b6fc-cccccccccccc'); -const testAccount = { - id: '8552e0bf-340d-4fc8-b6fc-cccccccccccc', - name: 'ntr', -}; // Redux Store const store = createStore( @@ -24,20 +13,15 @@ const store = createStore( window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(), ); +const testAccount = { + id: '8552e0bf-340d-4fc8-b6fc-cccccccccccc', + name: 'ntr', +}; store.dispatch(actions.setAccount(testAccount)); -store.dispatch(actions.setGame(testGame)); function animationsNav(ws) { function useSkill(skill) { - const ateam = Math.round(Math.random()); - const bteam = Math.round(Math.random()); - const acon = Math.floor(Math.random() * 3); - const bcon = Math.floor(Math.random() * 3); - - const a = testGame.players[ateam].constructs[acon].id; - const b = testGame.players[bteam].constructs[bcon].id; - - return ws.sendDevResolve(a, b, skill); + return ws.sendDevResolve(skill); } return SKILLS.map((s, i) => ( @@ -81,19 +65,19 @@ const SKILLS = [ 'Buff', 'Chaos', 'Counter', - 'CounterAttack', + // 'CounterAttack', 'Curse', 'Debuff', 'Decay', 'DecayTick', 'Electrify', 'Electrocute', - 'ElectrocuteTick', + // 'ElectrocuteTick', 'Haste', - 'HasteStrike', + // 'HasteStrike', 'Heal', 'Hybrid', - 'HybridBlast', + // 'HybridBlast', 'Intercept', 'Invert', 'Link', @@ -105,12 +89,12 @@ const SKILLS = [ 'Ruin', 'Silence', 'Siphon', - 'SiphonTick', + // 'SiphonTick', 'Slay', 'Sleep', 'Strike', 'Stun', 'Sustain', 'Triage', - 'TriageTick', + // 'TriageTick', ]; diff --git a/client/src/components/animations.jsx b/client/src/components/animations.jsx index 38aaa2b6..485dcacd 100644 --- a/client/src/components/animations.jsx +++ b/client/src/components/animations.jsx @@ -75,7 +75,6 @@ class ConstructAnimation extends Component { const animSkill = removeTier(skill); if (!constructId.includes(construct.id)) return false; - // find target animation const chooseAnim = () => { switch (animSkill) { diff --git a/client/src/events.jsx b/client/src/events.jsx index 94b7c96b..240d9bf1 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -87,7 +87,6 @@ function registerEvents(store) { store.dispatch(actions.setGameSkillInfo(null)); // stop fetching the game state til animations are done const newRes = game.resolutions[game.resolutions.length - 1]; - console.log(newRes); return eachSeries(newRes, (r, cb) => { if (r.delay === 0) return cb(); // TargetKo etc setAnimations(r, store); diff --git a/core/src/game.rs b/core/src/game.rs index a5bacbda..6724e12b 100644 --- a/core/src/game.rs +++ b/core/src/game.rs @@ -1596,54 +1596,53 @@ mod tests { // } - // #[test] - // fn sleep_cooldown_test() { - // let mut game = create_test_game(); + #[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_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(); + 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); + 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()); + // 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(); + 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()); + // 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(); + 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()); + // 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(); + 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()); - // } - - // } + // 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() { @@ -1885,52 +1884,52 @@ mod tests { // } // } - // #[test] - // fn ko_pve_test() { - // let mut game = create_2v2_test_game(); + #[test] + fn ko_pve_test() { + let mut game = create_2v2_test_game(); - // let i_player = game.players[0].clone(); - // let x_player = game.players[1].clone(); + let i_player = game.players[0].clone(); + let x_player = game.players[1].clone(); - // let i_construct = i_player.constructs[0].clone(); - // let j_construct = i_player.constructs[1].clone(); - // let x_construct = x_player.constructs[0].clone(); - // let y_construct = x_player.constructs[1].clone(); + let i_construct = i_player.constructs[0].clone(); + let j_construct = i_player.constructs[1].clone(); + let x_construct = x_player.constructs[0].clone(); + let y_construct = x_player.constructs[1].clone(); - // game.add_skill(i_player.id, i_construct.id, x_construct.id, Skill::Attack).unwrap() - // .add_skill(i_player.id, j_construct.id, x_construct.id, Skill::Attack).unwrap() - // .add_skill(x_player.id, x_construct.id, i_construct.id, Skill::Attack).unwrap() - // .add_skill(x_player.id, y_construct.id, i_construct.id, Skill::Attack).unwrap() - // .player_ready(i_player.id).unwrap() - // .player_ready(x_player.id).unwrap(); + game.add_skill(i_player.id, i_construct.id, x_construct.id, Skill::Attack).unwrap() + .add_skill(i_player.id, j_construct.id, x_construct.id, Skill::Attack).unwrap() + .add_skill(x_player.id, x_construct.id, i_construct.id, Skill::Attack).unwrap() + .add_skill(x_player.id, y_construct.id, i_construct.id, Skill::Attack).unwrap() + .player_ready(i_player.id).unwrap() + .player_ready(x_player.id).unwrap(); - // assert!(game.skill_phase_finished()); - // game = game.resolve_phase_start(); + assert!(game.skill_phase_finished()); + game = game.resolve_phase_start(); - // assert!([Phase::Skill, Phase::Finished].contains(&game.phase)); + assert!([Phase::Skill, Phase::Finished].contains(&game.phase)); - // // kill a construct - // game.player_by_id(i_player.id).unwrap().construct_by_id(i_construct.id).unwrap().green_life.reduce(usize::max_value()); + // kill a construct + game.player_by_id(i_player.id).unwrap().construct_by_id(i_construct.id).unwrap().green_life.reduce(usize::max_value()); - // assert!(game.player_by_id(i_player.id).unwrap().skills_required() == 1); - // assert!(game.player_by_id(x_player.id).unwrap().skills_required() == 2); + assert!(game.player_by_id(i_player.id).unwrap().skills_required() == 1); + assert!(game.player_by_id(x_player.id).unwrap().skills_required() == 2); - // // add some more skills - // game.add_skill(i_player.id, j_construct.id, x_construct.id, Skill::Attack).unwrap(); - // game.add_skill(x_player.id, x_construct.id, j_construct.id, Skill::Attack).unwrap(); - // game.add_skill(x_player.id, y_construct.id, j_construct.id, Skill::Attack).unwrap(); - // assert!(game.add_skill(x_player.id, x_construct.id, i_construct.id, Skill::Attack).is_err()); + // add some more skills + game.add_skill(i_player.id, j_construct.id, x_construct.id, Skill::Attack).unwrap(); + game.add_skill(x_player.id, x_construct.id, j_construct.id, Skill::Attack).unwrap(); + game.add_skill(x_player.id, y_construct.id, j_construct.id, Skill::Attack).unwrap(); + assert!(game.add_skill(x_player.id, x_construct.id, i_construct.id, Skill::Attack).is_err()); - // game.player_ready(i_player.id).unwrap(); - // game.player_ready(x_player.id).unwrap(); + game.player_ready(i_player.id).unwrap(); + game.player_ready(x_player.id).unwrap(); - // assert!(game.skill_phase_finished()); - // game = game.resolve_phase_start(); + assert!(game.skill_phase_finished()); + game = game.resolve_phase_start(); - // assert!(game.player_by_id(i_player.id).unwrap().skills_required() == 1); - // assert!(game.player_by_id(x_player.id).unwrap().skills_required() == 2); - // return; - // } + assert!(game.player_by_id(i_player.id).unwrap().skills_required() == 1); + assert!(game.player_by_id(x_player.id).unwrap().skills_required() == 2); + return; + } // #[test] // fn tick_removal_test() { diff --git a/core/src/mob.rs b/core/src/mob.rs index 2dc40a27..479acb43 100644 --- a/core/src/mob.rs +++ b/core/src/mob.rs @@ -1,10 +1,13 @@ use uuid::Uuid; use std::iter; +use rand::prelude::*; use construct::{Construct}; use names::{name}; use player::{Player}; +use game::{Game}; +use skill::{Skill, Cast}; pub fn generate_mob() -> Construct { let mob = Construct::new() @@ -28,3 +31,51 @@ pub fn bot_player() -> Player { Player::new(bot_id, None, &name(), constructs).set_bot(true) } +pub fn anim_test_game(skill: Skill) -> Game { + let mut rng = thread_rng(); + let mut game = Game::new(); + + game + .set_player_num(2) + .set_player_constructs(3); + + let x_id = Uuid::parse_str("8552e0bf-340d-4fc8-b6fc-cccccccccccc").unwrap(); + let constructs = iter::repeat_with(|| + generate_mob() + .set_account(x_id) + .learn(Skill::Attack)) + .take(3) + .collect::>(); + let x_player = Player::new(x_id, None, &name(), constructs); + + let id = Uuid::new_v4(); + let constructs = iter::repeat_with(|| + generate_mob() + .set_account(id) + .learn(Skill::Attack)) + .take(3) + .collect::>(); + let y_player = Player::new(id, None, &name(), constructs); + + game + .player_add(x_player).unwrap() + .player_add(y_player).unwrap(); + + game = game.start(); + + let x_id = game.players[0].id; + let x_construct = game.players[0].constructs[1].id; + + let y_id = game.players[1].id; + let y_construct = game.players[1].constructs[1].id; + + let cast = match rng.gen_bool(0.5) { + true => Cast::new(x_construct, x_id, y_construct, skill), + false => Cast::new(y_construct, y_id, x_construct, skill), + }; + + game.stack.push(cast); + game = game.resolve_phase_start(); + return game; +} + diff --git a/core/src/skill.rs b/core/src/skill.rs index 8e0326c6..b75ddeca 100644 --- a/core/src/skill.rs +++ b/core/src/skill.rs @@ -199,20 +199,6 @@ impl Cast { } } -// pub fn dev_resolve(a_id: Uuid, b_id: Uuid, skill: Skill) { -// let mut resolutions =vec![]; - -// let mut a = Construct::new(); -// a.id = a_id; -// let mut b = Construct::new(); -// b.id = b_id; -// if skill.aoe() { // Send an aoe skill event for anims -// game.event(Event::new(&a, &b).event(Event::AoeSkill { skill }).stages(EventStages::StartEnd)); -// } -// return cast_actions(skill, &mut a, &mut b, resolutions); -// } - - #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub enum Skill { Attack, @@ -894,7 +880,7 @@ fn attack(cast: Cast, game: &mut Game, values: Attack) { enum Blast { Base, Plus, PlusPlus, Hybrid } impl Blast { fn dmg_multi(self) -> usize { - match self { + match self { Blast::Base => 105, Blast::Plus => 125, Blast::PlusPlus => 145, @@ -931,7 +917,7 @@ impl Chaos { fn description(self) -> String { format!("Hits twice for red and blue damage. Damage {:?}% RedPower and BluePower. Randomly deals 0 to 30% more damage.", self.dmg_multi()) - } + } } fn chaos(cast: Cast, game: &mut Game, values: Chaos) { @@ -961,7 +947,7 @@ impl Heal { } fn description(self) -> String { format!("Heals target for {:?}% GreenPower.", self.heal_multiplier()) - } + } } @@ -1283,7 +1269,7 @@ impl Absorb { Absorption increases RedPower and BluePower based on damage taken. Absorption lasts {:?}T. Recharges BlueLife based on {:?}% BluePower.", self.duration(), - match self { + match self { Absorb::Base => Absorption::Base.duration(), Absorb::Plus => Absorption::Plus.duration(), Absorb::PlusPlus => Absorption::PlusPlus.duration(), @@ -1297,7 +1283,7 @@ fn absorb(cast: Cast, game: &mut Game, values: Absorb) { game.action(cast, Action::Effect { construct: cast.target, - effect: ConstructEffect { + effect: ConstructEffect { effect: Effect::Absorb, duration: values.duration(), meta: Some(EffectMeta::CastOnHit(values.absorption_skill())) }, @@ -1483,7 +1469,7 @@ fn curse(cast: Cast, game: &mut Game, values: Curse) { game.action(cast, Action::Effect { construct: cast.target, - effect: ConstructEffect { + effect: ConstructEffect { effect: Effect::Curse, duration: values.curse_duration(), meta: Some(EffectMeta::Multiplier(values.curse_multi())) @@ -1603,10 +1589,10 @@ fn decay(cast: Cast, game: &mut Game, values: Decay) { game.action(cast, Action::Effect { construct: cast.target, - effect: ConstructEffect { + effect: ConstructEffect { effect: Effect::Wither, duration: values.wither_duration(), - meta: Some(EffectMeta::Multiplier(values.wither_multiplier())) + meta: Some(EffectMeta::Multiplier(values.wither_multiplier())) }, } ); @@ -1653,11 +1639,11 @@ impl Electrify { Electrify::PlusPlus => Skill::ElectrocutePlusPlus, } } - + fn duration(self) -> u8 { match self { Electrify::Base => 1, Electrify::Plus => 1, Electrify::PlusPlus => 2 } } - + fn description(self) -> String { let electro = match self { Electrify::Base => Electrocute::Base, @@ -2228,4 +2214,4 @@ fn triage_tick(cast: Cast, game: &mut Game) { effect: ConstructEffect { effect: Effect::Triaged, duration: 1, meta: None }, }, ); -} \ No newline at end of file +} diff --git a/server/src/rpc.rs b/server/src/rpc.rs index 238b0015..9fd4e824 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -53,7 +53,7 @@ use mnml_core::player::Player; use mnml_core::vbox::{ItemType}; use mnml_core::item::Item; use mnml_core::skill::Skill; -// use mnml_core::skill::{dev_resolve, Resolutions}; +use mnml_core::mob::{anim_test_game}; use mnml_core::instance::{Instance}; use mtx; @@ -88,8 +88,6 @@ pub enum RpcMessage { Pong(()), - // DevResolutions(Resolutions), - QueueRequested(()), QueueJoined(()), QueueLeft(()), @@ -108,7 +106,7 @@ pub enum RpcMessage { pub enum RpcRequest { Ping {}, ItemInfo {}, - DevResolve { a: Uuid, b: Uuid, skill: Skill }, + DevResolve { skill: Skill }, MtxConstructApply { mtx: mtx::MtxVariant, construct_id: Uuid, name: String }, MtxConstructSpawn { }, @@ -171,8 +169,8 @@ impl Connection { match v { RpcRequest::Ping {} => return Ok(RpcMessage::Pong(())), RpcRequest::ItemInfo {} => return Ok(RpcMessage::ItemInfo(item_info())), - // RpcRequest::DevResolve {a, b, skill } => - // return Ok(RpcMessage::DevResolutions(dev_resolve(a, b, skill))), + RpcRequest::DevResolve { skill } => + return Ok(RpcMessage::GameState(anim_test_game(skill))), _ => (), };