From 1bc73694cea09bc4ac7f8259275cfb68c24a6a3e Mon Sep 17 00:00:00 2001 From: Mashy Date: Fri, 5 Jul 2019 16:54:09 +1000 Subject: [PATCH] ruin & aoe skills --- client/src/components/animations.jsx | 27 ++++---- client/src/components/anims/ruin.jsx | 85 ++++++++++++++++++++++++ client/src/components/game.construct.jsx | 2 +- client/src/utils.jsx | 65 ++++++------------ server/src/skill.rs | 10 ++- 5 files changed, 128 insertions(+), 61 deletions(-) create mode 100644 client/src/components/anims/ruin.jsx diff --git a/client/src/components/animations.jsx b/client/src/components/animations.jsx index f60207f8..1a27c1a2 100644 --- a/client/src/components/animations.jsx +++ b/client/src/components/animations.jsx @@ -23,11 +23,12 @@ const Heal = require('./anims/heal'); const Hybrid = require('./anims/hybrid'); const Intercept = require('./anims/intercept'); const Invert = require('./anims/invert'); +const Link = require('./anims/link'); const Purify = require('./anims/purify'); const Recharge = require('./anims/recharge'); const Refl = require('./anims/reflect'); const Restrict = require('./anims/restrict'); -const Link = require('./anims/link'); +const Ruin = require('./anims/ruin'); const Siphon = require('./anims/siphon'); const SiphonTick = require('./anims/siphon.tick'); const Slay = require('./anims/slay'); @@ -61,17 +62,16 @@ function animations(props) { if (!resolution.target) return false; // source animation + const playerTeam = game.players.find(t => t.id === account.id); + const playerTeamIds = playerTeam.constructs.map(c => c.id); + const otherTeam = game.players.find(t => t.id !== account.id); + const otherTeamIds = otherTeam.constructs.map(c => c.id); + + const sourceIsPlayer = playerTeamIds.includes(construct.id); + const targetIsPlayer = playerTeamIds.includes(resolution.target.id); + if (resolution.source.id === construct.id && resolution.stages.includes('START_SKILL')) { - const playerTeam = game.players.find(t => t.id === account.id); - const playerTeamIds = playerTeam.constructs.map(c => c.id); - const otherTeam = game.players.find(t => t.id !== account.id); - const otherTeamIds = otherTeam.constructs.map(c => c.id); - - const sourceIsPlayer = playerTeamIds.includes(construct.id); - const targetIsPlayer = playerTeamIds.includes(resolution.target.id); - const sameTeam = (sourceIsPlayer && targetIsPlayer) || (!sourceIsPlayer && !targetIsPlayer); - const y = sameTeam ? 0 : targetIsPlayer @@ -97,8 +97,9 @@ function animations(props) { }); } - - if (resolution.target.id !== construct.id) return false; + const targetTeam = targetIsPlayer ? playerTeamIds : otherTeamIds; + if (!((resolution.target.id === construct.id) + || (resolution.event[0] === 'AoeSkill' && targetTeam.includes(construct.id)))) return false; // target animation const anim = text => { @@ -144,7 +145,7 @@ function animations(props) { case 'Absorb': return ; case 'Sleep': return ; case 'Throw': return false; - case 'Ruin': return false; + case 'Ruin': return ; // Block Base case 'Block': return ; diff --git a/client/src/components/anims/ruin.jsx b/client/src/components/anims/ruin.jsx new file mode 100644 index 00000000..36afdbc1 --- /dev/null +++ b/client/src/components/anims/ruin.jsx @@ -0,0 +1,85 @@ +const preact = require('preact'); +const { Component } = require('preact'); +const anime = require('animejs').default; + +const { TIMES } = require('../../constants'); + +// logarithmic spiral lifted from +// https://upload.wikimedia.org/wikipedia/commons/5/5b/Logarithmic_spiral_(1).svg + +class Ruin extends Component { + constructor() { + super(); + this.animations = []; + } + + render() { + const path = 'M0,100 C100,100 100,100 200,100'; + + return ( + + + + + + + + + + + + + + + + + ); + } + + componentDidMount() { + this.animations.push(anime({ + targets: ['#ruin'], + 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: ['#ruin'], + rotate: 180, + easing: 'linear', + loop: true, + delay: TIMES.TARGET_DELAY_MS, + duration: TIMES.TARGET_DURATION_MS, + })); + } + + // 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(); + } + } +} + +module.exports = Ruin; diff --git a/client/src/components/game.construct.jsx b/client/src/components/game.construct.jsx index 792822c0..e89cc7d0 100644 --- a/client/src/components/game.construct.jsx +++ b/client/src/components/game.construct.jsx @@ -58,7 +58,7 @@ function GameConstruct(props) { const ko = construct.green_life.value === 0 ? 'ko' : ''; - const classes = eventClasses(resolution, construct); + const classes = eventClasses(game, account, resolution, construct); const stats = ['RedLife', 'GreenLife', 'BlueLife'].map((s, j) => (
diff --git a/client/src/utils.jsx b/client/src/utils.jsx index ba71dd37..65780cd6 100644 --- a/client/src/utils.jsx +++ b/client/src/utils.jsx @@ -73,39 +73,34 @@ const STATS = { }, }; -function eventClasses(resolution, construct) { +function eventClasses(game, account, resolution, construct) { if (!resolution) return ''; const postSkill = resolution.stages.includes('POST_SKILL'); const source = construct.id === resolution.source.id; const target = construct.id === resolution.target.id; // not involved at all. blur them - if (!(source || target)) return 'unfocus'; - - // not the target. just ignore for now - // if (construct.id !== resolution.target.id) return ''; - const [type, event] = resolution.event; + if (type === 'AoeSkill') { + const playerTeam = game.players.find(t => t.id === account.id); + const playerTeamIds = playerTeam.constructs.map(c => c.id); + const otherTeam = game.players.find(t => t.id !== account.id); + const otherTeamIds = otherTeam.constructs.map(c => c.id); + const targetIsPlayer = playerTeamIds.includes(resolution.target.id); + + const targetTeam = targetIsPlayer ? playerTeamIds : otherTeamIds; + + if (targetTeam.includes(construct.id)) return ''; + } + + if (!(source || target)) return 'unfocus'; + if (type === 'Ko') { if (target) return 'ko'; } - if (type === 'Disable') { - const { skill, disable } = event; - } - - if (type === 'Immunity') { - const { skill, immunity } = event; - } - - if (type === 'TargetKo') { - const { skill } = event; - } - if (type === 'Damage') { - const { skill, amount, mitigation, colour } = event; - // Highlight the flow of damage from source -> target - // Deal damage to construct and return effect + const { colour } = event; if (target && postSkill) { construct.green_life.value = resolution.target.green; if (colour === 'Red') { @@ -120,44 +115,28 @@ function eventClasses(resolution, construct) { construct.green_life.value = resolution.target.green; return 'green-damage'; } - } } if (type === 'Healing') { - const { skill, amount, overhealing } = event; if (target && postSkill) { construct.green_life.value = resolution.target.green; return 'green-damage'; - } } - if (type === 'Inversion') { - const { skill } = event; - } - - if (type === 'Reflection') { - const { skill } = event; - } - if (type === 'Effect') { - const { skill, effect, duration, construct_effects: constructEffects } = event; + const { construct_effects: constructEffects } = event; if (target && postSkill) construct.effects = constructEffects; } - if (type === 'Skill') { - const { skill } = event; - // Highlight the flow of damage from source -> target - } - if (type === 'Removal') { - const { effect, construct_effects: constructEffects } = event; + const { construct_effects: constructEffects } = event; if (target && postSkill) construct.effects = constructEffects; } if (type === 'Recharge') { - const { skill, red, blue } = event; + const { red, blue } = event; if (target && postSkill) { if (red > 0 && blue > 0) { construct.red_life.value = resolution.target.red; @@ -175,17 +154,13 @@ function eventClasses(resolution, construct) { } } - if (type === 'Evasion') { - const { skill, evasion_rating } = event; - } - return ''; } function getCombatSequence(resolution) { if (!resolution.event) return false; if (resolution.event[0] === 'Inversion') return false; - if (resolution.event[0] === 'Skill') return [['START_SKILL', 'END_SKILL']]; + if (['Skill', 'AoeSkill'].includes(resolution.event[0])) return [['START_SKILL', 'END_SKILL']]; if (resolution.event[0] === 'Ko') return [['POST_SKILL']]; switch (resolution.stages) { diff --git a/server/src/skill.rs b/server/src/skill.rs index 299c2be3..a93367aa 100644 --- a/server/src/skill.rs +++ b/server/src/skill.rs @@ -9,11 +9,16 @@ use game::{Game}; use effect::{Effect, Colour, Cooldown}; pub fn dev_resolve(a_id: Uuid, b_id: Uuid, skill: Skill) -> Resolutions { + let mut resolutions = vec![]; + let mut a = Construct::new(); a.id = a_id; let mut b = Construct::new(); b.id = b_id; - return resolve(skill, &mut a, &mut b, vec![]); + if skill.aoe() { // Send an aoe skill event for anims + resolutions.push(Resolution::new(&a, &b).event(Event::AoeSkill { skill })); + } + return resolve(skill, &mut a, &mut b, resolutions); } pub fn resolution_steps(cast: &Cast, game: &mut Game) -> Resolutions { @@ -31,7 +36,7 @@ pub fn pre_resolve(cast: &Cast, game: &mut Game, mut resolutions: Resolutions) - if skill.aoe() { // Send an aoe skill event for anims resolutions.push(Resolution::new(&source, - &game.construct_by_id(cast.target_construct_id).unwrap().clone()).event(Event::Skill { skill })); + &game.construct_by_id(cast.target_construct_id).unwrap().clone()).event(Event::AoeSkill { skill })); } for target_id in targets { @@ -460,6 +465,7 @@ pub enum Event { Recharge { skill: Skill, red: u64, blue: u64 }, Inversion { skill: Skill }, Reflection { skill: Skill }, + AoeSkill { skill: Skill }, Skill { skill: Skill }, Effect { skill: Skill, effect: Effect, duration: u8, construct_effects: Vec }, Removal { effect: Effect, construct_effects: Vec },