Merge branch 'master' into production

This commit is contained in:
Nick Winter 2014-03-15 07:51:07 -07:00
commit 801eb0a9f7
22 changed files with 196 additions and 46 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

View file

@ -205,6 +205,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
.to({alpha: 0.6, scaleY: @options.camera.y2x, scaleX: 1}, 100, createjs.Ease.circOut) .to({alpha: 0.6, scaleY: @options.camera.y2x, scaleX: 1}, 100, createjs.Ease.circOut)
.to({alpha: 0, scaleY: 0, scaleX: 0}, 700, createjs.Ease.circIn) .to({alpha: 0, scaleY: 0, scaleX: 0}, 700, createjs.Ease.circIn)
.call => .call =>
return if @destroyed
@options.groundLayer.removeChild circle @options.groundLayer.removeChild circle
delete @handledAoEs[event] delete @handledAoEs[event]

View file

@ -23,7 +23,7 @@ module.exports = class CoordinateDisplay extends createjs.Container
build: -> build: ->
@mouseEnabled = @mouseChildren = false @mouseEnabled = @mouseChildren = false
@addChild @label = new createjs.Text("", "20px Arial", "#003300") @addChild @label = new createjs.Text("", "40px Arial", "#003300")
@label.name = 'position text' @label.name = 'position text'
@label.shadow = new createjs.Shadow("#FFFFFF", 1, 1, 0) @label.shadow = new createjs.Shadow("#FFFFFF", 1, 1, 0)

View file

@ -25,10 +25,10 @@ module.exports = class DebugDisplay extends createjs.Container
build: -> build: ->
@mouseEnabled = @mouseChildren = false @mouseEnabled = @mouseChildren = false
@addChild @frameText = new createjs.Text "...", "20px Arial", "#FFF" @addChild @frameText = new createjs.Text "...", "40px Arial", "#FFF"
@frameText.name = 'frame text' @frameText.name = 'frame text'
@frameText.x = @canvasWidth - 50 @frameText.x = @canvasWidth - 100
@frameText.y = @canvasHeight - 25 @frameText.y = @canvasHeight - 50
@frameText.alpha = 0.5 @frameText.alpha = 0.5
updateFrame: (currentFrame) -> updateFrame: (currentFrame) ->
@ -42,4 +42,4 @@ module.exports = class DebugDisplay extends createjs.Container
@framesRenderedThisSecond = 0 @framesRenderedThisSecond = 0
@frameText.text = Math.round(currentFrame) + (if @fps? then " - " + @fps + ' fps' else '') @frameText.text = Math.round(currentFrame) + (if @fps? then " - " + @fps + ' fps' else '')
@frameText.x = @canvasWidth - @frameText.getMeasuredWidth() - 10 @frameText.x = @canvasWidth - @frameText.getMeasuredWidth() - 20

View file

@ -59,7 +59,7 @@ module.exports = class Label extends CocoClass
o.fontWeight = {D: "bold", S: "bold", N: "bold"}[st] o.fontWeight = {D: "bold", S: "bold", N: "bold"}[st]
o.shadow = {D: false, S: true, N: true}[st] o.shadow = {D: false, S: true, N: true}[st]
o.shadowColor = {D: "#FFF", S: "#000", N: "#FFF"}[st] o.shadowColor = {D: "#FFF", S: "#000", N: "#FFF"}[st]
o.fontSize = {D: 25, S: 12, N: 12}[st] o.fontSize = {D: 50, S: 24, N: 24}[st]
fontFamily = {D: "Arial", S: "Arial", N: "Arial"}[st] fontFamily = {D: "Arial", S: "Arial", N: "Arial"}[st]
o.fontDescriptor = "#{o.fontWeight} #{o.fontSize}px #{fontFamily}" o.fontDescriptor = "#{o.fontWeight} #{o.fontSize}px #{fontFamily}"
o.fontColor = {D: "#000", S: "#FFF", N: "#00a"}[st] o.fontColor = {D: "#000", S: "#FFF", N: "#00a"}[st]

View file

@ -81,7 +81,7 @@ module.exports = class Mark extends CocoClass
shape.graphics.endStroke() shape.graphics.endStroke()
shape.graphics.endFill() shape.graphics.endFill()
text = new createjs.Text "" + index, "20px Arial", color.replace('0.5', '1') text = new createjs.Text "" + index, "40px Arial", color.replace('0.5', '1')
text.regX = text.getMeasuredWidth() / 2 text.regX = text.getMeasuredWidth() / 2
text.regY = text.getMeasuredHeight() / 2 text.regY = text.getMeasuredHeight() / 2
text.shadow = new createjs.Shadow("#000000", 1, 1, 0) text.shadow = new createjs.Shadow("#000000", 1, 1, 0)

View file

@ -110,7 +110,13 @@ module.exports = class SpriteBoss extends CocoClass
createOpponentWizard: (opponent) -> createOpponentWizard: (opponent) ->
# TODO: colorize name and cloud by team, colorize wizard by user's color config, level-specific wizard spawn points # TODO: colorize name and cloud by team, colorize wizard by user's color config, level-specific wizard spawn points
sprite = @createWizardSprite thangID: opponent.id, name: opponent.name sprite = @createWizardSprite thangID: opponent.id, name: opponent.name
sprite.targetPos = if opponent.team is 'ogres' then {x: 52, y: 52} else {x: 28, y: 28} if not opponent.levelSlug or opponent.levelSlug is "brawlwood"
sprite.targetPos = if opponent.team is 'ogres' then {x: 52, y: 52} else {x: 28, y: 28}
else if opponent.levelSlug is "dungeon-arena"
sprite.targetPos = if opponent.team is 'ogres' then {x:72, y: 39} else {x: 9, y:39}
else
sprite.targetPos = if opponent.team is 'ogres' then {x:52, y: 28} else {x: 20, y:28}
createWizardSprite: (options) -> createWizardSprite: (options) ->
sprite = new WizardSprite @thangTypeFor("Wizard"), @createSpriteOptions(options) sprite = new WizardSprite @thangTypeFor("Wizard"), @createSpriteOptions(options)
@ -294,7 +300,7 @@ module.exports = class SpriteBoss extends CocoClass
@willSelectThang = [thangID, null] @willSelectThang = [thangID, null]
@updateTarget() @updateTarget()
return unless @selectionMark return unless @selectionMark
@selectedSprite = null unless @selectedSprite?.thang @selectedSprite = null if @selectedSprite and (@selectedSprite.destroyed or not @selectedSprite.thang)
@selectionMark.toggle @selectedSprite? @selectionMark.toggle @selectedSprite?
@selectionMark.setSprite @selectedSprite @selectionMark.setSprite @selectedSprite
@selectionMark.update() @selectionMark.update()

View file

@ -4,6 +4,10 @@
html html
background-color: #2f261d background-color: #2f261d
html, body
// For level loading view wings
overflow-x: hidden
// https://github.com/twbs/bootstrap/issues/9237 -- need a version that's not !important // https://github.com/twbs/bootstrap/issues/9237 -- need a version that's not !important
.secret .secret
display: none display: none

View file

@ -18,8 +18,6 @@
display: block display: block
z-index: 1 z-index: 1
//max-width: 1680px // guideline, but for now let's let it stretch out
min-width: 1024px min-width: 1024px
position: relative position: relative

View file

@ -0,0 +1,65 @@
@import "app/styles/bootstrap/mixins"
@import "app/styles/mixins"
@mixin sky-background($url: '', $backgroundPosition: left)
$top: #95D9EF
$mid: #FFFFFF
$bot: #8EC643
$stop: 99.6%
background: $mid
background-image: url($url) // fallback
background-image: url($url), -webkit-linear-gradient(top, $top, $mid $stop, $bot)
background-image: url($url), -ms-linear-gradient(top, $top, $mid $stop, $bot)
background-image: url($url), linear-gradient(to bottom, $top, $mid $stop, $bot)
background-repeat: no-repeat
background-position: top $backgroundPosition
#level-loading-view
color: blue
width: 100%
height: 100%
position: absolute
z-index: 20
$UNVEIL_TIME: 1.2s
pointer-events: none
.loading-details
position: absolute
top: 20px
left: 50%
$WIDTH: 1000px
width: $WIDTH
margin-left: (-$WIDTH / 2)
z-index: 100
background-color: rgba(220, 255, 230, 0.5)
border-radius: 30px
padding: 10px
text-align: center
// http://matthewlein.com/ceaser/ Bounce down a bit, then snap up.
-webkit-transition: top $UNVEIL_TIME cubic-bezier(0.285, 0, 0.670, 0)
-webkit-transition: top $UNVEIL_TIME cubic-bezier(0.285, -0.595, 0.670, -0.600)
-moz-transition: top $UNVEIL_TIME cubic-bezier(0.285, -0.595, 0.670, -0.600)
-o-transition: top $UNVEIL_TIME cubic-bezier(0.285, -0.595, 0.670, -0.600)
transition: top $UNVEIL_TIME cubic-bezier(0.285, -0.595, 0.670, -0.600)
.load-progress
width: 100%
.progress-bar
width: 1%
transition-duration: 1.2s
.left-wing, .right-wing
width: 100%
height: 100%
position: absolute
.left-wing
@include sky-background('/images/level/loading_left_wing.png', right)
left: -50%
transition: all $UNVEIL_TIME ease
.right-wing
@include sky-background('/images/level/loading_right_wing.png', left)
right: -50%
transition: all $UNVEIL_TIME ease

View file

@ -1,7 +1,6 @@
@import "app/styles/bootstrap/mixins" @import "app/styles/bootstrap/mixins"
@import "app/styles/mixins" @import "app/styles/mixins"
#spectate-level-view #spectate-level-view
#playback-view #playback-view
width: 100% width: 100%
@ -24,12 +23,16 @@
line-height: 15px line-height: 15px
left: 0 left: 0
max-width: 1920px
margin: 0 auto margin: 0 auto
@include user-select(none) @include user-select(none)
#level-loading-view
max-height: 1284px
.level-content .level-content
position: relative position: relative
margin: 0px auto
#canvas-wrapper #canvas-wrapper
height: 100% height: 100%
@ -38,6 +41,8 @@
canvas#surface canvas#surface
background-color: #ddd background-color: #ddd
max-height: 93%
max-height: -webkit-calc(100% - 60px)
max-height: calc(100% - 60px) max-height: calc(100% - 60px)
height: auto height: auto
max-width: 100% max-width: 100%
@ -46,7 +51,6 @@
margin: 0 auto margin: 0 auto
//max-width: 1680px // guideline, but for now let's let it stretch out
min-width: 1024px min-width: 1024px
position: relative position: relative
#thang-hud #thang-hud

View file

@ -27,7 +27,7 @@
div.alert.alert-info div.alert.alert-info
strong Enter strong Enter
| to confirm | to confirm
canvas(width=924, height=590) canvas(width=1920, height=1224)
.modal-footer .modal-footer
a.btn.btn-primary#done-button Done a.btn.btn-primary#done-button Done

View file

@ -17,7 +17,7 @@
.world-container.thangs-column .world-container.thangs-column
h3(data-i18n="editor.level_tab_thangs_conditions") Starting Conditions h3(data-i18n="editor.level_tab_thangs_conditions") Starting Conditions
#canvas-wrapper #canvas-wrapper
canvas(width=924, height=589)#surface canvas(width=1920, height=1224)#surface
#canvas-left-gradient.gradient #canvas-left-gradient.gradient
#canvas-top-gradient.gradient #canvas-top-gradient.gradient

View file

@ -1,3 +1,5 @@
#level-loading-view
.level-content .level-content
#control-bar-view #control-bar-view
@ -7,7 +9,7 @@
#tome-view #tome-view
#canvas-wrapper #canvas-wrapper
canvas(width=924, height=589)#surface canvas(width=1920, height=1224)#surface
#canvas-left-gradient.gradient #canvas-left-gradient.gradient
#canvas-top-gradient.gradient #canvas-top-gradient.gradient

View file

@ -0,0 +1,13 @@
.left-wing
.right-wing
.loading-details
h2(data-i18n='play_level.loading_level') Loading Level
.load-progress
.progress.progress-striped.active
.progress-bar.progress-bar-success
h4 Tip: you can shift+click a position on the map to insert it into the spell editor.

View file

@ -1,7 +1,9 @@
#level-loading-view
.level-content .level-content
#control-bar-view #control-bar-view
#canvas-wrapper #canvas-wrapper
canvas(width=1848, height=1178)#surface canvas(width=1920, height=1224)#surface
#canvas-left-gradient.gradient #canvas-left-gradient.gradient
#canvas-top-gradient.gradient #canvas-top-gradient.gradient
#gold-view.secret.expanded #gold-view.secret.expanded

View file

@ -0,0 +1,40 @@
View = require 'views/kinds/CocoView'
template = require 'templates/play/level/level_loading'
module.exports = class LevelLoadingView extends View
id: "level-loading-view"
template: template
subscriptions:
'level-loader:progress-changed': 'onLevelLoaderProgressChanged'
onLevelLoaderProgressChanged: (e) ->
@progress = e.progress
@updateProgressBar()
updateProgressBar: ->
#@text.text = "BUILDING" if @progress is 1
@$el.find('.progress-bar').css('width', (100 * @progress) + '%')
showReady: ->
return
unveil: ->
_.delay @reallyUnveil, 1000
reallyUnveil: =>
return if @destroyed
loadingDetails = @$el.find('.loading-details')
duration = parseFloat loadingDetails.css 'transition-duration'
loadingDetails.css 'top', -loadingDetails.outerHeight(true)
@$el.find('.left-wing').css left: '-100%', backgroundPosition: 'right -400px top 0'
@$el.find('.right-wing').css right: '-100%', backgroundPosition: 'left -400px top 0'
_.delay @onUnveilEnded, duration * 1000
onUnveilEnded: =>
return if @destroyed
Backbone.Mediator.publish 'onLoadingViewUnveiled', view: @
getRenderData: (c={}) ->
super c
c

View file

@ -22,6 +22,7 @@ Camera = require 'lib/surface/Camera'
AudioPlayer = require 'lib/AudioPlayer' AudioPlayer = require 'lib/AudioPlayer'
# subviews # subviews
LoadingView = require './level/level_loading_view'
TomeView = require './level/tome/tome_view' TomeView = require './level/tome/tome_view'
ChatView = require './level/level_chat_view' ChatView = require './level/level_chat_view'
HUDView = require './level/hud_view' HUDView = require './level/hud_view'
@ -32,8 +33,6 @@ GoldView = require './level/gold_view'
VictoryModal = require './level/modal/victory_modal' VictoryModal = require './level/modal/victory_modal'
InfiniteLoopModal = require './level/modal/infinite_loop_modal' InfiniteLoopModal = require './level/modal/infinite_loop_modal'
LoadingScreen = require 'lib/LoadingScreen'
PROFILE_ME = false PROFILE_ME = false
module.exports = class PlayLevelView extends View module.exports = class PlayLevelView extends View
@ -62,6 +61,8 @@ module.exports = class PlayLevelView extends View
'level:session-will-save': 'onSessionWillSave' 'level:session-will-save': 'onSessionWillSave'
'level:set-team': 'setTeam' 'level:set-team': 'setTeam'
'god:new-world-created': 'loadSoundsForWorld' 'god:new-world-created': 'loadSoundsForWorld'
'level:started': 'onLevelStarted'
'level:loading-view-unveiled': 'onLoadingViewUnveiled'
events: events:
'click #level-done-button': 'onDonePressed' 'click #level-done-button': 'onDonePressed'
@ -122,8 +123,7 @@ module.exports = class PlayLevelView extends View
afterRender: -> afterRender: ->
window.onPlayLevelViewLoaded? @ # still a hack window.onPlayLevelViewLoaded? @ # still a hack
@loadingScreen = new LoadingScreen(@$el.find('canvas')[0]) @insertSubView @loadingView = new LoadingView {}
@loadingScreen.show()
@$el.find('#level-done-button').hide() @$el.find('#level-done-button').hide()
super() super()
@ -149,16 +149,15 @@ module.exports = class PlayLevelView extends View
onLevelLoaderLoaded: -> onLevelLoaderLoaded: ->
return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early
# Save latest level played in local storage
if window.currentModal and not window.currentModal.destroyed if window.currentModal and not window.currentModal.destroyed
@loadingScreen.showReady() @loadingView.showReady()
return Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaderLoaded, @ return Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaderLoaded, @
# Save latest level played in local storage
localStorage["lastLevel"] = @levelID if localStorage? localStorage["lastLevel"] = @levelID if localStorage?
@grabLevelLoaderData() @grabLevelLoaderData()
team = @getQueryVariable("team") ? @world.teamForPlayer(0) team = @getQueryVariable("team") ? @world.teamForPlayer(0)
@loadOpponentTeam(team) @loadOpponentTeam(team)
@loadingScreen.destroy()
@god.level = @level.serialize @supermodel @god.level = @level.serialize @supermodel
@god.worldClassMap = @world.classMap @god.worldClassMap = @world.classMap
@setTeam team @setTeam team
@ -202,6 +201,12 @@ module.exports = class PlayLevelView extends View
# For now, ladderGame will disallow multiplayer, because session code combining doesn't play nice yet. # For now, ladderGame will disallow multiplayer, because session code combining doesn't play nice yet.
@session.set 'multiplayer', false @session.set 'multiplayer', false
onLevelStarted: (e) ->
@loadingView?.unveil()
onLoadingViewUnveiled: (e) ->
@removeSubView @loadingView
@loadingView = null
onSupermodelLoadedOne: => onSupermodelLoadedOne: =>
@modelsLoaded ?= 0 @modelsLoaded ?= 0

View file

@ -20,6 +20,7 @@ Camera = require 'lib/surface/Camera'
AudioPlayer = require 'lib/AudioPlayer' AudioPlayer = require 'lib/AudioPlayer'
# subviews # subviews
LoadingView = require './level/level_loading_view'
TomeView = require './level/tome/tome_view' TomeView = require './level/tome/tome_view'
ChatView = require './level/level_chat_view' ChatView = require './level/level_chat_view'
HUDView = require './level/hud_view' HUDView = require './level/hud_view'
@ -30,8 +31,6 @@ GoldView = require './level/gold_view'
VictoryModal = require './level/modal/victory_modal' VictoryModal = require './level/modal/victory_modal'
InfiniteLoopModal = require './level/modal/infinite_loop_modal' InfiniteLoopModal = require './level/modal/infinite_loop_modal'
LoadingScreen = require 'lib/LoadingScreen'
PROFILE_ME = false PROFILE_ME = false
module.exports = class SpectateLevelView extends View module.exports = class SpectateLevelView extends View
@ -57,6 +56,8 @@ module.exports = class SpectateLevelView extends View
'level:set-team': 'setTeam' 'level:set-team': 'setTeam'
'god:new-world-created': 'loadSoundsForWorld' 'god:new-world-created': 'loadSoundsForWorld'
'next-game-pressed': 'onNextGamePressed' 'next-game-pressed': 'onNextGamePressed'
'level:started': 'onLevelStarted'
'level:loading-view-unveiled': 'onLoadingViewUnveiled'
events: events:
'click #level-done-button': 'onDonePressed' 'click #level-done-button': 'onDonePressed'
@ -73,6 +74,10 @@ module.exports = class SpectateLevelView extends View
@sessionOne = @getQueryVariable 'session-one' @sessionOne = @getQueryVariable 'session-one'
@sessionTwo = @getQueryVariable 'session-two' @sessionTwo = @getQueryVariable 'session-two'
if options.spectateSessions
@sessionOne = options.spectateSessions.sessionOne
@sessionTwo = options.spectateSessions.sessionTwo
if not @sessionOne or not @sessionTwo if not @sessionOne or not @sessionTwo
@fetchRandomSessionPair (err, data) => @fetchRandomSessionPair (err, data) =>
if err? then return console.log "There was an error fetching the random session pair: #{data}" if err? then return console.log "There was an error fetching the random session pair: #{data}"
@ -112,8 +117,7 @@ module.exports = class SpectateLevelView extends View
afterRender: -> afterRender: ->
window.onPlayLevelViewLoaded? @ # still a hack window.onPlayLevelViewLoaded? @ # still a hack
@loadingScreen = new LoadingScreen(@$el.find('canvas')[0]) @insertSubView @loadingView = new LoadingView {}
@loadingScreen.show()
@$el.find('#level-done-button').hide() @$el.find('#level-done-button').hide()
super() super()
@ -141,14 +145,13 @@ module.exports = class SpectateLevelView extends View
return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early
# Save latest level played in local storage # Save latest level played in local storage
if window.currentModal and not window.currentModal.destroyed if window.currentModal and not window.currentModal.destroyed
@loadingScreen.showReady() @loadingView.showReady()
return Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaderLoaded, @ return Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaderLoaded, @
@grabLevelLoaderData() @grabLevelLoaderData()
#at this point, all requisite data is loaded, and sessions are not denormalized #at this point, all requisite data is loaded, and sessions are not denormalized
team = @world.teamForPlayer(0) team = @world.teamForPlayer(0)
@loadOpponentTeam(team) @loadOpponentTeam(team)
@loadingScreen.destroy()
@god.level = @level.serialize @supermodel @god.level = @level.serialize @supermodel
@god.worldClassMap = @world.classMap @god.worldClassMap = @world.classMap
@setTeam team @setTeam team
@ -167,11 +170,13 @@ module.exports = class SpectateLevelView extends View
id: @session.get('creator') id: @session.get('creator')
name: @session.get('creatorName') name: @session.get('creatorName')
team: @session.get('team') team: @session.get('team')
levelSlug: @level.get('slug')
@surface.createOpponentWizard @surface.createOpponentWizard
id: @otherSession.get('creator') id: @otherSession.get('creator')
name: @otherSession.get('creatorName') name: @otherSession.get('creatorName')
team: @otherSession.get('team') team: @otherSession.get('team')
levelSlug: @level.get('slug')
grabLevelLoaderData: -> grabLevelLoaderData: ->
@session = @levelLoader.session @session = @levelLoader.session
@ -199,6 +204,12 @@ module.exports = class SpectateLevelView extends View
# For now, ladderGame will disallow multiplayer, because session code combining doesn't play nice yet. # For now, ladderGame will disallow multiplayer, because session code combining doesn't play nice yet.
@session.set 'multiplayer', false @session.set 'multiplayer', false
onLevelStarted: (e) ->
@loadingView?.unveil()
onLoadingViewUnveiled: (e) ->
@removeSubView @loadingView
@loadingView = null
onSupermodelLoadedOne: => onSupermodelLoadedOne: =>
@modelsLoaded ?= 0 @modelsLoaded ?= 0
@ -429,12 +440,11 @@ module.exports = class SpectateLevelView extends View
if err? then return console.log "There was an error fetching the random session pair: #{data}" if err? then return console.log "There was an error fetching the random session pair: #{data}"
@sessionOne = data[0]._id @sessionOne = data[0]._id
@sessionTwo = data[1]._id @sessionTwo = data[1]._id
console.log "Playing session #{@sessionOne} against #{@sessionTwo}" url = "/play/spectate/#{@levelID}?session-one=#{@sessionOne}&session-two=#{@sessionTwo}"
url = "/play/spectate/dungeon-arena?session-one=#{@sessionOne}&session-two=#{@sessionTwo}"
Backbone.Mediator.publish 'router:navigate', { Backbone.Mediator.publish 'router:navigate', {
route: url, route: url,
viewClass: SpectateLevelView, viewClass: SpectateLevelView,
viewArgs: [{spectateSessions:{sessionOne: @sessionOne, sessionTwo: @sessionTwo}}, "dungeon-arena"]} viewArgs: [{spectateSessions:{sessionOne: @sessionOne, sessionTwo: @sessionTwo}}, @levelID ]}
fetchRandomSessionPair: (cb) -> fetchRandomSessionPair: (cb) ->
console.log "Fetching random session pair!" console.log "Fetching random session pair!"

View file

@ -100,8 +100,8 @@ sendLadderUpdateEmail = (session, daysAgo) ->
context = context =
email_id: sendwithus.templates.ladder_update_email email_id: sendwithus.templates.ladder_update_email
recipient: recipient:
#address: user.email address: user.email
address: 'nick@codecombat.com' # Debugging #address: 'nick@codecombat.com' # Debugging
name: name name: name
email_data: email_data:
name: name name: name