diff --git a/client/assets/styles/vbox.less b/client/assets/styles/vbox.less
index 2e3bbde8..b6bff59f 100644
--- a/client/assets/styles/vbox.less
+++ b/client/assets/styles/vbox.less
@@ -3,7 +3,7 @@
grid-area: vbox;
display: grid;
grid-template-rows: 3fr minmax(min-content, 2fr);
- grid-template-columns: 1fr 4fr 6fr 17em; // =\
+ grid-template-columns: 1fr 4fr 6fr min-content;
grid-template-areas:
"store-hdr store info combos"
"stash-hdr stash combiner combos";
@@ -217,7 +217,9 @@
display: grid;
grid-area: combos;
margin-left: 0.5em;
+ margin-right: 0.5em;
grid-template-rows: min-content min-content;
+ width: 15.5em;
grid-template-areas:
"comboHeader"
"comboList";
diff --git a/client/src/actions.jsx b/client/src/actions.jsx
index 0c1456af..ab644966 100644
--- a/client/src/actions.jsx
+++ b/client/src/actions.jsx
@@ -48,5 +48,8 @@ export const setTutorial = value => ({ type: 'SET_TUTORIAL', value });
export const setTutorialGame = value => ({ type: 'SET_TUTORIAL_GAME', value });
export const setVboxSelected = value => ({ type: 'SET_VBOX_SELECTED', value });
+export const setVboxCombiner = value => ({ type: 'SET_VBOX_COMBINER', value });
+export const setVboxHighlight = value => ({ type: 'SET_VBOX_HIGHLIGHT', value });
+export const setVboxInfo = value => ({ type: 'SET_VBOX_INFO', value });
export const setWs = value => ({ type: 'SET_WS', value });
diff --git a/client/src/app.jsx b/client/src/app.jsx
index 0d668980..1599c1ab 100644
--- a/client/src/app.jsx
+++ b/client/src/app.jsx
@@ -8,7 +8,6 @@ const { createStore, combineReducers } = require('redux');
const { StripeProvider } = require('react-stripe-elements');
const reducers = require('./reducers');
-const actions = require('./actions');
const setupKeys = require('./keyboard');
const createSocket = require('./socket');
const registerEvents = require('./events');
diff --git a/client/src/components/vbox.combiner.jsx b/client/src/components/vbox.combiner.jsx
index 93051a33..9fef580e 100644
--- a/client/src/components/vbox.combiner.jsx
+++ b/client/src/components/vbox.combiner.jsx
@@ -1,104 +1,44 @@
const preact = require('preact');
-const { connect } = require('preact-redux');
-const countBy = require('lodash/countBy');
-
-const addState = connect(
- function receiveState(state) {
- const {
- ws,
- itemInfo,
- instance,
- player,
- vboxSelected,
- } = state;
-
- function sendVboxAccept(group, index) {
- document.activeElement.blur();
- return ws.sendVboxAccept(instance.id, group, index);
- }
-
- function sendVboxCombine() {
- return ws.sendVboxCombine(instance.id, vboxSelected.stashSelect, vboxSelected.storeSelect);
- }
-
- return {
- itemInfo,
- player,
- vboxSelected,
- sendVboxAccept,
- sendVboxCombine,
- };
- }
-);
function Combiner(args) {
const {
- // Variables that will change
- vboxHighlight,
+ vbox,
+ vboxCombiner,
vboxSelected,
- // Static
- player,
- itemInfo,
- // functions
- sendVboxAccept,
+ vboxBuySelected,
sendVboxCombine,
} = args;
- const { vbox } = player;
const { stashSelect, storeSelect } = vboxSelected;
- const vboxCombo = () => {
- if (!(vboxHighlight && vboxHighlight.length === 0)) return false;
- // The selected items can't be combined with additional items therefore valid combo
- 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 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;
- }));
- return comboItemObj.item;
- };
-
- const combinerCombo = vboxCombo();
-
- function vboxBuySelected() {
- if (!(storeSelect.length === 1 && stashSelect.length === 0)) return false;
- document.activeElement.blur();
- sendVboxAccept(storeSelect[0][0], storeSelect[0][1]);
- return true;
- }
- let text = '';
- let mouseEvent = false;
- if (combinerCombo) {
- const combinerComboText = combinerCombo.replace('Plus', '+');
+ if (vboxCombiner) {
+ const combinerComboText = vboxCombiner.replace('Plus', '+');
let bits = 0;
storeSelect.forEach(item => bits += item[0] + 1);
- text = bits
- ? `Buy ${combinerComboText} ${bits}b`
- : `Combine ${combinerComboText}`;
- if (vbox.bits >= bits) mouseEvent = sendVboxCombine;
- } else if (stashSelect.length === 0 && storeSelect.length === 1) {
- const item = storeSelect[0];
- text = `Buy ${vbox.free[item[0]][item[1]]} ${item[0] + 1}b`;
- mouseEvent = vboxBuySelected;
- } else {
- return false;
+ return (
+
+ );
}
- return (
-
- );
+ if (stashSelect.length === 0 && storeSelect.length === 1) {
+ const item = storeSelect[0];
+ return (
+
+ );
+ }
+
+ return false;
}
-module.exports = addState(Combiner);
+module.exports = Combiner;
diff --git a/client/src/components/vbox.combos.jsx b/client/src/components/vbox.combos.jsx
index 410252d0..f988064c 100644
--- a/client/src/components/vbox.combos.jsx
+++ b/client/src/components/vbox.combos.jsx
@@ -1,112 +1,27 @@
const preact = require('preact');
const { connect } = require('preact-redux');
-const reactStringReplace = require('react-string-replace');
-const countBy = require('lodash/countBy');
-const { convertItem, removeTier } = require('../utils');
-const shapes = require('./shapes');
+const { convertItem } = require('../utils');
-const actions = require('../actions');
-
-const addState = connect(
- function receiveState(state) {
- const {
- ws,
- info,
- itemInfo,
- itemUnequip,
- instance,
- player,
- account,
- tutorial,
- vboxSelected,
- } = state;
-
- function sendVboxAccept(group, index) {
- document.activeElement.blur();
- return ws.sendVboxAccept(instance.id, group, index);
- }
-
- function sendVboxCombine() {
- return ws.sendVboxCombine(instance.id, vboxSelected.stashSelect, vboxSelected.storeSelect);
- }
-
- return {
- ws,
- info,
- itemInfo,
- itemUnequip,
- instance,
- player,
- account,
- tutorial,
- vboxSelected,
- sendVboxAccept,
- sendVboxCombine,
- };
- }
-);
+const addState = connect(({ info, itemInfo, instance, tutorial, vboxInfo }) =>
+ ({ info, itemInfo, instance, tutorial, vboxInfo }));
function Combos(args) {
const {
// Variables that will change
info,
- itemUnequip,
tutorial,
- vboxHighlight,
- vboxSelected,
+ vboxInfo,
// Static
- player, // Only used for colour calcs which will be update if info changes
- ws,
itemInfo,
- instance, // Only used for instance id
+ instance, // Only used for tutorial check
// functions
- sendVboxAccept,
- sendVboxCombine,
- setTutorialNull,
} = args;
- const { comboItem } = this.state;
-
- const { vbox } = player;
- const { stashSelect, storeSelect } = vboxSelected;
-
- const vboxCombo = () => {
- if (!(vboxHighlight && vboxHighlight.length === 0)) return false;
- // The selected items can't be combined with additional items therefore valid combo
- 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 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;
- }));
- return comboItemObj.item;
- };
-
- const combinerCombo = vboxCombo();
- const checkVboxInfo = () => {
- if (combinerCombo) return combinerCombo;
- const stashBase = stashSelect.find(i => !(['Red', 'Blue', 'Green'].includes(vbox.bound[i])));
- if (stashBase > -1) return vbox.bound[stashBase];
- const storeBase = storeSelect.find(j => !(['Red', 'Blue', 'Green'].includes(vbox.free[j[0]][j[1]])));
- if (storeBase) return vbox.free[storeBase[0]][storeBase[1]];
- if (stashSelect.length > 0) return vbox.bound[stashSelect[0]];
- if (storeSelect.length > 0) return vbox.free[storeSelect[0][0]][storeSelect[0][1]];
- return false;
- };
- let vboxInfo = false;
- if (itemUnequip.length) [, vboxInfo] = itemUnequip;
- else if (stashSelect.length > 0 || storeSelect.length > 0) vboxInfo = checkVboxInfo();
if (tutorial && instance.time_control === 'Practice' && instance.rounds.length === 1) return false;
- if (!info && !vboxInfo) return false;
- const comboInfo = vboxInfo || info;
- const vboxCombos = itemInfo.combos.filter(c => c.components.includes(comboInfo));
- if (vboxCombos.length > 6 || vboxCombos.length === 0) return false;
+
+ const vboxCombos = itemInfo.combos.filter(c => c.components.includes(vboxInfo || info));
+ if (vboxCombos.length > 6 || vboxCombos.length === 0) return
;
const comboTable = vboxCombos.map((c, i) => {
const mouseOver = e => {
@@ -126,14 +41,15 @@ function Combos(args) {
);
});
- const comboList = comboTable.length > 0 ? {comboTable}
: false;
return (
- {comboList}
+
+ {comboTable}
+
);
}
diff --git a/client/src/components/vbox.component.jsx b/client/src/components/vbox.component.jsx
index 2f808f08..e0eb4307 100644
--- a/client/src/components/vbox.component.jsx
+++ b/client/src/components/vbox.component.jsx
@@ -1,7 +1,5 @@
const preact = require('preact');
const { connect } = require('preact-redux');
-const countBy = require('lodash/countBy');
-const forEach = require('lodash/forEach');
const actions = require('../actions');
@@ -11,17 +9,23 @@ const StoreElement = require('./vbox.store');
const Combiner = require('./vbox.combiner');
const Combos = require('./vbox.combos');
+const { setVboxState } = require('./vbox.utils');
+
const addState = connect(
function receiveState(state) {
const {
ws,
instance,
player,
- vboxSelected,
info,
itemInfo,
itemUnequip,
tutorial,
+
+ vboxCombiner,
+ vboxHighlight,
+ vboxInfo,
+ vboxSelected,
} = state;
function sendVboxDiscard() {
@@ -29,10 +33,15 @@ const addState = connect(
}
function sendVboxAccept(group, index) {
+ if (!(vboxSelected.storeSelect.length === 1 && vboxSelected.stashSelect.length === 0)) return false;
document.activeElement.blur();
return ws.sendVboxAccept(instance.id, group, index);
}
+ function sendVboxCombine() {
+ return ws.sendVboxCombine(instance.id, vboxSelected.stashSelect, vboxSelected.storeSelect);
+ }
+
function sendVboxReclaim(i) {
return ws.sendVboxReclaim(instance.id, i);
}
@@ -42,17 +51,23 @@ const addState = connect(
}
return {
+ player,
instance,
info,
- player,
- sendVboxAccept,
- sendVboxDiscard,
- sendVboxReclaim,
- vboxSelected,
itemInfo,
itemUnequip,
sendItemUnequip,
tutorial,
+
+ vboxCombiner,
+ vboxHighlight,
+ vboxInfo,
+ vboxSelected,
+
+ sendVboxAccept,
+ sendVboxCombine,
+ sendVboxDiscard,
+ sendVboxReclaim,
};
},
@@ -61,55 +76,26 @@ const addState = connect(
return dispatch(actions.setInfo(item));
}
- function setVboxSelected(v) {
+ function dispatchVboxSelect(v, state) {
+ setVboxState(dispatch, v, state);
dispatch(actions.setItemUnequip([]));
- dispatch(actions.setVboxSelected(v));
return dispatch(actions.setVboxSelected(v));
}
return {
+ dispatchVboxSelect,
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.vboxHighlight !== this.props.vboxHighlight) return true;
if (newProps.player !== this.props.player) return true;
if (newProps.instance !== this.props.instance) return true;
return false;
@@ -121,33 +107,33 @@ class Vbox extends preact.Component {
itemUnequip,
player,
tutorial,
- vboxSelected,
instance,
+ vboxCombiner,
+ vboxHighlight,
+ vboxInfo,
+ vboxSelected,
+
// Static
itemInfo,
// Function Calls
+ dispatchVboxSelect,
sendItemUnequip,
sendVboxAccept,
+ sendVboxCombine,
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 setVboxSelected = v => dispatchVboxSelect(v, { itemInfo, itemUnequip, vbox });
+ const clearVboxSelected = () => setVboxSelected({ storeSelect: [], stashSelect: [] });
+ const vboxBuySelected = () => sendVboxAccept(storeSelect[0][0], storeSelect[0][1]);
- const vboxHighlight = validVboxSelect(vbox, itemInfo, storeSelect, stashSelect);
- //
- // VBOX
- //
function vboxHover(e, v) {
if (v) {
e.stopPropagation();
@@ -157,17 +143,6 @@ class Vbox extends preact.Component {
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 (
@@ -233,37 +208,33 @@ class Vbox extends preact.Component {
clearVboxSelected = {clearVboxSelected}
setInfo = {setInfo}
setVboxSelected = {setVboxSelected}
- storeSelect = {storeSelect}
stashSelect = {stashSelect}
+ storeSelect = {storeSelect}
vbox = {vbox}
vboxHighlight = {vboxHighlight}
vboxHover = {vboxHover}
/>
-
-
+
+
);
}
diff --git a/client/src/components/vbox.info.jsx b/client/src/components/vbox.info.jsx
index 452f268d..80f32528 100644
--- a/client/src/components/vbox.info.jsx
+++ b/client/src/components/vbox.info.jsx
@@ -1,169 +1,33 @@
const preact = require('preact');
const { connect } = require('preact-redux');
-const reactStringReplace = require('react-string-replace');
-const countBy = require('lodash/countBy');
-
-const specThresholds = require('./vbox.info.thresholds');
-const { INFO } = require('./../constants');
-const { convertItem, removeTier } = require('../utils');
const { tutorialStage } = require('../tutorial.utils');
-const shapes = require('./shapes');
+const { genItemInfo } = require('./vbox.utils');
-const actions = require('../actions');
-
-const addState = connect(
- function receiveState(state) {
- const {
- ws,
- info,
- itemInfo,
- itemUnequip,
- instance,
- player,
- account,
- tutorial,
- vboxSelected,
- } = state;
-
- return {
- ws,
- info,
- itemInfo,
- itemUnequip,
- instance,
- player,
- account,
- tutorial,
- vboxSelected,
- };
- },
-
- function receiveDispatch(dispatch) {
- function setTutorialNull() {
- dispatch(actions.setTutorial(null));
- }
-
- function setInfo(info) {
- dispatch(actions.setInfo(info));
- }
- return { setTutorialNull, setInfo };
- }
-);
+const addState = connect(({ info, player, tutorial, vboxInfo, ws, itemInfo, instance }) =>
+ ({ info, player, tutorial, vboxInfo, ws, itemInfo, instance }));
function Info(args) {
const {
// Variables that will change
info,
- itemUnequip,
+ player,
tutorial,
- vboxHighlight,
- vboxSelected,
+ vboxInfo,
// Static
- player, // Only used for colour calcs which will be update if info changes
ws,
itemInfo,
- instance, // Only used for instance id
- // functions
- setTutorialNull,
+ instance,
} = args;
- const { comboItem } = this.state;
-
- const { vbox } = player;
- const { stashSelect, storeSelect } = vboxSelected;
-
- const vboxCombo = () => {
- if (!(vboxHighlight && vboxHighlight.length === 0)) return false;
- // The selected items can't be combined with additional items therefore valid combo
- 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 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;
- }));
- return comboItemObj.item;
- };
-
- const combinerCombo = vboxCombo();
- const checkVboxInfo = () => {
- if (combinerCombo) return combinerCombo;
- const stashBase = stashSelect.find(i => !(['Red', 'Blue', 'Green'].includes(vbox.bound[i])));
- if (stashBase > -1) return vbox.bound[stashBase];
- const storeBase = storeSelect.find(j => !(['Red', 'Blue', 'Green'].includes(vbox.free[j[0]][j[1]])));
- if (storeBase) return vbox.free[storeBase[0]][storeBase[1]];
- if (stashSelect.length > 0) return vbox.bound[stashSelect[0]];
- if (storeSelect.length > 0) return vbox.free[storeSelect[0][0]][storeSelect[0][1]];
- return false;
- };
- let vboxInfo = false;
- if (itemUnequip.length) [, vboxInfo] = itemUnequip;
- else if (stashSelect.length > 0 || storeSelect.length > 0) vboxInfo = checkVboxInfo();
if (tutorial) {
- const tutorialStageInfo = tutorialStage(tutorial, ws, setTutorialNull, instance);
+ const tutorialStageInfo = tutorialStage(tutorial, ws, instance);
if (tutorialStageInfo) return tutorialStageInfo;
}
- function genItemInfo(item) {
- const fullInfo = itemInfo.items.find(i => i.item === item) || INFO[item];
- const isSkill = fullInfo.skill;
- const isSpec = fullInfo.spec;
- const itemDescription = () => {
- const regEx = /(RedPower|BluePower|GreenPower|RedLife|BlueLife|GreenLife|SpeedStat|LIFE|SPEED|POWER)/;
- const infoDescription = reactStringReplace(fullInfo.description, regEx, m => shapes[m]());
- return {reactStringReplace(infoDescription, '\n', () =>
)}
;
- };
- if (isSkill || isSpec) {
- let infoName = fullInfo.item;
- while (infoName.includes('Plus')) infoName = infoName.replace('Plus', '+');
+ // Prioritise the vbox info
+ if (vboxInfo) return genItemInfo(vboxInfo, itemInfo, player, info);
- const itemSource = itemInfo.combos.filter(c => c.item === removeTier(fullInfo.item));
-
- let itemSourceInfo = itemSource.length && !isSpec
- ? `${itemSource[0].components[0]} ${itemSource[0].components[1]} ${itemSource[0].components[2]}`
- : false;
-
- let header = null;
- if (!itemSource.length) header = isSkill ? SKILL
: SPEC
;
- if (itemSourceInfo) {
- while (itemSourceInfo.includes('Plus')) itemSourceInfo = itemSourceInfo.replace('Plus', '+');
- const itemRegEx = /(Red|Blue|Green)/;
- itemSourceInfo = reactStringReplace(itemSourceInfo, itemRegEx, match => shapes[match]());
- }
-
- const cooldown = isSkill && fullInfo.cooldown ? {fullInfo.cooldown} Turn delay
: null;
-
- const speed = isSkill
- ? Speed {shapes.SpeedStat()} multiplier {fullInfo.speed * 4}%
- : null;
-
- const thresholds = isSpec ? specThresholds(player, fullInfo, info) : null;
-
- return (
-
-
{infoName}
- {header}
- {itemSourceInfo}
- {cooldown}
- {itemDescription()}
- {speed}
- {thresholds}
-
- );
- }
- return (
-
-
{fullInfo.item}
- {itemDescription()}
-
- );
- }
- const stateFullInfo = comboItem || vboxInfo;
- if (stateFullInfo) return genItemInfo(stateFullInfo);
+ // check normal info state
if (!info) return false;
if (info.includes('constructName')) {
return (
@@ -189,7 +53,7 @@ function Info(args) {
);
}
- return genItemInfo(info);
+ return genItemInfo(info, itemInfo, player, info);
}
module.exports = addState(Info);
diff --git a/client/src/components/vbox.stash.jsx b/client/src/components/vbox.stash.jsx
index 18dd6b78..264a9f60 100644
--- a/client/src/components/vbox.stash.jsx
+++ b/client/src/components/vbox.stash.jsx
@@ -8,20 +8,20 @@ const { removeTier } = require('../utils');
function stashElement(props) {
const {
- combinerChange,
itemUnequip,
+ sendItemUnequip,
+ setInfo,
+ setVboxSelected,
+ stashSelect,
+ storeSelect,
vbox,
vboxBuySelected,
vboxHighlight,
vboxHover,
- vboxSelecting,
- stashSelect,
-
- sendItemUnequip,
- setInfo,
- setVboxSelected,
-
} = props;
+
+ const vboxSelecting = storeSelect.length === 1 && stashSelect.length === 0;
+
function stashClick(e) {
e.stopPropagation();
if (itemUnequip.length) return sendItemUnequip(itemUnequip);
@@ -46,12 +46,13 @@ function stashElement(props) {
const notValidCombo = vboxHighlight && !vboxHighlight.includes(v);
- function onClick(type) {
+ function onClick(type, e) {
+ e.stopPropagation();
const combinerContainsIndex = stashSelect.indexOf(i) > -1;
// removing
if (combinerContainsIndex) {
if (type === 'click') {
- return combinerChange(without(stashSelect, i));
+ return setVboxSelected({ storeSelect, stashSelect: without(stashSelect, i) });
}
return true;
}
@@ -61,9 +62,7 @@ function stashElement(props) {
return setVboxSelected({ storeSelect: [], stashSelect: [i] });
}
- stashSelect.push(i);
- // if (stashSelect.length === 3) setInfo(comboItem.item);
- return combinerChange(stashSelect);
+ return setVboxSelected({ storeSelect, stashSelect: [...stashSelect, i] });
}
const highlighted = stashSelect.indexOf(i) > -1;
@@ -79,14 +78,14 @@ function stashElement(props) {
key={i}
draggable='true'
onDragStart={ev => {
- onClick('drag');
+ onClick('drag', ev);
ev.dataTransfer.setData('text', '');
}}>
diff --git a/client/src/components/vbox.utils.jsx b/client/src/components/vbox.utils.jsx
new file mode 100644
index 00000000..6d934263
--- /dev/null
+++ b/client/src/components/vbox.utils.jsx
@@ -0,0 +1,128 @@
+const preact = require('preact');
+const countBy = require('lodash/countBy');
+const forEach = require('lodash/forEach');
+const reactStringReplace = require('react-string-replace');
+
+const actions = require('../actions');
+const specThresholds = require('./vbox.info.thresholds');
+const { INFO } = require('./../constants');
+const { removeTier } = require('../utils');
+const shapes = require('./shapes');
+
+function setVboxState(dispatch, vboxSelected, state) {
+ const {
+ itemInfo,
+ itemUnequip,
+ vbox,
+ } = state;
+ const { storeSelect, stashSelect } = vboxSelected;
+
+ // default returns
+ let vboxCombiner = false;
+ let vboxHighlight = false;
+
+ if (!(storeSelect.length === 0 && stashSelect.length === 0)) {
+ vboxHighlight = [];
+ 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) {
+ const fullCombo = combo.components.every(c => itemCount[c] === comboCount[c]);
+ if (fullCombo) vboxCombiner = combo.item;
+
+ forEach(buyCount, (value, key) => {
+ if (value > 0 && !vboxHighlight.includes(key)) {
+ vboxHighlight.push(key);
+ }
+ });
+ }
+ });
+ }
+
+
+ const vboxInfo = () => {
+ if (vboxCombiner) return vboxCombiner;
+ if (itemUnequip.length) return itemUnequip[1];
+ const stashBase = stashSelect.find(i => !(['Red', 'Blue', 'Green'].includes(vbox.bound[i])));
+ if (stashBase > -1) return vbox.bound[stashBase];
+ const storeBase = storeSelect.find(j => !(['Red', 'Blue', 'Green'].includes(vbox.free[j[0]][j[1]])));
+ if (storeBase) return vbox.free[storeBase[0]][storeBase[1]];
+ if (stashSelect.length > 0) return vbox.bound[stashSelect[0]];
+ if (storeSelect.length > 0) return vbox.free[storeSelect[0][0]][storeSelect[0][1]];
+ return false;
+ };
+
+ dispatch(actions.setVboxInfo(vboxInfo()));
+ dispatch(actions.setVboxCombiner(vboxCombiner));
+ return dispatch(actions.setVboxHighlight(vboxHighlight));
+}
+
+function genItemInfo(item, itemInfo, player, info) {
+ const fullInfo = itemInfo.items.find(i => i.item === item) || INFO[item];
+ const isSkill = fullInfo.skill;
+ const isSpec = fullInfo.spec;
+ const itemDescription = () => {
+ const regEx = /(RedPower|BluePower|GreenPower|RedLife|BlueLife|GreenLife|SpeedStat|LIFE|SPEED|POWER)/;
+ const infoDescription = reactStringReplace(fullInfo.description, regEx, m => shapes[m]());
+ return {reactStringReplace(infoDescription, '\n', () =>
)}
;
+ };
+ if (isSkill || isSpec) {
+ let infoName = fullInfo.item;
+ while (infoName.includes('Plus')) infoName = infoName.replace('Plus', '+');
+
+ const itemSource = itemInfo.combos.filter(c => c.item === removeTier(fullInfo.item));
+
+ let itemSourceInfo = itemSource.length && !isSpec
+ ? `${itemSource[0].components[0]} ${itemSource[0].components[1]} ${itemSource[0].components[2]}`
+ : false;
+
+ let header = null;
+ if (!itemSource.length) header = isSkill ? SKILL
: SPEC
;
+ if (itemSourceInfo) {
+ while (itemSourceInfo.includes('Plus')) itemSourceInfo = itemSourceInfo.replace('Plus', '+');
+ const itemRegEx = /(Red|Blue|Green)/;
+ itemSourceInfo = reactStringReplace(itemSourceInfo, itemRegEx, match => shapes[match]());
+ }
+
+ const cooldown = isSkill && fullInfo.cooldown ? {fullInfo.cooldown} Turn delay
: null;
+
+ const speed = isSkill
+ ? Speed {shapes.SpeedStat()} multiplier {fullInfo.speed * 4}%
+ : null;
+
+ const thresholds = isSpec ? specThresholds(player, fullInfo, info) : null;
+
+ return (
+
+
{infoName}
+ {header}
+ {itemSourceInfo}
+ {cooldown}
+ {itemDescription()}
+ {speed}
+ {thresholds}
+
+ );
+ }
+ return (
+
+
{fullInfo.item}
+ {itemDescription()}
+
+ );
+}
+
+
+module.exports = { setVboxState, genItemInfo };
diff --git a/client/src/events.jsx b/client/src/events.jsx
index f852313c..a4b637a8 100644
--- a/client/src/events.jsx
+++ b/client/src/events.jsx
@@ -26,6 +26,12 @@ function registerEvents(store) {
return errorToast(msg);
}
+ function clearTutorial() {
+ store.dispatch(actions.setTutorial(null));
+ localStorage.setItem('tutorial-complete', true);
+ }
+
+
function setPing(ping) {
store.dispatch(actions.setPing(ping));
}
@@ -182,6 +188,9 @@ function registerEvents(store) {
store.dispatch(actions.setActiveSkill(null));
store.dispatch(actions.setInfo(null));
store.dispatch(actions.setItemUnequip([]));
+ store.dispatch(actions.setItemUnequip([]));
+ store.dispatch(actions.setVboxCombiner(null));
+ store.dispatch(actions.setVboxHighlight(null));
store.dispatch(actions.setVboxSelected({ storeSelect: [], stashSelect: [] }));
}
@@ -292,6 +301,9 @@ function registerEvents(store) {
startDemo();
}
+ // store.subscribe(setInfo);
+ // store.on('SET_INFO', setInfo);
+
// events.on('SET_PLAYER', setInstance);
// events.on('SEND_SKILL', function skillActive(gameId, constructId, targetConstructId, skill) {
@@ -340,6 +352,7 @@ function registerEvents(store) {
clearInfo,
clearInstance,
clearMtxActive,
+ clearTutorial,
setAccount,
setAccountInstances,
setActiveItem,
diff --git a/client/src/reducers.jsx b/client/src/reducers.jsx
index 3dcb0670..0267cf3f 100644
--- a/client/src/reducers.jsx
+++ b/client/src/reducers.jsx
@@ -57,6 +57,9 @@ module.exports = {
tutorialGame: createReducer(1, 'SET_TUTORIAL_GAME'),
vboxSelected: createReducer({ storeSelect: [], stashSelect: [] }, 'SET_VBOX_SELECTED'),
+ vboxCombiner: createReducer(null, 'SET_VBOX_COMBINER'),
+ vboxHighlight: createReducer(null, 'SET_VBOX_HIGHLIGHT'),
+ vboxInfo: createReducer(null, 'SET_VBOX_INFO'),
ws: createReducer(null, 'SET_WS'),
};
diff --git a/client/src/socket.jsx b/client/src/socket.jsx
index a9ec07ba..2ca12623 100644
--- a/client/src/socket.jsx
+++ b/client/src/socket.jsx
@@ -204,6 +204,11 @@ function createSocket(events) {
send(['SubscriptionState', {}]);
}
+ function clearTutorial(instanceId) {
+ events.clearTutorial();
+ sendInstanceState(instanceId);
+ }
+
// -------------
// Incoming
// -------------
@@ -430,6 +435,8 @@ function createSocket(events) {
sendMtxBuy,
sendMtxConstructSpawn,
+ clearTutorial,
+
connect,
};
}
diff --git a/client/src/tutorial.utils.jsx b/client/src/tutorial.utils.jsx
index 8736bd72..2e311ead 100644
--- a/client/src/tutorial.utils.jsx
+++ b/client/src/tutorial.utils.jsx
@@ -97,14 +97,10 @@ function tutorialVbox(player, store, tutorial) {
store.dispatch(actions.setTutorial(stage));
}
-function tutorialStage(tutorial, ws, clearTutorial, instance) {
+function tutorialStage(tutorial, ws, instance) {
if (!(instance.time_control === 'Practice' && instance.rounds.length === 1)) return false;
- const exit = () => {
- clearTutorial();
- localStorage.setItem('tutorial-complete', true);
- ws.sendInstanceState(instance.id);
- };
+ const exit = () => ws.clearTutorial(instance.id);
const tutorialText = () => {
if (tutorial === 1) {