Merge tag '1.5.4' into develop

1.5.4
This commit is contained in:
ntr 2019-10-10 18:33:49 +11:00
commit 349c74c08e
21 changed files with 1247 additions and 101 deletions

View File

@ -10,7 +10,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [0.1.5] - YYYY-MM-DD ## [0.1.5] - YYYY-MM-DD
### Changed ### Changed
`Recharge` Skill multiplier reduced 85/130/200 -> 70/110/170 `Recharge` Skill multiplier reduced 85/130/200 -> 70/110/170
`Absorbption` Skill duration reduced 5/7/9 -> 3/5/7 `Absorption` Skill duration reduced 5/7/9 -> 3/5/7
## [0.1.4 2019-09-18] ## [0.1.4 2019-09-18]

View File

@ -1 +1 @@
1.5.3 1.5.4

View File

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

View File

@ -13,6 +13,8 @@ rm -rf dist
npm i npm i
npm run build npm run build
cp tos.html dist/
# echo "Building acp version $VERSION" # echo "Building acp version $VERSION"
# cd $MNML_PATH/acp # cd $MNML_PATH/acp
# rm -rf dist # rm -rf dist

View File

@ -50,19 +50,31 @@ aside {
} }
} }
button.ready:enabled { // button.ready:enabled {
&:hover { // &:hover {
color: forestgreen; // color: forestgreen;
border-color: forestgreen; // border-color: forestgreen;
} // }
&:active, &:focus, &.enabled { // &:active, &:focus, &.enabled {
// background: forestgreen;
// color: black;
// border-color: forestgreen;
// }
// }
button.ready:enabled {
color: forestgreen;
border-color: forestgreen;
&:hover {
background: forestgreen; background: forestgreen;
color: black; color: black;
border-color: forestgreen; border-color: forestgreen;
} }
} }
.timer-container { .timer-container {
grid-area: timer; grid-area: timer;
@ -94,6 +106,7 @@ aside {
.ready { .ready {
color: forestgreen; color: forestgreen;
// animation: ready 2s linear 0s infinite alternate;
transition-property: color, background; transition-property: color, background;
transition-duration: 0.25s; transition-duration: 0.25s;
transition-timing-function: ease; transition-timing-function: ease;
@ -138,3 +151,13 @@ aside {
border: 2px solid black; border: 2px solid black;
} }
} }
@keyframes ready {
from {
border-color: @gray-exists;
}
to {
border-color: forestgreen;
}
}

View File

@ -129,13 +129,30 @@ section {
.demo { .demo {
margin-top: 1em; margin-top: 1em;
display: grid; display: block;
grid-template-areas:
"vinfo game"
"vcons game";
grid-template-columns: 1fr 1fr; button {
grid-template-rows: min-content 1fr; pointer-events: none;
}
section {
margin-bottom: 0.5em;
div:first-child {
padding-right: 1em;
}
}
.construct-section {
.construct-list {
height: 25em;
grid-area: unset;
.instance-construct {
// border: 0;
}
}
}
.colour-info { .colour-info {
grid-area: vinfo; grid-area: vinfo;
@ -152,17 +169,9 @@ section {
} }
} }
.vbox-demo {
grid-area: vinfo;
}
.game-demo { .game-demo {
grid-area: game;
display: grid;
grid-template-columns: 1fr 2fr;
.game { .game {
height: 25em;
display: flex; display: flex;
flex-flow: column; flex-flow: column;
@ -171,15 +180,6 @@ section {
} }
} }
} }
.construct-list {
grid-area: vcons;
height: 100%;
svg {
height: 100%;
}
}
} }
@media (max-width: 800px) { @media (max-width: 800px) {
@ -191,24 +191,6 @@ section {
} }
} }
.demo {
grid-template-columns: 1fr;
grid-template-areas:
"vinfo"
"vcons"
"game"
"game";
.construct-list .instance-construct:not(:first-child) {
display: none;
}
.game-demo {
grid-template-columns: 1fr;
}
}
.menu .team { .menu .team {
grid-template-columns: 1fr; grid-template-columns: 1fr;

View File

@ -14,7 +14,7 @@ html body {
-ms-user-select: none; -ms-user-select: none;
overflow-x: hidden; overflow-x: hidden;
overflow-y: hidden; // overflow-y: hidden;
} }
#mnml { #mnml {
@ -26,14 +26,14 @@ html body {
/* stops inspector going skitz*/ /* stops inspector going skitz*/
overflow-x: hidden; overflow-x: hidden;
overflow-y: hidden; // overflow-y: hidden;
} }
@media (min-width: 1921px) { // @media (min-width: 1921px) {
html, body, #mnml { // html, body, #mnml {
font-size: 16pt; // font-size: 16pt;
} // }
} // }
html { html {
box-sizing: border-box; box-sizing: border-box;
@ -162,13 +162,12 @@ svg {
fill: none; fill: none;
stroke: whitesmoke; stroke: whitesmoke;
stroke-width: 0.5em; stroke-width: 0.5em;
height: 2em; height: 1.5em;
} }
table { table {
table-layout: fixed; table-layout: fixed;
width: 100%; width: 100%;
/*margin-bottom: 2em;*/
margin-bottom: 0; margin-bottom: 0;
} }

View File

@ -123,4 +123,8 @@
padding: 0; padding: 0;
} }
} }
.play-p {
display: none;
}
} }

View File

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

View File

@ -84,7 +84,7 @@ function Demo(args) {
function inventoryElement() { function inventoryElement() {
return ( return (
<div class="vbox"> <div class="vbox visible">
<div class='vbox-section'> <div class='vbox-section'>
<h2 class='colour-info'> <h2 class='colour-info'>
VBOX PHASE {shapes.Red()} {shapes.Green()} {shapes.Blue()} VBOX PHASE {shapes.Red()} {shapes.Green()} {shapes.Blue()}
@ -116,39 +116,48 @@ function Demo(args) {
? 'equipping empty gray' ? 'equipping empty gray'
: 'empty gray'; : 'empty gray';
return ( const constructEl = c => (
<div class='news construct-list'> <div class="instance-construct visible">
{players[0].constructs.map((c, i) => ( <h2 class="name" >{c.name}</h2>
<div class="instance-construct" key={i}> <ConstructAvatar construct={c} />
<h2 class="name" >{c.name}</h2> <div class="skills">
<ConstructAvatar construct={c} /> {equipped
<div class="skills"> ? <button>Strike</button>
{i === 0 && equipped : <button disabled={!equipping} class={btnClass}>SKILL</button>
? <button>Strike</button> }
: <button disabled={!equipping} class={btnClass}>SKILL</button> <button disabled={!equipping} class={btnClass}>SKILL</button>
} <button disabled={!equipping} class={btnClass}>SKILL</button>
<button disabled={!equipping} class={btnClass}>SKILL</button> </div>
<button disabled={!equipping} class={btnClass}>SKILL</button> <div class="specs">
</div> </div>
<div class="specs"> <div class="stats">
</div> </div>
<div class="stats">
</div>
</div>
))}
</div> </div>
); );
return (
<section class="construct-section">
<div>
<h2>CONSTRUCTS</h2>
<p><b>Constructs</b> are the units you control. They are reset every game and their initial appearance is randomly generated.</p>
<p><b>Skills</b> and <b>Specs</b> you create in the <b>VBOX Phase</b> are equipped to your constructs to create a build.</p>
</div>
<div class='construct-list'>
{constructEl(players[0].constructs[0])}
</div>
</section>
);
}; };
const gameDemo = () => { const gameDemo = () => {
return ( return (
<div class="game-demo"> <section class="game-demo">
<div> <div>
<h2>COMBAT PHASE</h2> <h2>COMBAT PHASE</h2>
<p>Battle your opponent using dynamic team builds from the VBOX phase.</p> <p>Battle your opponent using dynamic team builds from the VBOX phase.</p>
<p>Crafted skills can be used to damage the opponent or support your team.</p> <p>The skills crafted can be used to damage the opponent or support your team.</p>
<p>Turn based combat, each team picks targets for their skills during this phase.</p> <p>Simultaneous turn based combat: each team picks targets for their skills during this phase.</p>
<p>The damage dealt by skills, cast order and construct life depend on your decisions in the VBOX phase. </p> <p>The damage dealt by skills, cast order and construct life depend on your decisions in the VBOX phase.</p>
</div> </div>
<div class="game"> <div class="game">
<div class="game-construct"> <div class="game-construct">
@ -165,7 +174,7 @@ function Demo(args) {
</div> </div>
</div> </div>
</div> </div>
</div> </section>
); );
}; };

View File

@ -93,12 +93,12 @@ class GameConstruct extends Component {
const skills = range(0, 3) const skills = range(0, 3)
.map(j => <SkillBtn key={j} construct={construct} i={j} j={i} animating={animating} />); .map(j => <SkillBtn key={j} construct={construct} i={j} j={i} animating={animating} />);
let crypSkills = <div> &nbsp; </div>; let crypSkills = <div></div>;
if (player) crypSkills = (<div class="skills"> {skills} </div>); if (player) crypSkills = (<div class="skills"> {skills} </div>);
const effects = construct.effects.length const effects = construct.effects.length
? construct.effects.map(c => <div key={c.effect}>{c.effect} - {c.duration}T</div>) ? construct.effects.map(c => <div key={c.effect}>{c.effect} - {c.duration}T</div>)
: <div>&nbsp;</div>; : null;
return ( return (
<div <div

View File

@ -38,6 +38,15 @@ function InstanceCtrlBtns(args) {
const finished = instance && instance.phase === 'Finished'; const finished = instance && instance.phase === 'Finished';
// cheeky to make sure nubs don't just abandon their first game
const beingNub = instance.phase_end
&& instance.phase === 'Lobby'
&& Date.parse(instance.phase_end) - Date.now() < 2000;
if (beingNub) {
sendReady();
}
return ( return (
<div class="instance-ctrl-btns"> <div class="instance-ctrl-btns">
<button disabled={true} >Chat</button> <button disabled={true} >Chat</button>

View File

@ -94,7 +94,7 @@ function Play(args) {
<section class="top"> <section class="top">
<div class="news"> <div class="news">
<h1>v{VERSION}</h1> <h1>v{VERSION}</h1>
<p>Use the buttons on the right to join an instance.</p> <p class="play-p">Use the buttons on the right to join an instance.</p>
<p> <p>
Select <b>PVP</b> to play against other players.<br /> Select <b>PVP</b> to play against other players.<br />
Select <b>INVITE</b> then click <b>COPY LINK</b> to generate an instance invitation for a friend.<br /> Select <b>INVITE</b> then click <b>COPY LINK</b> to generate an instance invitation for a friend.<br />

View File

@ -34,7 +34,7 @@ function Register(args) {
submitRegister, submitRegister,
} = args; } = args;
const { password, confirm, name } = this.state; const { password, confirm, name, terms } = this.state;
const registerSubmit = (event) => { const registerSubmit = (event) => {
event.preventDefault(); event.preventDefault();
@ -45,7 +45,7 @@ function Register(args) {
password === confirm; password === confirm;
const registerDisabled = () => { const registerDisabled = () => {
return !(registerConfirm() && password && name); return !(registerConfirm() && password && name && terms);
} }
return ( return (
@ -74,6 +74,14 @@ function Register(args) {
value={this.state.confirm} value={this.state.confirm}
onInput={linkState(this, 'confirm')} onInput={linkState(this, 'confirm')}
/> />
<div>
<input
type="checkbox"
onInput={linkState(this, 'terms')
}/>
&nbsp; Confirm agreement to terms of service &nbsp;
<button onClick={() => window.open('/tos.html')}>VIEW</button>
</div>
<button <button
class="login-btn" class="login-btn"
disabled={registerDisabled()} disabled={registerDisabled()}

1098
client/tos.html Normal file

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,9 @@ map $http_upgrade $connection_upgrade {
server { server {
server_name sixtysix.pro; server_name sixtysix.pro;
auth_basic "who dis";
auth_basic_user_file /etc/mnml/htpasswd.users;
location / { location / {
root /var/lib/mnml/public/current; root /var/lib/mnml/public/current;
index index.html; index index.html;

View File

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

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mnml" name = "mnml"
version = "1.5.3" version = "1.5.4"
authors = ["ntr <ntr@smokestack.io>"] authors = ["ntr <ntr@smokestack.io>"]
[dependencies] [dependencies]

View File

@ -530,13 +530,13 @@ pub fn instance_create(tx: &mut Transaction, instance: Instance) -> Result<Insta
let instance_bytes = to_vec(&instance)?; let instance_bytes = to_vec(&instance)?;
let query = " let query = "
INSERT INTO instances (id, data) INSERT INTO instances (id, data, upkeep)
VALUES ($1, $2) VALUES ($1, $2, $3)
RETURNING id; RETURNING id;
"; ";
let result = tx let result = tx
.query(query, &[&instance.id, &instance_bytes])?; .query(query, &[&instance.id, &instance_bytes, &instance.phase_end])?;
result.iter().next().ok_or(format_err!("no instances written"))?; result.iter().next().ok_or(format_err!("no instances written"))?;

View File

@ -1,7 +1,7 @@
use rand::prelude::*; use rand::prelude::*;
use rand::{thread_rng}; use rand::{thread_rng};
const FIRSTS: [&'static str; 51] = [ const FIRSTS: [&'static str; 53] = [
"artificial", "artificial",
"ambient", "ambient",
"borean", "borean",
@ -43,9 +43,11 @@ const FIRSTS: [&'static str; 51] = [
"ossified", "ossified",
"orbiting", "orbiting",
"piscine", "piscine",
"polar",
"purified", "purified",
"recalcitrant", "recalcitrant",
"rogue", "rogue",
"sealed",
"subversive", "subversive",
"subterranean", "subterranean",
"supercooled", "supercooled",
@ -55,13 +57,16 @@ const FIRSTS: [&'static str; 51] = [
"weary", "weary",
]; ];
const LASTS: [&'static str; 56] = [ const LASTS: [&'static str; 63] = [
"artifact", "artifact",
"assembly", "assembly",
"antenna",
"alloy", "alloy",
"carrier",
"carbon", "carbon",
"console", "console",
"construct", "construct",
"coordinates",
"craft", "craft",
"core", "core",
"design", "design",
@ -77,18 +82,22 @@ const LASTS: [&'static str; 56] = [
"fossil", "fossil",
"frequency", "frequency",
"function", "function",
"fusion",
"fission",
"information", "information",
"insulator", "insulator",
"layout", "layout",
"lifeform", "lifeform",
"liquid",
"landmass", "landmass",
"lens", "lens",
"mass",
"mantle", "mantle",
"magnetism", "magnetism",
"mechanism", "mechanism",
"mountain", "mountain",
"nectar", "nectar",
"oak", "nebula",
"oxide", "oxide",
"orbit", "orbit",
"pattern", "pattern",

View File

@ -294,7 +294,7 @@ fn post_resolve(_skill: Skill, game: &mut Game, mut resolutions: Resolutions) ->
match event { match event {
Event::Damage { amount, skill, mitigation: _, colour: c } => { Event::Damage { amount, skill, mitigation: _, colour: c } => {
if target.affected(Effect::Electric) { if target.affected(Effect::Electric) && !skill.is_tick() {
let ConstructEffect { effect: _, duration: _, meta, tick: _ } = target.effects.iter() let ConstructEffect { effect: _, duration: _, meta, tick: _ } = target.effects.iter()
.find(|e| e.effect == Effect::Electric).unwrap().clone(); .find(|e| e.effect == Effect::Electric).unwrap().clone();
match meta { match meta {