diff --git a/.editorconfig b/.editorconfig
index 4d70db8..b81924f 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -6,6 +6,6 @@ end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
-[*.{js,css}]
+[*.{js,css,js.default}]
indent_size = 2
indent_style = space
diff --git a/.gitignore b/.gitignore
index bbabf79..59680f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,4 +6,5 @@ data
public/out
public/lib
-config.js
+config.client.js
+config.server.js
diff --git a/Makefile b/Makefile
index e0e89b8..ee7f684 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,12 @@
.PHONY: all install clean cards score js
-all: install clean cards score js
+all: install cards score js
node := ${CURDIR}/node_modules
all_sets := ${CURDIR}/data/AllSets.json
traceur := ${node}/.bin/traceur
-config := config.js
+
+client_config := config.client.js
+server_config := config.server.js
${traceur}: install
@@ -32,14 +34,16 @@ ${all_sets}:
curl -so ${all_sets} https://mtgjson.com/json/AllSets.json
score:
- -node src/make score #ignore errors
+ -node src/make score
-js: ${traceur} ${all_sets} ${config}
+js: ${traceur} ${all_sets} ${client_config}
${traceur} --out public/lib/app.js public/src/init.js
# "order-only" prerequisite
-${config}: | ${config}.default
+${client_config}: | ${client_config}.default
+ cp $| $@
+${server_config}: | ${server_config}.default
cp $| $@
-run: js
+run: js ${server_config}
node run
diff --git a/README.md b/README.md
index c826cb0..8e219c9 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# drafts.ninja
+# drafts.ninja [](https://waffle.io/arxanas/drafts.ninja) [](https://gitter.im/arxanas/drafts.ninja)
[drafts.ninja](http://drafts.ninja) is a fork of aeosynth's `draft` project. It
supports all of the features of `draft` and more. Here are some of the
diff --git a/app.js b/app.js
index 0b01994..7016bcf 100644
--- a/app.js
+++ b/app.js
@@ -1,4 +1,4 @@
-const CONFIG = require('./config')
+const CONFIG = require('./config.server')
var http = require('http')
var eio = require('engine.io')
diff --git a/config.client.js.default b/config.client.js.default
new file mode 100644
index 0000000..c90aefa
--- /dev/null
+++ b/config.client.js.default
@@ -0,0 +1,20 @@
+let d = React.DOM
+
+export let STRINGS = {
+ BRANDING: {
+ SITE_NAME: ['drafts', 'ninja'],
+ DEFAULT_USERNAME: 'ninja',
+ },
+
+ PAGE_SECTIONS: {
+ MOTD: null, // message of the day; can be a React element
+
+ FOOTER: d.div({},
+ d.strong({}, 'drafts.ninja'),
+ ' is a fork of the ',
+ d.code({}, 'draft'),
+ ' project by aeosynth. Contributions welcome! ',
+ d.a({ href: 'https://github.com/arxanas/drafts.ninja' },
+ 'https://github.com/arxanas/drafts.ninja')),
+ },
+}
diff --git a/config.js.default b/config.js.default
deleted file mode 100644
index c522ecd..0000000
--- a/config.js.default
+++ /dev/null
@@ -1,4 +0,0 @@
-module.exports = {
- PORT: 1337,
- MOTD: null, // message of the day
-}
diff --git a/config.server.js.default b/config.server.js.default
new file mode 100644
index 0000000..e799072
--- /dev/null
+++ b/config.server.js.default
@@ -0,0 +1,8 @@
+module.exports = {
+ PORT: 1337,
+ STRINGS: {
+ BRANDING: {
+ DEFAULT_USERNAME: 'ninja',
+ }
+ }
+}
diff --git a/package.json b/package.json
index c530ee9..2959712 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,7 @@
"node-fetch": "^1.0.3",
"send": "^0.11.1",
"traceur": "0.0.65",
- "utils": "git://github.com/aeosynth/utils"
+ "utils": "git://github.com/arxanas/utils"
},
"devDependencies": {
"normalize.css": "^3.0.1",
diff --git a/public/index.html b/public/index.html
index 92367ed..539847b 100644
--- a/public/index.html
+++ b/public/index.html
@@ -2,7 +2,6 @@
- drafts.ninja
diff --git a/public/src/app.js b/public/src/app.js
index ac89c3f..39ed955 100644
--- a/public/src/app.js
+++ b/public/src/app.js
@@ -1,5 +1,6 @@
import _ from '../lib/utils'
import EventEmitter from '../lib/ee'
+import {STRINGS} from './config'
function message(msg) {
let args = JSON.parse(msg)
@@ -11,7 +12,7 @@ let App = {
state: {
id: null,
- name: 'ninja',
+ name: STRINGS.BRANDING.DEFAULT_USERNAME,
numUsers: 0,
numPlayers: 0,
@@ -35,7 +36,8 @@ let App = {
packs: 3,
bots: true,
- timer: true,
+ useTimer: true,
+ timerLength: 40, // seconds
beep: false,
chat: true,
diff --git a/public/src/cards.js b/public/src/cards.js
index 32a877e..0f3de45 100644
--- a/public/src/cards.js
+++ b/public/src/cards.js
@@ -93,8 +93,8 @@ let events = {
App.send('readyToStart', e.target.checked)
},
start() {
- let {bots, timer} = App.state
- let options = [bots, timer]
+ let {bots, useTimer, timerLength} = App.state
+ let options = {bots, useTimer, timerLength}
App.send('start', options)
},
pack(cards) {
@@ -390,6 +390,13 @@ function Key(groups, sort) {
return o
}
+function sortLandsBeforeNonLands(lhs, rhs) {
+ let isLand = x => x.type.toLowerCase().indexOf('land') !== -1
+ let lhsIsLand = isLand(lhs)
+ let rhsIsLand = isLand(rhs)
+ return rhsIsLand - lhsIsLand
+}
+
export function getZone(zoneName) {
let zone = Zones[zoneName]
@@ -401,7 +408,7 @@ export function getZone(zoneName) {
let {sort} = App.state
let groups = _.group(cards, sort)
for (let key in groups)
- _.sort(groups[key], 'color', 'cmc', 'name')
+ _.sort(groups[key], sortLandsBeforeNonLands, 'color', 'cmc', 'name')
groups = Key(groups, sort)
diff --git a/public/src/components/deck-settings.js b/public/src/components/deck-settings.js
index 27b3101..4045bc6 100644
--- a/public/src/components/deck-settings.js
+++ b/public/src/components/deck-settings.js
@@ -12,7 +12,7 @@ function Lands() {
let inputs = BASICS.map(cardName =>
d.td({},
d.input({
- className: 'num-lands',
+ className: 'number',
min: 0,
onChange: App._emit('land', zoneName, cardName),
type: 'number',
@@ -27,7 +27,7 @@ function Lands() {
let suggest = d.tr({},
d.td({}, 'deck size'),
d.td({}, d.input({
- className: 'num-lands',
+ className: 'number',
min: 0,
onChange: App._emit('deckSize'),
type: 'number',
diff --git a/public/src/components/game.js b/public/src/components/game.js
index 9831485..4fd836f 100644
--- a/public/src/components/game.js
+++ b/public/src/components/game.js
@@ -69,7 +69,22 @@ export default React.createClass({
let startControls = d.div({},
d.div({}, `Format: ${App.state.format}`),
LBox('bots', 'bots'),
- LBox('timer', 'timer'),
+ d.div({},
+ d.label({},
+ d.input({
+ type: 'checkbox',
+ checkedLink: App.link('useTimer'),
+ }), ' use '),
+ d.label({},
+ d.input({
+ className: 'number',
+ disabled: !App.state.useTimer,
+ min: 0,
+ max: 60,
+ step: 5,
+ type: 'number',
+ valueLink: App.link('timerLength'),
+ }), '-second timer')),
d.div({}, startButton, readyReminderText))
return d.fieldset({ className: 'start-controls fieldset' },
diff --git a/public/src/components/grid.js b/public/src/components/grid.js
index 60db5c5..3d81a21 100644
--- a/public/src/components/grid.js
+++ b/public/src/components/grid.js
@@ -1,6 +1,7 @@
import _ from '../../lib/utils'
import App from '../app'
import {getZone} from '../cards'
+import {Spaced} from './spacer'
let d = React.DOM
export default React.createClass({
@@ -30,9 +31,8 @@ function zone(zoneName) {
})))
return d.div({ className: 'zone' },
- d.h1({},
+ d.h1({}, Spaced(
d.span({}, zoneName),
- d.span({ className: 'spacer-dot' }),
- d.span({}, `${cards.length} ${cards.length === 1 ? 'card' : 'cards' }`)),
+ d.span({}, `${cards.length} ${cards.length === 1 ? 'card' : 'cards' }`))),
items)
}
diff --git a/public/src/components/lobby.js b/public/src/components/lobby.js
index 431b20d..55bfcc7 100644
--- a/public/src/components/lobby.js
+++ b/public/src/components/lobby.js
@@ -1,8 +1,10 @@
import _ from '../../lib/utils'
+import {STRINGS} from '../config'
import App from '../app'
import data from '../data'
import Chat from './chat'
import {RBox} from './checkbox'
+import {Spaced} from './spacer'
let d = React.DOM
export default React.createClass({
@@ -13,32 +15,29 @@ export default React.createClass({
App.send('join', 'lobby')
},
render() {
+ document.title = STRINGS.BRANDING.SITE_NAME.join('.')
+
return d.div({ className: 'container' },
d.div({ className: 'lobby' },
d.header({},
d.h1({ className: 'lobby-header' },
- d.span({}, 'drafts'),
- d.span({ className: 'spacer-dot' }),
- d.span({}, 'ninja'))),
- d.p({}, `${App.state.numUsers}
- ${App.state.numUsers === 1 ? 'user' : 'users'}
- connected;
- ${App.state.numPlayers}
- ${App.state.numPlayers === 1 ? 'player' : 'players'}
- playing
- ${App.state.numActiveGames}
- ${App.state.numActiveGames === 1 ? 'game' : 'games'}`),
+ Spaced(...STRINGS.BRANDING.SITE_NAME))),
+
+ d.p({},
+ Spaced(
+ `${App.state.numUsers}
+ ${App.state.numUsers === 1 ? 'user' : 'users'}
+ connected`,
+ `${App.state.numPlayers}
+ ${App.state.numPlayers === 1 ? 'player' : 'players'}
+ playing
+ ${App.state.numActiveGames}
+ ${App.state.numActiveGames === 1 ? 'game' : 'games'}`)),
d.p({ className: 'error' }, App.err),
Create(),
Join(),
Motd(),
- d.div({},
- d.strong({}, 'drafts.ninja'),
- ' is a fork of the ',
- d.code({}, 'draft'),
- ' project by aeosynth. Contributions welcome! ',
- d.a({ href: 'https://github.com/arxanas/drafts.ninja' },
- 'https://github.com/arxanas/drafts.ninja'))),
+ STRINGS.PAGE_SECTIONS.FOOTER),
Chat())
}
})
@@ -92,10 +91,11 @@ function content() {
}
function Motd() {
- if (App.state.motd)
+ let motd = STRINGS.PAGE_SECTIONS.MOTD
+ if (motd)
return d.fieldset({ className: 'fieldset' },
d.legend({ className: 'legend' }, 'News'),
- d.div({ dangerouslySetInnerHTML: { '__html': App.state.motd } }))
+ d.div({}, motd))
}
function Create() {
diff --git a/public/src/components/spacer.js b/public/src/components/spacer.js
new file mode 100644
index 0000000..3af9393
--- /dev/null
+++ b/public/src/components/spacer.js
@@ -0,0 +1,11 @@
+let d = React.DOM
+
+export function Spaced(...elements) {
+ let parts = []
+ for (let part of elements) {
+ parts.push(d.span({}, part))
+ parts.push(d.span({ className: 'spacer-dot' }))
+ }
+ parts.splice(-1, 1)
+ return parts
+}
diff --git a/public/src/config.js b/public/src/config.js
new file mode 120000
index 0000000..2dc6366
--- /dev/null
+++ b/public/src/config.js
@@ -0,0 +1 @@
+../../config.client.js
\ No newline at end of file
diff --git a/public/src/data.js b/public/src/data.js
index be9f2f6..49f4245 100644
--- a/public/src/data.js
+++ b/public/src/data.js
@@ -94,6 +94,7 @@ export default {
"Limited Edition Alpha": "LEA"
},
other: {
+ "Eternal Masters": "EMA",
"Magic Origins": "ORI",
"Modern Masters 2015": "MM2",
"Tempest Remastered": "TPR",
diff --git a/public/style.css b/public/style.css
index 61c7e29..5dd6ac6 100644
--- a/public/style.css
+++ b/public/style.css
@@ -109,6 +109,10 @@ input[type=button]:disabled:active, button:disabled:active {
box-shadow: 0 0 1px 0 black inset;
}
+.number {
+ width: 50px;
+}
+
/** Container of inputs that share a border. **/
.connected-container, .connected-column {
@@ -159,7 +163,7 @@ input[type=button]:disabled:active, button:disabled:active {
.spacer-dot:after {
content: "\00b7";
display: inline-block;
- width: 25px;
+ width: 0.75em;
text-align: center;
}
@@ -396,10 +400,6 @@ input[type=button]:disabled:active, button:disabled:active {
flex-shrink: 0;
}
-.num-lands {
- width: 50px;
-}
-
.deck-settings tr:first-of-type {
text-align: center;
}
diff --git a/src/game.js b/src/game.js
index 390fc6c..d2ce184 100644
--- a/src/game.js
+++ b/src/game.js
@@ -157,7 +157,6 @@ module.exports = class Game extends Room {
}
join(sock) {
- sock.on('exit', this.farewell.bind(this))
for (var i = 0; i < this.players.length; i++) {
var p = this.players[i]
if (p.id === sock.id) {
@@ -210,11 +209,6 @@ module.exports = class Game extends Room {
})
}
- farewell(sock) {
- sock.h.isConnected = false
- this.meta()
- }
-
exit(sock) {
if (this.didGameStart)
return
@@ -307,7 +301,7 @@ module.exports = class Game extends Room {
this.meta()
}
- start([addBots, useTimer]) {
+ start({addBots, useTimer, timerLength}) {
var src = this.cube ? this.cube : this.sets
var {players} = this
var p
@@ -329,8 +323,12 @@ module.exports = class Game extends Room {
return
}
- for (p of players)
+ timerLength = parseInt(timerLength, 10)
+ useTimer = !Number.isNaN(timerLength) && (timerLength > 0) && useTimer
+ for (p of players) {
p.useTimer = useTimer
+ p.timerLength = timerLength
+ }
console.log(`game ${this.id} started with ${this.players.length} players and ${this.seats} seats`)
Game.broadcastGameInfo()
diff --git a/src/human.js b/src/human.js
index 514227b..66bd82d 100644
--- a/src/human.js
+++ b/src/human.js
@@ -31,6 +31,7 @@ module.exports = class extends EventEmitter {
sock.on('autopick', this._autopick.bind(this))
sock.on('pick', this._pick.bind(this))
sock.on('hash', this._hash.bind(this))
+ sock.once('exit', this._farewell.bind(this))
var [pack] = this.packs
if (pack)
@@ -47,6 +48,10 @@ module.exports = class extends EventEmitter {
this.hash = hash(deck)
this.emit('meta')
}
+ _farewell() {
+ this.isConnected = false
+ this.emit('meta')
+ }
_readyToStart(value) {
this.isReadyToStart = value
this.emit('meta')
@@ -70,7 +75,7 @@ module.exports = class extends EventEmitter {
return this.pick(0)
if (this.useTimer)
- this.time = 20 + 5 * pack.length
+ this.time = this.timerLength + pack.length
this.send('pack', pack)
}
diff --git a/src/make/cards.js b/src/make/cards.js
index bcc48df..3c0f50e 100644
--- a/src/make/cards.js
+++ b/src/make/cards.js
@@ -1,6 +1,20 @@
var fs = require('fs')
var _ = require('../_')
var raw = require('../../data/AllSets')
+raw.EMA = {
+ name: 'Eternal Masters',
+ code: 'EMA',
+ cards: [{"name":"aven riftwatcher","rarity":"common"},{"name":"balance","rarity":"mythic"},{"name":"ballynock cohort","rarity":"common"},{"name":"benevolent bodyguard","rarity":"common"},{"name":"calciderm","rarity":"uncommon"},{"name":"coalition honor guard","rarity":"common"},{"name":"eight-and-a-half-tails","rarity":"rare"},{"name":"elite vanguard","rarity":"common"},{"name":"enlightened tutor","rarity":"rare"},{"name":"faith's fetters","rarity":"uncommon"},{"name":"field of souls","rarity":"uncommon"},{"name":"glimmerpoint stag","rarity":"uncommon"},{"name":"honden of cleansing fire","rarity":"uncommon"},{"name":"humble","rarity":"common"},{"name":"intangible virtue","rarity":"uncommon"},{"name":"jareth, leonine titan","rarity":"rare"},{"name":"karmic guide","rarity":"rare"},{"name":"kor hookmaster","rarity":"common"},{"name":"mesa enchantress","rarity":"uncommon"},{"name":"mistral charger","rarity":"common"},{"name":"monk idealist","rarity":"common"},{"name":"mother of runes","rarity":"rare"},{"name":"pacifism","rarity":"common"},{"name":"raise the alarm","rarity":"common"},{"name":"rally the peasants","rarity":"common"},{"name":"seal of cleansing","rarity":"common"},{"name":"second thoughts","rarity":"common"},{"name":"serra angel","rarity":"uncommon"},{"name":"shelter","rarity":"common"},{"name":"soulcatcher","rarity":"uncommon"},{"name":"squadron hawk","rarity":"common"},{"name":"swords to plowshares","rarity":"uncommon"},{"name":"unexpectedly absent","rarity":"rare"},{"name":"wall of omens","rarity":"uncommon"},{"name":"war priest of thune","rarity":"uncommon"},{"name":"welkin guide","rarity":"common"},{"name":"whitemane lion","rarity":"common"},{"name":"wrath of god","rarity":"rare"},{"name":"arcanis the omnipotent","rarity":"rare"},{"name":"brainstorm","rarity":"uncommon"},{"name":"cephalid sage","rarity":"common"},{"name":"control magic","rarity":"rare"},{"name":"counterspell","rarity":"common"},{"name":"daze","rarity":"uncommon"},{"name":"deep analysis","rarity":"common"},{"name":"diminishing returns","rarity":"rare"},{"name":"dream twist","rarity":"common"},{"name":"fact or fiction","rarity":"uncommon"},{"name":"force of will","rarity":"mythic"},{"name":"future sight","rarity":"rare"},{"name":"gaseous form","rarity":"common"},{"name":"giant tortoise","rarity":"common"},{"name":"glacial wall","rarity":"common"},{"name":"honden of seeing winds","rarity":"uncommon"},{"name":"hydroblast","rarity":"uncommon"},{"name":"inkwell leviathan","rarity":"rare"},{"name":"jace, the mind sculptor","rarity":"mythic"},{"name":"jetting glasskite","rarity":"uncommon"},{"name":"man-o'-war","rarity":"common"},{"name":"memory lapse","rarity":"common"},{"name":"merfolk looter","rarity":"uncommon"},{"name":"mystical tutor","rarity":"rare"},{"name":"oona's grace","rarity":"common"},{"name":"peregrine drake","rarity":"common"},{"name":"phantom monster","rarity":"common"},{"name":"phyrexian ingester","rarity":"uncommon"},{"name":"prodigal sorcerer","rarity":"uncommon"},{"name":"quiet speculation","rarity":"uncommon"},{"name":"screeching skaab","rarity":"common"},{"name":"serendib efreet","rarity":"rare"},{"name":"shoreline ranger","rarity":"common"},{"name":"silent departure","rarity":"common"},{"name":"sprite noble","rarity":"uncommon"},{"name":"stupefying touch","rarity":"common"},{"name":"tidal wave","rarity":"common"},{"name":"warden of evos isle","rarity":"common"},{"name":"wonder","rarity":"uncommon"},{"name":"animate dead","rarity":"uncommon"},{"name":"annihilate","rarity":"uncommon"},{"name":"blightsoil druid","rarity":"common"},{"name":"blood artist","rarity":"uncommon"},{"name":"braids, cabal minion","rarity":"rare"},{"name":"cabal therapy","rarity":"uncommon"},{"name":"carrion feeder","rarity":"common"},{"name":"deadbridge shaman","rarity":"common"},{"name":"duress","rarity":"common"},{"name":"entomb","rarity":"rare"},{"name":"eyeblight's ending","rarity":"common"},{"name":"gravedigger","rarity":"common"},{"name":"havoc demon","rarity":"uncommon"},{"name":"honden of night's reach","rarity":"uncommon"},{"name":"hymn to tourach","rarity":"uncommon"},{"name":"ichorid","rarity":"rare"},{"name":"innocent blood","rarity":"common"},{"name":"lys alana scarblade","rarity":"uncommon"},{"name":"malicious affliction","rarity":"rare"},{"name":"nausea","rarity":"common"},{"name":"necropotence","rarity":"mythic"},{"name":"nekrataal","rarity":"uncommon"},{"name":"night's whisper","rarity":"common"},{"name":"phyrexian gargantua","rarity":"uncommon"},{"name":"phyrexian rager","rarity":"common"},{"name":"plague witch","rarity":"common"},{"name":"prowling pangolin","rarity":"common"},{"name":"sengir autocrat","rarity":"uncommon"},{"name":"sinkhole","rarity":"rare"},{"name":"skulking ghost","rarity":"common"},{"name":"toxic deluge","rarity":"rare"},{"name":"tragic slip","rarity":"common"},{"name":"twisted abomination","rarity":"common"},{"name":"urborg uprising","rarity":"common"},{"name":"vampiric tutor","rarity":"mythic"},{"name":"victimize","rarity":"uncommon"},{"name":"visara the dreadful","rarity":"rare"},{"name":"wake of vultures","rarity":"common"},{"name":"wakedancer","rarity":"common"},{"name":"avarax","rarity":"common"},{"name":"battle squadron","rarity":"uncommon"},{"name":"beetleback chief","rarity":"uncommon"},{"name":"borderland marauder","rarity":"common"},{"name":"burning vengeance","rarity":"uncommon"},{"name":"carbonize","rarity":"common"},{"name":"chain lightning","rarity":"uncommon"},{"name":"crater hellion","rarity":"rare"},{"name":"desperate ravings","rarity":"common"},{"name":"dragon egg","rarity":"common"},{"name":"dualcaster mage","rarity":"rare"},{"name":"faithless looting","rarity":"common"},{"name":"fervent cathar","rarity":"common"},{"name":"firebolt","rarity":"common"},{"name":"flame jab","rarity":"uncommon"},{"name":"gamble","rarity":"rare"},{"name":"ghitu slinger","rarity":"uncommon"},{"name":"honden of infinite rage","rarity":"uncommon"},{"name":"keldon champion","rarity":"uncommon"},{"name":"keldon marauders","rarity":"common"},{"name":"kird ape","rarity":"common"},{"name":"mogg fanatic","rarity":"common"},{"name":"mogg war marshal","rarity":"common"},{"name":"orcish oriflamme","rarity":"common"},{"name":"price of progress","rarity":"uncommon"},{"name":"pyroblast","rarity":"uncommon"},{"name":"pyrokinesis","rarity":"rare"},{"name":"reckless charge","rarity":"common"},{"name":"rorix bladewing","rarity":"rare"},{"name":"seismic stomp","rarity":"common"},{"name":"siege-gang commander","rarity":"rare"},{"name":"sneak attack","rarity":"mythic"},{"name":"stingscourger","rarity":"common"},{"name":"sulfuric vortex","rarity":"rare"},{"name":"tooth and claw","rarity":"uncommon"},{"name":"undying rage","rarity":"common"},{"name":"wildfire emissary","rarity":"common"},{"name":"worldgorger dragon","rarity":"mythic"},{"name":"young pyromancer","rarity":"uncommon"},{"name":"abundant growth","rarity":"common"},{"name":"ancestral mask","rarity":"uncommon"},{"name":"argothian enchantress","rarity":"mythic"},{"name":"brawn","rarity":"uncommon"},{"name":"centaur chieftain","rarity":"uncommon"},{"name":"civic wayfinder","rarity":"common"},{"name":"commune with the gods","rarity":"common"},{"name":"elephant guide","rarity":"common"},{"name":"elvish vanguard","rarity":"common"},{"name":"emperor crocodile","rarity":"common"},{"name":"flinthoof boar","rarity":"uncommon"},{"name":"fog","rarity":"common"},{"name":"gaea's blessing","rarity":"uncommon"},{"name":"green sun's zenith","rarity":"rare"},{"name":"harmonize","rarity":"uncommon"},{"name":"heritage druid","rarity":"rare"},{"name":"honden of life's web","rarity":"uncommon"},{"name":"imperious perfect","rarity":"rare"},{"name":"invigorate","rarity":"uncommon"},{"name":"llanowar elves","rarity":"common"},{"name":"lys alana huntmaster","rarity":"common"},{"name":"natural order","rarity":"mythic"},{"name":"nature's claim","rarity":"common"},{"name":"nimble mongoose","rarity":"common"},{"name":"rancor","rarity":"uncommon"},{"name":"regal force","rarity":"rare"},{"name":"roar of the wurm","rarity":"uncommon"},{"name":"roots","rarity":"common"},{"name":"seal of strength","rarity":"common"},{"name":"sentinel spider","rarity":"common"},{"name":"silvos, rogue elemental","rarity":"rare"},{"name":"sylvan library","rarity":"rare"},{"name":"sylvan might","rarity":"common"},{"name":"thornweald archer","rarity":"common"},{"name":"timberwatch elf","rarity":"uncommon"},{"name":"werebear","rarity":"common"},{"name":"wirewood symbiote","rarity":"uncommon"},{"name":"xantid swarm","rarity":"rare"},{"name":"yavimaya enchantress","rarity":"common"},{"name":"armadillo cloak","rarity":"uncommon"},{"name":"baleful strix","rarity":"rare"},{"name":"bloodbraid elf","rarity":"uncommon"},{"name":"brago, king eternal","rarity":"rare"},{"name":"dack fayden","rarity":"mythic"},{"name":"extract from darkness","rarity":"uncommon"},{"name":"flame-kin zealot","rarity":"uncommon"},{"name":"glare of subdual","rarity":"rare"},{"name":"goblin trenches","rarity":"rare"},{"name":"maelstrom wanderer","rarity":"mythic"},{"name":"shaman of the pack","rarity":"uncommon"},{"name":"shardless agent","rarity":"rare"},{"name":"sphinx of the steel wind","rarity":"mythic"},{"name":"thunderclap wyvern","rarity":"uncommon"},{"name":"trygon predator","rarity":"uncommon"},{"name":"vindicate","rarity":"rare"},{"name":"void","rarity":"rare"},{"name":"wee dragonauts","rarity":"uncommon"},{"name":"zealous persecution","rarity":"uncommon"},{"name":"call the skybreaker","rarity":"rare"},{"name":"deathrite shaman","rarity":"rare"},{"name":"giant solifuge","rarity":"rare"},{"name":"torrent of souls","rarity":"uncommon"},{"name":"ashnod's altar","rarity":"uncommon"},{"name":"chrome mox","rarity":"mythic"},{"name":"duplicant","rarity":"rare"},{"name":"emmessi tome","rarity":"uncommon"},{"name":"goblin charbelcher","rarity":"rare"},{"name":"isochron scepter","rarity":"rare"},{"name":"juggernaut","rarity":"uncommon"},{"name":"mana crypt","rarity":"mythic"},{"name":"millikin","rarity":"uncommon"},{"name":"mindless automaton","rarity":"uncommon"},{"name":"nevinyrral's disk","rarity":"rare"},{"name":"pilgrim's eye","rarity":"common"},{"name":"prismatic lens","rarity":"uncommon"},{"name":"relic of progenitus","rarity":"uncommon"},{"name":"sensei's divining top","rarity":"rare"},{"name":"ticking gnomes","rarity":"uncommon"},{"name":"winter orb","rarity":"rare"},{"name":"worn powerstone","rarity":"uncommon"},{"name":"bloodfell caves","rarity":"common"},{"name":"blossoming sands","rarity":"common"},{"name":"dismal backwater","rarity":"common"},{"name":"jungle hollow","rarity":"common"},{"name":"karakas","rarity":"mythic"},{"name":"maze of ith","rarity":"rare"},{"name":"mishra's factory","rarity":"uncommon"},{"name":"rugged highlands","rarity":"common"},{"name":"scoured barrens","rarity":"common"},{"name":"swiftwater cliffs","rarity":"common"},{"name":"thornwood falls","rarity":"common"},{"name":"tranquil cove","rarity":"common"},{"name":"wasteland","rarity":"rare"},{"name":"wind-scarred crag","rarity":"common"}],
+ booster: ['common', 'common', 'common',
+ 'common', 'common', 'common',
+ 'common', 'common', 'common',
+ 'common', 'uncommon', 'uncommon',
+ 'uncommon', 'rare'],
+};
+for (let i of raw.EMA.cards) {
+ i.types = [null];
+ i.multiverseid = 0;
+}
var COLORS = {
W: 'White',
@@ -16,7 +30,7 @@ var Sets = {}
before()
var types = ['core', 'expansion', 'commander', 'planechase', 'starter', 'un']
-var codes = ['MMA', 'VMA', 'CNS', 'TPR', 'MM2']
+var codes = ['EMA', 'MMA', 'VMA', 'CNS', 'TPR', 'MM2']
for (var code in raw) {
var set = raw[code]
if (types.indexOf(set.type) > -1
@@ -214,6 +228,10 @@ function after() {
}
alias(FRF.special.fetch, 'FRF')
+ let {EMA} = Sets
+ let emaNames = raw.EMA.cards.map(x => x.name)
+ alias(emaNames, 'EMA')
+
Sets.OGW.common.push('wastes')// wastes are twice as common
}
@@ -222,8 +240,13 @@ function alias(arr, code) {
for (var cardName of arr) {
var {sets} = Cards[cardName]
var codes = Object.keys(sets)
- var last = codes[codes.length - 1]
- sets[code] = sets[last]
+ if (code === 'EMA') {
+ var first = codes[0]
+ sets[code] = sets[first]
+ } else {
+ var last = codes[codes.length - 1]
+ sets[code] = sets[last]
+ }
}
}
@@ -275,13 +298,16 @@ function doCard(rawCard, cards, code, set) {
if (rawCard.layout === 'split')
name = rawCard.names.join(' // ')
+
+ //separate landsfrom 0cmc cards by setting 0cmc to .2
+ var cmcadjusted = rawCard.cmc || 0.2
name = _.ascii(name)
if (name in cards) {
if (rawCard.layout === 'split') {
var card = cards[name]
- card.cmc += rawCard.cmc
+ cmcadjusted = card.cmc + rawCard.cmc
if (card.color !== rawCard.color)
card.color = 'multicolor'
}
@@ -292,11 +318,14 @@ function doCard(rawCard, cards, code, set) {
var color = !colors ? 'colorless' :
colors.length > 1 ? 'multicolor' :
colors[0].toLowerCase()
+
+ //set lands to .1 to sort them before nonland 0cmc
+ if ('Land'.indexOf(rawCard.types) > -1)
+ cmcadjusted = 0.1
cards[name] = { color, name,
- manaCost: rawCard.manaCost,
type: rawCard.types[rawCard.types.length - 1],
- cmc: rawCard.cmc || 0,
+ cmc: cmcadjusted,
text: rawCard.text || '',
manaCost: rawCard.manaCost || '',
sets: {
diff --git a/src/router.js b/src/router.js
index 64a5ccb..9fb2fb2 100644
--- a/src/router.js
+++ b/src/router.js
@@ -1,4 +1,4 @@
-const {MOTD} = require('../config')
+const {MOTD} = require('../config.server')
var Game = require('./game')
var Room = require('./room')
var Sock = require('./sock')
diff --git a/src/sock.js b/src/sock.js
index d9021d5..634d8a4 100644
--- a/src/sock.js
+++ b/src/sock.js
@@ -1,4 +1,5 @@
-var {EventEmitter} = require('events')
+let {EventEmitter} = require('events')
+let {STRINGS} = require('../config.server')
// All sockets currently connected to the server.
let allSocks = []
@@ -28,7 +29,7 @@ var mixins = {
class Sock extends EventEmitter {
constructor(ws) {
this.ws = ws
- var {id='', name='ninja'} = ws.request._query
+ var {id='', name=STRINGS.BRANDING.DEFAULT_USERNAME} = ws.request._query
this.id = id.slice(0, 25)
this.name = name.slice(0, 15)