combat text

This commit is contained in:
ntr 2019-04-13 14:39:24 +10:00
parent 56d1162d79
commit 2e7e9d465d
8 changed files with 262 additions and 108 deletions

View File

@ -596,6 +596,12 @@ header {
filter: blur(5px); filter: blur(5px);
} }
text.combat-text {
fill: whitesmoke;
font-size: 5em;
font-family: 'Jura';
}
.team-player { .team-player {
padding: 0; padding: 0;
} }
@ -654,6 +660,10 @@ CRYP DAMAGE
color: red; color: red;
} }
.red-damage text {
fill: red;
}
.red-damage .stats { .red-damage .stats {
border-top: 3px solid red; border-top: 3px solid red;
} }
@ -670,6 +680,10 @@ CRYP DAMAGE
color: blue; color: blue;
} }
.blue-damage text {
fill: blue;
}
.blue-damage .stats { .blue-damage .stats {
border-top: 3px solid blue; border-top: 3px solid blue;
} }
@ -686,6 +700,10 @@ CRYP DAMAGE
color: green; color: green;
} }
.green-damage text {
fill: green;
}
.green-damage .stats { .green-damage .stats {
border-top: 3px solid green; border-top: 3px solid green;
} }

View File

@ -3,7 +3,9 @@ const range = require('lodash/range');
const molecule = require('./molecule'); const molecule = require('./molecule');
const { STATS, eventClasses } = require('../utils'); const { STATS, eventClasses, getCombatText } = require('../utils');
const GameCryp = require('./game.cryp');
// const SKILL_HOT_KEYS = ['Q', 'W', 'E', 'R']; // const SKILL_HOT_KEYS = ['Q', 'W', 'E', 'R'];
@ -94,95 +96,8 @@ function GamePanel(props) {
); );
} }
function Skill(cryp, i, mobile) {
const ko = cryp.green_life.value === 0 ? 'ko' : '';
const s = cryp.skills[i];
if (!s) {
return (
<button
disabled='true'
key={i}
className='cryp-skill-btn disabled'>
<span>&nbsp;</span>
</button>
);
}
const side = mobile
? 'top'
: 'right';
const cdText = cryp.skills[i].cd > 0
? `- ${s.cd}`
: '';
const highlight = activeSkill
? activeSkill.crypId === cryp.id && activeSkill.skill === s
: false;
function onClick(e) {
e.stopPropagation();
return setActiveSkill(cryp.id, s.skill);
}
return (
<button
key={i}
disabled={!!cdText || ko}
className={`cryp-skill-btn ${side} ${highlight ? 'active' : ''}`}
type="submit"
onClick={onClick}>
{s.skill} {cdText}
</button>
);
}
function Cryp(cryp) {
const ko = cryp.green_life.value === 0 ? 'ko' : '';
const classes = eventClasses(resolution, cryp);
const skills = range(0, 3).map(i => Skill(cryp, i));
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>
));
function onClick(e) {
e.stopPropagation();
return setActiveCryp(cryp);
}
return (
<div
key={cryp.id}
style={ activeSkill ? { cursor: 'pointer' } : {}}
onClick={onClick}
className={`cryp-box ${ko} ${classes}`} >
<div className="cryp-box-top">
<figure
className="img"
onClick={() => selectSkillTarget(cryp.id)} >
{molecule}
<figcaption>{cryp.name}</figcaption>
</figure>
<div className="skills">
{skills}
</div>
</div>
<div className="stats">
{stats}
</div>
</div>
);
}
function PlayerTeam(team) { function PlayerTeam(team) {
const cryps = team.cryps.map(c => Cryp(c)); const cryps = team.cryps.map((c, i) => <GameCryp key={i} cryp={c} />);
return ( return (
<div className="team-player cryp-list"> <div className="team-player cryp-list">
@ -195,8 +110,6 @@ function GamePanel(props) {
const ko = cryp.green_life.value === 0 ? 'ko' : ''; const ko = cryp.green_life.value === 0 ? 'ko' : '';
const classes = eventClasses(resolution, cryp); const classes = eventClasses(resolution, cryp);
console.log(cryp.name, classes);
const stats = [STATS.greenLife, STATS.redLife, STATS.blueLife].map((s, j) => ( const stats = [STATS.greenLife, STATS.redLife, STATS.blueLife].map((s, j) => (
<figure key={j} alt={s.stat}> <figure key={j} alt={s.stat}>
{s.svg(`stat-icon ${s.colour}`)} {s.svg(`stat-icon ${s.colour}`)}
@ -204,6 +117,8 @@ function GamePanel(props) {
</figure> </figure>
)); ));
const combatText = getCombatText(cryp, resolution);
return ( return (
<div <div
key={i} key={i}
@ -212,7 +127,7 @@ function GamePanel(props) {
onClick={() => selectSkillTarget(cryp.id)} > onClick={() => selectSkillTarget(cryp.id)} >
<div className="cryp-box-top"> <div className="cryp-box-top">
<figure className="img"> <figure className="img">
{molecule} {molecule(combatText)}
<figcaption>{cryp.name}</figcaption> <figcaption>{cryp.name}</figcaption>
</figure> </figure>
</div> </div>
@ -241,16 +156,15 @@ function GamePanel(props) {
? resolutionEl(resolution) ? resolutionEl(resolution)
: playerTeam.cryps.map((c, i) => stackElement(c, i)); : playerTeam.cryps.map((c, i) => stackElement(c, i));
const mobileSkills = activeCryp // const mobileSkills = activeCryp
? range(0, 3).map(i => Skill(activeCryp, i, true)) // ? range(0, 3).map(i => Skill(activeCryp, i, true))
: (<div/>); // : (<div/>);
return ( return (
<main className="game" onClick={() => setActiveCryp(null)} > <main className="game" onClick={() => setActiveCryp(null)} >
{header} {header}
{PlayerTeam(playerTeam, setActiveSkill)} {PlayerTeam(playerTeam, setActiveSkill)}
<div className="mobile-skills"> <div className="mobile-skills">
{mobileSkills}
</div> </div>
<div className="selected-skills"> <div className="selected-skills">
{selectedSkills} {selectedSkills}

View File

@ -0,0 +1,150 @@
const { connect } = require('preact-redux');
const preact = require('preact');
const range = require('lodash/range');
const molecule = require('./molecule');
const actions = require('../actions');
const { STATS, eventClasses, getCombatText } = require('../utils');
const addState = connect(
function receiveState(state) {
const {
ws,
game,
resolution,
activeSkill,
activeCryp,
} = state;
function selectSkillTarget(targetCrypId) {
if (activeSkill) {
return ws.sendGameSkill(game.id, activeSkill.crypId, targetCrypId, activeSkill.skill);
}
return false;
}
// intercept self casting skills
if (activeSkill && activeSkill.skill.self_targeting) {
ws.sendGameSkill(game.id, activeSkill.crypId, null, activeSkill.skill.skill);
}
return {
resolution,
activeSkill,
activeCryp,
selectSkillTarget,
};
},
function receiveDispatch(dispatch) {
function setActiveSkill(crypId, skill) {
dispatch(actions.setActiveSkill(crypId, skill));
}
function setActiveCryp(cryp) {
dispatch(actions.setActiveCryp(cryp));
}
return { setActiveSkill, setActiveCryp };
}
);
function GameCryp(props) {
const {
cryp,
resolution,
activeSkill,
setActiveSkill,
setActiveCryp,
selectSkillTarget,
} = props;
const ko = cryp.green_life.value === 0 ? 'ko' : '';
function Skill(i, mobile) {
const s = cryp.skills[i];
if (!s) {
return (
<button
disabled='true'
key={i}
className='cryp-skill-btn disabled'>
<span>&nbsp;</span>
</button>
);
}
const side = mobile
? 'top'
: 'right';
const cdText = cryp.skills[i].cd > 0
? `- ${s.cd}`
: '';
const highlight = activeSkill
? activeSkill.crypId === cryp.id && activeSkill.skill === s
: false;
function onClick(e) {
e.stopPropagation();
return setActiveSkill(cryp.id, s.skill);
}
return (
<button
key={i}
disabled={!!cdText || ko}
className={`cryp-skill-btn ${side} ${highlight ? 'active' : ''}`}
type="submit"
onClick={onClick}>
{s.skill} {cdText}
</button>
);
}
const classes = eventClasses(resolution, cryp);
const skills = range(0, 3).map(i => Skill(i));
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>
));
function onClick(e) {
e.stopPropagation();
return setActiveCryp(cryp);
}
const combatText = getCombatText(cryp, resolution);
return (
<div
style={ activeSkill ? { cursor: 'pointer' } : {}}
onClick={onClick}
className={`cryp-box ${ko} ${classes}`} >
<div className="cryp-box-top">
<figure
className="img"
onClick={() => selectSkillTarget(cryp.id)} >
{molecule(combatText)}
<figcaption>{cryp.name}</figcaption>
</figure>
<div className="skills">
{skills}
</div>
</div>
<div className="stats">
{stats}
</div>
</div>
);
}
module.exports = addState(GameCryp);

View File

@ -92,7 +92,7 @@ function Cryp(props) {
> >
<div className="cryp-box-top"> <div className="cryp-box-top">
<figure className="img" onClick={onClick}> <figure className="img" onClick={onClick}>
{molecule} {molecule()}
<figcaption>{cryp.name}</figcaption> <figcaption>{cryp.name}</figcaption>
</figure> </figure>
<div className="skills"> <div className="skills">

View File

@ -109,7 +109,7 @@ function Menu(args) {
style={ { 'border-color': borderColour || 'whitesmoke' } } style={ { 'border-color': borderColour || 'whitesmoke' } }
onClick={() => selectCryp(cryp.id)} > onClick={() => selectCryp(cryp.id)} >
<figure className="img"> <figure className="img">
{molecule} {molecule()}
</figure> </figure>
<h2>{cryp.name}</h2> <h2>{cryp.name}</h2>
</div> </div>

File diff suppressed because one or more lines are too long

View File

@ -23,7 +23,7 @@ function registerEvents(store) {
if (game.resolved.length !== currentGame.resolved.length) { if (game.resolved.length !== currentGame.resolved.length) {
const newRes = game.resolved.slice(currentGame.resolved.length); const newRes = game.resolved.slice(currentGame.resolved.length);
return eachSeries(newRes, (r, cb) => { return eachSeries(newRes, (r, cb) => {
if (r.event[0] === 'Disable') return cb(); if (['Disable', 'TargetKo'].includes(r.event[0])) return cb();
store.dispatch(actions.setResolution(r)); store.dispatch(actions.setResolution(r));
return setTimeout(cb, TIMES.RESOLUTION_TIME_MS); return setTimeout(cb, TIMES.RESOLUTION_TIME_MS);
}, err => { }, err => {

View File

@ -81,13 +81,13 @@ const SPECS = {
GBDI: { colour: 'cyan', caption: 'DamageI', svg: shapes.circle }, GBDI: { colour: 'cyan', caption: 'DamageI', svg: shapes.circle },
RBDI: { colour: 'purple', caption: 'DamageI', svg: shapes.circle }, RBDI: { colour: 'purple', caption: 'DamageI', svg: shapes.circle },
Speed: { colour: 'white', caption: 'Speed', svg: shapes.diamond }, Speed: { colour: 'white', caption: 'Speed', svg: shapes.triangle },
RedSpeed: { colour: 'red', caption: 'Speed', svg: shapes.diamond }, RedSpeed: { colour: 'red', caption: 'Speed', svg: shapes.triangle },
BlueSpeedI: { colour: 'blue', caption: 'Speed', svg: shapes.diamond }, BlueSpeedI: { colour: 'blue', caption: 'Speed', svg: shapes.triangle },
GreenSpeedI: { colour: 'green', caption: 'Speed', svg: shapes.diamond }, GreenSpeedI: { colour: 'green', caption: 'Speed', svg: shapes.triangle },
GRSpeedI: { colour: 'yellow', caption: 'Speed', svg: shapes.diamond }, GRSpeedI: { colour: 'yellow', caption: 'Speed', svg: shapes.triangle },
GBSpeedI: { colour: 'cyan', caption: 'Speed', svg: shapes.diamond }, GBSpeedI: { colour: 'cyan', caption: 'Speed', svg: shapes.triangle },
RBSpeedI: { colour: 'purple', caption: 'Speed', svg: shapes.diamond }, RBSpeedI: { colour: 'purple', caption: 'Speed', svg: shapes.triangle },
}; };
@ -163,12 +163,70 @@ function eventClasses(resolution, cryp) {
return ''; return '';
} }
function getCombatText(cryp, resolution) {
if (!resolution) return '';
if (cryp.id !== resolution.target.id) return '';
const [type, event] = resolution.event;
if (type === 'Ko') {
return 'KO!';
}
if (type === 'Disable') {
const { skill, disable } = event;
}
if (type === 'Immunity') {
const { skill, immunity } = event;
return 'IMMUNE';
}
if (type === 'TargetKo') {
const { skill } = event;
}
if (type === 'Damage') {
const { skill, amount, mitigation, colour } = event;
return amount;
}
if (type === 'Healing') {
const { skill, amount, overhealing } = event;
return `${amount} (${overhealing}OH)`;
}
if (type === 'Inversion') {
const { skill } = event;
return 'INVERT';
}
if (type === 'Reflection') {
const { skill } = event;
return 'REFLECT';
}
if (type === 'Effect') {
const { skill, effect, duration } = event;
return `+ ${effect} ${duration}T`;
}
if (type === 'Removal') {
const { effect } = event;
return `- ${effect}`;
}
return '';
}
module.exports = { module.exports = {
stringSort, stringSort,
numSort, numSort,
genAvatar, genAvatar,
requestAvatar, requestAvatar,
eventClasses, eventClasses,
getCombatText,
NULL_UUID, NULL_UUID,
STATS, STATS,
SPECS, SPECS,