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 actions = require('../actions'); const addState = connect( function receiveState(state) { const { ws, info, itemInfo, 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, instance, player, account, tutorial, vboxSelected, sendVboxAccept, sendVboxCombine, }; }, 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 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; }; 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
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.
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.