From 349ab24da7bc9ab3628019bb332b0f9573ee143c Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Thu, 14 Jul 2016 09:38:45 -0700 Subject: [PATCH] First pass at adding 'web-dev' level type --- app/core/ParticleMan.coffee | 36 +++++++++++++++++++ app/lib/LevelSetupManager.coffee | 2 +- app/models/Level.coffee | 2 +- .../component/ThangComponentConfigView.coffee | 2 +- .../level/thangs/LevelThangEditView.coffee | 2 +- .../editor/level/thangs/ThangsTabView.coffee | 4 +-- app/views/editor/verifier/VerifierView.coffee | 2 +- app/views/play/level/ControlBarView.coffee | 3 +- app/views/play/level/PlayLevelView.coffee | 8 ++--- .../play/level/modal/HeroVictoryModal.coffee | 18 +++++----- .../play/level/tome/SpellPaletteView.coffee | 4 +-- app/views/play/level/tome/TomeView.coffee | 2 +- app/views/play/menu/GuideView.coffee | 2 +- 13 files changed, 62 insertions(+), 25 deletions(-) diff --git a/app/core/ParticleMan.coffee b/app/core/ParticleMan.coffee index bcaebd72b..41be7829c 100644 --- a/app/core/ParticleMan.coffee +++ b/app/core/ParticleMan.coffee @@ -245,6 +245,12 @@ particleKinds['level-dungeon-game-dev'] = particleKinds['level-dungeon-game-dev- colorMiddle: hsl 0.7, 0.75, 0.5 colorEnd: hsl 0.7, 0.75, 0.3 +particleKinds['level-dungeon-web-dev'] = particleKinds['level-dungeon-web-dev-premium'] = ext particleKinds['level-dungeon-hero-ladder'], + emitter: + colorStart: hsl 0.7, 0.25, 0.7 + colorMiddle: hsl 0.7, 0.25, 0.5 + colorEnd: hsl 0.7, 0.25, 0.3 + particleKinds['level-dungeon-premium-item'] = ext particleKinds['level-dungeon-gate'], emitter: particleCount: 2000 @@ -300,6 +306,12 @@ particleKinds['level-forest-game-dev'] = particleKinds['level-forest-game-dev-pr colorMiddle: hsl 0.7, 0.75, 0.5 colorEnd: hsl 0.7, 0.75, 0.3 +particleKinds['level-forest-web-dev'] = particleKinds['level-forest-web-dev-premium'] = ext particleKinds['level-forest-hero-ladder'], + emitter: + colorStart: hsl 0.7, 0.25, 0.7 + colorMiddle: hsl 0.7, 0.25, 0.5 + colorEnd: hsl 0.7, 0.25, 0.3 + particleKinds['level-forest-premium-item'] = ext particleKinds['level-forest-gate'], emitter: particleCount: 2000 @@ -355,6 +367,12 @@ particleKinds['level-desert-game-dev'] = particleKinds['level-desert-game-dev-pr colorMiddle: hsl 0.7, 0.75, 0.5 colorEnd: hsl 0.7, 0.75, 0.3 +particleKinds['level-desert-web-dev'] = particleKinds['level-desert-web-dev-premium'] = ext particleKinds['level-desert-hero-ladder'], + emitter: + colorStart: hsl 0.7, 0.25, 0.7 + colorMiddle: hsl 0.7, 0.25, 0.5 + colorEnd: hsl 0.7, 0.25, 0.3 + particleKinds['level-mountain-premium-hero'] = ext particleKinds['level-mountain-premium'], emitter: particleCount: 200 @@ -395,6 +413,12 @@ particleKinds['level-mountain-game-dev'] = particleKinds['level-mountain-game-de colorMiddle: hsl 0.7, 0.75, 0.5 colorEnd: hsl 0.7, 0.75, 0.3 +particleKinds['level-mountain-web-dev'] = particleKinds['level-mountain-web-dev-premium'] = ext particleKinds['level-mountain-hero-ladder'], + emitter: + colorStart: hsl 0.7, 0.25, 0.7 + colorMiddle: hsl 0.7, 0.25, 0.5 + colorEnd: hsl 0.7, 0.25, 0.3 + particleKinds['level-glacier-premium-hero'] = ext particleKinds['level-glacier-premium'], emitter: particleCount: 200 @@ -435,6 +459,12 @@ particleKinds['level-glacier-game-dev'] = particleKinds['level-glacier-game-dev- colorMiddle: hsl 0.7, 0.75, 0.5 colorEnd: hsl 0.7, 0.75, 0.3 +particleKinds['level-glacier-web-dev'] = particleKinds['level-glacier-web-dev-premium'] = ext particleKinds['level-glacier-hero-ladder'], + emitter: + colorStart: hsl 0.7, 0.25, 0.7 + colorMiddle: hsl 0.7, 0.25, 0.5 + colorEnd: hsl 0.7, 0.25, 0.3 + particleKinds['level-volcano-premium-hero'] = ext particleKinds['level-volcano-premium'], emitter: particleCount: 200 @@ -474,3 +504,9 @@ particleKinds['level-volcano-game-dev'] = particleKinds['level-volcano-game-dev- colorStart: hsl 0.7, 0.75, 0.7 colorMiddle: hsl 0.7, 0.75, 0.5 colorEnd: hsl 0.7, 0.75, 0.3 + +particleKinds['level-volcano-web-dev'] = particleKinds['level-volcano-web-dev-premium'] = ext particleKinds['level-volcano-hero-ladder'], + emitter: + colorStart: hsl 0.7, 0.25, 0.7 + colorMiddle: hsl 0.7, 0.25, 0.5 + colorEnd: hsl 0.7, 0.25, 0.3 diff --git a/app/lib/LevelSetupManager.coffee b/app/lib/LevelSetupManager.coffee index f9d00a823..840967c12 100644 --- a/app/lib/LevelSetupManager.coffee +++ b/app/lib/LevelSetupManager.coffee @@ -74,7 +74,7 @@ module.exports = class LevelSetupManager extends CocoClass @session.set 'heroConfig', {"thangType":raider,"inventory":{}} @onInventoryModalPlayClicked() return - if @level.isType('course', 'course-ladder') or window.serverConfig.picoCTF + if @level.isType('course', 'course-ladder', 'game-dev', 'web-dev') or window.serverConfig.picoCTF @onInventoryModalPlayClicked() return @heroesModal = new PlayHeroesModal({supermodel: @supermodel, session: @session, confirmButtonI18N: 'play.next', level: @level, hadEverChosenHero: @options.hadEverChosenHero}) diff --git a/app/models/Level.coffee b/app/models/Level.coffee index 268b1700f..998e40c2c 100644 --- a/app/models/Level.coffee +++ b/app/models/Level.coffee @@ -59,7 +59,7 @@ module.exports = class Level extends CocoModel denormalize: (supermodel, session, otherSession) -> o = $.extend true, {}, @attributes - if o.thangs and @isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') + if o.thangs and @isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') thangTypesWithComponents = (tt for tt in supermodel.getModels(ThangType) when tt.get('components')?) thangTypesByOriginal = _.indexBy thangTypesWithComponents, (tt) -> tt.get('original') # Optimization for levelThang in o.thangs diff --git a/app/views/editor/component/ThangComponentConfigView.coffee b/app/views/editor/component/ThangComponentConfigView.coffee index 08b20ebf9..2182e2a8c 100644 --- a/app/views/editor/component/ThangComponentConfigView.coffee +++ b/app/views/editor/component/ThangComponentConfigView.coffee @@ -46,7 +46,7 @@ module.exports = class ThangComponentConfigView extends CocoView schema.default ?= {} _.merge schema.default, @additionalDefaults if @additionalDefaults - if @level?.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') + if @level?.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') schema.required = [] treemaOptions = supermodel: @supermodel diff --git a/app/views/editor/level/thangs/LevelThangEditView.coffee b/app/views/editor/level/thangs/LevelThangEditView.coffee index 5dc7bc3f0..46da5067d 100644 --- a/app/views/editor/level/thangs/LevelThangEditView.coffee +++ b/app/views/editor/level/thangs/LevelThangEditView.coffee @@ -41,7 +41,7 @@ module.exports = class LevelThangEditView extends CocoView level: @level world: @world - if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') then options.thangType = thangType + if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') then options.thangType = thangType @thangComponentEditView = new ThangComponentsEditView options @listenTo @thangComponentEditView, 'components-changed', @onComponentsChanged diff --git a/app/views/editor/level/thangs/ThangsTabView.coffee b/app/views/editor/level/thangs/ThangsTabView.coffee index c2a631f47..a62c28460 100644 --- a/app/views/editor/level/thangs/ThangsTabView.coffee +++ b/app/views/editor/level/thangs/ThangsTabView.coffee @@ -636,14 +636,14 @@ module.exports = class ThangsTabView extends CocoView if batchInsert if thangType.get('name') is 'Hero Placeholder' thangID = 'Hero Placeholder' - return if not @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') or @getThangByID(thangID) + return if not @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') or @getThangByID(thangID) else thangID = "Random #{thangType.get('name')} #{@thangsBatch.length}" else thangID = Thang.nextID(thangType.get('name'), @world) until thangID and not @getThangByID(thangID) if @cloneSourceThang components = _.cloneDeep @getThangByID(@cloneSourceThang.id).components - else if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') + else if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') components = [] # Load them all from default ThangType Components else components = _.cloneDeep thangType.get('components') ? [] diff --git a/app/views/editor/verifier/VerifierView.coffee b/app/views/editor/verifier/VerifierView.coffee index 41a9500a6..423ea104d 100644 --- a/app/views/editor/verifier/VerifierView.coffee +++ b/app/views/editor/verifier/VerifierView.coffee @@ -51,7 +51,7 @@ module.exports = class VerifierView extends RootView for campaign in @campaigns.models when campaign.get('type') in ['course', 'hero'] and campaign.get('slug') isnt 'picoctf' @levelsByCampaign[campaign.get('slug')] ?= {levels: [], checked: true} campaignInfo = @levelsByCampaign[campaign.get('slug')] - for levelID, level of campaign.get('levels') when level.type not in ['hero-ladder', 'course-ladder', 'game-dev'] # Would use isType, but it's not a Level model + for levelID, level of campaign.get('levels') when level.type not in ['hero-ladder', 'course-ladder', 'game-dev', 'web-dev'] # Would use isType, but it's not a Level model campaignInfo.levels.push level.slug filterCodeLanguages: -> diff --git a/app/views/play/level/ControlBarView.coffee b/app/views/play/level/ControlBarView.coffee index 6e07caa8a..000256999 100644 --- a/app/views/play/level/ControlBarView.coffee +++ b/app/views/play/level/ControlBarView.coffee @@ -45,7 +45,7 @@ module.exports = class ControlBarView extends CocoView @observing = options.session.get('creator') isnt me.id @levelNumber = '' - if @level.isType('course') and @level.get('campaignIndex')? + if @level.isType('course', 'game-dev', 'web-dev') and @level.get('campaignIndex')? @levelNumber = @level.get('campaignIndex') + 1 if @courseInstanceID @courseInstance = new CourseInstance(_id: @courseInstanceID) @@ -137,6 +137,7 @@ module.exports = class ControlBarView extends CocoView @homeLink += "/#{@courseInstanceID}" @homeViewArgs.push @courseInstanceID #else if @level.isType('game-dev') # TODO + #else if @level.isType('web-dev') # TODO else @homeLink = '/' @homeViewClass = 'views/HomeView' diff --git a/app/views/play/level/PlayLevelView.coffee b/app/views/play/level/PlayLevelView.coffee index d2148fb2d..d0a4179f6 100644 --- a/app/views/play/level/PlayLevelView.coffee +++ b/app/views/play/level/PlayLevelView.coffee @@ -205,7 +205,7 @@ module.exports = class PlayLevelView extends RootView @session = @levelLoader.session @world = @levelLoader.world @level = @levelLoader.level - @$el.addClass 'hero' if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') + @$el.addClass 'hero' if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') # TODO: figure out what this does and comment it @$el.addClass 'flags' if _.any(@world.thangs, (t) -> (t.programmableProperties and 'findFlags' in t.programmableProperties) or t.inventory?.flag) or @level.get('slug') is 'sky-span' # TODO: Update terminology to always be opponentSession or otherSession # TODO: E.g. if it's always opponent right now, then variable names should be opponentSession until we have coop play @@ -468,7 +468,7 @@ module.exports = class PlayLevelView extends RootView return false if $.browser?.msie or $.browser?.msedge return false if $.browser.linux return false if me.level() < 8 - if @level.isType('course', 'game-dev') + if @level.isType('course', 'game-dev', 'web-dev') return false else if @level.isType('hero') and gamesSimulated return false if stillBuggy @@ -541,7 +541,7 @@ module.exports = class PlayLevelView extends RootView onDonePressed: -> @showVictory() onShowVictory: (e) -> - $('#level-done-button').show() unless @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') + $('#level-done-button').show() unless @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') @showVictory() if e.showModal return if @victorySeen @victorySeen = true @@ -559,7 +559,7 @@ module.exports = class PlayLevelView extends RootView return if @level.hasLocalChanges() # Don't award achievements when beating level changed in level editor @endHighlight() options = {level: @level, supermodel: @supermodel, session: @session, hasReceivedMemoryWarning: @hasReceivedMemoryWarning, courseID: @courseID, courseInstanceID: @courseInstanceID, world: @world} - ModalClass = if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') then HeroVictoryModal else VictoryModal + ModalClass = if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') then HeroVictoryModal else VictoryModal ModalClass = CourseVictoryModal if @isCourseMode() or me.isSessionless() ModalClass = PicoCTFVictoryModal if window.serverConfig.picoCTF victoryModal = new ModalClass(options) diff --git a/app/views/play/level/modal/HeroVictoryModal.coffee b/app/views/play/level/modal/HeroVictoryModal.coffee index 66eed4f9b..182a2ce4c 100644 --- a/app/views/play/level/modal/HeroVictoryModal.coffee +++ b/app/views/play/level/modal/HeroVictoryModal.coffee @@ -49,7 +49,7 @@ module.exports = class HeroVictoryModal extends ModalView @session = options.session @level = options.level @thangTypes = {} - if @level.isType('hero', 'hero-ladder', 'course', 'course-ladder', 'game-dev') + if @level.isType('hero', 'hero-ladder', 'course', 'course-ladder', 'game-dev', 'web-dev') achievements = new CocoCollection([], { url: "/db/achievement?related=#{@session.get('level').original}" model: Achievement @@ -63,7 +63,7 @@ module.exports = class HeroVictoryModal extends ModalView else @readyToContinue = true @playSound 'victory' - if @level.isType('course') + if @level.isType('course', 'game-dev', 'web-dev') if nextLevel = @level.get('nextLevel') @nextLevel = new Level().setURL "/db/level/#{nextLevel.original}/version/#{nextLevel.majorVersion}" @nextLevel = @supermodel.loadModel(@nextLevel).model @@ -73,7 +73,7 @@ module.exports = class HeroVictoryModal extends ModalView if @level.isType('course', 'course-ladder') @saveReviewEventually = _.debounce(@saveReviewEventually, 2000) @loadExistingFeedback() - # TODO: support game-dev + # TODO: support 'game-dev' and 'web-dev' (not the same as 'course' since can be played outside of courses) destroy: -> clearInterval @sequentialAnimationInterval @@ -154,8 +154,8 @@ module.exports = class HeroVictoryModal extends ModalView getRenderData: -> c = super() c.levelName = utils.i18n @level.attributes, 'name' - # TODO: support 'game-dev' - if @level.isType('hero', 'game-dev') + # TODO: support 'game-dev', 'web-dev' + if @level.isType('hero', 'game-dev', 'web-dev') c.victoryText = utils.i18n @level.get('victory') ? {}, 'body' earnedAchievementMap = _.indexBy(@newEarnedAchievements or [], (ea) -> ea.get('achievement')) for achievement in (@achievements?.models or []) @@ -223,7 +223,7 @@ module.exports = class HeroVictoryModal extends ModalView afterRender: -> super() - @$el.toggleClass 'with-achievements', @level.isType('hero', 'hero-ladder', 'game-dev') # TODO: support game-dev + @$el.toggleClass 'with-achievements', @level.isType('hero', 'hero-ladder', 'game-dev', 'web-dev') # TODO: support game-dev, web-dev return unless @supermodel.finished() @playSelectionSound hero, true for original, hero of @thangTypes # Preload them @updateSavingProgressStatus() @@ -233,7 +233,7 @@ module.exports = class HeroVictoryModal extends ModalView @insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view') initializeAnimations: -> - return @endSequentialAnimations() unless @level.isType('hero', 'hero-ladder', 'game-dev') # TODO: support game-dev + return @endSequentialAnimations() unless @level.isType('hero', 'hero-ladder', 'game-dev', 'web-dev') # TODO: support game-dev, web-dev @updateXPBars 0 #playVictorySound = => @playSound 'victory-title-appear' # TODO: actually add this @$el.find('#victory-header').delay(250).queue(-> @@ -264,7 +264,7 @@ module.exports = class HeroVictoryModal extends ModalView beginSequentialAnimations: -> return if @destroyed - return unless @level.isType('hero', 'hero-ladder', 'game-dev') # TODO: support game-dev + return unless @level.isType('hero', 'hero-ladder', 'game-dev', 'web-dev') # TODO: support game-dev, web-dev @sequentialAnimatedPanels = _.map(@animatedPanels.find('.reward-panel'), (panel) -> { number: $(panel).data('number') previousNumber: $(panel).data('previous-number') @@ -414,7 +414,7 @@ module.exports = class HeroVictoryModal extends ModalView {'kithgard-gates': 'forest', 'kithgard-mastery': 'forest', 'siege-of-stonehold': 'desert', 'clash-of-clones': 'mountain', 'summits-gate': 'glacier'}[@level.get('slug')] or @level.get 'campaign' # Much easier to just keep this updated than to dynamically figure it out. getNextLevelLink: (returnToCourse=false) -> - if @level.isType('course') and nextLevel = @level.get('nextLevel') and not returnToCourse + if @level.isType('course', 'game-dev', 'web-dev') and nextLevel = @level.get('nextLevel') and not returnToCourse # TODO: support game-dev and web-dev # need to do something more complicated to load its slug console.log 'have @nextLevel', @nextLevel, 'from nextLevel', nextLevel link = "/play/level/#{@nextLevel.get('slug')}" diff --git a/app/views/play/level/tome/SpellPaletteView.coffee b/app/views/play/level/tome/SpellPaletteView.coffee index 42954a37d..930f30faf 100644 --- a/app/views/play/level/tome/SpellPaletteView.coffee +++ b/app/views/play/level/tome/SpellPaletteView.coffee @@ -157,7 +157,7 @@ module.exports = class SpellPaletteView extends CocoView else propStorage = 'this': ['apiProperties', 'apiMethods'] - if not @options.level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') or not @options.programmable + if not @options.level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') or not @options.programmable @organizePalette propStorage, allDocs, excludedDocs else @organizePaletteHero propStorage, allDocs, excludedDocs @@ -199,7 +199,7 @@ module.exports = class SpellPaletteView extends CocoView if tabbify and _.find @entries, ((entry) -> entry.doc.owner isnt 'this') @entryGroups = _.groupBy @entries, groupForEntry else - i18nKey = if @options.level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') then 'play_level.tome_your_skills' else 'play_level.tome_available_spells' + i18nKey = if @options.level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') then 'play_level.tome_your_skills' else 'play_level.tome_available_spells' defaultGroup = $.i18n.t i18nKey @entryGroups = {} @entryGroups[defaultGroup] = @entries diff --git a/app/views/play/level/tome/TomeView.coffee b/app/views/play/level/tome/TomeView.coffee index 14c3057c0..0f5a23e17 100644 --- a/app/views/play/level/tome/TomeView.coffee +++ b/app/views/play/level/tome/TomeView.coffee @@ -60,7 +60,7 @@ module.exports = class TomeView extends CocoView @worker = @createWorker() programmableThangs = _.filter @options.thangs, (t) -> t.isProgrammable and t.programmableMethods @createSpells programmableThangs, programmableThangs[0]?.world # Do before spellList, thangList, and castButton - unless @options.level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') + unless @options.level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') @spellList = @insertSubView new SpellListView spells: @spells, supermodel: @supermodel, level: @options.level @castButton = @insertSubView new CastButtonView spells: @spells, level: @options.level, session: @options.session, god: @options.god @teamSpellMap = @generateTeamSpellMap(@spells) diff --git a/app/views/play/menu/GuideView.coffee b/app/views/play/menu/GuideView.coffee index fcd794117..e64c2c2a0 100644 --- a/app/views/play/menu/GuideView.coffee +++ b/app/views/play/menu/GuideView.coffee @@ -19,7 +19,7 @@ module.exports = class LevelGuideView extends CocoView @levelSlug = options.level.get('slug') @sessionID = options.session.get('_id') @requiresSubscription = not me.isPremium() - @isCourseLevel = options.level.isType('course', 'course-ladder') + @isCourseLevel = options.level.isType('course', 'course-ladder') # TODO: figure this out for game-dev, web-dev levels @helpVideos = if @isCourseLevel then [] else options.level.get('helpVideos') ? [] @trackedHelpVideoStart = @trackedHelpVideoFinish = false # A/B Testing video tutorial styles