Merge branch 'new-vbox-combiner' into new-vbox-resize
This commit is contained in:
commit
5f4659b6db
@ -5,6 +5,7 @@
|
|||||||
@white: #f5f5f5; // whitesmoke
|
@white: #f5f5f5; // whitesmoke
|
||||||
@purple: #9355b5; // 6lack - that far cover
|
@purple: #9355b5; // 6lack - that far cover
|
||||||
@yellow: #ffa100;
|
@yellow: #ffa100;
|
||||||
|
@silver: #c0c0c0;
|
||||||
|
|
||||||
@black: black;
|
@black: black;
|
||||||
@gray: #222;
|
@gray: #222;
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
height: 50%;
|
height: 50%;
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
@ -232,8 +233,8 @@
|
|||||||
|
|
||||||
#targeting, .resolving-skill {
|
#targeting, .resolving-skill {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 35%;
|
top: calc(35% + 0.5em); // calc for 0.5em top gap
|
||||||
height: 15%;
|
height: calc(15% - 1em); // calc for 0.5em + 0.5em top / bottom gap
|
||||||
width: calc(90% - 1.25em);
|
width: calc(90% - 1.25em);
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
span {
|
span {
|
||||||
@ -273,7 +274,7 @@
|
|||||||
/* some stupid bug in chrome makes it fill the entire screen */
|
/* some stupid bug in chrome makes it fill the entire screen */
|
||||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||||
#targeting {
|
#targeting {
|
||||||
max-height: 10em;
|
// max-height: 10em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,114 +5,17 @@
|
|||||||
.instance {
|
.instance {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr minmax(min-content, 1fr);
|
|
||||||
grid-template-rows: min-content 1fr;
|
grid-template-rows: min-content 1fr;
|
||||||
|
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"vbox info"
|
"vbox"
|
||||||
"constructs constructs";
|
"constructs";
|
||||||
|
|
||||||
.info {
|
|
||||||
h2 {
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
svg {
|
|
||||||
display: inline;
|
|
||||||
height: 1em;
|
|
||||||
}
|
|
||||||
figure {
|
|
||||||
display: inline;
|
|
||||||
height: 0.5em;
|
|
||||||
svg {
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
figcaption {
|
|
||||||
font-size: 1em;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
margin-left: 1em;
|
|
||||||
grid-area: info;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr min-content;
|
|
||||||
grid-template-areas:
|
|
||||||
"item combos";
|
|
||||||
|
|
||||||
.info-item {
|
|
||||||
grid-area: item;
|
|
||||||
}
|
|
||||||
.combos {
|
|
||||||
display: grid;
|
|
||||||
grid-area: combos;
|
|
||||||
margin-left: 0.5em;
|
|
||||||
grid-template-rows: min-content min-content;
|
|
||||||
grid-template-areas:
|
|
||||||
"comboHeader"
|
|
||||||
"comboList";
|
|
||||||
.combo-header {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.combo-list {
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: min-content min-content min-content;
|
|
||||||
grid-template-columns: min-content min-content;
|
|
||||||
grid-gap: 0.5em;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
width: 15.5em;
|
|
||||||
|
|
||||||
.table-button {
|
|
||||||
display: grid;
|
|
||||||
text-align: center;
|
|
||||||
align-content: center;
|
|
||||||
grid-template-areas:
|
|
||||||
"item"
|
|
||||||
"ingr";
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
&:hover {
|
|
||||||
color: whitesmoke;
|
|
||||||
background-color: @gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
border-top: 2px solid #222;
|
|
||||||
border-bottom: 2px solid #222;
|
|
||||||
flex: 1;
|
|
||||||
grid-area: item;
|
|
||||||
font-weight: bold;
|
|
||||||
div {
|
|
||||||
width: 5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
div {
|
|
||||||
border-left: 2px solid #222;
|
|
||||||
border-right: 2px solid #222;
|
|
||||||
height: 1.75em;
|
|
||||||
width: 7.5em;
|
|
||||||
svg {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: 2px solid #222;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.constructs {
|
.constructs {
|
||||||
grid-area: constructs;
|
grid-area: constructs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@keyframes action {
|
@keyframes action {
|
||||||
0% {
|
0% {
|
||||||
color: palegoldenrod;
|
color: palegoldenrod;
|
||||||
@ -152,7 +55,7 @@
|
|||||||
button {
|
button {
|
||||||
&.highlight {
|
&.highlight {
|
||||||
color: black;
|
color: black;
|
||||||
background: @white;
|
background: @silver;
|
||||||
// border: 1px solid @white; (this bangs around the vbox)
|
// border: 1px solid @white; (this bangs around the vbox)
|
||||||
|
|
||||||
// overwrite the classes on white svg elements
|
// overwrite the classes on white svg elements
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
@media (max-width: 800px) {
|
@media (max-width: 800px) {
|
||||||
body {
|
body {
|
||||||
overflow-y: initial;
|
overflow-y: initial;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#mnml {
|
#mnml {
|
||||||
@ -95,6 +94,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
opacity: 0.1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.game {
|
.game {
|
||||||
@ -221,8 +224,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// portrait menu
|
// portrait menu or small size vertical in landscape
|
||||||
@media (max-width: 500px) {
|
@media (max-width: 550px) {
|
||||||
#mnml {
|
#mnml {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
@ -289,6 +292,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stats {
|
||||||
|
font-size: 6pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skill-description {
|
||||||
|
font-size: 6pt;
|
||||||
|
}
|
||||||
|
|
||||||
section {
|
section {
|
||||||
.list {
|
.list {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|||||||
@ -3,10 +3,10 @@
|
|||||||
grid-area: vbox;
|
grid-area: vbox;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 3fr 2fr;
|
grid-template-rows: 3fr 2fr;
|
||||||
grid-template-columns: 1fr 4fr 1fr;
|
grid-template-columns: 1fr 4fr 6fr;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"store-hdr store combiner"
|
"store-hdr store info"
|
||||||
"stash-hdr stash combiner";
|
"stash-hdr stash info";
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
|
|
||||||
@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
.store {
|
.store {
|
||||||
grid-area: store;
|
grid-area: store;
|
||||||
border-right: 0.1em solid @gray;
|
border-right: 0.15em solid @gray;
|
||||||
border-top: 0.1em solid @gray;
|
border-top: 0.15em solid @gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
.store-hdr {
|
.store-hdr {
|
||||||
@ -27,17 +27,16 @@
|
|||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-left: 0.1em solid @gray;
|
border-left: 0.15em solid @gray;
|
||||||
border-top: 0.1em solid @gray;
|
border-top: 0.15em solid @gray;
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
margin: 1em 0 0 0;
|
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.15em;
|
||||||
background-color: #421010;
|
background-color: #421010;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: @red;
|
background-color: @red;
|
||||||
@ -46,38 +45,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.combiner {
|
|
||||||
grid-area: combiner;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
line-height: 1.3;
|
|
||||||
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
.vbox-padding {
|
|
||||||
margin-right: 0em;
|
|
||||||
margin-bottom: 0em;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
line-height: 1.3;
|
|
||||||
font-size: 1.25em;
|
|
||||||
|
|
||||||
letter-spacing: 0.1em;
|
|
||||||
background-color: @yellow;
|
|
||||||
color: black;
|
|
||||||
border-radius: 0;
|
|
||||||
border: 0;
|
|
||||||
&[disabled] {
|
|
||||||
border: 0.1em solid @gray;
|
|
||||||
border-left: 0;
|
|
||||||
color: @gray-exists;
|
|
||||||
};
|
|
||||||
|
|
||||||
transition-property: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.stash {
|
.stash {
|
||||||
grid-area: stash;
|
grid-area: stash;
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -85,37 +52,26 @@
|
|||||||
grid-gap: 0.5em 1em;
|
grid-gap: 0.5em 1em;
|
||||||
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border: 0.1em solid @gray;
|
border: 0.15em solid @gray;
|
||||||
border-left: 0;
|
border-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stash-hdr {
|
.stash-hdr {
|
||||||
|
grid-area: stash-hdr;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
grid-area: stash-hdr;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border: 0.1em solid @gray;
|
border: 0.15em solid @gray;
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
|
|
||||||
h3 {
|
h2 {
|
||||||
margin-bottom: 2.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.refund {
|
|
||||||
padding: 0.5em 0.5em 0 0;
|
|
||||||
|
|
||||||
button {
|
button {
|
||||||
line-height: 1.4;
|
line-height: 1.6;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.15em;
|
||||||
color: black;
|
|
||||||
background-color: @yellow;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vbox-padding {
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,14 +134,17 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
// text-transform: none;
|
// text-transform: none;
|
||||||
|
|
||||||
&.empty {
|
&.empty {
|
||||||
border-style: dashed;
|
border-style: dashed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.fade {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
&.highlight {
|
&.highlight {
|
||||||
color: black;
|
color: black;
|
||||||
background: @white;
|
background: @silver;
|
||||||
// border: 1px solid @white; (this bangs around the vbox)
|
// border: 1px solid @white; (this bangs around the vbox)
|
||||||
|
|
||||||
// overwrite the classes on white svg elements
|
// overwrite the classes on white svg elements
|
||||||
@ -210,6 +169,127 @@
|
|||||||
line-height: initial;
|
line-height: initial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
line-height: 1.6;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
display: inline;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
figure {
|
||||||
|
display: inline;
|
||||||
|
height: 0.5em;
|
||||||
|
svg {
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
figcaption {
|
||||||
|
font-size: 1em;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
margin-left: 1em;
|
||||||
|
grid-area: info;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr min-content;
|
||||||
|
grid-template-areas:
|
||||||
|
"details combos";
|
||||||
|
|
||||||
|
.info-details {
|
||||||
|
grid-area: details;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 1fr min-content;
|
||||||
|
grid-template-areas:
|
||||||
|
"item"
|
||||||
|
"combiner";
|
||||||
|
|
||||||
|
.combiner {
|
||||||
|
grid-area: combiner;
|
||||||
|
display: flex;
|
||||||
|
width: 60%;
|
||||||
|
button {
|
||||||
|
margin-top: 1em;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-size: 1.25em;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
&:hover {
|
||||||
|
border: 2px solid @gray-hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
grid-area: item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.combos {
|
||||||
|
display: grid;
|
||||||
|
grid-area: combos;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
grid-template-rows: min-content min-content;
|
||||||
|
grid-template-areas:
|
||||||
|
"comboHeader"
|
||||||
|
"comboList";
|
||||||
|
.combo-header {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.combo-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: min-content min-content min-content;
|
||||||
|
grid-template-columns: min-content min-content;
|
||||||
|
grid-gap: 0.5em;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
width: 15.5em;
|
||||||
|
|
||||||
|
.table-button {
|
||||||
|
display: grid;
|
||||||
|
text-align: center;
|
||||||
|
align-content: center;
|
||||||
|
grid-template-areas:
|
||||||
|
"item"
|
||||||
|
"ingr";
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
color: whitesmoke;
|
||||||
|
background-color: @gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
border-top: 2px solid #222;
|
||||||
|
border-bottom: 2px solid #222;
|
||||||
|
flex: 1;
|
||||||
|
grid-area: item;
|
||||||
|
font-weight: bold;
|
||||||
|
div {
|
||||||
|
width: 5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div {
|
||||||
|
border-left: 2px solid #222;
|
||||||
|
border-right: 2px solid #222;
|
||||||
|
height: 1.75em;
|
||||||
|
width: 7.5em;
|
||||||
|
svg {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 2px solid #222;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 2000px) {
|
@media (min-width: 2000px) {
|
||||||
|
|||||||
@ -1,191 +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');
|
|
||||||
|
|
||||||
|
|
||||||
class InfoComponent extends preact.Component {
|
|
||||||
shouldComponentUpdate(newProps, newState) {
|
|
||||||
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,
|
|
||||||
|
|
||||||
// Static
|
|
||||||
player, // Only used for colour calcs which will be update if info changes
|
|
||||||
ws,
|
|
||||||
itemInfo,
|
|
||||||
instance, // Only used for instance id
|
|
||||||
// functions
|
|
||||||
setInfo,
|
|
||||||
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 (
|
|
||||||
<div class='info-item'>
|
|
||||||
<h2> {info.replace('constructName ', '')} </h2>
|
|
||||||
<p> This is the name of your construct. <br />
|
|
||||||
Names are randomly generated and are purely cosmetic. <br />
|
|
||||||
You can change change your construct name in the <b>RESHAPE</b> tab outside of games.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.includes('constructAvatar')) {
|
|
||||||
return (
|
|
||||||
<div class='info-item'>
|
|
||||||
<h2> {info.replace('constructAvatar ', '')} </h2>
|
|
||||||
<p> This is your construct avatar. <br />
|
|
||||||
Avatars are randomly generated and are purely cosmetic. <br />
|
|
||||||
You can change your construct avatar in the <b>RESHAPE</b> tab outside of games.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
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 <div>{reactStringReplace(infoDescription, '\n', () => <br />)}</div>;
|
|
||||||
};
|
|
||||||
|
|
||||||
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 ? <h3> SKILL </h3> : <h3> SPEC </h3>;
|
|
||||||
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 ? <div>{fullInfo.cooldown} Turn delay</div> : null;
|
|
||||||
|
|
||||||
const speed = isSkill
|
|
||||||
? <div> Speed {shapes.SpeedStat()} multiplier {fullInfo.speed * 4}% </div>
|
|
||||||
: null;
|
|
||||||
|
|
||||||
const thresholds = isSpec ? specThresholds(player, fullInfo, info) : null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class={isSkill ? 'info-item' : 'info-item'}>
|
|
||||||
<h2>{infoName}</h2>
|
|
||||||
{header}
|
|
||||||
{itemSourceInfo}
|
|
||||||
{cooldown}
|
|
||||||
{itemDescription()}
|
|
||||||
{speed}
|
|
||||||
{thresholds}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class="info-item">
|
|
||||||
<h2>{fullInfo.item}</h2>
|
|
||||||
{itemDescription()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Combos = () => {
|
|
||||||
if (tutorial && instance.time_control === 'Practice' && instance.rounds.length === 1) return false;
|
|
||||||
/* const generalNotes = (
|
|
||||||
<div>
|
|
||||||
<h2> General </h2>
|
|
||||||
<p>
|
|
||||||
You can preview combos by clicking the combined item when it appears in this section. <br />
|
|
||||||
Click the <b>READY</b> button to start the <b>GAME PHASE</b>.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);*/
|
|
||||||
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)))
|
|
||||||
? [<div key="0">{convertItem(c.components[0])} {convertItem(c.components[1])}</div>,
|
|
||||||
<div key="1">{convertItem(c.components[2])}</div>]
|
|
||||||
: c.components.map((u, j) => <div key={j} >{convertItem(u)}</div>);
|
|
||||||
return (
|
|
||||||
<div key={i} onMouseOver={mouseOver} class="table-button">
|
|
||||||
<div class="item">
|
|
||||||
{convertItem(c.item)}
|
|
||||||
</div>
|
|
||||||
{componentTable}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
const comboList = comboTable.length > 0 ? <div class="combo-list">{comboTable}</div> : false;
|
|
||||||
return (
|
|
||||||
<div class="combos">
|
|
||||||
<div class="combo-header">
|
|
||||||
<h2>COMBOS</h2>
|
|
||||||
Combine colours and items.
|
|
||||||
</div>
|
|
||||||
{comboList}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class='info'>
|
|
||||||
<div onMouseOver={() => this.setState({ comboItem: null })}>
|
|
||||||
<Info />
|
|
||||||
</div>
|
|
||||||
<Combos />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = InfoComponent;
|
|
||||||
@ -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);
|
|
||||||
@ -2,7 +2,6 @@ const preact = require('preact');
|
|||||||
const { connect } = require('preact-redux');
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
const Vbox = require('./vbox.component');
|
const Vbox = require('./vbox.component');
|
||||||
const InfoContainer = require('./info.container');
|
|
||||||
const InstanceConstructsContainer = require('./instance.constructs');
|
const InstanceConstructsContainer = require('./instance.constructs');
|
||||||
const Faceoff = require('./faceoff');
|
const Faceoff = require('./faceoff');
|
||||||
|
|
||||||
@ -56,14 +55,9 @@ function Instance(args) {
|
|||||||
clearItems();
|
clearItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTouchMove(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main id="instance" class='instance' onClick={instanceClick}>
|
<main id="instance" class='instance' onClick={instanceClick}>
|
||||||
<Vbox />
|
<Vbox />
|
||||||
<InfoContainer />
|
|
||||||
<InstanceConstructsContainer />
|
<InstanceConstructsContainer />
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -129,8 +129,10 @@ function Construct(props) {
|
|||||||
|
|
||||||
function skillClick(e) {
|
function skillClick(e) {
|
||||||
if (!skill) return false;
|
if (!skill) return false;
|
||||||
setItemUnequip([construct.id, skill.skill, i]);
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
if (itemUnequip.length && itemUnequip[0] === construct.id && skill.skill === itemUnequip[1]
|
||||||
|
&& i === itemUnequip[2]) return setItemUnequip([]);
|
||||||
|
setItemUnequip([construct.id, skill.skill, i]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,8 +179,11 @@ function Construct(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function specClick(e) {
|
function specClick(e) {
|
||||||
|
if (!s) return false;
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setItemUnequip([construct.id, s, i]);
|
if (itemUnequip.length && itemUnequip[0] === construct.id && itemUnequip[1] === s
|
||||||
|
&& i === itemUnequip[2]) return setItemUnequip([]);
|
||||||
|
return setItemUnequip([construct.id, s, i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const highlight = itemUnequip[0] === construct.id && itemUnequip[1] === s && i === itemUnequip[2];
|
const highlight = itemUnequip[0] === construct.id && itemUnequip[1] === s && i === itemUnequip[2];
|
||||||
|
|||||||
@ -26,6 +26,9 @@ const addState = connect(
|
|||||||
dispatch(actions.setNav('play'));
|
dispatch(actions.setNav('play'));
|
||||||
dispatch(actions.setGame(null));
|
dispatch(actions.setGame(null));
|
||||||
dispatch(actions.setInstance(null));
|
dispatch(actions.setInstance(null));
|
||||||
|
dispatch(actions.setVboxSelected({ storeSelect: [], stashSelect: [] }));
|
||||||
|
dispatch(actions.setInfo(null));
|
||||||
|
dispatch(actions.setItemUnequip([]));
|
||||||
if (tutorial) dispatch(actions.setTutorial(1));
|
if (tutorial) dispatch(actions.setTutorial(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -110,8 +110,11 @@ class TargetSvg extends Component {
|
|||||||
? playerTeam.constructs.findIndex(c => c.id === cast.target_construct_id)
|
? playerTeam.constructs.findIndex(c => c.id === cast.target_construct_id)
|
||||||
: otherTeam.constructs.findIndex(c => c.id === cast.target_construct_id);
|
: otherTeam.constructs.findIndex(c => c.id === cast.target_construct_id);
|
||||||
|
|
||||||
|
const skillNumber = window.innerWidth <= 800 // mobile styling trigger
|
||||||
|
? playerTeam.constructs[source].skills.findIndex(s => s.skill === cast.skill)
|
||||||
|
: 0;
|
||||||
const sourceY = height;
|
const sourceY = height;
|
||||||
const sourceX = (source * width / 3) + width / 24;
|
const sourceX = (source * width / 3) + width / 18 + skillNumber * (width / 9);
|
||||||
const targetX = (target * width / 3) + width / 6
|
const targetX = (target * width / 3) + width / 6
|
||||||
+ (defensive ? width / 64 : 0)
|
+ (defensive ? width / 64 : 0)
|
||||||
+ (source * width / 18);
|
+ (source * width / 18);
|
||||||
|
|||||||
@ -1,66 +0,0 @@
|
|||||||
const preact = require('preact');
|
|
||||||
const countBy = require('lodash/countBy');
|
|
||||||
|
|
||||||
function combinerBtn(props) {
|
|
||||||
const {
|
|
||||||
itemInfo,
|
|
||||||
sendVboxCombine,
|
|
||||||
setInfo,
|
|
||||||
stashSelect,
|
|
||||||
storeSelect,
|
|
||||||
vbox,
|
|
||||||
vboxBuySelected,
|
|
||||||
vboxHighlight,
|
|
||||||
} = props;
|
|
||||||
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', '+');
|
|
||||||
let bits = 0;
|
|
||||||
storeSelect.forEach(item => bits += item[0] + 1);
|
|
||||||
text = bits
|
|
||||||
? <p>Buy<br/>{comboItem}<br />{bits}b</p>
|
|
||||||
: <p>Combine<br />{comboItem}</p>;
|
|
||||||
if (vbox.bits >= bits) mouseEvent = sendVboxCombine;
|
|
||||||
} else if (stashSelect.length === 0 && storeSelect.length === 1) {
|
|
||||||
const item = storeSelect[0];
|
|
||||||
text = <p>Buy<br />{vbox.free[item[0]][item[1]]}<br />{item[0] + 1}b</p>;
|
|
||||||
mouseEvent = vboxBuySelected;
|
|
||||||
} else {
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
if (combineLength > i) {
|
|
||||||
text += '■ ';
|
|
||||||
} else {
|
|
||||||
text += '▫ ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div class='combiner'>
|
|
||||||
<button
|
|
||||||
class='vbox-btn'
|
|
||||||
disabled={!mouseEvent}
|
|
||||||
onClick={e => e.stopPropagation()}
|
|
||||||
onMouseDown={() => mouseEvent()}>
|
|
||||||
{text}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = combinerBtn;
|
|
||||||
@ -5,9 +5,9 @@ const forEach = require('lodash/forEach');
|
|||||||
|
|
||||||
const actions = require('../actions');
|
const actions = require('../actions');
|
||||||
|
|
||||||
|
const InfoContainer = require('./vbox.info');
|
||||||
const StashElement = require('./vbox.stash');
|
const StashElement = require('./vbox.stash');
|
||||||
const StoreElement = require('./vbox.store');
|
const StoreElement = require('./vbox.store');
|
||||||
const CombinerElement = require('./vbox.combiner');
|
|
||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
@ -16,6 +16,7 @@ const addState = connect(
|
|||||||
instance,
|
instance,
|
||||||
player,
|
player,
|
||||||
vboxSelected,
|
vboxSelected,
|
||||||
|
info,
|
||||||
itemInfo,
|
itemInfo,
|
||||||
itemUnequip,
|
itemUnequip,
|
||||||
tutorial,
|
tutorial,
|
||||||
@ -30,10 +31,6 @@ const addState = connect(
|
|||||||
return ws.sendVboxAccept(instance.id, group, index);
|
return ws.sendVboxAccept(instance.id, group, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendVboxCombine() {
|
|
||||||
return ws.sendVboxCombine(instance.id, vboxSelected.stashSelect, vboxSelected.storeSelect);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendVboxReclaim(i) {
|
function sendVboxReclaim(i) {
|
||||||
return ws.sendVboxReclaim(instance.id, i);
|
return ws.sendVboxReclaim(instance.id, i);
|
||||||
}
|
}
|
||||||
@ -44,9 +41,9 @@ const addState = connect(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
instance,
|
instance,
|
||||||
|
info,
|
||||||
player,
|
player,
|
||||||
sendVboxAccept,
|
sendVboxAccept,
|
||||||
sendVboxCombine,
|
|
||||||
sendVboxDiscard,
|
sendVboxDiscard,
|
||||||
sendVboxReclaim,
|
sendVboxReclaim,
|
||||||
vboxSelected,
|
vboxSelected,
|
||||||
@ -130,7 +127,6 @@ class Vbox extends preact.Component {
|
|||||||
// Function Calls
|
// Function Calls
|
||||||
sendItemUnequip,
|
sendItemUnequip,
|
||||||
sendVboxAccept,
|
sendVboxAccept,
|
||||||
sendVboxCombine,
|
|
||||||
sendVboxDiscard,
|
sendVboxDiscard,
|
||||||
sendVboxReclaim,
|
sendVboxReclaim,
|
||||||
setVboxSelected,
|
setVboxSelected,
|
||||||
@ -153,11 +149,7 @@ class Vbox extends preact.Component {
|
|||||||
function vboxHover(e, v) {
|
function vboxHover(e, v) {
|
||||||
if (v) {
|
if (v) {
|
||||||
e.stopPropagation();
|
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 || storeSelect.length !== 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;
|
|
||||||
}
|
|
||||||
setInfo(v);
|
setInfo(v);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -177,10 +169,10 @@ class Vbox extends preact.Component {
|
|||||||
function storeHdr() {
|
function storeHdr() {
|
||||||
return (
|
return (
|
||||||
<div class="store-hdr">
|
<div class="store-hdr">
|
||||||
<h3
|
<h2
|
||||||
onTouchStart={e => e.target.scrollIntoView(true)}
|
onTouchStart={e => e.target.scrollIntoView(true)}
|
||||||
onMouseOver={e => vboxHover(e, 'store')}> STORE
|
onMouseOver={e => vboxHover(e, 'store')}> STORE
|
||||||
</h3>
|
</h2>
|
||||||
<div class={`bits ${vbox.bits < 3 ? 'red' : false}`} onMouseOver={e => vboxHover(e, 'bits')}>
|
<div class={`bits ${vbox.bits < 3 ? 'red' : false}`} onMouseOver={e => vboxHover(e, 'bits')}>
|
||||||
<h1> {vbox.bits}b </h1>
|
<h1> {vbox.bits}b </h1>
|
||||||
</div>
|
</div>
|
||||||
@ -222,9 +214,9 @@ class Vbox extends preact.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class='stash-hdr'>
|
<div class='stash-hdr'>
|
||||||
<h3 onTouchStart={e => e.target.scrollIntoView(true)}
|
<h2 onTouchStart={e => e.target.scrollIntoView(true)}
|
||||||
onMouseOver={e => vboxHover(e, 'stash')}> STASH
|
onMouseOver={e => vboxHover(e, 'stash')}> STASH
|
||||||
</h3>
|
</h2>
|
||||||
{refundBtn}
|
{refundBtn}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -235,6 +227,10 @@ class Vbox extends preact.Component {
|
|||||||
<div class='vbox'>
|
<div class='vbox'>
|
||||||
{storeHdr()}
|
{storeHdr()}
|
||||||
{stashHdr()}
|
{stashHdr()}
|
||||||
|
<InfoContainer
|
||||||
|
vboxHighlight={vboxHighlight}
|
||||||
|
vboxBuySelected={vboxBuySelected}
|
||||||
|
/>
|
||||||
<StoreElement
|
<StoreElement
|
||||||
clearVboxSelected = {clearVboxSelected}
|
clearVboxSelected = {clearVboxSelected}
|
||||||
setInfo = {setInfo}
|
setInfo = {setInfo}
|
||||||
@ -258,16 +254,6 @@ class Vbox extends preact.Component {
|
|||||||
setInfo = {setInfo}
|
setInfo = {setInfo}
|
||||||
setVboxSelected = {setVboxSelected}
|
setVboxSelected = {setVboxSelected}
|
||||||
/>
|
/>
|
||||||
<CombinerElement
|
|
||||||
itemInfo = {itemInfo}
|
|
||||||
sendVboxCombine = {sendVboxCombine}
|
|
||||||
setInfo = {setInfo}
|
|
||||||
stashSelect = {stashSelect}
|
|
||||||
storeSelect = {storeSelect}
|
|
||||||
vbox = {vbox}
|
|
||||||
vboxBuySelected = {vboxBuySelected}
|
|
||||||
vboxHighlight = {vboxHighlight}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
315
client/src/components/vbox.info.jsx
Normal file
315
client/src/components/vbox.info.jsx
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
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,
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
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.info !== this.props.info) return true;
|
||||||
|
if (newProps.itemUnequip !== this.props.itemUnequip) return true;
|
||||||
|
if (newProps.tutorial !== this.props.tutorial) return true;
|
||||||
|
if (newProps.vboxHighlight !== this.props.vboxHighlight) return true;
|
||||||
|
if (newProps.vboxSelected !== this.props.vboxSelected) 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,
|
||||||
|
itemUnequip,
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
let vboxInfo = false;
|
||||||
|
if (itemUnequip.length) [, vboxInfo] = itemUnequip;
|
||||||
|
else if (stashSelect.length > 0 || storeSelect.length > 0) vboxInfo = checkVboxInfo();
|
||||||
|
|
||||||
|
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 <div>{reactStringReplace(infoDescription, '\n', () => <br />)}</div>;
|
||||||
|
};
|
||||||
|
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 ? <h3> SKILL </h3> : <h3> SPEC </h3>;
|
||||||
|
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 ? <div>{fullInfo.cooldown} Turn delay</div> : null;
|
||||||
|
|
||||||
|
const speed = isSkill
|
||||||
|
? <div> Speed {shapes.SpeedStat()} multiplier {fullInfo.speed * 4}% </div>
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const thresholds = isSpec ? specThresholds(player, fullInfo, info) : null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={isSkill ? 'info-item' : 'info-item'}>
|
||||||
|
<h2>{infoName}</h2>
|
||||||
|
{header}
|
||||||
|
{itemSourceInfo}
|
||||||
|
{cooldown}
|
||||||
|
{itemDescription()}
|
||||||
|
{speed}
|
||||||
|
{thresholds}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div class="info-item">
|
||||||
|
<h2>{fullInfo.item}</h2>
|
||||||
|
{itemDescription()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const stateFullInfo = comboItem || vboxInfo;
|
||||||
|
if (stateFullInfo) return genItemInfo(stateFullInfo);
|
||||||
|
if (!info) return false;
|
||||||
|
if (info.includes('constructName')) {
|
||||||
|
return (
|
||||||
|
<div class='info-item'>
|
||||||
|
<h2> {info.replace('constructName ', '')} </h2>
|
||||||
|
<p> This is the name of your construct. <br />
|
||||||
|
Names are randomly generated and are purely cosmetic. <br />
|
||||||
|
You can change change your construct name in the <b>RESHAPE</b> tab outside of games.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.includes('constructAvatar')) {
|
||||||
|
return (
|
||||||
|
<div class='info-item'>
|
||||||
|
<h2> {info.replace('constructAvatar ', '')} </h2>
|
||||||
|
<p> This is your construct avatar. <br />
|
||||||
|
Avatars are randomly generated and are purely cosmetic. <br />
|
||||||
|
You can change your construct avatar in the <b>RESHAPE</b> tab outside of games.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return genItemInfo(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)))
|
||||||
|
? [<div key="0">{convertItem(c.components[0])} {convertItem(c.components[1])}</div>,
|
||||||
|
<div key="1">{convertItem(c.components[2])}</div>]
|
||||||
|
: c.components.map((u, j) => <div key={j} >{convertItem(u)}</div>);
|
||||||
|
return (
|
||||||
|
<div key={i} onMouseOver={mouseOver} class="table-button">
|
||||||
|
<div class="item">
|
||||||
|
{convertItem(c.item)}
|
||||||
|
</div>
|
||||||
|
{componentTable}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const comboList = comboTable.length > 0 ? <div class="combo-list">{comboTable}</div> : false;
|
||||||
|
return (
|
||||||
|
<div class="combos">
|
||||||
|
<div class="combo-header">
|
||||||
|
<h2>COMBOS</h2>
|
||||||
|
Combine colours and items.
|
||||||
|
</div>
|
||||||
|
{comboList}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Combiner = () => {
|
||||||
|
if (comboItem) return false;
|
||||||
|
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', '+');
|
||||||
|
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 (
|
||||||
|
<div class='combiner'>
|
||||||
|
<button
|
||||||
|
class='vbox-btn'
|
||||||
|
disabled={!mouseEvent}
|
||||||
|
onClick={e => e.stopPropagation()}
|
||||||
|
onMouseDown={() => mouseEvent()}>
|
||||||
|
{text}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class='info'>
|
||||||
|
<div onMouseOver={() => this.setState({ comboItem: null })}>
|
||||||
|
<div class='info-details'>
|
||||||
|
<Info />
|
||||||
|
<Combiner />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Combos />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = addState(InfoComponent);
|
||||||
@ -89,11 +89,7 @@ function specThresholds(player, fullInfo, info) {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div class="thresholds">
|
<div class="thresholds">
|
||||||
{thresholds[0]}
|
{thresholds}
|
||||||
{thresholds[1]}
|
|
||||||
</div>
|
|
||||||
<div class="thresholds">
|
|
||||||
{thresholds[2]}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ function stashElement(props) {
|
|||||||
class={stashHighlight ? 'receiving' : 'empty'} > </button>;
|
class={stashHighlight ? 'receiving' : 'empty'} > </button>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const comboHighlight = vboxHighlight && vboxHighlight.includes(v) ? 'combo-border' : '';
|
const notValidCombo = vboxHighlight && !vboxHighlight.includes(v);
|
||||||
|
|
||||||
function onClick(type) {
|
function onClick(type) {
|
||||||
const combinerContainsIndex = stashSelect.indexOf(i) > -1;
|
const combinerContainsIndex = stashSelect.indexOf(i) > -1;
|
||||||
@ -56,7 +56,7 @@ function stashElement(props) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!comboHighlight) {
|
if (notValidCombo) {
|
||||||
setInfo(vbox.bound[i]);
|
setInfo(vbox.bound[i]);
|
||||||
return setVboxSelected({ storeSelect: [], stashSelect: [i] });
|
return setVboxSelected({ storeSelect: [], stashSelect: [i] });
|
||||||
}
|
}
|
||||||
@ -68,7 +68,9 @@ function stashElement(props) {
|
|||||||
|
|
||||||
const highlighted = stashSelect.indexOf(i) > -1;
|
const highlighted = stashSelect.indexOf(i) > -1;
|
||||||
const border = buttons[removeTier(v)] ? buttons[removeTier(v)]() : '';
|
const border = buttons[removeTier(v)] ? buttons[removeTier(v)]() : '';
|
||||||
const classes = `${highlighted ? 'highlight' : border} ${comboHighlight}`;
|
const classes = highlighted
|
||||||
|
? 'highlight'
|
||||||
|
: `${border} ${notValidCombo ? 'fade' : ''}`;
|
||||||
|
|
||||||
const invObject = shapes[v] ? shapes[v]() : v;
|
const invObject = shapes[v] ? shapes[v]() : v;
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,6 @@ const shapes = require('./shapes');
|
|||||||
function storeElement(props) {
|
function storeElement(props) {
|
||||||
const {
|
const {
|
||||||
clearVboxSelected,
|
clearVboxSelected,
|
||||||
setInfo,
|
|
||||||
setVboxSelected,
|
setVboxSelected,
|
||||||
storeSelect,
|
storeSelect,
|
||||||
stashSelect,
|
stashSelect,
|
||||||
@ -20,11 +19,10 @@ function storeElement(props) {
|
|||||||
if (!v) return <button disabled class='empty' key={(group * 10) + index} > </button>;
|
if (!v) return <button disabled class='empty' key={(group * 10) + index} > </button>;
|
||||||
const selected = storeSelect.length && storeSelect.some(vs => vs[0] === group && vs[1] === index);
|
const selected = storeSelect.length && storeSelect.some(vs => vs[0] === group && vs[1] === index);
|
||||||
|
|
||||||
const comboHighlight = vboxHighlight && vboxHighlight.includes(v) ? 'combo-border' : '';
|
const notValidCombo = vboxHighlight && !vboxHighlight.includes(v);
|
||||||
|
|
||||||
function onClick(e) {
|
function onClick(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (!comboHighlight) setInfo(vbox.free[group][index]);
|
|
||||||
if (storeSelect.length && storeSelect.some(vs => vs[0] === group && vs[1] === index)) {
|
if (storeSelect.length && storeSelect.some(vs => vs[0] === group && vs[1] === index)) {
|
||||||
return setVboxSelected(
|
return setVboxSelected(
|
||||||
{ storeSelect: storeSelect.filter(vs => !(vs[0] === group && vs[1] === index)), stashSelect }
|
{ storeSelect: storeSelect.filter(vs => !(vs[0] === group && vs[1] === index)), stashSelect }
|
||||||
@ -34,20 +32,21 @@ function storeElement(props) {
|
|||||||
if (!storeSelect.length && !stashSelect.length) {
|
if (!storeSelect.length && !stashSelect.length) {
|
||||||
return setVboxSelected({ storeSelect: [[group, index]], stashSelect });
|
return setVboxSelected({ storeSelect: [[group, index]], stashSelect });
|
||||||
}
|
}
|
||||||
if (comboHighlight !== 'combo-border') {
|
if (notValidCombo) {
|
||||||
return setVboxSelected({ storeSelect: [[group, index]], stashSelect: [] });
|
return setVboxSelected({ storeSelect: [[group, index]], stashSelect: [] });
|
||||||
}
|
}
|
||||||
return setVboxSelected({ storeSelect: [...storeSelect, [group, index]], stashSelect });
|
return setVboxSelected({ storeSelect: [...storeSelect, [group, index]], stashSelect });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const classes = `${v.toLowerCase()} ${selected ? 'highlight' : ''} ${comboHighlight}`;
|
const classes = selected
|
||||||
|
? `${v.toLowerCase()} highlight`
|
||||||
|
: `${v.toLowerCase()} ${notValidCombo ? 'fade' : ''}`;
|
||||||
|
|
||||||
const vboxObject = shapes[v] ? shapes[v]() : v;
|
const vboxObject = shapes[v] ? shapes[v]() : v;
|
||||||
const disabled = vbox.bits <= group;
|
const disabled = vbox.bits <= group;
|
||||||
return (
|
return (
|
||||||
<label draggable='true'
|
<label
|
||||||
onDragStart={ev => ev.dataTransfer.setData('text', '')}
|
|
||||||
key={group * 10 + index}
|
key={group * 10 + index}
|
||||||
onDragEnd={clearVboxSelected}>
|
onDragEnd={clearVboxSelected}>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@ -171,7 +171,7 @@ impl Vbox {
|
|||||||
|
|
||||||
self.bound.push(combo.item);
|
self.bound.push(combo.item);
|
||||||
// self.bound.sort_unstable();
|
// self.bound.sort_unstable();
|
||||||
if self.bound.len() >= 6 {
|
if self.bound.len() > 6 {
|
||||||
return Err(err_msg("too many items bound"));
|
return Err(err_msg("too many items bound"));
|
||||||
}
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user