diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dca06b3..63a21137 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,29 @@ -## [1.8.1] - 2019-11-07 +## [1.8.3] - 2019-11-10 +### Added +- Preview combos by hovering over recipes +- Condensed recipe display + +### Fixed +- Construct display on info / demo page +- Case where a skill could send multiple ko events to target +- Resizing of vbox when you buy / create certain items + +### Changed +- Automatically shows a preview of combo item when you have 3 items selected for combining +- Only highlight the first available item slot when equipping +- Amplify no longer increase GreenPower +- Purify + - Now removes all effects on target + - Applies "Pure" increasing healing taken +- Purge + - Now removes all effects on target + + +## [1.8.2] - 2019-11-10 +### Fixed +- Duplicate button issue in reshape tab + +## [1.8.1] - 2019-11-09 ### Fixed - An issue where skills would not be put on cooldown after being used. diff --git a/VERSION b/VERSION index b9268dae..fe4e75fb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.8.1 \ No newline at end of file +1.8.3 \ No newline at end of file diff --git a/WORKLOG.md b/WORKLOG.md index 57b663fc..52e0b9c8 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -6,9 +6,15 @@ * can't reset password without knowing password =\ * ws gzip encoding -* mobile info page +* Graphics + * Img + * Skill Icons + * Buttons / General UI Theming + * Front Page ## SOON +* Graphical status effects instead of text +* Improve colour contrast / buttons * supporter gold name in instance (anyone whos put any money into game) @@ -59,7 +65,7 @@ * Items * instead of red noise, red and black bar gradient * eth adapter - *sets* + *sets* * illusions * vaporwave * crop circles diff --git a/acp/package.json b/acp/package.json index 904e91c6..18b68a3f 100644 --- a/acp/package.json +++ b/acp/package.json @@ -1,6 +1,6 @@ { "name": "mnml-client", - "version": "1.8.1", + "version": "1.8.3", "description": "", "main": "index.js", "scripts": { diff --git a/bin/client.sh b/bin/client.sh index 06daf871..8d1f9c5b 100755 --- a/bin/client.sh +++ b/bin/client.sh @@ -14,6 +14,7 @@ npm i npm run build cp tos.html dist/ +cp changelog.html dist/ # echo "Building acp version $VERSION" # cd $MNML_PATH/acp diff --git a/client/assets/rotate.svg b/client/assets/rotate.svg index b48ee399..23391adf 100644 --- a/client/assets/rotate.svg +++ b/client/assets/rotate.svg @@ -2457,9 +2457,9 @@ borderopacity="1.0" inkscape:pageopacity="1" inkscape:pageshadow="2" - inkscape:zoom="0.53357639" - inkscape:cx="411.32817" - inkscape:cy="1018.5983" + inkscape:zoom="0.53546627" + inkscape:cx="561.25984" + inkscape:cy="793.70079" inkscape:document-units="mm" inkscape:current-layer="layer1" showgrid="true" @@ -2539,8 +2539,8 @@ transform="translate(-472.60042,755.1467)" style="display:inline"> + transform="translate(0,2.7646743)"> + id="g5142" + transform="translate(0,-47.235375)"> + + + + + - - + id="path5003" + d="m 697.60042,-460.14669 -25,25.00001 -25,-25.00001 25,25.00001 v -75.00001 h -25" + style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#f5f5f5;stroke-width:2.9685142;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + + + + + + + + - diff --git a/client/assets/styles/colours.less b/client/assets/styles/colours.less index d8ca2a5d..a1ae5dcb 100644 --- a/client/assets/styles/colours.less +++ b/client/assets/styles/colours.less @@ -122,6 +122,15 @@ svg { } } +@keyframes border-co { + 0% { + border-color: @gray-box; + } + 100% { + border-color: @gray-hint; + } +} + @keyframes co { from { background: @black; diff --git a/client/assets/styles/game.less b/client/assets/styles/game.less index ad9c7f47..4ddacc63 100644 --- a/client/assets/styles/game.less +++ b/client/assets/styles/game.less @@ -94,7 +94,7 @@ justify-items: center; grid-template-columns: 1fr; - grid-template-rows: minmax(min-content, 1fr) min-content; + grid-template-rows: min-content 1fr; grid-template-areas: "left" "right"; diff --git a/client/assets/styles/instance.less b/client/assets/styles/instance.less index 65032870..b94ad2d9 100644 --- a/client/assets/styles/instance.less +++ b/client/assets/styles/instance.less @@ -11,7 +11,7 @@ @media (max-width: 1920px) { .instance .info table td svg { - height: 50%; + // height: 50%; stroke-width: 8px; } @@ -33,15 +33,57 @@ } .instance .info { - /*font-size: 75%;*/ margin: 0 0 0 1em; grid-area: info; - display: flex; - flex-flow: column; - // white-space: pre-wrap; - > *:first-child { - margin-bottom: 1em; + display: grid; + grid-template-rows: 13em min-content; + grid-template-areas: + "item" + "combos"; + + .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; + } + } + } } } @@ -392,6 +434,10 @@ &.winner { animation: win 2s ease-in-out 0s 1; } + + .cancelled { + color: white; + } } .tutorial { diff --git a/client/assets/styles/menu.less b/client/assets/styles/menu.less index c6349146..1ce06f73 100644 --- a/client/assets/styles/menu.less +++ b/client/assets/styles/menu.less @@ -122,6 +122,10 @@ section { // height: 3em; } + &.sub { + grid-template-columns: 1fr; + } + &.play { grid-template-columns: repeat(2, 1fr); align-items: flex-start; diff --git a/client/assets/styles/skeleton.css b/client/assets/styles/skeleton.css index f166c05b..8197aac0 100644 --- a/client/assets/styles/skeleton.css +++ b/client/assets/styles/skeleton.css @@ -269,7 +269,7 @@ textarea:focus, select:focus { border: 1px solid #33C3F0; outline: 0; } -label, + legend { display: block; margin-bottom: .5rem; diff --git a/client/assets/styles/vbox.less b/client/assets/styles/vbox.less index 59109463..ea0d9fd7 100644 --- a/client/assets/styles/vbox.less +++ b/client/assets/styles/vbox.less @@ -1,6 +1,6 @@ .vbox { margin-bottom: 2em; - + line-height: 0; .vbox-hdr { margin-bottom: 1em; height: 2em; @@ -53,7 +53,7 @@ &, &:hover, &:active { background: @red; color: black; - border: 1px solid black; + border: 2px solid black; } } svg { diff --git a/client/changelog.html b/client/changelog.html new file mode 100644 index 00000000..68719026 --- /dev/null +++ b/client/changelog.html @@ -0,0 +1,1211 @@ +CHANGELOG

+[1.8.3] - 2019-11-10

+

+Added

+
    +
  • Preview combos by hovering over recipes
  • +
  • Condensed recipe display
  • +
+

+Fixed

+
    +
  • Construct display on info / demo page
  • +
  • Case where a skill could send multiple ko events to target
  • +
  • Resizing of vbox when you buy / create certain items
  • +
+

+Changed

+
    +
  • Automatically shows a preview of combo item when you have 3 items selected for combining
  • +
  • Only highlight the first available item slot when equipping
  • +
  • Amplify no longer increase GreenPower
  • +
  • Purify +
      +
    • Now removes all effects on target
    • +
    • Applies "Purified" increasing healing taken
    • +
    +
  • +
  • Purge +
      +
    • Now removes all effects on target
    • +
    +
  • +
+

+[1.8.2] - 2019-11-10

+

+Fixed

+
    +
  • Duplicate button issue in reshape tab
  • +
+

+[1.8.1] - 2019-11-09

+

+Fixed

+
    +
  • An issue where skills would not be put on cooldown after being used.
  • +
+

+Changed

+
    +
  • +

    Game phase

    +
      +
    • Background for text overlapping with avatars in game phase (mobile)
    • +
    • Fixed issue where effect text would show when not highlighted
    • +
    • Avatar size doesn't decrease as effects are applied (now overlap)
    • +
    • Added back KO! event when a construct is knocked out
    • +
    +
  • +
  • +

    Invert

    +
      +
    • Now reverses recharge into damage
    • +
    +
  • +
  • +

    Link

    +
      +
    • Reworked completely
    • +
    • Now stuns target for 1T with 1T CD
    • +
    • Deals 20/45/70% blue power multiplied by number of effects on target as blue damage
    • +
    • Applies stun before effect multiplier calculation
    • +
    +
  • +
  • +

    Restrict

    +
      +
    • Changed cooldown from 2T -> 1T
    • +
    • Duration now 2T at all levels
    • +
    +
  • +
  • +

    Ruin

    +
      +
    • Cooldown now 2T at all levels (down from 3T)
    • +
    • Now deals damage to each target (40/70/100)%
    • +
    +
  • +
  • +

    Silence

    +
      +
    • Changed cooldown from 2T -> 1T
    • +
    • Duration now 2T at all levels
    • +
    +
  • +
+

+[1.8.0] - 2019-11-06

+

+Added

+
    +
  • +

    Drag and drop for vbox interactions can be used instead of single click / double click

    +
  • +
  • +

    Base white items and be directly equipped from vbox rather than going through the inventory

    +
      +
    • Useful if you want to equip an item without further combining with colours
    • +
    +
  • +
  • +

    You can swap skills and specs between constructs without using the inventory

    +
  • +
+

+Changed

+
    +
  • +

    Construct life changed

    +
      +
    • You now start with 800 green life (down from 950)
    • +
    • You now start with 125 red life and blue life (up from 0)
    • +
    +
  • +
  • +

    Game phase layout

    +
      +
    • Enemy team effects appear under your construct instead of next to it
    • +
    • Game phase constructs line up symmetrically now
    • +
    +
  • +
  • +

    Mobile

    +
      +
    • Tutorial is disabled for mobile view
    • +
    • Landscape is now default view
    • +
    • Vbox phase everything is now in one view
    • +
    • Game constructs and animations are much larger in mobile view
    • +
    +
  • +
  • +

    Amplify

    +
      +
    • Now increases green power
    • +
    +
  • +
  • +

    Absorb

    +
      +
    • Reduced duration and cooldown from 2T -> 1T (Absorption duration unchanged)
    • +
    • Absorption damage is now based on all damage taken (previously only green damage taken)
    • +
    • Now recharges blue life based on 95 / 120 / 155 blue power
    • +
    +
  • +
  • +

    Banish

    +
      +
    • Reduced cooldown to 1T
    • +
    +
  • +
  • +

    Decay

    +
      +
    • Removed cooldown
    • +
    +
  • +
  • +

    Haste / Hybrid

    +
      +
    • Fixed issue when hybridblast and hastestrike wouldn't trigger from upgraded + skills
    • +
    +
  • +
  • +

    Intercept

    +
      +
    • Reduced duration to 1T down from 2T
    • +
    • Reduced cooldown to 1T down from 2T
    • +
    +
  • +
+

+[1.7.0] - 2019-10-31

+

+Added

+
    +
  • +

    Step by step tutorial

    +
      +
    • Will activate during the learn game for the first round
    • +
    • There is a button which will exit tutorial so you can continune the normal practice mode
    • +
    +
  • +
  • +

    Skill combo previews

    +
      +
    • You can now preview what item combos will create!
    • +
    • Click into the item in the info section table (top right) and it will be replaced with the new item
    • +
    +
  • +
+

+Changed

+
    +
  • +

    Vbox phase

    +
      +
    • Made general performance improvements
    • +
    • Removed the default info state (should be smoother to navigate now)
    • +
    • When combining or selecting base items (skills/specs) the base item info won't be replaced with other vbox items
    • +
    • Added info text for construct names and avatars
    • +
    • Changed a number of info descriptions for clarity
    • +
    +
  • +
  • +

    Game phase

    +
      +
    • Made general performance improvements
    • +
    • Now has default tutorial text for the first round (tells the player to select skills and then the targets)
    • +
    +
  • +
  • +

    Moved the login page demo to a new info tab

    +
  • +
  • +

    Increased the speed of demo and it now creates random combos

    +
  • +
  • +

    Banish

    +
      +
    • Cooldown reduced to 2T (was 3T)
    • +
    +
  • +
  • +

    Bash

    +
      +
    • Skill multiplier reduced from 65/95/140 -> 45/65/100
    • +
    +
  • +
  • +

    Blast

    +
      +
    • Damage multiplier reduced 110/145/210 -> 105/140/200
    • +
    +
  • +
  • +

    Block

    +
      +
    • Previously reduced red damage taken by 50%
    • +
    • Now reduces red damage and blue damage taken by 65%
    • +
    +
  • +
  • +

    Buff

    +
      +
    • Previously increased red power and speed stat by 25%
    • +
    • Now increases red power, blue power and speed stat by 30%
    • +
    • Increased duration from 2T -> 3T
    • +
    +
  • +
  • +

    Counter

    +
      +
    • No longer applies block effect
    • +
    • CounterAttack multiplier increased from 70/95/120 -> 120/160/230
    • +
    • Will now animate an attack animation on counter attack
    • +
    +
  • +
  • +

    Curse

    +
      +
    • Now created by combining Debuff + RB was Debuff + RG
    • +
    • Fixed issue where curse was only increasing blue damage taken instead of red and blue
    • +
    • Fixed an issue where the animation would not display if it occured already
    • +
    +
  • +
  • +

    Haste

    +
      +
    • Cooldown reduced to 1T (was 2T)
    • +
    • Duration increased from 2/3/4T -> 3/4/5T
    • +
    • HasteStrike damage multiplier changed from 30% -> 60%
    • +
    +
  • +
  • +

    Hybrid

    +
      +
    • Cooldown reduced to 1T (was 3T)
    • +
    • Duration increased from 2/3/4T -> 3/4/5T
    • +
    • HybridBlast damage multiplier changed from 25% -> 50%
    • +
    +
  • +
  • +

    Invert

    +
      +
    • Now created by combining Debuff + RG was debuff + RB
    • +
    +
  • +
  • +

    Silence

    +
      +
    • Cooldown reduced to 2T (was 3T)
    • +
    +
  • +
  • +

    Siphon

    +
      +
    • Skill multiplier increased from 20/25/30 -> 25/30/40
    • +
    • Reworded part of description "Construct heals self for 100% of damage dealt to target construct GreenLife."
    • +
    +
  • +
  • +

    Slay

    +
      +
    • Self healing is now 50% of damage dealt to green life (was 100%)
    • +
    • Damage multiplier increased from (40/60/90)% -> (45/65/100)%
    • +
    +
  • +
  • +

    Sleep

    +
      +
    • Cooldown reduced to 2T (was 3T)
    • +
    • Skill multiplier reduced from 240/300/400 -> 200/290/400
    • +
    +
  • +
+

+[1.6.6] - 2019-10-27

+

+Added

+
    +
  • Offering of draws +
      +
    • Neither player receives a point if they agree to a draw
    • +
    • Bots automatically agree to draws
    • +
    +
  • +
+

+[1.6.5] - 2019-10-25

+

+Fixed

+
    +
  • Stripe being blocked no longer causes unrecoverable error
  • +
  • Automatic ready up is now throttled after abandons
  • +
  • Player width styling
  • +
+

+Changed

+
    +
  • Improved wiggle animation
  • +
  • Intercept is now considered defensive by bots
  • +
  • Password restrictions relaxed
  • +
+

+[1.6.4] - 2019-10-24

+

+Changed

+
    +
  • Animations processing on client side reduced.
  • +
+

+[1.6.3] - 2019-10-23

+

+Added

+
    +
  • MNNI: the MNML guide +
      +
    • Delivers the message of the day
    • +
    +
  • +
+

+Fixed

+
    +
  • Fixed issue where dots / hots would not trigger when reapplied at a higher speed
  • +
  • Changed layout of home page. UI elements for rerolling construct avatars moved to a separate tab.
  • +
  • Added highlighting to first round of a game against the bots to guide new users
  • +
  • Fixed UI issues related to scrolling
  • +
  • Improved the invite link
  • +
+

+[1.6.2] - 2019-10-20

+

+Fixed

+
    +
  • Combiner bug where it would preview items for different combinations
  • +
  • Skill descriptions are cleared when animations start
  • +
+

+[1.6.1] - Skipped

+

+[1.6.0] - 2019-10-18

+

+Added

+
    +
  • Subscriber chat!
  • +
+

+Changed

+
    +
  • +

    Made available skill / effect information during the combat phase.

    +
      +
    • Highlighting a skill replace the effect area with the skill description including speed multiplier.
    • +
    • Highlighting an effect will replace the targetting arrow / anim skill text with effect info.
    • +
    +
  • +
  • +

    You can now preview combinations before you create them

    +
      +
    • After selecting the three items for a combo hover over the combine button for info
    • +
    +
  • +
  • +

    Damage formula for Slay and Siphon reworked

    +
      +
    • Slay now deals red damage based RedPower and GreenPower. Previously only based on RedPower.
    • +
    • Siphon now deals blue damage based BluePower and GreenPower. Previously only based on BluePower.
    • +
    +
  • +
+

+Fixed

+
    +
  • Matchmaking bug where server matches you with yourself
  • +
+

+[1.5.6] - 2019-10-17

+

We've updated the UI during the vbox / buy phase to give a better indication of valid actions.

+

+Changed

+
    +
  • +

    Borders for skill combo's represent the base colours.

    +
      +
    • Heal (GG) has a green border, Siphon (BG) has an alternating blue / green border etc.
    • +
    • Borders are shown for items in inventory and as equipped skills during both phases.
    • +
    +
  • +
  • +

    Improvements to making item combo's

    +
      +
    • If you select an item in your inventory it will now highlight other items that are valid for combining.
    • +
    • This includes items that can be bought and in your inventory.
    • +
    +
  • +
  • +

    Improved the indicator for where to click for equipping and buying items where its valid.

    +
      +
    • Now slowly flashes between black and grey, previously changed the border once.
    • +
    +
  • +
+

+[1.5.5] - 2019-10-15

+

+Changed

+
    +
  • +

    Purge

    +
      +
    • Fixed bug where client animations would freeze when clearing a buff
    • +
    • Cooldown increased to 1T
    • +
    +
  • +
  • +

    VBOX

    +
      +
    • You can no longer select invalid combinations.
    • +
    +
  • +
  • +

    Controls

    +
      +
    • Abandon button now asks for confirmation.
    • +
    +
  • +
+
\ No newline at end of file diff --git a/client/package.json b/client/package.json index 119c92f2..96747156 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "mnml-client", - "version": "1.8.1", + "version": "1.8.3", "description": "", "main": "index.js", "scripts": { diff --git a/client/src/actions.jsx b/client/src/actions.jsx index e42d349c..ebec075d 100644 --- a/client/src/actions.jsx +++ b/client/src/actions.jsx @@ -1,5 +1,4 @@ export const setAccount = value => ({ type: 'SET_ACCOUNT', value }); -export const setActiveConstruct = value => ({ type: 'SET_ACTIVE_CONSTRUCT', value }); export const setAnimating = value => ({ type: 'SET_ANIMATING', value }); export const setAnimCb = value => ({ type: 'SET_ANIM_CB', value }); @@ -40,9 +39,9 @@ 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 setSkip = value => ({ type: 'SET_SKIP', value }); export const setShop = value => ({ type: 'SET_SHOP', value }); export const setSubscription = value => ({ type: 'SET_SUBSCRIPTION', value }); +export const setPvp = value => ({ type: 'SET_PVP', value }); export const setTeam = value => ({ type: 'SET_TEAM', value: Array.from(value) }); export const setTeamPage = value => ({ type: 'SET_TEAM_PAGE', value }); diff --git a/client/src/animations.socket.jsx b/client/src/animations.socket.jsx index ae99e1cc..d42ded1b 100644 --- a/client/src/animations.socket.jsx +++ b/client/src/animations.socket.jsx @@ -78,7 +78,6 @@ function createSocket(store) { store.dispatch(actions.setAnimText(null)); store.dispatch(actions.setAnimating(false)); store.dispatch(actions.setGameEffectInfo(null)); - store.dispatch(actions.setSkip(false)); // set the game state so resolutions don't fire twice store.dispatch(actions.setGame(game)); diff --git a/client/src/animations.utils.jsx b/client/src/animations.utils.jsx index ad926a8f..21b38925 100644 --- a/client/src/animations.utils.jsx +++ b/client/src/animations.utils.jsx @@ -168,6 +168,9 @@ function getText(resolution) { if (type === 'Removal') { const { effect, construct_effects: effects } = event; + if (!effect) { + return { text: 'Effect Removal', css: '', effects }; + } return { text: `-${effect}`, css: '', effects }; } return false; diff --git a/client/src/components/account.status.jsx b/client/src/components/account.status.jsx index 422d2233..c25b0855 100644 --- a/client/src/components/account.status.jsx +++ b/client/src/components/account.status.jsx @@ -36,7 +36,6 @@ const addState = connect( dispatch(actions.setCombiner([])); dispatch(actions.setReclaiming(false)); dispatch(actions.setActiveSkill(null)); - dispatch(actions.setActiveConstruct(null)); dispatch(actions.setInfo(null)); dispatch(actions.setItemEquip(null)); dispatch(actions.setItemUnequip([])); diff --git a/client/src/components/anims/siphon.tick.jsx b/client/src/components/anims/siphon.tick.jsx index 1f7f4d47..207b986f 100644 --- a/client/src/components/anims/siphon.tick.jsx +++ b/client/src/components/anims/siphon.tick.jsx @@ -20,6 +20,7 @@ function projectile(x, y, radius, colour) { cx={x} cy={y} r={radius} + stroke="none" fill={colour} /> ); diff --git a/client/src/components/faceoff.jsx b/client/src/components/faceoff.jsx index ea3858cd..579a9e6e 100644 --- a/client/src/components/faceoff.jsx +++ b/client/src/components/faceoff.jsx @@ -80,6 +80,12 @@ class Faceoff extends preact.Component { } function faceoffText() { if (!instance.winner) { + if (instance.phase === 'Finished') return ( +
+
game cancelled
+
+ ); + return (
{otherTeam.name}
diff --git a/client/src/components/game.construct.jsx b/client/src/components/game.construct.jsx index 68df7d47..4ffede73 100644 --- a/client/src/components/game.construct.jsx +++ b/client/src/components/game.construct.jsx @@ -148,7 +148,7 @@ class GameConstruct extends Component { return (

{gameSkillInfo.skill}

- {infoDescription} + {infoDescription}
{speed}
); } diff --git a/client/src/components/game.jsx b/client/src/components/game.jsx index 88cc3a1d..2767d290 100644 --- a/client/src/components/game.jsx +++ b/client/src/components/game.jsx @@ -14,7 +14,6 @@ const addState = connect( account, animating, activeSkill, - activeConstruct, } = state; function selectSkillTarget(targetConstructId) { @@ -34,7 +33,6 @@ const addState = connect( account, animating, activeSkill, - activeConstruct, selectSkillTarget, }; }, @@ -44,11 +42,7 @@ const addState = connect( dispatch(actions.setActiveSkill(constructId, skill)); } - function setActiveConstruct(construct) { - dispatch(actions.setActiveConstruct(construct)); - } - - return { setActiveSkill, setActiveConstruct }; + return { setActiveSkill }; } ); @@ -59,7 +53,6 @@ function Game(props) { account, animating, setActiveSkill, - setActiveConstruct, } = props; if (!game) return
...
; @@ -91,7 +84,6 @@ function Game(props) { function gameClick(e) { e.stopPropagation(); - setActiveConstruct(null); } return ( diff --git a/client/src/components/header.jsx b/client/src/components/header.jsx index 2ce0368f..76e96fe7 100644 --- a/client/src/components/header.jsx +++ b/client/src/components/header.jsx @@ -35,7 +35,6 @@ const addState = connect( dispatch(actions.setCombiner([])); dispatch(actions.setReclaiming(false)); dispatch(actions.setActiveSkill(null)); - dispatch(actions.setActiveConstruct(null)); dispatch(actions.setInfo(null)); dispatch(actions.setItemEquip(null)); dispatch(actions.setItemUnequip([])); diff --git a/client/src/components/info.component.jsx b/client/src/components/info.component.jsx index 0666010a..71360599 100644 --- a/client/src/components/info.component.jsx +++ b/client/src/components/info.component.jsx @@ -9,15 +9,22 @@ const shapes = require('./shapes'); class InfoComponent extends preact.Component { - shouldComponentUpdate(newProps) { + 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 @@ -33,7 +40,7 @@ class InfoComponent extends preact.Component { setInfo, setTutorialNull, } = args; - + const { comboItem } = this.state; function Info() { if (tutorial) { const tutorialStageInfo = tutorialStage(tutorial, ws, setTutorialNull, instance); @@ -42,19 +49,19 @@ class InfoComponent extends preact.Component { 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.
@@ -63,7 +70,9 @@ class InfoComponent extends preact.Component {

); } - const fullInfo = itemInfo.items.find(i => i.item === info) || INFO[info]; + 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; @@ -75,16 +84,17 @@ class InfoComponent extends preact.Component { }; if (isSkill || isSpec) { - let infoName = info; + let infoName = fullInfo.item; while (infoName.includes('Plus')) infoName = infoName.replace('Plus', '+'); - const header = isSkill ?

SKILL

:

SPEC

; + const itemSource = itemInfo.combos.filter(c => c.item === removeTier(fullInfo.item)); - const itemSource = itemInfo.combos.filter(c => c.item === removeTier(info)); - let itemSourceInfo = itemSource.length + 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)/; @@ -100,7 +110,7 @@ class InfoComponent extends preact.Component { const thresholds = isSpec ? specThresholds(player, fullInfo, info) : null; return ( -
+

{infoName} {fullInfo.cost}b

{header} {itemSourceInfo} @@ -120,7 +130,7 @@ class InfoComponent extends preact.Component { ); } - function Combos() { + const Combos = () => { if (tutorial && instance.time_control === 'Practice' && instance.rounds.length === 1) return false; const generalNotes = (
@@ -137,22 +147,33 @@ class InfoComponent extends preact.Component { 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 ( - - - {vboxCombos.map((c, i) => - - - {c.components.map((u, j) => )} - - )} - -
setInfo(c.item)} >{convertItem(c.item)}{convertItem(u)}
+
+ {comboTable} +
); - } + }; return ( -
+
this.setState({ comboItem: null })}>
diff --git a/client/src/components/instance.constructs.jsx b/client/src/components/instance.constructs.jsx index da843f8f..577fe84c 100644 --- a/client/src/components/instance.constructs.jsx +++ b/client/src/components/instance.constructs.jsx @@ -66,10 +66,6 @@ const addState = connect( dispatch(actions.setInfo(item)); } - function setActiveConstruct(value) { - dispatch(actions.setActiveConstruct(value)); - } - function setItemEquip(v) { return dispatch(actions.setItemEquip(v)); } @@ -78,7 +74,7 @@ const addState = connect( return dispatch(actions.setItemUnequip(v)); } - return { quit, setInfo, setActiveConstruct, setItemUnequip, setItemEquip }; + return { quit, setInfo, setItemUnequip, setItemEquip }; } ); @@ -101,7 +97,6 @@ function Construct(props) { sendVboxAcceptEquip, sendVboxUnequipApply, sendUnequip, - setActiveConstruct, setItemUnequip, setItemEquip, setInfo, @@ -144,7 +139,6 @@ function Construct(props) { function skillClick(e) { if (!skill) return false; setItemUnequip([construct.id, skill.skill]); - setActiveConstruct(construct); e.stopPropagation(); return true; } @@ -152,7 +146,6 @@ function Construct(props) { function skillDblClick(e) { if (!skill) return false; sendUnequip(construct.id, skill.skill); - setActiveConstruct(null); setItemUnequip([]); e.stopPropagation(); e.preventDefault(); @@ -160,7 +153,7 @@ function Construct(props) { } const equipping = skillList.includes(vbox.bound[itemEquip]) && !skill - && !tutorialDisableEquip && !duplicateSkill; + && !tutorialDisableEquip && !duplicateSkill && i === construct.skills.length; const border = () => { if (!skill) return ''; const borderFn = buttons[removeTier(skill.skill)]; @@ -173,7 +166,7 @@ function Construct(props) {
; }); - const classes = `instance-construct`; + const classes = 'instance-construct'; const avatarMouseOver = e => hoverInfo(e, `constructAvatar ${construct.name}`); return (
ev.preventDefault()} onDrop={onClick}> @@ -291,7 +282,6 @@ class InstanceConstructs extends preact.Component { itemInfo, // Function calls setInfo, - setActiveConstruct, sendVboxApply, sendVboxAcceptEquip, sendVboxUnequipApply, @@ -321,7 +311,6 @@ class InstanceConstructs extends preact.Component { sendVboxAcceptEquip, sendVboxUnequipApply, setInfo, - setActiveConstruct, itemInfo, setVboxHighlight, sendUnequip, @@ -331,7 +320,7 @@ class InstanceConstructs extends preact.Component { }); return ( -
setActiveConstruct(null)}> +
{constructs}
); diff --git a/client/src/components/instance.ctrl.btns.jsx b/client/src/components/instance.ctrl.btns.jsx index ecfded9c..45c26e1f 100644 --- a/client/src/components/instance.ctrl.btns.jsx +++ b/client/src/components/instance.ctrl.btns.jsx @@ -17,16 +17,11 @@ const addState = connect( return ws.sendInstanceReady(instance.id); } - function sendAbandon() { - return ws.sendInstanceAbandon(instance.id); - } - return { instance, chatShow, account, - sendAbandon, sendReady, }; }, @@ -48,22 +43,12 @@ function InstanceCtrlBtns(args) { chatShow, account, - sendAbandon, sendReady, setChatShow, } = args; const finished = instance && instance.phase === 'Finished'; - // cheeky to make sure nubs don't just abandon their first game - const beingNub = instance.phase_end - && instance.phase === 'Lobby' - && Date.parse(instance.phase_end) - Date.now() < 2000; - - if (beingNub) { - sendReady(); - } - return (
diff --git a/client/src/components/nav.jsx b/client/src/components/nav.jsx index daf513f1..e254690a 100644 --- a/client/src/components/nav.jsx +++ b/client/src/components/nav.jsx @@ -36,7 +36,6 @@ const addState = connect( dispatch(actions.setCombiner([])); dispatch(actions.setReclaiming(false)); dispatch(actions.setActiveSkill(null)); - dispatch(actions.setActiveConstruct(null)); dispatch(actions.setInfo(null)); dispatch(actions.setItemEquip(null)); dispatch(actions.setItemUnequip([])); diff --git a/client/src/components/play.jsx b/client/src/components/play.jsx index 2059f774..2c97b77f 100644 --- a/client/src/components/play.jsx +++ b/client/src/components/play.jsx @@ -14,6 +14,7 @@ const addState = connect( account, instances, invite, + pvp, } = state; function sendInstanceState(id) { @@ -32,15 +33,21 @@ const addState = connect( ws.sendInstanceInvite(); } + function sendInstanceLeave() { + ws.sendInstanceLeave(); + } + return { account, instances, invite, + pvp, sendInstanceState, sendInstanceQueue, sendInstancePractice, sendInstanceInvite, + sendInstanceLeave, }; }, @@ -67,11 +74,13 @@ function Play(args) { account, instances, invite, + pvp, sendInstanceState, sendInstanceQueue, sendInstancePractice, sendInstanceInvite, + sendInstanceLeave, setNav, } = args; @@ -125,6 +134,31 @@ function Play(args) { ); }; + const pvpBtn = () => { + if (pvp) return ( +
+ +
Finding Opponent
+
+ ); + + return ( +
+ +
Matchmaking
+
+ ); + } + const subscription = account.subscribed ? -
Matchmaking
- + {pvpBtn()} {inviteBtn()}
diff --git a/client/src/components/stripe.buttons.jsx b/client/src/components/stripe.buttons.jsx index 03d3e6b3..c23c2dfc 100644 --- a/client/src/components/stripe.buttons.jsx +++ b/client/src/components/stripe.buttons.jsx @@ -44,21 +44,26 @@ function BitsBtn(args) { } const subscription = account.subscribed - ? - : ; + ?
+
Thank you for your support
+ +
+ :
+
¤150 / month + Chat Wheel + more
+ +
; return (
-
+
{subscription}
diff --git a/client/src/components/vbox.component.jsx b/client/src/components/vbox.component.jsx index 1f70236c..d9589c2c 100644 --- a/client/src/components/vbox.component.jsx +++ b/client/src/components/vbox.component.jsx @@ -213,6 +213,7 @@ class Vbox extends preact.Component { const classes = `${v.toLowerCase()} ${selected ? 'highlight' : ''} ${comboHighlight}`; const vboxObject = shapes[v] ? shapes[v]() : v; + const disabled = vbox.bits <= group; return (
{range(0, 6).map(i => availableBtn(vbox.free[0][i], 0, i))} @@ -285,7 +287,7 @@ class Vbox extends preact.Component { const combinerItems = combiner.map(j => vbox.bound[j]); const combinerCount = countBy(combinerItems, co => co); - const comboHighlight = combinerItems.length > 0 && itemInfo.combos.some(combo => { + const comboItem = itemInfo.combos.find(combo => { if (combo.components.includes(v)) { return combinerItems.every(c => { if (!combo.components.includes(c)) return false; @@ -295,7 +297,8 @@ class Vbox extends preact.Component { return true; }); } return false; - }) ? 'combo-border' : ''; + }); + const comboHighlight = combinerItems.length > 0 && comboItem ? 'combo-border' : ''; function onClick(type) { if (vboxSelecting) clearVboxSelected(); @@ -321,6 +324,7 @@ class Vbox extends preact.Component { } combiner.push(i); + if (combiner.length === 3) setInfo(comboItem.item); return combinerChange(combiner); } diff --git a/client/src/constants.jsx b/client/src/constants.jsx index bf370e14..5a7a24a3 100644 --- a/client/src/constants.jsx +++ b/client/src/constants.jsx @@ -39,7 +39,7 @@ module.exports = { Colours - 1b
Skills - 2b
Specs - 3b
- At the beginning of each round you receive 18 bits increasing by 6 bits per round.

, + At the beginning of each round you receive 30 bits.

, }, ready: { item: 'READY', diff --git a/client/src/events.jsx b/client/src/events.jsx index 0c745017..ab634d98 100644 --- a/client/src/events.jsx +++ b/client/src/events.jsx @@ -30,6 +30,10 @@ function registerEvents(store) { store.dispatch(actions.setPing(ping)); } + function setPvp(v) { + store.dispatch(actions.setPvp(v)); + } + function setNav(v) { store.dispatch(actions.setNav(v)); } @@ -120,7 +124,6 @@ function registerEvents(store) { store.dispatch(actions.setAnimText(null)); store.dispatch(actions.setAnimating(false)); store.dispatch(actions.setGameEffectInfo(null)); - store.dispatch(actions.setSkip(false)); // set the game state so resolutions don't fire twice store.dispatch(actions.setGame(game)); @@ -177,7 +180,6 @@ function registerEvents(store) { function clearInfo() { store.dispatch(actions.setInfo(null)); - store.dispatch(actions.setActiveConstruct(null)); console.log('event clear item'); } @@ -185,7 +187,6 @@ function registerEvents(store) { store.dispatch(actions.setCombiner([])); store.dispatch(actions.setReclaiming(false)); store.dispatch(actions.setActiveSkill(null)); - store.dispatch(actions.setActiveConstruct(null)); store.dispatch(actions.setInfo(null)); store.dispatch(actions.setItemEquip(null)); store.dispatch(actions.setItemUnequip([])); @@ -209,16 +210,16 @@ function registerEvents(store) { } function setInstance(v) { - const { account, instance, ws, tutorial } = store.getState(); + const { account, ws, tutorial } = store.getState(); if (v) { setInvite(null); + setPvp(false); const player = v.players.find(p => p.id === account.id); store.dispatch(actions.setPlayer(player)); - if (!instance || v.id !== instance.id) { - store.dispatch(actions.setNav('vbox')); - const first = player.constructs[0]; - store.dispatch(actions.setActiveConstruct(first)); + const skip = v.time_control === 'Practice' && v.phase === 'Lobby'; + if (skip) { + ws.sendInstanceReady(v.id); } if (v.phase === 'Finished') { @@ -364,6 +365,7 @@ function registerEvents(store) { setItemInfo, setInvite, setPing, + setPvp, setShop, setTeam, setSubscription, diff --git a/client/src/keyboard.jsx b/client/src/keyboard.jsx index 1646a358..e037be18 100644 --- a/client/src/keyboard.jsx +++ b/client/src/keyboard.jsx @@ -9,7 +9,6 @@ function setupKeys(store) { key('esc', () => store.dispatch(actions.setCombiner([]))); key('esc', () => store.dispatch(actions.setReclaiming(false))); key('esc', () => store.dispatch(actions.setActiveSkill(null))); - key('esc', () => store.dispatch(actions.setActiveConstruct(null))); key('esc', () => store.dispatch(actions.setInfo(null))); key('esc', () => store.dispatch(actions.setItemEquip(null))); key('esc', () => store.dispatch(actions.setItemUnequip([]))); diff --git a/client/src/reducers.jsx b/client/src/reducers.jsx index 96d8001c..c9479f56 100644 --- a/client/src/reducers.jsx +++ b/client/src/reducers.jsx @@ -10,7 +10,6 @@ function createReducer(defaultState, actionType) { /* eslint-disable key-spacing */ module.exports = { account: createReducer(null, 'SET_ACCOUNT'), - activeConstruct: createReducer(null, 'SET_ACTIVE_CONSTRUCT'), activeItem: createReducer(null, 'SET_ACTIVE_VAR'), activeSkill: createReducer(null, 'SET_ACTIVE_SKILL'), @@ -48,8 +47,8 @@ module.exports = { ping: createReducer(null, 'SET_PING'), player: createReducer(null, 'SET_PLAYER'), reclaiming: createReducer(false, 'SET_RECLAIMING'), - skip: createReducer(false, 'SET_SKIP'), shop: createReducer(false, 'SET_SHOP'), + pvp: createReducer(null, 'SET_PVP'), subscription: createReducer(null, 'SET_SUBSCRIPTION'), diff --git a/client/src/socket.jsx b/client/src/socket.jsx index fbc6b296..959bfc30 100644 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -151,6 +151,10 @@ function createSocket(events) { send(['InstanceQueue', {}]); } + function sendInstanceLeave() { + send(['InstanceLeave', {}]); + } + function sendInstanceInvite() { send(['InstanceInvite', {}]); } @@ -274,8 +278,16 @@ function createSocket(events) { Pong: onPong, Demo: onDemo, - QueueRequested: () => events.notify('PVP queue request received.'), - QueueJoined: () => events.notify('You have joined the PVP queue.'), + // QueueRequested: () => events.notify('PVP queue request received.'), + QueueRequested: () => true, + QueueJoined: () => { + events.notify('You have joined the PVP queue.'); + events.setPvp(true); + }, + QueueLeft: () => { + events.notify('You have left the PVP queue.'); + events.setPvp(false); + }, QueueFound: () => events.notify('Your PVP game has started.'), InviteRequested: () => events.notify('PVP invite request received.'), Invite: code => events.setInvite(code), @@ -318,11 +330,8 @@ function createSocket(events) { return handlers[msgType](params); } - let attempts = 1; - // Connection opened function onOpen() { - attempts = 0; toast.info({ message: 'connected', position: 'topRight', @@ -341,21 +350,12 @@ function createSocket(events) { } function onClose(event) { - attempts *= 2; - if (attempts > 10) { - toast.warning({ - message: 'unable to connect, refreshing...', - position: 'topRight', - }); - setTimeout(() => window.location.reload(true), 2000); - } - console.error('WebSocket closed', event); toast.warning({ message: 'disconnected', position: 'topRight', }); - return setTimeout(connect, attempts * 1000); + return setTimeout(connect, 5000); } function connect() { @@ -402,6 +402,7 @@ function createSocket(events) { sendInstanceInvite, sendInstanceJoin, sendInstanceChat, + sendInstanceLeave, sendVboxAccept, sendVboxAcceptEquip, diff --git a/client/src/tutorial.utils.jsx b/client/src/tutorial.utils.jsx index 53268161..b3569b26 100644 --- a/client/src/tutorial.utils.jsx +++ b/client/src/tutorial.utils.jsx @@ -109,7 +109,7 @@ function tutorialStage(tutorial, ws, clearTutorial, instance) { const tutorialText = () => { if (tutorial === 1) { return ( -
+

Tutorial

Welcome to the vbox phase tutorial.

Colours are used to create powerful combinations.

@@ -121,7 +121,7 @@ function tutorialStage(tutorial, ws, clearTutorial, instance) { if (tutorial === 2) { return ( -
+

Tutorial

In a normal game you start with three base Attack skill items.

The Attack item can be combined with colours to create a new skill.

@@ -135,7 +135,7 @@ function tutorialStage(tutorial, ws, clearTutorial, instance) { if (tutorial === 3) { const constructOne = instance.players[0].constructs[0].name; return ( -
+

Tutorial

The first construct on your team is {constructOne}.

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

@@ -147,7 +147,7 @@ function tutorialStage(tutorial, ws, clearTutorial, instance) { if (tutorial === 4) { return ( -
+

Tutorial

You can also buy specialisation items for your constructs.
Specialisation items increase stats including power, speed and life.

@@ -159,7 +159,7 @@ function tutorialStage(tutorial, ws, clearTutorial, instance) { if (tutorial === 5) { return ( -
+

Tutorial

Equipping specialisation items will increase the stats of your constructs.

These can also be combined with colours for further specialisation.

@@ -173,7 +173,7 @@ function tutorialStage(tutorial, ws, clearTutorial, instance) { const constructTwo = instance.players[0].constructs[1].name; const constructThree = instance.players[0].constructs[2].name; return ( -
+

Tutorial

You have now created a construct with an upgraded skill and base spec.

The goal is to create three powerful constructs for combat.

@@ -185,7 +185,7 @@ function tutorialStage(tutorial, ws, clearTutorial, instance) { if (tutorial === 7) { return ( -
+

Tutorial

Each round you start with a vbox full of different skills, specs and colours.

Bits are your currency for buying skills, specs and colours from the vbox.
@@ -204,7 +204,7 @@ function tutorialStage(tutorial, ws, clearTutorial, instance) { } return ( -

+

Tutorial

You've completed the tutorial! Try to create more skill and spec combinations.

You can unequip skills and specs back into the inventory by double clicking.
@@ -216,7 +216,7 @@ function tutorialStage(tutorial, ws, clearTutorial, instance) { }; const classes = tutorial === 8 ? 'focus' : ''; - const text = tutorial === 8 ? 'Continue' : 'Close Tutorial' + const text = tutorial === 8 ? 'Continue' : 'Skip Tutorial' const exitTutorial =