mnml/client/src/components/instance.constructs.jsx
2019-05-25 15:30:26 +10:00

279 lines
7.9 KiB
JavaScript

const { connect } = require('react-redux');
const preact = require('preact');
const range = require('lodash/range');
const shapes = require('./shapes');
const { SPECS, STATS, instanceConstruct } = require('../utils');
const actions = require('../actions');
const addState = connect(
function receiveState(state) {
const { ws, instance, account, itemInfo, itemEquip, activeConstruct } = state;
const player = instance.players.find(p => p.id === account.id);
function sendInstanceReady() {
return ws.sendInstanceReady(instance.id);
}
function sendVboxApply(constructId, i) {
return ws.sendVboxApply(instance.id, constructId, i);
}
function sendUnequip(constructId, item) {
return ws.sendVboxUnequip(instance.id, constructId, item);
}
return {
instance,
player,
account,
sendInstanceReady,
sendVboxApply,
itemInfo,
itemEquip,
activeConstruct,
sendUnequip,
};
},
function receiveDispatch(dispatch) {
function quit() {
dispatch(actions.setInstance(null));
}
function setInfo(item) {
dispatch(actions.setInfo(item));
}
function setActiveConstruct(value) {
dispatch(actions.setActiveConstruct(value));
}
function clearInfo() {
return dispatch(actions.setInfo(null));
}
function setItemEquip(v) {
return dispatch(actions.setItemEquip(v));
}
function setItemUnequip(v) {
return dispatch(actions.setItemUnequip(v));
}
return { quit, clearInfo, setInfo, setActiveConstruct, setItemUnequip, setItemEquip };
}
);
function Construct(props) {
const {
activeConstruct,
itemEquip,
construct,
player,
sendVboxApply,
setActiveConstruct,
setItemUnequip,
setItemEquip,
itemInfo,
setInfo,
sendUnequip,
} = props;
function onClick(e) {
e.stopPropagation();
e.preventDefault();
if (itemEquip !== null) sendVboxApply(construct.id, itemEquip);
setItemEquip(null);
return setActiveConstruct(construct);
}
function hoverInfo(e, info) {
if (!info) return false;
e.stopPropagation();
return setInfo(info);
}
const { vbox } = player;
const skillList = itemInfo.items.filter(v => v.skill).map(v => v.item);
const specList = itemInfo.items.filter(v => v.spec).map(v => v.item);
const skills = range(0, 3).map(i => {
const skill = construct.skills[i];
const s = skill
? skill.skill
: (<span className="gray">+</span>);
function skillClick(e) {
if (!skill) return false;
setItemUnequip(skill.skill);
setActiveConstruct(construct);
e.stopPropagation();
return true;
}
function skillDblClick(e) {
if (!skill) return false;
sendUnequip(construct.id, skill.skill);
setActiveConstruct(null);
setItemUnequip(null);
e.stopPropagation();
e.preventDefault();
return true;
}
// const action = skill ? '' : 'action';
const equip = skillList.includes(vbox.bound[itemEquip]) && !skill ? 'equipping' : '';
const classes = `${equip}`;
return (
<button
key={i}
disabled={!skill && !itemEquip}
className={classes}
onClick={skillClick}
onDblClick={skillDblClick}
onMouseOver={e => hoverInfo(e, skill && skill.skill)} >
{s}
</button>
);
});
const specs = range(0, 6).map(i => {
const s = construct.specs[i];
if (!s) {
const equip = specList.includes(vbox.bound[itemEquip]) ? 'equip-spec' : 'gray';
return (
<figure key={i} className={equip} >
{shapes.diamond(`stat-icon ${equip}`)}
<figcaption>&nbsp;</figcaption>
</figure>
);
}
function specClick(e) {
e.stopPropagation();
setItemUnequip(s);
setActiveConstruct(construct);
}
function specDblClick(e) {
sendUnequip(construct.id, s);
setActiveConstruct(null);
setItemUnequip(null);
e.stopPropagation();
e.preventDefault();
return true;
}
return (
<figure
key={i}
onClick={specClick}
onDblClick={specDblClick}
onMouseOver={e => hoverInfo(e, s)} >
{SPECS[s].svg(`stat-icon ${SPECS[s].colour}`)}
<figcaption>{SPECS[s].caption}</figcaption>
</figure>
);
});
const stats = Object.values(STATS).map(s => (
<figure key={s.stat} alt={s.stat} className={s.stat}>
{s.svg(`stat-icon ${s.colour} stat`)}
<figcaption>{construct[s.stat].value}</figcaption>
</figure>
));
const activeId = activeConstruct ? activeConstruct.id : false;
const constructClass = activeId === construct.id ? 'instance-construct-active' : 'instance-construct';
// const cTotal = construct.colours.red + construct.colours.blue + construct.colours.green;
// const colours = mapValues(construct.colours, c => {
// if (cTotal === 0) return 245;
// return Math.floor(c / cTotal * 255);
// });
// const alpha = cTotal === 0 ? 1 : 0.75;
// const thickness = total => {
// if (total < 3) return 1;
// if (total < 6) return 2;
// if (total < 9) return 3;
// return 4;
// };
// const border = { border: `${thickness(cTotal)}px solid rgba(${colours.red}, ${colours.green}, ${colours.blue}, ${alpha})` };
return (
<div key={construct.id} className={constructClass} onClick={onClick} >
{instanceConstruct(construct.name, construct.id)}
<h2 className="name" >{construct.name}</h2>
<div className="skills" onMouseOver={e => hoverInfo(e, 'constructSkills')} >
{skills}
</div>
<div className="specs" onMouseOver={e => hoverInfo(e, 'constructSpecs')} >
{specs}
</div>
<div className="stats">
<div className="damage-label label">
Damage
</div>
<div className="speed-label label">
Speed
</div>
<div className="life-label label">
Life
</div>
<div className="icons">
{stats}
</div>
</div>
</div>
);
}
function InstanceConstructs(props) {
const {
activeConstruct,
itemEquip,
player,
instance,
// clearInfo,
setInfo,
setActiveConstruct,
sendVboxApply,
itemInfo,
setVboxHighlight,
setItemUnequip,
setItemEquip,
sendUnequip,
} = props;
if (!player) return false;
if (instance.phase === 'Lobby') return false;
const constructs = player.constructs.map((c, i) => Construct({
construct: c,
activeConstruct,
itemEquip,
setItemUnequip,
setItemEquip,
player,
sendVboxApply,
setInfo,
setActiveConstruct,
itemInfo,
setVboxHighlight,
sendUnequip,
}));
const classes = `construct-list`;
return (
<div className={classes} onClick={() => setActiveConstruct(null)}>
{constructs}
</div>
);
}
module.exports = addState(InstanceConstructs);