Merge branch 'release/1.5.3'
This commit is contained in:
commit
7972665515
@ -1,8 +1,8 @@
|
|||||||
# mnml
|
# mnml
|
||||||
mnml is a turn-based 1v1 strategy game in an abstract setting.
|
mnml is a turn-based 1v1 strategy game in an abstract setting.
|
||||||
players craft a team of 3 constructs combining a deep pool of skills, effects and specialisations to mindgame & outplay their opponents in a rapid series of duels.
|
Craft a team of 3 constructs combining a deep pool of skills, effects and specialisations to mindgame & outplay opponents in a rapid series of duels.
|
||||||
featuring complex interactions arising from simple rules, simultaneous turns to increase the pace, and a unique speed mechanic mnml is a tactical game in a genre of its own.
|
Featuring complex interactions arising from simple rules, simultaneous turns to increase the pace, and a unique speed mechanic mnml is a tactical game in a genre of its own.
|
||||||
it is completely free to play and requires no installation.
|
It is completely free to play and requires no installation.
|
||||||
|
|
||||||
minimal studios is ntr & mashy: 2 mates with a friendship forged in the fires of warcraft 3 dota.
|
minimal studios is ntr & mashy: 2 mates with a friendship forged in the fires of warcraft 3 dota.
|
||||||
we have both bailed out of the big city life and have dedicated ourselves to growing farm fresh, organic, ethical gaming produce in the rolling hills of brisbane and leaves of melbourne.
|
we have both bailed out of the big city life and have dedicated ourselves to growing farm fresh, organic, ethical gaming produce in the rolling hills of brisbane and leaves of melbourne.
|
||||||
|
|||||||
@ -6,6 +6,8 @@
|
|||||||
* mobile styles
|
* mobile styles
|
||||||
* mobile info page
|
* mobile info page
|
||||||
|
|
||||||
|
* fix info page for tablet layout
|
||||||
|
|
||||||
* Add TOS and accept to register page
|
* Add TOS and accept to register page
|
||||||
|
|
||||||
* can't reset password without knowing password =\
|
* can't reset password without knowing password =\
|
||||||
@ -45,8 +47,11 @@
|
|||||||
reconnect based on time delta
|
reconnect based on time delta
|
||||||
consolidate game and instance
|
consolidate game and instance
|
||||||
|
|
||||||
|
* return of the combat log (last few events with condensed descriptions)
|
||||||
|
- click in to scroll
|
||||||
* elo + leaderboards
|
* elo + leaderboards
|
||||||
|
|
||||||
|
* reflect event stages (for animations)
|
||||||
* mnml tv
|
* mnml tv
|
||||||
|
|
||||||
## LATER
|
## LATER
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-client",
|
"name": "mnml-client",
|
||||||
"version": "1.5.2",
|
"version": "1.5.3",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ require('./assets/styles/instance.less');
|
|||||||
require('./assets/styles/vbox.less');
|
require('./assets/styles/vbox.less');
|
||||||
require('./assets/styles/game.less');
|
require('./assets/styles/game.less');
|
||||||
require('./assets/styles/player.less');
|
require('./assets/styles/player.less');
|
||||||
require('./assets/styles/styles.mobile.css');
|
require('./assets/styles/styles.mobile.less');
|
||||||
require('./assets/styles/instance.mobile.css');
|
require('./assets/styles/instance.mobile.less');
|
||||||
|
|
||||||
require('./src/animations.test.jsx');
|
require('./src/animations.test.jsx');
|
||||||
|
|||||||
@ -44,7 +44,10 @@ aside {
|
|||||||
button {
|
button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 150%;
|
font-size: 150%;
|
||||||
margin-bottom: 0.5em;
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button.ready:enabled {
|
button.ready:enabled {
|
||||||
|
|||||||
@ -3,13 +3,13 @@
|
|||||||
|
|
||||||
.game {
|
.game {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: grid;
|
// display: grid;
|
||||||
grid-template-rows: 1fr 0.5fr 1.5fr;
|
// grid-template-rows: 1fr 0.75fr 1.5fr;
|
||||||
grid-template-columns: 1fr;
|
// grid-template-columns: 1fr;
|
||||||
grid-template-areas:
|
// grid-template-areas:
|
||||||
"opponent"
|
// "opponent"
|
||||||
"target "
|
// "target "
|
||||||
"player ";
|
// "player ";
|
||||||
}
|
}
|
||||||
|
|
||||||
.game .team {
|
.game .team {
|
||||||
@ -24,11 +24,22 @@
|
|||||||
.player {
|
.player {
|
||||||
grid-area: player;
|
grid-area: player;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
height: 50%;
|
||||||
|
width: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opponent {
|
.opponent {
|
||||||
grid-area: opponent;
|
grid-area: opponent;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
height: 35%;
|
||||||
|
width: 90%;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
|
||||||
.game-construct {
|
.game-construct {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
grid-template-columns: 1fr 2fr;
|
grid-template-columns: 1fr 2fr;
|
||||||
@ -66,14 +77,16 @@
|
|||||||
|
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
|
|
||||||
grid-template-columns: 1fr 3fr;
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: min-content 1fr;
|
||||||
|
|
||||||
.left {
|
.left {
|
||||||
|
width: 100%;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 1fr 1fr;
|
|
||||||
|
grid-template-columns: 1fr 2fr;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"skills "
|
"skills effects";
|
||||||
"effects";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.right {
|
.right {
|
||||||
@ -92,7 +105,6 @@
|
|||||||
transition-timing-function: ease;
|
transition-timing-function: ease;
|
||||||
|
|
||||||
.effects {
|
.effects {
|
||||||
align-self: flex-end;
|
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,13 +120,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.skills {
|
.skills {
|
||||||
grid-area: skills;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
button {
|
button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 2em;
|
height: 2em;
|
||||||
height: 25%;
|
height: 25%;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
button.active {
|
||||||
|
background: #2c2c2c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,12 +189,19 @@
|
|||||||
|
|
||||||
#targeting {
|
#targeting {
|
||||||
grid-area: target;
|
grid-area: target;
|
||||||
height: 100%;
|
// height: 100%;
|
||||||
width: 100%;
|
// width: 100%;
|
||||||
stroke-width: 2px;
|
stroke-width: 2px;
|
||||||
stroke: whitesmoke;
|
stroke: whitesmoke;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#targeting, .resolving-skill {
|
||||||
|
position: absolute;
|
||||||
|
top: 35%;
|
||||||
|
height: 15%;
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
.resolving-skill {
|
.resolving-skill {
|
||||||
grid-area: target;
|
grid-area: target;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
@ -203,9 +223,8 @@
|
|||||||
|
|
||||||
.combat-anim {
|
.combat-anim {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: flex;
|
|
||||||
flex-flow: column;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.combat-anim svg {
|
.combat-anim svg {
|
||||||
@ -310,7 +329,7 @@
|
|||||||
.skill-animation {
|
.skill-animation {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
stroke-width: 5px;
|
stroke-width: 5px;
|
||||||
height: 5em;
|
// height: 5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
@media (max-width: 1000px) {
|
||||||
@ -329,6 +348,11 @@
|
|||||||
grid-template-rows: min-content 1fr;
|
grid-template-rows: min-content 1fr;
|
||||||
|
|
||||||
.left {
|
.left {
|
||||||
|
width: 100%;
|
||||||
|
grid-template-areas:
|
||||||
|
"skills"
|
||||||
|
"effects";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: min-content min-content;
|
grid-template-rows: min-content min-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,6 +361,9 @@
|
|||||||
padding: 0 0.5em ;
|
padding: 0 0.5em ;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
button.active {
|
||||||
|
background: #2c2c2c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.stats div {
|
.stats div {
|
||||||
@ -363,17 +390,38 @@
|
|||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skills button, .stats, .name {
|
.stats, .name {
|
||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.skills button {
|
||||||
|
font-size: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.player {
|
||||||
|
width: calc(100% - 1em);
|
||||||
|
bottom: 3em;
|
||||||
|
height: calc(50% - 3em);
|
||||||
}
|
}
|
||||||
|
|
||||||
.opponent {
|
.opponent {
|
||||||
|
width: calc(100% - 1em);
|
||||||
.game-construct {
|
.game-construct {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: min-content 1fr;
|
grid-template-rows: min-content 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#targeting, .resolving-skill {
|
||||||
|
width: calc(100% - 1em);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.player {
|
||||||
|
width: calc(100% - 1em);
|
||||||
|
bottom: 3em;
|
||||||
|
height: calc(50% - 3em);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,5 +1,20 @@
|
|||||||
@import 'colours.less';
|
@import 'colours.less';
|
||||||
|
|
||||||
|
// 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) {
|
@media (max-width: 800px) {
|
||||||
.instance {
|
.instance {
|
||||||
font-size: 8pt;
|
font-size: 8pt;
|
||||||
@ -32,6 +47,10 @@
|
|||||||
&:not(.visible) {
|
&:not(.visible) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vbox-vbox {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.vbox-arrow {
|
.vbox-arrow {
|
||||||
@ -88,7 +107,7 @@
|
|||||||
"avatar "
|
"avatar "
|
||||||
"stats ";
|
"stats ";
|
||||||
|
|
||||||
border-top: 0;
|
border: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
transition-property: all;
|
transition-property: all;
|
||||||
|
|||||||
@ -12,6 +12,9 @@ html body {
|
|||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
|
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mnml {
|
#mnml {
|
||||||
@ -23,7 +26,7 @@ html body {
|
|||||||
|
|
||||||
/* stops inspector going skitz*/
|
/* stops inspector going skitz*/
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
// overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1921px) {
|
@media (min-width: 1921px) {
|
||||||
@ -97,14 +100,8 @@ dl {
|
|||||||
padding: 0.5em 1em;
|
padding: 0.5em 1em;
|
||||||
|
|
||||||
&.animations-test {
|
&.animations-test {
|
||||||
grid-template-columns: 1fr 9fr 1fr;
|
aside button {
|
||||||
grid-template-areas:
|
font-size: 50%;
|
||||||
"nav hdr ctrl"
|
|
||||||
"nav main ctrl"
|
|
||||||
"nav main ctrl";
|
|
||||||
|
|
||||||
nav {
|
|
||||||
display: initial;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,6 +121,7 @@ button, input {
|
|||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
|
line-height: 2em;
|
||||||
|
|
||||||
/*the transitions */
|
/*the transitions */
|
||||||
transition-property: border-color, color, background;
|
transition-property: border-color, color, background;
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
@media (max-width: 800px) {
|
@media (max-width: 800px) {
|
||||||
|
body {
|
||||||
|
overflow-y: initial;
|
||||||
|
}
|
||||||
|
|
||||||
#mnml {
|
#mnml {
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@ -13,10 +17,6 @@
|
|||||||
min-height: initial;
|
min-height: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mnml button {
|
|
||||||
font-size: 10pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
table td {
|
table td {
|
||||||
height: 2.5em;
|
height: 2.5em;
|
||||||
}
|
}
|
||||||
@ -34,6 +34,10 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#nav-btn, #instance-nav {
|
#nav-btn, #instance-nav {
|
||||||
@ -51,10 +55,6 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* header {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
main {
|
main {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: initial;
|
overflow-y: initial;
|
||||||
@ -93,4 +93,34 @@
|
|||||||
"inventory"
|
"inventory"
|
||||||
"games";
|
"games";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
.options {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
|
||||||
|
button:not(:last-child) {
|
||||||
|
border: 2px solid #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.logo {
|
||||||
|
border: none;
|
||||||
|
margin-right: 0;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
.list {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.account {
|
||||||
|
div {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -33,6 +33,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
background-color: @gray-box;
|
background-color: @gray-box;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
|
line-height: 1em;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
|
|
||||||
:active, :hover, :focus {
|
:active, :hover, :focus {
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>mnml - abstract strategy</title>
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
<meta name=apple-mobile-web-app-capable content=yes>
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name=apple-mobile-web-app-status-bar-style content=black>
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="application-name" content="mnml">
|
||||||
<meta name="description" content="mnml pvp tbs">
|
<meta name="description" content="mnml pvp tbs">
|
||||||
<meta name="author" content="ntr@smokestack.io">
|
<meta name="author" content="ntr@smokestack.io">
|
||||||
|
<title>mnml - abstract strategy</title>
|
||||||
<link rel="manifest" href="manifest.webmanifest">
|
<link rel="manifest" href="manifest.webmanifest">
|
||||||
<link rel="stylesheet" href="./node_modules/izitoast/dist/css/iziToast.min.css"></script>
|
<link rel="stylesheet" href="./node_modules/izitoast/dist/css/iziToast.min.css"></script>
|
||||||
<link href="https://fonts.googleapis.com/css?family=Jura" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Jura" rel="stylesheet">
|
||||||
|
|||||||
@ -8,7 +8,7 @@ require('./assets/styles/instance.less');
|
|||||||
require('./assets/styles/vbox.less');
|
require('./assets/styles/vbox.less');
|
||||||
require('./assets/styles/game.less');
|
require('./assets/styles/game.less');
|
||||||
require('./assets/styles/player.less');
|
require('./assets/styles/player.less');
|
||||||
require('./assets/styles/styles.mobile.css');
|
require('./assets/styles/styles.mobile.less');
|
||||||
require('./assets/styles/instance.mobile.less');
|
require('./assets/styles/instance.mobile.less');
|
||||||
|
|
||||||
// kick it off
|
// kick it off
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-client",
|
"name": "mnml-client",
|
||||||
"version": "1.5.2",
|
"version": "1.5.3",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -24,6 +24,7 @@
|
|||||||
"keymaster": "^1.6.2",
|
"keymaster": "^1.6.2",
|
||||||
"linkstate": "^1.1.1",
|
"linkstate": "^1.1.1",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
|
"logrocket": "^1.0.3",
|
||||||
"node-sass": "^4.12.0",
|
"node-sass": "^4.12.0",
|
||||||
"parcel": "^1.12.3",
|
"parcel": "^1.12.3",
|
||||||
"preact": "^8.4.2",
|
"preact": "^8.4.2",
|
||||||
@ -40,7 +41,7 @@
|
|||||||
"babel-plugin-module-resolver": "^3.2.0",
|
"babel-plugin-module-resolver": "^3.2.0",
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"babel-preset-es2015": "^6.24.1",
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-preset-react": "^6.24.1",
|
||||||
"eslint": "^5.6.0",
|
"eslint": "^5.16.0",
|
||||||
"eslint-config-airbnb-base": "^13.1.0",
|
"eslint-config-airbnb-base": "^13.1.0",
|
||||||
"eslint-plugin-import": "^2.14.0",
|
"eslint-plugin-import": "^2.14.0",
|
||||||
"eslint-plugin-react": "^7.11.1",
|
"eslint-plugin-react": "^7.11.1",
|
||||||
|
|||||||
@ -4,6 +4,7 @@ export const setActiveConstruct = value => ({ type: 'SET_ACTIVE_CONSTRUCT', valu
|
|||||||
export const setAnimating = value => ({ type: 'SET_ANIMATING', value });
|
export const setAnimating = value => ({ type: 'SET_ANIMATING', value });
|
||||||
export const setAnimCb = value => ({ type: 'SET_ANIM_CB', value });
|
export const setAnimCb = value => ({ type: 'SET_ANIM_CB', value });
|
||||||
export const setAnimFocus = value => ({ type: 'SET_ANIM_FOCUS', value });
|
export const setAnimFocus = value => ({ type: 'SET_ANIM_FOCUS', value });
|
||||||
|
export const setAnimSkill = value => ({ type: 'SET_ANIM_SKILL', value });
|
||||||
export const setAnimSource = value => ({ type: 'SET_ANIM_SOURCE', value });
|
export const setAnimSource = value => ({ type: 'SET_ANIM_SOURCE', value });
|
||||||
export const setAnimTarget = value => ({ type: 'SET_ANIM_TARGET', value });
|
export const setAnimTarget = value => ({ type: 'SET_ANIM_TARGET', value });
|
||||||
export const setAnimText = value => ({ type: 'SET_ANIM_TEXT', value });
|
export const setAnimText = value => ({ type: 'SET_ANIM_TEXT', value });
|
||||||
|
|||||||
@ -56,9 +56,9 @@ document.fonts.load('16pt "Jura"').then(() => {
|
|||||||
const Animations = () => (
|
const Animations = () => (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<div id="mnml" class="animations-test">
|
<div id="mnml" class="animations-test">
|
||||||
<nav>
|
<aside>
|
||||||
{animationsNav(ws)}
|
{animationsNav(ws)}
|
||||||
</nav>
|
</aside>
|
||||||
<Game />
|
<Game />
|
||||||
</div>
|
</div>
|
||||||
</Provider>
|
</Provider>
|
||||||
@ -69,13 +69,31 @@ document.fonts.load('16pt "Jura"').then(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const SKILLS = [
|
const SKILLS = [
|
||||||
|
'Absorb',
|
||||||
|
'Absorption',
|
||||||
|
'Amplify',
|
||||||
|
'Attack',
|
||||||
|
'Banish',
|
||||||
|
'Bash',
|
||||||
|
'Blast',
|
||||||
|
'Block',
|
||||||
|
'Break',
|
||||||
|
'Buff',
|
||||||
|
'Chaos',
|
||||||
|
'Counter',
|
||||||
|
'CounterAttack',
|
||||||
|
'Curse',
|
||||||
|
'Debuff',
|
||||||
|
'Decay',
|
||||||
|
'DecayTick',
|
||||||
|
'Electrify',
|
||||||
'Electrocute',
|
'Electrocute',
|
||||||
'ElectrocuteTick',
|
'ElectrocuteTick',
|
||||||
'Haste',
|
'Haste',
|
||||||
'HasteStrike',
|
'HasteStrike',
|
||||||
'Heal',
|
'Heal',
|
||||||
'HybridBlast',
|
|
||||||
'Hybrid',
|
'Hybrid',
|
||||||
|
'HybridBlast',
|
||||||
'Intercept',
|
'Intercept',
|
||||||
'Invert',
|
'Invert',
|
||||||
'Link',
|
'Link',
|
||||||
@ -95,22 +113,4 @@ const SKILLS = [
|
|||||||
'Sustain',
|
'Sustain',
|
||||||
'Triage',
|
'Triage',
|
||||||
'TriageTick',
|
'TriageTick',
|
||||||
'Absorb',
|
|
||||||
'Absorption',
|
|
||||||
'Amplify',
|
|
||||||
'Attack',
|
|
||||||
'Banish',
|
|
||||||
'Bash',
|
|
||||||
'Blast',
|
|
||||||
'Block',
|
|
||||||
'Break',
|
|
||||||
'Buff',
|
|
||||||
'Chaos',
|
|
||||||
'CounterAttack',
|
|
||||||
'Counter',
|
|
||||||
'Curse',
|
|
||||||
'Debuff',
|
|
||||||
'Decay',
|
|
||||||
'DecayTick',
|
|
||||||
'Electrify',
|
|
||||||
];
|
];
|
||||||
|
|||||||
@ -68,6 +68,7 @@ function getObjects(resolution, stages, game, account) {
|
|||||||
return {
|
return {
|
||||||
animSource,
|
animSource,
|
||||||
animTarget,
|
animTarget,
|
||||||
|
animSkill: event.skill,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ function getSequence(resolution) {
|
|||||||
case 'EndPost': return ['END_SKILL', 'POST_SKILL'];
|
case 'EndPost': return ['END_SKILL', 'POST_SKILL'];
|
||||||
case 'EndOnly': return ['END_SKILL'];
|
case 'EndOnly': return ['END_SKILL'];
|
||||||
case 'PostOnly': return ['POST_SKILL'];
|
case 'PostOnly': return ['POST_SKILL'];
|
||||||
case 'None': return [];
|
case 'NoStages': return [];
|
||||||
default: return ['START_SKILL', 'END_SKILL', 'POST_SKILL'];
|
default: return ['START_SKILL', 'END_SKILL', 'POST_SKILL'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,7 +178,10 @@ function getText(resolution, sequence) {
|
|||||||
|
|
||||||
if (type === 'Recharge') {
|
if (type === 'Recharge') {
|
||||||
const { red, blue } = event;
|
const { red, blue } = event;
|
||||||
return { text: [`+${red}R ${blue}B`, ''], css: '' };
|
if (red > 0 && blue > 0) return { text: [`+${red}R +${blue}B`, ''], css: 'purple-damage' };
|
||||||
|
if (red > 0) return { text: [`+${red}R`, ''], css: 'red-damage' };
|
||||||
|
if (blue > 0) return { text: [`+${blue}B`, ''], css: 'blue-damage' };
|
||||||
|
return nullText;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'Removal') {
|
if (type === 'Removal') {
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
const preact = require('preact');
|
const preact = require('preact');
|
||||||
// const logger = require('redux-diff-logger');
|
// const logger = require('redux-diff-logger');
|
||||||
|
|
||||||
|
const LogRocket = require('logrocket');
|
||||||
|
|
||||||
const { Provider, connect } = require('preact-redux');
|
const { Provider, connect } = require('preact-redux');
|
||||||
const { createStore, combineReducers } = require('redux');
|
const { createStore, combineReducers } = require('redux');
|
||||||
const { StripeProvider } = require('react-stripe-elements');
|
const { StripeProvider } = require('react-stripe-elements');
|
||||||
@ -13,6 +15,10 @@ const registerEvents = require('./events');
|
|||||||
|
|
||||||
const Mnml = require('./components/mnml');
|
const Mnml = require('./components/mnml');
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'development') {
|
||||||
|
LogRocket.init('yh0dy3/mnml');
|
||||||
|
}
|
||||||
|
|
||||||
function stripeKey() {
|
function stripeKey() {
|
||||||
if (window.location.host === 'mnml.gg') return 'pk_live_fQGrL1uWww2ot8W1G7vTySAv004ygmnMXq';
|
if (window.location.host === 'mnml.gg') return 'pk_live_fQGrL1uWww2ot8W1G7vTySAv004ygmnMXq';
|
||||||
return 'pk_test_Cb49tTqTXpzk7nEmlGzRrNJg00AU0aNZDj';
|
return 'pk_test_Cb49tTqTXpzk7nEmlGzRrNJg00AU0aNZDj';
|
||||||
|
|||||||
@ -19,10 +19,7 @@ function projectile(x, y, radius, colour) {
|
|||||||
cx={x}
|
cx={x}
|
||||||
cy={y}
|
cy={y}
|
||||||
r={radius}
|
r={radius}
|
||||||
fill="url(#grad1)"
|
fill={colour}
|
||||||
stroke-width="2"
|
|
||||||
stroke={colour}
|
|
||||||
filter="url(#explosion)"
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -31,8 +28,11 @@ class Chaos extends Component {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.animations = [];
|
this.animations = [];
|
||||||
const points = randomPoints(7, 30, { x: 0, y: 0, width: 300, height: 100 });
|
const points = randomPoints(20, 30, { x: 0, y: 0, width: 300, height: 100 });
|
||||||
this.charges = points.map(coord => projectile(coord[0], coord[1], 14, '#A25AC1'));
|
this.charges = points.map(coord => {
|
||||||
|
const colour = Math.random() >= 0.5 ? '#a52a2a' : '#3050f8';
|
||||||
|
return projectile(coord[0], coord[1], 14, colour);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -43,19 +43,6 @@ class Chaos extends Component {
|
|||||||
id="Layer_1"
|
id="Layer_1"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 300 400">
|
viewBox="0 0 300 400">
|
||||||
// {this.charges}
|
|
||||||
<defs>
|
|
||||||
<radialGradient id="grad1" cx="50%" cy="0%" r="85%" fx="50%" fy="50%">
|
|
||||||
<stop offset="0%" style="stop-color:#dba9a9;stop-opacity:0.6" />
|
|
||||||
<stop offset="100%" style={'stop-color:#A25AC1;stop-opacity:1'} />
|
|
||||||
</radialGradient>
|
|
||||||
</defs>
|
|
||||||
<filter id="explosion">
|
|
||||||
<feGaussianBlur stdDeviation="4"/>
|
|
||||||
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="3" result="turbulence"/>
|
|
||||||
<feDisplacementMap in2="turbulence" in="SourceGraphic" scale="1" xChannelSelector="A" yChannelSelector="A"/>
|
|
||||||
|
|
||||||
</filter>
|
|
||||||
{this.charges}
|
{this.charges}
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
@ -63,20 +50,11 @@ class Chaos extends Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const projectiles = document.querySelectorAll('.skill-anim circle');
|
const projectiles = document.querySelectorAll('.skill-anim circle');
|
||||||
projectiles.forEach(proj => {
|
|
||||||
const colour = Math.random() >= 0.5 ? '#a52a2a' : '#3050f8';
|
|
||||||
anime.set(proj, {
|
|
||||||
stroke: colour,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
anime.set('.skill-anim', {
|
anime.set('.skill-anim', {
|
||||||
translateY: -(window.screen.height) * 0.35 * this.props.direction.y,
|
translateY: -(window.innerHeight) * 0.35 * this.props.direction.y,
|
||||||
translateX: -(window.screen.width) * 0.15 * this.props.direction.x,
|
translateX: -(window.innerWidth) * 0.15 * this.props.direction.x,
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
});
|
});
|
||||||
anime.set('#explosion feDisplacementMap', {
|
|
||||||
scale: 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.animations.push(anime({
|
this.animations.push(anime({
|
||||||
targets: '.skill-anim',
|
targets: '.skill-anim',
|
||||||
@ -96,23 +74,19 @@ class Chaos extends Component {
|
|||||||
duration: (TIMES.TARGET_DURATION_MS * 1 / 2),
|
duration: (TIMES.TARGET_DURATION_MS * 1 / 2),
|
||||||
easing: 'easeInQuad',
|
easing: 'easeInQuad',
|
||||||
}));
|
}));
|
||||||
this.animations.push(anime({
|
|
||||||
targets: '#explosion feDisplacementMap',
|
|
||||||
scale: 75,
|
|
||||||
loop: false,
|
|
||||||
delay: (TIMES.TARGET_DELAY_MS + TIMES.TARGET_DURATION_MS * 2 / 3),
|
|
||||||
duration: (TIMES.TARGET_DURATION_MS * 1 / 3),
|
|
||||||
easing: 'easeInQuad',
|
|
||||||
}));
|
|
||||||
|
|
||||||
projectiles.forEach(proj => anime({
|
projectiles.forEach(proj => this.animations.push(anime({
|
||||||
targets: proj,
|
targets: proj,
|
||||||
cx: Math.random() * 250 + 25,
|
cx: 150 + (Math.random() * 50 * (Math.random() < 0.5 ? -1 : 1)),
|
||||||
cy: Math.random() * 300 + 50,
|
cy: 200 + (Math.random() * 50 * (Math.random() < 0.5 ? -1 : 1)),
|
||||||
|
// cx: 150,
|
||||||
|
// cy: 200,
|
||||||
|
// opacity: 0,
|
||||||
|
|
||||||
delay: TIMES.TARGET_DELAY_MS,
|
delay: TIMES.TARGET_DELAY_MS,
|
||||||
duration: (TIMES.TARGET_DURATION_MS * 2 / 3),
|
duration: (TIMES.TARGET_DURATION_MS * 2 / 3),
|
||||||
easing: 'easeInQuad',
|
easing: 'easeInQuad',
|
||||||
}));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
|||||||
@ -61,7 +61,7 @@ class Heal extends Component {
|
|||||||
targets: ['#heal'],
|
targets: ['#heal'],
|
||||||
opacity: [
|
opacity: [
|
||||||
{ value: 1, delay: TIMES.TARGET_DELAY_MS, duration: TIMES.TARGET_DURATION_MS * 0.2 },
|
{ value: 1, delay: TIMES.TARGET_DELAY_MS, duration: TIMES.TARGET_DURATION_MS * 0.2 },
|
||||||
{ value: 0, delay: TIMES.TARGET_DURATION_MS * 0.4, duration: TIMES.TARGET_DURATION_MS * 0.2 },
|
{ value: 0, delay: TIMES.TARGET_DURATION_MS / 4, duration: TIMES.TARGET_DURATION_MS * 0.2 },
|
||||||
],
|
],
|
||||||
easing: 'easeInOutSine',
|
easing: 'easeInOutSine',
|
||||||
}));
|
}));
|
||||||
@ -70,8 +70,8 @@ class Heal extends Component {
|
|||||||
targets: ['#heal circle'],
|
targets: ['#heal circle'],
|
||||||
cx: 150,
|
cx: 150,
|
||||||
cy: 200,
|
cy: 200,
|
||||||
delay: TIMES.TARGET_DELAY_MS * 2,
|
delay: TIMES.TARGET_DELAY_MS * 4,
|
||||||
duration: TIMES.TARGET_DURATION_MS,
|
duration: TIMES.TARGET_DURATION_MS * 0.9,
|
||||||
easing: 'easeOutCirc',
|
easing: 'easeOutCirc',
|
||||||
direction: 'reverse',
|
direction: 'reverse',
|
||||||
}));
|
}));
|
||||||
|
|||||||
@ -57,7 +57,7 @@ class Intercept extends Component {
|
|||||||
targets: ['#intercept'],
|
targets: ['#intercept'],
|
||||||
transform: [
|
transform: [
|
||||||
`scale(1 1) ${this.props.player ? 'rotate(180)' : ''}`,
|
`scale(1 1) ${this.props.player ? 'rotate(180)' : ''}`,
|
||||||
`scale(30 3) ${this.props.player ? 'rotate(180)' : ''}`,
|
`scale(5 5) ${this.props.player ? 'rotate(180)' : ''}`,
|
||||||
],
|
],
|
||||||
strokeWidth: 0,
|
strokeWidth: 0,
|
||||||
|
|
||||||
|
|||||||
@ -27,12 +27,9 @@ class Siphon extends Component {
|
|||||||
version="1.1"
|
version="1.1"
|
||||||
id="Layer_1"
|
id="Layer_1"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 300 400"
|
viewBox="0 0 300 300"
|
||||||
opacity="0">
|
opacity="0">
|
||||||
<filter id="blur">
|
<circle id="siphon" r="140" cx="150" cy="150" stroke="#3050f8" stroke-width="2.5%"/>
|
||||||
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
|
|
||||||
</filter>
|
|
||||||
<circle id="siphon" r="140" cx="150" cy="150" stroke="#3050f8" stroke-width="2.5%" filter="url(#blur)"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -53,15 +50,10 @@ class Siphon extends Component {
|
|||||||
|
|
||||||
anime({
|
anime({
|
||||||
targets: '#siphon',
|
targets: '#siphon',
|
||||||
keyframes: [
|
r: 0,
|
||||||
{ r: '110', stroke: '#1FF01F' },
|
|
||||||
{ r: '80', stroke: '#1FF01F' },
|
|
||||||
{ r: '50', stroke: '#3050f8' },
|
|
||||||
{ r: '20', stroke: '#3050f8' },
|
|
||||||
],
|
|
||||||
delay: TIMES.TARGET_DELAY_MS,
|
delay: TIMES.TARGET_DELAY_MS,
|
||||||
duration,
|
duration,
|
||||||
easing: 'easeInCubic',
|
easing: 'easeInSine',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,9 +20,7 @@ function projectile(x, y, radius, colour) {
|
|||||||
cx={x}
|
cx={x}
|
||||||
cy={y}
|
cy={y}
|
||||||
r={radius}
|
r={radius}
|
||||||
fill="url(#grad1)"
|
fill={colour}
|
||||||
stroke-width="0.1"
|
|
||||||
stroke={colour}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -44,24 +42,16 @@ class SiphonTick extends Component {
|
|||||||
version="1.1"
|
version="1.1"
|
||||||
id="Layer_1"
|
id="Layer_1"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 300 400">
|
viewBox="0 0 300 300">
|
||||||
<filter id="blur">
|
<filter id="blur">
|
||||||
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
|
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
|
||||||
</filter>
|
</filter>
|
||||||
<circle id="siphon" r="20" cx="150" cy="150" stroke="#3050f8" stroke-width="2.5%" filter="url(#blur)"/>
|
<circle id="siphon" r="20" cx="150" cy="150" stroke="#3050f8" stroke-width="2.5%" filter="url(#blur)"/>
|
||||||
|
|
||||||
<defs>
|
|
||||||
<radialGradient id="grad1" cx="50%" cy="0%" r="85%" fx="50%" fy="50%">
|
|
||||||
<stop offset="0%" style="stop-color:#3050f8;stop-opacity:0.4" />
|
|
||||||
<stop offset="100%" style={'stop-color:#1FF01F;stop-opacity:1'} />
|
|
||||||
</radialGradient>
|
|
||||||
</defs>
|
|
||||||
<filter id="explosion">
|
<filter id="explosion">
|
||||||
<feGaussianBlur stdDeviation="4"/>
|
<feGaussianBlur stdDeviation="4"/>
|
||||||
<feTurbulence type="turbulence" baseFrequency="0.001" numOctaves="3" result="turbulence"/>
|
<feTurbulence type="turbulence" baseFrequency="0.001" numOctaves="3" result="turbulence"/>
|
||||||
<feDisplacementMap in2="turbulence" in="SourceGraphic" scale="1" xChannelSelector="A" yChannelSelector="A"/>
|
<feDisplacementMap in2="turbulence" in="SourceGraphic" scale="1" xChannelSelector="A" yChannelSelector="A"/>
|
||||||
</filter>
|
</filter>
|
||||||
|
|
||||||
{this.charges}
|
{this.charges}
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
@ -84,27 +74,23 @@ class SiphonTick extends Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
anime.set('#siphon', {
|
anime.set('#siphon', {
|
||||||
r: '80',
|
r: 0,
|
||||||
stroke: '#3050f8',
|
stroke: '#3050f8',
|
||||||
});
|
});
|
||||||
|
|
||||||
anime({
|
anime({
|
||||||
targets: '#siphon',
|
targets: '#siphon',
|
||||||
keyframes: [
|
r: 600,
|
||||||
{ r: '50', stroke: '#3050f8' },
|
|
||||||
{ r: '20', stroke: '#3050f8' },
|
|
||||||
{ r: '0', stroke: '#3050f8' },
|
|
||||||
],
|
|
||||||
duration: duration * 2 / 3,
|
duration: duration * 2 / 3,
|
||||||
easing: 'easeInCubic',
|
easing: 'easeInSine',
|
||||||
});
|
});
|
||||||
|
|
||||||
const projectiles = document.querySelectorAll('.skill-anim circle');
|
const projectiles = document.querySelectorAll('.skill-anim circle');
|
||||||
projectiles.forEach(proj => {
|
projectiles.forEach(proj => {
|
||||||
anime({
|
anime({
|
||||||
targets: proj,
|
targets: proj,
|
||||||
cx: Math.random() * 250 + 25,
|
cx: 150 + (Math.random() * 300 * (Math.random() < 0.5 ? -1 : 1)),
|
||||||
cy: Math.random() * 200 - 100,
|
cy: 150 + (Math.random() * 300 * (Math.random() < 0.5 ? -1 : 1)),
|
||||||
delay: (Math.random() * duration * 1 / 2),
|
delay: (Math.random() * duration * 1 / 2),
|
||||||
duration,
|
duration,
|
||||||
easing: 'easeInQuad',
|
easing: 'easeInQuad',
|
||||||
|
|||||||
@ -21,20 +21,14 @@ function projectile(x, y, radius, colour) {
|
|||||||
cx={x}
|
cx={x}
|
||||||
cy={y}
|
cy={y}
|
||||||
r={radius}
|
r={radius}
|
||||||
fill="url(#grad1)"
|
fill={colour}
|
||||||
stroke-width="2"
|
|
||||||
stroke={colour}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sword(colour) {
|
function sword(colour) {
|
||||||
return (
|
return (
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
|
<polygon points='150,150 75,75, 150,300, 225,75' fill={colour} id="sword" filter="url(#slayFilter)"></polygon>
|
||||||
<g transform="rotate(90, 640, 360) translate(0,720) scale(0.1,-0.1)" fill={colour} stroke={colour} filter="url(#explosion)" id="sword">
|
|
||||||
<path d="M4110 5071 c-294 -119 -436 -228 -457 -350 -4 -25 -7 -230 -6 -454 2 -380 1 -408 -15 -402 -9 4 -48 16 -87 26 -160 41 -215 44 -815 41 -719 -4 -1088 13 -1475 69 -270 38 -384 75 -468 148 -67 58 -111 75 -193 74 -104 -1 -204 -59 -264 -153 -130 -202 -159 -698 -59 -998 62 -188 174 -282 335 -282 77 0 114 14 174 67 87 77 198 114 456 152 386 56 724 73 1459 70 676 -2 728 1 937 68 15 4 16 -29 15 -419 -2 -500 -4 -492 93 -582 45 -41 99 -74 217 -133 87 -43 182 -86 212 -96 172 -55 197 16 78 226 -114 202 -160 347 -187 587 -16 144 -27 371 -18 376 4 3 299 0 655 -5 2030 -31 2627 -35 3953 -23 903 8 1433 17 1665 28 l340 16 450 79 c248 44 491 88 540 99 234 50 777 180 796 190 18 10 19 14 7 26 -7 8 -198 57 -423 109 -346 80 -483 106 -885 170 -417 66 -517 78 -815 100 -312 24 -424 27 -1370 36 -1039 11 -2548 7 -3645 -10 -327 -5 -748 -11 -934 -13 l-339 -3 2 75 c3 130 22 331 41 441 25 147 71 276 142 404 34 61 70 127 80 147 21 42 24 108 6 126 -23 23 -100 13 -198 -27z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,18 +48,11 @@ class Slay extends Component {
|
|||||||
version="1.1"
|
version="1.1"
|
||||||
id="slay"
|
id="slay"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 300 400">
|
viewBox="0 0 300 300">
|
||||||
<defs>
|
<filter id="slayFilter">
|
||||||
<radialGradient id="grad1" cx="50%" cy="0%" r="85%" fx="50%" fy="50%">
|
|
||||||
<stop offset="0%" style="stop-color:#dba9a9;stop-opacity:0.6" />
|
|
||||||
<stop offset="100%" style={`stop-color:${this.colour};stop-opacity:1`} />
|
|
||||||
</radialGradient>
|
|
||||||
</defs>
|
|
||||||
<filter id="explosion">
|
|
||||||
<feGaussianBlur stdDeviation="4"/>
|
<feGaussianBlur stdDeviation="4"/>
|
||||||
<feTurbulence type="turbulence" baseFrequency="0.001" numOctaves="3" result="turbulence"/>
|
<feTurbulence type="turbulence" baseFrequency="0.001" numOctaves="3" result="turbulence"/>
|
||||||
<feDisplacementMap in2="turbulence" in="SourceGraphic" scale="1" xChannelSelector="A" yChannelSelector="A"/>
|
<feDisplacementMap in2="turbulence" in="SourceGraphic" scale="1" xChannelSelector="A" yChannelSelector="A"/>
|
||||||
|
|
||||||
</filter>
|
</filter>
|
||||||
{sword(this.colour)}
|
{sword(this.colour)}
|
||||||
{this.charges}
|
{this.charges}
|
||||||
@ -91,16 +78,17 @@ class Slay extends Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
anime.set('#slay', {
|
anime.set('#slay', {
|
||||||
translateY: -1 * (window.screen.height) * 0.35,
|
translateY: -1 * (window.innerHeight) * 0.35,
|
||||||
translateX: 0,
|
translateX: 0,
|
||||||
});
|
});
|
||||||
anime.set('#explosion feDisplacementMap', {
|
|
||||||
scale: 100,
|
anime.set('#slayFilter feDisplacementMap', {
|
||||||
|
scale: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
anime.set('#sword', {
|
anime.set('#sword', {
|
||||||
fill: this.colour,
|
fill: this.colour,
|
||||||
stroke: this.colour,
|
opacity: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.animations.push(anime({
|
this.animations.push(anime({
|
||||||
@ -119,10 +107,11 @@ class Slay extends Component {
|
|||||||
duration: (duration * 1 / 2),
|
duration: (duration * 1 / 2),
|
||||||
easing: 'easeInQuad',
|
easing: 'easeInQuad',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.animations.push(anime({
|
this.animations.push(anime({
|
||||||
targets: '#explosion feDisplacementMap',
|
targets: ['#slayFilter feTurbulence', '#slayFilter feDisplacementMap'],
|
||||||
scale: 10000,
|
baseFrequency: 10,
|
||||||
loop: false,
|
scale: 100,
|
||||||
delay: (TIMES.TARGET_DELAY_MS + duration * 1 / 2),
|
delay: (TIMES.TARGET_DELAY_MS + duration * 1 / 2),
|
||||||
duration: (duration * 1 / 2),
|
duration: (duration * 1 / 2),
|
||||||
easing: 'easeInQuad',
|
easing: 'easeInQuad',
|
||||||
@ -130,8 +119,7 @@ class Slay extends Component {
|
|||||||
|
|
||||||
this.animations.push(anime({
|
this.animations.push(anime({
|
||||||
targets: '#sword',
|
targets: '#sword',
|
||||||
fill: '#1FF01F',
|
opacity: 0,
|
||||||
stroke: '#1FF01F',
|
|
||||||
delay: (TIMES.TARGET_DELAY_MS + duration + TIMES.POST_SKILL_DURATION_MS * 0.7),
|
delay: (TIMES.TARGET_DELAY_MS + duration + TIMES.POST_SKILL_DURATION_MS * 0.7),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,8 @@ function sourceCast(id, direction, idle) {
|
|||||||
const { x, y } = direction;
|
const { x, y } = direction;
|
||||||
return anime({
|
return anime({
|
||||||
targets: [document.getElementById(id)],
|
targets: [document.getElementById(id)],
|
||||||
translateX: x * window.screen.width * 0.15,
|
translateX: x * window.screen.width * 0.1,
|
||||||
translateY: y * window.screen.height * 0.15,
|
translateY: y * window.screen.height * 0.1,
|
||||||
easing: 'easeInOutElastic',
|
easing: 'easeInOutElastic',
|
||||||
direction: 'alternate',
|
direction: 'alternate',
|
||||||
duration: TIMES.SOURCE_DURATION_MS,
|
duration: TIMES.SOURCE_DURATION_MS,
|
||||||
|
|||||||
@ -54,7 +54,7 @@ class Strike extends Component {
|
|||||||
x: [200, 0, 200],
|
x: [200, 0, 200],
|
||||||
height: [200, 10, 0],
|
height: [200, 10, 0],
|
||||||
width: [20, 400, 0],
|
width: [20, 400, 0],
|
||||||
delay: TIMES.TARGET_DELAY_MS / 2,
|
delay: TIMES.TARGET_DELAY_MS * 0.5,
|
||||||
duration: TIMES.TARGET_DURATION_MS,
|
duration: TIMES.TARGET_DURATION_MS,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,10 @@ const anime = require('animejs').default;
|
|||||||
function wiggle(id, idle) {
|
function wiggle(id, idle) {
|
||||||
const duration = 300;
|
const duration = 300;
|
||||||
const target = document.getElementById(id);
|
const target = document.getElementById(id);
|
||||||
const x = window.screen.width * 0.01 * (Math.round(Math.random()) ? Math.random() : -Math.random());
|
const x = window.innerWidth * 0.01 * (Math.round(Math.random()) ? Math.random() : -Math.random());
|
||||||
const y = window.screen.height * 0.01 * (Math.round(Math.random()) ? Math.random() : -Math.random());
|
const y = window.innerHeight * 0.01 * (Math.round(Math.random()) ? Math.random() : -Math.random());
|
||||||
|
|
||||||
console.log(x, y);
|
// console.log(x, y);
|
||||||
return anime({
|
return anime({
|
||||||
targets: target,
|
targets: target,
|
||||||
rotate: 0,
|
rotate: 0,
|
||||||
|
|||||||
@ -10,11 +10,13 @@ const GameCtrlTopButtons = require('./game.ctrl.btns.top');
|
|||||||
const addState = connect(
|
const addState = connect(
|
||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
const {
|
const {
|
||||||
|
animating,
|
||||||
game,
|
game,
|
||||||
account,
|
account,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
animating,
|
||||||
game,
|
game,
|
||||||
account,
|
account,
|
||||||
};
|
};
|
||||||
@ -23,6 +25,7 @@ const addState = connect(
|
|||||||
|
|
||||||
function Controls(args) {
|
function Controls(args) {
|
||||||
const {
|
const {
|
||||||
|
animating,
|
||||||
account,
|
account,
|
||||||
game,
|
game,
|
||||||
} = args;
|
} = args;
|
||||||
@ -31,10 +34,10 @@ function Controls(args) {
|
|||||||
|
|
||||||
const opponent = game.players.find(t => t.id !== account.id);
|
const opponent = game.players.find(t => t.id !== account.id);
|
||||||
const player = game.players.find(t => t.id === account.id);
|
const player = game.players.find(t => t.id === account.id);
|
||||||
|
|
||||||
const zero = Date.parse(game.phase_start);
|
const zero = Date.parse(game.phase_start);
|
||||||
const now = Date.now();
|
const now = animating ? zero : Date.now();
|
||||||
const end = Date.parse(game.phase_end);
|
const end = Date.parse(game.phase_end);
|
||||||
|
|
||||||
const timerPct = game.phase_end
|
const timerPct = game.phase_end
|
||||||
? ((now - zero) / (end - zero) * 100)
|
? ((now - zero) / (end - zero) * 100)
|
||||||
: 100;
|
: 100;
|
||||||
|
|||||||
@ -93,8 +93,6 @@ class Instance extends Component {
|
|||||||
if (!instance) return setTimeout(this.bindSwipes, 50);
|
if (!instance) return setTimeout(this.bindSwipes, 50);
|
||||||
if (this.h) this.h.destroy();
|
if (this.h) this.h.destroy();
|
||||||
this.h = new Hammer(instance);
|
this.h = new Hammer(instance);
|
||||||
const display = ['vbox', 'c0', 'c1', 'c2'];
|
|
||||||
|
|
||||||
this.h.on('swiperight', () => {
|
this.h.on('swiperight', () => {
|
||||||
const {
|
const {
|
||||||
navInstance,
|
navInstance,
|
||||||
@ -111,6 +109,7 @@ class Instance extends Component {
|
|||||||
setNavInstance((navInstance + 1) % 4);
|
setNavInstance((navInstance + 1) % 4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('hammer gestures bound');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,7 +55,6 @@ function Skill(props) {
|
|||||||
// if (skillChosen && !targeting) {
|
// if (skillChosen && !targeting) {
|
||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const cdText = construct.skills[i].cd > 0
|
const cdText = construct.skills[i].cd > 0
|
||||||
? `- ${s.cd}T`
|
? `- ${s.cd}T`
|
||||||
: '';
|
: '';
|
||||||
@ -72,7 +71,7 @@ function Skill(props) {
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
disabled={cdText || s.disabled || ko}
|
disabled={cdText || s.disabled || ko}
|
||||||
class={`construct-skill-btn ${(targeting || highlight) ? 'active' : ''}`}
|
class={`${(targeting || highlight) ? 'active' : ''}`}
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={onClick}>
|
onClick={onClick}>
|
||||||
{s.skill} {cdText}
|
{s.skill} {cdText}
|
||||||
|
|||||||
@ -9,8 +9,8 @@ const shapes = require('./shapes');
|
|||||||
const { removeTier } = require('../utils');
|
const { removeTier } = require('../utils');
|
||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
({ game, account, animTarget, animating, itemInfo }) =>
|
({ game, account, animSkill, animating, itemInfo }) =>
|
||||||
({ game, account, animTarget, animating, itemInfo })
|
({ game, account, animSkill, animating, itemInfo })
|
||||||
);
|
);
|
||||||
|
|
||||||
class TargetSvg extends Component {
|
class TargetSvg extends Component {
|
||||||
@ -28,15 +28,15 @@ class TargetSvg extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(props, state) {
|
render(props, state) {
|
||||||
const { game, account, animating, animTarget, itemInfo } = props;
|
const { game, account, animating, animSkill, itemInfo } = props;
|
||||||
const { width, height } = state;
|
const { width, height } = state;
|
||||||
if (!game) return false; // game will be null when battle ends
|
if (!game) return false; // game will be null when battle ends
|
||||||
|
|
||||||
// resolutions happening
|
// resolutions happening
|
||||||
// just put skill name up
|
// just put skill name up
|
||||||
if (animating) {
|
if (animating) {
|
||||||
if (!animTarget) return false;
|
if (!animSkill) return false;
|
||||||
const itemSource = itemInfo.combos.filter(c => c.item === removeTier(animTarget.skill));
|
const itemSource = itemInfo.combos.filter(c => c.item === removeTier(animSkill));
|
||||||
const itemSourceInfo = itemSource.length
|
const itemSourceInfo = itemSource.length
|
||||||
? `${itemSource[0].components[0]} ${itemSource[0].components[1]} ${itemSource[0].components[2]}`
|
? `${itemSource[0].components[0]} ${itemSource[0].components[1]} ${itemSource[0].components[2]}`
|
||||||
: false;
|
: false;
|
||||||
@ -44,7 +44,7 @@ class TargetSvg extends Component {
|
|||||||
const itemSourceDescription = reactStringReplace(itemSourceInfo, itemRegEx, match => shapes[match]());
|
const itemSourceDescription = reactStringReplace(itemSourceInfo, itemRegEx, match => shapes[match]());
|
||||||
return (
|
return (
|
||||||
<div class="resolving-skill">
|
<div class="resolving-skill">
|
||||||
<h1>{animTarget.skill}</h1>
|
<h1>{animSkill}</h1>
|
||||||
<div> {itemSourceDescription} </div>
|
<div> {itemSourceDescription} </div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -7,7 +7,6 @@ const addState = connect(
|
|||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
const {
|
const {
|
||||||
teamSelect,
|
teamSelect,
|
||||||
showNav,
|
|
||||||
ws,
|
ws,
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
@ -18,32 +17,18 @@ const addState = connect(
|
|||||||
return {
|
return {
|
||||||
sendAccountSetTeam,
|
sendAccountSetTeam,
|
||||||
teamSelect,
|
teamSelect,
|
||||||
showNav,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
function receiveDispatch(dispatch) {
|
|
||||||
|
|
||||||
function setShowNav(v) {
|
|
||||||
return dispatch(actions.setShowNav(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
setShowNav,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
function TeamFooter(args) {
|
function TeamFooter(args) {
|
||||||
const {
|
const {
|
||||||
showNav,
|
|
||||||
teamSelect,
|
teamSelect,
|
||||||
sendAccountSetTeam,
|
sendAccountSetTeam,
|
||||||
setShowNav,
|
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer>
|
<footer>
|
||||||
<button id="nav-btn" onClick={() => setShowNav(!showNav)} >☰</button>
|
|
||||||
<button
|
<button
|
||||||
disabled={teamSelect.some(c => !c)}
|
disabled={teamSelect.some(c => !c)}
|
||||||
onClick={sendAccountSetTeam}>
|
onClick={sendAccountSetTeam}>
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
const preact = require('preact');
|
const preact = require('preact');
|
||||||
|
|
||||||
const SOURCE_DURATION_MS = 1000;
|
const SOURCE_DURATION_MS = 1000; // Time for SOURCE ONLY
|
||||||
const TARGET_DELAY_MS = 500;
|
const TARGET_DELAY_MS = 500; // Used for Source + Target
|
||||||
const TARGET_DURATION_MS = 1500;
|
const TARGET_DURATION_MS = 1500; // Time for TARGET ONLY
|
||||||
const POST_SKILL_DURATION_MS = 1000;
|
const POST_SKILL_DURATION_MS = 1000; // Time for all POST
|
||||||
const SOURCE_AND_TARGET_TOTAL_DURATION = TARGET_DELAY_MS + TARGET_DURATION_MS;
|
const SOURCE_AND_TARGET_TOTAL_DURATION = TARGET_DELAY_MS + TARGET_DURATION_MS; // SOURCE + TARGET time
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
TIMES: {
|
TIMES: {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
const LogRocket = require('logrocket');
|
||||||
const querystring = require('query-string');
|
const querystring = require('query-string');
|
||||||
|
|
||||||
const eachSeries = require('async/eachSeries');
|
const eachSeries = require('async/eachSeries');
|
||||||
@ -73,6 +74,7 @@ function registerEvents(store) {
|
|||||||
const anims = animations.getObjects(r, sequence, game, account);
|
const anims = animations.getObjects(r, sequence, game, account);
|
||||||
const text = animations.getText(r, sequence);
|
const text = animations.getText(r, sequence);
|
||||||
store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r, game)));
|
store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r, game)));
|
||||||
|
if (anims.animSkill) store.dispatch(actions.setAnimSkill(anims.animSkill));
|
||||||
|
|
||||||
if (sequence.includes('START_SKILL') && anims.animSource) store.dispatch(actions.setAnimSource(anims.animSource));
|
if (sequence.includes('START_SKILL') && anims.animSource) store.dispatch(actions.setAnimSource(anims.animSource));
|
||||||
if (sequence.includes('END_SKILL') && anims.animTarget) {
|
if (sequence.includes('END_SKILL') && anims.animTarget) {
|
||||||
@ -81,23 +83,28 @@ function registerEvents(store) {
|
|||||||
}
|
}
|
||||||
if (sequence.includes('POST_SKILL') && text) {
|
if (sequence.includes('POST_SKILL') && text) {
|
||||||
// timeout to prevent text classes from being added too soon
|
// timeout to prevent text classes from being added too soon
|
||||||
|
if (timeout === TIMES.POST_SKILL_DURATION_MS) {
|
||||||
|
store.dispatch(actions.setAnimText(text));
|
||||||
|
} else {
|
||||||
setTimeout(
|
setTimeout(
|
||||||
() => store.dispatch(actions.setAnimText(text)),
|
() => store.dispatch(actions.setAnimText(text)),
|
||||||
timeout - TIMES.POST_SKILL_DURATION_MS
|
timeout - TIMES.POST_SKILL_DURATION_MS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return setTimeout(() => {
|
return setTimeout(() => {
|
||||||
const animSkill = anims.animTarget ? removeTier(anims.animTarget.skill) : false;
|
store.dispatch(actions.setAnimSkill(null));
|
||||||
store.dispatch(actions.setAnimSource(null));
|
store.dispatch(actions.setAnimSource(null));
|
||||||
store.dispatch(actions.setAnimTarget(null));
|
store.dispatch(actions.setAnimTarget(null));
|
||||||
store.dispatch(actions.setAnimText(null));
|
store.dispatch(actions.setAnimText(null));
|
||||||
store.dispatch(actions.setAnimFocus([]));
|
store.dispatch(actions.setAnimFocus([]));
|
||||||
if (!sequence.includes('END_SKILL') || (animSkill && ['Banish', 'Invert'].includes(animSkill))) return cb();
|
if (!sequence.includes('END_SKILL') || (anims.animSkill && ['Banish', 'Invert'].includes(anims.animSkill))) return cb();
|
||||||
return true;
|
return true;
|
||||||
}, timeout);
|
}, timeout);
|
||||||
}, err => {
|
}, err => {
|
||||||
if (err) return console.error(err);
|
if (err) return console.error(err);
|
||||||
// clear animation state
|
// clear animation state
|
||||||
|
store.dispatch(actions.setAnimSkill(null));
|
||||||
store.dispatch(actions.setAnimSource(null));
|
store.dispatch(actions.setAnimSource(null));
|
||||||
store.dispatch(actions.setAnimTarget(null));
|
store.dispatch(actions.setAnimTarget(null));
|
||||||
store.dispatch(actions.setAnimText(null));
|
store.dispatch(actions.setAnimText(null));
|
||||||
@ -117,6 +124,10 @@ function registerEvents(store) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setAccount(account) {
|
function setAccount(account) {
|
||||||
|
if (account) {
|
||||||
|
LogRocket.identify(account.id, account);
|
||||||
|
}
|
||||||
|
|
||||||
store.dispatch(actions.setAccount(account));
|
store.dispatch(actions.setAccount(account));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
function createReducer(defaultState, actionType) {
|
function createReducer(defaultState, actionType) {
|
||||||
return function reducer(state = defaultState, action) {
|
return function reducer(state = defaultState, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case actionType:
|
case actionType: return action.value;
|
||||||
return action.value;
|
default: return state;
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -18,6 +16,7 @@ module.exports = {
|
|||||||
|
|
||||||
animating: createReducer(false, 'SET_ANIMATING'),
|
animating: createReducer(false, 'SET_ANIMATING'),
|
||||||
animCb: createReducer(null, 'SET_ANIM_CB'),
|
animCb: createReducer(null, 'SET_ANIM_CB'),
|
||||||
|
animSkill: createReducer(null, 'SET_ANIM_SKILL'),
|
||||||
animSource: createReducer(null, 'SET_ANIM_SOURCE'),
|
animSource: createReducer(null, 'SET_ANIM_SOURCE'),
|
||||||
animFocus: createReducer(null, 'SET_ANIM_FOCUS'),
|
animFocus: createReducer(null, 'SET_ANIM_FOCUS'),
|
||||||
animTarget: createReducer(null, 'SET_ANIM_TARGET'),
|
animTarget: createReducer(null, 'SET_ANIM_TARGET'),
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-ops",
|
"name": "mnml-ops",
|
||||||
"version": "1.5.2",
|
"version": "1.5.3",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -8,13 +8,15 @@
|
|||||||
"migrate": "knex migrate:latest",
|
"migrate": "knex migrate:latest",
|
||||||
"migrate:make": "knex migrate:make --",
|
"migrate:make": "knex migrate:make --",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"nginx:dev": "sudo cp mnml.gg.DEV.SAMPLE.nginx.conf /etc/nginx/sites-available/mnml.gg.DEV.nginx.conf && sudo ln -nfs /etc/nginx/sites-available/mnml.gg.DEV.nginx.conf /etc/nginx/sites-enabled"
|
"nginx:dev": "sudo cp mnml.gg.DEV.SAMPLE.nginx.conf /etc/nginx/sites-available/mnml.gg.DEV.nginx.conf && sudo ln -nfs /etc/nginx/sites-available/mnml.gg.DEV.nginx.conf /etc/nginx/sites-enabled",
|
||||||
|
"qr": "qrcode-svg --color whitesmoke --background black -f -o mnml.qr.svg \"https://mnml.gg\""
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"knex": "^0.15.2",
|
"knex": "^0.15.2",
|
||||||
"pg": "^7.4.3",
|
"pg": "^7.4.3",
|
||||||
|
"qrcode-svg": "^1.0.0",
|
||||||
"request": "^2.88.0",
|
"request": "^2.88.0",
|
||||||
"sdftosvg": "0.0.4",
|
"sdftosvg": "0.0.4",
|
||||||
"uuid": "^3.3.3"
|
"uuid": "^3.3.3"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mnml"
|
name = "mnml"
|
||||||
version = "1.5.2"
|
version = "1.5.3"
|
||||||
authors = ["ntr <ntr@smokestack.io>"]
|
authors = ["ntr <ntr@smokestack.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -161,14 +161,12 @@ impl Game {
|
|||||||
self.skill_phase_start(0)
|
self.skill_phase_start(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skill_phase_start(mut self, num_resolutions: usize) -> Game {
|
fn skill_phase_start(mut self, resolution_time: i64) -> Game {
|
||||||
let resolution_animation_ms = num_resolutions as i64 * 2500;
|
|
||||||
|
|
||||||
self.phase_start = Utc::now()
|
self.phase_start = Utc::now()
|
||||||
.checked_add_signed(Duration::milliseconds(resolution_animation_ms))
|
.checked_add_signed(Duration::milliseconds(resolution_time))
|
||||||
.expect("could not set phase start");
|
.expect("could not set phase start");
|
||||||
|
|
||||||
self.phase_end = self.time_control.game_phase_end(resolution_animation_ms);
|
self.phase_end = self.time_control.game_phase_end(resolution_time);
|
||||||
|
|
||||||
for player in self.players.iter_mut() {
|
for player in self.players.iter_mut() {
|
||||||
if player.skills_required() == 0 {
|
if player.skills_required() == 0 {
|
||||||
@ -428,13 +426,12 @@ impl Game {
|
|||||||
// temp vec of this round's resolving skills
|
// temp vec of this round's resolving skills
|
||||||
// because need to check cooldown use before pushing them into the complete list
|
// because need to check cooldown use before pushing them into the complete list
|
||||||
let mut casts = vec![];
|
let mut casts = vec![];
|
||||||
let mut turn_events = 0;
|
let mut resolution_delay = 0;
|
||||||
|
|
||||||
while let Some(cast) = self.stack.pop() {
|
while let Some(cast) = self.stack.pop() {
|
||||||
// info!("{:} casts ", cast);
|
// info!("{:} casts ", cast);
|
||||||
|
|
||||||
let mut resolutions = resolution_steps(&cast, &mut self);
|
let mut resolutions = resolution_steps(&cast, &mut self);
|
||||||
turn_events += resolutions.len();
|
resolution_delay = resolutions.iter().fold(resolution_delay, |acc, r| acc + r.clone().get_delay());
|
||||||
self.resolved.append(&mut resolutions);
|
self.resolved.append(&mut resolutions);
|
||||||
|
|
||||||
// while let Some(resolution) = resolutions.pop() {
|
// while let Some(resolution) = resolutions.pop() {
|
||||||
@ -460,7 +457,7 @@ impl Game {
|
|||||||
return self.finish()
|
return self.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
self.skill_phase_start(turn_events)
|
self.skill_phase_start(resolution_delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn progress_durations(&mut self, resolved: &Vec<Cast>) -> &mut Game {
|
fn progress_durations(&mut self, resolved: &Vec<Cast>) -> &mut Game {
|
||||||
|
|||||||
@ -78,7 +78,7 @@ pub fn resolve(skill: Skill, source: &mut Construct, target: &mut Construct, mut
|
|||||||
return resolutions;
|
return resolutions;
|
||||||
}
|
}
|
||||||
|
|
||||||
if target.affected(Effect::Reflect) && skill.colours().contains(&Colour::Blue) {
|
if target.affected(Effect::Reflect) && skill.colours().contains(&Colour::Blue) && !skill.is_tick() {
|
||||||
// guard against overflow
|
// guard against overflow
|
||||||
if source.affected(Effect::Reflect) {
|
if source.affected(Effect::Reflect) {
|
||||||
return resolutions;
|
return resolutions;
|
||||||
@ -299,7 +299,17 @@ fn post_resolve(_skill: Skill, game: &mut Game, mut resolutions: Resolutions) ->
|
|||||||
.find(|e| e.effect == Effect::Electric).unwrap().clone();
|
.find(|e| e.effect == Effect::Electric).unwrap().clone();
|
||||||
match meta {
|
match meta {
|
||||||
Some(EffectMeta::Skill(s)) => {
|
Some(EffectMeta::Skill(s)) => {
|
||||||
|
// Gurad against reflect overflow
|
||||||
|
if !(source.affected(Effect::Reflect) && target.affected(Effect::Reflect)) {
|
||||||
|
// Check reflect don't bother if electrocute is procing on death
|
||||||
|
if source.affected(Effect::Reflect) && !target.is_ko() {
|
||||||
|
resolutions.push(Resolution::new(&target, &source)
|
||||||
|
.event(Event::Reflection { skill: s }).stages(EventStages::EndPost));
|
||||||
|
resolutions = electrocute(&mut source, &mut target, resolutions, s);
|
||||||
|
} else {
|
||||||
resolutions = electrocute(&mut target, &mut source, resolutions, s);
|
resolutions = electrocute(&mut target, &mut source, resolutions, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => panic!("no electrify skill"),
|
_ => panic!("no electrify skill"),
|
||||||
};
|
};
|
||||||
@ -405,7 +415,7 @@ pub enum EventStages {
|
|||||||
EndPost, // Skip Anim Anim
|
EndPost, // Skip Anim Anim
|
||||||
EndOnly, // Skip Anim Skip
|
EndOnly, // Skip Anim Skip
|
||||||
PostOnly, // Skip Skip Anim
|
PostOnly, // Skip Skip Anim
|
||||||
None, // Skip Skip Skip
|
NoStages, // Skip Skip Skip
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
|
#[derive(Debug,Clone,PartialEq,Serialize,Deserialize)]
|
||||||
@ -445,6 +455,25 @@ impl Resolution {
|
|||||||
self.stages = s;
|
self.stages = s;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_delay(self) -> i64 {
|
||||||
|
let source_duration = 1000; // Time for SOURCE ONLY
|
||||||
|
let target_delay = 500; // Used for Source + Target
|
||||||
|
let target_duration = 1500; // Time for TARGET ONLY
|
||||||
|
let post_skill = 1000; // Time for all POST
|
||||||
|
let source_and_target_total = target_delay + target_duration; // SOURCE + TARGET time
|
||||||
|
|
||||||
|
match self.stages {
|
||||||
|
EventStages::AllStages => source_and_target_total + post_skill, // Anim Anim Anim
|
||||||
|
EventStages::StartEnd => source_and_target_total, // Anim Anim Skip
|
||||||
|
EventStages::StartPost => source_duration + post_skill, // Anim Skip Anim
|
||||||
|
EventStages::StartOnly => source_duration, // Anim Skip Skip
|
||||||
|
EventStages::EndPost => target_duration + post_skill, // Skip Anim Anim
|
||||||
|
EventStages::EndOnly => target_duration, // Skip Anim Skip
|
||||||
|
EventStages::PostOnly => post_skill, // Skip Skip Anim
|
||||||
|
EventStages::NoStages => 0, // Skip Skip Skip
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -779,7 +808,7 @@ impl Skill {
|
|||||||
Skill::BashPlusPlus => 140,
|
Skill::BashPlusPlus => 140,
|
||||||
|
|
||||||
// Debuff Base
|
// Debuff Base
|
||||||
Skill::DecayTick=> 25,
|
Skill::DecayTick=> 33,
|
||||||
Skill::DecayTickPlus => 45,
|
Skill::DecayTickPlus => 45,
|
||||||
Skill::DecayTickPlusPlus => 70,
|
Skill::DecayTickPlusPlus => 70,
|
||||||
Skill::Silence=> 55, // Deals more per blue skill on target
|
Skill::Silence=> 55, // Deals more per blue skill on target
|
||||||
@ -1348,22 +1377,36 @@ fn sleep(source: &mut Construct, target: &mut Construct, mut results: Resolution
|
|||||||
|
|
||||||
fn sustain(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn sustain(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
let red_amount = source.red_power().pct(skill.multiplier());
|
let red_amount = source.red_power().pct(skill.multiplier());
|
||||||
results.push(Resolution::new(source, target)
|
results.push(Resolution::new(source, target).event(target.add_effect(skill, skill.effect()[0])));
|
||||||
.event(target.recharge(skill, red_amount, 0)));
|
let e = target.recharge(skill, red_amount, 0);
|
||||||
|
let stages = match e {
|
||||||
|
Event::Recharge { red, blue, skill: _ } => {
|
||||||
|
if red > 0 || blue > 0 { EventStages::PostOnly }
|
||||||
|
else { EventStages::NoStages }
|
||||||
|
}
|
||||||
|
_ => panic!("not recharge")
|
||||||
|
};
|
||||||
|
|
||||||
results.push(Resolution::new(source, target)
|
results.push(Resolution::new(source, target).event(e).stages(stages));
|
||||||
.event(target.add_effect(skill, skill.effect()[0]))
|
|
||||||
.stages(EventStages::PostOnly));
|
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intercept(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn intercept(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
let red_amount = source.red_power().pct(skill.multiplier());
|
|
||||||
results.push(Resolution::new(source, target).event(target.recharge(skill, red_amount, 0)));
|
|
||||||
|
|
||||||
let intercept = skill.effect()[0];
|
let intercept = skill.effect()[0];
|
||||||
results.push(Resolution::new(source, target).event(target.add_effect(skill, intercept)).stages(EventStages::PostOnly));
|
results.push(Resolution::new(source, target).event(target.add_effect(skill, intercept)));
|
||||||
|
|
||||||
|
let red_amount = source.red_power().pct(skill.multiplier());
|
||||||
|
let e = target.recharge(skill, red_amount, 0);
|
||||||
|
let stages = match e {
|
||||||
|
Event::Recharge { red, blue, skill: _ } => {
|
||||||
|
if red > 0 || blue > 0 { EventStages::PostOnly }
|
||||||
|
else { EventStages::NoStages }
|
||||||
|
}
|
||||||
|
_ => panic!("not recharge")
|
||||||
|
};
|
||||||
|
results.push(Resolution::new(source, target).event(e).stages(stages));
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1458,6 +1501,7 @@ fn heal(source: &mut Construct, target: &mut Construct, mut results: Resolutions
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn triage(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn triage(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
|
let skip_tick = target.effects.iter().any(|e| e.effect == Effect::Triage);
|
||||||
let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[0];
|
let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[0];
|
||||||
let tick_skill = match meta {
|
let tick_skill = match meta {
|
||||||
Some(EffectMeta::Skill(s)) => s,
|
Some(EffectMeta::Skill(s)) => s,
|
||||||
@ -1465,7 +1509,11 @@ fn triage(source: &mut Construct, target: &mut Construct, mut results: Resolutio
|
|||||||
};
|
};
|
||||||
let triage = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill));
|
let triage = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill));
|
||||||
results.push(Resolution::new(source, target).event(target.add_effect(skill, triage)));
|
results.push(Resolution::new(source, target).event(target.add_effect(skill, triage)));
|
||||||
return triage_tick(source, target, results, tick_skill);
|
|
||||||
|
match skip_tick {
|
||||||
|
true => return results,
|
||||||
|
false => return triage_tick(source, target, results, tick_skill)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn triage_tick(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn triage_tick(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
@ -1519,6 +1567,7 @@ fn decay(source: &mut Construct, target: &mut Construct, mut results: Resolution
|
|||||||
let wither = skill.effect()[0];
|
let wither = skill.effect()[0];
|
||||||
results.push(Resolution::new(source, target).event(target.add_effect(skill, wither)));
|
results.push(Resolution::new(source, target).event(target.add_effect(skill, wither)));
|
||||||
|
|
||||||
|
let skip_tick = target.effects.iter().any(|e| e.effect == Effect::Decay);
|
||||||
let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[1];
|
let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[1];
|
||||||
let tick_skill = match meta {
|
let tick_skill = match meta {
|
||||||
Some(EffectMeta::Skill(s)) => s,
|
Some(EffectMeta::Skill(s)) => s,
|
||||||
@ -1529,7 +1578,10 @@ fn decay(source: &mut Construct, target: &mut Construct, mut results: Resolution
|
|||||||
.event(target.add_effect(skill, decay))
|
.event(target.add_effect(skill, decay))
|
||||||
.stages(EventStages::PostOnly));
|
.stages(EventStages::PostOnly));
|
||||||
|
|
||||||
return decay_tick(source, target, results, tick_skill);
|
match skip_tick {
|
||||||
|
true => return results,
|
||||||
|
false => return decay_tick(source, target, results, tick_skill)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decay_tick(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn decay_tick(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
@ -1549,17 +1601,37 @@ fn electrify(source: &mut Construct, target: &mut Construct, mut results: Resolu
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn electrocute(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn electrocute(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
|
// Remove electric buff, no need to display if construct is dead
|
||||||
|
if !source.is_ko() {
|
||||||
|
let electric = source.effects.iter().position(|e| e.effect == Effect::Electric);
|
||||||
|
match electric {
|
||||||
|
Some(eff) => {
|
||||||
|
let ce = source.effects.remove(eff);
|
||||||
|
results.push(Resolution::new(source, source)
|
||||||
|
.event(Event::Removal { effect: ce.effect, construct_effects: source.effects.clone() })
|
||||||
|
.stages(EventStages::PostOnly));
|
||||||
|
}
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[0];
|
let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[0];
|
||||||
let tick_skill = match meta {
|
let tick_skill = match meta {
|
||||||
Some(EffectMeta::Skill(s)) => s,
|
Some(EffectMeta::Skill(s)) => s,
|
||||||
_ => panic!("no electrocute tick skill"),
|
_ => panic!("no electrocute tick skill"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let skip_tick = target.effects.iter().any(|e| e.effect == Effect::Electrocute);
|
||||||
let electrocute = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill));
|
let electrocute = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill));
|
||||||
results.push(Resolution::new(source, target)
|
results.push(Resolution::new(source, target)
|
||||||
.event(target.add_effect(skill, electrocute))
|
.event(target.add_effect(skill, electrocute))
|
||||||
.stages(EventStages::EndPost));
|
.stages(EventStages::PostOnly));
|
||||||
return electrocute_tick(source, target, results, tick_skill);
|
|
||||||
|
|
||||||
|
match skip_tick {
|
||||||
|
true => return results,
|
||||||
|
false => return electrocute_tick(source, target, results, tick_skill)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn electrocute_tick(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn electrocute_tick(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
@ -1617,22 +1689,36 @@ fn reflect(source: &mut Construct, target: &mut Construct, mut results: Resoluti
|
|||||||
results.push(Resolution::new(source, target).event(target.add_effect(skill, skill.effect()[0])));
|
results.push(Resolution::new(source, target).event(target.add_effect(skill, skill.effect()[0])));
|
||||||
|
|
||||||
let blue_amount = source.blue_power().pct(skill.multiplier());
|
let blue_amount = source.blue_power().pct(skill.multiplier());
|
||||||
results.push(Resolution::new(source, target)
|
let e = target.recharge(skill, 0, blue_amount);
|
||||||
.event(target.recharge(skill, 0, blue_amount))
|
let stages = match e {
|
||||||
.stages(EventStages::PostOnly));
|
Event::Recharge { red, blue, skill: _ } => {
|
||||||
|
if red > 0 || blue > 0 { EventStages::PostOnly }
|
||||||
|
else { EventStages::NoStages }
|
||||||
|
}
|
||||||
|
_ => panic!("not recharge")
|
||||||
|
};
|
||||||
|
results.push(Resolution::new(source, target).event(e).stages(stages));
|
||||||
return results;;
|
return results;;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recharge(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn recharge(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
let red_amount = source.red_power().pct(skill.multiplier());
|
let red_amount = source.red_power().pct(skill.multiplier());
|
||||||
let blue_amount = source.blue_power().pct(skill.multiplier());
|
let blue_amount = source.blue_power().pct(skill.multiplier());
|
||||||
|
let e = target.recharge(skill, red_amount, blue_amount);
|
||||||
results.push(Resolution::new(source, target).event(target.recharge(skill, red_amount, blue_amount)));
|
let stages = match e {
|
||||||
|
Event::Recharge { red, blue, skill: _ } => {
|
||||||
|
if red > 0 || blue > 0 { EventStages::AllStages }
|
||||||
|
else { EventStages::StartEnd }
|
||||||
|
}
|
||||||
|
_ => panic!("not recharge")
|
||||||
|
};
|
||||||
|
results.push(Resolution::new(source, target).event(e).stages(stages));
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn siphon(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn siphon(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
|
|
||||||
|
let skip_tick = target.effects.iter().any(|e| e.effect == Effect::Siphon);
|
||||||
let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[0];
|
let ConstructEffect { effect, duration, meta, tick: _ } = skill.effect()[0];
|
||||||
let tick_skill = match meta {
|
let tick_skill = match meta {
|
||||||
Some(EffectMeta::Skill(s)) => s,
|
Some(EffectMeta::Skill(s)) => s,
|
||||||
@ -1641,7 +1727,10 @@ fn siphon(source: &mut Construct, target: &mut Construct, mut results: Resolutio
|
|||||||
let siphon = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill));
|
let siphon = ConstructEffect::new(effect, duration).set_tick(Cast::new_tick(source, target, tick_skill));
|
||||||
results.push(Resolution::new(source, target).event(target.add_effect(skill, siphon)));
|
results.push(Resolution::new(source, target).event(target.add_effect(skill, siphon)));
|
||||||
|
|
||||||
return siphon_tick(source, target, results, tick_skill);
|
match skip_tick {
|
||||||
|
true => return results,
|
||||||
|
false => return siphon_tick(source, target, results, tick_skill)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn siphon_tick(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
fn siphon_tick(source: &mut Construct, target: &mut Construct, mut results: Resolutions, skill: Skill) -> Resolutions {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user