Merged conflicts.

This commit is contained in:
Scott Erickson 2014-07-04 17:54:24 -07:00
commit 85a6b648a5
343 changed files with 4363 additions and 4533 deletions

View file

@ -27,7 +27,7 @@ elementAcceptsKeystrokes = (el) ->
type = el.type?.toLowerCase()
textInputTypes = ['text', 'password', 'file', 'number', 'search', 'url', 'tel', 'email', 'date', 'month', 'week', 'time', 'datetimelocal']
# not radio, checkbox, range, or color
return (tag is 'textarea' or (tag is 'input' and type in textInputTypes) or el.contentEditable in ["", "true"]) and not (el.readOnly or el.disabled)
return (tag is 'textarea' or (tag is 'input' and type in textInputTypes) or el.contentEditable in ['', 'true']) and not (el.readOnly or el.disabled)
COMMON_FILES = ['/images/pages/base/modal_background.png', '/images/level/code_palette_background.png', '/images/level/popover_background.png', '/images/level/code_editor_background.png']
preload = (arrayOfImages) ->
@ -49,7 +49,7 @@ Application = initialize: ->
resStore: locale
#debug: true
#sendMissing: true
#sendMissingTo: "current"
#sendMissingTo: 'current'
#resPostPath: '/languages/add/__lng__/__ns__'
}, (t) =>
@router = new Router()

View file

@ -3,9 +3,9 @@ File = require 'models/File'
module.exports = class ModelFiles extends CocoCollection
model: File
constructor: (model) ->
super()
url = model.constructor.prototype.urlRoot
url += "/#{model.get('original') or model.id}/files"
@url = url
@url = url

View file

@ -3,8 +3,7 @@ CocoCollection = require 'collections/CocoCollection'
module.exports = class PatchesCollection extends CocoCollection
model: PatchModel
initialize: (models, options, forModel, @status='pending') ->
super(arguments...)
@url = "#{forModel.urlRoot}/#{forModel.get('original')}/patches?status=#{@status}"

View file

@ -7,7 +7,7 @@ module.exports = class ThangNamesCollection extends CocoCollection
isCachable: false
constructor: (@ids) -> super()
fetch: (options) ->
options ?= {}
_.extend options, {type:'POST', data:{ids:@ids}}

View file

@ -22,7 +22,7 @@ init = ->
testing = path.startsWith '/test'
demoing = path.startsWith '/demo'
initializeServices() unless testing or demoing
# Set up Backbone.Mediator schemas
setUpDefinitions()
setUpChannels()
@ -35,10 +35,10 @@ init = ->
treemaExt.setup()
$ -> init()
handleNormalUrls = ->
# http://artsy.github.com/blog/2012/06/25/replacing-hashbang-routes-with-pushstate/
$(document).on "click", "a[href^='/']", (event) ->
$(document).on 'click', "a[href^='/']", (event) ->
href = $(event.currentTarget).attr('href')

View file

@ -15,7 +15,7 @@ module.exports = class Angel extends CocoClass
constructor: (@shared) ->
super()
@say 'Got my wings.'
if window.navigator and (window.navigator.userAgent.search("MSIE") isnt -1 or window.navigator.appName is 'Microsoft Internet Explorer')
if window.navigator and (window.navigator.userAgent.search('MSIE') isnt -1 or window.navigator.appName is 'Microsoft Internet Explorer')
@infiniteLoopIntervalDuration *= 10 # since it's so slow to serialize without transferable objects, we can't trust it
@infiniteLoopTimeoutDuration *= 10
@abortTimeoutDuration *= 10
@ -40,7 +40,7 @@ module.exports = class Angel extends CocoClass
return if @destroyed
clearTimeout @condemnTimeout
@condemnTimeout = _.delay @infinitelyLooped, @infiniteLoopTimeoutDuration
@say "Let's give it", @infiniteLoopTimeoutDuration, "to not loop."
@say 'Let\'s give it', @infiniteLoopTimeoutDuration, 'to not loop.'
@worker.postMessage func: 'reportIn'
onWorkerMessage: (event) =>
@ -58,7 +58,7 @@ module.exports = class Angel extends CocoClass
when 'start-load-frames'
clearTimeout @condemnTimeout
when 'report-in'
@say "Worker reported in."
@say 'Worker reported in.'
clearTimeout @condemnTimeout
when 'end-load-frames'
clearTimeout @condemnTimeout
@ -84,7 +84,7 @@ module.exports = class Angel extends CocoClass
when 'new-world'
@beholdWorld event.data.serialized, event.data.goalStates
when 'abort'
@say "Aborted.", event.data
@say 'Aborted.', event.data
clearTimeout @abortTimeout
@aborting = false
@running = false
@ -92,7 +92,7 @@ module.exports = class Angel extends CocoClass
@doWork()
else
@log "Received unsupported message:", event.data
@log 'Received unsupported message:', event.data
beholdGoalStates: (goalStates) ->
return if @aborting
@ -125,37 +125,37 @@ module.exports = class Angel extends CocoClass
@doWork()
finalizePreload: ->
@say "Finalize preload."
@say 'Finalize preload.'
@worker.postMessage func: 'finalizePreload'
infinitelyLooped: =>
@say "On infinitely looped! Aborting?", @aborting
@say 'On infinitely looped! Aborting?', @aborting
return if @aborting
problem = type: "runtime", level: "error", id: "runtime_InfiniteLoop", message: "Code never finished. It's either really slow or has an infinite loop."
problem = type: 'runtime', level: 'error', id: 'runtime_InfiniteLoop', message: 'Code never finished. It\'s either really slow or has an infinite loop.'
Backbone.Mediator.publish 'god:user-code-problem', problem: problem
Backbone.Mediator.publish 'god:infinite-loop', firstWorld: @shared.firstWorld
@fireWorker()
doWork: ->
return if @aborting
return @say "Not initialized for work yet." unless @initialized
return @say 'Not initialized for work yet.' unless @initialized
if @shared.workQueue.length
@work = @shared.workQueue.shift()
return _.defer @simulateSync, @work if @work.synchronous
@say "Running world..."
@say 'Running world...'
@running = true
@shared.busyAngels.push @
@worker.postMessage func: 'runWorld', args: @work
clearTimeout @purgatoryTimer
@say "Infinite loop timer started at interval of", @infiniteLoopIntervalDuration
@say 'Infinite loop timer started at interval of', @infiniteLoopIntervalDuration
@purgatoryTimer = setInterval @testWorker, @infiniteLoopIntervalDuration
else
@say "No work to do."
@say 'No work to do.'
@hireWorker()
abort: ->
return unless @worker and @running
@say "Aborting..."
@say 'Aborting...'
@running = false
@work = null
_.remove @shared.busyAngels, @
@ -172,14 +172,14 @@ module.exports = class Angel extends CocoClass
@worker = null
clearTimeout @condemnTimeout
clearInterval @purgatoryTimer
@say "Fired worker."
@say 'Fired worker.'
@initialized = false
@work = null
@hireWorker() if rehire
hireWorker: ->
return if @worker
@say "Hiring worker."
@say 'Hiring worker.'
@worker = new Worker @shared.workerCode
@worker.addEventListener 'message', @onWorkerMessage
@worker.creationTime = new Date()
@ -199,7 +199,7 @@ module.exports = class Angel extends CocoClass
testWorld.setGoalManager testGM
@doSimulateWorld work
console?.profileEnd?() if imitateIE9?
console.log "Construction:", (work.t1 - work.t0).toFixed(0), "ms. Simulation:", (work.t2 - work.t1).toFixed(0), "ms --", ((work.t2 - work.t1) / testWorld.frames.length).toFixed(3), "ms per frame, profiled."
console.log 'Construction:', (work.t1 - work.t0).toFixed(0), 'ms. Simulation:', (work.t2 - work.t1).toFixed(0), 'ms --', ((work.t2 - work.t1) / testWorld.frames.length).toFixed(3), 'ms per frame, profiled.'
# If performance was really a priority in IE9, we would rework things to be able to skip this step.
goalStates = testGM?.getGoalStates()
@ -212,7 +212,7 @@ module.exports = class Angel extends CocoClass
doSimulateWorld: (work) ->
work.t1 = now()
Math.random = work.testWorld.rand.randf # so user code is predictable
Aether.replaceBuiltin("Math", Math)
Aether.replaceBuiltin('Math', Math)
i = 0
while i < work.testWorld.totalFrames
frame = work.testWorld.getFrame i++

View file

@ -6,17 +6,17 @@
# super()
# @indexLists = []
# @initClone()
#
#
# initClone: () ->
# @target = AsyncCloner.cloneToDepth(@source, @depth)
# @indexLists = [_.keys(@target)] if _.isObject @target
#
#
# @cloneToDepth: (value, depth) ->
# value = _.clone(value)
# return value unless depth and _.isObject value
# value[key] = @cloneToDepth(value[key], depth-1) for key in _.keys value
# value
#
#
# clone: ->
# while @indexLists.length
# #console.log 'Clone loop:', JSON.stringify @indexLists
@ -25,7 +25,7 @@
# @cloneOne()
# @moveIndexForwardOne()
# break if @done() or @timeToSleep()
#
#
# moveIndexForward: ->
# while @indexLists.length
# nextValue = @getNextValue()
@ -34,7 +34,7 @@
# # push a new list if it's a collection
# @indexLists.push _.keys(nextValue)
# continue
# else
# else
# break # we done, the next value needs to be deep cloned
# #console.log 'Skipping:', @getNextPath()
# @moveIndexForwardOne() # move past this value otherwise
@ -44,15 +44,15 @@
# value = @target
# value = value[indexList[0]] for indexList in @indexLists
# value
#
#
# getNextParent: ->
# parent = @target
# parent = parent[indexList[0]] for indexList in @indexLists[...-1]
# parent
#
#
# getNextPath: ->
# (indexList[0] for indexList in @indexLists when indexList.length).join '.'
#
#
# moveIndexForwardOne: ->
# @indexLists[@indexLists.length-1].shift() # move the index forward one
# # if we reached the end of an index list, trim down through all finished lists
@ -69,7 +69,7 @@
# #console.log 'Deep Cloned:', @getNextPath()
#
# done: -> not @indexLists.length
#
#
# timeToSleep: -> false
@ -79,4 +79,4 @@
Clone that one, popping it off the list.
If the last list is now empty, pop that list and every subsequent list if needed.
Check for doneness, or timeout.
###
###

View file

@ -1,11 +1,11 @@
CocoClass = require 'lib/CocoClass'
cache = {}
{me} = require('lib/auth')
{me} = require 'lib/auth'
# Top 20 obscene words (plus 'fiddlesticks') will trigger swearing Simlish with *beeps*.
# Didn't like leaving so much profanity lying around in the source, so rot13'd.
rot13 = (s) -> s.replace /[A-z]/g, (c) -> String.fromCharCode c.charCodeAt(0) + (if c.toUpperCase() <= "M" then 13 else -13)
swears = (rot13 s for s in ["nefrubyr", "nffubyr", "onfgneq", "ovgpu", "oybbql", "obyybpxf", "ohttre", "pbpx", "penc", "phag", "qnza", "qnea", "qvpx", "qbhpur", "snt", "shpx", "cvff", "chffl", "fuvg", "fyhg", "svqqyrfgvpxf"])
rot13 = (s) -> s.replace /[A-z]/g, (c) -> String.fromCharCode c.charCodeAt(0) + (if c.toUpperCase() <= 'M' then 13 else -13)
swears = (rot13 s for s in ['nefrubyr', 'nffubyr', 'onfgneq', 'ovgpu', 'oybbql', 'obyybpxf', 'ohttre', 'pbpx', 'penc', 'phag', 'qnza', 'qnea', 'qvpx', 'qbhpur', 'snt', 'shpx', 'cvff', 'chffl', 'fuvg', 'fyhg', 'svqqyrfgvpxf'])
createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.FlashPlugin, createjs.HTMLAudioPlugin])
@ -129,7 +129,7 @@ class AudioPlayer extends CocoClass
console.error 'Could not load sound', e
notifyProgressChanged: ->
Backbone.Mediator.publish('audio-player:loaded', {sender:@})
Backbone.Mediator.publish('audio-player:loaded', {sender: @})
getStatus: (src) ->
return cache[src] or null

View file

@ -26,9 +26,9 @@ module.exports = Bus = class Bus extends CocoClass
@notifyStateChanges()
connect: ->
Backbone.Mediator.publish 'bus:connecting', {bus:@}
Backbone.Mediator.publish 'bus:connecting', {bus: @}
Firebase.goOnline()
@fireRef = new Firebase(Bus.fireHost + "/" + @docName)
@fireRef = new Firebase(Bus.fireHost + '/' + @docName)
@fireRef.once 'value', @onFireOpen
onFireOpen: (snapshot) =>
@ -36,7 +36,7 @@ module.exports = Bus = class Bus extends CocoClass
console.log("Leaving '#{@docName}' because class has been destroyed.")
return
@init()
Backbone.Mediator.publish 'bus:connected', {bus:@}
Backbone.Mediator.publish 'bus:connected', {bus: @}
disconnect: ->
Firebase.goOffline()
@ -49,7 +49,7 @@ module.exports = Bus = class Bus extends CocoClass
@myConnection?.off()
@myConnection = null
@joined = false
Backbone.Mediator.publish 'bus:disconnected', {bus:@}
Backbone.Mediator.publish 'bus:disconnected', {bus: @}
init: ->
"""
@ -59,7 +59,7 @@ module.exports = Bus = class Bus extends CocoClass
@firePlayersRef = @fireRef.child('players')
@join()
@listenForChanges()
@sendMessage("/me joined.", true)
@sendMessage('/me joined.', true)
join: ->
@joined = true
@ -75,13 +75,13 @@ module.exports = Bus = class Bus extends CocoClass
@firePlayersRef.on 'child_changed', @onPlayerChanged
onChatAdded: (snapshot) =>
Backbone.Mediator.publish('bus:new-message', {message:snapshot.val(), bus:@})
Backbone.Mediator.publish('bus:new-message', {message: snapshot.val(), bus: @})
onPlayerJoined: (snapshot) =>
player = snapshot.val()
return unless player.connected
@players[player.id] = player
Backbone.Mediator.publish('bus:player-joined', {player:player, bus:@})
Backbone.Mediator.publish('bus:player-joined', {player: player, bus: @})
onPlayerLeft: (snapshot) =>
val = snapshot.val()
@ -89,7 +89,7 @@ module.exports = Bus = class Bus extends CocoClass
player = @players[val.id]
return unless player
delete @players[player.id]
Backbone.Mediator.publish('bus:player-left', {player:player, bus:@})
Backbone.Mediator.publish('bus:player-left', {player: player, bus: @})
onPlayerChanged: (snapshot) =>
player = snapshot.val()
@ -97,7 +97,7 @@ module.exports = Bus = class Bus extends CocoClass
@players[player.id] = player
@onPlayerLeft(snapshot) if wasConnected and not player.connected
@onPlayerJoined(snapshot) if player.connected and not wasConnected
Backbone.Mediator.publish('bus:player-states-changed', {states:@players, bus:@})
Backbone.Mediator.publish('bus:player-states-changed', {states: @players, bus: @})
onMeSynced: =>
@myConnection?.child('name').set(me.get('name'))
@ -118,9 +118,9 @@ module.exports = Bus = class Bus extends CocoClass
sendMessage: (content, system=false) ->
MAX_MESSAGE_LENGTH = 400
message =
content:content[... MAX_MESSAGE_LENGTH]
authorName:me.displayName()
authorID:me.id
content: content[... MAX_MESSAGE_LENGTH]
authorName: me.displayName()
authorID: me.id
dateMade: new Date()
message.system = system if system
@fireChatRef.push(message)
@ -128,7 +128,7 @@ module.exports = Bus = class Bus extends CocoClass
# TEARDOWN
destroy: ->
@sendMessage("/me left.", true) if @joined
@sendMessage('/me left.', true) if @joined
delete Bus.activeBuses[@docName] if @docName of Bus.activeBuses
@disconnect()
super()

View file

@ -9,7 +9,7 @@ module.exports = class CocoClass
@nicksUsed: {}
@remainingNicks: []
@nextNick: ->
return (@name or "CocoClass") + " " + classCount unless @nicks.length
return (@name or 'CocoClass') + ' ' + classCount unless @nicks.length
@remainingNicks = if @remainingNicks.length then @remainingNicks else @nicks.slice()
baseNick = @remainingNicks.splice(Math.floor(Math.random() * @remainingNicks.length), 1)[0]
i = 0

View file

@ -44,7 +44,7 @@ module.exports = FacebookHandler = class FacebookHandler extends CocoClass
me.set('gender', r.gender) if r.gender
me.set('email', r.email) if r.email
me.set('facebookID', r.id) if r.id
Backbone.Mediator.publish('logging-in-with-facebook')
window.tracker?.trackEvent 'Facebook Login'
window.tracker?.identify()

View file

@ -14,8 +14,8 @@ userPropsToSave =
fieldsToFetch = 'displayName,gender,image,name(familyName,givenName),id'
plusURL = '/plus/v1/people/me?fields='+fieldsToFetch
revokeUrl = 'https://accounts.google.com/o/oauth2/revoke?token='
clientID = "800329290710-j9sivplv2gpcdgkrsis9rff3o417mlfa.apps.googleusercontent.com"
scope = "https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email"
clientID = '800329290710-j9sivplv2gpcdgkrsis9rff3o417mlfa.apps.googleusercontent.com'
scope = 'https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email'
module.exports = GPlusHandler = class GPlusHandler extends CocoClass
constructor: ->
@ -32,7 +32,7 @@ module.exports = GPlusHandler = class GPlusHandler extends CocoClass
# We need to check the current state, given our access token
gapi.auth.setToken 'token', @accessToken
session_state = @accessToken.session_state
gapi.auth.checkSessionState({client_id:clientID, session_state:session_state}, @onCheckedSessionState)
gapi.auth.checkSessionState({client_id: clientID, session_state: session_state}, @onCheckedSessionState)
else
# If we ran checkSessionState, it might return true, that the user is logged into Google, but has not authorized us
@loggedIn = false
@ -57,7 +57,7 @@ module.exports = GPlusHandler = class GPlusHandler extends CocoClass
# email and profile data loaded separately
@responsesComplete = 0
gapi.client.request(path:plusURL, callback:@onPersonEntityReceived)
gapi.client.request(path: plusURL, callback: @onPersonEntityReceived)
gapi.client.load('oauth2', 'v2', =>
gapi.client.oauth2.userinfo.get().execute(@onEmailReceived))
@ -108,7 +108,7 @@ module.exports = GPlusHandler = class GPlusHandler extends CocoClass
loadFriends: (friendsCallback) ->
return friendsCallback() unless @loggedIn
expiresIn = if @accessToken then parseInt(@accessToken.expires_at) - new Date().getTime()/1000 else -1
onReauthorized = => gapi.client.request({path:'/plus/v1/people/me/people/visible', callback: friendsCallback})
onReauthorized = => gapi.client.request({path: '/plus/v1/people/me/people/visible', callback: friendsCallback})
if expiresIn < 0
# TODO: this tries to open a popup window, which might not ever finish or work, so the callback may never be called.
@reauthorize()

View file

@ -8,7 +8,7 @@ CocoClass = require 'lib/CocoClass'
Angel = require 'lib/Angel'
module.exports = class God extends CocoClass
@nicks: ['Athena', 'Baldr', 'Crom', 'Dagr', 'Eris', 'Freyja', 'Great Gish', 'Hades', 'Ishtar', 'Janus', 'Khronos', 'Loki', 'Marduk', 'Negafook', 'Odin', 'Poseidon', 'Quetzalcoatl', 'Ra', 'Shiva', 'Thor', 'Umvelinqangi', 'Týr', 'Vishnu', 'Wepwawet', 'Xipe Totec', 'Yahweh', 'Zeus', '上帝', 'Tiamat', '盘古', 'Phoebe', 'Artemis', 'Osiris', "嫦娥", 'Anhur', 'Teshub', 'Enlil', 'Perkele', 'Chaos', 'Hera', 'Iris', 'Theia', 'Uranus', 'Stribog', 'Sabazios', 'Izanagi', 'Ao', 'Tāwhirimātea', 'Tengri', 'Inmar', 'Torngarsuk', 'Centzonhuitznahua', 'Hunab Ku', 'Apollo', 'Helios', 'Thoth', 'Hyperion', 'Alectrona', 'Eos', 'Mitra', 'Saranyu', 'Freyr', 'Koyash', 'Atropos', 'Clotho', 'Lachesis', 'Tyche', 'Skuld', 'Urðr', 'Verðandi', 'Camaxtli', 'Huhetotl', 'Set', 'Anu', 'Allah', 'Anshar', 'Hermes', 'Lugh', 'Brigit', 'Manannan Mac Lir', 'Persephone', 'Mercury', 'Venus', 'Mars', 'Azrael', 'He-Man', 'Anansi', 'Issek', 'Mog', 'Kos', 'Amaterasu Omikami', 'Raijin', 'Susanowo', 'Blind Io', 'The Lady', 'Offler', 'Ptah', 'Anubis', 'Ereshkigal', 'Nergal', 'Thanatos', 'Macaria', 'Angelos', 'Erebus', 'Hecate', 'Hel', 'Orcus', 'Ishtar-Deela Nakh', 'Prometheus', 'Hephaestos', 'Sekhmet', 'Ares', 'Enyo', 'Otrera', 'Pele', 'Hadúr', 'Hachiman', 'Dayisun Tngri', 'Ullr', 'Lua', 'Minerva']
@nicks: ['Athena', 'Baldr', 'Crom', 'Dagr', 'Eris', 'Freyja', 'Great Gish', 'Hades', 'Ishtar', 'Janus', 'Khronos', 'Loki', 'Marduk', 'Negafook', 'Odin', 'Poseidon', 'Quetzalcoatl', 'Ra', 'Shiva', 'Thor', 'Umvelinqangi', 'Týr', 'Vishnu', 'Wepwawet', 'Xipe Totec', 'Yahweh', 'Zeus', '上帝', 'Tiamat', '盘古', 'Phoebe', 'Artemis', 'Osiris', '嫦娥', 'Anhur', 'Teshub', 'Enlil', 'Perkele', 'Chaos', 'Hera', 'Iris', 'Theia', 'Uranus', 'Stribog', 'Sabazios', 'Izanagi', 'Ao', 'Tāwhirimātea', 'Tengri', 'Inmar', 'Torngarsuk', 'Centzonhuitznahua', 'Hunab Ku', 'Apollo', 'Helios', 'Thoth', 'Hyperion', 'Alectrona', 'Eos', 'Mitra', 'Saranyu', 'Freyr', 'Koyash', 'Atropos', 'Clotho', 'Lachesis', 'Tyche', 'Skuld', 'Urðr', 'Verðandi', 'Camaxtli', 'Huhetotl', 'Set', 'Anu', 'Allah', 'Anshar', 'Hermes', 'Lugh', 'Brigit', 'Manannan Mac Lir', 'Persephone', 'Mercury', 'Venus', 'Mars', 'Azrael', 'He-Man', 'Anansi', 'Issek', 'Mog', 'Kos', 'Amaterasu Omikami', 'Raijin', 'Susanowo', 'Blind Io', 'The Lady', 'Offler', 'Ptah', 'Anubis', 'Ereshkigal', 'Nergal', 'Thanatos', 'Macaria', 'Angelos', 'Erebus', 'Hecate', 'Hel', 'Orcus', 'Ishtar-Deela Nakh', 'Prometheus', 'Hephaestos', 'Sekhmet', 'Ares', 'Enyo', 'Otrera', 'Pele', 'Hadúr', 'Hachiman', 'Dayisun Tngri', 'Ullr', 'Lua', 'Minerva']
subscriptions:
'tome:cast-spells': 'onTomeCast'
@ -98,7 +98,7 @@ module.exports = class God extends CocoClass
retrieveValueFromFrame: (args) =>
return if @destroyed
return unless args.thangID and args.spellID and args.variableChain
return console.error "Tried to retrieve debug value with no currentUserCodeMap" unless @currentUserCodeMap
return console.error 'Tried to retrieve debug value with no currentUserCodeMap' unless @currentUserCodeMap
@debugWorker ?= @createDebugWorker()
args.frame ?= @angelsShare.world.age / @angelsShare.world.dt
@debugWorker.postMessage

View file

@ -43,7 +43,7 @@ module.exports = class LevelBus extends Bus
incrementSessionPlaytime: =>
if @playerIsIdle then return
@changedSessionProperties.playtime = true
@session.set("playtime",@session.get("playtime") + 1)
@session.set('playtime', @session.get('playtime') + 1)
onPoint: ->
return true unless @session?.get('multiplayer')
@ -123,7 +123,7 @@ module.exports = class LevelBus extends Bus
@changedSessionProperties.teamSpells = true
@session.set({'teamSpells': @teamSpellMap})
@saveSession()
if spellTeam is me.team or spellTeam is "common"
if spellTeam is me.team or spellTeam is 'common'
@onSpellChanged e # Save the new spell to the session, too.
onScriptStateChanged: (e) ->
@ -233,7 +233,7 @@ module.exports = class LevelBus extends Bus
# since updates are coming fast and loose for session objects
# don't let what the server returns overwrite changes since the save began
tempSession = new LevelSession _id:@session.id
tempSession = new LevelSession _id: @session.id
tempSession.save(patch, {patch: true})
destroy: ->

View file

@ -48,7 +48,7 @@ module.exports = class LevelLoader extends CocoClass
# Apparently the jingle, when it tries to play immediately during all this loading, you can't hear it.
# Add the timeout to fix this weird behavior.
f = ->
jingles = ["ident_1", "ident_2"]
jingles = ['ident_1', 'ident_2']
AudioPlayer.playInterfaceSound jingles[Math.floor Math.random() * jingles.length]
setTimeout f, 500
@ -63,7 +63,7 @@ module.exports = class LevelLoader extends CocoClass
url += "?team=#{@team}" if @team
session = new LevelSession().setURL url
@sessionResource = @supermodel.loadModel(session, 'level_session', {cache:false})
@sessionResource = @supermodel.loadModel(session, 'level_session', {cache: false})
@session = @sessionResource.model
@session.once 'sync', -> @url = -> '/db/level.session/' + @id
@ -151,7 +151,7 @@ module.exports = class LevelLoader extends CocoClass
continue if thangType.isFullyLoaded()
thangType.fetch()
thangType = @supermodel.loadModel(thangType, 'thang').model
res = @supermodel.addSomethingResource "sprite_sheet", 5
res = @supermodel.addSomethingResource 'sprite_sheet', 5
res.thangType = thangType
res.markLoading()
@spriteSheetsToBuild.push res
@ -246,7 +246,7 @@ module.exports = class LevelLoader extends CocoClass
break
unless @teamConfigs
# Hack: pulled from Alliance System code. TODO: put in just one place.
@teamConfigs = {"humans":{"superteam":"humans","color":{"hue":0,"saturation":0.75,"lightness":0.5},"playable":true},"ogres":{"superteam":"ogres","color":{"hue":0.66,"saturation":0.75,"lightness":0.5},"playable":false},"neutral":{"superteam":"neutral","color":{"hue":0.33,"saturation":0.75,"lightness":0.5}}}
@teamConfigs = {'humans': {'superteam': 'humans', 'color': {'hue': 0, 'saturation': 0.75, 'lightness': 0.5}, 'playable': true}, 'ogres': {'superteam': 'ogres', 'color': {'hue': 0.66, 'saturation': 0.75, 'lightness': 0.5}, 'playable': false}, 'neutral': {'superteam': 'neutral', 'color': {'hue': 0.33, 'saturation': 0.75, 'lightness': 0.5}}}
@teamConfigs
buildSpriteSheet: (thangType, options) ->
@ -263,13 +263,13 @@ module.exports = class LevelLoader extends CocoClass
@world.levelSessionIDs = if @opponentSessionID then [@sessionID, @opponentSessionID] else [@sessionID]
serializedLevel = @level.serialize(@supermodel)
@world.loadFromLevel serializedLevel, false
console.log "World has been initialized from level loader."
console.log 'World has been initialized from level loader.'
# Initial Sound Loading
loadAudio: ->
return if @headless
AudioPlayer.preloadInterfaceSounds ["victory"]
AudioPlayer.preloadInterfaceSounds ['victory']
loadLevelSounds: ->
return if @headless

View file

@ -12,20 +12,20 @@ module.exports = LinkedInHandler = class LinkedInHandler extends CocoClass
'linkedin-loaded': 'onLinkedInLoaded'
onLinkedInLoaded: (e) ->
IN.Event.on IN, "auth", @onLinkedInAuth
IN.Event.on IN, 'auth', @onLinkedInAuth
onLinkedInAuth: (e) => console.log "Authorized with LinkedIn"
onLinkedInAuth: (e) => console.log 'Authorized with LinkedIn'
constructEmployerAgreementObject: (cb) =>
IN.API.Profile("me")
.fields(["positions","public-profile-url","id","first-name","last-name","email-address"])
IN.API.Profile('me')
.fields(['positions', 'public-profile-url', 'id', 'first-name', 'last-name', 'email-address'])
.error(cb)
.result (profiles) =>
cb null, profiles.values[0]
getProfileData: (cb) =>
IN.API.Profile("me")
.fields(["formatted-name","educations","skills","headline","summary","positions","public-profile-url"])
IN.API.Profile('me')
.fields(['formatted-name', 'educations', 'skills', 'headline', 'summary', 'positions', 'public-profile-url'])
.error(cb)
.result (profiles) =>
cb null, profiles.values[0]

View file

@ -7,9 +7,9 @@ class NameLoader extends CocoClass
toLoad = _.uniq (id for id in ids when not namesCache[id])
return false unless toLoad.length
jqxhrOptions = {
url: '/db/user/x/names',
type:'POST',
data:{ids:toLoad},
url: '/db/user/x/names',
type: 'POST',
data: {ids: toLoad},
success: @loadedNames
}
@ -17,7 +17,7 @@ class NameLoader extends CocoClass
loadedNames: (newNames) =>
_.extend namesCache, newNames
getName: (id) -> namesCache[id]?.name or id
module.exports = new NameLoader()

View file

@ -1,4 +1,4 @@
gplusClientID = "800329290710-j9sivplv2gpcdgkrsis9rff3o417mlfa.apps.googleusercontent.com"
gplusClientID = '800329290710-j9sivplv2gpcdgkrsis9rff3o417mlfa.apps.googleusercontent.com'
go = (path) -> -> @routeDirectly path, arguments
@ -75,16 +75,16 @@ module.exports = class CocoRouter extends Backbone.Router
gapi.plusone.go?() # Handles +1 button
for gplusButton in $('.gplus-login-button')
params = {
callback:"signinCallback",
clientid:gplusClientID,
cookiepolicy:"single_host_origin",
scope:"https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email",
height: "short",
callback: 'signinCallback',
clientid: gplusClientID,
cookiepolicy: 'single_host_origin',
scope: 'https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email',
height: 'short',
}
if gapi.signin?.render
gapi.signin.render(gplusButton, params)
else
console.warn "Didn't have gapi.signin to render G+ login button. (DoNotTrackMe extension?)"
console.warn 'Didn\'t have gapi.signin to render G+ login button. (DoNotTrackMe extension?)'
getViewFromCache: (route) ->
if route of @cache
@ -106,7 +106,7 @@ module.exports = class CocoRouter extends Backbone.Router
getView: (route, suffix='_view') ->
# iteratively breaks down the url pieces looking for the view
# passing the broken off pieces as args. This way views like "resource/14394893"
# passing the broken off pieces as args. This way views like 'resource/14394893'
# will get passed to the resource view with arg '14394893'
pieces = _.string.words(route, '/')
split = Math.max(1, pieces.length-1)

View file

@ -5,6 +5,6 @@ namesCache = {}
class SystemNameLoader extends CocoClass
getName: (id) -> namesCache[id]?.name
setName: (system) -> namesCache[system.get('original')] = {name:system.get('name')}
setName: (system) -> namesCache[system.get('original')] = {name: system.get('name')}
module.exports = new SystemNameLoader()

View file

@ -5,14 +5,14 @@ debugAnalytics = false
module.exports = class Tracker
constructor: ->
if window.tracker
console.error "Overwrote our Tracker!", window.tracker
console.error 'Overwrote our Tracker!', window.tracker
window.tracker = @
@isProduction = document.location.href.search("codecombat.com") isnt -1
@isProduction = document.location.href.search('codecombat.com') isnt -1
@identify()
@updateOlark()
identify: (traits) ->
console.log "Would identify", traits if debugAnalytics
console.log 'Would identify', traits if debugAnalytics
return unless me and @isProduction and analytics?
# https://segment.io/docs/methods/identify
traits ?= {}
@ -23,8 +23,8 @@ module.exports = class Tracker
updateOlark: ->
return unless me and olark?
olark 'api.chat.updateVisitorStatus', snippet: ["User ID: #{me.id}"]
return if me.get("anonymous")
olark 'api.visitor.updateEmailAddress', emailAddress: me.get("email") if me.get('email')
return if me.get('anonymous')
olark 'api.visitor.updateEmailAddress', emailAddress: me.get('email') if me.get('email')
olark 'api.chat.updateVisitorNickname', snippet: me.displayName()
updatePlayState: (level, session) ->
@ -41,13 +41,13 @@ module.exports = class Tracker
trackPageView: ->
return unless @isProduction and analytics?
url = Backbone.history.getFragment()
console.log "Going to track visit for", "/#{url}" if debugAnalytics
console.log 'Going to track visit for', "/#{url}" if debugAnalytics
analytics.pageview "/#{url}"
trackEvent: (event, properties, includeProviders=null) =>
console.log "Would track analytics event:", event, properties if debugAnalytics
console.log 'Would track analytics event:', event, properties if debugAnalytics
return unless me and @isProduction and analytics?
console.log "Going to track analytics event:", event, properties if debugAnalytics
console.log 'Going to track analytics event:', event, properties if debugAnalytics
properties = properties or {}
context = {}
if includeProviders
@ -60,5 +60,5 @@ module.exports = class Tracker
trackTiming: (duration, category, variable, label, samplePercentage=5) ->
# https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingTiming
return console.warn "Duration #{duration} invalid for trackTiming call." unless duration >= 0 and duration < 60 * 60 * 1000
console.log "Would track timing event:", arguments if debugAnalytics
console.log 'Would track timing event:', arguments if debugAnalytics
window._gaq?.push ['_trackTiming', category, variable, duration, label, samplePercentage]

View file

@ -12,13 +12,13 @@ init = ->
me.set 'testGroupNumber', Math.floor(Math.random() * 256)
me.patch()
Backbone.listenTo(me, 'sync', Backbone.Mediator.publish('me:synced', {me:me}))
Backbone.listenTo(me, 'sync', Backbone.Mediator.publish('me:synced', {me: me}))
module.exports.createUser = (userObject, failure=backboneFailure, nextURL=null) ->
user = new User(userObject)
user.notyErrors = false
user.save({}, {
error: (model,jqxhr,options) ->
error: (model, jqxhr, options) ->
error = parseServerError(jqxhr.responseText)
property = error.property if error.property
if jqxhr.status is 409 and property is 'name'
@ -34,14 +34,14 @@ module.exports.createUserWithoutReload = (userObject, failure=backboneFailure) -
user.save({}, {
error: failure
success: ->
Backbone.Mediator.publish("created-user-without-reload")
Backbone.Mediator.publish('created-user-without-reload')
})
module.exports.loginUser = (userObject, failure=genericFailure) ->
jqxhr = $.post('/auth/login',
{
username:userObject.email,
password:userObject.password
username: userObject.email,
password: userObject.password
},
(model) -> window.location.reload()
)

View file

@ -2,8 +2,8 @@ module.exports.sendContactMessage = (contactMessageObject, modal) ->
modal.find('.sending-indicator').show()
jqxhr = $.post '/contact', contactMessageObject, (response) ->
modal.find('.sending-indicator').hide()
modal.find('#contact-message').val("Thanks!")
modal.find('#contact-message').val('Thanks!')
_.delay ->
modal.find('#contact-message').val("")
modal.find('#contact-message').val('')
modal.modal 'hide'
, 1000

View file

@ -1,23 +1,23 @@
SystemNameLoader = require 'lib/SystemNameLoader'
###
###
Good-to-knows:
dataPath: an array of keys that walks you up a JSON object that's being patched
ex: ['scripts', 0, 'description']
deltaPath: an array of keys that walks you up a JSON Diff Patch object.
ex: ['scripts', '_0', 'description']
###
module.exports.expandDelta = (delta, left, schema) ->
flattenedDeltas = flattenDelta(delta)
(expandFlattenedDelta(fd, left, schema) for fd in flattenedDeltas)
flattenDelta = (delta, dataPath=null, deltaPath=null) ->
# takes a single jsondiffpatch delta and returns an array of objects with
return [] unless delta
dataPath ?= []
deltaPath ?= []
return [{dataPath:dataPath, deltaPath: deltaPath, o:delta}] if _.isArray delta
return [{dataPath: dataPath, deltaPath: deltaPath, o: delta}] if _.isArray delta
results = []
affectingArray = delta._t is 'a'
@ -27,12 +27,12 @@ flattenDelta = (delta, dataPath=null, deltaPath=null) ->
results = results.concat flattenDelta(
childDelta, dataPath.concat([dataIndex]), deltaPath.concat([deltaIndex]))
results
expandFlattenedDelta = (delta, left, schema) ->
# takes a single flattened delta and converts into an object that can be
# easily formatted into something human readable.
delta.action = '???'
o = delta.o # the raw jsondiffpatch delta
@ -80,34 +80,34 @@ expandFlattenedDelta = (delta, left, schema) ->
humanPath.push humanKey
parentLeft = childLeft
parentSchema = childSchema
delta.humanPath = humanPath.join(' :: ')
delta.schema = childSchema
delta.left = childLeft
delta.right = jsondiffpatch.patch childLeft, delta.o unless delta.action is 'moved-index'
delta
module.exports.makeJSONDiffer = ->
hasher = (obj) -> obj.name || obj.id || obj._id || JSON.stringify(_.keys(obj))
jsondiffpatch.create({objectHash:hasher})
jsondiffpatch.create({objectHash: hasher})
module.exports.getConflicts = (headDeltas, pendingDeltas) ->
# headDeltas and pendingDeltas should be lists of deltas returned by expandDelta
# Returns a list of conflict objects with properties:
# headDelta
# pendingDelta
# The deltas that have conflicts also have conflict properties pointing to one another.
headPathMap = groupDeltasByAffectingPaths(headDeltas)
pendingPathMap = groupDeltasByAffectingPaths(pendingDeltas)
paths = _.keys(headPathMap).concat(_.keys(pendingPathMap))
# Here's my thinking: conflicts happen when one delta path is a substring of another delta path
# So, sort paths from both deltas together, which will naturally make conflicts adjacent,
# and if one is identified AND one path is from the headDeltas AND the other is from pendingDeltas
# This is all to avoid an O(nm) brute force search.
conflicts = []
paths.sort()
for path, i in paths
@ -116,10 +116,10 @@ module.exports.getConflicts = (headDeltas, pendingDeltas) ->
# Look at the neighbor
nextPath = paths[i+offset]
offset += 1
# these stop being substrings of each other? Then conflict DNE
if not (nextPath.startsWith path) then break
# check if these two are from the same group, but we still need to check for more beyond
unless headPathMap[path] or headPathMap[nextPath] then continue
unless pendingPathMap[path] or pendingPathMap[nextPath] then continue
@ -129,12 +129,12 @@ module.exports.getConflicts = (headDeltas, pendingDeltas) ->
headDelta = headMetaDelta.delta
for pendingMetaDelta in (pendingPathMap[path] or pendingPathMap[nextPath])
pendingDelta = pendingMetaDelta.delta
conflicts.push({headDelta:headDelta, pendingDelta:pendingDelta})
conflicts.push({headDelta: headDelta, pendingDelta: pendingDelta})
pendingDelta.conflict = headDelta
headDelta.conflict = pendingDelta
return conflicts if conflicts.length
groupDeltasByAffectingPaths = (deltas) ->
metaDeltas = []
for delta in deltas
@ -153,21 +153,21 @@ groupDeltasByAffectingPaths = (deltas) ->
delta: delta
path: (item.toString() for item in path).join('/')
}
map = _.groupBy metaDeltas, 'path'
return map
module.exports.pruneConflictsFromDelta = (delta, conflicts) ->
expandedDeltas = (conflict.pendingDelta for conflict in conflicts)
module.exports.pruneExpandedDeltasFromDelta delta, expandedDeltas
module.exports.pruneExpandedDeltasFromDelta = (delta, expandedDeltas) ->
# the jsondiffpatch delta mustn't include any dangling nodes,
# or else things will get removed which shouldn't be, or errors will occur
for expandedDelta in expandedDeltas
prunePath delta, expandedDelta.deltaPath
if _.isEmpty delta then undefined else delta
prunePath = (delta, path) ->
if path.length is 1
delete delta[path]

View file

@ -1,16 +1,16 @@
errorModalTemplate = require('templates/modal/error')
{applyErrorsToForm} = require('lib/forms')
errorModalTemplate = require 'templates/modal/error'
{applyErrorsToForm} = require 'lib/forms'
module.exports.parseServerError = (text) ->
try
error = JSON.parse(text) or {message:"Unknown error."}
error = JSON.parse(text) or {message: 'Unknown error.'}
catch SyntaxError
error = {message:text or "Unknown error."}
error = {message: text or 'Unknown error.'}
error = error[0] if _.isArray(error)
error
module.exports.genericFailure = (jqxhr) ->
Backbone.Mediator.publish('server-error', {response:jqxhr})
Backbone.Mediator.publish('server-error', {response: jqxhr})
return connectionFailure() if not jqxhr.status
error = module.exports.parseServerError(jqxhr.responseText)
@ -24,8 +24,8 @@ module.exports.genericFailure = (jqxhr) ->
existingForm.append($('<div class="alert alert-danger"></div>').text(error.message))
else
res = errorModalTemplate(
status:jqxhr.status
statusText:jqxhr.statusText
status: jqxhr.status
statusText: jqxhr.statusText
message: message
)
showErrorModal(res)
@ -36,7 +36,7 @@ module.exports.backboneFailure = (model, jqxhr, options) ->
module.exports.connectionFailure = connectionFailure = ->
html = errorModalTemplate(
status: 0
statusText:'Connection Gone'
statusText: 'Connection Gone'
message: 'No response from the CoCo servers, captain.'
)
showErrorModal(html)

View file

@ -16,13 +16,13 @@ module.exports.applyErrorsToForm = (el, errors) ->
if error.dataPath
prop = error.dataPath[1..]
message = error.message
else
message = "#{error.property} #{error.message}."
message = message[0].toUpperCase() + message[1..]
message = error.message if error.formatted
prop = error.property
input = $("[name='#{prop}']", el)
if not input.length
missingErrors.push(error)
@ -35,4 +35,4 @@ module.exports.applyErrorsToForm = (el, errors) ->
module.exports.clearFormAlerts = (el) ->
$('.has-error', el).removeClass('has-error')
$('.alert.alert-danger', el).remove()
el.find('.help-block.error-help-block').remove()
el.find('.help-block.error-help-block').remove()

View file

@ -6,9 +6,9 @@ Filters.getPixels = (img) ->
c = @getCanvas(img.naturalWidth, img.naturalHeight)
ctx = c.getContext('2d')
ctx.drawImage(img, 0, 0)
return ctx.getImageData(0,0,c.width,c.height)
return ctx.getImageData(0, 0, c.width, c.height)
Filters.getCanvas = (w,h) ->
Filters.getCanvas = (w, h) ->
c = document.createElement('canvas')
c.width = w
c.height = h
@ -34,7 +34,7 @@ module.exports.darkenImage = darkenImage = (img, pct=0.5) ->
return img.src = cachedValue if cachedValue
jqimg.data('original', img.src) unless jqimg.data('original')
if not (img.naturalWidth > 0 and img.naturalHeight > 0)
console.warn "Tried to darken image", img, "but it has natural dimensions", img.naturalWidth, img.naturalHeight
console.warn 'Tried to darken image', img, 'but it has natural dimensions', img.naturalWidth, img.naturalHeight
return img
imageData = Filters.filterImage(Filters.brightness, img, pct)
c = Filters.getCanvas(img.naturalWidth, img.naturalHeight)

View file

@ -9,7 +9,7 @@ module.exports.getParentFolders = (subPath, urlPrefix='/test/') ->
url: urlPrefix + parts.join('/')
}
paths
module.exports.parseImmediateChildren = (allChildren, subPath, baseRequirePath='test/app/', urlPrefix='/test/') ->
return [] unless allChildren
folders = {}
@ -34,14 +34,14 @@ module.exports.parseImmediateChildren = (allChildren, subPath, baseRequirePath='
for name in _.keys(folders)
children.push {
type:'folder',
type: 'folder',
url: urlPrefix+name
name: name+'/'
size: folders[name]
}
for name in _.keys(files)
children.push {
type:'file',
type: 'file',
url: urlPrefix+name
name: name
}

View file

@ -15,8 +15,8 @@ module.exports = class DOMScriptModule extends ScriptModule
endNotes: ->
notes = []
notes.push({ 'channel': 'end-level-highlight-dom' }) if @noteGroup.dom.highlight?
notes.push({ 'channel': 'level-enable-controls' }) if @noteGroup.dom.lock?
notes.push({'channel': 'end-level-highlight-dom'}) if @noteGroup.dom.highlight?
notes.push({'channel': 'level-enable-controls'}) if @noteGroup.dom.lock?
return notes
skipNotes: ->
@ -60,7 +60,7 @@ module.exports = class DOMScriptModule extends ScriptModule
lock = @noteGroup.dom.lock
event.controls = lock if _.isArray lock # array: subset of controls
channel = if lock then 'level-disable-controls' else 'level-enable-controls'
return { channel: channel, event: event }
return {channel: channel, event: event}
letterboxNote: ->
return { channel: 'level-set-letterbox', event: { on: @noteGroup.dom.letterbox } }
return {channel: 'level-set-letterbox', event: {on: @noteGroup.dom.letterbox}}

View file

@ -76,10 +76,10 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
script.id = (idNum++).toString() unless script.id
callback = makeCallback(script.channel) # curry in the channel argument
@addNewSubscription(script.channel, callback)
beginTicking: ->
@tickInterval = setInterval @tick, 5000
tick: =>
scriptStates = {}
now = new Date()
@ -87,7 +87,7 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
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 ''
@ -123,7 +123,7 @@ module.exports = ScriptManager = class ScriptManager extends CocoClass
for scriptID in scriptsToSkip
script = _.find @scripts, {id: scriptID}
unless script
console.warn "Couldn't find script for", scriptID, "from scripts", @scripts, "when restoring session scripts."
console.warn 'Couldn\'t find script for', scriptID, 'from scripts', @scripts, 'when restoring session scripts.'
continue
continue if script.repeats # repeating scripts are not 'rerun'
@triggered.push(scriptID)

View file

@ -1,31 +1,31 @@
CocoClass = require 'lib/CocoClass'
module.exports = class ScriptModule extends CocoClass
scrubbingTime = 0
movementTime = 0
constructor: (@noteGroup) ->
super()
if not @noteGroup.prepared
@analyzeNoteGroup(noteGroup)
@noteGroup.notes ?= []
@noteGroup.prepared = true
# subclass should overwrite these
@neededFor: -> false
startNotes: -> []
endNotes: -> []
skipNotes: -> @endNotes()
# common logic
analyzeNoteGroup: ->
# some notes need to happen after others. Calculate the delays
@movementTime = @calculateMovementMax(@noteGroup)
@scrubbingTime = @noteGroup.playback?.scrub?.duration or 0
calculateMovementMax: ->
sums = {}
for sprite in @noteGroup.sprites
@ -36,4 +36,4 @@ module.exports = class ScriptModule extends CocoClass
Math.max(0, sums...)
maybeApplyDelayToNote: (note) ->
note.delay = (@scrubbingTime + @movementTime) or 0
note.delay = (@scrubbingTime + @movementTime) or 0

View file

@ -26,7 +26,7 @@ module.exports = class SoundScriptModule extends ScriptModule
channel: 'level-suppress-selection-sounds'
event: {suppress: @noteGroup.sound.suppressSelectionSounds}
return note
addMusicNote: ->
note =
channel: 'level-play-music'

View file

@ -45,7 +45,7 @@ module.exports = class SpritesScriptModule extends ScriptModule
event:
message: text
blurb: blurb
mood: sprite.say.mood or "explain"
mood: sprite.say.mood or 'explain'
responses: responses
spriteID: sprite.id
sound: sound

View file

@ -1,15 +1,15 @@
module.exports = initializeFilepicker = ->
((a) ->
return if window.filepicker
b = a.createElement("script")
b.type = "text/javascript"
return if window.filepicker
b = a.createElement('script')
b.type = 'text/javascript'
b.async = not 0
b.src = ((if "https:" is a.location.protocol then "https:" else "http:")) + "//api.filepicker.io/v1/filepicker.js"
c = a.getElementsByTagName("script")[0]
b.src = ((if 'https:' is a.location.protocol then 'https:' else 'http:')) + '//api.filepicker.io/v1/filepicker.js'
c = a.getElementsByTagName('script')[0]
c.parentNode.insertBefore b, c
d = {}
d._queue = []
e = "pick,pickMultiple,pickAndStore,read,write,writeUrl,export,convert,store,storeUrl,remove,stat,setKey,constructWidget,makeDropPane".split(",")
e = 'pick,pickMultiple,pickAndStore,read,write,writeUrl,export,convert,store,storeUrl,remove,stat,setKey,constructWidget,makeDropPane'.split(',')
f = (a, b) ->
->
b.push [

View file

@ -1,16 +1,16 @@
module.exports = initializeGoogle = ->
window.onGPlusLoaded = ->
Backbone.Mediator.publish "gapi-loaded"
Backbone.Mediator.publish 'gapi-loaded'
return
window.signinCallback = (authResult) ->
Backbone.Mediator.publish "gplus-logged-in", authResult if authResult["access_token"]
Backbone.Mediator.publish 'gplus-logged-in', authResult if authResult['access_token']
return
(->
po = document.createElement("script")
po.type = "text/javascript"
po = document.createElement('script')
po.type = 'text/javascript'
po.async = true
po.src = "https://apis.google.com/js/client:plusone.js?onload=onGPlusLoaded"
s = document.getElementsByTagName("script")[0]
po.src = 'https://apis.google.com/js/client:plusone.js?onload=onGPlusLoaded'
s = document.getElementsByTagName('script')[0]
s.parentNode.insertBefore po, s
return
)()

View file

@ -1,6 +1,6 @@
module.exports = initializeLinkedIn = ->
window.linkedInAsyncInit = ->
console.log "Linkedin async init success!"
console.log 'Linkedin async init success!'
Backbone.Mediator.publish 'linkedin-loaded'
linkedInSnippet =

View file

@ -2,9 +2,9 @@ module.exports = initializeOlark = ->
window.olark or ((c) -> #<![CDATA[
f = window
d = document
l = (if f.location.protocol is "https:" then "https:" else "http:")
l = (if f.location.protocol is 'https:' then 'https:' else 'http:')
z = c.name
r = "load"
r = 'load'
nt = ->
s = ->
a.P r
@ -19,7 +19,7 @@ module.exports = initializeOlark = ->
while q--
((n) ->
f[z][n] = ->
f[z] "call", n, arguments
f[z] 'call', n, arguments
return
return
@ -31,67 +31,67 @@ module.exports = initializeOlark = ->
a.p[u] = new Date - a.p[0]
return
(if f.addEventListener then f.addEventListener(r, s, false) else f.attachEvent("on" + r, s))
(if f.addEventListener then f.addEventListener(r, s, false) else f.attachEvent('on' + r, s))
ld = ->
p = (hd) ->
hd = "head"
hd = 'head'
[
"<"
'<'
hd
"></"
'></'
hd
"><"
'><'
i
" onl" + "oad=\"var d="
' onl' + 'oad=\"var d='
g
";d.getElementsByTagName('head')[0]."
j
"(d."
'(d.'
h
"('script'))."
k
"='"
l
"//"
'//'
a.l
"'"
"\""
"></"
'\"'
'></'
i
">"
].join ""
i = "body"
'>'
].join ''
i = 'body'
m = d[i]
return setTimeout(ld, 100) unless m
a.P 1
j = "appendChild"
h = "createElement"
k = "src"
n = d[h]("div")
j = 'appendChild'
h = 'createElement'
k = 'src'
n = d[h]('div')
v = n[j](d[h](z))
b = d[h]("iframe")
g = "document"
e = "domain"
b = d[h]('iframe')
g = 'document'
e = 'domain'
o = undefined
n.style.display = "none"
n.style.display = 'none'
m.insertBefore(n, m.firstChild).id = z
b.frameBorder = "0"
b.id = z + "-loader"
b.src = "javascript:false" if /MSIE[ ]+6/.test(navigator.userAgent)
b.allowTransparency = "true"
b.frameBorder = '0'
b.id = z + '-loader'
b.src = 'javascript:false' if /MSIE[ ]+6/.test(navigator.userAgent)
b.allowTransparency = 'true'
v[j] b
try
b.contentWindow[g].open()
catch w
c[e] = d[e]
o = "javascript:var d=" + g + ".open();d.domain='" + d.domain + "';"
b[k] = o + "void(0);"
o = 'javascript:var d=' + g + ".open();d.domain='" + d.domain + "';"
b[k] = o + 'void(0);'
try
t = b.contentWindow[g]
t.write p()
t.close()
catch x
b[k] = o + "d.write(\"" + p().replace(/"/g, String.fromCharCode(92) + "\"") + "\");d.close();"
b[k] = o + 'd.write(\"' + p().replace(/"/g, String.fromCharCode(92) + '\"') + '\");d.close();'
a.P 2
return
@ -101,16 +101,15 @@ module.exports = initializeOlark = ->
nt()
return
)(
loader: "static.olark.com/jsclient/loader0.js"
name: "olark"
loader: 'static.olark.com/jsclient/loader0.js'
name: 'olark'
methods: [
"configure"
"extend"
"declare"
"identify"
'configure'
'extend'
'declare'
'identify'
]
)
# custom configuration goes here (www.olark.com/documentation)
olark.identify "1451-787-10-5544" #]]>
# custom configuration goes here (www.olark.com/documentation)
olark.identify '1451-787-10-5544' #]]>

View file

@ -2,18 +2,18 @@ module.exports = initializeSegmentio = ->
analytics = analytics or []
(->
e = [
"identify"
"track"
"trackLink"
"trackForm"
"trackClick"
"trackSubmit"
"page"
"pageview"
"ab"
"alias"
"ready"
"group"
'identify'
'track'
'trackLink'
'trackForm'
'trackClick'
'trackSubmit'
'page'
'pageview'
'ab'
'alias'
'ready'
'group'
]
t = (e) ->
->
@ -28,14 +28,13 @@ module.exports = initializeSegmentio = ->
return
)()
analytics.load = (e) ->
t = document.createElement("script")
t.type = "text/javascript"
t = document.createElement('script')
t.type = 'text/javascript'
t.async = not 0
t.src = ((if "https:" is document.location.protocol then "https://" else "http://")) + "d2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/" + e + "/analytics.min.js"
t.src = ((if 'https:' is document.location.protocol then 'https://' else 'http://')) + 'd2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/' + e + '/analytics.min.js'
n = document.getElementsByTagName("script")[0]
n = document.getElementsByTagName('script')[0]
n.parentNode.insertBefore t, n
return
analytics.load "jsjzx9n4d2"
analytics.load 'jsjzx9n4d2'

View file

@ -2,11 +2,11 @@ module.exports = initializeTwitter = ->
((d, s, id) ->
js = undefined
fjs = d.getElementsByTagName(s)[0]
p = (if /^http:/.test(d.location) then "http" else "https")
p = (if /^http:/.test(d.location) then 'http' else 'https')
unless d.getElementById(id)
js = d.createElement(s)
js.id = id
js.src = p + "://platform.twitter.com/widgets.js"
js.src = p + '://platform.twitter.com/widgets.js'
fjs.parentNode.insertBefore js, fjs
return
) document, "script", "twitter-wjs"
) document, 'script', 'twitter-wjs'

View file

@ -8,7 +8,6 @@ Aether.addGlobal 'Vector', require 'lib/world/vector'
Aether.addGlobal '_', _
module.exports = class Simulator extends CocoClass
constructor: (@options) ->
@options ?= {}
_.extend @, Backbone.Events
@ -27,12 +26,12 @@ module.exports = class Simulator extends CocoClass
fetchAndSimulateOneGame: (humanGameID, ogresGameID) =>
return if @destroyed
$.ajax
url: "/queue/scoring/getTwoGames"
type: "POST"
url: '/queue/scoring/getTwoGames'
type: 'POST'
parse: true
data:
"humansGameID": humanGameID
"ogresGameID": ogresGameID
'humansGameID': humanGameID
'ogresGameID': ogresGameID
error: (errorData) ->
console.warn "There was an error fetching two games! #{JSON.stringify errorData}"
success: (taskData) =>
@ -71,31 +70,31 @@ module.exports = class Simulator extends CocoClass
@god.createWorld @generateSpellsObject()
handleSingleSimulationError: (error) ->
console.error "There was an error simulating a single game!", error
console.error 'There was an error simulating a single game!', error
if @options.headlessClient and @options.simulateOnlyOneGame
console.log "GAMERESULT:tie"
console.log 'GAMERESULT:tie'
process.exit(0)
@cleanupAndSimulateAnotherTask()
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 and @options.simulateOnlyOneGame
console.log "GAMERESULT:tie"
console.log 'GAMERESULT:tie'
process.exit(0)
@cleanupAndSimulateAnotherTask()
processSingleGameResults: (simulationResults) ->
taskResults = @formTaskResultsObject simulationResults
console.log "Processing results:", taskResults
console.log 'Processing results:', taskResults
humanSessionRank = taskResults.sessions[0].metrics.rank
ogreSessionRank = taskResults.sessions[1].metrics.rank
if @options.headlessClient and @options.simulateOnlyOneGame
if humanSessionRank is ogreSessionRank
console.log "GAMERESULT:tie"
console.log 'GAMERESULT:tie'
else if humanSessionRank < ogreSessionRank
console.log "GAMERESULT:humans"
console.log 'GAMERESULT:humans'
else if ogreSessionRank < humanSessionRank
console.log "GAMERESULT:ogres"
console.log 'GAMERESULT:ogres'
process.exit(0)
else
@sendSingleGameBackToServer(taskResults)
@ -104,32 +103,31 @@ module.exports = class Simulator extends CocoClass
@trigger 'statusUpdate', 'Simulation completed, sending results back to server!'
$.ajax
url: "/queue/scoring/recordTwoGames"
url: '/queue/scoring/recordTwoGames'
data: results
type: "PUT"
type: 'PUT'
parse: true
success: @handleTaskResultsTransferSuccess
error: @handleTaskResultsTransferError
complete: @cleanupAndSimulateAnotherTask
fetchAndSimulateTask: =>
return if @destroyed
if @options.headlessClient
if @dumpThisTime # The first heapdump would be useless to find leaks.
console.log "Writing snapshot."
console.log 'Writing snapshot.'
@options.heapdump.writeSnapshot()
@dumpThisTime = true if @options.heapdump
if @options.testing
_.delay @setupSimulationAndLoadLevel, 0, @options.testFile, "Testing...", status: 400
_.delay @setupSimulationAndLoadLevel, 0, @options.testFile, 'Testing...', status: 400
return
@trigger 'statusUpdate', 'Fetching simulation data!'
$.ajax
url: @taskURL
type: "GET"
type: 'GET'
parse: true
error: @handleFetchTaskError
success: @setupSimulationAndLoadLevel
@ -139,13 +137,12 @@ module.exports = class Simulator extends CocoClass
@trigger 'statusUpdate', 'There was an error fetching games to simulate. Retrying in 10 seconds.'
@simulateAnotherTaskAfterDelay()
handleNoGamesResponse: ->
info = 'Finding game to simulate...'
console.log info
@trigger 'statusUpdate', info
@fetchAndSimulateOneGame()
application.tracker?.trackEvent 'Simulator Result', label: "No Games", ['Google Analytics']
application.tracker?.trackEvent 'Simulator Result', label: 'No Games', ['Google Analytics']
simulateAnotherTaskAfterDelay: =>
console.log "Retrying in #{@retryDelayInSeconds}"
@ -184,7 +181,7 @@ module.exports = class Simulator extends CocoClass
try
@commenceSimulationAndSetupCallback()
catch err
console.error "There was an error in simulation:", err, "-- trying again in #{@retryDelayInSeconds} seconds"
console.error 'There was an error in simulation:', err, "-- trying again in #{@retryDelayInSeconds} seconds"
@simulateAnotherTaskAfterDelay()
assignWorldAndLevelFromLevelLoaderAndDestroyIt: ->
@ -205,11 +202,11 @@ module.exports = class Simulator extends CocoClass
Backbone.Mediator.subscribeOnce 'god:goals-calculated', @processResults, @
@god.createWorld @generateSpellsObject()
#Search for leaks, headless-client only.
# Search for leaks, headless-client only.
if @options.headlessClient and @options.leakTest and not @memwatch?
leakcount = 0
maxleakcount = 0
console.log "Setting leak callbacks."
console.log 'Setting leak callbacks.'
@memwatch = require 'memwatch'
@memwatch.on 'leak', (info) =>
@ -220,17 +217,17 @@ module.exports = class Simulator extends CocoClass
@hd = new @memwatch.HeapDiff()
@memwatch.on 'stats', (stats) =>
console.warn "stats callback: " + stats
console.warn 'stats callback: ' + stats
diff = @hd.end()
console.warn "HeapDiff:\n" + JSON.stringify(diff)
if @options.exitOnLeak
console.warn "Exiting because of Leak."
console.warn 'Exiting because of Leak.'
process.exit()
@hd = new @memwatch.HeapDiff()
onInfiniteLoop: ->
console.warn "Skipping infinitely looping game."
console.warn 'Skipping infinitely looping game.'
@trigger 'statusUpdate', "Infinite loop detected; grabbing a new game in #{@retryDelayInSeconds} seconds."
_.delay @cleanupAndSimulateAnotherTask, @retryDelayInSeconds * 1000
@ -244,16 +241,16 @@ module.exports = class Simulator extends CocoClass
sendResultsBackToServer: (results) ->
@trigger 'statusUpdate', 'Simulation completed, sending results back to server!'
console.log "Sending result back to server:"
console.log 'Sending result back to server:'
console.log JSON.stringify results
if @options.headlessClient and @options.testing
return @fetchAndSimulateTask()
$.ajax
url: "/queue/scoring"
url: '/queue/scoring'
data: results
type: "PUT"
type: 'PUT'
parse: true
success: @handleTaskResultsTransferSuccess
error: @handleTaskResultsTransferError
@ -263,12 +260,12 @@ module.exports = class Simulator extends CocoClass
return if @destroyed
console.log "Task registration result: #{JSON.stringify result}"
@trigger 'statusUpdate', 'Results were successfully sent back to server!'
console.log "Simulated by you:", @simulatedByYou
console.log 'Simulated by you:', @simulatedByYou
@simulatedByYou++
unless @options.headlessClient
simulatedBy = parseInt($('#simulated-by-you').text(), 10) + 1
$('#simulated-by-you').text(simulatedBy)
application.tracker?.trackEvent 'Simulator Result', label: "Success", ['Google Analytics']
application.tracker?.trackEvent 'Simulator Result', label: 'Success', ['Google Analytics']
handleTaskResultsTransferError: (error) =>
return if @destroyed
@ -316,11 +313,11 @@ module.exports = class Simulator extends CocoClass
humansWon = _.all humanGoals, {status: 'success'}
if ogresWon is humansWon
return 0
else if ogresWon and teamSessionMap["ogres"] is sessionID
else if ogresWon and teamSessionMap['ogres'] is sessionID
return 0
else if ogresWon and teamSessionMap["ogres"] isnt sessionID
else if ogresWon and teamSessionMap['ogres'] isnt sessionID
return 1
else if humansWon and teamSessionMap["humans"] is sessionID
else if humansWon and teamSessionMap['humans'] is sessionID
return 0
else
return 1
@ -376,14 +373,13 @@ module.exports = class Simulator extends CocoClass
else
spellSession = _.filter(@task.getSessions(), {team: spellTeam})[0]
unless codeLanguage = spellSession?.submittedCodeLanguage
console.warn "Session", spellSession.creatorName, spellSession.team, "didn't have submittedCodeLanguage, just:", spellSession
console.warn 'Session', spellSession.creatorName, spellSession.team, 'didn\'t have submittedCodeLanguage, just:', spellSession
@spells[spellKey].thangs[thang.id].aether = @createAether @spells[spellKey].name, method, useProtectAPI, codeLanguage ? 'javascript'
transpileSpell: (thang, spellKey, methodName) ->
slugifiedThangID = _.string.slugify thang.id
generatedSpellKey = [slugifiedThangID,methodName].join '/'
source = @currentUserCodeMap[generatedSpellKey] ? ""
source = @currentUserCodeMap[generatedSpellKey] ? ''
aether = @spells[spellKey].thangs[thang.id].aether
unless _.contains(@task.spellKeysToTranspile, generatedSpellKey)
aether.pure = source
@ -399,22 +395,21 @@ module.exports = class Simulator extends CocoClass
functionName: methodName
protectAPI: useProtectAPI
includeFlow: false
yieldConditionally: methodName is "plan"
yieldConditionally: methodName is 'plan'
globals: ['Vector', '_']
problems:
jshint_W040: {level: "ignore"}
jshint_W030: {level: "ignore"} # aether_NoEffect instead
jshint_W040: {level: 'ignore'}
jshint_W030: {level: 'ignore'} # aether_NoEffect instead
aether_MissingThis: {level: 'error'}
#functionParameters: # TODOOOOO
executionLimit: 1 * 1000 * 1000
language: codeLanguage
if methodName is 'hear' then aetherOptions.functionParameters = ['speaker', 'message', 'data']
if methodName is 'makeBid' then aetherOptions.functionParameters = ['tileGroupLetter']
if methodName is "findCentroids" then aetherOptions.functionParameters = ["centroids"]
#console.log "creating aether with options", aetherOptions
if methodName is 'findCentroids' then aetherOptions.functionParameters = ['centroids']
#console.log 'creating aether with options', aetherOptions
return new Aether aetherOptions
class SimulationTask
constructor: (@rawData) ->
@spellKeyToTeamMap = {}
@ -423,12 +418,12 @@ class SimulationTask
getLevelName: ->
levelName = @rawData.sessions?[0]?.levelID
return levelName if levelName?
@throwMalformedTaskError "The level name couldn't be deduced from the task."
@throwMalformedTaskError 'The level name couldn\'t be deduced from the task.'
generateTeamToSessionMap: ->
teamSessionMap = {}
for session in @rawData.sessions
@throwMalformedTaskError "Two players share the same team" if teamSessionMap[session.team]?
@throwMalformedTaskError 'Two players share the same team' if teamSessionMap[session.team]?
teamSessionMap[session.team] = session.sessionID
teamSessionMap
@ -450,7 +445,6 @@ class SimulationTask
setWorld: (@world) ->
generateSpellKeyToSourceMap: ->
playerTeams = _.pluck @rawData.sessions, 'team'
spellKeyToSourceMap = {}
@ -469,7 +463,7 @@ class SimulationTask
for thangName, thangSpells of session.transpiledCode
for spellName, spell of thangSpells
fullSpellName = [thangName,spellName].join '/'
fullSpellName = [thangName, spellName].join '/'
if _.contains(teamSpells, fullSpellName)
teamCode[fullSpellName]=spell

View file

@ -14,7 +14,7 @@ module.exports = class SpriteBuilder
buildMovieClip: (animationName, movieClipArgs...) ->
animData = @animationStore[animationName]
unless animData
console.error "couldn't find animData from", @animationStore, "for", animationName
console.error 'couldn\'t find animData from', @animationStore, 'for', animationName
return null
locals = {}
_.extend locals, @buildMovieClipShapes(animData.shapes)
@ -111,7 +111,7 @@ module.exports = class SpriteBuilder
shape
buildContainerFromStore: (containerKey) ->
console.error "Yo we don't have no", containerKey unless containerKey
console.error 'Yo we don\'t have no', containerKey unless containerKey
contData = @containerStore[containerKey]
cont = new createjs.Container()
cont.initialize()
@ -182,5 +182,4 @@ module.exports = class SpriteBuilder
continue if (not shape.fc?) or not(colors[shape.fc])
@colorMap[shapeKey] = hslToHex(colors[shape.fc])
sum = (nums) -> _.reduce(nums, (s, num) -> s + num)

View file

@ -29,8 +29,8 @@ module.exports = class SpriteParser
parse: (source) ->
# Grab the library properties' width/height so we can subtract half of each from frame bounds
properties = source.match(/.*lib\.properties = \{\n.*?width: (\d+),\n.*?height: (\d+)/im)
@width = parseInt(properties?[1] ? "0", 10)
@height = parseInt(properties?[2] ? "0", 10)
@width = parseInt(properties?[1] ? '0', 10)
@height = parseInt(properties?[2] ? '0', 10)
options = {loc: false, range: true}
ast = esprima.parse source, options
@ -60,7 +60,7 @@ module.exports = class SpriteParser
continue if gotIt
for c in localContainers
if c.bn is bn
instructions.push { t: c.t, gn: c.gn }
instructions.push {t: c.t, gn: c.gn}
break
@addContainer {c: instructions, b: container.bounds}, container.name
for movieClip in movieClips
@ -101,7 +101,7 @@ module.exports = class SpriteParser
if not shortKey?
shortKey = name
if @thangType.containers[shortKey]?
shortKey = @animationName + ":" + name
shortKey = @animationName + ':' + name
@thangType.containers[shortKey] = container
@containerLongKeys[longKey] = shortKey
@containerRenamings[name] = shortKey
@ -115,7 +115,7 @@ module.exports = class SpriteParser
else
shortKey = name
if @thangType.animations[shortKey]?
shortKey = @animationName + ":" + name
shortKey = @animationName + ':' + name
@thangType.animations[shortKey] = animation
@animationLongKeys[longKey] = shortKey
@animationRenamings[name] = shortKey
@ -173,7 +173,7 @@ module.exports = class SpriteParser
frameBoundsRange = frameBoundsStatement.expression.right.range
frameBoundsSource = @subSourceFromRange frameBoundsRange, source
if frameBoundsSource.search(/\[rect/) is -1 # some other statement; we don't have multiframe bounds
console.log "Didn't have multiframe bounds for this movie clip."
console.log 'Didn\'t have multiframe bounds for this movie clip.'
frameBounds = [nominalBounds]
else
lastRect = nominalBounds
@ -204,10 +204,10 @@ module.exports = class SpriteParser
functionExpressions
###
this.shape_1.graphics.f("#605E4A").s().p("AAOD/IgOgaIAEhkIgmgdIgMgBIgPgFIgVgJQA1h9g8jXQAQAHAOASQAQAUAKAeQARAuAJBJQAHA/gBA5IAAADIACAfIAFARIACAGIAEAHIAHAHQAVAXAQAUQAUAaANAUIABACIgsgdIgggXIAAAnIABAwIgBgBg");
this.shape_1.graphics.f('#605E4A').s().p('AAOD/IgOgaIAEhkIgmgdIgMgBIgPgFIgVgJQA1h9g8jXQAQAHAOASQAQAUAKAeQARAuAJBJQAHA/gBA5IAAADIACAfIAFARIACAGIAEAHIAHAHQAVAXAQAUQAUAaANAUIABACIgsgdIgggXIAAAnIABAwIgBgBg');
this.shape_1.sett(23.2,30.1);
this.shape.graphics.f().s("#000000").ss(0.1,1,1).p("AAAAAQAAAAAAAA");
this.shape.graphics.f().s('#000000').ss(0.1,1,1).p('AAAAAQAAAAAAAA');
this.shape.sett(3.8,22.4);
###
@ -218,7 +218,7 @@ module.exports = class SpriteParser
return unless node.type is 'NewExpression' and node.callee.property.name is 'Graphics'
blockName = node.parent.parent.parent.id.name
graphicsString = node.parent.parent.arguments[0].value
localGraphics.push({p:graphicsString, bn:blockName})
localGraphics.push {p:graphicsString, bn:blockName}
@walk block, null, gatherShapeDefinitions
return localGraphics
@ -233,7 +233,7 @@ module.exports = class SpriteParser
if not name
name = node.parent?.parent?.id?.name
return unless name and name.indexOf('mask') is 0 and node.property?.name is 'Shape'
shape = { bn: name, im: true }
shape = {bn: name, im: true}
localShapes.push shape
return
return unless name.search('shape') is 0 and node.object.property?.name is 'graphics'
@ -243,14 +243,14 @@ module.exports = class SpriteParser
linearGradientFill = @grabFunctionArguments linearGradientFillSource.replace(/.*?lf\(/, 'lf('), true
else
fillColor = fillCall.arguments[0]?.value ? null
console.error "What is this?! Not a fill!" unless fillCall.callee.property.name is 'f'
console.error 'What is this?! Not a fill!' unless fillCall.callee.property.name is 'f'
strokeCall = node.parent.parent.parent.parent
if strokeCall.object.callee.property.name is 'ls'
linearGradientStrokeSource = @subSourceFromRange strokeCall.parent.range, source
linearGradientStroke = @grabFunctionArguments linearGradientStrokeSource.replace(/.*?ls\(/, 'ls(').replace(/\).ss\(.*/, ')'), true
else
strokeColor = strokeCall.object.arguments?[0]?.value ? null
console.error "What is this?! Not a stroke!" unless strokeCall.object.callee.property.name is 's'
console.error 'What is this?! Not a stroke!' unless strokeCall.object.callee.property.name is 's'
strokeStyle = null
graphicsStatement = strokeCall.parent
if strokeColor or linearGradientStroke
@ -264,7 +264,7 @@ module.exports = class SpriteParser
drawEllipse = @grabFunctionArguments drawEllipseSource.replace(/.*?de\(/, 'de('), true
else
path = graphicsStatement.arguments?[0]?.value ? null
console.error "What is this?! Not a path!" unless graphicsStatement.callee.property.name is 'p'
console.error 'What is this?! Not a path!' unless graphicsStatement.callee.property.name is 'p'
body = graphicsStatement.parent.parent.body
graphicsStatementIndex = _.indexOf body, graphicsStatement.parent
t = body[graphicsStatementIndex + 1].expression
@ -295,8 +295,8 @@ module.exports = class SpriteParser
shape.fc = fillColor if fillColor
shape.lf = linearGradientFill if linearGradientFill
shape.ls = linearGradientStroke if linearGradientStroke
if name.search('shape') isnt -1 and shape.fc is "rgba(0,0,0,0.451)" and not shape.ss and not shape.sc
console.log "Skipping a shadow", name, shape, "because we're doing shadows separately now."
if name.search('shape') isnt -1 and shape.fc is 'rgba(0,0,0,0.451)' and not shape.ss and not shape.sc
console.log 'Skipping a shadow', name, shape, 'because we\'re doing shadows separately now.'
return
shapeKeys.push shapeKey = @addShape shape
localShape = {bn: name, gn: shapeKey}
@ -372,17 +372,17 @@ module.exports = class SpriteParser
return if name is 'get' and callExpressions.length # avoid Ease calls in the tweens
flattenedRanges = _.flatten [a.range for a in node.arguments]
range = [_.min(flattenedRanges), _.max(flattenedRanges)]
# Replace "this.<local>" references with just the "name"
# Replace 'this.<local>' references with just the 'name'
argsSource = @subSourceFromRange(range, source)
argsSource = argsSource.replace(/mask/g, 'this.mask') # so the mask thing will be handled correctly as a blockName in the next line
argsSource = argsSource.replace(/this\.([a-z_0-9]+)/ig, '"$1"') # turns this.shape literal to "shape" string
argsSource = argsSource.replace(/this\.([a-z_0-9]+)/ig, '"$1"') # turns this.shape literal to 'shape' string
argsSource = argsSource.replace(/cjs(.+)\)/, '"createjs$1)"') # turns cjs.Ease.get(0.5)
args = eval "[#{argsSource}]"
shadowTween = args[0]?.search?('shape') is 0 and not _.find(localShapes, bn: args[0])
shadowTween = shadowTween or args[0]?.state?[0]?.t?.search?("shape") is 0 and not _.find(localShapes, bn: args[0].state[0].t)
shadowTween = shadowTween or args[0]?.state?[0]?.t?.search?('shape') is 0 and not _.find(localShapes, bn: args[0].state[0].t)
if shadowTween
console.log "Skipping tween", name, argsSource, args, "from localShapes", localShapes, "presumably because it's a shadow we skipped."
console.log 'Skipping tween', name, argsSource, args, 'from localShapes', localShapes, 'presumably because it\'s a shadow we skipped.'
return
callExpressions.push {n: name, a: args}
@walk node.parent.parent, null, gatherCallExpressions
@ -395,7 +395,7 @@ module.exports = class SpriteParser
block = block.expression.object.right.body
localArgs = []
gatherAddChildCalls = (node) =>
return unless node.type is "Identifier" and node.name is "addChild"
return unless node.type is 'Identifier' and node.name is 'addChild'
args = node.parent.parent.arguments
args = (arg.property.name for arg in args)
localArgs.push arg for arg in args
@ -427,18 +427,18 @@ var p; // shortcut to reference prototypes
// Layer 7
this.shape = new cjs.Shape();
this.shape.graphics.f("#4F6877").s().p("AgsAxQgSgVgB");
this.shape.graphics.f('#4F6877').s().p('AgsAxQgSgVgB');
this.shape.setTransform(283.1,146.1);
// Layer 7 2
this.shape_1 = new cjs.Shape();
this.shape_1.graphics.f("rgba(255,255,255,0.4)").s().p("ArTs0QSMB7EbVGQhsBhiGBHQjg1IvVkhg");
this.shape_1.graphics.f('rgba(255,255,255,0.4)').s().p('ArTs0QSMB7EbVGQhsBhiGBHQjg1IvVkhg');
this.shape_1.setTransform(400.2,185.5);
this.timeline.addTween(cjs.Tween.get({}).to({state:[]}).to({state:[{t:this.shape}]},7).to({state:[]},2).wait(6));
// Wing
this.instance_9 = new lib.Wing_Animation("synched",0);
this.instance_9 = new lib.Wing_Animation('synched',0);
this.instance_9.setTransform(313.9,145.6,1,1,0,0,0,49,-83.5);
this.timeline.addTween(cjs.Tween.get(this.instance_9).to({y:128,startPosition:7},7).wait(1));
@ -455,11 +455,11 @@ p.nominalBounds = new cjs.Rectangle(7.1,48.9,528.7,431.1);
// Isolation Mode
this.shape = new cjs.Shape();
this.shape.graphics.f("#1D2226").s().p("AgVAwQgUgdgN");
this.shape.graphics.f('#1D2226').s().p('AgVAwQgUgdgN');
this.shape.setTransform(75,25.8);
this.shape_1 = new cjs.Shape();
this.shape_1.graphics.f("#1D2226").s().p("AgnBXQACABAF");
this.shape_1.graphics.f('#1D2226').s().p('AgnBXQACABAF');
this.shape_1.setTransform(80.8,22);
this.addChild(this.shape_1,this.shape);
@ -471,15 +471,15 @@ p.nominalBounds = new cjs.Rectangle(5.8,0,87.9,85);
// Layer 1
this.shape = new cjs.Shape();
this.shape.graphics.f("#DBDDBC").s().p("Ag3BeQgCgRA");
this.shape.graphics.f('#DBDDBC').s().p('Ag3BeQgCgRA');
this.shape.setTransform(10.6,19.7,1.081,1.081);
this.shape_1 = new cjs.Shape();
this.shape_1.graphics.f("#1D2226").s().p("AB4CDQgGg");
this.shape_1.graphics.f('#1D2226').s().p('AB4CDQgGg');
this.shape_1.setTransform(19.9,17.6,1.081,1.081);
this.shape_2 = new cjs.Shape();
this.shape_2.graphics.f("#605E4A").s().p("AiECbQgRg");
this.shape_2.graphics.f('#605E4A').s().p('AiECbQgRg');
this.shape_2.setTransform(19.5,18.4,1.081,1.081);
this.addChild(this.shape_2,this.shape_1,this.shape);

View file

@ -8,7 +8,7 @@ d2r = (degrees) -> degrees / 180 * Math.PI
MAX_ZOOM = 8
MIN_ZOOM = 0.1
DEFAULT_ZOOM = 2.0
DEFAULT_TARGET = {x:0, y:0}
DEFAULT_TARGET = {x: 0, y: 0}
DEFAULT_TIME = 1000
STANDARD_ZOOM_WIDTH = 924
STANDARD_ZOOM_HEIGHT = 589
@ -78,7 +78,7 @@ module.exports = class Camera extends CocoClass
console.log "Restricted given horizontal field of view to #{r2d(hFOV)} to #{r2d(@hFOV)}."
@vFOV = 2 * Math.atan(Math.tan(@hFOV / 2) * @canvasHeight / @canvasWidth)
if @vFOV > Math.PI
console.log "Vertical field of view problem: expected canvas not to be taller than it is wide with high field of view."
console.log 'Vertical field of view problem: expected canvas not to be taller than it is wide with high field of view.'
@vFOV = Math.PI - epsilon
calculateAxisConversionFactors: ->
@ -210,9 +210,9 @@ module.exports = class Camera extends CocoClass
right = Math.max(worldBounds[0].x, worldBounds[1].x)
bottom -= 1 if top is bottom
right += 1 if left is right
p1 = @worldToSurface({x:left, y:top})
p2 = @worldToSurface({x:right, y:bottom})
{x:p1.x, y:p1.y, width:p2.x-p1.x, height:p2.y-p1.y}
p1 = @worldToSurface({x: left, y: top})
p2 = @worldToSurface({x: right, y: bottom})
{x: p1.x, y: p1.y, width: p2.x-p1.x, height: p2.y-p1.y}
calculateMinMaxZoom: ->
# Zoom targets are always done in Surface coordinates.
@ -314,6 +314,7 @@ module.exports = class Camera extends CocoClass
lock: ->
@target = @currentTarget
@locked = true
unlock: ->
@locked = false

View file

@ -25,6 +25,6 @@ module.exports = class CameraBorder extends createjs.Container
i = width
while i
opacity = 3 * (1 - (i/width)) / width
@border.graphics.setStrokeStyle(i,"round").beginStroke("rgba(0,0,0,#{opacity})").drawRect(bounds.x, bounds.y, bounds.width, bounds.height)
@border.graphics.setStrokeStyle(i, 'round').beginStroke("rgba(0,0,0,#{opacity})").drawRect(bounds.x, bounds.y, bounds.width, bounds.height)
i -= 1
@border.cache bounds.x, bounds.y, bounds.width, bounds.height

View file

@ -11,21 +11,21 @@ module.exports = class CastingScreen extends CocoClass
options ?= {}
@camera = options.camera
@layer = options.layer
console.error @toString(), "needs a camera." unless @camera
console.error @toString(), "needs a layer." unless @layer
console.error @toString(), 'needs a camera.' unless @camera
console.error @toString(), 'needs a layer.' unless @layer
@build()
onCastingBegins: (e) -> @show() unless e.preload
onCastingEnds: (e) -> @hide()
toString: -> "<CastingScreen>"
toString: -> '<CastingScreen>'
build: ->
@dimLayer = new createjs.Container()
@dimLayer.mouseEnabled = @dimLayer.mouseChildren = false
@dimLayer.layerIndex = -11
@dimLayer.addChild @dimScreen = new createjs.Shape()
@dimScreen.graphics.beginFill("rgba(0,0,0,0.5)").rect 0, 0, @camera.canvasWidth, @camera.canvasHeight
@dimScreen.graphics.beginFill('rgba(0,0,0,0.5)').rect 0, 0, @camera.canvasWidth, @camera.canvasHeight
@dimLayer.alpha = 0
@layer.addChild @dimLayer
@dimLayer.addChild @makeProgressBar()
@ -34,7 +34,7 @@ module.exports = class CastingScreen extends CocoClass
onWorldLoadProgressChanged: (e) ->
if new Date().getTime() - @t0 > 500
createjs.Tween.removeTweens @progressBar
createjs.Tween.get(@progressBar).to({scaleX:e.progress}, 200)
createjs.Tween.get(@progressBar).to({scaleX: e.progress}, 200)
makeProgressBar: ->
BAR_PIXEL_HEIGHT = 3
@ -44,8 +44,8 @@ module.exports = class CastingScreen extends CocoClass
barY = 3 * (@camera.canvasHeight / 5)
g = new createjs.Graphics()
g.beginFill(createjs.Graphics.getRGB(255,255, 255))
g.drawRoundRect(0,0,pixelWidth, BAR_PIXEL_HEIGHT, 3)
g.beginFill(createjs.Graphics.getRGB(255, 255, 255))
g.drawRoundRect(0, 0, pixelWidth, BAR_PIXEL_HEIGHT, 3)
@progressBar = new createjs.Shape(g)
@progressBar.x = pixelMargin
@progressBar.y = barY
@ -54,7 +54,7 @@ module.exports = class CastingScreen extends CocoClass
makeCastingText: ->
size = @camera.canvasHeight / 15
text = new createjs.Text("Casting", "#{size}px cursive", "#aaaaaa")
text = new createjs.Text('Casting', "#{size}px cursive", '#aaaaaa')
text.regX = text.getMeasuredWidth() / 2
text.regY = text.getMeasuredHeight() / 2
text.x = @camera.canvasWidth / 2
@ -70,7 +70,7 @@ module.exports = class CastingScreen extends CocoClass
@progressBar.scaleX = 0
@dimLayer.alpha = 0
createjs.Tween.removeTweens @dimLayer
createjs.Tween.get(@dimLayer).to({alpha:1}, 500)
createjs.Tween.get(@dimLayer).to({alpha: 1}, 500)
hide: ->
return unless @showing
@ -78,4 +78,4 @@ module.exports = class CastingScreen extends CocoClass
createjs.Tween.removeTweens @progressBar
createjs.Tween.removeTweens @dimLayer
createjs.Tween.get(@dimLayer).to({alpha:0}, 500)
createjs.Tween.get(@dimLayer).to({alpha: 0}, 500)

View file

@ -65,7 +65,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
super()
@options = _.extend($.extend(true, {}, @options), options)
@setThang @options.thang
console.error @toString(), "has no ThangType!" unless @thangType
console.error @toString(), 'has no ThangType!' unless @thangType
# this is a stub, use @setImageObject to swap it out for something else later
@imageObject = new createjs.Container
@ -94,7 +94,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
else
result = @buildSpriteSheet()
if _.isString result # async build
@listenToOnce @thangType, 'build-complete', @setupSprite
@listenToOnce @thangType, 'build-complete', @setupSprite
else
@stillLoading = false
@actions = @thangType.getActions()
@ -171,7 +171,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
onSurfaceTicked: (e) -> @age += e.dt
playNextAction: =>
@playAction(@actionQueue.splice(0,1)[0]) if @actionQueue.length
@playAction(@actionQueue.splice(0, 1)[0]) if @actionQueue.length
playAction: (action) ->
return if @isRaster
@ -180,7 +180,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
@show()
@updateBaseScale()
return @updateActionDirection() unless action.animation or action.container
m = if action.container then "gotoAndStop" else "gotoAndPlay"
m = if action.container then 'gotoAndStop' else 'gotoAndPlay'
@imageObject.framerate = action.framerate or 20
@imageObject[m] action.name
reg = @getOffset 'registration'
@ -235,7 +235,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
@handledDisplayEvents[event] = true
args = JSON.parse(event[4...])
pos = @options.camera.worldToSurface {x:args[0], y:args[1]}
pos = @options.camera.worldToSurface {x: args[0], y: args[1]}
circle = new createjs.Shape()
circle.graphics.beginFill(args[3]).drawCircle(0, 0, args[2]*Camera.PPM)
circle.x = pos.x
@ -270,18 +270,17 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
window.labels.push label
label.alpha = 0
createjs.Tween.get(label)
.to({y:label.y-2, alpha:1}, 200, createjs.Ease.linear)
.to({y:label.y-12}, 1000, createjs.Ease.linear)
.to({y:label.y-22, alpha:0}, 1000, createjs.Ease.linear)
.to({y: label.y-2, alpha: 1}, 200, createjs.Ease.linear)
.to({y: label.y-12}, 1000, createjs.Ease.linear)
.to({y: label.y-22, alpha: 0}, 1000, createjs.Ease.linear)
.call =>
return if @destroyed
@options.floatingLayer.removeChild label
cache: ->
bounds = @imageObject.getBounds()
@imageObject.cache 0, 0, bounds.width, bounds.height
#console.log "just cached", @thang.id, "which was at", @imageObject.x, @imageObject.y, bounds.width, bounds.height, "with scale", Math.max(@imageObject.scaleX, @imageObject.scaleY)
#console.log 'just cached', @thang.id, 'which was at', @imageObject.x, @imageObject.y, bounds.width, bounds.height, 'with scale', Math.max(@imageObject.scaleX, @imageObject.scaleY)
getBobOffset: ->
return 0 unless @thang.bobHeight
@ -351,14 +350,14 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
angle = 180 - angle if angle > 90
scaleX = 0.5 + 0.5 * (90 - angle) / 90
# console.error "No thang for", @ unless @thang
# console.error 'No thang for', @ unless @thang
# TODO: support using scaleFactorX/Y from the thang object
@imageObject.scaleX = @baseScaleX * @scaleFactor * scaleX
@imageObject.scaleY = @baseScaleY * @scaleFactor * scaleY
if @thang and (@thang.scaleFactor or 1) isnt @targetScaleFactor
createjs.Tween.removeTweens(@)
createjs.Tween.get(@).to({scaleFactor:@thang.scaleFactor or 1}, 2000, createjs.Ease.elasticOut)
createjs.Tween.get(@).to({scaleFactor: @thang.scaleFactor or 1}, 2000, createjs.Ease.elasticOut)
@targetScaleFactor = @thang.scaleFactor or 1
updateAlpha: ->
@ -410,7 +409,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
action = @determineAction()
isDifferent = action isnt @currentRootAction or action is null
if not action and @thang?.actionActivated and not @stopLogging
console.error "action is", action, "for", @thang?.id, "from", @currentRootAction, @thang.action, @thang.getActionName?()
console.error 'action is', action, 'for', @thang?.id, 'from', @currentRootAction, @thang.action, @thang.getActionName?()
@stopLogging = true
@queueAction(action) if action and (isDifferent or (@thang?.actionActivated and action.name isnt 'move'))
@updateActionDirection()
@ -439,7 +438,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
rootAction ?= @currentRootAction
return null unless relatedActions = rootAction?.relatedActions ? {}
rotation = @getRotation()
if relatedActions["111111111111"] # has grid-surrounding-wall-based actions
if relatedActions['111111111111'] # has grid-surrounding-wall-based actions
if @wallGrid
action = ''
tileSize = 4
@ -452,25 +451,25 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
wallThangs = ['outside of the map yo']
if wallThangs.length is 0
if y is gy and x is gx
action += "1" # the center wall we're placing
action += '1' # the center wall we're placing
else
action += "0"
action += '0'
else if wallThangs.length is 1
action += "1"
action += '1'
else
console.error "Overlapping walls at", x, y, "...", wallThangs
action += "1"
console.error 'Overlapping walls at', x, y, '...', wallThangs
action += '1'
matchedAction = '111111111111'
for relatedAction of relatedActions
if action.match(relatedAction.replace(/\?/g, '.'))
matchedAction = relatedAction
break
#console.log "returning", matchedAction, "for", @thang.id, "at", gx, gy
#console.log 'returning', matchedAction, 'for', @thang.id, 'at', gx, gy
return relatedActions[matchedAction]
else
keys = _.keys relatedActions
index = Math.max 0, Math.floor((179 + rotation) / 360 * keys.length)
#console.log "Showing", relatedActions[keys[index]]
#console.log 'Showing', relatedActions[keys[index]]
return relatedActions[keys[index]]
value = Math.abs(rotation)
direction = null
@ -510,8 +509,8 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
Backbone.Mediator.publish ourEventName, newEvent
addHealthBar: ->
return unless @thang?.health? and "health" in (@thang?.hudProperties ? []) and @options.floatingLayer
healthColor = healthColors[@thang?.team] ? healthColors["neutral"]
return unless @thang?.health? and 'health' in (@thang?.hudProperties ? []) and @options.floatingLayer
healthColor = healthColors[@thang?.team] ? healthColors['neutral']
healthOffset = @getOffset 'aboveHead'
bar = @healthBar = createProgressBar(healthColor, healthOffset)
bar.name = 'health bar'
@ -660,7 +659,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
sound = e.sound ? AudioPlayer.soundForDialogue e.message, @thangType.get 'soundTriggers'
@instance?.stop()
if @instance = @playSound sound, false
@instance.addEventListener "complete", -> Backbone.Mediator.publish 'dialogue-sound-completed'
@instance.addEventListener 'complete', -> Backbone.Mediator.publish 'dialogue-sound-completed'
@notifySpeechUpdated e
onClearDialogue: (e) ->
@ -714,7 +713,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
delay = if withDelay and sound.delay then 1000 * sound.delay / createjs.Ticker.getFPS() else 0
name = AudioPlayer.nameForSoundReference sound
instance = AudioPlayer.playSound name, volume, delay, @getWorldPosition()
#console.log @thang?.id, "played sound", name, "with delay", delay, "volume", volume, "and got sound instance", instance
#console.log @thang?.id, 'played sound', name, 'with delay', delay, 'volume', volume, 'and got sound instance', instance
instance
onMove: (e) ->
@ -723,7 +722,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
if _.isArray pos
pos = new Vector pos...
else if _.isString pos
return console.warn "Couldn't find target sprite", pos, "from", @options.sprites unless pos of @options.sprites
return console.warn 'Couldn\'t find target sprite', pos, 'from', @options.sprites unless pos of @options.sprites
target = @options.sprites[pos].thang
heading = Vector.subtract(target.pos, @thang.pos).normalize()
distance = @thang.pos.distance target.pos
@ -766,7 +765,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
@lastTween = createjs.Tween
.get(@shadow.pos)
.to({x:pos.x, y:pos.y}, duration, ease)
.to({x: pos.x, y: pos.y}, duration, ease)
.call(endFunc)
pointToward: (pos) ->

View file

@ -11,7 +11,7 @@ module.exports = class CoordinateDisplay extends createjs.Container
super()
@initialize()
@camera = options.camera
console.error "CoordinateDisplay needs camera." unless @camera
console.error 'CoordinateDisplay needs camera.' unless @camera
@build()
@show = _.debounce @show, 125
Backbone.Mediator.subscribe(channel, @[func], @) for channel, func of @subscriptions
@ -24,10 +24,10 @@ module.exports = class CoordinateDisplay extends createjs.Container
build: ->
@mouseEnabled = @mouseChildren = false
@addChild @background = new createjs.Shape()
@addChild @label = new createjs.Text("", "bold 16px Arial", "#FFFFFF")
@addChild @label = new createjs.Text('', 'bold 16px Arial', '#FFFFFF')
@label.name = 'Coordinate Display Text'
@label.shadow = new createjs.Shadow("#000000", 1, 1, 0)
@background.name = "Coordinate Display Background"
@label.shadow = new createjs.Shadow('#000000', 1, 1, 0)
@background.name = 'Coordinate Display Background'
onMouseOver: (e) -> @mouseInBounds = true
onMouseOut: (e) -> @mouseInBounds = false
@ -71,8 +71,8 @@ module.exports = class CoordinateDisplay extends createjs.Container
@label.regY = @background.regY = height / 2 - margin
@background.graphics
.clear()
.beginFill("rgba(0, 0, 0, 0.4)")
.beginStroke("rgba(0, 0, 0, 0.6)")
.beginFill('rgba(0,0,0,0.4)')
.beginStroke('rgba(0,0,0,0.6)')
.setStrokeStyle(1)
.drawRoundRect(0, 0, width, height, radius)
.endFill()

View file

@ -8,7 +8,7 @@ module.exports = class DebugDisplay extends createjs.Container
@initialize()
@canvasWidth = options.canvasWidth
@canvasHeight = options.canvasHeight
console.error "DebugDisplay needs canvasWidth/Height." unless @canvasWidth and @canvasHeight
console.error 'DebugDisplay needs canvasWidth/Height.' unless @canvasWidth and @canvasHeight
@build()
@onSetDebug debug: true
Backbone.Mediator.subscribe(channel, @[func], @) for channel, func of @subscriptions
@ -25,7 +25,7 @@ module.exports = class DebugDisplay extends createjs.Container
build: ->
@mouseEnabled = @mouseChildren = false
@addChild @frameText = new createjs.Text "...", "20px Arial", "#FFF"
@addChild @frameText = new createjs.Text '...', '20px Arial', '#FFF'
@frameText.name = 'frame text'
@frameText.x = @canvasWidth - 50
@frameText.y = @canvasHeight - 25
@ -41,5 +41,5 @@ module.exports = class DebugDisplay extends createjs.Container
@lastFrameSecondStart = time
@framesRenderedThisSecond = 0
@frameText.text = Math.round(currentFrame) + (if @fps? then " - " + @fps + ' fps' else '')
@frameText.text = Math.round(currentFrame) + (if @fps? then ' - ' + @fps + ' fps' else '')
@frameText.x = @canvasWidth - @frameText.getMeasuredWidth() - 10

View file

@ -14,14 +14,14 @@ module.exports = class Dimmer extends CocoClass
options ?= {}
@camera = options.camera
@layer = options.layer
console.error @toString(), "needs a camera." unless @camera
console.error @toString(), "needs a layer." unless @layer
console.error @toString(), 'needs a camera.' unless @camera
console.error @toString(), 'needs a layer.' unless @layer
@build()
@updateDimMask = _.throttle @updateDimMask, 10
@highlightedThangIDs = []
@sprites = {}
toString: -> "<Dimmer>"
toString: -> '<Dimmer>'
build: ->
@dimLayer = new createjs.Container()
@ -29,7 +29,7 @@ module.exports = class Dimmer extends CocoClass
@dimLayer.layerIndex = -10
@dimLayer.addChild @dimScreen = new createjs.Shape()
@dimLayer.addChild @dimMask = new createjs.Shape()
@dimScreen.graphics.beginFill("rgba(0,0,0,0.5)").rect 0, 0, @camera.canvasWidth, @camera.canvasHeight
@dimScreen.graphics.beginFill('rgba(0,0,0,0.5)').rect 0, 0, @camera.canvasWidth, @camera.canvasHeight
@dimMask.compositeOperation = 'destination-out'
@dimLayer.cache 0, 0, @camera.canvasWidth, @camera.canvasHeight
@ -70,6 +70,6 @@ module.exports = class Dimmer extends CocoClass
sup = x: sprite.imageObject.x, y: sprite.imageObject.y
cap = @camera.surfaceToCanvas sup
r = 50 * @camera.zoom # TODO: find better way to get the radius based on the sprite's size
@dimMask.graphics.beginRadialGradientFill(["rgba(0,0,0,1)", "rgba(0,0,0,0)"], [0.5, 1], cap.x, cap.y, 0, cap.x, cap.y, r).drawCircle(cap.x, cap.y, r)
@dimMask.graphics.beginRadialGradientFill(['rgba(0,0,0,1)', 'rgba(0,0,0,0)'], [0.5, 1], cap.x, cap.y, 0, cap.x, cap.y, r).drawCircle(cap.x, cap.y, r)
@dimLayer.updateCache 0, 0, @camera.canvasWidth, @camera.canvasHeight

View file

@ -25,5 +25,4 @@ Dropper = class Dropper
drop: ->
return @drop_counter > 0
module.exports = new Dropper()

View file

@ -1,9 +1,9 @@
CocoClass = require 'lib/CocoClass'
module.exports = class Label extends CocoClass
@STYLE_DIALOGUE = "dialogue" # A speech bubble from a script
@STYLE_SAY = "say" # A piece of text generated from the world
@STYLE_NAME = "name" # A name like Scott set up for the Wizard
@STYLE_DIALOGUE = 'dialogue' # A speech bubble from a script
@STYLE_SAY = 'say' # A piece of text generated from the world
@STYLE_NAME = 'name' # A name like Scott set up for the Wizard
# We might want to combine 'say' and 'name'; they're very similar
# Nick designed 'say' based off of Scott's 'name' back when they were using two systems
@ -16,9 +16,9 @@ module.exports = class Label extends CocoClass
@camera = options.camera
@layer = options.layer
@style = options.style ? Label.STYLE_SAY
console.error @toString(), "needs a sprite." unless @sprite
console.error @toString(), "needs a camera." unless @camera
console.error @toString(), "needs a layer." unless @layer
console.error @toString(), 'needs a sprite.' unless @sprite
console.error @toString(), 'needs a camera.' unless @camera
console.error @toString(), 'needs a layer.' unless @layer
@setText options.text if options.text
destroy: ->
@ -58,15 +58,15 @@ module.exports = class Label extends CocoClass
st = {dialogue: 'D', say: 'S', name: 'N'}[@style]
o.marginX = {D: 5, S: 6, N: 3}[st]
o.marginY = {D: 6, S: 4, N: 3}[st]
o.fontWeight = {D: "bold", S: "bold", N: "bold"}[st]
o.fontWeight = {D: 'bold', S: 'bold', N: 'bold'}[st]
o.shadow = {D: false, S: true, N: true}[st]
o.shadowColor = {D: "#FFF", S: "#000", N: "#FFF"}[st]
o.shadowColor = {D: '#FFF', S: '#000', N: '#FFF'}[st]
o.fontSize = {D: 25, S: 12, N: 12}[st]
fontFamily = {D: "Arial", S: "Arial", N: "Arial"}[st]
fontFamily = {D: 'Arial', S: 'Arial', N: 'Arial'}[st]
o.fontDescriptor = "#{o.fontWeight} #{o.fontSize}px #{fontFamily}"
o.fontColor = {D: "#000", S: "#FFF", N: "#00a"}[st]
o.backgroundFillColor = {D: "white", S: "rgba(0, 0, 0, 0.4)", N: "rgba(255, 255, 255, 0.5)"}[st]
o.backgroundStrokeColor = {D: "black", S: "rgba(0, 0, 0, .6)", N: "rgba(0, 0, 0, 0.0)"}[st]
o.fontColor = {D: '#000', S: '#FFF', N: '#00a'}[st]
o.backgroundFillColor = {D: 'white', S: 'rgba(0,0,0,0.4)', N: 'rgba(255,255,255,0.5)'}[st]
o.backgroundStrokeColor = {D: 'black', S: 'rgba(0,0,0,0.6)', N: 'rgba(0,0,0,0)'}[st]
o.backgroundStrokeStyle = {D: 2, S: 1, N: 1}[st]
o.backgroundBorderRadius = {D: 10, S: 3, N: 3}[st]
o.layerPriority = {D: 10, S: 5, N: 5}[st]
@ -169,7 +169,7 @@ module.exports = class Label extends CocoClass
textWidth = 0
for word in words
row.push(word)
text = new createjs.Text(_.string.join(' ', row...), fontDescriptor, "#000")
text = new createjs.Text(_.string.join(' ', row...), fontDescriptor, '#000')
width = text.getMeasuredWidth()
if width > maxWidth
if row.length is 1 # one long word, truncate it
@ -186,5 +186,5 @@ module.exports = class Label extends CocoClass
textWidth = Math.max(textWidth, width)
rows.push(row) if row.length
for row, i in rows
rows[i] = _.string.join(" ", row...)
rows[i] = _.string.join(' ', row...)
text: _.string.join("\n", rows...), textWidth: textWidth

View file

@ -18,10 +18,10 @@
###
module.exports = class Layer extends createjs.Container
@TRANSFORM_CHILD = "child" # Layer transform is managed by its parents
@TRANSFORM_SURFACE = "surface" # Layer moves/scales/zooms with the Surface of the World
@TRANSFORM_SURFACE_TEXT = "surface_text" # Layer moves with the Surface but is size-independent
@TRANSFORM_SCREEN = "screen" # Layer stays fixed to the screen (different from child?)
@TRANSFORM_CHILD = 'child' # Layer transform is managed by its parents
@TRANSFORM_SURFACE = 'surface' # Layer moves/scales/zooms with the Surface of the World
@TRANSFORM_SURFACE_TEXT = 'surface_text' # Layer moves with the Surface but is size-independent
@TRANSFORM_SCREEN = 'screen' # Layer stays fixed to the screen (different from child?)
subscriptions:
'camera:zoom-updated': 'onZoomUpdated'
@ -30,11 +30,11 @@ module.exports = class Layer extends createjs.Container
super()
@initialize()
options ?= {}
@name = options.name ? "Unnamed"
@name = options.name ? 'Unnamed'
@layerPriority = options.layerPriority ? 0
@transformStyle = options.transform ? Layer.TRANSFORM_CHILD
@camera = options.camera
console.error @toString(), "needs a camera." unless @camera
console.error @toString(), 'needs a camera.' unless @camera
@updateLayerOrder = _.throttle @updateLayerOrder, 1000 / 30 # Don't call multiple times in one frame; 30 FPS is probably good enough
Backbone.Mediator.subscribe(channel, @[func], @) for channel, func of @subscriptions
@ -60,7 +60,7 @@ module.exports = class Layer extends createjs.Container
child.scaleY *= @scaleY
updateLayerOrder: =>
#console.log @, @toString(), "sorting children", _.clone @children if @name is 'Default'
#console.log @, @toString(), 'sorting children', _.clone @children if @name is 'Default'
@sortChildren @layerOrderComparator
layerOrderComparator: (a, b) ->

View file

@ -1,5 +1,4 @@
module.exports = class Letterbox extends createjs.Container
subscriptions:
'level-set-letterbox': 'onSetLetterbox'
@ -8,7 +7,7 @@ module.exports = class Letterbox extends createjs.Container
@initialize()
@canvasWidth = options.canvasWidth
@canvasHeight = options.canvasHeight
console.error "Letterbox needs canvasWidth/Height." unless @canvasWidth and @canvasHeight
console.error 'Letterbox needs canvasWidth/Height.' unless @canvasWidth and @canvasHeight
@build()
Backbone.Mediator.subscribe(channel, @[func], @) for channel, func of @subscriptions
@ -16,7 +15,7 @@ module.exports = class Letterbox extends createjs.Container
@mouseEnabled = @mouseChildren = false
@matteHeight = 0.10 * @canvasHeight
@upperMatte = new createjs.Shape()
@upperMatte.graphics.beginFill("black").rect(0, 0, @canvasWidth, @matteHeight)
@upperMatte.graphics.beginFill('black').rect(0, 0, @canvasWidth, @matteHeight)
@lowerMatte = @upperMatte.clone()
@upperMatte.x = @lowerMatte.x = 0
@upperMatte.y = -@matteHeight

View file

@ -15,9 +15,9 @@ module.exports = class Mark extends CocoClass
@camera = options.camera
@layer = options.layer
@thangType = options.thangType
console.error @toString(), "needs a name." unless @name
console.error @toString(), "needs a camera." unless @camera
console.error @toString(), "needs a layer." unless @layer
console.error @toString(), 'needs a name.' unless @name
console.error @toString(), 'needs a camera.' unless @camera
console.error @toString(), 'needs a layer.' unless @layer
@build()
destroy: ->
@ -58,7 +58,7 @@ module.exports = class Mark extends CocoClass
else if @name is 'debug' then @buildDebug()
else if @name.match(/.+(Range|Distance|Radius)$/) then @buildRadius(@name)
else if @thangType then @buildSprite()
else console.error "Don't know how to build mark for", @name
else console.error 'Don\'t know how to build mark for', @name
@mark?.mouseEnabled = false
@
@ -77,7 +77,7 @@ module.exports = class Mark extends CocoClass
shape.graphics.setStrokeStyle 5
shape.graphics.beginStroke color
shape.graphics.beginFill color.replace('0.5', '0.25')
if @sprite.thang.shape in ["ellipsoid", "disc"]
if @sprite.thang.shape in ['ellipsoid', 'disc']
shape.drawEllipse 0, 0, w, h
else
shape.graphics.drawRect -w / 2, -h / 2, w, h
@ -86,20 +86,20 @@ module.exports = class Mark extends CocoClass
@mark.addChild shape
if @sprite.thang.drawsBoundsStyle is 'border-text'
text = new createjs.Text "" + @drawsBoundsIndex, "20px Arial", color.replace('0.5', '1')
text = new createjs.Text '' + @drawsBoundsIndex, '20px Arial', color.replace('0.5', '1')
text.regX = text.getMeasuredWidth() / 2
text.regY = text.getMeasuredHeight() / 2
text.shadow = new createjs.Shadow("#000000", 1, 1, 0)
text.shadow = new createjs.Shadow('#000000', 1, 1, 0)
@mark.addChild text
else if @sprite.thang.drawsBoundsStyle is 'corner-text'
return if @sprite.thang.world.age is 0
letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[@drawsBoundsIndex % 26]
text = new createjs.Text letter, "14px Arial", "#333333" # color.replace('0.5', '1')
letter = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[@drawsBoundsIndex % 26]
text = new createjs.Text letter, '14px Arial', '#333333' # color.replace('0.5', '1')
text.x = -w / 2 + 2
text.y = -h / 2 + 2
@mark.addChild text
else
console.warn @sprite.thang.id, "didn't know how to draw bounds style:", @sprite.thang.drawsBoundsStyle
console.warn @sprite.thang.id, 'didn\'t know how to draw bounds style:', @sprite.thang.drawsBoundsStyle
if w > 0 and h > 0
@mark.cache -w / 2, -h / 2, w, h, 2
@ -118,7 +118,7 @@ module.exports = class Mark extends CocoClass
height *= Camera.PPM * @camera.y2x # TODO: doesn't work with rotation
@mark = new createjs.Shape()
@mark.mouseEnabled = false
@mark.graphics.beginFill "rgba(0, 0, 0, #{alpha})"
@mark.graphics.beginFill "rgba(0,0,0,#{alpha})"
if @sprite.thang.shape in ['ellipsoid', 'disc']
@mark.graphics.drawEllipse 0, 0, width, height
else
@ -132,16 +132,16 @@ module.exports = class Mark extends CocoClass
buildRadius: (range) ->
alpha = 0.15
colors =
voiceRange: "rgba(0, 145, 0, #{alpha})"
visualRange: "rgba(0, 0, 145, #{alpha})"
attackRange: "rgba(145, 0, 0, #{alpha})"
voiceRange: "rgba(0,145,0,#{alpha})"
visualRange: "rgba(0,0,145,#{alpha})"
attackRange: "rgba(145,0,0,#{alpha})"
# Fallback colors which work on both dungeon and grass tiles
extraColors = [
"rgba(145, 0, 145, #{alpha})"
"rgba(0, 145, 145, #{alpha})"
"rgba(145, 105, 0, #{alpha})"
"rgba(225, 125, 0, #{alpha})"
"rgba(145,0,145,#{alpha})"
"rgba(0,145,145,#{alpha})"
"rgba(145,105,0,#{alpha})"
"rgba(225,125,0,#{alpha})"
]
# Find the index of this range, to find the next-smallest radius
@ -179,7 +179,7 @@ module.exports = class Mark extends CocoClass
[w, h] = [Math.max(PX, @sprite.thang.width * Camera.PPM), Math.max(PX, @sprite.thang.height * Camera.PPM) * @camera.y2x]
@mark.alpha = 0.5
@mark.graphics.beginFill '#abcdef'
if @sprite.thang.shape in ["ellipsoid", "disc"]
if @sprite.thang.shape in ['ellipsoid', 'disc']
[w, h] = [Math.max(PX, w, h), Math.max(PX, w, h)]
@mark.graphics.drawCircle 0, 0, w / 2
else
@ -248,11 +248,11 @@ module.exports = class Mark extends CocoClass
if @name is 'shadow'
worldZ = @sprite.thang.pos.z - @sprite.thang.depth / 2 + @sprite.getBobOffset()
@mark.alpha = @alpha * 0.451 / Math.sqrt(worldZ / 2 + 1)
else if @name isnt "bounds"
else if @name isnt 'bounds'
@mark.alpha = @alpha
updateRotation: ->
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
updateScale: ->
@ -271,7 +271,7 @@ module.exports = class Mark extends CocoClass
@mark.scaleX = thang.scaleFactor ? thang.scaleFactorX ? 1
@mark.scaleY = thang.scaleFactor ? thang.scaleFactorY ? 1
return unless @name in ["selection", "target", "repair", "highlight"]
return unless @name in ['selection', 'target', 'repair', 'highlight']
# scale these marks to 10m (100px). Adjust based on sprite size.
factor = 0.3 # default size: 3m width, most commonly for target when pointing to a location

View file

@ -25,7 +25,7 @@ module.exports = class MusicPlayer extends CocoClass
if (not e.file) or src is @currentMusic?.src
if e.play then @restartCurrentMusic() else @fadeOutCurrentMusic()
return
media = AudioPlayer.getStatus(src)
if not media?.loaded
AudioPlayer.preloadSound(src)
@ -35,23 +35,23 @@ module.exports = class MusicPlayer extends CocoClass
@standingBy = null
@fadeOutCurrentMusic()
@startNewMusic(src) if e.play
restartCurrentMusic: ->
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)
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
@currentMusic.volume = 0.0
if me.get('music')
createjs.Tween.get(@currentMusic).to({volume:1.0}, CROSSFADE_LENGTH)
createjs.Tween.get(@currentMusic).to({volume: 1.0}, CROSSFADE_LENGTH)
onMusicSettingChanged: ->
@updateMusicVolume()
@ -64,4 +64,3 @@ module.exports = class MusicPlayer extends CocoClass
destroy: ->
me.off 'change:music', @onMusicSettingChanged, @
super()

View file

@ -6,18 +6,18 @@ module.exports = class PlaybackOverScreen extends CocoClass
options ?= {}
@camera = options.camera
@layer = options.layer
console.error @toString(), "needs a camera." unless @camera
console.error @toString(), "needs a layer." unless @layer
console.error @toString(), 'needs a camera.' unless @camera
console.error @toString(), 'needs a layer.' unless @layer
@build()
toString: -> "<PlaybackOverScreen>"
toString: -> '<PlaybackOverScreen>'
build: ->
@dimLayer = new createjs.Container()
@dimLayer.mouseEnabled = @dimLayer.mouseChildren = false
@dimLayer.layerIndex = -12
@dimLayer.addChild @dimScreen = new createjs.Shape()
@dimScreen.graphics.beginFill("rgba(0,0,0,0.4)").rect 0, 0, @camera.canvasWidth, @camera.canvasHeight
@dimScreen.graphics.beginFill('rgba(0,0,0,0.4)').rect 0, 0, @camera.canvasWidth, @camera.canvasHeight
@dimLayer.cache 0, 0, @camera.canvasWidth, @camera.canvasHeight
@dimLayer.alpha = 0
@layer.addChild @dimLayer
@ -28,11 +28,11 @@ module.exports = class PlaybackOverScreen extends CocoClass
@dimLayer.alpha = 0
createjs.Tween.removeTweens @dimLayer
createjs.Tween.get(@dimLayer).to({alpha:1}, 500)
createjs.Tween.get(@dimLayer).to({alpha: 1}, 500)
hide: ->
return unless @showing
@showing = false
createjs.Tween.removeTweens @dimLayer
createjs.Tween.get(@dimLayer).to({alpha:0}, 500)
createjs.Tween.get(@dimLayer).to({alpha: 0}, 500)

View file

@ -19,12 +19,12 @@ module.exports = class PointChooser extends CocoClass
@shape = new createjs.Shape()
@shape.alpha = 0.9
@shape.mouseEnabled = false
@shape.graphics.setStrokeStyle(1, "round").beginStroke("#000000").beginFill('#fedcba')
@shape.graphics.setStrokeStyle(1, 'round').beginStroke('#000000').beginFill('#fedcba')
@shape.graphics.drawCircle(0, 0, 4).endFill()
@shape.layerIndex = 100
onMouseDown: (e) =>
console.log "got stagemousedown", e, key.shift
console.log 'got stagemousedown', e, key.shift
return unless key.shift
@setPoint @options.camera.screenToWorld {x: e.stageX, y: e.stageY}
Backbone.Mediator.publish 'choose-point', point: @point

View file

@ -51,12 +51,12 @@ module.exports = class SpriteBoss extends CocoClass
createLayers: ->
@spriteLayers = {}
for [name, priority] in [
["Land", -40]
["Ground", -30]
["Obstacle", -20]
["Path", -10]
["Default", 0]
["Floating", 10]
['Land', -40]
['Ground', -30]
['Obstacle', -20]
['Path', -10]
['Default', 0]
['Floating', 10]
]
@spriteLayers[name] = new Layer name: name, layerPriority: priority, transform: Layer.TRANSFORM_CHILD, camera: @camera
@surfaceLayer.addChild _.values(@spriteLayers)...
@ -66,36 +66,36 @@ module.exports = class SpriteBoss extends CocoClass
# TODO: make better system
child.layerPriority = 0 if sprite?.thang?.isSelectable
child.layerPriority = -40 if sprite?.thang?.isLand
return @spriteLayers["Default"] unless child.layerPriority
return @spriteLayers['Default'] unless child.layerPriority
layer = _.findLast @spriteLayers, (layer, name) ->
layer.layerPriority <= child.layerPriority
#console.log "layer for", child, "is", (layer ? @spriteLayers["Default"])
layer ? @spriteLayers["Default"]
#console.log 'layer for', child, 'is', (layer ? @spriteLayers['Default'])
layer ? @spriteLayers['Default']
addSprite: (sprite, id=null, layer=null) ->
id ?= sprite.thang.id
console.error "Sprite collision! Already have:", id if @sprites[id]
console.error 'Sprite collision! Already have:', id if @sprites[id]
@sprites[id] = sprite
@spriteArray.push sprite
layer ?= @spriteLayers["Obstacle"] if sprite.thang?.spriteName.search(/(dungeon|indoor).wall/i) isnt -1
layer ?= @spriteLayers['Obstacle'] if sprite.thang?.spriteName.search(/(dungeon|indoor).wall/i) isnt -1
layer ?= @layerForChild sprite.imageObject, sprite
layer.addChild sprite.imageObject
layer.updateLayerOrder()
sprite
createMarks: ->
@targetMark = new Mark name: 'target', camera: @camera, layer: @spriteLayers["Ground"], thangType: 'target'
@selectionMark = new Mark name: 'selection', camera: @camera, layer: @spriteLayers["Ground"], thangType: 'selection'
@targetMark = new Mark name: 'target', camera: @camera, layer: @spriteLayers['Ground'], thangType: 'target'
@selectionMark = new Mark name: 'selection', camera: @camera, layer: @spriteLayers['Ground'], thangType: 'selection'
createSpriteOptions: (options) ->
_.extend options, camera: @camera, resolutionFactor: 4, groundLayer: @spriteLayers["Ground"], textLayer: @surfaceTextLayer, floatingLayer: @spriteLayers["Floating"], spriteSheetCache: @spriteSheetCache, showInvisible: @options.showInvisible
_.extend options, camera: @camera, resolutionFactor: 4, groundLayer: @spriteLayers['Ground'], textLayer: @surfaceTextLayer, floatingLayer: @spriteLayers['Floating'], spriteSheetCache: @spriteSheetCache, showInvisible: @options.showInvisible
createIndieSprites: (indieSprites, withWizards) ->
unless @indieSprites
@indieSprites = []
@indieSprites = (@createIndieSprite indieSprite for indieSprite in indieSprites) if indieSprites
if withWizards and not @selfWizardSprite
@selfWizardSprite = @createWizardSprite thangID: "My Wizard", isSelf: true, sprites: @sprites
@selfWizardSprite = @createWizardSprite thangID: 'My Wizard', isSelf: true, sprites: @sprites
createIndieSprite: (indieSprite) ->
unless thangType = @thangTypeFor indieSprite.thangType
@ -107,16 +107,16 @@ module.exports = class SpriteBoss extends CocoClass
createOpponentWizard: (opponent) ->
# TODO: colorize name and cloud by team, colorize wizard by user's color config, level-specific wizard spawn points
sprite = @createWizardSprite thangID: opponent.id, name: opponent.name
if not opponent.levelSlug or opponent.levelSlug is "brawlwood"
if not opponent.levelSlug or opponent.levelSlug is 'brawlwood'
sprite.targetPos = if opponent.team is 'ogres' then {x: 52, y: 52} else {x: 28, y: 28}
else if opponent.levelSlug is "dungeon-arena"
sprite.targetPos = if opponent.team is 'ogres' then {x:72, y: 39} else {x: 9, y:39}
else if opponent.levelSlug is 'dungeon-arena'
sprite.targetPos = if opponent.team is 'ogres' then {x: 72, y: 39} else {x: 9, y: 39}
else
sprite.targetPos = if opponent.team is 'ogres' then {x:52, y: 28} else {x: 20, y:28}
sprite.targetPos = if opponent.team is 'ogres' then {x: 52, y: 28} else {x: 20, y: 28}
createWizardSprite: (options) ->
sprite = new WizardSprite @thangTypeFor("Wizard"), @createSpriteOptions(options)
@addSprite sprite, sprite.thang.id, @spriteLayers["Floating"]
sprite = new WizardSprite @thangTypeFor('Wizard'), @createSpriteOptions(options)
@addSprite sprite, sprite.thang.id, @spriteLayers['Floating']
onPlayerJoined: (e) ->
# Create another WizardSprite, unless this player is just me
@ -172,7 +172,7 @@ module.exports = class SpriteBoss extends CocoClass
@adjustSpriteExistence() if frameChanged
sprite.update frameChanged for sprite in @spriteArray
@updateSelection()
@spriteLayers["Default"].updateLayerOrder()
@spriteLayers['Default'].updateLayerOrder()
@cache()
adjustSpriteExistence: ->
@ -184,11 +184,11 @@ module.exports = class SpriteBoss extends CocoClass
else
sprite = @addThangToSprites(thang)
Backbone.Mediator.publish 'surface:new-thang-added', thang:thang, sprite:sprite
updateCache = updateCache or sprite.imageObject.parent is @spriteLayers["Obstacle"]
updateCache = updateCache or sprite.imageObject.parent is @spriteLayers['Obstacle']
sprite.playSounds()
for thangID, sprite of @sprites
missing = not (sprite.notOfThisWorld or @world.thangMap[thangID]?.exists)
isObstacle = sprite.imageObject.parent is @spriteLayers["Obstacle"]
isObstacle = sprite.imageObject.parent is @spriteLayers['Obstacle']
updateCache = updateCache or (isObstacle and (missing or sprite.hasMoved))
sprite.hasMoved = false
@removeSprite sprite if missing
@ -210,11 +210,11 @@ module.exports = class SpriteBoss extends CocoClass
wallSprite.updateScale()
wallSprite.updatePosition()
#console.log @wallGrid.toString()
@spriteLayers["Obstacle"].uncache() if @spriteLayers["Obstacle"].cacheID # might have changed sizes
@spriteLayers["Obstacle"].cache()
@spriteLayers['Obstacle'].uncache() if @spriteLayers['Obstacle'].cacheID # might have changed sizes
@spriteLayers['Obstacle'].cache()
# test performance of doing land layer, too, to see if it's faster
# @spriteLayers["Land"].uncache() if @spriteLayers["Land"].cacheID # might have changed sizes
# @spriteLayers["Land"].cache()
# @spriteLayers['Land'].uncache() if @spriteLayers['Land'].cacheID # might have changed sizes
# @spriteLayers['Land'].cache()
# I don't notice much difference - Scott
@cached = true
@ -291,7 +291,6 @@ module.exports = class SpriteBoss extends CocoClass
instance.addEventListener 'complete', ->
Backbone.Mediator.publish 'thang-finished-talking', thang: sprite?.thang
# Marks
updateSelection: ->

View file

@ -90,7 +90,7 @@ module.exports = Surface = class Surface extends CocoClass
destroy: ->
@dead = true
@camera?.destroy()
createjs.Ticker.removeEventListener("tick", @tick)
createjs.Ticker.removeEventListener('tick', @tick)
createjs.Sound.stop()
layer.destroy() for layer in @layers
@spriteBoss.destroy()
@ -160,12 +160,12 @@ module.exports = Surface = class Surface extends CocoClass
addMeshRectanglesToContainer: (mesh, container) ->
for rect in mesh
shape = new createjs.Shape()
pos = @camera.worldToSurface {x:rect.x, y:rect.y}
dim = @camera.worldToSurface {x:rect.width, y:rect.height}
pos = @camera.worldToSurface {x: rect.x, y: rect.y}
dim = @camera.worldToSurface {x: rect.width, y: rect.height}
shape.graphics
.setStrokeStyle(3)
.beginFill('rgba(0, 0, 128, 0.3)')
.beginStroke('rgba(0, 0, 128, 0.7)')
.beginFill('rgba(0,0,128,0.3)')
.beginStroke('rgba(0,0,128,0.7)')
.drawRect(pos.x - dim.x/2, pos.y - dim.y/2, dim.x, dim.y)
container.addChild shape
@ -181,7 +181,7 @@ module.exports = Surface = class Surface extends CocoClass
shape.graphics
.setStrokeStyle(1)
.moveTo(v1.x, v1.y)
.beginStroke('rgba(128, 0, 0, 0.4)')
.beginStroke('rgba(128,0,0,0.4)')
.lineTo(v2.x, v2.y)
.endStroke()
container.addChild shape
@ -206,7 +206,7 @@ module.exports = Surface = class Surface extends CocoClass
if scrubDuration
t = createjs.Tween
.get(@)
.to({currentFrame:@scrubbingTo}, scrubDuration, createjs.Ease.sineInOut)
.to({currentFrame: @scrubbingTo}, scrubDuration, createjs.Ease.sineInOut)
.call(onTweenEnd)
t.addEventListener('change', @onFramesScrubbed)
else
@ -309,7 +309,7 @@ module.exports = Surface = class Surface extends CocoClass
return if @currentFrame is @lastFrame and not force
progress = @getProgress()
Backbone.Mediator.publish('surface:frame-changed',
type: "frame-changed"
type: 'frame-changed'
selectedThang: @spriteBoss.selectedSprite?.thang
progress: progress
frame: @currentFrame
@ -353,7 +353,7 @@ module.exports = Surface = class Surface extends CocoClass
@setPaused false if @ended
@casting = true
@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?
@ -361,7 +361,7 @@ module.exports = Surface = class Surface extends CocoClass
@coordinateDisplay.destroy()
createjs.Tween.removeTweens(@surfaceLayer)
createjs.Tween.get(@surfaceLayer).to({alpha:0.9}, 1000, createjs.Ease.getPowOut(4.0))
createjs.Tween.get(@surfaceLayer).to({alpha: 0.9}, 1000, createjs.Ease.getPowOut(4.0))
onNewWorld: (event) ->
return unless event.world.name is @world.name
@ -373,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
# so only run it after the first world is created.
Backbone.Mediator.publish 'level-set-playing', { playing: @wasPlayingWhenCastingBegan } unless event.firstWorld or @setPlayingCalled
Backbone.Mediator.publish 'level-set-playing', {playing: @wasPlayingWhenCastingBegan} unless event.firstWorld or @setPlayingCalled
fastForwardTo = null
if @playing
@ -391,9 +391,9 @@ module.exports = Surface = class Surface extends CocoClass
@setProgress fastForwardToRatio, 1000 * fastForwardToTime / fastForwardSpeed
@fastForwarding = true
createjs.Tween.get(@surfaceLayer)
.to({alpha:0.0}, 50)
.to({alpha: 0.0}, 50)
.call(f)
.to({alpha:1.0}, 2000, createjs.Ease.getPowOut(2.0))
.to({alpha: 1.0}, 2000, createjs.Ease.getPowOut(2.0))
# initialization
@ -405,9 +405,9 @@ module.exports = Surface = class Surface extends CocoClass
@camera?.destroy()
@camera = new Camera @canvas
AudioPlayer.camera = @camera
@layers.push @surfaceLayer = new Layer name: "Surface", layerPriority: 0, transform: Layer.TRANSFORM_SURFACE, camera: @camera
@layers.push @surfaceTextLayer = new Layer name: "Surface Text", layerPriority: 1, transform: Layer.TRANSFORM_SURFACE_TEXT, camera: @camera
@layers.push @screenLayer = new Layer name: "Screen", layerPriority: 2, transform: Layer.TRANSFORM_SCREEN, camera: @camera
@layers.push @surfaceLayer = new Layer name: 'Surface', layerPriority: 0, transform: Layer.TRANSFORM_SURFACE, camera: @camera
@layers.push @surfaceTextLayer = new Layer name: 'Surface Text', layerPriority: 1, transform: Layer.TRANSFORM_SURFACE_TEXT, camera: @camera
@layers.push @screenLayer = new Layer name: 'Screen', layerPriority: 2, transform: Layer.TRANSFORM_SCREEN, camera: @camera
@stage.addChild @layers...
@surfaceLayer.addChild @cameraBorder = new CameraBorder bounds: @camera.bounds
@screenLayer.addChild new Letterbox canvasWidth: canvasWidth, canvasHeight: canvasHeight
@ -449,7 +449,7 @@ module.exports = Surface = class Surface extends CocoClass
@updateState true
@drawCurrentFrame()
@showGrid() if @options.grid # TODO: pay attention to world grid setting (which we only know when world simulates)
createjs.Ticker.addEventListener "tick", @tick
createjs.Ticker.addEventListener 'tick', @tick
Backbone.Mediator.publish 'level:started'
createOpponentWizard: (opponent) ->
@ -469,10 +469,10 @@ module.exports = Surface = class Surface extends CocoClass
@gridLayer.z = 90019001
@gridLayer.mouseEnabled = false
@gridShape.alpha = 0.125
@gridShape.graphics.beginStroke "blue"
@gridShape.graphics.beginStroke 'blue'
gridSize = Math.round(@world.size()[0] / 20)
unless gridSize > 0.1
return console.error "Grid size is", gridSize, "so we can't draw a grid."
return console.error 'Grid size is', gridSize, 'so we can\'t draw a grid.'
wopStart = x: 0, y: 0
wopEnd = x: @world.size()[0], y: @world.size()[1]
supStart = @camera.worldToSurface wopStart
@ -481,7 +481,7 @@ module.exports = Surface = class Surface extends CocoClass
while wop.x < wopEnd.x
sup = @camera.worldToSurface wop
@gridShape.graphics.mt(sup.x, supStart.y).lt(sup.x, supEnd.y)
t = new createjs.Text(wop.x.toFixed(0), "16px Arial", "blue")
t = new createjs.Text(wop.x.toFixed(0), '16px Arial', 'blue')
t.x = sup.x - t.getMeasuredWidth() / 2
t.y = supStart.y - 10 - t.getMeasuredHeight() / 2
t.alpha = 0.75
@ -490,7 +490,7 @@ module.exports = Surface = class Surface extends CocoClass
while wop.y < wopEnd.y
sup = @camera.worldToSurface wop
@gridShape.graphics.mt(supStart.x, sup.y).lt(supEnd.x, sup.y)
t = new createjs.Text(wop.y.toFixed(0), "16px Arial", "blue")
t = new createjs.Text(wop.y.toFixed(0), '16px Arial', 'blue')
t.x = 10 - t.getMeasuredWidth() / 2
t.y = sup.y - t.getMeasuredHeight() / 2
t.alpha = 0.75
@ -596,7 +596,7 @@ module.exports = Surface = class Surface extends CocoClass
Backbone.Mediator.publish('surface:ticked', {dt: 1 / @options.frameRate})
mib = @stage.mouseInBounds
if @mouseInBounds isnt mib
Backbone.Mediator.publish('surface:mouse-' + (if mib then "over" else "out"), {})
Backbone.Mediator.publish('surface:mouse-' + (if mib then 'over' else 'out'), {})
@mouseInBounds = mib
restoreWorldState: ->
@ -631,10 +631,10 @@ module.exports = Surface = class Surface extends CocoClass
return if @world.showPaths is 'paused' and @playing
return if @world.showPaths is 'selected' and not selectedThang
@trailmaster ?= new path.Trailmaster @camera
selectedOnly = @playing and @world.showPaths is "selected"
selectedOnly = @playing and @world.showPaths is 'selected'
@paths = @trailmaster.generatePaths @world, @getCurrentFrame(), selectedThang, @spriteBoss.sprites, selectedOnly
@paths.name = 'paths'
@spriteBoss.spriteLayers["Path"].addChild @paths
@spriteBoss.spriteLayers['Path'].addChild @paths
hidePaths: ->
return if not @paths
@ -647,8 +647,8 @@ module.exports = Surface = class Surface extends CocoClass
margin = (1 - 1 / zoom) / 2
@stage.cache margin * w, margin * h, w / zoom, h / zoom, scale * zoom
imageData = @stage.cacheCanvas.toDataURL(format, quality)
#console.log "Screenshot with scale", scale, "format", format, "quality", quality, "was", Math.floor(imageData.length / 1024), "kB"
screenshot = document.createElement("img")
#console.log 'Screenshot with scale', scale, 'format', format, 'quality', quality, 'was', Math.floor(imageData.length / 1024), 'kB'
screenshot = document.createElement('img')
screenshot.src = imageData
@stage.uncache()
imageData

View file

@ -63,7 +63,7 @@ module.exports = class WizardSprite extends IndieSprite
continue unless state.wizard?
@setColorHue state.wizard.wizardColor1
if targetID = state.wizard.targetSprite
return console.warn "Wizard Sprite couldn't find target sprite", targetID unless targetID of @options.sprites
return console.warn 'Wizard Sprite couldn\'t find target sprite', targetID unless targetID of @options.sprites
@setTarget @options.sprites[targetID]
else
@setTarget state.wizard.targetPos
@ -129,7 +129,7 @@ module.exports = class WizardSprite extends IndieSprite
@targetPos = @boundWizard targetPos
@beginMoveTween(duration, isLinear)
@shoveOtherWizards()
Backbone.Mediator.publish('self-wizard:target-changed', {sender:@}) if @isSelf
Backbone.Mediator.publish('self-wizard:target-changed', {sender: @}) if @isSelf
boundWizard: (target) ->
# Passed an {x, y} in world coordinates, returns {x, y} within world bounds
@ -168,7 +168,7 @@ module.exports = class WizardSprite extends IndieSprite
createjs.Tween
.get(@)
.to({tweenPercentage:0.0}, duration, ease)
.to({tweenPercentage: 0.0}, duration, ease)
.call(@endMoveTween)
@reachedTarget = false
@update true
@ -176,7 +176,7 @@ module.exports = class WizardSprite extends IndieSprite
shoveOtherWizards: (removeMe) ->
return unless @targetSprite
allWizards = []
Backbone.Mediator.publish('echo-all-wizard-sprites', {payload:allWizards})
Backbone.Mediator.publish('echo-all-wizard-sprites', {payload: allWizards})
allOfUs = (wizard for wizard in allWizards when wizard.targetSprite is @targetSprite)
allOfUs = (wizard for wizard in allOfUs when wizard isnt @) if removeMe

View file

@ -121,12 +121,12 @@ module.exports.Trailmaster = class Trailmaster
return unless thang.allTargets
g = new createjs.Graphics()
g.setStrokeStyle(0.5)
g.beginStroke(createjs.Graphics.getRGB(0,0,0))
g.beginStroke(createjs.Graphics.getRGB(0, 0, 0))
color = colorForThang(thang.team)
i = 0
while i < thang.allTargets.length
g.beginStroke(createjs.Graphics.getRGB(0,0,0))
g.beginStroke(createjs.Graphics.getRGB(0, 0, 0))
g.beginFill(createjs.Graphics.getRGB(color...))
sup = @camera.worldToSurface x: thang.allTargets[i], y: thang.allTargets[i + 1]
g.drawEllipse(sup.x - 5, sup.y - 3, 10, 6)
@ -168,7 +168,7 @@ module.exports.Trailmaster = class Trailmaster
clone.scaleY *= CLONE_SCALE
if sprite.expandActions # old Sprite
sprite.updateRotation(clone, sprite.data)
animActions = sprite.expandActions(if thang.acts then thang.getActionName() else "idle")
animActions = sprite.expandActions(if thang.acts then thang.getActionName() else 'idle')
sprite.applyActionsToSprites(animActions, [clone], true)
animation = clone.spriteSheet.getAnimation(clone.currentAnimation)
clone.currentAnimationFrame = Math.min(@clock % (animation.frames.length * 3), animation.frames.length - 1)
@ -186,9 +186,6 @@ module.exports.Trailmaster = class Trailmaster
@world.frames[@currentFrame].restoreStateForThang(thang)
sprites
createPath = (points, options={}, g=null) ->
options = options or {}
tailColor = options.tailColor ? options.headColor
@ -290,5 +287,3 @@ colorForThang = (team, brightness=100, alpha=1.0) =>
return color
module.exports.createPath = createPath

View file

@ -1,5 +1,5 @@
module.exports.clone = (obj) ->
return obj if obj is null or typeof (obj) isnt "object"
return obj if obj is null or typeof (obj) isnt 'object'
temp = obj.constructor()
for key of obj
temp[key] = module.exports.clone(obj[key])
@ -25,7 +25,7 @@ module.exports.normalizeFunc = (func_thing, object) ->
if _.isString(func_thing)
func = object[func_thing]
if not func
console.error("Could not find method", func_thing, 'in object', @)
console.error('Could not find method', func_thing, 'in object', @)
return => null # always return a func, or Mediator will go boom
func_thing = func
return func_thing
@ -36,7 +36,7 @@ module.exports.hexToHSL = (hex) ->
hexToR = (h) -> parseInt (cutHex(h)).substring(0, 2), 16
hexToG = (h) -> parseInt (cutHex(h)).substring(2, 4), 16
hexToB = (h) -> parseInt (cutHex(h)).substring(4, 6), 16
cutHex = (h) -> (if (h.charAt(0) is "#") then h.substring(1, 7) else h)
cutHex = (h) -> (if (h.charAt(0) is '#') then h.substring(1, 7) else h)
module.exports.hslToHex = (hsl) ->
'#' + (toHex(n) for n in hslToRgb(hsl...)).join('')

View file

@ -14,7 +14,7 @@ module.exports = class GoalManager extends CocoClass
# If you want weird goals or hybrid goals, make a custom goal.
nextGoalID: 0
nicks: ["GoalManager"]
nicks: ['GoalManager']
constructor: (@world, @initialGoals, @team) ->
super()
@ -134,9 +134,9 @@ module.exports = class GoalManager extends CocoClass
}
@initGoalState(state, [goal.killThangs, goal.saveThangs], 'killed')
for getTo in goal.getAllToLocations ? []
@initGoalState(state,[ getTo.getToLocation?.who , [] ], 'arrived')
@initGoalState(state, [getTo.getToLocation?.who, []], 'arrived')
for keepFrom in goal.keepAllFromLocations ? []
@initGoalState(state,[ [] , keepFrom.keepFromLocation?.who], 'arrived')
@initGoalState(state, [[], keepFrom.keepFromLocation?.who], 'arrived')
@initGoalState(state, [goal.getToLocations?.who, goal.keepFromLocations?.who], 'arrived')
@initGoalState(state, [goal.leaveOffSides?.who, goal.keepFromLeavingOffSides?.who], 'left')
@initGoalState(state, [goal.collectThangs?.who, goal.keepFromCollectingThangs?.who], 'collected')
@ -229,8 +229,8 @@ module.exports = class GoalManager extends CocoClass
if overallStatus = @checkOverallStatus true
matchedGoals = (_.find(@goals, {id: goalID}) for goalID, goalState of @goalStates when goalState.status is overallStatus)
mostEagerGoal = _.min matchedGoals, 'worldEndsAfter'
victory = overallStatus is "success"
tentative = overallStatus is "success"
victory = overallStatus is 'success'
tentative = overallStatus is 'success'
@world.endWorld victory, mostEagerGoal.worldEndsAfter, tentative if mostEagerGoal isnt Infinity
updateGoalState: (goalID, thangID, progressObjectName, frameNumber) ->
@ -244,20 +244,20 @@ module.exports = class GoalManager extends CocoClass
if success
numNeeded = goal.howMany ? Math.max(1, _.size stateThangs)
else
# saveThangs: by default we would want to save all the Thangs, which means that we would want none of them to be "done"
# saveThangs: by default we would want to save all the Thangs, which means that we would want none of them to be 'done'
numNeeded = _.size(stateThangs) - Math.max((goal.howMany ? 1), _.size stateThangs) + 1
numDone = _.filter(stateThangs).length
#console.log "needed", numNeeded, "done", numDone, "of total", _.size(stateThangs), "with how many", goal.howMany, "and stateThangs", stateThangs
#console.log 'needed', numNeeded, 'done', numDone, 'of total', _.size(stateThangs), 'with how many', goal.howMany, 'and stateThangs', stateThangs
return unless numDone >= numNeeded
return if state.status and not success # already failed it; don't wipe keyframe
state.status = if success then "success" else "failure"
state.status = if success then 'success' else 'failure'
state.keyFrame = frameNumber
#console.log goalID, "became", success, "on frame", frameNumber, "with overallStatus", @checkOverallStatus true
#console.log goalID, 'became', success, 'on frame', frameNumber, 'with overallStatus', @checkOverallStatus true
if overallStatus = @checkOverallStatus true
matchedGoals = (_.find(@goals, {id: goalID}) for goalID, goalState of @goalStates when goalState.status is overallStatus)
mostEagerGoal = _.min matchedGoals, 'worldEndsAfter'
victory = overallStatus is "success"
tentative = overallStatus is "success"
victory = overallStatus is 'success'
tentative = overallStatus is 'success'
@world.endWorld victory, mostEagerGoal.worldEndsAfter, tentative if mostEagerGoal isnt Infinity
goalIsPositive: (goalID) ->

View file

@ -31,7 +31,7 @@ module.exports = class Grid
for y in @columns gy - height / 2, gy + height / 2
for x in @rows gx - width / 2, gx + width / 2
for thang in @grid[y][x]
thangs.push thang if thang.collides and not (thang in thangs) and thang.id isnt "Add Thang Phantom"
thangs.push thang if thang.collides and not (thang in thangs) and thang.id isnt 'Add Thang Phantom'
thangs
clampColumn: (y) ->
@ -51,4 +51,4 @@ module.exports = class Grid
toString: ->
upsideDown = _.clone @grid
upsideDown.reverse()
(((if thangs.length then ("" + thangs.length) else " ") for thangs in row).join(" ") for row in upsideDown).join("\n")
(((if thangs.length then ('' + thangs.length) else ' ') for thangs in row).join(' ') for row in upsideDown).join("\n")

View file

@ -1,7 +1,7 @@
componentKeywords = ['attach', 'constructor', 'validateArguments', 'toString', 'isComponent'] # Array is faster than object
module.exports = class Component
@className: "Component"
@className: 'Component'
isComponent: true
constructor: (config) ->
for key, value of config
@ -9,7 +9,7 @@ module.exports = class Component
attach: (thang) ->
# Optimize; this is much of the World constructor time
for key, value of @ when key not in componentKeywords and key[0] isnt "_"
for key, value of @ when key not in componentKeywords and key[0] isnt '_'
oldValue = thang[key]
if typeof oldValue is 'function'
thang.appendMethod key, value

View file

@ -1,23 +1,23 @@
Vector = require './vector'
module.exports.ArgumentError = class ArgumentError extends Error
@className: "ArgumentError"
@className: 'ArgumentError'
constructor: (@message, @functionName, @argumentName, @intendedType, @actualValue, @numArguments) ->
super message
@name = "ArgumentError"
@name = 'ArgumentError'
if Error.captureStackTrace?
Error.captureStackTrace @, @constructor
toString: ->
s = "#{@functionName}"
if @argumentName is "return"
if @argumentName is 'return'
s += "'s return value"
else if @argumentName is "_excess"
else if @argumentName is '_excess'
s += " takes only #{@numArguments} argument#{if @numArguments > 1 then 's' else ''}."
else if @argumentName
s += "'s argument #{@argumentName}"
else
s += " takes no arguments."
s += ' takes no arguments.'
actualType = typeof @actualValue
if not @actualValue?
@ -26,12 +26,12 @@ module.exports.ArgumentError = class ArgumentError extends Error
actualType = 'array'
typeMismatch = @intendedType and not @intendedType.match actualType
if typeMismatch
v = ""
v = ''
if actualType is 'string'
v = "\"#{@actualValue}\""
else if actualType is "number"
else if actualType is 'number'
if Math.round(@actualValue) is @actualValue then @actualValue else @actualValue.toFixed(2)
else if actualType is "boolean"
else if actualType is 'boolean'
v = "#{@actualValue}"
else if (@actualValue? and @actualValue.id and @actualValue.trackedPropertiesKeys)
# (Don't import Thang, but determine whether it is Thang.)
@ -40,7 +40,7 @@ module.exports.ArgumentError = class ArgumentError extends Error
v = @actualValue.toString()
showValue = showValue or @actualValue instanceof Vector
s += " should have type #{@intendedType}, but got #{actualType}#{if v then ': ' + v else ''}."
else if @argumentName and @argumentName isnt "_excess"
s += " has a problem."
else if @argumentName and @argumentName isnt '_excess'
s += ' has a problem.'
s += '\n' + @message if @message
s

View file

@ -1,375 +1,375 @@
module.exports.thangNames = thangNames =
"Soldier M": [
"Duke"
"William"
"Lucas"
"Marcus"
"Robert"
"Gordon"
"Kirin"
"Theo"
"Roger"
"Roderick"
"Samson"
"Silas"
"Richard"
"Max"
"Jax"
"Dax"
"Mischa"
"Ronald"
"Tyrone"
"Thelonious"
"Miles"
"Bill"
"Kumar"
"Ricardo"
"Maxwell"
"Jonah"
"Leopold"
"Phineas"
"Ferb"
"Felix"
"Ezra"
"Lucian"
"Augustus"
"Ronan"
"Pierce"
"Harry"
"Hirium"
"Hugo"
"Cecil"
"Barron"
"Huburt"
"Sterling"
"Alistair"
"Cid"
"Remy"
"Stormy"
"Halle"
"Sage"
"Ryan"
"Bond"
'Soldier M': [
'Duke'
'William'
'Lucas'
'Marcus'
'Robert'
'Gordon'
'Kirin'
'Theo'
'Roger'
'Roderick'
'Samson'
'Silas'
'Richard'
'Max'
'Jax'
'Dax'
'Mischa'
'Ronald'
'Tyrone'
'Thelonious'
'Miles'
'Bill'
'Kumar'
'Ricardo'
'Maxwell'
'Jonah'
'Leopold'
'Phineas'
'Ferb'
'Felix'
'Ezra'
'Lucian'
'Augustus'
'Ronan'
'Pierce'
'Harry'
'Hirium'
'Hugo'
'Cecil'
'Barron'
'Huburt'
'Sterling'
'Alistair'
'Cid'
'Remy'
'Stormy'
'Halle'
'Sage'
'Ryan'
'Bond'
]
"Soldier F": [
"Sarah"
"Alexandra"
"Holly"
"Trinity"
"Nikita"
"Alana"
"Lana"
"Joan"
"Helga"
"Annie"
"Lukaz"
"Gorgin"
"Coco"
"Buffy"
"Allankrita"
"Kay"
'Soldier F': [
'Sarah'
'Alexandra'
'Holly'
'Trinity'
'Nikita'
'Alana'
'Lana'
'Joan'
'Helga'
'Annie'
'Lukaz'
'Gorgin'
'Coco'
'Buffy'
'Allankrita'
'Kay'
]
"Peasant M": [
"Yorik"
"Hector"
"Thad"
"Victor"
"Lyle"
"Charles"
"Yusef"
"Hingle"
"Azgot"
"Piers"
"Carlton"
"Hershell"
"Gawain"
"Durfkor"
"Paps"
"Hodor"
'Peasant M': [
'Yorik'
'Hector'
'Thad'
'Victor'
'Lyle'
'Charles'
'Yusef'
'Hingle'
'Azgot'
'Piers'
'Carlton'
'Hershell'
'Gawain'
'Durfkor'
'Paps'
'Hodor'
]
"Peasant F": [
"Hilda"
"Icey"
"Matilda"
"Mertia"
"Mary"
"Brandy"
"Gwendolin"
"Tabitha"
"Regan"
"Giselle"
"Bernadette"
'Peasant F': [
'Hilda'
'Icey'
'Matilda'
'Mertia'
'Mary'
'Brandy'
'Gwendolin'
'Tabitha'
'Regan'
'Giselle'
'Bernadette'
]
"Archer F": [
"Phoebe"
"Mira"
"Agapi"
"Cecily"
"Tansy"
"Ivy"
"Gemma"
"Keturah"
"Korra"
"Kim"
"Odette"
"Orly"
"Mercedes"
"Rosaline"
"Vesper"
"Beverly"
"Natalie"
"Clare"
"Rowan"
"Omar"
"Alden"
"Cairn"
"Jensen"
"Yilitha"
"Mirana"
"Lina"
"Luna"
"Alleria"
"Vereesa"
"Beatrice"
'Archer F': [
'Phoebe'
'Mira'
'Agapi'
'Cecily'
'Tansy'
'Ivy'
'Gemma'
'Keturah'
'Korra'
'Kim'
'Odette'
'Orly'
'Mercedes'
'Rosaline'
'Vesper'
'Beverly'
'Natalie'
'Clare'
'Rowan'
'Omar'
'Alden'
'Cairn'
'Jensen'
'Yilitha'
'Mirana'
'Lina'
'Luna'
'Alleria'
'Vereesa'
'Beatrice'
]
"Archer M": [
"Brian"
"Cole"
"Roman"
"Hunter"
"Simon"
"Robin"
"Quinn"
"Arty"
"Gimsley"
"Fidsdale"
"Slyvos"
"Logos"
"Denin"
"Lycan"
"Loco"
"Vican"
"Mars"
"Dev"
"Oliver"
'Archer M': [
'Brian'
'Cole'
'Roman'
'Hunter'
'Simon'
'Robin'
'Quinn'
'Arty'
'Gimsley'
'Fidsdale'
'Slyvos'
'Logos'
'Denin'
'Lycan'
'Loco'
'Vican'
'Mars'
'Dev'
'Oliver'
]
"Ogre Munchkin M": [
"Brack"
"Gort"
"Weeb"
"Nerph"
"Kratt"
"Smerk"
"Raack"
"Dobo"
"Draff"
"Zozo"
"Kogpole"
"Leerer"
"Skoggen"
"Treg"
"Goreball"
"Gert"
"Thabt"
"Snortt"
"Kog"
"Ursa"
"Ragtime"
'Ogre Munchkin M': [
'Brack'
'Gort'
'Weeb'
'Nerph'
'Kratt'
'Smerk'
'Raack'
'Dobo'
'Draff'
'Zozo'
'Kogpole'
'Leerer'
'Skoggen'
'Treg'
'Goreball'
'Gert'
'Thabt'
'Snortt'
'Kog'
'Ursa'
'Ragtime'
]
"Ogre Munchkin F": [
"Iyert"
"Palt"
"Shmeal"
"Gurzunn"
"Yugark"
"Dosha"
"Inski"
"Lacos"
"Upfish"
'Ogre Munchkin F': [
'Iyert'
'Palt'
'Shmeal'
'Gurzunn'
'Yugark'
'Dosha'
'Inski'
'Lacos'
'Upfish'
]
"Ogre Peon M": [
"Durbo"
"Kurger"
"Mudwich"
"Ba Bo"
"Zugger"
"Toe Pod"
'Ogre Peon M': [
'Durbo'
'Kurger'
'Mudwich'
'Ba Bo'
'Zugger'
'Toe Pod'
]
"Ogre Peon F": [
"Iblet"
"Lorba"
"Zzoya"
"Yamra"
"Greeke"
"Vapa"
'Ogre Peon F': [
'Iblet'
'Lorba'
'Zzoya'
'Yamra'
'Greeke'
'Vapa'
]
"Ogre M": [
"Krogg"
"Dronck"
"Trogdor"
"Kulgor"
"Skrungt"
"Mak Fod"
"Trung"
"Axe Ox"
"Vargutt"
"Grumus"
"Gug"
"Tarlok"
"Gurulax"
"Mokrul"
"Polifemo"
"Muthyala"
"Saltporker"
'Ogre M': [
'Krogg'
'Dronck'
'Trogdor'
'Kulgor'
'Skrungt'
'Mak Fod'
'Trung'
'Axe Ox'
'Vargutt'
'Grumus'
'Gug'
'Tarlok'
'Gurulax'
'Mokrul'
'Polifemo'
'Muthyala'
'Saltporker'
]
"Ogre F": [
"Nareng"
"Morthrug"
"Glonc"
"Marghurk"
"Martha"
"Holkam"
"Alkaz"
"Gar'ah"
"Mak'rah"
"Marnag"
'Ogre F': [
'Nareng'
'Morthrug'
'Glonc'
'Marghurk'
'Martha'
'Holkam'
'Alkaz'
'Gar\'ah'
'Mak\'rah'
'Marnag'
]
"Ogre Brawler": [
"Grul'thock"
"Boz"
"Trod"
"Muul"
"Grumoll"
"Burobb"
"Arelt"
"Zagurk"
"Zeredd"
"Borgag"
"Grognar"
"Ironjaw"
"Tuguro"
"York"
"Ork'han"
"Roast Beefy"
"Haggar"
'Ogre Brawler': [
'Grul\'thock'
'Boz'
'Trod'
'Muul'
'Grumoll'
'Burobb'
'Arelt'
'Zagurk'
'Zeredd'
'Borgag'
'Grognar'
'Ironjaw'
'Tuguro'
'York'
'Ork\'han'
'Roast Beefy'
'Haggar'
]
"Ogre Fangrider": [
"Dreek"
"Flarsho"
"Mizzy"
"Secka"
"Arizard"
"Secka"
"Arizard"
"Morzgret"
"Doralt"
"Geggret"
"Gurzthrot"
"Murgark"
"Muttin"
"Bortrok"
'Ogre Fangrider': [
'Dreek'
'Flarsho'
'Mizzy'
'Secka'
'Arizard'
'Secka'
'Arizard'
'Morzgret'
'Doralt'
'Geggret'
'Gurzthrot'
'Murgark'
'Muttin'
'Bortrok'
]
"Ogre Shaman": [
"Sham'uk"
"Il'Du'duka"
"Ahst'durante"
"Poult"
"Aolian'Tak"
"Tuzell"
"Yamizeb"
"Yerong"
"Tuzang"
"Varreth"
"Yugargen"
"Turann"
"Ugoki"
"Zulabar"
"Zo'Goroth"
"Mogadishu"
"Nazgareth"
"Gror"
"Grek"
"Gom"
"Gogg"
"Ghuk"
"Makas"
"Drun"
'Ogre Shaman': [
'Sham\'uk'
'Il\'Du\'duka'
'Ahst\'durante'
'Poult'
'Aolian\'Tak'
'Tuzell'
'Yamizeb'
'Yerong'
'Tuzang'
'Varreth'
'Yugargen'
'Turann'
'Ugoki'
'Zulabar'
'Zo\'Goroth'
'Mogadishu'
'Nazgareth'
'Gror'
'Grek'
'Gom'
'Gogg'
'Ghuk'
'Makas'
'Drun'
]
"Ogre Thrower": [
"Kyrgg"
"Durnath"
"Kraggan"
"Rasha"
"Moza"
"Vujii"
"Esha"
"Zara"
"Hamedi"
"Jinjin"
"Yetu"
"Makas"
"Rakash"
"Drumbaa"
"Pinakin"
'Ogre Thrower': [
'Kyrgg'
'Durnath'
'Kraggan'
'Rasha'
'Moza'
'Vujii'
'Esha'
'Zara'
'Hamedi'
'Jinjin'
'Yetu'
'Makas'
'Rakash'
'Drumbaa'
'Pinakin'
]
"Burl": [
"Borlit"
"Burlosh"
"Dorf"
'Burl': [
'Borlit'
'Burlosh'
'Dorf'
]
"Griffin Rider": [
"Aeoldan"
"Bestarius"
'Griffin Rider': [
'Aeoldan'
'Bestarius'
]
"Potion Master": [
"Snake"
"Amaranth"
"Zander"
"Arora"
"Curie"
"Clause"
"Vanders"
'Potion Master': [
'Snake'
'Amaranth'
'Zander'
'Arora'
'Curie'
'Clause'
'Vanders'
]
"Librarian": [
"Hushbaum"
"Matilda"
"Agnes"
"Agathe"
"Satish"
'Librarian': [
'Hushbaum'
'Matilda'
'Agnes'
'Agathe'
'Satish'
]
"Equestrian": [
"Reynaldo"
"Ryder"
"Thoron"
"Mirial"
"Neely"
'Equestrian': [
'Reynaldo'
'Ryder'
'Thoron'
'Mirial'
'Neely'
]
"Knight": [
"Tharin"
"Arthur"
"Galahad"
"Mace"
"Drake"
"Duran"
"Almeric"
"Hunfray"
"Hank"
"Jeph"
"Neville"
"Alphonse"
"Edward"
'Knight': [
'Tharin'
'Arthur'
'Galahad'
'Mace'
'Drake'
'Duran'
'Almeric'
'Hunfray'
'Hank'
'Jeph'
'Neville'
'Alphonse'
'Edward'
]
"Captain": [
"Anya"
"Brigette"
"Sarre"
"Katana"
"Lily"
"Isa"
"Dimia"
"Jane"
"Lia"
"Hardcastle"
"Leona"
'Captain': [
'Anya'
'Brigette'
'Sarre'
'Katana'
'Lily'
'Isa'
'Dimia'
'Jane'
'Lia'
'Hardcastle'
'Leona'
]

View file

@ -1,6 +1,6 @@
# http://coffeescriptcookbook.com/chapters/math/generating-predictable-random-numbers
class Rand
@className: "Rand"
@className: 'Rand'
# If created without a seed, uses current time as seed.
constructor: (@seed) ->
# Knuth and Lewis' improvements to Park and Miller's LCPRNG

View file

@ -1,7 +1,7 @@
Vector = require './vector'
class Rectangle
@className: "Rectangle"
@className: 'Rectangle'
# Class methods for nondestructively operating
for name in ['add', 'subtract', 'multiply', 'divide']
do (name) ->

View file

@ -3,7 +3,7 @@
# Other Systems might be things like Attraction, EdgeBounce, EdgeWrap, and non-physics ones, too, like Rendering, Animation, ...
module.exports = class System
@className: "System"
@className: 'System'
constructor: (@world, config) ->
# Unlike with Component, we don't automatically copy all our properties onto the World.
# Subclasses can copy select properties here if they like.

View file

@ -1,16 +1,16 @@
# http://codingowl.com/readblog.php?blogid=124
module.exports.CollisionCategory = class CollisionCategory
@className: "CollisionCategory"
@className: 'CollisionCategory'
constructor: (name, @superteamIndex=null, @collisionSystem) ->
# @superteamIndex is null for "none", "obstacles", and "dead".
# It's 0 for "ground", "air", and "ground_and_air" units with no superteams.
# @superteamIndex is null for 'none', 'obstacles', and 'dead'.
# It's 0 for 'ground', 'air', and 'ground_and_air' units with no superteams.
# It's 1, 2, or 3 for the superteams it gets after that. We can only have 16 collision categories.
@ground = name.search("ground") isnt -1
@air = name.search("air") isnt -1
@ground = name.search('ground') isnt -1
@air = name.search('air') isnt -1
@name = CollisionCategory.nameFor name, @superteamIndex
@superteamIndex ?= 0 if @ground or @air
@number = 1 << @collisionSystem.totalCategories++
if @collisionSystem.totalCategories > 16 then console.log "There should only be 16 collision categories!"
if @collisionSystem.totalCategories > 16 then console.log 'There should only be 16 collision categories!'
@mask = 0
@collisionSystem.allCategories[@name] = @
for otherCatName, otherCat of @collisionSystem.allCategories
@ -19,32 +19,32 @@ module.exports.CollisionCategory = class CollisionCategory
otherCat.mask = otherCat.mask | @number
collidesWith: (cat) ->
# "none" collides with nothing
return false if @name is "none" or cat.name is "none"
# 'none' collides with nothing
return false if @name is 'none' or cat.name is 'none'
# "obstacles" collides with everything; could also try letting air units (but not ground_and_air) fly over these
return true if cat.name is "obstacles" or @name is "obstacles"
# 'obstacles' collides with everything; could also try letting air units (but not ground_and_air) fly over these
return true if cat.name is 'obstacles' or @name is 'obstacles'
# "dead" collides only with obstacles
return cat.name is "obstacles" if @name is "dead"
return @name is "obstacles" if cat.name is "dead"
# 'dead' collides only with obstacles
return cat.name is 'obstacles' if @name is 'dead'
return @name is 'obstacles' if cat.name is 'dead'
# "ground_and_air_<team>" units don't hit ground or air units on their team (so missiles don't hit same team)
# 'ground_and_air_<team>' units don't hit ground or air units on their team (so missiles don't hit same team)
sameTeam = @superteamIndex and cat.superteamIndex is @superteamIndex
return false if sameTeam and @ground and @air
# actually, "ground_and_air<team>" units don't hit any ground_and_air units (temp missile collision fix)
# actually, 'ground_and_air<team>' units don't hit any ground_and_air units (temp missile collision fix)
return false if @ground and @air and cat.ground and cat.air
# "ground" collides with "ground"
# 'ground' collides with 'ground'
return true if cat.ground and @ground
# "air" collides with "air"
# 'air' collides with 'air'
return true if cat.air and @air
# doesn't collide (probably "ground" and "air")
# doesn't collide (probably 'ground' and 'air')
false
@nameFor: (name, superteamIndex=null) ->
return name unless name.match("ground") or name.match("air")
name + "_" + (superteamIndex or 0)
return name unless name.match('ground') or name.match('air')
name + '_' + (superteamIndex or 0)

View file

@ -131,7 +131,7 @@ module.exports = class Thang
source.original = chain.original.toString()
source.user = chain.user?.toString()
else
source.original = @[methodName]?.toString() ? ""
source.original = @[methodName]?.toString() ? ''
source.original = Aether.getFunctionBody source.original
source

View file

@ -8,15 +8,15 @@ else
bytesPerFloat = 4
module.exports = class ThangState
@className: "ThangState"
@className: 'ThangState'
@trackedPropertyTypes: [
"boolean"
"number"
"string"
"array" # will turn everything into strings
"object" # grrr
"Vector"
"Thang" # serialized as ids, like strings
'boolean'
'number'
'string'
'array' # will turn everything into strings
'object' # grrr
'Vector'
'Thang' # serialized as ids, like strings
]
hasRestored: false
@ -40,7 +40,7 @@ module.exports = class ThangState
unless type
type = @trackedPropertyTypes[propIndex]
storage = @trackedPropertyValues[propIndex]
if type is "Vector"
if type is 'Vector'
value = new Vector storage[3 * @frameIndex], storage[3 * @frameIndex + 1], storage[3 * @frameIndex + 2]
else if type is 'string'
specialKey = storage[@frameIndex]
@ -78,7 +78,7 @@ module.exports = class ThangState
type = @trackedPropertyTypes[propIndex]
storage = @trackedPropertyValues[propIndex]
props.push(@thang[prop] = @getStoredProp propIndex, type, storage)
#console.log @frameIndex, @thang.id, prop, propIndex, type, storage, "got", @thang[prop]
#console.log @frameIndex, @thang.id, prop, propIndex, type, storage, 'got', @thang[prop]
@props = props
@trackedPropertyTypes = @trackedPropertyValues = @specialKeysToValues = null # leave @trackedPropertyKeys for indexing
@hasRestored = true
@ -90,14 +90,14 @@ module.exports = class ThangState
restorePartial: (ratio) ->
inverse = 1 - ratio
for prop, propIndex in @trackedPropertyKeys when prop is "pos" or prop is "rotation"
for prop, propIndex in @trackedPropertyKeys when prop is 'pos' or prop is 'rotation'
if @hasRestored
value = @props[propIndex]
else
type = @trackedPropertyTypes[propIndex]
storage = @trackedPropertyValues[propIndex]
value = @getStoredProp propIndex, type, storage
if prop is "pos"
if prop is 'pos'
if @thang.teleport and @thang.pos.distanceSquared(value) > 900
# Don't interpolate; it was probably a teleport. https://github.com/codecombat/codecombat/issues/738
@thang.pos = value
@ -106,7 +106,7 @@ module.exports = class ThangState
@thang.pos.x = inverse * @thang.pos.x + ratio * value.x
@thang.pos.y = inverse * @thang.pos.y + ratio * value.y
@thang.pos.z = inverse * @thang.pos.z + ratio * value.z
else if prop is "rotation"
else if prop is 'rotation'
@thang.rotation = inverse * @thang.rotation + ratio * value
@thang.partialState = true
@
@ -119,7 +119,7 @@ module.exports = class ThangState
value = @props[originalPropIndex]
if value
# undefined, null, false, 0 won't trigger in this serialization code scheme anyway, so we can't differentiate between them when deserializing
if type is "Vector"
if type is 'Vector'
storage[3 * frameIndex] = value.x
storage[3 * frameIndex + 1] = value.y
storage[3 * frameIndex + 2] = value.z
@ -157,7 +157,7 @@ module.exports = class ThangState
storage[frameIndex] = specialKey
else
storage[frameIndex] = value
#console.log @thang.id, "assigned prop", originalPropIndex, newPropIndex, value, type, "at", frameIndex, "to", storage[frameIndex]
#console.log @thang.id, 'assigned prop', originalPropIndex, newPropIndex, value, type, 'at', frameIndex, 'to', storage[frameIndex]
null
@deserialize: (world, frameIndex, thang, trackedPropertyKeys, trackedPropertyTypes, trackedPropertyValues, specialKeysToValues) ->
@ -173,12 +173,12 @@ module.exports = class ThangState
@transferableBytesNeededForType: (type, nFrames) ->
bytes = switch type
when "boolean" then 1
when "number" then bytesPerFloat
when "Vector" then bytesPerFloat * 3
when "string" then 4
when "Thang" then 4 # turn them into strings of their ids
when "array" then 4 # turn them into strings and hope it doesn't explode?
when 'boolean' then 1
when 'number' then bytesPerFloat
when 'Vector' then bytesPerFloat * 3
when 'string' then 4
when 'Thang' then 4 # turn them into strings of their ids
when 'array' then 4 # turn them into strings and hope it doesn't explode?
else 0
# We need to be a multiple of bytesPerFloat otherwise bigger-byte array (Float64Array, etc.) offsets won't work
# http://www.kirupa.com/forum/showthread.php?378737-Typed-Arrays-Y-U-No-offset-at-values-other-than-multiples-of-element-size
@ -187,17 +187,17 @@ module.exports = class ThangState
@createArrayForType: (type, nFrames, buffer, offset) ->
bytes = @transferableBytesNeededForType type, nFrames
storage = switch type
when "boolean"
when 'boolean'
new Uint8Array(buffer, offset, nFrames)
when "number"
when 'number'
new FloatArrayType(buffer, offset, nFrames)
when "Vector"
when 'Vector'
new FloatArrayType(buffer, offset, nFrames * 3)
when "string"
when 'string'
new Uint32Array(buffer, offset, nFrames)
when "Thang"
when 'Thang'
new Uint32Array(buffer, offset, nFrames)
when "array"
when 'array'
new Uint32Array(buffer, offset, nFrames)
else
[]

View file

@ -1,6 +1,6 @@
# https://github.com/hornairs/blog/blob/master/assets/coffeescripts/flocking/vector.coffee
class Vector
@className: "Vector"
@className: 'Vector'
# Class methods for nondestructively operating
for name in ['add', 'subtract', 'multiply', 'divide', 'limit', 'normalize']
do (name) ->

View file

@ -12,7 +12,7 @@ PROGRESS_UPDATE_INTERVAL = 200
DESERIALIZATION_INTERVAL = 20
module.exports = class World
@className: "World"
@className: 'World'
age: 0
ended: false
preloading: false # Whether we are just preloading a world in case we soon cast it
@ -63,12 +63,12 @@ module.exports = class World
@thangMap[thang.id] = thang
thangDialogueSounds: ->
if @frames.length < @totalFrames then throw new Error("World should be over before grabbing dialogue")
if @frames.length < @totalFrames then throw new Error('World should be over before grabbing dialogue')
[sounds, seen] = [[], {}]
for frame in @frames
for thangID, state of frame.thangStateMap
continue unless state.thang.say and sayMessage = state.getStateForProp "sayMessage"
soundKey = state.thang.spriteName + ":" + sayMessage
continue unless state.thang.say and sayMessage = state.getStateForProp 'sayMessage'
soundKey = state.thang.spriteName + ':' + sayMessage
unless seen[soundKey]
sounds.push [state.thang.spriteName, sayMessage]
seen[soundKey] = true
@ -83,7 +83,7 @@ module.exports = class World
loadFrames: (loadedCallback, errorCallback, loadProgressCallback, skipDeferredLoading, loadUntilFrame) ->
return if @aborted
unless @thangs.length
console.log "Warning: loadFrames called on empty World (no thangs)."
console.log 'Warning: loadFrames called on empty World (no thangs).'
t1 = now()
@t0 ?= t1
if loadUntilFrame
@ -113,7 +113,7 @@ module.exports = class World
loadProgressCallback? i / @totalFrames unless @preloading
t1 = t2
if t2 - @t0 > 1000
console.log(' Loaded', i, 'of', @totalFrames, "(+" + (t2 - @t0).toFixed(0) + "ms)")
console.log ' Loaded', i, 'of', @totalFrames, '(+' + (t2 - @t0).toFixed(0) + 'ms)'
@t0 = t2
continueFn = =>
return if @destroyed
@ -155,7 +155,7 @@ module.exports = class World
for levelSystem in level.systems
systemModel = levelSystem.model
config = levelSystem.config
systemClass = @loadClassFromCode systemModel.js, systemModel.name, "system"
systemClass = @loadClassFromCode systemModel.js, systemModel.name, 'system'
#console.log "using db system class ---\n", systemClass, "\n--- from code ---n", systemModel.js, "\n---"
system = new systemClass @, config
@addSystems system
@ -169,15 +169,15 @@ module.exports = class World
# Load new Thangs
toAdd = []
for d in level.thangs
continue if d.thangType is "Interface" # ignore old Interface Thangs until we've migrated away
continue if d.thangType is 'Interface' # ignore old Interface Thangs until we've migrated away
components = []
for component in d.components
componentModel = _.find level.levelComponents, (c) -> c.original is component.original and c.version.major is (component.majorVersion ? 0)
#console.log "found model", componentModel, "from", component, "for", d.id, "from existing components", level.levelComponents
componentClass = @loadClassFromCode componentModel.js, componentModel.name, "component"
#console.log 'found model', componentModel, 'from', component, 'for', d.id, 'from existing components', level.levelComponents
componentClass = @loadClassFromCode componentModel.js, componentModel.name, 'component'
components.push [componentClass, component.config]
#console.log "---", d.id, "using db component class ---\n", componentClass, "\n--- from code ---\n", componentModel.js, '\n---'
#console.log "(found", componentModel, "for id", component.original, "from", level.levelComponents, ")"
#console.log '---', d.id, "using db component class ---\n", componentClass, "\n--- from code ---\n", componentModel.js, '\n---'
#console.log '(found', componentModel, 'for id', component.original, 'from', level.levelComponents, ')'
thangType = d.thangType
thangTypeModel = _.find level.thangTypes, (t) -> t.original is thangType
thangType = thangTypeModel.name if thangTypeModel
@ -185,7 +185,7 @@ module.exports = class World
try
thang.addComponents components...
catch e
console.error "couldn't load components for", d.thangType, d.id, "because", e, e.stack, e.stackTrace
console.error 'couldn\'t load components for', d.thangType, d.id, 'because', e, e.stack, e.stackTrace
toAdd.push thang
@extraneousThangs = consolidateThangs toAdd if willSimulate # combine walls, for example; serialize the leftovers later
for thang in toAdd
@ -200,11 +200,11 @@ module.exports = class World
@scripts = []
@addScripts level.scripts...
loadClassFromCode: (js, name, kind="component") ->
loadClassFromCode: (js, name, kind='component') ->
# Cache them based on source code so we don't have to worry about extra compilations
@componentCodeClassMap ?= {}
@systemCodeClassMap ?= {}
map = if kind is "component" then @componentCodeClassMap else @systemCodeClassMap
map = if kind is 'component' then @componentCodeClassMap else @systemCodeClassMap
c = map[js]
return c if c
c = map[js] = eval js
@ -285,7 +285,7 @@ module.exports = class World
serialize: ->
# Code hotspot; optimize it
if @frames.length < @totalFrames then throw new Error("World Should Be Over Before Serialization")
if @frames.length < @totalFrames then throw new Error('World Should Be Over Before Serialization')
[transferableObjects, nontransferableObjects] = [0, 0]
o = {totalFrames: @totalFrames, maxTotalFrames: @maxTotalFrames, frameRate: @frameRate, dt: @dt, victory: @victory, userCodeMap: {}, trackedProperties: {}}
o.trackedProperties[prop] = @[prop] for prop in @trackedProperties or []
@ -364,20 +364,20 @@ module.exports = class World
flattened.push value
o.storageBuffer = flattened
#console.log "Allocating memory:", (t1 - t0).toFixed(0), "ms; assigning values:", (t2 - t1).toFixed(0), "ms, so", ((t2 - t1) / @frames.length).toFixed(3), "ms per frame"
#console.log "Got", transferableObjects, "transferable objects and", nontransferableObjects, "nontransferable; stored", transferableStorageBytesNeeded, "bytes transferably"
#console.log 'Allocating memory:', (t1 - t0).toFixed(0), 'ms; assigning values:', (t2 - t1).toFixed(0), 'ms, so', ((t2 - t1) / @frames.length).toFixed(3), 'ms per frame'
#console.log 'Got', transferableObjects, 'transferable objects and', nontransferableObjects, 'nontransferable; stored', transferableStorageBytesNeeded, 'bytes transferably'
o.thangs = (t.serialize() for t in @thangs.concat(@extraneousThangs ? []))
o.scriptNotes = (sn.serialize() for sn in @scriptNotes)
if o.scriptNotes.length > 200
console.log "Whoa, serializing a lot of WorldScriptNotes here:", o.scriptNotes.length
console.log 'Whoa, serializing a lot of WorldScriptNotes here:', o.scriptNotes.length
{serializedWorld: o, transferableObjects: [o.storageBuffer]}
@deserialize: (o, classMap, oldSerializedWorldFrames, finishedWorldCallback) ->
# Code hotspot; optimize it
#console.log "Deserializing", o, "length", JSON.stringify(o).length
#console.log 'Deserializing', o, 'length', JSON.stringify(o).length
#console.log JSON.stringify(o)
#console.log "Got special keys and values:", o.specialValuesToKeys, o.specialKeysToValues
#console.log 'Got special keys and values:', o.specialValuesToKeys, o.specialKeysToValues
perf = {}
perf.t0 = now()
w = new World o.userCodeMap, classMap
@ -424,13 +424,13 @@ module.exports = class World
w.ended = true
w.getFrame(w.totalFrames - 1).restoreState()
perf.t5 = now()
console.log "Deserialization:", (perf.t5 - perf.t0).toFixed(0) + "ms (" + ((perf.t5 - perf.t0) / w.frames.length).toFixed(3) + "ms per frame).", perf.batches, "batches."
console.log 'Deserialization:', (perf.t5 - perf.t0).toFixed(0) + 'ms (' + ((perf.t5 - perf.t0) / w.frames.length).toFixed(3) + 'ms per frame).', perf.batches, 'batches.'
if false
console.log " Deserializing--constructing new World:", (perf.t1 - perf.t0).toFixed(2) + "ms"
console.log " Deserializing--Thangs and ScriptNotes:", (perf.t2 - perf.t1).toFixed(2) + "ms"
console.log " Deserializing--reallocating memory:", (perf.t3 - perf.t2).toFixed(2) + "ms"
console.log " Deserializing--WorldFrames:", (perf.t4 - perf.t3).toFixed(2) + "ms"
console.log " Deserializing--restoring last WorldFrame:", (perf.t5 - perf.t4).toFixed(2) + "ms"
console.log ' Deserializing--constructing new World:', (perf.t1 - perf.t0).toFixed(2) + 'ms'
console.log ' Deserializing--Thangs and ScriptNotes:', (perf.t2 - perf.t1).toFixed(2) + 'ms'
console.log ' Deserializing--reallocating memory:', (perf.t3 - perf.t2).toFixed(2) + 'ms'
console.log ' Deserializing--WorldFrames:', (perf.t4 - perf.t3).toFixed(2) + 'ms'
console.log ' Deserializing--restoring last WorldFrame:', (perf.t5 - perf.t4).toFixed(2) + 'ms'
finishedWorldCallback w
findFirstChangedFrame: (oldWorld) ->
@ -440,9 +440,9 @@ module.exports = class World
break unless oldFrame and newFrame.hash is oldFrame.hash
@firstChangedFrame = i
if @frames[i]
console.log "First changed frame is", @firstChangedFrame, "with hash", @frames[i].hash, "compared to", oldWorld.frames[i]?.hash
console.log 'First changed frame is', @firstChangedFrame, 'with hash', @frames[i].hash, 'compared to', oldWorld.frames[i]?.hash
else
console.log "No frames were changed out of all", @frames.length
console.log 'No frames were changed out of all', @frames.length
@firstChangedFrame
pointsForThang: (thangID, frameStart=0, frameEnd=null, camera=null, resolution=4) ->
@ -478,7 +478,7 @@ module.exports = class World
actionsForThang: (thangID, keepIdle=false) ->
# Optimized
@actionsForThangCache ?= {}
cacheKey = thangID + "_" + Boolean(keepIdle)
cacheKey = thangID + '_' + Boolean(keepIdle)
cached = @actionsForThangCache[cacheKey]
return cached if cached
states = (frame.thangStateMap[thangID] for frame in @frames)

View file

@ -1,10 +1,12 @@
ThangState = require './thang_state'
module.exports = class WorldFrame
@className: "WorldFrame"
@className: 'WorldFrame'
constructor: (@world, @time=0) ->
@thangStateMap = {}
@setState() if @world
getNextFrame: ->
# Optimized. Must be called while thangs are current at this frame.
nextTime = @time + @world.dt
@ -22,7 +24,7 @@ module.exports = class WorldFrame
thangState.restore() for thangID, thangState of @thangStateMap
for thang in @world.thangs
if not @thangStateMap[thang.id] and not thang.stateless
#console.log "Frame", @time, "restoring state for", thang.id, "and saying it don't exist"
#console.log 'Frame', @time, 'restoring state for', thang.id, 'and saying it don\'t exist'
thang.exists = false
restorePartialState: (ratio) ->
@ -33,22 +35,22 @@ module.exports = class WorldFrame
if not thangState
if not thang.stateless
thang.exists = false
#console.log "Frame", @time, "restoring state for", thang.id, "in particular and saying it don't exist"
#console.log 'Frame', @time, 'restoring state for', thang.id, 'in particular and saying it don\'t exist'
return
thangState.restore()
clearEvents: -> thang.currentEvents = [] for thang in @world.thangs
toString: ->
map = ((' ' for x in [0 .. @world.width]) \
for y in [0 .. @world.height])
symbols = ".ox@dfga[]/D"
symbols = '.ox@dfga[]/D'
for thang, i in @world.thangs when thang.rectangle
rect = thang.rectangle().axisAlignedBoundingBox()
for y in [Math.floor(rect.y - rect.height / 2) ... Math.ceil(rect.y + rect.height / 2)]
for x in [Math.floor(rect.x - rect.width / 2) ... Math.ceil(rect.x + rect.width / 2)]
map[y][x] = symbols[i % symbols.length] if 0 <= y < @world.height and 0 <= x < @world.width
@time + "\n" + (xs.join(' ') for xs in map).join('\n') + '\n'
@time + '\n' + (xs.join(' ') for xs in map).join('\n') + '\n'
serialize: (frameIndex, trackedPropertiesThangIDs, trackedPropertiesPerThangIndices, trackedPropertiesPerThangTypes, trackedPropertiesPerThangValues, specialValuesToKeys, specialKeysToValues) ->
# Optimize

View file

@ -2,7 +2,7 @@
{scriptMatchesEventPrereqs} = require './script_event_prereqs'
module.exports = class WorldScriptNote
@className: "WorldScriptNote"
@className: 'WorldScriptNote'
constructor: (script, @event, world) ->
return unless script?
@invalid = true

View file

@ -78,17 +78,17 @@ module.exports.consolidateThangs = consolidateThangs = (thangs) ->
topmost = _.max structural, (t) -> t.pos.y + t.height / 2
leftmost = _.min structural, (t) -> t.pos.x - t.width / 2
bottommost = _.min structural, (t) -> t.pos.y - t.height / 2
console.log "got rightmost", rightmost.id, "topmost", topmost.id, "lefmostmost", leftmost.id, "bottommost", bottommost.id, "out of", structural.length, "structural thangs" if debug
console.log 'got rightmost', rightmost.id, 'topmost', topmost.id, 'lefmostmost', leftmost.id, 'bottommost', bottommost.id, 'out of', structural.length, 'structural thangs' if debug
left = Math.min 0, leftmost.pos.x - leftmost.width / 2
bottom = Math.min 0, bottommost.pos.y - bottommost.height / 2
if (left < 0) or (bottom < 0)
console.error "Negative structural Thangs aren't supported, sorry!" # TODO: largestRectangle, AI System, and anything else that accesses grid directly need updating to finish this
console.error 'Negative structural Thangs aren\'t supported, sorry!' # TODO: largestRectangle, AI System, and anything else that accesses grid directly need updating to finish this
left = 0
bottom = 0
width = rightmost.pos.x + rightmost.width / 2 - left
height = topmost.pos.y + topmost.height / 2 - bottom
padding = 0
console.log "got max width", width, "height", height, "left", left, "bottom", bottom, "of thangs", thangs.length, "structural", structural.length if debug
console.log 'got max width', width, 'height', height, 'left', left, 'bottom', bottom, 'of thangs', thangs.length, 'structural', structural.length if debug
grid = new Grid structural, width, height, padding, left, bottom
console.log grid.toString() if debug
@ -107,14 +107,14 @@ module.exports.consolidateThangs = consolidateThangs = (thangs) ->
grid.grid[y2][x2] = []
console.log grid.toString() if debug
thang = structural[dissection.length] # grab one we already know is configured properly
console.error "Hmm, our dissection has more Thangs than the original structural Thangs?", dissection.length unless thang
console.error 'Hmm, our dissection has more Thangs than the original structural Thangs?', dissection.length unless thang
thang.width = rect.width
thang.height = rect.height
thang.pos.x = rect.x
thang.pos.y = rect.y
thang.createBodyDef()
dissection.push thang
console.log "Turned", structural.length, "structural Thangs into", dissection.length, "dissecting Thangs."
console.log 'Turned', structural.length, 'structural Thangs into', dissection.length, 'dissecting Thangs.'
thangs.push dissection...
structural[dissection.length ... structural.length]
@ -133,7 +133,7 @@ module.exports.largestRectangle = largestRectangle = (grid, bottomY, leftX, want
break unless coveredRow
coveredRows.push coveredRow
shortestCoveredRow = Math.min(shortestCoveredRow, coveredRow)
console.log "largestRectangle() for", bottomY, leftX, "got coveredRows", coveredRows if debug
console.log 'largestRectangle() for', bottomY, leftX, 'got coveredRows', coveredRows if debug
[maxArea, maxAreaRows, maxAreaRowLength, shortestRow] = [0, 0, 0, 0]
for rowLength, rowIndex in coveredRows
shortestRow ||= rowLength
@ -143,7 +143,7 @@ module.exports.largestRectangle = largestRectangle = (grid, bottomY, leftX, want
maxAreaRowLength = shortestRow
maxArea = area
shortestRow = Math.min(rowLength, shortestRow)
console.log "So largest rect has area", maxArea, "with", maxAreaRows, "rows of length", maxAreaRowLength if debug
console.log 'So largest rect has area', maxArea, 'with', maxAreaRows, 'rows of length', maxAreaRowLength if debug
rect = new Rectangle leftX + maxAreaRowLength / 2, bottomY + maxAreaRows / 2, maxAreaRowLength, maxAreaRows
console.log "That corresponds to a rectangle", rect.toString() if debug
console.log 'That corresponds to a rectangle', rect.toString() if debug
rect

View file

@ -1,7 +1,7 @@
CocoModel = require('./CocoModel')
CocoModel = require './CocoModel'
module.exports = class Article extends CocoModel
@className: "Article"
@className: 'Article'
@schema: require 'schemas/models/article'
urlRoot: "/db/article"
urlRoot: '/db/article'
saveBackups: true

View file

@ -4,7 +4,7 @@ deltasLib = require 'lib/deltas'
NewAchievementCollection = require '../collections/NewAchievementCollection'
class CocoModel extends Backbone.Model
idAttribute: "_id"
idAttribute: '_id'
loaded: false
loading: false
saveBackups: false
@ -55,7 +55,7 @@ class CocoModel extends Backbone.Model
return unless @saveBackups
existing = storage.load @id
if existing
@set(existing, {silent:true})
@set(existing, {silent: true})
CocoModel.backedUp[@id] = @
saveBackup: -> @saveBackupNow()
@ -76,7 +76,7 @@ class CocoModel extends Backbone.Model
if errors?.length
console.debug "Validation failed for #{@constructor.className}: '#{@get('name') or @}'."
for error in errors
console.debug "\t", error.dataPath, ":", error.message
console.debug "\t", error.dataPath, ':', error.message
return errors
save: (attrs, options) ->
@ -86,7 +86,7 @@ class CocoModel extends Backbone.Model
success = options.success
error = options.error
options.success = (model, res) =>
@trigger "save:success", @
@trigger 'save:success', @
success(@, res) if success
@markToRevert() if @_revertAttributes
@clearBackup()
@ -97,7 +97,7 @@ class CocoModel extends Backbone.Model
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
patch: (options) ->
@ -139,7 +139,6 @@ class CocoModel extends Backbone.Model
cloneNewMinorVersion: ->
newData = _.clone @attributes
clone = new @constructor(newData)
clone
@ -154,20 +153,20 @@ class CocoModel extends Backbone.Model
false
publish: ->
if @isPublished() then throw new Error("Can't publish what's already-published. Can't kill what's already dead.")
@set "permissions", (@get("permissions") or []).concat({access: 'read', target: 'public'})
if @isPublished() then throw new Error('Can\'t publish what\'s already-published. Can\'t kill what\'s already dead.')
@set 'permissions', (@get('permissions') or []).concat({access: 'read', target: 'public'})
addSchemaDefaults: ->
return if @addedSchemaDefaults
@addedSchemaDefaults = true
for prop, defaultValue of @constructor.schema.default or {}
continue if @get(prop)?
#console.log "setting", prop, "to", defaultValue, "from attributes.default"
#console.log 'setting', prop, 'to', defaultValue, 'from attributes.default'
@set prop, defaultValue
for prop, sch of @constructor.schema.properties or {}
continue if @get(prop)?
continue if prop is 'emails' # hack, defaults are handled through User.coffee's email-specific methods.
#console.log "setting", prop, "to", sch.default, "from sch.default" if sch.default?
#console.log 'setting', prop, 'to', sch.default, 'from sch.default' if sch.default?
@set prop, sch.default if sch.default?
if @loaded
@loadFromBackup()
@ -212,7 +211,7 @@ class CocoModel extends Backbone.Model
try
jsondiffpatch.patch newAttributes, delta
catch error
console.error "Error applying delta", delta, "to attributes", newAttributes, error
console.error 'Error applying delta', delta, 'to attributes', newAttributes, error
return false
@set newAttributes
return true
@ -226,7 +225,7 @@ class CocoModel extends Backbone.Model
deltasLib.expandDelta(delta, @attributes, @schema())
watch: (doWatch=true) ->
$.ajax("#{@urlRoot}/#{@id}/watch", {type:'PUT', data:{on:doWatch}})
$.ajax("#{@urlRoot}/#{@id}/watch", {type: 'PUT', data: {on: doWatch}})
@watching = -> doWatch
watching: ->
@ -256,9 +255,9 @@ class CocoModel extends Backbone.Model
@getReferencedModel: (data, schema) ->
return null unless schema.links?
linkObject = _.find schema.links, rel: "db"
linkObject = _.find schema.links, rel: 'db'
return null unless linkObject
return null if linkObject.href.match("thang.type") and not @isObjectID(data) # Skip loading hardcoded Thang Types for now (TODO)
return null if linkObject.href.match('thang.type') and not @isObjectID(data) # Skip loading hardcoded Thang Types for now (TODO)
# not fully extensible, but we can worry about that later
link = linkObject.href
@ -298,7 +297,6 @@ class CocoModel extends Backbone.Model
me.fetch (success: -> Backbone.Mediator.publish('achievements:new', collection)) unless _.isEmpty(collection.models)
)
CocoModel.pollAchievements = _.debounce CocoModel.pollAchievements, 500
module.exports = CocoModel

View file

@ -1,6 +1,6 @@
CocoModel = require('./CocoModel')
CocoModel = require './CocoModel'
module.exports = class File extends CocoModel
@className: "File"
@className: 'File'
@schema: {}
urlRoot: "/db/file"
urlRoot: '/db/file'

View file

@ -4,10 +4,10 @@ LevelSystem = require './LevelSystem'
ThangType = require './ThangType'
module.exports = class Level extends CocoModel
@className: "Level"
@className: 'Level'
@schema: require 'schemas/models/level'
urlRoot: "/db/level"
urlRoot: '/db/level'
serialize: (supermodel) ->
# o = _.cloneDeep @attributes # slow in level editor when there are hundreds of Thangs
o = $.extend true, {}, @attributes
@ -23,7 +23,6 @@ module.exports = class Level extends CocoModel
@fillInDefaultSystemConfiguration o.systems
o.thangTypes = (original: tt.get('original'), name: tt.get('name') for tt in supermodel.getModels ThangType)
o
sortSystems: (levelSystems, systemModels) ->
@ -31,11 +30,11 @@ module.exports = class Level extends CocoModel
visit = (system) ->
return if system.original of originalsSeen
systemModel = _.find systemModels, {original: system.original}
console.error "Couldn't find model for original", system.original, "from", systemModels unless systemModel
console.error 'Couldn\'t find model for original', system.original, 'from', systemModels unless systemModel
for d in systemModel.dependencies or []
system2 = _.find levelSystems, {original: d.original}
visit system2
#console.log "sorted systems adding", systemModel.name
#console.log 'sorted systems adding', systemModel.name
sorted.push {model: systemModel, config: _.cloneDeep system.config}
originalsSeen[system.original] = true
visit system for system in levelSystems
@ -54,21 +53,21 @@ module.exports = class Level extends CocoModel
visit = (c) ->
return if c in sorted
lc = _.find levelComponents, {original: c.original}
console.error thang.id, "couldn't find lc for", c unless lc
if lc.name is "Programmable"
console.error thang.id, 'couldn\'t find lc for', c unless lc
if lc.name is 'Programmable'
# Programmable always comes last
visit c2 for c2 in _.without thang.components, c
else
for d in lc.dependencies or []
c2 = _.find thang.components, {original: d.original}
console.error thang.id, "couldn't find dependent Component", d.original, "from", lc.name unless c2
console.error thang.id, 'couldn\'t find dependent Component', d.original, 'from', lc.name unless c2
visit c2
if lc.name is "Collides"
allied = _.find levelComponents, {name: "Allied"}
if lc.name is 'Collides'
allied = _.find levelComponents, {name: 'Allied'}
if allied
collides = _.find(thang.components, {original: allied.original})
visit collides if collides
#console.log thang.id, "sorted comps adding", lc.name
#console.log thang.id, 'sorted comps adding', lc.name
sorted.push c
for comp in thang.components
visit comp
@ -90,7 +89,7 @@ module.exports = class Level extends CocoModel
return unless properties
for prop, schema of properties
if schema.default? and config[prop] is undefined
#console.log "Setting default of", config, "for", prop, "to", schema.default
#console.log 'Setting default of', config, 'for', prop, 'to', schema.default
config[prop] = schema.default
if schema.type is 'object' and config[prop]
@walkDefaults config[prop], schema.properties
@ -107,4 +106,4 @@ module.exports = class Level extends CocoModel
continue unless c?
width = c.width if c.width? and c.width > width
height = c.height if c.height? and c.height > height
return {width:width, height:height}
return {width: width, height: height}

View file

@ -1,9 +1,9 @@
CocoModel = require('./CocoModel')
CocoModel = require './CocoModel'
module.exports = class LevelComponent extends CocoModel
@className: "LevelComponent"
@className: 'LevelComponent'
@schema: require 'schemas/models/level_component'
urlRoot: "/db/level.component"
urlRoot: '/db/level.component'
set: (key, val, options) ->
if _.isObject key
@ -20,11 +20,11 @@ module.exports = class LevelComponent extends CocoModel
compile: (code) ->
if @get('codeLanguage') and @get('codeLanguage') isnt 'coffeescript'
return console.error("Can't compile", @get('codeLanguage'), "-- only CoffeeScript.", @)
return console.error('Can\'t compile', @get('codeLanguage'), '-- only CoffeeScript.', @)
try
js = CoffeeScript.compile(code, bare: true)
catch e
#console.log "couldn't compile", code, "for", @get('name'), "because", e
#console.log 'couldn\'t compile', code, 'for', @get('name'), 'because', e
js = @get 'js'
js

View file

@ -1,6 +1,6 @@
CocoModel = require('./CocoModel')
CocoModel = require './CocoModel'
module.exports = class LevelFeedback extends CocoModel
@className: "LevelFeedback"
@className: 'LevelFeedback'
@schema: require 'schemas/models/level_feedback'
urlRoot: "/db/level.feedback"
urlRoot: '/db/level.feedback'

View file

@ -1,9 +1,9 @@
CocoModel = require('./CocoModel')
CocoModel = require './CocoModel'
module.exports = class LevelSession extends CocoModel
@className: "LevelSession"
@className: 'LevelSession'
@schema: require 'schemas/models/level_session'
urlRoot: "/db/level.session"
urlRoot: '/db/level.session'
initialize: ->
super()
@ -16,7 +16,7 @@ module.exports = class LevelSession extends CocoModel
permissions = @get 'permissions'
permissions = (p for p in permissions when p.target isnt 'public')
if @get('multiplayer')
permissions.push {target:'public', access:'write'}
permissions.push {target: 'public', access: 'write'}
@set 'permissions', permissions
getSourceFor: (spellKey) ->
@ -30,7 +30,7 @@ module.exports = class LevelSession extends CocoModel
return false unless c1 = @get('code')
return false unless team = @get('team')
return true unless c2 = @get('submittedCode')
thangSpellArr = (s.split("/") for s in @get('teamSpells')[team])
thangSpellArr = (s.split('/') for s in @get('teamSpells')[team])
for item in thangSpellArr
thang = item[0]
spell = item[1]

View file

@ -1,10 +1,10 @@
CocoModel = require('./CocoModel')
SystemNameLoader = require('lib/SystemNameLoader')
CocoModel = require './CocoModel'
SystemNameLoader = require 'lib/SystemNameLoader'
module.exports = class LevelSystem extends CocoModel
@className: "LevelSystem"
@className: 'LevelSystem'
@schema: require 'schemas/models/level_system'
urlRoot: "/db/level.system"
urlRoot: '/db/level.system'
set: (key, val, options) ->
if _.isObject key
@ -22,11 +22,11 @@ module.exports = class LevelSystem extends CocoModel
compile: (code) ->
if @get('codeLanguage') and @get('codeLanguage') isnt 'coffeescript'
return console.error("Can't compile", @get('codeLanguage'), "-- only CoffeeScript.", @)
return console.error('Can\'t compile', @get('codeLanguage'), '-- only CoffeeScript.', @)
try
js = CoffeeScript.compile(code, bare: true)
catch e
#console.log "couldn't compile", code, "for", @get('name'), "because", e
#console.log 'couldn\'t compile', code, 'for', @get('name'), 'because', e
js = @get 'js'
js

View file

@ -1,12 +1,12 @@
CocoModel = require('./CocoModel')
CocoModel = require './CocoModel'
module.exports = class PatchModel extends CocoModel
@className: "Patch"
@className: 'Patch'
@schema: require 'schemas/models/patch'
urlRoot: "/db/patch"
urlRoot: '/db/patch'
setStatus: (status) ->
PatchModel.setStatus @id, status
@setStatus: (id, status) ->
$.ajax("/db/patch/#{id}/status", {type:"PUT", data: {status:status}})
$.ajax("/db/patch/#{id}/status", {type: 'PUT', data: {status: status}})

View file

@ -19,11 +19,11 @@ module.exports = class SuperModel extends Backbone.Model
report: ->
# Useful for debugging why a SuperModel never finishes loading.
console.info "SuperModel report ------------------------"
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
console.info "\t", resource.name, 'loaded', resource.isLoaded
unfinished.push resource unless resource.isLoaded
unfinished
@ -38,7 +38,6 @@ module.exports = class SuperModel extends Backbone.Model
res = @addModelResource(cachedModel, name, fetchOptions, value)
res.markLoading()
return res
else
@registerModel(model)
res = @addModelResource(model, name, fetchOptions, value)
@ -57,7 +56,6 @@ module.exports = class SuperModel extends Backbone.Model
res = @addModelResource(cachedCollection, name, fetchOptions, value)
res.markLoading()
return res
else
@addCollection collection
@listenToOnce collection, 'sync', (c) ->
@ -196,8 +194,6 @@ module.exports = class SuperModel extends Backbone.Model
getResource: (rid) ->
return @resources[rid]
class Resource extends Backbone.Model
constructor: (name, value=1) ->
@name = name
@ -230,8 +226,6 @@ class Resource extends Backbone.Model
load: -> @
class ModelResource extends Resource
constructor: (modelOrCollection, name, fetchOptions, value)->
super(name, value)
@ -253,7 +247,6 @@ class ModelResource extends Resource
@jqxhr = null
@model.jqxhr = null
class RequestResource extends Resource
constructor: (name, jqxhrOptions, value) ->
super(name, value)
@ -267,6 +260,4 @@ class RequestResource extends Resource
@jqxhr.fail => _.defer => @markFailed()
@
class SomethingResource extends Resource

View file

@ -1,12 +1,12 @@
CocoModel = require('./CocoModel')
CocoModel = require './CocoModel'
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
buildQueue = []
module.exports = class ThangType extends CocoModel
@className: "ThangType"
@className: 'ThangType'
@schema: require 'schemas/models/thang_type'
urlRoot: "/db/thang.type"
urlRoot: '/db/thang.type'
building: {}
initialize: ->
@ -27,7 +27,7 @@ module.exports = class ThangType extends CocoModel
@resetRawData() unless @get('raw')
resetRawData: ->
@set('raw', {shapes:{}, containers:{}, animations:{}})
@set('raw', {shapes: {}, containers: {}, animations: {}})
resetSpriteSheetCache: ->
@buildActions()
@ -48,7 +48,7 @@ module.exports = class ThangType extends CocoModel
for name, action of @actions
action.name = name
for relatedName, relatedAction of action.relatedActions ? {}
relatedAction.name = action.name + "_" + relatedName
relatedAction.name = action.name + '_' + relatedName
@actions[relatedAction.name] = relatedAction
@actions
@ -114,12 +114,12 @@ module.exports = class ThangType extends CocoModel
mc = @vectorParser.buildMovieClip name
continue unless mc
@builder.addMovieClip mc, null, animation.scale * @options.resolutionFactor
framesMap[animation.scale + "_" + name] = @builder._animations[name].frames
framesMap[animation.scale + '_' + name] = @builder._animations[name].frames
for name, action of @actions when action.animation
continue if name is 'portrait'
scale = action.scale ? @get('scale') ? 1
frames = framesMap[scale + "_" + action.animation]
frames = framesMap[scale + '_' + action.animation]
continue unless frames
frames = @mapFrames(action.frames, frames[0]) if action.frames?
next = true
@ -179,7 +179,7 @@ module.exports = class ThangType extends CocoModel
buildQueue[0]?.buildAsync()
@spriteSheets[key] = e.target.spriteSheet
@building[key] = false
@trigger 'build-complete', {key:key, thangType:@}
@trigger 'build-complete', {key: key, thangType: @}
@vectorParser = null
logBuild: (startTime, async, portrait) ->
@ -249,14 +249,14 @@ module.exports = class ThangType extends CocoModel
path: "db/thang.type/#{@get('original')}"
b64png: src
force: 'true'
$.ajax('/file', { type: 'POST', data: body, success: callback or @onFileUploaded })
$.ajax('/file', {type: 'POST', data: body, success: callback or @onFileUploaded})
onFileUploaded: =>
console.log 'Image uploaded'
@loadUniversalWizard: ->
return @wizardType if @wizardType
wizOriginal = "52a00d55cf1818f2be00000b"
wizOriginal = '52a00d55cf1818f2be00000b'
url = "/db/thang.type/#{wizOriginal}/version"
@wizardType = new module.exports()
@wizardType.url = -> url

View file

@ -1,11 +1,11 @@
GRAVATAR_URL = 'https://www.gravatar.com/'
cache = {}
CocoModel = require('./CocoModel')
CocoModel = require './CocoModel'
module.exports = class User extends CocoModel
@className: "User"
@className: 'User'
@schema: require 'schemas/models/user'
urlRoot: "/db/user"
urlRoot: '/db/user'
initialize: ->
super()
@ -16,24 +16,24 @@ module.exports = class User extends CocoModel
return 'admin' in permissions
displayName: ->
@get('name') or "Anoner"
@get('name') or 'Anoner'
lang: ->
@get('preferredLanguage') or "en-US"
@get('preferredLanguage') or 'en-US'
getPhotoURL: (size=80, useJobProfilePhoto=false) ->
photoURL = if useJobProfilePhoto then @get('jobProfile')?.photoURL else null
photoURL ||= @get('photoURL')
if photoURL
prefix = if photoURL.search(/\?/) is -1 then "?" else "&"
prefix = if photoURL.search(/\?/) is -1 then '?' else '&'
return "#{photoURL}#{prefix}s=#{size}" if photoURL.search('http') isnt -1 # legacy
return "/file/#{photoURL}#{prefix}s=#{size}"
return "/db/user/#{@id}/avatar?s=#{size}"
@getByID = (id, properties, force) ->
{me} = require('lib/auth')
{me} = require 'lib/auth'
return me if me.id is id
user = cache[id] or new module.exports({_id:id})
user = cache[id] or new module.exports({_id: id})
if force or not cache[id]
user.loading = true
user.fetch(
@ -44,18 +44,18 @@ module.exports = class User extends CocoModel
)
cache[id] = user
user
getEnabledEmails: ->
@migrateEmails()
emails = _.clone(@get('emails')) or {}
emails = _.defaults emails, @schema().properties.emails.default
(emailName for emailName, emailDoc of emails when emailDoc.enabled)
setEmailSubscription: (name, enabled) ->
newSubs = _.clone(@get('emails')) or {}
(newSubs[name] ?= {}).enabled = enabled
@set 'emails', newSubs
emailMap:
announcement: 'generalNews'
developer: 'archmageNews'
@ -70,9 +70,9 @@ module.exports = class User extends CocoModel
return if @attributes.emails or not @attributes.emailSubscriptions
oldSubs = @get('emailSubscriptions') or []
newSubs = {}
newSubs[newSubName] = { enabled: oldSubName in oldSubs } for oldSubName, newSubName of @emailMap
newSubs[newSubName] = {enabled: oldSubName in oldSubs} for oldSubName, newSubName of @emailMap
@set('emails', newSubs)
isEmailSubscriptionEnabled: (name) -> (@get('emails') or {})[name]?.enabled
a = 5

View file

@ -1,6 +1,6 @@
CocoModel = require('./CocoModel')
CocoModel = require './CocoModel'
module.exports = class UserRemark extends CocoModel
@className: "UserRemark"
@className: 'UserRemark'
@schema: require 'schemas/models/user_remark'
urlRoot: "/db/user.remark"
urlRoot: '/db/user.remark'

View file

@ -1,14 +1,14 @@
module.exports =
bus:
title: "Bus"
id: "bus"
$schema: "http://json-schema.org/draft-04/schema#"
description: "Bus" # TODO
type: "object"
title: 'Bus'
id: 'bus'
$schema: 'http://json-schema.org/draft-04/schema#'
description: 'Bus' # TODO
type: 'object'
properties: # TODO
joined:
type: ["boolean", "null"]
type: ['boolean', 'null']
players:
type: "object"
required: ["joined", "players"]
type: 'object'
required: ['joined', 'players']
additionalProperties: true

View file

@ -1,12 +1,12 @@
module.exports =
jQueryEvent:
title: "jQuery Event"
id: "jQueryEvent"
$schema: "http://json-schema.org/draft-04/schema#"
description: "A standard jQuery Event"
type: "object"
title: 'jQuery Event'
id: 'jQueryEvent'
$schema: 'http://json-schema.org/draft-04/schema#'
description: 'A standard jQuery Event'
type: 'object'
properties: # TODO schema complete
altKey:
type: "boolean"
type: 'boolean'
required: []
additionalProperties: true

View file

@ -3,26 +3,24 @@ c = require './schemas'
languageCodeArrayRegex = c.generateLanguageCodeArrayRegex()
ExampleSchema = {
title: "Example Schema",
description:"An example schema",
type: "object",
title: 'Example Schema',
description: 'An example schema',
type: 'object',
properties: {
text: {
title: "Text",
description: "A short message to display in the dialogue area. Markdown okay.",
type: "string",
title: 'Text',
description: 'A short message to display in the dialogue area. Markdown okay.',
type: 'string',
maxLength: 400
},
i18n: {"$ref": "#/definitions/i18n"}
i18n: {'$ref': '#/definitions/i18n'}
},
definitions: {
i18n: {
title: "i18n",
description: "The internationalization object",
type: "object",
title: 'i18n',
description: 'The internationalization object',
type: 'object',
patternProperties: {
languageCodeArrayRegex: {
additionalProperties: false,
@ -30,19 +28,18 @@ ExampleSchema = {
#put the translatable properties here
#if it is possible to not include i18n with a reference
# to #/properties, you could just do
properties: {"$ref":"#/properties"}
# text: {"$ref": "#/properties/text"}
properties: {'$ref': '#/properties'}
# text: {'$ref': '#/properties/text'}
}
default: {
title: "LanguageCode",
description: "LanguageDescription"
title: 'LanguageCode',
description: 'LanguageDescription'
}
}
}
}
},
}
}
#define a i18n object type for each schema, then have the i18n have it's oneOf check against
#translatable schemas of that object
#translatable schemas of that object

View file

@ -1,132 +1,132 @@
# The JSON Schema Core/Validation Meta-Schema, but with titles and descriptions added to make it easier to edit in Treema, and in CoffeeScript
module.exports =
id: "metaschema"
displayProperty: "title"
$schema: "http://json-schema.org/draft-04/schema#"
title: "Schema"
description: "Core schema meta-schema"
id: 'metaschema'
displayProperty: 'title'
$schema: 'http://json-schema.org/draft-04/schema#'
title: 'Schema'
description: 'Core schema meta-schema'
definitions:
schemaArray:
type: "array"
type: 'array'
minItems: 1
items: { $ref: "#" }
title: "Array of Schemas"
"default": [{}]
items: {$ref: '#'}
title: 'Array of Schemas'
'default': [{}]
positiveInteger:
type: "integer"
type: 'integer'
minimum: 0
title: "Positive Integer"
title: 'Positive Integer'
positiveIntegerDefault0:
allOf: [ { $ref: "#/definitions/positiveInteger" }, { "default": 0 } ]
allOf: [{$ref: '#/definitions/positiveInteger'}, {'default': 0}]
simpleTypes:
title: "Single Type"
"enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
title: 'Single Type'
'enum': ['array', 'boolean', 'integer', 'null', 'number', 'object', 'string']
stringArray:
type: "array"
items: { type: "string" }
type: 'array'
items: {type: 'string'}
minItems: 1
uniqueItems: true
title: "String Array"
"default": ['']
type: "object"
title: 'String Array'
'default': ['']
type: 'object'
properties:
id:
type: "string"
format: "uri"
type: 'string'
format: 'uri'
$schema:
type: "string"
format: "uri"
"default": "http://json-schema.org/draft-04/schema#"
type: 'string'
format: 'uri'
'default': 'http://json-schema.org/draft-04/schema#'
title:
type: "string"
type: 'string'
description:
type: "string"
"default": {}
type: 'string'
'default': {}
multipleOf:
type: "number"
type: 'number'
minimum: 0
exclusiveMinimum: true
maximum:
type: "number"
type: 'number'
exclusiveMaximum:
type: "boolean"
"default": false
type: 'boolean'
'default': false
minimum:
type: "number"
type: 'number'
exclusiveMinimum:
type: "boolean"
"default": false
maxLength: { $ref: "#/definitions/positiveInteger" }
minLength: { $ref: "#/definitions/positiveIntegerDefault0" }
type: 'boolean'
'default': false
maxLength: {$ref: '#/definitions/positiveInteger'}
minLength: {$ref: '#/definitions/positiveIntegerDefault0'}
pattern:
type: "string"
format: "regex"
type: 'string'
format: 'regex'
additionalItems:
anyOf: [
{ type: "boolean", "default": false }
{ $ref: "#" }
{type: 'boolean', 'default': false}
{$ref: '#'}
]
items:
anyOf: [
{ $ref: "#" }
{ $ref: "#/definitions/schemaArray" }
{$ref: '#'}
{$ref: '#/definitions/schemaArray'}
]
"default": {}
maxItems: { $ref: "#/definitions/positiveInteger" }
minItems: { $ref: "#/definitions/positiveIntegerDefault0" }
'default': {}
maxItems: {$ref: '#/definitions/positiveInteger'}
minItems: {$ref: '#/definitions/positiveIntegerDefault0'}
uniqueItems:
type: "boolean"
"default": false
maxProperties: { $ref: "#/definitions/positiveInteger" }
minProperties: { $ref: "#/definitions/positiveIntegerDefault0" }
required: { $ref: "#/definitions/stringArray" }
type: 'boolean'
'default': false
maxProperties: {$ref: '#/definitions/positiveInteger'}
minProperties: {$ref: '#/definitions/positiveIntegerDefault0'}
required: {$ref: '#/definitions/stringArray'}
additionalProperties:
anyOf: [
{ type: "boolean", "default": true }
{ $ref: "#" }
{type: 'boolean', 'default': true}
{$ref: '#'}
]
"default": {}
'default': {}
definitions:
type: "object"
additionalProperties: { $ref: "#" }
"default": {}
type: 'object'
additionalProperties: {$ref: '#'}
'default': {}
properties:
type: "object"
additionalProperties: { $ref: "#" }
"default": {}
type: 'object'
additionalProperties: {$ref: '#'}
'default': {}
patternProperties:
type: "object"
additionalProperties: { $ref: "#" }
"default": {}
type: 'object'
additionalProperties: {$ref: '#'}
'default': {}
dependencies:
type: "object"
type: 'object'
additionalProperties:
anyOf: [
{ $ref: "#" }
{ $ref: "#/definitions/stringArray" }
{$ref: '#'}
{$ref: '#/definitions/stringArray'}
]
"enum":
type: "array"
'enum':
type: 'array'
minItems: 1
uniqueItems: true
"default": ['']
'default': ['']
type:
anyOf: [
{ $ref: "#/definitions/simpleTypes" }
{$ref: '#/definitions/simpleTypes'}
{
type: "array"
items: { $ref: "#/definitions/simpleTypes" }
type: 'array'
items: {$ref: '#/definitions/simpleTypes'}
minItems: 1
uniqueItems: true
title: "Array of Types"
"default": ['string']
title: 'Array of Types'
'default': ['string']
}]
allOf: { $ref: "#/definitions/schemaArray" }
anyOf: { $ref: "#/definitions/schemaArray" }
oneOf: { $ref: "#/definitions/schemaArray" }
not: { $ref: "#" }
allOf: {$ref: '#/definitions/schemaArray'}
anyOf: {$ref: '#/definitions/schemaArray'}
oneOf: {$ref: '#/definitions/schemaArray'}
not: {$ref: '#'}
dependencies:
exclusiveMaximum: [ "maximum" ]
exclusiveMinimum: [ "minimum" ]
"default": {}
exclusiveMaximum: ['maximum']
exclusiveMinimum: ['minimum']
'default': {}

View file

@ -11,7 +11,7 @@ MongoQueryOperatorSchema =
'$in': type: 'array'
'$lt': type: 'number'
'$lte': type: 'number'
'$ne': type: [ 'number', 'string' ]
'$ne': type: ['number', 'string']
'$nin': type: 'array'
additionalProperties: true # TODO set to false when the schema's done
@ -23,9 +23,9 @@ MongoFindQuerySchema =
#'^[-a-zA-Z0-9_]*$':
'^[-a-zA-Z0-9\.]*$':
oneOf: [
#{ $ref: '#/definitions/' + MongoQueryOperatorSchema.id},
{ type: 'string' }
{ type: 'object' }
#{$ref: '#/definitions/' + MongoQueryOperatorSchema.id},
{type: 'string'},
{type: 'object'}
]
additionalProperties: true # TODO make Treema accept new pattern matched keys
definitions: {}
@ -41,12 +41,12 @@ _.extend(AchievementSchema.properties,
query:
#type:'object'
$ref: '#/definitions/' + MongoFindQuerySchema.id
worth: { type: 'number' }
collection: { type: 'string' }
description: { type: 'string' }
userField: { type: 'string' }
worth: {type: 'number'}
collection: {type: 'string'}
description: {type: 'string'}
userField: {type: 'string'}
related: c.objectId(description: 'Related entity')
icon: { type: 'string', format: 'image-file', title: 'Icon' }
icon: {type: 'string', format: 'image-file', title: 'Icon'}
proportionalTo:
type: 'string'
description: 'For repeatables only. Denotes the field a repeatable achievement needs for its calculations'

View file

@ -3,8 +3,8 @@ c = require './../schemas'
ArticleSchema = c.object()
c.extendNamedProperties ArticleSchema # name first
ArticleSchema.properties.body = { type: 'string', title: 'Content', format: 'markdown' }
ArticleSchema.properties.i18n = { type: 'object', title: 'i18n', format: 'i18n', props: ['name', 'body'] }
ArticleSchema.properties.body = {type: 'string', title: 'Content', format: 'markdown'}
ArticleSchema.properties.i18n = {type: 'object', title: 'i18n', format: 'i18n', props: ['name', 'body']}
c.extendBasicProperties ArticleSchema, 'article'
c.extendSearchableProperties ArticleSchema

View file

@ -9,7 +9,7 @@ module.exports =
[
{
rel: 'extra'
href: "/db/user/{($)}"
href: '/db/user/{($)}'
}
]
achievement: c.objectId

View file

@ -3,242 +3,242 @@ ThangComponentSchema = require './thang_component'
SpecificArticleSchema = c.object()
c.extendNamedProperties SpecificArticleSchema # name first
SpecificArticleSchema.properties.body = { type: 'string', title: 'Content', description: "The body content of the article, in Markdown.", format: 'markdown' }
SpecificArticleSchema.properties.i18n = {type: "object", format: 'i18n', props: ['name', 'body'], description: "Help translate this article"}
SpecificArticleSchema.properties.body = {type: 'string', title: 'Content', description: 'The body content of the article, in Markdown.', format: 'markdown'}
SpecificArticleSchema.properties.i18n = {type: 'object', format: 'i18n', props: ['name', 'body'], description: 'Help translate this article'}
SpecificArticleSchema.displayProperty = 'name'
side = {title: "Side", description: "A side.", type: 'string', 'enum': ['left', 'right', 'top', 'bottom']}
thang = {title: "Thang", description: "The name of a Thang.", type: 'string', maxLength: 30, format:'thang'}
side = {title: 'Side', description: 'A side.', type: 'string', 'enum': ['left', 'right', 'top', 'bottom']}
thang = {title: 'Thang', description: 'The name of a Thang.', type: 'string', maxLength: 30, format: 'thang'}
eventPrereqValueTypes = ["boolean", "integer", "number", "null", "string"] # not "object" or "array"
EventPrereqSchema = c.object {title: "Event Prerequisite", format: 'event-prereq', description: "Script requires that the value of some property on the event triggering it to meet some prerequisite.", "default": {eventProps: []}, required: ["eventProps"]},
eventProps: c.array {'default': ["thang"], format:'event-value-chain', maxItems: 10, title: "Event Property", description: 'A chain of keys in the event, like "thang.pos.x" to access event.thang.pos.x.'}, c.shortString(title: "Property", description: "A key in the event property key chain.")
equalTo: c.object {type: eventPrereqValueTypes, title: "==", description: "Script requires the event's property chain value to be equal to this value."}
notEqualTo: c.object {type: eventPrereqValueTypes, title: "!=", description: "Script requires the event's property chain value to *not* be equal to this value."}
greaterThan: {type: 'number', title: ">", description: "Script requires the event's property chain value to be greater than this value."}
greaterThanOrEqualTo: {type: 'number', title: ">=", description: "Script requires the event's property chain value to be greater or equal to this value."}
lessThan: {type: 'number', title: "<", description: "Script requires the event's property chain value to be less than this value."}
lessThanOrEqualTo: {type: 'number', title: "<=", description: "Script requires the event's property chain value to be less than or equal to this value."}
containingString: c.shortString(title: "Contains", description: "Script requires the event's property chain value to be a string containing this string.")
notContainingString: c.shortString(title: "Does not contain", description: "Script requires the event's property chain value to *not* be a string containing this string.")
containingRegexp: c.shortString(title: "Contains Regexp", description: "Script requires the event's property chain value to be a string containing this regular expression.")
notContainingRegexp: c.shortString(title: "Does not contain regexp", description: "Script requires the event's property chain value to *not* be a string containing this regular expression.")
eventPrereqValueTypes = ['boolean', 'integer', 'number', 'null', 'string'] # not 'object' or 'array'
EventPrereqSchema = c.object {title: 'Event Prerequisite', format: 'event-prereq', description: 'Script requires that the value of some property on the event triggering it to meet some prerequisite.', 'default': {eventProps: []}, required: ['eventProps']},
eventProps: c.array {'default': ['thang'], format: 'event-value-chain', maxItems: 10, title: 'Event Property', description: 'A chain of keys in the event, like "thang.pos.x" to access event.thang.pos.x.'}, c.shortString(title: 'Property', description: 'A key in the event property key chain.')
equalTo: c.object {type: eventPrereqValueTypes, title: '==', description: 'Script requires the event\'s property chain value to be equal to this value.'}
notEqualTo: c.object {type: eventPrereqValueTypes, title: '!=', description: 'Script requires the event\'s property chain value to *not* be equal to this value.'}
greaterThan: {type: 'number', title: '>', description: 'Script requires the event\'s property chain value to be greater than this value.'}
greaterThanOrEqualTo: {type: 'number', title: '>=', description: 'Script requires the event\'s property chain value to be greater or equal to this value.'}
lessThan: {type: 'number', title: '<', description: 'Script requires the event\'s property chain value to be less than this value.'}
lessThanOrEqualTo: {type: 'number', title: '<=', description: 'Script requires the event\'s property chain value to be less than or equal to this value.'}
containingString: c.shortString(title: 'Contains', description: 'Script requires the event\'s property chain value to be a string containing this string.')
notContainingString: c.shortString(title: 'Does not contain', description: 'Script requires the event\'s property chain value to *not* be a string containing this string.')
containingRegexp: c.shortString(title: 'Contains Regexp', description: 'Script requires the event\'s property chain value to be a string containing this regular expression.')
notContainingRegexp: c.shortString(title: 'Does not contain regexp', description: 'Script requires the event\'s property chain value to *not* be a string containing this regular expression.')
GoalSchema = c.object {title: "Goal", description: "A goal that the player can accomplish.", required: ["name", "id"]},
name: c.shortString(title: "Name", description: "Name of the goal that the player will see, like \"Defeat eighteen dragons\".")
i18n: {type: "object", format: 'i18n', props: ['name'], description: "Help translate this goal"}
id: c.shortString(title: "ID", description: "Unique identifier for this goal, like \"defeat-dragons\".") # unique somehow?
worldEndsAfter: {title: 'World Ends After', description: "When included, ends the world this many seconds after this goal succeeds or fails.", type: 'number', minimum: 0, exclusiveMinimum: true, maximum: 300, default: 3}
howMany: {title: "How Many", description: "When included, require only this many of the listed goal targets instead of all of them.", type: 'integer', minimum: 1}
hiddenGoal: {title: "Hidden", description: "Hidden goals don't show up in the goals area for the player until they're failed. (Usually they're obvious, like 'don't die'.)", 'type': 'boolean', default: false}
GoalSchema = c.object {title: 'Goal', description: 'A goal that the player can accomplish.', required: ['name', 'id']},
name: c.shortString(title: 'Name', description: 'Name of the goal that the player will see, like \"Defeat eighteen dragons\".')
i18n: {type: 'object', format: 'i18n', props: ['name'], description: 'Help translate this goal'}
id: c.shortString(title: 'ID', description: 'Unique identifier for this goal, like \"defeat-dragons\".') # unique somehow?
worldEndsAfter: {title: 'World Ends After', description: 'When included, ends the world this many seconds after this goal succeeds or fails.', type: 'number', minimum: 0, exclusiveMinimum: true, maximum: 300, default: 3}
howMany: {title: 'How Many', description: 'When included, require only this many of the listed goal targets instead of all of them.', type: 'integer', minimum: 1}
hiddenGoal: {title: 'Hidden', description: 'Hidden goals don\'t show up in the goals area for the player until they\'re failed. (Usually they\'re obvious, like "don\'t die".)', 'type': 'boolean', default: false}
team: c.shortString(title: 'Team', description: 'Name of the team this goal is for, if it is not for all of the playable teams.')
killThangs: c.array {title: "Kill Thangs", description: "A list of Thang IDs the player should kill, or team names.", uniqueItems: true, minItems: 1, "default": ["ogres"]}, thang
saveThangs: c.array {title: "Save Thangs", description: "A list of Thang IDs the player should save, or team names", uniqueItems: true, minItems: 1, "default": ["humans"]}, thang
getToLocations: c.object {title: "Get To Locations", description: "Will be set off when any of the \"who\" touch any of the \"targets\" ", required: ["who", "targets"]},
who: c.array {title: "Who", description: "The Thangs who must get to the target locations.", minItems: 1}, thang
targets: c.array {title: "Targets", description: "The target locations to which the Thangs must get.", minItems: 1}, thang
getAllToLocations: c.array {title: "Get all to locations", description: "Similar to getToLocations but now a specific \"who\" can have a specific \"target\", also must be used with the HowMany property for desired effect",required: ["getToLocation"]},
c.object {title: "", description: ""},
getToLocation: c.object {title: "Get To Locations", description: "TODO: explain", required: ["who", "targets"]},
who: c.array {title: "Who", description: "The Thangs who must get to the target locations.", minItems: 1}, thang
targets: c.array {title: "Targets", description: "The target locations to which the Thangs must get.", minItems: 1}, thang
keepFromLocations: c.object {title: "Keep From Locations", description: "TODO: explain", required: ["who", "targets"]},
who: c.array {title: "Who", description: "The Thangs who must not get to the target locations.", minItems: 1}, thang
targets: c.array {title: "Targets", description: "The target locations to which the Thangs must not get.", minItems: 1}, thang
keepAllFromLocations: c.array {title: "Keep ALL From Locations", description: "Similar to keepFromLocations but now a specific \"who\" can have a specific \"target\", also must be used with the HowMany property for desired effect", required: ["keepFromLocation"]},
c.object {title: "", description: ""},
keepFromLocation: c.object {title: "Keep From Locations", description: "TODO: explain", required: ["who", "targets"]},
who: c.array {title: "Who", description: "The Thangs who must not get to the target locations.", minItems: 1}, thang
targets: c.array {title: "Targets", description: "The target locations to which the Thangs must not get.", minItems: 1}, thang
leaveOffSides: c.object {title: "Leave Off Sides", description: "Sides of the level to get some Thangs to leave across.", required: ["who", "sides"]},
who: c.array {title: "Who", description: "The Thangs which must leave off the sides of the level.", minItems: 1}, thang
sides: c.array {title: "Sides", description: "The sides off which the Thangs must leave.", minItems: 1}, side
keepFromLeavingOffSides: c.object {title: "Keep From Leaving Off Sides", description: "Sides of the level to keep some Thangs from leaving across.", required: ["who", "sides"]},
who: c.array {title: "Who", description: "The Thangs which must not leave off the sides of the level.", minItems: 1}, thang
sides: side, {title: "Sides", description: "The sides off which the Thangs must not leave.", minItems: 1}, side
collectThangs: c.object {title: "Collect", description: "Thangs that other Thangs must collect.", required: ["who", "targets"]},
who: c.array {title: "Who", description: "The Thangs which must collect the target items.", minItems: 1}, thang
targets: c.array {title: "Targets", description: "The target items which the Thangs must collect.", minItems: 1}, thang
keepFromCollectingThangs: c.object {title: "Keep From Collecting", description: "Thangs that the player must prevent other Thangs from collecting.", required: ["who", "targets"]},
who: c.array {title: "Who", description: "The Thangs which must not collect the target items.", minItems: 1}, thang
targets: c.array {title: "Targets", description: "The target items which the Thangs must not collect.", minItems: 1}, thang
killThangs: c.array {title: 'Kill Thangs', description: 'A list of Thang IDs the player should kill, or team names.', uniqueItems: true, minItems: 1, 'default': ['ogres']}, thang
saveThangs: c.array {title: 'Save Thangs', description: 'A list of Thang IDs the player should save, or team names', uniqueItems: true, minItems: 1, 'default': ['humans']}, thang
getToLocations: c.object {title: 'Get To Locations', description: 'Will be set off when any of the \"who\" touch any of the \"targets\"', required: ['who', 'targets']},
who: c.array {title: 'Who', description: 'The Thangs who must get to the target locations.', minItems: 1}, thang
targets: c.array {title: 'Targets', description: 'The target locations to which the Thangs must get.', minItems: 1}, thang
getAllToLocations: c.array {title: 'Get all to locations', description: 'Similar to getToLocations but now a specific \"who\" can have a specific \"target\", also must be used with the HowMany property for desired effect', required: ['getToLocation']},
c.object {title: '', description: ''},
getToLocation: c.object {title: 'Get To Locations', description: 'TODO: explain', required: ['who', 'targets']},
who: c.array {title: 'Who', description: 'The Thangs who must get to the target locations.', minItems: 1}, thang
targets: c.array {title: 'Targets', description: 'The target locations to which the Thangs must get.', minItems: 1}, thang
keepFromLocations: c.object {title: 'Keep From Locations', description: 'TODO: explain', required: ['who', 'targets']},
who: c.array {title: 'Who', description: 'The Thangs who must not get to the target locations.', minItems: 1}, thang
targets: c.array {title: 'Targets', description: 'The target locations to which the Thangs must not get.', minItems: 1}, thang
keepAllFromLocations: c.array {title: 'Keep ALL From Locations', description: 'Similar to keepFromLocations but now a specific \"who\" can have a specific \"target\", also must be used with the HowMany property for desired effect', required: ['keepFromLocation']},
c.object {title: '', description: ''},
keepFromLocation: c.object {title: 'Keep From Locations', description: 'TODO: explain', required: ['who', 'targets']},
who: c.array {title: 'Who', description: 'The Thangs who must not get to the target locations.', minItems: 1}, thang
targets: c.array {title: 'Targets', description: 'The target locations to which the Thangs must not get.', minItems: 1}, thang
leaveOffSides: c.object {title: 'Leave Off Sides', description: 'Sides of the level to get some Thangs to leave across.', required: ['who', 'sides']},
who: c.array {title: 'Who', description: 'The Thangs which must leave off the sides of the level.', minItems: 1}, thang
sides: c.array {title: 'Sides', description: 'The sides off which the Thangs must leave.', minItems: 1}, side
keepFromLeavingOffSides: c.object {title: 'Keep From Leaving Off Sides', description: 'Sides of the level to keep some Thangs from leaving across.', required: ['who', 'sides']},
who: c.array {title: 'Who', description: 'The Thangs which must not leave off the sides of the level.', minItems: 1}, thang
sides: side, {title: 'Sides', description: 'The sides off which the Thangs must not leave.', minItems: 1}, side
collectThangs: c.object {title: 'Collect', description: 'Thangs that other Thangs must collect.', required: ['who', 'targets']},
who: c.array {title: 'Who', description: 'The Thangs which must collect the target items.', minItems: 1}, thang
targets: c.array {title: 'Targets', description: 'The target items which the Thangs must collect.', minItems: 1}, thang
keepFromCollectingThangs: c.object {title: 'Keep From Collecting', description: 'Thangs that the player must prevent other Thangs from collecting.', required: ['who', 'targets']},
who: c.array {title: 'Who', description: 'The Thangs which must not collect the target items.', minItems: 1}, thang
targets: c.array {title: 'Targets', description: 'The target items which the Thangs must not collect.', minItems: 1}, thang
ResponseSchema = c.object {title: "Dialogue Button", description: "A button to be shown to the user with the dialogue.", required: ["text"]},
text: {title: "Title", description: "The text that will be on the button", "default": "Okay", type: 'string', maxLength: 30}
channel: c.shortString(title: "Channel", format: 'event-channel', description: 'Channel that this event will be broadcast over, like "level-set-playing".')
event: {type: 'object', title: "Event", description: "Event that will be broadcast when this button is pressed, like {playing: true}."}
buttonClass: c.shortString(title: "Button Class", description: 'CSS class that will be added to the button, like "btn-primary".')
i18n: {type: "object", format: 'i18n', props: ['text'], description: "Help translate this button"}
ResponseSchema = c.object {title: 'Dialogue Button', description: 'A button to be shown to the user with the dialogue.', required: ['text']},
text: {title: 'Title', description: 'The text that will be on the button', 'default': 'Okay', type: 'string', maxLength: 30}
channel: c.shortString(title: 'Channel', format: 'event-channel', description: 'Channel that this event will be broadcast over, like "level-set-playing".')
event: {type: 'object', title: 'Event', description: 'Event that will be broadcast when this button is pressed, like {playing: true}.'}
buttonClass: c.shortString(title: 'Button Class', description: 'CSS class that will be added to the button, like "btn-primary".')
i18n: {type: 'object', format: 'i18n', props: ['text'], description: 'Help translate this button'}
PointSchema = c.object {title: "Point", description: "An {x, y} coordinate point.", format: "point2d", required: ["x", "y"]},
x: {title: "x", description: "The x coordinate.", type: "number", "default": 15}
y: {title: "y", description: "The y coordinate.", type: "number", "default": 20}
PointSchema = c.object {title: 'Point', description: 'An {x, y} coordinate point.', format: 'point2d', required: ['x', 'y']},
x: {title: 'x', description: 'The x coordinate.', type: 'number', 'default': 15}
y: {title: 'y', description: 'The y coordinate.', type: 'number', 'default': 20}
SpriteCommandSchema = c.object {title: "Thang Command", description: "Make a target Thang move or say something, or select/deselect it.", required: ["id"], default: {id: "Captain Anya"}},
SpriteCommandSchema = c.object {title: 'Thang Command', description: 'Make a target Thang move or say something, or select/deselect it.', required: ['id'], default: {id: 'Captain Anya'}},
id: thang
select: {title: "Select", description: "Select or deselect this Thang.", type: 'boolean'}
say: c.object {title: "Say", description: "Make this Thang say a message.", required: ["text"]},
blurb: c.shortString(title: "Blurb", description: "A very short message to display above this Thang's head. Plain text.", maxLength: 50)
mood: c.shortString(title: "Mood", description: "The mood with which the Thang speaks.", "enum": ["explain", "debrief", "congrats", "attack", "joke", "tip", "alarm"], "default": "explain")
text: {title: "Text", description: "A short message to display in the dialogue area. Markdown okay.", type: "string", maxLength: 400}
sound: c.object {title: "Sound", description: "A dialogue sound file to accompany the message.", required: ["mp3", "ogg"]},
mp3: c.shortString(title: "MP3", format: 'sound-file')
ogg: c.shortString(title: "OGG", format: 'sound-file')
preload: {title: "Preload", description: "Whether to load this sound file before the level can begin (typically for the first dialogue of a level).", type: 'boolean', "default": false}
responses: c.array {title: "Buttons", description: "An array of buttons to include with the dialogue, with which the user can respond."}, ResponseSchema
i18n: {type: "object", format: 'i18n', props: ['blurb', 'text'], description: "Help translate this message"}
move: c.object {title: "Move", description: "Tell the Thang to move.", required: ['target'], default: {target: {x: 20, y: 20}, duration: 500}},
select: {title: 'Select', description: 'Select or deselect this Thang.', type: 'boolean'}
say: c.object {title: 'Say', description: 'Make this Thang say a message.', required: ['text']},
blurb: c.shortString(title: 'Blurb', description: 'A very short message to display above this Thang\'s head. Plain text.', maxLength: 50)
mood: c.shortString(title: 'Mood', description: 'The mood with which the Thang speaks.', 'enum': ['explain', 'debrief', 'congrats', 'attack', 'joke', 'tip', 'alarm'], 'default': 'explain')
text: {title: 'Text', description: 'A short message to display in the dialogue area. Markdown okay.', type: 'string', maxLength: 400}
sound: c.object {title: 'Sound', description: 'A dialogue sound file to accompany the message.', required: ['mp3', 'ogg']},
mp3: c.shortString(title: 'MP3', format: 'sound-file')
ogg: c.shortString(title: 'OGG', format: 'sound-file')
preload: {title: 'Preload', description: 'Whether to load this sound file before the level can begin (typically for the first dialogue of a level).', type: 'boolean', 'default': false}
responses: c.array {title: 'Buttons', description: 'An array of buttons to include with the dialogue, with which the user can respond.'}, ResponseSchema
i18n: {type: 'object', format: 'i18n', props: ['blurb', 'text'], description: 'Help translate this message'}
move: c.object {title: 'Move', description: 'Tell the Thang to move.', required: ['target'], default: {target: {x: 20, y: 20}, duration: 500}},
target: _.extend _.cloneDeep(PointSchema), {title: 'Target', description: 'Target point to which the Thang will move.'}
duration: {title: "Duration", description: "Number of milliseconds over which to move, or 0 for an instant move.", type: 'integer', minimum: 0, default: 500, format: 'milliseconds'}
duration: {title: 'Duration', description: 'Number of milliseconds over which to move, or 0 for an instant move.', type: 'integer', minimum: 0, default: 500, format: 'milliseconds'}
NoteGroupSchema = c.object {title: "Note Group", description: "A group of notes that should be sent out as a result of this script triggering.", displayProperty: "name"},
name: {title: "Name", description: "Short name describing the script, like \"Anya greets the player\", for your convenience.", type: "string"}
dom: c.object {title: "DOM", description: "Manipulate things in the play area DOM, outside of the level area canvas."},
focus: c.shortString(title: "Focus", description: "Set the window focus to this DOM selector string.")
NoteGroupSchema = c.object {title: 'Note Group', description: 'A group of notes that should be sent out as a result of this script triggering.', displayProperty: 'name'},
name: {title: 'Name', description: 'Short name describing the script, like \"Anya greets the player\", for your convenience.', type: 'string'}
dom: c.object {title: 'DOM', description: 'Manipulate things in the play area DOM, outside of the level area canvas.'},
focus: c.shortString(title: 'Focus', description: 'Set the window focus to this DOM selector string.')
showVictory: {
title: "Show Victory",
description: "Show the done button and maybe also the victory modal.",
title: 'Show Victory',
description: 'Show the done button and maybe also the victory modal.',
enum: [true, 'Done Button', 'Done Button And Modal'] # deprecate true, same as 'done_button_and_modal'
}
highlight: c.object {title: "Highlight", description: "Highlight the target DOM selector string with a big arrow."},
target: c.shortString(title: "Target", description: "Target highlight element DOM selector string.")
delay: {type: 'integer', minimum: 0, title: "Delay", description: "Show the highlight after this many milliseconds. Doesn't affect the dim shade cutout highlight method."}
highlight: c.object {title: 'Highlight', description: 'Highlight the target DOM selector string with a big arrow.'},
target: c.shortString(title: 'Target', description: 'Target highlight element DOM selector string.')
delay: {type: 'integer', minimum: 0, title: 'Delay', description: 'Show the highlight after this many milliseconds. Doesn\'t affect the dim shade cutout highlight method.'}
offset: _.extend _.cloneDeep(PointSchema), {title: 'Offset', description: 'Pointing arrow tip offset in pixels from the default target.', format: null}
rotation: {type: 'number', minimum: 0, title: "Rotation", description: "Rotation of the pointing arrow, in radians. PI / 2 points left, PI points up, etc."}
sides: c.array {title: "Sides", description: "Which sides of the target element to point at."}, {type: 'string', 'enum': ['left', 'right', 'top', 'bottom'], title: "Side", description: "A side of the target element to point at."}
lock: {title: "Lock", description: "Whether the interface should be locked so that the player's focus is on the script, or specific areas to lock.", type: ['boolean', 'array'], items: {type: 'string', enum: ['surface', 'editor', 'palette', 'hud', 'playback', 'playback-hover', 'level']}}
letterbox: {type: 'boolean', title: 'Letterbox', description:'Turn letterbox mode on or off. Disables surface and playback controls.'}
rotation: {type: 'number', minimum: 0, title: 'Rotation', description: 'Rotation of the pointing arrow, in radians. PI / 2 points left, PI points up, etc.'}
sides: c.array {title: 'Sides', description: 'Which sides of the target element to point at.'}, {type: 'string', 'enum': ['left', 'right', 'top', 'bottom'], title: 'Side', description: 'A side of the target element to point at.'}
lock: {title: 'Lock', description: 'Whether the interface should be locked so that the player\'s focus is on the script, or specific areas to lock.', type: ['boolean', 'array'], items: {type: 'string', enum: ['surface', 'editor', 'palette', 'hud', 'playback', 'playback-hover', 'level']}}
letterbox: {type: 'boolean', title: 'Letterbox', description: 'Turn letterbox mode on or off. Disables surface and playback controls.'}
goals: c.object {title: "Goals (Old)", description: "Deprecated. Goals added here have no effect. Add goals in the level settings instead."},
add: c.array {title: "Add", description: "Deprecated. Goals added here have no effect. Add goals in the level settings instead."}, GoalSchema
remove: c.array {title: "Remove", description: "Deprecated. Goals removed here have no effect. Adjust goals in the level settings instead."}, GoalSchema
goals: c.object {title: 'Goals (Old)', description: 'Deprecated. Goals added here have no effect. Add goals in the level settings instead.'},
add: c.array {title: 'Add', description: 'Deprecated. Goals added here have no effect. Add goals in the level settings instead.'}, GoalSchema
remove: c.array {title: 'Remove', description: 'Deprecated. Goals removed here have no effect. Adjust goals in the level settings instead.'}, GoalSchema
playback: c.object {title: "Playback", description: "Control the playback of the level."},
playing: {type: 'boolean', title: "Set Playing", description: "Set whether playback is playing or paused."}
scrub: c.object {title: "Scrub", description: "Scrub the level playback time to a certain point.", default: {offset: 2, duration: 1000, toRatio: 0.5}},
offset: {type: 'integer', title: "Offset", description: "Number of frames by which to adjust the scrub target time.", default: 2}
duration: {type: 'integer', title: "Duration", description: "Number of milliseconds over which to scrub time.", minimum: 0, format: 'milliseconds'}
toRatio: {type: 'number', title: "To Progress Ratio", description: "Set playback time to a target playback progress ratio.", minimum: 0, maximum: 1}
toTime: {type: 'number', title: "To Time", description: "Set playback time to a target playback point, in seconds.", minimum: 0}
toGoal: c.shortString(title: "To Goal", description: "Set playback time to when this goal was achieved. (TODO: not implemented.)")
playback: c.object {title: 'Playback', description: 'Control the playback of the level.'},
playing: {type: 'boolean', title: 'Set Playing', description: 'Set whether playback is playing or paused.'}
scrub: c.object {title: 'Scrub', description: 'Scrub the level playback time to a certain point.', default: {offset: 2, duration: 1000, toRatio: 0.5}},
offset: {type: 'integer', title: 'Offset', description: 'Number of frames by which to adjust the scrub target time.', default: 2}
duration: {type: 'integer', title: 'Duration', description: 'Number of milliseconds over which to scrub time.', minimum: 0, format: 'milliseconds'}
toRatio: {type: 'number', title: 'To Progress Ratio', description: 'Set playback time to a target playback progress ratio.', minimum: 0, maximum: 1}
toTime: {type: 'number', title: 'To Time', description: 'Set playback time to a target playback point, in seconds.', minimum: 0}
toGoal: c.shortString(title: 'To Goal', description: 'Set playback time to when this goal was achieved. (TODO: not implemented.)')
script: c.object {title: "Script", description: "Extra configuration for this action group."},
duration: {type: 'integer', minimum: 0, title: "Duration", description: "How long this script should last in milliseconds. 0 for indefinite.", format: 'milliseconds'}
skippable: {type: 'boolean', title: "Skippable", description: "Whether this script shouldn't bother firing when the player skips past all current scripts."}
beforeLoad: {type: 'boolean', title: "Before Load", description: "Whether this script should fire before the level is finished loading."}
script: c.object {title: 'Script', description: 'Extra configuration for this action group.'},
duration: {type: 'integer', minimum: 0, title: 'Duration', description: 'How long this script should last in milliseconds. 0 for indefinite.', format: 'milliseconds'}
skippable: {type: 'boolean', title: 'Skippable', description: 'Whether this script shouldn\'t bother firing when the player skips past all current scripts.'}
beforeLoad: {type: 'boolean', title: 'Before Load', description: 'Whether this script should fire before the level is finished loading.'}
sprites: c.array {title: "Sprites", description: "Commands to issue to Sprites on the Surface."}, SpriteCommandSchema
sprites: c.array {title: 'Sprites', description: 'Commands to issue to Sprites on the Surface.'}, SpriteCommandSchema
surface: c.object {title: "Surface", description: "Commands to issue to the Surface itself."},
focus: c.object {title: "Camera", description: "Focus the camera on a specific point on the Surface.", format:'viewport'},
target: {anyOf: [PointSchema, thang, {type: 'null'}], title: "Target", description: "Where to center the camera view.", default: {x:0, y:0}}
zoom: {type: 'number', minimum: 0, exclusiveMinimum: true, maximum: 64, title: "Zoom", description: "What zoom level to use."}
duration: {type:'number', minimum: 0, title: "Duration", description: "in ms"}
bounds: c.array {title:'Boundary', maxItems: 2, minItems: 2, default:[{x:0,y:0}, {x:46, y:39}], format: 'bounds'}, PointSchema
isNewDefault: {type:'boolean', format: 'hidden', title: "New Default", description: 'Set this as new default zoom once scripts end.'} # deprecated
highlight: c.object {title: "Highlight", description: "Highlight specific Sprites on the Surface."},
targets: c.array {title: "Targets", description: "Thang IDs of target Sprites to highlight."}, thang
delay: {type: 'integer', minimum: 0, title: "Delay", description: "Delay in milliseconds before the highlight appears."}
lockSelect: {type: 'boolean', title: "Lock Select", description: "Whether to lock Sprite selection so that the player can't select/deselect anything."}
surface: c.object {title: 'Surface', description: 'Commands to issue to the Surface itself.'},
focus: c.object {title: 'Camera', description: 'Focus the camera on a specific point on the Surface.', format: 'viewport'},
target: {anyOf: [PointSchema, thang, {type: 'null'}], title: 'Target', description: 'Where to center the camera view.', default: {x: 0, y: 0}}
zoom: {type: 'number', minimum: 0, exclusiveMinimum: true, maximum: 64, title: 'Zoom', description: 'What zoom level to use.'}
duration: {type: 'number', minimum: 0, title: 'Duration', description: 'in ms'}
bounds: c.array {title: 'Boundary', maxItems: 2, minItems: 2, default: [{x: 0, y: 0}, {x: 46, y: 39}], format: 'bounds'}, PointSchema
isNewDefault: {type: 'boolean', format: 'hidden', title: 'New Default', description: 'Set this as new default zoom once scripts end.'} # deprecated
highlight: c.object {title: 'Highlight', description: 'Highlight specific Sprites on the Surface.'},
targets: c.array {title: 'Targets', description: 'Thang IDs of target Sprites to highlight.'}, thang
delay: {type: 'integer', minimum: 0, title: 'Delay', description: 'Delay in milliseconds before the highlight appears.'}
lockSelect: {type: 'boolean', title: 'Lock Select', description: 'Whether to lock Sprite selection so that the player can\'t select/deselect anything.'}
sound: c.object {title: "Sound", description: "Commands to control sound playback."},
suppressSelectionSounds: {type: "boolean", title: "Suppress Selection Sounds", description: "Whether to suppress selection sounds made from clicking on Thangs."}
music: c.object { title: "Music", description: "Control music playing"},
play: { title: "Play", type: "boolean" }
file: c.shortString(title: "File", enum:['/music/music_level_1','/music/music_level_2','/music/music_level_3','/music/music_level_4','/music/music_level_5'])
sound: c.object {title: 'Sound', description: 'Commands to control sound playback.'},
suppressSelectionSounds: {type: 'boolean', title: 'Suppress Selection Sounds', description: 'Whether to suppress selection sounds made from clicking on Thangs.'}
music: c.object {title: 'Music', description: 'Control music playing'},
play: {title: 'Play', type: 'boolean'}
file: c.shortString(title: 'File', enum: ['/music/music_level_1', '/music/music_level_2', '/music/music_level_3', '/music/music_level_4', '/music/music_level_5'])
ScriptSchema = c.object {
title: "Script"
title: 'Script'
description: 'A script fires off a chain of notes to interact with the game when a certain event triggers it.'
required: ["channel"]
'default': {channel: "world:won", noteChain: []}
required: ['channel']
'default': {channel: 'world:won', noteChain: []}
},
id: c.shortString(title: "ID", description: "A unique ID that other scripts can rely on in their Happens After prereqs, for sequencing.") # uniqueness?
channel: c.shortString(title: "Event", format: 'event-channel', description: 'Event channel this script might trigger for, like "world:won".')
eventPrereqs: c.array {title: "Event Checks", description: "Logical checks on the event for this script to trigger.", format:'event-prereqs'}, EventPrereqSchema
repeats: {title: "Repeats", description: "Whether this script can trigger more than once during a level.", enum: [true, false, 'session'], "default": false}
scriptPrereqs: c.array {title: "Happens After", description: "Scripts that need to fire first."},
c.shortString(title: "ID", description: "A unique ID of a script.")
notAfter: c.array {title: "Not After", description: "Do not run this script if any of these scripts have run."},
c.shortString(title: "ID", description: "A unique ID of a script.")
noteChain: c.array {title: "Actions", description: "A list of things that happen when this script triggers."}, NoteGroupSchema
id: c.shortString(title: 'ID', description: 'A unique ID that other scripts can rely on in their Happens After prereqs, for sequencing.') # uniqueness?
channel: c.shortString(title: 'Event', format: 'event-channel', description: 'Event channel this script might trigger for, like "world:won".')
eventPrereqs: c.array {title: 'Event Checks', description: 'Logical checks on the event for this script to trigger.', format: 'event-prereqs'}, EventPrereqSchema
repeats: {title: 'Repeats', description: 'Whether this script can trigger more than once during a level.', enum: [true, false, 'session'], 'default': false}
scriptPrereqs: c.array {title: 'Happens After', description: 'Scripts that need to fire first.'},
c.shortString(title: 'ID', description: 'A unique ID of a script.')
notAfter: c.array {title: 'Not After', description: 'Do not run this script if any of these scripts have run.'},
c.shortString(title: 'ID', description: 'A unique ID of a script.')
noteChain: c.array {title: 'Actions', description: 'A list of things that happen when this script triggers.'}, NoteGroupSchema
LevelThangSchema = c.object {
title: "Thang",
description: "Thangs are any units, doodads, or abstract things that you use to build the level. (\"Thing\" was too confusing to say.)",
format: "thang"
required: ["id", "thangType", "components"]
title: 'Thang',
description: 'Thangs are any units, doodads, or abstract things that you use to build the level. (\"Thing\" was too confusing to say.)',
format: 'thang'
required: ['id', 'thangType', 'components']
'default':
id: "Boris"
thangType: "Soldier"
id: 'Boris'
thangType: 'Soldier'
components: []
},
id: thang # TODO: figure out if we can make this unique and how to set dynamic defaults
# TODO: split thangType into "original" and "majorVersion" like the rest for consistency
thangType: c.objectId(links: [{rel: "db", href: "/db/thang.type/{($)}/version"}], title: "Thang Type", description: "A reference to the original Thang template being configured.", format: 'thang-type')
components: c.array {title: "Components", description: "Thangs are configured by changing the Components attached to them.", uniqueItems: true, format: 'thang-components-array'}, ThangComponentSchema # TODO: uniqueness should be based on "original", not whole thing
# TODO: split thangType into 'original' and 'majorVersion' like the rest for consistency
thangType: c.objectId(links: [{rel: 'db', href: '/db/thang.type/{($)}/version'}], title: 'Thang Type', description: 'A reference to the original Thang template being configured.', format: 'thang-type')
components: c.array {title: 'Components', description: 'Thangs are configured by changing the Components attached to them.', uniqueItems: true, format: 'thang-components-array'}, ThangComponentSchema # TODO: uniqueness should be based on 'original', not whole thing
LevelSystemSchema = c.object {
title: "System"
description: "Configuration for a System that this Level uses."
title: 'System'
description: 'Configuration for a System that this Level uses.'
format: 'level-system'
required: ['original', 'majorVersion']
'default':
majorVersion: 0
config: {}
links: [{rel: "db", href: "/db/level.system/{(original)}/version/{(majorVersion)}"}]
links: [{rel: 'db', href: '/db/level.system/{(original)}/version/{(majorVersion)}'}]
},
original: c.objectId(title: "Original", description: "A reference to the original System being configured.", format: "hidden")
config: c.object {title: "Configuration", description: "System-specific configuration properties.", additionalProperties: true, format: 'level-system-configuration'}
majorVersion: {title: "Major Version", description: "Which major version of the System is being used.", type: 'integer', minimum: 0, default: 0, format: "hidden"}
original: c.objectId(title: 'Original', description: 'A reference to the original System being configured.', format: 'hidden')
config: c.object {title: 'Configuration', description: 'System-specific configuration properties.', additionalProperties: true, format: 'level-system-configuration'}
majorVersion: {title: 'Major Version', description: 'Which major version of the System is being used.', type: 'integer', minimum: 0, default: 0, format: 'hidden'}
GeneralArticleSchema = c.object {
title: "Article"
description: "Reference to a general documentation article."
title: 'Article'
description: 'Reference to a general documentation article.'
required: ['original']
format: 'latest-version-reference'
'default':
original: null
majorVersion: 0
links: [{rel: "db", href: "/db/article/{(original)}/version/{(majorVersion)}"}]
links: [{rel: 'db', href: '/db/article/{(original)}/version/{(majorVersion)}'}]
},
original: c.objectId(title: "Original", description: "A reference to the original Article.")#, format: "hidden") # hidden?
majorVersion: {title: "Major Version", description: "Which major version of the Article is being used.", type: 'integer', minimum: 0}#, format: "hidden"} # hidden?
original: c.objectId(title: 'Original', description: 'A reference to the original Article.')#, format: 'hidden') # hidden?
majorVersion: {title: 'Major Version', description: 'Which major version of the Article is being used.', type: 'integer', minimum: 0}#, format: 'hidden'} # hidden?
LevelSchema = c.object {
title: "Level"
description: "A spectacular level which will delight and educate its stalwart players with the sorcery of coding."
required: ["name", "description", "scripts", "thangs", "documentation"]
title: 'Level'
description: 'A spectacular level which will delight and educate its stalwart players with the sorcery of coding.'
required: ['name', 'description', 'scripts', 'thangs', 'documentation']
'default':
name: "Ineffable Wizardry"
description: "This level is indescribably flarmy."
name: 'Ineffable Wizardry'
description: 'This level is indescribably flarmy.'
documentation: {specificArticles: [], generalArticles: []}
scripts: []
thangs: []
}
c.extendNamedProperties LevelSchema # let's have the name be the first property
_.extend LevelSchema.properties,
description: {title: "Description", description: "A short explanation of what this level is about.", type: "string", maxLength: 65536, "default": "This level is indescribably flarmy!", format: 'markdown'}
documentation: c.object {title: "Documentation", description: "Documentation articles relating to this level.", required: ["specificArticles", "generalArticles"], 'default': {specificArticles: [], generalArticles: []}},
specificArticles: c.array {title: "Specific Articles", description: "Specific documentation articles that live only in this level.", uniqueItems: true, "default": []}, SpecificArticleSchema
generalArticles: c.array {title: "General Articles", description: "General documentation articles that can be linked from multiple levels.", uniqueItems: true, "default": []}, GeneralArticleSchema
description: {title: 'Description', description: 'A short explanation of what this level is about.', type: 'string', maxLength: 65536, 'default': 'This level is indescribably flarmy!', format: 'markdown'}
documentation: c.object {title: 'Documentation', description: 'Documentation articles relating to this level.', required: ['specificArticles', 'generalArticles'], 'default': {specificArticles: [], generalArticles: []}},
specificArticles: c.array {title: 'Specific Articles', description: 'Specific documentation articles that live only in this level.', uniqueItems: true, 'default': []}, SpecificArticleSchema
generalArticles: c.array {title: 'General Articles', description: 'General documentation articles that can be linked from multiple levels.', uniqueItems: true, 'default': []}, GeneralArticleSchema
background: c.objectId({format: 'hidden'})
nextLevel: {
type:'object',
links: [{rel: "extra", href: "/db/level/{($)}"}, {rel:'db', href: "/db/level/{(original)}/version/{(majorVersion)}"}],
type: 'object',
links: [{rel: 'extra', href: '/db/level/{($)}'}, {rel: 'db', href: '/db/level/{(original)}/version/{(majorVersion)}'}],
format: 'latest-version-reference',
title: "Next Level",
description: "Reference to the next level players will play after beating this one."
title: 'Next Level',
description: 'Reference to the next level players will play after beating this one.'
}
scripts: c.array {title: "Scripts", description: "An array of scripts that trigger based on what the player does and affect things outside of the core level simulation.", "default": []}, ScriptSchema
thangs: c.array {title: "Thangs", description: "An array of Thangs that make up the level.", "default": []}, LevelThangSchema
systems: c.array {title: "Systems", description: "Levels are configured by changing the Systems attached to them.", uniqueItems: true, default: []}, LevelSystemSchema # TODO: uniqueness should be based on "original", not whole thing
victory: c.object {title: "Victory Screen", default: {}, properties: {'body': {type: 'string', format: 'markdown', title: 'Body Text', description: 'Inserted into the Victory Modal once this level is complete. Tell the player they did a good job and what they accomplished!'}, i18n: {type: "object", format: 'i18n', props: ['body'], description: "Help translate this victory message"}}}
i18n: {type: "object", format: 'i18n', props: ['name', 'description'], description: "Help translate this level"}
icon: { type: 'string', format: 'image-file', title: 'Icon' }
scripts: c.array {title: 'Scripts', description: 'An array of scripts that trigger based on what the player does and affect things outside of the core level simulation.', 'default': []}, ScriptSchema
thangs: c.array {title: 'Thangs', description: 'An array of Thangs that make up the level.', 'default': []}, LevelThangSchema
systems: c.array {title: 'Systems', description: 'Levels are configured by changing the Systems attached to them.', uniqueItems: true, default: []}, LevelSystemSchema # TODO: uniqueness should be based on 'original', not whole thing
victory: c.object {title: 'Victory Screen', default: {}, properties: {'body': {type: 'string', format: 'markdown', title: 'Body Text', description: 'Inserted into the Victory Modal once this level is complete. Tell the player they did a good job and what they accomplished!'}, i18n: {type: 'object', format: 'i18n', props: ['body'], description: 'Help translate this victory message'}}}
i18n: {type: 'object', format: 'i18n', props: ['name', 'description'], description: 'Help translate this level'}
icon: {type: 'string', format: 'image-file', title: 'Icon'}
goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema
type: c.shortString(title: "Type", description: "What kind of level this is.", "enum": ['campaign', 'ladder', 'ladder-tutorial'])
showsGuide: c.shortString(title: "Shows Guide", description: "If the guide is shown at the beginning of the level.", "enum": ['first-time', 'always'])
type: c.shortString(title: 'Type', description: 'What kind of level this is.', 'enum': ['campaign', 'ladder', 'ladder-tutorial'])
showsGuide: c.shortString(title: 'Shows Guide', description: 'If the guide is shown at the beginning of the level.', 'enum': ['first-time', 'always'])
c.extendBasicProperties LevelSchema, 'level'
c.extendSearchableProperties LevelSchema

View file

@ -3,54 +3,53 @@ metaschema = require './../metaschema'
attackSelfCode = """
class AttacksSelf extends Component
@className: "AttacksSelf"
@className: 'AttacksSelf'
chooseAction: ->
@attack @
"""
systems = [
'action', 'ai', 'alliance', 'collision', 'combat', 'display', 'event', 'existence', 'hearing'
'action', 'ai', 'alliance', 'collision', 'combat', 'display', 'event', 'existence', 'hearing',
'inventory', 'movement', 'programming', 'targeting', 'ui', 'vision', 'misc', 'physics', 'effect',
'magic'
]
PropertyDocumentationSchema = c.object {
title: "Property Documentation"
description: "Documentation entry for a property this Component will add to its Thang which other Components might
want to also use."
"default":
name: "foo"
type: "object"
title: 'Property Documentation'
description: 'Documentation entry for a property this Component will add to its Thang which other Components might want to also use.'
'default':
name: 'foo'
type: 'object'
description: 'The `foo` property can satisfy all the #{spriteName}\'s foobar needs. Use it wisely.'
required: ['name', 'type', 'description']
},
name: {type: 'string', title: "Name", description: "Name of the property."}
name: {type: 'string', title: 'Name', description: 'Name of the property.'}
# not actual JS types, just whatever they describe...
type: c.shortString(title: "Type", description: "Intended type of the property.")
type: c.shortString(title: 'Type', description: 'Intended type of the property.')
description:
oneOf: [
{title: "Description", type: 'string', description: "Description of the property.", maxLength: 1000, format: 'markdown'}
{title: 'Description', type: 'string', description: 'Description of the property.', maxLength: 1000, format: 'markdown'}
{
type: 'object',
title: "Language Descriptions",
description: "Property descriptions by code language.",
additionalProperties: {type: 'string', description: "Description of the property.", maxLength: 1000, format: 'markdown'}
title: 'Language Descriptions',
description: 'Property descriptions by code language.',
additionalProperties: {type: 'string', description: 'Description of the property.', maxLength: 1000, format: 'markdown'}
}
]
args: c.array {title: "Arguments", description: "If this property has type 'function', then provide documentation for any function arguments."}, c.FunctionArgumentSchema
owner: {title: "Owner", type: 'string', description: 'Owner of the property, like "this" or "Math".'}
args: c.array {title: 'Arguments', description: 'If this property has type "function", then provide documentation for any function arguments.'}, c.FunctionArgumentSchema
owner: {title: 'Owner', type: 'string', description: 'Owner of the property, like "this" or "Math".'}
example:
oneOf: [
{title: "Example", type: 'string', description: 'An optional example code block.', format: 'javascript'}
{title: 'Example', type: 'string', description: 'An optional example code block.', format: 'javascript'}
{
type: 'object',
title: "Language Examples",
description: "Examples by code language.",
title: 'Language Examples',
description: 'Examples by code language.',
additionalProperties: {type: 'string', description: 'An example code block.', format: 'javascript'} # TODO: not JS
}
]
snippets: c.object {
title: "Snippets",
description: "List of snippets for the respective programming languages"
title: 'Snippets',
description: 'List of snippets for the respective programming languages'
},
javascript: c.object {title: 'JavaScript'}, c.codeSnippet 'javascript'
coffeescript: c.object {title: 'CoffeeScript'}, c.codeSnippet 'coffee'
@ -59,60 +58,60 @@ PropertyDocumentationSchema = c.object {
lua: c.object {title: 'Lua'}, c.codeSnippet 'lua'
io: c.object {title: 'IO'}, c.codeSnippet 'io'
returns: c.object {
title: "Return Value"
title: 'Return Value'
description: 'Optional documentation of any return value.'
required: ['type']
default: {type: 'null'}
},
type: c.shortString(title: "Type", description: "Type of the return value")
type: c.shortString(title: 'Type', description: 'Type of the return value')
example:
oneOf: [
c.shortString(title: "Example", description: "Example return value")
c.shortString(title: 'Example', description: 'Example return value')
{
type: 'object',
title: "Language Examples",
description: "Example return values by code language.",
title: 'Language Examples',
description: 'Example return values by code language.',
additionalProperties: c.shortString(description: 'Example return value.', format: 'javascript') # TODO: not JS
}
]
description:
oneOf: [
{title: "Description", type: 'string', description: "Description of the return value.", maxLength: 1000}
{title: 'Description', type: 'string', description: 'Description of the return value.', maxLength: 1000}
{
type: 'object',
title: "Language Descriptions",
description: "Example return values by code language.",
additionalProperties: {type: 'string', description: "Description of the return value.", maxLength: 1000}
title: 'Language Descriptions',
description: 'Example return values by code language.',
additionalProperties: {type: 'string', description: 'Description of the return value.', maxLength: 1000}
}
]
DependencySchema = c.object {
title: "Component Dependency"
description: "A Component upon which this Component depends."
"default":
title: 'Component Dependency'
description: 'A Component upon which this Component depends.'
'default':
#original: ?
majorVersion: 0
required: ["original", "majorVersion"]
required: ['original', 'majorVersion']
format: 'latest-version-reference'
links: [{rel: "db", href: "/db/level.component/{(original)}/version/{(majorVersion)}"}]
links: [{rel: 'db', href: '/db/level.component/{(original)}/version/{(majorVersion)}'}]
},
original: c.objectId(title: "Original", description: "A reference to another Component upon which this Component depends.")
original: c.objectId(title: 'Original', description: 'A reference to another Component upon which this Component depends.')
majorVersion:
title: "Major Version"
description: "Which major version of the Component this Component needs."
title: 'Major Version'
description: 'Which major version of the Component this Component needs.'
type: 'integer'
minimum: 0
LevelComponentSchema = c.object {
title: "Component"
description: "A Component which can affect Thang behavior."
required: ["system", "name", "description", "code", "dependencies", "propertyDocumentation", "codeLanguage"]
"default":
system: "ai"
name: "AttacksSelf"
description: "This Component makes the Thang attack itself."
title: 'Component'
description: 'A Component which can affect Thang behavior.'
required: ['system', 'name', 'description', 'code', 'dependencies', 'propertyDocumentation', 'codeLanguage']
'default':
system: 'ai'
name: 'AttacksSelf'
description: 'This Component makes the Thang attack itself.'
code: attackSelfCode
codeLanguage: "coffeescript"
codeLanguage: 'coffeescript'
dependencies: [] # TODO: should depend on something by default
propertyDocumentation: []
}
@ -120,42 +119,41 @@ c.extendNamedProperties LevelComponentSchema # let's have the name be the first
LevelComponentSchema.properties.name.pattern = c.classNamePattern
_.extend LevelComponentSchema.properties,
system:
title: "System"
description: "The short name of the System this Component belongs to, like \"ai\"."
type: "string"
"enum": systems
"default": "ai"
title: 'System'
description: 'The short name of the System this Component belongs to, like \"ai\".'
type: 'string'
'enum': systems
'default': 'ai'
description:
title: "Description"
description: "A short explanation of what this Component does."
type: "string"
title: 'Description'
description: 'A short explanation of what this Component does.'
type: 'string'
maxLength: 2000
"default": "This Component makes the Thang attack itself."
'default': 'This Component makes the Thang attack itself.'
codeLanguage:
type: "string"
title: "Language"
description: "Which programming language this Component is written in."
"enum": ["coffeescript"]
type: 'string'
title: 'Language'
description: 'Which programming language this Component is written in.'
'enum': ['coffeescript']
code:
title: "Code"
description: "The code for this Component, as a CoffeeScript class. TODO: add link to documentation for
how to write these."
"default": attackSelfCode
type: "string"
format: "coffee"
title: 'Code'
description: 'The code for this Component, as a CoffeeScript class. TODO: add link to documentation for how to write these.'
'default': attackSelfCode
type: 'string'
format: 'coffee'
js:
title: "JavaScript"
description: "The transpiled JavaScript code for this Component"
type: "string"
format: "hidden"
dependencies: c.array {title: "Dependencies", description: "An array of Components upon which this Component depends.", "default": [], uniqueItems: true}, DependencySchema
propertyDocumentation: c.array {title: "Property Documentation", description: "An array of documentation entries for each notable property this Component will add to its Thang which other Components might want to also use.", "default": []}, PropertyDocumentationSchema
configSchema: _.extend metaschema, {title: "Configuration Schema", description: "A schema for validating the arguments that can be passed to this Component as configuration.", default: {type: 'object', additionalProperties: false}}
title: 'JavaScript'
description: 'The transpiled JavaScript code for this Component'
type: 'string'
format: 'hidden'
dependencies: c.array {title: 'Dependencies', description: 'An array of Components upon which this Component depends.', 'default': [], uniqueItems: true}, DependencySchema
propertyDocumentation: c.array {title: 'Property Documentation', description: 'An array of documentation entries for each notable property this Component will add to its Thang which other Components might want to also use.', 'default': []}, PropertyDocumentationSchema
configSchema: _.extend metaschema, {title: 'Configuration Schema', description: 'A schema for validating the arguments that can be passed to this Component as configuration.', default: {type: 'object', additionalProperties: false}}
official:
type: "boolean"
title: "Official"
description: "Whether this is an official CodeCombat Component."
"default": false
type: 'boolean'
title: 'Official'
description: 'Whether this is an official CodeCombat Component.'
'default': false
c.extendBasicProperties LevelComponentSchema, 'level.component'
c.extendSearchableProperties LevelComponentSchema

View file

@ -5,22 +5,22 @@ LevelFeedbackLevelSchema = c.object {required: ['original', 'majorVersion']}, {
majorVersion: {type: 'integer', minimum: 0, default: 0}}
LevelFeedbackSchema = c.object {
title: "Feedback"
description: "Feedback on a level."
title: 'Feedback'
description: 'Feedback on a level.'
}
_.extend LevelFeedbackSchema.properties,
# denormalization
creatorName: { type: 'string' }
levelName: { type: 'string' }
levelID: { type: 'string' }
creatorName: {type: 'string'}
levelName: {type: 'string'}
levelID: {type: 'string'}
creator: c.objectId(links: [{rel: 'extra', href: '/db/user/{($)}'}])
created: c.date({title: 'Created', readOnly: true})
creator: c.objectId(links: [{rel: 'extra', href: "/db/user/{($)}"}])
created: c.date( { title: 'Created', readOnly: true })
level: LevelFeedbackLevelSchema
rating: { type: 'number', minimum: 1, maximum: 5 }
review: { type: 'string' }
rating: {type: 'number', minimum: 1, maximum: 5}
review: {type: 'string'}
c.extendBasicProperties LevelFeedbackSchema, 'level.feedback'

Some files were not shown because too many files have changed in this diff Show more