This commit is contained in:
ntr 2019-09-06 12:13:54 +10:00
parent 60d9ea5198
commit 7af81c5252
23 changed files with 265 additions and 128 deletions

View File

@ -11,9 +11,6 @@
* constructs jiggle when clicked * constructs jiggle when clicked
* background colour changes depending on time of day * background colour changes depending on time of day
* bug fixes
* pvp 1st round doesn't resolve until warden timer completes
* bot game grind * bot game grind
* stress test * stress test

View File

@ -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;

View File

@ -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 {

View File

@ -1,7 +1,7 @@
@import 'colours.less'; @import 'colours.less';
.instance { .instance {
overflow-x: hidden; overflow: hidden;
display: grid; display: grid;
grid-template-columns: 1fr minmax(min-content, 1fr); grid-template-columns: 1fr minmax(min-content, 1fr);
grid-template-rows: min-content 1fr; grid-template-rows: min-content 1fr;

View File

@ -4,17 +4,16 @@
height: 100%; height: 100%;
display: grid; display: grid;
grid-template-rows: minmax(min-content, 2fr) min-content 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"
"tabs"
"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;
} }
@ -25,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;
@ -62,8 +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;
@ -89,16 +91,19 @@
} }
.options { .options {
grid-area: tabs; grid-area: hdr;
display: flex;
flex-flow: row;
button { button {
width: 25%;
border-top: 0; border-top: 0;
border: 1px solid #222; border: 1px solid #222;
&:not(:last-child) { &:not(:last-child) {
border-right: 0; border-right: 0;
} }
flex: 1;
&:last-child {
float: right;
}
} }
} }
} }

View File

@ -84,16 +84,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"
"main main ctrl" "main ctrl"
"main main ctrl"; "main ctrl";
padding: 0.5em 1em;
} }
main { main {
padding: 1em;
grid-area: main; grid-area: main;
} }
@ -253,10 +254,17 @@ figure.gray {
display: none; display: none;
} }
.options { header {
display: flex; .options {
flex-flow: row; font-size: 150%;
}
button {
height: 2em;
}
}
.options {
button { button {
&.highlight { &.highlight {
color: @white; color: @white;
@ -279,4 +287,4 @@ figure.gray {
nav { nav {
display: none; display: none;
} }

View File

@ -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>
); );

View File

@ -2,6 +2,7 @@ const { connect } = require('preact-redux');
const preact = require('preact'); const preact = require('preact');
const Team = require('./team'); const Team = require('./team');
const Header = require('./header');
const AccountManagement = require('./account.management'); const AccountManagement = require('./account.management');
const addState = connect( const addState = connect(
@ -24,6 +25,7 @@ function Account(args) {
return ( return (
<main class="menu"> <main class="menu">
<Header />
<Team /> <Team />
<AccountManagement /> <AccountManagement />
</main> </main>

View File

@ -125,9 +125,11 @@ function Controls(args) {
return ( return (
<aside class="controls"> <aside class="controls">
{timer} {timer}
{scoreboard(game, opponent, true)} <div class="controls">
{game.phase === 'Finish' ? quitBtn : readyBtn} {scoreboard(game, opponent, true)}
{scoreboard(game, player)} {game.phase === 'Finish' ? quitBtn : readyBtn}
{scoreboard(game, player)}
</div>
</aside> </aside>
); );
} }

View File

@ -1,40 +1,121 @@
// 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'); const AccountStatus = require('./account.status');
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,
instances,
team,
nav,
ping,
game,
} = state;
function sendInstanceState(instance) {
return ws.sendInstanceState(instance.id);
}
function sendAccountStates() {
ws.sendEmailState();
ws.sendSubscriptionState();
}
return {
account,
instances,
team,
game,
ping,
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));
}
function hideNav() {
return dispatch(actions.setShowNav(false));
}
return {
setNav,
hideNav,
};
}
); );
function renderHeader(args) { function Nav(args) {
const { account, ping } = args; const {
account,
game,
team,
nav,
const accountStatus = account sendAccountStates,
? (<div class="header-status"> sendInstanceState,
<h1 class="header-username">{account.name}</h1>
{saw(pingColour(ping))} setNav,
<div class="ping-text">{ping}ms</div> hideNav,
</div>) } = args;
: '';
if (!account) return false;
function navTo(p) {
return setNav(p);
}
function joinInstance(i) {
sendInstanceState(i);
if (game) navTo('transition');
return true;
}
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('news')}
class={`login-btn ${nav === 'news' ? 'highlight' : ''}`}>
Shop
</button>
<button
onClick={accountClick}
class={`login-btn ${nav === 'account' ? 'highlight' : ''}`}>
{account.name}
</button>
</div>
</header> </header>
); );
} }
module.exports = addState(Nav);
module.exports = addState(renderHeader);

View File

@ -18,7 +18,19 @@ 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 />
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;

View File

@ -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;

View File

@ -93,11 +93,13 @@ function Controls(args) {
); );
return ( return (
<aside class="controls"> <aside>
{timer} {timer}
{scoreboard(instance, opponent, true)} <div class="controls">
<button class="ready" onClick={() => sendReady()}>Ready</button> {scoreboard(instance, opponent, true)}
{scoreboard(instance, player)} <button class="ready" onClick={() => sendReady()}>Ready</button>
{scoreboard(instance, player)}
</div>
</aside> </aside>
); );
} }

View File

@ -7,6 +7,8 @@ const toast = require('izitoast');
const actions = require('./../actions'); const actions = require('./../actions');
const StripeBtns = require('./stripe.buttons'); const StripeBtns = require('./stripe.buttons');
const VERSION = process.env.npm_package_version;
const addState = connect( const addState = connect(
function receiveState(state) { function receiveState(state) {
const { const {
@ -64,21 +66,32 @@ function Inventory(args) {
); );
return ( return (
<div class="inventory"> <div class="inventory top">
<div class="news">
<h1>v{VERSION}</h1>
<h2>welcome to mnml</h2>
<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> <div>
<h1>Shop</h1> <h1 class="credits">¤ {account.balance}</h1>
<Elements> <Elements>
<StripeBtns account={account} /> <StripeBtns account={account} />
</Elements> </Elements>
<div class='list'>
{shop.available.map(availableMtx)}
</div>
</div>
<div>
<h1 class="credits">¤ {account.balance}</h1>
<div class='list'> <div class='list'>
{shop.owned.map(useMtx)} {shop.owned.map(useMtx)}
</div> </div>
<div class='list'>
{shop.available.map(availableMtx)}
</div>
</div> </div>
</div> </div>
); );

View File

@ -38,7 +38,7 @@ function Main(props) {
if (nav === 'transition') return false; if (nav === 'transition') return false;
if (nav === 'play') return <Play />; if (nav === 'play') return <Play />;
if (nav === 'team') return <Team />; // if (nav === 'team') return <Team />;
if (nav === 'account') return <Account />; if (nav === 'account') return <Account />;
return ( return (

View File

@ -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');

View File

@ -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>

View File

@ -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,25 +32,46 @@ const addState = connect(
function JoinButtons(args) { function JoinButtons(args) {
const { const {
instances,
sendInstanceState,
sendInstanceQueue, sendInstanceQueue,
sendInstancePractice, sendInstancePractice,
} = args; } = args;
if (instances.length) {
return (
<aside class='play-ctrl'>
<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 ( return (
<aside class='play-ctrl'> <aside class='play-ctrl'>
<div class="timer-container"></div> <div class="timer-container"></div>
<button <div class="controls">
class='pvp ready' <button
onClick={() => sendInstanceQueue()} class='pvp ready'
type="submit"> onClick={() => sendInstanceQueue()}
PVP type="submit">
</button> PVP
<button </button>
class='practice ready' <button
onClick={() => sendInstancePractice()} class='practice ready'
type="submit"> onClick={() => sendInstancePractice()}
Practice type="submit">
</button> Learn
</button>
</div>
</aside> </aside>
); );
} }

View File

@ -5,6 +5,7 @@ const { stringSort } = require('./../utils');
const { ConstructAvatar } = require('./construct'); const { ConstructAvatar } = require('./construct');
const actions = require('./../actions'); const actions = require('./../actions');
const Inventory = require('./inventory'); const Inventory = require('./inventory');
const Header = require('./header');
const idSort = stringSort('id'); const idSort = stringSort('id');
@ -108,28 +109,11 @@ function Play(args) {
return ( return (
<main class="menu"> <main class="menu">
<div class="team top"> <Header />
<Inventory />
<div class="team">
{constructPanels} {constructPanels}
</div> </div>
<div class="options">
<button
class={`login-btn highlight`}>
Play
</button>
<button
class={`login-btn`}>
News
</button>
<button
class={`login-btn`}>
Store
</button>
<button
class={`login-btn`}>
Account
</button>
</div>
<Inventory />
</main> </main>
); );
} }

View File

@ -42,7 +42,7 @@ module.exports = {
None: () => None: () =>
<figure> <figure>
{diamond(['gray'])} {diamond(['gray'])}
<figcaption>&nbsp;</figcaption> <figcaption>SPEC</figcaption>
</figure>, </figure>,

View File

@ -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}> &laquo; </button> <button onClick={() => setTeamPage(teamPage - 1)} disabled={disableDecrement}> &laquo; </button>

View File

@ -58,7 +58,7 @@ function Team(args) {
} }
console.log(constructs.length); console.log(constructs.length);
const dispConstructs = constructs.length >= ((teamPage + 1) * 6) const dispConstructs = constructs.length >= ((teamPage + 1) * 6)
? constructs.slice(teamPage * 6, (teamPage + 1) * 6) ? constructs.slice(teamPage * 6, (teamPage + 1) * 6)
: constructs.slice(teamPage * 6, constructs.length); : constructs.slice(teamPage * 6, constructs.length);
const constructPanels = dispConstructs.map(construct => { const constructPanels = dispConstructs.map(construct => {
@ -80,7 +80,7 @@ function Team(args) {
}); });
return ( return (
<section class="team top"> <section class="team">
{constructPanels} {constructPanels}
</section> </section>
); );

View File

@ -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;