mnml/client/src/components/vbox.component.jsx
2019-11-23 17:03:04 +10:00

267 lines
8.6 KiB
JavaScript

const preact = require('preact');
const { connect } = require('preact-redux');
const countBy = require('lodash/countBy');
const forEach = require('lodash/forEach');
const actions = require('../actions');
const InfoContainer = require('./info.container');
const StashElement = require('./vbox.stash');
const StoreElement = require('./vbox.store');
const addState = connect(
function receiveState(state) {
const {
ws,
instance,
player,
vboxSelected,
info,
itemInfo,
itemUnequip,
tutorial,
} = state;
function sendVboxDiscard() {
return ws.sendVboxDiscard(instance.id);
}
function sendVboxAccept(group, index) {
document.activeElement.blur();
return ws.sendVboxAccept(instance.id, group, index);
}
function sendVboxReclaim(i) {
return ws.sendVboxReclaim(instance.id, i);
}
function sendItemUnequip([constructId, item]) {
return ws.sendVboxUnequip(instance.id, constructId, item);
}
return {
instance,
info,
player,
sendVboxAccept,
sendVboxDiscard,
sendVboxReclaim,
vboxSelected,
itemInfo,
itemUnequip,
sendItemUnequip,
tutorial,
};
},
function receiveDispatch(dispatch) {
function setInfo(item) {
return dispatch(actions.setInfo(item));
}
function setVboxSelected(v) {
dispatch(actions.setItemUnequip([]));
dispatch(actions.setVboxSelected(v));
return dispatch(actions.setVboxSelected(v));
}
return {
setInfo,
setVboxSelected,
};
}
);
function validVboxSelect(vbox, itemInfo, storeSelect, stashSelect) {
if (storeSelect.length === 0 && stashSelect.length === 0) return false;
const validSelects = [];
const stashItems = stashSelect.map(j => vbox.bound[j]);
const shopItems = storeSelect.map(j => vbox.free[j[0]][j[1]]);
const selectedItems = stashItems.concat(shopItems);
const itemCount = countBy(selectedItems, co => co);
itemInfo.combos.forEach(combo => {
const comboCount = countBy(combo.components, co => co);
const buyCount = countBy(combo.components, co => co);
const valid = selectedItems.every(c => {
if (!combo.components.includes(c)) return false;
if (itemCount[c] > comboCount[c]) return false;
buyCount[c] -= 1;
return true;
});
if (valid) {
forEach(buyCount, (value, key) => {
if (value > 0 && !validSelects.includes(key)) validSelects.push(key);
});
}
});
return validSelects;
}
class Vbox extends preact.Component {
shouldComponentUpdate(newProps) {
// Single variable props
if (newProps.itemUnequip !== this.props.itemUnequip) return true;
if (newProps.tutorial !== this.props.tutorial) return true;
if (newProps.vboxSelected !== this.props.vboxSelected) return true;
if (newProps.player !== this.props.player) return true;
if (newProps.instance !== this.props.instance) return true;
return false;
}
render(args) {
const {
// Changing state variables
itemUnequip,
player,
tutorial,
vboxSelected,
instance,
// Static
itemInfo,
// Function Calls
sendItemUnequip,
sendVboxAccept,
sendVboxDiscard,
sendVboxReclaim,
setVboxSelected,
setInfo,
} = args;
if (!player) return false;
const { vbox } = player;
const { storeSelect, stashSelect } = vboxSelected;
const vboxSelecting = storeSelect.length === 1 && stashSelect.length === 0;
function combinerChange(newStashSelect) {
return setVboxSelected({ storeSelect, stashSelect: newStashSelect });
}
const vboxHighlight = validVboxSelect(vbox, itemInfo, storeSelect, stashSelect);
//
// VBOX
//
function vboxHover(e, v) {
if (v) {
e.stopPropagation();
if (storeSelect.find(c => c[0])) return true; // There is a base skill or spec selected in the vbox
if (stashSelect.length !== 0) {
const base = stashSelect.find(c => !['Red', 'Blue', 'Green'].includes(vbox.bound[c]));
if (base || base === 0) return true;
}
setInfo(v);
}
return true;
}
function clearVboxSelected() {
setVboxSelected({ storeSelect: [], stashSelect: [] });
}
function vboxBuySelected() {
if (!vboxSelecting) return false;
document.activeElement.blur();
sendVboxAccept(storeSelect[0][0], storeSelect[0][1]);
return true;
}
function storeHdr() {
return (
<div class="store-hdr">
<h3
onTouchStart={e => e.target.scrollIntoView(true)}
onMouseOver={e => vboxHover(e, 'store')}> STORE
</h3>
<div class={`bits ${vbox.bits < 3 ? 'red' : false}`} onMouseOver={e => vboxHover(e, 'bits')}>
<h1> {vbox.bits}b </h1>
</div>
<button
class='vbox-btn'
onMouseOver={e => vboxHover(e, 'refill')}
disabled={vbox.bits < 2
|| (tutorial && tutorial < 7
&& instance.time_control === 'Practice' && instance.rounds.length === 1)
}
onClick={e => e.stopPropagation()}
onMouseDown={() => sendVboxDiscard()}>
refill <br />
2b
</button>
</div>
);
}
function stashHdr() {
const refund = storeSelect.length === 0 && stashSelect.length === 1
? itemInfo.items.find(i => i.item === vbox.bound[stashSelect[0]]).cost
: 0;
const tutorialDisabled = tutorial && tutorial < 8
&& instance.time_control === 'Practice' && instance.rounds.length === 1;
const refundBtn = (
<button
disabled={tutorialDisabled || !refund}
class='vbox-btn'
onClick={e => e.stopPropagation()}
onMouseDown={e => {
e.stopPropagation();
sendVboxReclaim(vboxSelected.stashSelect[0]);
}}>
refund <br />
{refund}b
</button>
);
return (
<div class='stash-hdr'>
<h3 onTouchStart={e => e.target.scrollIntoView(true)}
onMouseOver={e => vboxHover(e, 'stash')}> STASH
</h3>
{refundBtn}
</div>
);
}
// EVERYTHING
return (
<div class='vbox'>
{storeHdr()}
{stashHdr()}
<InfoContainer
vboxHighlight={vboxHighlight}
vboxBuySelected={vboxBuySelected}
/>
<StoreElement
clearVboxSelected = {clearVboxSelected}
setInfo = {setInfo}
setVboxSelected = {setVboxSelected}
storeSelect = {storeSelect}
stashSelect = {stashSelect}
vbox = {vbox}
vboxHighlight = {vboxHighlight}
vboxHover = {vboxHover}
/>
<StashElement
combinerChange = {combinerChange}
itemUnequip = {itemUnequip}
vbox = {vbox}
vboxBuySelected = {vboxBuySelected}
vboxHighlight = {vboxHighlight}
vboxHover = {vboxHover}
vboxSelecting = {vboxSelecting}
stashSelect = {stashSelect}
sendItemUnequip = {sendItemUnequip}
setInfo = {setInfo}
setVboxSelected = {setVboxSelected}
/>
</div>
);
}
}
module.exports = addState(Vbox);