Merge pull request #943 from codecombat/master

Master into production
This commit is contained in:
Michael Schmatz 2014-05-01 16:46:31 -07:00
commit b7ddbe74a9
15 changed files with 60 additions and 154 deletions

View file

@ -121,7 +121,7 @@ module.exports = class LevelLoader extends CocoClass
url = "/db/level/#{obj.original}/version/#{obj.majorVersion}"
@maybeLoadURL url, Level, 'level'
unless @headless
unless @headless and not @editorMode
wizard = ThangType.loadUniversalWizard()
@supermodel.loadModel wizard, 'thang'

View file

@ -1,104 +0,0 @@
CocoClass = require 'lib/CocoClass'
module.exports = class LoadingScreen extends CocoClass
progress: 0
constructor: (canvas) ->
super()
@width = canvas.width
@height = canvas.height
@stage = new createjs.Stage(canvas)
subscriptions:
'level-loader:progress-changed': 'onLevelLoaderProgressChanged'
show: ->
@stage.removeChild(@screen) if @screen
@screen = @makeScreen()
@stage.addChild(@screen)
@updateProgressBar()
hide: ->
@stage.removeChild(@screen) if @screen
@screen = null
makeScreen: ->
c = new createjs.Container()
c.addChild(@makeLoadBackground())
c.addChild(@makeLoadText())
c.addChild(@makeProgressBar())
@makeLoadLogo(c)
c
makeLoadBackground: ->
g = new createjs.Graphics()
g.beginFill(createjs.Graphics.getRGB(30,30,60))
g.drawRoundRect(0, 0, @width, @height, 0.0)
s = new createjs.Shape(g)
s.y = 0
s.x = 0
s
makeLoadLogo: (container) ->
logoImage = new Image()
$(logoImage).load =>
@logo = new createjs.Bitmap logoImage
@logo.x = @width / 2 - logoImage.width / 2
@logo.y = 40
container.addChild @logo
logoImage.src = "/images/loading_image.png"
makeLoadText: ->
size = @height / 10
text = new createjs.Text("LOADING", "#{size}px Monospace", "#ff7700")
text.regX = text.getMeasuredWidth() / 2
text.regY = text.getMeasuredHeight() / 2
text.x = @width / 2
text.y = @height / 2
@text = text
return text
makeProgressBar: ->
BAR_PIXEL_HEIGHT = 20
BAR_PCT_WIDTH = .75
pixelWidth = parseInt(@width * BAR_PCT_WIDTH)
pixelMargin = (@width - (@width * BAR_PCT_WIDTH)) / 2
barY = 2 * (@height / 3)
c = new createjs.Container()
c.x = pixelMargin
c.y = barY
g = new createjs.Graphics()
g.beginFill(createjs.Graphics.getRGB(255,0,0))
g.drawRoundRect(0,0,pixelWidth, BAR_PIXEL_HEIGHT, 5)
@progressBar = new createjs.Shape(g)
c.addChild(@progressBar)
g = new createjs.Graphics()
g.setStrokeStyle(2)
g.beginStroke(createjs.Graphics.getRGB(230,230,230))
g.drawRoundRect(0,0,pixelWidth, BAR_PIXEL_HEIGHT, 5)
c.addChild(new createjs.Shape(g))
c
onLevelLoaderProgressChanged: (e) ->
@progress = e.progress
@updateProgressBar()
updateProgressBar: ->
newProg = parseInt((@progress or 0) * 100)
newProg = ' '+newProg while newProg.length < 4
@lastProg = newProg
@text.text = "BUILDING" if @progress is 1
@progressBar.scaleX = @progress
@stage.update()
showReady: ->
@text.text = 'READY'
@text.regX = @text.getMeasuredWidth() / 2
@stage.update()
destroy: ->
@stage.canvas = null
super()

View file

@ -96,11 +96,8 @@ module.exports = class SpriteBoss extends CocoClass
unless @indieSprites
@indieSprites = []
@indieSprites = (@createIndieSprite indieSprite for indieSprite in indieSprites) if indieSprites
unless @selfWizardSprite
if withWizards and not @selfWizardSprite
@selfWizardSprite = @createWizardSprite thangID: "My Wizard", isSelf: true, sprites: @sprites
unless withWizards
@selfWizardSprite.displayObject.visible = false
@selfWizardSprite.labels.name.setText null
createIndieSprite: (indieSprite) ->
unless thangType = @thangTypeFor indieSprite.thangType

View file

@ -29,8 +29,8 @@ module.exports = class ThangState
value = thang[prop]
if type is 'Vector'
@props.push value?.copy() # could try storing [x, y, z] or {x, y, z} here instead if this is expensive
else if type is 'object'
@props.push = clone(value, true)
else if type is 'object' or type is 'array'
@props.push clone(value, true)
else
@props.push value
@ -98,7 +98,7 @@ module.exports = class ThangState
storage = @trackedPropertyValues[propIndex]
value = @getStoredProp propIndex, type, storage
if prop is "pos"
if @thang.pos.distanceSquared(value) > 900
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
else
@ -144,6 +144,8 @@ module.exports = class ThangState
# We make sure the array keys won't collide with any string keys by using some unprintable characters.
stringPieces = ['\x1D'] # Group Separator
for element in value
if element and element.isThang
element = element.id
stringPieces.push element, '\x1E' # Record Separator(s)
value = stringPieces.join('')
specialKey = specialValuesToKeys[value]

View file

@ -42,12 +42,15 @@ module.exports.clone = clone = (obj, skipThangs=false) ->
if skipThangs and obj.isThang
return obj
if _.isArray obj
return obj.slice()
if ArrayBufferView and obj instanceof ArrayBufferView
newInstance = new obj.constructor obj
else
newInstance = new obj.constructor()
for key of obj
newInstance[key] = clone obj[key]
return new obj.constructor obj
newInstance = new obj.constructor()
for key of obj
newInstance[key] = clone obj[key], skipThangs
newInstance

View file

@ -40,3 +40,6 @@
font-size: 13px
height: 24px
#level-done-button
display: none

View file

@ -1,4 +1,4 @@
@import "../../../bootstrap/mixins"
@import "app/styles/bootstrap/mixins"
@mixin editor-height($extraHeight)
@include box-sizing(border-box)
@ -123,3 +123,13 @@
// https://github.com/codecombat/codecombat/issues/6
color: rgb(145, 48, 50)
.ace_search
background-color: rgba(216, 187, 165, 1)
border: 0
@include box-shadow(1px 2px 1px #444)
.ace_search_field
width: 190px
.ace_searchbtn, .ace_replacebtn
padding: 0px 4px

View file

@ -17,4 +17,4 @@ if spectateGame
button.btn.btn-xs.btn-inverse.banner#restart-button(title="Reload all custom code to reset level", data-i18n="play_level.restart") Restart
button.btn.btn-xs.btn-primary.banner.secret#level-done-button(data-i18n="play_level.done") Done
button.btn.btn-xs.btn-primary.banner#level-done-button(data-i18n="play_level.done") Done

View file

@ -64,7 +64,7 @@ module.exports = class EditorLevelView extends View
return unless @supermodel.finished()
@$el.find('a[data-toggle="tab"]').on 'shown.bs.tab', (e) =>
Backbone.Mediator.publish 'level:view-switched', e
@thangsTab = @insertSubView new ThangsTabView world: @world, supermodel: @supermodel
@thangsTab = @insertSubView new ThangsTabView world: @world, supermodel: @supermodel, level: @level
@settingsTab = @insertSubView new SettingsTabView supermodel: @supermodel
@scriptsTab = @insertSubView new ScriptsTabView world: @world, supermodel: @supermodel, files: @files
@componentsTab = @insertSubView new ComponentsTabView supermodel: @supermodel

View file

@ -35,7 +35,6 @@ module.exports = class ThangsTabView extends View
'surface:mouse-moved': 'onSurfaceMouseMoved'
'surface:mouse-over': 'onSurfaceMouseOver'
'surface:mouse-out': 'onSurfaceMouseOut'
'level-loaded': 'onLevelLoaded'
'edit-level-thang': 'editThang'
'level-thang-edited': 'onLevelThangEdited'
'level-thang-done-editing': 'onLevelThangDoneEditing'
@ -68,6 +67,7 @@ module.exports = class ThangsTabView extends View
@thangTypes = @supermodel.loadCollection(new ThangTypeSearchCollection(), 'thangs').model
# just loading all Components for now: https://github.com/codecombat/codecombat/issues/405
@componentCollection = @supermodel.loadCollection(new ComponentsCollection(), 'components').load()
@level = options.level
$(document).bind 'contextmenu', @preventDefaultContextMenu
@ -113,7 +113,7 @@ module.exports = class ThangsTabView extends View
@$el.find('#extant-thangs-filter button:first').button('toggle')
$(window).resize @onWindowResize
@addThangsView = @insertSubView new AddThangsView world: @world, supermodel: @supermodel
@onLevelLoaded() # refactor to not have this trigger when this view re-renders?
@buildInterface() # refactor to not have this trigger when this view re-renders?
onFilterExtantThangs: (e) ->
@$el.find('#extant-thangs-filter button.active').button('toggle')
@ -127,7 +127,7 @@ module.exports = class ThangsTabView extends View
@scrollTop += (if e.deltaY < 0 then 1 else -1) * 30
e.preventDefault()
onLevelLoaded: (e) ->
buildInterface: (e) ->
@level = e.level if e
data = $.extend(true, {}, @level.attributes)

View file

@ -115,7 +115,7 @@ module.exports = class CocoView extends Backbone.View
afterRender: ->
updateProgress: (progress)=>
updateProgress: (progress) ->
@loadProgress.progress = progress if progress > @loadProgress.progress
@updateProgressBar(progress)

View file

@ -6,9 +6,6 @@ module.exports = class LevelLoadingView extends View
id: "level-loading-view"
template: template
subscriptions:
'level-loader:progress-changed': 'onLevelLoaderProgressChanged'
onLoaded: ->
afterRender: ->
@$el.find('.tip.rare').remove() if _.random(1, 10) < 9
@ -17,15 +14,6 @@ module.exports = class LevelLoadingView extends View
$(tip).removeClass('to-remove')
@$el.find('.to-remove').remove()
onLevelLoaderProgressChanged: (e) ->
return if @destroyed
@progress = e.progress
@progress = 0.01 if @progress < 0.01
@updateProgressBar()
updateProgressBar: ->
@$el.find('.progress-bar').css('width', (100 * @progress) + '%')
showReady: ->
ready = $.i18n.t('play_level.loading_ready', defaultValue: 'Ready!')
@$el.find('#tip-wrapper .tip').addClass('ready').text ready
@ -35,7 +23,7 @@ module.exports = class LevelLoadingView extends View
_.delay @reallyUnveil, 1000
reallyUnveil: =>
return if @destroyed or @progress < 1
return if @destroyed
@$el.addClass 'unveiled'
loadingDetails = @$el.find('.loading-details')
duration = parseFloat loadingDetails.css 'transition-duration'

View file

@ -21,7 +21,7 @@ module.exports = class DebugView extends View
@ace = options.ace
@thang = options.thang
@variableStates = {}
@globals = {Math: Math, _: _} # ... add more as documented
@globals = {Math: Math, _: _, String: String, Number: Number, Array: Array, Object: Object} # ... add more as documented
for className, klass of serializedClasses
@globals[className] = klass
@onMouseMove = _.throttle @onMouseMove, 25
@ -33,17 +33,18 @@ module.exports = class DebugView extends View
setVariableStates: (@variableStates) ->
@update()
isIdentifier: (t) ->
t and (t.type is 'identifier' or t.value is 'this' or @globals[t.value])
onMouseMove: (e) =>
return if @destroyed
pos = e.getDocumentPosition()
endOfDoc = pos.row is @ace.getSession().getDocument().getLength() - 1
it = new TokenIterator e.editor.session, pos.row, pos.column
isIdentifier = (t) => t and (t.type is 'identifier' or t.value is 'this' or @globals[t.value])
while it.getCurrentTokenRow() is pos.row and not isIdentifier(token = it.getCurrentToken())
endOfLine = it.getCurrentToken()?.index is it.$rowTokens.length - 1
while it.getCurrentTokenRow() is pos.row and not @isIdentifier(token = it.getCurrentToken())
break if endOfLine or not token # Don't iterate beyond end or beginning of line
it.stepBackward()
break unless token
break if endOfDoc # Don't iterate backward on last line, since we might be way below.
if isIdentifier token
if @isIdentifier token
# This could be a property access, like "enemy.target.pos" or "this.spawnedRectangles".
# We have to realize this and dig into the nesting of the objects.
start = it.getCurrentTokenColumn()
@ -53,7 +54,7 @@ module.exports = class DebugView extends View
break unless it.getCurrentToken()?.value is "."
it.stepBackward()
token = null # If we're doing a complex access like this.getEnemies().length, then length isn't a valid var.
break unless isIdentifier(prev = it.getCurrentToken())
break unless @isIdentifier(prev = it.getCurrentToken())
token = prev
start = it.getCurrentTokenColumn()
chain.unshift token.value

View file

@ -87,10 +87,8 @@ module.exports = class PlayLevelView extends View
@saveScreenshot = _.throttle @saveScreenshot, 30000
if @isEditorPreview
f = =>
@supermodel.shouldSaveBackups = (model) ->
model.constructor.className in ['Level', 'LevelComponent', 'LevelSystem']
@load() unless @levelLoader
# wait to see if it's just given to us through setLevel
f = => @load() unless @levelLoader
setTimeout f, 100
else
@load()
@ -100,7 +98,11 @@ module.exports = class PlayLevelView extends View
# TODO NOW: remove this in favor of the supermodel handling it
application.router.navigate "/play?not_found=#{@levelID}", {trigger: true}
setLevel: (@level, @supermodel) ->
setLevel: (@level, givenSupermodel) ->
@supermodel.models = givenSupermodel.models
@supermodel.collections = givenSupermodel.collections
@supermodel.shouldSaveBackups = givenSupermodel.shouldSaveBackups
@god?.level = @level.serialize @supermodel
if @world
serializedLevel = @level.serialize(@supermodel)
@ -129,7 +131,8 @@ module.exports = class PlayLevelView extends View
@$el.find('#level-done-button').hide()
$('body').addClass('is-playing')
onLevelLoaderProgressChanged: ->
updateProgress: (progress) ->
super(progress)
return if @seenDocs
return unless @levelLoader.session.loaded and @levelLoader.level.loaded
return unless showFrequency = @levelLoader.level.get('showsGuide')

View file

@ -106,7 +106,6 @@ module.exports = class SpectateLevelView extends View
spectateMode: true
team: @getQueryVariable("team")
@listenToOnce(@levelLoader, 'loaded-all', @onLevelLoaderLoaded)
@listenTo(@levelLoader, 'progress', @onLevelLoaderProgressChanged)
@god = new God maxWorkerPoolSize: 1, maxAngels: 1
getRenderData: ->
@ -121,7 +120,8 @@ module.exports = class SpectateLevelView extends View
super()
$('body').addClass('is-playing')
onLevelLoaderProgressChanged: ->
updateProgress: (progress) ->
super(progress)
return if @seenDocs
return unless showFrequency = @levelLoader.level.get('showGuide')
session = @levelLoader.session
@ -141,7 +141,10 @@ module.exports = class SpectateLevelView extends View
Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaderLoaded, @
return true
onLevelLoaderLoaded: ->
onLoaded: ->
_.defer => @onLevelLoaded()
onLevelLoaded: ->
return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early
# Save latest level played in local storage
if window.currentModal and not window.currentModal.destroyed