Merge branch 'release/1.3.2'
This commit is contained in:
commit
cc2606248d
37
README.md
37
README.md
@ -1,33 +1,12 @@
|
|||||||
# Constructs ("creeps")
|
# mnml
|
||||||
|
mnml is a turn-based 1v1 strategy game in an abstract setting.
|
||||||
|
players craft a team of 3 constructs combining a deep pool of skills, effects and specialisations to mindgame & outplay their opponents in a rapid series of duels.
|
||||||
|
featuring complex interactions arising from simple rules, simultaneous turns to increase the pace, and a unique speed mechanic mnml is a tactical game in a genre of its own.
|
||||||
|
it is completely free to play and requires no installation.
|
||||||
|
|
||||||
## Combat
|
minimal studios is ntr & mashy: 2 mates with a friendship forged in the fires of warcraft 3 dota.
|
||||||
|
we have both bailed out of the big city life and have dedicated ourselves to growing farm fresh, organic, ethical gaming produce in the rolling hills of brisbane and leaves of melbourne.
|
||||||
skill phase:
|
completely self funded, we're just here to make games that feel good & play it clean.
|
||||||
1.1 -> block (sp 10) -> on self
|
|
||||||
1.2 -> attack (sp 5) -> on player 2
|
|
||||||
|
|
||||||
2.1 -> hex (sp 3) -> on player 1
|
|
||||||
2.2 -> attack (sp 5) -> on player 1
|
|
||||||
|
|
||||||
target phase:
|
|
||||||
player 2 targets 1.2 on 2.2
|
|
||||||
|
|
||||||
player 1 targets 2.1 on 1.1
|
|
||||||
player 1 targets 2.2 on 1.1
|
|
||||||
|
|
||||||
resolve phase:
|
|
||||||
1.1 <- block
|
|
||||||
1.1 <- attack (no effect because of block)
|
|
||||||
2.2 <- attack (normal resolve)
|
|
||||||
1.1 <- hexed (no skills for the rest of this turn and next)
|
|
||||||
|
|
||||||
## Damage Chart
|
|
||||||
|
|
||||||
| Red | Magic | Modifiers |
|
|
||||||
| ------ | ------ | ------ |
|
|
||||||
| damage | damage | speed |
|
|
||||||
| evasion | resistance | cooldowns |
|
|
||||||
| reduction | absorption? | durations |
|
|
||||||
|
|
||||||
|
|
||||||
## Construct Alignments
|
## Construct Alignments
|
||||||
|
|||||||
@ -17,16 +17,14 @@
|
|||||||
* bot game grind
|
* bot game grind
|
||||||
* stress test
|
* stress test
|
||||||
|
|
||||||
|
* msg pane
|
||||||
|
* game invites
|
||||||
* change score to enum
|
* change score to enum
|
||||||
* pct based translates for combat animation
|
|
||||||
* make our own toasts / msg pane
|
|
||||||
* send account_instances on players update
|
|
||||||
|
|
||||||
|
* pct based translates for combat animation
|
||||||
* add speed to descriptions
|
* add speed to descriptions
|
||||||
* clear skill (if currently targetted)
|
* clear skill (if currently targetted)
|
||||||
|
|
||||||
* only login / logout / register http
|
|
||||||
|
|
||||||
## SOON
|
## SOON
|
||||||
*SERVER*
|
*SERVER*
|
||||||
* modules
|
* modules
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-client",
|
"name": "mnml-client",
|
||||||
"version": "1.3.0",
|
"version": "1.3.2",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
@import 'colours.less';
|
@import 'colours.less';
|
||||||
|
|
||||||
.account {
|
.account {
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||||
grid-gap: 0 1em;
|
|
||||||
|
div {
|
||||||
|
padding-right: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
// height: 3em;
|
|
||||||
width: 75%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
width: 75%;
|
width: 100%;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@ -31,19 +32,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.list {
|
.list {
|
||||||
letter-spacing: 0.25em;
|
grid-template-columns: 1fr;
|
||||||
text-transform: uppercase;
|
|
||||||
|
|
||||||
figure {
|
|
||||||
width: 75%;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -61,7 +61,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.inventory {
|
.options {
|
||||||
|
grid-area: hdr;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 25%;
|
||||||
|
border-top: 0;
|
||||||
|
border: 1px solid #222;
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
|
|
||||||
@ -84,26 +102,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
figure {
|
figure {
|
||||||
|
letter-spacing: 0.25em;
|
||||||
|
text-transform: uppercase;
|
||||||
font-size: 125%;
|
font-size: 125%;
|
||||||
display: flex;
|
display: flex;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-client",
|
"name": "mnml-client",
|
||||||
"version": "1.3.0",
|
"version": "1.3.2",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -206,14 +206,12 @@ class AccountStatus extends Component {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="list">
|
|
||||||
<figure>
|
<figure>
|
||||||
<figcaption>spawn new construct</figcaption>
|
<figcaption>spawn new construct</figcaption>
|
||||||
<button onClick={() => sendConstructSpawn()} type="submit">
|
<button onClick={() => sendConstructSpawn()} type="submit">
|
||||||
¤50
|
¤50
|
||||||
</button>
|
</button>
|
||||||
</figure>
|
</figure>
|
||||||
</div>
|
|
||||||
<button onClick={() => logout()}>Logout</button>
|
<button onClick={() => logout()}>Logout</button>
|
||||||
<button><a href={`mailto:humans@mnml.gg?subject=Account%20Support:%20${account.name}`}>✉ support</a></button>
|
<button><a href={`mailto:humans@mnml.gg?subject=Account%20Support:%20${account.name}`}>✉ support</a></button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -21,6 +21,7 @@ function InfoComponent(args) {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2>VBOX phase</h2>
|
<h2>VBOX phase</h2>
|
||||||
|
<p>in this phase you strengthen and specialise your constructs by equipping items to them.</p>
|
||||||
<p>double clicking items in the <b>VBOX</b> will purchase and move them to your <b>INVENTORY</b>.</p>
|
<p>double clicking items in the <b>VBOX</b> will purchase and move them to your <b>INVENTORY</b>.</p>
|
||||||
<p>
|
<p>
|
||||||
hover over an item to see its effects and combinations.<br />
|
hover over an item to see its effects and combinations.<br />
|
||||||
|
|||||||
@ -89,7 +89,7 @@ function Play(args) {
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="inventory top">
|
<section class="top">
|
||||||
<div class="news">
|
<div class="news">
|
||||||
<h1>mnml v{VERSION}</h1>
|
<h1>mnml v{VERSION}</h1>
|
||||||
<p>use the buttons on the right to join an instance.</p>
|
<p>use the buttons on the right to join an instance.</p>
|
||||||
@ -122,7 +122,7 @@ function Play(args) {
|
|||||||
{shop.available.map(availableMtx)}
|
{shop.available.map(availableMtx)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,7 @@ function Shop(args) {
|
|||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="inventory top">
|
<section class="top">
|
||||||
<div class="news">
|
<div class="news">
|
||||||
<h1>support the game</h1>
|
<h1>support the game</h1>
|
||||||
<p>
|
<p>
|
||||||
@ -51,7 +51,7 @@ function Shop(args) {
|
|||||||
<StripeBtns account={account} />
|
<StripeBtns account={account} />
|
||||||
</Elements>
|
</Elements>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
bits: {
|
bits: {
|
||||||
item: 'BITS',
|
item: 'BITS',
|
||||||
description: 'The VBOX currency.\nColours: 1b\nSkills: 2b\nSpecs: 3b\nWin: +12b\nLose: +9b',
|
description: 'The VBOX currency.\nColours: 1b\nSkills: 2b\nSpecs: 3b\nAt the beginning of a round you receive 12 + 6 * round_number bits.',
|
||||||
},
|
},
|
||||||
ready: {
|
ready: {
|
||||||
item: 'READY',
|
item: 'READY',
|
||||||
@ -56,7 +56,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
refill: {
|
refill: {
|
||||||
item: 'REFILL',
|
item: 'REFILL',
|
||||||
description: 'Refill the VBOX with new ITEMS.\nCosts 5b.',
|
description: 'Refill the VBOX with new ITEMS.',
|
||||||
},
|
},
|
||||||
equipSkills: {
|
equipSkills: {
|
||||||
item: 'QUICK ACCESS - SKILLS',
|
item: 'QUICK ACCESS - SKILLS',
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mnml-ops",
|
"name": "mnml-ops",
|
||||||
"version": "1.3.0",
|
"version": "1.3.2",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mnml"
|
name = "mnml"
|
||||||
version = "1.3.0"
|
version = "1.3.2"
|
||||||
authors = ["ntr <ntr@smokestack.io>"]
|
authors = ["ntr <ntr@smokestack.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -40,12 +40,12 @@ pub enum MnmlHttpError {
|
|||||||
BadRequest,
|
BadRequest,
|
||||||
#[fail(display="not found")]
|
#[fail(display="not found")]
|
||||||
NotFound,
|
NotFound,
|
||||||
#[fail(display="account name taken or invalid")]
|
|
||||||
AccountNameNotProvided,
|
|
||||||
#[fail(display="account name not provided")]
|
#[fail(display="account name not provided")]
|
||||||
AccountNotFound,
|
AccountNameNotProvided,
|
||||||
|
#[fail(display="account name unavailable")]
|
||||||
|
AccountNameUnavailable,
|
||||||
#[fail(display="account not found")]
|
#[fail(display="account not found")]
|
||||||
AccountNameTaken,
|
AccountNotFound,
|
||||||
#[fail(display="password does not match")]
|
#[fail(display="password does not match")]
|
||||||
PasswordNotMatch,
|
PasswordNotMatch,
|
||||||
#[fail(display="password unacceptable. must be > 11 characters")]
|
#[fail(display="password unacceptable. must be > 11 characters")]
|
||||||
@ -66,7 +66,21 @@ impl From<bcrypt::BcryptError> for MnmlHttpError {
|
|||||||
impl From<postgres::Error> for MnmlHttpError {
|
impl From<postgres::Error> for MnmlHttpError {
|
||||||
fn from(err: postgres::Error) -> Self {
|
fn from(err: postgres::Error) -> Self {
|
||||||
warn!("{:?}", err);
|
warn!("{:?}", err);
|
||||||
MnmlHttpError::DbError
|
|
||||||
|
match err.as_db() {
|
||||||
|
Some(db) => {
|
||||||
|
let constraint = match db.constraint {
|
||||||
|
Some(ref c) => c,
|
||||||
|
None => return MnmlHttpError::DbError,
|
||||||
|
};
|
||||||
|
|
||||||
|
match constraint.as_ref() {
|
||||||
|
"accounts_name_unique" => MnmlHttpError::AccountNameUnavailable,
|
||||||
|
_ => MnmlHttpError::DbError,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => MnmlHttpError::DbError,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +123,7 @@ impl From<MnmlHttpError> for IronError {
|
|||||||
MnmlHttpError::DbError => (m_err.compat(), status::InternalServerError),
|
MnmlHttpError::DbError => (m_err.compat(), status::InternalServerError),
|
||||||
|
|
||||||
MnmlHttpError::AccountNameNotProvided |
|
MnmlHttpError::AccountNameNotProvided |
|
||||||
MnmlHttpError::AccountNameTaken |
|
MnmlHttpError::AccountNameUnavailable |
|
||||||
MnmlHttpError::AccountNotFound |
|
MnmlHttpError::AccountNotFound |
|
||||||
MnmlHttpError::BadRequest |
|
MnmlHttpError::BadRequest |
|
||||||
MnmlHttpError::PasswordUnacceptable => (m_err.compat(), status::BadRequest),
|
MnmlHttpError::PasswordUnacceptable => (m_err.compat(), status::BadRequest),
|
||||||
|
|||||||
@ -164,9 +164,15 @@ impl StripeData {
|
|||||||
Ok(self)
|
Ok(self)
|
||||||
},
|
},
|
||||||
StripeData::Purchase { account, customer: _, amount, checkout: _ } => {
|
StripeData::Purchase { account, customer: _, amount, checkout: _ } => {
|
||||||
let credits = amount
|
let credits = match amount {
|
||||||
|
500 => 50,
|
||||||
|
1000 => 110,
|
||||||
|
2000 => 250,
|
||||||
|
5000 => 660,
|
||||||
|
_ => amount
|
||||||
.checked_div(CREDITS_COST_CENTS)
|
.checked_div(CREDITS_COST_CENTS)
|
||||||
.expect("credits cost 0");
|
.expect("credits cost 0"),
|
||||||
|
};
|
||||||
|
|
||||||
account::credit(tx, *account, credits)?;
|
account::credit(tx, *account, credits)?;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user