diff --git a/WORKLOG.md b/WORKLOG.md index 9ea59bde..daaaefb6 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -1,10 +1,43 @@ # WORK WORK ## NOW -*PRODUCTION* - +_ntr_ * can't reset password without knowing password =\ +* skip faceoff on server side +* change cooldowns to delay & recharge + - delay is cooldown before skill can first be used + - recharge is cooldown after using skill + - every x speed reduces delay of skills +* audio + * animation effects + * vbox combine / buy / equip etc + * background music +* effects rework +Siphon = +[ + DamageBlue(50%), + Apply( + Siphon(2T) + - Siphoning(2T) + ), +] + +Hexagon Set +- Pick Colour +- Random Walk +- Draw hex +- Increase intensity for each visit + +_mashy_ +* buy from preview if you have the required bases in vbox / inventory + - a "buy" becomes available under the current info / preview section + - clicking the buy automatically purchases / combine items + - could also be used to upgrade already equipped skills / specs + - e.g. an equipped white power spec could be upgraded by clicking under preview + - if this was added we could reduce inventory size to 3 and rearrange vbox (see mockup img) + +_external_ * Graphics * Img * Skill Icons @@ -15,42 +48,17 @@ - Speed (e.g. boots) - Life (e.g. heart) -* reduce inventory size and consolidate vbox and inventory on left side - -* audio - * background music - * animation effects - * vbox combine / buy / equip etc - -* reclaim change colour from red (clashes with red items) - -* represent construct colours during game phase (coloured border?) +_tba_ * supporter gold name in instance (anyone whos put any money into game) - -* Give the bots some ai / make stronger so its a challenge for new people to beat - - train a few games of with some round losses to get them into the game - +* represent construct colours during game phase (coloured border?) * Speed up animations slightly (3s per normal event too long) - Improve combat text to start at the opposite end of construct and float towards health stats - Show combat text for skill cast possibly? Watch some pokemans etc for modern combat smoothing - -* skip faceoff on server side +* Give the bots some ai / make stronger so its a challenge for new people to beat + - train a few games of with some round losses to get them into the game ## SOON -* buy from preview if you have the required bases in vbox / inventory - - a "buy" becomes available under the current info / preview section - - clicking the buy automatically purchases / combine items - - could also be used to upgrade already equipped skills / specs - - e.g. an equipped white power spec could be upgraded by clicking under preview - - if this was added we could reduce inventory size to 3 and rearrange vbox (see mockup img) - - -* change cooldowns to delay & recharge - - delay is cooldown before skill can first be used - - recharge is cooldown after using skill - - every x speed reduces delay of skills - * combo rework - reduce number of items for creating t2/t3 items from 3 -> 2 - add lost complexity by adding skill spec items @@ -61,18 +69,14 @@ - Strike + SpeedRR -> StrikeSpeed (strike has Y% more speed) - Strike + LifeRR -> StrikeLife (Strike recharges X% of damage as red life) - - Can also work as module style passive keystones + - Can also work as module style passive keystones * troll life -> dmg -> Invert life spec? - * prince of peace + * prince of peace * bonus healing / no damage -> Heal power spec? * fuck magic -> Some sort of reflect spec? * empower on ko -> Amplify + Power spec * elo + leaderboards -* reconnect based on time delta - -* ACP - * essential ## LATER @@ -95,8 +99,8 @@ - Working as cooldowns in reverse by building up to the skill rather than waiting * constants -* (maybe) return of the combat log (last few events with condensed descriptions) - - click in to scroll +* return of the combat log (last few events with condensed descriptions) + - button to switch context or overlay the combatlog * mnml tv diff --git a/client/assets/styles/account.less b/client/assets/styles/account.less index a52e6e5b..c920c8dc 100644 --- a/client/assets/styles/account.less +++ b/client/assets/styles/account.less @@ -44,7 +44,7 @@ } &[disabled] { - border: 1px solid @yellow; + border: 0.1em solid @yellow; color: @yellow; background: black; } diff --git a/client/assets/styles/colours.less b/client/assets/styles/colours.less index a1ae5dcb..16e972af 100644 --- a/client/assets/styles/colours.less +++ b/client/assets/styles/colours.less @@ -5,6 +5,7 @@ @white: #f5f5f5; // whitesmoke @purple: #9355b5; // 6lack - that far cover @yellow: #ffa100; +@silver: #c0c0c0; @black: black; @gray: #222; diff --git a/client/assets/styles/controls.less b/client/assets/styles/controls.less index 0bdb4b59..a5938475 100644 --- a/client/assets/styles/controls.less +++ b/client/assets/styles/controls.less @@ -60,7 +60,7 @@ aside { width: 0.25em; max-width: 0.25em; - margin: 0 1em 0 0; + margin: 0 0.5em 0 0; border: none; } @@ -150,13 +150,13 @@ aside { &:hover { color: @red; border-color: @red; - border: 2px solid @red; + border: 0.1em solid @red; }; &:active, &.confirming { background: @red; color: black; - border: 2px solid @red; + border: 0.1em solid @red; } } @@ -164,7 +164,7 @@ aside { &:active, &.confirming { background: @gray-hover; color: black; - border: 2px solid @gray-hover; + border: 0.1em solid @gray-hover; } } diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index 4ddacc63..ea48cede 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -27,6 +27,7 @@ position: absolute; bottom: 0; + margin-bottom: 0.5em; height: 50%; .avatar { @@ -148,17 +149,13 @@ z-index: 2; button { width: 100%; - height: 2em; + height: 3em; + line-height: 1; margin-right: 1em; - span { - background-color: black; - } + background-color: black; } button.active { - background: #2c2c2c; - span { - background-color: #2c2c2c; - } + background-color: #2c2c2c; } } @@ -236,8 +233,8 @@ #targeting, .resolving-skill { position: absolute; - top: 35%; - height: 15%; + top: calc(35% + 0.5em); // calc for 0.5em top gap + height: calc(15% - 1em); // calc for 0.5em + 0.5em top / bottom gap width: calc(90% - 1.25em); z-index: 2; span { @@ -266,9 +263,7 @@ padding-right: 1em; text-align: center; z-index: 2; - span { - background-color: black; - } + background-color: black; svg { display: inline; height: 1em; @@ -279,7 +274,7 @@ /* some stupid bug in chrome makes it fill the entire screen */ @media screen and (-webkit-min-device-pixel-ratio:0) { #targeting { - max-height: 10em; + // max-height: 10em; } } diff --git a/client/assets/styles/instance.less b/client/assets/styles/instance.less index e54bf31e..52ad8fea 100644 --- a/client/assets/styles/instance.less +++ b/client/assets/styles/instance.less @@ -1,129 +1,21 @@ -.instance { - overflow: hidden; - display: grid; - grid-template-columns: 1fr minmax(min-content, 1fr); - grid-template-rows: min-content 1fr; - - grid-template-areas: - "vbox info" - "constructs constructs"; -} - -@media (max-width: 1920px) { - .instance .info table td svg { - // height: 50%; - stroke-width: 8px; - } - - .instance svg { - height: 1.5em; - } -} - -.instance .top { - grid-area: top; -} - .instance.lobby { align-content: center; } -.scoreboard { - flex: 1; -} - -.instance .info { - margin: 0 0 0 1em; - grid-area: info; - +.instance { + overflow: hidden; display: grid; - grid-template-rows: 13em min-content; + grid-template-rows: min-content 1fr; + grid-template-areas: - "item" - "combos"; + "vbox" + "constructs"; - .combos { - display: grid; - grid-template-columns: repeat(6, 1fr); - align-content: center; - - .table-button { - display: grid; - text-align: center; - align-content: center; - border-bottom: 2px solid #222; - - 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 { - border-right: 2px solid #222; - svg { - vertical-align: middle; - } - } - - &:first-child { - div { - border-left: 2px solid #222; - } - } - } + .constructs { + grid-area: constructs; } } -.instance .info h2 { - text-transform: uppercase; -} - -.instance .info svg { - display: inline; - height: 1em; -} - -.instance .info figure { - display: inline; - height: 0.5em; - - svg { - margin-right: 0.5em; - } -} - -.instance .info figcaption { - font-size: 1em; - display: inline-block; - vertical-align: middle; -} - - -.instance .constructs { - grid-area: constructs; -} - -.instance .equip { - grid-area: equip; -} - -.instance .equip .skills { - border-right-width: 0; -} - @keyframes action { 0% { color: palegoldenrod; @@ -135,10 +27,6 @@ /* CONSTRUCT LIST */ -.construct-list { - grid-area: constructs; - display: flex; -} .instance-construct { flex: 1; @@ -152,20 +40,22 @@ "stats "; /*padding: 0.5em;*/ - border: 2px solid #222; + border: 0.1em solid #222; border-left-width: 0; -} - -.instance-construct:first-child { - margin-left: 0; - border-left-width: 1px; + &:first-child { + margin-left: 0; + border-left-width: 1px; + } } .construct-list { + grid-area: constructs; + display: flex; + button { &.highlight { color: black; - background: @white; + background: @silver; // border: 1px solid @white; (this bangs around the vbox) // overwrite the classes on white svg elements @@ -264,95 +154,10 @@ } } -/* Equipment */ -.equip { - display: flex; - margin: 1.5em 0; - text-align: center; -} - -.equip h3 { - margin-bottom: 0.5em; - text-transform: uppercase; - font-weight: bold; - letter-spacing: 0.1em; -} - -.equip .specs { - flex: 1; - border: 2px solid #222; -} - -.equip .items { - display: flex; - flex: 1 0 100%; - justify-content: space-around; -} - .label { flex: 1 0 100%; } -// .equipping { -// position: relative; -// } - -// .equipping::before { -// content: ''; -// position: absolute; -// top: 2px; -// left: 50%; -// width: 100%; -// height: 2px; -// transform-origin: center; -// background-color: whitesmoke; -// animation: equipping-skill 2s infinite ease-out alternate; -// opacity: 0; -// } - -// .equipping::after { -// content: ''; -// position: absolute; -// bottom: 2px; -// left: 50%; -// width: 100%; -// height: 2px; -// transform-origin: center; -// background-color: whitesmoke; -// animation: equipping-skill 2s infinite ease-out alternate; -// opacity: 0; -// animation-delay: 0.75s -// } - -// @keyframes equipping-skill { -// from { -// transform: translate(-50%, 0) scaleX(0); -// } - -// to { -// transform: translate(-50%, 0) scaleX(0.75); -// opacity: 1; -// } -// } - -// .equip-spec { -// position: relative; -// stroke: #333; -// } - -// .equip-spec::after { -// content: ''; -// position: absolute; -// bottom: 2px; -// left: 50%; -// width: 100%; -// height: 2px; -// transform-origin: center; -// background-color: whitesmoke; -// animation: equipping-skill 2s infinite ease-out alternate; -// opacity: 0; -// } - .equipping, .receiving { animation: eq 0.75s cubic-bezier(0, 0, 1, 1) 0s infinite alternate; } @@ -484,9 +289,4 @@ to { color: @yellow; } -} - -/* Mobile Nav*/ -.instance-nav { display: none; } - -.vbox-arrow-mobile { display: none } +} \ No newline at end of file diff --git a/client/assets/styles/instance.mobile.less b/client/assets/styles/instance.mobile.less deleted file mode 100644 index 3b68cc7f..00000000 --- a/client/assets/styles/instance.mobile.less +++ /dev/null @@ -1,29 +0,0 @@ -// tablet / ipad -@media (max-width: 1100px) { - .instance { - grid-template-columns: 1fr; - grid-template-rows: min-content 1fr; - grid-template-areas: - "vbox" - "constructs"; - - .info { - display: none; - } - } -} - -@media (max-width: 800px) { - .instance { - font-size: 6pt; - grid-template-columns: 1fr; - grid-template-rows: min-content 1fr; - grid-template-areas: - "vbox" - "constructs"; - - .info { - display: none; - } - } -} \ No newline at end of file diff --git a/client/assets/styles/menu.less b/client/assets/styles/menu.less index 1ce06f73..e197781e 100644 --- a/client/assets/styles/menu.less +++ b/client/assets/styles/menu.less @@ -74,7 +74,7 @@ button { flex: 1; border-top: 0; - border: 2px solid #222; + border: 0.1em solid #222; &:not(:last-child) { border-right: 0; } diff --git a/client/assets/styles/player.less b/client/assets/styles/player.less index d731e418..bdcf2477 100644 --- a/client/assets/styles/player.less +++ b/client/assets/styles/player.less @@ -42,6 +42,7 @@ .msg { grid-area: msg; + text-transform: uppercase; color: @white; } diff --git a/client/assets/styles/skeleton.css b/client/assets/styles/skeleton.css index 13bb3549..037e1747 100644 --- a/client/assets/styles/skeleton.css +++ b/client/assets/styles/skeleton.css @@ -176,7 +176,6 @@ input[type="button"] { /*padding: 0 2em;*/ color: #555; text-align: center; - font-size: 11px; font-weight: 600; line-height: 38px; letter-spacing: .1rem; diff --git a/client/assets/styles/styles.less b/client/assets/styles/styles.less index 3a9edf37..b22ee13d 100644 --- a/client/assets/styles/styles.less +++ b/client/assets/styles/styles.less @@ -8,8 +8,6 @@ @import 'vbox.less'; @import 'game.less'; @import 'player.less'; -@import 'styles.mobile.less'; -@import 'instance.mobile.less'; html body { margin: 0; @@ -23,6 +21,7 @@ html body { -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; + -webkit-tap-highlight-color: transparent; overflow-x: hidden; overflow-y: hidden; @@ -33,7 +32,6 @@ html body { height: 100vh; max-height: 100vh; min-height: 100vh; - /*padding: 0 20%;*/ /* stops inspector going skitz*/ overflow-x: hidden; @@ -125,14 +123,19 @@ button, input { font-family: 'Jura'; color: whitesmoke; height: auto; - border-width: 2px; + border-width: 0.1em; border-color: @gray-exists; letter-spacing: 0.25em; box-sizing: border-box; - font-size: 100%; + font-size: 1em; flex: 1; border-radius: 0.5em; line-height: 2em; + padding-right: 0.1em; + padding-left: 0.1em; + padding-bottom: 0.1em; + padding-top: 0.1em; + /*the transitions */ transition-property: border-color, color, background; @@ -250,6 +253,7 @@ figure.gray { svg { height: 1em; + stroke-width: 1em; } } @@ -354,3 +358,5 @@ li { flex: 1; } } + +@import 'styles.mobile.less'; diff --git a/client/assets/styles/styles.mobile.less b/client/assets/styles/styles.mobile.less index e46e31a0..0c80a7bd 100644 --- a/client/assets/styles/styles.mobile.less +++ b/client/assets/styles/styles.mobile.less @@ -1,26 +1,43 @@ -@media (max-width: 1000px) { +@media (max-width: 800px) { body { overflow-y: initial; } #mnml { font-size: 8pt; - padding: 0.25em; + padding: 0; .instance { - grid-template-columns: 1fr; - grid-template-rows: min-content 1fr; - grid-template-areas: - "vbox" - "constructs"; + "vbox vbox" + "constructs constructs"; + + font-size: 7.5pt; + + .stats { + div:nth-child(4n) { + margin: 0; + } + } svg { stroke-width: 1.25em; } + } .game { + font-size: 7.5pt; + .stats { + svg { + stroke-width: 1.5em; + } + + div:nth-child(4n) { + margin: 0 0.25em; + } + } + .team, #targeting, .resolving-skill { width: calc(90% - 3em); } @@ -29,7 +46,6 @@ grid-template-columns: 1fr; grid-template-rows: min-content 1fr; - .avatar { grid-area: initial; position: absolute; @@ -45,17 +61,22 @@ } .skills { - button[disabled] { - display: none; + display: grid; + grid-template-rows: 1fr; + grid-template-columns: 1fr 1fr 1fr; + button { + font-size: 1em; + letter-spacing: 0.1em; } + + } .effects { - font-size: 1em; + font-size: 1.1em; } .skill-description { - font-size: 0.8em; svg { height: 1em; } @@ -100,21 +121,31 @@ .instance-construct { position: relative; + grid-template-columns: 1fr 1fr; + grid-template-rows: min-content min-content 1fr min-content; + grid-template-areas: + "skills skills" + "specs specs" + "avatar name" + "stats stats "; + .skills, .specs { font-size: 75%; } - .avatar { - grid-area: initial; - position: absolute; - top: 0; - height: 100%; - width: 100%; - z-index: -1; + .stats { + svg { + height: 1em; + } + } + + .name { + align-self: center; } } aside { + font-size: 75%; button { margin-bottom: 0.5em; } @@ -123,8 +154,8 @@ } -// portrait menu -@media (max-width: 600px) { +// portrait menu or small size vertical in landscape +@media (max-width: 550px) and (max-height: 800px) { #mnml { grid-template-columns: 1fr; grid-template-rows: 1fr; @@ -166,7 +197,7 @@ grid-template-columns: repeat(2, 1fr); button:not(:last-child) { - border: 2px solid #222; + border: 0.1em solid #222; } button.logo { @@ -191,9 +222,103 @@ } } + .stats { + font-size: 6pt; + } + + .skill-description { + font-size: 6pt; + } + section { .list { grid-template-columns: 1fr; } } -} \ No newline at end of file +} + +@media (max-width: 600px) { + .vbox { + grid-template-rows: min-content min-content 1fr; + grid-template-columns: min-content 1fr min-content 1fr; + grid-template-areas: + "store-hdr store-hdr stash-hdr stash-hdr" + "store store stash stash" + "store store combiner combiner"; + + > div { + padding: 0.25em; + } + + .info { + display: none; + } + + .combos { + display: none; + } + + .combiner { + margin: 0; + } + + .stash { + border: 0; + border-top: 0.1em solid @gray; + border-right: 0.1em solid @gray; + border-bottom: 0.1em solid @gray; + } + + .stash-hdr { + border: 0; + border-left: 0.1em solid @gray; + border-right: 0.1em solid @gray; + + display: grid; + grid-template-rows: min-content min-content; + grid-template-columns: 1fr 1fr; + + h3 { + margin: 0; + } + } + + .store { + border: 0; + border-top: 0.1em solid @gray; + border-bottom: 0.1em solid @gray; + border-right: 0.1em solid @gray; + } + + .store-hdr { + display: grid; + grid-template-columns: min-content min-content 1fr; + + > * { + margin-right: 1em; + } + + grid-template-areas: + "hdr bits btn"; + + h1 { + grid-area: hdr; + margin-bottom: 0.25em; + } + + .bits { + grid-area: bits; + } + + button { + grid-area: btn; + } + } + + .store-hdr, .stash-hdr { + button { + margin: 0; + } + } + } +} diff --git a/client/assets/styles/vbox.less b/client/assets/styles/vbox.less index ea0d9fd7..2e3bbde8 100644 --- a/client/assets/styles/vbox.less +++ b/client/assets/styles/vbox.less @@ -1,6 +1,79 @@ .vbox { - margin-bottom: 2em; - line-height: 0; + align-content: space-between; + grid-area: vbox; + display: grid; + grid-template-rows: 3fr minmax(min-content, 2fr); + grid-template-columns: 1fr 4fr 6fr 17em; // =\ + grid-template-areas: + "store-hdr store info combos" + "stash-hdr stash combiner combos"; + margin-bottom: 1em; + + // immediate children + > div { + padding: 0.5em; + } + + .store { + grid-area: store; + border-right: 0.15em solid @gray; + border-top: 0.15em solid @gray; + } + + .store-hdr { + grid-area: store-hdr; + display: flex; + flex-flow: column; + + text-align: center; + border-left: 0.15em solid @gray; + border-top: 0.15em solid @gray; + + h1 { + margin-bottom: 0.5em; + } + + button { + line-height: 1.6; + letter-spacing: 0.15em; + background-color: #421010; + &:hover { + background-color: @red; + + } + } + } + + .stash { + grid-area: stash; + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-gap: 0.5em 1em; + + align-items: center; + border: 0.15em solid @gray; + border-left: 0; + } + + .stash-hdr { + grid-area: stash-hdr; + display: flex; + flex-flow: column; + + text-align: center; + border: 0.15em solid @gray; + border-right: 0; + + h2 { + margin-bottom: 0.5em; + } + + button { + line-height: 1.6; + letter-spacing: 0.15em; + } + } + .vbox-hdr { margin-bottom: 1em; height: 2em; @@ -19,14 +92,12 @@ grid-template-columns: repeat(3, 1fr); grid-gap: 0.5em 1em; align-items: center; - margin-bottom: 0.5em; } .vbox-btn { width: 100%; margin: 0; background-color: @gray-box; - height: 3em; line-height: 1em; border-width: 0; @@ -34,14 +105,6 @@ color: white; } - &.reclaim { - height: auto; - - &:hover { - color: @red; - }; - } - &[disabled] { background: black; border-width: 1px; @@ -53,7 +116,7 @@ &, &:hover, &:active { background: @red; color: black; - border: 2px solid black; + border: 0.1em solid black; } } svg { @@ -65,19 +128,22 @@ } button { - height: 4em; + height: 3.5em; margin: 0; width: 100%; // text-transform: none; - &.empty { border-style: dashed; } + &.fade { + opacity: 0.4; + } + &.highlight { color: black; - background: @white; + background: @silver; // border: 1px solid @white; (this bangs around the vbox) // overwrite the classes on white svg elements @@ -94,7 +160,7 @@ // figures don't scale well figure { svg { - height: 2em; + height: 1.5em; stroke-width: 0.5em; } @@ -102,63 +168,143 @@ 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; + } + + .combiner { + grid-area: combiner; + // align-self: flex-end; + height: 100%; + margin: 0 0.5em; + line-height: 1.3; + font-size: 1.25em; + letter-spacing: 0.1em; + border: 0.1em solid @gray-exists; + &:hover { + border: 0.1em solid @gray-hover; + } + } + + .combos { + display: grid; + grid-area: combos; + margin-left: 0.5em; + grid-template-rows: min-content min-content; + grid-template-areas: + "comboHeader" + "comboList"; + + 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; + } + + + .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: 0.1em solid #222; + border-bottom: 0.1em solid #222; + flex: 1; + grid-area: item; + font-weight: bold; + div { + width: 5em; + } + } + + + div { + border-left: 0.1em solid #222; + border-right: 0.1em solid #222; + height: 1.75em; + width: 7.5em; + svg { + vertical-align: middle; + } + &:last-child { + border-bottom: 0.1em solid #222; + } + } + } + } + } } -/* VBOX */ -.vbox { - align-content: space-between; - grid-area: vbox; - display: grid; - grid-template-rows: min-content min-content min-content; - grid-template-columns: 1fr min-content 1fr; - grid-template-areas: - "vbox varrow inventory" - "vbox varrow combiner"; -} - -.vbox-inventory { - grid-area: inventory; -} - -.vbox-combiner { - grid-area: combiner; - display: flex; - flex-flow: column; - justify-content: flex-end; -} - -.vbox-arrow, .vbox-arrow-mobile { - display: flex; - justify-content:center; - align-content:center; - flex-direction:column; - - margin: 1em 0.25em 0 0.25em; - grid-area: varrow; - font-size: 2em; - color: @gray-hint; -} - -.vbox-combiner button { - flex: 0; -} - - -.vbox-hdr { - display: flex; -} - -.vbox-hdr h3 { - flex: 1; -} - -.vbox-hdr .bits { - font-size: 2em; - line-height: 1em; - animation: bits 1s ease-out; -} - -.arrow { - grid-area: arrow; - color: @gray-hint; -} +@media (min-width: 2000px) { + .vbox { + button { + height: 4.5em; + } + } +} \ No newline at end of file diff --git a/client/src/actions.jsx b/client/src/actions.jsx index 87d0cf51..0c1456af 100644 --- a/client/src/actions.jsx +++ b/client/src/actions.jsx @@ -35,7 +35,6 @@ export const setMtxActive = value => ({ type: 'SET_MTX_ACTIVE', value }); export const setNav = value => ({ type: 'SET_NAV', value }); export const setPing = value => ({ type: 'SET_PING', value }); export const setPlayer = value => ({ type: 'SET_PLAYER', value }); -export const setReclaiming = value => ({ type: 'SET_RECLAIMING', value }); export const setShowLog = value => ({ type: 'SET_SHOW_LOG', value }); export const setShop = value => ({ type: 'SET_SHOP', value }); export const setSubscription = value => ({ type: 'SET_SUBSCRIPTION', value }); @@ -48,7 +47,6 @@ export const setTeamSelect = value => ({ type: 'SET_TEAM_SELECT', value: Array.f export const setTutorial = value => ({ type: 'SET_TUTORIAL', value }); export const setTutorialGame = value => ({ type: 'SET_TUTORIAL_GAME', value }); -export const setVboxHighlight = value => ({ type: 'SET_VBOX_HIGHLIGHT', value }); export const setVboxSelected = value => ({ type: 'SET_VBOX_SELECTED', value }); export const setWs = value => ({ type: 'SET_WS', value }); diff --git a/client/src/components/account.status.jsx b/client/src/components/account.status.jsx index 99e5014e..1353deff 100644 --- a/client/src/components/account.status.jsx +++ b/client/src/components/account.status.jsx @@ -33,11 +33,9 @@ const addState = connect( function accountPage() { dispatch(actions.setGame(null)); dispatch(actions.setInstance(null)); - dispatch(actions.setReclaiming(false)); dispatch(actions.setActiveSkill(null)); dispatch(actions.setInfo(null)); dispatch(actions.setItemUnequip([])); - dispatch(actions.setVboxHighlight([])); return dispatch(actions.setNav('account')); } diff --git a/client/src/components/demo.jsx b/client/src/components/demo.jsx index 494015ef..e6bee9eb 100644 --- a/client/src/components/demo.jsx +++ b/client/src/components/demo.jsx @@ -46,7 +46,7 @@ function Demo(args) { const { combiner, items, equipping, equipped, players, combo } = demo; const vboxDemo = () => { - function inventoryBtn(i, j) { + function stashBtn(i, j) { if (!i) return ; const highlighted = combiner.indexOf(j) > -1; const classes = `${highlighted ? 'highlight' : ''}`; @@ -82,7 +82,7 @@ function Demo(args) { ); } - function inventoryElement() { + function stashElement() { return (
@@ -96,7 +96,7 @@ function Demo(args) {
 
- {items.map((i, j) => inventoryBtn(i, j))} + {items.map((i, j) => stashBtn(i, j))}
{combinerBtn()}
@@ -106,7 +106,7 @@ function Demo(args) { return (
- {inventoryElement()} + {stashElement()}
); }; diff --git a/client/src/components/header.jsx b/client/src/components/header.jsx index b591afe0..734b1761 100644 --- a/client/src/components/header.jsx +++ b/client/src/components/header.jsx @@ -32,11 +32,9 @@ const addState = connect( function setNav(place) { dispatch(actions.setGame(null)); dispatch(actions.setInstance(null)); - dispatch(actions.setReclaiming(false)); dispatch(actions.setActiveSkill(null)); dispatch(actions.setInfo(null)); dispatch(actions.setItemUnequip([])); - dispatch(actions.setVboxHighlight([])); dispatch(actions.setMtxActive(null)); return dispatch(actions.setNav(place)); } diff --git a/client/src/components/info.component.jsx b/client/src/components/info.component.jsx deleted file mode 100644 index 71360599..00000000 --- a/client/src/components/info.component.jsx +++ /dev/null @@ -1,184 +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 ( -
-

{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} {fullInfo.cost}b

- {header} - {itemSourceInfo} - {cooldown} - {itemDescription()} - {speed} - {thresholds} -
- ); - } - const cost = fullInfo.cost ? `- ${fullInfo.cost}b` : false; - return ( -
-

{fullInfo.item} {cost}

- {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 generalNotes; - if (!info) return generalNotes; - - const vboxCombos = itemInfo.combos.filter(c => c.components.includes(info)); - if (vboxCombos.length > 6 || vboxCombos.length === 0) return generalNotes; - - 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 ( -
setInfo(c.item)}> -
- {convertItem(c.item)} -
- {componentTable} -
- ); - }); - return ( -
- {comboTable} -
- ); - }; - - 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 8b6c2377..c59b5833 100644 --- a/client/src/components/instance.component.jsx +++ b/client/src/components/instance.component.jsx @@ -2,7 +2,6 @@ const preact = require('preact'); const { connect } = require('preact-redux'); const Vbox = require('./vbox.component'); -const InfoContainer = require('./info.container'); const InstanceConstructsContainer = require('./instance.constructs'); const Faceoff = require('./faceoff'); @@ -27,10 +26,8 @@ const addState = connect( function clearItems() { - dispatch(actions.setReclaiming(false)); dispatch(actions.setItemUnequip([])); - dispatch(actions.setVboxHighlight([])); - dispatch(actions.setVboxSelected({ shopSelect: [], stashSelect: [] })); + dispatch(actions.setVboxSelected({ storeSelect: [], stashSelect: [] })); return true; } @@ -58,14 +55,9 @@ function Instance(args) { clearItems(); } - function onTouchMove(e) { - e.preventDefault(); - } - return (
-
); diff --git a/client/src/components/instance.constructs.jsx b/client/src/components/instance.constructs.jsx index 59e77b10..c0a0b36d 100644 --- a/client/src/components/instance.constructs.jsx +++ b/client/src/components/instance.constructs.jsx @@ -25,7 +25,7 @@ const addState = connect( } = state; function sendVboxAcceptEquip(constructId) { - return ws.sendVboxAcceptEquip(instance.id, vboxSelected.shopSelect[0][0], vboxSelected.shopSelect[0][1], constructId); + return ws.sendVboxAcceptEquip(instance.id, vboxSelected.storeSelect[0][0], vboxSelected.storeSelect[0][1], constructId); } function sendVboxApply(constructId, i) { @@ -60,7 +60,7 @@ const addState = connect( } function setItemUnequip(v) { - dispatch(actions.setVboxSelected({ shopSelect: [], stashSelect: [] })); + dispatch(actions.setVboxSelected({ storeSelect: [], stashSelect: [] })); return dispatch(actions.setItemUnequip(v)); } @@ -91,7 +91,7 @@ function Construct(props) { const { vbox } = player; - const itemEquip = vboxSelected.shopSelect.length === 0 && vboxSelected.stashSelect.length === 1 + const itemEquip = vboxSelected.storeSelect.length === 0 && vboxSelected.stashSelect.length === 1 ? vboxSelected.stashSelect[0] : -1; @@ -106,7 +106,7 @@ function Construct(props) { e.preventDefault(); if (duplicateSkill || tutorialDisableEquip) return true; if (itemEquip !== -1) return sendVboxApply(construct.id, itemEquip); - if (vboxSelected.shopSelect.length === 1) return sendVboxAcceptEquip(construct.id); + if (vboxSelected.storeSelect.length === 1) return sendVboxAcceptEquip(construct.id); if (itemUnequip.length && itemUnequip[0] !== construct.id) return sendVboxUnequipApply(construct.id); setItemUnequip([]); return true; @@ -114,7 +114,7 @@ function Construct(props) { function hoverInfo(e, info) { e.stopPropagation(); if (!info) return false; - if (vboxSelected.shopSelect.length || vboxSelected.stashSelect.length) return false; + if (vboxSelected.storeSelect.length || vboxSelected.stashSelect.length) return false; return setInfo(info); } @@ -129,8 +129,10 @@ function Construct(props) { function skillClick(e) { if (!skill) return false; - setItemUnequip([construct.id, skill.skill, i]); 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; } @@ -177,8 +179,11 @@ function Construct(props) { } function specClick(e) { + if (!s) return false; 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]; @@ -258,7 +263,6 @@ class InstanceConstructs extends preact.Component { sendVboxApply, sendVboxAcceptEquip, sendVboxUnequipApply, - setVboxHighlight, setItemUnequip, } = props; @@ -281,7 +285,6 @@ class InstanceConstructs extends preact.Component { sendVboxUnequipApply, setInfo, itemInfo, - setVboxHighlight, vboxSelected, tutorial, }); diff --git a/client/src/components/instance.ctrl.top.btns.jsx b/client/src/components/instance.ctrl.top.btns.jsx index 108485f7..7fc4f018 100644 --- a/client/src/components/instance.ctrl.top.btns.jsx +++ b/client/src/components/instance.ctrl.top.btns.jsx @@ -26,6 +26,9 @@ const addState = connect( dispatch(actions.setNav('play')); dispatch(actions.setGame(null)); dispatch(actions.setInstance(null)); + dispatch(actions.setVboxSelected({ storeSelect: [], stashSelect: [] })); + dispatch(actions.setInfo(null)); + dispatch(actions.setItemUnequip([])); if (tutorial) dispatch(actions.setTutorial(1)); } diff --git a/client/src/components/mnml.jsx b/client/src/components/mnml.jsx index 7a5e94e0..d1a632ce 100644 --- a/client/src/components/mnml.jsx +++ b/client/src/components/mnml.jsx @@ -15,7 +15,7 @@ function Mnml(args) { instance, } = args; - const rotateClass = (game || instance) && window.innerWidth < window.innerHeight + const rotateClass = (game || instance) && window.innerHeight < 900 && window.innerWidth < window.innerHeight ? 'show' : ''; diff --git a/client/src/components/nav.jsx b/client/src/components/nav.jsx index 0c845c8f..505c41c3 100644 --- a/client/src/components/nav.jsx +++ b/client/src/components/nav.jsx @@ -33,11 +33,9 @@ const addState = connect( function setNav(place) { dispatch(actions.setGame(null)); dispatch(actions.setInstance(null)); - dispatch(actions.setReclaiming(false)); dispatch(actions.setActiveSkill(null)); dispatch(actions.setInfo(null)); dispatch(actions.setItemUnequip([])); - dispatch(actions.setVboxHighlight([])); return dispatch(actions.setNav(place)); } diff --git a/client/src/components/skill.btn.jsx b/client/src/components/skill.btn.jsx index 6f96e410..d7be22be 100644 --- a/client/src/components/skill.btn.jsx +++ b/client/src/components/skill.btn.jsx @@ -69,7 +69,7 @@ function Skill(props) { // return false; // } const cdText = construct.skills[i].cd > 0 - ? `- ${s.cd}T` + ? `${s.cd}T` : ''; const highlight = activeSkill @@ -91,7 +91,7 @@ function Skill(props) { onMouseOut={e => hoverInfo(e, null)} type="submit" onClick={onClick}> - {s.skill} {cdText} + {s.skill}
{cdText}
); } diff --git a/client/src/components/targeting.arrows.jsx b/client/src/components/targeting.arrows.jsx index f93966c5..a7a7e4b3 100644 --- a/client/src/components/targeting.arrows.jsx +++ b/client/src/components/targeting.arrows.jsx @@ -110,8 +110,11 @@ class TargetSvg extends Component { ? playerTeam.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 sourceX = (source * width / 3) + width / 24; + const sourceX = (source * width / 3) + width / 18 + skillNumber * (width / 9); const targetX = (target * width / 3) + width / 6 + (defensive ? width / 64 : 0) + (source * width / 18); diff --git a/client/src/components/vbox.combiner.jsx b/client/src/components/vbox.combiner.jsx new file mode 100644 index 00000000..93051a33 --- /dev/null +++ b/client/src/components/vbox.combiner.jsx @@ -0,0 +1,104 @@ +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, + vboxSelected, + // Static + player, + itemInfo, + // functions + sendVboxAccept, + 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', '+'); + 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 ( + + ); +} + +module.exports = addState(Combiner); diff --git a/client/src/components/vbox.combos.jsx b/client/src/components/vbox.combos.jsx new file mode 100644 index 00000000..410252d0 --- /dev/null +++ b/client/src/components/vbox.combos.jsx @@ -0,0 +1,141 @@ +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 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 Combos(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(); + + 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} +
+ ); +} + +module.exports = addState(Combos); diff --git a/client/src/components/vbox.component.jsx b/client/src/components/vbox.component.jsx index a0329268..2f808f08 100644 --- a/client/src/components/vbox.component.jsx +++ b/client/src/components/vbox.component.jsx @@ -1,14 +1,15 @@ const preact = require('preact'); const { connect } = require('preact-redux'); -const range = require('lodash/range'); const countBy = require('lodash/countBy'); -const without = require('lodash/without'); const forEach = require('lodash/forEach'); -const { removeTier } = require('../utils'); -const shapes = require('./shapes'); const actions = require('../actions'); -const buttons = require('./buttons'); + +const InfoContainer = require('./vbox.info'); +const StashElement = require('./vbox.stash'); +const StoreElement = require('./vbox.store'); +const Combiner = require('./vbox.combiner'); +const Combos = require('./vbox.combos'); const addState = connect( function receiveState(state) { @@ -16,8 +17,8 @@ const addState = connect( ws, instance, player, - reclaiming, vboxSelected, + info, itemInfo, itemUnequip, tutorial, @@ -32,10 +33,6 @@ const addState = connect( return ws.sendVboxAccept(instance.id, group, index); } - function sendVboxCombine() { - return ws.sendVboxCombine(instance.id, vboxSelected.stashSelect, vboxSelected.shopSelect); - } - function sendVboxReclaim(i) { return ws.sendVboxReclaim(instance.id, i); } @@ -46,10 +43,9 @@ const addState = connect( return { instance, + info, player, - reclaiming, sendVboxAccept, - sendVboxCombine, sendVboxDiscard, sendVboxReclaim, vboxSelected, @@ -61,12 +57,6 @@ const addState = connect( }, function receiveDispatch(dispatch) { - function setReclaiming(v) { - dispatch(actions.setItemUnequip([])); - dispatch(actions.setVboxSelected({ shopSelect: [], stashSelect: [] })); - return dispatch(actions.setReclaiming(v)); - } - function setInfo(item) { return dispatch(actions.setInfo(item)); } @@ -78,20 +68,19 @@ const addState = connect( } return { - setReclaiming, setInfo, setVboxSelected, }; } ); -function validVboxSelect(vbox, itemInfo, shopSelect, stashSelect) { - if (shopSelect.length === 0 && stashSelect.length === 0) return false; +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 = shopSelect.map(j => vbox.free[j[0]][j[1]]); + const shopItems = storeSelect.map(j => vbox.free[j[0]][j[1]]); const selectedItems = stashItems.concat(shopItems); const itemCount = countBy(selectedItems, co => co); @@ -119,7 +108,6 @@ class Vbox extends preact.Component { shouldComponentUpdate(newProps) { // Single variable props if (newProps.itemUnequip !== this.props.itemUnequip) return true; - if (newProps.reclaiming !== this.props.reclaiming) return true; if (newProps.tutorial !== this.props.tutorial) return true; if (newProps.vboxSelected !== this.props.vboxSelected) return true; if (newProps.player !== this.props.player) return true; @@ -132,7 +120,6 @@ class Vbox extends preact.Component { // Changing state variables itemUnequip, player, - reclaiming, tutorial, vboxSelected, instance, @@ -142,299 +129,141 @@ class Vbox extends preact.Component { // Function Calls sendItemUnequip, sendVboxAccept, - sendVboxCombine, sendVboxDiscard, sendVboxReclaim, setVboxSelected, setInfo, - setReclaiming, } = args; if (!player) return false; const { vbox } = player; - const { shopSelect, stashSelect } = vboxSelected; - const vboxSelecting = shopSelect.length === 1 && stashSelect.length === 0; + const { storeSelect, stashSelect } = vboxSelected; + const vboxSelecting = storeSelect.length === 1 && stashSelect.length === 0; function combinerChange(newStashSelect) { - return setVboxSelected({ shopSelect, stashSelect: newStashSelect }); + return setVboxSelected({ storeSelect, stashSelect: newStashSelect }); } - const vboxHighlight = validVboxSelect(vbox, itemInfo, shopSelect, stashSelect); + const vboxHighlight = validVboxSelect(vbox, itemInfo, storeSelect, stashSelect); // // VBOX // function vboxHover(e, v) { if (v) { e.stopPropagation(); - if (shopSelect.find(c => c[0])) return true; // There is a base skill or spec selected in the vbox - if (stashSelect.length !== 0) { - const base = stashSelect.find(c => !['Red', 'Blue', 'Green'].includes(vbox.bound[c])); - if (base || base === 0) return true; - } + if (stashSelect.length !== 0 || storeSelect.length !== 0) return true; setInfo(v); } return true; } function clearVboxSelected() { - setVboxSelected({ shopSelect: [], stashSelect: [] }); + setVboxSelected({ storeSelect: [], stashSelect: [] }); } function vboxBuySelected() { if (!vboxSelecting) return false; document.activeElement.blur(); - sendVboxAccept(shopSelect[0][0], shopSelect[0][1]); + sendVboxAccept(storeSelect[0][0], storeSelect[0][1]); return true; } - function availableBtn(v, group, index) { - if (!v) return ; - const selected = shopSelect.length && shopSelect.some(vs => vs[0] === group && vs[1] === index); - - const comboHighlight = vboxHighlight && vboxHighlight.includes(v) ? 'combo-border' : ''; - - function onClick(e) { - e.stopPropagation(); - if (!comboHighlight) setInfo(vbox.free[group][index]); - if (shopSelect.length && shopSelect.some(vs => vs[0] === group && vs[1] === index)) { - return setVboxSelected({ shopSelect: shopSelect.filter(vs => !(vs[0] === group && vs[1] === index)), stashSelect }); - } - - if (!shopSelect.length && !stashSelect.length) return setVboxSelected({ shopSelect: [[group, index]], stashSelect }); - if (comboHighlight !== 'combo-border') { - return setVboxSelected({ shopSelect: [[group, index]], stashSelect: [] }); - } - return setVboxSelected({ shopSelect: [...shopSelect, [group, index]], stashSelect }); - } - - - const classes = `${v.toLowerCase()} ${selected ? 'highlight' : ''} ${comboHighlight}`; - - const vboxObject = shapes[v] ? shapes[v]() : v; - const disabled = vbox.bits <= group; + function storeHdr() { return ( - - ); - } - - - function vboxElement() { - return ( -
e.stopPropagation()}> -
-

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

-
hoverInfo(e, 'bits')} >{vbox.bits}b
-
-
- {range(0, 6).map(i => availableBtn(vbox.free[0][i], 0, i))} -
-
- {range(0, 3).map(i => availableBtn(vbox.free[1][i], 1, i))} - {range(0, 3).map(i => availableBtn(vbox.free[2][i], 2, i))} -
+
+

e.target.scrollIntoView(true)} + onMouseOver={e => vboxHover(e, 'store')}> STORE +

+

vboxHover(e, 'bits')}> + {vbox.bits}b +

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

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

- -
- -
- {range(0, 9).map(i => inventoryBtn(vbox.bound[i], i))} -
- {combinerBtn()} +
+

e.target.scrollIntoView(true)} + onMouseOver={e => vboxHover(e, 'stash')}> STASH +

+ {refundBtn}
); } - // // EVERYTHING - // - function hoverInfo(e, newInfo) { - if (shopSelect.find(c => c[0])) return true; - if (stashSelect.length !== 0) { - const base = stashSelect.find(c => !['Red', 'Blue', 'Green'].includes(vbox.bound[c])); - if (base || base === 0) return true; - } - return setInfo(newInfo); - } - - const classes = 'vbox'; return ( -
- {vboxElement()} -
- {inventoryElement()} +
+ {storeHdr()} + {stashHdr()} + + + + +
); } diff --git a/client/src/components/vbox.info.jsx b/client/src/components/vbox.info.jsx new file mode 100644 index 00000000..452f268d --- /dev/null +++ b/client/src/components/vbox.info.jsx @@ -0,0 +1,195 @@ +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; + + 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 }; + } +); + +function Info(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 + 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) { + 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()} +
+ ); + } + const stateFullInfo = comboItem || vboxInfo; + if (stateFullInfo) return genItemInfo(stateFullInfo); + 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. +

+
+ ); + } + + return genItemInfo(info); +} + +module.exports = addState(Info); diff --git a/client/src/components/info.thresholds.jsx b/client/src/components/vbox.info.thresholds.jsx similarity index 95% rename from client/src/components/info.thresholds.jsx rename to client/src/components/vbox.info.thresholds.jsx index 7136a855..9f259f0e 100644 --- a/client/src/components/info.thresholds.jsx +++ b/client/src/components/vbox.info.thresholds.jsx @@ -3,6 +3,7 @@ const range = require('lodash/range'); const shapes = require('./shapes'); function specThresholds(player, fullInfo, info) { + if (!info) return false; let red = 0; let blue = 0; let green = 0; @@ -87,9 +88,12 @@ function specThresholds(player, fullInfo, info) { ); }); return ( -
- {thresholds} +
+
+ {thresholds} +
+ ); } diff --git a/client/src/components/vbox.stash.jsx b/client/src/components/vbox.stash.jsx new file mode 100644 index 00000000..18dd6b78 --- /dev/null +++ b/client/src/components/vbox.stash.jsx @@ -0,0 +1,109 @@ +const preact = require('preact'); +const range = require('lodash/range'); +const without = require('lodash/without'); + +const shapes = require('./shapes'); +const buttons = require('./buttons'); +const { removeTier } = require('../utils'); + +function stashElement(props) { + const { + combinerChange, + itemUnequip, + vbox, + vboxBuySelected, + vboxHighlight, + vboxHover, + vboxSelecting, + stashSelect, + + sendItemUnequip, + setInfo, + setVboxSelected, + + } = props; + function stashClick(e) { + e.stopPropagation(); + if (itemUnequip.length) return sendItemUnequip(itemUnequip); + if (vboxSelecting) return vboxBuySelected(); + return true; + } + + function stashBtn(v, i) { + const stashHighlight = vboxSelecting || itemUnequip.length; + + if (!v && v !== 0) { + const emptyInvClick = () => { + if (vboxSelecting) return vboxBuySelected(); + return false; + }; + return ; + } + + const notValidCombo = vboxHighlight && !vboxHighlight.includes(v); + + function onClick(type) { + const combinerContainsIndex = stashSelect.indexOf(i) > -1; + // removing + if (combinerContainsIndex) { + if (type === 'click') { + return combinerChange(without(stashSelect, i)); + } + return true; + } + + if (notValidCombo) { + setInfo(vbox.bound[i]); + return setVboxSelected({ storeSelect: [], stashSelect: [i] }); + } + + stashSelect.push(i); + // if (stashSelect.length === 3) setInfo(comboItem.item); + return combinerChange(stashSelect); + } + + const highlighted = stashSelect.indexOf(i) > -1; + const border = buttons[removeTier(v)] ? buttons[removeTier(v)]() : ''; + const classes = highlighted + ? 'highlight' + : `${border} ${notValidCombo ? 'fade' : ''}`; + + const invObject = shapes[v] ? shapes[v]() : v; + + return ( + + ); + } + + return ( +
e.stopPropagation()} + onDragOver={ev => ev.preventDefault()} + onDrop={stashClick} + > + {range(0, 6).map(i => stashBtn(vbox.bound[i], i))} +
+ ); +} + +module.exports = stashElement; diff --git a/client/src/components/vbox.store.jsx b/client/src/components/vbox.store.jsx new file mode 100644 index 00000000..4dfda70a --- /dev/null +++ b/client/src/components/vbox.store.jsx @@ -0,0 +1,78 @@ +const preact = require('preact'); +const range = require('lodash/range'); + +const shapes = require('./shapes'); + + +function storeElement(props) { + const { + clearVboxSelected, + setVboxSelected, + storeSelect, + stashSelect, + vbox, + vboxHighlight, + vboxHover, + } = props; + + function availableBtn(v, group, index) { + if (!v) return ; + const selected = storeSelect.length && storeSelect.some(vs => vs[0] === group && vs[1] === index); + + const notValidCombo = vboxHighlight && !vboxHighlight.includes(v); + + function onClick(e) { + e.stopPropagation(); + if (storeSelect.length && storeSelect.some(vs => vs[0] === group && vs[1] === index)) { + return setVboxSelected( + { storeSelect: storeSelect.filter(vs => !(vs[0] === group && vs[1] === index)), stashSelect } + ); + } + + if (!storeSelect.length && !stashSelect.length) { + return setVboxSelected({ storeSelect: [[group, index]], stashSelect }); + } + if (notValidCombo) { + return setVboxSelected({ storeSelect: [[group, index]], stashSelect: [] }); + } + return setVboxSelected({ storeSelect: [...storeSelect, [group, index]], stashSelect }); + } + + + const classes = selected + ? `${v.toLowerCase()} highlight` + : `${v.toLowerCase()} ${notValidCombo ? 'fade' : ''}`; + + const vboxObject = shapes[v] ? shapes[v]() : v; + const disabled = vbox.bits <= group; + return ( + + ); + } + + return ( +
e.stopPropagation()}> +
+ {range(0, 6).map(i => availableBtn(vbox.free[0][i], 0, i))} +
+
+ {range(0, 3).map(i => availableBtn(vbox.free[1][i], 1, i))} + {range(0, 3).map(i => availableBtn(vbox.free[2][i], 2, i))} +
+
+ ); +} + +module.exports = storeElement; diff --git a/client/src/constants.jsx b/client/src/constants.jsx index 5a7a24a3..f16b7f3b 100644 --- a/client/src/constants.jsx +++ b/client/src/constants.jsx @@ -24,22 +24,18 @@ module.exports = { }, INFO: { - vbox: { - item: 'VBOX', - description:

ITEMS that are available to buy.
- The VBOX is refilled every round.
Click REFILL at the bottom to purchase a refill.

, + store: { + item: 'STORE', + description:

Contains items that are available to buy.
+ The store is refilled every round.
Click REFILL to purchase a refill for 2 bits.

, }, - inventory: { - item: 'INVENTORY', + stash: { + item: 'STASH', description:

Holds ITEMS
ITEMS carry over each round.

, }, bits: { item: 'BITS', - description:

The VBOX currency.
- Colours - 1b
- Skills - 2b
- Specs - 3b
- At the beginning of each round you receive 30 bits.

, + description:

Currency to buy items.
At the beginning of each round you receive 30 bits.

, }, ready: { item: 'READY', @@ -60,7 +56,7 @@ module.exports = { }, constructSkills: { item: 'SKILLS', - description: 'Skills are used by constructs in the game phase.\nBase skills can be bought from the VBOX.\nEquip skills from the inventory. Double-click to unequip.', + description: 'Skills are used by constructs in the game phase.\nBase skills can be bought from the VBOX.\nEquip skills from the stash. Double-click to unequip.', }, constructSpecs: { item: 'SPECS', diff --git a/client/src/events.jsx b/client/src/events.jsx index 02c6af1e..f852313c 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -179,12 +179,10 @@ function registerEvents(store) { } function clearInstance() { - store.dispatch(actions.setReclaiming(false)); store.dispatch(actions.setActiveSkill(null)); store.dispatch(actions.setInfo(null)); store.dispatch(actions.setItemUnequip([])); - store.dispatch(actions.setVboxHighlight([])); - store.dispatch(actions.setVboxSelected({ shopSelect: [], stashSelect: [] })); + store.dispatch(actions.setVboxSelected({ storeSelect: [], stashSelect: [] })); } function setAccountInstances(v) { diff --git a/client/src/keyboard.jsx b/client/src/keyboard.jsx index bb525d47..43d7343b 100644 --- a/client/src/keyboard.jsx +++ b/client/src/keyboard.jsx @@ -6,12 +6,10 @@ function setupKeys(store) { key.unbind('esc'); key('esc', () => document.activeElement.blur()); - key('esc', () => store.dispatch(actions.setReclaiming(false))); key('esc', () => store.dispatch(actions.setActiveSkill(null))); key('esc', () => store.dispatch(actions.setInfo(null))); key('esc', () => store.dispatch(actions.setItemUnequip([]))); - key('esc', () => store.dispatch(actions.setVboxHighlight([]))); - key('esc', () => store.dispatch(actions.setVboxSelected({ shopSelect: [], stashSelect: [] }))); + key('esc', () => store.dispatch(actions.setVboxSelected({ storeSelect: [], stashSelect: [] }))); key('esc', () => store.dispatch(actions.setMtxActive(null))); } diff --git a/client/src/reducers.jsx b/client/src/reducers.jsx index 1bda4dc7..3dcb0670 100644 --- a/client/src/reducers.jsx +++ b/client/src/reducers.jsx @@ -44,7 +44,6 @@ module.exports = { nav: createReducer(null, 'SET_NAV'), ping: createReducer(null, 'SET_PING'), player: createReducer(null, 'SET_PLAYER'), - reclaiming: createReducer(false, 'SET_RECLAIMING'), shop: createReducer(false, 'SET_SHOP'), pvp: createReducer(null, 'SET_PVP'), @@ -57,7 +56,7 @@ module.exports = { tutorial: createReducer(1, 'SET_TUTORIAL'), tutorialGame: createReducer(1, 'SET_TUTORIAL_GAME'), - vboxSelected: createReducer({ shopSelect: [], stashSelect: [] }, 'SET_VBOX_SELECTED'), + vboxSelected: createReducer({ storeSelect: [], stashSelect: [] }, 'SET_VBOX_SELECTED'), ws: createReducer(null, 'SET_WS'), }; diff --git a/client/src/tutorial.utils.jsx b/client/src/tutorial.utils.jsx index a06cede2..8736bd72 100644 --- a/client/src/tutorial.utils.jsx +++ b/client/src/tutorial.utils.jsx @@ -138,7 +138,7 @@ function tutorialStage(tutorial, ws, clearTutorial, instance) {

Tutorial

The first construct on your team is {constructOne}.

Skill items can be equipped to your constructs to be used in the combat phase.

-

Click the newly combined skill item in the top right of the inventory.
+

Click the newly combined skill from the stash.
Once selected click the construct SKILL slot to equip the skill.

); @@ -161,7 +161,7 @@ function tutorialStage(tutorial, ws, clearTutorial, instance) {

Tutorial

Equipping specialisation items will increase the stats of your constructs.

These can also be combined with colours for further specialisation.

-

Click the specialisation item in the top right of the inventory.
+

Click the specialisation item from the stash.
Once selected click the construct SPEC slot to equip the specialisation.

); diff --git a/server/src/construct.rs b/server/src/construct.rs index bce0d5c0..3c41ffd1 100644 --- a/server/src/construct.rs +++ b/server/src/construct.rs @@ -323,8 +323,6 @@ impl Construct { } pub fn apply_modifiers(&mut self, player_colours: &Colours) -> &mut Construct { - self.specs.sort_unstable(); - self.red_power.recalculate(&self.specs, player_colours); self.red_life.recalculate(&self.specs, player_colours); self.blue_power.recalculate(&self.specs, player_colours); @@ -600,11 +598,11 @@ impl Construct { self.reduce_green_life(red_remainder); let red_damage_amount = red_current_green_life - self.green_life(); - events.push(Event::Damage { + events.push(Event::Damage { skill, amount: red_damage_amount, mitigation: red_mitigation, - colour: Colour::Red + colour: Colour::Red }); } @@ -629,11 +627,11 @@ impl Construct { self.reduce_green_life(blue_remainder); let blue_damage_amount = blue_current_green_life - self.green_life(); - events.push(Event::Damage { + events.push(Event::Damage { skill, amount: blue_damage_amount, mitigation: blue_mitigation, - colour: Colour::Blue + colour: Colour::Blue }); } } diff --git a/server/src/vbox.rs b/server/src/vbox.rs index 8df14c6d..faf93fdc 100644 --- a/server/src/vbox.rs +++ b/server/src/vbox.rs @@ -100,7 +100,7 @@ impl Vbox { } pub fn accept(&mut self, i: usize, j: usize, construct_id: Option) -> Result<&mut Vbox, Error> { - if self.bound.len() >= 9 && !construct_id.is_some() { + if self.bound.len() >= 6 && !construct_id.is_some() { return Err(err_msg("too many items bound")); } @@ -150,7 +150,7 @@ impl Vbox { for vi in vbox_indicies.iter() { inv_indices.push(self.bound.len()); self.accept(vi[0], vi[1], Some(Uuid::nil()))?; - } + } // have to sort the indices and keep track of the iteration // because when removing the elements the array shifts @@ -171,7 +171,7 @@ impl Vbox { self.bound.push(combo.item); // self.bound.sort_unstable(); - if self.bound.len() >= 10 { + if self.bound.len() > 6 { return Err(err_msg("too many items bound")); } Ok(self)