Merge branch 'master' into feature/thangload

This commit is contained in:
Scott Erickson 2014-05-13 10:27:10 -07:00
commit 66af855497
18 changed files with 227 additions and 160 deletions

View file

@ -25,7 +25,7 @@ elementAcceptsKeystrokes = (el) ->
# 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)
COMMON_FILES = ['/images/pages/base/modal_background.png', '/images/level/code_palette_background.png']
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) ->
$(arrayOfImages).each ->
$('<img/>')[0].src = @

View file

@ -169,38 +169,8 @@ self.stringifyValue = function(value, depth) {
return "" + prefix + brackets[0] + sep + " " + (values.join(sep + ' ')) + sep + brackets[1];
};
var cache = {};
self.invalidateCache = function () {
cache = {};
};
self.retrieveValueFromCache = function (thangID, spellID, variableChain, frame) {
var frameCache, thangCache, spellCache;
if ((frameCache = cache[frame]) && (thangCache = frameCache[thangID]) && (spellCache = thangCache[spellID]))
return spellCache[variableChain.join()];
return undefined;
};
self.updateCache = function (thangID, spellID, variableChain, frame, value) {
var key, keys, currentObject;
keys = [frame,thangID, spellID, variableChain.join()];
currentObject = cache;
for (var i = 0, len = keys.length - 1; i < len; i++)
{
key = keys[i];
if (!(key in currentObject))
currentObject[key] = {};
currentObject = currentObject[key];
}
currentObject[keys[keys.length - 1]] = value;
};
self.retrieveValueFromFrame = function retrieveValueFromFrame(args) {
var cacheValue;
if (args.frame === self.currentDebugWorldFrame && (cacheValue = self.retrieveValueFromCache(args.currentThangID, args.currentSpellID, args.variableChain, args.frame)))
return self.postMessage({type: 'debug-value-return', serialized: {"key": args.variableChain.join("."), "value": cacheValue}});
var retrieveProperty = function retrieveProperty(currentThangID, currentSpellID, variableChain)
{
@ -253,7 +223,6 @@ self.retrieveValueFromFrame = function retrieveValueFromFrame(args) {
"key": keys.join("."),
"value": self.stringifyValue(value,0)
};
self.updateCache(currentThangID,currentSpellID,variableChain, args.frame, serializedProperty.value);
self.postMessage({type: 'debug-value-return', serialized: serializedProperty});
};
self.enableFlowOnThangSpell(args.currentThangID, args.currentSpellID, args.userCodeMap);
@ -296,7 +265,6 @@ self.setupDebugWorldToRunUntilFrame = function (args) {
var stringifiedUserCodeMap = JSON.stringify(args.userCodeMap);
var userCodeMapHasChanged = ! _.isEqual(self.currentUserCodeMapCopy, stringifiedUserCodeMap);
self.currentUserCodeMapCopy = stringifiedUserCodeMap;
if (args.frame != self.currentDebugWorldFrame) self.invalidateCache();
if (!self.debugWorld || userCodeMapHasChanged || args.frame < self.currentDebugWorldFrame) {
try {
self.debugWorld = new World(args.userCodeMap);
@ -321,7 +289,7 @@ self.setupDebugWorldToRunUntilFrame = function (args) {
self.onDebugWorldLoaded = function onDebugWorldLoaded() {
console.log("Debug world loaded!");
self.postMessage({type: 'debug-world-loaded'});
};
self.onDebugWorldError = function onDebugWorldError(error) {

View file

@ -100,7 +100,7 @@ module.exports = class Angel extends CocoClass
world.findFirstChangedFrame @shared.world
@shared.world = world
errorCount = (t for t in @shared.world.thangs when t.errorsOut).length
Backbone.Mediator.publish 'god:new-world-created', world: world, firstWorld: @shared.firstWorld, errorCount: errorCount, goalStates: goalStates
Backbone.Mediator.publish 'god:new-world-created', world: world, firstWorld: @shared.firstWorld, errorCount: errorCount, goalStates: goalStates, team: me.team
for scriptNote in @shared.world.scriptNotes
Backbone.Mediator.publish scriptNote.channel, scriptNote.event
@shared.goalManager?.world = world
@ -190,7 +190,7 @@ module.exports = class Angel extends CocoClass
goalStates = testGM?.getGoalStates()
serialized = testWorld.serialize().serializedWorld
window.BOX2D_ENABLED = false
World.deserialize serialized, @angelsShare.worldClassMap, @hsared.lastSerializedWorldFrames, @finishBeholdingWorld(goalStates)
World.deserialize serialized, @angelsShare.worldClassMap, @shared.lastSerializedWorldFrames, @finishBeholdingWorld(goalStates)
window.BOX2D_ENABLED = true
@shared.lastSerializedWorldFrames = serialized.frames

View file

@ -93,7 +93,7 @@ module.exports = class God extends CocoClass
return unless args.thangID and args.spellID and args.variableChain
return console.error "Tried to retrieve debug value with no currentUserCodeMap" unless @currentUserCodeMap
@debugWorker ?= @createDebugWorker()
args.frame ?= @world.age / @world.dt
args.frame ?= @angelsShare.world.age / @angelsShare.world.dt
@debugWorker.postMessage
func: 'retrieveValueFromFrame'
args:

View file

@ -30,7 +30,6 @@ module.exports = class SurfaceScriptModule extends ScriptModule
e.pos = focus.target if _.isPlainObject focus.target
e.thangID = focus.target if _.isString focus.target
e.zoom = focus.zoom or 2.0 # TODO: test only doing this if e.pos, e.thangID, or focus.zoom?
e.zoom *= 2 if e.zoom # On 2014-03-16, we doubled the canvas width/height, so now we have a legacy zoom multipler.
e.duration = if focus.duration? then focus.duration else 1500
e.duration = 0 if instant
e.bounds = focus.bounds if focus.bounds?

View file

@ -10,6 +10,8 @@ MIN_ZOOM = 0.1
DEFAULT_ZOOM = 2.0
DEFAULT_TARGET = {x:0, y:0}
DEFAULT_TIME = 1000
STANDARD_ZOOM_WIDTH = 924
STANDARD_ZOOM_HEIGHT = 589
# You can't mutate any of the constructor parameters after construction.
# You can only call zoomTo to change the zoom target and zoom level.
@ -46,12 +48,16 @@ module.exports = class Camera extends CocoClass
constructor: (@canvasWidth, @canvasHeight, angle=Math.asin(0.75), hFOV=d2r(30)) ->
super()
@offset = {x: 0, y:0}
@offset = {x: 0, y: 0}
@calculateViewingAngle angle
@calculateFieldOfView hFOV
@calculateAxisConversionFactors()
@calculateMinMaxZoom()
@updateViewports()
@calculateMinZoom()
onResize: (newCanvasWidth, newCanvasHeight) ->
@canvasScaleFactorX = newCanvasWidth / @canvasWidth
@canvasScaleFactorY = newCanvasHeight / @canvasHeight
calculateViewingAngle: (angle) ->
# Operate on open interval between 0 - 90 degrees to make the math easier
@ -91,15 +97,11 @@ module.exports = class Camera extends CocoClass
surfaceToCanvas: (pos) ->
{x: (pos.x - @surfaceViewport.x) * @zoom, y: (pos.y - @surfaceViewport.y) * @zoom}
# TODO: do we even need separate screen coordinates?
# We would need some other properties for the actual ratio of screen size to canvas size.
canvasToScreen: (pos) ->
#{x: pos.x * @someCanvasToScreenXScaleFactor, y: pos.y * @someCanvasToScreenYScaleFactor}
{x: pos.x, y: pos.y}
{x: pos.x * @canvasScaleFactorX, y: pos.y * @canvasScaleFactorY}
screenToCanvas: (pos) ->
#{x: pos.x / @someCanvasToScreenXScaleFactor, y: pos.y / @someCanvasToScreenYScaleFactor}
{x: pos.x, y: pos.y}
{x: pos.x / @canvasScaleFactorX, y: pos.y / @canvasScaleFactorY}
canvasToSurface: (pos) ->
{x: pos.x / @zoom + @surfaceViewport.x, y: pos.y / @zoom + @surfaceViewport.y}
@ -161,11 +163,9 @@ module.exports = class Camera extends CocoClass
newHeight = @canvasHeight / newZoom
newTargetX = mousePoint.x - (newWidth * ratioPosX) + (newWidth / 2)
newTargetY = mousePoint.y - (newHeight * ratioPosY) + (newHeight / 2)
target = {x: newTargetX, y:newTargetY}
target = {x: newTargetX, y: newTargetY}
else
target = @target
newZoom = Math.min newZoom, MAX_ZOOM
newZoom = Math.max newZoom, MIN_ZOOM, @minZoom
@zoomTo target, newZoom, 0
onMouseDown: (e) ->
@ -175,10 +175,9 @@ module.exports = class Camera extends CocoClass
onMouseDragged: (e) ->
return if @dragDisabled
target = @boundTarget(@target, @zoom)
newPos = {
newPos =
x: target.x + (@lastPos.x - e.originalEvent.rawX) / @zoom
y: target.y + (@lastPos.y - e.originalEvent.rawY) / @zoom
}
@zoomTo newPos, @zoom, 0
@lastPos = {x: e.originalEvent.rawX, y: e.originalEvent.rawY}
Backbone.Mediator.publish 'camera:dragged'
@ -192,7 +191,7 @@ module.exports = class Camera extends CocoClass
# receives an array of two world points. Normalize and apply them
@firstBounds = worldBounds unless @firstBounds
@bounds = @normalizeBounds(worldBounds)
@calculateMinZoom()
@calculateMinMaxZoom()
@updateZoom true if updateZoom
@target = @currentTarget unless @focusedOnSprite()
@ -208,29 +207,31 @@ module.exports = class Camera extends CocoClass
p2 = @worldToSurface({x:right, y:bottom})
{x:p1.x, y:p1.y, width:p2.x-p1.x, height:p2.y-p1.y}
calculateMinZoom: ->
calculateMinMaxZoom: ->
# Zoom targets are always done in Surface coordinates.
if not @bounds
@minZoom = 0.5
return
@maxZoom = MAX_ZOOM
return @minZoom = MIN_ZOOM unless @bounds
@minZoom = Math.max @canvasWidth / @bounds.width, @canvasHeight / @bounds.height
@zoom = Math.max(@minZoom, @zoom) if @zoom
if @zoom
@zoom = Math.max @minZoom, @zoom
@zoom = Math.min @maxZoom, @zoom
zoomTo: (newTarget=null, newZoom=1.0, time=1500) ->
# Target is either just a {x, y} pos or a display object with {x, y} that might change; surface coordinates.
time = 0 if @instant
newTarget ?= {x:0, y:0}
newTarget ?= {x: 0, y: 0}
newTarget = (@newTarget or @target) if @locked
newZoom = Math.min((Math.max @minZoom, newZoom), MAX_ZOOM)
newZoom = Math.max newZoom, @minZoom
newZoom = Math.min newZoom, @maxZoom
thangType = @target?.sprite?.thangType
if thangType
@offset = _.clone(thangType.get('positions')?.torso or {x: 0, y:0})
@offset = _.clone(thangType.get('positions')?.torso or {x: 0, y: 0})
scale = thangType.get('scale') or 1
@offset.x *= scale
@offset.y *= scale
else
@offset = {x: 0, y:0}
@offset = {x: 0, y: 0}
return if @zoom is newZoom and newTarget is newTarget.x and newTarget.y is newTarget.y
@ -311,4 +312,4 @@ module.exports = class Camera extends CocoClass
super()
onZoomTo: (pos, time) ->
@zoomTo(@worldToSurface(pos), @zoom, time)
@zoomTo @worldToSurface(pos), @zoom, time

View file

@ -24,7 +24,7 @@ module.exports = class CoordinateDisplay extends createjs.Container
build: ->
@mouseEnabled = @mouseChildren = false
@addChild @background = new createjs.Shape()
@addChild @label = new createjs.Text("", "bold 32px 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"
@ -37,7 +37,7 @@ module.exports = class CoordinateDisplay extends createjs.Container
$('#surface').addClass('flag-cursor') unless $('#surface').hasClass('flag-cursor')
else if @mouseInBounds
$('#surface').removeClass('flag-cursor') if $('#surface').hasClass('flag-cursor')
wop = @camera.canvasToWorld x: e.x, y: e.y
wop = @camera.screenToWorld x: e.x, y: e.y
wop.x = Math.round(wop.x)
wop.y = Math.round(wop.y)
return if wop.x is @lastPos?.x and wop.y is @lastPos?.y
@ -47,7 +47,7 @@ module.exports = class CoordinateDisplay extends createjs.Container
onMouseDown: (e) ->
return unless key.shift
wop = @camera.canvasToWorld x: e.x, y: e.y
wop = @camera.screenToWorld x: e.x, y: e.y
wop.x = Math.round wop.x
wop.y = Math.round wop.y
Backbone.Mediator.publish 'surface:coordinate-selected', wop
@ -63,8 +63,8 @@ module.exports = class CoordinateDisplay extends createjs.Container
@uncache()
updateSize: ->
margin = 6
radius = 5
margin = 3
radius = 2.5
width = @label.getMeasuredWidth() + 2 * margin
height = @label.getMeasuredHeight() + 2 * margin
@label.regX = @background.regX = width / 2 - margin
@ -85,7 +85,7 @@ module.exports = class CoordinateDisplay extends createjs.Container
[width, height] = @updateSize()
sup = @camera.worldToSurface @lastPos
@x = sup.x
@y = sup.y - 5
@y = sup.y - 2.5
@addChild @background
@addChild @label
@cache -width / 2, -height / 2, width, height

View file

@ -25,10 +25,10 @@ module.exports = class DebugDisplay extends createjs.Container
build: ->
@mouseEnabled = @mouseChildren = false
@addChild @frameText = new createjs.Text "...", "40px Arial", "#FFF"
@addChild @frameText = new createjs.Text "...", "20px Arial", "#FFF"
@frameText.name = 'frame text'
@frameText.x = @canvasWidth - 100
@frameText.y = @canvasHeight - 50
@frameText.x = @canvasWidth - 50
@frameText.y = @canvasHeight - 25
@frameText.alpha = 0.5
updateFrame: (currentFrame) ->
@ -42,4 +42,4 @@ module.exports = class DebugDisplay extends createjs.Container
@framesRenderedThisSecond = 0
@frameText.text = Math.round(currentFrame) + (if @fps? then " - " + @fps + ' fps' else '')
@frameText.x = @canvasWidth - @frameText.getMeasuredWidth() - 20
@frameText.x = @canvasWidth - @frameText.getMeasuredWidth() - 10

View file

@ -61,7 +61,7 @@ module.exports = class Label extends CocoClass
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.fontSize = {D: 50, S: 24, N: 24}[st]
o.fontSize = {D: 25, S: 12, N: 12}[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]
@ -174,6 +174,8 @@ module.exports = class Label extends CocoClass
if width > maxWidth
if row.length is 1 # one long word, truncate it
row[0] = _.string.truncate(row[0], 40)
text.text = row[0]
textWidth = Math.max(text.getMeasuredWidth(), textWidth)
rows.push(row)
row = []
else
@ -182,7 +184,7 @@ module.exports = class Label extends CocoClass
row = [word]
else
textWidth = Math.max(textWidth, width)
rows.push(row)
rows.push(row) if row.length
for row, i in rows
rows[i] = _.string.join(" ", row...)
text: _.string.join("\n", rows...), textWidth: textWidth

View file

@ -81,7 +81,7 @@ module.exports = class Mark extends CocoClass
shape.graphics.endStroke()
shape.graphics.endFill()
text = new createjs.Text "" + index, "40px Arial", color.replace('0.5', '1')
text = new createjs.Text "" + index, "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)

View file

@ -20,7 +20,6 @@ module.exports = class SpriteBoss extends CocoClass
'level-lock-select': 'onSetLockSelect'
'level:restarted': 'onLevelRestarted'
'god:new-world-created': 'onNewWorld'
'tome:cast-spells': 'onCastSpells'
'camera:dragged': 'onCameraDragged'
'sprite:loaded': -> @update(true)
@ -222,9 +221,6 @@ module.exports = class SpriteBoss extends CocoClass
onNewWorld: (e) ->
@world = @options.world = e.world
@play()
onCastSpells: (e) -> @stop() unless e.preload
play: ->
sprite.play() for sprite in @spriteArray
@ -270,7 +266,7 @@ module.exports = class SpriteBoss extends CocoClass
worldPos = sprite?.thang?.pos
worldPos ?= @camera.canvasToWorld {x: e.originalEvent.rawX, y: e.originalEvent.rawY} if e
if worldPos and (@options.navigateToSelection or not sprite or treemaThangSelected)
@camera.zoomTo(sprite?.displayObject or @camera.worldToSurface(worldPos), @camera.zoom, 1000)
@camera.zoomTo(sprite?.displayObject or @camera.worldToSurface(worldPos), @camera.zoom, 1000, true)
sprite = null if @options.choosing # Don't select sprites while choosing
if sprite isnt @selectedSprite
@selectedSprite?.selected = false

View file

@ -66,6 +66,7 @@ module.exports = Surface = class Surface extends CocoClass
'tome:cast-spells': 'onCastSpells'
'level-set-letterbox': 'onSetLetterbox'
'application:idle-changed': 'onIdleChanged'
'camera:zoom-updated': 'onZoomUpdated'
shortcuts:
'ctrl+\\, ⌘+\\': 'onToggleDebug'
@ -81,6 +82,8 @@ module.exports = Surface = class Surface extends CocoClass
@options = _.extend(@options, givenOptions) if givenOptions
@initEasel()
@initAudio()
@onResize = _.debounce @onResize, 500
$(window).on 'resize', @onResize
destroy: ->
@dead = true
@ -102,6 +105,9 @@ module.exports = Surface = class Surface extends CocoClass
@stage.enableDOMEvents false
@stage.enableMouseOver 0
@canvas.off 'mousewheel', @onMouseWheel
$(window).off 'resize', @onResize
clearTimeout @surfacePauseTimeout if @surfacePauseTimeout
clearTimeout @surfaceZoomPauseTimeout if @surfaceZoomPauseTimeout
super()
setWorld: (@world) ->
@ -250,6 +256,11 @@ module.exports = Surface = class Surface extends CocoClass
@cameraBorder.updateBounds @camera.bounds
@camera.zoomTo target, e.zoom, e.duration # TODO: SurfaceScriptModule perhaps shouldn't assign e.zoom if not set
onZoomUpdated: (e) ->
if @ended
@setPaused false
@surfaceZoomPauseTimeout = _.delay (=> @setPaused true), 3000
setDisabled: (@disabled) ->
@spriteBoss.disabled = @disabled
@ -302,14 +313,10 @@ module.exports = Surface = class Surface extends CocoClass
)
if @lastFrame < @world.totalFrames and @currentFrame >= @world.totalFrames - 1
@spriteBoss.stop()
@playbackOverScreen.show()
@ended = true
@setPaused true
Backbone.Mediator.publish 'surface:playback-ended'
else if @currentFrame < @world.totalFrames and @ended
@spriteBoss.play()
@playbackOverScreen.hide()
@ended = false
@setPaused false
Backbone.Mediator.publish 'surface:playback-restarted'
@ -319,20 +326,27 @@ module.exports = Surface = class Surface extends CocoClass
onIdleChanged: (e) ->
@setPaused e.idle unless @ended
setPaused: (to) ->
setPaused: (paused) ->
# We want to be able to essentially stop rendering the surface if it doesn't need to animate anything.
# If pausing, though, we want to give it enough time to finish any tweens.
performToggle = =>
createjs.Ticker.setFPS if to then 1 else @options.frameRate
@surfacePauseInterval = null
clearTimeout @surfacePauseInterval if @surfacePauseInterval
if to
@surfacePauseInterval = _.delay performToggle, 2000
createjs.Ticker.setFPS if paused then 1 else @options.frameRate
@surfacePauseTimeout = null
clearTimeout @surfacePauseTimeout if @surfacePauseTimeout
clearTimeout @surfaceZoomPauseTimeout if @surfaceZoomPauseTimeout
@surfacePauseTimeout = @surfaceZoomPauseTimeout = null
if paused
@surfacePauseTimeout = _.delay performToggle, 2000
@spriteBoss.stop()
@playbackOverScreen.show()
else
performToggle()
@spriteBoss.play()
@playbackOverScreen.hide()
onCastSpells: (e) ->
return if e.preload
@setPaused false if @ended
@casting = true
@wasPlayingWhenCastingBegan = @playing
Backbone.Mediator.publish 'level-set-playing', { playing: false }
@ -347,6 +361,10 @@ module.exports = Surface = class Surface extends CocoClass
onNewWorld: (event) ->
return unless event.world.name is @world.name
@casting = false
if @ended and not @wasPlayingWhenCastingBegan
@setPaused true
else
@spriteBoss.play()
# 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.
@ -377,8 +395,8 @@ module.exports = Surface = class Surface extends CocoClass
initEasel: ->
# takes DOM objects, not jQuery objects
@stage = new createjs.Stage(@canvas[0])
canvasWidth = parseInt(@canvas.attr('width'), 10)
canvasHeight = parseInt(@canvas.attr('height'), 10)
canvasWidth = parseInt @canvas.attr('width'), 10
canvasHeight = parseInt @canvas.attr('height'), 10
@camera?.destroy()
@camera = new Camera canvasWidth, canvasHeight
AudioPlayer.camera = @camera
@ -398,6 +416,17 @@ module.exports = Surface = class Surface extends CocoClass
@hookUpChooseControls() if @options.choosing
createjs.Ticker.timingMode = createjs.Ticker.RAF_SYNCHED
createjs.Ticker.setFPS @options.frameRate
@onResize()
onResize: (e) =>
oldWidth = parseInt @canvas.attr('width'), 10
oldHeight = parseInt @canvas.attr('height'), 10
newWidth = @canvas.width()
newHeight = @canvas.height()
@canvas.attr width: newWidth, height: newHeight
@stage.scaleX *= newWidth / oldWidth
@stage.scaleY *= newHeight / oldHeight
@camera.onResize newWidth, newHeight
showLevel: ->
return if @dead

View file

@ -237,12 +237,12 @@ module.exports = class GoalManager extends CocoClass
# 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.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'

View file

@ -2,6 +2,7 @@
@import "app/styles/bootstrap/mixins"
#gold-view
display: none
position: absolute
right: 46%
top: 42px

View file

@ -174,7 +174,7 @@ module.exports = class MyMatchesTabView extends CocoView
button = $(e.target).closest('.rank-button')
sessionID = button.data('session-id')
session = _.find @sessions.models, {id: sessionID}
return unless @readyToRank(session)
return unless session.readyToRank()
@setRankingButtonText(button, 'submitting')
success = =>

View file

@ -15,6 +15,7 @@ module.exports = class DebugView extends View
'god:new-world-created': 'onNewWorld'
'god:debug-value-return': 'handleDebugValue'
'tome:spell-shown': 'changeCurrentThangAndSpell'
'tome:cast-spells': 'onTomeCast'
'surface:frame-changed': 'onFrameChanged'
events: {}
@ -30,16 +31,50 @@ module.exports = class DebugView extends View
@globals[className] = serializedClass
@onMouseMove = _.throttle @onMouseMove, 25
@cache = {}
@lastFrameRequested = -1
@workerIsSimulating = false
setTooltipKeyAndValue: (key, value) =>
@$el.find("code").text "#{key}: #{value}"
@$el.show().css(@pos)
setTooltipText: (text) =>
#perhaps changing styling here in the future
@$el.find("code").text text
@$el.show().css(@pos)
onTomeCast: ->
@invalidateCache()
invalidateCache: -> @cache = {}
retrieveValueFromCache: (thangID,spellID,variableChain,frame) ->
joinedVariableChain = variableChain.join()
value = @cache[frame]?[thangID]?[spellID]?[joinedVariableChain]
return value ? undefined
updateCache: (thangID, spellID, variableChain, frame, value) ->
currentObject = @cache
keys = [frame,thangID,spellID,variableChain.join()]
for keyIndex in [0...(keys.length - 1)]
key = keys[keyIndex]
unless key of currentObject
currentObject[key] = {}
currentObject = currentObject[key]
currentObject[keys[keys.length - 1]] = value
changeCurrentThangAndSpell: (thangAndSpellObject) ->
@thang = thangAndSpellObject.thang
@spell = thangAndSpellObject.spell
handleDebugValue: (returnObject) ->
@workerIsSimulating = false
{key, value} = returnObject
@updateCache(@thang.id,@spell.name,key.split("."),@lastFrameRequested,value)
if @variableChain and not key is @variableChain.join(".") then return
@$el.find("code").text "#{key}: #{value}"
@$el.show().css(@pos)
@setTooltipKeyAndValue(key,value)
afterRender: ->
@ -99,13 +134,19 @@ module.exports = class DebugView extends View
update: ->
if @variableChain
Backbone.Mediator.publish 'tome:spell-debug-value-request',
thangID: @thang.id
spellID: @spell.name
variableChain: @variableChain
frame: @currentFrame
@$el.find("code").text "Finding value..."
@$el.show().css(@pos)
if @workerIsSimulating
@setTooltipText("World is simulating, please wait...")
else if @currentFrame is @lastFrameRequested and (cacheValue = @retrieveValueFromCache(@thang.id, @spell.name, @variableChain, @currentFrame))
@setTooltipKeyAndValue(@variableChain.join("."),cacheValue)
else
Backbone.Mediator.publish 'tome:spell-debug-value-request',
thangID: @thang.id
spellID: @spell.name
variableChain: @variableChain
frame: @currentFrame
if @currentFrame isnt @lastFrameRequested then @workerIsSimulating = true
@lastFrameRequested = @currentFrame
@setTooltipText("Finding value...")
else
@$el.hide()
if @variableChain?.length is 2
@ -129,60 +170,6 @@ module.exports = class DebugView extends View
if @markerRange
@marker = @ace.getSession().addMarker @markerRange, "ace_bracket", "text"
stringifyValue: (value, depth) ->
return value if not value or _.isString value
if _.isFunction value
return if depth is 2 then undefined else "<Function>"
return "<this #{value.id}>" if value is @thang and depth
if depth is 2
if value.constructor?.className is "Thang"
value = "<#{value.type or value.spriteName} - #{value.id}, #{if value.pos then value.pos.toString() else 'non-physical'}>"
else
value = value.toString()
return value
isArray = _.isArray value
isObject = _.isObject value
return value.toString() unless isArray or isObject
brackets = if isArray then ["[", "]"] else ["{", "}"]
size = _.size value
return brackets.join "" unless size
values = []
if isArray
for v in value
s = @stringifyValue(v, depth + 1)
values.push "" + s unless s is undefined
else
for key in value.apiProperties ? _.keys value
s = @stringifyValue(value[key], depth + 1)
values.push key + ": " + s unless s is undefined
sep = '\n' + (" " for i in [0 ... depth]).join('')
prefix = value.constructor?.className
prefix ?= "Array" if isArray
prefix ?= "Object" if isObject
prefix = if prefix then prefix + " " else ""
return "#{prefix}#{brackets[0]}#{sep} #{values.join(sep + ' ')}#{sep}#{brackets[1]}"
deserializeVariableChain: (chain) ->
keys = []
for prop, i in chain
if prop is "this"
value = @thang
else if i is 0
value = @variableStates[prop]
if typeof value is "undefined" then value = @globals[prop]
else
value = value[prop]
keys.push prop
break unless value
if theClass = serializedClasses[value.CN]
if value.CN is "Thang"
thang = @thang.world.thangMap[value.id]
value = thang or "<Thang #{value.id} (non-existent)>"
else
value = theClass.deserializeFromAether(value)
value = @stringifyValue value, 0
key: keys.join("."), value: value
destroy: ->
@ace?.removeEventListener "mousemove", @onMouseMove

View file

@ -469,7 +469,7 @@ module.exports = class PlayLevelView extends View
onSessionWillSave: (e) ->
# Something interesting has happened, so (at a lower frequency), we'll save a screenshot.
@saveScreenshot e.session
#@saveScreenshot e.session
# Throttled
saveScreenshot: (session) =>

84
scripts/transpile.coffee Normal file
View file

@ -0,0 +1,84 @@
do (setupLodash = this) ->
GLOBAL._ = require 'lodash'
_.str = require 'underscore.string'
_.mixin _.str.exports()
Aether = require "aether"
async = require 'async'
serverSetup = require '../server_setup'
Level = require '../server/levels/Level.coffee'
LevelSession = require '../server/levels/sessions/LevelSession.coffee'
Aether.addGlobal 'Vector', require '../app/lib/world/vector'
Aether.addGlobal '_', _
transpileLevelSession = (sessionID, cb) ->
query = LevelSession
.find("_id": sessionID)
.select("submittedCode")
.lean()
query.exec (err, session) ->
if err then return cb err
submittedCode = session.submittedCode
transpiledCode = {}
for thang, spells of submittedCode
transpiledCode[thang] = {}
for spellID, spell of spells
aetherOptions =
problems: {}
language: "javascript"
functionName: spellID
functionParameters: {}
yieldConditionally: spellID is "plan"
globals: ['Vector', '_']
protectAPI: true
includeFlow: false
aether = new Aether aetherOptions
transpiledCode[thang][spellID] = aether.transpile spell
cb "Prematurely ended"
findLadderLevelSessions = (levelID, cb) ->
queryParameters =
level:
original: levelID + ""
submitted: true
selectString = "_id"
query = LevelSession
.find(queryParameters)
.select(selectString)
.lean()
query.exec (err, levelSessions) ->
if err then return cb err
levelSessionIDs = _.pluck levelSessions, "_id"
async.each levelSessionIDs, transpileLevelSession, (err) ->
if err then return cb err
cb null
transpileLadderSessions = ->
queryParameters =
type: "ladder"
version:
"isLatestMajor": true
"isLatestMinor": true
selectString = "original"
query = Level
.find(queryParameters)
.select(selectString)
.lean()
query.exec (err, ladderLevels) ->
throw err if err
ladderLevels = _.pluck ladderLevels, "original"
console.log "Found ladderlevels"
console.log ladderLevels
async.each ladderLevels, findLadderLevelSessions, (err) ->
throw err if err
serverSetup.connectToDatabase()
transpileLadderSessions()