diff --git a/client/assets/styles/vbox.less b/client/assets/styles/vbox.less index ec739a11..859919d8 100644 --- a/client/assets/styles/vbox.less +++ b/client/assets/styles/vbox.less @@ -218,11 +218,10 @@ margin-top: 1em; line-height: 1.3; font-size: 1.25em; - - letter-spacing: 0.1em; - border: 0; - transition-property: 0; + &:hover { + border: 2px solid @gray-hover; + } } } diff --git a/client/src/components/info.component.jsx b/client/src/components/info.component.jsx deleted file mode 100644 index 4b59e4d3..00000000 --- a/client/src/components/info.component.jsx +++ /dev/null @@ -1,195 +0,0 @@ -const preact = require('preact'); -const reactStringReplace = require('react-string-replace'); - -const specThresholds = require('./info.thresholds'); -const { INFO } = require('./../constants'); -const { convertItem, removeTier } = require('../utils'); -const { tutorialStage } = require('../tutorial.utils'); -const shapes = require('./shapes'); - -const Combiner = require('./vbox.combiner'); - - -class InfoComponent extends preact.Component { - shouldComponentUpdate(newProps, newState) { - if (newProps.vboxHighlight !== this.props.vboxHighlight) return true; - if (newProps.tutorial !== this.props.tutorial) return true; - // We don't care about info during tutorial - if (newProps.tutorial && this.props.instance.time_control === 'Practice' - && this.props.instance.rounds.length === 1) return false; - if (newProps.info !== this.props.info) return true; - if (newState.comboItem !== this.state.comboItem) return true; - - return false; - } - - componentDidUpdate(prevProps) { - // Catch case where mouse events don't properly clear state and info changed - if (prevProps.info !== this.props.info && this.state.comboItem) this.setState({ comboItem: null }); - } - - render(args) { - const { - // Variables that will change - info, - tutorial, - vboxHighlight, - - // Static - player, // Only used for colour calcs which will be update if info changes - ws, - itemInfo, - instance, // Only used for instance id - // functions - setTutorialNull, - } = args; - const { comboItem } = this.state; - function Info() { - if (tutorial) { - const tutorialStageInfo = tutorialStage(tutorial, ws, setTutorialNull, instance); - if (tutorialStageInfo) return tutorialStageInfo; - } - if (!info) return false; - if (info.includes('constructName')) { - return ( -
-

{info.replace('constructName ', '')}

-

This is the name of your construct.
- Names are randomly generated and are purely cosmetic.
- You can change change your construct name in the RESHAPE tab outside of games. -

-
- ); - } - - if (info.includes('constructAvatar')) { - return ( -
-

{info.replace('constructAvatar ', '')}

-

This is your construct avatar.
- Avatars are randomly generated and are purely cosmetic.
- You can change your construct avatar in the RESHAPE tab outside of games. -

-
- ); - } - const fullInfo = comboItem - ? itemInfo.items.find(i => i.item === comboItem) || INFO[comboItem] - : itemInfo.items.find(i => i.item === info) || INFO[info]; - if (!fullInfo) return false; - 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()} -
- ); - } - - const Combos = () => { - if (tutorial && instance.time_control === 'Practice' && instance.rounds.length === 1) return false; -/* const generalNotes = ( -
-

General

-

- You can preview combos by clicking the combined item when it appears in this section.
- Click the READY button to start the GAME PHASE. -

-
- );*/ - if (!player) return false; - if (!info) return false; - - const vboxCombos = itemInfo.combos.filter(c => c.components.includes(info)); - if (vboxCombos.length > 6 || vboxCombos.length === 0) return false; - - const comboTable = vboxCombos.map((c, i) => { - const mouseOver = e => { - e.stopPropagation(); - this.setState({ comboItem: c.item }); - }; - const componentTable = (c.components.some(ci => ['Red', 'Blue', 'Green'].includes(ci))) - ? [
{convertItem(c.components[0])} {convertItem(c.components[1])}
, -
{convertItem(c.components[2])}
] - : c.components.map((u, j) =>
{convertItem(u)}
); - return ( -
-
- {convertItem(c.item)} -
- {componentTable} -
- ); - }); - const comboList = comboTable.length > 0 ?
{comboTable}
: false; - return ( -
-
-

COMBOS

- Combine colours and items. -
- {comboList} -
- ); - }; - - return ( -
-
this.setState({ comboItem: null })}> - - -
- -
- ); - } -} - -module.exports = InfoComponent; diff --git a/client/src/components/info.container.jsx b/client/src/components/info.container.jsx deleted file mode 100644 index 8a8dbb6f..00000000 --- a/client/src/components/info.container.jsx +++ /dev/null @@ -1,43 +0,0 @@ -const { connect } = require('preact-redux'); - -const actions = require('../actions'); -const Info = require('./info.component'); - -const addState = connect( - function receiveState(state) { - const { - ws, - info, - itemInfo, - instance, - player, - account, - tutorial, - } = state; - - return { - ws, - info, - itemInfo, - instance, - player, - account, - tutorial, - }; - }, - - function receiveDispatch(dispatch) { - function setTutorialNull() { - dispatch(actions.setTutorial(null)); - } - - function setInfo(info) { - dispatch(actions.setInfo(info)); - } - return { setTutorialNull, setInfo }; - } - - -); - -module.exports = addState(Info); diff --git a/client/src/components/instance.component.jsx b/client/src/components/instance.component.jsx index d0d34345..c59b5833 100644 --- a/client/src/components/instance.component.jsx +++ b/client/src/components/instance.component.jsx @@ -55,10 +55,6 @@ function Instance(args) { clearItems(); } - function onTouchMove(e) { - e.preventDefault(); - } - return (
diff --git a/client/src/components/vbox.combiner.jsx b/client/src/components/vbox.combiner.jsx index 1ffd6797..261fb7a2 100644 --- a/client/src/components/vbox.combiner.jsx +++ b/client/src/components/vbox.combiner.jsx @@ -1,6 +1,5 @@ const preact = require('preact'); const { connect } = require('preact-redux'); -const countBy = require('lodash/countBy'); const actions = require('../actions'); @@ -27,19 +26,9 @@ const addState = connect( return { vbox, vboxSelected, - itemInfo, sendVboxAccept, sendVboxCombine, }; - }, - function receiveDispatch(dispatch) { - function setInfo(item) { - return dispatch(actions.setInfo(item)); - } - - return { - setInfo, - }; } ); @@ -47,22 +36,18 @@ class CombinerBtn extends preact.Component { shouldComponentUpdate(newProps) { // Single variable props if (newProps.vbox !== this.props.vbox) return true; - if (newProps.vboxHighlight !== this.props.vboxHighlight) return true; if (newProps.vboxSelected !== this.props.vboxSelected) return true; return false; } render(props) { const { - vboxHighlight, - vbox, vboxSelected, - itemInfo, sendVboxAccept, sendVboxCombine, + combinerCombo, - setInfo, } = props; const { stashSelect, storeSelect } = vboxSelected; @@ -73,31 +58,15 @@ class CombinerBtn extends preact.Component { sendVboxAccept(storeSelect[0][0], storeSelect[0][1]); return true; } - let text = ''; let mouseEvent = false; - const combineLength = stashSelect.length + storeSelect.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 = 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; - })); - let comboItem = comboItemObj ? comboItemObj.item : 'refine'; - setInfo(comboItem); - comboItem = comboItem.replace('Plus', '+'); + if (combinerCombo) { + const comboItem = combinerCombo.replace('Plus', '+'); let bits = 0; storeSelect.forEach(item => bits += item[0] + 1); text = bits ? `Buy ${comboItem} ${bits}b` - : `Combine${comboItem}`; + : `Combine ${comboItem}`; if (vbox.bits >= bits) mouseEvent = sendVboxCombine; } else if (stashSelect.length === 0 && storeSelect.length === 1) { const item = storeSelect[0]; diff --git a/client/src/components/vbox.component.jsx b/client/src/components/vbox.component.jsx index 756f17ee..1476ffb7 100644 --- a/client/src/components/vbox.component.jsx +++ b/client/src/components/vbox.component.jsx @@ -5,7 +5,7 @@ const forEach = require('lodash/forEach'); const actions = require('../actions'); -const InfoContainer = require('./info.container'); +const InfoContainer = require('./vbox.info'); const StashElement = require('./vbox.stash'); const StoreElement = require('./vbox.store'); @@ -149,11 +149,7 @@ class Vbox extends preact.Component { 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; - } + if (stashSelect.length !== 0 || storeSelect.length !== 0) return true; setInfo(v); } return true; diff --git a/client/src/components/vbox.info.jsx b/client/src/components/vbox.info.jsx new file mode 100644 index 00000000..3a553c0d --- /dev/null +++ b/client/src/components/vbox.info.jsx @@ -0,0 +1,261 @@ +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 Combiner = require('./vbox.combiner'); + +const actions = require('../actions'); + +const addState = connect( + function receiveState(state) { + const { + ws, + info, + itemInfo, + instance, + player, + account, + tutorial, + vboxSelected, + } = state; + + return { + ws, + info, + itemInfo, + instance, + player, + account, + tutorial, + vboxSelected, + }; + }, + + function receiveDispatch(dispatch) { + function setTutorialNull() { + dispatch(actions.setTutorial(null)); + } + + function setInfo(info) { + dispatch(actions.setInfo(info)); + } + return { setTutorialNull, setInfo }; + } +); + +class InfoComponent extends preact.Component { + shouldComponentUpdate(newProps, newState) { + if (newProps.vboxSelected !== this.props.vboxSelected) return true; + if (newProps.vboxHighlight !== this.props.vboxHighlight) return true; + if (newProps.tutorial !== this.props.tutorial) return true; + // We don't care about info during tutorial + if (newProps.tutorial && this.props.instance.time_control === 'Practice' + && this.props.instance.rounds.length === 1) return false; + if (newProps.info !== this.props.info) return true; + if (newState.comboItem !== this.state.comboItem) return true; + + return false; + } + + componentDidUpdate(prevProps) { + // Catch case where mouse events don't properly clear state and info changed + if (prevProps.info !== this.props.info && this.state.comboItem) this.setState({ comboItem: null }); + } + + render(args) { + const { + // Variables that will change + info, + tutorial, + vboxHighlight, + vboxSelected, + // Static + player, // Only used for colour calcs which will be update if info changes + ws, + itemInfo, + instance, // Only used for instance id + // functions + 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; + }; + + const vboxInfo = (stashSelect.length > 0 || storeSelect.length > 0) ? checkVboxInfo() : false; + + function Info() { + if (tutorial) { + const tutorialStageInfo = tutorialStage(tutorial, ws, setTutorialNull, 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', '+'); + + 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()} +
+ ); + } + if (vboxInfo) return genItemInfo(vboxInfo); + if (!info) return false; + if (info.includes('constructName')) { + return ( +
+

{info.replace('constructName ', '')}

+

This is the name of your construct.
+ Names are randomly generated and are purely cosmetic.
+ You can change change your construct name in the RESHAPE tab outside of games. +

+
+ ); + } + + if (info.includes('constructAvatar')) { + return ( +
+

{info.replace('constructAvatar ', '')}

+

This is your construct avatar.
+ Avatars are randomly generated and are purely cosmetic.
+ You can change your construct avatar in the RESHAPE tab outside of games. +

+
+ ); + } + const stateFullInfo = comboItem || info; + if (!stateFullInfo) return false; + return genItemInfo(stateFullInfo); + } + + const Combos = () => { + 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 comboTable = vboxCombos.map((c, i) => { + const mouseOver = e => { + e.stopPropagation(); + this.setState({ comboItem: c.item }); + }; + const componentTable = (c.components.some(ci => ['Red', 'Blue', 'Green'].includes(ci))) + ? [
{convertItem(c.components[0])} {convertItem(c.components[1])}
, +
{convertItem(c.components[2])}
] + : c.components.map((u, j) =>
{convertItem(u)}
); + return ( +
+
+ {convertItem(c.item)} +
+ {componentTable} +
+ ); + }); + const comboList = comboTable.length > 0 ?
{comboTable}
: false; + return ( +
+
+

COMBOS

+ Combine colours and items. +
+ {comboList} +
+ ); + }; + + return ( +
+
this.setState({ comboItem: null })}> + + +
+ +
+ ); + } +} + +module.exports = addState(InfoComponent); diff --git a/client/src/components/info.thresholds.jsx b/client/src/components/vbox.info.thresholds.jsx similarity index 100% rename from client/src/components/info.thresholds.jsx rename to client/src/components/vbox.info.thresholds.jsx