202 lines
5.9 KiB
JavaScript
202 lines
5.9 KiB
JavaScript
const preact = require('preact');
|
|
const { STATS, eventClasses, getCombatText, crypAvatar } = require('../utils');
|
|
const { animationDivs } = require('../animations');
|
|
const GameCryp = require('./game.cryp');
|
|
|
|
function GamePanel(props) {
|
|
const {
|
|
game,
|
|
account,
|
|
resolution,
|
|
activeSkill,
|
|
setActiveSkill,
|
|
setActiveCryp,
|
|
selectSkillTarget,
|
|
sendInstanceState,
|
|
sendGameReady,
|
|
showLog,
|
|
toggleLog,
|
|
skip,
|
|
quit,
|
|
} = props;
|
|
|
|
if (!game) return <div>...</div>;
|
|
|
|
// if (showLog) {
|
|
// const logs = game.log.map((l, i) => (<div key={i}>{l}</div>)).reverse();
|
|
// return (
|
|
// <main className="game">
|
|
// <div className="instance-hdr">
|
|
// <button
|
|
// className="game-btn instance-btn instance-ui-btn left"
|
|
// onClick={() => toggleLog(!showLog)}>
|
|
// Game
|
|
// </button>
|
|
// <div className="spacer">
|
|
// <div> </div>
|
|
// </div>
|
|
// </div>
|
|
// <div className="logs">
|
|
// {logs}
|
|
// </div>
|
|
// </main>
|
|
// );
|
|
// }
|
|
|
|
function actionClick() {
|
|
if (game.phase === 'Finish') {
|
|
sendInstanceState(game.instance);
|
|
quit();
|
|
return true;
|
|
}
|
|
|
|
if (resolution) {
|
|
return skip();
|
|
}
|
|
|
|
return sendGameReady();
|
|
}
|
|
|
|
const otherTeams = game.players.filter(t => t.id !== account.id);
|
|
const playerTeam = game.players.find(t => t.id === account.id);
|
|
|
|
let actionText = 'Ready';
|
|
let actionStyles = 'instance-btn instance-ui-btn right';
|
|
if (game.phase === 'Finish') actionText = 'Done';
|
|
if (resolution) actionText = 'Skip';
|
|
if (actionText === 'Ready' && playerTeam.ready) actionStyles += ' ready';
|
|
|
|
const header = (
|
|
<div className="top">
|
|
<button
|
|
className={actionStyles}
|
|
onClick={() => actionClick()}>
|
|
{actionText}
|
|
</button>
|
|
</div>
|
|
);
|
|
|
|
function findCryp(id) {
|
|
const team = game.players.find(t => t.cryps.find(c => c.id === id));
|
|
if (team) return team.cryps.find(c => c.id === id);
|
|
return null;
|
|
}
|
|
|
|
|
|
const zero = Date.parse(game.phase_end) - (1000 * 60);
|
|
const now = Date.now();
|
|
const end = Date.parse(game.phase_end);
|
|
const timerPct = ((now - zero) / (end - zero) * 100);
|
|
const displayPct = resolution || game.phase === 'Finish'
|
|
? 0
|
|
: Math.min(timerPct, 100);
|
|
|
|
const displayColour = playerTeam.ready
|
|
? 'forestgreen'
|
|
: timerPct > 80
|
|
? 'red'
|
|
: 'whitesmoke';
|
|
|
|
const timerStyles = {
|
|
width: `${displayPct}%`,
|
|
background: displayColour,
|
|
};
|
|
|
|
const timer = (
|
|
<div className="timer-container">
|
|
<div className="timer" style={timerStyles} > </div>
|
|
</div>
|
|
);
|
|
|
|
function PlayerTeam(team) {
|
|
const cryps = team.cryps.map((c, i) => <GameCryp key={c.id} cryp={c} />);
|
|
|
|
return (
|
|
<div className="team player">
|
|
{cryps}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function OpponentCryp(cryp, i) {
|
|
const ko = cryp.green_life.value === 0 ? 'ko' : '';
|
|
const classes = eventClasses(resolution, cryp);
|
|
|
|
const stats = [STATS.greenLife, STATS.redLife, STATS.blueLife].map((s, j) => (
|
|
<figure key={j} alt={s.stat}>
|
|
{s.svg(`stat-icon ${s.colour}`)}
|
|
<figcaption>{cryp[s.stat].value} / {cryp[s.stat].max}</figcaption>
|
|
</figure>
|
|
));
|
|
|
|
const [combatText, combatClass] = getCombatText(cryp, resolution);
|
|
const combatTextClass = `combat-text ${combatClass}`;
|
|
const combatTextEl = combatText
|
|
? <div className={combatTextClass}>{combatText}</div>
|
|
: null;
|
|
|
|
const effects = cryp.effects.length
|
|
? cryp.effects.map(c => <div key={c.effect}>{c.effect} - {c.duration}T</div>)
|
|
: <div> </div>;
|
|
|
|
const playerTeamIds = playerTeam.cryps.map(c => c.id);
|
|
const targeting = game.stack
|
|
.filter(s => playerTeamIds.includes(s.source_cryp_id) && s.target_cryp_id === cryp.id)
|
|
.map((s, i) => <h3 key={i}>{`< ${s.skill}`}</h3>);
|
|
|
|
const anim = (
|
|
<div className="anim-container">
|
|
{animationDivs(combatClass)}
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div
|
|
key={i}
|
|
className={`game-cryp ${ko} ${classes}`}
|
|
style={ activeSkill ? { cursor: 'pointer' } : {}}
|
|
onClick={() => selectSkillTarget(cryp.id)} >
|
|
<div className="stats">{stats}</div>
|
|
<h3 className="name" >{cryp.name}</h3>
|
|
<div className="effects">{effects}</div>
|
|
<div className="targeting">{targeting}</div>
|
|
<figure
|
|
className="img"
|
|
onClick={() => selectSkillTarget(cryp.id)} >
|
|
{crypAvatar(cryp.name)}
|
|
{combatTextEl}
|
|
{anim}
|
|
</figure>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
|
|
function OpponentTeam(team) {
|
|
const cryps = team.cryps.map(OpponentCryp);
|
|
return (
|
|
<div className="team opponent">
|
|
{cryps}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const gameClasses = `game ${resolution ? 'resolving': ''}`;
|
|
|
|
function gameClick(e) {
|
|
e.stopPropagation();
|
|
setActiveCryp(null);
|
|
}
|
|
|
|
return (
|
|
<main className={gameClasses} onClick={gameClick} >
|
|
{header}
|
|
{timer}
|
|
{otherTeams.map(OpponentTeam)}
|
|
{PlayerTeam(playerTeam, setActiveSkill)}
|
|
</main>
|
|
);
|
|
}
|
|
|
|
module.exports = GamePanel;
|