164 lines
5.9 KiB
JavaScript
164 lines
5.9 KiB
JavaScript
const preact = require('preact');
|
|
const { Component } = require('preact');
|
|
const { connect } = require('preact-redux');
|
|
// const anime = require('animejs').default;
|
|
const reactStringReplace = require('react-string-replace');
|
|
const throttle = require('lodash/throttle');
|
|
|
|
const shapes = require('./shapes');
|
|
const { effectInfo } = require('../utils');
|
|
|
|
const addState = connect(
|
|
({ game, account, animating, itemInfo, gameEffectInfo, authenticated }) =>
|
|
({ game, account, animating, itemInfo, gameEffectInfo, authenticated })
|
|
);
|
|
|
|
class TargetSvg extends Component {
|
|
constructor() {
|
|
super();
|
|
this.state = { width: 3000, height: 1000 };
|
|
|
|
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');
|
|
this.setState({ width, height });
|
|
}, 500);
|
|
}
|
|
|
|
shouldComponentUpdate(newProps, newState) {
|
|
if (newProps.game !== this.props.game) return true;
|
|
if (newProps.account !== this.props.account) return true;
|
|
if (newProps.animating !== this.props.animating) return true;
|
|
if (newProps.gameEffectInfo !== this.props.gameEffectInfo) return true;
|
|
if (newState.width !== this.state.width) return true;
|
|
if (newState.height !== this.state.height) return true;
|
|
return false;
|
|
}
|
|
|
|
render(props, state) {
|
|
const {
|
|
// Changing State Variables
|
|
account,
|
|
animating,
|
|
game,
|
|
gameEffectInfo,
|
|
authenticated,
|
|
} = props;
|
|
const { width, height } = state;
|
|
|
|
if (!game) return false; // game will be null when battle ends
|
|
if (game.phase === 'Finished') return false; // Clear everything if its over (in case of abandon)
|
|
|
|
// First time joining game phase
|
|
if (!authenticated && game.stack.length === 0) {
|
|
return (
|
|
<div class="resolving-skill">
|
|
<h2><b>Select a skill</b> from each construct, <b>click a target</b> for that skill and then click <b>READY</b>.</h2>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Whenever someones looking at effects throw it up here
|
|
if (gameEffectInfo) {
|
|
const regEx = /(RedPower|BluePower|GreenPower|RedLife|BlueLife|GreenLife|SpeedStat)/;
|
|
const infoString = effectInfo(gameEffectInfo);
|
|
const infoDescription = reactStringReplace(infoString, regEx, match => shapes[match]());
|
|
|
|
return (
|
|
<div class="resolving-skill">
|
|
<h1>{gameEffectInfo.effect}</h1>
|
|
<div>{infoDescription}</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// resolutions happening
|
|
// just put skill name up
|
|
if (animating) return false;
|
|
|
|
const playerTeam = game.players.find(t => t.id === account.id);
|
|
const otherTeam = game.players.find(t => t.id !== account.id);
|
|
|
|
const playerTeamIds = playerTeam.constructs.map(c => c.id);
|
|
const outgoing = game.stack.filter(stack => stack.player === account.id);
|
|
|
|
function getPath(cast) {
|
|
const source = playerTeam.constructs.findIndex(c => c.id === cast.source);
|
|
const defensive = playerTeamIds.includes(cast.target);
|
|
const target = defensive
|
|
? playerTeam.constructs.findIndex(c => c.id === cast.target)
|
|
: otherTeam.constructs.findIndex(c => c.id === cast.target);
|
|
|
|
const skillNumber = window.innerWidth <= 800 // mobile styling trigger
|
|
? playerTeam.constructs[source].skills.findIndex(s => s.skill === cast.skill)
|
|
: 0;
|
|
const sourceY = height;
|
|
const sourceX = (source * width / 3) + width / 18 + skillNumber * (width / 9);
|
|
const targetX = (target * width / 3) + width / 6
|
|
+ (defensive ? width / 64 : 0)
|
|
+ (source * width / 18);
|
|
const targetY = defensive ? height : 0;
|
|
const bendStart = height * (0.7 - 0.1 * source);
|
|
const bendEnd = height * 0.20;
|
|
|
|
if (defensive) {
|
|
const path = `
|
|
M${sourceX},${sourceY}
|
|
L${sourceX},${bendStart}
|
|
L${targetX},${bendStart}
|
|
L${targetX},${targetY}
|
|
L${targetX - (width * 0.005)},${height * 0.875}
|
|
M${targetX},${targetY}
|
|
L${targetX + (width * 0.005)},${height * 0.875}
|
|
`;
|
|
|
|
return <path d={path} />;
|
|
}
|
|
|
|
const path = `
|
|
M${sourceX},${sourceY}
|
|
L${sourceX},${bendStart}
|
|
L${targetX},${bendEnd}
|
|
L${targetX},${targetY}
|
|
L${targetX - (width * 0.005)},${height * 0.125}
|
|
M${targetX},${targetY}
|
|
L${targetX + (width * 0.005)},${height * 0.125}
|
|
|
|
`;
|
|
|
|
return <path d={path} />;
|
|
}
|
|
|
|
return (
|
|
<svg id="targeting"
|
|
viewBox={`0 0 ${width} ${height}`}
|
|
preserveAspectRatio="none"
|
|
class="targeting-arrows">
|
|
{outgoing.map(getPath)}
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
componentDidMount() {
|
|
window.addEventListener('resize', this.onResize);
|
|
this.onResize();
|
|
setTimeout(this.onResize, 50);
|
|
// anime({
|
|
// targets: ['#targeting path'],
|
|
// strokeDashoffset: [anime.setDashoffset, 0],
|
|
// duration: 1000,
|
|
// easing: 'linear',
|
|
// loop: true,
|
|
// delay: anime.stagger(3000),
|
|
// });
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
window.removeEventListener('resize', this.onResize);
|
|
}
|
|
}
|
|
|
|
module.exports = addState(TargetSvg);
|