2014-09-30 19:14:47 -04:00
|
|
|
ModalView = require 'views/kinds/ModalView'
|
|
|
|
template = require 'templates/play/level/modal/hero-victory-modal'
|
|
|
|
Achievement = require 'models/Achievement'
|
2014-10-10 16:11:35 -04:00
|
|
|
EarnedAchievement = require 'models/EarnedAchievement'
|
2014-09-30 19:14:47 -04:00
|
|
|
CocoCollection = require 'collections/CocoCollection'
|
|
|
|
LocalMongo = require 'lib/LocalMongo'
|
|
|
|
utils = require 'lib/utils'
|
|
|
|
ThangType = require 'models/ThangType'
|
2014-10-19 20:38:10 -04:00
|
|
|
LadderSubmissionView = require 'views/play/common/LadderSubmissionView'
|
2014-09-30 19:14:47 -04:00
|
|
|
|
2014-10-10 16:11:35 -04:00
|
|
|
module.exports = class HeroVictoryModal extends ModalView
|
2014-09-30 19:14:47 -04:00
|
|
|
id: 'hero-victory-modal'
|
|
|
|
template: template
|
2014-10-10 16:11:35 -04:00
|
|
|
closeButton: false
|
2014-10-14 14:11:56 -04:00
|
|
|
closesOnClickOutside: false
|
2014-09-30 19:14:47 -04:00
|
|
|
|
2014-10-19 20:38:10 -04:00
|
|
|
subscriptions:
|
|
|
|
'ladder:game-submitted': 'onGameSubmitted'
|
|
|
|
|
2014-09-30 19:14:47 -04:00
|
|
|
constructor: (options) ->
|
|
|
|
super(options)
|
|
|
|
@session = options.session
|
|
|
|
@level = options.level
|
|
|
|
achievements = new CocoCollection([], {
|
|
|
|
url: "/db/achievement?related=#{@session.get('level').original}"
|
|
|
|
model: Achievement
|
|
|
|
})
|
|
|
|
@thangTypes = {}
|
|
|
|
@achievements = @supermodel.loadCollection(achievements, 'achievements').model
|
|
|
|
@listenToOnce @achievements, 'sync', @onAchievementsLoaded
|
2014-10-13 17:18:33 -04:00
|
|
|
@readyToContinue = false
|
2014-10-17 23:15:41 -04:00
|
|
|
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'victory'
|
2014-10-14 14:11:56 -04:00
|
|
|
|
2014-09-30 19:14:47 -04:00
|
|
|
onAchievementsLoaded: ->
|
|
|
|
thangTypeOriginals = []
|
2014-10-10 16:11:35 -04:00
|
|
|
achievementIDs = []
|
2014-09-30 19:14:47 -04:00
|
|
|
for achievement in @achievements.models
|
|
|
|
rewards = achievement.get('rewards')
|
|
|
|
thangTypeOriginals.push rewards.heroes or []
|
|
|
|
thangTypeOriginals.push rewards.items or []
|
2014-10-13 17:18:33 -04:00
|
|
|
achievement.completed = LocalMongo.matchesQuery(@session.attributes, achievement.get('query'))
|
|
|
|
achievementIDs.push(achievement.id) if achievement.completed
|
2014-10-14 14:11:56 -04:00
|
|
|
|
2014-09-30 19:14:47 -04:00
|
|
|
thangTypeOriginals = _.uniq _.flatten thangTypeOriginals
|
|
|
|
for thangTypeOriginal in thangTypeOriginals
|
|
|
|
thangType = new ThangType()
|
|
|
|
thangType.url = "/db/thang.type/#{thangTypeOriginal}/version"
|
2014-10-10 16:11:35 -04:00
|
|
|
thangType.project = ['original', 'rasterIcon', 'name']
|
2014-09-30 19:14:47 -04:00
|
|
|
@thangTypes[thangTypeOriginal] = @supermodel.loadModel(thangType, 'thang').model
|
2014-10-13 17:18:33 -04:00
|
|
|
|
|
|
|
if achievementIDs.length
|
|
|
|
url = "/db/earned_achievement?view=get-by-achievement-ids&achievementIDs=#{achievementIDs.join(',')}"
|
|
|
|
earnedAchievements = new CocoCollection([], {
|
|
|
|
url: url
|
|
|
|
model: EarnedAchievement
|
|
|
|
})
|
|
|
|
earnedAchievements.sizeShouldBe = achievementIDs.length
|
|
|
|
res = @supermodel.loadCollection(earnedAchievements, 'earned_achievements')
|
|
|
|
@earnedAchievements = res.model
|
|
|
|
@listenTo @earnedAchievements, 'sync', ->
|
|
|
|
if @earnedAchievements.models.length < @earnedAchievements.sizeShouldBe
|
|
|
|
@earnedAchievements.fetch()
|
|
|
|
else
|
|
|
|
@listenToOnce me, 'sync', ->
|
|
|
|
@readyToContinue = true
|
|
|
|
@updateSavingProgressStatus()
|
|
|
|
me.fetch() unless me.loading
|
|
|
|
else
|
|
|
|
@readyToContinue = true
|
2014-10-14 14:11:56 -04:00
|
|
|
|
2014-09-30 19:14:47 -04:00
|
|
|
getRenderData: ->
|
|
|
|
c = super()
|
|
|
|
c.levelName = utils.i18n @level.attributes, 'name'
|
2014-10-10 16:11:35 -04:00
|
|
|
earnedAchievementMap = _.indexBy(@earnedAchievements?.models or [], (ea) -> ea.get('achievement'))
|
2014-10-13 17:18:33 -04:00
|
|
|
for achievement in @achievements.models
|
2014-10-10 16:11:35 -04:00
|
|
|
earnedAchievement = earnedAchievementMap[achievement.id]
|
|
|
|
if earnedAchievement
|
|
|
|
achievement.completedAWhileAgo = new Date() - Date.parse(earnedAchievement.get('created')) > 30 * 1000
|
2014-09-30 19:14:47 -04:00
|
|
|
c.achievements = @achievements.models
|
2014-10-10 16:11:35 -04:00
|
|
|
|
2014-10-17 23:15:41 -04:00
|
|
|
# for testing the three states
|
2014-10-17 20:57:18 -04:00
|
|
|
#if c.achievements.length
|
|
|
|
# c.achievements = [c.achievements[0].clone(), c.achievements[0].clone(), c.achievements[0].clone()]
|
|
|
|
#for achievement, index in c.achievements
|
2014-10-17 23:15:41 -04:00
|
|
|
## achievement.completed = index > 0
|
|
|
|
## achievement.completedAWhileAgo = index > 1
|
|
|
|
# achievement.completed = true
|
|
|
|
# achievement.completedAWhileAgo = false
|
|
|
|
# achievement.attributes.worth = (index + 1) * achievement.get('worth')
|
|
|
|
# rewards = achievement.get('rewards')
|
|
|
|
# rewards.gems *= (index + 1)
|
2014-10-10 16:11:35 -04:00
|
|
|
|
2014-09-30 19:14:47 -04:00
|
|
|
c.thangTypes = @thangTypes
|
2014-10-17 23:47:32 -04:00
|
|
|
c.me = me
|
2014-10-19 20:38:10 -04:00
|
|
|
c.readyToRank = @level.get('type', true) is 'hero-ladder' and @session.readyToRank()
|
2014-10-20 16:57:32 -04:00
|
|
|
c.level = @level
|
2014-10-10 16:11:35 -04:00
|
|
|
return c
|
2014-10-14 14:11:56 -04:00
|
|
|
|
2014-10-10 16:11:35 -04:00
|
|
|
afterRender: ->
|
|
|
|
super()
|
|
|
|
return unless @supermodel.finished()
|
2014-10-17 23:47:32 -04:00
|
|
|
@$el.addClass 'with-sign-up' if me.get('anonymous')
|
2014-10-13 17:18:33 -04:00
|
|
|
@updateSavingProgressStatus()
|
2014-10-17 23:15:41 -04:00
|
|
|
@$el.find('#victory-header').delay(250).queue(-> $(@).removeClass('out').dequeue())
|
2014-10-10 16:11:35 -04:00
|
|
|
complete = _.once(_.bind(@beginAnimateNumbers, @))
|
|
|
|
@animatedPanels = $()
|
|
|
|
panels = @$el.find('.achievement-panel')
|
|
|
|
for panel in panels
|
|
|
|
panel = $(panel)
|
|
|
|
continue unless panel.data('animate')
|
|
|
|
@animatedPanels = @animatedPanels.add(panel)
|
2014-10-17 23:15:41 -04:00
|
|
|
panel.delay(500) # Waiting for victory header to show up and fall
|
2014-10-10 16:11:35 -04:00
|
|
|
panel.queue(->
|
2014-10-17 23:15:41 -04:00
|
|
|
$(@).addClass('earned') # animate out the grayscale
|
|
|
|
$(@).dequeue()
|
2014-10-10 16:11:35 -04:00
|
|
|
)
|
|
|
|
panel.delay(500)
|
|
|
|
panel.queue(->
|
2014-10-17 23:15:41 -04:00
|
|
|
$(@).find('.reward-image-container').addClass('show')
|
|
|
|
$(@).dequeue()
|
2014-10-10 16:11:35 -04:00
|
|
|
)
|
|
|
|
panel.delay(500)
|
|
|
|
panel.queue(-> complete())
|
2014-10-14 14:11:56 -04:00
|
|
|
@animationComplete = not @animatedPanels.length
|
2014-10-19 20:38:10 -04:00
|
|
|
if @level.get('type', true) is 'hero-ladder'
|
|
|
|
@ladderSubmissionView = new LadderSubmissionView session: @session, level: @level
|
|
|
|
@insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view')
|
2014-10-14 14:11:56 -04:00
|
|
|
|
2014-10-10 16:11:35 -04:00
|
|
|
beginAnimateNumbers: ->
|
|
|
|
@numericalItemPanels = _.map(@animatedPanels.find('.numerical'), (panel) -> {
|
|
|
|
number: $(panel).data('number')
|
|
|
|
textEl: $(panel).find('.reward-text')
|
|
|
|
rootEl: $(panel)
|
|
|
|
unit: $(panel).data('number-unit')
|
|
|
|
})
|
2014-10-14 14:11:56 -04:00
|
|
|
|
2014-10-10 16:11:35 -04:00
|
|
|
@totalXP = 0
|
|
|
|
@totalXP += panel.number for panel in @numericalItemPanels when panel.unit is 'xp'
|
|
|
|
@totalGems = 0
|
|
|
|
@totalGems += panel.number for panel in @numericalItemPanels when panel.unit is 'gem'
|
|
|
|
@gemEl = $('#gem-total')
|
|
|
|
@XPEl = $('#xp-total')
|
2014-10-17 23:15:41 -04:00
|
|
|
@totalXPAnimated = @totalGemsAnimated = @lastTotalXP = @lastTotalGems = 0
|
|
|
|
@numberAnimationStart = new Date()
|
|
|
|
@numberAnimationInterval = setInterval(@tickNumberAnimation, 1000 / 60)
|
2014-10-14 14:11:56 -04:00
|
|
|
|
2014-10-10 16:11:35 -04:00
|
|
|
tickNumberAnimation: =>
|
2014-10-17 20:57:18 -04:00
|
|
|
# TODO: make sure the animation pulses happen when the numbers go up and sounds play (up to a max speed)
|
2014-10-17 23:15:41 -04:00
|
|
|
return @endAnimateNumbers() unless panel = @numericalItemPanels[0]
|
2014-10-20 12:41:28 -04:00
|
|
|
duration = Math.log(panel.number + 1) / Math.LN10 * 1000 # Math.log10 is ES6
|
2014-10-17 23:15:41 -04:00
|
|
|
ratio = @getEaseRatio (new Date() - @numberAnimationStart), duration
|
|
|
|
if panel.unit is 'xp'
|
|
|
|
totalXP = @totalXPAnimated + Math.floor(ratio * panel.number)
|
|
|
|
if totalXP isnt @lastTotalXP
|
|
|
|
panel.textEl.text('+' + totalXP)
|
|
|
|
@XPEl.text('+' + totalXP)
|
|
|
|
xpTrigger = 'xp-' + (totalXP % 6) # 6 xp sounds
|
|
|
|
Backbone.Mediator.publish 'audio-player:play-sound', trigger: xpTrigger, volume: 0.5 + ratio / 2
|
|
|
|
@lastTotalXP = totalXP
|
|
|
|
else
|
|
|
|
totalGems = @totalGemsAnimated + Math.floor(ratio * panel.number)
|
|
|
|
if totalGems isnt @lastTotalGems
|
|
|
|
panel.textEl.text('+' + totalGems)
|
|
|
|
@gemEl.text('+' + totalGems)
|
|
|
|
gemTrigger = 'gem-' + (parseInt(panel.number * ratio) % 4) # 4 gem sounds
|
|
|
|
Backbone.Mediator.publish 'audio-player:play-sound', trigger: gemTrigger, volume: 0.5 + ratio / 2
|
|
|
|
@lastTotalGems = totalGems
|
|
|
|
if ratio is 1
|
|
|
|
panel.rootEl.removeClass('animating').find('.reward-image-container img').removeClass('pulse')
|
|
|
|
@numberAnimationStart = new Date()
|
|
|
|
if panel.unit is 'xp'
|
|
|
|
@totalXPAnimated += panel.number
|
|
|
|
else
|
|
|
|
@totalGemsAnimated += panel.number
|
|
|
|
@numericalItemPanels.shift()
|
|
|
|
return
|
|
|
|
panel.rootEl.addClass('animating').find('.reward-image-container img').addClass('pulse')
|
|
|
|
|
|
|
|
getEaseRatio: (timeSinceStart, duration) ->
|
|
|
|
# Ease in/out quadratic - http://gizma.com/easing/
|
|
|
|
timeSinceStart = Math.min timeSinceStart, duration
|
|
|
|
t = 2 * timeSinceStart / duration
|
|
|
|
if t < 1
|
|
|
|
return 0.5 * t * t
|
|
|
|
--t
|
|
|
|
-0.5 * (t * (t - 2) - 1)
|
2014-10-10 16:11:35 -04:00
|
|
|
|
|
|
|
endAnimateNumbers: ->
|
2014-10-17 23:15:41 -04:00
|
|
|
clearInterval @numberAnimationInterval
|
2014-10-13 17:18:33 -04:00
|
|
|
@animationComplete = true
|
|
|
|
@updateSavingProgressStatus()
|
|
|
|
|
|
|
|
updateSavingProgressStatus: ->
|
|
|
|
return unless @animationComplete
|
|
|
|
@$el.find('#saving-progress-label').toggleClass('hide', @readyToContinue)
|
2014-10-14 14:11:56 -04:00
|
|
|
@$el.find('#continue-button').toggleClass('hide', not @readyToContinue)
|
2014-10-17 20:57:18 -04:00
|
|
|
|
2014-10-19 20:38:10 -04:00
|
|
|
onGameSubmitted: (e) ->
|
|
|
|
ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches"
|
|
|
|
Backbone.Mediator.publish 'router:navigate', route: ladderURL
|
|
|
|
|
|
|
|
|
2014-10-17 20:57:18 -04:00
|
|
|
# TODO: award heroes/items and play an awesome sound when you get one
|
2014-10-17 23:15:41 -04:00
|
|
|
|
|
|
|
destroy: ->
|
|
|
|
clearInterval @numberAnimationInterval
|
|
|
|
super()
|