Merge branch 'release/1.3.0'
This commit is contained in:
commit
1b95e171a8
@ -10,9 +10,9 @@
|
|||||||
* treats
|
* treats
|
||||||
* constructs jiggle when clicked
|
* constructs jiggle when clicked
|
||||||
* background colour changes depending on time of day
|
* background colour changes depending on time of day
|
||||||
|
* hit animation wobble
|
||||||
* bug fixes
|
* combat text scale + translate
|
||||||
* pvp 1st round doesn't resolve until warden timer completes
|
* susbcriber gold name in instance
|
||||||
|
|
||||||
* bot game grind
|
* bot game grind
|
||||||
* stress test
|
* stress test
|
||||||
@ -22,11 +22,8 @@
|
|||||||
* make our own toasts / msg pane
|
* make our own toasts / msg pane
|
||||||
* send account_instances on players update
|
* send account_instances on players update
|
||||||
|
|
||||||
* convert PlusPlus to ++ or rename
|
|
||||||
* add speed to descriptions
|
* add speed to descriptions
|
||||||
* add components to description e.g. Strike (red circle red circle attack)
|
|
||||||
* clear skill (if currently targetted)
|
* clear skill (if currently targetted)
|
||||||
* increase power to speed up early rounds
|
|
||||||
|
|
||||||
* only login / logout / register http
|
* only login / logout / register http
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-client",
|
"name": "mnml-client",
|
||||||
"version": "1.2.0",
|
"version": "1.3.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -6,7 +6,6 @@ MNML_PATH=$(realpath "$DIR/../")
|
|||||||
VERSION=$(<"$MNML_PATH/VERSION")
|
VERSION=$(<"$MNML_PATH/VERSION")
|
||||||
|
|
||||||
SERVER_BIN_DIR="/usr/local/mnml/bin"
|
SERVER_BIN_DIR="/usr/local/mnml/bin"
|
||||||
|
|
||||||
CLIENT_DIST_DIR="/var/lib/mnml/client"
|
CLIENT_DIST_DIR="/var/lib/mnml/client"
|
||||||
CLIENT_PUBLIC_DIR="/var/lib/mnml/public/current"
|
CLIENT_PUBLIC_DIR="/var/lib/mnml/public/current"
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
@import 'colours.less';
|
@import 'colours.less';
|
||||||
|
|
||||||
.account {
|
.account {
|
||||||
margin-top: 2em;
|
|
||||||
grid-area: bottom;
|
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||||
grid-gap: 0 1em;
|
grid-gap: 0 1em;
|
||||||
|
|||||||
@ -8,10 +8,17 @@ aside {
|
|||||||
"timer controls";
|
"timer controls";
|
||||||
|
|
||||||
grid-template-columns: min-content 1fr;
|
grid-template-columns: min-content 1fr;
|
||||||
grid-template-rows: 1fr 1fr 1fr;
|
grid-template-rows: 1fr;
|
||||||
grid-gap: 0.5em 0;
|
|
||||||
|
|
||||||
padding: 1em 1em 1em 0;
|
padding-left: 1em;
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
grid-area: controls;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-auto-rows: 1fr;
|
||||||
|
grid-gap: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
// fix chrome being inconsistent
|
// fix chrome being inconsistent
|
||||||
table {
|
table {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
@import 'colours.less';
|
@import 'colours.less';
|
||||||
|
|
||||||
.instance {
|
.instance {
|
||||||
overflow-x: hidden;
|
overflow: hidden;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 2fr minmax(min-content, 1fr);
|
grid-template-columns: 1fr minmax(min-content, 1fr);
|
||||||
grid-template-rows: min-content 1fr;
|
grid-template-rows: min-content 1fr;
|
||||||
|
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
@ -63,10 +63,16 @@
|
|||||||
.instance .info figure {
|
.instance .info figure {
|
||||||
display: inline;
|
display: inline;
|
||||||
height: 0.5em;
|
height: 0.5em;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.instance .info figcaption {
|
.instance .info figcaption {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,16 +4,16 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|
||||||
grid-template-rows: minmax(min-content, 2fr) 1fr;
|
grid-template-rows: min-content 1fr 2fr;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
|
"hdr"
|
||||||
"top"
|
"top"
|
||||||
"bottom";
|
"bottom";
|
||||||
|
|
||||||
.top {
|
.top {
|
||||||
grid-area: top;
|
grid-area: top;
|
||||||
padding: 0 0 0.5em 2em;
|
|
||||||
border-bottom: 0.1em solid #222;
|
border-bottom: 0.1em solid #222;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@ -24,9 +24,10 @@
|
|||||||
|
|
||||||
.team {
|
.team {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-area: top;
|
grid-area: bottom;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(min-content, 33%));
|
grid-template-columns: repeat(auto-fill, minmax(min-content, 33%));
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
|
margin-top: 1em;
|
||||||
|
|
||||||
.team-select:not(:nth-child(3n)) {
|
.team-select:not(:nth-child(3n)) {
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
@ -61,9 +62,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.inventory {
|
.inventory {
|
||||||
margin-top: 2em;
|
|
||||||
grid-area: bottom;
|
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
|
|
||||||
@ -71,6 +69,10 @@
|
|||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.news {
|
||||||
|
padding-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.list {
|
.list {
|
||||||
letter-spacing: 0.25em;
|
letter-spacing: 0.25em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
@ -87,4 +89,21 @@
|
|||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
grid-area: hdr;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 25%;
|
||||||
|
border-top: 0;
|
||||||
|
border: 1px solid #222;
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,6 +67,7 @@ hr {
|
|||||||
color: #222;
|
color: #222;
|
||||||
margin: 1.5em 0;
|
margin: 1.5em 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
border-top: 1px solid #222;
|
||||||
}
|
}
|
||||||
|
|
||||||
figure {
|
figure {
|
||||||
@ -84,16 +85,17 @@ dl {
|
|||||||
|
|
||||||
#mnml {
|
#mnml {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(min-content, 1fr) 8fr 1fr;
|
grid-template-columns: 9fr 1fr;
|
||||||
grid-template-rows: min-content 1fr min-content;
|
grid-template-rows: min-content min-content 1fr;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"hd hd ctrl"
|
"hdr ctrl"
|
||||||
"nav main ctrl"
|
"main ctrl"
|
||||||
"nav main ctrl";
|
"main ctrl";
|
||||||
|
|
||||||
|
padding: 0.5em 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
padding: 1em;
|
|
||||||
grid-area: main;
|
grid-area: main;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,12 +200,6 @@ button[disabled] {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.welcome {
|
.welcome {
|
||||||
.highlight {
|
|
||||||
color: black;
|
|
||||||
background: @white;
|
|
||||||
border: 1px solid @white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login {
|
.login {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -212,12 +208,8 @@ button[disabled] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.options {
|
.options {
|
||||||
width: 50%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row;
|
width: 50%;
|
||||||
button {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
@ -263,3 +255,47 @@ figure.gray {
|
|||||||
.mobile-title {
|
.mobile-title {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
.options {
|
||||||
|
font-size: 150%;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
button {
|
||||||
|
&.highlight {
|
||||||
|
color: @white;
|
||||||
|
box-shadow: inset 0px 5px 0px 0px @white;
|
||||||
|
border: 0;
|
||||||
|
&:first-child {
|
||||||
|
border-left: 1px solid #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-right: 1px solid #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
border: 1px solid #444;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
list-style: inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-client",
|
"name": "mnml-client",
|
||||||
"version": "1.2.0",
|
"version": "1.3.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
const { removeTier } = require('./utils');
|
|
||||||
const { TIMES } = require('./constants');
|
const { TIMES } = require('./constants');
|
||||||
|
|
||||||
function none() {
|
function none() {
|
||||||
@ -60,10 +59,8 @@ function getObjects(resolution, stages, game, account) {
|
|||||||
? null
|
? null
|
||||||
: createSourceAnim();
|
: createSourceAnim();
|
||||||
|
|
||||||
const skill = removeTier(event.skill);
|
|
||||||
|
|
||||||
const animTarget = {
|
const animTarget = {
|
||||||
skill,
|
skill: event.skill,
|
||||||
constructId: targetting(),
|
constructId: targetting(),
|
||||||
player: playerTeamIds.includes(resolution.target.id),
|
player: playerTeamIds.includes(resolution.target.id),
|
||||||
direction,
|
direction,
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
const { connect } = require('preact-redux');
|
|
||||||
const preact = require('preact');
|
|
||||||
|
|
||||||
const Team = require('./team');
|
|
||||||
const AccountManagement = require('./account.management');
|
|
||||||
|
|
||||||
const addState = connect(
|
|
||||||
function receiveState(state) {
|
|
||||||
const {
|
|
||||||
ws,
|
|
||||||
account,
|
|
||||||
} = state;
|
|
||||||
|
|
||||||
return {
|
|
||||||
account,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
function Account(args) {
|
|
||||||
const {
|
|
||||||
account,
|
|
||||||
} = args;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<main class="menu">
|
|
||||||
<Team />
|
|
||||||
<AccountManagement />
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = addState(Account);
|
|
||||||
@ -151,19 +151,9 @@ class AccountStatus extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section class='account' onClick={tlClick}>
|
<section class='account top' onClick={tlClick}>
|
||||||
<div>
|
<div>
|
||||||
<h1>{account.name}</h1>
|
{subInfo()}
|
||||||
<div class="list">
|
|
||||||
<figure>
|
|
||||||
<figcaption>spawn new construct</figcaption>
|
|
||||||
<button onClick={() => sendConstructSpawn()} type="submit">
|
|
||||||
¤50
|
|
||||||
</button>
|
|
||||||
</figure>
|
|
||||||
</div>
|
|
||||||
<button onClick={() => logout()}>Logout</button>
|
|
||||||
<button><a href={`mailto:humans@mnml.gg?subject=Account%20Support:%20${account.name}`}>✉ support</a></button>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="email">Email Settings:</label>
|
<label for="email">Email Settings:</label>
|
||||||
@ -216,7 +206,16 @@ class AccountStatus extends Component {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{subInfo()}
|
<div class="list">
|
||||||
|
<figure>
|
||||||
|
<figcaption>spawn new construct</figcaption>
|
||||||
|
<button onClick={() => sendConstructSpawn()} type="submit">
|
||||||
|
¤50
|
||||||
|
</button>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
<button onClick={() => logout()}>Logout</button>
|
||||||
|
<button><a href={`mailto:humans@mnml.gg?subject=Account%20Support:%20${account.name}`}>✉ support</a></button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
@ -40,6 +40,8 @@ const Triage = require('./anims/triage');
|
|||||||
const TriageTick = require('./anims/triage.tick');
|
const TriageTick = require('./anims/triage.tick');
|
||||||
|
|
||||||
const actions = require('../actions');
|
const actions = require('../actions');
|
||||||
|
const { removeTier } = require('../utils');
|
||||||
|
|
||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
@ -63,12 +65,12 @@ class ConstructAnimation extends Component {
|
|||||||
direction,
|
direction,
|
||||||
constructId,
|
constructId,
|
||||||
} = animTarget;
|
} = animTarget;
|
||||||
|
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 = (skill) => {
|
const chooseAnim = (animSkill) => {
|
||||||
switch (skill) {
|
switch (animSkill) {
|
||||||
// Attack base
|
// Attack base
|
||||||
case 'Attack': return <Attack direction={direction}/>;
|
case 'Attack': return <Attack direction={direction}/>;
|
||||||
case 'Blast': return <Blast direction={direction}/>;
|
case 'Blast': return <Blast direction={direction}/>;
|
||||||
@ -123,7 +125,7 @@ class ConstructAnimation extends Component {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const anim = chooseAnim(skill);
|
const anim = chooseAnim(animSkill);
|
||||||
if (!anim) return false;
|
if (!anim) return false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
89
client/src/components/collection.jsx
Normal file
89
client/src/components/collection.jsx
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
const preact = require('preact');
|
||||||
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
|
const actions = require('./../actions');
|
||||||
|
const { COLOURS } = require('./../utils');
|
||||||
|
const { ConstructAvatar } = require('./construct');
|
||||||
|
|
||||||
|
const addState = connect(
|
||||||
|
function receiveState(state) {
|
||||||
|
const { ws, constructs, teamPage, teamSelect } = state;
|
||||||
|
|
||||||
|
function sendConstructSpawn(name) {
|
||||||
|
return ws.sendMtxConstructSpawn(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
constructs,
|
||||||
|
teamPage,
|
||||||
|
teamSelect,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
function receiveDispatch(dispatch) {
|
||||||
|
function setTeam(constructIds) {
|
||||||
|
dispatch(actions.setTeamSelect(constructIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setTeam,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function Collection(args) {
|
||||||
|
const {
|
||||||
|
constructs,
|
||||||
|
teamPage,
|
||||||
|
teamSelect,
|
||||||
|
setTeam,
|
||||||
|
} = args;
|
||||||
|
|
||||||
|
if (!constructs) return <div></div>;
|
||||||
|
|
||||||
|
// redux limitation + suggested workaround
|
||||||
|
// so much for dumb components
|
||||||
|
function selectConstruct(id) {
|
||||||
|
// remove
|
||||||
|
const i = teamSelect.findIndex(sid => sid === id);
|
||||||
|
if (i > -1) {
|
||||||
|
teamSelect[i] = null;
|
||||||
|
return setTeam(teamSelect);
|
||||||
|
}
|
||||||
|
|
||||||
|
// window insert
|
||||||
|
const insert = teamSelect.findIndex(j => j === null);
|
||||||
|
if (insert === -1) return setTeam([id, null, null]);
|
||||||
|
teamSelect[insert] = id;
|
||||||
|
return setTeam(teamSelect);
|
||||||
|
}
|
||||||
|
console.log(constructs.length);
|
||||||
|
const dispConstructs = constructs.length >= ((teamPage + 1) * 6)
|
||||||
|
? constructs.slice(teamPage * 6, (teamPage + 1) * 6)
|
||||||
|
: constructs.slice(teamPage * 6, constructs.length);
|
||||||
|
|
||||||
|
const constructPanels = dispConstructs.map(construct => {
|
||||||
|
const colour = teamSelect.indexOf(construct.id);
|
||||||
|
const selected = colour > -1;
|
||||||
|
|
||||||
|
const borderColour = selected ? COLOURS[colour] : '#000000';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={construct.id}
|
||||||
|
class="construct team-select"
|
||||||
|
style={ { 'border-color': borderColour || 'whitesmoke' } }
|
||||||
|
onClick={() => selectConstruct(construct.id)} >
|
||||||
|
<ConstructAvatar construct={construct} />
|
||||||
|
<h2>{construct.name}</h2>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section class="team">
|
||||||
|
{constructPanels}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = addState(Collection);
|
||||||
@ -125,9 +125,11 @@ function Controls(args) {
|
|||||||
return (
|
return (
|
||||||
<aside class="controls">
|
<aside class="controls">
|
||||||
{timer}
|
{timer}
|
||||||
|
<div class="controls">
|
||||||
{scoreboard(game, opponent, true)}
|
{scoreboard(game, opponent, true)}
|
||||||
{game.phase === 'Finish' ? quitBtn : readyBtn}
|
{game.phase === 'Finish' ? quitBtn : readyBtn}
|
||||||
{scoreboard(game, player)}
|
{scoreboard(game, player)}
|
||||||
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,40 +1,96 @@
|
|||||||
// eslint-disable-next-line
|
|
||||||
const preact = require('preact');
|
|
||||||
const { connect } = require('preact-redux');
|
const { connect } = require('preact-redux');
|
||||||
|
const preact = require('preact');
|
||||||
|
|
||||||
const { saw } = require('./shapes');
|
const actions = require('../actions');
|
||||||
const actions = require('./../actions');
|
|
||||||
|
|
||||||
function pingColour(ping) {
|
|
||||||
if (ping < 100) return 'forestgreen';
|
|
||||||
if (ping < 200) return 'yellow';
|
|
||||||
return 'red';
|
|
||||||
}
|
|
||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
({ account, ping, showNav }) => {
|
function receiveState(state) {
|
||||||
return { account, ping };
|
const {
|
||||||
|
ws,
|
||||||
|
account,
|
||||||
|
nav,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
function sendInstanceState(instance) {
|
||||||
|
return ws.sendInstanceState(instance.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendAccountStates() {
|
||||||
|
ws.sendEmailState();
|
||||||
|
ws.sendSubscriptionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
account,
|
||||||
|
nav,
|
||||||
|
|
||||||
|
sendInstanceState,
|
||||||
|
sendAccountStates,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
function receiveDispatch(dispatch) {
|
||||||
|
function setNav(place) {
|
||||||
|
dispatch(actions.setGame(null));
|
||||||
|
dispatch(actions.setInstance(null));
|
||||||
|
dispatch(actions.setCombiner([]));
|
||||||
|
dispatch(actions.setReclaiming(false));
|
||||||
|
dispatch(actions.setActiveSkill(null));
|
||||||
|
dispatch(actions.setActiveConstruct(null));
|
||||||
|
dispatch(actions.setInfo(null));
|
||||||
|
dispatch(actions.setItemEquip(null));
|
||||||
|
dispatch(actions.setItemUnequip([]));
|
||||||
|
dispatch(actions.setVboxHighlight([]));
|
||||||
|
|
||||||
|
return dispatch(actions.setNav(place));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setNav,
|
||||||
|
};
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
function renderHeader(args) {
|
function Header(args) {
|
||||||
const { account, ping } = args;
|
const {
|
||||||
|
account,
|
||||||
|
nav,
|
||||||
|
|
||||||
const accountStatus = account
|
sendAccountStates,
|
||||||
? (<div class="header-status">
|
setNav,
|
||||||
<h1 class="header-username">{account.name}</h1>
|
} = args;
|
||||||
{saw(pingColour(ping))}
|
|
||||||
<div class="ping-text">{ping}ms</div>
|
if (!account) return false;
|
||||||
</div>)
|
|
||||||
: '';
|
function navTo(p) {
|
||||||
|
return setNav(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
function accountClick() {
|
||||||
|
sendAccountStates();
|
||||||
|
navTo('account');
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header>
|
<header>
|
||||||
<h1 class="header-title">mnml.gg</h1>
|
<div class="options">
|
||||||
{accountStatus}
|
<button
|
||||||
|
onClick={() => navTo('play')}
|
||||||
|
class={`login-btn ${nav === 'play' ? 'highlight' : ''}`}>
|
||||||
|
MNML
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => navTo('shop')}
|
||||||
|
class={`login-btn ${nav === 'shop' ? 'highlight' : ''}`}>
|
||||||
|
Shop
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={accountClick}
|
||||||
|
class={`login-btn ${nav === 'account' ? 'highlight' : ''}`}>
|
||||||
|
⚙ {account.name}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = addState(Header);
|
||||||
module.exports = addState(renderHeader);
|
|
||||||
@ -9,7 +9,6 @@ const shapes = require('./shapes');
|
|||||||
function InfoComponent(args) {
|
function InfoComponent(args) {
|
||||||
const {
|
const {
|
||||||
itemInfo,
|
itemInfo,
|
||||||
combiner,
|
|
||||||
player,
|
player,
|
||||||
info,
|
info,
|
||||||
} = args;
|
} = args;
|
||||||
@ -18,7 +17,21 @@ function InfoComponent(args) {
|
|||||||
// const { info } = args;
|
// const { info } = args;
|
||||||
|
|
||||||
function Info() {
|
function Info() {
|
||||||
if (!info) return false;
|
if (!info) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>VBOX phase</h2>
|
||||||
|
<p>double clicking items in the <b>VBOX</b> will purchase and move them to your <b>INVENTORY</b>.</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 3 of the same item to upgrade it.<br />
|
||||||
|
click an item and then click a construct to equip that item to it.<br />
|
||||||
|
</p>
|
||||||
|
<p>click the <b>READY</b> button on the right to progress to the <b>GAME PHASE</b>.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
const fullInfo = itemInfo.items.find(i => i.item === info) || INFO[info];
|
const fullInfo = itemInfo.items.find(i => i.item === info) || INFO[info];
|
||||||
if (!fullInfo) return false;
|
if (!fullInfo) return false;
|
||||||
const isSkill = fullInfo.skill;
|
const isSkill = fullInfo.skill;
|
||||||
@ -28,16 +41,10 @@ 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-skill">
|
<div class="info-skill">
|
||||||
<h2>{fullInfo.item}</h2>
|
<h2>{fullInfo.item}</h2>
|
||||||
<h3>{itemSourceDescription}</h3>
|
<h3>SKILL</h3>
|
||||||
<div>{infoDescription}</div>
|
<div>{infoDescription}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -132,6 +139,7 @@ function InfoComponent(args) {
|
|||||||
return (
|
return (
|
||||||
<div class="info-spec">
|
<div class="info-spec">
|
||||||
<h2>{info}</h2>
|
<h2>{info}</h2>
|
||||||
|
<h3>SPEC</h3>
|
||||||
<div>{infoDescription}</div>
|
<div>{infoDescription}</div>
|
||||||
<div class="thresholds">
|
<div class="thresholds">
|
||||||
{thresholds}
|
{thresholds}
|
||||||
@ -150,30 +158,11 @@ function InfoComponent(args) {
|
|||||||
|
|
||||||
function Combos() {
|
function Combos() {
|
||||||
if (!player) return false;
|
if (!player) return false;
|
||||||
|
|
||||||
// show recipe for what's in combiner
|
|
||||||
if (combiner.some(u => u !== null)) {
|
|
||||||
const filteredCombos = itemInfo.combos
|
|
||||||
.filter(combo => combiner.every(u => u === null
|
|
||||||
|| combo.components.includes(player.vbox.bound[u])));
|
|
||||||
if (filteredCombos.length > 6) return false;
|
|
||||||
return (
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
{filteredCombos.map((c, i) =>
|
|
||||||
<tr key={i} >
|
|
||||||
<td class="highlight" >{convertItem(c.item)}</td>
|
|
||||||
{c.components.map((u, j) => <td key={j}>{convertItem(u)}</td>)}
|
|
||||||
</tr>
|
|
||||||
)}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info) return false;
|
if (!info) return false;
|
||||||
|
|
||||||
const vboxCombos = itemInfo.combos.filter(c => c.components.includes(info));
|
const vboxCombos = itemInfo.combos.filter(c => c.components.includes(info));
|
||||||
if (vboxCombos.length > 6) return false;
|
if (vboxCombos.length > 6) return false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table class="combos">
|
<table class="combos">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
@ -98,7 +98,7 @@ function Construct(props) {
|
|||||||
const skill = construct.skills[i];
|
const skill = construct.skills[i];
|
||||||
const s = skill
|
const s = skill
|
||||||
? skill.skill
|
? skill.skill
|
||||||
: (<span class="gray">+</span>);
|
: (<span class="gray">SKILL</span>);
|
||||||
|
|
||||||
function skillClick(e) {
|
function skillClick(e) {
|
||||||
if (!skill) return false;
|
if (!skill) return false;
|
||||||
|
|||||||
@ -93,11 +93,13 @@ function Controls(args) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside class="controls">
|
<aside>
|
||||||
{timer}
|
{timer}
|
||||||
|
<div class="controls">
|
||||||
{scoreboard(instance, opponent, true)}
|
{scoreboard(instance, opponent, true)}
|
||||||
<button class="ready" onClick={() => sendReady()}>Ready</button>
|
<button class="ready" onClick={() => sendReady()}>Ready</button>
|
||||||
{scoreboard(instance, player)}
|
{scoreboard(instance, player)}
|
||||||
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,87 +0,0 @@
|
|||||||
const { connect } = require('preact-redux');
|
|
||||||
const { Elements } = require('react-stripe-elements');
|
|
||||||
|
|
||||||
const preact = require('preact');
|
|
||||||
const toast = require('izitoast');
|
|
||||||
|
|
||||||
const actions = require('./../actions');
|
|
||||||
const StripeBtns = require('./stripe.buttons');
|
|
||||||
|
|
||||||
const addState = connect(
|
|
||||||
function receiveState(state) {
|
|
||||||
const {
|
|
||||||
ws,
|
|
||||||
account,
|
|
||||||
shop,
|
|
||||||
} = state;
|
|
||||||
|
|
||||||
function mtxBuy(mtx) {
|
|
||||||
return ws.sendMtxBuy(mtx.variant);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
account,
|
|
||||||
shop,
|
|
||||||
mtxBuy,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
function receiveDispatch(dispatch) {
|
|
||||||
function setMtxActive(mtx) {
|
|
||||||
dispatch(actions.setConstructRename(null));
|
|
||||||
dispatch(actions.setMtxActive(mtx));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
setMtxActive,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
function Inventory(args) {
|
|
||||||
const {
|
|
||||||
account,
|
|
||||||
shop,
|
|
||||||
setMtxActive,
|
|
||||||
mtxBuy,
|
|
||||||
} = args;
|
|
||||||
|
|
||||||
if (!shop) return false;
|
|
||||||
|
|
||||||
const useMtx = (item, i) => (
|
|
||||||
<figure key={i} onClick={() => setMtxActive(item)} >
|
|
||||||
<figcaption>{item}</figcaption>
|
|
||||||
<button disabled={account.balance === 0}>¤1</button>
|
|
||||||
</figure>
|
|
||||||
);
|
|
||||||
|
|
||||||
const availableMtx = (item, i) => (
|
|
||||||
<figure key={i} onClick={() => mtxBuy(item)} >
|
|
||||||
<figcaption>{item.variant}</figcaption>
|
|
||||||
<button disabled={account.balance < item.credits}>¤{item.credits}</button>
|
|
||||||
</figure>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class="inventory">
|
|
||||||
<div>
|
|
||||||
<h1>Shop</h1>
|
|
||||||
<Elements>
|
|
||||||
<StripeBtns account={account} />
|
|
||||||
</Elements>
|
|
||||||
<div class='list'>
|
|
||||||
{shop.available.map(availableMtx)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h1 class="credits">¤ {account.balance}</h1>
|
|
||||||
<div class='list'>
|
|
||||||
{shop.owned.map(useMtx)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = addState(Inventory);
|
|
||||||
30
client/src/components/main.bottom.jsx
Normal file
30
client/src/components/main.bottom.jsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
const { connect } = require('preact-redux');
|
||||||
|
const preact = require('preact');
|
||||||
|
|
||||||
|
const actions = require('./../actions');
|
||||||
|
|
||||||
|
const Team = require('./team');
|
||||||
|
const Collection = require('./collection');
|
||||||
|
|
||||||
|
const addState = connect(
|
||||||
|
function receiveState(state) {
|
||||||
|
const {
|
||||||
|
nav,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
return {
|
||||||
|
nav,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
function Bottom(args) {
|
||||||
|
const {
|
||||||
|
nav,
|
||||||
|
} = args;
|
||||||
|
|
||||||
|
if (nav === 'account') return <Collection />;
|
||||||
|
return <Team />;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = addState(Bottom);
|
||||||
@ -5,14 +5,14 @@ const { connect } = require('preact-redux');
|
|||||||
const Welcome = require('./welcome');
|
const Welcome = require('./welcome');
|
||||||
const Game = require('./game');
|
const Game = require('./game');
|
||||||
const Instance = require('./instance.component');
|
const Instance = require('./instance.component');
|
||||||
const Team = require('./team');
|
const Header = require('./header');
|
||||||
const Play = require('./play');
|
const Top = require('./main.top');
|
||||||
const Account = require('./account.page');
|
const Bottom = require('./main.bottom');
|
||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
state => {
|
state => {
|
||||||
const { game, instance, account, nav, team, constructs } = state;
|
const { game, instance, account, nav } = state;
|
||||||
return { game, instance, account, nav, team, constructs };
|
return { game, instance, account, nav };
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -37,12 +37,13 @@ function Main(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nav === 'transition') return false;
|
if (nav === 'transition') return false;
|
||||||
if (nav === 'play') return <Play />;
|
|
||||||
if (nav === 'team') return <Team />;
|
|
||||||
if (nav === 'account') return <Account />;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Play />
|
<main class="menu">
|
||||||
|
<Header />
|
||||||
|
<Top />
|
||||||
|
<Bottom />
|
||||||
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
34
client/src/components/main.top.jsx
Normal file
34
client/src/components/main.top.jsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const { connect } = require('preact-redux');
|
||||||
|
const preact = require('preact');
|
||||||
|
|
||||||
|
const actions = require('./../actions');
|
||||||
|
|
||||||
|
const AccountTop = require('./account.top');
|
||||||
|
const Play = require('./play');
|
||||||
|
const Shop = require('./shop');
|
||||||
|
|
||||||
|
const addState = connect(
|
||||||
|
function receiveState(state) {
|
||||||
|
const {
|
||||||
|
nav,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
return {
|
||||||
|
nav,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
function Top(args) {
|
||||||
|
const {
|
||||||
|
nav,
|
||||||
|
} = args;
|
||||||
|
|
||||||
|
if (nav === 'account') return <AccountTop />;
|
||||||
|
if (nav === 'play') return <Play />
|
||||||
|
if (nav === 'shop') return <Shop />
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = addState(Top);
|
||||||
@ -1,7 +1,6 @@
|
|||||||
const preact = require('preact');
|
const preact = require('preact');
|
||||||
const { connect } = require('preact-redux');
|
const { connect } = require('preact-redux');
|
||||||
|
|
||||||
// const Header = require('./header');
|
|
||||||
const Main = require('./main');
|
const Main = require('./main');
|
||||||
const Nav = require('./nav');
|
const Nav = require('./nav');
|
||||||
const Controls = require('./controls');
|
const Controls = require('./controls');
|
||||||
|
|||||||
@ -92,7 +92,6 @@ function Nav(args) {
|
|||||||
|
|
||||||
const canJoin = team.some(c => !c);
|
const canJoin = team.some(c => !c);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav onClick={hideNav} >
|
<nav onClick={hideNav} >
|
||||||
<h1 class="header-title">mnml.gg</h1>
|
<h1 class="header-title">mnml.gg</h1>
|
||||||
|
|||||||
@ -3,7 +3,14 @@ const { connect } = require('preact-redux');
|
|||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
const { ws } = state;
|
const {
|
||||||
|
ws,
|
||||||
|
instances,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
function sendInstanceState(id) {
|
||||||
|
ws.sendInstanceState(id);
|
||||||
|
}
|
||||||
|
|
||||||
function sendInstancePractice() {
|
function sendInstancePractice() {
|
||||||
ws.sendInstancePractice();
|
ws.sendInstancePractice();
|
||||||
@ -14,6 +21,9 @@ const addState = connect(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
instances,
|
||||||
|
|
||||||
|
sendInstanceState,
|
||||||
sendInstanceQueue,
|
sendInstanceQueue,
|
||||||
sendInstancePractice,
|
sendInstancePractice,
|
||||||
};
|
};
|
||||||
@ -22,13 +32,33 @@ const addState = connect(
|
|||||||
|
|
||||||
function JoinButtons(args) {
|
function JoinButtons(args) {
|
||||||
const {
|
const {
|
||||||
|
instances,
|
||||||
|
|
||||||
|
sendInstanceState,
|
||||||
sendInstanceQueue,
|
sendInstanceQueue,
|
||||||
sendInstancePractice,
|
sendInstancePractice,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
|
if (instances.length) {
|
||||||
return (
|
return (
|
||||||
<aside class='play-ctrl'>
|
<aside class='play-ctrl'>
|
||||||
<div class="timer-container"></div>
|
<div class="timer-container"></div>
|
||||||
|
<div class="controls">
|
||||||
|
<button
|
||||||
|
class='pvp ready full'
|
||||||
|
onClick={() => sendInstanceState(instances[0].id)}
|
||||||
|
type="submit">
|
||||||
|
Rejoin
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<aside class='play-ctrl'>
|
||||||
|
<div class="timer-container"></div>
|
||||||
|
<div class="controls">
|
||||||
<button
|
<button
|
||||||
class='pvp ready'
|
class='pvp ready'
|
||||||
onClick={() => sendInstanceQueue()}
|
onClick={() => sendInstanceQueue()}
|
||||||
@ -39,8 +69,9 @@ function JoinButtons(args) {
|
|||||||
class='practice ready'
|
class='practice ready'
|
||||||
onClick={() => sendInstancePractice()}
|
onClick={() => sendInstancePractice()}
|
||||||
type="submit">
|
type="submit">
|
||||||
Practice
|
Learn
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,118 +1,128 @@
|
|||||||
const { connect } = require('preact-redux');
|
// const { connect } = require('preact-redux');
|
||||||
const preact = require('preact');
|
const preact = require('preact');
|
||||||
|
const { connect } = require('preact-redux');
|
||||||
|
const { Elements } = require('react-stripe-elements');
|
||||||
|
|
||||||
|
const Header = require('./header');
|
||||||
|
const Team = require('./team');
|
||||||
|
const StripeBtns = require('./stripe.buttons');
|
||||||
|
|
||||||
const { stringSort } = require('./../utils');
|
|
||||||
const { ConstructAvatar } = require('./construct');
|
|
||||||
const actions = require('./../actions');
|
const actions = require('./../actions');
|
||||||
const Inventory = require('./inventory');
|
|
||||||
|
|
||||||
const idSort = stringSort('id');
|
const VERSION = process.env.npm_package_version;
|
||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
const {
|
const {
|
||||||
ws,
|
ws,
|
||||||
constructs,
|
account,
|
||||||
constructRename,
|
shop,
|
||||||
team,
|
|
||||||
mtxActive,
|
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
function sendInstancePractice() {
|
function mtxBuy(mtx) {
|
||||||
return ws.sendInstancePractice();
|
return ws.sendMtxBuy(mtx.variant);
|
||||||
}
|
|
||||||
|
|
||||||
function sendConstructAvatarReroll(id) {
|
|
||||||
console.log('using', mtxActive, 'on', id);
|
|
||||||
return ws.sendMtxApply(id, mtxActive, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendConstructRename(id, name) {
|
|
||||||
ws.sendMtxApply(id, 'Rename', name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
constructs,
|
account,
|
||||||
mtxActive,
|
shop,
|
||||||
constructRename,
|
mtxBuy,
|
||||||
team,
|
|
||||||
sendConstructRename,
|
|
||||||
sendInstancePractice,
|
|
||||||
sendConstructAvatarReroll,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
function receiveDispatch(dispatch) {
|
function receiveDispatch(dispatch) {
|
||||||
function setConstructRename(id) {
|
function setMtxActive(mtx) {
|
||||||
dispatch(actions.setConstructRename(id));
|
dispatch(actions.setConstructRename(null));
|
||||||
|
dispatch(actions.setMtxActive(mtx));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearMtxRename() {
|
function setNav(place) {
|
||||||
dispatch(actions.setConstructRename(null));
|
return dispatch(actions.setNav(place));
|
||||||
dispatch(actions.setMtxActive(null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
clearMtxRename,
|
setMtxActive,
|
||||||
setConstructRename,
|
setNav,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
function Play(args) {
|
function Play(args) {
|
||||||
const {
|
const {
|
||||||
team,
|
account,
|
||||||
constructRename,
|
shop,
|
||||||
clearMtxRename,
|
mtxBuy,
|
||||||
setConstructRename,
|
|
||||||
sendConstructRename,
|
setMtxActive,
|
||||||
mtxActive,
|
setNav,
|
||||||
sendConstructAvatarReroll,
|
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
const constructPanels = team
|
if (!shop) return false;
|
||||||
.map(construct => {
|
|
||||||
const constructName = constructRename === construct.id
|
|
||||||
? <input id='renameInput' type="text" style="text-align: center" placeholder="enter a new name"></input>
|
|
||||||
: <h2>{construct.name}</h2>;
|
|
||||||
|
|
||||||
const confirm = constructRename === construct.id
|
const useMtx = (item, i) => (
|
||||||
? <button onClick={() => sendConstructRename(construct.id, document.getElementById('renameInput').value)}>
|
<figure key={i} onClick={() => setMtxActive(item)} >
|
||||||
Confirm
|
<figcaption>{item}</figcaption>
|
||||||
</button>
|
<button disabled={account.balance === 0}>¤1</button>
|
||||||
: false;
|
</figure>
|
||||||
|
|
||||||
const cancel = constructRename === construct.id
|
|
||||||
? <button onClick={() => clearMtxRename()}>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
: false;
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={construct.id}
|
|
||||||
style={ mtxActive ? { cursor: 'pointer' } : {}}
|
|
||||||
onClick={() => {
|
|
||||||
if (!mtxActive) return false;
|
|
||||||
if (mtxActive === 'Rename') return setConstructRename(construct.id);
|
|
||||||
return sendConstructAvatarReroll(construct.id);
|
|
||||||
}}
|
|
||||||
class="construct">
|
|
||||||
<ConstructAvatar construct={construct} />
|
|
||||||
{constructName}
|
|
||||||
{confirm}
|
|
||||||
{cancel}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
const availableMtx = (item, i) => (
|
||||||
|
<figure key={i} onClick={() => mtxBuy(item)} >
|
||||||
|
<figcaption>{item.variant}</figcaption>
|
||||||
|
<button disabled={account.balance < item.credits}>¤{item.credits}</button>
|
||||||
|
</figure>
|
||||||
|
);
|
||||||
|
|
||||||
|
const subscription = account.subscribed
|
||||||
|
? <button
|
||||||
|
class="stripe-btn"
|
||||||
|
disabled>
|
||||||
|
Subscribed
|
||||||
|
</button>
|
||||||
|
: <button
|
||||||
|
onClick={() => setNav('shop')}
|
||||||
|
class="stripe-btn"
|
||||||
|
role="link">
|
||||||
|
Subscribe
|
||||||
|
</button>;
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main class="menu">
|
<div class="inventory top">
|
||||||
<div class="team top">
|
<div class="news">
|
||||||
{constructPanels}
|
<h1>mnml v{VERSION}</h1>
|
||||||
|
<p>use the buttons on the right to join an instance.</p>
|
||||||
|
<p>
|
||||||
|
select <b>PVP</b> to play against other players.<br />
|
||||||
|
click <b>LEARN</b> to practice the game without time controls.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
if you enjoy the game please support its development by <b>subscribing</b> or purchasing <b>credits</b>.<br />
|
||||||
|
glhf
|
||||||
|
</p>
|
||||||
|
<p>--ntr & mashy</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="credits">¤ {account.balance}</h1>
|
||||||
|
<div class='list'>
|
||||||
|
{subscription}
|
||||||
|
<button
|
||||||
|
onClick={() => setNav('shop')}
|
||||||
|
class="stripe-btn"
|
||||||
|
role="link">
|
||||||
|
Get Credits
|
||||||
|
</button>
|
||||||
|
<div id="error-message"></div>
|
||||||
|
</div>
|
||||||
|
<div class='list'>
|
||||||
|
{shop.owned.map(useMtx)}
|
||||||
|
</div>
|
||||||
|
<div class='list'>
|
||||||
|
{shop.available.map(availableMtx)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Inventory />
|
|
||||||
</main>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,7 @@ module.exports = {
|
|||||||
None: () =>
|
None: () =>
|
||||||
<figure>
|
<figure>
|
||||||
{diamond(['gray'])}
|
{diamond(['gray'])}
|
||||||
<figcaption> </figcaption>
|
<figcaption>SPEC</figcaption>
|
||||||
</figure>,
|
</figure>,
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
58
client/src/components/shop.jsx
Normal file
58
client/src/components/shop.jsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// const { connect } = require('preact-redux');
|
||||||
|
const preact = require('preact');
|
||||||
|
const { connect } = require('preact-redux');
|
||||||
|
const { Elements } = require('react-stripe-elements');
|
||||||
|
|
||||||
|
const StripeBtns = require('./stripe.buttons');
|
||||||
|
const actions = require('./../actions');
|
||||||
|
|
||||||
|
const addState = connect(
|
||||||
|
function receiveState(state) {
|
||||||
|
const {
|
||||||
|
ws,
|
||||||
|
account,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
return {
|
||||||
|
account,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
function Shop(args) {
|
||||||
|
const {
|
||||||
|
account,
|
||||||
|
} = args;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="inventory top">
|
||||||
|
<div class="news">
|
||||||
|
<h1>support the game</h1>
|
||||||
|
<p>
|
||||||
|
<b>credits</b> are in game currency that can be used to purchase:
|
||||||
|
<ul>
|
||||||
|
<li>img sets</li>
|
||||||
|
<li>construct renames</li>
|
||||||
|
<li>new constructs</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>subscriptions</b> grant extra benefits:
|
||||||
|
<ul>
|
||||||
|
<li>additional credits</li>
|
||||||
|
<li>chat wheel (soon ™)</li>
|
||||||
|
<li>account icons (soon ™)</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="credits">¤ {account.balance}</h1>
|
||||||
|
<Elements>
|
||||||
|
<StripeBtns account={account} />
|
||||||
|
</Elements>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = addState(Shop);
|
||||||
@ -6,8 +6,16 @@ function subPlan() {
|
|||||||
return 'prod_FWSA8RoyMMV3st';
|
return 'prod_FWSA8RoyMMV3st';
|
||||||
}
|
}
|
||||||
|
|
||||||
function bitsSku() {
|
function bitsSku(d) {
|
||||||
if (window.location.host === 'mnml.gg') return 'sku_Fjdu7zOy3sLGc5';
|
if (window.location.host === 'mnml.gg') {
|
||||||
|
if (d === 50) return 'sku_Fl5tLCWogUsgus';
|
||||||
|
if (d === 20) return 'sku_Fl5qegnxYRv7Cy';
|
||||||
|
if (d === 10) return 'sku_Fl5qVosoDsUVgy';
|
||||||
|
if (d === 5) return 'sku_Fjdu7zOy3sLGc5';
|
||||||
|
|
||||||
|
// !!!!
|
||||||
|
return 'sku_Fjdu7zOy3sLGc5';
|
||||||
|
}
|
||||||
return 'sku_FjuNxONdWewjH2';
|
return 'sku_FjuNxONdWewjH2';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,6 +24,7 @@ function BitsBtn(args) {
|
|||||||
stripe,
|
stripe,
|
||||||
account,
|
account,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
function subscribeClick() {
|
function subscribeClick() {
|
||||||
stripe.redirectToCheckout({
|
stripe.redirectToCheckout({
|
||||||
items: [{ plan: subPlan(), quantity: 1 }],
|
items: [{ plan: subPlan(), quantity: 1 }],
|
||||||
@ -25,9 +34,9 @@ function BitsBtn(args) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function bitsClick() {
|
function bitsClick(d) {
|
||||||
stripe.redirectToCheckout({
|
stripe.redirectToCheckout({
|
||||||
items: [{ sku: bitsSku(), quantity: 1 }],
|
items: [{ sku: bitsSku(d), quantity: 1 }],
|
||||||
successUrl: window.location.origin,
|
successUrl: window.location.origin,
|
||||||
cancelUrl: window.location.origin,
|
cancelUrl: window.location.origin,
|
||||||
clientReferenceId: account.id,
|
clientReferenceId: account.id,
|
||||||
@ -48,16 +57,30 @@ function BitsBtn(args) {
|
|||||||
</button>;
|
</button>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div>
|
||||||
<div class='list'>
|
<div class='list'>
|
||||||
{subscription}
|
{subscription}
|
||||||
<button
|
</div>
|
||||||
onClick={bitsClick}
|
<div class='list'>
|
||||||
class="stripe-btn"
|
<figure onClick={() => bitsClick(5)} >
|
||||||
role="link">
|
<figcaption>$5 AUD</figcaption>
|
||||||
Get Credits
|
<button class="stripe-btn">¤50</button>
|
||||||
</button>
|
</figure>
|
||||||
|
<figure onClick={() => bitsClick(10)} >
|
||||||
|
<figcaption>$10 AUD</figcaption>
|
||||||
|
<button class="stripe-btn">¤110</button>
|
||||||
|
</figure>
|
||||||
|
<figure onClick={() => bitsClick(20)} >
|
||||||
|
<figcaption>$20 AUD</figcaption>
|
||||||
|
<button class="stripe-btn">¤250</button>
|
||||||
|
</figure>
|
||||||
|
<figure onClick={() => bitsClick(50)} >
|
||||||
|
<figcaption>$50 AUD</figcaption>
|
||||||
|
<button class="stripe-btn">¤660</button>
|
||||||
|
</figure>
|
||||||
<div id="error-message"></div>
|
<div id="error-message"></div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -52,7 +52,7 @@ function TeamCtrl(args) {
|
|||||||
class='ready'
|
class='ready'
|
||||||
disabled={teamSelect.some(c => !c)}
|
disabled={teamSelect.some(c => !c)}
|
||||||
onClick={sendAccountSetTeam}>
|
onClick={sendAccountSetTeam}>
|
||||||
Set Team
|
Set
|
||||||
</button>
|
</button>
|
||||||
<div class="team-page-ctrl">
|
<div class="team-page-ctrl">
|
||||||
<button onClick={() => setTeamPage(teamPage - 1)} disabled={disableDecrement}> « </button>
|
<button onClick={() => setTeamPage(teamPage - 1)} disabled={disableDecrement}> « </button>
|
||||||
|
|||||||
@ -1,88 +1,112 @@
|
|||||||
const preact = require('preact');
|
|
||||||
const { connect } = require('preact-redux');
|
const { connect } = require('preact-redux');
|
||||||
|
const preact = require('preact');
|
||||||
|
|
||||||
const actions = require('./../actions');
|
|
||||||
const { COLOURS } = require('./../utils');
|
|
||||||
const { ConstructAvatar } = require('./construct');
|
const { ConstructAvatar } = require('./construct');
|
||||||
|
const actions = require('./../actions');
|
||||||
|
|
||||||
const addState = connect(
|
const addState = connect(
|
||||||
function receiveState(state) {
|
function receiveState(state) {
|
||||||
const { ws, constructs, teamPage, teamSelect } = state;
|
const {
|
||||||
|
ws,
|
||||||
|
constructs,
|
||||||
|
constructRename,
|
||||||
|
team,
|
||||||
|
mtxActive,
|
||||||
|
} = state;
|
||||||
|
|
||||||
function sendConstructSpawn(name) {
|
function sendInstancePractice() {
|
||||||
return ws.sendMtxConstructSpawn(name);
|
return ws.sendInstancePractice();
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendConstructAvatarReroll(id) {
|
||||||
|
console.log('using', mtxActive, 'on', id);
|
||||||
|
return ws.sendMtxApply(id, mtxActive, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendConstructRename(id, name) {
|
||||||
|
ws.sendMtxApply(id, 'Rename', name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
constructs,
|
constructs,
|
||||||
teamPage,
|
mtxActive,
|
||||||
teamSelect,
|
constructRename,
|
||||||
|
team,
|
||||||
|
sendConstructRename,
|
||||||
|
sendInstancePractice,
|
||||||
|
sendConstructAvatarReroll,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
function receiveDispatch(dispatch) {
|
function receiveDispatch(dispatch) {
|
||||||
function setTeam(constructIds) {
|
function setConstructRename(id) {
|
||||||
dispatch(actions.setTeamSelect(constructIds));
|
dispatch(actions.setConstructRename(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearMtxRename() {
|
||||||
|
dispatch(actions.setConstructRename(null));
|
||||||
|
dispatch(actions.setMtxActive(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setTeam,
|
clearMtxRename,
|
||||||
|
setConstructRename,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
function Team(args) {
|
function Team(args) {
|
||||||
const {
|
const {
|
||||||
constructs,
|
team,
|
||||||
teamPage,
|
constructRename,
|
||||||
teamSelect,
|
clearMtxRename,
|
||||||
setTeam,
|
setConstructRename,
|
||||||
|
sendConstructRename,
|
||||||
|
mtxActive,
|
||||||
|
sendConstructAvatarReroll,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
if (!constructs) return <div></div>;
|
const constructPanels = team
|
||||||
|
.map(construct => {
|
||||||
|
const constructName = constructRename === construct.id
|
||||||
|
? <input id='renameInput' type="text" style="text-align: center" placeholder="enter a new name"></input>
|
||||||
|
: <h2>{construct.name}</h2>;
|
||||||
|
|
||||||
// redux limitation + suggested workaround
|
const confirm = constructRename === construct.id
|
||||||
// so much for dumb components
|
? <button onClick={() => sendConstructRename(construct.id, document.getElementById('renameInput').value)}>
|
||||||
function selectConstruct(id) {
|
Confirm
|
||||||
// remove
|
</button>
|
||||||
const i = teamSelect.findIndex(sid => sid === id);
|
: false;
|
||||||
if (i > -1) {
|
|
||||||
teamSelect[i] = null;
|
|
||||||
return setTeam(teamSelect);
|
|
||||||
}
|
|
||||||
|
|
||||||
// window insert
|
const cancel = constructRename === construct.id
|
||||||
const insert = teamSelect.findIndex(j => j === null);
|
? <button onClick={() => clearMtxRename()}>
|
||||||
if (insert === -1) return setTeam([id, null, null]);
|
Cancel
|
||||||
teamSelect[insert] = id;
|
</button>
|
||||||
return setTeam(teamSelect);
|
: false;
|
||||||
}
|
|
||||||
console.log(constructs.length);
|
|
||||||
const dispConstructs = constructs.length >= ((teamPage + 1) * 6)
|
|
||||||
? constructs.slice(teamPage * 6, (teamPage + 1) * 6)
|
|
||||||
: constructs.slice(teamPage * 6, constructs.length);
|
|
||||||
|
|
||||||
const constructPanels = dispConstructs.map(construct => {
|
|
||||||
const colour = teamSelect.indexOf(construct.id);
|
|
||||||
const selected = colour > -1;
|
|
||||||
|
|
||||||
const borderColour = selected ? COLOURS[colour] : '#000000';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={construct.id}
|
key={construct.id}
|
||||||
class="construct team-select"
|
style={ mtxActive ? { cursor: 'pointer' } : {}}
|
||||||
style={ { 'border-color': borderColour || 'whitesmoke' } }
|
onClick={() => {
|
||||||
onClick={() => selectConstruct(construct.id)} >
|
if (!mtxActive) return false;
|
||||||
|
if (mtxActive === 'Rename') return setConstructRename(construct.id);
|
||||||
|
return sendConstructAvatarReroll(construct.id);
|
||||||
|
}}
|
||||||
|
class="construct">
|
||||||
<ConstructAvatar construct={construct} />
|
<ConstructAvatar construct={construct} />
|
||||||
<h2>{construct.name}</h2>
|
{constructName}
|
||||||
|
{confirm}
|
||||||
|
{cancel}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section class="team top">
|
<div class="team">
|
||||||
{constructPanels}
|
{constructPanels}
|
||||||
</section>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,6 @@ const addState = connect(
|
|||||||
player,
|
player,
|
||||||
combiner,
|
combiner,
|
||||||
reclaiming,
|
reclaiming,
|
||||||
vboxHighlight,
|
|
||||||
vboxSelected,
|
vboxSelected,
|
||||||
itemInfo,
|
itemInfo,
|
||||||
itemUnequip,
|
itemUnequip,
|
||||||
@ -49,7 +48,6 @@ const addState = connect(
|
|||||||
sendVboxCombine,
|
sendVboxCombine,
|
||||||
sendVboxDiscard,
|
sendVboxDiscard,
|
||||||
sendVboxReclaim,
|
sendVboxReclaim,
|
||||||
vboxHighlight,
|
|
||||||
vboxSelected,
|
vboxSelected,
|
||||||
itemInfo,
|
itemInfo,
|
||||||
itemUnequip,
|
itemUnequip,
|
||||||
@ -70,10 +68,6 @@ const addState = connect(
|
|||||||
return dispatch(actions.setInfo(item));
|
return dispatch(actions.setInfo(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
function setVboxHighlight(v) {
|
|
||||||
return dispatch(actions.setVboxHighlight(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
function setVboxSelected(v) {
|
function setVboxSelected(v) {
|
||||||
return dispatch(actions.setVboxSelected(v));
|
return dispatch(actions.setVboxSelected(v));
|
||||||
}
|
}
|
||||||
@ -86,7 +80,6 @@ const addState = connect(
|
|||||||
setCombiner,
|
setCombiner,
|
||||||
setReclaiming,
|
setReclaiming,
|
||||||
setInfo,
|
setInfo,
|
||||||
setVboxHighlight,
|
|
||||||
setVboxSelected,
|
setVboxSelected,
|
||||||
setItemEquip,
|
setItemEquip,
|
||||||
};
|
};
|
||||||
@ -105,7 +98,6 @@ function Vbox(args) {
|
|||||||
sendVboxCombine,
|
sendVboxCombine,
|
||||||
sendVboxDiscard,
|
sendVboxDiscard,
|
||||||
sendVboxReclaim,
|
sendVboxReclaim,
|
||||||
// vboxHighlight,
|
|
||||||
|
|
||||||
setCombiner,
|
setCombiner,
|
||||||
setInfo,
|
setInfo,
|
||||||
@ -118,19 +110,12 @@ function Vbox(args) {
|
|||||||
sendItemUnequip,
|
sendItemUnequip,
|
||||||
|
|
||||||
setReclaiming,
|
setReclaiming,
|
||||||
setVboxHighlight,
|
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
if (!player) return false;
|
if (!player) return false;
|
||||||
const { vbox } = player;
|
const { vbox } = player;
|
||||||
const vboxSelecting = vboxSelected.length;
|
const vboxSelecting = vboxSelected.length;
|
||||||
|
|
||||||
// function setHighlight(type) {
|
|
||||||
// if (type === 'skill') return setVboxHighlight(itemInfo.items.filter(v => v.skill).map(v => v.item));
|
|
||||||
// if (type === 'spec') return setVboxHighlight(itemInfo.items.filter(v => v.spec).map(v => v.item));
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
function combinerChange(newCombiner) {
|
function combinerChange(newCombiner) {
|
||||||
setCombiner(newCombiner);
|
setCombiner(newCombiner);
|
||||||
|
|
||||||
@ -140,20 +125,7 @@ function Vbox(args) {
|
|||||||
setItemEquip(null);
|
setItemEquip(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newCombiner.every(c => c === null)) return setVboxHighlight([]);
|
|
||||||
|
|
||||||
const combinerValues = newCombiner.map(cv => player.vbox.bound[cv]).filter(cv => cv);
|
|
||||||
|
|
||||||
const filteredCombos = itemInfo.combos
|
|
||||||
.filter(combo => combinerValues.every(u => combo.components.includes(u)));
|
|
||||||
|
|
||||||
const comboValues = itemInfo.items.filter(v => {
|
|
||||||
if (!filteredCombos.some(c => c.components.includes(v.item))) return false;
|
|
||||||
if (!['Red', 'Green', 'Blue'].includes(v.item) && combinerValues.includes(v.item)) return false;
|
|
||||||
return true;
|
return true;
|
||||||
});
|
|
||||||
|
|
||||||
return setVboxHighlight(comboValues.map(v => v.item));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -192,6 +164,7 @@ function Vbox(args) {
|
|||||||
|
|
||||||
function onClick(e) {
|
function onClick(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
setCombiner([]);
|
||||||
if (selected) return clearVboxSelected();
|
if (selected) return clearVboxSelected();
|
||||||
return setVboxSelected([group, index]);
|
return setVboxSelected([group, index]);
|
||||||
}
|
}
|
||||||
@ -203,7 +176,8 @@ function Vbox(args) {
|
|||||||
<button
|
<button
|
||||||
class={classes}
|
class={classes}
|
||||||
onMouseOver={e => vboxHover(e, v)}
|
onMouseOver={e => vboxHover(e, v)}
|
||||||
onClick={onClick}
|
onMouseDown={onClick}
|
||||||
|
onClick={e => e.stopPropagation()}
|
||||||
onDblClick={onDblClick} >
|
onDblClick={onDblClick} >
|
||||||
{shapes[v]()}
|
{shapes[v]()}
|
||||||
</button>
|
</button>
|
||||||
@ -213,7 +187,8 @@ function Vbox(args) {
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
class={classes}
|
class={classes}
|
||||||
onClick={onClick}
|
onMouseDown={onClick}
|
||||||
|
onClick={e => e.stopPropagation()}
|
||||||
onDblClick={onDblClick}
|
onDblClick={onDblClick}
|
||||||
onMouseOver={e => vboxHover(e, v)}>
|
onMouseOver={e => vboxHover(e, v)}>
|
||||||
{v}
|
{v}
|
||||||
@ -225,7 +200,8 @@ function Vbox(args) {
|
|||||||
function vboxElement() {
|
function vboxElement() {
|
||||||
return (
|
return (
|
||||||
<div class='vbox-vbox'
|
<div class='vbox-vbox'
|
||||||
onClick={() => setReclaiming(false)}
|
onMouseDown={() => setReclaiming(false)}
|
||||||
|
onClick={e => e.stopPropagation()}
|
||||||
onMouseOver={e => hoverInfo(e, 'vbox')}>
|
onMouseOver={e => hoverInfo(e, 'vbox')}>
|
||||||
<div class="vbox-hdr">
|
<div class="vbox-hdr">
|
||||||
<h3 onTouchStart={e => e.target.scrollIntoView(true)}>VBOX</h3>
|
<h3 onTouchStart={e => e.target.scrollIntoView(true)}>VBOX</h3>
|
||||||
@ -241,7 +217,8 @@ function Vbox(args) {
|
|||||||
<button
|
<button
|
||||||
class='vbox-btn'
|
class='vbox-btn'
|
||||||
onMouseOver={e => hoverInfo(e, 'refill')}
|
onMouseOver={e => hoverInfo(e, 'refill')}
|
||||||
onClick={() => sendVboxDiscard()}>
|
onClick={e => e.stopPropagation()}
|
||||||
|
onMouseDown={() => sendVboxDiscard()}>
|
||||||
refill - 2b
|
refill - 2b
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -251,32 +228,6 @@ function Vbox(args) {
|
|||||||
//
|
//
|
||||||
// INVENTORY
|
// INVENTORY
|
||||||
//
|
//
|
||||||
|
|
||||||
// const boundTds = range(0, 9).map(i => {
|
|
||||||
// const value = vbox.bound[i];
|
|
||||||
// if (combiner.indexOf(i) > -1) {
|
|
||||||
// return (
|
|
||||||
// <td
|
|
||||||
// key={i}>
|
|
||||||
//
|
|
||||||
// </td>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const highlighted = value && vboxHighlight.includes(value);
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <td
|
|
||||||
// key={i}
|
|
||||||
// class={`${highlighted ? 'highlight' : ''}`}
|
|
||||||
// onMouseOver={(e) => vboxHover(e, value)}
|
|
||||||
// onClick={e => boundClick(e, i, highlighted) }>
|
|
||||||
// {convertItem(value)}
|
|
||||||
// </td>
|
|
||||||
// );
|
|
||||||
// });
|
|
||||||
|
|
||||||
|
|
||||||
function reclaimClick(e) {
|
function reclaimClick(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
return setReclaiming(!reclaiming);
|
return setReclaiming(!reclaiming);
|
||||||
@ -292,6 +243,7 @@ function Vbox(args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onClick(e) {
|
function onClick(e) {
|
||||||
|
if (vboxSelecting) clearVboxSelected();
|
||||||
if (reclaiming) return sendVboxReclaim(i);
|
if (reclaiming) return sendVboxReclaim(i);
|
||||||
|
|
||||||
const combinerIndex = combiner.indexOf(i);
|
const combinerIndex = combiner.indexOf(i);
|
||||||
@ -310,7 +262,8 @@ function Vbox(args) {
|
|||||||
<button
|
<button
|
||||||
class={classes}
|
class={classes}
|
||||||
onMouseOver={e => vboxHover(e, v)}
|
onMouseOver={e => vboxHover(e, v)}
|
||||||
onClick={onClick}>
|
onClick={e => e.stopPropagation()}
|
||||||
|
onMouseDown={onClick}>
|
||||||
{shapes[v]()}
|
{shapes[v]()}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
@ -319,7 +272,8 @@ function Vbox(args) {
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
class={classes}
|
class={classes}
|
||||||
onClick={onClick}
|
onMouseDown={onClick}
|
||||||
|
onClick={e => e.stopPropagation()}
|
||||||
onMouseOver={e => vboxHover(e, v)}>
|
onMouseOver={e => vboxHover(e, v)}>
|
||||||
{v}
|
{v}
|
||||||
</button>
|
</button>
|
||||||
@ -346,7 +300,8 @@ function Vbox(args) {
|
|||||||
class='vbox-btn'
|
class='vbox-btn'
|
||||||
disabled={combiner.length !== 3}
|
disabled={combiner.length !== 3}
|
||||||
onMouseOver={e => hoverInfo(e, 'refine')}
|
onMouseOver={e => hoverInfo(e, 'refine')}
|
||||||
onClick={() => sendVboxCombine()}>
|
onClick={e => e.stopPropagation()}
|
||||||
|
onMouseDown={() => sendVboxCombine()}>
|
||||||
{text}
|
{text}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
@ -363,7 +318,8 @@ function Vbox(args) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={inventoryClass}
|
<div class={inventoryClass}
|
||||||
onClick={inventoryClick}
|
onMouseDown={inventoryClick}
|
||||||
|
onClick={e => e.stopPropagation()}
|
||||||
style={vboxSelecting || itemUnequip.length ? { cursor: 'pointer' } : null}
|
style={vboxSelecting || itemUnequip.length ? { cursor: 'pointer' } : null}
|
||||||
onMouseOver={e => hoverInfo(e, 'inventory')}>
|
onMouseOver={e => hoverInfo(e, 'inventory')}>
|
||||||
<div class="vbox-hdr">
|
<div class="vbox-hdr">
|
||||||
@ -371,7 +327,8 @@ function Vbox(args) {
|
|||||||
<button
|
<button
|
||||||
class='vbox-btn reclaim'
|
class='vbox-btn reclaim'
|
||||||
onMouseOver={e => hoverInfo(e, 'reclaim')}
|
onMouseOver={e => hoverInfo(e, 'reclaim')}
|
||||||
onClick={reclaimClick}>
|
onClick={e => e.stopPropagation()}
|
||||||
|
onMouseDown={reclaimClick}>
|
||||||
reclaim
|
reclaim
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,7 +3,7 @@ const eachSeries = require('async/eachSeries');
|
|||||||
const actions = require('./actions');
|
const actions = require('./actions');
|
||||||
const { TIMES } = require('./constants');
|
const { TIMES } = require('./constants');
|
||||||
const animations = require('./animations.utils');
|
const animations = require('./animations.utils');
|
||||||
const { infoToast, errorToast } = require('./utils');
|
const { infoToast, errorToast, removeTier } = require('./utils');
|
||||||
|
|
||||||
function registerEvents(store) {
|
function registerEvents(store) {
|
||||||
function notify(msg) {
|
function notify(msg) {
|
||||||
@ -69,13 +69,12 @@ function registerEvents(store) {
|
|||||||
const timeout = animations.getTime(sequence);
|
const timeout = animations.getTime(sequence);
|
||||||
const anims = animations.getObjects(r, sequence, game, account);
|
const anims = animations.getObjects(r, sequence, game, account);
|
||||||
const text = animations.getText(r, sequence);
|
const text = animations.getText(r, sequence);
|
||||||
|
|
||||||
store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r, game)));
|
store.dispatch(actions.setAnimFocus(animations.getFocusTargets(r, game)));
|
||||||
|
|
||||||
if (sequence.includes('START_SKILL')) store.dispatch(actions.setAnimSource(anims.animSource));
|
if (sequence.includes('START_SKILL')) store.dispatch(actions.setAnimSource(anims.animSource));
|
||||||
if (sequence.includes('END_SKILL')) {
|
if (sequence.includes('END_SKILL')) {
|
||||||
store.dispatch(actions.setAnimTarget(anims.animTarget));
|
store.dispatch(actions.setAnimTarget(anims.animTarget));
|
||||||
if (!['Banish', 'Invert'].includes(anims.animTarget.skill)) store.dispatch(actions.setAnimCb(cb));
|
if (!['Banish', 'Invert'].includes(removeTier(anims.animTarget.skill))) store.dispatch(actions.setAnimCb(cb));
|
||||||
}
|
}
|
||||||
if (sequence.includes('POST_SKILL')) {
|
if (sequence.includes('POST_SKILL')) {
|
||||||
// timeout to prevent text classes from being added too soon
|
// timeout to prevent text classes from being added too soon
|
||||||
@ -90,7 +89,7 @@ function registerEvents(store) {
|
|||||||
store.dispatch(actions.setAnimText(null));
|
store.dispatch(actions.setAnimText(null));
|
||||||
store.dispatch(actions.setAnimFocus([]));
|
store.dispatch(actions.setAnimFocus([]));
|
||||||
if (!sequence.includes('END_SKILL')
|
if (!sequence.includes('END_SKILL')
|
||||||
|| ['Banish', 'Invert'].includes(anims.animTarget.skill)) return cb();
|
|| ['Banish', 'Invert'].includes(removeTier(anims.animTarget.skill))) return cb();
|
||||||
return true;
|
return true;
|
||||||
}, timeout);
|
}, timeout);
|
||||||
}, err => {
|
}, err => {
|
||||||
|
|||||||
@ -50,7 +50,6 @@ module.exports = {
|
|||||||
teamPage: createReducer(0, 'SET_TEAM_PAGE'),
|
teamPage: createReducer(0, 'SET_TEAM_PAGE'),
|
||||||
teamSelect: createReducer([null, null, null], 'SET_TEAM_SELECT'),
|
teamSelect: createReducer([null, null, null], 'SET_TEAM_SELECT'),
|
||||||
|
|
||||||
vboxHighlight: createReducer([], 'SET_VBOX_HIGHLIGHT'),
|
|
||||||
vboxSelected: createReducer([], 'SET_VBOX_SELECTED'),
|
vboxSelected: createReducer([], 'SET_VBOX_SELECTED'),
|
||||||
|
|
||||||
ws: createReducer(null, 'SET_WS'),
|
ws: createReducer(null, 'SET_WS'),
|
||||||
|
|||||||
@ -200,7 +200,7 @@ function createSocket(events) {
|
|||||||
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, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------
|
// -------------
|
||||||
|
|||||||
@ -101,7 +101,7 @@
|
|||||||
## urls will be written to each interval.
|
## urls will be written to each interval.
|
||||||
# urls = ["unix:///var/run/influxdb.sock"]
|
# urls = ["unix:///var/run/influxdb.sock"]
|
||||||
# urls = ["udp://127.0.0.1:8089"]
|
# urls = ["udp://127.0.0.1:8089"]
|
||||||
urls = ["http://mnml-prod-elk:8086"]
|
urls = ["http://mnml-prod-mn:8086"]
|
||||||
|
|
||||||
## The target database for metrics; will be created as needed.
|
## The target database for metrics; will be created as needed.
|
||||||
## For UDP url endpoint database needs to be configured on server side.
|
## For UDP url endpoint database needs to be configured on server side.
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-ops",
|
"name": "mnml-ops",
|
||||||
"version": "1.2.0",
|
"version": "1.3.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mnml"
|
name = "mnml"
|
||||||
version = "1.2.0"
|
version = "1.3.0"
|
||||||
authors = ["ntr <ntr@smokestack.io>"]
|
authors = ["ntr <ntr@smokestack.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use postgres::transaction::Transaction;
|
|||||||
|
|
||||||
use http::MnmlHttpError;
|
use http::MnmlHttpError;
|
||||||
use names::{name as generate_name};
|
use names::{name as generate_name};
|
||||||
use construct::{Construct, construct_recover, construct_spawn};
|
use construct::{Construct, ConstructSkeleton, construct_spawn};
|
||||||
use instance::{Instance, instance_delete};
|
use instance::{Instance, instance_delete};
|
||||||
use mtx::{Mtx, FREE_MTX};
|
use mtx::{Mtx, FREE_MTX};
|
||||||
use pg::Db;
|
use pg::Db;
|
||||||
@ -350,23 +350,20 @@ pub fn constructs(tx: &mut Transaction, account: &Account) -> Result<Vec<Constru
|
|||||||
let result = tx
|
let result = tx
|
||||||
.query(query, &[&account.id])?;
|
.query(query, &[&account.id])?;
|
||||||
|
|
||||||
let constructs: Result<Vec<Construct>, _> = result.iter()
|
let mut constructs = result.iter()
|
||||||
.map(|row| {
|
.filter_map(|row| {
|
||||||
let construct_bytes: Vec<u8> = row.get(0);
|
let construct_bytes: Vec<u8> = row.get(0);
|
||||||
match from_slice::<Construct>(&construct_bytes) {
|
match from_slice::<ConstructSkeleton>(&construct_bytes) {
|
||||||
Ok(c) => Ok(c),
|
Ok(s) => Some(s),
|
||||||
Err(_e) => construct_recover(construct_bytes, tx),
|
Err(e) => {
|
||||||
|
warn!("{:?}", e);
|
||||||
|
None
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.map(|sk| Construct::from_skeleton(&sk))
|
||||||
|
.collect::<Vec<Construct>>();
|
||||||
|
|
||||||
// catch any errors
|
|
||||||
if constructs.is_err() {
|
|
||||||
warn!("{:?}", constructs);
|
|
||||||
return Err(err_msg("could not deserialise a construct"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut constructs = constructs.unwrap();
|
|
||||||
constructs.sort_by_key(|c| c.id);
|
constructs.sort_by_key(|c| c.id);
|
||||||
return Ok(constructs);
|
return Ok(constructs);
|
||||||
}
|
}
|
||||||
@ -382,23 +379,19 @@ pub fn team(tx: &mut Transaction, account: &Account) -> Result<Vec<Construct>, E
|
|||||||
let result = tx
|
let result = tx
|
||||||
.query(query, &[&account.id])?;
|
.query(query, &[&account.id])?;
|
||||||
|
|
||||||
let constructs: Result<Vec<Construct>, _> = result.iter()
|
let mut constructs = result.iter()
|
||||||
.map(|row| {
|
.filter_map(|row| {
|
||||||
let construct_bytes: Vec<u8> = row.get(0);
|
let construct_bytes: Vec<u8> = row.get(0);
|
||||||
match from_slice::<Construct>(&construct_bytes) {
|
match from_slice::<ConstructSkeleton>(&construct_bytes) {
|
||||||
Ok(c) => Ok(c),
|
Ok(s) => Some(s),
|
||||||
Err(_e) => construct_recover(construct_bytes, tx),
|
Err(e) => {
|
||||||
|
warn!("{:?}", e);
|
||||||
|
None
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.map(|sk| Construct::from_skeleton(&sk))
|
||||||
|
.collect::<Vec<Construct>>();
|
||||||
// catch any errors
|
|
||||||
if constructs.is_err() {
|
|
||||||
warn!("{:?}", constructs);
|
|
||||||
return Err(err_msg("could not deserialise a construct"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut constructs = constructs.unwrap();
|
|
||||||
|
|
||||||
if constructs.len() != 3 {
|
if constructs.len() != 3 {
|
||||||
return Err(format_err!("team not size 3 account={:?}", account));
|
return Err(format_err!("team not size 3 account={:?}", account));
|
||||||
|
|||||||
@ -187,9 +187,10 @@ impl ConstructStat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||||
pub struct ConstructRecover {
|
pub struct ConstructSkeleton {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub account: Uuid,
|
pub account: Uuid,
|
||||||
|
pub img: Uuid,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,13 +221,13 @@ impl Construct {
|
|||||||
id,
|
id,
|
||||||
account: id,
|
account: id,
|
||||||
img: Uuid::new_v4(),
|
img: Uuid::new_v4(),
|
||||||
red_power: ConstructStat { base: 256, value: 256, max: 256, stat: Stat::RedPower },
|
red_power: ConstructStat { base: 320, value: 320, max: 320, stat: Stat::RedPower },
|
||||||
red_life: ConstructStat { base: 0, value: 0, max: 0, stat: Stat::RedLife },
|
red_life: ConstructStat { base: 0, value: 0, max: 0, stat: Stat::RedLife },
|
||||||
blue_power: ConstructStat { base: 256, value: 256, max: 256, stat: Stat::BluePower },
|
blue_power: ConstructStat { base: 320, value: 320, max: 320, stat: Stat::BluePower },
|
||||||
blue_life: ConstructStat { base: 0, value: 0, max: 0, stat: Stat::BlueLife },
|
blue_life: ConstructStat { base: 0, value: 0, max: 0, stat: Stat::BlueLife },
|
||||||
green_power: ConstructStat { base: 256, value: 256, max: 256, stat: Stat::GreenPower },
|
green_power: ConstructStat { base: 320, value: 300, max: 300, stat: Stat::GreenPower },
|
||||||
green_life: ConstructStat { base: 1024, value: 1024, max: 1024, stat: Stat::GreenLife },
|
green_life: ConstructStat { base: 950, value: 950, max: 950, stat: Stat::GreenLife },
|
||||||
speed: ConstructStat { base: 128, value: 128, max: 128, stat: Stat::Speed },
|
speed: ConstructStat { base: 100, value: 100, max: 100, stat: Stat::Speed },
|
||||||
// evasion: ConstructStat { base: 0, value: 0, max: 0, stat: Stat::Evasion },
|
// evasion: ConstructStat { base: 0, value: 0, max: 0, stat: Stat::Evasion },
|
||||||
skills: vec![],
|
skills: vec![],
|
||||||
effects: vec![],
|
effects: vec![],
|
||||||
@ -236,6 +237,27 @@ impl Construct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_skeleton(skeleton: &ConstructSkeleton) -> Construct {
|
||||||
|
return Construct {
|
||||||
|
id: skeleton.id,
|
||||||
|
account: skeleton.id,
|
||||||
|
img: skeleton.img,
|
||||||
|
name: skeleton.name.clone(),
|
||||||
|
|
||||||
|
.. Construct::new()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_skeleton(&self) -> ConstructSkeleton {
|
||||||
|
ConstructSkeleton {
|
||||||
|
id: self.id,
|
||||||
|
account: self.id,
|
||||||
|
img: self.img,
|
||||||
|
name: self.name.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn named(mut self, name: &String) -> Construct {
|
pub fn named(mut self, name: &String) -> Construct {
|
||||||
self.name = name.clone();
|
self.name = name.clone();
|
||||||
self
|
self
|
||||||
@ -827,10 +849,9 @@ pub fn construct_get(tx: &mut Transaction, id: Uuid, account_id: Uuid) -> Result
|
|||||||
|
|
||||||
let result = result.iter().next().ok_or(format_err!("construct {:} not found", id))?;
|
let result = result.iter().next().ok_or(format_err!("construct {:} not found", id))?;
|
||||||
let construct_bytes: Vec<u8> = result.get(0);
|
let construct_bytes: Vec<u8> = result.get(0);
|
||||||
let construct = from_slice::<Construct>(&construct_bytes)
|
let skeleton = from_slice::<ConstructSkeleton>(&construct_bytes)?;
|
||||||
.or_else(|_| construct_recover(construct_bytes, tx))?;
|
|
||||||
|
|
||||||
return Ok(construct);
|
return Ok(Construct::from_skeleton(&skeleton));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn construct_select(tx: &mut Transaction, id: Uuid, account_id: Uuid) -> Result<Construct, Error> {
|
pub fn construct_select(tx: &mut Transaction, id: Uuid, account_id: Uuid) -> Result<Construct, Error> {
|
||||||
@ -847,10 +868,9 @@ pub fn construct_select(tx: &mut Transaction, id: Uuid, account_id: Uuid) -> Res
|
|||||||
|
|
||||||
let result = result.iter().next().ok_or(format_err!("construct {:} not found", id))?;
|
let result = result.iter().next().ok_or(format_err!("construct {:} not found", id))?;
|
||||||
let construct_bytes: Vec<u8> = result.get(0);
|
let construct_bytes: Vec<u8> = result.get(0);
|
||||||
let construct = from_slice::<Construct>(&construct_bytes)
|
let skeleton = from_slice::<ConstructSkeleton>(&construct_bytes)?;
|
||||||
.or_else(|_| construct_recover(construct_bytes, tx))?;
|
|
||||||
|
|
||||||
return Ok(construct);
|
return Ok(Construct::from_skeleton(&skeleton));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn construct_spawn(tx: &mut Transaction, account: Uuid, name: String, team: bool) -> Result<Construct, Error> {
|
pub fn construct_spawn(tx: &mut Transaction, account: Uuid, name: String, team: bool) -> Result<Construct, Error> {
|
||||||
@ -878,7 +898,7 @@ pub fn construct_spawn(tx: &mut Transaction, account: Uuid, name: String, team:
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn construct_write(tx: &mut Transaction, construct: Construct) -> Result<Construct, Error> {
|
pub fn construct_write(tx: &mut Transaction, construct: Construct) -> Result<Construct, Error> {
|
||||||
let construct_bytes = to_vec(&construct)?;
|
let construct_bytes = to_vec(&construct.to_skeleton())?;
|
||||||
|
|
||||||
let query = "
|
let query = "
|
||||||
UPDATE constructs
|
UPDATE constructs
|
||||||
@ -897,20 +917,6 @@ pub fn construct_write(tx: &mut Transaction, construct: Construct) -> Result<Con
|
|||||||
return Ok(construct);
|
return Ok(construct);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn construct_recover(construct_bytes: Vec<u8>, tx: &mut Transaction) -> Result<Construct, Error> {
|
|
||||||
let c = from_slice::<ConstructRecover>(&construct_bytes)?;
|
|
||||||
|
|
||||||
let mut construct = Construct::new()
|
|
||||||
.named(&c.name)
|
|
||||||
.set_account(c.account);
|
|
||||||
|
|
||||||
construct.id = c.id;
|
|
||||||
|
|
||||||
info!("recovered construct {:?}", c.name);
|
|
||||||
|
|
||||||
return construct_write(tx, construct);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use construct::*;
|
use construct::*;
|
||||||
|
|||||||
@ -132,12 +132,12 @@ impl Events {
|
|||||||
},
|
},
|
||||||
|
|
||||||
Event::Subscribe(id, obj) => {
|
Event::Subscribe(id, obj) => {
|
||||||
info!("subscribe id={:?} object={:?}", id, obj);
|
trace!("subscribe id={:?} object={:?}", id, obj);
|
||||||
|
|
||||||
match self.clients.get_mut(&id) {
|
match self.clients.get_mut(&id) {
|
||||||
Some(client) => {
|
Some(client) => {
|
||||||
client.subs.insert(obj);
|
client.subs.insert(obj);
|
||||||
info!("client={:?} subscriptions={:?}", id, client.subs.len());
|
trace!("client={:?} subscriptions={:?}", id, client.subs.len());
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
None => return Err(format_err!("unknown client {:?}", id))
|
None => return Err(format_err!("unknown client {:?}", id))
|
||||||
@ -145,12 +145,12 @@ impl Events {
|
|||||||
},
|
},
|
||||||
|
|
||||||
Event::Unsubscribe(id, obj) => {
|
Event::Unsubscribe(id, obj) => {
|
||||||
info!("unsubscribe id={:?} object={:?}", id, obj);
|
trace!("unsubscribe id={:?} object={:?}", id, obj);
|
||||||
|
|
||||||
match self.clients.get_mut(&id) {
|
match self.clients.get_mut(&id) {
|
||||||
Some(mut client) => {
|
Some(mut client) => {
|
||||||
client.subs.remove(&obj);
|
client.subs.remove(&obj);
|
||||||
info!("unsubscribe subscriptions removed={:?}", client.subs.len());
|
trace!("unsubscribe subscriptions removed={:?}", client.subs.len());
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
None => return Err(format_err!("unknown client {:?}", id))
|
None => return Err(format_err!("unknown client {:?}", id))
|
||||||
@ -158,7 +158,7 @@ impl Events {
|
|||||||
},
|
},
|
||||||
|
|
||||||
Event::Push(id, msg) => {
|
Event::Push(id, msg) => {
|
||||||
info!("push id={:?}", id);
|
trace!("push id={:?}", id);
|
||||||
|
|
||||||
let mut subs = 0;
|
let mut subs = 0;
|
||||||
let mut dead = vec![];
|
let mut dead = vec![];
|
||||||
@ -177,11 +177,11 @@ impl Events {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !dead.is_empty() {
|
if !dead.is_empty() {
|
||||||
info!("dead connections={:?}", dead.len());
|
trace!("dead connections={:?}", dead.len());
|
||||||
dead.iter().for_each(|id| self.remove_client(*id));
|
dead.iter().for_each(|id| self.remove_client(*id));
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("push subscribers={:?}", subs);
|
trace!("push subscribers={:?}", subs);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1152,7 +1152,8 @@ mod tests {
|
|||||||
// should not be stunned because of counter
|
// should not be stunned because of counter
|
||||||
assert!(game.player_by_id(x_player.id).unwrap().constructs[0].is_stunned() == false);
|
assert!(game.player_by_id(x_player.id).unwrap().constructs[0].is_stunned() == false);
|
||||||
// riposte
|
// riposte
|
||||||
assert_eq!(game.player_by_id(y_player.id).unwrap().constructs[0].green_life(), (1024 - x_construct.red_power().pct(Skill::CounterAttack.multiplier())));
|
assert_eq!(game.player_by_id(y_player.id).unwrap().constructs[0].green_life(), (
|
||||||
|
y_construct.green_life() - x_construct.red_power().pct(Skill::CounterAttack.multiplier())));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1235,7 +1236,7 @@ mod tests {
|
|||||||
assert_eq!(target.id, y_construct.id);
|
assert_eq!(target.id, y_construct.id);
|
||||||
match event {
|
match event {
|
||||||
Event::Damage { amount, skill: _, mitigation: _, colour: _} =>
|
Event::Damage { amount, skill: _, mitigation: _, colour: _} =>
|
||||||
assert_eq!(amount, 256.pct(Skill::Attack.multiplier()) >> 1),
|
assert_eq!(amount, x_construct.red_power().pct(Skill::Attack.multiplier()) >> 1),
|
||||||
_ => panic!("not damage link"),
|
_ => panic!("not damage link"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,16 +53,15 @@ pub fn invader_write(id: Uuid) -> Result<Uuid, Error> {
|
|||||||
colours.push("none".to_string());
|
colours.push("none".to_string());
|
||||||
|
|
||||||
// add up to 100 for %
|
// add up to 100 for %
|
||||||
// [3] is the transparent colour
|
|
||||||
let weights = [
|
let weights = [
|
||||||
5,
|
5,
|
||||||
5,
|
5,
|
||||||
65,
|
65,
|
||||||
25,
|
25, // the transparent colour
|
||||||
];
|
];
|
||||||
let colour_dist = WeightedIndex::new(&weights)?;
|
let colour_dist = WeightedIndex::new(&weights)?;
|
||||||
|
|
||||||
write!(&mut svg, "<svg xmlns='http://www.w3.org/2000/svg' version='1.1' viewBox='-250 -250 1000 1000' width='500' height='500'><g>")?;
|
write!(&mut svg, "<svg xmlns='http://www.w3.org/2000/svg' version='1.1' viewBox='-250 -250 1000 1000' width='375' height='375'><g>")?;
|
||||||
for i in 0..50 {
|
for i in 0..50 {
|
||||||
let x = (i % 5) * 50;
|
let x = (i % 5) * 50;
|
||||||
let y = (i / 5) * 50;
|
let y = (i / 5) * 50;
|
||||||
|
|||||||
@ -76,7 +76,7 @@ impl TimeControl {
|
|||||||
|
|
||||||
pub fn lobby_timeout(&self) -> DateTime<Utc> {
|
pub fn lobby_timeout(&self) -> DateTime<Utc> {
|
||||||
Utc::now()
|
Utc::now()
|
||||||
.checked_add_signed(Duration::minutes(5))
|
.checked_add_signed(Duration::seconds(30))
|
||||||
.expect("could not set phase end")
|
.expect("could not set phase end")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,7 +366,7 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn current_game_id(&self) -> Option<Uuid> {
|
fn current_game_id(&self) -> Option<Uuid> {
|
||||||
if self.phase == InstancePhase::Lobby {
|
if self.phase != InstancePhase::InProgress {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -497,152 +497,235 @@ pub enum Skill {
|
|||||||
// Evade, // actively evade
|
// Evade, // actively evade
|
||||||
// Nightmare,
|
// Nightmare,
|
||||||
// Sleep,
|
// Sleep,
|
||||||
|
|
||||||
Amplify,
|
Amplify,
|
||||||
|
#[serde(rename = "Amplify+")]
|
||||||
AmplifyPlus,
|
AmplifyPlus,
|
||||||
|
#[serde(rename = "Amplify++")]
|
||||||
AmplifyPlusPlus,
|
AmplifyPlusPlus,
|
||||||
|
|
||||||
|
Absorb,
|
||||||
|
#[serde(rename = "Absorb+")]
|
||||||
|
AbsorbPlus,
|
||||||
|
#[serde(rename = "Absorb++")]
|
||||||
|
AbsorbPlusPlus,
|
||||||
|
|
||||||
Banish,
|
Banish,
|
||||||
|
#[serde(rename = "Banish+")]
|
||||||
BanishPlus,
|
BanishPlus,
|
||||||
|
#[serde(rename = "Banish++")]
|
||||||
BanishPlusPlus,
|
BanishPlusPlus,
|
||||||
|
|
||||||
Bash,
|
Bash,
|
||||||
|
#[serde(rename = "Bash+")]
|
||||||
BashPlus,
|
BashPlus,
|
||||||
|
#[serde(rename = "Bash++")]
|
||||||
BashPlusPlus,
|
BashPlusPlus,
|
||||||
|
|
||||||
Blast,
|
Blast,
|
||||||
|
#[serde(rename = "Blast+")]
|
||||||
BlastPlus,
|
BlastPlus,
|
||||||
|
#[serde(rename = "Blast++")]
|
||||||
BlastPlusPlus,
|
BlastPlusPlus,
|
||||||
|
|
||||||
Chaos,
|
Chaos,
|
||||||
|
#[serde(rename = "Chaos+")]
|
||||||
ChaosPlus,
|
ChaosPlus,
|
||||||
|
#[serde(rename = "Chaos++")]
|
||||||
ChaosPlusPlus,
|
ChaosPlusPlus,
|
||||||
|
|
||||||
Sustain,
|
Sustain,
|
||||||
|
#[serde(rename = "Sustain+")]
|
||||||
SustainPlus,
|
SustainPlus,
|
||||||
|
#[serde(rename = "Sustain++")]
|
||||||
SustainPlusPlus,
|
SustainPlusPlus,
|
||||||
|
|
||||||
Electrify,
|
Electrify,
|
||||||
|
#[serde(rename = "Electrify+")]
|
||||||
ElectrifyPlus,
|
ElectrifyPlus,
|
||||||
|
#[serde(rename = "Electrify++")]
|
||||||
ElectrifyPlusPlus,
|
ElectrifyPlusPlus,
|
||||||
Electrocute,
|
|
||||||
ElectrocutePlus,
|
|
||||||
ElectrocutePlusPlus,
|
|
||||||
ElectrocuteTick,
|
|
||||||
ElectrocuteTickPlus,
|
|
||||||
ElectrocuteTickPlusPlus,
|
|
||||||
|
|
||||||
Curse,
|
Curse,
|
||||||
|
#[serde(rename = "Curse+")]
|
||||||
CursePlus,
|
CursePlus,
|
||||||
|
#[serde(rename = "Curse++")]
|
||||||
CursePlusPlus,
|
CursePlusPlus,
|
||||||
|
|
||||||
Decay, // dot
|
Decay,
|
||||||
|
#[serde(rename = "Decay+")]
|
||||||
DecayPlus,
|
DecayPlus,
|
||||||
|
#[serde(rename = "Decay++")]
|
||||||
DecayPlusPlus,
|
DecayPlusPlus,
|
||||||
DecayTick, // dot
|
|
||||||
DecayTickPlus,
|
|
||||||
DecayTickPlusPlus,
|
|
||||||
|
|
||||||
Haste,
|
|
||||||
HastePlus,
|
|
||||||
HastePlusPlus,
|
|
||||||
HasteStrike,
|
|
||||||
|
|
||||||
Heal,
|
|
||||||
HealPlus,
|
|
||||||
HealPlusPlus,
|
|
||||||
|
|
||||||
Hex,
|
Hex,
|
||||||
|
#[serde(rename = "Hex+")]
|
||||||
HexPlus,
|
HexPlus,
|
||||||
|
#[serde(rename = "Hex++")]
|
||||||
HexPlusPlus,
|
HexPlusPlus,
|
||||||
|
|
||||||
Absorption,
|
Haste,
|
||||||
AbsorptionPlus,
|
#[serde(rename = "Haste+")]
|
||||||
AbsorptionPlusPlus,
|
HastePlus,
|
||||||
Absorb,
|
#[serde(rename = "Haste++")]
|
||||||
AbsorbPlus,
|
HastePlusPlus,
|
||||||
AbsorbPlusPlus,
|
|
||||||
HybridBlast,
|
Heal,
|
||||||
|
#[serde(rename = "Heal+")]
|
||||||
|
HealPlus,
|
||||||
|
#[serde(rename = "Heal++")]
|
||||||
|
HealPlusPlus,
|
||||||
|
|
||||||
Hybrid,
|
Hybrid,
|
||||||
|
#[serde(rename = "Hybrid+")]
|
||||||
HybridPlus,
|
HybridPlus,
|
||||||
|
#[serde(rename = "Hybrid++")]
|
||||||
HybridPlusPlus,
|
HybridPlusPlus,
|
||||||
|
|
||||||
Invert,
|
Invert,
|
||||||
|
#[serde(rename = "Invert+")]
|
||||||
InvertPlus,
|
InvertPlus,
|
||||||
|
#[serde(rename = "Invert++")]
|
||||||
InvertPlusPlus,
|
InvertPlusPlus,
|
||||||
|
|
||||||
Counter, // avoid all damage
|
Counter,
|
||||||
|
#[serde(rename = "Counter+")]
|
||||||
CounterPlus,
|
CounterPlus,
|
||||||
|
#[serde(rename = "Counter++")]
|
||||||
CounterPlusPlus,
|
CounterPlusPlus,
|
||||||
|
|
||||||
Purge,
|
Purge,
|
||||||
|
#[serde(rename = "Purge+")]
|
||||||
PurgePlus,
|
PurgePlus,
|
||||||
|
#[serde(rename = "Purge++")]
|
||||||
PurgePlusPlus,
|
PurgePlusPlus,
|
||||||
|
|
||||||
Purify,
|
Purify,
|
||||||
|
#[serde(rename = "Purify+")]
|
||||||
PurifyPlus,
|
PurifyPlus,
|
||||||
|
#[serde(rename = "Purify++")]
|
||||||
PurifyPlusPlus,
|
PurifyPlusPlus,
|
||||||
|
|
||||||
Recharge,
|
|
||||||
RechargePlus,
|
|
||||||
RechargePlusPlus,
|
|
||||||
|
|
||||||
Reflect,
|
Reflect,
|
||||||
|
#[serde(rename = "Reflect+")]
|
||||||
ReflectPlus,
|
ReflectPlus,
|
||||||
|
#[serde(rename = "Reflect++")]
|
||||||
ReflectPlusPlus,
|
ReflectPlusPlus,
|
||||||
|
|
||||||
CounterAttack,
|
Recharge,
|
||||||
CounterAttackPlus,
|
#[serde(rename = "Recharge+")]
|
||||||
CounterAttackPlusPlus,
|
RechargePlus,
|
||||||
|
#[serde(rename = "Recharge++")]
|
||||||
|
RechargePlusPlus,
|
||||||
|
|
||||||
Ruin,
|
Ruin,
|
||||||
|
#[serde(rename = "Ruin+")]
|
||||||
RuinPlus,
|
RuinPlus,
|
||||||
|
#[serde(rename = "Ruin++")]
|
||||||
RuinPlusPlus,
|
RuinPlusPlus,
|
||||||
|
|
||||||
Link,
|
Link,
|
||||||
|
#[serde(rename = "Link+")]
|
||||||
LinkPlus,
|
LinkPlus,
|
||||||
|
#[serde(rename = "Link++")]
|
||||||
LinkPlusPlus,
|
LinkPlusPlus,
|
||||||
|
|
||||||
Silence,
|
Silence,
|
||||||
|
#[serde(rename = "Silence+")]
|
||||||
SilencePlus,
|
SilencePlus,
|
||||||
|
#[serde(rename = "Silence++")]
|
||||||
SilencePlusPlus,
|
SilencePlusPlus,
|
||||||
|
|
||||||
Siphon,
|
|
||||||
SiphonPlus,
|
|
||||||
SiphonPlusPlus,
|
|
||||||
SiphonTick,
|
|
||||||
SiphonTickPlus,
|
|
||||||
SiphonTickPlusPlus,
|
|
||||||
|
|
||||||
Slay,
|
Slay,
|
||||||
|
#[serde(rename = "Slay+")]
|
||||||
SlayPlus,
|
SlayPlus,
|
||||||
|
#[serde(rename = "Slay++")]
|
||||||
SlayPlusPlus,
|
SlayPlusPlus,
|
||||||
|
|
||||||
Sleep,
|
Sleep,
|
||||||
|
#[serde(rename = "Sleep+")]
|
||||||
SleepPlus,
|
SleepPlus,
|
||||||
|
#[serde(rename = "Sleep++")]
|
||||||
SleepPlusPlus,
|
SleepPlusPlus,
|
||||||
|
|
||||||
Restrict,
|
Restrict,
|
||||||
|
#[serde(rename = "Restrict+")]
|
||||||
RestrictPlus,
|
RestrictPlus,
|
||||||
|
#[serde(rename = "Restrict++")]
|
||||||
RestrictPlusPlus,
|
RestrictPlusPlus,
|
||||||
|
|
||||||
Strike,
|
Strike,
|
||||||
|
#[serde(rename = "Strike+")]
|
||||||
StrikePlus,
|
StrikePlus,
|
||||||
|
#[serde(rename = "Strike++")]
|
||||||
StrikePlusPlus,
|
StrikePlusPlus,
|
||||||
|
|
||||||
|
Siphon,
|
||||||
|
#[serde(rename = "Siphon+")]
|
||||||
|
SiphonPlus,
|
||||||
|
#[serde(rename = "Siphon++")]
|
||||||
|
SiphonPlusPlus,
|
||||||
|
|
||||||
Intercept,
|
Intercept,
|
||||||
|
#[serde(rename = "Intercept+")]
|
||||||
InterceptPlus,
|
InterceptPlus,
|
||||||
|
#[serde(rename = "Intercept++")]
|
||||||
InterceptPlusPlus,
|
InterceptPlusPlus,
|
||||||
|
|
||||||
Break, // no damage stun, adds vulnerable
|
Break,
|
||||||
|
#[serde(rename = "Break+")]
|
||||||
BreakPlus,
|
BreakPlus,
|
||||||
|
#[serde(rename = "Break++")]
|
||||||
BreakPlusPlus,
|
BreakPlusPlus,
|
||||||
|
|
||||||
Triage, // hot
|
Triage,
|
||||||
|
#[serde(rename = "Triage+")]
|
||||||
TriagePlus,
|
TriagePlus,
|
||||||
|
#[serde(rename = "Triage++")]
|
||||||
TriagePlusPlus,
|
TriagePlusPlus,
|
||||||
|
|
||||||
|
Absorption,
|
||||||
|
#[serde(rename = "Absorption+")]
|
||||||
|
AbsorptionPlus,
|
||||||
|
#[serde(rename = "Absorption++")]
|
||||||
|
AbsorptionPlusPlus,
|
||||||
|
|
||||||
|
CounterAttack,
|
||||||
|
#[serde(rename = "CounterAttack+")]
|
||||||
|
CounterAttackPlus,
|
||||||
|
#[serde(rename = "CounterAttack++")]
|
||||||
|
CounterAttackPlusPlus,
|
||||||
|
|
||||||
|
Electrocute,
|
||||||
|
#[serde(rename = "Electrocute+")]
|
||||||
|
ElectrocutePlus,
|
||||||
|
#[serde(rename = "Electrocute++")]
|
||||||
|
ElectrocutePlusPlus,
|
||||||
|
ElectrocuteTick,
|
||||||
|
#[serde(rename = "ElectrocuteTick+")]
|
||||||
|
ElectrocuteTickPlus,
|
||||||
|
#[serde(rename = "ElectrocuteTick++")]
|
||||||
|
ElectrocuteTickPlusPlus,
|
||||||
|
|
||||||
|
DecayTick, // dot
|
||||||
|
#[serde(rename = "DecayTick+")]
|
||||||
|
DecayTickPlus,
|
||||||
|
#[serde(rename = "DecayTick++")]
|
||||||
|
DecayTickPlusPlus,
|
||||||
|
|
||||||
|
HasteStrike,
|
||||||
|
HybridBlast,
|
||||||
|
|
||||||
|
SiphonTick,
|
||||||
|
#[serde(rename = "SiphonTick+")]
|
||||||
|
SiphonTickPlus,
|
||||||
|
#[serde(rename = "SiphonTick++")]
|
||||||
|
SiphonTickPlusPlus,
|
||||||
|
|
||||||
TriageTick,
|
TriageTick,
|
||||||
|
#[serde(rename = "TriageTick+")]
|
||||||
TriageTickPlus,
|
TriageTickPlus,
|
||||||
|
#[serde(rename = "TriageTick++")]
|
||||||
TriageTickPlusPlus,
|
TriageTickPlusPlus,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1675,13 +1758,14 @@ fn purge(source: &mut Construct, target: &mut Construct, mut results: Resolution
|
|||||||
.event(Event::Removal { effect: ce.effect, construct_effects: target.effects.clone() }));
|
.event(Event::Removal { effect: ce.effect, construct_effects: target.effects.clone() }));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut turns = 0;
|
let mut turns = 1;
|
||||||
for cs in target.skills.iter_mut() {
|
for cs in target.skills.iter_mut() {
|
||||||
if Effect::Purge.disables_skill(cs.skill) {
|
if Effect::Purge.disables_skill(cs.skill) {
|
||||||
turns += 1;
|
turns += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if turns > 0 {
|
|
||||||
|
if turns > 1 {
|
||||||
let mut effect = skill.effect()[0];
|
let mut effect = skill.effect()[0];
|
||||||
effect.duration = effect.duration * turns;
|
effect.duration = effect.duration * turns;
|
||||||
results.push(Resolution::new(source, target).event(target.add_effect(skill, effect)).stages(EventStages::PostOnly));
|
results.push(Resolution::new(source, target).event(target.add_effect(skill, effect)).stages(EventStages::PostOnly));
|
||||||
@ -1789,6 +1873,7 @@ mod tests {
|
|||||||
.named(&"camel".to_string());
|
.named(&"camel".to_string());
|
||||||
|
|
||||||
x.red_power.force(10000000000000); // multiplication of int max will cause overflow
|
x.red_power.force(10000000000000); // multiplication of int max will cause overflow
|
||||||
|
y.green_life.force(1024); // make tests more flexible if we change stats
|
||||||
|
|
||||||
sustain(&mut y.clone(), &mut y, vec![], Skill::Sustain);
|
sustain(&mut y.clone(), &mut y, vec![], Skill::Sustain);
|
||||||
assert!(y.affected(Effect::Sustain));
|
assert!(y.affected(Effect::Sustain));
|
||||||
@ -1885,6 +1970,8 @@ mod tests {
|
|||||||
let mut y = Construct::new()
|
let mut y = Construct::new()
|
||||||
.named(&"camel".to_string());
|
.named(&"camel".to_string());
|
||||||
|
|
||||||
|
x.blue_power.force(256);
|
||||||
|
x.green_life.force(1024);
|
||||||
x.green_life.reduce(512);
|
x.green_life.reduce(512);
|
||||||
|
|
||||||
let mut results = resolve(Skill::Siphon, &mut x, &mut y, vec![]);
|
let mut results = resolve(Skill::Siphon, &mut x, &mut y, vec![]);
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use construct::{Stat, Colours};
|
use construct::{Stat, Colours};
|
||||||
use util::{IntPct};
|
use util::{IntPct};
|
||||||
use std::cmp;
|
|
||||||
|
|
||||||
#[derive(Debug,Clone,Serialize,Deserialize)]
|
#[derive(Debug,Clone,Serialize,Deserialize)]
|
||||||
pub struct SpecBonus {
|
pub struct SpecBonus {
|
||||||
@ -29,9 +28,11 @@ impl SpecValues {
|
|||||||
self.bonuses.iter().fold(self.base, |acc, s| acc + s.get_bonus(c))
|
self.bonuses.iter().fold(self.base, |acc, s| acc + s.get_bonus(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
pub fn calc_multi (&self, c: &Colours) -> u64 {
|
pub fn calc_multi (&self, c: &Colours) -> u64 {
|
||||||
self.multi * (c.red + c.green + c.blue) as u64
|
self.multi * (c.red + c.green + c.blue) as u64
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -711,10 +712,8 @@ impl Spec {
|
|||||||
Spec::SpeedBBPlusPlus |
|
Spec::SpeedBBPlusPlus |
|
||||||
Spec::SpeedRGPlusPlus |
|
Spec::SpeedRGPlusPlus |
|
||||||
Spec::SpeedGBPlusPlus |
|
Spec::SpeedGBPlusPlus |
|
||||||
Spec::SpeedRBPlusPlus => modified + {
|
Spec::SpeedRBPlusPlus => modified + base.pct(self.values().max_value(player_colours)),
|
||||||
base.pct(cmp::min(self.values().calc_multi(construct_colours),
|
|
||||||
self.values().max_value(player_colours)))
|
|
||||||
},
|
|
||||||
// Flat bonus
|
// Flat bonus
|
||||||
Spec::Life => modified + self.values().base,
|
Spec::Life => modified + self.values().base,
|
||||||
Spec::LifeRR|
|
Spec::LifeRR|
|
||||||
@ -734,10 +733,7 @@ impl Spec {
|
|||||||
Spec::LifeBBPlusPlus |
|
Spec::LifeBBPlusPlus |
|
||||||
Spec::LifeRGPlusPlus |
|
Spec::LifeRGPlusPlus |
|
||||||
Spec::LifeGBPlusPlus |
|
Spec::LifeGBPlusPlus |
|
||||||
Spec::LifeRBPlusPlus => modified + {
|
Spec::LifeRBPlusPlus => modified + self.values().max_value(player_colours),
|
||||||
cmp::min(self.values().calc_multi(construct_colours),
|
|
||||||
self.values().max_value(player_colours))
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user