Merge branch 'develop' into inventory

This commit is contained in:
ntr 2019-07-09 16:55:55 +10:00
commit 6696809d1e
9 changed files with 141 additions and 146 deletions

View File

@ -25,14 +25,18 @@ function createSocket(store) {
function onDevResolutions(newRes) { function onDevResolutions(newRes) {
const { game: currentGame } = store.getState(); const { game: currentGame } = store.getState();
let id = 0;
return eachSeries(newRes, (r, cb) => { return eachSeries(newRes, (r, cb) => {
if (['Disable', 'TargetKo'].includes(r.event[0])) return cb(); if (['Disable', 'TargetKo'].includes(r.event[0])) return cb();
// Create sub events for combat animations // Create sub events for combat animations
const sequence = getCombatSequence(r); const sequence = getCombatSequence(r);
id += 1;
return eachSeries(sequence, (stages, sCb) => { return eachSeries(sequence, (stages, sCb) => {
const stagedR = Object.create(r); const stagedR = Object.create(r);
stagedR.sequence = sequence; stagedR.sequence = sequence;
stagedR.stages = stages; stagedR.stages = stages;
stagedR.id = id;
let timeout = 0; let timeout = 0;
if (stages.includes('START_SKILL') && stages.includes('END_SKILL')) { if (stages.includes('START_SKILL') && stages.includes('END_SKILL')) {
@ -45,11 +49,13 @@ function createSocket(store) {
return setTimeout(sCb, timeout); return setTimeout(sCb, timeout);
}, err => { }, err => {
if (err) console.error(err); if (err) console.error(err);
store.dispatch(actions.setAvatarAnimation({ id, source: false, target: false }));
// Finished this resolution // Finished this resolution
return cb(); return cb();
}); });
}, err => { }, err => {
if (err) return console.error(err); if (err) return console.error(err);
store.dispatch(actions.setAvatarAnimation({ id: -1, source: false, target: false }));
store.dispatch(actions.setResolution(null)); store.dispatch(actions.setResolution(null));
// stop skipping resolutions // stop skipping resolutions
store.dispatch(actions.setSkip(false)); store.dispatch(actions.setSkip(false));

View File

@ -73,13 +73,20 @@ function animations(props) {
const sourceIsPlayer = playerTeamIds.includes(construct.id); const sourceIsPlayer = playerTeamIds.includes(construct.id);
const targetIsPlayer = playerTeamIds.includes(resolution.target.id); const targetIsPlayer = playerTeamIds.includes(resolution.target.id);
if (resolution.source.id === construct.id && resolution.stages.includes('START_SKILL')) { const skipSource = (resolution.source.id === resolution.target.id
&& ['Invert', 'Banish'].includes(removeTier(event.skill)));
if (!skipSource && resolution.source.id === construct.id && resolution.stages.includes('START_SKILL')) {
const sameTeam = (sourceIsPlayer && targetIsPlayer) || (!sourceIsPlayer && !targetIsPlayer); const sameTeam = (sourceIsPlayer && targetIsPlayer) || (!sourceIsPlayer && !targetIsPlayer);
const y = sameTeam
? 0 let y = 0;
: targetIsPlayer if (!sameTeam) y = targetIsPlayer ? 1 : -1;
? 1
: -1; // const y = sameTeam
// ? 0
// : targetIsPlayer
// ? 1
// : -1;
const i = sourceIsPlayer const i = sourceIsPlayer
? playerTeamIds.findIndex(c => c === construct.id) ? playerTeamIds.findIndex(c => c === construct.id)
@ -90,8 +97,15 @@ function animations(props) {
: otherTeamIds.findIndex(c => c === resolution.target.id); : otherTeamIds.findIndex(c => c === resolution.target.id);
const x = j - i; const x = j - i;
if (avatarAnimation.id !== resolution.id) { if (!avatarAnimation.source) {
setAvatarAnimation({ id: resolution.id, animTargetId: construct.id, x, y }); setAvatarAnimation({
source: true,
target: avatarAnimation.target,
id: resolution.id,
animTargetId: construct.id,
type: 'sourceCast',
params: { x, y },
});
} }
} }
const targetTeam = targetIsPlayer ? playerTeamIds : otherTeamIds; const targetTeam = targetIsPlayer ? playerTeamIds : otherTeamIds;
@ -100,7 +114,6 @@ function animations(props) {
// target animation // target animation
const anim = text => { const anim = text => {
console.log(text);
if (!text || !resolution.sequence[0].includes('END_SKILL')) return false; if (!text || !resolution.sequence[0].includes('END_SKILL')) return false;
const skill = removeTier(text); const skill = removeTier(text);
@ -130,14 +143,34 @@ function animations(props) {
case 'Curse': return <Curse />; case 'Curse': return <Curse />;
case 'Decay': return <Decay />; case 'Decay': return <Decay />;
case 'DecayTick': return <Decay />; case 'DecayTick': return <Decay />;
case 'Invert': return <Invert id={construct.id} />; case 'Invert': {
if (!avatarAnimation.target) {
setAvatarAnimation({
source: avatarAnimation.source,
target: true,
id: resolution.id,
animTargetId: construct.id,
type: 'invert',
});
} break;
}
case 'Purge': return <Purge />; case 'Purge': return <Purge />;
case 'Silence': return <Silence />; case 'Silence': return <Silence />;
case 'Restrict': return <Restrict />; case 'Restrict': return <Restrict />;
// Stun Base // Stun Base
case 'Stun': return <Stun />; case 'Stun': return <Stun />;
case 'Banish': return <Banish id={construct.id} />; case 'Banish': {
if (!avatarAnimation.target) {
setAvatarAnimation({
source: avatarAnimation.source,
target: true,
id: resolution.id,
animTargetId: construct.id,
type: 'banish',
});
} break;
}
case 'Bash': return <Bash />; case 'Bash': return <Bash />;
case 'Absorb': return <Absorb />; case 'Absorb': return <Absorb />;
case 'Sleep': return <Sleep />; case 'Sleep': return <Sleep />;

View File

@ -1,42 +1,17 @@
const preact = require('preact');
const { Component } = require('preact');
const anime = require('animejs').default; const anime = require('animejs').default;
const { TIMES } = require('../../constants'); const { TIMES } = require('../../constants');
class Banish extends Component { function Banish(id) {
constructor(props) { return anime({
super(); targets: [document.getElementById(id)],
this.id = props.id;
this.animations = [];
}
render() {
// Need this so unmount triggers
return <svg id='invert'></svg>;
}
componentDidMount() {
this.animations.push(anime({
targets: [document.getElementById(this.id)],
scaleY: 0, scaleY: 0,
fill: '#fff', fill: '#fff',
easing: 'easeOutElastic', easing: 'easeOutElastic',
delay: TIMES.TARGET_DELAY_MS, delay: TIMES.TARGET_DELAY_MS,
duration: TIMES.TARGET_DURATION_MS * 0.5, duration: TIMES.TARGET_DURATION_MS * 0.45,
direction: 'alternate', direction: 'alternate',
})); });
}
// 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 = Banish; module.exports = Banish;

View File

@ -0,0 +1,18 @@
const anime = require('animejs').default;
function idle(id) {
const duration = anime.random(2000, 18000);
const target = document.getElementById(id);
return anime({
targets: target,
translateX: () => anime.random(-20, 20),
translateY: () => anime.random(0, -40),
rotate: () => anime.random(-15, 15),
duration,
direction: 'alternate',
easing: 'linear',
loop: true,
});
}
module.exports = idle;

View File

@ -1,41 +1,16 @@
const preact = require('preact');
const { Component } = require('preact');
const anime = require('animejs').default; const anime = require('animejs').default;
const { TIMES } = require('../../constants'); const { TIMES } = require('../../constants');
class Invert extends Component { function Invert(id) {
constructor(props) { return anime({
super(); targets: [document.getElementById(id)],
this.id = props.id;
this.animations = [];
}
render() {
// Need this so unmount triggers
return <svg id='invert'></svg>;
}
componentDidMount() {
this.animations.push(anime({
targets: [document.getElementById(this.id)],
rotate: 180, rotate: 180,
delay: TIMES.TARGET_DELAY_MS, delay: TIMES.TARGET_DELAY_MS,
duration: TIMES.TARGET_DURATION_MS * 0.45, duration: TIMES.TARGET_DURATION_MS * 0.45,
easing: 'easeInOutElastic', easing: 'easeInOutElastic',
direction: 'alternate', direction: 'alternate',
})); });
}
// 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 = Invert; module.exports = Invert;

View File

@ -0,0 +1,17 @@
const anime = require('animejs').default;
const { TIMES } = require('../../constants');
function sourceCast(id, params) {
const { x, y } = params;
return anime({
targets: [document.getElementById(id)],
translateX: x * 200,
translateY: y * 200,
easing: 'easeInOutElastic',
direction: 'alternate',
duration: TIMES.SOURCE_DURATION_MS,
});
}
module.exports = sourceCast;

View File

@ -3,7 +3,11 @@ const { Component } = require('preact');
const { connect } = require('preact-redux'); const { connect } = require('preact-redux');
const anime = require('animejs').default; const anime = require('animejs').default;
const { TIMES } = require('../constants'); const banish = require('./anims/banish');
const idleAnimation = require('./anims/idle');
const invert = require('./anims/invert');
const sourceCast = require('./anims/source.cast');
const genAvatar = name => { const genAvatar = name => {
let hash = 0; let hash = 0;
@ -17,28 +21,6 @@ const genAvatar = name => {
return `${hash}`; return `${hash}`;
}; };
const animations = {};
function animateConstruct(id) {
if (animations[id]) return false;
animations[id] = true;
const duration = anime.random(2000, 18000);
const target = document.getElementById(id);
return anime({
targets: target,
translateX: () => anime.random(-20, 20),
translateY: () => anime.random(0, -40),
rotate: () => anime.random(-15, 15),
duration,
direction: 'alternate',
easing: 'linear',
loop: true,
complete: () => animations[id] = false,
});
}
function clearAnimation(id) {
animations[id] = false;
}
const addState = connect( const addState = connect(
function receiveState(state) { function receiveState(state) {
@ -48,10 +30,15 @@ const addState = connect(
); );
class ConstructAvatar extends Component { class ConstructAvatar extends Component {
constructor() { constructor(props) {
super(); super();
// The animation ids are a check to ensure that animations are not repeated
// When a new construct animation is communicated with state it will have a corresponding Id
// which is a count of how many resoluttions have passed
this.animId = 0; this.animId = 0;
this.source = false;
this.animations = []; this.animations = [];
this.avatar = genAvatar(props.name);
} }
render() { render() {
@ -59,61 +46,44 @@ class ConstructAvatar extends Component {
<div <div
class="avatar" class="avatar"
id={this.props.id} id={this.props.id}
style={{'background-image': `url(/molecules/${genAvatar(this.props.name)}.svg)`}} style={{ 'background-image': `url(/molecules/${this.avatar}.svg)` }}
/> />
); );
} }
componentDidMount() { componentDidMount() {
this.idle = animateConstruct(this.props.id); this.idle = idleAnimation(this.props.id);
this.animations.push(this.idle);
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (nextProps.avatarAnimation.id === -1) this.animId = 0; // The current set of resolutions ended reset to 0
if (nextProps.avatarAnimation.id !== this.animId && nextProps.avatarAnimation.animTargetId === this.props.id) { if (nextProps.avatarAnimation.id !== this.animId && nextProps.avatarAnimation.animTargetId === this.props.id) {
this.animId = nextProps.avatarAnimation.id; this.animId = nextProps.avatarAnimation.id;
const selectAnim = () => {
switch (nextProps.avatarAnimation.type) {
case 'banish': return banish(this.props.id);
case 'invert': return invert(this.props.id);
case 'sourceCast': return sourceCast(this.props.id, nextProps.avatarAnimation.params);
default: return null;
}
};
const anim = selectAnim();
if (anim) {
this.idle.pause(); this.idle.pause();
const anim = anime({ this.animations.push(anim);
targets: [document.getElementById(this.props.id)],
translateY: nextProps.avatarAnimation.y * 200,
translateX: nextProps.avatarAnimation.x * 200,
easing: 'easeInOutElastic',
direction: 'alternate',
duration: TIMES.SOURCE_DURATION_MS,
});
anim.finished.then(this.idle.play); anim.finished.then(this.idle.play);
} }
// console.log(this.props); }
// console.log(nextProps);
} }
componentWillUnmount() { componentWillUnmount() {
clearAnimation(this.props.id); for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset();
} }
}
class ConstructImg extends Component {
render() {
return (
<img
class="avatar"
id={this.props.id}
src={`/molecules/${genAvatar(this.props.name)}.svg`}
height="500"
onError={event => event.target.setAttribute('src', '/molecules/726.svg')}
/>
);
}
componentDidMount() {
animateConstruct(this.props.id);
}
componentWillUnmount() {
clearAnimation(this.props.id);
} }
} }
module.exports = { module.exports = {
ConstructAvatar: addState(ConstructAvatar), ConstructAvatar: addState(ConstructAvatar),
ConstructImg,
}; };

View File

@ -84,12 +84,13 @@ function registerEvents(store) {
if (err) console.error(err); if (err) console.error(err);
// Clear the anim classes // Clear the anim classes
store.dispatch(actions.setResolution('clear')); store.dispatch(actions.setResolution('clear'));
store.dispatch(actions.setAvatarAnimation({ id, source: false, target: false }));
// Finished this resolution small delay for reset // Finished this resolution small delay for reset
return setTimeout(cb, 5); return setTimeout(cb, 5);
}); });
}, err => { }, err => {
if (err) return console.error(err); if (err) return console.error(err);
store.dispatch(actions.setAvatarAnimation({ id: -1 })); store.dispatch(actions.setAvatarAnimation({ id: -1, source: false, target: false }));
store.dispatch(actions.setResolution(null)); store.dispatch(actions.setResolution(null));
// stop skipping resolutions // stop skipping resolutions
store.dispatch(actions.setSkip(false)); store.dispatch(actions.setSkip(false));

View File

@ -15,7 +15,7 @@ module.exports = {
activeConstruct: createReducer(null, 'SET_ACTIVE_CONSTRUCT'), activeConstruct: createReducer(null, 'SET_ACTIVE_CONSTRUCT'),
activeItem: createReducer(null, 'SET_ACTIVE_VAR'), activeItem: createReducer(null, 'SET_ACTIVE_VAR'),
activeSkill: createReducer(null, 'SET_ACTIVE_SKILL'), activeSkill: createReducer(null, 'SET_ACTIVE_SKILL'),
avatarAnimation: createReducer({ id: -1 }, 'SET_AVATAR_ANIMATION'), avatarAnimation: createReducer({ id: -1, source: false, target: false }, 'SET_AVATAR_ANIMATION'),
combiner: createReducer([null, null, null], 'SET_COMBINER'), combiner: createReducer([null, null, null], 'SET_COMBINER'),
constructs: createReducer([], 'SET_CONSTRUCTS'), constructs: createReducer([], 'SET_CONSTRUCTS'),
constructEditId: createReducer(null, 'SET_CONSTRUCT_EDIT_ID'), constructEditId: createReducer(null, 'SET_CONSTRUCT_EDIT_ID'),