From 87949210184235392f04905ca429bb4e4dd71850 Mon Sep 17 00:00:00 2001 From: Pablo Lobato Date: Sat, 17 May 2014 11:09:55 +0200 Subject: [PATCH 01/12] Update es-ES.coffee --- app/locale/es-ES.coffee | 62 ++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/app/locale/es-ES.coffee b/app/locale/es-ES.coffee index 632d9aeec..a0128d205 100644 --- a/app/locale/es-ES.coffee +++ b/app/locale/es-ES.coffee @@ -36,11 +36,11 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis nav: play: "Jugar" -# community: "Community" + community: "Comunidad" editor: "Editor" blog: "Blog" forum: "Foro" -# account: "Account" + account: "Cuenta" admin: "Admin" home: "Inicio" contribute: "Colaborar" @@ -152,7 +152,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis autosave: "Los cambios se guardan automáticamente" me_tab: "Yo" picture_tab: "Foto" -# upload_picture: "Upload a picture" + upload_picture: "Sube una imagen" wizard_tab: "Mago" password_tab: "Contraseña" 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_description: "Disable to stop all activity notification emails." # 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" contribute_prefix: "¡Buscamos gente que se una a nuestro comunidad! Comprueba la " 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_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." -# sample_profile: "See a sample profile" -# view_profile: "View Your Profile" + sample_profile: "Mira un perfil de ejemplo" + view_profile: "Mira tu perfil" account_profile: edit_settings: "Ajustes" @@ -199,7 +199,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis employers: 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_many: "muchos" 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_years_experience: "Años Exp" candidate_last_updated: "Última actualización" -# candidate_approved: "Us?" -# candidate_active: "Them?" + candidate_approved: "¿Nosotros?" + candidate_active: "¿Ellos?" play_level: 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: " 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_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" tome_minion_spells: "Los hechizos de tus súbditos" tome_read_only_spells: "Hechizos de solo lectura" @@ -321,9 +321,9 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis lg_title: "Últimos Juegos" clas: "CLAs" -# community: -# level_editor: "Level Editor" -# main_title: "CodeCombat Community" + community: + level_editor: "Editor de niveles" + main_title: "Comunidad de CodeCombat" # facebook: "Facebook" # twitter: "Twitter" # 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." 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!" -# got_questions: "Questions about using the CodeCombat editors?" + got_questions: "¿Preguntas sobre el uso de los editores CodeCombat?" contact_us: "¡Contacta con nosotros!" hipchat_prefix: "También puedes encontrarnos en nuestra" 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_thang_title: "Crea un nuevo tipo de objeto" 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_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í" thang_search_title: "Busca tipos de objetos aquí" level_search_title: "Buscar niveles aquí" @@ -651,11 +651,11 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis simple_ai: "IA sencilla" warmup: "calentamiento" vs: "VS" -# friends_playing: "Friends Playing" -# sign_up_for_friends: "Sign up to play with your friends!" -# social_connect_blurb: "Connect and play against your friends!" -# invite_friends_to_battle: "Invite your friends to join you in battle!" -# fight: "Fight!" + friends_playing: "Amigos jugando" + sign_up_for_friends: "¡Registrate para jugar con tus amigos!" + social_connect_blurb: "¡Conectate y juega contra tus amigos!" + invite_friends_to_battle: "¡Invita a tus amigos a unirse a la batalla!" + fight: "¡Pelea!" # watch_victory: "Watch your victory" # defeat_the: "Defeat the" @@ -700,15 +700,15 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis user_profile: "Perfil de usuario" patches: "Parches" model: "Modelo" -# system: "System" -# component: "Component" -# components: "Components" + system: "Sistema" + component: "Componente" + components: "Componentes" # thang: "Thang" # thangs: "Thangs" -# level_session: "Your Session" -# opponent_session: "Opponent Session" -# article: "Article" -# user_names: "User Names" -# files: "Files" -# top_simulators: "Top Simulators" -# source_document: "Source Document" + level_session: "Tu sesión" + opponent_session: "Sesión del oponente" + article: "Artículo" + user_names: "Nombres de usuarios" + files: "Archivos" + top_simulators: "Top simuladores" + source_document: "Documento fuente" From 736fc8c12f409b0d80ba8c866761881c68c31b53 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Sat, 17 May 2014 09:58:21 -0700 Subject: [PATCH 02/12] Remove overeager transpile problem showing for JS again. --- app/lib/surface/Mark.coffee | 2 +- app/views/play/level/tome/spell_view.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/surface/Mark.coffee b/app/lib/surface/Mark.coffee index de27d01dd..4d2e554c0 100644 --- a/app/lib/surface/Mark.coffee +++ b/app/lib/surface/Mark.coffee @@ -20,7 +20,7 @@ module.exports = class Mark extends CocoClass @build() destroy: -> - createjs.Tween.removeTweens @mark + createjs.Tween.removeTweens @mark if @mark @mark?.parent?.removeChild @mark @markSprite?.destroy() @sprite = null diff --git a/app/views/play/level/tome/spell_view.coffee b/app/views/play/level/tome/spell_view.coffee index e45869154..f978428f5 100644 --- a/app/views/play/level/tome/spell_view.coffee +++ b/app/views/play/level/tome/spell_view.coffee @@ -360,7 +360,7 @@ module.exports = class SpellView extends View displayAether: (aether) -> @displayedAether = aether 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. @problems = [] annotations = [] From 4be67113be5cc1710949ed8deb232cbe5734a2ff Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Sat, 17 May 2014 11:27:54 -0700 Subject: [PATCH 03/12] Thang events now only appear once per whole frame, rather than for each interpolated frame. --- app/lib/surface/Surface.coffee | 4 +++- app/lib/world/world_frame.coffee | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/lib/surface/Surface.coffee b/app/lib/surface/Surface.coffee index 7beb03cf4..b82683ea3 100644 --- a/app/lib/surface/Surface.coffee +++ b/app/lib/surface/Surface.coffee @@ -591,12 +591,14 @@ module.exports = Surface = class Surface extends CocoClass @mouseInBounds = mib restoreWorldState: -> - @world.getFrame(@getCurrentFrame()).restoreState() + frame = @world.getFrame(@getCurrentFrame()) + frame.restoreState() current = Math.max(0, Math.min(@currentFrame, @world.totalFrames - 1)) if current - Math.floor(current) > 0.01 next = Math.ceil current ratio = current % 1 @world.frames[next].restorePartialState ratio if next > 1 + frame.clearEvents() if parseInt(@currentFrame) is parseInt(@lastFrame) @spriteBoss.updateSounds() updateState: (frameChanged) -> diff --git a/app/lib/world/world_frame.coffee b/app/lib/world/world_frame.coffee index fcac050a8..fc21546e2 100644 --- a/app/lib/world/world_frame.coffee +++ b/app/lib/world/world_frame.coffee @@ -36,6 +36,8 @@ module.exports = class WorldFrame #console.log "Frame", @time, "restoring state for", thang.id, "in particular and saying it don't exist" return thangState.restore() + + clearEvents: -> thang.currentEvents = [] for thang in @world.thangs toString: -> map = ((' ' for x in [0 .. @world.width]) \ From f99a95768ebe54a1624e50812f88d29a49f141a7 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Sat, 17 May 2014 11:28:21 -0700 Subject: [PATCH 04/12] Set up CocoSprites to have text appear overhead based on events coming from the ShowsText component. --- app/lib/surface/CocoSprite.coffee | 34 +++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/app/lib/surface/CocoSprite.coffee b/app/lib/surface/CocoSprite.coffee index 9bfaaab64..833deaa4d 100644 --- a/app/lib/surface/CocoSprite.coffee +++ b/app/lib/surface/CocoSprite.coffee @@ -69,7 +69,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass @marks = {} @labels = {} @ranges = [] - @handledAoEs = {} + @handledDisplayEvents = {} @age = 0 @scaleFactor = @targetScaleFactor = 1 if @thangType.isFullyLoaded() @@ -213,6 +213,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass @updatePosition() frameChanged = frameChanged or @targetScaleFactor isnt @scaleFactor if frameChanged + @handledDisplayEvents = {} @updateScale() # must happen before rotation @updateAlpha() @updateRotation() @@ -220,6 +221,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass @updateStats() @updateGold() @showAreaOfEffects() + @showTextEvents() @updateHealthBar() @updateMarks() @updateLabels() @@ -228,9 +230,9 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass return unless @thang?.currentEvents for event in @thang.currentEvents continue unless event.startsWith 'aoe-' - continue if @handledAoEs[event] + continue if @handledDisplayEvents[event] - @handledAoEs[event] = true + @handledDisplayEvents[event] = true args = JSON.parse(event[4...]) pos = @options.camera.worldToSurface {x:args[0], y:args[1]} circle = new createjs.Shape() @@ -248,7 +250,31 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass .call => return if @destroyed @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: -> bounds = @imageObject.getBounds() From df222461bf621e61761a3cfe2863801a57b0043f Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Sat, 17 May 2014 11:38:33 -0700 Subject: [PATCH 05/12] Fixed a bug that was bringing the thang editor down. --- app/lib/surface/CocoSprite.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/surface/CocoSprite.coffee b/app/lib/surface/CocoSprite.coffee index 833deaa4d..d80d8705a 100644 --- a/app/lib/surface/CocoSprite.coffee +++ b/app/lib/surface/CocoSprite.coffee @@ -498,7 +498,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass Backbone.Mediator.publish ourEventName, newEvent 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"] healthOffset = @getOffset 'aboveHead' bar = @healthBar = createProgressBar(healthColor, healthOffset) From 5907ca86195ae0cf7c66bbc6f41f6fc516a134f2 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Sat, 17 May 2014 11:49:11 -0700 Subject: [PATCH 06/12] Fixed scaling in the thang type editor. --- app/views/editor/thang/edit.coffee | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/views/editor/thang/edit.coffee b/app/views/editor/thang/edit.coffee index 7baa18de6..60e0b7872 100644 --- a/app/views/editor/thang/edit.coffee +++ b/app/views/editor/thang/edit.coffee @@ -221,8 +221,8 @@ module.exports = class ThangTypeEditView extends View @showMovieClip(animationName) else @showSprite(animationName) - @updateScale() @updateRotation() + @updateScale() # must happen after update rotation, because updateRotation calls the sprite update() method. showMovieClip: (animationName) -> vectorParser = new SpriteBuilder(@thangType) @@ -279,11 +279,12 @@ module.exports = class ThangTypeEditView extends View @currentSprite.update(true) updateScale: => - value = (@scaleSlider.slider('value') + 1) / 10 - fixed = value.toFixed(1) - @scale = value + resValue = (@resolutionSlider.slider('value') + 1) / 10 + scaleValue = (@scaleSlider.slider('value') + 1) / 10 + fixed = scaleValue.toFixed(1) + @scale = scaleValue @$el.find('.scale-label').text " #{fixed}x " - @currentObject.scaleX = @currentObject.scaleY = value if @currentObject? + @currentObject.scaleX = @currentObject.scaleY = scaleValue / resValue if @currentObject? @updateGrid() @updateDots() From 3c9428ffd30e1ab83f03367f309a386d662ec5bc Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Sat, 17 May 2014 11:55:41 -0700 Subject: [PATCH 07/12] Refactored game ranking buttons into a LadderSubmissionView. --- app/locale/en.coffee | 2 - app/styles/play/common/ladder_submission.sass | 3 + .../play/common/ladder_submission.jade | 7 ++ app/templates/play/ladder/my_matches_tab.jade | 18 +--- .../play/level/modal/multiplayer.jade | 2 +- app/templates/play/level/modal/victory.jade | 2 +- .../play/common/ladder_submission_view.coffee | 88 ++++++++++++++++++ app/views/play/ladder/my_matches_tab.coffee | 92 ++----------------- .../play/level/modal/multiplayer_modal.coffee | 56 +++-------- .../play/level/modal/victory_modal.coffee | 50 ++-------- 10 files changed, 128 insertions(+), 192 deletions(-) create mode 100644 app/styles/play/common/ladder_submission.sass create mode 100644 app/templates/play/common/ladder_submission.jade create mode 100644 app/views/play/common/ladder_submission_view.coffee diff --git a/app/locale/en.coffee b/app/locale/en.coffee index 0854b1dc6..6d0c82186 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -233,8 +233,6 @@ victory_sign_up: "Sign Up to Save Progress" victory_sign_up_poke: "Want to save your code? Create a free account!" 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_play_next_level: "Play Next Level" victory_go_home: "Go Home" diff --git a/app/styles/play/common/ladder_submission.sass b/app/styles/play/common/ladder_submission.sass new file mode 100644 index 000000000..c26d413f3 --- /dev/null +++ b/app/styles/play/common/ladder_submission.sass @@ -0,0 +1,3 @@ +.ladder-submission-view + h3 + text-decoration: underline diff --git a/app/templates/play/common/ladder_submission.jade b/app/templates/play/common/ladder_submission.jade new file mode 100644 index 000000000..1e202bdd6 --- /dev/null +++ b/app/templates/play/common/ladder_submission.jade @@ -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 diff --git a/app/templates/play/ladder/my_matches_tab.jade b/app/templates/play/ladder/my_matches_tab.jade index 4975fa963..c1bc58918 100644 --- a/app/templates/play/ladder/my_matches_tab.jade +++ b/app/templates/play/ladder/my_matches_tab.jade @@ -1,9 +1,3 @@ -//if matches.length -// p#your-score -// span Your Current Score: -// span -// strong= score - div#columns.row for team in teams div.matches-column.col-md-6 @@ -23,21 +17,13 @@ div#columns.row if team.session tr th(colspan=4) - button.btn.btn-warning.btn-block.rank-button(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 + .ladder-submission-view(data-session-id=team.session.id) - if team.chartData + if team.scoreHistory tr th(colspan=4, style="color: #{team.primaryColor}") div(class="score-chart-wrapper", data-team-name=team.name, id="score-chart-#{team.name}") - - tr th(data-i18n="general.result") Result th(data-i18n="general.opponent") Opponent diff --git a/app/templates/play/level/modal/multiplayer.jade b/app/templates/play/level/modal/multiplayer.jade index 5a3413e3c..cc2712f38 100644 --- a/app/templates/play/level/modal/multiplayer.jade +++ b/app/templates/play/level/modal/multiplayer.jade @@ -29,7 +29,7 @@ block modal-body-content 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. 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 a.btn.btn-primary(href="/play/ladder/#{levelSlug}#my-matches", data-i18n="play_level.victory_go_ladder") Return to Ladder diff --git a/app/templates/play/level/modal/victory.jade b/app/templates/play/level/modal/victory.jade index 92c253955..afeeb9764 100644 --- a/app/templates/play/level/modal/victory.jade +++ b/app/templates/play/level/modal/victory.jade @@ -12,7 +12,7 @@ block modal-body-content block modal-footer-content 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' 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 diff --git a/app/views/play/common/ladder_submission_view.coffee b/app/views/play/common/ladder_submission_view.coffee new file mode 100644 index 000000000..535dafb76 --- /dev/null +++ b/app/views/play/common/ladder_submission_view.coffee @@ -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 + diff --git a/app/views/play/ladder/my_matches_tab.coffee b/app/views/play/ladder/my_matches_tab.coffee index 672d74a52..d84b9d5b4 100644 --- a/app/views/play/ladder/my_matches_tab.coffee +++ b/app/views/play/ladder/my_matches_tab.coffee @@ -2,6 +2,7 @@ CocoView = require 'views/kinds/CocoView' Level = require 'models/Level' LevelSession = require 'models/LevelSession' LeaderboardCollection = require 'collections/LeaderboardCollection' +LadderSubmissionView = require 'views/play/common/ladder_submission_view' {teamDataFromLevel} = require './utils' module.exports = class MyMatchesTabView extends CocoView @@ -9,9 +10,6 @@ module.exports = class MyMatchesTabView extends CocoView template: require 'templates/play/ladder/my_matches_tab' startsLoading: true - events: - 'click .rank-button': 'rankSession' - constructor: (options, @level, @sessions) -> super(options) @nameMap = {} @@ -49,8 +47,6 @@ module.exports = class MyMatchesTabView extends CocoView @startsLoading = false @render() - - getRenderData: -> ctx = super() ctx.level = @level @@ -84,36 +80,18 @@ module.exports = class MyMatchesTabView extends CocoView scoreHistory = team.session?.get('scoreHistory') if scoreHistory?.length > 1 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 afterRender: -> super() - @$el.find('.rank-button').each (i, el) => - button = $(el) - sessionID = button.data('session-id') + @$el.find('.ladder-submission-view').each (i, el) => + placeholder = $(el) + sessionID = placeholder.data('session-id') session = _.find @sessions.models, {id: sessionID} - rankingState = 'unavailable' - if session.readyToRank() - rankingState = 'rank' - else if session.get 'isRanking' - rankingState = 'ranking' - @setRankingButtonText button, rankingState + ladderSubmissionView = new LadderSubmissionView session: session, level: @level + @insertSubView ladderSubmissionView, placeholder + ladderSubmissionView.$el.find('.rank-button').addClass 'btn-block' @$el.find('.score-chart-wrapper').each (i, el) => scoreWrapper = $(el) @@ -170,59 +148,3 @@ module.exports = class MyMatchesTabView extends CocoView .datum(data) .attr("class",lineClass) .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' diff --git a/app/views/play/level/modal/multiplayer_modal.coffee b/app/views/play/level/modal/multiplayer_modal.coffee index 5ab5d0591..c7e02b157 100644 --- a/app/views/play/level/modal/multiplayer_modal.coffee +++ b/app/views/play/level/modal/multiplayer_modal.coffee @@ -1,15 +1,18 @@ View = require 'views/kinds/ModalView' 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 id: 'level-multiplayer-modal' template: template + subscriptions: + 'ladder:game-submitted': 'onGameSubmitted' + events: 'click textarea': 'onClickLink' 'change #multiplayer': 'updateLinkSection' - 'click .rank-game-button': 'onRankGame' constructor: (options) -> super(options) @@ -36,10 +39,16 @@ module.exports = class MultiplayerModal extends View afterRender: -> super() @updateLinkSection() + @ladderSubmissionView = new LadderSubmissionView session: @session, level: @level + @insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view') onClickLink: (e) -> e.target.select() + onGameSubmitted: (e) -> + ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches" + Backbone.Mediator.publish 'router:navigate', route: ladderURL + updateLinkSection: -> multiplayer = @$el.find('#multiplayer').prop('checked') la = @$el.find('#link-area') @@ -50,48 +59,5 @@ module.exports = class MultiplayerModal extends View multiplayer = Boolean(@$el.find('#multiplayer').prop('checked')) @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: -> super() diff --git a/app/views/play/level/modal/victory_modal.coffee b/app/views/play/level/modal/victory_modal.coffee index 2a0b02c89..ecc883426 100644 --- a/app/views/play/level/modal/victory_modal.coffee +++ b/app/views/play/level/modal/victory_modal.coffee @@ -1,6 +1,7 @@ View = require 'views/kinds/ModalView' template = require 'templates/play/level/modal/victory' {me} = require 'lib/auth' +LadderSubmissionView = require 'views/play/common/ladder_submission_view' LevelFeedback = require 'models/LevelFeedback' utils = require 'lib/utils' @@ -8,9 +9,11 @@ module.exports = class VictoryModal extends View id: 'level-victory-modal' template: template + subscriptions: + 'ladder:game-submitted': 'onGameSubmitted' + events: 'click .next-level-button': 'onPlayNextLevel' - 'click .rank-game-button': 'onRankGame' # review events '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() Backbone.Mediator.publish('play-next-level') - 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 + onGameSubmitted: (e) -> 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 - #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 + Backbone.Mediator.publish 'router:navigate', route: ladderURL getRenderData: -> c = super() @@ -126,6 +90,8 @@ module.exports = class VictoryModal extends View afterRender: -> super() + @ladderSubmissionView = new LadderSubmissionView session: @session, level: @level + @insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view') afterInsert: -> super() From a46714b1b648695a11a9662ad679af0d31ab547b Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Sat, 17 May 2014 12:02:34 -0700 Subject: [PATCH 08/12] Patching bug if newScoreObject is incomplete --- server/queues/scoring.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/queues/scoring.coffee b/server/queues/scoring.coffee index 6c021be3e..efc7d05da 100644 --- a/server/queues/scoring.coffee +++ b/server/queues/scoring.coffee @@ -449,7 +449,7 @@ addMatchToSessions = (newScoreObject, callback) -> matchObject.opponents[sessionID].name = session.name matchObject.opponents[sessionID].totalScore = session.totalScore 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 "Writing match object to database..." From 9df34875ee18d9bec36a385c0c9eafb8e9baa58c Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Sat, 17 May 2014 20:43:05 -0700 Subject: [PATCH 09/12] Added tournament rules/prizes placeholders. --- app/templates/play/ladder.jade | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/templates/play/ladder.jade b/app/templates/play/ladder.jade index bc8bd05d0..267b3a8b5 100644 --- a/app/templates/play/ladder.jade +++ b/app/templates/play/ladder.jade @@ -31,6 +31,11 @@ block content a(href="#my-matches", data-toggle="tab", data-i18n="ladder.my_matches") My Matches li 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 .tab-pane.active.well#ladder @@ -39,3 +44,9 @@ block content #my-matches-tab-view .tab-pane.well#simulate #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. From 5c72ccdce1e773609d07d492b7c106b92a41e7aa Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Sun, 18 May 2014 11:41:42 -0700 Subject: [PATCH 10/12] Add support for Aether globals in hover debugger --- app/assets/javascripts/workers/worker_world.js | 15 +++++++++++---- app/views/play/level/tome/spell_debug_view.coffee | 2 ++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/workers/worker_world.js b/app/assets/javascripts/workers/worker_world.js index f5d91cf18..7547c282a 100644 --- a/app/assets/javascripts/workers/worker_world.js +++ b/app/assets/javascripts/workers/worker_world.js @@ -188,10 +188,17 @@ self.retrieveValueFromFrame = function retrieveValueFromFrame(args) { { try { - 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 - //to collect the flow - value = _.last(flowStates[flowStates.length - 1].statements).variables[prop]; + if (Aether.globals[prop]) + { + value = Aether.globals[prop]; + } + else + { + 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 + //to collect the flow + value = _.last(flowStates[flowStates.length - 1].statements).variables[prop]; + } } catch (e) { diff --git a/app/views/play/level/tome/spell_debug_view.coffee b/app/views/play/level/tome/spell_debug_view.coffee index a8a03cbd7..f0505b513 100644 --- a/app/views/play/level/tome/spell_debug_view.coffee +++ b/app/views/play/level/tome/spell_debug_view.coffee @@ -150,6 +150,8 @@ module.exports = class DebugView extends View if @variableChain if @variableChain.length is 2 and @variableChain[0] is "this" @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 @setTooltipText("World is simulating, please wait...") else if @currentFrame is @lastFrameRequested and (cacheValue = @retrieveValueFromCache(@thang.id, @spell.name, @variableChain, @currentFrame)) From 38d732d8bc87e9c71bba44063f6667f7857d4745 Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Sun, 18 May 2014 11:51:31 -0700 Subject: [PATCH 11/12] Disable hover debugger when spell changed --- app/views/play/level/tome/cast_button_view.coffee | 2 +- app/views/play/level/tome/spell_debug_view.coffee | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/views/play/level/tome/cast_button_view.coffee b/app/views/play/level/tome/cast_button_view.coffee index 1ba2cab3f..bd06e8019 100644 --- a/app/views/play/level/tome/cast_button_view.coffee +++ b/app/views/play/level/tome/cast_button_view.coffee @@ -79,7 +79,7 @@ module.exports = class CastButtonView extends View async.some _.values(@spells), (spell, callback) => spell.hasChangedSignificantly spell.getSource(), null, callback , (castable) => - + Backbone.Mediator.publish 'tome:spell-has-changed-significantly-calculation', hasChangedSignificantly: castable @castButtonGroup.toggleClass('castable', castable).toggleClass('casting', @casting) if @casting s = $.i18n.t("play_level.tome_cast_button_casting", defaultValue: "Casting") diff --git a/app/views/play/level/tome/spell_debug_view.coffee b/app/views/play/level/tome/spell_debug_view.coffee index f0505b513..c48d3beab 100644 --- a/app/views/play/level/tome/spell_debug_view.coffee +++ b/app/views/play/level/tome/spell_debug_view.coffee @@ -17,6 +17,7 @@ module.exports = class DebugView extends View 'tome:spell-shown': 'changeCurrentThangAndSpell' 'tome:cast-spells': 'onTomeCast' 'surface:frame-changed': 'onFrameChanged' + 'tome:spell-has-changed-significantly-calculation': 'onSpellChangedCalculation' events: {} @@ -34,6 +35,8 @@ module.exports = class DebugView extends View @cache = {} @lastFrameRequested = -1 @workerIsSimulating = false + @spellHasChanged = false + pad2: (num) -> @@ -145,10 +148,14 @@ module.exports = class DebugView extends View onFrameChanged: (data) -> @currentFrame = data.frame @frameRate = data.world.frameRate - + onSpellChangedCalculation: (data) -> + @spellHasChanged = data.hasChangedSignificantly + update: -> 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)) else if @variableChain.length is 1 and Aether.globals[@variableChain[0]] @setTooltipKeyAndValue(@variableChain.join("."),@stringifyValue(Aether.globals[@variableChain[0]],0)) From 035cb7d3f7e9bf56ac4b9d543c417eadbe779627 Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Sun, 18 May 2014 12:56:32 -0700 Subject: [PATCH 12/12] Fix simulator jquery when dependency --- headless_client.coffee | 3 ++- package.json | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/headless_client.coffee b/headless_client.coffee index 82f84b067..ca91cc034 100644 --- a/headless_client.coffee +++ b/headless_client.coffee @@ -35,7 +35,7 @@ path = __dirname m = require 'module' request = require 'request' - +Deferred = require "JQDeferred" originalLoader = m._load unhook = () -> @@ -90,6 +90,7 @@ GLOBAL.$ = GLOBAL.jQuery = (input) -> append: (input)-> exports: ()-> cookies = request.jar() +$.when = Deferred.when $.ajax = (options) -> responded = false diff --git a/package.json b/package.json index cbe0addb3..59bfdb9e9 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "graceful-fs": "~2.0.1", "node-force-domain": "~0.1.0", "mailchimp-api": "2.0.x", - "express-useragent": "~0.0.9", + "express-useragent": "~0.0.9", "gridfs-stream": "0.4.x", "stream-buffers": "0.2.x", "sendwithus": "2.0.x", @@ -66,7 +66,8 @@ "webworker-threads": "~0.4.11", "node-gyp": "~0.13.0", "aether": "~0.2.3", - "JASON": "~0.1.3" + "JASON": "~0.1.3", + "JQDeferred": "^2.1.0" }, "devDependencies": { "jade": "0.33.x", @@ -97,7 +98,7 @@ "karma": "~0.10.9", "karma-coverage": "~0.1.4", "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", "private": true,