diff --git a/app/schemas/models/campaign.schema.coffee b/app/schemas/models/campaign.schema.coffee index 48b98075b..cbef4a7c4 100644 --- a/app/schemas/models/campaign.schema.coffee +++ b/app/schemas/models/campaign.schema.coffee @@ -116,6 +116,7 @@ _.extend CampaignSchema.properties, { }} campaign: c.shortString title: 'Campaign', description: 'Which campaign this level is part of (like "desert").', format: 'hidden' # Automatically set by campaign editor. + campaignIndex: c.int title: 'Campaign Index', description: 'The 0-based index of this level in its campaign.', format: 'hidden' # Automatically set by campaign editor. tasks: c.array {title: 'Tasks', description: 'Tasks to be completed for this level.'}, c.task concepts: c.array {title: 'Programming Concepts', description: 'Which programming concepts this level covers.'}, c.concept diff --git a/app/schemas/models/level.coffee b/app/schemas/models/level.coffee index c13b35df4..f0cfd1cfe 100644 --- a/app/schemas/models/level.coffee +++ b/app/schemas/models/level.coffee @@ -344,6 +344,7 @@ _.extend LevelSchema.properties, type: 'string', links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], format: 'latest-version-original-reference' }} campaign: c.shortString title: 'Campaign', description: 'Which campaign this level is part of (like "desert").', format: 'hidden' # Automatically set by campaign editor. + campaignIndex: c.int title: 'Campaign Index', description: 'The 0-based index of this level in its campaign.', format: 'hidden' # Automatically set by campaign editor. scoreTypes: c.array {title: 'Score Types', description: 'What metric to show leaderboards for.', uniqueItems: true}, c.shortString(title: 'Score Type', 'enum': ['time', 'damage-taken', 'damage-dealt', 'gold-collected', 'difficulty']) # TODO: good version of LoC; total gear value. concepts: c.array {title: 'Programming Concepts', description: 'Which programming concepts this level covers.', uniqueItems: true}, c.concept diff --git a/app/templates/courses/course-details.jade b/app/templates/courses/course-details.jade index 506664867..6a15383ba 100644 --- a/app/templates/courses/course-details.jade +++ b/app/templates/courses/course-details.jade @@ -269,6 +269,7 @@ mixin levels-tab tbody if campaign - var lastLevelCompleted = true; + - var levelCount = 0; each level, levelID in campaign.get('levels') tr td @@ -281,7 +282,7 @@ mixin levels-tab - lastLevelCompleted = userLevelStateMap[me.id][levelID] === 'complete' else - lastLevelCompleted = false - td= level.name.replace('Course: ', '') + td= ++levelCount + '. ' + level.name.replace('Course: ', '') td if levelConceptMap[levelID] each concept in course.get('concepts') diff --git a/app/templates/play/level/control_bar.jade b/app/templates/play/level/control_bar.jade index 6d1fc6fec..bf919707a 100644 --- a/app/templates/play/level/control_bar.jade +++ b/app/templates/play/level/control_bar.jade @@ -22,7 +22,7 @@ else .level-name-area .level-label(data-i18n="play_level.level") .level-name(title=difficultyTitle || "") - span= worldName.replace('Course: ', '') + span= (campaignIndex ? (campaignIndex + 1) + '. ' : '') + worldName.replace('Course: ', '') if levelDifficulty sup.level-difficulty= levelDifficulty diff --git a/app/views/editor/campaign/CampaignEditorView.coffee b/app/views/editor/campaign/CampaignEditorView.coffee index 5eef637c9..9e1f15122 100644 --- a/app/views/editor/campaign/CampaignEditorView.coffee +++ b/app/views/editor/campaign/CampaignEditorView.coffee @@ -92,7 +92,7 @@ module.exports = class CampaignEditorView extends RootView onLoaded: -> @toSave.add @campaign if @campaign.hasLocalChanges() campaignLevels = $.extend({}, @campaign.get('levels')) - for level in @levels.models + for level, levelIndex in @levels.models levelOriginal = level.get('original') campaignLevel = campaignLevels[levelOriginal] continue if not campaignLevel @@ -129,6 +129,8 @@ module.exports = class CampaignEditorView extends RootView delete campaignLevel.unlocks # Save campaign to level, unless it's a course campaign, since we reuse hero levels for course levels. campaignLevel.campaign = @campaign.get 'slug' if @campaign.get('type', true) isnt 'course' + # Save campaign index to level if it's a course campaign, since we show linear level order numbers for course levels. + campaignLevel.campaignIndex = (@levels.models.length - levelIndex - 1) if @campaign.get('type', true) is 'course' campaignLevels[levelOriginal] = campaignLevel @campaign.set('levels', campaignLevels) diff --git a/app/views/play/level/ControlBarView.coffee b/app/views/play/level/ControlBarView.coffee index 10e9f2e41..9c8a14981 100644 --- a/app/views/play/level/ControlBarView.coffee +++ b/app/views/play/level/ControlBarView.coffee @@ -61,6 +61,7 @@ module.exports = class ControlBarView extends CocoView getRenderData: (c={}) -> super c c.worldName = @worldName + c.campaignIndex = @level.get('campaignIndex') if @level.get('type') is 'course' c.multiplayerEnabled = @session.get('multiplayer') c.ladderGame = @level.get('type') in ['ladder', 'hero-ladder', 'course-ladder'] if c.isMultiplayerLevel = @isMultiplayerLevel diff --git a/server/levels/level_handler.coffee b/server/levels/level_handler.coffee index 049c575e8..75e2e8b84 100644 --- a/server/levels/level_handler.coffee +++ b/server/levels/level_handler.coffee @@ -61,6 +61,7 @@ LevelHandler = class LevelHandler extends Handler 'tasks' 'helpVideos' 'campaign' + 'campaignIndex' 'replayable' 'buildTime' 'scoreTypes'