diff --git a/app/Router.coffee b/app/Router.coffee index 58f93b3b5..b826fcd89 100644 --- a/app/Router.coffee +++ b/app/Router.coffee @@ -31,6 +31,7 @@ module.exports = class CocoRouter extends Backbone.Router 'admin/files': go('admin/FilesView') 'admin/level-sessions': go('admin/LevelSessionsView') 'admin/users': go('admin/UsersView') + 'admin/base': go('admin/BaseView') 'beta': go('HomeView') @@ -47,7 +48,8 @@ module.exports = class CocoRouter extends Backbone.Router 'db/*path': 'routeToServer' 'demo(/*subpath)': go('DemoView') - 'docs/components': go('docs/ComponentDocumentationView') + 'docs/components': go('docs/ComponentsDocumentationView') + 'docs/systems': go('docs/SystemsDocumentationView') 'editor': go('CommunityView') diff --git a/app/application.coffee b/app/application.coffee index da0352bd1..0e0c99104 100644 --- a/app/application.coffee +++ b/app/application.coffee @@ -45,7 +45,7 @@ Application = initialize: -> @linkedinHandler = new LinkedInHandler() preload(COMMON_FILES) $.i18n.init { - lng: me?.lang() ? 'en' + lng: me.get('preferredLanguage', true) fallbackLng: 'en' resStore: locale #debug: true diff --git a/app/assets/images/pages/contribute/archmage/alex_small.png b/app/assets/images/pages/contribute/archmage/alex_small.png deleted file mode 100644 index fd5db1b23..000000000 Binary files a/app/assets/images/pages/contribute/archmage/alex_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/becca_small.png b/app/assets/images/pages/contribute/archmage/becca_small.png deleted file mode 100644 index fa182573a..000000000 Binary files a/app/assets/images/pages/contribute/archmage/becca_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/ben_small.png b/app/assets/images/pages/contribute/archmage/ben_small.png deleted file mode 100644 index bdb8f2e08..000000000 Binary files a/app/assets/images/pages/contribute/archmage/ben_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/brad_small.png b/app/assets/images/pages/contribute/archmage/brad_small.png deleted file mode 100644 index 597491201..000000000 Binary files a/app/assets/images/pages/contribute/archmage/brad_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/chloe_small.png b/app/assets/images/pages/contribute/archmage/chloe_small.png deleted file mode 100644 index 706138e26..000000000 Binary files a/app/assets/images/pages/contribute/archmage/chloe_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/dan_small.png b/app/assets/images/pages/contribute/archmage/dan_small.png deleted file mode 100644 index b2cdd83e6..000000000 Binary files a/app/assets/images/pages/contribute/archmage/dan_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/deepak_small.png b/app/assets/images/pages/contribute/archmage/deepak_small.png deleted file mode 100644 index 8c541a4d9..000000000 Binary files a/app/assets/images/pages/contribute/archmage/deepak_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/glen_small.png b/app/assets/images/pages/contribute/archmage/glen_small.png deleted file mode 100644 index e0b299abd..000000000 Binary files a/app/assets/images/pages/contribute/archmage/glen_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/ken_small.png b/app/assets/images/pages/contribute/archmage/ken_small.png deleted file mode 100644 index df90c7208..000000000 Binary files a/app/assets/images/pages/contribute/archmage/ken_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/laura_small.png b/app/assets/images/pages/contribute/archmage/laura_small.png deleted file mode 100644 index 11b8a54fc..000000000 Binary files a/app/assets/images/pages/contribute/archmage/laura_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/mischa_small.png b/app/assets/images/pages/contribute/archmage/mischa_small.png deleted file mode 100644 index 26cfae9e3..000000000 Binary files a/app/assets/images/pages/contribute/archmage/mischa_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/paul_small.png b/app/assets/images/pages/contribute/archmage/paul_small.png deleted file mode 100644 index 89e71589a..000000000 Binary files a/app/assets/images/pages/contribute/archmage/paul_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/rachel_small.png b/app/assets/images/pages/contribute/archmage/rachel_small.png deleted file mode 100644 index 15cd5c51b..000000000 Binary files a/app/assets/images/pages/contribute/archmage/rachel_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/ronald_small.png b/app/assets/images/pages/contribute/archmage/ronald_small.png deleted file mode 100644 index 8875e2021..000000000 Binary files a/app/assets/images/pages/contribute/archmage/ronald_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/sebastien_small.png b/app/assets/images/pages/contribute/archmage/sebastien_small.png deleted file mode 100644 index 27d3f4189..000000000 Binary files a/app/assets/images/pages/contribute/archmage/sebastien_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/shiying_small.png b/app/assets/images/pages/contribute/archmage/shiying_small.png deleted file mode 100644 index 10d7b270c..000000000 Binary files a/app/assets/images/pages/contribute/archmage/shiying_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/archmage/tom_small.png b/app/assets/images/pages/contribute/archmage/tom_small.png deleted file mode 100644 index 94ad80576..000000000 Binary files a/app/assets/images/pages/contribute/archmage/tom_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/artisan/andrew_small.png b/app/assets/images/pages/contribute/artisan/andrew_small.png deleted file mode 100644 index d3674ded9..000000000 Binary files a/app/assets/images/pages/contribute/artisan/andrew_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/artisan/axandre_small.png b/app/assets/images/pages/contribute/artisan/axandre_small.png deleted file mode 100644 index 6d507c4da..000000000 Binary files a/app/assets/images/pages/contribute/artisan/axandre_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/artisan/derek_small.png b/app/assets/images/pages/contribute/artisan/derek_small.png deleted file mode 100644 index 49ed07efe..000000000 Binary files a/app/assets/images/pages/contribute/artisan/derek_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/artisan/katharine_small.png b/app/assets/images/pages/contribute/artisan/katharine_small.png deleted file mode 100644 index 4bd2a2721..000000000 Binary files a/app/assets/images/pages/contribute/artisan/katharine_small.png and /dev/null differ diff --git a/app/assets/images/pages/contribute/artisan/rob_small.png b/app/assets/images/pages/contribute/artisan/rob_small.png deleted file mode 100644 index e030aa5cf..000000000 Binary files a/app/assets/images/pages/contribute/artisan/rob_small.png and /dev/null differ diff --git a/app/collections/CocoCollection.coffee b/app/collections/CocoCollection.coffee index bb051811c..33b53f111 100644 --- a/app/collections/CocoCollection.coffee +++ b/app/collections/CocoCollection.coffee @@ -4,10 +4,14 @@ module.exports = class CocoCollection extends Backbone.Collection loaded: false model: null - initialize: -> + initialize: (models, options) -> + options ?= {} + @model ?= options.model if not @model console.error @constructor.name, 'does not have a model defined. This will not do!' - super() + super(models, options) + @setProjection options.project + if options.url then @url = options.url @once 'sync', => @loaded = true model.loaded = true for model in @models @@ -15,7 +19,13 @@ module.exports = class CocoCollection extends Backbone.Collection getURL: -> return if _.isString @url then @url else @url() - fetch: -> - @jqxhr = super(arguments...) + fetch: (options) -> + options ?= {} + if @project + options.data ?= {} + options.data.project = @project.join(',') + @jqxhr = super(options) @loading = true @jqxhr + + setProjection: (@project) -> \ No newline at end of file diff --git a/app/initialize.coffee b/app/initialize.coffee index fb744211a..7aced5353 100644 --- a/app/initialize.coffee +++ b/app/initialize.coffee @@ -68,9 +68,9 @@ setUpDefinitions = -> setUpMoment = -> {me} = require 'lib/auth' - moment.lang me.lang(), {} - me.on 'change', (me) -> - moment.lang me.lang(), {} if me._previousAttributes.preferredLanguage isnt me.get 'preferredLanguage' + moment.lang me.get('preferredLanguage', true), {} + me.on 'change:preferredLanguage', (me) -> + moment.lang me.get('preferredLanguage', true), {} initializeServices = -> services = [ diff --git a/app/lib/LevelLoader.coffee b/app/lib/LevelLoader.coffee index 4298460c0..ff7135f2d 100644 --- a/app/lib/LevelLoader.coffee +++ b/app/lib/LevelLoader.coffee @@ -35,7 +35,6 @@ module.exports = class LevelLoader extends CocoClass @worldNecessities = [] @listenTo @supermodel, 'resource-loaded', @onWorldNecessityLoaded - @loadSession() @loadLevel() @loadAudio() @playJingle() @@ -44,14 +43,19 @@ module.exports = class LevelLoader extends CocoClass else @listenToOnce @supermodel, 'loaded-all', @onSupermodelLoaded - playJingle: -> - return if @headless - # Apparently the jingle, when it tries to play immediately during all this loading, you can't hear it. - # Add the timeout to fix this weird behavior. - f = -> - jingles = ['ident_1', 'ident_2'] - AudioPlayer.playInterfaceSound jingles[Math.floor Math.random() * jingles.length] - setTimeout f, 500 + # Supermodel (Level) Loading + + loadLevel: -> + @level = @supermodel.getModel(Level, @levelID) or new Level _id: @levelID + if @level.loaded + @onLevelLoaded() + else + @level = @supermodel.loadModel(@level, 'level').model + @listenToOnce @level, 'sync', @onLevelLoaded + + onLevelLoaded: -> + @loadSession() + @populateLevel() # Session Loading @@ -66,40 +70,36 @@ module.exports = class LevelLoader extends CocoClass session = new LevelSession().setURL url @sessionResource = @supermodel.loadModel(session, 'level_session', {cache: false}) @session = @sessionResource.model - @listenToOnce @session, 'sync', -> - @session.url = -> '/db/level.session/' + @id - @loadDependenciesForSession(@session) + if @session.loaded + @loadDependenciesForSession @session + else + @listenToOnce @session, 'sync', -> + @session.url = -> '/db/level.session/' + @id + @loadDependenciesForSession @session if @opponentSessionID opponentSession = new LevelSession().setURL "/db/level_session/#{@opponentSessionID}" @opponentSessionResource = @supermodel.loadModel(opponentSession, 'opponent_session') @opponentSession = @opponentSessionResource.model - @listenToOnce @opponentSession, 'sync', @loadDependenciesForSession + if @opponentSession.loaded + @loadDependenciesForSession @opponentSession + else + @listenToOnce @opponentSession, 'sync', @loadDependenciesForSession loadDependenciesForSession: (session) -> - return if @levelID is 'sky-span' # TODO - # TODO: I think this runs afoul of https://github.com/codecombat/codecombat/issues/1108 - # TODO: this shouldn't happen when it's not a hero level, but we don't have level loaded yet, - # and the sessions are being created with default hero config regardless of whether it's a hero level. - if heroConfig = session.get('heroConfig') - url = "/db/thang.type/#{heroConfig.thangType}/version?project=name,components,original" + return unless @level.get('type', true) is 'hero' + heroConfig = session.get('heroConfig') + unless heroConfig + heroConfig = {inventory: {}, thangType: '529ffbf1cf1818f2be000001'} # Temp: assign Tharin as the hero + session.set 'heroConfig', heroConfig + url = "/db/thang.type/#{heroConfig.thangType}/version?project=name,components,original" + @worldNecessities.push @maybeLoadURL(url, ThangType, 'thang') + + for itemThangType in _.values(heroConfig.inventory) + url = "/db/thang.type/#{itemThangType}/version?project=name,components,original" @worldNecessities.push @maybeLoadURL(url, ThangType, 'thang') - for itemThangType in _.values(heroConfig.inventory) - url = "/db/thang.type/#{itemThangType}/version?project=name,components,original" - @worldNecessities.push @maybeLoadURL(url, ThangType, 'thang') - # Supermodel (Level) Loading - - loadLevel: -> - @level = @supermodel.getModel(Level, @levelID) or new Level _id: @levelID - if @level.loaded - @populateLevel() - else - @level = @supermodel.loadModel(@level, 'level').model - @listenToOnce @level, 'sync', @onLevelLoaded - - onLevelLoaded: -> - @populateLevel() + # Grabbing the rest of the required data for the level populateLevel: -> thangIDs = [] @@ -110,7 +110,7 @@ module.exports = class LevelLoader extends CocoClass flagThang = thangType: '53fa25f25bc220000052c2be', id: 'Placeholder Flag', components: [] for thang in (@level.get('thangs') or []).concat [flagThang] thangIDs.push thang.thangType - @loadItemThangsEquippedByLevelThang(thang) + @loadThangsRequiredByLevelThang(thang) for comp in thang.components or [] componentVersions.push _.pick(comp, ['original', 'majorVersion']) @@ -154,22 +154,28 @@ module.exports = class LevelLoader extends CocoClass @worldNecessities = @worldNecessities.concat worldNecessities - loadItemThangsEquippedByLevelThang: (levelThang) -> - return unless levelThang.components - for component in levelThang.components - if component.original is LevelComponent.EquipsID and inventory = component.config?.inventory - for itemThangType in _.values(inventory) - unless itemThangType - console.warn "Empty item in inventory for", levelThang - continue - url = "/db/thang.type/#{itemThangType}/version?project=name,components,original" - @worldNecessities.push @maybeLoadURL(url, ThangType, 'thang') + loadThangsRequiredByLevelThang: (levelThang) -> + @loadThangsRequiredFromComponentList levelThang.components + + loadThangsRequiredByThangType: (thangType) -> + @loadThangsRequiredFromComponentList thangType.get('components') + + loadThangsRequiredFromComponentList: (components) -> + return unless components + requiredThangTypes = [] + for component in components when component.config + if component.original is LevelComponent.EquipsID + requiredThangTypes.push itemThangType for itemThangType in _.values (component.config.inventory ? {}) + else if component.config.requiredThangTypes + requiredThangTypes = requiredThangTypes.concat component.config.requiredThangTypes + for thangType in requiredThangTypes + url = "/db/thang.type/#{thangType}/version?project=name,components,original" + @worldNecessities.push @maybeLoadURL(url, ThangType, 'thang') onThangNamesLoaded: (thangNames) -> - if @level.get('type') is 'hero' - for thangType in thangNames.models - @loadDefaultComponentsForThangType(thangType) - @loadEquippedItemsInheritedFromThangType(thangType) + for thangType in thangNames.models + @loadDefaultComponentsForThangType(thangType) + @loadThangsRequiredByThangType(thangType) loadDefaultComponentsForThangType: (thangType) -> return unless components = thangType.get('components') @@ -177,23 +183,11 @@ module.exports = class LevelLoader extends CocoClass url = "/db/level.component/#{component.original}/version/#{component.majorVersion}" @worldNecessities.push @maybeLoadURL(url, LevelComponent, 'component') - loadEquippedItemsInheritedFromThangType: (thangType) -> - for levelThang in @level.get('thangs') or [] - if levelThang.thangType is thangType.get('original') - levelThang = $.extend true, {}, levelThang - @level.denormalizeThang(levelThang, @supermodel) - equipsComponent = _.find levelThang.components, {original: LevelComponent.EquipsID} - inventory = equipsComponent?.config?.inventory - continue unless inventory - for itemThangType in _.values inventory - url = "/db/thang.type/#{itemThangType}/version?project=name,components,original" - @worldNecessities.push @maybeLoadURL(url, ThangType, 'thang') - onWorldNecessityLoaded: (resource) -> index = @worldNecessities.indexOf(resource) - if (@level?.loading or (@level?.get('type') is 'hero')) and resource.name is 'thang' + if resource.name is 'thang' @loadDefaultComponentsForThangType(resource.model) - @loadEquippedItemsInheritedFromThangType(resource.model) + @loadThangsRequiredByThangType(resource.model) return unless index >= 0 @worldNecessities.splice(index, 1) @@ -254,6 +248,7 @@ module.exports = class LevelLoader extends CocoClass resource = null for resource in @spriteSheetsToBuild break if e.thangType is resource.thangType + return console.error 'Did not find spriteSheetToBuildResource for', e unless resource resource.spriteSheetKeys = (k for k in resource.spriteSheetKeys when k isnt e.key) resource.markLoaded() if resource.spriteSheetKeys.length is 0 @@ -331,6 +326,15 @@ module.exports = class LevelLoader extends CocoClass # Initial Sound Loading + playJingle: -> + return if @headless + # Apparently the jingle, when it tries to play immediately during all this loading, you can't hear it. + # Add the timeout to fix this weird behavior. + f = -> + jingles = ['ident_1', 'ident_2'] + AudioPlayer.playInterfaceSound jingles[Math.floor Math.random() * jingles.length] + setTimeout f, 500 + loadAudio: -> return if @headless AudioPlayer.preloadInterfaceSounds ['victory'] diff --git a/app/lib/aether_utils.coffee b/app/lib/aether_utils.coffee new file mode 100644 index 000000000..de07fdb57 --- /dev/null +++ b/app/lib/aether_utils.coffee @@ -0,0 +1,48 @@ +Aether.addGlobal 'Vector', require 'lib/world/vector' +Aether.addGlobal '_', _ + +module.exports.createAetherOptions = (options) -> + throw new Error 'Specify a function name to create an Aether instance' unless options.functionName + throw new Error 'Specify a code language to create an Aether instance' unless options.codeLanguage + + aetherOptions = + functionName: options.functionName + protectAPI: not options.skipProtectAPI + includeFlow: false + yieldConditionally: options.functionName is 'plan' + globals: ['Vector', '_'] + problems: + jshint_W040: {level: 'ignore'} + jshint_W030: {level: 'ignore'} # aether_NoEffect instead + jshint_W038: {level: 'ignore'} # eliminates hoisting problems + jshint_W091: {level: 'ignore'} # eliminates more hoisting problems + jshint_E043: {level: 'ignore'} # https://github.com/codecombat/codecombat/issues/813 -- since we can't actually tell JSHint to really ignore things + jshint_Unknown: {level: 'ignore'} # E043 also triggers Unknown, so ignore that, too + aether_MissingThis: {level: 'error'} + #functionParameters: # TODOOOOO + executionLimit: 1 * 1000 * 1000 + language: options.codeLanguage + parameters = functionParameters[options.functionName] + unless parameters + console.warn "Unknown method #{options.functionName}: please add function parameters to lib/aether_utils.coffee." + parameters = [] + if options.functionParameters and not _.isEqual options.functionParameters, parameters + console.error "Update lib/aether_utils.coffee with the right function parameters for #{options.functionName} (had: #{parameters} but this gave #{options.functionParameters}." + parameters = options.functionParameters + aetherOptions.functionParameters = parameters.slice() + #console.log 'creating aether with options', aetherOptions + return aetherOptions + +# TODO: figure out some way of saving this info dynamically so that we don't have to hard-code it: #1329 +functionParameters = + hear: ['speaker', 'message', 'data'] + makeBid: ['tileGroupLetter'] + findCentroids: ['centroids'] + isFriend: ['name'] + evaluateBoard: ['board', 'player'] + getPossibleMoves: ['board'] + minimax_alphaBeta: ['board', 'player', 'depth', 'alpha', 'beta'] + + chooseAction: [] + plan: [] + initializeCentroids: [] diff --git a/app/lib/deltas.coffee b/app/lib/deltas.coffee index 55743f345..00d941a1e 100644 --- a/app/lib/deltas.coffee +++ b/app/lib/deltas.coffee @@ -89,7 +89,7 @@ expandFlattenedDelta = (delta, left, schema) -> delta module.exports.makeJSONDiffer = -> - hasher = (obj) -> obj.name || obj.id || obj._id || JSON.stringify(_.keys(obj)) + hasher = (obj) -> if obj? then obj.name or obj.id or obj._id or JSON.stringify(_.keys(obj)) else 'null' jsondiffpatch.create({objectHash: hasher}) module.exports.getConflicts = (headDeltas, pendingDeltas) -> @@ -175,5 +175,3 @@ prunePath = (delta, path) -> prunePath delta[path[0]], path.slice(1) unless delta[path[0]] is undefined keys = (k for k in _.keys(delta[path[0]]) when k isnt '_t') delete delta[path[0]] if keys.length is 0 - - diff --git a/app/lib/forms.coffee b/app/lib/forms.coffee index 86fe1530d..f319be0f2 100644 --- a/app/lib/forms.coffee +++ b/app/lib/forms.coffee @@ -31,7 +31,7 @@ module.exports.applyErrorsToForm = (el, errors, warning=false) -> module.exports.setErrorToField = setErrorToField = (el, message, warning=false) -> formGroup = el.closest('.form-group') unless formGroup.length - return console.error "#{el} did not contain a form group" + return console.error el, " did not contain a form group, so couldn't show message:", message kind = if warning then 'warning' else 'error' formGroup.addClass "has-#{kind}" @@ -40,7 +40,7 @@ module.exports.setErrorToField = setErrorToField = (el, message, warning=false) module.exports.setErrorToProperty = setErrorToProperty = (el, property, message, warning=false) -> input = $("[name='#{property}']", el) unless input.length - return console.error "#{property} not found in #{el}" + return console.error "#{property} not found in", el, "so couldn't show message:", message setErrorToField input, message, warning diff --git a/app/lib/simulator/Simulator.coffee b/app/lib/simulator/Simulator.coffee index 0e5a6631e..01cff2057 100644 --- a/app/lib/simulator/Simulator.coffee +++ b/app/lib/simulator/Simulator.coffee @@ -3,9 +3,7 @@ CocoClass = require 'lib/CocoClass' LevelLoader = require 'lib/LevelLoader' GoalManager = require 'lib/world/GoalManager' God = require 'lib/God' - -Aether.addGlobal 'Vector', require 'lib/world/vector' -Aether.addGlobal '_', _ +{createAetherOptions} = require 'lib/aether_utils' module.exports = class Simulator extends CocoClass constructor: (@options) -> @@ -400,23 +398,7 @@ module.exports = class Simulator extends CocoClass aether.transpile '' createAether: (methodName, method, useProtectAPI, codeLanguage) -> - aetherOptions = - functionName: methodName - protectAPI: useProtectAPI - includeFlow: false - yieldConditionally: methodName is 'plan' - globals: ['Vector', '_'] - problems: - jshint_W040: {level: 'ignore'} - jshint_W030: {level: 'ignore'} # aether_NoEffect instead - aether_MissingThis: {level: 'error'} - #functionParameters: # TODOOOOO - executionLimit: 1 * 1000 * 1000 - language: codeLanguage - if methodName is 'hear' then aetherOptions.functionParameters = ['speaker', 'message', 'data'] - if methodName is 'makeBid' then aetherOptions.functionParameters = ['tileGroupLetter'] - if methodName is 'findCentroids' then aetherOptions.functionParameters = ['centroids'] - #console.log 'creating aether with options', aetherOptions + aetherOptions = createAetherOptions functionName: methodName, codeLanguage: codeLanguage, skipProtectAPI: not useProtectAPI return new Aether aetherOptions class SimulationTask diff --git a/app/lib/surface/CocoSprite.coffee b/app/lib/surface/CocoSprite.coffee index 23e16cec8..d0a192515 100644 --- a/app/lib/surface/CocoSprite.coffee +++ b/app/lib/surface/CocoSprite.coffee @@ -80,13 +80,14 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass @age = 0 @stillLoading = true if @thangType.isFullyLoaded() - @setupSprite() + @setUpSprite() else @thangType.setProjection null @thangType.fetch() unless @thangType.loading - @listenToOnce(@thangType, 'sync', @setupSprite) + @listenToOnce(@thangType, 'sync', @setUpSprite) + @setUpPlaceholder() - setupSprite: -> + setUpSprite: -> for trigger, sounds of @thangType.get('soundTriggers') or {} when trigger isnt 'say' AudioPlayer.preloadSoundReference sound for sound in sounds if @thangType.get('raster') @@ -97,7 +98,8 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass else result = @buildSpriteSheet() if _.isString result # async build - @listenToOnce @thangType, 'build-complete', @setupSprite + @listenToOnce @thangType, 'build-complete', @setUpSprite + @setUpPlaceholder() else @stillLoading = false @actions = @thangType.getActions() @@ -106,6 +108,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass @queueAction 'idle' finishSetup: -> + @placeholder = null @updateBaseScale() @scaleFactorX = @thang.scaleFactorX if @thang?.scaleFactorX? @scaleFactorX = @thang.scaleFactor if @thang?.scaleFactor? @@ -127,6 +130,29 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass @imageObject.regY = -reg.y @finishSetup() + setUpPlaceholder: -> + return if @placeholder or not @thang + shape = new createjs.Shape() + width = @thang.width * Camera.PPM + height = @thang.height * Camera.PPM * @options.camera.y2x + depth = @thang.depth * Camera.PPM * @options.camera.z2y * @options.camera.y2x + brightnessFuzzFactor = 1 + 0.1 * (Math.random() - 0.5) + makeColor = (brightnessFactor) => (Math.round(c * brightnessFuzzFactor * brightnessFactor) for c in (healthColors[@thang.team] ? [180, 180, 180])) + topColor = "rgba(#{makeColor(0.85).join(', ')},1)" + mainColor = "rgba(#{makeColor(0.75).join(', ')},1)" + ellipse = @thang.shape in ['ellipsoid', 'disc'] + fn = if ellipse then 'drawEllipse' else 'drawRect' + shape.graphics.beginFill(mainColor)[fn](-width / 2, -height / 2, width, height).endFill() + if ellipse + shape.graphics.moveTo(-width / 2, 0).beginFill(mainColor).lineTo(-width / 2, -depth).lineTo(width / 2, -depth).lineTo(width / 2, 0).lineTo(-width / 2, 0).endFill() + else + shape.graphics.moveTo(-width / 2, 0).beginFill(mainColor).lineTo(-width / 2, -depth).lineTo(width / 2, -depth).lineTo(width / 2, 0).lineTo(-width / 2, 0).endFill() + shape.graphics.beginFill(topColor)[fn](-width / 2, -height / 2 - depth, width, height).endFill() + shape.layerPriority = @thang?.layerPriority ? @thangType.get 'layerPriority' + @setImageObject shape + @updatePosition true + @placeholder = shape + toString: -> "" buildSpriteSheet: -> @@ -311,15 +337,15 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass p1.z += bobOffset x: p1.x, y: p1.y, z: if @thang.isLand then 0 else p1.z - @thang.depth / 2 - updatePosition: (log) -> - return if @stillLoading + updatePosition: (whileLoading=false) -> + return if @stillLoading and not whileLoading return unless @thang?.pos and @options.camera? wop = @getWorldPosition() [p0, p1] = [@lastPos, @thang.pos] return if p0 and p0.x is p1.x and p0.y is p1.y and p0.z is p1.z and not @options.camera.tweeningZoomTo and not @thang.bobHeight sup = @options.camera.worldToSurface wop [@imageObject.x, @imageObject.y] = [sup.x, sup.y] - @lastPos = p1.copy?() or _.clone(p1) + @lastPos = p1.copy?() or _.clone(p1) unless whileLoading @hasMoved = true if @thangType.get('name') is 'Flag' and not @notOfThisWorld # Let the pending flags know we're here (but not this call stack, they need to delete themselves, and we may be iterating sprites). diff --git a/app/lib/surface/Surface.coffee b/app/lib/surface/Surface.coffee index 315a1a1d2..a3762e125 100644 --- a/app/lib/surface/Surface.coffee +++ b/app/lib/surface/Surface.coffee @@ -428,15 +428,18 @@ module.exports = Surface = class Surface extends CocoClass pageHeight = $('#page-container').height() - $('#control-bar-view').outerHeight() - $('#playback-view').outerHeight() newWidth = Math.min pageWidth, pageHeight * aspectRatio newHeight = newWidth / aspectRatio + else if $('#editor-level-thangs-tab-view') + newWidth = $('#canvas-wrapper').width() + newHeight = newWidth / aspectRatio else newWidth = 0.55 * pageWidth newHeight = newWidth / aspectRatio - @canvas.width newWidth - @canvas.height newHeight return unless newWidth > 0 and newHeight > 0 - #if InstallTrigger? # Firefox rendering performance goes down as canvas size goes up - # newWidth = Math.min 924, newWidth - # newHeight = Math.min 589, newHeight + ##if InstallTrigger? # Firefox rendering performance goes down as canvas size goes up + ## newWidth = Math.min 924, newWidth + ## newHeight = Math.min 589, newHeight + #@canvas.width newWidth + #@canvas.height newHeight @canvas.attr width: newWidth, height: newHeight @stage.scaleX *= newWidth / oldWidth @stage.scaleY *= newHeight / oldHeight @@ -578,6 +581,7 @@ module.exports = Surface = class Surface extends CocoClass @playing = false # Will start when countdown is done. onRealTimePlaybackEnded: (e) -> + return unless @realTime @realTime = false @onResize() @spriteBoss.selfWizardSprite?.toggle true diff --git a/app/lib/surface/WizardSprite.coffee b/app/lib/surface/WizardSprite.coffee index c577dae28..21b3b453c 100644 --- a/app/lib/surface/WizardSprite.coffee +++ b/app/lib/surface/WizardSprite.coffee @@ -82,7 +82,7 @@ module.exports = class WizardSprite extends IndieSprite shouldUpdate = not _.isEqual(newColorConfig, @options.colorConfig) @options.colorConfig = $.extend(true, {}, newColorConfig) if shouldUpdate - @setupSprite() + @setUpSprite() @playAction(@currentAction) if @currentAction onSpriteSelected: (e) -> @@ -199,14 +199,15 @@ module.exports = class WizardSprite extends IndieSprite wizard.beginMoveTween() endMoveTween: => + return if @destroyed @thang.action = if @editing then 'cast' else 'idle' @thang.actionActivated = @thang.action is 'cast' @reachedTarget = true @faceTarget() @update true - updatePosition: -> - return unless @options.camera + updatePosition: (whileLoading=false) -> + return if whileLoading or not @options.camera @thang.pos = @getCurrentPosition() @faceTarget() sup = @options.camera.worldToSurface x: @thang.pos.x, y: @thang.pos.y, z: @thang.pos.z - @thang.depth / 2 diff --git a/app/lib/surface/path.coffee b/app/lib/surface/path.coffee index 05654f906..be17ae42f 100644 --- a/app/lib/surface/path.coffee +++ b/app/lib/surface/path.coffee @@ -143,7 +143,7 @@ module.exports.Trailmaster = class Trailmaster i = 0 sprites = [] sprite = @sprites[thang.id] - return sprites unless sprite? + return sprites unless sprite?.actions lastPos = @camera.surfaceToWorld x: sprite.imageObject.x, y: sprite.imageObject.y minDistance = Math.pow(CLONE_INTERVAL * Camera.MPP, 2) actions = @world.actionsForThang(thang.id) diff --git a/app/lib/utils.coffee b/app/lib/utils.coffee index 17167422d..5a4e78594 100644 --- a/app/lib/utils.coffee +++ b/app/lib/utils.coffee @@ -46,7 +46,7 @@ toHex = (n) -> h = '0'+h if h.length is 1 h -module.exports.i18n = (say, target, language=me.lang(), fallback='en') -> +module.exports.i18n = (say, target, language=me.get('preferredLanguage', true), fallback='en') -> generalResult = null fallbackResult = null fallforwardResult = null # If a general language isn't available, the first specific one will do diff --git a/app/lib/world/world.coffee b/app/lib/world/world.coffee index 629a25f63..299296b3d 100644 --- a/app/lib/world/world.coffee +++ b/app/lib/world/world.coffee @@ -217,7 +217,7 @@ module.exports = class World @thangMap = {} # Load new Thangs - toAdd = (@loadThangFromLevel thangConfig, level.levelComponents, level.thangTypes for thangConfig in level.thangs) + toAdd = (@loadThangFromLevel thangConfig, level.levelComponents, level.thangTypes for thangConfig in level.thangs ? []) @extraneousThangs = consolidateThangs toAdd if willSimulate # Combine walls, for example; serialize the leftovers later @addThang thang for thang in toAdd null diff --git a/app/locale/ar.coffee b/app/locale/ar.coffee index 010730af7..f4539e605 100644 --- a/app/locale/ar.coffee +++ b/app/locale/ar.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/bg.coffee b/app/locale/bg.coffee index 280e57c66..ab12284b9 100644 --- a/app/locale/bg.coffee +++ b/app/locale/bg.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "български език", englishDescri # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "български език", englishDescri # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "български език", englishDescri # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/ca.coffee b/app/locale/ca.coffee index 98d0982ac..6a30f72a8 100644 --- a/app/locale/ca.coffee +++ b/app/locale/ca.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr campaign_multiplayer_description: "... on programes cara a cara contra altres jugadors." campaign_player_created: "Creats pel Jugador" campaign_player_created_description: "... on lluites contra la creativitat dels teus companys Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Dificultat: " play_as: "Jugar com" spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/cs.coffee b/app/locale/cs.coffee index 9dcb046f6..efd3ee7ae 100644 --- a/app/locale/cs.coffee +++ b/app/locale/cs.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr campaign_multiplayer_description: "...ve které programujete proti jiným hráčům." campaign_player_created: "Uživatelsky vytvořené úrovně" campaign_player_created_description: "...ve kterých bojujete proti kreativitě ostatních Zdatných Kouzelníků." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Obtížnost: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/da.coffee b/app/locale/da.coffee index 63f1b56b5..69640ab50 100644 --- a/app/locale/da.coffee +++ b/app/locale/da.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans campaign_multiplayer_description: "... hvor du koder ansigt-til-ansigt imod andre spillere." campaign_player_created: "Spillerkreerede" campaign_player_created_description: "... hvor du kæmper mod dine med-Kunsthåndværker-troldmænds kreativitet." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Sværhedsgrad: " play_as: "Spil Som " spectate: "Observér" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/de-AT.coffee b/app/locale/de-AT.coffee index c9365f521..7d934f8a8 100644 --- a/app/locale/de-AT.coffee +++ b/app/locale/de-AT.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Deutsch (Österreich)", englishDescription: campaign_multiplayer_description: "... in der Du Kopf-an-Kopf gegen andere Spieler programmierst." campaign_player_created: "Von Spielern erstellt" campaign_player_created_description: "... in welchem Du gegen die Kreativität eines Artisan Zauberers kämpfst." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Schwierigkeit: " play_as: "Spiele als " spectate: "Zuschauen" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Deutsch (Österreich)", englishDescription: options: general_options: "Allgemeine Einstellungen" +# volume_label: "Volume" music_label: "Musik" music_description: "Schalte Hintergrundmusik an/aus." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Deutsch (Österreich)", englishDescription: # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" delta: added: "hinzugefügt" diff --git a/app/locale/de-CH.coffee b/app/locale/de-CH.coffee index a0ac35ce7..1544bf85a 100644 --- a/app/locale/de-CH.coffee +++ b/app/locale/de-CH.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge campaign_multiplayer_description: "... i dene du Chopf a Chopf geg anderi Spieler spielsch." campaign_player_created: "Vo Spieler erstellti Level" campaign_player_created_description: "... i dene du gege d Kreativität vome Handwerker Zauberer kämpfsch." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Schwierigkeit: " play_as: "Spiel als" spectate: "Zueluege" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/de-DE.coffee b/app/locale/de-DE.coffee index 1c2f3e64d..5046d545e 100644 --- a/app/locale/de-DE.coffee +++ b/app/locale/de-DE.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription: campaign_multiplayer_description: "... in der Du Kopf-an-Kopf gegen andere Spieler programmierst." campaign_player_created: "Von Spielern erstellt" campaign_player_created_description: "... in welchem Du gegen die Kreativität eines Artisan Zauberers kämpfst." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Schwierigkeit: " play_as: "Spiele als " spectate: "Zuschauen" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription: options: general_options: "Allgemeine Einstellungen" +# volume_label: "Volume" music_label: "Musik" music_description: "Schalte Hintergrundmusik an/aus." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription: # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" delta: added: "hinzugefügt" diff --git a/app/locale/de.coffee b/app/locale/de.coffee deleted file mode 100644 index ae66eb7df..000000000 --- a/app/locale/de.coffee +++ /dev/null @@ -1,998 +0,0 @@ -module.exports = nativeDescription: "Deutsch", englishDescription: "German", translation: - common: - loading: "Lade..." - saving: "Speichere..." - sending: "Übertrage..." - send: "Senden" - cancel: "Abbrechen" - save: "Speichern" - publish: "Publiziere" - create: "Erstelle" - delay_1_sec: "1 Sekunde" - delay_3_sec: "3 Sekunden" - delay_5_sec: "5 Sekunden" - manual: "Manuell" - fork: "Fork" - play: "Abspielen" - retry: "Erneut versuchen" -# watch: "Watch" -# unwatch: "Unwatch" -# submit_patch: "Submit Patch" - - units: - second: "Sekunde" - seconds: "Sekunden" - minute: "Minute" - minutes: "Minuten" - hour: "Stunde" - hours: "Stunden" - day: "Tag" - days: "Tage" - week: "Woche" - weeks: "Wochen" - month: "Monat" - months: "Monate" - year: "Jahr" - years: "Jahre" - - modal: - close: "Schließen" - okay: "Okay" - - not_found: - page_not_found: "Seite nicht gefunden" - - nav: - play: "Spielen" -# community: "Community" - editor: "Editor" - blog: "Blog" - forum: "Forum" -# account: "Account" -# profile: "Profile" -# stats: "Stats" -# code: "Code" - admin: "Administration" - home: "Home" - contribute: "Helfen" - legal: "Rechtliches" - about: "Über" - contact: "Kontakt" - twitter_follow: "Twitter" - employers: "Mitarbeiter" - - versions: - save_version_title: "Neue Version speichern" - new_major_version: "Neue Hauptversion" - cla_prefix: "Damit Änderungen gespeichert werden können, musst du unsere Lizenzbedingungen (" - cla_url: "CLA" - cla_suffix: ") akzeptieren." - cla_agree: "Ich stimme zu" - - login: - sign_up: "Registrieren" - log_in: "Einloggen" - logging_in: "Logge ein" - log_out: "Ausloggen" - recover: "Account wiederherstellen" - - recover: - recover_account_title: "Account Wiederherstellung" - send_password: "Wiederherstellungskennwort senden" - - signup: - create_account_title: "Account anlegen, um Fortschritt zu speichern" - description: "Es ist kostenlos. Nur noch ein paar Dinge, dann kannst Du loslegen." - email_announcements: "Erhalte Benachrichtigungen per Email" - coppa: "Älter als 13 oder nicht aus den USA" - coppa_why: "(Warum?)" - creating: "Erzeuge Account..." - sign_up: "Neuen Account anlegen" - log_in: "mit Passwort einloggen" - social_signup: "oder, du registriest dich über Facebook oder G+:" -# required: "You need to log in before you can go that way." - - home: - slogan: "Lerne spielend Programmieren" - no_ie: "CodeCombat läuft nicht im IE8 oder älteren Browsern. Tut uns Leid!" - no_mobile: "CodeCombat ist nicht für Mobilgeräte optimiert und funktioniert möglicherweise nicht." - play: "Spielen" - old_browser: "Oh! Dein Browser ist zu alt für CodeCombat. Sorry!" - old_browser_suffix: "Du kannst es trotzdem versuchen, aber es wird wahrscheinlich nicht funktionieren." - campaign: "Kampagne" - for_beginners: "Für Anfänger" - multiplayer: "Mehrspieler" - for_developers: "Für Entwickler" - javascript_blurb: "Die Sprache des Web. Geeignet für die Erstellung von Webseiten, WebApps, HTML5 Spielen und Servern.." -# python_blurb: "Simple yet powerful, Python is a great general purpose programming language." - coffeescript_blurb: "Schönere JavaScript Syntax." - clojure_blurb: "Ein modernes Lisp." - lua_blurb: "Skriptsprache für Spiele." -# io_blurb: "Simple but obscure." - - play: - choose_your_level: "Wähle dein Level" - adventurer_prefix: "Du kannst zu jedem Level springen oder diskutiere die Level " - adventurer_forum: "im Abenteurerforum" - adventurer_suffix: "." - campaign_beginner: "Anfängerkampagne" - campaign_beginner_description: "... in der Du die Zauberei der Programmierung lernst." - campaign_dev: "Beliebiges schwierigeres Level" - campaign_dev_description: "... in welchem Du die Bedienung erlernst, indem Du etwas schwierigeres machst." - campaign_multiplayer: "Multiplayerarena" - campaign_multiplayer_description: "... in der Du Kopf-an-Kopf gegen andere Spieler programmierst." - campaign_player_created: "Von Spielern erstellt" - campaign_player_created_description: "... in welchem Du gegen die Kreativität eines Artisan Zauberers kämpfst." - level_difficulty: "Schwierigkeit: " - play_as: "Spiele als " - spectate: "Zuschauen" -# players: "players" -# hours_played: "hours played" - - contact: - contact_us: "Kontaktiere CodeCombat" - welcome: "Schön von Dir zu hören! Benutze dieses Formular um uns eine Email zu schicken." - contribute_prefix: "Wenn Du Interesse hast, uns zu unterstützen dann sieh dir die " - contribute_page: "Unterstützer Seite" - contribute_suffix: " an!" - forum_prefix: "Für alle öffentlichen Themen, benutze stattdessen " - forum_page: "unser Forum" - forum_suffix: "." - send: "Sende Feedback" - contact_candidate: "Kontaktiere Kandidaten" - recruitment_reminder: "Benutzen Sie dieses Formular um Kontakt zu Kandidaten aufzunehmen, an denen Sie interessiert sind. Bedenken Sie das CodeCombat 15% des ersten Jahresgehaltes berechnet. Diese Gebühr wird fällig wenn Sie den Kandidaten einstellen und ist für 90 Tage rückerstattungsfähig, sollte der Mitarbeiter nicht eingestellt bleiben. Mitarbeiter die für Teilzeit, Remote oder eine Auftragsarbeit eingestellt werden sind kostenlos, das gilt auch für Praktikanten." - - diplomat_suggestion: - title: "Hilf CodeCombat zu übersetzen!" - sub_heading: "Wir brauchen Deine Sprachfähigkeiten." - pitch_body: "Wir entwickeln CodeCombat in Englisch, aber wir haben Spieler in der ganzen Welt. Viele von ihnen wollen in Deutsch spielen, sprechen aber kein Englisch. Wenn Du also beide Sprachen beherrscht, melde Dich an um ein Diplomat zu werden und hilf die Website und die Levels zu Deutsch zu übersetzen." - missing_translations: "Solange wir nicht alles ins Deutsche übesetzt haben, siehst Du die englische Übersetzung, wo Deutsch leider noch nicht zur Verfügung steht." - learn_more: "Finde heraus, wie Du ein Diplomat werden kannst" - subscribe_as_diplomat: "Schreibe dich als Diplomat ein" - - wizard_settings: - title: "Zauberer Einstellungen" - customize_avatar: "Individualisiere deinen Avatar" - active: "Aktiv" - color: "Farbe" - group: "Gruppe" - clothes: "Kleidung" - trim: "Applikationen" - cloud: "Wolke" - team: "Team" - spell: "Zauber" - boots: "Stiefel" - hue: "Farbton" - saturation: "Sättigung" - lightness: "Helligkeit" - - account_settings: - title: "Accounteinstellungen" - not_logged_in: "Logge Dich ein oder lege einen Account an, um deine Einstellungen ändern zu können." - autosave: "Sichere Änderungen automatisch" - me_tab: "Ich" - picture_tab: "Bild" - upload_picture: "Ein Bild hochladen" - wizard_tab: "Zauberer" - password_tab: "Passwort" - emails_tab: "Emails" - admin: "Admin" - wizard_color: "Die Farbe der Kleidung des Zauberers" - new_password: "Neues Passwort" - new_password_verify: "Passwort verifizieren" - email_subscriptions: "Email Abonnements" - email_subscriptions_none: "Keine Email Abonnements." - email_announcements: "Ankündigungen" - email_announcements_description: "Erhalte regelmäßig Ankündigungen zu deinem Account." - email_notifications: "Benachrichtigungen" -# email_notifications_summary: "Controls for personalized, automatic email notifications related to your CodeCombat activity." -# email_any_notes: "Any Notifications" -# email_any_notes_description: "Disable to stop all activity notification emails." -# email_news: "News" - email_recruit_notes: "Job-Angebote" -# email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job." - contributor_emails: "Unterstützer Email" - contribute_prefix: "Wir suchen nach Leuten, die mitmachen! Schau dir die" - contribute_page: "Unterstützer Seite" - contribute_suffix: " an um mehr zu erfahren." - email_toggle: "Alles wählen" - error_saving: "Fehler beim Speichern" - saved: "Änderungen gespeichert" - password_mismatch: "Passwörter stimmen nicht überein." - password_repeat: "Bitte wiederhole dein Passwort." - job_profile: "Jobprofil" - job_profile_approved: "Dein Jobprofil wurde von CodeCombat freigegeben. Arbeitgeber können dieses solange einsehen, bis du es als inaktiv markiert oder wenn innerhalb von vier Wochen keine Änderung daran vorgenommen wurde." - job_profile_explanation: "Hi! Fülle dies aus und wir melden uns bei dir bezüglich des Auffindens eines Jobs als Programmierer" - sample_profile: "Ein Beispielprofil ansehen" - view_profile: "Dein Profil ansehen" - - account_profile: - settings: "Einstellungen" - edit_profile: "Profil editieren" -# done_editing: "Done Editing" - profile_for_prefix: "Profil von " - profile_for_suffix: "" -# featured: "Featured" -# not_featured: "Not Featured" - looking_for: "Suche nach:" - last_updated: "zuletzt geändert:" - contact: "Kontakt" -# active: "Looking for interview offers now" -# inactive: "Not looking for offers right now" -# complete: "complete" -# next: "Next" - next_city: "Stadt?" - next_country: "Wähle dein Land." - next_name: "Name?" - next_short_description: "Schreibe eine kurze Beschreibung." - next_long_description: "Beschreibe deine gewünschte Position" - next_skills: "Liste mindestens fünf Fähigkeiten." -# next_work: "chronicle your work history." -# next_education: "recount your educational ordeals." - next_projects: "Zeige bis zu 3 Projekte an denen du gearbeitet hast." -# next_links: "add any personal or social links." - next_photo: "Füge ein optionales professionelles Foto hinzu." -# next_active: "mark yourself open to offers to show up in searches." - example_blog: "Blog" - example_personal_site: "Persönliche Seite" - links_header: "Persönliche Links" - links_blurb: "Verlinke zu anderen Seiten oder Profilen die du hervorheben möchtest, wie z.B. dein GitHub, dein LinkedIn oder deinen Blog." - links_name: "Link-Name" -# links_name_help: "What are you linking to?" - links_link_blurb: "Link URL" -# basics_header: "Update basic info" -# basics_active: "Open to Offers" -# basics_active_help: "Want interview offers right now?" -# basics_job_title: "Desired Job Title" -# basics_job_title_help: "What role are you looking for?" - basics_city: "Stadt" - basics_city_help: "Stadt in der du arbeiten möchtest (oder jetzt lebst)." - basics_country: "Land" - basics_country_help: "Land in dem du arbeiten möchtest (oder jetzt lebst)." -# basics_visa: "US Work Status" -# basics_visa_help: "Are you authorized to work in the US, or do you need visa sponsorship? (If you live in Canada or Australia, mark authorized.)" -# basics_looking_for: "Looking For" - basics_looking_for_full_time: "Vollzeit" - basics_looking_for_part_time: "Teilzeit" - basics_looking_for_remote: "Remote" -# basics_looking_for_contracting: "Contracting" - basics_looking_for_internship: "Praktikum" -# basics_looking_for_help: "What kind of developer position do you want?" - name_header: "Trage deinen Namen ein" - name_anonymous: "Anonymer Entwickler" -# name_help: "Name you want employers to see, like 'Nick Winter'." -# short_description_header: "Write a short description of yourself" -# short_description_blurb: "Add a tagline to help an employer quickly learn more about you." -# short_description: "Tagline" -# short_description_help: "Who are you, and what are you looking for? 140 characters max." - skills_header: "Fähigkeiten" -# skills_help: "Tag relevant developer skills in order of proficiency." - long_description_header: "Beschreibe deine gewünschte Position" -# long_description_blurb: "Tell employers how awesome you are and what role you want." -# long_description: "Self Description" -# long_description_help: "Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max." - work_experience: "Berufserfahrung" -# work_header: "Chronicle your work history" -# work_years: "Years of Experience" -# work_years_help: "How many years of professional experience (getting paid) developing software do you have?" -# work_blurb: "List your relevant work experience, most recent first." - work_employer: "Arbeitgeber" - work_employer_help: "Name deines Arbeitgebers." -# work_role: "Job Title" -# work_role_help: "What was your job title or role?" -# work_duration: "Duration" -# work_duration_help: "When did you hold this gig?" - work_description: "Beschreibung" - work_description_help: "Was hast du dort gemacht (140 Zeichen; optional)" -# education: "Education" -# education_header: "Recount your academic ordeals" -# education_blurb: "List your academic ordeals." - education_school: "Schule" - education_school_help: "Name deiner Schule." - education_degree: "Abschluss" -# education_degree_help: "What was your degree and field of study?" -# education_duration: "Dates" - education_duration_help: "Wann?" - education_description: "Beschreibung" -# education_description_help: "Highlight anything about this educational experience. (140 chars; optional)" -# our_notes: "CodeCombat's Notes" -# remarks: "Remarks" - projects: "Projekte" - projects_header: "Füge 3 Projekte hinzu" - projects_header_2: "Projekte (Top 3)" -# projects_blurb: "Highlight your projects to amaze employers." - project_name: "Projekt Name" - project_name_help: "Wie wurde das Projekt genannt?" - project_description: "Beschreibung" - project_description_help: "Beschreibe kurz das Projekt." - project_picture: "Bild" - project_picture_help: "Lade ein 230x115px oder größeres Bild hoch, welches das Projekt darstellt." - project_link: "Link" - project_link_help: "Verlinke zu dem Projekt." - player_code: "Spieler Code" - - employers: -# hire_developers_not_credentials: "Hire developers, not credentials." -# get_started: "Get Started" -# already_screened: "We've already technically screened all our candidates" -# filter_further: ", but you can also filter further:" -# filter_visa: "Visa" -# filter_visa_yes: "US Authorized" -# filter_visa_no: "Not Authorized" -# filter_education_top: "Top School" -# filter_education_other: "Other" -# filter_role_web_developer: "Web Developer" -# filter_role_software_developer: "Software Developer" -# filter_role_mobile_developer: "Mobile Developer" -# filter_experience: "Experience" -# filter_experience_senior: "Senior" -# filter_experience_junior: "Junior" -# filter_experience_recent_grad: "Recent Grad" -# filter_experience_student: "College Student" -# filter_results: "results" -# start_hiring: "Start hiring." -# reasons: "Three reasons you should hire through us:" -# everyone_looking: "Everyone here is looking for their next opportunity." -# everyone_looking_blurb: "Forget about 20% LinkedIn InMail response rates. Everyone that we list on this site wants to find their next position and will respond to your request for an introduction." -# weeding: "Sit back; we've done the weeding for you." -# weeding_blurb: "Every player that we list has been screened for technical ability. We also perform phone screens for select candidates and make notes on their profiles to save you time." -# pass_screen: "They will pass your technical screen." -# pass_screen_blurb: "Review each candidate's code before reaching out. One employer found that 5x as many of our devs passed their technical screen than hiring from Hacker News." -# make_hiring_easier: "Make my hiring easier, please." - what: "Was ist CodeCombat?" -# what_blurb: "CodeCombat is a multiplayer browser programming game. Players write code to control their forces in battle against other developers. Our players have experience with all major tech stacks." -# cost: "How much do we charge?" -# cost_blurb: "We charge 15% of first year's salary and offer a 100% money back guarantee for 90 days. We don't charge for candidates who are already actively being interviewed at your company." - candidate_name: "Name" -# candidate_location: "Location" -# candidate_looking_for: "Looking For" - candidate_role: "Rolle" -# candidate_top_skills: "Top Skills" -# candidate_years_experience: "Yrs Exp" -# candidate_last_updated: "Last Updated" -# candidate_who: "Who" -# featured_developers: "Featured Developers" -# other_developers: "Other Developers" -# inactive_developers: "Inactive Developers" - - play_level: - done: "Fertig" - customize_wizard: "Bearbeite den Zauberer" - home: "Startseite" -# stop: "Stop" - game_menu: "Spielmenü" - guide: "Hilfe" - restart: "Neustart" - goals: "Ziele" - success: "Erfolgreich!" - incomplete: "Unvollständig" - timed_out: "Zeit abgelaufen" -# failing: "Failing" - action_timeline: "Aktionszeitstrahl" - click_to_select: "Klicke auf eine Einheit, um sie auszuwählen." - reload_title: "Gesamten Code neu laden?" - reload_really: "Bist Du sicher, dass Du das Level neu beginnen willst?" - reload_confirm: "Alles neu laden" - victory_title_prefix: "" - victory_title_suffix: " Abgeschlossen" - victory_sign_up: "Melde Dich an, um Fortschritte zu speichern" - victory_sign_up_poke: "Möchtest Du Neuigkeiten per Mail erhalten? Erstelle einen kostenlosen Account und wir halten Dich auf dem Laufenden." - victory_rate_the_level: "Bewerte das Level: " - victory_return_to_ladder: "Zurück zur Rangliste" - victory_play_next_level: "Spiel das nächste Level" - victory_go_home: "Geh auf die Startseite" - victory_review: "Erzähl uns davon!" - victory_hour_of_code_done: "Bist Du fertig?" - victory_hour_of_code_done_yes: "Ja, ich bin mit meiner Code-Stunde fertig!" - guide_title: "Anleitung" - tome_minion_spells: "Die Zaubersprüche Deiner Knechte" - tome_read_only_spells: "Nur-lesen Zauberspüche" - tome_other_units: "Andere Einheiten" - tome_cast_button_castable: "Führe aus" - tome_cast_button_casting: "Ausführen" - tome_cast_button_cast: "Zauberspuch ausführen" - tome_select_spell: "Wähle einen Zauber" - tome_select_a_thang: "Wähle jemanden aus, um " - tome_available_spells: "Verfügbare Zauber" - hud_continue: "Weiter (drücke Shift + Leertaste)" - spell_saved: "Zauber gespeichert" - skip_tutorial: "Überspringen (Esc)" - keyboard_shortcuts: "Tastenkürzel" - loading_ready: "Bereit!" - tip_insert_positions: "Halte 'Umschalt' gedrückt und klicke auf die Karte um die Koordinaten einzufügen." - tip_toggle_play: "Wechsel zwischen Play und Pause mit Strg+P." - tip_scrub_shortcut: "Spule vor und zurück mit Strg+[ und Strg+]" - tip_guide_exists: "Klicke auf die Anleitung am oberen Ende der Seite für nützliche Informationen" - tip_open_source: "CodeCombat ist 100% quelloffen!" - tip_beta_launch: "CodeCombat startete seine Beta im Oktober 2013." - tip_js_beginning: "JavaScript ist nur der Anfang." - tip_think_solution: "Denke über die Lösung nach, nicht über das Problem." - tip_theory_practice: "In der Theorie gibt es keinen Unterschied zwischen Theorie und Praxis. In der Praxis schon. - Yogi Berra" - tip_error_free: "Es gibt zwei Wege fehlerfreie Programme zu schreiben; nur der Dritte funktioniert. - Alan Perlis" - tip_debugging_program: "Wenn Debugging der Prozess zum Fehler entfernen ist, dann muss Programmieren der Prozess sein Fehler zu machen. - Edsger W. Dijkstra" - tip_forums: "Gehe zum Forum und sage uns was du denkst!" - tip_baby_coders: "In der Zukunft werden sogar Babies Erzmagier sein." - tip_morale_improves: "Das Laden wird weiter gehen bis die Stimmung sich verbessert." - tip_all_species: "Wir glauben an gleiche Chancen für alle Arten Programmieren zu lernen." -# tip_reticulating: "Reticulating spines." - tip_harry: "Du bist ein Zauberer, " - tip_great_responsibility: "Mit großen Programmierfähigkeiten kommt große Verantwortung." - tip_munchkin: "Wenn du dein Gemüse nicht isst, besucht dich ein Zwerg während du schläfst." - tip_binary: "Es gibt auf der Welt nur 10 Arten von Menschen: die, welche Binär verstehen und die, welche nicht." - tip_commitment_yoda: "Ein Programmier muss die größte Hingabe haben, den ernstesten Verstand. ~ Yoda" - tip_no_try: "Tu. Oder tu nicht. Es gibt kein Versuchen. - Yoda" - tip_patience: "Geduld du musst haben, junger Padawan. - Yoda" - tip_documented_bug: "Ein dokumentierter Fehler ist kein Fehler; er ist ein Merkmal." - tip_impossible: "Es wirkt immer unmöglich bis es vollbracht ist. - Nelson Mandela" - tip_talk_is_cheap: "Reden ist billig. Zeig mir den Code. - Linus Torvalds" - tip_first_language: "Das schwierigste, das du jemals lernen wirst, ist die erste Programmiersprache. - Alan Kay" - tip_hardware_problem: "Q: Wie viele Programmierer braucht man um eine Glühbirne auszuwechseln? A: Keine, es ist ein Hardware-Problem." - time_current: "Aktuell" - time_total: "Total" - time_goto: "Gehe zu" - infinite_loop_try_again: "Erneut versuchen" -# infinite_loop_reset_level: "Reset Level" - infinite_loop_comment_out: "Meinen Code auskommentieren" - -# game_menu: -# inventory_tab: "Inventory" -# choose_hero_tab: "Restart Level" -# save_load_tab: "Save/Load" -# options_tab: "Options" -# guide_tab: "Guide" -# multiplayer_tab: "Multiplayer" -# inventory_caption: "Equip your hero" -# choose_hero_caption: "Choose hero, language" -# save_load_caption: "... and view history" -# options_caption: "Configure settings" -# guide_caption: "Docs and tips" -# multiplayer_caption: "Play with friends!" - -# inventory: -# temp: "Temp" - -# choose_hero: -# temp: "Temp" - -# save_load: -# granularity_saved_games: "Saved" -# granularity_change_history: "History" - - options: - general_options: "Allgemeine Einstellungen" - music_label: "Musik" - music_description: "Schalte Hintergrundmusik an/aus." -# autorun_label: "Autorun" -# autorun_description: "Control automatic code execution." - editor_config: "Editor Einstellungen" - editor_config_title: "Editor Einstellungen" - editor_config_level_language_label: "Sprache für dieses Level" - editor_config_level_language_description: "Lege die Programmiersprache für dieses bestimmte Level fest." - editor_config_default_language_label: "Voreinstellung Programmiersprache" - editor_config_default_language_description: "Definiere die Programmiersprache in der du programmieren möchtest wenn du ein neues Level beginnst." - editor_config_keybindings_label: "Tastenbelegung" - editor_config_keybindings_default: "Standard (Ace)" - editor_config_keybindings_description: "Fügt zusätzliche Tastenkombinationen, bekannt aus anderen Editoren, hinzu" - editor_config_livecompletion_label: "Live Auto-Vervollständigung" - editor_config_livecompletion_description: "Zeigt Vorschläge der Auto-Vervollständigung an während du tippst." - editor_config_invisibles_label: "Zeige unsichtbare Zeichen" - editor_config_invisibles_description: "Zeigt unsichtbare Zeichen wie Leertasten an." - editor_config_indentguides_label: "Zeige Einrückungshilfe" - editor_config_indentguides_description: "Zeigt vertikale Linien an um Einrückungen besser zu sehen." - editor_config_behaviors_label: "Intelligentes Verhalten" - editor_config_behaviors_description: "Vervollständigt automatisch Klammern und Anführungszeichen." - -# guide: -# temp: "Temp" - - multiplayer: - multiplayer_title: "Mehrspieler Einstellungen" -# multiplayer_toggle: "Enable multiplayer" - multiplayer_toggle_description: "Erlaube anderen an deinem Spiel teilzunehmen." - multiplayer_link_description: "Gib diesen Link jedem, der mitmachen will." - multiplayer_hint_label: "Hinweis:" - multiplayer_hint: " Klick den Link, um alles auszuwählen, dann drück ⌘-C oder Strg-C um den Link zu kopieren." - multiplayer_coming_soon: "Mehr Multiplayerfeatures werden kommen!" -# multiplayer_sign_in_leaderboard: "Sign in or create an account and get your solution on the leaderboard." - - keyboard_shortcuts: - keyboard_shortcuts: "Tastaturkürzel" - space: "Leertaste" - enter: "Eingabetaste" -# escape: "Escape" -# shift: "Shift" -# cast_spell: "Cast current spell." -# run_real_time: "Run in real time." -# continue_script: "Continue past current script." -# skip_scripts: "Skip past all skippable scripts." -# toggle_playback: "Toggle play/pause." -# scrub_playback: "Scrub back and forward through time." -# single_scrub_playback: "Scrub back and forward through time by a single frame." -# scrub_execution: "Scrub through current spell execution." -# toggle_debug: "Toggle debug display." -# toggle_grid: "Toggle grid overlay." -# toggle_pathfinding: "Toggle pathfinding overlay." -# beautify: "Beautify your code by standardizing its formatting." -# maximize_editor: "Maximize/minimize code editor." -# move_wizard: "Move your Wizard around the level." - - admin: - av_title: "Administrator Übersicht" - av_entities_sub_title: "Entitäten" - av_entities_users_url: "Benutzer" - av_entities_active_instances_url: "Aktive Instanzen" - av_entities_employer_list_url: "Arbeitgeberliste" - av_other_sub_title: "Sonstige" - av_other_debug_base_url: "Base (um base.jade zu debuggen)" - u_title: "Benutzerliste" - lg_title: "Letzte Spiele" -# clas: "CLAs" - - community: - main_title: "CodeCombat Community" -# introduction: "Check out the ways you can get involved below and decide what sounds the most fun. We look forward to working with you!" -# level_editor_prefix: "Use the CodeCombat" -# level_editor_suffix: "to create and edit levels. Users have created levels for their classes, friends, hackathons, students, and siblings. If create a new level sounds intimidating you can start by forking one of ours!" -# thang_editor_prefix: "We call units within the game 'thangs'. Use the" -# thang_editor_suffix: "to modify the CodeCombat source artwork. Allow units to throw projectiles, alter the direction of an animation, change a unit's hit points, or upload your own vector sprites." -# article_editor_prefix: "See a mistake in some of our docs? Want to make some instructions for your own creations? Check out the" -# article_editor_suffix: "and help CodeCombat players get the most out of their playtime." - find_us: "Finde uns auf diesen Seiten" -# contribute_to_the_project: "Contribute to the project" - - editor: - main_title: "CodeCombat Editoren" - article_title: "Artikel Editor" - thang_title: "Thang Editor" - level_title: "Level Editor" -# achievement_title: "Achievement Editor" - back: "Zurück" - revert: "Zurücksetzen" - revert_models: "Models zurücksetzen." - pick_a_terrain: "Wähle ein Terrain" - small: "Klein" -# grassy: "Grassy" - fork_title: "Forke neue Version" - fork_creating: "Erzeuge Fork..." -# randomize: "Randomize" - more: "Mehr" - wiki: "Wiki" - live_chat: "Live Chat" - level_some_options: "Einige Einstellungsmöglichkeiten?" - level_tab_thangs: "Thangs" - level_tab_scripts: "Skripte" - level_tab_settings: "Einstellungen" - level_tab_components: "Komponenten" - level_tab_systems: "Systeme" - level_tab_thangs_title: "Aktuelle Thangs" - level_tab_thangs_all: "Alle" - level_tab_thangs_conditions: "Startbedingungen" - level_tab_thangs_add: "Thangs hinzufügen" - delete: "Löschen" - duplicate: "Duplizieren" - level_settings_title: "Einstellungen" - level_component_tab_title: "Aktuelle Komponenten" - level_component_btn_new: "neue Komponente erstellen" - level_systems_tab_title: "Aktuelle Systeme" - level_systems_btn_new: "neues System erstellen" - level_systems_btn_add: "System hinzufügen" - level_components_title: "Zurück zu allen Thangs" - level_components_type: "Typ" - level_component_edit_title: "Komponente bearbeiten" - level_component_config_schema: "Konfigurationsschema" - level_component_settings: "Einstellungen" - level_system_edit_title: "System bearbeiten" - create_system_title: "neues System erstellen" - new_component_title: "Neue Komponente erstellen" - new_component_field_system: "System" - new_article_title: "Erstelle einen neuen Artikel" - new_thang_title: "Erstelle einen neuen Thang-Typen" - new_level_title: "Erstelle ein neues Level" - new_article_title_login: "Melde dich an um einen neuen Artikel zu erstellen" - new_thang_title_login: "Melde dich an um einen neuen Thang-Typen zu erstellen" - new_level_title_login: "Melde dich an um ein neues Level zu erstellen" -# new_achievement_title: "Create a New Achievement" -# new_achievement_title_login: "Log In to Create a New Achievement" - article_search_title: "Durchsuche Artikel hier" - thang_search_title: "Durchsuche Thang-Typen hier" - level_search_title: "Durchsuche Levels hier" -# achievement_search_title: "Search Achievements" -# read_only_warning2: "Note: you can't save any edits here, because you're not logged in." -# no_achievements: "No achievements have been added for this level yet." -# achievement_query_misc: "Key achievement off of miscellanea" -# achievement_query_goals: "Key achievement off of level goals" -# level_completion: "Level Completion" - - article: - edit_btn_preview: "Vorschau" - edit_article_title: "Artikel bearbeiten" - - general: - and: "und" - name: "Name" - date: "Datum" - body: "Inhalt" - version: "Version" - commit_msg: "Commit Nachricht" - version_history: "Versionshistorie" - version_history_for: "Versionsgeschichte für: " - result: "Ergebnis" - results: "Ergebnisse" - description: "Beschreibung" - or: "oder" - subject: "Betreff" - email: "Email" - password: "Passwort" - message: "Nachricht" - code: "Code" - ladder: "Rangliste" - when: "Wann" - opponent: "Gegner" - rank: "Rang" - score: "Punktzahl" - win: "Sieg" - loss: "Niederlage" - tie: "Unentschieden" - easy: "Einfach" - medium: "Mittel" - hard: "Schwer" - player: "Spieler" - - about: - who_is_codecombat: "Wer ist CodeCombat?" - why_codecombat: "Warum CodeCombat?" - who_description_prefix: "gründeten CodeCombat im Jahre 2013 zusammen. Wir entwickelten außerdem " - who_description_suffix: ", die meist benutzte (#1) Web and iOS Applikation 2008 zum Lernen des Schreibens von chinesischen und japanischen Schriftzeichen." - who_description_ending: "Nun ist es an der Zeit, den Leuten das Programmieren beizubringen." - why_paragraph_1: "Als er Skritter machte, wusste George nicht wie man programmiert und war permanent darüber frustriert, dass er seine Ideen nicht umsetzen konnte. Danach versuchte er es zu lernen, aber das ging ihm zu langsam. Sein Mitbewohner versuchte Codecademy, als er sich umorientierte und aufhörte zu lehren, aber \"langweilte sich\". Jede Woche begann ein neuer Freund mit Codecademy und ließ es dann wieder bleiben. Wir erkannten, dass es das gleiche Problem war, welches wir mit Skritter gelöst hatten: Leute lernen eine Fähigkeit mittels langsamer, intersiver Lerneinheiten, wobei sie schnelle, umfassende Übung bräuchten. Wir kennen Abhilfe." - why_paragraph_2: "Programmieren lernen? Du brauchst keine Stunden. Du musst einen Haufen Code schreiben und dabei Spaß haben." - why_paragraph_3_prefix: "Darum geht's beim Programmieren. Es soll Spaß machen. Nicht so einen Spaß wie" - why_paragraph_3_italic: "jau, 'ne Plakette" - why_paragraph_3_center: "sondern Spaß wie" - why_paragraph_3_italic_caps: "NEIN MUTTI ICH MUSS NOCH DEN LEVEL BEENDEN !" - why_paragraph_3_suffix: "Deshalb ist CodeCombat ein Multiplayerspiel und kein spielähnlicher Kurs. Wir werden nicht aufhören bis du nicht mehr aufhören kannst -- nur diesmal ist das eine gute Sache." - why_paragraph_4: "Wenn dich Spiele süchtig machen, dass lass dich von diesem süchtig machen und werde ein Zauberer des Technologiezeitalters." - why_ending: "Und hey, es kostet nichts. " - why_ending_url: "Beginne jetzt zu zaubern!" - george_description: "CEO, Businesstyp, Web Designer, Game Designer und Champion der Programmieranfänger überall." - scott_description: "Außergewöhnlicher Programmierer, Softwarearchitekt, Küchenzauberer und Finanzmeister. Scott ist der Vernünftige." - nick_description: "Programmierzauberer, exzentrischer Motivationskünstler und Auf-den-Kopf-stell-Experimentierer. Nick könnte alles mögliche tun und entschied CodeCombat zu bauen." - jeremy_description: "Kundendienstmagier, Usability Tester und Community-Organisator. Wahrscheinlich hast du schon mit Jeremy gesprochen." - michael_description: "Programmierer, Systemadministrator und studentisch technisches Wunderkind, Michael hält unsere Server am Laufen." -# matt_description: "Bicyclist, Software Engineer, reader of heroic fantasy, connoisseur of peanut butter, sipper of coffee." - - legal: - page_title: "Rechtliches" - opensource_intro: "CodeCombat ist Free-to-Play und vollständig Open Source." - opensource_description_prefix: "Schau dir " - github_url: "unsere GitHub-Seite" - opensource_description_center: " an und mach mit wenn Du möchtest! CodeCombat baut auf duzenden Open Source Projekten auf, und wir lieben sie. Schau dir die Liste in " - archmage_wiki_url: "unserem Erzmagier-Wiki" - opensource_description_suffix: " an, welche Software dieses Spiel möglich macht." - practices_title: "Best Practices" - practices_description: "Dies sind unsere Versprechen an dich, den Spieler, in weniger Fachchinesisch." - privacy_title: "Datenschutz" - privacy_description: "Wir werden deine persönlichen Daten nicht verkaufen. Letztenendes beabsichtigen wir, durch Vermittlung von Jobs zu verdienen, aber sei versichert, dass wir nicht deine persönlichen Daten ohne deine ausdrückliche Einwilligung interessierten Firmen zur Verfügung stellen werden." - security_title: "Datensicherheit" - security_description: "Wir streben an, deine persönlichen Daten sicher zu verwahren. Als Open Source Projekt ist unsere Site frei zugänglich für jedermann, auch um unsere Sicherheitsmaßnahmen in Augenschein zu nehmen und zu verbessern." - email_title: "Email" - email_description_prefix: "Wir werden dich nicht mit Spam überschwemmen. Mittels" - email_settings_url: "deiner Emaileinstellungen" - email_description_suffix: "oder durch von uns gesendete Links kannst du jederzeit deine Einstellungen ändern und Abonnements kündigen." - cost_title: "Kosten" - cost_description: "CodeCombat ist zur Zeit 100% kostenlos! Eines unserer Hauptziele ist, es dabei zu belassen, so dass es so viele Leute wie möglich spielen können, unabhängig davon in welcher Lebenssituation sie sich befinden. Falls dunkle Wolken aufziehen, könnten wir manche Inhalte im Rahmen eines Abonnements anbieten, aber lieber nicht. Mit etwas Glück können wir die Firma erhalten durch:" - recruitment_title: "Recruiting" - recruitment_description_prefix: "Hier bei CodeCombat kannst du ein mächtiger Zauberer werden, nicht nur im Spiel, sondern auch in der Realität." - url_hire_programmers: "Niemand kann schnell genug Programmierer einstellen." - recruitment_description_suffix: "So wenn du deine Fähigkeiten entwickelt hast und zustimmst, werden wir deine besten Leistungen den tausenden Arbeitgebern demonstrieren, welche nur auf die Gelegentheit warten, dich einzustellen. Sie bezahlen uns ein bisschen, und sie bezahlen dir " - recruitment_description_italic: "jede Menge" - recruitment_description_ending: ", die Seite bleibt kostenlos und jeder ist glücklich. So der Plan." - copyrights_title: "Copyrights und Lizenzen" -# contributor_title: "Contributor License Agreement" -# contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our" -# cla_url: "CLA" -# contributor_description_suffix: "to which you should agree before contributing." -# code_title: "Code - MIT" -# code_description_prefix: "All code owned by CodeCombat or hosted on codecombat.com, both in the GitHub repository or in the codecombat.com database, is licensed under the" - mit_license_url: "MIT Lizenz" -# code_description_suffix: "This includes all code in Systems and Components that are made available by CodeCombat for the purpose of creating levels." -# art_title: "Art/Music - Creative Commons " -# art_description_prefix: "All common content is available under the" -# cc_license_url: "Creative Commons Attribution 4.0 International License" -# art_description_suffix: "Common content is anything made generally available by CodeCombat for the purpose of creating Levels. This includes:" - art_music: "Musik" -# art_sound: "Sound" -# art_artwork: "Artwork" -# art_sprites: "Sprites" -# art_other: "Any and all other non-code creative works that are made available when creating Levels." -# art_access: "Currently there is no universal, easy system for fetching these assets. In general, fetch them from the URLs as used by the site, contact us for assistance, or help us in extending the site to make these assets more easily accessible." -# art_paragraph_1: "For attribution, please name and link to codecombat.com near where the source is used or where appropriate for the medium. For example:" -# use_list_1: "If used in a movie or another game, include codecombat.com in the credits." -# use_list_2: "If used on a website, include a link near the usage, for example underneath an image, or in a general attributions page where you might also mention other Creative Commons works and open source software being used on the site. Something that's already clearly referencing CodeCombat, such as a blog post mentioning CodeCombat, does not need some separate attribution." -# art_paragraph_2: "If the content being used is created not by CodeCombat but instead by a user of codecombat.com, attribute them instead, and follow attribution directions provided in that resource's description if there are any." -# rights_title: "Rights Reserved" -# rights_desc: "All rights are reserved for Levels themselves. This includes" -# rights_scripts: "Scripts" -# rights_unit: "Unit configuration" -# rights_description: "Description" -# rights_writings: "Writings" -# rights_media: "Media (sounds, music) and any other creative content made specifically for that Level and not made generally available when creating Levels." -# rights_clarification: "To clarify, anything that is made available in the Level Editor for the purpose of making levels is under CC, whereas the content created with the Level Editor or uploaded in the course of creation of Levels is not." - nutshell_title: "Zusammenfassung" -# nutshell_description: "Any resources we provide in the Level Editor are free to use as you like for creating Levels. But we reserve the right to restrict distribution of the Levels themselves (that are created on codecombat.com) so that they may be charged for in the future, if that's what ends up happening." - canonical: "Die englische Version dieses Dokuments ist die definitive, kanonische Version. Sollte es Unterschiede zwischen den Übersetzungen geben, dann hat das englische Dokument Vorrang." - - contribute: -# page_title: "Contributing" - character_classes_title: "Charakter Klassen" -# introduction_desc_intro: "We have high hopes for CodeCombat." -# introduction_desc_pref: "We want to be where programmers of all stripes come to learn and play together, introduce others to the wonderful world of coding, and reflect the best parts of the community. We can't and don't want to do that alone; what makes projects like GitHub, Stack Overflow and Linux great are the people who use them and build on them. To that end, " -# introduction_desc_github_url: "CodeCombat is totally open source" -# introduction_desc_suf: ", and we aim to provide as many ways as possible for you to take part and make this project as much yours as ours." -# introduction_desc_ending: "We hope you'll join our party!" -# introduction_desc_signature: "- Nick, George, Scott, Michael, Jeremy and Matt" -# alert_account_message_intro: "Hey there!" -# alert_account_message: "To subscribe for class emails, you'll need to be logged in first." -# archmage_summary: "Interested in working on game graphics, user interface design, database and server organization, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever." -# archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." - class_attributes: "Klassenattribute" -# archmage_attribute_1_pref: "Knowledge in " -# archmage_attribute_1_suf: ", or a desire to learn. Most of our code is in this language. If you're a fan of Ruby or Python, you'll feel right at home. It's JavaScript, but with a nicer syntax." -# archmage_attribute_2: "Some experience in programming and personal initiative. We'll help you get oriented, but we can't spend much time training you." -# how_to_join: "How To Join" -# join_desc_1: "Anyone can help out! Just check out our " -# join_desc_2: "to get started, and check the box below to mark yourself as a brave Archmage and get the latest news by email. Want to chat about what to do or how to get more deeply involved? " -# join_desc_3: ", or find us in our " -# join_desc_4: "and we'll go from there!" - join_url_email: "Emaile uns" -# join_url_hipchat: "public HipChat room" -# more_about_archmage: "Learn More About Becoming an Archmage" -# archmage_subscribe_desc: "Get emails on new coding opportunities and announcements." -# artisan_summary_pref: "Want to design levels and expand CodeCombat's arsenal? People are playing through our content at a pace faster than we can build! Right now, our level editor is barebone, so be wary. Making levels will be a little challenging and buggy. If you have visions of campaigns spanning for-loops to" -# artisan_summary_suf: ", then this class is for you." -# artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to" -# artisan_introduction_suf: ", then this class might be for you." -# artisan_attribute_1: "Any experience in building content like this would be nice, such as using Blizzard's level editors. But not required!" -# artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix." -# artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!" -# artisan_join_desc: "Use the Level Editor in these steps, give or take:" -# artisan_join_step1: "Read the documentation." -# artisan_join_step2: "Create a new level and explore existing levels." -# artisan_join_step3: "Find us in our public HipChat room for help." -# artisan_join_step4: "Post your levels on the forum for feedback." -# more_about_artisan: "Learn More About Becoming an Artisan" -# artisan_subscribe_desc: "Get emails on level editor updates and announcements." -# adventurer_summary: "Let us be clear about your role: you are the tank. You are going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class is for you." -# adventurer_introduction: "Let's be clear about your role: you are the tank. You're going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class might be for you." -# adventurer_attribute_1: "A thirst for learning. You want to learn how to code and we want to teach you how to code. You'll probably be doing most of the teaching in this case, though." -# adventurer_attribute_2: "Charismatic. Be gentle but articulate about what needs improving, and offer suggestions on how to improve." -# adventurer_join_pref: "Either get together with (or recruit!) an Artisan and work with them, or check the box below to receive emails when there are new levels to test. We'll also be posting about levels to review on our networks like" -# adventurer_forum_url: "our forum" -# adventurer_join_suf: "so if you prefer to be notified those ways, sign up there!" -# more_about_adventurer: "Learn More About Becoming an Adventurer" -# adventurer_subscribe_desc: "Get emails when there are new levels to test." -# scribe_summary_pref: "CodeCombat is not just going to be a bunch of levels. It will also be a resource of programming knowledge that players can hook into. That way, each Artisan can link to a detailed article that for the player's edification: documentation akin to what the " -# scribe_summary_suf: " has built. If you enjoy explaining programming concepts, then this class is for you." -# scribe_introduction_pref: "CodeCombat isn't just going to be a bunch of levels. It will also include a resource for knowledge, a wiki of programming concepts that levels can hook into. That way rather than each Artisan having to describe in detail what a comparison operator is, they can simply link their level to the Article describing them that is already written for the player's edification. Something along the lines of what the " -# scribe_introduction_url_mozilla: "Mozilla Developer Network" -# scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you." -# scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others." - contact_us_url: "Kontaktiere uns" -# scribe_join_description: "tell us a little about yourself, your experience with programming and what sort of things you'd like to write about. We'll go from there!" -# more_about_scribe: "Learn More About Becoming a Scribe" -# scribe_subscribe_desc: "Get emails about article writing announcements." -# diplomat_summary: "There is a large interest in CodeCombat in other countries that do not speak English! We are looking for translators who are willing to spend their time translating the site's corpus of words so that CodeCombat is accessible across the world as soon as possible. If you'd like to help getting CodeCombat international, then this class is for you." -# diplomat_introduction_pref: "So, if there's one thing we learned from the " -# diplomat_launch_url: "launch in October" -# diplomat_introduction_suf: "it's that there is sizeable interest in CodeCombat in other countries! We're building a corps of translators eager to turn one set of words into another set of words to get CodeCombat as accessible across the world as possible. If you like getting sneak peeks at upcoming content and getting these levels to your fellow nationals ASAP, then this class might be for you." -# diplomat_attribute_1: "Fluency in English and the language you would like to translate to. When conveying complicated ideas, it's important to have a strong grasp in both!" -# diplomat_join_pref_github: "Find your language locale file " -# diplomat_github_url: "on GitHub" -# diplomat_join_suf_github: ", edit it online, and submit a pull request. Also, check this box below to keep up-to-date on new internationalization developments!" -# more_about_diplomat: "Learn More About Becoming a Diplomat" -# diplomat_subscribe_desc: "Get emails about i18n developments and levels to translate." -# ambassador_summary: "We are trying to build a community, and every community needs a support team when there are troubles. We have got chats, emails, and social networks so that our users can get acquainted with the game. If you want to help people get involved, have fun, and learn some programming, then this class is for you." -# ambassador_introduction: "This is a community we're building, and you are the connections. We've got Olark chats, emails, and social networks with lots of people to talk with and help get acquainted with the game and learn from. If you want to help people get involved and have fun, and get a good feel of the pulse of CodeCombat and where we're going, then this class might be for you." -# ambassador_attribute_1: "Communication skills. Be able to identify the problems players are having and help them solve them. Also, keep the rest of us informed about what players are saying, what they like and don't like and want more of!" -# ambassador_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll go from there!" -# ambassador_join_note_strong: "Note" -# ambassador_join_note_desc: "One of our top priorities is to build multiplayer where players having difficulty solving levels can summon higher level wizards to help them. This will be a great way for ambassadors to do their thing. We'll keep you posted!" -# more_about_ambassador: "Learn More About Becoming an Ambassador" -# ambassador_subscribe_desc: "Get emails on support updates and multiplayer developments." -# changes_auto_save: "Changes are saved automatically when you toggle checkboxes." - diligent_scribes: "Unsere fleißgen Schreiber:" - powerful_archmages: "Unsere mächtigen Erzmagier:" - creative_artisans: "Unsere kreativen Handwerker:" - brave_adventurers: "Unsere mutigen Abenteurer:" - translating_diplomats: "Unsere übersetzenden Diplomaten:" - helpful_ambassadors: "Unsere hilfreichen Botschafter:" - - classes: - archmage_title: "Erzmagier" - archmage_title_description: "(Programmierer)" - artisan_title: "Handwerker" - artisan_title_description: "(Level Entwickler)" - adventurer_title: "Abenteurer" - adventurer_title_description: "(Level Spieltester)" - scribe_title: "Schreiber" - scribe_title_description: "(Artikel Editor)" - diplomat_title: "Diplomat" - diplomat_title_description: "(Übersetzer)" - ambassador_title: "Botschafter" - ambassador_title_description: "(Support)" - - ladder: - please_login: "Bitte logge dich zunächst ein, bevor du ein Ladder-Game spielst." - my_matches: "Meine Matches" - simulate: "Simuliere" -# simulation_explanation: "By simulating games you can get your game ranked faster!" - simulate_games: "Simuliere Spiele!" -# simulate_all: "RESET AND SIMULATE GAMES" - games_simulated_by: "Spiele die durch dich simuliert worden:" - games_simulated_for: "Spiele die für dich simuliert worden:" - games_simulated: "simulierte Spiele" - games_played: "gespielte Spiele" - ratio: "Ratio" -# leaderboard: "Leaderboard" -# battle_as: "Battle as " - summary_your: "Deine " - summary_matches: "Matches - " - summary_wins: " Siege, " -# summary_losses: " Losses" -# rank_no_code: "No New Code to Rank" -# rank_my_game: "Rank My Game!" -# rank_submitting: "Submitting..." -# rank_submitted: "Submitted for Ranking" -# rank_failed: "Failed to Rank" -# rank_being_ranked: "Game Being Ranked" -# rank_last_submitted: "submitted " -# help_simulate: "Help simulate games?" -# code_being_simulated: "Your new code is being simulated by other players for ranking. This will refresh as new matches come in." -# no_ranked_matches_pre: "No ranked matches for the " -# no_ranked_matches_post: " team! Play against some competitors and then come back here to get your game ranked." - choose_opponent: "Wähle einen Gegner" -# select_your_language: "Select your language!" - tutorial_play: "Spiele Tutorial" - tutorial_recommended: "Empfohlen, wenn du noch nie zuvor gespielt hast." - tutorial_skip: "Überspringe Tutorial" -# tutorial_not_sure: "Not sure what's going on?" - tutorial_play_first: "Spiele zuerst das Tutorial." - simple_ai: "Einfache KI" - warmup: "Aufwärmen" - vs: "VS" - friends_playing: "spielende Freunde" - log_in_for_friends: "Melde dich an um mit deinen Freunden zu spielen!" - social_connect_blurb: "Verbinde und spiele gegen deine Freunde!" -# invite_friends_to_battle: "Invite your friends to join you in battle!" -# fight: "Fight!" -# watch_victory: "Watch your victory" -# defeat_the: "Defeat the" - tournament_ends: "Turnier endet" - tournament_ended: "Turnier beendet" - tournament_rules: "Turnier-Regeln" -# tournament_blurb: "Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details" -# tournament_blurb_criss_cross: "Win bids, construct paths, outwit opponents, grab gems, and upgrade your career in our Criss-Cross tournament! Check out the details" -# tournament_blurb_blog: "on our blog" - rules: "Regeln" - winners: "Gewinner" - - ladder_prizes: - title: "Turnierpreise" -# blurb_1: "These prizes will be awarded according to" -# blurb_2: "the tournament rules" -# blurb_3: "to the top human and ogre players." - blurb_4: "Zwei Teams heißt die doppelte Anzahl zu gewinnender Preise!" -# blurb_5: "(There will be two first place winners, two second-place winners, etc.)" - rank: "Rang" - prizes: "Gewinne" -# total_value: "Total Value" -# in_cash: "in cash" -# custom_wizard: "Custom CodeCombat Wizard" -# custom_avatar: "Custom CodeCombat avatar" -# heap: "for six months of \"Startup\" access" -# credits: "credits" -# one_month_coupon: "coupon: choose either Rails or HTML" -# one_month_discount: "discount, 30% off: choose either Rails or HTML" - license: "Lizenz" - oreilly: "Ebook deiner Wahl" - - loading_error: - could_not_load: "Fehler beim Laden vom Server" - connection_failure: "Verbindung fehlgeschlagen." - unauthorized: "Du musst angemeldet sein. Hast du Cookies ausgeschaltet?" - forbidden: "Sie haben nicht die nötigen Berechtigungen." - not_found: "Nicht gefunden." - not_allowed: "Methode nicht erlaubt." - timeout: "Server timeout." - conflict: "Resourcen Konflikt." - bad_input: "Falsche Eingabe." - server_error: "Server Fehler." - unknown: "Unbekannter Fehler." - - resources: -# sessions: "Sessions" - your_sessions: "Meine Sessions" - level: "Level" - social_network_apis: "Social Network APIs" - facebook_status: "Facebook Status" - facebook_friends: "Facebook Freunde" - facebook_friend_sessions: "Facebook Freunde Sessions" - gplus_friends: "G+ Freunde" - gplus_friend_sessions: "G+ Freunde Sessions" -# leaderboard: "Leaderboard" - user_schema: "Benutzerschema" - user_profile: "Benutzerprofil" -# patches: "Patches" -# patched_model: "Source Document" - model: "Model" - system: "System" -# systems: "Systems" - component: "Komponente" - components: "Komponenten" - thang: "Thang" - thangs: "Thangs" - level_session: "Deine Session" - opponent_session: "Gegner-Session" - article: "Artikel" - user_names: "Benutzernamen" - thang_names: "Thang Namen" - files: "Dateien" - top_simulators: "Top Simulatoren" -# source_document: "Source Document" - document: "Dokument" - sprite_sheet: "Sprite Sheet" -# employers: "Employers" -# candidates: "Candidates" - candidate_sessions: "Kandidat-Sessions" - user_remark: "Benutzerkommentar" -# user_remarks: "User Remarks" - versions: "Versionen" - items: "Gegenstände" -# wizard: "Wizard" -# achievement: "Achievement" -# clas: "CLAs" -# play_counts: "Play Counts" - - delta: - added: "hinzugefügt" - modified: "modifiziert" - deleted: "gelöscht" -# moved_index: "Moved Index" -# text_diff: "Text Diff" - merge_conflict_with: "MERGE KONFLIKT MIT" - no_changes: "Keine Änderungen" - -# user: -# stats: "Stats" -# singleplayer_title: "Singleplayer Levels" -# multiplayer_title: "Multiplayer Levels" -# achievements_title: "Achievements" -# last_played: "Last Played" -# status: "Status" -# status_completed: "Completed" -# status_unfinished: "Unfinished" -# no_singleplayer: "No Singleplayer games played yet." -# no_multiplayer: "No Multiplayer games played yet." -# no_achievements: "No Achievements earned yet." -# favorite_prefix: "Favorite language is " -# favorite_postfix: "." - -# achievements: -# last_earned: "Last Earned" -# amount_achieved: "Amount" -# achievement: "Achievement" -# category_contributor: "Contributor" -# category_miscellaneous: "Miscellaneous" -# category_levels: "Levels" -# category_undefined: "Uncategorized" -# current_xp_prefix: "" -# current_xp_postfix: " in total" -# new_xp_prefix: "" -# new_xp_postfix: " earned" -# left_xp_prefix: "" -# left_xp_infix: " until level " -# left_xp_postfix: "" - -# account: -# recently_played: "Recently Played" -# no_recent_games: "No games played during the past two weeks." diff --git a/app/locale/el.coffee b/app/locale/el.coffee index 63a002c9e..f98e92e8b 100644 --- a/app/locale/el.coffee +++ b/app/locale/el.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "ελληνικά", englishDescription: "Gre campaign_multiplayer_description: "... στο οποίο μπορείτε να προγραμματίσετε σώμα με σώμα έναντι άλλων παικτών." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Δυσκολία: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "ελληνικά", englishDescription: "Gre # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "ελληνικά", englishDescription: "Gre # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/en-AU.coffee b/app/locale/en-AU.coffee index f22c6dbe2..0435f05b4 100644 --- a/app/locale/en-AU.coffee +++ b/app/locale/en-AU.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "English (AU)", englishDescription: "English # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "English (AU)", englishDescription: "English # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "English (AU)", englishDescription: "English # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/en-GB.coffee b/app/locale/en-GB.coffee index 925c908c6..18cea4ed4 100644 --- a/app/locale/en-GB.coffee +++ b/app/locale/en-GB.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/en-US.coffee b/app/locale/en-US.coffee index 8ad30dd89..6e8a10869 100644 --- a/app/locale/en-US.coffee +++ b/app/locale/en-US.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "English (US)", englishDescription: "English # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "English (US)", englishDescription: "English # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "English (US)", englishDescription: "English # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/en.coffee b/app/locale/en.coffee index 14c559e90..0be68564c 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -123,6 +123,8 @@ campaign_multiplayer_description: "... in which you code head-to-head against other players." campaign_player_created: "Player-Created" campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." + campaign_classic_algorithms: "Classic Algorithms" + campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Difficulty: " play_as: "Play As" spectate: "Spectate" @@ -460,6 +462,7 @@ options: general_options: "General Options" + volume_label: "Volume" music_label: "Music" music_description: "Turn background music on/off." autorun_label: "Autorun" @@ -952,6 +955,7 @@ achievement: "Achievement" clas: "CLAs" play_counts: "Play Counts" + feedback: "Feedback" delta: added: "Added" diff --git a/app/locale/es-419.coffee b/app/locale/es-419.coffee index a4d767b13..2d595c3dd 100644 --- a/app/locale/es-419.coffee +++ b/app/locale/es-419.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "español (América Latina)", englishDescrip campaign_multiplayer_description: "... en las que programas cara-a-cara contra otros jugadores." campaign_player_created: "Creados-Por-Jugadores" campaign_player_created_description: "... en los que luchas contra la creatividad de tus compañeros Hechiceros Artesanales." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Dificultad: " play_as: "Jugar Como " spectate: "Observar" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "español (América Latina)", englishDescrip options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "español (América Latina)", englishDescrip # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/es-ES.coffee b/app/locale/es-ES.coffee index 64cb82fcb..708209cf3 100644 --- a/app/locale/es-ES.coffee +++ b/app/locale/es-ES.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis campaign_multiplayer_description: "... en las que tu código se enfrentará al de otros jugadores." campaign_player_created: "Creaciones de los Jugadores" campaign_player_created_description: "... en las que luchas contra la creatividad de tus compañeros Magos Artesanos." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Dificultad: " play_as: "Jugar como" spectate: "Observar" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" delta: added: "Añadido" diff --git a/app/locale/es.coffee b/app/locale/es.coffee deleted file mode 100644 index 62896d625..000000000 --- a/app/locale/es.coffee +++ /dev/null @@ -1,998 +0,0 @@ -module.exports = nativeDescription: "español", englishDescription: "Spanish", translation: - common: - loading: "Cargando..." - saving: "Guardando..." - sending: "Enviando..." - send: "Enviar..." - cancel: "Cancelar" - save: "Guardar" -# publish: "Publish" - create: "Crear..." - delay_1_sec: "1 segundo" - delay_3_sec: "3 segundos" - delay_5_sec: "5 segundos" - manual: "Manual" -# fork: "Fork" - play: "Jugar" - retry: "Reintentar" -# watch: "Watch" -# unwatch: "Unwatch" -# submit_patch: "Submit Patch" - - units: - second: "Segundo" - seconds: "Segundos" -# minute: "minute" -# minutes: "minutes" -# hour: "hour" -# hours: "hours" -# day: "day" -# days: "days" -# week: "week" -# weeks: "weeks" -# month: "month" -# months: "months" -# year: "year" -# years: "years" - - modal: - close: "Cerrar" - okay: "OK" - - not_found: - page_not_found: "Pagina no encontrada" - - nav: - play: "Jugar" -# community: "Community" - editor: "Editor" - blog: "Blog" - forum: "Foro" -# account: "Account" -# profile: "Profile" -# stats: "Stats" -# code: "Code" - admin: "Admin" - home: "Inicio" - contribute: "Contribuir" - legal: "Legal" - about: "Sobre" - contact: "Contacto" - twitter_follow: "Seguir" - employers: "Empleados" - - versions: - save_version_title: "Guardar Nueva Versión" - new_major_version: "New Major Version" - cla_prefix: "Para poder guardar los cambios, primero debes aceptar nuestra" - cla_url: "CLA" - cla_suffix: "." - cla_agree: "ACEPTO" - - login: - sign_up: "Crear Cuenta" - log_in: "Iniciar Sesión" -# logging_in: "Logging In" - log_out: "Cerrar Sesión" - recover: "recuperar cuenta" - - recover: - recover_account_title: "Recuperar cuenta" - send_password: "Enviar contraseña olvidada" - - signup: - create_account_title: "Crea una cuenta para guardar el progreso" - description: "Es gratis. Solo necesitas un par de cosas y estarás listo para comenzar:" - email_announcements: "Recibe noticias por email" - coppa: "más de 13 años o fuera de los Estados Unidos" - coppa_why: "¿Por qué?" - creating: "Creando Cuenta..." - sign_up: "Registrarse" - log_in: "Inicia sesión con tu contraseña" -# social_signup: "Or, you can sign up through Facebook or G+:" -# required: "You need to log in before you can go that way." - - home: - slogan: "Aprende a programar jugando" - no_ie: "CodeCombat no funciona en Internet Explorer 9 o versiones anteriores. ¡Lo sentimos!" - no_mobile: "¡CodeCombat no fue diseñado para dispositivos móviles y quizás no funcione!" - play: "Jugar" -# old_browser: "Uh oh, your browser is too old to run CodeCombat. Sorry!" -# old_browser_suffix: "You can try anyway, but it probably won't work." - campaign: "Campaña" - for_beginners: "Para principiantes" - multiplayer: "Multijugador" - for_developers: "Para desarrolladores" -# javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers." -# python_blurb: "Simple yet powerful, Python is a great general purpose programming language." -# coffeescript_blurb: "Nicer JavaScript syntax." -# clojure_blurb: "A modern Lisp." -# lua_blurb: "Game scripting language." -# io_blurb: "Simple but obscure." - - play: - choose_your_level: "Elige tu nivel" - adventurer_prefix: "Puedes saltar a cualquier nivel de abajo, o discutir los niveles en " - adventurer_forum: "el foro del aventurero" - adventurer_suffix: "." - campaign_beginner: "Campaña para principiantes" - campaign_beginner_description: "... en la que aprendes la hechicería de la programación." - campaign_dev: "Niveles aleatorios más difíciles" - campaign_dev_description: "... en los que aprendes sobre la interfaz mientras haces algo un poco más difícil." - campaign_multiplayer: "Arenas Multijugador" - campaign_multiplayer_description: "... en las que programas cara-a-cara contra otros jugadores." - campaign_player_created: "Creados-Por-Jugadores" - campaign_player_created_description: "... en los que luchas contra la creatividad de tus compañeros Hechiceros Artesanales." - level_difficulty: "Dificultad: " - play_as: "Juega como " -# spectate: "Spectate" -# players: "players" -# hours_played: "hours played" - - contact: - contact_us: "Contacta a CodeCombat" - welcome: "¡Qué bueno es escucharte! Usa este formulario para enviarnos un mensaje" - contribute_prefix: "¡Si estas interesado en contribuir, chequea nuestra " - contribute_page: "página de contribución" - contribute_suffix: "!" - forum_prefix: "Para cualquier cosa pública, por favor prueba " - forum_page: "nuestro foro" - forum_suffix: " en su lugar." - send: "Enviar Comentario" -# contact_candidate: "Contact Candidate" -# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 15% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns." - - diplomat_suggestion: - title: "¡Ayuda a traducir CodeCombat!" - sub_heading: "Necesitamos tus habilidades de idioma." - pitch_body: "Desarrollamos CodeCombat en inglés, pero ya tenemos jugadores por todo el mundo. Muchos de ellos quieren jugar en español pero no hablan inglés, así que si puedes hablar ambos, por favor considera registrarte pare ser un Diplomático y ayudar a traducir tanto el sitio de CodeCombat como todos los niveles al español." - missing_translations: "Hasta que podamos traducir todo al español, verás inglés cuando el español no esté disponible." - learn_more: "Aprende más sobre ser un Diplomático" - subscribe_as_diplomat: "Suscribete como un Diplomático" - - wizard_settings: - title: "Configuración del mago" - customize_avatar: "Personaliza tu avatar" -# active: "Active" -# color: "Color" -# group: "Group" - clothes: "Ropa" - trim: "Trim" -# cloud: "Cloud" -# team: "Team" - spell: "Spell" - boots: "Botas" - hue: "Hue" - saturation: "Saturación" - lightness: "Brillo" - - account_settings: - title: "Configuración de la Cuenta" - not_logged_in: "Inicia sesión o crea una cuenta para cambiar tu configuración." - autosave: "Los cambios se guardan Automáticamente" - me_tab: "Yo" - picture_tab: "Imagen" -# upload_picture: "Upload a picture" - wizard_tab: "Hechicero" - password_tab: "Contraseña" - emails_tab: "Correos" - admin: "Administrador" - wizard_color: "Color de Ropas del Hechicero" - new_password: "Nueva Contraseña" - new_password_verify: "Verificar" - email_subscriptions: "Suscripciones de Email" -# email_subscriptions_none: "No Email Subscriptions." - email_announcements: "Noticias" - email_announcements_description: "Recibe correos electrónicos con las últimas noticias y desarrollos de CodeCombat." - email_notifications: "Notificación" -# email_notifications_summary: "Controls for personalized, automatic email notifications related to your CodeCombat activity." -# email_any_notes: "Any Notifications" -# email_any_notes_description: "Disable to stop all activity notification emails." -# email_news: "News" -# email_recruit_notes: "Job Opportunities" -# email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job." - contributor_emails: "Correos Para Colaboradores" - contribute_prefix: "¡Buscamos gente que se una a nuestro comunidad! Comprueba la " - contribute_page: "página de colaboraciones" - contribute_suffix: " para saber más." - email_toggle: "Activar todo" - error_saving: "Error al guardar" - saved: "Cambios guardados" - password_mismatch: "La contraseña no coincide" -# password_repeat: "Please repeat your password." -# job_profile: "Job Profile" -# job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks." -# job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job." -# sample_profile: "See a sample profile" -# view_profile: "View Your Profile" - - account_profile: -# settings: "Settings" -# edit_profile: "Edit Profile" -# done_editing: "Done Editing" - profile_for_prefix: "Perfil de " -# profile_for_suffix: "" -# featured: "Featured" -# not_featured: "Not Featured" -# looking_for: "Looking for:" -# last_updated: "Last updated:" -# contact: "Contact" -# active: "Looking for interview offers now" -# inactive: "Not looking for offers right now" -# complete: "complete" -# next: "Next" -# next_city: "city?" -# next_country: "pick your country." -# next_name: "name?" -# next_short_description: "write a short description." -# next_long_description: "describe your desired position." -# next_skills: "list at least five skills." -# next_work: "chronicle your work history." -# next_education: "recount your educational ordeals." -# next_projects: "show off up to three projects you've worked on." -# next_links: "add any personal or social links." -# next_photo: "add an optional professional photo." -# next_active: "mark yourself open to offers to show up in searches." -# example_blog: "Blog" -# example_personal_site: "Personal Site" -# links_header: "Personal Links" -# links_blurb: "Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog." -# links_name: "Link Name" -# links_name_help: "What are you linking to?" -# links_link_blurb: "Link URL" -# basics_header: "Update basic info" -# basics_active: "Open to Offers" -# basics_active_help: "Want interview offers right now?" -# basics_job_title: "Desired Job Title" -# basics_job_title_help: "What role are you looking for?" -# basics_city: "City" -# basics_city_help: "City you want to work in (or live in now)." -# basics_country: "Country" -# basics_country_help: "Country you want to work in (or live in now)." -# basics_visa: "US Work Status" -# basics_visa_help: "Are you authorized to work in the US, or do you need visa sponsorship? (If you live in Canada or Australia, mark authorized.)" -# basics_looking_for: "Looking For" -# basics_looking_for_full_time: "Full-time" -# basics_looking_for_part_time: "Part-time" -# basics_looking_for_remote: "Remote" -# basics_looking_for_contracting: "Contracting" -# basics_looking_for_internship: "Internship" -# basics_looking_for_help: "What kind of developer position do you want?" -# name_header: "Fill in your name" -# name_anonymous: "Anonymous Developer" -# name_help: "Name you want employers to see, like 'Nick Winter'." -# short_description_header: "Write a short description of yourself" -# short_description_blurb: "Add a tagline to help an employer quickly learn more about you." -# short_description: "Tagline" -# short_description_help: "Who are you, and what are you looking for? 140 characters max." -# skills_header: "Skills" -# skills_help: "Tag relevant developer skills in order of proficiency." -# long_description_header: "Describe your desired position" -# long_description_blurb: "Tell employers how awesome you are and what role you want." -# long_description: "Self Description" -# long_description_help: "Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max." -# work_experience: "Work Experience" -# work_header: "Chronicle your work history" -# work_years: "Years of Experience" -# work_years_help: "How many years of professional experience (getting paid) developing software do you have?" -# work_blurb: "List your relevant work experience, most recent first." -# work_employer: "Employer" -# work_employer_help: "Name of your employer." -# work_role: "Job Title" -# work_role_help: "What was your job title or role?" -# work_duration: "Duration" -# work_duration_help: "When did you hold this gig?" -# work_description: "Description" -# work_description_help: "What did you do there? (140 chars; optional)" -# education: "Education" -# education_header: "Recount your academic ordeals" -# education_blurb: "List your academic ordeals." -# education_school: "School" -# education_school_help: "Name of your school." -# education_degree: "Degree" -# education_degree_help: "What was your degree and field of study?" -# education_duration: "Dates" -# education_duration_help: "When?" -# education_description: "Description" -# education_description_help: "Highlight anything about this educational experience. (140 chars; optional)" -# our_notes: "CodeCombat's Notes" -# remarks: "Remarks" -# projects: "Projects" -# projects_header: "Add 3 projects" -# projects_header_2: "Projects (Top 3)" -# projects_blurb: "Highlight your projects to amaze employers." -# project_name: "Project Name" -# project_name_help: "What was the project called?" -# project_description: "Description" -# project_description_help: "Briefly describe the project." -# project_picture: "Picture" -# project_picture_help: "Upload a 230x115px or larger image showing off the project." -# project_link: "Link" -# project_link_help: "Link to the project." -# player_code: "Player Code" - -# employers: -# hire_developers_not_credentials: "Hire developers, not credentials." -# get_started: "Get Started" -# already_screened: "We've already technically screened all our candidates" -# filter_further: ", but you can also filter further:" -# filter_visa: "Visa" -# filter_visa_yes: "US Authorized" -# filter_visa_no: "Not Authorized" -# filter_education_top: "Top School" -# filter_education_other: "Other" -# filter_role_web_developer: "Web Developer" -# filter_role_software_developer: "Software Developer" -# filter_role_mobile_developer: "Mobile Developer" -# filter_experience: "Experience" -# filter_experience_senior: "Senior" -# filter_experience_junior: "Junior" -# filter_experience_recent_grad: "Recent Grad" -# filter_experience_student: "College Student" -# filter_results: "results" -# start_hiring: "Start hiring." -# reasons: "Three reasons you should hire through us:" -# everyone_looking: "Everyone here is looking for their next opportunity." -# everyone_looking_blurb: "Forget about 20% LinkedIn InMail response rates. Everyone that we list on this site wants to find their next position and will respond to your request for an introduction." -# weeding: "Sit back; we've done the weeding for you." -# weeding_blurb: "Every player that we list has been screened for technical ability. We also perform phone screens for select candidates and make notes on their profiles to save you time." -# pass_screen: "They will pass your technical screen." -# pass_screen_blurb: "Review each candidate's code before reaching out. One employer found that 5x as many of our devs passed their technical screen than hiring from Hacker News." -# make_hiring_easier: "Make my hiring easier, please." -# what: "What is CodeCombat?" -# what_blurb: "CodeCombat is a multiplayer browser programming game. Players write code to control their forces in battle against other developers. Our players have experience with all major tech stacks." -# cost: "How much do we charge?" -# cost_blurb: "We charge 15% of first year's salary and offer a 100% money back guarantee for 90 days. We don't charge for candidates who are already actively being interviewed at your company." -# candidate_name: "Name" -# candidate_location: "Location" -# candidate_looking_for: "Looking For" -# candidate_role: "Role" -# candidate_top_skills: "Top Skills" -# candidate_years_experience: "Yrs Exp" -# candidate_last_updated: "Last Updated" -# candidate_who: "Who" -# featured_developers: "Featured Developers" -# other_developers: "Other Developers" -# inactive_developers: "Inactive Developers" - - play_level: - done: "Hecho" - customize_wizard: "Personalizar Mago" - home: "Inicio" -# stop: "Stop" -# game_menu: "Game Menu" - guide: "Guía" - restart: "Reiniciar" - goals: "Objetivos" -# success: "Success!" -# incomplete: "Incomplete" -# timed_out: "Ran out of time" -# failing: "Failing" - action_timeline: "Cronología de Acción" - click_to_select: "Click en una unidad para seleccionarla" - reload_title: "¿Recargar todo el código?" - reload_really: "¿Estas seguro que quieres reiniciar el nivel?" - reload_confirm: "Recargarlo todo" -# victory_title_prefix: "" - victory_title_suffix: " Completo" - victory_sign_up: "Regístrate para recibir actualizaciones." - victory_sign_up_poke: "¿Buscas recivir las últimas noticias en tu email? Create una cuente gratuita y recibe la correspondencia." - victory_rate_the_level: "Puntúa este nivel: " -# victory_return_to_ladder: "Return to Ladder" - victory_play_next_level: "Jugar el siguiente nivel" - victory_go_home: "Ir a Inicio" - victory_review: "¡Cuéntanos más!" - victory_hour_of_code_done: "¿Has acabado?" - victory_hour_of_code_done_yes: "Si, ¡He terminado con mi hora de código!" - guide_title: "Guía" - tome_minion_spells: "Hechizos de tus Secuaces" - tome_read_only_spells: "Hechizos de Sólo Lectura" - tome_other_units: "Otras Unidades" - tome_cast_button_castable: "Invocable" - tome_cast_button_casting: "Invocando" - tome_cast_button_cast: "Invocar" - tome_select_spell: "Selecciona un Hechizo" - tome_select_a_thang: "Selecciona Alguien para " - tome_available_spells: "Hechizos Disponibles" - hud_continue: "Continuar (presionar shift+space)" - spell_saved: "Hechizo guardado" - skip_tutorial: "Saltar (esc)" -# keyboard_shortcuts: "Key Shortcuts" -# loading_ready: "Ready!" -# tip_insert_positions: "Shift+Click a point on the map to insert it into the spell editor." -# tip_toggle_play: "Toggle play/paused with Ctrl+P." -# tip_scrub_shortcut: "Ctrl+[ and Ctrl+] rewind and fast-forward." -# tip_guide_exists: "Click the guide at the top of the page for useful info." -# tip_open_source: "CodeCombat is 100% open source!" -# tip_beta_launch: "CodeCombat launched its beta in October, 2013." -# tip_js_beginning: "JavaScript is just the beginning." -# tip_think_solution: "Think of the solution, not the problem." -# tip_theory_practice: "In theory, there is no difference between theory and practice. But in practice, there is. - Yogi Berra" -# tip_error_free: "There are two ways to write error-free programs; only the third one works. - Alan Perlis" -# tip_debugging_program: "If debugging is the process of removing bugs, then programming must be the process of putting them in. - Edsger W. Dijkstra" -# tip_forums: "Head over to the forums and tell us what you think!" -# tip_baby_coders: "In the future, even babies will be Archmages." -# tip_morale_improves: "Loading will continue until morale improves." -# tip_all_species: "We believe in equal opportunities to learn programming for all species." -# tip_reticulating: "Reticulating spines." -# tip_harry: "Yer a Wizard, " -# tip_great_responsibility: "With great coding skill comes great debug responsibility." -# tip_munchkin: "If you don't eat your vegetables, a munchkin will come after you while you're asleep." -# tip_binary: "There are only 10 types of people in the world: those who understand binary, and those who don't." -# tip_commitment_yoda: "A programmer must have the deepest commitment, the most serious mind. ~ Yoda" -# tip_no_try: "Do. Or do not. There is no try. - Yoda" -# tip_patience: "Patience you must have, young Padawan. - Yoda" -# tip_documented_bug: "A documented bug is not a bug; it is a feature." -# tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" -# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" -# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" -# tip_hardware_problem: "Q: How many programmers does it take to change a light bulb? A: None, it's a hardware problem." -# time_current: "Now:" -# time_total: "Max:" -# time_goto: "Go to:" -# infinite_loop_try_again: "Try Again" -# infinite_loop_reset_level: "Reset Level" -# infinite_loop_comment_out: "Comment Out My Code" - - game_menu: -# inventory_tab: "Inventory" -# choose_hero_tab: "Restart Level" -# save_load_tab: "Save/Load" -# options_tab: "Options" -# guide_tab: "Guide" - multiplayer_tab: "Multijugador" -# inventory_caption: "Equip your hero" -# choose_hero_caption: "Choose hero, language" -# save_load_caption: "... and view history" -# options_caption: "Configure settings" -# guide_caption: "Docs and tips" -# multiplayer_caption: "Play with friends!" - -# inventory: -# temp: "Temp" - -# choose_hero: -# temp: "Temp" - -# save_load: -# granularity_saved_games: "Saved" -# granularity_change_history: "History" - -# options: -# general_options: "General Options" -# music_label: "Music" -# music_description: "Turn background music on/off." -# autorun_label: "Autorun" -# autorun_description: "Control automatic code execution." -# editor_config: "Editor Config" -# editor_config_title: "Editor Configuration" -# editor_config_level_language_label: "Language for This Level" -# editor_config_level_language_description: "Define the programming language for this particular level." -# editor_config_default_language_label: "Default Programming Language" -# editor_config_default_language_description: "Define the programming language you want to code in when starting new levels." -# editor_config_keybindings_label: "Key Bindings" -# editor_config_keybindings_default: "Default (Ace)" -# editor_config_keybindings_description: "Adds additional shortcuts known from the common editors." -# editor_config_livecompletion_label: "Live Autocompletion" -# editor_config_livecompletion_description: "Displays autocomplete suggestions while typing." -# editor_config_invisibles_label: "Show Invisibles" -# editor_config_invisibles_description: "Displays invisibles such as spaces or tabs." -# editor_config_indentguides_label: "Show Indent Guides" -# editor_config_indentguides_description: "Displays vertical lines to see indentation better." -# editor_config_behaviors_label: "Smart Behaviors" -# editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes." - -# guide: -# temp: "Temp" - - multiplayer: - multiplayer_title: "Configuración de Multijugador" -# multiplayer_toggle: "Enable multiplayer" -# multiplayer_toggle_description: "Allow others to join your game." - multiplayer_link_description: "Da este enlace a cualquiera para que se te una." - multiplayer_hint_label: "Consejo:" - multiplayer_hint: " Cliquea el enlace para seleccionar todo, luego presiona ⌘-C o Ctrl-C para copiar el enlace." - multiplayer_coming_soon: "¡Más características de multijugador por venir!" -# multiplayer_sign_in_leaderboard: "Sign in or create an account and get your solution on the leaderboard." - -# keyboard_shortcuts: -# keyboard_shortcuts: "Keyboard Shortcuts" -# space: "Space" -# enter: "Enter" -# escape: "Escape" -# shift: "Shift" -# cast_spell: "Cast current spell." -# run_real_time: "Run in real time." -# continue_script: "Continue past current script." -# skip_scripts: "Skip past all skippable scripts." -# toggle_playback: "Toggle play/pause." -# scrub_playback: "Scrub back and forward through time." -# single_scrub_playback: "Scrub back and forward through time by a single frame." -# scrub_execution: "Scrub through current spell execution." -# toggle_debug: "Toggle debug display." -# toggle_grid: "Toggle grid overlay." -# toggle_pathfinding: "Toggle pathfinding overlay." -# beautify: "Beautify your code by standardizing its formatting." -# maximize_editor: "Maximize/minimize code editor." -# move_wizard: "Move your Wizard around the level." - - admin: -# av_title: "Admin Views" -# av_entities_sub_title: "Entities" - av_entities_users_url: "Usuarios" -# av_entities_active_instances_url: "Active Instances" -# av_entities_employer_list_url: "Employer List" - av_other_sub_title: "Otros" -# av_other_debug_base_url: "Base (for debugging base.jade)" - u_title: "Lista de usuario" - lg_title: "Últimos juegos" -# clas: "CLAs" - -# community: -# main_title: "CodeCombat Community" -# introduction: "Check out the ways you can get involved below and decide what sounds the most fun. We look forward to working with you!" -# level_editor_prefix: "Use the CodeCombat" -# level_editor_suffix: "to create and edit levels. Users have created levels for their classes, friends, hackathons, students, and siblings. If create a new level sounds intimidating you can start by forking one of ours!" -# thang_editor_prefix: "We call units within the game 'thangs'. Use the" -# thang_editor_suffix: "to modify the CodeCombat source artwork. Allow units to throw projectiles, alter the direction of an animation, change a unit's hit points, or upload your own vector sprites." -# article_editor_prefix: "See a mistake in some of our docs? Want to make some instructions for your own creations? Check out the" -# article_editor_suffix: "and help CodeCombat players get the most out of their playtime." -# find_us: "Find us on these sites" -# contribute_to_the_project: "Contribute to the project" - - editor: -# main_title: "CodeCombat Editors" -# article_title: "Article Editor" -# thang_title: "Thang Editor" - level_title: "Editor de nivel" -# achievement_title: "Achievement Editor" -# back: "Back" -# revert: "Revert" -# revert_models: "Revert Models" -# pick_a_terrain: "Pick A Terrain" -# small: "Small" -# grassy: "Grassy" -# fork_title: "Fork New Version" -# fork_creating: "Creating Fork..." -# randomize: "Randomize" -# more: "More" -# wiki: "Wiki" -# live_chat: "Live Chat" -# level_some_options: "Some Options?" -# level_tab_thangs: "Thangs" -# level_tab_scripts: "Scripts" -# level_tab_settings: "Settings" -# level_tab_components: "Components" -# level_tab_systems: "Systems" -# level_tab_thangs_title: "Current Thangs" -# level_tab_thangs_all: "All" -# level_tab_thangs_conditions: "Starting Conditions" -# level_tab_thangs_add: "Add Thangs" -# delete: "Delete" -# duplicate: "Duplicate" - level_settings_title: "Ajustes" -# level_component_tab_title: "Current Components" -# level_component_btn_new: "Create New Component" -# level_systems_tab_title: "Current Systems" -# level_systems_btn_new: "Create New System" -# level_systems_btn_add: "Add System" -# level_components_title: "Back to All Thangs" - level_components_type: "Tipo" -# level_component_edit_title: "Edit Component" -# level_component_config_schema: "Config Schema" - level_component_settings: "Ajustes" -# level_system_edit_title: "Edit System" -# create_system_title: "Create New System" -# new_component_title: "Create New Component" - new_component_field_system: "Sistema" -# new_article_title: "Create a New Article" -# new_thang_title: "Create a New Thang Type" -# new_level_title: "Create a New Level" -# new_article_title_login: "Log In to Create a New Article" -# new_thang_title_login: "Log In to Create a New Thang Type" -# new_level_title_login: "Log In to Create a New Level" -# new_achievement_title: "Create a New Achievement" -# new_achievement_title_login: "Log In to Create a New Achievement" -# article_search_title: "Search Articles Here" -# thang_search_title: "Search Thang Types Here" -# level_search_title: "Search Levels Here" -# achievement_search_title: "Search Achievements" -# read_only_warning2: "Note: you can't save any edits here, because you're not logged in." -# no_achievements: "No achievements have been added for this level yet." -# achievement_query_misc: "Key achievement off of miscellanea" -# achievement_query_goals: "Key achievement off of level goals" -# level_completion: "Level Completion" - - article: - edit_btn_preview: "Previsualizar" - edit_article_title: "Editar artículo" - - general: - and: "y" - name: "Nombre" -# date: "Date" - body: "Cuerpo" - version: "Versión" -# commit_msg: "Commit Message" -# version_history: "Version History" -# version_history_for: "Version History for: " - result: "Resultado" - results: "Resultados" - description: "Descripción" - or: "o" -# subject: "Subject" - email: "Email" - password: "Contraseña" - message: "Mensaje" - code: "Código" -# ladder: "Ladder" - when: "Cuando" -# opponent: "Opponent" -# rank: "Rank" - score: "Puntuación" - win: "Victoria" - loss: "Pérdida" -# tie: "Tie" - easy: "Fácil" - medium: "Medio" - hard: "Difíficl" -# player: "Player" - - about: - who_is_codecombat: "¿Quién es CodeCombat?" - why_codecombat: "¿Por qué CodeCombat?" -# who_description_prefix: "together started CodeCombat in 2013. We also created " -# who_description_suffix: "in 2008, growing it to the #1 web and iOS application for learning to write Chinese and Japanese characters." -# who_description_ending: "Now it's time to teach people to write code." -# why_paragraph_1: "When making Skritter, George didn't know how to program and was constantly frustrated by his inability to implement his ideas. Afterwards, he tried learning, but the lessons were too slow. His housemate, wanting to reskill and stop teaching, tried Codecademy, but \"got bored.\" Each week another friend started Codecademy, then dropped off. We realized it was the same problem we'd solved with Skritter: people learning a skill via slow, intensive lessons when what they need is fast, extensive practice. We know how to fix that." -# why_paragraph_2: "Need to learn to code? You don't need lessons. You need to write a lot of code and have a great time doing it." -# why_paragraph_3_prefix: "That's what programming is about. It's gotta be fun. Not fun like" -# why_paragraph_3_italic: "yay a badge" -# why_paragraph_3_center: "but fun like" -# why_paragraph_3_italic_caps: "NO MOM I HAVE TO FINISH THE LEVEL!" -# why_paragraph_3_suffix: "That's why CodeCombat is a multiplayer game, not a gamified lesson course. We won't stop until you can't stop--but this time, that's a good thing." -# why_paragraph_4: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age." -# why_ending: "And hey, it's free. " -# why_ending_url: "Start wizarding now!" -# george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." -# scott_description: "Programmer extraordinaire, software architect, kitchen wizard, and master of finances. Scott is the reasonable one." -# nick_description: "Programming wizard, eccentric motivation mage, and upside-down experimenter. Nick can do anything and chooses to build CodeCombat." -# jeremy_description: "Customer support mage, usability tester, and community organizer; you've probably already spoken with Jeremy." -# michael_description: "Programmer, sys-admin, and undergrad technical wunderkind, Michael is the person keeping our servers online." -# matt_description: "Bicyclist, Software Engineer, reader of heroic fantasy, connoisseur of peanut butter, sipper of coffee." - -# legal: -# page_title: "Legal" -# opensource_intro: "CodeCombat is free to play and completely open source." -# opensource_description_prefix: "Check out " -# github_url: "our GitHub" -# opensource_description_center: "and help out if you like! CodeCombat is built on dozens of open source projects, and we love them. See " -# archmage_wiki_url: "our Archmage wiki" -# opensource_description_suffix: "for a list of the software that makes this game possible." -# practices_title: "Respectful Best Practices" -# practices_description: "These are our promises to you, the player, in slightly less legalese." -# privacy_title: "Privacy" -# privacy_description: "We will not sell any of your personal information. We intend to make money through recruitment eventually, but rest assured we will not distribute your personal information to interested companies without your explicit consent." -# security_title: "Security" -# security_description: "We strive to keep your personal information safe. As an open source project, our site is freely open to anyone to review and improve our security systems." -# email_title: "Email" -# email_description_prefix: "We will not inundate you with spam. Through" -# email_settings_url: "your email settings" -# email_description_suffix: "or through links in the emails we send, you can change your preferences and easily unsubscribe at any time." -# cost_title: "Cost" -# cost_description: "Currently, CodeCombat is 100% free! One of our main goals is to keep it that way, so that as many people can play as possible, regardless of place in life. If the sky darkens, we might have to charge subscriptions or for some content, but we'd rather not. With any luck, we'll be able to sustain the company with:" -# recruitment_title: "Recruitment" -# recruitment_description_prefix: "Here on CodeCombat, you're going to become a powerful wizard–not just in the game, but also in real life." -# url_hire_programmers: "No one can hire programmers fast enough" -# recruitment_description_suffix: "so once you've sharpened your skills and if you agree, we will demo your best coding accomplishments to the thousands of employers who are drooling for the chance to hire you. They pay us a little, they pay you" -# recruitment_description_italic: "a lot" -# recruitment_description_ending: "the site remains free and everybody's happy. That's the plan." -# copyrights_title: "Copyrights and Licenses" -# contributor_title: "Contributor License Agreement" -# contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our" -# cla_url: "CLA" -# contributor_description_suffix: "to which you should agree before contributing." -# code_title: "Code - MIT" -# code_description_prefix: "All code owned by CodeCombat or hosted on codecombat.com, both in the GitHub repository or in the codecombat.com database, is licensed under the" -# mit_license_url: "MIT license" -# code_description_suffix: "This includes all code in Systems and Components that are made available by CodeCombat for the purpose of creating levels." -# art_title: "Art/Music - Creative Commons " -# art_description_prefix: "All common content is available under the" -# cc_license_url: "Creative Commons Attribution 4.0 International License" -# art_description_suffix: "Common content is anything made generally available by CodeCombat for the purpose of creating Levels. This includes:" -# art_music: "Music" -# art_sound: "Sound" -# art_artwork: "Artwork" -# art_sprites: "Sprites" -# art_other: "Any and all other non-code creative works that are made available when creating Levels." -# art_access: "Currently there is no universal, easy system for fetching these assets. In general, fetch them from the URLs as used by the site, contact us for assistance, or help us in extending the site to make these assets more easily accessible." -# art_paragraph_1: "For attribution, please name and link to codecombat.com near where the source is used or where appropriate for the medium. For example:" -# use_list_1: "If used in a movie or another game, include codecombat.com in the credits." -# use_list_2: "If used on a website, include a link near the usage, for example underneath an image, or in a general attributions page where you might also mention other Creative Commons works and open source software being used on the site. Something that's already clearly referencing CodeCombat, such as a blog post mentioning CodeCombat, does not need some separate attribution." -# art_paragraph_2: "If the content being used is created not by CodeCombat but instead by a user of codecombat.com, attribute them instead, and follow attribution directions provided in that resource's description if there are any." -# rights_title: "Rights Reserved" -# rights_desc: "All rights are reserved for Levels themselves. This includes" -# rights_scripts: "Scripts" -# rights_unit: "Unit configuration" -# rights_description: "Description" -# rights_writings: "Writings" -# rights_media: "Media (sounds, music) and any other creative content made specifically for that Level and not made generally available when creating Levels." -# rights_clarification: "To clarify, anything that is made available in the Level Editor for the purpose of making levels is under CC, whereas the content created with the Level Editor or uploaded in the course of creation of Levels is not." -# nutshell_title: "In a Nutshell" -# nutshell_description: "Any resources we provide in the Level Editor are free to use as you like for creating Levels. But we reserve the right to restrict distribution of the Levels themselves (that are created on codecombat.com) so that they may be charged for in the future, if that's what ends up happening." -# canonical: "The English version of this document is the definitive, canonical version. If there are any discrepencies between translations, the English document takes precedence." - - contribute: -# page_title: "Contributing" -# character_classes_title: "Character Classes" -# introduction_desc_intro: "We have high hopes for CodeCombat." -# introduction_desc_pref: "We want to be where programmers of all stripes come to learn and play together, introduce others to the wonderful world of coding, and reflect the best parts of the community. We can't and don't want to do that alone; what makes projects like GitHub, Stack Overflow and Linux great are the people who use them and build on them. To that end, " -# introduction_desc_github_url: "CodeCombat is totally open source" -# introduction_desc_suf: ", and we aim to provide as many ways as possible for you to take part and make this project as much yours as ours." -# introduction_desc_ending: "We hope you'll join our party!" -# introduction_desc_signature: "- Nick, George, Scott, Michael, Jeremy and Matt" -# alert_account_message_intro: "Hey there!" -# alert_account_message: "To subscribe for class emails, you'll need to be logged in first." -# archmage_summary: "Interested in working on game graphics, user interface design, database and server organization, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever." -# archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." -# class_attributes: "Class Attributes" -# archmage_attribute_1_pref: "Knowledge in " -# archmage_attribute_1_suf: ", or a desire to learn. Most of our code is in this language. If you're a fan of Ruby or Python, you'll feel right at home. It's JavaScript, but with a nicer syntax." -# archmage_attribute_2: "Some experience in programming and personal initiative. We'll help you get oriented, but we can't spend much time training you." -# how_to_join: "How To Join" -# join_desc_1: "Anyone can help out! Just check out our " -# join_desc_2: "to get started, and check the box below to mark yourself as a brave Archmage and get the latest news by email. Want to chat about what to do or how to get more deeply involved? " -# join_desc_3: ", or find us in our " -# join_desc_4: "and we'll go from there!" -# join_url_email: "Email us" -# join_url_hipchat: "public HipChat room" -# more_about_archmage: "Learn More About Becoming an Archmage" -# archmage_subscribe_desc: "Get emails on new coding opportunities and announcements." -# artisan_summary_pref: "Want to design levels and expand CodeCombat's arsenal? People are playing through our content at a pace faster than we can build! Right now, our level editor is barebone, so be wary. Making levels will be a little challenging and buggy. If you have visions of campaigns spanning for-loops to" -# artisan_summary_suf: ", then this class is for you." -# artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to" -# artisan_introduction_suf: ", then this class might be for you." -# artisan_attribute_1: "Any experience in building content like this would be nice, such as using Blizzard's level editors. But not required!" -# artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix." -# artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!" -# artisan_join_desc: "Use the Level Editor in these steps, give or take:" - artisan_join_step1: "Leer la documentación." -# artisan_join_step2: "Create a new level and explore existing levels." -# artisan_join_step3: "Find us in our public HipChat room for help." -# artisan_join_step4: "Post your levels on the forum for feedback." -# more_about_artisan: "Learn More About Becoming an Artisan" -# artisan_subscribe_desc: "Get emails on level editor updates and announcements." -# adventurer_summary: "Let us be clear about your role: you are the tank. You are going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class is for you." -# adventurer_introduction: "Let's be clear about your role: you are the tank. You're going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class might be for you." -# adventurer_attribute_1: "A thirst for learning. You want to learn how to code and we want to teach you how to code. You'll probably be doing most of the teaching in this case, though." -# adventurer_attribute_2: "Charismatic. Be gentle but articulate about what needs improving, and offer suggestions on how to improve." -# adventurer_join_pref: "Either get together with (or recruit!) an Artisan and work with them, or check the box below to receive emails when there are new levels to test. We'll also be posting about levels to review on our networks like" -# adventurer_forum_url: "our forum" -# adventurer_join_suf: "so if you prefer to be notified those ways, sign up there!" -# more_about_adventurer: "Learn More About Becoming an Adventurer" -# adventurer_subscribe_desc: "Get emails when there are new levels to test." -# scribe_summary_pref: "CodeCombat is not just going to be a bunch of levels. It will also be a resource of programming knowledge that players can hook into. That way, each Artisan can link to a detailed article that for the player's edification: documentation akin to what the " -# scribe_summary_suf: " has built. If you enjoy explaining programming concepts, then this class is for you." -# scribe_introduction_pref: "CodeCombat isn't just going to be a bunch of levels. It will also include a resource for knowledge, a wiki of programming concepts that levels can hook into. That way rather than each Artisan having to describe in detail what a comparison operator is, they can simply link their level to the Article describing them that is already written for the player's edification. Something along the lines of what the " -# scribe_introduction_url_mozilla: "Mozilla Developer Network" -# scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you." -# scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others." -# contact_us_url: "Contact us" -# scribe_join_description: "tell us a little about yourself, your experience with programming and what sort of things you'd like to write about. We'll go from there!" -# more_about_scribe: "Learn More About Becoming a Scribe" -# scribe_subscribe_desc: "Get emails about article writing announcements." -# diplomat_summary: "There is a large interest in CodeCombat in other countries that do not speak English! We are looking for translators who are willing to spend their time translating the site's corpus of words so that CodeCombat is accessible across the world as soon as possible. If you'd like to help getting CodeCombat international, then this class is for you." -# diplomat_introduction_pref: "So, if there's one thing we learned from the " -# diplomat_launch_url: "launch in October" -# diplomat_introduction_suf: "it's that there is sizeable interest in CodeCombat in other countries! We're building a corps of translators eager to turn one set of words into another set of words to get CodeCombat as accessible across the world as possible. If you like getting sneak peeks at upcoming content and getting these levels to your fellow nationals ASAP, then this class might be for you." -# diplomat_attribute_1: "Fluency in English and the language you would like to translate to. When conveying complicated ideas, it's important to have a strong grasp in both!" -# diplomat_join_pref_github: "Find your language locale file " -# diplomat_github_url: "on GitHub" -# diplomat_join_suf_github: ", edit it online, and submit a pull request. Also, check this box below to keep up-to-date on new internationalization developments!" -# more_about_diplomat: "Learn More About Becoming a Diplomat" -# diplomat_subscribe_desc: "Get emails about i18n developments and levels to translate." -# ambassador_summary: "We are trying to build a community, and every community needs a support team when there are troubles. We have got chats, emails, and social networks so that our users can get acquainted with the game. If you want to help people get involved, have fun, and learn some programming, then this class is for you." -# ambassador_introduction: "This is a community we're building, and you are the connections. We've got Olark chats, emails, and social networks with lots of people to talk with and help get acquainted with the game and learn from. If you want to help people get involved and have fun, and get a good feel of the pulse of CodeCombat and where we're going, then this class might be for you." -# ambassador_attribute_1: "Communication skills. Be able to identify the problems players are having and help them solve them. Also, keep the rest of us informed about what players are saying, what they like and don't like and want more of!" -# ambassador_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll go from there!" -# ambassador_join_note_strong: "Note" -# ambassador_join_note_desc: "One of our top priorities is to build multiplayer where players having difficulty solving levels can summon higher level wizards to help them. This will be a great way for ambassadors to do their thing. We'll keep you posted!" -# more_about_ambassador: "Learn More About Becoming an Ambassador" -# ambassador_subscribe_desc: "Get emails on support updates and multiplayer developments." -# changes_auto_save: "Changes are saved automatically when you toggle checkboxes." -# diligent_scribes: "Our Diligent Scribes:" -# powerful_archmages: "Our Powerful Archmages:" -# creative_artisans: "Our Creative Artisans:" -# brave_adventurers: "Our Brave Adventurers:" -# translating_diplomats: "Our Translating Diplomats:" -# helpful_ambassadors: "Our Helpful Ambassadors:" - -# classes: -# archmage_title: "Archmage" -# archmage_title_description: "(Coder)" -# artisan_title: "Artisan" -# artisan_title_description: "(Level Builder)" -# adventurer_title: "Adventurer" -# adventurer_title_description: "(Level Playtester)" -# scribe_title: "Scribe" -# scribe_title_description: "(Article Editor)" -# diplomat_title: "Diplomat" -# diplomat_title_description: "(Translator)" -# ambassador_title: "Ambassador" -# ambassador_title_description: "(Support)" - - ladder: -# please_login: "Please log in first before playing a ladder game." -# my_matches: "My Matches" -# simulate: "Simulate" -# simulation_explanation: "By simulating games you can get your game ranked faster!" -# simulate_games: "Simulate Games!" -# simulate_all: "RESET AND SIMULATE GAMES" -# games_simulated_by: "Games simulated by you:" -# games_simulated_for: "Games simulated for you:" -# games_simulated: "Games simulated" -# games_played: "Games played" -# ratio: "Ratio" -# leaderboard: "Leaderboard" -# battle_as: "Battle as " -# summary_your: "Your " -# summary_matches: "Matches - " - summary_wins: " Victorias, " -# summary_losses: " Losses" -# rank_no_code: "No New Code to Rank" -# rank_my_game: "Rank My Game!" - rank_submitting: "Enviando..." -# rank_submitted: "Submitted for Ranking" -# rank_failed: "Failed to Rank" -# rank_being_ranked: "Game Being Ranked" -# rank_last_submitted: "submitted " -# help_simulate: "Help simulate games?" -# code_being_simulated: "Your new code is being simulated by other players for ranking. This will refresh as new matches come in." -# no_ranked_matches_pre: "No ranked matches for the " -# no_ranked_matches_post: " team! Play against some competitors and then come back here to get your game ranked." -# choose_opponent: "Choose an Opponent" -# select_your_language: "Select your language!" - tutorial_play: "Jugar Tutorial" -# tutorial_recommended: "Recommended if you've never played before" - tutorial_skip: "Saltar Tutorial" -# tutorial_not_sure: "Not sure what's going on?" -# tutorial_play_first: "Play the Tutorial first." -# simple_ai: "Simple AI" - warmup: "Calentamiento" -# vs: "VS" -# friends_playing: "Friends Playing" -# log_in_for_friends: "Log in to play with your friends!" -# social_connect_blurb: "Connect and play against your friends!" -# invite_friends_to_battle: "Invite your friends to join you in battle!" -# fight: "Fight!" -# watch_victory: "Watch your victory" -# defeat_the: "Defeat the" -# tournament_ends: "Tournament ends" -# tournament_ended: "Tournament ended" -# tournament_rules: "Tournament Rules" -# tournament_blurb: "Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details" -# tournament_blurb_criss_cross: "Win bids, construct paths, outwit opponents, grab gems, and upgrade your career in our Criss-Cross tournament! Check out the details" -# tournament_blurb_blog: "on our blog" -# rules: "Rules" -# winners: "Winners" - -# ladder_prizes: -# title: "Tournament Prizes" -# blurb_1: "These prizes will be awarded according to" -# blurb_2: "the tournament rules" -# blurb_3: "to the top human and ogre players." -# blurb_4: "Two teams means double the prizes!" -# blurb_5: "(There will be two first place winners, two second-place winners, etc.)" -# rank: "Rank" -# prizes: "Prizes" -# total_value: "Total Value" -# in_cash: "in cash" -# custom_wizard: "Custom CodeCombat Wizard" -# custom_avatar: "Custom CodeCombat avatar" -# heap: "for six months of \"Startup\" access" -# credits: "credits" -# one_month_coupon: "coupon: choose either Rails or HTML" -# one_month_discount: "discount, 30% off: choose either Rails or HTML" -# license: "license" -# oreilly: "ebook of your choice" - -# loading_error: -# could_not_load: "Error loading from server" -# connection_failure: "Connection failed." -# unauthorized: "You need to be signed in. Do you have cookies disabled?" -# forbidden: "You do not have the permissions." -# not_found: "Not found." -# not_allowed: "Method not allowed." -# timeout: "Server timeout." -# conflict: "Resource conflict." -# bad_input: "Bad input." -# server_error: "Server error." -# unknown: "Unknown error." - -# resources: -# sessions: "Sessions" -# your_sessions: "Your Sessions" -# level: "Level" -# social_network_apis: "Social Network APIs" -# facebook_status: "Facebook Status" -# facebook_friends: "Facebook Friends" -# facebook_friend_sessions: "Facebook Friend Sessions" -# gplus_friends: "G+ Friends" -# gplus_friend_sessions: "G+ Friend Sessions" -# leaderboard: "Leaderboard" -# user_schema: "User Schema" -# user_profile: "User Profile" -# patches: "Patches" -# patched_model: "Source Document" -# model: "Model" -# system: "System" -# systems: "Systems" -# component: "Component" -# components: "Components" -# thang: "Thang" -# thangs: "Thangs" -# level_session: "Your Session" -# opponent_session: "Opponent Session" -# article: "Article" -# user_names: "User Names" -# thang_names: "Thang Names" -# files: "Files" -# top_simulators: "Top Simulators" -# source_document: "Source Document" -# document: "Document" -# sprite_sheet: "Sprite Sheet" -# employers: "Employers" -# candidates: "Candidates" -# candidate_sessions: "Candidate Sessions" -# user_remark: "User Remark" -# user_remarks: "User Remarks" -# versions: "Versions" -# items: "Items" -# wizard: "Wizard" -# achievement: "Achievement" -# clas: "CLAs" -# play_counts: "Play Counts" - -# delta: -# added: "Added" -# modified: "Modified" -# deleted: "Deleted" -# moved_index: "Moved Index" -# text_diff: "Text Diff" -# merge_conflict_with: "MERGE CONFLICT WITH" -# no_changes: "No Changes" - -# user: -# stats: "Stats" -# singleplayer_title: "Singleplayer Levels" -# multiplayer_title: "Multiplayer Levels" -# achievements_title: "Achievements" -# last_played: "Last Played" -# status: "Status" -# status_completed: "Completed" -# status_unfinished: "Unfinished" -# no_singleplayer: "No Singleplayer games played yet." -# no_multiplayer: "No Multiplayer games played yet." -# no_achievements: "No Achievements earned yet." -# favorite_prefix: "Favorite language is " -# favorite_postfix: "." - -# achievements: -# last_earned: "Last Earned" -# amount_achieved: "Amount" -# achievement: "Achievement" -# category_contributor: "Contributor" -# category_miscellaneous: "Miscellaneous" -# category_levels: "Levels" -# category_undefined: "Uncategorized" -# current_xp_prefix: "" -# current_xp_postfix: " in total" -# new_xp_prefix: "" -# new_xp_postfix: " earned" -# left_xp_prefix: "" -# left_xp_infix: " until level " -# left_xp_postfix: "" - -# account: -# recently_played: "Recently Played" -# no_recent_games: "No games played during the past two weeks." diff --git a/app/locale/fa.coffee b/app/locale/fa.coffee index 2a75ddb3e..546186670 100644 --- a/app/locale/fa.coffee +++ b/app/locale/fa.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian", campaign_multiplayer_description: "... جایی که کد رو به رو شدن با بقیه بازیکنان رو مینویسید." campaign_player_created: "ایجاد بازیکن" campaign_player_created_description: "... جایی که در مقابل خلاقیت نیرو هاتون قرار میگیرید جادوگران آرتیزان." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "سختی: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian", # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian", # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/fi.coffee b/app/locale/fi.coffee index 6fb9c21d8..4a00e59e4 100644 --- a/app/locale/fi.coffee +++ b/app/locale/fi.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/fr.coffee b/app/locale/fr.coffee index 913dda2c9..e46ce838a 100644 --- a/app/locale/fr.coffee +++ b/app/locale/fr.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "français", englishDescription: "French", t campaign_multiplayer_description: "... dans laquelle vous coderez en face à face contre d'autres joueurs." campaign_player_created: "Niveaux créés par les joueurs" campaign_player_created_description: "... Dans laquelle vous serez confrontés à la créativité des votres.Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Difficulté: " play_as: "Jouer comme " spectate: "Spectateur" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" delta: added: "Ajouté" diff --git a/app/locale/he.coffee b/app/locale/he.coffee index 380bbdc08..3dd3b47b8 100644 --- a/app/locale/he.coffee +++ b/app/locale/he.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", campaign_multiplayer_description: "..." campaign_player_created: "תוצרי השחקנים" campaign_player_created_description: "... שבהם תילחם נגד היצירתיות של בעלי-המלאכה." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "רמת קושי: " play_as: "שחק בתור " spectate: "צופה" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/hi.coffee b/app/locale/hi.coffee index 4d00d4dee..22a3b4280 100644 --- a/app/locale/hi.coffee +++ b/app/locale/hi.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/hu.coffee b/app/locale/hu.coffee index 1e530b4c7..c5dff3e03 100644 --- a/app/locale/hu.coffee +++ b/app/locale/hu.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t campaign_multiplayer_description: "... amelyekben a kódod felveheti a versenyt más játékosok kódjával" campaign_player_created: "Játékosok pályái" campaign_player_created_description: "...melyekben Művészi Varázsló társaid ellen kűzdhetsz." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Nehézség: " play_as: "Játssz mint" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/id.coffee b/app/locale/id.coffee index ee80dff66..4af035a4a 100644 --- a/app/locale/id.coffee +++ b/app/locale/id.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/it.coffee b/app/locale/it.coffee index 84c168299..f481ebbab 100644 --- a/app/locale/it.coffee +++ b/app/locale/it.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t campaign_multiplayer_description: "... nelle quali programmi faccia a faccia contro altri giocatori." campaign_player_created: "Creati dai giocatori" campaign_player_created_description: "... nei quali affronterai la creatività dei tuoi compagni Stregoni Artigiani." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Difficoltà: " play_as: "Gioca come " spectate: "Spettatore" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/ja.coffee b/app/locale/ja.coffee index 20202577b..2c6f283bb 100644 --- a/app/locale/ja.coffee +++ b/app/locale/ja.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "難易度: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/ko.coffee b/app/locale/ko.coffee index e3a4ef045..73e89e210 100644 --- a/app/locale/ko.coffee +++ b/app/locale/ko.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t campaign_multiplayer_description: "... 이곳에서 당신은 다른 인간 플레이어들과 직접 결투할 수 있습니다." campaign_player_created: "사용자 직접 제작" campaign_player_created_description: "... 당신 동료가 고안한 레벨에 도전하세요 마법사 장인." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "난이도: " play_as: "Play As " spectate: "관중모드" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/locale.coffee b/app/locale/locale.coffee index 34e59f3f7..b94876bfa 100644 --- a/app/locale/locale.coffee +++ b/app/locale/locale.coffee @@ -9,14 +9,11 @@ module.exports = 'en-GB': require './en-GB' # English (UK), English (UK) 'en-AU': require './en-AU' # English (AU), English (AU) ru: require './ru' # русский язык, Russian - de: require './de' # Deutsch, German 'de-DE': require './de-DE' # Deutsch (Deutschland), German (Germany) 'de-AT': require './de-AT' # Deutsch (Österreich), German (Austria) 'de-CH': require './de-CH' # Deutsch (Schweiz), German (Switzerland) - es: require './es' # español, Spanish 'es-419': require './es-419' # español (América Latina), Spanish (Latin America) 'es-ES': require './es-ES' # español (ES), Spanish (Spain) - zh: require './zh' # 中文, Chinese 'zh-HANS': require './zh-HANS' # 简体中文, Chinese (Simplified) 'zh-HANT': require './zh-HANT' # 繁体中文, Chinese (Traditional) 'zh-WUU-HANS': require './zh-WUU-HANS' # 吴语, Wuu (Simplified) @@ -24,13 +21,11 @@ module.exports = fr: require './fr' # français, French ja: require './ja' # 日本語, Japanese ar: require './ar' # العربية, Arabic - pt: require './pt' # português, Portuguese 'pt-BR': require './pt-BR' # português do Brasil, Portuguese (Brazil) 'pt-PT': require './pt-PT' # Português (Portugal), Portuguese (Portugal) pl: require './pl' # język polski, Polish it: require './it' # italiano, Italian tr: require './tr' # Türkçe, Turkish - nl: require './nl' # Nederlands, Dutch 'nl-BE': require './nl-BE' # Nederlands (België), Dutch (Belgium) 'nl-NL': require './nl-NL' # Nederlands (Nederland), Dutch (Netherlands) fa: require './fa' # فارسی, Persian diff --git a/app/locale/lt.coffee b/app/locale/lt.coffee index e5ca1fffa..f9b886ca7 100644 --- a/app/locale/lt.coffee +++ b/app/locale/lt.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/ms.coffee b/app/locale/ms.coffee index d9d6fa714..dfe726098 100644 --- a/app/locale/ms.coffee +++ b/app/locale/ms.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/nb.coffee b/app/locale/nb.coffee index 0c3b52b92..ad155850e 100644 --- a/app/locale/nb.coffee +++ b/app/locale/nb.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg campaign_multiplayer_description: "... hvor du spiller direkte mot andre spillere." campaign_player_created: "Spiller-Lagde" campaign_player_created_description: "... hvor du kjemper mot kreativiteten til en av dine medspillende Artisan Trollmenn." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Vanskelighetsgrad: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/nl-BE.coffee b/app/locale/nl-BE.coffee index dca53ac5d..d842bbd39 100644 --- a/app/locale/nl-BE.coffee +++ b/app/locale/nl-BE.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Nederlands (België)", englishDescription: campaign_multiplayer_description: "... waarin je direct tegen andere spelers speelt." campaign_player_created: "Door-spelers-gemaakt" campaign_player_created_description: "... waarin je ten strijde trekt tegen de creativiteit van andere Ambachtelijke Tovenaars." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Moeilijkheidsgraad: " play_as: "Speel als " spectate: "Toeschouwen" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Nederlands (België)", englishDescription: options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Nederlands (België)", englishDescription: # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/nl-NL.coffee b/app/locale/nl-NL.coffee index 16d8706e0..bb9afa07b 100644 --- a/app/locale/nl-NL.coffee +++ b/app/locale/nl-NL.coffee @@ -15,9 +15,9 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription fork: "Fork" play: "Spelen" retry: "Probeer opnieuw" -# watch: "Watch" -# unwatch: "Unwatch" -# submit_patch: "Submit Patch" + watch: "Volgen" + unwatch: "Ontvolgen" + submit_patch: "Correctie Opsturen" units: second: "seconde" @@ -44,11 +44,11 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription nav: play: "Levels" -# community: "Community" + community: "Gemeenschap" editor: "Editor" blog: "Blog" forum: "Forum" -# account: "Account" + account: "Lidmaatschap" # profile: "Profile" # stats: "Stats" # code: "Code" @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription campaign_multiplayer_description: "... waarin je direct tegen andere spelers speelt." campaign_player_created: "Door-spelers-gemaakt" campaign_player_created_description: "... waarin je ten strijde trekt tegen de creativiteit van andere Ambachtelijke Tovenaars." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Moeilijkheidsgraad: " play_as: "Speel als " spectate: "Toeschouwen" @@ -172,7 +174,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription autosave: "Aanpassingen Automatisch Opgeslagen" me_tab: "Ik" picture_tab: "Afbeelding" -# upload_picture: "Upload a picture" + upload_picture: "Je afbeelding opsturen" wizard_tab: "Tovenaar" password_tab: "Wachtwoord" emails_tab: "Emails" @@ -185,12 +187,12 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription email_announcements: "Aankondigingen" email_announcements_description: "Verkrijg emails over het laatste nieuws en de ontwikkelingen bij CodeCombat." email_notifications: "Notificaties" -# email_notifications_summary: "Controls for personalized, automatic email notifications related to your CodeCombat activity." -# email_any_notes: "Any Notifications" -# email_any_notes_description: "Disable to stop all activity notification emails." + email_notifications_summary: "Instellingen voor gepersonaliseerde, automatische meldingen via e-mail omtrent je activiteit op CodeCombat." + email_any_notes: "Alle Meldingen" + email_any_notes_description: "Zet alle activiteit-meldingen via e-mail af." # email_news: "News" -# email_recruit_notes: "Job Opportunities" -# email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job." + email_recruit_notes: "Job Aanbiedingen" + email_recruit_notes_description: "Als je zeer goed speelt, zouden we je wel eens kunnen contacteren om je een (betere) job aan te bieden." contributor_emails: "Medewerker Klasse emails" contribute_prefix: "We zoeken mensen om met ons te komen feesten! Bekijk de " contribute_page: "bijdragepagina" @@ -203,8 +205,8 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription job_profile: "Job Profiel" job_profile_approved: "Jouw job profiel werd goedgekeurd door CodeCombat. Werkgevers zullen het kunnen bekijken totdat je het inactief zet of als er geen verandering in komt voor vier weken." job_profile_explanation: "Hey! Vul dit in en we zullen je contacteren om je een job als softwareontwikkelaar te helpen vinden." -# sample_profile: "See a sample profile" -# view_profile: "View Your Profile" + sample_profile: "Bekijk een voorbeeld kandidaat-profiel" + view_profile: "Bekijk je eigen kandidaat-profiel" account_profile: # settings: "Settings" @@ -394,7 +396,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription tome_select_spell: "Selecteer een Spreuk" tome_select_a_thang: "Selecteer Iemand voor " tome_available_spells: "Beschikbare spreuken" - hud_continue: "Ga verder (druk shift-space)" + hud_continue: "Ga verder (druk shift-spatie)" spell_saved: "Spreuk Opgeslagen" skip_tutorial: "Overslaan (esc)" # keyboard_shortcuts: "Key Shortcuts" @@ -412,9 +414,9 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription tip_debugging_program: "Als debuggen het proces is om bugs te verwijderen, dan moet programmeren het proces zijn om ze erin te stoppen. - Edsger W. Dijkstra" tip_forums: "Ga naar de forums en vertel ons wat je denkt!" tip_baby_coders: "Zelfs babies zullen in de toekomst een Tovenaar zijn." - tip_morale_improves: "Het spel zal blijven laden tot de moreel verbeterd." + tip_morale_improves: "Het spel zal blijven laden tot de moreel verbetert." tip_all_species: "Wij geloven in gelijke kansen voor alle wezens om te leren programmeren." -# tip_reticulating: "Reticulating spines." + tip_reticulating: "Paden aan het verknopen." tip_harry: "Je bent een tovenaar, " tip_great_responsibility: "Met een groots talent voor programmeren komt een grootse debug verantwoordelijkheid." tip_munchkin: "Als je je groentjes niet opeet zal een munchkin je ontvoeren terwijl je slaapt." @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -476,7 +479,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription # editor_config_livecompletion_label: "Live Autocompletion" # editor_config_livecompletion_description: "Displays autocomplete suggestions while typing." editor_config_invisibles_label: "Toon onzichtbare" - editor_config_invisibles_description: "Toon onzichtbare whitespace karakters." + editor_config_invisibles_description: "Toon onzichtbare (spatie) karakters." editor_config_indentguides_label: "Toon inspringing regels" editor_config_indentguides_description: "Toon verticale hulplijnen om de zichtbaarheid te verbeteren." editor_config_behaviors_label: "Slim gedrag" @@ -528,8 +531,8 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription lg_title: "Laatste Spelletjes" clas: "CLAs" -# community: -# main_title: "CodeCombat Community" + community: + main_title: "CodeCombat Gemeenschap" # introduction: "Check out the ways you can get involved below and decide what sounds the most fun. We look forward to working with you!" # level_editor_prefix: "Use the CodeCombat" # level_editor_suffix: "to create and edit levels. Users have created levels for their classes, friends, hackathons, students, and siblings. If create a new level sounds intimidating you can start by forking one of ours!" @@ -860,13 +863,13 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription simple_ai: "Simpele AI" warmup: "Opwarming" vs: "tegen" -# friends_playing: "Friends Playing" + friends_playing: "Spelende Vrienden" # log_in_for_friends: "Log in to play with your friends!" -# social_connect_blurb: "Connect and play against your friends!" -# invite_friends_to_battle: "Invite your friends to join you in battle!" -# fight: "Fight!" -# watch_victory: "Watch your victory" -# defeat_the: "Defeat the" + social_connect_blurb: "Koppel je sociaal netwerk om tegen je vrienden te spelen!" + invite_friends_to_battle: "Nodig je vrienden uit om deel te nemen aan het gevecht!" + fight: "Aanvallen!" + watch_victory: "Aanschouw je overwinning!" + defeat_the: "Versla de" # tournament_ends: "Tournament ends" # tournament_ended: "Tournament ended" # tournament_rules: "Tournament Rules" @@ -925,19 +928,19 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription patches: "Patches" # patched_model: "Source Document" model: "Model" -# system: "System" + system: "Systeem" # systems: "Systems" -# component: "Component" -# components: "Components" -# thang: "Thang" -# thangs: "Thangs" -# level_session: "Your Session" -# opponent_session: "Opponent Session" -# article: "Article" -# user_names: "User Names" + component: "Component" + components: "Componenten" + thang: "Thang" + thangs: "Thangs" + level_session: "Jouw Sessie" + opponent_session: "Sessie van tegenstander" + article: "Artikel" + user_names: "Gebruikersnamen" # thang_names: "Thang Names" -# files: "Files" -# top_simulators: "Top Simulators" + files: "Bestanden" + top_simulators: "Top Simulatoren" # source_document: "Source Document" # document: "Document" # sprite_sheet: "Sprite Sheet" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/nl.coffee b/app/locale/nl.coffee deleted file mode 100644 index 51399f105..000000000 --- a/app/locale/nl.coffee +++ /dev/null @@ -1,998 +0,0 @@ -module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", translation: - common: - loading: "Bezig met laden..." - saving: "Opslaan..." - sending: "Verzenden..." - send: "Verzend" - cancel: "Annuleren" - save: "Opslaan" - publish: "Publiceren" - create: "Creëer" - delay_1_sec: "1 seconde" - delay_3_sec: "3 secondes" - delay_5_sec: "5 secondes" - manual: "Handleiding" - fork: "Fork" - play: "Spelen" - retry: "Probeer opnieuw" - watch: "Volgen" - unwatch: "Ontvolgen" - submit_patch: "Correctie Opsturen" - - units: - second: "seconde" - seconds: "seconden" - minute: "minuut" - minutes: "minuten" - hour: "uur" - hours: "uren" -# day: "day" -# days: "days" -# week: "week" -# weeks: "weeks" -# month: "month" -# months: "months" -# year: "year" -# years: "years" - - modal: - close: "Sluiten" - okay: "Oké" - - not_found: - page_not_found: "Pagina niet gevonden" - - nav: - play: "Levels" - community: "Gemeenschap" - editor: "Editor" - blog: "Blog" - forum: "Forum" - account: "Lidmaatschap" -# profile: "Profile" -# stats: "Stats" -# code: "Code" - admin: "Administrator" - home: "Home" - contribute: "Bijdragen" - legal: "Legaal" - about: "Over Ons" - contact: "Contact" - twitter_follow: "Volgen" - employers: "Werkgevers" - - versions: - save_version_title: "Nieuwe versie opslaan" - new_major_version: "Nieuwe hoofd versie" - cla_prefix: "Om bewerkingen op te slaan, moet je eerst akkoord gaan met onze" - cla_url: "CLA" - cla_suffix: "." - cla_agree: "IK GA AKKOORD" - - login: - sign_up: "Account maken" - log_in: "Inloggen" - logging_in: "Bezig met inloggen" - log_out: "Uitloggen" - recover: "account herstellen" - - recover: - recover_account_title: "Herstel Account" - send_password: "Verzend nieuw wachtwoord" - - signup: - create_account_title: "Maak een account aan om je vooruitgang op te slaan" - description: "Het is gratis. We hebben maar een paar dingen nodig en dan kan je aan de slag:" - email_announcements: "Ontvang aankondigingen via email" - coppa: "13+ of niet uit de VS" - coppa_why: "(Waarom?)" - creating: "Account aanmaken..." - sign_up: "Aanmelden" - log_in: "inloggen met wachtwoord" - social_signup: "Of je kunt je registreren met Facebook of G+:" -# required: "You need to log in before you can go that way." - - home: - slogan: "Leer programmeren door het spelen van een spel" - no_ie: "CodeCombat werkt niet in IE8 of ouder. Sorry!" - no_mobile: "CodeCombat is niet gemaakt voor mobiele apparaten en werkt misschien niet!" - play: "Speel" - old_browser: "Uh oh, jouw browser is te oud om CodeCombat te kunnen spelen, Sorry!" - old_browser_suffix: "Je kan toch proberen, maar het zal waarschijnlijk niet werken!" - campaign: "Campagne" - for_beginners: "Voor Beginners" - multiplayer: "Multiplayer" - for_developers: "Voor ontwikkelaars" -# javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers." -# python_blurb: "Simple yet powerful, Python is a great general purpose programming language." -# coffeescript_blurb: "Nicer JavaScript syntax." -# clojure_blurb: "A modern Lisp." -# lua_blurb: "Game scripting language." -# io_blurb: "Simple but obscure." - - play: - choose_your_level: "Kies Je Level" - adventurer_prefix: "Je kunt meteen naar een van de levels hieronder springen, of de levels bespreken op " - adventurer_forum: "het Avonturiersforum" - adventurer_suffix: "." - campaign_beginner: "Beginnercampagne" - campaign_beginner_description: "... waarin je de toverkunst van het programmeren leert." - campaign_dev: "Willekeurige moeilijkere levels" - campaign_dev_description: "... waarin je de interface leert kennen terwijl je wat moeilijkers doet." - campaign_multiplayer: "Multiplayer Arena's" - campaign_multiplayer_description: "... waarin je direct tegen andere spelers speelt." - campaign_player_created: "Door-spelers-gemaakt" - campaign_player_created_description: "... waarin je ten strijde trekt tegen de creativiteit van andere Ambachtelijke Tovenaars." - level_difficulty: "Moeilijkheidsgraad: " - play_as: "Speel als " - spectate: "Toeschouwen" -# players: "players" -# hours_played: "hours played" - - contact: - contact_us: "Contact opnemen met CodeCombat" - welcome: "Goed om van je te horen! Gebruik dit formulier om ons een e-mail te sturen." - contribute_prefix: "Als je interesse hebt om bij te dragen, bekijk onze " - contribute_page: "pagina over bijdragen" - contribute_suffix: "!" - forum_prefix: "Voor iets publiekelijks, probeer dan " - forum_page: "ons forum" - forum_suffix: "." - send: "Feedback Verzonden" - contact_candidate: "Contacteer Kandidaat" - recruitment_reminder: "Gebruik dit formulier om kandidaten te contacteren voor wie je een interesse hebt om te interviewen. Vergeet niet dat CodeCombat een honorarium vraagt van 18% op het eerste-jaarssalaris. Dit honorarium moet betaald worden als de kandidaat wordt aangenomen en kon tot na 90 dagen terugbetaald worden als deze ontslagen wordt in deze periode. Deeltijds-, contract- en thuiswerkers worden van dit honorarium vrijgesteld, alsook interims." - - diplomat_suggestion: - title: "Help CodeCombat vertalen!" - sub_heading: "We hebben je taalvaardigheden nodig." - pitch_body: "We ontwikkelen CodeCombat in het Engels, maar we hebben al spelers van over de hele wereld. Veel van hen willen in het Nederlands spelen, maar kunnen geen Engels. Dus als je beiden spreekt, overweeg a.u.b. om je aan te melden als Diplomaat en help zowel de CodeCombat website als alle levels te vertalen naar het Nederlands." - missing_translations: "Totdat we alles hebben vertaald naar het Nederlands zul je Engels zien waar Nederlands niet beschikbaar is." - learn_more: "Meer informatie over het zijn van een Diplomaat" - subscribe_as_diplomat: "Abonneren als Diplomaat" - - wizard_settings: - title: "Tovenaar instellingen" - customize_avatar: "Bewerk je avatar" - active: "Actief" - color: "Kleur" - group: "Groep" - clothes: "Kleren" - trim: "Trim" - cloud: "Wolk" - team: "Team" - spell: "Spreuk" - boots: "Laarzen" - hue: "Hue" - saturation: "Saturatie" - lightness: "Helderheid" - - account_settings: - title: "Account Instellingen" - not_logged_in: "Log in of maak een account aan om je instellingen aan te passen." - autosave: "Aanpassingen Automatisch Opgeslagen" - me_tab: "Ik" - picture_tab: "Afbeelding" - upload_picture: "Je afbeelding opsturen" - wizard_tab: "Tovenaar" - password_tab: "Wachtwoord" - emails_tab: "Emails" - admin: "Administrator" - wizard_color: "Tovenaar Kleding Kleur" - new_password: "Nieuw Wachtwoord" - new_password_verify: "Verifieer" - email_subscriptions: "E-mail Abonnementen" -# email_subscriptions_none: "No Email Subscriptions." - email_announcements: "Aankondigingen" - email_announcements_description: "Verkrijg emails over het laatste nieuws en de ontwikkelingen bij CodeCombat." - email_notifications: "Meldingen" - email_notifications_summary: "Instellingen voor gepersonaliseerde, automatische meldingen via e-mail omtrent je activiteit op CodeCombat." - email_any_notes: "Alle Meldingen" - email_any_notes_description: "Zet alle activiteit-meldingen via e-mail af." -# email_news: "News" - email_recruit_notes: "Job Aanbiedingen" - email_recruit_notes_description: "Als je zeer goed speelt, zouden we je wel eens kunnen contacteren om je een (betere) job aan te bieden." - contributor_emails: "Medewerker Klasse emails" - contribute_prefix: "We zoeken mensen om met ons te komen feesten! Bekijk de " - contribute_page: "bijdragepagina" - contribute_suffix: " om meer te weten te komen." - email_toggle: "Vink alles aan/af" - error_saving: "Fout Tijdens Het Opslaan" - saved: "Aanpassingen Opgeslagen" - password_mismatch: "Het wachtwoord komt niet overeen." -# password_repeat: "Please repeat your password." - job_profile: "Job Profiel" - job_profile_approved: "Jouw job profiel werd goedgekeurd door CodeCombat. Werkgevers zullen het kunnen bekijken totdat je het inactief zet of als er geen verandering in komt voor vier weken." - job_profile_explanation: "Hey! Vul dit in en we zullen je contacteren om je een job als softwareontwikkelaar te helpen vinden." - sample_profile: "Bekijk een voorbeeld kandidaat-profiel" - view_profile: "Bekijk je eigen kandidaat-profiel" - - account_profile: -# settings: "Settings" -# edit_profile: "Edit Profile" -# done_editing: "Done Editing" - profile_for_prefix: "Profiel voor " - profile_for_suffix: "" -# featured: "Featured" -# not_featured: "Not Featured" - looking_for: "Zoekt naar:" - last_updated: "Laatst aangepast:" - contact: "Contact" -# active: "Looking for interview offers now" -# inactive: "Not looking for offers right now" -# complete: "complete" -# next: "Next" -# next_city: "city?" -# next_country: "pick your country." -# next_name: "name?" -# next_short_description: "write a short description." -# next_long_description: "describe your desired position." -# next_skills: "list at least five skills." -# next_work: "chronicle your work history." -# next_education: "recount your educational ordeals." -# next_projects: "show off up to three projects you've worked on." -# next_links: "add any personal or social links." -# next_photo: "add an optional professional photo." -# next_active: "mark yourself open to offers to show up in searches." -# example_blog: "Blog" -# example_personal_site: "Personal Site" -# links_header: "Personal Links" -# links_blurb: "Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog." -# links_name: "Link Name" -# links_name_help: "What are you linking to?" -# links_link_blurb: "Link URL" -# basics_header: "Update basic info" -# basics_active: "Open to Offers" -# basics_active_help: "Want interview offers right now?" -# basics_job_title: "Desired Job Title" -# basics_job_title_help: "What role are you looking for?" -# basics_city: "City" -# basics_city_help: "City you want to work in (or live in now)." -# basics_country: "Country" -# basics_country_help: "Country you want to work in (or live in now)." -# basics_visa: "US Work Status" -# basics_visa_help: "Are you authorized to work in the US, or do you need visa sponsorship? (If you live in Canada or Australia, mark authorized.)" -# basics_looking_for: "Looking For" -# basics_looking_for_full_time: "Full-time" -# basics_looking_for_part_time: "Part-time" -# basics_looking_for_remote: "Remote" -# basics_looking_for_contracting: "Contracting" -# basics_looking_for_internship: "Internship" -# basics_looking_for_help: "What kind of developer position do you want?" -# name_header: "Fill in your name" -# name_anonymous: "Anonymous Developer" -# name_help: "Name you want employers to see, like 'Nick Winter'." -# short_description_header: "Write a short description of yourself" -# short_description_blurb: "Add a tagline to help an employer quickly learn more about you." -# short_description: "Tagline" -# short_description_help: "Who are you, and what are you looking for? 140 characters max." -# skills_header: "Skills" -# skills_help: "Tag relevant developer skills in order of proficiency." -# long_description_header: "Describe your desired position" -# long_description_blurb: "Tell employers how awesome you are and what role you want." -# long_description: "Self Description" -# long_description_help: "Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max." - work_experience: "Werk ervaring" -# work_header: "Chronicle your work history" -# work_years: "Years of Experience" -# work_years_help: "How many years of professional experience (getting paid) developing software do you have?" -# work_blurb: "List your relevant work experience, most recent first." -# work_employer: "Employer" -# work_employer_help: "Name of your employer." -# work_role: "Job Title" -# work_role_help: "What was your job title or role?" -# work_duration: "Duration" -# work_duration_help: "When did you hold this gig?" -# work_description: "Description" -# work_description_help: "What did you do there? (140 chars; optional)" - education: "Opleiding" -# education_header: "Recount your academic ordeals" -# education_blurb: "List your academic ordeals." -# education_school: "School" -# education_school_help: "Name of your school." -# education_degree: "Degree" -# education_degree_help: "What was your degree and field of study?" -# education_duration: "Dates" -# education_duration_help: "When?" -# education_description: "Description" -# education_description_help: "Highlight anything about this educational experience. (140 chars; optional)" - our_notes: "Onze notities" -# remarks: "Remarks" - projects: "Projecten" -# projects_header: "Add 3 projects" -# projects_header_2: "Projects (Top 3)" -# projects_blurb: "Highlight your projects to amaze employers." -# project_name: "Project Name" -# project_name_help: "What was the project called?" -# project_description: "Description" -# project_description_help: "Briefly describe the project." -# project_picture: "Picture" -# project_picture_help: "Upload a 230x115px or larger image showing off the project." -# project_link: "Link" -# project_link_help: "Link to the project." -# player_code: "Player Code" - - employers: -# hire_developers_not_credentials: "Hire developers, not credentials." -# get_started: "Get Started" -# already_screened: "We've already technically screened all our candidates" -# filter_further: ", but you can also filter further:" -# filter_visa: "Visa" -# filter_visa_yes: "US Authorized" -# filter_visa_no: "Not Authorized" -# filter_education_top: "Top School" -# filter_education_other: "Other" -# filter_role_web_developer: "Web Developer" -# filter_role_software_developer: "Software Developer" -# filter_role_mobile_developer: "Mobile Developer" -# filter_experience: "Experience" -# filter_experience_senior: "Senior" -# filter_experience_junior: "Junior" -# filter_experience_recent_grad: "Recent Grad" -# filter_experience_student: "College Student" -# filter_results: "results" -# start_hiring: "Start hiring." -# reasons: "Three reasons you should hire through us:" -# everyone_looking: "Everyone here is looking for their next opportunity." -# everyone_looking_blurb: "Forget about 20% LinkedIn InMail response rates. Everyone that we list on this site wants to find their next position and will respond to your request for an introduction." -# weeding: "Sit back; we've done the weeding for you." -# weeding_blurb: "Every player that we list has been screened for technical ability. We also perform phone screens for select candidates and make notes on their profiles to save you time." -# pass_screen: "They will pass your technical screen." -# pass_screen_blurb: "Review each candidate's code before reaching out. One employer found that 5x as many of our devs passed their technical screen than hiring from Hacker News." -# make_hiring_easier: "Make my hiring easier, please." -# what: "What is CodeCombat?" -# what_blurb: "CodeCombat is a multiplayer browser programming game. Players write code to control their forces in battle against other developers. Our players have experience with all major tech stacks." -# cost: "How much do we charge?" -# cost_blurb: "We charge 15% of first year's salary and offer a 100% money back guarantee for 90 days. We don't charge for candidates who are already actively being interviewed at your company." - candidate_name: "Naam" - candidate_location: "Locatie" - candidate_looking_for: "Zoekt naar" - candidate_role: "Rol" - candidate_top_skills: "Beste vaardigheden" - candidate_years_experience: "Jaren ervaring" - candidate_last_updated: "Laatst aangepast" -# candidate_who: "Who" -# featured_developers: "Featured Developers" -# other_developers: "Other Developers" -# inactive_developers: "Inactive Developers" - - play_level: - done: "Klaar" - customize_wizard: "Pas Tovenaar aan" - home: "Home" -# stop: "Stop" -# game_menu: "Game Menu" - guide: "Handleiding" - restart: "Herstarten" - goals: "Doelen" -# success: "Success!" -# incomplete: "Incomplete" -# timed_out: "Ran out of time" -# failing: "Failing" - action_timeline: "Actie tijdlijn" - click_to_select: "Klik op een eenheid om deze te selecteren." - reload_title: "Alle Code Herladen?" - reload_really: "Weet je zeker dat je dit level tot het begin wilt herladen?" - reload_confirm: "Herlaad Alles" - victory_title_prefix: "" - victory_title_suffix: " Compleet" - victory_sign_up: "Schrijf je in om je vooruitgang op te slaan" - victory_sign_up_poke: "Wil je jouw code opslaan? Maak een gratis account aan!" - victory_rate_the_level: "Beoordeel het level: " - victory_return_to_ladder: "Keer terug naar de ladder" - victory_play_next_level: "Speel Volgend Level" - victory_go_home: "Ga naar Home" - victory_review: "Vertel ons meer!" - victory_hour_of_code_done: "Ben Je Klaar?" - victory_hour_of_code_done_yes: "Ja, ik ben klaar met mijn Hour of Code!" - guide_title: "Handleiding" - tome_minion_spells: "Jouw Minions' Spreuken" - tome_read_only_spells: "Read-Only Spreuken" - tome_other_units: "Andere Eenheden" - tome_cast_button_castable: "Uitvoeren" - tome_cast_button_casting: "Aan het uitvoeren" - tome_cast_button_cast: "Spreuk uitvoeren" - tome_select_spell: "Selecteer een Spreuk" - tome_select_a_thang: "Selecteer Iemand voor " - tome_available_spells: "Beschikbare spreuken" - hud_continue: "Ga verder (druk shift-spatie)" - spell_saved: "Spreuk Opgeslagen" - skip_tutorial: "Overslaan (esc)" -# keyboard_shortcuts: "Key Shortcuts" - loading_ready: "Klaar!" - tip_insert_positions: "Shift+Klik een punt op de kaart om het toe te voegen aan je spreuk editor." - tip_toggle_play: "Verwissel speel/pauze met Ctrl+P." - tip_scrub_shortcut: "Ctrl+[ en Ctrl+] om terug te spoelen en vooruit te spoelen." - tip_guide_exists: "Klik op de handleiding bovenaan het scherm voor nuttige informatie." - tip_open_source: "CodeCombat is 100% open source!" - tip_beta_launch: "CodeCombat lanceerde zijn beta versie in Oktober, 2013." - tip_js_beginning: "JavaScript is nog maar het begin." - tip_think_solution: "Denk aan de oplossing, niet aan het probleem." - tip_theory_practice: "In theorie is er geen verschil tussen de theorie en de praktijk; in de praktijk is er wel een verschil. - Yogi Berra" - tip_error_free: "Er zijn twee manieren om fout-vrije code te schrijven, maar enkele de derde manier werkt. - Alan Perlis" - tip_debugging_program: "Als debuggen het proces is om bugs te verwijderen, dan moet programmeren het proces zijn om ze erin te stoppen. - Edsger W. Dijkstra" - tip_forums: "Ga naar de forums en vertel ons wat je denkt!" - tip_baby_coders: "Zelfs babies zullen in de toekomst een Tovenaar zijn." - tip_morale_improves: "Het spel zal blijven laden tot de moreel verbetert." - tip_all_species: "Wij geloven in gelijke kansen voor alle wezens om te leren programmeren." - tip_reticulating: "Paden aan het verknopen." - tip_harry: "Je bent een tovenaar, " - tip_great_responsibility: "Met een groots talent voor programmeren komt een grootse debug verantwoordelijkheid." - tip_munchkin: "Als je je groentjes niet opeet zal een munchkin je ontvoeren terwijl je slaapt." - tip_binary: "Er zijn 10 soorten mensen in de wereld: Mensen die binair kunnen tellen en mensen die dat niet kunnen." - tip_commitment_yoda: "Een programmeur moet de grootste inzet hebben, een meest serieuze geest. ~ Yoda" - tip_no_try: "Doe het. Of doe het niet. Je kunt niet proberen. - Yoda" - tip_patience: "Geduld moet je hebben, jonge Padawan. - Yoda" - tip_documented_bug: "Een gedocumenteerde fout is geen fout; het is deel van het programma." - tip_impossible: "Het lijkt altijd onmogelijk tot het gedaan wordt. - Nelson Mandela" - tip_talk_is_cheap: "Je kunt het goed uitleggen, maar toon me de code. - Linus Torvalds" - tip_first_language: "Het ergste dat je kan leren is je eerste programmeertaal. - Alan Kay" -# tip_hardware_problem: "Q: How many programmers does it take to change a light bulb? A: None, it's a hardware problem." - time_current: "Nu:" - time_total: "Maximum:" - time_goto: "Ga naar:" - infinite_loop_try_again: "Probeer opnieuw" - infinite_loop_reset_level: "Level resetten" - infinite_loop_comment_out: "Mijn code weg commentariëren" - - game_menu: -# inventory_tab: "Inventory" -# choose_hero_tab: "Restart Level" -# save_load_tab: "Save/Load" -# options_tab: "Options" -# guide_tab: "Guide" - multiplayer_tab: "Multiplayer" -# inventory_caption: "Equip your hero" -# choose_hero_caption: "Choose hero, language" -# save_load_caption: "... and view history" -# options_caption: "Configure settings" -# guide_caption: "Docs and tips" -# multiplayer_caption: "Play with friends!" - -# inventory: -# temp: "Temp" - -# choose_hero: -# temp: "Temp" - -# save_load: -# granularity_saved_games: "Saved" -# granularity_change_history: "History" - - options: -# general_options: "General Options" -# music_label: "Music" -# music_description: "Turn background music on/off." -# autorun_label: "Autorun" -# autorun_description: "Control automatic code execution." - editor_config: "Editor Configuratie" - editor_config_title: "Editor Configuratie" -# editor_config_level_language_label: "Language for This Level" -# editor_config_level_language_description: "Define the programming language for this particular level." -# editor_config_default_language_label: "Default Programming Language" -# editor_config_default_language_description: "Define the programming language you want to code in when starting new levels." - editor_config_keybindings_label: "Toets instellingen" - editor_config_keybindings_default: "Standaard (Ace)" - editor_config_keybindings_description: "Voeg extra shortcuts toe van de gebruikelijke editors." -# editor_config_livecompletion_label: "Live Autocompletion" -# editor_config_livecompletion_description: "Displays autocomplete suggestions while typing." - editor_config_invisibles_label: "Toon onzichtbare" - editor_config_invisibles_description: "Toon onzichtbare (spatie) karakters." - editor_config_indentguides_label: "Toon inspringing regels" - editor_config_indentguides_description: "Toon verticale hulplijnen om de zichtbaarheid te verbeteren." - editor_config_behaviors_label: "Slim gedrag" - editor_config_behaviors_description: "Automatisch aanvullen van (gekrulde) haakjes en aanhalingstekens." - -# guide: -# temp: "Temp" - - multiplayer: - multiplayer_title: "Multiplayer Instellingen" -# multiplayer_toggle: "Enable multiplayer" -# multiplayer_toggle_description: "Allow others to join your game." - multiplayer_link_description: "Geef deze url aan iemand om hem/haar te laten meedoen met jou." - multiplayer_hint_label: "Hint:" - multiplayer_hint: " Klik de link om alles te selecteren, druk dan op Apple-C of Ctrl-C om de link te kopiëren." - multiplayer_coming_soon: "Binnenkort komen er meer Multiplayermogelijkheden!" -# multiplayer_sign_in_leaderboard: "Sign in or create an account and get your solution on the leaderboard." - -# keyboard_shortcuts: -# keyboard_shortcuts: "Keyboard Shortcuts" -# space: "Space" -# enter: "Enter" -# escape: "Escape" -# shift: "Shift" -# cast_spell: "Cast current spell." -# run_real_time: "Run in real time." -# continue_script: "Continue past current script." -# skip_scripts: "Skip past all skippable scripts." -# toggle_playback: "Toggle play/pause." -# scrub_playback: "Scrub back and forward through time." -# single_scrub_playback: "Scrub back and forward through time by a single frame." -# scrub_execution: "Scrub through current spell execution." -# toggle_debug: "Toggle debug display." -# toggle_grid: "Toggle grid overlay." -# toggle_pathfinding: "Toggle pathfinding overlay." -# beautify: "Beautify your code by standardizing its formatting." -# maximize_editor: "Maximize/minimize code editor." -# move_wizard: "Move your Wizard around the level." - - admin: - av_title: "Administrator panels" - av_entities_sub_title: "Entiteiten" - av_entities_users_url: "Gebruikers" - av_entities_active_instances_url: "Actieve instanties" -# av_entities_employer_list_url: "Employer List" - av_other_sub_title: "Andere" - av_other_debug_base_url: "Base (om base.jade te debuggen)" - u_title: "Gebruikerslijst" - lg_title: "Laatste Spelletjes" - clas: "CLAs" - - community: - main_title: "CodeCombat Gemeenschap" -# introduction: "Check out the ways you can get involved below and decide what sounds the most fun. We look forward to working with you!" -# level_editor_prefix: "Use the CodeCombat" -# level_editor_suffix: "to create and edit levels. Users have created levels for their classes, friends, hackathons, students, and siblings. If create a new level sounds intimidating you can start by forking one of ours!" -# thang_editor_prefix: "We call units within the game 'thangs'. Use the" -# thang_editor_suffix: "to modify the CodeCombat source artwork. Allow units to throw projectiles, alter the direction of an animation, change a unit's hit points, or upload your own vector sprites." -# article_editor_prefix: "See a mistake in some of our docs? Want to make some instructions for your own creations? Check out the" -# article_editor_suffix: "and help CodeCombat players get the most out of their playtime." -# find_us: "Find us on these sites" -# contribute_to_the_project: "Contribute to the project" - - editor: - main_title: "CodeCombat Editors" - article_title: "Artikel Editor" - thang_title: "Thang Editor" - level_title: "Level Editor" -# achievement_title: "Achievement Editor" - back: "Terug" - revert: "Keer wijziging terug" - revert_models: "keer wijziging model terug" -# pick_a_terrain: "Pick A Terrain" -# small: "Small" -# grassy: "Grassy" - fork_title: "Kloon naar nieuwe versie" - fork_creating: "Kloon aanmaken..." -# randomize: "Randomize" - more: "Meer" - wiki: "Wiki" - live_chat: "Live Chat" - level_some_options: "Enkele opties?" - level_tab_thangs: "Elementen" - level_tab_scripts: "Scripts" - level_tab_settings: "Instellingen" - level_tab_components: "Componenten" - level_tab_systems: "Systemen" - level_tab_thangs_title: "Huidige Elementen" - level_tab_thangs_all: "Alles" - level_tab_thangs_conditions: "Start Condities" - level_tab_thangs_add: "Voeg element toe" - delete: "Verwijder" - duplicate: "Dupliceer" - level_settings_title: "Instellingen" - level_component_tab_title: "Huidige Componenten" - level_component_btn_new: "Maak een nieuwe component aan" - level_systems_tab_title: "Huidige Systemen" - level_systems_btn_new: "Maak een nieuw systeem aan" - level_systems_btn_add: "Voeg Systeem toe" - level_components_title: "Terug naar Alle Elementen" - level_components_type: "Type" - level_component_edit_title: "Wijzig Component" - level_component_config_schema: "Schema" - level_component_settings: "Instellingen" - level_system_edit_title: "Wijzig Systeem" - create_system_title: "Maak een nieuw Systeem aan" - new_component_title: "Maak een nieuwe Component aan" - new_component_field_system: "Systeem" - new_article_title: "Maak een Nieuw Artikel" - new_thang_title: "Maak een Nieuw Thang Type" - new_level_title: "Maak een Nieuw Level" -# new_article_title_login: "Log In to Create a New Article" -# new_thang_title_login: "Log In to Create a New Thang Type" -# new_level_title_login: "Log In to Create a New Level" -# new_achievement_title: "Create a New Achievement" -# new_achievement_title_login: "Log In to Create a New Achievement" - article_search_title: "Zoek Artikels Hier" - thang_search_title: "Zoek Thang Types Hier" - level_search_title: "Zoek Levels Hier" -# achievement_search_title: "Search Achievements" - read_only_warning2: "Pas op, je kunt geen aanpassingen opslaan hier, want je bent niet ingelogd." -# no_achievements: "No achievements have been added for this level yet." -# achievement_query_misc: "Key achievement off of miscellanea" -# achievement_query_goals: "Key achievement off of level goals" -# level_completion: "Level Completion" - - article: - edit_btn_preview: "Voorbeeld" - edit_article_title: "Wijzig Artikel" - - general: - and: "en" - name: "Naam" -# date: "Date" - body: "Inhoud" - version: "Versie" - commit_msg: "Commit Bericht" - version_history: "Versie geschiedenis" - version_history_for: "Versie geschiedenis voor: " - result: "Resultaat" - results: "Resultaten" - description: "Beschrijving" - or: "of" - subject: "Onderwerp" - email: "Email" - password: "Wachtwoord" - message: "Bericht" - code: "Code" - ladder: "Ladder" - when: "Wanneer" - opponent: "Tegenstander" - rank: "Rang" - score: "Score" - win: "Win" - loss: "Verlies" - tie: "Gelijkstand" - easy: "Gemakkelijk" - medium: "Medium" - hard: "Moeilijk" - player: "Speler" - - about: - who_is_codecombat: "Wie is CodeCombat?" - why_codecombat: "Waarom CodeCombat?" - who_description_prefix: "hebben samen CodeCombat opgericht in 2013. We creëerden ook " - who_description_suffix: "en in 2008, groeide het uit tot de #1 web en iOS applicatie om Chinese en Japanse karakters te leren schrijven." - who_description_ending: "Nu is het tijd om mensen te leren programmeren." - why_paragraph_1: "Tijdens het maken van Skritter wist George niet hoe hij moest programmeren en was hij constant gefrustreerd doordat hij zijn ideeën niet kon verwezelijken. Nadien probeerde hij te studeren maar de lessen gingen te traag. Ook zijn huisgenoot wou opnieuw studeren en stopte met lesgeven. Hij probeerde Codecademy maar was al snel \"verveeld\". Iedere week startte een andere vriend met Codecademy, met telkens als resultaat dat hij/zij vrij snel met de lessen stopte. We realiseerden ons dat het hetzelfde probleem was zoals we al eerder hadden opgelost met Skritter: mensen leren iets via langzame en intensieve lessen, terwijl ze eigenlijk beter een snelle en uitgebreide opleiding nodig hebben. Wij weten hoe dat op te lossen." - why_paragraph_2: "Wil je leren programmeren? Je hebt geen lessen nodig. Je moet vooral veel code schrijven en je amuseren terwijl je dit doet." - why_paragraph_3_prefix: "Dat is waar programmeren om draait. Het moet tof zijn. Niet tof zoals" - why_paragraph_3_italic: "joepie een medaille" - why_paragraph_3_center: "maar tof zoals" - why_paragraph_3_italic_caps: "NEE MAMA IK MOET DIT LEVEL AF MAKEN!" - why_paragraph_3_suffix: "Dat is waarom CodeCombat een multiplayergame is, en niet zomaar lessen gegoten in spelformaat. We zullen niet stoppen totdat jij niet meer kan stoppen--maar deze keer, is dat iets goeds." - why_paragraph_4: "Als je verslaafd gaat zijn aan een spel, dan is het beter om hieraan verslaafd te raken en een tovenaar van het technisch tijdperk te worden." - why_ending: "En hallo, het is gratis." - why_ending_url: "Start nu met toveren!" - george_description: "CEO, zakenman, web designer, game designer, en kampioen van alle beginnende programmeurs." - scott_description: "Extraordinaire programmeur, software ontwikkelaar, keukenprins en heer en meester van financiën. Scott is het meeste voor reden vatbaar." - nick_description: "Getalenteerde programmeur, excentriek gemotiveerd, een rasechte experimenteerder. Nick kan alles en kiest ervoor om CodeCombat te ontwikkelen." - jeremy_description: "Klantenservice Manager, usability tester en gemeenschapsorganisator; Je hebt waarschijnlijk al gesproken met Jeremy." - michael_description: "Programmeur, sys-admin, en technisch wonderkind, Michael is de persoon die onze servers draaiende houdt." -# matt_description: "Bicyclist, Software Engineer, reader of heroic fantasy, connoisseur of peanut butter, sipper of coffee." - - legal: - page_title: "Legaal" - opensource_intro: "CodeCombat is gratis en volledig open source." - opensource_description_prefix: "Bekijk " - github_url: "onze GitHub" - opensource_description_center: "en help ons als je wil! CodeCombat is gebouwd met de hulp van tientallen open source projecten, en wij zijn er gek op. Bekijk ook " - archmage_wiki_url: "onze Tovenaar wiki" - opensource_description_suffix: "voor een lijst van de software die dit spel mogelijk maakt." - practices_title: "Goede Respectvolle gewoonten" - practices_description: "Dit zijn onze beloften aan u, de speler, in een iets minder juridische jargon." - privacy_title: "Privacy" - privacy_description: "We zullen nooit jouw persoonlijke informatie verkopen. We willen in verloop van tijd geld verdienen dankzij aanwervingen, maar je mag op je beide oren slapen dat wij nooit jouw persoonlijke informatie zullen verspreiden aan geïnteresseerde bedrijven zonder dat jij daar expliciet mee akkoord gaat." - security_title: "Beveiliging" - security_description: "We streven ernaar om jouw persoonlijke informatie veilig te bewaren. Onze website is open en beschikbaar voor iedereen, opdat ons beveiliging systeem kan worden nagekeken en geoptimaliseerd door iedereen die dat wil. Dit alles is mogelijk doordat we volledig open source en transparant zijn." - email_title: "E-mail" - email_description_prefix: "We zullen je niet overspoelen met spam. Door" - email_settings_url: "jouw e-mail instellingen" - email_description_suffix: "of via urls in de emails die wij verzenden, kan je jouw instellingen wijzigen en ten allen tijden uitschrijven." - cost_title: "Kosten" - cost_description: "Momenteel is CodeCombat 100% gratis! Één van onze doestellingen is om dit zo te houden, opdat zoveel mogelijk mensen kunnen spelen, onafhankelijk van waar je leeft of wie je bent. Als het financieel moeilijker wordt, kan het mogelijk zijn dat we gaan beginnen met abonnementen of een prijs zetten op bepaalde zaken, maar we streven ernaar om dit te voorkomen. Met een beetje geluk zullen we dit voor altijd kunnen garanderen met:" - recruitment_title: "Aanwervingen" - recruitment_description_prefix: "Hier bij CodeCombat, ga je ontplooien tot een krachtige tovenoor-niet enkel virtueel, maar ook in het echt." - url_hire_programmers: "Niemand kan snel genoeg programmeurs aanwerven" - recruitment_description_suffix: "dus eenmaal je jouw vaardigheden hebt aangescherp en ermee akkoord gaat, zullen we jouw beste programmeer prestaties voorstellen aan duizenden werkgevers die niet kunnen wachten om jou aan te werven. Zij betalen ons een beetje, maar betalen jou" - recruitment_description_italic: "enorm veel" - recruitment_description_ending: "de site blijft volledig gratis en iedereen is gelukkig. Dat is het plan." - copyrights_title: "Auteursrechten en licenties" - contributor_title: "Licentieovereenkomst voor vrijwilligers" - contributor_description_prefix: "Alle bijdragen, zowel op de website als op onze GitHub repository, vallen onder onze" - cla_url: "CLA" - contributor_description_suffix: "waarmee je moet akkoord gaan voordat wij jouw bijdragen kunnen gebruiken." - code_title: "Code - MIT" - code_description_prefix: "Alle code in het bezit van CodeCombat of aanwezig op codecombat.com, zowel in de GitHub respository als in de codecombat.com database, is erkend onder de" - mit_license_url: "MIT licentie" - code_description_suffix: "Dit geldt ook voor code in Systemen en Componenten dat publiek is gemaakt met als doel het maken van levels." - art_title: "Art/Music - Creative Commons " - art_description_prefix: "Alle gemeenschappelijke inhoud valt onder de" - cc_license_url: "Creative Commons Attribution 4.0 Internationale Licentie" - art_description_suffix: "Gemeenschappelijke inhoud is alles dat algemeen verkrijgbaar is bij CodeCombat met als doel levels te maken. Dit omvat:" - art_music: "Muziek" - art_sound: "Geluid" - art_artwork: "Illustraties" - art_sprites: "Sprites" - art_other: "Eender wat en al het creatief werk dat niet als code aanzien wordt en verkrijgbaar is bij het aanmaken van levels." - art_access: "Momenteel is er geen universeel en gebruiksvriendelijk systeem voor het ophalen van deze assets. In het algemeen, worden deze opgehaald via de links zoals gebruikt door de website. Contacteer ons voor assistentie, of help ons met de website uit te breiden en de assets bereikbaarder te maken." - art_paragraph_1: "Voor toekenning, gelieve de naam en link naar codecombat.com te plaatsen waar dit passend is voor de vorm waarin het voorkomt. Bijvoorbeeld:" - use_list_1: "Wanneer gebruikt in een film of een ander spel, voeg codecombat.com toe in de credits." - use_list_2: "Wanneer toegepast op een website, inclusief een link naar het gebruik, bijvoorbeeld onderaan een afbeelding. Of in een algemene webpagina waar je eventueel ook andere Creative Commons werken en open source software vernoemd die je gebruikt op de website. Iets dat al duidelijk gerelateerd is met CodeCombat, zoals een blog artikel dat CodeCombat vernoemd, heeft geen aparte vermelding nodig." - art_paragraph_2: "Wanneer de gebruikte inhoud is gemaakt door een gebruiker van codecombat.com, vernoem hem/haar in plaats van ons en volg toekenningsaanwijzingen als deze in de beschrijving van de bron staan." - rights_title: "Rechten Voorbehouden" - rights_desc: "Alle rechten zijn voorbehouden voor de Levels zelf. Dit omvat:" - rights_scripts: "Scripts" - rights_unit: "Eenheid Configuratie" - rights_description: "Beschrijvingen" - rights_writings: "Literaire werken" - rights_media: "Media (geluid, muziek) en eender welke creatieve inhoud, specifiek gemaakt voor dat level en niet verkrijgbaar bij het maken van levels." - rights_clarification: "Om het duidelijk te maken, iets dat beschikbaar is in de Level editor voor het maken van levels, valt onder de CC licentie. Terwijl de inhoud gemaakt met de Level Editor of geüpload in de loop van de creatie van de levels, hier niet onder vallen." - nutshell_title: "In een notendop" - nutshell_description: "Alle middelen die wij aanbieden in de Level Editor zijn gratis te gebruiken om levels aan te maken. Wij behouden ons echter het recht voor om levels die gemaakt zijn op codecombat.com te beperken, en hier in de toekomst geld voor te vragen, moest dat ooit gebeuren." - canonical: "De Engelse versie van dit document is de definitieve en kanonieke versie. Bij verschillen tussen vertalingen heeft de Engelse versie voorrang." - - contribute: - page_title: "Bijdragen" - character_classes_title: "Karakterklassen" - introduction_desc_intro: "We hebben hoge verwachtingen over CodeCombat." - introduction_desc_pref: "We willen zijn waar programmeurs van alle niveaus komen om te leren en samen te spelen, anderen introduceren aan de wondere wereld van code, en de beste delen van de gemeenschap te reflecteren. We kunnen en willen dit niet alleen doen; wat projecten zoals GitHub, Stack Overflow en Linux groots en succesvol maken, zijn de mensen die deze software gebruiken en verbeteren. Daartoe, " - introduction_desc_github_url: "CodeCombat is volledig open source" - introduction_desc_suf: ", en we streven ernaar om op zoveel mogelijk manieren het mogelijk te maken voor u om deel te nemen en dit project van zowel jou als ons te maken." - introduction_desc_ending: "We hopen dat je met ons meedoet!" - introduction_desc_signature: "- Nick, George, Scott, Michael, Jeremy en Matt" - alert_account_message_intro: "Hallo!" -# alert_account_message: "To subscribe for class emails, you'll need to be logged in first." - archmage_summary: "Geïnteresserd in het werken aan game graphics, user interface design, database- en serverorganisatie, multiplayer networking, physics, geluid of game engine prestaties? Wil jij helpen een game te bouwen wat anderen leert waar jij goed in bent? We moeten nog veel doen en als jij een ervaren programmeur bent en wil ontwikkelen voor CodeCombat, dan is dit de klasse voor jou. We zouden graag je hulp hebben bij het maken van de beste programmeergame ooit." - archmage_introduction: "Een van de beste aspecten aan het maken van spelletjes is dat zij zoveel verschillende zaken omvatten. Visualisaties, geluid, real-time netwerken, sociale netwerken, en natuurlijk enkele veelvoorkomende aspecten van programmeren, van low-level database beheer en server administratie tot gebruiksvriendelijke interfaces maken. Er is veel te doen, en als jij een ervaren programmeur bent met de motivatie om je volledig te verdiepen in de details van CodeCombat, dan ben je de tovenaar die wij zoeken! We zouden graag jouw hulp krijgen bij het bouwen van het allerbeste programmeerspel ooit." - class_attributes: "Klasse kenmerken" - archmage_attribute_1_pref: "Ervaring met " - archmage_attribute_1_suf: ", of de wil om het te leren. De meeste van onze code is in deze taal. Indien je een fan van Ruby of Python bent, zal je je meteen thuis voelen! Het is zoals JavaScript, maar met een mooiere syntax." - archmage_attribute_2: "Ervaring in programmeren en individueel initiatief. We kunnen jou helpen bij het opstarten, maar kunnen niet veel tijd spenderen om je op te leiden." - how_to_join: "Hoe deel te nemen" - join_desc_1: "Iedereen kan helpen! Bekijk onze " - join_desc_2: "om te starten, en vink het vierkantje hieronder aan om jezelf te abonneren als dappere tovenaar en het laatste magische nieuws te ontvangen. Wil je met ons praten over wat er te doen is of hoe je nog meer kunt helpen? " - join_desc_3: ", of vind ons in " - join_desc_4: "en we bekijken het verder vandaar!" - join_url_email: "E-mail ons" - join_url_hipchat: "ons publiek (Engelstalig) HipChat kanaal" - more_about_archmage: "Leer meer over hoe je een Machtige Tovenaar kan worden" - archmage_subscribe_desc: "Ontvang e-mails met nieuwe programmeer mogelijkheden en aankondigingen." - artisan_summary_pref: "Wil je levels ontwerpen en CodeCombat's arsenaal vergroten? Mensen spelen sneller door onze content dan wij bij kunnen houden! Op dit moment is onze level editor nog wat beperkt, dus wees daarvan bewust. Het maken van levels zal een uitdaging zijn met een grote kans op fouten. Als jij een visie van campagnes hebt van for-loops tot" - artisan_summary_suf: ", dan is dit de klasse voor jou." - artisan_introduction_pref: "We moeten meer levels bouwen! Mensen schreeuwen om meer inhoud, en er zijn ook maar zoveel levels dat wij kunnen maken. Momenteel is jouw werkplaats level een; onze level editor wordt zelfs door ons amper gebruikt, dus wees voorzichtig. Indien je een visie hebt van een campagne, gaande van for-loops tot" - artisan_introduction_suf: ", dan is deze klasse waarschijnlijk iets voor jou." - artisan_attribute_1: "Enige ervaring in het maken van vergelijkbare inhoud. Bijvoorbeeld ervaring in het gebruiken van Blizzard's level editor. Maar dit is niet vereist!" - artisan_attribute_2: "Tot in het detail testen en opnieuw proberen staat voor jou gelijk aan plezier. Om goede levels te maken, moet je het door anderen laten spelen en bereid zijn om een hele boel aan te passen." - artisan_attribute_3: "Momenteel heb je nog veel geduld nodig, doordat onze editor nog vrij ruw is en op je zenuwen kan werken. Samenwerken met een Avonturier kan jou ook veel helpen." - artisan_join_desc: "Gebruik de Level Editor min of meer in deze volgorde:" - artisan_join_step1: "Lees de documentatie." - artisan_join_step2: "Maak een nieuw level en bestudeer reeds bestaande levels." - artisan_join_step3: "Praat met ons in ons publieke (Engelstalige) HipChat kanaal voor hulp. (optioneel)" - artisan_join_step4: "Maak een bericht over jouw level op ons forum voor feedback." - more_about_artisan: "Leer meer over hoe je een Creatieve Ambachtsman kan worden." - artisan_subscribe_desc: "Ontvang e-mails met nieuws over de Level Editor." - adventurer_summary: "Laten we duidelijk zijn over je rol: jij bent de tank. Jij krijgt de zware klappen te verduren. We hebben mensen nodig om spiksplinternieuwe levels te proberen en te kijken hoe deze beter kunnen. Je zult veel afzien, want het maken van een goede game is een lang proces en niemand doet het de eerste keer goed. Als jij dit kan verduren en een hoog uihoudingsvermogen hebt, dan is dit de klasse voor jou." - adventurer_introduction: "Laten we duidelijk zijn over je rol: jij bent de tank. Jij krijgt de zware klappen te verduren. We hebben mensen nodig om spiksplinternieuwe levels uit te proberen en te kijken hoe deze beter kunnen. Je zult veel afzien.Het maken van een goede game is een lang proces en niemand doet het de eerste keer goed. Als jij dit kan verduren en een hoog uihoudingsvermogen hebt, dan is dit de klasse voor jou." - adventurer_attribute_1: "Een wil om te leren. Jij wilt leren hoe je programmeert en wij willen het jou leren. Je zal overigens zelf het meeste leren doen." - adventurer_attribute_2: "Charismatisch. Wees netjes maar duidelijk over wat er beter kan en geef suggesties over hoe het beter kan." - adventurer_join_pref: "Werk samen met een Ambachtsman of recruteer er een, of tik het veld hieronder aan om e-mails te ontvangen wanneer er nieuwe levels zijn om te testen. We zullen ook berichten over levels die beoordeeld moeten worden op onze netwerken zoals" - adventurer_forum_url: "ons forum" - adventurer_join_suf: "dus als je liever op deze manier wordt geïnformeerd, schrijf je daar in!" - more_about_adventurer: "Leer meer over hoe je een Dappere Avonturier kunt worden." - adventurer_subscribe_desc: "Ontvang e-mails wanneer er nieuwe levels zijn die getest moeten worden." - scribe_summary_pref: "CodeCombat is meer dan slechts een aantal levels, het zal ook een bron van kennis zijn die spelers kunnen nakijken. Op die manier zal een Ambachtsman een link kunnen geven naar een artikel dat past bij een level. Net zoiets als het " - scribe_summary_suf: " heeft gebouwd. Als jij het leuk vindt programmeerconcepten uit te leggen, dan is deze klasse iets voor jou." - scribe_introduction_pref: "CodeCombat is meer dan slechts een aantal levels, het zal ook een bron van kennis zijn en een wiki met programmeerconcepten waar levels op in kunnen gaan. Op die manier zal niet elke Ambachtsman in detail hoeven uit te leggen wat een vergelijkingsoperator is, maar een link kunnen geven naar een artikel die deze informatie al verduidelijkt voor speler. Net zoiets als het " - scribe_introduction_url_mozilla: "Mozilla Developer Network" - scribe_introduction_suf: " heeft gebouwd. Als jij het leuk vindt om programmeerconcepten uit te leggen in Markdown-vorm, dan is deze klasse wellicht iets voor jou." - scribe_attribute_1: "Taalvaardigheid is praktisch alles wat je nodig hebt. Je moet niet enkel bedreven zijn in grammatica en spelling, maar ook moeilijke ideeën kunnen overbrengen aan anderen." - contact_us_url: "Contacteer ons" - scribe_join_description: "vertel ons wat over jezelf, je ervaring met programmeren en over wat voor soort dingen je graag zou schrijven. Verder zien we wel!" - more_about_scribe: "Leer meer over het worden van een ijverige Klerk." - scribe_subscribe_desc: "Ontvang e-mails met aankondigingen over het schrijven van artikelen." - diplomat_summary: "Er is grote interesse voor CodeCombat in landen waar geen Engels wordt gesproken! We zijn op zoek naar vertalers die tijd willen spenderen aan het vertalen van de site's corpus aan woorden zodat CodeCombat zo snel mogelijk toegankelijk wordt voor de hele wereld. Als jij wilt helpen om CodeCombat internationaal maken, dan is dit de klasse voor jou." - diplomat_introduction_pref: "Dus, als er iets is wat we geleerd hebben van de " - diplomat_launch_url: "release in oktober" - diplomat_introduction_suf: "dan is het wel dat er een enorme belangstelling is voor CodeCombat in andere landen, vooral Brazilië! We zijn een groep van vertalers aan het creëren dat ijverig de ene set woorden in de andere omzet om CodeCombat zo toegankelijk mogelijk te maken in de hele wereld. Als jij het leuk vindt glimpsen op te vangen van aankomende content en deze levels zo snel mogelijk naar je landgenoten te krijgen, dan is dit de klasse voor jou." - diplomat_attribute_1: "Vloeiend Engels en de taal waar naar je wilt vertalen kunnen spreken. Wanneer je moeilijke ideeën wilt overbrengen, is het belangrijk beide talen goed te begrijpen!" - diplomat_join_pref_github: "Vind van jouw taal het locale bestand " - diplomat_github_url: "op GitHub" - diplomat_join_suf_github: ", edit het online, en submit een pull request. Daarnaast kun je hieronder aanvinken als je up-to-date wilt worden gehouden met nieuwe internationalisatie-ontwikkelingen." - more_about_diplomat: "Leer meer over het worden van een geweldige Diplomaat" - diplomat_subscribe_desc: "Ontvang e-mails over i18n ontwikkelingen en levels om te vertalen." - ambassador_summary: "We proberen een gemeenschap te bouwen en elke gemeenschap heeft een supportteam nodig wanneer er problemen zijn. We hebben chats, e-mails en sociale netwerken zodat onze gebruikers het spel kunnen leren kennen. Als jij mensen wilt helpen betrokken te raken, plezier te hebben en wat te leren programmeren, dan is dit wellicht de klasse voor jou." - ambassador_introduction: "We zijn een gemeenschap aan het uitbouwen, en jij maakt er deel van uit. We hebben Olark chatkamers, emails, en sociale netwerken met veel andere mensen waarmee je kan praten en hulp aan kan vragen over het spel of om bij te leren. Als jij mensen wil helpen en te werken nabij de hartslag van CodeCombat in het bijsturen van onze toekomstvisie, dan is dit de geknipte klasse voor jou!" - ambassador_attribute_1: "Communicatieskills. Problemen die spelers hebben kunnen identificeren en ze helpen deze op te lossen. Verder zul je ook de rest van ons geïnformeerd houden over wat de spelers zeggen, wat ze leuk vinden, wat ze minder vinden en waar er meer van moet zijn!" - ambassador_join_desc: "vertel ons wat over jezelf, wat je hebt gedaan en wat je graag zou doen. We zien verder wel!" - ambassador_join_note_strong: "Opmerking" - ambassador_join_note_desc: "Een van onze topprioriteiten is om een multiplayer te bouwen waar spelers die moeite hebben een level op te lossen een tovenaar met een hoger level kunnen oproepen om te helpen. Dit zal een goede manier zijn voor ambassadeurs om hun ding te doen. We houden je op de hoogte!" - more_about_ambassador: "Leer meer over het worden van een behulpzame Ambassadeur" - ambassador_subscribe_desc: "Ontvang e-mails met updates over ondersteuning en multiplayer-ontwikkelingen." - changes_auto_save: "Veranderingen worden automatisch opgeslagen wanneer je het vierkantje aan- of afvinkt." - diligent_scribes: "Onze ijverige Klerks:" - powerful_archmages: "Onze machtige Tovenaars:" - creative_artisans: "Onze creatieve Ambachtslieden:" - brave_adventurers: "Onze dappere Avonturiers:" - translating_diplomats: "Onze vertalende Diplomaten:" - helpful_ambassadors: "Onze behulpzame Ambassadeurs:" - - classes: - archmage_title: "Tovenaar" - archmage_title_description: "(Programmeur)" - artisan_title: "Ambachtsman" - artisan_title_description: "(Level Bouwer)" - adventurer_title: "Avonturier" - adventurer_title_description: "(Level Tester)" - scribe_title: "Klerk" - scribe_title_description: "(Redacteur)" - diplomat_title: "Diplomaat" - diplomat_title_description: "(Vertaler)" - ambassador_title: "Ambassadeur" - ambassador_title_description: "(Ondersteuning)" - - ladder: - please_login: "Log alstublieft eerst in voordat u een ladderspel speelt." - my_matches: "Mijn Wedstrijden" - simulate: "Simuleer" - simulation_explanation: "Door spellen te simuleren kan je zelf sneller beoordeeld worden!" - simulate_games: "Simuleer spellen!" - simulate_all: "RESET EN SIMULEER SPELLEN" - games_simulated_by: "Door jou gesimuleerde spellen:" - games_simulated_for: "Voor jou gesimuleerde spellen:" - games_simulated: "Spellen gesimuleerd" - games_played: "Spellen gespeeld" - ratio: "Verhouding" - leaderboard: "Leaderboard" - battle_as: "Vecht als " - summary_your: "Jouw " - summary_matches: "Wedstrijden - " - summary_wins: " Overwinningen, " - summary_losses: " Nederlagen" - rank_no_code: "Geen nieuwe code om te Beoordelen!" - rank_my_game: "Beoordeel mijn spel!" - rank_submitting: "Verzenden..." - rank_submitted: "Verzonden voor Beoordeling" - rank_failed: "Beoordeling mislukt" - rank_being_ranked: "Spel wordt Beoordeeld" -# rank_last_submitted: "submitted " -# help_simulate: "Help simulate games?" - code_being_simulated: "Uw nieuwe code wordt gesimuleerd door andere spelers om te beoordelen. Dit wordt vernieuwd zodra nieuwe matches binnenkomen." - no_ranked_matches_pre: "Geen beoordeelde wedstrijden voor het" - no_ranked_matches_post: " team! Speel tegen enkele tegenstanders en kom terug hier om uw spel te laten beoordelen." - choose_opponent: "Kies een tegenstander" -# select_your_language: "Select your language!" - tutorial_play: "Speel de Tutorial" - tutorial_recommended: "Aanbevolen als je nog niet eerder hebt gespeeld" - tutorial_skip: "Sla Tutorial over" - tutorial_not_sure: "Niet zeker wat er aan de hand is?" - tutorial_play_first: "Speel eerst de Tutorial." - simple_ai: "Simpele AI" - warmup: "Opwarming" - vs: "tegen" - friends_playing: "Spelende Vrienden" -# log_in_for_friends: "Log in to play with your friends!" - social_connect_blurb: "Koppel je sociaal netwerk om tegen je vrienden te spelen!" - invite_friends_to_battle: "Nodig je vrienden uit om deel te nemen aan het gevecht!" - fight: "Aanvallen!" - watch_victory: "Aanschouw je overwinning!" - defeat_the: "Versla de" -# tournament_ends: "Tournament ends" -# tournament_ended: "Tournament ended" -# tournament_rules: "Tournament Rules" -# tournament_blurb: "Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details" -# tournament_blurb_criss_cross: "Win bids, construct paths, outwit opponents, grab gems, and upgrade your career in our Criss-Cross tournament! Check out the details" -# tournament_blurb_blog: "on our blog" -# rules: "Rules" -# winners: "Winners" - -# ladder_prizes: -# title: "Tournament Prizes" -# blurb_1: "These prizes will be awarded according to" -# blurb_2: "the tournament rules" -# blurb_3: "to the top human and ogre players." -# blurb_4: "Two teams means double the prizes!" -# blurb_5: "(There will be two first place winners, two second-place winners, etc.)" -# rank: "Rank" -# prizes: "Prizes" -# total_value: "Total Value" -# in_cash: "in cash" -# custom_wizard: "Custom CodeCombat Wizard" -# custom_avatar: "Custom CodeCombat avatar" -# heap: "for six months of \"Startup\" access" -# credits: "credits" -# one_month_coupon: "coupon: choose either Rails or HTML" -# one_month_discount: "discount, 30% off: choose either Rails or HTML" -# license: "license" -# oreilly: "ebook of your choice" - - loading_error: - could_not_load: "Fout bij het laden van de server" - connection_failure: "Verbinding mislukt." - unauthorized: "Je moet ingelogd zijn. Heb je de cookies uitgeschakeld?" - forbidden: "Je hebt hier geen toestemming voor." - not_found: "Niet gevonden." - not_allowed: "Methode niet toegestaan." - timeout: "Server timeout." - conflict: "Conflict van resources" - bad_input: "Slechte input." - server_error: "Fout van de server." - unknown: "Onbekende fout." - - resources: -# sessions: "Sessions" - your_sessions: "Jouw sessies." - level: "Level" - social_network_apis: "Sociale netwerk APIs" - facebook_status: "Facebook Status" - facebook_friends: "Facebook vrienden" - facebook_friend_sessions: "Sessies van Facebook vrienden" - gplus_friends: "G+ vrienden" - gplus_friend_sessions: "Sessies van G+ vrienden" - leaderboard: "Scorebord" - user_schema: "Gebruikersschema" - user_profile: "Gebruikersprofiel" - patches: "Patches" -# patched_model: "Source Document" - model: "Model" - system: "Systeem" -# systems: "Systems" - component: "Component" - components: "Componenten" - thang: "Thang" - thangs: "Thangs" - level_session: "Jouw Sessie" - opponent_session: "Sessie van tegenstander" - article: "Artikel" - user_names: "Gebruikersnamen" -# thang_names: "Thang Names" - files: "Bestanden" - top_simulators: "Top Simulatoren" -# source_document: "Source Document" -# document: "Document" -# sprite_sheet: "Sprite Sheet" -# employers: "Employers" -# candidates: "Candidates" -# candidate_sessions: "Candidate Sessions" -# user_remark: "User Remark" -# user_remarks: "User Remarks" -# versions: "Versions" -# items: "Items" -# wizard: "Wizard" -# achievement: "Achievement" -# clas: "CLAs" -# play_counts: "Play Counts" - -# delta: -# added: "Added" -# modified: "Modified" -# deleted: "Deleted" -# moved_index: "Moved Index" -# text_diff: "Text Diff" -# merge_conflict_with: "MERGE CONFLICT WITH" -# no_changes: "No Changes" - -# user: -# stats: "Stats" -# singleplayer_title: "Singleplayer Levels" -# multiplayer_title: "Multiplayer Levels" -# achievements_title: "Achievements" -# last_played: "Last Played" -# status: "Status" -# status_completed: "Completed" -# status_unfinished: "Unfinished" -# no_singleplayer: "No Singleplayer games played yet." -# no_multiplayer: "No Multiplayer games played yet." -# no_achievements: "No Achievements earned yet." -# favorite_prefix: "Favorite language is " -# favorite_postfix: "." - -# achievements: -# last_earned: "Last Earned" -# amount_achieved: "Amount" -# achievement: "Achievement" -# category_contributor: "Contributor" -# category_miscellaneous: "Miscellaneous" -# category_levels: "Levels" -# category_undefined: "Uncategorized" -# current_xp_prefix: "" -# current_xp_postfix: " in total" -# new_xp_prefix: "" -# new_xp_postfix: " earned" -# left_xp_prefix: "" -# left_xp_infix: " until level " -# left_xp_postfix: "" - -# account: -# recently_played: "Recently Played" -# no_recent_games: "No games played during the past two weeks." diff --git a/app/locale/nn.coffee b/app/locale/nn.coffee index bcf5762e7..20586ece2 100644 --- a/app/locale/nn.coffee +++ b/app/locale/nn.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/no.coffee b/app/locale/no.coffee index f5333d761..0faf5283a 100644 --- a/app/locale/no.coffee +++ b/app/locale/no.coffee @@ -53,7 +53,7 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # stats: "Stats" # code: "Code" admin: "Administrator" - home: "Hjem" + home: "Hovedside" contribute: "Bidra" legal: "Juridisk" about: "Om" @@ -70,10 +70,10 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # cla_agree: "I AGREE" login: - sign_up: "Lag konto" - log_in: "Logg Inn" + sign_up: "Lag ny konto" + log_in: "Logg inn" # logging_in: "Logging In" - log_out: "Logg Ut" + log_out: "Logg ut" recover: "Gjenåpne konto" # recover: @@ -82,18 +82,18 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr signup: # create_account_title: "Create Account to Save Progress" - description: "Det er gratis. Trenger bare noen få avklaringer, så er du klar:" - email_announcements: "Motta kunngjøringer på epost" - coppa: "13+ eller ikke fra USA" + description: "Det er gratis. Trenger bare litt informasjon så er du klar:" + email_announcements: "Motta nyhetsbrev på epost" + coppa: "over 13 år eller bor ikke i USA" coppa_why: "(Hvorfor?)" - creating: "Oppretter Konto..." + creating: "Oppretter konto..." sign_up: "Registrer deg" log_in: "Logg inn med passord" # social_signup: "Or, you can sign up through Facebook or G+:" # required: "You need to log in before you can go that way." home: - slogan: "Lær å Kode ved å Spille et Spill" + slogan: "Lær å kode ved å spille et spill" no_ie: "CodeCombat kjører ikke på IE8 eller eldre. Beklager!" no_mobile: "CodeCombat ble ikke designet for mobile enheter, og vil muligens ikke virke!" play: "Spill" @@ -111,18 +111,20 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # io_blurb: "Simple but obscure." play: - choose_your_level: "Velg Ditt Nivå" - adventurer_prefix: "Du kan hoppe til hvilket som helts nivå under, eller diskutere nivåene på" + choose_your_level: "Velg brett" + adventurer_prefix: "Du kan velge hvilket som helst brett under, eller diskutere brettene på " adventurer_forum: "Eventyrerforumet" adventurer_suffix: "." - campaign_beginner: "Begynner Felttog" + campaign_beginner: "Nybegynner brett" campaign_beginner_description: "... hvor du lærer trolldommen bak programmering." - campaign_dev: "Tilfeldig Vanskeligere Nivåer" - campaign_dev_description: "... hvor du lærer grensesnittet mens du stadig gjør mer vanskeligere utfordringer." - campaign_multiplayer: "Multispiller Arenaer" + campaign_dev: "Vanskeligere brett (tilfeldige)" + campaign_dev_description: "... hvor du lærer hvordan du bruker skjermbildene mens du stadig løser mer vanskelige utfordringer." + campaign_multiplayer: "Flerspiller brett (arenaer)" campaign_multiplayer_description: "... hvor du spiller direkte mot andre spillere." - campaign_player_created: "Spillerlaget" + campaign_player_created: "Brett laget av andre brukere" campaign_player_created_description: "... hvor du kjemper mot kreativiteten til en av dine medspillende Artisan Trollmenn." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Vanskelighetsgrad: " # play_as: "Play As" # spectate: "Spectate" @@ -131,21 +133,21 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr contact: contact_us: "Kontakt CodeCombat" - welcome: "Bra å høre fra deg! Bruk dette skjemaet for å sende oss en epost." + welcome: "Kontakt oss gjerne, men vi må ha meldingen på engelsk! Bruk dette skjemaet for å sende oss en epost." contribute_prefix: "Hvis du er interessert i å bidra, sjekk ut vår " contribute_page: "bidragsside" contribute_suffix: "!" - forum_prefix: "For allment tilgjengelige henvendelser, vennligst prøv " - forum_page: "forumet vårt" - forum_suffix: " i steden." - send: "Send Tilbakemelding" + forum_prefix: "Du kan også stille spørsmål i våre åpne " + forum_page: "diskusjonsgrupper" + forum_suffix: " om du ønsker det. For å få flest mulig svar er det lurt å skrive på engelsk" + send: "Send tilbakemelding" # contact_candidate: "Contact Candidate" # recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 15% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns." diplomat_suggestion: title: "Hjelp med oversettelse av CodeCombat!" sub_heading: "Vi trenger dine språkkunnskaper." - pitch_body: "Vi utvikler CodeCombat på engelsk, men vi vi har allerede spillere over hele verden. Mange av dem vil spille på Norsk, men snakker ikke Engelsk, så hvis du kan snakke begge språk, vennligst vurder å meld deg på som Diplomat og hjelp å oversette både CodeCombat web siden og alle nivåene til Norsk." + pitch_body: "Vi utvikler CodeCombat på engelsk, men vi vi har allerede spillere over hele verden. Mange av dem vil spille på norsk, men snakker ikke engelsk, så hvis du kan snakke begge språk, vennligst vurder å meld deg på som Diplomat og hjelp å oversette både CodeCombat web siden og alle nivåene til norsk." missing_translations: "Inntil vi har oversatt alt til norsk vil du se engelsk hvor norsk ikke er tilgjengelig." learn_more: "Lær mer om hvordan det er å være en Diplomat" subscribe_as_diplomat: "Meld deg på som Diplomat" @@ -169,7 +171,7 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr account_settings: title: "Kontoinnstillinger" not_logged_in: "Logg inn eller opprett en konto for å endre innstillingene dine." - autosave: "Endringer Lagres Automatisk" + autosave: "Endringer lagres automatisk" me_tab: "Meg" picture_tab: "Bilde" # upload_picture: "Upload a picture" @@ -177,8 +179,8 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr password_tab: "Passord" emails_tab: "Epost" # admin: "Admin" - wizard_color: "Farge på trollmannens Klær" - new_password: "Nytt Passord" + wizard_color: "Farge på trollmannens klær" + new_password: "Nytt passord" new_password_verify: "Verifiser" email_subscriptions: "Epostabonnement" # email_subscriptions_none: "No Email Subscriptions." @@ -191,13 +193,13 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # email_news: "News" # email_recruit_notes: "Job Opportunities" # email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job." - contributor_emails: "Bidragsyterklasse Epost" - contribute_prefix: "Vi leter etter folk som vil delta på festen vår! Sjekk ut " + contributor_emails: "Bidragsyterklasse epost" + contribute_prefix: "Vi leter etter folk som vil delta på kodefesten vår! Sjekk ut " contribute_page: "bidragssiden" contribute_suffix: " for å finne ut mer." - email_toggle: "Vis Alle" - error_saving: "Lagring Feilet" - saved: "Endringer Lagret" + email_toggle: "Vis alle" + error_saving: "Lagring feilet" + saved: "Endringer lagret" password_mismatch: "Passordene er ikke like." # password_repeat: "Please repeat your password." # job_profile: "Job Profile" @@ -357,8 +359,8 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr play_level: done: "Ferdig" - customize_wizard: "Spesiallag Trollmann" - home: "Hjem" + customize_wizard: "Tilpass trollmann" + home: "Hovedside" # stop: "Stop" # game_menu: "Game Menu" guide: "Guide" @@ -379,21 +381,21 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr victory_sign_up_poke: "Vil du ha siste nytt på epost? Opprett en gratis konto, så vil vi holde deg oppdatert!" victory_rate_the_level: "Bedøm nivået: " # victory_return_to_ladder: "Return to Ladder" - victory_play_next_level: "Spill Neste Nivå" - victory_go_home: "Gå Hjem" + victory_play_next_level: "Spill neste nivå" + victory_go_home: "Gå til Hovedsiden" victory_review: "Fortell oss mer!" victory_hour_of_code_done: "Er du ferdig?" victory_hour_of_code_done_yes: "Ja, jeg er ferdig med min time i koding!" guide_title: "Guide" tome_minion_spells: "Din Minions' Trylleformularer" - tome_read_only_spells: "Kun-Lesbare Trylleformularer" - tome_other_units: "Andre Enheter" + tome_read_only_spells: "Kun-lesbare trylleformularer" + tome_other_units: "Andre enheter" tome_cast_button_castable: "Kast" tome_cast_button_casting: "Kaster" - tome_cast_button_cast: "Kast Trylleformular" + tome_cast_button_cast: "Kast trylleformular" tome_select_spell: "Velg et trylleformular" tome_select_a_thang: "Velg noe for å " - tome_available_spells: "Tilgjenglige Trylleformularer" + tome_available_spells: "Tilgjenglige trylleformularer" hud_continue: "Fortsett (trykk shift+mellomrom)" # spell_saved: "Spell Saved" # skip_tutorial: "Skip (esc)" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/pl.coffee b/app/locale/pl.coffee index befbc7ca9..6f5e8d568 100644 --- a/app/locale/pl.coffee +++ b/app/locale/pl.coffee @@ -44,14 +44,14 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish nav: play: "Graj" -# community: "Community" + community: "Społeczność" editor: "Edytor" blog: "Blog" forum: "Forum" -# account: "Account" -# profile: "Profile" -# stats: "Stats" -# code: "Code" + account: "Konto" + profile: "Profil" + stats: "Statystyki" + code: "Kod" admin: "Admin" home: "Główna" contribute: "Współpraca" @@ -90,7 +90,7 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish sign_up: "Zarejestruj" log_in: "zaloguj się używając hasła" social_signup: "lub zaloguj się używając konta Facebook lub G+:" -# required: "You need to log in before you can go that way." + required: "Musisz się zalogować zanim przejdziesz dalej." home: slogan: "Naucz się programowania grając" @@ -123,10 +123,12 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish campaign_multiplayer_description: "... w których konkurujesz z innymi graczami." campaign_player_created: "Stworzone przez graczy" campaign_player_created_description: "... w których walczysz przeciwko dziełom Czarodziejów Rękodzielnictwa" +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Poziom trudności: " play_as: "Graj jako " spectate: "Oglądaj" -# players: "players" + players: "graczy" # hours_played: "hours played" contact: @@ -153,13 +155,13 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish wizard_settings: title: "Ustawienia czarodzieja" customize_avatar: "Personalizuj swój awatar" -# active: "Active" -# color: "Color" -# group: "Group" + active: "Aktywuj" + color: "Kolor" + group: "Rodzaj" clothes: "Ubrania" trim: "Dodatki" cloud: "Chmura" -# team: "Team" + team: "Drużyna" spell: "Zaklęcie" boots: "Buty" hue: "Odcień" @@ -172,7 +174,7 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish autosave: "Zmiany zapisują się automatycznie" me_tab: "Ja" picture_tab: "Zdjęcie" -# upload_picture: "Upload a picture" + upload_picture: "Wgraj zdjęcie" wizard_tab: "Czarodziej" password_tab: "Hasło" emails_tab: "Powiadomienia" @@ -210,7 +212,7 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish settings: "Ustawienia" edit_profile: "Edytuj Profil" # done_editing: "Done Editing" - profile_for_prefix: "Profil" + profile_for_prefix: "Profil " profile_for_suffix: "" # featured: "Featured" # not_featured: "Not Featured" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish options: # general_options: "General Options" +# volume_label: "Volume" music_label: "Muzyka" music_description: "Wł/Wył muzykę w tle." autorun_label: "Autostart" @@ -851,7 +854,7 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish no_ranked_matches_pre: "Brak ocenionych pojedynków dla drużyny " no_ranked_matches_post: " ! Zagraj przeciwko kilku oponentom i wróc tutaj, aby uzyskać ocenę gry." choose_opponent: "Wybierz przeciwnika" -# select_your_language: "Select your language!" + select_your_language: "Wybierz swój język!" tutorial_play: "Rozegraj samouczek" tutorial_recommended: "Zalecane, jeśli wcześniej nie grałeś" tutorial_skip: "Pomiń samouczek" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/pt-BR.coffee b/app/locale/pt-BR.coffee index 76e1efe86..6ffe3a56c 100644 --- a/app/locale/pt-BR.coffee +++ b/app/locale/pt-BR.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "português do Brasil", englishDescription: campaign_multiplayer_description: "... nas quais você programará cara-a-cara contra outros jogadores." campaign_player_created: "Criados por Jogadores" campaign_player_created_description: "... nos quais você batalhará contra a criatividade dos seus companheiros feiticeiros Artesãos." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Dificuldade: " play_as: "Jogar Como " spectate: "Assistir" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "português do Brasil", englishDescription: options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "português do Brasil", englishDescription: # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/pt-PT.coffee b/app/locale/pt-PT.coffee index 83049398d..dcf88281f 100644 --- a/app/locale/pt-PT.coffee +++ b/app/locale/pt-PT.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription: campaign_multiplayer_description: "... onde programa frente-a-frente contra outros jogadores." campaign_player_created: "Criados por Jogadores" campaign_player_created_description: "... onde combate contra a criatividade dos seus colegas Feiticeiros Artesãos." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Dificuldade: " play_as: "Jogar Como" spectate: "Espectar" @@ -383,7 +385,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription: victory_go_home: "Ir para o Início" victory_review: "Conte-nos mais!" victory_hour_of_code_done: "Terminou?" - victory_hour_of_code_done_yes: "Sim, terminei a minha Hora de Código™!" + victory_hour_of_code_done_yes: "Sim, terminei a minha Hora do Código™!" guide_title: "Guia" tome_minion_spells: "Feitiços dos Seus Minions" tome_read_only_spells: "Feitiços Apenas de Leitura" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription: options: general_options: "Opções Gerais" +# volume_label: "Volume" music_label: "Música" music_description: "Ative ou desative a música de fundo." autorun_label: "Executar Automaticamente" @@ -655,7 +658,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription: why_ending: "E vejam só, é gratuito. " why_ending_url: "Comece a enfeitiçar agora!" george_description: "CEO, homem de negócios, designer da web, designer de jogos e campeão dos programadores iniciantes de todo o lado." - scott_description: "Programador extraordinário, arquiteto de software, feiticeiro da cozinha e mestre das finanças. O Scott é sensato." + scott_description: "Programador extraordinário, arquiteto de software, feiticeiro da cozinha e mestre das finanças. O Scott é o sensato." nick_description: "Feiticeiro da programção, mago da motivação excêntrico e experimentador de pernas para o ar. O Nick pode fazer qualquer coisa e escolhe construir o CodeCombat." jeremy_description: "Mago do suporte ao cliente, testador do uso e organizador da comunidade; provavelmente já falou com o Jeremy." michael_description: "Programador, administrador do sistema e técnico de graduação prodígio, o Michael é a pessoa que mantém os nossos servidores online." @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription: achievement: "Conquista" clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" delta: added: "Adicionados/as" diff --git a/app/locale/pt.coffee b/app/locale/pt.coffee deleted file mode 100644 index 2c9518552..000000000 --- a/app/locale/pt.coffee +++ /dev/null @@ -1,998 +0,0 @@ -module.exports = nativeDescription: "português", englishDescription: "Portuguese", translation: - common: - loading: "Carregando..." -# saving: "Saving..." - sending: "Enviando..." -# send: "Send" - cancel: "Cancelar" -# save: "Save" -# publish: "Publish" -# create: "Create" - delay_1_sec: "1 segundo" - delay_3_sec: "3 segundos" - delay_5_sec: "5 segundos" - manual: "Manual" -# fork: "Fork" - play: "Jogar" -# retry: "Retry" -# watch: "Watch" -# unwatch: "Unwatch" -# submit_patch: "Submit Patch" - -# units: -# second: "second" -# seconds: "seconds" -# minute: "minute" -# minutes: "minutes" -# hour: "hour" -# hours: "hours" -# day: "day" -# days: "days" -# week: "week" -# weeks: "weeks" -# month: "month" -# months: "months" -# year: "year" -# years: "years" - - modal: - close: "Fechar" - okay: "Ok" - - not_found: - page_not_found: "Página não encontrada" - - nav: - play: "Jogar" -# community: "Community" - editor: "Editor" - blog: "Blog" - forum: "Fórum" -# account: "Account" -# profile: "Profile" -# stats: "Stats" -# code: "Code" - admin: "Administrador" - home: "Início" - contribute: "Contribuir" - legal: "Legal" - about: "Sobre" - contact: "Contate-nos" - twitter_follow: "Seguir" -# employers: "Employers" - -# versions: -# save_version_title: "Save New Version" -# new_major_version: "New Major Version" -# cla_prefix: "To save changes, first you must agree to our" -# cla_url: "CLA" -# cla_suffix: "." -# cla_agree: "I AGREE" - - login: - sign_up: "Criar conta" - log_in: "Entrar" -# logging_in: "Logging In" - log_out: "Sair" - recover: "recuperar sua conta" - -# recover: -# recover_account_title: "Recover Account" -# send_password: "Send Recovery Password" - - signup: -# create_account_title: "Create Account to Save Progress" - description: "É grátis. Precisamos apenas de umas coisinhas e você estará pronto para seguir:" - email_announcements: "Receber notícias por email." - coppa: "acima de 13 anos ou não estadunidense" - coppa_why: "(Por quê?)" - creating: "Criando a nova conta..." - sign_up: "Criar conta" - log_in: "Entre com a senha" -# social_signup: "Or, you can sign up through Facebook or G+:" -# required: "You need to log in before you can go that way." - - home: - slogan: "Aprenda a programar enquanto se diverte com um jogo." - no_ie: "CodeCombat não roda em versões mais antigas que o Internet Explorer 10. Desculpe!" - no_mobile: "CodeCombat não foi projetado para dispositivos móveis e pode não funcionar!" - play: "Jogar" -# old_browser: "Uh oh, your browser is too old to run CodeCombat. Sorry!" -# old_browser_suffix: "You can try anyway, but it probably won't work." -# campaign: "Campaign" -# for_beginners: "For Beginners" -# multiplayer: "Multiplayer" -# for_developers: "For Developers" -# javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers." -# python_blurb: "Simple yet powerful, Python is a great general purpose programming language." -# coffeescript_blurb: "Nicer JavaScript syntax." -# clojure_blurb: "A modern Lisp." -# lua_blurb: "Game scripting language." -# io_blurb: "Simple but obscure." - - play: - choose_your_level: "Escolha seu estágio" - adventurer_prefix: "Você pode ir para qualquer um dos estágios abaixo, ou discutir sobre eles no " - adventurer_forum: "Fórum do Aventureiro" - adventurer_suffix: "." - campaign_beginner: "Campanha Iniciante" - campaign_beginner_description: "... na qual você aprenderá a magia da programação." - campaign_dev: "Fases Difíceis Aleatórias" - campaign_dev_description: "... nas quais você aprenderá a interface enquanto faz algo um pouco mais difícil." - campaign_multiplayer: "Arenas Multijogador" - campaign_multiplayer_description: "... nas quais você programará cara-a-cara contra outros jogadores." - campaign_player_created: "Criados por Jogadores" - campaign_player_created_description: "... nos quais você batalhará contra a criatividade dos seus companheiros feiticeiros Artesãos." - level_difficulty: "Dificuldade: " -# play_as: "Play As" -# spectate: "Spectate" -# players: "players" -# hours_played: "hours played" - - contact: - contact_us: "Contate-nos" - welcome: "É bom escutar suas opiniões! Use este formulário para nos enviar um email." - contribute_prefix: "Se você se interessar em contribuir conosco, dê uma conferida na nossa " - contribute_page: "página de contribuição" - contribute_suffix: "!" - forum_prefix: "Para algo público, por favor acesse " - forum_page: "nosso fórum" - forum_suffix: " ao invés disso." - send: "Enviar opinião" -# contact_candidate: "Contact Candidate" -# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 15% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns." - - diplomat_suggestion: - title: "Ajude a traduzir o CodeCombat!" - sub_heading: "Nós precisamos de suas habilidades linguísticas." - pitch_body: "Desenvolvemos o CodeCombat em Inglês, mas já temos jogadores de todo o mundo. Muitos deles querem jogar em Português Brasileiro mas não falam Inglês, por isso, se você conhece os dois idiomas, por favor, considere inscrever-se para ser um Diplomata e ajudar a traduzir tanto o site do CodeCombat quanto todos os estágios para o Português Brasileiro." - missing_translations: "Até que possamos traduzir tudo para o Português Brasileiro, você lerá em Inglês quando a versão em Português Brasileiro ainda não estiver disponível." - learn_more: "Saiba mais sobre ser um Diplomata" - subscribe_as_diplomat: "Assinar como um Diplomata" - -# wizard_settings: -# title: "Wizard Settings" -# customize_avatar: "Customize Your Avatar" -# active: "Active" -# color: "Color" -# group: "Group" -# clothes: "Clothes" -# trim: "Trim" -# cloud: "Cloud" -# team: "Team" -# spell: "Spell" -# boots: "Boots" -# hue: "Hue" -# saturation: "Saturation" -# lightness: "Lightness" - - account_settings: - title: "Configurações da Conta" - not_logged_in: "Entre com seu usuário e senha ou crie uma conta para poder alterar suas configurações." - autosave: "As alterações serão salvas automaticamente." - me_tab: "Eu" - picture_tab: "Foto" -# upload_picture: "Upload a picture" - wizard_tab: "Feiticeiro" - password_tab: "Senha" - emails_tab: "Emails" -# admin: "Admin" - wizard_color: "Cor das Roupas do Feiticeiro" - new_password: "Nova Senha" - new_password_verify: "Confirmação" - email_subscriptions: "Assinaturas para Notícias por Email" -# email_subscriptions_none: "No Email Subscriptions." - email_announcements: "Notícias" - email_announcements_description: "Receba emails com as últimas notícias e desenvolvimentos do CodeCombat." -# email_notifications: "Notifications" -# email_notifications_summary: "Controls for personalized, automatic email notifications related to your CodeCombat activity." -# email_any_notes: "Any Notifications" -# email_any_notes_description: "Disable to stop all activity notification emails." -# email_news: "News" -# email_recruit_notes: "Job Opportunities" -# email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job." - contributor_emails: "Emails para as Classes de Contribuidores" - contribute_prefix: "Estamos procurando pessoas para se juntar à nossa turma! Confira a nossa " - contribute_page: "página de contribuição" - contribute_suffix: " para saber mais." - email_toggle: "Ativar todos" - error_saving: "Erro no salvamento" - saved: "Alterações Salvas" - password_mismatch: "As senhas não estão iguais" -# password_repeat: "Please repeat your password." -# job_profile: "Job Profile" -# job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks." -# job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job." -# sample_profile: "See a sample profile" -# view_profile: "View Your Profile" - - account_profile: -# settings: "Settings" -# edit_profile: "Edit Profile" -# done_editing: "Done Editing" - profile_for_prefix: "Perfil de " -# profile_for_suffix: "" -# featured: "Featured" -# not_featured: "Not Featured" -# looking_for: "Looking for:" -# last_updated: "Last updated:" -# contact: "Contact" -# active: "Looking for interview offers now" -# inactive: "Not looking for offers right now" -# complete: "complete" -# next: "Next" -# next_city: "city?" -# next_country: "pick your country." -# next_name: "name?" -# next_short_description: "write a short description." -# next_long_description: "describe your desired position." -# next_skills: "list at least five skills." -# next_work: "chronicle your work history." -# next_education: "recount your educational ordeals." -# next_projects: "show off up to three projects you've worked on." -# next_links: "add any personal or social links." -# next_photo: "add an optional professional photo." -# next_active: "mark yourself open to offers to show up in searches." -# example_blog: "Blog" -# example_personal_site: "Personal Site" -# links_header: "Personal Links" -# links_blurb: "Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog." -# links_name: "Link Name" -# links_name_help: "What are you linking to?" -# links_link_blurb: "Link URL" -# basics_header: "Update basic info" -# basics_active: "Open to Offers" -# basics_active_help: "Want interview offers right now?" -# basics_job_title: "Desired Job Title" -# basics_job_title_help: "What role are you looking for?" -# basics_city: "City" -# basics_city_help: "City you want to work in (or live in now)." -# basics_country: "Country" -# basics_country_help: "Country you want to work in (or live in now)." -# basics_visa: "US Work Status" -# basics_visa_help: "Are you authorized to work in the US, or do you need visa sponsorship? (If you live in Canada or Australia, mark authorized.)" -# basics_looking_for: "Looking For" -# basics_looking_for_full_time: "Full-time" -# basics_looking_for_part_time: "Part-time" -# basics_looking_for_remote: "Remote" -# basics_looking_for_contracting: "Contracting" -# basics_looking_for_internship: "Internship" -# basics_looking_for_help: "What kind of developer position do you want?" -# name_header: "Fill in your name" -# name_anonymous: "Anonymous Developer" -# name_help: "Name you want employers to see, like 'Nick Winter'." -# short_description_header: "Write a short description of yourself" -# short_description_blurb: "Add a tagline to help an employer quickly learn more about you." -# short_description: "Tagline" -# short_description_help: "Who are you, and what are you looking for? 140 characters max." -# skills_header: "Skills" -# skills_help: "Tag relevant developer skills in order of proficiency." -# long_description_header: "Describe your desired position" -# long_description_blurb: "Tell employers how awesome you are and what role you want." -# long_description: "Self Description" -# long_description_help: "Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max." -# work_experience: "Work Experience" -# work_header: "Chronicle your work history" -# work_years: "Years of Experience" -# work_years_help: "How many years of professional experience (getting paid) developing software do you have?" -# work_blurb: "List your relevant work experience, most recent first." -# work_employer: "Employer" -# work_employer_help: "Name of your employer." -# work_role: "Job Title" -# work_role_help: "What was your job title or role?" -# work_duration: "Duration" -# work_duration_help: "When did you hold this gig?" -# work_description: "Description" -# work_description_help: "What did you do there? (140 chars; optional)" -# education: "Education" -# education_header: "Recount your academic ordeals" -# education_blurb: "List your academic ordeals." -# education_school: "School" -# education_school_help: "Name of your school." -# education_degree: "Degree" -# education_degree_help: "What was your degree and field of study?" -# education_duration: "Dates" -# education_duration_help: "When?" -# education_description: "Description" -# education_description_help: "Highlight anything about this educational experience. (140 chars; optional)" -# our_notes: "CodeCombat's Notes" -# remarks: "Remarks" -# projects: "Projects" -# projects_header: "Add 3 projects" -# projects_header_2: "Projects (Top 3)" -# projects_blurb: "Highlight your projects to amaze employers." -# project_name: "Project Name" -# project_name_help: "What was the project called?" -# project_description: "Description" -# project_description_help: "Briefly describe the project." -# project_picture: "Picture" -# project_picture_help: "Upload a 230x115px or larger image showing off the project." -# project_link: "Link" -# project_link_help: "Link to the project." -# player_code: "Player Code" - -# employers: -# hire_developers_not_credentials: "Hire developers, not credentials." -# get_started: "Get Started" -# already_screened: "We've already technically screened all our candidates" -# filter_further: ", but you can also filter further:" -# filter_visa: "Visa" -# filter_visa_yes: "US Authorized" -# filter_visa_no: "Not Authorized" -# filter_education_top: "Top School" -# filter_education_other: "Other" -# filter_role_web_developer: "Web Developer" -# filter_role_software_developer: "Software Developer" -# filter_role_mobile_developer: "Mobile Developer" -# filter_experience: "Experience" -# filter_experience_senior: "Senior" -# filter_experience_junior: "Junior" -# filter_experience_recent_grad: "Recent Grad" -# filter_experience_student: "College Student" -# filter_results: "results" -# start_hiring: "Start hiring." -# reasons: "Three reasons you should hire through us:" -# everyone_looking: "Everyone here is looking for their next opportunity." -# everyone_looking_blurb: "Forget about 20% LinkedIn InMail response rates. Everyone that we list on this site wants to find their next position and will respond to your request for an introduction." -# weeding: "Sit back; we've done the weeding for you." -# weeding_blurb: "Every player that we list has been screened for technical ability. We also perform phone screens for select candidates and make notes on their profiles to save you time." -# pass_screen: "They will pass your technical screen." -# pass_screen_blurb: "Review each candidate's code before reaching out. One employer found that 5x as many of our devs passed their technical screen than hiring from Hacker News." -# make_hiring_easier: "Make my hiring easier, please." -# what: "What is CodeCombat?" -# what_blurb: "CodeCombat is a multiplayer browser programming game. Players write code to control their forces in battle against other developers. Our players have experience with all major tech stacks." -# cost: "How much do we charge?" -# cost_blurb: "We charge 15% of first year's salary and offer a 100% money back guarantee for 90 days. We don't charge for candidates who are already actively being interviewed at your company." -# candidate_name: "Name" -# candidate_location: "Location" -# candidate_looking_for: "Looking For" -# candidate_role: "Role" -# candidate_top_skills: "Top Skills" -# candidate_years_experience: "Yrs Exp" -# candidate_last_updated: "Last Updated" -# candidate_who: "Who" -# featured_developers: "Featured Developers" -# other_developers: "Other Developers" -# inactive_developers: "Inactive Developers" - - play_level: - done: "Pronto" - customize_wizard: "Personalize o feiticeiro" - home: "Início" -# stop: "Stop" -# game_menu: "Game Menu" - guide: "Guia" - restart: "Reiniciar" - goals: "Objetivos" -# success: "Success!" -# incomplete: "Incomplete" -# timed_out: "Ran out of time" -# failing: "Failing" - action_timeline: "Linha do Tempo das Ações" - click_to_select: "Clique em um personagem para selecioná-lo." - reload_title: "Recarregar Todo o Código?" - reload_really: "Você tem certeza que quer reiniciar o estágio?" - reload_confirm: "Recarregar Tudo" -# victory_title_prefix: "" - victory_title_suffix: " Completado!" - victory_sign_up: "Assine para atualizações" - victory_sign_up_poke: "Quer receber as últimas novidades por email? Crie uma conta grátis e nós o manteremos informado!" - victory_rate_the_level: "Avalie o estágio: " -# victory_return_to_ladder: "Return to Ladder" - victory_play_next_level: "Jogar o próximo estágio" - victory_go_home: "Ir à página inicial" - victory_review: "Diga-nos mais!" - victory_hour_of_code_done: "Terminou?" - victory_hour_of_code_done_yes: "Sim, eu terminei minha Hora da Programação!" - guide_title: "Guia" - tome_minion_spells: "Magias dos seus subordinados" - tome_read_only_spells: "Magias não editáveis" - tome_other_units: "Outras Unidades" - tome_cast_button_castable: "Lançar" - tome_cast_button_casting: "Conjurando" - tome_cast_button_cast: "Feitiço" - tome_select_spell: "Selecione um Feitiço" - tome_select_a_thang: "Selecione alguém para " - tome_available_spells: "Feitiços Disponíveis" - hud_continue: "Continue (tecle Shift+Space)" -# spell_saved: "Spell Saved" -# skip_tutorial: "Skip (esc)" -# keyboard_shortcuts: "Key Shortcuts" -# loading_ready: "Ready!" -# tip_insert_positions: "Shift+Click a point on the map to insert it into the spell editor." -# tip_toggle_play: "Toggle play/paused with Ctrl+P." -# tip_scrub_shortcut: "Ctrl+[ and Ctrl+] rewind and fast-forward." -# tip_guide_exists: "Click the guide at the top of the page for useful info." -# tip_open_source: "CodeCombat is 100% open source!" -# tip_beta_launch: "CodeCombat launched its beta in October, 2013." -# tip_js_beginning: "JavaScript is just the beginning." -# tip_think_solution: "Think of the solution, not the problem." -# tip_theory_practice: "In theory, there is no difference between theory and practice. But in practice, there is. - Yogi Berra" -# tip_error_free: "There are two ways to write error-free programs; only the third one works. - Alan Perlis" -# tip_debugging_program: "If debugging is the process of removing bugs, then programming must be the process of putting them in. - Edsger W. Dijkstra" -# tip_forums: "Head over to the forums and tell us what you think!" -# tip_baby_coders: "In the future, even babies will be Archmages." -# tip_morale_improves: "Loading will continue until morale improves." -# tip_all_species: "We believe in equal opportunities to learn programming for all species." -# tip_reticulating: "Reticulating spines." -# tip_harry: "Yer a Wizard, " -# tip_great_responsibility: "With great coding skill comes great debug responsibility." -# tip_munchkin: "If you don't eat your vegetables, a munchkin will come after you while you're asleep." -# tip_binary: "There are only 10 types of people in the world: those who understand binary, and those who don't." -# tip_commitment_yoda: "A programmer must have the deepest commitment, the most serious mind. ~ Yoda" -# tip_no_try: "Do. Or do not. There is no try. - Yoda" -# tip_patience: "Patience you must have, young Padawan. - Yoda" -# tip_documented_bug: "A documented bug is not a bug; it is a feature." -# tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" -# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" -# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" -# tip_hardware_problem: "Q: How many programmers does it take to change a light bulb? A: None, it's a hardware problem." -# time_current: "Now:" -# time_total: "Max:" -# time_goto: "Go to:" -# infinite_loop_try_again: "Try Again" -# infinite_loop_reset_level: "Reset Level" -# infinite_loop_comment_out: "Comment Out My Code" - - game_menu: -# inventory_tab: "Inventory" -# choose_hero_tab: "Restart Level" -# save_load_tab: "Save/Load" -# options_tab: "Options" -# guide_tab: "Guide" - multiplayer_tab: "Multiplayer" -# inventory_caption: "Equip your hero" -# choose_hero_caption: "Choose hero, language" -# save_load_caption: "... and view history" -# options_caption: "Configure settings" -# guide_caption: "Docs and tips" -# multiplayer_caption: "Play with friends!" - -# inventory: -# temp: "Temp" - -# choose_hero: -# temp: "Temp" - -# save_load: -# granularity_saved_games: "Saved" -# granularity_change_history: "History" - -# options: -# general_options: "General Options" -# music_label: "Music" -# music_description: "Turn background music on/off." -# autorun_label: "Autorun" -# autorun_description: "Control automatic code execution." -# editor_config: "Editor Config" -# editor_config_title: "Editor Configuration" -# editor_config_level_language_label: "Language for This Level" -# editor_config_level_language_description: "Define the programming language for this particular level." -# editor_config_default_language_label: "Default Programming Language" -# editor_config_default_language_description: "Define the programming language you want to code in when starting new levels." -# editor_config_keybindings_label: "Key Bindings" -# editor_config_keybindings_default: "Default (Ace)" -# editor_config_keybindings_description: "Adds additional shortcuts known from the common editors." -# editor_config_livecompletion_label: "Live Autocompletion" -# editor_config_livecompletion_description: "Displays autocomplete suggestions while typing." -# editor_config_invisibles_label: "Show Invisibles" -# editor_config_invisibles_description: "Displays invisibles such as spaces or tabs." -# editor_config_indentguides_label: "Show Indent Guides" -# editor_config_indentguides_description: "Displays vertical lines to see indentation better." -# editor_config_behaviors_label: "Smart Behaviors" -# editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes." - -# guide: -# temp: "Temp" - - multiplayer: - multiplayer_title: "Configurações do Multiplayer" -# multiplayer_toggle: "Enable multiplayer" -# multiplayer_toggle_description: "Allow others to join your game." - multiplayer_link_description: "Passe este link para quem você quiser que se una à partida." - multiplayer_hint_label: "Dica:" - multiplayer_hint: " Clique no link para selecionar tudo, então dê Ctrl+C ou ⌘+C para copiar o link. " - multiplayer_coming_soon: "Mais novidades no multiplayer estão chegando!" -# multiplayer_sign_in_leaderboard: "Sign in or create an account and get your solution on the leaderboard." - -# keyboard_shortcuts: -# keyboard_shortcuts: "Keyboard Shortcuts" -# space: "Space" -# enter: "Enter" -# escape: "Escape" -# shift: "Shift" -# cast_spell: "Cast current spell." -# run_real_time: "Run in real time." -# continue_script: "Continue past current script." -# skip_scripts: "Skip past all skippable scripts." -# toggle_playback: "Toggle play/pause." -# scrub_playback: "Scrub back and forward through time." -# single_scrub_playback: "Scrub back and forward through time by a single frame." -# scrub_execution: "Scrub through current spell execution." -# toggle_debug: "Toggle debug display." -# toggle_grid: "Toggle grid overlay." -# toggle_pathfinding: "Toggle pathfinding overlay." -# beautify: "Beautify your code by standardizing its formatting." -# maximize_editor: "Maximize/minimize code editor." -# move_wizard: "Move your Wizard around the level." - -# admin: -# av_title: "Admin Views" -# av_entities_sub_title: "Entities" -# av_entities_users_url: "Users" -# av_entities_active_instances_url: "Active Instances" -# av_entities_employer_list_url: "Employer List" -# av_other_sub_title: "Other" -# av_other_debug_base_url: "Base (for debugging base.jade)" -# u_title: "User List" -# lg_title: "Latest Games" -# clas: "CLAs" - -# community: -# main_title: "CodeCombat Community" -# introduction: "Check out the ways you can get involved below and decide what sounds the most fun. We look forward to working with you!" -# level_editor_prefix: "Use the CodeCombat" -# level_editor_suffix: "to create and edit levels. Users have created levels for their classes, friends, hackathons, students, and siblings. If create a new level sounds intimidating you can start by forking one of ours!" -# thang_editor_prefix: "We call units within the game 'thangs'. Use the" -# thang_editor_suffix: "to modify the CodeCombat source artwork. Allow units to throw projectiles, alter the direction of an animation, change a unit's hit points, or upload your own vector sprites." -# article_editor_prefix: "See a mistake in some of our docs? Want to make some instructions for your own creations? Check out the" -# article_editor_suffix: "and help CodeCombat players get the most out of their playtime." -# find_us: "Find us on these sites" -# contribute_to_the_project: "Contribute to the project" - -# editor: -# main_title: "CodeCombat Editors" -# article_title: "Article Editor" -# thang_title: "Thang Editor" -# level_title: "Level Editor" -# achievement_title: "Achievement Editor" -# back: "Back" -# revert: "Revert" -# revert_models: "Revert Models" -# pick_a_terrain: "Pick A Terrain" -# small: "Small" -# grassy: "Grassy" -# fork_title: "Fork New Version" -# fork_creating: "Creating Fork..." -# randomize: "Randomize" -# more: "More" -# wiki: "Wiki" -# live_chat: "Live Chat" -# level_some_options: "Some Options?" -# level_tab_thangs: "Thangs" -# level_tab_scripts: "Scripts" -# level_tab_settings: "Settings" -# level_tab_components: "Components" -# level_tab_systems: "Systems" -# level_tab_thangs_title: "Current Thangs" -# level_tab_thangs_all: "All" -# level_tab_thangs_conditions: "Starting Conditions" -# level_tab_thangs_add: "Add Thangs" -# delete: "Delete" -# duplicate: "Duplicate" -# level_settings_title: "Settings" -# level_component_tab_title: "Current Components" -# level_component_btn_new: "Create New Component" -# level_systems_tab_title: "Current Systems" -# level_systems_btn_new: "Create New System" -# level_systems_btn_add: "Add System" -# level_components_title: "Back to All Thangs" -# level_components_type: "Type" -# level_component_edit_title: "Edit Component" -# level_component_config_schema: "Config Schema" -# level_component_settings: "Settings" -# level_system_edit_title: "Edit System" -# create_system_title: "Create New System" -# new_component_title: "Create New Component" -# new_component_field_system: "System" -# new_article_title: "Create a New Article" -# new_thang_title: "Create a New Thang Type" -# new_level_title: "Create a New Level" -# new_article_title_login: "Log In to Create a New Article" -# new_thang_title_login: "Log In to Create a New Thang Type" -# new_level_title_login: "Log In to Create a New Level" -# new_achievement_title: "Create a New Achievement" -# new_achievement_title_login: "Log In to Create a New Achievement" -# article_search_title: "Search Articles Here" -# thang_search_title: "Search Thang Types Here" -# level_search_title: "Search Levels Here" -# achievement_search_title: "Search Achievements" -# read_only_warning2: "Note: you can't save any edits here, because you're not logged in." -# no_achievements: "No achievements have been added for this level yet." -# achievement_query_misc: "Key achievement off of miscellanea" -# achievement_query_goals: "Key achievement off of level goals" -# level_completion: "Level Completion" - -# article: -# edit_btn_preview: "Preview" -# edit_article_title: "Edit Article" - - general: -# and: "and" - name: "Nome" -# date: "Date" -# body: "Body" -# version: "Version" -# commit_msg: "Commit Message" -# version_history: "Version History" -# version_history_for: "Version History for: " -# result: "Result" -# results: "Results" -# description: "Description" - or: "ou" -# subject: "Subject" - email: "Email" -# password: "Password" - message: "Mensagem" -# code: "Code" -# ladder: "Ladder" -# when: "When" -# opponent: "Opponent" -# rank: "Rank" -# score: "Score" -# win: "Win" -# loss: "Loss" -# tie: "Tie" -# easy: "Easy" -# medium: "Medium" -# hard: "Hard" -# player: "Player" - -# about: -# who_is_codecombat: "Who is CodeCombat?" -# why_codecombat: "Why CodeCombat?" -# who_description_prefix: "together started CodeCombat in 2013. We also created " -# who_description_suffix: "in 2008, growing it to the #1 web and iOS application for learning to write Chinese and Japanese characters." -# who_description_ending: "Now it's time to teach people to write code." -# why_paragraph_1: "When making Skritter, George didn't know how to program and was constantly frustrated by his inability to implement his ideas. Afterwards, he tried learning, but the lessons were too slow. His housemate, wanting to reskill and stop teaching, tried Codecademy, but \"got bored.\" Each week another friend started Codecademy, then dropped off. We realized it was the same problem we'd solved with Skritter: people learning a skill via slow, intensive lessons when what they need is fast, extensive practice. We know how to fix that." -# why_paragraph_2: "Need to learn to code? You don't need lessons. You need to write a lot of code and have a great time doing it." -# why_paragraph_3_prefix: "That's what programming is about. It's gotta be fun. Not fun like" -# why_paragraph_3_italic: "yay a badge" -# why_paragraph_3_center: "but fun like" -# why_paragraph_3_italic_caps: "NO MOM I HAVE TO FINISH THE LEVEL!" -# why_paragraph_3_suffix: "That's why CodeCombat is a multiplayer game, not a gamified lesson course. We won't stop until you can't stop--but this time, that's a good thing." -# why_paragraph_4: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age." -# why_ending: "And hey, it's free. " -# why_ending_url: "Start wizarding now!" -# george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." -# scott_description: "Programmer extraordinaire, software architect, kitchen wizard, and master of finances. Scott is the reasonable one." -# nick_description: "Programming wizard, eccentric motivation mage, and upside-down experimenter. Nick can do anything and chooses to build CodeCombat." -# jeremy_description: "Customer support mage, usability tester, and community organizer; you've probably already spoken with Jeremy." -# michael_description: "Programmer, sys-admin, and undergrad technical wunderkind, Michael is the person keeping our servers online." -# matt_description: "Bicyclist, Software Engineer, reader of heroic fantasy, connoisseur of peanut butter, sipper of coffee." - -# legal: -# page_title: "Legal" -# opensource_intro: "CodeCombat is free to play and completely open source." -# opensource_description_prefix: "Check out " -# github_url: "our GitHub" -# opensource_description_center: "and help out if you like! CodeCombat is built on dozens of open source projects, and we love them. See " -# archmage_wiki_url: "our Archmage wiki" -# opensource_description_suffix: "for a list of the software that makes this game possible." -# practices_title: "Respectful Best Practices" -# practices_description: "These are our promises to you, the player, in slightly less legalese." -# privacy_title: "Privacy" -# privacy_description: "We will not sell any of your personal information. We intend to make money through recruitment eventually, but rest assured we will not distribute your personal information to interested companies without your explicit consent." -# security_title: "Security" -# security_description: "We strive to keep your personal information safe. As an open source project, our site is freely open to anyone to review and improve our security systems." -# email_title: "Email" -# email_description_prefix: "We will not inundate you with spam. Through" -# email_settings_url: "your email settings" -# email_description_suffix: "or through links in the emails we send, you can change your preferences and easily unsubscribe at any time." -# cost_title: "Cost" -# cost_description: "Currently, CodeCombat is 100% free! One of our main goals is to keep it that way, so that as many people can play as possible, regardless of place in life. If the sky darkens, we might have to charge subscriptions or for some content, but we'd rather not. With any luck, we'll be able to sustain the company with:" -# recruitment_title: "Recruitment" -# recruitment_description_prefix: "Here on CodeCombat, you're going to become a powerful wizard–not just in the game, but also in real life." -# url_hire_programmers: "No one can hire programmers fast enough" -# recruitment_description_suffix: "so once you've sharpened your skills and if you agree, we will demo your best coding accomplishments to the thousands of employers who are drooling for the chance to hire you. They pay us a little, they pay you" -# recruitment_description_italic: "a lot" -# recruitment_description_ending: "the site remains free and everybody's happy. That's the plan." -# copyrights_title: "Copyrights and Licenses" -# contributor_title: "Contributor License Agreement" -# contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our" -# cla_url: "CLA" -# contributor_description_suffix: "to which you should agree before contributing." -# code_title: "Code - MIT" -# code_description_prefix: "All code owned by CodeCombat or hosted on codecombat.com, both in the GitHub repository or in the codecombat.com database, is licensed under the" -# mit_license_url: "MIT license" -# code_description_suffix: "This includes all code in Systems and Components that are made available by CodeCombat for the purpose of creating levels." -# art_title: "Art/Music - Creative Commons " -# art_description_prefix: "All common content is available under the" -# cc_license_url: "Creative Commons Attribution 4.0 International License" -# art_description_suffix: "Common content is anything made generally available by CodeCombat for the purpose of creating Levels. This includes:" -# art_music: "Music" -# art_sound: "Sound" -# art_artwork: "Artwork" -# art_sprites: "Sprites" -# art_other: "Any and all other non-code creative works that are made available when creating Levels." -# art_access: "Currently there is no universal, easy system for fetching these assets. In general, fetch them from the URLs as used by the site, contact us for assistance, or help us in extending the site to make these assets more easily accessible." -# art_paragraph_1: "For attribution, please name and link to codecombat.com near where the source is used or where appropriate for the medium. For example:" -# use_list_1: "If used in a movie or another game, include codecombat.com in the credits." -# use_list_2: "If used on a website, include a link near the usage, for example underneath an image, or in a general attributions page where you might also mention other Creative Commons works and open source software being used on the site. Something that's already clearly referencing CodeCombat, such as a blog post mentioning CodeCombat, does not need some separate attribution." -# art_paragraph_2: "If the content being used is created not by CodeCombat but instead by a user of codecombat.com, attribute them instead, and follow attribution directions provided in that resource's description if there are any." -# rights_title: "Rights Reserved" -# rights_desc: "All rights are reserved for Levels themselves. This includes" -# rights_scripts: "Scripts" -# rights_unit: "Unit configuration" -# rights_description: "Description" -# rights_writings: "Writings" -# rights_media: "Media (sounds, music) and any other creative content made specifically for that Level and not made generally available when creating Levels." -# rights_clarification: "To clarify, anything that is made available in the Level Editor for the purpose of making levels is under CC, whereas the content created with the Level Editor or uploaded in the course of creation of Levels is not." -# nutshell_title: "In a Nutshell" -# nutshell_description: "Any resources we provide in the Level Editor are free to use as you like for creating Levels. But we reserve the right to restrict distribution of the Levels themselves (that are created on codecombat.com) so that they may be charged for in the future, if that's what ends up happening." -# canonical: "The English version of this document is the definitive, canonical version. If there are any discrepencies between translations, the English document takes precedence." - -# contribute: -# page_title: "Contributing" -# character_classes_title: "Character Classes" -# introduction_desc_intro: "We have high hopes for CodeCombat." -# introduction_desc_pref: "We want to be where programmers of all stripes come to learn and play together, introduce others to the wonderful world of coding, and reflect the best parts of the community. We can't and don't want to do that alone; what makes projects like GitHub, Stack Overflow and Linux great are the people who use them and build on them. To that end, " -# introduction_desc_github_url: "CodeCombat is totally open source" -# introduction_desc_suf: ", and we aim to provide as many ways as possible for you to take part and make this project as much yours as ours." -# introduction_desc_ending: "We hope you'll join our party!" -# introduction_desc_signature: "- Nick, George, Scott, Michael, Jeremy and Matt" -# alert_account_message_intro: "Hey there!" -# alert_account_message: "To subscribe for class emails, you'll need to be logged in first." -# archmage_summary: "Interested in working on game graphics, user interface design, database and server organization, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever." -# archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." -# class_attributes: "Class Attributes" -# archmage_attribute_1_pref: "Knowledge in " -# archmage_attribute_1_suf: ", or a desire to learn. Most of our code is in this language. If you're a fan of Ruby or Python, you'll feel right at home. It's JavaScript, but with a nicer syntax." -# archmage_attribute_2: "Some experience in programming and personal initiative. We'll help you get oriented, but we can't spend much time training you." -# how_to_join: "How To Join" -# join_desc_1: "Anyone can help out! Just check out our " -# join_desc_2: "to get started, and check the box below to mark yourself as a brave Archmage and get the latest news by email. Want to chat about what to do or how to get more deeply involved? " -# join_desc_3: ", or find us in our " -# join_desc_4: "and we'll go from there!" -# join_url_email: "Email us" -# join_url_hipchat: "public HipChat room" -# more_about_archmage: "Learn More About Becoming an Archmage" -# archmage_subscribe_desc: "Get emails on new coding opportunities and announcements." -# artisan_summary_pref: "Want to design levels and expand CodeCombat's arsenal? People are playing through our content at a pace faster than we can build! Right now, our level editor is barebone, so be wary. Making levels will be a little challenging and buggy. If you have visions of campaigns spanning for-loops to" -# artisan_summary_suf: ", then this class is for you." -# artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to" -# artisan_introduction_suf: ", then this class might be for you." -# artisan_attribute_1: "Any experience in building content like this would be nice, such as using Blizzard's level editors. But not required!" -# artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix." -# artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!" -# artisan_join_desc: "Use the Level Editor in these steps, give or take:" -# artisan_join_step1: "Read the documentation." -# artisan_join_step2: "Create a new level and explore existing levels." -# artisan_join_step3: "Find us in our public HipChat room for help." -# artisan_join_step4: "Post your levels on the forum for feedback." -# more_about_artisan: "Learn More About Becoming an Artisan" -# artisan_subscribe_desc: "Get emails on level editor updates and announcements." -# adventurer_summary: "Let us be clear about your role: you are the tank. You are going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class is for you." -# adventurer_introduction: "Let's be clear about your role: you are the tank. You're going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class might be for you." -# adventurer_attribute_1: "A thirst for learning. You want to learn how to code and we want to teach you how to code. You'll probably be doing most of the teaching in this case, though." -# adventurer_attribute_2: "Charismatic. Be gentle but articulate about what needs improving, and offer suggestions on how to improve." -# adventurer_join_pref: "Either get together with (or recruit!) an Artisan and work with them, or check the box below to receive emails when there are new levels to test. We'll also be posting about levels to review on our networks like" -# adventurer_forum_url: "our forum" -# adventurer_join_suf: "so if you prefer to be notified those ways, sign up there!" -# more_about_adventurer: "Learn More About Becoming an Adventurer" -# adventurer_subscribe_desc: "Get emails when there are new levels to test." -# scribe_summary_pref: "CodeCombat is not just going to be a bunch of levels. It will also be a resource of programming knowledge that players can hook into. That way, each Artisan can link to a detailed article that for the player's edification: documentation akin to what the " -# scribe_summary_suf: " has built. If you enjoy explaining programming concepts, then this class is for you." -# scribe_introduction_pref: "CodeCombat isn't just going to be a bunch of levels. It will also include a resource for knowledge, a wiki of programming concepts that levels can hook into. That way rather than each Artisan having to describe in detail what a comparison operator is, they can simply link their level to the Article describing them that is already written for the player's edification. Something along the lines of what the " -# scribe_introduction_url_mozilla: "Mozilla Developer Network" -# scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you." -# scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others." -# contact_us_url: "Contact us" -# scribe_join_description: "tell us a little about yourself, your experience with programming and what sort of things you'd like to write about. We'll go from there!" -# more_about_scribe: "Learn More About Becoming a Scribe" -# scribe_subscribe_desc: "Get emails about article writing announcements." -# diplomat_summary: "There is a large interest in CodeCombat in other countries that do not speak English! We are looking for translators who are willing to spend their time translating the site's corpus of words so that CodeCombat is accessible across the world as soon as possible. If you'd like to help getting CodeCombat international, then this class is for you." -# diplomat_introduction_pref: "So, if there's one thing we learned from the " -# diplomat_launch_url: "launch in October" -# diplomat_introduction_suf: "it's that there is sizeable interest in CodeCombat in other countries! We're building a corps of translators eager to turn one set of words into another set of words to get CodeCombat as accessible across the world as possible. If you like getting sneak peeks at upcoming content and getting these levels to your fellow nationals ASAP, then this class might be for you." -# diplomat_attribute_1: "Fluency in English and the language you would like to translate to. When conveying complicated ideas, it's important to have a strong grasp in both!" -# diplomat_join_pref_github: "Find your language locale file " -# diplomat_github_url: "on GitHub" -# diplomat_join_suf_github: ", edit it online, and submit a pull request. Also, check this box below to keep up-to-date on new internationalization developments!" -# more_about_diplomat: "Learn More About Becoming a Diplomat" -# diplomat_subscribe_desc: "Get emails about i18n developments and levels to translate." -# ambassador_summary: "We are trying to build a community, and every community needs a support team when there are troubles. We have got chats, emails, and social networks so that our users can get acquainted with the game. If you want to help people get involved, have fun, and learn some programming, then this class is for you." -# ambassador_introduction: "This is a community we're building, and you are the connections. We've got Olark chats, emails, and social networks with lots of people to talk with and help get acquainted with the game and learn from. If you want to help people get involved and have fun, and get a good feel of the pulse of CodeCombat and where we're going, then this class might be for you." -# ambassador_attribute_1: "Communication skills. Be able to identify the problems players are having and help them solve them. Also, keep the rest of us informed about what players are saying, what they like and don't like and want more of!" -# ambassador_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll go from there!" -# ambassador_join_note_strong: "Note" -# ambassador_join_note_desc: "One of our top priorities is to build multiplayer where players having difficulty solving levels can summon higher level wizards to help them. This will be a great way for ambassadors to do their thing. We'll keep you posted!" -# more_about_ambassador: "Learn More About Becoming an Ambassador" -# ambassador_subscribe_desc: "Get emails on support updates and multiplayer developments." -# changes_auto_save: "Changes are saved automatically when you toggle checkboxes." -# diligent_scribes: "Our Diligent Scribes:" -# powerful_archmages: "Our Powerful Archmages:" -# creative_artisans: "Our Creative Artisans:" -# brave_adventurers: "Our Brave Adventurers:" -# translating_diplomats: "Our Translating Diplomats:" -# helpful_ambassadors: "Our Helpful Ambassadors:" - -# classes: -# archmage_title: "Archmage" -# archmage_title_description: "(Coder)" -# artisan_title: "Artisan" -# artisan_title_description: "(Level Builder)" -# adventurer_title: "Adventurer" -# adventurer_title_description: "(Level Playtester)" -# scribe_title: "Scribe" -# scribe_title_description: "(Article Editor)" -# diplomat_title: "Diplomat" -# diplomat_title_description: "(Translator)" -# ambassador_title: "Ambassador" -# ambassador_title_description: "(Support)" - -# ladder: -# please_login: "Please log in first before playing a ladder game." -# my_matches: "My Matches" -# simulate: "Simulate" -# simulation_explanation: "By simulating games you can get your game ranked faster!" -# simulate_games: "Simulate Games!" -# simulate_all: "RESET AND SIMULATE GAMES" -# games_simulated_by: "Games simulated by you:" -# games_simulated_for: "Games simulated for you:" -# games_simulated: "Games simulated" -# games_played: "Games played" -# ratio: "Ratio" -# leaderboard: "Leaderboard" -# battle_as: "Battle as " -# summary_your: "Your " -# summary_matches: "Matches - " -# summary_wins: " Wins, " -# summary_losses: " Losses" -# rank_no_code: "No New Code to Rank" -# rank_my_game: "Rank My Game!" -# rank_submitting: "Submitting..." -# rank_submitted: "Submitted for Ranking" -# rank_failed: "Failed to Rank" -# rank_being_ranked: "Game Being Ranked" -# rank_last_submitted: "submitted " -# help_simulate: "Help simulate games?" -# code_being_simulated: "Your new code is being simulated by other players for ranking. This will refresh as new matches come in." -# no_ranked_matches_pre: "No ranked matches for the " -# no_ranked_matches_post: " team! Play against some competitors and then come back here to get your game ranked." -# choose_opponent: "Choose an Opponent" -# select_your_language: "Select your language!" -# tutorial_play: "Play Tutorial" -# tutorial_recommended: "Recommended if you've never played before" -# tutorial_skip: "Skip Tutorial" -# tutorial_not_sure: "Not sure what's going on?" -# tutorial_play_first: "Play the Tutorial first." -# simple_ai: "Simple AI" -# warmup: "Warmup" -# vs: "VS" -# friends_playing: "Friends Playing" -# log_in_for_friends: "Log in to play with your friends!" -# social_connect_blurb: "Connect and play against your friends!" -# invite_friends_to_battle: "Invite your friends to join you in battle!" -# fight: "Fight!" -# watch_victory: "Watch your victory" -# defeat_the: "Defeat the" -# tournament_ends: "Tournament ends" -# tournament_ended: "Tournament ended" -# tournament_rules: "Tournament Rules" -# tournament_blurb: "Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details" -# tournament_blurb_criss_cross: "Win bids, construct paths, outwit opponents, grab gems, and upgrade your career in our Criss-Cross tournament! Check out the details" -# tournament_blurb_blog: "on our blog" -# rules: "Rules" -# winners: "Winners" - -# ladder_prizes: -# title: "Tournament Prizes" -# blurb_1: "These prizes will be awarded according to" -# blurb_2: "the tournament rules" -# blurb_3: "to the top human and ogre players." -# blurb_4: "Two teams means double the prizes!" -# blurb_5: "(There will be two first place winners, two second-place winners, etc.)" -# rank: "Rank" -# prizes: "Prizes" -# total_value: "Total Value" -# in_cash: "in cash" -# custom_wizard: "Custom CodeCombat Wizard" -# custom_avatar: "Custom CodeCombat avatar" -# heap: "for six months of \"Startup\" access" -# credits: "credits" -# one_month_coupon: "coupon: choose either Rails or HTML" -# one_month_discount: "discount, 30% off: choose either Rails or HTML" -# license: "license" -# oreilly: "ebook of your choice" - -# loading_error: -# could_not_load: "Error loading from server" -# connection_failure: "Connection failed." -# unauthorized: "You need to be signed in. Do you have cookies disabled?" -# forbidden: "You do not have the permissions." -# not_found: "Not found." -# not_allowed: "Method not allowed." -# timeout: "Server timeout." -# conflict: "Resource conflict." -# bad_input: "Bad input." -# server_error: "Server error." -# unknown: "Unknown error." - -# resources: -# sessions: "Sessions" -# your_sessions: "Your Sessions" -# level: "Level" -# social_network_apis: "Social Network APIs" -# facebook_status: "Facebook Status" -# facebook_friends: "Facebook Friends" -# facebook_friend_sessions: "Facebook Friend Sessions" -# gplus_friends: "G+ Friends" -# gplus_friend_sessions: "G+ Friend Sessions" -# leaderboard: "Leaderboard" -# user_schema: "User Schema" -# user_profile: "User Profile" -# patches: "Patches" -# patched_model: "Source Document" -# model: "Model" -# system: "System" -# systems: "Systems" -# component: "Component" -# components: "Components" -# thang: "Thang" -# thangs: "Thangs" -# level_session: "Your Session" -# opponent_session: "Opponent Session" -# article: "Article" -# user_names: "User Names" -# thang_names: "Thang Names" -# files: "Files" -# top_simulators: "Top Simulators" -# source_document: "Source Document" -# document: "Document" -# sprite_sheet: "Sprite Sheet" -# employers: "Employers" -# candidates: "Candidates" -# candidate_sessions: "Candidate Sessions" -# user_remark: "User Remark" -# user_remarks: "User Remarks" -# versions: "Versions" -# items: "Items" -# wizard: "Wizard" -# achievement: "Achievement" -# clas: "CLAs" -# play_counts: "Play Counts" - -# delta: -# added: "Added" -# modified: "Modified" -# deleted: "Deleted" -# moved_index: "Moved Index" -# text_diff: "Text Diff" -# merge_conflict_with: "MERGE CONFLICT WITH" -# no_changes: "No Changes" - -# user: -# stats: "Stats" -# singleplayer_title: "Singleplayer Levels" -# multiplayer_title: "Multiplayer Levels" -# achievements_title: "Achievements" -# last_played: "Last Played" -# status: "Status" -# status_completed: "Completed" -# status_unfinished: "Unfinished" -# no_singleplayer: "No Singleplayer games played yet." -# no_multiplayer: "No Multiplayer games played yet." -# no_achievements: "No Achievements earned yet." -# favorite_prefix: "Favorite language is " -# favorite_postfix: "." - -# achievements: -# last_earned: "Last Earned" -# amount_achieved: "Amount" -# achievement: "Achievement" -# category_contributor: "Contributor" -# category_miscellaneous: "Miscellaneous" -# category_levels: "Levels" -# category_undefined: "Uncategorized" -# current_xp_prefix: "" -# current_xp_postfix: " in total" -# new_xp_prefix: "" -# new_xp_postfix: " earned" -# left_xp_prefix: "" -# left_xp_infix: " until level " -# left_xp_postfix: "" - -# account: -# recently_played: "Recently Played" -# no_recent_games: "No games played during the past two weeks." diff --git a/app/locale/ro.coffee b/app/locale/ro.coffee index 0a8d6cc97..4e98cc54c 100644 --- a/app/locale/ro.coffee +++ b/app/locale/ro.coffee @@ -3,21 +3,21 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman loading: "Se incarcă..." saving: "Se salvează..." sending: "Se trimite..." -# send: "Send" + send: "Trimite" cancel: "Anulează" save: "Salvează" -# publish: "Publish" - create: "Crează" + publish: "Publica" + create: "Creează" delay_1_sec: "1 secundă" delay_3_sec: "3 secunde" delay_5_sec: "5 secunde" manual: "Manual" fork: "Fork" play: "Joacă" -# retry: "Retry" + retry: "Reîncearca" # watch: "Watch" # unwatch: "Unwatch" -# submit_patch: "Submit Patch" + submit_patch: "Înainteaza Patch" units: second: "secundă" @@ -26,14 +26,14 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman minutes: "minute" hour: "oră" hours: "ore" -# day: "day" -# days: "days" -# week: "week" -# weeks: "weeks" -# month: "month" -# months: "months" -# year: "year" -# years: "years" + day: "zi" + days: "zile" + week: "săptămână" + weeks: "săptămâni" + month: "luna" + months: "luni" + year: "an" + years: "ani" modal: close: "Inchide" @@ -44,16 +44,16 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman nav: play: "Nivele" -# community: "Community" + community: "Communitate" editor: "Editor" blog: "Blog" forum: "Forum" -# account: "Account" -# profile: "Profile" -# stats: "Stats" -# code: "Code" + account: "Cont" + profile: "Profil" + stats: "Statistică" + code: "Cod" admin: "Admin" - home: "Acasa" + home: "Acasă" contribute: "Contribuie" legal: "Confidențialitate și termeni" about: "Despre" @@ -89,8 +89,8 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman creating: "Se creează contul..." sign_up: "Înscrie-te" log_in: "loghează-te cu parola" -# social_signup: "Or, you can sign up through Facebook or G+:" -# required: "You need to log in before you can go that way." + social_signup: "Sau, te poți inregistra cu Facebook sau G+:" + required: "Trebuie să te înregistrezi înaite să parcurgi acest drum." home: slogan: "Învață sa scrii cod jucându-te" @@ -103,12 +103,12 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman for_beginners: "Pentru Începători" multiplayer: "Multiplayer" for_developers: "Pentru dezvoltatori" -# javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers." -# python_blurb: "Simple yet powerful, Python is a great general purpose programming language." -# coffeescript_blurb: "Nicer JavaScript syntax." -# clojure_blurb: "A modern Lisp." -# lua_blurb: "Game scripting language." -# io_blurb: "Simple but obscure." + javascript_blurb: "Limbajul web-ului. Perfect pentru crearea website-urilor, web applicații, jocuri HTML5, si servere. The language of the web. Great for writing websites, web apps, HTML5 games, and servers." + python_blurb: "Simplu dar puternic, Python este un limbaj de uz general extraordinar!" + coffeescript_blurb: "JavaScript cu o syntaxă mai placută! Nicer JavaScript syntax." + clojure_blurb: "Un Lisp modern." + lua_blurb: "Limbaj de scripting pentru jocuri." + io_blurb: "Simplu dar obscur." play: choose_your_level: "Alege nivelul" @@ -123,11 +123,13 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman campaign_multiplayer_description: "... în care te lupți cap-la-cap contra alti jucători." campaign_player_created: "Create de jucători" campaign_player_created_description: "... în care ai ocazia să testezi creativitatea colegilor tai Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Dificultate: " play_as: "Alege-ți echipa" spectate: "Spectator" -# players: "players" -# hours_played: "hours played" + players: "jucători" + hours_played: "ore jucate" contact: contact_us: "Contact CodeCombat" @@ -139,8 +141,8 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman forum_page: "forumul nostru" forum_suffix: " în schimb." send: "Trimite Feedback" -# contact_candidate: "Contact Candidate" -# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 15% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns." + contact_candidate: "Contacteaza Candidatul" + recruitment_reminder: "Folosiți acest formular pentru a ajunge la candidații care va intereseaza pentru interviu. CodeCombat percepe 15% din salariu în primul an. Taxa este datorată la angajare și este rambursabilă pentru 90 de zile în cazul în care salariatul nu rămâne angajat. Cele part time, și angajați cu contract la distanță sunt gratuite, așa cum sunt stagiari." diplomat_suggestion: title: "Ajută-ne să traducem CodeCombat!" @@ -153,16 +155,16 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman wizard_settings: title: "Setări Wizard" customize_avatar: "Personalizează-ți Avatarul" -# active: "Active" -# color: "Color" -# group: "Group" + active: "Activ" + color: "Culoare" + group: "Grup" clothes: "Haine" trim: "Margine" cloud: "Nor" -# team: "Team" + team: "Echipa" spell: "Vrajă" boots: "Încălțăminte" - hue: "Culoare" + hue: "Nuanță" saturation: "Saturație" lightness: "Luminozitate" @@ -172,7 +174,7 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman autosave: "Modificările se salvează automat" me_tab: "Eu" picture_tab: "Poză" -# upload_picture: "Upload a picture" + upload_picture: "Uploadeaza o imagine" wizard_tab: "Wizard" password_tab: "Parolă" emails_tab: "Email-uri" @@ -181,16 +183,16 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman new_password: "Parolă nouă" new_password_verify: "Verifică" email_subscriptions: "Subscripție Email" -# email_subscriptions_none: "No Email Subscriptions." + email_subscriptions_none: "Nu ai subscripții Email." email_announcements: "Anunțuri" email_announcements_description: "Primește email-uri cu ultimele știri despre CodeCombat." email_notifications: "Notificări" -# email_notifications_summary: "Controls for personalized, automatic email notifications related to your CodeCombat activity." -# email_any_notes: "Any Notifications" -# email_any_notes_description: "Disable to stop all activity notification emails." -# email_news: "News" -# email_recruit_notes: "Job Opportunities" -# email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job." + email_notifications_summary: "Control pentru notificări email personalizate, legate de activitatea CodeCombat." + email_any_notes: "Orice Notificări" + email_any_notes_description: "Dezactivați pentru a opri toate e-mailurile de notificare a activității. Disable to stop all activity notification emails." + email_news: "Noutăți" + email_recruit_notes: "Oportunități de job-uri" + email_recruit_notes_description: "Daca joci foarte bine, este posibil sa te contactăm pentru obținerea unui loc (mai bun) de muncă." contributor_emails: "Contributor Class Emails" contribute_prefix: "Căutăm oameni să se alăture distracției! Intră pe " contribute_page: "pagina de contribuție" @@ -199,49 +201,49 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman error_saving: "Salvare erori" saved: "Modificări salvate" password_mismatch: "Parola nu se potrivește." -# password_repeat: "Please repeat your password." + password_repeat: "Te rugăm sa repeți parola." # job_profile: "Job Profile" # job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks." # job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job." -# sample_profile: "See a sample profile" -# view_profile: "View Your Profile" + sample_profile: "Vezi un profil exemplu" + view_profile: "Vizualizează Profilul" account_profile: -# settings: "Settings" -# edit_profile: "Edit Profile" -# done_editing: "Done Editing" + settings: "Setări" + edit_profile: "Modifica Profil" + done_editing: "Am terminat modificările." profile_for_prefix: "Profil pentru " profile_for_suffix: "" -# featured: "Featured" + featured: "Recomandate" # not_featured: "Not Featured" # looking_for: "Looking for:" # last_updated: "Last updated:" # contact: "Contact" -# active: "Looking for interview offers now" -# inactive: "Not looking for offers right now" -# complete: "complete" -# next: "Next" -# next_city: "city?" -# next_country: "pick your country." -# next_name: "name?" -# next_short_description: "write a short description." -# next_long_description: "describe your desired position." -# next_skills: "list at least five skills." -# next_work: "chronicle your work history." -# next_education: "recount your educational ordeals." -# next_projects: "show off up to three projects you've worked on." -# next_links: "add any personal or social links." -# next_photo: "add an optional professional photo." -# next_active: "mark yourself open to offers to show up in searches." -# example_blog: "Blog" -# example_personal_site: "Personal Site" -# links_header: "Personal Links" -# links_blurb: "Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog." -# links_name: "Link Name" -# links_name_help: "What are you linking to?" -# links_link_blurb: "Link URL" -# basics_header: "Update basic info" -# basics_active: "Open to Offers" + active: "Caut oferte de interviu." + inactive: "Nu caut oferte" + complete: "complet" + next: "Urmatorul" + next_city: "oras?" + next_country: "alege țara." + next_name: "nume?" + next_short_description: "scrie o scurta descriere." + next_long_description: "descrie poziția dorită." + next_skills: "listeaza cel puțin cinci competențe." + next_work: "cronica istoricului dvs. de lucru." + next_education: "povesteste-ne de chinurile educaționale" + next_projects: "scoate in evidență pana la 3 proiecte la care ai lucrat." + next_links: "adăuga orice link-uri personale sau sociale." + next_photo: "adăuga o fotografie profesionala opțională." + next_active: "indica că esti deschis la oferte ca să apară în căutări." + example_blog: "Blog" + example_personal_site: "Site Personal" + links_header: "Link-uri Personale" + links_blurb: "Link către orice alte site-uri sau profiluri pe care doriți să se sublinieze, ca GitHub, LinkedIn, sau blog-ul personal." + links_name: "Nume Link" + links_name_help: "Catre ce faci link?" + links_link_blurb: "Link URL" + basics_header: "Actualizați informații de bază" + basics_active: "Deschis la Oferte" # basics_active_help: "Want interview offers right now?" # basics_job_title: "Desired Job Title" # basics_job_title_help: "What role are you looking for?" @@ -359,15 +361,15 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman done: "Gata" customize_wizard: "Personalizează Wizard-ul" home: "Acasă" -# stop: "Stop" -# game_menu: "Game Menu" + stop: "Stop" + game_menu: "Meniul Jocului" guide: "Ghid" restart: "Restart" goals: "Obiective" -# success: "Success!" -# incomplete: "Incomplete" -# timed_out: "Ran out of time" -# failing: "Failing" + success: "Success!" + incomplete: "Incomplet" + timed_out: "Ai ramas fara timp" + failing: "Eşec" action_timeline: "Timeline-ul acțiunii" click_to_select: "Apasă pe o unitate pentru a o selecta." reload_title: "Reîncarcă tot codul?" @@ -397,7 +399,7 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman hud_continue: "Continuă (apasă shift-space)" spell_saved: "Vrajă salvată" skip_tutorial: "Sari peste (esc)" -# keyboard_shortcuts: "Key Shortcuts" + keyboard_shortcuts: "Scurtături Keyboard" loading_ready: "Gata!" tip_insert_positions: "Shift+Click oriunde pe harta pentru a insera punctul în editorul de vrăji." tip_toggle_play: "Pune sau scoate pauza cu Ctrl+P." @@ -421,7 +423,7 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman # tip_binary: "There are only 10 types of people in the world: those who understand binary, and those who don't." # tip_commitment_yoda: "A programmer must have the deepest commitment, the most serious mind. ~ Yoda" # tip_no_try: "Do. Or do not. There is no try. - Yoda" -# tip_patience: "Patience you must have, young Padawan. - Yoda" + tip_patience: "Să ai rabdare trebuie, tinere Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" # tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" @@ -444,9 +446,9 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman # inventory_caption: "Equip your hero" # choose_hero_caption: "Choose hero, language" # save_load_caption: "... and view history" -# options_caption: "Configure settings" -# guide_caption: "Docs and tips" -# multiplayer_caption: "Play with friends!" + options_caption: "Configurarea setărilor" + guide_caption: "Documentație si sfaturi" + multiplayer_caption: "Joaca cu prieteni!" # inventory: # temp: "Temp" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -659,7 +662,7 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman nick_description: "Programming wizard, eccentric motivation mage, and upside-down experimenter. Nick poate să facă orice si a ales să dezvolte CodeCombat." jeremy_description: "Customer support mage, usability tester, and community organizer; probabil ca ați vorbit deja cu Jeremy." michael_description: "Programmer, sys-admin, and undergrad technical wunderkind, Michael este cel care ține serverele in picioare." -# matt_description: "Bicyclist, Software Engineer, reader of heroic fantasy, connoisseur of peanut butter, sipper of coffee." + matt_description: "Bicyclist, Software Engineer, cititor de fantezie eroică, cunoscator de unt de arahide, sorbitor de cafea." legal: page_title: "Aspecte Legale" @@ -830,9 +833,9 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman simulate_all: "RESETEAZĂ ȘI SIMULEAZĂ JOCURI" games_simulated_by: "Jocuri simulate de tine:" games_simulated_for: "Jocuri simulate pentru tine:" -# games_simulated: "Games simulated" -# games_played: "Games played" -# ratio: "Ratio" + games_simulated: "Jocuri simulate" + games_played: "Jocuri jucate" + ratio: "Ratie" leaderboard: "Clasament" battle_as: "Luptă ca " summary_your: "Al tău " @@ -851,7 +854,7 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman no_ranked_matches_pre: "Nici un meci de clasament pentru " no_ranked_matches_post: " echipă! Joacă împotriva unor concurenți și revino apoi aici pentr a-ți plasa meciul in clasament." choose_opponent: "Alege un adversar" -# select_your_language: "Select your language!" + select_your_language: "Alege limbă!" tutorial_play: "Joacă Tutorial-ul" tutorial_recommended: "Recomandat dacă nu ai mai jucat niciodată înainte" tutorial_skip: "Sari peste Tutorial" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/ru.coffee b/app/locale/ru.coffee index c5ea9cd1e..d6b578b9d 100644 --- a/app/locale/ru.coffee +++ b/app/locale/ru.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi campaign_multiplayer_description: "... в которых вы соревнуетесь в программировании с другими игроками." campaign_player_created: "Уровни игроков" campaign_player_created_description: "... в которых вы сражаетесь с креативностью ваших друзей Ремесленников." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Сложность: " play_as: "Играть за " spectate: "Наблюдать" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" delta: added: "Добавлено" diff --git a/app/locale/sk.coffee b/app/locale/sk.coffee index db7a48f7d..6cf8d53c4 100644 --- a/app/locale/sk.coffee +++ b/app/locale/sk.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", campaign_multiplayer_description: "... v ktorej si zmeriaš svoje programátorské sily proti ostatným hráčom." campaign_player_created: "Hráčmi vytvorené úrovne" campaign_player_created_description: "... v ktorých sa popasuješ s kreativitou svojich kúzelníckych súdruhov." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Obtiažnosť." play_as: "Hraj ako" spectate: "Sleduj" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/sl.coffee b/app/locale/sl.coffee index 28c63cbf1..8ed46d8aa 100644 --- a/app/locale/sl.coffee +++ b/app/locale/sl.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/sr.coffee b/app/locale/sr.coffee index 2ec357ed0..4b7423811 100644 --- a/app/locale/sr.coffee +++ b/app/locale/sr.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian campaign_multiplayer_description: "... у којима кодираш 1 на 1 мечеве против осталих играча." campaign_player_created: "Направљено од стране играча" campaign_player_created_description: "... у којима се бориш против креативности својих колега." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Тежина: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/sv.coffee b/app/locale/sv.coffee index 7c733b528..bf5d40751 100644 --- a/app/locale/sv.coffee +++ b/app/locale/sv.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Svenska", englishDescription: "Swedish", tr campaign_multiplayer_description: "... i vilken du tävlar i kodande mot andra spelare" campaign_player_created: "Spelarskapade" campaign_player_created_description: "... i vilken du tävlar mot kreativiteten hos andra Hantverkare." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Svårighetsgrad: " play_as: "Spela som " spectate: "Titta på" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Svenska", englishDescription: "Swedish", tr options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Svenska", englishDescription: "Swedish", tr # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/th.coffee b/app/locale/th.coffee index 661573d41..5abe55703 100644 --- a/app/locale/th.coffee +++ b/app/locale/th.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/tr.coffee b/app/locale/tr.coffee index 720488b3d..56e46cd76 100644 --- a/app/locale/tr.coffee +++ b/app/locale/tr.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t campaign_multiplayer_description: "Diğer oyuncularla kafa kafaya verip kodlamak için..." campaign_player_created: "Oyuncuların Oluşturdukları" campaign_player_created_description: "Zanaatkâr Büyücülerin yaratıcılıklarına karşı mücadele etmek için..." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Zorluk: " play_as: "Olarak Oyna" spectate: "İzleyici olarak katıl" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/uk.coffee b/app/locale/uk.coffee index d94e271e6..95b602b6e 100644 --- a/app/locale/uk.coffee +++ b/app/locale/uk.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "українська мова", englishDesc campaign_multiplayer_description: "... в яких ви програмуєте віч-на-віч із іншими гравцями." campaign_player_created: "Рівні, створені гравцями" campaign_player_created_description: "... у яких ви змагаєтесь у креативності із вашими друзями-Архітекторами." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Складність: " play_as: "Грати як" spectate: "Спостерігати" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "українська мова", englishDesc options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "українська мова", englishDesc # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/ur.coffee b/app/locale/ur.coffee index 4df03e932..10c1c74fb 100644 --- a/app/locale/ur.coffee +++ b/app/locale/ur.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu", # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu", # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu", # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/vi.coffee b/app/locale/vi.coffee index e451dfecf..9705d0f1b 100644 --- a/app/locale/vi.coffee +++ b/app/locale/vi.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # campaign_multiplayer_description: "... in which you code head-to-head against other players." campaign_player_created: "Tạo người chơi" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "Khó: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/zh-HANS.coffee b/app/locale/zh-HANS.coffee index 9845fd8bc..a3b911f4c 100644 --- a/app/locale/zh-HANS.coffee +++ b/app/locale/zh-HANS.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese campaign_multiplayer_description: "……在这里你可以与其他玩家进行代码肉搏战。" campaign_player_created: "创建玩家" campaign_player_created_description: "……在这里你可以与你的小伙伴的创造力战斗 技术指导." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "难度:" play_as: "Play As" spectate: "旁观他人的游戏" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/zh-HANT.coffee b/app/locale/zh-HANT.coffee index b2494cd5d..22c279adf 100644 --- a/app/locale/zh-HANT.coffee +++ b/app/locale/zh-HANT.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese campaign_multiplayer_description: "...在這裡你可以和其他玩家進行對戰。" campaign_player_created: "玩家建立的關卡" campaign_player_created_description: "...挑戰同伴的創意 技術指導." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "難度" # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/zh-WUU-HANS.coffee b/app/locale/zh-WUU-HANS.coffee index b548ee9c8..814760356 100644 --- a/app/locale/zh-WUU-HANS.coffee +++ b/app/locale/zh-WUU-HANS.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "吴语", englishDescription: "Wuu (Simplifi # campaign_multiplayer_description: "... in which you code head-to-head against other players." # campaign_player_created: "Player-Created" # campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." # level_difficulty: "Difficulty: " # play_as: "Play As" # spectate: "Spectate" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "吴语", englishDescription: "Wuu (Simplifi # options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "吴语", englishDescription: "Wuu (Simplifi # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/zh-WUU-HANT.coffee b/app/locale/zh-WUU-HANT.coffee index 5e531075a..06badf071 100644 --- a/app/locale/zh-WUU-HANT.coffee +++ b/app/locale/zh-WUU-HANT.coffee @@ -123,6 +123,8 @@ module.exports = nativeDescription: "吳語", englishDescription: "Wuu (Traditio campaign_multiplayer_description: "……徠箇搭爾好搭別人代碼捉跤。" campaign_player_created: "造玩家" campaign_player_created_description: "……徠箇搭爾好搭爾夥計造起來個賭打 技術相幫." +# campaign_classic_algorithms: "Classic Algorithms" +# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." level_difficulty: "難度:" play_as: "Play As" spectate: "望別人攪遊戲" @@ -460,6 +462,7 @@ module.exports = nativeDescription: "吳語", englishDescription: "Wuu (Traditio options: # general_options: "General Options" +# volume_label: "Volume" # music_label: "Music" # music_description: "Turn background music on/off." # autorun_label: "Autorun" @@ -952,6 +955,7 @@ module.exports = nativeDescription: "吳語", englishDescription: "Wuu (Traditio # achievement: "Achievement" # clas: "CLAs" # play_counts: "Play Counts" +# feedback: "Feedback" # delta: # added: "Added" diff --git a/app/locale/zh.coffee b/app/locale/zh.coffee deleted file mode 100644 index 988c73d08..000000000 --- a/app/locale/zh.coffee +++ /dev/null @@ -1,998 +0,0 @@ -module.exports = nativeDescription: "中文", englishDescription: "Chinese", translation: - common: - loading: "加载中..." - saving: "正在保存..." - sending: "在发送中。。。" - send: "发送" - cancel: "退出" - save: "保存" - publish: "发布" - create: "创建" - delay_1_sec: "1 秒" - delay_3_sec: "3 秒" - delay_5_sec: "5 秒" - manual: "手册" - fork: "Fork" - play: "玩" - retry: "重试" - watch: "关注" - unwatch: "取消关注" - submit_patch: "提交补丁" - - units: - second: "秒" - seconds: "秒" - minute: "分" - minutes: "分" - hour: "时" - hours: "时" - day: "日" - days: "日" - week: "星期" - weeks: "星期" - month: "月" - months: "月" - year: "年" - years: "年" - - modal: - close: "关闭" - okay: "好" - - not_found: - page_not_found: "找不到网页" - - nav: - play: "玩" - community: "社区" - editor: "编辑" - blog: "博客" - forum: "论坛" - account: "账号" - profile: "账户资料" - stats: "状态" - code: "编码" - admin: "超级管理员" - home: "首页" - contribute: "贡献" - legal: "法律" - about: "关于" - contact: "联系我们" - twitter_follow: "关注" - employers: "招募" - - versions: - save_version_title: "保存新版本" - new_major_version: "最新主要版本" - cla_prefix: "要保存更改, 首先你必须要同意我们的" -# cla_url: "CLA" -# cla_suffix: "." - cla_agree: "我同意" - - login: - sign_up: "注册" - log_in: "登录" - logging_in: "登录中..." - log_out: "登出" - recover: "找回账户" - - recover: - recover_account_title: "帐户恢复" - send_password: "发送恢复密码" - - signup: - create_account_title: "创建新帐户保存游戏进度" - description: "免费啊。先跟你讲两点你就可以开始了" - email_announcements: "收到邮件宣告" - coppa: "13岁+ 或 非美国国籍 " - coppa_why: "为什么?" - creating: "账户在创新中" - sign_up: "注册" - log_in: "以密码登录" - social_signup: "或者, 你可以通过Facebook 或者 G+ 注册:" -# required: "You need to log in before you can go that way." - - home: - slogan: "通过游戏学习编程" - no_ie: "抱歉!Internet Explorer 9等更旧的预览器打不开此网站" - no_mobile: "CodeCombat暂时没有手机版本,可能无法运行!" - play: "玩" - old_browser: "啊噢...你的浏览器太旧啦,CodeCombat无法运行了...抱歉!" - old_browser_suffix: "你可以继续尝试下去,但是这种尝试八成没用的。。更新浏览器吧。" -# campaign: "Campaign" -# for_beginners: "For Beginners" -# multiplayer: "Multiplayer" -# for_developers: "For Developers" -# javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers." -# python_blurb: "Simple yet powerful, Python is a great general purpose programming language." -# coffeescript_blurb: "Nicer JavaScript syntax." -# clojure_blurb: "A modern Lisp." -# lua_blurb: "Game scripting language." -# io_blurb: "Simple but obscure." - - play: - choose_your_level: "选取难度" -# adventurer_prefix: "You can jump to any level below, or discuss the levels on " -# adventurer_forum: "the Adventurer forum" -# adventurer_suffix: "." -# campaign_beginner: "Beginner Campaign" -# campaign_beginner_description: "... in which you learn the wizardry of programming." -# campaign_dev: "Random Harder Levels" -# campaign_dev_description: "... in which you learn the interface while doing something a little harder." -# campaign_multiplayer: "Multiplayer Arenas" -# campaign_multiplayer_description: "... in which you code head-to-head against other players." -# campaign_player_created: "Player-Created" -# campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." - level_difficulty: "难度" -# play_as: "Play As" -# spectate: "Spectate" -# players: "players" -# hours_played: "hours played" - - contact: - contact_us: "联系我们" -# welcome: "Good to hear from you! Use this form to send us email. " -# contribute_prefix: "If you're interested in contributing, check out our " -# contribute_page: "contribute page" -# contribute_suffix: "!" -# forum_prefix: "For anything public, please try " - forum_page: "我们的论坛" -# forum_suffix: " instead." - send: "意见反馈" -# contact_candidate: "Contact Candidate" -# recruitment_reminder: "Use this form to reach out to candidates you are interested in interviewing. Remember that CodeCombat charges 15% of first-year salary. The fee is due upon hiring the employee and is refundable for 90 days if the employee does not remain employed. Part time, remote, and contract employees are free, as are interns." - - diplomat_suggestion: - title: "帮我们翻译CodeCombat" - sub_heading: "我们需要您的语言技能" - pitch_body: "We develop CodeCombat in English, but we already have players all over the world. Many of them want to play in Chinese but don't speak English, so if you can speak both, please consider signing up to be a Diplomat and help translate both the CodeCombat website and all the levels into Chinese." -# missing_translations: "Until we can translate everything into {English}, you'll see English when {English} isn't available." -# learn_more: "Learn more about being a Diplomat" -# subscribe_as_diplomat: "Subscribe as a Diplomat" - - wizard_settings: - title: "巫师设定" - customize_avatar: "设置你的头像" - active: "启用" - color: "颜色" - group: "类别" - clothes: "衣服" - trim: "条纹" - cloud: "云" - team: "队伍" - spell: "魔法球" - boots: "鞋子" - hue: "色彩" - saturation: "饱和度" - lightness: "亮度" - - account_settings: - title: "账户设置" - not_logged_in: "请先登录或创建账户" - autosave: "变更已自动保存" - me_tab: "我" - picture_tab: "图片" - upload_picture: "上传图片" - wizard_tab: "巫师" - password_tab: "密码" - emails_tab: "邮箱" - admin: "管理员" - wizard_color: "巫师服装颜色" - new_password: "新密码" - new_password_verify: "验证" - email_subscriptions: "邮件订阅" -# email_subscriptions_none: "No Email Subscriptions." - email_announcements: "声明" - email_announcements_description: "获取有关CodeCombat的最新消息" - email_notifications: "通知" - email_notifications_summary: "控制个性化的自动邮件提醒,提醒您在CodeCombat的活动" - email_any_notes: "任何通知" -# email_any_notes_description: "Disable to stop all activity notification emails." -# email_news: "News" - email_recruit_notes: "工作机会" - email_recruit_notes_description: "如果你玩得的确不赖,我们会联系你,或许给你一份(更好的)工作" - contributor_emails: "贡献者邮件" - contribute_prefix: "我们正在寻求更多的参与者。参见 " - contribute_page: "贡献页" - contribute_suffix: " 寻找更多" -# email_toggle: "Toggle All" - error_saving: "保存失败" - saved: "已保存" - password_mismatch: "密码不对应" -# password_repeat: "Please repeat your password." -# job_profile: "Job Profile" -# job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks." -# job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job." -# sample_profile: "See a sample profile" -# view_profile: "View Your Profile" - -# account_profile: -# settings: "Settings" -# edit_profile: "Edit Profile" -# done_editing: "Done Editing" -# profile_for_prefix: "Profile for " -# profile_for_suffix: "" -# featured: "Featured" -# not_featured: "Not Featured" -# looking_for: "Looking for:" -# last_updated: "Last updated:" -# contact: "Contact" -# active: "Looking for interview offers now" -# inactive: "Not looking for offers right now" -# complete: "complete" -# next: "Next" -# next_city: "city?" -# next_country: "pick your country." -# next_name: "name?" -# next_short_description: "write a short description." -# next_long_description: "describe your desired position." -# next_skills: "list at least five skills." -# next_work: "chronicle your work history." -# next_education: "recount your educational ordeals." -# next_projects: "show off up to three projects you've worked on." -# next_links: "add any personal or social links." -# next_photo: "add an optional professional photo." -# next_active: "mark yourself open to offers to show up in searches." -# example_blog: "Blog" -# example_personal_site: "Personal Site" -# links_header: "Personal Links" -# links_blurb: "Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog." -# links_name: "Link Name" -# links_name_help: "What are you linking to?" -# links_link_blurb: "Link URL" -# basics_header: "Update basic info" -# basics_active: "Open to Offers" -# basics_active_help: "Want interview offers right now?" -# basics_job_title: "Desired Job Title" -# basics_job_title_help: "What role are you looking for?" -# basics_city: "City" -# basics_city_help: "City you want to work in (or live in now)." -# basics_country: "Country" -# basics_country_help: "Country you want to work in (or live in now)." -# basics_visa: "US Work Status" -# basics_visa_help: "Are you authorized to work in the US, or do you need visa sponsorship? (If you live in Canada or Australia, mark authorized.)" -# basics_looking_for: "Looking For" -# basics_looking_for_full_time: "Full-time" -# basics_looking_for_part_time: "Part-time" -# basics_looking_for_remote: "Remote" -# basics_looking_for_contracting: "Contracting" -# basics_looking_for_internship: "Internship" -# basics_looking_for_help: "What kind of developer position do you want?" -# name_header: "Fill in your name" -# name_anonymous: "Anonymous Developer" -# name_help: "Name you want employers to see, like 'Nick Winter'." -# short_description_header: "Write a short description of yourself" -# short_description_blurb: "Add a tagline to help an employer quickly learn more about you." -# short_description: "Tagline" -# short_description_help: "Who are you, and what are you looking for? 140 characters max." -# skills_header: "Skills" -# skills_help: "Tag relevant developer skills in order of proficiency." -# long_description_header: "Describe your desired position" -# long_description_blurb: "Tell employers how awesome you are and what role you want." -# long_description: "Self Description" -# long_description_help: "Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max." -# work_experience: "Work Experience" -# work_header: "Chronicle your work history" -# work_years: "Years of Experience" -# work_years_help: "How many years of professional experience (getting paid) developing software do you have?" -# work_blurb: "List your relevant work experience, most recent first." -# work_employer: "Employer" -# work_employer_help: "Name of your employer." -# work_role: "Job Title" -# work_role_help: "What was your job title or role?" -# work_duration: "Duration" -# work_duration_help: "When did you hold this gig?" -# work_description: "Description" -# work_description_help: "What did you do there? (140 chars; optional)" -# education: "Education" -# education_header: "Recount your academic ordeals" -# education_blurb: "List your academic ordeals." -# education_school: "School" -# education_school_help: "Name of your school." -# education_degree: "Degree" -# education_degree_help: "What was your degree and field of study?" -# education_duration: "Dates" -# education_duration_help: "When?" -# education_description: "Description" -# education_description_help: "Highlight anything about this educational experience. (140 chars; optional)" -# our_notes: "CodeCombat's Notes" -# remarks: "Remarks" -# projects: "Projects" -# projects_header: "Add 3 projects" -# projects_header_2: "Projects (Top 3)" -# projects_blurb: "Highlight your projects to amaze employers." -# project_name: "Project Name" -# project_name_help: "What was the project called?" -# project_description: "Description" -# project_description_help: "Briefly describe the project." -# project_picture: "Picture" -# project_picture_help: "Upload a 230x115px or larger image showing off the project." -# project_link: "Link" -# project_link_help: "Link to the project." -# player_code: "Player Code" - -# employers: -# hire_developers_not_credentials: "Hire developers, not credentials." -# get_started: "Get Started" -# already_screened: "We've already technically screened all our candidates" -# filter_further: ", but you can also filter further:" -# filter_visa: "Visa" -# filter_visa_yes: "US Authorized" -# filter_visa_no: "Not Authorized" -# filter_education_top: "Top School" -# filter_education_other: "Other" -# filter_role_web_developer: "Web Developer" -# filter_role_software_developer: "Software Developer" -# filter_role_mobile_developer: "Mobile Developer" -# filter_experience: "Experience" -# filter_experience_senior: "Senior" -# filter_experience_junior: "Junior" -# filter_experience_recent_grad: "Recent Grad" -# filter_experience_student: "College Student" -# filter_results: "results" -# start_hiring: "Start hiring." -# reasons: "Three reasons you should hire through us:" -# everyone_looking: "Everyone here is looking for their next opportunity." -# everyone_looking_blurb: "Forget about 20% LinkedIn InMail response rates. Everyone that we list on this site wants to find their next position and will respond to your request for an introduction." -# weeding: "Sit back; we've done the weeding for you." -# weeding_blurb: "Every player that we list has been screened for technical ability. We also perform phone screens for select candidates and make notes on their profiles to save you time." -# pass_screen: "They will pass your technical screen." -# pass_screen_blurb: "Review each candidate's code before reaching out. One employer found that 5x as many of our devs passed their technical screen than hiring from Hacker News." -# make_hiring_easier: "Make my hiring easier, please." -# what: "What is CodeCombat?" -# what_blurb: "CodeCombat is a multiplayer browser programming game. Players write code to control their forces in battle against other developers. Our players have experience with all major tech stacks." -# cost: "How much do we charge?" -# cost_blurb: "We charge 15% of first year's salary and offer a 100% money back guarantee for 90 days. We don't charge for candidates who are already actively being interviewed at your company." -# candidate_name: "Name" -# candidate_location: "Location" -# candidate_looking_for: "Looking For" -# candidate_role: "Role" -# candidate_top_skills: "Top Skills" -# candidate_years_experience: "Yrs Exp" -# candidate_last_updated: "Last Updated" -# candidate_who: "Who" -# featured_developers: "Featured Developers" -# other_developers: "Other Developers" -# inactive_developers: "Inactive Developers" - -# play_level: -# done: "Done" -# customize_wizard: "Customize Wizard" -# home: "Home" -# stop: "Stop" -# game_menu: "Game Menu" -# guide: "Guide" -# restart: "Restart" -# goals: "Goals" -# success: "Success!" -# incomplete: "Incomplete" -# timed_out: "Ran out of time" -# failing: "Failing" -# action_timeline: "Action Timeline" -# click_to_select: "Click on a unit to select it." -# reload_title: "Reload All Code?" -# reload_really: "Are you sure you want to reload this level back to the beginning?" -# reload_confirm: "Reload All" -# victory_title_prefix: "" -# victory_title_suffix: " Complete" -# victory_sign_up: "Sign Up to Save Progress" -# victory_sign_up_poke: "Want to save your code? Create a free account!" -# victory_rate_the_level: "Rate the level: " -# victory_return_to_ladder: "Return to Ladder" -# victory_play_next_level: "Play Next Level" -# victory_go_home: "Go Home" -# victory_review: "Tell us more!" -# victory_hour_of_code_done: "Are You Done?" -# victory_hour_of_code_done_yes: "Yes, I'm finished with my Hour of Code™!" -# guide_title: "Guide" -# tome_minion_spells: "Your Minions' Spells" -# tome_read_only_spells: "Read-Only Spells" -# tome_other_units: "Other Units" -# tome_cast_button_castable: "Cast Spell" -# tome_cast_button_casting: "Casting" -# tome_cast_button_cast: "Spell Cast" -# tome_select_spell: "Select a Spell" -# tome_select_a_thang: "Select Someone for " -# tome_available_spells: "Available Spells" -# hud_continue: "Continue (shift+space)" -# spell_saved: "Spell Saved" -# skip_tutorial: "Skip (esc)" -# keyboard_shortcuts: "Key Shortcuts" -# loading_ready: "Ready!" -# tip_insert_positions: "Shift+Click a point on the map to insert it into the spell editor." -# tip_toggle_play: "Toggle play/paused with Ctrl+P." -# tip_scrub_shortcut: "Ctrl+[ and Ctrl+] rewind and fast-forward." -# tip_guide_exists: "Click the guide at the top of the page for useful info." -# tip_open_source: "CodeCombat is 100% open source!" -# tip_beta_launch: "CodeCombat launched its beta in October, 2013." -# tip_js_beginning: "JavaScript is just the beginning." -# tip_think_solution: "Think of the solution, not the problem." -# tip_theory_practice: "In theory, there is no difference between theory and practice. But in practice, there is. - Yogi Berra" -# tip_error_free: "There are two ways to write error-free programs; only the third one works. - Alan Perlis" -# tip_debugging_program: "If debugging is the process of removing bugs, then programming must be the process of putting them in. - Edsger W. Dijkstra" -# tip_forums: "Head over to the forums and tell us what you think!" -# tip_baby_coders: "In the future, even babies will be Archmages." -# tip_morale_improves: "Loading will continue until morale improves." -# tip_all_species: "We believe in equal opportunities to learn programming for all species." -# tip_reticulating: "Reticulating spines." -# tip_harry: "Yer a Wizard, " -# tip_great_responsibility: "With great coding skill comes great debug responsibility." -# tip_munchkin: "If you don't eat your vegetables, a munchkin will come after you while you're asleep." -# tip_binary: "There are only 10 types of people in the world: those who understand binary, and those who don't." -# tip_commitment_yoda: "A programmer must have the deepest commitment, the most serious mind. ~ Yoda" -# tip_no_try: "Do. Or do not. There is no try. - Yoda" -# tip_patience: "Patience you must have, young Padawan. - Yoda" -# tip_documented_bug: "A documented bug is not a bug; it is a feature." -# tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" -# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" -# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" -# tip_hardware_problem: "Q: How many programmers does it take to change a light bulb? A: None, it's a hardware problem." -# time_current: "Now:" -# time_total: "Max:" -# time_goto: "Go to:" -# infinite_loop_try_again: "Try Again" -# infinite_loop_reset_level: "Reset Level" -# infinite_loop_comment_out: "Comment Out My Code" - -# game_menu: -# inventory_tab: "Inventory" -# choose_hero_tab: "Restart Level" -# save_load_tab: "Save/Load" -# options_tab: "Options" -# guide_tab: "Guide" -# multiplayer_tab: "Multiplayer" -# inventory_caption: "Equip your hero" -# choose_hero_caption: "Choose hero, language" -# save_load_caption: "... and view history" -# options_caption: "Configure settings" -# guide_caption: "Docs and tips" -# multiplayer_caption: "Play with friends!" - -# inventory: -# temp: "Temp" - -# choose_hero: -# temp: "Temp" - -# save_load: -# granularity_saved_games: "Saved" -# granularity_change_history: "History" - -# options: -# general_options: "General Options" -# music_label: "Music" -# music_description: "Turn background music on/off." -# autorun_label: "Autorun" -# autorun_description: "Control automatic code execution." -# editor_config: "Editor Config" -# editor_config_title: "Editor Configuration" -# editor_config_level_language_label: "Language for This Level" -# editor_config_level_language_description: "Define the programming language for this particular level." -# editor_config_default_language_label: "Default Programming Language" -# editor_config_default_language_description: "Define the programming language you want to code in when starting new levels." -# editor_config_keybindings_label: "Key Bindings" -# editor_config_keybindings_default: "Default (Ace)" -# editor_config_keybindings_description: "Adds additional shortcuts known from the common editors." -# editor_config_livecompletion_label: "Live Autocompletion" -# editor_config_livecompletion_description: "Displays autocomplete suggestions while typing." -# editor_config_invisibles_label: "Show Invisibles" -# editor_config_invisibles_description: "Displays invisibles such as spaces or tabs." -# editor_config_indentguides_label: "Show Indent Guides" -# editor_config_indentguides_description: "Displays vertical lines to see indentation better." -# editor_config_behaviors_label: "Smart Behaviors" -# editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes." - -# guide: -# temp: "Temp" - -# multiplayer: -# multiplayer_title: "Multiplayer Settings" -# multiplayer_toggle: "Enable multiplayer" -# multiplayer_toggle_description: "Allow others to join your game." -# multiplayer_link_description: "Give this link to anyone to have them join you." -# multiplayer_hint_label: "Hint:" -# multiplayer_hint: " Click the link to select all, then press ⌘-C or Ctrl-C to copy the link." -# multiplayer_coming_soon: "More multiplayer features to come!" -# multiplayer_sign_in_leaderboard: "Sign in or create an account and get your solution on the leaderboard." - -# keyboard_shortcuts: -# keyboard_shortcuts: "Keyboard Shortcuts" -# space: "Space" -# enter: "Enter" -# escape: "Escape" -# shift: "Shift" -# cast_spell: "Cast current spell." -# run_real_time: "Run in real time." -# continue_script: "Continue past current script." -# skip_scripts: "Skip past all skippable scripts." -# toggle_playback: "Toggle play/pause." -# scrub_playback: "Scrub back and forward through time." -# single_scrub_playback: "Scrub back and forward through time by a single frame." -# scrub_execution: "Scrub through current spell execution." -# toggle_debug: "Toggle debug display." -# toggle_grid: "Toggle grid overlay." -# toggle_pathfinding: "Toggle pathfinding overlay." -# beautify: "Beautify your code by standardizing its formatting." -# maximize_editor: "Maximize/minimize code editor." -# move_wizard: "Move your Wizard around the level." - -# admin: -# av_title: "Admin Views" -# av_entities_sub_title: "Entities" -# av_entities_users_url: "Users" -# av_entities_active_instances_url: "Active Instances" -# av_entities_employer_list_url: "Employer List" -# av_other_sub_title: "Other" -# av_other_debug_base_url: "Base (for debugging base.jade)" -# u_title: "User List" -# lg_title: "Latest Games" -# clas: "CLAs" - -# community: -# main_title: "CodeCombat Community" -# introduction: "Check out the ways you can get involved below and decide what sounds the most fun. We look forward to working with you!" -# level_editor_prefix: "Use the CodeCombat" -# level_editor_suffix: "to create and edit levels. Users have created levels for their classes, friends, hackathons, students, and siblings. If create a new level sounds intimidating you can start by forking one of ours!" -# thang_editor_prefix: "We call units within the game 'thangs'. Use the" -# thang_editor_suffix: "to modify the CodeCombat source artwork. Allow units to throw projectiles, alter the direction of an animation, change a unit's hit points, or upload your own vector sprites." -# article_editor_prefix: "See a mistake in some of our docs? Want to make some instructions for your own creations? Check out the" -# article_editor_suffix: "and help CodeCombat players get the most out of their playtime." -# find_us: "Find us on these sites" -# contribute_to_the_project: "Contribute to the project" - -# editor: -# main_title: "CodeCombat Editors" -# article_title: "Article Editor" -# thang_title: "Thang Editor" -# level_title: "Level Editor" -# achievement_title: "Achievement Editor" -# back: "Back" -# revert: "Revert" -# revert_models: "Revert Models" -# pick_a_terrain: "Pick A Terrain" -# small: "Small" -# grassy: "Grassy" -# fork_title: "Fork New Version" -# fork_creating: "Creating Fork..." -# randomize: "Randomize" -# more: "More" -# wiki: "Wiki" -# live_chat: "Live Chat" -# level_some_options: "Some Options?" -# level_tab_thangs: "Thangs" -# level_tab_scripts: "Scripts" -# level_tab_settings: "Settings" -# level_tab_components: "Components" -# level_tab_systems: "Systems" -# level_tab_thangs_title: "Current Thangs" -# level_tab_thangs_all: "All" -# level_tab_thangs_conditions: "Starting Conditions" -# level_tab_thangs_add: "Add Thangs" -# delete: "Delete" -# duplicate: "Duplicate" -# level_settings_title: "Settings" -# level_component_tab_title: "Current Components" -# level_component_btn_new: "Create New Component" -# level_systems_tab_title: "Current Systems" -# level_systems_btn_new: "Create New System" -# level_systems_btn_add: "Add System" -# level_components_title: "Back to All Thangs" -# level_components_type: "Type" -# level_component_edit_title: "Edit Component" -# level_component_config_schema: "Config Schema" -# level_component_settings: "Settings" -# level_system_edit_title: "Edit System" -# create_system_title: "Create New System" -# new_component_title: "Create New Component" -# new_component_field_system: "System" -# new_article_title: "Create a New Article" -# new_thang_title: "Create a New Thang Type" -# new_level_title: "Create a New Level" -# new_article_title_login: "Log In to Create a New Article" -# new_thang_title_login: "Log In to Create a New Thang Type" -# new_level_title_login: "Log In to Create a New Level" -# new_achievement_title: "Create a New Achievement" -# new_achievement_title_login: "Log In to Create a New Achievement" -# article_search_title: "Search Articles Here" -# thang_search_title: "Search Thang Types Here" -# level_search_title: "Search Levels Here" -# achievement_search_title: "Search Achievements" -# read_only_warning2: "Note: you can't save any edits here, because you're not logged in." -# no_achievements: "No achievements have been added for this level yet." -# achievement_query_misc: "Key achievement off of miscellanea" -# achievement_query_goals: "Key achievement off of level goals" -# level_completion: "Level Completion" - -# article: -# edit_btn_preview: "Preview" -# edit_article_title: "Edit Article" - - general: -# and: "and" - name: "名字" -# date: "Date" -# body: "Body" -# version: "Version" -# commit_msg: "Commit Message" -# version_history: "Version History" -# version_history_for: "Version History for: " -# result: "Result" -# results: "Results" -# description: "Description" - or: "或" -# subject: "Subject" - email: "邮箱" -# password: "Password" - message: "留言" -# code: "Code" -# ladder: "Ladder" -# when: "When" -# opponent: "Opponent" -# rank: "Rank" -# score: "Score" -# win: "Win" -# loss: "Loss" -# tie: "Tie" -# easy: "Easy" -# medium: "Medium" -# hard: "Hard" -# player: "Player" - -# about: -# who_is_codecombat: "Who is CodeCombat?" -# why_codecombat: "Why CodeCombat?" -# who_description_prefix: "together started CodeCombat in 2013. We also created " -# who_description_suffix: "in 2008, growing it to the #1 web and iOS application for learning to write Chinese and Japanese characters." -# who_description_ending: "Now it's time to teach people to write code." -# why_paragraph_1: "When making Skritter, George didn't know how to program and was constantly frustrated by his inability to implement his ideas. Afterwards, he tried learning, but the lessons were too slow. His housemate, wanting to reskill and stop teaching, tried Codecademy, but \"got bored.\" Each week another friend started Codecademy, then dropped off. We realized it was the same problem we'd solved with Skritter: people learning a skill via slow, intensive lessons when what they need is fast, extensive practice. We know how to fix that." -# why_paragraph_2: "Need to learn to code? You don't need lessons. You need to write a lot of code and have a great time doing it." -# why_paragraph_3_prefix: "That's what programming is about. It's gotta be fun. Not fun like" -# why_paragraph_3_italic: "yay a badge" -# why_paragraph_3_center: "but fun like" -# why_paragraph_3_italic_caps: "NO MOM I HAVE TO FINISH THE LEVEL!" -# why_paragraph_3_suffix: "That's why CodeCombat is a multiplayer game, not a gamified lesson course. We won't stop until you can't stop--but this time, that's a good thing." -# why_paragraph_4: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age." -# why_ending: "And hey, it's free. " -# why_ending_url: "Start wizarding now!" -# george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." -# scott_description: "Programmer extraordinaire, software architect, kitchen wizard, and master of finances. Scott is the reasonable one." -# nick_description: "Programming wizard, eccentric motivation mage, and upside-down experimenter. Nick can do anything and chooses to build CodeCombat." -# jeremy_description: "Customer support mage, usability tester, and community organizer; you've probably already spoken with Jeremy." -# michael_description: "Programmer, sys-admin, and undergrad technical wunderkind, Michael is the person keeping our servers online." -# matt_description: "Bicyclist, Software Engineer, reader of heroic fantasy, connoisseur of peanut butter, sipper of coffee." - -# legal: -# page_title: "Legal" -# opensource_intro: "CodeCombat is free to play and completely open source." -# opensource_description_prefix: "Check out " -# github_url: "our GitHub" -# opensource_description_center: "and help out if you like! CodeCombat is built on dozens of open source projects, and we love them. See " -# archmage_wiki_url: "our Archmage wiki" -# opensource_description_suffix: "for a list of the software that makes this game possible." -# practices_title: "Respectful Best Practices" -# practices_description: "These are our promises to you, the player, in slightly less legalese." -# privacy_title: "Privacy" -# privacy_description: "We will not sell any of your personal information. We intend to make money through recruitment eventually, but rest assured we will not distribute your personal information to interested companies without your explicit consent." -# security_title: "Security" -# security_description: "We strive to keep your personal information safe. As an open source project, our site is freely open to anyone to review and improve our security systems." -# email_title: "Email" -# email_description_prefix: "We will not inundate you with spam. Through" -# email_settings_url: "your email settings" -# email_description_suffix: "or through links in the emails we send, you can change your preferences and easily unsubscribe at any time." -# cost_title: "Cost" -# cost_description: "Currently, CodeCombat is 100% free! One of our main goals is to keep it that way, so that as many people can play as possible, regardless of place in life. If the sky darkens, we might have to charge subscriptions or for some content, but we'd rather not. With any luck, we'll be able to sustain the company with:" -# recruitment_title: "Recruitment" -# recruitment_description_prefix: "Here on CodeCombat, you're going to become a powerful wizard–not just in the game, but also in real life." -# url_hire_programmers: "No one can hire programmers fast enough" -# recruitment_description_suffix: "so once you've sharpened your skills and if you agree, we will demo your best coding accomplishments to the thousands of employers who are drooling for the chance to hire you. They pay us a little, they pay you" -# recruitment_description_italic: "a lot" -# recruitment_description_ending: "the site remains free and everybody's happy. That's the plan." -# copyrights_title: "Copyrights and Licenses" -# contributor_title: "Contributor License Agreement" -# contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our" -# cla_url: "CLA" -# contributor_description_suffix: "to which you should agree before contributing." -# code_title: "Code - MIT" -# code_description_prefix: "All code owned by CodeCombat or hosted on codecombat.com, both in the GitHub repository or in the codecombat.com database, is licensed under the" -# mit_license_url: "MIT license" -# code_description_suffix: "This includes all code in Systems and Components that are made available by CodeCombat for the purpose of creating levels." -# art_title: "Art/Music - Creative Commons " -# art_description_prefix: "All common content is available under the" -# cc_license_url: "Creative Commons Attribution 4.0 International License" -# art_description_suffix: "Common content is anything made generally available by CodeCombat for the purpose of creating Levels. This includes:" -# art_music: "Music" -# art_sound: "Sound" -# art_artwork: "Artwork" -# art_sprites: "Sprites" -# art_other: "Any and all other non-code creative works that are made available when creating Levels." -# art_access: "Currently there is no universal, easy system for fetching these assets. In general, fetch them from the URLs as used by the site, contact us for assistance, or help us in extending the site to make these assets more easily accessible." -# art_paragraph_1: "For attribution, please name and link to codecombat.com near where the source is used or where appropriate for the medium. For example:" -# use_list_1: "If used in a movie or another game, include codecombat.com in the credits." -# use_list_2: "If used on a website, include a link near the usage, for example underneath an image, or in a general attributions page where you might also mention other Creative Commons works and open source software being used on the site. Something that's already clearly referencing CodeCombat, such as a blog post mentioning CodeCombat, does not need some separate attribution." -# art_paragraph_2: "If the content being used is created not by CodeCombat but instead by a user of codecombat.com, attribute them instead, and follow attribution directions provided in that resource's description if there are any." -# rights_title: "Rights Reserved" -# rights_desc: "All rights are reserved for Levels themselves. This includes" -# rights_scripts: "Scripts" -# rights_unit: "Unit configuration" -# rights_description: "Description" -# rights_writings: "Writings" -# rights_media: "Media (sounds, music) and any other creative content made specifically for that Level and not made generally available when creating Levels." -# rights_clarification: "To clarify, anything that is made available in the Level Editor for the purpose of making levels is under CC, whereas the content created with the Level Editor or uploaded in the course of creation of Levels is not." -# nutshell_title: "In a Nutshell" -# nutshell_description: "Any resources we provide in the Level Editor are free to use as you like for creating Levels. But we reserve the right to restrict distribution of the Levels themselves (that are created on codecombat.com) so that they may be charged for in the future, if that's what ends up happening." -# canonical: "The English version of this document is the definitive, canonical version. If there are any discrepencies between translations, the English document takes precedence." - -# contribute: -# page_title: "Contributing" -# character_classes_title: "Character Classes" -# introduction_desc_intro: "We have high hopes for CodeCombat." -# introduction_desc_pref: "We want to be where programmers of all stripes come to learn and play together, introduce others to the wonderful world of coding, and reflect the best parts of the community. We can't and don't want to do that alone; what makes projects like GitHub, Stack Overflow and Linux great are the people who use them and build on them. To that end, " -# introduction_desc_github_url: "CodeCombat is totally open source" -# introduction_desc_suf: ", and we aim to provide as many ways as possible for you to take part and make this project as much yours as ours." -# introduction_desc_ending: "We hope you'll join our party!" -# introduction_desc_signature: "- Nick, George, Scott, Michael, Jeremy and Matt" -# alert_account_message_intro: "Hey there!" -# alert_account_message: "To subscribe for class emails, you'll need to be logged in first." -# archmage_summary: "Interested in working on game graphics, user interface design, database and server organization, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever." -# archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." -# class_attributes: "Class Attributes" -# archmage_attribute_1_pref: "Knowledge in " -# archmage_attribute_1_suf: ", or a desire to learn. Most of our code is in this language. If you're a fan of Ruby or Python, you'll feel right at home. It's JavaScript, but with a nicer syntax." -# archmage_attribute_2: "Some experience in programming and personal initiative. We'll help you get oriented, but we can't spend much time training you." -# how_to_join: "How To Join" -# join_desc_1: "Anyone can help out! Just check out our " -# join_desc_2: "to get started, and check the box below to mark yourself as a brave Archmage and get the latest news by email. Want to chat about what to do or how to get more deeply involved? " -# join_desc_3: ", or find us in our " -# join_desc_4: "and we'll go from there!" -# join_url_email: "Email us" -# join_url_hipchat: "public HipChat room" -# more_about_archmage: "Learn More About Becoming an Archmage" -# archmage_subscribe_desc: "Get emails on new coding opportunities and announcements." -# artisan_summary_pref: "Want to design levels and expand CodeCombat's arsenal? People are playing through our content at a pace faster than we can build! Right now, our level editor is barebone, so be wary. Making levels will be a little challenging and buggy. If you have visions of campaigns spanning for-loops to" -# artisan_summary_suf: ", then this class is for you." -# artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to" -# artisan_introduction_suf: ", then this class might be for you." -# artisan_attribute_1: "Any experience in building content like this would be nice, such as using Blizzard's level editors. But not required!" -# artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix." -# artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!" -# artisan_join_desc: "Use the Level Editor in these steps, give or take:" -# artisan_join_step1: "Read the documentation." -# artisan_join_step2: "Create a new level and explore existing levels." -# artisan_join_step3: "Find us in our public HipChat room for help." -# artisan_join_step4: "Post your levels on the forum for feedback." -# more_about_artisan: "Learn More About Becoming an Artisan" -# artisan_subscribe_desc: "Get emails on level editor updates and announcements." -# adventurer_summary: "Let us be clear about your role: you are the tank. You are going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class is for you." -# adventurer_introduction: "Let's be clear about your role: you are the tank. You're going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class might be for you." -# adventurer_attribute_1: "A thirst for learning. You want to learn how to code and we want to teach you how to code. You'll probably be doing most of the teaching in this case, though." -# adventurer_attribute_2: "Charismatic. Be gentle but articulate about what needs improving, and offer suggestions on how to improve." -# adventurer_join_pref: "Either get together with (or recruit!) an Artisan and work with them, or check the box below to receive emails when there are new levels to test. We'll also be posting about levels to review on our networks like" -# adventurer_forum_url: "our forum" -# adventurer_join_suf: "so if you prefer to be notified those ways, sign up there!" -# more_about_adventurer: "Learn More About Becoming an Adventurer" -# adventurer_subscribe_desc: "Get emails when there are new levels to test." -# scribe_summary_pref: "CodeCombat is not just going to be a bunch of levels. It will also be a resource of programming knowledge that players can hook into. That way, each Artisan can link to a detailed article that for the player's edification: documentation akin to what the " -# scribe_summary_suf: " has built. If you enjoy explaining programming concepts, then this class is for you." -# scribe_introduction_pref: "CodeCombat isn't just going to be a bunch of levels. It will also include a resource for knowledge, a wiki of programming concepts that levels can hook into. That way rather than each Artisan having to describe in detail what a comparison operator is, they can simply link their level to the Article describing them that is already written for the player's edification. Something along the lines of what the " -# scribe_introduction_url_mozilla: "Mozilla Developer Network" -# scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you." -# scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others." -# contact_us_url: "Contact us" -# scribe_join_description: "tell us a little about yourself, your experience with programming and what sort of things you'd like to write about. We'll go from there!" -# more_about_scribe: "Learn More About Becoming a Scribe" -# scribe_subscribe_desc: "Get emails about article writing announcements." -# diplomat_summary: "There is a large interest in CodeCombat in other countries that do not speak English! We are looking for translators who are willing to spend their time translating the site's corpus of words so that CodeCombat is accessible across the world as soon as possible. If you'd like to help getting CodeCombat international, then this class is for you." -# diplomat_introduction_pref: "So, if there's one thing we learned from the " -# diplomat_launch_url: "launch in October" -# diplomat_introduction_suf: "it's that there is sizeable interest in CodeCombat in other countries! We're building a corps of translators eager to turn one set of words into another set of words to get CodeCombat as accessible across the world as possible. If you like getting sneak peeks at upcoming content and getting these levels to your fellow nationals ASAP, then this class might be for you." -# diplomat_attribute_1: "Fluency in English and the language you would like to translate to. When conveying complicated ideas, it's important to have a strong grasp in both!" -# diplomat_join_pref_github: "Find your language locale file " -# diplomat_github_url: "on GitHub" -# diplomat_join_suf_github: ", edit it online, and submit a pull request. Also, check this box below to keep up-to-date on new internationalization developments!" -# more_about_diplomat: "Learn More About Becoming a Diplomat" -# diplomat_subscribe_desc: "Get emails about i18n developments and levels to translate." -# ambassador_summary: "We are trying to build a community, and every community needs a support team when there are troubles. We have got chats, emails, and social networks so that our users can get acquainted with the game. If you want to help people get involved, have fun, and learn some programming, then this class is for you." -# ambassador_introduction: "This is a community we're building, and you are the connections. We've got Olark chats, emails, and social networks with lots of people to talk with and help get acquainted with the game and learn from. If you want to help people get involved and have fun, and get a good feel of the pulse of CodeCombat and where we're going, then this class might be for you." -# ambassador_attribute_1: "Communication skills. Be able to identify the problems players are having and help them solve them. Also, keep the rest of us informed about what players are saying, what they like and don't like and want more of!" -# ambassador_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll go from there!" -# ambassador_join_note_strong: "Note" -# ambassador_join_note_desc: "One of our top priorities is to build multiplayer where players having difficulty solving levels can summon higher level wizards to help them. This will be a great way for ambassadors to do their thing. We'll keep you posted!" -# more_about_ambassador: "Learn More About Becoming an Ambassador" -# ambassador_subscribe_desc: "Get emails on support updates and multiplayer developments." -# changes_auto_save: "Changes are saved automatically when you toggle checkboxes." -# diligent_scribes: "Our Diligent Scribes:" -# powerful_archmages: "Our Powerful Archmages:" -# creative_artisans: "Our Creative Artisans:" -# brave_adventurers: "Our Brave Adventurers:" -# translating_diplomats: "Our Translating Diplomats:" -# helpful_ambassadors: "Our Helpful Ambassadors:" - -# classes: -# archmage_title: "Archmage" -# archmage_title_description: "(Coder)" -# artisan_title: "Artisan" -# artisan_title_description: "(Level Builder)" -# adventurer_title: "Adventurer" -# adventurer_title_description: "(Level Playtester)" -# scribe_title: "Scribe" -# scribe_title_description: "(Article Editor)" -# diplomat_title: "Diplomat" -# diplomat_title_description: "(Translator)" -# ambassador_title: "Ambassador" -# ambassador_title_description: "(Support)" - -# ladder: -# please_login: "Please log in first before playing a ladder game." -# my_matches: "My Matches" -# simulate: "Simulate" -# simulation_explanation: "By simulating games you can get your game ranked faster!" -# simulate_games: "Simulate Games!" -# simulate_all: "RESET AND SIMULATE GAMES" -# games_simulated_by: "Games simulated by you:" -# games_simulated_for: "Games simulated for you:" -# games_simulated: "Games simulated" -# games_played: "Games played" -# ratio: "Ratio" -# leaderboard: "Leaderboard" -# battle_as: "Battle as " -# summary_your: "Your " -# summary_matches: "Matches - " -# summary_wins: " Wins, " -# summary_losses: " Losses" -# rank_no_code: "No New Code to Rank" -# rank_my_game: "Rank My Game!" -# rank_submitting: "Submitting..." -# rank_submitted: "Submitted for Ranking" -# rank_failed: "Failed to Rank" -# rank_being_ranked: "Game Being Ranked" -# rank_last_submitted: "submitted " -# help_simulate: "Help simulate games?" -# code_being_simulated: "Your new code is being simulated by other players for ranking. This will refresh as new matches come in." -# no_ranked_matches_pre: "No ranked matches for the " -# no_ranked_matches_post: " team! Play against some competitors and then come back here to get your game ranked." -# choose_opponent: "Choose an Opponent" -# select_your_language: "Select your language!" -# tutorial_play: "Play Tutorial" -# tutorial_recommended: "Recommended if you've never played before" -# tutorial_skip: "Skip Tutorial" -# tutorial_not_sure: "Not sure what's going on?" -# tutorial_play_first: "Play the Tutorial first." -# simple_ai: "Simple AI" -# warmup: "Warmup" -# vs: "VS" -# friends_playing: "Friends Playing" -# log_in_for_friends: "Log in to play with your friends!" -# social_connect_blurb: "Connect and play against your friends!" -# invite_friends_to_battle: "Invite your friends to join you in battle!" -# fight: "Fight!" -# watch_victory: "Watch your victory" -# defeat_the: "Defeat the" -# tournament_ends: "Tournament ends" -# tournament_ended: "Tournament ended" -# tournament_rules: "Tournament Rules" -# tournament_blurb: "Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details" -# tournament_blurb_criss_cross: "Win bids, construct paths, outwit opponents, grab gems, and upgrade your career in our Criss-Cross tournament! Check out the details" -# tournament_blurb_blog: "on our blog" -# rules: "Rules" -# winners: "Winners" - -# ladder_prizes: -# title: "Tournament Prizes" -# blurb_1: "These prizes will be awarded according to" -# blurb_2: "the tournament rules" -# blurb_3: "to the top human and ogre players." -# blurb_4: "Two teams means double the prizes!" -# blurb_5: "(There will be two first place winners, two second-place winners, etc.)" -# rank: "Rank" -# prizes: "Prizes" -# total_value: "Total Value" -# in_cash: "in cash" -# custom_wizard: "Custom CodeCombat Wizard" -# custom_avatar: "Custom CodeCombat avatar" -# heap: "for six months of \"Startup\" access" -# credits: "credits" -# one_month_coupon: "coupon: choose either Rails or HTML" -# one_month_discount: "discount, 30% off: choose either Rails or HTML" -# license: "license" -# oreilly: "ebook of your choice" - -# loading_error: -# could_not_load: "Error loading from server" -# connection_failure: "Connection failed." -# unauthorized: "You need to be signed in. Do you have cookies disabled?" -# forbidden: "You do not have the permissions." -# not_found: "Not found." -# not_allowed: "Method not allowed." -# timeout: "Server timeout." -# conflict: "Resource conflict." -# bad_input: "Bad input." -# server_error: "Server error." -# unknown: "Unknown error." - -# resources: -# sessions: "Sessions" -# your_sessions: "Your Sessions" -# level: "Level" -# social_network_apis: "Social Network APIs" -# facebook_status: "Facebook Status" -# facebook_friends: "Facebook Friends" -# facebook_friend_sessions: "Facebook Friend Sessions" -# gplus_friends: "G+ Friends" -# gplus_friend_sessions: "G+ Friend Sessions" -# leaderboard: "Leaderboard" -# user_schema: "User Schema" -# user_profile: "User Profile" -# patches: "Patches" -# patched_model: "Source Document" -# model: "Model" -# system: "System" -# systems: "Systems" -# component: "Component" -# components: "Components" -# thang: "Thang" -# thangs: "Thangs" -# level_session: "Your Session" -# opponent_session: "Opponent Session" -# article: "Article" -# user_names: "User Names" -# thang_names: "Thang Names" -# files: "Files" -# top_simulators: "Top Simulators" -# source_document: "Source Document" -# document: "Document" -# sprite_sheet: "Sprite Sheet" -# employers: "Employers" -# candidates: "Candidates" -# candidate_sessions: "Candidate Sessions" -# user_remark: "User Remark" -# user_remarks: "User Remarks" -# versions: "Versions" -# items: "Items" -# wizard: "Wizard" -# achievement: "Achievement" -# clas: "CLAs" -# play_counts: "Play Counts" - -# delta: -# added: "Added" -# modified: "Modified" -# deleted: "Deleted" -# moved_index: "Moved Index" -# text_diff: "Text Diff" -# merge_conflict_with: "MERGE CONFLICT WITH" -# no_changes: "No Changes" - -# user: -# stats: "Stats" -# singleplayer_title: "Singleplayer Levels" -# multiplayer_title: "Multiplayer Levels" -# achievements_title: "Achievements" -# last_played: "Last Played" -# status: "Status" -# status_completed: "Completed" -# status_unfinished: "Unfinished" -# no_singleplayer: "No Singleplayer games played yet." -# no_multiplayer: "No Multiplayer games played yet." -# no_achievements: "No Achievements earned yet." -# favorite_prefix: "Favorite language is " -# favorite_postfix: "." - -# achievements: -# last_earned: "Last Earned" -# amount_achieved: "Amount" -# achievement: "Achievement" -# category_contributor: "Contributor" -# category_miscellaneous: "Miscellaneous" -# category_levels: "Levels" -# category_undefined: "Uncategorized" -# current_xp_prefix: "" -# current_xp_postfix: " in total" -# new_xp_prefix: "" -# new_xp_postfix: " earned" -# left_xp_prefix: "" -# left_xp_infix: " until level " -# left_xp_postfix: "" - -# account: -# recently_played: "Recently Played" -# no_recent_games: "No games played during the past two weeks." diff --git a/app/models/Achievement.coffee b/app/models/Achievement.coffee index 723b2b0bf..93434d728 100644 --- a/app/models/Achievement.coffee +++ b/app/models/Achievement.coffee @@ -9,11 +9,9 @@ module.exports = class Achievement extends CocoModel isRepeatable: -> @get('proportionalTo')? - # TODO logic is duplicated in Mongoose Achievement schema getExpFunction: -> - kind = @get('function')?.kind or jsonschema.properties.function.default.kind - parameters = @get('function')?.parameters or jsonschema.properties.function.default.parameters - return utils.functionCreators[kind](parameters) if kind of utils.functionCreators + func = @get('function', true) + return utils.functionCreators[func.kind](func.parameters) if func.kind of utils.functionCreators @styleMapping: 1: 'achievement-wood' diff --git a/app/models/CocoModel.coffee b/app/models/CocoModel.coffee index 5e94cfd0d..44a99bee3 100644 --- a/app/models/CocoModel.coffee +++ b/app/models/CocoModel.coffee @@ -9,15 +9,12 @@ class CocoModel extends Backbone.Model notyErrors: true @schema: null - getMe: -> @me or @me = require('lib/auth').me - initialize: (attributes, options) -> super(arguments...) options ?= {} @setProjection options.project if not @constructor.className console.error("#{@} needs a className set.") - @addSchemaDefaults() @on 'sync', @onLoaded, @ @on 'error', @onError, @ @on 'add', @onLoaded, @ @@ -55,13 +52,33 @@ class CocoModel extends Backbone.Model getNormalizedURL: -> "#{@urlRoot}/#{@id}" + attributesWithDefaults: undefined + + get: (attribute, withDefault=false) -> + if withDefault + if @attributesWithDefaults is undefined then @buildAttributesWithDefaults() + return @attributesWithDefaults[attribute] + else + super(attribute) + set: -> + delete @attributesWithDefaults inFlux = @loading or not @loaded @markToRevert() unless inFlux or @_revertAttributes res = super(arguments...) @saveBackup() if @saveBackups and (not inFlux) and @hasLocalChanges() res + buildAttributesWithDefaults: -> + t0 = new Date() + clone = $.extend true, {}, @attributes + thisTV4 = tv4.freshApi() + thisTV4.addSchema('#', @schema()) + thisTV4.addSchema('metaschema', require('schemas/metaschema')) + TreemaNode.utils.populateDefaults(clone, @schema(), thisTV4) + @attributesWithDefaults = clone + console.debug "Populated defaults for #{@attributes.name or @type()} in #{new Date() - t0}ms" + loadFromBackup: -> return unless @saveBackups existing = storage.load @id @@ -142,6 +159,7 @@ class CocoModel extends Backbone.Model @_revertAttributes = $.extend(true, {}, @attributes) revert: -> + @clear({silent: true}) @set(@_revertAttributes, {silent: true}) if @_revertAttributes @clearBackup() @@ -162,59 +180,39 @@ class CocoModel extends Backbone.Model clone isPublished: -> - for permission in @get('permissions') or [] + for permission in (@get('permissions', true) ? []) return true if permission.target is 'public' and permission.access is 'read' false publish: -> if @isPublished() then throw new Error('Can\'t publish what\'s already-published. Can\'t kill what\'s already dead.') - @set 'permissions', (@get('permissions') or []).concat({access: 'read', target: 'public'}) - - addSchemaDefaults: -> - return if @addedSchemaDefaults - @addedSchemaDefaults = true - for prop, defaultValue of @constructor.schema.default or {} - continue if @get(prop)? - #console.log 'setting', prop, 'to', defaultValue, 'from attributes.default' - @set prop, defaultValue - for prop, sch of @constructor.schema.properties or {} - continue if @get(prop)? - continue if prop is 'emails' # hack, defaults are handled through User.coffee's email-specific methods. - #console.log 'setting', prop, 'to', sch.default, 'from sch.default' if sch.default? - @set prop, sch.default if sch.default? - if @loaded - @loadFromBackup() + @set 'permissions', @get('permissions', true).concat({access: 'read', target: 'public'}) @isObjectID: (s) -> s.length is 24 and s.match(/[a-f0-9]/gi)?.length is 24 hasReadAccess: (actor) -> # actor is a User object - - actor ?= @getMe() + actor ?= me return true if actor.isAdmin() - if @get('permissions')? - for permission in @get('permissions') - if permission.target is 'public' or actor.get('_id') is permission.target - return true if permission.access in ['owner', 'read'] + for permission in (@get('permissions', true) ? []) + if permission.target is 'public' or actor.get('_id') is permission.target + return true if permission.access in ['owner', 'read'] return false hasWriteAccess: (actor) -> # actor is a User object - - actor ?= @getMe() + actor ?= me return true if actor.isAdmin() - if @get('permissions')? - for permission in @get('permissions') - if permission.target is 'public' or actor.get('_id') is permission.target - return true if permission.access in ['owner', 'write'] + for permission in (@get('permissions', true) ? []) + if permission.target is 'public' or actor.get('_id') is permission.target + return true if permission.access in ['owner', 'write'] return false getOwner: -> - return null unless permissions = @get 'permissions' - ownerPermission = _.find permissions, access: 'owner' + ownerPermission = _.find @get('permissions', true), access: 'owner' ownerPermission?.target getDelta: -> diff --git a/app/models/Level.coffee b/app/models/Level.coffee index 8dca3da50..fc49d8dfb 100644 --- a/app/models/Level.coffee +++ b/app/models/Level.coffee @@ -12,25 +12,25 @@ module.exports = class Level extends CocoModel o = @denormalize supermodel, session # Figure out Components - o.levelComponents = _.cloneDeep (lc.attributes for lc in supermodel.getModels LevelComponent) - @sortThangComponents o.thangs, o.levelComponents + o.levelComponents = $.extend true, [], (lc.attributes for lc in supermodel.getModels LevelComponent) + @sortThangComponents o.thangs, o.levelComponents, 'Level Thang' @fillInDefaultComponentConfiguration o.thangs, o.levelComponents # Figure out Systems - systemModels = _.cloneDeep (ls.attributes for ls in supermodel.getModels LevelSystem) + systemModels = $.extend true, [], (ls.attributes for ls in supermodel.getModels LevelSystem) o.systems = @sortSystems o.systems, systemModels @fillInDefaultSystemConfiguration o.systems # Figure out ThangTypes' Components o.thangTypes = (original: tt.get('original'), name: tt.get('name'), components: $.extend(true, [], tt.get('components')) for tt in supermodel.getModels ThangType) - @sortThangComponents o.thangTypes, o.levelComponents + @sortThangComponents o.thangTypes, o.levelComponents, 'ThangType' @fillInDefaultComponentConfiguration o.thangTypes, o.levelComponents o denormalize: (supermodel, session) -> o = $.extend true, {}, @attributes - if @get('type') is 'hero' + if @get('type', true) is 'hero' # TOOD: figure out if/when/how we are doing this for non-Hero levels that aren't expecting denormalization. for levelThang in o.thangs @denormalizeThang(levelThang, supermodel, session) @@ -38,22 +38,22 @@ module.exports = class Level extends CocoModel denormalizeThang: (levelThang, supermodel, session) -> levelThang.components ?= [] - thangType = supermodel.getModelByOriginal(ThangType, levelThang.thangType) - # Empty out placeholder Components and store their values if we're the hero placeholder. placeholders = {} if levelThang.id is 'Hero Placeholder' - for thangComponent in levelThang.components ? [] + for thangComponent in levelThang.components placeholders[thangComponent.original] = thangComponent - levelThang.components = [] + levelThang.components = [] # We have stored the placeholder values, so we can inherit everything else. heroThangType = session?.get('heroConfig')?.thangType levelThang.thangType = heroThangType if heroThangType + thangType = supermodel.getModelByOriginal(ThangType, levelThang.thangType) + configs = {} for thangComponent in levelThang.components configs[thangComponent.original] = thangComponent - for defaultThangComponent in thangType.get('components') + for defaultThangComponent in thangType.get('components') or [] if levelThangComponent = configs[defaultThangComponent.original] # Take the ThangType default Components and merge level-specific Component config into it copy = $.extend true, {}, defaultThangComponent.config @@ -79,6 +79,7 @@ module.exports = class Level extends CocoModel if levelThang.id is 'Hero Placeholder' and equips = _.find levelThang.components, {original: LevelComponent.EquipsID} inventory = session?.get('heroConfig')?.inventory + equips.config ?= {} equips.config.inventory = $.extend true, {}, inventory if inventory @@ -92,12 +93,12 @@ module.exports = class Level extends CocoModel system2 = _.find levelSystems, {original: d.original} visit system2 #console.log 'sorted systems adding', systemModel.name - sorted.push {model: systemModel, config: _.cloneDeep system.config} + sorted.push {model: systemModel, config: $.extend true, {}, system.config} originalsSeen[system.original] = true - visit system for system in levelSystems + visit system for system in levelSystems ? [] sorted - sortThangComponents: (thangs, levelComponents) -> + sortThangComponents: (thangs, levelComponents, parentType) -> # Here we have to sort the Components by their dependencies. # It's a bit tricky though, because we don't have either soft dependencies or priority levels. # Example: Programmable must come last, since it has to override any Component-provided methods that any other Component might have created. Can't enumerate all soft dependencies. @@ -105,7 +106,7 @@ module.exports = class Level extends CocoModel # Decision? Just special case the sort logic in here until we have more examples than these two and decide how best to handle most of the cases then, since we don't really know the whole of the problem yet. # TODO: anything that depends on Programmable will break right now. - for thang in thangs + for thang in thangs ? [] sorted = [] visit = (c) -> return if c in sorted @@ -118,7 +119,10 @@ module.exports = class Level extends CocoModel else for d in lc.dependencies or [] c2 = _.find thang.components, {original: d.original} - console.error thang.id or thang.name, 'couldn\'t find dependent Component', d.original, 'from', lc.name unless c2 + unless c2 + dependent = _.find levelComponents, {original: d.original} + dependent = dependent?.name or d.original + console.error parentType, thang.id or thang.name, 'does not have dependent Component', dependent, 'from', lc.name visit c2 if c2 if lc.name is 'Collides' allied = _.find levelComponents, {name: 'Allied'} @@ -132,22 +136,30 @@ module.exports = class Level extends CocoModel thang.components = sorted fillInDefaultComponentConfiguration: (thangs, levelComponents) -> - for thang in thangs + for thang in thangs ? [] for component in thang.components or [] continue unless lc = _.find levelComponents, {original: component.original} component.config ?= {} + TreemaUtils.populateDefaults(component.config, lc.configSchema, tv4) + @lastType = 'component' + @lastOriginal = component.original @walkDefaults component.config, lc.configSchema.properties fillInDefaultSystemConfiguration: (levelSystems) -> for system in levelSystems ? [] system.config ?= {} + TreemaUtils.populateDefaults(system.config, system.model.configSchema, tv4) + @lastType = 'system' + @lastOriginal = system.model.name @walkDefaults system.config, system.model.configSchema.properties walkDefaults: (config, properties) -> + # This function is redundant, but is the old implementation. + # Remove it and calls to it once we stop seeing these warnings. return unless properties for prop, schema of properties if schema.default? and config[prop] is undefined - #console.log 'Setting default of', config, 'for', prop, 'to', schema.default + console.warn 'Setting default of', config, 'for', prop, 'to', schema.default, 'but this method is deprecated... check your config schema!', @lastType, @lastOriginal config[prop] = schema.default if schema.type is 'object' and config[prop] @walkDefaults config[prop], schema.properties diff --git a/app/models/LevelComponent.coffee b/app/models/LevelComponent.coffee index 6353e9684..6c0dbbc65 100644 --- a/app/models/LevelComponent.coffee +++ b/app/models/LevelComponent.coffee @@ -3,10 +3,14 @@ CocoModel = require './CocoModel' module.exports = class LevelComponent extends CocoModel @className: 'LevelComponent' @schema: require 'schemas/models/level_component' - + @EquipsID: '53e217d253457600003e3ebb' @ItemID: '53e12043b82921000051cdf9' @AttacksID: '524b7ba57fc0f6d519000016' + @PhysicalID: '524b75ad7fc0f6d519000001' + @ExistsID: '524b4150ff92f1f4f8000024' + @LandID: '524b7aff7fc0f6d519000006' + @CollidesID: '524b7b857fc0f6d519000012' urlRoot: '/db/level.component' set: (key, val, options) -> diff --git a/app/models/LevelSession.coffee b/app/models/LevelSession.coffee index 34b03be6d..ba87aef23 100644 --- a/app/models/LevelSession.coffee +++ b/app/models/LevelSession.coffee @@ -13,7 +13,7 @@ module.exports = class LevelSession extends CocoModel @set('state', state) updatePermissions: -> - permissions = @get 'permissions' + permissions = @get 'permissions', true permissions = (p for p in permissions when p.target isnt 'public') if @get('multiplayer') permissions.push {target: 'public', access: 'write'} diff --git a/app/models/SuperModel.coffee b/app/models/SuperModel.coffee index cd7db688b..07cafff46 100644 --- a/app/models/SuperModel.coffee +++ b/app/models/SuperModel.coffee @@ -60,7 +60,6 @@ module.exports = class SuperModel extends Backbone.Model @addCollection collection onCollectionSynced = (c) -> if collection.url is c.url - console.debug 'Registering collection', url, c @registerCollection c else console.warn 'Sync triggered for collection', c @@ -84,14 +83,15 @@ module.exports = class SuperModel extends Backbone.Model getModelByURL: (modelURL) -> modelURL = modelURL() if _.isFunction(modelURL) return @models[modelURL] or null - + getModelByOriginal: (ModelClass, original) -> _.find @models, (m) -> m.get('original') is original and m.constructor.className is ModelClass.className getModelByOriginalAndMajorVersion: (ModelClass, original, majorVersion=0) -> _.find @models, (m) -> - m.get('original') is original and m.get('version').major is majorVersion and m.constructor.className is ModelClass.className + return unless v = m.get('version') + m.get('original') is original and v.major is majorVersion and m.constructor.className is ModelClass.className getModels: (ModelClass) -> # can't use instanceof. SuperModel gets passed between windows, and one window @@ -119,7 +119,9 @@ module.exports = class SuperModel extends Backbone.Model for model, i in collection.models cachedModel = @getModelByURL(model.getURL()) if cachedModel - collection.models[i] = cachedModel + clone = $.extend true, {}, model.attributes + cachedModel.set(clone, {silent: true}) + console.debug "Updated cached model <#{cachedModel.get('name') or cachedModel.getURL()}> with new data" else @registerModel(model) collection diff --git a/app/models/ThangType.coffee b/app/models/ThangType.coffee index 8a8d990ea..c74373c57 100644 --- a/app/models/ThangType.coffee +++ b/app/models/ThangType.coffee @@ -13,8 +13,6 @@ module.exports = class ThangType extends CocoModel initialize: -> super() @building = {} - @setDefaults() - @on 'sync', @setDefaults @spriteSheets = {} ## Testing memory clearing @@ -24,9 +22,6 @@ module.exports = class ThangType extends CocoModel # @_previousAttributes.raw = null #setTimeout f, 40000 - setDefaults: -> - @resetRawData() unless @get('raw') - resetRawData: -> @set('raw', {shapes: {}, containers: {}, animations: {}}) @@ -67,7 +62,7 @@ module.exports = class ThangType extends CocoModel options buildSpriteSheet: (options) -> - return false unless @isFullyLoaded() + return false unless @isFullyLoaded() and @get 'raw' @options = @fillOptions options key = @spriteSheetKey(@options) if ss = @spriteSheets[key] then return ss @@ -205,6 +200,7 @@ module.exports = class ThangType extends CocoModel $('').attr('src', src) getPortraitSource: (spriteOptionsOrKey, size=100) -> + return @getPortraitURL() if @get 'rasterIcon' stage = @getPortraitStage(spriteOptionsOrKey, size) stage?.toDataURL() @@ -279,43 +275,45 @@ module.exports = class ThangType extends CocoModel return itemComponentRef?.config?.slots or [] getFrontFacingStats: -> - stats = [] - for component in @get('components') or [] + components = @get('components') or [] + unless itemConfig = _.find(components, original: LevelComponent.ItemID)?.config + console.warn @get('name'), 'is not an item, but you are asking for its stats.' + return props: [], stats: {} + props = itemConfig.programmableProperties ? [] + props = props.concat itemConfig.moreProgrammableProperties ? [] + stats = {} + for stat, modifiers of itemConfig.stats ? {} + stats[stat] = @formatStatDisplay stat, modifiers + for stat in itemConfig.extraHUDProperties ? [] + stats[stat] = null # Find it in the other Components. + for component in components continue unless config = component.config - if config.attackDamage - stats.push { name: 'Attack Damage', value: config.attackDamage } - if config.attackRange - stats.push { name: 'Attack Range', value: "#{config.attackRange}m" } - if config.cooldown - stats.push { name: 'Cooldown', value: "#{config.cooldown}s" } - if config.maxSpeed - stats.push { name: 'Speed', value: "#{config.maxSpeed}m/s" } - if config.maxAcceleration - stats.push { name: 'Acceleration', value: "#{config.maxAcceleration}m/s^2" } - if config.stats - for stat, value of config.stats - if value.factor - value = "x#{value.factor}" - if value.addend and value.addend > 0 - value = "+#{value.addend}" - if value.addend and value.addend < 0 - value = "#{value.addend}" - if value.setTo - value = "=#{value.setTo}" - if stat is 'maxHealth' - stats.push { name: 'Health', value: value } - if stat is 'healthReplenishRate' - stats.push { name: 'Regen', value: value } - if config.programmableProperties - props = config.programmableProperties - if props.length - stats.push { name: 'Allows', value: props.join(', ') } - if config.visualRange - value = config.visualRange - if value is 9001 then value is "Infinite" - stats.push { name: 'Visual Range', value: "#{value}m"} + for stat, value of stats when not value? + value = config[stat] + continue unless value? + stats[stat] = @formatStatDisplay stat, setTo: value + if stat is 'attackDamage' + dps = (value / (config.cooldown or 0.5)).toFixed(1) + stats[stat].display += " (#{dps} DPS)" if config.programmableSnippets - snippets = config.programmableSnippets - if snippets.length - stats.push { name: 'Snippets', value: snippets.join(', ') } - stats + props = props.concat config.programmableSnippets + props: props, stats: stats + + formatStatDisplay: (name, modifiers) -> + name = {maxHealth: 'Health', maxSpeed: 'Speed', healthReplenishRate: 'Regeneration'}[name] ? name + name = _.string.humanize name + format = '' + format = 'm' if /(range|radius|distance)$/i.test name + format ||= 's' if /cooldown$/i.test name + format ||= 'm/s' if /speed$/i.test name + format ||= '/s' if /(regeneration| rate)$/i.test name + value = modifiers.setTo + value = value.join ', ' if _.isArray value + display = [] + display.push "#{value}#{format}" if value? + display.push "+#{modifiers.addend}#{format}" if modifiers.addend > 0 + display.push "#{modifiers.addend}#{format}" if modifiers.addend < 0 + display.push "x#{modifiers.factor}" if modifiers.factor? and modifiers.factor isnt 1 + display = display.join ', ' + display = display.replace /9001m?/, 'Infinity' + name: name, display: display diff --git a/app/models/User.coffee b/app/models/User.coffee index 7b492cdba..25071ac26 100644 --- a/app/models/User.coffee +++ b/app/models/User.coffee @@ -9,29 +9,13 @@ module.exports = class User extends CocoModel urlRoot: '/db/user' notyErrors: false - defaults: - points: 0 - - initialize: -> - super() - @migrateEmails() - onLoaded: -> CocoModel.pollAchievements() # Check for achievements on login super arguments... - isAdmin: -> - permissions = @attributes['permissions'] or [] - return 'admin' in permissions - - isAnonymous: -> - @get 'anonymous' - - displayName: -> - @get('name') or 'Anoner' - - lang: -> - @get('preferredLanguage') or 'en-US' + isAdmin: -> 'admin' in @get('permissions', true) + isAnonymous: -> @get('anonymous', true) + displayName: -> @get('name', true) getPhotoURL: (size=80, useJobProfilePhoto=false, useEmployerPageAvatar=false) -> photoURL = if useJobProfilePhoto then @get('jobProfile')?.photoURL else null @@ -57,33 +41,13 @@ module.exports = class User extends CocoModel done response.name getEnabledEmails: -> - @migrateEmails() - emails = _.clone(@get('emails')) or {} - emails = _.defaults emails, @schema().properties.emails.default - (emailName for emailName, emailDoc of emails when emailDoc.enabled) + (emailName for emailName, emailDoc of @get('emails', true) when emailDoc.enabled) setEmailSubscription: (name, enabled) -> newSubs = _.clone(@get('emails')) or {} (newSubs[name] ?= {}).enabled = enabled @set 'emails', newSubs - emailMap: - announcement: 'generalNews' - developer: 'archmageNews' - tester: 'adventurerNews' - level_creator: 'artisanNews' - article_editor: 'scribeNews' - translator: 'diplomatNews' - support: 'ambassadorNews' - notification: 'anyNotes' - - migrateEmails: -> - return if @attributes.emails or not @attributes.emailSubscriptions - oldSubs = @get('emailSubscriptions') or [] - newSubs = {} - newSubs[newSubName] = {enabled: oldSubName in oldSubs} for oldSubName, newSubName of @emailMap - @set('emails', newSubs) - isEmailSubscriptionEnabled: (name) -> (@get('emails') or {})[name]?.enabled a = 5 diff --git a/app/schemas/models/achievement.coffee b/app/schemas/models/achievement.coffee index 35bd36bba..fe45e03b5 100644 --- a/app/schemas/models/achievement.coffee +++ b/app/schemas/models/achievement.coffee @@ -38,15 +38,20 @@ c.extendNamedProperties AchievementSchema c.extendBasicProperties AchievementSchema, 'achievement' c.extendSearchableProperties AchievementSchema +AchievementSchema.default = + worth: 10 + description: 'Probably the coolest you\'ll ever get.' + difficulty: 1 + recalculable: true + function: {} + _.extend AchievementSchema.properties, query: #type:'object' $ref: '#/definitions/' + MongoFindQuerySchema.id worth: c.float - default: 10 collection: {type: 'string'} - description: c.shortString - default: 'Probably the coolest you\'ll ever get.' + description: c.shortString() userField: c.shortString() related: c.objectId(description: 'Related entity') icon: {type: 'string', format: 'image-file', title: 'Icon', description: 'Image should be a 100x100 transparent png.'} @@ -55,27 +60,26 @@ _.extend AchievementSchema.properties, description: 'For categorizing and display purposes' difficulty: c.int description: 'The higher the more difficult' - default: 1 proportionalTo: type: 'string' description: 'For repeatables only. Denotes the field a repeatable achievement needs for its calculations' recalculable: type: 'boolean' description: 'Needs to be set to true before it is elligible for recalculation.' - default: true function: type: 'object' description: 'Function that gives total experience for X amount achieved' properties: - kind: {enum: ['linear', 'logarithmic', 'quadratic'], default: 'linear'} + kind: {enum: ['linear', 'logarithmic', 'quadratic'] } parameters: type: 'object' + default: { a: 1, b: 0, c: 0 } properties: - a: {type: 'number', default: 1} - b: {type: 'number', default: 1} - c: {type: 'number', default: 1} + a: {type: 'number' } + b: {type: 'number' } + c: {type: 'number' } additionalProperties: true - default: {kind: 'linear', parameters: a: 1} + default: {kind: 'linear', parameters: {}} required: ['kind', 'parameters'] additionalProperties: false i18n: c.object diff --git a/app/schemas/models/earned_achievement.coffee b/app/schemas/models/earned_achievement.coffee index 12451ceac..04cfe9b91 100644 --- a/app/schemas/models/earned_achievement.coffee +++ b/app/schemas/models/earned_achievement.coffee @@ -3,6 +3,9 @@ c = require './../schemas' module.exports = EarnedAchievementSchema = type: 'object' + default: + previouslyAchievedAmount: 0 + properties: user: c.objectId links: @@ -26,5 +29,5 @@ module.exports = changed: type: 'date' achievedAmount: type: 'number' earnedPoints: type: 'number' - previouslyAchievedAmount: {type: 'number', default: 0} + previouslyAchievedAmount: {type: 'number'} notified: type: 'boolean' diff --git a/app/schemas/models/level.coffee b/app/schemas/models/level.coffee index 90bcde6c0..993eed92f 100644 --- a/app/schemas/models/level.coffee +++ b/app/schemas/models/level.coffee @@ -11,7 +11,7 @@ side = {title: 'Side', description: 'A side.', type: 'string', 'enum': ['left', thang = {title: 'Thang', description: 'The name of a Thang.', type: 'string', maxLength: 30, format: 'thang'} eventPrereqValueTypes = ['boolean', 'integer', 'number', 'null', 'string'] # not 'object' or 'array' -EventPrereqSchema = c.object {title: 'Event Prerequisite', format: 'event-prereq', description: 'Script requires that the value of some property on the event triggering it to meet some prerequisite.', 'default': {eventProps: []}, required: ['eventProps']}, +EventPrereqSchema = c.object {title: 'Event Prerequisite', format: 'event-prereq', description: 'Script requires that the value of some property on the event triggering it to meet some prerequisite.', required: ['eventProps']}, eventProps: c.array {'default': ['thang'], format: 'event-value-chain', maxItems: 10, title: 'Event Property', description: 'A chain of keys in the event, like "thang.pos.x" to access event.thang.pos.x.'}, c.shortString(title: 'Property', description: 'A key in the event property key chain.') equalTo: c.object {type: eventPrereqValueTypes, title: '==', description: 'Script requires the event\'s property chain value to be equal to this value.'} notEqualTo: c.object {type: eventPrereqValueTypes, title: '!=', description: 'Script requires the event\'s property chain value to *not* be equal to this value.'} @@ -30,7 +30,7 @@ GoalSchema = c.object {title: 'Goal', description: 'A goal that the player can a id: c.shortString(title: 'ID', description: 'Unique identifier for this goal, like \"defeat-dragons\".', pattern: '^[a-z0-9-]+$') # unique somehow? worldEndsAfter: {title: 'World Ends After', description: 'When included, ends the world this many seconds after this goal succeeds or fails.', type: 'number', minimum: 0, exclusiveMinimum: true, maximum: 300, default: 3} howMany: {title: 'How Many', description: 'When included, require only this many of the listed goal targets instead of all of them.', type: 'integer', minimum: 1} - hiddenGoal: {title: 'Hidden', description: 'Hidden goals don\'t show up in the goals area for the player until they\'re failed. (Usually they\'re obvious, like "don\'t die".)', 'type': 'boolean', default: false} + hiddenGoal: {title: 'Hidden', description: 'Hidden goals don\'t show up in the goals area for the player until they\'re failed. (Usually they\'re obvious, like "don\'t die".)', 'type': 'boolean' } team: c.shortString(title: 'Team', description: 'Name of the team this goal is for, if it is not for all of the playable teams.') killThangs: c.array {title: 'Kill Thangs', description: 'A list of Thang IDs the player should kill, or team names.', uniqueItems: true, minItems: 1, 'default': ['ogres']}, thang saveThangs: c.array {title: 'Save Thangs', description: 'A list of Thang IDs the player should save, or team names', uniqueItems: true, minItems: 1, 'default': ['humans']}, thang @@ -70,26 +70,26 @@ ResponseSchema = c.object {title: 'Dialogue Button', description: 'A button to b buttonClass: c.shortString(title: 'Button Class', description: 'CSS class that will be added to the button, like "btn-primary".') i18n: {type: 'object', format: 'i18n', props: ['text'], description: 'Help translate this button'} -PointSchema = c.object {title: 'Point', description: 'An {x, y} coordinate point.', format: 'point2d', required: ['x', 'y']}, - x: {title: 'x', description: 'The x coordinate.', type: 'number', 'default': 15} - y: {title: 'y', description: 'The y coordinate.', type: 'number', 'default': 20} +PointSchema = c.object {title: 'Point', description: 'An {x, y} coordinate point.', format: 'point2d', default: { x:15, y:20 }}, + x: {title: 'x', description: 'The x coordinate.', type: 'number'} + y: {title: 'y', description: 'The y coordinate.', type: 'number'} SpriteCommandSchema = c.object {title: 'Thang Command', description: 'Make a target Thang move or say something, or select/deselect it.', required: ['id'], default: {id: 'Captain Anya'}}, id: thang select: {title: 'Select', description: 'Select or deselect this Thang.', type: 'boolean'} - say: c.object {title: 'Say', description: 'Make this Thang say a message.', required: ['text']}, + say: c.object {title: 'Say', description: 'Make this Thang say a message.', required: ['text'], default: { mood: 'explain' }}, blurb: c.shortString(title: 'Blurb', description: 'A very short message to display above this Thang\'s head. Plain text.', maxLength: 50) - mood: c.shortString(title: 'Mood', description: 'The mood with which the Thang speaks.', 'enum': ['explain', 'debrief', 'congrats', 'attack', 'joke', 'tip', 'alarm'], 'default': 'explain') + mood: c.shortString(title: 'Mood', description: 'The mood with which the Thang speaks.', 'enum': ['explain', 'debrief', 'congrats', 'attack', 'joke', 'tip', 'alarm']) text: {title: 'Text', description: 'A short message to display in the dialogue area. Markdown okay.', type: 'string', maxLength: 400} - sound: c.object {title: 'Sound', description: 'A dialogue sound file to accompany the message.', required: ['mp3', 'ogg']}, + sound: c.object {title: 'Sound', description: 'A dialogue sound file to accompany the message.', required: ['mp3', 'ogg'] }, mp3: c.shortString(title: 'MP3', format: 'sound-file') ogg: c.shortString(title: 'OGG', format: 'sound-file') - preload: {title: 'Preload', description: 'Whether to load this sound file before the level can begin (typically for the first dialogue of a level).', type: 'boolean', 'default': false} + preload: {title: 'Preload', description: 'Whether to load this sound file before the level can begin (typically for the first dialogue of a level).', type: 'boolean' } responses: c.array {title: 'Buttons', description: 'An array of buttons to include with the dialogue, with which the user can respond.'}, ResponseSchema i18n: {type: 'object', format: 'i18n', props: ['blurb', 'text'], description: 'Help translate this message'} - move: c.object {title: 'Move', description: 'Tell the Thang to move.', required: ['target'], default: {target: {x: 20, y: 20}, duration: 500}}, - target: _.extend _.cloneDeep(PointSchema), {title: 'Target', description: 'Target point to which the Thang will move.'} - duration: {title: 'Duration', description: 'Number of milliseconds over which to move, or 0 for an instant move.', type: 'integer', minimum: 0, default: 500, format: 'milliseconds'} + move: c.object {title: 'Move', description: 'Tell the Thang to move.', required: ['target'], default: {target: {}, duration: 500}}, + target: _.extend _.cloneDeep(PointSchema), {title: 'Target', description: 'Target point to which the Thang will move.', default: {x: 20, y: 20}} + duration: {title: 'Duration', description: 'Number of milliseconds over which to move, or 0 for an instant move.', type: 'integer', minimum: 0, format: 'milliseconds'} NoteGroupSchema = c.object {title: 'Note Group', description: 'A group of notes that should be sent out as a result of this script triggering.', displayProperty: 'name'}, name: {title: 'Name', description: 'Short name describing the script, like \"Anya greets the player\", for your convenience.', type: 'string'} @@ -112,7 +112,7 @@ NoteGroupSchema = c.object {title: 'Note Group', description: 'A group of notes playback: c.object {title: 'Playback', description: 'Control the playback of the level.'}, playing: {type: 'boolean', title: 'Set Playing', description: 'Set whether playback is playing or paused.'} scrub: c.object {title: 'Scrub', description: 'Scrub the level playback time to a certain point.', default: {offset: 2, duration: 1000, toRatio: 0.5}}, - offset: {type: 'integer', title: 'Offset', description: 'Number of frames by which to adjust the scrub target time.', default: 2} + offset: {type: 'integer', title: 'Offset', description: 'Number of frames by which to adjust the scrub target time.'} duration: {type: 'integer', title: 'Duration', description: 'Number of milliseconds over which to scrub time.', minimum: 0, format: 'milliseconds'} toRatio: {type: 'number', title: 'To Progress Ratio', description: 'Set playback time to a target playback progress ratio.', minimum: 0, maximum: 1} toTime: {type: 'number', title: 'To Time', description: 'Set playback time to a target playback point, in seconds.', minimum: 0} @@ -152,7 +152,7 @@ ScriptSchema = c.object { id: c.shortString(title: 'ID', description: 'A unique ID that other scripts can rely on in their Happens After prereqs, for sequencing.') # uniqueness? channel: c.shortString(title: 'Event', format: 'event-channel', description: 'Event channel this script might trigger for, like "world:won".') eventPrereqs: c.array {title: 'Event Checks', description: 'Logical checks on the event for this script to trigger.', format: 'event-prereqs'}, EventPrereqSchema - repeats: {title: 'Repeats', description: 'Whether this script can trigger more than once during a level.', enum: [true, false, 'session'], 'default': false} + repeats: {title: 'Repeats', description: 'Whether this script can trigger more than once during a level.', enum: [true, false, 'session']} scriptPrereqs: c.array {title: 'Happens After', description: 'Scripts that need to fire first.'}, c.shortString(title: 'ID', description: 'A unique ID of a script.') notAfter: c.array {title: 'Not After', description: 'Do not run this script if any of these scripts have run.'}, @@ -185,7 +185,7 @@ LevelSystemSchema = c.object { }, original: c.objectId(title: 'Original', description: 'A reference to the original System being configured.', format: 'hidden') config: c.object {title: 'Configuration', description: 'System-specific configuration properties.', additionalProperties: true, format: 'level-system-configuration'} - majorVersion: {title: 'Major Version', description: 'Which major version of the System is being used.', type: 'integer', minimum: 0, default: 0, format: 'hidden'} + majorVersion: {title: 'Major Version', description: 'Which major version of the System is being used.', type: 'integer', minimum: 0, format: 'hidden'} GeneralArticleSchema = c.object { title: 'Article' @@ -203,20 +203,27 @@ GeneralArticleSchema = c.object { LevelSchema = c.object { title: 'Level' description: 'A spectacular level which will delight and educate its stalwart players with the sorcery of coding.' - required: ['name', 'description', 'scripts', 'thangs', 'documentation'] + required: ['name'] 'default': name: 'Ineffable Wizardry' description: 'This level is indescribably flarmy.' - documentation: {specificArticles: [], generalArticles: []} + documentation: {} scripts: [] thangs: [] + systems: [] + victory: {} + type: 'hero' + goals: [ + {id: 'ogres-die', name: 'Ogres must die.', killThangs: ['ogres'], worldEndsAfter: 3} + {id: 'humans-survive', name: 'Humans must survive.', saveThangs: ['humans'], howMany: 1, worldEndsAfter: 3, hiddenGoal: true} + ] } c.extendNamedProperties LevelSchema # let's have the name be the first property _.extend LevelSchema.properties, - description: {title: 'Description', description: 'A short explanation of what this level is about.', type: 'string', maxLength: 65536, 'default': 'This level is indescribably flarmy!', format: 'markdown'} + description: {title: 'Description', description: 'A short explanation of what this level is about.', type: 'string', maxLength: 65536, format: 'markdown'} documentation: c.object {title: 'Documentation', description: 'Documentation articles relating to this level.', required: ['specificArticles', 'generalArticles'], 'default': {specificArticles: [], generalArticles: []}}, - specificArticles: c.array {title: 'Specific Articles', description: 'Specific documentation articles that live only in this level.', uniqueItems: true, 'default': []}, SpecificArticleSchema - generalArticles: c.array {title: 'General Articles', description: 'General documentation articles that can be linked from multiple levels.', uniqueItems: true, 'default': []}, GeneralArticleSchema + specificArticles: c.array {title: 'Specific Articles', description: 'Specific documentation articles that live only in this level.', uniqueItems: true }, SpecificArticleSchema + generalArticles: c.array {title: 'General Articles', description: 'General documentation articles that can be linked from multiple levels.', uniqueItems: true}, GeneralArticleSchema background: c.objectId({format: 'hidden'}) nextLevel: { type: 'object', @@ -226,15 +233,19 @@ _.extend LevelSchema.properties, description: 'Reference to the next level players will play after beating this one.' } employerDescription: { type:'string', format: 'markdown', title: 'Employer Description' } - scripts: c.array {title: 'Scripts', description: 'An array of scripts that trigger based on what the player does and affect things outside of the core level simulation.', 'default': []}, ScriptSchema - thangs: c.array {title: 'Thangs', description: 'An array of Thangs that make up the level.', 'default': []}, LevelThangSchema - systems: c.array {title: 'Systems', description: 'Levels are configured by changing the Systems attached to them.', uniqueItems: true, default: []}, LevelSystemSchema # TODO: uniqueness should be based on 'original', not whole thing - victory: c.object {title: 'Victory Screen', default: {}, properties: {'body': {type: 'string', format: 'markdown', title: 'Body Text', description: 'Inserted into the Victory Modal once this level is complete. Tell the player they did a good job and what they accomplished!'}, i18n: {type: 'object', format: 'i18n', props: ['body'], description: 'Help translate this victory message'}}} + scripts: c.array {title: 'Scripts', description: 'An array of scripts that trigger based on what the player does and affect things outside of the core level simulation.'}, ScriptSchema + thangs: c.array {title: 'Thangs', description: 'An array of Thangs that make up the level.' }, LevelThangSchema + systems: c.array {title: 'Systems', description: 'Levels are configured by changing the Systems attached to them.', uniqueItems: true }, LevelSystemSchema # TODO: uniqueness should be based on 'original', not whole thing + victory: c.object {title: 'Victory Screen'}, { + body: {type: 'string', format: 'markdown', title: 'Body Text', description: 'Inserted into the Victory Modal once this level is complete. Tell the player they did a good job and what they accomplished!'}, + i18n: {type: 'object', format: 'i18n', props: ['body'], description: 'Help translate this victory message'} + } i18n: {type: 'object', format: 'i18n', props: ['name', 'description'], description: 'Help translate this level'} icon: {type: 'string', format: 'image-file', title: 'Icon'} banner: {type: 'string', format: 'image-file', title: 'Banner'} goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema type: c.shortString(title: 'Type', description: 'What kind of level this is.', 'enum': ['campaign', 'ladder', 'ladder-tutorial', 'hero']) + terrain: c.terrainString showsGuide: c.shortString(title: 'Shows Guide', description: 'If the guide is shown at the beginning of the level.', 'enum': ['first-time', 'always']) c.extendBasicProperties LevelSchema, 'level' diff --git a/app/schemas/models/level_component.coffee b/app/schemas/models/level_component.coffee index 162abc617..40e55800e 100644 --- a/app/schemas/models/level_component.coffee +++ b/app/schemas/models/level_component.coffee @@ -16,7 +16,7 @@ systems = [ PropertyDocumentationSchema = c.object { title: 'Property Documentation' description: 'Documentation entry for a property this Component will add to its Thang which other Components might want to also use.' - 'default': + default: name: 'foo' type: 'object' description: 'The `foo` property can satisfy all the #{spriteName}\'s foobar needs. Use it wisely.' @@ -88,9 +88,6 @@ PropertyDocumentationSchema = c.object { DependencySchema = c.object { title: 'Component Dependency' description: 'A Component upon which this Component depends.' - 'default': - #original: ? - majorVersion: 0 required: ['original', 'majorVersion'] format: 'latest-version-reference' links: [{rel: 'db', href: '/db/level.component/{(original)}/version/{(majorVersion)}'}] @@ -106,7 +103,7 @@ LevelComponentSchema = c.object { title: 'Component' description: 'A Component which can affect Thang behavior.' required: ['system', 'name', 'description', 'code', 'dependencies', 'propertyDocumentation', 'codeLanguage'] - 'default': + default: system: 'ai' name: 'AttacksSelf' description: 'This Component makes the Thang attack itself.' @@ -114,6 +111,7 @@ LevelComponentSchema = c.object { codeLanguage: 'coffeescript' dependencies: [] # TODO: should depend on something by default propertyDocumentation: [] + configSchema: {} } c.extendNamedProperties LevelComponentSchema # let's have the name be the first property LevelComponentSchema.properties.name.pattern = c.classNamePattern @@ -123,13 +121,11 @@ _.extend LevelComponentSchema.properties, description: 'The short name of the System this Component belongs to, like \"ai\".' type: 'string' 'enum': systems - 'default': 'ai' description: title: 'Description' description: 'A short explanation of what this Component does.' type: 'string' maxLength: 2000 - 'default': 'This Component makes the Thang attack itself.' codeLanguage: type: 'string' title: 'Language' @@ -138,7 +134,6 @@ _.extend LevelComponentSchema.properties, code: title: 'Code' description: 'The code for this Component, as a CoffeeScript class. TODO: add link to documentation for how to write these.' - 'default': attackSelfCode type: 'string' format: 'coffee' js: @@ -146,14 +141,13 @@ _.extend LevelComponentSchema.properties, description: 'The transpiled JavaScript code for this Component' type: 'string' format: 'hidden' - dependencies: c.array {title: 'Dependencies', description: 'An array of Components upon which this Component depends.', 'default': [], uniqueItems: true}, DependencySchema - propertyDocumentation: c.array {title: 'Property Documentation', description: 'An array of documentation entries for each notable property this Component will add to its Thang which other Components might want to also use.', 'default': []}, PropertyDocumentationSchema - configSchema: _.extend metaschema, {title: 'Configuration Schema', description: 'A schema for validating the arguments that can be passed to this Component as configuration.', default: {type: 'object', additionalProperties: false}} + dependencies: c.array {title: 'Dependencies', description: 'An array of Components upon which this Component depends.', uniqueItems: true}, DependencySchema + propertyDocumentation: c.array {title: 'Property Documentation', description: 'An array of documentation entries for each notable property this Component will add to its Thang which other Components might want to also use.'}, PropertyDocumentationSchema + configSchema: _.extend metaschema, {title: 'Configuration Schema', description: 'A schema for validating the arguments that can be passed to this Component as configuration.', default: {type: 'object'}} official: type: 'boolean' title: 'Official' description: 'Whether this is an official CodeCombat Component.' - 'default': false c.extendBasicProperties LevelComponentSchema, 'level.component' c.extendSearchableProperties LevelComponentSchema diff --git a/app/schemas/models/level_feedback.coffee b/app/schemas/models/level_feedback.coffee index ce0374d8b..fe7517057 100644 --- a/app/schemas/models/level_feedback.coffee +++ b/app/schemas/models/level_feedback.coffee @@ -2,7 +2,7 @@ c = require './../schemas' LevelFeedbackLevelSchema = c.object {required: ['original', 'majorVersion']}, { original: c.objectId({}) - majorVersion: {type: 'integer', minimum: 0, default: 0}} + majorVersion: {type: 'integer', minimum: 0 }} LevelFeedbackSchema = c.object { title: 'Feedback' diff --git a/app/schemas/models/level_session.coffee b/app/schemas/models/level_session.coffee index 235052c53..7fa0bbb15 100644 --- a/app/schemas/models/level_session.coffee +++ b/app/schemas/models/level_session.coffee @@ -18,11 +18,14 @@ LevelSessionLevelSchema = c.object {required: ['original', 'majorVersion'], link majorVersion: type: 'integer' minimum: 0 - default: 0 LevelSessionSchema = c.object title: 'Session' description: 'A single session for a given level.' + default: + codeLanguage: 'javascript' + submittedCodeLanguage: 'javascript' + playtime: 0 _.extend LevelSessionSchema.properties, # denormalization @@ -119,16 +122,14 @@ _.extend LevelSessionSchema.properties, type: 'object' additionalProperties: type: 'string' - format: 'javascript' + format: 'code' codeLanguage: type: 'string' - default: 'javascript' playtime: type: 'number' title: 'Playtime' - default: 0 description: 'The total playtime on this session' teamSpells: @@ -164,10 +165,10 @@ _.extend LevelSessionSchema.properties, type: 'object' additionalProperties: type: 'string' + format: 'code' submittedCodeLanguage: type: 'string' - default: 'javascript' transpiledCode: type: 'object' @@ -175,6 +176,7 @@ _.extend LevelSessionSchema.properties, type: 'object' additionalProperties: type: 'string' + format: 'code' isRanking: type: 'boolean' diff --git a/app/schemas/models/level_system.coffee b/app/schemas/models/level_system.coffee index 13f97e545..218e4a0e0 100644 --- a/app/schemas/models/level_system.coffee +++ b/app/schemas/models/level_system.coffee @@ -21,7 +21,7 @@ class Jitter extends System PropertyDocumentationSchema = c.object { title: 'Property Documentation' description: 'Documentation entry for a property this System will add to its Thang which other Systems might want to also use.' - 'default': + default: name: 'foo' type: 'object' description: 'This System provides a "foo" property to satisfy all one\'s foobar needs. Use it wisely.' @@ -36,9 +36,6 @@ PropertyDocumentationSchema = c.object { DependencySchema = c.object { title: 'System Dependency' description: 'A System upon which this System depends.' - 'default': - #original: ? - majorVersion: 0 required: ['original', 'majorVersion'] format: 'latest-version-reference' links: [{rel: 'db', href: '/db/level.system/{(original)}/version/{(majorVersion)}'}] @@ -54,7 +51,7 @@ LevelSystemSchema = c.object { title: 'System' description: 'A System which can affect Level behavior.' required: ['name', 'description', 'code', 'dependencies', 'propertyDocumentation', 'codeLanguage'] - 'default': + default: name: 'JitterSystem' description: 'This System makes all idle, movable Thangs jitter around.' code: jitterSystemCode @@ -70,7 +67,6 @@ _.extend LevelSystemSchema.properties, description: 'A short explanation of what this System does.' type: 'string' maxLength: 2000 - 'default': 'This System doesn\'t do anything yet.' codeLanguage: type: 'string' title: 'Language' @@ -79,7 +75,6 @@ _.extend LevelSystemSchema.properties, code: title: 'Code' description: 'The code for this System, as a CoffeeScript class. TODO: add link to documentation for how to write these.' - 'default': jitterSystemCode type: 'string' format: 'coffee' js: @@ -87,14 +82,13 @@ _.extend LevelSystemSchema.properties, description: 'The transpiled JavaScript code for this System' type: 'string' format: 'hidden' - dependencies: c.array {title: 'Dependencies', description: 'An array of Systems upon which this System depends.', 'default': [], uniqueItems: true}, DependencySchema - propertyDocumentation: c.array {title: 'Property Documentation', description: 'An array of documentation entries for each notable property this System will add to its Level which other Systems might want to also use.', 'default': []}, PropertyDocumentationSchema + dependencies: c.array {title: 'Dependencies', description: 'An array of Systems upon which this System depends.', uniqueItems: true}, DependencySchema + propertyDocumentation: c.array {title: 'Property Documentation', description: 'An array of documentation entries for each notable property this System will add to its Level which other Systems might want to also use.'}, PropertyDocumentationSchema configSchema: _.extend metaschema, {title: 'Configuration Schema', description: 'A schema for validating the arguments that can be passed to this System as configuration.', default: {type: 'object', additionalProperties: false}} official: type: 'boolean' title: 'Official' description: 'Whether this is an official CodeCombat System.' - 'default': false c.extendBasicProperties LevelSystemSchema, 'level.system' c.extendSearchableProperties LevelSystemSchema diff --git a/app/schemas/models/thang_component.coffee b/app/schemas/models/thang_component.coffee index 97b5e18d8..9daf0b3dd 100644 --- a/app/schemas/models/thang_component.coffee +++ b/app/schemas/models/thang_component.coffee @@ -5,7 +5,7 @@ module.exports = ThangComponentSchema = c.object { description: 'Configuration for a Component that this Thang uses.' format: 'component-reference' required: ['original', 'majorVersion'] - 'default': + default: majorVersion: 0 config: {} links: [{rel: 'db', href: '/db/level.component/{(original)}/version/{(majorVersion)}'}] @@ -17,5 +17,4 @@ module.exports = ThangComponentSchema = c.object { description: 'Which major version of the Component is being used.' type: 'integer' minimum: 0 - default: 0 format: 'hidden' diff --git a/app/schemas/models/thang_type.coffee b/app/schemas/models/thang_type.coffee index 5b7e4851e..c01c41878 100644 --- a/app/schemas/models/thang_type.coffee +++ b/app/schemas/models/thang_type.coffee @@ -1,7 +1,7 @@ c = require './../schemas' ThangComponentSchema = require './thang_component' -ThangTypeSchema = c.object() +ThangTypeSchema = c.object default: {kind: 'Misc'} c.extendNamedProperties ThangTypeSchema # name first ShapeObjectSchema = c.object {title: 'Shape'}, @@ -101,11 +101,12 @@ ActionSchema = c.object {}, SoundSchema = c.sound({delay: {type: 'number'}}) _.extend ThangTypeSchema.properties, - raw: c.object {title: 'Raw Vector Data'}, + raw: c.object {title: 'Raw Vector Data', default: {shapes: {}, containers: {}, animations: {}}}, shapes: c.object {title: 'Shapes', additionalProperties: ShapeObjectSchema} containers: c.object {title: 'Containers', additionalProperties: ContainerObjectSchema} animations: c.object {title: 'Animations', additionalProperties: RawAnimationObjectSchema} kind: c.shortString {enum: ['Unit', 'Floor', 'Wall', 'Doodad', 'Misc', 'Mark', 'Item'], default: 'Misc', title: 'Kind'} + terrains: c.array {title: 'Terrains', description: 'If specified, limits this ThangType to levels with matching terrains.', uniqueItems: true}, c.terrainString actions: c.object {title: 'Actions', additionalProperties: {$ref: '#/definitions/action'}} soundTriggers: c.object {title: 'Sound Triggers', additionalProperties: c.array({}, {$ref: '#/definitions/sound'})}, @@ -131,19 +132,22 @@ _.extend ThangTypeSchema.properties, type: 'array' format: 'thang-color-group' items: {type: 'string'} - snap: c.object {title: 'Snap', description: 'In the level editor, snap positioning to these intervals.', required: ['x', 'y']}, + snap: c.object {title: 'Snap', description: 'In the level editor, snap positioning to these intervals.', required: ['x', 'y'], default: {x: 4, y: 4}}, x: title: 'Snap X' type: 'number' description: 'Snap to this many meters in the x-direction.' - default: 4 y: title: 'Snap Y' type: 'number' description: 'Snap to this many meters in the y-direction.' - default: 4 components: c.array {title: 'Components', description: 'Thangs are configured by changing the Components attached to them.', uniqueItems: true, format: 'thang-components-array'}, ThangComponentSchema # TODO: uniqueness should be based on 'original', not whole thing +ThangTypeSchema.required = ['kind'] + +ThangTypeSchema.default = + raw: {} + ThangTypeSchema.definitions = action: ActionSchema sound: SoundSchema diff --git a/app/schemas/models/user.coffee b/app/schemas/models/user.coffee index 9f289f806..428cb7c0c 100644 --- a/app/schemas/models/user.coffee +++ b/app/schemas/models/user.coffee @@ -3,6 +3,20 @@ emailSubscriptions = ['announcement', 'tester', 'level_creator', 'developer', 'a UserSchema = c.object title: 'User' + default: + visa: 'Authorized to work in the US' + music: true + name: 'Anoner' + autocastDelay: 5000 + emails: {} + permissions: [] + anonymous: true + points: 0 + preferredLanguage: 'en-US' + aceConfig: {} + simulatedBy: 0 + simulatedFor: 0 + jobProfile: {} c.extendNamedProperties UserSchema # let's have the name be the first property @@ -31,8 +45,7 @@ visa = c.shortString title: 'US Work Status' description: 'Are you authorized to work in the US, or do you need visa sponsorship? (If you live in Canada or Australia, mark authorized.)' enum: ['Authorized to work in the US', 'Need visa sponsorship'] - default: 'Authorized to work in the US' - + _.extend UserSchema.properties, email: c.shortString({title: 'Email', format: 'email'}) firstName: c.shortString({title: 'First Name'}) @@ -48,12 +61,12 @@ _.extend UserSchema.properties, wizardColor1: c.pct({title: 'Wizard Clothes Color'}) volume: c.pct({title: 'Volume'}) - music: {type: 'boolean', default: true} - autocastDelay: {type: 'integer', 'default': 5000} - lastLevel: {type: 'string'} + music: { type: 'boolean' } + autocastDelay: { type: 'integer' } + lastLevel: { type: 'string' } emailSubscriptions: c.array {uniqueItems: true}, {'enum': emailSubscriptions} - emails: c.object {title: 'Email Settings', default: {generalNews: {enabled: true}, anyNotes: {enabled: true}, recruitNotes: {enabled: true}}}, + emails: c.object {title: 'Email Settings', default: generalNews: {enabled: true}, anyNotes: {enabled: true}, recruitNotes: {enabled: true} }, # newsletters generalNews: {$ref: '#/definitions/emailSubscription'} adventurerNews: {$ref: '#/definitions/emailSubscription'} @@ -69,9 +82,9 @@ _.extend UserSchema.properties, employerNotes: {$ref: '#/definitions/emailSubscription'} # server controlled - permissions: c.array {'default': []}, c.shortString() + permissions: c.array {}, c.shortString() dateCreated: c.date({title: 'Date Joined'}) - anonymous: {type: 'boolean', 'default': true} + anonymous: {type: 'boolean' } testGroupNumber: {type: 'integer', minimum: 0, maximum: 256, exclusiveMaximum: true} mailChimp: {type: 'object'} hourOfCode: {type: 'boolean'} @@ -85,36 +98,36 @@ _.extend UserSchema.properties, emailHash: {type: 'string'} #Internationalization stuff - preferredLanguage: {type: 'string', default: 'en', 'enum': c.getLanguageCodeArray()} + preferredLanguage: {type: 'string', 'enum': c.getLanguageCodeArray()} signedCLA: c.date({title: 'Date Signed the CLA'}) wizard: c.object {}, colorConfig: c.object {additionalProperties: c.colorConfig()} - aceConfig: c.object {}, - language: {type: 'string', 'default': 'javascript', 'enum': ['javascript', 'coffeescript', 'python', 'clojure', 'lua', 'io']} - keyBindings: {type: 'string', 'default': 'default', 'enum': ['default', 'vim', 'emacs']} - invisibles: {type: 'boolean', 'default': false} - indentGuides: {type: 'boolean', 'default': false} - behaviors: {type: 'boolean', 'default': false} - liveCompletion: {type: 'boolean', 'default': true} + aceConfig: c.object { default: { language: 'javascript', keyBindings: 'default', invisibles: false, indentGuides: false, behaviors: false, liveCompletion: true }}, + language: {type: 'string', 'enum': ['javascript', 'coffeescript', 'python', 'clojure', 'lua', 'io']} + keyBindings: {type: 'string', 'enum': ['default', 'vim', 'emacs']} + invisibles: {type: 'boolean' } + indentGuides: {type: 'boolean' } + behaviors: {type: 'boolean' } + liveCompletion: {type: 'boolean' } - simulatedBy: {type: 'integer', minimum: 0, default: 0} - simulatedFor: {type: 'integer', minimum: 0, default: 0} - - jobProfile: c.object {title: 'Job Profile', required: ['lookingFor', 'jobTitle', 'active', 'name', 'city', 'country', 'skills', 'experience', 'shortDescription', 'longDescription', 'visa', 'work', 'education', 'projects', 'links']}, - lookingFor: {title: 'Looking For', type: 'string', enum: ['Full-time', 'Part-time', 'Remote', 'Contracting', 'Internship'], default: 'Full-time', description: 'What kind of developer position do you want?'} - jobTitle: {type: 'string', maxLength: 50, title: 'Desired Job Title', description: 'What role are you looking for? Ex.: "Full Stack Engineer", "Front-End Developer", "iOS Developer"', default: 'Software Developer'} + simulatedBy: {type: 'integer', minimum: 0 } + simulatedFor: {type: 'integer', minimum: 0 } + + jobProfile: c.object {title: 'Job Profile', default: { active: false, lookingFor: 'Full-time', jobTitle: 'Software Developer', city: 'Defaultsville, CA', country: 'USA', skills: ['javascript'], shortDescription: 'Programmer seeking to build great software.', longDescription: '* I write great code.\n* You need great code?\n* Great!' }}, + lookingFor: {title: 'Looking For', type: 'string', enum: ['Full-time', 'Part-time', 'Remote', 'Contracting', 'Internship'], description: 'What kind of developer position do you want?'} + jobTitle: {type: 'string', maxLength: 50, title: 'Desired Job Title', description: 'What role are you looking for? Ex.: "Full Stack Engineer", "Front-End Developer", "iOS Developer"' } active: {title: 'Open to Offers', type: 'boolean', description: 'Want interview offers right now?'} updated: c.date {title: 'Last Updated', description: 'How fresh your profile appears to employers. Profiles go inactive after 4 weeks.'} name: c.shortString {title: 'Name', description: 'Name you want employers to see, like "Nick Winter".'} - city: c.shortString {title: 'City', description: 'City you want to work in (or live in now), like "San Francisco" or "Lubbock, TX".', default: 'Defaultsville, CA', format: 'city'} - country: c.shortString {title: 'Country', description: 'Country you want to work in (or live in now), like "USA" or "France".', default: 'USA', format: 'country'} - skills: c.array {title: 'Skills', description: 'Tag relevant developer skills in order of proficiency.', default: ['javascript'], minItems: 1, maxItems: 30, uniqueItems: true}, + city: c.shortString {title: 'City', description: 'City you want to work in (or live in now), like "San Francisco" or "Lubbock, TX".', format: 'city'} + country: c.shortString {title: 'Country', description: 'Country you want to work in (or live in now), like "USA" or "France".', format: 'country'} + skills: c.array {title: 'Skills', description: 'Tag relevant developer skills in order of proficiency', maxItems: 30, uniqueItems: true}, {type: 'string', minLength: 1, maxLength: 50, description: 'Ex.: "objective-c", "mongodb", "rails", "android", "javascript"', format: 'skill'} experience: {type: 'integer', title: 'Years of Experience', minimum: 0, description: 'How many years of professional experience (getting paid) developing software do you have?'} - shortDescription: {type: 'string', maxLength: 140, title: 'Short Description', description: 'Who are you, and what are you looking for? 140 characters max.', default: 'Programmer seeking to build great software.'} - longDescription: {type: 'string', maxLength: 600, title: 'Description', description: 'Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max.', format: 'markdown', default: '* I write great code.\n* You need great code?\n* Great!'} + shortDescription: {type: 'string', maxLength: 140, title: 'Short Description', description: 'Who are you, and what are you looking for? 140 characters max.' } + longDescription: {type: 'string', maxLength: 600, title: 'Description', description: 'Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max.', format: 'markdown' } visa: visa work: c.array {title: 'Work Experience', description: 'List your relevant work experience, most recent first.'}, c.object {title: 'Job', description: 'Some work experience you had.', required: ['employer', 'role', 'duration']}, @@ -130,14 +143,14 @@ _.extend UserSchema.properties, description: {type: 'string', title: 'Description', description: 'Highlight anything about this educational experience. (140 chars; optional)', maxLength: 140} projects: c.array {title: 'Projects (Top 3)', description: 'Highlight your projects to amaze employers.', maxItems: 3}, c.object {title: 'Project', description: 'A project you created.', required: ['name', 'description', 'picture'], default: {name: 'My Project', description: 'A project I worked on.', link: 'http://example.com', picture: ''}}, - name: c.shortString {title: 'Project Name', description: 'What was the project called?', default: 'My Project'} - description: {type: 'string', title: 'Description', description: 'Briefly describe the project.', maxLength: 400, default: 'A project I worked on.', format: 'markdown'} + name: c.shortString {title: 'Project Name', description: 'What was the project called?' } + description: {type: 'string', title: 'Description', description: 'Briefly describe the project.', maxLength: 400, format: 'markdown'} picture: {type: 'string', title: 'Picture', format: 'image-file', description: 'Upload a 230x115px or larger image showing off the project.'} - link: c.url {title: 'Link', description: 'Link to the project.', default: 'http://example.com'} + link: c.url {title: 'Link', description: 'Link to the project.'} links: c.array {title: 'Personal and Social Links', description: 'Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog.'}, - c.object {title: 'Link', description: 'A link to another site you want to highlight, like your GitHub, your LinkedIn, or your blog.', required: ['name', 'link']}, + c.object {title: 'Link', description: 'A link to another site you want to highlight, like your GitHub, your LinkedIn, or your blog.', required: ['name', 'link'], default: {link: 'http://example.com'}}, name: {type: 'string', maxLength: 30, title: 'Link Name', description: 'What are you linking to? Ex: "Personal Website", "GitHub"', format: 'link-name'} - link: c.url {title: 'Link', description: 'The URL.', default: 'http://example.com'} + link: c.url {title: 'Link', description: 'The URL.' } photoURL: {type: 'string', format: 'image-file', title: 'Profile Picture', description: 'Upload a 256x256px or larger image if you want to show a different profile picture to employers than your normal avatar.'} curated: c.object {title: 'Curated', required: ['shortDescription', 'mainTag', 'location', 'education', 'workHistory', 'phoneScreenFilter', 'schoolFilter', 'locationFilter', 'roleFilter', 'seniorityFilter']}, shortDescription: @@ -170,7 +183,7 @@ _.extend UserSchema.properties, description: 'Should this candidate be prominently featured on the site?' jobProfileApproved: {title: 'Job Profile Approved', type: 'boolean', description: 'Whether your profile has been approved by CodeCombat.'} jobProfileApprovedDate: c.date {title: 'Approved date', description: 'The date that the candidate was approved'} - jobProfileNotes: {type: 'string', maxLength: 1000, title: 'Our Notes', description: 'CodeCombat\'s notes on the candidate.', format: 'markdown', default: ''} + jobProfileNotes: {type: 'string', maxLength: 1000, title: 'Our Notes', description: 'CodeCombat\'s notes on the candidate.', format: 'markdown' } employerAt: c.shortString {description: 'If given employer permissions to view job candidates, for which employer?'} signedEmployerAgreement: c.object {}, linkedinID: c.shortString {title: 'LinkedInID', description: 'The user\'s LinkedIn ID when they signed the contract.'} @@ -253,10 +266,11 @@ _.extend UserSchema.properties, c.extendBasicProperties UserSchema, 'user' -c.definitions = - emailSubscription = +UserSchema.definitions = + emailSubscription: c.object { default: { enabled: true, count: 0 } }, { enabled: {type: 'boolean'} lastSent: c.date() count: {type: 'integer'} + } module.exports = UserSchema diff --git a/app/schemas/schemas.coffee b/app/schemas/schemas.coffee index ea6881729..0eb37689d 100644 --- a/app/schemas/schemas.coffee +++ b/app/schemas/schemas.coffee @@ -200,3 +200,5 @@ me.activity = me.object {description: 'Stats on an activity'}, first: me.date() last: me.date() count: {type: 'integer', minimum: 0} + +me.terrainString = me.shortString {enum: ['Grass', 'Dungeon', 'Indoor'], title: 'Terrain', description: 'Which terrain type this is.'} diff --git a/app/schemas/subscriptions/editor.coffee b/app/schemas/subscriptions/editor.coffee index 196723623..865f51071 100644 --- a/app/schemas/subscriptions/editor.coffee +++ b/app/schemas/subscriptions/editor.coffee @@ -5,7 +5,8 @@ module.exports = major: {type: 'boolean'} commitMessage: {type: 'string'} - 'editor:view-switched': c.object {title: 'Level View Switched', description: 'Published whenever the view switches'} + 'editor:view-switched': c.object {title: 'Level View Switched', description: 'Published whenever the view switches'}, + targetURL: {type: 'string'} 'editor:level-component-editing-ended': c.object {required: ['component']}, component: {type: 'object'} @@ -42,5 +43,16 @@ module.exports = 'level:reload-thang-type': c.object {required: ['thangType']}, thangType: {type: 'object'} - 'editor:random-terrain-generated': c.object {required: ['thangs']}, + 'editor:random-terrain-generated': c.object {required: ['thangs', 'terrain']}, thangs: c.array {}, {type: 'object'} + terrain: c.terrainString + + 'editor:terrain-changed': c.object {required: ['terrain']}, + terrain: + oneOf: [ + c.terrainString + {type: ['null', 'undefined']} + ] + + 'editor:thang-type-kind-changed': c.object {required: ['kind']}, + kind: {type: 'string'} diff --git a/app/schemas/subscriptions/misc.coffee b/app/schemas/subscriptions/misc.coffee index d279489ba..fbaa4b813 100644 --- a/app/schemas/subscriptions/misc.coffee +++ b/app/schemas/subscriptions/misc.coffee @@ -25,7 +25,7 @@ module.exports = viewClass: {type: 'function'} viewArgs: {type: 'array'} - 'achievements:new': c.object {required: 'earnedAchievements'}, + 'achievements:new': c.object {required: ['earnedAchievements']}, earnedAchievements: {type: 'object'} 'ladder:game-submitted': c.object {required: ['session', 'level']}, diff --git a/app/schemas/subscriptions/play.coffee b/app/schemas/subscriptions/play.coffee index 4c7c05fa5..9ffedd3b6 100644 --- a/app/schemas/subscriptions/play.coffee +++ b/app/schemas/subscriptions/play.coffee @@ -152,3 +152,5 @@ module.exports = timedOut: {type: 'boolean'} 'level:edit-wizard-settings': c.object {} + + 'level:inventory-changed': c.object {} diff --git a/app/styles/base.sass b/app/styles/base.sass index 443073605..56c1a37bd 100644 --- a/app/styles/base.sass +++ b/app/styles/base.sass @@ -302,3 +302,11 @@ a[data-toggle="coco-modal"] bottom: 0px right: 0px z-index: 1001 + +kbd + padding: 2px 4px + font-size: 90% + color: #fff + background-color: #333 + border-radius: 3px + @include box-shadow(inset 0 -1px 0 rgba(0, 0, 0, .25)) diff --git a/app/styles/common/top_nav.sass b/app/styles/common/top_nav.sass index 42e7fce47..f63c32476 100644 --- a/app/styles/common/top_nav.sass +++ b/app/styles/common/top_nav.sass @@ -45,6 +45,9 @@ a.disabled padding: 4px 20px 0px 20px margin-left: -20px + .navbar-nav + float: right + .navbuttontext, .fancy-select .trigger font-size: 20px font-weight: 400 @@ -190,32 +193,38 @@ a.disabled color: #ebebeb padding: 8px 20px + .navbar-toggle + display: none -#mobile-nav - display: none @media only screen and (max-width: 800px) #top-nav - display: none - #mobile-nav display: inline - a.navbar-brand - padding: 4px 20px 0px 20px - button.navbar-toggle background: #483a2d border: 2px solid #2f261d - span.icon-bar - background: #F9E612 - - ul li - font-family: 'Bangers', cursive - font-weight: normal - color: #fff - font-size: 25px - margin-top: 5px - margin-bottom: 5px - .header-font - color: #fff - .footer-link-text - width: 100% - display: ineline + display: inline-block + + span.icon-bar + background: #F9E612 + + a.navbar-brand + padding: 4px 20px 0px 20px + margin-left: 0 + + .navbar-nav + float: none + margin: 0 0 20px 0 + overflow: visible + + .dropdown-menu + background-color: white + position: absolute + + .btn, .fancy-select + margin-bottom: 10px + + .btn, .fancy-select + float: none + + .fancy-select .options + right: auto diff --git a/app/styles/docs/components-documentation-view.sass b/app/styles/docs/components-documentation-view.sass new file mode 100644 index 000000000..0a5bdb7fc --- /dev/null +++ b/app/styles/docs/components-documentation-view.sass @@ -0,0 +1,27 @@ +#components-documentation-view + background-color: #e4cf8c + height: 100% + + #toggle-all-component-code + margin: 10px + + .container, .row + height: 100% + + .index-column, .documentation-column + overflow-x: hidden + + > ul + padding: 0px 20px 20px 20px + + .doc-name + color: rgb(139, 69, 19) + + .index-column + width: 25% + + .documentation-column + width: 75% + + .special-list, .doc-description, .code-block + list-style-type: none diff --git a/app/styles/docs/components.sass b/app/styles/docs/components.sass deleted file mode 100644 index 145a9dfa5..000000000 --- a/app/styles/docs/components.sass +++ /dev/null @@ -1,31 +0,0 @@ -#docs-components-view - color: saddlebrown - - .row - - - - .index-column, .documentation-column - overflow-x: hidden - min-height: 600px - - > ul - padding: 0px 20px 20px 20px - - .doc-name - color: rgb(139, 69, 19) - - .index-column - width: 25% - - .documentation-column - width: 75% - - .specialList - list-style-type: none - - .doc-description - list-style-type: none - - .codeBlock - list-style-type: none \ No newline at end of file diff --git a/app/styles/docs/systems-documentation-view.sass b/app/styles/docs/systems-documentation-view.sass new file mode 100644 index 000000000..8af063555 --- /dev/null +++ b/app/styles/docs/systems-documentation-view.sass @@ -0,0 +1,27 @@ +#systems-documentation-view + background-color: #e4cf8c + height: 100% + + #toggle-all-system-code + margin: 10px + + .container, .row + height: 100% + + .index-column, .documentation-column + overflow-x: hidden + + > ul + padding: 0px 20px 20px 20px + + .doc-name + color: rgb(139, 69, 19) + + .index-column + width: 25% + + .documentation-column + width: 75% + + .special-list, .doc-description, .code-block + list-style-type: none diff --git a/app/styles/editor/achievement/edit.sass b/app/styles/editor/achievement/edit.sass index 157353e9a..499cc1794 100644 --- a/app/styles/editor/achievement/edit.sass +++ b/app/styles/editor/achievement/edit.sass @@ -4,7 +4,7 @@ .treema-root margin: 28px 0px 20px - button + .achievement-tool-button float: right margin-top: 15px margin-left: 10px diff --git a/app/styles/editor/article/edit.sass b/app/styles/editor/article/edit.sass index 1c8e5eba2..94743a383 100644 --- a/app/styles/editor/article/edit.sass +++ b/app/styles/editor/article/edit.sass @@ -2,11 +2,11 @@ .treema-root margin-bottom: 20px - button + .article-tool-button float: right - margin-top: 15px + margin-bottom: 15px margin-left: 10px textarea width: 92% - height: 300px \ No newline at end of file + height: 300px diff --git a/app/styles/editor/component/thang-component-config-view.sass b/app/styles/editor/component/thang-component-config-view.sass index e2670469b..ab8da8432 100644 --- a/app/styles/editor/component/thang-component-config-view.sass +++ b/app/styles/editor/component/thang-component-config-view.sass @@ -4,3 +4,6 @@ .treema-root border: 0 padding: 0 5px + + .is-default-component + background-color: lightgray \ No newline at end of file diff --git a/app/styles/editor/component/thang-components-edit-view.sass b/app/styles/editor/component/thang-components-edit-view.sass index 77b57132d..ffc9821b8 100644 --- a/app/styles/editor/component/thang-components-edit-view.sass +++ b/app/styles/editor/component/thang-components-edit-view.sass @@ -29,6 +29,9 @@ bottom: 0 overflow: scroll + .treema-key, .treema-description + display: none + .dependent background-color: rgba(128, 64, 255, 0.10) @@ -48,4 +51,6 @@ right: 0 left: 20px overflow: scroll - + + .selected-component .panel-heading + background-color: lightblue \ No newline at end of file diff --git a/app/styles/editor/level/component/edit.sass b/app/styles/editor/level/component/edit.sass index e4301dbde..978c286e5 100644 --- a/app/styles/editor/level/component/edit.sass +++ b/app/styles/editor/level/component/edit.sass @@ -26,4 +26,7 @@ left: 0 right: 0 bottom: 0 - top: 0px \ No newline at end of file + top: 0px + + #patch-component-button + display: none diff --git a/app/styles/editor/level/documentation_tab.sass b/app/styles/editor/level/documentation_tab.sass new file mode 100644 index 000000000..7996c36b1 --- /dev/null +++ b/app/styles/editor/level/documentation_tab.sass @@ -0,0 +1,5 @@ +#editor-level-documentation + height: 100% + + .tab-content + height: 100% diff --git a/app/styles/editor/level/level-feedback-view.sass b/app/styles/editor/level/level-feedback-view.sass new file mode 100644 index 000000000..6ebc29d38 --- /dev/null +++ b/app/styles/editor/level/level-feedback-view.sass @@ -0,0 +1,9 @@ +#level-feedback-view + height: 100% + + .user-feedback-list + height: 90% + height: -webkit-calc(100% - 80px) + height: calc(100% - 80px) + overflow-y: scroll + overflow-x: hidden diff --git a/app/styles/editor/level/system/edit.sass b/app/styles/editor/level/system/edit.sass index f8ca710d1..92f015d9e 100644 --- a/app/styles/editor/level/system/edit.sass +++ b/app/styles/editor/level/system/edit.sass @@ -26,4 +26,7 @@ left: 0 right: 0 bottom: 0 - top: 0px \ No newline at end of file + top: 0px + + #patch-system-button + display: none diff --git a/app/styles/game-menu/inventory-view.sass b/app/styles/game-menu/inventory-view.sass index afb9e6f02..18dee227a 100644 --- a/app/styles/game-menu/inventory-view.sass +++ b/app/styles/game-menu/inventory-view.sass @@ -1,9 +1,6 @@ $selected-area-height: 150px @import "../bootstrap/mixins" -//#inventory-view * - - #inventory-view position: relative height: 600px @@ -80,6 +77,8 @@ $selected-area-height: 150px padding: 10px height: 100% width: 49% + display: flex + align-items: center img width: 100px @@ -102,4 +101,4 @@ $selected-area-height: 150px height: $swap-item-height font-size: 24px line-height: 24px - display: inline-block \ No newline at end of file + display: inline-block diff --git a/app/styles/game-menu/item-view.sass b/app/styles/game-menu/item-view.sass index 259334682..d37b85e57 100644 --- a/app/styles/game-menu/item-view.sass +++ b/app/styles/game-menu/item-view.sass @@ -8,7 +8,7 @@ .item-info margin-left: 45px - + ul margin-top: 5px - padding-left: 20px + diff --git a/app/styles/home.sass b/app/styles/home.sass index 43c7a8b6a..c41497a2d 100644 --- a/app/styles/home.sass +++ b/app/styles/home.sass @@ -7,24 +7,6 @@ text-align: center margin-top: 0 - #front-screenshot - margin: 15px 0 40px 150px - - #trailer-wrapper - position: relative - margin: 0 auto 40px - width: 950px - iframe - display: block - margin: 0 auto - position: relative - top: 8px - img - position: absolute - left: 0 - top: 0 - pointer-events: none - .game-mode-wrapper position: relative margin-bottom: 60px @@ -97,6 +79,12 @@ .code-wizard opacity: 0.5 + .language-play-count + text-transform: lowercase + position: absolute + left: 0 + top: 0 + .code-language cursor: pointer text-align: center @@ -145,6 +133,8 @@ background: transparent url(/images/pages/home/language_js.png) no-repeat padding-right: 150px + .language-play-count + right: -100px .code-wizard left: 120px @@ -152,6 +142,8 @@ background: transparent url(/images/pages/home/language_python.png) no-repeat padding-left: 150px + .language-play-count + left: 125px .code-wizard right: 120px @@ -177,6 +169,10 @@ .col-md-3 padding: 0px + .language-play-count + left: 15px + top: -15px + .code-language background: transparent url(/images/pages/home/language_background_small.png) no-repeat width: 250px @@ -230,29 +226,27 @@ #home-view #site-slogan font-size: 30px - #trailer-wrapper - display: none - #front-screenshot - display: none - #mobile-trailer-wrapper - display: inline-block - - width: 100% - iframe - display: block - margin: 0 auto + margin-bottom: 30px + .code-languages + .col-sm-6, .col-sm-3 + margin-top: 30px + .code-language + margin: 0px auto .game-mode-wrapper width: 100% img width: 100% .play-text position: absolute - right: 45px - bottom: 0px + right: 15px + bottom: -15px color: $yellow font-size: 50px font-family: Bangers @include transition(color .10s linear) + .code-language-logo + right: 0px + top: 5px h1 text-align: center diff --git a/app/styles/treema-ext.sass b/app/styles/treema-ext.sass index 4d920df86..ff40f9aa7 100644 --- a/app/styles/treema-ext.sass +++ b/app/styles/treema-ext.sass @@ -9,6 +9,7 @@ &, & > div.ace_editor width: 100% + min-height: 48px .buttons button float: left diff --git a/app/templates/account/profile.jade b/app/templates/account/profile.jade index a178413ce..bbe9daba6 100644 --- a/app/templates/account/profile.jade +++ b/app/templates/account/profile.jade @@ -117,7 +117,7 @@ block content button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save .editable-section#basic-info-container - - var editableDefaults = editing && profile.city == jobProfileSchema.properties.city.default + - var editableDefaults = editing && !rawProfile.city div(class="editable-display" + (editableDefaults ? " edit-example-text" : ""), title="Click to edit your basic info") .editable-icon.glyphicon.glyphicon-pencil if editableDefaults @@ -224,7 +224,7 @@ block content #short-description-container.editable-section .editable-display(title="Click to write your tagline") .editable-icon.glyphicon.glyphicon-pencil - if editing && (!profile.shortDescription || profile.shortDescription == jobProfileSchema.properties.shortDescription.default) + if editing && !rawProfile.shortDescription h3.edit-label(data-i18n="account_profile.short_description_header") Write a short description of yourself p.edit-example-text(data-i18n="account_profile.short_description_blurb") Add a tagline to help an employer quickly learn more about you. @@ -269,7 +269,7 @@ block content #long-description-container.editable-section .editable-display(title="Click to start writing your longer description") .editable-icon.glyphicon.glyphicon-pencil - - var modified = profile.longDescription && profile.longDescription != jobProfileSchema.properties.longDescription.default + - var modified = rawProfile.longDescription if editing && !modified h3.edit-label(data-i18n="account_profile.long_description_header") Describe your desired position p.edit-example-text(data-i18n="account_profile.long_description_blurb") Tell employers how awesome you are and what role you want. diff --git a/app/templates/account/settings.jade b/app/templates/account/settings.jade index cbef47a7c..d07b97d16 100644 --- a/app/templates/account/settings.jade +++ b/app/templates/account/settings.jade @@ -32,7 +32,7 @@ block content .form - var name = me.get('name') || ''; - var email = me.get('email'); - - var admin = me.get('permissions').indexOf('admin') != -1; + - var admin = me.get('permissions', true).indexOf('admin') != -1; .form-group label.control-label(for="name", data-i18n="general.name") Name input#name.form-control(name="name", type="text", value="#{name}") diff --git a/app/templates/admin.jade b/app/templates/admin.jade index 79061e10d..1ba14abab 100644 --- a/app/templates/admin.jade +++ b/app/templates/admin.jade @@ -2,17 +2,23 @@ extends /templates/base block content - h3 Espionage mode - h5 Please enter the email/username of the person you want to spy on - .form - .form-group - label.control-label Email - input#user-email - .form-group - label.control-label Username - input#user-username - - button.btn.btn-primary.btn-large#enter-espionage-mode 007 + .form-horizontal + .form-group + label.control-label.col-sm-2(for="espionage-name-or-email") Espionage + .col-sm-4 + input.form-control#espionage-name-or-email(placeholder="Email or username", type="text") + .col-sm-1 + button.btn.btn-primary.btn-large#enter-espionage-mode 007 + label.control-label.col-sm-5(for="espionage-name-or-email") + em you are currently #{me.get('name')} at #{me.get('email')} + .form-group + label.control-label.col-sm-2(for="user-search") User Search + .col-sm-4 + input.form-control#user-search(placeholder="Email, username, name, whatever", type="text") + .col-sm-1 + button.btn.btn-primary.btn-large#user-search-button Search + #user-search-result + h3(data-i18n="admin.av_title") Admin Views diff --git a/app/templates/base.jade b/app/templates/base.jade index 076900376..a80d84c89 100644 --- a/app/templates/base.jade +++ b/app/templates/base.jade @@ -1,33 +1,19 @@ body #fb-root block header - .nav.navbar.navbar-fixed-top#mobile-nav + .nav.navbar.navbar-fixed-top#top-nav .content.clearfix .navbar-header - button.navbar-toggle(type="button" data-toggle="collapse" data-target="#collapsible-navbar") + button.navbar-toggle(type="button" data-toggle="collapse" data-target=".navbar-nav.collapse") span.sr-only Toggle navigation span.icon-bar span.icon-bar span.icon-bar - - a.navbar-brand(href='/') - img(src="/images/pages/base/logo.png", title="CodeCombat - Learn how to code by playing a game", alt="CodeCombat") - .collapse.navbar-collapse#collapsible-navbar - ul.nav.navbar-nav - li.play - a.header-font(href='/play', data-i18n="nav.play") Levels - li - a.header-font(href='/community', data-i18n="nav.community") Community - - .nav.navbar.navbar-fixed-top#top-nav - .content.clearfix - .navbar-header + a.navbar-brand(href='/') img(src="/images/pages/base/logo.png", title="CodeCombat - Learn how to code by playing a game", alt="CodeCombat") - select.language-dropdown - - ul(class='navbar-link-text').nav.navbar-nav.pull-right + ul(class='navbar-link-text').nav.navbar-nav.navbar-collapse.collapse li.play a.header-font(href='/play', data-i18n="nav.play") Levels li @@ -65,6 +51,8 @@ body span(data-i18n="login.log_in") Log In span.spr.spl / span(data-i18n="login.sign_up") Create Account + li + select.language-dropdown block outer_content #outer-content-wrapper(class=showBackground ? 'show-background' : '') @@ -79,7 +67,7 @@ body .footer.clearfix .content p.footer-link-text - if pathname == "/" || (me.get('permissions') || []).indexOf('employer') != -1 + if pathname == "/" || (me.get('permissions', true)).indexOf('employer') != -1 a(href='/employers', title='Home', tabindex=-1, data-i18n="nav.employers") Employers else a(href='/', title='Home', tabindex=-1, data-i18n="nav.home") Home diff --git a/app/templates/contribute/diplomat.jade b/app/templates/contribute/diplomat.jade index 2ddc3c53b..53e8d0cd7 100644 --- a/app/templates/contribute/diplomat.jade +++ b/app/templates/contribute/diplomat.jade @@ -55,7 +55,7 @@ block content // TODO: collect CodeCombat userids for these guys so we can include a tiled list ul.diplomats each stats, languageCode in languageStats - if !(languageCode.indexOf('-') != -1 && stats.completion < 0.02 && !stats.diplomats.length) + if !(stats.completion < 0.02 && !stats.diplomats.length) li a(href=stats.githubURL) span= stats.englishDescription diff --git a/app/templates/docs/components.jade b/app/templates/docs/components-documentation-view.jade similarity index 74% rename from app/templates/docs/components.jade rename to app/templates/docs/components-documentation-view.jade index 459ba0f00..6b4eb8169 100644 --- a/app/templates/docs/components.jade +++ b/app/templates/docs/components-documentation-view.jade @@ -1,13 +1,14 @@ -//extends /templates/base +.container + .pull-right + button.btn.btn-primary#toggle-all-component-code Toggle all code + .clearfix - -block content .row .col-xs-3.index-column.nano ul.nav.nav-list.list-group.nano-content for component in components a.doc-name(href="##{component.get('name')}") - li.list-group-item= component.get('name') + li.list-group-item= component.get('system') + '.' + component.get('name') ul // .list-group for different layout each doc in component.attributes.propertyDocumentation @@ -19,24 +20,26 @@ block content for component in components div(id="#{component.get('name')}" class="panel panel-defalt") div(class="panel-heading") - | #{component.get('name')} + strong= component.get('system') + '.' + component.get('name') div(class="panel-body") | #{component.get('description')} ul each doc in component.attributes.propertyDocumentation li.list-group-item(id="#{component.get('name')}#{doc.name}") | #{doc.name} - ul.specialList + ul.special-list if doc.description[codeLanguage] li!=marked(doc.description[codeLanguage]) else li!=marked(doc.description) li.panel-heading - a.codeBlock(data-toggle="collapse" data-parent="##{component.get('name')}" href="##{component.get('name')}Code") + a.code-block(data-toggle="collapse" data-parent="##{component.get('name')}" href="##{component.get('name')}Code") | Code div(id="#{component.get('name')}Code" class="panel-collapse collapse") div.panel-body pre | #{component.attributes.code} - + .clearfix + .clearfix + .clearfix \ No newline at end of file diff --git a/app/templates/docs/systems-documentation-view.jade b/app/templates/docs/systems-documentation-view.jade new file mode 100644 index 000000000..2f439e5cd --- /dev/null +++ b/app/templates/docs/systems-documentation-view.jade @@ -0,0 +1,31 @@ +.container + .pull-right + button.btn.btn-primary#toggle-all-system-code Toggle all code + .clearfix + + .row + .col-xs-3.index-column.nano + ul.nav.nav-list.list-group.nano-content + for system in systems + a.doc-name(href="##{system.get('name')}") + li.list-group-item= system.get('name') + .col-xs-9.documentation-column.nano + ul.nano-content + for system in systems + div(id="#{system.get('name')}" class="panel panel-defalt") + div(class="panel-heading") + | #{system.get('name')} + div(class="panel-body") + | #{system.get('description')} + ul + li.panel-heading + a.code-block(data-toggle="collapse" data-parent="##{system.get('name')}" href="##{system.get('name')}Code") + | Code + div(id="#{system.get('name')}Code" class="panel-collapse collapse") + div.panel-body + pre + | #{system.attributes.code} + + .clearfix + .clearfix + .clearfix \ No newline at end of file diff --git a/app/templates/editor/achievement/edit.jade b/app/templates/editor/achievement/edit.jade index 17bab8045..a7058b835 100644 --- a/app/templates/editor/achievement/edit.jade +++ b/app/templates/editor/achievement/edit.jade @@ -10,9 +10,9 @@ block content li.active | #{achievement.attributes.name} - button(data-i18n="", disabled=me.isAdmin() === true ? undefined : "true").btn.btn-primary#recalculate-button Recalculate - button(data-i18n="common.delete", disabled=me.isAdmin() === true ? undefined : "true").btn.btn-primary#delete-button Delete - button(data-i18n="common.save", disabled=me.isAdmin() === true ? undefined : "true").btn.btn-primary#save-button Save + button.achievement-tool-button(data-i18n="", disabled=me.isAdmin() === true ? undefined : "true").btn.btn-primary#recalculate-button Recalculate + button.achievement-tool-button(data-i18n="common.delete", disabled=me.isAdmin() === true ? undefined : "true").btn.btn-primary#delete-button Delete + button.achievement-tool-button(data-i18n="common.save", disabled=me.isAdmin() === true ? undefined : "true").btn.btn-primary#save-button Save h3(data-i18n="achievement.edit_achievement_title") Edit Achievement span diff --git a/app/templates/editor/article/edit.jade b/app/templates/editor/article/edit.jade index 76e8d255b..48f610ce2 100644 --- a/app/templates/editor/article/edit.jade +++ b/app/templates/editor/article/edit.jade @@ -10,10 +10,10 @@ block content li.active | #{article.attributes.name} - button(data-i18n="general.version_history").btn.btn-primary#history-button Version History - button(data-toggle="coco-modal", data-target="modal/RevertModal", data-i18n="editor.revert", disabled=authorized === true ? undefined : "true").btn.btn-primary#revert-button Revert - button(data-i18n="article.edit_btn_preview", disabled=authorized === true ? undefined : "true").btn.btn-primary#preview-button Preview - button(data-i18n="common.save", disabled=authorized === true ? undefined : "true").btn.btn-primary#save-button Save + button.article-tool-button(data-i18n="general.version_history").btn.btn-primary#history-button Version History + button.article-tool-button(data-toggle="coco-modal", data-target="modal/RevertModal", data-i18n="editor.revert", disabled=authorized === true ? undefined : "true").btn.btn-primary#revert-button Revert + button.article-tool-button(data-i18n="article.edit_btn_preview", disabled=authorized === true ? undefined : "true").btn.btn-primary#preview-button Preview + button.article-tool-button(data-i18n="common.save", disabled=authorized === true ? undefined : "true").btn.btn-primary#save-button Save h3(data-i18n="article.edit_article_title") Edit Article span diff --git a/app/templates/editor/component/thang-component-config-view.jade b/app/templates/editor/component/thang-component-config-view.jade index c1ef8c916..80535c740 100644 --- a/app/templates/editor/component/thang-component-config-view.jade +++ b/app/templates/editor/component/thang-component-config-view.jade @@ -1,5 +1,5 @@ .panel.panel-default - .panel-heading + .panel-heading(class=isDefaultComponent ? "is-default-component" : "") em #{component.system}. strong.panel-title.spr= component.name span#description.text-muted= component.description diff --git a/app/templates/editor/level/component/edit.jade b/app/templates/editor/level/component/edit.jade index 66a8375c2..86e11d051 100644 --- a/app/templates/editor/level/component/edit.jade +++ b/app/templates/editor/level/component/edit.jade @@ -13,6 +13,10 @@ nav.navbar.navbar-default(role='navigation') span.navbar-brand= editTitle ul.nav.navbar-nav.navbar-right + if !component.hasWriteAccess() + li#patch-component-button + a(data-i18n="[title]common.submit_patch") + span.glyphicon-floppy-disk.glyphicon li.dropdown a(data-toggle='dropdown') span.glyphicon-chevron-down.glyphicon @@ -27,10 +31,6 @@ nav.navbar.navbar-default(role='navigation') span.unwatch.secret span.glyphicon.glyphicon-eye-close span.spl Unwatch - - if !component.hasWriteAccess() - li#patch-component-button - a(data-i18n="common.submit_patch") Submit Patch if !me.get('anonymous') li#create-new-component-button a(data-i18n="editor.level_component_b_new") Create New Component diff --git a/app/templates/editor/level/edit.jade b/app/templates/editor/level/edit.jade index d61965365..f6d2fb663 100644 --- a/app/templates/editor/level/edit.jade +++ b/app/templates/editor/level/edit.jade @@ -36,7 +36,10 @@ block header li a(href="#related-achievements-view", data-toggle="tab") Achievements li - a(href="#docs-components-view", data-toggle="tab", data-i18n="editor.level_tab_docs") Documentation + a(href="#editor-level-documentation", data-toggle="tab", data-i18n="editor.level_tab_docs") Documentation + li + a(href="#level-feedback-view", data-toggle="tab") + .glyphicon.glyphicon-star .navbar-header span.navbar-brand #{level.attributes.name} @@ -46,7 +49,7 @@ block header span.glyphicon-arrow-left.glyphicon li#redo-button(title="Redo (Ctrl+Shift+Z)") a - span.glyphicon-repeat.glyphicon + span.glyphicon-arrow-right.glyphicon if authorized li#commit-level-start-button a @@ -64,7 +67,9 @@ block header li.dropdown-header Play As Which Team? li for team in ['humans', 'ogres'] - a.play-with-team-button(data-team=team)= team + a.play-with-team-button(data-team=team)= team + ' vs. AI' + for match in recentlyPlayedOpponents + a.play-with-team-button(data-team=match.yourTeam, data-opponent=match.opponentSessionID)= match.yourTeam + ' vs. ' + match.opponentName else li(title="⌃↩ or ⌘↩: Play preview of current level")#play-button @@ -125,7 +130,17 @@ block outer_content div.tab-pane#related-achievements-view - div.tab-pane#docs-components-view + div.tab-pane#editor-level-documentation + ul.nav.nav-pills.nav-justified + li + a(href="#components-documentation-view", data-toggle="pill", data-i18n="resources.components") Components + li + a(href="#systems-documentation-view", data-toggle="pill", data-i18n="resources.systems") Systems + div.tab-content + div.tab-pane#components-documentation-view + div.tab-pane#systems-documentation-view + + div.tab-pane#level-feedback-view div#error-view diff --git a/app/templates/editor/level/level-feedback-view.jade b/app/templates/editor/level/level-feedback-view.jade new file mode 100644 index 000000000..be266b474 --- /dev/null +++ b/app/templates/editor/level/level-feedback-view.jade @@ -0,0 +1,17 @@ +h2 Average Rating: #{averageRating.toFixed(2)}, #{totalRatings} ratings +ul.user-feedback-list.list-group + for feedback in allFeedback + li.list-group-item + each i in Array(feedback.rating) + .glyphicon.glyphicon-star + if feedback.rating < 5 + each i in Array(5 - feedback.rating) + .glyphicon.glyphicon-star-empty + span.spl.spr - + em= moment(new Date(feedback.created)).fromNow() + span.spl.spr - + a(href="/user/#{feedback.creator}") + strong= feedback.creatorName || 'Anoner' + if feedback.review + span.spr : + span= feedback.review diff --git a/app/templates/editor/level/related-achievements.jade b/app/templates/editor/level/related-achievements.jade index e0312d779..3d0ff9c34 100644 --- a/app/templates/editor/level/related-achievements.jade +++ b/app/templates/editor/level/related-achievements.jade @@ -1,9 +1,6 @@ - button.btn.btn-primary#new-achievement-button(disabled=me.isAdmin() === true ? undefined : "true" data-i18n="editor.new_achievement_title") Create a New Achievement -if achievements.loading - h2(data-i18n="common.loading") Loading... -else if ! achievements.models.length +if !achievements.models.length .panel .panel-body p(data-i18n="editor.no_achievements") No achievements added for this level yet. diff --git a/app/templates/editor/level/system/edit.jade b/app/templates/editor/level/system/edit.jade index 555709fca..f5c64f6ab 100644 --- a/app/templates/editor/level/system/edit.jade +++ b/app/templates/editor/level/system/edit.jade @@ -11,6 +11,10 @@ nav.navbar.navbar-default(role='navigation') a(href="#system-patches" data-toggle="tab" data-i18n="resources.patches")#system-patches-tab Patches ul.nav.navbar-nav.navbar-right + if !me.isAdmin() + li#patch-system-button + a(data-i18n="[title]common.submit_patch") + span.glyphicon-floppy-disk.glyphicon li.dropdown a(data-toggle='dropdown') span.glyphicon-chevron-down.glyphicon @@ -24,8 +28,6 @@ nav.navbar.navbar-default(role='navigation') span.unwatch.secret span.glyphicon.glyphicon-eye-close span.spl Unwatch - li#patch-system-button - a(data-i18n="common.submit_patch") Submit Patch if me.isAdmin() li#create-new-system a(data-i18n="editor.level_system_btn_new") Create New System diff --git a/app/templates/game-menu/game-menu-modal.jade b/app/templates/game-menu/game-menu-modal.jade index a8d8fb6ed..0876d23d5 100644 --- a/app/templates/game-menu/game-menu-modal.jade +++ b/app/templates/game-menu/game-menu-modal.jade @@ -8,8 +8,9 @@ block modal-body-content - if (!showDevBits) { // Not done yet. - submenus.splice(4, 1); - submenus.splice(2, 1); - - submenus.splice(0, 1); - } + - if (!showInventory) + - submenus.splice(0, 1); ul.nav.nav-tabs for submenu, index in submenus li(class=index ? "" : "active") @@ -19,10 +20,6 @@ block modal-body-content .tab-content for submenu, index in submenus .tab-pane(id=submenu + '-view') - h3= submenu + submenu + submenu - p - | Lorem ipsum dolor sit amet, charetra varius quam sit amet vulputate. - | Quisque mauris augue, molestie tincidunt condimentum vitae, gravida a libero. .clearfix block modal-footer \ No newline at end of file diff --git a/app/templates/game-menu/item-view.jade b/app/templates/game-menu/item-view.jade index 04dc9e350..c22c34e27 100644 --- a/app/templates/game-menu/item-view.jade +++ b/app/templates/game-menu/item-view.jade @@ -2,11 +2,20 @@ img(src=item.getPortraitURL()).img-thumbnail div.item-info if includes.name strong= item.get('name') - if includes.stats - - var stats = item.getFrontFacingStats() - ul - for stat in stats - li #{stat.name}: #{stat.value} + if includes.stats || (includes.props && props.length) + ul.list-unstyled + if includes.stats + for stat, prop in stats + if stat.display == 'true' + li= stat.name + else + li #{stat.name}: #{stat.display} + if includes.props && props.length + li Grants: + for prop in props + | + code= prop + .clearfix \ No newline at end of file diff --git a/app/templates/game-menu/options-view.jade b/app/templates/game-menu/options-view.jade index 14eafe026..f21090004 100644 --- a/app/templates/game-menu/options-view.jade +++ b/app/templates/game-menu/options-view.jade @@ -3,14 +3,14 @@ .editable-icon.glyphicon.glyphicon-pencil img.profile-photo(src=me.getPhotoURL(230)) .form-group - input#player-name.profile-caption(name="playerName", type="text", value=me.get('name') || 'Anoner') + input#player-name.profile-caption(name="playerName", type="text", value=me.get('name', true)) .form h3(data-i18n="options.general_options") General Options .form-group.slider-group label(for="option-volume") - span(data-i18n="options.volume") Volume + span(data-i18n="options.volume_label") Volume span.spr : span#option-volume-value= (me.get('volume') * 100).toFixed(0) + '%' #option-volume.slider @@ -18,7 +18,7 @@ .form-group.checkbox label(for="option-music") input#option-music(name="option-music", type="checkbox", checked=music) - span(data-i18n="options.music") Music + span(data-i18n="options.music_label") Music span.help-block(data-i18n="options.music_description") Turn background music on/off. .form-group.select-group diff --git a/app/templates/home.jade b/app/templates/home.jade index 6d9d939df..16698fb66 100644 --- a/app/templates/home.jade +++ b/app/templates/home.jade @@ -6,51 +6,81 @@ block content .code-languages .primary-code-languages.row - .col-md-6 + .col-sm-6 .code-language#javascript(data-code-language='javascript') .code-wizard h2 JavaScript p(data-i18n="home.javascript_blurb") The language of the web. Great for writing websites, web apps, HTML5 games, and servers. + - var playCount = codeLanguageCountMap.javascript + if playCount + div.language-play-count + span.spr= playCount + span(data-i18n="resources.sessions") sessions - .col-md-6 + .col-sm-6 .code-language.beta#python(data-code-language='python') .code-wizard .code-language-beta h2 Python p(data-i18n="home.python_blurb") Simple yet powerful, Python is a great general purpose programming language. + - var playCount = codeLanguageCountMap.python + if playCount + div.language-play-count + span.spr= playCount + span(data-i18n="resources.sessions") sessions .secondary-code-languages.row - .col-md-3 + .col-sm-3 .code-language.beta#coffeescript(data-code-language='coffeescript') .code-language-logo .code-wizard .code-language-beta h3 CoffeeScript p(data-i18n="home.coffeescript_blurb") Nicer JavaScript syntax. + - var playCount = codeLanguageCountMap.coffeescript + if playCount + div.language-play-count + span.spr= playCount + span(data-i18n="resources.sessions") sessions - .col-md-3 + .col-sm-3 .code-language.beta#clojure(data-code-language='clojure') .code-language-logo .code-wizard .code-language-beta h3 Clojure p(data-i18n="home.clojure_blurb") A modern Lisp. + - var playCount = codeLanguageCountMap.clojure + if playCount + div.language-play-count + span.spr= playCount + span(data-i18n="resources.sessions") sessions - .col-md-3 + .col-sm-3 .code-language.beta#lua(data-code-language='lua') .code-language-logo .code-wizard .code-language-beta h3 Lua p(data-i18n="home.lua_blurb") Game scripting language. + - var playCount = codeLanguageCountMap.lua + if playCount + div.language-play-count + span.spr= playCount + span(data-i18n="resources.sessions") sessions - .col-md-3 + .col-sm-3 .code-language.beta#io(data-code-language='io', title="Careful: Io is still quite buggy") .code-language-logo .code-wizard .code-language-beta h3 Io p(data-i18n="home.io_blurb") Simple but obscure. + - var playCount = codeLanguageCountMap.io + if playCount + div.language-play-count + span.spr= playCount + span(data-i18n="resources.sessions") sessions .alert.alert-danger.lt-ie10 strong(data-i18n="home.no_ie") CodeCombat does not run in Internet Explorer 9 or older. Sorry! diff --git a/app/templates/loading_error.jade b/app/templates/loading_error.jade index 2e9a8edfe..fdd566a45 100644 --- a/app/templates/loading_error.jade +++ b/app/templates/loading_error.jade @@ -24,8 +24,5 @@ else strong(data-i18n="loading_error.unknown") Unknown error. - if resourceIndex !== undefined - button.btn.btn-xs.retry-loading-resource(data-i18n="common.retry", data-resource-index=resourceIndex) Retry - if requestIndex !== undefined - button.btn.btn-xs.retry-loading-request(data-i18n="common.retry", data-request-index=requestIndex) Retry - \ No newline at end of file + button.btn.btn-xs.retry-loading-resource(data-i18n="common.retry", data-resource-index=resourceIndex) Retry + button.btn.btn-xs.skip-loading-resource(data-i18n="common.skip", data-resource-index=resourceIndex) Skip diff --git a/app/templates/modal/versions.jade b/app/templates/modal/versions.jade index 56c9b0f71..f99f9402c 100755 --- a/app/templates/modal/versions.jade +++ b/app/templates/modal/versions.jade @@ -19,7 +19,8 @@ block modal-body-content tr td input(type="checkbox", value=data._id).select - td #{data.version.major}.#{data.version.minor} + td + a(href="/editor/#{page}/#{data._id}") #{data.version.major}.#{data.version.minor} td= moment(data.created).format('l') td= data.creator td #{data.commitMessage} diff --git a/app/templates/play/level/level_loading.jade b/app/templates/play/level/level_loading.jade index 03d357f75..895524bce 100644 --- a/app/templates/play/level/level_loading.jade +++ b/app/templates/play/level/level_loading.jade @@ -39,7 +39,7 @@ strong.tip.rare(data-i18n='play_level.tip_first_language') The most disastrous thing that you can ever learn is your first programming language. - Alan Kay strong.tip.rare span(data-i18n='play_level.tip_harry') Yer a Wizard, - span= me.get('name') || 'Anoner' + span= me.get('name', true) .errors diff --git a/app/templates/play/level/modal/keyboard_shortcuts.jade b/app/templates/play/level/modal/keyboard_shortcuts.jade index 06815d09e..afca41d17 100644 --- a/app/templates/play/level/modal/keyboard_shortcuts.jade +++ b/app/templates/play/level/modal/keyboard_shortcuts.jade @@ -6,71 +6,71 @@ block modal-header-content block modal-body-content dl.dl-horizontal dt(title=shift + "+" + enter) - code ⇧+#{enter} + kbd ⇧+#{enter} dd(data-i18n="keyboard_shortcuts.cast_spell") Cast current spell. dl.dl-horizontal dt(title=ctrlName + "+" + shift + "+" + enter) - code #{ctrl}+⇧+#{enter} + kbd #{ctrl}+⇧+#{enter} dd(data-i18n="keyboard_shortcuts.run_real_time") Run in real time. dl.dl-horizontal dt(title=shift + "+" + space) - code ⇧+#{space} + kbd ⇧+#{space} dd(data-i18n="keyboard_shortcuts.continue_script") Continue past current script. dl.dl-horizontal dt(title=escapeKey) - code Esc + kbd Esc dd(data-i18n="keyboard_shortcuts.skip_scripts") Skip past all skippable scripts. dl.dl-horizontal dt(title=ctrlName + "+P") - code #{ctrl}+P + kbd #{ctrl}+P dd(data-i18n="keyboard_shortcuts.toggle_playback") Toggle play/pause. dl.dl-horizontal dt(title=ctrlName + "+[, " + ctrlName + "+]") - code #{ctrl}+[ + kbd #{ctrl}+[ | , - code #{ctrl}+] + kbd #{ctrl}+] dd(data-i18n="keyboard_shortcuts.scrub_playback") Scrub back and forward through time. dl.dl-horizontal dt(title=ctrlName + "+[, " + ctrlName + "+]") - code #{ctrl}+⇧+[ + kbd #{ctrl}+⇧+[ | , - code #{ctrl}+⇧+] + kbd #{ctrl}+⇧+] dd(data-i18n="keyboard_shortcuts.single_scrub_playback") Scrub back and forward through time by a single frame. dl.dl-horizontal dt(title=ctrlName + "+" + altName + "+[, " + ctrlName + "+" + altName + "+]") - code #{ctrl}+#{alt}+[ + kbd #{ctrl}+#{alt}+[ | , - code #{ctrl}+#{alt}+] + kbd #{ctrl}+#{alt}+] dd(data-i18n="keyboard_shortcuts.scrub_execution") Scrub through current spell execution. dl.dl-horizontal dt(title=ctrlName + "+\\") - code #{ctrl}+\ + kbd #{ctrl}+\ dd(data-i18n="keyboard_shortcuts.toggle_debug") Toggle debug display. dl.dl-horizontal dt(title=ctrlName + "+G") - code #{ctrl}+G + kbd #{ctrl}+G dd(data-i18n="keyboard_shortcuts.toggle_grid") Toggle grid overlay. dl.dl-horizontal dt(title=ctrlName + "+O") - code #{ctrl}+O + kbd #{ctrl}+O dd(data-i18n="keyboard_shortcuts.toggle_pathfinding") Toggle pathfinding overlay. dl.dl-horizontal dt(title=ctrlName + "+" + shift + "+B") - code #{ctrl}+⇧+B + kbd #{ctrl}+⇧+B dd(data-i18n="keyboard_shortcuts.beautify") Beautify your code by standardizing its formatting. dl.dl-horizontal dt(title=ctrlName + "+" + shift + "+M") - code #{ctrl}+⇧+M + kbd #{ctrl}+⇧+M dd(data-i18n="keyboard_shortcuts.maximize_editor") Maximize/minimize code editor. dl.dl-horizontal dt(title="Arrow keys") - code ← + kbd ← | , - code → + kbd → | , - code ↑ + kbd ↑ | , - code ↓ + kbd ↓ dd(data-i18n="keyboard_shortcuts.move_wizard") Move your Wizard around the level. block modal-footer-content diff --git a/app/treema-ext.coffee b/app/treema-ext.coffee index 56e91a303..92217b89c 100644 --- a/app/treema-ext.coffee +++ b/app/treema-ext.coffee @@ -5,20 +5,21 @@ locale = require 'locale/locale' class DateTimeTreema extends TreemaNode.nodeMap.string valueClass: 'treema-date-time' - buildValueForDisplay: (el) -> el.text(moment(@data).format('llll')) + buildValueForDisplay: (el, data) -> el.text(moment(data).format('llll')) buildValueForEditing: (valEl) -> @buildValueForEditingSimply valEl, null, 'date' class VersionTreema extends TreemaNode valueClass: 'treema-version' - buildValueForDisplay: (valEl) -> @buildValueForDisplaySimply(valEl, "#{@data.major}.#{@data.minor}") + buildValueForDisplay: (valEl, data) -> + @buildValueForDisplaySimply(valEl, "#{data.major}.#{data.minor}") class LiveEditingMarkup extends TreemaNode.nodeMap.ace valueClass: 'treema-markdown treema-multiline treema-ace' constructor: -> super(arguments...) - @schema.aceMode = 'ace/mode/markdown' + @workingSchema.aceMode = 'ace/mode/markdown' initEditor: (valEl) -> buttonRow = $('
') @@ -26,7 +27,7 @@ class LiveEditingMarkup extends TreemaNode.nodeMap.ace @addPreviewToggle(buttonRow) @addImageUpload(buttonRow) super(valEl) - valEl.append($('
')) + valEl.append($('
').hide()) addImageUpload: (valEl) -> return unless me.isAdmin() @@ -85,7 +86,7 @@ class SoundFileTreema extends TreemaNode.nodeMap.string getFiles: -> @settings[@soundCollection]?.models or [] - buildValueForDisplay: (valEl) -> + buildValueForDisplay: (valEl, data) -> mimetype = "audio/#{@keyForParent}" pickButton = $('') .click(=> filepicker.pick {mimetypes:[mimetype]}, @onFileChosen) @@ -116,17 +117,17 @@ class SoundFileTreema extends TreemaNode.nodeMap.string .text(filename) menu.append(li) menu.click (e) => - @data = $(e.target).data('fullPath') or @data + @data = $(e.target).data('fullPath') or data @reset() dropdown.append(menu) valEl.append(pickButton) - if @data + if data valEl.append(playButton) valEl.append(stopButton) valEl.append(dropdown) # if files.length and @canEdit() - if @data - path = @data.split('/') + if data + path = data.split('/') name = path[path.length-1] valEl.append($('').text(name)) @@ -136,7 +137,7 @@ class SoundFileTreema extends TreemaNode.nodeMap.string @refreshDisplay() playFile: => - @src = "/file/#{@data}" + @src = "/file/#{@getData()}" if @instance @instance.play() @@ -183,14 +184,14 @@ class ImageFileTreema extends TreemaNode.nodeMap.string return if $(e.target).closest('.btn').length super(arguments...) - buildValueForDisplay: (valEl) -> + buildValueForDisplay: (valEl, data) -> mimetype = 'image/*' pickButton = $(' Upload Picture') .click(=> filepicker.pick {mimetypes:[mimetype]}, @onFileChosen) valEl.append(pickButton) - if @data - valEl.append $('').attr('src', "/file/#{@data}") + if data + valEl.append $('').attr('src', "/file/#{data}") onFileChosen: (InkBlob) => if not @settings.filePath @@ -223,36 +224,36 @@ codeLanguages = class CodeLanguagesObjectTreema extends TreemaNode.nodeMap.object childPropertiesAvailable: -> - (key for key in _.keys(codeLanguages) when not @data[key]? and not (key is 'javascript' and @schema.skipJavaScript)) + (key for key in _.keys(codeLanguages) when not @data[key]? and not (key is 'javascript' and @workingSchema.skipJavaScript)) class CodeLanguageTreema extends TreemaNode.nodeMap.string - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) valEl.find('input').autocomplete(source: _.keys(codeLanguages), minLength: 0, delay: 0, autoFocus: true) valEl class CodeTreema extends TreemaNode.nodeMap.ace constructor: -> super(arguments...) - @schema.aceTabSize = 4 + @workingSchema.aceTabSize = 4 - buildValueForEditing: (valEl) -> - super(valEl) - if not @schema.aceMode and mode = codeLanguages[@keyForParent] + buildValueForEditing: (valEl, data) -> + super(valEl, data) + if not @workingSchema.aceMode and mode = codeLanguages[@keyForParent] @editor.getSession().setMode mode valEl class CoffeeTreema extends CodeTreema constructor: -> super(arguments...) - @schema.aceMode = 'ace/mode/coffee' - @schema.aceTabSize = 2 + @workingSchema.aceMode = 'ace/mode/coffee' + @workingSchema.aceTabSize = 2 class JavaScriptTreema extends CodeTreema constructor: -> super(arguments...) - @schema.aceMode = 'ace/mode/javascript' - @schema.aceTabSize = 4 + @workingSchema.aceMode = 'ace/mode/javascript' + @workingSchema.aceTabSize = 4 class InternationalizationNode extends TreemaNode.nodeMap.object @@ -275,11 +276,11 @@ class InternationalizationNode extends TreemaNode.nodeMap.object properties: {} } return i18nChildSchema unless @parent - unless @schema.props? + unless @workingSchema.props? console.warn 'i18n props array is empty! Filling with all parent properties by default' - @schema.props = (prop for prop,_ of @parent.schema.properties when prop isnt 'i18n') + @workingSchema.props = (prop for prop,_ of @parent.schema.properties when prop isnt 'i18n') - for i18nProperty in @schema.props + for i18nProperty in @workingSchema.props i18nChildSchema.properties[i18nProperty] = @parent.schema.properties[i18nProperty] return i18nChildSchema #this must be filled out in order for the i18n node to work @@ -300,22 +301,22 @@ class LatestVersionReferenceNode extends TreemaNode super(arguments...) # to dynamically build the search url, inspect the links url that should be included - links = @schema.links or [] + links = @workingSchema.links or [] link = (l for l in links when l.rel is 'db')[0] return unless link parts = (p for p in link.href.split('/') when p.length) @url = "/db/#{parts[1]}" @model = require('models/' + _.string.classify(parts[1])) - buildValueForDisplay: (valEl) -> - val = if @data then @formatDocument(@data) else 'None' + buildValueForDisplay: (valEl, data) -> + val = if data then @formatDocument(data) else 'None' @buildValueForDisplaySimply(valEl, val) - buildValueForEditing: (valEl) -> + buildValueForEditing: (valEl, data) -> valEl.html(@searchValueTemplate) input = valEl.find('input') input.focus().keyup @search - input.attr('placeholder', @formatDocument(@data)) if @data + input.attr('placeholder', @formatDocument(data)) if data buildSearchURL: (term) -> "#{@url}?term=#{term}&project=true" @@ -357,12 +358,11 @@ class LatestVersionReferenceNode extends TreemaNode formatDocument: (docOrModel) -> return @modelToString(docOrModel) if docOrModel instanceof CocoModel return 'Unknown' unless @settings.supermodel? - m = CocoModel.getReferencedModel(@data, @schema) - urlGoingFor = m.url() - m = @settings.supermodel.getModel(urlGoingFor) + m = CocoModel.getReferencedModel(@getData(), @workingSchema) + data = @getData() + m = @settings.supermodel.getModelByOriginalAndMajorVersion(m.constructor, data.original, data.majorVersion) if @instance and not m m = @instance - m.url = -> urlGoingFor @settings.supermodel.registerModel(m) return 'Unknown' unless m return @modelToString(m) @@ -387,9 +387,6 @@ class LatestVersionReferenceNode extends TreemaNode e.preventDefault() @navigateSearch(-1) - onDeletePressed: (e) -> - super(arguments...) - navigateSearch: (offset) -> selected = @getSelectedResultEl() func = if offset > 0 then 'next' else 'prev' @@ -418,14 +415,14 @@ class LevelComponentReferenceNode extends LatestVersionReferenceNode # supermodels. buildSearchURL: (term) -> "#{@url}?term=#{term}&project=name,system,original,version,dependencies,configSchema,description" modelToString: (model) -> model.get('system') + '.' + model.get('name') - canEdit: -> not @data.original # only allow editing if the row's data hasn't been set yet + canEdit: -> not @getData().original # only allow editing if the row's data hasn't been set yet LatestVersionReferenceNode.prototype.search = _.debounce(LatestVersionReferenceNode.prototype.search, 200) class SlugPropsObject extends TreemaNode.nodeMap.object getPropertyKey: -> res = super(arguments...) - return res if @schema.properties?[res]? + return res if @workingSchema.properties?[res]? _.string.slugify(res) module.exports.setup = -> diff --git a/app/views/EmployersView.coffee b/app/views/EmployersView.coffee index d9dcd5a89..4e9c45e5f 100644 --- a/app/views/EmployersView.coffee +++ b/app/views/EmployersView.coffee @@ -20,7 +20,7 @@ module.exports = class EmployersView extends RootView 'change #select_all_checkbox': 'handleSelectAllChange' 'click .get-started-button': 'openSignupModal' 'click .navbar-brand': 'restoreBodyColor' - 'click #login-link': 'onClickAuthbutton' + 'click #login-link': 'onClickAuthButton' 'click #filter-link': 'swapFolderIcon' 'click #create-alert-button': 'createFilterAlert' 'click .deletion-col': 'deleteFilterAlert' @@ -197,9 +197,7 @@ module.exports = class EmployersView extends RootView ctx.numberOfCandidates = ctx.featuredCandidates.length ctx - isEmployer: -> - userPermissions = me.get('permissions') ? [] - _.contains userPermissions, 'employer' + isEmployer: -> 'employer' in me.get('permissions', true) setUpScrolling: => $('.nano').nanoScroller() @@ -209,7 +207,7 @@ module.exports = class EmployersView extends RootView # $('.nano').nanoScroller({scrollTo: $(window.location.hash)}) checkForEmployerSignupHash: => - if window.location.hash is '#employerSignupLoggingIn' and not ('employer' in me.get('permissions')) and not me.isAdmin() + if window.location.hash is '#employerSignupLoggingIn' and not ('employer' in me.get('permissions', true)) and not me.isAdmin() @openModalView new EmployerSignupModal window.location.hash = '' diff --git a/app/views/HomeView.coffee b/app/views/HomeView.coffee index 4323f5ea0..23f619e56 100644 --- a/app/views/HomeView.coffee +++ b/app/views/HomeView.coffee @@ -15,6 +15,7 @@ module.exports = class HomeView extends RootView constructor: -> super(arguments...) ThangType.loadUniversalWizard() + @getCodeLanguageCounts() getRenderData: -> c = super() @@ -28,6 +29,7 @@ module.exports = class HomeView extends RootView c.isEnglish = (me.get('preferredLanguage') or 'en').startsWith 'en' c.languageName = me.get('preferredLanguage') c.codeLanguage = (me.get('aceConfig') ? {}).language or 'javascript' + c.codeLanguageCountMap = @codeLanguageCountMap c afterRender: -> @@ -68,3 +70,19 @@ module.exports = class HomeView extends RootView lastButton = @$el.find('#multiplayer .game-mode-wrapper').delay(1000).addClass('hovered', 500).delay(500).removeClass('hovered', 500) $('#page-container').animate {scrollTop: firstButton.offset().top - 100, easing: 'easeInOutCubic'}, 500 @updateLanguageLogos codeLanguage + + getCodeLanguageCounts: -> + @codeLanguageCountMap = {} + success = (codeLanguageCounts) => + return if @destroyed + for codeLanguage in codeLanguageCounts + @codeLanguageCountMap[codeLanguage._id] = codeLanguage.sessions + @codeLanguageCountMap.javascript += @codeLanguageCountMap[null] + @render() if @supermodel.finished() + + codeLanguageCountsRequest = @supermodel.addRequestResource 'play_counts', { + url: '/db/level.session/-/code_language_counts' + method: 'POST' + success: success + }, 0 + codeLanguageCountsRequest.load() diff --git a/app/views/account/AccountSettingsView.coffee b/app/views/account/AccountSettingsView.coffee index 7dabe37fa..c0c3fa707 100644 --- a/app/views/account/AccountSettingsView.coffee +++ b/app/views/account/AccountSettingsView.coffee @@ -234,3 +234,7 @@ module.exports = class AccountSettingsView extends RootView $(@).data 'saved-value', $(@).val() $('#settings-panes input:checkbox').each -> $(@).data 'saved-value', JSON.stringify $(@)[0].checked + + destroy: -> + @pictureTreema?.destroy() + super() \ No newline at end of file diff --git a/app/views/account/JobProfileTreemaView.coffee b/app/views/account/JobProfileTreemaView.coffee index 1ddde82e1..3c3b3a7f6 100644 --- a/app/views/account/JobProfileTreemaView.coffee +++ b/app/views/account/JobProfileTreemaView.coffee @@ -82,7 +82,7 @@ module.exports = class JobProfileTreemaView extends CocoView {name: 'Provide your name.', weight: 1, fn: modified 'name'} {name: 'Choose your city.', weight: 1, fn: modified 'city'} {name: 'Pick your country.', weight: 0, fn: exists 'country'} - {name: 'List at least five skills.', weight: 2, fn: -> jobProfile.skills.length >= 5} + {name: 'List at least five skills.', weight: 2, fn: -> jobProfile.skills?.length >= 5} {name: 'Write a short description to summarize yourself at a glance.', weight: 2, fn: modified 'shortDescription'} {name: 'Fill in your main description to sell yourself and describe the work you\'re looking for.', weight: 3, fn: modified 'longDescription'} {name: 'List your work experience.', weight: 3, fn: listStarted 'work', ['role', 'employer']} @@ -96,6 +96,10 @@ module.exports = class JobProfileTreemaView extends CocoView return {} unless me.get('jobProfile') or @hasEditedProfile _.pick @jobProfileTreema.data, (value, key) => key in @editableSettings + destroy: -> + @jobProfileTreema?.destroy() + super() + JobProfileTreemaView.commonSkills = commonSkills = ['c#', 'java', 'javascript', 'php', 'android', 'jquery', 'python', 'c++', 'html', 'mysql', 'ios', 'asp.net', 'css', 'sql', 'iphone', '.net', 'objective-c', 'ruby-on-rails', 'c', 'ruby', 'sql-server', 'ajax', 'wpf', 'linux', 'database', 'django', 'vb.net', 'windows', 'facebook', 'r', 'html5', 'multithreading', 'ruby-on-rails-3', 'wordpress', 'winforms', 'node.js', 'spring', 'osx', 'performance', 'visual-studio-2010', 'oracle', 'swing', 'algorithm', 'git', 'linq', 'apache', 'web-services', 'perl', 'wcf', 'entity-framework', 'bash', 'visual-studio', 'sql-server-2008', 'hibernate', 'actionscript-3', 'angularjs', 'matlab', 'qt', 'ipad', 'sqlite', 'cocoa-touch', 'cocoa', 'flash', 'mongodb', 'codeigniter', 'jquery-ui', 'css3', 'tsql', 'google-maps', 'silverlight', 'security', 'delphi', 'vba', 'postgresql', 'jsp', 'shell', 'internet-explorer', 'google-app-engine', 'sockets', 'validation', 'scala', 'oop', 'unit-testing', 'xaml', 'parsing', 'twitter-bootstrap', 'google-chrome', 'http', 'magento', 'email', 'android-layout', 'flex', 'rest', 'maven', 'jsf', 'listview', 'date', 'winapi', 'windows-phone-7', 'facebook-graph-api', 'unix', 'url', 'c#-4.0', 'jquery-ajax', 'svn', 'symfony2', 'table', 'cakephp', 'firefox', 'ms-access', 'java-ee', 'jquery-mobile', 'python-2.7', 'tomcat', 'zend-framework', 'opencv', 'visual-c++', 'opengl', 'spring-mvc', 'sql-server-2005', 'authentication', 'search', 'xslt', 'servlets', 'pdf', 'animation', 'math', 'batch-file', 'excel-vba', 'iis', 'mod-rewrite', 'sharepoint', 'gwt', 'powershell', 'visual-studio-2012', 'haskell', 'grails', 'ubuntu', 'networking', 'nhibernate', 'design-patterns', 'testing', 'jpa', 'visual-studio-2008', 'core-data', 'user-interface', 'audio', 'backbone.js', 'gcc', 'mobile', 'design', 'activerecord', 'extjs', 'video', 'stored-procedures', 'optimization', 'drupal', 'image-processing', 'android-intent', 'logging', 'web-applications', 'razor', 'database-design', 'azure', 'vim', 'memory-management', 'model-view-controller', 'cordova', 'c++11', 'selenium', 'ssl', 'assembly', 'soap', 'boost', 'canvas', 'google-maps-api-3', 'netbeans', 'heroku', 'jsf-2', 'encryption', 'hadoop', 'linq-to-sql', 'dll', 'xpath', 'data-binding', 'windows-phone-8', 'phonegap', 'jdbc', 'python-3.x', 'twitter', 'mvvm', 'gui', 'web', 'jquery-plugins', 'numpy', 'deployment', 'ios7', 'emacs', 'knockout.js', 'graphics', 'joomla', 'unicode', 'windows-8', 'android-fragments', 'ant', 'command-line', 'version-control', 'yii', 'github', 'amazon-web-services', 'macros', 'ember.js', 'svg', 'opengl-es', 'django-models', 'solr', 'orm', 'blackberry', 'windows-7', 'ruby-on-rails-4', 'compiler', 'tcp', 'pdo', 'architecture', 'groovy', 'nginx', 'concurrency', 'paypal', 'iis-7', 'express', 'vbscript', 'google-chrome-extension', 'memory-leaks', 'rspec', 'actionscript', 'interface', 'fonts', 'oauth', 'ssh', 'tfs', 'junit', 'struts2', 'd3.js', 'coldfusion', '.net-4.0', 'jqgrid', 'asp-classic', 'https', 'plsql', 'stl', 'sharepoint-2010', 'asp.net-web-api', 'mysqli', 'sed', 'awk', 'internet-explorer-8', 'jboss', 'charts', 'scripting', 'matplotlib', 'laravel', 'clojure', 'entity-framework-4', 'intellij-idea', 'xml-parsing', 'sqlite3', '3d', 'io', 'mfc', 'devise', 'playframework', 'youtube', 'amazon-ec2', 'localization', 'cuda', 'jenkins', 'ssis', 'safari', 'doctrine2', 'vb6', 'amazon-s3', 'dojo', 'air', 'eclipse-plugin', 'android-asynctask', 'crystal-reports', 'cocos2d-iphone', 'dns', 'highcharts', 'ruby-on-rails-3.2', 'ado.net', 'sql-server-2008-r2', 'android-emulator', 'spring-security', 'cross-browser', 'oracle11g', 'bluetooth', 'f#', 'msbuild', 'drupal-7', 'google-apps-script', 'mercurial', 'xna', 'google-analytics', 'lua', 'parallel-processing', 'internationalization', 'java-me', 'mono', 'monotouch', 'android-ndk', 'lucene', 'kendo-ui', 'linux-kernel', 'terminal', 'phpmyadmin', 'makefile', 'ffmpeg', 'applet', 'active-directory', 'coffeescript', 'pandas', 'responsive-design', 'xhtml', 'silverlight-4.0', '.net-3.5', 'jaxb', 'ruby-on-rails-3.1', 'gps', 'geolocation', 'network-programming', 'windows-services', 'laravel-4', 'ggplot2', 'rss', 'webkit', 'functional-programming', 'wsdl', 'telerik', 'maven-2', 'cron', 'mapreduce', 'websocket', 'automation', 'windows-runtime', 'django-forms', 'tkinter', 'android-widget', 'android-activity', 'rubygems', 'content-management-system', 'doctrine', 'django-templates', 'gem', 'fluent-nhibernate', 'seo', 'meteor', 'serial-port', 'glassfish', 'documentation', 'cryptography', 'ef-code-first', 'extjs4', 'x86', 'wordpress-plugin', 'go', 'wix', 'linq-to-entities', 'oracle10g', 'cocos2d', 'selenium-webdriver', 'open-source', 'jtable', 'qt4', 'smtp', 'redis', 'jvm', 'openssl', 'timezone', 'nosql', 'erlang', 'playframework-2.0', 'machine-learning', 'mocking', 'unity3d', 'thread-safety', 'android-actionbar', 'jni', 'udp', 'jasper-reports', 'zend-framework2', 'apache2', 'internet-explorer-7', 'sqlalchemy', 'neo4j', 'ldap', 'jframe', 'youtube-api', 'filesystems', 'make', 'flask', 'gdb', 'cassandra', 'sms', 'g++', 'django-admin', 'push-notification', 'statistics', 'tinymce', 'locking', 'javafx', 'firefox-addon', 'fancybox', 'windows-phone', 'log4j', 'uikit', 'prolog', 'socket.io', 'icons', 'oauth-2.0', 'refactoring', 'sencha-touch', 'elasticsearch', 'symfony1', 'google-api', 'webserver', 'wpf-controls', 'microsoft-metro', 'gtk', 'flex4', 'three.js', 'gradle', 'centos', 'angularjs-directive', 'internet-explorer-9', 'sass', 'html5-canvas', 'interface-builder', 'programming-languages', 'gmail', 'jersey', 'twitter-bootstrap-3', 'arduino', 'requirejs', 'cmake', 'web-development', 'software-engineering', 'startups', 'entrepreneurship', 'social-media-marketing', 'writing', 'marketing', 'web-design', 'graphic-design', 'game-development', 'game-design', 'photoshop', 'illustrator', 'robotics', 'aws', 'devops', 'mathematica', 'bioinformatics', 'data-vis', 'ui', 'embedded-systems', 'codecombat'] JobProfileTreemaView.commonLinkNames = commonLinkNames = ['GitHub', 'Facebook', 'Twitter', 'G+', 'LinkedIn', 'Personal Website', 'Blog'] @@ -107,25 +111,25 @@ JobProfileTreemaView.commonCities = commonCities = ['Tokyo', 'Jakarta', 'Seoul', autoFocus = true # Not working right now, possibly a Treema bower thing. class SkillTagNode extends TreemaNode.nodeMap.string - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) valEl.find('input').autocomplete(source: commonSkills, minLength: 1, delay: 0, autoFocus: autoFocus) valEl class LinkNameNode extends TreemaNode.nodeMap.string - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) valEl.find('input').autocomplete(source: commonLinkNames, minLength: 0, delay: 0, autoFocus: autoFocus) valEl class CityNode extends TreemaNode.nodeMap.string - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) valEl.find('input').autocomplete(source: commonCities, minLength: 1, delay: 0, autoFocus: autoFocus) valEl class CountryNode extends TreemaNode.nodeMap.string - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) valEl.find('input').autocomplete(source: commonCountries, minLength: 1, delay: 0, autoFocus: autoFocus) valEl diff --git a/app/views/admin/BaseView.coffee b/app/views/admin/BaseView.coffee new file mode 100644 index 000000000..ca58690c0 --- /dev/null +++ b/app/views/admin/BaseView.coffee @@ -0,0 +1,6 @@ +RootView = require 'views/kinds/RootView' +template = require 'templates/base' + +module.exports = class BaseView extends RootView + id: 'base-view' + template: template diff --git a/app/views/admin/CandidatesView.coffee b/app/views/admin/CandidatesView.coffee index 3216be2dc..39ddca817 100644 --- a/app/views/admin/CandidatesView.coffee +++ b/app/views/admin/CandidatesView.coffee @@ -52,9 +52,7 @@ module.exports = class CandidatesView extends RootView ctx._ = _ ctx - isEmployer: -> - userPermissions = me.get('permissions') ? [] - _.contains userPermissions, "employer" + isEmployer: -> 'employer' in me.get('permissions', true) setUpScrolling: -> $(".nano").nanoScroller() @@ -64,9 +62,9 @@ module.exports = class CandidatesView extends RootView $(".nano").nanoScroller({scrollTo:$(window.location.hash)}) checkForEmployerSignupHash: => - if window.location.hash is "#employerSignupLoggingIn" and not ("employer" in me.get("permissions")) + if window.location.hash is "#employerSignupLoggingIn" and not ("employer" in me.get('permissions', true)) @openModalView new EmployerSignupModal - window.location.hash = "" + window.location.hash = '' sortTable: -> # http://mottie.github.io/tablesorter/docs/example-widget-bootstrap-theme.html diff --git a/app/views/admin/MainAdminView.coffee b/app/views/admin/MainAdminView.coffee index 33bed066e..62c5d1ed5 100644 --- a/app/views/admin/MainAdminView.coffee +++ b/app/views/admin/MainAdminView.coffee @@ -5,32 +5,56 @@ template = require 'templates/admin' module.exports = class MainAdminView extends RootView id: 'admin-view' template: template + lastUserSearchValue: '' events: + 'keyup': 'checkForFormSubmissionEnterPress' 'click #enter-espionage-mode': 'enterEspionageMode' + 'click #user-search-button': 'searchForUser' 'click #increment-button': 'incrementUserAttribute' + checkForFormSubmissionEnterPress: (e) -> + if e.which is 13 and @$el.find('#espionage-name-or-email').val() isnt '' + @enterEspionageMode() + return + if @$el.find('#user-search').val() isnt @lastUserSearchValue + @searchForUser() + enterEspionageMode: -> - userEmail = $('#user-email').val().toLowerCase() - username = $('#user-username').val().toLowerCase() - - postData = - usernameLower: username - emailLower: userEmail - + userNameOrEmail = @$el.find('#espionage-name-or-email').val().toLowerCase() $.ajax type: 'POST', url: '/auth/spy' - data: postData + data: {nameOrEmailLower: userNameOrEmail} success: @espionageSuccess error: @espionageFailure espionageSuccess: (model) -> window.location.reload() - espionageFailure: (jqxhr, status,error)-> + espionageFailure: (jqxhr, status, error)-> console.log "There was an error entering espionage mode: #{error}" + searchForUser: -> + return @onSearchRequestSuccess [] unless @lastUserSearchValue = @$el.find('#user-search').val().toLowerCase() + $.ajax + type: 'POST', + url: '/db/user/-/admin_search' + data: {search: @lastUserSearchValue} + success: @onSearchRequestSuccess + error: @onSearchRequestFailure + + onSearchRequestSuccess: (users) => + result = '' + if users.length + result = ("#{user._id}#{_.escape(user.name or 'Anoner')}#{_.escape(user.email)}" for user in users) + result = "#{result.join('\n')}
" + @$el.find('#user-search-result').html(result) + + onSearchRequestFailure: (jqxhr, status, error) => + return if @destroyed + console.warn "There was an error looking up #{@lastUserSearchValue}:", error + incrementUserAttribute: (e) -> val = $('#increment-field').val() me.set(val, me.get(val) + 1) diff --git a/app/views/common/LevelSessionCodeView.coffee b/app/views/common/LevelSessionCodeView.coffee index 277eb2e3e..1977d9b03 100644 --- a/app/views/common/LevelSessionCodeView.coffee +++ b/app/views/common/LevelSessionCodeView.coffee @@ -26,13 +26,16 @@ module.exports = class LevelSessionCodeView extends CocoView afterRender: -> super() + editors = [] @$el.find('.code').each (index, codeEl) -> height = parseInt($(codeEl).data('height')) $(codeEl).height(height) editor = ace.edit codeEl editor.setReadOnly true + editors.push editor aceSession = editor.getSession() aceSession.setMode 'ace/mode/javascript' + @editors = editors organizeCode: -> team = @session.get('team') or 'humans' @@ -47,4 +50,8 @@ module.exports = class LevelSessionCodeView extends CocoView name: spell height: height } - filteredSpells \ No newline at end of file + filteredSpells + + destroy: -> + for editor in @editors + @editors \ No newline at end of file diff --git a/app/views/contribute/ArchmageView.coffee b/app/views/contribute/ArchmageView.coffee index e9847448a..4fd0e7494 100644 --- a/app/views/contribute/ArchmageView.coffee +++ b/app/views/contribute/ArchmageView.coffee @@ -10,25 +10,26 @@ module.exports = class ArchmageView extends ContributeClassView {id: '52ccfc9bd3eb6b5a4100b60d', name: 'Glen De Cauwsemaecker', github: 'GlenDC'} {id: '52bfc3ecb7ec628868001297', name: 'Tom Steinbrecher', github: 'TomSteinbrecher'} {id: '5272806093680c5817033f73', name: 'Sébastien Moratinos', github: 'smoratinos'} - {name: 'deepak1556', avatar: 'deepak', github: 'deepak1556'} - {name: 'Ronnie Cheng', avatar: 'ronald', github: 'rhc2104'} - {name: 'Chloe Fan', avatar: 'chloe', github: 'chloester'} - {name: 'Rachel Xiang', avatar: 'rachel', github: 'rdxiang'} - {name: 'Dan Ristic', avatar: 'dan', github: 'dristic'} - {name: 'Brad Dickason', avatar: 'brad', github: 'bdickason'} - {name: 'Rebecca Saines', avatar: 'becca'} - {name: 'Laura Watiker', avatar: 'laura', github: 'lwatiker'} - {name: 'Shiying Zheng', avatar: 'shiying', github: 'shiyingzheng'} - {name: 'Mischa Lewis-Norelle', avatar: 'mischa', github: 'mlewisno'} - {name: 'Paul Buser', avatar: 'paul'} - {name: 'Benjamin Stern', avatar: 'ben'} - {name: 'Alex Cotsarelis', avatar: 'alex'} - {name: 'Ken Stanley', avatar: 'ken'} - {name: 'devast8a', avatar: '', github: 'devast8a'} - {name: 'phansch', avatar: '', github: 'phansch'} - {name: 'Zach Martin', avatar: '', github: 'zachster01'} + {id: '52d133893dc46cbe15001179', name: 'Deepak Raj', github: 'deepak1556'} + {id: '52699df70e404d591b000af7', name: 'Ronnie Cheng', github: 'rhc2104'} + {id: '5260b4c3ae8ec6795e000019', name: 'Chloe Fan', github: 'chloester'} + {id: '52d726ab3c70cec90c008f2d', name: 'Rachel Xiang', github: 'rdxiang'} + {id: '5286706d93df39a952001574', name: 'Dan Ristic', github: 'dristic'} + {id: '52cec8620b0d5c1b4c0039e6', name: 'Brad Dickason', github: 'bdickason'} + {id: '540397e2bc5b69a40e9c2fb1', name: 'Rebecca Saines'} + {id: '525ae40248839d81090013f2', name: 'Laura Watiker', github: 'lwatiker'} + {id: '540395e9fe56769115d7da86', name: 'Shiying Zheng', github: 'shiyingzheng'} + {id: '5403964dfe56769115d7da96', name: 'Mischa Lewis-Norelle', github: 'mlewisno'} + {id: '52b8be459e47006b4100094b', name: 'Paul Buser'} + {id: '540396effe56769115d7daa8', name: 'Benjamin Stern'} + {id: '5403974b11058b4213074779', name: 'Alex Cotsarelis'} + {id: '54039780fe56769115d7dab5', name: 'Ken Stanley'} + {id: '531258b5e0789d4609614110', name: 'Ruben Vereecken', github: 'rubenvereecken'} + {id: '5276ad5dcf83207a2801d3b4', name: 'Zach Martin', github: 'zachster01'} + {id: '530df0cbc06854403ba67c15', name: 'Alexandru Caciulescu', github: 'Darredevil'} {name: 'David Golds', avatar: ''} {name: 'gabceb', avatar: '', github: 'gabceb'} {name: 'MDP66', avatar: '', github: 'MDP66'} - {name: 'Alexandru Caciulescu', avatar: '', github: 'Darredevil'} + {name: 'devast8a', avatar: '', github: 'devast8a'} + {name: 'phansch', avatar: '', github: 'phansch'} ] diff --git a/app/views/contribute/ArtisanView.coffee b/app/views/contribute/ArtisanView.coffee index 40aa5bba0..c64e66be5 100644 --- a/app/views/contribute/ArtisanView.coffee +++ b/app/views/contribute/ArtisanView.coffee @@ -8,18 +8,18 @@ module.exports = class ArtisanView extends ContributeClassView contributorClassName: 'artisan' contributors: [ + {id: '5276ad5dcf83207a2801d3b4', name: 'Zach Martin', github: 'zachster01'} + {id: '530df0cbc06854403ba67c15', name: 'Alexandru Caciulescu', github: 'Darredevil'} + {id: '54038e91d3dbccd212505dee', name: 'Robert Moreton'} + {id: '54038f0bbc5b69a40e9c2a01', name: 'Andrew Witcher'} + {id: '54038f6b11058b4213074320', name: 'Axandre Oge'} + {id: '5403905c0557f27b0c3384be', name: 'Katharine Chan'} + {id: '5403908e0557f27b0c3384d9', name: 'Derek Wong'} {name: 'Sootn', avatar: ''} - {name: 'Zach Martin', avatar: '', github: 'zachster01'} {name: 'Aftermath', avatar: ''} {name: 'mcdavid1991', avatar: ''} {name: 'dwhittaker', avatar: ''} {name: 'Zacharias Fisches', avatar: ''} {name: 'Tom Setliff', avatar: ''} - {name: 'Robert Moreton', avatar: 'rob'} - {name: 'Andrew Witcher', avatar: 'andrew'} - {name: 'Axandre Oge', avatar: 'axandre'} - {name: 'Katharine Chan', avatar: 'katharine'} - {name: 'Derek Wong', avatar: 'derek'} - {name: 'Alexandru Caciulescu', avatar: '', github: 'Darredevil'} {name: 'Prabh Simran Singh Baweja', avatar: '', github: 'prabh27'} ] diff --git a/app/views/contribute/DiplomatView.coffee b/app/views/contribute/DiplomatView.coffee index 1f075803f..f63286183 100644 --- a/app/views/contribute/DiplomatView.coffee +++ b/app/views/contribute/DiplomatView.coffee @@ -39,54 +39,49 @@ module.exports = class DiplomatView extends ContributeClassView 'en-US': [] # English (US), English (US) 'en-GB': [] # English (UK), English (UK) 'en-AU': [] # English (AU), English (AU) - ru: ['fess89', 'ser-storchak', 'Mr A', 'a1ip'] # русский язык, Russian - de: ['Dirk', 'faabsen', 'HiroP0', 'Anon', 'bkimminich'] # Deutsch, German - 'de-DE': [] # Deutsch (Deutschland), German (Germany) - 'de-AT': [] # Deutsch (Österreich), German (Austria) - 'de-CH': [] # Deutsch (Schweiz), German (Switzerland) - es: [] # español, Spanish - 'es-419': ['Jesús Ruppel', 'Matthew Burt', 'Mariano Luzza'] # español (América Latina), Spanish (Latin America) - 'es-ES': ['Matthew Burt', 'DanielRodriguezRivero', 'Anon', 'Pouyio'] # español (ES), Spanish (Spain) - zh: ['Adam23', 'spacepope', 'yangxuan8282', 'Cheng Zheng'] # 中文, Chinese - 'zh-HANS': [] # 简体中文, Chinese (Simplified) - 'zh-HANT': [] # 繁体中文, Chinese (Traditional) + ru: ['fess89', 'ser-storchak', 'Mr A', 'a1ip', 'iulianR', 'EagleTA', 'kisik21', 'Shpionus', 'kerradus', 'ImmortalJoker'] # русский язык, Russian + 'de-DE': ['Dirk', 'faabsen', 'HiroP0', 'Anon', 'bkimminich', 'bahuma20', 'domenukk', 'dkundel'] # Deutsch (Deutschland), German (Germany) + 'de-AT': ['djsmith85'] # Deutsch (Österreich), German (Austria) + 'de-CH': ['greyhusky'] # Deutsch (Schweiz), German (Switzerland) + 'es-419': ['Jesús Ruppel', 'Matthew Burt', 'Mariano Luzza', '2xG', ] # español (América Latina), Spanish (Latin America) + 'es-ES': ['Matthew Burt', 'DanielRodriguezRivero', 'Anon', 'Pouyio', '3rr3s3v3n', 'OviiiOne', 'Vindurrin'] # español (ES), Spanish (Spain) + 'zh-HANS': ['Adam23', 'spacepope', 'yangxuan8282', 'Cheng Zheng', 'yfdyh000', 'julycoolwind', 'Vic020', 'onion7878', 'BonnieBBS', '1c7', 'ZephyrSails'] # 简体中文, Chinese (Simplified) + 'zh-HANT': ['gintau', 'Adam23'] # 繁体中文, Chinese (Traditional) 'zh-WUU-HANS': [] # 吴语, Wuu (Simplified) - 'zh-WUU-HANT': [] # 吳語, Wuu (Traditional) - fr: ['Xeonarno', 'Elfisen', 'Armaldio', 'MartinDelille', 'pstweb', 'veritable', 'jaybi', 'xavismeh', 'Anon', 'Feugy'] # français, French + 'zh-WUU-HANT': ['benojan'] # 吳語, Wuu (Traditional) + fr: ['Xeonarno', 'Elfisen', 'Armaldio', 'MartinDelille', 'pstweb', 'veritable', 'jaybi', 'xavismeh', 'Anon', 'Feugy', 'dc55028', 'ChrisLightman', 'Oaugereau'] # français, French ja: ['g1itch', 'kengos', 'treby'] # 日本語, Japanese - ar: [] # العربية, Arabic - pt: [] # português, Portuguese - 'pt-BR': ['Gutenberg Barros', 'Kieizroe', 'Matthew Burt', 'brunoporto', 'cassiocardoso'] # português do Brasil, Portuguese (Brazil) - 'pt-PT': ['Matthew Burt', 'ReiDuKuduro', 'Imperadeiro98'] # Português (Portugal), Portuguese (Portugal) - pl: ['Anon', 'Kacper Ciepielewski'] # język polski, Polish - it: ['flauta'] # italiano, Italian - tr: ['Nazım Gediz Aydındoğmuş', 'cobaimelan', 'wakeup'] # Türkçe, Turkish - nl: ['Glen De Cauwsemaecker', 'Guido Zuidhof', 'Ruben Vereecken', 'Jasper D\'haene'] # Nederlands, Dutch - 'nl-BE': [] # Nederlands (België), Dutch (Belgium) - 'nl-NL': [] # Nederlands (Nederland), Dutch (Netherlands) + ar: ['ahmed80dz', '5y'] # العربية, Arabic + 'pt-BR': ['Gutenberg Barros', 'Kieizroe', 'Matthew Burt', 'brunoporto', 'cassiocardoso', 'Bia41'] # português do Brasil, Portuguese (Brazil) + 'pt-PT': ['Matthew Burt', 'ReiDuKuduro', 'Imperadeiro98', 'batista', 'ProgramadorLucas', 'gutierri'] # Português (Portugal), Portuguese (Portugal) + pl: ['Anon', 'Kacper Ciepielewski', 'TigroTigro', 'kvasnyk'] # język polski, Polish + it: ['flauta', 'AlessioPaternoster'] # italiano, Italian + tr: ['Nazım Gediz Aydındoğmuş', 'cobaimelan', 'wakeup', 'gediz', 'ilisyus'] # Türkçe, Turkish + 'nl-BE': ['Glen De Cauwsemaecker', 'Ruben Vereecken'] # Nederlands (België), Dutch (Belgium) + 'nl-NL': ['Jasper D\'haene', 'Guido Zuidhof'] # Nederlands (Nederland), Dutch (Netherlands) fa: ['Reza Habibi (Rehb)'] # فارسی, Persian cs: ['vanous'] # čeština, Czech - sv: [] # Svenska, Swedish - id: [] # Bahasa Indonesia, Indonesian + sv: ['iamhj'] # Svenska, Swedish + id: ['mlewisno-oberlin'] # Bahasa Indonesia, Indonesian el: ['Stergios'] # ελληνικά, Greek ro: [] # limba română, Romanian vi: ['An Nguyen Hoang Thien'] # Tiếng Việt, Vietnamese - hu: ['ferpeter', 'csuvsaregal', 'atlantisguru', 'Anon'] # magyar, Hungarian + hu: ['ferpeter', 'csuvsaregal', 'atlantisguru', 'Anon', 'kinez', 'bbeasmile'] # magyar, Hungarian th: ['Kamolchanok Jittrepit'] # ไทย, Thai - da: ['Einar Rasmussen', 'sorsjen', 'Randi Hillerøe', 'Anon'] # dansk, Danish - ko: [] # 한국어, Korean + da: ['Einar Rasmussen', 'sorsjen', 'Randi Hillerøe', 'Anon', 'Silwing', 'Rahazan', 'marc-portier'] # dansk, Danish + ko: ['Melondonut'] # 한국어, Korean sk: ['Anon'] # slovenčina, Slovak sl: [] # slovenščina, Slovene fi: [] # suomi, Finnish bg: [] # български език, Bulgarian - no: ['bardeh'] # Norsk, Norwegian + no: ['bardeh', 'torehaug'] # Norsk, Norwegian nn: [] # Norwegian (Nynorsk), Norwegian Nynorsk nb: [] # Norsk Bokmål, Norwegian (Bokmål) - he: [] # עברית, Hebrew + he: ['OverProgram', 'monetita'] # עברית, Hebrew lt: [] # lietuvių kalba, Lithuanian sr: [] # српски, Serbian - uk: ['fess89'] # українська мова, Ukrainian + uk: ['fess89', 'ImmortalJoker', 'gorodsb', 'endrilian', 'OlenaGapak'] # українська мова, Ukrainian hi: [] # मानक हिन्दी, Hindi ur: [] # اُردُو, Urdu ms: [] # Bahasa Melayu, Bahasa Malaysia - ca: [] # Català, Catalan + ca: ['ArniMcFrag'] # Català, Catalan diff --git a/app/views/docs/ComponentDocumentationView.coffee b/app/views/docs/ComponentDocumentationView.coffee deleted file mode 100644 index 7418e333d..000000000 --- a/app/views/docs/ComponentDocumentationView.coffee +++ /dev/null @@ -1,26 +0,0 @@ -#RootView = require 'views/kinds/RootView' -CocoView = require 'views/kinds/CocoView' -template = require 'templates/docs/components' -CocoCollection = require 'collections/CocoCollection' -LevelComponent = require 'models/LevelComponent' - -class ComponentDocsCollection extends CocoCollection - url: '/db/level.component?project=name,description,dependencies,propertyDocumentation,code' - model: LevelComponent - -module.exports = class ComponentDocumentationView extends CocoView - id: 'docs-components-view' - template: template - className: 'tab-pane' - - constructor: (options) -> - super(options) - @componentDocs = new ComponentDocsCollection() - @supermodel.loadCollection @componentDocs, 'components' - - getRenderData: -> - c = super() - c.components = @componentDocs.models - c.marked = marked - c.codeLanguage = me.get('aceConfig')?.language ? 'javascript' - c diff --git a/app/views/docs/ComponentsDocumentationView.coffee b/app/views/docs/ComponentsDocumentationView.coffee new file mode 100644 index 000000000..8d5b01be7 --- /dev/null +++ b/app/views/docs/ComponentsDocumentationView.coffee @@ -0,0 +1,48 @@ +CocoView = require 'views/kinds/CocoView' +template = require 'templates/docs/components-documentation-view' +CocoCollection = require 'collections/CocoCollection' +LevelComponent = require 'models/LevelComponent' + +class ComponentDocsCollection extends CocoCollection + url: '/db/level.component?project=system,name,description,dependencies,propertyDocumentation,code' + model: LevelComponent + comparator: 'system' + +module.exports = class ComponentsDocumentationView extends CocoView + id: 'components-documentation-view' + template: template + className: 'tab-pane' + collapsed: true + + events: + 'click #toggle-all-component-code': 'onToggleAllCode' + + subscriptions: + 'editor:view-switched': 'onViewSwitched' + + constructor: (options) -> + super(options) + @componentDocs = new ComponentDocsCollection() + @loadDocs() unless options.lazy + + loadDocs: -> + return if @loadingDocs + @supermodel.loadCollection @componentDocs, 'components' + @loadingDocs = true + @render() + + getRenderData: -> + c = super() + c.components = @componentDocs.models + c.marked = marked + c.codeLanguage = me.get('aceConfig')?.language ? 'javascript' + c + + onToggleAllCode: (e) -> + @collapsed = not @collapsed + @$el.find('.collapse').collapse(if @collapsed then 'hide' else 'show') + @$el.find('#toggle-all-component-code').toggleClass 'active', not @collapsed + + onViewSwitched: (e) -> + return unless e.targetURL is '#editor-level-documentation' + @loadDocs() diff --git a/app/views/docs/SystemsDocumentationView.coffee b/app/views/docs/SystemsDocumentationView.coffee new file mode 100644 index 000000000..8c3e251fe --- /dev/null +++ b/app/views/docs/SystemsDocumentationView.coffee @@ -0,0 +1,48 @@ +CocoView = require 'views/kinds/CocoView' +template = require 'templates/docs/systems-documentation-view' +CocoCollection = require 'collections/CocoCollection' +LevelSystem = require 'models/LevelSystem' + +class SystemDocsCollection extends CocoCollection + url: '/db/level.system?project=name,description,code' + model: LevelSystem + comparator: 'name' + +module.exports = class SystemsDocumentationView extends CocoView + id: 'systems-documentation-view' + template: template + className: 'tab-pane' + collapsed: true + + events: + 'click #toggle-all-system-code': 'onToggleAllCode' + + subscriptions: + 'editor:view-switched': 'onViewSwitched' + + constructor: (options) -> + super(options) + @systemDocs = new SystemDocsCollection() + @loadDocs() unless options.lazy + + loadDocs: -> + return if @loadingDocs + @supermodel.loadCollection @systemDocs, 'systems' + @loadingDocs = true + @render() + + getRenderData: -> + c = super() + c.systems = @systemDocs.models + c.marked = marked + c.codeLanguage = me.get('aceConfig')?.language ? 'javascript' + c + + onToggleAllCode: (e) -> + @collapsed = not @collapsed + @$el.find('.collapse').collapse(if @collapsed then 'hide' else 'show') + @$el.find('#toggle-all-system-code').toggleClass 'active', not @collapsed + + onViewSwitched: (e) -> + return unless e.targetURL is '#editor-level-documentation' + @loadDocs() diff --git a/app/views/editor/ForkModal.coffee b/app/views/editor/ForkModal.coffee index 99e4170ea..63399693f 100644 --- a/app/views/editor/ForkModal.coffee +++ b/app/views/editor/ForkModal.coffee @@ -31,7 +31,7 @@ module.exports = class ForkModal extends ModalView newModel.unset 'parent' newModel.set 'commitMessage', "Forked from #{@model.get('name')}" newModel.set 'name', @$el.find('#fork-model-name').val() - if @model.get 'permissions' + if @model.schema.properties.permissions newModel.set 'permissions', [access: 'owner', target: me.id] newPathPrefix = "editor/#{@editorPath}/" res = newModel.save() diff --git a/app/views/editor/achievement/AchievementEditView.coffee b/app/views/editor/achievement/AchievementEditView.coffee index 524c14e2e..0825c9de6 100644 --- a/app/views/editor/achievement/AchievementEditView.coffee +++ b/app/views/editor/achievement/AchievementEditView.coffee @@ -41,6 +41,7 @@ module.exports = class AchievementEditView extends RootView change: @pushChangesToPreview @treema = @$el.find('#achievement-treema').treema(options) @treema.build() + @pushChangesToPreview() getRenderData: (context={}) -> context = super(context) @@ -54,6 +55,7 @@ module.exports = class AchievementEditView extends RootView @pushChangesToPreview() pushChangesToPreview: => + return unless @treema @$el.find('#achievement-view').empty() for key, value of @treema.data @achievement.set key, value diff --git a/app/views/editor/component/ThangComponentConfigView.coffee b/app/views/editor/component/ThangComponentConfigView.coffee index b27ddb177..6b447ab5a 100644 --- a/app/views/editor/component/ThangComponentConfigView.coffee +++ b/app/views/editor/component/ThangComponentConfigView.coffee @@ -10,13 +10,12 @@ module.exports = class ThangComponentConfigView extends CocoView template: template changed: false - events: - 'click .treema-shortened': -> console.log 'clicked treema root' - constructor: (options) -> super options @component = options.component @config = options.config or {} + @additionalDefaults = options.additionalDefaults + @isDefaultComponent = false @world = options.world @level = options.level @callback = options.callback @@ -25,26 +24,40 @@ module.exports = class ThangComponentConfigView extends CocoView context = super(context) context.component = @component.attributes context.configProperties = [] + context.isDefaultComponent = @isDefaultComponent context afterRender: -> super() @buildTreema() + setConfig: (config) -> + @handlingChange = true + @editThangTreema.set('/', config) + @handlingChange = false + + setIsDefaultComponent: (isDefaultComponent) -> + changed = @isDefaultComponent isnt isDefaultComponent + if isDefaultComponent then @config = undefined + @isDefaultComponent = isDefaultComponent + @render() if changed + buildTreema: -> thangs = if @level? then @level.get('thangs') else [] thangIDs = _.filter(_.pluck(thangs, 'id')) teams = _.filter(_.pluck(thangs, 'team')) superteams = _.filter(_.pluck(thangs, 'superteam')) superteams = _.union(teams, superteams) - config = $.extend true, {}, @config schema = $.extend true, {}, @component.get('configSchema') + schema.default ?= {} + _.merge schema.default, @additionalDefaults if @additionalDefaults + if @level?.get('type') is 'hero' schema.required = [] treemaOptions = supermodel: @supermodel schema: schema - data: config + data: @config callbacks: {change: @onConfigEdited} world: @world view: @ @@ -64,6 +77,7 @@ module.exports = class ThangComponentConfigView extends CocoView 'seconds': nodes.SecondsNode 'speed': nodes.SpeedNode 'acceleration': nodes.AccelerationNode + 'thang-type': nodes.ThangTypeNode 'item-thang-type': nodes.ItemThangTypeNode @editThangTreema = @$el.find('.treema').treema treemaOptions @@ -73,10 +87,16 @@ module.exports = class ThangComponentConfigView extends CocoView @$el.find('.panel-body').hide() onConfigEdited: => + return if @destroyed or @handlingChange + @config = @data() @changed = true - @trigger 'changed', { component: @component, config: @data() } + @trigger 'changed', { component: @component, config: @config } data: -> @editThangTreema.data + destroy: -> + @editThangTreema?.destroy() + super() + class ComponentConfigNode extends TreemaObjectNode nodeDescription: 'Component Property' diff --git a/app/views/editor/component/ThangComponentsEditView.coffee b/app/views/editor/component/ThangComponentsEditView.coffee index eb72a84f4..dc8d2e0fb 100644 --- a/app/views/editor/component/ThangComponentsEditView.coffee +++ b/app/views/editor/component/ThangComponentsEditView.coffee @@ -12,6 +12,28 @@ nodes = require '../level/treema_nodes' ThangType = require 'models/ThangType' CocoCollection = require 'collections/CocoCollection' +LC = (componentName, config) -> original: LevelComponent[componentName + 'ID'], majorVersion: 0, config: config +DEFAULT_COMPONENTS = + Unit: [LC('Equips')] + Floor: [ + LC('Exists', stateless: true) + LC('Physical', width: 20, height: 17, depth: 2, shape: 'sheet', pos: {x: 10, y: 8.5, z: 1}) + LC('Land') + ] + Wall: [ + LC('Exists', stateless: true) + LC('Physical', width: 4, height: 4, depth: 12, shape: 'box', pos: {x: 2, y: 2, z: 6}) + LC('Collides', collisionType: 'static', collisionCategory: 'obstacles', mass: 1000, fixedRotation: true, restitution: 1) + ] + Doodad: [ + LC('Exists', stateless: true) + LC('Physical') + LC('Collides', collisionType: 'static', fixedRotation: true) + ] + Misc: [LC('Exists'), LC('Physical')] + Mark: [] + Item: [LC('Item')] + class ItemThangTypeSearchCollection extends CocoCollection url: '/db/thang.type?view=items&project=original,name,version,slug,kind,components' model: ThangType @@ -20,22 +42,33 @@ module.exports = class ThangComponentsEditView extends CocoView id: 'thang-components-edit-view' template: template + subscriptions: + 'editor:thang-type-kind-changed': 'onThangTypeKindChanged' + events: 'click #add-components-button': 'onAddComponentsButtonClicked' constructor: (options) -> super options + @originalsLoaded = {} @components = options.components or [] @components = $.extend true, [], @components # just to be sure + @setThangType options.thangType @lastComponentLength = @components.length @world = options.world @level = options.level @loadComponents(@components) - # Need to grab the ThangTypes so that we can autocomplete items in inventory based on them. - @itemThangTypes = @supermodel.loadCollection(new ItemThangTypeSearchCollection(), 'thangs').model + + setThangType: (@thangType) -> + return unless componentRefs = @thangType?.get('components') + @loadComponents(componentRefs) loadComponents: (components) -> for componentRef in components + # just to handle if ever somehow the same component is loaded twice, through bad data and alike + continue if @originalsLoaded[componentRef.original] + @originalsLoaded[componentRef.original] = componentRef.original + levelComponent = new LevelComponent(componentRef) url = "/db/level.component/#{componentRef.original}/version/#{componentRef.majorVersion}" levelComponent.setURL(url) @@ -54,26 +87,22 @@ module.exports = class ThangComponentsEditView extends CocoView @addThangComponentConfigViews() buildComponentsTreema: -> + components = _.zipObject((c.original for c in @components), @components) + defaultValue = undefined + if thangTypeComponents = @thangType?.get('components', true) + defaultValue = _.zipObject((c.original for c in thangTypeComponents), thangTypeComponents) + treemaOptions = supermodel: @supermodel - schema: Level.schema.properties.thangs.items.properties.components - data: $.extend true, [], @components + schema: { + type: 'object' + default: defaultValue + additionalProperties: Level.schema.properties.thangs.items.properties.components.items + }, + data: $.extend true, {}, components callbacks: {select: @onSelectComponent, change: @onComponentsTreemaChanged} - noSortable: true nodeClasses: - 'thang-components-array': ThangComponentsArrayNode - 'point2d': nodes.WorldPointNode - 'viewport': nodes.WorldViewportNode - 'bounds': nodes.WorldBoundsNode - 'radians': nodes.RadiansNode - 'team': nodes.TeamNode - 'superteam': nodes.SuperteamNode - 'meters': nodes.MetersNode - 'kilograms': nodes.KilogramsNode - 'seconds': nodes.SecondsNode - 'speed': nodes.SpeedNode - 'acceleration': nodes.AccelerationNode - 'item-thang-type': nodes.ItemThangTypeNode + 'object': ThangComponentsObjectNode @componentsTreema = @$el.find('#thang-components-column .treema').treema treemaOptions @componentsTreema.build() @@ -86,7 +115,7 @@ module.exports = class ThangComponentsEditView extends CocoView componentMap[component.original] = component newComponentsList = [] - for component in @componentsTreema.data + for component in _.values(@componentsTreema.data) newComponentsList.push(componentMap[component.original] or component) @components = newComponentsList @@ -102,14 +131,18 @@ module.exports = class ThangComponentsEditView extends CocoView if @components.length < @lastComponentLength @onComponentsRemoved() - else - @onComponentsAdded() + @onComponentsAdded() onComponentsRemoved: -> componentMap = {} for component in @components componentMap[component.original] = component + thangComponentMap = {} + if thangTypeComponents = @thangType?.get('components') + for thangTypeComponent in thangTypeComponents + thangComponentMap[thangTypeComponent.original] = thangTypeComponent + # Deleting components missing dependencies. while true removedSomething = false @@ -117,7 +150,7 @@ module.exports = class ThangComponentsEditView extends CocoView componentModel = @supermodel.getModelByOriginalAndMajorVersion( LevelComponent, componentRef.original, componentRef.majorVersion) for dependency in componentModel.get('dependencies') or [] - if not componentMap[dependency.original] + unless (componentMap[dependency.original] or thangComponentMap[dependency.original]) delete componentMap[componentRef.original] component = @supermodel.getModelByOriginal( LevelComponent, componentRef.original) @@ -136,14 +169,16 @@ module.exports = class ThangComponentsEditView extends CocoView # Delete individual component config views that are no longer included. for subview in _.values(@subviews) continue unless subview instanceof ThangComponentConfigView - if not componentMap[subview.component.get('original')] + unless (componentMap[subview.component.get('original')] or thangComponentMap[subview.component.get('original')]) @removeSubView(subview) @updateComponentsList() @reportChanges() updateComponentsList: -> - @componentsTreema?.set('/', $.extend(true, [], @components)) + # Before I was setting the data to the existing treema but then we had some + # nasty sorting/callback bugs. This is less efficient, but it's also less bug prone. + @buildComponentsTreema() onComponentsAdded: -> return unless @componentsTreema @@ -151,17 +186,24 @@ module.exports = class ThangComponentsEditView extends CocoView for component in @components componentMap[component.original] = component + if thangTypeComponents = @thangType?.get('components') + for thangTypeComponent in thangTypeComponents + componentMap[thangTypeComponent.original] = thangTypeComponent + # Go through the map, adding missing dependencies. while true addedSomething = false for componentRef in _.values(componentMap) componentModel = @supermodel.getModelByOriginalAndMajorVersion( LevelComponent, componentRef.original, componentRef.majorVersion) + if not componentModel?.loaded + @loadComponents([componentRef]) + continue for dependency in componentModel?.get('dependencies') or [] if not componentMap[dependency.original] component = @supermodel.getModelByOriginalAndMajorVersion( LevelComponent, dependency.original, dependency.majorVersion) - if not component + if not component?.loaded @loadComponents([dependency]) # will run onComponentsAdded once more when the model loads else @@ -194,17 +236,31 @@ module.exports = class ThangComponentsEditView extends CocoView # Put back config views into the DOM based on the component list ordering, # adding and registering new ones as needed. configsEl = @$el.find('#thang-component-configs') - for componentRef in @componentsTreema.data + + componentRefs = _.merge {}, @componentsTreema.data + if thangTypeComponents = @thangType?.get('components') + thangComponentRefs = _.zipObject((c.original for c in thangTypeComponents), thangTypeComponents) + for thangTypeComponent in thangTypeComponents + if componentRef = componentRefs[thangTypeComponent.original] + componentRef.additionalDefaults = thangTypeComponent.config + else + modifiedRef = _.merge {}, thangTypeComponent + modifiedRef.additionalDefaults = modifiedRef.config + delete modifiedRef.config + componentRefs[thangTypeComponent.original] = modifiedRef + + for componentRef in _.values(componentRefs) subview = componentConfigViews[componentRef.original] if not subview subview = @makeThangComponentConfigView(componentRef) continue unless subview @registerSubView(subview) + subview.setIsDefaultComponent(not @componentsTreema.data[componentRef.original]) configsEl.append(subview.$el) makeThangComponentConfigView: (thangComponent) -> component = @supermodel.getModelByOriginal(LevelComponent, thangComponent.original) - return unless component + return unless component?.loaded config = thangComponent.config ? {} configView = new ThangComponentConfigView({ supermodel: @supermodel @@ -212,53 +268,69 @@ module.exports = class ThangComponentsEditView extends CocoView world: @world config: config component: component + additionalDefaults: thangComponent.additionalDefaults }) configView.render() @listenTo configView, 'changed', @onConfigChanged configView onConfigChanged: (e) -> + foundComponent = false for thangComponent in @components if thangComponent.original is e.component.get('original') thangComponent.config = e.config + foundComponent = true + break + + if not foundComponent + @components.push({ + original: e.component.get('original') + majorVersion: e.component.get('version').major + config: e.config + }) + + for subview in _.values(@subviews) + continue unless subview instanceof ThangComponentConfigView + if subview.component.get('original') is e.component.get('original') + _.defer -> subview.setIsDefaultComponent(false) + break + + @updateComponentsList() @reportChanges() onSelectComponent: (e, nodes) => @componentsTreema.$el.find('.dependent').removeClass('dependent') + @$el.find('.selected-component').removeClass('selected-component') return unless nodes.length is 1 # find dependent components dependents = {} - dependents[nodes[0].data.original] = true - componentsToCheck = [nodes[0].data.original] + dependents[nodes[0].getData().original] = true + componentsToCheck = [nodes[0].getData().original] while componentsToCheck.length componentOriginal = componentsToCheck.pop() for otherComponentRef in @components continue if otherComponentRef.original is componentOriginal continue if dependents[otherComponentRef.original] otherComponent = @supermodel.getModelByOriginal(LevelComponent, otherComponentRef.original) - for dependency in otherComponent.get('dependencies') + for dependency in otherComponent.get('dependencies', true) if dependents[dependency.original] dependents[otherComponentRef.original] = true componentsToCheck.push otherComponentRef.original # highlight them for child in _.values(@componentsTreema.childrenTreemas) - if dependents[child.data.original] + if dependents[child.getData().original] child.$el.addClass('dependent') # scroll to the config for subview in _.values(@subviews) continue unless subview instanceof ThangComponentConfigView - if subview.component.get('original') is nodes[0].data.original + if subview.component.get('original') is nodes[0].getData().original subview.$el[0].scrollIntoView() + subview.$el.addClass('selected-component') break - onComponentConfigChanged: (data) => - @updatingFromConfig = true - @selectedRow.set '/config', data if data and @configView.changed and @configView.editing - @updatingFromConfig = false - onChangeExtantComponents: => @buildAddComponentTreema() @reportChanges() @@ -298,19 +370,33 @@ module.exports = class ThangComponentsEditView extends CocoView @components = @components.concat(sparseComponents) @onComponentsChanged() + onThangTypeKindChanged: (e) -> + return unless defaultComponents = DEFAULT_COMPONENTS[e.kind] + for component in defaultComponents when not _.find(@components, original: component.original) + @components.push component + @onComponentsAdded() -class ThangComponentsArrayNode extends TreemaArrayNode - valueClass: 'treema-thang-components-array' - sort: true + destroy: -> + @componentsTreema?.destroy() + super() + +class ThangComponentsObjectNode extends TreemaObjectNode + addNewChild: -> @addNewChildForKey('') # HACK to get the object adding to act more like adding to an array + + getChildren: -> + children = super(arguments...) + children.sort(@sortFunction) sortFunction: (a, b) => + a = a.value ? a.defaultData + b = b.value ? b.defaultData a = @settings.supermodel.getModelByOriginalAndMajorVersion(LevelComponent, a.original, a.majorVersion) b = @settings.supermodel.getModelByOriginalAndMajorVersion(LevelComponent, b.original, b.majorVersion) return 0 if not (a or b) return 1 if not b return -1 if not a - return 1 if a.attributes.system > b.attributes.system - return -1 if a.attributes.system < b.attributes.system - return 1 if a.name > b.name - return -1 if a.name < b.name + return 1 if a.get('system') > b.get('system') + return -1 if a.get('system') < b.get('system') + return 1 if a.get('name') > b.get('name') + return -1 if a.get('name') < b.get('name') return 0 diff --git a/app/views/editor/level/LevelEditView.coffee b/app/views/editor/level/LevelEditView.coffee index 567dd6d54..a6d6af179 100644 --- a/app/views/editor/level/LevelEditView.coffee +++ b/app/views/editor/level/LevelEditView.coffee @@ -17,7 +17,10 @@ SaveVersionModal = require 'views/modal/SaveVersionModal' PatchesView = require 'views/editor/PatchesView' RelatedAchievementsView = require 'views/editor/level/RelatedAchievementsView' VersionHistoryView = require './modals/LevelVersionsModal' -ComponentDocsView = require 'views/docs/ComponentDocumentationView' +ComponentsDocumentationView = require 'views/docs/ComponentsDocumentationView' +SystemsDocumentationView = require 'views/docs/SystemsDocumentationView' +LevelFeedbackView = require 'views/editor/level/LevelFeedbackView' +storage = require 'lib/storage' module.exports = class LevelEditView extends RootView id: 'editor-level-view' @@ -41,6 +44,7 @@ module.exports = class LevelEditView extends RootView 'click #level-patch-button': 'startPatchingLevel' 'click #level-watch-button': 'toggleWatchLevel' 'click #pop-level-i18n-button': -> @level.populateI18N() + 'click a[href="#editor-level-documentation"]': 'onClickDocumentationTab' 'mouseup .nav-tabs > li a': 'toggleTab' constructor: (options, @levelID) -> @@ -66,20 +70,23 @@ module.exports = class LevelEditView extends RootView context.level = @level context.authorized = me.isAdmin() or @level.hasWriteAccess(me) context.anonymous = me.get('anonymous') + context.recentlyPlayedOpponents = storage.load('recently-played-matches')?[@levelID] ? [] context afterRender: -> super() return unless @supermodel.finished() @$el.find('a[data-toggle="tab"]').on 'shown.bs.tab', (e) => - Backbone.Mediator.publish 'editor:view-switched', {} + Backbone.Mediator.publish 'editor:view-switched', {targetURL: $(e.target).attr('href')} @insertSubView new ThangsTabView world: @world, supermodel: @supermodel, level: @level @insertSubView new SettingsTabView supermodel: @supermodel @insertSubView new ScriptsTabView world: @world, supermodel: @supermodel, files: @files @insertSubView new ComponentsTabView supermodel: @supermodel @insertSubView new SystemsTabView supermodel: @supermodel @insertSubView new RelatedAchievementsView supermodel: @supermodel, level: @level - @insertSubView new ComponentDocsView # Don't give it the supermodel, it'll pollute it! + @insertSubView new ComponentsDocumentationView lazy: true # Don't give it the supermodel, it'll pollute it! + @insertSubView new SystemsDocumentationView lazy: true # Don't give it the supermodel, it'll pollute it! + @insertSubView new LevelFeedbackView level: @level Backbone.Mediator.publish 'editor:level-loaded', level: @level @showReadOnly() if me.get('anonymous') @@ -95,6 +102,7 @@ module.exports = class LevelEditView extends RootView onPlayLevel: (e) -> team = $(e.target).data('team') + opponentSessionID = $(e.target).data('opponent') sendLevel = => @childWindow.Backbone.Mediator.publish 'level:reload-from-data', level: @level, supermodel: @supermodel if @childWindow and not @childWindow.closed @@ -104,6 +112,7 @@ module.exports = class LevelEditView extends RootView # Create a new Window with a blank LevelView scratchLevelID = @level.get('slug') + '?dev=true' scratchLevelID += "&team=#{team}" if team + scratchLevelID += "&opponent=#{opponentSessionID}" if opponentSessionID if me.get('name') is 'Nick' @childWindow = window.open("/play/level/#{scratchLevelID}", 'child_window', 'width=2560,height=1080,left=0,top=-1600,location=1,menubar=1,scrollbars=1,status=0,titlebar=1,toolbar=1', true) else @@ -164,3 +173,9 @@ module.exports = class LevelEditView extends RootView li.parent().find('li').hide() li.show() console.log li.hasClass('active') + + onClickDocumentationTab: (e) -> + # It's either too late at night or something is going on with Bootstrap nested tabs, so we do the click instead of using .active. + return if @initializedDocs + @initializedDocs = true + @$el.find('a[href="#components-documentation-view"]').click() diff --git a/app/views/editor/level/LevelFeedbackView.coffee b/app/views/editor/level/LevelFeedbackView.coffee new file mode 100644 index 000000000..fa6a0884a --- /dev/null +++ b/app/views/editor/level/LevelFeedbackView.coffee @@ -0,0 +1,53 @@ +CocoView = require 'views/kinds/CocoView' +CocoCollection = require 'collections/CocoCollection' +template = require 'templates/editor/level/level-feedback-view' +Level = require 'models/Level' +LevelFeedback = require 'models/LevelFeedback' + +class LevelFeedbackCollection extends CocoCollection + model: LevelFeedback + initialize: (models, options) -> + super models, options + @url = "/db/level/#{options.level.get('slug')}/all_feedback" + + comparator: (a, b) -> + score = 0 + score -= 9001900190019001 if a.get('creator') is me.id + score += 9001900190019001 if b.get('creator') is me.id + score -= new Date(a.get 'created') + score -= -(new Date(b.get 'created')) + score -= 900190019001 if a.get('review') + score += 900190019001 if b.get('review') + if score < 0 then -1 else (if score > 0 then 1 else 0) + +module.exports = class LevelFeedbackView extends CocoView + id: 'level-feedback-view' + template: template + className: 'tab-pane' + + subscriptions: + 'editor:view-switched': 'onViewSwitched' + + constructor: (options) -> + super options + + getRenderData: (context={}) -> + context = super(context) + context.moment = moment + context.allFeedback = [] + context.averageRating = 0 + context.totalRatings = 0 + if @allFeedback + context.allFeedback = (m.attributes for m in @allFeedback.models when @allFeedback.models.length < 20 or m.get('review')) + context.averageRating = _.reduce((m.get('rating') for m in @allFeedback.models), (acc, x) -> acc + (x ? 5)) / (@allFeedback.models.length) + context.totalRatings = @allFeedback.models.length + else + context.loading = true + context + + onViewSwitched: (e) -> + # Lazily load. + return unless e.targetURL is '#level-feedback-view' + unless @allFeedback + @allFeedback = @supermodel.loadCollection(new LevelFeedbackCollection(null, level: @options.level), 'feedback').model + @render() diff --git a/app/views/editor/level/RelatedAchievementsView.coffee b/app/views/editor/level/RelatedAchievementsView.coffee index ccb9969eb..c4bf75e3c 100644 --- a/app/views/editor/level/RelatedAchievementsView.coffee +++ b/app/views/editor/level/RelatedAchievementsView.coffee @@ -13,17 +13,20 @@ module.exports = class RelatedAchievementsView extends CocoView events: 'click #new-achievement-button': 'makeNewAchievement' + subscriptions: + 'editor:view-switched': 'onViewSwitched' + constructor: (options) -> super options @level = options.level @relatedID = @level.get('original') @achievements = new RelatedAchievementsCollection @relatedID - @supermodel.loadCollection @achievements, 'achievements' - onLoaded: -> - console.debug 'related achievements loaded' - @achievements.loading = false - super() + loadAchievements: -> + return if @loadingAchievements + @supermodel.loadCollection @achievements, 'achievements' + @loadingAchievements = true + @render() getRenderData: -> c = super() @@ -38,3 +41,8 @@ module.exports = class RelatedAchievementsView extends CocoView modal = new NewAchievementModal model: Achievement, modelLabel: 'Achievement', level: @level modal.once 'model-created', @onNewAchievementSaved @openModalView modal + + onViewSwitched: (e) -> + # Lazily load. + return unless e.targetURL is '#related-achievements-view' + @loadAchievements() diff --git a/app/views/editor/level/components/ComponentsTabView.coffee b/app/views/editor/level/components/ComponentsTabView.coffee index 4507184ec..7162273de 100644 --- a/app/views/editor/level/components/ComponentsTabView.coffee +++ b/app/views/editor/level/components/ComponentsTabView.coffee @@ -1,5 +1,6 @@ CocoView = require 'views/kinds/CocoView' template = require 'templates/editor/level/components_tab' +ThangType = require 'models/ThangType' LevelComponent = require 'models/LevelComponent' LevelComponentEditView = require './LevelComponentEditView' LevelComponentNewView = require './NewLevelComponentModal' @@ -25,7 +26,15 @@ module.exports = class ComponentsTabView extends CocoView refreshLevelThangsTreema: (thangsData) -> presentComponents = {} for thang in thangsData + componentMap = {} + thangType = @supermodel.getModelByOriginal ThangType, thang.thangType + for component in thangType.get('components') ? [] + componentMap[component.original] = component + for component in thang.components + componentMap[component.original] = component + + for component in _.values(componentMap) haveThisComponent = (presentComponents[component.original + '.' + (component.majorVersion ? 0)] ?= []) haveThisComponent.push thang.id if haveThisComponent.length < 100 # for performance when adding many Thangs return if _.isEqual presentComponents, @presentComponents @@ -72,16 +81,20 @@ module.exports = class ComponentsTabView extends CocoView onLevelComponentEditingEnded: (e) -> @removeSubView @levelComponentEditView @levelComponentEditView = null + + destroy: -> + @componentsTreema?.destroy() + super() class LevelComponentNode extends TreemaObjectNode valueClass: 'treema-level-component' collection: false - buildValueForDisplay: (valEl) -> - count = if @data.count is 1 then @data.thangs[0] else ((if @data.count >= 100 then '100+' else @data.count) + ' Thangs') - if @data.original.match ':' - name = 'Old: ' + @data.original.replace('systems/', '') + buildValueForDisplay: (valEl, data) -> + count = if data.count is 1 then data.thangs[0] else ((if data.count >= 100 then '100+' else data.count) + ' Thangs') + if data.original.match ':' + name = 'Old: ' + data.original.replace('systems/', '') else comp = _.find @settings.supermodel.getModels(LevelComponent), (m) => - m.get('original') is @data.original and m.get('version').major is @data.majorVersion + m.get('original') is data.original and m.get('version').major is data.majorVersion name = "#{comp.get('system')}.#{comp.get('name')} v#{comp.get('version').major}" @buildValueForDisplaySimply valEl, "#{name} (#{count})" diff --git a/app/views/editor/level/components/LevelComponentEditView.coffee b/app/views/editor/level/components/LevelComponentEditView.coffee index 67fba26d1..898c88f0f 100644 --- a/app/views/editor/level/components/LevelComponentEditView.coffee +++ b/app/views/editor/level/components/LevelComponentEditView.coffee @@ -42,6 +42,7 @@ module.exports = class LevelComponentEditView extends CocoView @buildCodeEditor() @patchesView = @insertSubView(new PatchesView(@levelComponent), @$el.find('.patches-view')) @$el.find('#component-watch-button').find('> span').toggleClass('secret') if @levelComponent.watching() + @updatePatchButton() buildSettingsTreema: -> data = _.pick @levelComponent.attributes, (value, key) => key in @editableSettings @@ -49,6 +50,7 @@ module.exports = class LevelComponentEditView extends CocoView schema = _.cloneDeep LevelComponent.schema schema.properties = _.pick schema.properties, (value, key) => key in @editableSettings schema.required = _.intersection schema.required, @editableSettings + schema.default = _.pick schema.default, (value, key) => key in @editableSettings treemaOptions = supermodel: @supermodel @@ -64,13 +66,22 @@ module.exports = class LevelComponentEditView extends CocoView # Make sure it validates first? for key, value of @componentSettingsTreema.data @levelComponent.set key, value unless key is 'js' # will compile code if needed - null + @updatePatchButton() buildConfigSchemaTreema: -> + configSchema = @levelComponent.get 'configSchema' + if configSchema.properties + # Alphabetize (#1297) + propertyNames = _.keys configSchema.properties + propertyNames.sort() + orderedProperties = {} + for prop in propertyNames + orderedProperties[prop] = configSchema.properties[prop] + configSchema.properties = orderedProperties treemaOptions = supermodel: @supermodel schema: LevelComponent.schema.properties.configSchema - data: @levelComponent.get 'configSchema' + data: configSchema readOnly: me.get('anonymous') callbacks: {change: @onConfigSchemaEdited} @configSchemaTreema = @$el.find('#config-schema-treema').treema treemaOptions @@ -81,9 +92,10 @@ module.exports = class LevelComponentEditView extends CocoView onConfigSchemaEdited: => @levelComponent.set 'configSchema', @configSchemaTreema.data + @updatePatchButton() buildCodeEditor: -> - @editor?.destroy() + @destroyAceEditor(@editor) editorEl = $('
').text(@levelComponent.get('code')).addClass('inner-editor') @$el.find('#component-code-editor').empty().append(editorEl) @editor = ace.edit(editorEl[0]) @@ -98,7 +110,10 @@ module.exports = class LevelComponentEditView extends CocoView onEditorChange: => return if @destroyed @levelComponent.set 'code', @editor.getValue() - null + @updatePatchButton() + + updatePatchButton: -> + @$el.find('#patch-component-button').toggle Boolean @levelComponent.hasLocalChanges() endEditing: (e) -> Backbone.Mediator.publish 'editor:level-component-editing-ended', component: @levelComponent @@ -119,5 +134,7 @@ module.exports = class LevelComponentEditView extends CocoView button.find('> span').toggleClass('secret') destroy: -> - @editor?.destroy() + @destroyAceEditor(@editor) + @componentSettingsTreema?.destroy() + @configSchemaTreema?.destroy() super() diff --git a/app/views/editor/level/modals/TerrainRandomizeModal.coffee b/app/views/editor/level/modals/TerrainRandomizeModal.coffee index fa6da998a..94a772706 100644 --- a/app/views/editor/level/modals/TerrainRandomizeModal.coffee +++ b/app/views/editor/level/modals/TerrainRandomizeModal.coffee @@ -3,17 +3,21 @@ template = require 'templates/editor/level/modal/terrain_randomize' CocoModel = require 'models/CocoModel' clusters = { + 'hero': { + 'thangs': ['Hero Placeholder'] + 'margin': 1 + } 'rocks': { 'thangs': ['Rock 1', 'Rock 2', 'Rock 3', 'Rock 4', 'Rock 5', 'Rock Cluster 1', 'Rock Cluster 2', 'Rock Cluster 3'] 'margin': 1 } 'trees': { 'thangs': ['Tree 1', 'Tree 2', 'Tree 3', 'Tree 4'] - 'margin': 0 + 'margin': 0.5 } 'shrubs': { 'thangs': ['Shrub 1', 'Shrub 2', 'Shrub 3'] - 'margin': 0 + 'margin': 0.5 } 'houses': { 'thangs': ['House 1', 'House 2', 'House 3', 'House 4'] @@ -83,6 +87,7 @@ clusters = { presets = { 'dungeon': { + 'terrainName': 'Dungeon' 'type':'dungeon' 'borders':'dungeon_wall' 'borderNoise':0 @@ -97,6 +102,14 @@ presets = { 'thickness': [2,2] 'cluster': 'dungeon_wall' } + 'hero': { + 'num': [1, 1] + 'width': 2 + 'height': 2 + 'clusters': { + 'hero': [1, 1] + } + } 'Barrels': { 'num': [1,1] 'width': [8, 12] @@ -116,6 +129,7 @@ presets = { } } 'indoor': { + 'terrainName': 'Indoor' 'type':'indoor' 'borders':'indoor_wall' 'borderNoise':0 @@ -130,6 +144,14 @@ presets = { 'thickness': [2,2] 'cluster': 'indoor_wall' } + 'hero': { + 'num': [1, 1] + 'width': 2 + 'height': 2 + 'clusters': { + 'hero': [1, 1] + } + } 'furniture': { 'num':[1,2] 'width': 15 @@ -141,6 +163,7 @@ presets = { } } 'grassy': { + 'terrainName': 'Grass' 'type':'grassy' 'borders':'trees' 'borderNoise':1 @@ -148,6 +171,14 @@ presets = { 'borderThickness':3 'floors':'grass_floor' 'decorations': { + 'hero': { + 'num': [1, 1] + 'width': 2 + 'height': 2 + 'clusters': { + 'hero': [1, 1] + } + } 'house': { 'num':[1,2] #min-max 'width': 15 @@ -195,8 +226,8 @@ thangSizes = { 'borderSize': { 'x':4 'y':4 - } -} + }} + module.exports = class TerrainRandomizeModal extends ModalView id: 'terrain-randomize-modal' @@ -215,7 +246,7 @@ module.exports = class TerrainRandomizeModal extends ModalView presetType = target.attr 'data-preset-type' presetSize = target.attr 'data-preset-size' @randomizeThangs presetType, presetSize - Backbone.Mediator.publish 'editor:random-terrain-generated', thangs: @thangs + Backbone.Mediator.publish 'editor:random-terrain-generated', thangs: @thangs, terrain: presets[presetType].terrainName @hide() randomizeThangs: (presetName, presetSize) -> @@ -280,7 +311,7 @@ module.exports = class TerrainRandomizeModal extends ModalView 'id': @getRandomThang(clusters['torch'].thangs) 'pos': { 'x': i + preset.borderSize - 'y': presetSize.y - preset.borderSize + 'y': presetSize.y - preset.borderSize / 2 } 'margin': clusters['torch'].margin } @@ -289,7 +320,7 @@ module.exports = class TerrainRandomizeModal extends ModalView 'id': @getRandomThang(clusters['chains'].thangs) 'pos': { 'x': i + preset.borderSize - 'y': presetSize.y - preset.borderSize + 'y': presetSize.y - preset.borderSize / 2 } 'margin': clusters['chains'].margin } @@ -346,53 +377,57 @@ module.exports = class TerrainRandomizeModal extends ModalView continue buildRoom: (preset, presetSize, room) -> + grid = preset.borderSize while true rect = { - 'width':presetSize.sizeFactor * (room.width[0] + preset.borderSize * _.random(0, (room.width[1] - room.width[0])/preset.borderSize)) - 'height':presetSize.sizeFactor * (room.height[0] + preset.borderSize * _.random(0, (room.height[1] - room.height[0])/preset.borderSize)) + 'width':presetSize.sizeFactor * (room.width[0] + grid * _.random(0, (room.width[1] - room.width[0])/grid)) + 'height':presetSize.sizeFactor * (room.height[0] + grid * _.random(0, (room.height[1] - room.height[0])/grid)) } + # This logic isn't quite right--it makes the rooms bigger than intended--but it's snapping correctly, which is fine for now. + rect.width = Math.round((rect.width - grid) / (2 * grid)) * 2 * grid + grid + rect.height = Math.round((rect.height - grid) / (2 * grid)) * 2 * grid + grid roomThickness = _.random(room.thickness[0], room.thickness[1]) - rect.x = _.random(rect.width/2 + preset.borderSize * (roomThickness+1.5), presetSize.x - rect.width/2 - preset.borderSize * (roomThickness+1.5)) - rect.y = _.random(rect.height/2 + preset.borderSize * (roomThickness+2.5), presetSize.y - rect.height/2 - preset.borderSize * (roomThickness+3.5)) + rect.x = _.random(rect.width/2 + grid * (roomThickness+1.5), presetSize.x - rect.width/2 - grid * (roomThickness+1.5)) + rect.y = _.random(rect.height/2 + grid * (roomThickness+2.5), presetSize.y - rect.height/2 - grid * (roomThickness+3.5)) # Snap room walls to the wall grid. - rect.x = Math.round((rect.x - preset.borderSize / 2) / preset.borderSize) * preset.borderSize + preset.borderSize / 2 - rect.y = Math.round((rect.y - preset.borderSize / 2) / preset.borderSize) * preset.borderSize + preset.borderSize / 2 + rect.x = Math.round((rect.x - grid / 2) / grid) * grid + rect.y = Math.round((rect.y - grid / 2) / grid) * grid break if @addRect { 'x': rect.x 'y': rect.y - 'width': rect.width + 2.5 * roomThickness * preset.borderSize - 'height': rect.height + 2.5 * roomThickness * preset.borderSize + 'width': rect.width + 2.5 * roomThickness * grid + 'height': rect.height + 2.5 * roomThickness * grid } - xRange = _.range(rect.x - rect.width/2 + preset.borderSize, rect.x + rect.width/2, preset.borderSize) + xRange = _.range(rect.x - rect.width/2 + grid, rect.x + rect.width/2, grid) topDoor = _.random(1) > 0.5 topDoorX = xRange[_.random(0, xRange.length-1)] bottomDoor = if not topDoor then true else _.random(1) > 0.5 bottomDoorX = xRange[_.random(0, xRange.length-1)] for t in _.range(0, roomThickness+1) - for i in _.range(rect.x - rect.width/2 - (t-1) * preset.borderSize, rect.x + rect.width/2 + t * preset.borderSize, preset.borderSize) + for i in _.range(rect.x - rect.width/2 - (t-1) * grid, rect.x + rect.width/2 + t * grid, grid) # Bottom wall thang = { 'id': @getRandomThang(clusters[room.cluster].thangs) 'pos': { 'x': i - 'y': rect.y - rect.height/2 - t * preset.borderSize + 'y': rect.y - rect.height/2 - t * grid } 'margin': clusters[room.cluster].margin } if i is bottomDoorX and bottomDoor thang.id = @getRandomThang(clusters['doors'].thangs) - thang.pos.y -= preset.borderSize/3 + thang.pos.y -= grid/3 @addThang thang unless i is bottomDoorX and t isnt roomThickness and bottomDoor - if t is roomThickness and i isnt rect.x - rect.width/2 - (t-1) * preset.borderSize and preset.type is 'dungeon' - if ( i isnt bottomDoorX and i isnt bottomDoorX + preset.borderSize ) or not bottomDoor + if t is roomThickness and i isnt rect.x - rect.width/2 - (t-1) * grid and preset.type is 'dungeon' + if ( i isnt bottomDoorX and i isnt bottomDoorX + grid ) or not bottomDoor @addThang { 'id': @getRandomThang(clusters['torch'].thangs) 'pos': { - 'x': thang.pos.x - preset.borderSize / 2 - 'y': thang.pos.y + preset.borderSize / 2 + 'x': thang.pos.x - grid / 2 + 'y': thang.pos.y + grid } 'margin': clusters['torch'].margin } @@ -402,22 +437,22 @@ module.exports = class TerrainRandomizeModal extends ModalView 'id': @getRandomThang(clusters[room.cluster].thangs) 'pos': { 'x': i - 'y': rect.y + rect.height/2 + t * preset.borderSize + 'y': rect.y + rect.height/2 + t * grid } 'margin': clusters[room.cluster].margin } if i is topDoorX and topDoor thang.id = @getRandomThang(clusters['doors'].thangs) - thang.pos.y -= preset.borderSize + thang.pos.y -= grid @addThang thang unless i is topDoorX and t isnt roomThickness and topDoor for t in _.range(0, roomThickness) - for i in _.range(rect.y - rect.height/2 - t * preset.borderSize, rect.y + rect.height/2 + (t+1) * preset.borderSize, preset.borderSize) + for i in _.range(rect.y - rect.height/2 - t * grid, rect.y + rect.height/2 + (t+1) * grid, grid) # Left wall @addThang { 'id': @getRandomThang(clusters[room.cluster].thangs) 'pos': { - 'x': rect.x - rect.width/2 - t * preset.borderSize + 'x': rect.x - rect.width/2 - t * grid 'y': i } 'margin': clusters[room.cluster].margin @@ -427,7 +462,7 @@ module.exports = class TerrainRandomizeModal extends ModalView @addThang { 'id': @getRandomThang(clusters[room.cluster].thangs) 'pos': { - 'x': rect.x + rect.width/2 + t * preset.borderSize + 'x': rect.x + rect.width/2 + t * grid 'y': i } 'margin': clusters[room.cluster].margin diff --git a/app/views/editor/level/scripts/ScriptsTabView.coffee b/app/views/editor/level/scripts/ScriptsTabView.coffee index b4e486de9..c7be53716 100644 --- a/app/views/editor/level/scripts/ScriptsTabView.coffee +++ b/app/views/editor/level/scripts/ScriptsTabView.coffee @@ -18,6 +18,13 @@ module.exports = class ScriptsTabView extends CocoView super options @world = options.world @files = options.files + $(window).on 'resize', @onWindowResize + + destroy: -> + @scriptTreema?.destroy() + @scriptTreemas?.destroy() + $(window).off 'resize', @onWindowResize + super() onLoaded: -> onLevelLoaded: (e) -> @@ -83,13 +90,14 @@ module.exports = class ScriptsTabView extends CocoView newPath = selected.getPath() return if newPath is @selectedScriptPath + #@scriptTreema?.destroy() # TODO: get this to work @scriptTreema = @$el.find('#script-treema').treema treemaOptions @scriptTreema.build() @scriptTreema.childrenTreemas?.noteChain?.open() @selectedScriptPath = newPath getThangIDs: -> - (t.id for t in @level.get('thangs')) + (t.id for t in @level.get('thangs') ? []) onNewScriptAdded: (scriptNode) => return unless scriptNode @@ -113,8 +121,10 @@ module.exports = class ScriptsTabView extends CocoView onThangsEdited: (e) -> # Update in-place so existing Treema nodes refer to the same array. - @thangIDs.splice(0, @thangIDs.length, @getThangIDs()...) - + @thangIDs?.splice(0, @thangIDs.length, @getThangIDs()...) + + onWindowResize: (e) => + @$el.find('#scripts-treema').collapse('show') if $('body').width() > 800 class ScriptsNode extends TreemaArrayNode nodeDescription: 'Script' @@ -127,8 +137,8 @@ class ScriptsNode extends TreemaArrayNode class ScriptNode extends TreemaObjectNode valueClass: 'treema-script' collection: false - buildValueForDisplay: (valEl) -> - val = @data.id or @data.channel + buildValueForDisplay: (valEl, data) -> + val = data.id or data.channel s = "#{val}" @buildValueForDisplaySimply valEl, s @@ -158,15 +168,15 @@ class PropertiesNode extends TreemaObjectNode class EventPropsNode extends TreemaNode.nodeMap.string valueClass: 'treema-event-props' - arrayToString: -> (@data or []).join('.') + arrayToString: -> (@getData() or []).join('.') - buildValueForDisplay: (valEl) -> + buildValueForDisplay: (valEl, data) -> joined = @arrayToString() joined = '(unset)' if not joined.length @buildValueForDisplaySimply valEl, joined - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) channel = @getRoot().data.channel channelSchema = Backbone.Mediator.channelSchemas[channel] autocompleteValues = [] @@ -188,13 +198,13 @@ class EventPrereqsNode extends TreemaNode.nodeMap.array newTreema.childrenTreemas.eventProps?.edit() class EventPrereqNode extends TreemaNode.nodeMap.object - buildValueForDisplay: (valEl) -> - eventProp = (@data.eventProps or []).join('.') + buildValueForDisplay: (valEl, data) -> + eventProp = (data.eventProps or []).join('.') eventProp = '(unset)' unless eventProp.length statements = [] - for key, value of @data + for key, value of data continue if key is 'eventProps' - comparison = @schema.properties[key].title + comparison = @workingSchema.properties[key].title value = value.toString() statements.push("#{comparison} #{value}") statements = statements.join(', ') @@ -202,8 +212,8 @@ class EventPrereqNode extends TreemaNode.nodeMap.object @buildValueForDisplaySimply valEl, s class ChannelNode extends TreemaNode.nodeMap.string - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) autocompleteValues = ({label: val?.title or key, value: key} for key, val of Backbone.Mediator.channelSchemas) valEl.find('input').autocomplete(source: autocompleteValues, minLength: 0, delay: 0, autoFocus: true) valEl diff --git a/app/views/editor/level/settings/SettingsTabView.coffee b/app/views/editor/level/settings/SettingsTabView.coffee index c593e9120..fc6e02d91 100644 --- a/app/views/editor/level/settings/SettingsTabView.coffee +++ b/app/views/editor/level/settings/SettingsTabView.coffee @@ -13,12 +13,13 @@ module.exports = class SettingsTabView extends CocoView # not thangs or scripts or the backend stuff editableSettings: [ 'name', 'description', 'documentation', 'nextLevel', 'background', 'victory', 'i18n', 'icon', 'goals', - 'type', 'showsGuide', 'banner', 'employerDescription' + 'type', 'terrain', 'showsGuide', 'banner', 'employerDescription' ] subscriptions: 'editor:level-loaded': 'onLevelLoaded' 'editor:thangs-edited': 'onThangsEdited' + 'editor:random-terrain-generated': 'onRandomTerrainGenerated' constructor: (options) -> super options @@ -30,6 +31,7 @@ module.exports = class SettingsTabView extends CocoView schema = _.cloneDeep Level.schema schema.properties = _.pick schema.properties, (value, key) => key in @editableSettings schema.required = _.intersection schema.required, @editableSettings + schema.default = _.pick schema.default, (value, key) => key in @editableSettings @thangIDs = @getThangIDs() treemaOptions = filePath: "db/level/#{@level.get('original')}" @@ -46,19 +48,30 @@ module.exports = class SettingsTabView extends CocoView @settingsTreema = @$el.find('#settings-treema').treema treemaOptions @settingsTreema.build() @settingsTreema.open() + @lastTerrain = data.terrain getThangIDs: -> - (t.id for t in @level.get('thangs')) + (t.id for t in @level.get('thangs') ? []) onSettingsChanged: (e) => $('.level-title').text @settingsTreema.data.name for key in @editableSettings continue if @settingsTreema.data[key] is undefined @level.set key, @settingsTreema.data[key] + if (terrain = @settingsTreema.data.terrain) isnt @lastTerrain + @lastTerrain = terrain + Backbone.Mediator.publish 'editor:terrain-changed', terrain: terrain onThangsEdited: (e) -> # Update in-place so existing Treema nodes refer to the same array. - @thangIDs.splice(0, @thangIDs.length, @getThangIDs()...) + @thangIDs?.splice(0, @thangIDs.length, @getThangIDs()...) + + onRandomTerrainGenerated: (e) -> + @settingsTreema.set '/terrain', e.terrain + + destroy: -> + @settingsTreema?.destroy() + super() class SettingsNode extends TreemaObjectNode diff --git a/app/views/editor/level/systems/AddLevelSystemModal.coffee b/app/views/editor/level/systems/AddLevelSystemModal.coffee index 173cf05ab..84a0c0abf 100644 --- a/app/views/editor/level/systems/AddLevelSystemModal.coffee +++ b/app/views/editor/level/systems/AddLevelSystemModal.coffee @@ -48,7 +48,6 @@ module.exports = class AddLevelSystemModal extends ModalView levelSystem = original: s.get('original') ? id majorVersion: s.get('version').major ? 0 - config: $.extend(true, {}, s.get('configSchema').default ? {}) @extantSystems.push levelSystem Backbone.Mediator.publish 'level-system-added', system: levelSystem @renderAvailableSystems() diff --git a/app/views/editor/level/systems/LevelSystemEditView.coffee b/app/views/editor/level/systems/LevelSystemEditView.coffee index 455cf13ca..e50a37e4a 100644 --- a/app/views/editor/level/systems/LevelSystemEditView.coffee +++ b/app/views/editor/level/systems/LevelSystemEditView.coffee @@ -37,12 +37,14 @@ module.exports = class LevelSystemEditView extends CocoView @buildConfigSchemaTreema() @buildCodeEditor() @patchesView = @insertSubView(new PatchesView(@levelSystem), @$el.find('.patches-view')) + @updatePatchButton() buildSettingsTreema: -> data = _.pick @levelSystem.attributes, (value, key) => key in @editableSettings schema = _.cloneDeep LevelSystem.schema schema.properties = _.pick schema.properties, (value, key) => key in @editableSettings schema.required = _.intersection schema.required, @editableSettings + schema.default = _.pick schema.default, (value, key) => key in @editableSettings treemaOptions = supermodel: @supermodel @@ -58,7 +60,7 @@ module.exports = class LevelSystemEditView extends CocoView # Make sure it validates first? for key, value of @systemSettingsTreema.data @levelSystem.set key, value unless key is 'js' # will compile code if needed - null + @updatePatchButton() buildConfigSchemaTreema: -> treemaOptions = @@ -75,9 +77,10 @@ module.exports = class LevelSystemEditView extends CocoView onConfigSchemaEdited: => @levelSystem.set 'configSchema', @configSchemaTreema.data + @updatePatchButton() buildCodeEditor: -> - @editor?.destroy() + @destroyAceEditor(@editor) editorEl = $('
').text(@levelSystem.get('code')).addClass('inner-editor') @$el.find('#system-code-editor').empty().append(editorEl) @editor = ace.edit(editorEl[0]) @@ -91,7 +94,10 @@ module.exports = class LevelSystemEditView extends CocoView onEditorChange: => @levelSystem.set 'code', @editor.getValue() - null + @updatePatchButton() + + updatePatchButton: -> + @$el.find('#patch-system-button').toggle Boolean @levelSystem.hasLocalChanges() endEditing: (e) -> Backbone.Mediator.publish 'editor:level-system-editing-ended', system: @levelSystem @@ -113,5 +119,7 @@ module.exports = class LevelSystemEditView extends CocoView button.find('> span').toggleClass('secret') destroy: -> - @editor?.destroy() + @destroyAceEditor(@editor) + @systemSettingsTreema?.destroy() + @configSchemaTreema?.destroy() super() diff --git a/app/views/editor/level/systems/SystemsTabView.coffee b/app/views/editor/level/systems/SystemsTabView.coffee index 2ade6d0bd..78809330b 100644 --- a/app/views/editor/level/systems/SystemsTabView.coffee +++ b/app/views/editor/level/systems/SystemsTabView.coffee @@ -17,6 +17,7 @@ module.exports = class SystemsTabView extends CocoView 'editor:edit-level-system': 'editLevelSystem' 'editor:level-system-editing-ended': 'onLevelSystemEditingEnded' 'editor:level-loaded': 'onLevelLoaded' + 'editor:terrain-changed': 'onTerrainChanged' events: 'click #add-system-button': 'addLevelSystem' @@ -81,9 +82,9 @@ module.exports = class SystemsTabView extends CocoView @removeSubView @levelSystemEditView if @levelSystemEditView @levelSystemEditView = null return - until selected.data.original + until (data = selected.getData()) and data.original selected = selected.parent - @editLevelSystem original: selected.data.original, majorVersion: selected.data.majorVersion + @editLevelSystem original: data.original, majorVersion: data.majorVersion onLevelSystemAdded: (e) -> @systemsTreema.insert '/', e.system @@ -103,16 +104,30 @@ module.exports = class SystemsTabView extends CocoView @removeSubView @levelSystemEditView @levelSystemEditView = null + onTerrainChanged: (e) -> + defaultPathfinding = e.terrain in ['Dungeon', 'Indoor'] + return unless AI = @systemsTreema.get 'original=528110f30268d018e3000001' + return if AI.config?.findsPaths is defaultPathfinding + AI.config ?= {} + AI.config.findsPaths = defaultPathfinding + @systemsTreema.set 'original=528110f30268d018e3000001', AI + noty { + text: "AI System defaulted pathfinding to #{defaultPathfinding} for terrain #{e.terrain}." + layout: 'topCenter' + timeout: 5000 + type: 'information' + } + buildDefaultSystems: -> [ {original: '528112c00268d018e3000008', majorVersion: 0} # Event - {original: '5280f83b8ae1581b66000001', majorVersion: 0, config: {lifespan: 60}} # Existence + {original: '5280f83b8ae1581b66000001', majorVersion: 0} # Existence {original: '5281146f0268d018e3000014', majorVersion: 0} # Programming {original: '528110f30268d018e3000001', majorVersion: 0} # AI {original: '52810ffa33e01a6e86000012', majorVersion: 0} # Action {original: '528114b20268d018e3000017', majorVersion: 0} # Targeting {original: '528105f833e01a6e86000007', majorVersion: 0} # Collision - {original: '528113240268d018e300000c', majorVersion: 0, config: {gravity: 9.81}} # Movement + {original: '528113240268d018e300000c', majorVersion: 0} # Movement {original: '528112530268d018e3000007', majorVersion: 0} # Combat {original: '52810f4933e01a6e8600000c', majorVersion: 0} # Hearing {original: '528115040268d018e300001b', majorVersion: 0} # Vision @@ -120,8 +135,15 @@ module.exports = class SystemsTabView extends CocoView {original: '528111b30268d018e3000004', majorVersion: 0} # Alliance {original: '528114e60268d018e300001a', majorVersion: 0} # UI {original: '528114040268d018e3000011', majorVersion: 0} # Physics + {original: '52ae4f02a4dcd4415200000b', majorVersion: 0} # Display + {original: '52e953e81b2028d102000004', majorVersion: 0} # Effect + {original: '52f1354370fb890000000005', majorVersion: 0} # Magic ] + destroy: -> + @systemsTreema?.destroy() + super() + class LevelSystemNode extends TreemaObjectNode valueClass: 'treema-level-system' constructor: -> @@ -130,23 +152,26 @@ class LevelSystemNode extends TreemaObjectNode @collection = @system?.attributes?.configSchema?.properties? grabDBComponent: -> - unless _.isString @data.original + data = @getData() + unless _.isString data.original return alert('Press the "Add System" button at the bottom instead of the "+". Sorry.') - @system = @settings.supermodel.getModelByOriginalAndMajorVersion(LevelSystem, @data.original, @data.majorVersion) - console.error 'Couldn\'t find system for', @data.original, @data.majorVersion, 'from models', @settings.supermodel.models unless @system + @system = @settings.supermodel.getModelByOriginalAndMajorVersion(LevelSystem, data.original, data.majorVersion) + console.error 'Couldn\'t find system for', data.original, data.majorVersion, 'from models', @settings.supermodel.models unless @system getChildSchema: (key) -> return @system.attributes.configSchema if key is 'config' return super(key) - buildValueForDisplay: (valEl) -> - return super valEl unless @data.original and @system - name = "#{@system.get('name')} v#{@system.get('version').major}" - @buildValueForDisplaySimply valEl, "#{name}" + buildValueForDisplay: (valEl, data) -> + return super valEl unless data.original and @system + name = @system.get 'name' + name += " v#{@system.get('version').major}" if @system.get('version').major + @buildValueForDisplaySimply valEl, name onEnterPressed: (e) -> super e - Backbone.Mediator.publish 'editor:edit-level-system', original: @data.original, majorVersion: @data.majorVersion + data = @getData() + Backbone.Mediator.publish 'editor:edit-level-system', original: data.original, majorVersion: data.majorVersion open: (depth) -> super depth @@ -157,5 +182,4 @@ class LevelSystemNode extends TreemaObjectNode class LevelSystemConfigurationNode extends TreemaObjectNode valueClass: 'treema-level-system-configuration' - buildValueForDisplay: (valEl) -> - return + buildValueForDisplay: -> return diff --git a/app/views/editor/level/thangs/LevelThangEditView.coffee b/app/views/editor/level/thangs/LevelThangEditView.coffee index a7c6e1f9f..42fca453a 100644 --- a/app/views/editor/level/thangs/LevelThangEditView.coffee +++ b/app/views/editor/level/thangs/LevelThangEditView.coffee @@ -36,11 +36,14 @@ module.exports = class LevelThangEditView extends CocoView onLoaded: -> @render() afterRender: -> super() + thangType = @supermodel.getModelByOriginal(ThangType, @thangData.thangType) options = components: @thangData.components supermodel: @supermodel level: @level world: @world + + if @level.get('type') is 'hero' then options.thangType = thangType @thangComponentEditView = new ThangComponentsEditView options @listenTo @thangComponentEditView, 'components-changed', @onComponentsChanged diff --git a/app/views/editor/level/thangs/ThangsTabView.coffee b/app/views/editor/level/thangs/ThangsTabView.coffee index 0834f7c25..0231c7993 100644 --- a/app/views/editor/level/thangs/ThangsTabView.coffee +++ b/app/views/editor/level/thangs/ThangsTabView.coffee @@ -15,10 +15,8 @@ ComponentsCollection = require 'collections/ComponentsCollection' MOVE_MARGIN = 0.15 MOVE_SPEED = 13 -# Essential component original ids -componentOriginals = - 'existence.Exists': '524b4150ff92f1f4f8000024' - 'physics.Physical': '524b75ad7fc0f6d519000001' +# Let us place these on top of other Thangs +overlappableThangTypeNames = ['Torch', 'Chains', 'Bird', 'Cloud 1', 'Cloud 2', 'Cloud 3', 'Waterfall', 'Obstacle'] class ThangTypeSearchCollection extends CocoCollection url: '/db/thang.type?project=original,name,version,slug,kind,components' @@ -40,6 +38,7 @@ module.exports = class ThangsTabView extends CocoView 'editor:view-switched': 'onViewSwitched' 'sprite:dragged': 'onSpriteDragged' 'sprite:mouse-up': 'onSpriteMouseUp' + 'sprite:mouse-down': 'onSpriteMouseDown' 'sprite:double-clicked': 'onSpriteDoubleClicked' 'surface:stage-mouse-up': 'onStageMouseUp' 'editor:random-terrain-generated': 'onRandomTerrainGenerated' @@ -104,6 +103,8 @@ module.exports = class ThangsTabView extends CocoView $('#thangs-list').height(oldHeight - thangsHeaderHeight - 40) else $('#thangs-list').height(oldHeight - thangsHeaderHeight - 80) + $('#all-thangs').collapse 'show' + $('#add-thangs-column').collapse 'show' undo: (e) -> if not @editThangView then @thangsTreema.undo() else @editThangView.undo() @@ -117,7 +118,7 @@ module.exports = class ThangsTabView extends CocoView $('.tab-content').mousedown @selectAddThang $('#thangs-list').bind 'mousewheel', @preventBodyScrollingInThangList @$el.find('#extant-thangs-filter button:first').button('toggle') - $(window).resize @onWindowResize + $(window).on 'resize', @onWindowResize @addThangsView = @insertSubView new AddThangsView world: @world @buildInterface() # refactor to not have this trigger when this view re-renders? if @thangsTreema.data.length @@ -161,7 +162,7 @@ module.exports = class ThangsTabView extends CocoView thangsHeaderHeight = $('#thangs-header').height() oldHeight = $('#thangs-list').height() $('#thangs-list').height(oldHeight - thangsHeaderHeight) - if data.thangs.length + if data.thangs?.length @$el.find('#randomize-button').hide() initSurface: -> @@ -182,14 +183,17 @@ module.exports = class ThangsTabView extends CocoView destroy: -> @selectAddThangType null @surface.destroy() + $(window).off 'resize', @onWindowResize $(document).unbind 'contextmenu', @preventDefaultContextMenu + @thangsTreema?.destroy() super() onViewSwitched: (e) -> - @selectAddThang() + @selectAddThang null, true @surface?.spriteBoss?.selectSprite null, null onSpriteMouseDown: (e) -> + @dragged = false # Sprite clicks happen after stage clicks, but we need to know whether a sprite is being clicked. # clearTimeout @backgroundAddClickTimeout # if e.originalEvent.nativeEvent.button == 2 @@ -204,6 +208,7 @@ module.exports = class ThangsTabView extends CocoView onSpriteDragged: (e) -> return unless @selectedExtantThang and e.thang?.id is @selectedExtantThang?.id + @dragged = true @surface.camera.dragDisabled = true {stageX, stageY} = e.originalEvent wop = @surface.camera.screenToWorld x: stageX, y: stageY @@ -222,14 +227,13 @@ module.exports = class ThangsTabView extends CocoView @surface.camera.dragDisabled = false return unless @selectedExtantThang and e.thang?.id is @selectedExtantThang?.id pos = @selectedExtantThang.pos - physicalOriginal = componentOriginals['physics.Physical'] - path = "id=#{@selectedExtantThang.id}/components/original=#{physicalOriginal}" # TODO: hack + path = "id=#{@selectedExtantThang.id}/components/original=#{LevelComponent.PhysicalID}" physical = @thangsTreema.get path return if not physical or (physical.config.pos.x is pos.x and physical.config.pos.y is pos.y) @thangsTreema.set path + '/config/pos', x: pos.x, y: pos.y, z: pos.z onSpriteDoubleClicked: (e) -> - return unless e.thang + return unless e.thang and not @dragged @editThang thangID: e.thang.id onRandomTerrainGenerated: (e) -> @@ -251,9 +255,12 @@ module.exports = class ThangsTabView extends CocoView if e.thang and (key.alt or key.meta) # We alt-clicked, so create a clone addThang @selectAddThangType e.thang.spriteName, @selectedExtantThang - else if e.thang and not (@addThangSprite and @addThangType is 'Blood Torch Test') # TODO: figure out which Thangs can be placed on other Thangs + else if @justAdded() + # Skip double insert due to extra selection event + null + else if e.thang and not (@addThangSprite and @addThangType.get('name') in overlappableThangTypeNames) # We clicked on a Thang (or its Treema), so select the Thang - @selectAddThang null + @selectAddThang null, true @selectedExtantThangClickTime = new Date() treemaThang = _.find @thangsTreema.childrenTreemas, (treema) => treema.data.id is @selectedExtantThang.id if treemaThang @@ -266,16 +273,13 @@ module.exports = class ThangsTabView extends CocoView else if @addThangSprite # We clicked on the background when we had an add Thang selected, so add it @addThang @addThangType, @addThangSprite.thang.pos + @lastAddTime = new Date() - # Commented out this bit so the extant thangs treema editor can select invisible thangs like arrows. - # Couldn't spot any bugs... But if there are any, better come up with a better solution. -# else -# # We clicked on the background, so deselect anything selected -# @thangsTreema.deselectAll() + justAdded: -> @lastAddTime and (new Date() - @lastAddTime) < 150 - selectAddThang: (e) => + selectAddThang: (e, forceDeselect=false) => return if e? and $(e.target).closest('#thang-search').length # Ignore if you're trying to search thangs - return unless e? and $(e.target).closest('#editor-level-thangs-tab-view').length or key.isPressed('esc') + return unless (e? and $(e.target).closest('#editor-level-thangs-tab-view').length) or key.isPressed('esc') or forceDeselect if e then target = $(e.target) else target = @$el.find('.add-thangs-palette') # pretend to click on background if no event return true if target.attr('id') is 'surface' target = target.closest('.add-thang-palette-icon') @@ -312,12 +316,11 @@ module.exports = class ThangsTabView extends CocoView createEssentialComponents: (defaultComponents) -> physicalConfig = {pos: {x: 10, y: 10, z: 1}} - if physicalOriginal = _.find(defaultComponents ? [], original: componentOriginals['physics.Physical']) + if physicalOriginal = _.find(defaultComponents ? [], original: LevelComponent.PhysicalID) physicalConfig.pos.z = physicalOriginal.config?.pos?.z ? 1 # Get the z right - console.log physicalOriginal, defaultComponents, componentOriginals['physics.Physical'], physicalConfig [ - {original: componentOriginals['existence.Exists'], majorVersion: 0, config: {}} - {original: componentOriginals['physics.Physical'], majorVersion: 0, config: physicalConfig} + {original: LevelComponent.ExistsID, majorVersion: 0, config: {}} + {original: LevelComponent.PhysicalID, majorVersion: 0, config: physicalConfig} ] createAddThang: -> @@ -402,6 +405,11 @@ module.exports = class ThangsTabView extends CocoView thang.isSelectable = not thang.isLand for thang in @world.thangs # let us select walls and such @surface?.setWorld @world @selectAddThangType @addThangType, @cloneSourceThang if @addThangType # make another addThang sprite, since the World just refreshed + + # update selection, since the thangs have been remade + if @selectedExtantThang + @selectedExtantSprite = @surface.spriteBoss.sprites[@selectedExtantThang.id] + @selectedExtantThang = @selectedExtantSprite?.thang Backbone.Mediator.publish 'editor:thangs-edited', thangs: @world.thangs onTreemaThangSelected: (e, selectedTreemas) => @@ -420,12 +428,15 @@ module.exports = class ThangsTabView extends CocoView addThang: (thangType, pos, batchInsert=false) -> @$el.find('#randomize-button').hide() if batchInsert - thangID = "Random #{thangType.get('name')} #{@thangsBatch.length}" + if thangType.get('name') is 'Hero Placeholder' + thangID = 'Hero Placeholder' + return if @level.get('type') isnt 'hero' or @thangsTreema.get "id=#{thangID}" + else + thangID = "Random #{thangType.get('name')} #{@thangsBatch.length}" else thangID = Thang.nextID(thangType.get('name'), @world) until thangID and not @thangsTreema.get "id=#{thangID}" if @cloneSourceThang components = _.cloneDeep @thangsTreema.get "id=#{@cloneSourceThang.id}/components" - @selectAddThang null else if @level.get('type') is 'hero' components = [] # Load them all from default ThangType Components else @@ -510,9 +521,9 @@ class ThangNode extends TreemaObjectNode collection: false @thangNameMap: {} @thangKindMap: {} - buildValueForDisplay: (valEl) -> - pos = _.find(@data.components, (c) -> c.config?.pos?)?.config.pos # TODO: hack - s = "#{@data.thangType}" + buildValueForDisplay: (valEl, data) -> + pos = _.find(data.components, (c) -> c.config?.pos?)?.config.pos # TODO: hack + s = "#{data.thangType}" if isObjectID s unless name = ThangNode.thangNameMap[s] thangType = _.find @settings.supermodel.getModels(ThangType), (m) -> m.get('original') is s and m.get('kind') @@ -521,7 +532,7 @@ class ThangNode extends TreemaObjectNode kind = ThangNode.thangKindMap[s] @$el.addClass "treema-#{kind}" s = name - s += ' - ' + @data.id if @data.id isnt s + s += ' - ' + data.id if data.id isnt s if pos s += " (#{Math.round(pos.x)}, #{Math.round(pos.y)})" else @@ -529,4 +540,4 @@ class ThangNode extends TreemaObjectNode @buildValueForDisplaySimply valEl, s onEnterPressed: -> - Backbone.Mediator.publish 'editor:edit-level-thang', thangID: @data.id + Backbone.Mediator.publish 'editor:edit-level-thang', thangID: @getData().id diff --git a/app/views/editor/level/treema_nodes.coffee b/app/views/editor/level/treema_nodes.coffee index 5baac355a..989adfa22 100644 --- a/app/views/editor/level/treema_nodes.coffee +++ b/app/views/editor/level/treema_nodes.coffee @@ -1,5 +1,7 @@ WorldSelectModal = require './modals/WorldSelectModal' ThangType = require '/models/ThangType' +LevelComponent = require 'models/LevelComponent' +CocoCollection = require 'collections/CocoCollection' makeButton = -> $('') shorten = (f) -> parseFloat(f.toFixed(1)) @@ -11,12 +13,12 @@ module.exports.WorldPointNode = class WorldPointNode extends TreemaNode.nodeMap. console.error 'Point Treema node needs a World included in the settings.' unless @settings.world? console.error 'Point Treema node needs a RootView included in the settings.' unless @settings.view? - buildValueForDisplay: (valEl) -> - super(valEl) + buildValueForDisplay: (valEl, data) -> + super(valEl, data) valEl.find('.treema-shortened').prepend(makeButton()) - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) valEl.find('.treema-shortened').prepend(makeButton()) onClick: (e) -> @@ -24,7 +26,7 @@ module.exports.WorldPointNode = class WorldPointNode extends TreemaNode.nodeMap. if btn.length then @openMap() else super(arguments...) openMap: -> - modal = new WorldSelectModal(world: @settings.world, dataType: 'point', default: @data, supermodel: @settings.supermodel) + modal = new WorldSelectModal(world: @settings.world, dataType: 'point', default: @getData(), supermodel: @settings.supermodel) modal.callback = @callback @settings.view.openModalView modal @@ -42,12 +44,12 @@ class WorldRegionNode extends TreemaNode.nodeMap.object console.error 'Region Treema node needs a World included in the settings.' unless @settings.world? console.error 'Region Treema node needs a RootView included in the settings.' unless @settings.view? - buildValueForDisplay: (valEl) -> - super(valEl) + buildValueForDisplay: (valEl, data) -> + super(valEl, data) valEl.find('.treema-shortened').prepend(makeButton()) - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) valEl.find('.treema-shortened').prepend(makeButton()) onClick: (e) -> @@ -77,12 +79,12 @@ module.exports.WorldViewportNode = class WorldViewportNode extends TreemaNode.no console.error 'Viewport Treema node needs a World included in the settings.' unless @settings.world? console.error 'Viewport Treema node needs a RootView included in the settings.' unless @settings.view? - buildValueForDisplay: (valEl) -> - super(valEl) + buildValueForDisplay: (valEl, data) -> + super(valEl, data) valEl.find('.treema-shortened').prepend(makeButton()) - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) valEl.find('.treema-shortened').prepend(makeButton()) onClick: (e) -> @@ -92,7 +94,8 @@ module.exports.WorldViewportNode = class WorldViewportNode extends TreemaNode.no openMap: -> # can't really get the bounds from this data, so will have to hack this solution options = world: @settings.world, dataType: 'ratio-region' - options.defaultFromZoom = @data if @data?.target?.x? + data = @getData() + options.defaultFromZoom = data if data?.target?.x? options.supermodel = @settings.supermodel modal = new WorldSelectModal(options) modal.callback = @callback @@ -118,12 +121,12 @@ module.exports.WorldBoundsNode = class WorldBoundsNode extends TreemaNode.nodeMa console.error 'Bounds Treema node needs a World included in the settings.' unless @settings.world? console.error 'Bounds Treema node needs a RootView included in the settings.' unless @settings.view? - buildValueForDisplay: (valEl) -> - super(valEl) + buildValueForDisplay: (valEl, data) -> + super(valEl, data) valEl.find('.treema-shortened').prepend(makeButton()) - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) valEl.find('.treema-shortened').prepend(makeButton()) onClick: (e) -> @@ -131,7 +134,7 @@ module.exports.WorldBoundsNode = class WorldBoundsNode extends TreemaNode.nodeMa if btn.length then @openMap() else super(arguments...) openMap: -> - bounds = @data or [{x: 0, y: 0}, {x: 100, y: 80}] + bounds = @getData() or [{x: 0, y: 0}, {x: 100, y: 80}] modal = new WorldSelectModal(world: @settings.world, dataType: 'region', default: bounds, supermodel: @settings.supermodel) modal.callback = @callback @settings.view.openModalView modal @@ -142,71 +145,74 @@ module.exports.WorldBoundsNode = class WorldBoundsNode extends TreemaNode.nodeMa @set '/1', {x: shorten(e.points[1].x), y: shorten(e.points[1].y)} module.exports.ThangNode = class ThangNode extends TreemaNode.nodeMap.string - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForDisplay: (valEl, data) -> + super(valEl, data) valEl.find('input').autocomplete(source: @settings.thangIDs, minLength: 0, delay: 0, autoFocus: true) valEl module.exports.TeamNode = class TeamNode extends TreemaNode.nodeMap.string - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForDisplay: (valEl, data) -> + super(valEl, data) valEl.find('input').autocomplete(source: @settings.teams, minLength: 0, delay: 0, autoFocus: true) valEl module.exports.SuperteamNode = class SuperteamNode extends TreemaNode.nodeMap.string - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) valEl.find('input').autocomplete(source: @settings.superteams, minLength: 0, delay: 0, autoFocus: true) valEl module.exports.RadiansNode = class RadiansNode extends TreemaNode.nodeMap.number - buildValueForDisplay: (valEl) -> - super(valEl) - deg = @data / Math.PI * 180 + buildValueForDisplay: (valEl, data) -> + super(valEl, data) + deg = data / Math.PI * 180 valEl.text valEl.text() + "rad (#{deg.toFixed(0)}˚)" module.exports.MetersNode = class MetersNode extends TreemaNode.nodeMap.number - buildValueForDisplay: (valEl) -> - super(valEl) + buildValueForDisplay: (valEl, data) -> + super(valEl, data) valEl.text valEl.text() + 'm' module.exports.KilogramsNode = class KilogramsNode extends TreemaNode.nodeMap.number - buildValueForDisplay: (valEl) -> - super(valEl) + buildValueForDisplay: (valEl, data) -> + super(valEl, data) valEl.text valEl.text() + 'kg' module.exports.SecondsNode = class SecondsNode extends TreemaNode.nodeMap.number - buildValueForDisplay: (valEl) -> - super(valEl) + buildValueForDisplay: (valEl, data) -> + super(valEl, data) valEl.text valEl.text() + 's' module.exports.MillisecondsNode = class MillisecondsNode extends TreemaNode.nodeMap.number - buildValueForDisplay: (valEl) -> - super(valEl) + buildValueForDisplay: (valEl, data) -> + super(valEl, data) valEl.text valEl.text() + 'ms' module.exports.SpeedNode = class SpeedNode extends TreemaNode.nodeMap.number - buildValueForDisplay: (valEl) -> - super(valEl) + buildValueForDisplay: (valEl, data) -> + super(valEl, data) valEl.text valEl.text() + 'm/s' module.exports.AccelerationNode = class AccelerationNode extends TreemaNode.nodeMap.number - buildValueForDisplay: (valEl) -> - super(valEl) + buildValueForDisplay: (valEl, data) -> + super(valEl, data) valEl.text valEl.text() + 'm/s^2' module.exports.ThangTypeNode = class ThangTypeNode extends TreemaNode.nodeMap.string valueClass: 'treema-thang-type' + @thangTypes: null + @thangTypesCollection: null + constructor: (args...) -> super args... - @thangType = _.find @settings.supermodel.getModels(ThangType), (m) => m.get('original') is @data if @data - #console.log 'ThangTypeNode found ThangType', @thangType, 'for data', @data + data = @getData() + @thangType = _.find @settings.supermodel.getModels(ThangType), (m) => m.get('original') is data if data buildValueForDisplay: (valEl) -> @buildValueForDisplaySimply(valEl, @thangType?.get('name') or 'None') - buildValueForEditing: (valEl) -> - super(valEl) + buildValueForEditing: (valEl, data) -> + super(valEl, data) thangTypeNames = (m.get('name') for m in @settings.supermodel.getModels ThangType) input = valEl.find('input').autocomplete(source: thangTypeNames, minLength: 0, delay: 0, autoFocus: true) input.val(@thangType?.get('name') or 'None') @@ -220,11 +226,68 @@ module.exports.ThangTypeNode = class ThangTypeNode extends TreemaNode.nodeMap.st else @data = null -module.exports.ItemThangTypeNode = class ThangTypeNode extends ThangTypeNode - valueClass: 'treema-item-thang-type' - buildValueForEditing: (valEl) -> - super(valEl) - thangTypeNames = (m.get('name') for m in @settings.supermodel.getModels ThangType when m.get('kind') is 'Item') - input = valEl.find('input').autocomplete(source: thangTypeNames, minLength: 0, delay: 0, autoFocus: true) - input.val(@thangType?.get('name') or 'None') +module.exports.ThangTypeNode = ThangTypeNode = class ThangTypeNode extends TreemaNode.nodeMap.string + valueClass: 'treema-thang-type' + @thangTypesCollection: null # Lives in ThangTypeNode parent class + @thangTypes: null # Lives in ThangTypeNode or subclasses + + constructor: -> + super(arguments...) + @getThangTypes() + unless ThangTypeNode.thangTypesCollection.loaded + ThangTypeNode.thangTypesCollection.once('sync', @refreshDisplay, @) + + buildValueForDisplay: (valEl, data) -> + @buildValueForDisplaySimply(valEl, @getCurrentThangType() or '') valEl + + buildValueForEditing: (valEl, data) -> + super(valEl, data) + input = valEl.find 'input' + if @constructor.thangTypes + source = (thangType.name for thangType in @constructor.thangTypes when @filterThangType thangType) + input.autocomplete(source: source, minLength: 0, delay: 0, autoFocus: true) + input.val(@getCurrentThangType() or '') + valEl + + filterThangType: (thangType) -> true + + getCurrentThangType: -> + return null unless @constructor.thangTypes + return null unless original = @getData() + thangType = _.find @constructor.thangTypes, { original: original } + thangType?.name or '...' + + getThangTypes: -> + return if ThangTypeNode.thangTypesCollection + ThangTypeNode.thangTypesCollection = new CocoCollection([], { + url: '/db/thang.type' + project:['name', 'components', 'original'] + model: ThangType + }) + res = ThangTypeNode.thangTypesCollection.fetch() + ThangTypeNode.thangTypesCollection.once 'sync', => @processThangTypes(ThangTypeNode.thangTypesCollection) + + processThangTypes: (thangTypeCollection) -> + @constructor.thangTypes = [] + @processThangType thangType for thangType in thangTypeCollection.models + + processThangType: (thangType) -> + @constructor.thangTypes.push name: thangType.get('name'), original: thangType.get('original') + + saveChanges: -> + thangTypeName = @$el.find('input').val() + thangType = _.find(@constructor.thangTypes, {name: thangTypeName}) + return @remove() unless thangType + @data = thangType.original + +module.exports.ItemThangTypeNode = ItemThangTypeNode = class ItemThangTypeNode extends ThangTypeNode + valueClass: 'treema-item-thang-type' + + filterThangType: (thangType) -> + @keyForParent in thangType.slots + + processThangType: (thangType) -> + return unless itemComponent = _.find thangType.get('components'), {original: LevelComponent.ItemID} + return unless itemComponent.config?.slots?.length + @constructor.thangTypes.push name: thangType.get('name'), original: thangType.get('original'), slots: itemComponent.config.slots diff --git a/app/views/editor/thang/ThangTypeColorsTabView.coffee b/app/views/editor/thang/ThangTypeColorsTabView.coffee index cdc624587..69651b1ae 100644 --- a/app/views/editor/thang/ThangTypeColorsTabView.coffee +++ b/app/views/editor/thang/ThangTypeColorsTabView.coffee @@ -14,13 +14,14 @@ module.exports = class ThangTypeColorsTabView extends CocoView super options @supermodel.loadModel @thangType, 'thang' @colorConfig = {hue: 0, saturation: 0.5, lightness: 0.5} - @spriteBuilder = new SpriteBuilder(@thangType) + @spriteBuilder = new SpriteBuilder(@thangType) if @thangType.get('raw') f = => @offset++ @updateMovieClip() @interval = setInterval f, 1000 destroy: -> + @colorGroups?.destroy() clearInterval @interval super() @@ -54,7 +55,7 @@ module.exports = class ThangTypeColorsTabView extends CocoView @updateMovieClip() updateMovieClip: -> - return unless @currentColorGroupTreema + return unless @currentColorGroupTreema and @thangType.get('raw') actionDict = @thangType.getActions() animations = (a.animation for key, a of actionDict when a.animation) index = @offset % animations.length @@ -66,14 +67,16 @@ module.exports = class ThangTypeColorsTabView extends CocoView @spriteBuilder.setOptions options @spriteBuilder.buildColorMaps() @movieClip = @spriteBuilder.buildMovieClip animation - larger = Math.min(400 / @movieClip.nominalBounds.width, 400 / @movieClip.nominalBounds.height) + bounds = @movieClip.frameBounds?[0] ? @movieClip.nominalBounds + larger = Math.min(400 / bounds.width, 400 / bounds.height) @movieClip.scaleX = larger @movieClip.scaleY = larger - @movieClip.regX = @movieClip.nominalBounds.x - @movieClip.regY = @movieClip.nominalBounds.y + @movieClip.regX = bounds.x + @movieClip.regY = bounds.y @stage.addChild @movieClip updateContainer: -> + return unless @thangType.get('raw') actionDict = @thangType.getActions() idle = actionDict.idle @stage.removeChild(@container) if @container diff --git a/app/views/editor/thang/ThangTypeEditView.coffee b/app/views/editor/thang/ThangTypeEditView.coffee index afc14ef33..6d74534ab 100644 --- a/app/views/editor/thang/ThangTypeEditView.coffee +++ b/app/views/editor/thang/ThangTypeEditView.coffee @@ -59,6 +59,10 @@ module.exports = class ThangTypeEditView extends RootView @updateFileSize() @refreshAnimation = _.debounce @refreshAnimation, 500 + showLoading: ($el) -> + $el ?= @$el.find('.outer-content') + super($el) + getRenderData: (context={}) -> context = super(context) context.thangType = @thangType @@ -69,7 +73,7 @@ module.exports = class ThangTypeEditView extends RootView context getAnimationNames: -> - raw = _.keys(@thangType.get('raw').animations) + raw = _.keys(@thangType.get('raw', true).animations) raw = ("raw:#{name}" for name in raw) main = _.keys(@thangType.get('actions') or {}) main.concat(raw) @@ -84,6 +88,7 @@ module.exports = class ThangTypeEditView extends RootView @insertSubView(new ThangTypeColorsTabView(@thangType)) @patchesView = @insertSubView(new PatchesView(@thangType), @$el.find('.patches-view')) @showReadOnly() if me.get('anonymous') + @updatePortrait() initComponents: => options = @@ -375,6 +380,7 @@ module.exports = class ThangTypeEditView extends RootView el = @$el.find('#thang-type-treema') @treema = @$el.find('#thang-type-treema').treema(options) @treema.build() + @lastKind = data.kind pushChangesToPreview: => # TODO: This doesn't delete old Treema keys you deleted @@ -384,6 +390,11 @@ module.exports = class ThangTypeEditView extends RootView @refreshAnimation() @updateDots() @updatePortrait() + if (kind = @treema.data.kind) isnt @lastKind + @lastKind = kind + Backbone.Mediator.publish 'editor:thang-type-kind-changed', kind: kind + if kind in ['Doodad', 'Floor', 'Wall'] and not @treema.data.terrains + @treema.set '/terrains', ['Grass', 'Dungeon', 'Indoor'] # So editors know to set them. onSelectNode: (e, selected) => selected = selected[0] diff --git a/app/views/game-menu/GameMenuModal.coffee b/app/views/game-menu/GameMenuModal.coffee index cfb49a4db..b2d1aca45 100644 --- a/app/views/game-menu/GameMenuModal.coffee +++ b/app/views/game-menu/GameMenuModal.coffee @@ -13,10 +13,12 @@ module.exports = class GameMenuModal extends ModalView template: template modalWidthPercent: 95 id: 'game-menu-modal' + instant: true constructor: (options) -> super options @options.showDevBits = me.isAdmin() or /https?:\/\/localhost/.test(window.location.href) + @options.showInventory = @options.level.get('type', true) is 'hero' events: 'change input.select': 'onSelectionChanged' @@ -24,12 +26,14 @@ module.exports = class GameMenuModal extends ModalView getRenderData: (context={}) -> context = super(context) context.showDevBits = @options.showDevBits + context.showInventory = @options.showInventory context afterRender: -> super() + @$el.toggleClas @insertSubView new submenuView @options for submenuView in submenuViews - (if @options.showDevBits then @subviews.inventory_view else @subviews.choose_hero_view).$el.addClass 'active' + (if @options.showInventory then @subviews.inventory_view else @subviews.choose_hero_view).$el.addClass 'active' onHidden: -> subview.onHidden?() for subviewKey, subview of @subviews diff --git a/app/views/game-menu/InventoryView.coffee b/app/views/game-menu/InventoryView.coffee index ab74fa46d..b51fd3631 100644 --- a/app/views/game-menu/InventoryView.coffee +++ b/app/views/game-menu/InventoryView.coffee @@ -25,7 +25,7 @@ module.exports = class InventoryView extends CocoView super(arguments...) @items = new CocoCollection([], {model: ThangType}) @equipment = options.equipment or @options.session?.get('heroConfig')?.inventory or {} - @items.url = '/db/thang.type?view=items&project=name,description,components,original' + @items.url = '/db/thang.type?view=items&project=name,description,components,original,rasterIcon' @supermodel.loadCollection(@items, 'items') onLoaded: -> @@ -201,7 +201,7 @@ module.exports = class InventoryView extends CocoView showSelectedSlotItem: (item) -> if not @selectedEquippedItemView @selectedEquippedItemView = new ItemView({ - item: item, includes: {name: true, stats: true}}) + item: item, includes: {name: true, stats: true, props: true}}) @insertSubView(@selectedEquippedItemView, @$el.find('#selected-equipped-item .item-view-stub')) else @@ -215,7 +215,7 @@ module.exports = class InventoryView extends CocoView showSelectedAvailableItem: (item) -> if not @selectedAvailableItemView @selectedAvailableItemView = new ItemView({ - item: item, includes: {name: true, stats: true}}) + item: item, includes: {name: true, stats: true, props: true}}) @insertSubView(@selectedAvailableItemView, @$el.find('#selected-available-item .item-view-stub')) else @@ -240,8 +240,10 @@ module.exports = class InventoryView extends CocoView onHidden: -> inventory = @getCurrentEquipmentConfig() heroConfig = @options.session.get('heroConfig') ? {} - unless _.isEqual inventory, heroConfig.inventory - heroConfig.inventory = inventory - heroConfig.thangType ?= '529ffbf1cf1818f2be000001' # Temp: assign Tharin as the hero - @options.session.set 'heroConfig', heroConfig - @options.session.patch() + return if _.isEqual inventory, heroConfig.inventory + heroConfig.inventory = inventory + heroConfig.thangType ?= '529ffbf1cf1818f2be000001' # Temp: assign Tharin as the hero + @options.session.set 'heroConfig', heroConfig + @options.session.patch success: -> + _.defer -> + Backbone.Mediator.publish 'level:inventory-changed', {} diff --git a/app/views/game-menu/ItemView.coffee b/app/views/game-menu/ItemView.coffee index 8ff1b3612..0c143460b 100644 --- a/app/views/game-menu/ItemView.coffee +++ b/app/views/game-menu/ItemView.coffee @@ -3,9 +3,9 @@ template = require 'templates/game-menu/item-view' module.exports = class ItemView extends CocoView className: 'item-view' - + template: template - + initialize: (options) -> super(arguments...) @item = options.item @@ -15,7 +15,11 @@ module.exports = class ItemView extends CocoView c = super() c.item = @item c.includes = @includes + if @includes.props or @includes.stats + {props, stats} = @item.getFrontFacingStats() + c.props = props + c.stats = stats c - + afterRender: -> @$el.data('item-id', @item.id) diff --git a/app/views/kinds/CocoView.coffee b/app/views/kinds/CocoView.coffee index eb6d4859f..41e974a01 100644 --- a/app/views/kinds/CocoView.coffee +++ b/app/views/kinds/CocoView.coffee @@ -17,7 +17,7 @@ module.exports = class CocoView extends Backbone.View events: 'click .retry-loading-resource': 'onRetryResource' - 'click .retry-loading-request': 'onRetryRequest' + 'click .skip-loading-resource': 'onSkipResource' subscriptions: {} shortcuts: {} @@ -65,6 +65,13 @@ module.exports = class CocoView extends Backbone.View @destroy = doNothing $.noty.closeAll() + destroyAceEditor: (editor) -> + # convenience method to make sure the ace editor is as destroyed as can be + return unless editor + session = editor.getSession() + session.setMode '' + editor.destroy() + afterInsert: -> willDisappear: -> @@ -148,6 +155,13 @@ module.exports = class CocoView extends Backbone.View res.load() @$el.find('.progress').show() $(e.target).closest('.loading-error-alert').remove() + + onSkipResource: (e) -> + res = @supermodel.getResource($(e.target).data('resource-index')) + return unless res and res.isFailed + res.markLoaded() + @$el.find('.progress').show() + $(e.target).closest('.loading-error-alert').remove() # Modals diff --git a/app/views/kinds/ModalView.coffee b/app/views/kinds/ModalView.coffee index b2fecf1ce..5fd527b9d 100644 --- a/app/views/kinds/ModalView.coffee +++ b/app/views/kinds/ModalView.coffee @@ -6,6 +6,7 @@ module.exports = class ModalView extends CocoView closesOnClickOutside: true modalWidthPercent: null plain: false + instant: false events: 'click a': 'toggleModal' @@ -17,7 +18,7 @@ module.exports = class ModalView extends CocoView constructor: (options) -> options ?= {} - @className = @className.replace ' fade', '' if options.instant + @className = @className.replace ' fade', '' if options.instant or @instant @closeButton = options.closeButton if options.closeButton? @modalWidthPercent = options.modalWidthPercent if options.modalWidthPercent super options @@ -35,7 +36,7 @@ module.exports = class ModalView extends CocoView if Backbone.history.fragment is "employers" $(@$el).find(".background-wrapper").each -> $(this).addClass("employer-modal-background-wrapper").removeClass("background-wrapper") - + if @modalWidthPercent @$el.find('.modal-dialog').css width: "#{@modalWidthPercent}%" @$el.on 'hide.bs.modal', => diff --git a/app/views/kinds/RootView.coffee b/app/views/kinds/RootView.coffee index e44b3b0ba..ebd44c0b5 100644 --- a/app/views/kinds/RootView.coffee +++ b/app/views/kinds/RootView.coffee @@ -25,7 +25,7 @@ module.exports = class RootView extends CocoView 'click #logout-button': 'logoutAccount' 'change .language-dropdown': 'onLanguageChanged' 'click .toggle-fullscreen': 'toggleFullscreen' - 'click .auth-button': 'onClickAuthbutton' + 'click .auth-button': 'onClickAuthButton' 'click a': 'toggleModal' 'click button': 'toggleModal' 'click li': 'toggleModal' @@ -50,7 +50,7 @@ module.exports = class RootView extends CocoView subview = new WizardSettingsModal {} @openModalView subview - onClickAuthbutton: -> + onClickAuthButton: -> AuthModal = require 'views/modal/AuthModal' @openModalView new AuthModal {} @@ -66,7 +66,6 @@ module.exports = class RootView extends CocoView #location.hash = '' #location.hash = hash @renderScrollbar() - #@$('.antiscroll-wrap').antiscroll() # not yet, buggy getRenderData: -> c = super() @@ -89,7 +88,7 @@ module.exports = class RootView extends CocoView if $select.hasClass('fancified') $select.parent().find('.options, .trigger').remove() $select.unwrap().removeClass('fancified') - preferred = me.lang() + preferred = me.get('preferredLanguage', true) codes = _.keys(locale) genericCodes = _.filter codes, (code) -> _.find(codes, (code2) -> diff --git a/app/views/modal/AuthModal.coffee b/app/views/modal/AuthModal.coffee index 67abf2537..251a45a8a 100644 --- a/app/views/modal/AuthModal.coffee +++ b/app/views/modal/AuthModal.coffee @@ -75,7 +75,7 @@ module.exports = class AuthModal extends ModalView userObject.name = @suggestedName if @suggestedName for key, val of me.attributes when key in ['preferredLanguage', 'testGroupNumber', 'dateCreated', 'wizardColor1', 'name', 'music', 'volume', 'emails'] userObject[key] ?= val - subscribe = @$el.find('#signup-subscribe').prop('checked') + subscribe = @$el.find('#subscribe').prop('checked') userObject.emails ?= {} userObject.emails.generalNews ?= {} userObject.emails.generalNews.enabled = subscribe diff --git a/app/views/modal/EmployerSignupModal.coffee b/app/views/modal/EmployerSignupModal.coffee index 2c5306356..ab13e309b 100644 --- a/app/views/modal/EmployerSignupModal.coffee +++ b/app/views/modal/EmployerSignupModal.coffee @@ -57,7 +57,7 @@ module.exports = class EmployerSignupModal extends ModalView getRenderData: -> context = super() context.userIsAuthorized = @authorizedWithLinkedIn - context.userHasSignedContract = 'employer' in me.get('permissions') + context.userHasSignedContract = 'employer' in me.get('permissions', true) context.userIsAnonymous = context.me.get('anonymous') context.sentMoreInfoEmail = @sentMoreInfoEmail context diff --git a/app/views/modal/ModelModal.coffee b/app/views/modal/ModelModal.coffee index a5fbc5ce5..482482ea0 100644 --- a/app/views/modal/ModelModal.coffee +++ b/app/views/modal/ModelModal.coffee @@ -69,3 +69,7 @@ module.exports = class ModelModal extends ModalView res.success (model, response, options) => return if @destroyed @hide() + + destroy: -> + @modelTreemas[model].destroy() for model of @modelTreemas + super() \ No newline at end of file diff --git a/app/views/modal/SaveVersionModal.coffee b/app/views/modal/SaveVersionModal.coffee index 77c5556a7..8a8c50c9f 100644 --- a/app/views/modal/SaveVersionModal.coffee +++ b/app/views/modal/SaveVersionModal.coffee @@ -37,7 +37,7 @@ module.exports = class SaveVersionModal extends ModalView deltaView = new DeltaView({model: @model}) @insertSubView(deltaView, changeEl) catch e - console.error 'Couldn\'t create delta view:', e + console.error 'Couldn\'t create delta view:', e, e.stack @$el.find('.commit-message input').attr('placeholder', $.i18n.t('general.commit_msg')) onSubmitForm: (e) -> diff --git a/app/views/modal/VersionsModal.coffee b/app/views/modal/VersionsModal.coffee index b9c93bb95..ab63fd569 100755 --- a/app/views/modal/VersionsModal.coffee +++ b/app/views/modal/VersionsModal.coffee @@ -1,6 +1,5 @@ ModalView = require 'views/kinds/ModalView' template = require 'templates/modal/versions' -tableTemplate = require 'templates/kinds/table' DeltaView = require 'views/editor/DeltaView' PatchModal = require 'views/editor/PatchModal' nameLoader = require 'lib/NameLoader' diff --git a/app/views/play/common/LadderSubmissionView.coffee b/app/views/play/common/LadderSubmissionView.coffee index 4cf4b7e29..580afba8a 100644 --- a/app/views/play/common/LadderSubmissionView.coffee +++ b/app/views/play/common/LadderSubmissionView.coffee @@ -1,5 +1,6 @@ CocoView = require 'views/kinds/CocoView' template = require 'templates/play/common/ladder_submission' +{createAetherOptions} = require 'lib/aether_utils' module.exports = class LadderSubmissionView extends CocoView className: 'ladder-submission-view' @@ -72,29 +73,15 @@ module.exports = class LadderSubmissionView extends CocoView transpileSession: -> submittedCode = @session.get('code') - language = @session.get('codeLanguage') or 'javascript' - @session.set('submittedCodeLanguage', language) + codeLanguage = @session.get('codeLanguage') or 'javascript' + @session.set('submittedCodeLanguage', codeLanguage) @session.save() # TODO: maybe actually use a callback to make sure this works? transpiledCode = {} for thang, spells of submittedCode transpiledCode[thang] = {} for spellID, spell of spells unless _.contains(@session.get('teamSpells')[@session.get('team')], thang + '/' + spellID) then continue - #DRY this - aetherOptions = - problems: {} - language: language - functionName: spellID - functionParameters: [] - yieldConditionally: spellID is 'plan' - globals: ['Vector', '_'] - protectAPI: true - includeFlow: false - executionLimit: 1 * 1000 * 1000 - if spellID is 'hear' then aetherOptions.functionParameters = ['speaker', 'message', 'data'] - if spellID is 'makeBid' then aetherOptions.functionParameters = ['tileGroupLetter'] - if spellID is 'findCentroids' then aetherOptions.functionParameters = ['centroids'] - + aetherOptions = createAetherOptions functionName: spellID, codeLanguage: codeLanguage aether = new Aether aetherOptions transpiledCode[thang][spellID] = aether.transpile spell transpiledCode diff --git a/app/views/play/level/PlayLevelView.coffee b/app/views/play/level/PlayLevelView.coffee index 71981514f..a5c38c4cd 100644 --- a/app/views/play/level/PlayLevelView.coffee +++ b/app/views/play/level/PlayLevelView.coffee @@ -3,9 +3,7 @@ template = require 'templates/play/level' {me} = require 'lib/auth' ThangType = require 'models/ThangType' utils = require 'lib/utils' - -# temp hard coded data -World = require 'lib/world/world' +storage = require 'lib/storage' # tools Surface = require 'lib/surface/Surface' @@ -52,6 +50,7 @@ module.exports = class PlayLevelView extends RootView 'level:focus-dom': 'onFocusDom' 'level:disable-controls': 'onDisableControls' 'level:enable-controls': 'onEnableControls' + 'god:world-load-progress-changed': 'onWorldLoadProgressChanged' 'god:new-world-created': 'onNewWorld' 'god:streaming-world-updated': 'onNewWorld' 'god:infinite-loop': 'onInfiniteLoop' @@ -65,6 +64,7 @@ module.exports = class PlayLevelView extends RootView 'level:loading-view-unveiled': 'onLoadingViewUnveiled' 'playback:real-time-playback-started': 'onRealTimePlaybackStarted' 'playback:real-time-playback-ended': 'onRealTimePlaybackEnded' + 'level:inventory-changed': 'onInventoryChanged' events: 'click #level-done-button': 'onDonePressed' @@ -84,7 +84,7 @@ module.exports = class PlayLevelView extends RootView @isEditorPreview = @getQueryVariable 'dev' @sessionID = @getQueryVariable 'session' - $(window).on('resize', @onWindowResize) + $(window).on 'resize', @onWindowResize @saveScreenshot = _.throttle @saveScreenshot, 30000 if @isEditorPreview @@ -155,7 +155,7 @@ module.exports = class PlayLevelView extends RootView getRenderData: -> c = super() c.world = @world - if me.get('hourOfCode') and me.lang() is 'en-US' + if me.get('hourOfCode') and me.get('preferredLanguage', true) is 'en-US' # Show the Hour of Code footer explanation until it's been more than a day elapsed = (new Date() - new Date(me.get('dateCreated'))) c.explainHourOfCode = elapsed < 86400 * 1000 @@ -195,6 +195,18 @@ module.exports = class PlayLevelView extends RootView @world = @levelLoader.world @level = @levelLoader.level @otherSession = @levelLoader.opponentSession + @worldLoadFakeResources = [] # first element (0) is 1%, last (100) is 100% + for percent in [1 .. 100] + @worldLoadFakeResources.push @supermodel.addSomethingResource "world_simulation_#{percent}%", 1 + + onWorldLoadProgressChanged: (e) -> + return unless @worldLoadFakeResources + @lastWorldLoadPercent ?= 0 + worldLoadPercent = Math.floor 100 * e.progress + for percent in [@lastWorldLoadPercent + 1 .. worldLoadPercent] by 1 + @worldLoadFakeResources[percent - 1].markLoaded() + @lastWorldLoadPercent = worldLoadPercent + @worldFakeLoadResources = null if worldLoadPercent is 100 # Done, don't need to watch progress any more. loadOpponentTeam: (myTeam) -> opponentSpells = [] @@ -267,14 +279,23 @@ module.exports = class PlayLevelView extends RootView # Everything is now loaded return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early - # Save latest level played in local storage + # Save latest level played. if not (@levelLoader.level.get('type') in ['ladder', 'ladder-tutorial']) me.set('lastLevel', @levelID) me.save() + @saveRecentMatch() if @otherSession @levelLoader.destroy() @levelLoader = null @initSurface() + saveRecentMatch: -> + allRecentlyPlayedMatches = storage.load('recently-played-matches') ? {} + recentlyPlayedMatches = allRecentlyPlayedMatches[@levelID] ? [] + allRecentlyPlayedMatches[@levelID] = recentlyPlayedMatches + recentlyPlayedMatches.unshift yourTeam: me.team, otherSessionID: @otherSession.id, opponentName: @otherSession.get('creatorName') unless _.find recentlyPlayedMatches, otherSessionID: @otherSession.id + recentlyPlayedMatches.splice(8) + storage.save 'recently-played-matches', allRecentlyPlayedMatches + initSurface: -> surfaceCanvas = $('canvas#surface', @$el) @surface = new Surface(@world, surfaceCanvas, thangTypes: @supermodel.getModels(ThangType), playJingle: not @isEditorPreview) @@ -329,7 +350,7 @@ module.exports = class PlayLevelView extends RootView @setLevel e.level, e.supermodel if isReload @scriptManager.setScripts(e.level.get('scripts')) - Backbone.Mediator.publish 'tome:cast-spell' # a bit hacky + Backbone.Mediator.publish 'tome:cast-spell', {} # a bit hacky onLevelReloadThangType: (e) -> tt = e.thangType @@ -338,7 +359,17 @@ module.exports = class PlayLevelView extends RootView for key, val of tt.attributes model.attributes[key] = val break - Backbone.Mediator.publish 'tome:cast-spell' + Backbone.Mediator.publish 'tome:cast-spell', {} + + onInventoryChanged: (e) -> + # Doesn't work because the new inventory ThangTypes may not be loaded. + #@setLevel @level, @supermodel + #Backbone.Mediator.publish 'tome:cast-spell', {} + # We'll just make a new PlayLevelView instead + Backbone.Mediator.publish 'router:navigate', { + route: window.location.pathname, + viewClass: PlayLevelView, + viewArgs: [{supermodel: @supermodel}, @levelID]} onWindowResize: (s...) -> $('#pointer').css('opacity', 0.0) @@ -536,6 +567,7 @@ module.exports = class PlayLevelView extends RootView @god?.destroy() @goalManager?.destroy() @scriptManager?.destroy() + $(window).off 'resize', @onWindowResize delete window.world # not sure where this is set, but this is one way to clean it up clearInterval(@pointerInterval) @bus?.destroy() diff --git a/app/views/play/level/modal/LevelGuideModal.coffee b/app/views/play/level/modal/LevelGuideModal.coffee index 4f454b380..0d54a71a7 100644 --- a/app/views/play/level/modal/LevelGuideModal.coffee +++ b/app/views/play/level/modal/LevelGuideModal.coffee @@ -14,7 +14,7 @@ module.exports = class LevelGuideModal extends ModalView constructor: (options) -> @firstOnly = options.firstOnly - @docs = options?.docs + @docs = options?.docs ? {} general = @docs.generalArticles or [] specific = @docs.specificArticles or [] diff --git a/app/views/play/level/tome/Spell.coffee b/app/views/play/level/tome/Spell.coffee index ff2dc39e6..cfde25fe7 100644 --- a/app/views/play/level/tome/Spell.coffee +++ b/app/views/play/level/tome/Spell.coffee @@ -1,9 +1,7 @@ SpellView = require './SpellView' SpellListTabEntryView = require './SpellListTabEntryView' {me} = require 'lib/auth' - -Aether.addGlobal 'Vector', require 'lib/world/vector' -Aether.addGlobal '_', _ +{createAetherOptions} = require 'lib/aether_utils' module.exports = class Spell loaded: false @@ -125,25 +123,8 @@ module.exports = class Spell createAether: (thang) -> aceConfig = me.get('aceConfig') ? {} writable = @permissions.readwrite.length > 0 - aetherOptions = - problems: - jshint_W040: {level: 'ignore'} - jshint_W030: {level: 'ignore'} # aether_NoEffect instead - jshint_W038: {level: 'ignore'} # eliminates hoisting problems - jshint_W091: {level: 'ignore'} # eliminates more hoisting problems - jshint_E043: {level: 'ignore'} # https://github.com/codecombat/codecombat/issues/813 -- since we can't actually tell JSHint to really ignore things - jshint_Unknown: {level: 'ignore'} # E043 also triggers Unknown, so ignore that, too - aether_MissingThis: {level: 'error'} - language: @language - functionName: @name - functionParameters: @parameters - yieldConditionally: thang.plan? - globals: ['Vector', '_'] - # TODO: Gridmancer doesn't currently work with protectAPI, so hack it off - protectAPI: not (@skipProtectAPI or window.currentView?.level.get('name').match('Gridmancer')) and writable # If anyone can write to this method, we must protect it. - includeFlow: false - executionLimit: 1 * 1000 * 1000 - #console.log 'creating aether with options', aetherOptions + skipProtectAPI = @skipProtectAPI or not writable + aetherOptions = createAetherOptions functionName: @name, codeLanguage: @language, functionParameters: @parameters, skipProtectAPI: skipProtectAPI aether = new Aether aetherOptions workerMessage = function: 'createAether' @@ -178,5 +159,5 @@ module.exports = class Spell return true if @spectateView # Use transpiled code for both teams if we're just spectating. return true if @isEnemySpell() # Use transpiled for enemy spells. # Players without permissions can't view the raw code. - return true if @session.get('creator') isnt me.id and not (me.isAdmin() or 'employer' in me.get('permissions')) + return true if @session.get('creator') isnt me.id and not (me.isAdmin() or 'employer' in me.get('permissions', true)) false diff --git a/app/views/play/level/tome/SpellView.coffee b/app/views/play/level/tome/SpellView.coffee index e5cded4f7..b0b7b55a5 100644 --- a/app/views/play/level/tome/SpellView.coffee +++ b/app/views/play/level/tome/SpellView.coffee @@ -80,6 +80,7 @@ module.exports = class SpellView extends CocoView createACE: -> # Test themes and settings here: http://ace.ajax.org/build/kitchen-sink.html aceConfig = me.get('aceConfig') ? {} + @destroyAceEditor(@ace) @ace = ace.edit @$el.find('.ace')[0] @aceSession = @ace.getSession() @aceDoc = @aceSession.getDocument() @@ -710,5 +711,6 @@ module.exports = class SpellView extends CocoView @ace?.destroy() @aceDoc?.off 'change', @onCodeChangeMetaHandler @aceSession?.selection.off 'changeCursor', @onCursorActivity + @destroyAceEditor(@ace) @debugView?.destroy() super() diff --git a/app/views/user/JobProfileView.coffee b/app/views/user/JobProfileView.coffee index 6d5448ba5..9edc938fd 100644 --- a/app/views/user/JobProfileView.coffee +++ b/app/views/user/JobProfileView.coffee @@ -72,8 +72,16 @@ module.exports = class JobProfileView extends UserView finishInit: -> return unless @userID @uploadFilePath = "db/user/#{@userID}" + + if @user?.get('firstName') + jobProfile = @user.get('jobProfile') + jobProfile ?= {} + if not jobProfile.name + jobProfile.name = (@user.get('firstName') + ' ' + @user.get('lastName')).trim() + @user.set('jobProfile', jobProfile) + @highlightedContainers = [] - if me.isAdmin() or 'employer' in me.get('permissions') + if me.isAdmin() or 'employer' in me.get('permissions', true) $.post "/db/user/#{me.id}/track/view_candidate" $.post "/db/user/#{@userID}/track/viewed_by_employer" unless me.isAdmin() @sessions = @supermodel.loadCollection(new LevelSessionsCollection(@userID), 'candidate_sessions').model @@ -223,19 +231,11 @@ module.exports = class JobProfileView extends UserView context = super() context.userID = @userID context.linkedInAuthorized = @authorizedWithLinkedIn - context.jobProfileSchema = me.schema().properties.jobProfile - if @user and not jobProfile = @user.get 'jobProfile' - jobProfile = {} - for prop, schema of context.jobProfileSchema.properties - jobProfile[prop] = _.clone schema.default if schema.default? - for prop in context.jobProfileSchema.required - jobProfile[prop] ?= {string: '', boolean: false, number: 0, integer: 0, array: []}[context.jobProfileSchema.properties[prop].type] - @user.set 'jobProfile', jobProfile - jobProfile.name ?= (@user.get('firstName') + ' ' + @user.get('lastName')).trim() if @user?.get('firstName') - context.profile = jobProfile + context.profile = @user.get('jobProfile', true) + context.rawProfile = @user.get('jobProfile') or {} context.user = @user context.myProfile = @isMe() - context.allowedToViewJobProfile = @user and (me.isAdmin() or 'employer' in me.get('permissions') or (context.myProfile && !me.get('anonymous'))) + context.allowedToViewJobProfile = @user and (me.isAdmin() or 'employer' in me.get('permissions', true) or (context.myProfile && !me.get('anonymous'))) context.allowedToEditJobProfile = @user and (me.isAdmin() or (context.myProfile && !me.get('anonymous'))) context.profileApproved = @user?.get 'jobProfileApproved' context.progress = @progress ? @updateProgress() @@ -244,7 +244,7 @@ module.exports = class JobProfileView extends UserView context.marked = marked context.moment = moment context.iconForLink = @iconForLink - if links = jobProfile?.links + if links = context.profile.links links = ($.extend(true, {}, link) for link in links) link.icon = @iconForLink link for link in links context.profileLinks = _.sortBy links, (link) -> not link.icon # icons first @@ -290,8 +290,8 @@ module.exports = class JobProfileView extends UserView aceUseWrapMode: true callbacks: {change: @onRemarkChanged} @remarkTreema = @$el.find('#remark-treema').treema treemaOptions - @remarkTreema.build() - @remarkTreema.open(3) + @remarkTreema?.build() + @remarkTreema?.open(3) onRemarkChanged: (e) => return unless @remarkTreema.isValid() @@ -440,7 +440,8 @@ module.exports = class JobProfileView extends UserView $(@).remove() if isEmpty @ resetOnce = false # We have to clear out arrays if we're going to redo them serialized = form.serializeArray() - jobProfile = @user.get 'jobProfile' + jobProfile = @user.get('jobProfile') or {} + jobProfile[prop] ?= [] for prop in ['links', 'skills', 'work', 'education', 'projects'] rootPropertiesSeen = {} for field in serialized keyChain = @extractFieldKeyChain field.name @@ -449,6 +450,7 @@ module.exports = class JobProfileView extends UserView for key, i in keyChain rootPropertiesSeen[key] = true unless i break if i is keyChain.length - 1 + parent[key] ?= {} child = parent[key] if _.isArray(child) and not resetOnce child = parent[key] = [] @@ -467,6 +469,7 @@ module.exports = class JobProfileView extends UserView if section.hasClass('projects-container') and not section.find('.array-item').length jobProfile.projects = [] section.addClass 'saving' + @user.set('jobProfile', jobProfile) @saveEdits true extractFieldKeyChain: (key) -> @@ -583,3 +586,7 @@ module.exports = class JobProfileView extends UserView session = _.find @sessions.models, (session) -> session.id is sessionID modal = new JobProfileCodeModal({session:session}) @openModalView modal + + destroy: -> + @remarkTreema?.destroy() + super() diff --git a/bower.json b/bower.json index e6b9d3868..b5b07df5e 100644 --- a/bower.json +++ b/bower.json @@ -39,9 +39,9 @@ "d3": "~3.4.4", "jsondiffpatch": "~0.1.5", "nanoscroller": "~0.8.0", + "treema": "https://github.com/codecombat/treema.git#master", "jquery.tablesorter": "~2", - "treema": "~0.0.14", - "bootstrap": "~3.1.1", + "bootstrap": "~3.2.0", "validated-backbone-mediator": "~0.1.3", "jquery.browser": "~0.0.6", "zatanna": "~0.0.6", diff --git a/config.coffee b/config.coffee index 26c7687ca..62d05b3d8 100644 --- a/config.coffee +++ b/config.coffee @@ -7,7 +7,7 @@ exports.config = 'public': 'public' conventions: ignored: (path) -> startsWith(sysPath.basename(path), '_') - sourceMaps: false + sourceMaps: true files: javascripts: defaultExtension: 'coffee' diff --git a/headless_client.coffee b/headless_client.coffee index 04fdc109a..1c426bdba 100644 --- a/headless_client.coffee +++ b/headless_client.coffee @@ -42,6 +42,7 @@ Worker::removeEventListener = (what) -> if what is 'message' @onmessage = -> #This webworker api has only one event listener at a time. GLOBAL.tv4 = require('tv4').tv4 +GLOBAL.TreemaUtils = require './bower_components/treema/treema-utils.js' GLOBAL.marked = setOptions: -> store = {} GLOBAL.localStorage = diff --git a/headless_client/test.js b/headless_client/test.js index fdd51bf83..3c92b64e0 100644 --- a/headless_client/test.js +++ b/headless_client/test.js @@ -1,87 +1,42 @@ module.exports = { - "messageGenerated": 1396792689279, - "sessions": [ - { - "sessionID": "533a2c4893b95d9319a58049", - "submitDate": "2014-04-06T06:31:11.806Z", + "messageGenerated": 1409357317134, + "sessions": [{ + "sessionID": "539bb9f86e1d92310506f138", "team": "humans", - "code": { - "ogre-base": { - "chooseAction": "// This is the code for your base. Decide which unit to build each frame.\n// Units you build will go into the this.built array.\n// Destroy the enemy base within 60 seconds!\n// Check out the Guide at the top for more info.\n\n// Choose your hero! You can only build one hero.\nvar hero;\n//hero = 'ironjaw'; // A leaping juggernaut hero, type 'brawler'.\nhero = 'yugargen'; // A devious spellcaster hero, type 'shaman'.\nif(hero && !this.builtHero) {\n this.builtHero = this.build(hero);\n return;\n}\n\n// Munchkins are weak melee units with 1.25s build cooldown.\n// Throwers are fragile, deadly ranged units with 2.5s build cooldown.\nvar buildOrder = ['munchkin', 'thrower', 'munchkin', 'thrower', 'munchkin', 'thrower'];\nvar type = buildOrder[this.built.length % buildOrder.length];\n//this.say('Unit #' + this.built.length + ' will be a ' + type);\nthis.build(type);\n//this.say(\"Move\", {to:{x:20, y:30}});{x: 68, y: 29}{x: 70, y: 30}" + "transpiledCode": { + "mak-fod": {}, + "tharin": { + "chooseAction": "var __interceptThis=(function(){var G=this;return function($this,sandbox){if($this==G){return sandbox;}return $this;};})();\nreturn (function (__global) {\n var tmp0, tmp1;\n tmp1 = function () {\n 'use strict'; _aether.logCallStart(_aether._userInfo); var rjust, debug_coin, use_terrify, player, items, tmp93, tmp94, tmp95, tmp96, tmp97, tmp103, tmp104, tmp105, tmp106, tmp107, tmp118, tmp119, tmp120, tmp121, tmp122, tmp123, tmp124, tmp125, tmp126, tmp127, tmp128, tmp129, tmp130, tmp131, tmp132, tmp133, tmp134, tmp135, tmp136, tmp137, tmp138, tmp139, tmp140, tmp141, tmp142, tmp143, tmp144, tmp145, tmp146, tmp147, tmp148, tmp149, tmp150, tmp151, tmp152, tmp153, tmp154, tmp155, tmp156, tmp157, tmp158, tmp159, tmp160, tmp161, tmp162, tmp163, tmp164, tmp165; for(var __argIndexer = 0; __argIndexer < arguments.length; ++__argIndexer) arguments[__argIndexer] = _aether.createAPIClone(_aether, arguments[__argIndexer]);\n _aether.logStatementStart([{ofs: 0, row: 0, col: 0}, {ofs: 234, row: 9, col: 2}]); rjust = function (s, n, fill) {\n var num_pad_chars, out, i, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17, tmp18, tmp19, tmp20, tmp21, tmp22, tmp23, tmp24, tmp27, tmp28, tmp29, tmp30, tmp31; s = _aether.createAPIClone(_aether, s); n = _aether.createAPIClone(_aether, n); fill = _aether.createAPIClone(_aether, fill); for(var __argIndexer = 0; __argIndexer < arguments.length; ++__argIndexer) arguments[__argIndexer] = _aether.createAPIClone(_aether, arguments[__argIndexer]);\n _aether.logStatementStart([{ofs: 43, row: 1, col: 8}, {ofs: 45, row: 1, col: 10}]); tmp2 = ''; _aether.logStatement([{ofs: 43, row: 1, col: 8}, {ofs: 45, row: 1, col: 10}], _aether._userInfo, false);\n tmp6 = 'Math';\n tmp7 = tmp6 in __global;\n if (tmp7) {\n tmp4 = __global[tmp6];\n } else { _aether.logStatementStart([{ofs: 46, row: 1, col: 11}, {ofs: 50, row: 1, col: 15}]);\n tmp8 = 'ReferenceError';\n tmp9 = __global[tmp8];\n tmp10 = new tmp9('ReferenceError: ' + (tmp6 + ' is not defined'));\n throw tmp10;\n _aether.logStatement([{ofs: 46, row: 1, col: 11}, {ofs: 50, row: 1, col: 15}], _aether._userInfo, false); }\n tmp5 = 'floor';\n tmp12 = s;\n _aether.logStatementStart([{ofs: 59, row: 1, col: 24}, {ofs: 61, row: 1, col: 26}]); tmp13 = 10; _aether.logStatement([{ofs: 59, row: 1, col: 24}, {ofs: 61, row: 1, col: 26}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 57, row: 1, col: 22}, {ofs: 61, row: 1, col: 26}]); tmp11 = tmp12 * tmp13; _aether.logStatement([{ofs: 57, row: 1, col: 22}, {ofs: 61, row: 1, col: 26}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 46, row: 1, col: 11}, {ofs: 62, row: 1, col: 27}]); tmp3 = _aether.createAPIClone(_aether, tmp4[tmp5](_aether.restoreAPIClone(_aether, tmp11))); _aether.logStatement([{ofs: 46, row: 1, col: 11}, {ofs: 62, row: 1, col: 27}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 39, row: 1, col: 4}, {ofs: 63, row: 1, col: 28}]); s = tmp2 + tmp3; _aether.logStatement([{ofs: 39, row: 1, col: 4}, {ofs: 63, row: 1, col: 28}], _aether._userInfo, false);\n tmp14 = n;\n tmp16 = s;\n tmp17 = 'length';\n _aether.logStatementStart([{ofs: 92, row: 2, col: 28}, {ofs: 100, row: 2, col: 36}]); tmp15 = tmp16[tmp17]; _aether.logStatement([{ofs: 92, row: 2, col: 28}, {ofs: 100, row: 2, col: 36}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 68, row: 2, col: 4}, {ofs: 101, row: 2, col: 37}]); num_pad_chars = tmp14 - tmp15; _aether.logStatement([{ofs: 68, row: 2, col: 4}, {ofs: 101, row: 2, col: 37}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 106, row: 3, col: 4}, {ofs: 119, row: 3, col: 17}]); out = ''; _aether.logStatement([{ofs: 106, row: 3, col: 4}, {ofs: 119, row: 3, col: 17}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 128, row: 4, col: 8}, {ofs: 137, row: 4, col: 17}]); i = 0; _aether.logStatement([{ofs: 128, row: 4, col: 8}, {ofs: 137, row: 4, col: 17}], _aether._userInfo, false);\n tmp19 = i;\n tmp20 = num_pad_chars;\n _aether.logStatementStart([{ofs: 139, row: 4, col: 19}, {ofs: 156, row: 4, col: 36}]); tmp18 = tmp19 < tmp20; _aether.logStatement([{ofs: 139, row: 4, col: 19}, {ofs: 156, row: 4, col: 36}], _aether._userInfo, false);\n tmp25: {\n while (tmp18) {\n tmp26: {\n tmp27 = out;\n tmp28 = fill;\n _aether.logStatementStart([{ofs: 173, row: 5, col: 8}, {ofs: 190, row: 5, col: 25}]); out = tmp27 + tmp28; _aether.logStatement([{ofs: 173, row: 5, col: 8}, {ofs: 190, row: 5, col: 25}], _aether._userInfo, false);\n }\n tmp23 = i;\n tmp24 = 1;\n i = tmp23 + tmp24;\n tmp21 = i;\n tmp22 = num_pad_chars;\n _aether.logStatementStart([{ofs: 139, row: 4, col: 19}, {ofs: 156, row: 4, col: 36}]); tmp18 = tmp21 < tmp22; _aether.logStatement([{ofs: 139, row: 4, col: 19}, {ofs: 156, row: 4, col: 36}], _aether._userInfo, false);\n }\n }\n tmp29 = out;\n tmp30 = s;\n _aether.logStatementStart([{ofs: 201, row: 7, col: 4}, {ofs: 215, row: 7, col: 18}]); out = tmp29 + tmp30; _aether.logStatement([{ofs: 201, row: 7, col: 4}, {ofs: 215, row: 7, col: 18}], _aether._userInfo, false);\n tmp31 = out;\n return _aether.restoreAPIClone(_aether, tmp31);\n }; _aether.logStatement([{ofs: 0, row: 0, col: 0}, {ofs: 234, row: 9, col: 2}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 236, row: 11, col: 0}, {ofs: 449, row: 15, col: 2}]); debug_coin = function (dist_and_coin) {\n var dist, coin, tmp32, tmp33, tmp34, tmp35, tmp36, tmp37, tmp38, tmp39, tmp40, tmp41, tmp42, tmp43, tmp44, tmp45, tmp46, tmp47, tmp48, tmp49, tmp50, tmp51, tmp52, tmp53, tmp54, tmp55, tmp56, tmp57, tmp58, tmp59, tmp60, tmp61, tmp62, tmp63, tmp64, tmp65, tmp66, tmp67, tmp68, tmp69, tmp70, tmp71, tmp72, tmp73, tmp74, tmp75, tmp76, tmp77, tmp78, tmp79, tmp80, tmp81, tmp82, tmp83, tmp84, tmp85, tmp86; dist_and_coin = _aether.createAPIClone(_aether, dist_and_coin); for(var __argIndexer = 0; __argIndexer < arguments.length; ++__argIndexer) arguments[__argIndexer] = _aether.createAPIClone(_aether, arguments[__argIndexer]);\n tmp32 = dist_and_coin;\n _aether.logStatementStart([{ofs: 308, row: 12, col: 29}, {ofs: 309, row: 12, col: 30}]); tmp33 = 0; _aether.logStatement([{ofs: 308, row: 12, col: 29}, {ofs: 309, row: 12, col: 30}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 283, row: 12, col: 4}, {ofs: 311, row: 12, col: 32}]); dist = tmp32[tmp33]; _aether.logStatement([{ofs: 283, row: 12, col: 4}, {ofs: 311, row: 12, col: 32}], _aether._userInfo, false);\n tmp34 = dist_and_coin;\n _aether.logStatementStart([{ofs: 341, row: 13, col: 29}, {ofs: 342, row: 13, col: 30}]); tmp35 = 1; _aether.logStatement([{ofs: 341, row: 13, col: 29}, {ofs: 342, row: 13, col: 30}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 316, row: 13, col: 4}, {ofs: 344, row: 13, col: 32}]); coin = tmp34[tmp35]; _aether.logStatement([{ofs: 316, row: 13, col: 4}, {ofs: 344, row: 13, col: 32}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 356, row: 14, col: 11}, {ofs: 358, row: 14, col: 13}]); tmp51 = ''; _aether.logStatement([{ofs: 356, row: 14, col: 11}, {ofs: 358, row: 14, col: 13}], _aether._userInfo, false);\n tmp55 = 'Math';\n tmp56 = tmp55 in __global;\n if (tmp56) {\n tmp53 = __global[tmp55];\n } else { _aether.logStatementStart([{ofs: 359, row: 14, col: 14}, {ofs: 363, row: 14, col: 18}]);\n tmp57 = 'ReferenceError';\n tmp58 = __global[tmp57];\n tmp59 = new tmp58('ReferenceError: ' + (tmp55 + ' is not defined'));\n throw tmp59;\n _aether.logStatement([{ofs: 359, row: 14, col: 14}, {ofs: 363, row: 14, col: 18}], _aether._userInfo, false); }\n tmp54 = 'floor';\n tmp60 = dist;\n _aether.logStatementStart([{ofs: 359, row: 14, col: 14}, {ofs: 375, row: 14, col: 30}]); tmp52 = _aether.createAPIClone(_aether, tmp53[tmp54](_aether.restoreAPIClone(_aether, tmp60))); _aether.logStatement([{ofs: 359, row: 14, col: 14}, {ofs: 375, row: 14, col: 30}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 356, row: 14, col: 11}, {ofs: 375, row: 14, col: 30}]); tmp49 = tmp51 + tmp52; _aether.logStatement([{ofs: 356, row: 14, col: 11}, {ofs: 375, row: 14, col: 30}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 376, row: 14, col: 31}, {ofs: 379, row: 14, col: 34}]); tmp50 = ','; _aether.logStatement([{ofs: 376, row: 14, col: 31}, {ofs: 379, row: 14, col: 34}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 356, row: 14, col: 11}, {ofs: 379, row: 14, col: 34}]); tmp47 = tmp49 + tmp50; _aether.logStatement([{ofs: 356, row: 14, col: 11}, {ofs: 379, row: 14, col: 34}], _aether._userInfo, false);\n tmp63 = 'Math';\n tmp64 = tmp63 in __global;\n if (tmp64) {\n tmp61 = __global[tmp63];\n } else { _aether.logStatementStart([{ofs: 380, row: 14, col: 35}, {ofs: 384, row: 14, col: 39}]);\n tmp65 = 'ReferenceError';\n tmp66 = __global[tmp65];\n tmp67 = new tmp66('ReferenceError: ' + (tmp63 + ' is not defined'));\n throw tmp67;\n _aether.logStatement([{ofs: 380, row: 14, col: 35}, {ofs: 384, row: 14, col: 39}], _aether._userInfo, false); }\n tmp62 = 'floor';\n tmp71 = coin;\n tmp72 = 'pos';\n _aether.logStatementStart([{ofs: 391, row: 14, col: 46}, {ofs: 399, row: 14, col: 54}]); tmp69 = tmp71[tmp72]; _aether.logStatement([{ofs: 391, row: 14, col: 46}, {ofs: 399, row: 14, col: 54}], _aether._userInfo, false);\n tmp70 = 'x';\n _aether.logStatementStart([{ofs: 391, row: 14, col: 46}, {ofs: 401, row: 14, col: 56}]); tmp68 = tmp69[tmp70]; _aether.logStatement([{ofs: 391, row: 14, col: 46}, {ofs: 401, row: 14, col: 56}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 380, row: 14, col: 35}, {ofs: 402, row: 14, col: 57}]); tmp48 = _aether.createAPIClone(_aether, tmp61[tmp62](_aether.restoreAPIClone(_aether, tmp68))); _aether.logStatement([{ofs: 380, row: 14, col: 35}, {ofs: 402, row: 14, col: 57}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 356, row: 14, col: 11}, {ofs: 402, row: 14, col: 57}]); tmp45 = tmp47 + tmp48; _aether.logStatement([{ofs: 356, row: 14, col: 11}, {ofs: 402, row: 14, col: 57}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 403, row: 14, col: 58}, {ofs: 406, row: 14, col: 61}]); tmp46 = ','; _aether.logStatement([{ofs: 403, row: 14, col: 58}, {ofs: 406, row: 14, col: 61}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 356, row: 14, col: 11}, {ofs: 406, row: 14, col: 61}]); tmp43 = tmp45 + tmp46; _aether.logStatement([{ofs: 356, row: 14, col: 11}, {ofs: 406, row: 14, col: 61}], _aether._userInfo, false);\n tmp75 = 'Math';\n tmp76 = tmp75 in __global;\n if (tmp76) {\n tmp73 = __global[tmp75];\n } else { _aether.logStatementStart([{ofs: 407, row: 14, col: 62}, {ofs: 411, row: 14, col: 66}]);\n tmp77 = 'ReferenceError';\n tmp78 = __global[tmp77];\n tmp79 = new tmp78('ReferenceError: ' + (tmp75 + ' is not defined'));\n throw tmp79;\n _aether.logStatement([{ofs: 407, row: 14, col: 62}, {ofs: 411, row: 14, col: 66}], _aether._userInfo, false); }\n tmp74 = 'floor';\n tmp83 = coin;\n tmp84 = 'pos';\n _aether.logStatementStart([{ofs: 418, row: 14, col: 73}, {ofs: 426, row: 14, col: 81}]); tmp81 = tmp83[tmp84]; _aether.logStatement([{ofs: 418, row: 14, col: 73}, {ofs: 426, row: 14, col: 81}], _aether._userInfo, false);\n tmp82 = 'y';\n _aether.logStatementStart([{ofs: 418, row: 14, col: 73}, {ofs: 428, row: 14, col: 83}]); tmp80 = tmp81[tmp82]; _aether.logStatement([{ofs: 418, row: 14, col: 73}, {ofs: 428, row: 14, col: 83}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 407, row: 14, col: 62}, {ofs: 429, row: 14, col: 84}]); tmp44 = _aether.createAPIClone(_aether, tmp73[tmp74](_aether.restoreAPIClone(_aether, tmp80))); _aether.logStatement([{ofs: 407, row: 14, col: 62}, {ofs: 429, row: 14, col: 84}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 356, row: 14, col: 11}, {ofs: 429, row: 14, col: 84}]); tmp41 = tmp43 + tmp44; _aether.logStatement([{ofs: 356, row: 14, col: 11}, {ofs: 429, row: 14, col: 84}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 430, row: 14, col: 85}, {ofs: 433, row: 14, col: 88}]); tmp42 = ','; _aether.logStatement([{ofs: 430, row: 14, col: 85}, {ofs: 433, row: 14, col: 88}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 356, row: 14, col: 11}, {ofs: 433, row: 14, col: 88}]); tmp39 = tmp41 + tmp42; _aether.logStatement([{ofs: 356, row: 14, col: 11}, {ofs: 433, row: 14, col: 88}], _aether._userInfo, false);\n tmp85 = coin;\n tmp86 = 'id';\n _aether.logStatementStart([{ofs: 434, row: 14, col: 89}, {ofs: 441, row: 14, col: 96}]); tmp40 = tmp85[tmp86]; _aether.logStatement([{ofs: 434, row: 14, col: 89}, {ofs: 441, row: 14, col: 96}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 356, row: 14, col: 11}, {ofs: 441, row: 14, col: 96}]); tmp37 = tmp39 + tmp40; _aether.logStatement([{ofs: 356, row: 14, col: 11}, {ofs: 441, row: 14, col: 96}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 442, row: 14, col: 97}, {ofs: 445, row: 14, col: 100}]); tmp38 = '|'; _aether.logStatement([{ofs: 442, row: 14, col: 97}, {ofs: 445, row: 14, col: 100}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 356, row: 14, col: 11}, {ofs: 445, row: 14, col: 100}]); tmp36 = tmp37 + tmp38; _aether.logStatement([{ofs: 356, row: 14, col: 11}, {ofs: 445, row: 14, col: 100}], _aether._userInfo, false);\n return _aether.restoreAPIClone(_aether, tmp36);\n }; _aether.logStatement([{ofs: 236, row: 11, col: 0}, {ofs: 449, row: 15, col: 2}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 451, row: 17, col: 0}, {ofs: 543, row: 20, col: 2}]); use_terrify = function (player) {\n var tmp87, tmp88, tmp89, tmp90, tmp91, tmp92; player = _aether.createAPIClone(_aether, player); for(var __argIndexer = 0; __argIndexer < arguments.length; ++__argIndexer) arguments[__argIndexer] = _aether.createAPIClone(_aether, arguments[__argIndexer]);\n tmp87 = player;\n tmp88 = 'terrify';\n _aether.logStatementStart([{ofs: 492, row: 18, col: 4}, {ofs: 508, row: 18, col: 20}]); tmp89 = _aether.createAPIClone(_aether, tmp87[tmp88]()); _aether.logStatement([{ofs: 492, row: 18, col: 4}, {ofs: 508, row: 18, col: 20}], _aether._userInfo, false);\n tmp90 = player;\n tmp91 = 'usedTerrify';\n _aether.logStatementStart([{ofs: 514, row: 19, col: 4}, {ofs: 540, row: 19, col: 30}]); tmp92 = true; _aether.logStatement([{ofs: 514, row: 19, col: 4}, {ofs: 540, row: 19, col: 30}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 514, row: 19, col: 4}, {ofs: 539, row: 19, col: 29}]); tmp90[tmp91] = tmp92; _aether.logStatement([{ofs: 514, row: 19, col: 4}, {ofs: 539, row: 19, col: 29}], _aether._userInfo, false);\n return;\n }; _aether.logStatement([{ofs: 451, row: 17, col: 0}, {ofs: 543, row: 20, col: 2}], _aether._userInfo, false);\n player = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp93 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp94 = 'getItems';\n _aether.logStatementStart([{ofs: 633, row: 25, col: 0}, {ofs: 661, row: 25, col: 28}]); items = _aether.createAPIClone(_aether, tmp93[tmp94]()); _aether.logStatement([{ofs: 633, row: 25, col: 0}, {ofs: 661, row: 25, col: 28}], _aether._userInfo, false);\n tmp95 = items;\n tmp96 = 'filter';\n _aether.logStatementStart([{ofs: 683, row: 26, col: 21}, {ofs: 723, row: 26, col: 61}]); tmp97 = function (x) {\n var tmp98, tmp99, tmp100, tmp101, tmp102; x = _aether.createAPIClone(_aether, x); for(var __argIndexer = 0; __argIndexer < arguments.length; ++__argIndexer) arguments[__argIndexer] = _aether.createAPIClone(_aether, arguments[__argIndexer]);\n tmp101 = x;\n tmp102 = 'bountyGold';\n _aether.logStatementStart([{ofs: 704, row: 26, col: 42}, {ofs: 716, row: 26, col: 54}]); tmp99 = tmp101[tmp102]; _aether.logStatement([{ofs: 704, row: 26, col: 42}, {ofs: 716, row: 26, col: 54}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 719, row: 26, col: 57}, {ofs: 720, row: 26, col: 58}]); tmp100 = 2; _aether.logStatement([{ofs: 719, row: 26, col: 57}, {ofs: 720, row: 26, col: 58}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 704, row: 26, col: 42}, {ofs: 720, row: 26, col: 58}]); tmp98 = tmp99 > tmp100; _aether.logStatement([{ofs: 704, row: 26, col: 42}, {ofs: 720, row: 26, col: 58}], _aether._userInfo, false);\n return _aether.restoreAPIClone(_aether, tmp98);\n }; _aether.logStatement([{ofs: 683, row: 26, col: 21}, {ofs: 723, row: 26, col: 61}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 662, row: 26, col: 0}, {ofs: 725, row: 26, col: 63}]); items = _aether.createAPIClone(_aether, tmp95[tmp96](_aether.restoreAPIClone(_aether, tmp97))); _aether.logStatement([{ofs: 662, row: 26, col: 0}, {ofs: 725, row: 26, col: 63}], _aether._userInfo, false);\n tmp105 = items;\n tmp106 = 'map';\n _aether.logStatementStart([{ofs: 744, row: 27, col: 18}, {ofs: 806, row: 27, col: 80}]); tmp107 = function (x) {\n var tmp108, tmp109, tmp110, tmp111, tmp112, tmp113, tmp114, tmp115, tmp116, tmp117; x = _aether.createAPIClone(_aether, x); for(var __argIndexer = 0; __argIndexer < arguments.length; ++__argIndexer) arguments[__argIndexer] = _aether.createAPIClone(_aether, arguments[__argIndexer]);\n tmp111 = rjust;\n tmp115 = player;\n tmp116 = 'distance';\n tmp117 = x;\n _aether.logStatementStart([{ofs: 772, row: 27, col: 46}, {ofs: 790, row: 27, col: 64}]); tmp112 = _aether.createAPIClone(_aether, tmp115[tmp116](_aether.restoreAPIClone(_aether, tmp117))); _aether.logStatement([{ofs: 772, row: 27, col: 46}, {ofs: 790, row: 27, col: 64}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 792, row: 27, col: 66}, {ofs: 793, row: 27, col: 67}]); tmp113 = 7; _aether.logStatement([{ofs: 792, row: 27, col: 66}, {ofs: 793, row: 27, col: 67}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 795, row: 27, col: 69}, {ofs: 798, row: 27, col: 72}]); tmp114 = '0'; _aether.logStatement([{ofs: 795, row: 27, col: 69}, {ofs: 798, row: 27, col: 72}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 766, row: 27, col: 40}, {ofs: 799, row: 27, col: 73}]); tmp109 = _aether.createAPIClone(_aether, tmp111(_aether.restoreAPIClone(_aether, tmp112), _aether.restoreAPIClone(_aether, tmp113), _aether.restoreAPIClone(_aether, tmp114))); _aether.logStatement([{ofs: 766, row: 27, col: 40}, {ofs: 799, row: 27, col: 73}], _aether._userInfo, false);\n tmp110 = x;\n _aether.logStatementStart([{ofs: 765, row: 27, col: 39}, {ofs: 803, row: 27, col: 77}]); tmp108 = [\n tmp109,\n tmp110\n ]; _aether.logStatement([{ofs: 765, row: 27, col: 39}, {ofs: 803, row: 27, col: 77}], _aether._userInfo, false);\n return _aether.restoreAPIClone(_aether, tmp108);\n }; _aether.logStatement([{ofs: 744, row: 27, col: 18}, {ofs: 806, row: 27, col: 80}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 734, row: 27, col: 8}, {ofs: 807, row: 27, col: 81}]); tmp103 = _aether.createAPIClone(_aether, tmp105[tmp106](_aether.restoreAPIClone(_aether, tmp107))); _aether.logStatement([{ofs: 734, row: 27, col: 8}, {ofs: 807, row: 27, col: 81}], _aether._userInfo, false);\n tmp104 = 'sort';\n _aether.logStatementStart([{ofs: 726, row: 27, col: 0}, {ofs: 815, row: 27, col: 89}]); items = _aether.createAPIClone(_aether, tmp103[tmp104]()); _aether.logStatement([{ofs: 726, row: 27, col: 0}, {ofs: 815, row: 27, col: 89}], _aether._userInfo, false);\n tmp118 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp119 = 'say';\n tmp121 = items;\n tmp122 = 'map';\n tmp123 = debug_coin;\n _aether.logStatementStart([{ofs: 825, row: 28, col: 9}, {ofs: 846, row: 28, col: 30}]); tmp120 = _aether.createAPIClone(_aether, tmp121[tmp122](_aether.restoreAPIClone(_aether, tmp123))); _aether.logStatement([{ofs: 825, row: 28, col: 9}, {ofs: 846, row: 28, col: 30}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 816, row: 28, col: 0}, {ofs: 847, row: 28, col: 31}]); tmp124 = _aether.createAPIClone(_aether, tmp118[tmp119](_aether.restoreAPIClone(_aether, tmp120))); _aether.logStatement([{ofs: 816, row: 28, col: 0}, {ofs: 847, row: 28, col: 31}], _aether._userInfo, false);\n tmp127 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp128 = 'usedTerrify';\n _aether.logStatementStart([{ofs: 854, row: 30, col: 4}, {ofs: 870, row: 30, col: 20}]); tmp126 = tmp127[tmp128]; _aether.logStatement([{ofs: 854, row: 30, col: 4}, {ofs: 870, row: 30, col: 20}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 853, row: 30, col: 3}, {ofs: 870, row: 30, col: 20}]); tmp125 = !tmp126; _aether.logStatement([{ofs: 853, row: 30, col: 3}, {ofs: 870, row: 30, col: 20}], _aether._userInfo, false);\n if (tmp125) {\n tmp132 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp133 = 'distance';\n tmp135 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp136 = 'getNearestEnemy';\n _aether.logStatementStart([{ofs: 895, row: 31, col: 21}, {ofs: 917, row: 31, col: 43}]); tmp134 = _aether.createAPIClone(_aether, tmp135[tmp136]()); _aether.logStatement([{ofs: 895, row: 31, col: 21}, {ofs: 917, row: 31, col: 43}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 881, row: 31, col: 7}, {ofs: 918, row: 31, col: 44}]); tmp130 = _aether.createAPIClone(_aether, tmp132[tmp133](_aether.restoreAPIClone(_aether, tmp134))); _aether.logStatement([{ofs: 881, row: 31, col: 7}, {ofs: 918, row: 31, col: 44}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 921, row: 31, col: 47}, {ofs: 922, row: 31, col: 48}]); tmp131 = 5; _aether.logStatement([{ofs: 921, row: 31, col: 47}, {ofs: 922, row: 31, col: 48}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 881, row: 31, col: 7}, {ofs: 922, row: 31, col: 48}]); tmp129 = tmp130 < tmp131; _aether.logStatement([{ofs: 881, row: 31, col: 7}, {ofs: 922, row: 31, col: 48}], _aether._userInfo, false);\n if (tmp129) {\n tmp138 = use_terrify;\n tmp139 = player;\n _aether.logStatementStart([{ofs: 941, row: 32, col: 15}, {ofs: 960, row: 32, col: 34}]); tmp137 = _aether.createAPIClone(_aether, tmp138(_aether.restoreAPIClone(_aether, tmp139))); _aether.logStatement([{ofs: 941, row: 32, col: 15}, {ofs: 960, row: 32, col: 34}], _aether._userInfo, false);\n _aether.logCallEnd(); return _aether.restoreAPIClone(_aether, tmp137);\n } else {\n ;\n }\n tmp143 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp144 = 'now';\n _aether.logStatementStart([{ofs: 975, row: 34, col: 7}, {ofs: 985, row: 34, col: 17}]); tmp141 = _aether.createAPIClone(_aether, tmp143[tmp144]()); _aether.logStatement([{ofs: 975, row: 34, col: 7}, {ofs: 985, row: 34, col: 17}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 988, row: 34, col: 20}, {ofs: 990, row: 34, col: 22}]); tmp142 = 40; _aether.logStatement([{ofs: 988, row: 34, col: 20}, {ofs: 990, row: 34, col: 22}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 975, row: 34, col: 7}, {ofs: 990, row: 34, col: 22}]); tmp140 = tmp141 > tmp142; _aether.logStatement([{ofs: 975, row: 34, col: 7}, {ofs: 990, row: 34, col: 22}], _aether._userInfo, false);\n if (tmp140) {\n tmp146 = use_terrify;\n tmp147 = player;\n _aether.logStatementStart([{ofs: 1009, row: 35, col: 15}, {ofs: 1028, row: 35, col: 34}]); tmp145 = _aether.createAPIClone(_aether, tmp146(_aether.restoreAPIClone(_aether, tmp147))); _aether.logStatement([{ofs: 1009, row: 35, col: 15}, {ofs: 1028, row: 35, col: 34}], _aether._userInfo, false);\n _aether.logCallEnd(); return _aether.restoreAPIClone(_aether, tmp145);\n } else {\n ;\n }\n } else {\n ;\n }\n tmp149 = items;\n _aether.logStatementStart([{ofs: 1049, row: 39, col: 10}, {ofs: 1050, row: 39, col: 11}]); tmp150 = 0; _aether.logStatement([{ofs: 1049, row: 39, col: 10}, {ofs: 1050, row: 39, col: 11}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 1043, row: 39, col: 4}, {ofs: 1051, row: 39, col: 12}]); tmp148 = tmp149[tmp150]; _aether.logStatement([{ofs: 1043, row: 39, col: 4}, {ofs: 1051, row: 39, col: 12}], _aether._userInfo, false);\n if (tmp148) {\n tmp151 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp152 = 'move';\n tmp158 = items;\n _aether.logStatementStart([{ofs: 1075, row: 40, col: 20}, {ofs: 1076, row: 40, col: 21}]); tmp159 = 0; _aether.logStatement([{ofs: 1075, row: 40, col: 20}, {ofs: 1076, row: 40, col: 21}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 1069, row: 40, col: 14}, {ofs: 1077, row: 40, col: 22}]); tmp156 = tmp158[tmp159]; _aether.logStatement([{ofs: 1069, row: 40, col: 14}, {ofs: 1077, row: 40, col: 22}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 1078, row: 40, col: 23}, {ofs: 1079, row: 40, col: 24}]); tmp157 = 1; _aether.logStatement([{ofs: 1078, row: 40, col: 23}, {ofs: 1079, row: 40, col: 24}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 1069, row: 40, col: 14}, {ofs: 1080, row: 40, col: 25}]); tmp154 = tmp156[tmp157]; _aether.logStatement([{ofs: 1069, row: 40, col: 14}, {ofs: 1080, row: 40, col: 25}], _aether._userInfo, false);\n tmp155 = 'pos';\n _aether.logStatementStart([{ofs: 1069, row: 40, col: 14}, {ofs: 1084, row: 40, col: 29}]); tmp153 = tmp154[tmp155]; _aether.logStatement([{ofs: 1069, row: 40, col: 14}, {ofs: 1084, row: 40, col: 29}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 1059, row: 40, col: 4}, {ofs: 1085, row: 40, col: 30}]); tmp160 = _aether.createAPIClone(_aether, tmp151[tmp152](_aether.restoreAPIClone(_aether, tmp153))); _aether.logStatement([{ofs: 1059, row: 40, col: 4}, {ofs: 1085, row: 40, col: 30}], _aether._userInfo, false);\n } else {\n tmp161 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp162 = 'moveXY';\n _aether.logStatementStart([{ofs: 1112, row: 42, col: 16}, {ofs: 1114, row: 42, col: 18}]); tmp163 = 64; _aether.logStatement([{ofs: 1112, row: 42, col: 16}, {ofs: 1114, row: 42, col: 18}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 1116, row: 42, col: 20}, {ofs: 1118, row: 42, col: 22}]); tmp164 = 40; _aether.logStatement([{ofs: 1116, row: 42, col: 20}, {ofs: 1118, row: 42, col: 22}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 1100, row: 42, col: 4}, {ofs: 1119, row: 42, col: 23}]); tmp165 = _aether.createAPIClone(_aether, tmp161[tmp162](_aether.restoreAPIClone(_aether, tmp163), _aether.restoreAPIClone(_aether, tmp164))); _aether.logStatement([{ofs: 1100, row: 42, col: 4}, {ofs: 1119, row: 42, col: 23}], _aether._userInfo, false);\n }\n _aether.logCallEnd(); return;\n };\n tmp0 = 'chooseAction';\n __global[tmp0] = tmp1;\n}(this));" }, - "programmable-shaman": { - "chooseAction": "if (this.hero !== undefined) {\n this.hero = this.getNearest(enemy);\n}\n// Shamans are spellcasters with a weak magic attack\n// and three spells: 'shrink', 'grow', and 'poison-cloud'.\n// Shrink: target has 2/3 health, 1.5x speed for 5s.\n// Grow: target has double health, half speed for 5s.\n// Once per match, she can cast poison cloud, which does\n// 5 poison dps for 10s to enemies in a 10m radius.\nvar right = 0;\nif(right === 0){this.move({x: 70, y: 40});\n}\nvar friends = this.getFriends();\nvar enemies = this.getEnemies();\nif (enemies.length === 0) return; // Chill if all enemies are dead.\nvar enemy = this.getNearest(enemies);\nvar friend = this.getNearest(friends);\n\nif(this.canCast('shrink', enemy)) \n{\n this.castShrink(enemy);\n}\nelse\n{\n this.castGrow(friend);\n}\n\nvar enemiesinpoisonrange = 0;\nfor (var i = 0; i < enemies.lenght; ++i) {\n var enemi = enemies[i];\n if (this.distance(enemi) <= 10) {\n enemiesinpoisonrange++;\n }\n}\nif (enemiesinpoisonrange >= 7) {\n this.castPoisonCloud(enemy);\n}\n//if (this.distance(ogrebase) > 10) {\n// this.move({x: 70, y: 30});\n//}\n//this.say(\"Defend!\", {targetPos: {x: 45, y: 30}});\n\n//this.say(\"Defend!\", {targetPos: {x: 35, y: 30}});\n\n//this.say(\"Defend!\", {targetPos: {x: 25, y: 30}});\n\n//this.say(\"Attack!\", {to:{x:20, y:30}});\n\n\n// Which one do you do at any given time? Only the last called action happens.\n//if(this.canCast('shrink', enemy)) this.castShrink(enemy);\n//if(this.canCast('grow', friend)) this.castGrow(friend);\n//if(this.canCast('poison-cloud', enemy)) this.castPoisonCloud(enemy);\n//this.attack(enemy);\n\n// You can also command your troops with this.say():\n//this.say(\"Defend!\", {targetPos: {x: 45, y: 30}});\n//this.say(\"Attack!\", {target: enemy});\n//this.say(\"Move!\", {targetPos: {x: 50, y: 40});" - }, - "programmable-brawler": { - "chooseAction": "// The Brawler is a huge melee hero with mighty mass.\n// this.throw() hurls an enemy behind him.\n// this.jumpTo() leaps to a target within 20m every 10s.\n// this.stomp() knocks everyone away, once per match.\n\nvar friends = this.getFriends();\nvar enemies = this.getEnemies();\nif (enemies.length === 0) return; // Chill if all enemies are dead.\nvar enemy = this.getNearest(enemies);\nvar friend = this.getNearest(friends);\n\n// Which one do you do at any given time? Only the last called action happens.\n//if(!this.getCooldown('jump')) this.jumpTo(enemy.pos);\n//if(!this.getCooldown('stomp') && this.distance(enemy) < 10) this.stomp();\n//if(!this.getCooldown('throw')) this.throw(enemy);\n//this.attack(enemy);\n\n// You can also command your troops with this.say():\n//this.say(\"Defend!\", {targetPos: {x: 60, y: 30}}));\n//this.say(\"Attack!\", {target: enemy});\n//this.say(\"Move!\", {targetPos: {x: 50, y: 40});\n\n// You can store state on this across frames:\n//this.lastHealth = this.health;{x: 68, y: 29}{x: 70, y: 30}" - }, - "programmable-librarian": { - "chooseAction": "var enemies = this.getEnemies();\nif (enemies.length === 0)\n return;\nvar enemy = this.getNearest(enemies);\nvar friends = this.getFriends();\nvar friend = this.getNearest(friends);\nvar archer = this.getFriends(type, \"archer\");\nvar soldier = this.getFriends(type, \"soldier\");\nvar hero = this.getFriends(type, \"hushbaum\");\nvar rand = Math.random();\nvar xmove;\nvar ymove;\nfor (var i = 0; i < enemies.length / 3; i += 1) {\n var e = enemies[i];\n var ehealth = Math.floor(e.health);\n if (this.canCast(\"haste\", friend)) {\n this.say(\"Godspeed \" + friend.id + \"!\");\n this.castHaste(friend);\n }\n if (this.canCast(\"haste\", this)) {\n this.say(\"I am Godspeed!\");\n this.castHaste(this);\n }\n if (this.canCast(\"slow\", e)) {\n this.say(\"Chill Out \" + e.id + \"!\");\n this.castSlow(e);\n }\n if (this.distance(e) < 45) {\n this.attack(e);\n this.say(\"Attacking \" + e.id + \" life is \" + ehealth + \".\");\n }\n if (this.health < this.maxHealth * 0.75) {\n if (this.pos.x > 20) {\n this.move({\n x: this.pos.x - 20,\n y: this.pos.y\n });\n } else {\n this.move({\n x: this.pos.x + 20,\n y: this.pos.y\n });\n }\n }\n if (this.canCast(\"regen\", this)) {\n this.castRegen(this);\n this.say(\"I won't die today bitch!\");\n }\n if (friend.health < friend.maxHealth * 0.5) {\n if (this.canCast(\"regen\", friend)) {\n this.say(\"You won't die today \" + friend.id + \".\");\n this.castRegen(friend);\n }\n }\n}\n;" - }, - "programmable-tharin": { - "chooseAction": "// Tharin is a melee fighter with shield, warcry, and terrify skills.\n// this.shield() lets him take one-third damage while defending.\n// this.warcry() gives allies within 10m 30% haste for 5s, every 10s.\n// this.terrify() sends foes within 30m fleeing for 5s, once per match.\n\nvar friends = this.getFriends();\nvar enemies = this.getEnemies();\nif (enemies.length === 0) return; // Chill if all enemies are dead.\nvar enemy = this.getNearest(enemies);\nvar friend = this.getNearest(friends);\n\n// Which one do you do at any given time? Only the last called action happens.\n//if(!this.getCooldown('warcry')) this.warcry();\n//if(!this.getCooldown('terrify')) this.terrify();\n//this.shield();\n//this.attack(enemy);\n\n// You can also command your troops with this.say():\n//this.say(\"Defend!\", {targetPos: {x: 30, y: 30}}));\n//this.say(\"Attack!\", {target: enemy});\n//this.say(\"Move!\", {targetPos: {x: 40, y: 40});\n\n// You can store state on this across frames:\n//this.lastHealth = this.health;" - }, - "human-base": { - "chooseAction": "// This is the code for your base. Decide which unit to build each frame.\n// Units you build will go into the this.built array.\n// Destroy the enemy base within 60 seconds!\n// Check out the Guide at the top for more info.\n\n// CHOOSE YOUR HERO! You can only build one hero.\nvar hero;\n//hero = 'tharin'; // A fierce knight with battlecry abilities.\nhero = 'hushbaum'; // A fiery spellcaster hero.\n\nif(hero && !this.builtHero) {\n this.builtHero = this.build(hero);\n return;\n}\n\n// Soldiers are hard-to-kill, low damage melee units with 2s build cooldown.\n// Archers are fragile but deadly ranged units with 2.5s build cooldown.\nvar buildOrder = ['soldier', 'soldier', 'archer', 'archer', 'soldier', 'soldier'];\nvar type = buildOrder[this.built.length % buildOrder.length];\nthis.say('Unit #' + this.built.length + ' will be a ' + type);\nthis.build(type);\n\n " - } + "coin-generator-9000": {} }, + "submittedCodeLanguage": "javascript", "teamSpells": { - "ogres": [ - "programmable-brawler/chooseAction", - "programmable-shaman/chooseAction", - "ogre-base/chooseAction" - ], - "humans": [ - "programmable-librarian/chooseAction", - "programmable-tharin/chooseAction", - "human-base/chooseAction" - ] + "common": ["coin-generator-9000/chooseAction"], + "humans": ["tharin/chooseAction"], + "ogres": ["mak-fod/chooseAction"] }, - "levelID": "dungeon-arena", - "creator": "5338c38c4811eff221de2347", - "creatorName": "iC0DE" - }, - { - "sessionID": "532a777c2042708b711a6c29", - "submitDate": "2014-03-20T05:45:54.691Z", + "levelID": "gold-rush", + "creatorName": "s-krackas", + "creator": "539b4c9cb4c4f93805452aba", + "totalScore": 36.389248829587835 + }, { + "sessionID": "53fdc33abfe0d7f308a6906a", "team": "ogres", - "code": { - "ogre-base": { - "chooseAction": "// This is the code for your base. Decide which unit to build each frame.\n// Units you build will go into the this.built array.\n// Destroy the enemy base within 60 seconds!\n// Check out the Guide at the top for more info.\n\n// Choose your hero! You can only build one hero.\nvar hero;\n//hero = 'ironjaw'; // A leaping juggernaut hero, type 'brawler'.\nhero = 'yugargen'; // A devious spellcaster hero, type 'shaman'.\nif(hero && !this.builtHero) {\n this.builtHero = this.build(hero);\n return;\n}\n\n// Munchkins are weak melee units with 1.25s build cooldown.\n// Throwers are fragile, deadly ranged units with 2.5s build cooldown.\nvar buildOrder = ['munchkin', 'munchkin', 'munchkin', 'thrower'];\nvar type = buildOrder[this.built.length % buildOrder.length];\n//this.say('Unit #' + this.built.length + ' will be a ' + type);\nthis.build(type);" - }, - "programmable-shaman": { - "chooseAction": "// Shamans are spellcasters with a weak magic attack\n// and three spells: 'shrink', 'grow', and 'poison-cloud'.\n// Shrink: target has 2/3 health, 1.5x speed for 5s.\n// Grow: target has double health, half speed for 5s.\n// Once per match, she can cast poison cloud, which does\n// 5 poison dps for 10s to enemies in a 10m radius.\n\nvar friends = this.getFriends();\nvar enemies = this.getEnemies();\nif (enemies.length === 0) {\n return; // Chill if all enemies are dead.\n}\nvar enemy = this.getNearest(enemies);\nvar friend = this.getNearest(friends);\nif (enemies.length > 5) {\n if(this.canCast('poison-cloud', enemy)) {\n this.castPoisonCloud(enemy);\n return;\n }\n}\n\nif (friends.length > 4) {\n this.attack(enemy); \n}\nfor (var i = 0; i < friends.length; ++i) {\n if (friends[i].health < 0) {\n continue;\n }\n if(friends[i].type == \"thrower\" && this.canCast('shrink', friends[i])) {\n this.castShrink(friends[i]);\n return;\n } \n if(friends[i].type == \"munchkin\" && this.canCast('grow', friends[i])) {\n this.castGrow(friends[i]);\n return;\n } \n}\n\n// Which one do you do at any given time? Only the last called action happens.\n//if(this.canCast('shrink', enemy)) this.castShrink(enemy);\n//if(this.canCast('grow', friend)) this.castGrow(friend);\n//if(this.canCast('poison-cloud', enemy)) this.castPoisonCloud(enemy);\n//this.attack(enemy);\n\n// You can also command your troops with this.say():\n//this.say(\"Defend!\", {targetPos: {x: 60, y: 30}}));\n//this.say(\"Attack!\", {target: enemy});\n//this.say(\"Move!\", {targetPos: {x: 50, y: 40});" - }, - "programmable-brawler": { - "chooseAction": "// The Brawler is a huge melee hero with mighty mass.\n// this.throw() hurls an enemy behind him.\n// this.jumpTo() leaps to a target within 20m every 10s.\n// this.stomp() knocks everyone away, once per match.\n\nvar friends = this.getFriends();\nvar enemies = this.getEnemies();\nif (enemies.length === 0) return; // Chill if all enemies are dead.\nvar enemy = this.getNearest(enemies);\nvar friend = this.getNearest(friends);\n\n// Which one do you do at any given time? Only the last called action happens.\n//if(!this.getCooldown('jump')) this.jumpTo(enemy.pos);\n//if(!this.getCooldown('stomp') && this.distance(enemy) < 10) this.stomp();\n//if(!this.getCooldown('throw')) this.throw(enemy);\n//this.attack(enemy);\n\n// You can also command your troops with this.say():\n//this.say(\"Defend!\", {targetPos: {x: 60, y: 30}}));\n//this.say(\"Attack!\", {target: enemy});\n//this.say(\"Move!\", {targetPos: {x: 50, y: 40});\n\n// You can store state on this across frames:\n//this.lastHealth = this.health;" - }, - "human-base": { - "chooseAction": "// This is the code for your base. Decide which unit to build each frame.\n// Units you build will go into the this.built array.\n// Destroy the enemy base within 60 seconds!\n// Check out the Guide at the top for more info.\n\n// CHOOSE YOUR HERO! You can only build one hero.\nvar hero;\nhero = 'tharin'; // A fierce knight with battlecry abilities.\n//hero = 'hushbaum'; // A fiery spellcaster hero.\n\nif(hero && !this.builtHero) {\n this.builtHero = this.build(hero);\n return;\n}\n\n// Soldiers are hard-to-kill, low damage melee units with 2s build cooldown.\n// Archers are fragile but deadly ranged units with 2.5s build cooldown.\nvar buildOrder = ['archer', 'archer', 'soldier', 'archer', 'soldier'];\nvar type = buildOrder[this.built.length % buildOrder.length];\n//this.say('Unit #' + this.built.length + ' will be a ' + type);\nthis.build(type);" - }, - "programmable-tharin": { - "chooseAction": "this.findTypeInRange = function(units, type) {\n for (var i = 0; i < units.length; ++i) {\n var unit = units[i];\n if (unit.type === type && this.distance(unit) < 20)\n return unit;\n }\n return null;\n};\n\nthis.findType = function(units, type) {\n for (var i = 0; i < units.length; ++i) {\n var unit = units[i];\n if (unit.type === type)\n return unit;\n }\n return null;\n};\n\nthis.findHeroInRange = function(units, range) {\n for (var i = 0; i < units.length; ++i) {\n var unit = units[i];\n if ((unit.type === 'shaman' || unit.type === 'brawler') && this.distance(unit) < range)\n return unit;\n }\n return null;\n};\n\n// Tharin is a melee fighter with shield, warcry, and terrify skills.\n// this.shield() lets him take one-third damage while defending.\n// this.warcry() gives allies within 10m 30% haste for 5s, every 10s.\n// this.terrify() sends foes within 30m fleeing for 5s, once per match.\n\nvar friends = this.getFriends();\nvar enemies = this.getEnemies();\n\n//Enemies\nvar enemyBase = this.findType(enemies, 'base');\nvar brawler = this.findTypeInRange(enemies, 'brawler');\nvar shaman = this.findTypeInRange(enemies, 'shaman');\n\nif (enemies.length === 0) return; // Chill if all enemies are dead.\nvar enemy = this.getNearest(enemies);\nvar friend = this.getNearest(friends);\n\n// Which one do you do at any given time? Only the last called action happens.\n//if(!this.getCooldown('warcry')) this.warcry();\n//if(!this.getCooldown('terrify')) this.terrify();\n//this.shield();\n\nif((brawler || shaman) && !this.attackTime)\n{\n this.attackTime = true;\n if(brawler)\n this.say(\"Attack!\", {target: brawler});\n else if(shaman)\n this.say(\"Attack!\", {target: shaman});\n}\nelse if(this.health < 15 && this.getCooldown('terrify'))\n{\n this.terrify();\n}\nelse if(this.findHeroInRange(enemies, 30) && this.getCooldown('terrify'))\n{\n this.terrify();\n}\nelse if(this.health < 25)\n{\n this.shield();\n}\nelse if(brawler && this.distance(brawler) <=10)\n{\n this.attack(brawler);\n}\nelse\n{\n this.attack(enemy);\n}\n\n// You can also command your troops with this.say():\n//this.say(\"Defend!\", {targetPos: {x: 30, y: 30}}));\n//this.say(\"Attack!\", {target: enemy});\n//this.say(\"Move!\", {targetPos: {x: 40, y: 40});\n\n// You can store state on this across frames:\n//this.lastHealth = this.health;" - }, - "programmable-librarian": { - "chooseAction": "// The Librarian is a spellcaster with a fireball attack\n// plus three useful spells: 'slow', 'regen', and 'haste'.\n// Slow makes a target move and attack at half speed for 5s.\n// Regen makes a target heal 10 hp/s for 10s.\n// Haste speeds up a target by 4x for 5s, once per match.\n\nvar friends = this.getFriends();\nvar enemies = this.getEnemies();\nif (enemies.length === 0) return; // Chill if all enemies are dead.\nvar enemy = this.getNearest(enemies);\nvar friend = this.getNearest(friends);\n\n// Which one do you do at any given time? Only the last called action happens.\n//if(this.canCast('slow', enemy)) this.castSlow(enemy);\n//if(this.canCast('regen', friend)) this.castRegen(friend);\n//if(this.canCast('haste', friend)) this.castHaste(friend);\n//this.attack(enemy);\n\n// You can also command your troops with this.say():\n//this.say(\"Defend!\", {targetPos: {x: 30, y: 30}}));\n//this.say(\"Attack!\", {target: enemy});\n//this.say(\"Move!\", {targetPos: {x: 50, y: 40});" + "transpiledCode": { + "mak-fod": { + "chooseAction": "var __interceptThis=(function(){var G=this;return function($this,sandbox){if($this==G){return sandbox;}return $this;};})();\nreturn (function (__global) {\n var tmp0, tmp1;\n tmp1 = function () {\n 'use strict'; _aether.logCallStart(_aether._userInfo); var items, saystring, currdistance, currindex, i, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp18, tmp19, tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27, tmp28, tmp29, tmp30, tmp31, tmp32, tmp33, tmp34, tmp35, tmp36, tmp37, tmp38, tmp39, tmp40, tmp41, tmp42, tmp43, tmp44, tmp45, tmp46, tmp47, tmp48, tmp49, tmp50, tmp51, tmp52, tmp53, tmp54, tmp55, tmp56, tmp57, tmp58, tmp59, tmp60, tmp61, tmp62, tmp63, tmp64; for(var __argIndexer = 0; __argIndexer < arguments.length; ++__argIndexer) arguments[__argIndexer] = _aether.createAPIClone(_aether, arguments[__argIndexer]);\n tmp2 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp3 = 'getItems';\n _aether.logStatementStart([{ofs: 173, row: 4, col: 0}, {ofs: 201, row: 4, col: 28}]); items = _aether.convertToNativeType(_aether.createAPIClone(_aether, tmp2[tmp3]())); _aether.logStatement([{ofs: 173, row: 4, col: 0}, {ofs: 201, row: 4, col: 28}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 202, row: 5, col: 0}, {ofs: 221, row: 5, col: 19}]); saystring = ''; _aether.logStatement([{ofs: 202, row: 5, col: 0}, {ofs: 221, row: 5, col: 19}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 242, row: 6, col: 20}, {ofs: 243, row: 6, col: 21}]); tmp4 = 1; _aether.logStatement([{ofs: 242, row: 6, col: 20}, {ofs: 243, row: 6, col: 21}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 222, row: 6, col: 0}, {ofs: 244, row: 6, col: 22}]); currdistance = -tmp4; _aether.logStatement([{ofs: 222, row: 6, col: 0}, {ofs: 244, row: 6, col: 22}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 245, row: 7, col: 0}, {ofs: 263, row: 7, col: 18}]); currindex = 0; _aether.logStatement([{ofs: 245, row: 7, col: 0}, {ofs: 263, row: 7, col: 18}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 268, row: 8, col: 4}, {ofs: 277, row: 8, col: 13}]); i = 0; _aether.logStatement([{ofs: 268, row: 8, col: 4}, {ofs: 277, row: 8, col: 13}], _aether._userInfo, false);\n tmp6 = i;\n tmp8 = items;\n tmp9 = 'length';\n _aether.logStatementStart([{ofs: 283, row: 8, col: 19}, {ofs: 295, row: 8, col: 31}]); tmp7 = tmp8[tmp9]; _aether.logStatement([{ofs: 283, row: 8, col: 19}, {ofs: 295, row: 8, col: 31}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 279, row: 8, col: 15}, {ofs: 295, row: 8, col: 31}]); tmp5 = tmp6 < tmp7; _aether.logStatement([{ofs: 279, row: 8, col: 15}, {ofs: 295, row: 8, col: 31}], _aether._userInfo, false);\n tmp16: {\n while (tmp5) {\n tmp17: {\n tmp19 = i;\n _aether.logStatementStart([{ofs: 325, row: 9, col: 21}, {ofs: 327, row: 9, col: 23}]); tmp20 = ''; _aether.logStatement([{ofs: 325, row: 9, col: 21}, {ofs: 327, row: 9, col: 23}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 308, row: 9, col: 4}, {ofs: 328, row: 9, col: 24}]); tmp18 = tmp19 + tmp20; _aether.logStatement([{ofs: 308, row: 9, col: 4}, {ofs: 328, row: 9, col: 24}], _aether._userInfo, false);\n tmp21 = saystring;\n tmp22 = tmp18;\n saystring = tmp21 + tmp22;\n tmp24 = currdistance;\n _aether.logStatementStart([{ofs: 353, row: 10, col: 24}, {ofs: 354, row: 10, col: 25}]); tmp26 = 1; _aether.logStatement([{ofs: 353, row: 10, col: 24}, {ofs: 354, row: 10, col: 25}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 352, row: 10, col: 23}, {ofs: 354, row: 10, col: 25}]); tmp25 = -tmp26; _aether.logStatement([{ofs: 352, row: 10, col: 23}, {ofs: 354, row: 10, col: 25}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 336, row: 10, col: 7}, {ofs: 354, row: 10, col: 25}]); tmp23 = tmp24 == tmp25; _aether.logStatement([{ofs: 336, row: 10, col: 7}, {ofs: 354, row: 10, col: 25}], _aether._userInfo, false);\n if (tmp23) {\n tmp27 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp28 = 'distance';\n tmp30 = items;\n tmp31 = i;\n _aether.logStatementStart([{ofs: 395, row: 11, col: 37}, {ofs: 403, row: 11, col: 45}]); tmp29 = tmp30[tmp31]; _aether.logStatement([{ofs: 395, row: 11, col: 37}, {ofs: 403, row: 11, col: 45}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 366, row: 11, col: 8}, {ofs: 405, row: 11, col: 47}]); currdistance = _aether.convertToNativeType(_aether.createAPIClone(_aether, tmp27[tmp28](_aether.restoreAPIClone(_aether, tmp29)))); _aether.logStatement([{ofs: 366, row: 11, col: 8}, {ofs: 405, row: 11, col: 47}], _aether._userInfo, false);\n } else {\n ;\n }\n tmp35 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp36 = 'distance';\n tmp38 = items;\n tmp39 = i;\n _aether.logStatementStart([{ofs: 433, row: 13, col: 21}, {ofs: 441, row: 13, col: 29}]); tmp37 = tmp38[tmp39]; _aether.logStatement([{ofs: 433, row: 13, col: 21}, {ofs: 441, row: 13, col: 29}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 419, row: 13, col: 7}, {ofs: 442, row: 13, col: 30}]); tmp33 = _aether.convertToNativeType(_aether.createAPIClone(_aether, tmp35[tmp36](_aether.restoreAPIClone(_aether, tmp37)))); _aether.logStatement([{ofs: 419, row: 13, col: 7}, {ofs: 442, row: 13, col: 30}], _aether._userInfo, false);\n tmp34 = currdistance;\n _aether.logStatementStart([{ofs: 419, row: 13, col: 7}, {ofs: 457, row: 13, col: 45}]); tmp32 = tmp33 < tmp34; _aether.logStatement([{ofs: 419, row: 13, col: 7}, {ofs: 457, row: 13, col: 45}], _aether._userInfo, false);\n if (tmp32) {\n tmp40 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp41 = 'distance';\n tmp43 = items;\n tmp44 = i;\n _aether.logStatementStart([{ofs: 498, row: 14, col: 37}, {ofs: 506, row: 14, col: 45}]); tmp42 = tmp43[tmp44]; _aether.logStatement([{ofs: 498, row: 14, col: 37}, {ofs: 506, row: 14, col: 45}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 469, row: 14, col: 8}, {ofs: 508, row: 14, col: 47}]); currdistance = _aether.convertToNativeType(_aether.createAPIClone(_aether, tmp40[tmp41](_aether.restoreAPIClone(_aether, tmp42)))); _aether.logStatement([{ofs: 469, row: 14, col: 8}, {ofs: 508, row: 14, col: 47}], _aether._userInfo, false);\n currindex = i;\n } else {\n ;\n }\n }\n tmp14 = i;\n tmp15 = 1;\n i = tmp14 + tmp15;\n tmp10 = i;\n tmp12 = items;\n tmp13 = 'length';\n _aether.logStatementStart([{ofs: 283, row: 8, col: 19}, {ofs: 295, row: 8, col: 31}]); tmp11 = tmp12[tmp13]; _aether.logStatement([{ofs: 283, row: 8, col: 19}, {ofs: 295, row: 8, col: 31}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 279, row: 8, col: 15}, {ofs: 295, row: 8, col: 31}]); tmp5 = tmp10 < tmp11; _aether.logStatement([{ofs: 279, row: 8, col: 15}, {ofs: 295, row: 8, col: 31}], _aether._userInfo, false);\n }\n }\n tmp45 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp46 = 'say';\n tmp47 = currindex;\n _aether.logStatementStart([{ofs: 546, row: 20, col: 0}, {ofs: 565, row: 20, col: 19}]); tmp48 = _aether.convertToNativeType(_aether.createAPIClone(_aether, tmp45[tmp46](_aether.restoreAPIClone(_aether, tmp47)))); _aether.logStatement([{ofs: 546, row: 20, col: 0}, {ofs: 565, row: 20, col: 19}], _aether._userInfo, false);\n tmp50 = items;\n tmp51 = currindex;\n _aether.logStatementStart([{ofs: 571, row: 21, col: 4}, {ofs: 587, row: 21, col: 20}]); tmp49 = tmp50[tmp51]; _aether.logStatement([{ofs: 571, row: 21, col: 4}, {ofs: 587, row: 21, col: 20}], _aether._userInfo, false);\n if (tmp49) {\n tmp52 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp53 = 'move';\n tmp57 = items;\n tmp58 = currindex;\n _aether.logStatementStart([{ofs: 605, row: 22, col: 14}, {ofs: 621, row: 22, col: 30}]); tmp55 = tmp57[tmp58]; _aether.logStatement([{ofs: 605, row: 22, col: 14}, {ofs: 621, row: 22, col: 30}], _aether._userInfo, false);\n tmp56 = 'pos';\n _aether.logStatementStart([{ofs: 605, row: 22, col: 14}, {ofs: 625, row: 22, col: 34}]); tmp54 = tmp55[tmp56]; _aether.logStatement([{ofs: 605, row: 22, col: 14}, {ofs: 625, row: 22, col: 34}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 595, row: 22, col: 4}, {ofs: 626, row: 22, col: 35}]); tmp59 = _aether.convertToNativeType(_aether.createAPIClone(_aether, tmp52[tmp53](_aether.restoreAPIClone(_aether, tmp54)))); _aether.logStatement([{ofs: 595, row: 22, col: 4}, {ofs: 626, row: 22, col: 35}], _aether._userInfo, false);\n } else {\n tmp60 = _aether.createAPIClone(_aether, __interceptThis(this, __global));\n tmp61 = 'moveXY';\n _aether.logStatementStart([{ofs: 653, row: 24, col: 16}, {ofs: 655, row: 24, col: 18}]); tmp62 = 18; _aether.logStatement([{ofs: 653, row: 24, col: 16}, {ofs: 655, row: 24, col: 18}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 657, row: 24, col: 20}, {ofs: 659, row: 24, col: 22}]); tmp63 = 36; _aether.logStatement([{ofs: 657, row: 24, col: 20}, {ofs: 659, row: 24, col: 22}], _aether._userInfo, false);\n _aether.logStatementStart([{ofs: 641, row: 24, col: 4}, {ofs: 660, row: 24, col: 23}]); tmp64 = _aether.convertToNativeType(_aether.createAPIClone(_aether, tmp60[tmp61](_aether.restoreAPIClone(_aether, tmp62), _aether.restoreAPIClone(_aether, tmp63)))); _aether.logStatement([{ofs: 641, row: 24, col: 4}, {ofs: 660, row: 24, col: 23}], _aether._userInfo, false);\n }\n _aether.logCallEnd(); return;\n };\n tmp0 = 'chooseAction';\n __global[tmp0] = tmp1;\n}(this));" } }, + "submittedCodeLanguage": "javascript", "teamSpells": { - "ogres": [ - "programmable-brawler/chooseAction", - "programmable-shaman/chooseAction", - "ogre-base/chooseAction" - ], - "humans": [ - "programmable-librarian/chooseAction", - "programmable-tharin/chooseAction", - "human-base/chooseAction" - ] + "common": ["coin-generator-9000/chooseAction"], + "humans": ["tharin/chooseAction"], + "ogres": ["mak-fod/chooseAction"] }, - "levelID": "dungeon-arena", - "creator": "53291a80b112e7240f324667", - "creatorName": "Imbal Oceanrage" - } -], - "taskID": "53415d71942d00aa43dbf3e9", - "receiptHandle": "cd50e44db7dbd4cc0bcce047aa822ba2fe3556cf" -} \ No newline at end of file + "levelID": "gold-rush", + "creatorName": "monkboll", + "creator": "53fdb782716abde208a0e7a4", + "totalScore": 24.174942315603005 + }] +} diff --git a/scripts/mongodb/migrations/2014-08-27-component-and-system-config-defaults.js b/scripts/mongodb/migrations/2014-08-27-component-and-system-config-defaults.js new file mode 100644 index 000000000..64346d8a1 --- /dev/null +++ b/scripts/mongodb/migrations/2014-08-27-component-and-system-config-defaults.js @@ -0,0 +1,45 @@ +load('bower_components/lodash/dist/lodash.js'); +load('bower_components/underscore.string/dist/underscore.string.min.js'); +load('bower_components/tv4/tv4.js'); +load('bower_components/treema/treema-utils.js'); + +print(db.level.components.count()); + +// This script can be modified later to also remove the old defaults in these components and systems. + +migrateDefault = function (doc) { + thisTv4 = tv4.freshApi(); + thisTv4.addSchema('#', doc.configSchema || {}); + var data = TreemaUtils.cloneDeep(doc.configSchema.default) || {}; + TreemaUtils.populateRequireds(data, doc.configSchema); + var props = doc.configSchema.properties; + if(props) { + _.keys(doc.configSchema.properties).forEach(function (key) { + if(data[key]) return; + var childSchema = props[key]; + var workingSchema = TreemaUtils.buildWorkingSchemas(childSchema, thisTv4)[0]; + if(workingSchema.default) + return data[key] = TreemaUtils.cloneDeep(workingSchema.default); + var type = props[key].type; + if(!type) return; + if(Array.isArray(type)) type = type[0]; + data[key] = TreemaUtils.defaultForType(type); + }) + } + delete doc.configSchema.required; + doc.configSchema.default = data; +// print('\n\n--------------------', doc.name); +// print("SCHEMA: ", JSON.stringify(doc.configSchema, null, '\t')); + if(doc.system) { + print('saving component', doc.name); + db.level.components.save(doc); + } + else { + print('saving system', doc.name); + db.level.systems.save(doc); + } +}; + +db.level.components.find({slug: {$exists: true}}).forEach(migrateDefault); +db.level.systems.find({slug: {$exists: true}}).forEach(migrateDefault); + diff --git a/scripts/transpile.coffee b/scripts/transpile.coffee index 5c39b414b..53e66e43a 100644 --- a/scripts/transpile.coffee +++ b/scripts/transpile.coffee @@ -8,9 +8,8 @@ async = require 'async' serverSetup = require '../server_setup' Level = require '../server/levels/Level' LevelSession = require '../server/levels/sessions/LevelSession' +{createAetherOptions} = require '../app/lib/aether_utils' -Aether.addGlobal 'Vector', require '../app/lib/world/vector' -Aether.addGlobal '_', _ i = 0 transpileLevelSession = (sessionID, cb) -> query = LevelSession.findOne('_id': sessionID).select('team teamSpells submittedCode submittedCodeLanguage').lean() @@ -27,23 +26,9 @@ transpileLevelSession = (sessionID, cb) -> transpiledCode[thang] = {} for spellID, spell of spells spellName = thang + '/' + spellID - - if session.teamSpells and not (spellName in session.teamSpells[session.team]) then continue + continue if session.teamSpells and not (spellName in session.teamSpells[session.team]) #console.log "Transpiling spell #{spellName}" - aetherOptions = - problems: {} - language: session.submittedCodeLanguage - functionName: spellID - functionParameters: [] - yieldConditionally: spellID is 'plan' - globals: ['Vector', '_'] - protectAPI: true - includeFlow: false - executionLimit: 1 * 1000 * 1000 - if spellID is 'hear' then aetherOptions.functionParameters = ['speaker', 'message', 'data'] - if spellID is 'makeBid' then aetherOptions.functionParameters = ['tileGroupLetter'] - if spellID is 'findCentroids' then aetherOptions.functionParameters = ['centroids'] - + aetherOptions = createAetherOptions functionName: spellID, codeLanguage: session.submittedCodeLanguage aether = new Aether aetherOptions transpiledCode[thang][spellID] = aether.transpile spell conditions = diff --git a/server/achievements/Achievement.coffee b/server/achievements/Achievement.coffee index 07a492a7c..649bc4527 100644 --- a/server/achievements/Achievement.coffee +++ b/server/achievements/Achievement.coffee @@ -4,6 +4,7 @@ log = require 'winston' utils = require '../../app/lib/utils' plugins = require('../plugins/plugins') AchievablePlugin = require '../plugins/achievements' +TreemaUtils = require '../../bower_components/treema/treema-utils.js' # `pre` and `post` are not called for update operations executed directly on the database, # including `Model.update`,`.findByIdAndUpdate`,`.findOneAndUpdate`, `.findOneAndRemove`,and `.findByIdAndRemove`.order @@ -25,9 +26,9 @@ AchievementSchema.methods.stringifyQuery = -> @set('query', JSON.stringify(@get('query'))) if typeof @get('query') != 'string' AchievementSchema.methods.getExpFunction = -> - kind = @get('function')?.kind or jsonschema.properties.function.default.kind - parameters = @get('function')?.parameters or jsonschema.properties.function.default.parameters - return utils.functionCreators[kind](parameters) if kind of utils.functionCreators + func = @get('function') ? {} + TreemaUtils.populateDefaults(func, jsonschema.properties.function) + return utils.functionCreators[func.kind](func.parameters) if func.kind of utils.functionCreators AchievementSchema.methods.isRecalculable = -> @get('recalculable') isnt false diff --git a/server/levels/Level.coffee b/server/levels/Level.coffee index 05cbdeb8f..dc2020557 100644 --- a/server/levels/Level.coffee +++ b/server/levels/Level.coffee @@ -12,12 +12,6 @@ LevelSchema.plugin(plugins.VersionedPlugin) LevelSchema.plugin(plugins.SearchablePlugin, {searchable: ['name', 'description']}) LevelSchema.plugin(plugins.PatchablePlugin) -LevelSchema.pre 'init', (next) -> - return next() unless jsonschema.properties? - for prop, sch of jsonschema.properties - @set(prop, _.cloneDeep(sch.default)) if sch.default? - next() - LevelSchema.post 'init', (doc) -> if _.isString(doc.get('nextLevel')) doc.set('nextLevel', undefined) diff --git a/server/levels/components/LevelComponent.coffee b/server/levels/components/LevelComponent.coffee index 6fb467908..ffd7b6468 100644 --- a/server/levels/components/LevelComponent.coffee +++ b/server/levels/components/LevelComponent.coffee @@ -13,10 +13,4 @@ LevelComponentSchema.plugin plugins.VersionedPlugin LevelComponentSchema.plugin plugins.SearchablePlugin, {searchable: ['name', 'description', 'system']} LevelComponentSchema.plugin plugins.PatchablePlugin -LevelComponentSchema.pre 'init', (next) -> - return next() unless jsonschema.properties? - for prop, sch of jsonschema.properties - @set(prop, _.cloneDeep sch.default) if sch.default? - next() - module.exports = LevelComponent = mongoose.model('level.component', LevelComponentSchema) diff --git a/server/levels/level_handler.coffee b/server/levels/level_handler.coffee index 79946b116..f51f6574f 100644 --- a/server/levels/level_handler.coffee +++ b/server/levels/level_handler.coffee @@ -37,6 +37,7 @@ LevelHandler = class LevelHandler extends Handler return @getMyLeaderboardRank(req, res, args[0]) if args[1] is 'leaderboard_rank' return @getMySessions(req, res, args[0]) if args[1] is 'my_sessions' return @getFeedback(req, res, args[0]) if args[1] is 'feedback' + return @getAllFeedback(req, res, args[0]) if args[1] is 'all_feedback' return @getRandomSessionPair(req, res, args[0]) if args[1] is 'random_session_pair' return @getLeaderboardFacebookFriends(req, res, args[0]) if args[1] is 'leaderboard_facebook_friends' return @getLeaderboardGPlusFriends(req, res, args[0]) if args[1] is 'leaderboard_gplus_friends' @@ -266,18 +267,24 @@ LevelHandler = class LevelHandler extends Handler if map.length != 2 then return @sendDatabaseError res, 'There aren\'t sessions of 2 teams, so cannot choose random opponents!' @sendSuccess res, sessions - getFeedback: (req, res, id) -> + getFeedback: (req, res, levelID) -> return @sendNotFoundError(res) unless req.user - @fetchLevelByIDAndHandleErrors id, req, res, (err, level) => + @doGetFeedback req, res, levelID, false + + getAllFeedback: (req, res, levelID) -> + @doGetFeedback req, res, levelID, true + + doGetFeedback: (req, res, levelID, multiple) -> + @fetchLevelByIDAndHandleErrors levelID, req, res, (err, level) => feedbackQuery = - creator: mongoose.Types.ObjectId(req.user.id.toString()) 'level.original': level.original.toString() 'level.majorVersion': level.version.major - - Feedback.findOne(feedbackQuery).exec (err, doc) => + feedbackQuery.creator = mongoose.Types.ObjectId(req.user.id.toString()) unless multiple + fn = if multiple then 'find' else 'findOne' + Feedback[fn](feedbackQuery).exec (err, result) => return @sendDatabaseError(res, err) if err - return @sendNotFoundError(res) unless doc? - @sendSuccess(res, doc) + return @sendNotFoundError(res) unless result? + @sendSuccess(res, result) getPlayCountsBySlugs: (req, res) -> # This is hella slow (4s on my box), so relying on some dumb caching for it. @@ -292,8 +299,8 @@ LevelHandler = class LevelHandler extends Handler if playCounts = @playCountCache[cacheKey] return @sendSuccess res, playCounts query = Session.aggregate [ - {$match: {levelID: {$in: levelIDs}}}, - {$group: {_id: "$levelID", playtime: {$sum: "$playtime"}, sessions: {$sum: 1}}}, + {$match: {levelID: {$in: levelIDs}}} + {$group: {_id: "$levelID", playtime: {$sum: "$playtime"}, sessions: {$sum: 1}}} {$sort: {sessions: -1}} ] query.exec (err, data) => diff --git a/server/levels/sessions/LevelSession.coffee b/server/levels/sessions/LevelSession.coffee index 329914f01..b9ae9cb5d 100644 --- a/server/levels/sessions/LevelSession.coffee +++ b/server/levels/sessions/LevelSession.coffee @@ -14,13 +14,6 @@ LevelSessionSchema = new mongoose.Schema({ LevelSessionSchema.plugin(plugins.PermissionsPlugin) LevelSessionSchema.plugin(AchievablePlugin) -LevelSessionSchema.pre 'init', (next) -> - # TODO: refactor this into a set of common plugins for all models? - return next() unless jsonschema.properties? - for prop, sch of jsonschema.properties - @set(prop, _.cloneDeep(sch.default)) if sch.default? - next() - previous = {} LevelSessionSchema.post 'init', (doc) -> diff --git a/server/levels/sessions/level_session_handler.coffee b/server/levels/sessions/level_session_handler.coffee index 678b33e80..7d7e2886d 100644 --- a/server/levels/sessions/level_session_handler.coffee +++ b/server/levels/sessions/level_session_handler.coffee @@ -9,11 +9,12 @@ class LevelSessionHandler extends Handler getByRelationship: (req, res, args...) -> return @getActiveSessions req, res if args.length is 2 and args[1] is 'active' + return @getCodeLanguageCounts req, res if args[1] is 'code_language_counts' super(arguments...) formatEntity: (req, document) -> documentObject = super(req, document) - if req.user.isAdmin() or req.user.id is document.creator or ('employer' in req.user.get('permissions')) + if req.user.isAdmin() or req.user.id is document.creator or ('employer' in (req.user.get('permissions') ? [])) return documentObject else return _.omit documentObject, @privateProperties @@ -30,7 +31,25 @@ class LevelSessionHandler extends Handler hasAccessToDocument: (req, document, method=null) -> return true if req.method is 'GET' and document.get('totalScore') - return true if ('employer' in req.user.get('permissions')) and (method ? req.method).toLowerCase() is 'get' + return true if ('employer' in (req.user.get('permissions') ? [])) and (method ? req.method).toLowerCase() is 'get' super(arguments...) + getCodeLanguageCounts: (req, res) -> + if @codeLanguageCache and (new Date()) - @codeLanguageCountCachedSince > 86400 * 1000 # Dumb cache expiration + @codeLanguageCountCache = null + @codeLanguageCountCacheSince = null + if @codeLanguageCountCache + return @sendSuccess res, @codeLanguageCountCache + query = LevelSession.aggregate [ + #{$match: {codeLanguage: {$exists: true}}} # actually slows it down + {$group: {_id: "$codeLanguage", sessions: {$sum: 1}}} + {$sort: {sessions: -1}} + ] + query.exec (err, data) => + if err? then return @sendDatabaseError res, err + @codeLanguageCountCache = data + @codeLanguageCountCachedSince = new Date() + @sendSuccess res, data + + module.exports = new LevelSessionHandler() diff --git a/server/levels/systems/LevelSystem.coffee b/server/levels/systems/LevelSystem.coffee index b553cdd89..87c4a2bab 100644 --- a/server/levels/systems/LevelSystem.coffee +++ b/server/levels/systems/LevelSystem.coffee @@ -12,10 +12,4 @@ LevelSystemSchema.plugin(plugins.VersionedPlugin) LevelSystemSchema.plugin(plugins.SearchablePlugin, {searchable: ['name', 'description']}) LevelSystemSchema.plugin(plugins.PatchablePlugin) -LevelSystemSchema.pre 'init', (next) -> - return next() unless jsonschema.properties? - for prop, sch of jsonschema.properties - @set(prop, _.cloneDeep sch.default) if sch.default? - next() - module.exports = LevelSystem = mongoose.model('level.system', LevelSystemSchema) diff --git a/server/routes/auth.coffee b/server/routes/auth.coffee index 5bb1cf1a2..666954496 100644 --- a/server/routes/auth.coffee +++ b/server/routes/auth.coffee @@ -32,23 +32,14 @@ module.exports.setup = (app) -> app.post '/auth/spy', (req, res, next) -> if req?.user?.isAdmin() - - username = req.body.usernameLower - emailLower = req.body.emailLower - if emailLower - query = {'emailLower': emailLower} - else if username - query = {'nameLower': username} - else - return errors.badInput res, 'You need to supply one of emailLower or username' - + target = req.body.nameOrEmailLower + return errors.badInput res, 'Specify a username or email to espionage.' unless target + query = $or: [{nameLower: target}, {emailLower: target}] User.findOne query, (err, user) -> if err? then return errors.serverError res, 'There was an error finding the specified user' - unless user then return errors.badInput res, 'The specified user couldn\'t be found' - req.logIn user, (err) -> - if err? then return errors.serverError res, 'There was an error logging in with the specified' + if err? then return errors.serverError res, 'There was an error logging in with the specified user' res.send(UserHandler.formatEntity(req, user)) return res.end() else @@ -117,7 +108,7 @@ module.exports.setup = (app) -> ) ) - app.get '/auth/unsubscribe', (req, res) -> + app.get '/auth/unsubscribe', (req, res) -> req.query.email = decodeURIComponent(req.query.email) email = req.query.email unless req.query.email @@ -132,7 +123,7 @@ module.exports.setup = (app) -> return errors.serverError res, 'Database failure.' if err res.send "Unsubscribed #{req.query.email} from CodeCombat emails for #{session.levelName} #{session.team} ladder updates. Sorry to see you go!

Ladder preferences

" res.end() - + User.findOne({emailLower: req.query.email.toLowerCase()}).exec (err, user) -> if not user return errors.notFound res, "No user found with email '#{req.query.email}'" @@ -147,7 +138,7 @@ module.exports.setup = (app) -> else if req.query.employerNotes emails.employerNotes ?= {} emails.employerNotes.enabled = false - + msg = "Unsubscribed #{req.query.email} from employer emails." else msg = "Unsubscribed #{req.query.email} from all CodeCombat emails. Sorry to see you go!" diff --git a/server/routes/languages.coffee b/server/routes/languages.coffee index b29cc8fdb..e6f411a04 100644 --- a/server/routes/languages.coffee +++ b/server/routes/languages.coffee @@ -26,6 +26,11 @@ module.exports.languageCodesLower = languageCodesLower = (code.toLowerCase() for # Keep keys lower-case for matching and values with second subtag uppercase like i18next expects languageAliases = 'en': 'en-US' + 'de': 'de-DE' + 'es': 'es-ES' + 'zh': 'zh-HANS' + 'pt': 'pt-PT' + 'nl': 'nl-NL' 'zh-cn': 'zh-HANS' 'zh-hans-cn': 'zh-HANS' @@ -39,6 +44,7 @@ languageAliases = 'zh-mo': 'zh-HANT' 'zh-hant-mo': 'zh-HANT' + module.exports.languageCodeFromAcceptedLanguages = languageCodeFromAcceptedLanguages = (acceptedLanguages) -> for lang in acceptedLanguages ? [] code = languageAliases[lang.toLowerCase()] diff --git a/server/routes/mail.coffee b/server/routes/mail.coffee index 4d905b4d1..38c159bab 100644 --- a/server/routes/mail.coffee +++ b/server/routes/mail.coffee @@ -139,7 +139,7 @@ sendReminderEmailToCandidate = (candidate, sendEmailCallback) -> log.error "Error sending candidate update reminder email: #{err} with result #{result}" if err sendEmailCallback null ### End Approved Candidate Update Reminder Task ### - + ### Unapproved Candidate Finish Reminder Task ### unapprovedCandidateFinishProfileTask = -> mailTaskName = "unapprovedCandidateFinishProfileTask" @@ -187,13 +187,13 @@ findAllUnapprovedCandidatesWithinTimeRange = (cb) -> User.find(findParameters).select(selection).lean().exec cb ignoredCandidateFilter = (candidate, cb) -> - findParameters = + findParameters = "user": candidate._id "contactName": "Ignore" UserRemark.count findParameters, (err, results) -> if err? then return true return cb Boolean(results.length) - + unapprovedCandidateFilter = (candidate, sentEmailFilterCallback) -> if candidate.emails?.anyNotes?.enabled is false or candidate.emails?.recruitNotes?.enabled is false return sentEmailFilterCallback true @@ -234,7 +234,7 @@ sendReminderEmailToUnapprovedCandidate = (candidate, sendEmailCallback) -> log.error "Error sending candidate finish profile reminder email: #{err} with result #{result}" if err sendEmailCallback null ### End Unapproved Candidate Finish Reminder Task ### - + ### Internal Candidate Update Reminder Email ### internalCandidateUpdateTask = -> mailTaskName = "internalCandidateUpdateTask" @@ -408,7 +408,7 @@ sendEmployerNewCandidatesAvailableEmail = (employer, cb) -> cb null ### End Employer New Candidates Available Email ### - + ### Task Emails ### emailUserRemarkTaskRemindersTask = -> mailTaskName = "emailUserRemarkTaskRemindersTask" @@ -428,7 +428,7 @@ emailUserRemarkTaskReminders = (cb) -> asyncContext = "currentTime": currentTime "mailTaskName": @mailTaskName - + async.waterfall [ findAllIncompleteUserRemarkTasksDue.bind(asyncContext) processRemarksIntoTasks.bind(asyncContext) @@ -437,9 +437,9 @@ emailUserRemarkTaskReminders = (cb) -> (tasksToRemind, cb) -> async.each tasksToRemind, sendUserRemarkTaskEmail.bind(asyncContext), cb ], cb - + findAllIncompleteUserRemarkTasksDue = (cb) -> - findParameters = + findParameters = tasks: $exists: true $elemMatch: @@ -449,12 +449,12 @@ findAllIncompleteUserRemarkTasksDue = (cb) -> $ne: 'Completed' selection = "contact user tasks" UserRemark.find(findParameters).select(selection).lean().exec cb - + processRemarksIntoTasks = (remarks, cb) -> tasks = [] for remark in remarks for task in remark.tasks - taskObject = + taskObject = date: task.date action: task.action contact: remark.contact @@ -476,7 +476,7 @@ taskReminderAlreadySentThisWeekFilter = (task, cb) -> MailSent.count findParameters, (err, count) -> if err? then return cb true return cb Boolean(count) - + sendUserRemarkTaskEmail = (task, cb) -> mailTaskName = @mailTaskName User.findOne("_id":task.contact).select("email").lean().exec (err, contact) -> @@ -548,8 +548,8 @@ isRequestFromDesignatedCronHandler = (req, res) -> handleLadderUpdate = (req, res) -> log.info('Going to see about sending ladder update emails.') - requestIsFromDesignatedCronHandler = isRequestFromDesignatedCronHandler req, res - return unless requestIsFromDesignatedCronHandler or DEBUGGING + requestIsFromDesignatedCronHandler = DEBUGGING or isRequestFromDesignatedCronHandler req, res + return unless requestIsFromDesignatedCronHandler res.send('Great work, Captain Cron! I can take it from here.') res.end() @@ -564,7 +564,7 @@ handleLadderUpdate = (req, res) -> endTime = startTime + 15 * 60 * 1000 # Debugging: make sure there's something to send findParameters = {submitted: true, submitDate: {$gt: new Date(startTime), $lte: new Date(endTime)}} # TODO: think about putting screenshots in the email - selectString = 'creator team levelName levelID totalScore matches submitted submitDate scoreHistory' + selectString = 'creator team levelName levelID totalScore matches submitted submitDate scoreHistory level.original' query = LevelSession.find(findParameters) .select(selectString) .lean() @@ -600,7 +600,7 @@ sendLadderUpdateEmail = (session, now, daysAgo) -> defeat = _.last defeats victory = _.last victories - sendEmail = (defeatContext, victoryContext) -> + sendEmail = (defeatContext, victoryContext, levelVersionsContext) -> # TODO: do something with the preferredLanguage? context = email_id: sendwithus.templates.ladder_update_email @@ -621,6 +621,7 @@ sendLadderUpdateEmail = (session, now, daysAgo) -> score_history_graph_url: getScoreHistoryGraphURL session, daysAgo defeat: defeatContext victory: victoryContext + levelVersions: levelVersionsContext log.info "Sending ladder update email to #{context.recipient.address} with #{context.email_data.wins} wins and #{context.email_data.losses} losses since #{daysAgo} day(s) ago." sendwithus.api.send context, (err, result) -> log.error "Error sending ladder update email: #{err} with result #{result}" if err @@ -639,7 +640,9 @@ sendLadderUpdateEmail = (session, now, daysAgo) -> log.error "Couldn't find victorious opponent: #{err}" victoriousOpponent = null defeatContext = {opponent_name: victoriousOpponent?.name ? 'Anoner', url: urlForMatch(defeat)} if defeat - sendEmail defeatContext, victoryContext + + Level.find({original: session.level.original, created: {$gt: session.submitDate}}).select('created commitMessage version').sort('-created').lean().exec (err, levelVersions) -> + sendEmail defeatContext, victoryContext, (if levelVersions.length then levelVersions else null) if defeat User.findOne({_id: defeat.opponents[0].userID}).select('name').lean().exec onFetchedVictoriousOpponent diff --git a/server/users/User.coffee b/server/users/User.coffee index 988107f9e..a0e7fe18a 100644 --- a/server/users/User.coffee +++ b/server/users/User.coffee @@ -15,14 +15,6 @@ UserSchema = new mongoose.Schema({ 'default': Date.now }, {strict: false}) -UserSchema.pre('init', (next) -> - return next() unless jsonschema.properties? - for prop, sch of jsonschema.properties - continue if prop is 'emails' # defaults may change, so don't carry them over just yet - @set(prop, sch.default) if sch.default? - next() -) - UserSchema.post('init', -> @set('anonymous', false) if @get('email') ) diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee index d96d86cf8..40eed11ea 100644 --- a/server/users/user_handler.coffee +++ b/server/users/user_handler.coffee @@ -13,6 +13,7 @@ LevelSession = require '../levels/sessions/LevelSession' LevelSessionHandler = require '../levels/sessions/level_session_handler' EarnedAchievement = require '../achievements/EarnedAchievement' UserRemark = require './remarks/UserRemark' +{isID} = require '../lib/utils' serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset'] candidateProperties = [ @@ -161,7 +162,7 @@ UserHandler = class UserHandler extends Handler post: (req, res) -> return @sendBadInputError(res, 'No input.') if _.isEmpty(req.body) return @sendBadInputError(res, 'Must have an anonymous user to post with.') unless req.user - return @sendBadInputError(res, 'Existing users cannot create new ones.') unless req.user.get('anonymous') + return @sendBadInputError(res, 'Existing users cannot create new ones.') if req.user.get('anonymous') is false req.body._id = req.user._id if req.user.get('anonymous') @put(req, res) @@ -187,6 +188,7 @@ UserHandler = class UserHandler extends Handler return @getRecentlyPlayed(req, res, args[0]) if args[1] is 'recently_played' return @trackActivity(req, res, args[0], args[2], args[3]) if args[1] is 'track' and args[2] return @getRemark(req, res, args[0]) if args[1] is 'remark' + return @searchForUser(req, res) if args[1] is 'admin_search' return @sendNotFoundError(res) super(arguments...) @@ -222,7 +224,7 @@ UserHandler = class UserHandler extends Handler res.end() getLevelSessionsForEmployer: (req, res, userID) -> - return @sendUnauthorizedError(res) unless req.user._id+'' is userID or req.user.isAdmin() or ('employer' in req.user.get('permissions')) + return @sendUnauthorizedError(res) unless req.user._id+'' is userID or req.user.isAdmin() or ('employer' in (req.user.get('permissions') ? [])) query = creator: userID, levelID: {$in: ['gridmancer', 'greed', 'dungeon-arena', 'brawlwood', 'gold-rush']} projection = 'levelName levelID team playtime codeLanguage submitted code totalScore teamSpells level' LevelSession.find(query).select(projection).exec (err, documents) => @@ -278,7 +280,7 @@ UserHandler = class UserHandler extends Handler return @sendMethodNotAllowed res unless req.method is 'POST' isMe = userID is req.user._id + '' isAuthorized = isMe or req.user.isAdmin() - isAuthorized ||= ('employer' in req.user.get('permissions')) and (activityName in ['viewed_by_employer', 'contacted_by_employer']) + isAuthorized ||= ('employer' in (req.user.get('permissions') ? [])) and (activityName in ['viewed_by_employer', 'contacted_by_employer']) return @sendUnauthorizedError res unless isAuthorized updateUser = (user) => activity = user.trackActivity activityName, increment @@ -301,7 +303,7 @@ UserHandler = class UserHandler extends Handler if not profileData.id or not profileData.positions or not profileData.emailAddress or not profileData.firstName or not profileData.lastName return errors.badInput(res, 'You need to have a more complete profile to sign up for this service.') @modelClass.findById(req.user.id).exec (err, user) => - if user.get('employerAt') or user.get('signedEmployerAgreement') or 'employer' in user.get('permissions') + if user.get('employerAt') or user.get('signedEmployerAgreement') or 'employer' in (user.get('permissions') ? []) return errors.conflict(res, 'You already have signed the agreement!') #TODO: Search for the current position employerAt = _.filter(profileData.positions.values, 'isCurrent')[0]?.company.name ? 'Not available' @@ -320,7 +322,7 @@ UserHandler = class UserHandler extends Handler res.end() getCandidates: (req, res) -> - authorized = req.user.isAdmin() or ('employer' in req.user.get('permissions')) + authorized = req.user.isAdmin() or ('employer' in (req.user.get('permissions') ? [])) months = if req.user.isAdmin() then 12 else 2 since = (new Date((new Date()) - months * 30.4 * 86400 * 1000)).toISOString() query = {'jobProfile.updated': {$gt: since}} @@ -388,6 +390,25 @@ UserHandler = class UserHandler extends Handler return @sendNotFoundError res unless remark? @sendSuccess res, remark + searchForUser: (req, res) -> + # TODO: also somehow search the CLAs to find a match amongst those fields and to find GitHub ids + return @sendUnauthorizedError(res) unless req.user.isAdmin() + search = req.body.search + query = email: {$exists: true}, $or: [ + {emailLower: search} + {nameLower: search} + ] + query.$or.push {_id: mongoose.Types.ObjectId(search) if isID search} + if search.length > 5 + searchParts = search.split(/[.+@]/) + if searchParts.length > 1 + query.$or.push {emailLower: {$regex: '^' + searchParts[0]}} + projection = name: 1, email: 1, dateCreated: 1 + User.find(query).select(projection).lean().exec (err, users) => + return @sendDatabaseError res, err if err + @sendSuccess res, users + + countEdits = (model, done) -> statKey = User.statsMapping.edits[model.modelName] return done(new Error 'Could not resolve statKey for model') unless statKey? @@ -402,6 +423,7 @@ UserHandler = class UserHandler extends Handler userStream.on 'error', (err) -> log.error err userStream.on 'close', -> streamFinished = true userStream.on 'data', (user) -> + usersTotal += 1 userObjectID = user.get('_id') userStringID = userObjectID.toHexString() @@ -450,6 +472,7 @@ UserHandler = class UserHandler extends Handler userStream.on 'error', (err) -> log.error err userStream.on 'close', -> streamFinished = true userStream.on 'data', (user) -> + usersTotal += 1 userObjectID = user.get '_id' userStringID = userObjectID.toHexString() # Extend query with a patch ownership test @@ -478,6 +501,7 @@ UserHandler = class UserHandler extends Handler userStream.on 'error', (err) -> log.error err userStream.on 'close', -> streamFinished = true userStream.on 'data', (user) -> + usersTotal += 1 userObjectID = user.get '_id' userStringID = userObjectID.toHexString() # Extend query with a patch ownership test @@ -505,6 +529,7 @@ UserHandler = class UserHandler extends Handler userStream.on 'error', (err) -> log.error err userStream.on 'close', -> streamFinished = true userStream.on 'data', (user) -> + usersTotal += 1 userID = user.get('_id').toHexString() LevelSession.count {creator: userID, 'state.completed': true}, (err, count) -> @@ -513,7 +538,7 @@ UserHandler = class UserHandler extends Handler articleEdits: (done) -> Article = require '../articles/Article' - countEdits Article, done + countEdits Article, done levelEdits: (done) -> Level = require '../levels/Level' @@ -574,7 +599,7 @@ UserHandler = class UserHandler extends Handler thangTypeTranslationPatches: (done) -> countPatchesByUsersInMemory {'target.collection': 'thang_type'}, isTranslationPatch, User.statsMapping.translations['thang.type'], done - + recalculateStats: (statName, done) => done new Error 'Recalculation handler not found' unless statName of @statRecalculators @statRecalculators[statName] done diff --git a/server_setup.coffee b/server_setup.coffee index 10a586713..8a76573ef 100644 --- a/server_setup.coffee +++ b/server_setup.coffee @@ -13,6 +13,7 @@ logging = require './server/commons/logging' config = require './server_config' auth = require './server/routes/auth' UserHandler = require './server/users/user_handler' +global.tv4 = require 'tv4' # required for TreemaUtils to work productionLogging = (tokens, req, res) -> status = res.statusCode diff --git a/test/app/collections/CocoCollection.spec.coffee b/test/app/collections/CocoCollection.spec.coffee new file mode 100644 index 000000000..6f233c6ce --- /dev/null +++ b/test/app/collections/CocoCollection.spec.coffee @@ -0,0 +1,12 @@ +CocoCollection = require 'collections/CocoCollection' +LevelComponent = require 'models/LevelComponent' + +describe 'CocoCollection', -> + it 'can be given a project function to include a project query arg', -> + collection = new CocoCollection([], { + url: '/db/level.component' + project:['name', 'description'] + model: LevelComponent + }) + collection.fetch({data: {view: 'items'}}) + expect(jasmine.Ajax.requests.mostRecent().url).toBe('/db/level.component?view=items&project=name%2Cdescription') diff --git a/test/app/lib/LevelLoader.spec.coffee b/test/app/lib/LevelLoader.spec.coffee index e3cb98dd1..a9f69bb18 100644 --- a/test/app/lib/LevelLoader.spec.coffee +++ b/test/app/lib/LevelLoader.spec.coffee @@ -7,7 +7,6 @@ LevelLoader = require 'lib/LevelLoader' # LEVELS levelWithOgreWithMace = { - type: 'hero' thangs: [{ thangType: 'ogre' components: [{ @@ -19,14 +18,12 @@ levelWithOgreWithMace = { } levelWithShaman = { - type: 'hero' thangs: [{ thangType: 'shaman' }] } levelWithShamanWithSuperWand = { - type: 'hero' thangs: [{ thangType: 'shaman' components: [{ @@ -115,12 +112,14 @@ describe 'LevelLoader', -> requests = jasmine.Ajax.requests.all() urls = (r.url for r in requests) expect('/db/level.component/jumps/version/0' in urls).toBeTruthy() - + it 'is idempotent', -> levelLoader = new LevelLoader({supermodel:new SuperModel(), sessionID: 'id', levelID: 'id'}) # first load Tharin by the 'normal' session load - responses = { '/db/level_session/id': sessionWithTharinWithHelmet } + responses = '/db/level/id': levelWithOgreWithMace + jasmine.Ajax.requests.sendResponses(responses) + responses = '/db/level_session/id': sessionWithTharinWithHelmet jasmine.Ajax.requests.sendResponses(responses) numRequestsBefore = jasmine.Ajax.requests.count() @@ -129,21 +128,21 @@ describe 'LevelLoader', -> levelLoader.loadDependenciesForSession(session) levelLoader.loadDependenciesForSession(session) levelLoader.loadDependenciesForSession(session) - numRequestsAfter = jasmine.Ajax.requests.count() - expect(numRequestsBefore).toBe(numRequestsAfter) - + numRequestsAfter = jasmine.Ajax.requests.count() + expect(numRequestsAfter).toBe(numRequestsBefore) + it 'loads thangs for items that the level thangs have in their Equips component configs', -> new LevelLoader({supermodel:supermodel = new SuperModel(), sessionID: 'id', levelID: 'id'}) - - responses = { - '/db/level/id': levelWithOgreWithMace + + responses = { + '/db/level/id': levelWithOgreWithMace } jasmine.Ajax.requests.sendResponses(responses) requests = jasmine.Ajax.requests.all() urls = (r.url for r in requests) expect('/db/thang.type/mace/version?project=name,components,original' in urls).toBeTruthy() - + it 'loads components which are inherited by level thangs from thang type default components', -> new LevelLoader({supermodel:new SuperModel(), sessionID: 'id', levelID: 'id'}) @@ -155,7 +154,7 @@ describe 'LevelLoader', -> requests = jasmine.Ajax.requests.all() urls = (r.url for r in requests) expect('/db/level.component/physical/version/0' in urls).toBeTruthy() - + it 'loads item thang types which are inherited by level thangs from thang type default equips component configs', -> new LevelLoader({supermodel:new SuperModel(), sessionID: 'id', levelID: 'id'}) @@ -167,7 +166,7 @@ describe 'LevelLoader', -> requests = jasmine.Ajax.requests.all() urls = (r.url for r in requests) expect('/db/thang.type/wand/version?project=name,components,original' in urls).toBeTruthy() - + it 'loads components for item thang types which are inherited by level thangs from thang type default equips component configs', -> new LevelLoader({supermodel:new SuperModel(), sessionID: 'id', levelID: 'id'}) @@ -180,15 +179,3 @@ describe 'LevelLoader', -> requests = jasmine.Ajax.requests.all() urls = (r.url for r in requests) expect('/db/level.component/poisons/version/0' in urls).toBeTruthy() - - it 'does not load item thang types from thang type equips component configs which are overriden by level thang equips component configs', -> - new LevelLoader({supermodel:new SuperModel(), sessionID: 'id', levelID: 'id'}) - - responses = - '/db/level/id': levelWithShamanWithSuperWand - '/db/thang.type/names': [thangTypeShamanWithWandEquipped] - - jasmine.Ajax.requests.sendResponses(responses) - requests = jasmine.Ajax.requests.all() - urls = (r.url for r in requests) - expect('/db/thang.type/wand/version?project=name,components,original' in urls).toBeFalsy() diff --git a/test/app/models/SuperModel.spec.coffee b/test/app/models/SuperModel.spec.coffee index 1e64d8d14..12219a584 100644 --- a/test/app/models/SuperModel.spec.coffee +++ b/test/app/models/SuperModel.spec.coffee @@ -50,3 +50,23 @@ describe 'SuperModel', -> _.defer -> expect(triggered).toBe(true) done() + + describe 'collection loading', -> + it 'combines models which are fetched from multiple sources', -> + s = new SuperModel() + + c1 = new ComponentsCollection() + c1.url = '/db/level.component?v=1' + s.loadCollection(c1, 'components') + + c2 = new ComponentsCollection() + c2.url = '/db/level.component?v=2' + s.loadCollection(c2, 'components') + + request = jasmine.Ajax.requests.sendResponses({ + '/db/level.component?v=1': [{"_id":"id","name":"Something"}] + '/db/level.component?v=2': [{"_id":"id","description":"This is something"}] + }) + + expect(s.models['/db/level.component/id'].get('name')).toBe('Something') + expect(s.models['/db/level.component/id'].get('description')).toBe('This is something') diff --git a/test/app/models/User.spec.coffee b/test/app/models/User.spec.coffee index 35b87f450..c6012896e 100644 --- a/test/app/models/User.spec.coffee +++ b/test/app/models/User.spec.coffee @@ -14,3 +14,28 @@ describe 'UserModel', -> me.set 'points', 50 expect(me.level()).toBe User.levelFromExp 50 + + describe 'user emails', -> + it 'has anyNotes, generalNews and recruitNotes enabled by default', -> + u = new User() + expect(u.get('emails')).toBeUndefined() + defaultEmails = u.get('emails', true) + expect(defaultEmails.anyNotes.enabled).toBe(true) + expect(defaultEmails.generalNews.enabled).toBe(true) + expect(defaultEmails.recruitNotes.enabled).toBe(true) + + it 'maintains defaults of other emails when one is explicitly set', -> + u = new User() + u.setEmailSubscription('recruitNotes', false) + defaultEmails = u.get('emails', true) + expect(defaultEmails.anyNotes?.enabled).toBe(true) + expect(defaultEmails.generalNews?.enabled).toBe(true) + expect(defaultEmails.recruitNotes.enabled).toBe(false) + + it 'does not populate raw data for other emails when one is explicitly set', -> + u = new User() + u.setEmailSubscription('recruitNotes', false) + u.buildAttributesWithDefaults() + emails = u.get('emails') + expect(emails.anyNotes).toBeUndefined() + expect(emails.generalNews).toBeUndefined() diff --git a/test/app/views/editor/component/ThangComponentsEditView.spec.coffee b/test/app/views/editor/component/ThangComponentsEditView.spec.coffee index dba8d8443..a2349a8d9 100644 --- a/test/app/views/editor/component/ThangComponentsEditView.spec.coffee +++ b/test/app/views/editor/component/ThangComponentsEditView.spec.coffee @@ -6,14 +6,14 @@ responses = '/db/level.component/B/version/0': { system: 'System' original: 'B' - majorVersion: 0 + version: {major: 0, minor:0} name: 'B (depends on A)' dependencies: [{original:'A', majorVersion: 0}] } '/db/level.component/A/version/0': { system: 'System' original: 'A' - majorVersion: 0 + version: {major: 0, minor:0} name: 'A' configSchema: { type: 'object', properties: { propA: { type: 'number' }, propB: { type: 'string' }} } } @@ -21,7 +21,7 @@ responses = componentC = new LevelComponent({ system: 'System' original: 'C' - majorVersion: 0 + version: {major: 0, minor:0} name: 'C (depends on B)' dependencies: [{original:'B', majorVersion: 0}] }) @@ -52,14 +52,12 @@ describe 'ThangComponentsEditView', -> # TODO: Figure out why this is breaking karma but not always it 'adds dependencies to its components list', -> -# jasmine.Ajax.requests.sendResponses(responses) componentOriginals = (c.original for c in view.components) expect('A' in componentOriginals).toBeTruthy() expect('B' in componentOriginals).toBeTruthy() expect('C' in componentOriginals).toBeTruthy() it 'removes components that are dependent on a removed component', -> -# jasmine.Ajax.requests.sendResponses(responses) view.components = (c for c in view.components when c.original isnt 'A') view.onComponentsChanged() expect(view.components.length).toBe(0) diff --git a/test/demo/views/editor/component/ThangComponentsEditView.demo.coffee b/test/demo/views/editor/component/ThangComponentsEditView.demo.coffee index d41af9628..079fc50ef 100644 --- a/test/demo/views/editor/component/ThangComponentsEditView.demo.coffee +++ b/test/demo/views/editor/component/ThangComponentsEditView.demo.coffee @@ -1,36 +1,59 @@ ThangComponentEditView = require('views/editor/component/ThangComponentsEditView') +ThangType = require 'models/ThangType' responses = '/db/level.component/A/version/0': { system: 'System' original: 'A' - majorVersion: 0 + version: { major: 0, minor: 0 } name: 'A' - configSchema: { type: 'object', properties: { propA: { type: 'number' }, propB: { type: 'string' }} } - + configSchema: { + type: 'object' + properties: { + propA: { type: 'number' } + propB: { type: 'string' } + } + } } '/db/level.component/B/version/0': { system: 'System' original: 'B' - majorVersion: 0 + version: { major: 0, minor: 0 } name: 'B (depends on A)' dependencies: [{original:'A', majorVersion: 0}] } '/db/level.component/C/version/0': { system: 'System' original: 'C' - majorVersion: 0 + version: { major: 0, minor: 0 } name: 'C (depends on B)' dependencies: [{original:'B', majorVersion: 0}] + configSchema: { + type: 'object' + default: { propC: 'Default property from component config' } + } } + '/db/level.component/D/version/0': { + system: 'System' + original: 'D' + version: { major: 0, minor: 0 } + name: 'D (comes from ThangType components)' + } + '/db/thang.type': [] module.exports = -> view = new ThangComponentEditView({ components: [ - { original: 'A', majorVersion: 0, config: {propA: 1, propB: 'string'} } { original: 'B', majorVersion: 0 } { original: 'C', majorVersion: 0 } + { original: 'A', majorVersion: 0, config: {propA: 1, propB: 'string'} } ] + thangType: new ThangType({ + components: [ + { original: 'A', majorVersion: 0, config: {propD: 'Default property from thang type component.'} } + { original: 'D', majorVersion: 0, config: {prop1: 'one', prop2: 'two'} } + ] + }) }) view.render() diff --git a/test/demo/views/user/JobProfileView.demo.coffee b/test/demo/views/user/JobProfileView.demo.coffee index 5ab643f87..6832fdee7 100644 --- a/test/demo/views/user/JobProfileView.demo.coffee +++ b/test/demo/views/user/JobProfileView.demo.coffee @@ -1,4 +1,4 @@ -JobProfileView = require 'views/account/JobProfileView' +JobProfileView = require 'views/user/JobProfileView' responses = '/db/user/joe/nameToID':'512ef4805a67a8c507000001' diff --git a/test/server/common.coffee b/test/server/common.coffee index fa1b04f4c..82531ee2b 100644 --- a/test/server/common.coffee +++ b/test/server/common.coffee @@ -20,6 +20,8 @@ GLOBAL.mongoose = require 'mongoose' mongoose.connect('mongodb://localhost/coco_unittest') path = require 'path' GLOBAL.testing = true +GLOBAL.tv4 = require 'tv4' # required for TreemaUtils to work +# _.str = require 'underscore.string' models_path = [ '../../server/articles/Article' diff --git a/test/server/functional/article.spec.coffee b/test/server/functional/article.spec.coffee index e17f241ea..acc7aab2b 100644 --- a/test/server/functional/article.spec.coffee +++ b/test/server/functional/article.spec.coffee @@ -117,7 +117,7 @@ describe '/db/article', -> request.get {uri: url + '?project=true', json: {}}, (err, res, body) -> expect(res.statusCode).toBe(200) expect(body.length).toBe(2) - expect(body[0].created).toBeUndefined() + expect(body[0].body).toBeUndefined() expect(body[0].version).toBeDefined() # custom projection diff --git a/test/server/functional/level_component.spec.coffee b/test/server/functional/level_component.spec.coffee index 697c14df7..a0c3b33e8 100644 --- a/test/server/functional/level_component.spec.coffee +++ b/test/server/functional/level_component.spec.coffee @@ -65,11 +65,9 @@ describe 'LevelComponent', -> expect(body.code).toBe(components[0].code) expect(body.codeLanguage).toBe(components[0].codeLanguage) expect(body.__v).toBe(0) - expect(body.official).toBeDefined() expect(body.creator).toBeDefined() expect(body.original).toBeDefined() expect(body.created).toBeDefined() - expect(body.configSchema).toBeDefined() expect(body.dependencies).toBeDefined() expect(body.propertyDocumentation).toBeDefined() expect(body.version.isLatestMajor).toBe(true) @@ -83,7 +81,7 @@ describe 'LevelComponent', -> expect(res.statusCode).toBe(200) body = JSON.parse(body) expect(body._id).toBe(components[0]._id) - expect(body.official).toBe(false) + expect(body.official).toBeUndefined() done() it 'has system ai by default', (done) -> @@ -100,7 +98,7 @@ describe 'LevelComponent', -> loginJoe -> request.post {uri: url, json: components[0]}, (err, res, body) -> expect(res.statusCode).toBe(200) - expect(body.official).toBe(false) + expect(body.official).toBeUndefined() done() it 'official property is editable by an admin.', (done) -> @@ -118,7 +116,7 @@ describe 'LevelComponent', -> expect(res.statusCode).toBe(200) body = JSON.parse(body) expect(body._id).toBe(components[0]._id) - expect(body.official).toBe(false) + expect(body.official).toBeUndefined() expect(body.version.isLatestMinor).toBe(false) expect(body.version.isLatestMajor).toBe(false) done() diff --git a/test/server/functional/level_system.spec.coffee b/test/server/functional/level_system.spec.coffee index 7d5c1e488..669fe5c4c 100644 --- a/test/server/functional/level_system.spec.coffee +++ b/test/server/functional/level_system.spec.coffee @@ -73,11 +73,9 @@ describe 'LevelSystem', -> expect(body.code).toBe(systems[0].code) expect(body.codeLanguage).toBe(systems[0].codeLanguage) expect(body.__v).toBe(0) - expect(body.official).toBeDefined() expect(body.creator).toBeDefined() expect(body.original).toBeDefined() expect(body.created).toBeDefined() - expect(body.configSchema).toBeDefined() expect(body.dependencies).toBeDefined() expect(body.propertyDocumentation).toBeDefined() expect(body.version.isLatestMajor).toBe(true) @@ -91,7 +89,7 @@ describe 'LevelSystem', -> expect(res.statusCode).toBe(200) body = JSON.parse(body) expect(body._id).toBe(systems[0]._id) - expect(body.official).toBe(false) + expect(body.official).toBeUndefined() done() it 'official property isn\'t editable by an ordinary user.', (done) -> @@ -116,7 +114,7 @@ describe 'LevelSystem', -> expect(res.statusCode).toBe(200) body = JSON.parse(body) expect(body._id).toBe(systems[0]._id) - expect(body.official).toBe(false) + expect(body.official).toBeUndefined() expect(body.version.isLatestMinor).toBe(false) expect(body.version.isLatestMajor).toBe(false) done() diff --git a/test/server/functional/patch.spec.coffee b/test/server/functional/patch.spec.coffee index 08eaac60c..c17a81774 100644 --- a/test/server/functional/patch.spec.coffee +++ b/test/server/functional/patch.spec.coffee @@ -71,13 +71,13 @@ describe '/db/patch', -> it 'does not add duplicate watchers', (done) -> watchingURL = getURL("/db/article/#{articles[0]._id}/watch") request.put {uri: watchingURL, json: {on: true}}, (err, res, body) -> - expect(body.watchers.length).toBe(2) + expect(body.watchers.length).toBe(4) done() it 'allows removing yourself', (done) -> watchingURL = getURL("/db/article/#{articles[0]._id}/watch") request.put {uri: watchingURL, json: {on: false}}, (err, res, body) -> - expect(body.watchers.length).toBe(1) + expect(body.watchers.length).toBe(3) done() it 'allows the submitter to withdraw the pull request', (done) ->