CocoView = require 'views/core/CocoView' template = require 'templates/play/level/level-dialogue-view' DialogueAnimator = require './DialogueAnimator' module.exports = class LevelDialogueView extends CocoView id: 'level-dialogue-view' template: template subscriptions: 'sprite:speech-updated': 'onSpriteDialogue' 'level:sprite-clear-dialogue': 'onSpriteClearDialogue' 'level:shift-space-pressed': 'onShiftSpacePressed' 'level:escape-pressed': 'onEscapePressed' 'sprite:dialogue-sound-completed': 'onDialogueSoundCompleted' events: 'click': 'onClick' 'click a': 'onClickLink' constructor: (options) -> super options @level = options.level @sessionID = options.sessionID onClick: (e) -> Backbone.Mediator.publish 'tome:focus-editor', {} onClickLink: (e) -> route = $(e.target).attr('href') if route and /item-store/.test route PlayItemsModal = require 'views/play/modal/PlayItemsModal' @openModalView new PlayItemsModal supermodel: @supermodal e.stopPropagation() onSpriteDialogue: (e) -> return unless e.message @$el.addClass 'active speaking' $('body').addClass('dialogue-view-active') @setMessage e.message, e.mood, e.responses window.tracker?.trackEvent 'Heard Sprite', {message: e.message, label: e.message, ls: @sessionID} onDialogueSoundCompleted: -> @$el.removeClass 'speaking' onSpriteClearDialogue: -> @$el.removeClass 'active speaking' $('body').removeClass('dialogue-view-active') setMessage: (message, mood, responses) -> message = marked message # Fix old HTML icons like in the Markdown message = message.replace /<i class='(.+?)'><\/i>/, "" clearInterval(@messageInterval) if @messageInterval @bubble = $('.dialogue-bubble', @$el) @bubble.removeClass(@lastMood) if @lastMood @lastMood = mood @bubble.text('') group = $('
') @bubble.append(group) if responses @lastResponses = responses for response in responses button = $('').text(response.text) button.addClass response.buttonClass if response.buttonClass group.append(button) response.button = $('button:last', group) else s = $.i18n.t('play_level.hud_continue_short', defaultValue: 'Continue') sk = $.i18n.t('play_level.skip_tutorial', defaultValue: 'skip: esc') if not @escapePressed group.append('' + sk + '') group.append($('')) @lastResponses = null @animator = new DialogueAnimator(message, @bubble) @messageInterval = setInterval(@addMoreMessage, 1000 / 30) # 30 FPS addMoreMessage: => if @animator.done() clearInterval(@messageInterval) @messageInterval = null $('.enter', @bubble).removeClass('secret').css('opacity', 0.0).delay(500).animate({opacity: 1.0}, 500, @animateEnterButton) if @lastResponses buttons = $('.enter button') for response, i in @lastResponses channel = response.channel.replace 'level-set-playing', 'level:set-playing' # Easier than migrating all those victory buttons. f = (r) => => setTimeout((-> Backbone.Mediator.publish(channel, r.event or {})), 10) $(buttons[i]).click(f(response)) else $('.enter', @bubble).click(-> Backbone.Mediator.publish('script:end-current-script', {})) return @animator.tick() onShiftSpacePressed: (e) -> @shiftSpacePressed = (@shiftSpacePressed || 0) + 1 # We don't need to handle script:end-current-script--that's done--but if we do have # custom buttons, then we need to trigger the one that should fire (the last one). # If we decide that always having the last one fire is bad, we should make it smarter. return unless @lastResponses?.length r = @lastResponses[@lastResponses.length - 1] channel = r.channel.replace 'level-set-playing', 'level:set-playing' _.delay (-> Backbone.Mediator.publish(channel, r.event or {})), 10 onEscapePressed: (e) -> @escapePressed = true animateEnterButton: => return unless @bubble button = $('.enter', @bubble) dot = $('.dot', button) dot.animate({opacity: 0.2}, 300).animate({opacity: 1.9}, 600, @animateEnterButton) destroy: -> clearInterval(@messageInterval) if @messageInterval super()