From 600e9852597ad825918ead67ec857a6b2e8a9c97 Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Sun, 21 Sep 2014 20:19:27 -0700 Subject: [PATCH] Removed Wizards from hero levels. Fixed issues with GameMenuModal width and swapping of hero config. No need to click start with ?dev=true. Hero is always selected in hero levels. GameMenuModal shows up while loading if no heroConfig is detected. --- app/lib/LevelLoader.coffee | 10 +++-- app/schemas/subscriptions/play.coffee | 4 ++ app/styles/game-menu/game-menu-modal.sass | 3 +- app/styles/play/level/loading.sass | 1 + app/templates/game-menu/inventory-view.jade | 4 +- app/views/game-menu/ChooseHeroView.coffee | 1 - app/views/game-menu/GameMenuModal.coffee | 8 ++-- app/views/game-menu/InventoryView.coffee | 4 ++ app/views/game-menu/MultiplayerView.coffee | 2 - app/views/play/SpectateView.coffee | 31 +++++++------- app/views/play/level/ControlBarView.coffee | 3 +- app/views/play/level/LevelLoadingView.coffee | 14 ++++--- app/views/play/level/PlayLevelView.coffee | 44 +++++++++++++------- app/views/play/level/tome/TomeView.coffee | 1 + 14 files changed, 82 insertions(+), 48 deletions(-) diff --git a/app/lib/LevelLoader.coffee b/app/lib/LevelLoader.coffee index 186c0ca03..da87a1221 100644 --- a/app/lib/LevelLoader.coffee +++ b/app/lib/LevelLoader.coffee @@ -63,7 +63,7 @@ module.exports = class LevelLoader extends CocoClass loadSession: -> return if @headless if @sessionID - url = "/db/level_session/#{@sessionID}" + url = "/db/level.session/#{@sessionID}" else url = "/db/level/#{@levelID}/session" url += "?team=#{@team}" if @team @@ -72,14 +72,15 @@ module.exports = class LevelLoader extends CocoClass @sessionResource = @supermodel.loadModel(session, 'level_session', {cache: false}) @session = @sessionResource.model if @session.loaded + @session.setURL '/db/level.session/' + @session.id @loadDependenciesForSession @session else @listenToOnce @session, 'sync', -> - @session.url = -> '/db/level.session/' + @id + @session.setURL '/db/level.session/' + @session.id @loadDependenciesForSession @session if @opponentSessionID - opponentSession = new LevelSession().setURL "/db/level_session/#{@opponentSessionID}" + opponentSession = new LevelSession().setURL "/db/level.session/#{@opponentSessionID}" @opponentSessionResource = @supermodel.loadModel(opponentSession, 'opponent_session') @opponentSession = @opponentSessionResource.model if @opponentSession.loaded @@ -100,6 +101,9 @@ module.exports = class LevelLoader extends CocoClass url = "/db/thang.type/#{itemThangType}/version?project=name,components,original" @worldNecessities.push @maybeLoadURL(url, ThangType, 'thang') + if session is @session + Backbone.Mediator.publish 'level:session-loaded', level: @level, session: @session + # Grabbing the rest of the required data for the level populateLevel: -> diff --git a/app/schemas/subscriptions/play.coffee b/app/schemas/subscriptions/play.coffee index 72993e5fe..bdbab754a 100644 --- a/app/schemas/subscriptions/play.coffee +++ b/app/schemas/subscriptions/play.coffee @@ -81,6 +81,10 @@ module.exports = level: {type: 'object'} team: {type: ['string', 'null', 'undefined']} + 'level:session-loaded': c.object {required: ['level', 'session']}, + level: {type: 'object'} + session: {type: 'object'} + 'level:loading-view-unveiling': c.object {} 'level:loading-view-unveiled': c.object {required: ['view']}, diff --git a/app/styles/game-menu/game-menu-modal.sass b/app/styles/game-menu/game-menu-modal.sass index da4ad9f23..7e55cfa5e 100644 --- a/app/styles/game-menu/game-menu-modal.sass +++ b/app/styles/game-menu/game-menu-modal.sass @@ -28,7 +28,8 @@ .modal-dialog margin-top: 0 - + width: 963px + .nav-tabs h2 margin: 0 diff --git a/app/styles/play/level/loading.sass b/app/styles/play/level/loading.sass index 0bffa92f3..baafd99f1 100644 --- a/app/styles/play/level/loading.sass +++ b/app/styles/play/level/loading.sass @@ -25,6 +25,7 @@ left: 50% $WIDTH: 1000px width: $WIDTH + min-height: 60px margin-left: (-$WIDTH / 2) z-index: 100 background-color: rgba(220, 255, 230, 0.6) diff --git a/app/templates/game-menu/inventory-view.jade b/app/templates/game-menu/inventory-view.jade index 7dfcb55da..71ff11d21 100644 --- a/app/templates/game-menu/inventory-view.jade +++ b/app/templates/game-menu/inventory-view.jade @@ -8,7 +8,7 @@ .replace-me(data-item-id=equipment[slot].get('original')) .item-slot-column.pull-left - for slot in ['torso', 'gloves', 'left-hand', 'minion'] + for slot in ['minion', 'torso', 'gloves', 'left-hand'] .item-slot(data-slot=slot) .placeholder .item-container @@ -26,7 +26,7 @@ span.glyphicon.glyphicon-transfer .item-slot-column.pull-right - for slot in ['waist', 'feet', 'right-hand', 'pet'] + for slot in ['pet', 'waist', 'feet', 'right-hand'] .item-slot(data-slot=slot) .placeholder .item-container diff --git a/app/views/game-menu/ChooseHeroView.coffee b/app/views/game-menu/ChooseHeroView.coffee index 8ec027e51..c21e33635 100644 --- a/app/views/game-menu/ChooseHeroView.coffee +++ b/app/views/game-menu/ChooseHeroView.coffee @@ -23,7 +23,6 @@ module.exports = class ChooseHeroView extends CocoView constructor: (options) -> super options @heroes = new CocoCollection([], {model: ThangType}) - @equipment = options.equipment or @options.session?.get('heroConfig')?.inventory or {} @heroes.url = '/db/thang.type?view=heroes&project=original,name,slug,soundTriggers' @supermodel.loadCollection(@heroes, 'heroes') @stages = {} diff --git a/app/views/game-menu/GameMenuModal.coffee b/app/views/game-menu/GameMenuModal.coffee index 412d8ce75..87bc66af0 100644 --- a/app/views/game-menu/GameMenuModal.coffee +++ b/app/views/game-menu/GameMenuModal.coffee @@ -11,7 +11,6 @@ submenuViews = [ module.exports = class GameMenuModal extends ModalView template: template - modalWidthPercent: 95 id: 'game-menu-modal' instant: true @@ -52,7 +51,7 @@ module.exports = class GameMenuModal extends ModalView Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1 updateConfig: -> - sessionHeroConfig = @options.session.get('heroConfig') ? {} + sessionHeroConfig = $.extend {}, true, (@options.session.get('heroConfig') ? {}) lastHeroConfig = me.get('heroConfig') ? {} thangType = @subviews.choose_hero_view.selectedHero.get 'original' inventory = @subviews.inventory_view.getCurrentEquipmentConfig() @@ -72,8 +71,11 @@ module.exports = class GameMenuModal extends ModalView me.set 'aceConfig', aceConfig if patchSession @options.session.set 'heroConfig', sessionHeroConfig - @options.session.patch success: -> + success = -> _.defer -> Backbone.Mediator.publish 'level:hero-config-changed', {} + error = (model, res) -> + console.error 'error patching session', model, res, res.responseJSON, res.status, res.statusText + @options.session.patch success: success, error: error if patchMe me.set 'heroConfig', lastHeroConfig me.patch() diff --git a/app/views/game-menu/InventoryView.coffee b/app/views/game-menu/InventoryView.coffee index f59f8269f..317fef60e 100644 --- a/app/views/game-menu/InventoryView.coffee +++ b/app/views/game-menu/InventoryView.coffee @@ -29,6 +29,7 @@ module.exports = class InventoryView extends CocoView super(arguments...) @items = new CocoCollection([], {model: ThangType}) @equipment = options.equipment or @options.session?.get('heroConfig')?.inventory or me.get('heroConfig')?.inventory or {} + @equipment = $.extend true, {}, @equipment @assignLevelEquipment() @items.url = '/db/thang.type?view=items&project=name,components,original,rasterIcon' @supermodel.loadCollection(@items, 'items') @@ -88,6 +89,7 @@ module.exports = class InventoryView extends CocoView cursorAt: {left: 35.5, top: 35.5} helper: -> dragHelper revertDuration: 200 + distance: 10 scroll: false zIndex: 100 itemView.$el.on 'dragstart', => @@ -137,6 +139,8 @@ module.exports = class InventoryView extends CocoView @onSelectionChanged() onAvailableItemDoubleClick: (e) -> + @selectAvailableItem $(e.target).closest('.list-group-item') + @onSelectionChanged() slot = @getSelectedSlot() slot = @$el.find('.item-slot:not(.disabled):first') if not slot.length @unequipItemFromSlot(slot) diff --git a/app/views/game-menu/MultiplayerView.coffee b/app/views/game-menu/MultiplayerView.coffee index 41b6a08dc..9d95345bd 100644 --- a/app/views/game-menu/MultiplayerView.coffee +++ b/app/views/game-menu/MultiplayerView.coffee @@ -24,7 +24,6 @@ module.exports = class MultiplayerView extends CocoView super(options) @level = options.level @session = options.session - @playableTeams = options.playableTeams @listenTo @session, 'change:multiplayer', @updateLinkSection @initMultiplayerSessions() @@ -40,7 +39,6 @@ module.exports = class MultiplayerView extends CocoView c.multiplayer = @session.get 'multiplayer' c.team = @session.get 'team' c.levelSlug = @level?.get 'slug' - c.playableTeams = @playableTeams # For now, ladderGame will disallow multiplayer, because session code combining doesn't play nice yet. if @level?.get('type') is 'ladder' c.ladderGame = true diff --git a/app/views/play/SpectateView.coffee b/app/views/play/SpectateView.coffee index 565127603..4adab5a3f 100644 --- a/app/views/play/SpectateView.coffee +++ b/app/views/play/SpectateView.coffee @@ -98,9 +98,9 @@ module.exports = class SpectateLevelView extends RootView $('body').addClass('is-playing') onLoaded: -> - _.defer => @onLevelLoaded() + _.defer => @onLevelLoaderLoaded() - onLevelLoaded: -> + onLevelLoaderLoaded: -> @grabLevelLoaderData() #at this point, all requisite data is loaded, and sessions are not denormalized team = @world.teamForPlayer(0) @@ -119,18 +119,19 @@ module.exports = class SpectateLevelView extends RootView @register() @controlBar.setBus(@bus) @surface.showLevel() - if me.id isnt @session.get 'creator' - @surface.createOpponentWizard - id: @session.get('creator') - name: @session.get('creatorName') - team: @session.get('team') - levelSlug: @level.get('slug') + if @level.get('type', true) isnt 'hero' + if me.id isnt @session.get 'creator' + @surface.createOpponentWizard + id: @session.get('creator') + name: @session.get('creatorName') + team: @session.get('team') + levelSlug: @level.get('slug') - @surface.createOpponentWizard - id: @otherSession.get('creator') - name: @otherSession.get('creatorName') - team: @otherSession.get('team') - levelSlug: @level.get('slug') + @surface.createOpponentWizard + id: @otherSession.get('creator') + name: @otherSession.get('creatorName') + team: @otherSession.get('team') + levelSlug: @level.get('slug') grabLevelLoaderData: -> @session = @levelLoader.session @@ -186,7 +187,7 @@ module.exports = class SpectateLevelView extends RootView ctx.fillText("Loaded #{@modelsLoaded} thingies",50,50) insertSubviews: -> - @insertSubView @tome = new TomeView levelID: @levelID, session: @session, thangs: @world.thangs, supermodel: @supermodel, spectateView: true, spectateOpponentCodeLanguage: @otherSession?.get('submittedCodeLanguage') + @insertSubView @tome = new TomeView levelID: @levelID, session: @session, thangs: @world.thangs, supermodel: @supermodel, spectateView: true, spectateOpponentCodeLanguage: @otherSession?.get('submittedCodeLanguage'), level: @level @insertSubView new PlaybackView {} @insertSubView new GoldView {} @@ -205,7 +206,7 @@ module.exports = class SpectateLevelView extends RootView initSurface: -> surfaceCanvas = $('canvas#surface', @$el) - @surface = new Surface(@world, surfaceCanvas, thangTypes: @supermodel.getModels(ThangType), playJingle: not @isEditorPreview, spectateGame: true) + @surface = new Surface(@world, surfaceCanvas, thangTypes: @supermodel.getModels(ThangType), playJingle: not @isEditorPreview, spectateGame: true, wizards: @level.get('type', true) isnt 'hero') worldBounds = @world.getBounds() bounds = [{x:worldBounds.left, y:worldBounds.top}, {x:worldBounds.right, y:worldBounds.bottom}] @surface.camera.setBounds(bounds) diff --git a/app/views/play/level/ControlBarView.coffee b/app/views/play/level/ControlBarView.coffee index 2eca3bbb7..30a8bbaa3 100644 --- a/app/views/play/level/ControlBarView.coffee +++ b/app/views/play/level/ControlBarView.coffee @@ -32,7 +32,6 @@ module.exports = class ControlBarView extends CocoView @worldName = options.worldName @session = options.session @level = options.level - @playableTeams = options.playableTeams @spectateGame = options.spectateGame ? false super options @@ -83,7 +82,7 @@ module.exports = class ControlBarView extends CocoView @guideHighlightInterval = null showGameMenuModal: -> - @openModalView new GameMenuModal level: @level, session: @session, playableTeams: @playableTeams + @openModalView new GameMenuModal level: @level, session: @session onJoinedRealTimeMultiplayerGame: (e) -> @multiplayerSession = e.session diff --git a/app/views/play/level/LevelLoadingView.coffee b/app/views/play/level/LevelLoadingView.coffee index b0e778b95..62834d214 100644 --- a/app/views/play/level/LevelLoadingView.coffee +++ b/app/views/play/level/LevelLoadingView.coffee @@ -6,11 +6,11 @@ module.exports = class LevelLoadingView extends CocoView template: template events: - 'mousedown .start-level-button': 'startUnveiling' # split into two for animation smoothness + 'mousedown .start-level-button': 'startUnveiling' # Split into two for animation smoothness. 'click .start-level-button': 'onClickStartLevel' subscriptions: - 'level:loaded': 'onLevelLoaded' + 'level:loaded': 'onLevelLoaded' # If Level loads after level loading view. afterRender: -> @$el.find('.tip.rare').remove() if _.random(1, 10) < 9 @@ -18,13 +18,13 @@ module.exports = class LevelLoadingView extends CocoView tip = _.sample(tips) $(tip).removeClass('to-remove') @$el.find('.to-remove').remove() + @onLevelLoaded level: @options.level if @options.level?.get('goals') # If Level was already loaded. onLevelLoaded: (e) -> @level = e.level goalList = @$el.find('.level-loading-goals').removeClass('secret').find('ul') - for goalID, goal of @level.get('goals') when not goal.team or goal.team is e.team + for goalID, goal of @level.get('goals') when (not goal.team or goal.team is e.team) and not goal.hiddenGoal goalList.append $('
  • ' + goal.name + '
  • ') - console.log 'got goals', @level.get('goals'), 'team', e.team showReady: -> return if @shownReady @@ -32,7 +32,11 @@ module.exports = class LevelLoadingView extends CocoView ready = $.i18n.t('play_level.loading_ready', defaultValue: 'Ready!') @$el.find('#tip-wrapper .tip').addClass('ready').text ready Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'level_loaded', volume: 0.75 # old: loading_ready - @$el.find('.start-level-button').removeClass 'secret' + if @options.autoUnveil + @startUnveiling() + @unveil() + else + @$el.find('.start-level-button').removeClass 'secret' startUnveiling: (e) -> Backbone.Mediator.publish 'level:loading-view-unveiling', {} diff --git a/app/views/play/level/PlayLevelView.coffee b/app/views/play/level/PlayLevelView.coffee index 87d0489d4..f62519c31 100644 --- a/app/views/play/level/PlayLevelView.coffee +++ b/app/views/play/level/PlayLevelView.coffee @@ -33,6 +33,7 @@ LevelFlagsView = require './LevelFlagsView' GoldView = require './LevelGoldView' VictoryModal = require './modal/VictoryModal' InfiniteLoopModal = require './modal/InfiniteLoopModal' +GameMenuModal = require 'views/game-menu/GameMenuModal' PROFILE_ME = false @@ -64,6 +65,8 @@ module.exports = class PlayLevelView extends RootView 'level:started': 'onLevelStarted' 'level:loading-view-unveiling': 'onLoadingViewUnveiling' 'level:loading-view-unveiled': 'onLoadingViewUnveiled' + 'level:loaded': 'onLevelLoaded' + 'level:session-loaded': 'onSessionLoaded' 'playback:real-time-playback-waiting': 'onRealTimePlaybackWaiting' 'playback:real-time-playback-started': 'onRealTimePlaybackStarted' 'playback:real-time-playback-ended': 'onRealTimePlaybackEnded' @@ -171,14 +174,13 @@ module.exports = class PlayLevelView extends RootView afterRender: -> super() window.onPlayLevelViewLoaded? @ # still a hack - @insertSubView @loadingView = new LevelLoadingView {} + @insertSubView @loadingView = new LevelLoadingView autoUnveil: @options.autoUnveil, level: @level # May not have @level loaded yet @$el.find('#level-done-button').hide() $('body').addClass('is-playing') $('body').bind('touchmove', false) if @isIPadApp() afterInsert: -> super() - @showWizardSettingsModal() if not me.get('name') and not @isIPadApp() # Partially Loaded Setup #################################################### @@ -252,7 +254,7 @@ module.exports = class PlayLevelView extends RootView @god.setGoalManager @goalManager insertSubviews: -> - @insertSubView @tome = new TomeView levelID: @levelID, session: @session, otherSession: @otherSession, thangs: @world.thangs, supermodel: @supermodel + @insertSubView @tome = new TomeView levelID: @levelID, session: @session, otherSession: @otherSession, thangs: @world.thangs, supermodel: @supermodel, level: @level @insertSubView new LevelPlaybackView session: @session @insertSubView new GoalsView {} @insertSubView new LevelFlagsView world: @world @@ -260,7 +262,7 @@ module.exports = class PlayLevelView extends RootView @insertSubView new HUDView {} @insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session worldName = utils.i18n @level.attributes, 'name' - @controlBar = @insertSubView new ControlBarView {worldName: worldName, session: @session, level: @level, supermodel: @supermodel, playableTeams: @world.playableTeams} + @controlBar = @insertSubView new ControlBarView {worldName: worldName, session: @session, level: @level, supermodel: @supermodel} Backbone.Mediator.publish('level:set-debug', debug: true) if @isIPadApp() # if me.displayName() is 'Nick' initVolume: -> @@ -280,10 +282,19 @@ module.exports = class PlayLevelView extends RootView # Load Completed Setup ###################################################### - onLoaded: -> - _.defer => @onLevelLoaded() + onLevelLoaded: (e) -> + # Just the level has been loaded by the level loader + @showWizardSettingsModal() if not me.get('name') and not @isIPadApp() and e.level.get('type', true) isnt 'hero' - onLevelLoaded: -> + onSessionLoaded: (e) -> + # Just the level and session have been loaded by the level loader + if e.level.get('type', true) is 'hero' and not _.size e.session.get('heroConfig')?.inventory ? {} + @openModalView new GameMenuModal level: e.level, session: e.session + + onLoaded: -> + _.defer => @onLevelLoaderLoaded() + + onLevelLoaderLoaded: -> # Everything is now loaded return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early @@ -306,7 +317,7 @@ module.exports = class PlayLevelView extends RootView initSurface: -> surfaceCanvas = $('canvas#surface', @$el) - @surface = new Surface(@world, surfaceCanvas, thangTypes: @supermodel.getModels(ThangType), playJingle: not @isEditorPreview) + @surface = new Surface(@world, surfaceCanvas, thangTypes: @supermodel.getModels(ThangType), playJingle: not @isEditorPreview, wizards: @level.get('type', true) isnt 'hero') worldBounds = @world.getBounds() bounds = [{x: worldBounds.left, y: worldBounds.top}, {x: worldBounds.right, y: worldBounds.bottom}] @surface.camera.setBounds(bounds) @@ -320,9 +331,12 @@ module.exports = class PlayLevelView extends RootView if window.currentModal and not window.currentModal.destroyed return Backbone.Mediator.subscribeOnce 'modal:closed', @onLevelStarted, @ @surface.showLevel() - if @otherSession + if @otherSession and @level.get('type', true) isnt 'hero' # 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'), levelSlug: @level.get('slug'), codeLanguage: @otherSession.get('submittedCodeLanguage') + if @isEditorPreview + @loadingView.startUnveiling() + @loadingView.unveil() onLoadingViewUnveiling: (e) -> @restoreSessionState() @@ -342,13 +356,13 @@ module.exports = class PlayLevelView extends RootView return if @alreadyLoadedState @alreadyLoadedState = true state = @originalSessionState - if state.frame and @level.get('type') isnt 'ladder' # https://github.com/codecombat/codecombat/issues/714 + if state.frame and @level.get('type', true) isnt 'ladder' # https://github.com/codecombat/codecombat/issues/714 Backbone.Mediator.publish 'level:set-time', time: 0, frameOffset: state.frame - if state.selected + if @level.get('type', true) is 'hero' + Backbone.Mediator.publish 'tome:select-primary-sprite', {} + else if state.selected # TODO: Should also restore selected spell here by saving spellName Backbone.Mediator.publish 'level:select-sprite', thangID: state.selected, spellName: null - else if @isIPadApp() - Backbone.Mediator.publish 'tome:select-primary-sprite', {} if state.playing? Backbone.Mediator.publish 'level:set-playing', playing: state.playing @@ -378,10 +392,12 @@ module.exports = class PlayLevelView extends RootView #@setLevel @level, @supermodel #Backbone.Mediator.publish 'tome:cast-spell', {} # We'll just make a new PlayLevelView instead + console.log 'Hero config changed; reload the level.' Backbone.Mediator.publish 'router:navigate', { route: window.location.pathname, viewClass: PlayLevelView, - viewArgs: [{supermodel: @supermodel}, @levelID]} + viewArgs: [{supermodel: @supermodel, autoUnveil: true}, @levelID] + } onWindowResize: (s...) -> $('#pointer').css('opacity', 0.0) diff --git a/app/views/play/level/tome/TomeView.coffee b/app/views/play/level/tome/TomeView.coffee index 066fa9b71..c473262af 100644 --- a/app/views/play/level/tome/TomeView.coffee +++ b/app/views/play/level/tome/TomeView.coffee @@ -183,6 +183,7 @@ module.exports = class TomeView extends CocoView @thangList?.$el.show() onSpriteSelected: (e) -> + return if @spellView and @options.level.get('type', true) is 'hero' # Never deselect the hero in the Tome. thang = e.thang spellName = e.spellName @spellList?.$el.hide()