Merge branch 'master' of https://github.com/codecombat/codecombat
This commit is contained in:
commit
a2fbe5865a
35 changed files with 562 additions and 278 deletions
app
assets/javascripts/workers
initialize.coffeelib
locale
models
schemas
templates/play/ladder
views
server/queues
server_setup.coffee
|
@ -378,6 +378,7 @@ self.onWorldLoaded = function onWorldLoaded() {
|
||||||
}
|
}
|
||||||
var t3 = new Date();
|
var t3 = new Date();
|
||||||
console.log("And it was so: (" + (diff / self.world.totalFrames).toFixed(3) + "ms per frame,", self.world.totalFrames, "frames)\nSimulation :", diff + "ms \nSerialization:", (t2 - t1) + "ms\nDelivery :", (t3 - t2) + "ms");
|
console.log("And it was so: (" + (diff / self.world.totalFrames).toFixed(3) + "ms per frame,", self.world.totalFrames, "frames)\nSimulation :", diff + "ms \nSerialization:", (t2 - t1) + "ms\nDelivery :", (t3 - t2) + "ms");
|
||||||
|
self.world.goalManager.destroy();
|
||||||
self.world = null;
|
self.world = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -408,6 +409,7 @@ self.onWorldLoadProgress = function onWorldLoadProgress(progress) {
|
||||||
self.abort = function abort() {
|
self.abort = function abort() {
|
||||||
if(self.world) {
|
if(self.world) {
|
||||||
self.world.abort();
|
self.world.abort();
|
||||||
|
self.world.goalManager.destroy();
|
||||||
self.world = null;
|
self.world = null;
|
||||||
}
|
}
|
||||||
self.postMessage({type: 'abort'});
|
self.postMessage({type: 'abort'});
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
Backbone.Mediator.setValidationEnabled false
|
||||||
app = require 'application'
|
app = require 'application'
|
||||||
|
|
||||||
channelSchemas =
|
channelSchemas =
|
||||||
|
@ -17,6 +18,10 @@ definitionSchemas =
|
||||||
'misc': require './schemas/definitions/misc'
|
'misc': require './schemas/definitions/misc'
|
||||||
|
|
||||||
init = ->
|
init = ->
|
||||||
|
# Set up Backbone.Mediator schemas
|
||||||
|
setUpDefinitions()
|
||||||
|
setUpChannels()
|
||||||
|
Backbone.Mediator.setValidationEnabled document.location.href.search(/codecombat.com/) is -1
|
||||||
app.initialize()
|
app.initialize()
|
||||||
Backbone.history.start({ pushState: true })
|
Backbone.history.start({ pushState: true })
|
||||||
handleNormalUrls()
|
handleNormalUrls()
|
||||||
|
@ -25,10 +30,6 @@ init = ->
|
||||||
treemaExt.setup()
|
treemaExt.setup()
|
||||||
filepicker.setKey('AvlkNoldcTOU4PvKi2Xm7z')
|
filepicker.setKey('AvlkNoldcTOU4PvKi2Xm7z')
|
||||||
|
|
||||||
# Set up Backbone.Mediator schemas
|
|
||||||
setUpDefinitions()
|
|
||||||
setUpChannels()
|
|
||||||
|
|
||||||
$ -> init()
|
$ -> init()
|
||||||
|
|
||||||
handleNormalUrls = ->
|
handleNormalUrls = ->
|
||||||
|
|
|
@ -9,7 +9,7 @@ module.exports = class CocoClass
|
||||||
@nicksUsed: {}
|
@nicksUsed: {}
|
||||||
@remainingNicks: []
|
@remainingNicks: []
|
||||||
@nextNick: ->
|
@nextNick: ->
|
||||||
return "CocoClass " + classCount unless @nicks.length
|
return (@name or "CocoClass") + " " + classCount unless @nicks.length
|
||||||
@remainingNicks = if @remainingNicks.length then @remainingNicks else @nicks.slice()
|
@remainingNicks = if @remainingNicks.length then @remainingNicks else @nicks.slice()
|
||||||
baseNick = @remainingNicks.splice(Math.floor(Math.random() * @remainingNicks.length), 1)[0]
|
baseNick = @remainingNicks.splice(Math.floor(Math.random() * @remainingNicks.length), 1)[0]
|
||||||
i = 0
|
i = 0
|
||||||
|
@ -37,7 +37,7 @@ module.exports = class CocoClass
|
||||||
destroy: ->
|
destroy: ->
|
||||||
# teardown subscriptions, prevent new ones
|
# teardown subscriptions, prevent new ones
|
||||||
@stopListening?()
|
@stopListening?()
|
||||||
@off()
|
@off?()
|
||||||
@unsubscribeAll()
|
@unsubscribeAll()
|
||||||
@stopListeningToShortcuts()
|
@stopListeningToShortcuts()
|
||||||
@constructor.nicksUsed[@nick] = false
|
@constructor.nicksUsed[@nick] = false
|
||||||
|
@ -65,6 +65,7 @@ module.exports = class CocoClass
|
||||||
Backbone.Mediator.subscribe(channel, func, @)
|
Backbone.Mediator.subscribe(channel, func, @)
|
||||||
|
|
||||||
unsubscribeAll: ->
|
unsubscribeAll: ->
|
||||||
|
return unless Backbone?.Mediator?
|
||||||
for channel, func of @subscriptions
|
for channel, func of @subscriptions
|
||||||
func = utils.normalizeFunc(func, @)
|
func = utils.normalizeFunc(func, @)
|
||||||
Backbone.Mediator.unsubscribe(channel, func, @)
|
Backbone.Mediator.unsubscribe(channel, func, @)
|
||||||
|
|
|
@ -47,7 +47,9 @@ module.exports = class God extends CocoClass
|
||||||
|
|
||||||
setLevel: (@level) ->
|
setLevel: (@level) ->
|
||||||
setLevelSessionIDs: (@levelSessionIDs) ->
|
setLevelSessionIDs: (@levelSessionIDs) ->
|
||||||
setGoalManager: (goalManager) -> @angelsShare.goalManager = goalManager
|
setGoalManager: (goalManager) ->
|
||||||
|
@angelsShare.goalManager?.destroy() unless @angelsShare.goalManager is goalManager
|
||||||
|
@angelsShare.goalManager = goalManager
|
||||||
setWorldClassMap: (worldClassMap) -> @angelsShare.worldClassMap = worldClassMap
|
setWorldClassMap: (worldClassMap) -> @angelsShare.worldClassMap = worldClassMap
|
||||||
|
|
||||||
onTomeCast: (e) ->
|
onTomeCast: (e) ->
|
||||||
|
|
|
@ -63,12 +63,14 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
url += "?team=#{@team}" if @team
|
url += "?team=#{@team}" if @team
|
||||||
|
|
||||||
session = new LevelSession().setURL url
|
session = new LevelSession().setURL url
|
||||||
@session = @supermodel.loadModel(session, 'level_session', {cache:false}).model
|
@sessionResource = @supermodel.loadModel(session, 'level_session', {cache:false})
|
||||||
|
@session = @sessionResource.model
|
||||||
@session.once 'sync', -> @url = -> '/db/level.session/' + @id
|
@session.once 'sync', -> @url = -> '/db/level.session/' + @id
|
||||||
|
|
||||||
if @opponentSessionID
|
if @opponentSessionID
|
||||||
opponentSession = new LevelSession().setURL "/db/level_session/#{@opponentSessionID}"
|
opponentSession = new LevelSession().setURL "/db/level_session/#{@opponentSessionID}"
|
||||||
@opponentSession = @supermodel.loadModel(opponentSession, 'opponent_session').model
|
@opponentSessionResource = @supermodel.loadModel(opponentSession, 'opponent_session')
|
||||||
|
@opponentSession = @opponentSessionResource.model
|
||||||
|
|
||||||
# Supermodel (Level) Loading
|
# Supermodel (Level) Loading
|
||||||
|
|
||||||
|
@ -111,6 +113,8 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
@thangIDs = _.uniq thangIDs
|
@thangIDs = _.uniq thangIDs
|
||||||
@thangNames = new ThangNamesCollection(@thangIDs)
|
@thangNames = new ThangNamesCollection(@thangIDs)
|
||||||
worldNecessities.push @supermodel.loadCollection(@thangNames, 'thang_names')
|
worldNecessities.push @supermodel.loadCollection(@thangNames, 'thang_names')
|
||||||
|
worldNecessities.push @sessionResource if @sessionResource?.isLoading
|
||||||
|
worldNecessities.push @opponentSessionResource if @opponentSessionResource?.isLoading
|
||||||
|
|
||||||
for obj in objUniq componentVersions
|
for obj in objUniq componentVersions
|
||||||
url = "/db/level.component/#{obj.original}/version/#{obj.majorVersion}"
|
url = "/db/level.component/#{obj.original}/version/#{obj.majorVersion}"
|
||||||
|
@ -144,6 +148,7 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
|
|
||||||
for thangTypeName in thangsToLoad
|
for thangTypeName in thangsToLoad
|
||||||
thangType = nameModelMap[thangTypeName]
|
thangType = nameModelMap[thangTypeName]
|
||||||
|
continue if thangType.isFullyLoaded()
|
||||||
thangType.fetch()
|
thangType.fetch()
|
||||||
thangType = @supermodel.loadModel(thangType, 'thang').model
|
thangType = @supermodel.loadModel(thangType, 'thang').model
|
||||||
res = @supermodel.addSomethingResource "sprite_sheet", 5
|
res = @supermodel.addSomethingResource "sprite_sheet", 5
|
||||||
|
@ -165,16 +170,27 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
app.tracker.updatePlayState(@level, @session) unless @headless
|
app.tracker.updatePlayState(@level, @session) unless @headless
|
||||||
|
|
||||||
buildLoop: =>
|
buildLoop: =>
|
||||||
return if @lastBuilt and new Date().getTime() - @lastBuilt < 10
|
someLeft = false
|
||||||
return clearInterval @buildLoopInterval unless @spriteSheetsToBuild.length
|
|
||||||
|
|
||||||
for spriteSheetResource, i in @spriteSheetsToBuild
|
for spriteSheetResource, i in @spriteSheetsToBuild
|
||||||
if spriteSheetResource.thangType.loaded
|
continue if spriteSheetResource.spriteSheetKeys
|
||||||
@buildSpriteSheetsForThangType spriteSheetResource.thangType
|
someLeft = true
|
||||||
@spriteSheetsToBuild.splice i, 1
|
thangType = spriteSheetResource.thangType
|
||||||
@lastBuilt = new Date().getTime()
|
if thangType.loaded and not thangType.loading
|
||||||
spriteSheetResource.markLoaded()
|
keys = @buildSpriteSheetsForThangType spriteSheetResource.thangType
|
||||||
return
|
if keys and keys.length
|
||||||
|
@listenTo spriteSheetResource.thangType, 'build-complete', @onBuildComplete
|
||||||
|
spriteSheetResource.spriteSheetKeys = keys
|
||||||
|
else
|
||||||
|
spriteSheetResource.markLoaded()
|
||||||
|
|
||||||
|
clearInterval @buildLoopInterval unless someLeft
|
||||||
|
|
||||||
|
onBuildComplete: (e) ->
|
||||||
|
resource = null
|
||||||
|
for resource in @spriteSheetsToBuild
|
||||||
|
break if e.thangType is resource.thangType
|
||||||
|
resource.spriteSheetKeys = (k for k in resource.spriteSheetKeys when k isnt e.key)
|
||||||
|
resource.markLoaded() if resource.spriteSheetKeys.length is 0
|
||||||
|
|
||||||
denormalizeSession: ->
|
denormalizeSession: ->
|
||||||
return if @headless or @sessionDenormalized or @spectateMode
|
return if @headless or @sessionDenormalized or @spectateMode
|
||||||
|
@ -201,13 +217,16 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
# queue = new createjs.LoadQueue()
|
# queue = new createjs.LoadQueue()
|
||||||
# queue.loadFile('/file/'+f)
|
# queue.loadFile('/file/'+f)
|
||||||
@grabThangTypeTeams() unless @thangTypeTeams
|
@grabThangTypeTeams() unless @thangTypeTeams
|
||||||
|
keys = []
|
||||||
for team in @thangTypeTeams[thangType.get('original')] ? [null]
|
for team in @thangTypeTeams[thangType.get('original')] ? [null]
|
||||||
spriteOptions = {resolutionFactor: SPRITE_RESOLUTION_FACTOR, async: false}
|
spriteOptions = {resolutionFactor: SPRITE_RESOLUTION_FACTOR, async: true}
|
||||||
if thangType.get('kind') is 'Floor'
|
if thangType.get('kind') is 'Floor'
|
||||||
spriteOptions.resolutionFactor = 2
|
spriteOptions.resolutionFactor = 2
|
||||||
if team and color = @teamConfigs[team]?.color
|
if team and color = @teamConfigs[team]?.color
|
||||||
spriteOptions.colorConfig = team: color
|
spriteOptions.colorConfig = team: color
|
||||||
@buildSpriteSheet thangType, spriteOptions
|
key = @buildSpriteSheet thangType, spriteOptions
|
||||||
|
if _.isString(key) then keys.push key
|
||||||
|
keys
|
||||||
|
|
||||||
grabThangTypeTeams: ->
|
grabThangTypeTeams: ->
|
||||||
@grabTeamConfigs()
|
@grabTeamConfigs()
|
||||||
|
|
|
@ -35,6 +35,7 @@ module.exports = class DOMScriptModule extends ScriptModule
|
||||||
sides: dom.highlight.sides
|
sides: dom.highlight.sides
|
||||||
offset: dom.highlight.offset
|
offset: dom.highlight.offset
|
||||||
rotation: dom.highlight.rotation
|
rotation: dom.highlight.rotation
|
||||||
|
note.event = _.pick note.event, (value) -> not _.isUndefined value
|
||||||
@maybeApplyDelayToNote note
|
@maybeApplyDelayToNote note
|
||||||
note
|
note
|
||||||
|
|
||||||
|
|
|
@ -52,12 +52,14 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
|
||||||
@debugScripts = @view.getQueryVariable 'dev'
|
@debugScripts = @view.getQueryVariable 'dev'
|
||||||
@initProperties()
|
@initProperties()
|
||||||
@addScriptSubscriptions()
|
@addScriptSubscriptions()
|
||||||
|
@beginTicking()
|
||||||
|
|
||||||
setScripts: (@originalScripts) ->
|
setScripts: (@originalScripts) ->
|
||||||
@quiet = true
|
@quiet = true
|
||||||
@initProperties()
|
@initProperties()
|
||||||
@loadFromSession()
|
@loadFromSession()
|
||||||
@quiet = false
|
@quiet = false
|
||||||
|
@addScriptSubscriptions()
|
||||||
@run()
|
@run()
|
||||||
|
|
||||||
initProperties: ->
|
initProperties: ->
|
||||||
|
@ -74,6 +76,25 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
|
||||||
script.id = (idNum++).toString() unless script.id
|
script.id = (idNum++).toString() unless script.id
|
||||||
callback = makeCallback(script.channel) # curry in the channel argument
|
callback = makeCallback(script.channel) # curry in the channel argument
|
||||||
@addNewSubscription(script.channel, callback)
|
@addNewSubscription(script.channel, callback)
|
||||||
|
|
||||||
|
beginTicking: ->
|
||||||
|
@tickInterval = setInterval @tick, 5000
|
||||||
|
|
||||||
|
tick: =>
|
||||||
|
scriptStates = {}
|
||||||
|
now = new Date()
|
||||||
|
for script in @scripts
|
||||||
|
scriptStates[script.id] =
|
||||||
|
timeSinceLastEnded: (if script.lastEnded then now - script.lastEnded else 0) / 1000
|
||||||
|
timeSinceLastTriggered: (if script.lastTriggered then now - script.lastTriggered else 0) / 1000
|
||||||
|
|
||||||
|
stateEvent =
|
||||||
|
scriptRunning: @currentNoteGroup?.scriptID or ''
|
||||||
|
noteGroupRunning: @currentNoteGroup?.name or ''
|
||||||
|
scriptStates: scriptStates
|
||||||
|
timeSinceLastScriptEnded: (if @lastScriptEnded then now - @lastScriptEnded else 0) / 1000
|
||||||
|
|
||||||
|
Backbone.Mediator.publish 'script-manager:tick', stateEvent
|
||||||
|
|
||||||
loadFromSession: ->
|
loadFromSession: ->
|
||||||
# load the queue with note groups to skip through
|
# load the queue with note groups to skip through
|
||||||
|
@ -88,6 +109,7 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
|
||||||
return unless script
|
return unless script
|
||||||
@triggered.push(script.id)
|
@triggered.push(script.id)
|
||||||
noteChain = @processScript(script)
|
noteChain = @processScript(script)
|
||||||
|
return unless noteChain
|
||||||
if scripts.currentScriptOffset
|
if scripts.currentScriptOffset
|
||||||
noteGroup.skipMe = true for noteGroup in noteChain[..scripts.currentScriptOffset-1]
|
noteGroup.skipMe = true for noteGroup in noteChain[..scripts.currentScriptOffset-1]
|
||||||
@addNoteChain(noteChain, false)
|
@addNoteChain(noteChain, false)
|
||||||
|
@ -107,6 +129,7 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
|
||||||
@triggered.push(scriptID)
|
@triggered.push(scriptID)
|
||||||
@ended.push(scriptID)
|
@ended.push(scriptID)
|
||||||
noteChain = @processScript(script)
|
noteChain = @processScript(script)
|
||||||
|
return unless noteChain
|
||||||
noteGroup.skipMe = true for noteGroup in noteChain
|
noteGroup.skipMe = true for noteGroup in noteChain
|
||||||
@addNoteChain(noteChain, false)
|
@addNoteChain(noteChain, false)
|
||||||
|
|
||||||
|
@ -123,6 +146,7 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
|
||||||
|
|
||||||
destroy: ->
|
destroy: ->
|
||||||
@onEndAll()
|
@onEndAll()
|
||||||
|
clearInterval @tickInterval
|
||||||
super()
|
super()
|
||||||
|
|
||||||
# TRIGGERERING NOTES
|
# TRIGGERERING NOTES
|
||||||
|
@ -147,10 +171,11 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
|
||||||
continue unless @scriptPrereqsSatisfied(script)
|
continue unless @scriptPrereqsSatisfied(script)
|
||||||
continue unless scriptMatchesEventPrereqs(script, event)
|
continue unless scriptMatchesEventPrereqs(script, event)
|
||||||
# everything passed!
|
# everything passed!
|
||||||
console.log "SCRIPT: Running script '#{script.id}'" if @debugScripts
|
console.debug "SCRIPT: Running script '#{script.id}'" if @debugScripts
|
||||||
script.lastTriggered = new Date().getTime()
|
script.lastTriggered = new Date().getTime()
|
||||||
@triggered.push(script.id) unless alreadyTriggered
|
@triggered.push(script.id) unless alreadyTriggered
|
||||||
noteChain = @processScript(script)
|
noteChain = @processScript(script)
|
||||||
|
if not noteChain then return @trackScriptCompletions (script.id)
|
||||||
@addNoteChain(noteChain)
|
@addNoteChain(noteChain)
|
||||||
@run()
|
@run()
|
||||||
|
|
||||||
|
@ -159,10 +184,10 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
|
||||||
|
|
||||||
processScript: (script) ->
|
processScript: (script) ->
|
||||||
noteChain = script.noteChain
|
noteChain = script.noteChain
|
||||||
|
return null unless noteChain?.length
|
||||||
noteGroup.scriptID = script.id for noteGroup in noteChain
|
noteGroup.scriptID = script.id for noteGroup in noteChain
|
||||||
if noteChain.length
|
lastNoteGroup = noteChain[noteChain.length - 1]
|
||||||
lastNoteGroup = noteChain[noteChain.length - 1]
|
lastNoteGroup.isLast = true
|
||||||
lastNoteGroup.isLast = true
|
|
||||||
return noteChain
|
return noteChain
|
||||||
|
|
||||||
addNoteChain: (noteChain, clearYields=true) ->
|
addNoteChain: (noteChain, clearYields=true) ->
|
||||||
|
@ -207,7 +232,7 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
|
||||||
@notifyScriptStateChanged()
|
@notifyScriptStateChanged()
|
||||||
@scriptInProgress = true
|
@scriptInProgress = true
|
||||||
@currentTimeouts = []
|
@currentTimeouts = []
|
||||||
console.log "SCRIPT: Starting note group '#{nextNoteGroup.name}'" if @debugScripts
|
console.debug "SCRIPT: Starting note group '#{nextNoteGroup.name}'" if @debugScripts
|
||||||
for module in nextNoteGroup.modules
|
for module in nextNoteGroup.modules
|
||||||
@processNote(note, nextNoteGroup) for note in module.startNotes()
|
@processNote(note, nextNoteGroup) for note in module.startNotes()
|
||||||
if nextNoteGroup.script.duration
|
if nextNoteGroup.script.duration
|
||||||
|
@ -221,12 +246,12 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
|
||||||
@ignoreEvents = true
|
@ignoreEvents = true
|
||||||
for noteGroup, i in @noteGroupQueue
|
for noteGroup, i in @noteGroupQueue
|
||||||
break unless noteGroup.skipMe
|
break unless noteGroup.skipMe
|
||||||
console.log "SCRIPT: Skipping note group '#{noteGroup.name}'" if @debugScripts
|
console.debug "SCRIPT: Skipping note group '#{noteGroup.name}'" if @debugScripts
|
||||||
@processNoteGroup(noteGroup)
|
@processNoteGroup(noteGroup)
|
||||||
for module in noteGroup.modules
|
for module in noteGroup.modules
|
||||||
notes = module.skipNotes()
|
notes = module.skipNotes()
|
||||||
@processNote(note, noteGroup) for note in notes
|
@processNote(note, noteGroup) for note in notes
|
||||||
@trackScriptCompletions(noteGroup)
|
@trackScriptCompletionsFromNoteGroup(noteGroup)
|
||||||
@noteGroupQueue = @noteGroupQueue[i..]
|
@noteGroupQueue = @noteGroupQueue[i..]
|
||||||
@ignoreEvents = false
|
@ignoreEvents = false
|
||||||
|
|
||||||
|
@ -268,14 +293,13 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
|
||||||
return if @ending # kill infinite loops right here
|
return if @ending # kill infinite loops right here
|
||||||
@ending = true
|
@ending = true
|
||||||
return unless @currentNoteGroup?
|
return unless @currentNoteGroup?
|
||||||
console.log "SCRIPT: Ending note group '#{@currentNoteGroup.name}'" if @debugScripts
|
console.debug "SCRIPT: Ending note group '#{@currentNoteGroup.name}'" if @debugScripts
|
||||||
clearTimeout(timeout) for timeout in @currentTimeouts
|
clearTimeout(timeout) for timeout in @currentTimeouts
|
||||||
for module in @currentNoteGroup.modules
|
for module in @currentNoteGroup.modules
|
||||||
@processNote(note, @currentNoteGroup) for note in module.endNotes()
|
@processNote(note, @currentNoteGroup) for note in module.endNotes()
|
||||||
Backbone.Mediator.publish 'note-group-ended' unless @quiet
|
Backbone.Mediator.publish 'note-group-ended' unless @quiet
|
||||||
@scriptInProgress = false
|
@scriptInProgress = false
|
||||||
@ended.push(@currentNoteGroup.scriptID) if @currentNoteGroup.isLast
|
@trackScriptCompletionsFromNoteGroup(@currentNoteGroup)
|
||||||
@trackScriptCompletions(@currentNoteGroup)
|
|
||||||
@currentNoteGroup = null
|
@currentNoteGroup = null
|
||||||
unless @noteGroupQueue.length
|
unless @noteGroupQueue.length
|
||||||
@notifyScriptStateChanged()
|
@notifyScriptStateChanged()
|
||||||
|
@ -302,7 +326,7 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
|
||||||
for module in noteGroup.modules
|
for module in noteGroup.modules
|
||||||
notes = module.skipNotes()
|
notes = module.skipNotes()
|
||||||
@processNote(note, noteGroup) for note in notes unless @quiet
|
@processNote(note, noteGroup) for note in notes unless @quiet
|
||||||
@trackScriptCompletions(noteGroup) unless @quiet
|
@trackScriptCompletionsFromNoteGroup(noteGroup) unless @quiet
|
||||||
|
|
||||||
@noteGroupQueue = []
|
@noteGroupQueue = []
|
||||||
|
|
||||||
|
@ -317,11 +341,18 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
|
||||||
Backbone.Mediator.publish 'level-enable-controls', {}
|
Backbone.Mediator.publish 'level-enable-controls', {}
|
||||||
Backbone.Mediator.publish 'level-set-letterbox', { on: false }
|
Backbone.Mediator.publish 'level-set-letterbox', { on: false }
|
||||||
|
|
||||||
trackScriptCompletions: (noteGroup) ->
|
trackScriptCompletionsFromNoteGroup: (noteGroup) ->
|
||||||
return if @quiet
|
|
||||||
return unless noteGroup.isLast
|
return unless noteGroup.isLast
|
||||||
@ended.push(noteGroup.scriptID) unless noteGroup.scriptID in @ended
|
@trackScriptCompletions(noteGroup.scriptID)
|
||||||
Backbone.Mediator.publish 'script:ended', {scriptID: noteGroup.scriptID}
|
|
||||||
|
trackScriptCompletions: (scriptID) ->
|
||||||
|
return if @quiet
|
||||||
|
@ended.push(scriptID) unless scriptID in @ended
|
||||||
|
for script in @scripts
|
||||||
|
if script.id is scriptID
|
||||||
|
script.lastEnded = new Date()
|
||||||
|
@lastScriptEnded = new Date()
|
||||||
|
Backbone.Mediator.publish 'script:ended', {scriptID: scriptID}
|
||||||
|
|
||||||
notifyScriptStateChanged: ->
|
notifyScriptStateChanged: ->
|
||||||
return if @quiet
|
return if @quiet
|
||||||
|
|
|
@ -36,4 +36,4 @@ module.exports = class ScriptModule extends CocoClass
|
||||||
Math.max(0, sums...)
|
Math.max(0, sums...)
|
||||||
|
|
||||||
maybeApplyDelayToNote: (note) ->
|
maybeApplyDelayToNote: (note) ->
|
||||||
note.delay = @scrubbingTime + @movementTime
|
note.delay = (@scrubbingTime + @movementTime) or 0
|
|
@ -23,7 +23,7 @@ module.exports = class Simulator extends CocoClass
|
||||||
@cleanupSimulation()
|
@cleanupSimulation()
|
||||||
@god?.destroy()
|
@god?.destroy()
|
||||||
super()
|
super()
|
||||||
|
|
||||||
fetchAndSimulateOneGame: (humanGameID, ogresGameID) =>
|
fetchAndSimulateOneGame: (humanGameID, ogresGameID) =>
|
||||||
return if @destroyed
|
return if @destroyed
|
||||||
$.ajax
|
$.ajax
|
||||||
|
@ -34,20 +34,22 @@ module.exports = class Simulator extends CocoClass
|
||||||
"humansGameID": humanGameID
|
"humansGameID": humanGameID
|
||||||
"ogresGameID": ogresGameID
|
"ogresGameID": ogresGameID
|
||||||
error: (errorData) ->
|
error: (errorData) ->
|
||||||
console.log "There was an error fetching two games! #{JSON.stringify errorData}"
|
console.warn "There was an error fetching two games! #{JSON.stringify errorData}"
|
||||||
success: (taskData) =>
|
success: (taskData) =>
|
||||||
|
return if @destroyed
|
||||||
@trigger 'statusUpdate', 'Setting up simulation...'
|
@trigger 'statusUpdate', 'Setting up simulation...'
|
||||||
#refactor this
|
#refactor this
|
||||||
@task = new SimulationTask(taskData)
|
@task = new SimulationTask(taskData)
|
||||||
|
|
||||||
@supermodel ?= new SuperModel()
|
@supermodel ?= new SuperModel()
|
||||||
@supermodel.resetProgress()
|
@supermodel.resetProgress()
|
||||||
@levelLoader = new LevelLoader supermodel: @supermodel, levelID: @task.getLevelName(), sessionID: @task.getFirstSessionID(), headless: true
|
@levelLoader = new LevelLoader supermodel: @supermodel, levelID: @task.getLevelName(), sessionID: @task.getFirstSessionID(), headless: true
|
||||||
|
|
||||||
if @supermodel.finished()
|
if @supermodel.finished()
|
||||||
@simulateSingleGame()
|
@simulateSingleGame()
|
||||||
else
|
else
|
||||||
@listenToOnce @supermodel, 'loaded-all', @simulateSingleGame
|
@listenToOnce @supermodel, 'loaded-all', @simulateSingleGame
|
||||||
|
|
||||||
simulateSingleGame: ->
|
simulateSingleGame: ->
|
||||||
return if @destroyed
|
return if @destroyed
|
||||||
@trigger 'statusUpdate', 'Simulating...'
|
@trigger 'statusUpdate', 'Simulating...'
|
||||||
|
@ -55,32 +57,31 @@ module.exports = class Simulator extends CocoClass
|
||||||
@setupGod()
|
@setupGod()
|
||||||
try
|
try
|
||||||
@commenceSingleSimulation()
|
@commenceSingleSimulation()
|
||||||
catch err
|
catch error
|
||||||
console.log err
|
@handleSingleSimulationError error
|
||||||
@handleSingleSimulationError()
|
|
||||||
|
|
||||||
commenceSingleSimulation: ->
|
commenceSingleSimulation: ->
|
||||||
@god.createWorld @generateSpellsObject()
|
@god.createWorld @generateSpellsObject()
|
||||||
Backbone.Mediator.subscribeOnce 'god:infinite-loop', @handleSingleSimulationInfiniteLoop, @
|
Backbone.Mediator.subscribeOnce 'god:infinite-loop', @handleSingleSimulationInfiniteLoop, @
|
||||||
Backbone.Mediator.subscribeOnce 'god:goals-calculated', @processSingleGameResults, @
|
Backbone.Mediator.subscribeOnce 'god:goals-calculated', @processSingleGameResults, @
|
||||||
|
|
||||||
handleSingleSimulationError: ->
|
handleSingleSimulationError: (error) ->
|
||||||
console.log "There was an error simulating a single game!"
|
console.error "There was an error simulating a single game!", error
|
||||||
if @options.headlessClient
|
if @options.headlessClient
|
||||||
console.log "GAMERESULT:tie"
|
console.log "GAMERESULT:tie"
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
@cleanupSimulation()
|
@cleanupSimulation()
|
||||||
|
|
||||||
handleSingleSimulationInfiniteLoop: ->
|
handleSingleSimulationInfiniteLoop: ->
|
||||||
console.log "There was an infinite loop in the single game!"
|
console.log "There was an infinite loop in the single game!"
|
||||||
if @options.headlessClient
|
if @options.headlessClient
|
||||||
console.log "GAMERESULT:tie"
|
console.log "GAMERESULT:tie"
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
@cleanupSimulation()
|
@cleanupSimulation()
|
||||||
|
|
||||||
processSingleGameResults: (simulationResults) ->
|
processSingleGameResults: (simulationResults) ->
|
||||||
console.log "Processing results!"
|
|
||||||
taskResults = @formTaskResultsObject simulationResults
|
taskResults = @formTaskResultsObject simulationResults
|
||||||
|
console.log "Processing results:", taskResults
|
||||||
humanSessionRank = taskResults.sessions[0].metrics.rank
|
humanSessionRank = taskResults.sessions[0].metrics.rank
|
||||||
ogreSessionRank = taskResults.sessions[1].metrics.rank
|
ogreSessionRank = taskResults.sessions[1].metrics.rank
|
||||||
if @options.headlessClient
|
if @options.headlessClient
|
||||||
|
@ -93,12 +94,12 @@ module.exports = class Simulator extends CocoClass
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
else
|
else
|
||||||
@sendSingleGameBackToServer(taskResults)
|
@sendSingleGameBackToServer(taskResults)
|
||||||
|
|
||||||
@cleanupSimulation()
|
@cleanupSimulation()
|
||||||
|
|
||||||
sendSingleGameBackToServer: (results) ->
|
sendSingleGameBackToServer: (results) ->
|
||||||
@trigger 'statusUpdate', 'Simulation completed, sending results back to server!'
|
@trigger 'statusUpdate', 'Simulation completed, sending results back to server!'
|
||||||
|
|
||||||
$.ajax
|
$.ajax
|
||||||
url: "/queue/scoring/recordTwoGames"
|
url: "/queue/scoring/recordTwoGames"
|
||||||
data: results
|
data: results
|
||||||
|
@ -107,8 +108,8 @@ module.exports = class Simulator extends CocoClass
|
||||||
success: @handleTaskResultsTransferSuccess
|
success: @handleTaskResultsTransferSuccess
|
||||||
error: @handleTaskResultsTransferError
|
error: @handleTaskResultsTransferError
|
||||||
complete: @cleanupAndSimulateAnotherTask
|
complete: @cleanupAndSimulateAnotherTask
|
||||||
|
|
||||||
|
|
||||||
fetchAndSimulateTask: =>
|
fetchAndSimulateTask: =>
|
||||||
return if @destroyed
|
return if @destroyed
|
||||||
|
|
||||||
|
@ -134,7 +135,7 @@ module.exports = class Simulator extends CocoClass
|
||||||
console.error "There was a horrible Error: #{JSON.stringify errorData}"
|
console.error "There was a horrible Error: #{JSON.stringify errorData}"
|
||||||
@trigger 'statusUpdate', 'There was an error fetching games to simulate. Retrying in 10 seconds.'
|
@trigger 'statusUpdate', 'There was an error fetching games to simulate. Retrying in 10 seconds.'
|
||||||
@simulateAnotherTaskAfterDelay()
|
@simulateAnotherTaskAfterDelay()
|
||||||
|
|
||||||
|
|
||||||
handleNoGamesResponse: ->
|
handleNoGamesResponse: ->
|
||||||
info = 'Finding game to simulate...'
|
info = 'Finding game to simulate...'
|
||||||
|
@ -191,7 +192,7 @@ module.exports = class Simulator extends CocoClass
|
||||||
|
|
||||||
setupGod: ->
|
setupGod: ->
|
||||||
@god.setLevel @level.serialize @supermodel
|
@god.setLevel @level.serialize @supermodel
|
||||||
@god.setLevelSessionIDs (session.id for session in @task.getSessions())
|
@god.setLevelSessionIDs (session.sessionID for session in @task.getSessions())
|
||||||
@god.setWorldClassMap @world.classMap
|
@god.setWorldClassMap @world.classMap
|
||||||
@god.setGoalManager new GoalManager(@world, @level.get 'goals')
|
@god.setGoalManager new GoalManager(@world, @level.get 'goals')
|
||||||
|
|
||||||
|
@ -235,7 +236,7 @@ module.exports = class Simulator extends CocoClass
|
||||||
|
|
||||||
sendResultsBackToServer: (results) ->
|
sendResultsBackToServer: (results) ->
|
||||||
@trigger 'statusUpdate', 'Simulation completed, sending results back to server!'
|
@trigger 'statusUpdate', 'Simulation completed, sending results back to server!'
|
||||||
console.log "Sending result back to server!", results
|
console.log "Sending result back to server:", results
|
||||||
|
|
||||||
if @options.headlessClient and @options.testing
|
if @options.headlessClient and @options.testing
|
||||||
return @fetchAndSimulateTask()
|
return @fetchAndSimulateTask()
|
||||||
|
@ -250,9 +251,10 @@ module.exports = class Simulator extends CocoClass
|
||||||
complete: @cleanupAndSimulateAnotherTask
|
complete: @cleanupAndSimulateAnotherTask
|
||||||
|
|
||||||
handleTaskResultsTransferSuccess: (result) =>
|
handleTaskResultsTransferSuccess: (result) =>
|
||||||
|
return if @destroyed
|
||||||
console.log "Task registration result: #{JSON.stringify result}"
|
console.log "Task registration result: #{JSON.stringify result}"
|
||||||
@trigger 'statusUpdate', 'Results were successfully sent back to server!'
|
@trigger 'statusUpdate', 'Results were successfully sent back to server!'
|
||||||
console.log "Simulated by you: " + @simulatedByYou
|
console.log "Simulated by you:", @simulatedByYou
|
||||||
@simulatedByYou++
|
@simulatedByYou++
|
||||||
unless @options.headlessClient
|
unless @options.headlessClient
|
||||||
simulatedBy = parseInt($('#simulated-by-you').text(), 10) + 1
|
simulatedBy = parseInt($('#simulated-by-you').text(), 10) + 1
|
||||||
|
@ -260,10 +262,12 @@ module.exports = class Simulator extends CocoClass
|
||||||
application.tracker?.trackEvent 'Simulator Result', label: "Success"
|
application.tracker?.trackEvent 'Simulator Result', label: "Success"
|
||||||
|
|
||||||
handleTaskResultsTransferError: (error) =>
|
handleTaskResultsTransferError: (error) =>
|
||||||
|
return if @destroyed
|
||||||
@trigger 'statusUpdate', 'There was an error sending the results back to the server.'
|
@trigger 'statusUpdate', 'There was an error sending the results back to the server.'
|
||||||
console.log "Task registration error: #{JSON.stringify error}"
|
console.log "Task registration error: #{JSON.stringify error}"
|
||||||
|
|
||||||
cleanupAndSimulateAnotherTask: =>
|
cleanupAndSimulateAnotherTask: =>
|
||||||
|
return if @destroyed
|
||||||
@cleanupSimulation()
|
@cleanupSimulation()
|
||||||
@fetchAndSimulateTask()
|
@fetchAndSimulateTask()
|
||||||
|
|
||||||
|
@ -472,6 +476,5 @@ class SimulationTask
|
||||||
spellKey = pathComponents.join '/'
|
spellKey = pathComponents.join '/'
|
||||||
@thangSpells[thang.id].push spellKey
|
@thangSpells[thang.id].push spellKey
|
||||||
if not method.cloneOf and spellKey is desiredSpellKey
|
if not method.cloneOf and spellKey is desiredSpellKey
|
||||||
console.log "Setting #{desiredSpellKey} from world!"
|
#console.log "Setting #{desiredSpellKey} from world!"
|
||||||
|
|
||||||
return method.source
|
return method.source
|
||||||
|
|
|
@ -33,6 +33,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
||||||
camera: null
|
camera: null
|
||||||
spriteSheetCache: null
|
spriteSheetCache: null
|
||||||
showInvisible: false
|
showInvisible: false
|
||||||
|
async: true
|
||||||
|
|
||||||
possessed: false
|
possessed: false
|
||||||
flipped: false
|
flipped: false
|
||||||
|
@ -75,28 +76,32 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
||||||
@ranges = []
|
@ranges = []
|
||||||
@handledDisplayEvents = {}
|
@handledDisplayEvents = {}
|
||||||
@age = 0
|
@age = 0
|
||||||
|
@stillLoading = true
|
||||||
if @thangType.isFullyLoaded()
|
if @thangType.isFullyLoaded()
|
||||||
@setupSprite()
|
@setupSprite()
|
||||||
else
|
else
|
||||||
@stillLoading = true
|
|
||||||
@thangType.fetch()
|
@thangType.fetch()
|
||||||
@listenToOnce(@thangType, 'sync', @setupSprite)
|
@listenToOnce(@thangType, 'sync', @setupSprite)
|
||||||
|
|
||||||
setupSprite: ->
|
setupSprite: ->
|
||||||
for trigger, sounds of @thangType.get('soundTriggers') or {} when trigger isnt 'say'
|
for trigger, sounds of @thangType.get('soundTriggers') or {} when trigger isnt 'say'
|
||||||
AudioPlayer.preloadSoundReference sound for sound in sounds
|
AudioPlayer.preloadSoundReference sound for sound in sounds
|
||||||
@stillLoading = false
|
|
||||||
if @thangType.get('raster')
|
if @thangType.get('raster')
|
||||||
|
@stillLoading = false
|
||||||
@actions = {}
|
@actions = {}
|
||||||
@isRaster = true
|
@isRaster = true
|
||||||
@setUpRasterImage()
|
@setUpRasterImage()
|
||||||
else
|
else
|
||||||
@actions = @thangType.getActions()
|
result = @buildSpriteSheet()
|
||||||
@buildFromSpriteSheet @buildSpriteSheet()
|
if _.isString result # async build
|
||||||
@createMarks()
|
@listenToOnce @thangType, 'build-complete', @setupSprite
|
||||||
|
else
|
||||||
|
@stillLoading = false
|
||||||
|
@actions = @thangType.getActions()
|
||||||
|
@buildFromSpriteSheet result
|
||||||
|
@createMarks()
|
||||||
|
|
||||||
finishSetup: ->
|
finishSetup: ->
|
||||||
return unless @thang
|
|
||||||
@updateBaseScale()
|
@updateBaseScale()
|
||||||
@scaleFactor = @thang.scaleFactor if @thang?.scaleFactor
|
@scaleFactor = @thang.scaleFactor if @thang?.scaleFactor
|
||||||
@update true # Reflect initial scale and other state
|
@update true # Reflect initial scale and other state
|
||||||
|
@ -120,7 +125,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
||||||
buildSpriteSheet: ->
|
buildSpriteSheet: ->
|
||||||
options = _.extend @options, @thang?.getSpriteOptions?() ? {}
|
options = _.extend @options, @thang?.getSpriteOptions?() ? {}
|
||||||
options.colorConfig = @options.colorConfig if @options.colorConfig
|
options.colorConfig = @options.colorConfig if @options.colorConfig
|
||||||
options.async = false
|
options.async = @options.async
|
||||||
@thangType.getSpriteSheet options
|
@thangType.getSpriteSheet options
|
||||||
|
|
||||||
setImageObject: (newImageObject) ->
|
setImageObject: (newImageObject) ->
|
||||||
|
@ -677,6 +682,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
||||||
updateGold: ->
|
updateGold: ->
|
||||||
# TODO: eventually this should be moved into some sort of team-based update
|
# TODO: eventually this should be moved into some sort of team-based update
|
||||||
# rather than an each-thang-that-shows-gold-per-team thing.
|
# rather than an each-thang-that-shows-gold-per-team thing.
|
||||||
|
return unless @thang
|
||||||
return if @thang.gold is @lastGold
|
return if @thang.gold is @lastGold
|
||||||
gold = Math.floor @thang.gold
|
gold = Math.floor @thang.gold
|
||||||
if @thang.world.age is 0
|
if @thang.world.age is 0
|
||||||
|
@ -752,7 +758,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
||||||
|
|
||||||
endFunc = =>
|
endFunc = =>
|
||||||
@lastTween = null
|
@lastTween = null
|
||||||
@imageObject.gotoAndPlay(endAnimation)
|
@imageObject.gotoAndPlay(endAnimation) unless @stillLoading
|
||||||
@shadow.action = 'idle'
|
@shadow.action = 'idle'
|
||||||
@update true
|
@update true
|
||||||
@possessed = false
|
@possessed = false
|
||||||
|
|
|
@ -181,7 +181,8 @@ module.exports = class Mark extends CocoClass
|
||||||
|
|
||||||
return @listenToOnce(@thangType, 'sync', @onLoadedThangType) if not @thangType.loaded
|
return @listenToOnce(@thangType, 'sync', @onLoadedThangType) if not @thangType.loaded
|
||||||
CocoSprite = require './CocoSprite'
|
CocoSprite = require './CocoSprite'
|
||||||
markSprite = new CocoSprite @thangType, @thangType.spriteOptions
|
# don't bother with making these render async for now, but maybe later for fun and more complexity of code
|
||||||
|
markSprite = new CocoSprite @thangType, {async: false}
|
||||||
markSprite.queueAction 'idle'
|
markSprite.queueAction 'idle'
|
||||||
@mark = markSprite.imageObject
|
@mark = markSprite.imageObject
|
||||||
@markSprite = markSprite
|
@markSprite = markSprite
|
||||||
|
@ -234,28 +235,27 @@ module.exports = class Mark extends CocoClass
|
||||||
if @name is 'debug' or (@name is 'shadow' and @sprite.thang?.shape in ["rectangle", "box"])
|
if @name is 'debug' or (@name is 'shadow' and @sprite.thang?.shape in ["rectangle", "box"])
|
||||||
@mark.rotation = @sprite.thang.rotation * 180 / Math.PI
|
@mark.rotation = @sprite.thang.rotation * 180 / Math.PI
|
||||||
|
|
||||||
updateScale: ->
|
updateScale: (log) ->
|
||||||
if @name is 'bounds' and (@sprite.thang.width isnt @lastWidth or @sprite.thang.height isnt @lastHeight)
|
if @name is 'bounds' and (@sprite.thang.width isnt @lastWidth or @sprite.thang.height isnt @lastHeight)
|
||||||
oldMark = @mark
|
oldMark = @mark
|
||||||
@buildBounds()
|
@buildBounds()
|
||||||
oldMark.parent.addChild @mark
|
oldMark.parent.addChild @mark
|
||||||
oldMark.parent.swapChildren oldMark, @mark
|
oldMark.parent.swapChildren oldMark, @mark
|
||||||
oldMark.parent.removeChild oldMark
|
oldMark.parent.removeChild oldMark
|
||||||
|
|
||||||
|
if @markSprite?
|
||||||
|
@markSprite.scaleFactor = 1.2
|
||||||
|
@markSprite.updateScale()
|
||||||
return unless @name in ["selection", "target", "repair", "highlight"]
|
return unless @name in ["selection", "target", "repair", "highlight"]
|
||||||
scale = 0.5
|
|
||||||
if @sprite?.imageObject
|
if @sprite?.imageObject
|
||||||
size = @sprite.getAverageDimension()
|
size = @sprite.getAverageDimension()
|
||||||
size += 60 if @name is 'selection'
|
size += 60 if @name is 'selection'
|
||||||
size += 60 if @name is 'repair'
|
size += 60 if @name is 'repair'
|
||||||
size *= @sprite.scaleFactor
|
size *= @sprite.scaleFactor
|
||||||
scale = size / {selection: 128, target: 128, repair: 320, highlight: 160}[@name]
|
scale = size / {selection: 128, target: 128, repair: 320, highlight: 160}[@name]
|
||||||
|
scale /= 3
|
||||||
if @sprite?.thang.spriteName.search(/(dungeon|indoor).wall/i) isnt -1
|
if @sprite?.thang.spriteName.search(/(dungeon|indoor).wall/i) isnt -1
|
||||||
scale *= 2
|
scale *= 2
|
||||||
|
|
||||||
if @markSprite?
|
|
||||||
@markSprite.scaleFactor = scale
|
|
||||||
@markSprite.updateScale()
|
|
||||||
else
|
|
||||||
@mark.scaleX = @mark.scaleY = Math.min 1, scale
|
@mark.scaleX = @mark.scaleY = Math.min 1, scale
|
||||||
if @name in ['selection', 'target', 'repair']
|
if @name in ['selection', 'target', 'repair']
|
||||||
@mark.scaleY *= @camera.y2x # code applies perspective
|
@mark.scaleY *= @camera.y2x # code applies perspective
|
||||||
|
|
|
@ -21,21 +21,33 @@ module.exports = class MusicPlayer extends CocoClass
|
||||||
|
|
||||||
onPlayMusic: (e) ->
|
onPlayMusic: (e) ->
|
||||||
src = e.file
|
src = e.file
|
||||||
if src
|
src = "/file#{e.file}#{AudioPlayer.ext}"
|
||||||
src = "/file#{src}#{AudioPlayer.ext}"
|
if (not e.file) or src is @currentMusic?.src
|
||||||
return @currentMusic.play('none', 0, 0, -1, 0.3) if src is @currentMusic?.src
|
if e.play then @restartCurrentMusic() else @fadeOutCurrentMusic()
|
||||||
media = AudioPlayer.getStatus(src)
|
return
|
||||||
if not media?.loaded
|
|
||||||
AudioPlayer.preloadSound(src)
|
media = AudioPlayer.getStatus(src)
|
||||||
@standingBy = e
|
if not media?.loaded
|
||||||
return
|
AudioPlayer.preloadSound(src)
|
||||||
|
@standingBy = e
|
||||||
|
return
|
||||||
|
|
||||||
@standingBy = null
|
@standingBy = null
|
||||||
if @currentMusic
|
@fadeOutCurrentMusic()
|
||||||
f = -> @stop()
|
@startNewMusic(src) if e.play
|
||||||
createjs.Tween.get(@currentMusic).to({volume:0.0}, CROSSFADE_LENGTH).call(f)
|
|
||||||
|
restartCurrentMusic: ->
|
||||||
@currentMusic = createjs.Sound.play(src, 'none', 0, 0, -1, 0.3) if src and e.play
|
return unless @currentMusic
|
||||||
|
@currentMusic.play('none', 0, 0, -1, 0.3)
|
||||||
|
@updateMusicVolume()
|
||||||
|
|
||||||
|
fadeOutCurrentMusic: ->
|
||||||
|
return unless @currentMusic
|
||||||
|
f = -> @stop()
|
||||||
|
createjs.Tween.get(@currentMusic).to({volume:0.0}, CROSSFADE_LENGTH).call(f)
|
||||||
|
|
||||||
|
startNewMusic: (src) ->
|
||||||
|
@currentMusic = createjs.Sound.play(src, 'none', 0, 0, -1, 0.3) if src
|
||||||
return unless @currentMusic
|
return unless @currentMusic
|
||||||
@currentMusic.volume = 0.0
|
@currentMusic.volume = 0.0
|
||||||
if me.get('music')
|
if me.get('music')
|
||||||
|
|
|
@ -103,6 +103,7 @@ module.exports = Surface = class Surface extends CocoClass
|
||||||
@stage.removeAllChildren()
|
@stage.removeAllChildren()
|
||||||
@stage.removeEventListener 'stagemousemove', @onMouseMove
|
@stage.removeEventListener 'stagemousemove', @onMouseMove
|
||||||
@stage.removeEventListener 'stagemousedown', @onMouseDown
|
@stage.removeEventListener 'stagemousedown', @onMouseDown
|
||||||
|
@stage.removeEventListener 'stagemouseup', @onMouseUp
|
||||||
@stage.removeAllEventListeners()
|
@stage.removeAllEventListeners()
|
||||||
@stage.enableDOMEvents false
|
@stage.enableDOMEvents false
|
||||||
@stage.enableMouseOver 0
|
@stage.enableMouseOver 0
|
||||||
|
@ -281,6 +282,7 @@ module.exports = Surface = class Surface extends CocoClass
|
||||||
|
|
||||||
onSetPlaying: (e) ->
|
onSetPlaying: (e) ->
|
||||||
@playing = (e ? {}).playing ? true
|
@playing = (e ? {}).playing ? true
|
||||||
|
@setPlayingCalled = true
|
||||||
if @playing and @currentFrame >= (@world.totalFrames - 5)
|
if @playing and @currentFrame >= (@world.totalFrames - 5)
|
||||||
@currentFrame = 0
|
@currentFrame = 0
|
||||||
if @fastForwarding and not @playing
|
if @fastForwarding and not @playing
|
||||||
|
@ -352,6 +354,7 @@ module.exports = Surface = class Surface extends CocoClass
|
||||||
@casting = true
|
@casting = true
|
||||||
@wasPlayingWhenCastingBegan = @playing
|
@wasPlayingWhenCastingBegan = @playing
|
||||||
Backbone.Mediator.publish 'level-set-playing', { playing: false }
|
Backbone.Mediator.publish 'level-set-playing', { playing: false }
|
||||||
|
@setPlayingCalled = false # don't overwrite playing settings if they changed by, say, scripts
|
||||||
|
|
||||||
if @coordinateDisplay?
|
if @coordinateDisplay?
|
||||||
@surfaceTextLayer.removeChild @coordinateDisplay
|
@surfaceTextLayer.removeChild @coordinateDisplay
|
||||||
|
@ -370,7 +373,7 @@ module.exports = Surface = class Surface extends CocoClass
|
||||||
|
|
||||||
# This has a tendency to break scripts that are waiting for playback to change when the level is loaded
|
# This has a tendency to break scripts that are waiting for playback to change when the level is loaded
|
||||||
# so only run it after the first world is created.
|
# so only run it after the first world is created.
|
||||||
Backbone.Mediator.publish 'level-set-playing', { playing: @wasPlayingWhenCastingBegan } unless event.firstWorld
|
Backbone.Mediator.publish 'level-set-playing', { playing: @wasPlayingWhenCastingBegan } unless event.firstWorld or @setPlayingCalled
|
||||||
|
|
||||||
fastForwardTo = null
|
fastForwardTo = null
|
||||||
if @playing
|
if @playing
|
||||||
|
@ -414,6 +417,7 @@ module.exports = Surface = class Surface extends CocoClass
|
||||||
@stage.enableMouseOver(10)
|
@stage.enableMouseOver(10)
|
||||||
@stage.addEventListener 'stagemousemove', @onMouseMove
|
@stage.addEventListener 'stagemousemove', @onMouseMove
|
||||||
@stage.addEventListener 'stagemousedown', @onMouseDown
|
@stage.addEventListener 'stagemousedown', @onMouseDown
|
||||||
|
@stage.addEventListener 'stagemouseup', @onMouseUp
|
||||||
@canvas.on 'mousewheel', @onMouseWheel
|
@canvas.on 'mousewheel', @onMouseWheel
|
||||||
@hookUpChooseControls() if @options.choosing
|
@hookUpChooseControls() if @options.choosing
|
||||||
createjs.Ticker.timingMode = createjs.Ticker.RAF_SYNCHED
|
createjs.Ticker.timingMode = createjs.Ticker.RAF_SYNCHED
|
||||||
|
@ -537,6 +541,11 @@ module.exports = Surface = class Surface extends CocoClass
|
||||||
onBackground = not @stage.hitTest e.stageX, e.stageY
|
onBackground = not @stage.hitTest e.stageX, e.stageY
|
||||||
Backbone.Mediator.publish 'surface:stage-mouse-down', onBackground: onBackground, x: e.stageX, y: e.stageY, originalEvent: e
|
Backbone.Mediator.publish 'surface:stage-mouse-down', onBackground: onBackground, x: e.stageX, y: e.stageY, originalEvent: e
|
||||||
|
|
||||||
|
onMouseUp: (e) =>
|
||||||
|
return if @disabled
|
||||||
|
onBackground = not @stage.hitTest e.stageX, e.stageY
|
||||||
|
Backbone.Mediator.publish 'surface:stage-mouse-up', onBackground: onBackground, x: e.stageX, y: e.stageY, originalEvent: e
|
||||||
|
|
||||||
onMouseWheel: (e) =>
|
onMouseWheel: (e) =>
|
||||||
# https://github.com/brandonaaron/jquery-mousewheel
|
# https://github.com/brandonaaron/jquery-mousewheel
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
|
@ -39,8 +39,6 @@ module.exports = class WizardSprite extends IndieSprite
|
||||||
else if options.name
|
else if options.name
|
||||||
@setNameLabel options.name
|
@setNameLabel options.name
|
||||||
|
|
||||||
finishSetup: -> # No initial setup update needed.
|
|
||||||
|
|
||||||
makeIndieThang: (thangType, thangID, pos) ->
|
makeIndieThang: (thangType, thangID, pos) ->
|
||||||
thang = super thangType, thangID, pos
|
thang = super thangType, thangID, pos
|
||||||
thang.isSelectable = false
|
thang.isSelectable = false
|
||||||
|
@ -49,6 +47,13 @@ module.exports = class WizardSprite extends IndieSprite
|
||||||
thang.pos.z += thang.bobHeight
|
thang.pos.z += thang.bobHeight
|
||||||
thang
|
thang
|
||||||
|
|
||||||
|
finishSetup: ->
|
||||||
|
@updateBaseScale()
|
||||||
|
@scaleFactor = @thang.scaleFactor if @thang?.scaleFactor
|
||||||
|
@updateScale()
|
||||||
|
@updateRotation()
|
||||||
|
# Don't call general update() because Thang isn't built yet
|
||||||
|
|
||||||
onPlayerStatesChanged: (e) ->
|
onPlayerStatesChanged: (e) ->
|
||||||
for playerID, state of e.states
|
for playerID, state of e.states
|
||||||
continue unless playerID is @thang.id
|
continue unless playerID is @thang.id
|
||||||
|
|
|
@ -14,6 +14,7 @@ module.exports = class GoalManager extends CocoClass
|
||||||
# If you want weird goals or hybrid goals, make a custom goal.
|
# If you want weird goals or hybrid goals, make a custom goal.
|
||||||
|
|
||||||
nextGoalID: 0
|
nextGoalID: 0
|
||||||
|
nicks: ["GoalManager"]
|
||||||
|
|
||||||
constructor: (@world, @initialGoals, @team) ->
|
constructor: (@world, @initialGoals, @team) ->
|
||||||
super()
|
super()
|
||||||
|
|
|
@ -185,6 +185,22 @@ module.exports.thangNames = thangNames =
|
||||||
"Lacos"
|
"Lacos"
|
||||||
"Upfish"
|
"Upfish"
|
||||||
]
|
]
|
||||||
|
"Ogre Peon M": [
|
||||||
|
"Durbo"
|
||||||
|
"Kurger"
|
||||||
|
"Mudwich"
|
||||||
|
"Ba Bo"
|
||||||
|
"Zugger"
|
||||||
|
"Toe Pod"
|
||||||
|
]
|
||||||
|
"Ogre Peon F": [
|
||||||
|
"Iblet"
|
||||||
|
"Lorba"
|
||||||
|
"Zzoya"
|
||||||
|
"Yamra"
|
||||||
|
"Greeke"
|
||||||
|
"Vapa"
|
||||||
|
]
|
||||||
"Ogre M": [
|
"Ogre M": [
|
||||||
"Krogg"
|
"Krogg"
|
||||||
"Dronck"
|
"Dronck"
|
||||||
|
|
|
@ -3,10 +3,10 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
loading: "Carregando..."
|
loading: "Carregando..."
|
||||||
saving: "Salvando..."
|
saving: "Salvando..."
|
||||||
sending: "Enviando..."
|
sending: "Enviando..."
|
||||||
# send: "Send"
|
send: "Enviar"
|
||||||
cancel: "Cancelar"
|
cancel: "Cancelar"
|
||||||
save: "Salvar"
|
save: "Salvar"
|
||||||
# publish: "Publish"
|
publish: "Publicar"
|
||||||
create: "Criar"
|
create: "Criar"
|
||||||
delay_1_sec: "1 segundo"
|
delay_1_sec: "1 segundo"
|
||||||
delay_3_sec: "3 segundos"
|
delay_3_sec: "3 segundos"
|
||||||
|
@ -14,7 +14,7 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
manual: "Manual"
|
manual: "Manual"
|
||||||
fork: "Fork"
|
fork: "Fork"
|
||||||
play: "Jogar"
|
play: "Jogar"
|
||||||
# retry: "Retry"
|
retry: "Tente novamente"
|
||||||
# watch: "Watch"
|
# watch: "Watch"
|
||||||
# unwatch: "Unwatch"
|
# unwatch: "Unwatch"
|
||||||
# submit_patch: "Submit Patch"
|
# submit_patch: "Submit Patch"
|
||||||
|
@ -36,11 +36,11 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
|
|
||||||
nav:
|
nav:
|
||||||
play: "Jogar"
|
play: "Jogar"
|
||||||
# community: "Community"
|
community: "Comunidade"
|
||||||
editor: "Editor"
|
editor: "Editor"
|
||||||
blog: "Blog"
|
blog: "Blog"
|
||||||
forum: "Fórum"
|
forum: "Fórum"
|
||||||
# account: "Account"
|
account: "Conta"
|
||||||
admin: "Administrador"
|
admin: "Administrador"
|
||||||
home: "Início"
|
home: "Início"
|
||||||
contribute: "Contribuir"
|
contribute: "Contribuir"
|
||||||
|
@ -78,7 +78,7 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
creating: "Criando a nova conta..."
|
creating: "Criando a nova conta..."
|
||||||
sign_up: "Criar conta"
|
sign_up: "Criar conta"
|
||||||
log_in: "Entre com a senha"
|
log_in: "Entre com a senha"
|
||||||
# social_signup: "Or, you can sign up through Facebook or G+:"
|
social_signup: "Ou, você pode fazer login pelo Facebook ou G+:"
|
||||||
|
|
||||||
home:
|
home:
|
||||||
slogan: "Aprenda a programar em JavaScript enquanto se diverte com um jogo."
|
slogan: "Aprenda a programar em JavaScript enquanto se diverte com um jogo."
|
||||||
|
@ -133,15 +133,15 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
wizard_settings:
|
wizard_settings:
|
||||||
title: "Configurações do Feiticeiro"
|
title: "Configurações do Feiticeiro"
|
||||||
customize_avatar: "Personalize o seu Avatar"
|
customize_avatar: "Personalize o seu Avatar"
|
||||||
# active: "Active"
|
active: "Ativo"
|
||||||
# color: "Color"
|
color: "Cor"
|
||||||
# group: "Group"
|
group: "Grupo"
|
||||||
clothes: "Roupas"
|
clothes: "Roupas"
|
||||||
trim: "Aparar"
|
trim: "Aparar"
|
||||||
cloud: "Nuvem"
|
cloud: "Nuvem"
|
||||||
# team: "Team"
|
team: "Time"
|
||||||
spell: "Feitiço"
|
spell: "Feitiço"
|
||||||
boots: "Boots"
|
boots: "Botas"
|
||||||
hue: "Matiz"
|
hue: "Matiz"
|
||||||
saturation: "Saturação"
|
saturation: "Saturação"
|
||||||
lightness: "Luminosidade"
|
lightness: "Luminosidade"
|
||||||
|
@ -152,7 +152,7 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
autosave: "As alterações serão salvas automaticamente."
|
autosave: "As alterações serão salvas automaticamente."
|
||||||
me_tab: "Eu"
|
me_tab: "Eu"
|
||||||
picture_tab: "Foto"
|
picture_tab: "Foto"
|
||||||
# upload_picture: "Upload a picture"
|
upload_picture: "Enviar uma foto"
|
||||||
wizard_tab: "Feiticeiro"
|
wizard_tab: "Feiticeiro"
|
||||||
password_tab: "Senha"
|
password_tab: "Senha"
|
||||||
emails_tab: "Emails"
|
emails_tab: "Emails"
|
||||||
|
@ -167,8 +167,8 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
# email_notifications_summary: "Controls for personalized, automatic email notifications related to your CodeCombat activity."
|
# email_notifications_summary: "Controls for personalized, automatic email notifications related to your CodeCombat activity."
|
||||||
# email_any_notes: "Any Notifications"
|
# email_any_notes: "Any Notifications"
|
||||||
# email_any_notes_description: "Disable to stop all activity notification emails."
|
# email_any_notes_description: "Disable to stop all activity notification emails."
|
||||||
# email_recruit_notes: "Job Opportunities"
|
email_recruit_notes: "Oportunidades de emprego"
|
||||||
# email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job."
|
email_recruit_notes_description: "Se você jogar muito bem, nós podemos lhe contactar para lhe oferecer um emprego (melhor)"
|
||||||
contributor_emails: "Emails para as Classes de Contribuidores"
|
contributor_emails: "Emails para as Classes de Contribuidores"
|
||||||
contribute_prefix: "Estamos procurando pessoas para se juntar à nossa turma! Confira a nossa "
|
contribute_prefix: "Estamos procurando pessoas para se juntar à nossa turma! Confira a nossa "
|
||||||
contribute_page: "página de contribuição"
|
contribute_page: "página de contribuição"
|
||||||
|
@ -180,22 +180,22 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
# job_profile: "Job Profile"
|
# job_profile: "Job Profile"
|
||||||
# job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks."
|
# job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks."
|
||||||
# job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job."
|
# job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job."
|
||||||
# sample_profile: "See a sample profile"
|
sample_profile: "Veja um perfil de exemplo"
|
||||||
# view_profile: "View Your Profile"
|
view_profile: "Visualizar seu perfil"
|
||||||
|
|
||||||
account_profile:
|
account_profile:
|
||||||
edit_settings: "Editar as configurações"
|
edit_settings: "Editar as configurações"
|
||||||
profile_for_prefix: "Perfil de "
|
profile_for_prefix: "Perfil de "
|
||||||
profile_for_suffix: ""
|
profile_for_suffix: ""
|
||||||
# approved: "Approved"
|
approved: "Aprovado"
|
||||||
# not_approved: "Not Approved"
|
not_approved: "Não Aprovado"
|
||||||
# looking_for: "Looking for:"
|
# looking_for: "Looking for:"
|
||||||
# last_updated: "Last updated:"
|
last_updated: "Última atualização:"
|
||||||
# contact: "Contact"
|
contact: "Contato"
|
||||||
# work_experience: "Work Experience"
|
# work_experience: "Work Experience"
|
||||||
# education: "Education"
|
education: "Formação"
|
||||||
# our_notes: "Our Notes"
|
# our_notes: "Our Notes"
|
||||||
# projects: "Projects"
|
projects: "Projetos"
|
||||||
|
|
||||||
# employers:
|
# employers:
|
||||||
# want_to_hire_our_players: "Want to hire expert CodeCombat players?"
|
# want_to_hire_our_players: "Want to hire expert CodeCombat players?"
|
||||||
|
@ -203,8 +203,8 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
# candidates_count_prefix: "We currently have "
|
# candidates_count_prefix: "We currently have "
|
||||||
# candidates_count_many: "many"
|
# candidates_count_many: "many"
|
||||||
# candidates_count_suffix: "highly skilled and vetted developers looking for work."
|
# candidates_count_suffix: "highly skilled and vetted developers looking for work."
|
||||||
# candidate_name: "Name"
|
candidate_name: "Nome"
|
||||||
# candidate_location: "Location"
|
candidate_location: "Localização"
|
||||||
# candidate_looking_for: "Looking For"
|
# candidate_looking_for: "Looking For"
|
||||||
# candidate_role: "Role"
|
# candidate_role: "Role"
|
||||||
# candidate_top_skills: "Top Skills"
|
# candidate_top_skills: "Top Skills"
|
||||||
|
@ -421,7 +421,7 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
results: "Resultados"
|
results: "Resultados"
|
||||||
description: "Descrição"
|
description: "Descrição"
|
||||||
or: "ou"
|
or: "ou"
|
||||||
# subject: "Subject"
|
subject: "Assunto"
|
||||||
email: "Email"
|
email: "Email"
|
||||||
password: "Senha"
|
password: "Senha"
|
||||||
message: "Mensagem"
|
message: "Mensagem"
|
||||||
|
@ -437,7 +437,7 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
easy: "Fácil"
|
easy: "Fácil"
|
||||||
medium: "Médio"
|
medium: "Médio"
|
||||||
hard: "Difícil"
|
hard: "Difícil"
|
||||||
# player: "Player"
|
player: "Jogador"
|
||||||
|
|
||||||
about:
|
about:
|
||||||
who_is_codecombat: "Quem é CodeCombat?"
|
who_is_codecombat: "Quem é CodeCombat?"
|
||||||
|
@ -705,8 +705,8 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
# unknown: "Unknown error."
|
# unknown: "Unknown error."
|
||||||
|
|
||||||
# resources:
|
# resources:
|
||||||
# your_sessions: "Your Sessions"
|
your_sessions: "Suas sessões"
|
||||||
# level: "Level"
|
level: "Nível"
|
||||||
# social_network_apis: "Social Network APIs"
|
# social_network_apis: "Social Network APIs"
|
||||||
# facebook_status: "Facebook Status"
|
# facebook_status: "Facebook Status"
|
||||||
# facebook_friends: "Facebook Friends"
|
# facebook_friends: "Facebook Friends"
|
||||||
|
@ -719,27 +719,27 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
|
||||||
# patches: "Patches"
|
# patches: "Patches"
|
||||||
# patched_model: "Source Document"
|
# patched_model: "Source Document"
|
||||||
# model: "Model"
|
# model: "Model"
|
||||||
# system: "System"
|
system: "Sistema"
|
||||||
# component: "Component"
|
component: "Componente"
|
||||||
# components: "Components"
|
components: "Componentes"
|
||||||
# thang: "Thang"
|
# thang: "Thang"
|
||||||
# thangs: "Thangs"
|
# thangs: "Thangs"
|
||||||
# level_session: "Your Session"
|
level_session: "Sua sessão"
|
||||||
# opponent_session: "Opponent Session"
|
# opponent_session: "Opponent Session"
|
||||||
# article: "Article"
|
article: "Artigos"
|
||||||
# user_names: "User Names"
|
user_names: "Nomes de usuário"
|
||||||
# thang_names: "Thang Names"
|
# thang_names: "Thang Names"
|
||||||
# files: "Files"
|
files: "Arquivos"
|
||||||
# top_simulators: "Top Simulators"
|
# top_simulators: "Top Simulators"
|
||||||
# source_document: "Source Document"
|
# source_document: "Source Document"
|
||||||
# document: "Document"
|
document: "Documento"
|
||||||
# sprite_sheet: "Sprite Sheet"
|
sprite_sheet: "Planilha"
|
||||||
|
|
||||||
# delta:
|
# delta:
|
||||||
# added: "Added"
|
added: "Adicionado"
|
||||||
# modified: "Modified"
|
modified: "Modificado"
|
||||||
# deleted: "Deleted"
|
deleted: "Removido"
|
||||||
# moved_index: "Moved Index"
|
# moved_index: "Moved Index"
|
||||||
# text_diff: "Text Diff"
|
# text_diff: "Text Diff"
|
||||||
# merge_conflict_with: "MERGE CONFLICT WITH"
|
merge_conflict_with: "CONFLITO DE MERGE COM"
|
||||||
# no_changes: "No Changes"
|
no_changes: "Sem mudanças"
|
||||||
|
|
|
@ -37,7 +37,7 @@ class CocoModel extends Backbone.Model
|
||||||
@loading = false
|
@loading = false
|
||||||
@markToRevert()
|
@markToRevert()
|
||||||
@loadFromBackup()
|
@loadFromBackup()
|
||||||
|
|
||||||
getNormalizedURL: -> "#{@urlRoot}/#{@id}"
|
getNormalizedURL: -> "#{@urlRoot}/#{@id}"
|
||||||
|
|
||||||
set: ->
|
set: ->
|
||||||
|
@ -69,11 +69,17 @@ class CocoModel extends Backbone.Model
|
||||||
@set 'editPath', document.location.pathname
|
@set 'editPath', document.location.pathname
|
||||||
options ?= {}
|
options ?= {}
|
||||||
success = options.success
|
success = options.success
|
||||||
options.success = (resp) =>
|
error = options.error
|
||||||
|
options.success = (model, res) =>
|
||||||
@trigger "save:success", @
|
@trigger "save:success", @
|
||||||
success(@, resp) if success
|
success(@, res) if success
|
||||||
@markToRevert()
|
@markToRevert()
|
||||||
@clearBackup()
|
@clearBackup()
|
||||||
|
options.error = (model, res) =>
|
||||||
|
error(@, res) if error
|
||||||
|
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
|
||||||
@trigger "save", @
|
@trigger "save", @
|
||||||
return super attrs, options
|
return super attrs, options
|
||||||
|
|
||||||
|
@ -164,7 +170,7 @@ class CocoModel extends Backbone.Model
|
||||||
getDelta: ->
|
getDelta: ->
|
||||||
differ = deltasLib.makeJSONDiffer()
|
differ = deltasLib.makeJSONDiffer()
|
||||||
differ.diff @_revertAttributes, @attributes
|
differ.diff @_revertAttributes, @attributes
|
||||||
|
|
||||||
getDeltaWith: (otherModel) ->
|
getDeltaWith: (otherModel) ->
|
||||||
differ = deltasLib.makeJSONDiffer()
|
differ = deltasLib.makeJSONDiffer()
|
||||||
differ.diff @attributes, otherModel.attributes
|
differ.diff @attributes, otherModel.attributes
|
||||||
|
|
|
@ -17,6 +17,16 @@ module.exports = class SuperModel extends Backbone.Model
|
||||||
# necessarily have the same model or collection that was passed in, if it was fetched from
|
# necessarily have the same model or collection that was passed in, if it was fetched from
|
||||||
# the cache.
|
# the cache.
|
||||||
|
|
||||||
|
report: ->
|
||||||
|
# Useful for debugging why a SuperModel never finishes loading.
|
||||||
|
console.info "SuperModel report ------------------------"
|
||||||
|
console.info "#{_.values(@resources).length} resources."
|
||||||
|
unfinished = []
|
||||||
|
for resource in _.values(@resources) when resource
|
||||||
|
console.info '\t', resource.name, "loaded", resource.isLoaded
|
||||||
|
unfinished.push resource unless resource.isLoaded
|
||||||
|
unfinished
|
||||||
|
|
||||||
loadModel: (model, name, fetchOptions, value=1) ->
|
loadModel: (model, name, fetchOptions, value=1) ->
|
||||||
cachedModel = @getModelByURL(model.getURL())
|
cachedModel = @getModelByURL(model.getURL())
|
||||||
if cachedModel
|
if cachedModel
|
||||||
|
@ -118,6 +128,9 @@ module.exports = class SuperModel extends Backbone.Model
|
||||||
@storeResource(res, value)
|
@storeResource(res, value)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
removeModelResource: (modelOrCollection) ->
|
||||||
|
@removeResource _.find(@resources, (resource) -> resource?.model is modelOrCollection)
|
||||||
|
|
||||||
addRequestResource: (name, jqxhrOptions, value=1) ->
|
addRequestResource: (name, jqxhrOptions, value=1) ->
|
||||||
@checkName(name)
|
@checkName(name)
|
||||||
res = new RequestResource(name, jqxhrOptions, value)
|
res = new RequestResource(name, jqxhrOptions, value)
|
||||||
|
@ -143,11 +156,20 @@ module.exports = class SuperModel extends Backbone.Model
|
||||||
@denom += value
|
@denom += value
|
||||||
_.defer @updateProgress if @denom
|
_.defer @updateProgress if @denom
|
||||||
|
|
||||||
|
removeResource: (resource) ->
|
||||||
|
return unless @resources[resource.rid]
|
||||||
|
@resources[resource.rid] = null
|
||||||
|
--@num if resource.isLoaded
|
||||||
|
--@denom
|
||||||
|
_.defer @updateProgress
|
||||||
|
|
||||||
onResourceLoaded: (r) ->
|
onResourceLoaded: (r) ->
|
||||||
|
return unless @resources[r.rid]
|
||||||
@num += r.value
|
@num += r.value
|
||||||
_.defer @updateProgress
|
_.defer @updateProgress
|
||||||
|
|
||||||
onResourceFailed: (source) ->
|
onResourceFailed: (source) ->
|
||||||
|
return unless @resources[r.rid]
|
||||||
@trigger('failed', source)
|
@trigger('failed', source)
|
||||||
|
|
||||||
updateProgress: =>
|
updateProgress: =>
|
||||||
|
@ -160,13 +182,13 @@ module.exports = class SuperModel extends Backbone.Model
|
||||||
@progress = newProg
|
@progress = newProg
|
||||||
@trigger('update-progress', @progress)
|
@trigger('update-progress', @progress)
|
||||||
@trigger('loaded-all') if @finished()
|
@trigger('loaded-all') if @finished()
|
||||||
|
|
||||||
setMaxProgress: (@maxProgress) ->
|
setMaxProgress: (@maxProgress) ->
|
||||||
resetProgress: -> @progress = 0
|
resetProgress: -> @progress = 0
|
||||||
clearMaxProgress: ->
|
clearMaxProgress: ->
|
||||||
@maxProgress = 1
|
@maxProgress = 1
|
||||||
_.defer @updateProgress
|
_.defer @updateProgress
|
||||||
|
|
||||||
getProgress: -> return @progress
|
getProgress: -> return @progress
|
||||||
|
|
||||||
getResource: (rid) ->
|
getResource: (rid) ->
|
||||||
|
|
|
@ -62,7 +62,7 @@ module.exports = class ThangType extends CocoModel
|
||||||
@options = @fillOptions options
|
@options = @fillOptions options
|
||||||
key = @spriteSheetKey(@options)
|
key = @spriteSheetKey(@options)
|
||||||
if ss = @spriteSheets[key] then return ss
|
if ss = @spriteSheets[key] then return ss
|
||||||
return if @building[key]
|
return key if @building[key]
|
||||||
@t0 = new Date().getTime()
|
@t0 = new Date().getTime()
|
||||||
@initBuild(options)
|
@initBuild(options)
|
||||||
@addGeneralFrames() unless @options.portraitOnly
|
@addGeneralFrames() unless @options.portraitOnly
|
||||||
|
@ -151,25 +151,34 @@ module.exports = class ThangType extends CocoModel
|
||||||
buildQueue.push @builder
|
buildQueue.push @builder
|
||||||
@builder.t0 = new Date().getTime()
|
@builder.t0 = new Date().getTime()
|
||||||
@builder.buildAsync() unless buildQueue.length > 1
|
@builder.buildAsync() unless buildQueue.length > 1
|
||||||
@builder.on 'complete', @onBuildSpriteSheetComplete, @, true, key
|
@builder.on 'complete', @onBuildSpriteSheetComplete, @, true, [@builder, key, @options]
|
||||||
return true
|
@builder = null
|
||||||
|
return key
|
||||||
spriteSheet = @builder.build()
|
spriteSheet = @builder.build()
|
||||||
console.debug "Built #{@get('name')}#{if @options.portraitOnly then ' portrait' else ''} in #{new Date().getTime() - @t0}ms."
|
@logBuild @t0, false, @options.portraitOnly
|
||||||
@spriteSheets[key] = spriteSheet
|
@spriteSheets[key] = spriteSheet
|
||||||
delete @building[key]
|
delete @building[key]
|
||||||
|
@builder = null
|
||||||
spriteSheet
|
spriteSheet
|
||||||
|
|
||||||
onBuildSpriteSheetComplete: (e, key) ->
|
onBuildSpriteSheetComplete: (e, data) ->
|
||||||
console.log "Built #{@get('name')}#{if @options.portraitOnly then ' portrait' else ''} async in #{new Date().getTime() - @builder.t0}ms." if @builder
|
[builder, key, options] = data
|
||||||
|
@logBuild builder.t0, true, options.portraitOnly
|
||||||
buildQueue = buildQueue.slice(1)
|
buildQueue = buildQueue.slice(1)
|
||||||
buildQueue[0].t0 = new Date().getTime() if buildQueue[0]
|
buildQueue[0].t0 = new Date().getTime() if buildQueue[0]
|
||||||
buildQueue[0]?.buildAsync()
|
buildQueue[0]?.buildAsync()
|
||||||
@spriteSheets[key] = e.target.spriteSheet
|
@spriteSheets[key] = e.target.spriteSheet
|
||||||
delete @building[key]
|
delete @building[key]
|
||||||
@trigger 'build-complete'
|
@trigger 'build-complete', {key:key, thangType:@}
|
||||||
@builder = null
|
|
||||||
@vectorParser = null
|
@vectorParser = null
|
||||||
|
|
||||||
|
logBuild: (startTime, async, portrait) ->
|
||||||
|
kind = if async then 'Async' else 'Sync '
|
||||||
|
portrait = if portrait then '(Portrait)' else ''
|
||||||
|
name = _.string.rpad @get('name'), 20
|
||||||
|
time = _.string.lpad '' + new Date().getTime() - startTime, 6
|
||||||
|
console.debug "Built sheet: #{name} #{time}ms #{kind} #{portrait}"
|
||||||
|
|
||||||
spriteSheetKey: (options) ->
|
spriteSheetKey: (options) ->
|
||||||
colorConfigs = []
|
colorConfigs = []
|
||||||
for groupName, config of options.colorConfig or {}
|
for groupName, config of options.colorConfig or {}
|
||||||
|
@ -196,6 +205,7 @@ module.exports = class ThangType extends CocoModel
|
||||||
options = if _.isPlainObject spriteOptionsOrKey then spriteOptionsOrKey else {}
|
options = if _.isPlainObject spriteOptionsOrKey then spriteOptionsOrKey else {}
|
||||||
options.portraitOnly = true
|
options.portraitOnly = true
|
||||||
spriteSheet = @buildSpriteSheet(options)
|
spriteSheet = @buildSpriteSheet(options)
|
||||||
|
return if _.isString spriteSheet
|
||||||
return unless spriteSheet
|
return unless spriteSheet
|
||||||
canvas = $("<canvas width='#{size}' height='#{size}'></canvas>")
|
canvas = $("<canvas width='#{size}' height='#{size}'></canvas>")
|
||||||
stage = new createjs.Stage(canvas[0])
|
stage = new createjs.Stage(canvas[0])
|
||||||
|
|
|
@ -223,19 +223,19 @@ _.extend LevelSessionSchema.properties,
|
||||||
sessionID:
|
sessionID:
|
||||||
title: 'Opponent Session ID'
|
title: 'Opponent Session ID'
|
||||||
description: 'The session ID of an opponent.'
|
description: 'The session ID of an opponent.'
|
||||||
type: ['object', 'string']
|
type: ['object', 'string','null']
|
||||||
userID:
|
userID:
|
||||||
title: 'Opponent User ID'
|
title: 'Opponent User ID'
|
||||||
description: 'The user ID of an opponent'
|
description: 'The user ID of an opponent'
|
||||||
type: ['object','string']
|
type: ['object','string','null']
|
||||||
name:
|
name:
|
||||||
title: 'Opponent name'
|
title: 'Opponent name'
|
||||||
description: 'The name of the opponent'
|
description: 'The name of the opponent'
|
||||||
type: 'string'
|
type: ['string','null']
|
||||||
totalScore:
|
totalScore:
|
||||||
title: 'Opponent total score'
|
title: 'Opponent total score'
|
||||||
description: 'The totalScore of a user when the match was computed'
|
description: 'The totalScore of a user when the match was computed'
|
||||||
type: ['number','string']
|
type: ['number','string', 'null']
|
||||||
metrics:
|
metrics:
|
||||||
type: 'object'
|
type: 'object'
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -15,8 +15,21 @@ module.exports =
|
||||||
type: "object"
|
type: "object"
|
||||||
properties:
|
properties:
|
||||||
response:
|
response:
|
||||||
type: "string"
|
type: "object"
|
||||||
|
properties:
|
||||||
|
status: { type: "string" }
|
||||||
|
authResponse:
|
||||||
|
type: "object"
|
||||||
|
properties:
|
||||||
|
accessToken: { type: "string" }
|
||||||
|
expiresIn: { type: "number" }
|
||||||
|
signedRequest: { type: "string" }
|
||||||
|
userID: { type: "string" }
|
||||||
required: ["response"]
|
required: ["response"]
|
||||||
|
|
||||||
|
"facebook-logged-out": {}
|
||||||
|
|
||||||
|
"linkedin-loaded": {}
|
||||||
|
|
||||||
"gapi-loaded":
|
"gapi-loaded":
|
||||||
{} # TODO schema
|
{} # TODO schema
|
||||||
|
|
|
@ -53,8 +53,9 @@ module.exports =
|
||||||
"level:team-set":
|
"level:team-set":
|
||||||
{} # TODO schema
|
{} # TODO schema
|
||||||
|
|
||||||
"level:docs-hidden":
|
"level:docs-shown": {}
|
||||||
{} # TODO schema
|
|
||||||
|
"level:docs-hidden": {}
|
||||||
|
|
||||||
"level:victory-hidden":
|
"level:victory-hidden":
|
||||||
{} # TODO schema
|
{} # TODO schema
|
||||||
|
@ -74,9 +75,32 @@ module.exports =
|
||||||
"script:ended":
|
"script:ended":
|
||||||
{} # TODO schema
|
{} # TODO schema
|
||||||
|
|
||||||
|
"end-all-scripts": {}
|
||||||
|
|
||||||
"script:state-changed":
|
"script:state-changed":
|
||||||
{} # TODO schema
|
{} # TODO schema
|
||||||
|
|
||||||
|
'script-manager:tick':
|
||||||
|
type: 'object'
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
scriptRunning: { type: 'string' }
|
||||||
|
noteGroupRunning: { type: 'string' }
|
||||||
|
timeSinceLastScriptEnded: { type: 'number' }
|
||||||
|
scriptStates:
|
||||||
|
type: 'object'
|
||||||
|
additionalProperties:
|
||||||
|
title: 'Script State'
|
||||||
|
type: 'object'
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
timeSinceLastEnded:
|
||||||
|
type: 'number'
|
||||||
|
description: 'seconds since this script ended last'
|
||||||
|
timeSinceLastTriggered:
|
||||||
|
type: 'number'
|
||||||
|
description: 'seconds since this script was triggered last'
|
||||||
|
|
||||||
"play-sound":
|
"play-sound":
|
||||||
{} # TODO schema
|
{} # TODO schema
|
||||||
|
|
||||||
|
@ -114,5 +138,21 @@ module.exports =
|
||||||
"level-scrub-back":
|
"level-scrub-back":
|
||||||
{} # TODO schema
|
{} # TODO schema
|
||||||
|
|
||||||
|
"level-show-victory":
|
||||||
|
type: 'object'
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
showModal: { type: 'boolean' }
|
||||||
|
|
||||||
|
"level-highlight-dom":
|
||||||
|
type: 'object'
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
selector: { type: 'string' }
|
||||||
|
delay: { type: 'number' }
|
||||||
|
sides: { type: 'array', items: { 'enum': ['left', 'right', 'top', 'bottom'] }}
|
||||||
|
offset: { type: 'object' }
|
||||||
|
rotation: { type: 'number' }
|
||||||
|
|
||||||
"goal-manager:new-goal-states":
|
"goal-manager:new-goal-states":
|
||||||
{} # TODO schema
|
{} # TODO schema
|
||||||
|
|
|
@ -638,7 +638,7 @@ block content
|
||||||
.tab-pane.well#rules
|
.tab-pane.well#rules
|
||||||
h1(data-i18n="ladder.tournament_rules") Tournament Rules
|
h1(data-i18n="ladder.tournament_rules") Tournament Rules
|
||||||
h2 General
|
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.
|
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. Although we don't anticipate the rules changing, they are subject to change.
|
||||||
|
|
||||||
h2 Dates and Times
|
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.
|
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.
|
||||||
|
|
|
@ -39,11 +39,10 @@ module.exports = class ThangsTabView extends View
|
||||||
'level-thang-edited': 'onLevelThangEdited'
|
'level-thang-edited': 'onLevelThangEdited'
|
||||||
'level-thang-done-editing': 'onLevelThangDoneEditing'
|
'level-thang-done-editing': 'onLevelThangDoneEditing'
|
||||||
'level:view-switched': 'onViewSwitched'
|
'level:view-switched': 'onViewSwitched'
|
||||||
'sprite:mouse-down': 'onSpriteMouseDown'
|
|
||||||
'sprite:dragged': 'onSpriteDragged'
|
'sprite:dragged': 'onSpriteDragged'
|
||||||
'sprite:mouse-up': 'onSpriteMouseUp'
|
'sprite:mouse-up': 'onSpriteMouseUp'
|
||||||
'sprite:double-clicked': 'onSpriteDoubleClicked'
|
'sprite:double-clicked': 'onSpriteDoubleClicked'
|
||||||
'surface:stage-mouse-down': 'onStageMouseDown'
|
'surface:stage-mouse-up': 'onStageMouseUp'
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'click #extant-thangs-filter button': 'onFilterExtantThangs'
|
'click #extant-thangs-filter button': 'onFilterExtantThangs'
|
||||||
|
@ -108,7 +107,7 @@ module.exports = class ThangsTabView extends View
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
super()
|
super()
|
||||||
return unless @supermodel.finished()
|
return unless @supermodel.finished()
|
||||||
$('.tab-content').click @selectAddThang
|
$('.tab-content').mousedown @selectAddThang
|
||||||
$('#thangs-list').bind 'mousewheel', @preventBodyScrollingInThangList
|
$('#thangs-list').bind 'mousewheel', @preventBodyScrollingInThangList
|
||||||
@$el.find('#extant-thangs-filter button:first').button('toggle')
|
@$el.find('#extant-thangs-filter button:first').button('toggle')
|
||||||
$(window).resize @onWindowResize
|
$(window).resize @onWindowResize
|
||||||
|
@ -181,13 +180,13 @@ module.exports = class ThangsTabView extends View
|
||||||
|
|
||||||
onSpriteMouseDown: (e) ->
|
onSpriteMouseDown: (e) ->
|
||||||
# Sprite clicks happen after stage clicks, but we need to know whether a sprite is being clicked.
|
# Sprite clicks happen after stage clicks, but we need to know whether a sprite is being clicked.
|
||||||
clearTimeout @backgroundAddClickTimeout
|
# clearTimeout @backgroundAddClickTimeout
|
||||||
if e.originalEvent.nativeEvent.button == 2
|
# if e.originalEvent.nativeEvent.button == 2
|
||||||
@onSpriteContextMenu e
|
# @onSpriteContextMenu e
|
||||||
|
|
||||||
onStageMouseDown: (e) ->
|
onStageMouseUp: (e) ->
|
||||||
if @addThangSprite
|
if @addThangSprite
|
||||||
# If we click on the background, we need to add @addThangSprite, but not if onSpriteMouseDown will fire.
|
# If we click on the background, we need to add @addThangSprite, but not if onSpriteMouseUp will fire.
|
||||||
@backgroundAddClickTimeout = _.defer => @onExtantThangSelected {}
|
@backgroundAddClickTimeout = _.defer => @onExtantThangSelected {}
|
||||||
$('#contextmenu').hide()
|
$('#contextmenu').hide()
|
||||||
|
|
||||||
|
@ -202,6 +201,9 @@ module.exports = class ThangsTabView extends View
|
||||||
@calculateMovement(stageX / w, stageY / h, w / h)
|
@calculateMovement(stageX / w, stageY / h, w / h)
|
||||||
|
|
||||||
onSpriteMouseUp: (e) ->
|
onSpriteMouseUp: (e) ->
|
||||||
|
clearTimeout @backgroundAddClickTimeout
|
||||||
|
if e.originalEvent.nativeEvent.button == 2
|
||||||
|
@onSpriteContextMenu e
|
||||||
clearInterval(@movementInterval) if @movementInterval?
|
clearInterval(@movementInterval) if @movementInterval?
|
||||||
@movementInterval = null
|
@movementInterval = null
|
||||||
@surface.camera.dragDisabled = false
|
@surface.camera.dragDisabled = false
|
||||||
|
|
|
@ -72,6 +72,9 @@ module.exports = class LadderSubmissionView extends CocoView
|
||||||
|
|
||||||
transpileSession: ->
|
transpileSession: ->
|
||||||
submittedCode = @session.get('code')
|
submittedCode = @session.get('code')
|
||||||
|
language = @session.get('codeLanguage') or 'javascript'
|
||||||
|
@session.set('submittedCodeLanguage', language)
|
||||||
|
@session.save() # TODO: maybe actually use a callback to make sure this works?
|
||||||
transpiledCode = {}
|
transpiledCode = {}
|
||||||
for thang, spells of submittedCode
|
for thang, spells of submittedCode
|
||||||
transpiledCode[thang] = {}
|
transpiledCode[thang] = {}
|
||||||
|
@ -80,7 +83,7 @@ module.exports = class LadderSubmissionView extends CocoView
|
||||||
#DRY this
|
#DRY this
|
||||||
aetherOptions =
|
aetherOptions =
|
||||||
problems: {}
|
problems: {}
|
||||||
language: "javascript"
|
language: language
|
||||||
functionName: spellID
|
functionName: spellID
|
||||||
functionParameters: []
|
functionParameters: []
|
||||||
yieldConditionally: spellID is "plan"
|
yieldConditionally: spellID is "plan"
|
||||||
|
|
|
@ -150,9 +150,12 @@ module.exports = class LadderTabView extends CocoView
|
||||||
# LADDER LOADING
|
# LADDER LOADING
|
||||||
|
|
||||||
refreshLadder: ->
|
refreshLadder: ->
|
||||||
|
@supermodel.resetProgress()
|
||||||
@ladderLimit ?= parseInt @getQueryVariable('top_players', 20)
|
@ladderLimit ?= parseInt @getQueryVariable('top_players', 20)
|
||||||
for team in @teams
|
for team in @teams
|
||||||
@leaderboards[team.id]?.destroy()
|
if oldLeaderboard = @leaderboards[team.id]
|
||||||
|
@supermodel.removeModelResource oldLeaderboard
|
||||||
|
oldLeaderboard.destroy()
|
||||||
teamSession = _.find @sessions.models, (session) -> session.get('team') is team.id
|
teamSession = _.find @sessions.models, (session) -> session.get('team') is team.id
|
||||||
@leaderboards[team.id] = new LeaderboardData(@level, team.id, teamSession, @ladderLimit)
|
@leaderboards[team.id] = new LeaderboardData(@level, team.id, teamSession, @ladderLimit)
|
||||||
@leaderboardRes = @supermodel.addModelResource(@leaderboards[team.id], 'leaderboard', 3)
|
@leaderboardRes = @supermodel.addModelResource(@leaderboards[team.id], 'leaderboard', 3)
|
||||||
|
@ -242,7 +245,7 @@ module.exports = class LadderTabView extends CocoView
|
||||||
if teamName.toLowerCase() is "humans" then rankClass = "rank-text humans-rank-text"
|
if teamName.toLowerCase() is "humans" then rankClass = "rank-text humans-rank-text"
|
||||||
|
|
||||||
message = "#{histogramData.length} players"
|
message = "#{histogramData.length} players"
|
||||||
if @leaderboards[teamName].session?
|
if @leaderboards[teamName].session?
|
||||||
if @leaderboards[teamName].myRank <= histogramData.length
|
if @leaderboards[teamName].myRank <= histogramData.length
|
||||||
message="##{@leaderboards[teamName].myRank} of #{histogramData.length}"
|
message="##{@leaderboards[teamName].myRank} of #{histogramData.length}"
|
||||||
else
|
else
|
||||||
|
|
|
@ -65,7 +65,7 @@ module.exports = class LadderView extends RootView
|
||||||
@insertSubView(@simulateTab = new SimulateTabView())
|
@insertSubView(@simulateTab = new SimulateTabView())
|
||||||
@refreshInterval = setInterval(@fetchSessionsAndRefreshViews.bind(@), 20 * 1000)
|
@refreshInterval = setInterval(@fetchSessionsAndRefreshViews.bind(@), 20 * 1000)
|
||||||
hash = document.location.hash[1..] if document.location.hash
|
hash = document.location.hash[1..] if document.location.hash
|
||||||
if hash and not (hash in ['my-matches', 'simulate', 'ladder'])
|
if hash and not (hash in ['my-matches', 'simulate', 'ladder', 'prizes', 'rules'])
|
||||||
@showPlayModal(hash) if @sessions.loaded
|
@showPlayModal(hash) if @sessions.loaded
|
||||||
|
|
||||||
fetchSessionsAndRefreshViews: ->
|
fetchSessionsAndRefreshViews: ->
|
||||||
|
|
|
@ -26,6 +26,9 @@ module.exports = class MyMatchesTabView extends CocoView
|
||||||
for session in @sessions.models
|
for session in @sessions.models
|
||||||
for match in (session.get('matches') or [])
|
for match in (session.get('matches') or [])
|
||||||
id = match.opponents[0].userID
|
id = match.opponents[0].userID
|
||||||
|
unless id
|
||||||
|
console.error "Found bad opponent ID in malformed match:", match, "from session", session
|
||||||
|
continue
|
||||||
ids.push id unless @nameMap[id]
|
ids.push id unless @nameMap[id]
|
||||||
|
|
||||||
return @finishRendering() unless ids.length
|
return @finishRendering() unless ids.length
|
||||||
|
@ -35,7 +38,7 @@ module.exports = class MyMatchesTabView extends CocoView
|
||||||
for session in @sessions.models
|
for session in @sessions.models
|
||||||
for match in session.get('matches') or []
|
for match in session.get('matches') or []
|
||||||
opponent = match.opponents[0]
|
opponent = match.opponents[0]
|
||||||
@nameMap[opponent.userID] ?= nameMap[opponent.userID].name
|
@nameMap[opponent.userID] ?= nameMap[opponent.userID]?.name ? "<bad match data>"
|
||||||
@finishRendering()
|
@finishRendering()
|
||||||
|
|
||||||
$.ajax('/db/user/-/names', {
|
$.ajax('/db/user/-/names', {
|
||||||
|
@ -94,6 +97,7 @@ module.exports = class MyMatchesTabView extends CocoView
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
super()
|
super()
|
||||||
|
@removeSubView subview for key, subview of @subviews when subview instanceof LadderSubmissionView
|
||||||
@$el.find('.ladder-submission-view').each (i, el) =>
|
@$el.find('.ladder-submission-view').each (i, el) =>
|
||||||
placeholder = $(el)
|
placeholder = $(el)
|
||||||
sessionID = placeholder.data('session-id')
|
sessionID = placeholder.data('session-id')
|
||||||
|
|
|
@ -13,6 +13,7 @@ module.exports = class DocsModal extends View
|
||||||
'enter': 'hide'
|
'enter': 'hide'
|
||||||
|
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
|
@firstOnly = options.firstOnly
|
||||||
@docs = options?.docs
|
@docs = options?.docs
|
||||||
general = @docs.generalArticles or []
|
general = @docs.generalArticles or []
|
||||||
specific = @docs.specificArticles or []
|
specific = @docs.specificArticles or []
|
||||||
|
@ -25,6 +26,7 @@ module.exports = class DocsModal extends View
|
||||||
|
|
||||||
@docs = specific.concat(general)
|
@docs = specific.concat(general)
|
||||||
@docs = $.extend(true, [], @docs)
|
@docs = $.extend(true, [], @docs)
|
||||||
|
@docs = [@docs[0]] if @firstOnly and @docs[0]
|
||||||
doc.html = marked(utils.i18n doc, 'body') for doc in @docs
|
doc.html = marked(utils.i18n doc, 'body') for doc in @docs
|
||||||
doc.name = (utils.i18n doc, 'name') for doc in @docs
|
doc.name = (utils.i18n doc, 'name') for doc in @docs
|
||||||
doc.slug = _.string.slugify(doc.name) for doc in @docs
|
doc.slug = _.string.slugify(doc.name) for doc in @docs
|
||||||
|
@ -47,6 +49,10 @@ module.exports = class DocsModal extends View
|
||||||
|
|
||||||
clickTab: (e) =>
|
clickTab: (e) =>
|
||||||
@$el.find('li.active').removeClass('active')
|
@$el.find('li.active').removeClass('active')
|
||||||
|
|
||||||
|
afterInsert: ->
|
||||||
|
super()
|
||||||
|
Backbone.Mediator.publish 'level:docs-shown'
|
||||||
|
|
||||||
onHidden: ->
|
onHidden: ->
|
||||||
Backbone.Mediator.publish 'level:docs-hidden'
|
Backbone.Mediator.publish 'level:docs-hidden'
|
||||||
|
|
|
@ -21,8 +21,11 @@ module.exports = class ThangAvatarView extends View
|
||||||
|
|
||||||
unless @thangType.isFullyLoaded() or @thangType.loading
|
unless @thangType.isFullyLoaded() or @thangType.loading
|
||||||
@thangType.fetch()
|
@thangType.fetch()
|
||||||
|
|
||||||
@supermodel.loadModel @thangType, 'thang'
|
# couldn't get the level view to load properly through the supermodel
|
||||||
|
# so just doing it manually this time.
|
||||||
|
@listenTo @thangType, 'sync', @render
|
||||||
|
@listenTo @thangType, 'build-complete', @render
|
||||||
|
|
||||||
getSpriteThangType: ->
|
getSpriteThangType: ->
|
||||||
thangs = @supermodel.getModels(ThangType)
|
thangs = @supermodel.getModels(ThangType)
|
||||||
|
@ -34,7 +37,7 @@ module.exports = class ThangAvatarView extends View
|
||||||
context = super context
|
context = super context
|
||||||
context.thang = @thang
|
context.thang = @thang
|
||||||
options = @thang?.getSpriteOptions() or {}
|
options = @thang?.getSpriteOptions() or {}
|
||||||
options.async = false
|
options.async = true
|
||||||
context.avatarURL = @thangType.getPortraitSource(options) unless @thangType.loading
|
context.avatarURL = @thangType.getPortraitSource(options) unless @thangType.loading
|
||||||
context.includeName = @includeName
|
context.includeName = @includeName
|
||||||
context
|
context
|
||||||
|
|
|
@ -153,6 +153,11 @@ module.exports = class SpellView extends View
|
||||||
name: 'spell-beautify'
|
name: 'spell-beautify'
|
||||||
bindKey: {win: 'Ctrl-Shift-B', mac: 'Command-Shift-B|Ctrl-Shift-B'}
|
bindKey: {win: 'Ctrl-Shift-B', mac: 'Command-Shift-B|Ctrl-Shift-B'}
|
||||||
exec: -> Backbone.Mediator.publish 'spell-beautify'
|
exec: -> Backbone.Mediator.publish 'spell-beautify'
|
||||||
|
addCommand
|
||||||
|
name: 'prevent-line-jump'
|
||||||
|
bindKey: {win: 'Ctrl-L', mac: 'Command-L'}
|
||||||
|
passEvent: true
|
||||||
|
exec: -> # just prevent default ACE go-to-line alert
|
||||||
|
|
||||||
fillACE: ->
|
fillACE: ->
|
||||||
@ace.setValue @spell.source
|
@ace.setValue @spell.source
|
||||||
|
|
|
@ -133,7 +133,10 @@ module.exports = class PlayLevelView extends View
|
||||||
showGuide: ->
|
showGuide: ->
|
||||||
@seenDocs = true
|
@seenDocs = true
|
||||||
DocsModal = require './level/modal/docs_modal'
|
DocsModal = require './level/modal/docs_modal'
|
||||||
options = {docs: @levelLoader.level.get('documentation'), supermodel: @supermodel}
|
options =
|
||||||
|
docs: @levelLoader.level.get('documentation')
|
||||||
|
supermodel: @supermodel
|
||||||
|
firstOnly: true
|
||||||
@openModalView(new DocsModal(options), true)
|
@openModalView(new DocsModal(options), true)
|
||||||
Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelStarted, @
|
Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelStarted, @
|
||||||
return true
|
return true
|
||||||
|
@ -287,6 +290,7 @@ module.exports = class PlayLevelView extends View
|
||||||
unless @isEditorPreview
|
unless @isEditorPreview
|
||||||
@loadEndTime = new Date()
|
@loadEndTime = new Date()
|
||||||
loadDuration = @loadEndTime - @loadStartTime
|
loadDuration = @loadEndTime - @loadStartTime
|
||||||
|
console.debug "Level unveiled after #{(loadDuration / 1000).toFixed(2)}s"
|
||||||
application.tracker?.trackEvent 'Finished Level Load', level: @levelID, label: @levelID, loadDuration: loadDuration
|
application.tracker?.trackEvent 'Finished Level Load', level: @levelID, label: @levelID, loadDuration: loadDuration
|
||||||
application.tracker?.trackTiming loadDuration, 'Level Load Time', @levelID, @levelID
|
application.tracker?.trackTiming loadDuration, 'Level Load Time', @levelID, @levelID
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ addPairwiseTaskToQueue = (taskPair, cb) ->
|
||||||
if taskPairError? then return cb taskPairError
|
if taskPairError? then return cb taskPairError
|
||||||
cb null
|
cb null
|
||||||
|
|
||||||
|
# We should rip these out, probably
|
||||||
module.exports.resimulateAllSessions = (req, res) ->
|
module.exports.resimulateAllSessions = (req, res) ->
|
||||||
unless isUserAdmin req then return errors.unauthorized res, "Unauthorized. Even if you are authorized, you shouldn't do this"
|
unless isUserAdmin req then return errors.unauthorized res, "Unauthorized. Even if you are authorized, you shouldn't do this"
|
||||||
|
|
||||||
|
@ -99,6 +100,30 @@ resimulateSession = (originalLevelID, levelMajorVersion, session, cb) =>
|
||||||
if taskPairError? then return cb taskPairError, null
|
if taskPairError? then return cb taskPairError, null
|
||||||
cb null
|
cb null
|
||||||
|
|
||||||
|
selectRandomSkipIndex = (numberOfSessions) ->
|
||||||
|
numbers = [0...numberOfSessions]
|
||||||
|
numberWeights = []
|
||||||
|
lambda = 0.025
|
||||||
|
|
||||||
|
for number, index in numbers
|
||||||
|
numberWeights[index] = lambda*Math.exp(-1*lambda*number) + lambda/(numberOfSessions/15)
|
||||||
|
sum = numberWeights.reduce (a, b) -> a + b
|
||||||
|
|
||||||
|
for number,index in numberWeights
|
||||||
|
numberWeights[index] /= sum
|
||||||
|
|
||||||
|
rand = (min, max) -> Math.random() * (max - min) + min
|
||||||
|
|
||||||
|
totalWeight = 1
|
||||||
|
randomNumber = Math.random()
|
||||||
|
weightSum = 0
|
||||||
|
|
||||||
|
for number, i in numbers
|
||||||
|
weightSum += numberWeights[i]
|
||||||
|
|
||||||
|
if (randomNumber <= weightSum)
|
||||||
|
return numbers[i]
|
||||||
|
|
||||||
module.exports.getTwoGames = (req, res) ->
|
module.exports.getTwoGames = (req, res) ->
|
||||||
#if userIsAnonymous req then return errors.unauthorized(res, "You need to be logged in to get games.")
|
#if userIsAnonymous req then return errors.unauthorized(res, "You need to be logged in to get games.")
|
||||||
humansGameID = req.body.humansGameID
|
humansGameID = req.body.humansGameID
|
||||||
|
@ -106,53 +131,64 @@ module.exports.getTwoGames = (req, res) ->
|
||||||
|
|
||||||
unless ogresGameID and humansGameID
|
unless ogresGameID and humansGameID
|
||||||
#fetch random games here
|
#fetch random games here
|
||||||
queryParams =
|
queryParams =
|
||||||
"levelID":"greed"
|
"levelID":"greed"
|
||||||
"submitted":true
|
"submitted":true
|
||||||
"team":"humans"
|
"team":"humans"
|
||||||
selection = "team totalScore transpiledCode teamSpells levelID creatorName creator"
|
selection = "team totalScore transpiledCode teamSpells levelID creatorName creator submitDate"
|
||||||
LevelSession.count queryParams, (err, numberOfHumans) =>
|
LevelSession.count queryParams, (err, numberOfHumans) =>
|
||||||
query = LevelSession
|
if err? then return errors.serverError(res, "Couldn't get the number of human games")
|
||||||
.find(queryParams)
|
humanSkipCount = selectRandomSkipIndex(numberOfHumans)
|
||||||
.limit(1)
|
ogreCountParams =
|
||||||
.select(selection)
|
"levelID": "greed"
|
||||||
.skip(Math.floor(Math.random()*numberOfHumans))
|
"submitted":true
|
||||||
.lean()
|
"team":"ogres"
|
||||||
query.exec (err, randomSession) =>
|
LevelSession.count ogreCountParams, (err, numberOfOgres) =>
|
||||||
if err? then return errors.serverError(res, "Couldn't select a top 15 random session!")
|
if err? then return errors.serverError(res, "Couldnt' get the number of ogre games")
|
||||||
randomSession = randomSession[0]
|
ogresSkipCount = selectRandomSkipIndex(numberOfOgres)
|
||||||
queryParams =
|
|
||||||
"levelID":"greed"
|
|
||||||
"submitted":true
|
|
||||||
"totalScore":
|
|
||||||
$lte: randomSession.totalScore
|
|
||||||
"team": "ogres"
|
|
||||||
query = LevelSession
|
query = LevelSession
|
||||||
.find(queryParams)
|
.aggregate()
|
||||||
.select(selection)
|
.match(queryParams)
|
||||||
.sort(totalScore: -1)
|
.project(selection)
|
||||||
|
.sort({"submitDate": -1})
|
||||||
|
.skip(humanSkipCount)
|
||||||
.limit(1)
|
.limit(1)
|
||||||
.lean()
|
query.exec (err, randomSession) =>
|
||||||
query.exec (err, otherSession) =>
|
if err? then return errors.serverError(res, "Couldn't select a random session! #{err}")
|
||||||
if err? then return errors.serverError(res, "Couldnt' select the other top 15 random session!")
|
randomSession = randomSession[0]
|
||||||
otherSession = otherSession[0]
|
queryParams =
|
||||||
taskObject =
|
"levelID":"greed"
|
||||||
"messageGenerated": Date.now()
|
"submitted":true
|
||||||
"sessions": []
|
"team": "ogres"
|
||||||
for session in [randomSession, otherSession]
|
query = LevelSession
|
||||||
sessionInformation =
|
.aggregate()
|
||||||
"sessionID": session._id
|
.match(queryParams)
|
||||||
"team": session.team ? "No team"
|
.project(selection)
|
||||||
"transpiledCode": session.transpiledCode
|
.sort({"submitDate": -1})
|
||||||
"teamSpells": session.teamSpells ? {}
|
.skip(ogresSkipCount)
|
||||||
"levelID": session.levelID
|
.limit(1)
|
||||||
"creatorName": session.creatorName
|
query.exec (err, otherSession) =>
|
||||||
"creator": session.creator
|
if err? then return errors.serverError(res, "Couldnt' select the other random session!")
|
||||||
"totalScore": session.totalScore
|
otherSession = otherSession[0]
|
||||||
|
taskObject =
|
||||||
taskObject.sessions.push sessionInformation
|
"messageGenerated": Date.now()
|
||||||
sendResponseObject req, res, taskObject
|
"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
|
||||||
|
console.log "Dispatching random game between", taskObject.sessions[0].creatorName, "and", taskObject.sessions[1].creatorName
|
||||||
|
sendResponseObject req, res, taskObject
|
||||||
else
|
else
|
||||||
|
console.log "Directly simulating #{humansGameID} vs. #{ogresGameID}."
|
||||||
LevelSession.findOne(_id: humansGameID).lean().exec (err, humanSession) =>
|
LevelSession.findOne(_id: humansGameID).lean().exec (err, humanSession) =>
|
||||||
if err? then return errors.serverError(res, "Couldn't find the human game")
|
if err? then return errors.serverError(res, "Couldn't find the human game")
|
||||||
LevelSession.findOne(_id: ogresGameID).lean().exec (err, ogreSession) =>
|
LevelSession.findOne(_id: ogresGameID).lean().exec (err, ogreSession) =>
|
||||||
|
@ -167,23 +203,25 @@ module.exports.getTwoGames = (req, res) ->
|
||||||
"transpiledCode": session.transpiledCode
|
"transpiledCode": session.transpiledCode
|
||||||
"teamSpells": session.teamSpells ? {}
|
"teamSpells": session.teamSpells ? {}
|
||||||
"levelID": session.levelID
|
"levelID": session.levelID
|
||||||
|
|
||||||
taskObject.sessions.push sessionInformation
|
taskObject.sessions.push sessionInformation
|
||||||
sendResponseObject req, res, taskObject
|
sendResponseObject req, res, taskObject
|
||||||
|
|
||||||
module.exports.recordTwoGames = (req, res) ->
|
module.exports.recordTwoGames = (req, res) ->
|
||||||
@clientResponseObject = req.body
|
sessions = req.body.sessions
|
||||||
|
console.log "Recording non-chained result of", sessions?[0]?.name, sessions[0]?.metrics?.rank, "and", sessions?[1]?.name, sessions?[1]?.metrics?.rank
|
||||||
|
|
||||||
|
yetiGuru = clientResponseObject: req.body, isRandomMatch: true
|
||||||
async.waterfall [
|
async.waterfall [
|
||||||
fetchLevelSession.bind(@)
|
fetchLevelSession.bind(yetiGuru)
|
||||||
updateSessions.bind(@)
|
updateSessions.bind(yetiGuru)
|
||||||
indexNewScoreArray.bind(@)
|
indexNewScoreArray.bind(yetiGuru)
|
||||||
addMatchToSessions.bind(@)
|
addMatchToSessions.bind(yetiGuru)
|
||||||
updateUserSimulationCounts.bind(@, req.user._id)
|
updateUserSimulationCounts.bind(yetiGuru, req.user._id)
|
||||||
], (err, successMessageObject) ->
|
], (err, successMessageObject) ->
|
||||||
if err? then return errors.serverError res, "There was an error recording the single game:#{err}"
|
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!"}
|
sendResponseObject req, res, {"message":"The single game was submitted successfully!"}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports.createNewTask = (req, res) ->
|
module.exports.createNewTask = (req, res) ->
|
||||||
|
@ -193,12 +231,13 @@ module.exports.createNewTask = (req, res) ->
|
||||||
transpiledCode = req.body.transpiledCode
|
transpiledCode = req.body.transpiledCode
|
||||||
requestLevelMajorVersion = parseInt(req.body.levelMajorVersion)
|
requestLevelMajorVersion = parseInt(req.body.levelMajorVersion)
|
||||||
|
|
||||||
|
yetiGuru = {}
|
||||||
async.waterfall [
|
async.waterfall [
|
||||||
validatePermissions.bind(@,req,requestSessionID)
|
validatePermissions.bind(yetiGuru,req,requestSessionID)
|
||||||
fetchAndVerifyLevelType.bind(@,currentLevelID)
|
fetchAndVerifyLevelType.bind(yetiGuru,currentLevelID)
|
||||||
fetchSessionObjectToSubmit.bind(@, requestSessionID)
|
fetchSessionObjectToSubmit.bind(yetiGuru, requestSessionID)
|
||||||
updateSessionToSubmit.bind(@, transpiledCode)
|
updateSessionToSubmit.bind(yetiGuru, transpiledCode)
|
||||||
fetchInitialSessionsToRankAgainst.bind(@, requestLevelMajorVersion, originalLevelID)
|
fetchInitialSessionsToRankAgainst.bind(yetiGuru, requestLevelMajorVersion, originalLevelID)
|
||||||
generateAndSendTaskPairsToTheQueue
|
generateAndSendTaskPairsToTheQueue
|
||||||
], (err, successMessageObject) ->
|
], (err, successMessageObject) ->
|
||||||
if err? then return errors.serverError res, "There was an error submitting the game to the queue:#{err}"
|
if err? then return errors.serverError res, "There was an error submitting the game to the queue:#{err}"
|
||||||
|
@ -256,9 +295,9 @@ updateSessionToSubmit = (transpiledCode, sessionToUpdate, callback) ->
|
||||||
submittedCode: sessionToUpdate.code
|
submittedCode: sessionToUpdate.code
|
||||||
transpiledCode: transpiledCode
|
transpiledCode: transpiledCode
|
||||||
submitDate: new Date()
|
submitDate: new Date()
|
||||||
meanStrength: 25
|
#meanStrength: 25 # Let's try not resetting the score on resubmission
|
||||||
standardDeviation: 25/3
|
standardDeviation: 25/3
|
||||||
totalScore: 10
|
#totalScore: 10 # Let's try not resetting the score on resubmission
|
||||||
numberOfWinsAndTies: 0
|
numberOfWinsAndTies: 0
|
||||||
numberOfLosses: 0
|
numberOfLosses: 0
|
||||||
isRanking: true
|
isRanking: true
|
||||||
|
@ -300,13 +339,14 @@ generateAndSendTaskPairsToTheQueue = (sessionToRankAgainst,submittedSession, cal
|
||||||
|
|
||||||
|
|
||||||
module.exports.dispatchTaskToConsumer = (req, res) ->
|
module.exports.dispatchTaskToConsumer = (req, res) ->
|
||||||
|
yetiGuru = {}
|
||||||
async.waterfall [
|
async.waterfall [
|
||||||
checkSimulationPermissions.bind(@,req)
|
checkSimulationPermissions.bind(yetiGuru,req)
|
||||||
receiveMessageFromSimulationQueue
|
receiveMessageFromSimulationQueue
|
||||||
changeMessageVisibilityTimeout
|
changeMessageVisibilityTimeout
|
||||||
parseTaskQueueMessage
|
parseTaskQueueMessage
|
||||||
constructTaskObject
|
constructTaskObject
|
||||||
constructTaskLogObject.bind(@, getUserIDFromRequest(req))
|
constructTaskLogObject.bind(yetiGuru, getUserIDFromRequest(req))
|
||||||
processTaskObject
|
processTaskObject
|
||||||
], (err, taskObjectToSend) ->
|
], (err, taskObjectToSend) ->
|
||||||
if err?
|
if err?
|
||||||
|
@ -357,7 +397,6 @@ constructTaskObject = (taskMessageBody, message, callback) ->
|
||||||
"sessionID": session._id
|
"sessionID": session._id
|
||||||
"submitDate": session.submitDate
|
"submitDate": session.submitDate
|
||||||
"team": session.team ? "No team"
|
"team": session.team ? "No team"
|
||||||
"code": session.submittedCode
|
|
||||||
"transpiledCode": session.transpiledCode
|
"transpiledCode": session.transpiledCode
|
||||||
"teamSpells": session.teamSpells ? {}
|
"teamSpells": session.teamSpells ? {}
|
||||||
"levelID": session.levelID
|
"levelID": session.levelID
|
||||||
|
@ -397,34 +436,38 @@ getSessionInformation = (sessionIDString, callback) ->
|
||||||
|
|
||||||
module.exports.processTaskResult = (req, res) ->
|
module.exports.processTaskResult = (req, res) ->
|
||||||
originalSessionID = req.body?.originalSessionID
|
originalSessionID = req.body?.originalSessionID
|
||||||
async.waterfall [
|
yetiGuru = {}
|
||||||
verifyClientResponse.bind(@,req.body)
|
try
|
||||||
fetchTaskLog.bind(@)
|
async.waterfall [
|
||||||
checkTaskLog.bind(@)
|
verifyClientResponse.bind(yetiGuru,req.body)
|
||||||
deleteQueueMessage.bind(@)
|
fetchTaskLog.bind(yetiGuru)
|
||||||
fetchLevelSession.bind(@)
|
checkTaskLog.bind(yetiGuru)
|
||||||
checkSubmissionDate.bind(@)
|
deleteQueueMessage.bind(yetiGuru)
|
||||||
logTaskComputation.bind(@)
|
fetchLevelSession.bind(yetiGuru)
|
||||||
updateSessions.bind(@)
|
checkSubmissionDate.bind(yetiGuru)
|
||||||
indexNewScoreArray.bind(@)
|
logTaskComputation.bind(yetiGuru)
|
||||||
addMatchToSessions.bind(@)
|
updateSessions.bind(yetiGuru)
|
||||||
updateUserSimulationCounts.bind(@, req.user._id)
|
indexNewScoreArray.bind(yetiGuru)
|
||||||
determineIfSessionShouldContinueAndUpdateLog.bind(@)
|
addMatchToSessions.bind(yetiGuru)
|
||||||
findNearestBetterSessionID.bind(@)
|
updateUserSimulationCounts.bind(yetiGuru, req.user._id)
|
||||||
addNewSessionsToQueue.bind(@)
|
determineIfSessionShouldContinueAndUpdateLog.bind(yetiGuru)
|
||||||
], (err, results) ->
|
findNearestBetterSessionID.bind(yetiGuru)
|
||||||
if err is "shouldn't continue"
|
addNewSessionsToQueue.bind(yetiGuru)
|
||||||
markSessionAsDoneRanking originalSessionID, (err) ->
|
], (err, results) ->
|
||||||
if err? then return sendResponseObject req, res, {"error":"There was an error marking the session as done ranking"}
|
if err is "shouldn't continue"
|
||||||
sendResponseObject req, res, {"message":"The scores were updated successfully, person lost so no more games are being inserted!"}
|
markSessionAsDoneRanking originalSessionID, (err) ->
|
||||||
else if err is "no session was found"
|
if err? then return sendResponseObject req, res, {"error":"There was an error marking the session as done ranking"}
|
||||||
markSessionAsDoneRanking originalSessionID, (err) ->
|
sendResponseObject req, res, {"message":"The scores were updated successfully, person lost so no more games are being inserted!"}
|
||||||
if err? then return sendResponseObject req, res, {"error":"There was an error marking the session as done ranking"}
|
else if err is "no session was found"
|
||||||
sendResponseObject req, res, {"message":"There were no more games to rank (game is at top)!"}
|
markSessionAsDoneRanking originalSessionID, (err) ->
|
||||||
else if err?
|
if err? then return sendResponseObject req, res, {"error":"There was an error marking the session as done ranking"}
|
||||||
errors.serverError res, "There was an error:#{err}"
|
sendResponseObject req, res, {"message":"There were no more games to rank (game is at top)!"}
|
||||||
else
|
else if err?
|
||||||
sendResponseObject req, res, {"message":"The scores were updated successfully and more games were sent to the queue!"}
|
errors.serverError res, "There was an error:#{err}"
|
||||||
|
else
|
||||||
|
sendResponseObject req, res, {"message":"The scores were updated successfully and more games were sent to the queue!"}
|
||||||
|
catch e
|
||||||
|
errors.serverError res, "There was an error processing the task result!"
|
||||||
|
|
||||||
verifyClientResponse = (responseObject, callback) ->
|
verifyClientResponse = (responseObject, callback) ->
|
||||||
#TODO: better verification
|
#TODO: better verification
|
||||||
|
@ -432,6 +475,7 @@ verifyClientResponse = (responseObject, callback) ->
|
||||||
callback "The response to that query is required to be a JSON object."
|
callback "The response to that query is required to be a JSON object."
|
||||||
else
|
else
|
||||||
@clientResponseObject = responseObject
|
@clientResponseObject = responseObject
|
||||||
|
|
||||||
#log.info "Verified client response!"
|
#log.info "Verified client response!"
|
||||||
callback null, responseObject
|
callback null, responseObject
|
||||||
|
|
||||||
|
@ -459,6 +503,7 @@ deleteQueueMessage = (callback) ->
|
||||||
fetchLevelSession = (callback) ->
|
fetchLevelSession = (callback) ->
|
||||||
findParameters =
|
findParameters =
|
||||||
_id: @clientResponseObject.originalSessionID
|
_id: @clientResponseObject.originalSessionID
|
||||||
|
|
||||||
query = LevelSession
|
query = LevelSession
|
||||||
.findOne(findParameters)
|
.findOne(findParameters)
|
||||||
.lean()
|
.lean()
|
||||||
|
@ -490,11 +535,12 @@ updateSessions = (callback) ->
|
||||||
|
|
||||||
async.map sessionIDs, retrieveOldSessionData, (err, oldScores) =>
|
async.map sessionIDs, retrieveOldSessionData, (err, oldScores) =>
|
||||||
if err? then callback err, {"error": "There was an error retrieving the old scores"}
|
if err? then callback err, {"error": "There was an error retrieving the old scores"}
|
||||||
|
try
|
||||||
oldScoreArray = _.toArray putRankingFromMetricsIntoScoreObject @clientResponseObject, oldScores
|
oldScoreArray = _.toArray putRankingFromMetricsIntoScoreObject @clientResponseObject, oldScores
|
||||||
newScoreArray = bayes.updatePlayerSkills oldScoreArray
|
newScoreArray = bayes.updatePlayerSkills oldScoreArray
|
||||||
saveNewScoresToDatabase newScoreArray, callback
|
saveNewScoresToDatabase newScoreArray, callback
|
||||||
|
catch e
|
||||||
|
callback e
|
||||||
|
|
||||||
saveNewScoresToDatabase = (newScoreArray, callback) ->
|
saveNewScoresToDatabase = (newScoreArray, callback) ->
|
||||||
async.eachSeries newScoreArray, updateScoreInSession, (err) ->
|
async.eachSeries newScoreArray, updateScoreInSession, (err) ->
|
||||||
|
@ -541,7 +587,8 @@ addMatchToSessions = (newScoreObject, callback) ->
|
||||||
#log.info "Writing match object to database..."
|
#log.info "Writing match object to database..."
|
||||||
#use bind with async to do the writes
|
#use bind with async to do the writes
|
||||||
sessionIDs = _.pluck @clientResponseObject.sessions, 'sessionID'
|
sessionIDs = _.pluck @clientResponseObject.sessions, 'sessionID'
|
||||||
async.each sessionIDs, updateMatchesInSession.bind(@,matchObject), (err) -> callback err
|
async.each sessionIDs, updateMatchesInSession.bind(@,matchObject), (err) ->
|
||||||
|
callback err
|
||||||
|
|
||||||
updateMatchesInSession = (matchObject, sessionID, callback) ->
|
updateMatchesInSession = (matchObject, sessionID, callback) ->
|
||||||
currentMatchObject = {}
|
currentMatchObject = {}
|
||||||
|
@ -562,7 +609,11 @@ updateMatchesInSession = (matchObject, sessionID, callback) ->
|
||||||
updateUserSimulationCounts = (reqUserID,callback) ->
|
updateUserSimulationCounts = (reqUserID,callback) ->
|
||||||
incrementUserSimulationCount reqUserID, 'simulatedBy', (err) =>
|
incrementUserSimulationCount reqUserID, 'simulatedBy', (err) =>
|
||||||
if err? then return callback err
|
if err? then return callback err
|
||||||
incrementUserSimulationCount @levelSession.creator, 'simulatedFor', callback
|
console.log "Incremented user simulation count!"
|
||||||
|
unless @isRandomMatch
|
||||||
|
incrementUserSimulationCount @levelSession.creator, 'simulatedFor', callback
|
||||||
|
else
|
||||||
|
callback null
|
||||||
|
|
||||||
incrementUserSimulationCount = (userID, type, callback) =>
|
incrementUserSimulationCount = (userID, type, callback) =>
|
||||||
inc = {}
|
inc = {}
|
||||||
|
@ -605,13 +656,16 @@ determineIfSessionShouldContinueAndUpdateLog = (cb) ->
|
||||||
|
|
||||||
|
|
||||||
findNearestBetterSessionID = (cb) ->
|
findNearestBetterSessionID = (cb) ->
|
||||||
levelOriginalID = @levelSession.level.original
|
try
|
||||||
levelMajorVersion = @levelSession.level.majorVersion
|
levelOriginalID = @levelSession.level.original
|
||||||
sessionID = @clientResponseObject.originalSessionID
|
levelMajorVersion = @levelSession.level.majorVersion
|
||||||
sessionTotalScore = @newScoresObject[sessionID].totalScore
|
sessionID = @clientResponseObject.originalSessionID
|
||||||
opponentSessionID = _.pull(_.keys(@newScoresObject), sessionID)
|
sessionTotalScore = @newScoresObject[sessionID].totalScore
|
||||||
opponentSessionTotalScore = @newScoresObject[opponentSessionID].totalScore
|
opponentSessionID = _.pull(_.keys(@newScoresObject), sessionID)
|
||||||
opposingTeam = calculateOpposingTeam(@clientResponseObject.originalSessionTeam)
|
opponentSessionTotalScore = @newScoresObject[opponentSessionID].totalScore
|
||||||
|
opposingTeam = calculateOpposingTeam(@clientResponseObject.originalSessionTeam)
|
||||||
|
catch e
|
||||||
|
cb e
|
||||||
|
|
||||||
retrieveAllOpponentSessionIDs sessionID, (err, opponentSessionIDs) ->
|
retrieveAllOpponentSessionIDs sessionID, (err, opponentSessionIDs) ->
|
||||||
if err? then return cb err, null
|
if err? then return cb err, null
|
||||||
|
@ -708,7 +762,7 @@ hasTaskTimedOut = (taskSentTimestamp) -> taskSentTimestamp + scoringTaskTimeoutI
|
||||||
|
|
||||||
handleTimedOutTask = (req, res, taskBody) -> errors.clientTimeout res, "The results weren't provided within the timeout"
|
handleTimedOutTask = (req, res, taskBody) -> errors.clientTimeout res, "The results weren't provided within the timeout"
|
||||||
|
|
||||||
putRankingFromMetricsIntoScoreObject = (taskObject,scoreObject) ->
|
putRankingFromMetricsIntoScoreObject = (taskObject, scoreObject) ->
|
||||||
scoreObject = _.indexBy scoreObject, 'id'
|
scoreObject = _.indexBy scoreObject, 'id'
|
||||||
scoreObject[session.sessionID].gameRanking = session.metrics.rank for session in taskObject.sessions
|
scoreObject[session.sessionID].gameRanking = session.metrics.rank for session in taskObject.sessions
|
||||||
return scoreObject
|
return scoreObject
|
||||||
|
|
|
@ -22,7 +22,7 @@ productionLogging = (tokens, req, res) ->
|
||||||
else if status >= 300 then color = 36
|
else if status >= 300 then color = 36
|
||||||
elapsed = (new Date()) - req._startTime
|
elapsed = (new Date()) - req._startTime
|
||||||
elapsedColor = if elapsed < 500 then 90 else 31
|
elapsedColor = if elapsed < 500 then 90 else 31
|
||||||
if (status isnt 200 and status isnt 304 and status isnt 302) or elapsed > 500
|
if (status isnt 200 and status isnt 204 and status isnt 304 and status isnt 302) or elapsed > 500
|
||||||
return "\x1b[90m#{req.method} #{req.originalUrl} \x1b[#{color}m#{res.statusCode} \x1b[#{elapsedColor}m#{elapsed}ms\x1b[0m"
|
return "\x1b[90m#{req.method} #{req.originalUrl} \x1b[#{color}m#{res.statusCode} \x1b[#{elapsedColor}m#{elapsed}ms\x1b[0m"
|
||||||
null
|
null
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ sendMain = (req, res) ->
|
||||||
fs.readFile path.join(__dirname, 'public', 'main.html'), 'utf8', (err, data) ->
|
fs.readFile path.join(__dirname, 'public', 'main.html'), 'utf8', (err, data) ->
|
||||||
log.error "Error modifying main.html: #{err}" if err
|
log.error "Error modifying main.html: #{err}" if err
|
||||||
# insert the user object directly into the html so the application can have it immediately. Sanitize </script>
|
# 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('/', '\\/'))
|
data = data.replace('"userObjectTag"', JSON.stringify(UserHandler.formatEntity(req, req.user)).replace(/\//g, '\\/'))
|
||||||
res.send data
|
res.send data
|
||||||
|
|
||||||
setupFacebookCrossDomainCommunicationRoute = (app) ->
|
setupFacebookCrossDomainCommunicationRoute = (app) ->
|
||||||
|
|
Reference in a new issue