mnml/client/src/components/targeting.arrows.jsx
2019-11-08 09:59:42 +11:00

180 lines
6.6 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, removeTier } = require('../utils');
const addState = connect(
({ game, account, animSkill, animating, itemInfo, gameEffectInfo, tutorialGame }) =>
({ game, account, animSkill, animating, itemInfo, gameEffectInfo, tutorialGame })
);
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.animSkill !== this.props.animSkill) return true;
if (newProps.gameEffectInfo !== this.props.gameEffectInfo) return true;
if (newProps.tutorialGame !== this.props.tutorialGame) 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,
animSkill,
game,
gameEffectInfo,
tutorialGame,
// Static
itemInfo,
} = 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 (tutorialGame) {
return (
<div class="resolving-skill">
<h2>Select your skills, click on targets and then hit <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) {
if (!animSkill) return false;
const itemSource = itemInfo.combos.filter(c => c.item === removeTier(animSkill));
const itemSourceInfo = itemSource.length
? `${itemSource[0].components[0]} ${itemSource[0].components[1]} ${itemSource[0].components[2]}`
: false;
const itemRegEx = /(Red|Blue|Green)/;
const itemSourceDescription = reactStringReplace(itemSourceInfo, itemRegEx, match => shapes[match]());
return (
<div class="resolving-skill">
<h1>{animSkill}</h1>
<div>{itemSourceDescription}</div>
</div>
);
}
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 => playerTeamIds.includes(stack.source_construct_id));
function getPath(cast) {
const source = playerTeam.constructs.findIndex(c => c.id === cast.source_construct_id);
const defensive = playerTeamIds.includes(cast.target_construct_id);
const target = defensive
? playerTeam.constructs.findIndex(c => c.id === cast.target_construct_id)
: otherTeam.constructs.findIndex(c => c.id === cast.target_construct_id);
const sourceY = height;
const sourceX = (source * width / 3) + width / 24;
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);