Merge branch 'master' into production

This commit is contained in:
Nick Winter 2014-05-18 13:46:47 -07:00
commit 83df107cdf
24 changed files with 244 additions and 248 deletions

View file

@ -187,12 +187,19 @@ self.retrieveValueFromFrame = function retrieveValueFromFrame(args) {
else if (i === 0) else if (i === 0)
{ {
try try
{
if (Aether.globals[prop])
{
value = Aether.globals[prop];
}
else
{ {
var flowStates = self.debugWorld.userCodeMap[currentThangID][currentSpellID].flow.states; var flowStates = self.debugWorld.userCodeMap[currentThangID][currentSpellID].flow.states;
//we have to go to the second last flowState as we run the world for one additional frame //we have to go to the second last flowState as we run the world for one additional frame
//to collect the flow //to collect the flow
value = _.last(flowStates[flowStates.length - 1].statements).variables[prop]; value = _.last(flowStates[flowStates.length - 1].statements).variables[prop];
} }
}
catch (e) catch (e)
{ {
value = undefined; value = undefined;

View file

@ -69,7 +69,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
@marks = {} @marks = {}
@labels = {} @labels = {}
@ranges = [] @ranges = []
@handledAoEs = {} @handledDisplayEvents = {}
@age = 0 @age = 0
@scaleFactor = @targetScaleFactor = 1 @scaleFactor = @targetScaleFactor = 1
if @thangType.isFullyLoaded() if @thangType.isFullyLoaded()
@ -213,6 +213,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
@updatePosition() @updatePosition()
frameChanged = frameChanged or @targetScaleFactor isnt @scaleFactor frameChanged = frameChanged or @targetScaleFactor isnt @scaleFactor
if frameChanged if frameChanged
@handledDisplayEvents = {}
@updateScale() # must happen before rotation @updateScale() # must happen before rotation
@updateAlpha() @updateAlpha()
@updateRotation() @updateRotation()
@ -220,6 +221,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
@updateStats() @updateStats()
@updateGold() @updateGold()
@showAreaOfEffects() @showAreaOfEffects()
@showTextEvents()
@updateHealthBar() @updateHealthBar()
@updateMarks() @updateMarks()
@updateLabels() @updateLabels()
@ -228,9 +230,9 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
return unless @thang?.currentEvents return unless @thang?.currentEvents
for event in @thang.currentEvents for event in @thang.currentEvents
continue unless event.startsWith 'aoe-' continue unless event.startsWith 'aoe-'
continue if @handledAoEs[event] continue if @handledDisplayEvents[event]
@handledAoEs[event] = true @handledDisplayEvents[event] = true
args = JSON.parse(event[4...]) args = JSON.parse(event[4...])
pos = @options.camera.worldToSurface {x:args[0], y:args[1]} pos = @options.camera.worldToSurface {x:args[0], y:args[1]}
circle = new createjs.Shape() circle = new createjs.Shape()
@ -248,7 +250,31 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
.call => .call =>
return if @destroyed return if @destroyed
@options.groundLayer.removeChild circle @options.groundLayer.removeChild circle
delete @handledAoEs[event] delete @handledDisplayEvents[event]
showTextEvents: ->
return unless @thang?.currentEvents
for event in @thang.currentEvents
continue unless event.startsWith 'text-'
continue if @handledDisplayEvents[event]
@handledDisplayEvents[event] = true
options = JSON.parse(event[5...])
label = new createjs.Text options.text, "bold #{options.size or 16}px Arial", options.color or '#FFF'
label.shadow = new createjs.Shadow '#000', 0, 0, 2
offset = @getOffset 'aboveHead'
[label.x, label.y] = [@imageObject.x + offset.x - label.getMeasuredWidth() / 2, @imageObject.y + offset.y]
@options.floatingLayer.addChild label
window.labels ?= []
window.labels.push label
label.alpha = 0
createjs.Tween.get(label)
.to({y:label.y-2, alpha:1}, 200, createjs.Ease.linear)
.to({y:label.y-12}, 1000, createjs.Ease.linear)
.to({y:label.y-22, alpha:0}, 1000, createjs.Ease.linear)
.call =>
return if @destroyed
@options.floatingLayer.removeChild label
cache: -> cache: ->
bounds = @imageObject.getBounds() bounds = @imageObject.getBounds()
@ -472,7 +498,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
Backbone.Mediator.publish ourEventName, newEvent Backbone.Mediator.publish ourEventName, newEvent
addHealthBar: -> addHealthBar: ->
return unless @thang?.health? and "health" in (@thang?.hudProperties ? []) return unless @thang?.health? and "health" in (@thang?.hudProperties ? []) and @options.floatingLayer
healthColor = healthColors[@thang?.team] ? healthColors["neutral"] healthColor = healthColors[@thang?.team] ? healthColors["neutral"]
healthOffset = @getOffset 'aboveHead' healthOffset = @getOffset 'aboveHead'
bar = @healthBar = createProgressBar(healthColor, healthOffset) bar = @healthBar = createProgressBar(healthColor, healthOffset)

View file

@ -20,7 +20,7 @@ module.exports = class Mark extends CocoClass
@build() @build()
destroy: -> destroy: ->
createjs.Tween.removeTweens @mark createjs.Tween.removeTweens @mark if @mark
@mark?.parent?.removeChild @mark @mark?.parent?.removeChild @mark
@markSprite?.destroy() @markSprite?.destroy()
@sprite = null @sprite = null

View file

@ -591,12 +591,14 @@ module.exports = Surface = class Surface extends CocoClass
@mouseInBounds = mib @mouseInBounds = mib
restoreWorldState: -> restoreWorldState: ->
@world.getFrame(@getCurrentFrame()).restoreState() frame = @world.getFrame(@getCurrentFrame())
frame.restoreState()
current = Math.max(0, Math.min(@currentFrame, @world.totalFrames - 1)) current = Math.max(0, Math.min(@currentFrame, @world.totalFrames - 1))
if current - Math.floor(current) > 0.01 if current - Math.floor(current) > 0.01
next = Math.ceil current next = Math.ceil current
ratio = current % 1 ratio = current % 1
@world.frames[next].restorePartialState ratio if next > 1 @world.frames[next].restorePartialState ratio if next > 1
frame.clearEvents() if parseInt(@currentFrame) is parseInt(@lastFrame)
@spriteBoss.updateSounds() @spriteBoss.updateSounds()
updateState: (frameChanged) -> updateState: (frameChanged) ->

View file

@ -37,6 +37,8 @@ module.exports = class WorldFrame
return return
thangState.restore() thangState.restore()
clearEvents: -> thang.currentEvents = [] for thang in @world.thangs
toString: -> toString: ->
map = ((' ' for x in [0 .. @world.width]) \ map = ((' ' for x in [0 .. @world.width]) \
for y in [0 .. @world.height]) for y in [0 .. @world.height])

View file

@ -233,8 +233,6 @@
victory_sign_up: "Sign Up to Save Progress" victory_sign_up: "Sign Up to Save Progress"
victory_sign_up_poke: "Want to save your code? Create a free account!" victory_sign_up_poke: "Want to save your code? Create a free account!"
victory_rate_the_level: "Rate the level: " victory_rate_the_level: "Rate the level: "
victory_rank_my_game: "Rank My Game"
victory_ranking_game: "Submitting..."
victory_return_to_ladder: "Return to Ladder" victory_return_to_ladder: "Return to Ladder"
victory_play_next_level: "Play Next Level" victory_play_next_level: "Play Next Level"
victory_go_home: "Go Home" victory_go_home: "Go Home"

View file

@ -36,11 +36,11 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
nav: nav:
play: "Jugar" play: "Jugar"
# community: "Community" community: "Comunidad"
editor: "Editor" editor: "Editor"
blog: "Blog" blog: "Blog"
forum: "Foro" forum: "Foro"
# account: "Account" account: "Cuenta"
admin: "Admin" admin: "Admin"
home: "Inicio" home: "Inicio"
contribute: "Colaborar" contribute: "Colaborar"
@ -152,7 +152,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
autosave: "Los cambios se guardan automáticamente" autosave: "Los cambios se guardan automáticamente"
me_tab: "Yo" me_tab: "Yo"
picture_tab: "Foto" picture_tab: "Foto"
# upload_picture: "Upload a picture" upload_picture: "Sube una imagen"
wizard_tab: "Mago" wizard_tab: "Mago"
password_tab: "Contraseña" password_tab: "Contraseña"
emails_tab: "Correos electrónicos" emails_tab: "Correos electrónicos"
@ -168,7 +168,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
# email_any_notes: "Any Notifications" # email_any_notes: "Any Notifications"
# email_any_notes_description: "Disable to stop all activity notification emails." # email_any_notes_description: "Disable to stop all activity notification emails."
# email_recruit_notes: "Job Opportunities" # email_recruit_notes: "Job Opportunities"
# email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job." email_recruit_notes_description: "Si tu juegas realmente bien, puede que contactemos contigo para que consigas un trabajo (mejor)."
contributor_emails: "Correos para colaboradores" contributor_emails: "Correos para colaboradores"
contribute_prefix: "¡Buscamos gente que se una a nuestro comunidad! Comprueba la " contribute_prefix: "¡Buscamos gente que se una a nuestro comunidad! Comprueba la "
contribute_page: "página de colaboraciones" contribute_page: "página de colaboraciones"
@ -180,8 +180,8 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
job_profile: "Perfil de trabajo" job_profile: "Perfil de trabajo"
job_profile_approved: "Tu perfil de trabajo ha sido aprobado por CodeCombat. Los empleadores podrán verlo hasta que lo marques como inactivo o no haya sido cambiado durante cuatro semanas." job_profile_approved: "Tu perfil de trabajo ha sido aprobado por CodeCombat. Los empleadores podrán verlo hasta que lo marques como inactivo o no haya sido cambiado durante cuatro semanas."
job_profile_explanation: "¡Hola! Rellena esto y estaremos en contacto para hablar sobre encontrarte un trabajo como desarrollador de software." job_profile_explanation: "¡Hola! Rellena esto y estaremos en contacto para hablar sobre encontrarte un trabajo como desarrollador de software."
# sample_profile: "See a sample profile" sample_profile: "Mira un perfil de ejemplo"
# view_profile: "View Your Profile" view_profile: "Mira tu perfil"
account_profile: account_profile:
edit_settings: "Ajustes" edit_settings: "Ajustes"
@ -199,7 +199,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
employers: employers:
want_to_hire_our_players: "¿Quieres contratar jugadores expertos de CodeCombat?" want_to_hire_our_players: "¿Quieres contratar jugadores expertos de CodeCombat?"
# see_candidates: "Click here to see our candidates" see_candidates: "Click aquí para ver a nuestros candidatos"
candidates_count_prefix: "Actualmente tenemos " candidates_count_prefix: "Actualmente tenemos "
candidates_count_many: "muchos" candidates_count_many: "muchos"
candidates_count_suffix: "desarrolladores altamente cualificados, y examinados atentamente, buscando trabajo." candidates_count_suffix: "desarrolladores altamente cualificados, y examinados atentamente, buscando trabajo."
@ -210,8 +210,8 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
candidate_top_skills: "Mejores Habilidades" candidate_top_skills: "Mejores Habilidades"
candidate_years_experience: "Años Exp" candidate_years_experience: "Años Exp"
candidate_last_updated: "Última actualización" candidate_last_updated: "Última actualización"
# candidate_approved: "Us?" candidate_approved: "¿Nosotros?"
# candidate_active: "Them?" candidate_active: "¿Ellos?"
play_level: play_level:
level_load_error: "No se pudo cargar el nivel: " level_load_error: "No se pudo cargar el nivel: "
@ -246,7 +246,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
multiplayer_hint_label: "Pista:" multiplayer_hint_label: "Pista:"
multiplayer_hint: " Haz un click en el link para que se seleccione, después utiliza Ctrl-C o ⌘-C para copiar el link." multiplayer_hint: " Haz un click en el link para que se seleccione, después utiliza Ctrl-C o ⌘-C para copiar el link."
multiplayer_coming_soon: "¡Más opciones de Multijugador están por venir!" multiplayer_coming_soon: "¡Más opciones de Multijugador están por venir!"
# multiplayer_sign_in_leaderboard: "Sign in or create an account and get your solution on the leaderboard." multiplayer_sign_in_leaderboard: "Logueate o crea una cuentra para guardar tus resultados en la tabla de clasificación."
guide_title: "Guía" guide_title: "Guía"
tome_minion_spells: "Los hechizos de tus súbditos" tome_minion_spells: "Los hechizos de tus súbditos"
tome_read_only_spells: "Hechizos de solo lectura" tome_read_only_spells: "Hechizos de solo lectura"
@ -321,9 +321,9 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
lg_title: "Últimos Juegos" lg_title: "Últimos Juegos"
clas: "CLAs" clas: "CLAs"
# community: community:
# level_editor: "Level Editor" level_editor: "Editor de niveles"
# main_title: "CodeCombat Community" main_title: "Comunidad de CodeCombat"
# facebook: "Facebook" # facebook: "Facebook"
# twitter: "Twitter" # twitter: "Twitter"
# gplus: "Google+" # gplus: "Google+"
@ -337,7 +337,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
thang_description: "Construye unidades, su lógica predeterminada, gráficos y audio. Actualmente sólo se permite importar gráficos vectoriales exportados de Flash." thang_description: "Construye unidades, su lógica predeterminada, gráficos y audio. Actualmente sólo se permite importar gráficos vectoriales exportados de Flash."
level_title: "Editor de Niveles" level_title: "Editor de Niveles"
level_description: "Incluye las herramientas para escribir scripts, subir audio, y construir una lógica personalidad con la que crear todo tipo de niveles. ¡Todo lo que usamos nosotros!" level_description: "Incluye las herramientas para escribir scripts, subir audio, y construir una lógica personalidad con la que crear todo tipo de niveles. ¡Todo lo que usamos nosotros!"
# got_questions: "Questions about using the CodeCombat editors?" got_questions: "¿Preguntas sobre el uso de los editores CodeCombat?"
contact_us: "¡Contacta con nosotros!" contact_us: "¡Contacta con nosotros!"
hipchat_prefix: "También puedes encontrarnos en nuestra" hipchat_prefix: "También puedes encontrarnos en nuestra"
hipchat_url: "sala de HipChat." hipchat_url: "sala de HipChat."
@ -379,9 +379,9 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
new_article_title: "Crear un nuevo artículo" new_article_title: "Crear un nuevo artículo"
new_thang_title: "Crea un nuevo tipo de objeto" new_thang_title: "Crea un nuevo tipo de objeto"
new_level_title: "Crear un nuevo nivel" new_level_title: "Crear un nuevo nivel"
# new_article_title_signup: "Sign Up to Create a New Article" new_article_title_signup: "Registrarte para crear un nuevo artículo"
# new_thang_title_signup: "Sign Up to Create a New Thang Type" # new_thang_title_signup: "Sign Up to Create a New Thang Type"
# new_level_title_signup: "Sign Up to Create a New Level" new_level_title_signup: "Registrarte para crear un nuevo nivel"
article_search_title: "Buscar artículos aquí" article_search_title: "Buscar artículos aquí"
thang_search_title: "Busca tipos de objetos aquí" thang_search_title: "Busca tipos de objetos aquí"
level_search_title: "Buscar niveles aquí" level_search_title: "Buscar niveles aquí"
@ -651,11 +651,11 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
simple_ai: "IA sencilla" simple_ai: "IA sencilla"
warmup: "calentamiento" warmup: "calentamiento"
vs: "VS" vs: "VS"
# friends_playing: "Friends Playing" friends_playing: "Amigos jugando"
# sign_up_for_friends: "Sign up to play with your friends!" sign_up_for_friends: "¡Registrate para jugar con tus amigos!"
# social_connect_blurb: "Connect and play against your friends!" social_connect_blurb: "¡Conectate y juega contra tus amigos!"
# invite_friends_to_battle: "Invite your friends to join you in battle!" invite_friends_to_battle: "¡Invita a tus amigos a unirse a la batalla!"
# fight: "Fight!" fight: "¡Pelea!"
# watch_victory: "Watch your victory" # watch_victory: "Watch your victory"
# defeat_the: "Defeat the" # defeat_the: "Defeat the"
@ -700,15 +700,15 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
user_profile: "Perfil de usuario" user_profile: "Perfil de usuario"
patches: "Parches" patches: "Parches"
model: "Modelo" model: "Modelo"
# system: "System" system: "Sistema"
# component: "Component" component: "Componente"
# components: "Components" components: "Componentes"
# thang: "Thang" # thang: "Thang"
# thangs: "Thangs" # thangs: "Thangs"
# level_session: "Your Session" level_session: "Tu sesión"
# opponent_session: "Opponent Session" opponent_session: "Sesión del oponente"
# article: "Article" article: "Artículo"
# user_names: "User Names" user_names: "Nombres de usuarios"
# files: "Files" files: "Archivos"
# top_simulators: "Top Simulators" top_simulators: "Top simuladores"
# source_document: "Source Document" source_document: "Documento fuente"

View file

@ -0,0 +1,3 @@
.ladder-submission-view
h3
text-decoration: underline

View file

@ -0,0 +1,7 @@
button.btn.btn-success.rank-button
span(data-i18n="ladder.rank_no_code").unavailable.hidden No New Code to Rank
span(data-i18n="ladder.rank_my_game").rank.hidden Rank My Game!
span(data-i18n="ladder.rank_submitting").submitting.hidden Submitting...
span(data-i18n="ladder.rank_submitted").submitted.hidden Submitted for Ranking
span(data-i18n="ladder.rank_failed").failed.hidden Failed to Rank
span(data-i18n="ladder.rank_being_ranked").ranking.hidden Game Being Ranked

View file

@ -31,6 +31,11 @@ block content
a(href="#my-matches", data-toggle="tab", data-i18n="ladder.my_matches") My Matches a(href="#my-matches", data-toggle="tab", data-i18n="ladder.my_matches") My Matches
li li
a(href="#simulate", data-toggle="tab", data-i18n="ladder.simulate") Simulate a(href="#simulate", data-toggle="tab", data-i18n="ladder.simulate") Simulate
if level.get('name') == 'Greed'
li
a(href="#prizes", data-toggle="tab", data-i18n="ladder.prizes") Prizes
li
a(href="#rules", data-toggle="tab", data-i18n="ladder.rules") Rules
div.tab-content div.tab-content
.tab-pane.active.well#ladder .tab-pane.active.well#ladder
@ -39,3 +44,9 @@ block content
#my-matches-tab-view #my-matches-tab-view
.tab-pane.well#simulate .tab-pane.well#simulate
#simulate-tab-view #simulate-tab-view
.tab-pane.well#prizes
h1(data-i18n="ladder.prizes_remember_to_add_i18n_tags") Tournament Prizes
p(data-i18n="ladder.prizes_but_this_is_just_placeholder") Fill in the Greed prizes list here.
.tab-pane.well#rules
h1(data-i18n="ladder.rules_remember_to_add_i18n_tags") Tournament Rules
p(data-i18n="ladder.rules_but_this_is_just_placeholder") We probably don't have to translate legal documents from English, but we should translate any conversational summary.

View file

@ -1,9 +1,3 @@
//if matches.length
// p#your-score
// span Your Current Score:
// span
// strong= score
div#columns.row div#columns.row
for team in teams for team in teams
div.matches-column.col-md-6 div.matches-column.col-md-6
@ -23,21 +17,13 @@ div#columns.row
if team.session if team.session
tr tr
th(colspan=4) th(colspan=4)
button.btn.btn-warning.btn-block.rank-button(data-session-id=team.session.id) .ladder-submission-view(data-session-id=team.session.id)
span(data-i18n="ladder.rank_no_code").unavailable.hidden No New Code to Rank
span(data-i18n="ladder.rank_my_game").rank.hidden Rank My Game!
span(data-i18n="ladder.rank_submitting").submitting.hidden Submitting...
span(data-i18n="ladder.rank_submitted").submitted.hidden Submitted for Ranking
span(data-i18n="ladder.rank_failed").failed.hidden Failed to Rank
span(data-i18n="ladder.rank_being_ranked").ranking.hidden Game Being Ranked
if team.chartData if team.scoreHistory
tr tr
th(colspan=4, style="color: #{team.primaryColor}") th(colspan=4, style="color: #{team.primaryColor}")
div(class="score-chart-wrapper", data-team-name=team.name, id="score-chart-#{team.name}") div(class="score-chart-wrapper", data-team-name=team.name, id="score-chart-#{team.name}")
tr tr
th(data-i18n="general.result") Result th(data-i18n="general.result") Result
th(data-i18n="general.opponent") Opponent th(data-i18n="general.opponent") Opponent

View file

@ -29,7 +29,7 @@ block modal-body-content
if me.get('anonymous') if me.get('anonymous')
p(data-i18n="play_level.multiplayer_sign_in_leaderboard") Sign in or create an account and get your solution on the leaderboard. p(data-i18n="play_level.multiplayer_sign_in_leaderboard") Sign in or create an account and get your solution on the leaderboard.
else if readyToRank else if readyToRank
button.btn.btn-success.rank-game-button(data-i18n="play_level.victory_rank_my_game") Rank My Game .ladder-submission-view
else else
a.btn.btn-primary(href="/play/ladder/#{levelSlug}#my-matches", data-i18n="play_level.victory_go_ladder") Return to Ladder a.btn.btn-primary(href="/play/ladder/#{levelSlug}#my-matches", data-i18n="play_level.victory_go_ladder") Return to Ladder

View file

@ -12,7 +12,7 @@ block modal-body-content
block modal-footer-content block modal-footer-content
if readyToRank if readyToRank
button.btn.btn-success.rank-game-button(data-i18n="play_level.victory_rank_my_game") Rank My Game .ladder-submission-view
else if level.get('type') === 'ladder' else if level.get('type') === 'ladder'
a.btn.btn-primary(href="/play/ladder/#{level.get('slug')}#my-matches", data-dismiss="modal", data-i18n="play_level.victory_go_ladder") Return to Ladder a.btn.btn-primary(href="/play/ladder/#{level.get('slug')}#my-matches", data-dismiss="modal", data-i18n="play_level.victory_go_ladder") Return to Ladder
else if hasNextLevel else if hasNextLevel

View file

@ -221,8 +221,8 @@ module.exports = class ThangTypeEditView extends View
@showMovieClip(animationName) @showMovieClip(animationName)
else else
@showSprite(animationName) @showSprite(animationName)
@updateScale()
@updateRotation() @updateRotation()
@updateScale() # must happen after update rotation, because updateRotation calls the sprite update() method.
showMovieClip: (animationName) -> showMovieClip: (animationName) ->
vectorParser = new SpriteBuilder(@thangType) vectorParser = new SpriteBuilder(@thangType)
@ -279,11 +279,12 @@ module.exports = class ThangTypeEditView extends View
@currentSprite.update(true) @currentSprite.update(true)
updateScale: => updateScale: =>
value = (@scaleSlider.slider('value') + 1) / 10 resValue = (@resolutionSlider.slider('value') + 1) / 10
fixed = value.toFixed(1) scaleValue = (@scaleSlider.slider('value') + 1) / 10
@scale = value fixed = scaleValue.toFixed(1)
@scale = scaleValue
@$el.find('.scale-label').text " #{fixed}x " @$el.find('.scale-label').text " #{fixed}x "
@currentObject.scaleX = @currentObject.scaleY = value if @currentObject? @currentObject.scaleX = @currentObject.scaleY = scaleValue / resValue if @currentObject?
@updateGrid() @updateGrid()
@updateDots() @updateDots()

View file

@ -0,0 +1,88 @@
CocoView = require 'views/kinds/CocoView'
template = require 'templates/play/common/ladder_submission'
module.exports = class LadderSubmissionView extends CocoView
class: "ladder-submission-view"
template: template
events:
'click .rank-button': 'rankSession'
constructor: (options) ->
super options
@session = options.session
@level = options.level
getRenderData: ->
ctx = super()
ctx.readyToRank = @session?.readyToRank()
ctx.isRanking = @ession?.get('isRanking')
ctx
afterRender: ->
super()
return unless @supermodel.finished()
@rankButton = @$el.find('.rank-button')
@updateButton()
updateButton: ->
rankingState = 'unavailable'
if @session?.readyToRank()
rankingState = 'rank'
else if @session?.get 'isRanking'
rankingState = 'ranking'
@setRankingButtonText rankingState
setRankingButtonText: (spanClass) ->
@rankButton.find('span').addClass('hidden')
@rankButton.find(".#{spanClass}").removeClass('hidden')
@rankButton.toggleClass 'disabled', spanClass isnt 'rank'
rankSession: (e) ->
return unless @session.readyToRank()
@setRankingButtonText 'submitting'
success = =>
@setRankingButtonText 'submitted' unless @destroyed
Backbone.Mediator.publish 'ladder:game-submitted', session: @session, level: @level
failure = (jqxhr, textStatus, errorThrown) =>
console.log jqxhr.responseText
@setRankingButtonText 'failed' unless @destroyed
transpiledCode = @transpileSession()
ajaxData =
session: @session.id
levelID: @level.id
originalLevelID: @level.get('original')
levelMajorVersion: @level.get('version').major
transpiledCode: transpiledCode
$.ajax '/queue/scoring', {
type: 'POST'
data: ajaxData
success: success
error: failure
}
transpileSession: ->
submittedCode = @session.get('code')
transpiledCode = {}
for thang, spells of submittedCode
transpiledCode[thang] = {}
for spellID, spell of spells
unless _.contains(@session.get('teamSpells')[@session.get('team')], thang + "/" + spellID) then continue
#DRY this
aetherOptions =
problems: {}
language: "javascript"
functionName: spellID
functionParameters: []
yieldConditionally: spellID is "plan"
globals: ['Vector', '_']
protectAPI: true
includeFlow: false
if spellID is "hear" then aetherOptions["functionParameters"] = ["speaker","message","data"]
aether = new Aether aetherOptions
transpiledCode[thang][spellID] = aether.transpile spell
transpiledCode

View file

@ -2,6 +2,7 @@ CocoView = require 'views/kinds/CocoView'
Level = require 'models/Level' Level = require 'models/Level'
LevelSession = require 'models/LevelSession' LevelSession = require 'models/LevelSession'
LeaderboardCollection = require 'collections/LeaderboardCollection' LeaderboardCollection = require 'collections/LeaderboardCollection'
LadderSubmissionView = require 'views/play/common/ladder_submission_view'
{teamDataFromLevel} = require './utils' {teamDataFromLevel} = require './utils'
module.exports = class MyMatchesTabView extends CocoView module.exports = class MyMatchesTabView extends CocoView
@ -9,9 +10,6 @@ module.exports = class MyMatchesTabView extends CocoView
template: require 'templates/play/ladder/my_matches_tab' template: require 'templates/play/ladder/my_matches_tab'
startsLoading: true startsLoading: true
events:
'click .rank-button': 'rankSession'
constructor: (options, @level, @sessions) -> constructor: (options, @level, @sessions) ->
super(options) super(options)
@nameMap = {} @nameMap = {}
@ -49,8 +47,6 @@ module.exports = class MyMatchesTabView extends CocoView
@startsLoading = false @startsLoading = false
@render() @render()
getRenderData: -> getRenderData: ->
ctx = super() ctx = super()
ctx.level = @level ctx.level = @level
@ -84,36 +80,18 @@ module.exports = class MyMatchesTabView extends CocoView
scoreHistory = team.session?.get('scoreHistory') scoreHistory = team.session?.get('scoreHistory')
if scoreHistory?.length > 1 if scoreHistory?.length > 1
team.scoreHistory = scoreHistory team.scoreHistory = scoreHistory
scoreHistory = _.last scoreHistory, 100 # Chart URL needs to be under 2048 characters for GET
team.currentScore = Math.round scoreHistory[scoreHistory.length - 1][1] * 100
team.chartColor = team.primaryColor.replace '#', ''
#times = (s[0] for s in scoreHistory)
#times = ((100 * (t - times[0]) / (times[times.length - 1] - times[0])).toFixed(1) for t in times)
# Let's try being independent of time.
times = (i for s, i in scoreHistory)
scores = (s[1] for s in scoreHistory)
lowest = _.min scores #.concat([0])
highest = _.max scores #.concat(50)
scores = (Math.round(100 * (s - lowest) / (highest - lowest)) for s in scores)
team.chartData = times.join(',') + '|' + scores.join(',')
team.minScore = Math.round(100 * lowest)
team.maxScore = Math.round(100 * highest)
ctx ctx
afterRender: -> afterRender: ->
super() super()
@$el.find('.rank-button').each (i, el) => @$el.find('.ladder-submission-view').each (i, el) =>
button = $(el) placeholder = $(el)
sessionID = button.data('session-id') sessionID = placeholder.data('session-id')
session = _.find @sessions.models, {id: sessionID} session = _.find @sessions.models, {id: sessionID}
rankingState = 'unavailable' ladderSubmissionView = new LadderSubmissionView session: session, level: @level
if session.readyToRank() @insertSubView ladderSubmissionView, placeholder
rankingState = 'rank' ladderSubmissionView.$el.find('.rank-button').addClass 'btn-block'
else if session.get 'isRanking'
rankingState = 'ranking'
@setRankingButtonText button, rankingState
@$el.find('.score-chart-wrapper').each (i, el) => @$el.find('.score-chart-wrapper').each (i, el) =>
scoreWrapper = $(el) scoreWrapper = $(el)
@ -170,59 +148,3 @@ module.exports = class MyMatchesTabView extends CocoView
.datum(data) .datum(data)
.attr("class",lineClass) .attr("class",lineClass)
.attr("d",line) .attr("d",line)
rankSession: (e) ->
button = $(e.target).closest('.rank-button')
sessionID = button.data('session-id')
session = _.find @sessions.models, {id: sessionID}
return unless session.readyToRank()
@setRankingButtonText(button, 'submitting')
success = =>
@setRankingButtonText(button, 'submitted') unless @destroyed
failure = (jqxhr, textStatus, errorThrown) =>
console.log jqxhr.responseText
@setRankingButtonText(button, 'failed') unless @destroyed
transpiledCode = @transpileSession session
ajaxData =
session: sessionID
levelID: @level.id
originalLevelID: @level.attributes.original
levelMajorVersion: @level.attributes.version.major
transpiledCode: transpiledCode
$.ajax '/queue/scoring', {
type: 'POST'
data: ajaxData
success: success
error: failure
}
transpileSession: (session) ->
submittedCode = session.get('code')
transpiledCode = {}
for thang, spells of submittedCode
transpiledCode[thang] = {}
for spellID, spell of spells
unless _.contains(session.get('teamSpells')[session.get('team')], thang + "/" + spellID) then continue
#DRY this
aetherOptions =
problems: {}
language: "javascript"
functionName: spellID
functionParameters: []
yieldConditionally: spellID is "plan"
globals: ['Vector', '_']
protectAPI: true
includeFlow: false
if spellID is "hear" then aetherOptions["functionParameters"] = ["speaker","message","data"]
aether = new Aether aetherOptions
transpiledCode[thang][spellID] = aether.transpile spell
transpiledCode
setRankingButtonText: (rankButton, spanClass) ->
rankButton.find('span').addClass('hidden')
rankButton.find(".#{spanClass}").removeClass('hidden')
rankButton.toggleClass 'disabled', spanClass isnt 'rank'

View file

@ -1,15 +1,18 @@
View = require 'views/kinds/ModalView' View = require 'views/kinds/ModalView'
template = require 'templates/play/level/modal/multiplayer' template = require 'templates/play/level/modal/multiplayer'
{me} = require('lib/auth') {me} = require 'lib/auth'
LadderSubmissionView = require 'views/play/common/ladder_submission_view'
module.exports = class MultiplayerModal extends View module.exports = class MultiplayerModal extends View
id: 'level-multiplayer-modal' id: 'level-multiplayer-modal'
template: template template: template
subscriptions:
'ladder:game-submitted': 'onGameSubmitted'
events: events:
'click textarea': 'onClickLink' 'click textarea': 'onClickLink'
'change #multiplayer': 'updateLinkSection' 'change #multiplayer': 'updateLinkSection'
'click .rank-game-button': 'onRankGame'
constructor: (options) -> constructor: (options) ->
super(options) super(options)
@ -36,10 +39,16 @@ module.exports = class MultiplayerModal extends View
afterRender: -> afterRender: ->
super() super()
@updateLinkSection() @updateLinkSection()
@ladderSubmissionView = new LadderSubmissionView session: @session, level: @level
@insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view')
onClickLink: (e) -> onClickLink: (e) ->
e.target.select() e.target.select()
onGameSubmitted: (e) ->
ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches"
Backbone.Mediator.publish 'router:navigate', route: ladderURL
updateLinkSection: -> updateLinkSection: ->
multiplayer = @$el.find('#multiplayer').prop('checked') multiplayer = @$el.find('#multiplayer').prop('checked')
la = @$el.find('#link-area') la = @$el.find('#link-area')
@ -50,48 +59,5 @@ module.exports = class MultiplayerModal extends View
multiplayer = Boolean(@$el.find('#multiplayer').prop('checked')) multiplayer = Boolean(@$el.find('#multiplayer').prop('checked'))
@session.set('multiplayer', multiplayer) @session.set('multiplayer', multiplayer)
onRankGame: (e) ->
button = @$el.find('.rank-game-button')
button.text($.i18n.t('play_level.victory_ranking_game', defaultValue: 'Submitting...'))
button.prop 'disabled', true
ajaxData =
session: @session.id
levelID: @level.id
originalLevelID: @level.get('original')
levelMajorVersion: @level.get('version').major
transpiledCode: @transpileSession(@session)
ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches"
goToLadder = -> Backbone.Mediator.publish 'router:navigate', route: ladderURL
$.ajax '/queue/scoring',
type: 'POST'
data: ajaxData
success: goToLadder
failure: (response) ->
console.error "Couldn't submit game for ranking:", response
goToLadder()
transpileSession: (session) ->
submittedCode = session.get('code')
transpiledCode = {}
for thang, spells of submittedCode
transpiledCode[thang] = {}
for spellID, spell of spells
unless _.contains(session.get('teamSpells')[session.get('team')], thang + "/" + spellID) then continue
#DRY this
aetherOptions =
problems: {}
language: "javascript"
functionName: spellID
functionParameters: []
yieldConditionally: spellID is "plan"
globals: ['Vector', '_']
protectAPI: true
includeFlow: false
if spellID is "hear" then aetherOptions["functionParameters"] = ["speaker","message","data"]
aether = new Aether aetherOptions
transpiledCode[thang][spellID] = aether.transpile spell
transpiledCode
destroy: -> destroy: ->
super() super()

View file

@ -1,6 +1,7 @@
View = require 'views/kinds/ModalView' View = require 'views/kinds/ModalView'
template = require 'templates/play/level/modal/victory' template = require 'templates/play/level/modal/victory'
{me} = require 'lib/auth' {me} = require 'lib/auth'
LadderSubmissionView = require 'views/play/common/ladder_submission_view'
LevelFeedback = require 'models/LevelFeedback' LevelFeedback = require 'models/LevelFeedback'
utils = require 'lib/utils' utils = require 'lib/utils'
@ -8,9 +9,11 @@ module.exports = class VictoryModal extends View
id: 'level-victory-modal' id: 'level-victory-modal'
template: template template: template
subscriptions:
'ladder:game-submitted': 'onGameSubmitted'
events: events:
'click .next-level-button': 'onPlayNextLevel' 'click .next-level-button': 'onPlayNextLevel'
'click .rank-game-button': 'onRankGame'
# review events # review events
'mouseover .rating i': (e) -> @showStars(@starNum($(e.target))) 'mouseover .rating i': (e) -> @showStars(@starNum($(e.target)))
@ -58,48 +61,9 @@ module.exports = class VictoryModal extends View
@saveReview() if @$el.find('.review textarea').val() @saveReview() if @$el.find('.review textarea').val()
Backbone.Mediator.publish('play-next-level') Backbone.Mediator.publish('play-next-level')
onRankGame: (e) -> onGameSubmitted: (e) ->
button = @$el.find('.rank-game-button')
button.text($.i18n.t('play_level.victory_ranking_game', defaultValue: 'Submitting...'))
button.prop 'disabled', true
ajaxData =
session: @session.id
levelID: @level.id
originalLevelID: @level.get('original')
levelMajorVersion: @level.get('version').major
transpiledCode: @transpileSession @session
ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches" ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches"
goToLadder = -> Backbone.Mediator.publish 'router:navigate', route: ladderURL Backbone.Mediator.publish 'router:navigate', route: ladderURL
$.ajax '/queue/scoring',
type: 'POST'
data: ajaxData
success: goToLadder
failure: (response) ->
console.error "Couldn't submit game for ranking:", response
goToLadder()
transpileSession: (session) ->
submittedCode = session.get('code')
transpiledCode = {}
for thang, spells of submittedCode
transpiledCode[thang] = {}
for spellID, spell of spells
#DRY this
unless _.contains(session.get('teamSpells')[session.get('team')], thang + "/" + spellID) then continue
aetherOptions =
problems: {}
language: "javascript"
functionName: spellID
functionParameters: []
yieldConditionally: spellID is "plan"
globals: ['Vector', '_']
protectAPI: true
includeFlow: false
if spellID is "hear" then aetherOptions["functionParameters"] = ["speaker","message","data"]
aether = new Aether aetherOptions
transpiledCode[thang][spellID] = aether.transpile spell
transpiledCode
getRenderData: -> getRenderData: ->
c = super() c = super()
@ -126,6 +90,8 @@ module.exports = class VictoryModal extends View
afterRender: -> afterRender: ->
super() super()
@ladderSubmissionView = new LadderSubmissionView session: @session, level: @level
@insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view')
afterInsert: -> afterInsert: ->
super() super()

View file

@ -79,7 +79,7 @@ module.exports = class CastButtonView extends View
async.some _.values(@spells), (spell, callback) => async.some _.values(@spells), (spell, callback) =>
spell.hasChangedSignificantly spell.getSource(), null, callback spell.hasChangedSignificantly spell.getSource(), null, callback
, (castable) => , (castable) =>
Backbone.Mediator.publish 'tome:spell-has-changed-significantly-calculation', hasChangedSignificantly: castable
@castButtonGroup.toggleClass('castable', castable).toggleClass('casting', @casting) @castButtonGroup.toggleClass('castable', castable).toggleClass('casting', @casting)
if @casting if @casting
s = $.i18n.t("play_level.tome_cast_button_casting", defaultValue: "Casting") s = $.i18n.t("play_level.tome_cast_button_casting", defaultValue: "Casting")

View file

@ -17,6 +17,7 @@ module.exports = class DebugView extends View
'tome:spell-shown': 'changeCurrentThangAndSpell' 'tome:spell-shown': 'changeCurrentThangAndSpell'
'tome:cast-spells': 'onTomeCast' 'tome:cast-spells': 'onTomeCast'
'surface:frame-changed': 'onFrameChanged' 'surface:frame-changed': 'onFrameChanged'
'tome:spell-has-changed-significantly-calculation': 'onSpellChangedCalculation'
events: {} events: {}
@ -34,6 +35,8 @@ module.exports = class DebugView extends View
@cache = {} @cache = {}
@lastFrameRequested = -1 @lastFrameRequested = -1
@workerIsSimulating = false @workerIsSimulating = false
@spellHasChanged = false
pad2: (num) -> pad2: (num) ->
@ -145,11 +148,17 @@ module.exports = class DebugView extends View
onFrameChanged: (data) -> onFrameChanged: (data) ->
@currentFrame = data.frame @currentFrame = data.frame
@frameRate = data.world.frameRate @frameRate = data.world.frameRate
onSpellChangedCalculation: (data) ->
@spellHasChanged = data.hasChangedSignificantly
update: -> update: ->
if @variableChain if @variableChain
if @variableChain.length is 2 and @variableChain[0] is "this" if @spellHasChanged
@setTooltipText("You've changed this spell! \nPlease recast to use the hover debugger.")
else if @variableChain.length is 2 and @variableChain[0] is "this"
@setTooltipKeyAndValue(@variableChain.join("."),@stringifyValue(@thang[@variableChain[1]],0)) @setTooltipKeyAndValue(@variableChain.join("."),@stringifyValue(@thang[@variableChain[1]],0))
else if @variableChain.length is 1 and Aether.globals[@variableChain[0]]
@setTooltipKeyAndValue(@variableChain.join("."),@stringifyValue(Aether.globals[@variableChain[0]],0))
else if @workerIsSimulating else if @workerIsSimulating
@setTooltipText("World is simulating, please wait...") @setTooltipText("World is simulating, please wait...")
else if @currentFrame is @lastFrameRequested and (cacheValue = @retrieveValueFromCache(@thang.id, @spell.name, @variableChain, @currentFrame)) else if @currentFrame is @lastFrameRequested and (cacheValue = @retrieveValueFromCache(@thang.id, @spell.name, @variableChain, @currentFrame))

View file

@ -360,7 +360,7 @@ module.exports = class SpellView extends View
displayAether: (aether) -> displayAether: (aether) ->
@displayedAether = aether @displayedAether = aether
isCast = not _.isEmpty(aether.metrics) or _.some aether.problems.errors, {type: 'runtime'} isCast = not _.isEmpty(aether.metrics) or _.some aether.problems.errors, {type: 'runtime'}
isCast = isCast or @language isnt 'javascript' # Since we don't have linting for other languages isCast = isCast or @spell.language isnt 'javascript' # Since we don't have linting for other languages
problem.destroy() for problem in @problems # Just in case another problem was added since clearAetherDisplay() ran. problem.destroy() for problem in @problems # Just in case another problem was added since clearAetherDisplay() ran.
@problems = [] @problems = []
annotations = [] annotations = []

View file

@ -35,7 +35,7 @@ path = __dirname
m = require 'module' m = require 'module'
request = require 'request' request = require 'request'
Deferred = require "JQDeferred"
originalLoader = m._load originalLoader = m._load
unhook = () -> unhook = () ->
@ -90,6 +90,7 @@ GLOBAL.$ = GLOBAL.jQuery = (input) ->
append: (input)-> exports: ()-> append: (input)-> exports: ()->
cookies = request.jar() cookies = request.jar()
$.when = Deferred.when
$.ajax = (options) -> $.ajax = (options) ->
responded = false responded = false

View file

@ -66,7 +66,8 @@
"webworker-threads": "~0.4.11", "webworker-threads": "~0.4.11",
"node-gyp": "~0.13.0", "node-gyp": "~0.13.0",
"aether": "~0.2.3", "aether": "~0.2.3",
"JASON": "~0.1.3" "JASON": "~0.1.3",
"JQDeferred": "^2.1.0"
}, },
"devDependencies": { "devDependencies": {
"jade": "0.33.x", "jade": "0.33.x",
@ -97,7 +98,7 @@
"karma": "~0.10.9", "karma": "~0.10.9",
"karma-coverage": "~0.1.4", "karma-coverage": "~0.1.4",
"compressible": "~1.0.1", "compressible": "~1.0.1",
"jasmine-spec-reporter":"~0.3.0" "jasmine-spec-reporter": "~0.3.0"
}, },
"license": "MIT for the code, and CC-BY for the art and music", "license": "MIT for the code, and CC-BY for the art and music",
"private": true, "private": true,

View file

@ -449,7 +449,7 @@ addMatchToSessions = (newScoreObject, callback) ->
matchObject.opponents[sessionID].name = session.name matchObject.opponents[sessionID].name = session.name
matchObject.opponents[sessionID].totalScore = session.totalScore matchObject.opponents[sessionID].totalScore = session.totalScore
matchObject.opponents[sessionID].metrics = {} matchObject.opponents[sessionID].metrics = {}
matchObject.opponents[sessionID].metrics.rank = Number(newScoreObject[sessionID].gameRanking) matchObject.opponents[sessionID].metrics.rank = Number(newScoreObject[sessionID]?.gameRanking ? 0)
#log.info "Match object computed, result: #{matchObject}" #log.info "Match object computed, result: #{matchObject}"
#log.info "Writing match object to database..." #log.info "Writing match object to database..."