From 3cb15a8c1e6628097558eb3d485a41b5b323ddc8 Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 15 Sep 2019 17:27:00 +1000 Subject: [PATCH 01/24] remove self targeting --- client/src/components/play.jsx | 9 ++-- server/src/construct.rs | 2 - server/src/game.rs | 94 ++++++++++++++++------------------ server/src/rpc.rs | 2 +- server/src/skill.rs | 14 ----- 5 files changed, 49 insertions(+), 72 deletions(-) diff --git a/client/src/components/play.jsx b/client/src/components/play.jsx index b76feb0c..362ed057 100644 --- a/client/src/components/play.jsx +++ b/client/src/components/play.jsx @@ -92,13 +92,14 @@ function Play(args) {

v{VERSION}

-

use the buttons on the right to join an instance.

+

Use the buttons on the right to join an instance.

- select PVP to play against other players.
- click LEARN to practice the game without time controls. + Select PVP to play against other players.
+ Select INVITE then click COPY LINK to generate an instance invitation for a friend.
+ Click LEARN to practice the game without time controls.

- if you enjoy the game please support its development by subscribing or purchasing credits.
+ If you enjoy the game please support its development by subscribing or purchasing credits.
glhf

--ntr & mashy

diff --git a/server/src/construct.rs b/server/src/construct.rs index 2d0e4fe8..80b4d7bb 100644 --- a/server/src/construct.rs +++ b/server/src/construct.rs @@ -46,7 +46,6 @@ impl Colours { #[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)] pub struct ConstructSkill { pub skill: Skill, - pub self_targeting: bool, pub cd: Cooldown, // used for Uon client pub disabled: bool, @@ -56,7 +55,6 @@ impl ConstructSkill { pub fn new(skill: Skill) -> ConstructSkill { ConstructSkill { skill, - self_targeting: skill.self_targeting(), cd: skill.base_cd(), disabled: false, } diff --git a/server/src/game.rs b/server/src/game.rs index caeb1e61..97354d86 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -236,7 +236,7 @@ impl Game { target = find_target(); } - pve_skills.push((mobs.id, mob.id, Some(target.id), s)); + pve_skills.push((mobs.id, mob.id, target.id, s)); }, None => continue, }; @@ -258,7 +258,7 @@ impl Game { self } - fn add_skill(&mut self, player_id: Uuid, source_construct_id: Uuid, target_construct_id: Option, skill: Skill) -> Result<&mut Game, Error> { + fn add_skill(&mut self, player_id: Uuid, source_construct_id: Uuid, target_construct_id: Uuid, skill: Skill) -> Result<&mut Game, Error> { // check player in game self.player_by_id(player_id)?; @@ -266,17 +266,9 @@ impl Game { return Err(err_msg("game not in skill phase")); } - let final_target_id = match skill.self_targeting() { - true => source_construct_id, - false => match target_construct_id { - Some(t) => t, - None => return Err(err_msg("skill requires a target")), - } - }; - // target checks { - let target = match self.construct_by_id(final_target_id) { + let target = match self.construct_by_id(target_construct_id) { Some(c) => c, None => return Err(err_msg("target construct not in game")), }; @@ -318,7 +310,7 @@ impl Game { self.stack.remove(s); } - let skill = Cast::new(source_construct_id, player_id, final_target_id, skill); + let skill = Cast::new(source_construct_id, player_id, target_construct_id, skill); self.stack.push(skill); return Ok(self); @@ -887,7 +879,7 @@ fn game_json_file_write(g: &Game) -> Result { Ok(dest) } -pub fn game_skill(tx: &mut Transaction, account: &Account, game_id: Uuid, construct_id: Uuid, target_construct_id: Option, skill: Skill) -> Result { +pub fn game_skill(tx: &mut Transaction, account: &Account, game_id: Uuid, construct_id: Uuid, target_construct_id: Uuid, skill: Skill) -> Result { let mut game = game_get(tx, game_id)?; game.add_skill(account.id, construct_id, target_construct_id, skill)?; @@ -1039,8 +1031,8 @@ mod tests { let x_construct = x_player.constructs[0].clone(); let y_construct = y_player.constructs[0].clone(); - game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Attack).unwrap(); - game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap(); + game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Attack).unwrap(); + 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(); @@ -1068,8 +1060,8 @@ mod tests { game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns(); } - game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Stun).unwrap(); - game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap(); + game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Stun).unwrap(); + 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(); @@ -1105,8 +1097,8 @@ mod tests { // remove all mitigation game.player_by_id(x_player.id).unwrap().construct_by_id(x_construct.id).unwrap().red_life.force(0); - game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Stun).unwrap(); - game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap(); + game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Stun).unwrap(); + 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(); @@ -1135,8 +1127,8 @@ mod tests { assert!(game.player_by_id(y_player.id).unwrap().constructs[0].skill_on_cd(Skill::Stun).is_some()); assert!(game.player_by_id(x_player.id).unwrap().constructs[0].skill_on_cd(Skill::Block).is_none()); - game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Attack).unwrap(); - game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap(); + game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Attack).unwrap(); + 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(); @@ -1149,8 +1141,8 @@ mod tests { // second round // now we block and it should go back on cd - // game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Stun).unwrap(); - game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap(); + // game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Stun).unwrap(); + 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(); @@ -1179,8 +1171,8 @@ mod tests { game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns(); } - game.add_skill(x_player.id, x_construct.id, None, Skill::Counter).unwrap(); - game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Stun).unwrap(); + game.add_skill(x_player.id, x_construct.id, x_construct.id, Skill::Counter).unwrap(); + game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::Stun).unwrap(); game.player_ready(x_player.id).unwrap(); game.player_ready(y_player.id).unwrap(); @@ -1214,14 +1206,14 @@ mod tests { } // apply buff - game.add_skill(x_player.id, x_construct.id, Some(x_construct.id), Skill::Electrify).unwrap(); + game.add_skill(x_player.id, x_construct.id, x_construct.id, Skill::Electrify).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::Electric)); // attack and receive debuff - game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap(); + 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(); @@ -1246,7 +1238,7 @@ mod tests { } // apply buff - game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Link).unwrap(); + 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(); @@ -1265,7 +1257,7 @@ mod tests { } // attack and receive link hit - game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::Attack).unwrap(); + 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(); @@ -1296,14 +1288,14 @@ mod tests { // } // // apply buff - // game.add_skill(x_player.id, x_construct.id, Some(x_construct.id), Skill::Absorb).unwrap(); + // game.add_skill(x_player.id, x_construct.id, x_construct.id, Skill::Absorb).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::Absorb)); // // attack and receive debuff - // game.add_skill(y_player.id, y_construct.id, Some(x_construct.id), Skill::TestAttack).unwrap(); + // game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::TestAttack).unwrap(); // game.player_ready(x_player.id).unwrap(); // game.player_ready(y_player.id).unwrap(); // game = game.resolve_phase_start(); @@ -1330,10 +1322,10 @@ mod tests { game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns(); } - game.add_skill(i_player.id, i_construct.id, Some(x_construct.id), Skill::Attack).unwrap(); - game.add_skill(i_player.id, j_construct.id, Some(x_construct.id), Skill::Attack).unwrap(); - game.add_skill(x_player.id, x_construct.id, Some(i_construct.id), Skill::Ruin).unwrap(); - game.add_skill(x_player.id, y_construct.id, Some(i_construct.id), Skill::Attack).unwrap(); + game.add_skill(i_player.id, i_construct.id, x_construct.id, Skill::Attack).unwrap(); + game.add_skill(i_player.id, j_construct.id, x_construct.id, Skill::Attack).unwrap(); + game.add_skill(x_player.id, x_construct.id, i_construct.id, Skill::Ruin).unwrap(); + game.add_skill(x_player.id, y_construct.id, i_construct.id, Skill::Attack).unwrap(); game.player_ready(i_player.id).unwrap(); game.player_ready(x_player.id).unwrap(); @@ -1380,10 +1372,10 @@ mod tests { game.construct_by_id(x_construct.id).unwrap().reduce_cooldowns(); } - game.add_skill(i_player.id, i_construct.id, Some(x_construct.id), Skill::Attack).unwrap(); - game.add_skill(i_player.id, j_construct.id, Some(x_construct.id), Skill::Attack).unwrap(); - game.add_skill(x_player.id, x_construct.id, Some(i_construct.id), Skill::Intercept).unwrap(); - game.add_skill(x_player.id, y_construct.id, Some(i_construct.id), Skill::Attack).unwrap(); + game.add_skill(i_player.id, i_construct.id, x_construct.id, Skill::Attack).unwrap(); + game.add_skill(i_player.id, j_construct.id, x_construct.id, Skill::Attack).unwrap(); + game.add_skill(x_player.id, x_construct.id, i_construct.id, Skill::Intercept).unwrap(); + game.add_skill(x_player.id, y_construct.id, i_construct.id, Skill::Attack).unwrap(); game.player_ready(i_player.id).unwrap(); game.player_ready(x_player.id).unwrap(); @@ -1411,10 +1403,10 @@ mod tests { 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, Some(x_construct.id), Skill::Attack).unwrap() - .add_skill(i_player.id, j_construct.id, Some(x_construct.id), Skill::Attack).unwrap() - .add_skill(x_player.id, x_construct.id, Some(i_construct.id), Skill::Attack).unwrap() - .add_skill(x_player.id, y_construct.id, Some(i_construct.id), Skill::Attack).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(); @@ -1430,10 +1422,10 @@ mod tests { 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, Some(x_construct.id), Skill::Attack).unwrap(); - game.add_skill(x_player.id, x_construct.id, Some(j_construct.id), Skill::Attack).unwrap(); - game.add_skill(x_player.id, y_construct.id, Some(j_construct.id), Skill::Attack).unwrap(); - assert!(game.add_skill(x_player.id, x_construct.id, Some(i_construct.id), Skill::Attack).is_err()); + 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(); @@ -1475,7 +1467,7 @@ mod tests { } // apply buff - game.add_skill(x_player.id, x_construct.id, Some(y_construct.id), Skill::Decay).unwrap(); + game.add_skill(x_player.id, x_construct.id, y_construct.id, Skill::Decay).unwrap(); game.player_ready(x_player.id).unwrap(); game.player_ready(y_player.id).unwrap(); game = game.resolve_phase_start(); @@ -1490,7 +1482,7 @@ mod tests { game.resolved.clear(); // remove - game.add_skill(y_player.id, y_construct.id, Some(y_construct.id), Skill::Purify).unwrap(); + game.add_skill(y_player.id, y_construct.id, y_construct.id, Skill::Purify).unwrap(); game.player_ready(x_player.id).unwrap(); game.player_ready(y_player.id).unwrap(); game = game.resolve_phase_start(); @@ -1503,14 +1495,14 @@ mod tests { } }; - game.add_skill(y_player.id, x_construct.id, Some(y_construct.id), Skill::Siphon).unwrap(); + game.add_skill(y_player.id, x_construct.id, y_construct.id, Skill::Siphon).unwrap(); game.player_ready(x_player.id).unwrap(); game.player_ready(y_player.id).unwrap(); game = game.resolve_phase_start(); game.resolved.clear(); - game.add_skill(y_player.id, y_construct.id, Some(y_construct.id), Skill::Purify).unwrap(); + game.add_skill(y_player.id, y_construct.id, y_construct.id, Skill::Purify).unwrap(); game.player_ready(x_player.id).unwrap(); game.player_ready(y_player.id).unwrap(); game = game.resolve_phase_start(); diff --git a/server/src/rpc.rs b/server/src/rpc.rs index 3439a6c4..be3071e8 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -82,7 +82,7 @@ pub enum RpcRequest { GameState { id: Uuid }, GameReady { id: Uuid }, - GameSkill { game_id: Uuid, construct_id: Uuid, target_construct_id: Option, skill: Skill }, + GameSkill { game_id: Uuid, construct_id: Uuid, target_construct_id: Uuid, skill: Skill }, GameSkillClear { game_id: Uuid }, AccountState {}, diff --git a/server/src/skill.rs b/server/src/skill.rs index d71ac47e..52ef3092 100644 --- a/server/src/skill.rs +++ b/server/src/skill.rs @@ -1213,20 +1213,6 @@ impl Skill { } } - pub fn self_targeting(&self) -> bool { - match self { - Skill::Block | - Skill::Sustain| - Skill::SustainPlus | - Skill::SustainPlusPlus | - Skill::Counter| - Skill::CounterPlus | - Skill::CounterPlusPlus => true, - - _ => false, - } - } - pub fn defensive(&self) -> bool { let mut rng = thread_rng(); From c027b2dec1a8886a525520e9ce8ae9db20342272 Mon Sep 17 00:00:00 2001 From: Mashy Date: Sun, 15 Sep 2019 17:56:51 +1000 Subject: [PATCH 02/24] check for null objects --- client/src/events.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/events.jsx b/client/src/events.jsx index 242e2888..3e0943fd 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -72,12 +72,12 @@ function registerEvents(store) { const text = animations.getText(r, sequence); store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r, game))); - if (sequence.includes('START_SKILL')) store.dispatch(actions.setAnimSource(anims.animSource)); - if (sequence.includes('END_SKILL')) { + if (sequence.includes('START_SKILL') && anims.animSource) store.dispatch(actions.setAnimSource(anims.animSource)); + if (sequence.includes('END_SKILL') && anims.animTarget) { store.dispatch(actions.setAnimTarget(anims.animTarget)); if (!['Banish', 'Invert'].includes(removeTier(anims.animTarget.skill))) store.dispatch(actions.setAnimCb(cb)); } - if (sequence.includes('POST_SKILL')) { + if (sequence.includes('POST_SKILL' && text)) { // timeout to prevent text classes from being added too soon setTimeout( () => store.dispatch(actions.setAnimText(text)), From d1b13ce0920248a23b892bb7a49fc5408dca08d4 Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 14:22:57 +1000 Subject: [PATCH 03/24] targeting text --- client/assets/styles/game.less | 7 +++++++ client/src/components/targeting.arrows.jsx | 13 +++---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index e51237bc..7722f5fc 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -88,6 +88,13 @@ stroke: whitesmoke; } +.resolving-skill { + grid-area: target; + align-self: center; + text-align: center; + height: auto; +} + /* some stupid bug in chrome makes it fill the entire screen */ @media screen and (-webkit-min-device-pixel-ratio:0) { #targeting { diff --git a/client/src/components/targeting.arrows.jsx b/client/src/components/targeting.arrows.jsx index ac087830..ed822459 100644 --- a/client/src/components/targeting.arrows.jsx +++ b/client/src/components/targeting.arrows.jsx @@ -17,8 +17,9 @@ class TargetSvg extends Component { this.onResize = throttle(() => { const svg = document.getElementById('targeting'); + if (!svg) return setTimeout(this.onResize, 500); const { width, height } = svg.getBoundingClientRect(); - const path = document.querySelector('#targeting path'); + // const path = document.querySelector('#targeting path'); this.setState({ width, height }); }, 500); } @@ -34,15 +35,7 @@ class TargetSvg extends Component { if (!animTarget) return false; return ( - - - {animTarget.skill} - - +

{animTarget.skill}

); } From 0edfe553876e34f6640aa53b7864f219ac60656b Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 13:37:15 +1000 Subject: [PATCH 04/24] animations test fixes + new strike --- client/animations.test.js | 12 ++- client/assets/styles/styles.less | 12 +++ client/src/animations.test.jsx | 38 ++++----- client/src/components/anims/strike.jsx | 113 +++++++------------------ server/src/effect.rs | 2 +- 5 files changed, 73 insertions(+), 104 deletions(-) diff --git a/client/animations.test.js b/client/animations.test.js index fa76c5dd..3271b840 100644 --- a/client/animations.test.js +++ b/client/animations.test.js @@ -1,8 +1,14 @@ require('./assets/styles/styles.less'); -require('./assets/styles/styles.mobile.css'); +require('./assets/styles/menu.less'); +require('./assets/styles/nav.less'); +require('./assets/styles/footer.less'); +require('./assets/styles/account.less'); +require('./assets/styles/controls.less'); require('./assets/styles/instance.less'); +require('./assets/styles/vbox.less'); +require('./assets/styles/game.less'); +require('./assets/styles/player.less'); +require('./assets/styles/styles.mobile.css'); require('./assets/styles/instance.mobile.css'); -require('./assets/styles/game.css'); -// kick it off require('./src/animations.test.jsx'); diff --git a/client/assets/styles/styles.less b/client/assets/styles/styles.less index 83ab40d9..3ca91487 100644 --- a/client/assets/styles/styles.less +++ b/client/assets/styles/styles.less @@ -93,6 +93,18 @@ dl { "main ctrl"; padding: 0.5em 1em; + + &.animations-test { + grid-template-columns: 1fr 9fr 1fr; + grid-template-areas: + "hdr hdr ctrl" + "nav main ctrl" + "nav main ctrl"; + + nav { + display: initial; + } + } } main { diff --git a/client/src/animations.test.jsx b/client/src/animations.test.jsx index 2127ab35..5a676a23 100644 --- a/client/src/animations.test.jsx +++ b/client/src/animations.test.jsx @@ -55,7 +55,7 @@ document.fonts.load('16pt "Jura"').then(() => { const Animations = () => ( -
+
@@ -69,24 +69,6 @@ document.fonts.load('16pt "Jura"').then(() => { }); const SKILLS = [ - 'Absorb', - 'Absorption', - 'Amplify', - 'Attack', - 'Banish', - 'Bash', - 'Blast', - 'Block', - 'Break', - 'Buff', - 'Chaos', - 'CounterAttack', - 'Counter', - 'Curse', - 'Debuff', - 'Decay', - 'DecayTick', - 'Electrify', 'Electrocute', 'ElectrocuteTick', 'Haste', @@ -113,4 +95,22 @@ const SKILLS = [ 'Sustain', 'Triage', 'TriageTick', + 'Absorb', + 'Absorption', + 'Amplify', + 'Attack', + 'Banish', + 'Bash', + 'Blast', + 'Block', + 'Break', + 'Buff', + 'Chaos', + 'CounterAttack', + 'Counter', + 'Curse', + 'Debuff', + 'Decay', + 'DecayTick', + 'Electrify', ]; diff --git a/client/src/components/anims/strike.jsx b/client/src/components/anims/strike.jsx index 37cac718..066fe1c5 100644 --- a/client/src/components/anims/strike.jsx +++ b/client/src/components/anims/strike.jsx @@ -1,9 +1,9 @@ const preact = require('preact'); const { Component } = require('preact'); -const anime = require('animejs').default; const { connect } = require('preact-redux'); +const anime = require('animejs').default; -const { TIMES } = require('../../constants'); +const { TIMES, COLOURS } = require('../../constants'); const addState = connect( function receiveState(state) { @@ -12,116 +12,67 @@ const addState = connect( } ); -function laser(dimensions, colour) { - const { x, y, length } = dimensions; - return ( - - ); -} - class Strike extends Component { constructor(props) { super(); - this.team = props.team; + this.props = props; this.animations = []; - this.colour = props.colour; - - const coord = [0, 50, 100, 150, 200]; - const points = coord.map(pos => ({ - x: pos + Math.random() * 40, - y: 50 + Math.random() * 100, - length: 150 + Math.random() * 150, - })); - this.charges = points.map(pos => laser(pos, this.colour)); } render() { return ( - - - - - - - - - - + viewBox="0 0 400 400"> + + + - {this.charges} + + + ); } componentDidMount() { - let rotate = 0; // Self target value - if (this.props.direction.y) { - if (!this.props.direction.x) rotate = this.props.direction.y > 0 ? 0 : 180; - else { - rotate = this.props.direction.y > 0 - ? -Math.atan(this.props.direction.y / this.props.direction.x) * 180 / Math.PI - : -Math.atan(this.props.direction.y / this.props.direction.x) * 180 / Math.PI + 180; - } - } else if (this.props.direction.x) { - rotate = this.props.direction.x > 0 ? 270 : 90; - } - anime.set('#strike', { - rotate, - }); - - anime.set('#strike', { - translateY: (window.screen.height) * 0.35 * this.props.direction.y, - translateX: 0, - }); - this.animations.push(anime({ - targets: '#strike', - opacity: [ - { value: 1, delay: TIMES.TARGET_DELAY_MS, duration: TIMES.TARGET_DURATION_MS * 0.2 }, - { value: 0, delay: TIMES.TARGET_DURATION_MS * 0.6, duration: TIMES.TARGET_DURATION_MS * 0.2 }, - ], - easing: 'easeInOutSine', - })); - - this.animations.push(anime({ - targets: '#strike', - translateY: 0, - translateX: 0, - loop: false, + targets: ['#strike rect'], + easing: 'easeOutExpo', + y: [400, 200, 200], + x: [200, 0, 200], + height: [200, 10, 0], + width: [20, 400, 0], delay: TIMES.TARGET_DELAY_MS, - duration: (TIMES.TARGET_DURATION_MS * 1 / 2), - easing: 'easeInQuad', + duration: TIMES.TARGET_DURATION_MS, })); + this.animations.push(anime({ - targets: '#strikeFilter feDisplacementMap', - scale: 200, - loop: false, - delay: (TIMES.TARGET_DELAY_MS + TIMES.TARGET_DURATION_MS * 1 / 4), - easing: 'easeInQuad', + targets: ['#strikeFilter feTurbulence', '#strikeFilter feDisplacementMap'], + baseFrequency: 2, + scale: 50, + numOctaves: 5, + easing: 'easeOutSine', + delay: TIMES.TARGET_DELAY_MS + (TIMES.TARGET_DURATION_MS / 3), + duration: TIMES.TARGET_DURATION_MS / 2, })); } + // this is necessary because + // skipping / timing / unmounting race conditions + // can cause the animations to cut short, this will ensure the values are reset + // because preact will recycle all these components componentWillUnmount() { for (let i = this.animations.length - 1; i >= 0; i--) { this.animations[i].reset(); } this.props.animCb && this.props.animCb(); } + } module.exports = addState(Strike); diff --git a/server/src/effect.rs b/server/src/effect.rs index 83c445d9..f9e5c05d 100644 --- a/server/src/effect.rs +++ b/server/src/effect.rs @@ -154,7 +154,7 @@ impl Effect { }, _ => { - info!("{:?} does not have a mod effect", self); + warn!("{:?} does not have a mod effect", self); return value; }, } From 0b62a392f527dd147698ed8c661ee69b9cd28b68 Mon Sep 17 00:00:00 2001 From: Mashy Date: Mon, 16 Sep 2019 14:49:36 +1000 Subject: [PATCH 05/24] link rework --- client/src/events.jsx | 2 +- server/src/item.rs | 176 +++++++++++++++++++++--------------------- server/src/skill.rs | 67 +++++----------- 3 files changed, 109 insertions(+), 136 deletions(-) diff --git a/client/src/events.jsx b/client/src/events.jsx index 184f4ad7..05b01677 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -79,7 +79,7 @@ function registerEvents(store) { store.dispatch(actions.setAnimTarget(anims.animTarget)); if (!['Banish', 'Invert'].includes(removeTier(anims.animTarget.skill))) store.dispatch(actions.setAnimCb(cb)); } - if (sequence.includes('POST_SKILL' && text)) { + if (sequence.includes('POST_SKILL') && text) { // timeout to prevent text classes from being added too soon setTimeout( () => store.dispatch(actions.setAnimText(text)), diff --git a/server/src/item.rs b/server/src/item.rs index 55c883f9..3c5c29f9 100644 --- a/server/src/item.rs +++ b/server/src/item.rs @@ -865,100 +865,100 @@ impl Item { fn combo(&self) -> Vec { match self { - Item::Intercept => vec![Item::Buff, Item::Red, Item::Red], - Item::InterceptPlus => vec![Item::Intercept, Item::Intercept, Item::Intercept], - Item::InterceptPlusPlus => vec![Item::InterceptPlus, Item::InterceptPlus, Item::InterceptPlus], - Item::Triage => vec![Item::Buff, Item::Green, Item::Green], - Item::TriagePlus => vec![Item::Triage, Item::Triage, Item::Triage], - Item::TriagePlusPlus => vec![Item::TriagePlus, Item::TriagePlus, Item::TriagePlus], - Item::Link => vec![Item::Buff, Item::Blue, Item::Blue], - Item::LinkPlus => vec![Item::Link, Item::Link, Item::Link], - Item::LinkPlusPlus => vec![Item::LinkPlusPlus, Item::LinkPlusPlus, Item::LinkPlusPlus], - Item::Haste => vec![Item::Buff, Item::Red, Item::Green], - Item::HastePlus => vec![Item::Haste, Item::Haste, Item::Haste], - Item::HastePlusPlus => vec![Item::HastePlus, Item::HastePlus, Item::HastePlus], - Item::Hybrid => vec![Item::Buff, Item::Green, Item::Blue], - Item::HybridPlus => vec![Item::Hybrid, Item::Hybrid, Item::Hybrid], - Item::HybridPlusPlus => vec![Item::HybridPlus, Item::HybridPlus, Item::HybridPlus], - Item::Amplify => vec![Item::Buff, Item::Red, Item::Blue], - Item::AmplifyPlus => vec![Item::Amplify, Item::Amplify, Item::Amplify], - Item::AmplifyPlusPlus => vec![Item::AmplifyPlus, Item::AmplifyPlus, Item::AmplifyPlus], + Item::Intercept => vec![Item::Buff, Item::Red, Item::Red], + Item::Triage => vec![Item::Buff, Item::Green, Item::Green], + Item::Absorb => vec![Item::Buff, Item::Blue, Item::Blue], + Item::Amplify => vec![Item::Buff, Item::Red, Item::Blue], + Item::Haste => vec![Item::Buff, Item::Red, Item::Green], + Item::Hybrid => vec![Item::Buff, Item::Green, Item::Blue], + Item::InterceptPlus => vec![Item::Intercept, Item::Intercept, Item::Intercept], + Item::InterceptPlusPlus => vec![Item::InterceptPlus, Item::InterceptPlus, Item::InterceptPlus], + Item::TriagePlus => vec![Item::Triage, Item::Triage, Item::Triage], + Item::TriagePlusPlus => vec![Item::TriagePlus, Item::TriagePlus, Item::TriagePlus], + Item::HastePlus => vec![Item::Haste, Item::Haste, Item::Haste], + Item::HastePlusPlus => vec![Item::HastePlus, Item::HastePlus, Item::HastePlus], + Item::HybridPlus => vec![Item::Hybrid, Item::Hybrid, Item::Hybrid], + Item::HybridPlusPlus => vec![Item::HybridPlus, Item::HybridPlus, Item::HybridPlus], + Item::AbsorbPlus => vec![Item::Absorb, Item::Absorb, Item::Absorb], + Item::AbsorbPlusPlus => vec![Item::AbsorbPlus, Item::AbsorbPlus, Item::AbsorbPlus], + Item::AmplifyPlus => vec![Item::Amplify, Item::Amplify, Item::Amplify], + Item::AmplifyPlusPlus => vec![Item::AmplifyPlus, Item::AmplifyPlus, Item::AmplifyPlus], - Item::Restrict => vec![Item::Debuff, Item::Red, Item::Red], - Item::RestrictPlus => vec![Item::Restrict, Item::Restrict, Item::Restrict], - Item::RestrictPlusPlus => vec![Item::RestrictPlus, Item::RestrictPlus, Item::RestrictPlus], - Item::Purge => vec![Item::Debuff, Item::Green, Item::Green], // Needs flavour - Item::PurgePlus => vec![Item::Purge, Item::Purge, Item::Purge], // Needs flavour - Item::PurgePlusPlus => vec![Item::PurgePlus, Item::PurgePlus, Item::PurgePlus], // Needs flavour - Item::Silence => vec![Item::Debuff, Item::Blue, Item::Blue], - Item::SilencePlus => vec![Item::Silence, Item::Silence, Item::Silence], - Item::SilencePlusPlus => vec![Item::SilencePlus, Item::SilencePlus, Item::SilencePlus], - Item::Curse => vec![Item::Debuff, Item::Red, Item::Green], - Item::CursePlus => vec![Item::Curse, Item::Curse, Item::Curse], - Item::CursePlusPlus => vec![Item::CursePlus, Item::CursePlus, Item::CursePlus], - Item::Decay => vec![Item::Debuff, Item::Green, Item::Blue], - Item::DecayPlus => vec![Item::Decay, Item::Decay, Item::Decay], - Item::DecayPlusPlus => vec![Item::DecayPlus, Item::DecayPlus, Item::DecayPlus], - Item::Invert => vec![Item::Debuff, Item::Red, Item::Blue], - Item::InvertPlus => vec![Item::Invert, Item::Invert, Item::Invert], - Item::InvertPlusPlus => vec![Item::InvertPlus, Item::InvertPlus, Item::InvertPlus], + Item::Purge => vec![Item::Debuff, Item::Green, Item::Green], // Needs flavour + Item::Invert => vec![Item::Debuff, Item::Red, Item::Blue], + Item::Restrict => vec![Item::Debuff, Item::Red, Item::Red], + Item::Silence => vec![Item::Debuff, Item::Blue, Item::Blue], + Item::Curse => vec![Item::Debuff, Item::Red, Item::Green], + Item::Decay => vec![Item::Debuff, Item::Green, Item::Blue], + Item::RestrictPlus => vec![Item::Restrict, Item::Restrict, Item::Restrict], + Item::RestrictPlusPlus => vec![Item::RestrictPlus, Item::RestrictPlus, Item::RestrictPlus], + Item::PurgePlus => vec![Item::Purge, Item::Purge, Item::Purge], // Needs flavour + Item::PurgePlusPlus => vec![Item::PurgePlus, Item::PurgePlus, Item::PurgePlus], // Needs flavour + Item::SilencePlus => vec![Item::Silence, Item::Silence, Item::Silence], + Item::SilencePlusPlus => vec![Item::SilencePlus, Item::SilencePlus, Item::SilencePlus], + Item::CursePlus => vec![Item::Curse, Item::Curse, Item::Curse], + Item::CursePlusPlus => vec![Item::CursePlus, Item::CursePlus, Item::CursePlus], + Item::DecayPlus => vec![Item::Decay, Item::Decay, Item::Decay], + Item::DecayPlusPlus => vec![Item::DecayPlus, Item::DecayPlus, Item::DecayPlus], + Item::InvertPlus => vec![Item::Invert, Item::Invert, Item::Invert], + Item::InvertPlusPlus => vec![Item::InvertPlus, Item::InvertPlus, Item::InvertPlus], - Item::Counter => vec![Item::Block, Item::Red, Item::Red], + Item::Counter => vec![Item::Block, Item::Red, Item::Red], + Item::Reflect => vec![Item::Block, Item::Green, Item::Blue], + Item::Purify => vec![Item::Block, Item::Green, Item::Green], + Item::Sustain => vec![Item::Block, Item::Red, Item::Green], + Item::Electrify => vec![Item::Block, Item::Blue, Item::Blue], + Item::Recharge => vec![Item::Block, Item::Red, Item::Blue], Item::CounterPlus => vec![Item::Counter, Item::Counter, Item::Counter], - Item::CounterPlusPlus => vec![Item::CounterPlus, Item::CounterPlus, Item::CounterPlus], // Add red recharge - Item::Purify => vec![Item::Block, Item::Green, Item::Green], - Item::PurifyPlus => vec![Item::Purify, Item::Purify, Item::Purify], - Item::PurifyPlusPlus => vec![Item::PurifyPlus, Item::PurifyPlus, Item::PurifyPlus], - Item::Electrify => vec![Item::Block, Item::Blue, Item::Blue], + Item::CounterPlusPlus => vec![Item::CounterPlus, Item::CounterPlus, Item::CounterPlus], // Add red recharge + Item::PurifyPlus => vec![Item::Purify, Item::Purify, Item::Purify], + Item::PurifyPlusPlus => vec![Item::PurifyPlus, Item::PurifyPlus, Item::PurifyPlus], Item::ElectrifyPlus => vec![Item::Electrify, Item::Electrify, Item::Electrify], - Item::ElectrifyPlusPlus => vec![Item::ElectrifyPlus, Item::ElectrifyPlus, Item::ElectrifyPlus], - Item::Sustain => vec![Item::Block, Item::Red, Item::Green], - Item::SustainPlus => vec![Item::Sustain, Item::Sustain, Item::Sustain], - Item::SustainPlusPlus => vec![Item::SustainPlus, Item::SustainPlus, Item::SustainPlus], - Item::Reflect => vec![Item::Block, Item::Green, Item::Blue], - Item::ReflectPlus => vec![Item::Reflect, Item::Reflect, Item::Reflect], - Item::ReflectPlusPlus => vec![Item::ReflectPlus, Item::ReflectPlus, Item::ReflectPlus], - Item::Recharge => vec![Item::Block, Item::Red, Item::Blue], - Item::RechargePlus => vec![Item::Recharge, Item::Recharge, Item::Recharge], - Item::RechargePlusPlus => vec![Item::RechargePlus, Item::RechargePlus, Item::RechargePlus], + Item::ElectrifyPlusPlus => vec![Item::ElectrifyPlus, Item::ElectrifyPlus, Item::ElectrifyPlus], + Item::SustainPlus => vec![Item::Sustain, Item::Sustain, Item::Sustain], + Item::SustainPlusPlus => vec![Item::SustainPlus, Item::SustainPlus, Item::SustainPlus], + Item::ReflectPlus => vec![Item::Reflect, Item::Reflect, Item::Reflect], + Item::ReflectPlusPlus => vec![Item::ReflectPlus, Item::ReflectPlus, Item::ReflectPlus], + Item::RechargePlus => vec![Item::Recharge, Item::Recharge, Item::Recharge], + Item::RechargePlusPlus => vec![Item::RechargePlus, Item::RechargePlus, Item::RechargePlus], - Item::Bash => vec![Item::Stun, Item::Red, Item::Red], - Item::BashPlus => vec![Item::Bash, Item::Bash, Item::Bash], - Item::BashPlusPlus => vec![Item::BashPlus, Item::BashPlus, Item::BashPlus], - Item::Sleep => vec![Item::Stun, Item::Green, Item::Green], - Item::SleepPlus => vec![Item::Sleep, Item::Sleep, Item::Sleep], - Item::SleepPlusPlus => vec![Item::SleepPlus, Item::SleepPlus, Item::SleepPlus], - Item::Ruin => vec![Item::Stun, Item::Blue, Item::Blue], - Item::RuinPlus => vec![Item::Ruin, Item::Ruin, Item::Ruin], - Item::RuinPlusPlus => vec![Item::RuinPlus, Item::RuinPlus, Item::RuinPlus], - Item::Break => vec![Item::Stun, Item::Red, Item::Green], - Item::BreakPlus => vec![Item::Break, Item::Break, Item::Break], - Item::BreakPlusPlus => vec![Item::BreakPlus, Item::BreakPlus, Item::BreakPlus], - Item::Absorb => vec![Item::Stun, Item::Green, Item::Blue], - Item::AbsorbPlus => vec![Item::Absorb, Item::Absorb, Item::Absorb], - Item::AbsorbPlusPlus => vec![Item::AbsorbPlus, Item::AbsorbPlus, Item::AbsorbPlus], - Item::Banish => vec![Item::Stun, Item::Red, Item::Blue], - Item::BanishPlus => vec![Item::Banish, Item::Banish, Item::Banish], - Item::BanishPlusPlus => vec![Item::BanishPlus, Item::BanishPlus, Item::BanishPlus], + Item::Bash => vec![Item::Stun, Item::Red, Item::Red], + Item::Sleep => vec![Item::Stun, Item::Green, Item::Green], + Item::Ruin => vec![Item::Stun, Item::Blue, Item::Blue], + Item::Link => vec![Item::Stun, Item::Blue, Item::Green], + Item::Banish => vec![Item::Stun, Item::Red, Item::Blue], + Item::Break => vec![Item::Stun, Item::Red, Item::Green], + Item::BashPlus => vec![Item::Bash, Item::Bash, Item::Bash], + Item::BashPlusPlus => vec![Item::BashPlus, Item::BashPlus, Item::BashPlus], + Item::SleepPlus => vec![Item::Sleep, Item::Sleep, Item::Sleep], + Item::SleepPlusPlus => vec![Item::SleepPlus, Item::SleepPlus, Item::SleepPlus], + Item::RuinPlus => vec![Item::Ruin, Item::Ruin, Item::Ruin], + Item::RuinPlusPlus => vec![Item::RuinPlus, Item::RuinPlus, Item::RuinPlus], + Item::BreakPlus => vec![Item::Break, Item::Break, Item::Break], + Item::BreakPlusPlus => vec![Item::BreakPlus, Item::BreakPlus, Item::BreakPlus], + Item::LinkPlus => vec![Item::Link, Item::Link, Item::Link], + Item::LinkPlusPlus => vec![Item::LinkPlusPlus, Item::LinkPlusPlus, Item::LinkPlusPlus], + Item::BanishPlus => vec![Item::Banish, Item::Banish, Item::Banish], + Item::BanishPlusPlus => vec![Item::BanishPlus, Item::BanishPlus, Item::BanishPlus], - Item::Strike => vec![Item::Attack, Item::Red, Item::Red], - Item::StrikePlus => vec![Item::Strike, Item::Strike, Item::Strike], - Item::StrikePlusPlus => vec![Item::StrikePlus, Item::StrikePlus, Item::StrikePlus], - Item::Heal => vec![Item::Attack, Item::Green, Item::Green], - Item::HealPlus => vec![Item::Heal, Item::Heal, Item::Heal], - Item::HealPlusPlus => vec![Item::HealPlus, Item::HealPlus, Item::HealPlus], - Item::Blast => vec![Item::Attack, Item::Blue, Item::Blue], - Item::BlastPlus => vec![Item::Blast, Item::Blast, Item::Blast], - Item::BlastPlusPlus => vec![Item::BlastPlus, Item::BlastPlus, Item::BlastPlus], - Item::Slay => vec![Item::Attack, Item::Red, Item::Green], - Item::SlayPlus => vec![Item::Slay, Item::Slay, Item::Slay], - Item::SlayPlusPlus => vec![Item::SlayPlus, Item::SlayPlus, Item::SlayPlus], - Item::Siphon => vec![Item::Attack, Item::Green, Item::Blue], - Item::SiphonPlus => vec![Item::Siphon, Item::Siphon, Item::Siphon], - Item::SiphonPlusPlus => vec![Item::SiphonPlus, Item::SiphonPlus, Item::SiphonPlus], - Item::Chaos => vec![Item::Attack, Item::Red, Item::Blue], - Item::ChaosPlus => vec![Item::Chaos, Item::Chaos, Item::Chaos], - Item::ChaosPlusPlus => vec![Item::ChaosPlus, Item::ChaosPlus, Item::ChaosPlus], + Item::Strike => vec![Item::Attack, Item::Red, Item::Red], + Item::Chaos => vec![Item::Attack, Item::Red, Item::Blue], + Item::Heal => vec![Item::Attack, Item::Green, Item::Green], + Item::Blast => vec![Item::Attack, Item::Blue, Item::Blue], + Item::Slay => vec![Item::Attack, Item::Red, Item::Green], + Item::Siphon => vec![Item::Attack, Item::Green, Item::Blue], + Item::StrikePlus => vec![Item::Strike, Item::Strike, Item::Strike], + Item::StrikePlusPlus => vec![Item::StrikePlus, Item::StrikePlus, Item::StrikePlus], + Item::HealPlus => vec![Item::Heal, Item::Heal, Item::Heal], + Item::HealPlusPlus => vec![Item::HealPlus, Item::HealPlus, Item::HealPlus], + Item::BlastPlus => vec![Item::Blast, Item::Blast, Item::Blast], + Item::BlastPlusPlus => vec![Item::BlastPlus, Item::BlastPlus, Item::BlastPlus], + Item::SlayPlus => vec![Item::Slay, Item::Slay, Item::Slay], + Item::SlayPlusPlus => vec![Item::SlayPlus, Item::SlayPlus, Item::SlayPlus], + Item::SiphonPlus => vec![Item::Siphon, Item::Siphon, Item::Siphon], + Item::SiphonPlusPlus => vec![Item::SiphonPlus, Item::SiphonPlus, Item::SiphonPlus], + Item::ChaosPlus => vec![Item::Chaos, Item::Chaos, Item::Chaos], + Item::ChaosPlusPlus => vec![Item::ChaosPlus, Item::ChaosPlus, Item::ChaosPlus], Item::PowerRR => vec![Item::Power, Item::Red, Item::Red], Item::PowerGG => vec![Item::Power, Item::Green, Item::Green], diff --git a/server/src/skill.rs b/server/src/skill.rs index 52ef3092..5ae0bd11 100644 --- a/server/src/skill.rs +++ b/server/src/skill.rs @@ -319,12 +319,6 @@ fn post_resolve(_skill: Skill, game: &mut Game, mut resolutions: Resolutions) -> _ => panic!("no absorb skill"), }; } - - // beware that link doesn't cause any damage - // because then applying it will proc this - if target.affected(Effect::Link) { - resolutions = link_hit(&source, &target, resolutions, game, event) - } }, Event::Immunity { skill: _, immunity } => match immunity.contains(&Effect::Counter) { @@ -805,9 +799,9 @@ impl Skill { // Buff base Skill::HybridBlast => 25, Skill::HasteStrike => 30, - Skill::Link=> 140, - Skill::LinkPlus => 200, - Skill::LinkPlusPlus => 300, + Skill::Link=> 75, + Skill::LinkPlus => 100, + Skill::LinkPlusPlus => 150, Skill::Intercept=> 80, Skill::InterceptPlus => 110, Skill::InterceptPlusPlus => 150, @@ -932,9 +926,9 @@ impl Skill { Skill::PurgePlus => vec![ConstructEffect {effect: Effect::Purge, duration: 2, meta: None, tick: None}], Skill::PurgePlusPlus => vec![ConstructEffect {effect: Effect::Purge, duration: 3, meta: None, tick: None}], - Skill::Link => vec![ConstructEffect {effect: Effect::Link, duration: 2, meta: None, tick: None}], - Skill::LinkPlus => vec![ConstructEffect {effect: Effect::Link, duration: 3, meta: None, tick: None}], - Skill::LinkPlusPlus => vec![ConstructEffect {effect: Effect::Link, duration: 4, meta: None, tick: None}], + Skill::Link => vec![ConstructEffect {effect: Effect::Stun, duration: 3, meta: None, tick: None}], + Skill::LinkPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}], + Skill::LinkPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}], Skill::Silence => vec![ConstructEffect {effect: Effect::Silence, duration: 2, meta: None, tick: None}], Skill::SilencePlus => vec![ConstructEffect {effect: Effect::Silence, duration: 3, meta: None, tick: None}], @@ -1180,10 +1174,6 @@ impl Skill { pub fn speed(&self) -> u64 { match self { - Skill::Strike=> Item::from(Skill::Strike).speed().pct(150), - Skill::StrikePlus => Skill::Strike.speed(), - Skill::StrikePlusPlus => Skill::Strike.speed(), - Skill::SiphonTick| Skill::SiphonTickPlus | Skill::SiphonTickPlusPlus => Skill::Siphon.speed(), @@ -1674,42 +1664,25 @@ fn siphon_tick(source: &mut Construct, target: &mut Construct, mut results: Reso } fn link(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions { - let blue_amount = source.blue_power().pct(skill.multiplier()); - results.push(Resolution::new(source, target).event(target.recharge(skill, 0, blue_amount))); + let swap = match target.green_life().checked_sub(source.green_life()) { + Some(s) => s.pct(skill.multiplier()), + None => 0 + }; - let link = skill.effect()[0].set_meta(EffectMeta::LinkTarget(target.id)); - results.push(Resolution::new(source, target).event(source.add_effect(skill, link)).stages(EventStages::PostOnly)); + target.deal_blue_damage(skill, swap) + .into_iter() + .for_each(|e| results.push(Resolution::new(source, target).event(e))); + + source.deal_green_damage(skill, swap) + .into_iter() + .for_each(|e| results.push(Resolution::new(source, source).event(e).stages(EventStages::PostOnly))); + + results.push(Resolution::new(source, source) + .event(source.add_effect(skill, skill.effect()[0])).stages(EventStages::PostOnly)); return results; } -fn link_hit(source: &Construct, target: &Construct, mut results: Resolutions, game: &mut Game, event: Event) -> Resolutions { - match event { - Event::Damage { amount, skill, mitigation: _, colour } => { - let link = target.effects.iter().find(|e| e.effect == Effect::Link).unwrap(); - - if let Some(EffectMeta::LinkTarget(link_target_id)) = link.meta { - let mut link_target = game.construct_by_id(link_target_id).unwrap(); - - let res = match colour { - Colour::Red => link_target.deal_red_damage(skill, amount), - Colour::Blue => link_target.deal_blue_damage(skill, amount), - Colour::Green => link_target.deal_green_damage(skill, amount), - }; - - results.push(Resolution::new(target, link_target).event(Event::Skill { skill: Skill::Link})); - res.into_iter().for_each(|e| results.push(Resolution::new(&source, &link_target) - .event(e).stages(EventStages::EndPost))); - } else { - panic!("not a link target {:?}", link); - } - - return results; - }, - _ => panic!("{:?} link hit not damage event", event), - } -} - fn silence(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions { results.push(Resolution::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); From 6045a77bb688bffc09bbaf54894a51c485340f0b Mon Sep 17 00:00:00 2001 From: Mashy Date: Mon, 16 Sep 2019 15:25:21 +1000 Subject: [PATCH 06/24] link description & cleanup --- server/src/effect.rs | 6 - server/src/item.rs | 361 +++++++++++++++++++++---------------------- 2 files changed, 179 insertions(+), 188 deletions(-) diff --git a/server/src/effect.rs b/server/src/effect.rs index 83c445d9..f6f1522d 100644 --- a/server/src/effect.rs +++ b/server/src/effect.rs @@ -38,7 +38,6 @@ pub enum Effect { Absorption, // magic immunity - Link, // effects over time Triage, @@ -125,8 +124,6 @@ impl Effect { Effect::Haste => vec![Stat::Speed], Effect::Slow => vec![Stat::Speed], - Effect::Link => vec![Stat::BlueDamageTaken, Stat::GreenDamageTaken, Stat::RedDamageTaken], - _ => vec![], } } @@ -146,8 +143,6 @@ impl Effect { _ => 100, }), - Effect::Link => value >> 1, - Effect::Absorption => value + match meta { Some(EffectMeta::AddedDamage(d)) => d, _ => panic!("absorb meta not damage"), @@ -194,7 +189,6 @@ impl Effect { // magic Effect::Hybrid => Some(Colour::Green), - Effect::Link => Some(Colour::Green), Effect::Invert => Some(Colour::Green), // effects over time diff --git a/server/src/item.rs b/server/src/item.rs index 3c5c29f9..6ba76bf1 100644 --- a/server/src/item.rs +++ b/server/src/item.rs @@ -785,9 +785,11 @@ impl Item { Item::Link| Item::LinkPlus | Item::LinkPlusPlus => format!( - "Caster links with target. Linked constructs split incoming Damage evenly. - Recharges target BlueLife based on {:?}% of BluePower", - self.into_skill().unwrap().multiplier()), + "Form a link with target swapping relative life values. + If the target construct has more green life than caster, {:?}% of green life difference as blue damage to the target and heal to the caster. + Stuns caster for {:?}T in the process.", + self.into_skill().unwrap().multiplier(), + self.into_skill().unwrap().effect()[0].get_duration()), Item::Silence| Item::SilencePlus | @@ -813,10 +815,9 @@ impl Item { Item::Restrict| Item::RestrictPlus | Item::RestrictPlusPlus => format!( - "Block the target from using red skills for {:?}T and deals {:?}% RedPower as red damage. {}", + "Block the target from using red skills for {:?}T and deals {:?}% RedPower as red damage. Deals 35% more damage per red skill on target", self.into_skill().unwrap().effect()[0].get_duration(), - self.into_skill().unwrap().multiplier(), - "Deals 35% more damage per red skill on target"), + self.into_skill().unwrap().multiplier()), Item::Bash| Item::BashPlus | @@ -960,66 +961,62 @@ impl Item { Item::ChaosPlus => vec![Item::Chaos, Item::Chaos, Item::Chaos], Item::ChaosPlusPlus => vec![Item::ChaosPlus, Item::ChaosPlus, Item::ChaosPlus], - Item::PowerRR => vec![Item::Power, Item::Red, Item::Red], - Item::PowerGG => vec![Item::Power, Item::Green, Item::Green], - Item::PowerBB => vec![Item::Power, Item::Blue, Item::Blue], - Item::PowerRG => vec![Item::Power, Item::Red, Item::Green], - Item::PowerGB => vec![Item::Power, Item::Green, Item::Blue], - Item::PowerRB => vec![Item::Power, Item::Red, Item::Blue], - Item::PowerRRPlus => vec![Item::PowerRR, Item::PowerRR, Item::PowerRR], - Item::PowerGGPlus => vec![Item::PowerGG, Item::PowerGG, Item::PowerGG], - Item::PowerBBPlus => vec![Item::PowerBB, Item::PowerBB, Item::PowerBB], - Item::PowerRGPlus => vec![Item::PowerRG, Item::PowerRG, Item::PowerRG], - Item::PowerGBPlus => vec![Item::PowerGB, Item::PowerGB, Item::PowerGB], - Item::PowerRBPlus => vec![Item::PowerRB, Item::PowerRB, Item::PowerRB], - Item::PowerRRPlusPlus => vec![Item::PowerRRPlus, Item::PowerRRPlus, Item::PowerRRPlus], - Item::PowerGGPlusPlus => vec![Item::PowerGGPlus, Item::PowerGGPlus, Item::PowerGGPlus], - Item::PowerBBPlusPlus => vec![Item::PowerBBPlus, Item::PowerBBPlus, Item::PowerBBPlus], - Item::PowerRGPlusPlus => vec![Item::PowerRGPlus, Item::PowerRGPlus, Item::PowerRGPlus], - Item::PowerGBPlusPlus => vec![Item::PowerGBPlus, Item::PowerGBPlus, Item::PowerGBPlus], - Item::PowerRBPlusPlus => vec![Item::PowerRBPlus, Item::PowerRBPlus, Item::PowerRBPlus], + Item::PowerRR => vec![Item::Power, Item::Red, Item::Red], + Item::PowerGG => vec![Item::Power, Item::Green, Item::Green], + Item::PowerBB => vec![Item::Power, Item::Blue, Item::Blue], + Item::PowerRG => vec![Item::Power, Item::Red, Item::Green], + Item::PowerGB => vec![Item::Power, Item::Green, Item::Blue], + Item::PowerRB => vec![Item::Power, Item::Red, Item::Blue], + Item::PowerRRPlus => vec![Item::PowerRR, Item::PowerRR, Item::PowerRR], + Item::PowerGGPlus => vec![Item::PowerGG, Item::PowerGG, Item::PowerGG], + Item::PowerBBPlus => vec![Item::PowerBB, Item::PowerBB, Item::PowerBB], + Item::PowerRGPlus => vec![Item::PowerRG, Item::PowerRG, Item::PowerRG], + Item::PowerGBPlus => vec![Item::PowerGB, Item::PowerGB, Item::PowerGB], + Item::PowerRBPlus => vec![Item::PowerRB, Item::PowerRB, Item::PowerRB], + Item::PowerRRPlusPlus => vec![Item::PowerRRPlus, Item::PowerRRPlus, Item::PowerRRPlus], + Item::PowerGGPlusPlus => vec![Item::PowerGGPlus, Item::PowerGGPlus, Item::PowerGGPlus], + Item::PowerBBPlusPlus => vec![Item::PowerBBPlus, Item::PowerBBPlus, Item::PowerBBPlus], + Item::PowerRGPlusPlus => vec![Item::PowerRGPlus, Item::PowerRGPlus, Item::PowerRGPlus], + Item::PowerGBPlusPlus => vec![Item::PowerGBPlus, Item::PowerGBPlus, Item::PowerGBPlus], + Item::PowerRBPlusPlus => vec![Item::PowerRBPlus, Item::PowerRBPlus, Item::PowerRBPlus], - Item::LifeRR => vec![Item::Life, Item::Red, Item::Red], - Item::LifeGG => vec![Item::Life, Item::Green, Item::Green], - Item::LifeBB => vec![Item::Life, Item::Blue, Item::Blue], - Item::LifeRG => vec![Item::Life, Item::Red, Item::Green], - Item::LifeGB => vec![Item::Life, Item::Green, Item::Blue], - Item::LifeRB => vec![Item::Life, Item::Red, Item::Blue], - Item::LifeRRPlus => vec![Item::LifeRR, Item::LifeRR, Item::LifeRR], - Item::LifeGGPlus => vec![Item::LifeGG, Item::LifeGG, Item::LifeGG], - Item::LifeBBPlus => vec![Item::LifeBB, Item::LifeBB, Item::LifeBB], - Item::LifeRGPlus => vec![Item::LifeRG, Item::LifeRG, Item::LifeRG], - Item::LifeGBPlus => vec![Item::LifeGB, Item::LifeGB, Item::LifeGB], - Item::LifeRBPlus => vec![Item::LifeRB, Item::LifeRB, Item::LifeRB], - Item::LifeRRPlusPlus => vec![Item::LifeRRPlus, Item::LifeRRPlus, Item::LifeRRPlus], - Item::LifeGGPlusPlus => vec![Item::LifeGGPlus, Item::LifeGGPlus, Item::LifeGGPlus], - Item::LifeBBPlusPlus => vec![Item::LifeBBPlus, Item::LifeBBPlus, Item::LifeBBPlus], - Item::LifeRGPlusPlus => vec![Item::LifeRGPlus, Item::LifeRGPlus, Item::LifeRGPlus], - Item::LifeGBPlusPlus => vec![Item::LifeGBPlus, Item::LifeGBPlus, Item::LifeGBPlus], - Item::LifeRBPlusPlus => vec![Item::LifeRBPlus, Item::LifeRBPlus, Item::LifeRBPlus], + Item::LifeRR => vec![Item::Life, Item::Red, Item::Red], + Item::LifeGG => vec![Item::Life, Item::Green, Item::Green], + Item::LifeBB => vec![Item::Life, Item::Blue, Item::Blue], + Item::LifeRG => vec![Item::Life, Item::Red, Item::Green], + Item::LifeGB => vec![Item::Life, Item::Green, Item::Blue], + Item::LifeRB => vec![Item::Life, Item::Red, Item::Blue], + Item::LifeRRPlus => vec![Item::LifeRR, Item::LifeRR, Item::LifeRR], + Item::LifeGGPlus => vec![Item::LifeGG, Item::LifeGG, Item::LifeGG], + Item::LifeBBPlus => vec![Item::LifeBB, Item::LifeBB, Item::LifeBB], + Item::LifeRGPlus => vec![Item::LifeRG, Item::LifeRG, Item::LifeRG], + Item::LifeGBPlus => vec![Item::LifeGB, Item::LifeGB, Item::LifeGB], + Item::LifeRBPlus => vec![Item::LifeRB, Item::LifeRB, Item::LifeRB], + Item::LifeRRPlusPlus => vec![Item::LifeRRPlus, Item::LifeRRPlus, Item::LifeRRPlus], + Item::LifeGGPlusPlus => vec![Item::LifeGGPlus, Item::LifeGGPlus, Item::LifeGGPlus], + Item::LifeBBPlusPlus => vec![Item::LifeBBPlus, Item::LifeBBPlus, Item::LifeBBPlus], + Item::LifeRGPlusPlus => vec![Item::LifeRGPlus, Item::LifeRGPlus, Item::LifeRGPlus], + Item::LifeGBPlusPlus => vec![Item::LifeGBPlus, Item::LifeGBPlus, Item::LifeGBPlus], + Item::LifeRBPlusPlus => vec![Item::LifeRBPlus, Item::LifeRBPlus, Item::LifeRBPlus], - - - Item::SpeedRR => vec![Item::Speed, Item::Red, Item::Red], - Item::SpeedGG => vec![Item::Speed, Item::Green, Item::Green], - Item::SpeedBB => vec![Item::Speed, Item::Blue, Item::Blue], - Item::SpeedRG => vec![Item::Speed, Item::Red, Item::Green], - Item::SpeedGB => vec![Item::Speed, Item::Green, Item::Blue], - Item::SpeedRB => vec![Item::Speed, Item::Red, Item::Blue], - - Item::SpeedRRPlus => vec![Item::SpeedRR, Item::SpeedRR, Item::SpeedRR], - Item::SpeedGGPlus => vec![Item::SpeedGG, Item::SpeedGG, Item::SpeedGG], - Item::SpeedBBPlus => vec![Item::SpeedBB, Item::SpeedBB, Item::SpeedBB], - Item::SpeedRGPlus => vec![Item::SpeedRG, Item::SpeedRG, Item::SpeedRG], - Item::SpeedGBPlus => vec![Item::SpeedGB, Item::SpeedGB, Item::SpeedGB], - Item::SpeedRBPlus => vec![Item::SpeedRB, Item::SpeedRB, Item::SpeedRB], - - Item::SpeedRRPlusPlus => vec![Item::SpeedRRPlus, Item::SpeedRRPlus, Item::SpeedRRPlus], - Item::SpeedGGPlusPlus => vec![Item::SpeedGGPlus, Item::SpeedGGPlus, Item::SpeedGGPlus], - Item::SpeedBBPlusPlus => vec![Item::SpeedBBPlus, Item::SpeedBBPlus, Item::SpeedBBPlus], - Item::SpeedRGPlusPlus => vec![Item::SpeedRGPlus, Item::SpeedRGPlus, Item::SpeedRGPlus], - Item::SpeedGBPlusPlus => vec![Item::SpeedGBPlus, Item::SpeedGBPlus, Item::SpeedGBPlus], - Item::SpeedRBPlusPlus => vec![Item::SpeedRBPlus, Item::SpeedRBPlus, Item::SpeedRBPlus], + Item::SpeedRR => vec![Item::Speed, Item::Red, Item::Red], + Item::SpeedGG => vec![Item::Speed, Item::Green, Item::Green], + Item::SpeedBB => vec![Item::Speed, Item::Blue, Item::Blue], + Item::SpeedRG => vec![Item::Speed, Item::Red, Item::Green], + Item::SpeedGB => vec![Item::Speed, Item::Green, Item::Blue], + Item::SpeedRB => vec![Item::Speed, Item::Red, Item::Blue], + Item::SpeedRRPlus => vec![Item::SpeedRR, Item::SpeedRR, Item::SpeedRR], + Item::SpeedGGPlus => vec![Item::SpeedGG, Item::SpeedGG, Item::SpeedGG], + Item::SpeedBBPlus => vec![Item::SpeedBB, Item::SpeedBB, Item::SpeedBB], + Item::SpeedRGPlus => vec![Item::SpeedRG, Item::SpeedRG, Item::SpeedRG], + Item::SpeedGBPlus => vec![Item::SpeedGB, Item::SpeedGB, Item::SpeedGB], + Item::SpeedRBPlus => vec![Item::SpeedRB, Item::SpeedRB, Item::SpeedRB], + Item::SpeedRRPlusPlus => vec![Item::SpeedRRPlus, Item::SpeedRRPlus, Item::SpeedRRPlus], + Item::SpeedGGPlusPlus => vec![Item::SpeedGGPlus, Item::SpeedGGPlus, Item::SpeedGGPlus], + Item::SpeedBBPlusPlus => vec![Item::SpeedBBPlus, Item::SpeedBBPlus, Item::SpeedBBPlus], + Item::SpeedRGPlusPlus => vec![Item::SpeedRGPlus, Item::SpeedRGPlus, Item::SpeedRGPlus], + Item::SpeedGBPlusPlus => vec![Item::SpeedGBPlus, Item::SpeedGBPlus, Item::SpeedGBPlus], + Item::SpeedRBPlusPlus => vec![Item::SpeedRBPlus, Item::SpeedRBPlus, Item::SpeedRBPlus], _ => vec![*self], } @@ -1029,129 +1026,129 @@ impl Item { impl From for Item { fn from(skill: Skill) -> Item { match skill { - Skill::Absorb => Item::Absorb, - Skill::AbsorbPlus => Item::AbsorbPlus, - Skill::AbsorbPlusPlus => Item::AbsorbPlusPlus, - Skill::Amplify => Item::Amplify, - Skill::AmplifyPlus => Item::AmplifyPlus, - Skill::AmplifyPlusPlus => Item::AmplifyPlusPlus, + Skill::Absorb => Item::Absorb, + Skill::AbsorbPlus => Item::AbsorbPlus, + Skill::AbsorbPlusPlus => Item::AbsorbPlusPlus, + Skill::Amplify => Item::Amplify, + Skill::AmplifyPlus => Item::AmplifyPlus, + Skill::AmplifyPlusPlus => Item::AmplifyPlusPlus, Skill::Attack => Item::Attack, - Skill::Banish => Item::Banish, - Skill::BanishPlus => Item::BanishPlus, - Skill::BanishPlusPlus => Item::BanishPlusPlus, - Skill::Bash => Item::Bash, - Skill::BashPlus => Item::BashPlus, - Skill::BashPlusPlus => Item::BashPlusPlus, - Skill::Blast => Item::Blast, - Skill::BlastPlus => Item::BlastPlus, - Skill::BlastPlusPlus => Item::BlastPlusPlus, + Skill::Banish => Item::Banish, + Skill::BanishPlus => Item::BanishPlus, + Skill::BanishPlusPlus => Item::BanishPlusPlus, + Skill::Bash => Item::Bash, + Skill::BashPlus => Item::BashPlus, + Skill::BashPlusPlus => Item::BashPlusPlus, + Skill::Blast => Item::Blast, + Skill::BlastPlus => Item::BlastPlus, + Skill::BlastPlusPlus => Item::BlastPlusPlus, Skill::Block => Item::Block, Skill::Buff => Item::Buff, - Skill::Chaos => Item::Chaos, - Skill::ChaosPlus => Item::ChaosPlus, - Skill::ChaosPlusPlus => Item::ChaosPlusPlus, - Skill::Counter => Item::Counter, - Skill::CounterPlus => Item::CounterPlus, - Skill::CounterPlusPlus => Item::CounterPlusPlus, - Skill::Curse => Item::Curse, - Skill::CursePlus => Item::CursePlus, - Skill::CursePlusPlus => Item::CursePlusPlus, + Skill::Chaos => Item::Chaos, + Skill::ChaosPlus => Item::ChaosPlus, + Skill::ChaosPlusPlus => Item::ChaosPlusPlus, + Skill::Counter => Item::Counter, + Skill::CounterPlus => Item::CounterPlus, + Skill::CounterPlusPlus => Item::CounterPlusPlus, + Skill::Curse => Item::Curse, + Skill::CursePlus => Item::CursePlus, + Skill::CursePlusPlus => Item::CursePlusPlus, Skill::Debuff => Item::Debuff, - Skill::Decay => Item::Decay, - Skill::DecayPlus => Item::DecayPlus, - Skill::DecayPlusPlus => Item::DecayPlusPlus, - Skill::Electrify => Item::Electrify, - Skill::ElectrifyPlus => Item::ElectrifyPlus, - Skill::ElectrifyPlusPlus => Item::ElectrifyPlusPlus, - Skill::Haste => Item::Haste, - Skill::HastePlus => Item::HastePlus, - Skill::HastePlusPlus => Item::HastePlusPlus, - Skill::Heal => Item::Heal, - Skill::HealPlus => Item::HealPlus, - Skill::HealPlusPlus => Item::HealPlusPlus, - Skill::Hex => Item::Hex, - Skill::HexPlus => Item::HexPlus, - Skill::HexPlusPlus => Item::HexPlusPlus, - Skill::Hybrid => Item::Hybrid, - Skill::HybridPlus => Item::HybridPlus, - Skill::HybridPlusPlus => Item::HybridPlusPlus, - Skill::Intercept => Item::Intercept, - Skill::InterceptPlus => Item::InterceptPlus, - Skill::InterceptPlusPlus => Item::InterceptPlusPlus, - Skill::Invert => Item::Invert, - Skill::InvertPlus => Item::InvertPlus, - Skill::InvertPlusPlus => Item::InvertPlusPlus, - Skill::Purge => Item::Purge, - Skill::PurgePlus => Item::PurgePlus, - Skill::PurgePlusPlus => Item::PurgePlusPlus, - Skill::Purify => Item::Purify, - Skill::PurifyPlus => Item::PurifyPlus, - Skill::PurifyPlusPlus => Item::PurifyPlusPlus, - Skill::Recharge => Item::Recharge, - Skill::RechargePlus => Item::RechargePlus, - Skill::RechargePlusPlus => Item::RechargePlusPlus, - Skill::Reflect => Item::Reflect, - Skill::ReflectPlus => Item::ReflectPlus, - Skill::ReflectPlusPlus => Item::ReflectPlusPlus, - Skill::Restrict => Item::Restrict, - Skill::RestrictPlus => Item::RestrictPlus, - Skill::RestrictPlusPlus => Item::RestrictPlusPlus, - Skill::Ruin => Item::Ruin, - Skill::RuinPlus => Item::RuinPlus, - Skill::RuinPlusPlus => Item::RuinPlusPlus, - Skill::Link => Item::Link, - Skill::LinkPlus => Item::LinkPlus, - Skill::LinkPlusPlus => Item::LinkPlusPlus, - Skill::Silence => Item::Silence, - Skill::SilencePlus => Item::SilencePlus, - Skill::SilencePlusPlus => Item::SilencePlusPlus, - Skill::Siphon => Item::Siphon, - Skill::SiphonPlus => Item::SiphonPlus, - Skill::SiphonPlusPlus => Item::SiphonPlusPlus, - Skill::Slay => Item::Slay, - Skill::SlayPlus => Item::SlayPlus, - Skill::SlayPlusPlus => Item::SlayPlusPlus, - Skill::Sleep => Item::Sleep, - Skill::SleepPlus => Item::SleepPlus, - Skill::SleepPlusPlus => Item::SleepPlusPlus, - Skill::Strike => Item::Strike, - Skill::StrikePlus => Item::StrikePlus, - Skill::StrikePlusPlus => Item::StrikePlusPlus, + Skill::Decay => Item::Decay, + Skill::DecayPlus => Item::DecayPlus, + Skill::DecayPlusPlus => Item::DecayPlusPlus, + Skill::Electrify => Item::Electrify, + Skill::ElectrifyPlus => Item::ElectrifyPlus, + Skill::ElectrifyPlusPlus=> Item::ElectrifyPlusPlus, + Skill::Haste => Item::Haste, + Skill::HastePlus => Item::HastePlus, + Skill::HastePlusPlus => Item::HastePlusPlus, + Skill::Heal => Item::Heal, + Skill::HealPlus => Item::HealPlus, + Skill::HealPlusPlus => Item::HealPlusPlus, + Skill::Hex => Item::Hex, + Skill::HexPlus => Item::HexPlus, + Skill::HexPlusPlus => Item::HexPlusPlus, + Skill::Hybrid => Item::Hybrid, + Skill::HybridPlus => Item::HybridPlus, + Skill::HybridPlusPlus => Item::HybridPlusPlus, + Skill::Intercept => Item::Intercept, + Skill::InterceptPlus => Item::InterceptPlus, + Skill::InterceptPlusPlus=> Item::InterceptPlusPlus, + Skill::Invert => Item::Invert, + Skill::InvertPlus => Item::InvertPlus, + Skill::InvertPlusPlus => Item::InvertPlusPlus, + Skill::Purge => Item::Purge, + Skill::PurgePlus => Item::PurgePlus, + Skill::PurgePlusPlus => Item::PurgePlusPlus, + Skill::Purify => Item::Purify, + Skill::PurifyPlus => Item::PurifyPlus, + Skill::PurifyPlusPlus => Item::PurifyPlusPlus, + Skill::Recharge => Item::Recharge, + Skill::RechargePlus => Item::RechargePlus, + Skill::RechargePlusPlus => Item::RechargePlusPlus, + Skill::Reflect => Item::Reflect, + Skill::ReflectPlus => Item::ReflectPlus, + Skill::ReflectPlusPlus => Item::ReflectPlusPlus, + Skill::Restrict => Item::Restrict, + Skill::RestrictPlus => Item::RestrictPlus, + Skill::RestrictPlusPlus => Item::RestrictPlusPlus, + Skill::Ruin => Item::Ruin, + Skill::RuinPlus => Item::RuinPlus, + Skill::RuinPlusPlus => Item::RuinPlusPlus, + Skill::Link => Item::Link, + Skill::LinkPlus => Item::LinkPlus, + Skill::LinkPlusPlus => Item::LinkPlusPlus, + Skill::Silence => Item::Silence, + Skill::SilencePlus => Item::SilencePlus, + Skill::SilencePlusPlus => Item::SilencePlusPlus, + Skill::Siphon => Item::Siphon, + Skill::SiphonPlus => Item::SiphonPlus, + Skill::SiphonPlusPlus => Item::SiphonPlusPlus, + Skill::Slay => Item::Slay, + Skill::SlayPlus => Item::SlayPlus, + Skill::SlayPlusPlus => Item::SlayPlusPlus, + Skill::Sleep => Item::Sleep, + Skill::SleepPlus => Item::SleepPlus, + Skill::SleepPlusPlus => Item::SleepPlusPlus, + Skill::Strike => Item::Strike, + Skill::StrikePlus => Item::StrikePlus, + Skill::StrikePlusPlus => Item::StrikePlusPlus, Skill::Stun => Item::Stun, - Skill::Sustain => Item::Sustain, - Skill::SustainPlus => Item::SustainPlus, - Skill::SustainPlusPlus => Item::SustainPlusPlus, - Skill::Break => Item::Break, - Skill::BreakPlus => Item::BreakPlus, - Skill::BreakPlusPlus => Item::BreakPlusPlus, - Skill::Triage => Item::Triage, - Skill::TriagePlus => Item::TriagePlus, - Skill::TriagePlusPlus => Item::TriagePlusPlus, + Skill::Sustain => Item::Sustain, + Skill::SustainPlus => Item::SustainPlus, + Skill::SustainPlusPlus => Item::SustainPlusPlus, + Skill::Break => Item::Break, + Skill::BreakPlus => Item::BreakPlus, + Skill::BreakPlusPlus => Item::BreakPlusPlus, + Skill::Triage => Item::Triage, + Skill::TriagePlus => Item::TriagePlus, + Skill::TriagePlusPlus => Item::TriagePlusPlus, // Convert subskills into parent skills - Skill::Electrocute => Item::Electrify, - Skill::ElectrocutePlus => Item::ElectrifyPlus, - Skill::ElectrocutePlusPlus => Item::ElectrifyPlusPlus, - Skill::ElectrocuteTick => Item::Electrify, - Skill::ElectrocuteTickPlus => Item::ElectrifyPlus, - Skill::ElectrocuteTickPlusPlus => Item::ElectrifyPlus, - Skill::DecayTick => Item::Decay, - Skill::DecayTickPlus => Item::DecayPlus, - Skill::DecayTickPlusPlus => Item::DecayPlusPlus, - Skill::Absorption => Item::Absorb, - Skill::AbsorptionPlus => Item::AbsorbPlus, - Skill::AbsorptionPlusPlus => Item::AbsorbPlusPlus, - Skill::HasteStrike => Item::Haste, - Skill::HybridBlast => Item::Hybrid, - Skill::CounterAttack => Item::Counter, - Skill::CounterAttackPlus => Item::CounterPlus, - Skill::CounterAttackPlusPlus => Item::CounterPlusPlus, - Skill::SiphonTick => Item::Siphon, - Skill::SiphonTickPlus => Item::SiphonPlus, - Skill::SiphonTickPlusPlus => Item::SiphonPlusPlus, - Skill::TriageTick => Item::Triage, - Skill::TriageTickPlus => Item::TriagePlus, - Skill::TriageTickPlusPlus => Item::TriagePlusPlus, + Skill::Electrocute => Item::Electrify, + Skill::ElectrocutePlus => Item::ElectrifyPlus, + Skill::ElectrocutePlusPlus => Item::ElectrifyPlusPlus, + Skill::ElectrocuteTick => Item::Electrify, + Skill::ElectrocuteTickPlus => Item::ElectrifyPlus, + Skill::ElectrocuteTickPlusPlus => Item::ElectrifyPlus, + Skill::DecayTick => Item::Decay, + Skill::DecayTickPlus => Item::DecayPlus, + Skill::DecayTickPlusPlus => Item::DecayPlusPlus, + Skill::Absorption => Item::Absorb, + Skill::AbsorptionPlus => Item::AbsorbPlus, + Skill::AbsorptionPlusPlus => Item::AbsorbPlusPlus, + Skill::HasteStrike => Item::Haste, + Skill::HybridBlast => Item::Hybrid, + Skill::CounterAttack => Item::Counter, + Skill::CounterAttackPlus => Item::CounterPlus, + Skill::CounterAttackPlusPlus => Item::CounterPlusPlus, + Skill::SiphonTick => Item::Siphon, + Skill::SiphonTickPlus => Item::SiphonPlus, + Skill::SiphonTickPlusPlus => Item::SiphonPlusPlus, + Skill::TriageTick => Item::Triage, + Skill::TriageTickPlus => Item::TriagePlus, + Skill::TriageTickPlusPlus => Item::TriagePlusPlus, } } } @@ -1159,7 +1156,7 @@ impl From for Item { impl From for Item { fn from(spec: Spec) -> Item { match spec { - Spec::Speed => Item::Speed, + Spec::Speed => Item::Speed, Spec::SpeedRR => Item::SpeedRR, Spec::SpeedBB => Item::SpeedBB, Spec::SpeedGG => Item::SpeedGG, @@ -1181,7 +1178,7 @@ impl From for Item { Spec::SpeedGBPlusPlus => Item::SpeedGBPlusPlus, Spec::SpeedRBPlusPlus => Item::SpeedRBPlusPlus, - Spec::Power => Item::Power, + Spec::Power => Item::Power, Spec::PowerRR => Item::PowerRR, Spec::PowerBB => Item::PowerBB, Spec::PowerGG => Item::PowerGG, From 50f2afd657baa752a2f72e85f9deb22e5216b7fd Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 15:26:44 +1000 Subject: [PATCH 07/24] strike stuff --- client/assets/styles/styles.less | 2 +- client/src/animations.socket.jsx | 16 ++++++++-------- client/src/components/anims/strike.jsx | 15 +++++++++++---- client/src/test.game.js | 12 ++++++------ 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/client/assets/styles/styles.less b/client/assets/styles/styles.less index 3ca91487..29e06109 100644 --- a/client/assets/styles/styles.less +++ b/client/assets/styles/styles.less @@ -97,7 +97,7 @@ dl { &.animations-test { grid-template-columns: 1fr 9fr 1fr; grid-template-areas: - "hdr hdr ctrl" + "nav hdr ctrl" "nav main ctrl" "nav main ctrl"; diff --git a/client/src/animations.socket.jsx b/client/src/animations.socket.jsx index c1567fa5..edd822c6 100644 --- a/client/src/animations.socket.jsx +++ b/client/src/animations.socket.jsx @@ -6,6 +6,7 @@ const eachSeries = require('async/eachSeries'); const actions = require('./actions'); const { TIMES } = require('./constants'); const animations = require('./animations.utils'); +const { removeTier } = require('./utils'); const SOCKET_URL = process.env.NODE_ENV === 'production' ? 'wss://mnml.gg/api/ws' : 'ws://localhost/api/ws'; @@ -28,6 +29,7 @@ function createSocket(store) { if (animating) return false; store.dispatch(actions.setAnimating(true)); + // stop fetching the game state til animations are done return eachSeries(newRes, (r, cb) => { if (['Disable', 'TargetKo'].includes(r.event[0])) return cb(); @@ -37,15 +39,14 @@ function createSocket(store) { const timeout = animations.getTime(sequence); const anims = animations.getObjects(r, sequence, game, account); const text = animations.getText(r, sequence); + store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r, game))); - store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r))); - - if (sequence.includes('START_SKILL')) store.dispatch(actions.setAnimSource(anims.animSource)); - if (sequence.includes('END_SKILL')) { + if (sequence.includes('START_SKILL') && anims.animSource) store.dispatch(actions.setAnimSource(anims.animSource)); + if (sequence.includes('END_SKILL') && anims.animTarget) { store.dispatch(actions.setAnimTarget(anims.animTarget)); - if (!['Banish', 'Invert'].includes(anims.animTarget.skill)) store.dispatch(actions.setAnimCb(cb)); + if (!['Banish', 'Invert'].includes(removeTier(anims.animTarget.skill))) store.dispatch(actions.setAnimCb(cb)); } - if (sequence.includes('POST_SKILL')) { + if (sequence.includes('POST_SKILL' && text)) { // timeout to prevent text classes from being added too soon setTimeout( () => store.dispatch(actions.setAnimText(text)), @@ -58,7 +59,7 @@ function createSocket(store) { store.dispatch(actions.setAnimText(null)); store.dispatch(actions.setAnimFocus([])); if (!sequence.includes('END_SKILL') - || ['Banish', 'Invert'].includes(anims.animTarget.skill)) return cb(); + || ['Banish', 'Invert'].includes(removeTier(anims.animTarget.skill))) return cb(); return true; }, timeout); }, err => { @@ -70,7 +71,6 @@ function createSocket(store) { store.dispatch(actions.setAnimating(false)); store.dispatch(actions.setSkip(false)); - store.dispatch(actions.setResolution(null)); // set the game state so resolutions don't fire twice store.dispatch(actions.setGame(game)); diff --git a/client/src/components/anims/strike.jsx b/client/src/components/anims/strike.jsx index 066fe1c5..00dbbb18 100644 --- a/client/src/components/anims/strike.jsx +++ b/client/src/components/anims/strike.jsx @@ -20,6 +20,12 @@ class Strike extends Component { } render() { + // const { x, y } = (this.props && this.props.direction) || { x: 0, y: 0 }; + // const angle = (Math.atan(y / x) * (180 / Math.PI)) + 90; + // console.log(x, -y); + // console.log(angle); + // can't get this shit to work + return ( - + ); @@ -43,11 +50,11 @@ class Strike extends Component { this.animations.push(anime({ targets: ['#strike rect'], easing: 'easeOutExpo', - y: [400, 200, 200], + y: [800, 100, 100], x: [200, 0, 200], height: [200, 10, 0], width: [20, 400, 0], - delay: TIMES.TARGET_DELAY_MS, + delay: TIMES.TARGET_DELAY_MS / 2, duration: TIMES.TARGET_DURATION_MS, })); diff --git a/client/src/test.game.js b/client/src/test.game.js index e17cb8e0..6ee80a0b 100644 --- a/client/src/test.game.js +++ b/client/src/test.game.js @@ -35,7 +35,7 @@ function testGame(uuid) { "constructs": [ { "id": "82e8b940-411c-42a1-8fc2-484ec7207734", - "img": "8446736d-d682-4588-b8a0-5b7ba53bdb55", + "img": "b1be1dfe-f8b5-4467-8406-11f22ffb9e95", "account": "8552e0bf-340d-4fc8-b6fc-3d56b68fe2a1", "red_damage": { "base": 256, @@ -109,7 +109,7 @@ function testGame(uuid) { }, { "id": "96ca4a0e-fed2-4ea2-9ec5-ae308f8dde4b", - "img": "8446736d-d682-4588-b8a0-5b7ba53bdb55", + "img": "b1be1dfe-f8b5-4467-8406-11f22ffb9e95", "account": "8552e0bf-340d-4fc8-b6fc-3d56b68fe2a1", "red_damage": { "base": 256, @@ -186,7 +186,7 @@ function testGame(uuid) { { "id": "ea302c35-d326-475c-a867-8ad5b162165a", "account": "8552e0bf-340d-4fc8-b6fc-3d56b68fe2a1", - "img": "8446736d-d682-4588-b8a0-5b7ba53bdb55", + "img": "b1be1dfe-f8b5-4467-8406-11f22ffb9e95", "red_damage": { "base": 256, "value": Math.floor(Math.random() * 10000), @@ -302,7 +302,7 @@ function testGame(uuid) { { "id": "3aa0f284-1e1b-4054-b38a-b2d50db471bd", "account": uuid, - "img": "8446736d-d682-4588-b8a0-5b7ba53bdb55", + "img": "b1be1dfe-f8b5-4467-8406-11f22ffb9e95", "red_damage": { "base": 256, "value": Math.floor(Math.random() * 10000), @@ -389,7 +389,7 @@ function testGame(uuid) { { "id": "50e5d94e-8ebe-495c-a916-3eb509ff4683", "account": uuid, - "img": "8446736d-d682-4588-b8a0-5b7ba53bdb55", + "img": "b1be1dfe-f8b5-4467-8406-11f22ffb9e95", "red_damage": { "base": 256, "value": Math.floor(Math.random() * 10000), @@ -470,7 +470,7 @@ function testGame(uuid) { { "id": "5d49fe65-27f0-4372-90a3-334ef906a0f5", "account": uuid, - "img": "8446736d-d682-4588-b8a0-5b7ba53bdb55", + "img": "b1be1dfe-f8b5-4467-8406-11f22ffb9e95", "red_damage": { "base": 256, "value": Math.floor(Math.random() * 10000), From 9ae7317f3740d4e5f3ee6b5a9860ec50ff1e1f15 Mon Sep 17 00:00:00 2001 From: Mashy Date: Mon, 16 Sep 2019 15:56:21 +1000 Subject: [PATCH 08/24] block skills ->> 1T duration / no cooldown --- server/src/skill.rs | 92 ++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/server/src/skill.rs b/server/src/skill.rs index 5ae0bd11..d7542577 100644 --- a/server/src/skill.rs +++ b/server/src/skill.rs @@ -816,37 +816,37 @@ impl Skill { pub fn effect(&self) -> Vec { match self { // Modifiers - Skill::Amplify => vec![ConstructEffect {effect: Effect::Amplify, duration: 2, + Skill::Amplify => vec![ConstructEffect {effect: Effect::Amplify, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None}], - Skill::AmplifyPlus => vec![ConstructEffect {effect: Effect::Amplify, duration: 3, + Skill::AmplifyPlus => vec![ConstructEffect {effect: Effect::Amplify, duration: 3, meta: Some(EffectMeta::Multiplier(175)), tick: None}], - Skill::AmplifyPlusPlus => vec![ConstructEffect {effect: Effect::Amplify, duration: 4, + Skill::AmplifyPlusPlus => vec![ConstructEffect {effect: Effect::Amplify, duration: 4, meta: Some(EffectMeta::Multiplier(200)), tick: None}], - Skill::Banish => vec![ConstructEffect {effect: Effect::Banish, duration: 1,meta: None, tick: None}], - Skill::BanishPlus => vec![ConstructEffect {effect: Effect::Banish, duration: 2,meta: None, tick: None}], - Skill::BanishPlusPlus => vec![ConstructEffect {effect: Effect::Banish, duration: 3,meta: None, tick: None}], - Skill::Block => vec![ConstructEffect {effect: Effect::Block, duration: 1, - meta: Some(EffectMeta::Multiplier(50)), tick: None}], - Skill::Buff => vec![ConstructEffect {effect: Effect::Buff, duration: 2, - meta: Some(EffectMeta::Multiplier(125)), tick: None }], + Skill::Banish => vec![ConstructEffect {effect: Effect::Banish, duration: 1,meta: None, tick: None}], + Skill::BanishPlus => vec![ConstructEffect {effect: Effect::Banish, duration: 2,meta: None, tick: None}], + Skill::BanishPlusPlus => vec![ConstructEffect {effect: Effect::Banish, duration: 3,meta: None, tick: None}], + Skill::Block => vec![ConstructEffect {effect: Effect::Block, duration: 1, + meta: Some(EffectMeta::Multiplier(50)), tick: None}], + Skill::Buff => vec![ConstructEffect {effect: Effect::Buff, duration: 2, + meta: Some(EffectMeta::Multiplier(125)), tick: None }], - Skill::Electrify => vec![ConstructEffect {effect: Effect::Electric, duration: 2, - meta: Some(EffectMeta::Skill(Skill::Electrocute)), tick: None}], - Skill::ElectrifyPlus => vec![ConstructEffect {effect: Effect::Electric, duration: 3, - meta: Some(EffectMeta::Skill(Skill::ElectrocutePlus)), tick: None}], - Skill::ElectrifyPlusPlus => vec![ConstructEffect {effect: Effect::Electric, duration: 4, - meta: Some(EffectMeta::Skill(Skill::ElectrocutePlusPlus)), tick: None}], - Skill::Electrocute => vec![ConstructEffect {effect: Effect::Electrocute, duration: 3, - meta: Some(EffectMeta::Skill(Skill::ElectrocuteTick)), tick: None}], - Skill::ElectrocutePlus => vec![ConstructEffect {effect: Effect::Electrocute, duration: 4, - meta: Some(EffectMeta::Skill(Skill::ElectrocuteTickPlus)), tick: None}], - Skill::ElectrocutePlusPlus => vec![ConstructEffect {effect: Effect::Electrocute, duration: 5, - meta: Some(EffectMeta::Skill(Skill::ElectrocuteTickPlusPlus)), tick: None}], + Skill::Electrify => vec![ConstructEffect {effect: Effect::Electric, duration: 1, + meta: Some(EffectMeta::Skill(Skill::Electrocute)), tick: None}], + Skill::ElectrifyPlus => vec![ConstructEffect {effect: Effect::Electric, duration: 1, + meta: Some(EffectMeta::Skill(Skill::ElectrocutePlus)), tick: None}], + Skill::ElectrifyPlusPlus => vec![ConstructEffect {effect: Effect::Electric, duration: 1, + meta: Some(EffectMeta::Skill(Skill::ElectrocutePlusPlus)), tick: None}], + Skill::Electrocute => vec![ConstructEffect {effect: Effect::Electrocute, duration: 2, + meta: Some(EffectMeta::Skill(Skill::ElectrocuteTick)), tick: None}], + Skill::ElectrocutePlus => vec![ConstructEffect {effect: Effect::Electrocute, duration: 3, + meta: Some(EffectMeta::Skill(Skill::ElectrocuteTickPlus)), tick: None}], + Skill::ElectrocutePlusPlus => vec![ConstructEffect {effect: Effect::Electrocute, duration: 4, + meta: Some(EffectMeta::Skill(Skill::ElectrocuteTickPlusPlus)), tick: None}], - Skill::Sustain => vec![ConstructEffect {effect: Effect::Sustain, duration: 1, meta: None, tick: None }], - Skill::SustainPlus => vec![ConstructEffect {effect: Effect::Sustain, duration: 2, meta: None, tick: None }], - Skill::SustainPlusPlus => vec![ConstructEffect {effect: Effect::Sustain, duration: 3, meta: None, tick: None }], + Skill::Sustain => vec![ConstructEffect {effect: Effect::Sustain, duration: 1, meta: None, tick: None }], + Skill::SustainPlus => vec![ConstructEffect {effect: Effect::Sustain, duration: 1, meta: None, tick: None }], + Skill::SustainPlusPlus => vec![ConstructEffect {effect: Effect::Sustain, duration: 1, meta: None, tick: None }], Skill::Curse => vec![ConstructEffect {effect: Effect::Curse, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None}], @@ -900,16 +900,16 @@ impl Skill { Skill::InvertPlus => vec![ConstructEffect {effect: Effect::Invert, duration: 3, meta: None, tick: None}], Skill::InvertPlusPlus => vec![ConstructEffect {effect: Effect::Invert, duration: 4, meta: None, tick: None}], - Skill::Counter => vec![ConstructEffect {effect: Effect::Counter, duration: 2, + Skill::Counter => vec![ConstructEffect {effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttack)), tick: None}], - Skill::CounterPlus => vec![ConstructEffect {effect: Effect::Counter, duration: 2, + Skill::CounterPlus => vec![ConstructEffect {effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttackPlus)), tick: None}], - Skill::CounterPlusPlus => vec![ConstructEffect {effect: Effect::Counter, duration: 2, + Skill::CounterPlusPlus => vec![ConstructEffect {effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttackPlusPlus)), tick: None}], - Skill::Reflect => vec![ConstructEffect {effect: Effect::Reflect, duration: 1, meta: None, tick: None }], - Skill::ReflectPlus => vec![ConstructEffect {effect: Effect::Reflect, duration: 2, meta: None, tick: None }], - Skill::ReflectPlusPlus => vec![ConstructEffect {effect: Effect::Reflect, duration: 3, meta: None, tick: None }], + Skill::Reflect => vec![ConstructEffect {effect: Effect::Reflect, duration: 1, meta: None, tick: None }], + Skill::ReflectPlus => vec![ConstructEffect {effect: Effect::Reflect, duration: 1, meta: None, tick: None }], + Skill::ReflectPlusPlus => vec![ConstructEffect {effect: Effect::Reflect, duration: 1, meta: None, tick: None }], Skill::Break => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}, ConstructEffect {effect: Effect::Vulnerable, duration: 3, meta: Some(EffectMeta::Multiplier(150)), tick: None}], @@ -985,7 +985,7 @@ impl Skill { Skill::Block => None, // reduce damage Skill::Counter| Skill::CounterPlus | - Skill::CounterPlusPlus => Some(2), // avoid all damage + Skill::CounterPlusPlus => None, // avoid all damage Skill::Restrict=> Some(2), Skill::RestrictPlus => Some(2), @@ -1045,8 +1045,8 @@ impl Skill { Skill::SilencePlus => Some(2), Skill::SilencePlusPlus => Some(2), - Skill::Purify=> None, - Skill::PurifyPlus => None, + Skill::Purify | + Skill::PurifyPlus | Skill::PurifyPlusPlus => None, Skill::Purge=> None, @@ -1065,13 +1065,13 @@ impl Skill { Skill::HastePlus => Some(2), Skill::HastePlusPlus => Some(2), - Skill::Reflect=> Some(2), - Skill::ReflectPlus => Some(2), - Skill::ReflectPlusPlus => Some(2), + Skill::Reflect | + Skill::ReflectPlus | + Skill::ReflectPlusPlus => None, - Skill::Recharge=> Some(2), - Skill::RechargePlus => Some(2), - Skill::RechargePlusPlus => Some(2), + Skill::Recharge=> None, + Skill::RechargePlus => None, + Skill::RechargePlusPlus => None, Skill::Ruin=> Some(3), Skill::RuinPlus => Some(2), @@ -1085,17 +1085,17 @@ impl Skill { Skill::SleepPlus => Some(3), Skill::SleepPlusPlus => Some(3), - Skill::Sustain=> Some(1), - Skill::SustainPlus => Some(2), - Skill::SustainPlusPlus => Some(3), + Skill::Sustain | + Skill::SustainPlus | + Skill::SustainPlusPlus => None, Skill::Intercept=> Some(2), Skill::InterceptPlus => Some(2), Skill::InterceptPlusPlus => Some(2), - Skill::Electrify=>Some(1), - Skill::ElectrifyPlus =>Some(1), - Skill::ElectrifyPlusPlus =>Some(1), + Skill::Electrify | + Skill::ElectrifyPlus | + Skill::ElectrifyPlusPlus => None, Skill::Absorb| From a512bcb76cca1139789aaa92fe2e0adb5f055b37 Mon Sep 17 00:00:00 2001 From: Mashy Date: Mon, 16 Sep 2019 16:47:57 +1000 Subject: [PATCH 09/24] nerf purge -> flat (2 / 3 / 4)T no lockout scaling --- server/src/item.rs | 192 ++++++++++++++++++++++---------------------- server/src/skill.rs | 188 ++++++++++++++++++++++--------------------- 2 files changed, 194 insertions(+), 186 deletions(-) diff --git a/server/src/item.rs b/server/src/item.rs index 6ba76bf1..3d6e2d2f 100644 --- a/server/src/item.rs +++ b/server/src/item.rs @@ -385,102 +385,102 @@ impl Item { pub fn into_skill(&self) -> Option { match self { - Item::Absorb => Some(Skill::Absorb), - Item::AbsorbPlus => Some(Skill::AbsorbPlus), - Item::AbsorbPlusPlus => Some(Skill::AbsorbPlusPlus), - Item::Amplify => Some(Skill::Amplify), - Item::AmplifyPlus => Some(Skill::AmplifyPlus), - Item::AmplifyPlusPlus => Some(Skill::AmplifyPlusPlus), - Item::Attack => Some(Skill::Attack), - Item::Banish => Some(Skill::Banish), - Item::BanishPlus => Some(Skill::BanishPlus), - Item::BanishPlusPlus => Some(Skill::BanishPlusPlus), - Item::Bash => Some(Skill::Bash), - Item::BashPlus => Some(Skill::BashPlus), - Item::BashPlusPlus => Some(Skill::BashPlusPlus), - Item::Blast => Some(Skill::Blast), - Item::BlastPlus => Some(Skill::BlastPlus), - Item::BlastPlusPlus => Some(Skill::BlastPlusPlus), - Item::Block => Some(Skill::Block), - Item::Buff => Some(Skill::Buff), - Item::Chaos => Some(Skill::Chaos), - Item::ChaosPlus => Some(Skill::ChaosPlus), - Item::ChaosPlusPlus => Some(Skill::ChaosPlusPlus), - Item::Counter => Some(Skill::Counter), - Item::CounterPlus => Some(Skill::CounterPlus), - Item::CounterPlusPlus => Some(Skill::CounterPlusPlus), - Item::Curse => Some(Skill::Curse), - Item::CursePlus => Some(Skill::CursePlus), - Item::CursePlusPlus => Some(Skill::CursePlusPlus), - Item::Debuff => Some(Skill::Debuff), - Item::Decay => Some(Skill::Decay), - Item::DecayPlus => Some(Skill::DecayPlus), - Item::DecayPlusPlus => Some(Skill::DecayPlusPlus), - Item::Electrify => Some(Skill::Electrify), - Item::ElectrifyPlus => Some(Skill::ElectrifyPlus), - Item::ElectrifyPlusPlus => Some(Skill::ElectrifyPlusPlus), - Item::Haste => Some(Skill::Haste), - Item::HastePlus => Some(Skill::HastePlus), - Item::HastePlusPlus => Some(Skill::HastePlusPlus), - Item::Heal => Some(Skill::Heal), - Item::HealPlus => Some(Skill::HealPlus), - Item::HealPlusPlus => Some(Skill::HealPlusPlus), - Item::Hybrid => Some(Skill::Hybrid), - Item::HybridPlus => Some(Skill::HybridPlus), - Item::HybridPlusPlus => Some(Skill::HybridPlusPlus), - Item::Intercept => Some(Skill::Intercept), - Item::InterceptPlus => Some(Skill::InterceptPlus), - Item::InterceptPlusPlus => Some(Skill::InterceptPlusPlus), - Item::Invert => Some(Skill::Invert), - Item::InvertPlus => Some(Skill::InvertPlus), - Item::InvertPlusPlus => Some(Skill::InvertPlusPlus), - Item::Purge => Some(Skill::Purge), - Item::PurgePlus => Some(Skill::PurgePlus), - Item::PurgePlusPlus => Some(Skill::PurgePlusPlus), - Item::Purify => Some(Skill::Purify), - Item::PurifyPlus => Some(Skill::PurifyPlus), - Item::PurifyPlusPlus => Some(Skill::PurifyPlusPlus), - Item::Recharge => Some(Skill::Recharge), - Item::RechargePlus => Some(Skill::RechargePlus), - Item::RechargePlusPlus => Some(Skill::RechargePlusPlus), - Item::Reflect => Some(Skill::Reflect), - Item::ReflectPlus => Some(Skill::ReflectPlus), - Item::ReflectPlusPlus => Some(Skill::ReflectPlusPlus), - Item::Restrict => Some(Skill::Restrict), - Item::RestrictPlus => Some(Skill::RestrictPlus), - Item::RestrictPlusPlus => Some(Skill::RestrictPlusPlus), - Item::Ruin => Some(Skill::Ruin), - Item::RuinPlus => Some(Skill::RuinPlus), - Item::RuinPlusPlus => Some(Skill::RuinPlusPlus), - Item::Link => Some(Skill::Link), - Item::LinkPlus => Some(Skill::LinkPlus), - Item::LinkPlusPlus => Some(Skill::LinkPlusPlus), - Item::Silence => Some(Skill::Silence), - Item::SilencePlus => Some(Skill::SilencePlus), - Item::SilencePlusPlus => Some(Skill::SilencePlusPlus), - Item::Siphon => Some(Skill::Siphon), - Item::SiphonPlus => Some(Skill::SiphonPlus), - Item::SiphonPlusPlus => Some(Skill::SiphonPlusPlus), - Item::Slay => Some(Skill::Slay), - Item::SlayPlus => Some(Skill::SlayPlus), - Item::SlayPlusPlus => Some(Skill::SlayPlusPlus), - Item::Sleep => Some(Skill::Sleep), - Item::SleepPlus => Some(Skill::SleepPlus), - Item::SleepPlusPlus => Some(Skill::SleepPlusPlus), - Item::Strike => Some(Skill::Strike), - Item::StrikePlus => Some(Skill::StrikePlus), - Item::StrikePlusPlus => Some(Skill::StrikePlusPlus), - Item::Stun => Some(Skill::Stun), - Item::Sustain => Some(Skill::Sustain), - Item::SustainPlus => Some(Skill::SustainPlus), - Item::SustainPlusPlus => Some(Skill::SustainPlusPlus), - Item::Break => Some(Skill::Break), - Item::BreakPlus => Some(Skill::BreakPlus), - Item::BreakPlusPlus => Some(Skill::BreakPlusPlus), - Item::Triage => Some(Skill::Triage), - Item::TriagePlus => Some(Skill::TriagePlus), - Item::TriagePlusPlus => Some(Skill::TriagePlusPlus), - _ => None, + Item::Absorb => Some(Skill::Absorb), + Item::AbsorbPlus => Some(Skill::AbsorbPlus), + Item::AbsorbPlusPlus => Some(Skill::AbsorbPlusPlus), + Item::Amplify => Some(Skill::Amplify), + Item::AmplifyPlus => Some(Skill::AmplifyPlus), + Item::AmplifyPlusPlus => Some(Skill::AmplifyPlusPlus), + Item::Attack => Some(Skill::Attack), + Item::Banish => Some(Skill::Banish), + Item::BanishPlus => Some(Skill::BanishPlus), + Item::BanishPlusPlus => Some(Skill::BanishPlusPlus), + Item::Bash => Some(Skill::Bash), + Item::BashPlus => Some(Skill::BashPlus), + Item::BashPlusPlus => Some(Skill::BashPlusPlus), + Item::Blast => Some(Skill::Blast), + Item::BlastPlus => Some(Skill::BlastPlus), + Item::BlastPlusPlus => Some(Skill::BlastPlusPlus), + Item::Block => Some(Skill::Block), + Item::Buff => Some(Skill::Buff), + Item::Chaos => Some(Skill::Chaos), + Item::ChaosPlus => Some(Skill::ChaosPlus), + Item::ChaosPlusPlus => Some(Skill::ChaosPlusPlus), + Item::Counter => Some(Skill::Counter), + Item::CounterPlus => Some(Skill::CounterPlus), + Item::CounterPlusPlus => Some(Skill::CounterPlusPlus), + Item::Curse => Some(Skill::Curse), + Item::CursePlus => Some(Skill::CursePlus), + Item::CursePlusPlus => Some(Skill::CursePlusPlus), + Item::Debuff => Some(Skill::Debuff), + Item::Decay => Some(Skill::Decay), + Item::DecayPlus => Some(Skill::DecayPlus), + Item::DecayPlusPlus => Some(Skill::DecayPlusPlus), + Item::Electrify => Some(Skill::Electrify), + Item::ElectrifyPlus => Some(Skill::ElectrifyPlus), + Item::ElectrifyPlusPlus => Some(Skill::ElectrifyPlusPlus), + Item::Haste => Some(Skill::Haste), + Item::HastePlus => Some(Skill::HastePlus), + Item::HastePlusPlus => Some(Skill::HastePlusPlus), + Item::Heal => Some(Skill::Heal), + Item::HealPlus => Some(Skill::HealPlus), + Item::HealPlusPlus => Some(Skill::HealPlusPlus), + Item::Hybrid => Some(Skill::Hybrid), + Item::HybridPlus => Some(Skill::HybridPlus), + Item::HybridPlusPlus => Some(Skill::HybridPlusPlus), + Item::Intercept => Some(Skill::Intercept), + Item::InterceptPlus => Some(Skill::InterceptPlus), + Item::InterceptPlusPlus => Some(Skill::InterceptPlusPlus), + Item::Invert => Some(Skill::Invert), + Item::InvertPlus => Some(Skill::InvertPlus), + Item::InvertPlusPlus => Some(Skill::InvertPlusPlus), + Item::Purge => Some(Skill::Purge), + Item::PurgePlus => Some(Skill::PurgePlus), + Item::PurgePlusPlus => Some(Skill::PurgePlusPlus), + Item::Purify => Some(Skill::Purify), + Item::PurifyPlus => Some(Skill::PurifyPlus), + Item::PurifyPlusPlus => Some(Skill::PurifyPlusPlus), + Item::Recharge => Some(Skill::Recharge), + Item::RechargePlus => Some(Skill::RechargePlus), + Item::RechargePlusPlus => Some(Skill::RechargePlusPlus), + Item::Reflect => Some(Skill::Reflect), + Item::ReflectPlus => Some(Skill::ReflectPlus), + Item::ReflectPlusPlus => Some(Skill::ReflectPlusPlus), + Item::Restrict => Some(Skill::Restrict), + Item::RestrictPlus => Some(Skill::RestrictPlus), + Item::RestrictPlusPlus => Some(Skill::RestrictPlusPlus), + Item::Ruin => Some(Skill::Ruin), + Item::RuinPlus => Some(Skill::RuinPlus), + Item::RuinPlusPlus => Some(Skill::RuinPlusPlus), + Item::Link => Some(Skill::Link), + Item::LinkPlus => Some(Skill::LinkPlus), + Item::LinkPlusPlus => Some(Skill::LinkPlusPlus), + Item::Silence => Some(Skill::Silence), + Item::SilencePlus => Some(Skill::SilencePlus), + Item::SilencePlusPlus => Some(Skill::SilencePlusPlus), + Item::Siphon => Some(Skill::Siphon), + Item::SiphonPlus => Some(Skill::SiphonPlus), + Item::SiphonPlusPlus => Some(Skill::SiphonPlusPlus), + Item::Slay => Some(Skill::Slay), + Item::SlayPlus => Some(Skill::SlayPlus), + Item::SlayPlusPlus => Some(Skill::SlayPlusPlus), + Item::Sleep => Some(Skill::Sleep), + Item::SleepPlus => Some(Skill::SleepPlus), + Item::SleepPlusPlus => Some(Skill::SleepPlusPlus), + Item::Strike => Some(Skill::Strike), + Item::StrikePlus => Some(Skill::StrikePlus), + Item::StrikePlusPlus => Some(Skill::StrikePlusPlus), + Item::Stun => Some(Skill::Stun), + Item::Sustain => Some(Skill::Sustain), + Item::SustainPlus => Some(Skill::SustainPlus), + Item::SustainPlusPlus => Some(Skill::SustainPlusPlus), + Item::Break => Some(Skill::Break), + Item::BreakPlus => Some(Skill::BreakPlus), + Item::BreakPlusPlus => Some(Skill::BreakPlusPlus), + Item::Triage => Some(Skill::Triage), + Item::TriagePlus => Some(Skill::TriagePlus), + Item::TriagePlusPlus => Some(Skill::TriagePlusPlus), + _ => None, } } diff --git a/server/src/skill.rs b/server/src/skill.rs index d7542577..da57c70f 100644 --- a/server/src/skill.rs +++ b/server/src/skill.rs @@ -817,66 +817,70 @@ impl Skill { match self { // Modifiers Skill::Amplify => vec![ConstructEffect {effect: Effect::Amplify, duration: 2, - meta: Some(EffectMeta::Multiplier(150)), tick: None}], + meta: Some(EffectMeta::Multiplier(150)), tick: None}], Skill::AmplifyPlus => vec![ConstructEffect {effect: Effect::Amplify, duration: 3, - meta: Some(EffectMeta::Multiplier(175)), tick: None}], + meta: Some(EffectMeta::Multiplier(175)), tick: None}], Skill::AmplifyPlusPlus => vec![ConstructEffect {effect: Effect::Amplify, duration: 4, - meta: Some(EffectMeta::Multiplier(200)), tick: None}], + meta: Some(EffectMeta::Multiplier(200)), tick: None}], Skill::Banish => vec![ConstructEffect {effect: Effect::Banish, duration: 1,meta: None, tick: None}], Skill::BanishPlus => vec![ConstructEffect {effect: Effect::Banish, duration: 2,meta: None, tick: None}], Skill::BanishPlusPlus => vec![ConstructEffect {effect: Effect::Banish, duration: 3,meta: None, tick: None}], Skill::Block => vec![ConstructEffect {effect: Effect::Block, duration: 1, - meta: Some(EffectMeta::Multiplier(50)), tick: None}], + meta: Some(EffectMeta::Multiplier(50)), tick: None}], Skill::Buff => vec![ConstructEffect {effect: Effect::Buff, duration: 2, - meta: Some(EffectMeta::Multiplier(125)), tick: None }], + meta: Some(EffectMeta::Multiplier(125)), tick: None }], Skill::Electrify => vec![ConstructEffect {effect: Effect::Electric, duration: 1, - meta: Some(EffectMeta::Skill(Skill::Electrocute)), tick: None}], + meta: Some(EffectMeta::Skill(Skill::Electrocute)), tick: None}], Skill::ElectrifyPlus => vec![ConstructEffect {effect: Effect::Electric, duration: 1, - meta: Some(EffectMeta::Skill(Skill::ElectrocutePlus)), tick: None}], + meta: Some(EffectMeta::Skill(Skill::ElectrocutePlus)), tick: None}], Skill::ElectrifyPlusPlus => vec![ConstructEffect {effect: Effect::Electric, duration: 1, - meta: Some(EffectMeta::Skill(Skill::ElectrocutePlusPlus)), tick: None}], + meta: Some(EffectMeta::Skill(Skill::ElectrocutePlusPlus)), tick: None}], Skill::Electrocute => vec![ConstructEffect {effect: Effect::Electrocute, duration: 2, - meta: Some(EffectMeta::Skill(Skill::ElectrocuteTick)), tick: None}], + meta: Some(EffectMeta::Skill(Skill::ElectrocuteTick)), tick: None}], Skill::ElectrocutePlus => vec![ConstructEffect {effect: Effect::Electrocute, duration: 3, - meta: Some(EffectMeta::Skill(Skill::ElectrocuteTickPlus)), tick: None}], + meta: Some(EffectMeta::Skill(Skill::ElectrocuteTickPlus)), tick: None}], Skill::ElectrocutePlusPlus => vec![ConstructEffect {effect: Effect::Electrocute, duration: 4, - meta: Some(EffectMeta::Skill(Skill::ElectrocuteTickPlusPlus)), tick: None}], + meta: Some(EffectMeta::Skill(Skill::ElectrocuteTickPlusPlus)), tick: None}], Skill::Sustain => vec![ConstructEffect {effect: Effect::Sustain, duration: 1, meta: None, tick: None }], Skill::SustainPlus => vec![ConstructEffect {effect: Effect::Sustain, duration: 1, meta: None, tick: None }], Skill::SustainPlusPlus => vec![ConstructEffect {effect: Effect::Sustain, duration: 1, meta: None, tick: None }], - Skill::Curse => vec![ConstructEffect {effect: Effect::Curse, duration: 2, - meta: Some(EffectMeta::Multiplier(150)), tick: None}], - Skill::CursePlus => vec![ConstructEffect {effect: Effect::Curse, duration: 2, - meta: Some(EffectMeta::Multiplier(200)), tick: None}], - Skill::CursePlusPlus => vec![ConstructEffect {effect: Effect::Curse, duration: 3, - meta: Some(EffectMeta::Multiplier(250)), tick: None}], + Skill::Curse => vec![ConstructEffect {effect: Effect::Curse, duration: 2, + meta: Some(EffectMeta::Multiplier(150)), tick: None}], + Skill::CursePlus => vec![ConstructEffect {effect: Effect::Curse, duration: 2, + meta: Some(EffectMeta::Multiplier(200)), tick: None}], + Skill::CursePlusPlus => vec![ConstructEffect {effect: Effect::Curse, duration: 3, + meta: Some(EffectMeta::Multiplier(250)), tick: None}], Skill::Debuff => vec![ConstructEffect {effect: Effect::Slow, duration: 3, - meta: Some(EffectMeta::Multiplier(50)), tick: None }], + meta: Some(EffectMeta::Multiplier(50)), tick: None }], - Skill::Decay => vec![ConstructEffect {effect: Effect::Wither, duration: 3, meta: Some(EffectMeta::Multiplier(50)), tick: None }, - ConstructEffect {effect: Effect::Decay, duration: 3, + Skill::Decay => vec![ConstructEffect {effect: Effect::Wither, duration: 3, + meta: Some(EffectMeta::Multiplier(50)), tick: None }, + ConstructEffect {effect: Effect::Decay, duration: 3, meta: Some(EffectMeta::Skill(Skill::DecayTick)), tick: None}], - Skill::DecayPlus => vec![ConstructEffect {effect: Effect::Wither, duration: 3, meta: Some(EffectMeta::Multiplier(35)), tick: None }, - ConstructEffect {effect: Effect::Decay, duration: 3, + Skill::DecayPlus => vec![ConstructEffect {effect: Effect::Wither, duration: 3, + meta: Some(EffectMeta::Multiplier(35)), tick: None }, + ConstructEffect {effect: Effect::Decay, duration: 3, meta: Some(EffectMeta::Skill(Skill::DecayTickPlus)), tick: None}], - Skill::DecayPlusPlus => vec![ConstructEffect {effect: Effect::Wither, duration: 4, meta: Some(EffectMeta::Multiplier(20)), tick: None }, - ConstructEffect {effect: Effect::Decay, duration: 4, + Skill::DecayPlusPlus => vec![ConstructEffect {effect: Effect::Wither, duration: 4, + meta: Some(EffectMeta::Multiplier(20)), tick: None }, + ConstructEffect {effect: Effect::Decay, duration: 4, meta: Some(EffectMeta::Skill(Skill::DecayTickPlusPlus)), tick: None}], - Skill::Haste => vec![ConstructEffect {effect: Effect::Haste, duration: 2, - meta: Some(EffectMeta::Multiplier(150)), tick: None }], - Skill::HastePlus => vec![ConstructEffect {effect: Effect::Haste, duration: 3, - meta: Some(EffectMeta::Multiplier(175)), tick: None }], - Skill::HastePlusPlus => vec![ConstructEffect {effect: Effect::Haste, duration: 4, - meta: Some(EffectMeta::Multiplier(225)), tick: None }], + Skill::Haste => vec![ConstructEffect {effect: Effect::Haste, duration: 2, + meta: Some(EffectMeta::Multiplier(150)), tick: None }], + Skill::HastePlus => vec![ConstructEffect {effect: Effect::Haste, duration: 3, + meta: Some(EffectMeta::Multiplier(175)), tick: None }], + Skill::HastePlusPlus => vec![ConstructEffect {effect: Effect::Haste, duration: 4, + meta: Some(EffectMeta::Multiplier(225)), tick: None }], + Skill::Hex => vec![ConstructEffect {effect: Effect::Hex, duration: 2, meta: None, tick: None}], - Skill::HexPlus => vec![ConstructEffect {effect: Effect::Hex, duration: 3, meta: None, tick: None}], - Skill::HexPlusPlus => vec![ConstructEffect {effect: Effect::Hex, duration: 4, meta: None, tick: None}], + Skill::HexPlus => vec![ConstructEffect {effect: Effect::Hex, duration: 3, meta: None, tick: None}], + Skill::HexPlusPlus => vec![ConstructEffect {effect: Effect::Hex, duration: 4, meta: None, tick: None}], Skill::Absorb => vec![ConstructEffect {effect: Effect::Absorb, duration: 2, meta: Some(EffectMeta::Skill(Skill::Absorption)), tick: None}], @@ -885,87 +889,90 @@ impl Skill { Skill::AbsorbPlusPlus => vec![ConstructEffect {effect: Effect::Absorb, duration: 4, meta: Some(EffectMeta::Skill(Skill::AbsorptionPlusPlus)), tick: None}], - Skill::Absorption => vec![ConstructEffect {effect: Effect::Absorption, duration: 5, meta: None, tick: None}], - Skill::AbsorptionPlus => vec![ConstructEffect {effect: Effect::Absorption, duration: 7, meta: None, tick: None}], - Skill::AbsorptionPlusPlus => vec![ConstructEffect {effect: Effect::Absorption, duration: 9, meta: None, tick: None}], + Skill::Absorption => vec![ConstructEffect {effect: Effect::Absorption, duration: 5, meta: None, tick: None}], + Skill::AbsorptionPlus => vec![ConstructEffect {effect: Effect::Absorption, duration: 7, meta: None, tick: None}], + Skill::AbsorptionPlusPlus => vec![ConstructEffect {effect: Effect::Absorption, duration: 9, meta: None, tick: None}], - Skill::Hybrid => vec![ConstructEffect {effect: Effect::Hybrid, duration: 2, + Skill::Hybrid => vec![ConstructEffect {effect: Effect::Hybrid, duration: 2, meta: Some(EffectMeta::Multiplier(150)), tick: None }], - Skill::HybridPlus => vec![ConstructEffect {effect: Effect::Hybrid, duration: 3, + Skill::HybridPlus => vec![ConstructEffect {effect: Effect::Hybrid, duration: 3, meta: Some(EffectMeta::Multiplier(175)), tick: None }], - Skill::HybridPlusPlus => vec![ConstructEffect {effect: Effect::Hybrid, duration: 4, + Skill::HybridPlusPlus => vec![ConstructEffect {effect: Effect::Hybrid, duration: 4, meta: Some(EffectMeta::Multiplier(225)), tick: None }], - Skill::Invert => vec![ConstructEffect {effect: Effect::Invert, duration: 2, meta: None, tick: None}], - Skill::InvertPlus => vec![ConstructEffect {effect: Effect::Invert, duration: 3, meta: None, tick: None}], - Skill::InvertPlusPlus => vec![ConstructEffect {effect: Effect::Invert, duration: 4, meta: None, tick: None}], + Skill::Invert => vec![ConstructEffect {effect: Effect::Invert, duration: 2, meta: None, tick: None}], + Skill::InvertPlus => vec![ConstructEffect {effect: Effect::Invert, duration: 3, meta: None, tick: None}], + Skill::InvertPlusPlus => vec![ConstructEffect {effect: Effect::Invert, duration: 4, meta: None, tick: None}], - Skill::Counter => vec![ConstructEffect {effect: Effect::Counter, duration: 1, + Skill::Counter => vec![ConstructEffect {effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttack)), tick: None}], - Skill::CounterPlus => vec![ConstructEffect {effect: Effect::Counter, duration: 1, + Skill::CounterPlus => vec![ConstructEffect {effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttackPlus)), tick: None}], - Skill::CounterPlusPlus => vec![ConstructEffect {effect: Effect::Counter, duration: 1, + Skill::CounterPlusPlus => vec![ConstructEffect {effect: Effect::Counter, duration: 1, meta: Some(EffectMeta::Skill(Skill::CounterAttackPlusPlus)), tick: None}], Skill::Reflect => vec![ConstructEffect {effect: Effect::Reflect, duration: 1, meta: None, tick: None }], Skill::ReflectPlus => vec![ConstructEffect {effect: Effect::Reflect, duration: 1, meta: None, tick: None }], Skill::ReflectPlusPlus => vec![ConstructEffect {effect: Effect::Reflect, duration: 1, meta: None, tick: None }], - Skill::Break => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}, - ConstructEffect {effect: Effect::Vulnerable, duration: 3, meta: Some(EffectMeta::Multiplier(150)), tick: None}], - Skill::BreakPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}, - ConstructEffect {effect: Effect::Vulnerable, duration: 4, meta: Some(EffectMeta::Multiplier(200)), tick: None}], - Skill::BreakPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}, - ConstructEffect {effect: Effect::Vulnerable, duration: 4, meta: Some(EffectMeta::Multiplier(250)), tick: None}], + Skill::Break => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}, + ConstructEffect {effect: Effect::Vulnerable, duration: 3, + meta: Some(EffectMeta::Multiplier(150)), tick: None}], + Skill::BreakPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}, + ConstructEffect {effect: Effect::Vulnerable, duration: 4, + meta: Some(EffectMeta::Multiplier(200)), tick: None}], + Skill::BreakPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}, + ConstructEffect {effect: Effect::Vulnerable, duration: 4, + meta: Some(EffectMeta::Multiplier(250)), tick: None}], - Skill::Ruin => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}], - Skill::RuinPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}], - Skill::RuinPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}], + Skill::Ruin => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}], + Skill::RuinPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}], + Skill::RuinPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}], - Skill::Purge => vec![ConstructEffect {effect: Effect::Purge, duration: 1, meta: None, tick: None}], - Skill::PurgePlus => vec![ConstructEffect {effect: Effect::Purge, duration: 2, meta: None, tick: None}], - Skill::PurgePlusPlus => vec![ConstructEffect {effect: Effect::Purge, duration: 3, meta: None, tick: None}], + Skill::Purge => vec![ConstructEffect {effect: Effect::Purge, duration: 2, meta: None, tick: None}], + Skill::PurgePlus => vec![ConstructEffect {effect: Effect::Purge, duration: 3, meta: None, tick: None}], + Skill::PurgePlusPlus => vec![ConstructEffect {effect: Effect::Purge, duration: 4, meta: None, tick: None}], - Skill::Link => vec![ConstructEffect {effect: Effect::Stun, duration: 3, meta: None, tick: None}], - Skill::LinkPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}], - Skill::LinkPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}], + Skill::Link => vec![ConstructEffect {effect: Effect::Stun, duration: 3, meta: None, tick: None}], + Skill::LinkPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}], + Skill::LinkPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}], - Skill::Silence => vec![ConstructEffect {effect: Effect::Silence, duration: 2, meta: None, tick: None}], - Skill::SilencePlus => vec![ConstructEffect {effect: Effect::Silence, duration: 3, meta: None, tick: None}], - Skill::SilencePlusPlus => vec![ConstructEffect {effect: Effect::Silence, duration: 4, meta: None, tick: None}], + Skill::Silence => vec![ConstructEffect {effect: Effect::Silence, duration: 2, meta: None, tick: None}], + Skill::SilencePlus => vec![ConstructEffect {effect: Effect::Silence, duration: 3, meta: None, tick: None}], + Skill::SilencePlusPlus => vec![ConstructEffect {effect: Effect::Silence, duration: 4, meta: None, tick: None}], - Skill::Siphon => vec![ConstructEffect {effect: Effect::Siphon, duration: 2, - meta: Some(EffectMeta::Skill(Skill::SiphonTick)), tick: None}], - Skill::SiphonPlus => vec![ConstructEffect {effect: Effect::Siphon, duration: 3, - meta: Some(EffectMeta::Skill(Skill::SiphonTickPlus)), tick: None}], - Skill::SiphonPlusPlus => vec![ConstructEffect {effect: Effect::Siphon, duration: 4, - meta: Some(EffectMeta::Skill(Skill::SiphonTickPlusPlus)), tick: None}], + Skill::Siphon => vec![ConstructEffect {effect: Effect::Siphon, duration: 2, + meta: Some(EffectMeta::Skill(Skill::SiphonTick)), tick: None}], + Skill::SiphonPlus => vec![ConstructEffect {effect: Effect::Siphon, duration: 3, + meta: Some(EffectMeta::Skill(Skill::SiphonTickPlus)), tick: None}], + Skill::SiphonPlusPlus => vec![ConstructEffect {effect: Effect::Siphon, duration: 4, + meta: Some(EffectMeta::Skill(Skill::SiphonTickPlusPlus)), tick: None}], - Skill::Sleep => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}], - Skill::SleepPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 3, meta: None, tick: None}], - Skill::SleepPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 4, meta: None, tick: None}], + Skill::Sleep => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}], + Skill::SleepPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 3, meta: None, tick: None}], + Skill::SleepPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 4, meta: None, tick: None}], - Skill::Restrict => vec![ConstructEffect {effect: Effect::Restrict, duration: 2, meta: None, tick: None}], - Skill::RestrictPlus => vec![ConstructEffect {effect: Effect::Restrict, duration: 3, meta: None, tick: None}], - Skill::RestrictPlusPlus => vec![ConstructEffect {effect: Effect::Restrict, duration: 4, meta: None, tick: None}], + Skill::Restrict => vec![ConstructEffect {effect: Effect::Restrict, duration: 2, meta: None, tick: None}], + Skill::RestrictPlus => vec![ConstructEffect {effect: Effect::Restrict, duration: 3, meta: None, tick: None}], + Skill::RestrictPlusPlus => vec![ConstructEffect {effect: Effect::Restrict, duration: 4, meta: None, tick: None}], - Skill::Bash => vec![ConstructEffect {effect: Effect::Stun, duration: 2, - meta: Some(EffectMeta::Skill(Skill::Bash)), tick: None}], - Skill::BashPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, - meta: Some(EffectMeta::Skill(Skill::BashPlus)), tick: None}], - Skill::BashPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, - meta: Some(EffectMeta::Skill(Skill::BashPlusPlus)), tick: None}], - Skill::Stun => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}], + Skill::Bash => vec![ConstructEffect {effect: Effect::Stun, duration: 2, + meta: Some(EffectMeta::Skill(Skill::Bash)), tick: None}], + Skill::BashPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, + meta: Some(EffectMeta::Skill(Skill::BashPlus)), tick: None}], + Skill::BashPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, + meta: Some(EffectMeta::Skill(Skill::BashPlusPlus)), tick: None}], + Skill::Stun => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}], - Skill::Intercept => vec![ConstructEffect {effect: Effect::Intercept, duration: 2, meta: None, tick: None}], - Skill::InterceptPlus => vec![ConstructEffect {effect: Effect::Intercept, duration: 3, meta: None, tick: None}], - Skill::InterceptPlusPlus => vec![ConstructEffect {effect: Effect::Intercept, duration: 4, meta: None, tick: None}], + Skill::Intercept => vec![ConstructEffect {effect: Effect::Intercept, duration: 2, meta: None, tick: None}], + Skill::InterceptPlus => vec![ConstructEffect {effect: Effect::Intercept, duration: 3, meta: None, tick: None}], + Skill::InterceptPlusPlus => vec![ConstructEffect {effect: Effect::Intercept, duration: 4, meta: None, tick: None}], - Skill::Triage => vec![ConstructEffect {effect: Effect::Triage, duration: 2, - meta: Some(EffectMeta::Skill(Skill::TriageTick)), tick: None}], + Skill::Triage => vec![ConstructEffect {effect: Effect::Triage, duration: 2, + meta: Some(EffectMeta::Skill(Skill::TriageTick)), tick: None}], Skill::TriagePlus => vec![ConstructEffect {effect: Effect::Triage, duration: 3, meta: Some(EffectMeta::Skill(Skill::TriageTickPlus)), tick: None}], - Skill::TriagePlusPlus => vec![ConstructEffect {effect: Effect::Triage, duration: 4, + Skill::TriagePlusPlus => vec![ConstructEffect {effect: Effect::Triage, duration: 4, meta: Some(EffectMeta::Skill(Skill::TriageTickPlusPlus)), tick: None}], _ => { panic!("{:?} no skill effect", self); @@ -1717,7 +1724,9 @@ fn purge(source: &mut Construct, target: &mut Construct, mut results: Resolution .event(Event::Removal { effect: ce.effect, construct_effects: target.effects.clone() })); } - let mut turns = 1; + results.push(Resolution::new(source, target).event(target.add_effect(skill, effect)).stages(EventStages::PostOnly)); + + /*let mut turns = 1; for cs in target.skills.iter_mut() { if Effect::Purge.disables_skill(cs.skill) { turns += 1; @@ -1727,8 +1736,7 @@ fn purge(source: &mut Construct, target: &mut Construct, mut results: Resolution if turns > 1 { let mut effect = skill.effect()[0]; effect.duration = effect.duration * turns; - results.push(Resolution::new(source, target).event(target.add_effect(skill, effect)).stages(EventStages::PostOnly)); - } + }*/ return results; } From b52b6a5334fb8cf0631261a355a1a044a6f3d0fd Mon Sep 17 00:00:00 2001 From: Mashy Date: Mon, 16 Sep 2019 17:04:41 +1000 Subject: [PATCH 10/24] delete hex (wasn't actually in game) --- server/src/effect.rs | 6 ------ server/src/item.rs | 15 --------------- 2 files changed, 21 deletions(-) diff --git a/server/src/effect.rs b/server/src/effect.rs index b9489a2a..5b3d6bba 100644 --- a/server/src/effect.rs +++ b/server/src/effect.rs @@ -13,7 +13,6 @@ pub enum Effect { Sustain, Curse, Haste, - Hex, Hybrid, Invert, Counter, @@ -73,9 +72,6 @@ impl Effect { Effect::Banish => true, Effect::Sustain => [ Skill::Stun, - Skill::Hex, - Skill::HexPlus, - Skill::HexPlusPlus, Skill::Silence, Skill::SilencePlus, Skill::SilencePlusPlus, @@ -97,7 +93,6 @@ impl Effect { match self { Effect::Stun => true, - Effect::Hex => true, Effect::Banish => true, Effect::Silence => skill.colours().contains(&Colour::Blue), Effect::Restrict => skill.colours().contains(&Colour::Red), @@ -168,7 +163,6 @@ impl Effect { Effect::Intercept => Some(Colour::Green), // magic - Effect::Hex => Some(Colour::Blue), Effect::Curse => Some(Colour::Blue), Effect::Banish => None, // Effect::Banish => rng.gen_bool(0.5), diff --git a/server/src/item.rs b/server/src/item.rs index 3d6e2d2f..928a2850 100644 --- a/server/src/item.rs +++ b/server/src/item.rs @@ -143,12 +143,6 @@ pub enum Item { #[serde(rename = "Decay++")] DecayPlusPlus, - Hex, - #[serde(rename = "Hex+")] - HexPlus, - #[serde(rename = "Hex++")] - HexPlusPlus, - Haste, #[serde(rename = "Haste+")] HastePlus, @@ -726,12 +720,6 @@ impl Item { Item::HealPlus | Item::HealPlusPlus => format!("Heals target for {:?}% GreenPower.", self.into_skill().unwrap().multiplier()), - Item::Hex| - Item::HexPlus | - Item::HexPlusPlus => format!("Blue based skill that applies Hex for {:?}T. \ - Hexed targets cannot cast any skills.", - self.into_skill().unwrap().effect()[0].get_duration()), - Item::Hybrid| Item::HybridPlus | Item::HybridPlusPlus => format!( @@ -1066,9 +1054,6 @@ impl From for Item { Skill::Heal => Item::Heal, Skill::HealPlus => Item::HealPlus, Skill::HealPlusPlus => Item::HealPlusPlus, - Skill::Hex => Item::Hex, - Skill::HexPlus => Item::HexPlus, - Skill::HexPlusPlus => Item::HexPlusPlus, Skill::Hybrid => Item::Hybrid, Skill::HybridPlus => Item::HybridPlus, Skill::HybridPlusPlus => Item::HybridPlusPlus, From 16a0a18905b583890bf2ce2d296f8eefb895255c Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 18:31:45 +1000 Subject: [PATCH 11/24] new game styles --- client/assets/styles/game.less | 253 +++++++++------------ client/src/components/skill.btn.jsx | 2 +- client/src/components/targeting.arrows.jsx | 10 +- 3 files changed, 114 insertions(+), 151 deletions(-) diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index 7722f5fc..df25689f 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -28,30 +28,34 @@ .opponent { grid-area: opponent; -} -.opponent .combat-text { - top: 75%; -} + .combat-text { + top: 75%; + } -.opponent .combat-anim { - top: 25%; -} + .combat-anim { + top: 25%; + } -.opponent .game-construct { - align-items: flex-start; - grid-template-rows: min-content min-content min-content minmax(min-content, 2fr); - grid-template-columns: 1fr; - grid-template-areas: - "stats " - "name " - "effects " - "avatar "; -} + .game-construct { + align-items: flex-start; + grid-template-rows: min-content min-content 1fr; + grid-template-columns: 1fr 2fr; + grid-template-areas: + "effects stats" + "effects name" + "effects avatar"; -.opponent .game-construct .name { - margin-bottom: 0; - margin-top: 0.25em; + .effects { + align-self: flex-start; + text-align: right; + } + } + + .game-construct .name { + margin-bottom: 0; + margin-top: 0.25em; + } } .game-construct { @@ -65,19 +69,98 @@ justify-items: center; - grid-template-rows: min-content minmax(min-content, 1fr) min-content min-content min-content; - grid-template-columns: 1fr; + grid-template-rows: minmax(min-content, 1fr) min-content min-content; + grid-template-columns: 1fr 3fr; grid-template-areas: - "skills " - "avatar " - "effects " - "name " - "stats "; + "skills avatar" + "effects name" + "effects stats"; transition-property: translate, opacity; transition-duration: 0.25s; transition-delay: 0; transition-timing-function: ease; + + .effects { + align-self: flex-end; + } + + .stats { + align-self: flex-end; + } + + .name { + width: 100%; + margin-bottom: 0.25em; + text-align: center; + grid-area: name; + } + + .skills { + grid-area: skills; + width: 100%; + + button { + width: 100%; + height: 2em; + height: 25%; + } + } + + .effects { + grid-area: effects; + white-space: nowrap; + width: 100%; + text-align: center; + font-size: 1.5em; + } + + .ko { + animation: none; + opacity: 0.20; + } + + .ko button:hover { + color: #333; + } + + .unfocus { + opacity: 0.35; + } + + .unfocus.ko { + opacity: 0.20; + } + + .stats { + grid-area: stats; + display: flex; + justify-content: center; + text-align: center; + } + + .stats div { + padding: 0 0.5em; + display: flex; + flex-flow: column; + white-space: nowrap; + text-align: center; + } + + .stats .value { + display: none; + } + + figcaption { + white-space: nowrap; + font-size: 100%; + } +} + +@media (max-width: 1500px) { + .game-construct figure { + padding: 0 0.25em; + } } #targeting { @@ -101,116 +184,6 @@ max-height: 10em; } } -/* -.resolving #targeting { - opacity: 0; -} -*/ -.game-construct .name { - width: 100%; - margin-bottom: 0.25em; - text-align: center; - grid-area: name; -} - -.game-construct .stats { - grid-area: stats; - display: flex; - justify-content: center; - text-align: center; -} - -.game-construct .stats div { - padding: 0 0.5em; - display: flex; - flex-flow: column; - white-space: nowrap; - text-align: center; -} - -.game-construct .stats .value { - display: none; -} - -.game-construct figcaption { - white-space: nowrap; - font-size: 100%; -} - -@media (max-width: 1500px) { - .game-construct figure { - padding: 0 0.25em; - } -} - -.game-construct .skills { - grid-area: skills; - display: flex; - flex-flow: column-reverse; - justify-self: center; - width: 100%; -} - -.game-construct .skills button { - width: 100%; -} - -.game-construct .effects { - grid-area: effects; - white-space: nowrap; - width: 100%; - text-align: center; - font-size: 1.5em; -} - -.game-btn { - flex: 0 0 25%; -} - -.game-btn:first-child { - margin-right: 0.5em; -} - -.game-construct button { - color: #888; - flex: 1 1 100%; - padding: 0; - margin: 0 0.5em; - border-width: 0px; -} - -.game-construct button.active { - color: whitesmoke; -} - -.game-construct button[disabled], .game-construct button[disabled]:hover { - color: #333333; - text-decoration: line-through -} - -.game-construct button:hover { - color: whitesmoke; -} - -.game-construct.ko { - animation: none; - opacity: 0.20; -/* filter: grayscale(100%); -*/} - -.game-construct.ko button:hover { - color: #333; -} - -.game-construct.unfocus { - opacity: 0.35; -/* filter: blur(5px); -*/} - -.game-construct.unfocus.ko { - opacity: 0.20; -/* filter: blur(5px) grayscale(100%); -*/} .combat-text { font-size: 2em; @@ -238,10 +211,6 @@ width: 100%; } -.game-construct.active-skill { -/* filter: drop-shadow(0 0 0.2em silver); -*/} - .game-construct.red-damage { color: #a52a2a; /*ensure construct doesn't get opacity lowered because of being KO before the KO animation*/ @@ -326,7 +295,7 @@ object-fit: contain; background-size: contain; background-repeat: no-repeat; - background-position: center; + background-position: top; pointer-events: none; } diff --git a/client/src/components/skill.btn.jsx b/client/src/components/skill.btn.jsx index 3fa23031..d1f39939 100644 --- a/client/src/components/skill.btn.jsx +++ b/client/src/components/skill.btn.jsx @@ -44,7 +44,7 @@ function Skill(props) { return ( ); } diff --git a/client/src/components/targeting.arrows.jsx b/client/src/components/targeting.arrows.jsx index ed822459..6ea195f1 100644 --- a/client/src/components/targeting.arrows.jsx +++ b/client/src/components/targeting.arrows.jsx @@ -52,17 +52,11 @@ class TargetSvg extends Component { ? playerTeam.constructs.findIndex(c => c.id === cast.target_construct_id) : otherTeam.constructs.findIndex(c => c.id === cast.target_construct_id); - const pathOffset = [ - [0, -1, -2], - [1, 0, -1], - [2, 1, 0], - ][source][target]; - const sourceY = height; - const sourceX = (source * width / 3) + width / 6; + const sourceX = (source * width / 3) + width / 24; const targetX = (target * width / 3) + width / 6 + (defensive ? width / 64 : 0) - + (pathOffset * width / 32); + + (source * width / 18); const targetY = defensive ? height : 0; const bendStart = height * (0.7 - 0.1 * source); const bendEnd = height * 0.20; From 0533cf2ca2129dec23c72ede6c1125e7fce0c77e Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 18:45:17 +1000 Subject: [PATCH 12/24] anim alignment --- client/assets/styles/game.less | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index df25689f..8e7ca777 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -31,10 +31,12 @@ .combat-text { top: 75%; + left: 50%; } .combat-anim { top: 25%; + left: 50%; } .game-construct { @@ -48,7 +50,6 @@ .effects { align-self: flex-start; - text-align: right; } } @@ -70,7 +71,7 @@ justify-items: center; grid-template-rows: minmax(min-content, 1fr) min-content min-content; - grid-template-columns: 1fr 3fr; + grid-template-columns: 1fr 4fr; grid-template-areas: "skills avatar" "effects name" @@ -83,6 +84,7 @@ .effects { align-self: flex-end; + text-align: right; } .stats { From 7b51bc7ec8e0df36eb89d896bda6bc916efb78c4 Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 19:33:21 +1000 Subject: [PATCH 13/24] praise it --- client/assets/styles/game.less | 103 +++++++++++------------ client/src/components/construct.jsx | 17 ++-- client/src/components/game.construct.jsx | 17 ++-- 3 files changed, 66 insertions(+), 71 deletions(-) diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index 8e7ca777..74f4309f 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -29,24 +29,20 @@ .opponent { grid-area: opponent; - .combat-text { - top: 75%; - left: 50%; - } - - .combat-anim { - top: 25%; - left: 50%; - } - .game-construct { align-items: flex-start; - grid-template-rows: min-content min-content 1fr; grid-template-columns: 1fr 2fr; - grid-template-areas: - "effects stats" - "effects name" - "effects avatar"; + grid-template-rows: 1fr; + + .right { + height: 100%; + display: grid; + grid-template-rows: min-content min-content 1fr; + grid-template-areas: + "stats" + "name" + "avatar"; + } .effects { align-self: flex-start; @@ -70,12 +66,24 @@ justify-items: center; - grid-template-rows: minmax(min-content, 1fr) min-content min-content; - grid-template-columns: 1fr 4fr; - grid-template-areas: - "skills avatar" - "effects name" - "effects stats"; + grid-template-columns: 1fr 3fr; + + .left { + display: grid; + grid-template-rows: 1fr 1fr; + grid-template-areas: + "skills " + "effects" + } + + .right { + display: grid; + grid-template-rows: minmax(min-content, 1fr) min-content min-content; + grid-template-areas: + "avatar" + "name" + "stats"; + } transition-property: translate, opacity; transition-duration: 0.25s; @@ -117,23 +125,6 @@ font-size: 1.5em; } - .ko { - animation: none; - opacity: 0.20; - } - - .ko button:hover { - color: #333; - } - - .unfocus { - opacity: 0.35; - } - - .unfocus.ko { - opacity: 0.20; - } - .stats { grid-area: stats; display: flex; @@ -157,6 +148,23 @@ white-space: nowrap; font-size: 100%; } + + &.ko { + animation: none; + opacity: 0.20; + } + + &.ko button:hover { + color: #333; + } + + &.unfocus { + opacity: 0.35; + } + + &.unfocus.ko { + opacity: 0.20; + } } @media (max-width: 1500px) { @@ -187,29 +195,12 @@ } } -.combat-text { - font-size: 2em; - font-family: 'Jura'; - position: absolute; - top: 5%; -} - -.combat-text svg { - height: 7em; - max-width: 100%; -} - .combat-anim { - font-size: 2em; - font-family: 'Jura'; - position: absolute; - object-fit: contain; - top: 15%; max-width: 100%; } .combat-anim svg { - height: 7em; + height: 100%; width: 100%; } diff --git a/client/src/components/construct.jsx b/client/src/components/construct.jsx index 964da49c..c502be9e 100644 --- a/client/src/components/construct.jsx +++ b/client/src/components/construct.jsx @@ -8,6 +8,7 @@ const banish = require('./anims/banish'); const idleAnimation = require('./anims/idle'); const invert = require('./anims/invert'); const sourceCast = require('./anims/source.cast'); +const { ConstructAnimation } = require('./animations'); const addState = connect( function receiveState(state) { @@ -27,12 +28,14 @@ class ConstructAvatar extends Component { } render() { + const { construct } = this.props; return (
+ id={construct.id} + style={{ 'background-image': `url(/imgs/${construct.img}.svg)` }}> + +
); } @@ -94,13 +97,13 @@ const addStateText = connect( function constructText(props) { const { construct, animText } = props; - if (!construct || !animText) return false; + if (!construct) return false; - const text = animText.constructId === construct.id + const text = animText && animText.constructId === construct.id ? animText.text - : null; + : construct.name; - return
{text}
; + return

{text}

; } module.exports = { diff --git a/client/src/components/game.construct.jsx b/client/src/components/game.construct.jsx index 8976c78e..01d81cdf 100644 --- a/client/src/components/game.construct.jsx +++ b/client/src/components/game.construct.jsx @@ -5,7 +5,6 @@ const range = require('lodash/range'); const { STATS } = require('../utils'); const { ConstructAvatar, ConstructText } = require('./construct'); -const { ConstructAnimation } = require('./animations'); const shapes = require('./shapes'); const SkillBtn = require('./skill.btn'); @@ -106,13 +105,15 @@ class GameConstruct extends Component { onClick={() => selectSkillTarget(construct.id)} style={ activeSkill ? { cursor: 'pointer' } : {}} class={`game-construct ${ko} ${classes}`} > -

{construct.name}

- {crypSkills} -
{stats}
- - - -
{effects}
+
+ {crypSkills} +
{effects}
+
+
+
{stats}
+ + +
); } From 48a3f75f0c5b91a15ca2dc92c379817c1f9c075b Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 19:50:48 +1000 Subject: [PATCH 14/24] width --- client/assets/styles/game.less | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index 74f4309f..4e818dc0 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -73,7 +73,8 @@ grid-template-rows: 1fr 1fr; grid-template-areas: "skills " - "effects" + "effects"; + width: 100%; } .right { @@ -83,6 +84,7 @@ "avatar" "name" "stats"; + width: 100%; } transition-property: translate, opacity; From 2876b24cb3542deca443f0f61dcc72695785b3db Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 20:02:03 +1000 Subject: [PATCH 15/24] compiling" --- client/assets/styles/game.less | 7 ++- client/src/animations.socket.jsx | 1 + server/src/game.rs | 80 ++++++++++++++++---------------- server/src/img.rs | 12 ++--- server/src/skill.rs | 46 +++++------------- 5 files changed, 61 insertions(+), 85 deletions(-) diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index 4e818dc0..b17b2d80 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -74,7 +74,6 @@ grid-template-areas: "skills " "effects"; - width: 100%; } .right { @@ -198,12 +197,12 @@ } .combat-anim { - max-width: 100%; + display: flex; + flex-flow: column; } .combat-anim svg { - height: 100%; - width: 100%; + flex: 1 } .game-construct.red-damage { diff --git a/client/src/animations.socket.jsx b/client/src/animations.socket.jsx index edd822c6..16decdef 100644 --- a/client/src/animations.socket.jsx +++ b/client/src/animations.socket.jsx @@ -53,6 +53,7 @@ function createSocket(store) { timeout - TIMES.POST_SKILL_DURATION_MS ); } + return false; return setTimeout(() => { store.dispatch(actions.setAnimSource(null)); store.dispatch(actions.setAnimTarget(null)); diff --git a/server/src/game.rs b/server/src/game.rs index 97354d86..ed2ab7e6 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -1221,55 +1221,55 @@ mod tests { assert!(game.construct_by_id(y_construct.id).unwrap().affected(Effect::Electrocute)); } - #[test] - fn link_test() { - let mut game = create_test_game(); + // #[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_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(); - game.construct_by_id(x_construct.id).unwrap().learn_mut(Skill::Link); + // 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(); - } + // 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)); + // // 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: _, event, stages: _ } = game.resolved.pop().unwrap(); - match event { - Event::Effect { effect, skill: _, duration: _, construct_effects: _ } => assert_eq!(effect, Effect::Link), - _ => panic!("not siphon"), - }; + // let Resolution { source: _, target: _, event, stages: _ } = game.resolved.pop().unwrap(); + // match event { + // Event::Effect { effect, skill: _, duration: _, construct_effects: _ } => assert_eq!(effect, Effect::Link), + // _ => panic!("not siphon"), + // }; - let Resolution { source: _, target: _, event, stages: _ } = game.resolved.pop().unwrap(); - match event { - Event::Recharge { red: _, blue: _, skill: _ } => (), - _ => panic!("link result was not recharge"), - } + // let Resolution { source: _, target: _, event, stages: _ } = game.resolved.pop().unwrap(); + // match event { + // Event::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(); + // // 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, event, stages: _ } = game.resolved.pop().unwrap(); - assert_eq!(target.id, y_construct.id); - match event { - Event::Damage { amount, skill: _, mitigation: _, colour: _} => - assert_eq!(amount, x_construct.red_power().pct(Skill::Attack.multiplier()) >> 1), - _ => panic!("not damage link"), - }; - } + // let Resolution { source: _, target, event, stages: _ } = game.resolved.pop().unwrap(); + // assert_eq!(target.id, y_construct.id); + // match event { + // Event::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() { diff --git a/server/src/img.rs b/server/src/img.rs index 3fc746b3..d4c92bad 100644 --- a/server/src/img.rs +++ b/server/src/img.rs @@ -273,12 +273,12 @@ mod tests { // hieroglyph(); // } - #[test] - fn shapes_img_test() { - for i in 0..100 { - shapes_write(Uuid::new_v4()).unwrap(); - } - } + // #[test] + // fn shapes_img_test() { + // for i in 0..100 { + // shapes_write(Uuid::new_v4()).unwrap(); + // } + // } } diff --git a/server/src/skill.rs b/server/src/skill.rs index da57c70f..d0972ca9 100644 --- a/server/src/skill.rs +++ b/server/src/skill.rs @@ -177,10 +177,6 @@ pub fn resolve(skill: Skill, source: &mut Construct, target: &mut Construct, mut Skill::HealPlus | Skill::HealPlusPlus => heal(source, target, resolutions, skill), - Skill::Hex| - Skill::HexPlus | - Skill::HexPlusPlus => hex(source, target, resolutions, skill), - Skill::Absorb| Skill::AbsorbPlus | Skill::AbsorbPlusPlus => absorb(source, target, resolutions, skill), @@ -552,12 +548,6 @@ pub enum Skill { #[serde(rename = "Decay++")] DecayPlusPlus, - Hex, - #[serde(rename = "Hex+")] - HexPlus, - #[serde(rename = "Hex++")] - HexPlusPlus, - Haste, #[serde(rename = "Haste+")] HastePlus, @@ -858,15 +848,15 @@ impl Skill { Skill::Debuff => vec![ConstructEffect {effect: Effect::Slow, duration: 3, meta: Some(EffectMeta::Multiplier(50)), tick: None }], - Skill::Decay => vec![ConstructEffect {effect: Effect::Wither, duration: 3, + Skill::Decay => vec![ConstructEffect {effect: Effect::Wither, duration: 3, meta: Some(EffectMeta::Multiplier(50)), tick: None }, - ConstructEffect {effect: Effect::Decay, duration: 3, + ConstructEffect {effect: Effect::Decay, duration: 3, meta: Some(EffectMeta::Skill(Skill::DecayTick)), tick: None}], - Skill::DecayPlus => vec![ConstructEffect {effect: Effect::Wither, duration: 3, + Skill::DecayPlus => vec![ConstructEffect {effect: Effect::Wither, duration: 3, meta: Some(EffectMeta::Multiplier(35)), tick: None }, - ConstructEffect {effect: Effect::Decay, duration: 3, + ConstructEffect {effect: Effect::Decay, duration: 3, meta: Some(EffectMeta::Skill(Skill::DecayTickPlus)), tick: None}], - Skill::DecayPlusPlus => vec![ConstructEffect {effect: Effect::Wither, duration: 4, + Skill::DecayPlusPlus => vec![ConstructEffect {effect: Effect::Wither, duration: 4, meta: Some(EffectMeta::Multiplier(20)), tick: None }, ConstructEffect {effect: Effect::Decay, duration: 4, meta: Some(EffectMeta::Skill(Skill::DecayTickPlusPlus)), tick: None}], @@ -878,10 +868,6 @@ impl Skill { Skill::HastePlusPlus => vec![ConstructEffect {effect: Effect::Haste, duration: 4, meta: Some(EffectMeta::Multiplier(225)), tick: None }], - Skill::Hex => vec![ConstructEffect {effect: Effect::Hex, duration: 2, meta: None, tick: None}], - Skill::HexPlus => vec![ConstructEffect {effect: Effect::Hex, duration: 3, meta: None, tick: None}], - Skill::HexPlusPlus => vec![ConstructEffect {effect: Effect::Hex, duration: 4, meta: None, tick: None}], - Skill::Absorb => vec![ConstructEffect {effect: Effect::Absorb, duration: 2, meta: Some(EffectMeta::Skill(Skill::Absorption)), tick: None}], Skill::AbsorbPlus => vec![ConstructEffect {effect: Effect::Absorb, duration: 3, @@ -916,13 +902,13 @@ impl Skill { Skill::ReflectPlusPlus => vec![ConstructEffect {effect: Effect::Reflect, duration: 1, meta: None, tick: None }], Skill::Break => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}, - ConstructEffect {effect: Effect::Vulnerable, duration: 3, + ConstructEffect {effect: Effect::Vulnerable, duration: 3, meta: Some(EffectMeta::Multiplier(150)), tick: None}], Skill::BreakPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}, - ConstructEffect {effect: Effect::Vulnerable, duration: 4, + ConstructEffect {effect: Effect::Vulnerable, duration: 4, meta: Some(EffectMeta::Multiplier(200)), tick: None}], Skill::BreakPlusPlus => vec![ConstructEffect {effect: Effect::Stun, duration: 2, meta: None, tick: None}, - ConstructEffect {effect: Effect::Vulnerable, duration: 4, + ConstructEffect {effect: Effect::Vulnerable, duration: 4, meta: Some(EffectMeta::Multiplier(250)), tick: None}], Skill::Ruin => vec![ConstructEffect {effect: Effect::Stun, duration: 1, meta: None, tick: None}], @@ -1064,10 +1050,6 @@ impl Skill { Skill::BanishPlus => Some(1), Skill::BanishPlusPlus => Some(1), - Skill::Hex=> Some(1), - Skill::HexPlus => Some(2), - Skill::HexPlusPlus => Some(2), - Skill::Haste=> Some(2), Skill::HastePlus => Some(2), Skill::HastePlusPlus => Some(2), @@ -1585,12 +1567,6 @@ fn ruin(source: &mut Construct, target: &mut Construct, mut results: Resolutions return results;; } - -fn hex(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions { - results.push(Resolution::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); - return results;; -} - fn absorb(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions { results.push(Resolution::new(source, target).event(target.add_effect(skill, skill.effect()[0]))); return results;; @@ -1683,7 +1659,7 @@ fn link(source: &mut Construct, target: &mut Construct, mut results: Resolutions source.deal_green_damage(skill, swap) .into_iter() .for_each(|e| results.push(Resolution::new(source, source).event(e).stages(EventStages::PostOnly))); - + results.push(Resolution::new(source, source) .event(source.add_effect(skill, skill.effect()[0])).stages(EventStages::PostOnly)); @@ -1724,6 +1700,7 @@ fn purge(source: &mut Construct, target: &mut Construct, mut results: Resolution .event(Event::Removal { effect: ce.effect, construct_effects: target.effects.clone() })); } + let effect = skill.effect()[0]; results.push(Resolution::new(source, target).event(target.add_effect(skill, effect)).stages(EventStages::PostOnly)); /*let mut turns = 1; @@ -1734,7 +1711,6 @@ fn purge(source: &mut Construct, target: &mut Construct, mut results: Resolution } if turns > 1 { - let mut effect = skill.effect()[0]; effect.duration = effect.duration * turns; }*/ @@ -1845,7 +1821,7 @@ mod tests { sustain(&mut y.clone(), &mut y, vec![], Skill::Sustain); assert!(y.affected(Effect::Sustain)); - let mut results = hex(&mut x, &mut y, vec![], Skill::Hex); + let mut results = blast(&mut x, &mut y, vec![], Skill::Blast); let Resolution { source: _, target: _, event, stages: _ } = results.remove(0); match event { Event::Immunity { skill: _, immunity } => assert!(immunity.contains(&Effect::Sustain)), From 0659e121df5674cb8d44186064aeadd3833aef3c Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 20:03:24 +1000 Subject: [PATCH 16/24] anims --- client/src/animations.socket.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/animations.socket.jsx b/client/src/animations.socket.jsx index 16decdef..edd822c6 100644 --- a/client/src/animations.socket.jsx +++ b/client/src/animations.socket.jsx @@ -53,7 +53,6 @@ function createSocket(store) { timeout - TIMES.POST_SKILL_DURATION_MS ); } - return false; return setTimeout(() => { store.dispatch(actions.setAnimSource(null)); store.dispatch(actions.setAnimTarget(null)); From f9d36fce63069133398a17d32f196da8acdec4bc Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 20:49:46 +1000 Subject: [PATCH 17/24] fix all the shit i broke --- client/assets/styles/game.less | 9 ++++++++- client/src/animations.socket.jsx | 1 + client/src/components/faceoff.jsx | 7 +++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index b17b2d80..bbe14129 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -197,12 +197,19 @@ } .combat-anim { + max-width: 100%; + max-height: 100%; + height: 100%; + width: 100%; display: flex; flex-flow: column; } .combat-anim svg { - flex: 1 + flex: 1; + // chrome shit + width: 100%; + height: 100%; } .game-construct.red-damage { diff --git a/client/src/animations.socket.jsx b/client/src/animations.socket.jsx index edd822c6..16decdef 100644 --- a/client/src/animations.socket.jsx +++ b/client/src/animations.socket.jsx @@ -53,6 +53,7 @@ function createSocket(store) { timeout - TIMES.POST_SKILL_DURATION_MS ); } + return false; return setTimeout(() => { store.dispatch(actions.setAnimSource(null)); store.dispatch(actions.setAnimTarget(null)); diff --git a/client/src/components/faceoff.jsx b/client/src/components/faceoff.jsx index f7634366..68de5481 100644 --- a/client/src/components/faceoff.jsx +++ b/client/src/components/faceoff.jsx @@ -33,8 +33,11 @@ function FaceoffConstruct(args) { return (
-

{construct.name}

- +
+
+

{construct.name}

+ +
) } From 0f6912134096d998ef7f02f151e0eb4b37debe60 Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 21:32:01 +1000 Subject: [PATCH 18/24] anims return rm --- client/src/animations.socket.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/animations.socket.jsx b/client/src/animations.socket.jsx index 16decdef..edd822c6 100644 --- a/client/src/animations.socket.jsx +++ b/client/src/animations.socket.jsx @@ -53,7 +53,6 @@ function createSocket(store) { timeout - TIMES.POST_SKILL_DURATION_MS ); } - return false; return setTimeout(() => { store.dispatch(actions.setAnimSource(null)); store.dispatch(actions.setAnimTarget(null)); From c2731c1eea794c860dca5597df416c23ea190d80 Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 21:43:25 +1000 Subject: [PATCH 19/24] stop skills repainting --- client/assets/styles/game.less | 4 ++-- client/src/components/game.construct.jsx | 2 +- client/src/components/game.jsx | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index bbe14129..88620afe 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -199,7 +199,7 @@ .combat-anim { max-width: 100%; max-height: 100%; - height: 100%; + // height: 100%; width: 100%; display: flex; flex-flow: column; @@ -300,7 +300,7 @@ pointer-events: none; } -.resolving .skills button { +.animating .skills { opacity: 0; } diff --git a/client/src/components/game.construct.jsx b/client/src/components/game.construct.jsx index 01d81cdf..ea4db106 100644 --- a/client/src/components/game.construct.jsx +++ b/client/src/components/game.construct.jsx @@ -94,7 +94,7 @@ class GameConstruct extends Component { .map(j => ); let crypSkills =
 
; - if (player && !animating) crypSkills = (
{skills}
); + if (player) crypSkills = (
{skills}
); const effects = construct.effects.length ? construct.effects.map(c =>
{c.effect} - {c.duration}T
) diff --git a/client/src/components/game.jsx b/client/src/components/game.jsx index 95c34691..88cc3a1d 100644 --- a/client/src/components/game.jsx +++ b/client/src/components/game.jsx @@ -12,7 +12,7 @@ const addState = connect( ws, game, account, - resolution, + animating, activeSkill, activeConstruct, } = state; @@ -32,7 +32,7 @@ const addState = connect( return { game, account, - resolution, + animating, activeSkill, activeConstruct, selectSkillTarget, @@ -57,7 +57,7 @@ function Game(props) { const { game, account, - resolution, + animating, setActiveSkill, setActiveConstruct, } = props; @@ -87,7 +87,7 @@ function Game(props) { ); } - const gameClasses = `game ${resolution ? 'resolving': ''}`; + const gameClasses = `game ${animating ? 'animating' : ''}`; function gameClick(e) { e.stopPropagation(); From 8dc9d726aaefb3fc30031fda58dd212f88c6dcf8 Mon Sep 17 00:00:00 2001 From: ntr Date: Mon, 16 Sep 2019 21:46:54 +1000 Subject: [PATCH 20/24] remove styles that don't do anythin --- client/assets/styles/game.less | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index 88620afe..bd6adab4 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -197,9 +197,6 @@ } .combat-anim { - max-width: 100%; - max-height: 100%; - // height: 100%; width: 100%; display: flex; flex-flow: column; From 2cedbb63f4782c946487849fabad3f828e932a0c Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 17 Sep 2019 12:59:55 +1000 Subject: [PATCH 21/24] stop animations resizing constructs --- client/assets/styles/game.less | 1 + 1 file changed, 1 insertion(+) diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index bd6adab4..43e9d795 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -198,6 +198,7 @@ .combat-anim { width: 100%; + position: absolute; display: flex; flex-flow: column; } From aa3b9badef48d26abe3db3445e0c5a4ad9c9ad01 Mon Sep 17 00:00:00 2001 From: Mashy Date: Tue, 17 Sep 2019 13:04:48 +1000 Subject: [PATCH 22/24] rework counter & sustain, update logs and tests --- CHANGELOG.md | 48 ++++++++++++++++++++++++----------- WORKLOG.md | 1 + server/src/effect.rs | 5 ---- server/src/game.rs | 8 +++--- server/src/skill.rs | 59 +++++++++++++++++++++++++------------------- 5 files changed, 71 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46d96690..a817f86d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,39 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed ### Changed -## [In Progress] +## [0.1.4 2019-09-17] + +### Changed +Removed self targetting, all skills can be used on any target + +`Reflect` No cooldown, 1T duration +`Purify` No cooldown +`Recharge` No cooldown + +`Link` reworked -> + Stuns caster for 3/2/1T + If target has higher green life than caster: + Deal blue damage to target equal to difference between green life + Heal with green damage to source equal to difference between green life + +`Counter` effect no longer applies immunities + Counter no cooldown + Counter applies for 1T + Counter skill now applies block at 40% / 60% / 80% reduction for 1T + Counter no longer recharges red life + +`Electrify` + No Cooldown + Duration -> 1T + Electrocute duration now 2/3/4T + +`Sustain` + Now has 1T cooldown at all levels + Has 1T duration at all levels + Now recharges red life to target (120 / 150 / 230)% + + +## [0.1.3 2019-??-??] ### Added @@ -20,20 +52,6 @@ Added `Buff` as a skill `Sustain` now grants immunity to disables. -*BALANCE* -- purify - - 1 effect from all constructs at level 2 - - removes all effects from all constructs at l3 - -- invert - - fx for buffs when applied to enemies - - invert + haste -> doubles all cooldowns - -var / skill info rpc - thresholds / bonuses - sell cost - etc - ## [0.1.2] - 2019-05-07 ### Added diff --git a/WORKLOG.md b/WORKLOG.md index 298e6f99..3b95543c 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -31,6 +31,7 @@ * fuck magic * empower on ko +var / skill info rpc -> sell cost / cooldown * rework vecs into sets * remove names so games/instances are copy diff --git a/server/src/effect.rs b/server/src/effect.rs index 5b3d6bba..1e959e50 100644 --- a/server/src/effect.rs +++ b/server/src/effect.rs @@ -64,11 +64,6 @@ pub enum Effect { impl Effect { pub fn immune(&self, skill: Skill) -> bool { match self { - Effect::Counter => match skill { - Skill::Attack => true, - Skill::Stun => true, - _ => skill.colours().contains(&Colour::Red) - }, Effect::Banish => true, Effect::Sustain => [ Skill::Stun, diff --git a/server/src/game.rs b/server/src/game.rs index ed2ab7e6..222ab0f6 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -1172,14 +1172,14 @@ mod tests { } game.add_skill(x_player.id, x_construct.id, x_construct.id, Skill::Counter).unwrap(); - game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::Stun).unwrap(); + 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(); - // should not be stunned because of counter + // don't get stunned but not really stunning ¯\_(ツ)_/¯ assert!(game.player_by_id(x_player.id).unwrap().constructs[0].is_stunned() == false); // riposte assert_eq!(game.player_by_id(y_player.id).unwrap().constructs[0].green_life(), ( @@ -1209,8 +1209,8 @@ mod tests { game.add_skill(x_player.id, x_construct.id, x_construct.id, Skill::Electrify).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::Electric)); + // game = game.resolve_phase_start(); + // assert!(game.construct_by_id(x_construct.id).unwrap().affected(Effect::Electric)); // attack and receive debuff game.add_skill(y_player.id, y_construct.id, x_construct.id, Skill::Attack).unwrap(); diff --git a/server/src/skill.rs b/server/src/skill.rs index d0972ca9..2f122399 100644 --- a/server/src/skill.rs +++ b/server/src/skill.rs @@ -315,21 +315,17 @@ fn post_resolve(_skill: Skill, game: &mut Game, mut resolutions: Resolutions) -> _ => panic!("no absorb skill"), }; } - }, - Event::Immunity { skill: _, immunity } => match immunity.contains(&Effect::Counter) { - true => { + if target.affected(Effect::Counter) { let ConstructEffect { effect: _, duration: _, meta, tick: _ } = target.effects.iter() .find(|e| e.effect == Effect::Counter).unwrap().clone(); match meta { Some(EffectMeta::Skill(s)) => { - resolutions = riposte(&mut target, &mut source, resolutions, s); + resolutions = counter_attack(&mut target, &mut source, resolutions, s); }, _ => panic!("no counter skill"), }; - - }, - false => (), + } }, _ => (), }; @@ -747,9 +743,6 @@ impl Skill { Skill::ElectrocuteTickPlus => 100, Skill::ElectrocuteTickPlusPlus => 130, - Skill::Counter=> 110, - Skill::CounterPlus => 145, - Skill::CounterPlusPlus => 200, Skill::CounterAttack=> 70, Skill::CounterAttackPlus => 95, Skill::CounterAttackPlusPlus => 120, @@ -758,14 +751,18 @@ impl Skill { Skill::PurifyPlus => 70, Skill::PurifyPlusPlus => 105, - Skill::Reflect=> 45, //restore blue life (heal) + Skill::Reflect=> 45, //Recharge blue life (heal) Skill::ReflectPlus => 70, Skill::ReflectPlusPlus => 100, - Skill::Recharge=> 85, //restore red and blue life (heal) + Skill::Recharge=> 85, //Recharge red and blue life (heal) Skill::RechargePlus => 130, Skill::RechargePlusPlus => 200, + Skill::Sustain => 120, // Recharge red life (heal) + Skill::SustainPlus => 150, + Skill::SustainPlusPlus => 230, + // Stun Base Skill::Sleep=> 240, //Green dmg (heal) Skill::SleepPlus => 300, @@ -891,11 +888,17 @@ impl Skill { Skill::InvertPlusPlus => vec![ConstructEffect {effect: Effect::Invert, duration: 4, meta: None, tick: None}], Skill::Counter => vec![ConstructEffect {effect: Effect::Counter, duration: 1, - meta: Some(EffectMeta::Skill(Skill::CounterAttack)), tick: None}], + meta: Some(EffectMeta::Skill(Skill::CounterAttack)), tick: None}, + ConstructEffect {effect: Effect::Block, duration: 1, + meta: Some(EffectMeta::Multiplier(60)), tick: None}], Skill::CounterPlus => vec![ConstructEffect {effect: Effect::Counter, duration: 1, - meta: Some(EffectMeta::Skill(Skill::CounterAttackPlus)), tick: None}], + meta: Some(EffectMeta::Skill(Skill::CounterAttackPlus)), tick: None}, + ConstructEffect {effect: Effect::Block, duration: 1, + meta: Some(EffectMeta::Multiplier(40)), tick: None}], Skill::CounterPlusPlus => vec![ConstructEffect {effect: Effect::Counter, duration: 1, - meta: Some(EffectMeta::Skill(Skill::CounterAttackPlusPlus)), tick: None}], + meta: Some(EffectMeta::Skill(Skill::CounterAttackPlusPlus)), tick: None}, + ConstructEffect {effect: Effect::Block, duration: 1, + meta: Some(EffectMeta::Multiplier(20)), tick: None}], Skill::Reflect => vec![ConstructEffect {effect: Effect::Reflect, duration: 1, meta: None, tick: None }], Skill::ReflectPlus => vec![ConstructEffect {effect: Effect::Reflect, duration: 1, meta: None, tick: None }], @@ -1076,7 +1079,7 @@ impl Skill { Skill::Sustain | Skill::SustainPlus | - Skill::SustainPlusPlus => None, + Skill::SustainPlusPlus => Some(1), Skill::Intercept=> Some(2), Skill::InterceptPlus => Some(2), @@ -1341,8 +1344,14 @@ fn sleep(source: &mut Construct, target: &mut Construct, mut results: Resolution } fn sustain(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions { - skill.effect().into_iter() - .for_each(|e| (results.push(Resolution::new(source, target).event(target.add_effect(skill, e))))); + let red_amount = source.red_power().pct(skill.multiplier()); + results.push(Resolution::new(source, target) + .event(target.recharge(skill, red_amount, 0))); + + results.push(Resolution::new(source, target) + .event(target.add_effect(skill, skill.effect()[0])) + .stages(EventStages::PostOnly)); + return results; } @@ -1378,19 +1387,17 @@ fn buff(source: &mut Construct, target: &mut Construct, mut results: Resolutions } fn counter(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions { - let red_amount = source.red_power().pct(skill.multiplier()); results.push(Resolution::new(source, target) - .event(target.recharge(skill, red_amount, 0)) - .stages(EventStages::StartEnd)); + .event(target.add_effect(skill, skill.effect()[0]))); results.push(Resolution::new(source, target) - .event(target.add_effect(skill, skill.effect()[0])) + .event(target.add_effect(skill, skill.effect()[1])) .stages(EventStages::PostOnly)); return results; } -fn riposte(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions { +fn counter_attack(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions { let amount = source.red_power().pct(skill.multiplier()); target.deal_red_damage(skill, amount) .into_iter() @@ -1821,7 +1828,7 @@ mod tests { sustain(&mut y.clone(), &mut y, vec![], Skill::Sustain); assert!(y.affected(Effect::Sustain)); - let mut results = blast(&mut x, &mut y, vec![], Skill::Blast); + let mut results = ruin(&mut x, &mut y, vec![], Skill::Ruin); let Resolution { source: _, target: _, event, stages: _ } = results.remove(0); match event { Event::Immunity { skill: _, immunity } => assert!(immunity.contains(&Effect::Sustain)), @@ -2056,8 +2063,8 @@ mod tests { .learn(Skill::HealPlus); purge(&mut x, &mut y, vec![], Skill::Purge); - // current turn + 2 turns at lvl 1 - assert!(y.effects.iter().any(|e| e.effect == Effect::Purge && e.duration == 3)); + // 2 turns at lvl 1 + assert!(y.effects.iter().any(|e| e.effect == Effect::Purge && e.duration == 2)); assert!(y.disabled(Skill::Heal).is_some()); } } From fb80f8921400c6423492f5fe8045be280e6582f4 Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 17 Sep 2019 14:36:15 +1000 Subject: [PATCH 23/24] v1.4.6 --- VERSION | 2 +- acp/package.json | 2 +- client/package.json | 2 +- ops/package.json | 2 +- server/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 03e5161d..7b5753f5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.5 \ No newline at end of file +1.4.6 \ No newline at end of file diff --git a/acp/package.json b/acp/package.json index 2d6bcc99..9b9d7f41 100644 --- a/acp/package.json +++ b/acp/package.json @@ -1,6 +1,6 @@ { "name": "mnml-client", - "version": "1.4.5", + "version": "1.4.6", "description": "", "main": "index.js", "scripts": { diff --git a/client/package.json b/client/package.json index f03cab0e..13676814 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "mnml-client", - "version": "1.4.5", + "version": "1.4.6", "description": "", "main": "index.js", "scripts": { diff --git a/ops/package.json b/ops/package.json index 5314c598..a7f08e96 100755 --- a/ops/package.json +++ b/ops/package.json @@ -1,6 +1,6 @@ { "name": "mnml-ops", - "version": "1.4.5", + "version": "1.4.6", "description": "", "main": "index.js", "scripts": { diff --git a/server/Cargo.toml b/server/Cargo.toml index d3970fb5..89ecb188 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mnml" -version = "1.4.5" +version = "1.4.6" authors = ["ntr "] [dependencies] From 27c410d63dc3e80aa1f811479bc76cef8675b248 Mon Sep 17 00:00:00 2001 From: ntr Date: Tue, 17 Sep 2019 15:37:34 +1000 Subject: [PATCH 24/24] they call me "pixar pete" --- client/assets/icons/mnml.png | Bin 0 -> 53137 bytes client/assets/styles/game.less | 2 +- client/assets/styles/instance.less | 2 +- client/assets/styles/menu.less | 2 +- client/manifest.webmanifest | 4 ++-- client/src/components/anims/wiggle.jsx | 21 +++++++++++++++++++++ client/src/components/construct.jsx | 19 ++++++++++++++++--- 7 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 client/assets/icons/mnml.png create mode 100644 client/src/components/anims/wiggle.jsx diff --git a/client/assets/icons/mnml.png b/client/assets/icons/mnml.png new file mode 100644 index 0000000000000000000000000000000000000000..068e30c139b28437ec136ab98d2d554e280d2676 GIT binary patch literal 53137 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 H<39fb74iao literal 0 HcmV?d00001 diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index 43e9d795..0a71051c 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -295,7 +295,7 @@ background-size: contain; background-repeat: no-repeat; background-position: top; - pointer-events: none; + // pointer-events: none; } .animating .skills { diff --git a/client/assets/styles/instance.less b/client/assets/styles/instance.less index ee7a1898..9d3ea05a 100644 --- a/client/assets/styles/instance.less +++ b/client/assets/styles/instance.less @@ -201,7 +201,7 @@ background-size: contain; background-repeat: no-repeat; background-position: center; - pointer-events: none; + // pointer-events: none; } .name { diff --git a/client/assets/styles/menu.less b/client/assets/styles/menu.less index bafdaa29..a1320161 100644 --- a/client/assets/styles/menu.less +++ b/client/assets/styles/menu.less @@ -55,7 +55,7 @@ background-size: contain; background-repeat: no-repeat; background-position: center; - pointer-events: none; + // pointer-events: none; height: 100%; } } diff --git a/client/manifest.webmanifest b/client/manifest.webmanifest index 1e8a3408..afb2065e 100644 --- a/client/manifest.webmanifest +++ b/client/manifest.webmanifest @@ -4,12 +4,12 @@ "short_name": "mnml", "icons": [ { - "src": "./assets/icons/726.png", + "src": "./assets/icons/mnml.png", "sizes": "32x32", "type": "image/png" }, { - "src": "./assets/icons/726.png", + "src": "./assets/icons/mnml.png", "sizes": "512x512", "type": "image/png" } diff --git a/client/src/components/anims/wiggle.jsx b/client/src/components/anims/wiggle.jsx new file mode 100644 index 00000000..c4f06b9b --- /dev/null +++ b/client/src/components/anims/wiggle.jsx @@ -0,0 +1,21 @@ +const anime = require('animejs').default; + +function wiggle(id, idle) { + const duration = 300; + const target = document.getElementById(id); + const x = (window.screen.width / anime.random(-100, 100)) * 0.1; + const y = (window.screen.height / anime.random(-20, 100)) * 0.1; + return anime({ + targets: target, + rotate: 0, + translateX: [x, -x, 0], + translateY: [y, -y, 0], + duration, + easing: 'easeInOutSine', + // direction: 'alternate', + begin: idle.pause, + complete: idle.restart, + }); +} + +module.exports = wiggle; diff --git a/client/src/components/construct.jsx b/client/src/components/construct.jsx index c502be9e..151b9846 100644 --- a/client/src/components/construct.jsx +++ b/client/src/components/construct.jsx @@ -7,13 +7,14 @@ const { connect } = require('preact-redux'); const banish = require('./anims/banish'); const idleAnimation = require('./anims/idle'); const invert = require('./anims/invert'); +const wiggle = require('./anims/wiggle'); const sourceCast = require('./anims/source.cast'); const { ConstructAnimation } = require('./animations'); const addState = connect( function receiveState(state) { - const { animSource, animTarget } = state; - return { animSource, animTarget }; + const { animSource, animTarget, animText } = state; + return { animSource, animTarget, animText }; } ); @@ -33,12 +34,17 @@ class ConstructAvatar extends Component {
); } + onClick() { + return this.animations.push(wiggle(this.props.construct.id, this.idle)); + } + componentDidMount() { this.idle = idleAnimation(this.props.construct.id); return this.animations.push(this.idle); @@ -54,11 +60,17 @@ class ConstructAvatar extends Component { this.resetAnimations(); } - shouldComponentUpdate({ animSource, animTarget, construct }) { + shouldComponentUpdate(newProps) { + const { animSource, animTarget, animText, construct } = newProps; + if (construct !== this.props.construct) { return true; } + if (animText && animText.constructId === construct.id) { + return wiggle(construct.id, this.idle); + } + if (animSource === this.props.animSource && animTarget === this.props.animTarget) { // console.warn(construct.name, 'thinks its same props') return false; @@ -73,6 +85,7 @@ class ConstructAvatar extends Component { return sourceCast(animSource.constructId, animSource.direction, this.idle); } + // this is the target if (animTarget && animTarget.constructId.includes(construct.id)) { // console.warn(construct.name, 'should update')