codecombat/app/views/play/level/tome/CastButtonView.coffee
Scott Erickson ffa840910d Do not automatically show victory modal for shareable game dev levels
Students are likely to want to keep working on their level, even if
they beat it.
2016-08-10 12:47:34 -07:00

179 lines
8 KiB
CoffeeScript

CocoView = require 'views/core/CocoView'
template = require 'templates/play/level/tome/cast-button-view'
{me} = require 'core/auth'
LadderSubmissionView = require 'views/play/common/LadderSubmissionView'
LevelSession = require 'models/LevelSession'
module.exports = class CastButtonView extends CocoView
id: 'cast-button-view'
template: template
events:
'click .cast-button': 'onCastButtonClick'
'click .submit-button': 'onCastRealTimeButtonClick'
'click .done-button': 'onDoneButtonClick'
'click .game-dev-play-btn': 'onClickGameDevPlayButton'
subscriptions:
'tome:spell-changed': 'onSpellChanged'
'tome:cast-spells': 'onCastSpells'
'tome:manual-cast-denied': 'onManualCastDenied'
'god:new-world-created': 'onNewWorld'
'goal-manager:new-goal-states': 'onNewGoalStates'
'god:goals-calculated': 'onGoalsCalculated'
'playback:ended-changed': 'onPlaybackEndedChanged'
constructor: (options) ->
super options
@spells = options.spells
@castShortcut = '⇧↵'
@updateReplayabilityInterval = setInterval @updateReplayability, 1000
@observing = options.session.get('creator') isnt me.id
@loadMirrorSession() if @options.level.get('slug') in ['ace-of-coders', 'elemental-wars']
@mirror = @mirrorSession?
@autoSubmitsToLadder = @options.level.get('slug') in ['wakka-maul']
destroy: ->
clearInterval @updateReplayabilityInterval
super()
afterRender: ->
super()
@castButton = $('.cast-button', @$el)
spell.view?.createOnCodeChangeHandlers() for spellKey, spell of @spells
if @options.level.get('hidesSubmitUntilRun') or @options.level.get('hidesRealTimePlayback') or @options.level.isType('web-dev')
@$el.find('.submit-button').hide() # Hide Submit for the first few until they run it once.
if @options.session.get('state')?.complete and (@options.level.get('hidesRealTimePlayback') or @options.level.isType('web-dev'))
@$el.find('.done-button').show()
if @options.level.get('slug') in ['course-thornbush-farm', 'thornbush-farm']
@$el.find('.submit-button').hide() # Hide submit until first win so that script can explain it.
@updateReplayability()
@updateLadderSubmissionViews()
attachTo: (spellView) ->
@$el.detach().prependTo(spellView.toolbarView.$el).show()
castShortcutVerbose: ->
shift = $.i18n.t 'keyboard_shortcuts.shift'
enter = $.i18n.t 'keyboard_shortcuts.enter'
"#{shift}+#{enter}"
castVerbose: ->
@castShortcutVerbose() + ': ' + $.i18n.t('keyboard_shortcuts.run_code')
castRealTimeVerbose: ->
castRealTimeShortcutVerbose = (if @isMac() then 'Cmd' else 'Ctrl') + '+' + @castShortcutVerbose()
castRealTimeShortcutVerbose + ': ' + $.i18n.t('keyboard_shortcuts.run_real_time')
onCastButtonClick: (e) ->
Backbone.Mediator.publish 'tome:manual-cast', {}
onCastRealTimeButtonClick: (e) ->
if @options.level.get('replayable') and (timeUntilResubmit = @options.session.timeUntilResubmit()) > 0
Backbone.Mediator.publish 'tome:manual-cast-denied', timeUntilResubmit: timeUntilResubmit
else
Backbone.Mediator.publish 'tome:manual-cast', {realTime: true}
@updateReplayability()
onClickGameDevPlayButton: ->
Backbone.Mediator.publish 'tome:manual-cast', {realTime: true}
onDoneButtonClick: (e) ->
return if @options.level.hasLocalChanges() # Don't award achievements when beating level changed in level editor
@options.session.recordScores @world?.scores, @options.level
Backbone.Mediator.publish 'level:show-victory', { showModal: true, manual: true }
onSpellChanged: (e) ->
@updateCastButton()
onCastSpells: (e) ->
return if e.preload
@casting = true
if @hasStartedCastingOnce # Don't play this sound the first time
@playSound 'cast', 0.5 unless @options.level.isType('game-dev')
@hasStartedCastingOnce = true
@updateCastButton()
onManualCastDenied: (e) ->
wait = moment().add(e.timeUntilResubmit, 'ms').fromNow()
#@playSound 'manual-cast-denied', 1.0 # find some sound for this?
noty text: "You can try again #{wait}.", layout: 'center', type: 'warning', killer: false, timeout: 6000
onNewWorld: (e) ->
@casting = false
if @hasCastOnce # Don't play this sound the first time
@playSound 'cast-end', 0.5 unless @options.level.isType('game-dev')
# Worked great for live beginner tournaments, but probably annoying for asynchronous tournament mode.
myHeroID = if me.team is 'ogres' then 'Hero Placeholder 1' else 'Hero Placeholder'
if @autoSubmitsToLadder and not e.world.thangMap[myHeroID]?.errorsOut and not me.get('anonymous')
_.delay (=> @ladderSubmissionView?.rankSession()), 1000 if @ladderSubmissionView
@hasCastOnce = true
@updateCastButton()
@world = e.world
onNewGoalStates: (e) ->
winnable = e.overallStatus is 'success'
return if @winnable is winnable
@winnable = winnable
@$el.toggleClass 'winnable', @winnable
Backbone.Mediator.publish 'tome:winnability-updated', winnable: @winnable, level: @options.level
if @options.level.get('hidesRealTimePlayback') or @options.level.isType('web-dev', 'game-dev')
@$el.find('.done-button').toggle @winnable
else if @winnable and @options.level.get('slug') in ['course-thornbush-farm', 'thornbush-farm']
@$el.find('.submit-button').show() # Hide submit until first win so that script can explain it.
onGoalsCalculated: (e) ->
# When preloading, with real-time playback enabled, we highlight the submit button when we think they'll win.
return unless e.god is @god
return unless e.preload
return if @options.level.get 'hidesRealTimePlayback'
return if @options.level.get('slug') in ['course-thornbush-farm', 'thornbush-farm'] # Don't show it until they actually win for this first one.
@onNewGoalStates e
onPlaybackEndedChanged: (e) ->
return unless e.ended and @winnable
@$el.toggleClass 'has-seen-winning-replay', true
updateCastButton: ->
return if _.some @spells, (spell) => not spell.loaded
async.some _.values(@spells), (spell, callback) =>
spell.hasChangedSignificantly spell.getSource(), null, callback
, (castable) =>
Backbone.Mediator.publish 'tome:spell-has-changed-significantly-calculation', hasChangedSignificantly: castable
@castButton.toggleClass('castable', castable).toggleClass('casting', @casting)
if @casting
castText = $.i18n.t('play_level.tome_cast_button_running')
else if castable or true
castText = $.i18n.t('play_level.tome_cast_button_run')
unless @options.level.get 'hidesRunShortcut' # Hide for first few.
castText += ' ' + @castShortcut
else
castText = $.i18n.t('play_level.tome_cast_button_ran')
@castButton.text castText
#@castButton.prop 'disabled', not castable
@ladderSubmissionView?.updateButton()
updateReplayability: =>
return if @destroyed
return unless @options.level.get 'replayable'
timeUntilResubmit = @options.session.timeUntilResubmit()
disabled = timeUntilResubmit > 0
submitButton = @$el.find('.submit-button').toggleClass('disabled', disabled)
submitAgainLabel = submitButton.find('.submit-again-time').toggleClass('secret', not disabled)
if disabled
waitTime = moment().add(timeUntilResubmit, 'ms').fromNow()
submitAgainLabel.text waitTime
loadMirrorSession: ->
url = "/db/level/#{@options.level.get('slug') or @options.level.id}/session"
url += "?team=#{if me.team is 'humans' then 'ogres' else 'humans'}"
mirrorSession = new LevelSession().setURL url
@mirrorSession = @supermodel.loadModel(mirrorSession, {cache: false}).model
updateLadderSubmissionViews: ->
@removeSubView subview for key, subview of @subviews when subview instanceof LadderSubmissionView
placeholder = @$el.find('.ladder-submission-view')
return unless placeholder.length
@ladderSubmissionView = new LadderSubmissionView session: @options.session, level: @options.level, mirrorSession: @mirrorSession
@insertSubView @ladderSubmissionView, placeholder