diff --git a/app/models/LevelComponent.coffee b/app/models/LevelComponent.coffee
index 100ced453..a54f130a7 100644
--- a/app/models/LevelComponent.coffee
+++ b/app/models/LevelComponent.coffee
@@ -13,6 +13,7 @@ module.exports = class LevelComponent extends CocoModel
   @CollidesID: '524b7b857fc0f6d519000012'
   @PlansID: '524b7b517fc0f6d51900000d'
   @ProgrammableID: '524b7b5a7fc0f6d51900000e'
+  @MovesID: '524b7b8c7fc0f6d519000013'
   urlRoot: '/db/level.component'
 
   set: (key, val, options) ->
diff --git a/app/models/ThangType.coffee b/app/models/ThangType.coffee
index 407e2a68f..848c82f29 100644
--- a/app/models/ThangType.coffee
+++ b/app/models/ThangType.coffee
@@ -305,30 +305,34 @@ module.exports = class ThangType extends CocoModel
     ['Warrior', 'Ranger', 'Wizard']
 
   getHeroStats: ->
+    # Translate from raw hero properties into appropriate display values for the ChooseHeroView.
+    # Adapted from https://docs.google.com/a/codecombat.com/spreadsheets/d/1BGI1bzT4xHvWA81aeyIaCKWWw9zxn7-MwDdydmB5vw4/edit#gid=809922675
     return unless heroClass = @get('heroClass')
-    
-    return switch heroClass
-      when 'Warrior' then {
-        attack: 0.8
-        health: 0.85
-        speed: 0.6
-        skills: []
-      }
+    components = @get('components') or []
+    unless equipsConfig = _.find(components, original: LevelComponent.EquipsID)?.config
+      return console.warn @get('name'), 'is not an equipping hero, but you are asking for its hero stats. (Did you project away components?)'
+    unless movesConfig = _.find(components, original: LevelComponent.MovesID)?.config
+      return console.warn @get('name'), 'is not a moving hero, but you are asking for its hero stats.'
+    @classStatAverages ?=
+      attack: {Warrior: 7.5, Ranger: 5, Wizard: 2.5}
+      health: {Warrior: 7.5, Ranger: 5, Wizard: 3.5}
+    stats = {skills: []}  # TODO: find skills
+    rawNumbers = attack: equipsConfig.attackDamageFactor ? 1, health: equipsConfig.maxHealthFactor ? 1, speed: movesConfig.maxSpeed
+    for prop in ['attack', 'health']
+      stat = rawNumbers[prop]
+      if stat < 1
+        classSpecificScore = 10 - 5 / stat
+      else
+        classSpecificScore = stat * 5
+      classAverage = @classStatAverages[prop][@get('heroClass')]
+      stats[prop] = Math.round(2 * ((classAverage - 2.5) + classSpecificScore / 2)) / 2 / 10
+    minSpeed = 4
+    maxSpeed = 16
+    speedRange = maxSpeed - minSpeed
+    speedPoints = rawNumbers.speed - minSpeed
+    stats.speed = Math.round(20 * speedPoints / speedRange) / 2 / 10
+    stats
 
-      when 'Ranger' then {
-        attack: 0.6
-        health: 0.7
-        speed: 0.8
-        skills: []
-      }
-        
-      when 'Wizard' then {
-        attack: 0.5
-        health: 0.45
-        speed: 0.25
-        skills: []
-      }
-    
   getFrontFacingStats: ->
     components = @get('components') or []
     unless itemConfig = _.find(components, original: LevelComponent.ItemID)?.config
diff --git a/app/views/game-menu/ChooseHeroView.coffee b/app/views/game-menu/ChooseHeroView.coffee
index b322d3ed8..d88eff8e1 100644
--- a/app/views/game-menu/ChooseHeroView.coffee
+++ b/app/views/game-menu/ChooseHeroView.coffee
@@ -23,7 +23,7 @@ module.exports = class ChooseHeroView extends CocoView
   constructor: (options) ->
     super options
     @heroes = new CocoCollection([], {model: ThangType})
-    @heroes.url = '/db/thang.type?view=heroes&project=original,name,slug,soundTriggers,featureImage,gems,heroClass,description'
+    @heroes.url = '/db/thang.type?view=heroes&project=original,name,slug,soundTriggers,featureImage,gems,heroClass,description,components'
     @supermodel.loadCollection(@heroes, 'heroes')
     @stages = {}
 
diff --git a/app/views/play/WorldMapView.coffee b/app/views/play/WorldMapView.coffee
index 79d87188a..c26fd611f 100644
--- a/app/views/play/WorldMapView.coffee
+++ b/app/views/play/WorldMapView.coffee
@@ -86,6 +86,7 @@ module.exports = class WorldMapView extends RootView
       level.locked = index > 0 and not me.ownsLevel level.original
       window.levelUnlocksNotWorking = true if level.locked and level.id is @nextLevel  # Temporary
       level.locked = false if window.levelUnlocksNotWorking  # Temporary; also possible in HeroVictoryModal
+      level.locked = false if @levelStatusMap[level.id] in ['started', 'complete']
       level.color = 'rgb(255, 80, 60)'
       if level.practice
         level.color = 'rgb(80, 130, 200)' unless me.getBranchingGroup() is 'all-practice'