Merge branch 'master' into production

This commit is contained in:
Nick Winter 2014-09-17 22:37:44 -07:00
commit dca6eb6f11
58 changed files with 1490 additions and 116 deletions

View file

@ -14,7 +14,8 @@ module.exports = class CocoRouter extends Backbone.Router
Backbone.Mediator.subscribe 'router:navigate', @onNavigate, @
routes:
'': go('HomeView')
'': go('HomeView') # This will go somewhere deprecated when FrontView is done.
'front': go('FrontView') # This will become '' when it is done.
'about': go('AboutView')
@ -73,7 +74,8 @@ module.exports = class CocoRouter extends Backbone.Router
'multiplayer': go('MultiplayerView')
'play': go('play/MainPlayView')
'play': go('play/MainPlayView') # This will become 'play-old' or something.
'play-hero': go('play/WorldMapView') # This will become 'play' when it is done.
'play/ladder/:levelID': go('play/ladder/LadderView')
'play/ladder': go('play/ladder/MainLadderView')
'play/level/:levelID': go('play/level/PlayLevelView')

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View file

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View file

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View file

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View file

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View file

@ -202,7 +202,7 @@ module.exports = class LevelLoader extends CocoClass
thangsToLoad = _.uniq( (t.spriteName for t in @world.thangs when t.exists) )
nameModelTuples = ([thangType.get('name'), thangType] for thangType in @thangNames.models)
nameModelMap = _.zipObject nameModelTuples
@spriteSheetsToBuild = []
@spriteSheetsToBuild ?= []
for thangTypeName in thangsToLoad
thangType = nameModelMap[thangTypeName]
@ -230,7 +230,7 @@ module.exports = class LevelLoader extends CocoClass
buildLoop: =>
someLeft = false
for spriteSheetResource, i in @spriteSheetsToBuild
for spriteSheetResource, i in @spriteSheetsToBuild ? []
continue if spriteSheetResource.spriteSheetKeys
someLeft = true
thangType = spriteSheetResource.thangType

View file

@ -79,6 +79,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
@handledDisplayEvents = {}
@age = 0
@stillLoading = true
@setNameLabel @thang.id if @thang?.showsName and not @thang.health <= 0
if @thangType.isFullyLoaded()
@setUpSprite()
else
@ -488,6 +489,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
rotation = @getRotation()
if relatedActions['111111111111'] # has grid-surrounding-wall-based actions
if @wallGrid
@hadWallGrid = true
action = ''
tileSize = 4
[gx, gy] = [@thang.pos.x, @thang.pos.y]
@ -514,6 +516,8 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
break
#console.log 'returning', matchedAction, 'for', @thang.id, 'at', gx, gy
return relatedActions[matchedAction]
else if @hadWallGrid
return null
else
keys = _.keys relatedActions
index = Math.max 0, Math.floor((179 + rotation) / 360 * keys.length)
@ -527,13 +531,15 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
relatedActions[direction]
updateStats: ->
return unless @thang and @thang.health isnt @lastHealth
@lastHealth = @thang.health
if bar = @healthBar
return if @thang.health is @lastHealth
@lastHealth = @thang.health
healthPct = Math.max(@thang.health / @thang.maxHealth, 0)
bar.scaleX = healthPct / bar.baseScale
healthOffset = @getOffset 'aboveHead'
[bar.x, bar.y] = [healthOffset.x - bar.width / 2, healthOffset.y]
if @thang.showsName
@setNameLabel(if @thang.health <= 0 then '' else @thang.id)
configureMouse: ->
@imageObject.cursor = 'pointer' if @thang?.isSelectable

View file

@ -22,7 +22,7 @@ module.exports = class RegionChooser extends CocoClass
onMouseMove: (e) =>
return unless @firstPoint
@secondPoint = @options.camera.screenToWorld {x: e.stageX, y: e.stageY}
@restrictRegion() if @options.restrictRatio
@restrictRegion() if @options.restrictRatio or key.alt
@updateShape()
onMouseUp: (e) =>

View file

@ -186,11 +186,11 @@ module.exports = class SpriteBoss extends CocoClass
sprite.update frameChanged for sprite in @spriteArray
@updateSelection()
@spriteLayers['Default'].updateLayerOrder()
@cache()
@cacheObstacles()
adjustSpriteExistence: ->
# Add anything new, remove anything old, update everything current
updateCache = false
updatedObstacles = []
itemsJustEquipped = []
for thang in @world.thangs when thang.exists and thang.pos
itemsJustEquipped = itemsJustEquipped.concat @equipNewItems thang
@ -199,16 +199,16 @@ module.exports = class SpriteBoss extends CocoClass
else
sprite = @addThangToSprites(thang)
Backbone.Mediator.publish 'surface:new-thang-added', thang: thang, sprite: sprite
updateCache = updateCache or sprite.imageObject.parent is @spriteLayers['Obstacle']
updatedObstacles.push sprite if sprite.imageObject.parent is @spriteLayers['Obstacle']
sprite.playSounds()
item.modifyStats() for item in itemsJustEquipped
for thangID, sprite of @sprites
missing = not (sprite.notOfThisWorld or @world.thangMap[thangID]?.exists)
isObstacle = sprite.imageObject.parent is @spriteLayers['Obstacle']
updateCache = updateCache or (isObstacle and (missing or sprite.hasMoved))
updatedObstacles.push sprite if isObstacle and (missing or sprite.hasMoved)
sprite.hasMoved = false
@removeSprite sprite if missing
@cache true if updateCache and @cached
@cacheObstacles updatedObstacles if updatedObstacles.length and @cachedObstacles
# mainly for handling selecting thangs from session when the thang is not always in existence
if @willSelectThang and @sprites[@willSelectThang[0]]
@ -229,25 +229,26 @@ module.exports = class SpriteBoss extends CocoClass
itemsJustEquipped.push item
return itemsJustEquipped
cache: (update=false) ->
return if @cached and not update
cacheObstacles: (updatedObstacles=null) ->
return if @cachedObstacles and not updatedObstacles
wallSprites = (sprite for sprite in @spriteArray when sprite.thangType?.get('name').search(/(dungeon|indoor).wall/i) isnt -1)
return if _.any (s.stillLoading for s in wallSprites)
walls = (sprite.thang for sprite in wallSprites)
@world.calculateBounds()
wallGrid = new Grid walls, @world.size()...
for wallSprite in wallSprites
if updatedObstacles
possiblyUpdatedWallSprites = (sprite for sprite in wallSprites when _.find updatedObstacles, (w2) -> sprite is w2 or (Math.abs(sprite.thang.pos.x - w2.thang.pos.x) + Math.abs(sprite.thang.pos.y - w2.thang.pos.y)) <= 16)
else
possiblyUpdatedWallSprites = wallSprites
#console.log 'updating up to', possiblyUpdatedWallSprites.length, 'of', wallSprites.length, 'wall sprites from updatedObstacles', updatedObstacles
for wallSprite in possiblyUpdatedWallSprites
wallSprite.updateActionDirection wallGrid
wallSprite.updateScale()
wallSprite.updatePosition()
#console.log @wallGrid.toString()
@spriteLayers['Obstacle'].uncache() if @spriteLayers['Obstacle'].cacheID # might have changed sizes
@spriteLayers['Obstacle'].cache()
# test performance of doing land layer, too, to see if it's faster
# @spriteLayers['Land'].uncache() if @spriteLayers['Land'].cacheID # might have changed sizes
# @spriteLayers['Land'].cache()
# I don't notice much difference - Scott
@cached = true
@cachedObstacles = true
spriteFor: (thangID) -> @sprites[thangID]

View file

@ -488,7 +488,7 @@ module.exports = Surface = class Surface extends CocoClass
#- Canvas callbacks
onResize: (e) =>
return if @destroyed
return if @destroyed or @options.choosing
oldWidth = parseInt @canvas.attr('width'), 10
oldHeight = parseInt @canvas.attr('height'), 10
aspectRatio = oldWidth / oldHeight

View file

@ -139,7 +139,7 @@ module.exports = class GoalManager extends CocoClass
@initGoalState(state, [[], keepFrom.keepFromLocation?.who], 'arrived')
@initGoalState(state, [goal.getToLocations?.who, goal.keepFromLocations?.who], 'arrived')
@initGoalState(state, [goal.leaveOffSides?.who, goal.keepFromLeavingOffSides?.who], 'left')
@initGoalState(state, [goal.collectThangs?.who, goal.keepFromCollectingThangs?.who], 'collected')
@initGoalState(state, [goal.collectThangs?.targets, goal.keepFromCollectingThangs?.targets], 'collected')
@goalStates[goal.id] = state
onThangDied: (e, frameNumber) ->
@ -169,23 +169,23 @@ module.exports = class GoalManager extends CocoClass
onThangLeftMap: (e, frameNumber) ->
for goal in @goals ? []
@checkLeft(goal.id, goal.leaveOffSides.who, goal.leaveOffSides.sides, e.thang.id, e.side, frameNumber) if goal.leaveOffSides?
@checkLeft(goal.id, goal.keepFromLeavingOffSides.who, goal.keepFromLeavingOffSides.sides, e.thang.id, e.side, frameNumber) if goal.keepFromLeavingOffSides?
@checkLeft(goal.id, goal.leaveOffSides.who, goal.leaveOffSides.sides, e.thang, e.side, frameNumber) if goal.leaveOffSides?
@checkLeft(goal.id, goal.keepFromLeavingOffSides.who, goal.keepFromLeavingOffSides.sides, e.thang, e.side, frameNumber) if goal.keepFromLeavingOffSides?
checkLeft: (goalID, who, sides, thangID, side, frameNumber) ->
checkLeft: (goalID, who, sides, thang, side, frameNumber) ->
return if sides and side and not (side in sides)
return unless thangID in who
@updateGoalState(goalID, thangID, 'left', frameNumber)
return unless thang.id in who or thang.team in who
@updateGoalState(goalID, thang.id, 'left', frameNumber)
onThangCollectedItem: (e, frameNumber) ->
for goal in @goals ? []
@checkCollected(goal.id, goal.collectThangs.who, goal.collectThangs.targets, e.actor.id, e.item.id, frameNumber) if goal.collectThangs?
@checkCollected(goal.id, goal.keepFromCollectingThangs.who, goal.keepFromCollectingThangs.targets, e.actor.id, e.item.id, frameNumber) if goal.keepFromCollectingThangs?
@checkCollected(goal.id, goal.collectThangs.who, goal.collectThangs.targets, e.actor, e.item.id, frameNumber) if goal.collectThangs?
@checkCollected(goal.id, goal.keepFromCollectingThangs.who, goal.keepFromCollectingThangs.targets, e.actor, e.item.id, frameNumber) if goal.keepFromCollectingThangs?
checkCollected: (goalID, who, targets, thangID, itemID, frameNumber) ->
checkCollected: (goalID, who, targets, thang, itemID, frameNumber) ->
return unless itemID in targets
return unless thangID in who
@updateGoalState(goalID, thangID, 'collected', frameNumber)
return unless thang.id in who or thang.team in who
@updateGoalState(goalID, itemID, 'collected', frameNumber)
wrapUpGoalStates: (finalFrame) ->
for goalID, state of @goalStates

View file

@ -131,6 +131,19 @@
spectate: "Spectate"
players: "players"
hours_played: "hours played"
items: "Items"
heroes: "Heroes"
achievements: "Achievements"
account: "Account"
settings: "Settings"
items:
armor: "Armor"
hands: "Hands"
accessories: "Accessories"
books: "Books"
minions: "Minions"
misc: "Misc"
contact:
contact_us: "Contact CodeCombat"
@ -878,7 +891,6 @@
tutorial_play_first: "Play the Tutorial first."
simple_ai: "Simple AI"
warmup: "Warmup"
vs: "VS"
friends_playing: "Friends Playing"
log_in_for_friends: "Log in to play with your friends!"
social_connect_blurb: "Connect and play against your friends!"

View file

@ -62,7 +62,7 @@ class CocoModel extends Backbone.Model
super(attribute)
set: (attributes, options) ->
delete @attributesWithDefaults
delete @attributesWithDefaults unless attributes is 'thangs' # unless attributes is 'thangs': performance optimization for Levels keeping their cache.
inFlux = @loading or not @loaded
@markToRevert() unless inFlux or @_revertAttributes or @project or options?.fromMerge
res = super attributes, options
@ -125,8 +125,12 @@ class CocoModel extends Backbone.Model
error(@, res) if error
return unless @notyErrors
errorMessage = "Error saving #{@get('name') ? @type()}"
console.error errorMessage, res.responseJSON
noty text: "#{errorMessage}: #{res.status} #{res.statusText}", layout: 'topCenter', type: 'error', killer: false, timeout: 10000
console.log 'going to log an error message'
console.warn errorMessage, res.responseJSON
try
noty text: "#{errorMessage}: #{res.status} #{res.statusText}", layout: 'topCenter', type: 'error', killer: false, timeout: 10000
catch notyError
console.warn "Couldn't even show noty error for", error, "because", notyError
@trigger 'save', @
return super attrs, options

View file

@ -170,14 +170,31 @@ module.exports = class Level extends CocoModel
thang.components = sorted
fillInDefaultComponentConfiguration: (thangs, levelComponents) ->
# This is slow, so I inserted some optimizations to speed it up by caching the eventual defaults of commonly-used Components.
@defaultComponentConfigurations ?= {}
cached = 0
missed = 0
cachedConfigs = 0
for thang in thangs ? []
for component in thang.components or []
isPhysical = component.original is LevelComponent.PhysicalID
if not isPhysical and defaultConfiguration = _.find @defaultComponentConfigurations[component.original], ((d) -> _.isEqual component, d.originalComponent)
component.config = defaultConfiguration.defaultedConfig
++cached
continue
continue unless lc = _.find levelComponents, {original: component.original}
unless isPhysical
originalComponent = $.extend true, {}, component
component.config ?= {}
TreemaUtils.populateDefaults(component.config, lc.configSchema, tv4)
TreemaUtils.populateDefaults(component.config, lc.configSchema ? {}, tv4)
@lastType = 'component'
@lastOriginal = component.original
@walkDefaults component.config, lc.configSchema.properties
unless isPhysical
@defaultComponentConfigurations[component.original] ?= []
@defaultComponentConfigurations[component.original].push originalComponent: originalComponent, defaultedConfig: component.config
++cachedConfigs
++missed
#console.log 'cached', cached, 'missed', missed
fillInDefaultSystemConfiguration: (levelSystems) ->
for system in levelSystems ? []
@ -185,21 +202,6 @@ module.exports = class Level extends CocoModel
TreemaUtils.populateDefaults(system.config, system.model.configSchema, tv4)
@lastType = 'system'
@lastOriginal = system.model.name
@walkDefaults system.config, system.model.configSchema.properties
walkDefaults: (config, properties) ->
# This function is redundant, but is the old implementation.
# Remove it and calls to it once we stop seeing these warnings.
return unless properties
for prop, schema of properties
if schema.default? and config[prop] is undefined
console.warn 'Setting default of', config, 'for', prop, 'to', schema.default, 'but this method is deprecated... check your config schema!', @lastType, @lastOriginal
config[prop] = schema.default
if schema.type is 'object' and config[prop]
@walkDefaults config[prop], schema.properties
else if schema.type is 'array' and config[prop]
for item in config[prop] or []
@walkDefaults item, schema.items
dimensions: ->
width = 0

View file

@ -104,7 +104,7 @@ NoteGroupSchema = c.object {title: 'Note Group', description: 'A group of notes
target: c.shortString(title: 'Target', description: 'Target highlight element DOM selector string.')
delay: {type: 'integer', minimum: 0, title: 'Delay', description: 'Show the highlight after this many milliseconds. Doesn\'t affect the dim shade cutout highlight method.'}
offset: _.extend _.cloneDeep(PointSchema), {title: 'Offset', description: 'Pointing arrow tip offset in pixels from the default target.', format: null}
rotation: {type: 'number', minimum: 0, title: 'Rotation', description: 'Rotation of the pointing arrow, in radians. PI / 2 points left, PI points up, etc.'}
rotation: {type: 'number', minimum: 0, title: 'Rotation', description: 'Rotation of the pointing arrow, in radians. PI / 2 points left, PI points up, etc.', format: 'radians'}
sides: c.array {title: 'Sides', description: 'Which sides of the target element to point at.'}, {type: 'string', 'enum': ['left', 'right', 'top', 'bottom'], title: 'Side', description: 'A side of the target element to point at.'}
lock: {title: 'Lock', description: 'Whether the interface should be locked so that the player\'s focus is on the script, or specific areas to lock.', type: ['boolean', 'array'], items: {type: 'string', enum: ['surface', 'editor', 'palette', 'hud', 'playback', 'playback-hover', 'level']}}
letterbox: {type: 'boolean', title: 'Letterbox', description: 'Turn letterbox mode on or off. Disables surface and playback controls.'}

View file

@ -102,7 +102,7 @@ DependencySchema = c.object {
LevelComponentSchema = c.object {
title: 'Component'
description: 'A Component which can affect Thang behavior.'
required: ['system', 'name', 'description', 'code', 'dependencies', 'propertyDocumentation', 'codeLanguage']
required: ['system', 'name', 'code']
default:
system: 'ai'
name: 'AttacksSelf'

View file

@ -24,6 +24,10 @@ module.exports =
'editor:edit-level-thang': c.object {required: ['thangID']},
thangID: {type: 'string'}
'editor:level-thang-edited': c.object {required: ['thangData', 'oldPath']},
thangData: {type: 'object'}
oldPath: {type: 'string'}
'editor:level-thang-done-editing': c.object {required: ['thangData', 'oldPath']},
thangData: {type: 'object'}
oldPath: {type: 'string'}

View file

@ -0,0 +1,30 @@
@import "bootstrap/mixins"
@import "bootstrap/variables"
#front-view
h1
text-align: center
margin-top: 0
.platform-choices
a
text-align: center
.panel
@include transition(background-color 0.5s ease)
&:hover
text-decoration: none
.panel
background-color: rgb(230, 230, 255)
.platform-ios
img
transform: scaleY(-1)
@media only screen and (max-width: 800px)
#front-view
#site-slogan
font-size: 30px
margin-bottom: 30px

View file

@ -47,3 +47,17 @@
color: black
text-shadow: 0 1px 0 white
.modal.play-modal
.modal-header
border: 0
text-align: center
padding: 0
margin: 0 25px
h3
margin-bottom: 0
.modal-body
padding-top: 0

View file

@ -16,8 +16,7 @@
height: 100px
overflow: hidden
background: white
border: 1px solid #333
border-radius: 5px
border-radius: 8px
position: relative
-webkit-transition: opacity 0.3s ease-in-out
-moz-transition: opacity 0.3s ease-in-out
@ -46,15 +45,15 @@
.my-team-icon
height: 60px
position: relative
top: -10px
left: 10px
top: -3.5px
left: 13.5px
z-index: 0
.opponent-team-icon
height: 60px
position: relative
top: 10px
right: 10px
top: 16.5px
right: 13.5px
z-index: 0
float: right
-moz-transform: scaleX(-1)
@ -78,19 +77,19 @@
z-index: 1
.name-label
border-bottom: 20px solid lightslategray
height: 0
height: 20px
width: 40%
position: absolute
bottom: 0
color: black
color: white
font-weight: bold
text-shadow: -1px -1px 0px black
text-align: center
z-index: 2
span
position: relative
top: 1px
top: 4px
.code-language
position: absolute
@ -116,9 +115,6 @@
right: 3px
.difficulty
border-top: 25px solid darkgray
border-left: 20px solid transparent
border-right: 20px solid transparent
height: 0
width: 30%
position: absolute
@ -131,17 +127,21 @@
span
position: relative
top: -25px
top: 6px
.play-option
background-image: url(/images/pages/play/ladder/warmup_button.png)
.easy-option .difficulty
border-top: 25px solid limegreen
.easy-option
background-image: url(/images/pages/play/ladder/easy_button.png)
.medium-option .difficulty
border-top: 25px solid darkorange
.medium-option
background-image: url(/images/pages/play/ladder/medium_button.png)
.hard-option .difficulty
border-top: 25px solid black
color: white
.hard-option
background-image: url(/images/pages/play/ladder/hard_button.png)
.difficulty
color: white
.vs
position: absolute

View file

@ -0,0 +1,4 @@
#play-account-modal
.account-view
color: black

View file

@ -0,0 +1,4 @@
#play-achievements-modal
.achievement-view
color: black

View file

@ -0,0 +1,4 @@
#play-heroes-modal
.hero-view
color: black

View file

@ -0,0 +1,8 @@
#play-items-modal
.item-view
width: 420px
float: left
background-color: white
border-radius: 6px
margin: 5px

View file

@ -0,0 +1,4 @@
#play-settings-modal
.settings-view
color: black

View file

@ -0,0 +1,151 @@
@import "app/styles/bootstrap/mixins"
@import "app/styles/bootstrap/variables"
$forestMapWidth: 2500
$forestMapHeight: 1536
$forestMapSeaBackground: #71bad0
$levelDotWidth: 2%
$levelDotHeight: $levelDotWidth * $forestMapWidth / $forestMapHeight
$levelDotZ: $levelDotHeight * 0.25
$levelDotHoverZ: $levelDotZ * 2
$levelDotShadowWidth: 0.8 * $levelDotWidth
$levelDotShadowHeight: 0.8 * $levelDotHeight
$levelClickRadius: 40px
$gameControlSize: 80px
$gameControlMargin: 40px
#world-map-view
width: 100%
height: 100%
background-color: $forestMapSeaBackground
.map
//background: white url("/images/pages/play/map_forest.jpg") no-repeat center center
position: relative
.map-background
width: 100%
height: 100%
.level, .level-shadow
position: absolute
border-radius: 100%
transform: scaleY(0.75)
.level
z-index: 2
width: $levelDotWidth
height: $levelDotHeight
margin-left: -0.5 * $levelDotWidth
margin-bottom: -$levelDotHeight / 3 + $levelDotZ
border: 2px groove white
@include transition(margin-bottom 0.5s ease)
&.disabled
opacity: 0.7
&.first
width: 2 * $levelDotWidth
height: 2 * $levelDotHeight
margin-left: -0.5 * 2 * $levelDotWidth
margin-bottom: -2 * $levelDotHeight / 3 + 2 * $levelDotZ
.level-shadow
z-index: 1
width: $levelDotShadowWidth
height: $levelDotShadowHeight
margin-left: -0.5 * $levelDotShadowWidth
margin-bottom: -$levelDotShadowHeight / 3
background-color: black
box-shadow: 0px 0px 10px black
@include opacity(0.75)
&.first
width: 2 * $levelDotShadowWidth
height: 2 * $levelDotShadowHeight
margin-left: -0.5 * 2 * $levelDotShadowWidth
margin-bottom: -2 * $levelDotShadowHeight / 3
.level:hover
margin-bottom: -$levelDotHeight / 3 + $levelDotHoverZ
.level
a
display: block
padding: $levelClickRadius
margin-left: -0.5 * $levelClickRadius
margin-top: -0.5 * $levelClickRadius
border-radius: $levelClickRadius
&.first a
padding: 2 * $levelClickRadius
margin-left: 2 * -0.5 * $levelClickRadius
margin-top: 2 * -0.5 * $levelClickRadius
border-radius: 2 * $levelClickRadius
.level-info-container
display: none
position: absolute
z-index: 3
padding: 10px 10px 30px 10px
border-image: url(/images/level/popover_background.png) 18 fill round
border-width: 15px
.level-image
float: left
margin-right: 20px
.level-info.complete h3:after
content: " - Complete!"
color: green
.level-info.started h3:after
content: " - Started"
color: desaturate(green, 50%)
.level-info
width: 330px
float: left
h3
margin-top: 0
margin-bottom: 0px
.level-description
color: black
text-shadow: 0 1px 0 white
.campaign-label
text-shadow: 0 1px 0 white
.game-controls
position: absolute
right: 1%
bottom: 1%
button.btn
&:not(:first-child)
margin-left: $gameControlMargin
width: $gameControlSize
height: $gameControlSize
background: url(/images/pages/play/menu_icons.png) no-repeat
background-size: cover
@include transition(0.5s ease)
box-shadow: 0 0 0 #bbf
border: 0
border-radius: 12px
&:hover
box-shadow: 0 0 12px #bbf
&:active
box-shadow: 0 0 20px white
&.heroes
background-position-x: -1 * $gameControlSize
&.achievements
background-position-x: -2 * $gameControlSize
&.account
background-position-x: -3 * $gameControlSize
&.settings
background-position-x: -4 * $gameControlSize

View file

@ -177,7 +177,7 @@ block content
if !editing && !myProfile
button#contact-candidate.btn.btn-large.btn-inverse.flat-button
span(data-i18n="account_profile.contact") Contact
| #{profile.name.split(' ')[0]}
| #{(profile.name || user.get('name') || 'Anonymous').split(' ')[0]}
if me.isAdmin()
select#admin-contact.form-control
for contact in adminContacts

View file

@ -24,9 +24,14 @@ block modal-body-content
div.alert.alert-info
strong Shift-drag
| to select
div.alert.alert-info
strong Enter
| to confirm
if flexibleRegion
div.alert.alert-info
strong Alt-shift-drag
| to select ratio
else
div.alert.alert-info
strong Enter
| to confirm
canvas(width=924, height=589)
block modal-footer-content

View file

@ -0,0 +1,28 @@
extends /templates/base
block content
.page-header
h1#site-slogan
span(data-i18n="home.slogan") Learn to Code by Playing a Game
small.spl.spr -
small free!
.row.platform-choices
.col-xs-6.platform-ios
a(href="#")
.panel.panel-default
.panel-body
h1 Play on iPad
img.img-responsive(src="/images/pages/front/play_web.jpg")
p.lead Get the app!
.col-xs-6.platform-web
a(href="/play-hero")
.panel.panel-default
.panel-body
h1 Play on web
img.img-responsive(src="/images/pages/front/play_web.jpg")
p.lead Play right now!
.clearfix

26
app/templates/front.jade Normal file
View file

@ -0,0 +1,26 @@
extends /templates/base
block content
.page-header
h1#site-slogan
span(data-i18n="home.slogan") Learn to Code by Playing a Game
small.spl.spr -
small free!
.row.platform-choices
.col-xs-6.platform-ios
a(href="#")
.panel.panel-default
.panel-body
h1 Play on iPad
em - get the app!
.col-xs-6.platform-web
a(href="/play")
.panel.panel-default
.panel-body
h1 Play on web
em - play right now!
.clearfix

View file

@ -6,14 +6,20 @@
if closeButton
.button.close(type="button", data-dismiss="modal", aria-hidden="true") &times;
block modal-header-content
h3 man bites God
if headerContent
h3!= headerContent
else
h3 man bites God
block modal-body
.modal-body
block modal-body-content
p Man Bites God are the bad boys of the Melbourne live music and comedy scene. It is like being drowned in a bathtub of harmony.
img(src="http://www.manbitesgod.com/images/picturecoupleb.jpg")
img(src="http://www.manbitesgod.com/images/manrantb.jpg")
if bodyContent
div!= bodyContent
else
p Man Bites God are the bad boys of the Melbourne live music and comedy scene. It is like being drowned in a bathtub of harmony.
img(src="http://www.manbitesgod.com/images/picturecoupleb.jpg")
img(src="http://www.manbitesgod.com/images/manrantb.jpg")
.modal-body.wait.secret
block modal-body-wait-content

View file

@ -55,6 +55,18 @@ block content
|
a(href="http://blog.codecombat.com/6-programming-languages-one-victor-codecombats-newest-tournament", data-i18n="ladder.tournament_blurb_blog") on our blog
| .
p
strong Tournament ended!
a(href="#winners") Behold the winners
| . Thanks for playing! You can
strong still play
| Criss-Cross and all of our other
a(href="/play/ladder") multiplayer arenas
| .
p
| Want to commiserate? Head over to
a(href="http://discourse.codecombat.com/") the forum
| and discuss your strategies, your triumphs, and your turmoils.
div#columns.row
div.column.col-md-2
@ -86,7 +98,7 @@ block content
if level.get('name') == 'Greed'
li
a(href="#rules", data-toggle="tab", data-i18n="ladder.rules") Rules
if level.get('name') == 'Greed' || (level.get('name') == 'Criss-Cross!!!')
if level.get('name') == 'Greed' || (level.get('name') == 'Criss-Cross')
li
a(href="#winners", data-toggle="tab", data-i18n="ladder.winners") Winners
@ -725,7 +737,7 @@ block content
a(href="http://discourse.codecombat.com/") Discourse forum
| .
if level.get('name') == 'Greed' || level.get('name') == 'Criss-Cross!!!'
if level.get('name') == 'Greed' || level.get('name') == 'Criss-Cross'
.tab-pane.well#winners
h1(data-i18n="ladder.winners") Winners
@ -734,9 +746,15 @@ block content
tr
th(data-i18n="ladder_prizes.rank") Rank
th Human
th Human wins/losses/ties
if level.get('name') == 'Greed'
th Human wins/losses/ties
else
th Human score
th Ogre
th Ogre wins/losses/ties
if level.get('name') == 'Greed'
th Ogre wins/losses/ties
else
th Ogre score
th Spectate
tbody
each human, index in winners.humans
@ -744,20 +762,28 @@ block content
tr
td= human.rank
td= human.name
td
span.win= human.wins
| -
span.loss= human.losses
| -
span.tie= 377 - human.wins - human.losses
if level.get('name') == 'Greed'
td
span.win= human.wins
| -
span.loss= human.losses
| -
span.tie= 377 - human.wins - human.losses
else
td
span= Math.round(100 * human.score)
if ogre
td= ogre.name
td
span.win= ogre.wins
| -
span.loss= ogre.losses
| -
span.tie= 407 - ogre.wins - ogre.losses
if level.get('name') == 'Greed'
td
span.win= ogre.wins
| -
span.loss= ogre.losses
| -
span.tie= 407 - ogre.wins - ogre.losses
else
td
span= Math.round(100 * ogre.score)
td
a(href="/play/spectate/" + level.get('slug') + "?session-one=" + human.sessionID + "&session-two=" + ogre.sessionID) Watch the battle
else

View file

@ -37,7 +37,6 @@ block modal-body-content
//span.code-language(style="background-image: url(/images/common/code_languages/javascript_small.png)")
div.difficulty
span(data-i18n="ladder.warmup") Warmup
div(data-i18n="ladder.vs").vs VS
if challengers.easy
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.easy.sessionID}")
@ -54,7 +53,6 @@ block modal-body-content
span.code-language(style="background-image: url(/images/common/code_languages/" + challengers.easy.codeLanguage + "_small.png)")
div.difficulty
span(data-i18n="general.easy") Easy
div(data-i18n="ladder.vs").vs VS
if challengers.medium
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.medium.sessionID}")
@ -71,7 +69,6 @@ block modal-body-content
span.code-language(style="background-image: url(/images/common/code_languages/" + challengers.medium.codeLanguage + "_small.png)")
div.difficulty
span(data-i18n="general.medium") Medium
div(data-i18n="ladder.vs").vs VS
if challengers.hard
a(href="/play/level/#{levelID}?team=#{teamID}&opponent=#{challengers.hard.sessionID}")
@ -88,6 +85,5 @@ block modal-body-content
span.code-language(style="background-image: url(/images/common/code_languages/" + challengers.hard.codeLanguage + "_small.png)")
div.difficulty
span(data-i18n="general.hard") Hard
div(data-i18n="ladder.vs").vs VS
block modal-footer

View file

@ -0,0 +1,7 @@
extends /templates/modal/modal_base
block modal-header-content
h3(data-i18n="play.account") Account
block modal-body-content
p TODO: show all dem account

View file

@ -0,0 +1,7 @@
extends /templates/modal/modal_base
block modal-header-content
h3(data-i18n="play.achievements") Achievements
block modal-body-content
p TODO: show all dem achievements

View file

@ -0,0 +1,7 @@
extends /templates/modal/modal_base
block modal-header-content
h3(data-i18n="play.heroes") Heroes
block modal-body-content
p TODO: show all dem heroes

View file

@ -0,0 +1,17 @@
extends /templates/modal/modal_base
block modal-header-content
h3(data-i18n="play.items") Items
block modal-body-content
ul.nav.nav-tabs
for slotGroup, index in slotGroupsArray
li(class=index ? "" : "active")
a(href="#slot-group-" + slotGroup, data-toggle="tab")
span= slotGroupsNames[index]
.tab-content
for slotGroup, index in slotGroupsArray
.tab-pane(id="slot-group-" + slotGroup, class=index ? "" : "active")
h3 buy some #{slotGroupsNames[index]} yo:
for item in slotGroups[slotGroup]
.replace-me(data-item-id=item.id)

View file

@ -0,0 +1,7 @@
extends /templates/modal/modal_base
block modal-header-content
h3(data-i18n="play.settings") Settings
block modal-body-content
p TODO: show all dem settings

View file

@ -0,0 +1,34 @@
.map
img.map-background(src="/images/pages/play/map_forest.jpg", alt="")
each campaign in campaigns
each level in campaign.levels
div(style="left: #{level.x}%; bottom: #{level.y}%; background-color: #{campaign.color}", class="level" + (level.first ? " first" : "") + (level.disabled ? " disabled" : ""), data-level-id=level.id)
a(href=level.disabled ? "/play" : "/play/#{level.levelPath || 'level'}/#{level.id}", disabled=level.disabled, class=levelStatusMap[level.id] || "")
div(style="left: #{level.x}%; bottom: #{level.y}%", class="level-shadow" + (level.first ? " first" : ""))
.level-info-container(data-level-id=level.id)
if level.image
img.level-image(src="#{level.image}", alt="#{level.name}")
else
img.level-image(src="/images/generic-icon.png", alt="#{level.name}")
div(class="level-info " + (levelStatusMap[level.id] || ""))
h3= level.name + (level.disabled ? " (Coming soon!)" : "")
.level-description= level.description
span(data-i18n="play.level_difficulty") Difficulty:
each i in Array(level.difficulty)
i.icon-star
- var playCount = levelPlayCountMap[level.id]
if playCount
div
span.spr #{playCount.sessions}
span(data-i18n="play.players") players
span.spr , #{Math.round(playCount.playtime / 3600)}
span(data-i18n="play.hours_played") hours played
.campaign-label(style="color: #{campaign.color}")= campaign.name
.game-controls
button.btn.items(data-toggle='coco-modal', data-target='play/modal/PlayItemsModal', data-i18n="[title]play.items")
button.btn.heroes(data-toggle='coco-modal', data-target='play/modal/PlayHeroesModal', data-i18n="[title]play.heroes")
button.btn.achievements(data-toggle='coco-modal', data-target='play/modal/PlayAchievementsModal', data-i18n="[title]play.achievements")
button.btn.account(data-toggle='coco-modal', data-target='play/modal/PlayAccountModal', data-i18n="[title]play.account")
button.btn.settings(data-toggle='coco-modal', data-target='play/modal/PlaySettingsModal', data-i18n="[title]play.settings")

View file

@ -0,0 +1,34 @@
RootView = require 'views/kinds/RootView'
template = require 'templates/front-view'
{me} = require '/lib/auth'
ModalView = require 'views/kinds/ModalView'
module.exports = class FrontView extends RootView
id: 'front-view'
template: template
events:
'click .platform-ios a': 'onIOSClicked'
getRenderData: ->
c = super()
if $.browser
majorVersion = $.browser.versionNumber
c.isOldBrowser = true if $.browser.mozilla && majorVersion < 21
c.isOldBrowser = true if $.browser.chrome && majorVersion < 17
c.isOldBrowser = true if $.browser.safari && majorVersion < 6
else
console.warn 'no more jquery browser version...'
c
afterRender: ->
super()
onIOSClicked: (e) ->
header = 'Sorry, the iPad app isn\'t ready yet'
body = '''
<p class="lead">We are working on it!</p>
<p>For now, try playing on the web, and totally sign up (with emails enabled) so you can be the first to hear when it is ready.</p>
'''
notImplementedModal = new ModalView headerContent: header, bodyContent: body
@openModalView notImplementedModal

View file

@ -26,7 +26,7 @@ module.exports = class NewLevelComponentModal extends ModalView
component = new LevelComponent()
component.set 'system', system
component.set 'name', name
component.set 'code', component.get('code').replace(/AttacksSelf/g, name)
component.set 'code', component.get('code', true).replace(/AttacksSelf/g, name)
component.set 'permissions', [{access: 'owner', target: me.id}] # Private until saved in a published Level
res = component.save()
return unless res

View file

@ -31,11 +31,11 @@ module.exports = class WorldSelectModal extends ModalView
getRenderData: (c={}) =>
c = super(c)
c.selectingPoint = @dataType is 'point'
c.flexibleRegion = @dataType is 'region'
c
afterInsert: ->
super()
window.e = @$el
@initSurface()
# surface setup
@ -54,7 +54,6 @@ module.exports = class WorldSelectModal extends ModalView
thangTypes: @supermodel.getModels(ThangType)
showInvisible: true
}
window.s = @surface
@surface.playing = false
@surface.setWorld @world
@surface.camera.zoomTo({x: 262, y: -164}, 1.66, 0)

View file

@ -19,6 +19,8 @@ module.exports = class LevelThangEditView extends CocoView
'click #thang-type-link span': 'toggleTypeEdit'
'blur #thang-name-link input': 'toggleNameEdit'
'blur #thang-type-link input': 'toggleTypeEdit'
'keydown #thang-name-link input': 'toggleNameEditIfReturn'
'keydown #thang-type-link input': 'toggleTypeEditIfReturn'
constructor: (options) ->
options ?= {}
@ -27,6 +29,7 @@ module.exports = class LevelThangEditView extends CocoView
@thangData = $.extend true, {}, options.thangData ? {}
@level = options.level
@oldPath = options.oldPath
@reportChanges = _.debounce @reportChanges, 1000
getRenderData: (context={}) ->
context = super(context)
@ -83,5 +86,16 @@ module.exports = class LevelThangEditView extends CocoView
if thangType and wasEditing
@thangData.thangType = thangType.get('original')
toggleNameEditIfReturn: (e) ->
@$el.find('#thang-name-link input').blur() if e.which is 13
toggleTypeEditIfReturn: (e) ->
@$el.find('#thang-type-link input').blur() if e.which is 13
onComponentsChanged: (components) =>
@thangData.components = components
@reportChanges()
reportChanges: =>
return if @destroyed
Backbone.Mediator.publish 'editor:level-thang-edited', {thangData: $.extend(true, {}, @thangData), oldPath: @oldPath}

View file

@ -16,7 +16,7 @@ MOVE_MARGIN = 0.15
MOVE_SPEED = 13
# Let us place these on top of other Thangs
overlappableThangTypeNames = ['Torch', 'Chains', 'Bird', 'Cloud 1', 'Cloud 2', 'Cloud 3', 'Waterfall', 'Obstacle']
overlappableThangTypeNames = ['Torch', 'Chains', 'Bird', 'Cloud 1', 'Cloud 2', 'Cloud 3', 'Waterfall', 'Obstacle', 'Electrowall']
class ThangTypeSearchCollection extends CocoCollection
url: '/db/thang.type?project=original,name,version,slug,kind,components'
@ -33,12 +33,14 @@ module.exports = class ThangsTabView extends CocoView
'surface:mouse-over': 'onSurfaceMouseOver'
'surface:mouse-out': 'onSurfaceMouseOut'
'editor:edit-level-thang': 'editThang'
'editor:level-thang-edited': 'onLevelThangEdited'
'editor:level-thang-done-editing': 'onLevelThangDoneEditing'
'editor:view-switched': 'onViewSwitched'
'sprite:dragged': 'onSpriteDragged'
'sprite:mouse-up': 'onSpriteMouseUp'
'sprite:mouse-down': 'onSpriteMouseDown'
'sprite:double-clicked': 'onSpriteDoubleClicked'
'surface:stage-mouse-down': 'onStageMouseDown'
'surface:stage-mouse-up': 'onStageMouseUp'
'editor:random-terrain-generated': 'onRandomTerrainGenerated'
@ -225,8 +227,17 @@ module.exports = class ThangsTabView extends CocoView
# if e.originalEvent.nativeEvent.button == 2
# @onSpriteContextMenu e
onStageMouseDown: (e) ->
return unless @addThangSprite?.thangType.get('kind') is 'Wall'
@surface.camera.dragDisabled = true
@paintingWalls = true
onStageMouseUp: (e) ->
if @addThangSprite
if @paintingWalls
# We need to stop painting walls, but we may also stop in onExtantThangSelected.
_.defer =>
@paintingWalls = @paintedWalls = @surface.camera.dragDisabled = false
else if @addThangSprite
@surface.camera.lock()
# If we click on the background, we need to add @addThangSprite, but not if onSpriteMouseUp will fire.
@backgroundAddClickTimeout = _.defer => @onExtantThangSelected {}
@ -295,7 +306,12 @@ module.exports = class ThangsTabView extends CocoView
@selectedExtantSprite?.setNameLabel? null unless @selectedExtantSprite is e.sprite
@selectedExtantThang = e.thang
@selectedExtantSprite = e.sprite
if e.thang and (key.alt or key.meta)
paintedAWall = @paintedWalls
@paintingWalls = @paintedWalls = @surface.camera.dragDisabled = false
if paintedAWall
# Skip adding a wall now, because we already dragged to add one
null
else if e.thang and (key.alt or key.meta)
# We alt-clicked, so create a clone addThang
@selectAddThangType e.thang.spriteName, @selectedExtantThang
else if @justAdded()
@ -389,6 +405,16 @@ module.exports = class ThangsTabView extends CocoView
wop = @surface.camera.screenToWorld x: e.x, y: e.y
wop.z = 0.5
@adjustThangPos @addThangSprite, @addThangSprite.thang, wop
if @paintingWalls
unless _.find @surface.spriteBoss.spriteArray, ((sprite) =>
sprite.thangType.get('kind') is 'Wall' and
Math.abs(sprite.thang.pos.x - @addThangSprite.thang.pos.x) < 2 and
Math.abs(sprite.thang.pos.y - @addThangSprite.thang.pos.y) < 2 and
sprite isnt @addThangSprite
)
@addThang @addThangType, @addThangSprite.thang.pos
@lastAddTime = new Date()
@paintedWalls = true
null
onSurfaceMouseOver: (e) ->
@ -427,6 +453,7 @@ module.exports = class ThangsTabView extends CocoView
deleteSelectedExtantThang: (e) =>
return if $(e.target).hasClass 'treema-node'
return unless @selectedExtantThang
thang = @getThangByID(@selectedExtantThang.id)
@thangsTreema.delete(@pathForThang(thang))
Thang.resetThangIDs() # TODO: find some way to do this when we delete from treema, too
@ -547,14 +574,19 @@ module.exports = class ThangsTabView extends CocoView
onLevelThangDoneEditing: (e) ->
@removeSubView @editThangView
@editThangView = null
newThang = e.thangData
@updateEditedThang e.thangData, e.oldPath
@$el.find('>').show()
onLevelThangEdited: (e) ->
@updateEditedThang e.thangData, e.oldPath
updateEditedThang: (newThang, oldPath) ->
@hush = true
@thangsTreema.delete e.oldPath
@thangsTreema.delete oldPath
@populateFoldersForThang(newThang)
@thangsTreema.set(@pathForThang(newThang), newThang)
@hush = false
@onThangsChanged()
@$el.find('>').show()
preventDefaultContextMenu: (e) ->
return unless $(e.target).closest('#canvas-wrapper').length

View file

@ -41,6 +41,7 @@ module.exports = class GameMenuModal extends ModalView
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-tab-switch', volume: 1
onHidden: ->
super()
subview.onHidden?() for subviewKey, subview of @subviews
me.patch()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1

View file

@ -176,7 +176,7 @@ module.exports = class CocoView extends Backbone.View
target = elem.data('target')
Modal = require 'views/'+target
e.stopPropagation()
@openModalView new Modal
@openModalView new Modal supermodel: @supermodal
openModalView: (modalView, softly=false) ->
return if waitingModal # can only have one waiting at once

View file

@ -7,6 +7,7 @@ module.exports = class ModalView extends CocoView
modalWidthPercent: null
plain: false
instant: false
template: require 'templates/modal/modal_base'
events:
'click a': 'toggleModal'
@ -26,6 +27,8 @@ module.exports = class ModalView extends CocoView
getRenderData: (context={}) ->
context = super(context)
context.closeButton = @closeButton
context.headerContent = @options.headerContent
context.bodyContent = @options.bodyContent
context
subscriptions:

View file

@ -0,0 +1,472 @@
RootView = require 'views/kinds/RootView'
template = require 'templates/play/world-map-view'
LevelSession = require 'models/LevelSession'
CocoCollection = require 'collections/CocoCollection'
AudioPlayer = require 'lib/AudioPlayer'
class LevelSessionsCollection extends CocoCollection
url: ''
model: LevelSession
constructor: (model) ->
super()
@url = "/db/user/#{me.id}/level.sessions?project=state.complete,levelID"
module.exports = class MainPlayView extends RootView
id: 'world-map-view'
template: template
events:
'click .map': 'onClickMap'
'click .game-controls button': 'onClickGameControl'
'mouseenter .level a': 'onMouseEnterLevel'
'mouseleave .level a': 'onMouseLeaveLevel'
'mousemove .map': 'onMouseMoveMap'
constructor: (options) ->
super options
@levelStatusMap = {}
@levelPlayCountMap = {}
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', null, 0).model
@listenToOnce @sessions, 'sync', @onSessionsLoaded
@getLevelPlayCounts()
$(window).on 'resize', @onWindowResize
getLevelPlayCounts: ->
success = (levelPlayCounts) =>
return if @destroyed
for level in levelPlayCounts
@levelPlayCountMap[level._id] = playtime: level.playtime, sessions: level.sessions
@render() if @supermodel.finished()
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()
getRenderData: (context={}) ->
context = super(context)
context.campaigns = campaigns
for campaign in context.campaigns
for level in campaign.levels
level.x ?= 10 + 80 * Math.random()
level.y ?= 10 + 80 * Math.random()
context.levelStatusMap = @levelStatusMap
context.levelPlayCountMap = @levelPlayCountMap
context
afterRender: ->
super()
@onWindowResize()
_.defer => @$el.find('.game-controls button').tooltip() # Have to defer or i18n doesn't take effect.
onSessionsLoaded: (e) ->
for session in @sessions.models
@levelStatusMap[session.get('levelID')] = if session.get('state')?.complete then 'complete' else 'started'
@render()
onClickMap: (e) ->
# 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"
onClickGameControl: (e) ->
onMouseEnterLevel: (e) ->
levelID = $(e.target).parents('.level').data('level-id')
@$levelInfo = @$el.find(".level-info-container[data-level-id=#{levelID}]").show()
@adjustLevelInfoPosition e
onMouseLeaveLevel: (e) ->
levelID = $(e.target).parents('.level').data('level-id')
@$el.find(".level-info-container[data-level-id='#{levelID}']").hide()
onMouseMoveMap: (e) ->
@adjustLevelInfoPosition e
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) =>
forestMapWidth = 2401
forestMapHeight = 1536
aspectRatio = forestMapWidth / forestMapHeight
pageWidth = $(window).width()
pageHeight = $(window).height()
widthRatio = pageWidth / forestMapWidth
heightRatio = pageHeight / forestMapHeight
if widthRatio > heightRatio
resultingWidth = pageWidth
resultingHeight = resultingWidth / aspectRatio
else
resultingHeight = pageHeight
resultingWidth = resultingHeight * aspectRatio
resultingMarginX = (pageWidth - resultingWidth) / 2
resultingMarginY = (pageHeight - resultingHeight) / 2
@$el.find('.map').css(width: resultingWidth, height: resultingHeight, 'margin-left': resultingMarginX, 'margin-top': resultingMarginY)
tutorials = [
{
name: 'Rescue Mission'
difficulty: 1
id: 'rescue-mission'
image: '/file/db/level/52740644904ac0411700067c/rescue_mission_icon.png'
description: 'Tharin has been captured! Start here.'
first: true
x: 17.23
y: 36.94
}
{
name: 'Grab the Mushroom'
difficulty: 1
id: 'grab-the-mushroom'
image: '/file/db/level/529662dfe0df8f0000000007/grab_the_mushroom_icon.png'
description: 'Grab a powerup and smash a big ogre.'
x: 22.6
y: 35.1
}
{
name: 'Drink Me'
difficulty: 1
id: 'drink-me'
image: '/file/db/level/525dc5589a0765e496000006/drink_me_icon.png'
description: 'Drink up and slay two munchkins.'
x: 27.74
y: 35.17
}
{
name: 'Taunt the Guards'
difficulty: 1
id: 'taunt-the-guards'
image: '/file/db/level/5276c9bdcf83207a2801ff8f/taunt_icon.png'
description: 'Tharin, if clever, can escape with Phoebe.'
x: 32.7
y: 36.7
}
{
name: 'It\'s a Trap'
difficulty: 1
id: 'its-a-trap'
image: '/file/db/level/528aea2d7f37fc4e0700016b/its_a_trap_icon.png'
description: 'Organize a dungeon ambush with archers.'
x: 37.6
y: 40.0
}
{
name: 'Break the Prison'
difficulty: 1
id: 'break-the-prison'
image: '/file/db/level/5275272c69abdcb12401216e/break_the_prison_icon.png'
description: 'More comrades are imprisoned!'
x: 44.1
y: 39.5
}
{
name: 'Taunt'
difficulty: 1
id: 'taunt'
image: '/file/db/level/525f150306e1ab0962000018/taunt_icon.png'
description: 'Taunt the ogre to claim victory.'
x: 38.5
y: 44.1
}
{
name: 'Cowardly Taunt'
difficulty: 1
id: 'cowardly-taunt'
image: '/file/db/level/525abfd9b12777d78e000009/cowardly_taunt_icon.png'
description: 'Lure infuriated ogres to their doom.'
x: 39.2
y: 50.1
}
{
name: 'Commanding Followers'
difficulty: 1
id: 'commanding-followers'
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
description: 'Lead allied soldiers into battle.'
x: 39.1
y: 54.7
}
{
name: 'Mobile Artillery'
difficulty: 1
id: 'mobile-artillery'
image: '/file/db/level/525085419851b83f4b000001/mobile_artillery_icon.png'
description: 'Blow ogres up!'
x: 39.5
y: 60.2
}
]
experienced = [
{
name: 'Hunter Triplets'
difficulty: 2
id: 'hunter-triplets'
image: '/file/db/level/526711d9add4f8965f000002/hunter_triplets_icon.png'
description: 'Three soldiers go ogre hunting.'
x: 51.76
y: 35.5
}
{
name: 'Emphasis on Aim'
difficulty: 2
id: 'emphasis-on-aim'
image: '/file/db/level/525f384d96cd77000000000f/munchkin_masher_icon.png'
description: 'Choose your targets carefully.'
x: 61.47
y: 33.46
}
{
name: 'Zone of Danger'
difficulty: 3
id: 'zone-of-danger'
image: '/file/db/level/526ae95c1e5cd30000000008/zone_of_danger_icon.png'
description: 'Target the ogres swarming into arrow range.'
x: 65.72
y: 26.72
}
{
name: 'Molotov Medic'
difficulty: 2
id: 'molotov-medic'
image: '/file/db/level/52602ecb026e8481e7000001/generic_1.png'
description: 'Tharin must play support in this dungeon battle.'
x: 70.95
y: 18.64
}
{
name: 'Gridmancer'
difficulty: 5
id: 'gridmancer'
image: '/file/db/level/52ae2460ef42c52f13000008/gridmancer_icon.png'
description: 'Super algorithm challenge level!'
x: 61.41
y: 17.22
}
]
arenas = [
{
name: 'Criss-Cross'
difficulty: 5
id: 'criss-cross'
image: '/file/db/level/528aea2d7f37fc4e0700016b/its_a_trap_icon.png'
description: 'Participate in a bidding war with opponents to reach the other side!'
levelPath: 'ladder'
x: 49.43
y: 21.48
}
{
name: 'Greed'
difficulty: 4
id: 'greed'
image: '/file/db/level/526fd3043c637ece50001bb2/the_herd_icon.png'
description: 'Liked Dungeon Arena and Gold Rush? Put them together in this economic arena!'
levelPath: 'ladder'
x: 45.00
y: 23.34
}
{
name: 'Dungeon Arena'
difficulty: 3
id: 'dungeon-arena'
image: '/file/db/level/526ae95c1e5cd30000000008/zone_of_danger_icon.png'
description: 'Play head-to-head against fellow Wizards in a dungeon melee!'
levelPath: 'ladder'
x: 36.82
y: 23.17
}
{
name: 'Gold Rush'
difficulty: 3
id: 'gold-rush'
image: '/file/db/level/52602ecb026e8481e7000001/generic_1.png'
description: 'Prove you are better at collecting gold than your opponent!'
levelPath: 'ladder'
x: 30.8
y: 16.87
}
{
name: 'Brawlwood'
difficulty: 4
id: 'brawlwood'
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
description: 'Combat the armies of other Wizards in a strategic forest arena! (Fast computer required.)'
levelPath: 'ladder'
x: 41.93
y: 12.79
}
{
name: 'Sky Span (Testing)'
difficulty: 3
id: 'sky-span'
image: '/file/db/level/526ae95c1e5cd30000000008/zone_of_danger_icon.png'
description: 'Preview version of an upgraded Dungeon Arena. Help us with hero balance before release!'
levelPath: 'ladder'
x: 53.12
y: 11.37
}
]
classicAlgorithms = [
{
name: 'Bubble Sort Bootcamp Battle'
difficulty: 3
id: 'bubble-sort-bootcamp-battle'
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
description: 'Write a bubble sort to organize your soldiers. - by Alexandru Caciulescu'
x: 26.37
y: 93.02
}
{
name: 'Ogres of Hanoi'
difficulty: 3
id: 'ogres-of-hanoi'
image: '/file/db/level/526fd3043c637ece50001bb2/the_herd_icon.png'
description: 'Transfer a stack of ogres while preserving their honor. - by Alexandru Caciulescu'
x: 32.39
y: 92.67
}
{
name: 'Danger! Minefield'
difficulty: 3
id: 'danger-minefield'
image: '/file/db/level/526bda3fe79aefde2a003e36/mobile_artillery_icon.png'
description: 'Learn how to find prime numbers while defusing mines! - by Alexandru Caciulescu'
x: 38.07
y: 92.76
}
{
name: 'K-means++ Cluster Wars'
difficulty: 4
id: 'k-means-cluster-wars'
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
description: 'Learn cluster analysis while leading armies into battle! - by Alexandru Caciulescu'
x: 43.75
y: 90.36
}
{
name: 'Quicksort the Spiral'
difficulty: 3
id: 'quicksort-the-spiral'
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
description: 'Learn Quicksort while sorting a spiral of ogres! - by Alexandru Caciulescu'
x: 48.97
y: 87.08
}
{
name: 'Minimax Tic-Tac-Toe'
difficulty: 4
id: 'minimax-tic-tac-toe'
image: '/file/db/level/525ef8ef06e1ab0962000003/commanding_followers_icon.png'
description: 'Learn how to make a game AI with the Minimax algorithm. - by Alexandru Caciulescu'
x: 55.96
y: 82.73
}
]
playerCreated = [
{
name: 'Extra Extrapolation'
difficulty: 2
id: 'extra-extrapolation'
image: '/file/db/level/526bda3fe79aefde2a003e36/mobile_artillery_icon.png'
description: 'Predict your target\'s position for deadly aim. - by Sootn'
x: 42.67
y: 67.98
}
{
name: 'The Right Route'
difficulty: 1
id: 'the-right-route'
image: '/file/db/level/526fd3043c637ece50001bb2/the_herd_icon.png'
description: 'Strike at the weak point in an array of enemies. - by Aftermath'
x: 47.38
y: 70.55
}
{
name: 'Sword Loop'
difficulty: 2
id: 'sword-loop'
image: '/file/db/level/525dc5589a0765e496000006/drink_me_icon.png'
description: 'Kill the ogres and save the peasants with for-loops. - by Prabh Simran Singh Baweja'
x: 52.66
y: 69.66
}
{
name: 'Coin Mania'
difficulty: 2
id: 'coin-mania'
image: '/file/db/level/529662dfe0df8f0000000007/grab_the_mushroom_icon.png'
description: 'Learn while-loops to grab coins and potions. - by Prabh Simran Singh Baweja'
x: 58.46
y: 66.38
}
{
name: 'Find the Spy'
difficulty: 2
id: 'find-the-spy'
image: '/file/db/level/526ae95c1e5cd30000000008/zone_of_danger_icon.png'
description: 'Identify the spies hidden among your soldiers - by Nathan Gossett'
x: 63.11
y: 62.74
}
{
name: 'Harvest Time'
difficulty: 2
id: 'harvest-time'
image: '/file/db/level/529662dfe0df8f0000000007/grab_the_mushroom_icon.png'
description: 'Collect a hundred mushrooms in just five lines of code - by Nathan Gossett'
x: 69.19
y: 60.61
}
{
name: 'Guide Everyone Home'
difficulty: 2
id: 'guide-everyone-home'
image: '/file/db/level/52740644904ac0411700067c/rescue_mission_icon.png'
description: 'Fetch the wizards teleporting into the area - by Nathan Gossett'
x: 77.54
y: 65.94
}
{
name: "Let's go Fly a Kite"
difficulty: 3
id: 'lets-go-fly-a-kite'
image: '/file/db/level/526711d9add4f8965f000002/hunter_triplets_icon.png'
description: 'There is a horde of ogres marching on your village. Stay out of reach and use your bow to take them out! - by Danny Whittaker'
x: 84.29
y: 61.23
}
]
campaigns = [
{id: 'beginner', name: 'Beginner Campaign', description: '... in which you learn the wizardry of programming.', levels: tutorials, color: "rgb(255, 80, 60)"}
{id: 'multiplayer', name: 'Multiplayer Arenas', description: '... in which you code head-to-head against other players.', levels: arenas, color: "rgb(80, 5, 60)"}
{id: 'dev', name: 'Random Harder Levels', description: '... in which you learn the interface while doing something a little harder.', levels: experienced, color: "rgb(80, 60, 255)"}
{id: 'classic' ,name: 'Classic Algorithms', description: '... in which you learn the most popular algorithms in Computer Science.', levels: classicAlgorithms, color: "rgb(110, 80, 120)"}
{id: 'player_created', name: 'Player-Created', description: '... in which you battle against the creativity of your fellow <a href=\"/contribute#artisan\">Artisan Wizards</a>.', levels: playerCreated, color: "rgb(160, 160, 180)"}
]

View file

@ -1,4 +1,4 @@
module.exports = results = greed: {}
module.exports = results = greed: {}, 'criss-cross': {}
results.greed.humans = [
{team: 'humans', rank: 1, sessionID: '5381e3537585483905a829c1', name: 'Wizard Dude', playtime: 63184, wins: 363, losses: 0, score: 363}
@ -550,3 +550,199 @@ results.greed.ogres = [
{team: 'ogres', rank: 269, sessionID: '537b96b16c13497e05de82a8', name: 'Krris', playtime: 2618, wins: 0, losses: 379, score: -379}
{team: 'ogres', rank: 270, sessionID: '537bc1b81db8c8ac063a3b7b', name: 'jpiasetz', playtime: 14565, wins: 0, losses: 380, score: -380}
]
results['criss-cross'].humans = [
{team: 'humans', rank: 1, sessionID: '53f63c00f7bc7336054f14f5', codeLanguage: 'javascript', name: 'mdz', score: 89.27983686}
{team: 'humans', rank: 2, sessionID: '53f5fdb054e4f234059ff58d', codeLanguage: 'javascript', name: 'Nafaya', score: 84.77623255}
{team: 'humans', rank: 3, sessionID: '53f4c7f454e4f234059e97a0', codeLanguage: 'javascript', name: 'nino48', score: 84.62650458}
{team: 'humans', rank: 4, sessionID: '53f66c3af7bc7336054f4b93', codeLanguage: 'javascript', name: 'Cracker', score: 82.04044463}
{team: 'humans', rank: 5, sessionID: '53f3b7751171a83405504419', codeLanguage: 'javascript', name: 'c11ris', score: 68.68840693}
{team: 'humans', rank: 6, sessionID: '5400515cff5d7535058f274e', codeLanguage: 'javascript', name: 'fireantik', score: 67.38125522}
{team: 'humans', rank: 7, sessionID: '53f6924ff7bc7336054f6007', codeLanguage: 'javascript', name: 'Alexei2', score: 66.05333713}
{team: 'humans', rank: 8, sessionID: '53f4c91c54e4f234059e9824', codeLanguage: 'javascript', name: 'Mortimer Blackwood', score: 65.94607122}
{team: 'humans', rank: 9, sessionID: '53a35c928dd4b200006b0573', codeLanguage: 'python', name: 'Nick', score: 63.06756959}
{team: 'humans', rank: 10, sessionID: '53f6c36ffda22e3305c025cb', codeLanguage: 'javascript', name: 'lichens', score: 60.19465423}
{team: 'humans', rank: 11, sessionID: '53f397aae7a7643005c042f7', codeLanguage: 'javascript', name: 'qwe', score: 60.03001559}
{team: 'humans', rank: 12, sessionID: '53f45a49fda22e3305bd9009', codeLanguage: 'javascript', name: 'paulgator', score: 59.8852267}
{team: 'humans', rank: 13, sessionID: '5406519efcbd8f33059c4ea8', codeLanguage: 'javascript', name: 'shadowfire', score: 59.61113289}
{team: 'humans', rank: 14, sessionID: '53ac4b7123798d3605a87f9f', codeLanguage: 'javascript', name: 'DollarAkshay', score: 56.10811426}
{team: 'humans', rank: 15, sessionID: '53f7d4dbbc7e716d14e80de6', codeLanguage: 'javascript', name: 'cholesky', score: 55.27757899}
{team: 'humans', rank: 16, sessionID: '53f39df01171a834055013df', codeLanguage: 'javascript', name: 'Wizard Dude', score: 55.22843626}
{team: 'humans', rank: 17, sessionID: '53b2ba14102a853605e48f39', codeLanguage: 'javascript', name: 'nemoyatpeace', score: 54.3862373}
{team: 'humans', rank: 18, sessionID: '53f6be67fda22e3305c02523', codeLanguage: 'javascript', name: 'Ibyoki', score: 54.28563847}
{team: 'humans', rank: 19, sessionID: '53f554c6d822c23505b7b48d', codeLanguage: 'javascript', name: 'Valiant', score: 53.70432642}
{team: 'humans', rank: 20, sessionID: '53ba3f1194abf748058eb864', codeLanguage: 'javascript', name: 'Jex', score: 51.53868217}
{team: 'humans', rank: 21, sessionID: '53f3956e7c1c003605e8ab74', codeLanguage: 'javascript', name: 'piThrower', score: 51.38189056}
{team: 'humans', rank: 22, sessionID: '53d02fbc7b4eee430a5f238a', codeLanguage: 'javascript', name: 'dcm', score: 51.079906}
{team: 'humans', rank: 23, sessionID: '53f5b34154e4f234059fcc34', codeLanguage: 'javascript', name: 'zbanana', score: 50.4276462}
{team: 'humans', rank: 24, sessionID: '53f401c2e7a7643005c1358d', codeLanguage: 'javascript', name: 'Jerigan', score: 49.98484298}
{team: 'humans', rank: 25, sessionID: '53fbcdd07c3dc73405009ca5', codeLanguage: 'javascript', name: 'ojannen', score: 49.70746541}
{team: 'humans', rank: 26, sessionID: '53f59a2fd822c23505b80aff', codeLanguage: 'javascript', name: 'gorunir', score: 48.68311327}
{team: 'humans', rank: 27, sessionID: '53f3a5b3e7a7643005c05d11', codeLanguage: 'javascript', name: 'Tilorian', score: 47.32564935}
{team: 'humans', rank: 28, sessionID: '53f38b90e7a7643005c0150d', codeLanguage: 'javascript', name: 'MyWizard', score: 46.616599}
{team: 'humans', rank: 29, sessionID: '53f3dbf3e7a7643005c0dd43', codeLanguage: 'javascript', name: 'Terebijoke', score: 45.40772291}
{team: 'humans', rank: 30, sessionID: '53c22de027d0244a057ecbd8', codeLanguage: 'javascript', name: 'JavaCaster1', score: 45.08075025}
{team: 'humans', rank: 31, sessionID: '53f8f7de67ab263605e41dc6', codeLanguage: 'javascript', name: 'Moojo', score: 43.91409757}
{team: 'humans', rank: 32, sessionID: '53f49f28d822c23505b6ccdb', codeLanguage: 'clojure', name: 'jChuck', score: 43.69648547}
{team: 'humans', rank: 33, sessionID: '53f3ecaa8165533205fb46a2', codeLanguage: 'javascript', name: 'MCS', score: 43.65500921}
{team: 'humans', rank: 34, sessionID: '53f51289fda22e3305beac6a', codeLanguage: 'javascript', name: 'anykey', score: 43.52308768}
{team: 'humans', rank: 35, sessionID: '53f3a645e7a7643005c05dd8', codeLanguage: 'javascript', name: 'Nazywam', score: 42.76690262}
{team: 'humans', rank: 36, sessionID: '53f3b7a6e7a7643005c08b17', codeLanguage: 'javascript', name: 'Lunt', score: 42.5117331}
{team: 'humans', rank: 37, sessionID: '53fb57b85cfd700d099b733e', codeLanguage: 'python', name: 'other019', score: 42.46817345}
{team: 'humans', rank: 38, sessionID: '53fb51c83baef834054b5f87', codeLanguage: 'python', name: 'KiPu', score: 42.37172766}
{team: 'humans', rank: 39, sessionID: '53f7b114c5baa2f41501231a', codeLanguage: 'javascript', name: 'Pop-up', score: 42.10472537}
{team: 'humans', rank: 40, sessionID: '53f3866b7c1c003605e886cf', codeLanguage: 'javascript', name: 'Plak87', score: 40.75472545}
{team: 'humans', rank: 41, sessionID: '53f4c876f7bc7336054d84cf', codeLanguage: 'javascript', name: 'chriswen', score: 40.2773747}
{team: 'humans', rank: 42, sessionID: '53fad79467ab263605e5daff', codeLanguage: 'python', name: 'JLeow00', score: 40.23592348}
{team: 'humans', rank: 43, sessionID: '53f3909e7c1c003605e8a089', codeLanguage: 'javascript', name: 'juckele', score: 39.71481956}
{team: 'humans', rank: 44, sessionID: '53f387abe7a7643005c01095', codeLanguage: 'python', name: 'parseval', score: 39.40974773}
{team: 'humans', rank: 45, sessionID: '53f387b47c1c003605e8878a', codeLanguage: 'javascript', name: 'NicRio', score: 39.06434886}
{team: 'humans', rank: 46, sessionID: '53f6377154e4f23405a05ce6', codeLanguage: 'javascript', name: 'Moji', score: 38.60381239}
{team: 'humans', rank: 47, sessionID: '54022fd6973a642e10f08679', codeLanguage: 'javascript', name: 'droidwarrior', score: 38.12258027}
{team: 'humans', rank: 48, sessionID: '53f47e87fda22e3305bdbc2d', codeLanguage: 'javascript', name: 'Santinell', score: 37.77333035}
{team: 'humans', rank: 49, sessionID: '53fcfddf10bddbd805b1606a', codeLanguage: 'javascript', name: '[i].Lashes', score: 37.10129461}
{team: 'humans', rank: 50, sessionID: '54034c2a0557f27b0c33577a', codeLanguage: 'javascript', name: 'Finwe', score: 36.33095077}
{team: 'humans', rank: 51, sessionID: '53f490dcd822c23505b6c346', codeLanguage: 'python', name: 'AlienHunter3010', score: 35.57859105}
{team: 'humans', rank: 52, sessionID: '53f3e780e7a7643005c0ecd5', codeLanguage: 'javascript', name: 'Plloi', score: 34.79515433}
{team: 'humans', rank: 53, sessionID: '53fe1d04450764220abe3ff4', codeLanguage: 'javascript', name: 'Ehrks', score: 34.79168316}
{team: 'humans', rank: 54, sessionID: '53f3927fe7a7643005c03438', codeLanguage: 'javascript', name: 'taz', score: 34.2703216}
{team: 'humans', rank: 55, sessionID: '53f37d707c1c003605e87b1a', codeLanguage: 'javascript', name: 'zero_degrees', score: 33.64927149}
{team: 'humans', rank: 56, sessionID: '53f47bbdd822c23505b6a40a', codeLanguage: 'javascript', name: 'liorst1', score: 33.60823861}
{team: 'humans', rank: 57, sessionID: '541413a75117a4d10e468fe5', codeLanguage: 'python', name: 'Ever', score: 33.5904028}
{team: 'humans', rank: 58, sessionID: '53f671acfda22e3305c009a2', codeLanguage: 'python', name: 'Gnu', score: 33.42381407}
{team: 'humans', rank: 59, sessionID: '53fdb707a1a2c92409fd3fae', codeLanguage: 'javascript', name: 'gyuri', score: 32.56147128}
{team: 'humans', rank: 60, sessionID: '53dee08059839b35051fb52f', codeLanguage: 'javascript', name: 'Lanner', score: 31.89927824}
{team: 'humans', rank: 61, sessionID: '53f566b3f7bc7336054e3f4f', codeLanguage: 'javascript', name: 'redWizzard', score: 31.71795432}
{team: 'humans', rank: 62, sessionID: '53f38d58e7a7643005c0205e', codeLanguage: 'javascript', name: 'Maixck', score: 31.13482773}
{team: 'humans', rank: 63, sessionID: '5416ada992fc490115ce300c', codeLanguage: 'javascript', name: 'DanielAwesome', score: 30.0249466}
{team: 'humans', rank: 64, sessionID: '53f3f08d1171a8340550b8e3', codeLanguage: 'python', name: 'Handsome2734', score: 29.61969526}
{team: 'humans', rank: 65, sessionID: '540d9481a6128791125a1765', codeLanguage: 'javascript', name: 'Thom VB', score: 29.59295282}
{team: 'humans', rank: 66, sessionID: '5415d931fed2785a13ccac3b', codeLanguage: 'python', name: 'RedPill', score: 28.6484878}
{team: 'humans', rank: 67, sessionID: '53f3969f7c1c003605e8aeda', codeLanguage: 'python', name: 'Icatpasdu', score: 28.59919383}
{team: 'humans', rank: 68, sessionID: '53f422abe7a7643005c17609', codeLanguage: 'python', name: 'akhtyamovpavel', score: 28.53107357}
{team: 'humans', rank: 69, sessionID: '53a341aeaa66a7afbe3d1175', codeLanguage: 'javascript', name: 'Scott', score: 28.13105798}
{team: 'humans', rank: 70, sessionID: '5408bee18d0b993805d6e2ed', codeLanguage: 'python', name: 'Juan13', score: 27.72431383}
{team: 'humans', rank: 71, sessionID: '53f3827c8165533205fa7e53', codeLanguage: 'coffeescript', name: 'Anomander', score: 27.48633158}
{team: 'humans', rank: 72, sessionID: '53f4e25cf7bc7336054dcb1e', codeLanguage: 'javascript', name: 'Eterm', score: 27.44590315}
{team: 'humans', rank: 73, sessionID: '53f3e09f1171a83405509857', codeLanguage: 'javascript', name: 'stuntman_fx', score: 27.31894123}
{team: 'humans', rank: 74, sessionID: '54022bcd0557f27b0c32a26a', codeLanguage: 'javascript', name: 'matom', score: 26.92817056}
{team: 'humans', rank: 75, sessionID: '540eaeae25c82d2b06e84e6e', codeLanguage: 'python', name: 'JamiePilgrim', score: 26.66085117}
{team: 'humans', rank: 76, sessionID: '53f39bef8165533205faaf1c', codeLanguage: 'python', name: 'Gybseaa', score: 25.67104323}
{team: 'humans', rank: 77, sessionID: '53f5266dfda22e3305bec4d4', codeLanguage: 'python', name: 'sdetfaewtgswrf', score: 25.11200369}
{team: 'humans', rank: 78, sessionID: '53f3bade7c1c003605e912e8', codeLanguage: 'javascript', name: 'Tyler', score: 24.45104378}
{team: 'humans', rank: 79, sessionID: '54145e81e8c6b8ed0ec3c0de', codeLanguage: 'javascript', name: 'yuvi', score: 23.35851543}
{team: 'humans', rank: 80, sessionID: '53f37c861171a834054fd63f', codeLanguage: 'python', name: 'pbd', score: 21.95799255}
{team: 'humans', rank: 81, sessionID: '53f67052f7bc7336054f4d9f', codeLanguage: 'python', name: 'Napillo', score: 21.59848035}
{team: 'humans', rank: 82, sessionID: '53f5a34ed822c23505b80e62', codeLanguage: 'javascript', name: 'Sailor', score: 19.88903243}
{team: 'humans', rank: 83, sessionID: '53f60815fda22e3305bf8d14', codeLanguage: 'javascript', name: 'Gordon2012', score: 19.3703958}
{team: 'humans', rank: 84, sessionID: '53f3a49ce7a7643005c05c28', codeLanguage: 'clojure', name: 'Oze', score: 19.15746715}
{team: 'humans', rank: 85, sessionID: '53f3cee5e7a7643005c0cd04', codeLanguage: 'javascript', name: 'Frewdicket', score: 18.32983195}
{team: 'humans', rank: 86, sessionID: '53f3dfe07c1c003605e9560b', codeLanguage: 'python', name: 'Wizardioo', score: 17.24637409}
{team: 'humans', rank: 87, sessionID: '53f73786d822c23505b99bdc', codeLanguage: 'javascript', name: 'WOUN', score: 16.09512312}
{team: 'humans', rank: 88, sessionID: '53fb3c3567ab263605e64525', codeLanguage: 'javascript', name: 'Uyjen', score: 15.41176492}
{team: 'humans', rank: 89, sessionID: '5412232591cb5534055f9df1', codeLanguage: 'javascript', name: 'alltom', score: 14.93217724}
{team: 'humans', rank: 90, sessionID: '53a35877367e5794b2f5d430', codeLanguage: 'javascript', name: 'Michael S.', score: 14.69737904}
{team: 'humans', rank: 91, sessionID: '53f3959a7c1c003605e8ab90', codeLanguage: 'javascript', name: 'Xyphex', score: 14.60922258}
{team: 'humans', rank: 92, sessionID: '53fdfc25bfe0d7f308a6c2f8', codeLanguage: 'javascript', name: 'BEFOR', score: 14.09951331}
{team: 'humans', rank: 93, sessionID: '53f39293e7a7643005c03596', codeLanguage: 'python', name: 'melondonkey', score: 13.66123744}
{team: 'humans', rank: 94, sessionID: '53f5865efda22e3305bf2296', codeLanguage: 'python', name: 'hax0r00110', score: 13.27129663}
{team: 'humans', rank: 95, sessionID: '53fb87786c1ea23605924fc5', codeLanguage: 'lua', name: 'Joker78', score: 12.82530944}
{team: 'humans', rank: 96, sessionID: '54127ddcb2f1cc3605cf7454', codeLanguage: 'javascript', name: 'yakotaki', score: 12.80841814}
{team: 'humans', rank: 97, sessionID: '54172c214580e6bb21433b96', codeLanguage: 'javascript', name: 'VictorMGB', score: 11.79712559}
{team: 'humans', rank: 98, sessionID: '5410b0520e98527205cf23b8', codeLanguage: 'python', name: 'SliceNDiceSpud', score: 11.7339923}
{team: 'humans', rank: 99, sessionID: '53fd248cb14343450634feda', codeLanguage: 'python', name: 'Galvan', score: 11.2788073}
{team: 'humans', rank: 100, sessionID: '53ff3dcf919148a7074c9608', codeLanguage: 'clojure', name: 'jjjjj', score: 10.28409032}
{team: 'humans', rank: 101, sessionID: '53b4a6862082f23505b849f7', codeLanguage: 'javascript', name: 'Anonymous', score: 10.10879041}
{team: 'humans', rank: 102, sessionID: '5415de2dc6f5ec4e13326a22', codeLanguage: 'javascript', name: 'Anonymous', score: 10.08833109}
{team: 'humans', rank: 103, sessionID: '53f803b0bc7e716d14e82fde', codeLanguage: 'javascript', name: 'Aaryan', score: 10.0045068}
{team: 'humans', rank: 104, sessionID: '53f848714d9388fa15d1a457', codeLanguage: 'python', name: 'null000llun', score: 9.753414719}
{team: 'humans', rank: 105, sessionID: '53fc7b9a7c3dc7340500f09a', codeLanguage: 'javascript', name: 'Hackrylix', score: 9.704839891}
{team: 'humans', rank: 106, sessionID: '53f9aa35549ae742068f9f7e', codeLanguage: 'javascript', name: 'AlexTelon', score: 9.357260227}
{team: 'humans', rank: 107, sessionID: '53f72633fda22e3305c06b56', codeLanguage: 'javascript', name: 'eellson', score: 8.949914084}
{team: 'humans', rank: 108, sessionID: '54049a2011058b421307e0e1', codeLanguage: 'javascript', name: 'ugly loaf', score: 8.813606154}
{team: 'humans', rank: 109, sessionID: '53f98c823baef834054a0544', codeLanguage: 'javascript', name: 'Gamagori-sama', score: 8.52660922}
{team: 'humans', rank: 110, sessionID: '54019e1e49086dee0ddaf200', codeLanguage: 'javascript', name: 'akonand', score: 7.542416738}
{team: 'humans', rank: 111, sessionID: '53f39b918165533205faaed6', codeLanguage: 'python', name: 'roshan360', score: 6.740957014}
{team: 'humans', rank: 112, sessionID: '54046519e2b6e64a1832659d', codeLanguage: 'javascript', name: 'Val-per', score: 6.444447281}
{team: 'humans', rank: 113, sessionID: '53fe8cee95fba83305f4592d', codeLanguage: 'javascript', name: 'Bendalf0', score: 6.003282371}
{team: 'humans', rank: 114, sessionID: '53a39f1a573d6d3505b187de', codeLanguage: 'javascript', name: '┬─┬ノ( º _ ºノ)', score: 5.650008807}
{team: 'humans', rank: 115, sessionID: '540efacbba536e450767b2e8', codeLanguage: 'javascript', name: 'cole3', score: 5.314407805}
{team: 'humans', rank: 116, sessionID: '540fb13d098c622109a769e5', codeLanguage: 'python', name: 'Crunchy Meatball', score: 5.107994897}
{team: 'humans', rank: 117, sessionID: '53b36e22bb61aa3405d50f18', codeLanguage: 'javascript', name: 'sjarvie', score: 4.846878355}
]
results['criss-cross'].ogres = [
{team: 'ogres', rank: 1, sessionID: '5404bc1a2c6432b618fdbc41', codeLanguage: 'javascript', name: 'HighSea', score: 86.69028832}
{team: 'ogres', rank: 2, sessionID: '53f3ba2d1171a834055046f2', codeLanguage: 'javascript', name: 'matthewd', score: 82.94918281}
{team: 'ogres', rank: 3, sessionID: '53f397528165533205faabbf', codeLanguage: 'clojure', name: 'Driphter', score: 78.85897022}
{team: 'ogres', rank: 4, sessionID: '53f3ac981171a83405503789', codeLanguage: 'javascript', name: 'Forsaken', score: 78.63231082}
{team: 'ogres', rank: 5, sessionID: '53f4d91d54e4f234059ea96c', codeLanguage: 'javascript', name: 'Tehvudgaw', score: 76.79927673}
{team: 'ogres', rank: 6, sessionID: '53fe21d197d25d030aae69c8', codeLanguage: 'javascript', name: 'Blash', score: 74.05348884}
{team: 'ogres', rank: 7, sessionID: '53f8f7c967ab263605e41dbf', codeLanguage: 'javascript', name: 'Aldo', score: 73.47433531}
{team: 'ogres', rank: 8, sessionID: '53f94a206c1ea23605902730', codeLanguage: 'javascript', name: 'ThatOtherPerson', score: 69.82052272}
{team: 'ogres', rank: 9, sessionID: '54171cd74580e6bb2143312d', codeLanguage: 'javascript', name: 'Tech', score: 68.94907702}
{team: 'ogres', rank: 10, sessionID: '53f86f3cbc7e716d14e8a15c', codeLanguage: 'python', name: 'CookieMonster', score: 66.97949263}
{team: 'ogres', rank: 11, sessionID: '53f49a36d822c23505b6cb63', codeLanguage: 'python', name: 'odoacre', score: 65.53452876}
{team: 'ogres', rank: 12, sessionID: '53f6f84654e4f23405a1070e', codeLanguage: 'javascript', name: 'Arkhaix', score: 62.24714335}
{team: 'ogres', rank: 13, sessionID: '53f3b0257c1c003605e8ee11', codeLanguage: 'python', name: 'Buddy7', score: 61.63398791}
{team: 'ogres', rank: 14, sessionID: '53f39dce7c1c003605e8bdab', codeLanguage: 'javascript', name: 'CryZe', score: 61.00336334}
{team: 'ogres', rank: 15, sessionID: '53f38d7f7c1c003605e893b7', codeLanguage: 'javascript', name: 'Interimo', score: 57.77153143}
{team: 'ogres', rank: 16, sessionID: '53ced120f5ef3848053b9033', codeLanguage: 'javascript', name: 'chess', score: 55.44106174}
{team: 'ogres', rank: 17, sessionID: '53f39bde1171a83405500eab', codeLanguage: 'javascript', name: 'MyWizardlyName', score: 52.78486678}
{team: 'ogres', rank: 18, sessionID: '53f7e3e0b8a67b731487de15', codeLanguage: 'python', name: 'nineties', score: 52.48111694}
{team: 'ogres', rank: 19, sessionID: '540f6761098c622109a74a7d', codeLanguage: 'javascript', name: 'snake-345', score: 50.92666589}
{team: 'ogres', rank: 20, sessionID: '53f3f1468165533205fb63e1', codeLanguage: 'javascript', name: 'jmmk', score: 48.92922599}
{team: 'ogres', rank: 21, sessionID: '53f39896e7a7643005c0443d', codeLanguage: 'javascript', name: 'aggressiveFloor', score: 48.14095491}
{team: 'ogres', rank: 22, sessionID: '53f389d48165533205fa8599', codeLanguage: 'javascript', name: 'RustyDoorknobs', score: 47.26139895}
{team: 'ogres', rank: 23, sessionID: '53f44cfafda22e3305bd815c', codeLanguage: 'python', name: 'PugachAG', score: 47.04215583}
{team: 'ogres', rank: 24, sessionID: '53f3f12b1171a8340550c098', codeLanguage: 'python', name: 'lanzafame', score: 46.62859491}
{team: 'ogres', rank: 25, sessionID: '540725e9fedc2a55092aedf5', codeLanguage: 'python', name: 'Snooze', score: 44.8836671}
{team: 'ogres', rank: 26, sessionID: '53b36ac7bb61aa3405d50df3', codeLanguage: 'javascript', name: 'differentmatt', score: 44.48371038}
{team: 'ogres', rank: 27, sessionID: '53ffbc9c4fa75bc805dc8fd7', codeLanguage: 'javascript', name: 'kwksilver', score: 43.89457566}
{team: 'ogres', rank: 28, sessionID: '53f86ac64d9388fa15d1cb81', codeLanguage: 'javascript', name: 'Burhub', score: 43.15569365}
{team: 'ogres', rank: 29, sessionID: '5407b788e2007791053bb498', codeLanguage: 'javascript', name: 'SocioDude', score: 43.15346459}
{team: 'ogres', rank: 30, sessionID: '53f46bbb54e4f234059e118f', codeLanguage: 'javascript', name: 'Diruna', score: 43.14092027}
{team: 'ogres', rank: 31, sessionID: '53fad85d6c1ea2360591b7bc', codeLanguage: 'python', name: 'XY00', score: 42.82746659}
{team: 'ogres', rank: 32, sessionID: '53f4d3ef54e4f234059ea632', codeLanguage: 'javascript', name: 'Kefir', score: 42.12141876}
{team: 'ogres', rank: 33, sessionID: '5402249e42fb9c380ad1ee81', codeLanguage: 'python', name: 'mattmatt', score: 41.89852019}
{team: 'ogres', rank: 34, sessionID: '53f4c47e54e4f234059e95bb', codeLanguage: 'javascript', name: 'Trefader', score: 41.30414337}
{team: 'ogres', rank: 35, sessionID: '53fa70243baef834054ab75a', codeLanguage: 'javascript', name: 'haydennedyah', score: 41.22021639}
{team: 'ogres', rank: 36, sessionID: '53fdc936bfe0d7f308a6911c', codeLanguage: 'python', name: 'Luogbelnu', score: 40.96555677}
{team: 'ogres', rank: 37, sessionID: '53ffc7e4a1e10bbd05ae2e1b', codeLanguage: 'python', name: 'bob0the0mighty', score: 40.41223631}
{team: 'ogres', rank: 38, sessionID: '53f5d0f2fda22e3305bf67ed', codeLanguage: 'javascript', name: 'lifeline', score: 39.0406456}
{team: 'ogres', rank: 39, sessionID: '53f379ca7c1c003605e8793d', codeLanguage: 'coffeescript', name: 'Makaze', score: 38.88913774}
{team: 'ogres', rank: 40, sessionID: '53f39b577c1c003605e8b97a', codeLanguage: 'javascript', name: 'Braleigh', score: 38.19984465}
{team: 'ogres', rank: 41, sessionID: '53f4b841fda22e3305be136a', codeLanguage: 'python', name: 'qeinar', score: 38.13867335}
{team: 'ogres', rank: 42, sessionID: '53fbf5e7547f52350547a66f', codeLanguage: 'javascript', name: 'Ziroby', score: 37.48383317}
{team: 'ogres', rank: 43, sessionID: '54161f1dc6f5ec4e13328bd8', codeLanguage: 'javascript', name: 'MrCrepe', score: 37.3907791}
{team: 'ogres', rank: 44, sessionID: '53f4e5efd822c23505b74ecd', codeLanguage: 'javascript', name: 'Ryan Matte', score: 36.780337}
{team: 'ogres', rank: 45, sessionID: '541721b34580e6bb21433509', codeLanguage: 'javascript', name: 'Ryemane', score: 36.40478416}
{team: 'ogres', rank: 46, sessionID: '53f4f349d822c23505b758a0', codeLanguage: 'python', name: 'ChadM', score: 34.0284634}
{team: 'ogres', rank: 47, sessionID: '540d00a18b7031c212067cfe', codeLanguage: 'javascript', name: 'mch82', score: 33.45805275}
{team: 'ogres', rank: 48, sessionID: '53f37d318165533205fa7af0', codeLanguage: 'python', name: 'Mateo', score: 33.31751134}
{team: 'ogres', rank: 49, sessionID: '53f57005fda22e3305befc0d', codeLanguage: 'python', name: 'liewjianwei7', score: 32.86449352}
{team: 'ogres', rank: 50, sessionID: '540a44e6a8fb9e2908864a95', codeLanguage: 'python', name: 'NupTup', score: 31.54057431}
{team: 'ogres', rank: 51, sessionID: '53ff7b1e620719340501eb62', codeLanguage: 'javascript', name: 'korrident', score: 30.36103457}
{team: 'ogres', rank: 52, sessionID: '5413faed64e0ac4609bc0506', codeLanguage: 'javascript', name: 'Vhr', score: 29.57257834}
{team: 'ogres', rank: 53, sessionID: '53fe610581b81d3505175aa4', codeLanguage: 'javascript', name: 'Anonymous', score: 26.11692793}
{team: 'ogres', rank: 54, sessionID: '53f4320a1171a8340551357c', codeLanguage: 'python', name: 'igemon', score: 25.57886325}
{team: 'ogres', rank: 55, sessionID: '53f44441f7bc7336054cec4c', codeLanguage: 'python', name: 'Willybe', score: 25.31132405}
{team: 'ogres', rank: 56, sessionID: '54092dfb4236843405e684e6', codeLanguage: 'javascript', name: 'Noidificus', score: 25.24067489}
{team: 'ogres', rank: 57, sessionID: '5408aac5901c3f7007b60799', codeLanguage: 'javascript', name: 'Robert7', score: 25.15177276}
{team: 'ogres', rank: 58, sessionID: '53f5364a54e4f234059f3d3b', codeLanguage: 'javascript', name: 'Bage', score: 24.80093885}
{team: 'ogres', rank: 59, sessionID: '53fc1b22547f52350547be8a', codeLanguage: 'javascript', name: 'Christian S.', score: 24.51828741}
{team: 'ogres', rank: 60, sessionID: '53f3efd17c1c003605e97769', codeLanguage: 'javascript', name: 'Dodrithard', score: 24.25374686}
{team: 'ogres', rank: 61, sessionID: '53f4e550fda22e3305be7032', codeLanguage: 'javascript', name: 'Saikarsis', score: 24.03641464}
{team: 'ogres', rank: 62, sessionID: '53f64591d822c23505b8b536', codeLanguage: 'javascript', name: 'SurferIX', score: 22.50107203}
{team: 'ogres', rank: 63, sessionID: '53f89788bc7e716d14e8e536', codeLanguage: 'javascript', name: 'Ezrael', score: 22.06693778}
{team: 'ogres', rank: 64, sessionID: '53f39c91e7a7643005c04751', codeLanguage: 'javascript', name: 'ksj00', score: 16.40406633}
{team: 'ogres', rank: 65, sessionID: '53f396f41171a834055008e0', codeLanguage: 'javascript', name: 'no_login_found', score: 14.50374011}
{team: 'ogres', rank: 66, sessionID: '53f6ac1fd822c23505b91f29', codeLanguage: 'javascript', name: 'soccer66', score: 13.95564768}
{team: 'ogres', rank: 67, sessionID: '53f394978165533205faa44a', codeLanguage: 'javascript', name: 'skeltoac', score: 13.77314387}
{team: 'ogres', rank: 68, sessionID: '53fdeef0a1a2c92409fd7dd1', codeLanguage: 'javascript', name: 'Luke Lunsford', score: 12.31318938}
{team: 'ogres', rank: 69, sessionID: '53ed2e5c5d4d593305f9d006', codeLanguage: 'python', name: 'Sir Giroto', score: 11.90012214}
{team: 'ogres', rank: 70, sessionID: '53a3a012573d6d3505b1882b', codeLanguage: 'javascript', name: 'Quantanaray', score: 11.7169867}
{team: 'ogres', rank: 71, sessionID: '5414d693e4fb6fc61274e974', codeLanguage: 'javascript', name: 'XxDavidxX', score: 11.32103184}
{team: 'ogres', rank: 72, sessionID: '53f4847afda22e3305bdbea5', codeLanguage: 'javascript', name: 'CodeMinion', score: 9.706964015}
{team: 'ogres', rank: 73, sessionID: '53fba49c3baef834054b98c6', codeLanguage: 'javascript', name: 'Moises Banales', score: 8.991630973}
]

View file

@ -27,7 +27,10 @@ module.exports = class LevelChatView extends CocoView
updateMultiplayerVisibility: ->
return unless @$el?
@$el.toggle Boolean @session.get('multiplayer')
try
@$el.toggle Boolean @session.get('multiplayer')
catch e
console.error "Couldn't toggle the style on the LevelChatView to #{Boolean @session.get('multiplayer')} because of an error:", e
afterRender: ->
@chatTables = $('table', @$el)

View file

@ -0,0 +1,28 @@
ModalView = require 'views/kinds/ModalView'
template = require 'templates/play/modal/play-account-modal'
module.exports = class PlayAccountModal extends ModalView
className: 'modal fade play-modal'
template: template
modalWidthPercent: 90
id: 'play-account-modal'
#instant: true
#events:
# 'change input.select': 'onSelectionChanged'
constructor: (options) ->
super options
getRenderData: (context={}) ->
context = super(context)
context
afterRender: ->
super()
return unless @supermodel.finished()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
onHidden: ->
super()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1

View file

@ -0,0 +1,35 @@
ModalView = require 'views/kinds/ModalView'
template = require 'templates/play/modal/play-achievements-modal'
CocoCollection = require 'collections/CocoCollection'
Achievement = require 'models/Achievement'
#AchievementView = require 'views/game-menu/AchievementView'
module.exports = class PlayAchievementsModal extends ModalView
className: 'modal fade play-modal'
template: template
modalWidthPercent: 90
id: 'play-achievements-modal'
#instant: true
#events:
# 'change input.select': 'onSelectionChanged'
constructor: (options) ->
super options
#@achievements = new CocoCollection([], {model: Achievement})
#@achievements.url = '/db/thang.type?view=achievements&project=name,description,components,original,rasterIcon'
#@supermodel.loadCollection(@achievements, 'achievements')
getRenderData: (context={}) ->
context = super(context)
#context.achievements = @achievements.models
context
afterRender: ->
super()
return unless @supermodel.finished()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
onHidden: ->
super()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1

View file

@ -0,0 +1,47 @@
ModalView = require 'views/kinds/ModalView'
template = require 'templates/play/modal/play-heroes-modal'
CocoCollection = require 'collections/CocoCollection'
ThangType = require 'models/ThangType'
#HeroView = require 'views/game-menu/HeroView'
module.exports = class PlayHeroesModal extends ModalView
className: 'modal fade play-modal'
template: template
modalWidthPercent: 90
id: 'play-heroes-modal'
#instant: true
#events:
# 'change input.select': 'onSelectionChanged'
constructor: (options) ->
super options
@heroes = new CocoCollection([], {model: ThangType})
@heroes.url = '/db/thang.type?view=heroes&project=name,description,components,original,rasterIcon'
@supermodel.loadCollection(@heroes, 'heroes')
getRenderData: (context={}) ->
context = super(context)
context.heroes = @heroes.models
context
afterRender: ->
super()
return unless @supermodel.finished()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
#@addHeroViews()
onHidden: ->
super()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
#addHeroViews: ->
# keys = (hero.id for hero in @heroes.models)
# heroMap = _.zipObject keys, @heroes.models
# for heroStub in @$el.find('.replace-me')
# heroID = $(heroStub).data('hero-id')
# hero = heroMap[heroID]
# heroView = new HeroView({hero: hero, includes: {name: true, stats: true, props: true}})
# heroView.render()
# $(heroStub).replaceWith(heroView.$el)
# @registerSubView(heroView)

View file

@ -0,0 +1,66 @@
ModalView = require 'views/kinds/ModalView'
template = require 'templates/play/modal/play-items-modal'
CocoCollection = require 'collections/CocoCollection'
ThangType = require 'models/ThangType'
ItemView = require 'views/game-menu/ItemView'
module.exports = class PlayItemsModal extends ModalView
className: 'modal fade play-modal'
template: template
modalWidthPercent: 90
id: 'play-items-modal'
#instant: true
slotGroups:
armor: ['torso', 'head', 'gloves', 'feet']
hands: ['right-hand', 'left-hand']
accessories: ['eyes', 'neck', 'left-ring', 'right-ring', 'waist']
books: ['programming-book', 'spellbook']
minions: ['minion', 'pet']
misc: ['misc-0', 'misc-1', 'misc-2', 'misc-3', 'misc-4']
#events:
# 'change input.select': 'onSelectionChanged'
constructor: (options) ->
super options
@items = new CocoCollection([], {model: ThangType})
@items.url = '/db/thang.type?view=items&project=name,description,components,original,rasterIcon'
@supermodel.loadCollection(@items, 'items')
groupItems: ->
groups = {}
for item in @items.models
itemSlots = item.getAllowedSlots()
for group, groupSlots of @slotGroups
if _.find itemSlots, ((slot) -> slot in groupSlots)
groups[group] ?= []
groups[group].push item
groups
getRenderData: (context={}) ->
context = super(context)
context.slotGroups = @groupItems()
context.slotGroupsArray = _.keys context.slotGroups
context.slotGroupsNames = ($.i18n.t "items.#{slotGroup}" for slotGroup in context.slotGroupsArray)
context
afterRender: ->
super()
return unless @supermodel.finished()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
@addItemViews()
onHidden: ->
super()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1
addItemViews: ->
keys = (item.id for item in @items.models)
itemMap = _.zipObject keys, @items.models
for itemStub in @$el.find('.replace-me')
itemID = $(itemStub).data('item-id')
item = itemMap[itemID]
itemView = new ItemView({item: item, includes: {name: true, stats: true, props: true}})
itemView.render()
$(itemStub).replaceWith(itemView.$el)
@registerSubView(itemView)

View file

@ -0,0 +1,28 @@
ModalView = require 'views/kinds/ModalView'
template = require 'templates/play/modal/play-settings-modal'
module.exports = class PlaySettingsModal extends ModalView
className: 'modal fade play-modal'
template: template
modalWidthPercent: 90
id: 'play-settings-modal'
#instant: true
#events:
# 'change input.select': 'onSelectionChanged'
constructor: (options) ->
super options
getRenderData: (context={}) ->
context = super(context)
context
afterRender: ->
super()
return unless @supermodel.finished()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-open', volume: 1
onHidden: ->
super()
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'game-menu-close', volume: 1