mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-01 11:27:14 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
f396114a47
19 changed files with 356 additions and 88 deletions
|
@ -119,7 +119,7 @@ module.exports = class Angel extends CocoClass
|
||||||
return if @aborting
|
return if @aborting
|
||||||
# Toggle BOX2D_ENABLED during deserialization so that if we have box2d in the namespace, the Collides Components still don't try to create bodies for deserialized Thangs upon attachment.
|
# Toggle BOX2D_ENABLED during deserialization so that if we have box2d in the namespace, the Collides Components still don't try to create bodies for deserialized Thangs upon attachment.
|
||||||
window.BOX2D_ENABLED = false
|
window.BOX2D_ENABLED = false
|
||||||
@streamingWorld = World.deserialize serialized, @shared.worldClassMap, @shared.lastSerializedWorldFrames, @finishBeholdingWorld(goalStates), startFrame, endFrame, streamingWorld
|
@streamingWorld = World.deserialize serialized, @shared.worldClassMap, @shared.lastSerializedWorldFrames, @finishBeholdingWorld(goalStates), startFrame, endFrame, @work.level, streamingWorld
|
||||||
window.BOX2D_ENABLED = true
|
window.BOX2D_ENABLED = true
|
||||||
@shared.lastSerializedWorldFrames = serialized.frames
|
@shared.lastSerializedWorldFrames = serialized.frames
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ module.exports = class Angel extends CocoClass
|
||||||
work.testWorld.goalManager.worldGenerationEnded() if work.testWorld.ended
|
work.testWorld.goalManager.worldGenerationEnded() if work.testWorld.ended
|
||||||
serialized = testWorld.serialize()
|
serialized = testWorld.serialize()
|
||||||
window.BOX2D_ENABLED = false
|
window.BOX2D_ENABLED = false
|
||||||
World.deserialize serialized.serializedWorld, @shared.worldClassMap, @shared.lastSerializedWorldFrames, @finishBeholdingWorld(goalStates), serialized.startFrame, serialized.endFrame
|
World.deserialize serialized.serializedWorld, @shared.worldClassMap, @shared.lastSerializedWorldFrames, @finishBeholdingWorld(goalStates), serialized.startFrame, work.level, serialized.endFrame
|
||||||
window.BOX2D_ENABLED = true
|
window.BOX2D_ENABLED = true
|
||||||
@shared.lastSerializedWorldFrames = serialized.serializedWorld.frames
|
@shared.lastSerializedWorldFrames = serialized.serializedWorld.frames
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ module.exports = class MusicPlayer extends CocoClass
|
||||||
'audio-player:loaded': 'onAudioLoaded'
|
'audio-player:loaded': 'onAudioLoaded'
|
||||||
'playback:real-time-playback-started': 'onRealTimePlaybackStarted'
|
'playback:real-time-playback-started': 'onRealTimePlaybackStarted'
|
||||||
'playback:real-time-playback-ended': 'onRealTimePlaybackEnded'
|
'playback:real-time-playback-ended': 'onRealTimePlaybackEnded'
|
||||||
|
'music-player:enter-menu': 'onEnterMenu'
|
||||||
|
'music-player:exit-menu': 'onExitMenu'
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super arguments...
|
super arguments...
|
||||||
|
@ -35,9 +37,10 @@ module.exports = class MusicPlayer extends CocoClass
|
||||||
@standingBy = e
|
@standingBy = e
|
||||||
return
|
return
|
||||||
|
|
||||||
|
delay = e.delay ? 0
|
||||||
@standingBy = null
|
@standingBy = null
|
||||||
@fadeOutCurrentMusic()
|
@fadeOutCurrentMusic()
|
||||||
@startNewMusic(src) if e.play
|
@startNewMusic(src, delay) if e.play
|
||||||
|
|
||||||
restartCurrentMusic: ->
|
restartCurrentMusic: ->
|
||||||
return unless @currentMusic
|
return unless @currentMusic
|
||||||
|
@ -46,15 +49,16 @@ module.exports = class MusicPlayer extends CocoClass
|
||||||
|
|
||||||
fadeOutCurrentMusic: ->
|
fadeOutCurrentMusic: ->
|
||||||
return unless @currentMusic
|
return unless @currentMusic
|
||||||
|
createjs.Tween.removeTweens(@currentMusic)
|
||||||
f = -> @stop()
|
f = -> @stop()
|
||||||
createjs.Tween.get(@currentMusic).to({volume: 0.0}, CROSSFADE_LENGTH).call(f)
|
createjs.Tween.get(@currentMusic).to({volume: 0.0}, CROSSFADE_LENGTH).call(f)
|
||||||
|
|
||||||
startNewMusic: (src) ->
|
startNewMusic: (src, delay) ->
|
||||||
@currentMusic = createjs.Sound.play(src, 'none', 0, 0, -1, 0.3) if src
|
@currentMusic = createjs.Sound.play(src, 'none', 0, 0, -1, 0.3) if src
|
||||||
return unless @currentMusic
|
return unless @currentMusic
|
||||||
@currentMusic.volume = 0.0
|
@currentMusic.volume = 0.0
|
||||||
if me.get('music', true)
|
if me.get('music', true)
|
||||||
createjs.Tween.get(@currentMusic).to({volume: MUSIC_VOLUME}, CROSSFADE_LENGTH)
|
createjs.Tween.get(@currentMusic).wait(delay).to({volume: MUSIC_VOLUME}, CROSSFADE_LENGTH)
|
||||||
|
|
||||||
onMusicSettingChanged: ->
|
onMusicSettingChanged: ->
|
||||||
@updateMusicVolume()
|
@updateMusicVolume()
|
||||||
|
@ -74,6 +78,24 @@ module.exports = class MusicPlayer extends CocoClass
|
||||||
if @previousMusic
|
if @previousMusic
|
||||||
@currentMusic = @previousMusic
|
@currentMusic = @previousMusic
|
||||||
@restartCurrentMusic()
|
@restartCurrentMusic()
|
||||||
|
if @currentMusic.volume
|
||||||
|
createjs.Tween.get(@currentMusic).wait(5000).to({volume: MUSIC_VOLUME}, CROSSFADE_LENGTH)
|
||||||
|
|
||||||
|
onEnterMenu: (e) ->
|
||||||
|
return if @inMenu
|
||||||
|
@inMenu = true
|
||||||
|
@previousMusic = @currentMusic
|
||||||
|
terrain = (e.terrain ? 'Dungeon').toLowerCase()
|
||||||
|
file = "/music/music-menu-#{terrain}"
|
||||||
|
Backbone.Mediator.publish 'music-player:play-music', file: file, play: true, delay: 1000
|
||||||
|
|
||||||
|
onExitMenu: (e) ->
|
||||||
|
return unless @inMenu
|
||||||
|
@inMenu = false
|
||||||
|
@fadeOutCurrentMusic()
|
||||||
|
if @previousMusic
|
||||||
|
@currentMusic = @previousMusic
|
||||||
|
@restartCurrentMusic()
|
||||||
|
|
||||||
destroy: ->
|
destroy: ->
|
||||||
me.off 'change:music', @onMusicSettingChanged, @
|
me.off 'change:music', @onMusicSettingChanged, @
|
||||||
|
|
|
@ -151,10 +151,14 @@ module.exports = class Thang
|
||||||
o.unusedTrackedPropertyKeys = (@trackedPropertiesKeys[propIndex] for used, propIndex in @trackedPropertiesUsed when not used)
|
o.unusedTrackedPropertyKeys = (@trackedPropertiesKeys[propIndex] for used, propIndex in @trackedPropertiesUsed when not used)
|
||||||
o
|
o
|
||||||
|
|
||||||
@deserialize: (o, world, classMap) ->
|
@deserialize: (o, world, classMap, levelComponents) ->
|
||||||
t = new Thang world, o.spriteName, o.id
|
t = new Thang world, o.spriteName, o.id
|
||||||
for [componentClassName, componentConfig] in o.components
|
for [componentClassName, componentConfig] in o.components
|
||||||
componentClass = classMap[componentClassName]
|
unless componentClass = classMap[componentClassName]
|
||||||
|
console.debug 'Compiling new Component while deserializing:', componentClassName
|
||||||
|
componentModel = _.find levelComponents, name: componentClassName
|
||||||
|
componentClass = world.loadClassFromCode componentModel.js, componentClassName, 'component'
|
||||||
|
world.classMap[componentClassName] = componentClass
|
||||||
t.addComponents [componentClass, componentConfig]
|
t.addComponents [componentClass, componentConfig]
|
||||||
t.unusedTrackedPropertyKeys = o.unusedTrackedPropertyKeys
|
t.unusedTrackedPropertyKeys = o.unusedTrackedPropertyKeys
|
||||||
t.unusedTrackedPropertyValues = (t[prop] for prop in o.unusedTrackedPropertyKeys)
|
t.unusedTrackedPropertyValues = (t[prop] for prop in o.unusedTrackedPropertyKeys)
|
||||||
|
|
|
@ -436,7 +436,7 @@ module.exports = class World
|
||||||
console.log 'Whoa, serializing a lot of WorldScriptNotes here:', o.scriptNotes.length
|
console.log 'Whoa, serializing a lot of WorldScriptNotes here:', o.scriptNotes.length
|
||||||
{serializedWorld: o, transferableObjects: [o.storageBuffer], startFrame: startFrame, endFrame: endFrame}
|
{serializedWorld: o, transferableObjects: [o.storageBuffer], startFrame: startFrame, endFrame: endFrame}
|
||||||
|
|
||||||
@deserialize: (o, classMap, oldSerializedWorldFrames, finishedWorldCallback, startFrame, endFrame, streamingWorld) ->
|
@deserialize: (o, classMap, oldSerializedWorldFrames, finishedWorldCallback, startFrame, endFrame, level, streamingWorld) ->
|
||||||
# Code hotspot; optimize it
|
# Code hotspot; optimize it
|
||||||
#console.log 'Deserializing', o, 'length', JSON.stringify(o).length
|
#console.log 'Deserializing', o, 'length', JSON.stringify(o).length
|
||||||
#console.log JSON.stringify(o)
|
#console.log JSON.stringify(o)
|
||||||
|
@ -461,10 +461,10 @@ module.exports = class World
|
||||||
perf.t1 = now()
|
perf.t1 = now()
|
||||||
if w.thangs.length
|
if w.thangs.length
|
||||||
for thangConfig in o.thangs when not w.thangMap[thangConfig.id]
|
for thangConfig in o.thangs when not w.thangMap[thangConfig.id]
|
||||||
w.thangs.push thang = Thang.deserialize(thangConfig, w, classMap)
|
w.thangs.push thang = Thang.deserialize(thangConfig, w, classMap, level.levelComponents)
|
||||||
w.setThang thang
|
w.setThang thang
|
||||||
else
|
else
|
||||||
w.thangs = (Thang.deserialize(thang, w, classMap) for thang in o.thangs)
|
w.thangs = (Thang.deserialize(thang, w, classMap, level.levelComponents) for thang in o.thangs)
|
||||||
w.setThang thang for thang in w.thangs
|
w.setThang thang for thang in w.thangs
|
||||||
w.scriptNotes = (WorldScriptNote.deserialize(sn, w, classMap) for sn in o.scriptNotes)
|
w.scriptNotes = (WorldScriptNote.deserialize(sn, w, classMap) for sn in o.scriptNotes)
|
||||||
perf.t2 = now()
|
perf.t2 = now()
|
||||||
|
|
|
@ -202,8 +202,13 @@
|
||||||
victory_sign_up_poke: "Want to save your code? Create a free account!"
|
victory_sign_up_poke: "Want to save your code? Create a free account!"
|
||||||
victory_rate_the_level: "Rate the level: " # Only in old-style levels.
|
victory_rate_the_level: "Rate the level: " # Only in old-style levels.
|
||||||
victory_return_to_ladder: "Return to Ladder"
|
victory_return_to_ladder: "Return to Ladder"
|
||||||
victory_play_next_level: "Play Next Level" # Only in old-style levels.
|
|
||||||
victory_play_continue: "Continue"
|
victory_play_continue: "Continue"
|
||||||
|
victory_play_skip: "Skip Ahead"
|
||||||
|
victory_play_next_level: "Play Next Level"
|
||||||
|
victory_play_more_practice: "More Practice"
|
||||||
|
victory_play_too_easy: "Too Easy"
|
||||||
|
victory_play_just_right: "Just Right"
|
||||||
|
victory_play_too_hard: "Too Hard"
|
||||||
victory_saving_progress: "Saving Progress"
|
victory_saving_progress: "Saving Progress"
|
||||||
victory_go_home: "Go Home" # Only in old-style levels.
|
victory_go_home: "Go Home" # Only in old-style levels.
|
||||||
victory_review: "Tell us more!" # Only in old-style levels.
|
victory_review: "Tell us more!" # Only in old-style levels.
|
||||||
|
|
|
@ -61,10 +61,10 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
achievements: "Достижения" # Tooltip on achievement list button from /play
|
achievements: "Достижения" # Tooltip on achievement list button from /play
|
||||||
account: "Аккаунт" # Tooltip on account button from /play
|
account: "Аккаунт" # Tooltip on account button from /play
|
||||||
settings: "Настройки" # Tooltip on settings button from /play
|
settings: "Настройки" # Tooltip on settings button from /play
|
||||||
next: "Следующий" # Go from choose hero to choose inventory before playing a level
|
next: "Выбрать" # Go from choose hero to choose inventory before playing a level
|
||||||
change_hero: "Выбрать героя" # Go back from choose inventory to choose hero
|
change_hero: "Выбрать героя" # Go back from choose inventory to choose hero
|
||||||
choose_inventory: "Выбрать предметы"
|
choose_inventory: "Выбрать предметы"
|
||||||
older_campaigns: "Старые компании"
|
older_campaigns: "Старые кампании"
|
||||||
anonymous: "Неизвестный игрок"
|
anonymous: "Неизвестный игрок"
|
||||||
level_difficulty: "Сложность: "
|
level_difficulty: "Сложность: "
|
||||||
campaign_beginner: "Кампания для новичков"
|
campaign_beginner: "Кампания для новичков"
|
||||||
|
@ -72,7 +72,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
adventurer_prefix: "Вы можете зайти на любой из этих уровней, а также обсудить уровни на "
|
adventurer_prefix: "Вы можете зайти на любой из этих уровней, а также обсудить уровни на "
|
||||||
adventurer_forum: "форуме Искателей приключений"
|
adventurer_forum: "форуме Искателей приключений"
|
||||||
adventurer_suffix: "."
|
adventurer_suffix: "."
|
||||||
campaign_old_beginner: "Старые компании для новичков"
|
campaign_old_beginner: "Старые кампании для новичков"
|
||||||
campaign_old_beginner_description: "... в которой вы познакомитесь с магией программирования."
|
campaign_old_beginner_description: "... в которой вы познакомитесь с магией программирования."
|
||||||
campaign_dev: "Случайные уровни потруднее"
|
campaign_dev: "Случайные уровни потруднее"
|
||||||
campaign_dev_description: "... в которых вы изучите интерфейс и научитесь делать кое-что посложнее."
|
campaign_dev_description: "... в которых вы изучите интерфейс и научитесь делать кое-что посложнее."
|
||||||
|
@ -227,7 +227,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
tome_available_spells: "Доступные заклинания"
|
tome_available_spells: "Доступные заклинания"
|
||||||
tome_your_skills: "Ваши навыки"
|
tome_your_skills: "Ваши навыки"
|
||||||
hud_continue: "Продолжить (Shift+Пробел)"
|
hud_continue: "Продолжить (Shift+Пробел)"
|
||||||
# code_saved: "Code Saved"
|
code_saved: "Код сохранен"
|
||||||
skip_tutorial: "Пропуск (Esc)"
|
skip_tutorial: "Пропуск (Esc)"
|
||||||
keyboard_shortcuts: "Горячие клавиши"
|
keyboard_shortcuts: "Горячие клавиши"
|
||||||
loading_ready: "Готово!"
|
loading_ready: "Готово!"
|
||||||
|
@ -279,12 +279,12 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
inventory_caption: "Оденьте своего героя"
|
inventory_caption: "Оденьте своего героя"
|
||||||
choose_hero_caption: "Выбор героя, языка"
|
choose_hero_caption: "Выбор героя, языка"
|
||||||
# save_load_caption: "... and view history"
|
# save_load_caption: "... and view history"
|
||||||
# options_caption: "Configure settings"
|
options_caption: "Выбор настроек"
|
||||||
# guide_caption: "Docs and tips"
|
# guide_caption: "Docs and tips"
|
||||||
multiplayer_caption: "Играй с друзьями!"
|
multiplayer_caption: "Играй с друзьями!"
|
||||||
|
|
||||||
# inventory:
|
inventory:
|
||||||
# choose_inventory: "Equip Items"
|
choose_inventory: "Выбрать предметы"
|
||||||
|
|
||||||
choose_hero:
|
choose_hero:
|
||||||
choose_hero: "Выберите героя"
|
choose_hero: "Выберите героя"
|
||||||
|
@ -333,10 +333,10 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
why_paragraph_2_italic_caps: "НЕТ, МАМ, Я ДОЛЖЕН ПРОЙТИ УРОВЕНЬ!"
|
why_paragraph_2_italic_caps: "НЕТ, МАМ, Я ДОЛЖЕН ПРОЙТИ УРОВЕНЬ!"
|
||||||
why_paragraph_2_suffix: "Вот, почему CodeCombat - мультиплеерная игра, а не курс уроков в игровой форме. Мы не остановимся, пока вы не потеряете голову - в данном случае, это хорошо."
|
why_paragraph_2_suffix: "Вот, почему CodeCombat - мультиплеерная игра, а не курс уроков в игровой форме. Мы не остановимся, пока вы не потеряете голову - в данном случае, это хорошо."
|
||||||
why_paragraph_3: "Если вы собираетесь увлечься какой-нибудь игрой, увлекитесь этой и станьте одним из волшебников века информационных технологий."
|
why_paragraph_3: "Если вы собираетесь увлечься какой-нибудь игрой, увлекитесь этой и станьте одним из волшебников века информационных технологий."
|
||||||
# press_title: "Bloggers/Press"
|
press_title: "Блогерам/Прессе"
|
||||||
# press_paragraph_1_prefix: "Want to write about us? Feel free to download and use all of the resources included in our"
|
press_paragraph_1_prefix: "Хотите написать о нас? Скачивайте и используйте все ресурсы, включенный в наш"
|
||||||
# press_paragraph_1_link: "press packet"
|
press_paragraph_1_link: "пресс-пакет"
|
||||||
# press_paragraph_1_suffix: ". All logos and images may be used without contacting us directly."
|
press_paragraph_1_suffix: ". Все изображения могут быть использованы без предварительного уведомления."
|
||||||
# team: "Team"
|
# team: "Team"
|
||||||
# george_title: "CEO"
|
# george_title: "CEO"
|
||||||
# george_blurb: "Businesser"
|
# george_blurb: "Businesser"
|
||||||
|
@ -494,7 +494,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
level_tab_thangs_add: "Добавить объект"
|
level_tab_thangs_add: "Добавить объект"
|
||||||
delete: "Удалить"
|
delete: "Удалить"
|
||||||
duplicate: "Дублировать"
|
duplicate: "Дублировать"
|
||||||
# rotate: "Rotate"
|
rotate: "Повернуть"
|
||||||
level_settings_title: "Настройки"
|
level_settings_title: "Настройки"
|
||||||
level_component_tab_title: "Текущие компоненты"
|
level_component_tab_title: "Текущие компоненты"
|
||||||
level_component_btn_new: "Создать новый компонент"
|
level_component_btn_new: "Создать новый компонент"
|
||||||
|
|
|
@ -76,3 +76,15 @@ module.exports = class User extends CocoModel
|
||||||
earnedHero: (heroOriginal) -> heroOriginal in (me.get('earned')?.heroes ? [])
|
earnedHero: (heroOriginal) -> heroOriginal in (me.get('earned')?.heroes ? [])
|
||||||
earnedItem: (itemOriginal) -> itemOriginal in (me.get('earned')?.items ? [])
|
earnedItem: (itemOriginal) -> itemOriginal in (me.get('earned')?.items ? [])
|
||||||
earnedLevel: (levelOriginal) -> levelOriginal in (me.get('earned')?.levels ? [])
|
earnedLevel: (levelOriginal) -> levelOriginal in (me.get('earned')?.levels ? [])
|
||||||
|
|
||||||
|
getBranchingGroup: ->
|
||||||
|
return @branchingGroup if @branchingGroup
|
||||||
|
group = me.get('testGroupNumber') % 4
|
||||||
|
@branchingGroup = switch group
|
||||||
|
when 0 then 'no-practice'
|
||||||
|
when 1 then 'all-practice'
|
||||||
|
when 2 then 'choice-explicit'
|
||||||
|
when 3 then 'choice-implicit'
|
||||||
|
@branchingGroup = 'choice-explicit' if me.isAdmin()
|
||||||
|
application.tracker.identify branchingGroup: @branchingGroup
|
||||||
|
@branchingGroup
|
||||||
|
|
|
@ -18,6 +18,12 @@ module.exports =
|
||||||
'music-player:play-music': c.object {required: ['play']},
|
'music-player:play-music': c.object {required: ['play']},
|
||||||
play: {type: 'boolean'}
|
play: {type: 'boolean'}
|
||||||
file: {type: 'string'}
|
file: {type: 'string'}
|
||||||
|
delay: {type: 'integer', minimum: 0, format: 'milliseconds'}
|
||||||
|
|
||||||
|
'music-player:enter-menu': c.object {required: []},
|
||||||
|
terrain: {type: 'string'}
|
||||||
|
|
||||||
|
'music-player:exit-menu': c.object {}
|
||||||
|
|
||||||
'modal:opened': c.object {}
|
'modal:opened': c.object {}
|
||||||
|
|
||||||
|
|
|
@ -168,43 +168,49 @@
|
||||||
|
|
||||||
//- Footer
|
//- Footer
|
||||||
|
|
||||||
.modal-content
|
|
||||||
padding-bottom: 50px // so the footer appears at the bottom
|
|
||||||
|
|
||||||
&.with-sign-up .modal-content
|
|
||||||
padding-bottom: 100px // need more space for signup poke
|
|
||||||
|
|
||||||
.modal-footer
|
.modal-footer
|
||||||
position: absolute
|
padding-bottom: 0
|
||||||
bottom: -20px
|
|
||||||
left: 20px
|
|
||||||
right: 20px
|
|
||||||
|
|
||||||
#totals
|
|
||||||
color: white
|
|
||||||
|
|
||||||
p.sign-up-poke
|
p.sign-up-poke
|
||||||
position: absolute
|
|
||||||
bottom: 60px
|
|
||||||
right: 20px
|
|
||||||
color: white
|
color: white
|
||||||
|
|
||||||
.sign-up-button
|
.sign-up-button
|
||||||
float: right
|
float: right
|
||||||
margin-left: 10px
|
margin: 2px 10px
|
||||||
|
|
||||||
.ladder-submission-view
|
#totals
|
||||||
display: inline-block
|
|
||||||
color: white
|
color: white
|
||||||
|
|
||||||
.rank-button.btn-block
|
.next-level-buttons
|
||||||
display: inline-block
|
float: right
|
||||||
width: initial
|
|
||||||
padding-left: 19px
|
|
||||||
padding-right: 19px
|
|
||||||
|
|
||||||
.last-submitted
|
.next-level-button
|
||||||
float: none
|
display: block
|
||||||
|
margin: 8px 10px
|
||||||
|
width: 150px
|
||||||
|
|
||||||
|
.ladder-submission-view
|
||||||
|
display: inline-block
|
||||||
|
color: white
|
||||||
|
|
||||||
|
.rank-button.btn-block
|
||||||
|
display: inline-block
|
||||||
|
width: initial
|
||||||
|
padding-left: 19px
|
||||||
|
padding-right: 19px
|
||||||
|
|
||||||
|
.last-submitted
|
||||||
|
float: none
|
||||||
|
|
||||||
|
.next-levels-prompt
|
||||||
|
display: none
|
||||||
|
margin: 30px -21px
|
||||||
|
|
||||||
|
.btn
|
||||||
|
width: 30%
|
||||||
|
width: -webkit-calc(33.333333% - 10px)
|
||||||
|
width: calc(33.333333% - 10px)
|
||||||
|
margin: 5px
|
||||||
|
|
||||||
|
|
||||||
html.no-borderimage
|
html.no-borderimage
|
||||||
|
|
|
@ -41,8 +41,17 @@ block modal-body-content
|
||||||
img(src=item.getPortraitURL())
|
img(src=item.getPortraitURL())
|
||||||
.reward-text= animate ? 'New Item' : item.get('name')
|
.reward-text= animate ? 'New Item' : item.get('name')
|
||||||
|
|
||||||
|
.next-levels-prompt
|
||||||
|
for button in continueButtons
|
||||||
|
- var enabled = Boolean(button.link != '/play' || me.getBranchingGroup() == 'choice-implicit' || button.key == 'continue');
|
||||||
|
a.btn.btn-success.btn-lg.world-map-button.next-level-branch-button(href=button.link, disabled=!enabled, data-dismiss="modal", data-i18n="play_level.victory_play_" + button[me.getBranchingGroup()], data-branch-key=button.key)
|
||||||
|
|
||||||
block modal-footer-content
|
block modal-footer-content
|
||||||
|
if me.get('anonymous')
|
||||||
|
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!
|
||||||
|
|
||||||
div#totals.pull-left
|
div#totals.pull-left
|
||||||
span.spr Experience Gained:
|
span.spr Experience Gained:
|
||||||
span#xp-total +0
|
span#xp-total +0
|
||||||
|
@ -52,15 +61,10 @@ block modal-footer-content
|
||||||
|
|
||||||
button.btn.btn-warning.hide#saving-progress-label(disabled, data-i18n="play_level.victory_saving_progress") Saving Progress
|
button.btn.btn-warning.hide#saving-progress-label(disabled, data-i18n="play_level.victory_saving_progress") Saving Progress
|
||||||
|
|
||||||
if readyToRank
|
.next-level-buttons
|
||||||
.ladder-submission-view
|
if readyToRank
|
||||||
else if level.get('type') === 'hero-ladder'
|
.ladder-submission-view
|
||||||
a.btn.btn-primary(href="/play/ladder/#{level.get('slug')}#my-matches", data-dismiss="modal", data-i18n="play_level.victory_return_to_ladder") Return to Ladder
|
else if level.get('type') === 'hero-ladder'
|
||||||
else
|
a.btn.btn-primary(href="/play/ladder/#{level.get('slug')}#my-matches", data-dismiss="modal", data-i18n="play_level.victory_return_to_ladder") Return to Ladder
|
||||||
a.btn.btn-success.world-map-button.hide#continue-button(href="/play-hero", data-dismiss="modal", data-i18n="play_level.victory_play_continue") Continue
|
else
|
||||||
|
button.btn.btn-success.world-map-button.next-level-button.hide#continue-button(data-i18n="play_level.victory_play_continue") Continue
|
||||||
if me.get('anonymous')
|
|
||||||
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!
|
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,14 @@
|
||||||
.gradient.vertical-gradient.left-gradient
|
.gradient.vertical-gradient.left-gradient
|
||||||
img.map-background(src="/images/pages/play/map_" + mapType + ".jpg", alt="")
|
img.map-background(src="/images/pages/play/map_" + mapType + ".jpg", alt="")
|
||||||
|
|
||||||
- var seenNext = false;
|
- var seenNext = nextLevel;
|
||||||
each campaign in campaigns
|
each campaign in campaigns
|
||||||
each level in campaign.levels
|
each level in campaign.levels
|
||||||
- var next = !seenNext && levelStatusMap[level.id] != "complete";
|
if level.hidden
|
||||||
|
continue;
|
||||||
|
- var next = level.id == nextLevel || (!seenNext && levelStatusMap[level.id] != "complete" && !level.locked && !level.disabled);
|
||||||
- seenNext = seenNext || next;
|
- seenNext = seenNext || next;
|
||||||
div(style="left: #{level.x}%; bottom: #{level.y}%; background-color: #{campaign.color}", class="level" + (next ? " next" : "") + (level.disabled ? " disabled" : "") + (level.locked ? " locked" : "") + " " + levelStatusMap[level.id] || "", data-level-id=level.id, title=level.name)
|
div(style="left: #{level.x}%; bottom: #{level.y}%; background-color: #{level.color}", class="level" + (next ? " next" : "") + (level.disabled ? " disabled" : "") + (level.locked ? " locked" : "") + " " + levelStatusMap[level.id] || "", data-level-id=level.id, title=level.name)
|
||||||
a(href=level.type == 'hero' ? '#' : level.disabled ? "/play" : "/play/#{level.levelPath || 'level'}/#{level.id}", disabled=level.disabled, data-level-id=level.id, data-level-path=level.levelPath || 'level', data-level-name=level.name)
|
a(href=level.type == 'hero' ? '#' : level.disabled ? "/play" : "/play/#{level.levelPath || 'level'}/#{level.id}", disabled=level.disabled, data-level-id=level.id, data-level-path=level.levelPath || 'level', data-level-name=level.name)
|
||||||
div(style="left: #{level.x}%; bottom: #{level.y}%", class="level-shadow" + (next ? " next" : "") + " " + levelStatusMap[level.id] || "")
|
div(style="left: #{level.x}%; bottom: #{level.y}%", class="level-shadow" + (next ? " next" : "") + " " + levelStatusMap[level.id] || "")
|
||||||
.level-info-container(data-level-id=level.id, data-level-path=level.levelPath || 'level', data-level-name=level.name)
|
.level-info-container(data-level-id=level.id, data-level-path=level.levelPath || 'level', data-level-name=level.name)
|
||||||
|
|
|
@ -501,7 +501,7 @@ module.exports = class ThangsTabView extends CocoView
|
||||||
# foldered thangs -> array of thangs
|
# foldered thangs -> array of thangs
|
||||||
flattened = []
|
flattened = []
|
||||||
for key, value of thangs
|
for key, value of thangs
|
||||||
if value.id and value.thangType
|
if value.id? and value.thangType
|
||||||
flattened.push value
|
flattened.push value
|
||||||
else
|
else
|
||||||
flattened = flattened.concat @flattenThangs(value)
|
flattened = flattened.concat @flattenThangs(value)
|
||||||
|
@ -675,10 +675,10 @@ class ThangsFolderNode extends TreemaNode.nodeMap.object
|
||||||
valEl.append(el)
|
valEl.append(el)
|
||||||
|
|
||||||
countThangs: (data) ->
|
countThangs: (data) ->
|
||||||
return 0 if data.thangType and data.id
|
return 0 if data.thangType and data.id?
|
||||||
num = 0
|
num = 0
|
||||||
for key, value of data
|
for key, value of data
|
||||||
if value.thangType and value.id
|
if value.thangType and value.id?
|
||||||
num += 1
|
num += 1
|
||||||
else
|
else
|
||||||
num += @countThangs(value)
|
num += @countThangs(value)
|
||||||
|
|
|
@ -24,6 +24,7 @@ module.exports = class GameMenuModal extends ModalView
|
||||||
@options.showInventory = @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop']
|
@options.showInventory = @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop']
|
||||||
@options.levelID = @options.level.get('slug')
|
@options.levelID = @options.level.get('slug')
|
||||||
@options.startingSessionHeroConfig = $.extend {}, true, (@options.session.get('heroConfig') ? {})
|
@options.startingSessionHeroConfig = $.extend {}, true, (@options.session.get('heroConfig') ? {})
|
||||||
|
Backbone.Mediator.publish 'music-player:enter-menu', terrain: @options.level.get('terrain', true)
|
||||||
|
|
||||||
getRenderData: (context={}) ->
|
getRenderData: (context={}) ->
|
||||||
context = super(context)
|
context = super(context)
|
||||||
|
@ -50,6 +51,7 @@ module.exports = class GameMenuModal extends ModalView
|
||||||
patchingMe = @updateConfig()
|
patchingMe = @updateConfig()
|
||||||
me.patch() unless patchingMe # Might need to patch for options menu, too
|
me.patch() unless patchingMe # Might need to patch for options menu, too
|
||||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
|
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
|
||||||
|
Backbone.Mediator.publish 'music-player:exit-menu', {}
|
||||||
|
|
||||||
updateConfig: ->
|
updateConfig: ->
|
||||||
sessionHeroConfig = @options.startingSessionHeroConfig
|
sessionHeroConfig = @options.startingSessionHeroConfig
|
||||||
|
|
|
@ -32,6 +32,7 @@ module.exports = class WorldMapView extends RootView
|
||||||
|
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
super options
|
super options
|
||||||
|
@nextLevel = @getQueryVariable 'next'
|
||||||
@levelStatusMap = {}
|
@levelStatusMap = {}
|
||||||
@levelPlayCountMap = {}
|
@levelPlayCountMap = {}
|
||||||
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', null, 0).model
|
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', null, 0).model
|
||||||
|
@ -83,11 +84,17 @@ module.exports = class WorldMapView extends RootView
|
||||||
level.x ?= 10 + 80 * Math.random()
|
level.x ?= 10 + 80 * Math.random()
|
||||||
level.y ?= 10 + 80 * Math.random()
|
level.y ?= 10 + 80 * Math.random()
|
||||||
level.locked = index > 0 and not me.earnedLevel level.original
|
level.locked = index > 0 and not me.earnedLevel level.original
|
||||||
level.locked = false if window.levelUnlocksNotWorking
|
window.levelUnlocksNotWorking = true if level.locked and level.id is @nextLevel # Temporary
|
||||||
|
level.locked = false if window.levelUnlocksNotWorking # Temporary; also possible in HeroVictoryModal
|
||||||
|
level.color = campaign.color
|
||||||
|
if level.practice
|
||||||
|
level.color = 'rgb(80, 130, 200)' unless me.getBranchingGroup() is 'all-practice'
|
||||||
|
level.hidden = true if me.getBranchingGroup() is 'no-practice'
|
||||||
context.levelStatusMap = @levelStatusMap
|
context.levelStatusMap = @levelStatusMap
|
||||||
context.levelPlayCountMap = @levelPlayCountMap
|
context.levelPlayCountMap = @levelPlayCountMap
|
||||||
context.isIPadApp = application.isIPadApp
|
context.isIPadApp = application.isIPadApp
|
||||||
context.mapType = _.string.slugify @terrain
|
context.mapType = _.string.slugify @terrain
|
||||||
|
context.nextLevel = @nextLevel
|
||||||
context
|
context
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
|
@ -599,6 +606,9 @@ hero = [
|
||||||
description: 'Grab the gem, but touch nothing else. Start here.'
|
description: 'Grab the gem, but touch nothing else. Start here.'
|
||||||
x: 14
|
x: 14
|
||||||
y: 15.5
|
y: 15.5
|
||||||
|
nextLevels:
|
||||||
|
continue: 'gems-in-the-deep'
|
||||||
|
skip_ahead: 'shadow-guard'
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name: 'Gems in the Deep'
|
name: 'Gems in the Deep'
|
||||||
|
@ -609,6 +619,24 @@ hero = [
|
||||||
description: 'Quickly collect the gems; you will need them.'
|
description: 'Quickly collect the gems; you will need them.'
|
||||||
x: 32
|
x: 32
|
||||||
y: 15.5
|
y: 15.5
|
||||||
|
nextLevels:
|
||||||
|
more_practice: 'gem-grabber'
|
||||||
|
continue: 'shadow-guard'
|
||||||
|
skip_ahead: 'true-names'
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name: 'Gem Grabber'
|
||||||
|
type: 'hero'
|
||||||
|
difficulty: 1
|
||||||
|
id: 'gem-grabber'
|
||||||
|
original: '54174347844506ae0195a0b8'
|
||||||
|
description: 'Grab even more gems as you practice moving.'
|
||||||
|
x: 35.49
|
||||||
|
y: 24.61
|
||||||
|
nextLevels:
|
||||||
|
continue: 'shadow-guard'
|
||||||
|
practice: true
|
||||||
|
disabled: true
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name: 'Shadow Guard'
|
name: 'Shadow Guard'
|
||||||
|
@ -619,6 +647,23 @@ hero = [
|
||||||
description: 'Evade the Kithgard minion.'
|
description: 'Evade the Kithgard minion.'
|
||||||
x: 54
|
x: 54
|
||||||
y: 9
|
y: 9
|
||||||
|
nextLevels:
|
||||||
|
more_practice: 'munchkin-dodger'
|
||||||
|
continue: 'true-names'
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name: 'Munchkin Dodger'
|
||||||
|
type: 'hero'
|
||||||
|
difficulty: 1
|
||||||
|
id: 'munchkin-dodger'
|
||||||
|
original: '541875da4c16460000ab990f'
|
||||||
|
description: 'Practice your evasion skills with more guards.'
|
||||||
|
x: 61.19
|
||||||
|
y: 13.80
|
||||||
|
nextLevels:
|
||||||
|
continue: 'true-names'
|
||||||
|
practice: true
|
||||||
|
disabled: true
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name: 'True Names'
|
name: 'True Names'
|
||||||
|
@ -629,6 +674,23 @@ hero = [
|
||||||
description: 'Learn an enemy\'s true name to defeat it.'
|
description: 'Learn an enemy\'s true name to defeat it.'
|
||||||
x: 74
|
x: 74
|
||||||
y: 12
|
y: 12
|
||||||
|
nextLevels:
|
||||||
|
more_practice: 'munchkin-slayer'
|
||||||
|
continue: 'the-raised-sword'
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name: 'Munchkin Slayer'
|
||||||
|
type: 'hero'
|
||||||
|
difficulty: 1
|
||||||
|
id: 'munchkin-slayer'
|
||||||
|
original: '5418aec24c16460000ab9aa6'
|
||||||
|
description: 'Test out your battle skills by defeating more munchkins.'
|
||||||
|
x: 80.85
|
||||||
|
y: 11.85
|
||||||
|
nextLevels:
|
||||||
|
continue: 'the-raised-sword'
|
||||||
|
practice: true
|
||||||
|
disabled: true
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name: 'The Raised Sword'
|
name: 'The Raised Sword'
|
||||||
|
@ -639,6 +701,8 @@ hero = [
|
||||||
description: 'Learn to equip yourself for combat.'
|
description: 'Learn to equip yourself for combat.'
|
||||||
x: 85
|
x: 85
|
||||||
y: 20
|
y: 20
|
||||||
|
nextLevels:
|
||||||
|
continue: 'the-first-kithmaze'
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name: 'The First Kithmaze'
|
name: 'The First Kithmaze'
|
||||||
|
@ -649,6 +713,24 @@ hero = [
|
||||||
description: 'The builders of Kith constructed many mazes to confuse travelers.'
|
description: 'The builders of Kith constructed many mazes to confuse travelers.'
|
||||||
x: 70
|
x: 70
|
||||||
y: 28
|
y: 28
|
||||||
|
nextLevels:
|
||||||
|
more_practice: 'the-one-point-fifth-kithmaze'
|
||||||
|
continue: 'the-second-kithmaze'
|
||||||
|
skip_ahead: 'new-sight'
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name: 'The One-Point-Fifth Kithmaze'
|
||||||
|
type: 'hero'
|
||||||
|
difficulty: 1
|
||||||
|
id: 'the-one-point-fifth-kithmaze'
|
||||||
|
original: '5418cf256bae62f707c7e1c3'
|
||||||
|
description: 'Another day, another maze.'
|
||||||
|
x: 78.47
|
||||||
|
y: 34.38
|
||||||
|
nextLevels:
|
||||||
|
continue: 'the-second-kithmaze'
|
||||||
|
practice: true
|
||||||
|
disabled: true
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name: 'The Second Kithmaze'
|
name: 'The Second Kithmaze'
|
||||||
|
@ -659,6 +741,23 @@ hero = [
|
||||||
description: 'Many have tried, few have found their way through this maze.'
|
description: 'Many have tried, few have found their way through this maze.'
|
||||||
x: 55.54
|
x: 55.54
|
||||||
y: 26.96
|
y: 26.96
|
||||||
|
nextLevels:
|
||||||
|
more_practice: 'the-two-point-fifth-kithmaze'
|
||||||
|
continue: 'new-sight'
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name: 'The Two-Point-Fifth Kithmaze'
|
||||||
|
type: 'hero'
|
||||||
|
difficulty: 1
|
||||||
|
id: 'the-two-point-fifth-kithmaze'
|
||||||
|
original: '5418d40f4c16460000ab9ac2'
|
||||||
|
description: 'You must really like doing these mazes!'
|
||||||
|
x: 49.02
|
||||||
|
y: 25.78
|
||||||
|
nextLevels:
|
||||||
|
continue: 'new-sight'
|
||||||
|
practice: true
|
||||||
|
disabled: true
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name: 'New Sight'
|
name: 'New Sight'
|
||||||
|
@ -669,6 +768,8 @@ hero = [
|
||||||
description: 'A true name can only be seen with the correct lenses.'
|
description: 'A true name can only be seen with the correct lenses.'
|
||||||
x: 67
|
x: 67
|
||||||
y: 41
|
y: 41
|
||||||
|
nextLevels:
|
||||||
|
continue: 'lowly-kithmen'
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name: 'Lowly Kithmen'
|
name: 'Lowly Kithmen'
|
||||||
|
@ -679,6 +780,24 @@ hero = [
|
||||||
description: 'Use your glasses to seek out and attack the Kithmen.'
|
description: 'Use your glasses to seek out and attack the Kithmen.'
|
||||||
x: 74
|
x: 74
|
||||||
y: 48
|
y: 48
|
||||||
|
nextLevels:
|
||||||
|
more_practice: 'still-pretty-low-kithmen'
|
||||||
|
continue: 'closing-the-distance'
|
||||||
|
skip_ahead: 'the-final-kithmaze'
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name: 'Still-Pretty-Low Kithmen'
|
||||||
|
type: 'hero'
|
||||||
|
difficulty: 1
|
||||||
|
id: 'still-pretty-low-kithmen'
|
||||||
|
original: '541b288e1ccc8eaae19f3c25'
|
||||||
|
description: 'Now that you can see them, they\'re everywhere!'
|
||||||
|
x: 80.17
|
||||||
|
y: 45.31
|
||||||
|
nextLevels:
|
||||||
|
continue: 'closing-the-distance'
|
||||||
|
practice: true
|
||||||
|
disabled: true
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name: 'Closing the Distance'
|
name: 'Closing the Distance'
|
||||||
|
@ -689,6 +808,23 @@ hero = [
|
||||||
description: 'Kithmen are not the only ones to stand in your way.'
|
description: 'Kithmen are not the only ones to stand in your way.'
|
||||||
x: 76
|
x: 76
|
||||||
y: 60
|
y: 60
|
||||||
|
nextLevels:
|
||||||
|
more_practice: 'assassinating-more-kithmen'
|
||||||
|
continue: 'the-final-kithmaze'
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name: 'Assassinating More Kithmen'
|
||||||
|
type: 'hero'
|
||||||
|
difficulty: 1
|
||||||
|
id: 'assassinating-more-kithmen'
|
||||||
|
original: '541b434e1ccc8eaae19f3c33'
|
||||||
|
description: 'They\'re, uh, coming right for us?'
|
||||||
|
x: 80.34
|
||||||
|
y: 55.60
|
||||||
|
nextLevels:
|
||||||
|
continue: 'the-final-kithmaze'
|
||||||
|
practice: true
|
||||||
|
disabled: true
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name: 'The Final Kithmaze'
|
name: 'The Final Kithmaze'
|
||||||
|
@ -699,6 +835,23 @@ hero = [
|
||||||
description: 'To escape you must find your way through an Elder Kithman\'s maze.'
|
description: 'To escape you must find your way through an Elder Kithman\'s maze.'
|
||||||
x: 82
|
x: 82
|
||||||
y: 70
|
y: 70
|
||||||
|
nextLevels:
|
||||||
|
more_practice: 'okay-one-more-kithmaze'
|
||||||
|
continue: 'kithgard-gates'
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name: 'Okay, One More Kithmaze'
|
||||||
|
type: 'hero'
|
||||||
|
difficulty: 1
|
||||||
|
id: 'okay-one-more-kithmaze'
|
||||||
|
original: '541c9a30c6362edfb0f34479'
|
||||||
|
description: 'But you really gotta get outside after this, okay?'
|
||||||
|
x: 76.94
|
||||||
|
y: 74.22
|
||||||
|
nextLevels:
|
||||||
|
continue: 'kithgard-gates'
|
||||||
|
practice: true
|
||||||
|
disabled: true
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name: 'Kithgard Gates'
|
name: 'Kithgard Gates'
|
||||||
|
@ -707,9 +860,10 @@ hero = [
|
||||||
id: 'kithgard-gates'
|
id: 'kithgard-gates'
|
||||||
original: '541c9a30c6362edfb0f34479'
|
original: '541c9a30c6362edfb0f34479'
|
||||||
description: 'Escape the Kithgard dungeons and don\'t let the guardians get you.'
|
description: 'Escape the Kithgard dungeons and don\'t let the guardians get you.'
|
||||||
disabled: true
|
|
||||||
x: 89
|
x: 89
|
||||||
y: 82
|
y: 82
|
||||||
|
nextLevels:
|
||||||
|
continue: 'defence-of-plainswood'
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name: 'Defence of Plainswood'
|
name: 'Defence of Plainswood'
|
||||||
|
@ -718,7 +872,6 @@ hero = [
|
||||||
id: 'defence-of-plainswood'
|
id: 'defence-of-plainswood'
|
||||||
original: '541b67f71ccc8eaae19f3c62'
|
original: '541b67f71ccc8eaae19f3c62'
|
||||||
description: 'Protect the peasants from the pursuing ogres.'
|
description: 'Protect the peasants from the pursuing ogres.'
|
||||||
disabled: true
|
|
||||||
x: 95.31
|
x: 95.31
|
||||||
y: 88.26
|
y: 88.26
|
||||||
}
|
}
|
||||||
|
@ -781,7 +934,7 @@ hero = [
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
campaigns = [
|
WorldMapView.campaigns = campaigns = [
|
||||||
#{id: 'beginner', name: 'Beginner Campaign', description: '... in which you learn the wizardry of programming.', levels: tutorials, color: "rgb(255, 80, 60)"}
|
#{id: 'beginner', name: 'Beginner Campaign', description: '... in which you learn the wizardry of programming.', levels: tutorials, color: "rgb(255, 80, 60)"}
|
||||||
#{id: 'multiplayer', name: 'Multiplayer Arenas', description: '... in which you code head-to-head against other players.', levels: arenas, color: "rgb(80, 5, 60)"}
|
#{id: 'multiplayer', name: 'Multiplayer Arenas', description: '... in which you code head-to-head against other players.', levels: arenas, color: "rgb(80, 5, 60)"}
|
||||||
#{id: 'dev', name: 'Random Harder Levels', description: '... in which you learn the interface while doing something a little harder.', levels: experienced, color: "rgb(80, 60, 255)"}
|
#{id: 'dev', name: 'Random Harder Levels', description: '... in which you learn the interface while doing something a little harder.', levels: experienced, color: "rgb(80, 60, 255)"}
|
||||||
|
|
|
@ -18,6 +18,10 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
subscriptions:
|
subscriptions:
|
||||||
'ladder:game-submitted': 'onGameSubmitted'
|
'ladder:game-submitted': 'onGameSubmitted'
|
||||||
|
|
||||||
|
events:
|
||||||
|
'click #continue-button': 'onClickContinue'
|
||||||
|
'click .next-level-branch-button': 'onClickNextLevelBranch'
|
||||||
|
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
super(options)
|
super(options)
|
||||||
@session = options.session
|
@session = options.session
|
||||||
|
@ -33,6 +37,14 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
@waitingToContinueSince = new Date()
|
@waitingToContinueSince = new Date()
|
||||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'victory'
|
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'victory'
|
||||||
|
|
||||||
|
destroy: ->
|
||||||
|
clearInterval @sequentialAnimationInterval
|
||||||
|
super()
|
||||||
|
|
||||||
|
onHidden: ->
|
||||||
|
Backbone.Mediator.publish 'music-player:exit-menu', {}
|
||||||
|
super()
|
||||||
|
|
||||||
onAchievementsLoaded: ->
|
onAchievementsLoaded: ->
|
||||||
thangTypeOriginals = []
|
thangTypeOriginals = []
|
||||||
achievementIDs = []
|
achievementIDs = []
|
||||||
|
@ -102,13 +114,20 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
c.me = me
|
c.me = me
|
||||||
c.readyToRank = @level.get('type', true) is 'hero-ladder' and @session.readyToRank()
|
c.readyToRank = @level.get('type', true) is 'hero-ladder' and @session.readyToRank()
|
||||||
c.level = @level
|
c.level = @level
|
||||||
|
@continueLevelLink = @getNextLevelLink 'continue'
|
||||||
|
@morePracticeLevelLink = me.isAdmin() and @getNextLevelLink 'more_practice'
|
||||||
|
@skipAheadLevelLink = me.isAdmin() and @getNextLevelLink 'skip_ahead'
|
||||||
|
c.continueButtons = [
|
||||||
|
{key: 'skip_ahead', link: @skipAheadLevelLink, 'choice-explicit': 'skip', 'choice-implicit': 'too_easy'}
|
||||||
|
{key: 'continue', link: @continueLevelLink, 'choice-explicit': 'next_level', 'choice-implicit': 'just_right'}
|
||||||
|
{key: 'more_practice', link: @morePracticeLevelLink, 'choice-explicit': 'more_practice', 'choice-implicit': 'too_hard'}
|
||||||
|
]
|
||||||
return c
|
return c
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
super()
|
super()
|
||||||
return unless @supermodel.finished()
|
return unless @supermodel.finished()
|
||||||
@playSelectionSound hero, true for original, hero of @thangTypes # Preload them
|
@playSelectionSound hero, true for original, hero of @thangTypes # Preload them
|
||||||
@$el.addClass 'with-sign-up' if me.get('anonymous')
|
|
||||||
@updateSavingProgressStatus()
|
@updateSavingProgressStatus()
|
||||||
@$el.find('#victory-header').delay(250).queue(->
|
@$el.find('#victory-header').delay(250).queue(->
|
||||||
$(@).removeClass('out').dequeue()
|
$(@).removeClass('out').dequeue()
|
||||||
|
@ -134,6 +153,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
panel.delay(500)
|
panel.delay(500)
|
||||||
panel.queue(-> complete())
|
panel.queue(-> complete())
|
||||||
@animationComplete = not @animatedPanels.length
|
@animationComplete = not @animatedPanels.length
|
||||||
|
complete() if @animationComplete
|
||||||
if @level.get('type', true) is 'hero-ladder'
|
if @level.get('type', true) is 'hero-ladder'
|
||||||
@ladderSubmissionView = new LadderSubmissionView session: @session, level: @level
|
@ladderSubmissionView = new LadderSubmissionView session: @session, level: @level
|
||||||
@insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view')
|
@insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view')
|
||||||
|
@ -216,16 +236,18 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
clearInterval @sequentialAnimationInterval
|
clearInterval @sequentialAnimationInterval
|
||||||
@animationComplete = true
|
@animationComplete = true
|
||||||
@updateSavingProgressStatus()
|
@updateSavingProgressStatus()
|
||||||
|
Backbone.Mediator.publish 'music-player:enter-menu', terrain: @level.get('terrain', true)
|
||||||
|
|
||||||
updateSavingProgressStatus: ->
|
updateSavingProgressStatus: ->
|
||||||
return unless @animationComplete
|
return unless @animationComplete
|
||||||
@$el.find('#saving-progress-label').toggleClass('hide', @readyToContinue)
|
@$el.find('#saving-progress-label').toggleClass('hide', @readyToContinue)
|
||||||
@$el.find('#continue-button').toggleClass('hide', not @readyToContinue)
|
@$el.find('.next-level-button').toggleClass('hide', not @readyToContinue)
|
||||||
@$el.find('.sign-up-poke').toggleClass('hide', not @readyToContinue)
|
@$el.find('.sign-up-poke').toggleClass('hide', not @readyToContinue)
|
||||||
|
|
||||||
onGameSubmitted: (e) ->
|
onGameSubmitted: (e) ->
|
||||||
ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches"
|
ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches"
|
||||||
Backbone.Mediator.publish 'router:navigate', route: ladderURL
|
# Preserve the supermodel as we navigate back to the ladder.
|
||||||
|
Backbone.Mediator.publish 'router:navigate', route: ladderURL, viewClass: require('views/play/ladder/LadderView'), viewArgs: [{supermodel: @supermodel}]
|
||||||
|
|
||||||
playSelectionSound: (hero, preload=false) ->
|
playSelectionSound: (hero, preload=false) ->
|
||||||
return unless sounds = hero.get('soundTriggers')?.selected
|
return unless sounds = hero.get('soundTriggers')?.selected
|
||||||
|
@ -236,8 +258,36 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
else
|
else
|
||||||
AudioPlayer.playSound name, 1
|
AudioPlayer.playSound name, 1
|
||||||
|
|
||||||
# TODO: award heroes/items and play an awesome sound when you get one
|
# Branching group testing
|
||||||
|
|
||||||
destroy: ->
|
getNextLevel: (type) ->
|
||||||
clearInterval @sequentialAnimationInterval
|
for campaign in require('views/play/WorldMapView').campaigns
|
||||||
super()
|
break if levelInfo
|
||||||
|
for level in campaign.levels
|
||||||
|
if level.id is @level.get 'slug'
|
||||||
|
levelInfo = level
|
||||||
|
break
|
||||||
|
levelInfo?.nextLevels?[type] # 'more_practice', 'skip_ahead', 'continue'
|
||||||
|
|
||||||
|
getNextLevelLink: (type) ->
|
||||||
|
return '/play' unless nextLevel = @getNextLevel type
|
||||||
|
"play?next=#{nextLevel}"
|
||||||
|
|
||||||
|
onClickContinue: (e) ->
|
||||||
|
nextLevelLink = @continueLevelLink
|
||||||
|
if me.getBranchingGroup() is 'all-practice' and @morePracticeLevelLink
|
||||||
|
nextLevelLink = @morePracticeLevelLink
|
||||||
|
skipPrompt = me.getBranchingGroup() in ['no-practice', 'all-practice']
|
||||||
|
skipPrompt ||= not (@skipAheadLevelLink or @morePractiveLevelLink) and me.getBranchingGroup() is 'choice-explicit'
|
||||||
|
if skipPrompt
|
||||||
|
# Preserve the supermodel as we navigate back to the world map.
|
||||||
|
Backbone.Mediator.publish 'router:navigate', route: nextLevelLink, viewClass: require('views/play/WorldMapView'), viewArgs: [{supermodel: @supermodel}]
|
||||||
|
else
|
||||||
|
# Hide everything except the buttons prompting them for which kind of next level to do
|
||||||
|
@$el.find('.modal-footer, .modal-body > *').hide()
|
||||||
|
@$el.find('.next-levels-prompt').show()
|
||||||
|
|
||||||
|
onClickNextLevelBranch: (e) ->
|
||||||
|
application.tracker?.trackEvent 'Branch Selected', level: @level.get('slug'), label: @level.get('slug'), branch: $(e.target).data('branch-key'), branchingGroup: me.getBranchingGroup()
|
||||||
|
# Preserve the supermodel as we navigate back to world map.
|
||||||
|
Backbone.Mediator.publish 'router:navigate', route: '/play', viewClass: require('views/play/WorldMapView'), viewArgs: [{supermodel: @supermodel}]
|
||||||
|
|
|
@ -47,7 +47,7 @@ module.exports = class SpellPaletteEntryView extends CocoView
|
||||||
).on 'show.bs.popover', =>
|
).on 'show.bs.popover', =>
|
||||||
Backbone.Mediator.publish 'tome:palette-hovered', thang: @thang, prop: @doc.name, entry: @
|
Backbone.Mediator.publish 'tome:palette-hovered', thang: @thang, prop: @doc.name, entry: @
|
||||||
soundIndex = Math.floor(Math.random() * 4)
|
soundIndex = Math.floor(Math.random() * 4)
|
||||||
Backbone.Mediator.publish 'audio-player:play-sound', trigger: "spell-palette-entry-open-{soundIndex}", volume: 0.75
|
Backbone.Mediator.publish 'audio-player:play-sound', trigger: "spell-palette-entry-open-#{soundIndex}", volume: 0.75
|
||||||
|
|
||||||
onMouseEnter: (e) ->
|
onMouseEnter: (e) ->
|
||||||
# Make sure the doc has the updated Thang so it can regenerate its prop value
|
# Make sure the doc has the updated Thang so it can regenerate its prop value
|
||||||
|
|
|
@ -75,7 +75,7 @@ module.exports = class SpellPaletteView extends CocoView
|
||||||
columns = ({items: [], nEntries: 0} for i in [0 ... nColumns])
|
columns = ({items: [], nEntries: 0} for i in [0 ... nColumns])
|
||||||
nRows = 0
|
nRows = 0
|
||||||
for group, entries of @entryGroups
|
for group, entries of @entryGroups
|
||||||
shortestColumn = _.sortBy(columns, (column) -> column.nEntries)[0]
|
continue unless shortestColumn = _.sortBy(columns, (column) -> column.nEntries)[0]
|
||||||
shortestColumn.nEntries += Math.max 2, entries.length
|
shortestColumn.nEntries += Math.max 2, entries.length
|
||||||
shortestColumn.items.push @entryGroupElements[group]
|
shortestColumn.items.push @entryGroupElements[group]
|
||||||
nRows = Math.max nRows, shortestColumn.nEntries
|
nRows = Math.max nRows, shortestColumn.nEntries
|
||||||
|
|
|
@ -197,13 +197,15 @@ module.exports = class SpellView extends CocoView
|
||||||
@zatanna = new Zatanna @ace,
|
@zatanna = new Zatanna @ace,
|
||||||
basic: false
|
basic: false
|
||||||
liveCompletion: false
|
liveCompletion: false
|
||||||
snippets: @autocomplete
|
|
||||||
snippetsLangDefaults: false
|
snippetsLangDefaults: false
|
||||||
completers:
|
completers:
|
||||||
keywords: false
|
keywords: false
|
||||||
text: false
|
snippets: @autocomplete
|
||||||
|
text: @autocomplete
|
||||||
autoLineEndings:
|
autoLineEndings:
|
||||||
javascript: ';'
|
javascript: ';'
|
||||||
|
popupFontSizePx: 16
|
||||||
|
popupWidthPx: 380
|
||||||
|
|
||||||
updateAutocomplete: (@autocomplete) ->
|
updateAutocomplete: (@autocomplete) ->
|
||||||
@zatanna?.set 'snippets', @autocomplete
|
@zatanna?.set 'snippets', @autocomplete
|
||||||
|
@ -639,7 +641,7 @@ module.exports = class SpellView extends CocoView
|
||||||
# TODO: move this whole thing into SpellDebugView or somewhere?
|
# TODO: move this whole thing into SpellDebugView or somewhere?
|
||||||
@highlightComments() unless @destroyed
|
@highlightComments() unless @destroyed
|
||||||
flow ?= @spellThang?.castAether?.flow
|
flow ?= @spellThang?.castAether?.flow
|
||||||
return unless flow
|
return unless flow and @thang
|
||||||
executed = []
|
executed = []
|
||||||
executedRows = {}
|
executedRows = {}
|
||||||
matched = false
|
matched = false
|
||||||
|
|
|
@ -32,7 +32,7 @@ setupExpressMiddleware = (app) ->
|
||||||
express.logger.format('prod', productionLogging)
|
express.logger.format('prod', productionLogging)
|
||||||
app.use(express.logger('prod'))
|
app.use(express.logger('prod'))
|
||||||
app.use express.compress filter: (req, res) ->
|
app.use express.compress filter: (req, res) ->
|
||||||
return false if req.headers.host is 'codecombat.com' # Cloudflare will gzip it for us on codecombat.com
|
#return false if req.headers.host is 'codecombat.com' # CloudFlare will gzip it for us on codecombat.com # But now it's disabled.
|
||||||
compressible res.getHeader('Content-Type')
|
compressible res.getHeader('Content-Type')
|
||||||
else
|
else
|
||||||
app.use(express.logger('dev'))
|
app.use(express.logger('dev'))
|
||||||
|
|
Loading…
Reference in a new issue