const preact = require('preact'); const { connect } = require('preact-redux'); const range = require('lodash/range'); const countBy = require('lodash/countBy'); const without = require('lodash/without'); const forEach = require('lodash/forEach'); const { removeTier } = require('../utils'); const shapes = require('./shapes'); const actions = require('../actions'); const buttons = require('./buttons'); const addState = connect( function receiveState(state) { const { ws, instance, player, vboxSelected, 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 sendVboxCombine() { return ws.sendVboxCombine(instance.id, vboxSelected.stashSelect, vboxSelected.shopSelect); } function sendVboxReclaim(i) { return ws.sendVboxReclaim(instance.id, i); } function sendItemUnequip([constructId, item]) { return ws.sendVboxUnequip(instance.id, constructId, item); } return { instance, player, sendVboxAccept, sendVboxCombine, 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, shopSelect, stashSelect) { if (shopSelect.length === 0 && stashSelect.length === 0) return false; const validSelects = []; const stashItems = stashSelect.map(j => vbox.bound[j]); const shopItems = shopSelect.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] -= itemCount[c]; 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, sendVboxCombine, sendVboxDiscard, sendVboxReclaim, setVboxSelected, setInfo, } = args; if (!player) return false; const { vbox } = player; const { shopSelect, stashSelect } = vboxSelected; const vboxSelecting = shopSelect.length === 1 && stashSelect.length === 0; function combinerChange(newStashSelect) { return setVboxSelected({ shopSelect, stashSelect: newStashSelect }); } const vboxHighlight = validVboxSelect(vbox, itemInfo, shopSelect, stashSelect); // // VBOX // function vboxHover(e, v) { if (v) { e.stopPropagation(); if (shopSelect.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({ shopSelect: [], stashSelect: [] }); } function vboxBuySelected() { if (!vboxSelecting) return false; document.activeElement.blur(); sendVboxAccept(shopSelect[0][0], shopSelect[0][1]); return true; } function availableBtn(v, group, index) { if (!v) return ; const selected = shopSelect.length && shopSelect.some(vs => vs[0] === group && vs[1] === index); const comboHighlight = vboxHighlight && vboxHighlight.includes(v) ? 'combo-border' : ''; function onClick(e) { e.stopPropagation(); if (!comboHighlight) setInfo(vbox.free[group][index]); if (shopSelect.length && shopSelect.some(vs => vs[0] === group && vs[1] === index)) { return setVboxSelected({ shopSelect: shopSelect.filter(vs => !(vs[0] === group && vs[1] === index)), stashSelect }); } if (!shopSelect.length && !stashSelect.length) return setVboxSelected({ shopSelect: [[group, index]], stashSelect }); if (comboHighlight !== 'combo-border') { return setVboxSelected({ shopSelect: [[group, index]], stashSelect: [] }); } return setVboxSelected({ shopSelect: [...shopSelect, [group, index]], stashSelect }); } const classes = `${v.toLowerCase()} ${selected ? 'highlight' : ''} ${comboHighlight}`; const vboxObject = shapes[v] ? shapes[v]() : v; const disabled = vbox.bits <= group; return ( ); } function vboxElement() { return (
e.stopPropagation()}>
{range(0, 6).map(i => availableBtn(vbox.free[0][i], 0, i))}
{range(0, 3).map(i => availableBtn(vbox.free[1][i], 1, i))} {range(0, 3).map(i => availableBtn(vbox.free[2][i], 2, i))}
); } function vboxHdr() { return (

e.target.scrollIntoView(true)} onMouseOver={e => hoverInfo(e, 'vbox')}> STORE

hoverInfo(e, 'bits')}>

{vbox.bits}b

); } // // INVENTORY // function inventoryBtn(v, i) { const inventoryHighlight = vboxSelecting || itemUnequip.length; if (!v && v !== 0) { const emptyInvClick = () => { if (vboxSelecting) return vboxBuySelected(); return false; }; return ; } const comboHighlight = vboxHighlight && vboxHighlight.includes(v) ? 'combo-border' : ''; function onClick(type) { const combinerContainsIndex = stashSelect.indexOf(i) > -1; // removing if (combinerContainsIndex) { if (type === 'click') { return combinerChange(without(stashSelect, i)); } return true; } if (!comboHighlight) { setInfo(vbox.bound[i]); return setVboxSelected({ shopSelect: [], stashSelect: [i] }); } stashSelect.push(i); // if (stashSelect.length === 3) setInfo(comboItem.item); return combinerChange(stashSelect); } const highlighted = stashSelect.indexOf(i) > -1; const border = buttons[removeTier(v)] ? buttons[removeTier(v)]() : ''; const classes = `${highlighted ? 'highlight' : border} ${comboHighlight}`; const invObject = shapes[v] ? shapes[v]() : v; return ( ); } function combinerBtn() { let text = ''; let mouseEvent = false; const combineLength = stashSelect.length + shopSelect.length; if (vboxHighlight && vboxHighlight.length === 0) { // The selected items can't be combined with additional items therefore valid combo const stashItems = stashSelect.map(j => vbox.bound[j]); const shopItems = shopSelect.map(j => vbox.free[j[0]][j[1]]); const selectedItems = stashItems.concat(shopItems); const combinerCount = countBy(selectedItems, co => co); const comboItemObj = itemInfo.combos.find(combo => selectedItems.every(c => { if (!combo.components.includes(c)) return false; const comboCount = countBy(combo.components, co => co); if (combinerCount[c] > comboCount[c]) return false; return true; })); let comboItem = comboItemObj ? comboItemObj.item : 'refine'; setInfo(comboItem); comboItem = comboItem.replace('Plus', '+'); let bits = 0; shopSelect.forEach(item => bits += item[0] + 1); text = bits ? `Buy ${comboItem} - ${bits}b` : `Combine - ${comboItem}`; if (vbox.bits >= bits) mouseEvent = sendVboxCombine; } else if (stashSelect.length === 0 && shopSelect.length === 1) { const item = shopSelect[0]; text = `Buy ${vbox.free[item[0]][item[1]]} ${item[0] + 1}b`; mouseEvent = vboxBuySelected; } else { for (let i = 0; i < 3; i++) { if (combineLength > i) { text += '■ '; } else { text += '▫ '; } } } return (
); } function inventoryElement() { function inventoryClick(e) { e.stopPropagation(); if (itemUnequip.length) return sendItemUnequip(itemUnequip); return true; } return (
e.stopPropagation()} onDragOver={ev => ev.preventDefault()} onDrop={inventoryClick} >
{range(0, 4).map(i => inventoryBtn(vbox.bound[i], i))}
); } function inventoryHdr() { const refund = shopSelect.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; return (

e.target.scrollIntoView(true)} onMouseOver={e => hoverInfo(e, 'inventory')}> STASH

); } // // EVERYTHING // function hoverInfo(e, newInfo) { if (shopSelect.find(c => c[0])) return true; if (stashSelect.length !== 0) { const base = stashSelect.find(c => !['Red', 'Blue', 'Green'].includes(vbox.bound[c])); if (base || base === 0) return true; } return setInfo(newInfo); } return (
{vboxHdr()} {vboxElement()} {inventoryHdr()} {inventoryElement()} {combinerBtn()}
); } } module.exports = addState(Vbox);