mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-29 18:45:48 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
11a725e992
351 changed files with 4534 additions and 4681 deletions
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}"
|
||||
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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++
|
||||
|
|
|
@ -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.
|
||||
###
|
||||
###
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: ->
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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()
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,58 +80,72 @@ 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 interpretDelta
|
||||
# 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, one path is from the headDeltas, the other is from pendingDeltas
|
||||
# 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
|
||||
continue if i + 1 is paths.length
|
||||
nextPath = paths[i+1]
|
||||
if nextPath.startsWith path
|
||||
headDelta = (headPathMap[path] or headPathMap[nextPath])[0].delta
|
||||
pendingDelta = (pendingPathMap[path] or pendingPathMap[nextPath])[0].delta
|
||||
conflicts.push({headDelta:headDelta, pendingDelta:pendingDelta})
|
||||
pendingDelta.conflict = headDelta
|
||||
headDelta.conflict = pendingDelta
|
||||
offset = 1
|
||||
while i + offset < paths.length
|
||||
# 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
|
||||
|
||||
# Okay, we found two deltas from different groups which conflict
|
||||
for headMetaDelta in (headPathMap[path] or headPathMap[nextPath])
|
||||
headDelta = headMetaDelta.delta
|
||||
for pendingMetaDelta in (pendingPathMap[path] or pendingPathMap[nextPath])
|
||||
pendingDelta = pendingMetaDelta.delta
|
||||
conflicts.push({headDelta: headDelta, pendingDelta: pendingDelta})
|
||||
pendingDelta.conflict = headDelta
|
||||
headDelta.conflict = pendingDelta
|
||||
|
||||
return conflicts if conflicts.length
|
||||
|
||||
|
||||
groupDeltasByAffectingPaths = (deltas) ->
|
||||
metaDeltas = []
|
||||
for delta in deltas
|
||||
conflictPaths = []
|
||||
# We're being fairly liberal with what's a conflict, because the alternative is worse
|
||||
if delta.action is 'moved-index'
|
||||
# every other action affects just the data path, but moved indexes affect a swath
|
||||
indices = [delta.originalIndex, delta.destinationIndex]
|
||||
indices.sort()
|
||||
for index in _.range(indices[0], indices[1]+1)
|
||||
conflictPaths.push delta.dataPath.slice(0, delta.dataPath.length-1).concat(index)
|
||||
# If you moved items around in an array, mark the whole array as a gonner
|
||||
conflictPaths.push delta.dataPath.slice(0, delta.dataPath.length-1)
|
||||
else if delta.action in ['deleted', 'added'] and _.isNumber(delta.dataPath[delta.dataPath.length-1])
|
||||
# If you remove or add items in an array, mark the whole thing as a gonner
|
||||
conflictPaths.push delta.dataPath.slice(0, delta.dataPath.length-1)
|
||||
else
|
||||
conflictPaths.push delta.dataPath
|
||||
for path in conflictPaths
|
||||
|
@ -139,39 +153,21 @@ groupDeltasByAffectingPaths = (deltas) ->
|
|||
delta: delta
|
||||
path: (item.toString() for item in path).join('/')
|
||||
}
|
||||
|
||||
|
||||
map = _.groupBy metaDeltas, 'path'
|
||||
return map
|
||||
|
||||
# Turns out there are cases where a single delta can include paths
|
||||
# that 'conflict' with each other, ie one is a substring of the other
|
||||
# because of moved indices. To handle this case, go through and prune
|
||||
# out all deeper paths that conflict with more shallow paths, so
|
||||
# getConflicts path checking works properly.
|
||||
|
||||
paths = _.keys(map)
|
||||
return map unless paths.length
|
||||
paths.sort()
|
||||
prunedMap = {}
|
||||
previousPath = paths[0]
|
||||
for path, i in paths
|
||||
continue if i is 0
|
||||
continue if path.startsWith previousPath
|
||||
prunedMap[path] = map[path]
|
||||
previousPath = path
|
||||
|
||||
prunedMap
|
||||
|
||||
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]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,42 +1,42 @@
|
|||
module.exports = initializeFacebook = ->
|
||||
# Additional JS functions here
|
||||
window.fbAsyncInit = ->
|
||||
Backbone.Mediator.publish "fbapi-loaded"
|
||||
FB.init
|
||||
appId: (if document.location.origin is "http://localhost:3000" then "607435142676437" else "148832601965463") # App ID
|
||||
channelUrl: document.location.origin + "/channel.html" # Channel File
|
||||
appId: (if document.location.origin is 'http://localhost:3000' then '607435142676437' else '148832601965463') # App ID
|
||||
channelUrl: document.location.origin + '/channel.html' # Channel File
|
||||
status: true # check login status
|
||||
cookie: true # enable cookies to allow the server to access the session
|
||||
xfbml: true # parse XFBML
|
||||
|
||||
|
||||
Backbone.Mediator.publish 'fbapi-loaded'
|
||||
|
||||
# This is fired for any auth related change, such as login, logout or session refresh.
|
||||
FB.Event.subscribe "auth.authResponseChange", (response) ->
|
||||
|
||||
# Here we specify what we do with the response anytime this event occurs.
|
||||
if response.status is "connected"
|
||||
|
||||
FB.Event.subscribe 'auth.authResponseChange', (response) ->
|
||||
|
||||
# Here we specify what we do with the response anytime this event occurs.
|
||||
if response.status is 'connected'
|
||||
|
||||
# They have logged in to the app.
|
||||
Backbone.Mediator.publish "facebook-logged-in",
|
||||
Backbone.Mediator.publish 'facebook-logged-in',
|
||||
response: response
|
||||
|
||||
else if response.status is "not_authorized"
|
||||
else if response.status is 'not_authorized'
|
||||
#
|
||||
else
|
||||
#
|
||||
#
|
||||
|
||||
# Load the SDK asynchronously
|
||||
((d) ->
|
||||
js = undefined
|
||||
id = "facebook-jssdk"
|
||||
ref = d.getElementsByTagName("script")[0]
|
||||
id = 'facebook-jssdk'
|
||||
ref = d.getElementsByTagName('script')[0]
|
||||
return if d.getElementById(id)
|
||||
js = d.createElement("script")
|
||||
js = d.createElement('script')
|
||||
js.id = id
|
||||
js.async = true
|
||||
js.src = "//connect.facebook.net/en_US/all.js"
|
||||
|
||||
#js.src = "//connect.facebook.net/en_US/all/debug.js";
|
||||
js.src = '//connect.facebook.net/en_US/all.js'
|
||||
|
||||
#js.src = '//connect.facebook.net/en_US/all/debug.js'
|
||||
ref.parentNode.insertBefore js, ref
|
||||
return
|
||||
) document
|
||||
|
|
|
@ -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 [
|
||||
|
|
|
@ -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
|
||||
)()
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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' #]]>
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -25,5 +25,4 @@ Dropper = class Dropper
|
|||
drop: ->
|
||||
return @drop_counter > 0
|
||||
|
||||
|
||||
module.exports = new Dropper()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: ->
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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('')
|
||||
|
@ -57,10 +57,10 @@ module.exports.i18n = (say, target, language=me.lang(), fallback='en') ->
|
|||
if target of locale
|
||||
result = locale[target]
|
||||
else continue
|
||||
return result if localeName == language
|
||||
generalResult = result if localeName == generalName
|
||||
fallbackResult = result if localeName == fallback
|
||||
fallforwardResult = result if localeName.indexOf(language) == 0 and not fallforwardResult?
|
||||
return result if localeName is language
|
||||
generalResult = result if localeName is generalName
|
||||
fallbackResult = result if localeName is fallback
|
||||
fallforwardResult = result if localeName.indexOf(language) is 0 and not fallforwardResult?
|
||||
|
||||
return generalResult if generalResult?
|
||||
return fallforwardResult if fallforwardResult?
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
[]
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -101,40 +101,40 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge
|
|||
multiplayer: "Multiplayer"
|
||||
for_developers: "Für Entwickler"
|
||||
|
||||
# play:
|
||||
# choose_your_level: "Choose Your Level"
|
||||
# adventurer_prefix: "You can jump to any level below, or discuss the levels on "
|
||||
# adventurer_forum: "the Adventurer forum"
|
||||
play:
|
||||
choose_your_level: "Wähl dis Level us"
|
||||
adventurer_prefix: "Du chasch zu de untere Level zrugg goh oder die kommende Level diskutiere "
|
||||
adventurer_forum: "s Abentürer-Forum"
|
||||
# adventurer_suffix: "."
|
||||
# campaign_beginner: "Beginner Campaign"
|
||||
# campaign_beginner_description: "... in which you learn the wizardry of programming."
|
||||
# campaign_dev: "Random Harder Levels"
|
||||
# campaign_dev_description: "... in which you learn the interface while doing something a little harder."
|
||||
# campaign_multiplayer: "Multiplayer Arenas"
|
||||
# campaign_multiplayer_description: "... in which you code head-to-head against other players."
|
||||
campaign_beginner: "Afängerkampagne"
|
||||
campaign_beginner_description: "... i dere du d Zauberkunst vom Programmiere lernsch."
|
||||
campaign_dev: "Zuefälligi schwierigeri Level"
|
||||
campaign_dev_description: "... i dene du s Interface kenne lernsch, während du öppis chli Schwierigers machsch."
|
||||
campaign_multiplayer: "Multiplayer Arenas"
|
||||
campaign_multiplayer_description: "... i dene du Chopf a Chopf geg anderi Spieler spielsch."
|
||||
# campaign_player_created: "Player-Created"
|
||||
# campaign_player_created_description: "... in which you battle against the creativity of your fellow <a href=\"/contribute#artisan\">Artisan Wizards</a>."
|
||||
# level_difficulty: "Difficulty: "
|
||||
# play_as: "Play As"
|
||||
# spectate: "Spectate"
|
||||
level_difficulty: "Schwierigkeit: "
|
||||
play_as: "Spiel als"
|
||||
spectate: "Zueluege"
|
||||
|
||||
# contact:
|
||||
# contact_us: "Contact CodeCombat"
|
||||
# welcome: "Good to hear from you! Use this form to send us email. "
|
||||
# contribute_prefix: "If you're interested in contributing, check out our "
|
||||
# contribute_page: "contribute page"
|
||||
contact:
|
||||
contact_us: "CodeCombat kontaktiere"
|
||||
welcome: "Mir ghöred gern vo dir! Benutz das Formular zum üs e E-Mail schicke."
|
||||
contribute_prefix: "Wenn du dra interessiert bisch, mitzhelfe denn lueg doch mol verbii uf üsere"
|
||||
contribute_page: "Contribute Page"
|
||||
# contribute_suffix: "!"
|
||||
# forum_prefix: "For anything public, please try "
|
||||
# forum_page: "our forum"
|
||||
# forum_suffix: " instead."
|
||||
# send: "Send Feedback"
|
||||
forum_prefix: "Für öffentlichi Sache versuechs mol bi"
|
||||
forum_page: "üsem Forum"
|
||||
forum_suffix: " stattdesse."
|
||||
send: "Feedback schicke"
|
||||
# contact_candidate: "Contact Candidate"
|
||||
# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 15% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns."
|
||||
|
||||
diplomat_suggestion:
|
||||
title: "Hilf, CodeCombat z übersetze!"
|
||||
sub_heading: "Mir bruuched dini Sprochfähigkeite."
|
||||
pitch_body: "We develop CodeCombat in English, but we already have players all over the world. Many of them want to play in Swiss German but don't speak English, so if you can speak both, please consider signing up to be a Diplomat and help translate both the CodeCombat website and all the levels into Swiss German."
|
||||
pitch_body: "Mir entwickled CodeCombat in Englisch, aber mir hend scho Spieler uf de ganze Welt. Vieli devo würed gern uf Schwiizerdütsch spiele, aber chönd kei Englisch. Wenn du beides chasch, denk doch mol drüber noh, dich bi üs als Diplomat izträge und z helfe, d CodeCombat Websiite und alli Level uf Schwiizerdütsch z übersetze."
|
||||
missing_translations: "Until we can translate everything into Swiss German, you'll see generic German or English when Swiss German isn't available."
|
||||
learn_more: "Lern meh drüber, en Diplomat zsii"
|
||||
subscribe_as_diplomat: "Abonnier als en Diplomat"
|
||||
|
@ -142,18 +142,18 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge
|
|||
wizard_settings:
|
||||
title: "Zaubereristellige"
|
||||
customize_avatar: "Pass din Avatar ah"
|
||||
# active: "Active"
|
||||
active: "Aktiv"
|
||||
color: "Farb"
|
||||
group: "Gruppe"
|
||||
clothes: "Chleider"
|
||||
# trim: "Trim"
|
||||
trim: "Zueschniide"
|
||||
cloud: "Wolke"
|
||||
team: "Team"
|
||||
spell: "Zauberspruch"
|
||||
boots: "Stiefel"
|
||||
# hue: "Hue"
|
||||
hue: "Färbig"
|
||||
saturation: "Sättigung"
|
||||
# lightness: "Lightness"
|
||||
lightness: "Helligkeit"
|
||||
|
||||
account_settings:
|
||||
title: "Account Istellige"
|
||||
|
@ -166,16 +166,16 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge
|
|||
password_tab: "Passwort"
|
||||
emails_tab: "E-Mails"
|
||||
admin: "Admin"
|
||||
# wizard_color: "Wizard Clothes Color"
|
||||
wizard_color: "Zaubererchleid Farb"
|
||||
new_password: "Neus Passwort"
|
||||
new_password_verify: "Bestätige"
|
||||
email_subscriptions: "E-Mail Abos"
|
||||
email_announcements: "Akündigunge"
|
||||
email_announcements_description: "Bechum Mails mit Neuigkeite und de neuste Entwicklige bi CodeCombat."
|
||||
email_notifications: "Benachrichtigunge"
|
||||
# email_notifications_summary: "Controls for personalized, automatic email notifications related to your CodeCombat activity."
|
||||
# email_any_notes: "Any Notifications"
|
||||
# email_any_notes_description: "Disable to stop all activity notification emails."
|
||||
email_notifications_summary: "Istellige für personalisierti, automatischi E-Mail Notifikatione im Zemehang mit dine CodeCombat Aktivitäte"
|
||||
email_any_notes: "Alli Notifikatione"
|
||||
email_any_notes_description: "Deaktiviere zum kei Aktivitäts-Notifikatione meh per E-Mail becho."
|
||||
# email_recruit_notes: "Job Opportunities"
|
||||
# email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job."
|
||||
# contributor_emails: "Contributor Class Emails"
|
||||
|
@ -192,36 +192,35 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge
|
|||
# sample_profile: "See a sample profile"
|
||||
# view_profile: "View Your Profile"
|
||||
|
||||
# account_profile:
|
||||
# settings: "Settings"
|
||||
# edit_profile: "Edit Profile"
|
||||
# done_editing: "Done Editing"
|
||||
# profile_for_prefix: "Profile for "
|
||||
# profile_for_suffix: ""
|
||||
account_profile:
|
||||
settings: "Istellige"
|
||||
edit_profile: "Profil bearbeite"
|
||||
done_editing: "Fertig mit bearbeite"
|
||||
profile_for_prefix: "Profil für "
|
||||
# profile_for_suffix: ""
|
||||
# featured: "Featured"
|
||||
# not_featured: "Not Featured"
|
||||
# looking_for: "Looking for:"
|
||||
# last_updated: "Last updated:"
|
||||
# contact: "Contact"
|
||||
last_updated: "S letzte Update:"
|
||||
contact: "Kontakt"
|
||||
# active: "Looking for interview offers now"
|
||||
# inactive: "Not looking for offers right now"
|
||||
# complete: "complete"
|
||||
# next: "Next"
|
||||
# next_city: "city?"
|
||||
# next_country: "pick your country."
|
||||
# next_name: "name?"
|
||||
# next_short_description: "write a short description."
|
||||
# next_long_description: "describe your desired position."
|
||||
# next_skills: "list at least five skills."
|
||||
complete: "komplett"
|
||||
next: "Nögst"
|
||||
next_city: "Stadt?"
|
||||
next_country: "wähl dis Land."
|
||||
next_name: "Name?"
|
||||
next_short_description: "schriibe e churzi Beschriibig."
|
||||
next_long_description: "beschriib dini Wunschstell."
|
||||
# next_work: "chronicle your work history."
|
||||
# next_education: "recount your educational ordeals."
|
||||
# next_projects: "show off up to three projects you've worked on."
|
||||
# next_links: "add any personal or social links."
|
||||
next_projects: "Zeig üs bis zu drü Projekt a dene du scho gschaffet hesch."
|
||||
next_links: "füeg persönlichi oder Social Media Links ih."
|
||||
# next_photo: "add an optional professional photo."
|
||||
# next_active: "mark yourself open to offers to show up in searches."
|
||||
# example_blog: "Blog"
|
||||
# example_personal_site: "Personal Site"
|
||||
# links_header: "Personal Links"
|
||||
example_blog: "Blog"
|
||||
example_personal_site: "Eigeni Websiite"
|
||||
links_header: "Eigeni Links"
|
||||
# links_blurb: "Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog."
|
||||
# links_name: "Link Name"
|
||||
# links_name_help: "What are you linking to?"
|
||||
|
@ -324,39 +323,39 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge
|
|||
# other_developers: "Other Developers"
|
||||
# inactive_developers: "Inactive Developers"
|
||||
|
||||
# play_level:
|
||||
# done: "Done"
|
||||
# grid: "Grid"
|
||||
# customize_wizard: "Customize Wizard"
|
||||
# home: "Home"
|
||||
# guide: "Guide"
|
||||
# multiplayer: "Multiplayer"
|
||||
# restart: "Restart"
|
||||
# goals: "Goals"
|
||||
# success: "Success!"
|
||||
# incomplete: "Incomplete"
|
||||
# timed_out: "Ran out of time"
|
||||
# failing: "Failing"
|
||||
# action_timeline: "Action Timeline"
|
||||
# click_to_select: "Click on a unit to select it."
|
||||
# reload_title: "Reload All Code?"
|
||||
# reload_really: "Are you sure you want to reload this level back to the beginning?"
|
||||
# reload_confirm: "Reload All"
|
||||
play_level:
|
||||
done: "Fertig"
|
||||
grid: "Gitter"
|
||||
customize_wizard: "Zauberer apasse"
|
||||
home: "Home"
|
||||
guide: "Aleitig"
|
||||
multiplayer: "Multiplayer"
|
||||
restart: "Neu starte"
|
||||
goals: "Ziel"
|
||||
success: "Erfolg!"
|
||||
incomplete: "Unvollständig"
|
||||
timed_out: "Ziit abglaufe"
|
||||
failing: "Fehler"
|
||||
action_timeline: "Aktionsziitleiste"
|
||||
click_to_select: "Klick uf e Einheit zum sie uswähle."
|
||||
reload_title: "De ganze Code neu lade?"
|
||||
reload_really: "Bisch sicher du willsch level neu lade bis zrugg zum Afang?"
|
||||
reload_confirm: "Alles neu lade"
|
||||
# victory_title_prefix: ""
|
||||
# victory_title_suffix: " Complete"
|
||||
# victory_sign_up: "Sign Up to Save Progress"
|
||||
# victory_sign_up_poke: "Want to save your code? Create a free account!"
|
||||
# victory_rate_the_level: "Rate the level: "
|
||||
# victory_return_to_ladder: "Return to Ladder"
|
||||
# victory_play_next_level: "Play Next Level"
|
||||
victory_title_suffix: " Vollständig"
|
||||
victory_sign_up: "Meld dich ah zum din Fortschritt speichere"
|
||||
victory_sign_up_poke: "Wötsch din Code speichere? Erstell gratis en Account!"
|
||||
victory_rate_the_level: "Bewerte das Level: "
|
||||
victory_return_to_ladder: "Zrugg zum letzte Level"
|
||||
victory_play_next_level: "Spiel s nögste Level"
|
||||
# victory_go_home: "Go Home"
|
||||
# victory_review: "Tell us more!"
|
||||
# victory_hour_of_code_done: "Are You Done?"
|
||||
# victory_hour_of_code_done_yes: "Yes, I'm finished with my Hour of Code™!"
|
||||
# multiplayer_title: "Multiplayer Settings"
|
||||
# multiplayer_link_description: "Give this link to anyone to have them join you."
|
||||
# multiplayer_hint_label: "Hint:"
|
||||
# multiplayer_hint: " Click the link to select all, then press ⌘-C or Ctrl-C to copy the link."
|
||||
victory_review: "Verzell üs meh!"
|
||||
victory_hour_of_code_done: "Bisch fertig?"
|
||||
victory_hour_of_code_done_yes: "Jo, ich bin fertig mit mim Hour of Code™!"
|
||||
multiplayer_title: "Multiplayer Istellige"
|
||||
multiplayer_link_description: "Gib de Link jedem, wo mit dir will spiele."
|
||||
multiplayer_hint_label: "Hiiwis:"
|
||||
multiplayer_hint: " Klick uf de Link zum alles uswähle und druck ⌘-C or Ctrl-C zum de Link kopiere"
|
||||
# multiplayer_coming_soon: "More multiplayer features to come!"
|
||||
# multiplayer_sign_in_leaderboard: "Sign in or create an account and get your solution on the leaderboard."
|
||||
# guide_title: "Guide"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,10 +55,12 @@ 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: ->
|
||||
saveBackup: -> @saveBackupNow()
|
||||
|
||||
saveBackupNow: ->
|
||||
storage.save(@id, @attributes)
|
||||
CocoModel.backedUp[@id] = @
|
||||
|
||||
|
@ -74,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) ->
|
||||
|
@ -84,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()
|
||||
|
@ -95,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) ->
|
||||
|
@ -137,7 +139,6 @@ class CocoModel extends Backbone.Model
|
|||
|
||||
cloneNewMinorVersion: ->
|
||||
newData = _.clone @attributes
|
||||
|
||||
clone = new @constructor(newData)
|
||||
clone
|
||||
|
||||
|
@ -152,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()
|
||||
|
@ -210,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\n', JSON.stringify(delta, null, '\t'), '\n\nto attributes\n\n', newAttributes
|
||||
return false
|
||||
@set newAttributes
|
||||
return true
|
||||
|
@ -224,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: ->
|
||||
|
@ -254,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
|
||||
|
@ -296,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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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}})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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': {}
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -9,7 +9,7 @@ module.exports =
|
|||
[
|
||||
{
|
||||
rel: 'extra'
|
||||
href: "/db/user/{($)}"
|
||||
href: '/db/user/{($)}'
|
||||
}
|
||||
]
|
||||
achievement: c.objectId
|
||||
|
|
|
@ -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
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue