2014-11-28 20:49:41 -05:00
RootView = require ' views/core/RootView '
2014-09-17 21:56:08 -04:00
template = require ' templates/play/world-map-view '
LevelSession = require ' models/LevelSession '
2014-11-21 02:03:16 -05:00
EarnedAchievement = require ' models/EarnedAchievement '
2014-09-17 21:56:08 -04:00
CocoCollection = require ' collections/CocoCollection '
AudioPlayer = require ' lib/AudioPlayer '
2014-11-06 19:23:23 -05:00
LevelSetupManager = require ' lib/LevelSetupManager '
2014-10-02 01:02:52 -04:00
ThangType = require ' models/ThangType '
2014-10-15 13:28:29 -04:00
MusicPlayer = require ' lib/surface/MusicPlayer '
2014-11-28 20:49:41 -05:00
storage = require ' core/storage '
2014-11-29 11:54:08 -05:00
AuthModal = require ' views/core/AuthModal '
2014-12-18 23:34:59 -05:00
SubscribeModal = require ' views/core/SubscribeModal '
2014-12-07 17:57:23 -05:00
Level = require ' models/Level '
2014-09-17 21:56:08 -04:00
2014-11-27 12:44:08 -05:00
trackedHourOfCode = false
2014-09-17 21:56:08 -04:00
class LevelSessionsCollection extends CocoCollection
url: ' '
model: LevelSession
constructor: (model) ->
super ( )
@url = " /db/user/ #{ me . id } /level.sessions?project=state.complete,levelID "
2014-09-18 21:25:33 -04:00
module.exports = class WorldMapView extends RootView
2014-09-17 21:56:08 -04:00
id: ' world-map-view '
template: template
2014-12-03 14:19:10 -05:00
subscriptions:
' subscribe-modal:subscribed ' : ' onSubscribed '
2014-09-17 21:56:08 -04:00
events:
2014-09-23 22:12:05 -04:00
' click .map-background ' : ' onClickMap '
2014-09-19 14:03:38 -04:00
' click .level a ' : ' onClickLevel '
2014-09-23 22:12:05 -04:00
' click .level-info-container .start-level ' : ' onClickStartLevel '
2014-09-24 18:21:39 -04:00
' mouseenter .level a ' : ' onMouseEnterLevel '
' mouseleave .level a ' : ' onMouseLeaveLevel '
' mousemove .map ' : ' onMouseMoveMap '
2014-10-06 13:17:40 -04:00
' click # volume-button ' : ' onToggleVolume '
2014-09-17 21:56:08 -04:00
2014-10-29 12:47:00 -04:00
constructor: (options, @terrain) ->
2014-11-18 14:21:29 -05:00
if options and application . isIPAdApp # TODO: later only clear the SuperModel if it has received a memory warning (not in app store yet)
options.supermodel = null
2014-12-10 13:00:52 -05:00
@ terrain ? = ' dungeon ' # or 'forest', 'desert'
2014-09-17 21:56:08 -04:00
super options
2014-10-22 18:42:51 -04:00
@nextLevel = @ getQueryVariable ' next '
2014-09-17 21:56:08 -04:00
@levelStatusMap = { }
@levelPlayCountMap = { }
@sessions = @ supermodel . loadCollection ( new LevelSessionsCollection ( ) , ' your_sessions ' , null , 0 ) . model
2014-11-21 14:56:31 -05:00
2014-11-21 02:03:16 -05:00
# Temporary attempt to make sure all earned rewards are accounted for. Figure out a better solution...
@earnedAchievements = new CocoCollection ( [ ] , { url: ' /db/earned_achievement ' , model : EarnedAchievement , project: [ ' earnedRewards ' ] } )
@ listenToOnce @ earnedAchievements , ' sync ' , ->
earned = me . get ( ' earned ' )
addedSomething = false
for m in @ earnedAchievements . models
continue unless loadedEarned = m . get ( ' earnedRewards ' )
for group in [ ' heroes ' , ' levels ' , ' items ' ]
continue unless loadedEarned [ group ]
for reward in loadedEarned [ group ]
if reward not in earned [ group ]
console . warn ' Filling in a gap for reward ' , group , reward
earned [ group ] . push ( reward )
addedSomething = true
@ supermodel . loadCollection ( @ earnedAchievements , ' achievements ' )
2014-11-21 14:56:31 -05:00
2014-09-17 21:56:08 -04:00
@ listenToOnce @ sessions , ' sync ' , @ onSessionsLoaded
@ getLevelPlayCounts ( )
$ ( window ) . on ' resize ' , @ onWindowResize
2014-09-25 14:37:29 -04:00
@ playAmbientSound ( )
2014-11-30 17:57:34 -05:00
@probablyCachedMusic = storage . load ( " loaded-menu-music " )
2014-10-15 13:28:29 -04:00
musicDelay = if @ probablyCachedMusic then 1000 else 10000
@playMusicTimeout = _ . delay ( => @ playMusic ( ) unless @ destroyed ) , musicDelay
2014-10-02 14:18:43 -04:00
@hadEverChosenHero = me . get ( ' heroConfig ' ) ? . thangType
2014-11-12 13:22:56 -05:00
@ listenTo me , ' change:purchased ' , -> @ renderSelectors ( ' # gems-count ' )
@ listenTo me , ' change:spent ' , -> @ renderSelectors ( ' # gems-count ' )
2014-12-07 19:55:08 -05:00
@ listenTo me , ' change:heroConfig ' , -> @ updateHero ( )
2014-12-02 12:13:39 -05:00
window . tracker ? . trackEvent ' Loaded World Map ' , category: ' World Map ' , [ ' Google Analytics ' ]
2014-09-17 21:56:08 -04:00
2014-11-27 12:44:08 -05:00
# If it's a new player who didn't appear to come from Hour of Code, we register her here without setting the hourOfCode property.
elapsed = ( new Date ( ) - new Date ( me . get ( ' dateCreated ' ) ) )
if not trackedHourOfCode and not me . get ( ' hourOfCode ' ) and elapsed < 5 * 60 * 1000
$ ( ' body ' ) . append ( $ ( ' <img src= " http://code.org/api/hour/begin_codecombat.png " style= " visibility: hidden; " > ' ) )
trackedHourOfCode = true
2014-12-05 21:16:58 -05:00
@requiresSubscription = not me . isPremium ( )
2014-12-02 23:01:53 -05:00
2014-09-18 21:25:33 -04:00
destroy: ->
2014-11-09 19:19:18 -05:00
@ setupManager ? . destroy ( )
2014-12-08 14:09:04 -05:00
@ $el . find ( ' .ui-draggable ' ) . draggable ' destroy '
2014-09-18 21:25:33 -04:00
$ ( window ) . off ' resize ' , @ onWindowResize
2014-09-25 14:37:29 -04:00
if ambientSound = @ ambientSound
# Doesn't seem to work; stops immediately.
createjs . Tween . get ( ambientSound ) . to ( { volume: 0.0 } , 1500 ) . call -> ambientSound . stop ( )
2014-10-15 13:28:29 -04:00
@ musicPlayer ? . destroy ( )
clearTimeout @ playMusicTimeout
2014-09-18 21:25:33 -04:00
super ( )
2014-09-17 21:56:08 -04:00
getLevelPlayCounts: ->
2014-10-14 12:54:18 -04:00
return unless me . isAdmin ( )
2014-09-17 21:56:08 -04:00
success = (levelPlayCounts) =>
return if @ destroyed
for level in levelPlayCounts
@ levelPlayCountMap [ level . _id ] = playtime: level . playtime , sessions: level . sessions
2014-11-30 16:23:08 -05:00
@ render ( ) if @ fullyRendered
2014-09-17 21:56:08 -04:00
levelIDs = [ ]
for campaign in campaigns
for level in campaign . levels
levelIDs . push level . id
levelPlayCountsRequest = @ supermodel . addRequestResource ' play_counts ' , {
url: ' /db/level/-/play_counts '
data: { ids: levelIDs }
method: ' POST '
success: success
} , 0
levelPlayCountsRequest . load ( )
2014-11-30 16:23:08 -05:00
onLoaded: ->
return if @ fullyRendered
@fullyRendered = true
@ render ( )
@ preloadTopHeroes ( ) unless me . get ( ' heroConfig ' ) ? . thangType
2014-12-03 14:19:10 -05:00
onSubscribed: ->
@requiresSubscription = false
@ render ( )
2014-09-17 21:56:08 -04:00
getRenderData: (context={}) ->
context = super ( context )
2014-10-29 12:47:00 -04:00
context.campaign = _ . find campaigns , { id: @ terrain }
2014-12-07 17:57:23 -05:00
for level in context . campaign . levels
2014-10-29 12:47:00 -04:00
level . x ? = 10 + 80 * Math . random ( )
level . y ? = 10 + 80 * Math . random ( )
2014-12-07 17:57:23 -05:00
level.locked = not me . ownsLevel level . original
2014-11-21 00:57:47 -05:00
window . levelUnlocksNotWorking = true if level . locked and level . id is @ nextLevel # Temporary
2014-10-29 12:47:00 -04:00
level.locked = false if window . levelUnlocksNotWorking # Temporary; also possible in HeroVictoryModal
2014-11-05 16:28:54 -05:00
level.locked = false if @ levelStatusMap [ level . id ] in [ ' started ' , ' complete ' ]
2014-11-21 23:36:56 -05:00
level.locked = false if me . get ( ' slug ' ) is ' nick '
2014-11-06 21:18:57 -05:00
level.disabled = false if @ levelStatusMap [ level . id ] in [ ' started ' , ' complete ' ]
2014-10-29 12:47:00 -04:00
level.color = ' rgb(255, 80, 60) '
2014-12-05 18:44:49 -05:00
if level . requiresSubscription
level.color = ' rgb(80, 130, 200) '
2014-12-10 13:44:25 -05:00
if level . unlocksHero
level.color = ' rgb(0,0,0) '
level.unlockedHero = level . unlocksHero . originalID in ( me . get ( ' earned ' ) ? . heroes or [ ] )
2014-12-07 16:28:32 -05:00
level.hidden = level . locked or level . disabled
2014-12-07 17:57:23 -05:00
2014-12-07 18:51:32 -05:00
## put lower levels in last, so in the world map they layer over one another properly.
#context.campaign.levels = (_.sortBy context.campaign.levels, 'y').reverse()
# Actually, there's some logic that depends on the order of iteration of levels to determine
# which one to do next when you're coming here not from a level; can we do this another way?
2014-12-07 17:57:23 -05:00
2014-09-17 21:56:08 -04:00
context.levelStatusMap = @ levelStatusMap
context.levelPlayCountMap = @ levelPlayCountMap
2014-09-24 18:21:39 -04:00
context.isIPadApp = application . isIPadApp
2014-10-02 17:05:18 -04:00
context.mapType = _ . string . slugify @ terrain
2014-10-22 18:42:51 -04:00
context.nextLevel = @ nextLevel
2014-12-07 17:57:23 -05:00
context.forestIsAvailable = @ startedForestLevel or ( Level . levels [ ' defense-of-plainswood ' ] in ( me . get ( ' earned ' ) ? . levels or [ ] ) )
2014-12-10 13:00:52 -05:00
context.desertIsAvailable = @ startedDesertLevel or ( Level . levels [ ' the-mighty-sand-yak ' ] in ( me . get ( ' earned ' ) ? . levels or [ ] ) )
2014-12-03 14:19:10 -05:00
context.requiresSubscription = @ requiresSubscription
2014-09-17 21:56:08 -04:00
context
afterRender: ->
super ( )
@ onWindowResize ( )
2014-09-24 18:21:39 -04:00
unless application . isIPadApp
2014-10-29 13:47:17 -04:00
_ . defer => @ $el ? . find ( ' .game-controls .btn ' ) . tooltip ( ) # Have to defer or i18n doesn't take effect.
2014-12-05 18:44:49 -05:00
@ $el . find ( ' .level ' ) . tooltip ( ) . each ->
return unless me . isAdmin ( )
$ ( @ ) . draggable ( ) . on ' dragstop ' , ->
bg = $ ( ' .map-background ' )
x = ( $ ( @ ) . offset ( ) . left - bg . offset ( ) . left + $ ( @ ) . outerWidth ( ) / 2 ) / bg . width ( )
y = 1 - ( $ ( @ ) . offset ( ) . top - bg . offset ( ) . top + $ ( @ ) . outerHeight ( ) / 2 ) / bg . height ( )
console . log " #{ $ ( @ ) . data ( ' level-id ' ) } \n x: #{ ( 100 * x ) . toFixed ( 2 ) } \n y: #{ ( 100 * y ) . toFixed ( 2 ) } \n "
2014-10-02 17:05:18 -04:00
@ $el . addClass _ . string . slugify @ terrain
2014-10-06 13:17:40 -04:00
@ updateVolume ( )
2014-12-07 19:55:08 -05:00
@ updateHero ( )
2014-12-05 18:44:49 -05:00
unless window . currentModal or not @ fullyRendered
2014-11-10 00:33:47 -05:00
@ highlightElement ' .level.next ' , delay: 500 , duration: 60000 , rotation: 0 , sides: [ ' top ' ]
2014-11-10 11:21:28 -05:00
if levelID = @ $el . find ( ' .level.next ' ) . data ( ' level-id ' )
@$levelInfo = @ $el . find ( " .level-info-container[data-level-id= #{ levelID } ] " ) . show ( )
pos = @ $el . find ( ' .level.next ' ) . offset ( )
2014-11-21 14:56:31 -05:00
@ adjustLevelInfoPosition pageX: pos . left , pageY: pos . top
2014-11-10 11:21:28 -05:00
@manuallyPositionedLevelInfoID = levelID
2014-09-17 21:56:08 -04:00
2014-11-02 21:36:43 -05:00
afterInsert: ->
super ( )
return unless @ getQueryVariable ' signup '
return if me . get ( ' email ' )
@ endHighlight ( )
authModal = new AuthModal supermodel: @ supermodel
authModal.mode = ' signup '
@ openModalView authModal
2014-09-17 21:56:08 -04:00
onSessionsLoaded: (e) ->
2014-11-19 13:05:02 -05:00
forestLevels = ( f . id for f in forest )
2014-12-10 13:00:52 -05:00
desertLevels = ( f . id for f in desert )
2014-09-17 21:56:08 -04:00
for session in @ sessions . models
@ levelStatusMap [ session . get ( ' levelID ' ) ] = if session . get ( ' state ' ) ? . complete then ' complete ' else ' started '
2014-11-19 13:05:02 -05:00
@startedForestLevel = true if session . get ( ' levelID ' ) in forestLevels
2014-12-10 13:00:52 -05:00
@startedDesertLevel = true if session . get ( ' levelID ' ) in desertLevels
2014-11-10 11:21:28 -05:00
if @ nextLevel and @ levelStatusMap [ @ nextLevel ] is ' complete '
@nextLevel = null
2014-09-17 21:56:08 -04:00
@ render ( )
onClickMap: (e) ->
2014-09-23 22:12:05 -04:00
@ $levelInfo ? . hide ( )
2014-09-17 21:56:08 -04:00
# Easy-ish way of figuring out coordinates for placing level dots.
x = e . offsetX / @ $el . find ( ' .map-background ' ) . width ( )
y = ( 1 - e . offsetY / @ $el . find ( ' .map-background ' ) . height ( ) )
console . log " x: #{ ( 100 * x ) . toFixed ( 2 ) } \n y: #{ ( 100 * y ) . toFixed ( 2 ) } \n "
2014-09-19 14:03:38 -04:00
onClickLevel: (e) ->
2014-09-20 01:15:58 -04:00
e . preventDefault ( )
2014-09-23 22:12:05 -04:00
e . stopPropagation ( )
@ $levelInfo ? . hide ( )
2014-12-02 23:01:53 -05:00
levelElement = $ ( e . target ) . parents ( ' .level ' )
levelID = levelElement . data ( ' level-id ' )
campaign = _ . find campaigns , id: @ terrain
level = _ . find campaign . levels , id: levelID
2014-09-24 18:21:39 -04:00
if application . isIPadApp
@$levelInfo = @ $el . find ( " .level-info-container[data-level-id= #{ levelID } ] " ) . show ( )
@ adjustLevelInfoPosition e
2014-10-24 16:03:10 -04:00
@ endHighlight ( )
2014-09-24 18:21:39 -04:00
else
2014-12-05 18:44:49 -05:00
if level . requiresSubscription and @ requiresSubscription and not @ levelStatusMap [ level . id ] and not level . adventurer
2014-12-06 12:35:13 -05:00
@ openModalView new SubscribeModal ( )
2014-12-08 01:44:20 -05:00
window . tracker ? . trackEvent ' Show subscription modal ' , category: ' Subscription ' , label: ' map level clicked ' , level: levelID
2014-12-02 23:01:53 -05:00
else if $ ( e . target ) . attr ( ' disabled ' )
2014-11-10 00:27:03 -05:00
Backbone . Mediator . publish ' router:navigate ' , route: ' /contribute/adventurer '
return
else if $ ( e . target ) . parent ( ) . hasClass ' locked '
return
else
@ startLevel levelElement
2014-11-28 15:05:34 -05:00
window . tracker ? . trackEvent ' Clicked Level ' , category: ' World Map ' , levelID: levelID , [ ' Google Analytics ' ]
2014-09-17 21:56:08 -04:00
2014-09-23 22:12:05 -04:00
onClickStartLevel: (e) ->
2014-11-10 00:27:03 -05:00
levelElement = $ ( e . target ) . parents ( ' .level-info-container ' )
@ startLevel levelElement
2014-11-28 15:05:34 -05:00
window . tracker ? . trackEvent ' Clicked Start Level ' , category: ' World Map ' , levelID: levelElement . data ( ' level-id ' ) , [ ' Google Analytics ' ]
2014-09-24 18:21:39 -04:00
startLevel: (levelElement) ->
2014-11-09 19:19:18 -05:00
@ setupManager ? . destroy ( )
@setupManager = new LevelSetupManager supermodel: @ supermodel , levelID: levelElement . data ( ' level-id ' ) , levelPath: levelElement . data ( ' level-path ' ) , levelName: levelElement . data ( ' level-name ' ) , hadEverChosenHero: @ hadEverChosenHero , parent: @
@ setupManager . open ( )
2014-09-23 22:12:05 -04:00
@ $levelInfo ? . hide ( )
2014-09-17 21:56:08 -04:00
2014-09-24 18:21:39 -04:00
onMouseEnterLevel: (e) ->
return if application . isIPadApp
levelID = $ ( e . target ) . parents ( ' .level ' ) . data ( ' level-id ' )
2014-11-10 11:21:28 -05:00
return if @ manuallyPositionedLevelInfoID and levelID isnt @ manuallyPositionedLevelInfoID
2014-09-24 18:21:39 -04:00
@$levelInfo = @ $el . find ( " .level-info-container[data-level-id= #{ levelID } ] " ) . show ( )
@ adjustLevelInfoPosition e
2014-10-15 13:33:33 -04:00
@ endHighlight ( )
2014-11-21 14:56:31 -05:00
@manuallyPositionedLevelInfoID = false
2014-09-24 18:21:39 -04:00
onMouseLeaveLevel: (e) ->
return if application . isIPadApp
levelID = $ ( e . target ) . parents ( ' .level ' ) . data ( ' level-id ' )
2014-11-10 11:21:28 -05:00
return if @ manuallyPositionedLevelInfoID and levelID isnt @ manuallyPositionedLevelInfoID
2014-09-24 18:21:39 -04:00
@ $el . find ( " .level-info-container[data-level-id= ' #{ levelID } ' ] " ) . hide ( )
2014-11-10 11:21:28 -05:00
@manuallyPositionedLevelInfoID = null
2014-11-29 18:06:54 -05:00
@$levelInfo = null
2014-09-24 18:21:39 -04:00
onMouseMoveMap: (e) ->
return if application . isIPadApp
2014-11-10 11:21:28 -05:00
@ adjustLevelInfoPosition e unless @ manuallyPositionedLevelInfoID
2014-09-17 21:56:08 -04:00
adjustLevelInfoPosition: (e) ->
return unless @ $levelInfo
@ $map ? = @ $el . find ( ' .map ' )
mapOffset = @ $map . offset ( )
mapX = e . pageX - mapOffset . left
mapY = e . pageY - mapOffset . top
margin = 20
width = @ $levelInfo . outerWidth ( )
@ $levelInfo . css ( ' left ' , Math . min ( Math . max ( margin , mapX - width / 2 ) , @ $map . width ( ) - width - margin ) )
height = @ $levelInfo . outerHeight ( )
top = mapY - @ $levelInfo . outerHeight ( ) - 60
if top < 20
top = mapY + 60
@ $levelInfo . css ( ' top ' , top )
onWindowResize: (e) =>
2014-10-02 17:05:18 -04:00
mapHeight = iPadHeight = 1536
2014-12-10 13:00:52 -05:00
mapWidth = { dungeon: 2350 , forest: 2500 , desert: 2350 } [ @ terrain ] or 2350
2014-10-01 21:17:21 -04:00
aspectRatio = mapWidth / mapHeight
2014-09-17 21:56:08 -04:00
pageWidth = $ ( window ) . width ( )
pageHeight = $ ( window ) . height ( )
2014-10-01 21:17:21 -04:00
widthRatio = pageWidth / mapWidth
heightRatio = pageHeight / mapHeight
2014-11-30 17:35:13 -05:00
# Make sure we can see the whole map, fading to background in one dimension.
if heightRatio <= widthRatio
# Left and right margin
resultingHeight = pageHeight
resultingWidth = resultingHeight * aspectRatio
2014-09-17 21:56:08 -04:00
else
2014-11-30 17:35:13 -05:00
# Top and bottom margin
resultingWidth = pageWidth
resultingHeight = resultingWidth / aspectRatio
2014-09-17 21:56:08 -04:00
resultingMarginX = ( pageWidth - resultingWidth ) / 2
resultingMarginY = ( pageHeight - resultingHeight ) / 2
@ $el . find ( ' .map ' ) . css ( width: resultingWidth , height: resultingHeight , ' margin-left ' : resultingMarginX , ' margin-top ' : resultingMarginY )
2014-09-25 14:37:29 -04:00
playAmbientSound: ->
return if @ ambientSound
2014-12-10 13:00:52 -05:00
return unless file = { dungeon: ' ambient-dungeon ' , forest: ' ambient-map-grass ' , desert: ' ambient-desert ' } [ @ terrain ]
2014-09-25 14:37:29 -04:00
src = " /file/interface/ #{ file } #{ AudioPlayer . ext } "
unless AudioPlayer . getStatus ( src ) ? . loaded
AudioPlayer . preloadSound src
Backbone . Mediator . subscribeOnce ' audio-player:loaded ' , @ playAmbientSound , @
return
@ambientSound = createjs . Sound . play src , loop : - 1 , volume: 0.1
2014-12-06 23:06:14 -05:00
createjs . Tween . get ( @ ambientSound ) . to ( { volume: 0.5 } , 1000 )
2014-09-25 14:37:29 -04:00
2014-10-15 13:28:29 -04:00
playMusic: ->
@musicPlayer = new MusicPlayer ( )
2014-11-30 17:57:34 -05:00
musicFile = ' /music/music-menu '
2014-10-15 13:28:29 -04:00
Backbone . Mediator . publish ' music-player:play-music ' , play: true , file: musicFile
2014-11-30 17:57:34 -05:00
storage . save ( " loaded-menu-music " , true ) unless @ probablyCachedMusic
2014-10-15 13:28:29 -04:00
2014-10-02 01:02:52 -04:00
preloadTopHeroes: ->
for heroID in [ ' captain ' , ' knight ' ]
url = " /db/thang.type/ #{ ThangType . heroes [ heroID ] } /version "
continue if @ supermodel . getModel url
fullHero = new ThangType ( )
fullHero . setURL url
@ supermodel . loadModel fullHero , ' thang '
2014-10-06 13:17:40 -04:00
updateVolume: (volume) ->
volume ? = me . get ( ' volume ' ) ? 1.0
classes = [ ' vol-off ' , ' vol-down ' , ' vol-up ' ]
button = $ ( ' # volume-button ' , @ $el )
button . toggleClass ' vol-off ' , volume <= 0.0
button . toggleClass ' vol-down ' , 0.0 < volume < 1.0
button . toggleClass ' vol-up ' , volume >= 1.0
createjs . Sound . setVolume ( if volume is 1 then 0.6 else volume ) # Quieter for now until individual sound FX controls work again.
if volume isnt me . get ' volume '
me . set ' volume ' , volume
me . patch ( )
onToggleVolume: (e) ->
button = $ ( e . target ) . closest ( ' # volume-button ' )
classes = [ ' vol-off ' , ' vol-down ' , ' vol-up ' ]
volumes = [ 0 , 0.4 , 1.0 ]
for oldClass , i in classes
if button . hasClass oldClass
newI = ( i + 1 ) % classes . length
break
else if i is classes . length - 1 # no oldClass
newI = 2
@ updateVolume volumes [ newI ]
2014-12-07 19:55:08 -05:00
updateHero: ->
return unless hero = me . get ( ' heroConfig ' ) ? . thangType
for slug , original of ThangType . heroes when original is hero
@ $el . find ( ' .player-hero-icon ' ) . removeClass ( ) . addClass ( ' player-hero-icon ' + slug )
return
console . error " WorldMapView hero update couldn ' t find hero slug for original: " , hero
2014-09-25 14:37:29 -04:00
2014-10-29 12:47:00 -04:00
dungeon = [
2014-09-19 14:03:38 -04:00
{
name: ' Dungeons of Kithgard '
type: ' hero '
id: ' dungeons-of-kithgard '
2014-12-07 17:57:23 -05:00
original: ' 5411cb3769152f1707be029c '
2014-09-19 14:03:38 -04:00
description: ' Grab the gem, but touch nothing else. Start here. '
2014-10-02 17:36:26 -04:00
x: 14
y: 15.5
2014-10-22 18:42:51 -04:00
nextLevels:
continue : ' gems-in-the-deep '
2014-09-19 14:03:38 -04:00
}
{
name: ' Gems in the Deep '
type: ' hero '
id: ' gems-in-the-deep '
2014-09-26 05:28:54 -04:00
original: ' 54173c90844506ae0195a0b4 '
2014-09-19 14:03:38 -04:00
description: ' Quickly collect the gems; you will need them. '
2014-10-30 22:58:11 -04:00
x: 29
y: 12
2014-10-22 18:42:51 -04:00
nextLevels:
continue : ' shadow-guard '
2014-09-19 14:03:38 -04:00
}
{
name: ' Shadow Guard '
type: ' hero '
id: ' shadow-guard '
2014-09-26 05:28:54 -04:00
original: ' 54174347844506ae0195a0b8 '
2014-09-19 14:03:38 -04:00
description: ' Evade the Kithgard minion. '
2014-12-05 18:44:49 -05:00
x: 40.54
y: 11.03
2014-10-22 18:42:51 -04:00
nextLevels:
2014-11-05 13:40:37 -05:00
continue : ' forgetful-gemsmith '
2014-10-22 18:42:51 -04:00
}
{
2014-10-30 22:14:40 -04:00
name: ' Kounter Kithwise '
2014-10-22 18:42:51 -04:00
type: ' hero '
2014-10-30 22:14:40 -04:00
id: ' kounter-kithwise '
original: ' 54527a6257e83800009730c7 '
2014-10-22 18:42:51 -04:00
description: ' Practice your evasion skills with more guards. '
2014-12-05 18:44:49 -05:00
x: 35.37
y: 20.61
nextLevels:
continue : ' crawlways-of-kithgard '
practice: true
requiresSubscription: true
}
{
name: ' Crawlways of Kithgard '
type: ' hero '
id: ' crawlways-of-kithgard '
original: ' 545287ef57e83800009730d5 '
description: ' Dart in and grab the gem– at the right moment. '
x: 36.48
y: 29.03
2014-10-30 22:14:40 -04:00
nextLevels:
2014-11-13 13:49:37 -05:00
continue : ' forgetful-gemsmith '
2014-10-30 22:14:40 -04:00
practice: true
2014-12-05 18:44:49 -05:00
requiresSubscription: true
2014-10-30 22:14:40 -04:00
}
{
2014-11-05 13:40:37 -05:00
name: ' Forgetful Gemsmith '
2014-10-30 22:14:40 -04:00
type: ' hero '
2014-11-05 13:40:37 -05:00
id: ' forgetful-gemsmith '
original: ' 544a98f62d002f0000fe331a '
description: ' Grab even more gems as you practice moving. '
2014-12-05 18:44:49 -05:00
x: 54.98
y: 10.53
2014-10-22 18:42:51 -04:00
nextLevels:
2014-11-13 13:49:37 -05:00
continue : ' true-names '
2014-09-19 14:03:38 -04:00
}
{
name: ' True Names '
type: ' hero '
id: ' true-names '
2014-09-26 05:28:54 -04:00
original: ' 541875da4c16460000ab990f '
2014-09-19 14:03:38 -04:00
description: ' Learn an enemy \' s true name to defeat it. '
2014-12-05 18:44:49 -05:00
x: 68.44
y: 10.70
2014-10-22 18:42:51 -04:00
nextLevels:
continue : ' the-raised-sword '
2014-12-10 13:44:25 -05:00
unlocksHero: {
img: ' /file/db/thang.type/53e12be0d042f23505c3023b/portrait.png '
originalID: ' 53e12be0d042f23505c3023b '
}
2014-10-22 18:42:51 -04:00
}
{
2014-10-30 22:14:40 -04:00
name: ' Favorable Odds '
2014-10-22 18:42:51 -04:00
type: ' hero '
2014-10-30 22:14:40 -04:00
id: ' favorable-odds '
original: ' 5452972f57e83800009730de '
2014-10-22 18:42:51 -04:00
description: ' Test out your battle skills by defeating more munchkins. '
2014-12-05 18:44:49 -05:00
x: 88.25
y: 14.92
2014-10-22 18:42:51 -04:00
nextLevels:
continue : ' the-raised-sword '
practice: true
2014-12-05 18:44:49 -05:00
requiresSubscription: true
2014-09-19 14:03:38 -04:00
}
{
name: ' The Raised Sword '
type: ' hero '
id: ' the-raised-sword '
2014-09-26 05:28:54 -04:00
original: ' 5418aec24c16460000ab9aa6 '
2014-09-19 14:03:38 -04:00
description: ' Learn to equip yourself for combat. '
2014-12-05 18:44:49 -05:00
x: 81.51
y: 17.92
2014-10-22 18:42:51 -04:00
nextLevels:
2014-11-21 00:57:47 -05:00
continue : ' haunted-kithmaze '
2014-11-05 13:40:37 -05:00
}
{
name: ' Haunted Kithmaze '
type: ' hero '
id: ' haunted-kithmaze '
original: ' 545a5914d820eb0000f6dc0a '
description: ' The builders of Kithgard constructed many mazes to confuse travelers. '
x: 78
y: 29
nextLevels:
2014-12-05 21:30:31 -05:00
continue : ' the-second-kithmaze '
2014-10-22 18:42:51 -04:00
}
2014-12-05 18:44:49 -05:00
{
name: ' Riddling Kithmaze '
type: ' hero '
id: ' riddling-kithmaze '
original: ' 5418b9d64c16460000ab9ab4 '
description: ' If at first you go astray, change your loop to find the way. '
x: 69.97
y: 28.03
nextLevels:
2014-12-05 21:29:15 -05:00
continue : ' descending-further '
2014-12-05 18:44:49 -05:00
practice: true
requiresSubscription: true
}
2014-10-22 18:42:51 -04:00
{
2014-10-30 22:14:40 -04:00
name: ' Descending Further '
2014-10-22 18:42:51 -04:00
type: ' hero '
2014-10-30 22:14:40 -04:00
id: ' descending-further '
original: ' 5452a84d57e83800009730e4 '
2014-10-22 18:42:51 -04:00
description: ' Another day, another maze. '
2014-12-05 18:44:49 -05:00
x: 61.68
y: 22.80
2014-10-22 18:42:51 -04:00
nextLevels:
continue : ' the-second-kithmaze '
practice: true
2014-12-05 18:44:49 -05:00
requiresSubscription: true
2014-09-19 14:03:38 -04:00
}
{
name: ' The Second Kithmaze '
type: ' hero '
id: ' the-second-kithmaze '
2014-09-26 05:28:54 -04:00
original: ' 5418cf256bae62f707c7e1c3 '
2014-09-19 14:03:38 -04:00
description: ' Many have tried, few have found their way through this maze. '
2014-12-05 18:44:49 -05:00
x: 54.49
y: 26.49
2014-10-22 18:42:51 -04:00
nextLevels:
2014-11-05 13:40:37 -05:00
continue : ' dread-door '
2014-10-22 18:42:51 -04:00
}
2014-09-19 14:03:38 -04:00
{
2014-11-05 13:40:37 -05:00
name: ' Dread Door '
2014-09-19 14:03:38 -04:00
type: ' hero '
2014-11-05 13:40:37 -05:00
id: ' dread-door '
2014-09-26 05:28:54 -04:00
original: ' 5418d40f4c16460000ab9ac2 '
2014-11-05 13:40:37 -05:00
description: ' Behind a dread door lies a chest full of riches. '
2014-12-05 18:44:49 -05:00
x: 60.52
y: 33.70
2014-10-30 22:14:40 -04:00
nextLevels:
continue : ' known-enemy '
}
{
name: ' Known Enemy '
type: ' hero '
id: ' known-enemy '
original: ' 5452adea57e83800009730ee '
description: ' Begin to use variables in your battles. '
2014-11-22 19:14:43 -05:00
x: 67
y: 39
2014-10-30 22:14:40 -04:00
nextLevels:
continue : ' master-of-names '
}
{
name: ' Master of Names '
type: ' hero '
id: ' master-of-names '
original: ' 5452c3ce57e83800009730f7 '
description: ' Use your glasses to defend yourself from the Kithmen. '
2014-10-31 00:34:49 -04:00
x: 75
y: 46
2014-10-22 18:42:51 -04:00
nextLevels:
continue : ' lowly-kithmen '
2014-09-19 14:03:38 -04:00
}
{
2014-09-20 18:18:21 -04:00
name: ' Lowly Kithmen '
2014-09-19 14:03:38 -04:00
type: ' hero '
2014-09-20 18:18:21 -04:00
id: ' lowly-kithmen '
2014-09-26 05:28:54 -04:00
original: ' 541b24511ccc8eaae19f3c1f '
2014-10-30 22:14:40 -04:00
description: ' Now that you can see them, they \' re everywhere! '
2014-11-22 19:14:43 -05:00
x: 85
y: 40
2014-10-22 18:42:51 -04:00
nextLevels:
continue : ' closing-the-distance '
}
2014-09-19 14:03:38 -04:00
{
2014-10-06 20:46:13 -04:00
name: ' Closing the Distance '
2014-09-19 14:03:38 -04:00
type: ' hero '
2014-10-06 20:46:13 -04:00
id: ' closing-the-distance '
2014-09-26 05:28:54 -04:00
original: ' 541b288e1ccc8eaae19f3c25 '
2014-09-19 14:03:38 -04:00
description: ' Kithmen are not the only ones to stand in your way. '
2014-10-31 00:34:49 -04:00
x: 93
y: 47
2014-10-22 18:42:51 -04:00
nextLevels:
continue : ' the-final-kithmaze '
}
{
2014-10-30 22:14:40 -04:00
name: ' Tactical Strike '
2014-10-22 18:42:51 -04:00
type: ' hero '
2014-10-30 22:14:40 -04:00
id: ' tactical-strike '
original: ' 5452cfa706a59e000067e4f5 '
description: ' They \' re, uh, coming right for us! Sneak up behind them. '
2014-12-05 18:44:49 -05:00
x: 83.23
y: 52.73
2014-10-22 18:42:51 -04:00
nextLevels:
continue : ' the-final-kithmaze '
practice: true
2014-12-05 18:44:49 -05:00
requiresSubscription: true
2014-09-19 14:03:38 -04:00
}
{
name: ' The Final Kithmaze '
type: ' hero '
id: ' the-final-kithmaze '
2014-09-26 05:28:54 -04:00
original: ' 541b434e1ccc8eaae19f3c33 '
2014-09-19 14:03:38 -04:00
description: ' To escape you must find your way through an Elder Kithman \' s maze. '
2014-12-05 18:44:49 -05:00
x: 86.95
y: 64.70
2014-10-22 18:42:51 -04:00
nextLevels:
continue : ' kithgard-gates '
}
{
2014-10-30 22:14:40 -04:00
name: ' The Gauntlet '
2014-10-22 18:42:51 -04:00
type: ' hero '
2014-10-30 22:14:40 -04:00
id: ' the-gauntlet '
original: ' 5452d8b906a59e000067e4fa '
description: ' Rush for the stairs, battling foes at every turn. '
2014-12-05 18:44:49 -05:00
x: 76.50
y: 72.69
2014-10-22 18:42:51 -04:00
nextLevels:
continue : ' kithgard-gates '
practice: true
2014-12-05 18:44:49 -05:00
requiresSubscription: true
2014-09-19 14:03:38 -04:00
}
{
name: ' Kithgard Gates '
type: ' hero '
id: ' kithgard-gates '
2014-09-26 05:28:54 -04:00
original: ' 541c9a30c6362edfb0f34479 '
2014-09-22 17:05:13 -04:00
description: ' Escape the Kithgard dungeons and don \' t let the guardians get you. '
2014-10-02 17:36:26 -04:00
x: 89
y: 82
2014-10-22 18:42:51 -04:00
nextLevels:
2014-10-26 18:31:20 -04:00
continue : ' defense-of-plainswood '
2014-09-19 14:03:38 -04:00
}
2014-10-29 13:47:17 -04:00
{
name: ' Cavern Survival '
type: ' hero-ladder '
id: ' cavern-survival '
original: ' 544437e0645c0c0000c3291d '
description: ' Stay alive longer than your opponent amidst hordes of ogres! '
x: 17.54
y: 78.39
2014-12-17 15:42:36 -05:00
adventurer: true
2014-10-29 13:47:17 -04:00
}
2014-10-29 12:47:00 -04:00
]
forest = [
2014-09-19 14:03:38 -04:00
{
2014-10-26 18:31:20 -04:00
name: ' Defense of Plainswood '
2014-09-19 14:03:38 -04:00
type: ' hero '
2014-10-26 18:31:20 -04:00
id: ' defense-of-plainswood '
2014-09-26 05:28:54 -04:00
original: ' 541b67f71ccc8eaae19f3c62 '
2014-09-19 14:03:38 -04:00
description: ' Protect the peasants from the pursuing ogres. '
2014-11-01 12:35:19 -04:00
nextLevels:
continue : ' winding-trail '
2014-12-03 13:53:45 -05:00
x: 18
y: 37
2014-09-19 14:03:38 -04:00
}
2014-10-18 17:51:43 -04:00
{
2014-10-29 13:47:17 -04:00
name: ' Winding Trail '
type: ' hero '
id: ' winding-trail '
original: ' 5446cb40ce01c23e05ecf027 '
description: ' Stay alive and navigate through the forest. '
2014-11-01 12:35:19 -04:00
nextLevels:
2014-12-09 15:38:58 -05:00
continue : ' patrol-buster '
2014-12-03 13:53:45 -05:00
x: 24
y: 35
2014-12-09 15:38:58 -05:00
}
{
name: ' Patrol Buster '
type: ' hero '
id: ' patrol-buster '
original: ' 5487330d84f7b4dac246d440 '
description: ' Defeat ogre patrols with new, selective targeting skills. '
nextLevels:
continue : ' thornbush-farm '
x: 34
y: 25
2014-12-17 15:42:36 -05:00
}
2014-11-20 22:32:09 -05:00
{
name: ' Endangered Burl '
type: ' hero '
id: ' endangered-burl '
2014-11-26 14:03:24 -05:00
original: ' 546e97033f1c1c1be898402b '
2014-11-20 22:32:09 -05:00
description: ' Hunt ogres in the woods, but watch out for lumbering beasts. '
nextLevels:
2014-12-05 21:29:15 -05:00
continue : ' thornbush-farm '
2014-12-03 13:53:45 -05:00
x: 29
y: 35
2014-11-20 22:32:09 -05:00
}
{
name: ' Village Guard '
type: ' hero '
id: ' village-guard '
original: ' 546e91b8a4b7840000ee92dc '
description: ' Defend a village from marauding munchkin mayhem. '
nextLevels:
continue : ' thornbush-farm '
2014-12-03 13:53:45 -05:00
x: 33
y: 37
2014-12-05 18:44:49 -05:00
practice: true
requiresSubscription: true
2014-11-20 22:32:09 -05:00
}
2014-10-29 13:47:17 -04:00
{
name: ' Thornbush Farm '
type: ' hero '
id: ' thornbush-farm '
original: ' 5447030525cce60000745e2a '
description: ' Determine refugee peasant from ogre when defending the farm. '
2014-11-01 12:35:19 -04:00
nextLevels:
2014-11-11 10:57:29 -05:00
continue : ' back-to-back '
2014-12-03 13:53:45 -05:00
x: 37
y: 40
2014-10-29 13:47:17 -04:00
}
{
2014-11-11 10:57:29 -05:00
name: ' Back to Back '
2014-10-29 13:47:17 -04:00
type: ' hero '
2014-11-11 10:57:29 -05:00
id: ' back-to-back '
2014-10-29 13:47:17 -04:00
original: ' 5448330517d7283e051f9b9e '
description: ' Patrol the village entrances, but stay defensive. '
2014-11-08 22:33:00 -05:00
nextLevels:
continue : ' ogre-encampment '
2014-12-03 13:53:45 -05:00
x: 39
y: 47.5
2014-10-18 17:51:43 -04:00
}
2014-11-08 22:33:00 -05:00
{
name: ' Ogre Encampment '
type: ' hero '
id: ' ogre-encampment '
2014-11-26 14:03:24 -05:00
original: ' 5456b3c8d5ada30000525605 '
2014-11-08 22:33:00 -05:00
description: ' Recover stolen treasure from an ogre encampment. '
nextLevels:
continue : ' woodland-cleaver '
2014-12-03 13:53:45 -05:00
x: 39
y: 55
2014-11-08 22:33:00 -05:00
}
{
name: ' Woodland Cleaver '
type: ' hero '
id: ' woodland-cleaver '
2014-11-26 14:03:24 -05:00
original: ' 5456bb8dd5ada30000525613 '
2014-11-08 22:33:00 -05:00
description: ' Use your new cleave ability to fend off munchkins. '
nextLevels:
continue : ' shield-rush '
2014-12-03 13:53:45 -05:00
x: 39.5
y: 61
2014-11-08 22:33:00 -05:00
}
{
name: ' Shield Rush '
type: ' hero '
id: ' shield-rush '
2014-11-26 14:03:24 -05:00
original: ' 5459570bb4461871053292f5 '
2014-11-08 22:33:00 -05:00
description: ' Combine cleave and shield to endure an ogre onslaught. '
nextLevels:
continue : ' peasant-protection '
2014-12-03 13:53:45 -05:00
x: 42
y: 68
2014-11-21 23:36:56 -05:00
}
# Warrior branch
2014-11-08 22:33:00 -05:00
{
name: ' Peasant Protection '
type: ' hero '
id: ' peasant-protection '
2014-11-26 14:03:24 -05:00
original: ' 545ec477e7f60fd6c55760e9 '
2014-11-08 22:33:00 -05:00
description: ' Stay close to Victor. '
nextLevels:
continue : ' munchkin-swarm '
2014-12-03 13:53:45 -05:00
x: 44.5
y: 75.5
2014-11-08 22:33:00 -05:00
}
{
name: ' Munchkin Swarm '
type: ' hero '
id: ' munchkin-swarm '
2014-11-26 14:03:24 -05:00
original: ' 545edba9e7f60fd6c5576133 '
2014-11-09 00:50:25 -05:00
description: ' Loot a gigantic chest while surrounded by a swarm of ogre munchkins. '
2014-11-08 22:33:00 -05:00
nextLevels:
continue : ' coinucopia '
2014-12-03 13:53:45 -05:00
x: 49
y: 81
2014-11-08 22:33:00 -05:00
}
2014-11-21 23:36:56 -05:00
# Ranger branch
{
name: ' Munchkin Harvest '
type: ' hero '
id: ' munchkin-harvest '
2014-11-26 14:03:24 -05:00
original: ' 5470001860f6cc376131525d '
2014-11-21 23:36:56 -05:00
description: ' Join forces with a new hero: Amara Arrowhead. '
nextLevels:
continue : ' swift-dagger '
2014-12-03 13:53:45 -05:00
x: 38
y: 72
2014-12-05 18:44:49 -05:00
requiresSubscription: true
2014-12-10 13:44:25 -05:00
unlocksHero: {
img: ' /file/db/thang.type/52fc0ed77e01835453bd8f6c/portrait.png '
originalID: ' 52fc0ed77e01835453bd8f6c '
}
2014-11-21 23:36:56 -05:00
}
{
name: ' Swift Dagger '
type: ' hero '
id: ' swift-dagger '
2014-11-26 14:03:24 -05:00
original: ' 54701f7860f6cc37613152a1 '
2014-11-22 01:35:03 -05:00
description: ' Deal damage from a distance with your new hero. '
2014-11-21 23:36:56 -05:00
nextLevels:
continue : ' shrapnel '
2014-12-03 13:53:45 -05:00
x: 33
y: 72
2014-12-05 18:44:49 -05:00
requiresSubscription: true
2014-11-21 23:36:56 -05:00
}
{
name: ' Shrapnel '
type: ' hero '
id: ' shrapnel '
2014-11-26 14:03:24 -05:00
original: ' 5470291c60f6cc37613152d1 '
2014-11-21 23:36:56 -05:00
description: ' Explore the explosive arts. '
nextLevels:
continue : ' coinucopia '
2014-12-03 13:53:45 -05:00
x: 28
y: 73
2014-12-05 18:44:49 -05:00
requiresSubscription: true
2014-11-21 23:36:56 -05:00
}
# Wizard branch
{
name: ' Arcane Ally '
type: ' hero '
id: ' arcane-ally '
2014-11-26 14:03:24 -05:00
original: ' 5470b98ceb739dbc9d2402c7 '
2014-11-21 23:36:56 -05:00
description: ' Stand your ground against large ogres with a new hero: Ms. Hushbaum. '
nextLevels:
continue : ' touch-of-death '
2014-12-03 13:53:45 -05:00
x: 47
y: 71
2014-12-05 18:44:49 -05:00
requiresSubscription: true
2014-12-10 13:44:25 -05:00
unlocksHero: {
img: ' /file/db/thang.type/52fbf74b7e01835453bd8d8e/portrait.png '
originalID: ' 529ec584c423d4e83b000014 '
}
2014-11-21 23:36:56 -05:00
}
{
name: ' Touch of Death '
type: ' hero '
id: ' touch-of-death '
2014-11-26 14:03:24 -05:00
original: ' 5470ca33eb739dbc9d2402ee '
2014-11-21 23:36:56 -05:00
description: ' Learn your first spell to siphon life from your foes. '
nextLevels:
continue : ' bonemender '
2014-12-03 13:53:45 -05:00
x: 52
y: 70
2014-12-05 18:44:49 -05:00
requiresSubscription: true
2014-11-21 23:36:56 -05:00
}
{
name: ' Bonemender '
type: ' hero '
id: ' bonemender '
2014-11-26 14:03:24 -05:00
original: ' 5470d013eb739dbc9d240323 '
2014-11-21 23:36:56 -05:00
description: ' Cast regeneration on allied soldiers to withstand a siege. '
nextLevels:
continue : ' coinucopia '
2014-12-03 13:53:45 -05:00
x: 58
y: 67
2014-12-05 18:44:49 -05:00
requiresSubscription: true
2014-11-21 23:36:56 -05:00
}
2014-11-06 21:18:57 -05:00
{
name: ' Coinucopia '
type: ' hero '
id: ' coinucopia '
2014-11-26 14:03:24 -05:00
original: ' 545bb1181e649a4495f887df '
2014-11-06 21:18:57 -05:00
description: ' Start playing in real-time with input flags as you collect gold coins! '
2014-11-08 22:33:00 -05:00
nextLevels:
continue : ' copper-meadows '
2014-12-03 13:53:45 -05:00
x: 56
y: 82
2014-11-08 22:33:00 -05:00
}
{
name: ' Copper Meadows '
type: ' hero '
id: ' copper-meadows '
2014-11-26 14:03:24 -05:00
original: ' 5462491c688f333d05d8af38 '
2014-11-16 23:38:15 -05:00
description: ' This level exercises: if/else, object members, variables, flag placement, and collection. '
2014-11-08 22:33:00 -05:00
nextLevels:
continue : ' drop-the-flag '
2014-12-03 13:53:45 -05:00
x: 60
y: 86
2014-11-08 22:33:00 -05:00
}
{
name: ' Drop the Flag '
type: ' hero '
id: ' drop-the-flag '
2014-11-26 14:03:24 -05:00
original: ' 54626472f3c64b7b0598590c '
2014-11-16 23:38:15 -05:00
description: ' This level exercises: flag position, object members. '
2014-11-08 22:33:00 -05:00
nextLevels:
2014-12-10 13:00:52 -05:00
continue : ' rich-forager '
2014-12-03 13:53:45 -05:00
x: 65.5
y: 91
2014-11-08 22:33:00 -05:00
}
{
2014-11-11 19:36:44 -05:00
name: ' Deadly Pursuit '
2014-11-08 22:33:00 -05:00
type: ' hero '
2014-11-11 19:36:44 -05:00
id: ' deadly-pursuit '
2014-11-26 14:03:24 -05:00
original: ' 54626f270cacde3f055434ac '
2014-11-16 23:38:15 -05:00
description: ' This level exercises: if/else, flag placement and timing, item collection. '
2014-11-08 22:33:00 -05:00
nextLevels:
2014-11-11 19:36:44 -05:00
continue : ' rich-forager '
2014-12-03 14:19:48 -05:00
x: 74.5
y: 92
2014-12-05 18:44:49 -05:00
requiresSubscription: true
2014-12-10 13:44:25 -05:00
unlocksHero: {
img: ' /file/db/thang.type/5466d449417c8b48a9811e83/portrait.png '
originalID: ' 5466d449417c8b48a9811e83 '
}
2014-11-08 22:33:00 -05:00
}
{
2014-11-11 19:36:44 -05:00
name: ' Rich Forager '
2014-11-08 22:33:00 -05:00
type: ' hero '
2014-11-11 19:36:44 -05:00
id: ' rich-forager '
2014-11-26 14:03:24 -05:00
original: ' 546283ddfdd66af405fa8209 '
2014-11-16 23:38:15 -05:00
description: ' This level exercises: if/else if, collection, combat. '
2014-11-08 22:33:00 -05:00
nextLevels:
2014-12-10 13:00:52 -05:00
continue : ' siege-of-stonehold '
2014-12-03 14:19:48 -05:00
x: 80
y: 88
2014-12-10 13:44:25 -05:00
unlocksHero: {
img: ' /file/db/thang.type/52e9adf7427172ae56002172/portrait.png '
originalID: ' 52e9adf7427172ae56002172 '
}
2014-11-08 22:33:00 -05:00
}
2014-11-21 23:36:56 -05:00
{
name: ' Siege of Stonehold '
type: ' hero '
id: ' siege-of-stonehold '
2014-11-26 14:03:24 -05:00
original: ' 54712072eb739dbc9d24034b '
2014-11-21 23:36:56 -05:00
description: ' Unlock the desert world, if you are strong enough to win this epic battle! '
2014-12-08 16:59:13 -05:00
nextLevels:
continue : ' the-dunes '
2014-12-03 14:19:48 -05:00
x: 85.5
y: 83.5
2014-11-21 23:36:56 -05:00
}
2014-11-08 22:33:00 -05:00
{
name: ' Multiplayer Treasure Grove '
2014-11-16 23:38:15 -05:00
type: ' hero-ladder '
2014-11-08 22:33:00 -05:00
id: ' multiplayer-treasure-grove '
2014-11-26 14:03:24 -05:00
original: ' 5469643c37600b40e0e09c5b '
2014-11-16 23:38:15 -05:00
description: ' Mix collection, flags, and combat in this multiplayer coin-gathering arena. '
2014-12-03 13:53:45 -05:00
x: 56.5
y: 20
2014-11-06 21:18:57 -05:00
}
2014-10-29 13:47:17 -04:00
{
name: ' Dueling Grounds '
type: ' hero-ladder '
id: ' dueling-grounds '
original: ' 5442ba0e1e835500007eb1c7 '
description: ' Battle head-to-head against another hero in this basic beginner combat arena. '
2014-12-03 13:53:45 -05:00
x: 83
y: 23
2014-12-03 23:46:47 -05:00
adventurer: true
2014-10-29 13:47:17 -04:00
}
2014-12-10 13:00:52 -05:00
]
2014-12-08 16:59:13 -05:00
2014-12-10 13:00:52 -05:00
desert = [
2014-12-08 16:59:13 -05:00
{
name: ' The Dunes '
type: ' hero '
id: ' the-dunes '
original: ' 5480b62e1bf0b10000711c59 '
description: ' Behold, the desert, full of glory, danger, and sand. Lots of sand. '
nextLevels:
continue : ' the-mighty-sand-yak '
2014-12-10 13:00:52 -05:00
x: 8.47
y: 21.93
2014-12-08 16:59:13 -05:00
requiresSubscription: true
}
{
name: ' The Mighty Sand Yak '
type: ' hero '
id: ' the-mighty-sand-yak '
original: ' 5480b9d01bf0b10000711c5f '
2014-12-09 22:23:11 -05:00
description: ' Test your nerves by dodging huge sand yaks on the open dunes! '
2014-12-08 16:59:13 -05:00
nextLevels:
continue : ' oasis '
2014-12-10 13:00:52 -05:00
x: 16.56
y: 27.77
requiresSubscription: false
2014-12-08 16:59:13 -05:00
}
{
name: ' Oasis '
type: ' hero '
id: ' oasis '
original: ' 5480ba761bf0b10000711c64 '
2014-12-10 13:00:52 -05:00
description: ' Run a gauntlet of sand yaks to reach oasis and quench your thirst! '
2014-12-13 22:43:12 -05:00
nextLevels:
continue : ' sarven-road '
2014-12-10 13:00:52 -05:00
x: 23.35
y: 31.60
requiresSubscription: false
2014-12-08 16:59:13 -05:00
}
2014-12-13 22:43:12 -05:00
{
name: ' Sarven Road '
type: ' hero '
id: ' sarven-road '
original: ' 548c82360ffdc235e80ef04b '
2014-12-17 15:42:36 -05:00
description: ' Watch out for ogre scouts on the road as you search for water. '
2014-12-13 22:43:12 -05:00
nextLevels:
continue : ' sarven-gaps '
x: 28.36
y: 24.59
adventurer: true
requiresSubscription: false
}
{
name: ' Sarven Gaps '
type: ' hero '
id: ' sarven-gaps '
original: ' 548c8f4a0ffdc235e80ef0a8 '
2014-12-17 15:42:36 -05:00
description: ' Keep the oasis safe by building fences to hold back the enemy. '
2014-12-13 22:43:12 -05:00
nextLevels:
continue : ' thunderhooves '
x: 21.13
y: 9.29
adventurer: true
requiresSubscription: true
}
{
name: ' Thunderhooves '
type: ' hero '
id: ' thunderhooves '
original: ' 548c90020ffdc235e80ef0ad '
2014-12-17 15:42:36 -05:00
description: ' Fence off the stampeding sand yaks to reach the next watering hole. '
2014-12-13 22:43:12 -05:00
nextLevels:
continue : ' medical-attention '
x: 35.08
y: 20.48
adventurer: true
requiresSubscription: false
}
{
name: ' Medical Attention '
type: ' hero '
id: ' medical-attention '
original: ' 548ce3300ffdc235e80ef0b2 '
2014-12-17 15:42:36 -05:00
description: ' Get help from a helpful wizard while you fend off an ogre attack. '
2014-12-13 22:43:12 -05:00
nextLevels:
continue : ' minesweeper '
x: 42.84
y: 21.82
adventurer: true
requiresSubscription: false
}
{
name: ' Minesweeper '
type: ' hero '
id: ' minesweeper '
2014-12-16 19:40:14 -05:00
original: ' 5490cb7c623b972aa26b25a3 '
2014-12-17 15:42:36 -05:00
description: ' Lead a band of hapless peasants through a treacherous canyon while you heroically trigger the mines. '
2014-12-13 22:43:12 -05:00
nextLevels:
continue : ' sarven-sentry '
x: 47.64
y: 12.40
adventurer: true
requiresSubscription: true
}
{
name: ' Sarven Sentry '
type: ' hero '
id: ' sarven-sentry '
original: ' 548cef7f0ffdc235e80ef0cc '
2014-12-23 20:14:09 -05:00
description: ' Work with your scouts to corral yaks and trap ogres. '
2014-12-13 22:43:12 -05:00
nextLevels:
continue : ' keeping-time '
x: 51.48
y: 26.09
adventurer: true
requiresSubscription: false
disabled: not me . isAdmin ( )
}
{
name: ' Keeping Time '
type: ' hero '
id: ' keeping-time '
original: ' 548cf1a90ffdc235e80ef0d1 '
2014-12-23 20:14:09 -05:00
description: ' Raise funds to support your allies in time to fight off the ogre horde! '
2014-12-13 22:43:12 -05:00
nextLevels:
continue : ' hoarding-gold '
x: 58.42
y: 34.14
adventurer: true
requiresSubscription: false
disabled: not me . isAdmin ( )
}
{
name: ' Hoarding Gold '
type: ' hero '
id: ' hoarding-gold '
2014-12-23 20:14:09 -05:00
original: ' 549875268e52573b10d3bcd7 '
description: ' You can get lost forever in the desert if you let the mirage of greed lead you. '
2014-12-13 22:43:12 -05:00
nextLevels:
continue : ' decoy-drill '
x: 61.73
y: 29.51
adventurer: true
requiresSubscription: false
disabled: not me . isAdmin ( )
}
{
name: ' Decoy Drill '
type: ' hero '
id: ' decoy-drill '
2014-12-23 20:14:09 -05:00
original: ' 549875428e52573b10d3bcd9 '
description: ' Gather gold to field test a new buildable unit: the decoy. '
2014-12-13 22:43:12 -05:00
nextLevels:
continue : ' yakstraction '
x: 62.05
y: 40.44
adventurer: true
requiresSubscription: false
disabled: not me . isAdmin ( )
}
{
name: ' Yakstraction '
type: ' hero '
id: ' yakstraction '
2014-12-23 20:14:09 -05:00
original: ' 5498cf468e52573b10d3bd15 '
description: ' Thirsty yaks are stampeding towards a vulnerable peasant sunning herself at an oasis, but you \' ve got decoys to distract the yaks out of the way. '
2014-12-13 22:43:12 -05:00
nextLevels:
continue : ' sarven-brawl '
x: 66.46
y: 48.87
adventurer: true
requiresSubscription: true
}
{
name: ' Sarven Brawl '
type: ' hero '
id: ' sarven-brawl '
original: ' 548cf2850ffdc235e80ef0d6 '
description: ' Coming Soon '
#nextLevels:
# continue: ''
x: 69.01
y: 33.80
adventurer: true
requiresSubscription: false
disabled: not me . isAdmin ( )
}
2014-12-08 16:59:13 -05:00
2014-09-19 14:03:38 -04:00
]
2014-10-22 18:42:51 -04:00
WorldMapView.campaigns = campaigns = [
2014-10-29 12:47:00 -04:00
{ id: ' dungeon ' , name: ' Dungeon Campaign ' , levels: dungeon }
{ id: ' forest ' , name: ' Forest Campaign ' , levels: forest }
2014-12-10 13:00:52 -05:00
{ id: ' desert ' , name: ' Desert Campaign ' , levels: desert }
2014-09-17 21:56:08 -04:00
]