mnml/client/src/components/vbox.component.jsx

405 lines
11 KiB
JavaScript

const preact = require('preact');
const range = require('lodash/range');
const without = require('lodash/without');
const { connect } = require('preact-redux');
const shapes = require('./shapes');
const actions = require('../actions');
const addState = connect(
function receiveState(state) {
const {
ws,
instance,
player,
combiner,
reclaiming,
vboxHighlight,
vboxSelected,
itemInfo,
itemUnequip,
} = state;
function sendVboxDiscard() {
return ws.sendVboxDiscard(instance.id);
}
function sendVboxAccept(group, index) {
return ws.sendVboxAccept(instance.id, group, index);
}
function sendVboxCombine() {
return ws.sendVboxCombine(instance.id, combiner);
}
function sendVboxReclaim(i) {
return ws.sendVboxReclaim(instance.id, i);
}
function sendItemUnequip([constructId, item]) {
return ws.sendVboxUnequip(instance.id, constructId, item);
}
return {
combiner,
instance,
player,
reclaiming,
sendVboxAccept,
sendVboxCombine,
sendVboxDiscard,
sendVboxReclaim,
vboxHighlight,
vboxSelected,
itemInfo,
itemUnequip,
sendItemUnequip
};
},
function receiveDispatch(dispatch) {
function setCombiner(c) {
return dispatch(actions.setCombiner(c));
}
function setReclaiming(v) {
return dispatch(actions.setReclaiming(v));
}
function setInfo(item) {
return dispatch(actions.setInfo(item));
}
function setVboxHighlight(v) {
return dispatch(actions.setVboxHighlight(v));
}
function setVboxSelected(v) {
return dispatch(actions.setVboxSelected(v));
}
function setItemEquip(v) {
return dispatch(actions.setItemEquip(v));
}
return {
setCombiner,
setReclaiming,
setInfo,
setVboxHighlight,
setVboxSelected,
setItemEquip,
};
}
);
function Vbox(args) {
const {
combiner,
// instance,
itemInfo,
player,
reclaiming,
sendVboxAccept,
sendVboxCombine,
sendVboxDiscard,
sendVboxReclaim,
// vboxHighlight,
setCombiner,
setInfo,
vboxSelected,
setVboxSelected,
setItemEquip,
itemUnequip,
sendItemUnequip,
setReclaiming,
setVboxHighlight,
} = args;
if (!player) return false;
const { vbox } = player;
const vboxSelecting = vboxSelected.length;
// function setHighlight(type) {
// if (type === 'skill') return setVboxHighlight(itemInfo.items.filter(v => v.skill).map(v => v.item));
// if (type === 'spec') return setVboxHighlight(itemInfo.items.filter(v => v.spec).map(v => v.item));
// return false;
// }
function combinerChange(newCombiner) {
setCombiner(newCombiner);
if (newCombiner.length === 1) {
setItemEquip(newCombiner[0]);
} else {
setItemEquip(null);
}
if (newCombiner.every(c => c === null)) return setVboxHighlight([]);
const combinerValues = newCombiner.map(cv => player.vbox.bound[cv]).filter(cv => cv);
const filteredCombos = itemInfo.combos
.filter(combo => combinerValues.every(u => combo.components.includes(u)));
const comboValues = itemInfo.items.filter(v => {
if (!filteredCombos.some(c => c.components.includes(v.item))) return false;
if (!['Red', 'Green', 'Blue'].includes(v.item) && combinerValues.includes(v.item)) return false;
return true;
});
return setVboxHighlight(comboValues.map(v => v.item));
}
//
// VBOX
//
function vboxHover(e, v) {
if (v) {
setInfo(v);
e.stopPropagation();
}
return true;
}
function clearVboxSelected() {
setVboxSelected([]);
}
function vboxBuySelected() {
if (!vboxSelecting) return false;
document.activeElement.blur();
clearVboxSelected();
sendVboxAccept(vboxSelected[0], vboxSelected[1]);
return true;
}
function availableBtn(v, group, index) {
if (!v) return <button disabled class='empty' >&nbsp;</button>;
const selected = vboxSelected[0] === group && vboxSelected[1] === index;
// state not yet set in double click handler
function onDblClick(e) {
sendVboxAccept(group, index);
e.stopPropagation();
}
function onClick(e) {
e.stopPropagation();
if (selected) return clearVboxSelected();
return setVboxSelected([group, index]);
}
const classes = `${selected ? 'highlight' : ''}`;
if (shapes[v]) {
return (
<button
class={classes}
onMouseOver={e => vboxHover(e, v)}
onMouseDown={onClick}
onDblClick={onDblClick} >
{shapes[v]()}
</button>
);
}
return (
<button
class={classes}
onMouseDown={onClick}
onDblClick={onDblClick}
onMouseOver={e => vboxHover(e, v)}>
{v}
</button>
);
}
function vboxElement() {
return (
<div class='vbox-vbox'
onMouseDown={() => setReclaiming(false)}
onMouseOver={e => hoverInfo(e, 'vbox')}>
<div class="vbox-hdr">
<h3 onTouchStart={e => e.target.scrollIntoView(true)}>VBOX</h3>
<div class="bits" onMouseOver={e => hoverInfo(e, 'bits')} >{vbox.bits}b</div>
</div>
<div class="vbox-colours">
{range(0, 6).map(i => availableBtn(vbox.free[0][i], 0, i))}
</div>
<div class="vbox-items">
{range(0, 3).map(i => availableBtn(vbox.free[1][i], 1, i))}
{range(0, 3).map(i => availableBtn(vbox.free[2][i], 2, i))}
</div>
<button
class='vbox-btn'
onMouseOver={e => hoverInfo(e, 'refill')}
onMouseDown={() => sendVboxDiscard()}>
refill - 2b
</button>
</div>
);
}
//
// INVENTORY
//
// const boundTds = range(0, 9).map(i => {
// const value = vbox.bound[i];
// if (combiner.indexOf(i) > -1) {
// return (
// <td
// key={i}>
// &nbsp;
// </td>
// );
// }
// const highlighted = value && vboxHighlight.includes(value);
// return (
// <td
// key={i}
// class={`${highlighted ? 'highlight' : ''}`}
// onMouseOver={(e) => vboxHover(e, value)}
// onMouseDown={e => boundClick(e, i, highlighted) }>
// {convertItem(value)}
// </td>
// );
// });
function reclaimClick(e) {
e.stopPropagation();
return setReclaiming(!reclaiming);
}
const inventoryClass = `vbox-section ${reclaiming ? 'reclaiming' : ''}`;
function inventoryBtn(v, i) {
const inventoryHighlight = vboxSelecting || itemUnequip.length;
if (!v && v !== 0) {
return <button disabled={!inventoryHighlight} class={inventoryHighlight ? 'receiving' : 'empty'} >&nbsp;</button>;
}
function onClick(e) {
if (reclaiming) return sendVboxReclaim(i);
const combinerIndex = combiner.indexOf(i);
if (combinerIndex > -1) {
return combinerChange(without(combiner, i));
}
combiner.push(i);
return combinerChange(combiner);
}
const highlighted = combiner.indexOf(i) > -1;
const classes = `${highlighted ? 'highlight' : ''}`;
if (shapes[v]) {
return (
<button
class={classes}
onMouseOver={e => vboxHover(e, v)}
onMouseDown={onClick}>
{shapes[v]()}
</button>
);
}
return (
<button
class={classes}
onMouseDown={onClick}
onMouseOver={e => vboxHover(e, v)}>
{v}
</button>
);
}
function combinerBtn() {
let text = '';
if (combiner.length < 3) {
for (let i = 0; i < 3; i++) {
if (combiner.length > i) {
text += '■ ';
} else {
text += '▫ ';
}
}
} else {
text = 'combine';
}
return (
<button
class='vbox-btn'
disabled={combiner.length !== 3}
onMouseOver={e => hoverInfo(e, 'refine')}
onMouseDown={() => sendVboxCombine()}>
{text}
</button>
);
}
function inventoryElement() {
function inventoryClick(e) {
e.stopPropagation();
setReclaiming(false);
if (vboxSelecting) return vboxBuySelected();
if (itemUnequip.length) return sendItemUnequip(itemUnequip);
return true;
}
return (
<div class={inventoryClass}
onMouseDown={inventoryClick}
style={vboxSelecting || itemUnequip.length ? { cursor: 'pointer' } : null}
onMouseOver={e => hoverInfo(e, 'inventory')}>
<div class="vbox-hdr">
<h3 onTouchStart={e => e.target.scrollIntoView(true)}>INVENTORY</h3>
<button
class='vbox-btn reclaim'
onMouseOver={e => hoverInfo(e, 'reclaim')}
onMouseDown={reclaimClick}>
reclaim
</button>
</div>
<div class='vbox-items'>
{range(0, 9).map(i => inventoryBtn(vbox.bound[i], i))}
</div>
{combinerBtn()}
</div>
);
}
//
// EVERYTHING
//
function hoverInfo(e, info) {
e.stopPropagation();
return setInfo(info);
}
const classes = 'vbox';
return (
<div class={classes}>
{vboxElement()}
<div class="vbox-arrow"></div>
{inventoryElement()}
</div>
);
}
module.exports = addState(Vbox);