diff --git a/app/styles/play/level/modal/hero-victory-modal.sass b/app/styles/play/level/modal/hero-victory-modal.sass index d825d9926..e3429b0b7 100644 --- a/app/styles/play/level/modal/hero-victory-modal.sass +++ b/app/styles/play/level/modal/hero-victory-modal.sass @@ -19,10 +19,11 @@ #victory-header display: block margin: 15px auto 0 - @include transition(0.25s ease-in) + // http://easings.net/#easeOutBack plus tweaked a bit: http://cubic-bezier.com/#.18,.68,.75,2 + @include transition(0.5s cubic-bezier(0.18, 0.68, 0.75, 2)) &.out - margin-top: -100px + @include scale(0) .modal-header height: 85px @@ -95,10 +96,10 @@ @include scale(1.5) z-index: 2 - .reward-text - font-size: 18px - overflow: visible - bottom: 9px + &.numerical &.animating .reward-text + font-size: 18px + overflow: visible + bottom: 9px .reward-image-container top: 8px @@ -113,6 +114,13 @@ &.show @include scale(1) + &.pending-reward-image + img + -webkit-filter: brightness(2000%) contrast(25%) + -moz-filter: brightness(2000%) contrast(25%) + -o-filter: brightness(2000%) contrast(25%) + filter: brightness(2000%) contrast(25%) + img margin: 0 position: absolute diff --git a/app/templates/play/level/modal/hero-victory-modal.jade b/app/templates/play/level/modal/hero-victory-modal.jade index 1ae5041bc..4be673ed1 100644 --- a/app/templates/play/level/modal/hero-victory-modal.jade +++ b/app/templates/play/level/modal/hero-victory-modal.jade @@ -15,31 +15,31 @@ block modal-body-content - var worth = achievement.get('worth', true); if worth .reward-panel.numerical.xp(data-number=worth, data-number-unit='xp') - .reward-image-container(class=animate?'':'show') + .reward-image-container(class=animate ? 'pending-reward-image' : 'show') img(src="/images/pages/play/level/modal/reward_icon_xp.png") .reward-text= animate ? '+0' : '+'+worth if rewards.gems .reward-panel.numerical.gems(data-number=rewards.gems, data-number-unit='gem') - .reward-image-container(class=animate?'':'show') + .reward-image-container(class=animate ? 'pending-reward-image' : 'show') img(src="/images/pages/play/level/modal/reward_icon_gems.png") .reward-text= animate ? '+0' : '+'+rewards.gems if rewards.heroes for hero in rewards.heroes - var hero = thangTypes[hero]; - .reward-panel.hero - .reward-image-container(class=animate?'':'show') + .reward-panel.hero(data-hero-thang-type=hero.get('original')) + .reward-image-container(class=animate ? 'pending-reward-image' : 'show') img(src=hero.getPortraitURL()) - .reward-text= hero.get('name') + .reward-text= animate ? 'New Hero' : hero.get('name') if rewards.items for item in rewards.items - var item = thangTypes[item]; - .reward-panel.item - .reward-image-container(class=animate?'':'show') + .reward-panel.item(data-item-thang-type=item.get('original')) + .reward-image-container(class=animate ? 'pending-reward-image' : 'show') img(src=item.getPortraitURL()) - .reward-text= item.get('name') + .reward-text= animate ? 'New Item' : item.get('name') block modal-footer-content @@ -60,7 +60,7 @@ block modal-footer-content a.btn.btn-success.world-map-button.hide#continue-button(href="/play-hero", data-dismiss="modal", data-i18n="play_level.victory_play_continue") Continue if me.get('anonymous') - p.sign-up-poke + p.sign-up-poke.hide button.btn.btn-success.sign-up-button.btn-large(data-toggle="coco-modal", data-target="modal/SignupModal", data-i18n="play_level.victory_sign_up") Sign Up to Save Progress span(data-i18n="play_level.victory_sign_up_poke") Want to save your code? Create a free account! diff --git a/app/views/play/level/modal/HeroVictoryModal.coffee b/app/views/play/level/modal/HeroVictoryModal.coffee index eb516d11b..448f67562 100644 --- a/app/views/play/level/modal/HeroVictoryModal.coffee +++ b/app/views/play/level/modal/HeroVictoryModal.coffee @@ -7,6 +7,7 @@ LocalMongo = require 'lib/LocalMongo' utils = require 'lib/utils' ThangType = require 'models/ThangType' LadderSubmissionView = require 'views/play/common/LadderSubmissionView' +AudioPlayer = require 'lib/AudioPlayer' module.exports = class HeroVictoryModal extends ModalView id: 'hero-victory-modal' @@ -45,7 +46,7 @@ module.exports = class HeroVictoryModal extends ModalView for thangTypeOriginal in thangTypeOriginals thangType = new ThangType() thangType.url = "/db/thang.type/#{thangTypeOriginal}/version" - thangType.project = ['original', 'rasterIcon', 'name'] + thangType.project = ['original', 'rasterIcon', 'name', 'soundTriggers'] @thangTypes[thangTypeOriginal] = @supermodel.loadModel(thangType, 'thang').model if achievementIDs.length @@ -86,7 +87,7 @@ module.exports = class HeroVictoryModal extends ModalView ## achievement.completedAWhileAgo = index > 1 # achievement.completed = true # achievement.completedAWhileAgo = false - # achievement.attributes.worth = (index + 1) * achievement.get('worth') + # achievement.attributes.worth = (index + 1) * achievement.get('worth', true) # rewards = achievement.get('rewards') # rewards.gems *= (index + 1) @@ -99,10 +100,14 @@ module.exports = class HeroVictoryModal extends ModalView afterRender: -> super() return unless @supermodel.finished() + @playSelectionSound hero, true for original, hero of @thangTypes # Preload them @$el.addClass 'with-sign-up' if me.get('anonymous') @updateSavingProgressStatus() - @$el.find('#victory-header').delay(250).queue(-> $(@).removeClass('out').dequeue()) - complete = _.once(_.bind(@beginAnimateNumbers, @)) + @$el.find('#victory-header').delay(250).queue(-> + $(@).removeClass('out').dequeue() + Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'victory-title-appear' # TODO: actually add this + ) + complete = _.once(_.bind(@beginSequentialAnimations, @)) @animatedPanels = $() panels = @$el.find('.achievement-panel') for panel in panels @@ -126,29 +131,34 @@ module.exports = class HeroVictoryModal extends ModalView @ladderSubmissionView = new LadderSubmissionView session: @session, level: @level @insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view') - beginAnimateNumbers: -> - @numericalItemPanels = _.map(@animatedPanels.find('.numerical'), (panel) -> { + beginSequentialAnimations: -> + @sequentialAnimatedPanels = _.map(@animatedPanels.find('.reward-panel'), (panel) -> { number: $(panel).data('number') textEl: $(panel).find('.reward-text') rootEl: $(panel) unit: $(panel).data('number-unit') + hero: $(panel).data('hero-thang-type') + item: $(panel).data('item-thang-type') }) @totalXP = 0 - @totalXP += panel.number for panel in @numericalItemPanels when panel.unit is 'xp' + @totalXP += panel.number for panel in @sequentialAnimatedPanels when panel.unit is 'xp' @totalGems = 0 - @totalGems += panel.number for panel in @numericalItemPanels when panel.unit is 'gem' + @totalGems += panel.number for panel in @sequentialAnimatedPanels when panel.unit is 'gem' @gemEl = $('#gem-total') @XPEl = $('#xp-total') @totalXPAnimated = @totalGemsAnimated = @lastTotalXP = @lastTotalGems = 0 - @numberAnimationStart = new Date() - @numberAnimationInterval = setInterval(@tickNumberAnimation, 1000 / 60) + @sequentialAnimationStart = new Date() + @sequentialAnimationInterval = setInterval(@tickSequentialAnimation, 1000 / 60) - tickNumberAnimation: => + tickSequentialAnimation: => # TODO: make sure the animation pulses happen when the numbers go up and sounds play (up to a max speed) - return @endAnimateNumbers() unless panel = @numericalItemPanels[0] - duration = Math.log(panel.number + 1) / Math.LN10 * 1000 # Math.log10 is ES6 - ratio = @getEaseRatio (new Date() - @numberAnimationStart), duration + return @endSequentialAnimations() unless panel = @sequentialAnimatedPanels[0] + if panel.number + duration = Math.log(panel.number + 1) / Math.LN10 * 1000 # Math.log10 is ES6 + else + duration = 1000 + ratio = @getEaseRatio (new Date() - @sequentialAnimationStart), duration if panel.unit is 'xp' newXP = Math.floor(ratio * panel.number) totalXP = @totalXPAnimated + newXP @@ -158,7 +168,7 @@ module.exports = class HeroVictoryModal extends ModalView xpTrigger = 'xp-' + (totalXP % 6) # 6 xp sounds Backbone.Mediator.publish 'audio-player:play-sound', trigger: xpTrigger, volume: 0.5 + ratio / 2 @lastTotalXP = totalXP - else + else if panel.unit is 'gem' newGems = Math.floor(ratio * panel.number) totalGems = @totalGemsAnimated + newGems if totalGems isnt @lastTotalGems @@ -167,16 +177,24 @@ module.exports = class HeroVictoryModal extends ModalView 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 + else if panel.item + thangType = @thangTypes[panel.item] + panel.textEl.text(thangType.get('name')) + Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'item-unlocked', volume: 1 if 0.5 < ratio < 0.6 + else if panel.hero + thangType = @thangTypes[panel.hero] + panel.textEl.text(thangType.get('name')) + @playSelectionSound hero if 0.5 < ratio < 0.6 if ratio is 1 panel.rootEl.removeClass('animating').find('.reward-image-container img').removeClass('pulse') - @numberAnimationStart = new Date() + @sequentialAnimationStart = new Date() if panel.unit is 'xp' @totalXPAnimated += panel.number - else + else if panel.unit is 'gem' @totalGemsAnimated += panel.number - @numericalItemPanels.shift() + @sequentialAnimatedPanels.shift() return - panel.rootEl.addClass('animating').find('.reward-image-container img').addClass('pulse') + panel.rootEl.addClass('animating').find('.reward-image-container').removeClass('pending-reward-image').find('img').addClass('pulse') getEaseRatio: (timeSinceStart, duration) -> # Ease in/out quadratic - http://gizma.com/easing/ @@ -187,8 +205,8 @@ module.exports = class HeroVictoryModal extends ModalView --t -0.5 * (t * (t - 2) - 1) - endAnimateNumbers: -> - clearInterval @numberAnimationInterval + endSequentialAnimations: -> + clearInterval @sequentialAnimationInterval @animationComplete = true @updateSavingProgressStatus() @@ -196,14 +214,23 @@ module.exports = class HeroVictoryModal extends ModalView return unless @animationComplete @$el.find('#saving-progress-label').toggleClass('hide', @readyToContinue) @$el.find('#continue-button').toggleClass('hide', not @readyToContinue) + @$el.find('.sign-up-poke').toggleClass('hide', not @readyToContinue) onGameSubmitted: (e) -> ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches" Backbone.Mediator.publish 'router:navigate', route: ladderURL + playSelectionSound: (hero, preload=false) -> + return unless sounds = hero.get('soundTriggers')?.selected + return unless sound = sounds[Math.floor Math.random() * sounds.length] + name = AudioPlayer.nameForSoundReference sound + if preload + AudioPlayer.preloadSoundReference sound + else + AudioPlayer.playSound name, 1 # TODO: award heroes/items and play an awesome sound when you get one destroy: -> - clearInterval @numberAnimationInterval + clearInterval @sequentialAnimationInterval super()