mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 17:45:40 -05:00
Merge branch 'master' into feature/thangload
This commit is contained in:
commit
66af855497
18 changed files with 227 additions and 160 deletions
|
@ -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 = @
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
@import "app/styles/bootstrap/mixins"
|
||||
|
||||
#gold-view
|
||||
display: none
|
||||
position: absolute
|
||||
right: 46%
|
||||
top: 42px
|
||||
|
|
|
@ -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 = =>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
84
scripts/transpile.coffee
Normal 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()
|
||||
|
||||
|
Loading…
Reference in a new issue