mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-29 10:35:51 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
7d5bcc6365
14 changed files with 73 additions and 61 deletions
|
@ -53,6 +53,7 @@ module.exports = class CoordinateDisplay extends createjs.Container
|
||||||
wop = @camera.screenToWorld x: e.x, y: e.y
|
wop = @camera.screenToWorld x: e.x, y: e.y
|
||||||
wop.x = Math.round wop.x
|
wop.x = Math.round wop.x
|
||||||
wop.y = Math.round wop.y
|
wop.y = Math.round wop.y
|
||||||
|
Backbone.Mediator.publish 'tome:focus-editor', {}
|
||||||
Backbone.Mediator.publish 'surface:coordinate-selected', wop
|
Backbone.Mediator.publish 'surface:coordinate-selected', wop
|
||||||
|
|
||||||
onZoomUpdated: (e) ->
|
onZoomUpdated: (e) ->
|
||||||
|
|
|
@ -26,7 +26,6 @@ module.exports = class Dimmer extends CocoClass
|
||||||
build: ->
|
build: ->
|
||||||
@dimLayer = new createjs.Container()
|
@dimLayer = new createjs.Container()
|
||||||
@dimLayer.mouseEnabled = @dimLayer.mouseChildren = false
|
@dimLayer.mouseEnabled = @dimLayer.mouseChildren = false
|
||||||
@dimLayer.layerIndex = -10
|
|
||||||
@dimLayer.addChild @dimScreen = new createjs.Shape()
|
@dimLayer.addChild @dimScreen = new createjs.Shape()
|
||||||
@dimLayer.addChild @dimMask = 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
|
||||||
|
|
|
@ -45,6 +45,13 @@ module.exports = class Mark extends CocoClass
|
||||||
@mark.visible = true
|
@mark.visible = true
|
||||||
@
|
@
|
||||||
|
|
||||||
|
setLayer: (layer) ->
|
||||||
|
return if layer is @layer
|
||||||
|
wasOn = @on
|
||||||
|
@toggle false
|
||||||
|
@layer = layer
|
||||||
|
@toggle true if wasOn
|
||||||
|
|
||||||
setSprite: (sprite) ->
|
setSprite: (sprite) ->
|
||||||
return if sprite is @sprite
|
return if sprite is @sprite
|
||||||
@sprite = sprite
|
@sprite = sprite
|
||||||
|
@ -131,7 +138,6 @@ module.exports = class Mark extends CocoClass
|
||||||
@mark.graphics.endFill()
|
@mark.graphics.endFill()
|
||||||
@mark.regX = width / 2
|
@mark.regX = width / 2
|
||||||
@mark.regY = height / 2
|
@mark.regY = height / 2
|
||||||
@mark.layerIndex = 10
|
|
||||||
@mark.cache -1, -1, width + 2, height + 2 # not actually faster than simple ellipse draw
|
@mark.cache -1, -1, width + 2, height + 2 # not actually faster than simple ellipse draw
|
||||||
|
|
||||||
buildRadius: (range) ->
|
buildRadius: (range) ->
|
||||||
|
|
|
@ -15,7 +15,6 @@ module.exports = class PlaybackOverScreen extends CocoClass
|
||||||
build: ->
|
build: ->
|
||||||
@dimLayer = new createjs.Container()
|
@dimLayer = new createjs.Container()
|
||||||
@dimLayer.mouseEnabled = @dimLayer.mouseChildren = false
|
@dimLayer.mouseEnabled = @dimLayer.mouseChildren = false
|
||||||
@dimLayer.layerIndex = -12
|
|
||||||
@dimLayer.addChild @dimScreen = new createjs.Shape()
|
@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.cache 0, 0, @camera.canvasWidth, @camera.canvasHeight
|
||||||
|
|
|
@ -21,7 +21,6 @@ module.exports = class PointChooser extends CocoClass
|
||||||
@shape.mouseEnabled = false
|
@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.graphics.drawCircle(0, 0, 4).endFill()
|
||||||
@shape.layerIndex = 100
|
|
||||||
|
|
||||||
onMouseDown: (e) =>
|
onMouseDown: (e) =>
|
||||||
return unless key.shift
|
return unless key.shift
|
||||||
|
|
|
@ -373,6 +373,11 @@ module.exports = class SpriteBoss extends CocoClass
|
||||||
@updateTarget()
|
@updateTarget()
|
||||||
return unless @selectionMark
|
return unless @selectionMark
|
||||||
@selectedSprite = null if @selectedSprite and (@selectedSprite.destroyed or not @selectedSprite.thang)
|
@selectedSprite = null if @selectedSprite and (@selectedSprite.destroyed or not @selectedSprite.thang)
|
||||||
|
# The selection mark should be on the ground layer, unless we're not a normal sprite (like a wall), in which case we'll place it higher so we can see it.
|
||||||
|
if @selectedSprite and @selectedSprite.imageObject.parent isnt @spriteLayers.Default
|
||||||
|
@selectionMark.setLayer @spriteLayers.Default
|
||||||
|
else if @selectedSprite
|
||||||
|
@selectionMark.setLayer @spriteLayers.Ground
|
||||||
@selectionMark.toggle @selectedSprite?
|
@selectionMark.toggle @selectedSprite?
|
||||||
@selectionMark.setSprite @selectedSprite
|
@selectionMark.setSprite @selectedSprite
|
||||||
@selectionMark.update()
|
@selectionMark.update()
|
||||||
|
|
|
@ -483,11 +483,13 @@ module.exports = Surface = class Surface extends CocoClass
|
||||||
worldPos = @camera.screenToWorld x: e.stageX, y: e.stageY
|
worldPos = @camera.screenToWorld x: e.stageX, y: e.stageY
|
||||||
event = onBackground: onBackground, x: e.stageX, y: e.stageY, originalEvent: e, worldPos: worldPos
|
event = onBackground: onBackground, x: e.stageX, y: e.stageY, originalEvent: e, worldPos: worldPos
|
||||||
Backbone.Mediator.publish 'surface:stage-mouse-down', event
|
Backbone.Mediator.publish 'surface:stage-mouse-down', event
|
||||||
|
Backbone.Mediator.publish 'tome:focus-editor', {}
|
||||||
|
|
||||||
onMouseUp: (e) =>
|
onMouseUp: (e) =>
|
||||||
return if @disabled
|
return if @disabled
|
||||||
onBackground = not @stage.hitTest e.stageX, e.stageY
|
onBackground = not @stage.hitTest e.stageX, e.stageY
|
||||||
Backbone.Mediator.publish 'surface:stage-mouse-up', onBackground: onBackground, x: e.stageX, y: e.stageY, originalEvent: e
|
Backbone.Mediator.publish 'surface:stage-mouse-up', onBackground: onBackground, x: e.stageX, y: e.stageY, originalEvent: e
|
||||||
|
Backbone.Mediator.publish 'tome:focus-editor', {}
|
||||||
|
|
||||||
onMouseWheel: (e) =>
|
onMouseWheel: (e) =>
|
||||||
# https://github.com/brandonaaron/jquery-mousewheel
|
# https://github.com/brandonaaron/jquery-mousewheel
|
||||||
|
|
|
@ -92,60 +92,58 @@ module.exports.consolidateThangs = consolidateThangs = (thangs) ->
|
||||||
padding = 0
|
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
|
grid = new Grid structural, width, height, padding, left, bottom
|
||||||
console.log grid.toString() if debug
|
|
||||||
|
|
||||||
# Approach: start at bottom left. Go right, then up. At each occupied grid square, find the largest rectangle we can make starting at that corner, add a corresponding Thang to the grid, and unmark all occupied grid squares.
|
|
||||||
# Since it's not like we're going to do any of these:
|
|
||||||
# http://stackoverflow.com/questions/5919298/algorithm-for-finding-the-fewest-rectangles-to-cover-a-set-of-rectangles
|
|
||||||
# http://stackoverflow.com/questions/4701887/find-the-set-of-largest-contiguous-rectangles-to-cover-multiple-areas
|
|
||||||
dissection = []
|
dissection = []
|
||||||
for y in grid.columns bottom, height
|
addStructuralThang = (rect) ->
|
||||||
for x in grid.rows left, width
|
thang = structural[dissection.length] # Grab one we already know is configured properly.
|
||||||
continue unless grid.grid[y][x].length
|
|
||||||
rect = largestRectangle grid, y, x, false, debug
|
|
||||||
vertices = rect.vertices()
|
|
||||||
for y2 in [vertices[0].y ... vertices[1].y] # maybe ..?
|
|
||||||
for x2 in [vertices[0].x ... vertices[2].x] # maybe ..?
|
|
||||||
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.x = rect.x
|
||||||
thang.pos.y = rect.y
|
thang.pos.y = rect.y
|
||||||
|
thang.width = rect.width
|
||||||
|
thang.height = rect.height
|
||||||
thang.createBodyDef()
|
thang.createBodyDef()
|
||||||
dissection.push thang
|
dissection.push thang
|
||||||
|
|
||||||
|
dissectRectangles grid, addStructuralThang, false, debug
|
||||||
|
|
||||||
|
# Now add the new structural thangs back to thangs and return the ones not in the dissection.
|
||||||
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...
|
thangs.push dissection...
|
||||||
structural[dissection.length ... structural.length]
|
structural[dissection.length ... structural.length]
|
||||||
|
|
||||||
module.exports.largestRectangle = largestRectangle = (grid, bottomY, leftX, wantEmpty, debug) ->
|
|
||||||
# If wantEmpty, then we try to cover empty rectangles.
|
module.exports.dissectRectangles = dissectRectangles = (grid, rectangleCallback, wantEmpty, debug) ->
|
||||||
# Otherwise, we try to cover occupied rectangles.
|
# Mark Maxham's fast sweeper approach: https://github.com/codecombat/codecombat/issues/1090
|
||||||
coveredRows = []
|
console.log grid.toString() if debug
|
||||||
shortestCoveredRow = grid.width - leftX
|
for x in grid.rows grid.left, grid.left + grid.width
|
||||||
for y in grid.columns bottomY, grid.height
|
y = grid.clampColumn grid.bottom
|
||||||
coveredRow = 0
|
while y < grid.clampColumn grid.bottom + grid.height
|
||||||
for x in grid.rows leftX, leftX + shortestCoveredRow
|
y2 = y # Note our current y.
|
||||||
if Boolean(grid.grid[y][x].length) isnt wantEmpty
|
++y2 until occ x, y2, grid, wantEmpty # Sweep through y to expand 1xN rect.
|
||||||
++coveredRow
|
if y2 > y # If we get a hit, sweep X with that swath.
|
||||||
else
|
x2 = x + 1
|
||||||
break
|
++x2 until occCol x2, y, y2, grid, wantEmpty
|
||||||
break unless coveredRow
|
w = x2 - x
|
||||||
coveredRows.push coveredRow
|
h = y2 - y
|
||||||
shortestCoveredRow = Math.min(shortestCoveredRow, coveredRow)
|
rect = addRect grid, x, y, w, h, wantEmpty
|
||||||
console.log 'largestRectangle() for', bottomY, leftX, 'got coveredRows', coveredRows if debug
|
rectangleCallback rect
|
||||||
[maxArea, maxAreaRows, maxAreaRowLength, shortestRow] = [0, 0, 0, 0]
|
console.log grid.toString() if debug
|
||||||
for rowLength, rowIndex in coveredRows
|
y = y2
|
||||||
shortestRow ||= rowLength
|
++y
|
||||||
area = rowLength * (rowIndex + 1)
|
|
||||||
if area > maxArea
|
occ = (x, y, grid, wantEmpty) ->
|
||||||
maxAreaRows = rowIndex + 1
|
return true if y > grid.bottom + grid.height or x > grid.left + grid.width
|
||||||
maxAreaRowLength = shortestRow
|
console.error 'trying to check invalid coordinates', x, y, 'from grid', grid.bottom, grid.left, grid.width, grid.height unless grid.grid[y]?[x]
|
||||||
maxArea = area
|
Boolean(grid.grid[y][x].length) is wantEmpty
|
||||||
shortestRow = Math.min(rowLength, shortestRow)
|
|
||||||
console.log 'So largest rect has area', maxArea, 'with', maxAreaRows, 'rows of length', maxAreaRowLength if debug
|
occCol = (x, y1, y2, grid, wantEmpty) ->
|
||||||
rect = new Rectangle leftX + maxAreaRowLength / 2, bottomY + maxAreaRows / 2, maxAreaRowLength, maxAreaRows
|
for j in [y1 ... y2]
|
||||||
console.log 'That corresponds to a rectangle', rect.toString() if debug
|
if occ(x, j, grid, wantEmpty)
|
||||||
rect
|
return true
|
||||||
|
false
|
||||||
|
|
||||||
|
addRect = (grid, leftX, bottomY, width, height, wantEmpty) ->
|
||||||
|
for x in [leftX ... leftX + width]
|
||||||
|
for y in [bottomY ... bottomY + height]
|
||||||
|
grid.grid[y][x] = if wantEmpty then [true] else []
|
||||||
|
new Rectangle leftX + width / 2, bottomY + height / 2, width, height
|
||||||
|
|
|
@ -23,5 +23,5 @@ module.exports =
|
||||||
bus: {$ref: 'bus'}
|
bus: {$ref: 'bus'}
|
||||||
|
|
||||||
'bus:player-states-changed': c.object {title: 'Player state changes', description: 'State of the players has changed'},
|
'bus:player-states-changed': c.object {title: 'Player state changes', description: 'State of the players has changed'},
|
||||||
states: c.array {}, {type: 'object'}
|
states: {type: 'object', additionalProperties: {type: 'object'}}
|
||||||
bus: {$ref: 'bus'}
|
bus: {$ref: 'bus'}
|
||||||
|
|
|
@ -66,6 +66,7 @@ module.exports = # /app/lib/surface
|
||||||
'surface:coordinate-selected': c.object {required: ['x', 'y']},
|
'surface:coordinate-selected': c.object {required: ['x', 'y']},
|
||||||
x: {type: 'number'}
|
x: {type: 'number'}
|
||||||
y: {type: 'number'}
|
y: {type: 'number'}
|
||||||
|
z: {type: 'number'}
|
||||||
|
|
||||||
'surface:coordinates-shown': c.object {}
|
'surface:coordinates-shown': c.object {}
|
||||||
|
|
||||||
|
@ -76,12 +77,14 @@ module.exports = # /app/lib/surface
|
||||||
point: c.object {required: ['x', 'y']},
|
point: c.object {required: ['x', 'y']},
|
||||||
x: {type: 'number'}
|
x: {type: 'number'}
|
||||||
y: {type: 'number'}
|
y: {type: 'number'}
|
||||||
|
z: {type: 'number'}
|
||||||
|
|
||||||
'surface:choose-region': c.object {required: ['points']},
|
'surface:choose-region': c.object {required: ['points']},
|
||||||
points: c.array {minItems: 2, maxItems: 2},
|
points: c.array {minItems: 2, maxItems: 2},
|
||||||
c.object {required: ['x', 'y']},
|
c.object {required: ['x', 'y']},
|
||||||
x: {type: 'number'}
|
x: {type: 'number'}
|
||||||
y: {type: 'number'}
|
y: {type: 'number'}
|
||||||
|
z: {type: 'number'}
|
||||||
|
|
||||||
'surface:new-thang-added': c.object {required: ['thang', 'sprite']},
|
'surface:new-thang-added': c.object {required: ['thang', 'sprite']},
|
||||||
thang: {type: 'object'}
|
thang: {type: 'object'}
|
||||||
|
|
|
@ -6,7 +6,7 @@ module.exports = class LevelSearchView extends SearchView
|
||||||
model: require 'models/Level'
|
model: require 'models/Level'
|
||||||
modelURL: '/db/level'
|
modelURL: '/db/level'
|
||||||
tableTemplate: require 'templates/editor/level/table'
|
tableTemplate: require 'templates/editor/level/table'
|
||||||
page: 'editor'
|
page: 'level'
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
context = super()
|
context = super()
|
||||||
|
|
|
@ -50,10 +50,11 @@ module.exports = class WizardSettingsModal extends ModalView
|
||||||
res.error =>
|
res.error =>
|
||||||
errors = JSON.parse(res.responseText)
|
errors = JSON.parse(res.responseText)
|
||||||
console.warn 'Got errors saving user:', errors
|
console.warn 'Got errors saving user:', errors
|
||||||
|
return if @destroyed
|
||||||
forms.applyErrorsToForm(@$el, errors)
|
forms.applyErrorsToForm(@$el, errors)
|
||||||
@disableModalInProgress(@$el)
|
@disableModalInProgress(@$el)
|
||||||
|
|
||||||
res.success (model, response, options) =>
|
res.success (model, response, options) =>
|
||||||
@hide()
|
@hide() unless @destroyed
|
||||||
|
|
||||||
@enableModalInProgress(@$el)
|
@enableModalInProgress(@$el)
|
||||||
|
|
|
@ -221,7 +221,6 @@ module.exports = class SpectateLevelView extends RootView
|
||||||
else
|
else
|
||||||
console.log 'World scripts don\'t exist!'
|
console.log 'World scripts don\'t exist!'
|
||||||
nonVictoryPlaybackScripts = []
|
nonVictoryPlaybackScripts = []
|
||||||
console.log nonVictoryPlaybackScripts
|
|
||||||
@scriptManager = new ScriptManager({scripts: nonVictoryPlaybackScripts, view:@, session: @session})
|
@scriptManager = new ScriptManager({scripts: nonVictoryPlaybackScripts, view:@, session: @session})
|
||||||
@scriptManager.loadFromSession()
|
@scriptManager.loadFromSession()
|
||||||
|
|
||||||
|
|
|
@ -234,7 +234,7 @@ module.exports = class LevelPlaybackView extends CocoView
|
||||||
button.addClass(classes[2]) if e.volume >= 1.0
|
button.addClass(classes[2]) if e.volume >= 1.0
|
||||||
|
|
||||||
onScrub: (e, options) ->
|
onScrub: (e, options) ->
|
||||||
e?.preventDefault()
|
e?.preventDefault?()
|
||||||
options.scrubDuration = 500
|
options.scrubDuration = 500
|
||||||
Backbone.Mediator.publish('level:set-time', options)
|
Backbone.Mediator.publish('level:set-time', options)
|
||||||
|
|
||||||
|
@ -347,7 +347,7 @@ module.exports = class LevelPlaybackView extends CocoView
|
||||||
shouldIgnore: -> return @disabled or @realTime
|
shouldIgnore: -> return @disabled or @realTime
|
||||||
|
|
||||||
onTogglePlay: (e) ->
|
onTogglePlay: (e) ->
|
||||||
e?.preventDefault()
|
e?.preventDefault?()
|
||||||
return if @shouldIgnore()
|
return if @shouldIgnore()
|
||||||
button = $('#play-button')
|
button = $('#play-button')
|
||||||
willPlay = button.hasClass('paused') or button.hasClass('ended')
|
willPlay = button.hasClass('paused') or button.hasClass('ended')
|
||||||
|
|
Loading…
Reference in a new issue