2014-11-28 20:49:41 -05:00
ModalView = require ' views/core/ModalView '
2014-12-08 16:45:01 -05:00
AuthModal = require ' views/core/AuthModal '
2014-09-30 19:14:47 -04:00
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 '
2014-11-28 20:49:41 -05:00
utils = require ' core/utils '
2014-09-30 19:14:47 -04:00
ThangType = require ' models/ThangType '
2014-10-19 20:38:10 -04:00
LadderSubmissionView = require ' views/play/common/LadderSubmissionView '
2014-10-20 22:01:00 -04:00
AudioPlayer = require ' lib/AudioPlayer '
2014-12-07 17:03:11 -05:00
User = require ' models/User '
utils = require ' core/utils '
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-10-23 19:36:59 -04:00
events:
' click # continue-button ' : ' onClickContinue '
2015-01-30 15:27:19 -05:00
' click .leaderboard-button ' : ' onClickLeaderboard '
2014-11-03 12:58:57 -05:00
' click .return-to-ladder-button ' : ' onClickReturnToLadder '
2014-12-08 16:45:01 -05:00
' click .sign-up-button ' : ' onClickSignupButton '
2014-10-23 19:36:59 -04:00
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-22 13:46:34 -04:00
@waitingToContinueSince = new Date ( )
2014-12-07 17:03:11 -05:00
@previousXP = me . get ' points ' , true
@previousLevel = me . level ( )
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-10-23 19:36:59 -04:00
destroy: ->
clearInterval @ sequentialAnimationInterval
super ( )
2014-10-23 23:03:19 -04:00
onHidden: ->
Backbone . Mediator . publish ' music-player:exit-menu ' , { }
super ( )
2014-09-30 19:14:47 -04:00
onAchievementsLoaded: ->
2014-12-07 17:03:11 -05:00
@ $el . toggleClass ' full-achievements ' , @ achievements . models . length is 3
2014-09-30 19:14:47 -04:00
thangTypeOriginals = [ ]
2014-10-10 16:11:35 -04:00
achievementIDs = [ ]
2014-09-30 19:14:47 -04:00
for achievement in @ achievements . models
2014-10-22 16:52:37 -04:00
rewards = achievement . get ( ' rewards ' ) or { }
2014-09-30 19:14:47 -04:00
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-20 22:01:00 -04:00
thangType.project = [ ' original ' , ' rasterIcon ' , ' name ' , ' soundTriggers ' ]
2014-09-30 19:14:47 -04:00
@ thangTypes [ thangTypeOriginal ] = @ supermodel . loadModel ( thangType , ' thang ' ) . model
2014-10-13 17:18:33 -04:00
2014-11-26 15:02:42 -05:00
@newEarnedAchievements = [ ]
for achievement in @ achievements . models
continue unless achievement . completed
ea = new EarnedAchievement ( {
collection: achievement . get ( ' collection ' )
triggeredBy: @ session . id
achievement: achievement . id
2014-10-13 17:18:33 -04:00
} )
2014-11-26 15:02:42 -05:00
ea . save ( )
@ newEarnedAchievements . push ea
@ listenToOnce ea , ' sync ' , ->
if _ . all ( ( ea . id for ea in @ newEarnedAchievements ) )
2015-01-12 17:43:29 -05:00
@ newEarnedAchievementsResource . markLoaded ( )
2014-11-26 15:02:42 -05:00
@ listenToOnce me , ' sync ' , ->
@readyToContinue = true
@ updateSavingProgressStatus ( )
2015-01-07 21:36:02 -05:00
me . fetch cache: false unless me . loading
2014-11-27 12:44:08 -05:00
2014-11-26 15:02:42 -05:00
@readyToContinue = true if not @ achievements . models . length
2015-01-21 14:49:56 -05:00
2015-01-12 17:43:29 -05:00
# have to use a something resource because addModelResource doesn't handle models being upserted/fetched via POST like we're doing here
@newEarnedAchievementsResource = @ supermodel . addSomethingResource ( ' earned achievements ' ) if @ newEarnedAchievements . length
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 '
2015-01-12 17:43:29 -05:00
earnedAchievementMap = _ . indexBy ( @ newEarnedAchievements 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
2015-01-12 17:43:29 -05:00
achievement.completedAWhileAgo = new Date ( ) . getTime ( ) - Date . parse ( earnedAchievement . get ( ' created ' ) ) > 30 * 1000
2015-01-07 21:36:02 -05:00
achievement.worth = achievement . get ' worth ' , true
achievement.gems = achievement . get ( ' rewards ' ) ? . gems
c.achievements = @ achievements . models . slice ( )
for achievement in c . achievements
continue unless @ supermodel . finished ( ) and proportionalTo = achievement . get ' proportionalTo '
# For repeatable achievements, we modify their base worth/gems by their repeatable growth functions.
achievedAmount = utils . getByPath @ session . attributes , proportionalTo
func = achievement . getExpFunction ( )
achievement.worth = ( achievement . get ( ' worth ' ) ? 0 ) * func achievedAmount
rewards = achievement . get ' rewards '
achievement.gems = rewards ? . gems * func achievedAmount if rewards ? . gems
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
2014-10-20 22:01:00 -04:00
# achievement.attributes.worth = (index + 1) * achievement.get('worth', true)
2014-10-22 16:52:37 -04:00
# rewards = achievement.get('rewards') or {}
2014-10-17 23:15:41 -04:00
# 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-11-27 12:44:08 -05:00
elapsed = ( new Date ( ) - new Date ( me . get ( ' dateCreated ' ) ) )
isHourOfCode = me . get ( ' hourOfCode ' ) or elapsed < 120 * 60 * 1000
# Later we should only check me.get('hourOfCode'), but for now so much traffic comes in that we just assume it.
if isHourOfCode
# Show the Hour of Code "I'm Done" tracking pixel after they played for 20 minutes
enough = elapsed >= 20 * 60 * 1000
tooMuch = elapsed > 120 * 60 * 1000
showDone = elapsed >= 30 * 60 * 1000 and not tooMuch
if enough and not tooMuch and not me . get ( ' hourOfCodeComplete ' )
$ ( ' body ' ) . append ( $ ( ' <img src= " http://code.org/api/hour/finish_codecombat.png " style= " visibility: hidden; " > ' ) )
me . set ' hourOfCodeComplete ' , true # Note that this will track even for players who don't have hourOfCode set.
me . patch ( )
window . tracker ? . trackEvent ' Hour of Code Finish ' , { }
# Show the "I'm done" button between 30 - 120 minutes if they definitely came from Hour of Code
c.showHourOfCodeDoneButton = me . get ( ' hourOfCode ' ) and showDone
2015-01-31 00:36:36 -05:00
if @ level . get ( ' scoreTypes ' ) ? . length
lg = me . getLeaderboardsGroup ( )
c.showLeaderboard = lg is ' always '
c.showLeaderboard = true if me . level ( ) >= 3 and lg . group is ' early '
c.showLeaderboard = true if me . level ( ) >= 5 and lg . group is ' late '
2015-01-30 15:27:19 -05:00
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-20 22:01:00 -04:00
@ playSelectionSound hero , true for original , hero of @ thangTypes # Preload them
2014-10-13 17:18:33 -04:00
@ updateSavingProgressStatus ( )
2014-12-07 17:03:11 -05:00
@ updateXPBars 0
2014-10-20 22:01:00 -04:00
@ $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 , @ ) )
2014-10-10 16:11:35 -04:00
@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-23 23:03:19 -04:00
complete ( ) if @ animationComplete
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-20 22:01:00 -04:00
beginSequentialAnimations: ->
2014-11-10 18:16:28 -05:00
return if @ destroyed
2014-10-20 22:01:00 -04:00
@sequentialAnimatedPanels = _ . map ( @ animatedPanels . find ( ' .reward-panel ' ) , (panel) -> {
2014-10-10 16:11:35 -04:00
number: $ ( panel ) . data ( ' number ' )
textEl: $ ( panel ) . find ( ' .reward-text ' )
rootEl: $ ( panel )
unit: $ ( panel ) . data ( ' number-unit ' )
2014-10-20 22:01:00 -04:00
hero: $ ( panel ) . data ( ' hero-thang-type ' )
item: $ ( panel ) . data ( ' item-thang-type ' )
2014-10-10 16:11:35 -04:00
} )
2014-10-14 14:11:56 -04:00
2014-10-10 16:11:35 -04:00
@totalXP = 0
2014-10-20 22:01:00 -04:00
@ totalXP += panel . number for panel in @ sequentialAnimatedPanels when panel . unit is ' xp '
2014-10-10 16:11:35 -04:00
@totalGems = 0
2014-10-20 22:01:00 -04:00
@ totalGems += panel . number for panel in @ sequentialAnimatedPanels when panel . unit is ' gem '
2014-10-10 16:11:35 -04:00
@gemEl = $ ( ' # gem-total ' )
@XPEl = $ ( ' # xp-total ' )
2014-10-17 23:15:41 -04:00
@totalXPAnimated = @totalGemsAnimated = @lastTotalXP = @lastTotalGems = 0
2014-10-20 22:01:00 -04:00
@sequentialAnimationStart = new Date ( )
@sequentialAnimationInterval = setInterval ( @ tickSequentialAnimation , 1000 / 60 )
2014-10-14 14:11:56 -04:00
2014-10-20 22:01:00 -04:00
tickSequentialAnimation: =>
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-20 22:01:00 -04:00
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
2014-10-17 23:15:41 -04:00
if panel . unit is ' xp '
2014-10-20 19:13:56 -04:00
newXP = Math . floor ( ratio * panel . number )
totalXP = @ totalXPAnimated + newXP
2014-10-17 23:15:41 -04:00
if totalXP isnt @ lastTotalXP
2014-10-20 19:13:56 -04:00
panel . textEl . text ( ' + ' + newXP )
2014-12-07 17:03:11 -05:00
@ XPEl . text ( totalXP )
@ updateXPBars ( totalXP )
2014-10-17 23:15:41 -04:00
xpTrigger = ' xp- ' + ( totalXP % 6 ) # 6 xp sounds
Backbone . Mediator . publish ' audio-player:play-sound ' , trigger: xpTrigger , volume: 0.5 + ratio / 2
@lastTotalXP = totalXP
2014-10-20 22:01:00 -04:00
else if panel . unit is ' gem '
2014-10-20 19:13:56 -04:00
newGems = Math . floor ( ratio * panel . number )
totalGems = @ totalGemsAnimated + newGems
2014-10-17 23:15:41 -04:00
if totalGems isnt @ lastTotalGems
2014-10-20 19:13:56 -04:00
panel . textEl . text ( ' + ' + newGems )
2014-12-07 17:03:11 -05:00
@ gemEl . text ( totalGems )
2014-10-17 23:15:41 -04:00
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
2014-10-20 22:01:00 -04:00
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 ' ) )
2014-10-26 13:16:43 -04:00
@ playSelectionSound thangType if 0.5 < ratio < 0.6
2014-10-17 23:15:41 -04:00
if ratio is 1
panel . rootEl . removeClass ( ' animating ' ) . find ( ' .reward-image-container img ' ) . removeClass ( ' pulse ' )
2014-10-20 22:01:00 -04:00
@sequentialAnimationStart = new Date ( )
2014-10-17 23:15:41 -04:00
if panel . unit is ' xp '
@ totalXPAnimated += panel . number
2014-10-20 22:01:00 -04:00
else if panel . unit is ' gem '
2014-10-17 23:15:41 -04:00
@ totalGemsAnimated += panel . number
2014-10-20 22:01:00 -04:00
@ sequentialAnimatedPanels . shift ( )
2014-10-17 23:15:41 -04:00
return
2014-10-20 22:01:00 -04:00
panel . rootEl . addClass ( ' animating ' ) . find ( ' .reward-image-container ' ) . removeClass ( ' pending-reward-image ' ) . find ( ' img ' ) . addClass ( ' pulse ' )
2014-10-17 23:15:41 -04:00
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
2014-12-07 17:03:11 -05:00
updateXPBars: (achievedXP) ->
previousXP = @ previousXP
previousLevel = @ previousLevel
currentXP = previousXP + achievedXP
currentLevel = User . levelFromExp currentXP
currentLevelXP = User . expForLevel currentLevel
nextLevel = currentLevel + 1
nextLevelXP = User . expForLevel nextLevel
leveledUp = currentLevel > previousLevel
totalXPNeeded = nextLevelXP - currentLevelXP
alreadyAchievedPercentage = 100 * ( previousXP - currentLevelXP ) / totalXPNeeded
alreadyAchievedPercentage = 0 if alreadyAchievedPercentage < 0 # In case of level up
if leveledUp
newlyAchievedPercentage = 100 * ( currentXP - currentLevelXP ) / totalXPNeeded
else
newlyAchievedPercentage = 100 * achievedXP / totalXPNeeded
xpEl = $ ( ' # xp-wrapper ' )
xpBarJustEarned = xpEl . find ( ' .xp-bar-already-achieved ' ) . css ( ' width ' , alreadyAchievedPercentage + ' % ' )
xpBarTotal = xpEl . find ( ' .xp-bar-total ' ) . css ( ' width ' , ( alreadyAchievedPercentage + newlyAchievedPercentage ) + ' % ' )
levelLabel = xpEl . find ( ' .level ' )
utils . replaceText levelLabel , currentLevel
2014-12-07 22:38:24 -05:00
if leveledUp and ( not @ displayedLevel or currentLevel > @ displayedLevel )
@ playSound ' level-up '
@displayedLevel = currentLevel
2014-10-20 22:01:00 -04:00
endSequentialAnimations: ->
clearInterval @ sequentialAnimationInterval
2014-10-13 17:18:33 -04:00
@animationComplete = true
@ updateSavingProgressStatus ( )
2014-10-23 23:03:19 -04:00
Backbone . Mediator . publish ' music-player:enter-menu ' , terrain: @ level . get ( ' terrain ' , true )
2014-10-13 17:18:33 -04:00
updateSavingProgressStatus: ->
@ $el . find ( ' # saving-progress-label ' ) . toggleClass ( ' hide ' , @ readyToContinue )
2014-10-22 18:42:51 -04:00
@ $el . find ( ' .next-level-button ' ) . toggleClass ( ' hide ' , not @ readyToContinue )
2014-10-20 22:01:00 -04:00
@ $el . find ( ' .sign-up-poke ' ) . 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 "
2014-10-23 19:36:59 -04:00
# Preserve the supermodel as we navigate back to the ladder.
2014-11-29 19:46:36 -05:00
Backbone . Mediator . publish ' router:navigate ' , route: ladderURL , viewClass: ' views/ladder/LadderView ' , viewArgs: [ { supermodel: @ supermodel } , @ level . get ( ' slug ' ) ]
2014-10-19 20:38:10 -04:00
2014-10-20 22:01:00 -04:00
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
2014-10-19 20:38:10 -04:00
2014-11-10 15:47:24 -05:00
getNextLevelCampaign: ->
2015-01-21 14:49:56 -05:00
{ ' kithgard-gates ' : ' forest ' , ' siege-of-stonehold ' : ' desert ' , ' clash-of-clones ' : ' mountain ' } [ @ level . get ( ' slug ' ) ] or @ level . get ' campaign ' # Much easier to just keep this updated than to dynamically figure it out.
2014-10-29 13:47:17 -04:00
2014-12-28 16:25:20 -05:00
getNextLevelLink: ->
2014-10-29 13:47:17 -04:00
link = ' /play '
2014-11-10 15:47:24 -05:00
nextCampaign = @ getNextLevelCampaign ( )
2015-02-05 18:05:22 -05:00
link += ' / ' + nextCampaign
2014-12-28 16:25:20 -05:00
link
2014-11-10 15:47:24 -05:00
2015-01-30 15:27:19 -05:00
onClickContinue: (e, extraOptions=null) ->
2014-11-26 09:58:23 -05:00
@ playSound ' menu-button-click '
2014-12-28 16:25:20 -05:00
nextLevelLink = @ getNextLevelLink ( )
2014-12-05 18:44:49 -05:00
# Preserve the supermodel as we navigate back to the world map.
2015-01-30 15:27:19 -05:00
options =
justBeatLevel: @ level
supermodel: if @ options . hasReceivedMemoryWarning then null else @ supermodel
_ . merge options , extraOptions if extraOptions
Backbone . Mediator . publish ' router:navigate ' , route: nextLevelLink , viewClass: require ( ' views/play/CampaignView ' ) , viewArgs: [ options , @ getNextLevelCampaign ( ) ]
onClickLeaderboard: (e) ->
@ onClickContinue e , showLeaderboard: true
2014-11-03 12:58:57 -05:00
onClickReturnToLadder: (e) ->
2014-11-26 09:58:23 -05:00
@ playSound ' menu-button-click '
2014-11-03 12:58:57 -05:00
e . preventDefault ( )
route = $ ( e . target ) . data ( ' href ' )
# Preserve the supermodel as we navigate back to the ladder.
2014-11-29 19:46:36 -05:00
Backbone . Mediator . publish ' router:navigate ' , route: route , viewClass: ' views/ladder/LadderView ' , viewArgs: [ { supermodel: if @ options . hasReceivedMemoryWarning then null else @ supermodel } , @ level . get ( ' slug ' ) ]
2014-12-08 16:45:01 -05:00
onClickSignupButton: (e) ->
e . preventDefault ( )
window . tracker ? . trackEvent ' Started Signup ' , category: ' Play Level ' , label: ' Hero Victory Modal ' , level: @ level . get ( ' slug ' )
@ openModalView new AuthModal { mode: ' signup ' }