Merge branch 'release/1.4.2'

This commit is contained in:
ntr 2019-09-13 19:38:23 +10:00
commit c4b78734c8
99 changed files with 2404 additions and 433 deletions

View File

@ -8,6 +8,13 @@ minimal studios is ntr & mashy: 2 mates with a friendship forged in the fires of
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.
completely self funded, we're just here to make games that feel good & play it clean. completely self funded, we're just here to make games that feel good & play it clean.
## inspiration
- peggle
- soldat
- mini metro
- poe
- mtg
## Construct Alignments ## Construct Alignments

View File

@ -1 +1 @@
1.4.1 1.4.2

View File

@ -19,11 +19,6 @@
* msg pane * msg pane
* game invites * game invites
* change score to enum
* pct based translates for combat animation
* add speed to descriptions
* clear skill (if currently targetted)
## SOON ## SOON
*SERVER* *SERVER*

View File

@ -1,6 +1,6 @@
{ {
"name": "mnml-client", "name": "mnml-client",
"version": "1.4.1", "version": "1.4.2",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -0,0 +1 @@
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 272.1"><style>.st0{fill:#7289DA;}</style><path class="st0" d="M142.8 120.1c-5.7 0-10.2 4.9-10.2 11s4.6 11 10.2 11c5.7 0 10.2-4.9 10.2-11s-4.6-11-10.2-11zM106.3 120.1c-5.7 0-10.2 4.9-10.2 11s4.6 11 10.2 11c5.7 0 10.2-4.9 10.2-11 .1-6.1-4.5-11-10.2-11z"/><path class="st0" d="M191.4 36.9h-134c-11.3 0-20.5 9.2-20.5 20.5v134c0 11.3 9.2 20.5 20.5 20.5h113.4l-5.3-18.3 12.8 11.8 12.1 11.1 21.6 18.7V57.4c-.1-11.3-9.3-20.5-20.6-20.5zm-38.6 129.5s-3.6-4.3-6.6-8c13.1-3.7 18.1-11.8 18.1-11.8-4.1 2.7-8 4.6-11.5 5.9-5 2.1-9.8 3.4-14.5 4.3-9.6 1.8-18.4 1.3-25.9-.1-5.7-1.1-10.6-2.6-14.7-4.3-2.3-.9-4.8-2-7.3-3.4-.3-.2-.6-.3-.9-.5-.2-.1-.3-.2-.4-.2-1.8-1-2.8-1.7-2.8-1.7s4.8 7.9 17.5 11.7c-3 3.8-6.7 8.2-6.7 8.2-22.1-.7-30.5-15.1-30.5-15.1 0-31.9 14.4-57.8 14.4-57.8 14.4-10.7 28-10.4 28-10.4l1 1.2c-18 5.1-26.2 13-26.2 13s2.2-1.2 5.9-2.8c10.7-4.7 19.2-5.9 22.7-6.3.6-.1 1.1-.2 1.7-.2 6.1-.8 13-1 20.2-.2 9.5 1.1 19.7 3.9 30.1 9.5 0 0-7.9-7.5-24.9-12.6l1.4-1.6s13.7-.3 28 10.4c0 0 14.4 25.9 14.4 57.8 0-.1-8.4 14.3-30.5 15zM303.8 79.7h-33.2V117l22.1 19.9v-36.2h11.8c7.5 0 11.2 3.6 11.2 9.4v27.7c0 5.8-3.5 9.7-11.2 9.7h-34v21.1h33.2c17.8.1 34.5-8.8 34.5-29.2v-29.8c.1-20.8-16.6-29.9-34.4-29.9zm174 59.7v-30.6c0-11 19.8-13.5 25.8-2.5l18.3-7.4c-7.2-15.8-20.3-20.4-31.2-20.4-17.8 0-35.4 10.3-35.4 30.3v30.6c0 20.2 17.6 30.3 35 30.3 11.2 0 24.6-5.5 32-19.9l-19.6-9c-4.8 12.3-24.9 9.3-24.9-1.4zM417.3 113c-6.9-1.5-11.5-4-11.8-8.3.4-10.3 16.3-10.7 25.6-.8l14.7-11.3c-9.2-11.2-19.6-14.2-30.3-14.2-16.3 0-32.1 9.2-32.1 26.6 0 16.9 13 26 27.3 28.2 7.3 1 15.4 3.9 15.2 8.9-.6 9.5-20.2 9-29.1-1.8l-14.2 13.3c8.3 10.7 19.6 16.1 30.2 16.1 16.3 0 34.4-9.4 35.1-26.6 1-21.7-14.8-27.2-30.6-30.1zm-67 55.5h22.4V79.7h-22.4v88.8zM728 79.7h-33.2V117l22.1 19.9v-36.2h11.8c7.5 0 11.2 3.6 11.2 9.4v27.7c0 5.8-3.5 9.7-11.2 9.7h-34v21.1H728c17.8.1 34.5-8.8 34.5-29.2v-29.8c0-20.8-16.7-29.9-34.5-29.9zm-162.9-1.2c-18.4 0-36.7 10-36.7 30.5v30.3c0 20.3 18.4 30.5 36.9 30.5 18.4 0 36.7-10.2 36.7-30.5V109c0-20.4-18.5-30.5-36.9-30.5zm14.4 60.8c0 6.4-7.2 9.7-14.3 9.7-7.2 0-14.4-3.1-14.4-9.7V109c0-6.5 7-10 14-10 7.3 0 14.7 3.1 14.7 10v30.3zM682.4 109c-.5-20.8-14.7-29.2-33-29.2h-35.5v88.8h22.7v-28.2h4l20.6 28.2h28L665 138.1c10.7-3.4 17.4-12.7 17.4-29.1zm-32.6 12h-13.2v-20.3h13.2c14.1 0 14.1 20.3 0 20.3z"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1 @@
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 272.1"><style>.st0{fill:#FFFFFF;}</style><path class="st0" d="M142.8 120.1c-5.7 0-10.2 4.9-10.2 11s4.6 11 10.2 11c5.7 0 10.2-4.9 10.2-11s-4.6-11-10.2-11zM106.3 120.1c-5.7 0-10.2 4.9-10.2 11s4.6 11 10.2 11c5.7 0 10.2-4.9 10.2-11 .1-6.1-4.5-11-10.2-11z"/><path class="st0" d="M191.4 36.9h-134c-11.3 0-20.5 9.2-20.5 20.5v134c0 11.3 9.2 20.5 20.5 20.5h113.4l-5.3-18.3 12.8 11.8 12.1 11.1 21.6 18.7V57.4c-.1-11.3-9.3-20.5-20.6-20.5zm-38.6 129.5s-3.6-4.3-6.6-8c13.1-3.7 18.1-11.8 18.1-11.8-4.1 2.7-8 4.6-11.5 5.9-5 2.1-9.8 3.4-14.5 4.3-9.6 1.8-18.4 1.3-25.9-.1-5.7-1.1-10.6-2.6-14.7-4.3-2.3-.9-4.8-2-7.3-3.4-.3-.2-.6-.3-.9-.5-.2-.1-.3-.2-.4-.2-1.8-1-2.8-1.7-2.8-1.7s4.8 7.9 17.5 11.7c-3 3.8-6.7 8.2-6.7 8.2-22.1-.7-30.5-15.1-30.5-15.1 0-31.9 14.4-57.8 14.4-57.8 14.4-10.7 28-10.4 28-10.4l1 1.2c-18 5.1-26.2 13-26.2 13s2.2-1.2 5.9-2.8c10.7-4.7 19.2-5.9 22.7-6.3.6-.1 1.1-.2 1.7-.2 6.1-.8 13-1 20.2-.2 9.5 1.1 19.7 3.9 30.1 9.5 0 0-7.9-7.5-24.9-12.6l1.4-1.6s13.7-.3 28 10.4c0 0 14.4 25.9 14.4 57.8 0-.1-8.4 14.3-30.5 15zM303.8 79.7h-33.2V117l22.1 19.9v-36.2h11.8c7.5 0 11.2 3.6 11.2 9.4v27.7c0 5.8-3.5 9.7-11.2 9.7h-34v21.1h33.2c17.8.1 34.5-8.8 34.5-29.2v-29.8c.1-20.8-16.6-29.9-34.4-29.9zm174 59.7v-30.6c0-11 19.8-13.5 25.8-2.5l18.3-7.4c-7.2-15.8-20.3-20.4-31.2-20.4-17.8 0-35.4 10.3-35.4 30.3v30.6c0 20.2 17.6 30.3 35 30.3 11.2 0 24.6-5.5 32-19.9l-19.6-9c-4.8 12.3-24.9 9.3-24.9-1.4zM417.3 113c-6.9-1.5-11.5-4-11.8-8.3.4-10.3 16.3-10.7 25.6-.8l14.7-11.3c-9.2-11.2-19.6-14.2-30.3-14.2-16.3 0-32.1 9.2-32.1 26.6 0 16.9 13 26 27.3 28.2 7.3 1 15.4 3.9 15.2 8.9-.6 9.5-20.2 9-29.1-1.8l-14.2 13.3c8.3 10.7 19.6 16.1 30.2 16.1 16.3 0 34.4-9.4 35.1-26.6 1-21.7-14.8-27.2-30.6-30.1zm-67 55.5h22.4V79.7h-22.4v88.8zM728 79.7h-33.2V117l22.1 19.9v-36.2h11.8c7.5 0 11.2 3.6 11.2 9.4v27.7c0 5.8-3.5 9.7-11.2 9.7h-34v21.1H728c17.8.1 34.5-8.8 34.5-29.2v-29.8c0-20.8-16.7-29.9-34.5-29.9zm-162.9-1.2c-18.4 0-36.7 10-36.7 30.5v30.3c0 20.3 18.4 30.5 36.9 30.5 18.4 0 36.7-10.2 36.7-30.5V109c0-20.4-18.5-30.5-36.9-30.5zm14.4 60.8c0 6.4-7.2 9.7-14.3 9.7-7.2 0-14.4-3.1-14.4-9.7V109c0-6.5 7-10 14-10 7.3 0 14.7 3.1 14.7 10v30.3zM682.4 109c-.5-20.8-14.7-29.2-33-29.2h-35.5v88.8h22.7v-28.2h4l20.6 28.2h28L665 138.1c10.7-3.4 17.4-12.7 17.4-29.1zm-32.6 12h-13.2v-20.3h13.2c14.1 0 14.1 20.3 0 20.3z"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -36,10 +36,9 @@
} }
} }
.stripe-btn { .yellow-btn {
background: @yellow; background: @yellow;
color: black; color: black;
border-radius: 2px;
border-width: 0; border-width: 0;
&:active, &:focus, &:hover { &:active, &:focus, &:hover {

View File

@ -1,3 +1,5 @@
@import 'colours.less';
aside { aside {
grid-area: ctrl; grid-area: ctrl;
display: grid; display: grid;
@ -12,6 +14,10 @@ aside {
padding-left: 1em; padding-left: 1em;
.instance-ctrl {
grid-template-rows: 1fr 1fr 1fr min-content;
}
.controls { .controls {
grid-area: controls; grid-area: controls;
@ -20,6 +26,12 @@ aside {
grid-gap: 0.5em 0; grid-gap: 0.5em 0;
} }
&.play-ctrl {
.controls {
grid-template-rows: 4fr 4fr 1fr;
}
}
// fix chrome being inconsistent // fix chrome being inconsistent
table { table {
height: 100%; height: 100%;
@ -32,7 +44,7 @@ aside {
button { button {
width: 100%; width: 100%;
font-size: 150%; font-size: 150%;
margin: 0; margin-bottom: 0.5em;
} }
button.ready:enabled { button.ready:enabled {
@ -93,3 +105,21 @@ aside {
.team-page-ctrl h2 { .team-page-ctrl h2 {
padding: 0 0.75em 0 0.75em; padding: 0 0.75em 0 0.75em;
} }
.instance-ctrl-btns {
font-size: 50%;
}
.abandon:not([disabled]) {
&:hover {
color: @red;
border-color: @red;
border: 2px solid @red;
};
&:active, &.confirming {
background: @red;
color: black;
border: 2px solid black;
}
}

View File

@ -64,10 +64,18 @@
.options { .options {
grid-area: hdr; grid-area: hdr;
display: flex;
.logo {
flex: 0 1 10%;
margin-right: 1em;
border: none;
}
button { button {
width: 25%; flex: 1;
border-top: 0; border-top: 0;
border: 1px solid #222; border: 2px solid #222;
&:not(:last-child) { &:not(:last-child) {
border-right: 0; border-right: 0;
} }
@ -77,6 +85,11 @@
} }
} }
} }
.login {
display: flex;
flex-flow: column;
}
} }
section { section {
@ -99,6 +112,9 @@ section {
grid-gap: 1em; grid-gap: 1em;
flex-flow: row wrap; flex-flow: row wrap;
align-items: flex-end; align-items: flex-end;
button {
border-radius: 0.25em;
}
} }
figure { figure {
@ -109,3 +125,59 @@ section {
flex-flow: column; flex-flow: column;
} }
} }
.demo {
margin-top: 1em;
display: grid;
grid-template-areas:
"vinfo game"
"vcons game";
grid-template-columns: 1fr 1fr;
grid-template-rows: min-content 1fr;
.colour-info {
grid-area: vinfo;
display: flex;
align-items: center;
div {
display: flex;
}
svg {
flex: 1;
height: 1em;
}
}
.vbox-demo {
grid-area: vinfo;
}
.game-demo {
grid-area: game;
display: grid;
grid-template-columns: 1fr 2fr;
.game {
display: flex;
flex-flow: column;
.game-construct {
flex: 1;
}
}
}
.construct-list {
grid-area: vcons;
height: 100%;
svg {
height: 100%;
}
}
}

View File

@ -105,14 +105,14 @@ button, input {
height: auto; height: auto;
border-width: 2px; border-width: 2px;
border-color: @gray-exists; border-color: @gray-exists;
border-radius: 0;
letter-spacing: 0.25em; letter-spacing: 0.25em;
box-sizing: border-box; box-sizing: border-box;
font-size: 100%; font-size: 100%;
flex: 1; flex: 1;
border-radius: 0.5em;
/*the transitions */ /*the transitions */
transition-property: color, background; transition-property: border-color, color, background;
transition-duration: 0.25s; transition-duration: 0.25s;
transition-delay: 0; transition-delay: 0;
transition-timing-function: ease; transition-timing-function: ease;
@ -195,28 +195,6 @@ button[disabled] {
border-color: #222; border-color: #222;
} }
/*
LOGIN
*/
.welcome {
.login {
width: 50%;
display: flex;
flex-flow: column;
margin-bottom: 2em;
}
.options {
display: flex;
width: 50%;
}
h2 {
margin-bottom: 0.5em;
}
}
#mnml input, #mnml select { #mnml input, #mnml select {
border-color: #222; border-color: #222;
background-color: #222; background-color: #222;
@ -258,11 +236,14 @@ figure.gray {
header { header {
.options { .options {
font-size: 150%; font-size: 200%;
} }
button { button {
height: 2em; height: 2em;
// border-radius: 0.1em;
border: none;
border-radius: 0;
} }
} }
@ -272,18 +253,9 @@ header {
color: @white; color: @white;
box-shadow: inset 0px 5px 0px 0px @white; box-shadow: inset 0px 5px 0px 0px @white;
border: 0; border: 0;
&:first-child {
border-left: 1px solid #444;
} }
&:last-child { border: none;
border-right: 1px solid #444;
}
}
border: 1px solid #444;
flex: 1;
} }
} }
@ -299,3 +271,18 @@ ul {
li { li {
margin-bottom: 0.5em; margin-bottom: 0.5em;
} }
.logo {
height: 2em;
background-image: url("../../src/components/svgs/mnml.2.svg");
background-size: contain;
background-repeat: no-repeat;
background-position: left;
}
.discord-btn {
background-image: url("./../discord.white.svg");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}

View File

@ -1,6 +1,6 @@
{ {
"name": "mnml-client", "name": "mnml-client",
"version": "1.4.1", "version": "1.4.2",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -8,6 +8,8 @@ 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 });
export const setDemo = value => ({ type: 'SET_DEMO', value });
export const setActiveItem = value => ({ type: 'SET_ACTIVE_VAR', value }); export const setActiveItem = value => ({ type: 'SET_ACTIVE_VAR', value });
export const setActiveSkill = (constructId, skill) => ({ type: 'SET_ACTIVE_SKILL', value: constructId ? { constructId, skill } : null }); export const setActiveSkill = (constructId, skill) => ({ type: 'SET_ACTIVE_SKILL', value: constructId ? { constructId, skill } : null });
export const setCombiner = value => ({ type: 'SET_COMBINER', value: Array.from(value) }); export const setCombiner = value => ({ type: 'SET_COMBINER', value: Array.from(value) });

View File

@ -120,7 +120,7 @@ class AccountStatus extends Component {
// resub button // resub button
if (subscription.cancel_at_period_end) { if (subscription.cancel_at_period_end) {
return <button class='stripe-btn' onClick={() => sendSubscriptionEnding(false)}>Resubscribe</button> return <button class='yellow-btn' onClick={() => sendSubscriptionEnding(false)}>Resubscribe</button>
} }
const classes = `unsub ${unsubState ? 'confirming' : ''}`; const classes = `unsub ${unsubState ? 'confirming' : ''}`;

View File

@ -68,6 +68,7 @@ class ConstructAnimation extends Component {
const animSkill = removeTier(skill); const animSkill = removeTier(skill);
if (!constructId.includes(construct.id)) return false; if (!constructId.includes(construct.id)) return false;
// find target animation // find target animation
const chooseAnim = (animSkill) => { const chooseAnim = (animSkill) => {
switch (animSkill) { switch (animSkill) {

View File

@ -90,7 +90,7 @@ class Absorb extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -78,7 +78,7 @@ class Amplify extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -59,7 +59,7 @@ class Attack extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -100,7 +100,7 @@ class Bash extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -103,7 +103,7 @@ class Bash extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -88,7 +88,7 @@ class Blast extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -53,7 +53,7 @@ class Block extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -107,7 +107,7 @@ class Break extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -81,7 +81,7 @@ class Buff extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -69,10 +69,9 @@ class Chaos extends Component {
stroke: colour, stroke: colour,
}); });
}); });
anime.set('.skill-anim', { anime.set('.skill-anim', {
translateY: -300 * this.props.direction.y, translateY: -(window.screen.height) * 0.35 * this.props.direction.y,
translateX: -200 * this.props.direction.x, translateX: -(window.screen.width) * 0.15 * this.props.direction.x,
opacity: 0, opacity: 0,
}); });
anime.set('#explosion feDisplacementMap', { anime.set('#explosion feDisplacementMap', {
@ -120,7 +119,7 @@ class Chaos extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -85,7 +85,7 @@ class Counter extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -78,7 +78,7 @@ class Curse extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -83,7 +83,7 @@ class Debuff extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -68,7 +68,7 @@ class Decay extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -109,7 +109,7 @@ class Electrify extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -101,7 +101,7 @@ class Electrocute extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -83,7 +83,7 @@ class Haste extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -81,7 +81,7 @@ class Heal extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -88,7 +88,7 @@ class Hex extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -153,7 +153,7 @@ class Hybrid extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -96,7 +96,7 @@ class Intercept extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -91,7 +91,7 @@ class Link extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -81,7 +81,7 @@ class Purge extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -115,7 +115,7 @@ class Purify extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -95,7 +95,7 @@ class Recharge extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -76,7 +76,7 @@ class Block extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -82,7 +82,7 @@ class Intercept extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -77,7 +77,7 @@ class Refl extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -102,7 +102,7 @@ class Restrict extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -100,7 +100,7 @@ class Ruin extends Component {
this.animations[i].reset(); this.animations[i].reset();
} }
try { try {
this.props.animCb(); this.props.animCb && this.props.animCb();
} catch (e) { } catch (e) {
console.log(e); console.log(e);
} }

View File

@ -97,7 +97,7 @@ class Silence extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -69,9 +69,8 @@ class Siphon extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }
module.exports = addState(Siphon); module.exports = addState(Siphon);

View File

@ -116,7 +116,7 @@ class SiphonTick extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -91,7 +91,7 @@ class Slay extends Component {
}); });
anime.set('#slay', { anime.set('#slay', {
translateY: -400, translateY: -1 * (window.screen.height) * 0.35,
translateX: 0, translateX: 0,
}); });
anime.set('#explosion feDisplacementMap', { anime.set('#explosion feDisplacementMap', {
@ -152,7 +152,7 @@ class Slay extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -47,7 +47,7 @@ class Sleep extends Component {
version="1.1" version="1.1"
id="sleep" id="sleep"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="-291 -191 582 582"> viewBox="-291 -291 582 582">
<defs> <defs>
<filter id="sleepFilter"> <filter id="sleepFilter">
<feGaussianBlur stdDeviation="3"/> <feGaussianBlur stdDeviation="3"/>
@ -140,7 +140,7 @@ class Sleep extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -85,7 +85,7 @@ class Strike extends Component {
}); });
anime.set('#strike', { anime.set('#strike', {
translateY: -400, translateY: (window.screen.height) * 0.35 * this.props.direction.y,
translateX: 0, translateX: 0,
}); });
@ -120,7 +120,7 @@ class Strike extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -78,7 +78,7 @@ class Stun extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -127,7 +127,7 @@ class Sustain extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -80,7 +80,7 @@ class Triage extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -79,7 +79,7 @@ class TriageTick extends Component {
for (let i = this.animations.length - 1; i >= 0; i--) { for (let i = this.animations.length - 1; i >= 0; i--) {
this.animations[i].reset(); this.animations[i].reset();
} }
this.props.animCb(); this.props.animCb && this.props.animCb();
} }
} }

View File

@ -56,7 +56,7 @@ function Collection(args) {
teamSelect[insert] = id; teamSelect[insert] = id;
return setTeam(teamSelect); return setTeam(teamSelect);
} }
console.log(constructs.length);
const dispConstructs = constructs.length >= ((teamPage + 1) * 6) const dispConstructs = constructs.length >= ((teamPage + 1) * 6)
? constructs.slice(teamPage * 6, (teamPage + 1) * 6) ? constructs.slice(teamPage * 6, (teamPage + 1) * 6)
: constructs.slice(teamPage * 6, constructs.length); : constructs.slice(teamPage * 6, constructs.length);

View File

@ -0,0 +1,179 @@
const { connect } = require('preact-redux');
const preact = require('preact');
const actions = require('../actions');
const shapes = require('./shapes');
const { ConstructAvatar } = require('./construct');
const { ConstructAnimation } = require('./animations');
const addState = connect(
function receiveState(state) {
const {
account,
itemInfo,
demo,
} = state;
return {
account,
itemInfo,
demo,
};
},
function receiveDispatch(dispatch) {
function setAnimTarget(anim) {
dispatch(actions.setAnimTarget(anim));
}
return { setAnimTarget };
}
);
function Demo(args) {
const {
demo,
itemInfo,
account,
setAnimTarget,
} = args;
if (!demo || !itemInfo.items.length || account) return false;
const { combiner, items, equipping, equipped, players } = demo;
console.log(items);
const vboxDemo = () => {
function inventoryBtn(i, j) {
if (!i) return <button disabled class='empty' >&nbsp;</button>;
const highlighted = combiner.indexOf(j) > -1;
const classes = `${highlighted ? 'highlight' : ''}`;
if (shapes[i]) {
return <button class={classes} key={j}>{shapes[i]()}</button>;
}
return <button class={classes}>{i}</button>;
}
function combinerBtn() {
let text = '';
if (combiner.length < 3) {
for (let i = 0; i < 3; i++) {
if (combiner.length > i) {
text += '■ ';
} else {
text += '▫ ';
}
}
} else {
text = 'combine';
}
return (
<button
class='vbox-btn'
disabled={combiner.length !== 3}>
{text}
</button>
);
}
function inventoryElement() {
return (
<div class="vbox">
<div class='vbox-section'>
<h2 class='colour-info'>
VBOX PHASE {shapes.Red()} {shapes.Green()} {shapes.Blue()}
</h2>
<p>
Combine the colour base items with an array of skills and specialisations to build powerful variants.
</p>
</div>
<div>&nbsp;</div>
<div class='vbox-section'>
<div class='vbox-items'>
{items.map((i, j) => inventoryBtn(i, j))}
</div>
{combinerBtn()}
</div>
</div>
);
}
return (
<div class="news vbox-demo">
{inventoryElement()}
</div>
);
};
const vboxConstructs = () => {
const btnClass = equipping
? 'equipping empty gray'
: 'empty gray';
return (
<div class='news construct-list'>
{players[0].constructs.map((c, i) => (
<div class="instance-construct" key={i}>
<h2 class="name" >{c.name}</h2>
<ConstructAvatar construct={c} />
<div class="skills">
{i === 0 && equipped
? <button>Strike</button>
: <button disabled={!equipping} class={btnClass}>SKILL</button>
}
<button disabled={!equipping} class={btnClass}>SKILL</button>
<button disabled={!equipping} class={btnClass}>SKILL</button>
</div>
<div class="specs">
</div>
<div class="stats">
</div>
</div>
))}
</div>
);
};
const gameDemo = () => {
return (
<div class="game-demo">
<div>
<h2>COMBAT PHASE</h2>
<p>Battle your opponent using dynamic team builds from the VBOX phase.</p>
<p>Crafted skills can be used to damage the opponent or support your team.</p>
<p>Turn based combat, each team picks targets for their skills during this phase.</p>
<p>The damage dealt by skills, cast order and construct life depend on your decisions in the VBOX phase. </p>
</div>
<div class="game">
<div class="game-construct">
<ConstructAvatar construct={players[1].constructs[0]} />
<ConstructAnimation construct={players[1].constructs[0]} />
</div>
<div></div>
<div class="game-construct">
<ConstructAvatar construct={players[1].constructs[1]} />
<ConstructAnimation construct={players[1].constructs[1]} />
</div>
</div>
</div>
);
};
return (
<section class='demo news'>
{vboxDemo()}
{vboxConstructs()}
{gameDemo()}
</section>
);
}
module.exports = addState(Demo);

View File

@ -4,6 +4,7 @@ const { connect } = require('preact-redux');
const actions = require('../actions'); const actions = require('../actions');
const PlayerBox = require('./player.box'); const PlayerBox = require('./player.box');
const InstanceCtrlBtns = require('./instance.ctrl.btns');
const addState = connect( const addState = connect(
function receiveState(state) { function receiveState(state) {
@ -23,8 +24,18 @@ const addState = connect(
return ws.sendInstanceState(game.instance); return ws.sendInstanceState(game.instance);
} }
function sendGameSkillClear() {
return ws.sendGameSkillClear(game.id);
}
function sendAbandon() {
return ws.sendInstanceAbandon(game.instance);
}
return { return {
game, game,
sendAbandon,
sendGameSkillClear,
sendReady, sendReady,
account, account,
getInstanceState, getInstanceState,
@ -46,15 +57,19 @@ const addState = connect(
function Controls(args) { function Controls(args) {
const { const {
account, account,
sendAbandon,
game, game,
animating, animating,
sendGameSkillClear,
sendReady, sendReady,
quit,
getInstanceState, getInstanceState,
quit,
} = args; } = args;
if (!game) return false; if (!game) return false;
const { abandonState } = this.state;
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);
@ -92,13 +107,27 @@ function Controls(args) {
const readyBtn = <button disabled={animating} class="ready" onClick={() => sendReady()}>Ready</button>; const readyBtn = <button disabled={animating} class="ready" onClick={() => sendReady()}>Ready</button>;
const quitBtn = <button disabled={animating} onClick={quitClick}>Back</button>; const quitBtn = <button disabled={animating} onClick={quitClick}>Back</button>;
const cancelAbandon = e => {
e.stopPropagation();
return this.setState({ abandonState: false });
};
const abandonStateTrue = e => {
e.stopPropagation();
this.setState({ abandonState: true });
};
const abandonClasses = `abandon ${abandonState ? 'confirming' : ''}`;
const abandonAction = abandonState ? sendAbandon : abandonStateTrue;
return ( return (
<aside class="controls"> <aside onClick={cancelAbandon}>
{timer} {timer}
<div class="controls"> <div class="controls instance-ctrl">
<PlayerBox player={opponent}/> <PlayerBox player={opponent}/>
{game.phase === 'Finish' ? quitBtn : readyBtn} {game.phase === 'Finish' ? quitBtn : readyBtn}
<PlayerBox player={player} isPlayer={true}/> <PlayerBox player={player} isPlayer={true} />
<InstanceCtrlBtns />
</div> </div>
</aside> </aside>
); );

View File

@ -42,7 +42,6 @@ const addState = connect(
function receiveDispatch(dispatch) { function receiveDispatch(dispatch) {
function setActiveSkill(constructId, skill) { function setActiveSkill(constructId, skill) {
dispatch(actions.setActiveSkill(constructId, skill)); dispatch(actions.setActiveSkill(constructId, skill));
// particlesJS(`particles-${constructId}`, config);
} }
function setActiveConstruct(construct) { function setActiveConstruct(construct) {

View File

@ -73,10 +73,15 @@ function Header(args) {
return ( return (
<header> <header>
<div class="options"> <div class="options">
<button
onClick={() => navTo('play')}
class='logo login-btn'>
&nbsp;
</button>
<button <button
onClick={() => navTo('play')} onClick={() => navTo('play')}
class={`login-btn ${nav === 'play' ? 'highlight' : ''}`}> class={`login-btn ${nav === 'play' ? 'highlight' : ''}`}>
MNML Play
</button> </button>
<button <button
onClick={() => navTo('shop')} onClick={() => navTo('shop')}

View File

@ -3,7 +3,7 @@ const range = require('lodash/range');
const reactStringReplace = require('react-string-replace'); const reactStringReplace = require('react-string-replace');
const { INFO } = require('./../constants'); const { INFO } = require('./../constants');
const { convertItem } = require('../utils'); const { convertItem, removeTier, itemSpeed } = require('../utils');
const shapes = require('./shapes'); const shapes = require('./shapes');
function InfoComponent(args) { function InfoComponent(args) {
@ -21,15 +21,14 @@ function InfoComponent(args) {
return ( return (
<div> <div>
<h2>VBOX phase</h2> <h2>VBOX phase</h2>
<p>in this phase you strengthen and specialise your constructs by equipping items to them.</p> <p>strengthen and specialise your constructs by equipping items to them.</p>
<p>double clicking items in the <b>VBOX</b> will purchase and move them to your <b>INVENTORY</b>.</p> <p>double click to purchase items in the <b>VBOX</b> and move them to your <b>INVENTORY</b>.</p>
<p> <p>
hover over an item to see its effects and combinations.<br />
combine a <b>SKILL</b> or <b>SPEC</b> with 2 <b>COLOURS</b> to create an item.<br /> combine a <b>SKILL</b> or <b>SPEC</b> with 2 <b>COLOURS</b> to create an item.<br />
combine 3 of the same item to upgrade it.<br /> combine <b>3 of the same item</b> to upgrade it.<br />
click an item and then click a construct to equip that item to it.<br /> click an item and then click a construct to <b>equip</b> that item to it.<br />
</p> </p>
<p>click the <b>READY</b> button on the right to progress to the <b>GAME PHASE</b>.</p> <p>click the <b>READY</b> button for the <b>GAME PHASE</b>.</p>
</div> </div>
); );
} }
@ -41,12 +40,23 @@ function InfoComponent(args) {
if (isSkill) { if (isSkill) {
const regEx = /(RedPower|BluePower|GreenPower|RedLife|BlueLife|GreenLife|SpeedStat)/; const regEx = /(RedPower|BluePower|GreenPower|RedLife|BlueLife|GreenLife|SpeedStat)/;
const infoDescription = reactStringReplace(fullInfo.description, regEx, match => shapes[match]()); const infoDescription = reactStringReplace(fullInfo.description, regEx, match => shapes[match]());
const itemSource = itemInfo.combos.filter(c => c.item === removeTier(info));
const itemSourceInfo = itemSource.length
? `${itemSource[0].components[0]} ${itemSource[0].components[1]} ${itemSource[0].components[2]}`
: false;
const itemRegEx = /(Red|Blue|Green)/;
const itemSourceDescription = reactStringReplace(itemSourceInfo, itemRegEx, match => shapes[match]());
const calcSpeed = itemSource.length
? (24 + (itemSpeed(itemSource[0].components[0]) + itemSpeed(itemSource[0].components[1])) * itemSpeed(itemSource[0].components[2])) * 4
: (24 + itemSpeed(info)) * 4;
const speed = <div> Speed {shapes.SpeedStat()} multiplier {calcSpeed}% </div>;
return ( return (
<div class="info-skill"> <div class="info-skill">
<h2>{fullInfo.item}</h2> <h2>{fullInfo.item}</h2>
<h3>SKILL</h3> <h3>SKILL</h3>
{itemSourceDescription}
<div>{infoDescription}</div> <div>{infoDescription}</div>
{speed}
</div> </div>
); );
} }
@ -136,11 +146,18 @@ function InfoComponent(args) {
}); });
const regEx = /(RedPower|BluePower|GreenPower|RedLife|BlueLife|GreenLife|SpeedStat)/; const regEx = /(RedPower|BluePower|GreenPower|RedLife|BlueLife|GreenLife|SpeedStat)/;
const infoDescription = reactStringReplace(fullInfo.description, regEx, match => shapes[match]()); const infoDescription = reactStringReplace(fullInfo.description, regEx, match => shapes[match]());
const itemSource = itemInfo.combos.filter(c => c.item === info);
const itemSourceInfo = itemSource.length
? `${itemSource[0].components[0]} ${itemSource[0].components[1]} ${itemSource[0].components[2]}`
: false;
const itemRegEx = /(Red|Blue|Green)/;
const itemSourceDescription = reactStringReplace(itemSourceInfo, itemRegEx, match => shapes[match]());
return ( return (
<div class="info-spec"> <div class="info-spec">
<h2>{info}</h2> <h2>{info}</h2>
<h3>SPEC</h3> <h3>SPEC</h3>
{itemSourceDescription}
<div>{infoDescription}</div> <div>{infoDescription}</div>
<div class="thresholds"> <div class="thresholds">
{thresholds} {thresholds}

View File

@ -179,7 +179,7 @@ function Construct(props) {
const stats = Object.keys(STATS).map(s => { const stats = Object.keys(STATS).map(s => {
const stat = STATS[s]; const stat = STATS[s];
const info = (s === 'Speed' && 'Speed') const info = (s === 'SpeedStat' && 'Speed')
|| (s.includes('Power') && 'Power') || (s.includes('Power') && 'Power')
|| (s.includes('Life') && 'Life'); || (s.includes('Life') && 'Life');

View File

@ -0,0 +1,76 @@
const preact = require('preact');
const { connect } = require('preact-redux');
const actions = require('../actions');
const addState = connect(
function receiveState(state) {
const {
ws,
game,
instance,
animating,
} = state;
function sendReady() {
document.activeElement.blur();
return ws.sendGameReady(game.id);
}
function sendGameSkillClear() {
return ws.sendGameSkillClear(game.id);
}
function sendAbandon() {
const id = instance ? instance.id : game.instance;
return ws.sendInstanceAbandon(id);
}
return {
game,
instance,
animating,
sendAbandon,
sendGameSkillClear,
};
},
);
function InstanceCtrlBtns(args) {
const {
sendAbandon,
animating,
sendGameSkillClear,
game,
instance,
} = args;
const finished = instance && instance.phase === 'Finished';
const { abandonState } = this.state;
const cancelAbandon = e => {
e.stopPropagation();
return this.setState({ abandonState: false });
};
const abandonStateTrue = e => {
e.stopPropagation();
this.setState({ abandonState: true });
setTimeout(() => this.setState({ abandonState: false }), 2000);
};
const abandonClasses = `abandon ${abandonState ? 'confirming' : ''}`;
const abandonAction = abandonState ? sendAbandon : abandonStateTrue;
return (
<div class="instance-ctrl-btns">
{game ? <button disabled={animating} onClick={sendGameSkillClear}>Clear</button> : null}
<button class={abandonClasses} disabled={animating || finished} onClick={abandonAction}>Abandon</button>
</div>
);
}
module.exports = addState(InstanceCtrlBtns);

View File

@ -2,8 +2,8 @@ const preact = require('preact');
const { connect } = require('preact-redux'); const { connect } = require('preact-redux');
const actions = require('../actions'); const actions = require('../actions');
const PlayerBox = require('./player.box'); const PlayerBox = require('./player.box');
const InstanceCtrlBtns = require('./instance.ctrl.btns');
const addState = connect( const addState = connect(
function receiveState(state) { function receiveState(state) {
@ -15,12 +15,16 @@ const addState = connect(
} = state; } = state;
function sendReady() { function sendReady() {
document.activeElement.blur() document.activeElement.blur();
return ws.sendInstanceReady(instance.id); return ws.sendInstanceReady(instance.id);
return false; }
function sendAbandon() {
return ws.sendInstanceAbandon(instance.id);
} }
return { return {
sendAbandon,
instance, instance,
sendReady, sendReady,
account, account,
@ -41,6 +45,7 @@ const addState = connect(
function Controls(args) { function Controls(args) {
const { const {
account, account,
sendAbandon,
instance, instance,
sendReady, sendReady,
leave, leave,
@ -77,13 +82,20 @@ function Controls(args) {
</div> </div>
); );
const ready = instance.phase !== 'Finished'
? <button class="ready" onClick={() => sendReady()}>Ready</button>
: <button class="ready" onClick={leave}>Leave</button>
const abandon = instance.phase !== 'Finished' ? sendAbandon : false;
return ( return (
<aside> <aside>
{timer} {timer}
<div class="controls"> <div class="controls instance-ctrl">
<PlayerBox player={opponent} /> <PlayerBox player={opponent} />
<button class="ready" onClick={() => sendReady()}>Ready</button> {ready}
<PlayerBox player={player} isPlayer={true} leave={leave}/> <PlayerBox player={player} isPlayer={true} abandon={abandon}/>
<InstanceCtrlBtns />
</div> </div>
</aside> </aside>
); );

View File

@ -1,18 +1,11 @@
const preact = require('preact'); const preact = require('preact');
module.exports = function molecule(combatText) { module.exports = function molecule() {
const text = combatText return (
? <text x="0" y="400" class="combat-text"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 500 500">
{combatText}
<animate attributeType="XML" attributeName="y" from="300" to="200" dur="2s" repeatCount="1"/>
<animate attributeType="XML" attributeName="opacity" from="1" to="0" dur="2s" repeatCount="1"/>
</text>
: '';
return (<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 500 500">
<rect style="fill: none;"></rect> <rect style="fill: none;"></rect>
<g transform="translate(-133.97462520598594, -116.025374794014) "><g><line x1="325.9602631261639" x2="296.95475676906796" y1="332.53171849251754" y2="315.78489034176926" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: butt;"></line><line x1="267.949250411972" x2="296.95475676906796" y1="299.038062191021" y2="315.78489034176926" transform="" style="stroke-width: 3; stroke: #1FF01F;"></line></g><g><line x1="383.9712758403558" x2="383.9712758403558" y1="433.01268739700697" y2="466.5063436985035" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: butt;"></line><line x1="383.9712758403558" x2="383.9712758403558" y1="500" y2="466.5063436985035" transform="" style="stroke-width: 3; stroke: #1FF01F;"></line></g><g><line x1="383.9712758403558" x2="383.9712758403558" y1="299.038062191021" y2="265.5444058895245" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: butt;"></line><line x1="383.9712758403558" x2="383.9712758403558" y1="232.050749588028" y2="265.5444058895245" transform="" style="stroke-width: 3; stroke: #1FF01F;"></line></g><g><line x1="500" x2="470.994493642904" y1="433.01268739700697" y2="416.26585924625874" transform="" style="stroke: #1FF01F; stroke-width: 3; stroke-linecap: butt;"></line><line x1="441.98898728580804" x2="470.994493642904" y1="399.5190310955105" y2="416.26585924625874" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g><line x1="441.98898728580804" x2="470.994493642904" y1="332.53171849251754" y2="315.78489034176926" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: butt;"></line><line x1="500" x2="470.994493642904" y1="299.038062191021" y2="315.78489034176926" transform="" style="stroke-width: 3; stroke: #1FF01F;"></line></g><g><line x1="325.9602631261639" x2="296.95475676906796" y1="399.5190310955105" y2="416.26585924625874" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: butt;"></line><line x1="267.949250411972" x2="296.95475676906796" y1="433.01268739700697" y2="416.26585924625874" transform="" style="stroke-width: 3; stroke: #1FF01F;"></line></g><g><line x1="383.9712758403558" x2="354.96576948325986" y1="299.038062191021" y2="315.78489034176926" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: round;"></line><line x1="325.9602631261639" x2="354.96576948325986" y1="332.53171849251754" y2="315.78489034176926" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g><line x1="441.98898728580804" x2="412.98013156308195" y1="332.53171849251754" y2="315.78489034176926" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: round;"></line><line x1="383.9712758403558" x2="412.98013156308195" y1="299.038062191021" y2="315.78489034176926" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g><line x1="325.9602631261639" x2="325.9602631261639" y1="332.53171849251754" y2="366.02537479401406" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: round;"></line><line x1="325.9602631261639" x2="325.9602631261639" y1="399.5190310955105" y2="366.02537479401406" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g><line x1="383.9712758403558" x2="412.98013156308195" y1="433.01268739700697" y2="416.26585924625874" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: round;"></line><line x1="441.98898728580804" x2="412.98013156308195" y1="399.5190310955105" y2="416.26585924625874" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g><line x1="325.9602631261639" x2="354.96576948325986" y1="399.5190310955105" y2="416.26585924625874" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: round;"></line><line x1="383.9712758403558" x2="354.96576948325986" y1="433.01268739700697" y2="416.26585924625874" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g><line x1="441.98898728580804" x2="441.98898728580804" y1="399.5190310955105" y2="366.02537479401406" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: round;"></line><line x1="441.98898728580804" x2="441.98898728580804" y1="332.53171849251754" y2="366.02537479401406" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g class="atom" transform="translate(267.949250411972, 299.038062191021) "><circle r="8" style="fill: #1FF01F;"></circle></g><g class="atom" transform="translate(383.9712758403558, 500) "><circle r="8" style="fill: #1FF01F;"></circle></g><g class="atom" transform="translate(383.9712758403558, 232.050749588028) "><circle r="8" style="fill: #1FF01F;"></circle></g><g class="atom" transform="translate(500, 433.01268739700697) "><circle r="8" style="fill: #1FF01F;"></circle></g><g class="atom" transform="translate(500, 299.038062191021) "><circle r="8" style="fill: #1FF01F;"></circle></g><g class="atom" transform="translate(267.949250411972, 433.01268739700697) "><circle r="8" style="fill: #1FF01F;"></circle></g> <g transform="translate(-133.97462520598594, -116.025374794014) "><g><line x1="325.9602631261639" x2="296.95475676906796" y1="332.53171849251754" y2="315.78489034176926" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: butt;"></line><line x1="267.949250411972" x2="296.95475676906796" y1="299.038062191021" y2="315.78489034176926" transform="" style="stroke-width: 3; stroke: #1FF01F;"></line></g><g><line x1="383.9712758403558" x2="383.9712758403558" y1="433.01268739700697" y2="466.5063436985035" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: butt;"></line><line x1="383.9712758403558" x2="383.9712758403558" y1="500" y2="466.5063436985035" transform="" style="stroke-width: 3; stroke: #1FF01F;"></line></g><g><line x1="383.9712758403558" x2="383.9712758403558" y1="299.038062191021" y2="265.5444058895245" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: butt;"></line><line x1="383.9712758403558" x2="383.9712758403558" y1="232.050749588028" y2="265.5444058895245" transform="" style="stroke-width: 3; stroke: #1FF01F;"></line></g><g><line x1="500" x2="470.994493642904" y1="433.01268739700697" y2="416.26585924625874" transform="" style="stroke: #1FF01F; stroke-width: 3; stroke-linecap: butt;"></line><line x1="441.98898728580804" x2="470.994493642904" y1="399.5190310955105" y2="416.26585924625874" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g><line x1="441.98898728580804" x2="470.994493642904" y1="332.53171849251754" y2="315.78489034176926" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: butt;"></line><line x1="500" x2="470.994493642904" y1="299.038062191021" y2="315.78489034176926" transform="" style="stroke-width: 3; stroke: #1FF01F;"></line></g><g><line x1="325.9602631261639" x2="296.95475676906796" y1="399.5190310955105" y2="416.26585924625874" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: butt;"></line><line x1="267.949250411972" x2="296.95475676906796" y1="433.01268739700697" y2="416.26585924625874" transform="" style="stroke-width: 3; stroke: #1FF01F;"></line></g><g><line x1="383.9712758403558" x2="354.96576948325986" y1="299.038062191021" y2="315.78489034176926" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: round;"></line><line x1="325.9602631261639" x2="354.96576948325986" y1="332.53171849251754" y2="315.78489034176926" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g><line x1="441.98898728580804" x2="412.98013156308195" y1="332.53171849251754" y2="315.78489034176926" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: round;"></line><line x1="383.9712758403558" x2="412.98013156308195" y1="299.038062191021" y2="315.78489034176926" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g><line x1="325.9602631261639" x2="325.9602631261639" y1="332.53171849251754" y2="366.02537479401406" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: round;"></line><line x1="325.9602631261639" x2="325.9602631261639" y1="399.5190310955105" y2="366.02537479401406" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g><line x1="383.9712758403558" x2="412.98013156308195" y1="433.01268739700697" y2="416.26585924625874" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: round;"></line><line x1="441.98898728580804" x2="412.98013156308195" y1="399.5190310955105" y2="416.26585924625874" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g><line x1="325.9602631261639" x2="354.96576948325986" y1="399.5190310955105" y2="416.26585924625874" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: round;"></line><line x1="383.9712758403558" x2="354.96576948325986" y1="433.01268739700697" y2="416.26585924625874" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g><line x1="441.98898728580804" x2="441.98898728580804" y1="399.5190310955105" y2="366.02537479401406" transform="" style="stroke: #909090; stroke-width: 3; stroke-linecap: round;"></line><line x1="441.98898728580804" x2="441.98898728580804" y1="332.53171849251754" y2="366.02537479401406" transform="" style="stroke-width: 3; stroke: #909090;"></line></g><g class="atom" transform="translate(267.949250411972, 299.038062191021) "><circle r="8" style="fill: #1FF01F;"></circle></g><g class="atom" transform="translate(383.9712758403558, 500) "><circle r="8" style="fill: #1FF01F;"></circle></g><g class="atom" transform="translate(383.9712758403558, 232.050749588028) "><circle r="8" style="fill: #1FF01F;"></circle></g><g class="atom" transform="translate(500, 433.01268739700697) "><circle r="8" style="fill: #1FF01F;"></circle></g><g class="atom" transform="translate(500, 299.038062191021) "><circle r="8" style="fill: #1FF01F;"></circle></g><g class="atom" transform="translate(267.949250411972, 433.01268739700697) "><circle r="8" style="fill: #1FF01F;"></circle></g>
</g> </g>
{text} </svg>
</svg>); );
}; };

View File

@ -71,6 +71,11 @@ function JoinButtons(args) {
type="submit"> type="submit">
Learn Learn
</button> </button>
<button
class='discord-btn'
onClick={() => window.open('https://discord.gg/YJJgurM') }>
&nbsp;
</button>
</div> </div>
</aside> </aside>
); );

View File

@ -76,13 +76,13 @@ function Play(args) {
const subscription = account.subscribed const subscription = account.subscribed
? <button ? <button
class="stripe-btn" class="yellow-btn"
disabled> disabled>
Subscribed Subscribed
</button> </button>
: <button : <button
onClick={() => setNav('shop')} onClick={() => setNav('shop')}
class="stripe-btn" class="yellow-btn"
role="link"> role="link">
Subscribe Subscribe
</button>; </button>;
@ -91,7 +91,7 @@ function Play(args) {
return ( return (
<section class="top"> <section class="top">
<div class="news"> <div class="news">
<h1>mnml v{VERSION}</h1> <h1>v{VERSION}</h1>
<p>use the buttons on the right to join an instance.</p> <p>use the buttons on the right to join an instance.</p>
<p> <p>
select <b>PVP</b> to play against other players.<br /> select <b>PVP</b> to play against other players.<br />
@ -109,7 +109,7 @@ function Play(args) {
{subscription} {subscription}
<button <button
onClick={() => setNav('shop')} onClick={() => setNav('shop')}
class="stripe-btn" class="yellow-btn"
role="link"> role="link">
Get Credits Get Credits
</button> </button>

View File

@ -39,7 +39,7 @@ function Shop(args) {
<p> <p>
<b>subscriptions</b> grant extra benefits: <b>subscriptions</b> grant extra benefits:
<ul> <ul>
<li>additional credits</li> <li>¤150 per month</li>
<li>chat wheel (soon )</li> <li>chat wheel (soon )</li>
<li>account icons (soon )</li> <li>account icons (soon )</li>
</ul> </ul>

View File

@ -45,13 +45,13 @@ function BitsBtn(args) {
const subscription = account.subscribed const subscription = account.subscribed
? <button ? <button
class="stripe-btn" class="yellow-btn"
disabled> disabled>
Subscribed Subscribed
</button> </button>
: <button : <button
onClick={subscribeClick} onClick={subscribeClick}
class="stripe-btn" class="yellow-btn"
role="link"> role="link">
Subscribe Subscribe
</button>; </button>;
@ -64,19 +64,19 @@ function BitsBtn(args) {
<div class='list'> <div class='list'>
<figure onClick={() => bitsClick(5)} > <figure onClick={() => bitsClick(5)} >
<figcaption>$5 AUD</figcaption> <figcaption>$5 AUD</figcaption>
<button class="stripe-btn">¤50</button> <button class="yellow-btn">¤50</button>
</figure> </figure>
<figure onClick={() => bitsClick(10)} > <figure onClick={() => bitsClick(10)} >
<figcaption>$10 AUD</figcaption> <figcaption>$10 AUD</figcaption>
<button class="stripe-btn">¤110</button> <button class="yellow-btn">¤110</button>
</figure> </figure>
<figure onClick={() => bitsClick(20)} > <figure onClick={() => bitsClick(20)} >
<figcaption>$20 AUD</figcaption> <figcaption>$20 AUD</figcaption>
<button class="stripe-btn">¤250</button> <button class="yellow-btn">¤250</button>
</figure> </figure>
<figure onClick={() => bitsClick(50)} > <figure onClick={() => bitsClick(50)} >
<figcaption>$50 AUD</figcaption> <figcaption>$50 AUD</figcaption>
<button class="stripe-btn">¤660</button> <button class="yellow-btn">¤660</button>
</figure> </figure>
<div id="error-message"></div> <div id="error-message"></div>
</div> </div>

View File

@ -0,0 +1,5 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 198.13 199.94" >
<ellipse cx="100" cy="100" rx="30" ry="30"/>
<ellipse cx="100" cy="100" rx="60" ry="60"/>
<ellipse cx="100" cy="100" rx="90" ry="90"/>
</svg>

After

Width:  |  Height:  |  Size: 266 B

View File

@ -0,0 +1,184 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="800mm"
height="320mm"
viewBox="0 0 800 320"
version="1.1"
id="svg16"
inkscape:version="0.92.1 r15371"
sodipodi:docname="mnml.2.svg"
inkscape:export-filename="/home/ntr/notes/mnml/logo.1.png"
inkscape:export-xdpi="33.290001"
inkscape:export-ydpi="33.290001">
<defs
id="defs10">
<font
horiz-adv-x="1024"
id="font1681"
inkscape:label="font 1"
horiz-origin-x="0"
horiz-origin-y="0"
vert-origin-x="45"
vert-origin-y="90"
vert-adv-y="90">
<font-face
units-per-em="1024"
id="font-face1683"
font-family="jura book" />
<missing-glyph
d="M0,0h1000v1024h-1000z"
id="missing-glyph1685" />
</font>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="0.17652669"
inkscape:cx="-1319.6072"
inkscape:cy="1669.4273"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:snap-grids="false"
inkscape:window-width="2560"
inkscape:window-height="1417"
inkscape:window-x="0"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:measure-start="2425.38,406.879"
inkscape:measure-end="1249.73,1603.74"
inkscape:snap-to-guides="false"
inkscape:snap-global="false"
borderlayer="false"
inkscape:showpageshadow="false">
<inkscape:grid
type="xygrid"
id="grid18"
color="#ff453f"
opacity="0.1254902"
empcolor="#ff453f"
empopacity="0.25098039"
spacingx="13.229167"
spacingy="13.229167"
originx="-309.61981"
originy="-386.26976" />
</sodipodi:namedview>
<metadata
id="metadata13">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-309.6198,409.26974)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:202.02764893px;line-height:1.25;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:94.70045471;stroke-miterlimit:4;stroke-dasharray:none"
x="304.63995"
y="-255.67854"
id="text22"><tspan
dx="0 0 0 20"
sodipodi:role="line"
id="tspan20"
x="304.63995"
y="-255.67854"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:202.02764893px;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:94.70045471;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0">mnml.gg</tspan></text>
<g
id="g1874">
<g
style="fill:none;stroke:#f5f5f5;stroke-width:9.80856895;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.47777575,0,0,0.47777575,509.84135,-209.12233)"
id="g936">
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:9.80856895;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="190,190 10,190 100,10 "
id="polygon920" />
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:9.80856895;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="160,170 40,170 100,50 "
id="polygon922" />
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:9.80856895;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="130,150 70,150 100,90 "
id="polygon924" />
</g>
<g
style="fill:none;stroke:#f5f5f5;stroke-width:9.61643505;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.48732156,0,0,0.48732156,318.23159,-210.93603)"
id="g986">
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:9.61643505;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="10"
y="10"
width="180"
height="180"
id="rect970" />
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:9.61643505;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="40"
y="40"
width="120"
height="120"
id="rect972" />
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:9.61643505;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="70"
y="70"
width="60"
height="60"
id="rect974" />
</g>
<g
style="fill:none;stroke:#f5f5f5;stroke-width:9.78425312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.47896311,0,0,0.47896311,700.3778,-209.34793)"
id="g1136">
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:9.78425312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="30"
cx="100"
cy="100"
id="ellipse1120" />
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:9.78425312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="60"
cx="100"
cy="100"
id="ellipse1122" />
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:9.78425312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="90"
cx="100"
cy="100"
id="ellipse1124" />
</g>
</g>
<path
sodipodi:nodetypes="cccc"
style="fill:none;stroke:#f5f5fa;stroke-width:5.29166651;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 320.79192,-228.53672 h 476.24812 l 66.30344,66.3036 h 236.61072"
id="path1152"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="800mm"
height="500mm"
viewBox="0 0 800 500"
version="1.1"
id="svg16"
inkscape:version="0.92.1 r15371"
sodipodi:docname="mnml.3.svg"
inkscape:export-filename="/home/ntr/notes/mnml/logo.0.png"
inkscape:export-xdpi="33.290001"
inkscape:export-ydpi="33.290001">
<defs
id="defs10" />
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="0.31458958"
inkscape:cx="339.43091"
inkscape:cy="1053.2018"
inkscape:document-units="mm"
inkscape:current-layer="g1085"
showgrid="false"
inkscape:snap-grids="false"
inkscape:window-width="2560"
inkscape:window-height="1417"
inkscape:window-x="0"
inkscape:window-y="23"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid18"
color="#ff453f"
opacity="0.1254902"
empcolor="#ff453f"
empopacity="0.25098039"
spacingx="13.229167"
spacingy="13.229167"
originx="-318.50419"
originy="-300.77664" />
</sodipodi:namedview>
<metadata
id="metadata13">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-318.50418,503.77662)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:202.02764893px;line-height:1.25;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:94.70045471;stroke-miterlimit:4;stroke-dasharray:none"
x="324.63995"
y="-321.57922"
id="text22"><tspan
sodipodi:role="line"
id="tspan20"
x="324.63995"
y="-321.57922"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:202.02764893px;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:94.70045471;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0">mnml.gg</tspan></text>
<g
id="g1085"
transform="translate(-3.5762787e-6,282.74713)">
<g
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.61133548,0,0,0.61133548,658.17325,-455.06409)"
id="g936">
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="190,190 10,190 100,10 "
id="polygon920" />
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="160,170 40,170 100,50 "
id="polygon922" />
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="130,150 70,150 100,90 "
id="polygon924" />
</g>
<g
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.62354979,0,0,0.62354979,333.74058,-457.40471)"
id="g986">
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="10"
y="10"
width="180"
height="180"
id="rect970" />
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="40"
y="40"
width="120"
height="120"
id="rect972" />
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="70"
y="70"
width="60"
height="60"
id="rect974" />
</g>
<g
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.61285479,0,0,0.61285479,981.23264,-456.33521)"
id="g1136">
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="30"
cx="100"
cy="100"
id="ellipse1120" />
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="60"
cx="100"
cy="100"
id="ellipse1122" />
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="90"
cx="100"
cy="100"
id="ellipse1124" />
</g>
<circle
style="fill:none;stroke:#a52a2a;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="22.942408"
cx="360.85284"
cy="-498.49799"
id="circle1125" />
<circle
id="circle1132"
cy="-498.49799"
cx="564.80573"
r="22.942408"
style="fill:none;stroke:#1ff01f;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
style="fill:none;stroke:#3050f8;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="22.942408"
cx="768.75867"
cy="-498.49799"
id="circle1134" />
</g>
<path
style="fill:none;stroke:#f5f5fa;stroke-width:5.29166651;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 337.00836,-261.44316 h 476.24812 l 66.30344,66.30345 h 219.95898"
id="path1152"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="800mm"
height="500mm"
viewBox="0 0 800 500"
version="1.1"
id="svg16"
inkscape:version="0.92.1 r15371"
sodipodi:docname="mnml.4.svg"
inkscape:export-filename="/home/ntr/Dropbox/mnml/mnml.4.png"
inkscape:export-xdpi="33.290001"
inkscape:export-ydpi="33.290001">
<defs
id="defs10" />
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="0.22244843"
inkscape:cx="763.22194"
inkscape:cy="952.76605"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-grids="false"
inkscape:window-width="2560"
inkscape:window-height="1417"
inkscape:window-x="0"
inkscape:window-y="23"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid18"
color="#ff453f"
opacity="0.1254902"
empcolor="#ff453f"
empopacity="0.25098039"
spacingx="13.229167"
spacingy="13.229167"
originx="-318.50419"
originy="-300.77663" />
</sodipodi:namedview>
<metadata
id="metadata13">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-318.50418,503.77661)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:179.92054749px;line-height:1.25;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:84.3377533;stroke-miterlimit:4;stroke-dasharray:none"
x="366.74548"
y="-214.34631"
id="text22"><tspan
sodipodi:role="line"
id="tspan20"
x="366.74548"
y="-214.34631"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:179.92054749px;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:84.3377533;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0">mnml.gg</tspan></text>
<g
id="g936"
transform="matrix(0.54443942,0,0,0.54443942,664.50223,-143.74083)"
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
<polygon
id="polygon920"
points="10,190 100,10 190,190 "
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<polygon
id="polygon922"
points="40,170 100,50 160,170 "
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<polygon
id="polygon924"
points="70,150 100,90 130,150 "
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
id="g986"
transform="matrix(0.55531716,0,0,0.55531716,375.75615,-145.82532)"
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
<rect
id="rect970"
height="180"
width="180"
y="10"
x="10"
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
id="rect972"
height="120"
width="120"
y="40"
x="40"
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
id="rect974"
height="60"
width="60"
y="70"
x="70"
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
id="g1136"
transform="matrix(0.54579247,0,0,0.54579247,952.02526,-144.87285)"
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
<circle
id="ellipse1120"
cy="100"
cx="100"
r="30"
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
id="ellipse1122"
cy="100"
cx="100"
r="60"
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
id="ellipse1124"
cy="100"
cx="100"
r="90"
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
id="g5700"
transform="translate(61.243363,-7.5514839)">
<circle
style="fill:none;stroke:#a52a2a;stroke-width:8.4862175;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="48.673557"
cx="371.42084"
cy="-408.40045"
id="circle1125" />
<circle
id="circle1132"
cy="-408.40045"
cx="657.2608"
r="48.673557"
style="fill:none;stroke:#1ff01f;stroke-width:8.48621655;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
style="fill:none;stroke:#3050f8;stroke-width:8.48621559;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="48.673557"
cx="943.10077"
cy="-407.21103"
id="circle1134" />
</g>
<path
style="fill:none;stroke:#f5f5fa;stroke-width:5.29166651;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 334.62953,307.09686 h 476.24812 l 66.30344,66.30345 h 219.95901"
id="path1152"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -0,0 +1,191 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1400mm"
height="1000mm"
viewBox="0 0 1400 999.99999"
version="1.1"
id="svg16"
inkscape:version="0.92.1 r15371"
sodipodi:docname="mnml.horizontal.svg"
inkscape:export-filename="/home/ntr/notes/mnml/logo.1.png"
inkscape:export-xdpi="33.290001"
inkscape:export-ydpi="33.290001">
<defs
id="defs10">
<font
horiz-adv-x="1024"
id="font1681"
inkscape:label="font 1"
horiz-origin-x="0"
horiz-origin-y="0"
vert-origin-x="45"
vert-origin-y="90"
vert-adv-y="90">
<font-face
units-per-em="1024"
id="font-face1683"
font-family="jura book" />
<missing-glyph
d="M0,0h1000v1024h-1000z"
id="missing-glyph1685" />
</font>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="0.31538333"
inkscape:cx="2645.6693"
inkscape:cy="1889.7638"
inkscape:document-units="mm"
inkscape:current-layer="g1189"
showgrid="false"
inkscape:snap-grids="false"
inkscape:window-width="2560"
inkscape:window-height="1417"
inkscape:window-x="0"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:measure-start="2425.38,406.879"
inkscape:measure-end="1249.73,1603.74"
inkscape:snap-to-guides="false"
inkscape:snap-global="false">
<inkscape:grid
type="xygrid"
id="grid18"
color="#ff453f"
opacity="0.1254902"
empcolor="#ff453f"
empopacity="0.25098039"
spacingx="13.229167"
spacingy="13.229167"
originx="-309.61983"
originy="-380.09401" />
</sodipodi:namedview>
<metadata
id="metadata13">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-309.61979,1083.094)">
<g
id="g1189"
transform="translate(1.1156274,26.93094)">
<g
id="g931"
transform="translate(271.63304,-379.93571)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:202.02764893px;line-height:1.25;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:94.70045471;stroke-miterlimit:4;stroke-dasharray:none"
x="293.90451"
y="-223.2944"
id="text22"><tspan
dx="0 0 0 20"
sodipodi:role="line"
id="tspan20"
x="293.90451"
y="-223.2944"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:202.02764893px;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:94.70045471;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0">mnml.gg</tspan></text>
<g
transform="translate(884.80779)"
id="g913">
<g
style="fill:none;stroke:#f5f5f5;stroke-width:9.80856895;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.27710921,0,0,0.27710921,225.5806,-256.1823)"
id="g936">
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:9.80856895;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="100,10 190,190 10,190 "
id="polygon920" />
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:9.80856895;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="100,50 160,170 40,170 "
id="polygon922" />
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:9.80856895;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="100,90 130,150 70,150 "
id="polygon924" />
</g>
<g
style="fill:none;stroke:#f5f5f5;stroke-width:9.61643505;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.28264577,0,0,0.28264577,224.68531,-351.621)"
id="g986">
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:9.61643505;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="10"
y="10"
width="180"
height="180"
id="rect970" />
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:9.61643505;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="40"
y="40"
width="120"
height="120"
id="rect972" />
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:9.61643505;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="70"
y="70"
width="60"
height="60"
id="rect974" />
</g>
<g
style="fill:none;stroke:#f5f5f5;stroke-width:9.78425312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.27779788,0,0,0.27779788,224.73379,-164.16552)"
id="g1136">
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:9.78425312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="30"
cx="100"
cy="100"
id="ellipse1120" />
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:9.78425312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="60"
cx="100"
cy="100"
id="ellipse1122" />
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:9.78425312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="90"
cx="100"
cy="100"
id="ellipse1124" />
</g>
</g>
<path
sodipodi:nodetypes="cccc"
style="fill:none;stroke:#f5f5fa;stroke-width:5.29166651;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 310.05649,-185.15011 h 476.24812 l 66.30344,66.3036 h 236.61075"
id="path1152"
inkscape:connector-curvature="0" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="800mm"
height="350mm"
viewBox="0 0 800 350"
version="1.1"
id="svg16"
inkscape:version="0.92.1 r15371"
sodipodi:docname="mnml.line.svg"
inkscape:export-filename="/home/ntr/notes/mnml/logo.0.png"
inkscape:export-xdpi="33.290001"
inkscape:export-ydpi="33.290001">
<defs
id="defs10" />
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="0.33139063"
inkscape:cx="934.2462"
inkscape:cy="720.22548"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-grids="false"
inkscape:window-width="2560"
inkscape:window-height="1417"
inkscape:window-x="0"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:showpageshadow="false"
showborder="true">
<inkscape:grid
type="xygrid"
id="grid18"
color="#ff453f"
opacity="0.1254902"
empcolor="#ff453f"
empopacity="0.25098039"
spacingx="13.229167"
spacingy="13.229167"
originx="-337.00838"
originy="-489.49389" />
</sodipodi:namedview>
<metadata
id="metadata13">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-337.00836,542.49388)">
<g
id="g1085"
transform="translate(-3.5762787e-6,282.74713)" />
<g
id="g1701"
transform="translate(1.5e-5,-47.027751)">
<text
id="text22"
y="-321.57922"
x="342.0285"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:202.02764893px;line-height:1.25;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:94.70045471;stroke-miterlimit:4;stroke-dasharray:none"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:202.02764893px;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:94.70045471;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0"
y="-321.57922"
x="342.0285"
id="tspan20"
sodipodi:role="line">mnml.gg</tspan></text>
<path
inkscape:connector-curvature="0"
id="path1152"
d="m 355.75309,-261.44316 h 476.24812 l 66.30344,66.30345 h 219.95895"
style="fill:none;stroke:#f5f5fa;stroke-width:5.29166651;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="800mm"
height="800mm"
viewBox="0 0 800 800"
version="1.1"
id="svg16"
inkscape:version="0.92.1 r15371"
sodipodi:docname="mnml.plain.svg"
inkscape:export-filename="/home/ntr/Dropbox/mnml/mnml.discord.png"
inkscape:export-xdpi="33.290001"
inkscape:export-ydpi="33.290001">
<defs
id="defs10" />
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="0.22244843"
inkscape:cx="814.91932"
inkscape:cy="952.76605"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-grids="false"
inkscape:window-width="2560"
inkscape:window-height="1417"
inkscape:window-x="0"
inkscape:window-y="23"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid18"
color="#ff453f"
opacity="0.1254902"
empcolor="#ff453f"
empopacity="0.25098039"
spacingx="13.229167"
spacingy="13.229167"
originx="-318.50419"
originy="-300.77663" />
</sodipodi:namedview>
<metadata
id="metadata13">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-318.50418,803.77661)">
<g
id="g5786"
transform="translate(-7.5725212e-6,-150)">
<text
id="text22"
y="-214.34631"
x="366.74548"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:179.92054749px;line-height:1.25;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:84.3377533;stroke-miterlimit:4;stroke-dasharray:none"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:179.92054749px;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:84.3377533;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0"
y="-214.34631"
x="366.74548"
id="tspan20"
sodipodi:role="line">mnml.gg</tspan></text>
<g
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.54443942,0,0,0.54443942,664.50223,-143.74083)"
id="g936">
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="100,10 190,190 10,190 "
id="polygon920" />
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="100,50 160,170 40,170 "
id="polygon922" />
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="100,90 130,150 70,150 "
id="polygon924" />
</g>
<g
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.55531716,0,0,0.55531716,375.75615,-145.82532)"
id="g986">
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="10"
y="10"
width="180"
height="180"
id="rect970" />
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="40"
y="40"
width="120"
height="120"
id="rect972" />
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="70"
y="70"
width="60"
height="60"
id="rect974" />
</g>
<g
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.54579247,0,0,0.54579247,952.02526,-144.87285)"
id="g1136">
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="30"
cx="100"
cy="100"
id="ellipse1120" />
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="60"
cx="100"
cy="100"
id="ellipse1122" />
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="90"
cx="100"
cy="100"
id="ellipse1124" />
</g>
<g
transform="translate(61.243363,-7.5514839)"
id="g5700">
<circle
id="circle1125"
cy="-408.40045"
cx="371.42084"
r="48.673557"
style="fill:none;stroke:#a52a2a;stroke-width:8.4862175;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
style="fill:none;stroke:#1ff01f;stroke-width:8.48621655;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="48.673557"
cx="657.2608"
cy="-408.40045"
id="circle1132" />
<circle
id="circle1134"
cy="-407.21103"
cx="943.10077"
r="48.673557"
style="fill:none;stroke:#3050f8;stroke-width:8.48621559;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
<path
style="fill:none;stroke:#f5f5fa;stroke-width:5.29166651;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 334.62953,307.09686 h 476.24812 l 66.30344,66.30345 h 219.95901"
id="path1152"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -0,0 +1,190 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="800mm"
height="500mm"
viewBox="0 0 800 500"
version="1.1"
id="svg16"
inkscape:version="0.92.1 r15371"
sodipodi:docname="mnml.svg"
inkscape:export-filename="/home/ntr/notes/mnml/logo.0.png"
inkscape:export-xdpi="33.290001"
inkscape:export-ydpi="33.290001">
<defs
id="defs10" />
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="0.31458958"
inkscape:cx="494.17573"
inkscape:cy="535.02564"
inkscape:document-units="mm"
inkscape:current-layer="g1189"
showgrid="true"
inkscape:snap-grids="false"
inkscape:window-width="2560"
inkscape:window-height="1417"
inkscape:window-x="0"
inkscape:window-y="23"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid18"
color="#ff453f"
opacity="0.1254902"
empcolor="#ff453f"
empopacity="0.25098039"
spacingx="13.229167"
spacingy="13.229167"
originx="-318.50419"
originy="-300.77664" />
</sodipodi:namedview>
<metadata
id="metadata13">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-318.50418,503.77662)">
<g
id="g1189"
transform="translate(1.1156274,26.93094)">
<g
id="g1010"
transform="translate(18.50418,-50.77662)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:202.02764893px;line-height:1.25;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:94.70045471;stroke-miterlimit:4;stroke-dasharray:none"
x="305.02014"
y="-159.79291"
id="text22"><tspan
sodipodi:role="line"
id="tspan20"
x="305.02014"
y="-159.79291"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:202.02764893px;font-family:Jura;-inkscape-font-specification:'Jura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#f5f5f5;fill-opacity:1;stroke:none;stroke-width:94.70045471;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0">mnml.gg</tspan></text>
<g
id="g1150"
transform="translate(0,-13.758336)">
<g
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.61133548,0,0,0.61133548,638.55344,-417.46007)"
id="g936">
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="10,190 100,10 190,190 "
id="polygon920" />
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="40,170 100,50 160,170 "
id="polygon922" />
<polygon
style="fill:none;stroke:#f5f5f5;stroke-width:5.92435312;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
points="70,150 100,90 130,150 "
id="polygon924" />
</g>
<g
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.62354979,0,0,0.62354979,314.12077,-419.80069)"
id="g986">
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="10"
y="10"
width="180"
height="180"
id="rect970" />
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="40"
y="40"
width="120"
height="120"
id="rect972" />
<rect
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="70"
y="70"
width="60"
height="60"
id="rect974" />
</g>
<g
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.61285479,0,0,0.61285479,961.61283,-418.73119)"
id="g1136">
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="30"
cx="100"
cy="100"
id="ellipse1120" />
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="60"
cx="100"
cy="100"
id="ellipse1122" />
<circle
style="fill:none;stroke:#f5f5f5;stroke-width:5.62481165;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
r="90"
cx="100"
cy="100"
id="ellipse1124" />
</g>
<flowRoot
transform="matrix(0.26458333,0,0,0.26458333,-1.1156274,-716.1726)"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
id="flowRoot1191"
xml:space="preserve"><flowRegion
id="flowRegion1193"><rect
y="2484.8455"
x="1209.269"
height="507.98291"
width="2396.061"
id="rect1195" /></flowRegion><flowPara
style="fill:#f00000;fill-opacity:0;stroke:none;stroke-opacity:1"
id="flowPara1197">abstract strategy</flowPara></flowRoot> <text
id="text1201"
y="-36.125034"
x="455.61945"
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="stroke-width:0.26458332"
y="-36.125034"
x="455.61945"
id="tspan1199"
sodipodi:role="line">v</tspan></text>
</g>
<path
style="fill:none;stroke:#f5f5fa;stroke-width:5.29166651;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 317.38855,-99.656848 h 476.24812 l 66.30344,66.303445 h 219.95899"
id="path1152"
inkscape:connector-curvature="0" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -0,0 +1,6 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
viewBox="0 0 200 200" >
<rect x="10" y="10" width="180" height="180"/>
<rect x="40" y="40" width="120" height="120"/>
<rect x="70" y="70" width="60" height="60"/>
</svg>

After

Width:  |  Height:  |  Size: 270 B

View File

@ -0,0 +1,6 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
viewBox="0 0 200 200" >
<polygon points="10,190 100,10 190,190"/>
<polygon points="40,170 100,50 160,170"/>
<polygon points="70,150 100,90 130,150"/>
</svg>

After

Width:  |  Height:  |  Size: 271 B

View File

@ -4,7 +4,8 @@ const preact = require('preact');
const Login = require('./welcome.login'); const Login = require('./welcome.login');
const Register = require('./welcome.register'); const Register = require('./welcome.register');
const Help = require('./welcome.help'); const Help = require('./welcome.help');
const About = require('./welcome.about'); // const About = require('./welcome.about');
const Demo = require('./demo');
function Welcome() { function Welcome() {
const page = this.state.page || 'login'; const page = this.state.page || 'login';
@ -13,21 +14,19 @@ function Welcome() {
const pageEl = () => { const pageEl = () => {
if (page === 'login') return <Login />; if (page === 'login') return <Login />;
if (page === 'register') return <Register />; if (page === 'register') return <Register />;
if (page === 'about') return <About navRegister={navRegister} />;
if (page === 'help') return <Help />; if (page === 'help') return <Help />;
return false; return false;
}; };
return ( return (
<main class="welcome"> <main class="menu">
<h1>mnml.gg</h1> <header>
<div class="login">
<div>mnml is an abstract turn based strategy game</div>
<div>free to play</div>
<div>no email required</div>
<div>glhf</div>
</div>
<div class="options"> <div class="options">
<button
onClick={() => this.setState({ page: 'login' })}
class='logo login-btn'>
&nbsp;
</button>
<button <button
class={`login-btn ${page === 'login' ? 'highlight' : ''}`} class={`login-btn ${page === 'login' ? 'highlight' : ''}`}
disabled={page === 'login'} disabled={page === 'login'}
@ -40,12 +39,6 @@ function Welcome() {
onClick={() => this.setState({ page: 'register' })}> onClick={() => this.setState({ page: 'register' })}>
Register Register
</button> </button>
<button
class={`login-btn ${page === 'about' ? 'highlight' : ''}`}
disabled={page === 'about'}
onClick={() => this.setState({ page: 'about' })}>
About
</button>
<button <button
class={`login-btn ${page === 'help' ? 'highlight' : ''}`} class={`login-btn ${page === 'help' ? 'highlight' : ''}`}
disabled={page === 'help'} disabled={page === 'help'}
@ -53,7 +46,28 @@ function Welcome() {
Help Help
</button> </button>
</div> </div>
</header>
<div class="top">
<section>
<div class="news">
<p>
mnml is a turn-based 1v1 strategy game in an abstract setting.<br />
outplay your opponents by building your team of 3 constructs from a shifting meta of skills, effects and specialisations.<br />
</p>
<p>
simple rules, complex interactions, simultaneous turns to increase the pace, and a unique speed mechanic;<br />
mnml is a tactical game unlike any other.
</p>
<p>
free to play<br />
no email required<br />
glhf
</p>
</div>
{pageEl()} {pageEl()}
</section>
</div>
<Demo />
</main> </main>
); );
} }

View File

@ -12,8 +12,8 @@ const addState = connect(
ws ws
} = state; } = state;
function submitRegister(name, password, code) { function submitRegister(name, password) {
postData('/account/register', { name, password, code }) postData('/account/register', { name, password })
.then(res => res.json()) .then(res => res.json())
.then(data => { .then(data => {
if (data.error) return errorToast(data.error); if (data.error) return errorToast(data.error);
@ -34,19 +34,18 @@ function Register(args) {
submitRegister, submitRegister,
} = args; } = args;
const { password, confirm, name, code } = this.state; const { password, confirm, name } = this.state;
const registerSubmit = (event) => { const registerSubmit = (event) => {
event.preventDefault(); event.preventDefault();
submitRegister(name, password, code); submitRegister(name, password);
// this.setState({ name: '', password: '', confirm: '', code: ''});
} }
const registerConfirm = () => const registerConfirm = () =>
password === confirm; password === confirm;
const registerDisabled = () => { const registerDisabled = () => {
return !(registerConfirm() && password && name && code); return !(registerConfirm() && password && name);
} }
return ( return (
@ -75,14 +74,6 @@ function Register(args) {
value={this.state.confirm} value={this.state.confirm}
onInput={linkState(this, 'confirm')} onInput={linkState(this, 'confirm')}
/> />
<label for="code">Access Code</label>
<input
class="login-input"
type="text"
placeholder="code"
value={this.state.code}
onInput={linkState(this, 'code')}
/>
<button <button
class="login-btn" class="login-btn"
disabled={registerDisabled()} disabled={registerDisabled()}

View File

@ -1,3 +1,5 @@
const preact = require('preact');
const SOURCE_DURATION_MS = 1000; const SOURCE_DURATION_MS = 1000;
const TARGET_DELAY_MS = 500; const TARGET_DELAY_MS = 500;
const TARGET_DURATION_MS = 1500; const TARGET_DURATION_MS = 1500;
@ -24,15 +26,11 @@ module.exports = {
INFO: { INFO: {
vbox: { vbox: {
item: 'VBOX', item: 'VBOX',
description: 'Contains ITEMS that are available for you to buy.\nDouble-click to purchase.', description: <p><b>ITEMS</b> that are available to buy.<br />the <b>VBOX</b> is refilled every round.<br />click <b>REFILL</b> at the bottom to purchase a refill. </p>,
}, },
inventory: { inventory: {
item: 'INVENTORY', item: 'INVENTORY',
description: 'Holds purchased ITEMS.\nClick to add ITEM to I-COMBINATOR.', description: <p>holds <b>ITEMS</b><br /><b>ITEMS</b> carry over each round.</p>,
},
combiner: {
item: 'I-COMBINATOR',
description: 'Combines purchased ITEMS into more powerful variants. Hover over an ITEM to see recipes.',
}, },
bits: { bits: {
item: 'BITS', item: 'BITS',
@ -51,12 +49,12 @@ module.exports = {
description: 'Reclaim ITEMS for half the purchase cost of their combined ITEMS.\nClick to enable and click ITEM to reclaim.', description: 'Reclaim ITEMS for half the purchase cost of their combined ITEMS.\nClick to enable and click ITEM to reclaim.',
}, },
refine: { refine: {
item: 'REFINE', item: 'COMBINE',
description: 'Refine ITEMS currently in I-COMBINATOR into more powerful variants', description: <p>combine the selected items.<br />hover over an item to see <b>RECIPES</b>.</p>,
}, },
refill: { refill: {
item: 'REFILL', item: 'REFILL',
description: 'Refill the VBOX with new ITEMS.', description: 'Refill the VBOX with new items.',
}, },
equipSkills: { equipSkills: {
item: 'QUICK ACCESS - SKILLS', item: 'QUICK ACCESS - SKILLS',

View File

@ -1,4 +1,5 @@
const eachSeries = require('async/eachSeries'); const eachSeries = require('async/eachSeries');
const sample = require('lodash/sample');
const actions = require('./actions'); const actions = require('./actions');
const { TIMES } = require('./constants'); const { TIMES } = require('./constants');
@ -168,7 +169,7 @@ function registerEvents(store) {
} }
function setInstance(v) { function setInstance(v) {
const { account, instance } = store.getState(); const { account, instance, ws } = store.getState();
if (v) { if (v) {
const player = v.players.find(p => p.id === account.id); const player = v.players.find(p => p.id === account.id);
store.dispatch(actions.setPlayer(player)); store.dispatch(actions.setPlayer(player));
@ -179,6 +180,11 @@ function registerEvents(store) {
store.dispatch(actions.setActiveConstruct(first)); store.dispatch(actions.setActiveConstruct(first));
} }
} }
if (v.phase === 'Finished') {
setGame(null);
ws.sendAccountInstances();
}
return store.dispatch(actions.setInstance(v)); return store.dispatch(actions.setInstance(v));
} }
@ -186,6 +192,53 @@ function registerEvents(store) {
return store.dispatch(actions.setItemInfo(v)); return store.dispatch(actions.setItemInfo(v));
} }
function setDemo(d) {
const initial = {
players: d,
combiner: [],
items: ['Red', 'Red', 'Attack'],
equipped: false,
equipping: false,
};
const startDemo = () => {
console.log(initial);
store.dispatch(actions.setDemo(initial));
store.dispatch(actions.setAnimTarget(null));
setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, initial, { combiner: [0] }))), 2000);
setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, initial, { combiner: [0, 1] }))), 4000);
setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, initial, { combiner: [0, 1, 2] }))), 6000);
setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, initial, { combiner: [], items: ['Strike', '', ''] }))), 8000);
setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, initial, { combiner: [0], items: ['Strike', '', ''], equipping: true }))), 10000);
setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, initial, { combiner: [], items: ['', '', ''], equipped: true, equipping: false }))), 12000);
setTimeout(() => store.dispatch(actions.setDemo(Object.assign({}, initial, { items: ['', '', ''], equipped: true, equipping: false }))), 12000);
setTimeout(() => {
const { itemInfo } = store.getState();
return store.dispatch(actions.setAnimTarget({
skill: sample(itemInfo.items.filter(i => i.skill)).item,
constructId: d[1].constructs[0].id,
player: false,
direction: 0,
}));
}, 14000);
setTimeout(() => {
const { itemInfo } = store.getState();
return store.dispatch(actions.setAnimTarget({
skill: sample(itemInfo.items.filter(i => i.skill)).item,
constructId: d[1].constructs[1].id,
player: true,
direction: 0,
}));
}, 16000);
setTimeout(startDemo, 20000);
};
startDemo();
}
// events.on('SET_PLAYER', setInstance); // events.on('SET_PLAYER', setInstance);
// events.on('SEND_SKILL', function skillActive(gameId, constructId, targetConstructId, skill) { // events.on('SEND_SKILL', function skillActive(gameId, constructId, targetConstructId, skill) {
@ -229,6 +282,7 @@ function registerEvents(store) {
setAccountInstances, setAccountInstances,
setActiveItem, setActiveItem,
setActiveSkill, setActiveSkill,
setDemo,
setConstructList, setConstructList,
setNewConstruct, setNewConstruct,
setGame, setGame,

View File

@ -23,6 +23,8 @@ module.exports = {
animTarget: createReducer(null, 'SET_ANIM_TARGET'), animTarget: createReducer(null, 'SET_ANIM_TARGET'),
animText: createReducer(null, 'SET_ANIM_TEXT'), animText: createReducer(null, 'SET_ANIM_TEXT'),
demo: createReducer(null, 'SET_DEMO'),
combiner: createReducer([], 'SET_COMBINER'), combiner: createReducer([], 'SET_COMBINER'),
constructs: createReducer([], 'SET_CONSTRUCTS'), constructs: createReducer([], 'SET_CONSTRUCTS'),
constructEditId: createReducer(null, 'SET_CONSTRUCT_EDIT_ID'), constructEditId: createReducer(null, 'SET_CONSTRUCT_EDIT_ID'),

View File

@ -108,6 +108,11 @@ function createSocket(events) {
events.setActiveSkill(null); events.setActiveSkill(null);
} }
function sendGameSkillClear(gameId) {
send(['GameSkillClear', { game_id: gameId }]);
events.setActiveSkill(null);
}
function sendGameTarget(gameId, constructId, skillId) { function sendGameTarget(gameId, constructId, skillId) {
send(['GameTarget', { game_id: gameId, construct_id: constructId, skill_id: skillId }]); send(['GameTarget', { game_id: gameId, construct_id: constructId, skill_id: skillId }]);
events.setActiveSkill(null); events.setActiveSkill(null);
@ -125,6 +130,10 @@ function createSocket(events) {
send(['InstanceReady', { instance_id: instanceId }]); send(['InstanceReady', { instance_id: instanceId }]);
} }
function sendInstanceAbandon(instanceId) {
send(['InstanceAbandon', { instance_id: instanceId }]);
}
function sendMtxApply(constructId, mtx, name) { function sendMtxApply(constructId, mtx, name) {
send(['MtxConstructApply', { construct_id: constructId, mtx, name }]); send(['MtxConstructApply', { construct_id: constructId, mtx, name }]);
if (mtx === 'Rename') { if (mtx === 'Rename') {
@ -197,10 +206,14 @@ function createSocket(events) {
events.setItemInfo(info); events.setItemInfo(info);
} }
function onDemo(v) {
events.setDemo(v);
}
let pongTimeout; let pongTimeout;
function onPong() { function onPong() {
events.setPing(Date.now() - ping); events.setPing(Date.now() - ping);
// pongTimeout = setTimeout(sendPing, 1000); pongTimeout = setTimeout(sendPing, 10000);
} }
// ------------- // -------------
@ -222,6 +235,7 @@ function createSocket(events) {
InstanceState: onInstanceState, InstanceState: onInstanceState,
ItemInfo: onItemInfo, ItemInfo: onItemInfo,
Pong: onPong, Pong: onPong,
Demo: onDemo,
QueueRequested: () => events.notify('pvp queue request received'), QueueRequested: () => events.notify('pvp queue request received'),
QueueJoined: () => events.notify('you have joined the pvp queue'), QueueJoined: () => events.notify('you have joined the pvp queue'),
@ -316,8 +330,10 @@ function createSocket(events) {
sendGameState, sendGameState,
sendGameReady, sendGameReady,
sendGameSkill, sendGameSkill,
sendGameSkillClear,
sendGameTarget, sendGameTarget,
sendInstanceAbandon,
sendInstanceReady, sendInstanceReady,
sendInstancePractice, sendInstancePractice,
sendInstanceQueue, sendInstanceQueue,

View File

@ -187,6 +187,20 @@ const removeTier = skill => {
return skill; return skill;
}; };
function itemSpeed(item) {
switch (item) {
case 'Attack': return 1;
case 'Stun': return 2;
case 'Block': return 3;
case 'Buff': return 4;
case 'Debuff': return 4;
case 'Red': return 3;
case 'Green': return 2;
case 'Blue': return 1;
default: return 0;
}
}
function postData(url = '/', data = {}) { function postData(url = '/', data = {}) {
// Default options are marked with * // Default options are marked with *
return fetch(`/api${url}`, { return fetch(`/api${url}`, {
@ -250,5 +264,6 @@ module.exports = {
TARGET_COLOURS, TARGET_COLOURS,
randomPoints, randomPoints,
removeTier, removeTier,
itemSpeed,
match, match,
}; };

View File

@ -1,6 +1,6 @@
{ {
"name": "mnml-ops", "name": "mnml-ops",
"version": "1.4.1", "version": "1.4.2",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mnml" name = "mnml"
version = "1.4.1" version = "1.4.2"
authors = ["ntr <ntr@smokestack.io>"] authors = ["ntr <ntr@smokestack.io>"]
[dependencies] [dependencies]
@ -33,10 +33,13 @@ router = "0.6"
mount = "0.4" mount = "0.4"
cookie = "0.12" cookie = "0.12"
crossbeam-channel = "0.3" crossbeam-channel = "0.3"
ws = "0.8" ws = { version = "0.8", features = ["ssl"] }
lettre = "0.9" lettre = "0.9"
lettre_email = "0.9" lettre_email = "0.9"
stripe-rust = "0.10" stripe-rust = "0.10"
# stripe-rust = { path = "/home/ntr/code/stripe-rs" } # stripe-rust = { path = "/home/ntr/code/stripe-rs" }
reqwest = "0.9"
url = "1"

View File

@ -288,15 +288,11 @@ pub fn set_subscribed(tx: &mut Transaction, id: Uuid, subscribed: bool) -> Resul
Ok(name) Ok(name)
} }
pub fn create(name: &String, password: &String, code: &String, tx: &mut Transaction) -> Result<String, MnmlHttpError> { pub fn create(name: &String, password: &String, tx: &mut Transaction) -> Result<String, MnmlHttpError> {
if password.len() < PASSWORD_MIN_LEN { if password.len() < PASSWORD_MIN_LEN {
return Err(MnmlHttpError::PasswordUnacceptable); return Err(MnmlHttpError::PasswordUnacceptable);
} }
if code.to_lowercase() != "grep842" {
return Err(MnmlHttpError::InvalidCode);
}
if name.len() == 0 { if name.len() == 0 {
return Err(MnmlHttpError::AccountNameNotProvided); return Err(MnmlHttpError::AccountNameNotProvided);
} }

101
server/src/bin/svt.rs Normal file
View File

@ -0,0 +1,101 @@
extern crate reqwest;
extern crate rand;
extern crate ws;
extern crate mnml;
extern crate serde_cbor;
use std::env;
use std::thread;
use serde_cbor::{from_slice, to_vec};
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use reqwest::header;
use std::iter;
use ws::{connect, CloseCode, Message, Handler, Sender, Result, Request, Response};
use mnml::rpc::{RpcRequest};
use mnml::{setup_logger};
struct Bot {
out: Sender,
token: String,
}
impl Handler for Bot {
fn build_request(&mut self, url: &url::Url) -> Result<Request> {
let mut req = Request::from_url(url)?;
let token = format!("x-auth-token={:}", self.token);
println!("{:?}", token);
req.headers_mut().push(("Cookie".to_string(), Vec::from(token)));
Ok(req)
}
fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> {
println!("websocket connected");
let pvp_q = to_vec(&RpcRequest::InstanceQueue {}).unwrap();
self.out.send(Message::Binary(pvp_q)).unwrap();
Ok(())
}
}
fn main() {
let args: Vec<String> = env::args().collect();
let num_clients: usize = args[1].parse().unwrap();
setup_logger().unwrap();
let mut clients = vec![];
for i in 0..num_clients {
clients.push(thread::Builder::new().name(i.to_string()).spawn(|| {
let mut rng = thread_rng();
let name: String = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(12).collect();
let password: String = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(12).collect();
let mut headers = header::HeaderMap::new();
headers.insert(header::CONTENT_TYPE, header::HeaderValue::from_static("application/json"));
let client = reqwest::Client::builder()
.cookie_store(true)
.default_headers(headers)
.build()
.unwrap();
let register_body = format!("{{ \"name\": {:?}, \"password\": {:?}, \"code\": \"grep842\" }}", name, password);
println!("{:?}", register_body);
let account = client.post("https://sixtysix.pro/api/account/register")
.body(register_body)
.send()
.unwrap();
println!("{:?}", account.headers().get("set-cookie"));
let ws = thread::Builder::new().name(name).spawn(move || {
connect("wss://sixtysix.pro/api/ws", |out| {
let token_cookie = account.cookies()
.find(|c| c.name() == "x-auth-token")
.unwrap();
Bot {
out: out,
token: token_cookie.value().to_string(),
}
}).unwrap()
}).unwrap();
ws.join().unwrap();
}).unwrap());
}
for client in clients {
let _ = client.join();
}
}

View File

@ -1,3 +1,5 @@
use std::fs::File;
use rand::prelude::*; use rand::prelude::*;
use uuid::Uuid; use uuid::Uuid;
@ -322,6 +324,17 @@ impl Game {
return Ok(self); return Ok(self);
} }
fn clear_skill(&mut self, player_id: Uuid) -> Result<&mut Game, Error> {
self.player_by_id(player_id)?;
if self.phase != Phase::Skill {
return Err(err_msg("game not in skill phase"));
}
let mut game_state = self.clone();
self.stack.retain(|s| game_state.construct_by_id(s.source_construct_id).unwrap().account == player_id);
return Ok(self);
}
fn player_ready(&mut self, player_id: Uuid) -> Result<&mut Game, Error> { fn player_ready(&mut self, player_id: Uuid) -> Result<&mut Game, Error> {
if self.phase != Phase::Skill { if self.phase != Phase::Skill {
return Err(err_msg("game not in skill phase")); return Err(err_msg("game not in skill phase"));
@ -853,7 +866,12 @@ pub fn game_update(tx: &mut Transaction, game: &Game) -> Result<(), Error> {
result.iter().next().ok_or(format_err!("game {:?} could not be written", game))?; result.iter().next().ok_or(format_err!("game {:?} could not be written", game))?;
if game.finished() { if game.finished() {
info!("game finished state={:?}", game); info!("finished id={:?}", game.id);
match game_json_file_write(&game) {
Ok(dest) => info!("wrote dest={:?}", dest),
Err(e) => error!("json write error={:?}", e),
};
if let Some(i) = game.instance { if let Some(i) = game.instance {
instance_game_finished(tx, &game, i)?; instance_game_finished(tx, &game, i)?;
@ -863,6 +881,12 @@ pub fn game_update(tx: &mut Transaction, game: &Game) -> Result<(), Error> {
return Ok(()); return Ok(());
} }
fn game_json_file_write(g: &Game) -> Result<String, Error> {
let dest = format!("/var/lib/mnml/data/games/{}.mnml.game.json", g.id);
serde_json::to_writer(File::create(&dest)?, g)?;
Ok(dest)
}
pub fn game_skill(tx: &mut Transaction, account: &Account, game_id: Uuid, construct_id: Uuid, target_construct_id: Option<Uuid>, skill: Skill) -> Result<Game, Error> { pub fn game_skill(tx: &mut Transaction, account: &Account, game_id: Uuid, construct_id: Uuid, target_construct_id: Option<Uuid>, skill: Skill) -> Result<Game, Error> {
let mut game = game_get(tx, game_id)?; let mut game = game_get(tx, game_id)?;
@ -877,6 +901,20 @@ pub fn game_skill(tx: &mut Transaction, account: &Account, game_id: Uuid, constr
Ok(game) Ok(game)
} }
pub fn game_skill_clear(tx: &mut Transaction, account: &Account, game_id: Uuid) -> Result<Game, Error> {
let mut game = game_get(tx, game_id)?;
game.clear_skill(account.id)?;
if game.skill_phase_finished() {
game = game.resolve_phase_start();
}
game_update(tx, &game)?;
Ok(game)
}
pub fn game_ready(tx: &mut Transaction, account: &Account, id: Uuid) -> Result<Game, Error> { pub fn game_ready(tx: &mut Transaction, account: &Account, id: Uuid) -> Result<Game, Error> {
let mut game = game_get(tx, id)?; let mut game = game_get(tx, id)?;

View File

@ -52,8 +52,6 @@ pub enum MnmlHttpError {
PasswordUnacceptable, PasswordUnacceptable,
#[fail(display="incorrect token. refresh or logout of existing sessions")] #[fail(display="incorrect token. refresh or logout of existing sessions")]
TokenDoesNotMatch, TokenDoesNotMatch,
#[fail(display="invalid code. https://discord.gg/YJJgurM")]
InvalidCode,
} }
impl From<bcrypt::BcryptError> for MnmlHttpError { impl From<bcrypt::BcryptError> for MnmlHttpError {
@ -129,7 +127,6 @@ impl From<MnmlHttpError> for IronError {
MnmlHttpError::PasswordUnacceptable => (m_err.compat(), status::BadRequest), MnmlHttpError::PasswordUnacceptable => (m_err.compat(), status::BadRequest),
MnmlHttpError::PasswordNotMatch | MnmlHttpError::PasswordNotMatch |
MnmlHttpError::InvalidCode |
MnmlHttpError::TokenDoesNotMatch | MnmlHttpError::TokenDoesNotMatch |
MnmlHttpError::Unauthorized => (m_err.compat(), status::Unauthorized), MnmlHttpError::Unauthorized => (m_err.compat(), status::Unauthorized),
@ -211,7 +208,6 @@ fn token_res(token: String) -> Response {
struct RegisterBody { struct RegisterBody {
name: String, name: String,
password: String, password: String,
code: String,
} }
fn register(req: &mut Request) -> IronResult<Response> { fn register(req: &mut Request) -> IronResult<Response> {
@ -224,7 +220,7 @@ fn register(req: &mut Request) -> IronResult<Response> {
let db = state.pool.get().or(Err(MnmlHttpError::DbError))?; let db = state.pool.get().or(Err(MnmlHttpError::DbError))?;
let mut tx = db.transaction().or(Err(MnmlHttpError::DbError))?; let mut tx = db.transaction().or(Err(MnmlHttpError::DbError))?;
match account::create(&params.name, &params.password, &params.code, &mut tx) { match account::create(&params.name, &params.password, &mut tx) {
Ok(token) => { Ok(token) => {
tx.commit().or(Err(MnmlHttpError::ServerError))?; tx.commit().or(Err(MnmlHttpError::ServerError))?;
Ok(token_res(token)) Ok(token_res(token))

View File

@ -1,3 +1,5 @@
use std::fs::File;
use uuid::Uuid; use uuid::Uuid;
use serde_cbor::{from_slice, to_vec}; use serde_cbor::{from_slice, to_vec};
@ -17,7 +19,7 @@ use events::{EventsTx, Event};
use player::{Player, Score, player_create}; use player::{Player, Score, player_create};
use construct::{Construct, construct_get}; use construct::{Construct, construct_get};
use mob::{bot_player, instance_mobs}; use mob::{bot_player, instance_mobs};
use game::{Game, Phase, game_get, game_write}; use game::{Game, Phase, game_get, game_write, game_update};
use item::{Item}; use item::{Item};
use rpc::{RpcMessage}; use rpc::{RpcMessage};
use img; use img;
@ -139,28 +141,30 @@ impl Instance {
.collect::<Vec<Uuid>>() .collect::<Vec<Uuid>>()
} }
pub fn upkeep(mut self) -> (Instance, Vec<Game>) { pub fn upkeep(mut self) -> (Instance, Option<Game>) {
// time out lobbies that have been open too long // time out lobbies that have been open too long
if self.phase == InstancePhase::Lobby && self.phase_timed_out() { if self.phase == InstancePhase::Lobby && self.phase_timed_out() {
self.finish(); self.finish();
return (self, vec![]); return (self, None);
} }
if self.phase != InstancePhase::InProgress { if self.phase != InstancePhase::InProgress {
return (self, vec![]); return (self, None);
} }
if !self.phase_timed_out() { if !self.phase_timed_out() {
return (self, vec![]); return (self, None);
} }
let new_games = self let new_game = self
.timed_out_players() .timed_out_players()
.iter() .iter()
.filter_map(|p| self.player_ready(*p).unwrap()) .filter_map(|p| self.player_ready(*p).unwrap())
.collect::<Vec<Game>>(); .collect::<Vec<Game>>()
.into_iter()
.next();
(self, new_games) (self, new_game)
} }
fn set_name(mut self, name: String) -> Result<Instance, Error> { fn set_name(mut self, name: String) -> Result<Instance, Error> {
@ -312,10 +316,6 @@ impl Instance {
} }
fn finish_condition(&mut self) -> bool { fn finish_condition(&mut self) -> bool {
if self.rounds.len() < 4 {
return false;
}
// tennis // tennis
for player in self.players.iter() { for player in self.players.iter() {
if player.score == Score::Win { if player.score == Score::Win {
@ -323,6 +323,10 @@ impl Instance {
return true; return true;
} }
} }
// Game defaults to lose otherwise
if self.rounds.len() < 4 {
return false;
}
// both players afk // both players afk
if self.players.iter().all(|p| p.score == Score::Zero) { if self.players.iter().all(|p| p.score == Score::Zero) {
@ -454,6 +458,13 @@ impl Instance {
.ok_or(err_msg("account not in instance")) .ok_or(err_msg("account not in instance"))
} }
fn account_opponent(&mut self, account: Uuid) -> Result<&mut Player, Error> {
self.players
.iter_mut()
.find(|p| p.id != account)
.ok_or(err_msg("opponent not in instance"))
}
pub fn vbox_action_allowed(&self, account: Uuid) -> Result<(), Error> { pub fn vbox_action_allowed(&self, account: Uuid) -> Result<(), Error> {
if self.players.iter().find(|p| p.id == account).is_none() { if self.players.iter().find(|p| p.id == account).is_none() {
return Err(err_msg("player not in this instance")); return Err(err_msg("player not in this instance"));
@ -545,15 +556,26 @@ pub fn instance_update(tx: &mut Transaction, instance: Instance) -> Result<Insta
result.iter().next().ok_or(err_msg("no instance row returned"))?; result.iter().next().ok_or(err_msg("no instance row returned"))?;
// info!("{:?} wrote instance", instance.id); trace!("{:?} wrote instance", instance.id);
if instance.finished() { if instance.finished() {
info!("instance finished state={:?}", instance); info!("finished id={:?}", instance.id);
match instance_json_file_write(&instance) {
Ok(dest) => info!("wrote dest={:?}", dest),
Err(e) => error!("json write error={:?}", e),
};
} }
return Ok(instance); return Ok(instance);
} }
fn instance_json_file_write(g: &Instance) -> Result<String, Error> {
let dest = format!("/var/lib/mnml/data/instances/{}.mnml.instance.json", g.id);
serde_json::to_writer(File::create(&dest)?, g)?;
Ok(dest)
}
pub fn instance_get(tx: &mut Transaction, instance_id: Uuid) -> Result<Instance, Error> { pub fn instance_get(tx: &mut Transaction, instance_id: Uuid) -> Result<Instance, Error> {
let query = " let query = "
SELECT * SELECT *
@ -724,6 +746,22 @@ pub fn pvp(tx: &mut Transaction, a: &Account, b: &Account) -> Result<Instance, E
instance_update(tx, instance) instance_update(tx, instance)
} }
pub fn instance_abandon(tx: &mut Transaction, account: &Account, instance_id: Uuid) -> Result<RpcMessage, Error> {
let mut instance = instance_get(tx, instance_id)?;
if let Some(game_id) = instance.current_game_id() {
let mut game = game_get(tx, game_id)?;
game.player_by_id(account.id)?.forfeit();
game = game.start(); // actually finishes it...
game_update(tx, &game)?;
}
instance.account_player(account.id)?.set_lose();
instance.account_opponent(account.id)?.set_win();
instance.next_round();
Ok(RpcMessage::InstanceState(instance_update(tx, instance)?))
}
pub fn instance_ready(tx: &mut Transaction, account: &Account, instance_id: Uuid) -> Result<RpcMessage, Error> { pub fn instance_ready(tx: &mut Transaction, account: &Account, instance_id: Uuid) -> Result<RpcMessage, Error> {
let mut instance = instance_get(tx, instance_id)?; let mut instance = instance_get(tx, instance_id)?;
@ -731,6 +769,10 @@ pub fn instance_ready(tx: &mut Transaction, account: &Account, instance_id: Uuid
if let Some(game) = instance.player_ready(player_id)? { if let Some(game) = instance.player_ready(player_id)? {
game_write(tx, &game)?; game_write(tx, &game)?;
// ensures cleanup for warden etc is done
game_update(tx, &game)?;
instance_update(tx, instance)?; instance_update(tx, instance)?;
return Ok(RpcMessage::GameState(game)); return Ok(RpcMessage::GameState(game));
} }
@ -763,6 +805,43 @@ pub fn instance_game_finished(tx: &mut Transaction, game: &Game, instance_id: Uu
Ok(()) Ok(())
} }
pub fn bot_instance() -> Instance {
let mut instance = Instance::new();
let bot_player = bot_player();
let bot = bot_player.id;
instance.add_player(bot_player).unwrap();
let player_account = Uuid::new_v4();
let constructs = instance_mobs(player_account);
let player = Player::new(player_account, &"test".to_string(), constructs).set_bot(true);
instance.add_player(player).expect("could not add player");
instance.player_ready(player_account).unwrap();
instance.player_ready(bot).unwrap();
return instance;
}
pub fn demo() -> Result<Vec<Player>, Error> {
let bot = bot_player();
// generate bot imgs for the client to see
for c in bot.constructs.iter() {
img::molecular_write(c.img)?;
};
let bot2 = bot_player();
// generate bot imgs for the client to see
for c in bot2.constructs.iter() {
img::molecular_write(c.img)?;
};
Ok(vec![bot, bot2])
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -862,12 +941,12 @@ mod tests {
let (mut instance, new_games) = instance.upkeep(); let (mut instance, new_games) = instance.upkeep();
assert_eq!(new_games.len(), 1); assert!(new_games.is_some());
let game = &new_games[0]; let game = new_games.unwrap();
assert!(game.finished()); assert!(game.finished());
instance.game_finished(game).unwrap(); instance.game_finished(&game).unwrap();
assert_eq!(instance.rounds.len(), 2); assert_eq!(instance.rounds.len(), 2);
assert!(instance.players.iter().all(|p| !p.ready)); assert!(instance.players.iter().all(|p| !p.ready));

160
server/src/lib.rs Normal file
View File

@ -0,0 +1,160 @@
extern crate rand;
extern crate uuid;
extern crate bcrypt;
extern crate chrono;
extern crate dotenv;
extern crate postgres;
extern crate r2d2;
extern crate r2d2_postgres;
extern crate fallible_iterator;
extern crate serde;
extern crate serde_cbor;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate failure;
extern crate fern;
#[macro_use] extern crate log;
extern crate stripe;
extern crate iron;
extern crate bodyparser;
extern crate urlencoded;
extern crate persistent;
extern crate router;
extern crate mount;
extern crate cookie;
extern crate lettre;
extern crate lettre_email;
extern crate ws;
extern crate crossbeam_channel;
mod account;
mod acp;
mod construct;
mod effect;
mod game;
mod instance;
mod item;
mod img;
mod mail;
mod mob;
mod mtx;
mod names;
mod http;
mod payments;
mod pg;
mod player;
mod events;
pub mod rpc;
mod skill;
mod spec;
mod util;
mod vbox;
mod warden;
use std::thread::{spawn};
use std::path::{Path};
use fern::colors::{Color, ColoredLevelConfig};
use crossbeam_channel::{unbounded};
#[derive(Serialize)]
struct JsonLog {
time: String,
module: String,
level: String,
msg: String,
}
pub fn setup_logger() -> Result<(), fern::InitError> {
let colors_line = ColoredLevelConfig::new()
.error(Color::Red)
.warn(Color::Yellow)
.info(Color::BrightWhite)
.debug(Color::BrightWhite)
.trace(Color::BrightBlack);
let colors_level = colors_line.clone().info(Color::Green);
let term = fern::Dispatch::new()
.format(move |out, message, record| {
out.finish(format_args!(
"{color_line}{date} {target} {level}{color_line} {message}\x1B[0m",
color_line = format_args!("\x1B[{}m", colors_line.get_color(&record.level()).to_fg_str()),
date = chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
target = record.target(),
level = colors_level.color(record.level()),
message = message,
));
})
.chain(std::io::stdout());
let json = fern::Dispatch::new()
.format(|out, message, record| {
let json = JsonLog {
time: chrono::Local::now().to_rfc3339(),
module: record.target().to_string(),
level: record.level().to_string(),
msg: message.to_string()
};
out.finish(format_args!(
"{}",
serde_json::to_string(&json).unwrap(),
))
})
.chain(fern::log_file("/var/log/mnml/mnml.log")?);
fern::Dispatch::new()
.level_for("postgres", log::LevelFilter::Info)
.level_for("ws", log::LevelFilter::Warn)
.level_for("iron", log::LevelFilter::Info)
.level(log::LevelFilter::Info)
.chain(term)
.chain(json)
.apply()?;
Ok(())
}
pub fn start() {
setup_logger().unwrap();
dotenv::from_path(Path::new("/etc/mnml/gs.conf")).ok();
let pool = pg::create_pool();
let http_pool = pool.clone();
let (events_tx, events_rx) = unbounded();
let pg_events_tx = events_tx.clone();
let rpc_events_tx = events_tx.clone();
let (warden_tx, warden_rx) = unbounded();
let events_warden_tx = warden_tx.clone();
let warden_tick_tx = warden_tx.clone();
let (mail_tx, mail_rx) = unbounded();
let http_mail_tx = mail_tx.clone();
// create a clone of the tx so ws handler can tell events
// about connection status
let events = events::Events::new(events_tx, events_rx, events_warden_tx, mail_tx);
let warden = warden::Warden::new(warden_tx, warden_rx, events.tx.clone(), pool.clone());
let pg_pool = pool.clone();
let mailer = mail::listen(mail_rx);
let stripe = payments::stripe_client();
spawn(move || http::start(http_pool, mailer));
spawn(move || warden.listen());
spawn(move || warden::upkeep_tick(warden_tick_tx));
spawn(move || pg::listen(pg_pool, pg_events_tx));
spawn(move || events.listen());
// the main thread becomes this ws listener
let rpc_pool = pool.clone();
rpc::start(rpc_pool, rpc_events_tx, stripe);
}

View File

@ -1,160 +1,7 @@
extern crate rand; extern crate mnml;
extern crate uuid;
extern crate bcrypt;
extern crate chrono;
extern crate dotenv; use mnml::start;
extern crate postgres;
extern crate r2d2;
extern crate r2d2_postgres;
extern crate fallible_iterator;
extern crate serde;
extern crate serde_cbor;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate failure;
extern crate fern;
#[macro_use] extern crate log;
extern crate stripe;
extern crate iron;
extern crate bodyparser;
extern crate urlencoded;
extern crate persistent;
extern crate router;
extern crate mount;
extern crate cookie;
extern crate lettre;
extern crate lettre_email;
extern crate ws;
extern crate crossbeam_channel;
mod account;
mod acp;
mod construct;
mod effect;
mod game;
mod instance;
mod item;
mod img;
mod mail;
mod mob;
mod mtx;
mod names;
mod http;
mod payments;
mod pg;
mod player;
mod events;
mod rpc;
mod skill;
mod spec;
mod util;
mod vbox;
mod warden;
use std::thread::{spawn};
use std::path::{Path};
use fern::colors::{Color, ColoredLevelConfig};
use crossbeam_channel::{unbounded};
#[derive(Serialize)]
struct JsonLog {
time: String,
module: String,
level: String,
msg: String,
}
fn setup_logger() -> Result<(), fern::InitError> {
let colors_line = ColoredLevelConfig::new()
.error(Color::Red)
.warn(Color::Yellow)
.info(Color::BrightWhite)
.debug(Color::BrightWhite)
.trace(Color::BrightBlack);
let colors_level = colors_line.clone().info(Color::Green);
let term = fern::Dispatch::new()
.format(move |out, message, record| {
out.finish(format_args!(
"{color_line}{date} {target} {level}{color_line} {message}\x1B[0m",
color_line = format_args!("\x1B[{}m", colors_line.get_color(&record.level()).to_fg_str()),
date = chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
target = record.target(),
level = colors_level.color(record.level()),
message = message,
));
})
.chain(std::io::stdout());
let json = fern::Dispatch::new()
.format(|out, message, record| {
let json = JsonLog {
time: chrono::Local::now().to_rfc3339(),
module: record.target().to_string(),
level: record.level().to_string(),
msg: message.to_string()
};
out.finish(format_args!(
"{}",
serde_json::to_string(&json).unwrap(),
))
})
.chain(fern::log_file("/var/log/mnml/mnml.log")?);
fern::Dispatch::new()
.level_for("postgres", log::LevelFilter::Info)
.level_for("ws", log::LevelFilter::Warn)
.level_for("iron", log::LevelFilter::Info)
.level(log::LevelFilter::Info)
.chain(term)
.chain(json)
.apply()?;
Ok(())
}
fn main() { fn main() {
setup_logger().unwrap(); start()
dotenv::from_path(Path::new("/etc/mnml/gs.conf")).ok();
let pool = pg::create_pool();
let http_pool = pool.clone();
let (events_tx, events_rx) = unbounded();
let pg_events_tx = events_tx.clone();
let rpc_events_tx = events_tx.clone();
let (warden_tx, warden_rx) = unbounded();
let events_warden_tx = warden_tx.clone();
let warden_tick_tx = warden_tx.clone();
let (mail_tx, mail_rx) = unbounded();
let http_mail_tx = mail_tx.clone();
// create a clone of the tx so ws handler can tell events
// about connection status
let events = events::Events::new(events_tx, events_rx, events_warden_tx, mail_tx);
let warden = warden::Warden::new(warden_tx, warden_rx, events.tx.clone(), pool.clone());
let pg_pool = pool.clone();
let mailer = mail::listen(mail_rx);
let stripe = payments::stripe_client();
spawn(move || http::start(http_pool, mailer));
spawn(move || warden.listen());
spawn(move || warden::upkeep_tick(warden_tick_tx));
spawn(move || pg::listen(pg_pool, pg_events_tx));
spawn(move || events.listen());
// the main thread becomes this ws listener
let rpc_pool = pool.clone();
rpc::start(rpc_pool, rpc_events_tx, stripe);
} }

View File

@ -27,3 +27,4 @@ pub fn bot_player() -> Player {
let constructs = instance_mobs(bot_id); let constructs = instance_mobs(bot_id);
Player::new(bot_id, &name(), constructs).set_bot(true) Player::new(bot_id, &name(), constructs).set_bot(true)
} }

View File

@ -99,6 +99,16 @@ impl Player {
self self
} }
pub fn set_win(&mut self) -> &mut Player {
self.score = Score::Win;
self
}
pub fn set_lose(&mut self) -> &mut Player {
self.score = Score::Lose;
self
}
pub fn construct_get(&mut self, id: Uuid) -> Result<&mut Construct, Error> { pub fn construct_get(&mut self, id: Uuid) -> Result<&mut Construct, Error> {
self.constructs.iter_mut().find(|c| c.id == id).ok_or(err_msg("construct not found")) self.constructs.iter_mut().find(|c| c.id == id).ok_or(err_msg("construct not found"))
} }

View File

@ -14,17 +14,19 @@ use cookie::Cookie;
use stripe::{Client as StripeClient, Subscription}; use stripe::{Client as StripeClient, Subscription};
use crossbeam_channel::{unbounded, Sender as CbSender}; use crossbeam_channel::{unbounded, Sender as CbSender};
use ws::{listen, CloseCode, Message, Handler, Request, Response}; use ws::{Builder, listen, CloseCode, Message, Handler, Request, Response, Settings, Sender as WsSender};
use account::{Account}; use account::{Account};
use account; use account;
use construct::{Construct}; use construct::{Construct};
use events::{Event}; use events::{Event};
use game::{Game, game_state, game_skill, game_ready}; use game::{Game, game_state, game_skill, game_skill_clear, game_ready};
use instance::{Instance, instance_state, instance_practice, instance_ready}; use instance::{Instance, instance_state, instance_practice, instance_ready, instance_abandon, demo};
use item::{Item, ItemInfoCtr, item_info}; use item::{Item, ItemInfoCtr, item_info};
use mtx; use mtx;
use mail; use mail;
use player::{Player};
use payments; use payments;
use mail::Email; use mail::Email;
use pg::{Db}; use pg::{Db};
@ -41,6 +43,8 @@ pub enum RpcMessage {
AccountInstances(Vec<Instance>), AccountInstances(Vec<Instance>),
AccountShop(mtx::Shop), AccountShop(mtx::Shop),
Demo(Vec<Player>),
ConstructSpawn(Construct), ConstructSpawn(Construct),
GameState(Game), GameState(Game),
ItemInfo(ItemInfoCtr), ItemInfo(ItemInfoCtr),
@ -62,7 +66,7 @@ pub enum RpcMessage {
} }
#[derive(Debug,Clone,Serialize,Deserialize)] #[derive(Debug,Clone,Serialize,Deserialize)]
enum RpcRequest { pub enum RpcRequest {
Ping {}, Ping {},
ItemInfo {}, ItemInfo {},
DevResolve { a: Uuid, b: Uuid, skill: Skill }, DevResolve { a: Uuid, b: Uuid, skill: Skill },
@ -75,9 +79,11 @@ enum RpcRequest {
GameState { id: Uuid }, GameState { id: Uuid },
GameReady { id: Uuid }, GameReady { id: Uuid },
GameSkill { game_id: Uuid, construct_id: Uuid, target_construct_id: Option<Uuid>, skill: Skill }, GameSkill { game_id: Uuid, construct_id: Uuid, target_construct_id: Option<Uuid>, skill: Skill },
GameSkillClear { game_id: Uuid },
AccountState {}, AccountState {},
AccountShop {}, AccountShop {},
AccountInstances {},
AccountConstructs {}, AccountConstructs {},
AccountSetTeam { ids: Vec<Uuid> }, AccountSetTeam { ids: Vec<Uuid> },
@ -87,6 +93,7 @@ enum RpcRequest {
InstanceQueue {}, InstanceQueue {},
InstancePractice {}, InstancePractice {},
InstanceAbandon { instance_id: Uuid },
InstanceReady { instance_id: Uuid }, InstanceReady { instance_id: Uuid },
InstanceState { instance_id: Uuid }, InstanceState { instance_id: Uuid },
@ -148,7 +155,8 @@ impl Connection {
Ok(RpcMessage::AccountState(account.clone())), Ok(RpcMessage::AccountState(account.clone())),
RpcRequest::AccountConstructs {} => RpcRequest::AccountConstructs {} =>
Ok(RpcMessage::AccountConstructs(account::constructs(&mut tx, &account)?)), Ok(RpcMessage::AccountConstructs(account::constructs(&mut tx, &account)?)),
RpcRequest::AccountInstances {} =>
Ok(RpcMessage::AccountInstances(account::account_instances(&mut tx, account)?)),
RpcRequest::AccountSetTeam { ids } => RpcRequest::AccountSetTeam { ids } =>
Ok(RpcMessage::AccountTeam(account::set_team(&mut tx, &account, ids)?)), Ok(RpcMessage::AccountTeam(account::set_team(&mut tx, &account, ids)?)),
@ -169,6 +177,9 @@ impl Connection {
RpcRequest::GameSkill { game_id, construct_id, target_construct_id, skill } => RpcRequest::GameSkill { game_id, construct_id, target_construct_id, skill } =>
Ok(RpcMessage::GameState(game_skill(&mut tx, account, game_id, construct_id, target_construct_id, skill)?)), Ok(RpcMessage::GameState(game_skill(&mut tx, account, game_id, construct_id, target_construct_id, skill)?)),
RpcRequest::GameSkillClear { game_id } =>
Ok(RpcMessage::GameState(game_skill_clear(&mut tx, account, game_id)?)),
RpcRequest::GameReady { id } => RpcRequest::GameReady { id } =>
Ok(RpcMessage::GameState(game_ready(&mut tx, account, id)?)), Ok(RpcMessage::GameState(game_ready(&mut tx, account, id)?)),
@ -180,6 +191,8 @@ impl Connection {
Ok(instance_ready(&mut tx, account, instance_id)?), Ok(instance_ready(&mut tx, account, instance_id)?),
RpcRequest::InstanceState { instance_id } => RpcRequest::InstanceState { instance_id } =>
Ok(instance_state(&mut tx, instance_id)?), Ok(instance_state(&mut tx, instance_id)?),
RpcRequest::InstanceAbandon { instance_id } =>
Ok(instance_abandon(&mut tx, account, instance_id)?),
RpcRequest::VboxAccept { instance_id, group, index } => RpcRequest::VboxAccept { instance_id, group, index } =>
Ok(RpcMessage::InstanceState(vbox_accept(&mut tx, account, instance_id, group, index)?)), Ok(RpcMessage::InstanceState(vbox_accept(&mut tx, account, instance_id, group, index)?)),
@ -264,6 +277,8 @@ impl Handler for Connection {
// tx should do nothing // tx should do nothing
tx.commit().unwrap(); tx.commit().unwrap();
} else {
self.ws.send(RpcMessage::Demo(demo().unwrap())).unwrap();
} }
Ok(()) Ok(())
@ -346,8 +361,12 @@ impl Handler for Connection {
pub fn start(pool: PgPool, events_tx: CbSender<Event>, stripe: StripeClient) { pub fn start(pool: PgPool, events_tx: CbSender<Event>, stripe: StripeClient) {
let mut rng = thread_rng(); let mut rng = thread_rng();
listen("127.0.0.1:40055", move |out| { Builder::new()
.with_settings(Settings {
max_connections: 10_000,
..Settings::default()
})
.build(move |out: WsSender| {
// we give the tx half to the connection object // we give the tx half to the connection object
// which in turn passes a clone to the events system // which in turn passes a clone to the events system
// the rx half goes into a thread where it waits for messages // the rx half goes into a thread where it waits for messages
@ -379,6 +398,9 @@ pub fn start(pool: PgPool, events_tx: CbSender<Event>, stripe: StripeClient) {
stripe: stripe.clone(), stripe: stripe.clone(),
events: events_tx.clone(), events: events_tx.clone(),
} }
}).unwrap(); })
.unwrap()
.listen("127.0.0.1:40055")
.unwrap();
} }

View File

@ -131,11 +131,16 @@ fn fetch_games(mut tx: Transaction) -> Result<Transaction, Error> {
fn fetch_instances(mut tx: Transaction) -> Result<Transaction, Error> { fn fetch_instances(mut tx: Transaction) -> Result<Transaction, Error> {
for mut instance in instances_need_upkeep(&mut tx)? { for mut instance in instances_need_upkeep(&mut tx)? {
let (instance, new_games) = instance.upkeep(); let (instance, new_game) = instance.upkeep();
for game in new_games {
if let Some(game) = new_game {
game_write(&mut tx, &game)?; game_write(&mut tx, &game)?;
}
instance_update(&mut tx, instance)?; instance_update(&mut tx, instance)?;
// ensures cleanup for forfeits etc is done
game_update(&mut tx, &game)?;
} else {
instance_update(&mut tx, instance)?;
}
} }
for mut instance in instances_idle(&mut tx)? { for mut instance in instances_idle(&mut tx)? {