236 lines
6.1 KiB
JavaScript
236 lines
6.1 KiB
JavaScript
|
import React from 'react';
|
||
|
import lodash from 'lodash';
|
||
|
import TimerMixin from 'react-timer-mixin';
|
||
|
import classNames from 'classnames';
|
||
|
import KeyboardShortcutModalActionCreators from '../actions/KeyboardShortcutModalActionCreators';
|
||
|
import {ComponentDispatch} from '../utils/ComponentDispatchUtils';
|
||
|
// import {playSound} from '../utils/SoundUtils';
|
||
|
import {ComponentActions} from '../Constants';
|
||
|
import '../styles/raging_demon.styl';
|
||
|
|
||
|
const Sounds = {
|
||
|
// PRIMARY: () => lodash.delay(playSound, 20, 'raging_demon-primary'),
|
||
|
// SECONDARY: () => lodash.delay(playSound, 40, 'raging_demon-secondary')
|
||
|
PRIMARY: () => true,
|
||
|
SECONDARY: () => true,
|
||
|
};
|
||
|
|
||
|
const Symbol = () =>
|
||
|
<div className="symbol" key="symbol">
|
||
|
<div className="symbol-background" />
|
||
|
<img src={require('../images/raging_demon/symbol.svg')} />
|
||
|
</div>;
|
||
|
|
||
|
const EXPLOSION_DURATION = 1000;
|
||
|
const SECONDARY_DELAY = 120;
|
||
|
const EXPLOSION_OFFSET = 140;
|
||
|
const Explosion = React.createClass({
|
||
|
mixins: [TimerMixin],
|
||
|
|
||
|
getInitialState() {
|
||
|
return {
|
||
|
animating: false,
|
||
|
renderSecondary: false,
|
||
|
scale: lodash.random(0.6, 1, true),
|
||
|
offsetX: lodash.random(0, EXPLOSION_OFFSET, false) - EXPLOSION_OFFSET / 2,
|
||
|
offsetY: lodash.random(0, EXPLOSION_OFFSET, false) - EXPLOSION_OFFSET / 2,
|
||
|
};
|
||
|
},
|
||
|
|
||
|
componentDidMount() {
|
||
|
this.setState({
|
||
|
animating: true,
|
||
|
});
|
||
|
this.setTimeout(() => {
|
||
|
this.setState({
|
||
|
renderSecondary: true,
|
||
|
});
|
||
|
}, SECONDARY_DELAY);
|
||
|
this.setTimeout(this.done, EXPLOSION_DURATION);
|
||
|
Sounds.PRIMARY();
|
||
|
},
|
||
|
|
||
|
componentDidUpdate(prevProps, prevState) {
|
||
|
if (this.state.renderSecondary && !prevState.renderSecondary) {
|
||
|
Sounds.SECONDARY();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
done() {
|
||
|
this.props.onAnimationComplete(this.props.componentId);
|
||
|
},
|
||
|
|
||
|
/* eslint-disable max-len */
|
||
|
renderPrimary() {
|
||
|
return (
|
||
|
<div className="explosion primary" key="primary-explosion">
|
||
|
<img
|
||
|
className="circle-inner"
|
||
|
src={require('../images/raging_demon/red-expl-circle-inner.png')}
|
||
|
width={70}
|
||
|
height={69}
|
||
|
/>
|
||
|
<img
|
||
|
className="circle-outer"
|
||
|
src={require('../images/raging_demon/red-expl-circle-outer.png')}
|
||
|
width={96}
|
||
|
height={95}
|
||
|
/>
|
||
|
<img
|
||
|
className="lines-secondary"
|
||
|
src={require('../images/raging_demon/red-expl-yellow-lines.png')}
|
||
|
width={183}
|
||
|
height={104}
|
||
|
/>
|
||
|
<img
|
||
|
className="lines-main"
|
||
|
src={require('../images/raging_demon/red-expl-red-lines.png')}
|
||
|
width={69}
|
||
|
height={180}
|
||
|
/>
|
||
|
</div>
|
||
|
);
|
||
|
},
|
||
|
|
||
|
renderSecondary(offsetX, offsetY) {
|
||
|
return (
|
||
|
<div
|
||
|
className="explosion secondary"
|
||
|
key="secondary-explosion"
|
||
|
style={{
|
||
|
top: offsetY,
|
||
|
left: offsetX,
|
||
|
}}>
|
||
|
<img
|
||
|
key="circle-inner"
|
||
|
className="circle-inner"
|
||
|
src={require('../images/raging_demon/blue-expl-circle-inner.png')}
|
||
|
width={61}
|
||
|
height={58}
|
||
|
/>
|
||
|
<img
|
||
|
key="circle-outer"
|
||
|
className="circle-outer"
|
||
|
src={require('../images/raging_demon/blue-expl-circle-outer.png')}
|
||
|
width={85}
|
||
|
height={85}
|
||
|
/>
|
||
|
<img
|
||
|
key="lines-secondary"
|
||
|
className="lines-secondary"
|
||
|
src={require('../images/raging_demon/blue-expl-purple-lines.png')}
|
||
|
width={162}
|
||
|
height={173}
|
||
|
/>
|
||
|
<img
|
||
|
key="lines-main"
|
||
|
className="lines-main"
|
||
|
src={require('../images/raging_demon/blue-expl-blue-lines.png')}
|
||
|
width={156}
|
||
|
height={306}
|
||
|
/>
|
||
|
</div>
|
||
|
);
|
||
|
},
|
||
|
/* eslint-enable max-len */
|
||
|
|
||
|
render() {
|
||
|
const {renderSecondary, offsetX, offsetY, animating, scale} = this.state;
|
||
|
const explosions = [this.renderPrimary()];
|
||
|
if (renderSecondary) {
|
||
|
explosions.push(this.renderSecondary(offsetX, offsetY));
|
||
|
}
|
||
|
return (
|
||
|
<div
|
||
|
className={classNames('container', {animate: animating})}
|
||
|
style={{
|
||
|
top: this.props.top,
|
||
|
left: this.props.left,
|
||
|
transform: `scale(${scale})`,
|
||
|
}}>
|
||
|
{explosions}
|
||
|
</div>
|
||
|
);
|
||
|
},
|
||
|
});
|
||
|
|
||
|
const EXPLOSION_TOTAL = 8;
|
||
|
const EXPLOSION_WAIT = SECONDARY_DELAY * 2;
|
||
|
const RagingDemon = React.createClass({
|
||
|
mixins: [TimerMixin],
|
||
|
|
||
|
getInitialState() {
|
||
|
return {
|
||
|
explosions: 0,
|
||
|
};
|
||
|
},
|
||
|
|
||
|
componentWillMount() {
|
||
|
this.children = [];
|
||
|
},
|
||
|
|
||
|
componentDidMount() {
|
||
|
// Wait for modal to animate out
|
||
|
this.setTimeout(() => ComponentDispatch.dispatch(ComponentActions.SHAKE_APP, {duration: 2400}), 1800);
|
||
|
this.setTimeout(this.createExplosion, 1800);
|
||
|
},
|
||
|
|
||
|
removeExplosion(componentId) {
|
||
|
const children = this.children;
|
||
|
const toRemove = children.find(child => child.props.componentId === componentId);
|
||
|
const index = children.indexOf(toRemove);
|
||
|
if (index >= 0) {
|
||
|
children.splice(index, 1);
|
||
|
}
|
||
|
this.forceUpdate();
|
||
|
},
|
||
|
|
||
|
createExplosion() {
|
||
|
const children = this.children;
|
||
|
const xCenter = (window.innerWidth / 2) >> 0;
|
||
|
const yCenter = (window.innerHeight / 2) >> 0;
|
||
|
if (this.state.explosions < EXPLOSION_TOTAL) {
|
||
|
const key = `expl-${this.state.explosions}`;
|
||
|
children.push(
|
||
|
<Explosion
|
||
|
key={key}
|
||
|
componentId={key}
|
||
|
top={lodash.random(yCenter - 100, yCenter + 100, false)}
|
||
|
left={lodash.random(xCenter - 200, xCenter + 200, false)}
|
||
|
onAnimationComplete={this.removeExplosion}
|
||
|
/>
|
||
|
);
|
||
|
this.setTimeout(this.createExplosion, EXPLOSION_WAIT);
|
||
|
this.setState({
|
||
|
explosions: this.state.explosions + 1,
|
||
|
});
|
||
|
} else {
|
||
|
this.setTimeout(this.addSymbol, 750);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
addSymbol() {
|
||
|
this.children = [<Symbol key="symbol" />];
|
||
|
this.forceUpdate();
|
||
|
this.setTimeout(this.delayedClose, 3000);
|
||
|
},
|
||
|
|
||
|
delayedClose() {
|
||
|
KeyboardShortcutModalActionCreators.hide();
|
||
|
},
|
||
|
|
||
|
componentWillUnmount() {
|
||
|
this.children.length = 0;
|
||
|
},
|
||
|
|
||
|
render() {
|
||
|
return <div className="raging-demon">{this.children}</div>;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export default RagingDemon;
|
||
|
|
||
|
|
||
|
|
||
|
// WEBPACK FOOTER //
|
||
|
// ./discord_app/components/RagingDemon.js
|