Merge branch 'master' into production
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB |
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 156 KiB |
BIN
app/assets/images/pages/play/ladder/prize_aws.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
app/assets/images/pages/play/ladder/prize_cash1.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
app/assets/images/pages/play/ladder/prize_cash2.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
app/assets/images/pages/play/ladder/prize_cash3.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
app/assets/images/pages/play/ladder/prize_custom_avatar.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
app/assets/images/pages/play/ladder/prize_custom_wizard.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
app/assets/images/pages/play/ladder/prize_digital_ocean.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/assets/images/pages/play/ladder/prize_firebase.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
app/assets/images/pages/play/ladder/prize_heap.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/assets/images/pages/play/ladder/prize_one_month.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
app/assets/images/pages/play/ladder/prize_oreilly.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
app/assets/images/pages/play/ladder/prize_webstorm.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
|
@ -113,6 +113,7 @@ module.exports = class Angel extends CocoClass
|
|||
@doWork()
|
||||
|
||||
finalizePreload: ->
|
||||
@say "Finalize preload."
|
||||
@worker.postMessage func: 'finalizePreload'
|
||||
|
||||
infinitelyLooped: =>
|
||||
|
|
|
@ -54,7 +54,7 @@ module.exports = class God extends CocoClass
|
|||
@createWorld e.spells, e.preload
|
||||
|
||||
createWorld: (spells, preload=false) ->
|
||||
console.log "#{@nick}: Let there be light upon #{@level.name}!"
|
||||
console.log "#{@nick}: Let there be light upon #{@level.name}! (preload: #{preload})"
|
||||
userCodeMap = @getUserCodeMap spells
|
||||
|
||||
# We only want one world being simulated, so we abort other angels, unless we had one preloading this very code.
|
||||
|
@ -66,6 +66,9 @@ module.exports = class God extends CocoClass
|
|||
if not hadPreloader and isPreloading
|
||||
angel.finalizePreload()
|
||||
hadPreloader = true
|
||||
else if preload and angel.running and not angel.work.preload
|
||||
# It's still running for real, so let's not preload.
|
||||
return
|
||||
else
|
||||
angel.abort()
|
||||
return if hadPreloader
|
||||
|
|
|
@ -135,6 +135,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
onWorldNecessitiesLoaded: =>
|
||||
@initWorld()
|
||||
@supermodel.clearMaxProgress()
|
||||
@trigger 'world-necessities-loaded'
|
||||
return if @headless and not @editorMode
|
||||
thangsToLoad = _.uniq( (t.spriteName for t in @world.thangs when t.exists) )
|
||||
nameModelTuples = ([thangType.get('name'), thangType] for thangType in @thangNames.models)
|
||||
|
|
|
@ -23,6 +23,7 @@ module.exports = class Simulator extends CocoClass
|
|||
@cleanupSimulation()
|
||||
@god?.destroy()
|
||||
super()
|
||||
|
||||
fetchAndSimulateOneGame: (humanGameID, ogresGameID) =>
|
||||
return if @destroyed
|
||||
$.ajax
|
||||
|
@ -35,7 +36,7 @@ module.exports = class Simulator extends CocoClass
|
|||
error: (errorData) ->
|
||||
console.log "There was an error fetching two games! #{JSON.stringify errorData}"
|
||||
success: (taskData) =>
|
||||
|
||||
@trigger 'statusUpdate', 'Setting up simulation...'
|
||||
#refactor this
|
||||
@task = new SimulationTask(taskData)
|
||||
|
||||
|
@ -49,7 +50,7 @@ module.exports = class Simulator extends CocoClass
|
|||
@listenToOnce @supermodel, 'loaded-all', @simulateSingleGame
|
||||
simulateSingleGame: ->
|
||||
return if @destroyed
|
||||
console.log "Commencing simulation!"
|
||||
@trigger 'statusUpdate', 'Simulating...'
|
||||
@assignWorldAndLevelFromLevelLoaderAndDestroyIt()
|
||||
@setupGod()
|
||||
try
|
||||
|
@ -57,6 +58,7 @@ module.exports = class Simulator extends CocoClass
|
|||
catch err
|
||||
console.log err
|
||||
@handleSingleSimulationError()
|
||||
|
||||
commenceSingleSimulation: ->
|
||||
@god.createWorld @generateSpellsObject()
|
||||
Backbone.Mediator.subscribeOnce 'god:infinite-loop', @handleSingleSimulationInfiniteLoop, @
|
||||
|
@ -89,10 +91,22 @@ module.exports = class Simulator extends CocoClass
|
|||
else if ogreSessionRank < humanSessionRank
|
||||
console.log "GAMERESULT:ogres"
|
||||
process.exit(0)
|
||||
else
|
||||
@sendSingleGameBackToServer(taskResults)
|
||||
|
||||
@cleanupSimulation()
|
||||
|
||||
sendSingleGameBackToServer: (results) ->
|
||||
@trigger 'statusUpdate', 'Simulation completed, sending results back to server!'
|
||||
|
||||
|
||||
$.ajax
|
||||
url: "/queue/scoring/recordTwoGames"
|
||||
data: results
|
||||
type: "PUT"
|
||||
parse: true
|
||||
success: @handleTaskResultsTransferSuccess
|
||||
error: @handleTaskResultsTransferError
|
||||
complete: @cleanupAndSimulateAnotherTask
|
||||
|
||||
|
||||
fetchAndSimulateTask: =>
|
||||
|
@ -120,12 +134,13 @@ module.exports = class Simulator extends CocoClass
|
|||
console.error "There was a horrible Error: #{JSON.stringify errorData}"
|
||||
@trigger 'statusUpdate', 'There was an error fetching games to simulate. Retrying in 10 seconds.'
|
||||
@simulateAnotherTaskAfterDelay()
|
||||
|
||||
|
||||
handleNoGamesResponse: ->
|
||||
info = 'There were no games to simulate--all simulations are done or in process. Retrying in 10 seconds.'
|
||||
info = 'Finding game to simulate...'
|
||||
console.log info
|
||||
@trigger 'statusUpdate', info
|
||||
@simulateAnotherTaskAfterDelay()
|
||||
@fetchAndSimulateOneGame()
|
||||
application.tracker?.trackEvent 'Simulator Result', label: "No Games"
|
||||
|
||||
simulateAnotherTaskAfterDelay: =>
|
||||
|
|
|
@ -37,12 +37,16 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
possessed: false
|
||||
flipped: false
|
||||
flippedCount: 0
|
||||
originalScaleX: null
|
||||
originalScaleY: null
|
||||
actionQueue: null
|
||||
actions: null
|
||||
rotation: 0
|
||||
|
||||
# Scale numbers
|
||||
baseScaleX: 1 # scale + flip (for current action) / resolutionFactor.
|
||||
baseScaleY: 1 # These numbers rarely change, so keep them around.
|
||||
scaleFactor: 1 # Current scale adjustment. This can change rapidly.
|
||||
targetScaleFactor: 1 # What the scaleFactor is going toward during a tween.
|
||||
|
||||
# ACTION STATE
|
||||
# Actions have relations. If you say 'move', 'move_side' may play because of a direction
|
||||
# relationship, and if you say 'cast', 'cast_begin' may happen first, or 'cast_end' after.
|
||||
|
@ -71,7 +75,6 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@ranges = []
|
||||
@handledDisplayEvents = {}
|
||||
@age = 0
|
||||
@scaleFactor = @targetScaleFactor = 1
|
||||
if @thangType.isFullyLoaded()
|
||||
@setupSprite()
|
||||
else
|
||||
|
@ -94,6 +97,8 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
|
||||
finishSetup: ->
|
||||
return unless @thang
|
||||
@updateBaseScale()
|
||||
@scaleFactor = @thang.scaleFactor if @thang?.scaleFactor
|
||||
@update true # Reflect initial scale and other state
|
||||
|
||||
setUpRasterImage: ->
|
||||
|
@ -102,8 +107,6 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@setImageObject image
|
||||
$(image.image).one 'load', => @updateScale?()
|
||||
@configureMouse()
|
||||
@originalScaleX = image.scaleX
|
||||
@originalScaleY = image.scaleY
|
||||
@imageObject.sprite = @
|
||||
@imageObject.layerPriority = @thangType.get 'layerPriority'
|
||||
@imageObject.name = @thang?.spriteName or @thangType.get 'name'
|
||||
|
@ -112,14 +115,6 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@imageObject.regY = -reg.y
|
||||
@finishSetup()
|
||||
|
||||
destroy: ->
|
||||
mark.destroy() for name, mark of @marks
|
||||
label.destroy() for name, label of @labels
|
||||
p.removeChild @healthBar if p = @healthBar?.parent
|
||||
@imageObject?.off 'animationend', @playNextAction
|
||||
clearInterval @effectInterval if @effectInterval
|
||||
super()
|
||||
|
||||
toString: -> "<CocoSprite: #{@thang?.id}>"
|
||||
|
||||
buildSpriteSheet: ->
|
||||
|
@ -139,17 +134,11 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
sprite = new createjs.Sprite(spriteSheet)
|
||||
else
|
||||
sprite = new createjs.Shape()
|
||||
sprite.scaleX = sprite.scaleY = 1 / @options.resolutionFactor
|
||||
# temp, until these are re-exported with perspective
|
||||
if @options.camera and @thangType.get('name') in ['Dungeon Floor', 'Indoor Floor', 'Grass', 'Goal Trigger', 'Obstacle']
|
||||
sprite.scaleY *= @options.camera.y2x
|
||||
|
||||
@setImageObject sprite
|
||||
@addHealthBar()
|
||||
@configureMouse()
|
||||
# TODO: generalize this later?
|
||||
@originalScaleX = sprite.scaleX
|
||||
@originalScaleY = sprite.scaleY
|
||||
@imageObject.sprite = @
|
||||
@imageObject.layerPriority = @thangType.get 'layerPriority'
|
||||
@imageObject.name = @thang?.spriteName or @thangType.get 'name'
|
||||
|
@ -183,6 +172,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@currentAction = action
|
||||
return @hide() unless action.animation or action.container or action.relatedActions
|
||||
@show()
|
||||
@updateBaseScale()
|
||||
return @updateActionDirection() unless action.animation or action.container
|
||||
m = if action.container then "gotoAndStop" else "gotoAndPlay"
|
||||
@imageObject.framerate = action.framerate or 20
|
||||
|
@ -307,6 +297,18 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
[@imageObject.x, @imageObject.y] = [sup.x, sup.y]
|
||||
@lastPos = p1.copy?() or _.clone(p1)
|
||||
@hasMoved = true
|
||||
|
||||
updateBaseScale: ->
|
||||
scale = 1
|
||||
scale = @thangType.get('scale') or 1 if @isRaster
|
||||
scale /= @options.resolutionFactor unless @isRaster
|
||||
@baseScaleX = @baseScaleY = scale
|
||||
@baseScaleX *= -1 if @getActionProp 'flipX'
|
||||
@baseScaleY *= -1 if @getActionProp 'flipY'
|
||||
# temp, until these are re-exported with perspective
|
||||
floors = ['Dungeon Floor', 'Indoor Floor', 'Grass', 'Goal Trigger', 'Obstacle']
|
||||
if @options.camera and @thangType.get('name') in floors
|
||||
@baseScaleY *= @options.camera.y2x
|
||||
|
||||
updateScale: ->
|
||||
return unless @imageObject
|
||||
|
@ -316,18 +318,17 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
return unless bounds
|
||||
@imageObject.scaleX = @thang.width * Camera.PPM / bounds.width
|
||||
@imageObject.scaleY = @thang.height * Camera.PPM * @options.camera.y2x / bounds.height
|
||||
@imageObject.regX ?= 0
|
||||
@imageObject.regX += bounds.width / 2
|
||||
@imageObject.regY ?= 0
|
||||
@imageObject.regY += bounds.height / 2
|
||||
@imageObject.regX = bounds.width / 2
|
||||
@imageObject.regY = bounds.height / 2
|
||||
|
||||
unless @thang.spriteName is 'Beam'
|
||||
@imageObject.scaleX *= @thangType.get('scale') ? 1
|
||||
@imageObject.scaleY *= @thangType.get('scale') ? 1
|
||||
[@lastThangWidth, @lastThangHeight] = [@thang.width, @thang.height]
|
||||
return
|
||||
scaleX = if @getActionProp 'flipX' then -1 else 1
|
||||
scaleY = if @getActionProp 'flipY' then -1 else 1
|
||||
|
||||
scaleX = scaleY = 1
|
||||
|
||||
if @thangType.get('name') in ['Arrow', 'Spear']
|
||||
# Scales the arrow so it appears longer when flying parallel to horizon.
|
||||
# To do that, we convert angle to [0, 90] (mirroring half-planes twice), then make linear function out of it:
|
||||
|
@ -342,18 +343,12 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
angle = 180 - angle if angle > 90
|
||||
scaleX = 0.5 + 0.5 * (90 - angle) / 90
|
||||
|
||||
if @isRaster # scale is worked into building the sprite sheet for animations
|
||||
scale = @thangType.get('scale') or 1
|
||||
scaleX *= scale
|
||||
scaleY *= scale
|
||||
# console.error "No thang for", @ unless @thang
|
||||
# TODO: support using scaleFactorX/Y from the thang object
|
||||
@imageObject.scaleX = @baseScaleX * @scaleFactor * scaleX
|
||||
@imageObject.scaleY = @baseScaleY * @scaleFactor * scaleY
|
||||
|
||||
console.error "No thang for", @ unless @thang
|
||||
scaleFactorX = @thang.scaleFactorX ? @scaleFactor
|
||||
scaleFactorY = @thang.scaleFactorY ? @scaleFactor
|
||||
@imageObject.scaleX = @originalScaleX * scaleX * scaleFactorX
|
||||
@imageObject.scaleY = @originalScaleY * scaleY * scaleFactorY
|
||||
|
||||
if (@thang.scaleFactor or 1) isnt @targetScaleFactor
|
||||
if @thang and (@thang.scaleFactor or 1) isnt @targetScaleFactor
|
||||
createjs.Tween.removeTweens(@)
|
||||
createjs.Tween.get(@).to({scaleFactor:@thang.scaleFactor or 1}, 2000, createjs.Ease.elasticOut)
|
||||
@targetScaleFactor = @thang.scaleFactor or 1
|
||||
|
@ -783,3 +778,11 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
return unless @healthBar
|
||||
@healthBar.x = @imageObject.x
|
||||
@healthBar.y = @imageObject.y
|
||||
|
||||
destroy: ->
|
||||
mark.destroy() for name, mark of @marks
|
||||
label.destroy() for name, label of @labels
|
||||
p.removeChild @healthBar if p = @healthBar?.parent
|
||||
@imageObject?.off 'animationend', @playNextAction
|
||||
clearInterval @effectInterval if @effectInterval
|
||||
super()
|
|
@ -201,7 +201,8 @@ module.exports = class Mark extends CocoClass
|
|||
Backbone.Mediator.publish 'sprite:loaded'
|
||||
|
||||
update: (pos=null) ->
|
||||
return false unless @on and @mark and @sprite?.thangType.isFullyLoaded()
|
||||
return false unless @on and @mark
|
||||
return false if @sprite? and not @sprite.thangType.isFullyLoaded()
|
||||
@mark.visible = not @hidden
|
||||
@updatePosition pos
|
||||
@updateRotation()
|
||||
|
@ -240,20 +241,20 @@ module.exports = class Mark extends CocoClass
|
|||
oldMark.parent.addChild @mark
|
||||
oldMark.parent.swapChildren oldMark, @mark
|
||||
oldMark.parent.removeChild oldMark
|
||||
|
||||
if @markSprite?
|
||||
@markSprite.updateScale()
|
||||
return unless @name in ["selection", "target", "repair", "highlight"]
|
||||
scale = 0.5
|
||||
if @sprite?.imageObject
|
||||
size = @sprite.getAverageDimension()
|
||||
size += 60 if @name is 'selection'
|
||||
size += 60 if @name is 'repair'
|
||||
size *= @sprite.scaleFactor
|
||||
scale = size / {selection: 128, target: 128, repair: 320, highlight: 160}[@name]
|
||||
scale /= 3
|
||||
if @sprite?.thang.spriteName.search(/(dungeon|indoor).wall/i) isnt -1
|
||||
scale *= 2
|
||||
@mark.scaleX = @mark.scaleY = Math.min 1, scale
|
||||
if @markSprite?
|
||||
@mark.scaleX *= @markSprite.originalScaleX
|
||||
@mark.scaleY *= @markSprite.originalScaleY
|
||||
@mark.scaleX = @mark.scaleY = Math.min 1, scale
|
||||
if @name in ['selection', 'target', 'repair']
|
||||
@mark.scaleY *= @camera.y2x # code applies perspective
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ module.exports = class GoalManager extends CocoClass
|
|||
|
||||
nextGoalID: 0
|
||||
|
||||
constructor: (@world, @initialGoals) ->
|
||||
constructor: (@world, @initialGoals, @team) ->
|
||||
super()
|
||||
@init()
|
||||
|
||||
|
@ -78,8 +78,8 @@ module.exports = class GoalManager extends CocoClass
|
|||
# main instance gets them and updates their existing goal states,
|
||||
# passes the word along
|
||||
onNewWorldCreated: (e) ->
|
||||
@updateGoalStates(e.goalStates) if e.goalStates?
|
||||
@world = e.world
|
||||
@updateGoalStates(e.goalStates) if e.goalStates?
|
||||
|
||||
updateGoalStates: (newGoalStates) ->
|
||||
for goalID, goalState of newGoalStates
|
||||
|
@ -104,12 +104,19 @@ module.exports = class GoalManager extends CocoClass
|
|||
|
||||
notifyGoalChanges: ->
|
||||
overallStatus = @checkOverallStatus()
|
||||
event = {goalStates: @goalStates, goals: @goals, overallStatus: overallStatus}
|
||||
event =
|
||||
goalStates: @goalStates
|
||||
goals: @goals
|
||||
overallStatus: overallStatus
|
||||
timedOut: @world.totalFrames is @world.maxTotalFrames
|
||||
console.log 'timed out', @world.totalFrames is @world.maxTotalFrames, @world.totalFrames, @world.maxTotalFrames, @world.frames.length
|
||||
Backbone.Mediator.publish('goal-manager:new-goal-states', event)
|
||||
|
||||
checkOverallStatus: (ignoreIncomplete=false) ->
|
||||
overallStatus = null
|
||||
statuses = if @goalStates then (val.status for key, val of @goalStates) else []
|
||||
goals = if @goalStates then _.values @goalStates else []
|
||||
goals = (g for g in goals when g.team in [undefined, @team]) if @team
|
||||
statuses = if @goalStates then (goal.status for goal in goals) else []
|
||||
overallStatus = 'success' if statuses.length > 0 and _.every(statuses, (s) -> s is 'success' or (ignoreIncomplete and s is null))
|
||||
overallStatus = 'failure' if statuses.length > 0 and 'failure' in statuses
|
||||
overallStatus
|
||||
|
|
|
@ -222,6 +222,10 @@
|
|||
multiplayer: "Multiplayer"
|
||||
restart: "Restart"
|
||||
goals: "Goals"
|
||||
success: "Success!"
|
||||
incomplete: "Incomplete"
|
||||
timed_out: "Ran out of time"
|
||||
failing: "Failing"
|
||||
action_timeline: "Action Timeline"
|
||||
click_to_select: "Click on a unit to select it."
|
||||
reload_title: "Reload All Code?"
|
||||
|
@ -656,6 +660,8 @@
|
|||
rank_submitted: "Submitted for Ranking"
|
||||
rank_failed: "Failed to Rank"
|
||||
rank_being_ranked: "Game Being Ranked"
|
||||
rank_last_submitted: "submitted "
|
||||
help_simulate: "Help simulate games?"
|
||||
code_being_simulated: "Your new code is being simulated by other players for ranking. This will refresh as new matches come in."
|
||||
no_ranked_matches_pre: "No ranked matches for the "
|
||||
no_ranked_matches_post: " team! Play against some competitors and then come back here to get your game ranked."
|
||||
|
@ -675,6 +681,31 @@
|
|||
fight: "Fight!"
|
||||
watch_victory: "Watch your victory"
|
||||
defeat_the: "Defeat the"
|
||||
tournament_ends: "Tournament ends"
|
||||
tournament_rules: "Tournament Rules"
|
||||
tournament_blurb: "Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details"
|
||||
tournament_blurb_blog: "on our blog"
|
||||
|
||||
ladder_prizes:
|
||||
title: "Tournament Prizes"
|
||||
blurb_1: "These prizes will be awarded according to"
|
||||
blurb_2: "the tournament rules"
|
||||
blurb_3: "to the top human and ogre players."
|
||||
blurb_4: "Two teams means double the prizes!"
|
||||
blurb_5: "(There will be two first place winners, two second-place winners, etc.)"
|
||||
rank: "Rank"
|
||||
prizes: "Prizes"
|
||||
total_value: "Total Value"
|
||||
in_cash: "in cash"
|
||||
custom_wizard: "Custom CodeCombat Wizard"
|
||||
custom_avatar: "Custom CodeCombat avatar"
|
||||
heap: "for six months of \"Startup\" access"
|
||||
credits: "credits"
|
||||
one_month_coupon: "coupon: choose either Rails or HTML"
|
||||
one_month_discount: "discount, 30% off: choose either Rails or HTML"
|
||||
license: "license"
|
||||
oreilly: "ebook of your choice"
|
||||
|
||||
|
||||
multiplayer_launch:
|
||||
introducing_dungeon_arena: "Introducing Dungeon Arena"
|
||||
|
|
|
@ -16,7 +16,7 @@ class CocoModel extends Backbone.Model
|
|||
console.error("#{@} needs a className set.")
|
||||
@markToRevert()
|
||||
@addSchemaDefaults()
|
||||
@once 'sync', @onLoaded, @
|
||||
@on 'sync', @onLoaded, @
|
||||
@on 'error', @onError, @
|
||||
@saveBackup = _.debounce(@saveBackup, 500)
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ module.exports = class ThangType extends CocoModel
|
|||
isFullyLoaded: ->
|
||||
# TODO: Come up with a better way to identify when the model doesn't have everything needed to build the sprite. ie when it's a projection without all the required data.
|
||||
return @get('actions') or @get('raster') # needs one of these two things
|
||||
|
||||
|
||||
getActions: ->
|
||||
return {} unless @isFullyLoaded()
|
||||
return @actions or @buildActions()
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
.ladder-submission-view
|
||||
h3
|
||||
text-decoration: underline
|
||||
button
|
||||
text-shadow: 0px -1px 0px black
|
||||
|
||||
.last-submitted, .help-simulate
|
||||
font-size: 14px
|
||||
font-weight: normal
|
||||
|
||||
.last-submitted
|
||||
float: left
|
||||
|
||||
.help-simulate
|
||||
float: right
|
||||
|
||||
|
|
|
@ -1,6 +1,47 @@
|
|||
#ladder-view
|
||||
.main-content-area
|
||||
background-color: whitesmoke
|
||||
|
||||
#level-column img
|
||||
margin: -14px -12px 0px -12px
|
||||
width: 100%
|
||||
width: -webkit-calc(100% + 24px)
|
||||
width: calc(100% + 24px)
|
||||
|
||||
h1
|
||||
text-align: center
|
||||
|
||||
.tournament-blurb
|
||||
margin: -20px -12px 20px -12px
|
||||
padding: 10px
|
||||
background-color: white
|
||||
|
||||
h2
|
||||
text-align: center
|
||||
|
||||
a
|
||||
font-weight: bold
|
||||
|
||||
.sponsor-logos
|
||||
padding: 10px 15px 10px 15px
|
||||
|
||||
-webkit-filter: grayscale(100%)
|
||||
-webkit-transition: .5s ease-in-out
|
||||
-moz-filter: grayscale(100%)
|
||||
-moz-transition: .5s ease-in-out
|
||||
-o-filter: grayscale(100%)
|
||||
-o-transition: .5s ease-in-out
|
||||
filter: grayscale(100%)
|
||||
transition: .5s ease-in-out
|
||||
|
||||
&:hover
|
||||
-webkit-filter: grayscale(0%)
|
||||
-moz-filter: grayscale(0%)
|
||||
-o-filter: grayscale(0%)
|
||||
filter: grayscale(0%)
|
||||
|
||||
img
|
||||
margin: 0px 15px
|
||||
|
||||
.tab-pane
|
||||
margin-top: 10px
|
||||
|
@ -63,18 +104,38 @@
|
|||
td
|
||||
padding: 1px 2px
|
||||
|
||||
tr.stale
|
||||
opacity: 0.5
|
||||
|
||||
tr.win .state-cell
|
||||
color: #172
|
||||
tr.loss .state-cell
|
||||
color: #712
|
||||
|
||||
#must-log-in button
|
||||
margin-right: 10px
|
||||
|
||||
#prize_table
|
||||
width: 960px
|
||||
font-weight: bold
|
||||
|
||||
thead
|
||||
font-size: 24px
|
||||
|
||||
tbody
|
||||
tr:not(:first-child)
|
||||
border-top: 10px solid #ddd
|
||||
|
||||
td
|
||||
vertical-align: middle
|
||||
|
||||
&:nth-child(1), &:nth-child(3)
|
||||
text-align: center
|
||||
font-size: 24px
|
||||
|
||||
li
|
||||
list-style: none
|
||||
|
||||
&:not(:last-child)
|
||||
margin-bottom: 10px
|
||||
border-bottom: 1px solid #ddd
|
||||
|
||||
img
|
||||
margin-right: 10px
|
||||
|
||||
@media only screen and (max-width: 800px)
|
||||
#ladder-view
|
||||
#level-column img
|
||||
width: 100%
|
||||
width: 100%
|
||||
|
|
|
@ -26,4 +26,13 @@
|
|||
fill: #555555
|
||||
shape-rendering: crispEdges
|
||||
|
||||
|
||||
tr.fresh
|
||||
background-color: #39F
|
||||
tr.stale
|
||||
opacity: 0.5
|
||||
tr.win .state-cell
|
||||
color: #172
|
||||
tr.loss .state-cell
|
||||
color: #712
|
||||
|
||||
|
||||
|
|
|
@ -5,24 +5,26 @@
|
|||
left: 10px
|
||||
top: -100px
|
||||
@include transition(top 0.5s ease-in-out)
|
||||
background-color: rgba(200,200,200,0.8)
|
||||
|
||||
&.brighter
|
||||
background-color: rgba(200,200,200,1.0)
|
||||
background-color: rgba(200,200,200,1.0)
|
||||
|
||||
border: black
|
||||
padding: 15px 7px 5px 5px
|
||||
padding: 15px 7px 2px 5px
|
||||
box-sizing: border-box
|
||||
border: 1px solid #333
|
||||
border-radius: 5px
|
||||
|
||||
h3
|
||||
.goals-status
|
||||
font-size: 14px
|
||||
margin: 0
|
||||
color: black
|
||||
|
||||
i
|
||||
margin-right: 5px
|
||||
.success
|
||||
color: darkgreen
|
||||
.timed-out
|
||||
color: darkslategray
|
||||
.failure
|
||||
color: darkred
|
||||
.incomplete
|
||||
color: darkgoldenrod
|
||||
|
||||
ul
|
||||
padding-left: 0
|
||||
|
|
|
@ -38,7 +38,7 @@ block content
|
|||
input#email.form-control(name="email", type="text", value="#{me.get('email')}")
|
||||
if !isProduction
|
||||
.form-group.checkbox
|
||||
label(for="email", data-i18n="account_settings.admin") Admin
|
||||
label(for="admin", data-i18n="account_settings.admin") Admin
|
||||
input#admin(name="admin", type="checkbox", checked=me.get('permissions').indexOf('admin') != -1)
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
button.btn.btn-success.rank-button
|
||||
span(data-i18n="ladder.rank_no_code").unavailable.hidden No New Code to Rank
|
||||
span(data-i18n="ladder.rank_my_game").rank.hidden Rank My Game!
|
||||
span(data-i18n="ladder.rank_submitting").submitting.hidden Submitting...
|
||||
span(data-i18n="ladder.rank_submitted").submitted.hidden Submitted for Ranking
|
||||
span(data-i18n="ladder.rank_failed").failed.hidden Failed to Rank
|
||||
span(data-i18n="ladder.rank_being_ranked").ranking.hidden Game Being Ranked
|
||||
button.btn.btn-lg.btn-block.btn-success.rank-button
|
||||
span(data-i18n="ladder.rank_no_code").unavailable.secret No New Code to Rank
|
||||
span(data-i18n="ladder.rank_my_game").rank.secret Rank My Game!
|
||||
span(data-i18n="ladder.rank_submitting").submitting.secret Submitting...
|
||||
span(data-i18n="ladder.rank_submitted").submitted.secret Submitted for Ranking
|
||||
span(data-i18n="ladder.rank_failed").failed.secret Failed to Rank
|
||||
span(data-i18n="ladder.rank_being_ranked").ranking.secret Game Being Ranked
|
||||
|
||||
if lastSubmitted
|
||||
.last-submitted.secret
|
||||
span(data-i18n="ladder.rank_last_submitted") submitted
|
||||
| #{lastSubmitted}
|
||||
|
||||
a(href=simulateURL, data-i18n="ladder.help_simulate").help-simulate.secret Help simulate games?
|
||||
|
||||
.clearfix
|
|
@ -1,5 +1,6 @@
|
|||
extends /templates/base
|
||||
block content
|
||||
- var base = "/images/pages/play/ladder/prize_";
|
||||
|
||||
div#level-column
|
||||
if levelDescription
|
||||
|
@ -7,6 +8,31 @@ block content
|
|||
else
|
||||
h1= level.get('name')
|
||||
|
||||
if level.get('name') == 'Greed'
|
||||
.tournament-blurb
|
||||
h2
|
||||
span(data-i18n="ladder.tournament_ends") Tournament ends
|
||||
| #{tournamentTimeLeft}
|
||||
p
|
||||
span(data-i18n="ladder.tournament_blurb") Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details
|
||||
|
|
||||
a(href="http://blog.codecombat.com/multiplayer-programming-tournament", data-i18n="ladder.tournament_blurb_blog") on our blog
|
||||
| .
|
||||
|
||||
.sponsor-logos
|
||||
a(href="https://heapanalytics.com/")
|
||||
img(src=base + "heap.png")
|
||||
a(href="https://www.firebase.com/")
|
||||
img(src=base + "firebase.png")
|
||||
a(href="https://onemonthrails.com/")
|
||||
img(src=base + "one_month.png")
|
||||
a(href="http://www.jetbrains.com/webstorm/")
|
||||
img(src=base + "webstorm.png")
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do")
|
||||
img(src=base + "oreilly.png")
|
||||
a(href="http://aws.amazon.com/")
|
||||
img(src=base + "aws.png")
|
||||
|
||||
div#columns.row
|
||||
div.column.col-md-2
|
||||
for team in teams
|
||||
|
@ -45,8 +71,627 @@ block content
|
|||
.tab-pane.well#simulate
|
||||
#simulate-tab-view
|
||||
.tab-pane.well#prizes
|
||||
h1(data-i18n="ladder.prizes_remember_to_add_i18n_tags") Tournament Prizes
|
||||
p(data-i18n="ladder.prizes_but_this_is_just_placeholder") Fill in the Greed prizes list here.
|
||||
h1(data-i18n="ladder_prizes.title") Tournament Prizes
|
||||
p
|
||||
span(data-i18n="ladder_prizes.blurb_1") These prizes will be awarded according to
|
||||
|
|
||||
a(href="#rules", data-i18n="ladder_prizes.blurb_2") the tournament rules
|
||||
|
|
||||
span(data-i18n="ladder_prizes.blurb_3") to the top human and ogre players.
|
||||
|
|
||||
strong(data-i18n="ladder_prizes.blurb_4") Two teams means double the prizes!
|
||||
|
|
||||
span(data-i18n="ladder_prizes.blurb_5") (There will be two first place winners, two second-place winners, etc.)
|
||||
|
||||
table#prize_table.table
|
||||
thead
|
||||
tr
|
||||
td(data-i18n="ladder_prizes.rank") Rank
|
||||
td(data-i18n="ladder_prizes.prizes") Prizes
|
||||
td(data-i18n="ladder_prizes.total_value") Total Value
|
||||
tbody
|
||||
tr
|
||||
td 1st
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash1.png")
|
||||
span $512
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "custom_wizard.png")
|
||||
span(data-i18n="ladder_prizes.custom_wizard") Custom CodeCombat Wizard
|
||||
li
|
||||
img(src=base + "custom_avatar.png")
|
||||
span(data-i18n="ladder_prizes.custom_avatar") Custom CodeCombat avatar
|
||||
li
|
||||
img(src=base + "heap.png")
|
||||
span
|
||||
a(href="https://heapanalytics.com/") Heap Analytics
|
||||
|
|
||||
span(data-i18n="ladder_prizes.heap") for six months of "Startup" access
|
||||
| - $354
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_coupon") coupon: choose either Rails or HTML
|
||||
| - $99
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $2054
|
||||
tr
|
||||
td 2nd
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash2.png")
|
||||
span $256
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "custom_avatar.png")
|
||||
span(data-i18n="ladder_prizes.custom_avatar") Custom CodeCombat avatar
|
||||
li
|
||||
img(src=base + "heap.png")
|
||||
span
|
||||
a(href="https://heapanalytics.com/") Heap Analytics
|
||||
|
|
||||
span(data-i18n="ladder_prizes.heap") for six months of "Startup" access
|
||||
| - $354
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $1229
|
||||
tr
|
||||
td 3rd
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash2.png")
|
||||
span $128
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "custom_avatar.png")
|
||||
span(data-i18n="ladder_prizes.custom_avatar") Custom CodeCombat avatar
|
||||
li
|
||||
img(src=base + "heap.png")
|
||||
span
|
||||
a(href="https://heapanalytics.com/") Heap Analytics
|
||||
|
|
||||
span(data-i18n="ladder_prizes.heap") for six months of "Startup" access
|
||||
| - $354
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $1101
|
||||
tr
|
||||
td 4th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $64
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "heap.png")
|
||||
span
|
||||
a(href="https://heapanalytics.com/") Heap Analytics
|
||||
|
|
||||
span(data-i18n="ladder_prizes.heap") for six months of "Startup" access
|
||||
| - $354
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $887
|
||||
tr
|
||||
td 5th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $32
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "heap.png")
|
||||
span
|
||||
a(href="https://heapanalytics.com/") Heap Analytics
|
||||
|
|
||||
span(data-i18n="ladder_prizes.heap") for six months of "Startup" access
|
||||
| - $354
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $855
|
||||
tr
|
||||
td 6th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $16
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $485
|
||||
tr
|
||||
td 7th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $8
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $477
|
||||
tr
|
||||
td 8th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $4
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $473
|
||||
tr
|
||||
td 9th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $2
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $471
|
||||
tr
|
||||
td 10th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $1
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $470
|
||||
tr
|
||||
td 11 - 40
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $139
|
||||
tr
|
||||
td 41 - 100
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $90
|
||||
tr
|
||||
td 101+
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $50
|
||||
|
||||
.tab-pane.well#rules
|
||||
h1(data-i18n="ladder.rules_remember_to_add_i18n_tags") Tournament Rules
|
||||
p(data-i18n="ladder.rules_but_this_is_just_placeholder") We probably don't have to translate legal documents from English, but we should translate any conversational summary.
|
||||
h1(data-i18n="ladder.tournament_rules") Tournament Rules
|
||||
h2 General
|
||||
p You don't have to buy anything to participate in the tournament, and trying to pay us won't increase your odds of winning.
|
||||
|
||||
h2 Dates and Times
|
||||
p The tournament starts on Tuesday, May 20 at 8:30AM and ends on Tuesday, June 10 at 5:00PM PDT. After the tournament finishes, we will check the games manually to prevent duplicate entries and cheating. We will email all the winners within two weeks of the end date.
|
||||
|
||||
h2 Eligilibity
|
||||
p The tournament is open to anyone over the age of 13. Players are allowed to form teams to compete, but we will only be rewarding submissions, so if a team of 10 wins, they will need to split the prize.
|
||||
|
||||
p The tournament is NOT open to people who live in countries or states that prohibit participating or receiving a prize in a challenge (these include, but are not limited to Brazil, Quebec, Italy, Cuba, Sudan, Iran, North Korea, and Syria). Organizations involved in putting the tournament together (namely CodeCombat and all of our employees) are excluded from participating/winning prizes.
|
||||
|
||||
h2 Submission Requirements
|
||||
p
|
||||
| To be eligible to win prizes, players must submit their code to the Greed ladder for ranking AND defeat our default AI. Every player that submits their code to the ladder and beats our default AI will receive $50 in AWS credits as described on the
|
||||
a(href="#prizes", data-i18n="ladder_prizes.tournament_prizes") Tournament Prizes
|
||||
| page.
|
||||
|
||||
p
|
||||
| There are some restrictions regarding who can use the AWS credits. Please see the additional rules of use on
|
||||
a(href="https://aws.amazon.com/awscredits") Amazon's AWS credits page.
|
||||
|
||||
h2 Submission Rights
|
||||
p We reserve the right to use your submission and site identity (including username, avatar, and any information you mark as public) to promote the tournament. This is in keeping with our overall site terms of service.
|
||||
|
||||
h2 Judging Criteria
|
||||
p
|
||||
| We will calculate final rankings by running the top games from the public leaderboard from both teams against each other and sorting solutions by wins and losses. The number of games from each side to be used in the final ranking is yet to be determined, but is probably around 150. The final ranking will be performed with a snapshot of solutions taken the end of the contest. The final ranking methedology is subject to change. We will not be evaluating code in any manual way for common traits like adequate documentation, cleanliness, etc. We reserve the right to disqualify any player for any reason. The public leaderboards are a good proxy for your final rank, but are not guaranteed to be accurate. To repeat,
|
||||
strong the leaderboards are only a preliminary proxy for your final rank
|
||||
| .
|
||||
|
||||
p
|
||||
| Your rank will change as players submit more solutions and more matches are played according to
|
||||
a(href="https://github.com/codecombat/bayesian-battle") our open-source ranking library, Bayesian Battle
|
||||
| , but our final ranking will use an exhaustive pairwise matching round amongst the top players as described above.
|
||||
|
||||
h2 Prizes
|
||||
p
|
||||
| Prizes will be awarded to everyone that achieves a rank covered on the
|
||||
a(href="#prizes", data-i18n="ladder.prizes") Tournament Prizes
|
||||
| page.
|
||||
|
||||
p Please remember that the player ranks listed on the prize page refer to ranks WITHIN a leaderboard. So if you are the #2 Ogre player, you will win the #2 prize. Similarly, if you are the #3 Human player, you will receive the #3 prize. If you have submissions on both leaderboards, we will only count your highest submission for the purposes of distributing prizes. As a result, your final ranking may be higher than your preliminary ranking due to removing duplicate submissions above you.
|
||||
|
||||
h2 Verifying Potential Winners
|
||||
p We may ask players to identify themselves so that we can detect duplicate entries. This may be done in the form of a Facebook, Google+, or LinkedIn profile, but we may need more information. All players eligible for prizes agree that refusing to provide us with identifying information may lead to ineligibility for prizes.
|
||||
|
||||
p On a related note, if we have reason to believe that a player has intentionally submitted duplicate entries for the purpose of receiving more prizes or manipulating the leaderboards in any way, we will remove that player and all submissions we believe to be associated with them. We want this to be fair for everyone.
|
||||
|
||||
h2 Prize Distribution
|
||||
p Different sponsors require different ways of claiming their prizes, and we will work with winners to ensure they are able to redeem their prizes in a timely fashion. For cash prizes, we will deliver the money via PayPal. We will not ship checks, money orders, or cash through the mail. We will assume reasonable international money transfer costs to deliver cash prizes through Paypal.
|
||||
|
||||
p Winners are responsible for any taxes associated with claiming their prizes. CodeCombat is not responsible for filing paperwork on behalf of winners for tax claims.
|
||||
|
||||
h2 Contact
|
||||
p
|
||||
| If you have any questions or would like to get in touch with us for any other reason, we can be reached at team@codecombat.com. You can also post to our public
|
||||
a(href="http://discourse.codecombat.com/") Discourse forum
|
||||
| .
|
||||
|
|
|
@ -30,7 +30,7 @@ div#columns.row
|
|||
th(data-i18n="general.when") When
|
||||
th
|
||||
for match in team.matches
|
||||
tr(class=(match.stale ? "stale " : "") + match.state)
|
||||
tr(class=(match.stale ? "stale " : "") + (match.fresh ? "fresh " : "") + match.state)
|
||||
td.state-cell
|
||||
if match.state === 'win'
|
||||
span(data-i18n="general.win").win Win
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
ul#primary-goals-list
|
||||
h3
|
||||
span(data-i18n="play_level.goals") Goals
|
||||
div.goals-status
|
||||
strong(data-i18n="play_level.goals") Goals
|
||||
span.spl.spr :
|
||||
span(data-i18n="play_level.success").secret.goal-status.success Success!
|
||||
span(data-i18n="play_level.incomplete").secret.goal-status.incomplete Incomplete
|
||||
span(data-i18n="play_level.timed_out").secret.goal-status.timed-out Ran out of time
|
||||
span(data-i18n="play_level.failing").secret.goal-status.failure Failing
|
||||
|
|
|
@ -284,7 +284,11 @@ module.exports = class ThangTypeEditView extends View
|
|||
fixed = scaleValue.toFixed(1)
|
||||
@scale = scaleValue
|
||||
@$el.find('.scale-label').text " #{fixed}x "
|
||||
@currentObject.scaleX = @currentObject.scaleY = scaleValue / resValue if @currentObject?
|
||||
if @currentSprite
|
||||
@currentSprite.scaleFactor = scaleValue
|
||||
@currentSprite.updateScale()
|
||||
else if @currentObject?
|
||||
@currentObject.scaleX = @currentObject.scaleY = scaleValue / resValue
|
||||
@updateGrid()
|
||||
@updateDots()
|
||||
|
||||
|
|
|
@ -2,11 +2,12 @@ CocoView = require 'views/kinds/CocoView'
|
|||
template = require 'templates/play/common/ladder_submission'
|
||||
|
||||
module.exports = class LadderSubmissionView extends CocoView
|
||||
class: "ladder-submission-view"
|
||||
className: "ladder-submission-view"
|
||||
template: template
|
||||
|
||||
events:
|
||||
'click .rank-button': 'rankSession'
|
||||
'click .help-simulate': 'onHelpSimulate'
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
|
@ -16,9 +17,11 @@ module.exports = class LadderSubmissionView extends CocoView
|
|||
getRenderData: ->
|
||||
ctx = super()
|
||||
ctx.readyToRank = @session?.readyToRank()
|
||||
ctx.isRanking = @ession?.get('isRanking')
|
||||
ctx.isRanking = @session?.get('isRanking')
|
||||
ctx.simulateURL = "/play/ladder/#{@level.get('slug')}#simulate"
|
||||
ctx.lastSubmitted = moment(submitDate).fromNow() if submitDate = @session?.get('submitDate')
|
||||
ctx
|
||||
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
return unless @supermodel.finished()
|
||||
|
@ -34,9 +37,13 @@ module.exports = class LadderSubmissionView extends CocoView
|
|||
@setRankingButtonText rankingState
|
||||
|
||||
setRankingButtonText: (spanClass) ->
|
||||
@rankButton.find('span').addClass('hidden')
|
||||
@rankButton.find(".#{spanClass}").removeClass('hidden')
|
||||
@rankButton.find('span').hide()
|
||||
@rankButton.find(".#{spanClass}").show()
|
||||
@rankButton.toggleClass 'disabled', spanClass isnt 'rank'
|
||||
helpSimulate = spanClass in ['submitted', 'ranking']
|
||||
@$el.find('.help-simulate').toggle(helpSimulate, 'slow')
|
||||
showLastSubmitted = not (spanClass in ['submitting'])
|
||||
@$el.find('.last-submitted').toggle(showLastSubmitted)
|
||||
|
||||
rankSession: (e) ->
|
||||
return unless @session.readyToRank()
|
||||
|
@ -86,3 +93,5 @@ module.exports = class LadderSubmissionView extends CocoView
|
|||
transpiledCode[thang][spellID] = aether.transpile spell
|
||||
transpiledCode
|
||||
|
||||
onHelpSimulate: ->
|
||||
$('a[href="#simulate"]').tab('show')
|
||||
|
|
|
@ -53,6 +53,7 @@ module.exports = class LadderView extends RootView
|
|||
ctx.levelID = @levelID
|
||||
ctx.levelDescription = marked(@level.get('description')) if @level.get('description')
|
||||
ctx._ = _
|
||||
ctx.tournamentTimeLeft = moment(new Date(1402444800000)).fromNow()
|
||||
ctx
|
||||
|
||||
afterRender: ->
|
||||
|
@ -100,6 +101,10 @@ module.exports = class LadderView extends RootView
|
|||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
@showApologeticSignupModal()
|
||||
if link and /#rules$/.test link
|
||||
@$el.find('a[href="#rules"]').tab('show')
|
||||
if link and /#prizes/.test link
|
||||
@$el.find('a[href="#prizes"]').tab('show')
|
||||
|
||||
destroy: ->
|
||||
clearInterval @refreshInterval
|
||||
|
|
|
@ -13,6 +13,7 @@ module.exports = class MyMatchesTabView extends CocoView
|
|||
constructor: (options, @level, @sessions) ->
|
||||
super(options)
|
||||
@nameMap = {}
|
||||
@previouslyRankingTeams = {}
|
||||
@refreshMatches()
|
||||
|
||||
refreshMatches: ->
|
||||
|
@ -58,6 +59,9 @@ module.exports = class MyMatchesTabView extends CocoView
|
|||
state = 'win'
|
||||
state = 'loss' if match.metrics.rank > opponent.metrics.rank
|
||||
state = 'tie' if match.metrics.rank is opponent.metrics.rank
|
||||
fresh = match.date > (new Date(new Date() - 20 * 1000)).toISOString()
|
||||
if fresh
|
||||
Backbone.Mediator.publish 'play-sound', trigger: 'chat_received'
|
||||
{
|
||||
state: state
|
||||
opponentName: @nameMap[opponent.userID]
|
||||
|
@ -65,6 +69,7 @@ module.exports = class MyMatchesTabView extends CocoView
|
|||
when: moment(match.date).fromNow()
|
||||
sessionID: opponent.sessionID
|
||||
stale: match.date < submitDate
|
||||
fresh: fresh
|
||||
}
|
||||
|
||||
for team in @teams
|
||||
|
@ -81,6 +86,10 @@ module.exports = class MyMatchesTabView extends CocoView
|
|||
if scoreHistory?.length > 1
|
||||
team.scoreHistory = scoreHistory
|
||||
|
||||
if not team.isRanking and @previouslyRankingTeams[team.id]
|
||||
Backbone.Mediator.publish 'play-sound', trigger: 'cast-end'
|
||||
@previouslyRankingTeams[team.id] = team.isRanking
|
||||
|
||||
ctx
|
||||
|
||||
afterRender: ->
|
||||
|
@ -91,13 +100,14 @@ module.exports = class MyMatchesTabView extends CocoView
|
|||
session = _.find @sessions.models, {id: sessionID}
|
||||
ladderSubmissionView = new LadderSubmissionView session: session, level: @level
|
||||
@insertSubView ladderSubmissionView, placeholder
|
||||
ladderSubmissionView.$el.find('.rank-button').addClass 'btn-block'
|
||||
|
||||
@$el.find('.score-chart-wrapper').each (i, el) =>
|
||||
scoreWrapper = $(el)
|
||||
team = _.find @teams, name: scoreWrapper.data('team-name')
|
||||
@generateScoreLineChart(scoreWrapper.attr('id'), team.scoreHistory, team.name)
|
||||
|
||||
@$el.find('tr.fresh').removeClass('fresh', 5000)
|
||||
|
||||
generateScoreLineChart: (wrapperID, scoreHistory,teamName) =>
|
||||
margin =
|
||||
top: 20
|
||||
|
|
|
@ -19,13 +19,26 @@ module.exports = class GoalsView extends View
|
|||
'surface:playback-ended': 'onSurfacePlaybackEnded'
|
||||
|
||||
events:
|
||||
'mouseenter': -> @$el.css('top', -10)
|
||||
'mouseleave': -> @updateTop()
|
||||
'mouseenter': ->
|
||||
@mouseEntered = true
|
||||
@updatePlacement()
|
||||
|
||||
'mouseleave': ->
|
||||
@mouseEntered = false
|
||||
@updatePlacement()
|
||||
|
||||
toggleCollapse: (e) ->
|
||||
@$el.toggleClass('expanded').toggleClass('collapsed')
|
||||
|
||||
onNewGoalStates: (e) ->
|
||||
@$el.find('.goal-status').addClass 'secret'
|
||||
classToShow = null
|
||||
classToShow = 'success' if e.overallStatus is 'success'
|
||||
classToShow = 'failure' if e.overallStatus is 'failure'
|
||||
classToShow ?= 'timed-out' if e.timedOut
|
||||
classToShow ?= 'incomplete'
|
||||
@$el.find('.goal-status.'+classToShow).removeClass 'secret'
|
||||
|
||||
list = $('#primary-goals-list', @$el)
|
||||
list.empty()
|
||||
goals = []
|
||||
|
@ -53,10 +66,14 @@ module.exports = class GoalsView extends View
|
|||
@$el.removeClass('secret') if goals.length > 0
|
||||
|
||||
onSurfacePlaybackRestarted: ->
|
||||
@playbackEnded = false
|
||||
@$el.removeClass 'brighter'
|
||||
@updatePlacement()
|
||||
|
||||
onSurfacePlaybackEnded: ->
|
||||
@playbackEnded = true
|
||||
@$el.addClass 'brighter'
|
||||
@updatePlacement()
|
||||
|
||||
render: ->
|
||||
super()
|
||||
|
@ -64,11 +81,16 @@ module.exports = class GoalsView extends View
|
|||
|
||||
afterRender: ->
|
||||
super()
|
||||
@updateTop()
|
||||
@updatePlacement()
|
||||
|
||||
updateTop: ->
|
||||
@$el.css('top', 26 - @$el.outerHeight())
|
||||
updatePlacement: ->
|
||||
if @playbackEnded or @mouseEntered
|
||||
# expand
|
||||
@$el.css('top', -10)
|
||||
else
|
||||
# collapse
|
||||
@$el.css('top', 26 - @$el.outerHeight())
|
||||
|
||||
onSetLetterbox: (e) ->
|
||||
@$el.toggle not e.on
|
||||
@updateTop()
|
||||
@updatePlacement()
|
||||
|
|
|
@ -15,6 +15,8 @@ module.exports = class LevelLoadingView extends View
|
|||
@$el.find('.to-remove').remove()
|
||||
|
||||
showReady: ->
|
||||
return if @shownReady
|
||||
@shownReady = true
|
||||
ready = $.i18n.t('play_level.loading_ready', defaultValue: 'Ready!')
|
||||
@$el.find('#tip-wrapper .tip').addClass('ready').text ready
|
||||
Backbone.Mediator.publish 'play-sound', trigger: 'level_loaded', volume: 0.75 # old: loading_ready
|
||||
|
|
|
@ -13,6 +13,7 @@ module.exports = class DocsModal extends View
|
|||
'enter': 'hide'
|
||||
|
||||
constructor: (options) ->
|
||||
@firstOnly = options.firstOnly
|
||||
@docs = options?.docs
|
||||
general = @docs.generalArticles or []
|
||||
specific = @docs.specificArticles or []
|
||||
|
@ -25,6 +26,7 @@ module.exports = class DocsModal extends View
|
|||
|
||||
@docs = specific.concat(general)
|
||||
@docs = $.extend(true, [], @docs)
|
||||
@docs = [@docs[0]] if @firstOnly and @docs[0]
|
||||
doc.html = marked(utils.i18n doc, 'body') for doc in @docs
|
||||
doc.name = (utils.i18n doc, 'name') for doc in @docs
|
||||
doc.slug = _.string.slugify(doc.name) for doc in @docs
|
||||
|
|
|
@ -46,7 +46,6 @@ module.exports = class CastButtonView extends View
|
|||
Backbone.Mediator.publish 'tome:manual-cast', {}
|
||||
|
||||
onCastOptionsClick: (e) =>
|
||||
console.log 'cast options click', $(e.target)
|
||||
Backbone.Mediator.publish 'focus-editor'
|
||||
@castButtonGroup.removeClass 'open'
|
||||
@setAutocastDelay $(e.target).attr 'data-delay'
|
||||
|
@ -58,7 +57,9 @@ module.exports = class CastButtonView extends View
|
|||
onCastSpells: (e) ->
|
||||
return if e.preload
|
||||
@casting = true
|
||||
Backbone.Mediator.publish 'play-sound', trigger: 'cast', volume: 0.5
|
||||
if @hasStartedCastingOnce # Don't play this sound the first time
|
||||
Backbone.Mediator.publish 'play-sound', trigger: 'cast', volume: 0.5
|
||||
@hasStartedCastingOnce = true
|
||||
@updateCastButton()
|
||||
@onWorldLoadProgressChanged progress: 0
|
||||
|
||||
|
@ -69,7 +70,9 @@ module.exports = class CastButtonView extends View
|
|||
|
||||
onNewWorld: (e) ->
|
||||
@casting = false
|
||||
Backbone.Mediator.publish 'play-sound', trigger: 'cast-end', volume: 0.5
|
||||
if @hasCastOnce # Don't play this sound the first time
|
||||
Backbone.Mediator.publish 'play-sound', trigger: 'cast-end', volume: 0.5
|
||||
@hasCastOnce = true
|
||||
@updateCastButton()
|
||||
|
||||
updateCastButton: ->
|
||||
|
|
|
@ -69,14 +69,13 @@ module.exports = class PlayLevelView extends View
|
|||
shortcuts:
|
||||
'ctrl+s': 'onCtrlS'
|
||||
|
||||
# Initial Setup #############################################################
|
||||
|
||||
constructor: (options, @levelID) ->
|
||||
console.profile?() if PROFILE_ME
|
||||
super options
|
||||
if not me.get('hourOfCode') and @getQueryVariable "hour_of_code"
|
||||
me.set 'hourOfCode', true
|
||||
me.save()
|
||||
$('body').append($("<img src='http://code.org/api/hour/begin_codecombat.png' style='visibility: hidden;'>"))
|
||||
application.tracker?.trackEvent 'Hour of Code Begin', {}
|
||||
@setUpHourOfCode()
|
||||
|
||||
@isEditorPreview = @getQueryVariable 'dev'
|
||||
@sessionID = @getQueryVariable 'session'
|
||||
|
@ -92,9 +91,11 @@ module.exports = class PlayLevelView extends View
|
|||
@load()
|
||||
application.tracker?.trackEvent 'Started Level Load', level: @levelID, label: @levelID
|
||||
|
||||
onLevelLoadError: (e) ->
|
||||
# TODO NOW: remove this in favor of the supermodel handling it
|
||||
application.router.navigate "/play?not_found=#{@levelID}", {trigger: true}
|
||||
setUpHourOfCode: ->
|
||||
me.set 'hourOfCode', true
|
||||
me.save()
|
||||
$('body').append($("<img src='http://code.org/api/hour/begin_codecombat.png' style='visibility: hidden;'>"))
|
||||
application.tracker?.trackEvent 'Hour of Code Begin', {}
|
||||
|
||||
setLevel: (@level, givenSupermodel) ->
|
||||
@supermodel.models = givenSupermodel.models
|
||||
|
@ -112,6 +113,33 @@ module.exports = class PlayLevelView extends View
|
|||
@loadStartTime = new Date()
|
||||
@god = new God debugWorker: true
|
||||
@levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, sessionID: @sessionID, opponentSessionID: @getQueryVariable('opponent'), team: @getQueryVariable("team")
|
||||
@listenToOnce @levelLoader, 'world-necessities-loaded', @onWorldNecessitiesLoaded
|
||||
|
||||
# CocoView overridden methods ###############################################
|
||||
|
||||
updateProgress: (progress) ->
|
||||
super(progress)
|
||||
return if @seenDocs
|
||||
return unless @levelLoader.session.loaded and @levelLoader.level.loaded
|
||||
return unless showFrequency = @levelLoader.level.get('showsGuide')
|
||||
session = @levelLoader.session
|
||||
diff = new Date().getTime() - new Date(session.get('created')).getTime()
|
||||
return if showFrequency is 'first-time' and diff > (5 * 60 * 1000)
|
||||
articles = @levelLoader.supermodel.getModels Article
|
||||
for article in articles
|
||||
return unless article.loaded
|
||||
@showGuide()
|
||||
|
||||
showGuide: ->
|
||||
@seenDocs = true
|
||||
DocsModal = require './level/modal/docs_modal'
|
||||
options =
|
||||
docs: @levelLoader.level.get('documentation')
|
||||
supermodel: @supermodel
|
||||
firstOnly: true
|
||||
@openModalView(new DocsModal(options), true)
|
||||
Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelStarted, @
|
||||
return true
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
|
@ -129,62 +157,26 @@ module.exports = class PlayLevelView extends View
|
|||
@$el.find('#level-done-button').hide()
|
||||
$('body').addClass('is-playing')
|
||||
|
||||
updateProgress: (progress) ->
|
||||
super(progress)
|
||||
if not @worldInitialized and @levelLoader.session.loaded and @levelLoader.level.loaded and @levelLoader.world and (not @levelLoader.opponentSession or @levelLoader.opponentSession.loaded)
|
||||
@grabLevelLoaderData()
|
||||
@onWorldInitialized()
|
||||
return if @seenDocs
|
||||
return unless @levelLoader.session.loaded and @levelLoader.level.loaded
|
||||
return unless showFrequency = @levelLoader.level.get('showsGuide')
|
||||
session = @levelLoader.session
|
||||
diff = new Date().getTime() - new Date(session.get('created')).getTime()
|
||||
return if showFrequency is 'first-time' and diff > (5 * 60 * 1000)
|
||||
articles = @levelLoader.supermodel.getModels Article
|
||||
for article in articles
|
||||
return unless article.loaded
|
||||
@showGuide()
|
||||
afterInsert: ->
|
||||
super()
|
||||
@showWizardSettingsModal() if not me.get('name')
|
||||
|
||||
onWorldInitialized: ->
|
||||
@worldInitialized = true
|
||||
# Partially Loaded Setup ####################################################
|
||||
|
||||
onWorldNecessitiesLoaded: ->
|
||||
# Called when we have enough to build the world, but not everything is loaded
|
||||
@grabLevelLoaderData()
|
||||
team = @getQueryVariable("team") ? @world.teamForPlayer(0)
|
||||
@loadOpponentTeam(team)
|
||||
@god.setLevel @level.serialize @supermodel
|
||||
@god.setLevelSessionIDs if @otherSession then [@session.id, @otherSession.id] else [@session.id]
|
||||
@god.setWorldClassMap @world.classMap
|
||||
@setupGod()
|
||||
@setTeam team
|
||||
@initGoalManager()
|
||||
@insertSubviews ladderGame: (@level.get('type') is "ladder")
|
||||
@insertSubviews()
|
||||
@initVolume()
|
||||
@listenTo(@session, 'change:multiplayer', @onMultiplayerChanged)
|
||||
@originalSessionState = $.extend(true, {}, @session.get('state'))
|
||||
@register()
|
||||
@controlBar.setBus(@bus)
|
||||
|
||||
showGuide: ->
|
||||
@seenDocs = true
|
||||
DocsModal = require './level/modal/docs_modal'
|
||||
options = {docs: @levelLoader.level.get('documentation'), supermodel: @supermodel}
|
||||
@openModalView(new DocsModal(options), true)
|
||||
Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaded, @
|
||||
return true
|
||||
|
||||
onLoaded: ->
|
||||
_.defer => @onLevelLoaded()
|
||||
|
||||
onLevelLoaded: ->
|
||||
return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early
|
||||
@loadingView.showReady()
|
||||
if window.currentModal and not window.currentModal.destroyed
|
||||
return Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaded, @
|
||||
|
||||
# Save latest level played in local storage
|
||||
if not (@levelLoader.level.get('type') in ['ladder', 'ladder-tutorial'])
|
||||
me.set('lastLevel', @levelID)
|
||||
me.save()
|
||||
@levelLoader.destroy()
|
||||
@levelLoader = null
|
||||
@initSurface()
|
||||
@initScriptManager()
|
||||
|
||||
grabLevelLoaderData: ->
|
||||
|
@ -212,7 +204,79 @@ module.exports = class PlayLevelView extends View
|
|||
# For now, ladderGame will disallow multiplayer, because session code combining doesn't play nice yet.
|
||||
@session.set 'multiplayer', false
|
||||
|
||||
onLevelStarted: (e) ->
|
||||
setupGod: ->
|
||||
@god.setLevel @level.serialize @supermodel
|
||||
@god.setLevelSessionIDs if @otherSession then [@session.id, @otherSession.id] else [@session.id]
|
||||
@god.setWorldClassMap @world.classMap
|
||||
|
||||
setTeam: (team) ->
|
||||
team = team?.team unless _.isString team
|
||||
team ?= 'humans'
|
||||
me.team = team
|
||||
Backbone.Mediator.publish 'level:team-set', team: team
|
||||
@team = team
|
||||
|
||||
initGoalManager: ->
|
||||
@goalManager = new GoalManager(@world, @level.get('goals'), @team)
|
||||
@god.setGoalManager @goalManager
|
||||
|
||||
insertSubviews: ->
|
||||
@insertSubView @tome = new TomeView levelID: @levelID, session: @session, thangs: @world.thangs, supermodel: @supermodel
|
||||
@insertSubView new PlaybackView session: @session
|
||||
@insertSubView new GoalsView {}
|
||||
@insertSubView new GoldView {}
|
||||
@insertSubView new HUDView {}
|
||||
@insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session
|
||||
worldName = utils.i18n @level.attributes, 'name'
|
||||
@controlBar = @insertSubView new ControlBarView {worldName: worldName, session: @session, level: @level, supermodel: @supermodel, playableTeams: @world.playableTeams}
|
||||
#Backbone.Mediator.publish('level-set-debug', debug: true) if me.displayName() is 'Nick!'
|
||||
|
||||
initVolume: ->
|
||||
volume = me.get('volume')
|
||||
volume = 1.0 unless volume?
|
||||
Backbone.Mediator.publish 'level-set-volume', volume: volume
|
||||
|
||||
initScriptManager: ->
|
||||
@scriptManager = new ScriptManager({scripts: @world.scripts or [], view:@, session: @session})
|
||||
@scriptManager.loadFromSession()
|
||||
|
||||
register: ->
|
||||
@bus = LevelBus.get(@levelID, @session.id)
|
||||
@bus.setSession(@session)
|
||||
@bus.setSpells @tome.spells
|
||||
@bus.connect() if @session.get('multiplayer')
|
||||
|
||||
# Load Completed Setup ######################################################
|
||||
|
||||
onLoaded: ->
|
||||
_.defer => @onLevelLoaded()
|
||||
|
||||
onLevelLoaded: ->
|
||||
# Everything is now loaded
|
||||
return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early
|
||||
|
||||
# Save latest level played in local storage
|
||||
if not (@levelLoader.level.get('type') in ['ladder', 'ladder-tutorial'])
|
||||
me.set('lastLevel', @levelID)
|
||||
me.save()
|
||||
@levelLoader.destroy()
|
||||
@levelLoader = null
|
||||
@initSurface()
|
||||
|
||||
initSurface: ->
|
||||
surfaceCanvas = $('canvas#surface', @$el)
|
||||
@surface = new Surface(@world, surfaceCanvas, thangTypes: @supermodel.getModels(ThangType), playJingle: not @isEditorPreview)
|
||||
worldBounds = @world.getBounds()
|
||||
bounds = [{x:worldBounds.left, y:worldBounds.top}, {x:worldBounds.right, y:worldBounds.bottom}]
|
||||
@surface.camera.setBounds(bounds)
|
||||
@surface.camera.zoomTo({x:0, y:0}, 0.1, 0)
|
||||
|
||||
# Once Surface is Loaded ####################################################
|
||||
|
||||
onLevelStarted: ->
|
||||
@loadingView.showReady()
|
||||
if window.currentModal and not window.currentModal.destroyed
|
||||
return Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelStarted, @
|
||||
@surface.showLevel()
|
||||
if @otherSession
|
||||
# TODO: colorize name and cloud by team, colorize wizard by user's color config
|
||||
|
@ -229,34 +293,17 @@ module.exports = class PlayLevelView extends View
|
|||
application.tracker?.trackEvent 'Finished Level Load', level: @levelID, label: @levelID, loadDuration: loadDuration
|
||||
application.tracker?.trackTiming loadDuration, 'Level Load Time', @levelID, @levelID
|
||||
|
||||
onSupermodelLoadedOne: =>
|
||||
@modelsLoaded ?= 0
|
||||
@modelsLoaded += 1
|
||||
@updateInitString()
|
||||
|
||||
updateInitString: ->
|
||||
return if @surface
|
||||
@modelsLoaded ?= 0
|
||||
canvas = @$el.find('#surface')[0]
|
||||
ctx = canvas.getContext('2d')
|
||||
ctx.font="20px Georgia"
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
ctx.fillText("Loaded #{@modelsLoaded} thingies",50,50)
|
||||
|
||||
insertSubviews: ->
|
||||
@insertSubView @tome = new TomeView levelID: @levelID, session: @session, thangs: @world.thangs, supermodel: @supermodel
|
||||
@insertSubView new PlaybackView session: @session
|
||||
@insertSubView new GoalsView {}
|
||||
@insertSubView new GoldView {}
|
||||
@insertSubView new HUDView {}
|
||||
@insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session
|
||||
worldName = utils.i18n @level.attributes, 'name'
|
||||
@controlBar = @insertSubView new ControlBarView {worldName: worldName, session: @session, level: @level, supermodel: @supermodel, playableTeams: @world.playableTeams}
|
||||
#Backbone.Mediator.publish('level-set-debug', debug: true) if me.displayName() is 'Nick!'
|
||||
|
||||
afterInsert: ->
|
||||
super()
|
||||
@showWizardSettingsModal() if not me.get('name')
|
||||
onSurfaceSetUpNewWorld: ->
|
||||
return if @alreadyLoadedState
|
||||
@alreadyLoadedState = true
|
||||
state = @originalSessionState
|
||||
if state.frame and @level.get('type') isnt 'ladder' # https://github.com/codecombat/codecombat/issues/714
|
||||
Backbone.Mediator.publish 'level-set-time', { time: 0, frameOffset: state.frame }
|
||||
if state.selected
|
||||
# TODO: Should also restore selected spell here by saving spellName
|
||||
Backbone.Mediator.publish 'level-select-sprite', { thangID: state.selected, spellName: null }
|
||||
if state.playing?
|
||||
Backbone.Mediator.publish 'level-set-playing', { playing: state.playing }
|
||||
|
||||
# callbacks
|
||||
|
||||
|
@ -412,46 +459,11 @@ module.exports = class PlayLevelView extends View
|
|||
@bus.removeFirebaseData =>
|
||||
@bus.disconnect()
|
||||
|
||||
# initialization
|
||||
|
||||
addPointer: ->
|
||||
p = $('#pointer')
|
||||
return if p.length
|
||||
@$el.append($('<img src="/images/level/pointer.png" id="pointer">'))
|
||||
|
||||
initSurface: ->
|
||||
surfaceCanvas = $('canvas#surface', @$el)
|
||||
@surface = new Surface(@world, surfaceCanvas, thangTypes: @supermodel.getModels(ThangType), playJingle: not @isEditorPreview)
|
||||
worldBounds = @world.getBounds()
|
||||
bounds = [{x:worldBounds.left, y:worldBounds.top}, {x:worldBounds.right, y:worldBounds.bottom}]
|
||||
@surface.camera.setBounds(bounds)
|
||||
@surface.camera.zoomTo({x:0, y:0}, 0.1, 0)
|
||||
|
||||
initGoalManager: ->
|
||||
@goalManager = new GoalManager(@world, @level.get('goals'))
|
||||
@god.setGoalManager @goalManager
|
||||
|
||||
initScriptManager: ->
|
||||
@scriptManager = new ScriptManager({scripts: @world.scripts or [], view:@, session: @session})
|
||||
@scriptManager.loadFromSession()
|
||||
|
||||
initVolume: ->
|
||||
volume = me.get('volume')
|
||||
volume = 1.0 unless volume?
|
||||
Backbone.Mediator.publish 'level-set-volume', volume: volume
|
||||
|
||||
onSurfaceSetUpNewWorld: ->
|
||||
return if @alreadyLoadedState
|
||||
@alreadyLoadedState = true
|
||||
state = @originalSessionState
|
||||
if state.frame and @level.get('type') isnt 'ladder' # https://github.com/codecombat/codecombat/issues/714
|
||||
Backbone.Mediator.publish 'level-set-time', { time: 0, frameOffset: state.frame }
|
||||
if state.selected
|
||||
# TODO: Should also restore selected spell here by saving spellName
|
||||
Backbone.Mediator.publish 'level-select-sprite', { thangID: state.selected, spellName: null }
|
||||
if state.playing?
|
||||
Backbone.Mediator.publish 'level-set-playing', { playing: state.playing }
|
||||
|
||||
preloadNextLevel: =>
|
||||
# TODO: Loading models in the middle of gameplay causes stuttering. Most of the improvement in loading time is simply from passing the supermodel from this level to the next, but if we can find a way to populate the level early without it being noticeable, that would be even better.
|
||||
# return if @destroyed
|
||||
|
@ -460,12 +472,6 @@ module.exports = class PlayLevelView extends View
|
|||
# @supermodel.populateModel nextLevel
|
||||
# @preloaded = true
|
||||
|
||||
register: ->
|
||||
@bus = LevelBus.get(@levelID, @session.id)
|
||||
@bus.setSession(@session)
|
||||
@bus.setSpells @tome.spells
|
||||
@bus.connect() if @session.get('multiplayer')
|
||||
|
||||
onSessionWillSave: (e) ->
|
||||
# Something interesting has happened, so (at a lower frequency), we'll save a screenshot.
|
||||
#@saveScreenshot e.session
|
||||
|
@ -475,12 +481,6 @@ module.exports = class PlayLevelView extends View
|
|||
return unless screenshot = @surface?.screenshot()
|
||||
session.save {screenshot: screenshot}, {patch: true}
|
||||
|
||||
setTeam: (team) ->
|
||||
team = team?.team unless _.isString team
|
||||
team ?= 'humans'
|
||||
me.team = team
|
||||
Backbone.Mediator.publish 'level:team-set', team: team
|
||||
|
||||
# Dynamic sound loading
|
||||
|
||||
onNewWorld: (e) ->
|
||||
|
|
|
@ -9,7 +9,7 @@ import sys
|
|||
current_directory = os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||
coco_path = os.getenv("COCO_DIR",os.path.join(current_directory,os.pardir))
|
||||
brunch_path = coco_path + os.sep + "node_modules" + os.sep + ".bin" + os.sep + "brunch"
|
||||
subprocess.Popen("ulimit -n 10000",shell=True)
|
||||
subprocess.Popen("ulimit -n 100000",shell=True)
|
||||
while True:
|
||||
print("Starting brunch. After the first compile, it'll keep running and watch for changes.")
|
||||
call(brunch_path + " w",shell=True,cwd=coco_path)
|
||||
|
|
|
@ -121,7 +121,7 @@ module.exports = class Handler
|
|||
@modelClass.findOne(criteria, project).sort(sort).exec (err, document) ->
|
||||
return done(err) if err
|
||||
callback(null, document?.toObject() or null)
|
||||
|
||||
|
||||
funcs = {}
|
||||
for id in ids
|
||||
return errors.badInput(res, "Given an invalid id: #{id}") unless Handler.isID(id)
|
||||
|
|
|
@ -103,28 +103,89 @@ module.exports.getTwoGames = (req, res) ->
|
|||
#if userIsAnonymous req then return errors.unauthorized(res, "You need to be logged in to get games.")
|
||||
humansGameID = req.body.humansGameID
|
||||
ogresGameID = req.body.ogresGameID
|
||||
|
||||
|
||||
unless ogresGameID and humansGameID
|
||||
#fetch random games here
|
||||
return errors.badInput(res, "You need to supply two games(for now)")
|
||||
LevelSession.findOne(_id: humansGameID).lean().exec (err, humanSession) =>
|
||||
if err? then return errors.serverError(res, "Couldn't find the human game")
|
||||
LevelSession.findOne(_id: ogresGameID).lean().exec (err, ogreSession) =>
|
||||
if err? then return errors.serverError(res, "Couldn't find the ogre game")
|
||||
taskObject =
|
||||
"messageGenerated": Date.now()
|
||||
"sessions": []
|
||||
for session in [humanSession, ogreSession]
|
||||
sessionInformation =
|
||||
"sessionID": session._id
|
||||
"team": session.team ? "No team"
|
||||
"transpiledCode": session.transpiledCode
|
||||
"teamSpells": session.teamSpells ? {}
|
||||
"levelID": session.levelID
|
||||
queryParams =
|
||||
"levelID":"greed"
|
||||
"submitted":true
|
||||
"team":"humans"
|
||||
selection = "team totalScore transpiledCode teamSpells levelID creatorName creator"
|
||||
LevelSession.count queryParams, (err, numberOfHumans) =>
|
||||
query = LevelSession
|
||||
.find(queryParams)
|
||||
.limit(1)
|
||||
.select(selection)
|
||||
.skip(Math.floor(Math.random()*numberOfHumans))
|
||||
.lean()
|
||||
query.exec (err, randomSession) =>
|
||||
if err? then return errors.serverError(res, "Couldn't select a top 15 random session!")
|
||||
randomSession = randomSession[0]
|
||||
queryParams =
|
||||
"levelID":"greed"
|
||||
"submitted":true
|
||||
"totalScore":
|
||||
$lte: randomSession.totalScore
|
||||
"team": "ogres"
|
||||
query = LevelSession
|
||||
.find(queryParams)
|
||||
.select(selection)
|
||||
.sort(totalScore: -1)
|
||||
.limit(1)
|
||||
.lean()
|
||||
query.exec (err, otherSession) =>
|
||||
if err? then return errors.serverError(res, "Couldnt' select the other top 15 random session!")
|
||||
otherSession = otherSession[0]
|
||||
taskObject =
|
||||
"messageGenerated": Date.now()
|
||||
"sessions": []
|
||||
for session in [randomSession, otherSession]
|
||||
sessionInformation =
|
||||
"sessionID": session._id
|
||||
"team": session.team ? "No team"
|
||||
"transpiledCode": session.transpiledCode
|
||||
"teamSpells": session.teamSpells ? {}
|
||||
"levelID": session.levelID
|
||||
"creatorName": session.creatorName
|
||||
"creator": session.creator
|
||||
"totalScore": session.totalScore
|
||||
|
||||
taskObject.sessions.push sessionInformation
|
||||
sendResponseObject req, res, taskObject
|
||||
else
|
||||
LevelSession.findOne(_id: humansGameID).lean().exec (err, humanSession) =>
|
||||
if err? then return errors.serverError(res, "Couldn't find the human game")
|
||||
LevelSession.findOne(_id: ogresGameID).lean().exec (err, ogreSession) =>
|
||||
if err? then return errors.serverError(res, "Couldn't find the ogre game")
|
||||
taskObject =
|
||||
"messageGenerated": Date.now()
|
||||
"sessions": []
|
||||
for session in [humanSession, ogreSession]
|
||||
sessionInformation =
|
||||
"sessionID": session._id
|
||||
"team": session.team ? "No team"
|
||||
"transpiledCode": session.transpiledCode
|
||||
"teamSpells": session.teamSpells ? {}
|
||||
"levelID": session.levelID
|
||||
|
||||
taskObject.sessions.push sessionInformation
|
||||
sendResponseObject req, res, taskObject
|
||||
|
||||
module.exports.recordTwoGames = (req, res) ->
|
||||
@clientResponseObject = req.body
|
||||
|
||||
taskObject.sessions.push sessionInformation
|
||||
sendResponseObject req, res, taskObject
|
||||
|
||||
async.waterfall [
|
||||
fetchLevelSession.bind(@)
|
||||
updateSessions.bind(@)
|
||||
indexNewScoreArray.bind(@)
|
||||
addMatchToSessions.bind(@)
|
||||
updateUserSimulationCounts.bind(@, req.user._id)
|
||||
], (err, successMessageObject) ->
|
||||
if err? then return errors.serverError res, "There was an error recording the single game:#{err}"
|
||||
sendResponseObject req, res, {"message":"The single game was submitted successfully!"}
|
||||
|
||||
|
||||
|
||||
module.exports.createNewTask = (req, res) ->
|
||||
requestSessionID = req.body.session
|
||||
originalLevelID = req.body.originalLevelID
|
||||
|
@ -214,7 +275,7 @@ fetchInitialSessionsToRankAgainst = (levelMajorVersion, levelID, submittedSessio
|
|||
submittedCode:
|
||||
$exists: true
|
||||
team: opposingTeam
|
||||
|
||||
|
||||
sortParameters =
|
||||
totalScore: 1
|
||||
|
||||
|
@ -663,9 +724,7 @@ retrieveOldSessionData = (sessionID, callback) ->
|
|||
"totalScore":session.totalScore ? (25 - 1.8*(25/3))
|
||||
"id": sessionID
|
||||
callback err, oldScoreObject
|
||||
|
||||
markSessionAsDoneRanking = (sessionID, cb) ->
|
||||
|
||||
markSessionAsDoneRanking = (sessionID, cb) ->
|
||||
#console.log "Marking session as done ranking..."
|
||||
LevelSession.update {"_id":sessionID}, {"isRanking":false}, cb
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,10 @@ module.exports.setup = (app) ->
|
|||
app.post '/queue/scoring/getTwoGames', (req, res) ->
|
||||
handler = loadQueueHandler 'scoring'
|
||||
handler.getTwoGames req, res
|
||||
|
||||
app.put '/queue/scoring/recordTwoGames', (req, res) ->
|
||||
handler = loadQueueHandler 'scoring'
|
||||
handler.recordTwoGames req, res
|
||||
|
||||
app.all '/queue/*', (req, res) ->
|
||||
setResponseHeaderToJSONContentType res
|
||||
|
|
|
@ -91,8 +91,8 @@ setupFallbackRouteToIndex = (app) ->
|
|||
sendMain = (req, res) ->
|
||||
fs.readFile path.join(__dirname, 'public', 'main.html'), 'utf8', (err, data) ->
|
||||
log.error "Error modifying main.html: #{err}" if err
|
||||
# insert the user object directly into the html so the application can have it immediately
|
||||
data = data.replace('"userObjectTag"', JSON.stringify(UserHandler.formatEntity(req, req.user)))
|
||||
# insert the user object directly into the html so the application can have it immediately. Sanitize </script>
|
||||
data = data.replace('"userObjectTag"', JSON.stringify(UserHandler.formatEntity(req, req.user)).replace('/', '\\/'))
|
||||
res.send data
|
||||
|
||||
setupFacebookCrossDomainCommunicationRoute = (app) ->
|
||||
|
|