Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Mashy 2019-07-23 18:07:39 +10:00
commit 2dc929de40
15 changed files with 252 additions and 180 deletions

View File

@ -1,6 +1,6 @@
require('./assets/styles/styles.css');
require('./assets/styles/styles.mobile.css');
require('./assets/styles/instance.css');
require('./assets/styles/instance.less');
require('./assets/styles/instance.mobile.css');
require('./assets/styles/game.css');

View File

@ -234,65 +234,54 @@
*/}
.game-construct.red-damage {
/* filter: drop-shadow(0 0 0.2em red);
*/ color: red;
color: #a52a2a;
/*ensure construct doesn't get opacity lowered because of being KO before the KO animation*/
opacity: 1;
/*border-color: red;*/
}
.red-damage button {
/*border: 1px solid red;*/
color: red;
color: #a52a2a;
}
.red-damage text {
fill: red;
fill: #a52a2a;
}
.red-damage .stats {
/*border-top: 1px solid red;*/
/*border-top: 1px solid #a52a2a;*/
}
.game-construct.blue-damage {
/* filter: drop-shadow(0 0 0.2em blue);
*/ color: blue;
color: #3498db;
opacity: 1;
/*border-color: blue;*/
}
.blue-damage button {
/*border: 1px solid blue;*/
color: blue;
color: #3498db;
}
.blue-damage text {
fill: blue;
fill: #3498db;
}
.blue-damage .stats {
/*border-top: 1px solid blue;*/
}
.game-construct.green-damage {
/* filter: drop-shadow(0 0 0.2em green);
*/ color: green;
color: #1FF01F;
opacity: 1;
/*border-color: green;*/
}
.green-damage button {
/*border: 1px solid green;*/
color: green;
color: #1FF01F;
}
.green-damage text {
fill: green;
fill: #1FF01F;
}
.green-damage .stats {
/*border-top: 1px solid green;*/
/*border-top: 1px solid #1FF01F;*/
}
.game-construct.purple-damage {

View File

@ -287,66 +287,80 @@
flex: 1 0 100%;
}
// .equipping {
// position: relative;
// }
// .equipping::before {
// content: '';
// position: absolute;
// top: 2px;
// left: 50%;
// width: 100%;
// height: 2px;
// transform-origin: center;
// background-color: whitesmoke;
// animation: equipping-skill 2s infinite ease-out alternate;
// opacity: 0;
// }
// .equipping::after {
// content: '';
// position: absolute;
// bottom: 2px;
// left: 50%;
// width: 100%;
// height: 2px;
// transform-origin: center;
// background-color: whitesmoke;
// animation: equipping-skill 2s infinite ease-out alternate;
// opacity: 0;
// animation-delay: 0.75s
// }
// @keyframes equipping-skill {
// from {
// transform: translate(-50%, 0) scaleX(0);
// }
// to {
// transform: translate(-50%, 0) scaleX(0.75);
// opacity: 1;
// }
// }
// .equip-spec {
// position: relative;
// stroke: #333;
// }
// .equip-spec::after {
// content: '';
// position: absolute;
// bottom: 2px;
// left: 50%;
// width: 100%;
// height: 2px;
// transform-origin: center;
// background-color: whitesmoke;
// animation: equipping-skill 2s infinite ease-out alternate;
// opacity: 0;
// }
.equipping {
position: relative;
animation: equipping 2s infinite ease-in-out alternate;
}
.equipping::before {
content: '';
position: absolute;
top: 2px;
left: 50%;
width: 100%;
height: 2px;
transform-origin: center;
background-color: whitesmoke;
animation: equipping-skill 2s infinite ease-out alternate;
opacity: 0;
}
.equipping::after {
content: '';
position: absolute;
bottom: 2px;
left: 50%;
width: 100%;
height: 2px;
transform-origin: center;
background-color: whitesmoke;
animation: equipping-skill 2s infinite ease-out alternate;
opacity: 0;
animation-delay: 0.75s
}
@keyframes equipping-skill {
@keyframes equipping {
from {
transform: translate(-50%, 0) scaleX(0);
border-color: #444;
}
to {
transform: translate(-50%, 0) scaleX(0.75);
opacity: 1;
border-color: whitesmoke;
}
}
.equip-spec {
position: relative;
stroke: #333;
}
.equip-spec::after {
content: '';
position: absolute;
bottom: 2px;
left: 50%;
width: 100%;
height: 2px;
transform-origin: center;
background-color: whitesmoke;
animation: equipping-skill 2s infinite ease-out alternate;
opacity: 0;
}
.thresholds {
display: flex;
flex-flow: column;

View File

@ -78,9 +78,18 @@
background: @white;
border: 1px solid @white;
// overwrite the classes on white svg elements
ellipse.white {
stroke: black;
}
rect.white {
stroke: black;
}
polygon.white {
stroke: black;
}
}
}

View File

@ -5,7 +5,7 @@
"main": "index.js",
"scripts": {
"start": "parcel watch index.html --out-dir /var/lib/mnml/public/current",
"anims": "parcel watch animations.html --out-dir /var/lib/mnml/public/current",
"anims": "parcel watch animations.html --no-hmr --out-dir /var/lib/mnml/public/current",
"build": "parcel build index.html",
"scss": "node-sass --watch assets/scss -o assets/styles",
"lint": "eslint --fix --ext .jsx src/",

View File

@ -28,12 +28,9 @@ function createSocket(store) {
if (animating) return false;
store.dispatch(actions.setAnimating(true));
return eachSeries(newRes, (r, cb) => {
if (['Disable', 'TargetKo'].includes(r.event[0])) return cb();
store.dispatch(actions.setResolution(r));
// convert server enum into anims keywords
// todo make serersideonly
const sequence = animations.getSequence(r);
@ -41,23 +38,29 @@ function createSocket(store) {
const anims = animations.getObjects(r, sequence, game, account);
const text = animations.getText(r, sequence);
store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r)));
if (sequence.includes('START_SKILL')) store.dispatch(actions.setAnimSource(anims.animSource));
if (sequence.includes('END_SKILL')) store.dispatch(actions.setAnimTarget(anims.animTarget));
if (sequence.includes('END_SKILL')) {
store.dispatch(actions.setAnimTarget(anims.animTarget));
if (!['Banish', 'Invert'].includes(anims.animTarget.skill)) store.dispatch(actions.setAnimCb(cb));
}
if (sequence.includes('POST_SKILL')) {
// timeout to prevent text classes from being added too soon
setTimeout(
() => store.dispatch(actions.setAnimText(text)),
timeout - 1000,
timeout - TIMES.POST_SKILL_DURATION_MS
);
}
return setTimeout(() => {
store.dispatch(actions.setAnimSource(null));
store.dispatch(actions.setAnimTarget(null));
store.dispatch(actions.setAnimText(null));
return setTimeout(cb, 50);
store.dispatch(actions.setAnimFocus([]));
if (!sequence.includes('END_SKILL')
|| ['Banish', 'Invert'].includes(anims.animTarget.skill)) return cb();
return true;
}, timeout);
}, err => {
if (err) return console.error(err);
// clear animation state

View File

@ -69,48 +69,48 @@ document.fonts.load('16pt "Jura"').then(() => {
});
const SKILLS = [
'AbsorbI',
'AbsorptionI',
'AmplifyI',
'Absorb',
'Absorption',
'Amplify',
'Attack',
'BanishI',
'BashI',
'BlastI',
'Banish',
'Bash',
'Blast',
'Block',
'BreakI',
'Break',
'Buff',
'ChaosI',
'CounterAttackI',
'CounterI',
'CurseI',
'Chaos',
'CounterAttack',
'Counter',
'Curse',
'Debuff',
'DecayI',
'DecayTickI',
'ElectrifyI',
'ElectrocuteI',
'ElectrocuteTickI',
'HasteI',
'Decay',
'DecayTick',
'Electrify',
'Electrocute',
'ElectrocuteTick',
'Haste',
'HasteStrike',
'HealI',
'Heal',
'HybridBlast',
'HybridI',
'InterceptI',
'InvertI',
'LinkI',
'PurgeI',
'PurifyI',
'RechargeI',
'ReflectI',
'RestrictI',
'RuinI',
'SilenceI',
'SiphonI',
'SiphonTickI',
'SlayI',
'SleepI',
'StrikeI',
'Hybrid',
'Intercept',
'Invert',
'Link',
'Purge',
'Purify',
'Recharge',
'Reflect',
'Restrict',
'Ruin',
'Silence',
'Siphon',
'SiphonTick',
'Slay',
'Sleep',
'Strike',
'Stun',
'SustainI',
'TriageI',
'TriageTickI',
'Sustain',
'Triage',
'TriageTick',
];

View File

@ -3,6 +3,7 @@ const { Component } = require('preact');
const { connect } = require('preact-redux');
const Amplify = require('./anims/amplify');
const Attack = require('./anims/attack');
const Absorb = require('./anims/absorb');
const Bash = require('./anims/bash');
const Blast = require('./anims/blast');
@ -69,7 +70,7 @@ class ConstructAnimation extends Component {
const chooseAnim = (skill) => {
switch (skill) {
// Attack base
case 'Attack': return <Strike colour={'#f5f5f5'} direction={direction}/>;
case 'Attack': return <Attack direction={direction}/>;
case 'Blast': return <Blast direction={direction}/>;
case 'Siphon': return <Siphon />;
case 'SiphonTick': return <SiphonTick />;

View File

@ -0,0 +1,67 @@
const preact = require('preact');
const { Component } = require('preact');
const { connect } = require('preact-redux');
const anime = require('animejs').default;
const { TIMES, COLOURS } = require('../../constants');
const addState = connect(
function receiveState(state) {
const { animCb } = state;
return { animCb };
}
);
class Attack extends Component {
constructor(props) {
super();
this.props = props;
this.animations = [];
}
render() {
return (
<svg
class='attack-anim'
version="1.1"
id="attack"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 400 400">
<g>
<rect x="0" y="400" transform="skewX(45)"
width="12" height="100" stroke-width="0" fill={COLOURS.RED}/>
<rect x="200" y="400"
width="12" height="100" stroke-width="0" fill={COLOURS.RED}/>
<rect x="400" y="400" transform="skewX(-45)"
width="12" height="100" stroke-width="0" fill={COLOURS.RED}/>
</g>
</svg>
);
}
componentDidMount() {
this.animations.push(anime({
targets: ['#attack rect'],
easing: 'easeOutExpo',
y: [400, 200],
height: [100, 10, 0],
width: [12, 5, 0],
delay: () => anime.random(TIMES.TARGET_DELAY_MS, TIMES.TARGET_DELAY_MS + TIMES.TARGET_DURATION_MS / 2),
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();
}
this.props.animCb();
}
}
module.exports = addState(Attack);

View File

@ -2,9 +2,9 @@ const preact = require('preact');
const { Component } = require('preact');
const { connect } = require('preact-redux');
const anime = require('animejs').default;
const times = require('lodash/times');
const { TIMES } = require('../../constants');
const { randomPoints } = require('../../utils');
const { TIMES, COLOURS } = require('../../constants');
const addState = connect(
function receiveState(state) {
@ -30,76 +30,65 @@ function projectile(x, y, radius, colour) {
class Blast extends Component {
constructor(props) {
super();
this.team = props.team;
this.animations = [];
const points = randomPoints(8, 60, { x: 0, y: 0, width: 300, height: 400 });
this.charges = points.map(coord => projectile(coord[0], coord[1], 20, '#00aabb'));
}
render() {
return (
<svg
class={'skill-animation'}
id='blast'
class="skill-animation"
version="1.1"
id="blast"
transform-box='fill-box'
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 300 400">
// {this.charges}
viewBox="0 0 300 300">
<defs>
<radialGradient id="grad1" cx="50%" cy="50%" r="70%" fx="50%" fy="50%">
<stop offset="0%" style="stop-color:rgb(255,255,255);stop-opacity:0.6" />
<stop offset="100%" style={'stop-color:#00aabb;stop-opacity:1'} />
</radialGradient>
<filter id="blastFilter">
<feGaussianBlur in="SourceGraphic" stdDeviation="3" />
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<filter id="explosion">
<feGaussianBlur stdDeviation="4"/>
<feTurbulence type="turbulence" baseFrequency="0.05" numOctaves="3" result="turbulence"/>
<feDisplacementMap in2="turbulence" in="SourceGraphic" scale="1" xChannelSelector="A" yChannelSelector="A"/>
</filter>
{this.charges}
<g>
{times(50, () => (
<g>
<rect filter="url(#blastFilter)" class="blue" x="150" y="200" width="3" height="5" />
<rect filter="url(#blastFilter)" class="white" x="150" y="200" width="1" height="3" />
</g>
))}
</g>
</svg>
);
}
componentDidMount() {
anime.set('#blast', {
translateX: -200 * this.props.direction.x,
translateY: -300 * this.props.direction.y,
});
this.animations.push(anime({
targets: '#blast',
targets: ['#blast'],
opacity: [
{ value: 1, delay: TIMES.TARGET_DELAY_MS, duration: TIMES.TARGET_DURATION_MS * 0.3 },
{ value: 0, delay: TIMES.TARGET_DURATION_MS * 0.7, duration: TIMES.POST_SKILL_DURATION_MS },
{ value: 1, delay: TIMES.TARGET_DELAY_MS, duration: TIMES.TARGET_DURATION_MS * 0.2 },
{ value: 0, delay: TIMES.TARGET_DURATION_MS * 0.5, duration: TIMES.TARGET_DURATION_MS * 0.2 },
],
easing: 'easeInOutSine',
}));
anime.set('#explosion feDisplacementMap', {
scale: 1,
});
this.animations.push(anime({
targets: '#blast',
translateY: 0,
translateX: 0,
loop: false,
targets: ['#blast g'],
transform: () => `
translate(${anime.random(-100, 100)} ${anime.random(-100, 100)})
`,
style: { rotate: anime.random(-180, 180) },
easing: 'easeOutCubic',
delay: TIMES.TARGET_DELAY_MS,
duration: (TIMES.TARGET_DURATION_MS * 1 / 2),
easing: 'easeInQuad',
}));
this.animations.push(anime({
targets: '#explosion feDisplacementMap',
scale: 200,
loop: false,
delay: TIMES.TARGET_DELAY_MS + TIMES.TARGET_DURATION_MS * 1 / 2,
duration: TIMES.TARGET_DURATION_MS * 1 / 2,
easing: 'easeInQuad',
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();

View File

@ -106,7 +106,8 @@ class Break extends Component {
componentWillUnmount() {
for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset();
} this.props.animCb();
}
this.props.animCb();
}
}

View File

@ -144,7 +144,7 @@ function Construct(props) {
if (!s) {
const equipping = specList.includes(vbox.bound[itemEquip]);
const classes = `${equipping ? 'equip-spec' : 'gray'} empty`;
const classes = `${equipping ? 'equipping' : 'gray'} empty`;
return (
<button key={i} class={classes} disabled={!equipping} >
{shapes.None()}

View File

@ -33,7 +33,7 @@ module.exports = {
RedPower: () => circle(['red']),
GreenPower: () => circle(['green']),
BluePower: () => circle(['blue']),
Speed: () => triangle(['white']),
SpeedStat: () => triangle(['white']),
// specs
@ -58,12 +58,11 @@ module.exports = {
<figcaption>Life</figcaption>
</figure>,
// Speed:
// <figure>
// {triangle(['white'])}
// <figcaption>Speed</figcaption>
// </figure>,
Speed: () =>
<figure>
{triangle(['white'])}
<figcaption>Speed</figcaption>
</figure>,
// Lifes Upgrades
LifeGG: () =>

View File

@ -4,9 +4,9 @@ module.exports = function triangle(classes) {
return (
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 200 200" class={classes} transform="rotate(45)" >
<rect x="10" y="10" width="180" height="180"/>
<rect x="40" y="40" width="120" height="120"/>
<rect x="70" y="70" width="60" height="60"/>
<rect x="25" y="25" width="175" height="175"/>
<rect x="55" y="55" width="115" height="115"/>
<rect x="85" y="85" width="55" height="55"/>
</svg>
);
};

View File

@ -63,7 +63,7 @@ const STATS = {
colour: 'blue',
svg: shapes.circle,
},
Speed: {
SpeedStat: {
stat: 'speed',
colour: 'white',
svg: shapes.triangle,