2014-01-03 13:32:13 -05:00
View = require ' views/kinds/RootView '
template = require ' templates/play/level '
{ me } = require ( ' lib/auth ' )
ThangType = require ' models/ThangType '
2014-03-13 12:02:19 -04:00
utils = require ' lib/utils '
2014-01-03 13:32:13 -05:00
# temp hard coded data
World = require ' lib/world/world '
# tools
Surface = require ' lib/surface/Surface '
God = require ' lib/God '
GoalManager = require ' lib/world/GoalManager '
ScriptManager = require ' lib/scripts/ScriptManager '
2014-05-05 20:37:14 -04:00
LevelBus = require ' lib/LevelBus '
2014-01-03 13:32:13 -05:00
LevelLoader = require ' lib/LevelLoader '
LevelSession = require ' models/LevelSession '
Level = require ' models/Level '
LevelComponent = require ' models/LevelComponent '
2014-03-07 18:18:56 -05:00
Article = require ' models/Article '
2014-01-03 13:32:13 -05:00
Camera = require ' lib/surface/Camera '
2014-02-19 14:42:33 -05:00
AudioPlayer = require ' lib/AudioPlayer '
2014-01-03 13:32:13 -05:00
# subviews
2014-03-14 20:06:08 -04:00
LoadingView = require ' ./level/level_loading_view '
2014-01-03 13:32:13 -05:00
TomeView = require ' ./level/tome/tome_view '
ChatView = require ' ./level/level_chat_view '
HUDView = require ' ./level/hud_view '
ControlBarView = require ' ./level/control_bar_view '
PlaybackView = require ' ./level/playback_view '
GoalsView = require ' ./level/goals_view '
2014-02-11 15:02:27 -05:00
GoldView = require ' ./level/gold_view '
2014-01-03 13:32:13 -05:00
VictoryModal = require ' ./level/modal/victory_modal '
InfiniteLoopModal = require ' ./level/modal/infinite_loop_modal '
PROFILE_ME = false
module.exports = class PlayLevelView extends View
id: ' level-view '
template: template
cache: false
shortcutsEnabled: true
startsLoading: true
isEditorPreview: false
subscriptions:
' level-set-volume ' : (e) -> createjs . Sound . setVolume ( e . volume )
' level-show-victory ' : ' onShowVictory '
' restart-level ' : ' onRestartLevel '
' level-highlight-dom ' : ' onHighlightDom '
' end-level-highlight-dom ' : ' onEndHighlight '
' level-focus-dom ' : ' onFocusDom '
' level-disable-controls ' : ' onDisableControls '
' level-enable-controls ' : ' onEnableControls '
2014-02-06 17:00:27 -05:00
' god:new-world-created ' : ' onNewWorld '
2014-01-03 13:32:13 -05:00
' god:infinite-loop ' : ' onInfiniteLoop '
' level-reload-from-data ' : ' onLevelReloadFromData '
' play-next-level ' : ' onPlayNextLevel '
' edit-wizard-settings ' : ' showWizardSettingsModal '
' surface:world-set-up ' : ' onSurfaceSetUpNewWorld '
' level:session-will-save ' : ' onSessionWillSave '
2014-02-06 20:31:08 -05:00
' level:set-team ' : ' setTeam '
2014-03-14 20:06:08 -04:00
' level:started ' : ' onLevelStarted '
' level:loading-view-unveiled ' : ' onLoadingViewUnveiled '
2014-01-03 13:32:13 -05:00
events:
' click # level-done-button ' : ' onDonePressed '
2014-02-20 18:11:20 -05:00
shortcuts:
' ctrl+s ' : ' onCtrlS '
2014-01-03 13:32:13 -05:00
constructor: (options, @levelID) ->
console . profile ? ( ) if PROFILE_ME
super options
if not me . get ( ' hourOfCode ' ) and @ getQueryVariable " hour_of_code "
me . set ' hourOfCode ' , true
me . save ( )
$ ( ' body ' ) . append ( $ ( " <img src= ' http://code.org/api/hour/begin_codecombat.png ' style= ' visibility: hidden; ' > " ) )
2014-04-13 23:31:23 -04:00
application . tracker ? . trackEvent ' Hour of Code Begin ' , { }
2014-01-03 13:32:13 -05:00
2014-01-27 14:00:36 -05:00
@isEditorPreview = @ getQueryVariable ' dev '
@sessionID = @ getQueryVariable ' session '
2014-01-03 13:32:13 -05:00
2014-03-24 12:07:09 -04:00
$ ( window ) . on ( ' resize ' , @ onWindowResize )
2014-01-03 13:32:13 -05:00
@saveScreenshot = _ . throttle @ saveScreenshot , 30000
2014-01-16 14:37:04 -05:00
2014-01-27 14:00:36 -05:00
if @ isEditorPreview
2014-05-01 19:38:27 -04:00
# wait to see if it's just given to us through setLevel
f = => @ load ( ) unless @ levelLoader
2014-01-27 14:00:36 -05:00
setTimeout f , 100
else
@ load ( )
2014-04-13 23:31:23 -04:00
application . tracker ? . trackEvent ' Started Level Load ' , level: @ levelID , label: @ levelID
2014-01-03 13:32:13 -05:00
2014-03-24 02:53:41 -04:00
onLevelLoadError: (e) ->
2014-04-25 17:30:06 -04:00
# TODO NOW: remove this in favor of the supermodel handling it
2014-02-25 15:59:35 -05:00
application . router . navigate " /play?not_found= #{ @ levelID } " , { trigger: true }
2014-02-12 15:41:41 -05:00
2014-05-01 19:38:27 -04:00
setLevel: (@level, givenSupermodel) ->
@supermodel.models = givenSupermodel . models
@supermodel.collections = givenSupermodel . collections
@supermodel.shouldSaveBackups = givenSupermodel . shouldSaveBackups
2014-05-15 17:54:31 -04:00
serializedLevel = @ level . serialize @ supermodel
@ god ? . setLevel serializedLevel
2014-01-21 02:14:34 -05:00
if @ world
@ world . loadFromLevel serializedLevel , false
else
@ load ( )
2014-01-16 14:37:04 -05:00
2014-01-15 21:37:47 -05:00
load: ->
2014-04-13 23:31:23 -04:00
@loadStartTime = new Date ( )
2014-05-10 21:24:50 -04:00
@god = new God debugWorker: true
2014-05-02 15:32:41 -04:00
@levelLoader = new LevelLoader supermodel: @ supermodel , levelID: @ levelID , sessionID: @ sessionID , opponentSessionID: @ getQueryVariable ( ' opponent ' ) , team: @ getQueryVariable ( " team " )
2014-01-03 13:32:13 -05:00
getRenderData: ->
c = super ( )
c.world = @ world
2014-02-23 14:48:34 -05:00
if me . get ( ' hourOfCode ' ) and me . lang ( ) is ' en-US '
# Show the Hour of Code footer explanation until it's been more than a day
elapsed = ( new Date ( ) - new Date ( me . get ( ' dateCreated ' ) ) )
c.explainHourOfCode = elapsed < 86400 * 1000
2014-01-03 13:32:13 -05:00
c
afterRender: ->
2014-04-17 19:23:35 -04:00
super ( )
2014-01-03 13:32:13 -05:00
window . onPlayLevelViewLoaded ? @ # still a hack
2014-03-14 20:06:08 -04:00
@ insertSubView @loadingView = new LoadingView { }
2014-02-13 12:26:21 -05:00
@ $el . find ( ' # level-done-button ' ) . hide ( )
2014-04-11 19:15:26 -04:00
$ ( ' body ' ) . addClass ( ' is-playing ' )
2014-01-03 13:32:13 -05:00
2014-05-01 19:38:27 -04:00
updateProgress: (progress) ->
super ( progress )
2014-05-02 15:32:41 -04:00
if not @ worldInitialized and @ levelLoader . session . loaded and @ levelLoader . level . loaded and @ levelLoader . world and ( not @ levelLoader . opponentSession or @ levelLoader . opponentSession . loaded )
@ grabLevelLoaderData ( )
@ onWorldInitialized ( )
2014-03-07 18:18:56 -05:00
return if @ seenDocs
2014-03-12 16:49:28 -04:00
return unless @ levelLoader . session . loaded and @ levelLoader . level . loaded
2014-03-12 15:44:06 -04:00
return unless showFrequency = @ levelLoader . level . get ( ' showsGuide ' )
2014-03-07 18:18:56 -05:00
session = @ levelLoader . session
diff = new Date ( ) . getTime ( ) - new Date ( session . get ( ' created ' ) ) . getTime ( )
return if showFrequency is ' first-time ' and diff > ( 5 * 60 * 1000 )
articles = @ levelLoader . supermodel . getModels Article
for article in articles
return unless article . loaded
@ showGuide ( )
2014-05-02 15:32:41 -04:00
onWorldInitialized: ->
@worldInitialized = true
team = @ getQueryVariable ( " team " ) ? @ world . teamForPlayer ( 0 )
@ loadOpponentTeam ( team )
2014-05-12 12:57:31 -04:00
@ god . setLevel @ level . serialize @ supermodel
2014-05-15 17:57:24 -04:00
@ god . setLevelSessionIDs if @ otherSession then [ @ session . id , @ otherSession . id ] else [ @ session . id ]
2014-05-09 15:56:58 -04:00
@ god . setWorldClassMap @ world . classMap
2014-05-02 15:32:41 -04:00
@ setTeam team
@ initGoalManager ( )
@ insertSubviews ladderGame: ( @ level . get ( ' type ' ) is " ladder " )
@ initVolume ( )
@ listenTo ( @ session , ' change:multiplayer ' , @ onMultiplayerChanged )
@originalSessionState = $ . extend ( true , { } , @ session . get ( ' state ' ) )
@ register ( )
@ controlBar . setBus ( @ bus )
2014-03-07 18:18:56 -05:00
showGuide: ->
@seenDocs = true
DocsModal = require ' ./level/modal/docs_modal '
options = { docs: @ levelLoader . level . get ( ' documentation ' ) , supermodel: @ supermodel }
@ openModalView ( new DocsModal ( options ) , true )
2014-04-29 18:25:59 -04:00
Backbone . Mediator . subscribeOnce ' modal-closed ' , @ onLevelLoaded , @
2014-03-07 18:18:56 -05:00
return true
2014-04-25 17:30:06 -04:00
onLoaded: ->
_ . defer => @ onLevelLoaded ( )
onLevelLoaded: ->
2014-03-07 18:18:56 -05:00
return unless @ levelLoader . progress ( ) is 1 # double check, since closing the guide may trigger this early
2014-03-17 08:52:19 -04:00
@ loadingView . showReady ( )
2014-02-27 19:44:11 -05:00
if window . currentModal and not window . currentModal . destroyed
2014-04-29 18:25:59 -04:00
return Backbone . Mediator . subscribeOnce ' modal-closed ' , @ onLevelLoaded , @
2014-03-13 12:02:19 -04:00
2014-03-15 10:45:44 -04:00
# Save latest level played in local storage
2014-03-21 19:49:30 -04:00
if not ( @ levelLoader . level . get ( ' type ' ) in [ ' ladder ' , ' ladder-tutorial ' ] )
me . set ( ' lastLevel ' , @ levelID )
me . save ( )
2014-05-02 15:32:41 -04:00
@ levelLoader . destroy ( )
@levelLoader = null
2014-01-03 13:32:13 -05:00
@ initSurface ( )
@ initScriptManager ( )
2014-03-13 12:02:19 -04:00
2014-02-27 19:44:11 -05:00
grabLevelLoaderData: ->
@session = @ levelLoader . session
@world = @ levelLoader . world
@level = @ levelLoader . level
@otherSession = @ levelLoader . opponentSession
2014-03-13 12:02:19 -04:00
2014-02-27 19:44:11 -05:00
loadOpponentTeam: (myTeam) ->
opponentSpells = [ ]
for spellTeam , spells of @ session . get ( ' teamSpells ' ) ? @ otherSession ? . get ( ' teamSpells ' ) ? { }
continue if spellTeam is myTeam or not myTeam
opponentSpells = opponentSpells . concat spells
2014-05-16 12:47:15 -04:00
if ( not @ session . get ( ' teamSpells ' ) ) and @ otherSession ? . get ( ' teamSpells ' )
@ session . set ( ' teamSpells ' , @ otherSession . get ( ' teamSpells ' ) )
2014-05-15 18:18:15 -04:00
opponentCode = @ otherSession ? . get ( ' transpiledCode ' ) or { }
2014-02-27 19:44:11 -05:00
myCode = @ session . get ( ' code ' ) or { }
for spell in opponentSpells
[ thang , spell ] = spell . split ' / '
c = opponentCode [ thang ] ? [ spell ]
myCode [ thang ] ? = { }
if c then myCode [ thang ] [ spell ] = c else delete myCode [ thang ] [ spell ]
@ session . set ( ' code ' , myCode )
if @ session . get ( ' multiplayer ' ) and @ otherSession ?
# For now, ladderGame will disallow multiplayer, because session code combining doesn't play nice yet.
@ session . set ' multiplayer ' , false
2014-01-03 13:32:13 -05:00
2014-03-14 20:06:08 -04:00
onLevelStarted: (e) ->
2014-05-03 12:13:26 -04:00
@ surface . showLevel ( )
if @ otherSession
# TODO: colorize name and cloud by team, colorize wizard by user's color config
@ surface . createOpponentWizard id: @ otherSession . get ( ' creator ' ) , name: @ otherSession . get ( ' creatorName ' ) , team: @ otherSession . get ( ' team ' )
2014-03-14 20:06:08 -04:00
@ loadingView ? . unveil ( )
onLoadingViewUnveiled: (e) ->
2014-04-28 17:01:33 -04:00
@ loadingView . $el . remove ( )
2014-03-14 20:06:08 -04:00
@ removeSubView @ loadingView
@loadingView = null
2014-04-13 23:31:23 -04:00
unless @ isEditorPreview
@loadEndTime = new Date ( )
loadDuration = @ loadEndTime - @ loadStartTime
application . tracker ? . trackEvent ' Finished Level Load ' , level: @ levelID , label: @ levelID , loadDuration: loadDuration
application . tracker ? . trackTiming loadDuration , ' Level Load Time ' , @ levelID , @ levelID
2014-03-13 12:02:19 -04:00
2014-01-03 13:32:13 -05:00
onSupermodelLoadedOne: =>
@ modelsLoaded ? = 0
@ modelsLoaded += 1
@ updateInitString ( )
updateInitString: ->
return if @ surface
@ modelsLoaded ? = 0
canvas = @ $el . find ( ' # surface ' ) [ 0 ]
ctx = canvas . getContext ( ' 2d ' )
ctx . font = " 20px Georgia "
ctx . clearRect ( 0 , 0 , canvas . width , canvas . height )
ctx . fillText ( " Loaded #{ @ modelsLoaded } thingies " , 50 , 50 )
2014-05-05 18:33:08 -04:00
insertSubviews: ->
@ insertSubView @tome = new TomeView levelID: @ levelID , session: @ session , thangs: @ world . thangs , supermodel: @ supermodel
2014-05-15 00:54:36 -04:00
@ insertSubView new PlaybackView session: @ session
2014-01-03 13:32:13 -05:00
@ insertSubView new GoalsView { }
2014-02-11 15:02:27 -05:00
@ insertSubView new GoldView { }
2014-01-03 13:32:13 -05:00
@ insertSubView new HUDView { }
@ insertSubView new ChatView levelID: @ levelID , sessionID: @ session . id , session: @ session
2014-03-13 12:02:19 -04:00
worldName = utils . i18n @ level . attributes , ' name '
2014-05-05 18:33:08 -04:00
@controlBar = @ insertSubView new ControlBarView { worldName: worldName , session: @ session , level: @ level , supermodel: @ supermodel , playableTeams: @ world . playableTeams }
2014-01-03 13:32:13 -05:00
#Backbone.Mediator.publish('level-set-debug', debug: true) if me.displayName() is 'Nick!'
afterInsert: ->
super ( )
2014-02-24 15:52:35 -05:00
@ showWizardSettingsModal ( ) if not me . get ( ' name ' )
2014-01-03 13:32:13 -05:00
# callbacks
2014-02-20 18:11:20 -05:00
onCtrlS: (e) ->
e . preventDefault ( )
2014-01-03 13:32:13 -05:00
onLevelReloadFromData: (e) ->
isReload = Boolean @ world
@ setLevel e . level , e . supermodel
if isReload
@ scriptManager . setScripts ( e . level . get ( ' scripts ' ) )
Backbone . Mediator . publish ' tome:cast-spell ' # a bit hacky
onWindowResize: (s...) ->
$ ( ' # pointer ' ) . css ( ' opacity ' , 0.0 )
2014-02-12 15:41:41 -05:00
onDisableControls: (e) ->
2014-01-03 13:32:13 -05:00
return if e . controls and not ( ' level ' in e . controls )
@shortcutsEnabled = false
@wasFocusedOn = document . activeElement
$ ( ' body ' ) . focus ( )
2014-02-12 15:41:41 -05:00
onEnableControls: (e) ->
2014-01-03 13:32:13 -05:00
return if e . controls ? and not ( ' level ' in e . controls )
@shortcutsEnabled = true
$ ( @ wasFocusedOn ) . focus ( ) if @ wasFocusedOn
@wasFocusedOn = null
2014-02-12 15:41:41 -05:00
onDonePressed: -> @ showVictory ( )
2014-01-03 13:32:13 -05:00
2014-02-12 15:41:41 -05:00
onShowVictory: (e) ->
2014-01-03 13:32:13 -05:00
$ ( ' # level-done-button ' ) . show ( )
@ showVictory ( ) if e . showModal
setTimeout ( @ preloadNextLevel , 3000 )
2014-04-13 23:31:23 -04:00
return if @ victorySeen
@victorySeen = true
victoryTime = ( new Date ( ) ) - @ loadEndTime
if victoryTime > 10 * 1000 # Don't track it if we're reloading an already-beaten level
application . tracker ? . trackEvent ' Saw Victory ' , level: @ world . name , label: @ world . name
application . tracker ? . trackTiming victoryTime , ' Level Victory Time ' , @ levelID , @ levelID , 100
2014-01-03 13:32:13 -05:00
showVictory: ->
2014-03-31 16:56:13 -04:00
options = { level: @ level , supermodel: @ supermodel , session: @ session }
2014-01-03 13:32:13 -05:00
docs = new VictoryModal ( options )
@ openModalView ( docs )
2014-03-31 16:56:13 -04:00
if me . get ( ' anonymous ' )
2014-04-29 18:25:59 -04:00
window . nextLevelURL = @ getNextLevelURL ( ) # Signup will go here on completion instead of reloading.
2014-01-03 13:32:13 -05:00
onRestartLevel: ->
@ tome . reloadAllCode ( )
Backbone . Mediator . publish ' level:restarted '
$ ( ' # level-done-button ' , @ $el ) . hide ( )
2014-04-13 23:31:23 -04:00
application . tracker ? . trackEvent ' Confirmed Restart ' , level: @ world . name , label: @ world . name
2014-01-03 13:32:13 -05:00
onInfiniteLoop: (e) ->
return unless e . firstWorld
@ openModalView new InfiniteLoopModal ( )
2014-04-13 23:31:23 -04:00
application . tracker ? . trackEvent ' Saw Initial Infinite Loop ' , level: @ world . name , label: @ world . name
2014-01-03 13:32:13 -05:00
2014-02-12 15:41:41 -05:00
onPlayNextLevel: ->
2014-03-31 16:56:13 -04:00
nextLevelID = @ getNextLevelID ( )
nextLevelURL = @ getNextLevelURL ( )
2014-01-03 13:32:13 -05:00
Backbone . Mediator . publish ' router:navigate ' , {
2014-03-31 16:56:13 -04:00
route: nextLevelURL ,
2014-01-03 13:32:13 -05:00
viewClass: PlayLevelView ,
viewArgs: [ { supermodel : @ supermodel } , nextLevelID ] }
getNextLevel: ->
2014-04-29 18:25:59 -04:00
return null unless nextLevelOriginal = @ level . get ( ' nextLevel ' ) ? . original
2014-01-03 13:32:13 -05:00
levels = @ supermodel . getModels ( Level )
return l for l in levels when l . get ( ' original ' ) is nextLevelOriginal
2014-03-31 16:56:13 -04:00
getNextLevelID: ->
2014-04-29 18:25:59 -04:00
return null unless nextLevel = @ getNextLevel ( )
2014-03-31 16:56:13 -04:00
nextLevelID = nextLevel . get ( ' slug ' ) or nextLevel . id
2014-04-29 18:25:59 -04:00
getNextLevelURL: ->
return null unless @ getNextLevelID ( )
" /play/level/ #{ @ getNextLevelID ( ) } "
2014-03-31 16:56:13 -04:00
2014-02-12 15:41:41 -05:00
onHighlightDom: (e) ->
2014-01-03 13:32:13 -05:00
if e . delay
delay = e . delay
delete e . delay
@pointerInterval = _ . delay ( ( => @ onHighlightDom e ) , delay )
return
@ addPointer ( )
selector = e . selector + ' :visible '
dom = $ ( selector )
return if parseFloat ( dom . css ( ' opacity ' ) ) is 0.0
offset = dom . offset ( )
return if not offset
target_left = offset . left + dom . outerWidth ( ) * 0.5
target_top = offset . top + dom . outerHeight ( ) * 0.5
body = $ ( ' # level-view ' )
if e . sides
if ' left ' in e . sides then target_left = offset . left
if ' right ' in e . sides then target_left = offset . left + dom . outerWidth ( )
if ' top ' in e . sides then target_top = offset . top
if ' bottom ' in e . sides then target_top = offset . top + dom . outerHeight ( )
else
# aim to hit the side if the target is entirely on one side of the screen
if offset . left > body . outerWidth ( ) * 0.5
target_left = offset . left
else if offset . left + dom . outerWidth ( ) < body . outerWidth ( ) * 0.5
target_left = offset . left + dom . outerWidth ( )
# aim to hit the bottom or top if the target is entirely on the top or bottom of the screen
if offset . top > body . outerWidth ( ) * 0.5
target_top = offset . top
else if offset . top + dom . outerHeight ( ) < body . outerHeight ( ) * 0.5
target_top = offset . top + dom . outerHeight ( )
if e . offset
target_left += e . offset . x
target_top += e . offset . y
@pointerRadialDistance = - 47 # - Math.sqrt(Math.pow(dom.outerHeight()*0.5, 2), Math.pow(dom.outerWidth()*0.5))
@pointerRotation = e . rotation ? Math . atan2 ( body . outerWidth ( ) * 0.5 - target_left , target_top - body . outerHeight ( ) * 0.5 )
pointer = $ ( ' # pointer ' )
pointer
. css ( ' opacity ' , 1.0 )
. css ( ' transition ' , ' none ' )
. css ( ' transform ' , " rotate( #{ @ pointerRotation } rad) translate(-3px, #{ @ pointerRadialDistance } px) " )
. css ( ' top ' , target_top - 50 )
. css ( ' left ' , target_left - 50 )
2014-04-10 16:59:08 -04:00
setTimeout ( ()=>
2014-04-25 17:30:06 -04:00
return if @ destroyed
2014-01-03 13:32:13 -05:00
@ animatePointer ( )
clearInterval ( @ pointerInterval )
@pointerInterval = setInterval ( @ animatePointer , 1200 )
2014-04-10 16:59:08 -04:00
, 1 )
2014-01-03 13:32:13 -05:00
2014-04-28 17:01:33 -04:00
animatePointer: =>
2014-01-03 13:32:13 -05:00
pointer = $ ( ' # pointer ' )
pointer . css ( ' transition ' , ' all 0.6s ease-out ' )
pointer . css ( ' transform ' , " rotate( #{ @ pointerRotation } rad) translate(-3px, #{ @ pointerRadialDistance - 50 } px) " )
setTimeout ( ( =>
pointer . css ( ' transform ' , " rotate( #{ @ pointerRotation } rad) translate(-3px, #{ @ pointerRadialDistance } px) " ) . css ( ' transition ' , ' all 0.4s ease-in ' ) ) , 800 )
2014-02-12 15:41:41 -05:00
onFocusDom: (e) -> $ ( e . selector ) . focus ( )
2014-01-03 13:32:13 -05:00
2014-02-12 15:41:41 -05:00
onEndHighlight: ->
2014-01-03 13:32:13 -05:00
$ ( ' # pointer ' ) . css ( ' opacity ' , 0.0 )
clearInterval ( @ pointerInterval )
2014-02-11 18:38:36 -05:00
onMultiplayerChanged: (e) ->
2014-01-03 13:32:13 -05:00
if @ session . get ( ' multiplayer ' )
@ bus . connect ( )
else
@ bus . removeFirebaseData =>
@ bus . disconnect ( )
# initialization
addPointer: ->
p = $ ( ' # pointer ' )
return if p . length
@ $el . append ( $ ( ' <img src= " /images/level/pointer.png " id= " pointer " > ' ) )
initSurface: ->
surfaceCanvas = $ ( ' canvas # surface ' , @ $el )
@surface = new Surface ( @ world , surfaceCanvas , thangTypes: @ supermodel . getModels ( ThangType ) , playJingle: not @ isEditorPreview )
worldBounds = @ world . getBounds ( )
bounds = [ { x : worldBounds . left , y : worldBounds . top } , { x : worldBounds . right , y : worldBounds . bottom } ]
@ surface . camera . setBounds ( bounds )
@ surface . camera . zoomTo ( { x : 0 , y : 0 } , 0.1 , 0 )
initGoalManager: ->
2014-02-12 19:20:25 -05:00
@goalManager = new GoalManager ( @ world , @ level . get ( ' goals ' ) )
2014-05-05 23:07:34 -04:00
@ god . setGoalManager @ goalManager
2014-01-03 13:32:13 -05:00
initScriptManager: ->
@scriptManager = new ScriptManager ( { scripts: @ world . scripts or [ ] , view : @ , session: @ session } )
@ scriptManager . loadFromSession ( )
initVolume: ->
volume = me . get ( ' volume ' )
volume = 1.0 unless volume ?
Backbone . Mediator . publish ' level-set-volume ' , volume: volume
onSurfaceSetUpNewWorld: ->
return if @ alreadyLoadedState
@alreadyLoadedState = true
state = @ originalSessionState
2014-04-11 20:55:47 -04:00
if state . frame and @ level . get ( ' type ' ) isnt ' ladder ' # https://github.com/codecombat/codecombat/issues/714
2014-01-03 13:32:13 -05:00
Backbone . Mediator . publish ' level-set-time ' , { time: 0 , frameOffset: state . frame }
if state . selected
# TODO: Should also restore selected spell here by saving spellName
Backbone . Mediator . publish ' level-select-sprite ' , { thangID: state . selected , spellName: null }
if state . playing ?
Backbone . Mediator . publish ' level-set-playing ' , { playing: state . playing }
preloadNextLevel: =>
# TODO: Loading models in the middle of gameplay causes stuttering. Most of the improvement in loading time is simply from passing the supermodel from this level to the next, but if we can find a way to populate the level early without it being noticeable, that would be even better.
# return if @destroyed
# return if @preloaded
# nextLevel = @getNextLevel()
# @supermodel.populateModel nextLevel
# @preloaded = true
register: ->
@bus = LevelBus . get ( @ levelID , @ session . id )
@ bus . setSession ( @ session )
2014-02-25 13:48:23 -05:00
@ bus . setSpells @ tome . spells
2014-01-03 13:32:13 -05:00
@ bus . connect ( ) if @ session . get ( ' multiplayer ' )
onSessionWillSave: (e) ->
# Something interesting has happened, so (at a lower frequency), we'll save a screenshot.
2014-05-12 16:28:46 -04:00
#@saveScreenshot e.session
2014-01-03 13:32:13 -05:00
# Throttled
saveScreenshot: (session) =>
return unless screenshot = @ surface ? . screenshot ( )
session . save { screenshot: screenshot } , { patch: true }
setTeam: (team) ->
2014-02-06 20:31:08 -05:00
team = team ? . team unless _ . isString team
team ? = ' humans '
2014-01-03 13:32:13 -05:00
me.team = team
Backbone . Mediator . publish ' level:team-set ' , team: team
2014-02-19 14:42:33 -05:00
# Dynamic sound loading
2014-05-14 13:35:16 -04:00
onNewWorld: (e) ->
2014-02-19 14:42:33 -05:00
return if @ headless
2014-05-14 13:35:16 -04:00
@world = e . world
2014-02-19 14:42:33 -05:00
thangTypes = @ supermodel . getModels ( ThangType )
2014-05-14 13:35:16 -04:00
for [ spriteName , message ] in @ world . thangDialogueSounds ( )
2014-02-19 14:42:33 -05:00
continue unless thangType = _ . find thangTypes , (m) -> m . get ( ' name ' ) is spriteName
continue unless sound = AudioPlayer . soundForDialogue message , thangType . get ( ' soundTriggers ' )
AudioPlayer . preloadSoundReference sound
2014-01-03 13:32:13 -05:00
destroy: ->
2014-02-06 17:00:27 -05:00
@ levelLoader ? . destroy ( )
2014-01-03 13:32:13 -05:00
@ surface ? . destroy ( )
@ god ? . destroy ( )
@ goalManager ? . destroy ( )
@ scriptManager ? . destroy ( )
2014-02-11 17:24:06 -05:00
delete window . world # not sure where this is set, but this is one way to clean it up
2014-01-03 13:32:13 -05:00
clearInterval ( @ pointerInterval )
@ bus ? . destroy ( )
#@instance.save() unless @instance.loading
2014-03-31 16:56:13 -04:00
delete window . nextLevelURL
2014-01-03 13:32:13 -05:00
console . profileEnd ? ( ) if PROFILE_ME
2014-02-14 13:57:47 -05:00
super ( )